diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index dab3040f0..73381a92b 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -588,11 +588,11 @@ void menuHandler::favoriteBaseMenu() void menuHandler::positionBaseMenu() { - enum optionsNumbers { Back, GPSToggle, CompassMenu, CompassCalibrate, enumEnd }; + enum optionsNumbers { Back, GPSToggle, GPSFormat, CompassMenu, CompassCalibrate, enumEnd }; - static const char *optionsArray[enumEnd] = {"Back", "GPS Toggle", "Compass"}; - static int optionsEnumArray[enumEnd] = {Back, GPSToggle, CompassMenu}; - int options = 3; + static const char *optionsArray[enumEnd] = {"Back", "GPS Toggle", "GPS Format", "Compass"}; + static int optionsEnumArray[enumEnd] = {Back, GPSToggle, GPSFormat, CompassMenu}; + int options = 4; if (accelerometerThread) { optionsArray[options] = "Compass Calibrate"; @@ -608,6 +608,9 @@ void menuHandler::positionBaseMenu() if (selected == GPSToggle) { menuQueue = gps_toggle_menu; screen->runNow(); + } else if (selected == GPSFormat) { + menuQueue = gps_format_menu; + screen->runNow(); } else if (selected == CompassMenu) { menuQueue = compass_point_north_menu; screen->runNow(); @@ -726,6 +729,47 @@ void menuHandler::GPSToggleMenu() bannerOptions.InitialSelected = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED ? 1 : 2; screen->showOverlayBanner(bannerOptions); } +void menuHandler::GPSFormatMenu() +{ + + static const char *optionsArray[] = {"Back", + isHighResolution ? "Decimal Degrees" : "DEC", + isHighResolution ? "Degrees Minutes Seconds" : "DMS", + isHighResolution ? "Universal Transverse Mercator" : "UTM", + isHighResolution ? "Military Grid Reference System" : "MGRS", + isHighResolution ? "Open Location Code" : "OLC", + isHighResolution ? "Ordnance Survey Grid Ref" : "OSGR"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "GPS Format"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 7; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + config.display.gps_format = meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DEC; + service->reloadConfig(SEGMENT_CONFIG); + } else if (selected == 2) { + config.display.gps_format = meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS; + service->reloadConfig(SEGMENT_CONFIG); + } else if (selected == 3) { + config.display.gps_format = meshtastic_Config_DisplayConfig_GpsCoordinateFormat_UTM; + service->reloadConfig(SEGMENT_CONFIG); + } else if (selected == 4) { + config.display.gps_format = meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MGRS; + service->reloadConfig(SEGMENT_CONFIG); + } else if (selected == 5) { + config.display.gps_format = meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OLC; + service->reloadConfig(SEGMENT_CONFIG); + } else if (selected == 6) { + config.display.gps_format = meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR; + service->reloadConfig(SEGMENT_CONFIG); + } else { + menuQueue = position_base_menu; + screen->runNow(); + } + }; + bannerOptions.InitialSelected = config.display.gps_format + 1; + screen->showOverlayBanner(bannerOptions); +} #endif void menuHandler::BluetoothToggleMenu() @@ -1378,6 +1422,9 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display) case gps_toggle_menu: GPSToggleMenu(); break; + case gps_format_menu: + GPSFormatMenu(); + break; #endif case compass_point_north_menu: compassNorthMenu(); diff --git a/src/graphics/draw/MenuHandler.h b/src/graphics/draw/MenuHandler.h index 2be8e58a6..e8a2904a0 100644 --- a/src/graphics/draw/MenuHandler.h +++ b/src/graphics/draw/MenuHandler.h @@ -19,6 +19,7 @@ class menuHandler clock_menu, position_base_menu, gps_toggle_menu, + gps_format_menu, compass_point_north_menu, reset_node_db_menu, buzzermodemenupicker, @@ -63,6 +64,7 @@ class menuHandler static void positionBaseMenu(); static void compassNorthMenu(); static void GPSToggleMenu(); + static void GPSFormatMenu(); static void BuzzerModeMenu(); static void switchToMUIMenu(); static void TFTColorPickerMenu(OLEDDisplay *display); diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp index e9da66712..2a7f3aeee 100644 --- a/src/graphics/draw/UIRenderer.cpp +++ b/src/graphics/draw/UIRenderer.cpp @@ -116,64 +116,78 @@ void UIRenderer::drawGpsAltitude(OLEDDisplay *display, int16_t x, int16_t y, con } // Draw GPS status coordinates -void UIRenderer::drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps) +void UIRenderer::drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps, + const char *mode) { auto gpsFormat = config.display.gps_format; char displayLine[32]; if (!gps->getIsConnected() && !config.position.fixed_position) { strcpy(displayLine, "No GPS present"); - display->drawString(x + (display->getWidth() - (display->getStringWidth(displayLine))) / 2, y, displayLine); + display->drawString(x, y, displayLine); } else if (!gps->getHasLock() && !config.position.fixed_position) { strcpy(displayLine, "No GPS Lock"); - display->drawString(x + (display->getWidth() - (display->getStringWidth(displayLine))) / 2, y, displayLine); + display->drawString(x, y, displayLine); } else { geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude())); if (gpsFormat != meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) { - char coordinateLine[22]; + char coordinateLine_1[22]; + char coordinateLine_2[22]; if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees - snprintf(coordinateLine, sizeof(coordinateLine), "%f %f", geoCoord.getLatitude() * 1e-7, - geoCoord.getLongitude() * 1e-7); + snprintf(coordinateLine_1, sizeof(coordinateLine_1), "Lat: %f", geoCoord.getLatitude() * 1e-7); + snprintf(coordinateLine_2, sizeof(coordinateLine_2), "Lon: %f", geoCoord.getLongitude() * 1e-7); } else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator - snprintf(coordinateLine, sizeof(coordinateLine), "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(), - geoCoord.getUTMEasting(), geoCoord.getUTMNorthing()); + snprintf(coordinateLine_1, sizeof(coordinateLine_1), "%2i%1c %06u E", geoCoord.getUTMZone(), + geoCoord.getUTMBand(), geoCoord.getUTMEasting()); + snprintf(coordinateLine_2, sizeof(coordinateLine_2), "%07u N", geoCoord.getUTMNorthing()); } else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MGRS) { // Military Grid Reference System - snprintf(coordinateLine, sizeof(coordinateLine), "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(), - geoCoord.getMGRSBand(), geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(), - geoCoord.getMGRSEasting(), geoCoord.getMGRSNorthing()); + snprintf(coordinateLine_1, sizeof(coordinateLine_1), "%2i%1c %1c%1c", geoCoord.getMGRSZone(), + geoCoord.getMGRSBand(), geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k()); + snprintf(coordinateLine_2, sizeof(coordinateLine_2), "%05u E %05u N", geoCoord.getMGRSEasting(), + geoCoord.getMGRSNorthing()); } else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OLC) { // Open Location Code - geoCoord.getOLCCode(coordinateLine); + geoCoord.getOLCCode(coordinateLine_1); + coordinateLine_2[0] = '\0'; } else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR) { // Ordnance Survey Grid Reference - if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region - snprintf(coordinateLine, sizeof(coordinateLine), "%s", "Out of Boundary"); - else - snprintf(coordinateLine, sizeof(coordinateLine), "%1c%1c %05u %05u", geoCoord.getOSGRE100k(), - geoCoord.getOSGRN100k(), geoCoord.getOSGREasting(), geoCoord.getOSGRNorthing()); + if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') { // OSGR is only valid around the UK region + snprintf(coordinateLine_1, sizeof(coordinateLine_1), "%s", "Out of Boundary"); + coordinateLine_2[0] = '\0'; + } else { + snprintf(coordinateLine_1, sizeof(coordinateLine_1), "%1c%1c", geoCoord.getOSGRE100k(), + geoCoord.getOSGRN100k()); + snprintf(coordinateLine_2, sizeof(coordinateLine_2), "%05u E %05u N", geoCoord.getOSGREasting(), + geoCoord.getOSGRNorthing()); + } } - // If fixed position, display text "Fixed GPS" alternating with the coordinates. - if (config.position.fixed_position) { - if ((millis() / 10000) % 2) { - display->drawString(x + (display->getWidth() - (display->getStringWidth(coordinateLine))) / 2, y, - coordinateLine); - } else { - display->drawString(x + (display->getWidth() - (display->getStringWidth("Fixed GPS"))) / 2, y, "Fixed GPS"); + if (strcmp(mode, "line1") == 0) { + display->drawString(x, y, coordinateLine_1); + } else if (strcmp(mode, "line2") == 0) { + display->drawString(x, y, coordinateLine_2); + } else if (strcmp(mode, "combined") == 0) { + display->drawString(x, y, coordinateLine_1); + if (coordinateLine_2[0] != '\0') { + display->drawString(x + display->getStringWidth(coordinateLine_1), y, coordinateLine_2); } - } else { - display->drawString(x + (display->getWidth() - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine); } + } else { - char latLine[22]; - char lonLine[22]; - snprintf(latLine, sizeof(latLine), "%2i° %2i' %2u\" %1c", geoCoord.getDMSLatDeg(), geoCoord.getDMSLatMin(), - geoCoord.getDMSLatSec(), geoCoord.getDMSLatCP()); - snprintf(lonLine, sizeof(lonLine), "%3i° %2i' %2u\" %1c", geoCoord.getDMSLonDeg(), geoCoord.getDMSLonMin(), - geoCoord.getDMSLonSec(), geoCoord.getDMSLonCP()); - display->drawString(x + (display->getWidth() - (display->getStringWidth(latLine))) / 2, y - FONT_HEIGHT_SMALL * 1, - latLine); - display->drawString(x + (display->getWidth() - (display->getStringWidth(lonLine))) / 2, y, lonLine); + char coordinateLine_1[22]; + char coordinateLine_2[22]; + snprintf(coordinateLine_1, sizeof(coordinateLine_1), "Lat: %2i° %2i' %2u\" %1c", geoCoord.getDMSLatDeg(), + geoCoord.getDMSLatMin(), geoCoord.getDMSLatSec(), geoCoord.getDMSLatCP()); + snprintf(coordinateLine_2, sizeof(coordinateLine_2), "Lon: %3i° %2i' %2u\" %1c", geoCoord.getDMSLonDeg(), + geoCoord.getDMSLonMin(), geoCoord.getDMSLonSec(), geoCoord.getDMSLonCP()); + if (strcmp(mode, "line1") == 0) { + display->drawString(x, y, coordinateLine_1); + } else if (strcmp(mode, "line2") == 0) { + display->drawString(x, y, coordinateLine_2); + } else { // both + display->drawString(x, y, coordinateLine_1); + display->drawString(x, y + 10, coordinateLine_2); + } } } } @@ -978,17 +992,15 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU display->drawString(0, getTextPositions(display)[line++], "Last: ?"); } - // === Third Row: Latitude === - char latStr[32]; - snprintf(latStr, sizeof(latStr), "Lat: %.5f", geoCoord.getLatitude() * 1e-7); - display->drawString(x, getTextPositions(display)[line++], latStr); + // === Third Row: Line 1 GPS Info === + UIRenderer::drawGpsCoordinates(display, x, getTextPositions(display)[line++], gpsStatus, "line1"); - // === Fourth Row: Longitude === - char lonStr[32]; - snprintf(lonStr, sizeof(lonStr), "Lon: %.5f", geoCoord.getLongitude() * 1e-7); - display->drawString(x, getTextPositions(display)[line++], lonStr); + if (config.display.gps_format != meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OLC) { + // === Fourth Row: Line 2 GPS Info === + UIRenderer::drawGpsCoordinates(display, x, getTextPositions(display)[line++], gpsStatus, "line2"); + } - // === Fifth Row: Altitude === + // === Fourth/Fifth Row: Altitude === char DisplayLineTwo[32] = {0}; int32_t alt = (strcmp(displayLine, "Phone GPS") == 0 && ourNode && nodeDB->hasValidPosition(ourNode)) ? ourNode->position.altitude diff --git a/src/graphics/draw/UIRenderer.h b/src/graphics/draw/UIRenderer.h index eada150f9..438d56cc2 100644 --- a/src/graphics/draw/UIRenderer.h +++ b/src/graphics/draw/UIRenderer.h @@ -38,7 +38,8 @@ class UIRenderer // GPS status functions static void drawGps(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus); - static void drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus); + static void drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus, + const char *mode = "line1"); static void drawGpsAltitude(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus); static void drawGpsPowerStatus(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus);