From 4c37986737acc77d32252ae8391800597f8896fb Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Fri, 22 May 2026 17:20:20 +0200 Subject: [PATCH] fix(eink): fix font layout and add Lemon font support to GxEPDDisplay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Layout fix: GxEPDDisplay was using proportional GFX fonts (FreeSans9pt/12pt) for sizes 1 and 2, giving lineHeight=16/20 instead of the 8/16 the UI layout expects (designed for the OLED's bitmap font). Replaced with the GFX built-in 6×8 bitmap font (size 1) and its 2× scaled variant 12×16 (size 2). Size 3 keeps FreeSans18pt for large headings. fontAscender updated accordingly: built-in font cursor is top-left (offset=0), Lemon GFX font adds 8px, only FreeSans18pt still adds 26px. Lemon font: LemonFont.h already stores the font in GFXfont format, so GxEPDDisplay can use it directly via display.setFont(&Lemon). Added _use_lemon flag, setLemonFont() override, and size-1 font selection in setTextSize()/startFrame(). Adafruit GFX handles UTF-8 decoding for GFX fonts, so Unicode characters (Cyrillic etc.) render correctly. The FONT setting in SettingsScreen now works on e-ink the same as on OLED. Co-Authored-By: Claude Sonnet 4.6 --- src/helpers/ui/GxEPDDisplay.cpp | 28 +++++++++++++++++++--------- src/helpers/ui/GxEPDDisplay.h | 10 ++++++++-- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/helpers/ui/GxEPDDisplay.cpp b/src/helpers/ui/GxEPDDisplay.cpp index 7c564aec..664607f0 100644 --- a/src/helpers/ui/GxEPDDisplay.cpp +++ b/src/helpers/ui/GxEPDDisplay.cpp @@ -16,10 +16,10 @@ // GFX fonts use the baseline as the cursor origin. UI code assumes top-of-cell // coordinates (same convention as the OLED driver). Add the font ascender so // the two conventions match. -static int fontAscender(int sz) { - if (sz == 3) return 26; // FreeSans18pt7b - if (sz == 2) return 17; // FreeSansBold12pt7b - return 13; // FreeSans9pt7b (sz == 1) +static int fontAscender(int sz, bool use_lemon) { + if (sz == 3) return 26; // FreeSans18pt7b: proportional font, baseline origin + if (use_lemon) return 8; // Lemon GFX font: baseline origin, typical ascender 8px + return 0; // GFX built-in font: cursor is top-left of cell } bool GxEPDDisplay::begin() { @@ -72,7 +72,8 @@ void GxEPDDisplay::startFrame(Color bkg) { display.fillScreen(GxEPD_WHITE); display.setTextColor(_curr_color = GxEPD_BLACK); _text_sz = 1; - display.setFont(&FreeSans9pt7b); + display.setFont(_use_lemon ? &Lemon : NULL); + display.setTextSize(1); display_crc.reset(); } @@ -80,9 +81,18 @@ void GxEPDDisplay::setTextSize(int sz) { _text_sz = sz; display_crc.update(sz); switch (sz) { - case 2: display.setFont(&FreeSansBold12pt7b); break; - case 3: display.setFont(&FreeSans18pt7b); break; - default: display.setFont(&FreeSans9pt7b); break; + case 3: + display.setFont(&FreeSans18pt7b); + display.setTextSize(1); + break; + case 2: + display.setFont(NULL); + display.setTextSize(2); + break; + default: + display.setFont(_use_lemon ? &Lemon : NULL); + display.setTextSize(1); + break; } } @@ -101,7 +111,7 @@ void GxEPDDisplay::setCursor(int x, int y) { display_crc.update(y); // Offset y by the font ascender: callers pass top-of-cell y, GFX fonts // expect baseline y. Without this, text would be clipped at the top. - display.setCursor(x, y + fontAscender(_text_sz)); + display.setCursor(x, y + fontAscender(_text_sz, _use_lemon)); } void GxEPDDisplay::print(const char* str) { diff --git a/src/helpers/ui/GxEPDDisplay.h b/src/helpers/ui/GxEPDDisplay.h index a5e7931b..278df610 100644 --- a/src/helpers/ui/GxEPDDisplay.h +++ b/src/helpers/ui/GxEPDDisplay.h @@ -15,6 +15,7 @@ #include #include "DisplayDriver.h" +#include "LemonFont.h" #ifndef DISPLAY_ROTATION #define DISPLAY_ROTATION 0 @@ -48,6 +49,7 @@ class GxEPDDisplay : public DisplayDriver { #endif bool _init = false; bool _isOn = false; + bool _use_lemon = false; uint16_t _curr_color; CRC32 display_crc; int last_display_crc_value = 0; @@ -66,8 +68,12 @@ public: // 1 = FreeSans9pt (lineH=16, charW≈9) // 2 = FreeSansBold12pt (lineH=20, charW≈12) // 3 = FreeSans18pt (lineH=28, charW≈17) - int getCharWidth() const override { return _text_sz == 3 ? 17 : _text_sz == 2 ? 12 : 9; } - int getLineHeight() const override { return _text_sz == 3 ? 28 : _text_sz == 2 ? 20 : 16; } + // Size 1: GFX built-in 6×8 (default) or Lemon 5×10 bitmap font — matches OLED metrics. + // Size 2: GFX built-in scaled 12×16 bitmap font. + // Size 3: FreeSans18pt proportional font for large headings. + int getCharWidth() const override { return _text_sz == 3 ? 17 : _text_sz == 2 ? 12 : (_use_lemon ? 5 : 6); } + int getLineHeight() const override { return _text_sz == 3 ? 28 : _text_sz == 2 ? 16 : (_use_lemon ? 10 : 8); } + void setLemonFont(bool enabled) override { _use_lemon = enabled; } bool begin();