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.
This commit is contained in:
parent
3a1145b999
commit
e79af802b1
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -47,4 +47,5 @@
|
||||
#include "sound_list.h"
|
||||
#include "polygon.h"
|
||||
#include "text_box.h"
|
||||
#include "text_ellipsis.h"
|
||||
#endif
|
||||
|
@ -173,10 +173,21 @@ class UncachedScreen {
|
||||
template<uint8_t DL_SLOT,uint32_t DL_SIZE = 0>
|
||||
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;
|
||||
|
@ -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: <https://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
#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
|
@ -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: <https://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
#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);
|
||||
}
|
@ -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)
|
||||
|
@ -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 *************************/
|
||||
|
Loading…
Reference in New Issue
Block a user