FTDI EVE: Cyrillic font, some minor fixes (#20517)

This commit is contained in:
LinFor 2020-12-23 09:51:59 +03:00 committed by Scott Lahteine
parent ad15890a81
commit 323bf47738
22 changed files with 3319 additions and 30 deletions

View file

@ -1563,6 +1563,9 @@
//#define TOUCH_UI_UTF8_FRACTIONS // ¼ ½ ¾ //#define TOUCH_UI_UTF8_FRACTIONS // ¼ ½ ¾
//#define TOUCH_UI_UTF8_SYMBOLS // µ ¶ ¦ § ¬ //#define TOUCH_UI_UTF8_SYMBOLS // µ ¶ ¦ § ¬
#endif #endif
// Cyrillic character set, costs about 27KiB of flash
//#define TOUCH_UI_UTF8_CYRILLIC_CHARSET
#endif #endif
// Use a smaller font when labels don't fit buttons // Use a smaller font when labels don't fit buttons

View file

@ -211,6 +211,14 @@ void CLCD::mem_write_32(uint32_t reg_address, uint32_t data) {
spi_ftdi_deselect(); spi_ftdi_deselect();
} }
// Fill area of len size with repeated data bytes
void CLCD::mem_write_fill(uint32_t reg_address, uint8_t data, uint16_t len) {
spi_ftdi_select();
spi_write_addr(reg_address);
while (len--) spi_write_8(data);
spi_ftdi_deselect();
}
/******************* FT800/810 Co-processor Commands *********************************/ /******************* FT800/810 Co-processor Commands *********************************/
#if FTDI_API_LEVEL == 800 #if FTDI_API_LEVEL == 800

View file

@ -115,6 +115,7 @@ class CLCD {
static void mem_write_8 (uint32_t reg_address, uint8_t w_data); static void mem_write_8 (uint32_t reg_address, uint8_t w_data);
static void mem_write_16 (uint32_t reg_address, uint16_t w_data); static void mem_write_16 (uint32_t reg_address, uint16_t w_data);
static void mem_write_32 (uint32_t reg_address, uint32_t w_data); static void mem_write_32 (uint32_t reg_address, uint32_t w_data);
static void mem_write_fill (uint32_t reg_address, uint8_t w_data, uint16_t len);
static void mem_write_bulk (uint32_t reg_address, const void *data, uint16_t len, uint8_t padding = 0); static void mem_write_bulk (uint32_t reg_address, const void *data, uint16_t len, uint8_t padding = 0);
static void mem_write_pgm (uint32_t reg_address, const void *data, uint16_t len, uint8_t padding = 0); static void mem_write_pgm (uint32_t reg_address, const void *data, uint16_t len, uint8_t padding = 0);
static void mem_write_bulk (uint32_t reg_address, progmem_str str, uint16_t len, uint8_t padding = 0); static void mem_write_bulk (uint32_t reg_address, progmem_str str, uint16_t len, uint8_t padding = 0);

View file

@ -34,6 +34,7 @@
#include "unicode/unicode.h" #include "unicode/unicode.h"
#include "unicode/standard_char_set.h" #include "unicode/standard_char_set.h"
#include "unicode/western_char_set.h" #include "unicode/western_char_set.h"
#include "unicode/cyrillic_char_set.h"
#include "unicode/font_bitmaps.h" #include "unicode/font_bitmaps.h"
#include "rgb_t.h" #include "rgb_t.h"
#include "bitmap_info.h" #include "bitmap_info.h"

View file

@ -37,11 +37,22 @@ namespace FTDI {
// split and still allow the ellipsis to fit. // split and still allow the ellipsis to fit.
int16_t lineWidth = 0; int16_t lineWidth = 0;
char *breakPoint = str; char *breakPoint = str;
for (char* c = str; *c; c++) { #ifdef TOUCH_UI_USE_UTF8
lineWidth += fm.get_char_width(*c); char *tstr = str;
if (lineWidth + ellipsisWidth < w) while (*tstr) {
breakPoint = c; breakPoint = tstr;
} const utf8_char_t c = get_utf8_char_and_inc(tstr);
lineWidth += fm.get_char_width(c);
if (lineWidth + ellipsisWidth < w)
break;
}
#else
for (char* c = str; *c; c++) {
lineWidth += fm.get_char_width(*c);
if (lineWidth + ellipsisWidth < w)
breakPoint = c;
}
#endif
if (lineWidth > w) { if (lineWidth > w) {
*breakPoint = '\0'; *breakPoint = '\0';

View file

@ -0,0 +1,139 @@
/************************
* cyrillic_char_set.cpp *
************************/
/****************************************************************************
* Written By Kirill Shashlov 2020 *
* 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"
#if ALL(FTDI_EXTENDED, TOUCH_UI_USE_UTF8, TOUCH_UI_UTF8_CYRILLIC_CHARSET)
#include "cyrillic_char_set_bitmap_31.h"
#define NUM_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
#define UTF8(A) uint16_t(utf8(U##A))
using namespace FTDI;
constexpr static uint8_t cyrillic_font_handle = 6;
uint32_t FTDI::CyrillicCharSet::bitmap_addr;
/**
* Load bitmap data into RAMG. This function is called once at the start
* of the program.
*
* Parameters:
*
* addr - Address in RAMG where the font data is written
*
* Returns: Last wrote address
*/
uint32_t FTDI::CyrillicCharSet::load_data(uint32_t addr) {
if (addr % 4 != 0)
addr += 4 - (addr % 4);
// Load the alternative font metrics
CLCD::FontMetrics cyrillic_fm;
cyrillic_fm.ptr = addr + 148;
cyrillic_fm.format = L4;
cyrillic_fm.stride = 20;
cyrillic_fm.width = 40;
cyrillic_fm.height = 49;
LOOP_L_N(i, 127)
cyrillic_fm.char_widths[i] = 0;
// For cyrillic characters, copy the character widths from the widths tables
LOOP_L_N(i, NUM_ELEMENTS(cyrillic_font_widths)) {
cyrillic_fm.char_widths[i] = cyrillic_font_widths[i];
}
CLCD::mem_write_bulk(addr, &cyrillic_fm, 148);
// Decode the RLE data and load it into RAMG as a bitmap
uint32_t lastaddr = write_rle_data(addr + 148, cyrillic_font, sizeof(cyrillic_font));
bitmap_addr = addr;
return lastaddr;
}
/**
* Populates the bitmap handles for the custom into the display list.
* This function is called once at the start of each display list.
*
* Parameters:
*
* cmd - Object used for writing to the FTDI chip command queue.
*/
void FTDI::CyrillicCharSet::load_bitmaps(CommandProcessor& cmd) {
CLCD::FontMetrics cyrillic_fm;
cyrillic_fm.ptr = bitmap_addr + 148;
cyrillic_fm.format = L4;
cyrillic_fm.stride = 20;
cyrillic_fm.width = 40;
cyrillic_fm.height = 49;
set_font_bitmap(cmd, cyrillic_fm, cyrillic_font_handle);
}
/**
* Renders a character at location x and y. The x position is incremented
* by the width of the character.
*
* Parameters:
*
* cmd - If non-NULL the symbol is drawn to the screen.
* If NULL, only increment position for text measurement.
*
* x, y - The location at which to draw the character. On output,
* incremented to the location of the next character.
*
* fs - A scaling object used to scale the font. The display will
* already be configured to scale bitmaps, but positions
* must be scaled using fs.scale()
*
* c - The unicode code point to draw. If the renderer does not
* support the character, it should return false.
*
* Returns: Whether the character was supported.
*/
bool FTDI::CyrillicCharSet::render_glyph(CommandProcessor* cmd, int &x, int &y, font_size_t fs, utf8_char_t c) {
// A supported character?
if ((c < UTF8('А') || c > UTF8('я')) && (c != UTF8('Ё')) && (c != UTF8('ё'))) return false;
uint8_t idx = (c == UTF8('Ё')) ? 64 :
(c == UTF8('ё')) ? 65 :
(c < UTF8('р')) ? c - UTF8('А') :
c - UTF8('р') + 48
;
uint8_t width = cyrillic_font_widths[idx];
// Draw the character
if (cmd) ext_vertex2ii(*cmd, x, y, cyrillic_font_handle, idx);
// Increment X to the next character position
x += fs.scale(width);
return true;
}
#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8 && TOUCH_UI_UTF8_WESTERN_CHARSET

View file

@ -0,0 +1,32 @@
/**********************
* cyrillic_char_set.h *
**********************/
/****************************************************************************
* Written By Kirill Shashlov 2020 *
* 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/>. *
****************************************************************************/
namespace FTDI {
class CyrillicCharSet {
private:
static uint32_t bitmap_addr;
public:
static uint32_t load_data(uint32_t addr);
static void load_bitmaps(CommandProcessor&);
static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
};
}

View file

@ -25,12 +25,14 @@
namespace FTDI { namespace FTDI {
void write_rle_data(uint16_t addr, const uint8_t *data, size_t n) { uint32_t write_rle_data(uint32_t addr, const uint8_t *data, size_t n) {
for (; n >= 2; n -= 2) { for (; n >= 2; n -= 2) {
uint8_t count = pgm_read_byte(data++); uint8_t count = pgm_read_byte(data++);
uint8_t value = pgm_read_byte(data++); uint8_t value = pgm_read_byte(data++);
while (count--) CLCD::mem_write_8(addr++, value); CLCD::mem_write_fill(addr, value, count);
addr += count;
} }
return addr;
} }
void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle) { void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle) {

View file

@ -24,7 +24,7 @@
class CommandProcessor; class CommandProcessor;
namespace FTDI { namespace FTDI {
void write_rle_data(uint16_t addr, const uint8_t *data, size_t n); uint32_t write_rle_data(uint32_t addr, const uint8_t *data, size_t n);
void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle); void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle);
void ext_vertex2ii(CommandProcessor &cmd, int x, int y, uint8_t handle, uint8_t cell); void ext_vertex2ii(CommandProcessor &cmd, int x, int y, uint8_t handle, uint8_t cell);
} }

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -48,7 +48,8 @@
* addr - Address in RAMG where the font data is written * addr - Address in RAMG where the font data is written
*/ */
void FTDI::StandardCharSet::load_data(uint32_t) { uint32_t FTDI::StandardCharSet::load_data(uint32_t addr) {
return addr;
} }
/** /**

View file

@ -23,7 +23,7 @@ namespace FTDI {
class StandardCharSet { class StandardCharSet {
public: public:
static uint8_t std_char_width(char); static uint8_t std_char_width(char);
static void load_data(uint32_t addr); static uint32_t load_data(uint32_t addr);
static void load_bitmaps(CommandProcessor&); static void load_bitmaps(CommandProcessor&);
static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t); static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
}; };

View file

@ -73,6 +73,13 @@
return val; return val;
} }
utf8_char_t FTDI::get_utf8_char_and_inc(char *&c) {
utf8_char_t val = *(uint8_t*)c++;
while ((*c & 0xC0) == 0x80)
val = (val << 8) | *(uint8_t*)c++;
return val;
}
/** /**
* Helper function to draw and/or measure a UTF8 string * Helper function to draw and/or measure a UTF8 string
* *
@ -92,6 +99,9 @@
const int start_x = x; const int start_x = x;
while (*str) { while (*str) {
const utf8_char_t c = get_utf8_char_and_inc(str); const utf8_char_t c = get_utf8_char_and_inc(str);
#ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
CyrillicCharSet::render_glyph(cmd, x, y, fs, c) ||
#endif
#ifdef TOUCH_UI_UTF8_WESTERN_CHARSET #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
WesternCharSet::render_glyph(cmd, x, y, fs, c) || WesternCharSet::render_glyph(cmd, x, y, fs, c) ||
#endif #endif
@ -108,11 +118,14 @@
* addr - Address in RAMG where the font data is written * addr - Address in RAMG where the font data is written
*/ */
void FTDI::load_utf8_data(uint16_t addr) { void FTDI::load_utf8_data(uint32_t addr) {
#ifdef TOUCH_UI_UTF8_WESTERN_CHARSET #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
WesternCharSet::load_data(addr); addr = CyrillicCharSet::load_data(addr);
#endif #endif
StandardCharSet::load_data(addr); #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
addr = WesternCharSet::load_data(addr);
#endif
addr = StandardCharSet::load_data(addr);
} }
/** /**
@ -125,6 +138,9 @@
*/ */
void FTDI::load_utf8_bitmaps(CommandProcessor &cmd) { void FTDI::load_utf8_bitmaps(CommandProcessor &cmd) {
#ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
CyrillicCharSet::load_bitmaps(cmd);
#endif
#ifdef TOUCH_UI_UTF8_WESTERN_CHARSET #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
WesternCharSet::load_bitmaps(cmd); WesternCharSet::load_bitmaps(cmd);
#endif #endif
@ -145,6 +161,9 @@
uint16_t FTDI::get_utf8_char_width(utf8_char_t c, font_size_t fs) { uint16_t FTDI::get_utf8_char_width(utf8_char_t c, font_size_t fs) {
int x = 0, y = 0; int x = 0, y = 0;
#ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
CyrillicCharSet::render_glyph(nullptr, x, y, fs, c) ||
#endif
#ifdef TOUCH_UI_UTF8_WESTERN_CHARSET #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
WesternCharSet::render_glyph(nullptr, x, y, fs, c) || WesternCharSet::render_glyph(nullptr, x, y, fs, c) ||
#endif #endif

View file

@ -47,19 +47,20 @@ namespace FTDI {
* pointer to the next character */ * pointer to the next character */
utf8_char_t get_utf8_char_and_inc(const char *&c); utf8_char_t get_utf8_char_and_inc(const char *&c);
utf8_char_t get_utf8_char_and_inc(char *&c);
/* Returns the next character in a UTF8 string, without incrementing */ /* Returns the next character in a UTF8 string, without incrementing */
inline utf8_char_t get_utf8_char(const char *c) {return get_utf8_char_and_inc(c);} inline utf8_char_t get_utf8_char(const char *c) {return get_utf8_char_and_inc(c);}
void load_utf8_data(uint16_t addr); void load_utf8_data(uint32_t addr);
#else #else
typedef char utf8_char_t; typedef char utf8_char_t;
inline utf8_char_t get_utf8_char_and_inc(const char *&c) {return *c++;} inline utf8_char_t get_utf8_char_and_inc(const char *&c) {return *c++;}
inline utf8_char_t get_utf8_char(const char *c) {return *c;} inline utf8_char_t get_utf8_char(const char *c) {return *c;}
inline void load_utf8_data(uint16_t) {} inline void load_utf8_data(uint32_t) {}
#endif #endif
void load_utf8_bitmaps(CommandProcessor& cmd); void load_utf8_bitmaps(CommandProcessor& cmd);

View file

@ -32,7 +32,7 @@
constexpr static uint8_t std_font = 31; constexpr static uint8_t std_font = 31;
constexpr static uint8_t alt_font = 1; constexpr static uint8_t alt_font = 1;
static uint32_t bitmap_addr; uint32_t FTDI::WesternCharSet::bitmap_addr;
/* Glyphs in the WesternCharSet bitmap */ /* Glyphs in the WesternCharSet bitmap */
@ -286,7 +286,7 @@
#if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN) #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
{UTF8('þ'), 0 , SML_THORN, 25 }, {UTF8('þ'), 0 , SML_THORN, 25 },
#endif #endif
{UTF8('ÿ'), 'y', DIAERESIS, mid_y} {UTF8('ÿ'), 'y', DIAERESIS, mid_y},
}; };
static_assert(UTF8('¡') == 0xC2A1, "Incorrect encoding for character"); static_assert(UTF8('¡') == 0xC2A1, "Incorrect encoding for character");
@ -331,7 +331,10 @@
* addr - Address in RAMG where the font data is written * addr - Address in RAMG where the font data is written
*/ */
void FTDI::WesternCharSet::load_data(uint32_t addr) { uint32_t FTDI::WesternCharSet::load_data(uint32_t addr) {
if (addr % 4 != 0)
addr += 4 - (addr % 4);
// Load the alternative font metrics // Load the alternative font metrics
CLCD::FontMetrics alt_fm; CLCD::FontMetrics alt_fm;
alt_fm.ptr = addr + 148; alt_fm.ptr = addr + 148;
@ -352,9 +355,11 @@
CLCD::mem_write_bulk(addr, &alt_fm, 148); CLCD::mem_write_bulk(addr, &alt_fm, 148);
// Decode the RLE data and load it into RAMG as a bitmap // Decode the RLE data and load it into RAMG as a bitmap
write_rle_data(addr + 148, font, sizeof(font)); uint32_t lastaddr = write_rle_data(addr + 148, font, sizeof(font));
bitmap_addr = addr; bitmap_addr = addr;
return lastaddr;
} }
/** /**
@ -394,7 +399,7 @@
* *
* c - The unicode code point to draw. If the renderer does not * c - The unicode code point to draw. If the renderer does not
* support the character, it should return false. * support the character, it should return false.
*
* Returns: Whether the character was supported. * Returns: Whether the character was supported.
*/ */

View file

@ -21,8 +21,10 @@
namespace FTDI { namespace FTDI {
class WesternCharSet { class WesternCharSet {
private:
static uint32_t bitmap_addr;
public: public:
static void load_data(uint32_t addr); static uint32_t load_data(uint32_t addr);
static void load_bitmaps(CommandProcessor&); static void load_bitmaps(CommandProcessor&);
static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t); static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
}; };

View file

@ -49,19 +49,19 @@ class WriteSource:
def convert_to_4bpp(self, data, chunk_size = 0): def convert_to_4bpp(self, data, chunk_size = 0):
# Invert the image # Invert the image
data = map(lambda i: 255 - i, data) data = list(map(lambda i: 255 - i, data))
# Quanitize 8-bit values into 4-bits # Quanitize 8-bit values into 4-bits
data = map(lambda i: i >> 4, data) data = list(map(lambda i: i >> 4, data))
# Make sure there is an even number of elements # Make sure there is an even number of elements
if (len(data) & 1) == 1: if (len(data) & 1) == 1:
result.append(0) data.append(0)
# Combine each two adjacent values into one # Combine each two adjacent values into one
i = iter(data) i = iter(data)
data = map(lambda a, b: a << 4 | b, i ,i) data = list(map(lambda a, b: a << 4 | b, i ,i))
# Pack the data # Pack the data
data = pack_rle(data) data = pack_rle(data)
# Convert values into hex strings # Convert values into hex strings
return map(lambda a: "0x" + format(a, '02x'), data) return list(map(lambda a: "0x" + format(a, '02x'), data))
def end_row(self, y): def end_row(self, y):
# Pad each row into even number of values # Pad each row into even number of values

View file

@ -1016,7 +1016,7 @@ namespace ExtUI {
} }
const char* FileList::filename() { const char* FileList::filename() {
return IFSD(card.longFilename[0] ? card.longFilename : card.filename, ""); return IFSD(card.longest_filename(), "");
} }
const char* FileList::shortFilename() { const char* FileList::shortFilename() {

View file

@ -1077,7 +1077,7 @@ int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
// If we have a longFilename buffer, mark it as invalid. // If we have a longFilename buffer, mark it as invalid.
// If a long filename is found it will be filled automatically. // If a long filename is found it will be filled automatically.
if (longFilename) longFilename[0] = '\0'; if (longFilename) { longFilename[0] = '\0'; longFilename[1] = '\0'; }
while (1) { while (1) {
@ -1089,7 +1089,7 @@ int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
// skip deleted entry and entry for . and .. // skip deleted entry and entry for . and ..
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') { if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
if (longFilename) longFilename[0] = '\0'; // Invalidate erased file long name, if any if (longFilename) { longFilename[0] = '\0'; longFilename[1] = '\0'; } // Invalidate erased file long name, if any
continue; continue;
} }