refactor / cleanup font selection logic
* centralize font selection logic into getFontInfo() * removed unneeded parameter "numberOfChars" from drawText() * new file: wled_fonts.hpp to centralize font management logic (inline) * only compile wchar16ToCodepage437 when WLED_ENABLE_FULL_FONTS * minor cleanup
This commit is contained in:
@@ -6817,7 +6817,7 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
char text[WLED_MAX_SEGNAME_LEN+1] = {'\0'};
|
char text[WLED_MAX_SEGNAME_LEN+1] = {'\0'};
|
||||||
unsigned maxLen = (SEGMENT.name) ? min(WLED_MAX_SEGNAME_LEN, (int)strlen(SEGMENT.name)) : 0; // WLEDMM make it robust against too long segment names
|
unsigned maxLen = (SEGMENT.name) ? min(WLED_MAX_SEGNAME_LEN, (int)strlen(SEGMENT.name)) : 0; // WLEDMM make it robust against too long segment names
|
||||||
|
|
||||||
#if !defined(WLED_ENABLE_FULL_FONTS)
|
#if !defined(WLED_ENABLE_FULL_FONTS) || defined(ESP8266)
|
||||||
if (SEGMENT.name) for (size_t i=0,j=0; i<maxLen; i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i]; // unicode killer
|
if (SEGMENT.name) for (size_t i=0,j=0; i<maxLen; i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i]; // unicode killer
|
||||||
#else
|
#else
|
||||||
if (SEGMENT.name) for (size_t i=0,j=0; i<maxLen; i++) text[j++] = SEGMENT.name[i]; // don't kill unicode
|
if (SEGMENT.name) for (size_t i=0,j=0; i<maxLen; i++) text[j++] = SEGMENT.name[i]; // don't kill unicode
|
||||||
@@ -6865,12 +6865,12 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
else if ((!strncmp_P(text,PSTR("#AMP"),4)) || (!strncmp_P(text,PSTR("#POW"),4))) sprintf_P(text, PSTR("%3.1fA"), float(strip.currentMilliamps)/1000.0f); // WLEDMM
|
else if ((!strncmp_P(text,PSTR("#AMP"),4)) || (!strncmp_P(text,PSTR("#POW"),4))) sprintf_P(text, PSTR("%3.1fA"), float(strip.currentMilliamps)/1000.0f); // WLEDMM
|
||||||
else sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
else sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
||||||
} else drawShadow = false; // static text does not require shadow
|
} else drawShadow = false; // static text does not require shadow
|
||||||
|
const int numberOfChars = strlen(text); // bytes count after macros expansions
|
||||||
|
|
||||||
const int numberOfChars = strlen(text);
|
#if !defined(WLED_ENABLE_FULL_FONTS) || defined(ESP8266)
|
||||||
#if defined(WLED_ENABLE_FULL_FONTS)
|
|
||||||
const int numberOfLetters = strlenUC((unsigned char *)text); // get the mumber of unicode letters
|
|
||||||
#else
|
|
||||||
const int numberOfLetters = numberOfChars;
|
const int numberOfLetters = numberOfChars;
|
||||||
|
#else
|
||||||
|
const int numberOfLetters = strlenUC((unsigned char *)text); // get the mumber of unicode letters
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
long delayTime = long(strip.now) - long(SEGENV.step);
|
long delayTime = long(strip.now) - long(SEGENV.step);
|
||||||
@@ -6910,13 +6910,13 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
col1 = SEGCOLOR(0);
|
col1 = SEGCOLOR(0);
|
||||||
col2 = SEGCOLOR(2);
|
col2 = SEGCOLOR(2);
|
||||||
}
|
}
|
||||||
maxLen = numberOfChars; // Ensure maxLen reflects the actual rendered text, not the original SEGMENT.name // ToDO remove double parameter
|
maxLen = numberOfChars; // Ensure maxLen reflects the actual rendered text, not the original SEGMENT.name length
|
||||||
SEGMENT.drawText((unsigned char*)text, maxLen, numberOfChars, int(cols) - int(SEGENV.aux0), yoffset, letterWidth, letterHeight, col1, col2, drawShadow);
|
SEGMENT.drawText((unsigned char*)text, maxLen, int(cols) - int(SEGENV.aux0), yoffset, letterWidth, letterHeight, col1, col2, drawShadow);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// WLEDMM add some blur
|
// WLEDMM add some blur
|
||||||
if (SEGMENT.check3) {
|
if (SEGMENT.check3 && !SEGMENT.check2) { // blur looks ugly together with "overlay"
|
||||||
if (SEGMENT.custom1 < 16) SEGMENT.blurRows(16); // only blur if no trail
|
if (SEGMENT.custom1 < 16) SEGMENT.blurRows(16); // only blur rows when no trail
|
||||||
SEGMENT.blurCols(20);
|
SEGMENT.blurCols(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -827,7 +827,7 @@ typedef struct Segment {
|
|||||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, bool drawShadow = false);
|
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, bool drawShadow = false);
|
||||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, uint32_t(c) & 0x00FFFFFF, uint32_t(c2) & 0x00FFFFFF); } // automatic inline
|
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, uint32_t(c) & 0x00FFFFFF, uint32_t(c2) & 0x00FFFFFF); } // automatic inline
|
||||||
// unicode-aware wrapper for drawCharacter(), to be called from mode_2Dscrollingtext()
|
// unicode-aware wrapper for drawCharacter(), to be called from mode_2Dscrollingtext()
|
||||||
void drawText(const unsigned char* text, size_t maxLen, int maxLetters, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, bool drawShadow = false);
|
void drawText(const unsigned char* text, size_t maxLen, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, bool drawShadow = false);
|
||||||
// #if !WLED_ENABLE_FULL_FONTS => drawText() will fall back to just forwarding each char to drawCharacter()
|
// #if !WLED_ENABLE_FULL_FONTS => drawText() will fall back to just forwarding each char to drawCharacter()
|
||||||
|
|
||||||
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
||||||
|
|||||||
@@ -877,41 +877,35 @@ bool Segment::jsonToPixels(char * name, uint8_t fileNr) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "src/font/console_font_4x6.h"
|
#include "wled_fonts.hpp"
|
||||||
#include "src/font/console_font_5x8.h"
|
|
||||||
#include "src/font/console_font_5x12.h"
|
|
||||||
#include "src/font/console_font_6x8.h"
|
|
||||||
#include "src/font/console_font_7x9.h"
|
|
||||||
#if defined(WLED_ENABLE_FULL_FONTS)
|
#if defined(WLED_ENABLE_FULL_FONTS)
|
||||||
#include "src/font/codepages.h"
|
#include "src/font/codepages.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// unicode-aware wrapper for drawCharacter(), to be called from mode_2Dscrollingtext()
|
// unicode-aware wrapper for drawCharacter(), to be called from mode_2Dscrollingtext()
|
||||||
void Segment::drawText(const unsigned char* text, size_t maxLen, int maxLetters, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, bool drawShadow) {
|
void Segment::drawText(const unsigned char* text, size_t maxLen, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, bool drawShadow) {
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
// ToDO: find font _first/_last, based on width / height
|
//size_t maxLetters = WLED_MAX_SEGNAME_LEN;
|
||||||
|
const size_t numberOfChars = strlen((const char *) text); // size in bytes // toDo check if this is duplicate -> maxLen
|
||||||
|
|
||||||
#if defined(WLED_ENABLE_FULL_FONTS)
|
#if defined(WLED_ENABLE_FULL_FONTS)
|
||||||
|
FontInfo_t font = getFontInfo(w, h); // use central font selection legic
|
||||||
uint16_t decoded_text[WLED_MAX_SEGNAME_LEN+1] = { 0 }; // UTF-16 converted text. Cannot be longer than WLED_MAX_SEGNAME_LEN
|
uint16_t decoded_text[WLED_MAX_SEGNAME_LEN+1] = { 0 }; // UTF-16 converted text. Cannot be longer than WLED_MAX_SEGNAME_LEN
|
||||||
size_t utf16_index = 0;
|
size_t utf16_index = 0;
|
||||||
for(const unsigned char* now = text; now != nullptr && now[0] != '\0'; now = nextUnicode(now, maxLen)) {
|
for(const unsigned char* now = text; now != nullptr && now[0] != '\0'; now = nextUnicode(now, maxLen)) {
|
||||||
if (utf16_index < WLED_MAX_SEGNAME_LEN) {
|
if (utf16_index < WLED_MAX_SEGNAME_LEN) {
|
||||||
decoded_text[utf16_index] = unicodeToWchar16(now, maxLen); // UTF-8 decode into decoded_text
|
decoded_text[utf16_index] = unicodeToWchar16(now, maxLen); // UTF-8 decode into decoded_text
|
||||||
decoded_text[utf16_index] = wchar16ToCodepage437(decoded_text[utf16_index]); // decoded_text to CP437 (in-place conversion)
|
decoded_text[utf16_index] = wchar16ToCodepage437(decoded_text[utf16_index]); // decoded_text to CP437 (in-place conversion)
|
||||||
if ((decoded_text[utf16_index] >= 1) && ((decoded_text[utf16_index] <= 254))) utf16_index++; // don't advance on NUL or codes not suppoted in DrawCharacter
|
if ((decoded_text[utf16_index] >= font.firstChar) && ((decoded_text[utf16_index] <= font.lastChar))) // don't advance on NUL, or on codes not suppoted in DrawCharacter
|
||||||
|
utf16_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decoded_text[utf16_index] = 0; // NUL terminate string
|
decoded_text[utf16_index] = 0; // NUL terminate string
|
||||||
size_t textLength = min(utf16_index, size_t(maxLetters));
|
size_t textLength = min(utf16_index, numberOfChars);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
const unsigned char* decoded_text = text; // fallback
|
const unsigned char* decoded_text = text; // fallback
|
||||||
size_t textLength = min(strnlen((char*)text, maxLen), size_t(maxLetters));
|
size_t textLength = min(strnlen((char*)text, maxLen), numberOfChars);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// toDo: ensure that decoded_text[i] is between console_font_YxZ_first and console_font_YxZ_last
|
|
||||||
// if (chr < 32 || chr > 126) --> clamp chr
|
|
||||||
// chr -= 32; // align with font table entries
|
|
||||||
|
|
||||||
// pass characters to drawCharacter()
|
// pass characters to drawCharacter()
|
||||||
for (int i = 0; i < textLength; i++) {
|
for (int i = 0; i < textLength; i++) {
|
||||||
SEGMENT.drawCharacter((unsigned char) decoded_text[i], x + w*i, y, w, h, color, col2, drawShadow);
|
SEGMENT.drawCharacter((unsigned char) decoded_text[i], x + w*i, y, w, h, color, col2, drawShadow);
|
||||||
@@ -922,18 +916,12 @@ void Segment::drawText(const unsigned char* text, size_t maxLen, int maxLetters,
|
|||||||
// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM
|
// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM
|
||||||
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, bool drawShadow) {
|
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, bool drawShadow) {
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
#if !defined(WLED_ENABLE_FULL_FONTS)
|
|
||||||
if (chr < 32 || chr > 126) return; // legacy mode - only ASCII 32-126 supported
|
|
||||||
chr -= 32; // align with font table entries
|
|
||||||
#else
|
|
||||||
// ToDO: clamp to actual font limits
|
|
||||||
if (chr < 1 || chr > 254) return; // sanity check // ToDO needs improvements
|
|
||||||
chr = chr -1; // all fonts start at 1 // ToDO needs improvements
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const uint16_t cols = virtualWidth();
|
const uint16_t cols = virtualWidth();
|
||||||
const uint16_t rows = virtualHeight();
|
const uint16_t rows = virtualHeight();
|
||||||
const int font = w*h;
|
FontInfo_t font = getFontInfo(w, h); // use central font selection logic
|
||||||
|
if (!font.isProgMem || font.width_bytes > 1) return; // do nothing for not (yet) supported font features: width_bytes > 1, !isProgMem
|
||||||
|
if (chr < font.firstChar || chr > font.lastChar) return; // do nothing when out of limits
|
||||||
|
chr = chr - font.firstChar; // adjust chr to point to the first allowed character byte
|
||||||
|
|
||||||
CRGB col = CRGB(color);
|
CRGB col = CRGB(color);
|
||||||
CRGBPalette16 grad = CRGBPalette16(col, (col2 != BLACK) ? CRGB(col2) : col);
|
CRGBPalette16 grad = CRGBPalette16(col, (col2 != BLACK) ? CRGB(col2) : col);
|
||||||
@@ -941,16 +929,21 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
|||||||
|
|
||||||
//if (w<5 || w>6 || h!=8) return;
|
//if (w<5 || w>6 || h!=8) return;
|
||||||
if (drawShadow) w++; // one more column for shadow on right side
|
if (drawShadow) w++; // one more column for shadow on right side
|
||||||
for (int i = 0; i<h; i++) { // character height
|
for (int i = 0; i<h; i++) { // // paint character - top down by row (height)
|
||||||
int y0 = y + i;
|
int y0 = y + i;
|
||||||
if (y0 < 0) continue; // drawing off-screen
|
if (y0 < 0) continue; // drawing off-screen
|
||||||
if (y0 >= rows) break; // drawing off-screen
|
if (y0 >= rows) break; // drawing off-screen
|
||||||
uint8_t bits = 0;
|
uint8_t bits = 0;
|
||||||
uint8_t bits_up = 0; // WLEDMM this is the previous line: font[(chr * h) + i -1]
|
uint8_t bits_up = 0; // WLEDMM this is the previous line: font[(chr * h) + i -1]
|
||||||
|
|
||||||
// ToDO: move font selection logic into separate function
|
#if 1
|
||||||
|
// new code - experimental
|
||||||
switch (font) { // font = w * h
|
bits = pgm_read_byte_near(&font.raw[(chr * h) + i]);
|
||||||
|
if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&font.raw[(chr * h) + i -1]);
|
||||||
|
#else
|
||||||
|
// legacy code, will be deleted after some tests
|
||||||
|
int pixels = w*h;
|
||||||
|
switch (pixels) { // font = w * h
|
||||||
case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]);
|
case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]);
|
||||||
if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&console_font_4x6[(chr * h) + i -1]);
|
if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&console_font_4x6[(chr * h) + i -1]);
|
||||||
break; // 4x6 font
|
break; // 4x6 font
|
||||||
@@ -968,17 +961,18 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
|||||||
break; // 5x12 font
|
break; // 5x12 font
|
||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (col2 != BLACK) col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
|
if (col2 != BLACK) col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
|
||||||
uint32_t fgCol = uint32_t(col) & 0x00FFFFFF; // WLEDMM cache color value
|
uint32_t fgCol = uint32_t(col) & 0x00FFFFFF; // WLEDMM cache color value
|
||||||
|
|
||||||
for (int j = 0; j<w; j++) { // character width
|
for (int j = 0; j<w; j++) { // paint character - single row of pixels (width)
|
||||||
int x0 = x + (w-1) - j;
|
int x0 = x + (w-1) - j;
|
||||||
if (unsigned(x0) < cols) { // WLEDMM same as "x0 > 0 && x0 < cols"
|
if (unsigned(x0) < cols) { // WLEDMM same as "x0 > 0 && x0 < cols"
|
||||||
if ((bits>>(j+(8-w))) & 0x01) { // bit set & drawing on-screen
|
if ((bits>>(j+(8-w))) & 0x01) { // bit set & drawing on-screen
|
||||||
setPixelColorXY(x0, y0, fgCol);
|
setPixelColorXY(x0, y0, fgCol);
|
||||||
} else {
|
} else {
|
||||||
if (drawShadow) {
|
if (drawShadow) {
|
||||||
// WLEDMM
|
// WLEDMM
|
||||||
if ((j < (w-1)) && (bits>>(j+(8-w) +1)) & 0x01) setPixelColorXY(x0, y0, bgCol); // blank when pixel to the right is set
|
if ((j < (w-1)) && (bits>>(j+(8-w) +1)) & 0x01) setPixelColorXY(x0, y0, bgCol); // blank when pixel to the right is set
|
||||||
else if ((j > 0) && (bits>>(j+(8-w) -1)) & 0x01) setPixelColorXY(x0, y0, bgCol);// blank when pixel to the left is set
|
else if ((j > 0) && (bits>>(j+(8-w) -1)) & 0x01) setPixelColorXY(x0, y0, bgCol);// blank when pixel to the left is set
|
||||||
else if ((bits_up>>(j+(8-w))) & 0x01) setPixelColorXY(x0, y0, bgCol); // blank when pixel above is set
|
else if ((bits_up>>(j+(8-w))) & 0x01) setPixelColorXY(x0, y0, bgCol); // blank when pixel above is set
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#if defined(WLED_ENABLE_FULL_FONTS)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@title WLED(-MM) - unicode to CP437 conversion
|
@title WLED(-MM) - unicode to CP437 conversion
|
||||||
@repo https://github.com/MoonModules/WLED-MM, https://github.com/wled/WLED
|
@repo https://github.com/MoonModules/WLED-MM, https://github.com/wled/WLED
|
||||||
@@ -7,6 +5,8 @@
|
|||||||
@license Licensed under the EUPL-1.2 or later
|
@license Licensed under the EUPL-1.2 or later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined(WLED_ENABLE_FULL_FONTS)
|
||||||
|
|
||||||
#include "codepages.h"
|
#include "codepages.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#undef WLED_ENABLE_FULL_FONTS
|
#undef WLED_ENABLE_FULL_FONTS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// visual replacements when decoding fails
|
// UTF-16 visual replacements when decoding fails
|
||||||
//constexpr uint16_t UNKNOWN_CODE = 0x2219; // ∙ multiplication dot (try this if you don't like the middle dot)
|
//constexpr uint16_t UNKNOWN_CODE = 0x2219; // ∙ multiplication dot (try this if you don't like the middle dot)
|
||||||
constexpr uint16_t UNKNOWN_CODE = 0x00B7; // · middle dot = unknown code (generic error)
|
constexpr uint16_t UNKNOWN_CODE = 0x00B7; // · middle dot = unknown code (generic error)
|
||||||
constexpr uint16_t BAD_CODE = 0x2022; // • bigger dot = cannot decode (unicode malformed)
|
constexpr uint16_t BAD_CODE = 0x2022; // • bigger dot = cannot decode (unicode malformed)
|
||||||
@@ -19,6 +19,11 @@ constexpr uint16_t EXT_CODE = 0x263B; // ☻ smiling face = extended cod
|
|||||||
// return "•" in case of input errors, and for unsupported/invalid UTF-8
|
// return "•" in case of input errors, and for unsupported/invalid UTF-8
|
||||||
uint16_t unicodeToWchar16(const unsigned char* utf8, size_t maxLen); // unicodetool.cpp
|
uint16_t unicodeToWchar16(const unsigned char* utf8, size_t maxLen); // unicodetool.cpp
|
||||||
|
|
||||||
|
#if defined(WLED_ENABLE_FULL_FONTS)
|
||||||
|
// translates unicode 2-byte (UTF-16) "code point" into corresponding character in codepage 437 (IBM PC aka PC-8)
|
||||||
|
uint16_t wchar16ToCodepage437(uint16_t wideChar); // codepage437.cpp
|
||||||
|
#endif
|
||||||
|
|
||||||
// returns a pointer to the next unicode item - can be used to "advance" conversion after unicodeToWchar16()
|
// returns a pointer to the next unicode item - can be used to "advance" conversion after unicodeToWchar16()
|
||||||
// return nullptr at end of input
|
// return nullptr at end of input
|
||||||
const unsigned char* nextUnicode(const unsigned char* utf8, size_t maxLen); // unicodetool.cpp
|
const unsigned char* nextUnicode(const unsigned char* utf8, size_t maxLen); // unicodetool.cpp
|
||||||
@@ -30,7 +35,16 @@ size_t strlenUC(const unsigned char* utf8);
|
|||||||
// Important: calling code is responsible to provide a string with at least _where_ chars
|
// Important: calling code is responsible to provide a string with at least _where_ chars
|
||||||
size_t cutUnicodeAt(const unsigned char* utf8, size_t where);
|
size_t cutUnicodeAt(const unsigned char* utf8, size_t where);
|
||||||
|
|
||||||
// translates unicode 2-byte (UTF-16) "code point" into corresponding character in codepage 437 (IBM PC aka PC-8)
|
|
||||||
uint16_t wchar16ToCodepage437(uint16_t wideChar); // codepage437.cpp
|
// special utility function for @troyhacks ;-)
|
||||||
|
// removes all unicode letter from a C style char[] - conversion is in-place, to avoid heap fragging
|
||||||
|
// doesn't work on PROGMEM strings, unless you strdup() them into RAM before calling this function
|
||||||
|
inline void killUnicode(unsigned char* utf8) {
|
||||||
|
if (utf8 == nullptr) return;
|
||||||
|
size_t clean_index = 0;
|
||||||
|
for (size_t i=0; utf8[i] != '\0'; i++)
|
||||||
|
if ((utf8[i] > 0) && (utf8[i] < 128)) utf8[clean_index++] = utf8[i]; // only keep pure ASCII; unicode extended chars start at 128
|
||||||
|
utf8[clean_index] = '\0'; // ensure proper string termination
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
87
wled00/wled_fonts.hpp
Normal file
87
wled00/wled_fonts.hpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef WLED_FONTS_H
|
||||||
|
#define WLED_FONTS_H
|
||||||
|
#include <stdlib.h> // needed to get uint16_t definition
|
||||||
|
#include <stdint.h> // helps for code analysis with clang
|
||||||
|
|
||||||
|
// always disable unicode for 8266 builds - not enough program space
|
||||||
|
#if !defined(ARDUINO_ARCH_ESP32) && defined(WLED_ENABLE_FULL_FONTS)
|
||||||
|
#undef WLED_ENABLE_FULL_FONTS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// pull in all fonts
|
||||||
|
#include "src/font/console_font_4x6.h"
|
||||||
|
#include "src/font/console_font_5x8.h"
|
||||||
|
#include "src/font/console_font_5x12.h"
|
||||||
|
#include "src/font/console_font_6x8.h"
|
||||||
|
#include "src/font/console_font_7x9.h"
|
||||||
|
|
||||||
|
|
||||||
|
// fontInfo struct returned by getFontInfo
|
||||||
|
typedef struct {
|
||||||
|
unsigned firstChar; // first supported glyph (32 for standard "reduced" fonts)
|
||||||
|
unsigned lastChar; // last supported glyph (126 for standard "reduced" fonts)
|
||||||
|
unsigned width_bytes; // single letter width in bytes (default:1)
|
||||||
|
// unsigned height_bytes; // future support
|
||||||
|
bool isProgMem; // raw data points into ProgMem => 8266 needs pgm_read_byte_near()
|
||||||
|
const unsigned char* raw; // array of bytes with raw pixeldata (typicially lives in PROGMEM)
|
||||||
|
// note: we only support monospaced fonts
|
||||||
|
} FontInfo_t;
|
||||||
|
|
||||||
|
// logic for font selection based on width and height
|
||||||
|
inline FontInfo_t getFontInfo(unsigned width, unsigned height) {
|
||||||
|
static FontInfo_t font = {0}; // not sure if this needs to be static - just wanted to be sure that the function return value is not in the stack area (use-after-free).
|
||||||
|
|
||||||
|
unsigned pixels = width * height;
|
||||||
|
switch (pixels) {
|
||||||
|
// WLED standard fonts (PROGMEM)
|
||||||
|
case 24: // 4x6 font
|
||||||
|
font.raw = console_font_4x6;
|
||||||
|
font.isProgMem = true;
|
||||||
|
font.firstChar = console_font_4x6_first;
|
||||||
|
font.lastChar = console_font_4x6_last;
|
||||||
|
font.width_bytes= 1;
|
||||||
|
break;
|
||||||
|
case 40: // 5x8 font
|
||||||
|
font.raw = console_font_5x8;
|
||||||
|
font.isProgMem = true;
|
||||||
|
font.firstChar = console_font_5x8_first;
|
||||||
|
font.lastChar = console_font_5x8_last;
|
||||||
|
font.width_bytes= 1;
|
||||||
|
break;
|
||||||
|
case 48: // 6x8 font
|
||||||
|
font.raw = console_font_6x8;
|
||||||
|
font.isProgMem = true;
|
||||||
|
font.firstChar = console_font_6x8_first;
|
||||||
|
font.lastChar = console_font_6x8_last;
|
||||||
|
font.width_bytes= 1;
|
||||||
|
break;
|
||||||
|
case 63: // 7x9 font
|
||||||
|
font.raw = console_font_7x9;
|
||||||
|
font.isProgMem = true;
|
||||||
|
font.firstChar = console_font_7x9_first;
|
||||||
|
font.lastChar = console_font_7x9_last;
|
||||||
|
font.width_bytes= 1;
|
||||||
|
break;
|
||||||
|
case 60: // 5x12 font
|
||||||
|
font.raw = console_font_5x12;
|
||||||
|
font.isProgMem = true;
|
||||||
|
font.firstChar = console_font_5x12_first;
|
||||||
|
font.lastChar = console_font_5x12_last;
|
||||||
|
font.width_bytes= 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// you can add any custom fonts here
|
||||||
|
|
||||||
|
default: // no font
|
||||||
|
font.raw = nullptr;
|
||||||
|
font.isProgMem = false;
|
||||||
|
font.firstChar = 1;
|
||||||
|
font.lastChar = 1;
|
||||||
|
font.width_bytes= 1;
|
||||||
|
}
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user