From 480c7ac94e8906f44d790a7eaa56d142759cd613 Mon Sep 17 00:00:00 2001 From: liu weikai Date: Mon, 6 Jul 2026 22:33:36 +0800 Subject: [PATCH] Add map altitude overlay and info toggle --- .../ui_presentation/gps/gps_status_snapshot.h | 1 + .../tests/test_gps_status_model.cpp | 2 + .../runtime_gps_status_source.cpp | 3 +- .../src/ui/screens/gps/gps_page_runtime.cpp | 211 +++++++++++++++++- .../src/uconsole_map_workspace_model.cpp | 2 +- 5 files changed, 216 insertions(+), 3 deletions(-) diff --git a/modules/ui_presentation/include/ui_presentation/gps/gps_status_snapshot.h b/modules/ui_presentation/include/ui_presentation/gps/gps_status_snapshot.h index 8e82f3d0..77f60952 100644 --- a/modules/ui_presentation/include/ui_presentation/gps/gps_status_snapshot.h +++ b/modules/ui_presentation/include/ui_presentation/gps/gps_status_snapshot.h @@ -18,6 +18,7 @@ struct GpsStatusSnapshot bool fix_valid = false; double latitude = 0.0; double longitude = 0.0; + bool has_altitude = false; float altitude_m = 0.0f; float speed_mps = 0.0f; float course_deg = 0.0f; diff --git a/modules/ui_presentation/tests/test_gps_status_model.cpp b/modules/ui_presentation/tests/test_gps_status_model.cpp index 9ccf058d..1866cade 100644 --- a/modules/ui_presentation/tests/test_gps_status_model.cpp +++ b/modules/ui_presentation/tests/test_gps_status_model.cpp @@ -14,6 +14,7 @@ int main() source.snapshot_value.fix_valid = true; source.snapshot_value.latitude = 31.2304; source.snapshot_value.longitude = 121.4737; + source.snapshot_value.has_altitude = true; source.snapshot_value.altitude_m = 12.5f; source.snapshot_value.speed_mps = 1.25f; source.snapshot_value.course_deg = 48.0f; @@ -35,6 +36,7 @@ int main() assert(snapshot.fix_valid); assert(snapshot.latitude == 31.2304); assert(snapshot.longitude == 121.4737); + assert(snapshot.has_altitude); assert(snapshot.satellites == 8); assert(snapshot.time_synced); assert(snapshot.epoch_seconds == 1700000000ULL); diff --git a/modules/ui_shared/src/ui/presentation_sources/runtime_gps_status_source.cpp b/modules/ui_shared/src/ui/presentation_sources/runtime_gps_status_source.cpp index f4483c43..6b4d6323 100644 --- a/modules/ui_shared/src/ui/presentation_sources/runtime_gps_status_source.cpp +++ b/modules/ui_shared/src/ui/presentation_sources/runtime_gps_status_source.cpp @@ -64,7 +64,8 @@ bool RuntimeGpsStatusSource::buildGpsStatusSnapshot(ui::gps::GpsStatusSnapshot& out.fix_valid = state.valid || diagnostics.has_fix; out.latitude = state.lat; out.longitude = state.lng; - out.altitude_m = state.has_alt ? static_cast(state.alt_m) : 0.0f; + out.has_altitude = state.valid && state.has_alt; + out.altitude_m = out.has_altitude ? static_cast(state.alt_m) : 0.0f; out.speed_mps = state.has_speed ? static_cast(state.speed_mps) : 0.0f; out.course_deg = state.has_course ? static_cast(state.course_deg) : 0.0f; platform::ui::gps::GnssStatus gnss_status{}; diff --git a/modules/ui_shared/src/ui/screens/gps/gps_page_runtime.cpp b/modules/ui_shared/src/ui/screens/gps/gps_page_runtime.cpp index e06db68c..901c0308 100644 --- a/modules/ui_shared/src/ui/screens/gps/gps_page_runtime.cpp +++ b/modules/ui_shared/src/ui/screens/gps/gps_page_runtime.cpp @@ -84,6 +84,8 @@ constexpr lv_coord_t kMapControlButtonWideWidth = 44; constexpr lv_coord_t kMapControlButtonContourWidth = 56; constexpr lv_coord_t kMapControlButtonTrackerWidth = 42; constexpr lv_coord_t kMapSideRailWidth = 72; +constexpr lv_coord_t kMapAltitudePanelHeight = 18; +constexpr lv_coord_t kMapAltitudePanelWidth = 82; constexpr std::uint32_t kLvglFunctionKeyF1 = 0x110001U; constexpr std::uint32_t kInvalidMemberId = 0xFFFFFFFFU; constexpr std::size_t kMaxTrackOverlayPoints = 48; @@ -123,10 +125,12 @@ lv_obj_t* s_root = nullptr; lv_timer_t* s_timer = nullptr; ::ui::widgets::TopBar s_top_bar; ::ui::widgets::map::Runtime s_map_runtime; +lv_obj_t* s_map_viewport = nullptr; int s_map_zoom = kCardputerZeroMapDefaultZoom; int s_map_pan_x = 0; int s_map_pan_y = 0; bool s_map_view_initialized = false; +bool s_map_info_visible = true; UI_GPS_PAGE_STATE_RAM_ATTR ::ui::map::MapOverlaySnapshot s_overlay_snapshot; Projection s_projection = Projection::Map; bool s_gps_power_lease_active = false; @@ -146,6 +150,8 @@ lv_obj_t* s_map_layer_btn = nullptr; lv_obj_t* s_map_contour_btn = nullptr; lv_obj_t* s_map_help_btn = nullptr; lv_obj_t* s_map_tracker_btn = nullptr; +lv_obj_t* s_map_altitude_panel = nullptr; +lv_obj_t* s_map_altitude_label = nullptr; lv_obj_t* s_map_notice_panel = nullptr; lv_obj_t* s_map_notice_label = nullptr; lv_obj_t* s_map_context_rail = nullptr; @@ -178,6 +184,8 @@ void open_tracker_modal(); void add_map_controls_to_group(lv_group_t* group); void request_refresh_view(); void consume_key_event(lv_event_t* e); +void sync_map_chrome_visibility(); +void rebuild_map_control_group(); bool load_map_track_file_impl(const char* path, bool show_fail_toast); void append_track_point(std::vector& out, double lat, @@ -453,6 +461,7 @@ void set_button_label(lv_obj_t* btn, const char* text) void clear_map_controls() { + s_map_viewport = nullptr; s_map_control_bar = nullptr; s_map_zoom_label = nullptr; s_map_zoom_out_btn = nullptr; @@ -462,6 +471,8 @@ void clear_map_controls() s_map_contour_btn = nullptr; s_map_help_btn = nullptr; s_map_tracker_btn = nullptr; + s_map_altitude_panel = nullptr; + s_map_altitude_label = nullptr; s_map_notice_panel = nullptr; s_map_notice_label = nullptr; s_map_context_rail = nullptr; @@ -502,6 +513,112 @@ bool map_control_visible(lv_obj_t* obj) return obj && lv_obj_is_valid(obj) && !lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN); } +void resize_map_runtime_to_viewport() +{ + if (!s_root || !s_map_viewport || !lv_obj_is_valid(s_map_viewport)) + { + return; + } + + lv_obj_update_layout(s_root); + lv_obj_update_layout(s_map_viewport); + ::ui::widgets::map::set_size(s_map_runtime, + lv_obj_get_content_width(s_map_viewport), + lv_obj_get_content_height(s_map_viewport)); + + const auto& widgets = ::ui::widgets::map::widgets(s_map_runtime); + if (widgets.root && lv_obj_is_valid(widgets.root)) + { + lv_obj_align(widgets.root, LV_ALIGN_CENTER, 0, 0); + } +} + +void sync_map_chrome_visibility() +{ + if (s_projection != Projection::Map) + { + return; + } + + const bool show_info = s_map_info_visible; + set_hidden(s_top_bar.container, !show_info); + set_hidden(s_map_control_bar, !show_info); + + if (!show_info) + { + set_hidden(s_map_altitude_panel, true); + set_hidden(s_map_context_rail, true); + set_hidden(s_map_notice_panel, true); + } + + if (app_g && !(s_map_help_modal && lv_obj_is_valid(s_map_help_modal)) && + !(s_tracker_modal && lv_obj_is_valid(s_tracker_modal))) + { + if (show_info) + { + rebuild_map_control_group(); + } + else if (s_root && lv_obj_is_valid(s_root)) + { + lv_group_remove_all_objs(app_g); + lv_group_add_obj(app_g, s_root); + lv_group_focus_obj(s_root); + lv_group_set_editing(app_g, false); + } + } + + resize_map_runtime_to_viewport(); +} + +bool format_map_altitude_label(char* out, size_t out_len) +{ + if (!out || out_len == 0) + { + return false; + } + + const auto snapshot = gps_status_model().snapshot(); + if (snapshot.header.valid && + snapshot.fix_valid && + snapshot.has_altitude && + std::isfinite(snapshot.altitude_m)) + { + std::snprintf(out, out_len, "Alt %.0f m", static_cast(snapshot.altitude_m)); + return true; + } + + std::snprintf(out, out_len, "Alt --"); + return false; +} + +void sync_map_altitude_overlay() +{ + if (!s_map_altitude_panel || !lv_obj_is_valid(s_map_altitude_panel) || + !s_map_altitude_label || !lv_obj_is_valid(s_map_altitude_label)) + { + return; + } + + if (!s_map_info_visible) + { + set_hidden(s_map_altitude_panel, true); + return; + } + + char label[24]{}; + (void)format_map_altitude_label(label, sizeof(label)); + set_compact_label(s_map_altitude_label, label); + set_hidden(s_map_altitude_panel, false); + lv_obj_move_foreground(s_map_altitude_panel); +} + +void toggle_map_info_visibility() +{ + s_map_info_visible = !s_map_info_visible; + sync_map_chrome_visibility(); + refresh_view(); +} + bool help_uses_f1() { #if defined(TRAIL_MATE_CARDPUTER_ZERO_LINUX) || defined(TRAIL_MATE_ESP_BOARD_T_DISPLAY_P4) @@ -784,6 +901,12 @@ void sync_map_notice_overlay() return; } + if (!s_map_info_visible) + { + set_hidden(s_map_notice_panel, true); + return; + } + const uint32_t now = sys::millis_now(); if (s_map_notice_text[0] != '\0' && now < s_map_notice_until_ms) { @@ -800,6 +923,14 @@ void sync_map_notice_overlay() void sync_map_context_buttons(const ::ui::map::MapWorkspaceSnapshot& snapshot) { + if (!s_map_info_visible) + { + set_hidden(s_map_route_btn, true); + set_hidden(s_map_context_rail, true); + (void)snapshot; + return; + } + const bool show_route = route_context_available(); ::team::ui::TeamUiSnapshot team_snapshot; const bool has_team_members = load_team_snapshot(team_snapshot) && !team_snapshot.members.empty(); @@ -871,6 +1002,18 @@ void sync_map_control_labels(const ::ui::map::MapWorkspaceSnapshot& snapshot) return; } + if (!s_map_info_visible) + { + set_hidden(s_map_control_bar, true); + sync_map_altitude_overlay(); + sync_map_context_buttons(snapshot); + sync_map_notice_overlay(); + return; + } + + set_hidden(s_map_control_bar, false); + sync_map_altitude_overlay(); + const auto layers = ::ui::widgets::map::current_layer_state(); set_button_label(s_map_layer_btn, compact_map_source_label(layers.map_source)); set_button_label(s_map_contour_btn, layers.contour_enabled ? "Contour*" : "Contour"); @@ -960,7 +1103,7 @@ void refresh_gps_status_view() set_compact_label(s_gps_sat_label, snapshot.satellite_label.c_str()); char line[48]{}; - if (snapshot.fix_valid && std::isfinite(snapshot.altitude_m)) + if (snapshot.fix_valid && snapshot.has_altitude && std::isfinite(snapshot.altitude_m)) { std::snprintf(line, sizeof(line), "%.0f m", static_cast(snapshot.altitude_m)); } @@ -1516,6 +1659,26 @@ void append_track_overlay(::ui::map::MapOverlaySnapshot& snapshot) } } +void keep_only_current_position_overlay(::ui::map::MapOverlaySnapshot& snapshot) +{ + std::size_t write = 0; + for (std::size_t read = 0; read < snapshot.item_count; ++read) + { + const auto& item = snapshot.items[read]; + if (item.kind != ::ui::map::MapOverlayKind::CurrentPosition) + { + continue; + } + if (write != read) + { + snapshot.items[write] = item; + } + ++write; + } + snapshot.item_count = write; + snapshot.truncated = false; +} + bool load_map_track_file_impl(const char* path, bool show_fail_toast) { if (!path || path[0] == '\0') @@ -1643,6 +1806,10 @@ void refresh_view() auto snapshot = map_workspace_model().snapshot(); (void)map_overlay_source().buildMapOverlaySnapshot(s_overlay_snapshot); append_track_overlay(s_overlay_snapshot); + if (!s_map_info_visible) + { + keep_only_current_position_overlay(s_overlay_snapshot); + } if (snapshot.header.valid) { @@ -2026,6 +2193,7 @@ void open_map_help_modal() add_help_row("L", nullptr, "Change base layer"); add_help_row("O", "Contour", "Toggle contour overlay"); add_help_row("T", "Track", "Select track file"); + add_help_row("I", nullptr, "Hide info"); add_help_row("Route", nullptr, "Shown when route active"); add_help_row("Members", nullptr, "Shown when team active"); add_help_row(help_key_label(), "Back", "Close help"); @@ -2385,6 +2553,11 @@ bool handle_map_key(uint32_t key, lv_event_t* e) adjust_map_zoom(1); consume_key_event(e); return true; + case 'i': + case 'I': + toggle_map_info_visibility(); + consume_key_event(e); + return true; case 'c': case 'C': case 'p': @@ -2553,6 +2726,36 @@ void create_map_control_bar(lv_obj_t* viewport) lv_obj_move_foreground(s_map_control_bar); } +void create_map_altitude_overlay(lv_obj_t* viewport) +{ + s_map_altitude_panel = lv_obj_create(viewport); + lv_obj_set_size(s_map_altitude_panel, kMapAltitudePanelWidth, kMapAltitudePanelHeight); + lv_obj_align(s_map_altitude_panel, + LV_ALIGN_BOTTOM_LEFT, + 4, + -(kMapControlBarHeight + 4)); + lv_obj_add_flag(s_map_altitude_panel, LV_OBJ_FLAG_IGNORE_LAYOUT); + lv_obj_set_style_bg_color(s_map_altitude_panel, lv_color_hex(0x25170D), 0); + lv_obj_set_style_bg_opa(s_map_altitude_panel, LV_OPA_70, 0); + lv_obj_set_style_border_width(s_map_altitude_panel, 0, 0); + lv_obj_set_style_radius(s_map_altitude_panel, 4, 0); + lv_obj_set_style_pad_left(s_map_altitude_panel, 5, 0); + lv_obj_set_style_pad_right(s_map_altitude_panel, 5, 0); + lv_obj_set_style_pad_top(s_map_altitude_panel, 1, 0); + lv_obj_set_style_pad_bottom(s_map_altitude_panel, 1, 0); + lv_obj_clear_flag(s_map_altitude_panel, LV_OBJ_FLAG_SCROLLABLE); + + s_map_altitude_label = lv_label_create(s_map_altitude_panel); + lv_label_set_text(s_map_altitude_label, "Alt --"); + lv_obj_set_width(s_map_altitude_label, kMapAltitudePanelWidth - 10); + lv_obj_set_style_text_font(s_map_altitude_label, &lv_font_montserrat_10, 0); + lv_obj_set_style_text_color(s_map_altitude_label, lv_color_hex(0xFFF3DF), 0); + lv_obj_set_style_text_align(s_map_altitude_label, LV_TEXT_ALIGN_LEFT, 0); + lv_label_set_long_mode(s_map_altitude_label, LV_LABEL_LONG_CLIP); + lv_obj_center(s_map_altitude_label); + lv_obj_move_foreground(s_map_altitude_panel); +} + void create_map_notice_overlay(lv_obj_t* viewport) { s_map_notice_panel = lv_obj_create(viewport); @@ -2666,6 +2869,7 @@ void create_gps_status_content(lv_obj_t* content) void create_map_content(lv_obj_t* content) { lv_obj_t* viewport = lv_obj_create(content); + s_map_viewport = viewport; lv_obj_set_size(viewport, LV_PCT(100), 0); lv_obj_set_flex_grow(viewport, 1); lv_obj_set_style_bg_color(viewport, lv_color_hex(0xEAD9B2), 0); @@ -2688,6 +2892,7 @@ void create_map_content(lv_obj_t* content) lv_obj_align(map_widgets.root, LV_ALIGN_CENTER, 0, 0); } create_map_control_bar(viewport); + create_map_altitude_overlay(viewport); create_map_notice_overlay(viewport); create_map_context_rail(viewport); @@ -2738,6 +2943,10 @@ void enter(const shell::Host* host, lv_obj_t* parent, shell::Projection projecti s_projection = projection; clear_gps_status_labels(); clear_map_controls(); + if (s_projection == Projection::Map) + { + s_map_info_visible = true; + } if (s_projection == Projection::Map && !s_map_view_initialized) { s_map_zoom = kCardputerZeroMapDefaultZoom; diff --git a/platform/linux/uconsole/src/uconsole_map_workspace_model.cpp b/platform/linux/uconsole/src/uconsole_map_workspace_model.cpp index 3a50e9b8..73251d8f 100644 --- a/platform/linux/uconsole/src/uconsole_map_workspace_model.cpp +++ b/platform/linux/uconsole/src/uconsole_map_workspace_model.cpp @@ -317,7 +317,7 @@ MapWorkspaceSnapshot UConsoleMapWorkspaceModel::snapshot() const out.lat = gps.latitude; out.lon = gps.longitude; out.altitude_m = static_cast(gps.altitude_m); - out.has_altitude = out.has_fix; + out.has_altitude = out.has_fix && gps.has_altitude; out.speed_mps = static_cast(gps.speed_mps); out.has_speed = out.has_fix; out.satellites = gps.satellites;