From 98af868e68e499310551278b933298d199dfa84d Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Mon, 15 Jun 2026 18:17:34 +0200 Subject: [PATCH] refactor(ui): dedup status-bar indicators - Extract drawBoxedIcon()/drawSlotIcon() in icons.h; collapse the four near-identical mute/BT/advert/trail blocks in renderBatteryIndicator. - Centre the glyph on the actual indicator box (box_h) instead of the text line, fixing the 1px vertical offset in Lemon mode. - Extract blinkOn() for the shared advert/trail blink cadence. Co-Authored-By: Claude Opus 4.8 --- examples/companion_radio/ui-new/UITask.cpp | 46 +++++++--------------- examples/companion_radio/ui-new/icons.h | 22 +++++++++++ 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index a8954b1c..c24801e7 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -35,6 +35,12 @@ #include "icons.h" +// Blinking status indicators: on for the first half of a 4 s cycle, but e-ink +// can't repaint fast enough to blink, so it shows them steadily. +static inline bool blinkOn() { + return Features::BLINK_INDICATORS ? ((millis() % 4000) < 2000) : true; +} + class SplashScreen : public UIScreen { UITask* _task; unsigned long dismiss_after; @@ -441,12 +447,8 @@ class HomeScreen : public UIScreen { #ifdef PIN_BUZZER if (_task->isBuzzerQuiet()) { - display.setColor(DisplayDriver::LIGHT); int mx = battLeftX - ind - ind_gap; - display.fillRect(mx, 0, ind, ind_h); - display.setColor(DisplayDriver::DARK); - miniIconDraw(display, mx + (ind - ICON_MUTE.w * miniIconScale(display)) / 2, 0, ICON_MUTE); - display.setColor(DisplayDriver::LIGHT); + drawBoxedIcon(display, mx, ind, ind_h, ICON_MUTE); battLeftX = mx; } #endif @@ -455,43 +457,23 @@ class HomeScreen : public UIScreen { int leftmostX = battLeftX; if (_task->isSerialEnabled()) { int btX = battLeftX - ind - ind_gap; - int btIconX = btX + (ind - ICON_BLUETOOTH.w * miniIconScale(display)) / 2; - if (_task->isBLEConnected()) { // BT icon reflects BLE link, not USB - display.setColor(DisplayDriver::LIGHT); - display.fillRect(btX, 0, ind, ind_h); - display.setColor(DisplayDriver::DARK); - miniIconDraw(display, btIconX, 0, ICON_BLUETOOTH); - display.setColor(DisplayDriver::LIGHT); - } else { - miniIconDraw(display, btIconX, 0, ICON_BLUETOOTH); // plain glyph: available, not linked - } + if (_task->isBLEConnected()) // BT icon reflects BLE link, not USB + drawBoxedIcon(display, btX, ind, ind_h, ICON_BLUETOOTH); + else + drawSlotIcon(display, btX, ind, ind_h, ICON_BLUETOOTH); // plain glyph: available, not linked leftmostX = btX - ind_gap; // "A" indicator — left of BT; blinks on OLED, always shown on e-ink if (_node_prefs && _node_prefs->advert_auto_interval_sec > 0) { int aX = leftmostX - ind; - bool show_a = Features::BLINK_INDICATORS ? ((millis() % 4000) < 2000) : true; - if (show_a) { - display.setColor(DisplayDriver::LIGHT); - display.fillRect(aX, 0, ind, ind_h); - display.setColor(DisplayDriver::DARK); - miniIconDraw(display, aX + (ind - ICON_ADVERT.w * miniIconScale(display)) / 2, 0, ICON_ADVERT); - display.setColor(DisplayDriver::LIGHT); - } + if (blinkOn()) drawBoxedIcon(display, aX, ind, ind_h, ICON_ADVERT); leftmostX = aX - 1; } - // "G" indicator — GPS trail logging active. Same blink convention. + // GPS trail logging active. Same blink convention. if (_task->trail().isActive()) { int gX = leftmostX - ind; - bool show_g = Features::BLINK_INDICATORS ? ((millis() % 4000) < 2000) : true; - if (show_g) { - display.setColor(DisplayDriver::LIGHT); - display.fillRect(gX, 0, ind, ind_h); - display.setColor(DisplayDriver::DARK); - miniIconDraw(display, gX + (ind - ICON_TRAIL.w * miniIconScale(display)) / 2, 0, ICON_TRAIL); - display.setColor(DisplayDriver::LIGHT); - } + if (blinkOn()) drawBoxedIcon(display, gX, ind, ind_h, ICON_TRAIL); leftmostX = gX - 1; } } diff --git a/examples/companion_radio/ui-new/icons.h b/examples/companion_radio/ui-new/icons.h index af9bfeeb..d1875523 100644 --- a/examples/companion_radio/ui-new/icons.h +++ b/examples/companion_radio/ui-new/icons.h @@ -96,6 +96,28 @@ inline void miniIconDrawHalo(DisplayDriver& d, int x, int y, const MiniIcon& ic, if (ic.rows[r] & (1 << c)) d.fillRect(x + c * s, y + r * s, s, s); } +// Centre a mini-icon inside the slot [x, 0, box_w, box_h] using the current ink +// colour (no background). Centres on the box itself, not the text line, so the +// glyph sits dead-centre regardless of font line height. +inline void drawSlotIcon(DisplayDriver& d, int x, int box_w, int box_h, const MiniIcon& ic) { + const int s = miniIconScale(d); + int ix = x + (box_w - ic.w * s) / 2; + int iy = (box_h - ic.h * s) / 2; + if (ix < x) ix = x; + if (iy < 0) iy = 0; + miniIconDrawTop(d, ix, iy, ic); +} + +// Inverted status indicator: fill the box [x, 0, box_w, box_h] LIGHT, draw the +// glyph DARK and centred, then restore ink to LIGHT. +inline void drawBoxedIcon(DisplayDriver& d, int x, int box_w, int box_h, const MiniIcon& ic) { + d.setColor(DisplayDriver::LIGHT); + d.fillRect(x, 0, box_w, box_h); + d.setColor(DisplayDriver::DARK); + drawSlotIcon(d, x, box_w, box_h, ic); + d.setColor(DisplayDriver::LIGHT); +} + // Horizontal row of `count` square dots (scaled, vertically centred). Used by // the "awaiting ACK" marker, where the dot count = number of send attempts. inline void miniIconDotRow(DisplayDriver& d, int x, int top_y, int count) {