From 247a1c63ed4634d1a6ba17ea298fd6dafe0b3e80 Mon Sep 17 00:00:00 2001 From: Attaky <203162318+attakygit@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:42:34 -0700 Subject: [PATCH 1/7] fix(graphics): fit the statistics table on narrow screens The six data columns use a fixed 36 px width unless the horizontal resolution exceeds 320, so a 240 px screen asks for 57 + 6*36 = 273 px and the table overflows its panel. Derive the column width from the available space instead. --- source/graphics/TFT/TFTView_320x240.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/graphics/TFT/TFTView_320x240.cpp b/source/graphics/TFT/TFTView_320x240.cpp index e572a936..d2ea076d 100644 --- a/source/graphics/TFT/TFTView_320x240.cpp +++ b/source/graphics/TFT/TFTView_320x240.cpp @@ -625,6 +625,10 @@ void TFTView_320x240::apply_hotfix(void) int32_t rows = 12; if (h > 320) { width = (h - 48 - 57) / 6; + } else if (h < 320) { + // narrow screens (240 px portrait): the default 57 + 6*36 = 273 does + // not fit, so shrink the six data columns instead of overflowing + width = (h - 57 - 6) / 6; } if (v > 240) { rows = (v - 32) / 18; From c78932bf8a178d8949e5374f785396fbfaca8b73 Mon Sep 17 00:00:00 2001 From: Attaky <203162318+attakygit@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:42:53 -0700 Subject: [PATCH 2/7] fix(build): select the generated view as a scalar and derive its macro set(GENERATED_VIEW ${VIEW} "ui_320x240") produces a two-element list as soon as VIEW is set, and VIEW_320x240 was defined unconditionally, so the CMake build could only ever produce ui_320x240. Give VIEW a default and derive the macro from it; behaviour is unchanged when VIEW is unset. --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 74f2f3cc..7e0f565e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,14 +24,18 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin") -set(GENERATED_VIEW ${VIEW} "ui_320x240") +if(NOT VIEW) + set(VIEW "ui_320x240") +endif() +set(GENERATED_VIEW ${VIEW}) message(STATUS "Using C++${CMAKE_CXX_STANDARD}") message(STATUS "Using Generated View: " ${GENERATED_VIEW}) add_compile_definitions(ARCH_PORTDUINO) add_compile_definitions(ARDUINO) -add_compile_definitions(VIEW_320x240) +string(REGEX REPLACE "^ui_" "VIEW_" GENERATED_VIEW_MACRO ${GENERATED_VIEW}) +add_compile_definitions(${GENERATED_VIEW_MACRO}) add_compile_definitions(USE_X11=1) include(FetchContent) From 61fdababdc7a1146dfe8db0c64dbf0e20f0815e3 Mon Sep 17 00:00:00 2001 From: Attaky <203162318+attakygit@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:43:02 -0700 Subject: [PATCH 3/7] feat(build): generator and generated glue for dual-layout builds Linking both generated UI trees into one binary requires renaming the secondary tree's 198 colliding globals and republishing its widget pointers into the symbols the C++ view addresses. tools/gen_dual_ui.py derives that glue from the trees themselves and asserts the invariants it depends on: identical objects_t member sets, symmetric global symbols, byte-identical shared assets, and an identical non-asset source inventory. The output is orientation-neutral, so one set of artifacts serves either tree as the primary one. --check regenerates every artifact and byte-compares it, and rejects unexpected files, so the committed glue cannot drift from the trees unnoticed. --- tools/gen_dual_ui.py | 406 +++++++++++++++ tools/generated/dual/bridge_primary.c | 553 +++++++++++++++++++++ tools/generated/dual/bridge_secondary.c | 551 ++++++++++++++++++++ tools/generated/dual/manifest.txt | 212 ++++++++ tools/generated/dual/style_routing.h | 353 +++++++++++++ tools/generated/dual/ui_secondary_rename.h | 203 ++++++++ 6 files changed, 2278 insertions(+) create mode 100644 tools/gen_dual_ui.py create mode 100644 tools/generated/dual/bridge_primary.c create mode 100644 tools/generated/dual/bridge_secondary.c create mode 100644 tools/generated/dual/manifest.txt create mode 100644 tools/generated/dual/style_routing.h create mode 100644 tools/generated/dual/ui_secondary_rename.h diff --git a/tools/gen_dual_ui.py b/tools/gen_dual_ui.py new file mode 100644 index 00000000..b83f9515 --- /dev/null +++ b/tools/gen_dual_ui.py @@ -0,0 +1,406 @@ +#!/usr/bin/env python3 +"""Generate the dual-layout glue used by MUI_RUNTIME_ROTATION builds. + +Both generated UI trees are linked into one binary so the screen rotation +becomes a runtime setting. The primary tree (the build's VIEW_*) keeps its +symbol names; the secondary tree is compiled with its colliding globals renamed +through a generated forced include, and a bridge republishes its widget +pointers into the symbols the C++ view addresses. + +Usage: + python3 tools/gen_dual_ui.py [primary_view] regenerate + python3 tools/gen_dual_ui.py --check [view] verify the committed output +""" + +import hashlib +import os +import re +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) +OUT = os.path.join(ROOT, "tools", "generated", "dual") +VIEWS = ("ui_320x240", "ui_240x320") +DEFAULT_PRIMARY = "ui_320x240" +PREFIX = "MUI2_" + +# Secondary-tree assets the primary tree does not provide and whose image table +# actually references them. Compiled once, never renamed. +SECONDARY_ONLY_ASSETS = ( + "ui_image_top_message_node_images.c", + "ui_image_home_bell_slash_image.c", +) + +# Shared asset definitions, C++-implemented actions, and type/tag tokens that +# are not linker symbols. +NEVER_RENAME = re.compile( + r"^(img_|ui_font_|action_|objects_t|_objects_t|ScreensEnum|SCREEN_ID_|tick_screen_func_t$)" +) + + +def read(path): + with open(path, "r", encoding="utf-8", errors="replace") as f: + return f.read() + + +def core_sources(): + """Every non-asset translation unit, derived from the trees rather than + hardcoded: a newly generated one must not silently enter only one tree. + + Assets are recognised by the ui_image_/ui_font_ filename prefixes, which is + how the UI generator names them. A future asset under a different prefix + would be treated as a core source and compiled into both trees, and its + definition would collide because NEVER_RENAME excludes those symbols from + the rename list. The symmetry assert below cannot see that, so the + prefixes have to stay in sync with the UI generator.""" + per_tree = {} + for view in VIEWS: + d = os.path.join(ROOT, "generated", view) + per_tree[view] = sorted( + n + for n in os.listdir(d) + if n.endswith(".c") and not n.startswith(("ui_image_", "ui_font_")) + ) + a, b = (per_tree[v] for v in VIEWS) + if a != b: + sys.exit( + "ERROR: generated core source sets diverged.\n %s: %s\n %s: %s" + % (VIEWS[0], a, VIEWS[1], b) + ) + return a + + +def objects_members(tree): + src = read(os.path.join(ROOT, "generated", tree, "screens.h")) + m = re.search( + r"typedef\s+struct\s+_objects_t\s*\{(.*?)\}\s*objects_t\s*;", src, re.S + ) + if not m: + sys.exit("ERROR: objects_t definition not found in %s/screens.h" % tree) + return re.findall(r"lv_obj_t\s*\*\s*([A-Za-z_][A-Za-z_0-9]*)\s*;", m.group(1)) + + +def global_symbols(tree, sources): + # Scan the sources, not the headers: styles.h declares only a subset of + # styles.c's globals, so a header-driven rename list would be incomplete. + syms = set() + for src_name in sources: + path = os.path.join(ROOT, "generated", tree, src_name) + if not os.path.exists(path): + continue + src = read(path) + src = re.sub(r"/\*.*?\*/", "", src, flags=re.S) + src = re.sub(r"//[^\n]*", "", src) + for m in re.finditer( + r"^(?!static\b|typedef\b|extern\b|#|\}|\{)" + r"(?:const\s+|unsigned\s+|signed\s+|struct\s+|enum\s+)*" + r"[A-Za-z_][A-Za-z_0-9]*\s+\**\s*" + r"([A-Za-z_][A-Za-z_0-9]*)\s*" + r"(?:\([^;{]*\)\s*\{|\[[^\]]*\]\s*=|=|;)", + src, + re.M, + ): + syms.add(m.group(1)) + return {s for s in syms if not NEVER_RENAME.match(s)} + + +def asset_symbol(name): + """Linker symbol an asset translation unit defines, or None.""" + if name.startswith("ui_image_"): + return "img_" + name[len("ui_image_") : -len(".c")] + if name.startswith("ui_font_"): + return name[: -len(".c")] + return None + + +def tree_sources(tree, name): + path = os.path.join(ROOT, "generated", tree, name) + return read(path) if os.path.exists(path) else "" + + +def asset_inventory(sources): + """Shared assets (present in both trees) must be byte-identical, because + only the primary copy is compiled. Assets unique to one tree have to be + compiled additionally whenever that tree is the secondary one, so the + inventory is computed for both directions.""" + h = hashlib.sha256() + dirs = {v: os.path.join(ROOT, "generated", v) for v in VIEWS} + names = set() + for d in dirs.values(): + names |= { + n + for n in os.listdir(d) + if n.startswith(("ui_image_", "ui_font_")) and n.endswith(".c") + } + + shared, unique = [], {v: [] for v in VIEWS} + for name in sorted(names): + present = [v for v in VIEWS if os.path.exists(os.path.join(dirs[v], name))] + if len(present) == len(VIEWS): + a, b = (read(os.path.join(dirs[v], name)) for v in VIEWS) + if a != b: + sys.exit( + "ERROR: asset %s is no longer identical between trees; the shared-asset " + "deduplication would silently use the primary bytes" % name + ) + shared.append(name) + h.update(name.encode()) + h.update(hashlib.sha256(a.encode()).digest()) + else: + unique[present[0]].append(name) + + # An unlisted unique asset that the tree's own sources reference would be a + # missing definition once that tree is compiled as the secondary one. + for view, extras in unique.items(): + body = "".join(tree_sources(view, s) for s in sources) + for name in extras: + if name in SECONDARY_ONLY_ASSETS: + continue + sym = asset_symbol(name) + if sym and re.search(r"\b%s\b" % re.escape(sym), body): + sys.exit( + "ERROR: %s-only asset %s is now referenced by that tree but is excluded " + "from the build; add it to SECONDARY_ONLY_ASSETS" % (view, name) + ) + + listed = { + v: sorted(n for n in unique[v] if n in SECONDARY_ONLY_ASSETS) for v in VIEWS + } + for view in VIEWS: + for name in listed[view]: + h.update(("%s/%s" % (view, name)).encode()) + h.update( + hashlib.sha256(read(os.path.join(dirs[view], name)).encode()).digest() + ) + return h.hexdigest(), len(shared), listed + + +def build_artifacts(): + """Return {filename: content} for every generated file. + + The output is orientation-neutral: both trees expose the same member and + symbol sets and the bridge copies field-wise in canonical order, so one set + of artifacts serves either tree as the primary one.""" + first, second = VIEWS + sources = core_sources() + a_members, b_members = objects_members(first), objects_members(second) + if set(a_members) != set(b_members): + sys.exit( + "ERROR: objects_t member sets diverged.\n %s-only: %s\n %s-only: %s" + % ( + first, + sorted(set(a_members) - set(b_members)), + second, + sorted(set(b_members) - set(a_members)), + ) + ) + members = sorted(set(a_members)) + + a_syms, b_syms = global_symbols(first, sources), global_symbols(second, sources) + if a_syms != b_syms: + sys.exit( + "ERROR: global symbol sets are not symmetric; the rename list would be wrong.\n" + " %s-only: %s\n %s-only: %s" + % (first, sorted(a_syms - b_syms), second, sorted(b_syms - a_syms)) + ) + syms = sorted(a_syms) + ui_ptrs = sorted( + s + for s in syms + if s.startswith("ui_") and s not in ("ui_init", "ui_tick", "ui_init_boot") + ) + assets_fp, shared_assets, unique_assets = asset_inventory(sources) + fp = hashlib.sha256( + ( + "|".join(sources) + + "#" + + "|".join(members) + + "#" + + "|".join(syms) + + "#" + + "|".join(ui_ptrs) + + "#" + + assets_fp + ).encode() + ).hexdigest() + + banner = "// GENERATED by tools/gen_dual_ui.py - do not edit.\n" + out = {} + + # lvgl.h must come before the defines so the generic names (objects, + # images, add_style, ...) cannot leak into the dependency headers. + rename = [ + banner, + "// Forced include for the secondary generated tree's sources only.\n", + "#pragma once\n#include \n\n", + ] + rename += ["#define %s %s%s\n" % (s, PREFIX, s) for s in syms] + out["ui_secondary_rename.h"] = "".join(rename) + + # The two objects_t structs share member names but not member order, so the + # bridge copies field-wise by name. Neither side may include both trees' + # screens.h (identical include guards), hence the flat intermediate arrays. + sec = [ + banner, + "// Secondary tree (renamed): flatten objects + ui_* pointers into\n", + "// canonical (alphabetical) order.\n", + '#include "screens.h"\n\n', + "lv_obj_t *mui_secondary_objects_flat[%d];\n" % len(members), + "lv_obj_t *mui_secondary_ui_flat[%d];\n\n" % len(ui_ptrs), + "void mui_bridge_collect_secondary(void)\n{\n", + ] + sec += [ + " mui_secondary_objects_flat[%d] = objects.%s;\n" % (i, n) + for i, n in enumerate(members) + ] + sec += [ + " mui_secondary_ui_flat[%d] = %s;\n" % (i, n) for i, n in enumerate(ui_ptrs) + ] + sec.append("}\n") + out["bridge_secondary.c"] = "".join(sec) + + pri = [ + banner, + "// Primary tree: publish the flattened secondary pointers into the\n", + "// symbols the C++ view addresses.\n", + '#include "screens.h"\n\n', + "extern lv_obj_t *mui_secondary_objects_flat[%d];\n" % len(members), + "extern lv_obj_t *mui_secondary_ui_flat[%d];\n" % len(ui_ptrs), + "void mui_bridge_collect_secondary(void);\n\n", + "void mui_bridge_publish_secondary(void)\n{\n", + " mui_bridge_collect_secondary();\n", + ] + pri += [ + " objects.%s = mui_secondary_objects_flat[%d];\n" % (n, i) + for i, n in enumerate(members) + ] + pri += [ + " %s = mui_secondary_ui_flat[%d];\n" % (n, i) for i, n in enumerate(ui_ptrs) + ] + pri.append("}\n") + out["bridge_primary.c"] = "".join(pri) + + # The secondary tree attaches its own renamed style objects, so theme + # mutations and C++ add_style_* calls must reach the active tree or the + # secondary layout renders unthemed. init_style_* is internal to styles.c + # and never called from C++, so it is renamed but not routed. + style_funcs = sorted( + s for s in syms if s.startswith(("get_style_", "add_style_", "remove_style_")) + ) + style_objs = sorted(s for s in syms if s.startswith("style_")) + rt = [ + banner, + "// Force-included into the C++ sources that reference generated styles.\n", + '#pragma once\n#include "graphics/ScreenRotation.h"\n#include "styles.h"\n\n', + 'extern "C" {\n', + ] + for fn in style_funcs: + if fn.startswith("get_style_"): + rt.append("lv_style_t *%s%s(void);\n" % (PREFIX, fn)) + else: + rt.append("void %s%s(lv_obj_t *obj);\n" % (PREFIX, fn)) + rt += ["extern lv_style_t %s%s;\n" % (PREFIX, ob) for ob in style_objs] + rt.append("}\n\n") + for fn in style_funcs: + if fn.startswith("get_style_"): + rt.append( + "static inline lv_style_t *mui_route_%s(void)\n" + "{ return ScreenRotation::usesSecondaryTree() ? %s%s() : %s(); }\n" + "#define %s mui_route_%s\n" % (fn, PREFIX, fn, fn, fn, fn) + ) + else: + rt.append( + "static inline void mui_route_%s(lv_obj_t *obj)\n" + "{ if (ScreenRotation::usesSecondaryTree()) %s%s(obj); else %s(obj); }\n" + "#define %s mui_route_%s\n" % (fn, PREFIX, fn, fn, fn, fn) + ) + for ob in style_objs: + rt.append( + "static inline lv_style_t &mui_route_%s(void)\n" + "{ return ScreenRotation::usesSecondaryTree() ? %s%s : %s; }\n" + "#define %s (mui_route_%s())\n" % (ob, PREFIX, ob, ob, ob, ob) + ) + out["style_routing.h"] = "".join(rt) + + # Single source of truth for the build: which sources each side compiles, + # and which glue files may exist in this directory. + glue_sources = sorted(n for n in out if n.endswith(".c")) + manifest = [ + "members=%d\nrenamed_symbols=%d\nui_pointers=%d\nshared_assets=%d\nfingerprint=%s\n" + % (len(members), len(syms), len(ui_ptrs), shared_assets, fp) + ] + manifest += ["core_source %s\n" % s for s in sources] + manifest += ["glue_source %s\n" % s for s in glue_sources] + # per-direction: extra sources to compile when is the secondary tree + for view in VIEWS: + manifest += ["secondary_asset %s %s\n" % (view, n) for n in unique_assets[view]] + manifest += ["sym %s\n" % s for s in syms] + out["manifest.txt"] = "".join(manifest) + + return out, dict( + members=len(members), + syms=len(syms), + ui_ptrs=len(ui_ptrs), + style_funcs=len(style_funcs), + style_objs=len(style_objs), + fp=fp, + ) + + +def main(): + check_only = "--check" in sys.argv[1:] + args = [a for a in sys.argv[1:] if not a.startswith("--")] + # accepted for symmetry with the build invocation; the output is the same + # for either primary, so it only has to be a supported view + view = args[0] if args else DEFAULT_PRIMARY + if view not in VIEWS: + sys.exit( + "ERROR: MUI_RUNTIME_ROTATION supports only %s; view %r is not one of them" + % (" and ".join(VIEWS), view) + ) + + artifacts, stats = build_artifacts() + + if check_only: + # Regenerate everything and byte-compare: a fingerprint check alone + # would pass on hand-edited output. + for name, want in sorted(artifacts.items()): + path = os.path.join(OUT, name) + if not os.path.exists(path): + sys.exit( + "ERROR: %s is missing; rerun: python3 tools/gen_dual_ui.py" % name + ) + if read(path) != want: + sys.exit( + "ERROR: %s does not match freshly generated output; rerun: " + "python3 tools/gen_dual_ui.py" % name + ) + # the build globs this directory, so a stale file left behind would be + # compiled even though --check never generated it + unexpected = sorted(set(os.listdir(OUT)) - set(artifacts)) + if unexpected: + sys.exit( + "ERROR: unexpected file(s) in %s: %s; remove them and rerun the generator" + % (os.path.relpath(OUT, ROOT), ", ".join(unexpected)) + ) + print("dual-UI glue is current (fingerprint %s)" % stats["fp"][:16]) + return + + os.makedirs(OUT, exist_ok=True) + for name, content in sorted(artifacts.items()): + with open(os.path.join(OUT, name), "w") as f: + f.write(content) + + print("objects_t members: %d (name sets match)" % stats["members"]) + print( + "renamed globals: %d (symmetric across trees), ui_* pointers: %d" + % (stats["syms"], stats["ui_ptrs"]) + ) + print( + "style routing: %d functions + %d objects" + % (stats["style_funcs"], stats["style_objs"]) + ) + print("wrote %s" % OUT) + + +if __name__ == "__main__": + main() diff --git a/tools/generated/dual/bridge_primary.c b/tools/generated/dual/bridge_primary.c new file mode 100644 index 00000000..8488f005 --- /dev/null +++ b/tools/generated/dual/bridge_primary.c @@ -0,0 +1,553 @@ +// GENERATED by tools/gen_dual_ui.py - do not edit. +// Primary tree: publish the flattened secondary pointers into the +// symbols the C++ view addresses. +#include "screens.h" + +extern lv_obj_t *mui_secondary_objects_flat[487]; +extern lv_obj_t *mui_secondary_ui_flat[53]; +void mui_bridge_collect_secondary(void); + +void mui_bridge_publish_secondary(void) +{ + mui_bridge_collect_secondary(); + objects.advanced_settings_panel = mui_secondary_objects_flat[0]; + objects.alert_label = mui_secondary_objects_flat[1]; + objects.alert_panel = mui_secondary_objects_flat[2]; + objects.arrow_down_button = mui_secondary_objects_flat[3]; + objects.arrow_left_button = mui_secondary_objects_flat[4]; + objects.arrow_right_button = mui_secondary_objects_flat[5]; + objects.arrow_up_button = mui_secondary_objects_flat[6]; + objects.basic_settings_alert_button = mui_secondary_objects_flat[7]; + objects.basic_settings_alert_label = mui_secondary_objects_flat[8]; + objects.basic_settings_backup_restore_button = mui_secondary_objects_flat[9]; + objects.basic_settings_backup_restore_label = mui_secondary_objects_flat[10]; + objects.basic_settings_brightness_button = mui_secondary_objects_flat[11]; + objects.basic_settings_brightness_label = mui_secondary_objects_flat[12]; + objects.basic_settings_calibration_button = mui_secondary_objects_flat[13]; + objects.basic_settings_calibration_label = mui_secondary_objects_flat[14]; + objects.basic_settings_channel_button = mui_secondary_objects_flat[15]; + objects.basic_settings_channel_label = mui_secondary_objects_flat[16]; + objects.basic_settings_input_button = mui_secondary_objects_flat[17]; + objects.basic_settings_input_label = mui_secondary_objects_flat[18]; + objects.basic_settings_language_button = mui_secondary_objects_flat[19]; + objects.basic_settings_language_label = mui_secondary_objects_flat[20]; + objects.basic_settings_modem_preset_button = mui_secondary_objects_flat[21]; + objects.basic_settings_modem_preset_label = mui_secondary_objects_flat[22]; + objects.basic_settings_reboot_button = mui_secondary_objects_flat[23]; + objects.basic_settings_reboot_label = mui_secondary_objects_flat[24]; + objects.basic_settings_region_button = mui_secondary_objects_flat[25]; + objects.basic_settings_region_label = mui_secondary_objects_flat[26]; + objects.basic_settings_reset_button = mui_secondary_objects_flat[27]; + objects.basic_settings_reset_label = mui_secondary_objects_flat[28]; + objects.basic_settings_role_button = mui_secondary_objects_flat[29]; + objects.basic_settings_role_label = mui_secondary_objects_flat[30]; + objects.basic_settings_screen_lock_button = mui_secondary_objects_flat[31]; + objects.basic_settings_screen_lock_label = mui_secondary_objects_flat[32]; + objects.basic_settings_theme_button = mui_secondary_objects_flat[33]; + objects.basic_settings_theme_label = mui_secondary_objects_flat[34]; + objects.basic_settings_timeout_button = mui_secondary_objects_flat[35]; + objects.basic_settings_timeout_label = mui_secondary_objects_flat[36]; + objects.basic_settings_timezone_button = mui_secondary_objects_flat[37]; + objects.basic_settings_timezone_label = mui_secondary_objects_flat[38]; + objects.basic_settings_user_button = mui_secondary_objects_flat[39]; + objects.basic_settings_user_label = mui_secondary_objects_flat[40]; + objects.basic_settings_wifi_button = mui_secondary_objects_flat[41]; + objects.basic_settings_wifi_label = mui_secondary_objects_flat[42]; + objects.battery_image = mui_secondary_objects_flat[43]; + objects.battery_label = mui_secondary_objects_flat[44]; + objects.battery_panel = mui_secondary_objects_flat[45]; + objects.battery_percentage_label = mui_secondary_objects_flat[46]; + objects.blank_screen = mui_secondary_objects_flat[47]; + objects.blank_screen_button = mui_secondary_objects_flat[48]; + objects.bluetooth_button = mui_secondary_objects_flat[49]; + objects.boot_logo = mui_secondary_objects_flat[50]; + objects.boot_logo_arc = mui_secondary_objects_flat[51]; + objects.boot_logo_button = mui_secondary_objects_flat[52]; + objects.boot_screen = mui_secondary_objects_flat[53]; + objects.brightness_slider = mui_secondary_objects_flat[54]; + objects.button_panel = mui_secondary_objects_flat[55]; + objects.calibration_screen = mui_secondary_objects_flat[56]; + objects.cancel_reboot_button = mui_secondary_objects_flat[57]; + objects.channel_button0 = mui_secondary_objects_flat[58]; + objects.channel_button1 = mui_secondary_objects_flat[59]; + objects.channel_button2 = mui_secondary_objects_flat[60]; + objects.channel_button3 = mui_secondary_objects_flat[61]; + objects.channel_button4 = mui_secondary_objects_flat[62]; + objects.channel_button5 = mui_secondary_objects_flat[63]; + objects.channel_button6 = mui_secondary_objects_flat[64]; + objects.channel_button7 = mui_secondary_objects_flat[65]; + objects.channel_label0 = mui_secondary_objects_flat[66]; + objects.channel_label1 = mui_secondary_objects_flat[67]; + objects.channel_label2 = mui_secondary_objects_flat[68]; + objects.channel_label3 = mui_secondary_objects_flat[69]; + objects.channel_label4 = mui_secondary_objects_flat[70]; + objects.channel_label5 = mui_secondary_objects_flat[71]; + objects.channel_label6 = mui_secondary_objects_flat[72]; + objects.channel_label7 = mui_secondary_objects_flat[73]; + objects.chat_del_button = mui_secondary_objects_flat[74]; + objects.chats_button = mui_secondary_objects_flat[75]; + objects.chats_button_label = mui_secondary_objects_flat[76]; + objects.chats_panel = mui_secondary_objects_flat[77]; + objects.controller_panel = mui_secondary_objects_flat[78]; + objects.controller_tab_view = mui_secondary_objects_flat[79]; + objects.del_label = mui_secondary_objects_flat[80]; + objects.details_panel = mui_secondary_objects_flat[81]; + objects.detected_node_button = mui_secondary_objects_flat[82]; + objects.detected_node_image = mui_secondary_objects_flat[83]; + objects.detected_node_label = mui_secondary_objects_flat[84]; + objects.detector_contact_button = mui_secondary_objects_flat[85]; + objects.detector_contact_image = mui_secondary_objects_flat[86]; + objects.detector_contact_label = mui_secondary_objects_flat[87]; + objects.detector_heard_label = mui_secondary_objects_flat[88]; + objects.detector_radar_panel = mui_secondary_objects_flat[89]; + objects.detector_start_button = mui_secondary_objects_flat[90]; + objects.detector_start_button_panel = mui_secondary_objects_flat[91]; + objects.detector_start_label = mui_secondary_objects_flat[92]; + objects.firmware_label = mui_secondary_objects_flat[93]; + objects.frequency_slot_label = mui_secondary_objects_flat[94]; + objects.frequency_slot_slider = mui_secondary_objects_flat[95]; + objects.google_logo_image = mui_secondary_objects_flat[96]; + objects.gps_lock_button = mui_secondary_objects_flat[97]; + objects.gps_position_image = mui_secondary_objects_flat[98]; + objects.groups_button = mui_secondary_objects_flat[99]; + objects.groups_panel = mui_secondary_objects_flat[100]; + objects.home_bell_button = mui_secondary_objects_flat[101]; + objects.home_bell_label = mui_secondary_objects_flat[102]; + objects.home_bluetooth_button = mui_secondary_objects_flat[103]; + objects.home_bluetooth_label = mui_secondary_objects_flat[104]; + objects.home_button = mui_secondary_objects_flat[105]; + objects.home_cancel_qr_button = mui_secondary_objects_flat[106]; + objects.home_container = mui_secondary_objects_flat[107]; + objects.home_ethernet_button = mui_secondary_objects_flat[108]; + objects.home_ethernet_label = mui_secondary_objects_flat[109]; + objects.home_location_button = mui_secondary_objects_flat[110]; + objects.home_location_image = mui_secondary_objects_flat[111]; + objects.home_location_label = mui_secondary_objects_flat[112]; + objects.home_lora_button = mui_secondary_objects_flat[113]; + objects.home_lora_label = mui_secondary_objects_flat[114]; + objects.home_mail_button = mui_secondary_objects_flat[115]; + objects.home_mail_label = mui_secondary_objects_flat[116]; + objects.home_memory_button = mui_secondary_objects_flat[117]; + objects.home_memory_label = mui_secondary_objects_flat[118]; + objects.home_mqtt_button = mui_secondary_objects_flat[119]; + objects.home_mqtt_label = mui_secondary_objects_flat[120]; + objects.home_nodes_button = mui_secondary_objects_flat[121]; + objects.home_nodes_label = mui_secondary_objects_flat[122]; + objects.home_panel = mui_secondary_objects_flat[123]; + objects.home_qr_button = mui_secondary_objects_flat[124]; + objects.home_qr_label = mui_secondary_objects_flat[125]; + objects.home_sd_card_button = mui_secondary_objects_flat[126]; + objects.home_sd_card_label = mui_secondary_objects_flat[127]; + objects.home_show_qr_panel = mui_secondary_objects_flat[128]; + objects.home_signal_button = mui_secondary_objects_flat[129]; + objects.home_signal_label = mui_secondary_objects_flat[130]; + objects.home_signal_pct_label = mui_secondary_objects_flat[131]; + objects.home_time_button = mui_secondary_objects_flat[132]; + objects.home_time_label = mui_secondary_objects_flat[133]; + objects.home_wlan_button = mui_secondary_objects_flat[134]; + objects.home_wlan_label = mui_secondary_objects_flat[135]; + objects.hop_routes_panel = mui_secondary_objects_flat[136]; + objects.initial_setup_panel = mui_secondary_objects_flat[137]; + objects.keyboard = mui_secondary_objects_flat[138]; + objects.keyboard_button_0 = mui_secondary_objects_flat[139]; + objects.keyboard_button_1 = mui_secondary_objects_flat[140]; + objects.keyboard_button_10 = mui_secondary_objects_flat[141]; + objects.keyboard_button_11 = mui_secondary_objects_flat[142]; + objects.keyboard_button_2 = mui_secondary_objects_flat[143]; + objects.keyboard_button_3 = mui_secondary_objects_flat[144]; + objects.keyboard_button_4 = mui_secondary_objects_flat[145]; + objects.keyboard_button_5 = mui_secondary_objects_flat[146]; + objects.keyboard_button_6 = mui_secondary_objects_flat[147]; + objects.keyboard_button_7 = mui_secondary_objects_flat[148]; + objects.keyboard_button_8 = mui_secondary_objects_flat[149]; + objects.keyboard_button_9 = mui_secondary_objects_flat[150]; + objects.last_heard_label = mui_secondary_objects_flat[151]; + objects.lock_screen = mui_secondary_objects_flat[152]; + objects.lock_screen_digits_label = mui_secondary_objects_flat[153]; + objects.main_screen = mui_secondary_objects_flat[154]; + objects.map_brightness_slider = mui_secondary_objects_flat[155]; + objects.map_button = mui_secondary_objects_flat[156]; + objects.map_contrast_slider = mui_secondary_objects_flat[157]; + objects.map_location_label = mui_secondary_objects_flat[158]; + objects.map_osd_panel = mui_secondary_objects_flat[159]; + objects.map_panel = mui_secondary_objects_flat[160]; + objects.map_style_dropdown = mui_secondary_objects_flat[161]; + objects.map_url_dropdown = mui_secondary_objects_flat[162]; + objects.mesh_detector_panel = mui_secondary_objects_flat[163]; + objects.meshtastic_image = mui_secondary_objects_flat[164]; + objects.meshtastic_label = mui_secondary_objects_flat[165]; + objects.meshtastic_url = mui_secondary_objects_flat[166]; + objects.message_input_area = mui_secondary_objects_flat[167]; + objects.message_restore_bar = mui_secondary_objects_flat[168]; + objects.messages_button = mui_secondary_objects_flat[169]; + objects.messages_container = mui_secondary_objects_flat[170]; + objects.messages_panel = mui_secondary_objects_flat[171]; + objects.msg_popup_button = mui_secondary_objects_flat[172]; + objects.msg_popup_label = mui_secondary_objects_flat[173]; + objects.msg_popup_panel = mui_secondary_objects_flat[174]; + objects.msg_restore_button = mui_secondary_objects_flat[175]; + objects.msg_restore_label = mui_secondary_objects_flat[176]; + objects.msg_restore_panel = mui_secondary_objects_flat[177]; + objects.nav_button = mui_secondary_objects_flat[178]; + objects.navigation_panel = mui_secondary_objects_flat[179]; + objects.node_button = mui_secondary_objects_flat[180]; + objects.node_details_battery_label = mui_secondary_objects_flat[181]; + objects.node_details_image = mui_secondary_objects_flat[182]; + objects.node_details_last_heard_label = mui_secondary_objects_flat[183]; + objects.node_details_name_label = mui_secondary_objects_flat[184]; + objects.node_details_name_short_label = mui_secondary_objects_flat[185]; + objects.node_details_panel = mui_secondary_objects_flat[186]; + objects.node_details_signal_label = mui_secondary_objects_flat[187]; + objects.node_image = mui_secondary_objects_flat[188]; + objects.node_options_panel = mui_secondary_objects_flat[189]; + objects.node_options_tab_view = mui_secondary_objects_flat[190]; + objects.node_panel = mui_secondary_objects_flat[191]; + objects.nodes_button = mui_secondary_objects_flat[192]; + objects.nodes_filter_channel_dropdown = mui_secondary_objects_flat[193]; + objects.nodes_filter_channel_label = mui_secondary_objects_flat[194]; + objects.nodes_filter_hops_away_label = mui_secondary_objects_flat[195]; + objects.nodes_filter_hops_dropdown = mui_secondary_objects_flat[196]; + objects.nodes_filter_mqtt_label = mui_secondary_objects_flat[197]; + objects.nodes_filter_mqtt_switch = mui_secondary_objects_flat[198]; + objects.nodes_filter_name_area = mui_secondary_objects_flat[199]; + objects.nodes_filter_name_label = mui_secondary_objects_flat[200]; + objects.nodes_filter_offline_label = mui_secondary_objects_flat[201]; + objects.nodes_filter_offline_switch = mui_secondary_objects_flat[202]; + objects.nodes_filter_position_label = mui_secondary_objects_flat[203]; + objects.nodes_filter_position_switch = mui_secondary_objects_flat[204]; + objects.nodes_filter_public_key_label = mui_secondary_objects_flat[205]; + objects.nodes_filter_public_key_switch = mui_secondary_objects_flat[206]; + objects.nodes_filter_unknown_label = mui_secondary_objects_flat[207]; + objects.nodes_filter_unknown_switch = mui_secondary_objects_flat[208]; + objects.nodes_hl_active_chat_label = mui_secondary_objects_flat[209]; + objects.nodes_hl_active_chat_switch = mui_secondary_objects_flat[210]; + objects.nodes_hl_name_area = mui_secondary_objects_flat[211]; + objects.nodes_hl_name_label = mui_secondary_objects_flat[212]; + objects.nodes_hl_position_label = mui_secondary_objects_flat[213]; + objects.nodes_hl_position_switch = mui_secondary_objects_flat[214]; + objects.nodes_hl_telemetry_label = mui_secondary_objects_flat[215]; + objects.nodes_hl_telemetry_switch = mui_secondary_objects_flat[216]; + objects.nodes_hliaq_label = mui_secondary_objects_flat[217]; + objects.nodes_hliaq_switch = mui_secondary_objects_flat[218]; + objects.nodes_panel = mui_secondary_objects_flat[219]; + objects.obj0 = mui_secondary_objects_flat[220]; + objects.obj1 = mui_secondary_objects_flat[221]; + objects.obj10 = mui_secondary_objects_flat[222]; + objects.obj10__cancel_button_w = mui_secondary_objects_flat[223]; + objects.obj10__ok_button_w = mui_secondary_objects_flat[224]; + objects.obj10__ok_cancel_panel_w = mui_secondary_objects_flat[225]; + objects.obj11 = mui_secondary_objects_flat[226]; + objects.obj11__cancel_button_w = mui_secondary_objects_flat[227]; + objects.obj11__ok_button_w = mui_secondary_objects_flat[228]; + objects.obj11__ok_cancel_panel_w = mui_secondary_objects_flat[229]; + objects.obj12 = mui_secondary_objects_flat[230]; + objects.obj12__cancel_button_w = mui_secondary_objects_flat[231]; + objects.obj12__ok_button_w = mui_secondary_objects_flat[232]; + objects.obj12__ok_cancel_panel_w = mui_secondary_objects_flat[233]; + objects.obj13 = mui_secondary_objects_flat[234]; + objects.obj13__cancel_button_w = mui_secondary_objects_flat[235]; + objects.obj13__ok_button_w = mui_secondary_objects_flat[236]; + objects.obj13__ok_cancel_panel_w = mui_secondary_objects_flat[237]; + objects.obj14 = mui_secondary_objects_flat[238]; + objects.obj14__cancel_button_w = mui_secondary_objects_flat[239]; + objects.obj14__ok_button_w = mui_secondary_objects_flat[240]; + objects.obj14__ok_cancel_panel_w = mui_secondary_objects_flat[241]; + objects.obj15 = mui_secondary_objects_flat[242]; + objects.obj15__cancel_button_w = mui_secondary_objects_flat[243]; + objects.obj15__ok_button_w = mui_secondary_objects_flat[244]; + objects.obj15__ok_cancel_panel_w = mui_secondary_objects_flat[245]; + objects.obj16 = mui_secondary_objects_flat[246]; + objects.obj16__cancel_button_w = mui_secondary_objects_flat[247]; + objects.obj16__ok_button_w = mui_secondary_objects_flat[248]; + objects.obj16__ok_cancel_panel_w = mui_secondary_objects_flat[249]; + objects.obj17 = mui_secondary_objects_flat[250]; + objects.obj17__cancel_button_w = mui_secondary_objects_flat[251]; + objects.obj17__ok_button_w = mui_secondary_objects_flat[252]; + objects.obj17__ok_cancel_panel_w = mui_secondary_objects_flat[253]; + objects.obj18 = mui_secondary_objects_flat[254]; + objects.obj18__cancel_button_w = mui_secondary_objects_flat[255]; + objects.obj18__ok_button_w = mui_secondary_objects_flat[256]; + objects.obj18__ok_cancel_panel_w = mui_secondary_objects_flat[257]; + objects.obj19 = mui_secondary_objects_flat[258]; + objects.obj2 = mui_secondary_objects_flat[259]; + objects.obj20 = mui_secondary_objects_flat[260]; + objects.obj21 = mui_secondary_objects_flat[261]; + objects.obj21__cancel_button_w = mui_secondary_objects_flat[262]; + objects.obj21__ok_button_w = mui_secondary_objects_flat[263]; + objects.obj21__ok_cancel_panel_w = mui_secondary_objects_flat[264]; + objects.obj22 = mui_secondary_objects_flat[265]; + objects.obj23 = mui_secondary_objects_flat[266]; + objects.obj24 = mui_secondary_objects_flat[267]; + objects.obj25 = mui_secondary_objects_flat[268]; + objects.obj26 = mui_secondary_objects_flat[269]; + objects.obj27 = mui_secondary_objects_flat[270]; + objects.obj27__cancel_button_w = mui_secondary_objects_flat[271]; + objects.obj27__ok_button_w = mui_secondary_objects_flat[272]; + objects.obj27__ok_cancel_panel_w = mui_secondary_objects_flat[273]; + objects.obj2__cancel_button_w = mui_secondary_objects_flat[274]; + objects.obj2__ok_button_w = mui_secondary_objects_flat[275]; + objects.obj2__ok_cancel_panel_w = mui_secondary_objects_flat[276]; + objects.obj3 = mui_secondary_objects_flat[277]; + objects.obj3__cancel_button_w = mui_secondary_objects_flat[278]; + objects.obj3__ok_button_w = mui_secondary_objects_flat[279]; + objects.obj3__ok_cancel_panel_w = mui_secondary_objects_flat[280]; + objects.obj4 = mui_secondary_objects_flat[281]; + objects.obj4__cancel_button_w = mui_secondary_objects_flat[282]; + objects.obj4__ok_button_w = mui_secondary_objects_flat[283]; + objects.obj4__ok_cancel_panel_w = mui_secondary_objects_flat[284]; + objects.obj5 = mui_secondary_objects_flat[285]; + objects.obj5__cancel_button_w = mui_secondary_objects_flat[286]; + objects.obj5__ok_button_w = mui_secondary_objects_flat[287]; + objects.obj5__ok_cancel_panel_w = mui_secondary_objects_flat[288]; + objects.obj6 = mui_secondary_objects_flat[289]; + objects.obj6__cancel_button_w = mui_secondary_objects_flat[290]; + objects.obj6__ok_button_w = mui_secondary_objects_flat[291]; + objects.obj6__ok_cancel_panel_w = mui_secondary_objects_flat[292]; + objects.obj7 = mui_secondary_objects_flat[293]; + objects.obj7__cancel_button_w = mui_secondary_objects_flat[294]; + objects.obj7__ok_button_w = mui_secondary_objects_flat[295]; + objects.obj7__ok_cancel_panel_w = mui_secondary_objects_flat[296]; + objects.obj8 = mui_secondary_objects_flat[297]; + objects.obj8__cancel_button_w = mui_secondary_objects_flat[298]; + objects.obj8__ok_button_w = mui_secondary_objects_flat[299]; + objects.obj8__ok_cancel_panel_w = mui_secondary_objects_flat[300]; + objects.obj9 = mui_secondary_objects_flat[301]; + objects.obj9__cancel_button_w = mui_secondary_objects_flat[302]; + objects.obj9__ok_button_w = mui_secondary_objects_flat[303]; + objects.obj9__ok_cancel_panel_w = mui_secondary_objects_flat[304]; + objects.position2_label = mui_secondary_objects_flat[305]; + objects.position_label = mui_secondary_objects_flat[306]; + objects.progmode_button = mui_secondary_objects_flat[307]; + objects.radar_beam = mui_secondary_objects_flat[308]; + objects.raw_map_panel = mui_secondary_objects_flat[309]; + objects.reboot_button = mui_secondary_objects_flat[310]; + objects.reboot_panel = mui_secondary_objects_flat[311]; + objects.route_back_panel = mui_secondary_objects_flat[312]; + objects.route_towards_panel = mui_secondary_objects_flat[313]; + objects.rssi_slider = mui_secondary_objects_flat[314]; + objects.screen_lock_button_matrix = mui_secondary_objects_flat[315]; + objects.screen_timeout_slider = mui_secondary_objects_flat[316]; + objects.settings_alert_buzzer_panel = mui_secondary_objects_flat[317]; + objects.settings_alert_buzzer_switch = mui_secondary_objects_flat[318]; + objects.settings_backup_checkbox = mui_secondary_objects_flat[319]; + objects.settings_backup_restore_dropdown = mui_secondary_objects_flat[320]; + objects.settings_backup_restore_panel = mui_secondary_objects_flat[321]; + objects.settings_brightness_label = mui_secondary_objects_flat[322]; + objects.settings_brightness_panel = mui_secondary_objects_flat[323]; + objects.settings_button = mui_secondary_objects_flat[324]; + objects.settings_channel0_button = mui_secondary_objects_flat[325]; + objects.settings_channel0_label = mui_secondary_objects_flat[326]; + objects.settings_channel1_button = mui_secondary_objects_flat[327]; + objects.settings_channel1_label = mui_secondary_objects_flat[328]; + objects.settings_channel2_button = mui_secondary_objects_flat[329]; + objects.settings_channel2_label = mui_secondary_objects_flat[330]; + objects.settings_channel3_button = mui_secondary_objects_flat[331]; + objects.settings_channel3_label = mui_secondary_objects_flat[332]; + objects.settings_channel4_button = mui_secondary_objects_flat[333]; + objects.settings_channel4_label = mui_secondary_objects_flat[334]; + objects.settings_channel5_button = mui_secondary_objects_flat[335]; + objects.settings_channel5_label = mui_secondary_objects_flat[336]; + objects.settings_channel6_button = mui_secondary_objects_flat[337]; + objects.settings_channel6_label = mui_secondary_objects_flat[338]; + objects.settings_channel7_button = mui_secondary_objects_flat[339]; + objects.settings_channel7_label = mui_secondary_objects_flat[340]; + objects.settings_channel_panel = mui_secondary_objects_flat[341]; + objects.settings_device_role_dropdown = mui_secondary_objects_flat[342]; + objects.settings_device_role_panel = mui_secondary_objects_flat[343]; + objects.settings_input_control_panel = mui_secondary_objects_flat[344]; + objects.settings_keyboard_input_dropdown = mui_secondary_objects_flat[345]; + objects.settings_language_dropdown = mui_secondary_objects_flat[346]; + objects.settings_language_panel = mui_secondary_objects_flat[347]; + objects.settings_modem_preset_dropdown = mui_secondary_objects_flat[348]; + objects.settings_modem_preset_panel = mui_secondary_objects_flat[349]; + objects.settings_modify_channel_key_generate_button = mui_secondary_objects_flat[350]; + objects.settings_modify_channel_name_textarea = mui_secondary_objects_flat[351]; + objects.settings_modify_channel_panel = mui_secondary_objects_flat[352]; + objects.settings_modify_channel_psk_textarea = mui_secondary_objects_flat[353]; + objects.settings_modify_channel_qr_button = mui_secondary_objects_flat[354]; + objects.settings_modify_channel_qr_panel = mui_secondary_objects_flat[355]; + objects.settings_modify_trash_button = mui_secondary_objects_flat[356]; + objects.settings_mouse_input_dropdown = mui_secondary_objects_flat[357]; + objects.settings_reboot_panel = mui_secondary_objects_flat[358]; + objects.settings_region_dropdown = mui_secondary_objects_flat[359]; + objects.settings_region_panel = mui_secondary_objects_flat[360]; + objects.settings_reset_dropdown = mui_secondary_objects_flat[361]; + objects.settings_reset_panel = mui_secondary_objects_flat[362]; + objects.settings_restore_checkbox = mui_secondary_objects_flat[363]; + objects.settings_ringtone_dropdown = mui_secondary_objects_flat[364]; + objects.settings_screen_lock_panel = mui_secondary_objects_flat[365]; + objects.settings_screen_lock_password_textarea = mui_secondary_objects_flat[366]; + objects.settings_screen_lock_switch = mui_secondary_objects_flat[367]; + objects.settings_screen_timeout_label = mui_secondary_objects_flat[368]; + objects.settings_screen_timeout_panel = mui_secondary_objects_flat[369]; + objects.settings_settings_lock_switch = mui_secondary_objects_flat[370]; + objects.settings_theme_dropdown = mui_secondary_objects_flat[371]; + objects.settings_theme_panel = mui_secondary_objects_flat[372]; + objects.settings_timezone = mui_secondary_objects_flat[373]; + objects.settings_tzcity = mui_secondary_objects_flat[374]; + objects.settings_tzzone = mui_secondary_objects_flat[375]; + objects.settings_user_long_textarea = mui_secondary_objects_flat[376]; + objects.settings_user_short_textarea = mui_secondary_objects_flat[377]; + objects.settings_username_panel = mui_secondary_objects_flat[378]; + objects.settings_wifi_panel = mui_secondary_objects_flat[379]; + objects.settings_wifi_password_textarea = mui_secondary_objects_flat[380]; + objects.settings_wifi_ssid_textarea = mui_secondary_objects_flat[381]; + objects.setup_panel = mui_secondary_objects_flat[382]; + objects.setup_region_dropdown = mui_secondary_objects_flat[383]; + objects.setup_user_long_textarea = mui_secondary_objects_flat[384]; + objects.setup_user_short_textarea = mui_secondary_objects_flat[385]; + objects.shutdown_button = mui_secondary_objects_flat[386]; + objects.signal_label = mui_secondary_objects_flat[387]; + objects.signal_scanner_node_button = mui_secondary_objects_flat[388]; + objects.signal_scanner_node_button_label = mui_secondary_objects_flat[389]; + objects.signal_scanner_node_image = mui_secondary_objects_flat[390]; + objects.signal_scanner_panel = mui_secondary_objects_flat[391]; + objects.signal_scanner_rssi_label = mui_secondary_objects_flat[392]; + objects.signal_scanner_rssi_scale_label = mui_secondary_objects_flat[393]; + objects.signal_scanner_snr_label = mui_secondary_objects_flat[394]; + objects.signal_scanner_snr_scale_label = mui_secondary_objects_flat[395]; + objects.signal_scanner_start_button = mui_secondary_objects_flat[396]; + objects.signal_scanner_start_label = mui_secondary_objects_flat[397]; + objects.snr_slider = mui_secondary_objects_flat[398]; + objects.start_button_panel = mui_secondary_objects_flat[399]; + objects.statistics_table = mui_secondary_objects_flat[400]; + objects.tab_page_basic_settings = mui_secondary_objects_flat[401]; + objects.tab_page_filter = mui_secondary_objects_flat[402]; + objects.tab_page_highlight = mui_secondary_objects_flat[403]; + objects.tab_page_tools = mui_secondary_objects_flat[404]; + objects.telemetry1_label = mui_secondary_objects_flat[405]; + objects.telemetry2_label = mui_secondary_objects_flat[406]; + objects.tools_mesh_detector_button = mui_secondary_objects_flat[407]; + objects.tools_mesh_detector_label = mui_secondary_objects_flat[408]; + objects.tools_neighbors_button = mui_secondary_objects_flat[409]; + objects.tools_neighbors_label = mui_secondary_objects_flat[410]; + objects.tools_packet_log_button = mui_secondary_objects_flat[411]; + objects.tools_packet_log_label = mui_secondary_objects_flat[412]; + objects.tools_packet_log_panel = mui_secondary_objects_flat[413]; + objects.tools_signal_scanner_button = mui_secondary_objects_flat[414]; + objects.tools_signal_scanner_label = mui_secondary_objects_flat[415]; + objects.tools_statistics_button = mui_secondary_objects_flat[416]; + objects.tools_statistics_label = mui_secondary_objects_flat[417]; + objects.tools_statistics_panel = mui_secondary_objects_flat[418]; + objects.tools_trace_route_button = mui_secondary_objects_flat[419]; + objects.tools_trace_route_label = mui_secondary_objects_flat[420]; + objects.top_advanced_settings_image = mui_secondary_objects_flat[421]; + objects.top_advanced_settings_label = mui_secondary_objects_flat[422]; + objects.top_advanced_settings_panel = mui_secondary_objects_flat[423]; + objects.top_basic_settings_image = mui_secondary_objects_flat[424]; + objects.top_basic_settings_label = mui_secondary_objects_flat[425]; + objects.top_chats_image = mui_secondary_objects_flat[426]; + objects.top_chats_label = mui_secondary_objects_flat[427]; + objects.top_chats_panel = mui_secondary_objects_flat[428]; + objects.top_group_chat_image = mui_secondary_objects_flat[429]; + objects.top_group_chat_label = mui_secondary_objects_flat[430]; + objects.top_group_chat_panel = mui_secondary_objects_flat[431]; + objects.top_group_image = mui_secondary_objects_flat[432]; + objects.top_groups_panel = mui_secondary_objects_flat[433]; + objects.top_lora_tx_image = mui_secondary_objects_flat[434]; + objects.top_lora_tx_label = mui_secondary_objects_flat[435]; + objects.top_lora_tx_panel = mui_secondary_objects_flat[436]; + objects.top_map_image = mui_secondary_objects_flat[437]; + objects.top_map_label = mui_secondary_objects_flat[438]; + objects.top_map_panel = mui_secondary_objects_flat[439]; + objects.top_mesh_detector_image = mui_secondary_objects_flat[440]; + objects.top_mesh_detector_label = mui_secondary_objects_flat[441]; + objects.top_mesh_detector_panel = mui_secondary_objects_flat[442]; + objects.top_messages_node_image = mui_secondary_objects_flat[443]; + objects.top_messages_node_label = mui_secondary_objects_flat[444]; + objects.top_messages_panel = mui_secondary_objects_flat[445]; + objects.top_neighbors_image = mui_secondary_objects_flat[446]; + objects.top_neighbors_label = mui_secondary_objects_flat[447]; + objects.top_neighbors_panel = mui_secondary_objects_flat[448]; + objects.top_node_options_image = mui_secondary_objects_flat[449]; + objects.top_node_options_label = mui_secondary_objects_flat[450]; + objects.top_node_options_panel = mui_secondary_objects_flat[451]; + objects.top_node_search_image = mui_secondary_objects_flat[452]; + objects.top_node_search_label = mui_secondary_objects_flat[453]; + objects.top_node_search_panel = mui_secondary_objects_flat[454]; + objects.top_nodes_image = mui_secondary_objects_flat[455]; + objects.top_nodes_online_label = mui_secondary_objects_flat[456]; + objects.top_nodes_panel = mui_secondary_objects_flat[457]; + objects.top_packet_log_image = mui_secondary_objects_flat[458]; + objects.top_packet_log_label = mui_secondary_objects_flat[459]; + objects.top_packet_log_panel = mui_secondary_objects_flat[460]; + objects.top_panel = mui_secondary_objects_flat[461]; + objects.top_settings_panel = mui_secondary_objects_flat[462]; + objects.top_setup_image = mui_secondary_objects_flat[463]; + objects.top_setup_label = mui_secondary_objects_flat[464]; + objects.top_setup_panel = mui_secondary_objects_flat[465]; + objects.top_signal_scanner_image = mui_secondary_objects_flat[466]; + objects.top_signal_scanner_label = mui_secondary_objects_flat[467]; + objects.top_signal_scanner_panel = mui_secondary_objects_flat[468]; + objects.top_statistics_image = mui_secondary_objects_flat[469]; + objects.top_statistics_label = mui_secondary_objects_flat[470]; + objects.top_statistics_panel = mui_secondary_objects_flat[471]; + objects.top_trace_route_image = mui_secondary_objects_flat[472]; + objects.top_trace_route_label = mui_secondary_objects_flat[473]; + objects.top_trace_route_panel = mui_secondary_objects_flat[474]; + objects.top_user_group_label = mui_secondary_objects_flat[475]; + objects.trace_route_panel = mui_secondary_objects_flat[476]; + objects.trace_route_start_button = mui_secondary_objects_flat[477]; + objects.trace_route_start_label = mui_secondary_objects_flat[478]; + objects.trace_route_to_button = mui_secondary_objects_flat[479]; + objects.trace_route_to_button_label = mui_secondary_objects_flat[480]; + objects.trace_route_to_image = mui_secondary_objects_flat[481]; + objects.user_name_label = mui_secondary_objects_flat[482]; + objects.user_name_short_label = mui_secondary_objects_flat[483]; + objects.zoom_in_button = mui_secondary_objects_flat[484]; + objects.zoom_out_button = mui_secondary_objects_flat[485]; + objects.zoom_slider = mui_secondary_objects_flat[486]; + ui_AdvancedSettingsPanel = mui_secondary_ui_flat[0]; + ui_AmbientLightingLabel = mui_secondary_ui_flat[1]; + ui_AudioLabel = mui_secondary_ui_flat[2]; + ui_AudioLabel1 = mui_secondary_ui_flat[3]; + ui_BluetoothLabel = mui_secondary_ui_flat[4]; + ui_CannedMsgLabel = mui_secondary_ui_flat[5]; + ui_DetectionSensorLabel = mui_secondary_ui_flat[6]; + ui_DeviceLabel = mui_secondary_ui_flat[7]; + ui_DisplayLabel = mui_secondary_ui_flat[8]; + ui_ExtNotificationLabel = mui_secondary_ui_flat[9]; + ui_GeneralAudioButton = mui_secondary_ui_flat[10]; + ui_GeneralLanguageButton = mui_secondary_ui_flat[11]; + ui_GeneralMapsButton = mui_secondary_ui_flat[12]; + ui_GeneralScreenButton = mui_secondary_ui_flat[13]; + ui_GeneralTimezoneButton = mui_secondary_ui_flat[14]; + ui_LanguageLabel = mui_secondary_ui_flat[15]; + ui_LoRaLabel = mui_secondary_ui_flat[16]; + ui_MQTTLabel = mui_secondary_ui_flat[17]; + ui_MapsLabel = mui_secondary_ui_flat[18]; + ui_ModuleAmbientLightingButton = mui_secondary_ui_flat[19]; + ui_ModuleAudioButton = mui_secondary_ui_flat[20]; + ui_ModuleCannedMsgButton = mui_secondary_ui_flat[21]; + ui_ModuleDetectionSensorButton = mui_secondary_ui_flat[22]; + ui_ModuleExtNotificationButton = mui_secondary_ui_flat[23]; + ui_ModuleMQTTButton = mui_secondary_ui_flat[24]; + ui_ModuleNeighborInfoButton = mui_secondary_ui_flat[25]; + ui_ModuleRangeTestButton = mui_secondary_ui_flat[26]; + ui_ModuleRemoteHardwareButton = mui_secondary_ui_flat[27]; + ui_ModuleSaFButton = mui_secondary_ui_flat[28]; + ui_ModuleSerialButton = mui_secondary_ui_flat[29]; + ui_ModuleTelemetryButton = mui_secondary_ui_flat[30]; + ui_NeighborInfoLabel = mui_secondary_ui_flat[31]; + ui_NetworkLabel = mui_secondary_ui_flat[32]; + ui_PositionLabel = mui_secondary_ui_flat[33]; + ui_PowerLabel = mui_secondary_ui_flat[34]; + ui_RadioBluetoothButton = mui_secondary_ui_flat[35]; + ui_RadioDeviceButton = mui_secondary_ui_flat[36]; + ui_RadioDisplayButton = mui_secondary_ui_flat[37]; + ui_RadioLoRaButton = mui_secondary_ui_flat[38]; + ui_RadioNetworkButton = mui_secondary_ui_flat[39]; + ui_RadioPositionButton = mui_secondary_ui_flat[40]; + ui_RadioPowerButton = mui_secondary_ui_flat[41]; + ui_RangeTestLabel = mui_secondary_ui_flat[42]; + ui_RemoteHardwareLabel = mui_secondary_ui_flat[43]; + ui_ScreenLabel = mui_secondary_ui_flat[44]; + ui_SerialLabel = mui_secondary_ui_flat[45]; + ui_SettingsTabView = mui_secondary_ui_flat[46]; + ui_StoreAndForwardLabel = mui_secondary_ui_flat[47]; + ui_TabPageGeneral = mui_secondary_ui_flat[48]; + ui_TabPageModules = mui_secondary_ui_flat[49]; + ui_TabPageRadio = mui_secondary_ui_flat[50]; + ui_TelemetryLabel = mui_secondary_ui_flat[51]; + ui_TimezoneLabel = mui_secondary_ui_flat[52]; +} diff --git a/tools/generated/dual/bridge_secondary.c b/tools/generated/dual/bridge_secondary.c new file mode 100644 index 00000000..218ad18f --- /dev/null +++ b/tools/generated/dual/bridge_secondary.c @@ -0,0 +1,551 @@ +// GENERATED by tools/gen_dual_ui.py - do not edit. +// Secondary tree (renamed): flatten objects + ui_* pointers into +// canonical (alphabetical) order. +#include "screens.h" + +lv_obj_t *mui_secondary_objects_flat[487]; +lv_obj_t *mui_secondary_ui_flat[53]; + +void mui_bridge_collect_secondary(void) +{ + mui_secondary_objects_flat[0] = objects.advanced_settings_panel; + mui_secondary_objects_flat[1] = objects.alert_label; + mui_secondary_objects_flat[2] = objects.alert_panel; + mui_secondary_objects_flat[3] = objects.arrow_down_button; + mui_secondary_objects_flat[4] = objects.arrow_left_button; + mui_secondary_objects_flat[5] = objects.arrow_right_button; + mui_secondary_objects_flat[6] = objects.arrow_up_button; + mui_secondary_objects_flat[7] = objects.basic_settings_alert_button; + mui_secondary_objects_flat[8] = objects.basic_settings_alert_label; + mui_secondary_objects_flat[9] = objects.basic_settings_backup_restore_button; + mui_secondary_objects_flat[10] = objects.basic_settings_backup_restore_label; + mui_secondary_objects_flat[11] = objects.basic_settings_brightness_button; + mui_secondary_objects_flat[12] = objects.basic_settings_brightness_label; + mui_secondary_objects_flat[13] = objects.basic_settings_calibration_button; + mui_secondary_objects_flat[14] = objects.basic_settings_calibration_label; + mui_secondary_objects_flat[15] = objects.basic_settings_channel_button; + mui_secondary_objects_flat[16] = objects.basic_settings_channel_label; + mui_secondary_objects_flat[17] = objects.basic_settings_input_button; + mui_secondary_objects_flat[18] = objects.basic_settings_input_label; + mui_secondary_objects_flat[19] = objects.basic_settings_language_button; + mui_secondary_objects_flat[20] = objects.basic_settings_language_label; + mui_secondary_objects_flat[21] = objects.basic_settings_modem_preset_button; + mui_secondary_objects_flat[22] = objects.basic_settings_modem_preset_label; + mui_secondary_objects_flat[23] = objects.basic_settings_reboot_button; + mui_secondary_objects_flat[24] = objects.basic_settings_reboot_label; + mui_secondary_objects_flat[25] = objects.basic_settings_region_button; + mui_secondary_objects_flat[26] = objects.basic_settings_region_label; + mui_secondary_objects_flat[27] = objects.basic_settings_reset_button; + mui_secondary_objects_flat[28] = objects.basic_settings_reset_label; + mui_secondary_objects_flat[29] = objects.basic_settings_role_button; + mui_secondary_objects_flat[30] = objects.basic_settings_role_label; + mui_secondary_objects_flat[31] = objects.basic_settings_screen_lock_button; + mui_secondary_objects_flat[32] = objects.basic_settings_screen_lock_label; + mui_secondary_objects_flat[33] = objects.basic_settings_theme_button; + mui_secondary_objects_flat[34] = objects.basic_settings_theme_label; + mui_secondary_objects_flat[35] = objects.basic_settings_timeout_button; + mui_secondary_objects_flat[36] = objects.basic_settings_timeout_label; + mui_secondary_objects_flat[37] = objects.basic_settings_timezone_button; + mui_secondary_objects_flat[38] = objects.basic_settings_timezone_label; + mui_secondary_objects_flat[39] = objects.basic_settings_user_button; + mui_secondary_objects_flat[40] = objects.basic_settings_user_label; + mui_secondary_objects_flat[41] = objects.basic_settings_wifi_button; + mui_secondary_objects_flat[42] = objects.basic_settings_wifi_label; + mui_secondary_objects_flat[43] = objects.battery_image; + mui_secondary_objects_flat[44] = objects.battery_label; + mui_secondary_objects_flat[45] = objects.battery_panel; + mui_secondary_objects_flat[46] = objects.battery_percentage_label; + mui_secondary_objects_flat[47] = objects.blank_screen; + mui_secondary_objects_flat[48] = objects.blank_screen_button; + mui_secondary_objects_flat[49] = objects.bluetooth_button; + mui_secondary_objects_flat[50] = objects.boot_logo; + mui_secondary_objects_flat[51] = objects.boot_logo_arc; + mui_secondary_objects_flat[52] = objects.boot_logo_button; + mui_secondary_objects_flat[53] = objects.boot_screen; + mui_secondary_objects_flat[54] = objects.brightness_slider; + mui_secondary_objects_flat[55] = objects.button_panel; + mui_secondary_objects_flat[56] = objects.calibration_screen; + mui_secondary_objects_flat[57] = objects.cancel_reboot_button; + mui_secondary_objects_flat[58] = objects.channel_button0; + mui_secondary_objects_flat[59] = objects.channel_button1; + mui_secondary_objects_flat[60] = objects.channel_button2; + mui_secondary_objects_flat[61] = objects.channel_button3; + mui_secondary_objects_flat[62] = objects.channel_button4; + mui_secondary_objects_flat[63] = objects.channel_button5; + mui_secondary_objects_flat[64] = objects.channel_button6; + mui_secondary_objects_flat[65] = objects.channel_button7; + mui_secondary_objects_flat[66] = objects.channel_label0; + mui_secondary_objects_flat[67] = objects.channel_label1; + mui_secondary_objects_flat[68] = objects.channel_label2; + mui_secondary_objects_flat[69] = objects.channel_label3; + mui_secondary_objects_flat[70] = objects.channel_label4; + mui_secondary_objects_flat[71] = objects.channel_label5; + mui_secondary_objects_flat[72] = objects.channel_label6; + mui_secondary_objects_flat[73] = objects.channel_label7; + mui_secondary_objects_flat[74] = objects.chat_del_button; + mui_secondary_objects_flat[75] = objects.chats_button; + mui_secondary_objects_flat[76] = objects.chats_button_label; + mui_secondary_objects_flat[77] = objects.chats_panel; + mui_secondary_objects_flat[78] = objects.controller_panel; + mui_secondary_objects_flat[79] = objects.controller_tab_view; + mui_secondary_objects_flat[80] = objects.del_label; + mui_secondary_objects_flat[81] = objects.details_panel; + mui_secondary_objects_flat[82] = objects.detected_node_button; + mui_secondary_objects_flat[83] = objects.detected_node_image; + mui_secondary_objects_flat[84] = objects.detected_node_label; + mui_secondary_objects_flat[85] = objects.detector_contact_button; + mui_secondary_objects_flat[86] = objects.detector_contact_image; + mui_secondary_objects_flat[87] = objects.detector_contact_label; + mui_secondary_objects_flat[88] = objects.detector_heard_label; + mui_secondary_objects_flat[89] = objects.detector_radar_panel; + mui_secondary_objects_flat[90] = objects.detector_start_button; + mui_secondary_objects_flat[91] = objects.detector_start_button_panel; + mui_secondary_objects_flat[92] = objects.detector_start_label; + mui_secondary_objects_flat[93] = objects.firmware_label; + mui_secondary_objects_flat[94] = objects.frequency_slot_label; + mui_secondary_objects_flat[95] = objects.frequency_slot_slider; + mui_secondary_objects_flat[96] = objects.google_logo_image; + mui_secondary_objects_flat[97] = objects.gps_lock_button; + mui_secondary_objects_flat[98] = objects.gps_position_image; + mui_secondary_objects_flat[99] = objects.groups_button; + mui_secondary_objects_flat[100] = objects.groups_panel; + mui_secondary_objects_flat[101] = objects.home_bell_button; + mui_secondary_objects_flat[102] = objects.home_bell_label; + mui_secondary_objects_flat[103] = objects.home_bluetooth_button; + mui_secondary_objects_flat[104] = objects.home_bluetooth_label; + mui_secondary_objects_flat[105] = objects.home_button; + mui_secondary_objects_flat[106] = objects.home_cancel_qr_button; + mui_secondary_objects_flat[107] = objects.home_container; + mui_secondary_objects_flat[108] = objects.home_ethernet_button; + mui_secondary_objects_flat[109] = objects.home_ethernet_label; + mui_secondary_objects_flat[110] = objects.home_location_button; + mui_secondary_objects_flat[111] = objects.home_location_image; + mui_secondary_objects_flat[112] = objects.home_location_label; + mui_secondary_objects_flat[113] = objects.home_lora_button; + mui_secondary_objects_flat[114] = objects.home_lora_label; + mui_secondary_objects_flat[115] = objects.home_mail_button; + mui_secondary_objects_flat[116] = objects.home_mail_label; + mui_secondary_objects_flat[117] = objects.home_memory_button; + mui_secondary_objects_flat[118] = objects.home_memory_label; + mui_secondary_objects_flat[119] = objects.home_mqtt_button; + mui_secondary_objects_flat[120] = objects.home_mqtt_label; + mui_secondary_objects_flat[121] = objects.home_nodes_button; + mui_secondary_objects_flat[122] = objects.home_nodes_label; + mui_secondary_objects_flat[123] = objects.home_panel; + mui_secondary_objects_flat[124] = objects.home_qr_button; + mui_secondary_objects_flat[125] = objects.home_qr_label; + mui_secondary_objects_flat[126] = objects.home_sd_card_button; + mui_secondary_objects_flat[127] = objects.home_sd_card_label; + mui_secondary_objects_flat[128] = objects.home_show_qr_panel; + mui_secondary_objects_flat[129] = objects.home_signal_button; + mui_secondary_objects_flat[130] = objects.home_signal_label; + mui_secondary_objects_flat[131] = objects.home_signal_pct_label; + mui_secondary_objects_flat[132] = objects.home_time_button; + mui_secondary_objects_flat[133] = objects.home_time_label; + mui_secondary_objects_flat[134] = objects.home_wlan_button; + mui_secondary_objects_flat[135] = objects.home_wlan_label; + mui_secondary_objects_flat[136] = objects.hop_routes_panel; + mui_secondary_objects_flat[137] = objects.initial_setup_panel; + mui_secondary_objects_flat[138] = objects.keyboard; + mui_secondary_objects_flat[139] = objects.keyboard_button_0; + mui_secondary_objects_flat[140] = objects.keyboard_button_1; + mui_secondary_objects_flat[141] = objects.keyboard_button_10; + mui_secondary_objects_flat[142] = objects.keyboard_button_11; + mui_secondary_objects_flat[143] = objects.keyboard_button_2; + mui_secondary_objects_flat[144] = objects.keyboard_button_3; + mui_secondary_objects_flat[145] = objects.keyboard_button_4; + mui_secondary_objects_flat[146] = objects.keyboard_button_5; + mui_secondary_objects_flat[147] = objects.keyboard_button_6; + mui_secondary_objects_flat[148] = objects.keyboard_button_7; + mui_secondary_objects_flat[149] = objects.keyboard_button_8; + mui_secondary_objects_flat[150] = objects.keyboard_button_9; + mui_secondary_objects_flat[151] = objects.last_heard_label; + mui_secondary_objects_flat[152] = objects.lock_screen; + mui_secondary_objects_flat[153] = objects.lock_screen_digits_label; + mui_secondary_objects_flat[154] = objects.main_screen; + mui_secondary_objects_flat[155] = objects.map_brightness_slider; + mui_secondary_objects_flat[156] = objects.map_button; + mui_secondary_objects_flat[157] = objects.map_contrast_slider; + mui_secondary_objects_flat[158] = objects.map_location_label; + mui_secondary_objects_flat[159] = objects.map_osd_panel; + mui_secondary_objects_flat[160] = objects.map_panel; + mui_secondary_objects_flat[161] = objects.map_style_dropdown; + mui_secondary_objects_flat[162] = objects.map_url_dropdown; + mui_secondary_objects_flat[163] = objects.mesh_detector_panel; + mui_secondary_objects_flat[164] = objects.meshtastic_image; + mui_secondary_objects_flat[165] = objects.meshtastic_label; + mui_secondary_objects_flat[166] = objects.meshtastic_url; + mui_secondary_objects_flat[167] = objects.message_input_area; + mui_secondary_objects_flat[168] = objects.message_restore_bar; + mui_secondary_objects_flat[169] = objects.messages_button; + mui_secondary_objects_flat[170] = objects.messages_container; + mui_secondary_objects_flat[171] = objects.messages_panel; + mui_secondary_objects_flat[172] = objects.msg_popup_button; + mui_secondary_objects_flat[173] = objects.msg_popup_label; + mui_secondary_objects_flat[174] = objects.msg_popup_panel; + mui_secondary_objects_flat[175] = objects.msg_restore_button; + mui_secondary_objects_flat[176] = objects.msg_restore_label; + mui_secondary_objects_flat[177] = objects.msg_restore_panel; + mui_secondary_objects_flat[178] = objects.nav_button; + mui_secondary_objects_flat[179] = objects.navigation_panel; + mui_secondary_objects_flat[180] = objects.node_button; + mui_secondary_objects_flat[181] = objects.node_details_battery_label; + mui_secondary_objects_flat[182] = objects.node_details_image; + mui_secondary_objects_flat[183] = objects.node_details_last_heard_label; + mui_secondary_objects_flat[184] = objects.node_details_name_label; + mui_secondary_objects_flat[185] = objects.node_details_name_short_label; + mui_secondary_objects_flat[186] = objects.node_details_panel; + mui_secondary_objects_flat[187] = objects.node_details_signal_label; + mui_secondary_objects_flat[188] = objects.node_image; + mui_secondary_objects_flat[189] = objects.node_options_panel; + mui_secondary_objects_flat[190] = objects.node_options_tab_view; + mui_secondary_objects_flat[191] = objects.node_panel; + mui_secondary_objects_flat[192] = objects.nodes_button; + mui_secondary_objects_flat[193] = objects.nodes_filter_channel_dropdown; + mui_secondary_objects_flat[194] = objects.nodes_filter_channel_label; + mui_secondary_objects_flat[195] = objects.nodes_filter_hops_away_label; + mui_secondary_objects_flat[196] = objects.nodes_filter_hops_dropdown; + mui_secondary_objects_flat[197] = objects.nodes_filter_mqtt_label; + mui_secondary_objects_flat[198] = objects.nodes_filter_mqtt_switch; + mui_secondary_objects_flat[199] = objects.nodes_filter_name_area; + mui_secondary_objects_flat[200] = objects.nodes_filter_name_label; + mui_secondary_objects_flat[201] = objects.nodes_filter_offline_label; + mui_secondary_objects_flat[202] = objects.nodes_filter_offline_switch; + mui_secondary_objects_flat[203] = objects.nodes_filter_position_label; + mui_secondary_objects_flat[204] = objects.nodes_filter_position_switch; + mui_secondary_objects_flat[205] = objects.nodes_filter_public_key_label; + mui_secondary_objects_flat[206] = objects.nodes_filter_public_key_switch; + mui_secondary_objects_flat[207] = objects.nodes_filter_unknown_label; + mui_secondary_objects_flat[208] = objects.nodes_filter_unknown_switch; + mui_secondary_objects_flat[209] = objects.nodes_hl_active_chat_label; + mui_secondary_objects_flat[210] = objects.nodes_hl_active_chat_switch; + mui_secondary_objects_flat[211] = objects.nodes_hl_name_area; + mui_secondary_objects_flat[212] = objects.nodes_hl_name_label; + mui_secondary_objects_flat[213] = objects.nodes_hl_position_label; + mui_secondary_objects_flat[214] = objects.nodes_hl_position_switch; + mui_secondary_objects_flat[215] = objects.nodes_hl_telemetry_label; + mui_secondary_objects_flat[216] = objects.nodes_hl_telemetry_switch; + mui_secondary_objects_flat[217] = objects.nodes_hliaq_label; + mui_secondary_objects_flat[218] = objects.nodes_hliaq_switch; + mui_secondary_objects_flat[219] = objects.nodes_panel; + mui_secondary_objects_flat[220] = objects.obj0; + mui_secondary_objects_flat[221] = objects.obj1; + mui_secondary_objects_flat[222] = objects.obj10; + mui_secondary_objects_flat[223] = objects.obj10__cancel_button_w; + mui_secondary_objects_flat[224] = objects.obj10__ok_button_w; + mui_secondary_objects_flat[225] = objects.obj10__ok_cancel_panel_w; + mui_secondary_objects_flat[226] = objects.obj11; + mui_secondary_objects_flat[227] = objects.obj11__cancel_button_w; + mui_secondary_objects_flat[228] = objects.obj11__ok_button_w; + mui_secondary_objects_flat[229] = objects.obj11__ok_cancel_panel_w; + mui_secondary_objects_flat[230] = objects.obj12; + mui_secondary_objects_flat[231] = objects.obj12__cancel_button_w; + mui_secondary_objects_flat[232] = objects.obj12__ok_button_w; + mui_secondary_objects_flat[233] = objects.obj12__ok_cancel_panel_w; + mui_secondary_objects_flat[234] = objects.obj13; + mui_secondary_objects_flat[235] = objects.obj13__cancel_button_w; + mui_secondary_objects_flat[236] = objects.obj13__ok_button_w; + mui_secondary_objects_flat[237] = objects.obj13__ok_cancel_panel_w; + mui_secondary_objects_flat[238] = objects.obj14; + mui_secondary_objects_flat[239] = objects.obj14__cancel_button_w; + mui_secondary_objects_flat[240] = objects.obj14__ok_button_w; + mui_secondary_objects_flat[241] = objects.obj14__ok_cancel_panel_w; + mui_secondary_objects_flat[242] = objects.obj15; + mui_secondary_objects_flat[243] = objects.obj15__cancel_button_w; + mui_secondary_objects_flat[244] = objects.obj15__ok_button_w; + mui_secondary_objects_flat[245] = objects.obj15__ok_cancel_panel_w; + mui_secondary_objects_flat[246] = objects.obj16; + mui_secondary_objects_flat[247] = objects.obj16__cancel_button_w; + mui_secondary_objects_flat[248] = objects.obj16__ok_button_w; + mui_secondary_objects_flat[249] = objects.obj16__ok_cancel_panel_w; + mui_secondary_objects_flat[250] = objects.obj17; + mui_secondary_objects_flat[251] = objects.obj17__cancel_button_w; + mui_secondary_objects_flat[252] = objects.obj17__ok_button_w; + mui_secondary_objects_flat[253] = objects.obj17__ok_cancel_panel_w; + mui_secondary_objects_flat[254] = objects.obj18; + mui_secondary_objects_flat[255] = objects.obj18__cancel_button_w; + mui_secondary_objects_flat[256] = objects.obj18__ok_button_w; + mui_secondary_objects_flat[257] = objects.obj18__ok_cancel_panel_w; + mui_secondary_objects_flat[258] = objects.obj19; + mui_secondary_objects_flat[259] = objects.obj2; + mui_secondary_objects_flat[260] = objects.obj20; + mui_secondary_objects_flat[261] = objects.obj21; + mui_secondary_objects_flat[262] = objects.obj21__cancel_button_w; + mui_secondary_objects_flat[263] = objects.obj21__ok_button_w; + mui_secondary_objects_flat[264] = objects.obj21__ok_cancel_panel_w; + mui_secondary_objects_flat[265] = objects.obj22; + mui_secondary_objects_flat[266] = objects.obj23; + mui_secondary_objects_flat[267] = objects.obj24; + mui_secondary_objects_flat[268] = objects.obj25; + mui_secondary_objects_flat[269] = objects.obj26; + mui_secondary_objects_flat[270] = objects.obj27; + mui_secondary_objects_flat[271] = objects.obj27__cancel_button_w; + mui_secondary_objects_flat[272] = objects.obj27__ok_button_w; + mui_secondary_objects_flat[273] = objects.obj27__ok_cancel_panel_w; + mui_secondary_objects_flat[274] = objects.obj2__cancel_button_w; + mui_secondary_objects_flat[275] = objects.obj2__ok_button_w; + mui_secondary_objects_flat[276] = objects.obj2__ok_cancel_panel_w; + mui_secondary_objects_flat[277] = objects.obj3; + mui_secondary_objects_flat[278] = objects.obj3__cancel_button_w; + mui_secondary_objects_flat[279] = objects.obj3__ok_button_w; + mui_secondary_objects_flat[280] = objects.obj3__ok_cancel_panel_w; + mui_secondary_objects_flat[281] = objects.obj4; + mui_secondary_objects_flat[282] = objects.obj4__cancel_button_w; + mui_secondary_objects_flat[283] = objects.obj4__ok_button_w; + mui_secondary_objects_flat[284] = objects.obj4__ok_cancel_panel_w; + mui_secondary_objects_flat[285] = objects.obj5; + mui_secondary_objects_flat[286] = objects.obj5__cancel_button_w; + mui_secondary_objects_flat[287] = objects.obj5__ok_button_w; + mui_secondary_objects_flat[288] = objects.obj5__ok_cancel_panel_w; + mui_secondary_objects_flat[289] = objects.obj6; + mui_secondary_objects_flat[290] = objects.obj6__cancel_button_w; + mui_secondary_objects_flat[291] = objects.obj6__ok_button_w; + mui_secondary_objects_flat[292] = objects.obj6__ok_cancel_panel_w; + mui_secondary_objects_flat[293] = objects.obj7; + mui_secondary_objects_flat[294] = objects.obj7__cancel_button_w; + mui_secondary_objects_flat[295] = objects.obj7__ok_button_w; + mui_secondary_objects_flat[296] = objects.obj7__ok_cancel_panel_w; + mui_secondary_objects_flat[297] = objects.obj8; + mui_secondary_objects_flat[298] = objects.obj8__cancel_button_w; + mui_secondary_objects_flat[299] = objects.obj8__ok_button_w; + mui_secondary_objects_flat[300] = objects.obj8__ok_cancel_panel_w; + mui_secondary_objects_flat[301] = objects.obj9; + mui_secondary_objects_flat[302] = objects.obj9__cancel_button_w; + mui_secondary_objects_flat[303] = objects.obj9__ok_button_w; + mui_secondary_objects_flat[304] = objects.obj9__ok_cancel_panel_w; + mui_secondary_objects_flat[305] = objects.position2_label; + mui_secondary_objects_flat[306] = objects.position_label; + mui_secondary_objects_flat[307] = objects.progmode_button; + mui_secondary_objects_flat[308] = objects.radar_beam; + mui_secondary_objects_flat[309] = objects.raw_map_panel; + mui_secondary_objects_flat[310] = objects.reboot_button; + mui_secondary_objects_flat[311] = objects.reboot_panel; + mui_secondary_objects_flat[312] = objects.route_back_panel; + mui_secondary_objects_flat[313] = objects.route_towards_panel; + mui_secondary_objects_flat[314] = objects.rssi_slider; + mui_secondary_objects_flat[315] = objects.screen_lock_button_matrix; + mui_secondary_objects_flat[316] = objects.screen_timeout_slider; + mui_secondary_objects_flat[317] = objects.settings_alert_buzzer_panel; + mui_secondary_objects_flat[318] = objects.settings_alert_buzzer_switch; + mui_secondary_objects_flat[319] = objects.settings_backup_checkbox; + mui_secondary_objects_flat[320] = objects.settings_backup_restore_dropdown; + mui_secondary_objects_flat[321] = objects.settings_backup_restore_panel; + mui_secondary_objects_flat[322] = objects.settings_brightness_label; + mui_secondary_objects_flat[323] = objects.settings_brightness_panel; + mui_secondary_objects_flat[324] = objects.settings_button; + mui_secondary_objects_flat[325] = objects.settings_channel0_button; + mui_secondary_objects_flat[326] = objects.settings_channel0_label; + mui_secondary_objects_flat[327] = objects.settings_channel1_button; + mui_secondary_objects_flat[328] = objects.settings_channel1_label; + mui_secondary_objects_flat[329] = objects.settings_channel2_button; + mui_secondary_objects_flat[330] = objects.settings_channel2_label; + mui_secondary_objects_flat[331] = objects.settings_channel3_button; + mui_secondary_objects_flat[332] = objects.settings_channel3_label; + mui_secondary_objects_flat[333] = objects.settings_channel4_button; + mui_secondary_objects_flat[334] = objects.settings_channel4_label; + mui_secondary_objects_flat[335] = objects.settings_channel5_button; + mui_secondary_objects_flat[336] = objects.settings_channel5_label; + mui_secondary_objects_flat[337] = objects.settings_channel6_button; + mui_secondary_objects_flat[338] = objects.settings_channel6_label; + mui_secondary_objects_flat[339] = objects.settings_channel7_button; + mui_secondary_objects_flat[340] = objects.settings_channel7_label; + mui_secondary_objects_flat[341] = objects.settings_channel_panel; + mui_secondary_objects_flat[342] = objects.settings_device_role_dropdown; + mui_secondary_objects_flat[343] = objects.settings_device_role_panel; + mui_secondary_objects_flat[344] = objects.settings_input_control_panel; + mui_secondary_objects_flat[345] = objects.settings_keyboard_input_dropdown; + mui_secondary_objects_flat[346] = objects.settings_language_dropdown; + mui_secondary_objects_flat[347] = objects.settings_language_panel; + mui_secondary_objects_flat[348] = objects.settings_modem_preset_dropdown; + mui_secondary_objects_flat[349] = objects.settings_modem_preset_panel; + mui_secondary_objects_flat[350] = objects.settings_modify_channel_key_generate_button; + mui_secondary_objects_flat[351] = objects.settings_modify_channel_name_textarea; + mui_secondary_objects_flat[352] = objects.settings_modify_channel_panel; + mui_secondary_objects_flat[353] = objects.settings_modify_channel_psk_textarea; + mui_secondary_objects_flat[354] = objects.settings_modify_channel_qr_button; + mui_secondary_objects_flat[355] = objects.settings_modify_channel_qr_panel; + mui_secondary_objects_flat[356] = objects.settings_modify_trash_button; + mui_secondary_objects_flat[357] = objects.settings_mouse_input_dropdown; + mui_secondary_objects_flat[358] = objects.settings_reboot_panel; + mui_secondary_objects_flat[359] = objects.settings_region_dropdown; + mui_secondary_objects_flat[360] = objects.settings_region_panel; + mui_secondary_objects_flat[361] = objects.settings_reset_dropdown; + mui_secondary_objects_flat[362] = objects.settings_reset_panel; + mui_secondary_objects_flat[363] = objects.settings_restore_checkbox; + mui_secondary_objects_flat[364] = objects.settings_ringtone_dropdown; + mui_secondary_objects_flat[365] = objects.settings_screen_lock_panel; + mui_secondary_objects_flat[366] = objects.settings_screen_lock_password_textarea; + mui_secondary_objects_flat[367] = objects.settings_screen_lock_switch; + mui_secondary_objects_flat[368] = objects.settings_screen_timeout_label; + mui_secondary_objects_flat[369] = objects.settings_screen_timeout_panel; + mui_secondary_objects_flat[370] = objects.settings_settings_lock_switch; + mui_secondary_objects_flat[371] = objects.settings_theme_dropdown; + mui_secondary_objects_flat[372] = objects.settings_theme_panel; + mui_secondary_objects_flat[373] = objects.settings_timezone; + mui_secondary_objects_flat[374] = objects.settings_tzcity; + mui_secondary_objects_flat[375] = objects.settings_tzzone; + mui_secondary_objects_flat[376] = objects.settings_user_long_textarea; + mui_secondary_objects_flat[377] = objects.settings_user_short_textarea; + mui_secondary_objects_flat[378] = objects.settings_username_panel; + mui_secondary_objects_flat[379] = objects.settings_wifi_panel; + mui_secondary_objects_flat[380] = objects.settings_wifi_password_textarea; + mui_secondary_objects_flat[381] = objects.settings_wifi_ssid_textarea; + mui_secondary_objects_flat[382] = objects.setup_panel; + mui_secondary_objects_flat[383] = objects.setup_region_dropdown; + mui_secondary_objects_flat[384] = objects.setup_user_long_textarea; + mui_secondary_objects_flat[385] = objects.setup_user_short_textarea; + mui_secondary_objects_flat[386] = objects.shutdown_button; + mui_secondary_objects_flat[387] = objects.signal_label; + mui_secondary_objects_flat[388] = objects.signal_scanner_node_button; + mui_secondary_objects_flat[389] = objects.signal_scanner_node_button_label; + mui_secondary_objects_flat[390] = objects.signal_scanner_node_image; + mui_secondary_objects_flat[391] = objects.signal_scanner_panel; + mui_secondary_objects_flat[392] = objects.signal_scanner_rssi_label; + mui_secondary_objects_flat[393] = objects.signal_scanner_rssi_scale_label; + mui_secondary_objects_flat[394] = objects.signal_scanner_snr_label; + mui_secondary_objects_flat[395] = objects.signal_scanner_snr_scale_label; + mui_secondary_objects_flat[396] = objects.signal_scanner_start_button; + mui_secondary_objects_flat[397] = objects.signal_scanner_start_label; + mui_secondary_objects_flat[398] = objects.snr_slider; + mui_secondary_objects_flat[399] = objects.start_button_panel; + mui_secondary_objects_flat[400] = objects.statistics_table; + mui_secondary_objects_flat[401] = objects.tab_page_basic_settings; + mui_secondary_objects_flat[402] = objects.tab_page_filter; + mui_secondary_objects_flat[403] = objects.tab_page_highlight; + mui_secondary_objects_flat[404] = objects.tab_page_tools; + mui_secondary_objects_flat[405] = objects.telemetry1_label; + mui_secondary_objects_flat[406] = objects.telemetry2_label; + mui_secondary_objects_flat[407] = objects.tools_mesh_detector_button; + mui_secondary_objects_flat[408] = objects.tools_mesh_detector_label; + mui_secondary_objects_flat[409] = objects.tools_neighbors_button; + mui_secondary_objects_flat[410] = objects.tools_neighbors_label; + mui_secondary_objects_flat[411] = objects.tools_packet_log_button; + mui_secondary_objects_flat[412] = objects.tools_packet_log_label; + mui_secondary_objects_flat[413] = objects.tools_packet_log_panel; + mui_secondary_objects_flat[414] = objects.tools_signal_scanner_button; + mui_secondary_objects_flat[415] = objects.tools_signal_scanner_label; + mui_secondary_objects_flat[416] = objects.tools_statistics_button; + mui_secondary_objects_flat[417] = objects.tools_statistics_label; + mui_secondary_objects_flat[418] = objects.tools_statistics_panel; + mui_secondary_objects_flat[419] = objects.tools_trace_route_button; + mui_secondary_objects_flat[420] = objects.tools_trace_route_label; + mui_secondary_objects_flat[421] = objects.top_advanced_settings_image; + mui_secondary_objects_flat[422] = objects.top_advanced_settings_label; + mui_secondary_objects_flat[423] = objects.top_advanced_settings_panel; + mui_secondary_objects_flat[424] = objects.top_basic_settings_image; + mui_secondary_objects_flat[425] = objects.top_basic_settings_label; + mui_secondary_objects_flat[426] = objects.top_chats_image; + mui_secondary_objects_flat[427] = objects.top_chats_label; + mui_secondary_objects_flat[428] = objects.top_chats_panel; + mui_secondary_objects_flat[429] = objects.top_group_chat_image; + mui_secondary_objects_flat[430] = objects.top_group_chat_label; + mui_secondary_objects_flat[431] = objects.top_group_chat_panel; + mui_secondary_objects_flat[432] = objects.top_group_image; + mui_secondary_objects_flat[433] = objects.top_groups_panel; + mui_secondary_objects_flat[434] = objects.top_lora_tx_image; + mui_secondary_objects_flat[435] = objects.top_lora_tx_label; + mui_secondary_objects_flat[436] = objects.top_lora_tx_panel; + mui_secondary_objects_flat[437] = objects.top_map_image; + mui_secondary_objects_flat[438] = objects.top_map_label; + mui_secondary_objects_flat[439] = objects.top_map_panel; + mui_secondary_objects_flat[440] = objects.top_mesh_detector_image; + mui_secondary_objects_flat[441] = objects.top_mesh_detector_label; + mui_secondary_objects_flat[442] = objects.top_mesh_detector_panel; + mui_secondary_objects_flat[443] = objects.top_messages_node_image; + mui_secondary_objects_flat[444] = objects.top_messages_node_label; + mui_secondary_objects_flat[445] = objects.top_messages_panel; + mui_secondary_objects_flat[446] = objects.top_neighbors_image; + mui_secondary_objects_flat[447] = objects.top_neighbors_label; + mui_secondary_objects_flat[448] = objects.top_neighbors_panel; + mui_secondary_objects_flat[449] = objects.top_node_options_image; + mui_secondary_objects_flat[450] = objects.top_node_options_label; + mui_secondary_objects_flat[451] = objects.top_node_options_panel; + mui_secondary_objects_flat[452] = objects.top_node_search_image; + mui_secondary_objects_flat[453] = objects.top_node_search_label; + mui_secondary_objects_flat[454] = objects.top_node_search_panel; + mui_secondary_objects_flat[455] = objects.top_nodes_image; + mui_secondary_objects_flat[456] = objects.top_nodes_online_label; + mui_secondary_objects_flat[457] = objects.top_nodes_panel; + mui_secondary_objects_flat[458] = objects.top_packet_log_image; + mui_secondary_objects_flat[459] = objects.top_packet_log_label; + mui_secondary_objects_flat[460] = objects.top_packet_log_panel; + mui_secondary_objects_flat[461] = objects.top_panel; + mui_secondary_objects_flat[462] = objects.top_settings_panel; + mui_secondary_objects_flat[463] = objects.top_setup_image; + mui_secondary_objects_flat[464] = objects.top_setup_label; + mui_secondary_objects_flat[465] = objects.top_setup_panel; + mui_secondary_objects_flat[466] = objects.top_signal_scanner_image; + mui_secondary_objects_flat[467] = objects.top_signal_scanner_label; + mui_secondary_objects_flat[468] = objects.top_signal_scanner_panel; + mui_secondary_objects_flat[469] = objects.top_statistics_image; + mui_secondary_objects_flat[470] = objects.top_statistics_label; + mui_secondary_objects_flat[471] = objects.top_statistics_panel; + mui_secondary_objects_flat[472] = objects.top_trace_route_image; + mui_secondary_objects_flat[473] = objects.top_trace_route_label; + mui_secondary_objects_flat[474] = objects.top_trace_route_panel; + mui_secondary_objects_flat[475] = objects.top_user_group_label; + mui_secondary_objects_flat[476] = objects.trace_route_panel; + mui_secondary_objects_flat[477] = objects.trace_route_start_button; + mui_secondary_objects_flat[478] = objects.trace_route_start_label; + mui_secondary_objects_flat[479] = objects.trace_route_to_button; + mui_secondary_objects_flat[480] = objects.trace_route_to_button_label; + mui_secondary_objects_flat[481] = objects.trace_route_to_image; + mui_secondary_objects_flat[482] = objects.user_name_label; + mui_secondary_objects_flat[483] = objects.user_name_short_label; + mui_secondary_objects_flat[484] = objects.zoom_in_button; + mui_secondary_objects_flat[485] = objects.zoom_out_button; + mui_secondary_objects_flat[486] = objects.zoom_slider; + mui_secondary_ui_flat[0] = ui_AdvancedSettingsPanel; + mui_secondary_ui_flat[1] = ui_AmbientLightingLabel; + mui_secondary_ui_flat[2] = ui_AudioLabel; + mui_secondary_ui_flat[3] = ui_AudioLabel1; + mui_secondary_ui_flat[4] = ui_BluetoothLabel; + mui_secondary_ui_flat[5] = ui_CannedMsgLabel; + mui_secondary_ui_flat[6] = ui_DetectionSensorLabel; + mui_secondary_ui_flat[7] = ui_DeviceLabel; + mui_secondary_ui_flat[8] = ui_DisplayLabel; + mui_secondary_ui_flat[9] = ui_ExtNotificationLabel; + mui_secondary_ui_flat[10] = ui_GeneralAudioButton; + mui_secondary_ui_flat[11] = ui_GeneralLanguageButton; + mui_secondary_ui_flat[12] = ui_GeneralMapsButton; + mui_secondary_ui_flat[13] = ui_GeneralScreenButton; + mui_secondary_ui_flat[14] = ui_GeneralTimezoneButton; + mui_secondary_ui_flat[15] = ui_LanguageLabel; + mui_secondary_ui_flat[16] = ui_LoRaLabel; + mui_secondary_ui_flat[17] = ui_MQTTLabel; + mui_secondary_ui_flat[18] = ui_MapsLabel; + mui_secondary_ui_flat[19] = ui_ModuleAmbientLightingButton; + mui_secondary_ui_flat[20] = ui_ModuleAudioButton; + mui_secondary_ui_flat[21] = ui_ModuleCannedMsgButton; + mui_secondary_ui_flat[22] = ui_ModuleDetectionSensorButton; + mui_secondary_ui_flat[23] = ui_ModuleExtNotificationButton; + mui_secondary_ui_flat[24] = ui_ModuleMQTTButton; + mui_secondary_ui_flat[25] = ui_ModuleNeighborInfoButton; + mui_secondary_ui_flat[26] = ui_ModuleRangeTestButton; + mui_secondary_ui_flat[27] = ui_ModuleRemoteHardwareButton; + mui_secondary_ui_flat[28] = ui_ModuleSaFButton; + mui_secondary_ui_flat[29] = ui_ModuleSerialButton; + mui_secondary_ui_flat[30] = ui_ModuleTelemetryButton; + mui_secondary_ui_flat[31] = ui_NeighborInfoLabel; + mui_secondary_ui_flat[32] = ui_NetworkLabel; + mui_secondary_ui_flat[33] = ui_PositionLabel; + mui_secondary_ui_flat[34] = ui_PowerLabel; + mui_secondary_ui_flat[35] = ui_RadioBluetoothButton; + mui_secondary_ui_flat[36] = ui_RadioDeviceButton; + mui_secondary_ui_flat[37] = ui_RadioDisplayButton; + mui_secondary_ui_flat[38] = ui_RadioLoRaButton; + mui_secondary_ui_flat[39] = ui_RadioNetworkButton; + mui_secondary_ui_flat[40] = ui_RadioPositionButton; + mui_secondary_ui_flat[41] = ui_RadioPowerButton; + mui_secondary_ui_flat[42] = ui_RangeTestLabel; + mui_secondary_ui_flat[43] = ui_RemoteHardwareLabel; + mui_secondary_ui_flat[44] = ui_ScreenLabel; + mui_secondary_ui_flat[45] = ui_SerialLabel; + mui_secondary_ui_flat[46] = ui_SettingsTabView; + mui_secondary_ui_flat[47] = ui_StoreAndForwardLabel; + mui_secondary_ui_flat[48] = ui_TabPageGeneral; + mui_secondary_ui_flat[49] = ui_TabPageModules; + mui_secondary_ui_flat[50] = ui_TabPageRadio; + mui_secondary_ui_flat[51] = ui_TelemetryLabel; + mui_secondary_ui_flat[52] = ui_TimezoneLabel; +} diff --git a/tools/generated/dual/manifest.txt b/tools/generated/dual/manifest.txt new file mode 100644 index 00000000..6d467e21 --- /dev/null +++ b/tools/generated/dual/manifest.txt @@ -0,0 +1,212 @@ +members=487 +renamed_symbols=198 +ui_pointers=53 +shared_assets=93 +fingerprint=4311c2ae048d6318567e8de8bcc465a19db25a381358a8597539c397c8242ab9 +core_source images.c +core_source screens.c +core_source styles.c +core_source ui.c +core_source ui_tabview_settings.c +glue_source bridge_primary.c +glue_source bridge_secondary.c +secondary_asset ui_320x240 ui_image_home_bell_slash_image.c +secondary_asset ui_320x240 ui_image_top_message_node_images.c +sym active_theme_index +sym add_style +sym add_style_alert_panel_style +sym add_style_button_matrix_style +sym add_style_button_panel_style +sym add_style_bw_label_style +sym add_style_channel_button_style +sym add_style_chat_message_style +sym add_style_color_label_style +sym add_style_drop_down_style +sym add_style_home_button_style +sym add_style_home_container_style +sym add_style_main_button_style +sym add_style_main_screen_style +sym add_style_map_arrow_style +sym add_style_new_message_style +sym add_style_node_button_style +sym add_style_node_panel_style +sym add_style_panel_style +sym add_style_positive_image_style +sym add_style_settings_button_style +sym add_style_settings_label_style +sym add_style_settings_panel_style +sym add_style_spinner_style +sym add_style_statistics_table_style +sym add_style_tab_view_style +sym add_style_top_image_style +sym add_style_top_panel_style +sym create_screen_blank_screen +sym create_screen_boot_screen +sym create_screen_calibration_screen +sym create_screen_lock_screen +sym create_screen_main_screen +sym create_screens +sym create_tabview_settings +sym create_user_widget_ok_cancel_widget +sym fonts +sym get_style_alert_panel_style_MAIN_DEFAULT +sym get_style_button_matrix_style_ITEMS_DEFAULT +sym get_style_button_matrix_style_MAIN_DEFAULT +sym get_style_button_panel_style_MAIN_DEFAULT +sym get_style_bw_label_style_MAIN_DEFAULT +sym get_style_channel_button_style_MAIN_DEFAULT +sym get_style_chat_message_style_MAIN_DEFAULT +sym get_style_color_label_style_MAIN_DEFAULT +sym get_style_home_button_style_MAIN_DEFAULT +sym get_style_home_container_style_MAIN_DEFAULT +sym get_style_main_button_style_MAIN_DEFAULT +sym get_style_main_screen_style_MAIN_DEFAULT +sym get_style_main_screen_style_MAIN_PRESSED +sym get_style_map_arrow_style_MAIN_DEFAULT +sym get_style_map_arrow_style_MAIN_PRESSED +sym get_style_new_message_style_MAIN_DEFAULT +sym get_style_node_button_style_MAIN_DEFAULT +sym get_style_node_panel_style_MAIN_DEFAULT +sym get_style_panel_style_MAIN_DEFAULT +sym get_style_panel_style_MAIN_PRESSED +sym get_style_positive_image_style_MAIN_DEFAULT +sym get_style_settings_button_style_MAIN_DEFAULT +sym get_style_settings_label_style_MAIN_DEFAULT +sym get_style_settings_panel_style_MAIN_DEFAULT +sym get_style_spinner_style_INDICATOR_DEFAULT +sym get_style_spinner_style_MAIN_DEFAULT +sym get_style_statistics_table_style_ITEMS_DEFAULT +sym get_style_statistics_table_style_MAIN_DEFAULT +sym get_style_tab_view_style_MAIN_DEFAULT +sym get_style_top_image_style_MAIN_DEFAULT +sym get_style_top_panel_style_MAIN_DEFAULT +sym images +sym init_style_alert_panel_style_MAIN_DEFAULT +sym init_style_button_matrix_style_ITEMS_DEFAULT +sym init_style_button_matrix_style_MAIN_DEFAULT +sym init_style_button_panel_style_MAIN_DEFAULT +sym init_style_bw_label_style_MAIN_DEFAULT +sym init_style_channel_button_style_MAIN_DEFAULT +sym init_style_chat_message_style_MAIN_DEFAULT +sym init_style_color_label_style_MAIN_DEFAULT +sym init_style_home_button_style_MAIN_DEFAULT +sym init_style_home_container_style_MAIN_DEFAULT +sym init_style_main_button_style_MAIN_DEFAULT +sym init_style_main_screen_style_MAIN_DEFAULT +sym init_style_main_screen_style_MAIN_PRESSED +sym init_style_map_arrow_style_MAIN_DEFAULT +sym init_style_map_arrow_style_MAIN_PRESSED +sym init_style_new_message_style_MAIN_DEFAULT +sym init_style_node_button_style_MAIN_DEFAULT +sym init_style_node_panel_style_MAIN_DEFAULT +sym init_style_panel_style_MAIN_DEFAULT +sym init_style_panel_style_MAIN_PRESSED +sym init_style_positive_image_style_MAIN_DEFAULT +sym init_style_settings_button_style_MAIN_DEFAULT +sym init_style_settings_label_style_MAIN_DEFAULT +sym init_style_settings_panel_style_MAIN_DEFAULT +sym init_style_spinner_style_INDICATOR_DEFAULT +sym init_style_spinner_style_MAIN_DEFAULT +sym init_style_statistics_table_style_ITEMS_DEFAULT +sym init_style_statistics_table_style_MAIN_DEFAULT +sym init_style_tab_view_style_MAIN_DEFAULT +sym init_style_top_image_style_MAIN_DEFAULT +sym init_style_top_panel_style_MAIN_DEFAULT +sym loadScreen +sym objects +sym remove_style +sym remove_style_alert_panel_style +sym remove_style_button_matrix_style +sym remove_style_button_panel_style +sym remove_style_bw_label_style +sym remove_style_channel_button_style +sym remove_style_chat_message_style +sym remove_style_color_label_style +sym remove_style_drop_down_style +sym remove_style_home_button_style +sym remove_style_home_container_style +sym remove_style_main_button_style +sym remove_style_main_screen_style +sym remove_style_map_arrow_style +sym remove_style_new_message_style +sym remove_style_node_button_style +sym remove_style_node_panel_style +sym remove_style_panel_style +sym remove_style_positive_image_style +sym remove_style_settings_button_style +sym remove_style_settings_label_style +sym remove_style_settings_panel_style +sym remove_style_spinner_style +sym remove_style_statistics_table_style +sym remove_style_tab_view_style +sym remove_style_top_image_style +sym remove_style_top_panel_style +sym style_btn_active +sym style_btn_default +sym style_btn_pressed +sym tick_screen +sym tick_screen_blank_screen +sym tick_screen_boot_screen +sym tick_screen_by_id +sym tick_screen_calibration_screen +sym tick_screen_funcs +sym tick_screen_lock_screen +sym tick_screen_main_screen +sym tick_user_widget_ok_cancel_widget +sym tick_value_change_obj +sym ui_AdvancedSettingsPanel +sym ui_AmbientLightingLabel +sym ui_AudioLabel +sym ui_AudioLabel1 +sym ui_BluetoothLabel +sym ui_CannedMsgLabel +sym ui_DetectionSensorLabel +sym ui_DeviceLabel +sym ui_DisplayLabel +sym ui_ExtNotificationLabel +sym ui_GeneralAudioButton +sym ui_GeneralLanguageButton +sym ui_GeneralMapsButton +sym ui_GeneralScreenButton +sym ui_GeneralTimezoneButton +sym ui_LanguageLabel +sym ui_LoRaLabel +sym ui_MQTTLabel +sym ui_MapsLabel +sym ui_ModuleAmbientLightingButton +sym ui_ModuleAudioButton +sym ui_ModuleCannedMsgButton +sym ui_ModuleDetectionSensorButton +sym ui_ModuleExtNotificationButton +sym ui_ModuleMQTTButton +sym ui_ModuleNeighborInfoButton +sym ui_ModuleRangeTestButton +sym ui_ModuleRemoteHardwareButton +sym ui_ModuleSaFButton +sym ui_ModuleSerialButton +sym ui_ModuleTelemetryButton +sym ui_NeighborInfoLabel +sym ui_NetworkLabel +sym ui_PositionLabel +sym ui_PowerLabel +sym ui_RadioBluetoothButton +sym ui_RadioDeviceButton +sym ui_RadioDisplayButton +sym ui_RadioLoRaButton +sym ui_RadioNetworkButton +sym ui_RadioPositionButton +sym ui_RadioPowerButton +sym ui_RangeTestLabel +sym ui_RemoteHardwareLabel +sym ui_ScreenLabel +sym ui_SerialLabel +sym ui_SettingsTabView +sym ui_StoreAndForwardLabel +sym ui_TabPageGeneral +sym ui_TabPageModules +sym ui_TabPageRadio +sym ui_TelemetryLabel +sym ui_TimezoneLabel +sym ui_init +sym ui_init_boot +sym ui_tick diff --git a/tools/generated/dual/style_routing.h b/tools/generated/dual/style_routing.h new file mode 100644 index 00000000..10a219bb --- /dev/null +++ b/tools/generated/dual/style_routing.h @@ -0,0 +1,353 @@ +// GENERATED by tools/gen_dual_ui.py - do not edit. +// Force-included into the C++ sources that reference generated styles. +#pragma once +#include "graphics/ScreenRotation.h" +#include "styles.h" + +extern "C" { +void MUI2_add_style_alert_panel_style(lv_obj_t *obj); +void MUI2_add_style_button_matrix_style(lv_obj_t *obj); +void MUI2_add_style_button_panel_style(lv_obj_t *obj); +void MUI2_add_style_bw_label_style(lv_obj_t *obj); +void MUI2_add_style_channel_button_style(lv_obj_t *obj); +void MUI2_add_style_chat_message_style(lv_obj_t *obj); +void MUI2_add_style_color_label_style(lv_obj_t *obj); +void MUI2_add_style_drop_down_style(lv_obj_t *obj); +void MUI2_add_style_home_button_style(lv_obj_t *obj); +void MUI2_add_style_home_container_style(lv_obj_t *obj); +void MUI2_add_style_main_button_style(lv_obj_t *obj); +void MUI2_add_style_main_screen_style(lv_obj_t *obj); +void MUI2_add_style_map_arrow_style(lv_obj_t *obj); +void MUI2_add_style_new_message_style(lv_obj_t *obj); +void MUI2_add_style_node_button_style(lv_obj_t *obj); +void MUI2_add_style_node_panel_style(lv_obj_t *obj); +void MUI2_add_style_panel_style(lv_obj_t *obj); +void MUI2_add_style_positive_image_style(lv_obj_t *obj); +void MUI2_add_style_settings_button_style(lv_obj_t *obj); +void MUI2_add_style_settings_label_style(lv_obj_t *obj); +void MUI2_add_style_settings_panel_style(lv_obj_t *obj); +void MUI2_add_style_spinner_style(lv_obj_t *obj); +void MUI2_add_style_statistics_table_style(lv_obj_t *obj); +void MUI2_add_style_tab_view_style(lv_obj_t *obj); +void MUI2_add_style_top_image_style(lv_obj_t *obj); +void MUI2_add_style_top_panel_style(lv_obj_t *obj); +lv_style_t *MUI2_get_style_alert_panel_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_button_matrix_style_ITEMS_DEFAULT(void); +lv_style_t *MUI2_get_style_button_matrix_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_button_panel_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_bw_label_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_channel_button_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_chat_message_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_color_label_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_home_button_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_home_container_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_main_button_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_main_screen_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_main_screen_style_MAIN_PRESSED(void); +lv_style_t *MUI2_get_style_map_arrow_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_map_arrow_style_MAIN_PRESSED(void); +lv_style_t *MUI2_get_style_new_message_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_node_button_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_node_panel_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_panel_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_panel_style_MAIN_PRESSED(void); +lv_style_t *MUI2_get_style_positive_image_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_settings_button_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_settings_label_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_settings_panel_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_spinner_style_INDICATOR_DEFAULT(void); +lv_style_t *MUI2_get_style_spinner_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_statistics_table_style_ITEMS_DEFAULT(void); +lv_style_t *MUI2_get_style_statistics_table_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_tab_view_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_top_image_style_MAIN_DEFAULT(void); +lv_style_t *MUI2_get_style_top_panel_style_MAIN_DEFAULT(void); +void MUI2_remove_style_alert_panel_style(lv_obj_t *obj); +void MUI2_remove_style_button_matrix_style(lv_obj_t *obj); +void MUI2_remove_style_button_panel_style(lv_obj_t *obj); +void MUI2_remove_style_bw_label_style(lv_obj_t *obj); +void MUI2_remove_style_channel_button_style(lv_obj_t *obj); +void MUI2_remove_style_chat_message_style(lv_obj_t *obj); +void MUI2_remove_style_color_label_style(lv_obj_t *obj); +void MUI2_remove_style_drop_down_style(lv_obj_t *obj); +void MUI2_remove_style_home_button_style(lv_obj_t *obj); +void MUI2_remove_style_home_container_style(lv_obj_t *obj); +void MUI2_remove_style_main_button_style(lv_obj_t *obj); +void MUI2_remove_style_main_screen_style(lv_obj_t *obj); +void MUI2_remove_style_map_arrow_style(lv_obj_t *obj); +void MUI2_remove_style_new_message_style(lv_obj_t *obj); +void MUI2_remove_style_node_button_style(lv_obj_t *obj); +void MUI2_remove_style_node_panel_style(lv_obj_t *obj); +void MUI2_remove_style_panel_style(lv_obj_t *obj); +void MUI2_remove_style_positive_image_style(lv_obj_t *obj); +void MUI2_remove_style_settings_button_style(lv_obj_t *obj); +void MUI2_remove_style_settings_label_style(lv_obj_t *obj); +void MUI2_remove_style_settings_panel_style(lv_obj_t *obj); +void MUI2_remove_style_spinner_style(lv_obj_t *obj); +void MUI2_remove_style_statistics_table_style(lv_obj_t *obj); +void MUI2_remove_style_tab_view_style(lv_obj_t *obj); +void MUI2_remove_style_top_image_style(lv_obj_t *obj); +void MUI2_remove_style_top_panel_style(lv_obj_t *obj); +extern lv_style_t MUI2_style_btn_active; +extern lv_style_t MUI2_style_btn_default; +extern lv_style_t MUI2_style_btn_pressed; +} + +static inline void mui_route_add_style_alert_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_alert_panel_style(obj); else add_style_alert_panel_style(obj); } +#define add_style_alert_panel_style mui_route_add_style_alert_panel_style +static inline void mui_route_add_style_button_matrix_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_button_matrix_style(obj); else add_style_button_matrix_style(obj); } +#define add_style_button_matrix_style mui_route_add_style_button_matrix_style +static inline void mui_route_add_style_button_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_button_panel_style(obj); else add_style_button_panel_style(obj); } +#define add_style_button_panel_style mui_route_add_style_button_panel_style +static inline void mui_route_add_style_bw_label_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_bw_label_style(obj); else add_style_bw_label_style(obj); } +#define add_style_bw_label_style mui_route_add_style_bw_label_style +static inline void mui_route_add_style_channel_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_channel_button_style(obj); else add_style_channel_button_style(obj); } +#define add_style_channel_button_style mui_route_add_style_channel_button_style +static inline void mui_route_add_style_chat_message_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_chat_message_style(obj); else add_style_chat_message_style(obj); } +#define add_style_chat_message_style mui_route_add_style_chat_message_style +static inline void mui_route_add_style_color_label_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_color_label_style(obj); else add_style_color_label_style(obj); } +#define add_style_color_label_style mui_route_add_style_color_label_style +static inline void mui_route_add_style_drop_down_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_drop_down_style(obj); else add_style_drop_down_style(obj); } +#define add_style_drop_down_style mui_route_add_style_drop_down_style +static inline void mui_route_add_style_home_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_home_button_style(obj); else add_style_home_button_style(obj); } +#define add_style_home_button_style mui_route_add_style_home_button_style +static inline void mui_route_add_style_home_container_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_home_container_style(obj); else add_style_home_container_style(obj); } +#define add_style_home_container_style mui_route_add_style_home_container_style +static inline void mui_route_add_style_main_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_main_button_style(obj); else add_style_main_button_style(obj); } +#define add_style_main_button_style mui_route_add_style_main_button_style +static inline void mui_route_add_style_main_screen_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_main_screen_style(obj); else add_style_main_screen_style(obj); } +#define add_style_main_screen_style mui_route_add_style_main_screen_style +static inline void mui_route_add_style_map_arrow_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_map_arrow_style(obj); else add_style_map_arrow_style(obj); } +#define add_style_map_arrow_style mui_route_add_style_map_arrow_style +static inline void mui_route_add_style_new_message_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_new_message_style(obj); else add_style_new_message_style(obj); } +#define add_style_new_message_style mui_route_add_style_new_message_style +static inline void mui_route_add_style_node_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_node_button_style(obj); else add_style_node_button_style(obj); } +#define add_style_node_button_style mui_route_add_style_node_button_style +static inline void mui_route_add_style_node_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_node_panel_style(obj); else add_style_node_panel_style(obj); } +#define add_style_node_panel_style mui_route_add_style_node_panel_style +static inline void mui_route_add_style_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_panel_style(obj); else add_style_panel_style(obj); } +#define add_style_panel_style mui_route_add_style_panel_style +static inline void mui_route_add_style_positive_image_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_positive_image_style(obj); else add_style_positive_image_style(obj); } +#define add_style_positive_image_style mui_route_add_style_positive_image_style +static inline void mui_route_add_style_settings_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_settings_button_style(obj); else add_style_settings_button_style(obj); } +#define add_style_settings_button_style mui_route_add_style_settings_button_style +static inline void mui_route_add_style_settings_label_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_settings_label_style(obj); else add_style_settings_label_style(obj); } +#define add_style_settings_label_style mui_route_add_style_settings_label_style +static inline void mui_route_add_style_settings_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_settings_panel_style(obj); else add_style_settings_panel_style(obj); } +#define add_style_settings_panel_style mui_route_add_style_settings_panel_style +static inline void mui_route_add_style_spinner_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_spinner_style(obj); else add_style_spinner_style(obj); } +#define add_style_spinner_style mui_route_add_style_spinner_style +static inline void mui_route_add_style_statistics_table_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_statistics_table_style(obj); else add_style_statistics_table_style(obj); } +#define add_style_statistics_table_style mui_route_add_style_statistics_table_style +static inline void mui_route_add_style_tab_view_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_tab_view_style(obj); else add_style_tab_view_style(obj); } +#define add_style_tab_view_style mui_route_add_style_tab_view_style +static inline void mui_route_add_style_top_image_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_top_image_style(obj); else add_style_top_image_style(obj); } +#define add_style_top_image_style mui_route_add_style_top_image_style +static inline void mui_route_add_style_top_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_add_style_top_panel_style(obj); else add_style_top_panel_style(obj); } +#define add_style_top_panel_style mui_route_add_style_top_panel_style +static inline lv_style_t *mui_route_get_style_alert_panel_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_alert_panel_style_MAIN_DEFAULT() : get_style_alert_panel_style_MAIN_DEFAULT(); } +#define get_style_alert_panel_style_MAIN_DEFAULT mui_route_get_style_alert_panel_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_button_matrix_style_ITEMS_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_button_matrix_style_ITEMS_DEFAULT() : get_style_button_matrix_style_ITEMS_DEFAULT(); } +#define get_style_button_matrix_style_ITEMS_DEFAULT mui_route_get_style_button_matrix_style_ITEMS_DEFAULT +static inline lv_style_t *mui_route_get_style_button_matrix_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_button_matrix_style_MAIN_DEFAULT() : get_style_button_matrix_style_MAIN_DEFAULT(); } +#define get_style_button_matrix_style_MAIN_DEFAULT mui_route_get_style_button_matrix_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_button_panel_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_button_panel_style_MAIN_DEFAULT() : get_style_button_panel_style_MAIN_DEFAULT(); } +#define get_style_button_panel_style_MAIN_DEFAULT mui_route_get_style_button_panel_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_bw_label_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_bw_label_style_MAIN_DEFAULT() : get_style_bw_label_style_MAIN_DEFAULT(); } +#define get_style_bw_label_style_MAIN_DEFAULT mui_route_get_style_bw_label_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_channel_button_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_channel_button_style_MAIN_DEFAULT() : get_style_channel_button_style_MAIN_DEFAULT(); } +#define get_style_channel_button_style_MAIN_DEFAULT mui_route_get_style_channel_button_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_chat_message_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_chat_message_style_MAIN_DEFAULT() : get_style_chat_message_style_MAIN_DEFAULT(); } +#define get_style_chat_message_style_MAIN_DEFAULT mui_route_get_style_chat_message_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_color_label_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_color_label_style_MAIN_DEFAULT() : get_style_color_label_style_MAIN_DEFAULT(); } +#define get_style_color_label_style_MAIN_DEFAULT mui_route_get_style_color_label_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_home_button_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_home_button_style_MAIN_DEFAULT() : get_style_home_button_style_MAIN_DEFAULT(); } +#define get_style_home_button_style_MAIN_DEFAULT mui_route_get_style_home_button_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_home_container_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_home_container_style_MAIN_DEFAULT() : get_style_home_container_style_MAIN_DEFAULT(); } +#define get_style_home_container_style_MAIN_DEFAULT mui_route_get_style_home_container_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_main_button_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_main_button_style_MAIN_DEFAULT() : get_style_main_button_style_MAIN_DEFAULT(); } +#define get_style_main_button_style_MAIN_DEFAULT mui_route_get_style_main_button_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_main_screen_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_main_screen_style_MAIN_DEFAULT() : get_style_main_screen_style_MAIN_DEFAULT(); } +#define get_style_main_screen_style_MAIN_DEFAULT mui_route_get_style_main_screen_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_main_screen_style_MAIN_PRESSED(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_main_screen_style_MAIN_PRESSED() : get_style_main_screen_style_MAIN_PRESSED(); } +#define get_style_main_screen_style_MAIN_PRESSED mui_route_get_style_main_screen_style_MAIN_PRESSED +static inline lv_style_t *mui_route_get_style_map_arrow_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_map_arrow_style_MAIN_DEFAULT() : get_style_map_arrow_style_MAIN_DEFAULT(); } +#define get_style_map_arrow_style_MAIN_DEFAULT mui_route_get_style_map_arrow_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_map_arrow_style_MAIN_PRESSED(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_map_arrow_style_MAIN_PRESSED() : get_style_map_arrow_style_MAIN_PRESSED(); } +#define get_style_map_arrow_style_MAIN_PRESSED mui_route_get_style_map_arrow_style_MAIN_PRESSED +static inline lv_style_t *mui_route_get_style_new_message_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_new_message_style_MAIN_DEFAULT() : get_style_new_message_style_MAIN_DEFAULT(); } +#define get_style_new_message_style_MAIN_DEFAULT mui_route_get_style_new_message_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_node_button_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_node_button_style_MAIN_DEFAULT() : get_style_node_button_style_MAIN_DEFAULT(); } +#define get_style_node_button_style_MAIN_DEFAULT mui_route_get_style_node_button_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_node_panel_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_node_panel_style_MAIN_DEFAULT() : get_style_node_panel_style_MAIN_DEFAULT(); } +#define get_style_node_panel_style_MAIN_DEFAULT mui_route_get_style_node_panel_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_panel_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_panel_style_MAIN_DEFAULT() : get_style_panel_style_MAIN_DEFAULT(); } +#define get_style_panel_style_MAIN_DEFAULT mui_route_get_style_panel_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_panel_style_MAIN_PRESSED(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_panel_style_MAIN_PRESSED() : get_style_panel_style_MAIN_PRESSED(); } +#define get_style_panel_style_MAIN_PRESSED mui_route_get_style_panel_style_MAIN_PRESSED +static inline lv_style_t *mui_route_get_style_positive_image_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_positive_image_style_MAIN_DEFAULT() : get_style_positive_image_style_MAIN_DEFAULT(); } +#define get_style_positive_image_style_MAIN_DEFAULT mui_route_get_style_positive_image_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_settings_button_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_settings_button_style_MAIN_DEFAULT() : get_style_settings_button_style_MAIN_DEFAULT(); } +#define get_style_settings_button_style_MAIN_DEFAULT mui_route_get_style_settings_button_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_settings_label_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_settings_label_style_MAIN_DEFAULT() : get_style_settings_label_style_MAIN_DEFAULT(); } +#define get_style_settings_label_style_MAIN_DEFAULT mui_route_get_style_settings_label_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_settings_panel_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_settings_panel_style_MAIN_DEFAULT() : get_style_settings_panel_style_MAIN_DEFAULT(); } +#define get_style_settings_panel_style_MAIN_DEFAULT mui_route_get_style_settings_panel_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_spinner_style_INDICATOR_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_spinner_style_INDICATOR_DEFAULT() : get_style_spinner_style_INDICATOR_DEFAULT(); } +#define get_style_spinner_style_INDICATOR_DEFAULT mui_route_get_style_spinner_style_INDICATOR_DEFAULT +static inline lv_style_t *mui_route_get_style_spinner_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_spinner_style_MAIN_DEFAULT() : get_style_spinner_style_MAIN_DEFAULT(); } +#define get_style_spinner_style_MAIN_DEFAULT mui_route_get_style_spinner_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_statistics_table_style_ITEMS_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_statistics_table_style_ITEMS_DEFAULT() : get_style_statistics_table_style_ITEMS_DEFAULT(); } +#define get_style_statistics_table_style_ITEMS_DEFAULT mui_route_get_style_statistics_table_style_ITEMS_DEFAULT +static inline lv_style_t *mui_route_get_style_statistics_table_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_statistics_table_style_MAIN_DEFAULT() : get_style_statistics_table_style_MAIN_DEFAULT(); } +#define get_style_statistics_table_style_MAIN_DEFAULT mui_route_get_style_statistics_table_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_tab_view_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_tab_view_style_MAIN_DEFAULT() : get_style_tab_view_style_MAIN_DEFAULT(); } +#define get_style_tab_view_style_MAIN_DEFAULT mui_route_get_style_tab_view_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_top_image_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_top_image_style_MAIN_DEFAULT() : get_style_top_image_style_MAIN_DEFAULT(); } +#define get_style_top_image_style_MAIN_DEFAULT mui_route_get_style_top_image_style_MAIN_DEFAULT +static inline lv_style_t *mui_route_get_style_top_panel_style_MAIN_DEFAULT(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_get_style_top_panel_style_MAIN_DEFAULT() : get_style_top_panel_style_MAIN_DEFAULT(); } +#define get_style_top_panel_style_MAIN_DEFAULT mui_route_get_style_top_panel_style_MAIN_DEFAULT +static inline void mui_route_remove_style_alert_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_alert_panel_style(obj); else remove_style_alert_panel_style(obj); } +#define remove_style_alert_panel_style mui_route_remove_style_alert_panel_style +static inline void mui_route_remove_style_button_matrix_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_button_matrix_style(obj); else remove_style_button_matrix_style(obj); } +#define remove_style_button_matrix_style mui_route_remove_style_button_matrix_style +static inline void mui_route_remove_style_button_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_button_panel_style(obj); else remove_style_button_panel_style(obj); } +#define remove_style_button_panel_style mui_route_remove_style_button_panel_style +static inline void mui_route_remove_style_bw_label_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_bw_label_style(obj); else remove_style_bw_label_style(obj); } +#define remove_style_bw_label_style mui_route_remove_style_bw_label_style +static inline void mui_route_remove_style_channel_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_channel_button_style(obj); else remove_style_channel_button_style(obj); } +#define remove_style_channel_button_style mui_route_remove_style_channel_button_style +static inline void mui_route_remove_style_chat_message_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_chat_message_style(obj); else remove_style_chat_message_style(obj); } +#define remove_style_chat_message_style mui_route_remove_style_chat_message_style +static inline void mui_route_remove_style_color_label_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_color_label_style(obj); else remove_style_color_label_style(obj); } +#define remove_style_color_label_style mui_route_remove_style_color_label_style +static inline void mui_route_remove_style_drop_down_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_drop_down_style(obj); else remove_style_drop_down_style(obj); } +#define remove_style_drop_down_style mui_route_remove_style_drop_down_style +static inline void mui_route_remove_style_home_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_home_button_style(obj); else remove_style_home_button_style(obj); } +#define remove_style_home_button_style mui_route_remove_style_home_button_style +static inline void mui_route_remove_style_home_container_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_home_container_style(obj); else remove_style_home_container_style(obj); } +#define remove_style_home_container_style mui_route_remove_style_home_container_style +static inline void mui_route_remove_style_main_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_main_button_style(obj); else remove_style_main_button_style(obj); } +#define remove_style_main_button_style mui_route_remove_style_main_button_style +static inline void mui_route_remove_style_main_screen_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_main_screen_style(obj); else remove_style_main_screen_style(obj); } +#define remove_style_main_screen_style mui_route_remove_style_main_screen_style +static inline void mui_route_remove_style_map_arrow_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_map_arrow_style(obj); else remove_style_map_arrow_style(obj); } +#define remove_style_map_arrow_style mui_route_remove_style_map_arrow_style +static inline void mui_route_remove_style_new_message_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_new_message_style(obj); else remove_style_new_message_style(obj); } +#define remove_style_new_message_style mui_route_remove_style_new_message_style +static inline void mui_route_remove_style_node_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_node_button_style(obj); else remove_style_node_button_style(obj); } +#define remove_style_node_button_style mui_route_remove_style_node_button_style +static inline void mui_route_remove_style_node_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_node_panel_style(obj); else remove_style_node_panel_style(obj); } +#define remove_style_node_panel_style mui_route_remove_style_node_panel_style +static inline void mui_route_remove_style_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_panel_style(obj); else remove_style_panel_style(obj); } +#define remove_style_panel_style mui_route_remove_style_panel_style +static inline void mui_route_remove_style_positive_image_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_positive_image_style(obj); else remove_style_positive_image_style(obj); } +#define remove_style_positive_image_style mui_route_remove_style_positive_image_style +static inline void mui_route_remove_style_settings_button_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_settings_button_style(obj); else remove_style_settings_button_style(obj); } +#define remove_style_settings_button_style mui_route_remove_style_settings_button_style +static inline void mui_route_remove_style_settings_label_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_settings_label_style(obj); else remove_style_settings_label_style(obj); } +#define remove_style_settings_label_style mui_route_remove_style_settings_label_style +static inline void mui_route_remove_style_settings_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_settings_panel_style(obj); else remove_style_settings_panel_style(obj); } +#define remove_style_settings_panel_style mui_route_remove_style_settings_panel_style +static inline void mui_route_remove_style_spinner_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_spinner_style(obj); else remove_style_spinner_style(obj); } +#define remove_style_spinner_style mui_route_remove_style_spinner_style +static inline void mui_route_remove_style_statistics_table_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_statistics_table_style(obj); else remove_style_statistics_table_style(obj); } +#define remove_style_statistics_table_style mui_route_remove_style_statistics_table_style +static inline void mui_route_remove_style_tab_view_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_tab_view_style(obj); else remove_style_tab_view_style(obj); } +#define remove_style_tab_view_style mui_route_remove_style_tab_view_style +static inline void mui_route_remove_style_top_image_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_top_image_style(obj); else remove_style_top_image_style(obj); } +#define remove_style_top_image_style mui_route_remove_style_top_image_style +static inline void mui_route_remove_style_top_panel_style(lv_obj_t *obj) +{ if (ScreenRotation::usesSecondaryTree()) MUI2_remove_style_top_panel_style(obj); else remove_style_top_panel_style(obj); } +#define remove_style_top_panel_style mui_route_remove_style_top_panel_style +static inline lv_style_t &mui_route_style_btn_active(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_style_btn_active : style_btn_active; } +#define style_btn_active (mui_route_style_btn_active()) +static inline lv_style_t &mui_route_style_btn_default(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_style_btn_default : style_btn_default; } +#define style_btn_default (mui_route_style_btn_default()) +static inline lv_style_t &mui_route_style_btn_pressed(void) +{ return ScreenRotation::usesSecondaryTree() ? MUI2_style_btn_pressed : style_btn_pressed; } +#define style_btn_pressed (mui_route_style_btn_pressed()) diff --git a/tools/generated/dual/ui_secondary_rename.h b/tools/generated/dual/ui_secondary_rename.h new file mode 100644 index 00000000..202cc4a0 --- /dev/null +++ b/tools/generated/dual/ui_secondary_rename.h @@ -0,0 +1,203 @@ +// GENERATED by tools/gen_dual_ui.py - do not edit. +// Forced include for the secondary generated tree's sources only. +#pragma once +#include + +#define active_theme_index MUI2_active_theme_index +#define add_style MUI2_add_style +#define add_style_alert_panel_style MUI2_add_style_alert_panel_style +#define add_style_button_matrix_style MUI2_add_style_button_matrix_style +#define add_style_button_panel_style MUI2_add_style_button_panel_style +#define add_style_bw_label_style MUI2_add_style_bw_label_style +#define add_style_channel_button_style MUI2_add_style_channel_button_style +#define add_style_chat_message_style MUI2_add_style_chat_message_style +#define add_style_color_label_style MUI2_add_style_color_label_style +#define add_style_drop_down_style MUI2_add_style_drop_down_style +#define add_style_home_button_style MUI2_add_style_home_button_style +#define add_style_home_container_style MUI2_add_style_home_container_style +#define add_style_main_button_style MUI2_add_style_main_button_style +#define add_style_main_screen_style MUI2_add_style_main_screen_style +#define add_style_map_arrow_style MUI2_add_style_map_arrow_style +#define add_style_new_message_style MUI2_add_style_new_message_style +#define add_style_node_button_style MUI2_add_style_node_button_style +#define add_style_node_panel_style MUI2_add_style_node_panel_style +#define add_style_panel_style MUI2_add_style_panel_style +#define add_style_positive_image_style MUI2_add_style_positive_image_style +#define add_style_settings_button_style MUI2_add_style_settings_button_style +#define add_style_settings_label_style MUI2_add_style_settings_label_style +#define add_style_settings_panel_style MUI2_add_style_settings_panel_style +#define add_style_spinner_style MUI2_add_style_spinner_style +#define add_style_statistics_table_style MUI2_add_style_statistics_table_style +#define add_style_tab_view_style MUI2_add_style_tab_view_style +#define add_style_top_image_style MUI2_add_style_top_image_style +#define add_style_top_panel_style MUI2_add_style_top_panel_style +#define create_screen_blank_screen MUI2_create_screen_blank_screen +#define create_screen_boot_screen MUI2_create_screen_boot_screen +#define create_screen_calibration_screen MUI2_create_screen_calibration_screen +#define create_screen_lock_screen MUI2_create_screen_lock_screen +#define create_screen_main_screen MUI2_create_screen_main_screen +#define create_screens MUI2_create_screens +#define create_tabview_settings MUI2_create_tabview_settings +#define create_user_widget_ok_cancel_widget MUI2_create_user_widget_ok_cancel_widget +#define fonts MUI2_fonts +#define get_style_alert_panel_style_MAIN_DEFAULT MUI2_get_style_alert_panel_style_MAIN_DEFAULT +#define get_style_button_matrix_style_ITEMS_DEFAULT MUI2_get_style_button_matrix_style_ITEMS_DEFAULT +#define get_style_button_matrix_style_MAIN_DEFAULT MUI2_get_style_button_matrix_style_MAIN_DEFAULT +#define get_style_button_panel_style_MAIN_DEFAULT MUI2_get_style_button_panel_style_MAIN_DEFAULT +#define get_style_bw_label_style_MAIN_DEFAULT MUI2_get_style_bw_label_style_MAIN_DEFAULT +#define get_style_channel_button_style_MAIN_DEFAULT MUI2_get_style_channel_button_style_MAIN_DEFAULT +#define get_style_chat_message_style_MAIN_DEFAULT MUI2_get_style_chat_message_style_MAIN_DEFAULT +#define get_style_color_label_style_MAIN_DEFAULT MUI2_get_style_color_label_style_MAIN_DEFAULT +#define get_style_home_button_style_MAIN_DEFAULT MUI2_get_style_home_button_style_MAIN_DEFAULT +#define get_style_home_container_style_MAIN_DEFAULT MUI2_get_style_home_container_style_MAIN_DEFAULT +#define get_style_main_button_style_MAIN_DEFAULT MUI2_get_style_main_button_style_MAIN_DEFAULT +#define get_style_main_screen_style_MAIN_DEFAULT MUI2_get_style_main_screen_style_MAIN_DEFAULT +#define get_style_main_screen_style_MAIN_PRESSED MUI2_get_style_main_screen_style_MAIN_PRESSED +#define get_style_map_arrow_style_MAIN_DEFAULT MUI2_get_style_map_arrow_style_MAIN_DEFAULT +#define get_style_map_arrow_style_MAIN_PRESSED MUI2_get_style_map_arrow_style_MAIN_PRESSED +#define get_style_new_message_style_MAIN_DEFAULT MUI2_get_style_new_message_style_MAIN_DEFAULT +#define get_style_node_button_style_MAIN_DEFAULT MUI2_get_style_node_button_style_MAIN_DEFAULT +#define get_style_node_panel_style_MAIN_DEFAULT MUI2_get_style_node_panel_style_MAIN_DEFAULT +#define get_style_panel_style_MAIN_DEFAULT MUI2_get_style_panel_style_MAIN_DEFAULT +#define get_style_panel_style_MAIN_PRESSED MUI2_get_style_panel_style_MAIN_PRESSED +#define get_style_positive_image_style_MAIN_DEFAULT MUI2_get_style_positive_image_style_MAIN_DEFAULT +#define get_style_settings_button_style_MAIN_DEFAULT MUI2_get_style_settings_button_style_MAIN_DEFAULT +#define get_style_settings_label_style_MAIN_DEFAULT MUI2_get_style_settings_label_style_MAIN_DEFAULT +#define get_style_settings_panel_style_MAIN_DEFAULT MUI2_get_style_settings_panel_style_MAIN_DEFAULT +#define get_style_spinner_style_INDICATOR_DEFAULT MUI2_get_style_spinner_style_INDICATOR_DEFAULT +#define get_style_spinner_style_MAIN_DEFAULT MUI2_get_style_spinner_style_MAIN_DEFAULT +#define get_style_statistics_table_style_ITEMS_DEFAULT MUI2_get_style_statistics_table_style_ITEMS_DEFAULT +#define get_style_statistics_table_style_MAIN_DEFAULT MUI2_get_style_statistics_table_style_MAIN_DEFAULT +#define get_style_tab_view_style_MAIN_DEFAULT MUI2_get_style_tab_view_style_MAIN_DEFAULT +#define get_style_top_image_style_MAIN_DEFAULT MUI2_get_style_top_image_style_MAIN_DEFAULT +#define get_style_top_panel_style_MAIN_DEFAULT MUI2_get_style_top_panel_style_MAIN_DEFAULT +#define images MUI2_images +#define init_style_alert_panel_style_MAIN_DEFAULT MUI2_init_style_alert_panel_style_MAIN_DEFAULT +#define init_style_button_matrix_style_ITEMS_DEFAULT MUI2_init_style_button_matrix_style_ITEMS_DEFAULT +#define init_style_button_matrix_style_MAIN_DEFAULT MUI2_init_style_button_matrix_style_MAIN_DEFAULT +#define init_style_button_panel_style_MAIN_DEFAULT MUI2_init_style_button_panel_style_MAIN_DEFAULT +#define init_style_bw_label_style_MAIN_DEFAULT MUI2_init_style_bw_label_style_MAIN_DEFAULT +#define init_style_channel_button_style_MAIN_DEFAULT MUI2_init_style_channel_button_style_MAIN_DEFAULT +#define init_style_chat_message_style_MAIN_DEFAULT MUI2_init_style_chat_message_style_MAIN_DEFAULT +#define init_style_color_label_style_MAIN_DEFAULT MUI2_init_style_color_label_style_MAIN_DEFAULT +#define init_style_home_button_style_MAIN_DEFAULT MUI2_init_style_home_button_style_MAIN_DEFAULT +#define init_style_home_container_style_MAIN_DEFAULT MUI2_init_style_home_container_style_MAIN_DEFAULT +#define init_style_main_button_style_MAIN_DEFAULT MUI2_init_style_main_button_style_MAIN_DEFAULT +#define init_style_main_screen_style_MAIN_DEFAULT MUI2_init_style_main_screen_style_MAIN_DEFAULT +#define init_style_main_screen_style_MAIN_PRESSED MUI2_init_style_main_screen_style_MAIN_PRESSED +#define init_style_map_arrow_style_MAIN_DEFAULT MUI2_init_style_map_arrow_style_MAIN_DEFAULT +#define init_style_map_arrow_style_MAIN_PRESSED MUI2_init_style_map_arrow_style_MAIN_PRESSED +#define init_style_new_message_style_MAIN_DEFAULT MUI2_init_style_new_message_style_MAIN_DEFAULT +#define init_style_node_button_style_MAIN_DEFAULT MUI2_init_style_node_button_style_MAIN_DEFAULT +#define init_style_node_panel_style_MAIN_DEFAULT MUI2_init_style_node_panel_style_MAIN_DEFAULT +#define init_style_panel_style_MAIN_DEFAULT MUI2_init_style_panel_style_MAIN_DEFAULT +#define init_style_panel_style_MAIN_PRESSED MUI2_init_style_panel_style_MAIN_PRESSED +#define init_style_positive_image_style_MAIN_DEFAULT MUI2_init_style_positive_image_style_MAIN_DEFAULT +#define init_style_settings_button_style_MAIN_DEFAULT MUI2_init_style_settings_button_style_MAIN_DEFAULT +#define init_style_settings_label_style_MAIN_DEFAULT MUI2_init_style_settings_label_style_MAIN_DEFAULT +#define init_style_settings_panel_style_MAIN_DEFAULT MUI2_init_style_settings_panel_style_MAIN_DEFAULT +#define init_style_spinner_style_INDICATOR_DEFAULT MUI2_init_style_spinner_style_INDICATOR_DEFAULT +#define init_style_spinner_style_MAIN_DEFAULT MUI2_init_style_spinner_style_MAIN_DEFAULT +#define init_style_statistics_table_style_ITEMS_DEFAULT MUI2_init_style_statistics_table_style_ITEMS_DEFAULT +#define init_style_statistics_table_style_MAIN_DEFAULT MUI2_init_style_statistics_table_style_MAIN_DEFAULT +#define init_style_tab_view_style_MAIN_DEFAULT MUI2_init_style_tab_view_style_MAIN_DEFAULT +#define init_style_top_image_style_MAIN_DEFAULT MUI2_init_style_top_image_style_MAIN_DEFAULT +#define init_style_top_panel_style_MAIN_DEFAULT MUI2_init_style_top_panel_style_MAIN_DEFAULT +#define loadScreen MUI2_loadScreen +#define objects MUI2_objects +#define remove_style MUI2_remove_style +#define remove_style_alert_panel_style MUI2_remove_style_alert_panel_style +#define remove_style_button_matrix_style MUI2_remove_style_button_matrix_style +#define remove_style_button_panel_style MUI2_remove_style_button_panel_style +#define remove_style_bw_label_style MUI2_remove_style_bw_label_style +#define remove_style_channel_button_style MUI2_remove_style_channel_button_style +#define remove_style_chat_message_style MUI2_remove_style_chat_message_style +#define remove_style_color_label_style MUI2_remove_style_color_label_style +#define remove_style_drop_down_style MUI2_remove_style_drop_down_style +#define remove_style_home_button_style MUI2_remove_style_home_button_style +#define remove_style_home_container_style MUI2_remove_style_home_container_style +#define remove_style_main_button_style MUI2_remove_style_main_button_style +#define remove_style_main_screen_style MUI2_remove_style_main_screen_style +#define remove_style_map_arrow_style MUI2_remove_style_map_arrow_style +#define remove_style_new_message_style MUI2_remove_style_new_message_style +#define remove_style_node_button_style MUI2_remove_style_node_button_style +#define remove_style_node_panel_style MUI2_remove_style_node_panel_style +#define remove_style_panel_style MUI2_remove_style_panel_style +#define remove_style_positive_image_style MUI2_remove_style_positive_image_style +#define remove_style_settings_button_style MUI2_remove_style_settings_button_style +#define remove_style_settings_label_style MUI2_remove_style_settings_label_style +#define remove_style_settings_panel_style MUI2_remove_style_settings_panel_style +#define remove_style_spinner_style MUI2_remove_style_spinner_style +#define remove_style_statistics_table_style MUI2_remove_style_statistics_table_style +#define remove_style_tab_view_style MUI2_remove_style_tab_view_style +#define remove_style_top_image_style MUI2_remove_style_top_image_style +#define remove_style_top_panel_style MUI2_remove_style_top_panel_style +#define style_btn_active MUI2_style_btn_active +#define style_btn_default MUI2_style_btn_default +#define style_btn_pressed MUI2_style_btn_pressed +#define tick_screen MUI2_tick_screen +#define tick_screen_blank_screen MUI2_tick_screen_blank_screen +#define tick_screen_boot_screen MUI2_tick_screen_boot_screen +#define tick_screen_by_id MUI2_tick_screen_by_id +#define tick_screen_calibration_screen MUI2_tick_screen_calibration_screen +#define tick_screen_funcs MUI2_tick_screen_funcs +#define tick_screen_lock_screen MUI2_tick_screen_lock_screen +#define tick_screen_main_screen MUI2_tick_screen_main_screen +#define tick_user_widget_ok_cancel_widget MUI2_tick_user_widget_ok_cancel_widget +#define tick_value_change_obj MUI2_tick_value_change_obj +#define ui_AdvancedSettingsPanel MUI2_ui_AdvancedSettingsPanel +#define ui_AmbientLightingLabel MUI2_ui_AmbientLightingLabel +#define ui_AudioLabel MUI2_ui_AudioLabel +#define ui_AudioLabel1 MUI2_ui_AudioLabel1 +#define ui_BluetoothLabel MUI2_ui_BluetoothLabel +#define ui_CannedMsgLabel MUI2_ui_CannedMsgLabel +#define ui_DetectionSensorLabel MUI2_ui_DetectionSensorLabel +#define ui_DeviceLabel MUI2_ui_DeviceLabel +#define ui_DisplayLabel MUI2_ui_DisplayLabel +#define ui_ExtNotificationLabel MUI2_ui_ExtNotificationLabel +#define ui_GeneralAudioButton MUI2_ui_GeneralAudioButton +#define ui_GeneralLanguageButton MUI2_ui_GeneralLanguageButton +#define ui_GeneralMapsButton MUI2_ui_GeneralMapsButton +#define ui_GeneralScreenButton MUI2_ui_GeneralScreenButton +#define ui_GeneralTimezoneButton MUI2_ui_GeneralTimezoneButton +#define ui_LanguageLabel MUI2_ui_LanguageLabel +#define ui_LoRaLabel MUI2_ui_LoRaLabel +#define ui_MQTTLabel MUI2_ui_MQTTLabel +#define ui_MapsLabel MUI2_ui_MapsLabel +#define ui_ModuleAmbientLightingButton MUI2_ui_ModuleAmbientLightingButton +#define ui_ModuleAudioButton MUI2_ui_ModuleAudioButton +#define ui_ModuleCannedMsgButton MUI2_ui_ModuleCannedMsgButton +#define ui_ModuleDetectionSensorButton MUI2_ui_ModuleDetectionSensorButton +#define ui_ModuleExtNotificationButton MUI2_ui_ModuleExtNotificationButton +#define ui_ModuleMQTTButton MUI2_ui_ModuleMQTTButton +#define ui_ModuleNeighborInfoButton MUI2_ui_ModuleNeighborInfoButton +#define ui_ModuleRangeTestButton MUI2_ui_ModuleRangeTestButton +#define ui_ModuleRemoteHardwareButton MUI2_ui_ModuleRemoteHardwareButton +#define ui_ModuleSaFButton MUI2_ui_ModuleSaFButton +#define ui_ModuleSerialButton MUI2_ui_ModuleSerialButton +#define ui_ModuleTelemetryButton MUI2_ui_ModuleTelemetryButton +#define ui_NeighborInfoLabel MUI2_ui_NeighborInfoLabel +#define ui_NetworkLabel MUI2_ui_NetworkLabel +#define ui_PositionLabel MUI2_ui_PositionLabel +#define ui_PowerLabel MUI2_ui_PowerLabel +#define ui_RadioBluetoothButton MUI2_ui_RadioBluetoothButton +#define ui_RadioDeviceButton MUI2_ui_RadioDeviceButton +#define ui_RadioDisplayButton MUI2_ui_RadioDisplayButton +#define ui_RadioLoRaButton MUI2_ui_RadioLoRaButton +#define ui_RadioNetworkButton MUI2_ui_RadioNetworkButton +#define ui_RadioPositionButton MUI2_ui_RadioPositionButton +#define ui_RadioPowerButton MUI2_ui_RadioPowerButton +#define ui_RangeTestLabel MUI2_ui_RangeTestLabel +#define ui_RemoteHardwareLabel MUI2_ui_RemoteHardwareLabel +#define ui_ScreenLabel MUI2_ui_ScreenLabel +#define ui_SerialLabel MUI2_ui_SerialLabel +#define ui_SettingsTabView MUI2_ui_SettingsTabView +#define ui_StoreAndForwardLabel MUI2_ui_StoreAndForwardLabel +#define ui_TabPageGeneral MUI2_ui_TabPageGeneral +#define ui_TabPageModules MUI2_ui_TabPageModules +#define ui_TabPageRadio MUI2_ui_TabPageRadio +#define ui_TelemetryLabel MUI2_ui_TelemetryLabel +#define ui_TimezoneLabel MUI2_ui_TimezoneLabel +#define ui_init MUI2_ui_init +#define ui_init_boot MUI2_ui_init_boot +#define ui_tick MUI2_ui_tick From 5411a71f8057b3ec29307cde781fc5173e3f8f08 Mon Sep 17 00:00:00 2001 From: Attaky <203162318+attakygit@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:43:11 -0700 Subject: [PATCH 4/7] feat(graphics): runtime screen-rotation state The stored value is the quarter-turn count applied on top of the board's compile-time LGFX_ROTATION offset, so value 0 reproduces each board's current behaviour. Even values keep the compile-time layout, odd values need the perpendicular one. Applied at boot only: an LVGL layout tree cannot be rebuilt in place once the view has cached its object pointers. The mapping helpers are pure so they can be tested without touching the loaded state. --- include/graphics/ScreenRotation.h | 69 ++++++++++++++++++++++++++++++ source/graphics/ScreenRotation.cpp | 48 +++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 include/graphics/ScreenRotation.h create mode 100644 source/graphics/ScreenRotation.cpp diff --git a/include/graphics/ScreenRotation.h b/include/graphics/ScreenRotation.h new file mode 100644 index 00000000..bad549c6 --- /dev/null +++ b/include/graphics/ScreenRotation.h @@ -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 + +/** + * 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 diff --git a/source/graphics/ScreenRotation.cpp b/source/graphics/ScreenRotation.cpp new file mode 100644 index 00000000..20733351 --- /dev/null +++ b/source/graphics/ScreenRotation.cpp @@ -0,0 +1,48 @@ +#ifdef MUI_RUNTIME_ROTATION + +#include "graphics/ScreenRotation.h" +#include "util/ILog.h" + +#if defined(VIEW_240x320) +static const uint16_t kPrimaryWidth = 240; +static const uint16_t kPrimaryHeight = 320; +#else +static const uint16_t kPrimaryWidth = 320; +static const uint16_t kPrimaryHeight = 240; +#endif + +ScreenRotation::Value ScreenRotation::current = ScreenRotation::Rotation0; +bool ScreenRotation::loaded = false; + +void ScreenRotation::setLoaded(uint8_t raw) +{ + if (loaded) + return; + loaded = true; + if (raw > (uint8_t)Rotation270) { + ILOG_WARN("invalid stored screen rotation %u, using %u", raw, (unsigned)current); + return; + } + current = (Value)raw; + ILOG_INFO("screen rotation %u restored", (unsigned)current); +} + +void ScreenRotation::load(void) +{ + if (!loaded) { + loaded = true; + ILOG_WARN("screen rotation not supplied, using %u", (unsigned)current); + } +} + +uint16_t ScreenRotation::width(Value v) +{ + return usesSecondaryTree(v) ? kPrimaryHeight : kPrimaryWidth; +} + +uint16_t ScreenRotation::height(Value v) +{ + return usesSecondaryTree(v) ? kPrimaryWidth : kPrimaryHeight; +} + +#endif // MUI_RUNTIME_ROTATION From 90fa200f0109d656a9b614686544a8fd99a0bfe9 Mon Sep 17 00:00:00 2001 From: Attaky <203162318+attakygit@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:43:40 -0700 Subject: [PATCH 5/7] feat(build): compile both generated UI trees under MUI_RUNTIME_ROTATION Off by default. When enabled, the primary tree supplies every shared asset and the secondary tree is compiled with the generated rename header forced in, so both layouts are linked exactly once. Both build systems read the source inventory from the generator's manifest rather than globbing, and both run --check so stale glue fails the build. The CMake path matters because that is what CI builds: without it the feature would be invisible to CI and effectively untested. X11 is not LGFX, so the new job covers compiling, linking and the state tests, not the panel rotation itself. The link test references a symbol from each tree because a static library would otherwise link green without ever pulling in the secondary one. --- .github/workflows/ci.yml | 15 +++++ CMakeLists.txt | 17 ++++++ cmake/MuiRuntimeRotation.cmake | 103 +++++++++++++++++++++++++++++++++ extra_script.py | 90 ++++++++++++++++++++++++++-- tests/test_ScreenRotation.cpp | 69 ++++++++++++++++++++++ 5 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 cmake/MuiRuntimeRotation.cmake create mode 100644 tests/test_ScreenRotation.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16d37f8b..c46c9bfe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,3 +75,18 @@ jobs: - name: Run Unit Tests run: | ctest --test-dir build + + # Step 7: Same again with the optional runtime-rotation feature enabled, + # which links both generated layouts. X11 is not LGFX, so this covers + # compiling, linking and the state tests -- not the panel rotation itself. + - name: Configure CMake (runtime rotation) + run: | + cmake -S . -B build-rotation -G Ninja -DMUI_RUNTIME_ROTATION=ON + + - name: Build Project (runtime rotation) + run: | + cmake --build build-rotation + + - name: Run Unit Tests (runtime rotation) + run: | + ctest --test-dir build-rotation diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e0f565e..4a488d1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ endif() option(ENABLE_DOCTESTS "Include tests in the library. Setting this to OFF will remove all doctest related code. Tests in tests/*.cpp will still be enabled." ${MAIN_PROJECT}) option(ENABLE_DEBUG_LOG "Enable debug log" OFF) +option(MUI_RUNTIME_ROTATION "Link both perpendicular UI layouts and select the screen rotation at runtime" OFF) set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON) # with newer cmake versions put all find_package in global scope @@ -52,9 +53,18 @@ find_package(CURL REQUIRED) file(GLOB_RECURSE sources source/* generated/* portduino/* locale/* generated/${GENERATED_VIEW}/*) file(GLOB_RECURSE sources_test tests/*.cpp) +if(MUI_RUNTIME_ROTATION) + include(MuiRuntimeRotation) + mui_runtime_rotation_sources(sources) +endif() + add_library(DeviceUI ${sources}) target_link_libraries(DeviceUI PRIVATE lvgl::lvgl LovyanGFX Portduino Protobufs CURL::libcurl) +if(MUI_RUNTIME_ROTATION) + mui_runtime_rotation_configure(DeviceUI) +endif() + # Handle Windows Static linking dependencies if applicable if(WIN32) target_compile_definitions(DeviceUI PRIVATE CURL_STATICLIB) @@ -95,4 +105,11 @@ if(ENABLE_DOCTESTS) ) set_target_properties(tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) add_test(NAME tests COMMAND tests) + + if(MUI_RUNTIME_ROTATION) + target_include_directories(tests PRIVATE ${MUI_GLUE_DIR}) + add_test(NAME dual_ui_glue + COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_dual_ui.py + --check ${MUI_PRIMARY_VIEW}) + endif() endif() \ No newline at end of file diff --git a/cmake/MuiRuntimeRotation.cmake b/cmake/MuiRuntimeRotation.cmake new file mode 100644 index 00000000..fda3febf --- /dev/null +++ b/cmake/MuiRuntimeRotation.cmake @@ -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() rewrites the caller's source list. +# mui_runtime_rotation_configure() 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() diff --git a/extra_script.py b/extra_script.py index e8269abd..ddae87dc 100644 --- a/extra_script.py +++ b/extra_script.py @@ -1,6 +1,9 @@ # See https://docs.platformio.org/en/latest/manifests/library-json/fields/build/extrascript.html Import("env") -from os.path import join, realpath +import os +import subprocess +from os.path import basename, join, realpath + # Base srcFilter. Cannot be set in library.json. src_filter = [ "+", @@ -8,17 +11,96 @@ "+" ] +DUAL_UI_VIEWS = ("ui_320x240", "ui_240x320") + + +def define_name(item): + # CPPDEFINES entries are either "NAME" or a ("NAME", value) pair + if isinstance(item, str): + return item + if isinstance(item, (list, tuple)) and item: + return str(item[0]) + return "" + + +view = None +runtime_rotation = False for item in env.get("CPPDEFINES", []): + name = define_name(item) # Add generated view directory to include path dependending on VIEW_* macro - if isinstance(item,str) and item.startswith("VIEW_"): - view = f"ui_{item[5:]}".lower() # Ex value: "ui_320x240" + if name.startswith("VIEW_"): + view = f"ui_{name[5:]}".lower() # Ex value: "ui_320x240" env.Append(CPPPATH=[realpath(join("generated", view))]) src_filter.append(f"+") + elif name == "MUI_RUNTIME_ROTATION": + runtime_rotation = True # Add portduino directory to include path dependending on ARCH_PORTDUINO macro - elif item == "ARCH_PORTDUINO": + elif name == "ARCH_PORTDUINO": env.Append(CPPPATH=[realpath("portduino")]) src_filter.append("+") +if runtime_rotation: + # Link both perpendicular layouts so the rotation becomes a runtime setting. + # The primary tree (this build's VIEW_*) supplies every shared asset; the + # secondary tree is compiled with its colliding globals renamed through a + # generated forced include. + if view not in DUAL_UI_VIEWS: + raise Exception("MUI_RUNTIME_ROTATION supports only %s, not %r" + % (" and ".join(DUAL_UI_VIEWS), view)) + secondary = DUAL_UI_VIEWS[1] if view == DUAL_UI_VIEWS[0] else DUAL_UI_VIEWS[0] + + lib_root = realpath(".") + generated = join(lib_root, "tools", "generated", "dual") + generator = join(lib_root, "tools", "gen_dual_ui.py") + + # Fails the build when the committed glue no longer matches the UI trees. + check = subprocess.run([env.subst("$PYTHONEXE"), generator, "--check", view], + capture_output=True, text=True) + if check.returncode != 0: + raise Exception("MUI_RUNTIME_ROTATION: %s%s" % (check.stdout, check.stderr)) + + core_sources, secondary_assets, glue_sources = [], [], [] + with open(join(generated, "manifest.txt")) as f: + for line in f: + key, _, value = line.strip().partition(" ") + if key == "core_source": + core_sources.append(value) + elif key == "glue_source": + glue_sources.append(value) + elif key == "secondary_asset": + # "secondary_asset ": only when is the + # secondary tree does its unique asset have to be compiled + view_name, _, asset = value.partition(" ") + if view_name == secondary: + secondary_assets.append(asset) + + for src_name in core_sources + secondary_assets: + if os.path.exists(join(lib_root, "generated", secondary, src_name)): + src_filter.append(f"+") + # listed rather than globbed, so a stale .c cannot enter the build + for src_name in glue_sources: + src_filter.append(f"+") + env.Append(CPPPATH=[generated]) + + rename_flags = ["-include", join(generated, "ui_secondary_rename.h"), + "-I", realpath(join("generated", secondary))] + routing_flags = ["-include", join(generated, "style_routing.h")] + STYLE_ROUTED_CXX = ("Themes.cpp", "TFTView_320x240.cpp") + + def apply_dual_ui_flags(env, node): + path = realpath(node.srcnode().get_abspath()) + name = basename(path) + secondary_tu = os.sep + secondary + os.sep in path and name not in secondary_assets + # the secondary-side bridge needs the secondary screens.h and the + # renames; the primary-side bridge must see the primary tree untouched + if secondary_tu or name == "bridge_secondary.c": + return env.Object(node, CPPFLAGS=env.get("CPPFLAGS", []) + rename_flags) + if name in STYLE_ROUTED_CXX: + return env.Object(node, CXXFLAGS=env.get("CXXFLAGS", []) + routing_flags) + return node + + env.AddBuildMiddleware(apply_dual_ui_flags, "*") + # Only `Replace` is supported for SRC_FILTER, not `Append` or `Prepend` env.Replace(SRC_FILTER=src_filter) diff --git a/tests/test_ScreenRotation.cpp b/tests/test_ScreenRotation.cpp new file mode 100644 index 00000000..5fc67de0 --- /dev/null +++ b/tests/test_ScreenRotation.cpp @@ -0,0 +1,69 @@ +#ifdef MUI_RUNTIME_ROTATION + +#include "graphics/ScreenRotation.h" +#include "screens.h" +#include + +// The secondary tree is linked under renamed symbols. Referencing one here +// forces the linker to extract its objects: without this a static-library +// build links green while never pulling in the secondary layout at all. +extern "C" { +extern objects_t MUI2_objects; +void mui_bridge_publish_secondary(void); +} + +TEST_CASE("both generated layouts are linked") +{ + CHECK(&objects != &MUI2_objects); + CHECK(mui_bridge_publish_secondary != nullptr); +} + +TEST_CASE("panel rotation runs opposite to the panel's own numbering") +{ + CHECK(ScreenRotation::panelRotation(ScreenRotation::Rotation0) == 0); + CHECK(ScreenRotation::panelRotation(ScreenRotation::Rotation90) == 3); + CHECK(ScreenRotation::panelRotation(ScreenRotation::Rotation180) == 2); + CHECK(ScreenRotation::panelRotation(ScreenRotation::Rotation270) == 1); + + // parity must survive, or the tree selection would disagree with the size + for (uint8_t v = 0; v <= 3; v++) + CHECK((ScreenRotation::panelRotation((ScreenRotation::Value)v) & 1) == (v & 1)); +} + +TEST_CASE("odd quarter turns select the perpendicular tree") +{ + CHECK_FALSE(ScreenRotation::usesSecondaryTree(ScreenRotation::Rotation0)); + CHECK(ScreenRotation::usesSecondaryTree(ScreenRotation::Rotation90)); + CHECK_FALSE(ScreenRotation::usesSecondaryTree(ScreenRotation::Rotation180)); + CHECK(ScreenRotation::usesSecondaryTree(ScreenRotation::Rotation270)); +} + +TEST_CASE("odd quarter turns swap the layout dimensions") +{ + const uint16_t w = ScreenRotation::width(ScreenRotation::Rotation0); + const uint16_t h = ScreenRotation::height(ScreenRotation::Rotation0); + CHECK(w != h); + + // 180 keeps the aspect, 90/270 transpose it + CHECK(ScreenRotation::width(ScreenRotation::Rotation180) == w); + CHECK(ScreenRotation::height(ScreenRotation::Rotation180) == h); + CHECK(ScreenRotation::width(ScreenRotation::Rotation90) == h); + CHECK(ScreenRotation::height(ScreenRotation::Rotation90) == w); + CHECK(ScreenRotation::width(ScreenRotation::Rotation270) == h); + CHECK(ScreenRotation::height(ScreenRotation::Rotation270) == w); +} + +// The tests above use the pure mapping helpers and never touch the loaded +// state; this is the only one that does, and setLoaded() is deliberately +// one-shot. +TEST_CASE("an out-of-range stored value falls back to the build default") +{ + const ScreenRotation::Value before = ScreenRotation::get(); + ScreenRotation::setLoaded(9); + CHECK(ScreenRotation::get() == before); + + ScreenRotation::setLoaded(ScreenRotation::Rotation90); // ignored, one-shot + CHECK(ScreenRotation::get() == before); +} + +#endif // MUI_RUNTIME_ROTATION From e4f763900a1fba80fb02a29b387632e4bea38cc5 Mon Sep 17 00:00:00 2001 From: Attaky <203162318+attakygit@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:43:55 -0700 Subject: [PATCH 6/7] feat(graphics): apply the stored rotation in the display path The panel is rotated before any layout exists and LVGL is then told the rotated panel's own resolution, rather than the layout's nominal size: substituting the latter would misreport panels larger than the layout, such as 320x480 ones. The view dispatches the secondary tree's ui_init* and publishes the bridge before any objects.* dereference and before apply_hotfix caches pointers. --- include/graphics/driver/LGFXDriver.h | 17 ++++++++++++- source/graphics/TFT/TFTView_320x240.cpp | 34 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/graphics/driver/LGFXDriver.h b/include/graphics/driver/LGFXDriver.h index 2255d2f9..486b6424 100644 --- a/include/graphics/driver/LGFXDriver.h +++ b/include/graphics/driver/LGFXDriver.h @@ -1,6 +1,9 @@ #pragma once #include "LovyanGFX.h" +#ifdef MUI_RUNTIME_ROTATION +#include "graphics/ScreenRotation.h" +#endif #include "graphics/driver/DisplayDriverConfig.h" #include "graphics/driver/TFTDriver.h" #include "input/InputDriver.h" @@ -321,7 +324,19 @@ template void LGFXDriver::init(DeviceGUI *gui) lv_display_add_event_cb(this->display, rounder_cb, LV_EVENT_INVALIDATE_AREA, this->display); #endif -#if defined(DISPLAY_SET_RESOLUTION) +#if defined(MUI_RUNTIME_ROTATION) + // Rotate before any layout exists, then take the resolution from the + // rotated panel itself: the layout's nominal size must not be substituted + // here, or panels larger than the layout (e.g. 320x480) would be told the + // wrong size. + ScreenRotation::load(); + { + ISpiLock::Guard bus; // setRotation talks to the panel + lgfx->setRotation(ScreenRotation::panelRotation()); + } + ILOG_DEBUG("Set display resolution: %dx%d, rotation %d", lgfx->width(), lgfx->height(), ScreenRotation::panelRotation()); + lv_display_set_resolution(this->display, lgfx->width(), lgfx->height()); +#elif defined(DISPLAY_SET_RESOLUTION) ILOG_DEBUG("Set display resolution: %dx%d", lgfx->screenWidth, lgfx->screenHeight); lv_display_set_resolution(this->display, lgfx->screenWidth, lgfx->screenHeight); #endif diff --git a/source/graphics/TFT/TFTView_320x240.cpp b/source/graphics/TFT/TFTView_320x240.cpp index d2ea076d..3c5c6a89 100644 --- a/source/graphics/TFT/TFTView_320x240.cpp +++ b/source/graphics/TFT/TFTView_320x240.cpp @@ -22,6 +22,15 @@ #include "util/FileLoader.h" #include "util/ILog.h" #include "util/ISpiLock.h" +#ifdef MUI_RUNTIME_ROTATION +#include "graphics/ScreenRotation.h" +// secondary (renamed) generated tree plus the generated field-wise bridge +extern "C" { +void MUI2_ui_init_boot(void); +void MUI2_ui_init(void); +void mui_bridge_publish_secondary(void); +} +#endif #include #include #include @@ -126,7 +135,14 @@ bool TFTView_320x240::screenUnlockRequest = false; TFTView_320x240 *TFTView_320x240::instance(void) { if (!gui) { +#ifdef MUI_RUNTIME_ROTATION + // the driver applies the stored rotation during init(); these sizes + // only seed DisplayDriver's members, so they come from the same source + ScreenRotation::load(); + gui = new TFTView_320x240(nullptr, DisplayDriverFactory::create(ScreenRotation::width(), ScreenRotation::height())); +#else gui = new TFTView_320x240(nullptr, DisplayDriverFactory::create(320, 240)); +#endif } return gui; } @@ -171,7 +187,16 @@ void TFTView_320x240::init(IClientBase *client) MeshtasticView::init(client); +#ifdef MUI_RUNTIME_ROTATION + if (ScreenRotation::usesSecondaryTree()) { + MUI2_ui_init_boot(); + mui_bridge_publish_secondary(); // must precede any objects.* deref + } else { + ui_init_boot(); + } +#else ui_init_boot(); +#endif FileLoader::init(&fileSystem); if (!FileLoader::loadBootImage(objects.boot_logo)) lv_image_set_src(objects.boot_logo, &img_meshtastic_boot_logo_image); @@ -356,7 +381,16 @@ void TFTView_320x240::init_screens(void) { ILOG_DEBUG("init screens..."); state = MeshtasticView::eInitScreens; +#ifdef MUI_RUNTIME_ROTATION + if (ScreenRotation::usesSecondaryTree()) { + MUI2_ui_init(); + mui_bridge_publish_secondary(); // before apply_hotfix caches pointers + } else { + ui_init(); + } +#else ui_init(); +#endif apply_hotfix(); activeMsgContainer = objects.messages_container; From 35131fae714d20539587386cf5238e835212465a Mon Sep 17 00:00:00 2001 From: Attaky <203162318+attakygit@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:44:06 -0700 Subject: [PATCH 7/7] feat(settings): screen rotation chooser Adds a settings entry and a dropdown dialog copied from the generated dropdown-panel idiom. The option order is the stored value order, and the labels follow from which layout the build compiled as primary, so an even value always reads as the built-in aspect. The choice is persisted through the existing storeUIConfig path and followed by a reboot request: the value is only read at boot, and the firmware keeps serving the pre-change config until it reloads. A copy is submitted so a failed store cannot leave the new value in memory for an unrelated save to persist, and the dialog stays open unless both submissions succeed. Comparing against the persisted value rather than the active one keeps a saved-but-not-yet-applied change retryable. --- include/graphics/view/TFT/TFTView_320x240.h | 19 +- locale/bg.yml | 8 + locale/cs.yml | 8 + locale/da.yml | 8 + locale/de.yml | 8 + locale/el.yml | 8 + locale/en.yml | 8 + locale/es.yml | 8 + locale/fi.yml | 8 + locale/fr.yml | 8 + locale/hu.yml | 8 + locale/it.yml | 8 + locale/nl.yml | 8 + locale/no.yml | 8 + locale/pl.yml | 8 + locale/pt.yml | 8 + locale/ro.yml | 8 + locale/ru.yml | 8 + locale/se.yml | 8 + locale/sl.yml | 8 + locale/sr.yml | 8 + locale/tr.yml | 8 + locale/uk.yml | 8 + locale/zh-CN.yml | 8 + source/graphics/TFT/TFTView_320x240.cpp | 206 ++++++++++++++++++++ 25 files changed, 408 insertions(+), 1 deletion(-) diff --git a/include/graphics/view/TFT/TFTView_320x240.h b/include/graphics/view/TFT/TFTView_320x240.h index 1730f308..00b4472e 100644 --- a/include/graphics/view/TFT/TFTView_320x240.h +++ b/include/graphics/view/TFT/TFTView_320x240.h @@ -106,7 +106,10 @@ class TFTView_320x240 : public MeshtasticView eReset, eReboot, eDisplayMode, - eModifyChannel + eModifyChannel, +#ifdef MUI_RUNTIME_ROTATION + eScreenRotation +#endif }; protected: @@ -368,6 +371,20 @@ class TFTView_320x240 : public MeshtasticView static void ui_event_cancel(lv_event_t *e); static void ui_event_backup_restore_radio_button(lv_event_t *e); +#ifdef MUI_RUNTIME_ROTATION + static void ui_event_screen_rotation_button(lv_event_t *e); + void showScreenRotationDialog(void); + void applyScreenRotationDialog(void); + void closeScreenRotationDialog(void); + void updateScreenRotationLabel(void); + // the generated ok_cancel_widget writes into the objects struct by index, + // so the row is rebuilt here instead of reused + void addOkCancelRow(lv_obj_t *parent); + lv_obj_t *screenRotationLabel = nullptr; + lv_obj_t *screenRotationPanel = nullptr; + lv_obj_t *screenRotationDropdown = nullptr; +#endif + // map navigation static void ui_screen_event_cb(lv_event_t *e); static void ui_event_arrow(lv_event_t *e); diff --git a/locale/bg.yml b/locale/bg.yml index b56ee124..18040506 100644 --- a/locale/bg.yml +++ b/locale/bg.yml @@ -144,3 +144,11 @@ bg: Sound only: Само звук no signal: ~ Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/cs.yml b/locale/cs.yml index b87c2ef0..60b795f5 100644 --- a/locale/cs.yml +++ b/locale/cs.yml @@ -144,3 +144,11 @@ cs: region unset: region nenastaven no signal: bez signálu Restoring messages ...: Obnovuji zprávy... + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/da.yml b/locale/da.yml index bfd47794..155c7fb5 100644 --- a/locale/da.yml +++ b/locale/da.yml @@ -165,3 +165,11 @@ da: SD card error: SD-kort fejl SD unknown error: Ukendt SD-kort-fejl "Heap: %d (%d%%)\nLVGL: %d (%d%%)": "Heap: %d (%d%%)\nLVGL: %d (%d%%)" + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/de.yml b/locale/de.yml index e939bd56..29d17de1 100644 --- a/locale/de.yml +++ b/locale/de.yml @@ -154,3 +154,11 @@ de: region unset: keine Region no signal: kein Signal Restoring messages ...: Lade Nachrichten... + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/el.yml b/locale/el.yml index 72ad621a..05c1d001 100644 --- a/locale/el.yml +++ b/locale/el.yml @@ -167,3 +167,11 @@ el: SD card error: SD σφάλμα κάρτας SD unknown error: SD άγνωστο σφάλμα "Heap: %d (%d%%)\nLVGL: %d (%d%%)": ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/en.yml b/locale/en.yml index 8c0a27bb..9fe78563 100644 --- a/locale/en.yml +++ b/locale/en.yml @@ -167,3 +167,11 @@ en: SD card error: ~ SD unknown error: ~ "Heap: %d (%d%%)\nLVGL: %d (%d%%)": ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/es.yml b/locale/es.yml index bc83677b..e81556f9 100644 --- a/locale/es.yml +++ b/locale/es.yml @@ -162,3 +162,11 @@ es: 'Failed to parse keys!': Error procesando claves! 'Failed to retrieve keys!': Error obteniendo ficheros! "%s (%0.1f GB)\nUsed: %d MB (%d%%)": "%s (%0.1f GB)\nUsado: %d MB (%d%%)" + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/fi.yml b/locale/fi.yml index a980c9b9..21ebb5ea 100644 --- a/locale/fi.yml +++ b/locale/fi.yml @@ -150,3 +150,11 @@ fi: Sound only: ~ no signal: ~ Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/fr.yml b/locale/fr.yml index c28a9594..990793fe 100644 --- a/locale/fr.yml +++ b/locale/fr.yml @@ -157,3 +157,11 @@ fr: Failed to parse keys!: Erreur de lecture! Failed to retrieve keys!: Erreur de lecture! "%s (%0.1f GB)\nUsed: %d MB (%d%%)": "%s (%0.1f GB)\nUtilisé: %d MB (%d%%)" + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/hu.yml b/locale/hu.yml index d37a5242..3302cb49 100644 --- a/locale/hu.yml +++ b/locale/hu.yml @@ -167,3 +167,11 @@ hu: SD card error: SD-kártya hiba SD unknown error: Ismeretlen SD-hiba "Heap: %d (%d%%)\nLVGL: %d (%d%%)": ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/it.yml b/locale/it.yml index 37f2e232..84284380 100644 --- a/locale/it.yml +++ b/locale/it.yml @@ -144,3 +144,11 @@ it: Sound only: Solo Suono no signal: nessun segnale Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/nl.yml b/locale/nl.yml index 3ad3ffd3..3a4a34dd 100644 --- a/locale/nl.yml +++ b/locale/nl.yml @@ -187,3 +187,11 @@ nl: Failed to parse keys!: Keys verwerken mislukt! Failed to retrieve keys!: Keys ophalen mislukt! "%s (%0.1f GB)\nUsed: %d MB (%d%%)": "%s (%0.1f GB)\nGebruikt: %d MB (%d%%)" + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/no.yml b/locale/no.yml index 7e61e19e..325bcd86 100644 --- a/locale/no.yml +++ b/locale/no.yml @@ -189,3 +189,11 @@ no: Failed to parse keys!: Analysering av nøkler feilet! Failed to retrieve keys!: Mottak av nøkler feilet! "%s: %d GB (%s)\nUsed: %0.2f GB (%d%%)": "%s: %d GB (%s)\nBrukt: %0.2f GB (%d%%)" + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/pl.yml b/locale/pl.yml index 8c052896..430e819b 100644 --- a/locale/pl.yml +++ b/locale/pl.yml @@ -152,3 +152,11 @@ pl: Sound only: ~ no signal: ~ Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/pt.yml b/locale/pt.yml index 7ad8027f..db3fa6b9 100644 --- a/locale/pt.yml +++ b/locale/pt.yml @@ -172,3 +172,11 @@ pt: Sound only: ~ no signal: ~ Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/ro.yml b/locale/ro.yml index 30b450dc..dcddd3dc 100644 --- a/locale/ro.yml +++ b/locale/ro.yml @@ -141,3 +141,11 @@ ro: Sound only: ~ no signal: ~ Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/ru.yml b/locale/ru.yml index d6c1d141..fa8ef1ab 100644 --- a/locale/ru.yml +++ b/locale/ru.yml @@ -140,3 +140,11 @@ ru: Sound only: Только звук no signal: ~ Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/se.yml b/locale/se.yml index 3bb8b7e4..1048afd8 100644 --- a/locale/se.yml +++ b/locale/se.yml @@ -196,3 +196,11 @@ se: Client Hidden Lost & Found TAK Tracker + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/sl.yml b/locale/sl.yml index d65deb96..f859cd3b 100644 --- a/locale/sl.yml +++ b/locale/sl.yml @@ -154,3 +154,11 @@ sl: region unset: regija ni nastavljena no signal: ni signala Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/sr.yml b/locale/sr.yml index 7df6c736..7e17ef08 100644 --- a/locale/sr.yml +++ b/locale/sr.yml @@ -153,3 +153,11 @@ sr: region unset: ~ no signal: ~ Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/tr.yml b/locale/tr.yml index 195e9cae..a6c3713a 100644 --- a/locale/tr.yml +++ b/locale/tr.yml @@ -143,3 +143,11 @@ tr: Sound only: Sadece ses no signal: Sinyal yok Restoring messages ...: Mesajlar kurtarılıyor... + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/uk.yml b/locale/uk.yml index 34f71b41..8307330d 100644 --- a/locale/uk.yml +++ b/locale/uk.yml @@ -157,3 +157,11 @@ uk: 'uptime: %02d:%02d:%02d': 'час роботи: %02d:%02d:%02d' "%s (%0.1f GB)\nUsed: %d MB (%d%%)": "%s (%0.1f GB)\nВикорист.: %d MB (%d%%)" "Heap: %d (%d%%)\nLVGL: %d (%d%%)": ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/locale/zh-CN.yml b/locale/zh-CN.yml index 946d496c..f37fdd00 100644 --- a/locale/zh-CN.yml +++ b/locale/zh-CN.yml @@ -131,3 +131,11 @@ zh-CN: region unset: 区域未设置 no signal: 无信号 Restoring messages ...: ~ + Orientation: ~ + Landscape: ~ + Portrait: ~ + Landscape flipped: ~ + Portrait flipped: ~ + Restarting to apply: ~ + Save failed: ~ + Restart required: ~ diff --git a/source/graphics/TFT/TFTView_320x240.cpp b/source/graphics/TFT/TFTView_320x240.cpp index 3c5c6a89..d7e17366 100644 --- a/source/graphics/TFT/TFTView_320x240.cpp +++ b/source/graphics/TFT/TFTView_320x240.cpp @@ -825,6 +825,21 @@ void TFTView_320x240::ui_events_init(void) lv_obj_add_event_cb(objects.basic_settings_reset_button, ui_event_reset_button, LV_EVENT_CLICKED, NULL); lv_obj_add_event_cb(objects.basic_settings_reboot_button, ui_event_reboot_button, LV_EVENT_CLICKED, NULL); +#ifdef MUI_RUNTIME_ROTATION + { + // the feature is build-time optional, so no generated entry exists for + // it; the row is created here with the generated button style + lv_obj_t *rotationButton = lv_button_create(lv_obj_get_parent(objects.basic_settings_timezone_button)); + lv_obj_set_size(rotationButton, LV_PCT(95), 30); + add_style_settings_button_style(rotationButton); + lv_obj_set_style_shadow_width(rotationButton, 0, LV_PART_MAIN | LV_STATE_DEFAULT); + screenRotationLabel = lv_label_create(rotationButton); + lv_obj_set_align(screenRotationLabel, LV_ALIGN_LEFT_MID); + updateScreenRotationLabel(); + lv_obj_add_event_cb(rotationButton, ui_event_screen_rotation_button, LV_EVENT_CLICKED, NULL); + } +#endif + lv_obj_add_event_cb(objects.reboot_button, ui_event_device_reboot_button, LV_EVENT_CLICKED, NULL); lv_obj_add_event_cb(objects.progmode_button, ui_event_device_progmode_button, LV_EVENT_ALL, NULL); lv_obj_add_event_cb(objects.shutdown_button, ui_event_device_shutdown_button, LV_EVENT_CLICKED, NULL); @@ -4291,6 +4306,12 @@ void TFTView_320x240::ui_event_ok(lv_event_t *e) } return; } +#ifdef MUI_RUNTIME_ROTATION + case eScreenRotation: + // apply/close own the panel state, so skip the common tail + THIS->applyScreenRotationDialog(); + return; +#endif default: ILOG_ERROR("Unhandled ok event"); break; @@ -4409,6 +4430,11 @@ void TFTView_320x240::ui_event_cancel(lv_event_t *e) THIS->activeSettings = eChannel; return; } +#ifdef MUI_RUNTIME_ROTATION + case eScreenRotation: + THIS->closeScreenRotationDialog(); // owns the panel state + return; +#endif default: ILOG_ERROR("Unhandled cancel event"); break; @@ -5929,6 +5955,186 @@ bool TFTView_320x240::isScreenLocked(void) return screenLocked && !screenUnlockRequest; } +#ifdef MUI_RUNTIME_ROTATION + +// Even values keep the primary layout's aspect, odd values use the +// perpendicular one, so which label a value carries depends on which tree this +// build compiled as primary. +static const char *rotationValueName(uint8_t value) +{ + switch (value & 3) { +#if defined(VIEW_240x320) + case ScreenRotation::Rotation0: + return _("Portrait"); + case ScreenRotation::Rotation90: + return _("Landscape"); + case ScreenRotation::Rotation180: + return _("Portrait flipped"); + default: + return _("Landscape flipped"); +#else + case ScreenRotation::Rotation0: + return _("Landscape"); + case ScreenRotation::Rotation90: + return _("Portrait"); + case ScreenRotation::Rotation180: + return _("Landscape flipped"); + default: + return _("Portrait flipped"); +#endif + } +} + +void TFTView_320x240::updateScreenRotationLabel(void) +{ + if (!screenRotationLabel) + return; + char buf[64]; + lv_snprintf(buf, sizeof(buf), "%s: %s", _("Orientation"), rotationValueName((uint8_t)ScreenRotation::get())); + lv_label_set_text(screenRotationLabel, buf); +} + +void TFTView_320x240::ui_event_screen_rotation_button(lv_event_t *e) +{ + if (lv_event_get_code(e) == LV_EVENT_CLICKED && THIS->activeSettings == eNone) + THIS->showScreenRotationDialog(); +} + +void TFTView_320x240::showScreenRotationDialog(void) +{ + if (screenRotationPanel || activeSettings != eNone) + return; + + // copies the generated dropdown-panel idiom (SettingsDeviceRolePanel) + screenRotationPanel = lv_obj_create(objects.main_screen); + lv_obj_set_pos(screenRotationPanel, LV_PCT(3), LV_PCT(25)); + lv_obj_set_size(screenRotationPanel, 220, 120); + lv_obj_clear_flag(screenRotationPanel, LV_OBJ_FLAG_SCROLLABLE); + add_style_settings_panel_style(screenRotationPanel); + lv_obj_set_style_pad_all(screenRotationPanel, 0, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_border_width(screenRotationPanel, 2, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_radius(screenRotationPanel, 12, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_border_color(screenRotationPanel, lv_color_hex(0xff216ad8), LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_align(screenRotationPanel, LV_ALIGN_TOP_MID, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_border_opa(screenRotationPanel, 255, LV_PART_MAIN | LV_STATE_DEFAULT); + + screenRotationDropdown = lv_dropdown_create(screenRotationPanel); + lv_obj_set_pos(screenRotationDropdown, 0, 8); + lv_obj_set_size(screenRotationDropdown, 150, 30); + char options[128]; // option order is the stored value order (0..3) + lv_snprintf(options, sizeof(options), "%s\n%s\n%s\n%s", rotationValueName(ScreenRotation::Rotation0), + rotationValueName(ScreenRotation::Rotation90), rotationValueName(ScreenRotation::Rotation180), + rotationValueName(ScreenRotation::Rotation270)); + lv_dropdown_set_options(screenRotationDropdown, options); + add_style_drop_down_style(screenRotationDropdown); + lv_obj_set_style_align(screenRotationDropdown, LV_ALIGN_TOP_MID, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_border_color(screenRotationDropdown, lv_color_hex(0xffe0e0e0), LV_PART_MAIN | LV_STATE_DEFAULT); + // the persisted value, which is what the next boot will use + lv_dropdown_set_selected(screenRotationDropdown, (uint8_t)db.uiConfig.screen_rotation); + + addOkCancelRow(screenRotationPanel); + lv_group_focus_obj(screenRotationDropdown); + disablePanel(objects.controller_panel); + disablePanel(objects.tab_page_basic_settings); + activeSettings = eScreenRotation; +} + +void TFTView_320x240::applyScreenRotationDialog(void) +{ + // Compare against the persisted value, not the active one: a change saved + // earlier may still be waiting for the restart, and re-picking the active + // value then has to be treated as a real change back. + const uint8_t persisted = (uint8_t)db.uiConfig.screen_rotation; + const uint8_t choice = screenRotationDropdown ? (uint8_t)lv_dropdown_get_selected(screenRotationDropdown) : persisted; + if (choice > (uint8_t)ScreenRotation::Rotation270 || choice == persisted) { + closeScreenRotationDialog(); + if (persisted != (uint8_t)ScreenRotation::get()) + messageAlert(_("Restart required"), true); + return; + } + + // Submit a copy: a failed store must not leave the new value in db.uiConfig, + // where an unrelated save would later persist it behind the user's back. + meshtastic_DeviceUIConfig cfg = db.uiConfig; + cfg.screen_rotation = (meshtastic_DeviceUIConfig_ScreenRotation)choice; + if (!controller->storeUIConfig(cfg)) { + messageAlert(_("Save failed"), true); + return; // dialog stays open so OK can be retried + } + db.uiConfig = cfg; // persisted, keep the in-memory copy in sync + + // The value is only read at boot, and the firmware keeps serving the + // pre-change config until it reloads, so the reboot is part of applying it + // (same pattern as the language setting). + if (!controller->requestReboot(5)) { + messageAlert(_("Restart required"), true); + return; + } + closeScreenRotationDialog(); + messageAlert(_("Restarting to apply"), true); +} + +void TFTView_320x240::closeScreenRotationDialog(void) +{ + if (activeSettings == eScreenRotation) { + activeSettings = eNone; + enablePanel(objects.controller_panel); + enablePanel(objects.tab_page_basic_settings); + if (screenRotationLabel) + lv_group_focus_obj(lv_obj_get_parent(screenRotationLabel)); // back to the opener + } + if (screenRotationPanel) { + lv_obj_delete(screenRotationPanel); + screenRotationPanel = nullptr; + screenRotationDropdown = nullptr; // child of the panel + } +} + +void TFTView_320x240::addOkCancelRow(lv_obj_t *parent) +{ + // visual copy of the generated ok_cancel_widget: the generated function + // cannot be reused because it writes its objects into the objects struct + // by index + lv_obj_t *row = lv_obj_create(parent); + lv_obj_set_size(row, 160, 50); + lv_obj_clear_flag(row, (lv_obj_flag_t)(LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_SCROLL_ELASTIC | + LV_OBJ_FLAG_SCROLL_WITH_ARROW)); // C++ needs the explicit cast + lv_obj_set_scrollbar_mode(row, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_scroll_dir(row, LV_DIR_NONE); + add_style_panel_style(row); + lv_obj_set_style_align(row, LV_ALIGN_BOTTOM_MID, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_border_width(row, 0, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_layout(row, LV_LAYOUT_FLEX, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_pad_top(row, 8, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_pad_left(row, 4, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_pad_right(row, 4, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_flex_main_place(row, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT); + + struct { + const char *text; + lv_align_t align; + lv_event_cb_t cb; + bool pad; + } spec[2] = {{_("OK"), LV_ALIGN_LEFT_MID, ui_event_ok, false}, {_("Cancel"), LV_ALIGN_RIGHT_MID, ui_event_cancel, true}}; + for (auto &b : spec) { + lv_obj_t *btn = lv_btn_create(row); + lv_obj_set_size(btn, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_obj_set_style_bg_color(btn, lv_color_hex(0xff216ad8), LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_radius(btn, 7, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_clip_corner(btn, true, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_align(btn, b.align, LV_PART_MAIN | LV_STATE_DEFAULT); + if (b.pad) { + lv_obj_set_style_pad_left(btn, 10, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_pad_right(btn, 10, LV_PART_MAIN | LV_STATE_DEFAULT); + } + lv_label_set_text(lv_label_create(btn), b.text); + lv_obj_add_event_cb(btn, b.cb, LV_EVENT_CLICKED, 0); + } +} + +#endif // MUI_RUNTIME_ROTATION + void TFTView_320x240::updateChannelConfig(const meshtastic_Channel &ch) { static lv_obj_t *btn[c_max_channels] = {objects.channel_button0, objects.channel_button1, objects.channel_button2,