From b9a96ca26d08c1434e9a969fea2a774b3e7e97e2 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 11 Oct 2026 00:32:27 +0200 Subject: [PATCH] UX improvements (#686) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduce "side" mode for system bar, versus classic statusbar on top with launcher bar below - Automatic system bar mode detection with override by Kconfig/device.properties and secondary override by user via Appereance settings app - Open a quick-settings menu from the status bar for available Wi-Fi, Bluetooth, GPS, and power controls. - Apps can display overlays with backdrop or Escape-key dismissal. - Added focus-container support and improved keyboard navigation, including Fn+Enter on Cardputer devices. - Power-off controls are available on supported device cards. - Updated status-bar layouts, simulator display dimensions, and toolbar navigation styling. - I²C scanning now supports selecting individual buses to rescan. - SD-card mount status is no longer shown in the status bar. --- .claude/rules/lvgl.md | 18 ++ .gitignore | 7 +- .gitmodules | 3 + Buildscripts/release-sdk-modules.txt | 1 + .../fonts/MaterialSymbolsRounded.codepoints | 1 + Data/system/fonts/MaterialSymbolsRounded.ttf | Bin 19880 -> 20192 bytes Devices/cl32-v02-v03/cl32-v02-v03.dts | 15 +- Devices/cl32-v02-v03/device.properties | 1 + Devices/cl32-v04/cl32-v04.dts | 15 +- Devices/cl32-v04/device.properties | 1 + .../guition,jc1060p470ciwy.dts | 1 - Devices/lilygo-tlora-pager/device.properties | 1 - .../m5stack-cardputer-adv/device.properties | 3 + Devices/m5stack-cardputer/device.properties | 3 + .../m5stack-stickc-plus2/device.properties | 3 + Devices/m5stack-sticks3/device.properties | 3 + Devices/m5stack-tab5/m5stack,tab5.dts | 1 - Devices/simulator/Source/module.cpp | 2 +- .../waveshare-esp32-s3-geek/device.properties | 3 + Devices/waveshare-s3-lcd-13/device.properties | 3 + .../device.properties | 3 + .../device.properties | 3 + Documentation/ideas.md | 9 +- .../source/cardputer_keyboard.cpp | 1 + .../source/st7789_i8080.cpp | 2 +- Modules/lvgl-module/generate-icons.py | 5 + .../include/lvgl/devices/keyboard.h | 18 +- .../lvgl-module/include/lvgl/icons/names.h | 2 +- .../lvgl-module/include/lvgl/icons/shared.h | 4 + .../include/lvgl/widgets/focus_container.h | 20 ++ Modules/lvgl-module/lss | 1 + .../lvgl-module/source/devices/keyboard.cpp | 29 +- .../lvgl-module/source/grid_navigation.cpp | 36 ++- Modules/lvgl-module/source/icon_names.c | 4 + Modules/lvgl-module/source/symbols.c | 38 +++ .../source/themes/lv_theme_material.c | 39 ++- .../source/themes/lv_theme_material_mono.c | 37 ++- .../source/widgets/focus_container.cpp | 27 ++ .../lvgl-module/source/widgets/sliderbox.cpp | 4 + Modules/lvgl-module/themes/material.lss | 36 ++- Modules/lvgl-module/themes/material_mono.lss | 34 +- .../lvgl_window_manager/window_manager.h | 37 +++ .../source/module.cpp | 3 + .../source/window_manager.cpp | 130 ++++++++ Tactility/Include/Tactility/lvgl/Statusbar.h | 19 +- .../Tactility/settings/LauncherSettings.h | 61 ++++ Tactility/Kconfig | 26 ++ Tactility/Private/Tactility/app/TileGrid.h | 22 +- Tactility/Private/Tactility/lvgl/SystemBars.h | 59 ++++ Tactility/Private/Tactility/lvgl/SystemMenu.h | 11 + Tactility/Source/app/TileGrid.cpp | 196 ++++++++++-- .../appearancesettings/AppearanceSettings.cpp | 92 ++++++ .../app/apppackagelist/AppPackageList.cpp | 2 +- .../Source/app/i2cscanner/I2cScanner.cpp | 50 ++- Tactility/Source/app/launcher/Launcher.cpp | 46 +-- Tactility/Source/app/power/Power.cpp | 34 ++ Tactility/Source/app/terminal/main.cpp | 6 +- Tactility/Source/lvgl/Lvgl.cpp | 8 + Tactility/Source/lvgl/Statusbar.cpp | 297 +++++++++++++++--- Tactility/Source/lvgl/SystemBars.cpp | 194 ++++++++++++ Tactility/Source/lvgl/SystemMenu.cpp | 284 +++++++++++++++++ .../memorychecker/MemoryCheckerService.cpp | 1 - .../Source/service/statusbar/Statusbar.cpp | 51 +-- .../service/webserver/WebServerService.cpp | 1 - .../Source/settings/LauncherSettings.cpp | 138 ++++++++ .../Tests/Source/SystemBarsLayoutTest.cpp | 49 +++ device.py | 11 + 67 files changed, 2032 insertions(+), 233 deletions(-) create mode 100644 Modules/lvgl-module/include/lvgl/widgets/focus_container.h create mode 160000 Modules/lvgl-module/lss create mode 100644 Modules/lvgl-module/source/widgets/focus_container.cpp create mode 100644 Tactility/Include/Tactility/settings/LauncherSettings.h create mode 100644 Tactility/Private/Tactility/lvgl/SystemBars.h create mode 100644 Tactility/Private/Tactility/lvgl/SystemMenu.h create mode 100644 Tactility/Source/lvgl/SystemBars.cpp create mode 100644 Tactility/Source/lvgl/SystemMenu.cpp create mode 100644 Tactility/Source/settings/LauncherSettings.cpp create mode 100644 Tactility/Tests/Source/SystemBarsLayoutTest.cpp diff --git a/.claude/rules/lvgl.md b/.claude/rules/lvgl.md index c6c73ed9a..ab6370458 100644 --- a/.claude/rules/lvgl.md +++ b/.claude/rules/lvgl.md @@ -6,3 +6,21 @@ Two kernel modules cover LVGL: - **`lvgl-module`** (`Modules/lvgl-module/`, ``) owns LVGL's lifecycle: init/deinit, the LVGL task loop, and `lvgl_lock()`/`lvgl_try_lock()`/`lvgl_unlock()` mutex-based locking that any task must hold before touching LVGL objects. It bridges Tactility's device model to LVGL indevs (`lvgl/devices/*.h`: `display`, `pointer`, `keyboard`, `trackball`), and provides shared fonts (`lvgl/fonts.h`: Montserrat text sizes, Material Symbols icon sets for statusbar/launcher/shared use) and a few shared widgets (`lvgl/widgets/*.h`: `toolbar`, `spinner`, `sliderbox`). - **`lvgl-window-manager-module`** (`Modules/lvgl-window-manager-module/`, ``) manages a single stacked window per app instance on top of `lvgl-module`. `window_manager_start()`/`window_manager_stop()` create/tear down the root widget (plus optional chrome from a configured `WindowManagerScreenInitFn`); `window_manager_create()`/`window_manager_remove()` push/pop an app's window and (re)populate it via a `WindowCreateWidgetsFn`. Only the topmost window ever has live widgets - burying and resurfacing a window deletes and rebuilds its widget tree rather than hiding/showing it. That rebuild-on-remove path can run `create_widgets` on a *different* app's thread (whichever app's `window_manager_remove()` call caused this window to resurface), so `create_widgets` must only rebuild already-committed state, never decide what happens next - state transitions belong in the app's own `main()` event loop, driven by real `APP_EVENT_RESULT`s. + +## Keyboard navigation + +- Put groups of related focusable widgets (pills/chips, rows of buttons, toggle tiles) in a grid navigation container with `lvgl_grid_navigation_add()` (`lvgl/grid_navigation.h`). Only the container joins the input group: left/right moves within the group and up/down moves between groups. +- Never make checkable widgets (switches, checkable buttons) direct input group members: LVGL toggles them on arrow keys. Grid navigation forwards only Enter to them. + +## Theming (LSS) + +The themes in `Modules/lvgl-module/source/themes/lv_theme_material*.c/.h` are generated: never edit them directly. They're compiled from the LVGL Style Sheets in `Modules/lvgl-module/themes/*.lss` by the LSS tool, a git submodule at `Modules/lvgl-module/lss/` (see its `README.md` for the syntax). + +- Styles are defined once and attached to widget types with `apply() {