mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-14 15:16:40 +00:00
feat(ui): marquee-scroll selected long names/labels instead of static ellipsis
Selecting a row whose ellipsized text overflows now animates a "swing" marquee: holds at the start, scrolls to reveal the full tail, holds there, then scrolls back and repeats. Unselected/non-overflowing text is unchanged (still a static "..."). E-ink gets slower, coarser steps (fewer, cheaper partial refreshes) than OLED; unchanged frames are already skipped by the display's CRC diff, so idle holds are free. Wired into every screen with a selectable row: home favourites, DM/ channel lists and message bodies, Settings, popup menus, Bot, Admin, Nearby, Waypoints, Locator, Live Share, and the alarm screen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -514,6 +514,7 @@ public:
|
||||
}
|
||||
tabbar::draw(display, TAB_LABELS, ATAB_COUNT, _tab);
|
||||
int n = ROWS_PER_TAB[_tab];
|
||||
int mq_delay = 0;
|
||||
drawList(display, n, _row_sel, _row_scroll, [&](int i, int y, bool sel, int reserve) {
|
||||
drawRowSelection(display, y, sel, reserve);
|
||||
const AdminField& f = fieldAt(_tab, i);
|
||||
@@ -523,7 +524,8 @@ public:
|
||||
// the value being edited -- only rows without an inline value get the
|
||||
// full row width.
|
||||
int label_max = show_val ? display.valCol() - 4 : display.width() - 4 - reserve;
|
||||
display.drawTextEllipsized(2, y, label_max, f.label);
|
||||
int r = display.drawTextEllipsized(2, y, label_max, f.label, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
if (show_val) {
|
||||
if (f.kind == FK_RADIO_FREQ) {
|
||||
// valCol() reserves exactly the 8-char width this editor draws (4
|
||||
@@ -540,7 +542,8 @@ public:
|
||||
}
|
||||
});
|
||||
if (_confirm.active) { _confirm.render(display); return 50; }
|
||||
return _value_editing ? 50 : 2000;
|
||||
if (_value_editing) return 50;
|
||||
return (mq_delay > 0 && mq_delay < 2000) ? mq_delay : 2000;
|
||||
}
|
||||
|
||||
// REPLY
|
||||
|
||||
@@ -149,6 +149,7 @@ public:
|
||||
}
|
||||
|
||||
int n = ROWS_PER_TAB[_tab];
|
||||
int mq_delay = 0;
|
||||
drawList(display, n, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
||||
Row r = tabRow(_tab, i);
|
||||
drawRowSelection(display, y, sel, reserve);
|
||||
@@ -173,9 +174,10 @@ public:
|
||||
ChannelDetails ch;
|
||||
if (_num_channels == 0)
|
||||
display.print("(none)");
|
||||
else if (the_mesh.getChannel(_prefs->bot_channel_idx, ch) && ch.name[0])
|
||||
display.drawTextEllipsized(val_x, y, display.width() - val_x - 1 - reserve, ch.name);
|
||||
else
|
||||
else if (the_mesh.getChannel(_prefs->bot_channel_idx, ch) && ch.name[0]) {
|
||||
int mqr = display.drawTextEllipsized(val_x, y, display.width() - val_x - 1 - reserve, ch.name, sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
} else
|
||||
display.print("?");
|
||||
break;
|
||||
}
|
||||
@@ -184,9 +186,10 @@ public:
|
||||
display.print("(none)");
|
||||
} else {
|
||||
ContactInfo* c = the_mesh.lookupContactByPubKey(_prefs->bot_room_prefix, NodePrefs::FAVOURITE_PREFIX_LEN);
|
||||
if (c && c->name[0])
|
||||
display.drawTextEllipsized(val_x, y, display.width() - val_x - 1 - reserve, c->name);
|
||||
else
|
||||
if (c && c->name[0]) {
|
||||
int mqr = display.drawTextEllipsized(val_x, y, display.width() - val_x - 1 - reserve, c->name, sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
} else
|
||||
display.print("?");
|
||||
}
|
||||
break;
|
||||
@@ -200,7 +203,8 @@ public:
|
||||
const char* shown = !tr[0] ? "(none)"
|
||||
: (tr[0] == '*' && !tr[1]) ? "(any msg)" // wildcard / away mode
|
||||
: tr;
|
||||
display.drawTextEllipsized(val_x, y, display.width() - val_x - 1 - reserve, shown);
|
||||
int mqr = display.drawTextEllipsized(val_x, y, display.width() - val_x - 1 - reserve, shown, sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
break;
|
||||
}
|
||||
case REPLY_DM:
|
||||
@@ -209,7 +213,8 @@ public:
|
||||
const char* rp = (r.kind == REPLY_DM) ? _prefs->bot_reply_dm
|
||||
: (r.kind == REPLY_CH) ? _prefs->bot_reply_ch
|
||||
: _prefs->bot_reply_room;
|
||||
display.drawTextEllipsized(val_x, y, display.width() - val_x - 1 - reserve, rp[0] ? rp : "(none)");
|
||||
int mqr = display.drawTextEllipsized(val_x, y, display.width() - val_x - 1 - reserve, rp[0] ? rp : "(none)", sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
break;
|
||||
}
|
||||
case COMMANDS_DM:
|
||||
|
||||
@@ -188,6 +188,7 @@ public:
|
||||
|
||||
if (_mode == ADD_HASHTAG) {
|
||||
display.drawCenteredHeader("ADD CHANNEL");
|
||||
int mq_delay = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int y = top + i * step;
|
||||
bool sel = (i == _sel);
|
||||
@@ -195,13 +196,15 @@ public:
|
||||
char row[40];
|
||||
if (i == 0) snprintf(row, sizeof(row), "Topic: %s", _topic[0] ? _topic : "(none)");
|
||||
else snprintf(row, sizeof(row), "[Save]");
|
||||
display.drawTextEllipsized(2, y, display.width() - 4, row);
|
||||
int r = display.drawTextEllipsized(2, y, display.width() - 4, row, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
}
|
||||
return 1000;
|
||||
return (mq_delay > 0 && mq_delay < 1000) ? mq_delay : 1000;
|
||||
}
|
||||
|
||||
display.drawCenteredHeader(_mode == ADD ? "ADD CHANNEL" : "EDIT CHANNEL");
|
||||
int mq_delay = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int y = top + i * step;
|
||||
bool sel = (i == _sel);
|
||||
@@ -213,10 +216,11 @@ public:
|
||||
else snprintf(row, sizeof(row), "[Save]");
|
||||
// Ellipsize rather than print() directly -- a long name/secret must not
|
||||
// wrap onto the next row's line (print() wraps by default).
|
||||
display.drawTextEllipsized(2, y, display.width() - 4, row);
|
||||
int r = display.drawTextEllipsized(2, y, display.width() - 4, row, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
}
|
||||
return 1000;
|
||||
return (mq_delay > 0 && mq_delay < 1000) ? mq_delay : 1000;
|
||||
}
|
||||
|
||||
bool handleInput(char c) {
|
||||
|
||||
@@ -166,19 +166,22 @@ class ClockToolsScreen : public UIScreen {
|
||||
const char* rows[3] = { "Time", "Repeat", "Armed" };
|
||||
if (_sel > 2) _sel = 2;
|
||||
const int valx = d.width() / 2 + 6;
|
||||
int mq_delay = 0;
|
||||
drawList(d, 3, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
||||
drawRowSelection(d, y, sel, reserve);
|
||||
d.setCursor(4, y); d.print(rows[i]);
|
||||
if (i == 0) {
|
||||
drawAlarmTime(d, y, valx, sel && _alarm_editing);
|
||||
} else if (i == 1) {
|
||||
d.drawTextEllipsized(valx, y, d.width() - valx - reserve,
|
||||
NodePrefs::alarmRepeatLabel(NodePrefs::alarmRepeatIdxForMask(_prefs->alarm_repeat_mask)));
|
||||
int mqr = d.drawTextEllipsized(valx, y, d.width() - valx - reserve,
|
||||
NodePrefs::alarmRepeatLabel(NodePrefs::alarmRepeatIdxForMask(_prefs->alarm_repeat_mask)), sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
} else {
|
||||
d.drawTextEllipsized(valx, y, d.width() - valx - reserve, _prefs->alarm_on ? "ON" : "OFF");
|
||||
}
|
||||
});
|
||||
return _alarm_editing ? 50 : 60000;
|
||||
if (_alarm_editing) return 50;
|
||||
return (mq_delay > 0 && mq_delay < 60000) ? mq_delay : 60000;
|
||||
}
|
||||
|
||||
int renderTimer(DisplayDriver& d) {
|
||||
|
||||
@@ -90,6 +90,7 @@ public:
|
||||
display.drawCenteredHeader("LIVE SHARE");
|
||||
|
||||
const int valx = display.width() / 2 + 6;
|
||||
int mq_delay = 0;
|
||||
drawList(display, ROW_COUNT, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
||||
Row r = rows(i);
|
||||
drawRowSelection(display, y, sel, reserve);
|
||||
@@ -97,9 +98,12 @@ public:
|
||||
display.print(r.label);
|
||||
char val[24];
|
||||
valueLabel(r.kind, val, sizeof(val));
|
||||
if (val[0]) display.drawTextEllipsized(valx, y, display.width() - valx - reserve, val);
|
||||
if (val[0]) {
|
||||
int mqr = display.drawTextEllipsized(valx, y, display.width() - valx - reserve, val, sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
}
|
||||
});
|
||||
return 500;
|
||||
return (mq_delay > 0 && mq_delay < 500) ? mq_delay : 500;
|
||||
}
|
||||
|
||||
void moveSel(int dir) { _sel = (_sel + dir + ROW_COUNT) % ROW_COUNT; }
|
||||
|
||||
@@ -108,12 +108,13 @@ public:
|
||||
int render(DisplayDriver& display) override {
|
||||
display.setTextSize(1);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
if (_picking) { renderPicker(display); return 400; }
|
||||
if (_picking) { int mq = renderPicker(display); return (mq > 0 && mq < 400) ? mq : 400; }
|
||||
display.drawCenteredHeader("LOCATOR");
|
||||
|
||||
const int rc = visibleRows();
|
||||
if (_sel >= rc) _sel = rc - 1; // beeper row may have just been hidden
|
||||
const int valx = display.width() / 2 + 6;
|
||||
int mq_delay = 0;
|
||||
drawList(display, rc, _sel, _scroll, [&](int i, int y, bool sel, int reserve) {
|
||||
Row r = rows(i);
|
||||
drawRowSelection(display, y, sel, reserve);
|
||||
@@ -121,9 +122,12 @@ public:
|
||||
display.print(r.label);
|
||||
char val[24];
|
||||
valueLabel(r.kind, val, sizeof(val));
|
||||
if (val[0]) display.drawTextEllipsized(valx, y, display.width() - valx - reserve, val);
|
||||
if (val[0]) {
|
||||
int mqr = display.drawTextEllipsized(valx, y, display.width() - valx - reserve, val, sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
}
|
||||
});
|
||||
return 500;
|
||||
return (mq_delay > 0 && mq_delay < 500) ? mq_delay : 500;
|
||||
}
|
||||
|
||||
void moveSel(int dir) { int rc = visibleRows(); _sel = (_sel + dir + rc) % rc; }
|
||||
@@ -261,9 +265,12 @@ public:
|
||||
_picking = true;
|
||||
}
|
||||
|
||||
void renderPicker(DisplayDriver& display) {
|
||||
// Returns 0, or the ms until the selected row should next redraw to keep a
|
||||
// marquee animation going (see DisplayDriver::drawTextEllipsized).
|
||||
int renderPicker(DisplayDriver& display) {
|
||||
display.drawCenteredHeader("PICK TARGET");
|
||||
uint32_t now = rtc_clock.getCurrentTime();
|
||||
int mq_delay = 0;
|
||||
drawList(display, _target_n, _pick_sel, _pick_scroll, [&](int i, int y, bool sel, int reserve) {
|
||||
drawRowSelection(display, y, sel, reserve);
|
||||
const Target& t = _targets[i];
|
||||
@@ -279,8 +286,10 @@ public:
|
||||
} else {
|
||||
snprintf(row, sizeof(row), "@%s", t.name); // favourite, no position known yet
|
||||
}
|
||||
display.drawTextEllipsized(2, y, display.width() - 2 - reserve, row);
|
||||
int mqr = display.drawTextEllipsized(2, y, display.width() - 2 - reserve, row, sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
});
|
||||
return mq_delay;
|
||||
}
|
||||
|
||||
bool handleInput(char c) override {
|
||||
|
||||
@@ -955,6 +955,7 @@ public:
|
||||
}
|
||||
|
||||
int render(DisplayDriver& display) override {
|
||||
int mq_delay = 0; // >0 while a selected row's text is marquee-scrolling
|
||||
display.setTextSize(1);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
|
||||
@@ -1007,7 +1008,8 @@ public:
|
||||
display.translateUTF8ToBlocks(filtered, c.name, sizeof(filtered));
|
||||
uint8_t dm_unread = _task->getDMUnread(c.id.pub_key);
|
||||
int bw = dm_unread > 0 ? display.unreadBadgeWidth(dm_unread) + 2 : 0;
|
||||
display.drawTextEllipsized(2, y, display.width() - 2 - bw - reserve, filtered);
|
||||
int r = display.drawTextEllipsized(2, y, display.width() - 2 - bw - reserve, filtered, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
if (dm_unread > 0)
|
||||
display.drawUnreadBadge(display.width() - reserve, y, dm_unread, sel);
|
||||
}
|
||||
@@ -1040,7 +1042,8 @@ public:
|
||||
if (the_mesh.getChannel(_channel_indices[list_idx], ch)) {
|
||||
uint8_t unread = _history.chUnread(_channel_indices[list_idx]);
|
||||
int bw = unread > 0 ? display.unreadBadgeWidth(unread) + 2 : 0;
|
||||
display.drawTextEllipsized(2, y, display.width() - 4 - bw - reserve, ch.name);
|
||||
int r = display.drawTextEllipsized(2, y, display.width() - 4 - bw - reserve, ch.name, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
if (unread > 0)
|
||||
display.drawUnreadBadge(display.width() - reserve, y, unread, sel);
|
||||
}
|
||||
@@ -1179,6 +1182,9 @@ public:
|
||||
BubbleBox box = computeBubbleBox(full_avail, e.outgoing, header_w, body_w);
|
||||
|
||||
drawHistRowFrame(display, box.x, box.w, y, bh, lh, sel);
|
||||
// Only the body marquees, not the sender too: both share the single
|
||||
// marquee slot on DisplayDriver, and if two texts in the same row both
|
||||
// qualified they'd keep resetting each other's animation every frame.
|
||||
display.drawTextEllipsized(box.x + 3, y + 1, box.w - 6 - age_w, sender);
|
||||
if (e.outgoing) { // delivery marker after "Me"
|
||||
int gx = box.x + 3 + display.getTextWidth(sender) + 3;
|
||||
@@ -1189,7 +1195,8 @@ public:
|
||||
if (portrait_expand) {
|
||||
for (int li = 0; li < nl; li++) { display.setCursor(box.x + 3, y + (li + 1) * lh + 1); display.print(s_wrap_lines[li]); }
|
||||
} else {
|
||||
display.drawTextEllipsized(box.x + 3, y + lh + 1, box.w - 6, body);
|
||||
int r_body = display.drawTextEllipsized(box.x + 3, y + lh + 1, box.w - 6, body, sel);
|
||||
if (sel && r_body > 0) mq_delay = r_body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1213,7 +1220,7 @@ public:
|
||||
|
||||
drawComposeButton(display, cby, lh, _dm_hist_sel == -1);
|
||||
if (_ctx_menu.active) _ctx_menu.render(display);
|
||||
return dm_count > 0 ? 500 : 2000;
|
||||
{ int ret = dm_count > 0 ? 500 : 2000; return (mq_delay > 0 && mq_delay < ret) ? mq_delay : ret; }
|
||||
|
||||
} else if (_phase == CHANNEL_HIST) {
|
||||
if (_fs.active && _hist_sel >= 0) {
|
||||
@@ -1354,6 +1361,7 @@ public:
|
||||
BubbleBox box = computeBubbleBox(full_avail, outgoing, header_w, body_w);
|
||||
|
||||
drawHistRowFrame(display, box.x, box.w, y, bh, lh, sel);
|
||||
// Only the body marquees, not the sender — see the DM history block above.
|
||||
display.drawTextEllipsized(box.x + 3, y + 1, box.w - 6 - age_w, sender);
|
||||
if (show_ack) {
|
||||
int gx = box.x + 3 + display.getTextWidth(sender) + 3;
|
||||
@@ -1364,7 +1372,8 @@ public:
|
||||
if (portrait_expand) {
|
||||
for (int li = 0; li < nl; li++) { display.setCursor(box.x + 3, y + (li + 1) * lh + 1); display.print(s_wrap_lines[li]); }
|
||||
} else {
|
||||
display.drawTextEllipsized(box.x + 3, y + lh + 1, box.w - 6, body);
|
||||
int r_body = display.drawTextEllipsized(box.x + 3, y + lh + 1, box.w - 6, body, sel);
|
||||
if (sel && r_body > 0) mq_delay = r_body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1421,11 +1430,12 @@ public:
|
||||
NodePrefs* p = _task->getNodePrefs();
|
||||
int slot = _active_msgs[idx - 1];
|
||||
const char* tmpl = p ? p->custom_msgs[slot] : "";
|
||||
display.drawTextEllipsized(2, y, display.width() - 4 - reserve, tmpl);
|
||||
int r = display.drawTextEllipsized(2, y, display.width() - 4 - reserve, tmpl, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
}
|
||||
});
|
||||
}
|
||||
return 2000;
|
||||
return (mq_delay > 0 && mq_delay < 2000) ? mq_delay : 2000;
|
||||
}
|
||||
|
||||
bool handleInput(char c) override {
|
||||
|
||||
@@ -771,6 +771,7 @@ public:
|
||||
|
||||
int render(DisplayDriver& display) override {
|
||||
display.setTextSize(1);
|
||||
int mq_delay = 0; // >0 while the selected row's name is marquee-scrolling
|
||||
|
||||
// Periodic refresh of the selected entry while in detail or navigate view,
|
||||
// preserving the selection across the list rebuild. Navigate refreshes
|
||||
@@ -876,7 +877,8 @@ public:
|
||||
if (_source == SRC_SCAN && !e.name[0]) { // unknown node → "[Type]"
|
||||
snprintf(filt, sizeof(filt), "[%s]", typeName(e.type));
|
||||
}
|
||||
display.drawTextEllipsized(tx, y, dist_col - tx - 2, filt);
|
||||
int mqr = display.drawTextEllipsized(tx, y, dist_col - tx - 2, filt, sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
|
||||
display.setColor(sel ? DisplayDriver::DARK : DisplayDriver::LIGHT);
|
||||
char right[10];
|
||||
@@ -894,8 +896,10 @@ public:
|
||||
}
|
||||
|
||||
if (renderActivePopup(display)) return 50;
|
||||
if (_source == SRC_SCAN) return _scanning ? 200 : 2000;
|
||||
return _count == 0 ? 3000 : 2000;
|
||||
int ret;
|
||||
if (_source == SRC_SCAN) ret = _scanning ? 200 : 2000;
|
||||
else ret = _count == 0 ? 3000 : 2000;
|
||||
return (mq_delay > 0 && mq_delay < ret) ? mq_delay : ret;
|
||||
}
|
||||
|
||||
bool handleInput(char c) override {
|
||||
|
||||
@@ -114,7 +114,9 @@ struct PopupMenu {
|
||||
} else {
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
}
|
||||
display.drawTextEllipsized(bx + pad, py, text_w, _items[idx]);
|
||||
// Return value not needed here: this popup already redraws every 50ms
|
||||
// (below), faster than any marquee step, so the animation is already smooth.
|
||||
display.drawTextEllipsized(bx + pad, py, text_w, _items[idx], idx == _sel);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
}
|
||||
|
||||
|
||||
@@ -440,8 +440,11 @@ class SettingsScreen : public UIScreen {
|
||||
return item - MSG_SLOT_0;
|
||||
}
|
||||
|
||||
void renderItem(DisplayDriver& display, int item, int y, bool sel) {
|
||||
// Returns 0, or the ms until the selected row's value should next redraw
|
||||
// to keep a marquee animation going (see DisplayDriver::drawTextEllipsized).
|
||||
int renderItem(DisplayDriver& display, int item, int y, bool sel) {
|
||||
NodePrefs* p = _task->getNodePrefs();
|
||||
int mq_delay = 0;
|
||||
|
||||
drawRowSelection(display, y, sel, _reserve);
|
||||
|
||||
@@ -514,7 +517,8 @@ class SettingsScreen : public UIScreen {
|
||||
display.print("Preset");
|
||||
const char* name = p ? _picker.currentName(p, radioTarget(p)) : "Custom";
|
||||
int xc = valCol(display);
|
||||
display.drawTextEllipsized(xc, y, display.width() - xc - _reserve, name);
|
||||
int r = display.drawTextEllipsized(xc, y, display.width() - xc - _reserve, name, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
} else if (item == CUSTOM_FREQ) {
|
||||
display.print("Freq");
|
||||
int xc = valCol(display);
|
||||
@@ -559,8 +563,9 @@ class SettingsScreen : public UIScreen {
|
||||
} else if (item == SCOPE_NAME) {
|
||||
display.print("Scope");
|
||||
int vx = valCol(display);
|
||||
display.drawTextEllipsized(vx, y, display.width() - vx - _reserve,
|
||||
(p && p->default_scope_name[0]) ? p->default_scope_name : "(none)");
|
||||
int r = display.drawTextEllipsized(vx, y, display.width() - vx - _reserve,
|
||||
(p && p->default_scope_name[0]) ? p->default_scope_name : "(none)", sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
} else if (item == AUTO_OFF) {
|
||||
display.print("AutoOff");
|
||||
@@ -596,7 +601,8 @@ class SettingsScreen : public UIScreen {
|
||||
} else if (item == DEVICE_NAME) {
|
||||
display.print("Name");
|
||||
int vx = valCol(display);
|
||||
display.drawTextEllipsized(vx, y, display.width() - vx - _reserve, the_mesh.getNodeName());
|
||||
int r = display.drawTextEllipsized(vx, y, display.width() - vx - _reserve, the_mesh.getNodeName(), sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
} else if (item == REBOOT) {
|
||||
display.print("Reboot"); // action row: Enter reboots this device
|
||||
} else if (item == KEYBOARD_TYPE) {
|
||||
@@ -677,8 +683,10 @@ class SettingsScreen : public UIScreen {
|
||||
display.print(label);
|
||||
const char* tmpl = (p && p->custom_msgs[slot][0]) ? p->custom_msgs[slot] : "(empty)";
|
||||
int xm = 8 + display.getCharWidth() * 4;
|
||||
display.drawTextEllipsized(xm, y, display.width() - xm - _reserve, tmpl);
|
||||
int r = display.drawTextEllipsized(xm, y, display.width() - xm - _reserve, tmpl, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
}
|
||||
return mq_delay;
|
||||
}
|
||||
|
||||
// Keyboard state for editing message slots
|
||||
@@ -722,6 +730,7 @@ public:
|
||||
|
||||
display.drawCenteredHeader("SETTINGS");
|
||||
|
||||
int mq_delay = 0;
|
||||
_acc.render(display,
|
||||
// Section header: "[+/-] Name"
|
||||
[&](int sec, int y, bool sel, int reserve, bool collapsed) {
|
||||
@@ -736,12 +745,13 @@ public:
|
||||
// Item row
|
||||
[&](int sec, int item, int y, bool sel, int reserve) {
|
||||
_reserve = reserve;
|
||||
renderItem(display, _sec_items[sec][item], y, sel);
|
||||
int r = renderItem(display, _sec_items[sec][item], y, sel);
|
||||
if (r > 0) mq_delay = r;
|
||||
});
|
||||
|
||||
if (_picker.menu.active) _picker.menu.render(display);
|
||||
|
||||
return 2000;
|
||||
return (mq_delay > 0 && mq_delay < 2000) ? mq_delay : 2000;
|
||||
}
|
||||
|
||||
bool handleInput(char c) override {
|
||||
|
||||
@@ -718,6 +718,7 @@ public:
|
||||
|
||||
int render(DisplayDriver& display) override {
|
||||
char tmp[80];
|
||||
int mq_delay = 0; // >0 while a selected row's name is marquee-scrolling
|
||||
display.setTextSize(1);
|
||||
const int lh = display.getLineHeight(); // line height at sz1
|
||||
const int step = display.lineStep(); // lh + 2
|
||||
@@ -1198,7 +1199,8 @@ public:
|
||||
int name_y = cy + (cell_h - line_h) / 2;
|
||||
int name_max_w = cell_w - 4 - bw;
|
||||
if (name_max_w < 6) name_max_w = 6;
|
||||
display.drawTextEllipsized(cx + 2, name_y, name_max_w, name);
|
||||
int r = display.drawTextEllipsized(cx + 2, name_y, name_max_w, name, sel);
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
if (unread > 0)
|
||||
display.drawUnreadBadge(cx + cell_w - 2, name_y, unread, sel);
|
||||
} else {
|
||||
@@ -1244,13 +1246,15 @@ public:
|
||||
(auto_adv || _task->trail().isActive() || repeating || loc_sharing);
|
||||
if (Features::IS_EINK) {
|
||||
// slow display: poll every 30 s; inbound msgs force immediate refresh via notify()
|
||||
return Features::HOME_REFRESH_MS;
|
||||
return (mq_delay > 0 && mq_delay < Features::HOME_REFRESH_MS) ? mq_delay : Features::HOME_REFRESH_MS;
|
||||
}
|
||||
if (_page == HomePage::CLOCK) {
|
||||
bool show_sec = !_node_prefs || !_node_prefs->clock_hide_seconds;
|
||||
return need_blink ? 1000 : (show_sec ? 1000 : 60000);
|
||||
int ret = need_blink ? 1000 : (show_sec ? 1000 : 60000);
|
||||
return (mq_delay > 0 && mq_delay < ret) ? mq_delay : ret;
|
||||
}
|
||||
return need_blink ? 1000 : 5000;
|
||||
int ret = need_blink ? 1000 : 5000;
|
||||
return (mq_delay > 0 && mq_delay < ret) ? mq_delay : ret;
|
||||
}
|
||||
|
||||
bool handleInput(char c) override {
|
||||
|
||||
@@ -190,7 +190,10 @@ class WaypointsView {
|
||||
display.setCursor(2, top + 2 * step); display.print("Cancel to abort");
|
||||
}
|
||||
|
||||
void renderWpList(DisplayDriver& display) {
|
||||
// Returns 0, or the ms until the selected row's name should next redraw to
|
||||
// keep a marquee animation going (see DisplayDriver::drawTextEllipsized).
|
||||
int renderWpList(DisplayDriver& display) {
|
||||
int mq_delay = 0;
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
char title[24];
|
||||
snprintf(title, sizeof(title), "WAYPOINTS %d/%d",
|
||||
@@ -219,10 +222,12 @@ class WaypointsView {
|
||||
}
|
||||
char nm[24];
|
||||
display.translateUTF8ToBlocks(nm, label, sizeof(nm));
|
||||
display.drawTextEllipsized(2, y, display.width() - 2 - bw - reserve, nm);
|
||||
int mqr = display.drawTextEllipsized(2, y, display.width() - 2 - bw - reserve, nm, sel);
|
||||
if (sel && mqr > 0) mq_delay = mqr;
|
||||
if (dist[0]) { display.setCursor(display.width() - bw + 1 - reserve, y); display.print(dist); }
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
});
|
||||
return mq_delay;
|
||||
}
|
||||
|
||||
void renderWpNav(DisplayDriver& display) {
|
||||
@@ -361,9 +366,9 @@ public:
|
||||
if (_mode == AVG) { renderAvg(display); return display.isEink() ? 1000 : 300; }
|
||||
if (_mode == TRACKBACK) { renderTrackBack(display); return 1000; }
|
||||
if (_mode == NAV) { renderWpNav(display); return 1000; }
|
||||
renderWpList(display); // LIST
|
||||
int mq_delay = renderWpList(display); // LIST
|
||||
if (_ctx.active) _ctx.render(display);
|
||||
return 1000;
|
||||
return (mq_delay > 0 && mq_delay < 1000) ? mq_delay : 1000;
|
||||
}
|
||||
|
||||
// Returns true if the input was consumed (always, while active()).
|
||||
|
||||
Reference in New Issue
Block a user