From d73d88a10bd69a7e54f73ea93902d1a4963aa99c Mon Sep 17 00:00:00 2001 From: philmoz Date: Sat, 30 Mar 2024 11:57:30 +1100 Subject: [PATCH] fix(bw): language special characters not working for 10x14 font size (#4816) Also cleans up the font handling to make the different font sizes more consistent. It will now allow more than 64 special characters for language translation (if it is ever required). --- radio/src/gui/128x64/lcd.cpp | 111 ++++++++++++-------------- radio/src/gui/128x64/lcd.h | 6 +- radio/src/gui/212x64/lcd.cpp | 110 ++++++++++++------------- radio/src/gui/212x64/lcd.h | 6 +- radio/src/gui/common/stdlcd/fonts.cpp | 86 ++++++++++++-------- radio/src/gui/common/stdlcd/fonts.h | 31 +++---- radio/src/gui/common/stdlcd/utf8.cpp | 8 +- 7 files changed, 178 insertions(+), 180 deletions(-) diff --git a/radio/src/gui/128x64/lcd.cpp b/radio/src/gui/128x64/lcd.cpp index 47c25b1a586..bcc4b4457a0 100644 --- a/radio/src/gui/128x64/lcd.cpp +++ b/radio/src/gui/128x64/lcd.cpp @@ -162,70 +162,72 @@ uint8_t getPatternWidth(const PatternData * pattern) LcdFlags getCharPattern(PatternData * pattern, unsigned char c, LcdFlags flags) { #if !defined(BOOT) + static const uint8_t fontWidth[] = { 5, 3, 5, 8, 10, 22, 5 }; + static const uint8_t fontHeight[] = { 7, 5, 6, 12, 16, 38, 7 }; + uint32_t fontsize = FONTSIZE(flags); unsigned char c_remapped = 0; if (fontsize == DBLSIZE || (flags & BOLD)) { // To save space only some DBLSIZE and BOLD chars are available // c has to be remapped. All non existing chars mapped to 0 (space) - if (c>=',' && c<=':') + if (c >= ',' && c <= ':') c_remapped = c - ',' + 1; - else if (c>='A' && c<='Z') + else if (c >= 'A' && c <= 'Z') c_remapped = c - 'A' + 16; - else if (c>='a' && c<='z') + else if (c >= 'a' && c <= 'z') c_remapped = c - 'a' + 42; - else if (c=='_') + else if (c == '_') c_remapped = 4; - else if (c!=' ') - flags &= ~BOLD; + else if (c != ' ') + flags &= ~BOLD; // For BOLD use Standard font if character is not in BOLD } - if (fontsize == DBLSIZE) { - pattern->width = 10; - pattern->height = 16; - if (c >= 0xC0) { - pattern->data = &font_10x14_extra[((uint16_t)(c-0xC0))*20]; - } - else { - if (c >= 128) - c_remapped = c - 81; - pattern->data = &font_10x14[((uint16_t)c_remapped)*20]; - } - } - else if (fontsize == XXLSIZE) { - pattern->width = 22; - pattern->height = 38; - pattern->data = &font_22x38_num[((uint16_t)c-'0'+5)*110]; - } - else if (fontsize == MIDSIZE) { - pattern->width = 8; - pattern->height = 12; - pattern->data = &font_8x10[((uint16_t)c-0x20)*16]; - } - else if (fontsize == SMLSIZE) { - pattern->width = 5; - pattern->height = 6; - pattern->data = (c < 0xc0 ? &font_4x6[(c-0x20)*5] : &font_4x6_extra[(c-0xc0)*5]); - } - else if (fontsize == TINSIZE) { - pattern->width = 3; - pattern->height = 5; - pattern->data = &font_3x5[((uint16_t)c-0x20)*3]; - } - else if (flags & BOLD) { - pattern->width = 5; - pattern->height = 7; - pattern->data = &font_5x7_B[c_remapped*5]; - } - else { - pattern->width = 5; - pattern->height = 7; - pattern->data = &font_5x7[(c - 0x20) * 5]; - } + uint8_t fontIdx = fontsize >> 8; + if (fontIdx == 0 && flags & BOLD) fontIdx = 6; + + pattern->width = fontWidth[fontIdx]; + pattern->height = fontHeight[fontIdx]; + int charSize = (pattern->height + 7) / 8 * pattern->width; + + switch (fontIdx) { + case 0: // Standard + pattern->data = &font_5x7[(c - FONT_BASE_START) * charSize]; + break; + case 1: // TINSIZE + pattern->data = &font_3x5[(c - FONT_BASE_START) * charSize]; + break; + case 2: // SMLSIZE + // Adjust language special characters offset + if (c >= FONT_LANG_START) + c = c - (FONT_SYMS_CNT - FONT_SYMS_CNT_4x6); + pattern->data = &font_4x6[(c - FONT_BASE_START) * charSize]; + break; + case 3: // MDLSIZE + // Adjust language special characters offset + if (c >= FONT_LANG_START) + c = c - FONT_SYMS_CNT; + pattern->data = &font_8x10[(c - FONT_BASE_START) * charSize]; + break; + case 4: // DBLSIZE + // Adjust language special characters offset and symbols offset + if (c >= FONT_LANG_START) + c_remapped = c - (FONT_BASE_CNT - FONT_BASE_CNT_10x14) - (FONT_SYMS_CNT - FONT_SYMS_CNT_10x14) - FONT_BASE_START; + else if (c >= FONT_SYMS_START) + c_remapped = c - (FONT_BASE_CNT - FONT_BASE_CNT_10x14) - FONT_BASE_START; + pattern->data = &font_10x14[(c_remapped) * charSize]; + break; + case 5: // XXLSIZE + pattern->data = &font_22x38_num[(c - '0' + 5) * charSize]; + break; + case 6: // BOLD + pattern->data = &font_5x7_B[c_remapped * charSize]; + break; + }; #else pattern->width = 5; pattern->height = 7; - pattern->data = &font_5x7[(c-0x20)*5]; + pattern->data = &font_5x7[(c - FONT_BASE_START) * 5]; #endif return flags; } @@ -240,14 +242,9 @@ uint8_t getCharWidth(char c, LcdFlags flags) void lcdDrawChar(coord_t x, coord_t y, uint8_t c, LcdFlags flags) { lcdNextPos = x - 1; -#if defined(BOOT) - const uint8_t * data = &font_5x7[(c-0x20)*5]; - lcdPutPattern(x, y, data, 5, 7, flags); -#else PatternData pattern; flags = getCharPattern(&pattern, c, flags); lcdPutPattern(x, y, pattern.data, pattern.width, pattern.height, flags); -#endif } void lcdDrawChar(coord_t x, coord_t y, uint8_t c) @@ -260,12 +257,7 @@ uint8_t getTextWidth(const char * s, uint8_t len, LcdFlags flags) uint8_t width = 0; if (len == 0) len = strlen(s); while (len--) { -#if !defined(BOOT) unsigned char c = map_utf8_char(s, len); - if (c >= 0x95 && FONTSIZE(flags)) c -=21; -#else - unsigned char c = *s; -#endif if (!c) { break; } @@ -306,7 +298,6 @@ void lcdDrawSizedText(coord_t x, coord_t y, const char * s, uint8_t len, LcdFlag else if (c >= 0x20) { // UTF8 detection c = map_utf8_char(s, len); - if (c >= 0x95 && fontsize) c -=21; if (!c) break; lcdDrawChar(x, y, c, flags); diff --git a/radio/src/gui/128x64/lcd.h b/radio/src/gui/128x64/lcd.h index b126f6936db..97cda967256 100644 --- a/radio/src/gui/128x64/lcd.h +++ b/radio/src/gui/128x64/lcd.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _LCD_H_ -#define _LCD_H_ +#pragma once #include @@ -94,7 +93,6 @@ extern coord_t lcdNextPos; #define IS_IN_DISPLAY(p) ((p) >= displayBuf && (p) < DISPLAY_END) #define ASSERT_IN_DISPLAY(p) assert((p) >= displayBuf && (p) < DISPLAY_END) - void lcdDrawChar(coord_t x, coord_t y, uint8_t c); void lcdDrawChar(coord_t x, coord_t y, uint8_t c, LcdFlags flags); void lcdDrawCenteredText(coord_t y, const char * s, LcdFlags flags = 0); @@ -190,5 +188,3 @@ inline pixel_t getPixel(uint8_t x, uint8_t y) } uint8_t getTextWidth(const char * s, uint8_t len=0, LcdFlags flags=0); - -#endif // _LCD_H_ diff --git a/radio/src/gui/212x64/lcd.cpp b/radio/src/gui/212x64/lcd.cpp index 318c1035807..9b13bdb89d6 100644 --- a/radio/src/gui/212x64/lcd.cpp +++ b/radio/src/gui/212x64/lcd.cpp @@ -167,6 +167,9 @@ void lcdPutPattern(coord_t x, coord_t y, const uint8_t * pattern, uint8_t width, LcdFlags getCharPattern(PatternData * pattern, unsigned char c, LcdFlags flags) { #if !defined(BOOT) + static const uint8_t fontWidth[] = { 5, 3, 5, 8, 10, 22, 5 }; + static const uint8_t fontHeight[] = { 7, 5, 6, 12, 16, 38, 7 }; + uint32_t fontsize = FONTSIZE(flags); unsigned char c_remapped = 0; @@ -175,62 +178,61 @@ LcdFlags getCharPattern(PatternData * pattern, unsigned char c, LcdFlags flags) // c has to be remapped. All non existing chars mapped to 0 (space) if (c >= ',' && c <= ':') c_remapped = c - ',' + 1; - else if (c>='A' && c<='Z') + else if (c >= 'A' && c <= 'Z') c_remapped = c - 'A' + 16; - else if (c>='a' && c<='z') + else if (c >= 'a' && c <= 'z') c_remapped = c - 'a' + 42; - else if (c=='_') + else if (c == '_') c_remapped = 4; - else if (c!=' ') - flags &= ~BOLD; + else if (c != ' ') + flags &= ~BOLD; // For BOLD use Standard font if character is not in BOLD } - if (fontsize == DBLSIZE) { - pattern->width = 10; - pattern->height = 16; - if (c >= 0x80) { - pattern->data = &font_10x14_extra[((uint16_t) (c - 0x80)) * 20]; - } - else { - if (c >= 0x80) - c_remapped = c - 81; - pattern->data = &font_10x14[((uint16_t) c_remapped) * 20]; - } - } - else if (fontsize == XXLSIZE) { - pattern->width = 22; - pattern->height = 38; - pattern->data = &font_22x38_num[((uint16_t) c - '0' + 5) * 110]; - } - else if (fontsize == MIDSIZE) { - pattern->width = 8; - pattern->height = 12; - pattern->data = &font_8x10[((uint16_t) c - 0x20) * 16]; - } - else if (fontsize == SMLSIZE) { - pattern->width = 5; - pattern->height = 6; - pattern->data = (c < 0x80 ? &font_4x6[(c - 0x20) * 5] : &font_4x6_extra[(c - 0x80) * 5]); - } - else if (fontsize == TINSIZE) { - pattern->width = 3; - pattern->height = 5; - pattern->data = &font_3x5[((uint16_t) c - 0x20) * 3]; - } - else if (flags & BOLD) { - pattern->width = 5; - pattern->height = 7; - pattern->data = &font_5x7_B[c_remapped*5]; - } - else { - pattern->width = 5; - pattern->height = 7; - pattern->data = &font_5x7[(c - 0x20) * 5]; - } + uint8_t fontIdx = fontsize >> 8; + if (fontIdx == 0 && flags & BOLD) fontIdx = 6; + + pattern->width = fontWidth[fontIdx]; + pattern->height = fontHeight[fontIdx]; + int charSize = (pattern->height + 7) / 8 * pattern->width; + + switch (fontIdx) { + case 0: // Standard + pattern->data = &font_5x7[(c - FONT_BASE_START) * charSize]; + break; + case 1: // TINSIZE + pattern->data = &font_3x5[(c - FONT_BASE_START) * charSize]; + break; + case 2: // SMLSIZE + // Adjust language special characters offset + if (c >= FONT_LANG_START) + c = c - (FONT_SYMS_CNT - FONT_SYMS_CNT_4x6); + pattern->data = &font_4x6[(c - FONT_BASE_START) * charSize]; + break; + case 3: // MDLSIZE + // Adjust language special characters offset + if (c >= FONT_LANG_START) + c = c - FONT_SYMS_CNT; + pattern->data = &font_8x10[(c - FONT_BASE_START) * charSize]; + break; + case 4: // DBLSIZE + // Adjust language special characters offset and symbols offset + if (c >= FONT_LANG_START) + c_remapped = c - (FONT_BASE_CNT - FONT_BASE_CNT_10x14) - (FONT_SYMS_CNT - FONT_SYMS_CNT_10x14) - FONT_BASE_START; + else if (c >= FONT_SYMS_START) + c_remapped = c - (FONT_BASE_CNT - FONT_BASE_CNT_10x14) - FONT_BASE_START; + pattern->data = &font_10x14[(c_remapped) * charSize]; + break; + case 5: // XXLSIZE + pattern->data = &font_22x38_num[(c - '0' + 5) * charSize]; + break; + case 6: // BOLD + pattern->data = &font_5x7_B[c_remapped * charSize]; + break; + }; #else pattern->width = 5; pattern->height = 7; - pattern->data = &font_5x7[(c - 0x20) * 5]; + pattern->data = &font_5x7[(c - FONT_BASE_START) * 5]; #endif return flags; } @@ -245,14 +247,9 @@ uint8_t getCharWidth(char c, LcdFlags flags) void lcdDrawChar(coord_t x, coord_t y, uint8_t c, LcdFlags flags) { lcdNextPos = x - 1; -#if defined(BOOT) - const uint8_t * data = &font_5x7[(c-0x20)*5]; - lcdPutPattern(x, y, data, 5, 7, flags); -#else PatternData pattern; flags = getCharPattern(&pattern, c, flags); lcdPutPattern(x, y, pattern.data, pattern.width, pattern.height, flags); -#endif } void lcdDrawChar(coord_t x, coord_t y, uint8_t c) @@ -264,11 +261,7 @@ uint8_t getTextWidth(const char * s, uint8_t len, LcdFlags flags) { uint8_t width = 0; for (int i = 0; len == 0 || i < len; ++i) { -#if !defined(BOOT) - unsigned char c = *s; -#else - unsigned char c = *s; -#endif + unsigned char c = map_utf8_char(s, len); if (!c) { break; } @@ -309,7 +302,6 @@ void lcdDrawSizedText(coord_t x, coord_t y, const char * s, uint8_t len, LcdFlag #if !defined(BOOT) // UTF8 detection c = map_utf8_char(s, len); - if (c >= 0x95 && FONTSIZE(flags)) c -=21; if (!c) break; if (c == 46 && FONTSIZE(flags) == TINSIZE) { // '.' handling diff --git a/radio/src/gui/212x64/lcd.h b/radio/src/gui/212x64/lcd.h index 6d018c4ba7d..c7d6a3fa27f 100644 --- a/radio/src/gui/212x64/lcd.h +++ b/radio/src/gui/212x64/lcd.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _LCD_H_ -#define _LCD_H_ +#pragma once #include @@ -255,6 +254,3 @@ class RleBitmap coord_t pos; }; - - -#endif // _LCD_H_ diff --git a/radio/src/gui/common/stdlcd/fonts.cpp b/radio/src/gui/common/stdlcd/fonts.cpp index 0fe41b46ea2..74c3a33adb7 100644 --- a/radio/src/gui/common/stdlcd/fonts.cpp +++ b/radio/src/gui/common/stdlcd/fonts.cpp @@ -21,6 +21,32 @@ #include "fonts.h" +/* + Strings in EdgeTX are encoded using UTF8. Latin characters are single byte in the range 32 - 127. + Special characters for language translations and special symbols are encoded as 2-byte or 3-byte + sequences. + The UTF8 encoded characters are mapped to single byte characters before display. + The single byte characters are mapped to the various font sizes as per the table below: + + Char 3x5 4x6 5x7 5x7 BOLD 8x10 10x14 22x38 + Range TINSIZE SMLSIZE Standard BOLD MDLSIZE DBLSIZE XXLSIZE + ----- ------- ------- -------- -------- ------- ------- ------- + 0 - 31 not used not used not used not used not used not used not used + 31 - 127 Latin(1) Latin Latin Latin(2) Latin Latin(2) Latin(3) + 128 - 148 not used extra(4) extra(5) extra(6) not used extra(4) not used + 149 - 255 not used Language Language Language(7) Language Language not used + + Notes: + (1) - reduced character set, contains only space, upper case letters, numbers, '-' and '.'. + (2) - reduced character set, contains only space, alphanumeric, ',', '.', '-', ':' and '_'. + (3) - reduced character set, contains only space, numbers, ',', '.', '-', ':' and '_'. + Note: to display ' ' use '+', to display '_' use '/'. + (4) - arrows + (5) - arrows and symbols (e.g. delta, stick, switch, etc) + (6) - uses the 5x7 arrow and symbol font characters (not bold) + (7) - uses the 5x7 Language font characters (not bold) +*/ + const unsigned char font_5x7[] = { #include "font_05x07.lbm" #include "font_05x07_extra.lbm" @@ -58,31 +84,32 @@ const unsigned char font_5x7_B[] = { const unsigned char font_10x14[] = { #include "font_10x14_compressed.lbm" - #if defined(TRANSLATIONS_DE) - #include "font_de_10x14.lbm" - #elif defined(TRANSLATIONS_DA) - #include "font_da_10x14.lbm" - #elif defined(TRANSLATIONS_CZ) - #include "font_cz_10x14.lbm" - #elif defined(TRANSLATIONS_ES) - #include "font_es_10x14.lbm" - #elif defined(TRANSLATIONS_FI) - #include "font_fi_10x14.lbm" - #elif defined(TRANSLATIONS_FR) - #include "font_fr_10x14.lbm" - #elif defined(TRANSLATIONS_IT) - #include "font_it_10x14.lbm" - #elif defined(TRANSLATIONS_PL) - #include "font_pl_10x14.lbm" - #elif defined(TRANSLATIONS_PT) - #include "font_pt_10x14.lbm" - #elif defined(TRANSLATIONS_RU) - #include "font_ru_10x14.lbm" - #elif defined(TRANSLATIONS_SE) - #include "font_se_10x14.lbm" - #elif defined(TRANSLATIONS_UA) - #include "font_ua_10x14.lbm" - #endif +#include "font_10x14_extra.lbm" +#if defined(TRANSLATIONS_DE) +#include "font_de_10x14.lbm" +#elif defined(TRANSLATIONS_DA) +#include "font_da_10x14.lbm" +#elif defined(TRANSLATIONS_CZ) +#include "font_cz_10x14.lbm" +#elif defined(TRANSLATIONS_ES) +#include "font_es_10x14.lbm" +#elif defined(TRANSLATIONS_FI) +#include "font_fi_10x14.lbm" +#elif defined(TRANSLATIONS_FR) +#include "font_fr_10x14.lbm" +#elif defined(TRANSLATIONS_IT) +#include "font_it_10x14.lbm" +#elif defined(TRANSLATIONS_PL) +#include "font_pl_10x14.lbm" +#elif defined(TRANSLATIONS_PT) +#include "font_pt_10x14.lbm" +#elif defined(TRANSLATIONS_RU) +#include "font_ru_10x14.lbm" +#elif defined(TRANSLATIONS_SE) +#include "font_se_10x14.lbm" +#elif defined(TRANSLATIONS_UA) +#include "font_ua_10x14.lbm" +#endif }; const unsigned char font_3x5[] = { @@ -91,6 +118,7 @@ const unsigned char font_3x5[] = { const unsigned char font_4x6[] = { #include "font_04x06.lbm" +#include "font_04x06_extra.lbm" #if defined(TRANSLATIONS_DE) #include "font_de_04x06.lbm" #elif defined(TRANSLATIONS_DA) @@ -151,12 +179,4 @@ const unsigned char font_22x38_num[] = { #include "font_22x38_num.lbm" }; -const unsigned char font_4x6_extra[] = { -#include "font_04x06_extra.lbm" -}; - -const unsigned char font_10x14_extra[] = { -#include "font_10x14_extra.lbm" -}; - #endif // !defined(BOOT) diff --git a/radio/src/gui/common/stdlcd/fonts.h b/radio/src/gui/common/stdlcd/fonts.h index e4ab192ed88..9252bca7ad8 100644 --- a/radio/src/gui/common/stdlcd/fonts.h +++ b/radio/src/gui/common/stdlcd/fonts.h @@ -19,20 +19,23 @@ * GNU General Public License for more details. */ -#ifndef _FONTS_H_ -#define _FONTS_H_ +#pragma once -extern const unsigned char font_5x7[]; -extern const unsigned char font_10x14[]; +constexpr int FONT_BASE_START = 0x20; +constexpr int FONT_SYMS_START = 0x80; +constexpr int FONT_LANG_START = 0x95; + +constexpr int FONT_BASE_CNT = 96; // Number of characters in standard 5x7 font +constexpr int FONT_BASE_CNT_10x14 = 68; // Number of characters in compressed 10x14 font -#if !defined(BOOT) - extern const unsigned char font_5x7_B[]; - extern const unsigned char font_3x5[]; - extern const unsigned char font_4x6[]; - extern const unsigned char font_8x10[]; - extern const unsigned char font_22x38_num[]; - extern const unsigned char font_10x14_extra[]; - extern const unsigned char font_4x6_extra[]; -#endif +constexpr int FONT_SYMS_CNT = 21; // Max # of extra symbols (based on 5x7 standard font) +constexpr int FONT_SYMS_CNT_4x6 = 8; // # of extra symbols in 4x6 font (adjust if font is changed) +constexpr int FONT_SYMS_CNT_10x14 = 8; // # of extra symbols in 10x14 font (adjust if font is changed) -#endif // _FONTS_H_ +extern const unsigned char font_5x7[]; +extern const unsigned char font_5x7_B[]; +extern const unsigned char font_3x5[]; +extern const unsigned char font_4x6[]; +extern const unsigned char font_8x10[]; +extern const unsigned char font_10x14[]; +extern const unsigned char font_22x38_num[]; diff --git a/radio/src/gui/common/stdlcd/utf8.cpp b/radio/src/gui/common/stdlcd/utf8.cpp index e7dcb627b13..8513c0bcf77 100644 --- a/radio/src/gui/common/stdlcd/utf8.cpp +++ b/radio/src/gui/common/stdlcd/utf8.cpp @@ -21,6 +21,7 @@ /* -*- coding: utf-8 -*- */ #include +#include "fonts.h" #include "definitions.h" #include "translations/untranslated.h" @@ -141,7 +142,7 @@ static unsigned char lookup_utf8_mapping(wchar_t w) { for (uint32_t i=0; i < DIM(_utf8_lut); i++) { if (w == _utf8_lut[i]) - return 0x95 + (uint8_t)i; // TODO: use constant + return FONT_LANG_START + (uint8_t)i; } return 0x20; // return 'space' for unknown chars } @@ -177,8 +178,7 @@ unsigned char map_utf8_char(const char*& s, uint8_t& len) len--; s++; c = *s; w |= c & 0x3F; } - // TODO: use constants - if (w >= 0x80 && w <= 0x94) { // extra chars + if (w >= FONT_SYMS_START && w < FONT_LANG_START) { // extra chars return (unsigned char)w; } if(w == L'≥') @@ -187,7 +187,7 @@ unsigned char map_utf8_char(const char*& s, uint8_t& len) return STR_CHAR_BW_DEGREE; #if defined(UTF8_SUBS_LUT) auto w_map = lookup_utf8_substitution(w); - if (w_map> 0x95) + if (w_map> FONT_LANG_START) w_map = lookup_utf8_mapping(w_map); return w_map; #elif !defined(NO_UTF8_LUT)