UI Framework & Screens
Section titled “UI Framework & Screens”Purpose
Section titled “Purpose”The UI_Framework_&_Screens module (main/display/) is the complete display and interaction layer of the Pibot CNC Pendant firmware. It owns every pixel on screen: the LVGL task lifecycle, theme system, resource loading from flash, screen navigation, reusable widget components, and all CNC firmware-specific UI screens. It runs exclusively on Core 1 and is the sole consumer of LVGL APIs anywhere in the codebase.
The module is structured in four tiers:
| Tier | Sub-module | Responsibility |
|---|---|---|
| Foundation | ui_core | LVGL task runner, UIManager, theme tokens/styles, flash resource loader |
| Components | ui_components | Reusable widgets: circular menu, list menu, panel, virtual buttons, custom keyboard |
| Screens | common_screens, activity_monitoring | Transport-agnostic screens (splash, input, message box, scan, settings pickers) |
| CNC firmware UI | cnc_shared, fluidnc_module, grbl_module, grblhal_module | Machine-specific screens: main, jog, status, GC state, files, probe, tool change |
Two other UI builds exist next to the CNC pendant UI, selected by CMake:
| Build | Folder | Status |
|---|---|---|
Small UI tier (UI_TIER=SMALL → ESP3D_UI_SMALL) | main/display/small_ui/ (ESP3DSmallUi) | Basic, self-contained read-only dashboard for small displays (1.47” 172×320). Uses nothing from the pendant UI: own LVGL task, built-in LVGL fonts and symbols only (no ui_resources). Pages cycled by the board page button: (1) remote link icon (WiFi STA / AP / USB / BT), network state, IP, job or update progress arc; (2) SD card state and SSID. cmake/sanity_check.cmake only accepts SMALL (or unset) and requires TFT_UI_SERVICE=ON |
3D printer UI (TARGET_FW_MARLIN / REPETIER / SMOOTHIEWARE) | main/display/3dprinter/ | Groundwork: main screen, settings screen header and macro manager; the other folders hold dummy.c placeholders |
Architecture
Section titled “Architecture”Module Overview
Section titled “Module Overview”LVGL Task Lifecycle
Section titled “LVGL Task Lifecycle”Theme and Style Pipeline
Section titled “Theme and Style Pipeline”Screen Navigation (CNC shared flow)
Section titled “Screen Navigation (CNC shared flow)”The critical alert (main/display/cnc/components/critical_alert.cpp) is not a navigation target: it subscribes to the critical_alert value and opens a message box on top of whatever screen is active when a condition raised outside the UI needs the user (input overflow, Recover action).
Work units (inch / mm)
Section titled “Work units (inch / mm)”Two shared headers carry the unit logic used by several screens:
main/display/esp3d_unit_sections.h— jog step / feedrate lists hold one section per work unit (mm;0.01;0.1;1;10;in;0.001;0.01;0.1;1); the section is selected by G20 / G21, no conversion is ever done.main/display/cnc/screens/position_unit.h— themm/inlabel next to the positions follows the report unit ($13/report_inches), not G20 / G21; also the active WCS badge of the position button.
Detail: jog_unit_lists.md, inch_mm_units_reference.md.
Component Hierarchy
Section titled “Component Hierarchy”Core Components Documentation
Section titled “Core Components Documentation”| Sub-module | Path | Key files | Documentation |
|---|---|---|---|
| ui_core — LVGL task, UIManager, theme, resources | main/display/ | esp3d_x_ui.h/cpp, esp3d_ui.h/cpp, esp3d_resources.cpp, esp3d_snapshot.h, esp3d_translations_id_map.h | docs/architecture/screens_architecture.md, docs/ui_resources/development.md, docs/ui_resources/theme_palette.md, docs/ui_resources/ui_style_guide.md |
| ui_components — reusable widgets | main/display/components/ | circular_menu_component.h, list_menu_component.h, panel_component.h, virtual_buttons_component.h, custom_keyboard_component.h/cpp | docs/architecture/Input_system.md, docs/architecture/screen_transitions_flow.md |
| common_screens — transport-agnostic screens | main/display/screens/ | generic_screen.h, circular_menu_screen.h, list_menu_screen.h, input_screen.*, message_box_screen.*, splash_screen.*, wifi_scan_screen.*, connection_status_screen.*, range_editor_screen.* | docs/architecture/screens_architecture.md, docs/architecture/screen_transitions_flow.md |
| activity_monitoring — screen timeout/backlight | main/display/activity_monitoring.cpp | activity_monitoring.cpp/.h | components/esp3d_activity_manager/ |
| cnc_shared — shared CNC screens | main/display/cnc/screens/ | main_screen.cpp, jog_screen.cpp, status_screen.cpp, settings_screen.cpp, macros_screen.cpp, macro_manager.h/cpp, firmware_status_screen.cpp, information_screen.cpp, gc_state_screen.cpp, position_unit.h; components/critical_alert.cpp | docs/ux_flows/ |
| fluidnc_module — FluidNC-specific UI | main/display/cnc/fluidnc/ | connection_status.h, change_tool_screen.cpp, files_screen.cpp, probe_screen.cpp | docs/ux_flows/ |
| grbl_module — grbl-specific UI | main/display/cnc/grbl/ | esp3d_screen_type.cpp, connection_status.h, change_tool_screen.cpp, files_screen.cpp, probe_screen.cpp | docs/ux_flows/ |
| grblhal_module — grblHAL-specific UI | main/display/cnc/grblhal/ | esp3d_screen_type.cpp, connection_status.h, change_tool_screen.cpp, files_screen.cpp, probe_screen.cpp | docs/ux_flows/ |
Related documentation
Section titled “Related documentation”| Topic | Document |
|---|---|
Screen architecture, GenericScreen base, registration patterns | docs/architecture/screens_architecture.md |
| Safe timer-based screen transition idiom | docs/architecture/screen_transitions_flow.md |
| Input system (encoder, buttons, switch, potentiometer) | docs/architecture/Input_system.md |
| Display driver architecture (SPI / RGB / I80, orientation math) | docs/architecture/display_drivers.md |
ui_resources partition binary format, generate_resources.py, SD update | docs/ui_resources/development.md |
| 26 semantic color tokens, per-theme RGBA values, design conventions | docs/ui_resources/theme_palette.md |
ThemeStyles architecture, apply* catalog, per-screen style inventory | docs/ui_resources/ui_style_guide.md |
| Adding/modifying icons and fonts, SD-card update workflow | docs/guides/ui_resources_guide.md |
| FluidNC / grblHAL screen-by-screen UX flows | docs/ux_flows/ |
UI sounds (semantic ESP3DSoundEvent API, ESP3D_SELECTION_BEEP …) | docs/architecture/sound_system.md |
| Encoder jog, wheel sensitivity setting | docs/architecture/handwheel_jog.md |
| Small UI tier study (1.47” dashboard) | docs/ongoing_reflection/small_display_dashboard_and_ui_tiers_study.md |
| Memory constraints (heap, fragmentation, WiFi vs BT) | docs/guides/esp32_memory_constraints.md |
Critical Constraints
Section titled “Critical Constraints”| Rule | Reason |
|---|---|
All lv_obj_* / lv_style_* calls must be inside _lock_acquire / _lock_release or within LVGL event/timer callbacks | LVGL is strictly single-threaded on Core 1 |
| Never destroy LVGL objects inside an event callback | Use lv_timer_create() cleanup timers — see screen_transitions_flow.md |
initializeStyles() / resetStyles() only from the LVGL task or before it starts | lv_style_* APIs are not thread-safe |
Never call lv_obj_remove_style_all() on widgets styled via apply*Style() | Styles are shared objects; removing all strips them from the shared pool |
After esp3d_resources_write_blob(), the mmap view is stale | The update service must reboot immediately after a successful blob write |
All calloc/malloc in display code must be checked; log total free + largest block on failure | Heap can drop to ~10 KB in Bluetooth mode; silent allocation failure crashes the system |