From ee2ed0a8fb8518e4f519ef60bd80e4906b89b7a9 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Fri, 17 Oct 2025 23:26:47 -0400 Subject: [PATCH 1/7] Fixe battery voltage to show missing decimals --- src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp index 7876276a8..09f76ed46 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp @@ -709,7 +709,7 @@ void InkHUD::MenuApplet::drawSystemInfoPanel(int16_t left, int16_t top, uint16_t // Voltage float voltage = powerStatus->getBatteryVoltageMv() / 1000.0; char voltageStr[6]; // "XX.XV" - sprintf(voltageStr, "%.1fV", voltage); + sprintf(voltageStr, "%.2fV", voltage); printAt(colC[0], labelT, "Bat", CENTER, TOP); printAt(colC[0], valT, voltageStr, CENTER, TOP); From 2357ea004264fe9f433639ed1df8d197ae921e86 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sun, 19 Oct 2025 02:48:55 -0400 Subject: [PATCH 2/7] Clearer hop markers for inkHUD map --- .../InkHUD/Applets/Bases/Map/MapApplet.cpp | 357 ++++++++++++------ 1 file changed, 232 insertions(+), 125 deletions(-) diff --git a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp index db0805f4e..0639501ea 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp @@ -14,44 +14,128 @@ void InkHUD::MapApplet::onRender() } // Find center of map - // - latitude and longitude - // - will be placed at X(0.5), Y(0.5) getMapCenter(&latCenter, &lngCenter); - - // Calculate North+East distance of each node to map center - // - which nodes to use controlled by virtual shouldDrawNode method calculateAllMarkers(); - - // Set the region shown on the map - // - default: fit all nodes, plus padding - // - maybe overriden by derived applet - // - getMapSize *sets* passed parameters (C-style) getMapSize(&widthMeters, &heightMeters); - - // Set the metersToPx conversion value calculateMapScale(); - // Special marker for own node - meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); - if (ourNode && nodeDB->hasValidPosition(ourNode)) - drawLabeledMarker(ourNode); - - // Draw all markers + // Draw all markers first for (Marker m : markers) { int16_t x = X(0.5) + (m.eastMeters * metersToPx); int16_t y = Y(0.5) - (m.northMeters * metersToPx); - // Cross Size - constexpr uint16_t csMin = 5; - constexpr uint16_t csMax = 12; + // --- Add white halo outline first --- + constexpr int outlinePad = 2; // size of white outline padding + int boxSize = (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) || !m.hasHopsAway ? 12 : 10; + fillRect(x - (boxSize / 2) - outlinePad, y - (boxSize / 2) - outlinePad, + boxSize + (outlinePad * 2), boxSize + (outlinePad * 2), WHITE); - // Too many hops away - if (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) // Too many mops - printAt(x, y, "!", CENTER, MIDDLE); - else if (!m.hasHopsAway) // Unknown hops - drawCross(x, y, csMin); - else // The fewer hops, the larger the cross - drawCross(x, y, map(m.hopsAway, 0, config.lora.hop_limit, csMax, csMin)); + // --- Draw actual marker on top --- + if (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) { + fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); + setFont(fontSmall); setTextColor(WHITE); + printAt(x, y, "X", CENTER, MIDDLE); + } + else if (!m.hasHopsAway) { + fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); + setFont(fontSmall); setTextColor(WHITE); + printAt(x, y, "?", CENTER, MIDDLE); + } + else { + fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); + char hopStr[4]; snprintf(hopStr, sizeof(hopStr), "%d", m.hopsAway); + setFont(fontSmall); setTextColor(WHITE); + printAt(x, y, hopStr, CENTER, MIDDLE); + } + + // Restore default font and color (safety for rest of UI) + setFont(fontSmall); setTextColor(BLACK); + } + + // Dual map scale bars + int16_t horizPx = width() * 0.25f; + int16_t vertPx = height() * 0.25f; + float horizMeters = horizPx / metersToPx; + float vertMeters = vertPx / metersToPx; + + auto formatDistance = [&](float meters, char *out, size_t len) { + if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { + float feet = meters * 3.28084f; + if (feet < 528) snprintf(out, len, "%.0f ft", feet); + else { + float miles = feet / 5280.0f; + snprintf(out, len, miles < 10 ? "%.1f mi" : "%.0f mi", miles); + } + } else { + if (meters >= 1000) snprintf(out, len, "%.1f km", meters / 1000.0f); + else snprintf(out, len, "%.0f m", meters); + } + }; + + // === Horizontal scale bar === + int16_t horizBarY = height() - 2; + int16_t horizBarX = 1; + drawLine(horizBarX, horizBarY, horizBarX + horizPx, horizBarY, BLACK); + drawLine(horizBarX, horizBarY - 3, horizBarX, horizBarY + 3, BLACK); + drawLine(horizBarX + horizPx, horizBarY - 3, horizBarX + horizPx, horizBarY + 3, BLACK); + + char horizLabel[32]; + formatDistance(horizMeters, horizLabel, sizeof(horizLabel)); + int16_t horizLabelW = getTextWidth(horizLabel); + int16_t horizLabelH = getFont().lineHeight(); + int16_t horizLabelX = horizBarX + horizPx + 4; + int16_t horizLabelY = horizBarY - horizLabelH + 1; + fillRect(horizLabelX - 2, horizLabelY - 1, horizLabelW + 4, horizLabelH + 2, WHITE); + printAt(horizLabelX, horizBarY, horizLabel, LEFT, BOTTOM); + + // === Vertical scale bar === + int16_t vertBarX = 1; + int16_t vertBarBottom = horizBarY; + int16_t vertBarTop = vertBarBottom - vertPx; + drawLine(vertBarX, vertBarBottom, vertBarX, vertBarTop, BLACK); + drawLine(vertBarX - 3, vertBarBottom, vertBarX + 3, vertBarBottom, BLACK); + drawLine(vertBarX - 3, vertBarTop, vertBarX + 3, vertBarTop, BLACK); + + char vertTopLabel[32]; + formatDistance(vertMeters, vertTopLabel, sizeof(vertTopLabel)); + int16_t topLabelY = vertBarTop - getFont().lineHeight() - 2; + int16_t topLabelW = getTextWidth(vertTopLabel); + int16_t topLabelH = getFont().lineHeight(); + fillRect(vertBarX - 2, topLabelY - 1, topLabelW + 6, topLabelH + 2, WHITE); + printAt(vertBarX + (topLabelW / 2) + 1, topLabelY + (topLabelH / 2), vertTopLabel, CENTER, MIDDLE); + + char vertBottomLabel[32]; + formatDistance(horizMeters, vertBottomLabel, sizeof(vertBottomLabel)); + int16_t bottomLabelY = vertBarBottom + 4; + int16_t bottomLabelW = getTextWidth(vertBottomLabel); + int16_t bottomLabelH = getFont().lineHeight(); + fillRect(vertBarX - 2, bottomLabelY - 1, bottomLabelW + 6, bottomLabelH + 2, WHITE); + printAt(vertBarX + (bottomLabelW / 2) + 1, bottomLabelY + (bottomLabelH / 2), vertBottomLabel, CENTER, MIDDLE); + + // --- Draw our node LAST with full white fill + outline --- + meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); + if (ourNode && nodeDB->hasValidPosition(ourNode)) { + Marker self = calculateMarker( + ourNode->position.latitude_i * 1e-7, + ourNode->position.longitude_i * 1e-7, + false, + 0 + ); + + int16_t centerX = X(0.5) + (self.eastMeters * metersToPx); + int16_t centerY = Y(0.5) - (self.northMeters * metersToPx); + + // --- White fill background + halo --- + fillCircle(centerX, centerY, 8, WHITE); // big white base + drawCircle(centerX, centerY, 8, WHITE); // crisp edge + + // --- Black bullseye on top --- + drawCircle(centerX, centerY, 6, BLACK); + fillCircle(centerX, centerY, 2, BLACK); + + // --- Crosshairs --- + drawLine(centerX - 8, centerY, centerX + 8, centerY, BLACK); + drawLine(centerX, centerY - 8, centerX, centerY + 8, BLACK); } } @@ -63,110 +147,122 @@ void InkHUD::MapApplet::onRender() void InkHUD::MapApplet::getMapCenter(float *lat, float *lng) { - // Find mean lat long coords - // ============================ - // - assigning X, Y and Z values to position on Earth's surface in 3D space, relative to center of planet - // - averages the x, y and z coords - // - uses tan to find angles for lat / long degrees - // - longitude: triangle formed by x and y (on plane of the equator) - // - latitude: triangle formed by z (north south), - // and the line along plane of equator which stretches from earth's axis to where point xyz intersects planet's surface + // If we have a valid position for our own node, use that as the anchor + meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); + if (ourNode && nodeDB->hasValidPosition(ourNode)) { + *lat = ourNode->position.latitude_i * 1e-7; + *lng = ourNode->position.longitude_i * 1e-7; + } else { + // Find mean lat long coords + // ============================ + // - assigning X, Y and Z values to position on Earth's surface in 3D space, relative to center of planet + // - averages the x, y and z coords + // - uses tan to find angles for lat / long degrees + // - longitude: triangle formed by x and y (on plane of the equator) + // - latitude: triangle formed by z (north south), + // and the line along plane of equator which stretches from earth's axis to where point xyz intersects planet's surface - // Working totals, averaged after nodeDB processed - uint32_t positionCount = 0; - float xAvg = 0; - float yAvg = 0; - float zAvg = 0; + // Working totals, averaged after nodeDB processed + uint32_t positionCount = 0; + float xAvg = 0; + float yAvg = 0; + float zAvg = 0; - // For each node in db - for (uint32_t i = 0; i < nodeDB->getNumMeshNodes(); i++) { - meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i); + // For each node in db + for (uint32_t i = 0; i < nodeDB->getNumMeshNodes(); i++) { + meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i); - // Skip if no position - if (!nodeDB->hasValidPosition(node)) - continue; + // Skip if no position + if (!nodeDB->hasValidPosition(node)) + continue; - // Skip if derived applet doesn't want to show this node on the map - if (!shouldDrawNode(node)) - continue; + // Skip if derived applet doesn't want to show this node on the map + if (!shouldDrawNode(node)) + continue; - // Latitude and Longitude of node, in radians - float latRad = node->position.latitude_i * (1e-7) * DEG_TO_RAD; - float lngRad = node->position.longitude_i * (1e-7) * DEG_TO_RAD; + // Latitude and Longitude of node, in radians + float latRad = node->position.latitude_i * (1e-7) * DEG_TO_RAD; + float lngRad = node->position.longitude_i * (1e-7) * DEG_TO_RAD; - // Convert to cartesian points, with center of earth at 0, 0, 0 - // Exact distance from center is irrelevant, as we're only interested in the vector - float x = cos(latRad) * cos(lngRad); - float y = cos(latRad) * sin(lngRad); - float z = sin(latRad); + // Convert to cartesian points, with center of earth at 0, 0, 0 + // Exact distance from center is irrelevant, as we're only interested in the vector + float x = cos(latRad) * cos(lngRad); + float y = cos(latRad) * sin(lngRad); + float z = sin(latRad); - // To find mean values shortly - xAvg += x; - yAvg += y; - zAvg += z; - positionCount++; + // To find mean values shortly + xAvg += x; + yAvg += y; + zAvg += z; + positionCount++; + } + + // All NodeDB processed, find mean values + xAvg /= positionCount; + yAvg /= positionCount; + zAvg /= positionCount; + + // Longitude from cartesian coords + // (Angle from 3D coords describing a point of globe's surface) + /* + UK + /-------\ + (Top View) /- -\ + /- (You) -\ + /- . -\ + /- . X -\ + Asia - ... - USA + \- Y -/ + \- -/ + \- -/ + \- -/ + \- -----/ + Pacific + + */ + + *lng = atan2(yAvg, xAvg) * RAD_TO_DEG; + + // Latitude from cartesian coords + // (Angle from 3D coords describing a point on the globe's surface) + // As latitude increases, distance from the Earth's north-south axis out to our surface point decreases. + // Means we need to first find the hypotenuse which becomes base of our triangle in the second step + /* + UK North + /-------\ (Front View) /-------\ + (Top View) /- -\ /- -\ + /- (You) -\ /-(You) -\ + /- /. -\ /- . -\ + /- √X²+Y²/ . X -\ /- Z . -\ + Asia - /... - USA - ..... - + \- Y -/ \- √X²+Y² -/ + \- -/ \- -/ + \- -/ \- -/ + \- -/ \- -/ + \- -----/ \- -----/ + Pacific South + */ + + float hypotenuse = sqrt((xAvg * xAvg) + (yAvg * yAvg)); // Distance from globe's north-south axis to surface intersect + *lat = atan2(zAvg, hypotenuse) * RAD_TO_DEG; } - // All NodeDB processed, find mean values - xAvg /= positionCount; - yAvg /= positionCount; - zAvg /= positionCount; - - // Longitude from cartesian coords - // (Angle from 3D coords describing a point of globe's surface) - /* - UK - /-------\ - (Top View) /- -\ - /- (You) -\ - /- . -\ - /- . X -\ - Asia - ... - USA - \- Y -/ - \- -/ - \- -/ - \- -/ - \- -----/ - Pacific - - */ - - *lng = atan2(yAvg, xAvg) * RAD_TO_DEG; - - // Latitude from cartesian coords - // (Angle from 3D coords describing a point on the globe's surface) - // As latitude increases, distance from the Earth's north-south axis out to our surface point decreases. - // Means we need to first find the hypotenuse which becomes base of our triangle in the second step - /* - UK North - /-------\ (Front View) /-------\ - (Top View) /- -\ /- -\ - /- (You) -\ /-(You) -\ - /- /. -\ /- . -\ - /- √X²+Y²/ . X -\ /- Z . -\ - Asia - /... - USA - ..... - - \- Y -/ \- √X²+Y² -/ - \- -/ \- -/ - \- -/ \- -/ - \- -/ \- -/ - \- -----/ \- -----/ - Pacific South - */ - - float hypotenuse = sqrt((xAvg * xAvg) + (yAvg * yAvg)); // Distance from globe's north-south axis to surface intersect - *lat = atan2(zAvg, hypotenuse) * RAD_TO_DEG; + // Use either our node position, or the mean fallback as the center + latCenter = *lat; + lngCenter = *lng; // ---------------------------------------------- - // This has given us the "mean position" - // This will be a position *somewhere* near the center of our nodes. - // What we actually want is to place our center so that our outermost nodes end up on the border of our map. - // The only real use of our "mean position" is to give us a reference frame: - // which direction is east, and which is west. + // This has given us either: + // - our actual position (preferred), or + // - a mean position (fallback if we had no fix) + // + // What we actually want is to place our center so that our outermost nodes + // end up on the border of our map. The only real use of our "center" is to give + // us a reference frame: which direction is east, and which is west. //------------------------------------------------ - // Find furthest nodes from "mean lat long" + // Find furthest nodes from our center // ======================================== - float northernmost = latCenter; float southernmost = latCenter; float easternmost = lngCenter; @@ -184,14 +280,14 @@ void InkHUD::MapApplet::getMapCenter(float *lat, float *lng) continue; // Check for a new top or bottom latitude - float lat = node->position.latitude_i * 1e-7; - northernmost = max(northernmost, lat); - southernmost = min(southernmost, lat); + float latNode = node->position.latitude_i * 1e-7; + northernmost = max(northernmost, latNode); + southernmost = min(southernmost, latNode); // Longitude is trickier - float lng = node->position.longitude_i * 1e-7; - float degEastward = fmod(((lng - lngCenter) + 360), 360); // Degrees traveled east from lngCenter to reach node - float degWestward = abs(fmod(((lng - lngCenter) - 360), 360)); // Degrees traveled west from lngCenter to reach node + float lngNode = node->position.longitude_i * 1e-7; + float degEastward = fmod(((lngNode - lngCenter) + 360), 360); // Degrees traveled east from lngCenter to reach node + float degWestward = abs(fmod(((lngNode - lngCenter) - 360), 360)); // Degrees traveled west from lngCenter to reach node if (degEastward < degWestward) easternmost = max(easternmost, lngCenter + degEastward); else @@ -250,7 +346,6 @@ InkHUD::MapApplet::Marker InkHUD::MapApplet::calculateMarker(float lat, float ln m.hopsAway = hopsAway; return m; } - // Draw a marker on the map for a node, with a shortname label, and backing box void InkHUD::MapApplet::drawLabeledMarker(meshtastic_NodeInfoLite *node) { @@ -324,6 +419,18 @@ void InkHUD::MapApplet::drawLabeledMarker(meshtastic_NodeInfoLite *node) textX = labelX + paddingW; } + // Prevent overlap with scale bars and their labels + // Define a "safe zone" in the bottom-left where the scale bars and text are drawn + constexpr int16_t safeZoneHeight = 28; // adjust based on your label font height + constexpr int16_t safeZoneWidth = 60; // adjust based on horizontal label width zone + bool overlapsScale = (labelY + labelH > height() - safeZoneHeight) && (labelX < safeZoneWidth); + + // If it overlaps, shift label upward slightly above the safe zone + if (overlapsScale) { + labelY = height() - safeZoneHeight - labelH - 2; + textY = labelY + (labelH / 2); + } + // Backing box fillRect(labelX, labelY, labelW, labelH, WHITE); drawRect(labelX, labelY, labelW, labelH, BLACK); From 68e739359f0b9387025b59f40b289ebdfb2e1622 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sun, 19 Oct 2025 03:36:25 -0400 Subject: [PATCH 3/7] cleanup --- .../InkHUD/Applets/Bases/Map/MapApplet.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp index 0639501ea..89e6f35f1 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp @@ -24,13 +24,13 @@ void InkHUD::MapApplet::onRender() int16_t x = X(0.5) + (m.eastMeters * metersToPx); int16_t y = Y(0.5) - (m.northMeters * metersToPx); - // --- Add white halo outline first --- - constexpr int outlinePad = 2; // size of white outline padding + // Add white halo outline first + constexpr int outlinePad = 1; // size of white outline padding int boxSize = (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) || !m.hasHopsAway ? 12 : 10; fillRect(x - (boxSize / 2) - outlinePad, y - (boxSize / 2) - outlinePad, boxSize + (outlinePad * 2), boxSize + (outlinePad * 2), WHITE); - // --- Draw actual marker on top --- + // Draw actual marker on top if (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) { fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); setFont(fontSmall); setTextColor(WHITE); @@ -72,7 +72,7 @@ void InkHUD::MapApplet::onRender() } }; - // === Horizontal scale bar === + // Horizontal scale bar int16_t horizBarY = height() - 2; int16_t horizBarX = 1; drawLine(horizBarX, horizBarY, horizBarX + horizPx, horizBarY, BLACK); @@ -88,7 +88,7 @@ void InkHUD::MapApplet::onRender() fillRect(horizLabelX - 2, horizLabelY - 1, horizLabelW + 4, horizLabelH + 2, WHITE); printAt(horizLabelX, horizBarY, horizLabel, LEFT, BOTTOM); - // === Vertical scale bar === + // Vertical scale bar int16_t vertBarX = 1; int16_t vertBarBottom = horizBarY; int16_t vertBarTop = vertBarBottom - vertPx; @@ -112,7 +112,7 @@ void InkHUD::MapApplet::onRender() fillRect(vertBarX - 2, bottomLabelY - 1, bottomLabelW + 6, bottomLabelH + 2, WHITE); printAt(vertBarX + (bottomLabelW / 2) + 1, bottomLabelY + (bottomLabelH / 2), vertBottomLabel, CENTER, MIDDLE); - // --- Draw our node LAST with full white fill + outline --- + // Draw our node LAST with full white fill + outline meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); if (ourNode && nodeDB->hasValidPosition(ourNode)) { Marker self = calculateMarker( @@ -125,15 +125,15 @@ void InkHUD::MapApplet::onRender() int16_t centerX = X(0.5) + (self.eastMeters * metersToPx); int16_t centerY = Y(0.5) - (self.northMeters * metersToPx); - // --- White fill background + halo --- + // White fill background + halo fillCircle(centerX, centerY, 8, WHITE); // big white base drawCircle(centerX, centerY, 8, WHITE); // crisp edge - // --- Black bullseye on top --- + // Black bullseye on top drawCircle(centerX, centerY, 6, BLACK); fillCircle(centerX, centerY, 2, BLACK); - // --- Crosshairs --- + // Crosshairs drawLine(centerX - 8, centerY, centerX + 8, centerY, BLACK); drawLine(centerX, centerY - 8, centerX, centerY + 8, BLACK); } From 7afc6ef8331d253b78cb597e1ff255ac56db5456 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sun, 19 Oct 2025 03:47:02 -0400 Subject: [PATCH 4/7] trunk --- .../InkHUD/Applets/Bases/Map/MapApplet.cpp | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp index 89e6f35f1..aee51c6ad 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp @@ -27,48 +27,54 @@ void InkHUD::MapApplet::onRender() // Add white halo outline first constexpr int outlinePad = 1; // size of white outline padding int boxSize = (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) || !m.hasHopsAway ? 12 : 10; - fillRect(x - (boxSize / 2) - outlinePad, y - (boxSize / 2) - outlinePad, - boxSize + (outlinePad * 2), boxSize + (outlinePad * 2), WHITE); + fillRect(x - (boxSize / 2) - outlinePad, y - (boxSize / 2) - outlinePad, boxSize + (outlinePad * 2), + boxSize + (outlinePad * 2), WHITE); // Draw actual marker on top if (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) { fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); - setFont(fontSmall); setTextColor(WHITE); + setFont(fontSmall); + setTextColor(WHITE); printAt(x, y, "X", CENTER, MIDDLE); - } - else if (!m.hasHopsAway) { + } else if (!m.hasHopsAway) { fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); - setFont(fontSmall); setTextColor(WHITE); + setFont(fontSmall); + setTextColor(WHITE); printAt(x, y, "?", CENTER, MIDDLE); - } - else { + } else { fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); - char hopStr[4]; snprintf(hopStr, sizeof(hopStr), "%d", m.hopsAway); - setFont(fontSmall); setTextColor(WHITE); + char hopStr[4]; + snprintf(hopStr, sizeof(hopStr), "%d", m.hopsAway); + setFont(fontSmall); + setTextColor(WHITE); printAt(x, y, hopStr, CENTER, MIDDLE); } // Restore default font and color (safety for rest of UI) - setFont(fontSmall); setTextColor(BLACK); + setFont(fontSmall); + setTextColor(BLACK); } // Dual map scale bars int16_t horizPx = width() * 0.25f; - int16_t vertPx = height() * 0.25f; + int16_t vertPx = height() * 0.25f; float horizMeters = horizPx / metersToPx; - float vertMeters = vertPx / metersToPx; + float vertMeters = vertPx / metersToPx; auto formatDistance = [&](float meters, char *out, size_t len) { if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { float feet = meters * 3.28084f; - if (feet < 528) snprintf(out, len, "%.0f ft", feet); + if (feet < 528) + snprintf(out, len, "%.0f ft", feet); else { float miles = feet / 5280.0f; snprintf(out, len, miles < 10 ? "%.1f mi" : "%.0f mi", miles); } } else { - if (meters >= 1000) snprintf(out, len, "%.1f km", meters / 1000.0f); - else snprintf(out, len, "%.0f m", meters); + if (meters >= 1000) + snprintf(out, len, "%.1f km", meters / 1000.0f); + else + snprintf(out, len, "%.0f m", meters); } }; @@ -115,12 +121,7 @@ void InkHUD::MapApplet::onRender() // Draw our node LAST with full white fill + outline meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); if (ourNode && nodeDB->hasValidPosition(ourNode)) { - Marker self = calculateMarker( - ourNode->position.latitude_i * 1e-7, - ourNode->position.longitude_i * 1e-7, - false, - 0 - ); + Marker self = calculateMarker(ourNode->position.latitude_i * 1e-7, ourNode->position.longitude_i * 1e-7, false, 0); int16_t centerX = X(0.5) + (self.eastMeters * metersToPx); int16_t centerY = Y(0.5) - (self.northMeters * metersToPx); @@ -160,7 +161,8 @@ void InkHUD::MapApplet::getMapCenter(float *lat, float *lng) // - uses tan to find angles for lat / long degrees // - longitude: triangle formed by x and y (on plane of the equator) // - latitude: triangle formed by z (north south), - // and the line along plane of equator which stretches from earth's axis to where point xyz intersects planet's surface + // and the line along plane of equator which stretches from earth's axis to where point xyz intersects planet's + // surface // Working totals, averaged after nodeDB processed uint32_t positionCount = 0; @@ -422,13 +424,13 @@ void InkHUD::MapApplet::drawLabeledMarker(meshtastic_NodeInfoLite *node) // Prevent overlap with scale bars and their labels // Define a "safe zone" in the bottom-left where the scale bars and text are drawn constexpr int16_t safeZoneHeight = 28; // adjust based on your label font height - constexpr int16_t safeZoneWidth = 60; // adjust based on horizontal label width zone + constexpr int16_t safeZoneWidth = 60; // adjust based on horizontal label width zone bool overlapsScale = (labelY + labelH > height() - safeZoneHeight) && (labelX < safeZoneWidth); // If it overlaps, shift label upward slightly above the safe zone if (overlapsScale) { labelY = height() - safeZoneHeight - labelH - 2; - textY = labelY + (labelH / 2); + textY = labelY + (labelH / 2); } // Backing box From 5b9563a357f5d6c535b866be1987619869ee786e Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sun, 19 Oct 2025 15:11:06 -0400 Subject: [PATCH 5/7] Update src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp makes sense, applying did not cause any visible issues. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp index aee51c6ad..0baca4f87 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp @@ -111,7 +111,7 @@ void InkHUD::MapApplet::onRender() printAt(vertBarX + (topLabelW / 2) + 1, topLabelY + (topLabelH / 2), vertTopLabel, CENTER, MIDDLE); char vertBottomLabel[32]; - formatDistance(horizMeters, vertBottomLabel, sizeof(vertBottomLabel)); + formatDistance(vertMeters, vertBottomLabel, sizeof(vertBottomLabel)); int16_t bottomLabelY = vertBarBottom + 4; int16_t bottomLabelW = getTextWidth(vertBottomLabel); int16_t bottomLabelH = getFont().lineHeight(); From 2ad52812c0e182ea4d9389cafa8125c8467da4af Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sun, 19 Oct 2025 15:12:03 -0400 Subject: [PATCH 6/7] Update src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp better for clarity Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp index 0baca4f87..396a8dfe7 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp @@ -26,7 +26,12 @@ void InkHUD::MapApplet::onRender() // Add white halo outline first constexpr int outlinePad = 1; // size of white outline padding - int boxSize = (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) || !m.hasHopsAway ? 12 : 10; + int boxSize; + if ((m.hasHopsAway && m.hopsAway > config.lora.hop_limit) || !m.hasHopsAway) { + boxSize = 12; + } else { + boxSize = 10; + } fillRect(x - (boxSize / 2) - outlinePad, y - (boxSize / 2) - outlinePad, boxSize + (outlinePad * 2), boxSize + (outlinePad * 2), WHITE); From cb3ce1b1a869daef5cc773ea2a5bd09b8d201b1f Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sun, 19 Oct 2025 16:25:53 -0400 Subject: [PATCH 7/7] proper centering and rounder hops labels --- .../InkHUD/Applets/Bases/Map/MapApplet.cpp | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp index 396a8dfe7..818c68070 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp @@ -13,6 +13,23 @@ void InkHUD::MapApplet::onRender() return; } + // Helper: draw rounded rectangle centered at x,y + auto fillRoundedRect = [&](int16_t cx, int16_t cy, int16_t w, int16_t h, int16_t r, uint16_t color) { + int16_t x = cx - (w / 2); + int16_t y = cy - (h / 2); + + // center rects + fillRect(x + r, y, w - 2 * r, h, color); + fillRect(x, y + r, r, h - 2 * r, color); + fillRect(x + w - r, y + r, r, h - 2 * r, color); + + // corners + fillCircle(x + r, y + r, r, color); + fillCircle(x + w - r - 1, y + r, r, color); + fillCircle(x + r, y + h - r - 1, r, color); + fillCircle(x + w - r - 1, y + h - r - 1, r, color); + }; + // Find center of map getMapCenter(&latCenter, &lngCenter); calculateAllMarkers(); @@ -25,37 +42,32 @@ void InkHUD::MapApplet::onRender() int16_t y = Y(0.5) - (m.northMeters * metersToPx); // Add white halo outline first - constexpr int outlinePad = 1; // size of white outline padding - int boxSize; - if ((m.hasHopsAway && m.hopsAway > config.lora.hop_limit) || !m.hasHopsAway) { - boxSize = 12; - } else { - boxSize = 10; - } - fillRect(x - (boxSize / 2) - outlinePad, y - (boxSize / 2) - outlinePad, boxSize + (outlinePad * 2), - boxSize + (outlinePad * 2), WHITE); + constexpr int outlinePad = 1; + int boxSize = 11; + int radius = 2; // rounded corner radius + + // White halo background + fillRoundedRect(x, y, boxSize + (outlinePad * 2), boxSize + (outlinePad * 2), radius + 1, WHITE); + + // Draw inner box + fillRoundedRect(x, y, boxSize, boxSize, radius, BLACK); + + // Text inside + setFont(fontSmall); + setTextColor(WHITE); // Draw actual marker on top if (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) { - fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); - setFont(fontSmall); - setTextColor(WHITE); - printAt(x, y, "X", CENTER, MIDDLE); + printAt(x + 1, y + 1, "X", CENTER, MIDDLE); } else if (!m.hasHopsAway) { - fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); - setFont(fontSmall); - setTextColor(WHITE); - printAt(x, y, "?", CENTER, MIDDLE); + printAt(x + 1, y + 1, "?", CENTER, MIDDLE); } else { - fillRect(x - boxSize / 2, y - boxSize / 2, boxSize, boxSize, BLACK); char hopStr[4]; snprintf(hopStr, sizeof(hopStr), "%d", m.hopsAway); - setFont(fontSmall); - setTextColor(WHITE); - printAt(x, y, hopStr, CENTER, MIDDLE); + printAt(x, y + 1, hopStr, CENTER, MIDDLE); } - // Restore default font and color (safety for rest of UI) + // Restore default font and color setFont(fontSmall); setTextColor(BLACK); }