#pragma once // Map tools > Vector regions: the region packs on the card (/vmap/*.vpk, // map/VectorPacks.h, made with tools/maps/osm_vector.py --pack): show one on // the map, delete it. // // Single-TU fragment: included by ui-lvgl/UITask.cpp after MapAreas.h. namespace regions { static int s_sel = -1; // the pack a popup is about static uint32_t s_del_armed_ms = 0; static lv_obj_t* s_del_lbl = nullptr; enum : uint8_t { A_SHOW, A_DELETE }; static void onDeleted(lv_event_t* e) { if (lv_event_get_target(e) == s_del_lbl) s_del_lbl = nullptr; } static void onPack(lv_event_t* e) { s_ui->mapRegionPopup((int)(intptr_t)lv_event_get_user_data(e)); } static void onAct(lv_event_t* e) { s_ui->mapRegionAction((uint8_t)(uintptr_t)lv_event_get_user_data(e)); } static lv_obj_t* actButton(lv_obj_t* row, const char* text, uint8_t act, bool accent) { lv_obj_t* b = lv_button_create(row); lv_obj_set_height(b, 36); lv_obj_set_flex_grow(b, 1); lv_obj_set_style_pad_hor(b, 4, 0); lv_obj_set_style_radius(b, theme::RADIUS, 0); lv_obj_set_style_shadow_width(b, 0, 0); lv_obj_set_style_bg_color(b, lv_color_hex(accent ? theme::ACCENT_DIM : theme::SURFACE), 0); lv_obj_set_style_bg_color(b, lv_color_hex(theme::SURFACE_2), LV_STATE_PRESSED); lv_obj_add_event_cb(b, onAct, LV_EVENT_CLICKED, (void*)(uintptr_t)act); lv_obj_t* l = label(b, text, THEME_FONT_SMALL, theme::TEXT); lv_obj_center(l); return l; } static void fmtMB(char* out, size_t n, uint32_t bytes) { if (bytes >= 1024 * 1024) snprintf(out, n, "%.1f MB", bytes / 1048576.0); else snprintf(out, n, "%lu KB", (unsigned long)((bytes + 1023) / 1024)); } } // namespace regions void UITask::mapRegionsPopup() { using namespace regions; mapview::s_vpacks.scan(); lv_obj_t* panel = navPopupPanel("Vector regions", true); lv_obj_t* list = scrollList(panel); int np = mapview::s_vpacks.count(); if (np) { lv_obj_t* g = group(list, nullptr); for (int i = 0; i < np; i++) { const mapview::VectorPacks::Pack& p = mapview::s_vpacks.at(i); char sub[48], mb[16]; fmtMB(mb, sizeof(mb), p.size); snprintf(sub, sizeof(sub), "%s%s", mb, (p.flags & mapview::VectorPacks::F_CONTOURS) ? " - contours" : ""); listRow(g, p.name[0] ? p.name : p.file, sub, onPack, (void*)(intptr_t)i); } } lv_obj_t* l = label(list, np ? "Packs in /vmap on the SD card, made with tools/maps/osm_vector.py --pack." : "No regions yet. Make a pack with tools/maps/osm_vector.py --pack and copy it to /vmap on the SD card.", THEME_FONT_SMALL, theme::TEXT_MUTED); lv_label_set_long_mode(l, LV_LABEL_LONG_WRAP); lv_obj_set_width(l, LV_PCT(100)); } void UITask::mapRegionPopup(int idx) { using namespace regions; if (idx < 0 || idx >= mapview::s_vpacks.count()) return; s_sel = idx; const mapview::VectorPacks::Pack& p = mapview::s_vpacks.at(idx); lv_obj_t* panel = navPopupPanel(p.name[0] ? p.name : p.file, false); char info[128], mb[16]; fmtMB(mb, sizeof(mb), p.size); snprintf(info, sizeof(info), "%s, zoom %d-18%s\n%s", mb, p.zmin, (p.flags & mapview::VectorPacks::F_CONTOURS) ? ", contours" : "", p.file); lv_obj_t* l = label(panel, info, THEME_FONT_SMALL, theme::TEXT); lv_label_set_long_mode(l, LV_LABEL_LONG_WRAP); lv_obj_set_width(l, LV_PCT(100)); lv_obj_t* r = toolRow(panel); actButton(r, UI_SYMBOL_MAP " Show", A_SHOW, true); s_del_lbl = actButton(r, LV_SYMBOL_TRASH " Delete", A_DELETE, false); lv_obj_add_event_cb(s_del_lbl, onDeleted, LV_EVENT_DELETE, NULL); s_del_armed_ms = 0; } void UITask::mapRegionAction(uint8_t act) { using namespace regions; if (s_sel < 0 || s_sel >= mapview::s_vpacks.count()) return; const mapview::VectorPacks::Pack& p = mapview::s_vpacks.at(s_sel); switch (act) { case A_SHOW: { navClosePopup(); double x0 = mapview::lonToTileX(p.box[0] / 1e6, 0), x1 = mapview::lonToTileX(p.box[2] / 1e6, 0); double y0 = mapview::latToTileY(p.box[3] / 1e6, 0), y1 = mapview::latToTileY(p.box[1] / 1e6, 0); int w = _map_area ? lv_obj_get_width(_map_area) : 320, h = _map_area ? lv_obj_get_height(_map_area) : 218; _map_z = areas::fitZoom(x1 - x0, y1 - y0, w - 40, h - 60); double s = (double)(1 << _map_z); _map_cx = (x0 + x1) / 2 * s; _map_cy = (y0 + y1) / 2 * s; _map_follow = false; layoutMap(); return; } case A_DELETE: { if (!s_del_armed_ms || millis() - s_del_armed_ms > 3000) { // a second tap within 3 s confirms s_del_armed_ms = millis() | 1; if (s_del_lbl) lv_label_set_text(s_del_lbl, "Delete?"); return; } char path[80]; snprintf(path, sizeof(path), "%s/%s", mapview::VECTOR_ROOT, p.file); mapview::s_vpacks.closeOpen(); remove(path); mapview::s_vector.available(); // lists the packs again, forgets the data read mapview::labels::flush(); mapview::s_cache.invalidate(); mapRegionsPopup(); showToast("Region deleted"); return; } } }