diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 6ce4d7ec..aff4d46c 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -334,6 +334,11 @@ static void sanitize(NodePrefs& p) { flag(p.lock_compact, 0); flag(p.ble_off, 0); if (p.msg_alert > NodePrefs::MSG_ALERT_OFF) p.msg_alert = NodePrefs::MSG_ALERT_NORMAL; + if (p.ui_text_scale > NodePrefs::UI_TEXT_SCALE_MAX) p.ui_text_scale = 0; +#ifdef EINK_FONT_SCALE // the Text size row shows the scale in use: start at the build's + if (p.ui_text_scale == 0) p.ui_text_scale = EINK_FONT_SCALE; +#endif + if (p.ui_icon_scale > NodePrefs::UI_ICON_SCALE_MAX) p.ui_icon_scale = 0; if (!p.ch_scope_follow) { for (uint8_t i = 0; i < NodePrefs::MAX_SCOPED_CHANNELS; i++) if (p.ch_scope_idx[i] == 0) p.ch_scope_idx[i] = NodePrefs::CH_SCOPE_DEFAULT; diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index b656d9a0..e42a5232 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -538,6 +538,15 @@ struct NodePrefs { // persisted to file static const uint8_t MSG_ALERT_NORMAL = 0, MSG_ALERT_COMPACT = 1, MSG_ALERT_OFF = 2; uint8_t msg_alert; + // ── Text and icon size (ui-new, big e-ink panels) ────────────────────── + // Settings > Display, only on builds that opt in (EINK_FONT_SCALE / + // STATUS_ICON_SCALE). ui_text_scale: the font's pixel multiplier, 1-5; 0 is + // the build's own (DataStore sanitize sets EINK_FONT_SCALE there). + // ui_icon_scale: Home's status icons, 0 = Auto (1.5x the text), else 1-8. + static const uint8_t UI_TEXT_SCALE_MAX = 5, UI_ICON_SCALE_MAX = 8; + uint8_t ui_text_scale; + uint8_t ui_icon_scale; + // Single source of truth for the live-share option tables (shared by the Map // UI labels and the auto-send engine in UITask). static const uint8_t LOC_SHARE_MOVE_COUNT = 4; diff --git a/examples/companion_radio/ui-core/SettingsCli.h b/examples/companion_radio/ui-core/SettingsCli.h index e6006876..0f79c493 100644 --- a/examples/companion_radio/ui-core/SettingsCli.h +++ b/examples/companion_radio/ui-core/SettingsCli.h @@ -23,6 +23,7 @@ static const Key KEYS[] = { K("contacts.expiry", contact_expiry_idx), K("contacts.fav.first", fav_sort), K("dm.resend", dm_resend_count), K("display.brightness", display_brightness), K("display.off", auto_off_secs), K("display.wake", msg_wake), K("display.alert", msg_alert), K("lock", auto_lock), K("lock.clock", lock_compact), + K("display.text.size", ui_text_scale), K("display.icon.size", ui_icon_scale), K("batt.display", batt_display_mode), K("batt.shutdown", low_batt_mv), K("gps.interval", gps_interval), K("clock.12h", clock_12h), K("clock.seconds", clock_hide_seconds), K("units.imperial", units_imperial), K("sound.volume", buzzer_volume), K("quiet", quiet_hours), K("quiet.from", quiet_from), K("quiet.until", quiet_to), diff --git a/examples/companion_radio/ui-core/SettingsSchema.h b/examples/companion_radio/ui-core/SettingsSchema.h index e8f865d8..d2efff6b 100644 --- a/examples/companion_radio/ui-core/SettingsSchema.h +++ b/examples/companion_radio/ui-core/SettingsSchema.h @@ -144,6 +144,15 @@ static void optMsgAlert(uint8_t v, char* b, int n, const NodePrefs&) { static const char* const L[] = { "Normal", "Compact", "Off" }; snprintf(b, n, "%s", L[v < 3 ? v : 0]); } +#ifdef EINK_FONT_SCALE +static const int32_t TEXT_SCALE[] = { 1, 2, 3, 4, 5 }; +static void optTextScale(uint8_t v, char* b, int n, const NodePrefs&) { snprintf(b, n, "%ldx", (long)TEXT_SCALE[v]); } +#endif +#ifdef STATUS_ICON_SCALE +static void optIconScale(uint8_t v, char* b, int n, const NodePrefs&) { + if (v == 0) snprintf(b, n, "Auto"); else snprintf(b, n, "%ux", (unsigned)v); +} +#endif static void optLockLook(uint8_t v, char* b, int n, const NodePrefs&) { snprintf(b, n, "%s", v ? "Compact" : "Big"); } static void optExpiry(uint8_t v, char* b, int n, const NodePrefs&) { snprintf(b, n, "%s", NodePrefs::contactExpiryLabel(v)); @@ -243,6 +252,15 @@ static const Setting ALL[] = { SW("Lock screen", "Slide to unlock after sleep", SEC_DISPLAY, auto_lock, nullptr), IDX("Lock clock", "Big, or compact with the clock fields", SEC_DISPLAY, lock_compact, 2, optLockLook, nullptr), IDX("Battery display", "In the status bar", SEC_DISPLAY, batt_display_mode, 3, optBattDisplay, nullptr), + // Only the builds that ask for them (big e-ink panels): each screen elsewhere + // is laid out for one cell size. +#ifdef EINK_FONT_SCALE + MAP("Text size", "Bigger letters on a big panel", SEC_DISPLAY, ui_text_scale, TEXT_SCALE, optTextScale, applyDisplay), +#endif +#ifdef STATUS_ICON_SCALE + IDX("Icon size", "Home's status icons", SEC_DISPLAY, ui_icon_scale, NodePrefs::UI_ICON_SCALE_MAX + 1, + optIconScale, applyDisplay), +#endif MAP("Battery shutdown", "Power off below this voltage", SEC_POWER, low_batt_mv, LOW_BATT, optLowBatt, nullptr), MAP("GPS power saving", "Sleep between fixes", SEC_POWER, gps_interval, GPS_DUTY, optGpsDuty, applyGpsDuty), diff --git a/examples/companion_radio/ui-new/SettingsScreen.h b/examples/companion_radio/ui-new/SettingsScreen.h index 965fa2aa..bcb7dccf 100644 --- a/examples/companion_radio/ui-new/SettingsScreen.h +++ b/examples/companion_radio/ui-new/SettingsScreen.h @@ -27,10 +27,6 @@ class SettingsScreen : public UIScreen { #endif #if FEAT_FULL_REFRESH_SETTING EINK_FULL_REFRESH, - UI_TEXT_SCALE, // Text size: 1x..5x the 6x9 font -#if STATUS_ICONS_SCALED - UI_ICON_SCALE, // Icon size: Auto, 1x..8x -#endif #endif // Sound section SECTION_SOUND, @@ -559,18 +555,6 @@ class SettingsScreen : public UIScreen { uint8_t idx = p ? p->eink_full_refresh_every : 0; if (idx >= EINK_FULL_REFRESH_COUNT) idx = 0; val("Full rfsh", EINK_FULL_REFRESH_LABELS[idx]); - } else if (item == UI_TEXT_SCALE) { - char b[4]; - snprintf(b, sizeof(b), "%ux", (unsigned)_task->getUiFontScale()); - val("Text size", b); -#if STATUS_ICONS_SCALED - } else if (item == UI_ICON_SCALE) { - char b[12]; - const uint8_t v = _task->getStatusIconScale(); - if (v == 0) snprintf(b, sizeof(b), "Auto"); - else snprintf(b, sizeof(b), "%ux", (unsigned)v); - val("Icon size", b); -#endif #endif } else if (item == DM_FILTER) { val("DMs", (p && p->dm_show_all) ? "All" : "Fav"); @@ -1202,21 +1186,6 @@ public: _dirty = true; return true; } - if (_selected == UI_TEXT_SCALE && (left || right || enter)) { - int v = _task->getUiFontScale(); // 1..5, wrapping - v = left ? (v <= 1 ? 5 : v - 1) : (v >= 5 ? 1 : v + 1); - _task->setUiFontScale(v); // saved to /ui_scale immediately - return true; - } -#if STATUS_ICONS_SCALED - if (_selected == UI_ICON_SCALE && (left || right || enter)) { - const int n = STATUS_ICON_SCALE_MAX + 1; // Auto, 1x..8x - int v = _task->getStatusIconScale(); - v = (v + (left ? n - 1 : 1)) % n; - _task->setStatusIconScale(v); // saved to /ui_scale immediately - return true; - } -#endif #endif if (_selected == DM_FILTER && p && (left || right || enter)) { p->dm_show_all = p->dm_show_all ? 0 : 1; diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index d4632718..fdb11d16 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -2063,7 +2063,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no applyBrightness(); applyRotation(); applyFullRefreshInterval(); - loadUiScale(); // Settings > Display > Text size / Icon size + applyUiScale(); // Settings > Display > Text size / Icon size applyAllGpioModes(); // restore persisted pin modes to hardware before any UI/bot use // Locked above (a PIN, or the cover closed) before Home existed to be told. if (_locked) syncLockToHome(); @@ -4163,57 +4163,17 @@ void UITask::applyFullRefreshInterval() { } } -// Text size and Icon size (Settings > Display), in their own /ui_scale file -- -// [text pixel scale (0 = build default), icon scale (0 = Auto)] -- so the -// NodePrefs schema is untouched. -static const char* UI_SCALE_FILE = "/ui_scale"; -static const uint8_t UI_TEXT_SCALE_MAX = 5; - -void UITask::loadUiScale() { - uint8_t b[2] = { 0, statusIconScaleSetting() }; - DataStore* ds = the_mesh.getDataStore(); - if (ds) { - File f = ds->openRead(UI_SCALE_FILE); - if (f) { - f.read(b, 2); - f.close(); - } - } - _ui_font_scale = b[0] <= UI_TEXT_SCALE_MAX ? b[0] : 0; - if (b[1] <= STATUS_ICON_SCALE_MAX) statusIconScaleSetting() = b[1]; - if (_display != NULL && _ui_font_scale) _display->setUiScale(_ui_font_scale); -} - -void UITask::saveUiScale() { - DataStore* ds = the_mesh.getDataStore(); - if (!ds) return; - File f = ds->openWrite(UI_SCALE_FILE); - if (f) { - uint8_t b[2] = { _ui_font_scale, statusIconScaleSetting() }; - f.write(b, 2); - f.close(); - } -} - -uint8_t UITask::getUiFontScale() const { - return _display != NULL ? (uint8_t)_display->pixelScale() : 1; -} - -void UITask::setUiFontScale(uint8_t s) { - if (s < 1 || s > UI_TEXT_SCALE_MAX) s = 1; - _ui_font_scale = s; - if (_display != NULL) _display->setUiScale(s); - _next_refresh = 0; - saveUiScale(); -} - -uint8_t UITask::getStatusIconScale() const { return statusIconScaleSetting(); } - -void UITask::setStatusIconScale(uint8_t s) { - if (s > STATUS_ICON_SCALE_MAX) s = 0; - statusIconScaleSetting() = s; - _next_refresh = 0; // the frame differs, so it's redrawn - saveUiScale(); +// Text size and Icon size (Settings > Display, NodePrefs ui_text_scale / +// ui_icon_scale), on the builds that offer them. Elsewhere the fields stay 0: +// the build's font scale and Auto icons, as stock. +void UITask::applyUiScale() { + if (!_node_prefs) return; +#ifdef EINK_FONT_SCALE + if (_display != NULL) _display->setUiScale(_node_prefs->ui_text_scale); +#endif +#if STATUS_ICONS_SCALED + statusIconScaleSetting() = _node_prefs->ui_icon_scale; +#endif } void UITask::applySoundPrefs() { diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index 4b678e1e..86fe04e5 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -62,7 +62,6 @@ class UITask : public UITaskBase, public UiCoreHost { unsigned long _next_refresh, _auto_off; bool _display_was_on = true; // loop(): messagesInView() last time round NodePrefs* _node_prefs; - uint8_t _ui_font_scale = 0; // Settings > Display > Text size (0 = build default) bool _locked; bool _tool_from_home = false; bool messagesInView() const; // Messages on a lit, unlocked display @@ -529,7 +528,7 @@ public: void applyAllGpioModes(); // boot-time restore from NodePrefs, called from begin() void applyBrightness(); // Settings changed through the schema (ui-core/SettingsSchema.h). - void applyDisplayPrefs() override { applyBrightness(); _next_refresh = 0; } + void applyDisplayPrefs() override { applyBrightness(); applyUiScale(); _next_refresh = 0; } void applySoundPrefs() override; bool cliCommand(const char* command, char* reply, int n) override; void setBuzzerVolumeLevel(uint8_t level); @@ -544,14 +543,7 @@ public: bool savePrefsIfDirty(bool& dirty); void applyRotation(); void applyFullRefreshInterval(); - // Settings > Display > Text size / Icon size. Kept in their own /ui_scale - // file rather than NodePrefs, so the prefs schema (and its size assert) is untouched. - uint8_t getUiFontScale() const; // the text's current pixel scale - void setUiFontScale(uint8_t s); // 1..5: applies + saves - uint8_t getStatusIconScale() const; // 0 = Auto (1.5x text), else n - void setStatusIconScale(uint8_t s); // 0..8: applies + saves - void loadUiScale(); // boot-time restore, from begin() - void saveUiScale(); + void applyUiScale(); // Settings > Display > Text size / Icon size, from the prefs uint32_t autoOffMillis() const { if (!_node_prefs || _node_prefs->auto_off_secs == 0) return 0; return (uint32_t)_node_prefs->auto_off_secs * 1000UL; diff --git a/examples/companion_radio/ui-new/icons.h b/examples/companion_radio/ui-new/icons.h index 88509584..d9433bf3 100644 --- a/examples/companion_radio/ui-new/icons.h +++ b/examples/companion_radio/ui-new/icons.h @@ -94,20 +94,19 @@ inline void miniIconDrawCentered(DisplayDriver& d, int cx, int cy, const MiniIco // Home status bar icon scale. Defining STATUS_ICON_SCALE (build flag) turns on // scalable status icons: the bar's icons, battery and the page-icon row below it // are drawn at n x their pixel grid, and the bar grows tall enough to hold them -- -// for big panels whose 1-line bar leaves them tiny. Its value is the default for -// Settings > Display > Icon size: 0 = Auto (1.5x the text's pixel scale), else n. -// Unset: icons follow the font, as stock. +// for big panels whose 1-line bar leaves them tiny -- and adds Settings > Display > +// Icon size (NodePrefs::ui_icon_scale): 0 = Auto (1.5x the text's pixel scale), +// else n. Unset: icons follow the font, as stock. #ifdef STATUS_ICON_SCALE #define STATUS_ICONS_SCALED 1 #else #define STATUS_ICONS_SCALED 0 - #define STATUS_ICON_SCALE 0 #endif -static constexpr int STATUS_ICON_SCALE_MAX = 8; static constexpr int STATUS_ICON_ROWS = MINI_ICONS_LARGE == 2 ? 9 : 7; // tallest status icon -// The Icon size setting (0 = Auto). One instance across translation units. +// The Icon size setting (0 = Auto), copied from the prefs by UITask::applyUiScale(). +// One instance across translation units. inline uint8_t& statusIconScaleSetting() { - static uint8_t v = (STATUS_ICON_SCALE >= 0 && STATUS_ICON_SCALE <= STATUS_ICON_SCALE_MAX) ? STATUS_ICON_SCALE : 0; + static uint8_t v = 0; return v; } inline int statusIconScale(DisplayDriver& d) { diff --git a/solo/wio-tracker-l1-gdeq0426/platformio.ini b/solo/wio-tracker-l1-gdeq0426/platformio.ini index 9ab3b0ef..7238ecaa 100644 --- a/solo/wio-tracker-l1-gdeq0426/platformio.ini +++ b/solo/wio-tracker-l1-gdeq0426/platformio.ini @@ -13,11 +13,10 @@ ; OFFLINE_QUEUE_SIZE 32 (stock e-ink: 128) frees ~17 KB ; MAX_CONTACTS 250 (stock: 350) frees ~18 KB ; - EINK_FONT_SCALE 4: text at 4x the 6x9 font (24x36 cells, ~33 characters -; x 13 lines) -- twice the stock 2x. The default for Settings > Display > -; Text size (1x-5x), which overrides it once changed. -; - STATUS_ICON_SCALE 0: turns on scalable Home status/page icons; 0 = Auto -; (1.5x the text: 6x at 4x text). The default for Settings > Display > -; Icon size (Auto, 1x-8x). +; x 13 lines) -- twice the stock 2x. Also adds Settings > Display > Text +; size (1x-5x), which starts here. +; - STATUS_ICON_SCALE turns on scalable Home status/page icons and adds +; Settings > Display > Icon size (Auto = 1.5x the text: 6x at 4x text, 1x-8x). ; ; Build: pio run -e WioTrackerL1_GDEQ0426T82_companion_solo_dual [env:WioTrackerL1_GDEQ0426T82_companion_solo_dual] diff --git a/src/helpers/ui/EinkGfxDisplay.h b/src/helpers/ui/EinkGfxDisplay.h index 6e983559..822a61f1 100644 --- a/src/helpers/ui/EinkGfxDisplay.h +++ b/src/helpers/ui/EinkGfxDisplay.h @@ -29,7 +29,7 @@ class EinkGfxDisplay : public DisplayDriver { uint16_t _curr; const GFXfont* _font; int _cell_w = 6, _cell_h = 9; // the font's cell, before _px and the text size - int _px = 1; // pixel doubling (landscape without EINK_LARGE_FONT) + int _px = 1; // pixel multiplier (landscape: EINK_FONT_PX, or Text size) uint8_t _px_override = 0; // Settings > Display > Text size (0 = build default) int _text_sz = 1; int _cx = 0, _cy = 0; // cursor, top of the text row @@ -77,7 +77,11 @@ public: bool isEink() override { return true; } // Runtime text scale (Settings > Display > Text size): re-lays out and forces // a full redraw. 0 = the build default (EINK_FONT_SCALE). - void setUiScale(uint8_t font_scale) override { _px_override = font_scale; updateLayout(); } + void setUiScale(uint8_t font_scale) override { + if (font_scale == _px_override) return; // unchanged: no full redraw + _px_override = font_scale; + updateLayout(); + } void startFrame(Color bkg = DARK) override; void setTextSize(int sz) override; diff --git a/src/helpers/ui/EinkGfxDisplayImpl.h b/src/helpers/ui/EinkGfxDisplayImpl.h index 26457b97..16b3aee4 100644 --- a/src/helpers/ui/EinkGfxDisplayImpl.h +++ b/src/helpers/ui/EinkGfxDisplayImpl.h @@ -3,11 +3,15 @@ // the font tables below are static arrays. #include "EinkGfxDisplay.h" -// EINK_FONT_SCALE=: pixel multiplier for the 6x9 font on a landscape panel -// without EINK_LARGE_FONT (default 2). 4 on an 800x480 panel = 24x36 cells, -// ~33 characters x 13 lines. Settings > Display > Text size overrides it at run time. -#ifndef EINK_FONT_SCALE - #define EINK_FONT_SCALE 2 +// EINK_FONT_SCALE=: pixel multiplier for the landscape font -- the 6x9, or +// the EINK_LARGE_FONT one if the build picks it. 4 on an 800x480 panel with the +// 6x9 = 24x36 cells, ~33 characters x 13 lines. Setting it also adds Settings > +// Display > Text size, which overrides it at run time. Unset: stock, the 6x9 at +// 2x or the large font at its own size. +#ifdef EINK_FONT_SCALE + #define EINK_FONT_PX EINK_FONT_SCALE +#else + #define EINK_FONT_PX (EINK_LARGE_FONT ? 1 : 2) #endif #include "MiscFixedRenderer.h" #if EINK_LARGE_FONT == 2 @@ -26,8 +30,8 @@ EinkGfxDisplay::EinkGfxDisplay(int w, int h, Adafruit_GFX& gfx, uint16_t ink, ui void EinkGfxDisplay::updateLayout() { const bool landscape = width() >= height(); _font = (EINK_LARGE_FONT && landscape) ? &EINK_LARGE_GFXFONT : &MiscFixed; - _px = (!EINK_LARGE_FONT && landscape) ? EINK_FONT_SCALE : 1; - if (_px_override) _px = _px_override; + _px = landscape ? EINK_FONT_PX : 1; + if (_px_override && landscape) _px = _px_override; // portrait screens are laid out for 1x _cell_w = miscFixedCellW(*_font); _cell_h = _font->yAdvance; _vw_dirty = true;