mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-10-09 11:16:39 +00:00
feat(ui-lvgl): Nearby screen, node detail, scan popup; NearbyModel in the Core
ui-core/NearbyModel.h builds the Nearby list (contacts + live [LOC] shares + heard adverts, or discover-scan results) with type filter and sort, moved verbatim out of ui-new's NearbyScreen, which now inherits it. ui-lvgl: Home is three tiles (Messages, Nearby, Settings). Nearby lists known nodes with filter chips and a Dist/Recent toggle; tapping a row opens node detail (distance/bearing, position, last heard, ID) with Message, Ping, favourite, Add and two-tap Delete. Scan is a popup over the list with its own model: nodes in range now, not the known set. Fonts gain the FontAwesome star for favourites. The LVGL sim page adds an optional repeater so Scan has something to find. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -160,7 +160,7 @@ checked in the sim plus on L1 hardware before the next one.
|
||||
3. **Flip the interface** ✅. `UiCore` is `MyMesh::Listener`; `ui-new`'s `UITask` derives `UITaskBase` + `UiCoreHost` and is fed by events, drained at the start (mesh-originated) and end (engines) of its `loop()`. Mesh callbacks no longer touch the display or buzzer directly.
|
||||
4. **Settings schema.** Convert `SettingsScreen` section by section.
|
||||
5. **`ui-lvgl` skeleton** ✅ on L2 hardware (env `Wio_Tracker_L2_companion_solo_lvgl`, LVGL 9.2.2): status bar, home, conversation list, contact picker, conversation with keyboard, toasts, display sleep/wake. The Core gained the first actions (`sendDirectText`, `sendChannelText`) and runs DM resends itself. Then: European fonts + phone-style keyboard ✅, 320×240 sim target ✅. Next: screens by priority.
|
||||
6. Contacts/Nearby, Admin, Bot logic extraction as the LVGL screens for them are built.
|
||||
6. Contacts/Nearby, Admin, Bot logic extraction as the LVGL screens for them are built. Nearby ✅: `ui-core/NearbyModel.h` builds the list (contacts + live [LOC] shares + heard adverts, or scan results), filter and sort; `ui-new`'s `NearbyScreen` inherits it (entry array stays with the screen), `ui-lvgl` owns one for its Nearby list + node detail (Message, Ping, favourite, Add, Delete). Home became three tiles: Messages, Nearby, Settings.
|
||||
|
||||
## Decisions
|
||||
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
#pragma once
|
||||
// Nearby-nodes list model, shared by every frontend's Nearby screen: builds one
|
||||
// list of entries from two sources and applies the type filter and sort.
|
||||
// SRC_STORED -- contacts, with live [LOC] shares overlaid (fresher position,
|
||||
// plus senders who aren't contacts) and, under the All filter,
|
||||
// passively heard adverts that aren't listed yet
|
||||
// SRC_SCAN -- NODE_DISCOVER_REQ results (RSSI / SNR), strongest first
|
||||
// Selection, scrolling and actions stay in the frontend. Each screen owns its
|
||||
// model (ui-new inherits it, so the entry array lives with the screen as
|
||||
// before) and binds it to the Core for own position and live shares.
|
||||
//
|
||||
// Header-only; include after UiCore.h (needs the_mesh, rtc_clock, geo::).
|
||||
|
||||
#include "../GeoUtils.h"
|
||||
|
||||
class NearbyModel {
|
||||
public:
|
||||
enum Filter : uint8_t { F_ALL, F_FAV, F_COMP, F_RPT, F_ROOM, F_SNSR, F_COUNT };
|
||||
enum Sort : uint8_t { SORT_DIST, SORT_TIME };
|
||||
enum Source : uint8_t { SRC_STORED, SRC_SCAN };
|
||||
|
||||
struct Entry {
|
||||
char name[32];
|
||||
uint8_t type;
|
||||
uint8_t pub_key[PUB_KEY_SIZE];
|
||||
// has_key: the full 32-byte pubkey is present -- what Ping and the base64
|
||||
// key view need. has_prefix: at least the leading FAVOURITE_PREFIX_LEN
|
||||
// bytes are, which is all an identity-keyed reference needs (a Locator
|
||||
// person target). Every has_key row also has_prefix; the reverse doesn't
|
||||
// hold -- a [LOC] share and a heard advert carry a prefix and nothing more.
|
||||
bool has_key;
|
||||
bool has_prefix;
|
||||
// stored-source fields
|
||||
int32_t lat_e6, lon_e6;
|
||||
float dist_km; // -1 = unknown (no own fix or no node position)
|
||||
uint32_t lastmod;
|
||||
int contact_idx; // raw contact-table index, -1 = not a contact
|
||||
// scan-source fields
|
||||
int8_t rssi, snr_x4, remote_snr_x4;
|
||||
bool is_known;
|
||||
// live-track ([LOC] share) overlay: this row's position/age came from a
|
||||
// shared-location message. live_verified: a DM (pubkey) share, not a
|
||||
// channel (name, best-effort) one.
|
||||
bool is_live;
|
||||
bool live_verified;
|
||||
// Favourite (ContactInfo::flags bit 0) -- only a contact carries it.
|
||||
bool fav;
|
||||
};
|
||||
|
||||
static const int MAX_NEARBY = 32;
|
||||
|
||||
static const char* const* filterLabels() {
|
||||
static const char* const L[F_COUNT] = { "All", "Fav", "Comp", "Rpt", "Room", "Snsr" };
|
||||
return L;
|
||||
}
|
||||
static const char* filterLabel(uint8_t f) { return f < F_COUNT ? filterLabels()[f] : ""; }
|
||||
|
||||
static const char* typeName(uint8_t t) {
|
||||
switch (t) {
|
||||
case ADV_TYPE_CHAT: return "Companion";
|
||||
case ADV_TYPE_REPEATER: return "Repeater";
|
||||
case ADV_TYPE_ROOM: return "Room";
|
||||
case ADV_TYPE_SENSOR: return "Sensor";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* typeShort(uint8_t t) {
|
||||
switch (t) {
|
||||
case ADV_TYPE_REPEATER: return "Rpt";
|
||||
case ADV_TYPE_SENSOR: return "Snsr";
|
||||
case ADV_TYPE_ROOM: return "Room";
|
||||
case ADV_TYPE_CHAT: return "Comp";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
void bindModel(UiCore* core, NodePrefs* prefs) { _core = core; _prefs = prefs; }
|
||||
|
||||
int count() const { return _count; }
|
||||
const Entry& at(int i) const { return _entries[i]; }
|
||||
Source source() const { return _source; }
|
||||
uint8_t filter() const { return _filter; }
|
||||
uint8_t sortMode() const { return _sort; }
|
||||
bool ownPosition(int32_t& lat, int32_t& lon) const { lat = _own_lat; lon = _own_lon; return _own_gps; }
|
||||
void setSource(Source s) { _source = s; }
|
||||
void setFilter(uint8_t f) { _filter = f < F_COUNT ? f : F_ALL; }
|
||||
void setSortMode(uint8_t s) { _sort = s; }
|
||||
|
||||
bool typeMatchesFilter(uint8_t type, uint8_t flags, bool have_flags) const {
|
||||
switch (_filter) {
|
||||
case F_FAV: return have_flags && (flags & 0x01);
|
||||
case F_COMP: return type == ADV_TYPE_CHAT;
|
||||
case F_RPT: return type == ADV_TYPE_REPEATER;
|
||||
case F_ROOM: return type == ADV_TYPE_ROOM;
|
||||
case F_SNSR: return type == ADV_TYPE_SENSOR;
|
||||
case F_ALL:
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ── data refresh ──────────────────────────────────────────────────────────
|
||||
void refreshStored() {
|
||||
_count = 0;
|
||||
_own_lat = _own_lon = 0;
|
||||
_own_gps = _core && _core->course.currentLocation(_own_lat, _own_lon);
|
||||
|
||||
int nc = the_mesh.getNumContacts();
|
||||
for (int i = 0; i < nc && _count < MAX_NEARBY; i++) {
|
||||
ContactInfo ci;
|
||||
// getContactByIdx() indexes the RAW contact table, whose first
|
||||
// MAX_ANON_CONTACTS slots are reserved for anon-request bookkeeping
|
||||
// (see BaseChatMesh::resetContacts()/ContactsIterator) -- getNumContacts()
|
||||
// already excludes them from the count, so real contact 0 lives at raw
|
||||
// index MAX_ANON_CONTACTS, not 0. Reading from 0 pulled those reserved
|
||||
// (blank, type=ADV_TYPE_NONE) slots into the list as bogus "Unknown"
|
||||
// rows, and silently dropped the same number of real contacts off the end.
|
||||
if (!the_mesh.getContactByIdx(i + MAX_ANON_CONTACTS, ci)) continue;
|
||||
if (!typeMatchesFilter(ci.type, ci.flags, true)) continue;
|
||||
|
||||
Entry& e = _entries[_count++];
|
||||
strncpy(e.name, ci.name, sizeof(e.name) - 1);
|
||||
e.name[sizeof(e.name) - 1] = '\0';
|
||||
memcpy(e.pub_key, ci.id.pub_key, PUB_KEY_SIZE);
|
||||
e.has_key = true;
|
||||
e.has_prefix = true;
|
||||
e.lat_e6 = ci.gps_lat;
|
||||
e.lon_e6 = ci.gps_lon;
|
||||
bool remote_gps = (ci.gps_lat != 0 || ci.gps_lon != 0);
|
||||
e.dist_km = (_own_gps && remote_gps)
|
||||
? geo::haversineKm(_own_lat, _own_lon, ci.gps_lat, ci.gps_lon)
|
||||
: -1.0f;
|
||||
e.type = ci.type;
|
||||
e.fav = (ci.flags & 0x01) != 0;
|
||||
e.contact_idx = i + MAX_ANON_CONTACTS; // raw index -- other lookups re-key off this directly
|
||||
e.lastmod = ci.lastmod;
|
||||
e.is_known = true;
|
||||
e.is_live = false;
|
||||
e.live_verified = false;
|
||||
}
|
||||
|
||||
mergeLiveTrack();
|
||||
mergeRecentlyHeard();
|
||||
sortStored();
|
||||
}
|
||||
|
||||
void refreshScan() {
|
||||
static DiscoverResult dr[DISCOVER_RESULTS_MAX]; // scratch -- refresh isn't reentrant
|
||||
int n = the_mesh.getDiscoverResults(dr, DISCOVER_RESULTS_MAX);
|
||||
_count = 0;
|
||||
for (int i = 0; i < n && _count < MAX_NEARBY; i++) {
|
||||
if (!typeMatchesFilter(dr[i].type, 0, false)) continue;
|
||||
Entry& e = _entries[_count++];
|
||||
strncpy(e.name, dr[i].name, sizeof(e.name) - 1);
|
||||
e.name[sizeof(e.name) - 1] = '\0';
|
||||
e.type = dr[i].type;
|
||||
memcpy(e.pub_key, dr[i].pub_key, PUB_KEY_SIZE);
|
||||
e.has_key = true;
|
||||
e.has_prefix = true;
|
||||
e.rssi = dr[i].rssi;
|
||||
e.snr_x4 = dr[i].snr_x4;
|
||||
e.remote_snr_x4 = dr[i].remote_snr_x4;
|
||||
e.is_known = dr[i].is_known;
|
||||
e.fav = false;
|
||||
e.lat_e6 = e.lon_e6 = 0;
|
||||
e.dist_km = -1.0f;
|
||||
e.lastmod = 0;
|
||||
e.contact_idx = -1;
|
||||
e.is_live = false;
|
||||
e.live_verified = false;
|
||||
}
|
||||
// strongest first
|
||||
for (int i = 0; i < _count - 1; i++) {
|
||||
int best = i;
|
||||
for (int j = i + 1; j < _count; j++)
|
||||
if (_entries[j].rssi > _entries[best].rssi) best = j;
|
||||
if (best != i) { Entry tmp = _entries[i]; _entries[i] = _entries[best]; _entries[best] = tmp; }
|
||||
}
|
||||
}
|
||||
|
||||
void refreshModel() { if (_source == SRC_SCAN) refreshScan(); else refreshStored(); }
|
||||
|
||||
// Index of the row for raw contact index `contact_idx`, or of the non-contact
|
||||
// live row named `name` -- how a screen keeps its selection across a rebuild.
|
||||
int findContact(int contact_idx) const {
|
||||
for (int i = 0; i < _count; i++) if (_entries[i].contact_idx == contact_idx) return i;
|
||||
return -1;
|
||||
}
|
||||
int findLiveByName(const char* name) const {
|
||||
for (int i = 0; i < _count; i++)
|
||||
if (_entries[i].is_live && strncmp(_entries[i].name, name, sizeof(_entries[i].name) - 1) == 0) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected:
|
||||
UiCore* _core = nullptr;
|
||||
NodePrefs* _prefs = nullptr;
|
||||
|
||||
Entry _entries[MAX_NEARBY];
|
||||
int _count = 0;
|
||||
int32_t _own_lat = 0, _own_lon = 0;
|
||||
bool _own_gps = false;
|
||||
|
||||
Source _source = SRC_STORED;
|
||||
uint8_t _filter = F_ALL;
|
||||
uint8_t _sort = SORT_DIST;
|
||||
|
||||
// Overlay live [LOC] shares onto the stored list: refresh a matching contact
|
||||
// with the fresher shared position, and append senders who aren't contacts so
|
||||
// a group sharing on a channel still shows up. DM shares match by pubkey
|
||||
// prefix (verified); channel shares match by name (best-effort).
|
||||
void mergeLiveTrack() {
|
||||
if (!_core) return;
|
||||
LiveTrackStore& lt = _core->live_share.track();
|
||||
uint32_t now = rtc_clock.getCurrentTime();
|
||||
for (int i = 0; i < LiveTrackStore::CAPACITY; i++) {
|
||||
if (!lt.isActive(i, now)) continue;
|
||||
const LiveTrackStore::Entry& s = lt.slotAt(i);
|
||||
|
||||
int m = -1;
|
||||
for (int j = 0; j < _count; j++) {
|
||||
if (s.verified && _entries[j].has_key
|
||||
&& memcmp(_entries[j].pub_key, s.key, LiveTrackStore::KEY_LEN) == 0) { m = j; break; }
|
||||
if (!s.verified && strncmp(_entries[j].name, s.name, sizeof(_entries[j].name) - 1) == 0) { m = j; break; }
|
||||
}
|
||||
|
||||
if (m >= 0) {
|
||||
Entry& e = _entries[m];
|
||||
// A [LOC] share is an explicit "here I am now", so it defines the pin and
|
||||
// the distance (used for proximity sorting). Recency for the time sort is
|
||||
// the most recent of the advert and the share.
|
||||
e.lat_e6 = s.lat_1e6;
|
||||
e.lon_e6 = s.lon_1e6;
|
||||
e.dist_km = _own_gps ? geo::haversineKm(_own_lat, _own_lon, s.lat_1e6, s.lon_1e6) : -1.0f;
|
||||
if (s.ts > e.lastmod) e.lastmod = s.ts;
|
||||
e.is_live = true;
|
||||
e.live_verified = s.verified;
|
||||
} else if (_count < MAX_NEARBY && typeMatchesFilter(ADV_TYPE_CHAT, 0, false)) {
|
||||
// A sender we don't have as a contact: treat it as a companion (the only
|
||||
// node type that shares position), so the type filter still applies.
|
||||
Entry& e = _entries[_count++];
|
||||
memset(&e, 0, sizeof(e));
|
||||
strncpy(e.name, s.name, sizeof(e.name) - 1);
|
||||
e.name[sizeof(e.name) - 1] = '\0';
|
||||
// Only a key *prefix* is kept for shares, so Ping and the key view stay
|
||||
// unavailable for a non-contact live entry; Navigate / waypoint work off
|
||||
// lat/lon. A DM share's prefix is real (a Locator person target); a
|
||||
// channel share is matched by name and carries no identity at all.
|
||||
e.has_key = false;
|
||||
e.has_prefix = s.verified;
|
||||
if (s.verified) memcpy(e.pub_key, s.key, LiveTrackStore::KEY_LEN);
|
||||
e.type = ADV_TYPE_CHAT;
|
||||
e.lat_e6 = s.lat_1e6;
|
||||
e.lon_e6 = s.lon_1e6;
|
||||
e.dist_km = _own_gps ? geo::haversineKm(_own_lat, _own_lon, s.lat_1e6, s.lon_1e6) : -1.0f;
|
||||
e.lastmod = s.ts;
|
||||
e.contact_idx = -1;
|
||||
e.is_known = false;
|
||||
e.is_live = true;
|
||||
e.live_verified = s.verified;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fold passively-heard adverts that aren't already listed (contact or live) into
|
||||
// the list as name+age rows -- no full key/GPS, so informational only. Gated to
|
||||
// the All filter because AdvertPath carries no node type to filter or sort on.
|
||||
void mergeRecentlyHeard() {
|
||||
if (_filter != F_ALL) return;
|
||||
static AdvertPath heard[8]; // scratch -- refreshStored isn't reentrant
|
||||
int n = the_mesh.getRecentlyHeard(heard, 8);
|
||||
for (int i = 0; i < n && _count < MAX_NEARBY; i++) {
|
||||
AdvertPath& a = heard[i];
|
||||
if (a.name[0] == 0) continue;
|
||||
bool dup = false;
|
||||
for (int j = 0; j < _count; j++) {
|
||||
if (_entries[j].has_key &&
|
||||
memcmp(_entries[j].pub_key, a.pubkey_prefix, sizeof(a.pubkey_prefix)) == 0) { dup = true; break; }
|
||||
if (strncmp(_entries[j].name, a.name, sizeof(a.name) - 1) == 0) { dup = true; break; }
|
||||
}
|
||||
if (dup) continue;
|
||||
Entry& e = _entries[_count++];
|
||||
memset(&e, 0, sizeof(e));
|
||||
strncpy(e.name, a.name, sizeof(e.name) - 1);
|
||||
e.name[sizeof(e.name) - 1] = '\0';
|
||||
e.type = ADV_TYPE_CHAT; // unknown from AdvertPath -- best-effort label
|
||||
e.has_key = false;
|
||||
e.has_prefix = true;
|
||||
memcpy(e.pub_key, a.pubkey_prefix, sizeof(a.pubkey_prefix));
|
||||
e.dist_km = -1.0f;
|
||||
e.lastmod = a.recv_timestamp;
|
||||
e.contact_idx = -1;
|
||||
e.is_known = false;
|
||||
e.is_live = false;
|
||||
}
|
||||
}
|
||||
|
||||
void sortStored() {
|
||||
uint32_t now_ts = rtc_clock.getCurrentTime();
|
||||
const bool fav_first = !(_prefs && _prefs->fav_sort_off);
|
||||
for (int i = 0; i < _count - 1; i++) {
|
||||
int best = i;
|
||||
for (int j = i + 1; j < _count; j++) {
|
||||
if (fav_first && _entries[j].fav != _entries[best].fav) {
|
||||
if (_entries[j].fav) best = j; // favourites outrank the time/distance key
|
||||
continue;
|
||||
}
|
||||
if (_sort == SORT_TIME) {
|
||||
// lastmod=0 or lastmod>now (RTC not synced) → "unknown" → sort to bottom.
|
||||
uint32_t tj = (_entries[j].lastmod > 0 && now_ts >= _entries[j].lastmod) ? _entries[j].lastmod : 0;
|
||||
uint32_t tb = (_entries[best].lastmod > 0 && now_ts >= _entries[best].lastmod) ? _entries[best].lastmod : 0;
|
||||
if (tj > 0 && (tb == 0 || tj > tb)) best = j; // descending — most recent first
|
||||
} else {
|
||||
float dj = _entries[j].dist_km, db = _entries[best].dist_km;
|
||||
if (dj >= 0.0f && (db < 0.0f || dj < db)) best = j; // ascending — closest first
|
||||
}
|
||||
}
|
||||
if (best != i) { Entry tmp = _entries[i]; _entries[i] = _entries[best]; _entries[best] = tmp; }
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -28,4 +28,7 @@ namespace theme {
|
||||
#define THEME_FONT_TITLE (&ui_font_16)
|
||||
#define THEME_FONT_LARGE (&ui_font_20)
|
||||
#define THEME_FONT_CLOCK (&ui_font_40)
|
||||
|
||||
// Extra FontAwesome glyphs baked into ui_font_12..20 beyond LVGL's LV_SYMBOL_*.
|
||||
#define UI_SYMBOL_STAR "\xEF\x80\x85" // U+F005, favourite
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#endif
|
||||
|
||||
#include "../ui-core/UiCore.h" // shared UI Core (header-only, this TU)
|
||||
#include "../ui-core/NearbyModel.h"
|
||||
#include "Theme.h"
|
||||
#include "LvglPort.h"
|
||||
#include "../ui-core/KeyboardData.h"
|
||||
@@ -87,6 +88,11 @@ void UITask::begin(DisplayDriver* display_drv, SensorManager* sensors, NodePrefs
|
||||
|
||||
_core = new UiCore();
|
||||
_core->begin(node_prefs, sensors, this);
|
||||
_nearby = new NearbyModel();
|
||||
_nearby->bindModel(_core, node_prefs);
|
||||
_scan = new NearbyModel();
|
||||
_scan->bindModel(_core, node_prefs);
|
||||
_scan->setSource(NearbyModel::SRC_SCAN);
|
||||
|
||||
#ifdef PIN_USER_BTN
|
||||
user_btn.begin();
|
||||
@@ -141,6 +147,17 @@ void UITask::loop() {
|
||||
refreshStatusBar();
|
||||
if (_screen == SCR_HOME) refreshHome();
|
||||
}
|
||||
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.
|
||||
_next_nearby_ms = millis() + (_scanning ? 250 : 2000);
|
||||
if (_scanning && (int32_t)(millis() - _scan_until_ms) >= 0) _scanning = false;
|
||||
if (_screen == SCR_NEARBY) {
|
||||
refreshNearbyList();
|
||||
if (_scan_overlay) refreshScanPopup();
|
||||
} else {
|
||||
refreshNode();
|
||||
}
|
||||
}
|
||||
if (_screen == SCR_THREAD && (int32_t)(millis() - _next_thread_check_ms) >= 0) {
|
||||
_next_thread_check_ms = millis() + 500;
|
||||
uint32_t sig = threadSignature();
|
||||
@@ -323,6 +340,9 @@ lv_obj_t* UITask::newScreen(const char* title, bool with_back) {
|
||||
_home_clock = _home_date = _home_unread = nullptr;
|
||||
_thread_list = _compose_ta = _keyboard = nullptr;
|
||||
_header = _body = nullptr;
|
||||
_nearby_list = _nearby_status = _nearby_sort_lbl = _nearby_chips = nullptr;
|
||||
_node_info = _node_ping = _node_delete_lbl = nullptr;
|
||||
_scan_overlay = _scan_list = _scan_status = nullptr; // the popup went with the old screen
|
||||
lv_obj_t* prev = lv_screen_active();
|
||||
lv_obj_t* scr = lv_obj_create(NULL);
|
||||
styleSurface(scr, theme::BG);
|
||||
@@ -371,6 +391,15 @@ void UITask::back() {
|
||||
case SCR_CONTACTS: showChats(); break;
|
||||
case SCR_SETTINGS: showHome(); break;
|
||||
case SCR_CHATS: showHome(); break;
|
||||
case SCR_NEARBY:
|
||||
if (_scan_overlay) closeScanPopup();
|
||||
else showHome();
|
||||
break;
|
||||
case SCR_NODE: // back to where the node was picked: the list, or the scan popup over it
|
||||
_screen = SCR_NEARBY;
|
||||
buildNearby();
|
||||
if (_node_from_scan) showScanPopup();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -380,19 +409,26 @@ void UITask::back() {
|
||||
static void onOpenChats(lv_event_t* e) { (void)e; s_ui->showChats(); }
|
||||
static void onOpenSettings(lv_event_t* e) { (void)e; s_ui->showSettings(); }
|
||||
|
||||
// Wide home tile: icon + label left, optional value label right.
|
||||
static lv_obj_t* homeTile(lv_obj_t* parent, const char* text, lv_event_cb_t cb, lv_obj_t** value_out) {
|
||||
static void onOpenNearby(lv_event_t* e) { (void)e; s_ui->showNearby(); }
|
||||
|
||||
// Home tile: icon over label, one of a row of three; optional amber value
|
||||
// (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,
|
||||
lv_obj_t** value_out) {
|
||||
lv_obj_t* tile = lv_button_create(parent);
|
||||
lv_obj_set_size(tile, LV_PCT(100), 42);
|
||||
lv_obj_set_height(tile, 64);
|
||||
lv_obj_set_flex_grow(tile, 1);
|
||||
lv_obj_set_style_bg_color(tile, lv_color_hex(theme::SURFACE), 0);
|
||||
lv_obj_set_style_bg_color(tile, lv_color_hex(theme::SURFACE_2), LV_STATE_PRESSED);
|
||||
lv_obj_set_style_radius(tile, theme::RADIUS, 0);
|
||||
lv_obj_set_style_shadow_width(tile, 0, 0);
|
||||
lv_obj_set_style_pad_all(tile, 4, 0);
|
||||
lv_obj_add_event_cb(tile, cb, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_t* tl = label(tile, text, THEME_FONT_TITLE, theme::TEXT);
|
||||
lv_obj_align(tl, LV_ALIGN_LEFT_MID, theme::PAD, 0);
|
||||
lv_obj_align(label(tile, icon, THEME_FONT_LARGE, theme::TEXT), LV_ALIGN_TOP_MID, 0, 6);
|
||||
lv_obj_align(label(tile, text, THEME_FONT_SMALL, theme::TEXT_MUTED), LV_ALIGN_BOTTOM_MID, 0, -4);
|
||||
if (value_out) {
|
||||
*value_out = label(tile, "", THEME_FONT_TITLE, theme::ACCENT);
|
||||
lv_obj_align(*value_out, LV_ALIGN_RIGHT_MID, -theme::PAD, 0);
|
||||
*value_out = label(tile, "", THEME_FONT_SMALL, theme::ACCENT);
|
||||
lv_obj_align(*value_out, LV_ALIGN_TOP_RIGHT, -2, 0);
|
||||
}
|
||||
return tile;
|
||||
}
|
||||
@@ -412,8 +448,15 @@ void UITask::buildHome() {
|
||||
lv_obj_t* name = label(body, the_mesh.getNodeName(), THEME_FONT_BODY, theme::ACCENT);
|
||||
lv_obj_set_style_pad_bottom(name, 4, 0);
|
||||
|
||||
homeTile(body, LV_SYMBOL_ENVELOPE " Messages", onOpenChats, &_home_unread);
|
||||
homeTile(body, LV_SYMBOL_SETTINGS " Settings", onOpenSettings, NULL);
|
||||
lv_obj_t* tiles = lv_obj_create(body);
|
||||
styleSurface(tiles, theme::BG);
|
||||
lv_obj_remove_flag(tiles, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_size(tiles, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_flex_flow(tiles, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_column(tiles, theme::GAP, 0);
|
||||
homeTile(tiles, LV_SYMBOL_ENVELOPE, "Messages", onOpenChats, &_home_unread);
|
||||
homeTile(tiles, LV_SYMBOL_GPS, "Nearby", onOpenNearby, NULL);
|
||||
homeTile(tiles, LV_SYMBOL_SETTINGS, "Settings", onOpenSettings, NULL);
|
||||
}
|
||||
|
||||
void UITask::refreshHome() {
|
||||
@@ -433,7 +476,7 @@ void UITask::refreshHome() {
|
||||
lv_label_set_text(_home_date, "time not synced");
|
||||
}
|
||||
int unread = _core->dmUnreadTotal() + _core->history.getTotalChannelUnread() + _core->roomUnread();
|
||||
if (unread > 0) lv_label_set_text_fmt(_home_unread, "%d new", unread);
|
||||
if (unread > 0) lv_label_set_text_fmt(_home_unread, "%d", unread);
|
||||
else lv_label_set_text(_home_unread, "");
|
||||
}
|
||||
|
||||
@@ -565,6 +608,442 @@ void UITask::buildContacts() {
|
||||
if (rows == 0) label(body, "No contacts yet", THEME_FONT_BODY, theme::TEXT_MUTED);
|
||||
}
|
||||
|
||||
// ── Nearby ────────────────────────────────────────────────────────────────────
|
||||
// Contacts / live shares / heard adverts from NearbyModel, filtered by type
|
||||
// chips, sorted by distance or recency. Tap a row for detail. Scan (nodes that
|
||||
// answer a discover request right now) is a popup over the list with its own
|
||||
// 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)
|
||||
enum : uint8_t { NODE_MSG, NODE_PING, NODE_FAV, NODE_ADD, NODE_DELETE };
|
||||
|
||||
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 onNearbyScan(lv_event_t* e) { (void)e; s_ui->startNearbyScan(); }
|
||||
static void onNearbyRow(lv_event_t* e) { s_ui->openNode((int)(uintptr_t)lv_event_get_user_data(e)); }
|
||||
static void onScanRow(lv_event_t* e) { s_ui->openScanNode((int)(uintptr_t)lv_event_get_user_data(e)); }
|
||||
static void onScanClose(lv_event_t* e) { (void)e; s_ui->closeScanPopup(); }
|
||||
static void onNodeAction(lv_event_t* e) { s_ui->nodeAction((uint8_t)(uintptr_t)lv_event_get_user_data(e)); }
|
||||
|
||||
static lv_obj_t* headerButton(lv_obj_t* hdr, const char* text, lv_event_cb_t cb, int right, lv_obj_t** label_out) {
|
||||
lv_obj_t* b = lv_button_create(hdr);
|
||||
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_bg_color(b, lv_color_hex(theme::SURFACE), 0);
|
||||
lv_obj_set_style_bg_color(b, lv_color_hex(theme::SURFACE_2), LV_STATE_PRESSED);
|
||||
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||
lv_obj_align(b, LV_ALIGN_RIGHT_MID, -right, 0);
|
||||
lv_obj_add_event_cb(b, cb, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_t* l = label(b, text, THEME_FONT_SMALL, theme::TEXT);
|
||||
lv_obj_center(l);
|
||||
if (label_out) *label_out = l;
|
||||
return b;
|
||||
}
|
||||
|
||||
void UITask::showNearby() {
|
||||
_screen = SCR_NEARBY;
|
||||
_scanning = false;
|
||||
buildNearby(); // filter / sort persist
|
||||
}
|
||||
|
||||
void UITask::buildNearby() {
|
||||
lv_obj_t* body = newScreen("Nearby", true);
|
||||
lv_obj_set_style_pad_row(body, 4, 0);
|
||||
if (_header) {
|
||||
headerButton(_header, LV_SYMBOL_REFRESH " Scan", onNearbyScan, 4, NULL);
|
||||
headerButton(_header, "", onNearbySort, 84, &_nearby_sort_lbl);
|
||||
}
|
||||
|
||||
// Type filter chips
|
||||
_nearby_chips = lv_obj_create(body);
|
||||
styleSurface(_nearby_chips, theme::BG);
|
||||
lv_obj_remove_flag(_nearby_chips, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_size(_nearby_chips, LV_PCT(100), 26);
|
||||
lv_obj_set_flex_flow(_nearby_chips, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_column(_nearby_chips, 4, 0);
|
||||
for (uint8_t f = 0; f < NearbyModel::F_COUNT; f++) {
|
||||
lv_obj_t* c = lv_button_create(_nearby_chips);
|
||||
lv_obj_set_height(c, 26);
|
||||
lv_obj_set_flex_grow(c, 1);
|
||||
lv_obj_set_style_pad_all(c, 0, 0);
|
||||
lv_obj_set_style_radius(c, 13, 0);
|
||||
lv_obj_set_style_shadow_width(c, 0, 0);
|
||||
bool on = f == _nearby->filter();
|
||||
lv_obj_set_style_bg_color(c, lv_color_hex(on ? theme::ACCENT : theme::SURFACE), 0);
|
||||
lv_obj_add_event_cb(c, onNearbyChip, LV_EVENT_CLICKED, (void*)(uintptr_t)f);
|
||||
lv_obj_center(label(c, NearbyModel::filterLabel(f), THEME_FONT_SMALL, on ? theme::BG : theme::TEXT));
|
||||
}
|
||||
|
||||
_nearby_status = label(body, "", THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||
|
||||
_nearby_list = lv_obj_create(body);
|
||||
styleSurface(_nearby_list, theme::BG);
|
||||
lv_obj_set_width(_nearby_list, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(_nearby_list, 1);
|
||||
lv_obj_set_flex_flow(_nearby_list, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_row(_nearby_list, theme::GAP, 0);
|
||||
lv_obj_set_scrollbar_mode(_nearby_list, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
|
||||
_nearby_sig = 0;
|
||||
refreshNearbyList();
|
||||
}
|
||||
|
||||
void UITask::setNearbyFilter(uint8_t f) {
|
||||
_nearby->setFilter(f);
|
||||
buildNearby();
|
||||
}
|
||||
|
||||
void UITask::toggleNearbySort() {
|
||||
_nearby->setSortMode(_nearby->sortMode() == NearbyModel::SORT_DIST ? NearbyModel::SORT_TIME
|
||||
: NearbyModel::SORT_DIST);
|
||||
_nearby_sig = 0;
|
||||
refreshNearbyList();
|
||||
}
|
||||
|
||||
void UITask::startNearbyScan() {
|
||||
_scanning = true;
|
||||
_scan_until_ms = millis() + 8000;
|
||||
_next_nearby_ms = millis() + 250;
|
||||
the_mesh.sendNodeDiscoverReq();
|
||||
if (!_scan_overlay) showScanPopup();
|
||||
else { _scan_sig = 0; refreshScanPopup(); }
|
||||
}
|
||||
|
||||
// Dimmed full-screen overlay (swallows taps) holding a panel with the results.
|
||||
// A child of the current screen, so it goes away with it.
|
||||
void UITask::showScanPopup() {
|
||||
_scan_overlay = lv_obj_create(lv_screen_active());
|
||||
lv_obj_remove_style_all(_scan_overlay);
|
||||
lv_obj_set_size(_scan_overlay, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_bg_color(_scan_overlay, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_bg_opa(_scan_overlay, LV_OPA_60, 0);
|
||||
lv_obj_add_flag(_scan_overlay, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_remove_flag(_scan_overlay, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lv_obj_t* panel = lv_obj_create(_scan_overlay);
|
||||
lv_obj_set_size(panel, lv_display_get_horizontal_resolution(NULL) - 16,
|
||||
lv_display_get_vertical_resolution(NULL) - theme::STATUS_H - 12);
|
||||
lv_obj_set_pos(panel, 8, theme::STATUS_H + 6);
|
||||
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, 4, 0);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lv_obj_t* hdr = lv_obj_create(panel);
|
||||
styleSurface(hdr, theme::BG);
|
||||
lv_obj_remove_flag(hdr, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_size(hdr, LV_PCT(100), 28);
|
||||
lv_obj_align(label(hdr, "In range now", THEME_FONT_TITLE, theme::TEXT), LV_ALIGN_LEFT_MID, 0, 0);
|
||||
headerButton(hdr, LV_SYMBOL_CLOSE, onScanClose, 0, NULL);
|
||||
headerButton(hdr, LV_SYMBOL_REFRESH " Again", onNearbyScan, 44, NULL);
|
||||
|
||||
_scan_status = label(panel, "", THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||
_scan_list = lv_obj_create(panel);
|
||||
styleSurface(_scan_list, theme::BG);
|
||||
lv_obj_set_width(_scan_list, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(_scan_list, 1);
|
||||
lv_obj_set_flex_flow(_scan_list, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_row(_scan_list, theme::GAP, 0);
|
||||
lv_obj_set_scrollbar_mode(_scan_list, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
|
||||
_scan_sig = 0;
|
||||
refreshScanPopup();
|
||||
}
|
||||
|
||||
void UITask::closeScanPopup() {
|
||||
if (_scan_overlay) lv_obj_delete_async(_scan_overlay); // may be closing from its own button
|
||||
_scan_overlay = _scan_list = _scan_status = nullptr;
|
||||
_scanning = false;
|
||||
}
|
||||
|
||||
void UITask::refreshScanPopup() {
|
||||
if (!_scan_list) return;
|
||||
_scan->refreshScan();
|
||||
int n = _scan->count();
|
||||
if (_scanning) lv_label_set_text_fmt(_scan_status, LV_SYMBOL_REFRESH " Listening for replies... %d", n);
|
||||
else lv_label_set_text_fmt(_scan_status, "%d node%s answered the discover request", n, n == 1 ? "" : "s");
|
||||
|
||||
uint32_t sig = (uint32_t)n + (_scanning ? 0x10000u : 0);
|
||||
for (int i = 0; i < n; i++) {
|
||||
const NearbyModel::Entry& e = _scan->at(i);
|
||||
sig = sig * 31 + e.rssi * 7 + e.snr_x4 + e.is_known;
|
||||
for (int k = 0; k < 4; k++) sig = sig * 31 + e.pub_key[k];
|
||||
}
|
||||
if (sig == _scan_sig) return;
|
||||
_scan_sig = sig;
|
||||
|
||||
lv_obj_clean(_scan_list);
|
||||
for (int i = 0; i < n; i++) {
|
||||
const NearbyModel::Entry& e = _scan->at(i);
|
||||
char title[40], sub[48], right[12];
|
||||
if (e.name[0]) snprintf(title, sizeof(title), "%s", e.name);
|
||||
else snprintf(title, sizeof(title), "%s %02X%02X%02X%02X", NearbyModel::typeName(e.type),
|
||||
e.pub_key[0], e.pub_key[1], e.pub_key[2], e.pub_key[3]);
|
||||
snprintf(sub, sizeof(sub), "%s - SNR %.1f / %.1f%s", NearbyModel::typeName(e.type),
|
||||
e.snr_x4 / 4.0f, e.remote_snr_x4 / 4.0f, e.is_known ? "" : " - new");
|
||||
snprintf(right, sizeof(right), "%d dBm", e.rssi);
|
||||
lv_obj_t* row = listRow(_scan_list, title, sub, onScanRow, (void*)(uintptr_t)i);
|
||||
lv_obj_align(label(row, right, THEME_FONT_SMALL, theme::TEXT_MUTED), LV_ALIGN_RIGHT_MID, -theme::PAD, 0);
|
||||
}
|
||||
if (n == 0) {
|
||||
lv_obj_t* l = label(_scan_list, _scanning ? "Repeaters and rooms in range will answer."
|
||||
: "Nobody answered. Try again later or move.",
|
||||
THEME_FONT_BODY, theme::TEXT_MUTED);
|
||||
lv_label_set_long_mode(l, LV_LABEL_LONG_WRAP);
|
||||
lv_obj_set_width(l, LV_PCT(100));
|
||||
lv_obj_set_style_pad_top(l, 8, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::openScanNode(int row) {
|
||||
if (row < 0 || row >= _scan->count()) return;
|
||||
s_node = _scan->at(row);
|
||||
_node_from_scan = true;
|
||||
_scanning = false;
|
||||
_pinging = false;
|
||||
_delete_armed_ms = 0;
|
||||
_screen = SCR_NODE;
|
||||
buildNode();
|
||||
}
|
||||
|
||||
// Changes whenever a rebuild would show something different.
|
||||
uint32_t UITask::nearbySignature() const {
|
||||
uint32_t sig = (uint32_t)_nearby->count() * 2654435761u + _nearby->sortMode() + (_scanning ? 7 : 0);
|
||||
for (int i = 0; i < _nearby->count(); i++) {
|
||||
const NearbyModel::Entry& e = _nearby->at(i);
|
||||
sig = sig * 31 + e.contact_idx + (uint32_t)e.lastmod + (uint32_t)(e.dist_km * 100) + e.rssi + e.fav;
|
||||
for (const char* p = e.name; *p; p++) sig = sig * 31 + (uint8_t)*p;
|
||||
}
|
||||
// Ages are shown in minutes, so let the list re-render once a minute anyway.
|
||||
return sig + rtc_clock.getCurrentTime() / 60;
|
||||
}
|
||||
|
||||
void UITask::refreshNearbyList() {
|
||||
if (!_nearby_list) return;
|
||||
_nearby->refreshModel();
|
||||
uint32_t sig = nearbySignature();
|
||||
int n = _nearby->count();
|
||||
|
||||
if (_nearby_sort_lbl)
|
||||
lv_label_set_text(_nearby_sort_lbl, _nearby->sortMode() == NearbyModel::SORT_TIME ? "Recent" : "Dist");
|
||||
int32_t lat, lon;
|
||||
bool gps = _nearby->ownPosition(lat, lon);
|
||||
lv_label_set_text_fmt(_nearby_status, "%d node%s%s", n, n == 1 ? "" : "s",
|
||||
gps ? "" : " - no GPS fix, distances unknown");
|
||||
if (sig == _nearby_sig) return;
|
||||
_nearby_sig = sig;
|
||||
|
||||
int32_t scroll = lv_obj_get_scroll_y(_nearby_list);
|
||||
lv_obj_clean(_nearby_list);
|
||||
uint32_t now = rtc_clock.getCurrentTime();
|
||||
bool imperial = _prefs && _prefs->units_imperial;
|
||||
for (int i = 0; i < n; i++) {
|
||||
const NearbyModel::Entry& e = _nearby->at(i);
|
||||
char title[48], sub[48], right[16] = "";
|
||||
const char* name = e.name[0] ? e.name : "(unknown)";
|
||||
snprintf(title, sizeof(title), "%s%s", e.fav ? UI_SYMBOL_STAR " " : "", name);
|
||||
char age[8];
|
||||
geo::fmtAgeShort(age, sizeof(age), now, e.lastmod);
|
||||
if (e.dist_km >= 0.0f) geo::fmtDist(right, sizeof(right), e.dist_km, imperial);
|
||||
else if (age[0]) snprintf(right, sizeof(right), "%s", age);
|
||||
const char* kind = e.contact_idx >= 0 ? NearbyModel::typeName(e.type) : "not a contact";
|
||||
snprintf(sub, sizeof(sub), "%s%s%s%s", kind, e.is_live ? " - live" : "",
|
||||
(e.dist_km >= 0.0f && age[0]) ? " - " : "", (e.dist_km >= 0.0f && age[0]) ? age : "");
|
||||
lv_obj_t* row = listRow(_nearby_list, title, sub, onNearbyRow, (void*)(uintptr_t)i);
|
||||
if (e.fav) lv_obj_set_style_text_color(lv_obj_get_child(row, 0), lv_color_hex(theme::ACCENT), 0);
|
||||
if (right[0]) {
|
||||
lv_obj_t* r = label(row, right, THEME_FONT_SMALL, e.is_live ? theme::OK : theme::TEXT_MUTED);
|
||||
lv_obj_align(r, LV_ALIGN_RIGHT_MID, -theme::PAD, 0);
|
||||
}
|
||||
}
|
||||
if (n == 0) {
|
||||
lv_obj_t* l = label(_nearby_list, "Nobody here yet. Tap Scan to look around.",
|
||||
THEME_FONT_BODY, theme::TEXT_MUTED);
|
||||
lv_obj_set_style_pad_top(l, 12, 0);
|
||||
}
|
||||
lv_obj_update_layout(_nearby_list);
|
||||
lv_obj_scroll_to_y(_nearby_list, scroll, LV_ANIM_OFF);
|
||||
}
|
||||
|
||||
// ── Node detail ───────────────────────────────────────────────────────────────
|
||||
|
||||
void UITask::openNode(int row) {
|
||||
if (row < 0 || row >= _nearby->count()) return;
|
||||
s_node = _nearby->at(row);
|
||||
_node_from_scan = false;
|
||||
_pinging = false;
|
||||
_delete_armed_ms = 0;
|
||||
_screen = SCR_NODE;
|
||||
buildNode();
|
||||
}
|
||||
|
||||
static lv_obj_t* actionButton(lv_obj_t* parent, const char* text, uint8_t action, bool accent) {
|
||||
lv_obj_t* b = lv_button_create(parent);
|
||||
lv_obj_set_height(b, 40);
|
||||
lv_obj_set_flex_grow(b, 1);
|
||||
lv_obj_set_style_pad_hor(b, 4, 0);
|
||||
lv_obj_set_style_radius(b, theme::RADIUS, 0);
|
||||
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||
lv_obj_set_style_bg_color(b, lv_color_hex(accent ? theme::ACCENT_DIM : theme::SURFACE), 0);
|
||||
lv_obj_set_style_bg_color(b, lv_color_hex(theme::SURFACE_2), LV_STATE_PRESSED);
|
||||
lv_obj_add_event_cb(b, onNodeAction, LV_EVENT_CLICKED, (void*)(uintptr_t)action);
|
||||
lv_obj_t* l = label(b, text, THEME_FONT_SMALL, theme::TEXT);
|
||||
lv_obj_center(l);
|
||||
return l;
|
||||
}
|
||||
|
||||
void UITask::buildNode() {
|
||||
const NearbyModel::Entry& e = s_node;
|
||||
lv_obj_t* body = newScreen(e.name[0] ? e.name : "(unknown)", true);
|
||||
|
||||
_node_info = label(body, "", THEME_FONT_BODY, theme::TEXT);
|
||||
lv_label_set_long_mode(_node_info, LV_LABEL_LONG_WRAP);
|
||||
lv_obj_set_width(_node_info, LV_PCT(100));
|
||||
lv_obj_set_style_text_line_space(_node_info, 3, 0);
|
||||
_node_ping = label(body, "", THEME_FONT_BODY, theme::ACCENT);
|
||||
|
||||
lv_obj_t* spacer = lv_obj_create(body); // pushes the actions to the bottom
|
||||
lv_obj_remove_style_all(spacer);
|
||||
lv_obj_set_width(spacer, 1);
|
||||
lv_obj_set_flex_grow(spacer, 1);
|
||||
|
||||
lv_obj_t* acts = lv_obj_create(body);
|
||||
styleSurface(acts, theme::BG);
|
||||
lv_obj_remove_flag(acts, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_size(acts, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_flex_flow(acts, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_column(acts, theme::GAP, 0);
|
||||
bool contact = e.contact_idx >= 0;
|
||||
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 (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) _node_delete_lbl = actionButton(acts, LV_SYMBOL_TRASH, NODE_DELETE, false);
|
||||
|
||||
refreshNode();
|
||||
}
|
||||
|
||||
void UITask::refreshNode() {
|
||||
if (!_node_info) return;
|
||||
const NearbyModel::Entry& e = s_node;
|
||||
// Refresh position / age / signal from its model while the node is still listed.
|
||||
NearbyModel* model = _node_from_scan ? _scan : _nearby;
|
||||
model->refreshModel();
|
||||
for (int i = 0; i < model->count(); i++) {
|
||||
const NearbyModel::Entry& m = model->at(i);
|
||||
bool same = e.has_key ? (m.has_key && memcmp(m.pub_key, e.pub_key, PUB_KEY_SIZE) == 0)
|
||||
: (e.contact_idx >= 0) ? m.contact_idx == e.contact_idx
|
||||
: strncmp(m.name, e.name, sizeof(m.name)) == 0;
|
||||
if (same) { s_node = m; break; }
|
||||
}
|
||||
|
||||
char buf[320];
|
||||
int o = 0;
|
||||
// A scan row carries no contact index; is_known says whether it's in the contacts.
|
||||
bool known = e.contact_idx >= 0 || (_node_from_scan && e.is_known);
|
||||
o += snprintf(buf + o, sizeof(buf) - o, "%s%s%s%s", NearbyModel::typeName(e.type),
|
||||
known ? "" : " - not a contact",
|
||||
e.is_live ? (e.live_verified ? " - live position" : " - live position (channel)") : "",
|
||||
e.fav ? " - favourite" : "");
|
||||
int32_t lat, lon;
|
||||
bool gps = _nearby->ownPosition(lat, lon);
|
||||
if (e.lat_e6 != 0 || e.lon_e6 != 0) {
|
||||
if (gps && e.dist_km >= 0.0f) {
|
||||
char d[16];
|
||||
geo::fmtDist(d, sizeof(d), e.dist_km, _prefs && _prefs->units_imperial);
|
||||
int az = geo::bearingDeg(lat, lon, e.lat_e6, e.lon_e6);
|
||||
o += snprintf(buf + o, sizeof(buf) - o, "\n%s %d\xC2\xB0 %s", d, az, geo::bearingCardinal(az));
|
||||
}
|
||||
o += snprintf(buf + o, sizeof(buf) - o, "\n%.5f, %.5f", e.lat_e6 / 1e6, e.lon_e6 / 1e6);
|
||||
} else if (!_node_from_scan) {
|
||||
o += snprintf(buf + o, sizeof(buf) - o, "\nNo position shared");
|
||||
}
|
||||
char age[8];
|
||||
geo::fmtAgeShort(age, sizeof(age), rtc_clock.getCurrentTime(), e.lastmod);
|
||||
if (age[0]) o += snprintf(buf + o, sizeof(buf) - o, "\nHeard %s ago", age);
|
||||
if (_node_from_scan)
|
||||
o += snprintf(buf + o, sizeof(buf) - o, "\nRSSI %d dBm - SNR %.1f / %.1f dB", e.rssi,
|
||||
e.snr_x4 / 4.0f, e.remote_snr_x4 / 4.0f);
|
||||
if (e.has_prefix)
|
||||
o += snprintf(buf + o, sizeof(buf) - o, "\nID %02X%02X%02X%02X", e.pub_key[0], e.pub_key[1], e.pub_key[2], e.pub_key[3]);
|
||||
lv_label_set_text(_node_info, buf);
|
||||
|
||||
// Ping result (PingEngine releases its slot on reply; the view owns the timeout)
|
||||
if (_pinging) {
|
||||
int16_t out = 0, back = 0; uint32_t rtt = 0;
|
||||
_core->ping.getResult(out, back, rtt);
|
||||
if (!_core->ping.isActive() && (out || back || rtt)) {
|
||||
lv_label_set_text_fmt(_node_ping, "Ping %lu ms - SNR out %.1f back %.1f", (unsigned long)rtt,
|
||||
out / 4.0f, back / 4.0f);
|
||||
_pinging = false;
|
||||
} else if (millis() - _ping_started_ms > 3000) {
|
||||
_core->ping.clear();
|
||||
lv_label_set_text(_node_ping, "Ping: no reply");
|
||||
_pinging = false;
|
||||
}
|
||||
}
|
||||
if (_node_delete_lbl && _delete_armed_ms && millis() - _delete_armed_ms > 3000) {
|
||||
_delete_armed_ms = 0;
|
||||
lv_label_set_text(_node_delete_lbl, LV_SYMBOL_TRASH);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::nodeAction(uint8_t action) {
|
||||
NearbyModel::Entry& e = s_node;
|
||||
switch (action) {
|
||||
case NODE_MSG:
|
||||
openDM(e.pub_key);
|
||||
break;
|
||||
case NODE_PING: {
|
||||
if (_pinging) break;
|
||||
PingEngine::StartResult r = _core->ping.start(e.pub_key);
|
||||
if (r == PingEngine::STARTED) {
|
||||
_pinging = true;
|
||||
_ping_started_ms = millis();
|
||||
_next_nearby_ms = millis() + 250;
|
||||
lv_label_set_text(_node_ping, "Pinging...");
|
||||
} else {
|
||||
lv_label_set_text(_node_ping, r == PingEngine::UNSUPPORTED ? "Ping needs 1-2 byte path hashes"
|
||||
: "Ping failed");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_FAV:
|
||||
if (the_mesh.setContactFavourite(e.pub_key, !e.fav)) {
|
||||
e.fav = !e.fav;
|
||||
buildNode();
|
||||
}
|
||||
break;
|
||||
case NODE_ADD:
|
||||
if (the_mesh.addDiscoveredContact(e.pub_key, e.name, e.type)) {
|
||||
showToast("Contact added");
|
||||
_screen = SCR_NEARBY;
|
||||
buildNearby();
|
||||
} else {
|
||||
showToast("Contacts full");
|
||||
}
|
||||
break;
|
||||
case NODE_DELETE:
|
||||
if (!_delete_armed_ms) { // destructive: second tap within 3 s confirms
|
||||
_delete_armed_ms = millis();
|
||||
if (_delete_armed_ms == 0) _delete_armed_ms = 1;
|
||||
lv_label_set_text(_node_delete_lbl, "Delete?");
|
||||
break;
|
||||
}
|
||||
if (the_mesh.deleteContactByKey(e.pub_key)) {
|
||||
showToast("Contact deleted");
|
||||
_screen = SCR_NEARBY;
|
||||
buildNearby();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Conversation ──────────────────────────────────────────────────────────────
|
||||
|
||||
static void onKeyboard(lv_event_t* e) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "../ui-core/UiCoreHost.h"
|
||||
|
||||
class UiCore;
|
||||
class NearbyModel;
|
||||
struct UiEvent;
|
||||
|
||||
class UITask : public UITaskBase, public UiCoreHost {
|
||||
@@ -37,6 +38,14 @@ public:
|
||||
void showChats();
|
||||
void showContacts();
|
||||
void showSettings();
|
||||
void showNearby();
|
||||
void setNearbyFilter(uint8_t f);
|
||||
void toggleNearbySort();
|
||||
void startNearbyScan();
|
||||
void closeScanPopup();
|
||||
void openScanNode(int row);
|
||||
void openNode(int row);
|
||||
void nodeAction(uint8_t action);
|
||||
void setKeyboardAlphabets(int main_idx, int alt_sel);
|
||||
void openChannel(uint8_t channel_idx);
|
||||
void openDM(const uint8_t* pub_key);
|
||||
@@ -50,7 +59,7 @@ public:
|
||||
void openAdminFor(const ContactInfo& ci, bool from_picker) { (void)ci; (void)from_picker; }
|
||||
|
||||
private:
|
||||
enum Screen : uint8_t { SCR_HOME, SCR_CHATS, SCR_CONTACTS, SCR_THREAD, SCR_SETTINGS };
|
||||
enum Screen : uint8_t { SCR_HOME, SCR_CHATS, SCR_CONTACTS, SCR_THREAD, SCR_SETTINGS, SCR_NEARBY, SCR_NODE };
|
||||
|
||||
void buildStatusBar();
|
||||
void refreshStatusBar();
|
||||
@@ -60,6 +69,13 @@ private:
|
||||
void buildChats();
|
||||
void buildContacts();
|
||||
void buildSettings();
|
||||
void buildNearby();
|
||||
void refreshNearbyList();
|
||||
uint32_t nearbySignature() const;
|
||||
void showScanPopup();
|
||||
void refreshScanPopup();
|
||||
void buildNode();
|
||||
void refreshNode();
|
||||
void buildThread();
|
||||
void refreshThread();
|
||||
uint32_t threadSignature() const;
|
||||
@@ -99,4 +115,27 @@ private:
|
||||
lv_obj_t* _thread_list = nullptr;
|
||||
lv_obj_t* _compose_ta = nullptr;
|
||||
lv_obj_t* _keyboard = nullptr;
|
||||
|
||||
// Nearby (SCR_NEARBY) / node detail (SCR_NODE); list data in NearbyModel
|
||||
NearbyModel* _nearby = nullptr;
|
||||
NearbyModel* _scan = nullptr; // NODE_DISCOVER results: nodes in range now (popup over the list)
|
||||
bool _scanning = false;
|
||||
bool _node_from_scan = false;
|
||||
uint32_t _scan_sig = 0;
|
||||
lv_obj_t* _scan_overlay = nullptr;
|
||||
lv_obj_t* _scan_list = nullptr;
|
||||
lv_obj_t* _scan_status = nullptr;
|
||||
uint32_t _scan_until_ms = 0;
|
||||
uint32_t _nearby_sig = 0;
|
||||
uint32_t _next_nearby_ms = 0;
|
||||
bool _pinging = false;
|
||||
uint32_t _ping_started_ms = 0;
|
||||
uint32_t _delete_armed_ms = 0;
|
||||
lv_obj_t* _nearby_list = nullptr;
|
||||
lv_obj_t* _nearby_status = nullptr;
|
||||
lv_obj_t* _nearby_sort_lbl = nullptr;
|
||||
lv_obj_t* _nearby_chips = nullptr;
|
||||
lv_obj_t* _node_info = nullptr;
|
||||
lv_obj_t* _node_ping = nullptr;
|
||||
lv_obj_t* _node_delete_lbl = nullptr;
|
||||
};
|
||||
|
||||
@@ -26,8 +26,8 @@ FA_URL=https://raw.githubusercontent.com/lvgl/lvgl/v9.2.2/scripts/built_in_font/
|
||||
TEXT="0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3"
|
||||
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)
|
||||
# plus 61612 = globe (keyboard script key)
|
||||
SYMS="61612,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"
|
||||
# plus 61612 = globe (keyboard script key), 61445 = star (favourite)
|
||||
SYMS="61612,61445,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"
|
||||
gen() { # size weight ranges name
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 12 px
|
||||
* Bpp: 4
|
||||
* Opts: --bpp 4 --size 12 --force-fast-kern-format --font /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/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 /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/fonts/fa.woff -r 61612,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 61612,61445,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
|
||||
@@ -6379,6 +6379,17 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x70, 0x3, 0x20, 0x80, 0x19, 0x0, 0x2e, 0x0,
|
||||
0x17, 0x6f, 0x4e, 0x32, 0xc3, 0x0, 0x62, 0x10,
|
||||
|
||||
/* U+F005 "" */
|
||||
0x0, 0xf2, 0x90, 0x7, 0xfc, 0x75, 0x20, 0x1f,
|
||||
0xf4, 0x2, 0x18, 0x7, 0xf1, 0xa0, 0x2, 0x0,
|
||||
0x38, 0xa2, 0xb7, 0x0, 0x24, 0xec, 0x95, 0x4,
|
||||
0x75, 0x20, 0xe, 0x13, 0x6b, 0x6, 0x60, 0x7,
|
||||
0xf0, 0xe0, 0x2, 0x5c, 0x3, 0xe1, 0xc2, 0x0,
|
||||
0xa0, 0x40, 0x3d, 0x4, 0x1, 0xc2, 0x1, 0xee,
|
||||
0x0, 0xe3, 0x0, 0x84, 0x2, 0x30, 0xe, 0x60,
|
||||
0x18, 0xec, 0x40, 0x60, 0xe, 0x49, 0xe7, 0x3,
|
||||
0xbc, 0x80, 0x8,
|
||||
|
||||
/* U+F008 "" */
|
||||
0xb4, 0xdf, 0xff, 0x6a, 0x5a, 0xe1, 0xc6, 0xee,
|
||||
0x83, 0xc5, 0x28, 0x22, 0xf0, 0x94, 0x11, 0xe1,
|
||||
@@ -7919,66 +7930,67 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 30941, .adv_w = 196, .box_w = 11, .box_h = 9, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 30986, .adv_w = 148, .box_w = 9, .box_h = 5, .ofs_x = 0, .ofs_y = 4},
|
||||
{.bitmap_index = 31007, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31063, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31109, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31159, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31205, .adv_w = 132, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31247, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31320, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31395, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31455, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31509, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31557, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31630, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31653, .adv_w = 144, .box_w = 9, .box_h = 10, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31688, .adv_w = 216, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31762, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31804, .adv_w = 132, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31854, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 31891, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31937, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31964, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31981, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 32019, .adv_w = 168, .box_w = 12, .box_h = 11, .ofs_x = -1, .ofs_y = -1},
|
||||
{.bitmap_index = 32066, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32102, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32139, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32178, .adv_w = 168, .box_w = 11, .box_h = 3, .ofs_x = 0, .ofs_y = 3},
|
||||
{.bitmap_index = 32187, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 32249, .adv_w = 240, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 32340, .adv_w = 216, .box_w = 15, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 32415, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32474, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 32508, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 32542, .adv_w = 240, .box_w = 16, .box_h = 10, .ofs_x = -1, .ofs_y = 0},
|
||||
{.bitmap_index = 32602, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 32622, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 32679, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 32743, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 32813, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32874, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 32914, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32958, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32990, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33029, .adv_w = 120, .box_w = 9, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 33075, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33120, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33173, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33229, .adv_w = 192, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 33292, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33315, .adv_w = 240, .box_w = 15, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 33390, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33433, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33482, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33531, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33580, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33622, .adv_w = 240, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 33687, .adv_w = 168, .box_w = 10, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33751, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33794, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 33861, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33916, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33945, .adv_w = 193, .box_w = 13, .box_h = 9, .ofs_x = 0, .ofs_y = 0}
|
||||
{.bitmap_index = 31063, .adv_w = 216, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31130, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31176, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31226, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31272, .adv_w = 132, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31314, .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 = 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 = 31624, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31697, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31720, .adv_w = 144, .box_w = 9, .box_h = 10, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 31755, .adv_w = 216, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 31829, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 31871, .adv_w = 132, .box_w = 9, .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 = 31958, .adv_w = 168, .box_w = 11, .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 = 32031, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32048, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 32086, .adv_w = 168, .box_w = 12, .box_h = 11, .ofs_x = -1, .ofs_y = -1},
|
||||
{.bitmap_index = 32133, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32169, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32206, .adv_w = 168, .box_w = 11, .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 = 32254, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 32316, .adv_w = 240, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 32407, .adv_w = 216, .box_w = 15, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 32482, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32541, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 32575, .adv_w = 168, .box_w = 11, .box_h = 7, .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 = 32669, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 32689, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 32746, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 32810, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 32880, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 32941, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 32981, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 33025, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 33057, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33096, .adv_w = 120, .box_w = 9, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 33142, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33187, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33240, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33296, .adv_w = 192, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 33359, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33382, .adv_w = 240, .box_w = 15, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 33457, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33500, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33549, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33598, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33647, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33689, .adv_w = 240, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 33754, .adv_w = 168, .box_w = 10, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33818, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 33861, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 33928, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 33983, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 34012, .adv_w = 193, .box_w = 13, .box_h = 9, .ofs_x = 0, .ofs_y = 0}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@@ -8002,14 +8014,14 @@ static const uint16_t unicode_list_10[] = {
|
||||
};
|
||||
|
||||
static const uint16_t unicode_list_12[] = {
|
||||
0x0, 0xc, 0xceeb, 0xcef2, 0xcef5, 0xcef6, 0xcef7, 0xcefb,
|
||||
0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11, 0xcf12,
|
||||
0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b, 0xcf3c,
|
||||
0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b, 0xcf5e,
|
||||
0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96, 0xcfae,
|
||||
0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4, 0xcfdd, 0xd006,
|
||||
0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e,
|
||||
0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444, 0xd6ac, 0xd78c
|
||||
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
||||
0xcefb, 0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11,
|
||||
0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b,
|
||||
0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b,
|
||||
0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96,
|
||||
0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4, 0xcfdd,
|
||||
0xd006, 0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d,
|
||||
0xd12e, 0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444, 0xd6ac, 0xd78c
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@@ -8065,7 +8077,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
},
|
||||
{
|
||||
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 63, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 64, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8211,7 +8223,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
|
||||
};
|
||||
|
||||
/*Map glyph_ids to kern right classes*/
|
||||
@@ -8351,7 +8364,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
|
||||
};
|
||||
|
||||
/*Kern values between classes*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 14 px
|
||||
* Bpp: 4
|
||||
* Opts: --bpp 4 --size 14 --force-fast-kern-format --font /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/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 /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/fonts/fa.woff -r 61612,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 61612,61445,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
|
||||
@@ -7257,6 +7257,19 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0xbc, 0x44, 0x1, 0x8, 0x80, 0x2a, 0xfe, 0xd3,
|
||||
0x1c, 0x42, 0x5d, 0x0, 0xf0, 0x80, 0x0,
|
||||
|
||||
/* U+F005 "" */
|
||||
0x0, 0xf8, 0x84, 0x3, 0xff, 0x82, 0x3b, 0xa0,
|
||||
0xf, 0xfe, 0xc, 0x81, 0xa0, 0x7, 0xfc, 0x2e,
|
||||
0x0, 0x80, 0xf, 0xfa, 0x40, 0x23, 0x50, 0xe,
|
||||
0x19, 0xbe, 0xf7, 0x0, 0xd5, 0xfb, 0x6e, 0x8,
|
||||
0xc8, 0x20, 0x1f, 0x89, 0x20, 0x55, 0x80, 0x3f,
|
||||
0xf8, 0x14, 0x21, 0x2e, 0x1, 0xfe, 0xa5, 0x0,
|
||||
0xa1, 0x80, 0x3f, 0x52, 0x80, 0x77, 0x80, 0x7e,
|
||||
0x70, 0xf, 0x78, 0x7, 0xe7, 0x0, 0xf2, 0x80,
|
||||
0x42, 0x1, 0xb4, 0x3, 0xc4, 0x0, 0x8e, 0xd5,
|
||||
0x0, 0x10, 0x7, 0x99, 0xf9, 0xc0, 0xab, 0x5b,
|
||||
0xc0, 0x20,
|
||||
|
||||
/* U+F008 "" */
|
||||
0x50, 0x18, 0x8f, 0xc8, 0xb, 0x55, 0x3a, 0xaf,
|
||||
0x9e, 0x6a, 0x83, 0xd8, 0x19, 0xbb, 0xc6, 0xfc,
|
||||
@@ -8889,66 +8902,67 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 37928, .adv_w = 229, .box_w = 13, .box_h = 10, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 37984, .adv_w = 173, .box_w = 10, .box_h = 5, .ofs_x = 0, .ofs_y = 5},
|
||||
{.bitmap_index = 38007, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 38078, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 38139, .adv_w = 224, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 38199, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 38260, .adv_w = 154, .box_w = 10, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 38312, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 38402, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 38489, .adv_w = 252, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 38569, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 38634, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 38697, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 38792, .adv_w = 112, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 38820, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 38866, .adv_w = 252, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 38956, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 39012, .adv_w = 154, .box_w = 10, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 39072, .adv_w = 196, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 39119, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 39177, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39214, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39239, .adv_w = 196, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 39288, .adv_w = 196, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -1},
|
||||
{.bitmap_index = 39347, .adv_w = 140, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39395, .adv_w = 140, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39444, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39491, .adv_w = 196, .box_w = 13, .box_h = 4, .ofs_x = 0, .ofs_y = 3},
|
||||
{.bitmap_index = 39505, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 39588, .adv_w = 280, .box_w = 18, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 39705, .adv_w = 252, .box_w = 17, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 39793, .adv_w = 224, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39875, .adv_w = 196, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 39918, .adv_w = 196, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 39963, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 40034, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 40063, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40135, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 40214, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40307, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 40388, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40436, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 40492, .adv_w = 196, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 40532, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 40585, .adv_w = 140, .box_w = 10, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 40641, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40704, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40770, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 40843, .adv_w = 224, .box_w = 16, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 40920, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40952, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 41049, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41101, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41156, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41211, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41266, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41315, .adv_w = 280, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 41395, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 41479, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 41535, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 41612, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41690, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 41726, .adv_w = 225, .box_w = 15, .box_h = 10, .ofs_x = 0, .ofs_y = 0}
|
||||
{.bitmap_index = 38078, .adv_w = 252, .box_w = 16, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 38160, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 38221, .adv_w = 224, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 38281, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 38342, .adv_w = 154, .box_w = 10, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 38394, .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 = 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 = 38779, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 38874, .adv_w = 112, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 38902, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 38948, .adv_w = 252, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 39038, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 39094, .adv_w = 154, .box_w = 10, .box_h = 15, .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 = 39201, .adv_w = 196, .box_w = 13, .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 = 39296, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39321, .adv_w = 196, .box_w = 10, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 39370, .adv_w = 196, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -1},
|
||||
{.bitmap_index = 39429, .adv_w = 140, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39477, .adv_w = 140, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39526, .adv_w = 196, .box_w = 13, .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 = 39587, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 39670, .adv_w = 280, .box_w = 18, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 39787, .adv_w = 252, .box_w = 17, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 39875, .adv_w = 224, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 39957, .adv_w = 196, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 40000, .adv_w = 196, .box_w = 13, .box_h = 8, .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 = 40116, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 40145, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40217, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 40296, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40389, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 40470, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40518, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 40574, .adv_w = 196, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 40614, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 40667, .adv_w = 140, .box_w = 10, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 40723, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40786, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 40852, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 40925, .adv_w = 224, .box_w = 16, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 41002, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 41034, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 41131, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41183, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41238, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41293, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41348, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41397, .adv_w = 280, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 41477, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 41561, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 41617, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 41694, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 41772, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 41808, .adv_w = 225, .box_w = 15, .box_h = 10, .ofs_x = 0, .ofs_y = 0}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@@ -8972,14 +8986,14 @@ static const uint16_t unicode_list_10[] = {
|
||||
};
|
||||
|
||||
static const uint16_t unicode_list_12[] = {
|
||||
0x0, 0xc, 0xceeb, 0xcef2, 0xcef5, 0xcef6, 0xcef7, 0xcefb,
|
||||
0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11, 0xcf12,
|
||||
0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b, 0xcf3c,
|
||||
0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b, 0xcf5e,
|
||||
0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96, 0xcfae,
|
||||
0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4, 0xcfdd, 0xd006,
|
||||
0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e,
|
||||
0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444, 0xd6ac, 0xd78c
|
||||
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
||||
0xcefb, 0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11,
|
||||
0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b,
|
||||
0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b,
|
||||
0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96,
|
||||
0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4, 0xcfdd,
|
||||
0xd006, 0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d,
|
||||
0xd12e, 0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444, 0xd6ac, 0xd78c
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@@ -9035,7 +9049,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
},
|
||||
{
|
||||
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 63, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 64, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9181,7 +9195,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
|
||||
};
|
||||
|
||||
/*Map glyph_ids to kern right classes*/
|
||||
@@ -9321,7 +9336,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
|
||||
};
|
||||
|
||||
/*Kern values between classes*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 16 px
|
||||
* Bpp: 4
|
||||
* Opts: --bpp 4 --size 16 --force-fast-kern-format --font /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/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 /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/fonts/fa.woff -r 61612,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 61612,61445,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
|
||||
@@ -8308,6 +8308,21 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x0, 0x62, 0xbf, 0xf5, 0x97, 0xa0, 0x1, 0x3c,
|
||||
0x3, 0xfc,
|
||||
|
||||
/* U+F005 "" */
|
||||
0x0, 0xfd, 0x98, 0x0, 0xff, 0xe1, 0xa9, 0x99,
|
||||
0x40, 0x3f, 0xf8, 0x50, 0x0, 0x80, 0xf, 0xfe,
|
||||
0xa, 0x90, 0x0, 0x94, 0x3, 0xfc, 0x27, 0x0,
|
||||
0x1a, 0xc, 0x40, 0x30, 0xce, 0x77, 0x30, 0x80,
|
||||
0x31, 0x67, 0x73, 0x24, 0x55, 0x8c, 0x40, 0x3f,
|
||||
0xc2, 0x6c, 0xa8, 0xc0, 0x1f, 0xfc, 0x26, 0x40,
|
||||
0x96, 0x0, 0xff, 0xe0, 0x34, 0x80, 0x52, 0xe0,
|
||||
0x1f, 0xe7, 0x90, 0xe, 0x82, 0x0, 0xfc, 0x50,
|
||||
0x1, 0xf1, 0x0, 0x7e, 0x20, 0xf, 0x88, 0x3,
|
||||
0xfc, 0x40, 0x1e, 0x60, 0xf, 0xf3, 0x0, 0x78,
|
||||
0xc0, 0x27, 0xee, 0x38, 0x4, 0x60, 0x1e, 0x21,
|
||||
0x6e, 0x81, 0x14, 0x73, 0x9, 0x0, 0x79, 0x7a,
|
||||
0x44, 0x3, 0xc, 0xf2, 0x80, 0x40,
|
||||
|
||||
/* U+F008 "" */
|
||||
0xd0, 0x7, 0xff, 0xf8, 0x1, 0xa5, 0xfe, 0x3,
|
||||
0x77, 0xf1, 0x87, 0xf8, 0x83, 0xfc, 0x9, 0x11,
|
||||
@@ -9993,66 +10008,67 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 46302, .adv_w = 262, .box_w = 15, .box_h = 12, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 46374, .adv_w = 198, .box_w = 12, .box_h = 7, .ofs_x = 0, .ofs_y = 5},
|
||||
{.bitmap_index = 46410, .adv_w = 256, .box_w = 16, .box_h = 17, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 46484, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 46548, .adv_w = 256, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 46616, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 46689, .adv_w = 176, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 46753, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 46862, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 46964, .adv_w = 288, .box_w = 18, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47055, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 47123, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 47186, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 47290, .adv_w = 128, .box_w = 8, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47321, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47372, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 47479, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 47546, .adv_w = 176, .box_w = 11, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 47613, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2},
|
||||
{.bitmap_index = 47665, .adv_w = 224, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 47737, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47766, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47786, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2},
|
||||
{.bitmap_index = 47838, .adv_w = 224, .box_w = 16, .box_h = 14, .ofs_x = -1, .ofs_y = -1},
|
||||
{.bitmap_index = 47909, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47966, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 48023, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 48068, .adv_w = 224, .box_w = 14, .box_h = 4, .ofs_x = 0, .ofs_y = 4},
|
||||
{.bitmap_index = 48085, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 48184, .adv_w = 320, .box_w = 20, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 48318, .adv_w = 288, .box_w = 20, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 48430, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 48530, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 48585, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 48642, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 48730, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 48759, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 48827, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 48921, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49029, .adv_w = 224, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 49120, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49167, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 49219, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 49274, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 49333, .adv_w = 160, .box_w = 12, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 49401, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49462, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49532, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 49598, .adv_w = 256, .box_w = 18, .box_h = 18, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 49687, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49720, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 49833, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 49878, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 49922, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 49966, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 50012, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 50052, .adv_w = 320, .box_w = 21, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 50153, .adv_w = 224, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 50249, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 50304, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 50398, .adv_w = 320, .box_w = 20, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 50487, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 50526, .adv_w = 258, .box_w = 17, .box_h = 11, .ofs_x = 0, .ofs_y = 1}
|
||||
{.bitmap_index = 46484, .adv_w = 288, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 46586, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 46650, .adv_w = 256, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 46718, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 46791, .adv_w = 176, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 46855, .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 = 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 = 47288, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 47392, .adv_w = 128, .box_w = 8, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47423, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47474, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 47581, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 47648, .adv_w = 176, .box_w = 11, .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 = 47767, .adv_w = 224, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 47839, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47868, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 47888, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2},
|
||||
{.bitmap_index = 47940, .adv_w = 224, .box_w = 16, .box_h = 14, .ofs_x = -1, .ofs_y = -1},
|
||||
{.bitmap_index = 48011, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 48068, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 48125, .adv_w = 224, .box_w = 14, .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 = 48187, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 48286, .adv_w = 320, .box_w = 20, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 48420, .adv_w = 288, .box_w = 20, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 48532, .adv_w = 256, .box_w = 16, .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 = 48687, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 48744, .adv_w = 320, .box_w = 20, .box_h = 14, .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 = 48861, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 48929, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 49023, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49131, .adv_w = 224, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 49222, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49269, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 49321, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 49376, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 49435, .adv_w = 160, .box_w = 12, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 49503, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49564, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49634, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 49700, .adv_w = 256, .box_w = 18, .box_h = 18, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 49789, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 49822, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 49935, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 49980, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 50024, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 50068, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 50114, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 50154, .adv_w = 320, .box_w = 21, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 50255, .adv_w = 224, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 50351, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 50406, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 50500, .adv_w = 320, .box_w = 20, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 50589, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 50628, .adv_w = 258, .box_w = 17, .box_h = 11, .ofs_x = 0, .ofs_y = 1}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@@ -10076,14 +10092,14 @@ static const uint16_t unicode_list_10[] = {
|
||||
};
|
||||
|
||||
static const uint16_t unicode_list_12[] = {
|
||||
0x0, 0xc, 0xceeb, 0xcef2, 0xcef5, 0xcef6, 0xcef7, 0xcefb,
|
||||
0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11, 0xcf12,
|
||||
0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b, 0xcf3c,
|
||||
0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b, 0xcf5e,
|
||||
0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96, 0xcfae,
|
||||
0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4, 0xcfdd, 0xd006,
|
||||
0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e,
|
||||
0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444, 0xd6ac, 0xd78c
|
||||
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
||||
0xcefb, 0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11,
|
||||
0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b,
|
||||
0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b,
|
||||
0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96,
|
||||
0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4, 0xcfdd,
|
||||
0xd006, 0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d,
|
||||
0xd12e, 0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444, 0xd6ac, 0xd78c
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@@ -10139,7 +10155,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
},
|
||||
{
|
||||
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 63, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 64, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10285,7 +10301,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
|
||||
};
|
||||
|
||||
/*Map glyph_ids to kern right classes*/
|
||||
@@ -10425,7 +10442,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
|
||||
};
|
||||
|
||||
/*Kern values between classes*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 20 px
|
||||
* Bpp: 4
|
||||
* Opts: --bpp 4 --size 20 --force-fast-kern-format --font /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/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 /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/fonts/fa.woff -r 61612,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 61612,61445,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
|
||||
@@ -10406,6 +10406,25 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x1, 0xc4, 0xc0, 0x1f, 0x11, 0x0, 0x27, 0xd7,
|
||||
0x55, 0x4e, 0x88, 0x7, 0xff, 0x0,
|
||||
|
||||
/* U+F005 "" */
|
||||
0x0, 0xff, 0x1b, 0x0, 0x7f, 0xf1, 0xc7, 0x26,
|
||||
0x0, 0x3f, 0xf8, 0xd2, 0x0, 0x71, 0x0, 0xff,
|
||||
0xe2, 0xb, 0x80, 0x52, 0x1, 0xff, 0xc4, 0x90,
|
||||
0xc, 0xe2, 0x1, 0xff, 0xc3, 0x70, 0xe, 0x60,
|
||||
0xf, 0xf8, 0x95, 0xec, 0x3, 0xd1, 0x6, 0x41,
|
||||
0x0, 0xd3, 0xbf, 0xb5, 0x8, 0x1, 0xf3, 0xcd,
|
||||
0xf7, 0xe1, 0x93, 0x10, 0x7, 0xff, 0x14, 0xe4,
|
||||
0x94, 0x3, 0xff, 0x8c, 0x32, 0x14, 0xc0, 0x1f,
|
||||
0xfc, 0x41, 0xd3, 0x0, 0x4b, 0x0, 0x7f, 0xf0,
|
||||
0x87, 0xc, 0x3, 0x4b, 0x80, 0x7f, 0xf0, 0x7,
|
||||
0x8, 0x3, 0xd0, 0x60, 0x1f, 0xf5, 0x10, 0x7,
|
||||
0xe2, 0x0, 0xff, 0x88, 0x3, 0xf8, 0x40, 0x3f,
|
||||
0xee, 0x0, 0xfc, 0x60, 0x1f, 0xfc, 0x3, 0x0,
|
||||
0xfc, 0xa0, 0x1e, 0x20, 0xe, 0x50, 0xf, 0xde,
|
||||
0x1, 0x9b, 0xb6, 0x88, 0x2, 0x11, 0x0, 0x7f,
|
||||
0x97, 0x64, 0x41, 0x76, 0x88, 0x3, 0xfd, 0x10,
|
||||
0xda, 0x20, 0xe, 0x5d, 0xab, 0x10, 0x8,
|
||||
|
||||
/* U+F008 "" */
|
||||
0xc4, 0x3, 0xff, 0xff, 0xe0, 0x20, 0x26, 0x1c,
|
||||
0xe7, 0x0, 0x4, 0x7f, 0x0, 0x27, 0x24, 0xc1,
|
||||
@@ -12334,66 +12353,67 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 62808, .adv_w = 327, .box_w = 19, .box_h = 15, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 62909, .adv_w = 247, .box_w = 14, .box_h = 8, .ofs_x = 0, .ofs_y = 7},
|
||||
{.bitmap_index = 62952, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 63062, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 63174, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 63261, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 63361, .adv_w = 220, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 63452, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 63611, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 63764, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 63907, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 64011, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 64108, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 64263, .adv_w = 160, .box_w = 10, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 64301, .adv_w = 240, .box_w = 15, .box_h = 16, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 64375, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 64529, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 64624, .adv_w = 220, .box_w = 14, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 64727, .adv_w = 280, .box_w = 13, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
|
||||
{.bitmap_index = 64795, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 64897, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 64954, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 64995, .adv_w = 280, .box_w = 13, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
|
||||
{.bitmap_index = 65069, .adv_w = 280, .box_w = 19, .box_h = 19, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 65168, .adv_w = 200, .box_w = 11, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 65253, .adv_w = 200, .box_w = 11, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 65334, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 65406, .adv_w = 280, .box_w = 18, .box_h = 5, .ofs_x = 0, .ofs_y = 5},
|
||||
{.bitmap_index = 65428, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 65578, .adv_w = 400, .box_w = 26, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 65781, .adv_w = 360, .box_w = 24, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 65934, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 66076, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 66152, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 66230, .adv_w = 400, .box_w = 26, .box_h = 16, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 66348, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 66392, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 66502, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 66640, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 66799, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 66947, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 67020, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 67113, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 67173, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 67263, .adv_w = 200, .box_w = 14, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 67356, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 67444, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 67555, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 67681, .adv_w = 320, .box_w = 22, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 67802, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 67850, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 68014, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 68081, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 63062, .adv_w = 360, .box_w = 22, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 63197, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 63309, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 63396, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 63496, .adv_w = 220, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 63587, .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 = 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 = 64243, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 64398, .adv_w = 160, .box_w = 10, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 64436, .adv_w = 240, .box_w = 15, .box_h = 16, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 64510, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 64664, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 64759, .adv_w = 220, .box_w = 14, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 64862, .adv_w = 280, .box_w = 13, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
|
||||
{.bitmap_index = 64930, .adv_w = 280, .box_w = 18, .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 = 65089, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 65130, .adv_w = 280, .box_w = 13, .box_h = 19, .ofs_x = 2, .ofs_y = -2},
|
||||
{.bitmap_index = 65204, .adv_w = 280, .box_w = 19, .box_h = 19, .ofs_x = -1, .ofs_y = -2},
|
||||
{.bitmap_index = 65303, .adv_w = 200, .box_w = 11, .box_h = 19, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 65388, .adv_w = 200, .box_w = 11, .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 = 65541, .adv_w = 280, .box_w = 18, .box_h = 5, .ofs_x = 0, .ofs_y = 5},
|
||||
{.bitmap_index = 65563, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 65713, .adv_w = 400, .box_w = 26, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 65916, .adv_w = 360, .box_w = 24, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 66069, .adv_w = 320, .box_w = 20, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 66211, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 66287, .adv_w = 280, .box_w = 18, .box_h = 11, .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 = 66483, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 66527, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 66637, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 66775, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 66934, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 67082, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 67155, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 67248, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 67308, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 67398, .adv_w = 200, .box_w = 14, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 67491, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 67579, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 67690, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 67816, .adv_w = 320, .box_w = 22, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 67937, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 67985, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 68149, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 68216, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 68283, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 68343, .adv_w = 400, .box_w = 26, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 68477, .adv_w = 280, .box_w = 16, .box_h = 21, .ofs_x = 1, .ofs_y = -3},
|
||||
{.bitmap_index = 68624, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 68711, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 68851, .adv_w = 400, .box_w = 25, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 68971, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 69030, .adv_w = 322, .box_w = 21, .box_h = 13, .ofs_x = 0, .ofs_y = 1}
|
||||
{.bitmap_index = 68284, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 68351, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 68418, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 68478, .adv_w = 400, .box_w = 26, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 68612, .adv_w = 280, .box_w = 16, .box_h = 21, .ofs_x = 1, .ofs_y = -3},
|
||||
{.bitmap_index = 68759, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 68846, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
|
||||
{.bitmap_index = 68986, .adv_w = 400, .box_w = 25, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 69106, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
|
||||
{.bitmap_index = 69165, .adv_w = 322, .box_w = 21, .box_h = 13, .ofs_x = 0, .ofs_y = 1}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@@ -12417,14 +12437,14 @@ static const uint16_t unicode_list_10[] = {
|
||||
};
|
||||
|
||||
static const uint16_t unicode_list_12[] = {
|
||||
0x0, 0xc, 0xceeb, 0xcef2, 0xcef5, 0xcef6, 0xcef7, 0xcefb,
|
||||
0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11, 0xcf12,
|
||||
0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b, 0xcf3c,
|
||||
0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b, 0xcf5e,
|
||||
0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96, 0xcfae,
|
||||
0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4, 0xcfdd, 0xd006,
|
||||
0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e,
|
||||
0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444, 0xd6ac, 0xd78c
|
||||
0x0, 0xc, 0xceeb, 0xceef, 0xcef2, 0xcef5, 0xcef6, 0xcef7,
|
||||
0xcefb, 0xcefd, 0xceff, 0xcf03, 0xcf06, 0xcf0b, 0xcf10, 0xcf11,
|
||||
0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36, 0xcf37, 0xcf3b,
|
||||
0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58, 0xcf5a, 0xcf5b,
|
||||
0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d, 0xcf7f, 0xcf96,
|
||||
0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca, 0xcfd1, 0xcfd4, 0xcfdd,
|
||||
0xd006, 0xd00e, 0xd045, 0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d,
|
||||
0xd12e, 0xd171, 0xd17d, 0xd1d7, 0xd1ee, 0xd444, 0xd6ac, 0xd78c
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@@ -12480,7 +12500,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
},
|
||||
{
|
||||
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
|
||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 63, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 64, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12626,7 +12646,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
|
||||
};
|
||||
|
||||
/*Map glyph_ids to kern right classes*/
|
||||
@@ -12766,7 +12787,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
|
||||
};
|
||||
|
||||
/*Kern values between classes*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 40 px
|
||||
* Bpp: 4
|
||||
* Opts: --bpp 4 --size 40 --no-compress --font /private/tmp/claude-501/-Users-jakub-Documents-MeshCore-MeshCore/3d84fa48-e031-42a4-abec-01b33a2b06ef/scratchpad/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,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
|
||||
|
||||
@@ -10,18 +10,12 @@
|
||||
// Filter (type) and sort are independent axes and combine freely. The action
|
||||
// menu (Hold Enter) is identical everywhere; only the per-row column and the
|
||||
// detail fields differ between sources.
|
||||
class NearbyScreen : public UIScreen {
|
||||
class NearbyScreen : public UIScreen, protected NearbyModel {
|
||||
UITask* _task;
|
||||
|
||||
// ── filter (type axis) ──────────────────────────────────────────────────────
|
||||
enum Filter : uint8_t { F_ALL, F_FAV, F_COMP, F_RPT, F_ROOM, F_SNSR, F_COUNT };
|
||||
static const char* FILTER_LABELS[F_COUNT];
|
||||
|
||||
// ── sort axis ───────────────────────────────────────────────────────────────
|
||||
enum Sort : uint8_t { SORT_DIST, SORT_TIME };
|
||||
|
||||
// ── source ──────────────────────────────────────────────────────────────────
|
||||
enum Source : uint8_t { SRC_STORED, SRC_SCAN };
|
||||
// List data, filter / sort / source and the refresh logic live in
|
||||
// ui-core/NearbyModel.h (shared with ui-lvgl); this class adds selection,
|
||||
// detail / navigate views, scan timing and the action menu.
|
||||
|
||||
// ── action-menu actions (matched by id, not by row index) ────────────────────
|
||||
enum Action : uint8_t { ACT_NAV, ACT_PING, ACT_WAYPOINT, ACT_LOCATOR,
|
||||
@@ -36,52 +30,11 @@ class NearbyScreen : public UIScreen {
|
||||
// startPickBotChannel()/startPickBotRoom() pick-mode idiom.
|
||||
bool _pick_admin_target = false;
|
||||
|
||||
// ── unified list entry ───────────────────────────────────────────────────────
|
||||
struct Entry {
|
||||
char name[32];
|
||||
uint8_t type;
|
||||
uint8_t pub_key[PUB_KEY_SIZE];
|
||||
// has_key: the full 32-byte pubkey is present -- what Ping and the base64
|
||||
// key view need. has_prefix: at least the leading FAVOURITE_PREFIX_LEN
|
||||
// bytes are, which is all an identity-keyed reference needs (a Locator
|
||||
// person target, resolved via UITask::resolvePersonPos). Every has_key row
|
||||
// also has_prefix; the reverse doesn't hold -- a [LOC] share and a heard
|
||||
// advert carry a prefix and nothing more.
|
||||
bool has_key;
|
||||
bool has_prefix;
|
||||
// stored-source fields
|
||||
int32_t lat_e6, lon_e6;
|
||||
float dist_km;
|
||||
uint32_t lastmod;
|
||||
int contact_idx;
|
||||
// scan-source fields
|
||||
int8_t rssi, snr_x4, remote_snr_x4;
|
||||
bool is_known;
|
||||
// live-track ([LOC] share) overlay: this row's position/age came from a
|
||||
// shared-location message. live_verified == true for a DM (pubkey) share,
|
||||
// false for a channel (name, best-effort) share.
|
||||
bool is_live;
|
||||
bool live_verified;
|
||||
// Favourite (ContactInfo::flags bit 0) -- always false for a scan/live row
|
||||
// that isn't a contact, since only a contact can carry the flag.
|
||||
bool fav;
|
||||
};
|
||||
|
||||
static const int MAX_NEARBY = 32;
|
||||
Entry _entries[MAX_NEARBY];
|
||||
int _count;
|
||||
int _sel;
|
||||
int _scroll;
|
||||
bool _detail;
|
||||
bool _nav = false; // full-screen navigate-to-node view (over detail)
|
||||
navview::EtaTracker _nav_eta; // closing-speed/ETA for the navigate view
|
||||
int32_t _own_lat, _own_lon;
|
||||
bool _own_gps;
|
||||
|
||||
Source _source;
|
||||
uint8_t _filter;
|
||||
uint8_t _sort;
|
||||
|
||||
unsigned long _detail_refresh_ms;
|
||||
unsigned long _list_refresh_ms = 0;
|
||||
static const unsigned long DETAIL_REFRESH_MS = 10000UL;
|
||||
@@ -137,90 +90,15 @@ class NearbyScreen : public UIScreen {
|
||||
snprintf(buf, n, "%s ago", s);
|
||||
}
|
||||
|
||||
static const char* typeName(uint8_t t) {
|
||||
switch (t) {
|
||||
case ADV_TYPE_CHAT: return "Companion";
|
||||
case ADV_TYPE_REPEATER: return "Repeater";
|
||||
case ADV_TYPE_ROOM: return "Room";
|
||||
case ADV_TYPE_SENSOR: return "Sensor";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* typeShort(uint8_t t) {
|
||||
switch (t) {
|
||||
case ADV_TYPE_REPEATER: return "Rpt";
|
||||
case ADV_TYPE_SENSOR: return "Snsr";
|
||||
case ADV_TYPE_ROOM: return "Room";
|
||||
case ADV_TYPE_CHAT: return "Comp";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
// The selected entry, or nullptr when the list is empty.
|
||||
const Entry* selected() const {
|
||||
return (_count > 0 && _sel < _count) ? &_entries[_sel] : nullptr;
|
||||
}
|
||||
|
||||
bool typeMatchesFilter(uint8_t type, uint8_t flags, bool have_flags) const {
|
||||
switch (_filter) {
|
||||
case F_FAV: return have_flags && (flags & 0x01);
|
||||
case F_COMP: return type == ADV_TYPE_CHAT;
|
||||
case F_RPT: return type == ADV_TYPE_REPEATER;
|
||||
case F_ROOM: return type == ADV_TYPE_ROOM;
|
||||
case F_SNSR: return type == ADV_TYPE_SENSOR;
|
||||
case F_ALL:
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ── data refresh ──────────────────────────────────────────────────────────────
|
||||
void refreshStored() {
|
||||
_count = 0;
|
||||
_own_lat = _own_lon = 0;
|
||||
_own_gps = _task->currentLocation(_own_lat, _own_lon);
|
||||
|
||||
int nc = the_mesh.getNumContacts();
|
||||
for (int i = 0; i < nc && _count < MAX_NEARBY; i++) {
|
||||
ContactInfo ci;
|
||||
// getContactByIdx() indexes the RAW contact table, whose first
|
||||
// MAX_ANON_CONTACTS slots are reserved for anon-request bookkeeping
|
||||
// (see BaseChatMesh::resetContacts()/ContactsIterator) -- getNumContacts()
|
||||
// already excludes them from the count, so real contact 0 lives at raw
|
||||
// index MAX_ANON_CONTACTS, not 0. Reading from 0 pulled those reserved
|
||||
// (blank, type=ADV_TYPE_NONE) slots into the list as bogus "Unknown"
|
||||
// rows, and silently dropped the same number of real contacts off the
|
||||
// end -- while never touching the anon slots themselves, so it always
|
||||
// reproduced the same way regardless of the auto-add overwrite setting.
|
||||
if (!the_mesh.getContactByIdx(i + MAX_ANON_CONTACTS, ci)) continue;
|
||||
if (!typeMatchesFilter(ci.type, ci.flags, true)) continue;
|
||||
|
||||
Entry& e = _entries[_count++];
|
||||
strncpy(e.name, ci.name, sizeof(e.name) - 1);
|
||||
e.name[sizeof(e.name) - 1] = '\0';
|
||||
memcpy(e.pub_key, ci.id.pub_key, PUB_KEY_SIZE);
|
||||
e.has_key = true;
|
||||
e.has_prefix = true;
|
||||
e.lat_e6 = ci.gps_lat;
|
||||
e.lon_e6 = ci.gps_lon;
|
||||
bool remote_gps = (ci.gps_lat != 0 || ci.gps_lon != 0);
|
||||
e.dist_km = (_own_gps && remote_gps)
|
||||
? geo::haversineKm(_own_lat, _own_lon, ci.gps_lat, ci.gps_lon)
|
||||
: -1.0f;
|
||||
e.type = ci.type;
|
||||
e.fav = (ci.flags & 0x01) != 0;
|
||||
e.contact_idx = i + MAX_ANON_CONTACTS; // raw index -- other lookups re-key off this directly
|
||||
e.lastmod = ci.lastmod;
|
||||
e.is_known = true;
|
||||
e.is_live = false;
|
||||
e.live_verified = false;
|
||||
}
|
||||
|
||||
mergeLiveTrack();
|
||||
mergeRecentlyHeard();
|
||||
sortStored();
|
||||
clampSelection();
|
||||
}
|
||||
// ── data refresh (NearbyModel) + selection clamping ─────────────────────────
|
||||
void refreshStored() { NearbyModel::refreshStored(); clampSelection(); }
|
||||
void refreshScan() { NearbyModel::refreshScan(); clampSelection(); }
|
||||
void refresh() { refreshModel(); clampSelection(); }
|
||||
|
||||
// Rebuild the stored list (re-merge live shares + re-sort) while keeping the
|
||||
// currently highlighted node selected across the rebuild — by contact index
|
||||
@@ -236,173 +114,12 @@ class NearbyScreen : public UIScreen {
|
||||
saved_name[sizeof(saved_name) - 1] = '\0';
|
||||
}
|
||||
refreshStored();
|
||||
if (saved_idx >= 0) {
|
||||
for (int i = 0; i < _count; i++)
|
||||
if (_entries[i].contact_idx == saved_idx) { _sel = i; return true; }
|
||||
} else if (saved_live && saved_name[0]) {
|
||||
for (int i = 0; i < _count; i++)
|
||||
if (_entries[i].is_live && strncmp(_entries[i].name, saved_name, sizeof(saved_name) - 1) == 0)
|
||||
{ _sel = i; return true; }
|
||||
}
|
||||
int i = saved_idx >= 0 ? findContact(saved_idx)
|
||||
: (saved_live && saved_name[0]) ? findLiveByName(saved_name) : -1;
|
||||
if (i >= 0) { _sel = i; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
// Overlay live [LOC] shares onto the stored list: refresh a matching contact
|
||||
// with the fresher shared position, and append senders who aren't contacts so
|
||||
// a group sharing on a channel still shows up. DM shares match by pubkey
|
||||
// prefix (verified); channel shares match by name (best-effort).
|
||||
void mergeLiveTrack() {
|
||||
if (!_task) return;
|
||||
LiveTrackStore& lt = _task->liveTrack();
|
||||
uint32_t now = rtc_clock.getCurrentTime();
|
||||
for (int i = 0; i < LiveTrackStore::CAPACITY; i++) {
|
||||
if (!lt.isActive(i, now)) continue;
|
||||
const LiveTrackStore::Entry& s = lt.slotAt(i);
|
||||
|
||||
int m = -1;
|
||||
for (int j = 0; j < _count; j++) {
|
||||
if (s.verified && _entries[j].has_key
|
||||
&& memcmp(_entries[j].pub_key, s.key, LiveTrackStore::KEY_LEN) == 0) { m = j; break; }
|
||||
if (!s.verified && strncmp(_entries[j].name, s.name, sizeof(_entries[j].name) - 1) == 0) { m = j; break; }
|
||||
}
|
||||
|
||||
if (m >= 0) {
|
||||
Entry& e = _entries[m];
|
||||
// A [LOC] share is an explicit "here I am now", so it defines the pin and
|
||||
// the distance (used for proximity sorting). Recency for the time sort is
|
||||
// the most recent of the advert and the share.
|
||||
e.lat_e6 = s.lat_1e6;
|
||||
e.lon_e6 = s.lon_1e6;
|
||||
e.dist_km = _own_gps ? geo::haversineKm(_own_lat, _own_lon, s.lat_1e6, s.lon_1e6) : -1.0f;
|
||||
if (s.ts > e.lastmod) e.lastmod = s.ts;
|
||||
e.is_live = true;
|
||||
e.live_verified = s.verified;
|
||||
} else if (_count < MAX_NEARBY && typeMatchesFilter(ADV_TYPE_CHAT, 0, false)) {
|
||||
// A sender we don't have as a contact: treat it as a companion (the only
|
||||
// node type that shares position), so the type filter still applies —
|
||||
// e.g. it must not appear under the Repeater/Room/Sensor filters.
|
||||
Entry& e = _entries[_count++];
|
||||
memset(&e, 0, sizeof(e));
|
||||
strncpy(e.name, s.name, sizeof(e.name) - 1);
|
||||
e.name[sizeof(e.name) - 1] = '\0';
|
||||
// We only keep a key *prefix* for shares, not the full pubkey, so Ping
|
||||
// and the base64 key view (which need 32 bytes) stay unavailable for a
|
||||
// non-contact live entry. Navigate / Save-waypoint work off lat/lon.
|
||||
// A DM share is pubkey-keyed, so the prefix is real and good enough to
|
||||
// keep re-resolving them as a Locator person target; a channel share is
|
||||
// matched by name and carries no identity at all.
|
||||
e.has_key = false;
|
||||
e.has_prefix = s.verified;
|
||||
if (s.verified) memcpy(e.pub_key, s.key, LiveTrackStore::KEY_LEN);
|
||||
e.type = ADV_TYPE_CHAT;
|
||||
e.lat_e6 = s.lat_1e6;
|
||||
e.lon_e6 = s.lon_1e6;
|
||||
e.dist_km = _own_gps ? geo::haversineKm(_own_lat, _own_lon, s.lat_1e6, s.lon_1e6) : -1.0f;
|
||||
e.lastmod = s.ts;
|
||||
e.contact_idx = -1;
|
||||
e.is_known = false;
|
||||
e.is_live = true;
|
||||
e.live_verified = s.verified;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fold passively-heard adverts that aren't already listed (contact or live) into
|
||||
// the list as name+age rows — no full key/GPS, so informational only. This is
|
||||
// what absorbs the old standalone "Recent adverts" home page. Gated to the All
|
||||
// filter because AdvertPath carries no node type to filter or sort-by-dist on.
|
||||
void mergeRecentlyHeard() {
|
||||
if (_filter != F_ALL || !_task) return;
|
||||
static AdvertPath heard[8]; // scratch — refreshStored isn't reentrant
|
||||
int n = the_mesh.getRecentlyHeard(heard, 8);
|
||||
for (int i = 0; i < n && _count < MAX_NEARBY; i++) {
|
||||
AdvertPath& a = heard[i];
|
||||
if (a.name[0] == 0) continue;
|
||||
bool dup = false;
|
||||
for (int j = 0; j < _count; j++) {
|
||||
if (_entries[j].has_key &&
|
||||
memcmp(_entries[j].pub_key, a.pubkey_prefix, sizeof(a.pubkey_prefix)) == 0) { dup = true; break; }
|
||||
if (strncmp(_entries[j].name, a.name, sizeof(a.name) - 1) == 0) { dup = true; break; }
|
||||
}
|
||||
if (dup) continue;
|
||||
Entry& e = _entries[_count++];
|
||||
memset(&e, 0, sizeof(e));
|
||||
strncpy(e.name, a.name, sizeof(e.name) - 1);
|
||||
e.name[sizeof(e.name) - 1] = '\0';
|
||||
e.type = ADV_TYPE_CHAT; // unknown from AdvertPath — best-effort label
|
||||
e.has_key = false;
|
||||
e.has_prefix = true;
|
||||
memcpy(e.pub_key, a.pubkey_prefix, sizeof(a.pubkey_prefix));
|
||||
e.dist_km = -1.0f;
|
||||
e.lastmod = a.recv_timestamp;
|
||||
e.contact_idx = -1;
|
||||
e.is_known = false;
|
||||
e.is_live = false;
|
||||
}
|
||||
}
|
||||
|
||||
void sortStored() {
|
||||
uint32_t now_ts = rtc_clock.getCurrentTime();
|
||||
NodePrefs* p = _task->getNodePrefs();
|
||||
const bool fav_first = !(p && p->fav_sort_off);
|
||||
for (int i = 0; i < _count - 1; i++) {
|
||||
int best = i;
|
||||
for (int j = i + 1; j < _count; j++) {
|
||||
if (fav_first && _entries[j].fav != _entries[best].fav) {
|
||||
if (_entries[j].fav) best = j; // favourites outrank the time/distance key
|
||||
continue;
|
||||
}
|
||||
if (_sort == SORT_TIME) {
|
||||
// lastmod=0 or lastmod>now (RTC not synced) → "unknown" → sort to bottom.
|
||||
uint32_t tj = (_entries[j].lastmod > 0 && now_ts >= _entries[j].lastmod) ? _entries[j].lastmod : 0;
|
||||
uint32_t tb = (_entries[best].lastmod > 0 && now_ts >= _entries[best].lastmod) ? _entries[best].lastmod : 0;
|
||||
if (tj > 0 && (tb == 0 || tj > tb)) best = j; // descending — most recent first
|
||||
} else {
|
||||
float dj = _entries[j].dist_km, db = _entries[best].dist_km;
|
||||
if (dj >= 0.0f && (db < 0.0f || dj < db)) best = j; // ascending — closest first
|
||||
}
|
||||
}
|
||||
if (best != i) { Entry tmp = _entries[i]; _entries[i] = _entries[best]; _entries[best] = tmp; }
|
||||
}
|
||||
}
|
||||
|
||||
void refreshScan() {
|
||||
static DiscoverResult dr[DISCOVER_RESULTS_MAX]; // scratch — refresh isn't reentrant
|
||||
int n = the_mesh.getDiscoverResults(dr, DISCOVER_RESULTS_MAX);
|
||||
_count = 0;
|
||||
for (int i = 0; i < n && _count < MAX_NEARBY; i++) {
|
||||
if (!typeMatchesFilter(dr[i].type, 0, false)) continue;
|
||||
Entry& e = _entries[_count++];
|
||||
strncpy(e.name, dr[i].name, sizeof(e.name) - 1);
|
||||
e.name[sizeof(e.name) - 1] = '\0';
|
||||
e.type = dr[i].type;
|
||||
memcpy(e.pub_key, dr[i].pub_key, PUB_KEY_SIZE);
|
||||
e.has_key = true;
|
||||
e.has_prefix = true;
|
||||
e.rssi = dr[i].rssi;
|
||||
e.snr_x4 = dr[i].snr_x4;
|
||||
e.remote_snr_x4 = dr[i].remote_snr_x4;
|
||||
e.is_known = dr[i].is_known;
|
||||
e.fav = false;
|
||||
e.lat_e6 = e.lon_e6 = 0;
|
||||
e.dist_km = -1.0f;
|
||||
e.lastmod = 0;
|
||||
e.contact_idx = -1;
|
||||
e.is_live = false;
|
||||
e.live_verified = false;
|
||||
}
|
||||
// strongest first
|
||||
for (int i = 0; i < _count - 1; i++) {
|
||||
int best = i;
|
||||
for (int j = i + 1; j < _count; j++)
|
||||
if (_entries[j].rssi > _entries[best].rssi) best = j;
|
||||
if (best != i) { Entry tmp = _entries[i]; _entries[i] = _entries[best]; _entries[best] = tmp; }
|
||||
}
|
||||
clampSelection();
|
||||
}
|
||||
|
||||
void refresh() { if (_source == SRC_SCAN) refreshScan(); else refreshStored(); }
|
||||
|
||||
void clampSelection() {
|
||||
if (_count == 0) { _sel = _scroll = 0; }
|
||||
else if (_sel >= _count) { _sel = _count - 1; if (_scroll > _sel) _scroll = _sel; }
|
||||
@@ -804,17 +521,16 @@ class NearbyScreen : public UIScreen {
|
||||
// side and wrap around (the tab before "All" is "Snsr", and vice-versa),
|
||||
// matching the wrap-around LEFT/RIGHT cycle.
|
||||
void drawFilterTabs(DisplayDriver& display) {
|
||||
tabbar::draw(display, FILTER_LABELS, F_COUNT, _filter, display.menuHintWidth());
|
||||
tabbar::draw(display, filterLabels(), F_COUNT, _filter, display.menuHintWidth());
|
||||
display.drawContextMenuHint(DisplayDriver::LIGHT, ctxMenuOpen()); // Nodes list has a Hold-Enter menu
|
||||
}
|
||||
|
||||
public:
|
||||
NearbyScreen(UITask* task)
|
||||
: _task(task), _count(0), _sel(0), _scroll(0), _detail(false),
|
||||
_own_lat(0), _own_lon(0), _own_gps(false),
|
||||
_source(SRC_STORED), _filter(F_ALL), _sort(SORT_DIST),
|
||||
: _task(task), _sel(0), _scroll(0), _detail(false),
|
||||
_detail_refresh_ms(0), _scanning(false), _scan_started_ms(0),
|
||||
_menu_action_count(0), _pinging(false), _ping_started_ms(0) {
|
||||
bindModel(&task->core(), task->getNodePrefs());
|
||||
resetPingLines();
|
||||
_sort_label[0] = '\0';
|
||||
}
|
||||
@@ -895,7 +611,7 @@ public:
|
||||
int dist_col = display.width() - display.getCharWidth() * 7;
|
||||
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
const char* flt = (_filter != F_ALL) ? FILTER_LABELS[_filter] : nullptr;
|
||||
const char* flt = (_filter != F_ALL) ? filterLabel(_filter) : nullptr;
|
||||
if (_source == SRC_SCAN) {
|
||||
char title[28];
|
||||
const char* base = _scanning ? "SCANNING" : "SCAN";
|
||||
@@ -1056,4 +772,3 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
const char* NearbyScreen::FILTER_LABELS[F_COUNT] = { "All", "Fav", "Comp", "Rpt", "Room", "Snsr" };
|
||||
|
||||
@@ -167,6 +167,7 @@ static const int QUICK_MSGS_MAX = 10;
|
||||
#include "RingtoneEditorScreen.h"
|
||||
#include "BotScreen.h"
|
||||
#include "AdminScreen.h"
|
||||
#include "../ui-core/NearbyModel.h"
|
||||
#include "NearbyScreen.h"
|
||||
#include "DashboardConfigScreen.h"
|
||||
#include "AutoAdvertScreen.h"
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
ui-lvgl simulator: the Wio Tracker L2 frontend (320x240 touch LCD) running
|
||||
the real companion firmware in the browser, plus one ui-new peer device on a
|
||||
direct simulated link so there is someone to talk to.
|
||||
the real companion firmware in the browser, plus one ui-new peer device and
|
||||
one repeater on a shared simulated link, so there is someone to talk to and
|
||||
something for Nearby > Scan to find.
|
||||
|
||||
Build both, then serve this directory (http://, not file://):
|
||||
variants/sim/build_wasm.sh # peer -> build/meshcore_sim.js
|
||||
variants/sim/build_wasm_repeater.sh # repeater (optional; page runs without it)
|
||||
SIM_UI=lvgl variants/sim/build_wasm.sh # L2 -> build/meshcore_sim_lvgl.js
|
||||
cd variants/sim/web && python3 -m http.server 8080
|
||||
and open http://localhost:8080/lvgl.html .
|
||||
@@ -74,7 +76,7 @@
|
||||
<div class="row">
|
||||
<button id="peer-dm">Peer → DM to L2</button>
|
||||
<button id="peer-ch">Peer → Public</button>
|
||||
<button id="advert">Advert both</button>
|
||||
<button id="advert">Advert all</button>
|
||||
</div>
|
||||
<div id="log"></div>
|
||||
</div>
|
||||
@@ -82,6 +84,7 @@
|
||||
|
||||
<script src="build/meshcore_sim.js"></script>
|
||||
<script src="build/meshcore_sim_lvgl.js"></script>
|
||||
<script src="build/repeater/meshcore_sim_repeater.js" onerror="window.MeshCoreSimRepeater = null"></script>
|
||||
<script>
|
||||
const logEl = document.getElementById('log');
|
||||
function log(msg) {
|
||||
@@ -116,13 +119,14 @@
|
||||
};
|
||||
}
|
||||
|
||||
let L = null, P = null;
|
||||
let L = null, P = null, R = null;
|
||||
|
||||
// Direct link L <-> P, 50 ms air time.
|
||||
// Everyone hears everyone, 50 ms air time.
|
||||
setInterval(() => {
|
||||
if (!L || !P) return;
|
||||
for (const [from, to] of [[L, P], [P, L]]) {
|
||||
for (const pkt of from.pollTx()) setTimeout(() => to.injectRx(pkt), 50);
|
||||
const nodes = [L, P, R].filter(Boolean);
|
||||
for (const from of nodes) {
|
||||
for (const pkt of from.pollTx())
|
||||
for (const to of nodes) if (to !== from) setTimeout(() => to.injectRx(pkt), 50);
|
||||
}
|
||||
}, 40);
|
||||
|
||||
@@ -158,10 +162,19 @@
|
||||
return ok;
|
||||
}
|
||||
|
||||
async function bootR() {
|
||||
if (!window.MeshCoreSimRepeater) { log('repeater build not found (optional)'); return false; }
|
||||
R = wrap(await MeshCoreSimRepeater({ simInstanceTag: 'R' }), 'R');
|
||||
const ok = await waitReady(R);
|
||||
log(ok ? 'repeater up' : 'repeater boot timed out');
|
||||
return ok;
|
||||
}
|
||||
|
||||
function advertBoth() {
|
||||
L.call('sim_test_advert_flood', 'number');
|
||||
setTimeout(() => P.call('sim_test_advert_flood', 'number'), 300);
|
||||
log('advert: both');
|
||||
if (R) setTimeout(() => R.call('sim_test_advert_flood', 'number'), 600);
|
||||
log('advert: all');
|
||||
}
|
||||
|
||||
// ── Touch: mouse / pen / finger on the LCD canvas ─────────────────────
|
||||
@@ -202,6 +215,7 @@
|
||||
});
|
||||
|
||||
const ready = (async () => {
|
||||
await bootR();
|
||||
const [okP, okL] = [await bootP(), await bootL()];
|
||||
if (okP && okL) { advertBoth(); log('both devices up'); }
|
||||
return okP && okL;
|
||||
|
||||
Reference in New Issue
Block a user