mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-10-09 11:16:39 +00:00
feat(ui-lvgl): navigation map, clock tools, settings pages, radio
- Home > Map is the navigation map: waypoints (list, add at GPS / by coordinates / long-press spot), live shares, trail recording + tools (save, load, GPX export, track back), live share controls, target bar with ETA; the nodes map opens from Nearby. - Map: smooth panning (no decode during a drag, idle read-ahead, cached coarser stand-ins), overzoom limited to 2 levels, resumable downloads, map credit behind a "©" and in Settings > About; target ring and trail computed in double. - Home in swipeable pages; Clock (alarm, timer, stopwatch, ring card). - Settings rendered from the Core schema (display & power with a brightness slider, messages & contacts, trail / live share / alerts), GPS switch, Radio screen; low-battery shutdown. - WioTrackerL2Display: honour the 0-4 brightness level. - docs: L2 hardware checklist, ui-core notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,113 @@
|
|||||||
|
# Wio Tracker L2 (ui-lvgl) — hardware checklist
|
||||||
|
|
||||||
|
Things verified only in the browser simulator so far. Tick on the device;
|
||||||
|
note anything odd next to the item. Branch `wio-tracker-l2`.
|
||||||
|
|
||||||
|
## Feedback round 1 (2026-09-25) — fixed, check on the device
|
||||||
|
Confirmed on the device: live share sends and receives positions.
|
||||||
|
- [ ] Map: ☰ tools moved to the left column (back, pin, ☰); nothing overlaps the crosshair
|
||||||
|
- [ ] Target ring sits exactly on the marker (all markers were drawn ~3 px low)
|
||||||
|
- [ ] A person sharing on a channel, picked as target, is followed as they move (was a fixed point where they were); bar shows the person icon
|
||||||
|
- [ ] Settings: "Trail, live share, alerts" subtitle no longer covers the title (all list rows)
|
||||||
|
- [ ] Map credit is a small "©" (tap: full line in a toast); full text also in Settings > About; long toasts wrap
|
||||||
|
- [ ] Home: Messages, Nearby, Map, Settings — "Map" is the navigation map; the nodes map opens from Nearby's header (map icon), back returns to Nearby
|
||||||
|
- [ ] Home tiles are wider; more apps will go on further swipeable pages (dots appear once there are two)
|
||||||
|
- [ ] Overzoom limited to 2 levels (x4); past that "No map detail here at this zoom" — download more
|
||||||
|
- [ ] Panning: no tile decoding while the finger moves (smooth drag, tiles fill in once you stop); tiles around the view are decoded ahead while idle; newly revealed area shows the coarser tile until the sharp one is ready
|
||||||
|
- [ ] Note how panning feels now: ______ (next step if still slow: decode on the second core / JPEG tiles)
|
||||||
|
|
||||||
|
## Feedback round 2 (2026-09-25) — fixed, check on the device
|
||||||
|
Confirmed: settings rows OK, map pans much faster, ring centred.
|
||||||
|
- [ ] Target ring is wider (30 px) so the green / flag marker shows inside it; a target with no marker on it (map point, message position, stale live share) gets an orange centre dot
|
||||||
|
- [ ] "↓ Resume?" pill sits top right beside +, clear of the zoom pill; tapping it opens the download popup
|
||||||
|
- [ ] Pin button → Waypoints list (distance, tap → Go / Name / Share / Delete) with "Here (GPS)" and "Coordinates"
|
||||||
|
- [ ] Coordinates: digits keyboard, "50.06142, 19.93721 Name" or with a space instead of the comma; bad input keeps the field with a hint; the map centres on the new waypoint
|
||||||
|
- [ ] Holding the map no longer adds a waypoint straight away: "This spot" popup with Add waypoint / Go here
|
||||||
|
|
||||||
|
## Feedback round 3 (2026-09-25) — fixed, check on the device
|
||||||
|
Confirmed: green dot inside the ring, waypoints much better, download works, settings OK.
|
||||||
|
- [ ] Ring exactly on the marker at every zoom (it was computed in float: pixels off at z16+). The trail line had the same error and is fixed too
|
||||||
|
- [ ] Home: swipe left / right anywhere (clock or tiles) turns the page; a swipe starting on a tile doesn't open it; tapping a dot also switches
|
||||||
|
- [ ] Settings > Display & power: Brightness is a slider (5-100 %), changes live while dragging, kept after a reboot and after the screen sleeps / wakes
|
||||||
|
- [ ] After the update: prefs load normally (new field, schema sentinel 0xC0DE002F) — brightness starts from the old level, nothing else reset
|
||||||
|
|
||||||
|
## New: Clock, settings pages, radio (2026-09-25)
|
||||||
|
- [ ] Home has two pages now: swipe left → Clock (dots under the tiles follow; Home remembers the page)
|
||||||
|
- [ ] Clock > Alarm: hour / minute rollers (setting a time arms it), On switch, Repeat (Once / Daily / Weekdays / Weekends); rings at the local time
|
||||||
|
- [ ] Clock > Timer: H / M / S rollers, Start → big countdown, Stop; when it ends a full-screen "Timer done" card with Dismiss appears on any screen (also wakes the display; the user button dismisses too). Silent: no speaker driver yet
|
||||||
|
- [ ] Clock > Stopwatch: Start / Stop / Reset with tenths
|
||||||
|
- [ ] Settings > Display & power: Screen off after; Wake on message
|
||||||
|
- [ ] Settings > Display & power: Battery shutdown (not while on USB), GPS power saving, Time zone (clock + alarm follow)
|
||||||
|
- [ ] Settings > Messages & contacts: Resend direct messages, Contact expiry + "Remove inactive contacts now" (first tap shows the count, second removes; favourites kept), Favourites first
|
||||||
|
- [ ] Settings > Radio: Preset list (built-ins + your saved ones), Frequency (tap, type), SF, Bandwidth, Coding rate, TX power, Auto power; changes apply at once — check messages still flow after switching back to your usual preset
|
||||||
|
- [ ] L1 (ui-new): Settings > Radio TX power / Auto power / presets still apply (now through the shared RadioControl)
|
||||||
|
|
||||||
|
## Basics after the_mesh moved to PSRAM (`MESH_IN_PSRAM`)
|
||||||
|
- [ ] Boots normally, contacts and channels are all there
|
||||||
|
- [ ] Messages arrive and send (channel + DM), delivery ticks work
|
||||||
|
- [ ] Companion app over BLE connects and syncs
|
||||||
|
- [ ] A few hours of uptime without a reboot
|
||||||
|
|
||||||
|
## WiFi map download
|
||||||
|
- [ ] Settings > WiFi: Scan lists networks, pick one, password, Save
|
||||||
|
- [ ] Map > download button: popup shows tile count / size, Download starts
|
||||||
|
- [ ] Pill on the map: "Connecting..." then "↓ n / total"
|
||||||
|
- [ ] Popup while downloading: IP, dBm, heap (internal free / largest block) — note the numbers: ______
|
||||||
|
- [ ] Mesh messages still arrive during a download; BLE stays connected
|
||||||
|
- [ ] Stop → popup shows "Unfinished: z…-…, N tiles" with Resume / trash
|
||||||
|
- [ ] Power off mid-download → power on → map shows "↓ Resume?" (top right; tap it) → Resume continues (count jumps past the tiles already on the card)
|
||||||
|
- [ ] Trash discards the unfinished job
|
||||||
|
- [ ] Download finishes: toast "Map: Done, N new tiles", new tiles appear on the map
|
||||||
|
|
||||||
|
## Overzoom (map past the downloaded detail)
|
||||||
|
- [ ] Zoom in beyond the highest downloaded level: map stays visible (magnified), zoom pill reads e.g. "z17 (map z15)"
|
||||||
|
- [ ] Panning over magnified tiles is smooth enough (note if it stutters)
|
||||||
|
- [ ] From a magnified view, download a higher zoom for that area — the sharp tiles replace the magnified ones
|
||||||
|
|
||||||
|
## GPS
|
||||||
|
- [ ] Settings > Navigation shows a "GPS" switch; toggling it turns the module on/off (and survives a reboot)
|
||||||
|
- [ ] Status bar: GPS icon grey while searching, green with a fix, gone when off
|
||||||
|
- [ ] Map crosshair with GPS off: turns GPS on ("GPS on, waiting for a fix"), centres once a fix arrives
|
||||||
|
- [ ] Bot `!gps on` / `!gps off` works on L2
|
||||||
|
|
||||||
|
## Two maps
|
||||||
|
- [ ] Nodes map (Nearby > map icon): contacts with a position as markers, tap → node detail, back → map
|
||||||
|
- [ ] Map: hold the map → "This spot" → Add waypoint → "WPn" at the finger
|
||||||
|
- [ ] Map: pin button → Waypoints → Here (GPS) → waypoint at the GPS position
|
||||||
|
- [ ] Bar (bottom) → "Navigate to" list: waypoints with distance, Trail start (if a trail exists), people sharing live
|
||||||
|
- [ ] Tap a waypoint → target: ring, dashed line from you, bar with distance / bearing / your course / ETA; view frames you + target
|
||||||
|
- [ ] ✕ on the bar clears the target
|
||||||
|
- [ ] Waypoint menu (pencil): Go / Name (Polish letters, 11-byte limit) / Share / Delete (second tap confirms)
|
||||||
|
- [ ] Share → Messages → pick a conversation → compose holds `[WAY]lat,lon name` → send; a Solo L1 receiving it can save it
|
||||||
|
- [ ] Settings > Trail, live share, alerts > "Show others' positions" on → someone's `[LOC]` share appears on the Map and in the list; tap → navigate to them
|
||||||
|
- [ ] Node detail (a node with a position) has the compass button → Map with that node as target
|
||||||
|
- [ ] Settings > … > "Arrival alert" on + target set → toast "Arrived: …" when you get within the radius
|
||||||
|
|
||||||
|
## Positions in messages
|
||||||
|
- [ ] A received message with `[WAY]lat,lon name`, `[LOC]lat,lon` or plain "lat, lon" shows Go / Save under the bubble
|
||||||
|
- [ ] Save → waypoint named from the [WAY] label (else the sender), Polish letters not cut in half
|
||||||
|
- [ ] Go → Map with that spot as the target
|
||||||
|
|
||||||
|
## Trail & live share (Map > ☰ tools button, left column)
|
||||||
|
- [ ] Record → pill "REC 0 m" at the top; walk: blue trail line follows, distance grows
|
||||||
|
- [ ] Auto-pause (Settings > Trail, live share, alerts): standing still → "PAUSED", walking resumes
|
||||||
|
- [ ] Stop / Save / Load / Reset (second tap confirms) behave; a trail saved on L2 loads (same /trail file as L1)
|
||||||
|
- [ ] Export GPX → toast "Saved trails/trail-YYYYMMDD-HHMM.gpx"; the file opens in a GPX viewer (track + waypoints)
|
||||||
|
- [ ] Live share: pick "Send to" (channel or favourite), Share live → pill "LIVE 1h00"; another node sees the [LOC] updates while you move; stops by itself after the chosen time
|
||||||
|
- [ ] Send once: with sharing on → "Position sent"; with it off → Messages with `[LOC]lat,lon` waiting in the compose field
|
||||||
|
- [ ] Track back (with a recorded trail): bar "Back: n pt" with distance / bearing, ring on the breadcrumb; walking advances it; at the start toast "Back at the trail start"; ✕ stops it
|
||||||
|
- [ ] ☰ > Download this area opens the download popup
|
||||||
|
- [ ] Waypoint averaging 5 s/10 s/30 s: pin → "Averaging GPS… n s" pill (tap cancels) → waypoint saved at the mean
|
||||||
|
|
||||||
|
## Settings > Trail, live share, alerts (schema-driven)
|
||||||
|
- [ ] Every row changes and survives a reboot; "Imperial units" relabels point spacing and distances
|
||||||
|
- [ ] Changing "Stop sharing after" during a session restarts its clock
|
||||||
|
- [ ] Radius / Alert on (arrive, leave, both) change when the arrival toast fires
|
||||||
|
|
||||||
|
## Same data on L1 (ui-new) after the Core changes
|
||||||
|
- [ ] L1: waypoints saved before the update are still listed (Tools › Trail › Waypoints)
|
||||||
|
- [ ] L1: add / rename / delete waypoint, navigate, ETA line still shows
|
||||||
|
- [ ] L1: Home GPS toggle still works
|
||||||
|
- [ ] L1: Tools › Trail Save / Load / Reset still work (now via TrailEngine)
|
||||||
|
- [ ] L1: Mark with averaging (Trail › Settings › Mark avg) still counts down and marks
|
||||||
|
- [ ] L1: Track back still advances along the trail and ends at the start
|
||||||
@@ -29,18 +29,18 @@ interleaved. Classified:
|
|||||||
|
|
||||||
**Models — already UI-free, move as-is**
|
**Models — already UI-free, move as-is**
|
||||||
- `MessageHistory.h` — channel (48) / DM (32) rings, unread counters + overflow flags. ✅ moved to `ui-core/`.
|
- `MessageHistory.h` — channel (48) / DM (32) rings, unread counters + overflow flags. ✅ moved to `ui-core/`.
|
||||||
- `Trail.h` / `TrailStore`, waypoints (`WaypointsView` storage half), `ScopeList.h`.
|
- `Trail.h` / `TrailStore`, `ScopeList.h`. Waypoints ✅ `ui-core/WaypointModel.h` (store + `/waypoints` persistence + "delete clears the Locator target"; ui-new's `UITask::waypoints()` forwards to it).
|
||||||
|
|
||||||
**Engines — logic living inside `UITask.cpp` / `UITask.h`**
|
**Engines — logic living inside `UITask.cpp` / `UITask.h`**
|
||||||
- Unread tracking — DM unread table ✅ (`ui-core/DmUnreadTable.h`), room unread (still in `UITask`).
|
- Unread tracking — DM unread table ✅ (`ui-core/DmUnreadTable.h`), room unread (still in `UITask`).
|
||||||
- Notifications ✅ split: the Core decides *what* happened (`MessageArrived` with kind / DM sender / channel slot, `AdvertHeard`); the frontend decides *how* to show it (`showAlert`, `SoundNotifier`, vibration, LED, wake-on-message) — those are platform services.
|
- Notifications ✅ split: the Core decides *what* happened (`MessageArrived` with kind / DM sender / channel slot, `AdvertHeard`); the frontend decides *how* to show it (`showAlert`, `SoundNotifier`, vibration, LED, wake-on-message) — those are platform services.
|
||||||
- Live share ✅ `ui-core/LiveShareEngine.h` — session timer, movement/heartbeat gate, send + scope guard, peers' `LiveTrackStore` + expiry.
|
- Live share ✅ `ui-core/LiveShareEngine.h` — session timer, movement/heartbeat gate, send + scope guard, peers' `LiveTrackStore` + expiry.
|
||||||
- Locator ✅ `ui-core/LocatorEngine.h` — active target, geofence state machine, proximity beeper.
|
- Locator ✅ `ui-core/LocatorEngine.h` — active target, geofence state machine, proximity beeper.
|
||||||
- Trail ✅ `ui-core/TrailEngine.h` — store, sampling, auto-pause, low-battery auto-save.
|
- Trail ✅ `ui-core/TrailEngine.h` — store, sampling, auto-pause, low-battery auto-save, recording actions (start/stop, reset, save/load `/trail`) used by both frontends. GPS averaging for marks ✅ `ui-core/GpsAverager.h`. Track back ✅ `ui-core/TrackBack.h`.
|
||||||
- Course over ground + current position ✅ `ui-core/CourseEngine.h`.
|
- Course over ground + current position ✅ `ui-core/CourseEngine.h`.
|
||||||
- Clock tools — alarm / countdown / ring ✅ `ui-core/ClockEngine.h`.
|
- Clock tools — alarm / countdown / ring ✅ `ui-core/ClockEngine.h`.
|
||||||
- Ping ✅ `ui-core/PingEngine.h` (timeout still decided by `NearbyScreen`).
|
- Ping ✅ `ui-core/PingEngine.h` (timeout still decided by `NearbyScreen`).
|
||||||
- Device controls — GPS on/off, GPIO (`setGpioMode`, bot GPIO), buzzer mode/volume, brightness, radio apply (`applyTxPower`, `applyApc`, `applyRadioParams`, …).
|
- Device controls — GPS on/off ✅ (`UiCore::setGpsEnabled`, used by ui-new's toggle and ui-lvgl's Settings / map crosshair), GPIO (`setGpioMode`, bot GPIO), buzzer mode/volume, brightness, radio apply (`applyTxPower`, `applyApc`, `applyRadioParams`, …).
|
||||||
- Bot hooks — `botSetGPS`, `botBuzz`, `botSetGPIO`, …
|
- Bot hooks — `botSetGPS`, `botBuzz`, `botSetGPIO`, …
|
||||||
|
|
||||||
**Screen-embedded logic (harder to extract)**
|
**Screen-embedded logic (harder to extract)**
|
||||||
@@ -110,6 +110,8 @@ call the same ones, so e.g. "marking a channel read" has one implementation.
|
|||||||
|
|
||||||
### 5. Declarative settings schema
|
### 5. Declarative settings schema
|
||||||
|
|
||||||
|
`ui-core/SettingsSchema.h` holds three pages -- navigation (trail, live share, arrival alert, units), display & power (brightness, screen off, wake on message, battery shutdown, GPS power saving, time zone) and messages & contacts (DM resends, contact expiry, favourites first). An entry is a one-byte index by default, or a `values` table over a 1/2/4-byte field (seconds, millivolts, an hour offset, `{1, 0}` for a field stored inverted); side effects run through `UiCore` (`applyGpsInterval()`, `host()->applyDisplayPrefs()`). ui-lvgl renders each page; ui-new still uses its own screens. Radio settings are not schema rows (preset list, typed frequency, radio side effects): `ui-core/RadioControl.h` applies them (`applyParams`, `applyTxPower`, `applyApc`, presets = built-ins + user slots) for both ui-new's Settings > Radio and ui-lvgl's Radio screen.
|
||||||
|
|
||||||
Replaces the per-item code in `SettingsScreen`:
|
Replaces the per-item code in `SettingsScreen`:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -147,7 +149,7 @@ consumes keys only.
|
|||||||
- Theme tokens (colours, spacing, typography) in one place — the first chance to realise the "Amber Trace" direction in colour.
|
- Theme tokens (colours, spacing, typography) in one place — the first chance to realise the "Amber Trace" direction in colour.
|
||||||
- Fonts ✅ Noto Sans generated by `ui-lvgl/fonts/generate.sh` (lv_font_conv): European Latin (Latin-1, Extended-A/B), Greek, Cyrillic + supplement, typographic punctuation, currency, LVGL symbols; 12/14/16/20 px, clock 40 px digits only. On-screen keyboard (`ui-lvgl/Keyboard.h`), phone-style: one layout per script (Latin QWERTY / Cyrillic ЙЦУКЕН / Greek) chosen by the same `keyboard_main_alphabet` / `keyboard_alt_alphabet` prefs as `ui-new` (globe key switches), hold a key for its variants; compose limit counted in UTF-8 bytes. Long-press variants and UTF-8 case mapping are shared with `ui-new` in `ui-core/KeyboardData.h`.
|
- Fonts ✅ Noto Sans generated by `ui-lvgl/fonts/generate.sh` (lv_font_conv): European Latin (Latin-1, Extended-A/B), Greek, Cyrillic + supplement, typographic punctuation, currency, LVGL symbols; 12/14/16/20 px, clock 40 px digits only. On-screen keyboard (`ui-lvgl/Keyboard.h`), phone-style: one layout per script (Latin QWERTY / Cyrillic ЙЦУКЕН / Greek) chosen by the same `keyboard_main_alphabet` / `keyboard_alt_alphabet` prefs as `ui-new` (globe key switches), hold a key for its variants; compose limit counted in UTF-8 bytes. Long-press variants and UTF-8 case mapping are shared with `ui-new` in `ui-core/KeyboardData.h`.
|
||||||
- Simulator ✅: `SIM_UI=lvgl variants/sim/build_wasm.sh` builds the same `ui-lvgl` code for the browser (`SimLcdDisplay` in `variants/sim/SimDisplayDriver.h` blits LVGL's RGB565 flush to a 320×240 canvas; the `SIM_PLATFORM` branch of `ui-lvgl/LvglPort.h` feeds the mouse in as touch). LVGL comes from the L2 env's PlatformIO libdeps; its objects are cached in `web/build/obj_lvgl/`. `web/lvgl.html` runs it next to a `ui-new` peer on a direct link (buttons: advert, peer DM, peer → Public, the board button) and exposes `window.sim` (`tap`, `hold`, `touch`, `peerDM`, `peerChannel`) for headless checks.
|
- Simulator ✅: `SIM_UI=lvgl variants/sim/build_wasm.sh` builds the same `ui-lvgl` code for the browser (`SimLcdDisplay` in `variants/sim/SimDisplayDriver.h` blits LVGL's RGB565 flush to a 320×240 canvas; the `SIM_PLATFORM` branch of `ui-lvgl/LvglPort.h` feeds the mouse in as touch). LVGL comes from the L2 env's PlatformIO libdeps; its objects are cached in `web/build/obj_lvgl/`. `web/lvgl.html` runs it next to a `ui-new` peer on a direct link (buttons: advert, peer DM, peer → Public, the board button) and exposes `window.sim` (`tap`, `hold`, `touch`, `peerDM`, `peerChannel`) for headless checks.
|
||||||
- Map (in progress): offline Web-Mercator raster tiles on the microSD (`/maps/{z}/{x}/{y}.png`, the Meshtastic MUI layout; optional per-column `.pak` from PR #3381's packer), SDMMC 1-bit mount in `LvglPort.h`. `ui-lvgl/map/TileProvider.h` is the swap point: the screen and `map/TileCache.h` (12 decoded RGB565 tiles in PSRAM, LRU) only call `renderTile(z, x, y, rgb565)`, so a vector renderer can replace the PNG provider later. `MapScreen.h`: pan by drag, +/-, re-centre/follow GPS, Nearby nodes with a position as markers (tap = node detail), one tile decoded per loop pass. `maps/attribution.txt` is shown on the map. Planned split (user, 2026-09-25): a Nodes map (every contact with a position) and a separate Navigation map (waypoints + live shares only, for walking to a target). Tiles come from `tools/maps/fetch_tiles.py` (no default server: tile.openstreetmap.org blocks offline use) or on the device: the map's download button fetches the visible area (a few overview levels up to a chosen zoom) over WiFi (`map/TileDownloader.h`; skips tiles on the card, rejects non-PNG and placeholder answers; server from `maps/source.txt`, default OpenTopoMap). The HTTP GET runs on a worker task (`LvglPort.h`, keep-alive TLS); WiFi credentials (Settings > WiFi, with scan) live in NVS, and WiFi is on only during a download. Internal RAM is the constraint (Arduino-ESP32 2.0.17 / IDF 4.4: task stacks and, by default, mbedTLS buffers must be internal): with WiFi + Bluedroid up only ~13 KB was left, so the L2 LVGL env sets `MESH_IN_PSRAM` (`the_mesh`, ~120 KB, placement-new into PSRAM in `main.cpp`) and the fetch task points mbedTLS at PSRAM. The download popup shows IP, RSSI, free/largest internal heap and the last TLS/HTTP error. Arduino-ESP32 3.x (IDF 5: PSRAM stacks, NimBLE) is to be evaluated in the polishing phase. In the simulator the same code downloads through emscripten fetch.
|
- Map (in progress): offline Web-Mercator raster tiles on the microSD (`/maps/{z}/{x}/{y}.png`, the Meshtastic MUI layout; optional per-column `.pak` from PR #3381's packer), SDMMC 1-bit mount in `LvglPort.h`. `ui-lvgl/map/TileProvider.h` is the swap point: the screen and `map/TileCache.h` (24 decoded RGB565 tiles in PSRAM, LRU) only call `renderTile(z, x, y, rgb565)`, so a vector renderer can replace the PNG provider later. `MapScreen.h`: pan by drag, +/-, re-centre/follow GPS, Nearby nodes with a position as markers (tap = node detail), one tile decoded per loop pass, never during a drag (the view fills in once the finger rests; an idle map decodes the ring around the view ahead, and a not-yet-decoded tile shows a cached coarser one meanwhile). `maps/attribution.txt` is behind a "©" on the map and in Settings > About. Two maps over the same tile view: Nearby's header opens the Nodes map (every node Nearby knows a position for), Home > Map the Navigation map (`NavMap.h`): saved waypoints, live shares, the recorded trail and the Locator target with a dashed line to it and a bar with distance / bearing / own course / ETA (`ui-core/EtaTracker.h`, shared with ui-new's NavView). Hold the map to drop a waypoint, the pin marks the GPS position; the bar opens the target list and the waypoint menu (go, rename, share as `[WAY]` into a conversation, delete). Node detail has Navigate (target followed by key); a person sharing on a channel is followed by sender name (Locator target kind 2). Settings > Navigation carries the `track_shared_loc` / `locator_enabled` switches ui-new has on its Live share / Locator screens. Tiles come from `tools/maps/fetch_tiles.py` (no default server: tile.openstreetmap.org blocks offline use) or on the device: the map's download button fetches the visible area (a few overview levels up to a chosen zoom) over WiFi (`map/TileDownloader.h`; skips tiles on the card, rejects non-PNG and placeholder answers; server from `maps/source.txt`, default OpenTopoMap). The HTTP GET runs on a worker task (`LvglPort.h`, keep-alive TLS); WiFi credentials (Settings > WiFi, with scan) live in NVS, and WiFi is on only during a download. The job (area + zoom range) stays in `maps/.job` until it completes, so a download cut short by power-off, lost WiFi or Stop is offered for Resume (tiles already on the card are skipped). Past the downloaded detail the map magnifies the nearest coarser tile it has (up to 2 levels -- more is just big pixels; zoom pill shows e.g. `z17 (map z15)`); known-missing tiles are remembered without a pixel buffer. Internal RAM is the constraint (Arduino-ESP32 2.0.17 / IDF 4.4: task stacks and, by default, mbedTLS buffers must be internal): with WiFi + Bluedroid up only ~13 KB was left, so the L2 LVGL env sets `MESH_IN_PSRAM` (`the_mesh`, ~120 KB, placement-new into PSRAM in `main.cpp`) and the fetch task points mbedTLS at PSRAM. The download popup shows IP, RSSI, free/largest internal heap and the last TLS/HTTP error. Arduino-ESP32 3.x (IDF 5: PSRAM stacks, NimBLE) is to be evaluated in the polishing phase. In the simulator the same code downloads through emscripten fetch.
|
||||||
- PR #3381's LVGL UI is a reference for platform glue (flush, GT911, PSRAM pool) only; its screens are not adopted.
|
- PR #3381's LVGL UI is a reference for platform glue (flush, GT911, PSRAM pool) only; its screens are not adopted.
|
||||||
|
|
||||||
## Migration plan
|
## Migration plan
|
||||||
|
|||||||
@@ -0,0 +1,308 @@
|
|||||||
|
#pragma once
|
||||||
|
// Clock tools (Home > Clock): alarm, countdown timer and stopwatch -- ui-new's
|
||||||
|
// Tools > Clock on a touch screen. The alarm (NodePrefs alarm_*) and the
|
||||||
|
// countdown run in the Core's ClockEngine, so they fire on any screen and while
|
||||||
|
// the display sleeps; the stopwatch is view state here, as in ui-new. Whatever
|
||||||
|
// fires brings up a full-screen card with Dismiss (silent: the L2 speaker has
|
||||||
|
// no driver yet).
|
||||||
|
//
|
||||||
|
// Single-TU fragment: included by ui-lvgl/UITask.cpp after NavMap.h.
|
||||||
|
|
||||||
|
namespace clockview {
|
||||||
|
|
||||||
|
enum : uint8_t { TAB_ALARM, TAB_TIMER, TAB_STOPWATCH, TAB_COUNT };
|
||||||
|
enum : uint8_t { ACT_START_STOP, ACT_RESET };
|
||||||
|
|
||||||
|
static uint8_t s_tab = TAB_ALARM;
|
||||||
|
static uint8_t s_timer_h = 0, s_timer_m = 5, s_timer_s = 0; // countdown to start
|
||||||
|
static bool s_sw_running = false;
|
||||||
|
static uint32_t s_sw_start = 0, s_sw_accum = 0;
|
||||||
|
static bool s_shown_running = false; // timer state the screen was built for
|
||||||
|
static lv_obj_t* s_big = nullptr; // timer remaining / stopwatch reading
|
||||||
|
static lv_obj_t* s_go_lbl = nullptr; // Start / Stop
|
||||||
|
static lv_obj_t* s_ring = nullptr; // "Timer done" card on the top layer
|
||||||
|
static lv_obj_t* s_ring_lbl = nullptr;
|
||||||
|
static lv_obj_t* s_alarm_sw = nullptr; // follows a time change (setting it arms the alarm)
|
||||||
|
|
||||||
|
static char s_opts24[24 * 3], s_opts60[60 * 3]; // "00\n01\n..." for the rollers
|
||||||
|
static void buildOptions() {
|
||||||
|
if (s_opts24[0]) return;
|
||||||
|
int o = 0;
|
||||||
|
for (int i = 0; i < 24; i++) o += snprintf(s_opts24 + o, sizeof(s_opts24) - o, i ? "\n%02d" : "%02d", i);
|
||||||
|
o = 0;
|
||||||
|
for (int i = 0; i < 60; i++) o += snprintf(s_opts60 + o, sizeof(s_opts60) - o, i ? "\n%02d" : "%02d", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t swElapsed() { return s_sw_accum + (s_sw_running ? millis() - s_sw_start : 0); }
|
||||||
|
|
||||||
|
// Countdown: rounds up, so "00:01" shows until it actually fires.
|
||||||
|
static void fmtRemaining(char* b, int n, uint32_t ms) {
|
||||||
|
uint32_t t = (ms + 999) / 1000;
|
||||||
|
if (t >= 3600) snprintf(b, n, "%lu:%02lu:%02lu", (unsigned long)(t / 3600), (unsigned long)(t / 60 % 60), (unsigned long)(t % 60));
|
||||||
|
else snprintf(b, n, "%02lu:%02lu", (unsigned long)(t / 60), (unsigned long)(t % 60));
|
||||||
|
}
|
||||||
|
static void fmtStopwatch(char* b, int n, uint32_t ms) {
|
||||||
|
uint32_t t = ms / 1000;
|
||||||
|
if (t >= 3600) snprintf(b, n, "%lu:%02lu:%02lu", (unsigned long)(t / 3600), (unsigned long)(t / 60 % 60), (unsigned long)(t % 60));
|
||||||
|
else snprintf(b, n, "%02lu:%02lu.%lu", (unsigned long)(t / 60), (unsigned long)(t % 60), (unsigned long)(ms / 100 % 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
static lv_obj_t* roller(lv_obj_t* parent, const char* opts, int sel, lv_event_cb_t cb, uintptr_t which) {
|
||||||
|
lv_obj_t* r = lv_roller_create(parent);
|
||||||
|
lv_roller_set_options(r, opts, LV_ROLLER_MODE_INFINITE);
|
||||||
|
lv_roller_set_selected(r, sel, LV_ANIM_OFF);
|
||||||
|
lv_obj_set_size(r, 60, 84); // three rows; leaves room for the button below
|
||||||
|
lv_obj_set_style_text_font(r, THEME_FONT_TITLE, 0);
|
||||||
|
lv_obj_set_style_text_font(r, THEME_FONT_LARGE, LV_PART_SELECTED);
|
||||||
|
lv_obj_set_style_text_line_space(r, 4, 0);
|
||||||
|
lv_obj_set_style_text_color(r, lv_color_hex(theme::TEXT_MUTED), 0);
|
||||||
|
lv_obj_set_style_bg_color(r, lv_color_hex(theme::SURFACE), 0);
|
||||||
|
lv_obj_set_style_border_width(r, 0, 0);
|
||||||
|
lv_obj_set_style_bg_color(r, lv_color_hex(theme::SURFACE_2), LV_PART_SELECTED);
|
||||||
|
lv_obj_set_style_text_color(r, lv_color_hex(theme::ACCENT), LV_PART_SELECTED);
|
||||||
|
lv_obj_add_event_cb(r, cb, LV_EVENT_VALUE_CHANGED, (void*)which);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static lv_obj_t* colon(lv_obj_t* parent) { return label(parent, ":", THEME_FONT_LARGE, theme::TEXT_MUTED); }
|
||||||
|
|
||||||
|
static lv_obj_t* row(lv_obj_t* parent) {
|
||||||
|
lv_obj_t* r = lv_obj_create(parent);
|
||||||
|
styleSurface(r, theme::BG);
|
||||||
|
lv_obj_remove_flag(r, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_set_size(r, LV_PCT(100), LV_SIZE_CONTENT);
|
||||||
|
lv_obj_set_flex_flow(r, LV_FLEX_FLOW_ROW);
|
||||||
|
lv_obj_set_flex_align(r, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
|
lv_obj_set_style_pad_column(r, theme::GAP, 0);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace clockview
|
||||||
|
|
||||||
|
static void onOpenClock(lv_event_t* e) { (void)e; s_ui->showClock(); }
|
||||||
|
static void onClockTab(lv_event_t* e) { s_ui->clockTab((int)(uintptr_t)lv_event_get_user_data(e)); }
|
||||||
|
static void onClockAct(lv_event_t* e) { s_ui->clockAction((uint8_t)(uintptr_t)lv_event_get_user_data(e)); }
|
||||||
|
static void onRingDismiss(lv_event_t* e) { (void)e; s_ui->dismissRing(); }
|
||||||
|
|
||||||
|
// Alarm: hour / minute rollers, on switch, repeat. Saved on every change.
|
||||||
|
static void onAlarmRoller(lv_event_t* e) {
|
||||||
|
s_ui->setAlarm((int)(uintptr_t)lv_event_get_user_data(e), (int)lv_roller_get_selected((lv_obj_t*)lv_event_get_target(e)));
|
||||||
|
}
|
||||||
|
static void onAlarmSwitch(lv_event_t* e) {
|
||||||
|
s_ui->setAlarm(2, lv_obj_has_state((lv_obj_t*)lv_event_get_target(e), LV_STATE_CHECKED) ? 1 : 0);
|
||||||
|
}
|
||||||
|
static void onAlarmRepeat(lv_event_t* e) {
|
||||||
|
s_ui->setAlarm(3, (int)lv_dropdown_get_selected((lv_obj_t*)lv_event_get_target(e)));
|
||||||
|
}
|
||||||
|
static void onTimerRoller(lv_event_t* e) {
|
||||||
|
int v = (int)lv_roller_get_selected((lv_obj_t*)lv_event_get_target(e));
|
||||||
|
switch ((uintptr_t)lv_event_get_user_data(e)) {
|
||||||
|
case 0: clockview::s_timer_h = (uint8_t)v; break;
|
||||||
|
case 1: clockview::s_timer_m = (uint8_t)v; break;
|
||||||
|
default: clockview::s_timer_s = (uint8_t)v; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::showClock() {
|
||||||
|
_screen = SCR_CLOCK;
|
||||||
|
buildClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::clockTab(int tab) {
|
||||||
|
if (tab < 0 || tab >= clockview::TAB_COUNT) return;
|
||||||
|
clockview::s_tab = (uint8_t)tab;
|
||||||
|
buildClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::buildClock() {
|
||||||
|
using namespace clockview;
|
||||||
|
buildOptions();
|
||||||
|
lv_obj_t* body = newScreen("Clock", true);
|
||||||
|
lv_obj_set_style_pad_row(body, 6, 0);
|
||||||
|
lv_obj_remove_flag(body, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
s_big = s_go_lbl = s_alarm_sw = nullptr;
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
lv_obj_t* tabs = row(body);
|
||||||
|
static const char* const NAMES[TAB_COUNT] = { LV_SYMBOL_BELL " Alarm", UI_SYMBOL_CLOCK " Timer",
|
||||||
|
UI_SYMBOL_STOPWATCH " Stopwatch" };
|
||||||
|
for (int t = 0; t < TAB_COUNT; t++) {
|
||||||
|
lv_obj_t* b = lv_button_create(tabs);
|
||||||
|
lv_obj_set_height(b, 32);
|
||||||
|
lv_obj_set_flex_grow(b, 1);
|
||||||
|
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||||
|
lv_obj_set_style_radius(b, theme::RADIUS, 0);
|
||||||
|
lv_obj_set_style_bg_color(b, lv_color_hex(t == s_tab ? theme::ACCENT_DIM : theme::SURFACE), 0);
|
||||||
|
lv_obj_add_event_cb(b, onClockTab, LV_EVENT_CLICKED, (void*)(uintptr_t)t);
|
||||||
|
lv_obj_center(label(b, NAMES[t], THEME_FONT_SMALL, theme::TEXT));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_tab == TAB_ALARM) {
|
||||||
|
lv_obj_t* r = row(body);
|
||||||
|
roller(r, s_opts24, _prefs->alarm_hour % 24, onAlarmRoller, 0);
|
||||||
|
colon(r);
|
||||||
|
roller(r, s_opts60, _prefs->alarm_min % 60, onAlarmRoller, 1);
|
||||||
|
lv_obj_t* col = lv_obj_create(r);
|
||||||
|
styleSurface(col, theme::BG);
|
||||||
|
lv_obj_remove_flag(col, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_set_size(col, 120, LV_SIZE_CONTENT);
|
||||||
|
lv_obj_set_flex_flow(col, LV_FLEX_FLOW_COLUMN);
|
||||||
|
lv_obj_set_flex_align(col, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
|
||||||
|
lv_obj_set_style_pad_row(col, 6, 0);
|
||||||
|
lv_obj_set_style_pad_left(col, 8, 0);
|
||||||
|
label(col, "Alarm on", THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
lv_obj_t* sw = s_alarm_sw = lv_switch_create(col);
|
||||||
|
lv_obj_set_size(sw, 50, 26);
|
||||||
|
if (_prefs->alarm_on) lv_obj_add_state(sw, LV_STATE_CHECKED);
|
||||||
|
lv_obj_add_event_cb(sw, onAlarmSwitch, LV_EVENT_VALUE_CHANGED, NULL);
|
||||||
|
label(col, "Repeat", THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
lv_obj_t* dd = lv_dropdown_create(col);
|
||||||
|
char opts[48];
|
||||||
|
int o = 0;
|
||||||
|
for (uint8_t i = 0; i < NodePrefs::ALARM_REPEAT_COUNT; i++)
|
||||||
|
o += snprintf(opts + o, sizeof(opts) - o, "%s%s", i ? "\n" : "", i ? NodePrefs::alarmRepeatLabel(i) : "Once");
|
||||||
|
lv_dropdown_set_options(dd, opts);
|
||||||
|
lv_dropdown_set_selected(dd, NodePrefs::alarmRepeatIdxForMask(_prefs->alarm_repeat_mask));
|
||||||
|
lv_obj_set_width(dd, 112);
|
||||||
|
lv_obj_add_event_cb(dd, onAlarmRepeat, LV_EVENT_VALUE_CHANGED, NULL);
|
||||||
|
bool synced = rtc_clock.getCurrentTime() > 1000000000UL;
|
||||||
|
label(body, synced ? "Rings at this local time (Settings time zone)." : "The clock isn't set yet: the alarm waits for a time sync.",
|
||||||
|
THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_tab == TAB_TIMER) {
|
||||||
|
s_shown_running = _core->clock.isTimerRunning();
|
||||||
|
if (s_shown_running) {
|
||||||
|
s_big = label(body, "", THEME_FONT_CLOCK, theme::TEXT);
|
||||||
|
lv_obj_set_width(s_big, LV_PCT(100));
|
||||||
|
lv_obj_set_style_text_align(s_big, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
|
lv_obj_set_style_pad_ver(s_big, 18, 0);
|
||||||
|
} else {
|
||||||
|
lv_obj_t* r = row(body);
|
||||||
|
roller(r, s_opts24, s_timer_h, onTimerRoller, 0);
|
||||||
|
colon(r);
|
||||||
|
roller(r, s_opts60, s_timer_m, onTimerRoller, 1);
|
||||||
|
colon(r);
|
||||||
|
roller(r, s_opts60, s_timer_s, onTimerRoller, 2);
|
||||||
|
}
|
||||||
|
} else { // stopwatch
|
||||||
|
s_big = label(body, "", THEME_FONT_CLOCK, theme::TEXT);
|
||||||
|
lv_obj_set_width(s_big, LV_PCT(100));
|
||||||
|
lv_obj_set_style_text_align(s_big, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
|
lv_obj_set_style_pad_ver(s_big, 18, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_t* acts = row(body);
|
||||||
|
lv_obj_t* go = lv_button_create(acts);
|
||||||
|
lv_obj_set_size(go, 150, 40);
|
||||||
|
lv_obj_set_style_shadow_width(go, 0, 0);
|
||||||
|
lv_obj_set_style_radius(go, theme::RADIUS, 0);
|
||||||
|
lv_obj_set_style_bg_color(go, lv_color_hex(theme::ACCENT_DIM), 0);
|
||||||
|
lv_obj_add_event_cb(go, onClockAct, LV_EVENT_CLICKED, (void*)(uintptr_t)ACT_START_STOP);
|
||||||
|
s_go_lbl = label(go, "", THEME_FONT_BODY, theme::TEXT);
|
||||||
|
lv_obj_center(s_go_lbl);
|
||||||
|
if (s_tab == TAB_STOPWATCH) {
|
||||||
|
lv_obj_t* rs = lv_button_create(acts);
|
||||||
|
lv_obj_set_size(rs, 100, 40);
|
||||||
|
lv_obj_set_style_shadow_width(rs, 0, 0);
|
||||||
|
lv_obj_set_style_radius(rs, theme::RADIUS, 0);
|
||||||
|
lv_obj_set_style_bg_color(rs, lv_color_hex(theme::SURFACE), 0);
|
||||||
|
lv_obj_add_event_cb(rs, onClockAct, LV_EVENT_CLICKED, (void*)(uintptr_t)ACT_RESET);
|
||||||
|
lv_obj_center(label(rs, LV_SYMBOL_REFRESH " Reset", THEME_FONT_BODY, theme::TEXT));
|
||||||
|
}
|
||||||
|
refreshClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// From loop() while SCR_CLOCK is shown: the running readouts.
|
||||||
|
void UITask::refreshClock() {
|
||||||
|
using namespace clockview;
|
||||||
|
if (s_tab == TAB_TIMER) {
|
||||||
|
bool running = _core->clock.isTimerRunning();
|
||||||
|
if (running != s_shown_running) { buildClock(); return; } // started elsewhere / just fired
|
||||||
|
if (s_big) {
|
||||||
|
char b[16];
|
||||||
|
fmtRemaining(b, sizeof(b), _core->clock.timerRemainingMs());
|
||||||
|
lv_label_set_text(s_big, b);
|
||||||
|
}
|
||||||
|
if (s_go_lbl) lv_label_set_text(s_go_lbl, running ? LV_SYMBOL_STOP " Stop" : LV_SYMBOL_PLAY " Start");
|
||||||
|
} else if (s_tab == TAB_STOPWATCH) {
|
||||||
|
if (s_big) {
|
||||||
|
char b[16];
|
||||||
|
fmtStopwatch(b, sizeof(b), swElapsed());
|
||||||
|
lv_label_set_text(s_big, b);
|
||||||
|
}
|
||||||
|
if (s_go_lbl) lv_label_set_text(s_go_lbl, s_sw_running ? LV_SYMBOL_PAUSE " Stop" : LV_SYMBOL_PLAY " Start");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::clockAction(uint8_t act) {
|
||||||
|
using namespace clockview;
|
||||||
|
if (s_tab == TAB_TIMER) {
|
||||||
|
if (_core->clock.isTimerRunning()) _core->clock.stopTimer();
|
||||||
|
else {
|
||||||
|
uint32_t ms = ((uint32_t)s_timer_h * 3600 + s_timer_m * 60 + s_timer_s) * 1000UL;
|
||||||
|
if (ms == 0) { showToast("Set a time first"); return; }
|
||||||
|
_core->clock.startTimer(ms);
|
||||||
|
}
|
||||||
|
buildClock();
|
||||||
|
} else if (s_tab == TAB_STOPWATCH) {
|
||||||
|
if (act == ACT_RESET) { s_sw_accum = 0; s_sw_start = millis(); }
|
||||||
|
else if (s_sw_running) { s_sw_accum += millis() - s_sw_start; s_sw_running = false; }
|
||||||
|
else { s_sw_start = millis(); s_sw_running = true; }
|
||||||
|
refreshClock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// which: 0 hour, 1 minute, 2 on/off, 3 repeat preset.
|
||||||
|
void UITask::setAlarm(int which, int v) {
|
||||||
|
if (!_prefs) return;
|
||||||
|
switch (which) {
|
||||||
|
case 0: _prefs->alarm_hour = (uint8_t)v; _prefs->alarm_on = 1; break; // setting a time arms it
|
||||||
|
case 1: _prefs->alarm_min = (uint8_t)v; _prefs->alarm_on = 1; break;
|
||||||
|
case 2: _prefs->alarm_on = (uint8_t)v; break;
|
||||||
|
case 3: _prefs->alarm_repeat_mask = NodePrefs::alarmRepeatMaskForIdx((uint8_t)v); break;
|
||||||
|
}
|
||||||
|
_core->clock.onAlarmChanged();
|
||||||
|
the_mesh.savePrefs();
|
||||||
|
if (which < 2 && clockview::s_alarm_sw) lv_obj_add_state(clockview::s_alarm_sw, LV_STATE_CHECKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Ring card (any screen) ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
void UITask::showRing(const char* text) {
|
||||||
|
using namespace clockview;
|
||||||
|
wake();
|
||||||
|
if (!s_ring) {
|
||||||
|
s_ring = lv_obj_create(lv_layer_top());
|
||||||
|
lv_obj_remove_style_all(s_ring);
|
||||||
|
lv_obj_set_size(s_ring, LV_PCT(100), LV_PCT(100));
|
||||||
|
lv_obj_set_style_bg_color(s_ring, lv_color_hex(theme::BG), 0);
|
||||||
|
lv_obj_set_style_bg_opa(s_ring, LV_OPA_COVER, 0);
|
||||||
|
lv_obj_add_flag(s_ring, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_set_flex_flow(s_ring, LV_FLEX_FLOW_COLUMN);
|
||||||
|
lv_obj_set_flex_align(s_ring, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
|
lv_obj_set_style_pad_row(s_ring, 14, 0);
|
||||||
|
label(s_ring, LV_SYMBOL_BELL, THEME_FONT_LARGE, theme::ACCENT);
|
||||||
|
s_ring_lbl = label(s_ring, "", THEME_FONT_LARGE, theme::TEXT);
|
||||||
|
lv_obj_t* b = lv_button_create(s_ring);
|
||||||
|
lv_obj_set_size(b, 200, 56);
|
||||||
|
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||||
|
lv_obj_set_style_radius(b, theme::RADIUS, 0);
|
||||||
|
lv_obj_set_style_bg_color(b, lv_color_hex(theme::ACCENT_DIM), 0);
|
||||||
|
lv_obj_add_event_cb(b, onRingDismiss, LV_EVENT_CLICKED, NULL);
|
||||||
|
lv_obj_center(label(b, "Dismiss", THEME_FONT_LARGE, theme::TEXT));
|
||||||
|
}
|
||||||
|
lv_label_set_text(s_ring_lbl, text);
|
||||||
|
lv_obj_remove_flag(s_ring, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::dismissRing() {
|
||||||
|
_core->clock.dismissRing();
|
||||||
|
hideRing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::hideRing() {
|
||||||
|
if (clockview::s_ring) lv_obj_add_flag(clockview::s_ring, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
if (_screen == SCR_CLOCK) buildClock(); // e.g. the timer's Start again
|
||||||
|
}
|
||||||
@@ -87,6 +87,12 @@ static bool touched() {
|
|||||||
|
|
||||||
static void swallowTouch() { s_swallow = true; }
|
static void swallowTouch() { s_swallow = true; }
|
||||||
|
|
||||||
|
// Backlight 1-100 % (the brightness slider), on the LP5814 PWM.
|
||||||
|
static void setBacklightPct(uint8_t pct) {
|
||||||
|
if (pct > 100) pct = 100;
|
||||||
|
s_gfx->setBrightness((uint8_t)(8 + (uint16_t)pct * 247 / 100)); // never fully dark
|
||||||
|
}
|
||||||
|
|
||||||
// microSD over SDMMC, 1-bit (CLK 2, CMD 3, D0 1); its power rail (expander
|
// microSD over SDMMC, 1-bit (CLK 2, CMD 3, D0 1); its power rail (expander
|
||||||
// P14) is switched on in WioTrackerL2Board::begin(). Retried on every call
|
// P14) is switched on in WioTrackerL2Board::begin(). Retried on every call
|
||||||
// until it works, so a card inserted later is picked up the next time.
|
// until it works, so a card inserted later is picked up the next time.
|
||||||
@@ -328,6 +334,7 @@ static bool begin() {
|
|||||||
|
|
||||||
static bool touched() { return SimLcdDisplay::touchState().down; }
|
static bool touched() { return SimLcdDisplay::touchState().down; }
|
||||||
static void swallowTouch() { s_swallow = true; }
|
static void swallowTouch() { s_swallow = true; }
|
||||||
|
static void setBacklightPct(uint8_t pct) { (void)pct; } // the browser canvas has no backlight
|
||||||
|
|
||||||
// The host page preloads map tiles into the in-memory FS under /sdcard/maps.
|
// The host page preloads map tiles into the in-memory FS under /sdcard/maps.
|
||||||
static bool mountStorage() { return true; }
|
static bool mountStorage() { return true; }
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
// Map screen: offline Web-Mercator tiles from the card (map/TileProvider.h,
|
// Map screen: offline Web-Mercator tiles from the card (map/TileProvider.h,
|
||||||
// cached by map/TileCache.h) under own position and the nodes Nearby knows a
|
// cached by map/TileCache.h) under own position. Two modes over the same tile
|
||||||
// position for. Drag to pan, +/- to zoom, the crosshair re-centres and
|
// view: the Navigation map (Home > Map, NavMap.h) shows waypoints, live
|
||||||
// follows the GPS again; tap a marker for its node detail. The download
|
// shares, the trail and the active target; the Nodes map (Nearby > map
|
||||||
// button fetches the visible area over WiFi (map/TileDownloader.h).
|
// button) marks every node Nearby knows a position for, tap one for its
|
||||||
|
// detail. Drag to pan, +/- to zoom, the crosshair re-centres and follows the
|
||||||
|
// GPS again. The download button fetches the visible area over WiFi
|
||||||
|
// (map/TileDownloader.h).
|
||||||
//
|
//
|
||||||
// Tiles decode one per loop pass (a PNG takes tens of ms), so panning stays
|
// Tiles decode one per loop pass (a PNG takes tens of ms), never while a drag
|
||||||
// responsive and the radio keeps being serviced while a view fills in.
|
// is moving the map, so panning stays smooth and the radio keeps being
|
||||||
|
// serviced; an idle map decodes the tiles around the view ahead of time.
|
||||||
//
|
//
|
||||||
// Single-TU fragment: included by ui-lvgl/UITask.cpp after the Nearby section.
|
// Single-TU fragment: included by ui-lvgl/UITask.cpp after the Nearby section.
|
||||||
|
|
||||||
@@ -36,15 +40,89 @@ static double latToTileY(double lat, int z) {
|
|||||||
return (1.0 - asinh(tan(r)) / M_PI) / 2.0 * (double)(1 << z);
|
return (1.0 - asinh(tan(r)) / M_PI) / 2.0 * (double)(1 << z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Markers: one per positioned Nearby row, remembered so layout can reposition them.
|
// Markers, remembered so layout can reposition them. `idx` is the Nearby row
|
||||||
struct Mark { int32_t lat_e6, lon_e6; int row; lv_obj_t* obj; };
|
// (MK_NODE), the waypoint index (MK_WAYPOINT) or the live-share slot (MK_LIVE).
|
||||||
static Mark s_marks[NearbyModel::MAX_NEARBY];
|
enum : uint8_t { MK_NODE, MK_WAYPOINT, MK_LIVE };
|
||||||
|
struct Mark { int32_t lat_e6, lon_e6; int idx; uint8_t kind; lv_obj_t* obj; lv_obj_t* dot; };
|
||||||
|
static const int MAX_MARKS = 48; // >= MAX_NEARBY, and >= waypoints + live shares
|
||||||
|
static Mark s_marks[MAX_MARKS];
|
||||||
static int s_mark_count = 0;
|
static int s_mark_count = 0;
|
||||||
static int s_drag = 0; // px moved in the current press: a drag isn't a tap
|
static int s_drag = 0; // px moved in the current press: a drag isn't a tap
|
||||||
static bool s_available = false; // provider has data; checked when the map opens, not per frame
|
static bool s_available = false; // provider has data; checked when the map opens, not per frame
|
||||||
|
static double s_left = 0, s_top = 0; // world px (at the current zoom) of the view's top-left
|
||||||
|
static lv_obj_t* s_cells[GRID_COLS * GRID_ROWS]; // clip each grid tile (a magnified parent overflows)
|
||||||
|
|
||||||
|
// Overzoom: a tile the card doesn't have at this zoom is drawn as the matching
|
||||||
|
// part of the nearest coarser tile it does have, magnified -- so the map stays
|
||||||
|
// usable a little past the downloaded detail. Only two levels (x4): beyond
|
||||||
|
// that a raster tile is just big pixels, and the map says to download more.
|
||||||
|
// Returns that tile (k = levels up) or nullptr; want_z/x/y is the nearest
|
||||||
|
// coarser tile not looked up yet (decode it next), want_z = -1 if none.
|
||||||
|
static const int OVERZOOM = 2;
|
||||||
|
static TileCache::Slot* ancestorFor(int z, int x, int y, int& k, int& want_z, int& want_x, int& want_y) {
|
||||||
|
want_z = -1;
|
||||||
|
for (int d = 1; d <= OVERZOOM && z - d >= 0; d++) {
|
||||||
|
int ax = x >> d, ay = y >> d;
|
||||||
|
TileCache::Slot* s = s_cache.find(z - d, ax, ay);
|
||||||
|
if (!s) { want_z = z - d; want_x = ax; want_y = ay; return nullptr; }
|
||||||
|
if (s->present) { k = d; return s; }
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stand-in while z/x/y hasn't been decoded yet: a coarser tile already in the
|
||||||
|
// cache (typically the view you just zoomed in from), so a newly revealed part
|
||||||
|
// of the map shows something at once instead of a blank. Never decodes.
|
||||||
|
static TileCache::Slot* cachedAncestor(int z, int x, int y, int& k) {
|
||||||
|
for (int d = 1; d <= 3 && z - d >= 0; d++) {
|
||||||
|
TileCache::Slot* s = s_cache.find(z - d, x >> d, y >> d);
|
||||||
|
if (s && s->present) { k = d; return s; }
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decoding a tile holds the loop for tens of ms, which makes a drag stutter.
|
||||||
|
// So nothing is decoded while the finger is moving the map; the view fills in
|
||||||
|
// once it rests, and when idle the ring of tiles around the view is decoded
|
||||||
|
// ahead of the next pan.
|
||||||
|
static uint32_t s_last_pan_ms = 0;
|
||||||
|
static const uint32_t PAN_SETTLE_MS = 150, PREFETCH_IDLE_MS = 400;
|
||||||
|
|
||||||
|
// Idle read-ahead: decode the nearest not-yet-looked-up tile in the ring just
|
||||||
|
// outside the view (one per call). False when the ring is complete.
|
||||||
|
static bool prefetchOne(double left, double top, int w, int h, int z) {
|
||||||
|
int tx0 = (int)floor(left / TILE_PX), ty0 = (int)floor(top / TILE_PX);
|
||||||
|
int n = 1 << z;
|
||||||
|
int bx = 0, by = 0;
|
||||||
|
double best = 1e18;
|
||||||
|
for (int j = -1; j <= GRID_ROWS; j++) {
|
||||||
|
for (int i = -1; i <= GRID_COLS; i++) {
|
||||||
|
int tx = tx0 + i, ty = ty0 + j;
|
||||||
|
double px = tx * (double)TILE_PX - left, py = ty * (double)TILE_PX - top;
|
||||||
|
if (px < w && py < h && px + TILE_PX > 0 && py + TILE_PX > 0) continue; // on screen: not ours
|
||||||
|
if (ty < 0 || ty >= n) continue;
|
||||||
|
int wx = ((tx % n) + n) % n;
|
||||||
|
if (s_cache.find(z, wx, ty)) continue; // also keeps a decoded neighbour from being evicted
|
||||||
|
double d = fabs(px + TILE_PX / 2 - w / 2.0) + fabs(py + TILE_PX / 2 - h / 2.0);
|
||||||
|
if (d < best) { best = d; bx = wx; by = ty; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best >= 1e18) return false;
|
||||||
|
s_cache.load(*s_provider, z, bx, by);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int MARK_D = 12; // marker dot diameter
|
||||||
|
|
||||||
} // namespace mapview
|
} // namespace mapview
|
||||||
|
|
||||||
|
namespace navmap { // shared with NavMap.h (included after this file)
|
||||||
|
static const int BAR_H = 44; // target bar along the bottom of the Navigation map
|
||||||
|
// Navigation targets as one int (event user data): type << 8 | index.
|
||||||
|
enum : uint8_t { T_CLEAR, T_WAYPOINT, T_TRAILSTART, T_LIVE };
|
||||||
|
static int code(uint8_t type, int idx) { return (type << 8) | (idx & 0xFF); }
|
||||||
|
} // namespace navmap
|
||||||
|
|
||||||
static void onMapPress(lv_event_t* e) {
|
static void onMapPress(lv_event_t* e) {
|
||||||
lv_event_code_t code = lv_event_get_code(e);
|
lv_event_code_t code = lv_event_get_code(e);
|
||||||
if (code == LV_EVENT_PRESSED) { mapview::s_drag = 0; return; }
|
if (code == LV_EVENT_PRESSED) { mapview::s_drag = 0; return; }
|
||||||
@@ -52,8 +130,17 @@ static void onMapPress(lv_event_t* e) {
|
|||||||
lv_indev_get_vect(lv_indev_active(), &v);
|
lv_indev_get_vect(lv_indev_active(), &v);
|
||||||
if (v.x == 0 && v.y == 0) return;
|
if (v.x == 0 && v.y == 0) return;
|
||||||
mapview::s_drag += abs(v.x) + abs(v.y);
|
mapview::s_drag += abs(v.x) + abs(v.y);
|
||||||
|
mapview::s_last_pan_ms = millis();
|
||||||
s_ui->mapPan(v.x, v.y);
|
s_ui->mapPan(v.x, v.y);
|
||||||
}
|
}
|
||||||
|
static void onMapLongPress(lv_event_t* e) {
|
||||||
|
if (mapview::s_drag > 8) return; // held after a pan: not a long-press on a spot
|
||||||
|
lv_point_t p;
|
||||||
|
lv_indev_get_point(lv_indev_active(), &p);
|
||||||
|
lv_area_t a;
|
||||||
|
lv_obj_get_coords((lv_obj_t*)lv_event_get_target(e), &a);
|
||||||
|
s_ui->mapLongPress(p.x - a.x1, p.y - a.y1);
|
||||||
|
}
|
||||||
static void onMapZoomIn(lv_event_t* e) { (void)e; s_ui->mapZoom(+1); }
|
static void onMapZoomIn(lv_event_t* e) { (void)e; s_ui->mapZoom(+1); }
|
||||||
static void onMapZoomOut(lv_event_t* e) { (void)e; s_ui->mapZoom(-1); }
|
static void onMapZoomOut(lv_event_t* e) { (void)e; s_ui->mapZoom(-1); }
|
||||||
static void onMapCenter(lv_event_t* e) { (void)e; s_ui->mapCenterOnMe(); }
|
static void onMapCenter(lv_event_t* e) { (void)e; s_ui->mapCenterOnMe(); }
|
||||||
@@ -63,6 +150,10 @@ static void onDlStart(lv_event_t* e) { (void)e; s_ui->mapDownloadStart(); }
|
|||||||
static void onDlZoomMinus(lv_event_t* e) { (void)e; s_ui->mapDownloadZmax(-1); }
|
static void onDlZoomMinus(lv_event_t* e) { (void)e; s_ui->mapDownloadZmax(-1); }
|
||||||
static void onDlZoomPlus(lv_event_t* e) { (void)e; s_ui->mapDownloadZmax(+1); }
|
static void onDlZoomPlus(lv_event_t* e) { (void)e; s_ui->mapDownloadZmax(+1); }
|
||||||
static void onDlWifi(lv_event_t* e) { (void)e; s_ui->showWifi(true); }
|
static void onDlWifi(lv_event_t* e) { (void)e; s_ui->showWifi(true); }
|
||||||
|
static void onDlResume(lv_event_t* e) { (void)e; s_ui->mapDownloadResume(); }
|
||||||
|
static void onDlDiscard(lv_event_t* e) { (void)e; s_ui->mapDownloadDiscard(); }
|
||||||
|
static void onNavTools(lv_event_t* e); // NavMap.h
|
||||||
|
static void onMapCredits(lv_event_t* e) { (void)e; s_ui->showToast(mapview::s_provider->attribution(), 4000); }
|
||||||
static void onMapMarker(lv_event_t* e) {
|
static void onMapMarker(lv_event_t* e) {
|
||||||
if (mapview::s_drag > 8) return; // the press was a pan that ended on a marker
|
if (mapview::s_drag > 8) return; // the press was a pan that ended on a marker
|
||||||
s_ui->mapOpenMarker((int)(uintptr_t)lv_event_get_user_data(e));
|
s_ui->mapOpenMarker((int)(uintptr_t)lv_event_get_user_data(e));
|
||||||
@@ -93,6 +184,17 @@ static lv_obj_t* mapPill(lv_obj_t* parent, const char* text) {
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Centring on a point puts it mid-way down the visible map: above the nav bar
|
||||||
|
// on the Navigation map (the bias is in tiles, added to the view centre).
|
||||||
|
double UITask::mapCenterBias() const {
|
||||||
|
return _map_nav ? navmap::BAR_H / 2.0 / mapview::TILE_PX : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::openMap(bool nav) {
|
||||||
|
_map_nav = nav;
|
||||||
|
showMap();
|
||||||
|
}
|
||||||
|
|
||||||
void UITask::showMap() {
|
void UITask::showMap() {
|
||||||
_screen = SCR_MAP;
|
_screen = SCR_MAP;
|
||||||
mapview::s_available = lvport::mountStorage() && mapview::s_provider->available();
|
mapview::s_available = lvport::mountStorage() && mapview::s_provider->available();
|
||||||
@@ -109,6 +211,7 @@ void UITask::showMap() {
|
|||||||
_map_cy = mapview::latToTileY(la, z);
|
_map_cy = mapview::latToTileY(la, z);
|
||||||
}
|
}
|
||||||
buildMap();
|
buildMap();
|
||||||
|
if (_map_nav && _prefs && _prefs->locator_has_target) navFrameTarget(); // show where we're going
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::buildMap() {
|
void UITask::buildMap() {
|
||||||
@@ -120,11 +223,19 @@ void UITask::buildMap() {
|
|||||||
lv_obj_add_flag(body, LV_OBJ_FLAG_CLICKABLE);
|
lv_obj_add_flag(body, LV_OBJ_FLAG_CLICKABLE);
|
||||||
lv_obj_add_event_cb(body, onMapPress, LV_EVENT_PRESSED, NULL);
|
lv_obj_add_event_cb(body, onMapPress, LV_EVENT_PRESSED, NULL);
|
||||||
lv_obj_add_event_cb(body, onMapPress, LV_EVENT_PRESSING, NULL);
|
lv_obj_add_event_cb(body, onMapPress, LV_EVENT_PRESSING, NULL);
|
||||||
|
lv_obj_add_event_cb(body, onMapLongPress, LV_EVENT_LONG_PRESSED, NULL);
|
||||||
_map_area = body;
|
_map_area = body;
|
||||||
|
|
||||||
for (int i = 0; i < mapview::GRID_COLS * mapview::GRID_ROWS; i++) {
|
for (int i = 0; i < mapview::GRID_COLS * mapview::GRID_ROWS; i++) {
|
||||||
_map_tiles[i] = lv_image_create(body);
|
lv_obj_t* cell = lv_obj_create(body);
|
||||||
lv_obj_add_flag(_map_tiles[i], LV_OBJ_FLAG_HIDDEN);
|
lv_obj_remove_style_all(cell);
|
||||||
|
lv_obj_set_size(cell, mapview::TILE_PX, mapview::TILE_PX);
|
||||||
|
lv_obj_remove_flag(cell, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_remove_flag(cell, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_add_flag(cell, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
mapview::s_cells[i] = cell;
|
||||||
|
_map_tiles[i] = lv_image_create(cell);
|
||||||
|
lv_image_set_pivot(_map_tiles[i], 0, 0); // magnify from the top-left (overzoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marker layer: same size as the map, lets presses through to it.
|
// Marker layer: same size as the map, lets presses through to it.
|
||||||
@@ -135,6 +246,8 @@ void UITask::buildMap() {
|
|||||||
lv_obj_remove_flag(_map_marks, LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_remove_flag(_map_marks, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
lv_obj_add_flag(_map_marks, LV_OBJ_FLAG_EVENT_BUBBLE);
|
lv_obj_add_flag(_map_marks, LV_OBJ_FLAG_EVENT_BUBBLE);
|
||||||
|
|
||||||
|
if (_map_nav) buildNavLayers(); // trail + line to the target, under the markers
|
||||||
|
|
||||||
_map_me = lv_obj_create(_map_marks);
|
_map_me = lv_obj_create(_map_marks);
|
||||||
lv_obj_remove_style_all(_map_me);
|
lv_obj_remove_style_all(_map_me);
|
||||||
lv_obj_set_size(_map_me, 16, 16);
|
lv_obj_set_size(_map_me, 16, 16);
|
||||||
@@ -151,25 +264,38 @@ void UITask::buildMap() {
|
|||||||
lv_obj_align(back, LV_ALIGN_TOP_LEFT, 6, 6);
|
lv_obj_align(back, LV_ALIGN_TOP_LEFT, 6, 6);
|
||||||
lv_obj_align(mapButton(body, LV_SYMBOL_PLUS, onMapZoomIn), LV_ALIGN_TOP_RIGHT, -6, 6);
|
lv_obj_align(mapButton(body, LV_SYMBOL_PLUS, onMapZoomIn), LV_ALIGN_TOP_RIGHT, -6, 6);
|
||||||
lv_obj_align(mapButton(body, LV_SYMBOL_MINUS, onMapZoomOut), LV_ALIGN_TOP_RIGHT, -6, 52);
|
lv_obj_align(mapButton(body, LV_SYMBOL_MINUS, onMapZoomOut), LV_ALIGN_TOP_RIGHT, -6, 52);
|
||||||
lv_obj_align(mapButton(body, LV_SYMBOL_DOWNLOAD, onMapDownload), LV_ALIGN_TOP_RIGHT, -6, 98);
|
// Nav map: trail / live share / download live in its tools panel, in the
|
||||||
lv_obj_align(mapButton(body, LV_SYMBOL_GPS, onMapCenter), LV_ALIGN_BOTTOM_RIGHT, -6, -6);
|
// left column (back, pin, tools) -- the right one has no room above the bar.
|
||||||
_map_dl_pill = mapPill(body, "");
|
if (_map_nav) lv_obj_align(mapButton(body, LV_SYMBOL_BARS, onNavTools), LV_ALIGN_TOP_LEFT, 6, 98);
|
||||||
|
else lv_obj_align(mapButton(body, LV_SYMBOL_DOWNLOAD, onMapDownload), LV_ALIGN_TOP_RIGHT, -6, 98);
|
||||||
|
int bottom = _map_nav ? navmap::BAR_H : 0; // the nav bar takes the bottom edge
|
||||||
|
lv_obj_align(mapButton(body, LV_SYMBOL_GPS, onMapCenter), LV_ALIGN_BOTTOM_RIGHT, -6, -6 - bottom);
|
||||||
|
_map_dl_pill = mapPill(body, ""); // tap: the download popup
|
||||||
lv_obj_set_style_text_color(_map_dl_pill, lv_color_hex(theme::ACCENT), 0);
|
lv_obj_set_style_text_color(_map_dl_pill, lv_color_hex(theme::ACCENT), 0);
|
||||||
lv_obj_align(_map_dl_pill, LV_ALIGN_TOP_MID, 0, 16);
|
lv_obj_set_style_pad_ver(_map_dl_pill, 3, 0);
|
||||||
|
lv_obj_align(_map_dl_pill, LV_ALIGN_TOP_RIGHT, -52, 14); // beside +, clear of the zoom pill on the left
|
||||||
|
lv_obj_add_flag(_map_dl_pill, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_set_ext_click_area(_map_dl_pill, 6);
|
||||||
|
lv_obj_add_event_cb(_map_dl_pill, onMapDownload, LV_EVENT_CLICKED, NULL);
|
||||||
lv_obj_add_flag(_map_dl_pill, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(_map_dl_pill, LV_OBJ_FLAG_HIDDEN);
|
||||||
_map_zoom_lbl = mapPill(body, "");
|
_map_zoom_lbl = mapPill(body, "");
|
||||||
lv_obj_align(_map_zoom_lbl, LV_ALIGN_TOP_LEFT, 52, 16);
|
lv_obj_align(_map_zoom_lbl, LV_ALIGN_TOP_LEFT, 52, 16);
|
||||||
lv_obj_t* attr = mapPill(body, mapview::s_provider->attribution()); // required by the data licences
|
// Map data credit (the licences require it on the map): a small "©" that
|
||||||
lv_label_set_long_mode(attr, LV_LABEL_LONG_WRAP);
|
// shows the full line when tapped; it is also in Settings > About.
|
||||||
lv_obj_set_style_max_width(attr, 250, 0);
|
lv_obj_t* attr = mapPill(body, "\xC2\xA9");
|
||||||
lv_obj_set_width(attr, LV_SIZE_CONTENT);
|
lv_obj_set_style_pad_hor(attr, 7, 0);
|
||||||
lv_obj_align(attr, LV_ALIGN_BOTTOM_LEFT, 6, -6);
|
lv_obj_set_style_pad_ver(attr, 3, 0);
|
||||||
|
lv_obj_add_flag(attr, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_set_ext_click_area(attr, 8);
|
||||||
|
lv_obj_add_event_cb(attr, onMapCredits, LV_EVENT_CLICKED, NULL);
|
||||||
|
lv_obj_align(attr, LV_ALIGN_BOTTOM_LEFT, 6, -6 - bottom);
|
||||||
_map_hint = mapPill(body, "");
|
_map_hint = mapPill(body, "");
|
||||||
lv_label_set_long_mode(_map_hint, LV_LABEL_LONG_WRAP);
|
lv_label_set_long_mode(_map_hint, LV_LABEL_LONG_WRAP);
|
||||||
lv_obj_set_width(_map_hint, 200);
|
lv_obj_set_width(_map_hint, 200);
|
||||||
lv_obj_set_style_text_align(_map_hint, LV_TEXT_ALIGN_CENTER, 0);
|
lv_obj_set_style_text_align(_map_hint, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
lv_obj_center(_map_hint);
|
lv_obj_center(_map_hint);
|
||||||
lv_obj_add_flag(_map_hint, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(_map_hint, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
if (_map_nav) buildNavControls(body);
|
||||||
|
|
||||||
lv_obj_update_layout(body);
|
lv_obj_update_layout(body);
|
||||||
mapview::s_mark_count = 0; // the previous markers went with the previous screen
|
mapview::s_mark_count = 0; // the previous markers went with the previous screen
|
||||||
@@ -184,32 +310,49 @@ void UITask::layoutMap() {
|
|||||||
int w = lv_obj_get_width(_map_area), h = lv_obj_get_height(_map_area);
|
int w = lv_obj_get_width(_map_area), h = lv_obj_get_height(_map_area);
|
||||||
double left = _map_cx * mapview::TILE_PX - w / 2.0; // world px of the view's top-left
|
double left = _map_cx * mapview::TILE_PX - w / 2.0; // world px of the view's top-left
|
||||||
double top = _map_cy * mapview::TILE_PX - h / 2.0;
|
double top = _map_cy * mapview::TILE_PX - h / 2.0;
|
||||||
|
mapview::s_left = left; mapview::s_top = top;
|
||||||
int tx0 = (int)floor(left / mapview::TILE_PX), ty0 = (int)floor(top / mapview::TILE_PX);
|
int tx0 = (int)floor(left / mapview::TILE_PX), ty0 = (int)floor(top / mapview::TILE_PX);
|
||||||
int n = 1 << _map_z;
|
int n = 1 << _map_z;
|
||||||
bool have_provider = mapview::s_available;
|
bool have_provider = mapview::s_available;
|
||||||
int shown = 0, missing = 0;
|
int shown = 0, missing = 0, over = 0;
|
||||||
_map_pending = false;
|
_map_pending = false;
|
||||||
|
|
||||||
for (int j = 0; j < mapview::GRID_ROWS; j++) {
|
for (int j = 0; j < mapview::GRID_ROWS; j++) {
|
||||||
for (int i = 0; i < mapview::GRID_COLS; i++) {
|
for (int i = 0; i < mapview::GRID_COLS; i++) {
|
||||||
|
lv_obj_t* cell = mapview::s_cells[j * mapview::GRID_COLS + i];
|
||||||
lv_obj_t* img = _map_tiles[j * mapview::GRID_COLS + i];
|
lv_obj_t* img = _map_tiles[j * mapview::GRID_COLS + i];
|
||||||
int tx = tx0 + i, ty = ty0 + j;
|
int tx = tx0 + i, ty = ty0 + j, wx = ((tx % n) + n) % n;
|
||||||
int px = (int)lround(tx * (double)mapview::TILE_PX - left);
|
int px = (int)lround(tx * (double)mapview::TILE_PX - left);
|
||||||
int py = (int)lround(ty * (double)mapview::TILE_PX - top);
|
int py = (int)lround(ty * (double)mapview::TILE_PX - top);
|
||||||
bool on_screen = px < w && py < h && px + mapview::TILE_PX > 0 && py + mapview::TILE_PX > 0;
|
bool on_screen = px < w && py < h && px + mapview::TILE_PX > 0 && py + mapview::TILE_PX > 0;
|
||||||
mapview::TileCache::Slot* s = nullptr;
|
mapview::TileCache::Slot* s = nullptr;
|
||||||
if (have_provider && on_screen && ty >= 0 && ty < n) {
|
if (have_provider && on_screen && ty >= 0 && ty < n) {
|
||||||
s = mapview::s_cache.find(_map_z, ((tx % n) + n) % n, ty);
|
s = mapview::s_cache.find(_map_z, wx, ty);
|
||||||
if (!s) _map_pending = true;
|
if (!s) _map_pending = true;
|
||||||
}
|
}
|
||||||
if (s && s->present) {
|
mapview::TileCache::Slot* show = (s && s->present) ? s : nullptr;
|
||||||
if (lv_image_get_src(img) != &s->dsc) lv_image_set_src(img, &s->dsc);
|
int k = 0;
|
||||||
lv_obj_set_pos(img, px, py);
|
bool stand_in = false;
|
||||||
lv_obj_remove_flag(img, LV_OBJ_FLAG_HIDDEN);
|
if (s && !s->present) { // none at this zoom: magnify a coarser one
|
||||||
|
missing++;
|
||||||
|
int wz, ax, ay;
|
||||||
|
show = mapview::ancestorFor(_map_z, wx, ty, k, wz, ax, ay);
|
||||||
|
if (!show && wz >= 0) _map_pending = true;
|
||||||
|
} else if (!s && have_provider && on_screen && ty >= 0 && ty < n) { // not decoded yet
|
||||||
|
show = mapview::cachedAncestor(_map_z, wx, ty, k);
|
||||||
|
stand_in = show != nullptr;
|
||||||
|
}
|
||||||
|
if (show) {
|
||||||
|
if (lv_image_get_src(img) != &show->dsc) lv_image_set_src(img, &show->dsc);
|
||||||
|
lv_image_set_scale(img, LV_SCALE_NONE << k);
|
||||||
|
int m = (1 << k) - 1; // which part of the magnified tile this cell is
|
||||||
|
lv_obj_set_pos(img, -(wx & m) * mapview::TILE_PX, -(ty & m) * mapview::TILE_PX);
|
||||||
|
lv_obj_set_pos(cell, px, py);
|
||||||
|
lv_obj_remove_flag(cell, LV_OBJ_FLAG_HIDDEN);
|
||||||
shown++;
|
shown++;
|
||||||
|
if (k > over && !stand_in) over = k;
|
||||||
} else {
|
} else {
|
||||||
lv_obj_add_flag(img, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(cell, LV_OBJ_FLAG_HIDDEN);
|
||||||
if (s) missing++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,16 +367,21 @@ void UITask::layoutMap() {
|
|||||||
} else {
|
} else {
|
||||||
lv_obj_add_flag(_map_me, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(_map_me, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
|
const int half = mapview::MARK_D / 2;
|
||||||
for (int k = 0; k < mapview::s_mark_count; k++) {
|
for (int k = 0; k < mapview::s_mark_count; k++) {
|
||||||
const mapview::Mark& m = mapview::s_marks[k];
|
const mapview::Mark& m = mapview::s_marks[k];
|
||||||
|
int dy = lv_obj_get_y(m.dot); // the dot within the marker (vertically centred on the name)
|
||||||
double x = mapview::lonToTileX(m.lon_e6 / 1e6, _map_z) * mapview::TILE_PX - left;
|
double x = mapview::lonToTileX(m.lon_e6 / 1e6, _map_z) * mapview::TILE_PX - left;
|
||||||
double y = mapview::latToTileY(m.lat_e6 / 1e6, _map_z) * mapview::TILE_PX - top;
|
double y = mapview::latToTileY(m.lat_e6 / 1e6, _map_z) * mapview::TILE_PX - top;
|
||||||
lv_obj_set_pos(m.obj, (int)x - 6, (int)y - 6); // the dot's centre on the spot; name to its right
|
lv_obj_set_pos(m.obj, (int)lround(x) - half, (int)lround(y) - half - dy); // the dot's centre on the spot
|
||||||
}
|
}
|
||||||
|
if (_map_nav) layoutNav();
|
||||||
|
|
||||||
lv_label_set_text_fmt(_map_zoom_lbl, "z%d", _map_z);
|
if (over) lv_label_set_text_fmt(_map_zoom_lbl, "z%d (map z%d)", _map_z, _map_z - over); // magnified
|
||||||
|
else lv_label_set_text_fmt(_map_zoom_lbl, "z%d", _map_z);
|
||||||
const char* hint = !have_provider ? "No map on the SD card.\nPut tiles in /maps (tools/maps)."
|
const char* hint = !have_provider ? "No map on the SD card.\nPut tiles in /maps (tools/maps)."
|
||||||
: (!_map_pending && shown == 0 && missing > 0) ? "No tiles here at this zoom." : nullptr;
|
: (!_map_pending && shown == 0 && missing > 0)
|
||||||
|
? "No map detail here at this zoom.\nZoom out, or download this area." : nullptr;
|
||||||
if (hint) { lv_label_set_text(_map_hint, hint); lv_obj_remove_flag(_map_hint, LV_OBJ_FLAG_HIDDEN); }
|
if (hint) { lv_label_set_text(_map_hint, hint); lv_obj_remove_flag(_map_hint, LV_OBJ_FLAG_HIDDEN); }
|
||||||
else lv_obj_add_flag(_map_hint, LV_OBJ_FLAG_HIDDEN);
|
else lv_obj_add_flag(_map_hint, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
@@ -246,15 +394,27 @@ void UITask::mapLoop() {
|
|||||||
int32_t lat, lon;
|
int32_t lat, lon;
|
||||||
if (_core->course.currentLocation(lat, lon)) {
|
if (_core->course.currentLocation(lat, lon)) {
|
||||||
_map_cx = mapview::lonToTileX(lon / 1e6, _map_z);
|
_map_cx = mapview::lonToTileX(lon / 1e6, _map_z);
|
||||||
_map_cy = mapview::latToTileY(lat / 1e6, _map_z);
|
_map_cy = mapview::latToTileY(lat / 1e6, _map_z) + mapCenterBias();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rebuildMapMarkers();
|
rebuildMapMarkers();
|
||||||
layoutMap();
|
layoutMap();
|
||||||
}
|
}
|
||||||
if (!_map_pending || !_map_area) return;
|
if (_map_nav) navPollAveraging();
|
||||||
|
if (_map_nav && (int32_t)(millis() - _next_nav_bar_ms) >= 0) {
|
||||||
|
_next_nav_bar_ms = millis() + 1000;
|
||||||
|
refreshNavBar();
|
||||||
|
}
|
||||||
|
if (!_map_area) return;
|
||||||
|
uint32_t since_pan = millis() - mapview::s_last_pan_ms;
|
||||||
|
if (since_pan < mapview::PAN_SETTLE_MS) return; // mid-drag: keep it smooth, decode after
|
||||||
int w = lv_obj_get_width(_map_area), h = lv_obj_get_height(_map_area);
|
int w = lv_obj_get_width(_map_area), h = lv_obj_get_height(_map_area);
|
||||||
double left = _map_cx * mapview::TILE_PX - w / 2.0, top = _map_cy * mapview::TILE_PX - h / 2.0;
|
double left = _map_cx * mapview::TILE_PX - w / 2.0, top = _map_cy * mapview::TILE_PX - h / 2.0;
|
||||||
|
if (!_map_pending) { // view complete: when idle, decode the next tile a pan would reveal
|
||||||
|
if (since_pan >= mapview::PREFETCH_IDLE_MS && mapview::s_available)
|
||||||
|
mapview::prefetchOne(left, top, w, h, _map_z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
int tx0 = (int)floor(left / mapview::TILE_PX), ty0 = (int)floor(top / mapview::TILE_PX);
|
int tx0 = (int)floor(left / mapview::TILE_PX), ty0 = (int)floor(top / mapview::TILE_PX);
|
||||||
int n = 1 << _map_z;
|
int n = 1 << _map_z;
|
||||||
int best_x = 0, best_y = 0;
|
int best_x = 0, best_y = 0;
|
||||||
@@ -271,7 +431,28 @@ void UITask::mapLoop() {
|
|||||||
if (d < best_d) { best_d = d; best_x = wx; best_y = ty; }
|
if (d < best_d) { best_d = d; best_x = wx; best_y = ty; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (best_d < 1e18) mapview::s_cache.load(*mapview::s_provider, _map_z, best_x, best_y);
|
if (best_d < 1e18) {
|
||||||
|
mapview::s_cache.load(*mapview::s_provider, _map_z, best_x, best_y);
|
||||||
|
} else { // every tile at this zoom looked up: decode a coarser one for a missing tile
|
||||||
|
best_d = 1e18;
|
||||||
|
int bz = -1;
|
||||||
|
for (int j = 0; j < mapview::GRID_ROWS; j++) {
|
||||||
|
for (int i = 0; i < mapview::GRID_COLS; i++) {
|
||||||
|
int tx = tx0 + i, ty = ty0 + j;
|
||||||
|
double px = tx * (double)mapview::TILE_PX - left, py = ty * (double)mapview::TILE_PX - top;
|
||||||
|
if (px >= w || py >= h || px + mapview::TILE_PX <= 0 || py + mapview::TILE_PX <= 0) continue;
|
||||||
|
if (ty < 0 || ty >= n) continue;
|
||||||
|
int wx = ((tx % n) + n) % n;
|
||||||
|
mapview::TileCache::Slot* s = mapview::s_cache.find(_map_z, wx, ty);
|
||||||
|
if (!s || s->present) continue;
|
||||||
|
int k, wz, ax, ay;
|
||||||
|
if (mapview::ancestorFor(_map_z, wx, ty, k, wz, ax, ay) || wz < 0) continue;
|
||||||
|
double d = fabs(px + 128 - w / 2.0) + fabs(py + 128 - h / 2.0);
|
||||||
|
if (d < best_d) { best_d = d; bz = wz; best_x = ax; best_y = ay; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bz >= 0) mapview::s_cache.load(*mapview::s_provider, bz, best_x, best_y);
|
||||||
|
}
|
||||||
layoutMap();
|
layoutMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,38 +460,50 @@ void UITask::rebuildMapMarkers() {
|
|||||||
if (!_map_marks) return;
|
if (!_map_marks) return;
|
||||||
for (int k = 0; k < mapview::s_mark_count; k++) lv_obj_delete(mapview::s_marks[k].obj);
|
for (int k = 0; k < mapview::s_mark_count; k++) lv_obj_delete(mapview::s_marks[k].obj);
|
||||||
mapview::s_mark_count = 0;
|
mapview::s_mark_count = 0;
|
||||||
|
if (_map_nav) rebuildNavMarkers();
|
||||||
|
else rebuildNodeMarkers();
|
||||||
|
lv_obj_update_layout(_map_marks); // so layoutMap() knows where each dot sits in its marker
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::rebuildNodeMarkers() {
|
||||||
_nearby->refreshStored();
|
_nearby->refreshStored();
|
||||||
for (int i = 0; i < _nearby->count() && mapview::s_mark_count < NearbyModel::MAX_NEARBY; i++) {
|
for (int i = 0; i < _nearby->count() && mapview::s_mark_count < mapview::MAX_MARKS; i++) {
|
||||||
const NearbyModel::Entry& e = _nearby->at(i);
|
const NearbyModel::Entry& e = _nearby->at(i);
|
||||||
if (e.lat_e6 == 0 && e.lon_e6 == 0) continue;
|
if (e.lat_e6 == 0 && e.lon_e6 == 0) continue;
|
||||||
uint32_t col = e.is_live ? theme::OK : e.type == ADV_TYPE_CHAT ? theme::TEXT : theme::TEXT_MUTED;
|
uint32_t col = e.is_live ? theme::OK : e.type == ADV_TYPE_CHAT ? theme::TEXT : theme::TEXT_MUTED;
|
||||||
|
addMapMark(mapview::MK_NODE, i, e.lat_e6, e.lon_e6, col, e.name[0] ? e.name : "?");
|
||||||
// One clickable object per marker: a dot plus the name beside it.
|
|
||||||
lv_obj_t* m = lv_obj_create(_map_marks);
|
|
||||||
lv_obj_remove_style_all(m);
|
|
||||||
lv_obj_set_size(m, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
|
||||||
lv_obj_set_flex_flow(m, LV_FLEX_FLOW_ROW);
|
|
||||||
lv_obj_set_flex_align(m, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
|
||||||
lv_obj_set_style_pad_column(m, 3, 0);
|
|
||||||
lv_obj_add_flag(m, LV_OBJ_FLAG_EVENT_BUBBLE); // a drag starting here still pans
|
|
||||||
lv_obj_add_event_cb(m, onMapMarker, LV_EVENT_CLICKED, (void*)(uintptr_t)mapview::s_mark_count);
|
|
||||||
lv_obj_t* dot = lv_obj_create(m);
|
|
||||||
lv_obj_remove_style_all(dot);
|
|
||||||
lv_obj_set_size(dot, 12, 12);
|
|
||||||
lv_obj_set_style_radius(dot, LV_RADIUS_CIRCLE, 0);
|
|
||||||
lv_obj_set_style_bg_color(dot, lv_color_hex(col), 0);
|
|
||||||
lv_obj_set_style_bg_opa(dot, LV_OPA_COVER, 0);
|
|
||||||
lv_obj_set_style_border_color(dot, lv_color_hex(theme::BG), 0);
|
|
||||||
lv_obj_set_style_border_width(dot, 2, 0);
|
|
||||||
lv_obj_remove_flag(dot, LV_OBJ_FLAG_CLICKABLE);
|
|
||||||
lv_obj_t* name = mapPill(m, e.name[0] ? e.name : "?");
|
|
||||||
lv_obj_remove_flag(name, LV_OBJ_FLAG_CLICKABLE);
|
|
||||||
|
|
||||||
mapview::Mark& mk = mapview::s_marks[mapview::s_mark_count++];
|
|
||||||
mk.lat_e6 = e.lat_e6; mk.lon_e6 = e.lon_e6; mk.row = i; mk.obj = m;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One clickable object per marker: a dot plus the name beside it. The object
|
||||||
|
// is placed so the dot's centre is on the spot, from where layout actually put
|
||||||
|
// the dot inside it (Mark::dot) -- the name may be taller than the dot.
|
||||||
|
void UITask::addMapMark(uint8_t kind, int idx, int32_t lat_e6, int32_t lon_e6, uint32_t col, const char* text) {
|
||||||
|
if (!_map_marks || mapview::s_mark_count >= mapview::MAX_MARKS) return;
|
||||||
|
lv_obj_t* m = lv_obj_create(_map_marks);
|
||||||
|
lv_obj_remove_style_all(m);
|
||||||
|
lv_obj_set_size(m, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||||
|
lv_obj_set_flex_flow(m, LV_FLEX_FLOW_ROW);
|
||||||
|
lv_obj_set_flex_align(m, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
|
lv_obj_set_style_pad_column(m, 3, 0);
|
||||||
|
lv_obj_add_flag(m, LV_OBJ_FLAG_EVENT_BUBBLE); // a drag starting here still pans
|
||||||
|
lv_obj_add_event_cb(m, onMapMarker, LV_EVENT_CLICKED, (void*)(uintptr_t)mapview::s_mark_count);
|
||||||
|
lv_obj_t* dot = lv_obj_create(m);
|
||||||
|
lv_obj_remove_style_all(dot);
|
||||||
|
lv_obj_set_size(dot, mapview::MARK_D, mapview::MARK_D);
|
||||||
|
lv_obj_set_style_radius(dot, LV_RADIUS_CIRCLE, 0);
|
||||||
|
lv_obj_set_style_bg_color(dot, lv_color_hex(col), 0);
|
||||||
|
lv_obj_set_style_bg_opa(dot, LV_OPA_COVER, 0);
|
||||||
|
lv_obj_set_style_border_color(dot, lv_color_hex(theme::BG), 0);
|
||||||
|
lv_obj_set_style_border_width(dot, 2, 0);
|
||||||
|
lv_obj_remove_flag(dot, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_t* name = mapPill(m, text);
|
||||||
|
lv_obj_remove_flag(name, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
|
||||||
|
mapview::Mark& mk = mapview::s_marks[mapview::s_mark_count++];
|
||||||
|
mk.lat_e6 = lat_e6; mk.lon_e6 = lon_e6; mk.idx = idx; mk.kind = kind; mk.obj = m; mk.dot = dot;
|
||||||
|
}
|
||||||
|
|
||||||
void UITask::mapPan(int dx, int dy) {
|
void UITask::mapPan(int dx, int dy) {
|
||||||
_map_cx -= dx / (double)mapview::TILE_PX;
|
_map_cx -= dx / (double)mapview::TILE_PX;
|
||||||
_map_cy -= dy / (double)mapview::TILE_PX;
|
_map_cy -= dy / (double)mapview::TILE_PX;
|
||||||
@@ -332,19 +525,36 @@ void UITask::mapZoom(int delta) {
|
|||||||
|
|
||||||
void UITask::mapCenterOnMe() {
|
void UITask::mapCenterOnMe() {
|
||||||
int32_t lat, lon;
|
int32_t lat, lon;
|
||||||
if (!_core->course.currentLocation(lat, lon)) { showToast("No GPS fix"); return; }
|
if (!ensureGps() || !_core->course.currentLocation(lat, lon)) { _map_follow = true; return; } // centres once a fix comes
|
||||||
_map_follow = true;
|
_map_follow = true;
|
||||||
_map_cx = mapview::lonToTileX(lon / 1e6, _map_z);
|
_map_cx = mapview::lonToTileX(lon / 1e6, _map_z);
|
||||||
_map_cy = mapview::latToTileY(lat / 1e6, _map_z);
|
_map_cy = mapview::latToTileY(lat / 1e6, _map_z) + mapCenterBias();
|
||||||
layoutMap();
|
layoutMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::mapOpenMarker(int idx) {
|
void UITask::mapOpenMarker(int idx) {
|
||||||
if (idx < 0 || idx >= mapview::s_mark_count) return;
|
if (idx < 0 || idx >= mapview::s_mark_count) return;
|
||||||
openNode(mapview::s_marks[idx].row);
|
const mapview::Mark& m = mapview::s_marks[idx];
|
||||||
|
if (m.kind == mapview::MK_WAYPOINT) { navWaypointMenu(m.idx); return; }
|
||||||
|
if (m.kind == mapview::MK_LIVE) { navPick(navmap::code(navmap::T_LIVE, m.idx)); return; }
|
||||||
|
openNode(m.idx);
|
||||||
_node_from_map = true;
|
_node_from_map = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Screen point (relative to the map area) -> lat/lon at the current view.
|
||||||
|
void UITask::mapPointToLatLon(int x, int y, int32_t& lat_e6, int32_t& lon_e6) const {
|
||||||
|
double n = (double)(1 << _map_z);
|
||||||
|
double tx = (mapview::s_left + x) / mapview::TILE_PX, ty = (mapview::s_top + y) / mapview::TILE_PX;
|
||||||
|
double lon = tx / n * 360.0 - 180.0;
|
||||||
|
double lat = atan(sinh(M_PI * (1.0 - 2.0 * ty / n))) * 180.0 / M_PI;
|
||||||
|
lat_e6 = (int32_t)lround(lat * 1e6);
|
||||||
|
lon_e6 = (int32_t)lround(lon * 1e6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::mapLongPress(int x, int y) {
|
||||||
|
if (_map_nav) navDropAt(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ── Area download ─────────────────────────────────────────────────────────────
|
// ── Area download ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -405,6 +615,21 @@ void UITask::mapDownloadPopup() {
|
|||||||
lv_obj_align(_dl_zoom_lbl, LV_ALIGN_RIGHT_MID, -56, 0);
|
lv_obj_align(_dl_zoom_lbl, LV_ALIGN_RIGHT_MID, -56, 0);
|
||||||
headerButton(zr, LV_SYMBOL_MINUS, onDlZoomMinus, 96, NULL);
|
headerButton(zr, LV_SYMBOL_MINUS, onDlZoomMinus, 96, NULL);
|
||||||
|
|
||||||
|
// Unfinished job (power-off, lost WiFi, Stop): resume or drop it.
|
||||||
|
_dl_job_row = lv_obj_create(panel);
|
||||||
|
styleSurface(_dl_job_row, theme::SURFACE);
|
||||||
|
lv_obj_remove_flag(_dl_job_row, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_set_size(_dl_job_row, LV_PCT(100), 40);
|
||||||
|
lv_obj_set_style_radius(_dl_job_row, theme::RADIUS, 0);
|
||||||
|
_dl_job_lbl = label(_dl_job_row, "", THEME_FONT_SMALL, theme::TEXT);
|
||||||
|
lv_obj_set_width(_dl_job_lbl, 170);
|
||||||
|
lv_label_set_long_mode(_dl_job_lbl, LV_LABEL_LONG_WRAP);
|
||||||
|
lv_obj_align(_dl_job_lbl, LV_ALIGN_LEFT_MID, theme::PAD, 0);
|
||||||
|
lv_obj_t* res = headerButton(_dl_job_row, LV_SYMBOL_PLAY " Resume", onDlResume, 48, NULL);
|
||||||
|
lv_obj_set_style_bg_color(res, lv_color_hex(theme::ACCENT_DIM), 0);
|
||||||
|
headerButton(_dl_job_row, LV_SYMBOL_TRASH, onDlDiscard, 4, NULL);
|
||||||
|
lv_obj_add_flag(_dl_job_row, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
_dl_info = label(panel, "", THEME_FONT_SMALL, theme::TEXT);
|
_dl_info = label(panel, "", THEME_FONT_SMALL, theme::TEXT);
|
||||||
lv_label_set_long_mode(_dl_info, LV_LABEL_LONG_WRAP);
|
lv_label_set_long_mode(_dl_info, LV_LABEL_LONG_WRAP);
|
||||||
lv_obj_set_width(_dl_info, LV_PCT(100));
|
lv_obj_set_width(_dl_info, LV_PCT(100));
|
||||||
@@ -439,7 +664,7 @@ void UITask::mapDownloadPopup() {
|
|||||||
|
|
||||||
void UITask::mapDownloadClose() {
|
void UITask::mapDownloadClose() {
|
||||||
if (_dl_overlay) lv_obj_delete_async(_dl_overlay); // may be closing from its own button
|
if (_dl_overlay) lv_obj_delete_async(_dl_overlay); // may be closing from its own button
|
||||||
_dl_overlay = _dl_info = _dl_zoom_lbl = _dl_start_lbl = nullptr;
|
_dl_overlay = _dl_info = _dl_zoom_lbl = _dl_start_lbl = _dl_job_row = _dl_job_lbl = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::mapDownloadZmax(int delta) {
|
void UITask::mapDownloadZmax(int delta) {
|
||||||
@@ -468,23 +693,32 @@ void UITask::refreshDownloadPopup() {
|
|||||||
(unsigned long)dl.processed(), (unsigned long)dl.total(),
|
(unsigned long)dl.processed(), (unsigned long)dl.total(),
|
||||||
(unsigned long)dl.downloaded(), dl.sourceHost(), net);
|
(unsigned long)dl.downloaded(), dl.sourceHost(), net);
|
||||||
lv_label_set_text(_dl_start_lbl, LV_SYMBOL_STOP " Stop");
|
lv_label_set_text(_dl_start_lbl, LV_SYMBOL_STOP " Stop");
|
||||||
|
if (_dl_job_row) lv_obj_add_flag(_dl_job_row, LV_OBJ_FLAG_HIDDEN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mapview::TileArea job;
|
||||||
|
if (_dl_job_row && dl.savedJob(job)) {
|
||||||
|
lv_label_set_text_fmt(_dl_job_lbl, "Unfinished: z%d-%d,\n%lu tiles", job.zmin, job.zmax,
|
||||||
|
(unsigned long)mapview::countTiles(job));
|
||||||
|
lv_obj_remove_flag(_dl_job_row, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
} else if (_dl_job_row) {
|
||||||
|
lv_obj_add_flag(_dl_job_row, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
}
|
||||||
int w = _map_area ? lv_obj_get_width(_map_area) : 320, h = _map_area ? lv_obj_get_height(_map_area) : 218;
|
int w = _map_area ? lv_obj_get_width(_map_area) : 320, h = _map_area ? lv_obj_get_height(_map_area) : 218;
|
||||||
mapview::TileArea a = visibleArea(_map_cx, _map_cy, _map_z, w, h, dlZmin(_map_z), _dl_zmax);
|
mapview::TileArea a = visibleArea(_map_cx, _map_cy, _map_z, w, h, dlZmin(_map_z), _dl_zmax);
|
||||||
uint32_t n = mapview::countTiles(a);
|
uint32_t n = mapview::countTiles(a);
|
||||||
char ssid[33], pass[65];
|
char ssid[33], pass[65];
|
||||||
bool have_wifi = lvport::loadWifi(ssid, sizeof(ssid), pass, sizeof(pass));
|
bool have_wifi = lvport::loadWifi(ssid, sizeof(ssid), pass, sizeof(pass));
|
||||||
char last[64] = "";
|
char last[64] = "";
|
||||||
if (dl.state() == mapview::TileDownloader::DONE || dl.state() == mapview::TileDownloader::FAILED ||
|
bool job_shown = _dl_job_row && !lv_obj_has_flag(_dl_job_row, LV_OBJ_FLAG_HIDDEN); // it says enough
|
||||||
dl.state() == mapview::TileDownloader::CANCELLED)
|
if (!job_shown && (dl.state() == mapview::TileDownloader::DONE || dl.state() == mapview::TileDownloader::FAILED ||
|
||||||
|
dl.state() == mapview::TileDownloader::CANCELLED))
|
||||||
snprintf(last, sizeof(last), "\nLast: %s (%lu new)", dl.message(), (unsigned long)dl.downloaded());
|
snprintf(last, sizeof(last), "\nLast: %s (%lu new)", dl.message(), (unsigned long)dl.downloaded());
|
||||||
char size[16];
|
char size[16];
|
||||||
uint64_t bytes = (uint64_t)n * mapview::AVG_TILE_BYTES;
|
uint64_t bytes = (uint64_t)n * mapview::AVG_TILE_BYTES;
|
||||||
if (bytes < 1024 * 1024) snprintf(size, sizeof(size), "%lu KB", (unsigned long)(bytes / 1024));
|
if (bytes < 1024 * 1024) snprintf(size, sizeof(size), "%lu KB", (unsigned long)(bytes / 1024));
|
||||||
else snprintf(size, sizeof(size), "%lu MB", (unsigned long)((bytes + 512 * 1024) / (1024 * 1024)));
|
else snprintf(size, sizeof(size), "%lu MB", (unsigned long)((bytes + 512 * 1024) / (1024 * 1024)));
|
||||||
lv_label_set_text_fmt(_dl_info, "z%d-%d: %lu tiles, about %s (tiles on the card are skipped)\n"
|
lv_label_set_text_fmt(_dl_info, "z%d-%d: %lu tiles, about %s - from %s\nWiFi: %s%s",
|
||||||
"From %s\nWiFi: %s%s",
|
|
||||||
a.zmin, a.zmax, (unsigned long)n, size,
|
a.zmin, a.zmax, (unsigned long)n, size,
|
||||||
dl.sourceHost(), have_wifi ? ssid : "not set - tap WiFi", last);
|
dl.sourceHost(), have_wifi ? ssid : "not set - tap WiFi", last);
|
||||||
lv_label_set_text(_dl_start_lbl, n > mapview::TileDownloader::MAX_TILES ? "Too large - zoom in"
|
lv_label_set_text(_dl_start_lbl, n > mapview::TileDownloader::MAX_TILES ? "Too large - zoom in"
|
||||||
@@ -502,11 +736,28 @@ void UITask::mapDownloadStart() {
|
|||||||
refreshDownloadPopup();
|
refreshDownloadPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UITask::mapDownloadResume() {
|
||||||
|
mapview::TileArea a;
|
||||||
|
if (mapview::s_dl.active() || !mapview::s_dl.savedJob(a)) return;
|
||||||
|
char ssid[33], pass[65];
|
||||||
|
if (!lvport::loadWifi(ssid, sizeof(ssid), pass, sizeof(pass))) { showWifi(true); return; }
|
||||||
|
if (!lvport::mountStorage()) { showToast("No SD card"); return; }
|
||||||
|
if (!mapview::s_dl.start(a, ssid, pass)) { showToast(mapview::s_dl.message()); return; }
|
||||||
|
refreshDownloadPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::mapDownloadDiscard() {
|
||||||
|
mapview::s_dl.discardJob();
|
||||||
|
refreshDownloadPopup();
|
||||||
|
}
|
||||||
|
|
||||||
void UITask::mapDownloadStop() {
|
void UITask::mapDownloadStop() {
|
||||||
mapview::s_dl.cancel();
|
mapview::s_dl.cancel();
|
||||||
refreshDownloadPopup();
|
refreshDownloadPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mapview::TileArea s_job_tmp;
|
||||||
|
|
||||||
// Every UI loop pass, whatever the screen: a download keeps going in the background.
|
// Every UI loop pass, whatever the screen: a download keeps going in the background.
|
||||||
void UITask::mapDownloadTick() {
|
void UITask::mapDownloadTick() {
|
||||||
mapview::TileDownloader& dl = mapview::s_dl;
|
mapview::TileDownloader& dl = mapview::s_dl;
|
||||||
@@ -539,6 +790,9 @@ void UITask::mapDownloadTick() {
|
|||||||
lv_label_set_text_fmt(_map_dl_pill, LV_SYMBOL_DOWNLOAD " %lu / %lu", (unsigned long)dl.processed(),
|
lv_label_set_text_fmt(_map_dl_pill, LV_SYMBOL_DOWNLOAD " %lu / %lu", (unsigned long)dl.processed(),
|
||||||
(unsigned long)dl.total());
|
(unsigned long)dl.total());
|
||||||
lv_obj_remove_flag(_map_dl_pill, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_remove_flag(_map_dl_pill, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
} else if (mapview::s_available && dl.savedJob(s_job_tmp)) {
|
||||||
|
lv_label_set_text(_map_dl_pill, LV_SYMBOL_DOWNLOAD " Resume?");
|
||||||
|
lv_obj_remove_flag(_map_dl_pill, LV_OBJ_FLAG_HIDDEN);
|
||||||
} else {
|
} else {
|
||||||
lv_obj_add_flag(_map_dl_pill, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(_map_dl_pill, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,220 @@
|
|||||||
|
#pragma once
|
||||||
|
// Settings > Radio: preset, frequency, SF / bandwidth / coding rate, TX power
|
||||||
|
// and Adaptive Power Control -- ui-new's Settings > Radio. Every change is
|
||||||
|
// applied to the radio at once and saved (ui-core/RadioControl.h does the
|
||||||
|
// applying for both frontends).
|
||||||
|
//
|
||||||
|
// Single-TU fragment: included by ui-lvgl/UITask.cpp after ClockScreen.h.
|
||||||
|
|
||||||
|
namespace radioview {
|
||||||
|
|
||||||
|
enum : uint8_t { R_PRESET, R_SF, R_BW, R_CR, R_TX, R_APC };
|
||||||
|
static const int TX_MIN = 2;
|
||||||
|
#ifdef LORA_TX_POWER
|
||||||
|
static const int TX_MAX = LORA_TX_POWER;
|
||||||
|
#else
|
||||||
|
static const int TX_MAX = 22;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static lv_obj_t* s_overlay = nullptr; // frequency entry
|
||||||
|
static lv_obj_t* s_ta = nullptr;
|
||||||
|
static char s_opts[1024];
|
||||||
|
|
||||||
|
// Label + optional hint on the left of a settings row; the control goes on the right.
|
||||||
|
static lv_obj_t* settingRow(lv_obj_t* parent, const char* text, const char* hint) {
|
||||||
|
lv_obj_t* row = lv_obj_create(parent);
|
||||||
|
styleSurface(row, theme::SURFACE);
|
||||||
|
lv_obj_remove_flag(row, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_set_size(row, LV_PCT(100), theme::ROW_H);
|
||||||
|
lv_obj_set_style_radius(row, theme::RADIUS, 0);
|
||||||
|
lv_obj_align(label(row, text, THEME_FONT_BODY, theme::TEXT), LV_ALIGN_TOP_LEFT, theme::PAD, hint ? 5 : 13);
|
||||||
|
if (hint) {
|
||||||
|
lv_obj_t* h = label(row, hint, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
lv_label_set_long_mode(h, LV_LABEL_LONG_DOT);
|
||||||
|
lv_obj_set_size(h, 150, 15);
|
||||||
|
lv_obj_align(h, LV_ALIGN_BOTTOM_LEFT, theme::PAD, -5);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
static lv_obj_t* rowDropdown(lv_obj_t* row, const char* opts, int sel, int width, lv_event_cb_t cb, uintptr_t which) {
|
||||||
|
lv_obj_t* dd = lv_dropdown_create(row);
|
||||||
|
lv_dropdown_set_options(dd, opts);
|
||||||
|
if (sel >= 0) lv_dropdown_set_selected(dd, sel);
|
||||||
|
lv_obj_set_width(dd, width);
|
||||||
|
lv_obj_align(dd, LV_ALIGN_RIGHT_MID, -4, 0);
|
||||||
|
lv_obj_add_event_cb(dd, cb, LV_EVENT_VALUE_CHANGED, (void*)which);
|
||||||
|
return dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace radioview
|
||||||
|
|
||||||
|
static void onRadioDropdown(lv_event_t* e) {
|
||||||
|
s_ui->radioSet((int)(uintptr_t)lv_event_get_user_data(e), (int)lv_dropdown_get_selected((lv_obj_t*)lv_event_get_target(e)));
|
||||||
|
}
|
||||||
|
static void onRadioSwitch(lv_event_t* e) {
|
||||||
|
s_ui->radioSet((int)(uintptr_t)lv_event_get_user_data(e),
|
||||||
|
lv_obj_has_state((lv_obj_t*)lv_event_get_target(e), LV_STATE_CHECKED) ? 1 : 0);
|
||||||
|
}
|
||||||
|
static void onRadioFreq(lv_event_t* e) { (void)e; s_ui->radioFreqPopup(); }
|
||||||
|
static void onRadioFreqKb(lv_event_t* e) { s_ui->radioFreqDone(lv_event_get_code(e) == LV_EVENT_READY); }
|
||||||
|
static void onOpenRadio(lv_event_t* e) { (void)e; s_ui->showRadio(); }
|
||||||
|
|
||||||
|
void UITask::showRadio() {
|
||||||
|
_screen = SCR_RADIO;
|
||||||
|
buildRadio();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::buildRadio() {
|
||||||
|
using namespace radioview;
|
||||||
|
lv_obj_t* body = newScreen("Radio", true);
|
||||||
|
s_overlay = s_ta = nullptr;
|
||||||
|
NodePrefs* p = _prefs;
|
||||||
|
|
||||||
|
// Preset: "Custom" first (current params match none), then the list.
|
||||||
|
int o = snprintf(s_opts, sizeof(s_opts), "Custom");
|
||||||
|
const char* name; float f, b; uint8_t sf, cr;
|
||||||
|
for (int i = 0; radioctl::presetAt(p, i, name, f, b, sf, cr) && o < (int)sizeof(s_opts) - 24; i++)
|
||||||
|
o += snprintf(s_opts + o, sizeof(s_opts) - o, "\n%s", name);
|
||||||
|
lv_obj_t* row = settingRow(body, "Preset", nullptr);
|
||||||
|
lv_obj_t* dd = rowDropdown(row, s_opts, radioctl::currentPreset(p) + 1, 200, onRadioDropdown, R_PRESET);
|
||||||
|
lv_dropdown_set_dir(dd, LV_DIR_BOTTOM);
|
||||||
|
|
||||||
|
// Frequency: tap to type it.
|
||||||
|
row = settingRow(body, "Frequency", "MHz");
|
||||||
|
lv_obj_t* fb = lv_button_create(row);
|
||||||
|
lv_obj_set_size(fb, 120, 34);
|
||||||
|
lv_obj_align(fb, LV_ALIGN_RIGHT_MID, -4, 0);
|
||||||
|
lv_obj_set_style_shadow_width(fb, 0, 0);
|
||||||
|
lv_obj_set_style_radius(fb, theme::RADIUS, 0);
|
||||||
|
lv_obj_set_style_bg_color(fb, lv_color_hex(theme::SURFACE_2), 0);
|
||||||
|
lv_obj_add_event_cb(fb, onRadioFreq, LV_EVENT_CLICKED, NULL);
|
||||||
|
char fs[16];
|
||||||
|
snprintf(fs, sizeof(fs), "%.3f", p->freq);
|
||||||
|
lv_obj_center(label(fb, fs, THEME_FONT_BODY, theme::TEXT));
|
||||||
|
|
||||||
|
o = 0;
|
||||||
|
for (int v = 5; v <= 12; v++) o += snprintf(s_opts + o, sizeof(s_opts) - o, v > 5 ? "\n%d" : "%d", v);
|
||||||
|
rowDropdown(settingRow(body, "Spreading factor", "Higher = longer range"), s_opts,
|
||||||
|
p->sf >= 5 && p->sf <= 12 ? p->sf - 5 : 0, 90, onRadioDropdown, R_SF);
|
||||||
|
o = 0;
|
||||||
|
for (int i = 0; i < LORA_BW_OPT_COUNT; i++)
|
||||||
|
o += snprintf(s_opts + o, sizeof(s_opts) - o, "%s%g kHz", i ? "\n" : "", (double)LORA_BW_OPTS[i]);
|
||||||
|
rowDropdown(settingRow(body, "Bandwidth", nullptr), s_opts, nearestBwIndex(p->bw), 130, onRadioDropdown, R_BW);
|
||||||
|
o = 0;
|
||||||
|
for (int v = 5; v <= 8; v++) o += snprintf(s_opts + o, sizeof(s_opts) - o, v > 5 ? "\n4/%d" : "4/%d", v);
|
||||||
|
rowDropdown(settingRow(body, "Coding rate", nullptr), s_opts, p->cr >= 5 && p->cr <= 8 ? p->cr - 5 : 0, 90,
|
||||||
|
onRadioDropdown, R_CR);
|
||||||
|
|
||||||
|
sectionTitle(body, "TRANSMIT");
|
||||||
|
o = 0;
|
||||||
|
for (int v = TX_MIN; v <= TX_MAX; v++) o += snprintf(s_opts + o, sizeof(s_opts) - o, v > TX_MIN ? "\n%d dBm" : "%d dBm", v);
|
||||||
|
int tx = p->tx_power_dbm < TX_MIN ? TX_MIN : p->tx_power_dbm > TX_MAX ? TX_MAX : p->tx_power_dbm;
|
||||||
|
rowDropdown(settingRow(body, "TX power", p->tx_apc ? "Ceiling for auto power" : nullptr), s_opts, tx - TX_MIN, 110,
|
||||||
|
onRadioDropdown, R_TX);
|
||||||
|
row = settingRow(body, "Auto power", p->client_repeat ? "Off while repeating" : "Lowers power on good links");
|
||||||
|
lv_obj_t* sw = lv_switch_create(row);
|
||||||
|
lv_obj_set_size(sw, 46, 24);
|
||||||
|
lv_obj_align(sw, LV_ALIGN_RIGHT_MID, -theme::PAD, 0);
|
||||||
|
if (p->tx_apc) lv_obj_add_state(sw, LV_STATE_CHECKED);
|
||||||
|
if (p->client_repeat) lv_obj_add_state(sw, LV_STATE_DISABLED);
|
||||||
|
lv_obj_add_event_cb(sw, onRadioSwitch, LV_EVENT_VALUE_CHANGED, (void*)(uintptr_t)R_APC);
|
||||||
|
|
||||||
|
lv_obj_t* note = label(body, "Everyone you talk to must use the same frequency, SF, bandwidth and coding rate.",
|
||||||
|
THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
lv_label_set_long_mode(note, LV_LABEL_LONG_WRAP);
|
||||||
|
lv_obj_set_width(note, LV_PCT(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::radioSet(int which, int v) {
|
||||||
|
using namespace radioview;
|
||||||
|
NodePrefs* p = _prefs;
|
||||||
|
if (!p) return;
|
||||||
|
switch (which) {
|
||||||
|
case R_PRESET:
|
||||||
|
if (v == 0) return; // "Custom": nothing to take
|
||||||
|
radioctl::choosePreset(p, v - 1);
|
||||||
|
break;
|
||||||
|
case R_SF: p->sf = (uint8_t)(5 + v); radioctl::applyParams(); break;
|
||||||
|
case R_BW: if (v >= 0 && v < LORA_BW_OPT_COUNT) { p->bw = LORA_BW_OPTS[v]; radioctl::applyParams(); } break;
|
||||||
|
case R_CR: p->cr = (uint8_t)(5 + v); radioctl::applyParams(); break;
|
||||||
|
case R_TX: p->tx_power_dbm = (int8_t)(TX_MIN + v); radioctl::applyTxPower(p); break;
|
||||||
|
case R_APC: p->tx_apc = (uint8_t)v; radioctl::applyApc(); break;
|
||||||
|
}
|
||||||
|
the_mesh.savePrefs();
|
||||||
|
lv_obj_t* body = _body;
|
||||||
|
int32_t y = body ? lv_obj_get_scroll_y(body) : 0;
|
||||||
|
buildRadio(); // preset name / hints follow
|
||||||
|
if (_body) { lv_obj_update_layout(_body); lv_obj_scroll_to_y(_body, y, LV_ANIM_OFF); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::radioFreqPopup() {
|
||||||
|
using namespace radioview;
|
||||||
|
if (s_overlay) return;
|
||||||
|
s_overlay = lv_obj_create(lv_screen_active());
|
||||||
|
lv_obj_remove_style_all(s_overlay);
|
||||||
|
lv_obj_set_size(s_overlay, LV_PCT(100), LV_PCT(100));
|
||||||
|
lv_obj_set_style_bg_color(s_overlay, lv_color_hex(0x000000), 0);
|
||||||
|
lv_obj_set_style_bg_opa(s_overlay, LV_OPA_60, 0);
|
||||||
|
lv_obj_add_flag(s_overlay, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_t* panel = lv_obj_create(s_overlay);
|
||||||
|
lv_obj_set_size(panel, lv_display_get_horizontal_resolution(NULL) - 16, LV_SIZE_CONTENT);
|
||||||
|
lv_obj_align(panel, LV_ALIGN_TOP_MID, 0, theme::STATUS_H + 4);
|
||||||
|
lv_obj_set_style_bg_color(panel, lv_color_hex(theme::BG), 0);
|
||||||
|
lv_obj_set_style_border_color(panel, lv_color_hex(theme::ACCENT), 0);
|
||||||
|
lv_obj_set_style_border_width(panel, 1, 0);
|
||||||
|
lv_obj_set_style_radius(panel, theme::RADIUS, 0);
|
||||||
|
lv_obj_set_style_pad_all(panel, theme::PAD, 0);
|
||||||
|
lv_obj_set_style_pad_row(panel, 6, 0);
|
||||||
|
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
|
||||||
|
lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
float lo, hi;
|
||||||
|
radio_driver.getFreqBounds(lo, hi);
|
||||||
|
char t[48];
|
||||||
|
snprintf(t, sizeof(t), "Frequency, MHz (%.0f - %.0f)", lo, hi);
|
||||||
|
label(panel, t, THEME_FONT_BODY, theme::TEXT);
|
||||||
|
s_ta = lv_textarea_create(panel);
|
||||||
|
lv_textarea_set_one_line(s_ta, true);
|
||||||
|
lv_textarea_set_accepted_chars(s_ta, "0123456789.");
|
||||||
|
lv_textarea_set_max_length(s_ta, 10);
|
||||||
|
char fs[16];
|
||||||
|
snprintf(fs, sizeof(fs), "%.3f", _prefs->freq);
|
||||||
|
lv_textarea_set_text(s_ta, fs);
|
||||||
|
lv_obj_set_size(s_ta, LV_PCT(100), 34);
|
||||||
|
lv_obj_set_style_border_width(s_ta, 1, 0);
|
||||||
|
lv_obj_set_style_pad_ver(s_ta, 6, 0);
|
||||||
|
lv_obj_set_style_pad_hor(s_ta, 10, 0);
|
||||||
|
lv_obj_set_scrollbar_mode(s_ta, LV_SCROLLBAR_MODE_OFF);
|
||||||
|
lv_obj_set_style_border_color(s_ta, lv_color_hex(theme::ACCENT), LV_PART_CURSOR | LV_STATE_FOCUSED);
|
||||||
|
lv_obj_set_style_border_width(s_ta, 2, LV_PART_CURSOR | LV_STATE_FOCUSED);
|
||||||
|
lv_obj_add_state(s_ta, LV_STATE_FOCUSED);
|
||||||
|
lv_obj_t* kbd = kb::create(s_overlay, _prefs);
|
||||||
|
lv_obj_set_size(kbd, LV_PCT(100), 124);
|
||||||
|
lv_obj_align(kbd, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||||
|
lv_keyboard_set_textarea(kbd, s_ta);
|
||||||
|
kb::apply(kbd, kb::L_SYM);
|
||||||
|
lv_obj_add_event_cb(kbd, onRadioFreqKb, LV_EVENT_READY, NULL);
|
||||||
|
lv_obj_add_event_cb(kbd, onRadioFreqKb, LV_EVENT_CANCEL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::radioFreqDone(bool ok) {
|
||||||
|
using namespace radioview;
|
||||||
|
if (ok && s_ta) {
|
||||||
|
float lo, hi;
|
||||||
|
radio_driver.getFreqBounds(lo, hi);
|
||||||
|
float f = strtof(lv_textarea_get_text(s_ta), nullptr);
|
||||||
|
if (f < lo || f > hi) { showToast("Out of the radio's range"); return; }
|
||||||
|
_prefs->freq = f;
|
||||||
|
radioctl::applyParams();
|
||||||
|
the_mesh.savePrefs();
|
||||||
|
}
|
||||||
|
radioCloseFreq();
|
||||||
|
if (ok) buildRadio();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::radioCloseFreq() {
|
||||||
|
if (radioview::s_overlay) lv_obj_delete_async(radioview::s_overlay);
|
||||||
|
radioview::s_overlay = radioview::s_ta = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UITask::radioPopupOpen() const { return radioview::s_overlay != nullptr; }
|
||||||
@@ -22,7 +22,7 @@ namespace theme {
|
|||||||
static const int ROW_H = 44; // list row (touch target)
|
static const int ROW_H = 44; // list row (touch target)
|
||||||
|
|
||||||
// Type -- Noto Sans, generated by fonts/generate.sh (declared in lv_conf.h).
|
// Type -- Noto Sans, generated by fonts/generate.sh (declared in lv_conf.h).
|
||||||
// ui_font_40 holds digits / ':' / '-' only (clock).
|
// ui_font_40 holds digits / ':' / '-' / '.' only (clock, timer, stopwatch).
|
||||||
#define THEME_FONT_SMALL (&ui_font_12)
|
#define THEME_FONT_SMALL (&ui_font_12)
|
||||||
#define THEME_FONT_BODY (&ui_font_14)
|
#define THEME_FONT_BODY (&ui_font_14)
|
||||||
#define THEME_FONT_TITLE (&ui_font_16)
|
#define THEME_FONT_TITLE (&ui_font_16)
|
||||||
@@ -33,4 +33,10 @@ namespace theme {
|
|||||||
#define UI_SYMBOL_STAR "\xEF\x80\x85" // U+F005, favourite
|
#define UI_SYMBOL_STAR "\xEF\x80\x85" // U+F005, favourite
|
||||||
#define UI_SYMBOL_MAP "\xEF\x89\xB9" // U+F279
|
#define UI_SYMBOL_MAP "\xEF\x89\xB9" // U+F279
|
||||||
#define UI_SYMBOL_USERS "\xEF\x83\x80" // U+F0C0, Nearby
|
#define UI_SYMBOL_USERS "\xEF\x83\x80" // U+F0C0, Nearby
|
||||||
|
#define UI_SYMBOL_COMPASS "\xEF\x85\x8E" // U+F14E, Navigate
|
||||||
|
#define UI_SYMBOL_FLAG "\xEF\x80\xA4" // U+F024, waypoint
|
||||||
|
#define UI_SYMBOL_PIN "\xEF\x8F\x85" // U+F3C5, mark here
|
||||||
|
#define UI_SYMBOL_CLOCK "\xEF\x80\x97" // U+F017, Clock tools
|
||||||
|
#define UI_SYMBOL_STOPWATCH "\xEF\x8B\xB2" // U+F2F2
|
||||||
|
#define UI_SYMBOL_RADIO "\xEF\x94\x99" // U+F519, broadcast tower
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
|
|
||||||
#include "../ui-core/UiCore.h" // shared UI Core (header-only, this TU)
|
#include "../ui-core/UiCore.h" // shared UI Core (header-only, this TU)
|
||||||
#include "../ui-core/NearbyModel.h"
|
#include "../ui-core/NearbyModel.h"
|
||||||
|
#include "../ui-core/EtaTracker.h"
|
||||||
|
#include "../ui-core/SettingsSchema.h"
|
||||||
|
#include "../ui-core/GpsAverager.h"
|
||||||
|
#include "../ui-core/TrackBack.h"
|
||||||
|
#include "../ui-core/RadioControl.h"
|
||||||
#include "Theme.h"
|
#include "Theme.h"
|
||||||
#include "LvglPort.h"
|
#include "LvglPort.h"
|
||||||
#include "../ui-core/KeyboardData.h"
|
#include "../ui-core/KeyboardData.h"
|
||||||
@@ -109,6 +114,7 @@ void UITask::begin(DisplayDriver* display_drv, SensorManager* sensors, NodePrefs
|
|||||||
lv_display_set_theme(lv_display_get_default(), th);
|
lv_display_set_theme(lv_display_get_default(), th);
|
||||||
|
|
||||||
buildStatusBar();
|
buildStatusBar();
|
||||||
|
applyDisplayPrefs(); // a slider percentage overrides the level main.cpp set
|
||||||
showHome();
|
showHome();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +132,8 @@ void UITask::loop() {
|
|||||||
s_sim_btn_click = false;
|
s_sim_btn_click = false;
|
||||||
#endif
|
#endif
|
||||||
if (btn_click) {
|
if (btn_click) {
|
||||||
if (_asleep) wake();
|
if (_core->clock.isRinging()) dismissRing();
|
||||||
|
else if (_asleep) wake();
|
||||||
else if (_screen == SCR_HOME) sleep();
|
else if (_screen == SCR_HOME) sleep();
|
||||||
else back();
|
else back();
|
||||||
}
|
}
|
||||||
@@ -135,12 +142,17 @@ void UITask::loop() {
|
|||||||
if (lvport::touched()) { lvport::swallowTouch(); wake(); }
|
if (lvport::touched()) { lvport::swallowTouch(); wake(); }
|
||||||
} else {
|
} else {
|
||||||
uint32_t aoff = autoOffMillis();
|
uint32_t aoff = autoOffMillis();
|
||||||
if (aoff > 0 && lv_display_get_inactive_time(NULL) > aoff) sleep();
|
if (aoff > 0 && lv_display_get_inactive_time(NULL) > aoff && !_core->clock.isRinging()) sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
_core->loop();
|
_core->loop();
|
||||||
drainCoreEvents();
|
drainCoreEvents();
|
||||||
|
checkLowBattery();
|
||||||
mapDownloadTick(); // a map download keeps running on any screen, and asleep
|
mapDownloadTick(); // a map download keeps running on any screen, and asleep
|
||||||
|
if ((int32_t)(millis() - _next_trackback_ms) >= 0) { // walking the trail back, on any screen
|
||||||
|
_next_trackback_ms = millis() + 1000;
|
||||||
|
navPollTrackBack();
|
||||||
|
}
|
||||||
|
|
||||||
if (!_asleep) {
|
if (!_asleep) {
|
||||||
if ((int32_t)(millis() - _next_status_ms) >= 0) {
|
if ((int32_t)(millis() - _next_status_ms) >= 0) {
|
||||||
@@ -148,6 +160,7 @@ void UITask::loop() {
|
|||||||
refreshStatusBar();
|
refreshStatusBar();
|
||||||
if (_screen == SCR_HOME) refreshHome();
|
if (_screen == SCR_HOME) refreshHome();
|
||||||
}
|
}
|
||||||
|
if (_screen == SCR_HOME) homeSwipePoll();
|
||||||
if ((_screen == SCR_NEARBY || _screen == SCR_NODE) && (int32_t)(millis() - _next_nearby_ms) >= 0) {
|
if ((_screen == SCR_NEARBY || _screen == SCR_NODE) && (int32_t)(millis() - _next_nearby_ms) >= 0) {
|
||||||
// Scan results trickle in over a few seconds: poll fast while scanning.
|
// Scan results trickle in over a few seconds: poll fast while scanning.
|
||||||
_next_nearby_ms = millis() + (_scanning ? 250 : 2000);
|
_next_nearby_ms = millis() + (_scanning ? 250 : 2000);
|
||||||
@@ -161,6 +174,10 @@ void UITask::loop() {
|
|||||||
}
|
}
|
||||||
if (_screen == SCR_MAP) mapLoop();
|
if (_screen == SCR_MAP) mapLoop();
|
||||||
if (_screen == SCR_WIFI) pollWifiScan();
|
if (_screen == SCR_WIFI) pollWifiScan();
|
||||||
|
if (_screen == SCR_CLOCK && (int32_t)(millis() - _next_clock_ms) >= 0) {
|
||||||
|
_next_clock_ms = millis() + 100; // stopwatch tenths
|
||||||
|
refreshClock();
|
||||||
|
}
|
||||||
if (_screen == SCR_THREAD && (int32_t)(millis() - _next_thread_check_ms) >= 0) {
|
if (_screen == SCR_THREAD && (int32_t)(millis() - _next_thread_check_ms) >= 0) {
|
||||||
_next_thread_check_ms = millis() + 500;
|
_next_thread_check_ms = millis() + 500;
|
||||||
uint32_t sig = threadSignature();
|
uint32_t sig = threadSignature();
|
||||||
@@ -188,6 +205,22 @@ void UITask::shutdown(bool restart) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Settings > Display & power > Battery shutdown (NodePrefs::low_batt_mv), as
|
||||||
|
// ui-new does it: a smoothed reading every 8 s, never while on USB power.
|
||||||
|
void UITask::checkLowBattery() {
|
||||||
|
if ((int32_t)(millis() - _next_batt_ms) < 0) return;
|
||||||
|
_next_batt_ms = millis() + 8000;
|
||||||
|
uint16_t raw = getBattMilliVolts();
|
||||||
|
if (raw > 0) _batt_mv = _batt_mv == 0 ? raw : (uint16_t)((_batt_mv * 4u + raw) / 5u); // EMA, alpha 0.2
|
||||||
|
uint16_t low = _prefs ? _prefs->low_batt_mv : 0;
|
||||||
|
if (low == 0 || _batt_mv == 0 || _batt_mv >= low || _board->isExternalPowered()) return;
|
||||||
|
wake();
|
||||||
|
showToast("Low battery - shutting down", 3000);
|
||||||
|
lv_timer_handler();
|
||||||
|
delay(2000);
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t UITask::autoOffMillis() const {
|
uint32_t UITask::autoOffMillis() const {
|
||||||
if (!_prefs || _prefs->auto_off_secs == 0) return 0;
|
if (!_prefs || _prefs->auto_off_secs == 0) return 0;
|
||||||
return (uint32_t)_prefs->auto_off_secs * 1000UL;
|
return (uint32_t)_prefs->auto_off_secs * 1000UL;
|
||||||
@@ -220,10 +253,10 @@ void UITask::drainCoreEvents() {
|
|||||||
onMessageArrived(ev);
|
onMessageArrived(ev);
|
||||||
break;
|
break;
|
||||||
case UiEventType::ClockAlert:
|
case UiEventType::ClockAlert:
|
||||||
wake();
|
showRing(ev.text);
|
||||||
showToast(ev.text, ClockEngine::RING_MS);
|
|
||||||
break;
|
break;
|
||||||
case UiEventType::ClockRingEnded:
|
case UiEventType::ClockRingEnded:
|
||||||
|
hideRing();
|
||||||
break;
|
break;
|
||||||
case UiEventType::LiveShareEnded:
|
case UiEventType::LiveShareEnded:
|
||||||
showToast("Live share ended");
|
showToast("Live share ended");
|
||||||
@@ -272,6 +305,7 @@ void UITask::buildStatusBar() {
|
|||||||
lv_obj_align(_status_time, LV_ALIGN_LEFT_MID, 0, 0);
|
lv_obj_align(_status_time, LV_ALIGN_LEFT_MID, 0, 0);
|
||||||
_status_icons = label(bar, "", THEME_FONT_SMALL, theme::TEXT_MUTED);
|
_status_icons = label(bar, "", THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
lv_obj_align(_status_icons, LV_ALIGN_RIGHT_MID, 0, 0);
|
lv_obj_align(_status_icons, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||||
|
_status_gps = label(bar, LV_SYMBOL_GPS, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
|
||||||
_toast = lv_obj_create(lv_layer_top());
|
_toast = lv_obj_create(lv_layer_top());
|
||||||
lv_obj_remove_flag(_toast, LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_remove_flag(_toast, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
@@ -284,7 +318,10 @@ void UITask::buildStatusBar() {
|
|||||||
lv_obj_set_style_pad_hor(_toast, 12, 0);
|
lv_obj_set_style_pad_hor(_toast, 12, 0);
|
||||||
lv_obj_set_style_pad_ver(_toast, 6, 0);
|
lv_obj_set_style_pad_ver(_toast, 6, 0);
|
||||||
lv_obj_align(_toast, LV_ALIGN_BOTTOM_MID, 0, -12);
|
lv_obj_align(_toast, LV_ALIGN_BOTTOM_MID, 0, -12);
|
||||||
label(_toast, "", THEME_FONT_BODY, theme::TEXT);
|
lv_obj_t* tl = label(_toast, "", THEME_FONT_BODY, theme::TEXT);
|
||||||
|
lv_label_set_long_mode(tl, LV_LABEL_LONG_WRAP); // long texts wrap instead of running off the screen
|
||||||
|
lv_obj_set_style_max_width(tl, lv_display_get_horizontal_resolution(NULL) - 40, 0);
|
||||||
|
lv_obj_set_style_text_align(tl, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
lv_obj_add_flag(_toast, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(_toast, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
refreshStatusBar();
|
refreshStatusBar();
|
||||||
@@ -305,15 +342,33 @@ void UITask::refreshStatusBar() {
|
|||||||
int pct = mv <= 3300 ? 0 : mv >= 4200 ? 100 : (int)(mv - 3300) * 100 / 900;
|
int pct = mv <= 3300 ? 0 : mv >= 4200 ? 100 : (int)(mv - 3300) * 100 / 900;
|
||||||
const char* batt = pct > 80 ? LV_SYMBOL_BATTERY_FULL : pct > 55 ? LV_SYMBOL_BATTERY_3
|
const char* batt = pct > 80 ? LV_SYMBOL_BATTERY_FULL : pct > 55 ? LV_SYMBOL_BATTERY_3
|
||||||
: pct > 30 ? LV_SYMBOL_BATTERY_2 : pct > 10 ? LV_SYMBOL_BATTERY_1 : LV_SYMBOL_BATTERY_EMPTY;
|
: pct > 30 ? LV_SYMBOL_BATTERY_2 : pct > 10 ? LV_SYMBOL_BATTERY_1 : LV_SYMBOL_BATTERY_EMPTY;
|
||||||
bool gps = false;
|
lv_label_set_text_fmt(_status_icons, "%s%s %d%%", hasConnection() ? LV_SYMBOL_BLUETOOTH " " : "", batt, pct);
|
||||||
if (_sensors) {
|
// GPS: green with a fix, muted while on and searching, absent when off.
|
||||||
LocationProvider* loc = _sensors->getLocationProvider();
|
int32_t lat, lon;
|
||||||
gps = loc && loc->isValid();
|
bool fix = _core->course.currentLocation(lat, lon);
|
||||||
|
if (_core->gpsEnabled() || fix) {
|
||||||
|
lv_obj_set_style_text_color(_status_gps, lv_color_hex(fix ? theme::OK : theme::TEXT_MUTED), 0);
|
||||||
|
lv_obj_remove_flag(_status_gps, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_align_to(_status_gps, _status_icons, LV_ALIGN_OUT_LEFT_MID, -8, 0);
|
||||||
|
} else {
|
||||||
|
lv_obj_add_flag(_status_gps, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
lv_label_set_text_fmt(_status_icons, "%s%s%s %d%%",
|
}
|
||||||
hasConnection() ? LV_SYMBOL_BLUETOOTH " " : "",
|
|
||||||
gps ? LV_SYMBOL_GPS " " : "",
|
void UITask::setGps(bool on) {
|
||||||
batt, pct);
|
if (!_core->setGpsEnabled(on)) { showToast("No GPS on this device"); return; }
|
||||||
|
showToast(on ? "GPS on, waiting for a fix" : "GPS off");
|
||||||
|
refreshStatusBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::botSetGPS(bool on) { if (_core->setGpsEnabled(on)) refreshStatusBar(); }
|
||||||
|
|
||||||
|
bool UITask::ensureGps() {
|
||||||
|
int32_t lat, lon;
|
||||||
|
if (_core->course.currentLocation(lat, lon)) return true;
|
||||||
|
if (_core->gpsAvailable() && !_core->gpsEnabled()) setGps(true);
|
||||||
|
else showToast("Waiting for a GPS fix");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// One persistent timer, paused between toasts: hides the toast when it fires.
|
// One persistent timer, paused between toasts: hides the toast when it fires.
|
||||||
@@ -347,7 +402,10 @@ lv_obj_t* UITask::newScreen(const char* title, bool with_back) {
|
|||||||
_node_info = _node_ping = _node_delete_lbl = nullptr;
|
_node_info = _node_ping = _node_delete_lbl = nullptr;
|
||||||
_scan_overlay = _scan_list = _scan_status = nullptr; // the popup went with the old screen
|
_scan_overlay = _scan_list = _scan_status = nullptr; // the popup went with the old screen
|
||||||
_map_area = _map_marks = _map_me = _map_zoom_lbl = _map_hint = _map_dl_pill = nullptr;
|
_map_area = _map_marks = _map_me = _map_zoom_lbl = _map_hint = _map_dl_pill = nullptr;
|
||||||
_dl_overlay = _dl_info = _dl_zoom_lbl = _dl_start_lbl = nullptr;
|
_dl_overlay = _dl_info = _dl_zoom_lbl = _dl_start_lbl = _dl_job_row = _dl_job_lbl = nullptr;
|
||||||
|
_nav_bar = _nav_title = _nav_info = _nav_clear = nullptr;
|
||||||
|
_nav_overlay = _nav_ta = _nav_kb = _nav_del_lbl = _nav_rec = _nav_avg_pill = nullptr;
|
||||||
|
_nav_trail_lbl = _nav_trail_btn = _nav_reset_lbl = _nav_share_lbl = _nav_share_btn = _nav_tb_btn = nullptr;
|
||||||
_wifi_ssid = _wifi_pass = _wifi_kb = _wifi_list = _wifi_status = nullptr;
|
_wifi_ssid = _wifi_pass = _wifi_kb = _wifi_list = _wifi_status = nullptr;
|
||||||
_wifi_scanning = false;
|
_wifi_scanning = false;
|
||||||
for (lv_obj_t*& t : _map_tiles) t = nullptr;
|
for (lv_obj_t*& t : _map_tiles) t = nullptr;
|
||||||
@@ -398,19 +456,24 @@ void UITask::back() {
|
|||||||
case SCR_THREAD: showChats(); break;
|
case SCR_THREAD: showChats(); break;
|
||||||
case SCR_CONTACTS: showChats(); break;
|
case SCR_CONTACTS: showChats(); break;
|
||||||
case SCR_SETTINGS: showHome(); break;
|
case SCR_SETTINGS: showHome(); break;
|
||||||
|
case SCR_SETTINGS_NAV: showSettings(); break;
|
||||||
|
case SCR_CLOCK: showHome(); break;
|
||||||
|
case SCR_RADIO: if (radioPopupOpen()) radioCloseFreq(); else showSettings(); break;
|
||||||
case SCR_CHATS: showHome(); break;
|
case SCR_CHATS: showHome(); break;
|
||||||
case SCR_NEARBY:
|
case SCR_NEARBY:
|
||||||
if (_scan_overlay) closeScanPopup();
|
if (_scan_overlay) closeScanPopup();
|
||||||
else showHome();
|
else showHome();
|
||||||
break;
|
break;
|
||||||
case SCR_NODE: // back to where the node was picked: map, the list, or the scan popup over it
|
case SCR_NODE: // back to where the node was picked: map, the list, or the scan popup over it
|
||||||
if (_node_from_map) { showMap(); break; }
|
if (_node_from_map) { openMap(false); break; }
|
||||||
_screen = SCR_NEARBY;
|
_screen = SCR_NEARBY;
|
||||||
buildNearby();
|
buildNearby();
|
||||||
if (_node_from_scan) showScanPopup();
|
if (_node_from_scan) showScanPopup();
|
||||||
break;
|
break;
|
||||||
case SCR_MAP:
|
case SCR_MAP:
|
||||||
if (_dl_overlay) mapDownloadClose();
|
if (_nav_overlay) navClosePopup();
|
||||||
|
else if (_dl_overlay) mapDownloadClose();
|
||||||
|
else if (!_map_nav) showNearby(); // the Nodes map opens from Nearby
|
||||||
else showHome();
|
else showHome();
|
||||||
break;
|
break;
|
||||||
case SCR_WIFI: if (_wifi_from_map) showMap(); else showSettings(); break;
|
case SCR_WIFI: if (_wifi_from_map) showMap(); else showSettings(); break;
|
||||||
@@ -424,9 +487,40 @@ static void onOpenChats(lv_event_t* e) { (void)e; s_ui->showChats(); }
|
|||||||
static void onOpenSettings(lv_event_t* e) { (void)e; s_ui->showSettings(); }
|
static void onOpenSettings(lv_event_t* e) { (void)e; s_ui->showSettings(); }
|
||||||
|
|
||||||
static void onOpenNearby(lv_event_t* e) { (void)e; s_ui->showNearby(); }
|
static void onOpenNearby(lv_event_t* e) { (void)e; s_ui->showNearby(); }
|
||||||
static void onOpenMap(lv_event_t* e) { (void)e; s_ui->showMap(); }
|
static void onOpenNodesMap(lv_event_t* e) { (void)e; s_ui->openMap(false); }
|
||||||
|
static void onOpenNav(lv_event_t* e) { (void)e; s_ui->openMap(true); }
|
||||||
|
static void onOpenClock(lv_event_t* e); // ClockScreen.h
|
||||||
|
|
||||||
// Home tile: icon over label, one of a row of three; optional amber value
|
// Home apps, in order; PER_PAGE to a page, further pages are swiped to (with
|
||||||
|
// dots underneath), so new apps don't squeeze the row.
|
||||||
|
namespace home {
|
||||||
|
struct App { const char* icon; const char* text; lv_event_cb_t cb; bool unread; };
|
||||||
|
static const App APPS[] = {
|
||||||
|
{ LV_SYMBOL_ENVELOPE, "Messages", onOpenChats, true },
|
||||||
|
{ UI_SYMBOL_USERS, "Nearby", onOpenNearby, false },
|
||||||
|
{ UI_SYMBOL_MAP, "Map", onOpenNav, false },
|
||||||
|
{ LV_SYMBOL_SETTINGS, "Settings", onOpenSettings, false },
|
||||||
|
// Page 2: tools
|
||||||
|
{ UI_SYMBOL_CLOCK, "Clock", onOpenClock, false },
|
||||||
|
};
|
||||||
|
static const int COUNT = sizeof(APPS) / sizeof(APPS[0]);
|
||||||
|
static const int PER_PAGE = 4;
|
||||||
|
static const int PAGES = (COUNT + PER_PAGE - 1) / PER_PAGE;
|
||||||
|
static lv_obj_t* s_row = nullptr; // the current page's tiles
|
||||||
|
static lv_obj_t* s_dots = nullptr;
|
||||||
|
static int s_page = 0; // kept across rebuilds (the home screen is rebuilt on return)
|
||||||
|
|
||||||
|
// A horizontal swipe anywhere on Home turns the page (the tiles row alone is
|
||||||
|
// too small a target), tracked from the touch itself: LVGL's gesture detector
|
||||||
|
// drops a slow swipe (its sum resets on every read without movement). Tapping
|
||||||
|
// a dot also goes to that page.
|
||||||
|
static bool s_touching = false, s_swiped = false;
|
||||||
|
static lv_point_t s_start;
|
||||||
|
static const int SWIPE_PX = 40;
|
||||||
|
static void onDot(lv_event_t* e) { s_ui->setHomePage((int)(uintptr_t)lv_event_get_user_data(e)); }
|
||||||
|
} // namespace home
|
||||||
|
|
||||||
|
// Home tile: icon over label, one of a page's row; optional amber value
|
||||||
// (unread count) in its top-right corner.
|
// (unread count) in its top-right corner.
|
||||||
static lv_obj_t* homeTile(lv_obj_t* parent, const char* icon, const char* text, lv_event_cb_t cb,
|
static lv_obj_t* homeTile(lv_obj_t* parent, const char* icon, const char* text, lv_event_cb_t cb,
|
||||||
lv_obj_t** value_out) {
|
lv_obj_t** value_out) {
|
||||||
@@ -450,6 +544,7 @@ static lv_obj_t* homeTile(lv_obj_t* parent, const char* icon, const char* text,
|
|||||||
|
|
||||||
void UITask::showHome() {
|
void UITask::showHome() {
|
||||||
_screen = SCR_HOME;
|
_screen = SCR_HOME;
|
||||||
|
_share_text[0] = '\0'; // a share not sent to anyone
|
||||||
buildHome();
|
buildHome();
|
||||||
refreshHome();
|
refreshHome();
|
||||||
}
|
}
|
||||||
@@ -463,16 +558,72 @@ void UITask::buildHome() {
|
|||||||
lv_obj_t* name = label(body, the_mesh.getNodeName(), THEME_FONT_BODY, theme::ACCENT);
|
lv_obj_t* name = label(body, the_mesh.getNodeName(), THEME_FONT_BODY, theme::ACCENT);
|
||||||
lv_obj_set_style_pad_bottom(name, 4, 0);
|
lv_obj_set_style_pad_bottom(name, 4, 0);
|
||||||
|
|
||||||
lv_obj_t* tiles = lv_obj_create(body);
|
lv_obj_remove_flag(body, LV_OBJ_FLAG_SCROLLABLE); // a drag is a page swipe, not a scroll
|
||||||
styleSurface(tiles, theme::BG);
|
home::s_row = lv_obj_create(body);
|
||||||
lv_obj_remove_flag(tiles, LV_OBJ_FLAG_SCROLLABLE);
|
styleSurface(home::s_row, theme::BG);
|
||||||
lv_obj_set_size(tiles, LV_PCT(100), LV_SIZE_CONTENT);
|
lv_obj_remove_flag(home::s_row, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
lv_obj_set_flex_flow(tiles, LV_FLEX_FLOW_ROW);
|
lv_obj_set_size(home::s_row, LV_PCT(100), LV_SIZE_CONTENT);
|
||||||
lv_obj_set_style_pad_column(tiles, theme::GAP, 0);
|
lv_obj_set_flex_flow(home::s_row, LV_FLEX_FLOW_ROW);
|
||||||
homeTile(tiles, LV_SYMBOL_ENVELOPE, "Messages", onOpenChats, &_home_unread);
|
lv_obj_set_style_pad_column(home::s_row, theme::GAP, 0);
|
||||||
homeTile(tiles, UI_SYMBOL_USERS, "Nearby", onOpenNearby, NULL);
|
home::s_dots = nullptr;
|
||||||
homeTile(tiles, UI_SYMBOL_MAP, "Map", onOpenMap, NULL);
|
if (home::PAGES > 1) {
|
||||||
homeTile(tiles, LV_SYMBOL_SETTINGS, "Settings", onOpenSettings, NULL);
|
home::s_dots = lv_obj_create(body);
|
||||||
|
lv_obj_remove_style_all(home::s_dots);
|
||||||
|
lv_obj_set_size(home::s_dots, LV_SIZE_CONTENT, 22);
|
||||||
|
lv_obj_set_flex_flow(home::s_dots, LV_FLEX_FLOW_ROW);
|
||||||
|
lv_obj_set_flex_align(home::s_dots, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
|
lv_obj_set_style_pad_column(home::s_dots, 12, 0);
|
||||||
|
for (int p = 0; p < home::PAGES; p++) {
|
||||||
|
lv_obj_t* d = lv_obj_create(home::s_dots);
|
||||||
|
lv_obj_remove_style_all(d);
|
||||||
|
lv_obj_set_size(d, 8, 8);
|
||||||
|
lv_obj_set_style_radius(d, LV_RADIUS_CIRCLE, 0);
|
||||||
|
lv_obj_set_style_bg_opa(d, LV_OPA_COVER, 0);
|
||||||
|
lv_obj_set_ext_click_area(d, 8);
|
||||||
|
lv_obj_add_flag(d, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_add_event_cb(d, home::onDot, LV_EVENT_CLICKED, (void*)(uintptr_t)p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setHomePage(home::s_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From loop() on Home: turn the page once a press has moved SWIPE_PX sideways.
|
||||||
|
void UITask::homeSwipePoll() {
|
||||||
|
lv_indev_t* in = lv_indev_get_next(NULL);
|
||||||
|
if (!in || home::PAGES < 2) return;
|
||||||
|
bool down = lv_indev_get_state(in) == LV_INDEV_STATE_PRESSED;
|
||||||
|
lv_point_t p;
|
||||||
|
lv_indev_get_point(in, &p);
|
||||||
|
if (!down) { home::s_touching = false; return; }
|
||||||
|
if (!home::s_touching) { home::s_touching = true; home::s_swiped = false; home::s_start = p; return; }
|
||||||
|
if (home::s_swiped) return;
|
||||||
|
int dx = p.x - home::s_start.x, dy = p.y - home::s_start.y;
|
||||||
|
if (abs(dx) < home::SWIPE_PX || abs(dx) < 2 * abs(dy)) return;
|
||||||
|
home::s_swiped = true;
|
||||||
|
lv_indev_wait_release(in); // the swipe isn't also a tap on the tile it started on
|
||||||
|
setHomePage(home::s_page + (dx < 0 ? 1 : -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::setHomePage(int page) {
|
||||||
|
if (_screen != SCR_HOME || !home::s_row) return; // s_row went with an older screen
|
||||||
|
if (page < 0 || page >= home::PAGES) return;
|
||||||
|
home::s_page = page;
|
||||||
|
lv_obj_clean(home::s_row);
|
||||||
|
_home_unread = nullptr;
|
||||||
|
for (int i = page * home::PER_PAGE; i < (page + 1) * home::PER_PAGE; i++) {
|
||||||
|
if (i < home::COUNT) {
|
||||||
|
const home::App& a = home::APPS[i];
|
||||||
|
homeTile(home::s_row, a.icon, a.text, a.cb, a.unread ? &_home_unread : NULL);
|
||||||
|
} else { // keep a short last page's tiles the same width
|
||||||
|
lv_obj_t* gap = lv_obj_create(home::s_row);
|
||||||
|
lv_obj_remove_style_all(gap);
|
||||||
|
lv_obj_set_height(gap, 1);
|
||||||
|
lv_obj_set_flex_grow(gap, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; home::s_dots && i < (int)lv_obj_get_child_count(home::s_dots); i++)
|
||||||
|
lv_obj_set_style_bg_color(lv_obj_get_child(home::s_dots, i), lv_color_hex(i == page ? theme::ACCENT : theme::SURFACE_2), 0);
|
||||||
|
refreshHome();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::refreshHome() {
|
void UITask::refreshHome() {
|
||||||
@@ -491,6 +642,7 @@ void UITask::refreshHome() {
|
|||||||
lv_label_set_text(_home_clock, "--:--");
|
lv_label_set_text(_home_clock, "--:--");
|
||||||
lv_label_set_text(_home_date, "time not synced");
|
lv_label_set_text(_home_date, "time not synced");
|
||||||
}
|
}
|
||||||
|
if (!_home_unread) return;
|
||||||
int unread = _core->dmUnreadTotal() + _core->history.getTotalChannelUnread() + _core->roomUnread();
|
int unread = _core->dmUnreadTotal() + _core->history.getTotalChannelUnread() + _core->roomUnread();
|
||||||
if (unread > 0) lv_label_set_text_fmt(_home_unread, "%d", unread);
|
if (unread > 0) lv_label_set_text_fmt(_home_unread, "%d", unread);
|
||||||
else lv_label_set_text(_home_unread, "");
|
else lv_label_set_text(_home_unread, "");
|
||||||
@@ -532,7 +684,7 @@ static lv_obj_t* listRow(lv_obj_t* parent, const char* title, const char* sub,
|
|||||||
if (sub) {
|
if (sub) {
|
||||||
lv_obj_t* s = label(row, sub, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
lv_obj_t* s = label(row, sub, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
lv_label_set_long_mode(s, LV_LABEL_LONG_DOT);
|
lv_label_set_long_mode(s, LV_LABEL_LONG_DOT);
|
||||||
lv_obj_set_width(s, 230);
|
lv_obj_set_size(s, 230, 15); // fixed height: LONG_DOT cuts instead of wrapping over the title
|
||||||
lv_obj_align(s, LV_ALIGN_BOTTOM_LEFT, theme::PAD, -5);
|
lv_obj_align(s, LV_ALIGN_BOTTOM_LEFT, theme::PAD, -5);
|
||||||
}
|
}
|
||||||
return row;
|
return row;
|
||||||
@@ -631,7 +783,7 @@ void UITask::buildContacts() {
|
|||||||
// model, since it is a different set: who is in range, not who is known.
|
// model, since it is a different set: who is in range, not who is known.
|
||||||
|
|
||||||
static NearbyModel::Entry s_node; // the node open in SCR_NODE (a copy: the list re-sorts)
|
static NearbyModel::Entry s_node; // the node open in SCR_NODE (a copy: the list re-sorts)
|
||||||
enum : uint8_t { NODE_MSG, NODE_PING, NODE_FAV, NODE_ADD, NODE_DELETE };
|
enum : uint8_t { NODE_MSG, NODE_PING, NODE_FAV, NODE_ADD, NODE_DELETE, NODE_NAV };
|
||||||
|
|
||||||
static void onNearbyChip(lv_event_t* e) { s_ui->setNearbyFilter((uint8_t)(uintptr_t)lv_event_get_user_data(e)); }
|
static void onNearbyChip(lv_event_t* e) { s_ui->setNearbyFilter((uint8_t)(uintptr_t)lv_event_get_user_data(e)); }
|
||||||
static void onNearbySort(lv_event_t* e) { (void)e; s_ui->toggleNearbySort(); }
|
static void onNearbySort(lv_event_t* e) { (void)e; s_ui->toggleNearbySort(); }
|
||||||
@@ -668,7 +820,8 @@ void UITask::buildNearby() {
|
|||||||
lv_obj_set_style_pad_row(body, 4, 0);
|
lv_obj_set_style_pad_row(body, 4, 0);
|
||||||
if (_header) {
|
if (_header) {
|
||||||
headerButton(_header, LV_SYMBOL_REFRESH " Scan", onNearbyScan, 4, NULL);
|
headerButton(_header, LV_SYMBOL_REFRESH " Scan", onNearbyScan, 4, NULL);
|
||||||
headerButton(_header, "", onNearbySort, 84, &_nearby_sort_lbl);
|
lv_obj_set_width(headerButton(_header, "", onNearbySort, 84, &_nearby_sort_lbl), 62); // fits "Recent" / "Dist"
|
||||||
|
headerButton(_header, UI_SYMBOL_MAP, onOpenNodesMap, 152, NULL); // the Nodes map
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type filter chips
|
// Type filter chips
|
||||||
@@ -939,6 +1092,7 @@ void UITask::buildNode() {
|
|||||||
bool contact = e.contact_idx >= 0;
|
bool contact = e.contact_idx >= 0;
|
||||||
if (contact && e.type == ADV_TYPE_CHAT) actionButton(acts, LV_SYMBOL_ENVELOPE " Message", NODE_MSG, true);
|
if (contact && e.type == ADV_TYPE_CHAT) actionButton(acts, LV_SYMBOL_ENVELOPE " Message", NODE_MSG, true);
|
||||||
if (e.has_key) actionButton(acts, LV_SYMBOL_LOOP " Ping", NODE_PING, false);
|
if (e.has_key) actionButton(acts, LV_SYMBOL_LOOP " Ping", NODE_PING, false);
|
||||||
|
if (e.lat_e6 != 0 || e.lon_e6 != 0) actionButton(acts, UI_SYMBOL_COMPASS, NODE_NAV, false);
|
||||||
if (contact) actionButton(acts, e.fav ? UI_SYMBOL_STAR " Unfav" : UI_SYMBOL_STAR " Fav", NODE_FAV, false);
|
if (contact) actionButton(acts, e.fav ? UI_SYMBOL_STAR " Unfav" : UI_SYMBOL_STAR " Fav", NODE_FAV, false);
|
||||||
if (!contact && e.has_key && !e.is_known) actionButton(acts, LV_SYMBOL_PLUS " Add", NODE_ADD, true);
|
if (!contact && e.has_key && !e.is_known) actionButton(acts, LV_SYMBOL_PLUS " Add", NODE_ADD, true);
|
||||||
if (contact) _node_delete_lbl = actionButton(acts, LV_SYMBOL_TRASH, NODE_DELETE, false);
|
if (contact) _node_delete_lbl = actionButton(acts, LV_SYMBOL_TRASH, NODE_DELETE, false);
|
||||||
@@ -1046,6 +1200,17 @@ void UITask::nodeAction(uint8_t action) {
|
|||||||
showToast("Contacts full");
|
showToast("Contacts full");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NODE_NAV:
|
||||||
|
// Followed by key when there is one (the Locator resolves live share,
|
||||||
|
// then advert position); otherwise a fixed point where it was seen.
|
||||||
|
if (e.has_prefix) navToNode(e.pub_key, e.lat_e6, e.lon_e6, e.name[0] ? e.name : "Node");
|
||||||
|
else {
|
||||||
|
_core->locator.setTarget(0, nullptr, e.lat_e6, e.lon_e6, e.name[0] ? e.name : "Node");
|
||||||
|
the_mesh.savePrefs();
|
||||||
|
openMap(true);
|
||||||
|
navFrameTarget();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case NODE_DELETE:
|
case NODE_DELETE:
|
||||||
if (!_delete_armed_ms) { // destructive: second tap within 3 s confirms
|
if (!_delete_armed_ms) { // destructive: second tap within 3 s confirms
|
||||||
_delete_armed_ms = millis();
|
_delete_armed_ms = millis();
|
||||||
@@ -1063,6 +1228,9 @@ void UITask::nodeAction(uint8_t action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "MapScreen.h"
|
#include "MapScreen.h"
|
||||||
|
#include "NavMap.h"
|
||||||
|
#include "ClockScreen.h"
|
||||||
|
#include "RadioScreen.h"
|
||||||
#include "WifiScreen.h"
|
#include "WifiScreen.h"
|
||||||
|
|
||||||
// ── Conversation ──────────────────────────────────────────────────────────────
|
// ── Conversation ──────────────────────────────────────────────────────────────
|
||||||
@@ -1194,6 +1362,12 @@ void UITask::buildThread() {
|
|||||||
lv_obj_add_event_cb(_compose_ta, onComposeClicked, LV_EVENT_CLICKED, _keyboard);
|
lv_obj_add_event_cb(_compose_ta, onComposeClicked, LV_EVENT_CLICKED, _keyboard);
|
||||||
}
|
}
|
||||||
refreshThread();
|
refreshThread();
|
||||||
|
if (_compose_ta && _share_text[0]) { // shareToMessage(): the text waits in the field
|
||||||
|
lv_textarea_set_text(_compose_ta, _share_text);
|
||||||
|
_share_text[0] = '\0';
|
||||||
|
lv_obj_update_layout(lv_screen_active());
|
||||||
|
setKeyboardVisible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes whenever the open conversation's content or delivery markers change.
|
// Changes whenever the open conversation's content or delivery markers change.
|
||||||
@@ -1218,9 +1392,34 @@ uint32_t UITask::threadSignature() const {
|
|||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Positions found in the shown messages ([WAY] / [LOC] / plain "lat,lon"),
|
||||||
|
// for the Go / Save buttons under such a bubble.
|
||||||
|
struct MsgLoc { int32_t lat, lon; char label[WAYPOINT_LABEL_LEN * 2]; };
|
||||||
|
static const int THREAD_MAX_SHOWN = 30;
|
||||||
|
static MsgLoc s_msg_locs[THREAD_MAX_SHOWN];
|
||||||
|
static int s_msg_loc_n = 0;
|
||||||
|
|
||||||
|
static void onMsgLoc(lv_event_t* e) {
|
||||||
|
uintptr_t v = (uintptr_t)lv_event_get_user_data(e);
|
||||||
|
s_ui->messageLocationAction((int)(v >> 1), (v & 1) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msgLocButton(lv_obj_t* parent, const char* text, int idx, bool save, bool accent) {
|
||||||
|
lv_obj_t* b = lv_button_create(parent);
|
||||||
|
lv_obj_set_size(b, LV_SIZE_CONTENT, 28);
|
||||||
|
lv_obj_set_style_pad_hor(b, 10, 0);
|
||||||
|
lv_obj_set_style_pad_ver(b, 0, 0);
|
||||||
|
lv_obj_set_style_radius(b, 14, 0);
|
||||||
|
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||||
|
lv_obj_set_style_bg_color(b, lv_color_hex(accent ? theme::ACCENT : theme::SURFACE_2), 0);
|
||||||
|
lv_obj_add_event_cb(b, onMsgLoc, LV_EVENT_CLICKED, (void*)(uintptr_t)((idx << 1) | (save ? 1 : 0)));
|
||||||
|
lv_obj_center(label(b, text, THEME_FONT_SMALL, accent ? theme::BG : theme::TEXT));
|
||||||
|
}
|
||||||
|
|
||||||
// One message bubble. Own messages right-aligned in amber, others left.
|
// One message bubble. Own messages right-aligned in amber, others left.
|
||||||
|
// loc_idx >= 0: the text carries a position (s_msg_locs[loc_idx]).
|
||||||
static void bubble(lv_obj_t* list, const char* from, const char* text, bool own,
|
static void bubble(lv_obj_t* list, const char* from, const char* text, bool own,
|
||||||
uint32_t ts, const char* status, uint32_t status_col) {
|
uint32_t ts, const char* status, uint32_t status_col, int loc_idx = -1) {
|
||||||
// Full-width row that pushes the bubble to its side.
|
// Full-width row that pushes the bubble to its side.
|
||||||
lv_obj_t* row = lv_obj_create(list);
|
lv_obj_t* row = lv_obj_create(list);
|
||||||
styleSurface(row, theme::BG);
|
styleSurface(row, theme::BG);
|
||||||
@@ -1267,6 +1466,20 @@ static void bubble(lv_obj_t* list, const char* from, const char* text, bool own,
|
|||||||
lv_obj_set_style_max_width(t, 238, 0);
|
lv_obj_set_style_max_width(t, 238, 0);
|
||||||
lv_obj_set_width(t, LV_SIZE_CONTENT);
|
lv_obj_set_width(t, LV_SIZE_CONTENT);
|
||||||
|
|
||||||
|
if (loc_idx >= 0) { // position: navigate there / keep it as a waypoint
|
||||||
|
lv_obj_t* acts = lv_obj_create(b);
|
||||||
|
styleSurface(acts, theme::BG);
|
||||||
|
lv_obj_set_style_bg_opa(acts, LV_OPA_TRANSP, 0);
|
||||||
|
lv_obj_remove_flag(acts, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_remove_flag(acts, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_set_size(acts, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||||
|
lv_obj_set_flex_flow(acts, LV_FLEX_FLOW_ROW);
|
||||||
|
lv_obj_set_style_pad_column(acts, 6, 0);
|
||||||
|
lv_obj_set_style_pad_top(acts, 2, 0);
|
||||||
|
msgLocButton(acts, UI_SYMBOL_COMPASS " Go", loc_idx, false, true);
|
||||||
|
msgLocButton(acts, UI_SYMBOL_FLAG " Save", loc_idx, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!meta_in_header) {
|
if (!meta_in_header) {
|
||||||
lv_obj_t* m = label(b, meta, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
lv_obj_t* m = label(b, meta, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
if (status) {
|
if (status) {
|
||||||
@@ -1276,13 +1489,43 @@ static void bubble(lv_obj_t* list, const char* from, const char* text, bool own,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remember the position in `text` (if any) for its bubble's buttons; label
|
||||||
|
// from a [WAY] tag, else the sender. Returns the slot or -1.
|
||||||
|
static int noteMsgLocation(const char* text, const char* sender) {
|
||||||
|
if (s_msg_loc_n >= THREAD_MAX_SHOWN) return -1;
|
||||||
|
MsgLoc& m = s_msg_locs[s_msg_loc_n];
|
||||||
|
if (!geo::parseLatLon(text, m.lat, m.lon, m.label, sizeof(m.label))) return -1;
|
||||||
|
if (!m.label[0]) snprintf(m.label, sizeof(m.label), "%s", sender && sender[0] ? sender : "Msg loc");
|
||||||
|
return s_msg_loc_n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::messageLocationAction(int idx, bool save) {
|
||||||
|
if (idx < 0 || idx >= s_msg_loc_n) return;
|
||||||
|
const MsgLoc& m = s_msg_locs[idx];
|
||||||
|
if (save) {
|
||||||
|
if (_core->waypoints.full()) { showToast("Waypoints full (16)"); return; }
|
||||||
|
if (_core->waypoints.add(m.lat, m.lon, rtc_clock.getCurrentTime(), m.label)) {
|
||||||
|
char t[48];
|
||||||
|
snprintf(t, sizeof(t), "Saved %s", _core->waypoints.at(_core->waypoints.count() - 1).label);
|
||||||
|
showToast(t);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// A place snapshotted from the text (kind 0): nothing to keep re-resolving.
|
||||||
|
navSetTarget(0, nullptr, m.lat, m.lon, m.label);
|
||||||
|
openMap(true);
|
||||||
|
navFrameTarget();
|
||||||
|
refreshNavBar();
|
||||||
|
}
|
||||||
|
|
||||||
void UITask::refreshThread() {
|
void UITask::refreshThread() {
|
||||||
if (!_thread_list) return;
|
if (!_thread_list) return;
|
||||||
_thread_dirty = false;
|
_thread_dirty = false;
|
||||||
_thread_sig = threadSignature();
|
_thread_sig = threadSignature();
|
||||||
lv_obj_clean(_thread_list);
|
lv_obj_clean(_thread_list);
|
||||||
const MessageHistory& h = _core->history;
|
const MessageHistory& h = _core->history;
|
||||||
const int MAX_SHOWN = 30;
|
const int MAX_SHOWN = THREAD_MAX_SHOWN;
|
||||||
|
s_msg_loc_n = 0;
|
||||||
|
|
||||||
if (_thread_is_channel) {
|
if (_thread_is_channel) {
|
||||||
int n = h.histCountForChannel(_thread_channel);
|
int n = h.histCountForChannel(_thread_channel);
|
||||||
@@ -1302,7 +1545,8 @@ void UITask::refreshThread() {
|
|||||||
const char* st = NULL; uint32_t col = theme::TEXT_MUTED;
|
const char* st = NULL; uint32_t col = theme::TEXT_MUTED;
|
||||||
if (own && e.relay_status == ACK_OK) { st = LV_SYMBOL_OK " relayed"; col = theme::OK; }
|
if (own && e.relay_status == ACK_OK) { st = LV_SYMBOL_OK " relayed"; col = theme::OK; }
|
||||||
else if (own && e.relay_status == ACK_PENDING) st = "sent";
|
else if (own && e.relay_status == ACK_PENDING) st = "sent";
|
||||||
bubble(_thread_list, own ? NULL : from, body, own, e.timestamp, st, col);
|
bubble(_thread_list, own ? NULL : from, body, own, e.timestamp, st, col,
|
||||||
|
own ? -1 : noteMsgLocation(body, from));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int n = h.dmHistCountForContact(_thread_key);
|
int n = h.dmHistCountForContact(_thread_key);
|
||||||
@@ -1318,7 +1562,10 @@ void UITask::refreshThread() {
|
|||||||
default: st = "sent"; break;
|
default: st = "sent"; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bubble(_thread_list, NULL, e.text, e.outgoing, e.timestamp, st, col);
|
char who[33] = "";
|
||||||
|
if (!e.outgoing) contactName(_thread_key, who, sizeof(who));
|
||||||
|
bubble(_thread_list, NULL, e.text, e.outgoing, e.timestamp, st, col,
|
||||||
|
e.outgoing ? -1 : noteMsgLocation(e.text, who));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lv_obj_get_child_count(_thread_list) == 0)
|
if (lv_obj_get_child_count(_thread_list) == 0)
|
||||||
@@ -1375,12 +1622,197 @@ static lv_obj_t* dropdownRow(lv_obj_t* parent, const char* text, const char* opt
|
|||||||
return dd;
|
return dd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A preference toggle (0/1 byte in NodePrefs), saved on change.
|
||||||
|
static void onPrefSwitch(lv_event_t* e) {
|
||||||
|
uint8_t* pref = (uint8_t*)lv_event_get_user_data(e);
|
||||||
|
*pref = lv_obj_has_state((lv_obj_t*)lv_event_get_target(e), LV_STATE_CHECKED) ? 1 : 0;
|
||||||
|
the_mesh.savePrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onGpsSwitch(lv_event_t* e) {
|
||||||
|
s_ui->setGps(lv_obj_has_state((lv_obj_t*)lv_event_get_target(e), LV_STATE_CHECKED));
|
||||||
|
}
|
||||||
|
|
||||||
|
// pref == nullptr: the caller wires the switch itself.
|
||||||
|
static lv_obj_t* switchRow(lv_obj_t* parent, const char* text, const char* sub, uint8_t* pref) {
|
||||||
|
lv_obj_t* row = lv_obj_create(parent);
|
||||||
|
styleSurface(row, theme::SURFACE);
|
||||||
|
lv_obj_remove_flag(row, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_set_size(row, LV_PCT(100), theme::ROW_H);
|
||||||
|
lv_obj_set_style_radius(row, theme::RADIUS, 0);
|
||||||
|
lv_obj_t* l = label(row, text, THEME_FONT_BODY, theme::TEXT);
|
||||||
|
lv_obj_align(l, LV_ALIGN_TOP_LEFT, theme::PAD, sub ? 5 : 13);
|
||||||
|
if (sub) {
|
||||||
|
lv_obj_t* h = label(row, sub, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
lv_label_set_long_mode(h, LV_LABEL_LONG_DOT);
|
||||||
|
lv_obj_set_size(h, 236, 15); // clear of the switch
|
||||||
|
lv_obj_align(h, LV_ALIGN_BOTTOM_LEFT, theme::PAD, -5);
|
||||||
|
}
|
||||||
|
lv_obj_t* sw = lv_switch_create(row);
|
||||||
|
lv_obj_set_size(sw, 46, 24);
|
||||||
|
lv_obj_align(sw, LV_ALIGN_RIGHT_MID, -theme::PAD, 0);
|
||||||
|
if (pref) {
|
||||||
|
if (*pref) lv_obj_add_state(sw, LV_STATE_CHECKED);
|
||||||
|
lv_obj_add_event_cb(sw, onPrefSwitch, LV_EVENT_VALUE_CHANGED, pref);
|
||||||
|
}
|
||||||
|
return sw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Schema-driven settings (ui-core/SettingsSchema.h) ─────────────────────────
|
||||||
|
|
||||||
|
static void onSchemaSwitch(lv_event_t* e) {
|
||||||
|
s_ui->setSchemaValue((int)(uintptr_t)lv_event_get_user_data(e),
|
||||||
|
lv_obj_has_state((lv_obj_t*)lv_event_get_target(e), LV_STATE_CHECKED) ? 1 : 0);
|
||||||
|
}
|
||||||
|
static void onSchemaDropdown(lv_event_t* e) {
|
||||||
|
s_ui->setSchemaValue((int)(uintptr_t)lv_event_get_user_data(e),
|
||||||
|
(int)lv_dropdown_get_selected((lv_obj_t*)lv_event_get_target(e)));
|
||||||
|
}
|
||||||
|
static void onOpenSchemaPage(lv_event_t* e) { s_ui->showSchemaSettings((int)(uintptr_t)lv_event_get_user_data(e)); }
|
||||||
|
static void onPruneContacts(lv_event_t* e) { (void)e; s_ui->pruneContacts(); }
|
||||||
|
|
||||||
|
void UITask::showSchemaSettings(int page) {
|
||||||
|
_screen = SCR_SETTINGS_NAV;
|
||||||
|
_settings_page = (uint8_t)(page < settings::PG_COUNT ? page : 0);
|
||||||
|
buildSchemaSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contacts > prune now: first tap shows how many, the second (within 3 s) removes them.
|
||||||
|
void UITask::pruneContacts() {
|
||||||
|
int n = the_mesh.countStaleContacts();
|
||||||
|
if (n == 0) {
|
||||||
|
showToast(_prefs && _prefs->contact_expiry_idx == 0 ? "Contact expiry is off" : "No inactive contacts");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_prune_armed_ms || millis() - _prune_armed_ms > 3000) {
|
||||||
|
_prune_armed_ms = millis() | 1;
|
||||||
|
if (_prune_lbl) lv_label_set_text_fmt(_prune_lbl, LV_SYMBOL_TRASH " Remove %d contact%s?", n, n == 1 ? "" : "s");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_prune_armed_ms = 0;
|
||||||
|
int removed = the_mesh.pruneStaleContacts();
|
||||||
|
char t[40];
|
||||||
|
snprintf(t, sizeof(t), "Removed %d contact%s", removed, removed == 1 ? "" : "s");
|
||||||
|
showToast(t);
|
||||||
|
if (_prune_lbl) lv_label_set_text(_prune_lbl, LV_SYMBOL_TRASH " Remove inactive contacts now");
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::applyDisplayPrefs() {
|
||||||
|
if (!_prefs) return;
|
||||||
|
if (_prefs->display_brightness_pct) lvport::setBacklightPct(_prefs->display_brightness_pct);
|
||||||
|
else if (_display) _display->setBrightness(_prefs->display_brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Brightness slider: live while dragging, saved on release.
|
||||||
|
static void onBrightnessSlider(lv_event_t* e) {
|
||||||
|
lv_obj_t* sl = (lv_obj_t*)lv_event_get_target(e);
|
||||||
|
s_ui->setBrightnessPct((uint8_t)lv_slider_get_value(sl), lv_event_get_code(e) == LV_EVENT_RELEASED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::setBrightnessPct(uint8_t pct, bool save) {
|
||||||
|
if (!_prefs) return;
|
||||||
|
_prefs->display_brightness_pct = pct;
|
||||||
|
_prefs->display_brightness = (uint8_t)((pct + 12) / 25 > 4 ? 4 : (pct + 12) / 25); // nearest level, for anything reading it
|
||||||
|
applyDisplayPrefs();
|
||||||
|
if (save) the_mesh.savePrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::buildSchemaSettings() {
|
||||||
|
lv_obj_t* body = newScreen(settings::pageTitle(_settings_page), true);
|
||||||
|
_prune_lbl = nullptr;
|
||||||
|
_prune_armed_ms = 0;
|
||||||
|
uint8_t sec = 0xFF;
|
||||||
|
for (int i = 0; i < settings::COUNT; i++) {
|
||||||
|
const settings::Setting& st = settings::ALL[i];
|
||||||
|
if (settings::sectionPage(st.section) != _settings_page) continue;
|
||||||
|
if (st.section != sec) { sec = st.section; sectionTitle(body, settings::sectionTitle(sec)); }
|
||||||
|
uint8_t v = settings::get(*_prefs, st);
|
||||||
|
if (st.offset == offsetof(NodePrefs, display_brightness)) { // a slider here instead of five steps
|
||||||
|
lv_obj_t* row = lv_obj_create(body);
|
||||||
|
styleSurface(row, theme::SURFACE);
|
||||||
|
lv_obj_remove_flag(row, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_set_size(row, LV_PCT(100), theme::ROW_H);
|
||||||
|
lv_obj_set_style_radius(row, theme::RADIUS, 0);
|
||||||
|
lv_obj_align(label(row, st.label, THEME_FONT_BODY, theme::TEXT), LV_ALIGN_LEFT_MID, theme::PAD, 0);
|
||||||
|
lv_obj_t* sl = lv_slider_create(row);
|
||||||
|
lv_slider_set_range(sl, 5, 100);
|
||||||
|
uint8_t pct = _prefs->display_brightness_pct ? _prefs->display_brightness_pct
|
||||||
|
: (uint8_t)(_prefs->display_brightness * 25 > 5 ? _prefs->display_brightness * 25 : 5);
|
||||||
|
lv_slider_set_value(sl, pct, LV_ANIM_OFF);
|
||||||
|
lv_obj_set_size(sl, 170, 10);
|
||||||
|
lv_obj_align(sl, LV_ALIGN_RIGHT_MID, -18, 0);
|
||||||
|
lv_obj_set_ext_click_area(sl, 14);
|
||||||
|
lv_obj_add_event_cb(sl, onBrightnessSlider, LV_EVENT_VALUE_CHANGED, NULL);
|
||||||
|
lv_obj_add_event_cb(sl, onBrightnessSlider, LV_EVENT_RELEASED, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!st.option) {
|
||||||
|
lv_obj_t* sw = switchRow(body, st.label, st.hint, nullptr);
|
||||||
|
if (v) lv_obj_add_state(sw, LV_STATE_CHECKED);
|
||||||
|
lv_obj_add_event_cb(sw, onSchemaSwitch, LV_EVENT_VALUE_CHANGED, (void*)(uintptr_t)i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char opts[160];
|
||||||
|
int o = 0;
|
||||||
|
for (uint8_t k = 0; k < st.count && o < (int)sizeof(opts) - 16; k++) {
|
||||||
|
if (k) opts[o++] = '\n';
|
||||||
|
st.option(k, opts + o, sizeof(opts) - o, *_prefs);
|
||||||
|
o += strlen(opts + o);
|
||||||
|
}
|
||||||
|
opts[o] = '\0';
|
||||||
|
lv_obj_t* row = lv_obj_create(body);
|
||||||
|
styleSurface(row, theme::SURFACE);
|
||||||
|
lv_obj_remove_flag(row, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_set_size(row, LV_PCT(100), theme::ROW_H);
|
||||||
|
lv_obj_set_style_radius(row, theme::RADIUS, 0);
|
||||||
|
lv_obj_t* l = label(row, st.label, THEME_FONT_BODY, theme::TEXT);
|
||||||
|
lv_obj_align(l, LV_ALIGN_TOP_LEFT, theme::PAD, st.hint ? 5 : 13);
|
||||||
|
if (st.hint) {
|
||||||
|
lv_obj_t* h = label(row, st.hint, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
lv_label_set_long_mode(h, LV_LABEL_LONG_DOT);
|
||||||
|
lv_obj_set_size(h, 176, 15); // fixed height: cut, don't wrap onto the label
|
||||||
|
lv_obj_align(h, LV_ALIGN_BOTTOM_LEFT, theme::PAD, -5);
|
||||||
|
}
|
||||||
|
lv_obj_t* dd = lv_dropdown_create(row);
|
||||||
|
lv_dropdown_set_options(dd, opts);
|
||||||
|
lv_dropdown_set_selected(dd, v);
|
||||||
|
lv_obj_set_width(dd, 112);
|
||||||
|
lv_obj_align(dd, LV_ALIGN_RIGHT_MID, -4, 0);
|
||||||
|
lv_obj_add_event_cb(dd, onSchemaDropdown, LV_EVENT_VALUE_CHANGED, (void*)(uintptr_t)i);
|
||||||
|
}
|
||||||
|
if (_settings_page == settings::PG_MESSAGES) { // the action that goes with "Contact expiry"
|
||||||
|
lv_obj_t* b = lv_button_create(body);
|
||||||
|
lv_obj_set_size(b, LV_PCT(100), 38);
|
||||||
|
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||||
|
lv_obj_set_style_radius(b, theme::RADIUS, 0);
|
||||||
|
lv_obj_set_style_bg_color(b, lv_color_hex(theme::SURFACE), 0);
|
||||||
|
lv_obj_add_event_cb(b, onPruneContacts, LV_EVENT_CLICKED, NULL);
|
||||||
|
_prune_lbl = label(b, LV_SYMBOL_TRASH " Remove inactive contacts now", THEME_FONT_BODY, theme::TEXT);
|
||||||
|
lv_obj_center(_prune_lbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::setSchemaValue(int idx, int v) {
|
||||||
|
if (!_prefs || idx < 0 || idx >= settings::COUNT) return;
|
||||||
|
const settings::Setting& st = settings::ALL[idx];
|
||||||
|
settings::set(*_prefs, st, (uint8_t)v);
|
||||||
|
if (st.changed) st.changed(*_core);
|
||||||
|
the_mesh.savePrefs();
|
||||||
|
if (st.offset == offsetof(NodePrefs, units_imperial)) { // other labels depend on it
|
||||||
|
lv_obj_t* body = _body;
|
||||||
|
int32_t y = body ? lv_obj_get_scroll_y(body) : 0;
|
||||||
|
buildSchemaSettings();
|
||||||
|
if (_body) { lv_obj_update_layout(_body); lv_obj_scroll_to_y(_body, y, LV_ANIM_OFF); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UITask::showSettings() {
|
void UITask::showSettings() {
|
||||||
_screen = SCR_SETTINGS;
|
_screen = SCR_SETTINGS;
|
||||||
buildSettings();
|
buildSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onOpenWifi(lv_event_t* e) { (void)e; s_ui->showWifi(false); }
|
static void onOpenWifi(lv_event_t* e) { (void)e; s_ui->showWifi(false); }
|
||||||
|
static void onOpenRadio(lv_event_t* e); // RadioScreen.h
|
||||||
|
|
||||||
void UITask::buildSettings() {
|
void UITask::buildSettings() {
|
||||||
lv_obj_t* body = newScreen("Settings", true);
|
lv_obj_t* body = newScreen("Settings", true);
|
||||||
@@ -1388,6 +1820,29 @@ void UITask::buildSettings() {
|
|||||||
char ssid[33], pass[65];
|
char ssid[33], pass[65];
|
||||||
bool have = lvport::loadWifi(ssid, sizeof(ssid), pass, sizeof(pass));
|
bool have = lvport::loadWifi(ssid, sizeof(ssid), pass, sizeof(pass));
|
||||||
listRow(body, LV_SYMBOL_WIFI " WiFi", have ? ssid : "Not set (for map downloads)", onOpenWifi, NULL);
|
listRow(body, LV_SYMBOL_WIFI " WiFi", have ? ssid : "Not set (for map downloads)", onOpenWifi, NULL);
|
||||||
|
if (_prefs) {
|
||||||
|
char sub[48];
|
||||||
|
int pi = radioctl::currentPreset(_prefs);
|
||||||
|
const char* pn = "Custom"; float f, b; uint8_t sf, cr;
|
||||||
|
if (pi >= 0) radioctl::presetAt(_prefs, pi, pn, f, b, sf, cr);
|
||||||
|
snprintf(sub, sizeof(sub), "%s - %.3f MHz, %d dBm", pn, _prefs->freq, _prefs->tx_power_dbm);
|
||||||
|
listRow(body, UI_SYMBOL_RADIO " Radio", sub, onOpenRadio, NULL);
|
||||||
|
}
|
||||||
|
if (_prefs) { // the same NodePrefs switches as ui-new's Home GPS toggle / Live share / Locator screens
|
||||||
|
sectionTitle(body, "NAVIGATION");
|
||||||
|
if (_core->gpsAvailable()) {
|
||||||
|
lv_obj_t* sw = switchRow(body, "GPS", "Position for maps, sharing and adverts", nullptr);
|
||||||
|
if (_core->gpsEnabled()) lv_obj_add_state(sw, LV_STATE_CHECKED);
|
||||||
|
lv_obj_add_event_cb(sw, onGpsSwitch, LV_EVENT_VALUE_CHANGED, NULL);
|
||||||
|
}
|
||||||
|
listRow(body, UI_SYMBOL_COMPASS " Trail, live share, alerts", "Point spacing, auto-pause, sharing, radius",
|
||||||
|
onOpenSchemaPage, (void*)(uintptr_t)settings::PG_NAV);
|
||||||
|
sectionTitle(body, "DEVICE");
|
||||||
|
listRow(body, LV_SYMBOL_EYE_OPEN " Display & power", "Brightness, screen off, battery, GPS, time zone",
|
||||||
|
onOpenSchemaPage, (void*)(uintptr_t)settings::PG_DEVICE);
|
||||||
|
listRow(body, LV_SYMBOL_ENVELOPE " Messages & contacts", "Resending, contact expiry, sorting",
|
||||||
|
onOpenSchemaPage, (void*)(uintptr_t)settings::PG_MESSAGES);
|
||||||
|
}
|
||||||
sectionTitle(body, "KEYBOARD");
|
sectionTitle(body, "KEYBOARD");
|
||||||
uint8_t main_a = _prefs ? _prefs->keyboard_main_alphabet : 0;
|
uint8_t main_a = _prefs ? _prefs->keyboard_main_alphabet : 0;
|
||||||
uint8_t alt_a = _prefs ? _prefs->keyboard_alt_alphabet : 0;
|
uint8_t alt_a = _prefs ? _prefs->keyboard_alt_alphabet : 0;
|
||||||
@@ -1399,6 +1854,16 @@ void UITask::buildSettings() {
|
|||||||
s_kb_alt_dd = dropdownRow(body, "Additional", "None\nLatin\nCyrillic\nGreek",
|
s_kb_alt_dd = dropdownRow(body, "Additional", "None\nLatin\nCyrillic\nGreek",
|
||||||
alt_a == main_a ? 0 : alt_a + 1);
|
alt_a == main_a ? 0 : alt_a + 1);
|
||||||
label(body, "Hold a letter for accents and other variants.", THEME_FONT_SMALL, theme::TEXT_MUTED);
|
label(body, "Hold a letter for accents and other variants.", THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||||
|
|
||||||
|
sectionTitle(body, "ABOUT");
|
||||||
|
char about[200], built[24] = "";
|
||||||
|
if (!strstr(FIRMWARE_VERSION, FIRMWARE_BUILD_DATE)) snprintf(built, sizeof(built), " (%s)", FIRMWARE_BUILD_DATE);
|
||||||
|
snprintf(about, sizeof(about), "%s\nFirmware %s%s\n\nMap data: %s", the_mesh.getNodeName(), FIRMWARE_VERSION, built,
|
||||||
|
(lvport::mountStorage() && mapview::s_provider->available()) ? mapview::s_provider->attribution()
|
||||||
|
: "\xC2\xA9 OpenStreetMap contributors");
|
||||||
|
lv_obj_t* a = label(body, about, THEME_FONT_SMALL, theme::TEXT);
|
||||||
|
lv_label_set_long_mode(a, LV_LABEL_LONG_WRAP);
|
||||||
|
lv_obj_set_width(a, LV_PCT(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::setKeyboardAlphabets(int main_idx, int alt_sel) {
|
void UITask::setKeyboardAlphabets(int main_idx, int alt_sel) {
|
||||||
|
|||||||
@@ -32,14 +32,23 @@ public:
|
|||||||
bool isViewingChannel(uint8_t channel_idx) override;
|
bool isViewingChannel(uint8_t channel_idx) override;
|
||||||
bool isViewingDM(const uint8_t* pub_key) override;
|
bool isViewingDM(const uint8_t* pub_key) override;
|
||||||
void onViewedHistoryGrew(bool channel) override { (void)channel; _thread_dirty = true; }
|
void onViewedHistoryGrew(bool channel) override { (void)channel; _thread_dirty = true; }
|
||||||
|
void botSetGPS(bool on) override;
|
||||||
|
|
||||||
// ── Navigation (called from LVGL event callbacks) ────────────────────────
|
// ── Navigation (called from LVGL event callbacks) ────────────────────────
|
||||||
void showHome();
|
void showHome();
|
||||||
|
void setHomePage(int page);
|
||||||
void showChats();
|
void showChats();
|
||||||
void showContacts();
|
void showContacts();
|
||||||
void showSettings();
|
void showSettings();
|
||||||
|
void showSchemaSettings(int page);
|
||||||
|
void pruneContacts();
|
||||||
|
void setBrightnessPct(uint8_t pct, bool save);
|
||||||
|
void applyDisplayPrefs() override;
|
||||||
|
void setSchemaValue(int idx, int v);
|
||||||
void showNearby();
|
void showNearby();
|
||||||
void showMap();
|
void showMap(); // in its current mode
|
||||||
|
void openMap(bool nav); // Nodes map (false) or Navigation map (true)
|
||||||
|
void mapLongPress(int x, int y);
|
||||||
void mapZoom(int delta);
|
void mapZoom(int delta);
|
||||||
void mapCenterOnMe();
|
void mapCenterOnMe();
|
||||||
void mapPan(int dx, int dy);
|
void mapPan(int dx, int dy);
|
||||||
@@ -48,7 +57,27 @@ public:
|
|||||||
void mapDownloadClose();
|
void mapDownloadClose();
|
||||||
void mapDownloadStart();
|
void mapDownloadStart();
|
||||||
void mapDownloadStop();
|
void mapDownloadStop();
|
||||||
|
void mapDownloadResume();
|
||||||
|
void mapDownloadDiscard();
|
||||||
void mapDownloadZmax(int delta);
|
void mapDownloadZmax(int delta);
|
||||||
|
// Navigation map (NavMap.h)
|
||||||
|
void navTargetsPopup();
|
||||||
|
void navClosePopup();
|
||||||
|
void navPick(int code);
|
||||||
|
void navWaypointMenu(int idx);
|
||||||
|
void navWaypointAction(uint8_t act);
|
||||||
|
void navRenameDone(bool ok);
|
||||||
|
void navMarkHere();
|
||||||
|
void navAveragingCancel();
|
||||||
|
void navToNode(const uint8_t* key, int32_t lat, int32_t lon, const char* name);
|
||||||
|
void navToolsPopup();
|
||||||
|
void navToolAction(uint8_t act);
|
||||||
|
void navSetShareTarget(int sel);
|
||||||
|
void navWaypointsPopup();
|
||||||
|
void navCoordsPopup();
|
||||||
|
void navCoordsDone(bool ok);
|
||||||
|
void shareToMessage(const char* text);
|
||||||
|
void messageLocationAction(int idx, bool save);
|
||||||
void showWifi(bool from_map);
|
void showWifi(bool from_map);
|
||||||
void wifiScan();
|
void wifiScan();
|
||||||
void wifiPick(int idx);
|
void wifiPick(int idx);
|
||||||
@@ -69,22 +98,37 @@ public:
|
|||||||
void sendFromCompose();
|
void sendFromCompose();
|
||||||
void setKeyboardVisible(bool show);
|
void setKeyboardVisible(bool show);
|
||||||
void showToast(const char* text, uint32_t ms = 2500);
|
void showToast(const char* text, uint32_t ms = 2500);
|
||||||
|
// Clock tools (ClockScreen.h)
|
||||||
|
void showClock();
|
||||||
|
void clockTab(int tab);
|
||||||
|
void clockAction(uint8_t act);
|
||||||
|
void setAlarm(int which, int v);
|
||||||
|
void dismissRing();
|
||||||
|
// Settings > Radio (RadioScreen.h)
|
||||||
|
void showRadio();
|
||||||
|
void radioSet(int which, int v);
|
||||||
|
void radioFreqPopup();
|
||||||
|
void radioFreqDone(bool ok);
|
||||||
|
void setGps(bool on);
|
||||||
|
bool ensureGps(); // true with a fix; else turns GPS on / says it's waiting
|
||||||
|
|
||||||
// Kept for main.cpp's sim hooks (ui-new API).
|
// Kept for main.cpp's sim hooks (ui-new API).
|
||||||
void openContactDM(const ContactInfo& ci) { openDM(ci.id.pub_key); }
|
void openContactDM(const ContactInfo& ci) { openDM(ci.id.pub_key); }
|
||||||
void openAdminFor(const ContactInfo& ci, bool from_picker) { (void)ci; (void)from_picker; }
|
void openAdminFor(const ContactInfo& ci, bool from_picker) { (void)ci; (void)from_picker; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Screen : uint8_t { SCR_HOME, SCR_CHATS, SCR_CONTACTS, SCR_THREAD, SCR_SETTINGS, SCR_NEARBY, SCR_NODE, SCR_MAP, SCR_WIFI };
|
enum Screen : uint8_t { SCR_HOME, SCR_CHATS, SCR_CONTACTS, SCR_THREAD, SCR_SETTINGS, SCR_NEARBY, SCR_NODE, SCR_MAP, SCR_WIFI, SCR_SETTINGS_NAV, SCR_CLOCK, SCR_RADIO };
|
||||||
|
|
||||||
void buildStatusBar();
|
void buildStatusBar();
|
||||||
void refreshStatusBar();
|
void refreshStatusBar();
|
||||||
lv_obj_t* newScreen(const char* title, bool with_back);
|
lv_obj_t* newScreen(const char* title, bool with_back);
|
||||||
void buildHome();
|
void buildHome();
|
||||||
void refreshHome();
|
void refreshHome();
|
||||||
|
void homeSwipePoll();
|
||||||
void buildChats();
|
void buildChats();
|
||||||
void buildContacts();
|
void buildContacts();
|
||||||
void buildSettings();
|
void buildSettings();
|
||||||
|
void buildSchemaSettings();
|
||||||
void buildNearby();
|
void buildNearby();
|
||||||
void refreshNearbyList();
|
void refreshNearbyList();
|
||||||
uint32_t nearbySignature() const;
|
uint32_t nearbySignature() const;
|
||||||
@@ -94,6 +138,27 @@ private:
|
|||||||
void layoutMap();
|
void layoutMap();
|
||||||
void mapLoop();
|
void mapLoop();
|
||||||
void rebuildMapMarkers();
|
void rebuildMapMarkers();
|
||||||
|
void rebuildNodeMarkers();
|
||||||
|
void addMapMark(uint8_t kind, int idx, int32_t lat_e6, int32_t lon_e6, uint32_t col, const char* text);
|
||||||
|
void mapPointToLatLon(int x, int y, int32_t& lat_e6, int32_t& lon_e6) const;
|
||||||
|
double mapCenterBias() const;
|
||||||
|
void buildNavLayers();
|
||||||
|
void buildNavControls(lv_obj_t* body);
|
||||||
|
void rebuildNavMarkers();
|
||||||
|
void layoutNav();
|
||||||
|
void refreshNavBar();
|
||||||
|
void navFrameTarget();
|
||||||
|
void navSetTarget(uint8_t kind, const uint8_t* key, int32_t lat, int32_t lon, const char* name);
|
||||||
|
lv_obj_t* navPopupPanel(const char* title, bool full);
|
||||||
|
void navRenamePopup(int idx);
|
||||||
|
void navAddWaypoint(int32_t lat, int32_t lon);
|
||||||
|
void navDropAt(int x, int y);
|
||||||
|
void navSpotPopup(int32_t lat, int32_t lon);
|
||||||
|
void refreshNavTools();
|
||||||
|
void navPollAveraging();
|
||||||
|
void navPollTrackBack();
|
||||||
|
bool navCurrentTarget(int32_t& lat, int32_t& lon, char* name, int n, bool& person, bool& set);
|
||||||
|
bool exportTrailGpx(char* name_out, size_t n);
|
||||||
void mapDownloadTick();
|
void mapDownloadTick();
|
||||||
void refreshDownloadPopup();
|
void refreshDownloadPopup();
|
||||||
void buildWifi();
|
void buildWifi();
|
||||||
@@ -103,11 +168,19 @@ private:
|
|||||||
void buildThread();
|
void buildThread();
|
||||||
void refreshThread();
|
void refreshThread();
|
||||||
uint32_t threadSignature() const;
|
uint32_t threadSignature() const;
|
||||||
|
void buildClock();
|
||||||
|
void buildRadio();
|
||||||
|
void radioCloseFreq();
|
||||||
|
bool radioPopupOpen() const;
|
||||||
|
void refreshClock();
|
||||||
|
void showRing(const char* text);
|
||||||
|
void hideRing();
|
||||||
void drainCoreEvents();
|
void drainCoreEvents();
|
||||||
void onMessageArrived(const UiEvent& ev);
|
void onMessageArrived(const UiEvent& ev);
|
||||||
void wake();
|
void wake();
|
||||||
void sleep();
|
void sleep();
|
||||||
uint32_t autoOffMillis() const;
|
uint32_t autoOffMillis() const;
|
||||||
|
void checkLowBattery();
|
||||||
|
|
||||||
DisplayDriver* _display = nullptr;
|
DisplayDriver* _display = nullptr;
|
||||||
SensorManager* _sensors = nullptr;
|
SensorManager* _sensors = nullptr;
|
||||||
@@ -118,6 +191,13 @@ private:
|
|||||||
bool _asleep = false;
|
bool _asleep = false;
|
||||||
uint32_t _next_status_ms = 0;
|
uint32_t _next_status_ms = 0;
|
||||||
uint32_t _next_thread_check_ms = 0;
|
uint32_t _next_thread_check_ms = 0;
|
||||||
|
uint32_t _next_trackback_ms = 0;
|
||||||
|
uint32_t _next_clock_ms = 0;
|
||||||
|
uint8_t _settings_page = 0; // settings::Page shown in SCR_SETTINGS_NAV
|
||||||
|
uint32_t _prune_armed_ms = 0;
|
||||||
|
uint16_t _batt_mv = 0; // smoothed, for the low-battery shutdown
|
||||||
|
uint32_t _next_batt_ms = 0;
|
||||||
|
lv_obj_t* _prune_lbl = nullptr;
|
||||||
|
|
||||||
// Open conversation (SCR_THREAD)
|
// Open conversation (SCR_THREAD)
|
||||||
bool _thread_is_channel = false;
|
bool _thread_is_channel = false;
|
||||||
@@ -129,6 +209,7 @@ private:
|
|||||||
// Widgets
|
// Widgets
|
||||||
lv_obj_t* _status_time = nullptr;
|
lv_obj_t* _status_time = nullptr;
|
||||||
lv_obj_t* _status_icons = nullptr;
|
lv_obj_t* _status_icons = nullptr;
|
||||||
|
lv_obj_t* _status_gps = nullptr;
|
||||||
lv_obj_t* _toast = nullptr;
|
lv_obj_t* _toast = nullptr;
|
||||||
lv_timer_t* _toast_timer = nullptr;
|
lv_timer_t* _toast_timer = nullptr;
|
||||||
lv_obj_t* _home_clock = nullptr;
|
lv_obj_t* _home_clock = nullptr;
|
||||||
@@ -181,9 +262,36 @@ private:
|
|||||||
lv_obj_t* _dl_info = nullptr;
|
lv_obj_t* _dl_info = nullptr;
|
||||||
lv_obj_t* _dl_zoom_lbl = nullptr;
|
lv_obj_t* _dl_zoom_lbl = nullptr;
|
||||||
lv_obj_t* _dl_start_lbl = nullptr;
|
lv_obj_t* _dl_start_lbl = nullptr;
|
||||||
|
lv_obj_t* _dl_job_row = nullptr; // "Unfinished ... Resume" in the popup
|
||||||
|
lv_obj_t* _dl_job_lbl = nullptr;
|
||||||
int _dl_zmax = 0;
|
int _dl_zmax = 0;
|
||||||
uint8_t _dl_last_state = 0;
|
uint8_t _dl_last_state = 0;
|
||||||
|
|
||||||
|
// Navigation map (SCR_MAP with _map_nav)
|
||||||
|
bool _map_nav = false;
|
||||||
|
uint32_t _next_nav_bar_ms = 0;
|
||||||
|
lv_obj_t* _nav_bar = nullptr; // target bar along the bottom
|
||||||
|
lv_obj_t* _nav_title = nullptr;
|
||||||
|
lv_obj_t* _nav_info = nullptr;
|
||||||
|
lv_obj_t* _nav_clear = nullptr;
|
||||||
|
lv_obj_t* _nav_overlay = nullptr; // target list / waypoint menu / rename
|
||||||
|
lv_obj_t* _nav_ta = nullptr;
|
||||||
|
lv_obj_t* _nav_kb = nullptr;
|
||||||
|
lv_obj_t* _nav_del_lbl = nullptr;
|
||||||
|
uint32_t _nav_del_armed_ms = 0;
|
||||||
|
int _nav_wp = -1; // waypoint the menu / rename is about
|
||||||
|
lv_obj_t* _nav_rec = nullptr; // "REC 1.2 km LIVE 58m" pill
|
||||||
|
lv_obj_t* _nav_avg_pill = nullptr; // GPS averaging progress (tap: cancel)
|
||||||
|
lv_obj_t* _nav_trail_lbl = nullptr; // tools panel
|
||||||
|
lv_obj_t* _nav_trail_btn = nullptr;
|
||||||
|
lv_obj_t* _nav_reset_lbl = nullptr;
|
||||||
|
lv_obj_t* _nav_share_lbl = nullptr;
|
||||||
|
lv_obj_t* _nav_share_btn = nullptr;
|
||||||
|
lv_obj_t* _nav_tb_btn = nullptr;
|
||||||
|
uint32_t _nav_reset_armed_ms = 0;
|
||||||
|
int32_t _nav_spot_lat = 0, _nav_spot_lon = 0; // the spot a long-press picked
|
||||||
|
char _share_text[96] = ""; // waiting for a conversation to be picked (shareToMessage)
|
||||||
|
|
||||||
// WiFi settings (SCR_WIFI)
|
// WiFi settings (SCR_WIFI)
|
||||||
bool _wifi_from_map = false;
|
bool _wifi_from_map = false;
|
||||||
bool _wifi_scanning = false;
|
bool _wifi_scanning = false;
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ TEXT="0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0
|
|||||||
TEXT="$TEXT,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122"
|
TEXT="$TEXT,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122"
|
||||||
# LVGL built-in symbols (same list as lvgl/scripts/built_in_font/built_in_font_gen.py)
|
# LVGL built-in symbols (same list as lvgl/scripts/built_in_font/built_in_font_gen.py)
|
||||||
# plus 61612 = globe (keyboard script key), 61445 = star (favourite),
|
# plus 61612 = globe (keyboard script key), 61445 = star (favourite),
|
||||||
# 62073 = map, 61632 = users (home tiles)
|
# 62073 = map, 61632 = users (home tiles), 61774 = compass (Navigate),
|
||||||
SYMS="61612,61445,62073,61632,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650"
|
# 61476 = flag (waypoint), 62405 = map marker (mark here), 61463 = clock,
|
||||||
|
# 62194 = stopwatch, 62745 = broadcast tower (radio)
|
||||||
|
SYMS="62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650"
|
||||||
|
|
||||||
CONV="npx -y lv_font_conv@1.5.3"
|
CONV="npx -y lv_font_conv@1.5.3"
|
||||||
gen() { # size weight ranges name
|
gen() { # size weight ranges name
|
||||||
@@ -38,7 +40,7 @@ gen() { # size weight ranges name
|
|||||||
--format lvgl --lv-include lvgl.h --lv-font-name "$4" -o "$HERE/$4.c"
|
--format lvgl --lv-include lvgl.h --lv-font-name "$4" -o "$HERE/$4.c"
|
||||||
}
|
}
|
||||||
for s in 12 14 16 20; do gen "$s" Medium "$TEXT" "ui_font_$s"; done
|
for s in 12 14 16 20; do gen "$s" Medium "$TEXT" "ui_font_$s"; done
|
||||||
# Clock: digits, colon, dash, space only.
|
# Clock: digits, colon, dash, dot, space only.
|
||||||
$CONV --bpp 4 --size 40 --no-compress --font "$CACHE/NotoSans-SemiBold.ttf" -r "0x20,0x2D,0x30-0x3A" \
|
$CONV --bpp 4 --size 40 --no-compress --font "$CACHE/NotoSans-SemiBold.ttf" -r "0x20,0x2D-0x2E,0x30-0x3A" \
|
||||||
--format lvgl --lv-include lvgl.h --lv-font-name ui_font_40 -o "$HERE/ui_font_40.c"
|
--format lvgl --lv-include lvgl.h --lv-font-name ui_font_40 -o "$HERE/ui_font_40.c"
|
||||||
echo "done: $(ls "$HERE"/ui_font_*.c | wc -l) fonts"
|
echo "done: $(ls "$HERE"/ui_font_*.c | wc -l) fonts"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Size: 12 px
|
* Size: 12 px
|
||||||
* Bpp: 4
|
* Bpp: 4
|
||||||
* Opts: --bpp 4 --size 12 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 61612,61445,62073,61632,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_12 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_12.c
|
* Opts: --bpp 4 --size 12 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_12 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_12.c
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
@@ -6457,6 +6457,16 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x1, 0xcb, 0xfa, 0x1, 0xff, 0xca, 0x60, 0x1,
|
0x1, 0xcb, 0xfa, 0x1, 0xff, 0xca, 0x60, 0x1,
|
||||||
0x1, 0x80, 0x4e, 0x0,
|
0x1, 0x80, 0x4e, 0x0,
|
||||||
|
|
||||||
|
/* U+F017 "" */
|
||||||
|
0x0, 0xc2, 0x68, 0x20, 0x1e, 0x2b, 0xec, 0xbe,
|
||||||
|
0xb2, 0x0, 0x93, 0x50, 0x3, 0x26, 0xa0, 0xd,
|
||||||
|
0x0, 0x5d, 0xc0, 0xa, 0x86, 0x44, 0x3, 0xf0,
|
||||||
|
0xca, 0x0, 0x7f, 0x90, 0x40, 0x38, 0x48, 0x2,
|
||||||
|
0x11, 0x0, 0x67, 0xd, 0x40, 0x0, 0xa0, 0x6,
|
||||||
|
0x9b, 0x26, 0x0, 0x24, 0x80, 0x72, 0x69, 0x0,
|
||||||
|
0x24, 0x6c, 0x3, 0xf5, 0x88, 0x26, 0x18, 0x6,
|
||||||
|
0x3c, 0x40, 0x8, 0xf3, 0x6e, 0xdb, 0x86, 0x0,
|
||||||
|
|
||||||
/* U+F019 "" */
|
/* U+F019 "" */
|
||||||
0x0, 0xc4, 0xee, 0x20, 0xf, 0xcb, 0x10, 0x50,
|
0x0, 0xc4, 0xee, 0x20, 0xf, 0xcb, 0x10, 0x50,
|
||||||
0xf, 0xde, 0x0, 0xf0, 0xf, 0xfe, 0x96, 0xfb,
|
0xf, 0xde, 0x0, 0xf0, 0xf, 0xfe, 0x96, 0xfb,
|
||||||
@@ -6486,6 +6496,14 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x9b, 0x79, 0x83, 0x78, 0x47, 0x76, 0x91, 0x0,
|
0x9b, 0x79, 0x83, 0x78, 0x47, 0x76, 0x91, 0x0,
|
||||||
0x0,
|
0x0,
|
||||||
|
|
||||||
|
/* U+F024 "" */
|
||||||
|
0x3, 0x0, 0xff, 0x9f, 0x34, 0x3, 0xff, 0x80,
|
||||||
|
0x55, 0x94, 0xc2, 0x4, 0xf6, 0xc, 0x0, 0x53,
|
||||||
|
0x59, 0xef, 0xd8, 0x42, 0x0, 0xff, 0xfb, 0x8b,
|
||||||
|
0x44, 0x10, 0x2, 0x18, 0x20, 0x4, 0x4b, 0xba,
|
||||||
|
0xff, 0x75, 0xce, 0x1, 0xfc, 0x44, 0x0, 0x85,
|
||||||
|
0x54, 0x1, 0xfe,
|
||||||
|
|
||||||
/* U+F026 "" */
|
/* U+F026 "" */
|
||||||
0x0, 0xc5, 0x40, 0x11, 0x62, 0xbc, 0x43, 0x4,
|
0x0, 0xc5, 0x40, 0x11, 0x62, 0xbc, 0x43, 0x4,
|
||||||
0x21, 0xdc, 0x20, 0x1f, 0xfc, 0x22, 0x0, 0xed,
|
0x21, 0xdc, 0x20, 0x1f, 0xfc, 0x22, 0x0, 0xed,
|
||||||
@@ -6793,6 +6811,17 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0xe0, 0x30, 0x7, 0xff, 0x6, 0x40, 0x3f, 0xce,
|
0xe0, 0x30, 0x7, 0xff, 0x6, 0x40, 0x3f, 0xce,
|
||||||
0xc, 0x20, 0x1f, 0xe9, 0x98, 0x3, 0x80,
|
0xc, 0x20, 0x1f, 0xe9, 0x98, 0x3, 0x80,
|
||||||
|
|
||||||
|
/* U+F14E "" */
|
||||||
|
0x0, 0xc8, 0xca, 0x40, 0x1e, 0x5e, 0xb9, 0xad,
|
||||||
|
0xb2, 0x0, 0x9e, 0x84, 0x3, 0x26, 0x10, 0x1c,
|
||||||
|
0x0, 0x71, 0x28, 0xf8, 0x48, 0x6, 0x3b, 0xdc,
|
||||||
|
0x2, 0x44, 0x0, 0x51, 0xea, 0x16, 0x0, 0xc1,
|
||||||
|
0x0, 0xb, 0xf3, 0x21, 0x0, 0x4, 0x40, 0x9,
|
||||||
|
0xd, 0x78, 0x0, 0xb9, 0xc0, 0xc, 0x2f, 0xc6,
|
||||||
|
0x1, 0x25, 0x80, 0x23, 0xa0, 0x40, 0x24, 0x32,
|
||||||
|
0xb0, 0x60, 0xe, 0x3a, 0x0, 0x26, 0xa0, 0x4,
|
||||||
|
0x2f, 0x82, 0x1, 0x15, 0xfe, 0xeb, 0xa0, 0x2,
|
||||||
|
|
||||||
/* U+F15B "" */
|
/* U+F15B "" */
|
||||||
0x9b, 0xbc, 0x4e, 0x0, 0x64, 0x4c, 0xd1, 0x20,
|
0x9b, 0xbc, 0x4e, 0x0, 0x64, 0x4c, 0xd1, 0x20,
|
||||||
0x1f, 0x9a, 0x40, 0x38, 0x6e, 0xda, 0x1, 0xd5,
|
0x1f, 0x9a, 0x40, 0x38, 0x6e, 0xda, 0x1, 0xd5,
|
||||||
@@ -6889,6 +6918,16 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x1, 0x38, 0x2a, 0x86, 0x42, 0x81, 0xc0, 0xe5,
|
0x1, 0x38, 0x2a, 0x86, 0x42, 0x81, 0xc0, 0xe5,
|
||||||
0xdf, 0xd1, 0x20,
|
0xdf, 0xd1, 0x20,
|
||||||
|
|
||||||
|
/* U+F2F2 "" */
|
||||||
|
0x0, 0x92, 0x20, 0xa0, 0x1f, 0x73, 0xbb, 0x80,
|
||||||
|
0x3e, 0xa3, 0x2b, 0x0, 0xf4, 0x79, 0x97, 0xc4,
|
||||||
|
0x1c, 0x1, 0x4e, 0x6, 0x80, 0xee, 0xe0, 0x45,
|
||||||
|
0x0, 0x44, 0x0, 0x2c, 0xe, 0x0, 0xfd, 0xc0,
|
||||||
|
0xe0, 0x1f, 0x94, 0x4, 0x2, 0x17, 0x0, 0x8c,
|
||||||
|
0x10, 0x2, 0xab, 0x0, 0x90, 0x24, 0x40, 0x3c,
|
||||||
|
0x30, 0x3, 0xa2, 0x1, 0x87, 0x44, 0x0, 0x7d,
|
||||||
|
0xa, 0xa8, 0xf3, 0x0, 0x0,
|
||||||
|
|
||||||
/* U+F304 "" */
|
/* U+F304 "" */
|
||||||
0x0, 0xfe, 0x17, 0x10, 0xf, 0xe1, 0xf8, 0xc1,
|
0x0, 0xfe, 0x17, 0x10, 0xf, 0xe1, 0xf8, 0xc1,
|
||||||
0x0, 0xf8, 0x50, 0x40, 0xb4, 0x3, 0xc3, 0xfe,
|
0x0, 0xf8, 0x50, 0x40, 0xb4, 0x3, 0xc3, 0xfe,
|
||||||
@@ -6900,6 +6939,28 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x3, 0xc4, 0x0, 0x1c, 0x20, 0xf, 0xa6, 0x57,
|
0x3, 0xc4, 0x0, 0x1c, 0x20, 0xf, 0xa6, 0x57,
|
||||||
0xe4, 0x1, 0xf0,
|
0xe4, 0x1, 0xf0,
|
||||||
|
|
||||||
|
/* U+F3C5 "" */
|
||||||
|
0x0, 0xa, 0xba, 0x88, 0x4, 0xbd, 0x51, 0x5c,
|
||||||
|
0xa0, 0x74, 0x1, 0xd4, 0x70, 0x0, 0x8d, 0x80,
|
||||||
|
0x4, 0x20, 0x23, 0x93, 0xa0, 0x20, 0x7, 0xf2,
|
||||||
|
0x2, 0x39, 0x3a, 0x2, 0x40, 0x2, 0x36, 0x0,
|
||||||
|
0x10, 0x6c, 0x1, 0xcc, 0x61, 0x24, 0x1, 0x14,
|
||||||
|
0x80, 0x5c, 0x1, 0x70, 0x6, 0x37, 0x7, 0x30,
|
||||||
|
0xe, 0x8a, 0x80, 0x8,
|
||||||
|
|
||||||
|
/* U+F519 "" */
|
||||||
|
0x14, 0x0, 0xff, 0x90, 0x62, 0xc0, 0x3f, 0xeb,
|
||||||
|
0x84, 0x50, 0x97, 0x5, 0xb5, 0x7, 0x90, 0x54,
|
||||||
|
0x22, 0x3, 0x78, 0x5a, 0x58, 0x7b, 0x1, 0x10,
|
||||||
|
0x44, 0x2, 0x40, 0x60, 0x60, 0x42, 0x2, 0x25,
|
||||||
|
0x40, 0xcb, 0x22, 0x9, 0x12, 0xf0, 0x11, 0x7d,
|
||||||
|
0x80, 0x86, 0xc3, 0x2, 0xc4, 0x85, 0xbd, 0x2c,
|
||||||
|
0x2, 0x66, 0x13, 0x30, 0x40, 0x6d, 0x0, 0x33,
|
||||||
|
0x3, 0x7b, 0x3, 0x0, 0x7e, 0xb2, 0x77, 0x8a,
|
||||||
|
0x80, 0x3e, 0x42, 0x88, 0xe2, 0x40, 0xf, 0x70,
|
||||||
|
0xa8, 0x4, 0xa3, 0xe0, 0x1e, 0x9a, 0x0, 0xea,
|
||||||
|
0x80, 0x8,
|
||||||
|
|
||||||
/* U+F55A "" */
|
/* U+F55A "" */
|
||||||
0x0, 0x97, 0xbf, 0xff, 0xa0, 0x0, 0xb4, 0x20,
|
0x0, 0x97, 0xbf, 0xff, 0xa0, 0x0, 0xb4, 0x20,
|
||||||
0x1f, 0xce, 0xb, 0x40, 0x13, 0x71, 0x13, 0x98,
|
0x1f, 0xce, 0xb, 0x40, 0x13, 0x71, 0x13, 0x98,
|
||||||
@@ -7958,60 +8019,66 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||||||
{.bitmap_index = 31387, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 31387, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 31462, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 31462, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 31522, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 31522, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 31576, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 31586, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 31624, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 31640, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 31697, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 31688, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 31720, .adv_w = 144, .box_w = 9, .box_h = 10, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 31761, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 31755, .adv_w = 216, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 31804, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 31829, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 31827, .adv_w = 144, .box_w = 9, .box_h = 10, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 31871, .adv_w = 132, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 31862, .adv_w = 216, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 31921, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2},
|
{.bitmap_index = 31936, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 31958, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 31978, .adv_w = 132, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 32004, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 32028, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2},
|
||||||
{.bitmap_index = 32031, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 32065, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 32048, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2},
|
{.bitmap_index = 32111, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 32086, .adv_w = 168, .box_w = 12, .box_h = 11, .ofs_x = -1, .ofs_y = -1},
|
{.bitmap_index = 32138, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 32133, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 32155, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2},
|
||||||
{.bitmap_index = 32169, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 32193, .adv_w = 168, .box_w = 12, .box_h = 11, .ofs_x = -1, .ofs_y = -1},
|
||||||
{.bitmap_index = 32206, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 32240, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 32245, .adv_w = 168, .box_w = 11, .box_h = 3, .ofs_x = 0, .ofs_y = 3},
|
{.bitmap_index = 32276, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 32254, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 32313, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 32316, .adv_w = 240, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 32352, .adv_w = 168, .box_w = 11, .box_h = 3, .ofs_x = 0, .ofs_y = 3},
|
||||||
{.bitmap_index = 32407, .adv_w = 216, .box_w = 15, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 32361, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 32482, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 32423, .adv_w = 240, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 32541, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 32514, .adv_w = 216, .box_w = 15, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 32575, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 32589, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 32609, .adv_w = 240, .box_w = 16, .box_h = 10, .ofs_x = -1, .ofs_y = 0},
|
{.bitmap_index = 32648, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 32669, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 32682, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 32689, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 32716, .adv_w = 240, .box_w = 16, .box_h = 10, .ofs_x = -1, .ofs_y = 0},
|
||||||
{.bitmap_index = 32746, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 32776, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 32810, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 32796, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 32880, .adv_w = 240, .box_w = 15, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 32853, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 32954, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 32917, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 33015, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 32987, .adv_w = 240, .box_w = 15, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 33055, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 33061, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 33099, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 33122, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 33131, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 33162, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 33170, .adv_w = 120, .box_w = 9, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 33206, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 33216, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 33238, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 33261, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 33277, .adv_w = 120, .box_w = 9, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 33314, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 33323, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 33370, .adv_w = 192, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 33368, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 33433, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 33421, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 33456, .adv_w = 240, .box_w = 15, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 33477, .adv_w = 192, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 33531, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 33540, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 33574, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 33612, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 33623, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 33635, .adv_w = 240, .box_w = 15, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 33672, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 33710, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 33721, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 33753, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 33763, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 33802, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 33800, .adv_w = 240, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 33851, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 33865, .adv_w = 168, .box_w = 10, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 33900, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 33929, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 33942, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 33972, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 33979, .adv_w = 240, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 34039, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 34044, .adv_w = 168, .box_w = 10, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 34094, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 34108, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 34123, .adv_w = 193, .box_w = 13, .box_h = 9, .ofs_x = 0, .ofs_y = 0}
|
{.bitmap_index = 34151, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 34212, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 34279, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 34331, .adv_w = 240, .box_w = 15, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 34413, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||||
|
{.bitmap_index = 34468, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 34497, .adv_w = 193, .box_w = 13, .box_h = 9, .ofs_x = 0, .ofs_y = 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------
|
/*---------------------
|
||||||
@@ -8036,14 +8103,14 @@ static const uint16_t unicode_list_10[] = {
|
|||||||
|
|
||||||
static const uint16_t unicode_list_12[] = {
|
static const uint16_t unicode_list_12[] = {
|
||||||
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
||||||
0xcefb, 0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11,
|
0xcefb, 0xcefd, 0xceff, 0xcf01, 0xcf03, 0xcf06, 0xcf0b, 0xcf0e,
|
||||||
0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b,
|
0xcf10, 0xcf11, 0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36,
|
||||||
0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b,
|
0xcf37, 0xcf3b, 0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58,
|
||||||
0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96,
|
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d,
|
||||||
0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4,
|
0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca,
|
||||||
0xcfdd, 0xd006, 0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c,
|
0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045, 0xd0d5,
|
||||||
0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444,
|
0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d,
|
||||||
0xd6ac, 0xd78c
|
0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac, 0xd78c
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Collect the unicode lists and glyph_id offsets*/
|
/*Collect the unicode lists and glyph_id offsets*/
|
||||||
@@ -8099,7 +8166,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
||||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 66, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8246,7 +8313,8 @@ static const uint8_t kern_left_class_mapping[] =
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Map glyph_ids to kern right classes*/
|
/*Map glyph_ids to kern right classes*/
|
||||||
@@ -8387,7 +8455,8 @@ static const uint8_t kern_right_class_mapping[] =
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Kern values between classes*/
|
/*Kern values between classes*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Size: 14 px
|
* Size: 14 px
|
||||||
* Bpp: 4
|
* Bpp: 4
|
||||||
* Opts: --bpp 4 --size 14 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 61612,61445,62073,61632,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_14 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_14.c
|
* Opts: --bpp 4 --size 14 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_14 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_14.c
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
@@ -7348,6 +7348,18 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x63, 0x0, 0xfc, 0x8e, 0xe2, 0x0, 0xff, 0xe6,
|
0x63, 0x0, 0xfc, 0x8e, 0xe2, 0x0, 0xff, 0xe6,
|
||||||
0x10, 0x5, 0xc0, 0x6, 0x0, 0x9, 0x80, 0x0,
|
0x10, 0x5, 0xc0, 0x6, 0x0, 0x9, 0x80, 0x0,
|
||||||
|
|
||||||
|
/* U+F017 "" */
|
||||||
|
0x0, 0xff, 0xe2, 0x8c, 0x6f, 0xfb, 0x60, 0x40,
|
||||||
|
0x39, 0x39, 0xc8, 0x0, 0x4f, 0xc8, 0x1, 0x25,
|
||||||
|
0x80, 0x4a, 0xa0, 0xa, 0xd0, 0x1, 0x40, 0x1a,
|
||||||
|
0xa8, 0x1, 0xa8, 0x18, 0x40, 0x3f, 0xc2, 0xd8,
|
||||||
|
0x1, 0xff, 0xc0, 0xc6, 0x0, 0xff, 0xe0, 0x33,
|
||||||
|
0x80, 0x70, 0x87, 0x18, 0x4, 0xe6, 0x1, 0xde,
|
||||||
|
0x63, 0x0, 0x11, 0xd8, 0x7, 0xe, 0x4d, 0x0,
|
||||||
|
0x56, 0x6a, 0x1, 0xe6, 0x10, 0x2, 0x98, 0x51,
|
||||||
|
0x80, 0x7e, 0x3a, 0x0, 0xb1, 0xc0, 0x3c, 0xf8,
|
||||||
|
0x1, 0xd1, 0xd5, 0x10, 0xae, 0x80, 0x8,
|
||||||
|
|
||||||
/* U+F019 "" */
|
/* U+F019 "" */
|
||||||
0x0, 0xf1, 0x98, 0x3, 0xfe, 0xbc, 0xc5, 0x80,
|
0x0, 0xf1, 0x98, 0x3, 0xfe, 0xbc, 0xc5, 0x80,
|
||||||
0x7f, 0x9c, 0x0, 0xe0, 0x1f, 0xfe, 0x58, 0xff,
|
0x7f, 0x9c, 0x0, 0xe0, 0x1f, 0xfe, 0x58, 0xff,
|
||||||
@@ -7383,6 +7395,16 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x5, 0xea, 0x2f, 0x76, 0x71, 0x3f, 0x10, 0x1,
|
0x5, 0xea, 0x2f, 0x76, 0x71, 0x3f, 0x10, 0x1,
|
||||||
0x8d, 0x6b, 0xa2, 0x1a, 0xf0, 0x40, 0x0,
|
0x8d, 0x6b, 0xa2, 0x1a, 0xf0, 0x40, 0x0,
|
||||||
|
|
||||||
|
/* U+F024 "" */
|
||||||
|
0x1, 0x0, 0xff, 0xe0, 0xb7, 0x70, 0x40, 0x3f,
|
||||||
|
0xec, 0x1, 0x75, 0x51, 0x0, 0x71, 0x98, 0x38,
|
||||||
|
0x1, 0x35, 0x4d, 0xe9, 0x79, 0xdc, 0xc0, 0x28,
|
||||||
|
0x7, 0x85, 0xa1, 0x88, 0x3, 0xff, 0xfe, 0x1,
|
||||||
|
0xff, 0xc4, 0x20, 0x8, 0xab, 0x7f, 0xa9, 0x48,
|
||||||
|
0x4e, 0x34, 0x2, 0x75, 0x20, 0x15, 0xad, 0xec,
|
||||||
|
0x70, 0xf, 0xfe, 0x28, 0x9e, 0x80, 0x7f, 0xf0,
|
||||||
|
0x0,
|
||||||
|
|
||||||
/* U+F026 "" */
|
/* U+F026 "" */
|
||||||
0x0, 0xe2, 0x70, 0xc, 0x59, 0x0, 0x11, 0x60,
|
0x0, 0xe2, 0x70, 0xc, 0x59, 0x0, 0x11, 0x60,
|
||||||
0x86, 0xff, 0xb4, 0x40, 0x4, 0x1, 0xff, 0xcf,
|
0x86, 0xff, 0xb4, 0x40, 0x4, 0x1, 0xff, 0xcf,
|
||||||
@@ -7750,6 +7772,20 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0xa4, 0x3, 0xff, 0x80, 0x60, 0x4a, 0x1, 0xff,
|
0xa4, 0x3, 0xff, 0x80, 0x60, 0x4a, 0x1, 0xff,
|
||||||
0xc0, 0x94, 0xe0, 0xf, 0x0,
|
0xc0, 0x94, 0xe0, 0xf, 0x0,
|
||||||
|
|
||||||
|
/* U+F14E "" */
|
||||||
|
0x0, 0xff, 0xe2, 0x95, 0x77, 0xfb, 0x1c, 0x3,
|
||||||
|
0xcf, 0xaa, 0x20, 0x3, 0x8d, 0x20, 0x9, 0xe0,
|
||||||
|
0x3, 0xe2, 0xc1, 0x2, 0x80, 0xf, 0x1d, 0x10,
|
||||||
|
0xd0, 0x58, 0x7, 0x26, 0x61, 0x4c, 0x10, 0x90,
|
||||||
|
0x3, 0x5d, 0x8c, 0x1c, 0x40, 0x8, 0x40, 0x12,
|
||||||
|
0x23, 0xa0, 0x24, 0x2, 0xe1, 0x0, 0xa0, 0x26,
|
||||||
|
0xd4, 0x40, 0x2f, 0x20, 0x1, 0x98, 0x1d, 0x6c,
|
||||||
|
0x3, 0x15, 0x0, 0x28, 0x5f, 0xa4, 0x40, 0x21,
|
||||||
|
0x56, 0x20, 0x8e, 0x81, 0x0, 0xe8, 0x0, 0x78,
|
||||||
|
0x88, 0x3, 0xe6, 0x60, 0x0, 0xbd, 0x40, 0x38,
|
||||||
|
0x66, 0x40, 0x18, 0x6b, 0x65, 0xe2, 0xf9, 0x80,
|
||||||
|
0x20,
|
||||||
|
|
||||||
/* U+F15B "" */
|
/* U+F15B "" */
|
||||||
0x35, 0x5e, 0x2, 0x0, 0xb2, 0xab, 0x8b, 0x50,
|
0x35, 0x5e, 0x2, 0x0, 0xb2, 0xab, 0x8b, 0x50,
|
||||||
0x3, 0xfd, 0x68, 0x1, 0xfe, 0xb3, 0x0, 0xf0,
|
0x3, 0xfd, 0x68, 0x1, 0xfe, 0xb3, 0x0, 0xf0,
|
||||||
@@ -7858,6 +7894,17 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x10, 0xc, 0x60, 0x18, 0xc0, 0x18, 0x9, 0x1,
|
0x10, 0xc, 0x60, 0x18, 0xc0, 0x18, 0x9, 0x1,
|
||||||
0x24, 0x6, 0x3, 0x8, 0x67, 0xf3, 0x28, 0x0,
|
0x24, 0x6, 0x3, 0x8, 0x67, 0xf3, 0x28, 0x0,
|
||||||
|
|
||||||
|
/* U+F2F2 "" */
|
||||||
|
0x0, 0xff, 0xe2, 0x7f, 0xe0, 0xf, 0xca, 0x0,
|
||||||
|
0x50, 0xf, 0xd2, 0x0, 0x90, 0xf, 0x1e, 0xe0,
|
||||||
|
0x3, 0x35, 0x75, 0x1, 0x30, 0x80, 0x88, 0x5,
|
||||||
|
0x44, 0x63, 0x40, 0x16, 0x60, 0x3, 0x3b, 0x8,
|
||||||
|
0x7, 0xf3, 0x68, 0x7, 0xfb, 0x4, 0x3, 0xfc,
|
||||||
|
0x24, 0x1, 0x99, 0x80, 0x18, 0xb4, 0x3, 0x44,
|
||||||
|
0x0, 0x36, 0xa2, 0x80, 0x7e, 0x54, 0xa, 0x40,
|
||||||
|
0xf, 0x25, 0x0, 0x57, 0x48, 0x22, 0x4a, 0xb0,
|
||||||
|
0x0,
|
||||||
|
|
||||||
/* U+F304 "" */
|
/* U+F304 "" */
|
||||||
0x0, 0xff, 0x84, 0x80, 0x3f, 0xf8, 0x9, 0xda,
|
0x0, 0xff, 0x84, 0x80, 0x3f, 0xf8, 0x9, 0xda,
|
||||||
0xa0, 0x1f, 0xe2, 0xb0, 0x5, 0x28, 0x7, 0xe4,
|
0xa0, 0x1f, 0xe2, 0xb0, 0x5, 0x28, 0x7, 0xe4,
|
||||||
@@ -7870,6 +7917,35 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x32, 0x58, 0x7, 0xe2, 0x0, 0x92, 0xc0, 0x3f,
|
0x32, 0x58, 0x7, 0xe2, 0x0, 0x92, 0xc0, 0x3f,
|
||||||
0x99, 0x5e, 0x6c, 0x3, 0xf8,
|
0x99, 0x5e, 0x6c, 0x3, 0xf8,
|
||||||
|
|
||||||
|
/* U+F3C5 "" */
|
||||||
|
0x0, 0xc4, 0x40, 0xf, 0x9f, 0xb7, 0x5f, 0x22,
|
||||||
|
0x1, 0x4c, 0x8, 0x4, 0xd8, 0x20, 0xac, 0x1,
|
||||||
|
0x8, 0x0, 0xac, 0x24, 0x0, 0x9f, 0xd0, 0x0,
|
||||||
|
0x51, 0x30, 0x4, 0x80, 0x1c, 0x80, 0x4, 0x1,
|
||||||
|
0xfe, 0x73, 0x0, 0x48, 0x1, 0xc8, 0x0, 0xb2,
|
||||||
|
0x0, 0x4f, 0xe8, 0x0, 0x28, 0xaa, 0x0, 0x42,
|
||||||
|
0x0, 0x1b, 0x0, 0x48, 0x7, 0xa0, 0x40, 0x5,
|
||||||
|
0x20, 0x19, 0x18, 0x3, 0x32, 0x0, 0x6, 0x80,
|
||||||
|
0x3d, 0x42, 0x16, 0x20, 0x1e, 0x1a, 0x85, 0x0,
|
||||||
|
0xc0,
|
||||||
|
|
||||||
|
/* U+F519 "" */
|
||||||
|
0x2, 0x0, 0xff, 0xe0, 0x88, 0x81, 0xb5, 0x80,
|
||||||
|
0x3f, 0xf8, 0x19, 0xc1, 0xa0, 0xe2, 0xc2, 0x0,
|
||||||
|
0x42, 0x0, 0x2a, 0x2, 0x82, 0x29, 0xb, 0xcb,
|
||||||
|
0x85, 0xdb, 0x4c, 0x2e, 0x43, 0x0, 0xc4, 0x40,
|
||||||
|
0x20, 0x40, 0x80, 0x4, 0x2, 0x20, 0x38, 0x78,
|
||||||
|
0x90, 0x10, 0x10, 0x10, 0x0, 0x80, 0x88, 0xc,
|
||||||
|
0x1e, 0x82, 0x4b, 0xcc, 0x64, 0x40, 0xe0, 0xfd,
|
||||||
|
0xc, 0x4, 0x92, 0x70, 0x10, 0x90, 0x93, 0x42,
|
||||||
|
0x10, 0x1, 0x21, 0x9b, 0x54, 0x0, 0x2a, 0x69,
|
||||||
|
0x1, 0x60, 0x15, 0xd8, 0x3, 0xd2, 0x3, 0x7e,
|
||||||
|
0xc, 0x1, 0xff, 0x30, 0x12, 0x20, 0x0, 0xc0,
|
||||||
|
0x1f, 0xca, 0x2f, 0xff, 0x70, 0x58, 0x7, 0xf4,
|
||||||
|
0x84, 0x80, 0x42, 0xc4, 0x80, 0x1f, 0x11, 0xa8,
|
||||||
|
0x80, 0x6b, 0xe, 0x0, 0xf8, 0xa6, 0x0, 0x38,
|
||||||
|
0xa6, 0x0, 0x30,
|
||||||
|
|
||||||
/* U+F55A "" */
|
/* U+F55A "" */
|
||||||
0x0, 0xc2, 0xf1, 0x1f, 0xce, 0x80, 0x18, 0xbe,
|
0x0, 0xc2, 0xf1, 0x1f, 0xce, 0x80, 0x18, 0xbe,
|
||||||
0x1d, 0xff, 0xa2, 0xd0, 0x0, 0x78, 0x20, 0x11,
|
0x1d, 0xff, 0xa2, 0xd0, 0x0, 0x78, 0x20, 0x11,
|
||||||
@@ -8934,60 +9010,66 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||||||
{.bitmap_index = 38484, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 38484, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 38571, .adv_w = 252, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 38571, .adv_w = 252, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 38651, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 38651, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 38716, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 38730, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 38779, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 38795, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 38874, .adv_w = 112, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 38858, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 38902, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 38953, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 38948, .adv_w = 252, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 39010, .adv_w = 112, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 39038, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 39038, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 39094, .adv_w = 154, .box_w = 10, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 39084, .adv_w = 252, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 39154, .adv_w = 196, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
{.bitmap_index = 39174, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 39201, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 39230, .adv_w = 154, .box_w = 10, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 39259, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 39290, .adv_w = 196, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
||||||
{.bitmap_index = 39296, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 39337, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 39321, .adv_w = 196, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
{.bitmap_index = 39395, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 39370, .adv_w = 196, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -1},
|
{.bitmap_index = 39432, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 39429, .adv_w = 140, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 39457, .adv_w = 196, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
||||||
{.bitmap_index = 39477, .adv_w = 140, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 39506, .adv_w = 196, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -1},
|
||||||
{.bitmap_index = 39526, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 39565, .adv_w = 140, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 39573, .adv_w = 196, .box_w = 13, .box_h = 4, .ofs_x = 0, .ofs_y = 3},
|
{.bitmap_index = 39613, .adv_w = 140, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 39587, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 39662, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 39670, .adv_w = 280, .box_w = 18, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 39709, .adv_w = 196, .box_w = 13, .box_h = 4, .ofs_x = 0, .ofs_y = 3},
|
||||||
{.bitmap_index = 39787, .adv_w = 252, .box_w = 17, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 39723, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 39875, .adv_w = 224, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 39806, .adv_w = 280, .box_w = 18, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 39957, .adv_w = 196, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 39923, .adv_w = 252, .box_w = 17, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 40000, .adv_w = 196, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 40011, .adv_w = 224, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 40045, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 40093, .adv_w = 196, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 40116, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 40136, .adv_w = 196, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 40145, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 40181, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 40217, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 40252, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 40296, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 40281, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 40389, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 40353, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 40487, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 40432, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 40568, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 40525, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 40616, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 40623, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 40672, .adv_w = 196, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 40704, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 40712, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 40752, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 40765, .adv_w = 140, .box_w = 10, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 40808, .adv_w = 196, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 40821, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 40848, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 40884, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 40901, .adv_w = 140, .box_w = 10, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 40950, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 40957, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 41023, .adv_w = 224, .box_w = 16, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 41020, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 41100, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 41086, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 41132, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 41159, .adv_w = 224, .box_w = 16, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 41229, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 41236, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 41281, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 41325, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 41336, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 41357, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 41391, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 41454, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 41446, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 41506, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 41495, .adv_w = 252, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 41561, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 41540, .adv_w = 280, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 41616, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 41620, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 41671, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 41704, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 41720, .adv_w = 252, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 41760, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 41765, .adv_w = 280, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 41837, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 41845, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 41915, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 41929, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 41951, .adv_w = 225, .box_w = 15, .box_h = 10, .ofs_x = 0, .ofs_y = 0}
|
{.bitmap_index = 41985, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 42050, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 42127, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 42200, .adv_w = 280, .box_w = 18, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 42315, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||||
|
{.bitmap_index = 42393, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 42429, .adv_w = 225, .box_w = 15, .box_h = 10, .ofs_x = 0, .ofs_y = 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------
|
/*---------------------
|
||||||
@@ -9012,14 +9094,14 @@ static const uint16_t unicode_list_10[] = {
|
|||||||
|
|
||||||
static const uint16_t unicode_list_12[] = {
|
static const uint16_t unicode_list_12[] = {
|
||||||
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
||||||
0xcefb, 0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11,
|
0xcefb, 0xcefd, 0xceff, 0xcf01, 0xcf03, 0xcf06, 0xcf0b, 0xcf0e,
|
||||||
0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b,
|
0xcf10, 0xcf11, 0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36,
|
||||||
0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b,
|
0xcf37, 0xcf3b, 0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58,
|
||||||
0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96,
|
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d,
|
||||||
0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4,
|
0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca,
|
||||||
0xcfdd, 0xd006, 0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c,
|
0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045, 0xd0d5,
|
||||||
0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444,
|
0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d,
|
||||||
0xd6ac, 0xd78c
|
0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac, 0xd78c
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Collect the unicode lists and glyph_id offsets*/
|
/*Collect the unicode lists and glyph_id offsets*/
|
||||||
@@ -9075,7 +9157,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
||||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 66, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -9222,7 +9304,8 @@ static const uint8_t kern_left_class_mapping[] =
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Map glyph_ids to kern right classes*/
|
/*Map glyph_ids to kern right classes*/
|
||||||
@@ -9363,7 +9446,8 @@ static const uint8_t kern_right_class_mapping[] =
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Kern values between classes*/
|
/*Kern values between classes*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Size: 16 px
|
* Size: 16 px
|
||||||
* Bpp: 4
|
* Bpp: 4
|
||||||
* Opts: --bpp 4 --size 16 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 61612,61445,62073,61632,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_16 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_16.c
|
* Opts: --bpp 4 --size 16 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_16 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_16.c
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
@@ -8411,6 +8411,21 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x84, 0x3, 0xff, 0xa6, 0x20, 0x17, 0x0, 0x38,
|
0x84, 0x3, 0xff, 0xa6, 0x20, 0x17, 0x0, 0x38,
|
||||||
0x2, 0x10, 0x8,
|
0x2, 0x10, 0x8,
|
||||||
|
|
||||||
|
/* U+F017 "" */
|
||||||
|
0x0, 0xc3, 0x19, 0xdc, 0xc8, 0x10, 0xf, 0x9f,
|
||||||
|
0x9c, 0xc4, 0x46, 0xfc, 0xe0, 0x1d, 0x30, 0x1,
|
||||||
|
0xfa, 0x24, 0x2, 0x66, 0x0, 0x6f, 0xf0, 0x6,
|
||||||
|
0x66, 0x0, 0x20, 0x3, 0x8, 0x0, 0x40, 0x34,
|
||||||
|
0x2, 0x88, 0x7, 0xff, 0x0, 0x57, 0x0, 0x3f,
|
||||||
|
0xf8, 0x58, 0x60, 0x1f, 0x8c, 0x3, 0x8c, 0x3,
|
||||||
|
0xc2, 0x0, 0xc4, 0x0, 0xe2, 0x0, 0xf5, 0x88,
|
||||||
|
0xac, 0x40, 0x22, 0xb0, 0xf, 0x27, 0x9b, 0x8,
|
||||||
|
0x5, 0x66, 0x60, 0xf, 0xe, 0x48, 0x4, 0x66,
|
||||||
|
0xe, 0x0, 0xff, 0xe0, 0x70, 0x0, 0xb0, 0x40,
|
||||||
|
0x3f, 0xe, 0x10, 0x4, 0x78, 0x80, 0x1e, 0x4c,
|
||||||
|
0x30, 0xe, 0x2b, 0xe9, 0x77, 0x4f, 0x59, 0x0,
|
||||||
|
0x40,
|
||||||
|
|
||||||
/* U+F019 "" */
|
/* U+F019 "" */
|
||||||
0x0, 0xf6, 0xff, 0xb4, 0x3, 0xff, 0x80, 0x40,
|
0x0, 0xf6, 0xff, 0xb4, 0x3, 0xff, 0x80, 0x40,
|
||||||
0x2, 0x0, 0xff, 0xfe, 0x27, 0xfc, 0x1, 0xbf,
|
0x2, 0x0, 0xff, 0xfe, 0x27, 0xfc, 0x1, 0xbf,
|
||||||
@@ -8447,6 +8462,16 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x40, 0xa, 0xec, 0x40, 0x91, 0x2a, 0x3, 0x4e,
|
0x40, 0xa, 0xec, 0x40, 0x91, 0x2a, 0x3, 0x4e,
|
||||||
0x1, 0xc9, 0xb4, 0xa6, 0x49, 0x3c, 0xa0, 0x10,
|
0x1, 0xc9, 0xb4, 0xa6, 0x49, 0x3c, 0xa0, 0x10,
|
||||||
|
|
||||||
|
/* U+F024 "" */
|
||||||
|
0x0, 0xff, 0xe2, 0x1f, 0x70, 0xc0, 0x3f, 0xf8,
|
||||||
|
0x10, 0x22, 0x80, 0xf, 0xfe, 0x1, 0x80, 0x17,
|
||||||
|
0x7f, 0xad, 0xc8, 0x0, 0x4f, 0xb9, 0x0, 0x1,
|
||||||
|
0x20, 0x14, 0x8d, 0xff, 0x6c, 0x11, 0x80, 0x7f,
|
||||||
|
0xff, 0xc0, 0x3f, 0xfb, 0xa4, 0x8c, 0x80, 0x1f,
|
||||||
|
0x48, 0x5, 0xba, 0xb9, 0xbf, 0xb7, 0x56, 0x9e,
|
||||||
|
0x60, 0x8, 0x80, 0x39, 0x22, 0xa5, 0x84, 0x3,
|
||||||
|
0xff, 0x8c, 0x44, 0x0, 0xff, 0xe0, 0x80,
|
||||||
|
|
||||||
/* U+F026 "" */
|
/* U+F026 "" */
|
||||||
0x0, 0xff, 0xe1, 0x46, 0x80, 0x74, 0x39, 0x0,
|
0x0, 0xff, 0xe1, 0x46, 0x80, 0x74, 0x39, 0x0,
|
||||||
0x68, 0x70, 0x6, 0xff, 0xce, 0x1, 0x10, 0x7,
|
0x68, 0x70, 0x6, 0xff, 0xce, 0x1, 0x10, 0x7,
|
||||||
@@ -8851,6 +8876,21 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x38, 0x39, 0x0, 0x7f, 0xf0, 0xa3, 0xe0, 0x3,
|
0x38, 0x39, 0x0, 0x7f, 0xf0, 0xa3, 0xe0, 0x3,
|
||||||
0xe0,
|
0xe0,
|
||||||
|
|
||||||
|
/* U+F14E "" */
|
||||||
|
0x0, 0xc2, 0xd5, 0x75, 0x6, 0x1, 0xf9, 0xfa,
|
||||||
|
0x55, 0x15, 0xf3, 0x4, 0x1, 0xd5, 0x0, 0x1f,
|
||||||
|
0x1e, 0x98, 0x5, 0xa, 0x1, 0xfe, 0xd2, 0x2,
|
||||||
|
0x70, 0xf, 0x93, 0x24, 0x6, 0x2, 0x80, 0x3c,
|
||||||
|
0xdb, 0x67, 0xe0, 0x5, 0x15, 0x0, 0xc3, 0xb2,
|
||||||
|
0x40, 0x2c, 0x1, 0x21, 0x0, 0x69, 0x3e, 0x80,
|
||||||
|
0x90, 0xc, 0x40, 0x1c, 0xc0, 0x19, 0x80, 0x38,
|
||||||
|
0x80, 0x27, 0x11, 0x74, 0x40, 0x40, 0x31, 0x28,
|
||||||
|
0x5, 0x20, 0x6, 0xd7, 0x0, 0xe4, 0xa0, 0x1,
|
||||||
|
0x3, 0xf4, 0x90, 0x7, 0x28, 0x93, 0x81, 0x74,
|
||||||
|
0x8, 0x7, 0x86, 0x0, 0x10, 0xa0, 0x1f, 0xed,
|
||||||
|
0x20, 0xa, 0xa0, 0x3, 0xe3, 0xd3, 0x0, 0xe7,
|
||||||
|
0xe9, 0x54, 0x57, 0xcc, 0x10, 0x4,
|
||||||
|
|
||||||
/* U+F15B "" */
|
/* U+F15B "" */
|
||||||
0xdf, 0xff, 0x6, 0x88, 0x0, 0x80, 0x3e, 0x2c,
|
0xdf, 0xff, 0x6, 0x88, 0x0, 0x80, 0x3e, 0x2c,
|
||||||
0x10, 0xf, 0xf1, 0x60, 0x80, 0x7f, 0x8b, 0x0,
|
0x10, 0xf, 0xf1, 0x60, 0x80, 0x7f, 0x8b, 0x0,
|
||||||
@@ -8962,6 +9002,19 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x0, 0x88, 0x4, 0x40, 0x1e, 0x66, 0x3, 0x30,
|
0x0, 0x88, 0x4, 0x40, 0x1e, 0x66, 0x3, 0x30,
|
||||||
0x19, 0x80, 0x19, 0xc0, 0x3f, 0xce, 0x0,
|
0x19, 0x80, 0x19, 0xc0, 0x3f, 0xce, 0x0,
|
||||||
|
|
||||||
|
/* U+F2F2 "" */
|
||||||
|
0x0, 0xc7, 0xff, 0x8c, 0x3, 0xff, 0x94, 0x7e,
|
||||||
|
0x0, 0xf3, 0x0, 0xf8, 0x5f, 0x0, 0x18, 0xe0,
|
||||||
|
0x28, 0x1, 0x1f, 0xc1, 0x80, 0xe, 0x3b, 0x2d,
|
||||||
|
0x0, 0xb0, 0x40, 0xe, 0xe0, 0x0, 0x91, 0x14,
|
||||||
|
0x24, 0x3, 0x44, 0x0, 0x33, 0x9, 0x20, 0x7,
|
||||||
|
0xf9, 0x9, 0x0, 0x3f, 0xf8, 0x8, 0x20, 0x1f,
|
||||||
|
0xfc, 0x1, 0x10, 0x7, 0xff, 0x0, 0x50, 0x3,
|
||||||
|
0xbf, 0xc0, 0x1c, 0x84, 0x60, 0x1f, 0xe4, 0x20,
|
||||||
|
0xe1, 0x0, 0xfc, 0x32, 0x0, 0x2d, 0x10, 0xf,
|
||||||
|
0xe, 0x90, 0x4, 0x7d, 0x4, 0x0, 0x38, 0xe3,
|
||||||
|
0x0, 0x0,
|
||||||
|
|
||||||
/* U+F304 "" */
|
/* U+F304 "" */
|
||||||
0x0, 0xff, 0xe0, 0x3f, 0xd0, 0x7, 0xff, 0x5,
|
0x0, 0xff, 0xe0, 0x3f, 0xd0, 0x7, 0xff, 0x5,
|
||||||
0xe0, 0x16, 0xc0, 0x3f, 0xf8, 0x14, 0x1, 0x25,
|
0xe0, 0x16, 0xc0, 0x3f, 0xf8, 0x14, 0x1, 0x25,
|
||||||
@@ -8976,6 +9029,38 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x1a, 0x1c, 0x3, 0xfc, 0x62, 0x49, 0x2e, 0x1,
|
0x1a, 0x1c, 0x3, 0xfc, 0x62, 0x49, 0x2e, 0x1,
|
||||||
0xff, 0x6f, 0x6d, 0xb0, 0x7, 0xfc,
|
0xff, 0x6f, 0x6d, 0xb0, 0x7, 0xfc,
|
||||||
|
|
||||||
|
/* U+F3C5 "" */
|
||||||
|
0x0, 0x9f, 0x3f, 0xd8, 0xe0, 0x18, 0x76, 0xc,
|
||||||
|
0x0, 0x71, 0xa2, 0x0, 0xc2, 0x0, 0xf1, 0x60,
|
||||||
|
0x39, 0x0, 0x4c, 0xc0, 0x8, 0x9e, 0xc0, 0x2d,
|
||||||
|
0x99, 0x68, 0x5, 0x66, 0x0, 0x62, 0x0, 0x13,
|
||||||
|
0x0, 0xc, 0x3, 0xff, 0x80, 0x60, 0x6, 0x20,
|
||||||
|
0x1, 0x30, 0x0, 0xe8, 0x2, 0xd9, 0x96, 0x80,
|
||||||
|
0x54, 0xc4, 0x1, 0x33, 0x0, 0x22, 0x60, 0xe0,
|
||||||
|
0xf, 0xdc, 0x0, 0x37, 0x0, 0xf3, 0x98, 0x5,
|
||||||
|
0x6, 0x1, 0x8e, 0x0, 0x3b, 0x80, 0x37, 0x0,
|
||||||
|
0x78, 0xa0, 0x1, 0x4, 0x1, 0xf3, 0xa2, 0x1c,
|
||||||
|
0x3, 0x0,
|
||||||
|
|
||||||
|
/* U+F519 "" */
|
||||||
|
0x3f, 0xc0, 0xf, 0xfe, 0x16, 0x79, 0xd0, 0x58,
|
||||||
|
0x7, 0xff, 0x9, 0x2, 0x90, 0x14, 0x2f, 0xc8,
|
||||||
|
0x13, 0xb8, 0x80, 0x5f, 0x61, 0x40, 0x84, 0x4,
|
||||||
|
0xa, 0x6, 0x14, 0x22, 0xa0, 0x30, 0x50, 0x20,
|
||||||
|
0x20, 0xf, 0xfe, 0x28, 0x80, 0x8, 0xc, 0x14,
|
||||||
|
0xc, 0xc, 0x0, 0x60, 0x60, 0xa0, 0x40, 0x48,
|
||||||
|
0x8, 0x17, 0xe4, 0x64, 0x22, 0x23, 0x2f, 0xb0,
|
||||||
|
0xb0, 0x4a, 0xb, 0x0, 0xd2, 0xc, 0xc0, 0x90,
|
||||||
|
0xc, 0x81, 0x47, 0xf8, 0x1, 0xa, 0x85, 0x50,
|
||||||
|
0x14, 0x40, 0x2c, 0xf3, 0x0, 0xf3, 0x2, 0x11,
|
||||||
|
0x10, 0x18, 0x3, 0xff, 0x81, 0x40, 0x9f, 0xe4,
|
||||||
|
0xa, 0x0, 0xff, 0x90, 0x80, 0x3c, 0x48, 0x1,
|
||||||
|
0xfe, 0xf0, 0x8f, 0xfd, 0x1, 0xe0, 0x1f, 0xc4,
|
||||||
|
0x80, 0xc0, 0x19, 0x81, 0x8, 0x3, 0xf5, 0x3,
|
||||||
|
0x8, 0x6, 0x16, 0xa, 0x0, 0xfd, 0xc3, 0x40,
|
||||||
|
0x1e, 0xa1, 0xe0, 0xf, 0xcd, 0xc6, 0x1, 0xe3,
|
||||||
|
0xe6, 0x0, 0xc0,
|
||||||
|
|
||||||
/* U+F55A "" */
|
/* U+F55A "" */
|
||||||
0x0, 0xc3, 0x7f, 0xff, 0xfc, 0xe, 0x40, 0x8,
|
0x0, 0xc3, 0x7f, 0xff, 0xfc, 0xe, 0x40, 0x8,
|
||||||
0x71, 0x0, 0x3f, 0xf8, 0x3, 0x40, 0x1, 0xc2,
|
0x71, 0x0, 0x3f, 0xf8, 0x3, 0x40, 0x1, 0xc2,
|
||||||
@@ -10043,60 +10128,66 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||||||
{.bitmap_index = 46964, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 46964, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 47066, .adv_w = 288, .box_w = 18, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 47066, .adv_w = 288, .box_w = 18, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 47157, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 47157, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 47225, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 47254, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 47288, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 47322, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 47392, .adv_w = 128, .box_w = 8, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 47385, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 47423, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 47489, .adv_w = 256, .box_w = 16, .box_h = 17, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 47474, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 47552, .adv_w = 128, .box_w = 8, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 47581, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 47583, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 47648, .adv_w = 176, .box_w = 11, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 47634, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 47715, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2},
|
{.bitmap_index = 47741, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 47767, .adv_w = 224, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 47808, .adv_w = 176, .box_w = 11, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 47839, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 47875, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2},
|
||||||
{.bitmap_index = 47868, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 47927, .adv_w = 224, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 47888, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2},
|
{.bitmap_index = 47999, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 47940, .adv_w = 224, .box_w = 16, .box_h = 14, .ofs_x = -1, .ofs_y = -1},
|
{.bitmap_index = 48028, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 48011, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 48048, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2},
|
||||||
{.bitmap_index = 48068, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 48100, .adv_w = 224, .box_w = 16, .box_h = 14, .ofs_x = -1, .ofs_y = -1},
|
||||||
{.bitmap_index = 48125, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 48171, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 48170, .adv_w = 224, .box_w = 14, .box_h = 4, .ofs_x = 0, .ofs_y = 4},
|
{.bitmap_index = 48228, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 48187, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 48285, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 48286, .adv_w = 320, .box_w = 20, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 48330, .adv_w = 224, .box_w = 14, .box_h = 4, .ofs_x = 0, .ofs_y = 4},
|
||||||
{.bitmap_index = 48420, .adv_w = 288, .box_w = 20, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 48347, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 48532, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 48446, .adv_w = 320, .box_w = 20, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 48632, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 48580, .adv_w = 288, .box_w = 20, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 48687, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 48692, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 48744, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 48792, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 48832, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 48847, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 48861, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 48904, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 48929, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 48992, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 49023, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 49021, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 49131, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 49089, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 49241, .adv_w = 224, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 49183, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 49332, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 49291, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 49379, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 49401, .adv_w = 224, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 49431, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 49492, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 49486, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 49539, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 49545, .adv_w = 160, .box_w = 12, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 49591, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 49613, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 49646, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 49674, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 49705, .adv_w = 160, .box_w = 12, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 49744, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 49773, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 49810, .adv_w = 256, .box_w = 18, .box_h = 18, .ofs_x = -1, .ofs_y = -3},
|
{.bitmap_index = 49834, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 49899, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 49904, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 49932, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 49970, .adv_w = 256, .box_w = 18, .box_h = 18, .ofs_x = -1, .ofs_y = -3},
|
||||||
{.bitmap_index = 50045, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 50059, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 50090, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 50161, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 50134, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 50194, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 50178, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 50307, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 50224, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 50352, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 50264, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 50396, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 50323, .adv_w = 320, .box_w = 21, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 50440, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 50424, .adv_w = 224, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = -2},
|
{.bitmap_index = 50486, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 50520, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 50526, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 50575, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -3},
|
{.bitmap_index = 50585, .adv_w = 320, .box_w = 21, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 50669, .adv_w = 320, .box_w = 20, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 50686, .adv_w = 224, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = -2},
|
||||||
{.bitmap_index = 50758, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 50782, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 50797, .adv_w = 258, .box_w = 17, .box_h = 11, .ofs_x = 0, .ofs_y = 1}
|
{.bitmap_index = 50837, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 50919, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -3},
|
||||||
|
{.bitmap_index = 51013, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 51095, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -3},
|
||||||
|
{.bitmap_index = 51226, .adv_w = 320, .box_w = 20, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||||
|
{.bitmap_index = 51315, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||||
|
{.bitmap_index = 51354, .adv_w = 258, .box_w = 17, .box_h = 11, .ofs_x = 0, .ofs_y = 1}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------
|
/*---------------------
|
||||||
@@ -10121,14 +10212,14 @@ static const uint16_t unicode_list_10[] = {
|
|||||||
|
|
||||||
static const uint16_t unicode_list_12[] = {
|
static const uint16_t unicode_list_12[] = {
|
||||||
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
||||||
0xcefb, 0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11,
|
0xcefb, 0xcefd, 0xceff, 0xcf01, 0xcf03, 0xcf06, 0xcf0b, 0xcf0e,
|
||||||
0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b,
|
0xcf10, 0xcf11, 0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36,
|
||||||
0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b,
|
0xcf37, 0xcf3b, 0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58,
|
||||||
0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96,
|
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d,
|
||||||
0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4,
|
0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca,
|
||||||
0xcfdd, 0xd006, 0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c,
|
0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045, 0xd0d5,
|
||||||
0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444,
|
0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d,
|
||||||
0xd6ac, 0xd78c
|
0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac, 0xd78c
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Collect the unicode lists and glyph_id offsets*/
|
/*Collect the unicode lists and glyph_id offsets*/
|
||||||
@@ -10184,7 +10275,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
||||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 66, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -10331,7 +10422,8 @@ static const uint8_t kern_left_class_mapping[] =
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Map glyph_ids to kern right classes*/
|
/*Map glyph_ids to kern right classes*/
|
||||||
@@ -10472,7 +10564,8 @@ static const uint8_t kern_right_class_mapping[] =
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Kern values between classes*/
|
/*Kern values between classes*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Size: 20 px
|
* Size: 20 px
|
||||||
* Bpp: 4
|
* Bpp: 4
|
||||||
* Opts: --bpp 4 --size 20 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 61612,61445,62073,61632,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_20 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_20.c
|
* Opts: --bpp 4 --size 20 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_20 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_20.c
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
@@ -10547,6 +10547,25 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x1c, 0x40, 0x11, 0x0, 0x66, 0x0, 0xf8, 0xbf,
|
0x1c, 0x40, 0x11, 0x0, 0x66, 0x0, 0xf8, 0xbf,
|
||||||
0xf9, 0x0, 0x2c, 0xff, 0xd4, 0x1, 0x80,
|
0xf9, 0x0, 0x2c, 0xff, 0xd4, 0x1, 0x80,
|
||||||
|
|
||||||
|
/* U+F017 "" */
|
||||||
|
0x0, 0xff, 0xe6, 0x8b, 0xe7, 0x7f, 0xb6, 0x50,
|
||||||
|
0x3, 0xfc, 0xfd, 0x6, 0x20, 0x2, 0x6b, 0xc2,
|
||||||
|
0x0, 0xfa, 0xe0, 0x3, 0xf8, 0xf1, 0x0, 0x3a,
|
||||||
|
0x90, 0x3, 0x12, 0x20, 0x3, 0xd, 0x90, 0x4,
|
||||||
|
0xca, 0x1, 0xd7, 0x70, 0x80, 0x77, 0x80, 0x50,
|
||||||
|
0x1, 0xff, 0xc3, 0x26, 0x6, 0x10, 0xf, 0xfe,
|
||||||
|
0x25, 0x86, 0x0, 0x7f, 0xf1, 0x48, 0x58, 0x3,
|
||||||
|
0xff, 0x8c, 0xa4, 0x1, 0xfe, 0x20, 0xf, 0x84,
|
||||||
|
0xc0, 0x3f, 0xd8, 0xc0, 0x1e, 0x16, 0x0, 0xfa,
|
||||||
|
0xcc, 0x1, 0x32, 0x0, 0xe6, 0xc0, 0xf, 0x8b,
|
||||||
|
0x18, 0x1, 0x80, 0x18, 0x49, 0x40, 0x3f, 0xa6,
|
||||||
|
0xa1, 0x40, 0x33, 0x81, 0x30, 0x7, 0xf2, 0xb8,
|
||||||
|
0x7, 0x40, 0x2, 0x8, 0x3, 0xff, 0x85, 0x42,
|
||||||
|
0x0, 0x1f, 0x10, 0xf, 0xfe, 0x3, 0xa8, 0x6,
|
||||||
|
0x2f, 0x30, 0xf, 0xf5, 0x40, 0x7, 0x87, 0x28,
|
||||||
|
0xc0, 0x38, 0x5b, 0x94, 0x3, 0xf9, 0x73, 0xb2,
|
||||||
|
0xed, 0xbd, 0x22, 0x1, 0xc0,
|
||||||
|
|
||||||
/* U+F019 "" */
|
/* U+F019 "" */
|
||||||
0x0, 0xfc, 0xac, 0xc5, 0x0, 0xff, 0xe1, 0xbd,
|
0x0, 0xfc, 0xac, 0xc5, 0x0, 0xff, 0xe1, 0xbd,
|
||||||
0x4c, 0xa9, 0xc0, 0x3f, 0xf8, 0x5e, 0x1, 0xbc,
|
0x4c, 0xa9, 0xc0, 0x3f, 0xf8, 0x5e, 0x1, 0xbc,
|
||||||
@@ -10599,6 +10618,19 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x70, 0xc, 0xa9, 0x80, 0x12, 0xdf, 0xf7, 0x3f,
|
0x70, 0xc, 0xa9, 0x80, 0x12, 0xdf, 0xf7, 0x3f,
|
||||||
0x20, 0x40, 0x38,
|
0x20, 0x40, 0x38,
|
||||||
|
|
||||||
|
/* U+F024 "" */
|
||||||
|
0x1, 0x30, 0xf, 0xfe, 0x2a, 0x76, 0x68, 0x80,
|
||||||
|
0x7f, 0xf0, 0xe0, 0x0, 0x4c, 0x1, 0xff, 0xc3,
|
||||||
|
0x70, 0xb, 0x66, 0xed, 0x2a, 0x20, 0x1e, 0x6b,
|
||||||
|
0x49, 0x0, 0x95, 0x91, 0xd, 0x5d, 0x90, 0xf1,
|
||||||
|
0x7f, 0x29, 0x4, 0x20, 0x1f, 0xc6, 0xf0, 0xe8,
|
||||||
|
0x1, 0x8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe,
|
||||||
|
0x1, 0xff, 0xd1, 0x40, 0xc, 0x4f, 0x57, 0x92,
|
||||||
|
0x80, 0x1e, 0x18, 0x90, 0x9, 0xb6, 0x15, 0xd,
|
||||||
|
0xaf, 0xee, 0x1e, 0x2f, 0x9c, 0x3, 0xff, 0x82,
|
||||||
|
0x8f, 0xe, 0x80, 0x1f, 0xfe, 0x9, 0x4a, 0x0,
|
||||||
|
0xff, 0xe2, 0x0,
|
||||||
|
|
||||||
/* U+F026 "" */
|
/* U+F026 "" */
|
||||||
0x0, 0xfe, 0x10, 0xf, 0x8b, 0xbc, 0x3, 0xc5,
|
0x0, 0xfe, 0x10, 0xf, 0x8b, 0xbc, 0x3, 0xc5,
|
||||||
0x82, 0x20, 0xe, 0x2c, 0x10, 0x2, 0x3b, 0xec,
|
0x82, 0x20, 0xe, 0x2c, 0x10, 0x2, 0x3b, 0xec,
|
||||||
@@ -11154,6 +11186,27 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x20, 0x8, 0x0, 0xff, 0xe3, 0x64, 0x62, 0x0,
|
0x20, 0x8, 0x0, 0xff, 0xe3, 0x64, 0x62, 0x0,
|
||||||
0x7e,
|
0x7e,
|
||||||
|
|
||||||
|
/* U+F14E "" */
|
||||||
|
0x0, 0xff, 0xe6, 0x94, 0x6f, 0xfd, 0xd4, 0x80,
|
||||||
|
0x1f, 0xe9, 0xd7, 0x20, 0x8, 0x56, 0xf0, 0x80,
|
||||||
|
0x3c, 0x38, 0xc0, 0x1f, 0xc7, 0xa8, 0x1, 0xda,
|
||||||
|
0x60, 0x1f, 0xfc, 0xb, 0x30, 0xa, 0xc, 0x3,
|
||||||
|
0xfc, 0xa6, 0x0, 0xd0, 0x0, 0xb8, 0x7, 0xf3,
|
||||||
|
0xf5, 0x50, 0x0, 0x2e, 0xc, 0x1, 0xf0, 0xc7,
|
||||||
|
0xc0, 0x85, 0x0, 0x54, 0x16, 0x1, 0xe5, 0xe7,
|
||||||
|
0x0, 0x90, 0xc0, 0x22, 0x28, 0x3, 0xd6, 0x32,
|
||||||
|
0x80, 0xf, 0x0, 0xe6, 0x10, 0xe, 0x71, 0x96,
|
||||||
|
0xa0, 0x24, 0x0, 0xe1, 0x10, 0x7, 0x48, 0x51,
|
||||||
|
0xc8, 0x40, 0x7, 0x84, 0x80, 0x32, 0x88, 0x16,
|
||||||
|
0x3a, 0x28, 0x7, 0x99, 0x0, 0x34, 0x0, 0x49,
|
||||||
|
0x76, 0x0, 0xf0, 0x95, 0x80, 0x46, 0x40, 0xbb,
|
||||||
|
0x68, 0x1, 0xf3, 0x81, 0xa8, 0x0, 0xe7, 0xa8,
|
||||||
|
0x80, 0x3f, 0xa0, 0x1, 0x62, 0x0, 0x61, 0x0,
|
||||||
|
0xff, 0x50, 0x80, 0x7, 0x4, 0x3, 0xff, 0x81,
|
||||||
|
0xa, 0x1, 0x8b, 0xcc, 0x3, 0xf8, 0x69, 0xc0,
|
||||||
|
0x3c, 0x39, 0x46, 0x1, 0xc4, 0xfe, 0xa0, 0x1f,
|
||||||
|
0xcb, 0x9f, 0x97, 0x9d, 0xb0, 0x20, 0x1c,
|
||||||
|
|
||||||
/* U+F15B "" */
|
/* U+F15B "" */
|
||||||
0x24, 0x4f, 0x8c, 0xc, 0x3, 0x6d, 0xdf, 0xde,
|
0x24, 0x4f, 0x8c, 0xc, 0x3, 0x6d, 0xdf, 0xde,
|
||||||
0x18, 0xc0, 0x1f, 0xfc, 0x29, 0x60, 0xf, 0xfe,
|
0x18, 0xc0, 0x1f, 0xfc, 0x29, 0x60, 0xf, 0xfe,
|
||||||
@@ -11305,6 +11358,25 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x0, 0x70, 0x6, 0x0, 0x7f, 0xf0, 0x44, 0xc0,
|
0x0, 0x70, 0x6, 0x0, 0x7f, 0xf0, 0x44, 0xc0,
|
||||||
0xf, 0x50, 0xef, 0xfe, 0x8c, 0x0, 0x0,
|
0xf, 0x50, 0xef, 0xfe, 0x8c, 0x0, 0x0,
|
||||||
|
|
||||||
|
/* U+F2F2 "" */
|
||||||
|
0x0, 0xf2, 0xc4, 0x65, 0x0, 0xff, 0xe0, 0x43,
|
||||||
|
0xbe, 0x90, 0xf, 0xfe, 0x0, 0x80, 0x67, 0x0,
|
||||||
|
0xff, 0xe0, 0x65, 0x80, 0x32, 0xc0, 0x3f, 0xf8,
|
||||||
|
0xb, 0xe0, 0x9, 0x50, 0xf, 0xf3, 0x75, 0x20,
|
||||||
|
0x1, 0x6b, 0x95, 0x5e, 0xa0, 0x1a, 0x64, 0x20,
|
||||||
|
0x1e, 0x1a, 0xa0, 0x58, 0x5, 0xc, 0x1, 0xc,
|
||||||
|
0xc8, 0x40, 0x3b, 0x40, 0x6, 0xe0, 0x19, 0x59,
|
||||||
|
0x84, 0x1, 0xc4, 0x0, 0x90, 0xf, 0xfe, 0x14,
|
||||||
|
0x80, 0x10, 0x3, 0xff, 0x84, 0xa0, 0x22, 0x0,
|
||||||
|
0xff, 0xe1, 0x10, 0x18, 0x7, 0xff, 0x14, 0x80,
|
||||||
|
0x3c, 0xe0, 0x1, 0x0, 0xfc, 0x40, 0x1c, 0x7f,
|
||||||
|
0xe2, 0x0, 0xe4, 0x0, 0x50, 0x7, 0xff, 0xb,
|
||||||
|
0x40, 0xe, 0x20, 0x1f, 0xfc, 0x2, 0x60, 0xb,
|
||||||
|
0x40, 0x3f, 0xe1, 0xf0, 0xc, 0x78, 0x20, 0x1f,
|
||||||
|
0x8b, 0x8, 0x3, 0x8f, 0xdc, 0x40, 0x30, 0xc6,
|
||||||
|
0x90, 0x7, 0xc3, 0x1d, 0xb7, 0x6d, 0xe7, 0x0,
|
||||||
|
0xe0,
|
||||||
|
|
||||||
/* U+F304 "" */
|
/* U+F304 "" */
|
||||||
0x0, 0xff, 0xe1, 0x8b, 0x20, 0x7, 0xff, 0x14,
|
0x0, 0xff, 0xe1, 0x8b, 0x20, 0x7, 0xff, 0x14,
|
||||||
0x72, 0x6e, 0x0, 0x3f, 0xf8, 0x63, 0xe4, 0x0,
|
0x72, 0x6e, 0x0, 0x3f, 0xf8, 0x63, 0xe4, 0x0,
|
||||||
@@ -11325,6 +11397,51 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x38, 0x40, 0x1f, 0xfc, 0x1a, 0x8a, 0xce, 0xe1,
|
0x38, 0x40, 0x1f, 0xfc, 0x1a, 0x8a, 0xce, 0xe1,
|
||||||
0x0, 0x7f, 0xf0, 0x40,
|
0x0, 0x7f, 0xf0, 0x40,
|
||||||
|
|
||||||
|
/* U+F3C5 "" */
|
||||||
|
0x0, 0xe3, 0x67, 0x63, 0x0, 0xfc, 0xbb, 0x93,
|
||||||
|
0x13, 0x9a, 0xa0, 0x1d, 0x34, 0x40, 0x1c, 0x55,
|
||||||
|
0x20, 0x13, 0xb0, 0x7, 0xf3, 0x38, 0x14, 0x0,
|
||||||
|
0x70, 0x80, 0x74, 0x15, 0x80, 0x65, 0xee, 0x94,
|
||||||
|
0x3, 0x5a, 0x0, 0x47, 0x42, 0x3, 0x46, 0x1,
|
||||||
|
0x21, 0x0, 0x56, 0x1, 0xd6, 0x1, 0x10, 0x7,
|
||||||
|
0xff, 0xc, 0x80, 0x2b, 0x0, 0xeb, 0x0, 0x89,
|
||||||
|
0x40, 0x23, 0xa1, 0x1, 0xa3, 0x0, 0x96, 0x40,
|
||||||
|
0x32, 0xf7, 0x4a, 0x1, 0xa4, 0x5c, 0x3, 0x84,
|
||||||
|
0x3, 0x9c, 0x42, 0x8, 0x3, 0xf8, 0xa0, 0x2,
|
||||||
|
0xe0, 0xf, 0xee, 0x0, 0xc7, 0x0, 0x1f, 0x41,
|
||||||
|
0x80, 0x73, 0x98, 0x7, 0x1b, 0x80, 0x7d, 0xc0,
|
||||||
|
0x1d, 0xc0, 0x1f, 0x8a, 0x40, 0x29, 0x20, 0xf,
|
||||||
|
0xe6, 0x40, 0x46, 0x0, 0xff, 0xaa, 0x28, 0x3,
|
||||||
|
0xc0,
|
||||||
|
|
||||||
|
/* U+F519 "" */
|
||||||
|
0x3, 0x41, 0x0, 0xff, 0xe2, 0x8a, 0x18, 0x16,
|
||||||
|
0x5c, 0x80, 0x7f, 0xf1, 0x66, 0xf0, 0xa8, 0x1,
|
||||||
|
0x40, 0x1f, 0xfc, 0x5a, 0x0, 0x52, 0x1, 0x90,
|
||||||
|
0x3e, 0x40, 0x5, 0x17, 0x0, 0x14, 0x63, 0x81,
|
||||||
|
0x18, 0x21, 0x2, 0x80, 0x24, 0xc8, 0x1, 0x4e,
|
||||||
|
0x8f, 0x40, 0x2, 0x3a, 0x0, 0x28, 0x10, 0x80,
|
||||||
|
0x80, 0x4, 0x8, 0x0, 0xa0, 0x12, 0x80, 0x8,
|
||||||
|
0x8, 0x0, 0x20, 0x20, 0x1, 0x0, 0x8, 0x8,
|
||||||
|
0x0, 0x80, 0x22, 0x0, 0x8, 0x8, 0x0, 0x40,
|
||||||
|
0x4, 0x4, 0x0, 0x50, 0x50, 0x3, 0x0, 0x42,
|
||||||
|
0x0, 0x50, 0x50, 0x1, 0x1, 0x20, 0x20, 0x2,
|
||||||
|
0xb3, 0x40, 0x90, 0x2, 0x32, 0xd, 0xca, 0x0,
|
||||||
|
0x20, 0x3e, 0x80, 0x18, 0x4, 0xc4, 0x2c, 0x1,
|
||||||
|
0x60, 0xb, 0x1, 0x31, 0x6, 0x0, 0x7a, 0x2a,
|
||||||
|
0x18, 0x7, 0x30, 0x22, 0x40, 0xc0, 0x1c, 0x68,
|
||||||
|
0xaa, 0xa, 0xb5, 0x0, 0xcc, 0x0, 0xf0, 0xf0,
|
||||||
|
0x3, 0x80, 0x65, 0xba, 0x0, 0xfe, 0xb0, 0x24,
|
||||||
|
0x4, 0x20, 0xa0, 0xf, 0xfe, 0x1a, 0x10, 0x17,
|
||||||
|
0xfc, 0x40, 0x48, 0x1, 0xff, 0xc2, 0xe0, 0xf,
|
||||||
|
0xef, 0x0, 0xff, 0xe0, 0x8a, 0x82, 0x3b, 0xf2,
|
||||||
|
0x2, 0x10, 0x7, 0xff, 0x2, 0x40, 0x13, 0x11,
|
||||||
|
0xd2, 0x0, 0xa0, 0xf, 0xfe, 0x3, 0x2, 0x10,
|
||||||
|
0x7, 0x12, 0x3, 0x0, 0x7f, 0xca, 0x21, 0xc0,
|
||||||
|
0x1f, 0x70, 0xa, 0x80, 0x7f, 0xb0, 0x5, 0x40,
|
||||||
|
0x3e, 0x51, 0xc, 0x0, 0xff, 0x4d, 0xe8, 0x7,
|
||||||
|
0xf6, 0xd4, 0x80, 0x70,
|
||||||
|
|
||||||
/* U+F55A "" */
|
/* U+F55A "" */
|
||||||
0x0, 0xf3, 0x77, 0xff, 0xff, 0xe, 0xc8, 0x3,
|
0x0, 0xf3, 0x77, 0xff, 0xff, 0xe, 0xc8, 0x3,
|
||||||
0xa2, 0x44, 0x3, 0xff, 0x86, 0x92, 0x1, 0xa1,
|
0xa2, 0x44, 0x3, 0xff, 0x86, 0x92, 0x1, 0xa1,
|
||||||
@@ -12399,60 +12516,66 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||||||
{.bitmap_index = 63746, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 63746, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 63899, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 63899, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 64042, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 64042, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 64146, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 64175, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 64243, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 64279, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 64398, .adv_w = 160, .box_w = 10, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 64376, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 64436, .adv_w = 240, .box_w = 15, .box_h = 16, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 64531, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 64510, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 64614, .adv_w = 160, .box_w = 10, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 64664, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 64652, .adv_w = 240, .box_w = 15, .box_h = 16, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 64759, .adv_w = 220, .box_w = 14, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 64726, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 64862, .adv_w = 280, .box_w = 13, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
|
{.bitmap_index = 64880, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 64930, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 64975, .adv_w = 220, .box_w = 14, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 65032, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 65078, .adv_w = 280, .box_w = 13, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
|
||||||
{.bitmap_index = 65089, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 65146, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 65130, .adv_w = 280, .box_w = 13, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
|
{.bitmap_index = 65248, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 65204, .adv_w = 280, .box_w = 19, .box_h = 19, .ofs_x = -1, .ofs_y = -2},
|
{.bitmap_index = 65305, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 65303, .adv_w = 200, .box_w = 11, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
{.bitmap_index = 65346, .adv_w = 280, .box_w = 13, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
|
||||||
{.bitmap_index = 65388, .adv_w = 200, .box_w = 11, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
{.bitmap_index = 65420, .adv_w = 280, .box_w = 19, .box_h = 19, .ofs_x = -1, .ofs_y = -2},
|
||||||
{.bitmap_index = 65469, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 65519, .adv_w = 200, .box_w = 11, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||||
{.bitmap_index = 65541, .adv_w = 280, .box_w = 18, .box_h = 5, .ofs_x = 0, .ofs_y = 5},
|
{.bitmap_index = 65604, .adv_w = 200, .box_w = 11, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||||
{.bitmap_index = 65563, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 65685, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 65713, .adv_w = 400, .box_w = 26, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
{.bitmap_index = 65757, .adv_w = 280, .box_w = 18, .box_h = 5, .ofs_x = 0, .ofs_y = 5},
|
||||||
{.bitmap_index = 65916, .adv_w = 360, .box_w = 24, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
{.bitmap_index = 65779, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 66069, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 65929, .adv_w = 400, .box_w = 26, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||||
{.bitmap_index = 66211, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 2},
|
{.bitmap_index = 66132, .adv_w = 360, .box_w = 24, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||||
{.bitmap_index = 66287, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 2},
|
{.bitmap_index = 66285, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 66365, .adv_w = 400, .box_w = 26, .box_h = 16, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 66427, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 2},
|
||||||
{.bitmap_index = 66483, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 66503, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 2},
|
||||||
{.bitmap_index = 66527, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 66581, .adv_w = 400, .box_w = 26, .box_h = 16, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 66637, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
{.bitmap_index = 66699, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 66775, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 66743, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 66934, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 66853, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||||
{.bitmap_index = 67103, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 66991, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 67251, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 67150, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 67324, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 67319, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 67417, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 67467, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 67477, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 67540, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 67567, .adv_w = 200, .box_w = 14, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
{.bitmap_index = 67633, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 67660, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 67693, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 67748, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 67783, .adv_w = 200, .box_w = 14, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||||
{.bitmap_index = 67859, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 67876, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 67985, .adv_w = 320, .box_w = 22, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
{.bitmap_index = 67964, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 68106, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 68075, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 68154, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 68201, .adv_w = 320, .box_w = 22, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||||
{.bitmap_index = 68318, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 68322, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 68385, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 68473, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 68453, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 68521, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 68520, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 68685, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 68587, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
{.bitmap_index = 68752, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 68647, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
{.bitmap_index = 68820, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 68734, .adv_w = 400, .box_w = 26, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
{.bitmap_index = 68887, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 68868, .adv_w = 280, .box_w = 16, .box_h = 21, .ofs_x = 1, .ofs_y = -3},
|
{.bitmap_index = 68954, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||||
{.bitmap_index = 69015, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 69014, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||||
{.bitmap_index = 69102, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
{.bitmap_index = 69101, .adv_w = 400, .box_w = 26, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||||
{.bitmap_index = 69242, .adv_w = 400, .box_w = 25, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 69235, .adv_w = 280, .box_w = 16, .box_h = 21, .ofs_x = 1, .ofs_y = -3},
|
||||||
{.bitmap_index = 69362, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
{.bitmap_index = 69382, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
{.bitmap_index = 69421, .adv_w = 322, .box_w = 21, .box_h = 13, .ofs_x = 0, .ofs_y = 1}
|
{.bitmap_index = 69469, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
|
{.bitmap_index = 69598, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||||
|
{.bitmap_index = 69738, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
|
{.bitmap_index = 69851, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
|
{.bitmap_index = 70055, .adv_w = 400, .box_w = 25, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||||
|
{.bitmap_index = 70175, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||||
|
{.bitmap_index = 70234, .adv_w = 322, .box_w = 21, .box_h = 13, .ofs_x = 0, .ofs_y = 1}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------
|
/*---------------------
|
||||||
@@ -12477,14 +12600,14 @@ static const uint16_t unicode_list_10[] = {
|
|||||||
|
|
||||||
static const uint16_t unicode_list_12[] = {
|
static const uint16_t unicode_list_12[] = {
|
||||||
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
||||||
0xcefb, 0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11,
|
0xcefb, 0xcefd, 0xceff, 0xcf01, 0xcf03, 0xcf06, 0xcf0b, 0xcf0e,
|
||||||
0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b,
|
0xcf10, 0xcf11, 0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36,
|
||||||
0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b,
|
0xcf37, 0xcf3b, 0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58,
|
||||||
0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96,
|
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d,
|
||||||
0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4,
|
0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca,
|
||||||
0xcfdd, 0xd006, 0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c,
|
0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045, 0xd0d5,
|
||||||
0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444,
|
0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d,
|
||||||
0xd6ac, 0xd78c
|
0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac, 0xd78c
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Collect the unicode lists and glyph_id offsets*/
|
/*Collect the unicode lists and glyph_id offsets*/
|
||||||
@@ -12540,7 +12663,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
||||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 66, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12687,7 +12810,8 @@ static const uint8_t kern_left_class_mapping[] =
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Map glyph_ids to kern right classes*/
|
/*Map glyph_ids to kern right classes*/
|
||||||
@@ -12828,7 +12952,8 @@ static const uint8_t kern_right_class_mapping[] =
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Kern values between classes*/
|
/*Kern values between classes*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Size: 40 px
|
* Size: 40 px
|
||||||
* Bpp: 4
|
* Bpp: 4
|
||||||
* Opts: --bpp 4 --size 40 --no-compress --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-SemiBold.ttf -r 0x20,0x2D,0x30-0x3A --format lvgl --lv-include lvgl.h --lv-font-name ui_font_40 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_40.c
|
* Opts: --bpp 4 --size 40 --no-compress --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-SemiBold.ttf -r 0x20,0x2D-0x2E,0x30-0x3A --format lvgl --lv-include lvgl.h --lv-font-name ui_font_40 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_40.c
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
@@ -30,6 +30,12 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
|||||||
0x8b, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xbf, 0xff,
|
0x8b, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xbf, 0xff,
|
||||||
0xff, 0xff, 0xff, 0x80,
|
0xff, 0xff, 0xff, 0x80,
|
||||||
|
|
||||||
|
/* U+002E "." */
|
||||||
|
0x0, 0x2, 0x0, 0x0, 0x8f, 0xff, 0x80, 0x5f,
|
||||||
|
0xff, 0xff, 0x58, 0xff, 0xff, 0xf8, 0x7f, 0xff,
|
||||||
|
0xff, 0x83, 0xff, 0xff, 0xf3, 0x5, 0xdf, 0xd5,
|
||||||
|
0x0,
|
||||||
|
|
||||||
/* U+0030 "0" */
|
/* U+0030 "0" */
|
||||||
0x0, 0x0, 0x0, 0x4a, 0xdf, 0xfe, 0xc8, 0x20,
|
0x0, 0x0, 0x0, 0x4a, 0xdf, 0xfe, 0xc8, 0x20,
|
||||||
0x0, 0x0, 0x0, 0x0, 0x2, 0xdf, 0xff, 0xff,
|
0x0, 0x0, 0x0, 0x0, 0x2, 0xdf, 0xff, 0xff,
|
||||||
@@ -431,17 +437,18 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||||||
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
|
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
|
||||||
{.bitmap_index = 0, .adv_w = 166, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 0, .adv_w = 166, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 0, .adv_w = 205, .box_w = 11, .box_h = 5, .ofs_x = 1, .ofs_y = 9},
|
{.bitmap_index = 0, .adv_w = 205, .box_w = 11, .box_h = 5, .ofs_x = 1, .ofs_y = 9},
|
||||||
{.bitmap_index = 28, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 28, .adv_w = 177, .box_w = 7, .box_h = 7, .ofs_x = 2, .ofs_y = 0},
|
||||||
{.bitmap_index = 322, .adv_w = 366, .box_w = 14, .box_h = 28, .ofs_x = 2, .ofs_y = 0},
|
{.bitmap_index = 53, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
||||||
{.bitmap_index = 518, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 347, .adv_w = 366, .box_w = 14, .box_h = 28, .ofs_x = 2, .ofs_y = 0},
|
||||||
{.bitmap_index = 812, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 543, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
||||||
{.bitmap_index = 1106, .adv_w = 366, .box_w = 23, .box_h = 28, .ofs_x = 0, .ofs_y = 0},
|
{.bitmap_index = 837, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
||||||
{.bitmap_index = 1428, .adv_w = 366, .box_w = 19, .box_h = 28, .ofs_x = 2, .ofs_y = 0},
|
{.bitmap_index = 1131, .adv_w = 366, .box_w = 23, .box_h = 28, .ofs_x = 0, .ofs_y = 0},
|
||||||
{.bitmap_index = 1694, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 1453, .adv_w = 366, .box_w = 19, .box_h = 28, .ofs_x = 2, .ofs_y = 0},
|
||||||
{.bitmap_index = 1988, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 1719, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
||||||
{.bitmap_index = 2282, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 2013, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
||||||
{.bitmap_index = 2576, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
{.bitmap_index = 2307, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
||||||
{.bitmap_index = 2870, .adv_w = 177, .box_w = 7, .box_h = 22, .ofs_x = 2, .ofs_y = 0}
|
{.bitmap_index = 2601, .adv_w = 366, .box_w = 21, .box_h = 28, .ofs_x = 1, .ofs_y = 0},
|
||||||
|
{.bitmap_index = 2895, .adv_w = 177, .box_w = 7, .box_h = 22, .ofs_x = 2, .ofs_y = 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------
|
/*---------------------
|
||||||
@@ -449,18 +456,18 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
|||||||
*--------------------*/
|
*--------------------*/
|
||||||
|
|
||||||
static const uint16_t unicode_list_0[] = {
|
static const uint16_t unicode_list_0[] = {
|
||||||
0x0, 0xd
|
0x0, 0xd, 0xe
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Collect the unicode lists and glyph_id offsets*/
|
/*Collect the unicode lists and glyph_id offsets*/
|
||||||
static const lv_font_fmt_txt_cmap_t cmaps[] =
|
static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
.range_start = 32, .range_length = 14, .glyph_id_start = 1,
|
.range_start = 32, .range_length = 15, .glyph_id_start = 1,
|
||||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 2, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 3, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.range_start = 48, .range_length = 11, .glyph_id_start = 3,
|
.range_start = 48, .range_length = 11, .glyph_id_start = 4,
|
||||||
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
|
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
// Decoded map tiles (RGB565, 128 KB each) kept for reuse while panning / zooming
|
// Decoded map tiles (RGB565, 128 KB each) kept for reuse while panning / zooming
|
||||||
// back, least-recently-used evicted. Buffers live in PSRAM on the ESP32 and are
|
// back, least-recently-used evicted. Buffers live in PSRAM on the ESP32 and are
|
||||||
// allocated on first use, then kept for the session.
|
// allocated on first use, then kept for the session. Tiles found missing are
|
||||||
|
// remembered separately (no buffer), so looking up coarser zoom levels for the
|
||||||
|
// overzoom fallback doesn't push real tiles out.
|
||||||
//
|
//
|
||||||
// Single-TU fragment: included by ui-lvgl/UITask.cpp only.
|
// Single-TU fragment: included by ui-lvgl/UITask.cpp only.
|
||||||
|
|
||||||
@@ -15,7 +17,7 @@ namespace mapview {
|
|||||||
|
|
||||||
class TileCache {
|
class TileCache {
|
||||||
public:
|
public:
|
||||||
static const int SLOTS = 12; // 6 on screen at 320x218 + a ring of neighbours
|
static const int SLOTS = 24; // 6 on screen at 320x218 + the 14-tile read-ahead ring + a few coarser (3 MB)
|
||||||
|
|
||||||
struct Slot {
|
struct Slot {
|
||||||
int16_t z = -1;
|
int16_t z = -1;
|
||||||
@@ -26,10 +28,13 @@ public:
|
|||||||
lv_image_dsc_t dsc;
|
lv_image_dsc_t dsc;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The slot holding z/x/y if it was loaded (present or known missing), else nullptr.
|
// The slot holding z/x/y if it was loaded (present, or known missing: a
|
||||||
|
// shared slot with present == false), else nullptr.
|
||||||
Slot* find(int z, int x, int y) {
|
Slot* find(int z, int x, int y) {
|
||||||
for (Slot& s : _slots)
|
for (Slot& s : _slots)
|
||||||
if (s.z == z && s.x == x && s.y == y) { s.used = ++_tick; return &s; }
|
if (s.z == z && s.x == x && s.y == y) { s.used = ++_tick; return &s; }
|
||||||
|
for (const Missing& m : _missing)
|
||||||
|
if (m.z == z && m.x == x && m.y == y) return &_miss_slot;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +54,12 @@ public:
|
|||||||
s->z = z; s->x = x; s->y = y;
|
s->z = z; s->x = x; s->y = y;
|
||||||
s->used = ++_tick;
|
s->used = ++_tick;
|
||||||
s->present = src.renderTile(z, x, y, s->px);
|
s->present = src.renderTile(z, x, y, s->px);
|
||||||
|
if (!s->present) { // remember the miss without holding a buffer slot
|
||||||
|
Missing& m = _missing[_miss_next++ % MISSING];
|
||||||
|
m.z = (int16_t)z; m.x = x; m.y = y;
|
||||||
|
s->z = -1; s->used = 0;
|
||||||
|
return &_miss_slot;
|
||||||
|
}
|
||||||
memset(&s->dsc, 0, sizeof(s->dsc));
|
memset(&s->dsc, 0, sizeof(s->dsc));
|
||||||
s->dsc.header.magic = LV_IMAGE_HEADER_MAGIC;
|
s->dsc.header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||||
s->dsc.header.cf = LV_COLOR_FORMAT_RGB565;
|
s->dsc.header.cf = LV_COLOR_FORMAT_RGB565;
|
||||||
@@ -61,13 +72,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Forget the "no tile here" answers (new tiles may have been written).
|
// Forget the "no tile here" answers (new tiles may have been written).
|
||||||
void forgetMissing() { for (Slot& s : _slots) if (s.z >= 0 && !s.present) { s.z = -1; s.used = 0; } }
|
void forgetMissing() { for (Missing& m : _missing) m.z = -1; }
|
||||||
|
|
||||||
// Forget everything (e.g. the card was swapped); keeps the buffers.
|
// Forget everything (e.g. the card was swapped); keeps the buffers.
|
||||||
void invalidate() { for (Slot& s : _slots) { s.z = -1; s.used = 0; } }
|
void invalidate() { for (Slot& s : _slots) { s.z = -1; s.used = 0; } forgetMissing(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Missing { int16_t z = -1; int32_t x = 0, y = 0; };
|
||||||
|
static const int MISSING = 48;
|
||||||
Slot _slots[SLOTS];
|
Slot _slots[SLOTS];
|
||||||
|
Missing _missing[MISSING];
|
||||||
|
int _miss_next = 0;
|
||||||
|
Slot _miss_slot; // present == false
|
||||||
uint32_t _tick = 0;
|
uint32_t _tick = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
// alternative is tools/maps/fetch_tiles.py). Tiles already on the card are
|
// alternative is tools/maps/fetch_tiles.py). Tiles already on the card are
|
||||||
// skipped, so a download can be repeated to fill gaps or extend an area.
|
// skipped, so a download can be repeated to fill gaps or extend an area.
|
||||||
//
|
//
|
||||||
|
// The job (area + zoom range) is kept in <root>/.job until it completes, so a
|
||||||
|
// download cut short by a power-off, a lost network or Stop can be resumed:
|
||||||
|
// resuming re-runs the same job, and the tiles already written are skipped.
|
||||||
|
//
|
||||||
// Driven by loop() from the UI loop: one small step per call, the HTTP GET
|
// Driven by loop() from the UI loop: one small step per call, the HTTP GET
|
||||||
// itself runs asynchronously in the board's fetcher (lvport::fetch*), so the
|
// itself runs asynchronously in the board's fetcher (lvport::fetch*), so the
|
||||||
// mesh keeps being serviced during a long download.
|
// mesh keeps being serviced during a long download.
|
||||||
@@ -78,6 +82,20 @@ public:
|
|||||||
const char* message() const { return _msg; }
|
const char* message() const { return _msg; }
|
||||||
const char* sourceHost() { loadSource(); return _host; }
|
const char* sourceHost() { loadSource(); return _host; }
|
||||||
|
|
||||||
|
// Unfinished job from <root>/.job (read once, then tracked in memory).
|
||||||
|
bool savedJob(TileArea& a) {
|
||||||
|
if (!_job_checked) { _job_checked = true; _has_job = readJob(_job); }
|
||||||
|
if (_has_job) a = _job;
|
||||||
|
return _has_job;
|
||||||
|
}
|
||||||
|
void discardJob() {
|
||||||
|
char path[64];
|
||||||
|
jobPath(path, sizeof(path));
|
||||||
|
remove(path);
|
||||||
|
_has_job = false;
|
||||||
|
_job_checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool start(const TileArea& a, const char* ssid, const char* pass) {
|
bool start(const TileArea& a, const char* ssid, const char* pass) {
|
||||||
if (active()) return false;
|
if (active()) return false;
|
||||||
_area = a;
|
_area = a;
|
||||||
@@ -88,6 +106,7 @@ public:
|
|||||||
if (_total == 0 || _total > MAX_TILES) { fail("Area too large: use the PC tool"); return false; }
|
if (_total == 0 || _total > MAX_TILES) { fail("Area too large: use the PC tool"); return false; }
|
||||||
loadSource();
|
loadSource();
|
||||||
writeAttribution();
|
writeAttribution();
|
||||||
|
writeJob(a);
|
||||||
_z = a.zmin;
|
_z = a.zmin;
|
||||||
tileRange(a, _z, _x0, _y0, _x1, _y1);
|
tileRange(a, _z, _x0, _y0, _x1, _y1);
|
||||||
_x = _x0; _y = _y0;
|
_x = _x0; _y = _y0;
|
||||||
@@ -174,6 +193,8 @@ private:
|
|||||||
char _attr[96] = "";
|
char _attr[96] = "";
|
||||||
char _host[48] = "";
|
char _host[48] = "";
|
||||||
char _msg[64] = "";
|
char _msg[64] = "";
|
||||||
|
TileArea _job = {0, 0, 0, 0, 0, 0};
|
||||||
|
bool _has_job = false, _job_checked = false;
|
||||||
|
|
||||||
void fail(const char* m) { snprintf(_msg, sizeof(_msg), "%s", m); _state = FAILED; }
|
void fail(const char* m) { snprintf(_msg, sizeof(_msg), "%s", m); _state = FAILED; }
|
||||||
|
|
||||||
@@ -181,6 +202,35 @@ private:
|
|||||||
snprintf(_msg, sizeof(_msg), "%s", m);
|
snprintf(_msg, sizeof(_msg), "%s", m);
|
||||||
_state = s;
|
_state = s;
|
||||||
lvport::netEnd();
|
lvport::netEnd();
|
||||||
|
if (s == DONE) discardJob(); // anything else stays resumable
|
||||||
|
}
|
||||||
|
|
||||||
|
void jobPath(char* out, size_t n) const { snprintf(out, n, "%s/.job", _root); }
|
||||||
|
|
||||||
|
void writeJob(const TileArea& a) {
|
||||||
|
char path[64];
|
||||||
|
jobPath(path, sizeof(path));
|
||||||
|
makeParents(path);
|
||||||
|
if (FILE* f = fopen(path, "w")) {
|
||||||
|
fprintf(f, "%.6f %.6f %.6f %.6f %d %d\n", a.lon0, a.lat0, a.lon1, a.lat1, a.zmin, a.zmax);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
_job = a;
|
||||||
|
_has_job = true;
|
||||||
|
_job_checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readJob(TileArea& a) const {
|
||||||
|
char path[64];
|
||||||
|
jobPath(path, sizeof(path));
|
||||||
|
FILE* f = fopen(path, "r");
|
||||||
|
if (!f) return false;
|
||||||
|
TileArea t;
|
||||||
|
int n = fscanf(f, "%lf %lf %lf %lf %d %d", &t.lon0, &t.lat0, &t.lon1, &t.lat1, &t.zmin, &t.zmax);
|
||||||
|
fclose(f);
|
||||||
|
if (n != 6 || t.zmin < 0 || t.zmax > 20 || t.zmin > t.zmax) return false;
|
||||||
|
a = t;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onFailure(const char* m) {
|
void onFailure(const char* m) {
|
||||||
|
|||||||
@@ -162,6 +162,12 @@ class WioTrackerL2Display : public LGFXDisplay {
|
|||||||
public:
|
public:
|
||||||
WioTrackerL2Display() : LGFXDisplay(320, 240, disp) {}
|
WioTrackerL2Display() : LGFXDisplay(320, 240, disp) {}
|
||||||
|
|
||||||
|
// NodePrefs::display_brightness level 0-4 -> backlight PWM
|
||||||
|
void setBrightness(uint8_t level) override {
|
||||||
|
static const uint8_t PWM[5] = { 20, 60, 120, 190, 255 };
|
||||||
|
display->setBrightness(PWM[level > 4 ? 4 : level]);
|
||||||
|
}
|
||||||
|
|
||||||
// direct access to the LGFX device (LVGL flush/touch glue)
|
// direct access to the LGFX device (LVGL flush/touch glue)
|
||||||
lgfx::LGFX_Device* lgfxDevice() { return &disp; }
|
lgfx::LGFX_Device* lgfxDevice() { return &disp; }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user