mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-01 10:21:59 +00:00
refactor(ui): remove dead code and fix stale comments after the review
- ui-core: Diagnostics::systemLines, NearbyModel::typeShort, rptctl::currentPresetName, RoomSessions::pendingKey, settings::isSwitch, UiCore::reconcileDMUnread. - ui-new: the retired Recent page, fmtAlt, the battMvToPercent wrapper, setFavouriteChannelSlot, AccordionList onHeader/visibleCount, drawBoxedIcon and seven unused icons; info::row folded into info::valueRow. - ui-lvgl: onOpenNav, TileDownloader::withTrails; the trail header size is one constant (TRAIL_HDR) for live and saved trails. - Home quick panels save prefs only when a value changed. - Comments brought in line with the code (status bar reserve, settings rows, page order, SH1106 frame skip, UiCore header). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -543,14 +543,6 @@ extern "C" EMSCRIPTEN_KEEPALIVE int sim_test_set_timezone_hours(int hours) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// auto_off_secs (NodePrefs.h) defaults to 15 -- a real device's screen
|
||||
// (and, if auto_lock is also set, the UI itself) turns off/locks 15s
|
||||
// after the last input, real power-saving behaviour a battery-powered
|
||||
// board actually needs. UITask::autoOffMillis() (ui-new/UITask.h) treats
|
||||
// 0 as "never" and skips the whole turnOff()/auto_lock branch in
|
||||
// UITask::loop() entirely -- there's no separate flag to touch. A demo
|
||||
// running on a visitor's screen has no battery to save and no reason to
|
||||
// go dark or lock itself while they're reading it.
|
||||
// Renames this instance (NodePrefs::node_name, what Settings > Name sets) so
|
||||
// a host page's peers have readable names in screenshots, instead of the
|
||||
// default hex of their public key. In memory only; the next advert carries it.
|
||||
@@ -562,6 +554,14 @@ extern "C" EMSCRIPTEN_KEEPALIVE int sim_test_set_node_name(const char* name) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// auto_off_secs (NodePrefs.h) defaults to 15 -- a real device's screen
|
||||
// (and, if auto_lock is also set, the UI itself) turns off/locks 15s
|
||||
// after the last input, real power-saving behaviour a battery-powered
|
||||
// board actually needs. UITask::autoOffMillis() (ui-new/UITask.h) treats
|
||||
// 0 as "never" and skips the whole turnOff()/auto_lock branch in
|
||||
// UITask::loop() entirely -- there's no separate flag to touch. A demo
|
||||
// running on a visitor's screen has no battery to save and no reason to
|
||||
// go dark or lock itself while they're reading it.
|
||||
extern "C" EMSCRIPTEN_KEEPALIVE int sim_test_disable_screen_timeout() {
|
||||
if (!g_sim_ready) return 0;
|
||||
NodePrefs* prefs = the_mesh.getNodePrefs();
|
||||
|
||||
@@ -118,24 +118,6 @@ inline void shortVersion(char* out, size_t n) {
|
||||
out[len] = '\0';
|
||||
}
|
||||
|
||||
// Static system card, one full-width line each. Returns the line count.
|
||||
inline int systemLines(Line* lines) {
|
||||
int n = 0;
|
||||
char sv[24];
|
||||
shortVersion(sv, sizeof(sv));
|
||||
addLine(lines, n, "FW %s", sv);
|
||||
addLine(lines, n, "Built %s", FIRMWARE_BUILD_DATE);
|
||||
addLine(lines, n, "Dev %s", board.getManufacturerName());
|
||||
addLine(lines, n, "Node %s", the_mesh.getNodeName());
|
||||
NodePrefs* p = the_mesh.getNodePrefs();
|
||||
if (p) {
|
||||
addLine(lines, n, "Freq %.3f MHz", p->freq);
|
||||
addLine(lines, n, "SF%u BW%.0f CR%u", (unsigned)p->sf, p->bw, (unsigned)p->cr);
|
||||
addLine(lines, n, "TX %d dBm", (int)p->tx_power_dbm);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// One sample per script the UI font covers, to check coverage by eye. "Acc"
|
||||
// takes one letter from each of the keyboard's accent-popup groups.
|
||||
inline int fontLines(Line* lines) {
|
||||
|
||||
@@ -68,16 +68,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static const char* typeShort(uint8_t t) {
|
||||
switch (t) {
|
||||
case ADV_TYPE_REPEATER: return "Rpt";
|
||||
case ADV_TYPE_SENSOR: return "Snsr";
|
||||
case ADV_TYPE_ROOM: return "Room";
|
||||
case ADV_TYPE_CHAT: return "Comp";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
void bindModel(UiCore* core, NodePrefs* prefs) { _core = core; _prefs = prefs; }
|
||||
|
||||
int count() const { return _count; }
|
||||
|
||||
@@ -61,11 +61,6 @@ static int currentPreset(const NodePrefs* p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char* currentPresetName(const NodePrefs* p) {
|
||||
const char* name; float f, b; uint8_t s, c;
|
||||
return radioctl::presetAt(p, currentPreset(p), name, f, b, s, c) ? name : "Custom";
|
||||
}
|
||||
|
||||
static bool choosePreset(NodePrefs* p, int idx) {
|
||||
const char* name; float f, b; uint8_t s, c;
|
||||
if (!p || !radioctl::presetAt(p, idx, name, f, b, s, c)) return false;
|
||||
|
||||
@@ -43,7 +43,6 @@ public:
|
||||
|
||||
bool loggingIn() const { return _pending; }
|
||||
bool loggingIn(const uint8_t* pub_key) const { return _pending && memcmp(_pending_key, pub_key, 4) == 0; }
|
||||
const uint8_t* pendingKey() const { return _pending_key; }
|
||||
|
||||
// Local only: the room ACL has no session to tear down (MyMesh::logoutRoom()).
|
||||
void logout(const uint8_t* pub_key) {
|
||||
|
||||
@@ -249,8 +249,6 @@ static const char* shortLabel(const Setting& s) {
|
||||
for (auto& l : SHORT_LABELS) if (l.offset == s.offset) return l.text;
|
||||
return s.label;
|
||||
}
|
||||
// A switch: two values, no labels of its own (on / off, however it's stored).
|
||||
static bool isSwitch(const Setting& s) { return !s.option && s.count == 2; }
|
||||
// The index of the setting over NodePrefs field `offset`; -1 if none.
|
||||
static int indexOf(uint16_t offset) {
|
||||
for (int i = 0; i < COUNT; i++) if (ALL[i].offset == offset) return i;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
// UI Core: hardware-independent UI state and logic shared by every frontend
|
||||
// (ui-new today, ui-lvgl later). See docs/solo/developer/ui-core.md.
|
||||
// (ui-new on the OLED / e-ink boards, ui-lvgl on the L2). See
|
||||
// docs/solo/developer/ui-core.md.
|
||||
//
|
||||
// The Core is MyMesh's Listener: it files incoming/outgoing messages into the
|
||||
// history, keeps the unread counters, runs the engines, and tells the frontend
|
||||
@@ -89,7 +90,6 @@ public:
|
||||
void clearAllDMUnread() { dm_unread.clearAll(); }
|
||||
// Every conversation read: direct, channels, rooms.
|
||||
void markAllRead() { _room_unread = 0; dm_unread.clearAll(); history.clearAllChannelUnread(); }
|
||||
void reconcileDMUnread() { dm_unread.reconcile(history); }
|
||||
|
||||
// ── Actions ───────────────────────────────────────────────────────────────
|
||||
// Send a DM composed on the device and file it (with end-to-end ACK tracking
|
||||
|
||||
@@ -1131,7 +1131,7 @@ bool UITask::saveTrailToCard(char* name_out, size_t n) {
|
||||
// ring (the oldest points dropping off) is rewritten, at most every 10 min.
|
||||
namespace navmap {
|
||||
static const char* const LIVE_TRAIL = "/sdcard/trails/.live.trl";
|
||||
static const long LIVE_HDR = 12; // magic, version, reserved, count (uint16), time (uint32)
|
||||
static const long TRAIL_HDR = 12; // a trail file's header (TrailStore::writeTo): magic, version, flags, count (uint16), time (uint32)
|
||||
static uint32_t s_j_gen = 0xFFFFFFFF, s_j_seq = 0, s_j_next = 0, s_j_full_at = 0;
|
||||
static int s_j_n = 0;
|
||||
static uint8_t s_j_rec = 0; // the "recording" byte last written
|
||||
@@ -1202,7 +1202,7 @@ void UITask::savedTrailsPopup() {
|
||||
navmap::trailTitle(navmap::s_st_names[i], title, sizeof(title));
|
||||
snprintf(path, sizeof(path), "%s/%s", navmap::TRAILS_DIR, navmap::s_st_names[i]);
|
||||
struct stat st;
|
||||
long pts = stat(path, &st) == 0 ? ((long)st.st_size - 12) / (long)sizeof(TrailPoint) : 0;
|
||||
long pts = stat(path, &st) == 0 ? ((long)st.st_size - navmap::TRAIL_HDR) / (long)sizeof(TrailPoint) : 0;
|
||||
snprintf(sub, sizeof(sub), "%ld points", pts > 0 ? pts : 0);
|
||||
listRow(list, title, sub, onSavedTrail, (void*)(intptr_t)i);
|
||||
}
|
||||
|
||||
@@ -2786,7 +2786,6 @@ static void onOpenSettings(lv_event_t* e) { (void)e; s_ui->showSettings(); }
|
||||
|
||||
static void onOpenNearby(lv_event_t* e) { (void)e; s_ui->showNearby(); }
|
||||
static void onOpenNodesMap(lv_event_t* e) { (void)e; s_ui->openMap(false); }
|
||||
static void onOpenNav(lv_event_t* e) { (void)e; s_ui->openMap(true); }
|
||||
static void onOpenClock(lv_event_t* e); // ClockScreen.h
|
||||
static void onOpenBot(lv_event_t* e); // BotScreen.h
|
||||
static void onOpenCompass(lv_event_t* e); // CompassScreen.h
|
||||
|
||||
@@ -95,7 +95,6 @@ public:
|
||||
|
||||
State state() const { return _state; }
|
||||
const TileArea& area() const { return _area; } // of the current / last job
|
||||
bool withTrails() const { return _trails; }
|
||||
bool active() const { return _state == CONNECTING || _state == RUNNING; }
|
||||
uint32_t total() const { return _total; }
|
||||
uint32_t processed() const { return _done + _skipped + _failed; }
|
||||
|
||||
@@ -35,10 +35,8 @@ public:
|
||||
rebuild();
|
||||
}
|
||||
|
||||
int visibleCount() const { return _vis_count; }
|
||||
bool collapsed(int sec) const { return (_collapsed >> sec) & 1; }
|
||||
const Row& selected() const { return _rows[_sel]; }
|
||||
bool onHeader() const { return _vis_count && _rows[_sel].item < 0; }
|
||||
|
||||
// Paint via the shared drawList skeleton. `header(sec, y, sel, reserve,
|
||||
// collapsed)` and `item(sec, item, y, sel, reserve)` each draw one row
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
|
||||
namespace info {
|
||||
|
||||
// Label at the left, value flush right with its unit after a space ("50 m").
|
||||
// `reserve` keeps the value clear of a scroll column.
|
||||
// Whether a value fits on its label's line (else rowH() gives it a line below).
|
||||
// `reserve` keeps the value clear of a scroll column.
|
||||
inline bool rowFits(DisplayDriver& d, const char* label, const char* value, int reserve = 0, int x0 = 1) {
|
||||
if (!value || !*value) return true;
|
||||
const int room = d.width() - reserve - 2 - (x0 + d.getTextWidth(label) + d.getCharWidth());
|
||||
@@ -40,17 +39,6 @@ inline void rowWrapped(DisplayDriver& d, int y, const char* label, const char* v
|
||||
else d.drawTextEllipsized(right - room, vy, room, value);
|
||||
}
|
||||
|
||||
// A value too long for the space left beside its label ends in an ellipsis.
|
||||
inline void row(DisplayDriver& d, int y, const char* label, const char* value, int reserve = 0, int x0 = 1) {
|
||||
d.setCursor(x0, y);
|
||||
d.print(label);
|
||||
if (!value || !*value) return;
|
||||
const int right = d.width() - reserve - 2;
|
||||
const int room = right - (x0 + d.getTextWidth(label) + d.getCharWidth());
|
||||
if ((int)d.getTextWidth(value) <= room) d.drawTextRightAlign(right, y, value);
|
||||
else if (room > d.getCharWidth()) d.drawTextEllipsized(right - room, y, room, value);
|
||||
}
|
||||
|
||||
// A dotted rule across [x, x + w), the separator between categories.
|
||||
inline void rule(DisplayDriver& d, int x, int y, int w) {
|
||||
const int s = miniIconScale(d);
|
||||
@@ -146,8 +134,9 @@ inline void toggle(DisplayDriver& d, int x_right, int y, bool on, bool inv = fal
|
||||
}
|
||||
|
||||
// ── List rows (call after drawRowSelection(); text is already in the row's ink)
|
||||
// A setting or field: label at x0, value flush right. A value too long for the
|
||||
// room beside the label is cut, and scrolls while the row is selected.
|
||||
// A setting or field: label at x0, value flush right with its unit after a
|
||||
// space ("50 m"). A value too long for the room beside the label is cut, and
|
||||
// scrolls while the row is selected (sel).
|
||||
// Returns that marquee's next-step delay (0: nothing moving).
|
||||
inline int valueRow(DisplayDriver& d, int y, const char* label, const char* value, bool sel,
|
||||
int reserve, int x0 = 2) {
|
||||
|
||||
@@ -400,8 +400,9 @@ class SettingsScreen : public UIScreen {
|
||||
}
|
||||
}
|
||||
// Default: CLOCK FAVOURITES RECENT RADIO BT ADVERT [GPS] [SENSORS] SETTINGS
|
||||
// MAP TOOLS MESSAGES SHUTDOWN — mirrors the home-carousel enum order. Every
|
||||
// page has an explicit slot now (PAGE_ORDER_LEN == HPB_COUNT).
|
||||
// MAP TOOLS MESSAGES SHUTDOWN. Every bit keeps a slot (PAGE_ORDER_LEN ==
|
||||
// HPB_COUNT), retired ones too: RECENT shows nowhere, and Status stands in
|
||||
// the RADIO slot for the old Radio, GPS and Sensors pages.
|
||||
int j = 0;
|
||||
p->page_order[j++] = NodePrefs::HPB_CLOCK + 1;
|
||||
p->page_order[j++] = NodePrefs::HPB_FAVOURITES + 1;
|
||||
|
||||
@@ -107,7 +107,7 @@ private:
|
||||
if (f.place(d.lineStep())) { // label, the last half hour, the value now
|
||||
const int nf = (int)radio_driver.getNoiseFloor();
|
||||
if (nf) snprintf(a, sizeof(a), "%d dBm", nf); else strcpy(a, "-");
|
||||
info::row(d, f.at, "Noise", a, rsv);
|
||||
info::valueRow(d, f.at, "Noise", a, false, rsv, 1);
|
||||
const int x0 = 1 + d.getTextWidth("Noise") + 6;
|
||||
const int x1 = d.width() - rsv - 2 - d.getTextWidth(a) - 6;
|
||||
if (x1 - x0 > 12) info::spark(d, x0, f.at, x1 - x0, lh - 1, _noise);
|
||||
@@ -115,7 +115,7 @@ private:
|
||||
if (f.place(d.lineStep())) {
|
||||
const float snr = radio_driver.getLastSNR();
|
||||
snprintf(b, sizeof(b), "%d dBm", (int)radio_driver.getLastRSSI());
|
||||
info::row(d, f.at, "Last RX", b, rsv);
|
||||
info::valueRow(d, f.at, "Last RX", b, false, rsv, 1);
|
||||
drawSignalBars(d, d.width() - rsv - 2 - d.getTextWidth(b) - 5, f.at, (int)(snr * 4));
|
||||
}
|
||||
snprintf(b, sizeof(b), "%.1f dB", radio_driver.getLastSNR());
|
||||
@@ -128,7 +128,7 @@ private:
|
||||
const int lh = d.getLineHeight();
|
||||
const bool on = _task->getGPSState();
|
||||
if (f.place(d.lineStep())) {
|
||||
info::row(d, f.at, "GPS", nullptr, rsv);
|
||||
info::valueRow(d, f.at, "GPS", nullptr, false, rsv, 1);
|
||||
info::toggle(d, d.width() - rsv - 2, f.at, on);
|
||||
}
|
||||
LocationProvider* loc = sensors.getLocationProvider();
|
||||
|
||||
@@ -525,15 +525,15 @@ private:
|
||||
}
|
||||
if (f.place(d.lineStep())) {
|
||||
snprintf(a, sizeof(a), "%d", _store->count());
|
||||
info::row(d, f.at, "Points", a, rsv);
|
||||
info::valueRow(d, f.at, "Points", a, false, rsv, 1);
|
||||
const int x0 = 1 + d.getTextWidth("Points") + 6, x1 = right - d.getTextWidth("000") - 6;
|
||||
if (x1 - x0 > 10) info::meter(d, x0, f.at, x1 - x0, lh - 1, (float)_store->count() / TrailStore::CAPACITY);
|
||||
}
|
||||
if (f.place(d.lineStep())) {
|
||||
formatAvgPaceOrSpeed(a, sizeof(a), _task->getNodePrefs());
|
||||
char* c = strstr(a, ": "); // "Avg: 5 km/h" -> label + value
|
||||
if (c) { *c = 0; info::row(d, f.at, a, c + 2, rsv); }
|
||||
else info::row(d, f.at, a, nullptr, rsv);
|
||||
if (c) { *c = 0; info::valueRow(d, f.at, a, c + 2, false, rsv, 1); }
|
||||
else info::valueRow(d, f.at, a, nullptr, false, rsv, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,10 +48,6 @@
|
||||
|
||||
#define LONG_PRESS_MILLIS 1200
|
||||
|
||||
#ifndef UI_RECENT_LIST_SIZE
|
||||
#define UI_RECENT_LIST_SIZE 4
|
||||
#endif
|
||||
|
||||
|
||||
#include "icons.h"
|
||||
#include "../ui-core/Lettering.h" // boot splash wordmark + lettering (shared with the L2)
|
||||
@@ -140,6 +136,11 @@ public:
|
||||
static const int QUICK_MSGS_MAX = 10;
|
||||
|
||||
|
||||
// Telemetry (ui-core/Telemetry.h) in this display's font and width: tight for
|
||||
// the dashboard's short fields, spaced ("49 m") on the Status screen's rows.
|
||||
static const telemetry::Style L1_TELEMETRY = { "\xc2\xb0", false, false, 3 };
|
||||
static const telemetry::Style L1_INFO = { "\xc2\xb0", true, false, 5 };
|
||||
|
||||
// ── Screen fragments — included into THIS translation unit only ───────────────
|
||||
// These headers are not standalone: they are compiled solely as part of
|
||||
// UITask.cpp, in the order below. Two consequences a new screen must respect:
|
||||
@@ -151,14 +152,6 @@ static const int QUICK_MSGS_MAX = 10;
|
||||
// scope (e.g. NearbyScreen::FILTER_LABELS), so including any of them from a
|
||||
// second .cpp is a duplicate-symbol link error. Keep them UITask-internal;
|
||||
// anything genuinely shareable belongs in a real header (icons.h, GeoUtils.h).
|
||||
// Telemetry (ui-core/Telemetry.h) in this display's font and width: tight for
|
||||
// the dashboard's short fields, spaced ("49 m") on the Status screen's rows.
|
||||
static const telemetry::Style L1_TELEMETRY = { "\xc2\xb0", false, false, 3 };
|
||||
static const telemetry::Style L1_INFO = { "\xc2\xb0", true, false, 5 };
|
||||
// Altitude (baro or GPS) in Settings > System > Units, always the small unit.
|
||||
static void fmtAlt(char* buf, int n, float meters, bool imperial) {
|
||||
telemetry::altText(meters, imperial, L1_TELEMETRY, buf, n);
|
||||
}
|
||||
|
||||
#include "FullscreenMsgView.h"
|
||||
#include "../ui-core/MessageText.h"
|
||||
@@ -192,9 +185,6 @@ static void fmtAlt(char* buf, int n, float meters, bool imperial) {
|
||||
|
||||
#include "../ui-core/Battery.h"
|
||||
|
||||
// Voltage -> battery %, from the Core (top bar and dashboard Batt% alike).
|
||||
static int battMvToPercent(int mv, int low_mv) { return battery::percent(mv, low_mv); }
|
||||
|
||||
// The time on a tall portrait panel (e-ink in portrait -- height > width): HH
|
||||
// and MM stacked on two lines in the huge built-in font (size 4, ~56 px tall)
|
||||
// so the digits fill the narrow width. Returns the y just below it.
|
||||
@@ -300,7 +290,6 @@ class HomeScreen : public UIScreen {
|
||||
enum HomePage {
|
||||
CLOCK,
|
||||
FAVOURITES,
|
||||
RECENT,
|
||||
STATUS, // radio, GPS, power, mesh at a glance (took over Radio / GPS / Sensors)
|
||||
BLUETOOTH,
|
||||
ADVERT,
|
||||
@@ -393,6 +382,7 @@ class HomeScreen : public UIScreen {
|
||||
};
|
||||
uint8_t _quick_sel = 0;
|
||||
bool _quick_edit = false; // the selected row is being changed with Left/Right
|
||||
bool _quick_dirty = false; // ...and has moved: saved once when it ends
|
||||
static bool isQuickPage(int p) {
|
||||
return p == SETTINGS || p == QUICK_MSG || p == BLUETOOTH || p == ADVERT || p == TOOLS || p == SHUTDOWN;
|
||||
}
|
||||
@@ -536,7 +526,7 @@ class HomeScreen : public UIScreen {
|
||||
// The charge left, which is what you weigh before switching off.
|
||||
const int mv = _task->getBattMilliVolts();
|
||||
snprintf(rows[n - 1].value, sizeof(rows[0].value), "%d%%%s",
|
||||
battMvToPercent(mv, _node_prefs ? (int)_node_prefs->low_batt_mv : 0),
|
||||
battery::percent(mv, _node_prefs ? (int)_node_prefs->low_batt_mv : 0),
|
||||
board.isExternalPowered() ? " USB" : "");
|
||||
}
|
||||
return n;
|
||||
@@ -637,7 +627,6 @@ class HomeScreen : public UIScreen {
|
||||
int pageBit(int page) const {
|
||||
if (page == CLOCK) return NodePrefs::HPB_CLOCK;
|
||||
if (page == FAVOURITES) return NodePrefs::HPB_FAVOURITES;
|
||||
if (page == RECENT) return NodePrefs::HPB_RECENT;
|
||||
if (page == STATUS) return NodePrefs::HPB_RADIO; // the old Radio slot
|
||||
if (page == BLUETOOTH) return NodePrefs::HPB_BLUETOOTH;
|
||||
if (page == ADVERT) return NodePrefs::HPB_ADVERT;
|
||||
@@ -653,7 +642,6 @@ class HomeScreen : public UIScreen {
|
||||
switch (bit) {
|
||||
case NodePrefs::HPB_CLOCK: return CLOCK;
|
||||
case NodePrefs::HPB_FAVOURITES: return FAVOURITES;
|
||||
case NodePrefs::HPB_RECENT: return RECENT;
|
||||
case NodePrefs::HPB_RADIO: return STATUS;
|
||||
case NodePrefs::HPB_BLUETOOTH: return BLUETOOTH;
|
||||
case NodePrefs::HPB_ADVERT: return ADVERT;
|
||||
@@ -667,7 +655,6 @@ class HomeScreen : public UIScreen {
|
||||
}
|
||||
|
||||
bool isPageVisible(int page) const {
|
||||
if (page == RECENT) return false; // Recent adverts folded into Nearby Nodes; page retired
|
||||
int bit = pageBit(page);
|
||||
if (bit < 0) return true;
|
||||
uint16_t mask = (_node_prefs && _node_prefs->home_pages_mask) ? _node_prefs->home_pages_mask : NodePrefs::HP_ALL;
|
||||
@@ -711,13 +698,11 @@ class HomeScreen : public UIScreen {
|
||||
}
|
||||
|
||||
// reserve_left: how much width from x=0 must stay clear of status icons --
|
||||
// the node name on every other page (name_min below), or the LOCK page's
|
||||
// own clock (see the LOCK branch in render(), which passes its actual
|
||||
// footprint here so the icon row sheds low-priority icons instead of
|
||||
// drawing over the clock). -1 = use the normal name reserve.
|
||||
// the time / node name on the pages (name_min below); the lock page passes
|
||||
// 0, its clock sits under the bar. -1 = use the normal name reserve.
|
||||
int renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts, int reserve_left = -1) {
|
||||
int low_mv = _node_prefs ? (int)_node_prefs->low_batt_mv : 0;
|
||||
int pct = battMvToPercent((int)batteryMilliVolts, low_mv);
|
||||
int pct = battery::percent((int)batteryMilliVolts, low_mv);
|
||||
|
||||
uint8_t mode = battery::mode(_node_prefs ? _node_prefs->batt_display_mode : 0);
|
||||
|
||||
@@ -760,10 +745,9 @@ class HomeScreen : public UIScreen {
|
||||
}
|
||||
|
||||
// Secondary status icons, laid out right→left in PRIORITY order so a crowded
|
||||
// bar sheds its least-important cues instead of crushing the node name. Once
|
||||
// an icon won't fit above the reserved name area, every lower-priority icon
|
||||
// after it is dropped too (the list is ordered high→low). A blinking icon
|
||||
// still reserves its slot while off, so the name width doesn't flicker.
|
||||
// bar sheds its least-important cues instead of crushing the time. Once an
|
||||
// icon won't fit above the reserved area, every lower-priority icon after
|
||||
// it is dropped too (the list is ordered high→low).
|
||||
//
|
||||
// Priority: BT > GPS fix > alarm > mute > auto-advert > trail > live-share >
|
||||
// repeater. Battery (drawn above) is always rightmost. The background modes
|
||||
@@ -1260,7 +1244,7 @@ public:
|
||||
#endif
|
||||
|
||||
const int mv = _task->getBattMilliVolts();
|
||||
const int pct = battMvToPercent(mv, _node_prefs ? (int)_node_prefs->low_batt_mv : 0);
|
||||
const int pct = battery::percent(mv, _node_prefs ? (int)_node_prefs->low_batt_mv : 0);
|
||||
snprintf(h, sizeof(h), "%d%%", pct);
|
||||
snprintf(t, sizeof(t), "%d.%02d V%s", mv / 1000, (mv % 1000) / 10, board.isExternalPowered() ? " USB" : "");
|
||||
tile(0, 1, nullptr, pct / 100.0f, h, t);
|
||||
@@ -1279,7 +1263,6 @@ public:
|
||||
switch (page) {
|
||||
case CLOCK: return &ICON_PG_CLOCK;
|
||||
case FAVOURITES: return &ICON_PG_STAR;
|
||||
case RECENT: return &ICON_PG_RECENT;
|
||||
case STATUS: return &ICON_CHART;
|
||||
case BLUETOOTH: return &ICON_PG_BT;
|
||||
case ADVERT: return &ICON_PG_ADVERT;
|
||||
@@ -1611,16 +1594,24 @@ public:
|
||||
const int d = c == KEY_RIGHT ? 1 : -1;
|
||||
if (act == QA_BRIGHTNESS) {
|
||||
uint8_t& b = _node_prefs->display_brightness;
|
||||
b = (uint8_t)constrain((int)b + d, 0, 4);
|
||||
_task->applyDisplayPrefs();
|
||||
const uint8_t nb = (uint8_t)constrain((int)b + d, 0, 4);
|
||||
if (nb != b) { b = nb; _quick_dirty = true; _task->applyDisplayPrefs(); }
|
||||
} else if (act == QA_AUTO_ADVERT) {
|
||||
const int i = constrain(AutoAdvertScreen::indexOf(_node_prefs->advert_auto_interval_sec) + d,
|
||||
0, AutoAdvertScreen::OPT_COUNT - 1);
|
||||
if (_node_prefs->advert_auto_interval_sec != AutoAdvertScreen::OPTS[i]) {
|
||||
_node_prefs->advert_auto_interval_sec = AutoAdvertScreen::OPTS[i];
|
||||
_quick_dirty = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (c == KEY_ENTER || c == KEY_CANCEL) { _quick_edit = false; the_mesh.savePrefs(); return true; }
|
||||
if (c == KEY_ENTER || c == KEY_CANCEL) {
|
||||
_quick_edit = false;
|
||||
_task->savePrefsIfDirty(_quick_dirty);
|
||||
_quick_dirty = false;
|
||||
return true;
|
||||
}
|
||||
return true; // nothing else while editing
|
||||
}
|
||||
if (isQuickPage(_page)) {
|
||||
|
||||
@@ -418,7 +418,6 @@ public:
|
||||
int findFavouriteChannelSlot(uint8_t ch_idx) const { return favslots::findChannel(_node_prefs, ch_idx); }
|
||||
bool isFavouriteSlotEmpty(int slot) const { return favslots::isEmpty(_node_prefs, slot); }
|
||||
void setFavouriteSlot(int slot, const uint8_t* pub_key) { favslots::setContact(_node_prefs, slot, pub_key); }
|
||||
void setFavouriteChannelSlot(int slot, uint8_t ch_idx) { favslots::setChannel(_node_prefs, slot, ch_idx); }
|
||||
void clearFavouriteSlot(int slot) { favslots::clear(_node_prefs, slot); }
|
||||
bool isButtonPressed() const;
|
||||
|
||||
|
||||
@@ -93,16 +93,6 @@ inline void drawSlotIcon(DisplayDriver& d, int x, int box_w, int box_h, const Mi
|
||||
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) {
|
||||
@@ -275,40 +265,14 @@ MINI_ICON(ICON_GPS_SEARCH, 5, // the reticle broken, no dot: GPS on, still sea
|
||||
packRow("#...#"),
|
||||
packRow(".#.#."));
|
||||
|
||||
// Tools-menu glyphs (auto-reply bot, ringtone editor, diagnostics, system).
|
||||
MINI_ICON(ICON_BOT, 5, // robot head: antenna + eyes + grille (auto-reply bot)
|
||||
packRow("..#.."),
|
||||
packRow("#####"),
|
||||
packRow("#.#.#"),
|
||||
packRow("#####"),
|
||||
packRow("#.#.#"),
|
||||
packRow("#####"));
|
||||
MINI_ICON(ICON_NOTE, 5, // ♪ quaver — ringtone editor
|
||||
packRow("...##"),
|
||||
packRow("...##"),
|
||||
packRow("...#."),
|
||||
packRow("...#."),
|
||||
packRow("...#."),
|
||||
packRow("####."),
|
||||
packRow("####."));
|
||||
MINI_ICON(ICON_CHART, 5, // ascending bars — diagnostics / stats
|
||||
// The Status page's glyph.
|
||||
MINI_ICON(ICON_CHART, 5, // ascending bars — Home › Status
|
||||
packRow("....#"),
|
||||
packRow("..#.#"),
|
||||
packRow("..#.#"),
|
||||
packRow("#.#.#"),
|
||||
packRow("#.#.#"),
|
||||
packRow("#####"));
|
||||
MINI_ICON(ICON_KEY, 5, // padlock — remote admin (privileged/password-gated access)
|
||||
packRow(".###."),
|
||||
packRow("#...#"),
|
||||
packRow("#...#"),
|
||||
packRow("#####"),
|
||||
packRow("##.##"),
|
||||
packRow("#####"));
|
||||
MINI_ICON(ICON_PINS, 5, // 3-pin header — GPIO
|
||||
packRow("#.#.#"),
|
||||
packRow("#.#.#"),
|
||||
packRow("#####"));
|
||||
|
||||
// Home-carousel page glyphs — a uniform 5x5 set, deliberately smaller than the
|
||||
// menu/status icons above, used in place of the page-indicator dots. One per
|
||||
@@ -325,12 +289,6 @@ MINI_ICON(ICON_PG_STAR, 5, // favourites
|
||||
packRow(".###."),
|
||||
packRow("##.##"),
|
||||
packRow("#...#"));
|
||||
MINI_ICON(ICON_PG_RECENT, 5, // stacked lines — recent list
|
||||
packRow("#####"),
|
||||
packRow("....."),
|
||||
packRow("#####"),
|
||||
packRow("....."),
|
||||
packRow("#####"));
|
||||
MINI_ICON(ICON_PG_RADIO, 5, // antenna tower — radio params
|
||||
packRow("..#.."),
|
||||
packRow(".###."),
|
||||
@@ -421,12 +379,6 @@ MINI_ICON(ICON_MAP_NORTH, 5, // "N" with a peaked roof — compass north ma
|
||||
packRow("#.#.#"),
|
||||
packRow("#..##"),
|
||||
packRow("#...#"));
|
||||
MINI_ICON(ICON_MAP_ARROW, 5, // → distance-to-nearest-tracked-contact indicator
|
||||
packRow("..#.."),
|
||||
packRow("...#."),
|
||||
packRow("#####"),
|
||||
packRow("...#."),
|
||||
packRow("..#.."));
|
||||
MINI_ICON(ICON_MAP_TARGET, 5, // ⚑ flag on a pole — the active Locator/Nav target
|
||||
packRow("####."),
|
||||
packRow("#..#."),
|
||||
@@ -469,15 +421,6 @@ MINI_ICON(ICON_SPACE_R, 8,
|
||||
packRow(".......#"),
|
||||
packRow("########"));
|
||||
|
||||
// Scroll-indicator caps — small up/down triangles (authored on the 1× grid).
|
||||
MINI_ICON(ICON_SCROLL_UP, 5, // ▲
|
||||
packRow("..#.."),
|
||||
packRow(".###."),
|
||||
packRow("#####"));
|
||||
MINI_ICON(ICON_SCROLL_DOWN, 5, // ▼
|
||||
packRow("#####"),
|
||||
packRow(".###."),
|
||||
packRow("..#.."));
|
||||
|
||||
// Width of the right-edge column drawScrollIndicator occupies, or 0 when the
|
||||
// list fits and no indicator is drawn. Subtract from a row's content width so
|
||||
|
||||
@@ -33,13 +33,11 @@ class SH1106Display : public DisplayDriver
|
||||
uint8_t _precharge;
|
||||
bool _single_font = true; // OLED is single-font (misc-fixed 6x9); the Lemon/default switch is retired here
|
||||
int _text_sz;
|
||||
// Frame-skip: endFrame() hashes the GFX buffer (FNV-1a, no external dep — the
|
||||
// CRC32 lib is only wired into e-ink builds) and skips the I²C flush when it's
|
||||
// byte-identical to the last one pushed. _force_redraw guarantees the first
|
||||
// frame and the frame after turnOn()/clear() always flush.
|
||||
// Each frame is hashed per 32-column block of each 8-px page (FNV-1a), and
|
||||
// only blocks whose hash changed are sent: a clock tick or a moved selection
|
||||
// is a few blocks, not the whole screen. No frame copy needed.
|
||||
// Frame-skip: endFrame() hashes each 32-column block of each 8-px page
|
||||
// (FNV-1a, no external dep) and sends only the blocks whose hash changed: a
|
||||
// clock tick or a moved selection is a few blocks, not the whole screen, and
|
||||
// an unchanged frame sends nothing. No frame copy needed. _force_redraw
|
||||
// guarantees the first frame and the frame after turnOn()/clear() go out whole.
|
||||
static const uint8_t BLOCK_W = 32;
|
||||
static const uint8_t BLOCKS = (128 / BLOCK_W) * (64 / 8);
|
||||
uint32_t _block_hash[BLOCKS] = {};
|
||||
|
||||
Reference in New Issue
Block a user