diff --git a/modules/ui_map_runtime/include/ui_map_runtime/map_tiles/map_tile_types.h b/modules/ui_map_runtime/include/ui_map_runtime/map_tiles/map_tile_types.h index fd6179e2..7c5725c0 100644 --- a/modules/ui_map_runtime/include/ui_map_runtime/map_tiles/map_tile_types.h +++ b/modules/ui_map_runtime/include/ui_map_runtime/map_tiles/map_tile_types.h @@ -2,6 +2,7 @@ #include #include +#include namespace ui { @@ -62,6 +63,30 @@ struct MapTileLookupResult std::size_t size = 0; }; +/** + * Format the stable XYZ identity shown while a tile is loading or missing. + * + * This is shared by embedded and Linux renderers so a tile has the same + * diagnostic identity on every target. + */ +inline void formatMapTileCoordinateLabel(std::uint8_t z, + std::uint32_t x, + std::uint32_t y, + char* out, + std::size_t out_size) noexcept +{ + if (out == nullptr || out_size == 0U) + { + return; + } + std::snprintf(out, + out_size, + "z=%u\nx=%u\ny=%u", + static_cast(z), + static_cast(x), + static_cast(y)); +} + MapTileLayer mapTileLayerFromBaseSource(uint8_t map_source); MapTileLayer mapTileContourLayerForZoom(int zoom, bool* out_supported = nullptr); MapTileFormat mapTileFormatForLayer(MapTileLayer layer); diff --git a/platform/esp/arduino_common/src/ui/widgets/map/map_tiles.cpp b/platform/esp/arduino_common/src/ui/widgets/map/map_tiles.cpp index c6776dba..40accbbd 100644 --- a/platform/esp/arduino_common/src/ui/widgets/map/map_tiles.cpp +++ b/platform/esp/arduino_common/src/ui/widgets/map/map_tiles.cpp @@ -20,6 +20,7 @@ #include "ui_map_runtime/map_tiles/map_tile_async_runtime.h" #include "ui_map_runtime/map_tiles/map_tile_decoder_cache.h" #include "ui_map_runtime/map_tiles/map_tile_geometry.h" +#include "ui_map_runtime/map_tiles/map_tile_types.h" #include #include @@ -103,12 +104,12 @@ static void create_placeholder_tile_card(lv_obj_t* parent, MapTile& tile, int sc lv_obj_t* placeholder_label = lv_label_create(tile.img_obj); char placeholder_text[48]; - snprintf(placeholder_text, - sizeof(placeholder_text), - "z=%d\nx=%d\ny=%d", - tile.z, - fmt_tile_coord(tile.x), - fmt_tile_coord(tile.y)); + ui::map_tiles::formatMapTileCoordinateLabel( + static_cast(tile.z), + static_cast(fmt_tile_coord(tile.x)), + static_cast(fmt_tile_coord(tile.y)), + placeholder_text, + sizeof(placeholder_text)); lv_label_set_text(placeholder_label, placeholder_text); style_placeholder_text(placeholder_label); lv_obj_center(placeholder_label); @@ -261,8 +262,7 @@ constexpr uint32_t kMapTileDisplayPressureCooldownMs = 1500; constexpr uint32_t kMapTileDisplayPressureTileBackoffMs = 450; StaticTask_t s_map_tile_worker_task_tcb{}; -StackType_t s_map_tile_worker_task_stack[ - (kMapTileWorkerTaskStackBytes + sizeof(StackType_t) - 1U) / sizeof(StackType_t)]{}; +StackType_t s_map_tile_worker_task_stack[(kMapTileWorkerTaskStackBytes + sizeof(StackType_t) - 1U) / sizeof(StackType_t)]{}; uint32_t g_map_tile_decode_log_ms = 0; uint32_t g_map_tile_event_log_ms = 0; diff --git a/platform/linux/common/src/ui/widgets/map/map_tiles.cpp b/platform/linux/common/src/ui/widgets/map/map_tiles.cpp index 7dfe5c61..910466f6 100644 --- a/platform/linux/common/src/ui/widgets/map/map_tiles.cpp +++ b/platform/linux/common/src/ui/widgets/map/map_tiles.cpp @@ -9,6 +9,7 @@ #include "ui_map_runtime/map_tiles/filesystem_map_tile_source.h" #include "ui_map_runtime/map_tiles/map_tile_geometry.h" +#include "ui_map_runtime/map_tiles/map_tile_types.h" #include #include @@ -992,15 +993,21 @@ void create_or_refresh_tile_card(TileContext& ctx, MapTile& tile) lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); lv_obj_set_width(label, TILE_SIZE - 18); + char coordinate_text[48] = {}; + ui::map_tiles::formatMapTileCoordinateLabel( + static_cast(tile.z), + static_cast(tile.x), + static_cast(tile.y), + coordinate_text, + sizeof(coordinate_text)); + char text[128]; std::snprintf(text, sizeof(text), - "%s %s\nz%d x%d\ny%d", + "%s %s\n%s", has_base ? "Decode failed:" : "Missing", map_source_label(tile.map_source), - tile.z, - static_cast(tile.x), - static_cast(tile.y)); + coordinate_text); lv_label_set_text(label, text); lv_obj_center(label); diff --git a/platform/linux/uconsole/src/uconsole_desktop_shell.cpp b/platform/linux/uconsole/src/uconsole_desktop_shell.cpp index 0dd59d09..9f319c45 100644 --- a/platform/linux/uconsole/src/uconsole_desktop_shell.cpp +++ b/platform/linux/uconsole/src/uconsole_desktop_shell.cpp @@ -22,6 +22,7 @@ #include "uconsole/uconsole_chat_workspace_model.h" #include "uconsole/uconsole_dashboard_model.h" #include "uconsole/uconsole_map_workspace_model.h" +#include "ui_map_runtime/map_tiles/map_tile_types.h" namespace trailmate::uconsole { @@ -1682,6 +1683,7 @@ class UConsoleDesktopShell const auto snapshot = map_model_.snapshot(); map_tile_cells_.fill(nullptr); map_tile_images_.fill(nullptr); + map_tile_placeholder_labels_.fill(nullptr); map_tile_paths_.fill(std::string{}); lv_obj_t* map = createPreviewPanel( desktop_page_panel_, "Field map", 0, embedded_palette::kMapBg, @@ -1745,6 +1747,18 @@ class UConsoleDesktopShell tile, color(embedded_palette::kBorder), 0); lv_obj_set_style_border_width(tile, 1, 0); map_tile_cells_[static_cast(tile_index)] = tile; + lv_obj_t* placeholder = + createLabel(tile, "", &lv_font_montserrat_10, + embedded_palette::kTextDim, + LV_LABEL_LONG_WRAP); + lv_obj_set_width(placeholder, LV_PCT(100)); + lv_obj_set_height(placeholder, LV_PCT(100)); + lv_obj_set_style_text_align(placeholder, + LV_TEXT_ALIGN_CENTER, 0); + lv_obj_set_style_text_line_space(placeholder, 1, 0); + lv_obj_center(placeholder); + map_tile_placeholder_labels_ + [static_cast(tile_index)] = placeholder; const bool available = tile_index < static_cast(snapshot.tiles.size()) && snapshot.tiles[static_cast(tile_index)] @@ -1772,9 +1786,24 @@ class UConsoleDesktopShell image, map_tile_paths_[static_cast(tile_index)] .c_str()); + lv_obj_add_flag(placeholder, LV_OBJ_FLAG_HIDDEN); } else { + char xyz[48] = {}; + if (tile_index < static_cast(snapshot.tiles.size())) + { + const auto& id = + snapshot.tiles[static_cast(tile_index)] + .id; + ::ui::map_tiles::formatMapTileCoordinateLabel( + static_cast(id.z), + static_cast(id.x), + static_cast(id.y), + xyz, + sizeof(xyz)); + } + lv_label_set_text(placeholder, xyz); map_tile_paths_[static_cast(tile_index)] .clear(); } @@ -2159,6 +2188,14 @@ class UConsoleDesktopShell if (map_meta_label_ == nullptr) return; if (!force && active_section_ != Section::Map) return; + const auto now = clock::now(); + if (!force && + (now - last_map_preview_refresh_) < + std::chrono::milliseconds(100)) + { + return; + } + last_map_preview_refresh_ = now; const auto snapshot = map_model_.snapshot(); setLabel(map_meta_label_, mapSummary(snapshot)); @@ -2173,6 +2210,11 @@ class UConsoleDesktopShell if (tile == nullptr) continue; if (snapshot.tiles[index].available) { + if (map_tile_placeholder_labels_[index] != nullptr) + { + lv_obj_add_flag(map_tile_placeholder_labels_[index], + LV_OBJ_FLAG_HIDDEN); + } if (map_tile_images_[index] == nullptr) { auto* image = lv_image_create(tile); @@ -2180,12 +2222,16 @@ class UConsoleDesktopShell lv_obj_set_size(image, LV_PCT(100), LV_PCT(100)); map_tile_images_[index] = image; } - map_tile_paths_[index] = + const std::string path = "A:" + snapshot.tiles[index].path.string(); - lv_image_set_inner_align(map_tile_images_[index], - LV_IMAGE_ALIGN_STRETCH); - lv_image_set_src(map_tile_images_[index], - map_tile_paths_[index].c_str()); + if (map_tile_paths_[index] != path) + { + map_tile_paths_[index] = path; + lv_image_set_inner_align(map_tile_images_[index], + LV_IMAGE_ALIGN_STRETCH); + lv_image_set_src(map_tile_images_[index], + map_tile_paths_[index].c_str()); + } lv_obj_set_style_bg_color( tile, color(embedded_palette::kMapTile2), 0); } @@ -2196,6 +2242,21 @@ class UConsoleDesktopShell lv_obj_del(map_tile_images_[index]); map_tile_images_[index] = nullptr; } + if (map_tile_placeholder_labels_[index] != nullptr) + { + char xyz[48] = {}; + const auto& id = snapshot.tiles[index].id; + ::ui::map_tiles::formatMapTileCoordinateLabel( + static_cast(id.z), + static_cast(id.x), + static_cast(id.y), + xyz, + sizeof(xyz)); + lv_label_set_text(map_tile_placeholder_labels_[index], + xyz); + lv_obj_clear_flag(map_tile_placeholder_labels_[index], + LV_OBJ_FLAG_HIDDEN); + } lv_obj_set_style_bg_color( tile, color(embedded_palette::kSurfaceAlt), 0); } @@ -2857,9 +2918,12 @@ class UConsoleDesktopShell lv_obj_t* map_retry_label_ = nullptr; std::array map_tile_cells_{}; std::array map_tile_images_{}; + std::array + map_tile_placeholder_labels_{}; std::array map_tile_paths_{}; std::vector> map_download_jobs_{}; + clock::time_point last_map_preview_refresh_{}; std::array nav_bindings_{}; std::array nav_buttons_{};