mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-01 10:21:59 +00:00
refactor(eink): Text size and Icon size as schema settings, on opt-in builds only
Review follow-up: - The rows exist only where the build asks for them: Text size with EINK_FONT_SCALE, Icon size with STATUS_ICON_SCALE. The stock 2.13", the portrait builds and the L2 don't get them -- their screens are laid out for one cell size. The text override also applies in landscape only. - Stored in NodePrefs (ui_text_scale, ui_icon_scale) instead of a /ui_scale file, as rows in the schema's Display section: the usual row, save path and factory reset, and console keys display.text.size / display.icon.size. The hand-written Settings rows and the load/save code are gone; UITask::applyUiScale() applies the prefs at boot and on change (applyDisplayPrefs). On opt-in builds ui_text_scale starts at the build's EINK_FONT_SCALE (DataStore sanitize), so the row shows the scale in use. - EINK_FONT_SCALE, when set, now scales whichever landscape font the build picks (the 6x9, or the EINK_LARGE_FONT one); unset, it is stock as before. - setUiScale() skips the re-layout and full redraw when nothing changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
// the font tables below are static arrays.
|
||||
|
||||
#include "EinkGfxDisplay.h"
|
||||
// EINK_FONT_SCALE=<n>: 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=<n>: 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;
|
||||
|
||||
Reference in New Issue
Block a user