diff --git a/docs/design/solo_ui_framework.md b/docs/design/solo_ui_framework.md index 7771a4b5..9da87a67 100644 --- a/docs/design/solo_ui_framework.md +++ b/docs/design/solo_ui_framework.md @@ -111,14 +111,17 @@ indicator: ```cpp drawList(display, count, _sel, _scroll, [&](int idx, int y, bool sel, int reserve) { - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); // canonical highlight bar display.drawTextEllipsized(2, y, display.width() - reserve - 4, items[idx].name); }); ``` `reserve` is the width the scrollbar took (0 when the list fits) — subtract it from any right-aligned content so nothing slides under the indicator. The row -callback owns its own selection bar (so a screen can style it). For the +callback owns its own selection bar: `drawRowSelection(d, y, sel, reserve)` +(`ui-new/icons.h`) draws the standard one (full row minus reserve, one pixel +short); call `display.drawSelectionRow()` directly only when a row needs a +non-standard geometry (full-width, custom height). For the fold-in-place pattern (sections that expand/collapse) use `AccordionList` instead (`ui-new/AccordionList.h`) — same idea, two callbacks (header + item). @@ -299,7 +302,7 @@ public: d.setTextSize(1); d.drawCenteredHeader("MY TOOL"); drawList(d, ROWS, _sel, _scroll, [&](int i, int y, bool sel, int reserve) { - d.drawSelectionRow(0, y - 1, d.width() - reserve, d.lineStep() - 1, sel); + drawRowSelection(d, y, sel, reserve); d.setCursor(4, y); d.print(i == 0 ? "Alpha" : i == 1 ? "Bravo" : "Charlie"); }); diff --git a/examples/companion_radio/ui-new/BotScreen.h b/examples/companion_radio/ui-new/BotScreen.h index d8fa90aa..cbc9c975 100644 --- a/examples/companion_radio/ui-new/BotScreen.h +++ b/examples/companion_radio/ui-new/BotScreen.h @@ -75,7 +75,7 @@ public: "Trigger Ch", "Reply Ch", "Commands", "Quiet from", "Quiet to" }; drawList(display, ITEM_COUNT, _sel, _scroll, [&](int i, int y, bool sel, int reserve) { - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); display.setCursor(2, y); display.print(labels[i]); display.setCursor(val_x, y); diff --git a/examples/companion_radio/ui-new/LiveShareScreen.h b/examples/companion_radio/ui-new/LiveShareScreen.h index a7d8cf63..726b3757 100644 --- a/examples/companion_radio/ui-new/LiveShareScreen.h +++ b/examples/companion_radio/ui-new/LiveShareScreen.h @@ -92,7 +92,7 @@ public: const int valx = display.width() / 2 + 6; drawList(display, ROW_COUNT, _sel, _scroll, [&](int i, int y, bool sel, int reserve) { Row r = rows(i); - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); display.setCursor(4, y); display.print(r.label); char val[24]; diff --git a/examples/companion_radio/ui-new/LocatorScreen.h b/examples/companion_radio/ui-new/LocatorScreen.h index 09b5d65c..0cf7fba0 100644 --- a/examples/companion_radio/ui-new/LocatorScreen.h +++ b/examples/companion_radio/ui-new/LocatorScreen.h @@ -116,7 +116,7 @@ public: const int valx = display.width() / 2 + 6; drawList(display, rc, _sel, _scroll, [&](int i, int y, bool sel, int reserve) { Row r = rows(i); - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); display.setCursor(4, y); display.print(r.label); char val[24]; @@ -265,7 +265,7 @@ public: display.drawCenteredHeader("PICK TARGET"); uint32_t now = rtc_clock.getCurrentTime(); drawList(display, _target_n, _pick_sel, _pick_scroll, [&](int i, int y, bool sel, int reserve) { - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); const Target& t = _targets[i]; char row[36]; if (t.kind != 1) { diff --git a/examples/companion_radio/ui-new/NearbyScreen.h b/examples/companion_radio/ui-new/NearbyScreen.h index eb21c3b3..45d0d00f 100644 --- a/examples/companion_radio/ui-new/NearbyScreen.h +++ b/examples/companion_radio/ui-new/NearbyScreen.h @@ -686,7 +686,7 @@ public: drawList(display, _count, _sel, _scroll, [&](int idx, int y, bool sel, int reserve) { const Entry& e = _entries[idx]; - display.drawSelectionRow(0, y - 1, display.width() - reserve, item_h - 1, sel); + drawRowSelection(display, y, sel, reserve); char filt[32]; int tx = 2; diff --git a/examples/companion_radio/ui-new/QuickMsgScreen.h b/examples/companion_radio/ui-new/QuickMsgScreen.h index f3bcc109..fa0bcd2d 100644 --- a/examples/companion_radio/ui-new/QuickMsgScreen.h +++ b/examples/companion_radio/ui-new/QuickMsgScreen.h @@ -1046,7 +1046,7 @@ public: drawList(display, _num_contacts, _contact_sel, _contact_scroll, [&](int list_idx, int y, bool sel, int reserve) { int mesh_idx = _sorted[list_idx]; - display.drawSelectionRow(0, y - 1, display.width() - reserve, item_h - 1, sel); + drawRowSelection(display, y, sel, reserve); ContactInfo c; if (the_mesh.getContactByIdx(mesh_idx, c)) { @@ -1079,7 +1079,7 @@ public: } drawList(display, _num_channels, _channel_sel, _channel_scroll, [&](int list_idx, int y, bool sel, int reserve) { - display.drawSelectionRow(0, y - 1, display.width() - reserve, item_h - 1, sel); + drawRowSelection(display, y, sel, reserve); ChannelDetails ch; if (the_mesh.getChannel(_channel_indices[list_idx], ch)) { uint8_t unread = _ch_unread[_channel_indices[list_idx]]; @@ -1437,7 +1437,7 @@ public: int total_msg_items = 1 + _active_msg_count; drawList(display, total_msg_items, _msg_sel, _msg_scroll, [&](int idx, int y, bool sel, int reserve) { - display.drawSelectionRow(0, y - 1, display.width() - reserve, item_h - 1, sel); + drawRowSelection(display, y, sel, reserve); if (idx == 0) { display.setCursor(2, y); diff --git a/examples/companion_radio/ui-new/RepeaterScreen.h b/examples/companion_radio/ui-new/RepeaterScreen.h index ba8e5d40..5b4682bb 100644 --- a/examples/companion_radio/ui-new/RepeaterScreen.h +++ b/examples/companion_radio/ui-new/RepeaterScreen.h @@ -146,7 +146,7 @@ public: // Config only — live forwarding stats live on Tools › Diagnostics. drawList(display, _item_count, _sel, _scroll, [&](int row, int y, bool sel, int reserve) { int item = _items[row]; - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); display.setCursor(2, y); display.print(itemLabel(item)); if (item == IT_RFREQ && sel && _editor.active()) { diff --git a/examples/companion_radio/ui-new/SettingsScreen.h b/examples/companion_radio/ui-new/SettingsScreen.h index e6405ec7..b8322acf 100644 --- a/examples/companion_radio/ui-new/SettingsScreen.h +++ b/examples/companion_radio/ui-new/SettingsScreen.h @@ -422,7 +422,7 @@ class SettingsScreen : public UIScreen { void renderItem(DisplayDriver& display, int item, int y, bool sel) { NodePrefs* p = _task->getNodePrefs(); - display.drawSelectionRow(0, y - 1, display.width() - _reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, _reserve); display.setCursor(2, y); @@ -671,7 +671,7 @@ public: [&](int sec, int y, bool sel, int reserve, bool collapsed) { _reserve = reserve; display.setColor(DisplayDriver::LIGHT); - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); display.setCursor(2, y); display.print(collapsed ? "+" : "-"); display.print(" "); diff --git a/examples/companion_radio/ui-new/ToolsScreen.h b/examples/companion_radio/ui-new/ToolsScreen.h index 87c66cbb..9f15a27a 100644 --- a/examples/companion_radio/ui-new/ToolsScreen.h +++ b/examples/companion_radio/ui-new/ToolsScreen.h @@ -75,7 +75,7 @@ public: _acc.render(display, // Section header: "[+/-] Name" [&](int sec, int y, bool sel, int reserve, bool collapsed) { - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); display.setCursor(2, y); display.print(collapsed ? "+" : "-"); const int icon_x = 2 + cw + 2; @@ -85,7 +85,7 @@ public: }, // Item: indented " Label" [&](int sec, int item, int y, bool sel, int reserve) { - display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); + drawRowSelection(display, y, sel, reserve); const int icon_x = 2 + cw + 2; // align item icons under the header icon // drawIcon(display, icon_x, y, SECTIONS[sec].tools[item].icon); // icons disabled for now, don't fit visually display.setCursor(icon_x + g, y); diff --git a/examples/companion_radio/ui-new/WaypointsView.h b/examples/companion_radio/ui-new/WaypointsView.h index 5af1d8c9..8b921523 100644 --- a/examples/companion_radio/ui-new/WaypointsView.h +++ b/examples/companion_radio/ui-new/WaypointsView.h @@ -153,12 +153,10 @@ class WaypointsView { int n = wpListCount(); int total = n + 1; // final row = "+ Add by coords" - const int step = display.lineStep(); - int32_t mylat, mylon; bool have = ownPos(mylat, mylon); drawList(display, total, _sel, _scroll, [&](int row, int y, bool sel, int reserve) { - display.drawSelectionRow(0, y - 1, display.width() - reserve, step - 1, sel); + drawRowSelection(display, y, sel, reserve); if (row == n) { // the synthetic "Add" row display.setCursor(2, y); display.print("+ Add by coords"); diff --git a/examples/companion_radio/ui-new/icons.h b/examples/companion_radio/ui-new/icons.h index e3cbb315..f52f575e 100644 --- a/examples/companion_radio/ui-new/icons.h +++ b/examples/companion_radio/ui-new/icons.h @@ -499,6 +499,16 @@ inline int drawList(DisplayDriver& d, int total, int sel, int& scroll, RenderRow return visible; } +// Canonical selection bar for a drawList() row: spans the row width minus the +// scroll-indicator `reserve`, one pixel short of the row height, anchored one +// pixel above `y` (the row's text baseline-top). Call as the first line of a +// row callback, then draw content over it. Captures the geometry every list row +// repeated by hand; rows that intentionally differ (full-width, custom height) +// still call display.drawSelectionRow() directly. +inline void drawRowSelection(DisplayDriver& d, int y, bool sel, int reserve) { + d.drawSelectionRow(0, y - 1, d.width() - reserve, d.lineStep() - 1, sel); +} + // ── Big ASCII-art icons (skeleton, not yet used) ───────────────────────────── // Same authoring idea as the mini-icons but for full page glyphs up to 32 px // wide: one uint32_t per row. The existing XBM bitmaps below (logo/bluetooth/…)