fix(v4-r8): improve touch and text accessibility
This commit is contained in:
1 parent
bf114b4618
commit
eb4b71fb67
8 files changed
+108
-30
No files matched your search
@@ -48,6 +48,8 @@ USB) and the [GitHub releases](https://github.com/ALLFATHER-BV/wadamesh/releases
|
||||
CardKB at address `0x5F` on the board I2C bus (GPIO4/3 on V4, GPIO17/18 on
|
||||
V4-R8). It provides text and focus navigation; the on-screen keyboard remains
|
||||
available when CardKB is absent or when the active field is tapped again.
|
||||
V4-R8 also offers font-only Normal, Large and Huge text presets under Display;
|
||||
controls retain their normal geometry so the compact screen stays navigable.
|
||||
- **Tanmatsu**: keyboard-driven UI (no touchscreen) with the coloured function
|
||||
keys mapped to tabs, ALT accent picker, UI scaling (Normal/Large/Huge),
|
||||
microSD for all persistent data. Ships through the Tanmatsu launcher store,
|
||||
|
||||
+4
-5
@@ -56,11 +56,10 @@
|
||||
#define LV_FONT_MONTSERRAT_12 1
|
||||
#define LV_FONT_MONTSERRAT_14 1
|
||||
#define LV_FONT_MONTSERRAT_16 1
|
||||
/* Larger Montserrat sizes for the large-screen boards' crisp "UI size" (Large/Huge) — render the
|
||||
* UI bigger at native resolution instead of upscaling a low-res frame. Gated to the CAP_LARGE_SCREEN
|
||||
* P4 boards (Tanmatsu + T-Display P4) so the flash-tighter S3 touch builds don't pay for fonts they
|
||||
* never use. (device_caps.h isn't included here, so match on the board macros directly.) */
|
||||
#if defined(HAS_TANMATSU) || defined(HAS_TDISPLAY_P4)
|
||||
/* Larger Montserrat sizes for crisp UI/text-size presets at native resolution. The P4 boards scale
|
||||
* text and geometry; V4-R8 uses the same fonts without geometry scaling. Other flash-tighter S3
|
||||
* builds don't pay for fonts they never use. (Match board macros because device_caps.h isn't here.) */
|
||||
#if defined(HAS_TANMATSU) || defined(HAS_TDISPLAY_P4) || defined(HELTEC_LORA_V4_R8)
|
||||
#define LV_FONT_MONTSERRAT_18 1
|
||||
#define LV_FONT_MONTSERRAT_20 1
|
||||
#define LV_FONT_MONTSERRAT_24 1
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace TouchPrefsSchema {
|
||||
|
||||
static constexpr uint16_t MAGIC = 0x5743; // 'WC' (WadaCfg)
|
||||
static constexpr uint8_t CURRENT_VERSION = 62; // v49: fem_lna default flip on the V4-R8; v50: map tile z/x/y line off by default (no new fields); v51: console_mode (boot into the text console; new trailing field, default OFF); v52: console_monitor (show incoming messages in the console, default ON); v54: boot_wifi_time + boot_wifi_open (cold-boot saved-Wi-Fi time sync, #383; both OFF); v55: loud_alerts (resonant-pitch chime, #388; OFF); v56: theme_mode (Day/Night firmware theme, #296; default Night); v57: gps_fuzz_m (displace the advertised position, #399; 0 = off); v58: Attaky notification blink enable + room/DM color indexes (#423); v59: telem_loc_exact (answer position requests from chosen contacts with the REAL fix instead of the advert displacement; 0 = keep it displaced); v60: home_key_keeps_drawer (#491; default OFF); v61: ble_kbd_* (Bluetooth serves a keyboard instead of the phone app, its layout and the paired keyboard; default phone app); v62: ble_kbd_back (a second key that acts as Back; 0 = only Esc)
|
||||
static constexpr uint8_t CURRENT_VERSION = 63; // v49: fem_lna default flip on the V4-R8; v50: map tile z/x/y line off by default (no new fields); v51: console_mode (boot into the text console; new trailing field, default OFF); v52: console_monitor (show incoming messages in the console, default ON); v54: boot_wifi_time + boot_wifi_open (cold-boot saved-Wi-Fi time sync, #383; both OFF); v55: loud_alerts (resonant-pitch chime, #388; OFF); v56: theme_mode (Day/Night firmware theme, #296; default Night); v57: gps_fuzz_m (displace the advertised position, #399; 0 = off); v58: Attaky notification blink enable + room/DM color indexes (#423); v59: telem_loc_exact (answer position requests from chosen contacts with the REAL fix instead of the advert displacement; 0 = keep it displaced); v60: home_key_keeps_drawer (#491; default OFF); v61: ble_kbd_* (Bluetooth serves a keyboard instead of the phone app, its layout and the paired keyboard; default phone app); v62: ble_kbd_back (a second key that acts as Back; 0 = only Esc); v63: V4-R8 ui_scale reset before exposing font-only presets (#536)
|
||||
static constexpr uint8_t BROKEN_MID_INSERT_VERSION = 44;
|
||||
|
||||
// Persisted byte layout. New fields must be appended at the end: older blobs
|
||||
|
||||
@@ -112,8 +112,8 @@ static void cfgSetDefaults(TouchCfg& c) {
|
||||
c.map_show_tilexyz = 0; // v50: the "z12 12/2105/1376" tile-path line is developer clutter on the map; opt-in via Map options
|
||||
c.map_show_contacts = 1;
|
||||
c.app_grid_large = 0; // default: compact app grid (T-Deck 4 cols / V4 3 cols)
|
||||
#if defined(TLORA_PAGER)
|
||||
c.ui_scale = 0; // Pager: Small/current typography by default
|
||||
#if defined(TLORA_PAGER) || defined(HELTEC_LORA_V4_R8)
|
||||
c.ui_scale = 0; // Font-only presets start at the existing typography.
|
||||
#else
|
||||
c.ui_scale = 1; // large-screen boards keep their existing 150% default
|
||||
#endif
|
||||
@@ -280,6 +280,11 @@ static void cfgLoadOrMigrate() {
|
||||
memset(s_cfg.ble_kbd_name, 0, sizeof s_cfg.ble_kbd_name);
|
||||
}
|
||||
if (stored_version < 62) s_cfg.ble_kbd_back = 0; // only Esc goes back
|
||||
#if defined(HELTEC_LORA_V4_R8)
|
||||
// ui_scale existed before the R8 exposed a selector and inherited the
|
||||
// unrelated large-screen default. Preserve its current appearance once.
|
||||
if (stored_version < 63) s_cfg.ui_scale = 0;
|
||||
#endif
|
||||
if (stored_version < 58) {
|
||||
s_cfg.attaky_notify_enabled = 0;
|
||||
s_cfg.attaky_notify_room_color = 0;
|
||||
|
||||
@@ -163,7 +163,8 @@ bool touchPrefsGetSleepIdle();
|
||||
bool touchPrefsSetSleepIdle(bool on);
|
||||
|
||||
/* UI-size preset. Large-screen boards retain their 0..2 percentage mapping;
|
||||
* the T-Pager exposes four 0..3 semantic font presets. Reboot to apply. */
|
||||
* V4-R8 uses 0..2 font-only presets, and T-Pager uses four 0..3 semantic font
|
||||
* presets. Reboot to apply. */
|
||||
uint8_t touchPrefsGetUiScale();
|
||||
bool touchPrefsSetUiScale(uint8_t scale);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
// own title and close button UNDERNEATH the real status bar with no reachable exit. Going
|
||||
// through here instead means a page can never disagree with the bar about its own height.
|
||||
|
||||
/** y of the first usable content row: immediately under the (possibly tall) status bar. */
|
||||
/** y of the first usable content row below the target's reserved status-bar area. */
|
||||
lv_coord_t appPageContentTop();
|
||||
|
||||
/** Usable content height below the status bar. */
|
||||
|
||||
+88
-17
@@ -910,6 +910,28 @@ static void initTouchFontFallbacks() {
|
||||
break;
|
||||
}
|
||||
g_font_tab = lv_font_montserrat_16;
|
||||
#elif defined(HELTEC_LORA_V4_R8)
|
||||
// Accessible semantic text without scaling 240x320 geometry. Rows, cards and
|
||||
// controls retain their established dimensions and remain scrollable.
|
||||
s_ui_fscale = 100;
|
||||
switch (touchPrefsGetUiScale()) {
|
||||
case 1:
|
||||
g_font_12 = lv_font_montserrat_16;
|
||||
g_font_14 = lv_font_montserrat_18;
|
||||
g_font_16 = lv_font_montserrat_20;
|
||||
break;
|
||||
case 2:
|
||||
g_font_12 = lv_font_montserrat_18;
|
||||
g_font_14 = lv_font_montserrat_20;
|
||||
g_font_16 = lv_font_montserrat_24;
|
||||
break;
|
||||
default:
|
||||
g_font_12 = lv_font_montserrat_12;
|
||||
g_font_14 = lv_font_montserrat_14;
|
||||
g_font_16 = lv_font_montserrat_16;
|
||||
break;
|
||||
}
|
||||
g_font_tab = lv_font_montserrat_16;
|
||||
#elif CAP_LARGE_SCREEN
|
||||
// Crisp "UI size": render bigger by swapping in larger built-in Montserrat fonts (NOT by
|
||||
// upscaling a low-res frame). g_font_12/14/16 are what the whole UI draws with, so this scales
|
||||
@@ -1708,9 +1730,17 @@ static inline lv_coord_t statusBarCurH() { return STATUSBAR_H; }
|
||||
#else
|
||||
static inline lv_coord_t statusBarCurH() { return s_statusbar_tall ? (lv_coord_t)(STATUSBAR_H * 2) : STATUSBAR_H; }
|
||||
#endif
|
||||
#if defined(HELTEC_LORA_V4_R8)
|
||||
static void r8ResizeContentBelowStatusBar(lv_coord_t top);
|
||||
#endif
|
||||
static void statusBarSetTall(bool tall) {
|
||||
s_statusbar_tall = tall;
|
||||
if (g_statusbar.root) lv_obj_set_height(g_statusbar.root, statusBarCurH());
|
||||
#if defined(HELTEC_LORA_V4_R8)
|
||||
// R8 portrait mapping is identity, but a tall clickable bar used to cover the
|
||||
// first row of the tab view. Keep visible content below its live hitbox.
|
||||
r8ResizeContentBelowStatusBar(statusBarCurH());
|
||||
#endif
|
||||
// (updateGlobalStatusBar drives this every tick + refreshes the left zone; it must
|
||||
// NOT be called from here — it calls back into statusBarSetTall = recursion.)
|
||||
}
|
||||
@@ -1721,8 +1751,18 @@ void reserveTileFetchStack(); // fwd: claim the worker stack before Wi-Fi eats
|
||||
// Thin wrappers over the machinery just above, exported so the self-contained app
|
||||
// modules (SnakeGame) build the same page as the in-file tool
|
||||
// pages instead of hand-rolling it against a hardcoded bar height.
|
||||
lv_coord_t appPageContentTop() { return STATUSBAR_H; }
|
||||
lv_coord_t appPageContentH() { return (lv_coord_t)(lv_disp_get_ver_res(nullptr) - STATUSBAR_H); }
|
||||
lv_coord_t appPageContentTop() {
|
||||
#if defined(HELTEC_LORA_V4_R8)
|
||||
// appPageCreateRoot() runs before appPageBegin(), so reserve the height the
|
||||
// latter is about to activate rather than reading the current one-row state.
|
||||
return (lv_coord_t)(STATUSBAR_H * 2);
|
||||
#else
|
||||
return STATUSBAR_H;
|
||||
#endif
|
||||
}
|
||||
lv_coord_t appPageContentH() {
|
||||
return (lv_coord_t)(lv_disp_get_ver_res(nullptr) - appPageContentTop());
|
||||
}
|
||||
|
||||
lv_obj_t* appPageCreateRoot(uint32_t bg_color) {
|
||||
lv_obj_t* root = lv_obj_create(lv_layer_top());
|
||||
@@ -2000,8 +2040,8 @@ static inline lv_coord_t chatBarH() { return STATUSBAR_H; }
|
||||
#else
|
||||
static inline lv_coord_t chatBarH() { return (lv_coord_t)(STATUSBAR_H * 2); }
|
||||
#endif
|
||||
#if defined(HAS_TDECK_PRO)
|
||||
// E-paper cannot render the glass title row cleanly, so chat content starts below it.
|
||||
#if defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8)
|
||||
// E-paper and R8 content start below the complete status-bar hitbox.
|
||||
static inline lv_coord_t chatContentTop(){ return chatBarH(); }
|
||||
#else
|
||||
static inline lv_coord_t chatContentTop(){ return STATUSBAR_H; }
|
||||
@@ -2634,6 +2674,19 @@ static uint16_t* s_scale_buf = nullptr; // upscale s
|
||||
// ---- Global UI state instance ----
|
||||
LvUiState g_lv = {};
|
||||
|
||||
#if defined(HELTEC_LORA_V4_R8)
|
||||
static void r8ResizeContentBelowStatusBar(lv_coord_t top) {
|
||||
if (!g_lv.tabview) return;
|
||||
lv_obj_set_pos(g_lv.tabview, 0, top);
|
||||
lv_obj_set_size(g_lv.tabview, lv_disp_get_hor_res(nullptr),
|
||||
lv_disp_get_ver_res(nullptr) - top);
|
||||
if (g_lv.dm.list_cont) {
|
||||
lv_obj_set_size(g_lv.dm.list_cont, lv_disp_get_hor_res(nullptr),
|
||||
lv_disp_get_ver_res(nullptr) - top - TABBAR_H);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/** If `cp` has no glyph in `font`, show '*' instead of LVGL's missing-glyph box. Preserves \\n \\r \\t. */
|
||||
static bool uiFontHasGlyph(const lv_font_t* font, uint32_t cp) {
|
||||
if (!font) return true;
|
||||
@@ -14862,6 +14915,8 @@ static void buildDeviceSettings(int sec) {
|
||||
lv_obj_t* dd = lv_dropdown_create(body);
|
||||
#if defined(TLORA_PAGER)
|
||||
lv_dropdown_set_options(dd, TR("Small\nMedium\nLarge\nJumbo"));
|
||||
#elif defined(HELTEC_LORA_V4_R8)
|
||||
lv_dropdown_set_options(dd, TR("Normal\nLarge text\nHuge text"));
|
||||
#else
|
||||
lv_dropdown_set_options(dd, TR("Normal (100%)\nLarge (150%)\nHuge (200%)"));
|
||||
#endif
|
||||
@@ -27496,7 +27551,11 @@ static void openFileTransferPage() {
|
||||
|
||||
const lv_coord_t sw = lv_disp_get_hor_res(nullptr);
|
||||
s_file_transfer_root = appPageCreateRoot(COLOR_BG);
|
||||
#if defined(HELTEC_LORA_V4_R8)
|
||||
lv_obj_set_style_pad_top(s_file_transfer_root, 10, LV_PART_MAIN);
|
||||
#else
|
||||
lv_obj_set_style_pad_top(s_file_transfer_root, STATUSBAR_H + 10, LV_PART_MAIN);
|
||||
#endif
|
||||
lv_obj_set_style_pad_left(s_file_transfer_root, 14, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_right(s_file_transfer_root, 14, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_bottom(s_file_transfer_root, 14, LV_PART_MAIN);
|
||||
@@ -35544,7 +35603,8 @@ static void makeChatDetail(LvChatPanel& p) {
|
||||
p.overlay = lv_obj_create(lv_scr_act());
|
||||
lv_obj_set_size(p.overlay, chatScreenW(), chatScreenH());
|
||||
// Most boards start below the solid row and let the glass title row overlap the
|
||||
// list. T-Deck Pro starts below both rows because e-paper needs opaque separation.
|
||||
// list. T-Deck Pro and R8 start below both rows: e-paper needs opaque separation,
|
||||
// while R8 must not show tappable content beneath the bar's touch hitbox.
|
||||
lv_obj_set_pos(p.overlay, 0, chatContentTop());
|
||||
styleSurface(p.overlay, COLOR_BG, 0);
|
||||
lv_obj_set_style_pad_all(p.overlay, 0, LV_PART_MAIN); // prevent child-position offset
|
||||
@@ -35577,7 +35637,7 @@ static void makeChatDetail(LvChatPanel& p) {
|
||||
// The status bar's glass lower row floats over the TOP of the list on boards
|
||||
// with a two-row chat header. Pager keeps the chat header in one regular row,
|
||||
// so retaining that old row-sized inset only wastes message space.
|
||||
#if defined(TLORA_PAGER) || defined(HAS_TDECK_PRO)
|
||||
#if defined(TLORA_PAGER) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8)
|
||||
lv_obj_set_style_pad_top(p.msgs, 6, LV_PART_MAIN);
|
||||
#else
|
||||
lv_obj_set_style_pad_top(p.msgs, STATUSBAR_H + 6, LV_PART_MAIN);
|
||||
@@ -35623,7 +35683,7 @@ static void makeChatDetail(LvChatPanel& p) {
|
||||
lv_obj_set_style_border_width(p.jump_oldest_btn, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_width(p.jump_oldest_btn, 0, LV_PART_MAIN);
|
||||
lv_obj_set_ext_click_area(p.jump_oldest_btn, 6);
|
||||
#if defined(HAS_TDECK_PRO)
|
||||
#if defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8)
|
||||
lv_obj_set_pos(p.jump_oldest_btn, chatScreenW() - 28, CHAT_HDR_H + 2);
|
||||
#else
|
||||
lv_obj_set_pos(p.jump_oldest_btn, chatScreenW() - 28, CHAT_HDR_H + STATUSBAR_H + 2);
|
||||
@@ -36462,20 +36522,25 @@ static void openSettingsCategory(int cat) {
|
||||
const lv_coord_t sw = lv_disp_get_hor_res(nullptr);
|
||||
const lv_coord_t sh = lv_disp_get_ver_res(nullptr);
|
||||
|
||||
// On the BASE screen layer (like the chat overlay), so the status bar — which lives on
|
||||
// lv_layer_top above it — paints its glass lower row OVER this sheet and the page
|
||||
// content scrolls UNDER the bar. (On lv_layer_top the sheet would sit above the bar and
|
||||
// the glass would reveal the settings landing behind the bar instead of this page.)
|
||||
// On the BASE screen layer (like the chat overlay), so the status bar remains
|
||||
// above it. The R8 keeps the entire sheet below the bar's live touch hitbox.
|
||||
lv_obj_t* root = lv_obj_create(lv_scr_act());
|
||||
lv_obj_remove_style_all(root);
|
||||
// Settings detail pages use a DOUBLE-height status bar (its back chevron + title become
|
||||
// a tall title bar). Set the category first so the bar paints the title + goes tall.
|
||||
// The sheet starts under the SOLID top row (STATUSBAR_H); the page insets its top by
|
||||
// the glass lower-row height so content rests below the bar but scrolls under it.
|
||||
// Most boards start under the solid row and inset the page below the glass row.
|
||||
// R8 starts the sheet itself below both rows so no visible content is untappable.
|
||||
s_settings_open_cat = cat;
|
||||
statusBarSetTall(true);
|
||||
lv_obj_set_size(root, sw, sh - STATUSBAR_H);
|
||||
lv_obj_set_pos(root, 0, STATUSBAR_H);
|
||||
#if defined(HELTEC_LORA_V4_R8)
|
||||
const lv_coord_t settings_top = statusBarCurH();
|
||||
const lv_coord_t settings_pad_top = 8;
|
||||
#else
|
||||
const lv_coord_t settings_top = STATUSBAR_H;
|
||||
const lv_coord_t settings_pad_top = STATUSBAR_H + 8;
|
||||
#endif
|
||||
lv_obj_set_size(root, sw, sh - settings_top);
|
||||
lv_obj_set_pos(root, 0, settings_top);
|
||||
styleSurface(root, COLOR_BG, 0);
|
||||
lv_obj_set_style_pad_all(root, 0, LV_PART_MAIN);
|
||||
lv_obj_clear_flag(root, LV_OBJ_FLAG_SCROLLABLE);
|
||||
@@ -36484,9 +36549,9 @@ static void openSettingsCategory(int cat) {
|
||||
|
||||
lv_obj_t* page = lv_obj_create(root);
|
||||
lv_obj_set_pos(page, 0, 0);
|
||||
lv_obj_set_size(page, sw, sh - STATUSBAR_H);
|
||||
lv_obj_set_size(page, sw, sh - settings_top);
|
||||
prepSettingsPage(page);
|
||||
lv_obj_set_style_pad_top(page, STATUSBAR_H + 8, LV_PART_MAIN); // clear the glass lower bar row
|
||||
lv_obj_set_style_pad_top(page, settings_pad_top, LV_PART_MAIN);
|
||||
|
||||
resetSettingsModalState();
|
||||
s_settings_page = page;
|
||||
@@ -58126,6 +58191,12 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
STATUSBAR_H = SB_TOP_PAD + SB_ROW * 2; // top safe-area + two rows (round phone panel)
|
||||
#else
|
||||
STATUSBAR_H = SC(22); // grow the status bar to fit bigger text at Large/Huge (no-op at 100%)
|
||||
#if defined(HELTEC_LORA_V4_R8)
|
||||
// Geometry stays fixed for R8 text presets, but Huge's 20 px title role
|
||||
// needs two extra pixels to avoid clipping regular one-row status text.
|
||||
const lv_coord_t text_bar_h = lv_font_get_line_height(&g_font_14) + 4;
|
||||
if (STATUSBAR_H < text_bar_h) STATUSBAR_H = text_bar_h;
|
||||
#endif
|
||||
#endif
|
||||
// Allocate the draw buffer in PSRAM so the ~12 KB it costs comes out of
|
||||
// the 8 MB external RAM instead of the 320 KB internal DRAM that WiFi
|
||||
|
||||
@@ -181,9 +181,9 @@
|
||||
#endif
|
||||
|
||||
// Persisted, restart-to-apply UI-size selector. Large-screen boards already
|
||||
// expose it; the Pager adds font-only presets because its 480x222 viewport is
|
||||
// wide enough for larger type but too short for global geometry scaling.
|
||||
#if CAP_LARGE_SCREEN || defined(TLORA_PAGER)
|
||||
// expose it; the Pager and V4-R8 add font-only presets because their compact
|
||||
// viewports cannot safely take global geometry scaling.
|
||||
#if CAP_LARGE_SCREEN || defined(TLORA_PAGER) || defined(HELTEC_LORA_V4_R8)
|
||||
#define CAP_UI_SIZE 1
|
||||
#else
|
||||
#define CAP_UI_SIZE 0
|
||||
|
||||
Reference in new issue
Block a user