mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
refactor(companion): extract drawRowSelection() for the canonical list-row bar
Every drawList/AccordionList row opened with the same hand-written display.drawSelectionRow(0, y-1, width-reserve, lineStep-1, sel) line — 14 copies of the same geometry and magic offsets. Add a drawRowSelection(d, y, sel, reserve) helper in icons.h next to drawList and route the canonical sites through it (Bot/LiveShare/Locator/Repeater/Settings/Tools/Nearby/ QuickMsg/Waypoints). Rows that intentionally differ (full-width DashboardConfig/QuickMsg, the keyboard/ringtone grids) keep their explicit drawSelectionRow() call — the helper is opt-in rather than baked into drawList, so legitimate variants aren't forced into one geometry. Framework doc updated to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -111,14 +111,17 @@ indicator:
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
drawList(display, count, _sel, _scroll, [&](int idx, int y, bool sel, int reserve) {
|
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);
|
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
|
`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
|
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`
|
fold-in-place pattern (sections that expand/collapse) use `AccordionList`
|
||||||
instead (`ui-new/AccordionList.h`) — same idea, two callbacks (header + item).
|
instead (`ui-new/AccordionList.h`) — same idea, two callbacks (header + item).
|
||||||
|
|
||||||
@@ -299,7 +302,7 @@ public:
|
|||||||
d.setTextSize(1);
|
d.setTextSize(1);
|
||||||
d.drawCenteredHeader("MY TOOL");
|
d.drawCenteredHeader("MY TOOL");
|
||||||
drawList(d, ROWS, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
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.setCursor(4, y);
|
||||||
d.print(i == 0 ? "Alpha" : i == 1 ? "Bravo" : "Charlie");
|
d.print(i == 0 ? "Alpha" : i == 1 ? "Bravo" : "Charlie");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public:
|
|||||||
"Trigger Ch", "Reply Ch", "Commands",
|
"Trigger Ch", "Reply Ch", "Commands",
|
||||||
"Quiet from", "Quiet to" };
|
"Quiet from", "Quiet to" };
|
||||||
drawList(display, ITEM_COUNT, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
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.setCursor(2, y);
|
||||||
display.print(labels[i]);
|
display.print(labels[i]);
|
||||||
display.setCursor(val_x, y);
|
display.setCursor(val_x, y);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public:
|
|||||||
const int valx = display.width() / 2 + 6;
|
const int valx = display.width() / 2 + 6;
|
||||||
drawList(display, ROW_COUNT, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
drawList(display, ROW_COUNT, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
||||||
Row r = rows(i);
|
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.setCursor(4, y);
|
||||||
display.print(r.label);
|
display.print(r.label);
|
||||||
char val[24];
|
char val[24];
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public:
|
|||||||
const int valx = display.width() / 2 + 6;
|
const int valx = display.width() / 2 + 6;
|
||||||
drawList(display, rc, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
drawList(display, rc, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
||||||
Row r = rows(i);
|
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.setCursor(4, y);
|
||||||
display.print(r.label);
|
display.print(r.label);
|
||||||
char val[24];
|
char val[24];
|
||||||
@@ -265,7 +265,7 @@ public:
|
|||||||
display.drawCenteredHeader("PICK TARGET");
|
display.drawCenteredHeader("PICK TARGET");
|
||||||
uint32_t now = rtc_clock.getCurrentTime();
|
uint32_t now = rtc_clock.getCurrentTime();
|
||||||
drawList(display, _target_n, _pick_sel, _pick_scroll, [&](int i, int y, bool sel, int reserve) {
|
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];
|
const Target& t = _targets[i];
|
||||||
char row[36];
|
char row[36];
|
||||||
if (t.kind != 1) {
|
if (t.kind != 1) {
|
||||||
|
|||||||
@@ -686,7 +686,7 @@ public:
|
|||||||
drawList(display, _count, _sel, _scroll, [&](int idx, int y, bool sel, int reserve) {
|
drawList(display, _count, _sel, _scroll, [&](int idx, int y, bool sel, int reserve) {
|
||||||
const Entry& e = _entries[idx];
|
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];
|
char filt[32];
|
||||||
int tx = 2;
|
int tx = 2;
|
||||||
|
|||||||
@@ -1046,7 +1046,7 @@ public:
|
|||||||
drawList(display, _num_contacts, _contact_sel, _contact_scroll, [&](int list_idx, int y, bool sel, int reserve) {
|
drawList(display, _num_contacts, _contact_sel, _contact_scroll, [&](int list_idx, int y, bool sel, int reserve) {
|
||||||
int mesh_idx = _sorted[list_idx];
|
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;
|
ContactInfo c;
|
||||||
if (the_mesh.getContactByIdx(mesh_idx, 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) {
|
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;
|
ChannelDetails ch;
|
||||||
if (the_mesh.getChannel(_channel_indices[list_idx], ch)) {
|
if (the_mesh.getChannel(_channel_indices[list_idx], ch)) {
|
||||||
uint8_t unread = _ch_unread[_channel_indices[list_idx]];
|
uint8_t unread = _ch_unread[_channel_indices[list_idx]];
|
||||||
@@ -1437,7 +1437,7 @@ public:
|
|||||||
|
|
||||||
int total_msg_items = 1 + _active_msg_count;
|
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) {
|
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) {
|
if (idx == 0) {
|
||||||
display.setCursor(2, y);
|
display.setCursor(2, y);
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ public:
|
|||||||
// Config only — live forwarding stats live on Tools › Diagnostics.
|
// Config only — live forwarding stats live on Tools › Diagnostics.
|
||||||
drawList(display, _item_count, _sel, _scroll, [&](int row, int y, bool sel, int reserve) {
|
drawList(display, _item_count, _sel, _scroll, [&](int row, int y, bool sel, int reserve) {
|
||||||
int item = _items[row];
|
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.setCursor(2, y);
|
||||||
display.print(itemLabel(item));
|
display.print(itemLabel(item));
|
||||||
if (item == IT_RFREQ && sel && _editor.active()) {
|
if (item == IT_RFREQ && sel && _editor.active()) {
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ class SettingsScreen : public UIScreen {
|
|||||||
void renderItem(DisplayDriver& display, int item, int y, bool sel) {
|
void renderItem(DisplayDriver& display, int item, int y, bool sel) {
|
||||||
NodePrefs* p = _task->getNodePrefs();
|
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);
|
display.setCursor(2, y);
|
||||||
|
|
||||||
@@ -671,7 +671,7 @@ public:
|
|||||||
[&](int sec, int y, bool sel, int reserve, bool collapsed) {
|
[&](int sec, int y, bool sel, int reserve, bool collapsed) {
|
||||||
_reserve = reserve;
|
_reserve = reserve;
|
||||||
display.setColor(DisplayDriver::LIGHT);
|
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.setCursor(2, y);
|
||||||
display.print(collapsed ? "+" : "-");
|
display.print(collapsed ? "+" : "-");
|
||||||
display.print(" ");
|
display.print(" ");
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public:
|
|||||||
_acc.render(display,
|
_acc.render(display,
|
||||||
// Section header: "[+/-] <icon> Name"
|
// Section header: "[+/-] <icon> Name"
|
||||||
[&](int sec, int y, bool sel, int reserve, bool collapsed) {
|
[&](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.setCursor(2, y);
|
||||||
display.print(collapsed ? "+" : "-");
|
display.print(collapsed ? "+" : "-");
|
||||||
const int icon_x = 2 + cw + 2;
|
const int icon_x = 2 + cw + 2;
|
||||||
@@ -85,7 +85,7 @@ public:
|
|||||||
},
|
},
|
||||||
// Item: indented "<icon> Label"
|
// Item: indented "<icon> Label"
|
||||||
[&](int sec, int item, int y, bool sel, int reserve) {
|
[&](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
|
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
|
// drawIcon(display, icon_x, y, SECTIONS[sec].tools[item].icon); // icons disabled for now, don't fit visually
|
||||||
display.setCursor(icon_x + g, y);
|
display.setCursor(icon_x + g, y);
|
||||||
|
|||||||
@@ -153,12 +153,10 @@ class WaypointsView {
|
|||||||
|
|
||||||
int n = wpListCount();
|
int n = wpListCount();
|
||||||
int total = n + 1; // final row = "+ Add by coords"
|
int total = n + 1; // final row = "+ Add by coords"
|
||||||
const int step = display.lineStep();
|
|
||||||
|
|
||||||
int32_t mylat, mylon; bool have = ownPos(mylat, mylon);
|
int32_t mylat, mylon; bool have = ownPos(mylat, mylon);
|
||||||
|
|
||||||
drawList(display, total, _sel, _scroll, [&](int row, int y, bool sel, int reserve) {
|
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
|
if (row == n) { // the synthetic "Add" row
|
||||||
display.setCursor(2, y); display.print("+ Add by coords");
|
display.setCursor(2, y); display.print("+ Add by coords");
|
||||||
|
|||||||
@@ -499,6 +499,16 @@ inline int drawList(DisplayDriver& d, int total, int sel, int& scroll, RenderRow
|
|||||||
return visible;
|
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) ─────────────────────────────
|
// ── Big ASCII-art icons (skeleton, not yet used) ─────────────────────────────
|
||||||
// Same authoring idea as the mini-icons but for full page glyphs up to 32 px
|
// 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/…)
|
// wide: one uint32_t per row. The existing XBM bitmaps below (logo/bluetooth/…)
|
||||||
|
|||||||
Reference in New Issue
Block a user