mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 23:08:11 +00:00
feat(ui): GPS fix icon on status bar, minimap distance label, hide Tools icons
- Status bar: add a boxed/plain GPS reticle icon reflecting LocationProvider fix state, shown only on boards that have a location provider. Drop the now-redundant "Fix:y/n" text from the map page's info line. - Home minimap: replace the bottom-left scale bar with a "->dist" label to the nearest live-tracked point when one is available, falling back to a smaller single-tick scale indicator otherwise. Less likely to be covered by a plotted point than the old full-width bar, and more useful at a glance. Drop the now-duplicate nearest-distance text from the map page's info line. - Tools screen: comment out per-row/section icons (kept for easy restore) — they don't fit visually in that list for now. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -79,7 +79,7 @@ public:
|
||||
display.setCursor(2, y);
|
||||
display.print(collapsed ? "+" : "-");
|
||||
const int icon_x = 2 + cw + 2;
|
||||
drawIcon(display, icon_x, y, SECTIONS[sec].icon);
|
||||
// drawIcon(display, icon_x, y, SECTIONS[sec].icon); // icons disabled for now, don't fit visually
|
||||
display.setCursor(icon_x + g, y);
|
||||
display.print(SECTIONS[sec].name);
|
||||
},
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
[&](int sec, int item, int y, bool sel, int reserve) {
|
||||
display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel);
|
||||
const int icon_x = 2 + cw + 2; // align item icons under the header icon
|
||||
drawIcon(display, icon_x, y, SECTIONS[sec].tools[item].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);
|
||||
display.print(SECTIONS[sec].tools[item].label);
|
||||
});
|
||||
|
||||
@@ -491,6 +491,17 @@ class HomeScreen : public UIScreen {
|
||||
leftmostX = rX - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// GPS fix status — boxed (lit) when the receiver has a valid fix, plain
|
||||
// glyph while searching. Hidden entirely on boards with no GPS hardware,
|
||||
// so profiles without one don't carry a permanently-empty slot.
|
||||
LocationProvider* loc = _sensors ? _sensors->getLocationProvider() : nullptr;
|
||||
if (loc) {
|
||||
int gX = leftmostX - ind - ind_gap;
|
||||
if (loc->isValid()) drawBoxedIcon(display, gX, ind, ind_h, ICON_GPS);
|
||||
else drawSlotIcon(display, gX, ind, ind_h, ICON_GPS);
|
||||
leftmostX = gX - 1;
|
||||
}
|
||||
return leftmostX;
|
||||
}
|
||||
|
||||
@@ -594,34 +605,52 @@ public:
|
||||
}
|
||||
if (have_gps) { int px, py; project(mla, mlo, px, py); miniIconDrawCentered(display, px, py, ICON_MAP_CURRENT); }
|
||||
|
||||
// Scale bar (bottom-left): a round distance ~1/3 of the width, drawn with
|
||||
// fillRect ticks (gfx line isn't available this early in the TU) + a label,
|
||||
// so the preview conveys rough scale / distance.
|
||||
// Bottom-left info: distance to the nearest live-tracked point, when we
|
||||
// have both a fix and at least one active share — a single concrete
|
||||
// number beats an abstract scale, and as plain text it's far less likely
|
||||
// to land under a plotted dot than the old full-width bar+ticks were.
|
||||
// Falls back to a compact one-line scale tick when there's nothing to
|
||||
// measure against (no fix, or a trail with no live contacts).
|
||||
{
|
||||
static const float M_PER_1E6 = 0.11132f; // metres per 1e-6° lat
|
||||
float ppm = scale / M_PER_1E6; // pixels per metre
|
||||
if (ppm > 0.0f) {
|
||||
bool imp = _task->useImperial();
|
||||
static const float MET_M[] = { 5,10,25,50,100,250,500,1000,2000,5000,10000,25000,50000 };
|
||||
static const char* MET_L[] = { "5m","10m","25m","50m","100m","250m","500m","1km","2km","5km","10km","25km","50km" };
|
||||
static const float IMP_M[] = { 4.572f,15.24f,30.48f,76.2f,152.4f,402.34f,804.67f,1609.34f,4828.0f,16093.4f,80467.2f };
|
||||
static const char* IMP_L[] = { "15ft","50ft","100ft","250ft","500ft","1/4mi","1/2mi","1mi","3mi","10mi","50mi" };
|
||||
const float* M = imp ? IMP_M : MET_M;
|
||||
const char* const* L = imp ? IMP_L : MET_L;
|
||||
int N = imp ? (int)(sizeof(IMP_M) / sizeof(IMP_M[0])) : (int)(sizeof(MET_M) / sizeof(MET_M[0]));
|
||||
float target = (aw / 3.0f) / ppm; // ~1/3 of the width, in metres
|
||||
int sel = 0;
|
||||
for (int i = N - 1; i >= 0; i--) if (M[i] <= target) { sel = i; break; }
|
||||
int barpx = (int)(M[sel] * ppm + 0.5f);
|
||||
if (barpx < 6) barpx = 6;
|
||||
if (barpx > aw - 2) barpx = aw - 2;
|
||||
int bx = ax + 1, by = ay + ah - 1;
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
display.fillRect(bx, by, barpx, 1); // bar
|
||||
display.fillRect(bx, by - 2, 1, 3); // left tick
|
||||
display.fillRect(bx + barpx - 1, by - 2, 1, 3); // right tick
|
||||
display.setCursor(bx, by - 2 - display.getLineHeight());
|
||||
display.print(L[sel]);
|
||||
float nearest_km = -1.0f;
|
||||
if (have_gps) {
|
||||
for (int i = 0; i < LiveTrackStore::CAPACITY; i++) {
|
||||
if (!lt.isActive(i, now)) continue;
|
||||
float d = geo::haversineKm(mla, mlo, lt.slotAt(i).lat_1e6, lt.slotAt(i).lon_1e6);
|
||||
if (nearest_km < 0.0f || d < nearest_km) nearest_km = d;
|
||||
}
|
||||
}
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
int ty = ay + ah - display.getLineHeight();
|
||||
if (nearest_km >= 0.0f) {
|
||||
char dist[12], buf[16];
|
||||
geo::fmtDist(dist, sizeof(dist), nearest_km, _task->useImperial());
|
||||
snprintf(buf, sizeof(buf), "->%s", dist);
|
||||
display.setCursor(ax + 1, ty);
|
||||
display.print(buf);
|
||||
} else {
|
||||
static const float M_PER_1E6 = 0.11132f; // metres per 1e-6° lat
|
||||
float ppm = scale / M_PER_1E6; // pixels per metre
|
||||
if (ppm > 0.0f) {
|
||||
bool imp = _task->useImperial();
|
||||
static const float MET_M[] = { 5,10,25,50,100,250,500,1000,2000,5000,10000,25000,50000 };
|
||||
static const char* MET_L[] = { "5m","10m","25m","50m","100m","250m","500m","1km","2km","5km","10km","25km","50km" };
|
||||
static const float IMP_M[] = { 4.572f,15.24f,30.48f,76.2f,152.4f,402.34f,804.67f,1609.34f,4828.0f,16093.4f,80467.2f };
|
||||
static const char* IMP_L[] = { "15ft","50ft","100ft","250ft","500ft","1/4mi","1/2mi","1mi","3mi","10mi","50mi" };
|
||||
const float* M = imp ? IMP_M : MET_M;
|
||||
const char* const* L = imp ? IMP_L : MET_L;
|
||||
int N = imp ? (int)(sizeof(IMP_M) / sizeof(IMP_M[0])) : (int)(sizeof(MET_M) / sizeof(MET_M[0]));
|
||||
float target = 8.0f / ppm; // short reference tick, not 1/3 of the width
|
||||
int sel = 0;
|
||||
for (int i = N - 1; i >= 0; i--) if (M[i] <= target) { sel = i; break; }
|
||||
int barpx = (int)(M[sel] * ppm + 0.5f);
|
||||
if (barpx < 5) barpx = 5;
|
||||
if (barpx > aw / 4) barpx = aw / 4;
|
||||
int bx = ax + 1, mid = ty + display.getLineHeight() / 2;
|
||||
display.fillRect(bx, mid, barpx, 1); // single tick, on the text baseline
|
||||
display.setCursor(bx + barpx + 2, ty);
|
||||
display.print(L[sel]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1036,28 +1065,12 @@ public:
|
||||
int area_h = info_y - content_y - 2;
|
||||
bool drew = drawMapPreview(display, 2, content_y, display.width() - 4, area_h);
|
||||
char info[40];
|
||||
int32_t la, lo;
|
||||
bool fix = _task->currentLocation(la, lo);
|
||||
uint32_t now_m = rtc_clock.getCurrentTime();
|
||||
LiveTrackStore& lt = _task->liveTrack();
|
||||
int trk = lt.active(now_m);
|
||||
// Distance to the nearest tracked contact, so the page also answers
|
||||
// "how far is the closest shared point".
|
||||
float nearest = -1.0f;
|
||||
if (fix) {
|
||||
for (int i = 0; i < LiveTrackStore::CAPACITY; i++) {
|
||||
if (!lt.isActive(i, now_m)) continue;
|
||||
float d = geo::haversineKm(la, lo, lt.slotAt(i).lat_1e6, lt.slotAt(i).lon_1e6);
|
||||
if (nearest < 0 || d < nearest) nearest = d;
|
||||
}
|
||||
}
|
||||
if (nearest >= 0) {
|
||||
char ds[12];
|
||||
geo::fmtDist(ds, sizeof(ds), nearest, _task->useImperial());
|
||||
snprintf(info, sizeof(info), "Fix:%s Trk:%d %s", fix ? "y" : "n", trk, ds);
|
||||
} else {
|
||||
snprintf(info, sizeof(info), "Fix:%s Track:%d", fix ? "y" : "n", trk);
|
||||
}
|
||||
// Fix state now lives in the top-bar GPS icon and distance-to-nearest
|
||||
// inside the preview itself, so this line just covers track count.
|
||||
snprintf(info, sizeof(info), "Track:%d", trk);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
if (!drew)
|
||||
display.drawTextCentered(display.width() / 2, content_y + area_h / 2, "No GPS / no trail");
|
||||
|
||||
@@ -165,6 +165,13 @@ MINI_ICON(ICON_REPEATER, 6, // » double chevron — relaying/forwarding (repe
|
||||
packRow(".#..#."),
|
||||
packRow("#..#.."));
|
||||
|
||||
MINI_ICON(ICON_GPS, 5, // reticle — GPS fix status (boxed = fix, plain = searching)
|
||||
packRow(".###."),
|
||||
packRow("#...#"),
|
||||
packRow("#.#.#"),
|
||||
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("..#.."),
|
||||
@@ -238,8 +245,8 @@ MINI_ICON(ICON_PG_ADVERT, 5, // mast + radiating waves — advert
|
||||
packRow("..#.."));
|
||||
MINI_ICON(ICON_PG_GPS, 5, // location pin — GPS
|
||||
packRow(".###."),
|
||||
packRow("#...#"),
|
||||
packRow("#...#"),
|
||||
packRow("#.#.#"),
|
||||
packRow("#.#.#"),
|
||||
packRow(".#.#."),
|
||||
packRow("..#.."));
|
||||
MINI_ICON(ICON_PG_SENSORS, 5, // thermometer/gauge — sensors
|
||||
|
||||
Reference in New Issue
Block a user