-
-
Notifications
You must be signed in to change notification settings - Fork 110
feat: runtime screen rotation for the color UI (opt-in) #359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
attakygit
wants to merge
7
commits into
meshtastic:master
Choose a base branch
from
Attaky-Module:feat/runtime-screen-rotation
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
247a1c6
fix(graphics): fit the statistics table on narrow screens
attakygit c78932b
fix(build): select the generated view as a scalar and derive its macro
attakygit 61fdaba
feat(build): generator and generated glue for dual-layout builds
attakygit 5411a71
feat(graphics): runtime screen-rotation state
attakygit 90fa200
feat(build): compile both generated UI trees under MUI_RUNTIME_ROTATION
attakygit e4f7639
feat(graphics): apply the stored rotation in the display path
attakygit 35131fa
feat(settings): screen rotation chooser
attakygit File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| # Dual-layout build support for MUI_RUNTIME_ROTATION. | ||
| # | ||
| # Links both perpendicular generated layouts into one binary so the screen | ||
| # rotation becomes a runtime setting. The primary tree (this build's VIEW_*) | ||
| # keeps its symbols and supplies every shared asset; the secondary tree is | ||
| # compiled with its colliding globals renamed via a generated forced include. | ||
| # | ||
| # mui_runtime_rotation_sources(<sources_var>) rewrites the caller's source list. | ||
| # mui_runtime_rotation_configure(<target>) applies the target settings. | ||
|
|
||
| set(MUI_DUAL_VIEWS ui_320x240 ui_240x320) | ||
| set(MUI_GLUE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tools/generated/dual) | ||
| set(MUI_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_dual_ui.py) | ||
|
|
||
| function(mui_runtime_rotation_sources sources_var) | ||
| list(GET MUI_DUAL_VIEWS 0 _first) | ||
| list(GET MUI_DUAL_VIEWS 1 _second) | ||
| if(GENERATED_VIEW STREQUAL _first) | ||
| set(_primary ${_first}) | ||
| set(_secondary ${_second}) | ||
| elseif(GENERATED_VIEW STREQUAL _second) | ||
| set(_primary ${_second}) | ||
| set(_secondary ${_first}) | ||
| else() | ||
| message(FATAL_ERROR | ||
| "MUI_RUNTIME_ROTATION supports only ${_first} and ${_second}, not '${GENERATED_VIEW}': " | ||
| "it links the two perpendicular layouts and no other generated tree has a counterpart.") | ||
| endif() | ||
|
|
||
| find_package(Python COMPONENTS Interpreter REQUIRED) | ||
| execute_process(COMMAND ${Python_EXECUTABLE} ${MUI_GENERATOR} --check ${_primary} | ||
| RESULT_VARIABLE _rc OUTPUT_VARIABLE _out ERROR_VARIABLE _err) | ||
| if(NOT _rc EQUAL 0) | ||
| message(FATAL_ERROR "MUI_RUNTIME_ROTATION: ${_out}${_err}") | ||
| endif() | ||
|
|
||
| # The build reads the source inventory from the manifest so it cannot drift | ||
| # from the generator. | ||
| file(STRINGS ${MUI_GLUE_DIR}/manifest.txt _manifest) | ||
| set(_secondary_names "") | ||
| set(_glue_names "") | ||
| foreach(_line IN LISTS _manifest) | ||
| if(_line MATCHES "^core_source (.+)$") | ||
| list(APPEND _secondary_names ${CMAKE_MATCH_1}) | ||
| elseif(_line MATCHES "^secondary_asset ${_secondary} (.+)$") | ||
| # only the secondary tree's unique assets need compiling | ||
| list(APPEND _secondary_names ${CMAKE_MATCH_1}) | ||
| elseif(_line MATCHES "^glue_source (.+)$") | ||
| list(APPEND _glue_names ${CMAKE_MATCH_1}) | ||
| endif() | ||
| endforeach() | ||
|
|
||
| # Drop every generated tree from the catch-all glob, then add each tree | ||
| # exactly once. Without this both trees enter the target and their | ||
| # identically named globals collide. | ||
| set(_sources ${${sources_var}}) | ||
| list(FILTER _sources EXCLUDE REGEX "/generated/ui_[0-9]+x[0-9]+/") | ||
|
|
||
| file(GLOB_RECURSE _primary_sources ${CMAKE_CURRENT_SOURCE_DIR}/generated/${_primary}/*) | ||
| list(APPEND _sources ${_primary_sources}) | ||
|
|
||
| set(_secondary_sources "") | ||
| foreach(_name IN LISTS _secondary_names) | ||
| set(_path ${CMAKE_CURRENT_SOURCE_DIR}/generated/${_secondary}/${_name}) | ||
| if(EXISTS ${_path}) | ||
| list(APPEND _secondary_sources ${_path}) | ||
| endif() | ||
| endforeach() | ||
|
|
||
| # from the manifest, not a glob: a stale .c left in the directory must not | ||
| # silently enter the build | ||
| set(_glue_sources "") | ||
| foreach(_name IN LISTS _glue_names) | ||
| list(APPEND _glue_sources ${MUI_GLUE_DIR}/${_name}) | ||
| endforeach() | ||
| list(APPEND _sources ${_secondary_sources} ${_glue_sources}) | ||
|
|
||
| # The secondary tree and the secondary-side bridge must see the renames and | ||
| # the secondary headers; the primary-side bridge must see the primary tree | ||
| # untouched. | ||
| set(_rename_flags | ||
| -include ${MUI_GLUE_DIR}/ui_secondary_rename.h | ||
| -I${CMAKE_CURRENT_SOURCE_DIR}/generated/${_secondary}) | ||
| set_source_files_properties( | ||
| ${_secondary_sources} ${MUI_GLUE_DIR}/bridge_secondary.c | ||
| DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||
| PROPERTIES COMPILE_OPTIONS "${_rename_flags}") | ||
|
|
||
| # C++ sources referencing generated styles dispatch them to the active tree. | ||
| set_source_files_properties( | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/source/graphics/TFT/Themes.cpp | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/source/graphics/TFT/TFTView_320x240.cpp | ||
| DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||
| PROPERTIES COMPILE_OPTIONS "-include;${MUI_GLUE_DIR}/style_routing.h") | ||
|
|
||
| set(MUI_PRIMARY_VIEW ${_primary} PARENT_SCOPE) | ||
| set(${sources_var} ${_sources} PARENT_SCOPE) | ||
| endfunction() | ||
|
|
||
| function(mui_runtime_rotation_configure target) | ||
| target_compile_definitions(${target} PUBLIC MUI_RUNTIME_ROTATION) | ||
| target_include_directories(${target} PUBLIC ${MUI_GLUE_DIR}) | ||
| endfunction() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #pragma once | ||
|
|
||
| #ifdef MUI_RUNTIME_ROTATION | ||
|
|
||
| // Only these two layouts are perpendicular counterparts of each other. | ||
| #if !defined(VIEW_320x240) && !defined(VIEW_240x320) | ||
| #error "MUI_RUNTIME_ROTATION requires VIEW_320x240 or VIEW_240x320" | ||
| #endif | ||
|
|
||
| // Those drivers apply a fixed rotation to touch coordinates and would | ||
| // desynchronize from a rotated panel. | ||
| #ifdef CUSTOM_TOUCH_DRIVER | ||
| #error "MUI_RUNTIME_ROTATION is not supported with CUSTOM_TOUCH_DRIVER" | ||
| #endif | ||
|
|
||
| #include <cstdint> | ||
|
|
||
| /** | ||
| * Runtime screen rotation for builds that link both generated UI layouts. | ||
| * | ||
| * The stored value is a quarter-turn count applied on top of the board's | ||
| * compile-time LGFX_ROTATION offset, so value 0 reproduces the board's default. | ||
| * Even values keep the compile-time VIEW_* layout, odd values select the | ||
| * perpendicular one. Applied at boot only: an LVGL layout tree cannot be | ||
| * rebuilt in place once the view has cached its object pointers. | ||
| */ | ||
| class ScreenRotation | ||
| { | ||
| public: | ||
| enum Value : uint8_t { | ||
| Rotation0 = 0, | ||
| Rotation90 = 1, | ||
| Rotation180 = 2, | ||
| Rotation270 = 3, | ||
| }; | ||
|
|
||
| /// Supplied by the integrator before the display is created. Out-of-range | ||
| /// values fall back to the build default. Ignored after the first call. | ||
| static void setLoaded(uint8_t raw); | ||
| static void load(void); | ||
| static Value get(void) { return current; } | ||
|
|
||
| /// Odd quarter turns swap the aspect, so they need the perpendicular tree. | ||
| static bool usesSecondaryTree(Value v) { return ((uint8_t)v & 1) != 0; } | ||
|
|
||
| /// Nominal size of the layout, for seeding DisplayDriver. NOT the panel | ||
| /// resolution -- the driver reads that from the rotated panel. | ||
| static uint16_t width(Value v); | ||
| static uint16_t height(Value v); | ||
|
|
||
| /// Value passed to setRotation(); LovyanGFX composes it with the board's | ||
| /// offset_rotation. The quarter turns run opposite to the panel's own | ||
| /// numbering so that a rotation reads upright to the user: hardware-checked | ||
| /// on a 320x240 panel with offset_rotation 3, where upright portrait is | ||
| /// panel rotation 2, i.e. one step back from upright landscape, not one | ||
| /// step on. Parity is preserved, so tree selection is unaffected. | ||
| static uint8_t panelRotation(Value v) { return (uint8_t)((4 - (uint8_t)v) & 3); } | ||
|
|
||
| static bool usesSecondaryTree(void) { return usesSecondaryTree(current); } | ||
| static uint16_t width(void) { return width(current); } | ||
| static uint16_t height(void) { return height(current); } | ||
| static uint8_t panelRotation(void) { return panelRotation(current); } | ||
|
|
||
| private: | ||
| static Value current; | ||
| static bool loaded; | ||
| }; | ||
|
|
||
| #endif // MUI_RUNTIME_ROTATION |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: meshtastic/device-ui
Length of output: 158
🏁 Script executed:
Repository: meshtastic/device-ui
Length of output: 5946
🌐 Web query:
CMake set_source_files_properties DIRECTORY option version documentation💡 Result:
The DIRECTORY option for the set_source_files_properties command in CMake was introduced in version 3.18 [1][2]. It allows you to set source file properties in specific directory scopes beyond the current CMakeLists.txt file [1][3]. By default, source file properties are only visible to targets defined within the same directory scope [1][2]. The DIRECTORY option overrides this behavior by applying the specified properties to the source files within each of the provided directory scopes [1][3]. Key requirements and details for using the DIRECTORY option include: 1. Prerequisite Knowledge: CMake must already be aware of the specified directories [1][3]. This means they must have been added previously via the add_subdirectory command or be the top-level source directory [1][2]. 2. Path Handling: Relative paths provided to the DIRECTORY option are interpreted as relative to the current source directory [1][3]. 3. Alternative Scope: The command also supports a TARGET_DIRECTORY option, which allows setting properties in the directory scopes where specific targets were created [1][2]. You can retrieve these properties using the get_source_file_property command [1][3]. Note that the GENERATED property is an exception to these scoping rules and may be globally visible [1][4].
Citations:
Require CMake 3.18 for the CMakeLists.txt minimum.
CMakeLists.txtdeclarescmake_minimum_required(VERSION 3.15), butcmake/MuiRuntimeRotation.cmakeusesset_source_files_properties(... DIRECTORY ...)from lines 84-94. That call is invalid before CMake 3.18, so older compatible CMake releases fail at configure time and the rotation rename or style-routing flags are not applied.🤖 Prompt for AI Agents