From e79af802b1d1eb52016d27c975df55446a0c01e6 Mon Sep 17 00:00:00 2001 From: Marcio T Date: Sun, 6 Sep 2020 16:37:16 -0600 Subject: [PATCH] Touch UI long filenames fixes (#19262) * Improvements to FTDI DLCache functionality. * Better handling of long file names in Touch UI - Long file names now truncated and shown with ellipsis. - Increased display cache buffer to allow for longer filenames. - Visual error message when display cache is exceeded. --- .../ftdi_eve_lib/basic/commands.h | 1 + .../ftdi_eve_lib/extended/dl_cache.cpp | 80 ++++++++++--------- .../ftdi_eve_lib/extended/dl_cache.h | 18 +++-- .../ftdi_eve_lib/extended/ftdi_extended.h | 1 + .../ftdi_eve_lib/extended/screen_types.h | 11 +++ .../ftdi_eve_lib/extended/text_ellipsis.cpp | 80 +++++++++++++++++++ .../ftdi_eve_lib/extended/text_ellipsis.h | 31 +++++++ .../screens/files_screen.cpp | 15 ++-- .../lib/ftdi_eve_touch_ui/screens/screens.h | 2 +- 9 files changed, 187 insertions(+), 52 deletions(-) create mode 100644 Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp create mode 100644 Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h index 1bb35a5995..a9fdb5c5c7 100644 --- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h @@ -133,6 +133,7 @@ class CLCD { static void set_brightness (uint8_t brightness); static uint8_t get_brightness(); static void host_cmd (unsigned char host_command, unsigned char byte2); + static uint32_t dl_size() {return CLCD::mem_read_32(REG::CMD_DL) & 0x1FFF;} static void get_font_metrics (uint8_t font, struct FontMetrics &fm); static uint16_t get_text_width(const uint8_t font, const char *str); diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp index 728e433154..439541bd51 100644 --- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp @@ -32,7 +32,8 @@ * * The cache memory begins with a table at * DL_CACHE_START: each table entry contains - * an address and size for a cached DL slot. + * an address, size and used bytes for a cached + * DL slot. * * Immediately following the table is the * DL_FREE_ADDR, which points to free cache @@ -44,11 +45,14 @@ * * DL_CACHE_START slot0_addr 4 * slot0_size 4 + * slot0_used 4 * slot1_addr 4 * slot1_size 4 + * slot1_used 4 * ... * slotN_addr 4 * slotN_size 4 + * slotN_used 4 * DL_FREE_ADDR dl_free_ptr 4 * cached data * ... @@ -57,7 +61,7 @@ */ #define DL_CACHE_START MAP::RAM_G_SIZE - 0xFFFF -#define DL_FREE_ADDR DL_CACHE_START + DL_CACHE_SLOTS * 8 +#define DL_FREE_ADDR DL_CACHE_START + DL_CACHE_SLOTS * 12 using namespace FTDI; @@ -66,12 +70,12 @@ using namespace FTDI; void DLCache::init() { CLCD::mem_write_32(DL_FREE_ADDR, DL_FREE_ADDR + 4); for(uint8_t slot = 0; slot < DL_CACHE_SLOTS; slot++) { - save_slot(slot, 0, 0); + save_slot(slot, 0, 0, 0); } } bool DLCache::has_data() { - return dl_size != 0; + return dl_slot_size != 0; } bool DLCache::wait_until_idle() { @@ -93,12 +97,12 @@ bool DLCache::wait_until_idle() { * that it can be appended later. The memory is * dynamically allocated following DL_FREE_ADDR. * - * If num_bytes is provided, then that many bytes + * If min_bytes is provided, then that many bytes * will be reserved so that the cache may be re-written * later with potentially a bigger DL. */ -bool DLCache::store(uint32_t num_bytes /* = 0*/) { +bool DLCache::store(uint32_t min_bytes /* = 0*/) { CLCD::CommandFifo cmd; // Execute any commands already in the FIFO @@ -107,67 +111,67 @@ bool DLCache::store(uint32_t num_bytes /* = 0*/) { return false; // Figure out how long the display list is - uint32_t new_dl_size = CLCD::mem_read_32(REG::CMD_DL) & 0x1FFF; - uint32_t free_space = 0; - uint32_t dl_alloc = 0; + const uint32_t dl_size = CLCD::dl_size(); - if (dl_addr == 0) { + if (dl_slot_addr == 0) { // If we are allocating new space... - dl_addr = CLCD::mem_read_32(DL_FREE_ADDR); - free_space = MAP::RAM_G_SIZE - dl_addr; - dl_alloc = num_bytes ?: new_dl_size; - dl_size = new_dl_size; - } else { - // Otherwise, we can only store as much space - // as was previously allocated. - free_space = num_bytes ?: dl_size; - dl_alloc = 0; - dl_size = new_dl_size; + dl_slot_addr = CLCD::mem_read_32(DL_FREE_ADDR); + dl_slot_size = max(dl_size, min_bytes); + + const uint32_t free_space = MAP::RAM_G_SIZE - dl_slot_addr; + if(dl_slot_size <= free_space) { + CLCD::mem_write_32(DL_FREE_ADDR, dl_slot_addr + dl_slot_size); + } else { + dl_slot_addr = 0; + dl_slot_size = 0; + dl_slot_used = 0; + } } - if (dl_size > free_space) { + if (dl_size > dl_slot_size) { // Not enough memory to cache the display list. #if ENABLED(TOUCH_UI_DEBUG) SERIAL_ECHO_START(); - SERIAL_ECHOPAIR ("Not enough space in GRAM to cache display list, free space: ", free_space); + SERIAL_ECHOPAIR ("Not enough space in GRAM to cache display list, free space: ", dl_slot_size); SERIAL_ECHOLNPAIR(" Required: ", dl_size); #endif + dl_slot_used = 0; + save_slot(); return false; } else { #if ENABLED(TOUCH_UI_DEBUG) SERIAL_ECHO_START(); - SERIAL_ECHOPAIR ("Saving DL to RAMG cache, bytes: ", dl_size); - SERIAL_ECHOLNPAIR(" Free space: ", free_space); + SERIAL_ECHOPAIR ("Saving DL to RAMG cache, bytes: ", dl_slot_used); + SERIAL_ECHOLNPAIR(" Free space: ", dl_slot_size); #endif - cmd.memcpy(dl_addr, MAP::RAM_DL, dl_size); + dl_slot_used = dl_size; + save_slot(); + cmd.memcpy(dl_slot_addr, MAP::RAM_DL, dl_slot_used); cmd.execute(); - save_slot(dl_slot, dl_addr, dl_size); - if (dl_alloc > 0) { - // If we allocated space dynamically, then adjust dl_free_addr. - CLCD::mem_write_32(DL_FREE_ADDR, dl_addr + dl_alloc); - } return true; } } -void DLCache::save_slot(uint8_t dl_slot, uint32_t dl_addr, uint32_t dl_size) { - CLCD::mem_write_32(DL_CACHE_START + dl_slot * 8 + 0, dl_addr); - CLCD::mem_write_32(DL_CACHE_START + dl_slot * 8 + 4, dl_size); +void DLCache::save_slot(uint8_t indx, uint32_t addr, uint16_t size, uint16_t used) { + CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 0, addr); + CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 4, size); + CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 8, used); } -void DLCache::load_slot() { - dl_addr = CLCD::mem_read_32(DL_CACHE_START + dl_slot * 8 + 0); - dl_size = CLCD::mem_read_32(DL_CACHE_START + dl_slot * 8 + 4); +void DLCache::load_slot(uint8_t indx, uint32_t &addr, uint16_t &size, uint16_t &used) { + addr = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 0); + size = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 4); + used = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 8); } void DLCache::append() { CLCD::CommandFifo cmd; - cmd.append(dl_addr, dl_size); + cmd.append(dl_slot_addr, dl_slot_used); #if ENABLED(TOUCH_UI_DEBUG) cmd.execute(); wait_until_idle(); SERIAL_ECHO_START(); - SERIAL_ECHOPAIR ("Appending to DL from RAMG cache, bytes: ", dl_size); + SERIAL_ECHOPAIR ("Appending to DL from RAMG cache, bytes: ", dl_slot_used); SERIAL_ECHOLNPAIR(" REG_CMD_DL: ", CLCD::mem_read_32(REG::CMD_DL)); #endif } diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h index 4ae4bce3ef..c4bb22fbd7 100644 --- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h @@ -44,12 +44,16 @@ class DLCache { typedef FTDI::ftdi_registers REG; typedef FTDI::ftdi_memory_map MAP; - uint8_t dl_slot; - uint32_t dl_addr; - uint16_t dl_size; + uint8_t dl_slot_indx; + uint32_t dl_slot_addr; + uint16_t dl_slot_size; + uint16_t dl_slot_used; - void load_slot(); - static void save_slot(uint8_t dl_slot, uint32_t dl_addr, uint32_t dl_size); + void load_slot() {load_slot(dl_slot_indx, dl_slot_addr, dl_slot_size, dl_slot_used);} + void save_slot() {save_slot(dl_slot_indx, dl_slot_addr, dl_slot_size, dl_slot_used);} + + static void load_slot(uint8_t indx, uint32_t &addr, uint16_t &size, uint16_t &used); + static void save_slot(uint8_t indx, uint32_t addr, uint16_t size, uint16_t used); bool wait_until_idle(); @@ -57,12 +61,12 @@ class DLCache { static void init(); DLCache(uint8_t slot) { - dl_slot = slot; + dl_slot_indx = slot; load_slot(); } bool has_data(); - bool store(uint32_t num_bytes = 0); + bool store(uint32_t min_bytes = 0); void append(); }; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h index e1904511b2..6e4d0668fe 100644 --- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h @@ -47,4 +47,5 @@ #include "sound_list.h" #include "polygon.h" #include "text_box.h" + #include "text_ellipsis.h" #endif diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h index b12ab286e1..d1f84c8a6e 100644 --- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h @@ -173,10 +173,21 @@ class UncachedScreen { template class CachedScreen { protected: + static void gfxError() { + using namespace FTDI; + CommandProcessor cmd; + cmd.cmd(CMD_DLSTART) + .cmd(CLEAR(true,true,true)) + .font(30) + .text(0, 0, display_width, display_height, F("GFX MEM FULL")); + } + static bool storeBackground() { DLCache dlcache(DL_SLOT); if (!dlcache.store(DL_SIZE)) { SERIAL_ECHO_MSG("CachedScreen::storeBackground() failed: not enough DL cache space"); + gfxError(); // Try to cache a shorter error message instead. + dlcache.store(DL_SIZE); return false; } return true; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp new file mode 100644 index 0000000000..3746f1cde0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp @@ -0,0 +1,80 @@ +/********************* + * text_ellipsis.cpp * + *********************/ + +/**************************************************************************** + * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * To view a copy of the GNU General Public License, go to the following * + * location: . * + ****************************************************************************/ + +#include "ftdi_extended.h" + +#ifdef FTDI_EXTENDED + +namespace FTDI { + + /** + * Helper function for drawing text with ellipses. The str buffer may be modified and should have space for up to two extra characters. + */ + static void _draw_text_with_ellipsis(CommandProcessor& cmd, int16_t x, int16_t y, int16_t w, int16_t h, char *str, uint16_t options, uint8_t font) { + FontMetrics fm(font); + const uint16_t ellipsisWidth = fm.get_char_width('.') * 3; + + // Compute the total line length, as well as + // the location in the string where it can + // split and still allow the ellipsis to fit. + uint16_t lineWidth = 0; + char *breakPoint = str; + for(char* c = str; *c; c++) { + lineWidth += fm.get_char_width(*c); + if(lineWidth + ellipsisWidth < w) + breakPoint = c; + } + + if(lineWidth > w) { + *breakPoint = '\0'; + strcpy_P(breakPoint,PSTR("...")); + } + + cmd.apply_text_alignment(x, y, w, h, options); + #ifdef TOUCH_UI_USE_UTF8 + if (has_utf8_chars(str)) { + draw_utf8_text(cmd, x, y, str, font_size_t::from_romfont(font), options); + } else + #endif + { + cmd.CLCD::CommandFifo::text(x, y, font, options); + cmd.CLCD::CommandFifo::str(str); + } + } + + /** + * These functions draws text inside a bounding box, truncating the text and + * adding ellipsis if the text does not fit. + */ + void draw_text_with_ellipsis(CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options, uint8_t font) { + char tmp[strlen(str) + 3]; + strcpy(tmp, str); + _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font); + } + + void draw_text_with_ellipsis(CommandProcessor& cmd, int x, int y, int w, int h, progmem_str pstr, uint16_t options, uint8_t font) { + char tmp[strlen_P((const char*)pstr) + 3]; + strcpy_P(tmp, (const char*)pstr); + _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font); + } +} // namespace FTDI + +#endif // FTDI_EXTENDED diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h new file mode 100644 index 0000000000..7852b7ec3e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h @@ -0,0 +1,31 @@ +/******************* + * text_ellipsis.h * + *******************/ + +/**************************************************************************** + * Written By Marcio Teixeira 2020 - SynDaver Labs, Inc. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * To view a copy of the GNU General Public License, go to the following * + * location: . * + ****************************************************************************/ + +#pragma once + +/** + * This function draws text inside a bounding box, truncating the text and + * showing ellipsis if it does not fit. + */ +namespace FTDI { + void draw_text_with_ellipsis(class CommandProcessor& cmd, int x, int y, int w, int h, progmem_str str, uint16_t options = 0, uint8_t font = 31); + void draw_text_with_ellipsis(class CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options = 0, uint8_t font = 31); +} diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp index e304302422..8d6fb18603 100644 --- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp @@ -83,15 +83,19 @@ void FilesScreen::drawFileButton(const char* filename, uint8_t tag, bool is_dir, cmd.font(font_medium) .rectangle( 0, BTN_Y(header_h+line), display_width, BTN_H(1)); cmd.cmd(COLOR_RGB(is_highlighted ? normal_btn.rgb : bg_text_enabled)); + constexpr uint16_t dim[2] = {BTN_SIZE(6,1)}; + #define POS_AND_SHORTEN(SHORTEN) BTN_POS(1,header_h+line), dim[0] - (SHORTEN), dim[1] + #define POS_AND_SIZE POS_AND_SHORTEN(0) #if ENABLED(SCROLL_LONG_FILENAMES) if (is_highlighted) { cmd.cmd(SAVE_CONTEXT()); cmd.cmd(MACRO(0)); - } + cmd.text(POS_AND_SIZE, filename, OPT_CENTERY | OPT_NOFIT); + } else #endif - cmd.text (BTN_POS(1,header_h+line), BTN_SIZE(6,1), filename, OPT_CENTERY | TERN0(SCROLL_LONG_FILENAMES, OPT_NOFIT)); - if (is_dir) { - cmd.text(BTN_POS(1,header_h+line), BTN_SIZE(6,1), F("> "), OPT_CENTERY | OPT_RIGHTX); + draw_text_with_ellipsis(cmd, POS_AND_SHORTEN(is_dir ? 20 : 0), filename, OPT_CENTERY, font_medium); + if (is_dir && !is_highlighted) { + cmd.text(POS_AND_SIZE, F("> "), OPT_CENTERY | OPT_RIGHTX); } #if ENABLED(SCROLL_LONG_FILENAMES) if (is_highlighted) { @@ -102,7 +106,7 @@ void FilesScreen::drawFileButton(const char* filename, uint8_t tag, bool is_dir, void FilesScreen::drawFileList() { FileList files; - screen_data.FilesScreen.num_page = max(1,(ceil)(float(files.count()) / files_per_page)); + screen_data.FilesScreen.num_page = max(1,ceil(float(files.count()) / files_per_page)); screen_data.FilesScreen.cur_page = min(screen_data.FilesScreen.cur_page, screen_data.FilesScreen.num_page-1); screen_data.FilesScreen.flags.is_root = files.isAtRootDir(); @@ -134,7 +138,6 @@ void FilesScreen::drawHeader() { sprintf_P(str, PSTR("Page %d of %d"), screen_data.FilesScreen.cur_page + 1, screen_data.FilesScreen.num_page); - CommandProcessor cmd; cmd.colors(normal_btn) .font(font_small) diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h index 92e6b230f7..ae48f75240 100644 --- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h @@ -96,7 +96,7 @@ enum { #define STATUS_SCREEN_DL_SIZE 2048 #define ALERT_BOX_DL_SIZE 3072 #define SPINNER_DL_SIZE 3072 -#define FILE_SCREEN_DL_SIZE 3072 +#define FILE_SCREEN_DL_SIZE 4160 #define PRINTING_SCREEN_DL_SIZE 2048 /************************* MENU SCREEN DECLARATIONS *************************/