From 254c4f441394477c0d6a808aea43d9501f0bba61 Mon Sep 17 00:00:00 2001 From: philmoz Date: Fri, 24 Nov 2023 16:15:54 +1100 Subject: [PATCH] Color UI refactor. --- radio/src/bitmaps/480x272/CMakeLists.txt | 4 - .../bitmaps/480x272/bootloader/icon_error.png | Bin 1100 -> 0 bytes .../bitmaps/480x272/bootloader/icon_exit.png | Bin 641 -> 0 bytes .../bitmaps/480x272/bootloader/icon_file.png | Bin 276 -> 0 bytes .../bitmaps/480x272/bootloader/icon_flash.png | Bin 696 -> 0 bytes .../bitmaps/480x272/bootloader/icon_ok.png | Bin 823 -> 0 bytes .../bitmaps/480x272/bootloader/icon_sd.png | Bin 514 -> 0 bytes .../480x272/button/alpha_button_off.png | Bin 5512 -> 0 bytes .../src/bitmaps/480x272/mask_coord_shadow.png | Bin 251 -> 0 bytes radio/src/bitmaps/480x272/mask_cvpoint.png | Bin 369 -> 0 bytes .../bitmaps/480x272/mask_cvpoint_center.png | Bin 222 -> 0 bytes radio/src/bitmaps/480x272/mask_point.png | Bin 212 -> 0 bytes .../bitmaps/480x272/mask_round_title_left.png | Bin 0 -> 1791 bytes .../480x272/mask_round_title_right.png | Bin 0 -> 1807 bytes radio/src/bitmaps/480x272/mask_rscale.png | Bin 2604 -> 0 bytes .../bitmaps/480x272/mask_shutdown_circle.png | Bin 4547 -> 0 bytes .../bitmaps/480x272/mask_shutdown_circle0.png | Bin 0 -> 2478 bytes .../bitmaps/480x272/mask_shutdown_circle1.png | Bin 0 -> 2537 bytes .../bitmaps/480x272/mask_shutdown_circle2.png | Bin 0 -> 2495 bytes .../bitmaps/480x272/mask_shutdown_circle3.png | Bin 0 -> 2541 bytes .../src/bitmaps/480x272/mask_trim_shadow.png | Bin 210 -> 0 bytes radio/src/bitmaps/480x272/mask_txbat.png | Bin 310 -> 1483 bytes .../bitmaps/480x272/mask_txbat_charging.png | Bin 553 -> 1761 bytes .../bitmaps/480x272/volume/mask_volume_0.png | Bin 866 -> 1912 bytes .../bitmaps/480x272/volume/mask_volume_1.png | Bin 833 -> 1920 bytes .../bitmaps/480x272/volume/mask_volume_2.png | Bin 922 -> 1978 bytes .../bitmaps/480x272/volume/mask_volume_3.png | Bin 1012 -> 2075 bytes .../bitmaps/480x272/volume/mask_volume_4.png | Bin 1213 -> 2222 bytes .../480x272/volume/mask_volume_scale.png | Bin 604 -> 3457 bytes radio/src/boards/generic_stm32/switches.cpp | 1 - radio/src/dataconstants.h | 5 +- radio/src/gui/colorlcd/CMakeLists.txt | 167 +- radio/src/gui/colorlcd/LvglWrapper.cpp | 29 +- radio/src/gui/colorlcd/LvglWrapper.h | 9 +- radio/src/gui/colorlcd/access_settings.cpp | 412 ++--- radio/src/gui/colorlcd/access_settings.h | 51 +- radio/src/gui/colorlcd/afhds2a_settings.cpp | 32 +- radio/src/gui/colorlcd/afhds2a_settings.h | 2 +- radio/src/gui/colorlcd/afhds3_options.cpp | 32 +- radio/src/gui/colorlcd/afhds3_options.h | 2 +- radio/src/gui/colorlcd/afhds3_settings.cpp | 123 +- radio/src/gui/colorlcd/afhds3_settings.h | 4 +- radio/src/gui/colorlcd/bind_menu_d16.cpp | 4 +- radio/src/gui/colorlcd/bitmaps.cpp | 385 ++-- radio/src/gui/colorlcd/bitmaps.h | 143 +- radio/src/gui/colorlcd/channel_bar.cpp | 313 ++-- radio/src/gui/colorlcd/channel_bar.h | 144 +- radio/src/gui/colorlcd/channel_range.cpp | 82 +- radio/src/gui/colorlcd/channel_range.h | 4 +- radio/src/gui/colorlcd/color_editor.cpp | 386 ++-- radio/src/gui/colorlcd/color_editor.h | 25 +- radio/src/gui/colorlcd/color_list.cpp | 67 +- radio/src/gui/colorlcd/color_list.h | 27 +- radio/src/gui/colorlcd/color_picker.cpp | 141 +- radio/src/gui/colorlcd/color_picker.h | 6 +- radio/src/gui/colorlcd/colors.cpp | 183 +- radio/src/gui/colorlcd/colors.h | 112 +- radio/src/gui/colorlcd/confirm_dialog.cpp | 74 - radio/src/gui/colorlcd/confirm_dialog.h | 41 - radio/src/gui/colorlcd/crossfire_settings.cpp | 10 +- radio/src/gui/colorlcd/crossfire_settings.h | 2 +- radio/src/gui/colorlcd/curve.cpp | 348 ++-- radio/src/gui/colorlcd/curve.h | 96 +- radio/src/gui/colorlcd/curve_param.cpp | 17 +- radio/src/gui/colorlcd/curveedit.cpp | 348 ++-- radio/src/gui/colorlcd/curveedit.h | 8 +- radio/src/gui/colorlcd/curves.cpp | 98 -- radio/src/gui/colorlcd/custom_failsafe.cpp | 129 +- radio/src/gui/colorlcd/draw_functions.cpp | 544 ------ radio/src/gui/colorlcd/draw_functions.h | 97 - radio/src/gui/colorlcd/file_browser.cpp | 4 +- radio/src/gui/colorlcd/file_browser.h | 15 +- radio/src/gui/colorlcd/file_carosell.cpp | 8 +- radio/src/gui/colorlcd/file_carosell.h | 6 +- radio/src/gui/colorlcd/file_preview.cpp | 56 +- radio/src/gui/colorlcd/file_preview.h | 13 +- radio/src/gui/colorlcd/fm_matrix.cpp | 5 +- radio/src/gui/colorlcd/fonts.cpp | 2 +- .../src/font.h => gui/colorlcd/fonts.h} | 21 +- radio/src/gui/colorlcd/fullscreen_dialog.cpp | 178 +- radio/src/gui/colorlcd/fullscreen_dialog.h | 15 +- radio/src/gui/colorlcd/getset_helpers.h | 9 +- radio/src/gui/colorlcd/gui.h | 58 - radio/src/gui/colorlcd/gvar_numberedit.cpp | 17 +- radio/src/gui/colorlcd/gvar_numberedit.h | 5 +- radio/src/gui/colorlcd/hw_bluetooth.cpp | 127 +- radio/src/gui/colorlcd/hw_bluetooth.h | 8 +- radio/src/gui/colorlcd/hw_extmodule.cpp | 34 +- radio/src/gui/colorlcd/hw_extmodule.h | 11 +- radio/src/gui/colorlcd/hw_inputs.cpp | 140 +- radio/src/gui/colorlcd/hw_inputs.h | 10 +- radio/src/gui/colorlcd/hw_intmodule.cpp | 91 +- radio/src/gui/colorlcd/hw_intmodule.h | 14 +- radio/src/gui/colorlcd/hw_serial.cpp | 27 +- radio/src/gui/colorlcd/hw_serial.h | 4 +- radio/src/gui/colorlcd/input_edit.cpp | 131 +- radio/src/gui/colorlcd/input_edit.h | 2 +- radio/src/gui/colorlcd/input_edit_adv.cpp | 22 +- radio/src/gui/colorlcd/input_mix_button.cpp | 16 +- radio/src/gui/colorlcd/input_mix_group.cpp | 92 +- radio/src/gui/colorlcd/input_source.cpp | 64 +- radio/src/gui/colorlcd/input_source.h | 4 +- radio/src/gui/colorlcd/layout.cpp | 62 +- radio/src/gui/colorlcd/layout.h | 63 +- radio/src/gui/colorlcd/layouts/layout1+2.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout1+3.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout1x1.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout1x2.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout1x3.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout1x4.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout2+1.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout2+3.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout2x1.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout2x2.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout2x3.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout2x4.cpp | 107 +- radio/src/gui/colorlcd/layouts/layout4+2.cpp | 4 +- radio/src/gui/colorlcd/layouts/layout4+2b.cpp | 4 +- .../colorlcd/layouts/layout_factory_impl.cpp | 90 +- .../colorlcd/layouts/layout_factory_impl.h | 8 +- radio/src/gui/colorlcd/layouts/sliders.cpp | 201 ++- radio/src/gui/colorlcd/layouts/sliders.h | 51 +- .../src/gui/colorlcd/layouts/topbar_impl.cpp | 9 +- radio/src/gui/colorlcd/layouts/topbar_impl.h | 5 +- radio/src/gui/colorlcd/layouts/trims.cpp | 233 ++- radio/src/gui/colorlcd/layouts/trims.h | 57 +- radio/src/gui/colorlcd/lcd.cpp | 116 +- radio/src/gui/colorlcd/lcd.h | 6 +- radio/src/gui/colorlcd/libopenui.h | 16 +- radio/src/gui/colorlcd/list_line_button.cpp | 33 +- radio/src/gui/colorlcd/list_line_button.h | 2 +- radio/src/gui/colorlcd/listbox.cpp | 117 +- radio/src/gui/colorlcd/listbox.h | 37 +- radio/src/gui/colorlcd/lz4_bitmaps.cpp | 50 - radio/src/gui/colorlcd/lz4_bitmaps.h | 49 - radio/src/gui/colorlcd/menu_model.cpp | 43 +- radio/src/gui/colorlcd/menu_model.h | 9 - radio/src/gui/colorlcd/menu_radio.cpp | 25 +- radio/src/gui/colorlcd/menu_radio.h | 5 - radio/src/gui/colorlcd/menu_screen.cpp | 33 +- radio/src/gui/colorlcd/menu_screen.h | 1 - radio/src/gui/colorlcd/menus.h | 71 +- radio/src/gui/colorlcd/message_dialog.cpp | 88 - radio/src/gui/colorlcd/message_dialog.h | 82 - radio/src/gui/colorlcd/mixer_edit.cpp | 71 +- radio/src/gui/colorlcd/mixer_edit.h | 4 +- radio/src/gui/colorlcd/mixer_edit_adv.cpp | 69 +- radio/src/gui/colorlcd/mixer_edit_adv.h | 4 +- radio/src/gui/colorlcd/model_curves.cpp | 239 +-- radio/src/gui/colorlcd/model_curves.h | 35 +- radio/src/gui/colorlcd/model_flightmodes.cpp | 641 ++++--- radio/src/gui/colorlcd/model_flightmodes.h | 20 +- radio/src/gui/colorlcd/model_gvars.cpp | 383 ++-- radio/src/gui/colorlcd/model_gvars.h | 9 +- radio/src/gui/colorlcd/model_heli.cpp | 31 +- radio/src/gui/colorlcd/model_heli.h | 14 +- radio/src/gui/colorlcd/model_inputs.cpp | 15 +- radio/src/gui/colorlcd/model_inputs.h | 6 +- .../gui/colorlcd/model_logical_switches.cpp | 169 +- .../src/gui/colorlcd/model_logical_switches.h | 18 +- .../src/gui/colorlcd/model_mixer_scripts.cpp | 323 ++-- radio/src/gui/colorlcd/model_mixer_scripts.h | 23 +- radio/src/gui/colorlcd/model_mixes.cpp | 44 +- radio/src/gui/colorlcd/model_mixes.h | 5 +- radio/src/gui/colorlcd/model_outputs.cpp | 186 +- radio/src/gui/colorlcd/model_outputs.h | 7 +- radio/src/gui/colorlcd/model_select.cpp | 181 +- radio/src/gui/colorlcd/model_select.h | 3 +- radio/src/gui/colorlcd/model_setup.cpp | 398 +++-- radio/src/gui/colorlcd/model_setup.h | 2 +- radio/src/gui/colorlcd/model_telemetry.cpp | 1565 +++++++++-------- radio/src/gui/colorlcd/model_telemetry.h | 37 +- radio/src/gui/colorlcd/model_templates.cpp | 38 +- radio/src/gui/colorlcd/model_templates.h | 5 +- radio/src/gui/colorlcd/model_usbjoystick.cpp | 179 +- radio/src/gui/colorlcd/model_usbjoystick.h | 2 +- radio/src/gui/colorlcd/module_setup.cpp | 286 ++- radio/src/gui/colorlcd/mpm_settings.cpp | 528 +++--- radio/src/gui/colorlcd/mpm_settings.h | 2 +- radio/src/gui/colorlcd/multi_rfprotos.cpp | 2 +- radio/src/gui/colorlcd/output_edit.cpp | 148 +- radio/src/gui/colorlcd/output_edit.h | 2 +- radio/src/gui/colorlcd/page.cpp | 68 +- radio/src/gui/colorlcd/page.h | 22 +- radio/src/gui/colorlcd/popups.cpp | 105 +- radio/src/gui/colorlcd/popups.h | 24 +- radio/src/gui/colorlcd/ppm_settings.cpp | 14 +- radio/src/gui/colorlcd/ppm_settings.h | 2 +- radio/src/gui/colorlcd/preflight_checks.cpp | 62 +- radio/src/gui/colorlcd/preflight_checks.h | 3 +- radio/src/gui/colorlcd/preview_window.cpp | 174 ++ radio/src/gui/colorlcd/preview_window.h | 280 +-- radio/src/gui/colorlcd/pxx1_settings.cpp | 6 +- radio/src/gui/colorlcd/pxx1_settings.h | 2 +- radio/src/gui/colorlcd/radio_calibration.cpp | 118 +- radio/src/gui/colorlcd/radio_calibration.h | 2 +- radio/src/gui/colorlcd/radio_diaganas.cpp | 694 ++++---- radio/src/gui/colorlcd/radio_diagkeys.cpp | 261 ++- .../colorlcd/radio_ghost_module_config.cpp | 141 +- .../gui/colorlcd/radio_ghost_module_config.h | 2 +- radio/src/gui/colorlcd/radio_hardware.cpp | 198 ++- radio/src/gui/colorlcd/radio_hardware.h | 7 +- radio/src/gui/colorlcd/radio_sdmanager.cpp | 56 +- radio/src/gui/colorlcd/radio_sdmanager.h | 2 +- radio/src/gui/colorlcd/radio_setup.cpp | 1279 +++++++------- radio/src/gui/colorlcd/radio_setup.h | 2 +- .../gui/colorlcd/radio_spectrum_analyser.cpp | 427 +++-- .../gui/colorlcd/radio_spectrum_analyser.h | 30 +- radio/src/gui/colorlcd/radio_theme.cpp | 709 ++++---- radio/src/gui/colorlcd/radio_theme.h | 60 +- radio/src/gui/colorlcd/radio_tools.cpp | 118 +- radio/src/gui/colorlcd/radio_tools.h | 6 +- radio/src/gui/colorlcd/radio_trainer.cpp | 22 +- radio/src/gui/colorlcd/radio_trainer.h | 6 +- radio/src/gui/colorlcd/radio_version.cpp | 238 +-- radio/src/gui/colorlcd/radio_version.h | 2 +- radio/src/gui/colorlcd/screen_setup.cpp | 296 ++-- radio/src/gui/colorlcd/screen_setup.h | 19 +- .../gui/colorlcd/screen_user_interface.cpp | 184 +- .../src/gui/colorlcd/screen_user_interface.h | 2 +- radio/src/gui/colorlcd/select_fab_button.cpp | 72 - radio/src/gui/colorlcd/select_fab_button.h | 45 - .../src/gui/colorlcd/select_fab_carousel.cpp | 119 +- radio/src/gui/colorlcd/select_fab_carousel.h | 10 +- radio/src/gui/colorlcd/sourcechoice.cpp | 60 +- radio/src/gui/colorlcd/sourcechoice.h | 14 +- radio/src/gui/colorlcd/special_functions.cpp | 1519 ++++++++-------- radio/src/gui/colorlcd/special_functions.h | 164 +- radio/src/gui/colorlcd/splash.cpp | 176 -- radio/src/gui/colorlcd/standalone_lua.cpp | 106 +- radio/src/gui/colorlcd/standalone_lua.h | 3 +- radio/src/gui/colorlcd/startup_shutdown.cpp | 293 +++ .../colorlcd/startup_shutdown.h} | 11 +- radio/src/gui/colorlcd/switch_warn_dialog.cpp | 35 +- radio/src/gui/colorlcd/switch_warn_dialog.h | 4 +- radio/src/gui/colorlcd/switchchoice.cpp | 74 +- radio/src/gui/colorlcd/switchchoice.h | 7 +- radio/src/gui/colorlcd/tabsgroup.cpp | 404 +++-- radio/src/gui/colorlcd/tabsgroup.h | 147 +- radio/src/gui/colorlcd/textedits.h | 48 - radio/src/gui/colorlcd/theme.cpp | 261 +-- radio/src/gui/colorlcd/theme.h | 76 +- radio/src/gui/colorlcd/theme_manager.cpp | 256 +-- radio/src/gui/colorlcd/theme_manager.h | 8 +- .../src/gui/colorlcd/themes/etx_lv_theme.cpp | 1240 +++---------- radio/src/gui/colorlcd/themes/etx_lv_theme.h | 134 ++ radio/src/gui/colorlcd/throttle_params.cpp | 25 +- radio/src/gui/colorlcd/timeedit.h | 5 +- radio/src/gui/colorlcd/timer_setup.cpp | 64 +- radio/src/gui/colorlcd/topbar.cpp | 39 +- radio/src/gui/colorlcd/topbar.h | 2 +- radio/src/gui/colorlcd/trainer_bluetooth.cpp | 29 +- radio/src/gui/colorlcd/trainer_bluetooth.h | 2 +- radio/src/gui/colorlcd/trainer_setup.cpp | 32 +- radio/src/gui/colorlcd/trims_setup.cpp | 37 +- radio/src/gui/colorlcd/view_about.cpp | 47 +- radio/src/gui/colorlcd/view_about.h | 2 +- radio/src/gui/colorlcd/view_channels.cpp | 170 +- radio/src/gui/colorlcd/view_channels.h | 15 - .../gui/colorlcd/view_logical_switches.cpp | 63 +- .../src/gui/colorlcd/view_logical_switches.h | 2 +- radio/src/gui/colorlcd/view_main.cpp | 63 +- radio/src/gui/colorlcd/view_main.h | 12 +- .../src/gui/colorlcd/view_main_decoration.cpp | 104 +- radio/src/gui/colorlcd/view_main_decoration.h | 1 - radio/src/gui/colorlcd/view_main_menu.cpp | 38 +- radio/src/gui/colorlcd/view_statistics.cpp | 212 ++- radio/src/gui/colorlcd/view_statistics.h | 9 +- radio/src/gui/colorlcd/view_text.cpp | 308 ++-- radio/src/gui/colorlcd/view_text.h | 2 +- radio/src/gui/colorlcd/widget.cpp | 161 +- radio/src/gui/colorlcd/widget.h | 239 ++- radio/src/gui/colorlcd/widget_settings.cpp | 69 +- radio/src/gui/colorlcd/widget_settings.h | 9 +- radio/src/gui/colorlcd/widgets/gauge.cpp | 128 +- radio/src/gui/colorlcd/widgets/modelbmp.cpp | 180 +- radio/src/gui/colorlcd/widgets/outputs.cpp | 251 ++- radio/src/gui/colorlcd/widgets/radio_info.cpp | 409 +++-- radio/src/gui/colorlcd/widgets/text.cpp | 101 +- radio/src/gui/colorlcd/widgets/timer.cpp | 341 ++-- radio/src/gui/colorlcd/widgets/value.cpp | 388 ++-- .../colorlcd/widgets/widgets_container_impl.h | 43 +- radio/src/gui/colorlcd/widgets_container.h | 10 +- radio/src/gui/colorlcd/widgets_setup.cpp | 71 +- radio/src/gui/colorlcd/widgets_setup.h | 14 +- radio/src/gui/colorlcd/zone.h | 7 +- radio/src/gui/common/stdlcd/calibration.cpp | 1 - radio/src/gui/common/stdlcd/popups.cpp | 1 + radio/src/gui/common/stdlcd/popups.h | 5 +- radio/src/gui/common/stdlcd/splash.cpp | 10 +- radio/src/gui/gui_common.cpp | 8 +- radio/src/gui/gui_common.h | 7 +- radio/src/lua/api_colorlcd.cpp | 14 +- radio/src/lua/api_general.cpp | 4 +- radio/src/lua/interface.cpp | 6 +- radio/src/lua/lua_api.h | 13 - radio/src/lua/lua_widget.cpp | 114 +- radio/src/lua/lua_widget.h | 11 +- radio/src/lua/widgets.cpp | 2 +- radio/src/lv_conf.h | 27 +- radio/src/main.cpp | 147 +- radio/src/model_init.cpp | 2 +- radio/src/opentx.cpp | 29 +- radio/src/opentx.h | 10 + radio/src/opentx_constants.h | 5 +- radio/src/opentx_types.h | 2 - radio/src/storage/storage_common.cpp | 7 +- radio/src/strhelpers.cpp | 283 +-- radio/src/strhelpers.h | 119 +- radio/src/switches.cpp | 1 + .../arm/stm32/bootloader/CMakeLists.txt | 1 + .../common/arm/stm32/bootloader/bin_files.h | 2 +- .../targets/horus/bootloader/boot_menu.cpp | 8 +- .../src/targets/nv14/bootloader/boot_menu.cpp | 8 +- radio/src/targets/nv14/libopenui_config.h | 29 - .../src/targets/pl18/bootloader/boot_menu.cpp | 8 +- radio/src/targets/simu/led_driver.cpp | 2 +- radio/src/tasks.cpp | 6 + .../tests/images/color/clipping_320x480.png | Bin 5166 -> 5156 bytes .../tests/images/color/clipping_480x272.png | Bin 4386 -> 4349 bytes .../tests/images/color/clipping_480x320.png | Bin 5121 -> 5084 bytes .../src/tests/images/color/lines_320x480.png | Bin 5767 -> 5642 bytes .../src/tests/images/color/lines_480x272.png | Bin 4980 -> 4899 bytes .../src/tests/images/color/lines_480x320.png | Bin 5734 -> 5653 bytes .../tests/images/color/mask_menu_radio.lbm | 2 + .../images/color/transparency_CN_480x272.png | Bin 9489 -> 9456 bytes .../images/color/transparency_EN_320x480.png | Bin 9859 -> 9843 bytes .../images/color/transparency_EN_480x272.png | Bin 9282 -> 9268 bytes .../images/color/transparency_EN_480x320.png | Bin 10019 -> 10002 bytes radio/src/tests/lcd_480x272.cpp | 61 +- .../thirdparty/libopenui/src/CMakeLists.txt | 2 + .../thirdparty/libopenui/src/bitmapbuffer.cpp | 1429 ++------------- .../thirdparty/libopenui/src/bitmapbuffer.h | 601 +++---- .../libopenui/src/bitmapbuffer_draw_extra.cpp | 776 ++++++++ .../libopenui/src/bitmapbuffer_fileio.cpp | 285 +++ radio/src/thirdparty/libopenui/src/button.cpp | 95 +- radio/src/thirdparty/libopenui/src/button.h | 69 +- .../libopenui/src/button_matrix.cpp | 37 +- radio/src/thirdparty/libopenui/src/choice.cpp | 109 +- radio/src/thirdparty/libopenui/src/choice.h | 44 +- radio/src/thirdparty/libopenui/src/dialog.cpp | 159 +- radio/src/thirdparty/libopenui/src/dialog.h | 113 +- .../thirdparty/libopenui/src/filechoice.cpp | 6 - .../src/thirdparty/libopenui/src/flexlayout.h | 43 +- radio/src/thirdparty/libopenui/src/form.cpp | 105 +- radio/src/thirdparty/libopenui/src/form.h | 74 +- .../libopenui/src/keyboard_base.cpp | 51 +- .../thirdparty/libopenui/src/keyboard_base.h | 2 +- .../libopenui/src/keyboard_number.cpp | 215 +-- .../libopenui/src/keyboard_number.h | 22 +- .../libopenui/src/keyboard_text.cpp | 213 +-- .../thirdparty/libopenui/src/keyboard_text.h | 20 +- radio/src/thirdparty/libopenui/src/layer.cpp | 2 +- .../libopenui/src/libopenui_defines.h | 60 +- .../thirdparty/libopenui/src/mainwindow.cpp | 52 +- .../src/thirdparty/libopenui/src/mainwindow.h | 22 +- radio/src/thirdparty/libopenui/src/menu.cpp | 571 +++--- radio/src/thirdparty/libopenui/src/menu.h | 160 +- .../thirdparty/libopenui/src/menutoolbar.cpp | 66 +- .../thirdparty/libopenui/src/menutoolbar.h | 2 +- .../thirdparty/libopenui/src/modal_window.cpp | 64 +- .../thirdparty/libopenui/src/modal_window.h | 18 - .../thirdparty/libopenui/src/numberedit.cpp | 96 +- .../src/thirdparty/libopenui/src/numberedit.h | 44 +- .../src/thirdparty/libopenui/src/progress.cpp | 35 +- radio/src/thirdparty/libopenui/src/progress.h | 20 +- radio/src/thirdparty/libopenui/src/slider.cpp | 105 +- radio/src/thirdparty/libopenui/src/slider.h | 12 +- radio/src/thirdparty/libopenui/src/static.cpp | 188 +- radio/src/thirdparty/libopenui/src/static.h | 132 +- radio/src/thirdparty/libopenui/src/table.cpp | 279 +-- radio/src/thirdparty/libopenui/src/table.h | 23 +- .../src/thirdparty/libopenui/src/textedit.cpp | 40 +- radio/src/thirdparty/libopenui/src/textedit.h | 31 +- .../thirdparty/libopenui/src/toggleswitch.cpp | 63 +- .../thirdparty/libopenui/src/toggleswitch.h | 7 +- .../libopenui/src/widgets/etx_obj_create.h | 50 - radio/src/thirdparty/libopenui/src/window.cpp | 428 ++--- radio/src/thirdparty/libopenui/src/window.h | 71 +- .../src/thirdparty/libopenui/thirdparty/lvgl | 2 +- radio/src/thirdparty/libopenui/thirdparty/stb | 2 +- 381 files changed, 17708 insertions(+), 18326 deletions(-) delete mode 100644 radio/src/bitmaps/480x272/bootloader/icon_error.png delete mode 100644 radio/src/bitmaps/480x272/bootloader/icon_exit.png delete mode 100644 radio/src/bitmaps/480x272/bootloader/icon_file.png delete mode 100644 radio/src/bitmaps/480x272/bootloader/icon_flash.png delete mode 100644 radio/src/bitmaps/480x272/bootloader/icon_ok.png delete mode 100644 radio/src/bitmaps/480x272/bootloader/icon_sd.png delete mode 100644 radio/src/bitmaps/480x272/button/alpha_button_off.png delete mode 100644 radio/src/bitmaps/480x272/mask_coord_shadow.png delete mode 100644 radio/src/bitmaps/480x272/mask_cvpoint.png delete mode 100644 radio/src/bitmaps/480x272/mask_cvpoint_center.png delete mode 100644 radio/src/bitmaps/480x272/mask_point.png create mode 100644 radio/src/bitmaps/480x272/mask_round_title_left.png create mode 100644 radio/src/bitmaps/480x272/mask_round_title_right.png delete mode 100644 radio/src/bitmaps/480x272/mask_rscale.png delete mode 100644 radio/src/bitmaps/480x272/mask_shutdown_circle.png create mode 100644 radio/src/bitmaps/480x272/mask_shutdown_circle0.png create mode 100644 radio/src/bitmaps/480x272/mask_shutdown_circle1.png create mode 100644 radio/src/bitmaps/480x272/mask_shutdown_circle2.png create mode 100644 radio/src/bitmaps/480x272/mask_shutdown_circle3.png delete mode 100644 radio/src/bitmaps/480x272/mask_trim_shadow.png delete mode 100644 radio/src/gui/colorlcd/confirm_dialog.cpp delete mode 100644 radio/src/gui/colorlcd/confirm_dialog.h delete mode 100644 radio/src/gui/colorlcd/curves.cpp delete mode 100644 radio/src/gui/colorlcd/draw_functions.cpp delete mode 100644 radio/src/gui/colorlcd/draw_functions.h rename radio/src/{thirdparty/libopenui/src/font.h => gui/colorlcd/fonts.h} (66%) delete mode 100644 radio/src/gui/colorlcd/gui.h delete mode 100644 radio/src/gui/colorlcd/lz4_bitmaps.cpp delete mode 100644 radio/src/gui/colorlcd/lz4_bitmaps.h delete mode 100644 radio/src/gui/colorlcd/message_dialog.cpp delete mode 100644 radio/src/gui/colorlcd/message_dialog.h delete mode 100644 radio/src/gui/colorlcd/select_fab_button.cpp delete mode 100644 radio/src/gui/colorlcd/select_fab_button.h delete mode 100644 radio/src/gui/colorlcd/splash.cpp create mode 100644 radio/src/gui/colorlcd/startup_shutdown.cpp rename radio/src/{targets/horus/libopenui_config.h => gui/colorlcd/startup_shutdown.h} (72%) delete mode 100644 radio/src/gui/colorlcd/textedits.h delete mode 100644 radio/src/targets/nv14/libopenui_config.h create mode 100644 radio/src/tests/images/color/mask_menu_radio.lbm create mode 100644 radio/src/thirdparty/libopenui/src/bitmapbuffer_draw_extra.cpp create mode 100644 radio/src/thirdparty/libopenui/src/bitmapbuffer_fileio.cpp delete mode 100644 radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h diff --git a/radio/src/bitmaps/480x272/CMakeLists.txt b/radio/src/bitmaps/480x272/CMakeLists.txt index 6c0f81f6b0a..4fa9b49d832 100644 --- a/radio/src/bitmaps/480x272/CMakeLists.txt +++ b/radio/src/bitmaps/480x272/CMakeLists.txt @@ -19,7 +19,6 @@ set(BITMAP_LZ4_ARGS ${BITMAP_ARGS} --lz4) set(MASK_LZ4_ARGS ${MASK_ARGS} --lz4) add_bitmaps_target(${BITMAP_TARGET_PREFIX}_splash_logo "${RADIO_SRC_DIR}/bitmaps/480x272/splash_logo.png" "4/4/4/4" "${BITMAP_LZ4_ARGS}") -add_bitmaps_target(${BITMAP_TARGET_PREFIX}_button_bitmaps "${RADIO_SRC_DIR}/bitmaps/480x272/button/alpha_*.png" "4/4/4/4" "${BITMAP_LZ4_ARGS}") add_bitmaps_target(${BITMAP_TARGET_PREFIX}_masks "${RADIO_SRC_DIR}/bitmaps/480x272/mask_*.png" 8bits "${MASK_LZ4_ARGS}") add_bitmaps_target(${BITMAP_TARGET_PREFIX}_slider_masks "${RADIO_SRC_DIR}/bitmaps/480x272/slider/*.png" 8bits "${MASK_LZ4_ARGS}") add_bitmaps_target(${BITMAP_TARGET_PREFIX}_volume_masks ${RADIO_SRC_DIR}/bitmaps/480x272/volume/*.png 8bits "${MASK_LZ4_ARGS}") @@ -27,18 +26,15 @@ add_bitmaps_target(${BITMAP_TARGET_PREFIX}_themes_masks "${RADIO_SRC_DIR}/bitmap add_bitmaps_target(${BITMAP_TARGET_PREFIX}_themes_alpha "${RADIO_SRC_DIR}/bitmaps/480x272/default_theme/alpha_*.png" "4/4/4/4" "${BITMAP_LZ4_ARGS}") add_bitmaps_target(${BITMAP_TARGET_PREFIX}_bootloader_bitmaps "${RADIO_SRC_DIR}/bitmaps/480x272/bootloader/bmp_*.png" "4/4/4/4" "${BITMAP_LZ4_ARGS}") -add_bitmaps_target(${BITMAP_TARGET_PREFIX}_bootloader_icons "${RADIO_SRC_DIR}/bitmaps/480x272/bootloader/icon_*.png" 8bits "${MASK_LZ4_ARGS}") add_custom_target(${BITMAP_TARGET_PREFIX}_bitmaps) add_dependencies(${BITMAP_TARGET_PREFIX}_bitmaps ${BITMAP_TARGET_PREFIX}_splash_logo - ${BITMAP_TARGET_PREFIX}_button_bitmaps ${BITMAP_TARGET_PREFIX}_masks ${BITMAP_TARGET_PREFIX}_slider_masks ${BITMAP_TARGET_PREFIX}_themes_masks ${BITMAP_TARGET_PREFIX}_themes_alpha ${BITMAP_TARGET_PREFIX}_volume_masks ${BITMAP_TARGET_PREFIX}_bootloader_bitmaps - ${BITMAP_TARGET_PREFIX}_bootloader_icons ) diff --git a/radio/src/bitmaps/480x272/bootloader/icon_error.png b/radio/src/bitmaps/480x272/bootloader/icon_error.png deleted file mode 100644 index 52148e6bee4b2f4d4e3a55d683a770519a15770a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1100 zcmV-S1he~zP)uQ<)0Tn1X{WFBjn z+0-M~=nsFPmy=xJ68}EdCw^7zdF ztL)|z&Tx%f2A0H1fxFnqOSJ(obq(6%Z3YGwC%FR)w!79-X@DuF@=$lDOk6_ZcQk3wFCV z%GpsLsEZ72ce6%7J?lz$+yI{Uk(6nhuOv*5`%n!su)}Q$n~Sb9wCe_Nz>bW0x4p5k zo^)C2YzDTw%}Q)B>}Ep)L%+5nqrRIt%7I0@+?_z4a%F5Yj=LPMR@`Y@w7T9=IqRyL z+6XM#={s@Abs$2HqMcr*V;oaeo z98JB-BHu_jpLdlzQn>wgr+hV5$n$QDK7O~A8v^^I zt#$tJUI$~hQCG(z9N6ZTlp1a^G<5%jVqf;j46NWC9!enf zXt^eS3q7gokSh#pG_%#U5$=#>JM7C&4*N3O4h)@bpQA3XJ52<(x>`MG+14lonaN=* zAE(Mm@=RkoXQhXyx44<8^6AAndJytFByRai{9=M_tiSv zV8-6Vr<~)TXu3{UcR(9mJj3g8B5rDEhZB5AKYwwJ>(OkTC!owio?~6ZH2nu0Y0Nrg Soy^Jr0000P000>X1ONa4Zs1Mm00002VoOIv0RM-N z%)bBt010qNS#tmY79{`x79{~mQY7#I00JdRL_t(I%axQ%NR>ethM!|c@swSJQba24 zj+GJ-U5FN8s6jz3!WKnTL_~{-%vHDxq65&%d>Ea86NQ_*H*vEb{ z!i!WjsrGuv0ugg8vCKRX=UHjoph$H(+$Q1y+kEdwKiOx8XN-v}Y)D65x?L>xp>Z!e zHaR_PrxjwcO<`ov6XF`5`Pvfkrpdsr@2wWg?G7UM%yG8&eQT*$IU)R6!Ohu zM!n@L*NZ#-Zn|!WTkT3A?N)i)H*OMl_`wl}0%b(iPPd4SszxEkX_j!1II}3Donv^ufY0W|}lnbv4kQD2DFomvJ-|Y;$M4c^D4#0G~$2aN=O7)j7g6LES;kk2}**hrKaAwNXYKP4ygADO63 bhfJs6o_vAFXquo*00000NkvXXu0mjf+SD7d diff --git a/radio/src/bitmaps/480x272/bootloader/icon_file.png b/radio/src/bitmaps/480x272/bootloader/icon_file.png deleted file mode 100644 index 515ed0e39d4c05958672b6b2cbe64a40ad9c7383..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^fAl$b4ndSdd}o+-9Pw!Yw;NsX^iAoWvPP#VP_i)22*m znbFZP!OT#56Vt+wTAl25r5@7_b!ldY1ifVu{0{bEu{QH+@SFGOy|&mh1QRp zv+Sz$7+1kL40go#VzS2apKJ4i~9deH)6T@y06VxbP9v(ou$Wx&pc3D Uqt%|v5A*|rr>mdKI;Vst07@}o9smFU diff --git a/radio/src/bitmaps/480x272/bootloader/icon_flash.png b/radio/src/bitmaps/480x272/bootloader/icon_flash.png deleted file mode 100644 index a91436250e8dd1be66ad2cc849f8495aee688937..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 696 zcmV;p0!RIcP)P000>X1ONa4Zs1Mm00002VoOIv0RM-N z%)bBt010qNS#tmY79{`x79{~mQY7#I00LY|L_t(I%axQ{XwGpM$3O2jvzOtW)4U98 zj>EPbk_&O8lnV(-mczv^X+?1%IfUHJy;2TWk`zLbV~wGG}PhQ$+bs<^0RpMF%~MB1S>rNswUjzmZ;^^MW_Dk|0W)QkJroY#Jbg zU`UPbcaDe!7CA}8P3m(G_$?C^%5s|%Jfo1ktYjK_r1{P}R`HXw#F;u2ILO|0uDIQY zc8Buzn)bBC-VgZ#YsU}~-QvzHz3 zcprp1f5;1gRqH$pygk&HPMb};ORTYH*tn!rZMRCS3U^=ii6w5c!@t$$L9sM5Mj7OY z%Y1FhI+LOBe(zZ+#=SanU*6L~HH$gH70Ou7Y{rtJnR*`4L>VX9IC5XEd&abS&V?ez zj0am;=s_EXJv5@wPCX?Q11Uc8nwNZ_izu^MK{@jnH|#z{6q2Ngg`C~|qK|B%Od#^t e{fYel9s2`B(l#+)^lVfB0000!Gp)w5YQNd|p$cDu$N z8Uy1-NoRPTk=#ssAlycVLP(8tTI_t66%q`dP;ABBqBG>wt>>+J*c8UXxC^N~H(OU4 z77Y67Fyn5Ac~ckg{U5G_Z(+d_XyhQH{t{3d7HmDuL<57w`>g8?qZ}2`Mzrof{ji~i z!9^Vv`n--R-v=g{RMeI;JWB}xSWS~rQ|@yfr_Z_(gmkSlc|i#agQ6nXOQ!+reak%Jd>qqNT=)#QzCT!vaUUuMFVFg%{+RfGN9wqB&8WH&}CW|ah+IFcua<*SHUA`ebir|Mp(xmX)B&C zBP2ebx)dK?rb^097a#rBC9z6T9_5gd|MIxUMJ3U9%JoiD{_utq0rRelGfYboCzs5) zY@1f$ffN!(L(Y=Rw@>X^WQ`t&4IYH0|5lFNi5+iih4 zrCM$<3OQ!+pc;~WmS;VZGPc_HC|5ZgG$c8eLhGQ6LRloFQ7M*)IO*pWHNq>rqCkn2Y*QWPybq*}@}jSbwjX~}Hc#VTqgm%I64$~27?oa4xRx=(243ImKw zwK@_v9*QOB&k^U3Z9A_S!@*)aWazIJq2lH{{sMQc_X=qRH97zQ002ovPDHLkV1hJ? BZTbKJ diff --git a/radio/src/bitmaps/480x272/bootloader/icon_sd.png b/radio/src/bitmaps/480x272/bootloader/icon_sd.png deleted file mode 100644 index 360ce328f2600aa352b520350407f55013df4bc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 514 zcmV+d0{#7oP)N8_cduHm^;Ziu!$5Y@(_BSIwm7z>?T73!|8_FL6y zoO`qtd`KKZ&5HUfXxnR+I>B1ea%Y5As9MvB2BGzE?S;qojFc0dL$^WbCXm#!Xe3*7 zzn^OxjUN-y@*y|31(rwtEq)(P7}{&HuO2v{2xFUG`92UWsBC%S&0t#;wM{Et&)}z+ zY*>?LF=EizpUG5lmNWBD*#G}P^X%yGsb*OegOL*hGY6$o5uCPUT{(63WX=^MMRd+> zrQNAB&%5NNk&tut%|~CRF87!-78LD`*k7O1b=n@7U!%^J6Dv%H9RL6T07*qoM6N<$ Eg6d@D-T(jq diff --git a/radio/src/bitmaps/480x272/button/alpha_button_off.png b/radio/src/bitmaps/480x272/button/alpha_button_off.png deleted file mode 100644 index 0d82fb58e452e62d72b11fc44ab38b62e0b2ed38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5512 zcmX9=1z1!~7rwNBG)M|7(nyDNcY{bQA>G}zuypg$CEcJa4GU5VNJ*EJbeBjk^{>x= z?=y3rd*+^*Idjf==Z)3UP{hNb!T|sPPgzM$2Px(LwP%>fUWg>E0V&XJrPZYYp#DGH zdvgo`z!9~VmDSR+bMDa*=&+&o-u?47IuKq)pq(^vQ1!i(tf&bOUfsf2Oq z6OMK|s7iR9N-3OdJlKRPJ;?yQpq#FooOVjZGhUW8XsK*UJ$+mxigx`WI;Gr7 zgv9mp7+W=mvRnAo$GBC-=ncbo_0l~5zA*~A%CRO8KIe@Pqa5)Z+pzw#wamPkC`{ay zkYYwjzWeN^jkk-*GTci!O6rH}Ry}2qh9JO_y3D!b`OeCT!!nhHH;iM`A6Qcw`tWCp z%i!lY$p}IJ*iSGgF+*hxC6n>HsKhjq`1SE|_1*aXpWOIw6JKxe{K}y;q*?a>Y{u^m zN&THE8|X!U2?+~vJ99X9vCM>++<#2H_Q^Dj2sxpYqr2(7(httT1L`WQn->t#&h})0 z$svl?*N5m)GcF*mq01W|;!fKhWUAA*@y3?@)AF*hDoUXvE7#sBq7Xks_CwIPPS?um zwz=PVnoz12kF4oi7n^_zxxT@%4Y%9pJB86VbXbqxv@eM68M0zATCVX6VR43zn4vGD=y2l~ zKw1Cb{FEY$h#Vv&(~0&1$qv#qL>eShZ=qqx5^2$-KVy`YQ9>n?IxNzuqN#~GD7M)% z+GFveY6tLSTZ^>qh!JD~Sg*OUE53p2h@3DQ%`}CcB}I^b8~Vd5M8_G{+LPgi7DRXw zq1l_YMr42^8CppMB_t9liRUJI@m)bC#g74-=+&oW;xbfwsl{a4GP<@nrIgA+BT`Ix zc^)mbblhP&vdE2+%woM_!O|LSEUo-1iJA8^EDkuAMCuBTC8LvLdw|y)5z72{P6hp< zj}tHV8uy4Ugb-wy;l-8-JV_KGYBWq_ji`;3jnvag!jY6e63i>=4L*y^(HzF%^?TG= zIPtXL1QG@k2V#gOLBd~ec)7I*eJ~c&h+*%0zXo<=cGGtwfm3!6|0X<5Am~5;Gje8q zqYy+8{7f>b@D&S50``{(B^fqzj^fk_1tC?qs-H9i@nwugpIZqO9%Y~`CMTvz!`Q{B ztz^R>$QsJ<%K6nXb3XkFeJ3bwNWqH0L(EX^w~Px@;j2~VZtWsA12%M)Kcsr>Gb~z`hm>MrecIr1-BK^z{ivxX-uDX%!n(q;{*4~- ze=)WdN#FFxY{;%_$Fbb8*s@saM$~9pziXTEo>4e3JP^W@<*UG$(6KLXaEWrGDUs4k-H%_6i}PzbW$z-c%JAP0s4EsV%I=npSw`XXrlpKkSzYi{ zcnNqvcr&(NwuiU#1^fum4u}jm4!FL+M!b1oczB8EM7+Zk!F+{@feFKG#XF07(@WZG z67>*Oo0yPjkswInO)1W+$A`~7_SQw9%TY$q{jH(Rl$pmUspT-QI^T+Oz`}FE#d8qG2BLgR%@JZ3z#8u4^mPOp=75_pOuoCBBR>zhJDN`rnQ=f;Cp zgq^c%zRQXoWFX3d#O|HlwB`9HSPsX0%a5x?!^2C%2a89|rzU%NChOi(fnMWP7D@#p>F(H2$?Oa3XqxWc%H*=c@kr+lAIy-{JA!u92&(Ax$C4Pl8X> zC}5Oj=nk}6YM>`06e3+#gdsgEO%OI3CjU+Rm79{;;8pV1bG%*LUEj#C3FyRe@%8tF z-poh{T@p3{ZY_2Qg*k~f;bb?o-E1f<6Qh>ClYWH$R4zwOxg?;JtdykWW9f$hzk&1t zB}mE?#w%WZCA-z18K))DlZ^8WFhZ{`g0x^8ZW`x)~X z6^SQfd15(YPlb!~Fvl*Ypykb~m2jsM&J&UXELSYo)YDu6|mM6P8$== z6ursZlKRWwL!)@IIQjm!f^es*rIr@+5 z!IZ`eCe~Wb%?A)~l}n{Wef2aru8b{>w~XdYRyhZ1G*7on59v1 zkZg$X9j&0k+pCaKM0=ZZX?4?nZ}58XerOCDWHf1Xlp~kJ8s_$?%=@p|_irPsej(E< zKb$_fR<>r*qDC`B(}sM!Ilk5^)m&Oea$x*hcs65-@i^&_R)Wf} zsdb>dax-w`^qOv3T+h>Z+iwB;du$0wp~g;Oob!*-qF(!BZdP#AB3Bt@JX?o*# zuRNEQQ`s-c{$zajb8Er3+wY#2n@m*T(fHziy7uFTs_tJ;QzzD^UcW9L^eJm?OtU() zLp;|w4xOLAX8V%xwVl?VvP)(M@7+>doSjrAXch*eT}PbXt?AZqA!#MZQb|W000Ni* z02%=R2&4+S2LRsO0B~Ri03z7{K<<{;t}TWfz_d_Rlmnjry+xgsX-EyWo06d?0N|4R zYbZc&9tBc~<)y4HkF|k`jYCT!#|NLF-}l?p|nLLc4#iBo0$iL zo0(MKExB+|`3x(ck;tKi`hkeua(7CjLNV8PCz!^H-gWOze+G!qrJ1DtF#cpa5#Zu_ z1|K)icUW3jh}}OttYmVU9Bd#TGgntGw1~+`?ah_1zNgn07t7ABu5?u}*fBc`%ih%C z<@Hb65L^}v&iE3$1_zLi90NdIzAokG2R|Rn7u9ECWW>0+xp|X2W^{aX)bS1s4mghI z>Vhv$OmJiG;=2*Egrvs!J4m5R8=yL+MLnYybaGp5wAIv=k@=2;P5S!vYfE)?^%XKQ zvK2f$ya&mLi|Nj*tE&`I-xCUy7aU-Q>+5UZpp&-UJmjzBpJp9ulamR#6crUk?T_NO zx3}jT8yXHY3nd^%h(p1(I+nOjJv2GO2#Pf>sH~I}bW{HWgsj!)crhakWX79AYuw>? zhG<<4Uh-M%3H_*0dKUYm$e5G7#dWpo{&M~UfpMeFC{B)Aix#Q;SfOOd<%;hrtOIHO z%#H4*k|nO$6GtxK+$aPLBV2G=X6_ zMPI(0*nq*{oCUwuDtQG3k<-=g5OpuF3qGK~zkigKm3134+?=Kg6+f;-=y3+Bl#+r| zwX(9Zy*rj~L`Oul?uc|V=<#-!j4tSp^z^iW-1gR1M90(Pox?xBDyO|a8?~PNJYH%| zl)`Y^o2R#KfjXg>x_f%2y?_7SK0GWe6CWQx$!VztcF`A0(kUjt)Zu@g+8a&4%$lJx zFgG_>F#AcL9Pjz_Y$&ld>3`!Qgwli-q1|kxaTv%b=GN75pBlBgtgOJ@Ew!z!w zv~F%}7;6@YRbO6QcugK&<~uYa()oiPU&UFBrUCvXoe3BA5ZtxB$x>`{bMxO14-dUm zi8fZbWI&$7Z%Yh_DrL5nn2&dc8e16vs456dnouX2oW^2@#rv1R+ z#hl#ST;XsYdjSCfS$lhXTcjGUP^t~NKN~=ShNH{Z2@#qJ)bR=l8KmUo+@eakxSVW< zg@u`Z?!&>s3Gnpvb`CF}>H_LHf5PCAfCgOCb3fa@J3d<}G5P zXk}$pFW|CHO-02|L`2jj`FLZwq{`LlMN0wj%4ze19qm7TTXgZTLPz=Y^HxVRtL+1M~)WJ>b#{btA$ zX#_p9vawN69StcMHs;NEhK(wQEQWl27(N|9x;%yI1BF$&4$Otu9|N=wDd zXU*OU+8}doMTc$L!~rZp0#XI;@9)zA{V&FpbpjwHE}#L((5rYBR^VC@L9?>5*r6Jg z)J*~)Bvgb0BbgkY8M(_gsC|?@v$L}(MKG9i-yGD-%PRp@NLYA5Sv`pl#e!fB8BDB+ zr6o}tM=1mX@dG$IK0f{lX;6~b`p>Kz%ZhaE@!`%AP|bW(-zb13E+%#aC@3l>?ntPU z4~j#Ji;M4o(9qDN7RzK0y34Q*m&MI4=wh^QF3p_G&q73hcHTkFB) z%6-&*47mH|50I3dUDZbz3N|*jJDMF5RQa#%+ofDkXJ%(tP-7AkFB=3vX%H7Drw-?n zX|GUYjKT5o(^UFCRn9Ej7F1bek6hdoVAjanmu2WT4zicK0 zRaaMc;Y5D_Qdw!MB|-^jzU6lY(HEf!c^~Mq_k48iqO@X{V!8|1`I+OWlcw?4UIDie z2inomA*fB-9}y8j#+ETWv}j(X%T|f}vX$2+MHa!6<;jRzXcKDd!QtVlp1%HS@{kp7 zV`F14?4^>Aj}Kgp$wY5pe9OxRn!-j1LqC81ETT=Stf8S-J?rqvB&}-J z!P>*4L4{QQ>SV=;S)edK?!uuaFeko8N?TidH4>M6am(ZOJ90DVju@%P=z_9F$W7sH z#V|M={$Ff(O?>9B5jBNaqCqSrP0d&j=X1!0BbuTD}hK35h`W)-1_I~}090tKeYbp>4 z%u~@yQ(@gG`111dj{H=KHQn7ILaeO&TgL1FvOte=~egJb1re}8{!ad9y%JKKQ1 zI$A|e`*Vv|*k0>rpo)fqg1diUfc(&_9lu;>{|0$CIS&sF`8$v}YiMW;o^1}iMIy9f zzQ#Ne9o>gF`y*`S5)$>Jx|wY+4a&7xUeJj89Qh|IkUZD=@F9dxT>N3mY3MVO0T_4R z{~g&aEh))FBPAzqMfzl%N?%GP#BE}@)8tt*MR$TVM)5q#9j0e=HK|CKpMTGgm61`t zwYxiDC_Kum0zLr~Di z5LtVzGR1yM_fPwkg>zY%nc&)+)uYFuzsc%K%vLtruRiEvyTMYVw6rH3)*~-Yv$H8QB_$=x4N+2Pn38aqaARDS;XDRLMuCSnXPYL8 ziHSS8w-QC@Ml2viVhncbnjCi{G2crPMjMzX*uqBIs3)RhW0GEunJI~!j@v!P3c$=^ zkvRgspgi?c#SuQm2!^zX5?Ij={+|Wfj6Y)W-;il(;q?EaROCBgz{Bj2FS{yg&UBHd|2M3EAsi*OG^3>8 zw2E|Vgw@gZ-PTOcTrRXUZ@qS*x}SY^@u4#os);RvZW4(te?`mgwy#R+Y211(S@C&K o(5dPTQQ9snN}qmi5AwS4Z<~nT(aZJaKR diff --git a/radio/src/bitmaps/480x272/mask_cvpoint.png b/radio/src/bitmaps/480x272/mask_cvpoint.png deleted file mode 100644 index 48f9609dbfbfe9f380deac1d22af97d9c12d1f06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VY)RhkE)4%caKYZ?lR?r29+AaB z9oIpa(Me-=1xT>0z%d;}gYjee@D3oO)YHW=MB;MqgpIsM40xD3mk2GeG-+VFAR?tP z_1K5Jbum>8qJLhkKF@CXz>0~5bJClxcfm<_lJB4~-9<+CK9kr}5#5Gy4~wIkLL6;`3#8ll8d)iXTP3 z03D!O;u=wsT$GwvlB$~mBp8eg3{7lpinR(g8$%zH2dih1^v)|cB0TnTLy85}S Ib4q9e09JQ+wEzGB diff --git a/radio/src/bitmaps/480x272/mask_cvpoint_center.png b/radio/src/bitmaps/480x272/mask_cvpoint_center.png deleted file mode 100644 index e3dac7b206d634495d874713e6243c2ed6c4fdfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VEX7WqAsj$Z!;#Vfk}U9uEC#B- z4#JF18nY{af|4b!5hcO-X(i=}MX3zs<>h*rdD+Fui3O>8`9jQu#-bvMW2V7ki-8iQ8?fiDvD`Wyj}vQSk8683 z**zg{9C|4?`W-lMMS=sLfD=-`M6W&a>?9_wwq>;@6Eg)cXz(JcIDO; zP1CLow+DOhz6j5!mp_32J6l(Oh1ZA0_IDNR|J^(n9^HL0*R)GNrKA0NKm3{rmGyY6 zBH5c~1)w$U!NYmM#euB#NRHDyFkb!khoPr&V0`O_W>{>>NxFSf%Eu==BXM#dXly+E zLVqx4U?7t<*XP+Zuh={=TDuJ7W*HlL3#ktRW214X?}xkkrYfaQdlnL=Y3V*ljz{{G z`o4c(CnmA6>0#m`Vl&rgmZL9!26!yvgzXK!T>68rz?jr^!7!f9X1$r+Q{@<2lu~RG zOb7x5s*dxT&rx38URfB(N|b3)rz+PQi#$??bznfW3mRF`na!(Zsvv22&I@ey%!XDA zj75hl4$EolJQi3^WhV2w0<6_xi;1dLHBs*{-EF_&0MZ+VosUyv$+FHxRc{>ujb%bk zMOUNaLgGDHsl!spts@BYcEhG%o2BHnDo099SH;?0g{%{|NA$ZP7ir#*_5c+y3Y04a7OK^@O>iP>N2e^aJ# zzWDUqcA8VyGzHsED=63T@=QFIPnXg()!RN`Tr~Y17@{exjE&`TdP)Y)#$aJ~Hj!ZT zJ>_1&DwWhTUdoLzWa|tKh2Ir^#gE<}yywP}x|ATBCNXlP?V!HLedPF-?bA4s&cFIy z@aqj|Gvclq@O;59Q!6GsA4|A2v2lJnXY0ndYOzjd{XG4jbZ~Q1F8U0=-Gc4j+N}!3 zY?t7wZp3a*z(+S}WDc1sVUGO%YQGON=#$}KV|3%Dc>VFEkFJ0J`YWwnjOa@+CDB(XO37~8wa z?hzy;en3y{g+G7}F**S<-{N7YgEF%vrN zaj9d~Tc$an4ddSZWzNNks?1nTlPt9U{NYE-Ok`+%N+Ku9choG|yC~Gdi~X^nXJ*aFV|`kM7N}jNk>(w3R<@;rqS;HH+iuUP z(`tZHbh!Mqm^Z}0HQ)TDb)H1t5vK>9w1q23lUZWz4*eEM2o(VM?h8ASqOA^Tlk(>k+qk(cT@`dnF z?8h$h`++3f!NjL@y?&_0Y2Dj;{mSZ63*dMf)e&+KPkaxNiAzxs_yTxc2l?DpB#2!Z zV7zAgq)6avHkxPoy}yFIi--DV}N_H}YeJ+2hFUB8$qAbmmeSJ6v7sTRCY+f%6B73^g{ zPkzbIUM#*(q@o0x>CuTqzVduD=<@*if$IfSPL%(2eJ6g?jvm8g?cA3W-~X*~Yz`d?rDV%@BdtkLfN@Y@H+U;G1z C3om{E literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/mask_rscale.png b/radio/src/bitmaps/480x272/mask_rscale.png deleted file mode 100644 index 967766871c16328b9ce69532a76a67812265bf7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2604 zcmV+{3e)w8P)0RSxl%w{tM1qIps9cb|UEx_pLC_Q`jjGjM#PAZj( z)M_>T`0;}P(Ad}*5fQCixsv#NKCNE8npUq~O>5V#rS03d)6ShcDJCYypY({}2fTj$ z8u|J8NJvNk5!r1LiNtCzkw_fcZQQsK1qB6o@#2L)sKRFg7z_qnzI+*}si_W=S=e|y zp4FGf<8ksyPEN+<%a>s=7<@(BdjU))6KZQ~A(zWJC9$wE3jDg3)MP zS^?VH+OTQUCbtuqZ(6MuJ3A0{{S{(TL5PH+y{b`uqFQ-{0@Ce@aSw zxy}DyC=}xM?c2T;ptiQwE`gUXUjhKmojd1{s8lLNUS1w5D=X37-VU`|ZTB1&iv=o` z3QbK-C@n3;zJ2=;9v<#6Zdq9w0N~A=HxP@(tYbVL5B2r+z7e3cwH16m-!6&R*jQ*Z z8kkHboAFH^7cXtB- zPMtc%iCcVpJTw}O!ux(jAd7VCr_Sm z4jvH^fwynp`Yl;U=;`T!OeW*Zv%S6DZX6o{W@cuvVZ#PaL07C;f!D8J`#o7l=<4c1 zXlN)Wu1cj6)6>&7F>C}VFE8g5P%4$8tE(#@i8@0^M+bs~gE?_7E-tq5X9+MnJByf@ z7?**>Vlg^9I|G)aD?E7c03wlyQ(wg}49k}#!1e3bIVpMU*s*{n$OR`(oZ!U$>eZ_( zKdS&1iv>wZNiG9~g@s{kY%Jgjx`I}#<zSE97J7Ro%J^Xz}K%|t%|K%w+=^-9>x9p_c1j!Wi|Zx@grtt zW&)Ik=P(+LtndHH$w@RfH{-~WBdmeb{HT-wps}&hZif*Z9E{z&cjMy4iw=je%MruF z!#IEbJhHN~Y=+A7?cTk60OkZZe*C!0-t)$d8%vp!TWDx#aG6hGVIhFIw?J=iughLG zAtAw~&2j-3uCHFbA|fI_5z)_|KV3SkU%%c0fvW%iD*s$tyb&QI5afW|7&zU zL|j}Pi9{l&HaeY-h=}+A==bm6PK}jHrO(I(0s?`6;^X6;+E@k9>-F^K&mX78|I+h6 z4_BPcW-}QK2I30@0++#NXJ>uID_{_d#V&2kW;5}_!otXv2tz|dzTy=yxZ*4j2q-)} z{BI{19v<%0_}jN{E+3QShOb}0Iz1i{5kWj2@2>z65fM&}jYgyOwec@tbaa%arly?Q z$mMb(ntKh##l^V{`Y$~ODwWEm&8k(ah-glLjEoGI4*!w>T)3vErxVef09&_iwQD36 zizzEBi_V`vPdPa`KBVYhWM^m7#fujyJ3HIq+rWC!0YI%*TL%ei)~vyiBS+BO+{~Il z`0(L_PfAk!4TfRx@#9D9@2RONw6wIKpr8P2*RHkZIWjT=V8Mh)U0odp2M1Zfe*OA| z3l}a}7d{tGBrI1{RaJqAkd~H)+S*#1`AfSKA`8JV3>q67v1iX7n<=sA=xDpsO3MX0 zoz7+@Stt}@@7}$*d-ty02_35ddc7Wp4jpnivpT;nzZ`Mq%o(TLBO)S@pP$dVh^%RG zE)`!gnary-e}7?gbd=LFSxQO@%a8R4T)A?E)8fL36DITN={8$1^ zPfv4Nb{2_5c<|ssKofL^M~@zHs#99EYL(5K%%&48E-vPzWN>gWIyyQ6mZT#*efkt3 zAt9VNmzS5@_}d6DJv|MjQpqV`XlUq?t`K*3ce^a%nQw`Si8c$PfP(^w_V#v8LFYTg zo}M1RC%YKEy}eGW$QHN9k00BO3k~k_$^@7q*3klIiK`tYeXpkti!G^Xk#iYPBdTDzf=H zO-)UO$z*~?qd{zJtX*z=J|8VDEiTW&sZ_SUzTRe6$HG$Cva&LVS0Ow+9Q*d|LuqL# znwpxRQmJ6ESnQrhtyZJGy&aX6mB`D>b6P)q?%X*5z{{5}?Uu*X)YNbinRBu9ty{NP zgQNLk>At=`PW3s9Z_SL13=9noL8Ve5Gc(ie9VbGe5bxf-1HfJj6bJ;kcI_J1wA|Y; z(c0RIkdP2oxqM1Wid)1NHgC)2H*el-{jxi7-~c2N38&lMV*!A_1&Z@M{n@i;Jtj{? z`10iozI^%ORg9vdA^?9s;5_*r`M=*XKAiTU(nq zDR{qa&S*5Es;bJZy50Ha>9#q!T#nk>T9`~GZ|VDf<79GjGN&Xw**KY+n!5ZpPTIqZ z7cWpyP=JjaH#$s)>(*JNQi=The7_ZC2W0bfXJ;pMb#>AA@83zSR+Cz-CX2;l-8`*O zC#Kcf^bTlcIO4_kw2W4hva$2?W27VX75f*NlHLSbG=Pay*%QwzH|MlLck7Iht|;u%VW=7P&~OA(2vqnxlO9 zuO2mr%uK0-)NL(QiEM4;E0|8(F~6n?l>a{tiCLCcvfeaLD&i~XDmcYTAJMVLQ>3NF zGYe70!4b=XQ#&VFbk4uO78b5+^c9USsYmXGAMX_hAIn_Tvs}Mu4q6+%VP33!!6d^u zNg#yJVI4L$Ht489?E3Uc5d7@y?1xMHwzs#pwRLx$>9I|Tm%o2Q{iU5B8K}J21D5Yz z+VppX$NM6q3cSQQw6rws2d;#RlarH!13j{uoSZy5IvN)jH*leXSWnd#eP$@?O>lg0 zX~kJt@j|I>Z3?-QR~Z->K%fG(aQUh*Q1at{|Nh0tQ(z45jQ6y+x8u&M?j!KlxfR(r z%wtZE>ywv0dfvI2JGr(WpOD}n!%5PR;AX6ZdYPF$wUC&an7~Z97O1iE@PzMu>BJa~ z!@=u_yN^tOFj)R?b8~aEeC4H$o&f=Ui0^5@Ba@SSvR3i&@eL1pR4C}(RKtuYcKU|>TgFqmxV?Ds!C5V~#@BQiS z-7qUU*;=lUSj6M;2jQ>V+mA^kYAPyM4-YHvd8(eCp8WiLV2`S*s!Y>n!q3{;+Ood# zi;R{Qd0$#^$o6dTkN43hMDi-I%r$;~@>w50zv!b)JdsHJRA+}PRKg7mI8Wut6{u}) zZW?Yy=^~NH;juB7j-H3|`L#U^V$Kg92nYnD>*{=LZ8=HMlyCw(jdXOhj_8ErLXk*| zf{Sae@&tT^K|L1RBo>cGqrGAJwS{JChW1ugtuf~jj46Nz{NCXeX=!PoCR$oHDY`xD zKH=O+^Ae5S)m2tO!DRvg9lll@Gg~HV%{SH$$`I5%K0N%~5#)03-W5`d+zMs-2*pzd zOHu123yGq;!S24kGBM({#&QrNWx6;maOCmNRu5dQzJUZQ6bA7t>+B3)dK)q@FmMaj zJKQD$%?u1wV&&lYzP2X9nO-xWAvFH+r8)Y7l_IRxL(B4xm{`)ZJFF9t^k`3CT-YoU z($*37t2iZPY$E%Hr0OdymMZeY$O!exJ-RP78fES6p@bGU;4GY+oQ97KpWj+BIQsp2 zY-A)UF%cOS#)swaj`{!u^|=*ap>@fzsU zucGHh%Bfha3}Z@#c&Zn-goFfHu`{}6`|iM%!Ko<|$~&otKX3`^9iI4d;R|kA>qG9VX0#t|Vq*TmMU(=*Quz!F4wk=sIaXRueB-~wo3&{G z?ma*L%p&j3D4=#inunRcP_apeCMP9Ld`D0=qZ1RUz_R!)WWLF<+zQRfV-hU(+)bHb zYJ425s5rOhA+D^9qGFBF_3-#{e)^k@jqQ!!=h5#7`Ubz|2-0>2XZ3Pma4@A6{_M}8 zrXN5Kcj3EO$IcloZq(UH(CVc22hZ1DAFJz~xOQ4|@hIj$WLdtN(9cQBGby;{0#h*V}=(V)aB8-1M}pii(P) zWKC&lDNx3`1m;Kk0D+wmhnT2j9Drjaebxy5xj>FBqGb|@TAXe3nSWHM68bYwK>E*6 z3KIr{p$fzSQ2g=!g`1mOMGiB$Kq0hd3Wv)`P3;e<+TPd@#~2>XDAUl;{QUW|e|FGS zKBc2EA~G@#HVjnjQBE8v>EXv}(+&h~b{095d{xQ+3pY1685?Vypoh6R?$6stzxe^X}*f zDV~kaF44a@s{&ZGAJiFr+U}hIww&Wv4c!!^{QYY=gYEq6>`Y2px;cw&Aans*gZ#a> zBrYzV#}o;8^p{-|2!qx(DJLgqQL?74?uz{(K+XYQyYV+@R-a`9;mELqnmITIT+Z6s z+Q`YtQN#PBQ5)h27mRF2SYG}hSoZYvlv0V0g{4gCvH<$kc;$dx>ZCA|j*lPSl#MUB z-qP9%oH4ro`cZ}cX#Q;v_%jPf$Ft7ox18QmvEikpq-H2dKtFKq<-A0^i;IXEg-Azj zMPJ{=CcdKI%fZ{u^kK98OVi4pp6J0u`hH&fCinnRz%DW}GH(If(D>)`;$qX);?AzF z<*qO$yL=XkBgEmx^#0nI3-{{}ULKN_eS0{~i)+2-7iT{-!Mh%=uA4}$hu`1jaLZ@n zeo)d1jO#(z^`xbxUz!#s=XkgK63Q!Vp${G~w%%-NYunw~;p{vXB)wFaEN$ zR9~@uzCR||+#;v)BIfUr*TZ3bIx7nwA88_*&*luc^VU;rGWS*rPe@c$w|I|M@=GA= zb?I-XCng5o@wj+-h40MC4vHG2T3f+jFnfD$ac^GDm?$f&Y<~x|me3;}`Gf%!X*)-p zUmZmxs}^Bn%l5z(Z+$U~oT)U*%i~NR`TKi07R@do`~a51$Uo>h3SwZG6_#d6AIVHA zGT<z=2ycRl|aOTCdCH3+5QYBT~Tqq&Wd&&ear(E zQBYC}@bbcUkEJjPLbeqZ6>aUfQGk;s+}u1ogym)P?z7Z(_T1uP#zuwz{`>DhFf42G zJ1m;Sv2Mt8O&Pox<2csF6*2?%ncp6aA> z*}$Yo*)rS3ONV&0Wd-!jycmG4f`fyN8on+p*rTNHcZJqN%D}p;K!FGJ{-Jr0Fyxx) z$)D#6{&z5W3*HkzXrXTLk(RD2DBzu`eN$OUg(%l%9v&Lf>9XX}?J|Bg;R>97f^~Ug zwEGgQ?{CTDMcbPv&M5B?wDhVZvi>-riEI=+_#|i42P} zH*YH5zMX*IAoAqgcNSWxD$!~3`>cq1!yG7EW4^x>wv3UjXV>_hAo?{VQ54jJ++uYl zG9Ow!0M}WZ1PH|oF)}ie{o}S_2SAXe)8{;t3;;JlTY}$ zv7w(_^LKqBn|RuQFRox6MMNr+ zlWA5*fZEJ-@X|5quB`HB|Jr=<1l|lpYXZ1hRw3ajQ3vw>MAKCgDGCJJz)81-PF?3QbR)nH)zVe6>Z{|ZCnK|_K1y*W#v`lFQL23%W`yD@nK%K*H z5(E0qX=G*q>1pJ%y)Nb)5~9#FYI946`m4t7QWw`rA=deueR^(l{}i&oHz@YvJnZBY zszK4=PWwbZa(|Ut55gR%d<|Sxn4dr3YxcD#GHiQRGH*9!gCS8(lssc|)6;Pb(8v%7 zqyg5)=+J)%6o3Ee!X*+2?~P0ctzMdu_eDO6{}Zs>JN@n*5agg#t1D`OK)|d(4p5!IbQ%jE9n_GxY|reQ93>2$J(tHuZw7njHCuZ{b%r~^P zv{0akfGz-3s_i-dhQ283=hq&9QXgdAjk0Kg}~E-otS8N`F7e=g$ywY6EFM1@;!qn(nsD+Pn(*WDkv!EA(^$cwE^XG*-rKl)-s$x{=w%N{Ho8d3)6rV z6sT3-JT2c$=eqU!K&G`i+gF>Nc z>FGf#`;~e?ak&BGmxsq%Pp3_^c0UaAVu6`=Gnbj^WyzB#mwmrPGqyKm$9DD5j7~>O zODiNK1c7Mj=}{+%4KuvDS=!LR=!;YnFmF@vRgVGWj^_Ch+e9my+}P>wUu>+bL?WWC zy`6FE3ie?wFj{d2sPb`mN~CQMn>af=<3E0^cupA_8k(&^DV}{f@^0UuEOyjP%Fea| zCMRoac8q`>R9h;iSUG5QD*rYsnkt*d>rR2=O~EW2GZ)u9AUqE=k)fg9GtXYWe7X2c zk`;_cX_d{-(Pi!nK7ywza21X!FO-*>;WP?*zv1aU3s6`6UAyQN6@=7Jr zN8-6$;PBGUPKOYOd%)5}(?Uh3Zj|L=Ux|VbXU5ptKI$5yfpos(TWYi}0)Ro8MP6?1 zjoe9tF2nGnO-z~B)B;((Zni`ckQc!FzCO*2u|oAoMZJ2<8YMu;8BA9%ZTHu&zSxTxXXi3QQQ#+d zN7HpMA1vTLKB^(x)*k;i&UA&742M?t70a1iig+Ognjsu6AW-^gxu>6By`d;8S{Eo( n5{U#Ju}?~2t59OlQ+K1 diff --git a/radio/src/bitmaps/480x272/mask_shutdown_circle0.png b/radio/src/bitmaps/480x272/mask_shutdown_circle0.png new file mode 100644 index 0000000000000000000000000000000000000000..0465539ca4332f767fd593f03c37ab80bb7d629c GIT binary patch literal 2478 zcmbVO3se(V8U|gq6bi!8%4G@_tmT4>yfC>oyoNwv5u#4vg8l}B zKumZ95P%aHz@al~LI#5gc#$i2PnI`_y2P7>L zA~77v3tF~EK5@Y$wOR>7kVd1SYuI$0kU&fhhXXNK5Q{}45j0i0LXB!^3f1Nn1|Fso z5>lmFiYovEBbtb(sktEO?UD?+(nzaNEr*H>8l**)5R=X@$XW!7ghre)jgT!G7YQLu zhRHF7T18@+MyxUkSL3QA{J&5ew|`=Q3~zY2(Z| zk(dfkBZOGsUee9Y1~p1JfWS~SPDJ6jY$aI{D=q^p4>}8Q4o8Jjg+YYNkB(qGRE=># zGH)yzlSN~2q8MH<+Z|?kzRhI948{^P92ZH&=|(7f5$YAi3 zSR{nSI3Y(#$x=Bg!62nV0s_WB!U4DpCrHDjckD$k!oy*{LZwC(LX6Mjf~0D?R4Rg* zY>Xokd5URl2AW87M_Jx9)Scr^<9K>7SYBeW$Qv`B=i$OMLvB~ji~i5^+XyMyU#RRi z^BB6$P!w>8R7IvMeYq#LW2wt4nG{&80~i$=>YED+4T;4>;PPwfZ;rqcttJU0N&iQ> zmtZPftk$3e<}V?m^(zVrBHf1!y||dL_iasck(^ZcWk zINTi?(s*yOwcHGX-I}?%ITzbQmoHzQo>tB4va+(CWNx9Dj}Ym>!8u>c&ICOf9nGyi z^wCF8$Hp$kea5py1O0Ejp3B29tgNg|XOWkew>IoeC#Tn}t?!QStSdFL8yY9iy}u8&%6TDPu!vfG4t#mdpqF(^2=sIbr*X>&EfheL-u z-u#23;}1P9U**|3j`gm)u%OispR2F8TX6esYvj3J?JfQ>{Y~pNYt~tq*?(c;f=H&P zrz5M1cROACvw05kWNvOl{T-w{pH|KTIo{qt$P-y=YEMT;PW$7Iykk54bd<5fNI<~X zh@HK?%@!RUf*ui^T_G*+Z2JqP=H7TUo)Bo>@M3h-B^8mt9}55qBiQw5D5AfqlI%Q_ zotyhAqNg0z-q4$xnhrg!j(jVNp$s3a!jsy{U%6&0d@Ifx+Uqd|0@~$ra`)l|ITmN{G^6B~WBJYBi5A8~U^4{c` z*;z?;d|VtDXFfAC!(98#$Vfi@-TnJNJaVMnuJO{PSU0;0eSViHk=XFvx8H`?Bgu6R zyUb6HR90^JQeQn~^I>~`XFfii)c2-5H%^MmT zrgV(i9;$ADGMHIlw#u~m*ea@1QP(8>;mMvn3lv4ECzL3fWsRy->=V^ZO=Z^QtqE6c zc1B0vrn;B?UE9{&>8~6P`lKhhuBD}gtkjg0l;Ggt%naFc z0iO)mjvYJTj}-|C2?~Ycz=46p3%-7S84F0VuK$Harv3`jH*4S5+5%?eeKuwIN5u~m K@IFTpvi}XRrPH4P literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/mask_shutdown_circle1.png b/radio/src/bitmaps/480x272/mask_shutdown_circle1.png new file mode 100644 index 0000000000000000000000000000000000000000..deac8ea7301a2efb6301e8cfdcc3f876aa03d758 GIT binary patch literal 2537 zcmbVO3se(V8jcnFO*Ag?5o41pxGNh~3}ECEDTgG*atGLRt2gk&HALH{lOkAfHkVFB3*kDPW-_tl&;nLBg8`~Cm- zzs?*C4-H&tvEG6}Agl}y5=7wl_l*~EDgNI;9=eR*%vC{A8hpRocrD?(9oG>EW@GY5 z5hfCbz!FqJ6-&`w2vw(0;b;PZvstGSOLij|unUQkE4ieXUtT2vaw(Uz!&^ubs{9a{ zJSbI-Y)cJ|l%(#Ku%)EUJb=zD9$9 zNEi;PsU{|1mtJYn#dFt0!APj zG)XN%{F8AvHyYKbU_Uh?#!z)6iY6>3D}2#q0P?0nfSXV(kt>ZN+<$Zg5r{E_OTzO8 zQRonb#*U;hVJ`*@`FPUlFpV}36{1pkY>El$H3wxz(%CS?!c+VcC|)>HF(&@6V5tO- zMb!#1E?KS+$049f8Ak$4frS0g1XPV1#=Y~J^FkOI6Miv| zvFnUQ0SC!7c)C&+dSV-rxUfo)19No%izUYT=8`1F#3EAC!fW|2j=(&vR)*lD{~_J; zFbx`uX~k;9Hx7^1|4>jM?mlSj#d#&*zlxmO`%&L6!tr5XT$&~k{$QGAh!P)QYJ5_C z(P;hEbOT7tg zyfuO39KVhMwUZ@>$Ft3}3JVRrJz}$Zb;~PG&Mz=@osi>1g0_I()Qh%GRNT;FJ24{ zl^wdE*W3Cov-EZ{^yKC)?|kmp&?oGAJvQdu+*43cFgmJXc^nw;@9eZ$@6Z-Q)4e*d zsid&*J%_%Yo{3p2$j{9lY15gTo1-Yo+vaT3{2Nht_`Z;yyLSiCLxSe&YI@1g<;KQf zMp@Uh>|(+?D}!CG?_-iMBV+dd{SAf@y`DN4C}69!+O_PCB%>D znjQHa%vv?!In}(nzM(<#*u}+#%i&mWVL?!qV`g4%ZdQnsbANL)Utl(zc&w;sa(X(1 zRCZr^_~VbSf4!fiN>Arb2yDtmIy*Z@-oyn4wl-*j&3a2F9=!7{V}tWGVgRvh+3fw% z8woyn(8i2x)o{O~C9kf&K9>cCWq(@t$niOE;K>s_V>SXJ+ch>~@bkjL!kL+w+i^dX zSbHqLSx{V7R8(})7U+K+RB`_Nu7-UthKJwPuCw{W16X7cTKD!&`pJyr;dcCr+pVpw zM~@zj0%u1JhLTX%<|94MwIXs$OG`Ay?Ck0a3k&;pyNkF5t*opR3WfIGs9S!P?2{%A znSbD3dV2b~bLYMrI}2RxyLYcS%Gsj-)~#DlpUUKN_wEbKYg6@D%+V2pL9JBkuUz4I zc;x4`pW1S!`Spn%AMFjC7#kaV^yu24>yti?nY`}azyMOAjJntY_!NcUG}grk^wkyM z1CdCVnE2K9>^PhH+FD}YcrL@O;5>-Y-}f#_bKEmFKCZ8-`nt8XMz#%)8o#Wtq=aE- zS@ru(Sr;oRh^MfCfaPodn)C2XKzX7>vVUU}p&Hw}_e96WC7oRTuOc^<-H9K_TxsD+ z^uU#JFuTI+yu7^V@1J3R85&YNfMY`Vp{v&xpDjzpzP!I@94yMFU4A(gLAHp0+~42- zXssn@Ro0am^rGtd{>;oJpMB%<_hrEZ{-J>D+r>NFD9<`8{b%b(megRe5>2 z*sJ^Q-K8QtgxN7UzQo||{{A^{{lZThy1sdo{pl&Ux}6s$t;16?GB33G|M{~OGs{Bv W+gWU~-kERw7z_3f73ldfS^oqCXz8T@ literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/mask_shutdown_circle2.png b/radio/src/bitmaps/480x272/mask_shutdown_circle2.png new file mode 100644 index 0000000000000000000000000000000000000000..3e869d95f36fce90fb1ba4818d8b9fc2bf5f7c49 GIT binary patch literal 2495 zcmbVO3se(l7N$s-he%NbZ9xrV8&Jq=k`OWw(IFrhf`}2pM|GGPNF>RGWPpG?Y)NEk zrEIK%wg&}SwH!rxEQKltWtWGC6%or~mt~cLO3~V~rBYF3C%jI(r@PyB&Y6Gy$M@fR zzxz6q9~HTAk;5AfR#sMv!o$ST)K_A8?X0P>-uLS()W=>E7N?`mdoAxPu=mG$D=VAt z6|z_|RvH1Jgo=q^L_E&at27ka$|^8OuR+ixoTSC$i3+s{_~vpGKvQ5MU^`#RmTH1= zxgsn>i*L<{l%W|(s1O5!*3km>5G6o`lL$?(QmS>3UIa|bg{Zk@n+4FOA!L#W*kDme zi-Re0BVqAx6 z6&g}OsA(37NIa23iU7*m85%0hyjZnv)>V|#Sb9Xm;xO43TGK!boyTcXw90Aa7|Ozx zxC&R3Itt5~$7CeuJZ6Qp@d5mceJkXZAhE4UaTaS=ep z4Poi!rGhq{2M~f<@>>L;mcZf|FuSez%^sK$nOmk*`b4zBm#QuO$0kt^Nl$QoUhqQ$A``YUyZ zVt`ZrU4LvmS_MQzdwgPydeay(WK(v!Zy|q3*t3&Vf^qh|J-XxLebh@q4(Qt5Z1#zUPDD+TOY3TuYWOUTzShkC~ z(Pf9P8)#6eRPyGsGEdM@US2MT>vl*FIzKrshs&bE4t_f_;vikVVukcz*Wjo)B&5u9 zpgy?uJ(ek~%OH_RFuU(FL?2aMxbT7Fz{tqjkDS;2(ghs zWo@{9`*u5A86!E+rLNC28a-Ku>g(%m0?(Q@oo+AQQXyMH;~kG^hmXCUnwFNl?9#3a zLqiybWoMgvAGJ&>PF>quD(4A>`Inv5%kO5E{?K;#@Zl3DPE@(Ud_JFKqDe_UPns($ z84w(+?Yw!j+6@LwzjulTObz|&^TxiuzNJ^*aCfJ+U0q#yrqJ@mNdvcTEq**XY!?i} zf9vfXb%pEd>UbbQQr ztWZ`VQx=@h$tip-;NZP`dnejQM)sY(onP*}Ppv-l!nB^&@Y!eAwhU|hf5qs_Q(RnJ#OBngXP@_uj&d?h-c2!aap~#l`R_aL*tKh{!{M2bS$wYd(Q&k)JpH~5pLrjzk>Qy8h&x0{{2zap2S_QvLc0c7Ir!{HO9+s^eY{m__~ z*MZgCzmFGpw0z*4>bRq_DBf%^7|xub8}e@koh=Or2&h>9>SbX;C>I24YHPoH@xp`V zX%p1_jif#8Ow-sH8508oSe~7|((JeN+_m2oZ1BXYW0$zN#4UAm zb>;YsUFlon>x)TZw{2@_aMoV#XD}EMj-s4ODr23S3rG2MI{hlV9Jcl{>}@-c`6ri3 zv)O#WAxjz&@t2mCS3~V~TDuv#`ukVhSa$L5UzL8ftHK-`aJvy1Kft zF>nHo&3^qKJG-d!%@wkVm*&Ncbten!x{7ZkJkdSF2nnMnWAHVa*$#Q~*;5sY#(Sri>7yN-Q!@ zizei)N<{KDB76lkd?_F>LZkvUs)qriTBXrJMj>@fFGTL`pBYqO45HsCq%OA`1d?U3 zfEd@J0H4mHAxtI<;E_8H7YyU`c|2YS05U-~gUMxpp)`;Uh4LU42bj31q(!YF6N;Ct zn6O8_38_lGo`4vPoSYnb4x5f^vluKspU+@|3=pJ|2%0Weqlb+&jc(DT1_`P|v>2hs za1CJB2xs61y^u1agSMP8H6T_3QPqO65}ddOByDMkz9!ldQ3Jy)d%*+hsfGC&4R7}cCaKvEG?WDZoH_Csg#mN4GRli%0z3c2n0Yzdu zGF`b7J&}NJn%Jo@V5|-x7_ry4kc!w7i;@h+KV!c;0^{;IN|aRkU(!7e)8U!=99WAk z&myDse-sphbf01G#c?K#Uy>X<`$^wU!pUJ^-%d>;@?~n4p&D|4X~{`tE&lNaIRFnt zNtP!XZ}DnM>=eX^0fB%)MG^K0AA%ta2JQbH?Ju4A(Mj zW();0Q_Y~Igt9R}9O$2WmOB#O(yj{^w)2LO>QTnXTWjyL3e?*3T7KclaJA3Y>wC3^vf3&yv zJbYMi&!_J(l&%Deon2h`zB5HJ3;g{47*t}ldbqiXK5OjiI)<3My}hMUDdjmoEDTty zJe?X55s?xyPZa%QOH0(;ZvEdXD>?+GscP>2jyv!B!ykPl+;qllHdj=zn#CDuXrHK$ z@KQ8fxdI6UwHv3K<_rxFd%@FPT~m^iYtBj*5eAQ8+r8f2JFTs+UccTs@?L|cqqmn{ zTk`BeLTYMWcJ_+cY3r@cN{+L$^L=IE?%nOTZ&NF`iJu;KZ*6T2>#tceW8E~0XY`Ty zbE+B6h*J4kiQ~>P+m~O?J(ul0ukhW}S=WD%b6v@_Jh!~vRMmFq&?3-fGuL%Va4^yF z+$bnd+AAo1lS)}Lhb|zN@rq+Qn_BiV>Yjb&c=6iEVDG-!wy(eTe=2A$-5M>Hc8rdG zcj^>-MS5CVTV1u&aS9p9a(Rwtj_<|bwzjs~JLfiVe74`M8C~<|l9F9<-^3q_b?el1 zT)#ehMS4VpOZ0BQdY~N1$SCjISy))MW{IJou&^-Mc;LW+q@<)kw13AJP5(kXhlYj@ zCSLig?ZE>iL?|&DzZHL;nN68Le}2X0EgMez97+Du?4<(1Cr2rkfLWB-?uP*#eSJ*M zp391EJ#>7!mzP)9E#a+TCznX&g6$V89{SXOZ`-oPQCS+}FFt1ZxS*@6tGUJOylqRj zZU6rH&f6RV8tdzq1(o=Ts?uhjmjw9xD}j)}z)!x5b6jn97RlxEFgPXUz386J-rX2{;|4eOnr6yg4wy zb~okc=M(bv$;p3+-VWTjaf7hgY@$3$eqP=^Q~WXW0-MF+6V}nz<|{Nc7lm%f9<)-b z(&$c2SFi4VeR_0zc~w=_;lrl72U3aT)~NWf$>e1Ae`T2zvOfB#8Qsl&(@ z$szN0NQ#S#vM41{7Vqu0Z~SiYq7UTrPi$7gRR*b@(lOG2mTQfBxg#*kGIe Phb&6EN^(N9e(S#h3K-*f literal 0 HcmV?d00001 diff --git a/radio/src/bitmaps/480x272/mask_trim_shadow.png b/radio/src/bitmaps/480x272/mask_trim_shadow.png deleted file mode 100644 index 4870e77e35f321c96afb7b0f122d3a0581fb9d77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^f*{Pn1|+R>-G2comSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt=wZE{-7< zy>HKK=72B1~6O_F7|2%i~Zf|0?(fhp%SM6Bt5qfsQ x_GXzU@h6xVCMj4tD>2QqbiO02^oi5J*hXfzxVe8yqc_lK22WQ%mvv4FO#l|~LDB#K diff --git a/radio/src/bitmaps/480x272/mask_txbat.png b/radio/src/bitmaps/480x272/mask_txbat.png index 001d2751c03e3587780330fff21ee326b0d992a0..ff95c24b210cbbdaa530615d14fa7646b3a04f89 100644 GIT binary patch literal 1483 zcmbVM%WvF77v&W*O5?z;z-dS=k(|ivcy`yy+GFh5 zt`kM#Sx^NhkfKT)Dpg#NDh`~2I3R9tLZX#giNAmz-~bgIdf@XutWuR%E!iG>e)Idj z-}kz>w)*0cnG-XTBpqos+;wL;yy30M%RFVWT`^Ru z>xOK>s#-@2wryF~^D@$rsp)kM)l_8SnuU$3JiZjLmmF zplLZtG^3&yvWCEbmbj#!_J+m-s<9r6SS&KY8YMRAa>27M{~PLZ`!5C{yq;IuxUVl! zRGP@d%6X764#<7cnZJ`TZJlMjpHjAR9^5=xs7dg0%81~p&v|c>thI^DGOAUOJns=2 z#)XJy?mEI;BABB<-jHe_RkwZJ!e$kt`g4YXb$tZ&co4RCN~k%6)_g!9>s}}nPCx|t zS8zaao2L;0$zen~OiSX9BA0>0%e==^Fbv+ALoYlJH{(o@n6jqpD4@C$h5@cJq?`3R zRokd#sa0kzs4Zl)RlR1KHf;sw0wR<1E~ot>x0Cb1|2%&-4WYkC?}2%Wt}BWHH^L0k zwKMLCbL{o;su#+`I>3Y$_3bFMNGuDK@$c|~BQT;JbQzHTL%K(>jJL&rq-?1J(fSVs zrGfie(TgJ`+Pxx&dw2Ei1P;TXSeBCrKFV3fVi;g4Oe*(_AK!&3x7T!+{P|<_vE#@0 z4?VQGxj8pCH#oYKWxu|mZ>{D8-uE>FLye|z)hrK9g092`_@wWm(+ zH9q?w&+{LyUHks>;^Ljz>Gxh~G!7q|{b+x`y|wknZ$CYL`^sys8=z+|;r=ag<*f@B m9=y{D6rAs2rD2XskIMF->s1q?ALM9tb-0002PNklST6hzNo zh7Jjd5*mbPn8BiED8^tYXlU4g9s~@)u|ObEV&Wn>$=%7%r~gk@Bnbx+IFd84ilT_V z?*jm|*2wc5p67jZsWAq1U0;LKG-coSR?}2fg|=-kJz7K%hT(1ZXM6{A7zPwYfpHwq z!OODPPa}e|EHTgXzfSjp_kG7SP1mL@%V=A191{SyZ9Dbck~m2ckVFs!=RIE66;0DT v+)R=8-ldd!$w%9#>$<1o(2jn^AMEh~V-VAl6@Z1l00000NkvXXu0mjfH+y*H diff --git a/radio/src/bitmaps/480x272/mask_txbat_charging.png b/radio/src/bitmaps/480x272/mask_txbat_charging.png index fa8ab8154cbb6fc824535f69b414fc7eafc4859b..6b772e1cad9ad6a854aa22e2536c15720addc144 100644 GIT binary patch literal 1761 zcmbVNU2NM_6wauCZZH+3y?_8&u8>xNOC(&X&K2DYaARL5R%2gdJ55ry zb_}#Zr4GbHK@^Dx5D$Rh1&P8&^DuY-Y11AicmORzpdo=!1r^gqC(3nxtZiyXwMdSy zeZOT%b?EfGEJC<)p~flMRxvj1>8ls4}XX zh9xUESaJ(yT1YG{eyxM_~lz*PQ^=D97*bddNUu_bfNCkVAwXK><~Q z6p7ikW!P@y*6};3!bziRz@^zZ6Uu4<4L!oS6|dY1Zs;^DLmN7QkFjiobxSBfehF>i zI@-Q208X!}Mlm+!V%t#&KgdpF8J&b|iuSd-3+Zv_ql%})>@=p?AF6Scv%A1GV2kP zZ$U*3BRCA@uY=;oF+c$R7i{Q?i98!%$(9X@kanFSNkoZM(x{9)92m3XTP##n$vb`k z93AE}DH5xWTb7{!one!*z)^BRN>G9z01B7_OR+pJBzRsHS(EG9XOLbAYumLqu)PQi zlE?y)5()*G5?EkTNwFYO3C864q{MQjoaov==~?)Ef$}Z;2~SEkW$`CgpC!d}Iby;K89H&ek>>ir$L8 z52kNUetYG+f&5ktcx&W4sntusDMCCnX)=^Uhohxk82ZMVwf3$VLtQwYZQ(K+toR`s z&CtQFJv?~NImxf_&_12d3~9X&>X-X^nk%zk9{&A~o|o2Eo6QR+E~4hj(aRhEZk#;y z)1jwluD;Wld;Ds%F}J?_CjFN5$3~+;%vP)ui{$FUhi|-4K9;`o(g)wTzYW}_?Rihq zeqon?xG(o7pWDggUc5JbaMqm2JG17g_aFG|?cV|Mz@$}clW;b)Kj2kBHv`Tzg` delta 542 zcmV+(0^$AP4XFe(iBL{Q4GJ0x0000DNk~Le0000U0000I2nGNE08H|3*#H0l24YJ` zL;(K){{a7>y{D6rAs2rD2XskIMF->s1q?SP^)FD{0005DNkltC4EY!yfh9mQsQ7ms0gX65hoW17sohc5i_(kP}eR+Xt0BbZ7FJLMU;raK`4Tl zC4mH;)KaCBW=J6E(!S%MsE=$m@AZeX{BZd1e-8h>R}&H85TJkiEx6n7v$OLJ<)^5K z!{Wj`c48Dg7K;%K27lStb<*iHfk5Cu0@-YqQmNz?MflKcvc2_*pkbg#qfzSh`cR$a za=8KF{k?sri#ND>?K(#^4P7aPWm%q&`OeHuzI^`3#JNe(6uK9ptyYUnCPTGaC7Dd} zcJmGEj~@^+43>ZHmkEUoNTpITY?!7g`Fvg)jfRMbT)Z$Y@ew3$A@=X`B~GW$oagMs zB)wjj*Dp8d_51$hc<$~!0N%gb+U@oL|8#AYlVd3g#c6MLY}>W~ z((QKtl8z%M;$c~TvLcR%c;YybNFX9aB9T8_<;62blgDDYbomMzpm#bQ%H{Gvvr-DB z{_k9xrVVhb4;Pu5og-|T|J-Inu3D|;8vWPpExA?5yEw!LysA8x_K)u_&X?C|EOQF$ g=rQ*?4(lWE6G0@~e0$5!&Hw-a07*qoM6N<$f~7A1l>h($ diff --git a/radio/src/bitmaps/480x272/volume/mask_volume_0.png b/radio/src/bitmaps/480x272/volume/mask_volume_0.png index a6ae5b6ae75208a016d87cde1a4aa80d66b4ca50..f45563d3fbce4aa7f0b52424a97a06382a552c56 100644 GIT binary patch literal 1912 zcmbVN4NMbf7%qm1qD=V-DE{nr8V79cU9ShF7YkO(D2{?)H_-Xh>)o|IY448f(LWRn zCR0NeVQfxkrgID1&~0jrnMjNw6Nod6F*VFBZWFh#IMEmffeE_rN@;X)e>S<^clSNt z^S;mfce_>>7sSP;#wrwwxI&Y$4BQjIHFw4|@c$-#Y8JT76ijP9V836!qE@Eu_bU|9 z!>px3sxTK36z^7%G;d>6ezyS73dQnVzd%xzj0D*j2g~W<+wEszh^6&#d8QdP3wex_ zH3daxO|aNP1uH2X4d>=S%l!l(a5EAK`Q0wgL-_S@h?f9s`85JVA&69|hYhkpsKUG& z%Hu@_(y7!+3PshB7Oe0rEL*43YPByw7>a2SGz-Bpm6(Re)DmhO3jbhWQKaoeneoN2 zJ@BN5osuLF2;%ekR6dQ07afRNr_&)QhG3WyAe5c}Cy{<7=UFnvU}QX$$O;n6bCAqP z+W2Zo4+C!}Ww?b1E$0b`3Iq-DlLDevp|Y$HkftIyp;~l>jMEgtxEMFXNgjYzN3epE zmw1np{~PMa_9F&Bc+KXBjmP@pc1KKjq>(H=`cV30D#!&i$GlkWv?E|Jv; zM4rfy5-(bK-Zho1)l)7*Sf&bt(##~qab8hsZ2rI55COFsT}ER6+{HwDdxw!IIXr^$or0Fqzan@w7BII>nHX zx)6&tq?BGtn0?&4C_`}eb@X=T8;s-c^*p=bTX^Of$wU}NpXu})iQTGCB#O3^@87TWdSAOeePncWXYtSCn2=4MxMIq` z(%#{VS+-->NTA6*mxlWB(i#Fd|J4Gj$k&*Yk8qw6=HJY3eAlan(SYCd05QZhQH z?@*%Q{gnC+sLr9;-_zgUpWM*W=XBz!_2*1Q%Pwv{IS@6IbmHsU*5BVlqw`j5vV8p; zup3ie+xpCmXmn0h*M{@7*uBR(=lJ}O1AhO`?CICaS}zR_4i3HCRWmwKyLk7GI8|~(K|z7_!;9(hXWH80 q8#=FYz6JN{<7>8V?QFkYG#a<}kN83Bio!Pe+gO-iZ2WAcwf;|Rbg;-|e*hVDMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs0008t zNkl1W{o@2q-27VL>g#plgIwYApzBA=vtd*eIxAA(CLF zMOqakxDiAW!N%ArS{OtW6ss6r*FwnpFWK{&djr>d?}Hd0fA7H8%*^4(oSFGXAW8fW zD*4;Q`};fM@i-ER1Zrw(psFeqMfoAP54+#>Ox(Fo4I$ z$L}HYlXP8YYilbF!{FK38H2$f!{IP3%VH!FVOv`pP1F2rD_FmPpP!$pC<+b3pr&aA zkgw+EW?o!ee{g$yn}dUc-v`cSvkZkoTwPt|^z`&E(4SRaUe07P$-cfmCX>nH!HGnI zkw}Cc9UZ*Czh^~71p!b|6t1tY)93T$;gge-JUBRDAP^`X+}PO2{r!D*cXu-uixB{2 zS!OnyrPJx;+}s?uwzk;W*-2TJX;~I~dwYulJ8av=f6dJes;jFZNfJ!c1OTY23Q-i{ za=GAgxiC693Qg1C^?Gr6c?nI^5C{ZNRaJ%a^Yel)wd3jO2_GLHsI07nAP6WcD+2&L zJUjpZbX^BY7>0q7krAk>3a8VFlamuHEiECF$>co+Kd1WodhYG*v8$_#sZ@#pCa=GHV*yji)CMFmThk1H>e@eI8O#qyqpXb!n6alcbw3Nfc!}-|P z*4Dlh^>1Lyve?tp!}0NPzP-Ki?(U8o8yk73uIqe#edXffA^}hoMIIj?7Y`=MTrS6j zg$35t)v>?7pF2A{^mshfb)A_^CckcZd6_LOExfwADi|z~fB%nd+s5_vHC|p`;C8zq kAd2GG&-9c275rc7AJYu^c)o-TVE_OC07*qoM6N<$f__zjApigX diff --git a/radio/src/bitmaps/480x272/volume/mask_volume_1.png b/radio/src/bitmaps/480x272/volume/mask_volume_1.png index 6fe0636ba2bfa7bd0851b1fea553d2c14cda8818..cdfbcdb10c14b265cf1ecea12e78a9479beab8e7 100644 GIT binary patch literal 1920 zcmbVN3rrJt7_Sa-GMpXi78$zB$q=3Gwbw%1(?Vzu25K4BM$v7K>-E~6w0F0=s}y9Y zRR(Oq$C^b9E;^<&#zje(_#6bC1Lq7rVs!B_2f@v42*{w*&AI;-XmoMUORo3b{eR!% z_q|$`m;3VgnD`i(Og26z8@Gbz1aQlrj0V4_7QYw;9^<&|r2;s=B;BJ-$+do&ENXzZ z<%{{21sKVCm4t(}Q%b*=18A9SZn~c%$U;hl?39aUjBwAxi+$-kTf{p^fYL$9|H!wlt@5+uZIyZzYz}G#egh*Mqnrm5etoQhU5^+x8y-) zmZugz z-i)wY6gdn*ii(PqMH(f`yAZX(U_ewTf}#q5Pzc40Nca_uFnz=VP6;GWb0W<$kYtgt zvp&%XgJ_3nc)5sKMi@>NNE+fNI7F>fNwmU12N}U}KHd{{?jRA$LwPAi6aZEo!E$a^ zWCb_-7p5b}k2nD7wOArP9vh3-8*w3snJWQ};e*Gl(b0r9Ky2OUV z%sfSiEN^33&q%TIMnZM1A8>&#F3YEd8(qS4chNixx zR%0sF5Y)mtXlHQ*stH3=YyhE2!L<5EprCOagh>1&*g;}WmiH2XGVLW?6v8ns7>Xnk zGqWC+2aZ8>ns5{r3zowOBEgVU4sL`2Yb8xPFv_k$4Nkp5p)ruCLQAIV6?Pp;DRg!_ zkhKPfUgH?i$63-R)pkVR@gMbH;b|~mgy(+3M`uzK)H&CXJQfc=CI_Up>Q8y z1S$2m5hkU=Qh>qGXZn9Up%4&0BF*9u6Xee% z!)Fi8?Fbw!14)c*BJdK~WfTJz7!Nj8P1DMWGTCT#4xV94ZhtFi%)Ya5(iab~TBRv2 zDw?UPg4}`kOl3Qg^BcPoqXNOo+5o;ISXsRms?>jfb`o3`n}RPin=aoN8&?T;EXhpk zS+)Pz>g)AKxQbOh{c|e%w+T~Z=F*0=^z?;$Z1O66(}JYF-ro8;qG{dfF0`?+vEbm9 z&Dn`uNl8p~))QM!m$wx3YD#^+F^6BnO`|Ij)tW_-M($tC+s`k ze>WkfeDpQuxwP#QVo%hsa=FH~x3{--@%ps1-(!ODh*Bwk_oTc!t9i|X)a~u97cNYk z{p?de4BU$=D=o#b58giK#`j-Zmz`MG(cSHhKU<)xA2oWdY~HT8K+BD|#d|Ndeb=w5 zJ#(n3>EpVA0pGFaX7jA~kKYo{^KJKU-b_jgjvEYxw$$e(f8O1#D9@3@7>3pPHqWWT z0}TzD)L*Y%n<`>cYnsnhBs^VlWPaW2%a>bQu3w*4*x}X&F8xRm)}-RyTPbu3U~%To zy?ZgrE%P%EEUS)oA6Nzg|9L|q9RJz!=Jof>(yuZ)(}(hRPQsql=WEMj$8KyT+ZXSh zd~wC(88c?gKlDvcXK(MO#*Doe>%R7wAo(YsuJC%the9DvpI|$R65nz)gIiFyg*xvJ4n_x0MQv;~ziM*c?dlqH;nt)+|F$CwVt?x+L8@k5y?l9%b3wzhtG;-|e*hVDMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs0008M zNklQmzOy@I+{N?lgTg?3UPLJmNPRmAJAW|xVV^xVQ^qzfQN^N z*5UpAeJ(C8vbVRFH#awQI-LZ->gsBSLLv6_^yKiVsVT0mu5x;M+B)3Y+Dcv5+27yK z&CN{$U}`1ly(P$Kfg@q78U}a?m03b;c zN=ix~e@T)x7yx`eA9P(ub8|Be4i4b=`vCy$?d|Y-y{M|H!uk0*0Ko6}BNmIHva-?= z43Z+5OfnD%&@c>kbaXHtkJDzeeY#FXMMd1*-R02G5Dmkyez+VC2bPwW;BvXp-QA6F zIE<~WEwr?>*aCCG8MN!~#xvW?Gets$GbeesAeHhk&d&Js z^u%B=$j;7AK0G{Fsh0fn$^4aUHp^fz$g;9BHZ?VIaBz_2<>j21nBe2%qg9k7g+x-| zFaNP=nz+2YL_N;*=?HVg7&gV(4IGKnu+6ybYk@`=_p-_LzPs=D{r>;o z|8-k(bJD^>W`;;4lCX?)Lms?Og;%(ABK*I5#!v`vllb&CcDR4Vdrep}Z@*h23B1Re zR*S2R*(A+b6%@l20)^YkL$pM)DACPRbO{iVLQu@w^yqMVCyKC)9$gi0#EpD1Fth39 z0$5(2W1`DTXdQzlE=Cr)Nl0J?B89lE7Mq=P>ro#s3D@4&7>f8HVu>D2@)|@|8*`Cl zP5_8bp_J1&u0*tOrPdG$I-ORljY9~WP+_sbluw zlO8pTB2QwN%jHtIR0>Wg#*{jp4#NqIAmk7sx0l&O$}P9qXOA-&fSndtUSv5N;$@@? zIftl6p|_(lth}GrW*-X`3>xO9cuc9ly|R2jhW6ulhhXs;XJ`yqfECz8JH#seSl-Nu zoZZa*4Yhy!5d$#1Mx)=xV|}q&{U+>UiWABh3&>;9c2gM-usmSr90CneoY2kLUNtvh?lMBeD+pwsk)m0fSH%2>jsOEC0zC@zM#zA(V77jy+)W3omnk?c3D+ML9R;n0aysa2T{DCBs zISVI1!_YgG&kLiG%&^%-%0`0>gC2#d6)ek;ARegIbWwsFr+`+j21T@7N2!6F)+vD& z*WwJLRF0oFaJ0jl+wt?v|2)4`U}1kzmM7-%cAd8<$aK~Y(^WRs6U#yA*vi5pzB(W& z+FRdxl=dbTFzDE8_K71fO6xKMNcs=y9);PtBGE+&AgLHe>pv6}2HnTJy*R1_`>ROb z-a~ym4u`|QyYx>Y_~4&qzy=4H04G)Kz&VFR5>S$1NHQgK@7|S_{_e8yb1f~sb8;(@ zL+cNtQhnW#XJbQxmb*TR*i^S7y}eR;D00?2S+k^Q<%Y`(44KnE41Yc}=Lrffp5 z*9YJ0bbbHTs%zJO)bo-3I#uUB?srvMU|nVO*MozxO-)VBZEcf|U)jbGTUKV>ojP>q zPK3}FRo)?!RR`zi=g)|auIjU-wym>8J4;I^?9SYL^=kfrp!?;8#Y4lx^?jD>9*>l! z=_95E$EfP+>fHBwPqw#rUAPcpKzB6n&V1%XU)=WUYN}=JA7S+~e|@lVXlSUQqT+t2 z=S7#pF{?I*-ndb=FMHw^L*?LaL3=U}^E@x9&8e!Y3O>&ePFYmcfJCKI1zh?;L}yGc zv|3+%e`s*9tEZ|)Z{7qGQbAc~L&}==Ydh2I6w@bE2FNVW#L7+`U^_6}Zb?(JRijYV_x`0?4{(t^^`W#=p3T!HS8 z_J@XsN;faz6QTkvPUoKPPn+`^19yIY=ETzM?7G}}b?xo<^Gigh6O~nW72wUc`)`a` z12h`V$uEy2rKP3@hBszrM$2S{EZf*o`qqI%AKZ2>Y?WLrTzoLC{_?lz&aE-&S6|L~ zki0#nEw%o;nXgOUHXmDgzjM`%pBF@KJ9+BV+3xPF?zx`nDGOhkQy;-|e*hVDMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs0009Q zNklT_db17&4pn3h74Vk3O4+@9Ftf{GCJRaxS*%{~N=IHnP`TF|GKp?>8=4Q%rPRQR#&H<;>Y1-{} z-rU@9Y;24Gf3mN-x|*?AjKN@#LqkK~1`8x*00vc6;rIKINF+cKUa$9)JB5XX*xug8 z`1m-cr>CJP3X;hroKB}!qmv*hA08fZadDBIot?bDzo*%3CID7eR&rrsfgK$k+0MOQ zFW1)AI59E7U@%BYlBg)k-&x(%)WlFI#P05HZf$K5e*lY%i~08UMyu7z{{DX2?REm7 zBuPxAQgpdoR8^HWn~k%xvzoy=060B8g(OJ;fZN+!06<$?8}xcTBuT=-!2vuT4*=lm z>Ix?(Cr}gxf*@dWauQQhQ%I-Nn!MJ%zrQ1qNWg41Ba_KMuh#(~&1THc&uatg^?KNBHtg>1A}=owb#-;n>2z3MUq>VoL4JNd zWLd`Y@-hHG5Cjwz6+sY$Y?8sjL9DE-XafU)%jH5S6hcEo1CEZ4;C8zK04*&oa5x;O zsHnij#RUMs?RFy;i=n){Jey>7brnXVQ4<&>f8|6XL6677Xf#Tv)5*)rOBxJ@oIM7> zf`S6>@9(p>x0lgqG-p~enT+<~GMP+RT3Uj|VnKU*I|6|Kc6N5q*w~mY&}y|J91i37 z_!y!n!eX)HTBrN+`u@4&kEJMz!mh3^4i67Al}hp9;eqGp=X`m2q0i@IYilc?o}RR> zSkI@9KY>Y7RaN?YK9-b}u)e;YJv}`vEiL8f=qR6`pT7$wKc39rITDY@aeaM_+S*!( oqNvTz-zzDQyak|fB)={B2S(3gIdZz>9RL6T07*qoM6N<$f~HojqW}N^ diff --git a/radio/src/bitmaps/480x272/volume/mask_volume_3.png b/radio/src/bitmaps/480x272/volume/mask_volume_3.png index 5cb9421f21cf7b9e391c155ec83710710da69c2b..08fbc2e4ba31a06ecc7772a93b6b72348bbdd892 100644 GIT binary patch literal 2075 zcmbVN3rrJd9IuEB0SyWQ4uRW&8#vqRyY!@UKzVdn%A<3Pn1$>03J3JAv{z|W#*jrv zU?dBOY^X3_6UKZD1jQkWbGWD=Aw$48WHV6-!HE(zfZNvsjV|ta$=&zeeZT+j|NdV| zQexZ^w^!X*EY=c5ygUW0e&F_WbpcP0kd9qoS!{@Z-vrLD+wKKXp*0p3%XyMir!i^D z4Jc0QIhdB#5FCr%0MIN}#CnSX!*d7*(h!*>C4=vu>3|_pD}&z?DY;5RG?7KdZ!r?7 zTN2gymK*d{B*U=}uI3Z7?>6DHh98W@tMAR8m5 zq0Nj82G-8Hp*J{aDbrl2K+q5iWVZo2D35Ou3U>FL@uExD8>Y^JO|d0 zMKiQ1i~b90$MFjaKzNl(hmM!pqSrfAn3$N&z>T?pycBIxTMYz~LYQc?5hr3c12cnd z-WbqmBY`orQBBji^T|q@HyPrKID9BniQyz=b0X|H5kihJgbW6GG6i z<%{3s@lY;z7OJGRq|WMq3hYpk8XyE>R49D`3JOPyG1xzXwK%Gyjd~2YOzN>r0x?jT zFysg%8cpZYMxYp2C$L+gRH6#X#9$OoDC9C2c+DY6Eh@lx;Tj<(Wb<`G0b3Z(m9jMw zZ8)396Y+FXF|HGEv3Yqpjhk(`otM}CM|qWz1pS5O{%;;z*V&2!jVDbYUDmmtNG0;- zcDW>EuLBgrZS^gKaa&>uEj;&`{NE9nrOnSG0O{YPdlqJ*bxb~HBqB3GwEjgwA;5gZ z){C>AAb)n!e)e47&cnelux%Za2)sCE89{*oW(1RJ+Eq}*VmVz=$RpL^mk+5`p%3%? zf_#0OF8hSV)Cc(G9GVW(XqrVA4_AeUB`2m+mCauiSLKDAOiu|P`}U+y%P+^pt3to@ zOUW4${vfP|164%jo4T7=;qCU+TWLdclK=5p_Gwl&jKqdDm+W%o%P3#bv=D56-y+% zh=@JE9%*k6;D7GXneRR!-&JkZkOGcz-@32l30XHQSh-OO<>gC@GV=01o7ycpy=f^3 zVJEh|zCNt1tSm#PbNS$yFSW6N^k<(O7#{8#7^uFLbfDLD_3Gf2UR6%` z_O!Jw#plm0&(-TMPELyAetY+@=7isf!LOj8plqfs{nC-$m8(Y<7QH^GxW!y_WTpPHI#?Vm(aBs)C4PY2Z5e&33iMETLE HjO~8_d?o@Z delta 1005 zcmV;-|e*hVDMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs000AV zNkl{HM*V70q%ZcU({|<&qm0Q=}xhn3R%s zF}HJ}hU`ZEH<>^Av#*wgO~yvs`*-m?zx9*HczX1_>s*}Ef9HH&pL05=k3jMgfDHey zg3`aCAHcC#3>zC8SX)~|T3Q;atE-__tAC6v`KO@M=|oOW4#vmFA(zV$2n5jA*N4u| zPCPt3{0y07fPZLZWrfAX#q@f;JUu<-^z=06=jZwI^1`L1C012cF%Wo{LXs3kk)kMm zh<~EMJ8(E0e`ZNZ32$z0I503k0C6iSDx$~Zq0MGvcX#)Pn;IG#n4X?azu*7wz|m-w zR;!g`V`H>fEbpMdEj2ZjZnvAQt*tydI^yo`E}c#%Npfy(jsV!z)%AVw{{B7}78a<} z>FD?SsZb~gfCU8wv|6ofYHEtZ2L}hay1L4tp&{CAe>N(WN=70Pl4NspGXc=yaC{G3 zSy@TD-A=t;PnXL@0L;k9;OpxvRVo!tCKF3aN(g{TrIMjgh+3_du~>|Sg@v4&nj%S_ zpPw^1Ihj>eRbPT70B~}00;N(30Py*I0D$`XdL$(!L8(+?Z*LD~vl#$zeSMAN<6}f3 z5eR~Sf02<9jE;^X91bHpI~yjG37eanI5;>+IMkB2w>R9~-9e#HAR3J#DJcm6aC>_T z0I=Kb*xufT*XxZZNu^RqB!6vUdwV++3I%3oX8{1cy}bZ{nVFfd*Ga8bb9s50dcB@L zpN|rWgaEj{zD|<7y1HUkRu%zJ5Cr;sJ~lQsf5!VZF)=}%P8av{^71H?$rz1B6SrEc z)xvJKqrAKvhlhtS7z_Y_nwlC^S63rHKOYwt7XSc*!2plPgWTNQ_~RW82jp^j+^?vp zKrk4DD2jPhCss1xEJUmQ`#X^tALyblghpJR6x?Ct`5w^6nu&1Yop-_nT_xC(IJLB{7Gbbk}Syxxb$H&J{!Qa$JFiFN@F-}fSGBY!i zWo2bF8jZ}#%3^CtMzF_d={YB!a0SG)O`#yg_6t9mw$q=xW@fYB z?)QAp`#$gA?6#cj6=A_q!4ioiEHgu&2ktT8n)7HN_@9AayAEza_KYF{?BDQRGg6l{ zx+Ic63^Dm8(PYfRNzNuCD9%jFTsAvEOC-t5U3P*jqeaL}TNzdhd*1&5h8Ri<7pjbM zqdko-VKUr2y~>@PPrA!U4FxYxfs$P~Ah6LQ0l94Dtbn_;@B}Xo*1p#W3{619GA*q0 z8H7y694L+BX-FeeNJ+U|0VRT!QjIRtXc7|>6ChNMVu)OgpeiYf;i^Pjp@gP>FtEr| z7CcX%K4lL)Y2gx4wBrckbUI~DOvdq6M4{1W5IKsVs1zWi!Uk3(TvAqun`Y3{0?9LW zk>Oa#$4HpD3Q-FKZzpBg?0#BSm9tF z1%OrfvGx*9W8XQ2zR6u?fE#z;o(?}jIa1}gB z8yvvRIG-9jp2pLJ$np6cS3aGroN1RKR3$^9B}Rf|Sf7ZcKR80`36a*qAaAHtflB3? ze0d^{DRET&q(Xtq<&#h&M=_QSeke8pRpkQ&rpD#ikD#D%C_*HD6HJk~h2w1mkj&T! zD~;G$D-8JqiKlVp91jcw@309kj7B_@6-0t1=}f&A2C8KYL*b-Cqts9qQmQhmDXCJ8 zVN!xxW|m@Ri<(r>a)ky{PoLLwWQ8xc)90!G^Ze611Nw_7|J^*kuJaWIp1}wpT^pu) zVimo9YE{la6Lo+Sq_4iUFzHJyO~F&Incp3ONm^$K4M=|_-IFkZvxrWDr*&2kt^c8* z5a2%I>%~bW$WKL1?ERo`r{Q22_?G@j1RngejAp?A+?x@z*){?Ta^Ict0 z4*N>MmBj)|%leEe&Q_HX}PbedWrK{{H?s5fNLiUd<|AyY^wO%i)N`Ukgu9 zPjA@2|J$VQj*i@s(b4Xakp)RfNhKV&!s$$miHT{yapR@ix7U3>6uU>{c{q0crcL3| z(b03k=({vNKJIxjHa51~Mo}adWVKC3=gXxjE&VcHje3*B_}`Ta5&(n z#EOdM)}Ef8*F(J7NjTnq^XAs7s;bxZt=Fzx2?mT?ckaB@+Z+FixYz4VefQ+aOI|P5*4DP` zl~>{m&#n)?b?a89(&O=bF+7}JR`%C>Cr+N6g<;s2&sSZ)o;QD}ySw|^hbK;)FclZi zBVsmxbog)rVc#Cu+|p8*iy%l`LPA#WtiZtAcke#l8+ZJjcV0Z75V3mo>e4j@1)a|B zmfSw(x%V1!Lubzp*=Feob#C0ax{(C-XP1LPn{~NhcyO+p)>`CQ!hTYaN**Y zpD=^yhK7Y@idL&tu2x6F1GVd_i`T3vu=ot+D!qtndhgYfb7CX?x{?}CDY8usqh>2%LWRPWePP?&b?Uza=Yf8En# zI5>W8=-)3OGTE-$+C@zfQBl>El>wSBTY4yl*;Zda|IndBkA8C_a%KCISA$0dK`2d8 zsR}MW5)csPJi2dRR5Pg#*{#fdud&86IB0OYAG|sERe%3e=*3oXxgsUyC~VoISaNkA z)&G^(OD}rPd;k8?cePPl*}r`HaAsCZ!@v$>3s>X=HTZ>$sYlnq$X~L4l*OUo^L!I#qk%t1^@s6O!98o00004b3#c}2nYxWdeSaefw zW^{L9a%BK_cXuvnZfkR6VQ^(GZ*pgw?mQX*00cToL_t(YiM^FgNR(R`$N%p%Lkp=9 zK^lW01xYBgP^!s~J}gE}EX8ak?i56*Rnf8*wXj7z+}@~v(YhBd_YY@rIM4I^&hv2o90Qn<JC#tjt~7Ru}Ot{w!$_(e~iJfWbVfaAxHbM@*~E?&Gy zMMVWCPo89Paq-vi42_PCA_>DV7#bQ{EhLr!e)#YqyLRm&6bdnaJv~itZ!dT6-eq}t znSp@;%FD}%#WLqQdl)~#b|YAO@_^5skJ-MdFk zO%2g#6qn0|B(`tgPG4UihYugN;AhXC6G&pyrcHeN_Ko6y;$oVcn<*_VMG|hen?xdk z*Xt#nPP1dj4z69h2Ed08A6UPBJ>}))7UA^i(^l8Bv$Gc1CQ0w!y_4JRmLx?Y5lPa) zg9qhsIOKM__2R_~wY0QIl0JX_thaC9Dw#~mFbrL|a6y+YUDC?RiV6w})ZE;x@$qrJ zdi6?@)Y;j8X<6*%&6}2+Y^hXA3kwT!xm+?$Qx1nik~BX*FG=$I{d)TJsY0QUm1MWu zWwY5NNli^na=Bbq(Th|mi+vD%bSr%gzD;QYn)fET%o3arpDSA6&2xhIx$TX0H4oiy%C?! z_hZyvuUCG*UwiiK(d*Z*RbO8(Nvf)Bv@QrI&0|)r><;$9V;MLUH+G;i6a5zY%Qkh_YbUIB>PY;_n zZ)W%I-83{bke{DVS63HbzkdB!P=KkaDYk6cf+RXSI{{(_5Yun|<4`E1a5${8vNGB2 z_O-(PDAP2xyu7TetSlLZ5jTK{r0hRt{5e*_nCY_rBxz ze&6@rE-x>8tw&+M!cZvGqjX}l0zIEcch9a*px+X1UnP2Ub0$vnko;_L7mP33m>LUUO5!jVT;Ho?Yu|a6%mlb6_qT&#!=Y z@$AHOq@JJbn?^fx1Iax}!IasKY9Pt0I!dt%fp5EU+fL;8Q=UT+WB4$G6~%yNS^=&@ zgDkRBU=;W;f+H$11kDhX9H&HuqbtOFl( zsH|&>VY^9yR>4eyYDhX(HIC)iRw=dC2=-6}=v6xb7c|Nc-SQ?GsD21?T>Iy^Y z8q1*?kadnBI78wIRn{Rvsgz7n93u!4%*~J5T5UkLV1B0hbX!9BC56!eC4xhWG(53#Nx+ifc0oa|e| z#L^X}04Gp2x~KHo^AN`z=h+g5yG9Q3$oqtZL1Et zZ4z*R3sBpJt{1@#*G^)24r9KJ0mn(0T6#&zI!n*C#XQUKcKvvu?%^N_ye5fhqC*Dp z3djN>alA%|D$sPDW+0#uKkox6SFe<;u$02lxzhf3AZ4vQ~Wpa2M!yQNyULCtx8apM1nypLU6i96F_Hq0;s%1(X1#jy!!uHrVi8T+?LT!5#7J(J|(8;nwrxFG2fF10KEUVL^Ay9-W=qw?!oIuEo zArLw%Qw%g%iKWpFn~BDL)IBk1jcFL#96WPF=rkL==8w|oBYzl&7HUNaEbY5*&oTYlf}X%Q+vVW6 z_{{jK!Dp5nd1J^6Fa6~AuRGtPWq#_6+;a1>d+5r_tK%;o_|uU#mF+mctlNOyQ-{9| z@YP?>AAM)t?W^5?b)=&g=FDGJwu4-EqI&w;i&4Cw_w=*1Uwvvd-zu@2&s}u8@%@^5 ziW_5vuYdgFh!guZo*c5}_=UYi?=+w5vAt?U(w(r`_XGd;4`H9%)#-iJm zeHZ?=vSi!(Ke{(f*j_R8^zNyx^XyZ17ERvKYi-xRpE&qYm&5NbH-8EKB$ZAmi|!de GtMMP1?T&;1 delta 594 zcmV-Y0;-|e*hVDMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs0005m zNklqE zw$#x;=~O5*Tp=K2NrpCPNuN7hn@PCKr|)(+=i}k!J)F-1fBr}+>t~hx{)8F@XIZA} z>uXi3Re7HG^$-waSmW^+Nm!P})6>&eBe5}X7>0yl2tX7??C$O&iE6dVYPI@4@X^r` zwrvwd5de30cSu4KmzS4j!IQ~^(P#v~?d>g+Xt&#W-}5{qQ79Dfecv3o-|w@xx5xYY zI{?SW$4KJgf8hauAP6XxN=TyFY?=daHXC}q9{qkFfW>0L&dv^phllyh#l=PL`t|kI z40x*`2uRZufU~nRBr%;%0hrBZdDh)-*DQEGpL2C}1;B7PL=xxc=Xt+guOkV^arpT7 zFbBTBzo*e?bXBDtUcyaG)ef6o#QBsnu%9 zaU4m~U@$Oyxwh_JUS6;)3rRdbKj;0^(^Dkjx-OVJAX_C#!pX@AuIsW~E&+Iae8h1a zBw^e3_kh1ryWP$+E*6Wd*Xy4F`@YZq{yviEbUFaB1;qM+|2WGsrD>{CsU*v?5({{f gRQc~q7_*B10+@A)?(Tg8*#H0l07*qoM6N<$f{N=Cb^rhX diff --git a/radio/src/boards/generic_stm32/switches.cpp b/radio/src/boards/generic_stm32/switches.cpp index bf7bc3525db..8479521a7e3 100644 --- a/radio/src/boards/generic_stm32/switches.cpp +++ b/radio/src/boards/generic_stm32/switches.cpp @@ -24,7 +24,6 @@ #include "stm32_gpio_driver.h" #include "definitions.h" -#include "opentx_constants.h" #include "myeeprom.h" // generated switch structs diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index c69b8071d12..61c45ee9110 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _DATACONSTANTS_H_ -#define _DATACONSTANTS_H_ +#pragma once #include "board.h" #include "storage/yaml/yaml_defs.h" @@ -704,5 +703,3 @@ enum PPMUnit { PPM_PERCENT_PREC1, PPM_US }; - -#endif // _DATACONSTANTS_H_ diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index 6b634161fa9..2202c7fd295 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -17,87 +17,103 @@ file(GLOB WIDGETS_SRC RELATIVE ${RADIO_SRC_DIR}/gui/colorlcd set(GUI_SRC ${GUI_SRC} - colors.cpp - lcd.cpp - splash.cpp - fonts.cpp - curves.cpp + ${THEMES_SRC} + ${LAYOUTS_SRC} + ${WIDGETS_SRC} bitmaps.cpp - lz4_bitmaps.cpp - theme.cpp - theme_manager.cpp + channel_bar.cpp + channel_range.cpp color_editor.cpp - color_picker.cpp color_list.cpp - preview_window.cpp + color_picker.cpp + colors.cpp + curve.cpp file_browser.cpp file_preview.cpp - file_carosell.cpp + fonts.cpp + fullscreen_dialog.cpp + special_functions.cpp + layout.cpp + lcd.cpp + list_line_button.cpp listbox.cpp - tabsgroup.cpp + LvglWrapper.cpp + menu_model.cpp + menu_radio.cpp + menu_screen.cpp page.cpp - select_fab_button.cpp + popups.cpp + screen_setup.cpp + screen_user_interface.cpp select_fab_carousel.cpp + sourcechoice.cpp + startup_shutdown.cpp + switch_warn_dialog.cpp + switchchoice.cpp + tabsgroup.cpp + theme_manager.cpp + theme.cpp topbar.cpp - layout.cpp - widget.cpp + view_about.cpp + view_channels.cpp + view_logical_switches.cpp + view_main_decoration.cpp + view_main_menu.cpp + view_main.cpp + view_statistics.cpp + view_text.cpp widget_settings.cpp - ${THEMES_SRC} - ${LAYOUTS_SRC} - ${WIDGETS_SRC} - draw_functions.cpp - menu_model.cpp - model_select.cpp - bind_menu_d16.cpp - trainer_setup.cpp - custom_failsafe.cpp - ppm_settings.cpp - channel_range.cpp - module_setup.cpp - timer_setup.cpp - trims_setup.cpp - throttle_params.cpp - preflight_checks.cpp - model_setup.cpp + widget.cpp + widgets_setup.cpp + curve_param.cpp + curveedit.cpp + fm_matrix.cpp + gvar_numberedit.cpp + input_edit_adv.cpp + input_edit.cpp + input_mix_button.cpp + input_mix_group.cpp + input_source.cpp + mixer_edit_adv.cpp + mixer_edit.cpp + model_curves.cpp model_flightmodes.cpp + model_gvars.cpp model_inputs.cpp + model_logical_switches.cpp model_mixes.cpp model_outputs.cpp - model_curves.cpp - model_gvars.cpp - model_templates.cpp - model_logical_switches.cpp - special_functions.cpp + model_select.cpp + model_setup.cpp model_telemetry.cpp - menu_radio.cpp - radio_setup.cpp - radio_sdmanager.cpp - radio_tools.cpp - radio_trainer.cpp - radio_version.cpp - hw_intmodule.cpp + model_templates.cpp + output_edit.cpp + preflight_checks.cpp + throttle_params.cpp + timeedit.cpp + timer_setup.cpp + trainer_setup.cpp + trims_setup.cpp + bind_menu_d16.cpp + custom_failsafe.cpp hw_extmodule.cpp + hw_intmodule.cpp + module_setup.cpp + ppm_settings.cpp + file_carosell.cpp hw_inputs.cpp hw_serial.cpp - radio_hardware.cpp - radio_diagkeys.cpp + preview_window.cpp + radio_calibration.cpp radio_diaganas.cpp + radio_diagkeys.cpp + radio_hardware.cpp + radio_sdmanager.cpp + radio_setup.cpp radio_theme.cpp - radio_calibration.cpp - view_about.cpp - view_main.cpp - view_main_menu.cpp - view_main_decoration.cpp - view_channels.cpp - view_logical_switches.cpp - view_statistics.cpp - view_text.cpp - menu_screen.cpp - screen_user_interface.cpp - widgets_setup.cpp - screen_setup.cpp - switch_warn_dialog.cpp - LvglWrapper.cpp + radio_tools.cpp + radio_trainer.cpp + radio_version.cpp ) macro(add_gui_src src) @@ -124,10 +140,6 @@ if(HELI) add_gui_src(model_heli.cpp) endif() -if(PXX2 OR LUA OR MULTIMODULE) - add_gui_src(radio_tools.cpp) -endif() - if(PXX2 OR MULTIMODULE) add_gui_src(radio_spectrum_analyser.cpp) endif() @@ -193,31 +205,6 @@ set(SRC ${SRC} ${LVGL_FONT_SOURCES}) add_definitions(-DLIBOPENUI) -add_gui_src(fullscreen_dialog.cpp) -add_gui_src(message_dialog.cpp) -add_gui_src(confirm_dialog.cpp) -add_gui_src(popups.cpp) -add_gui_src(timeedit.cpp) -add_gui_src(curve.cpp) -add_gui_src(sourcechoice.cpp) -add_gui_src(switchchoice.cpp) -add_gui_src(curveedit.cpp) -add_gui_src(gvar_numberedit.cpp) -add_gui_src(curve_param.cpp) -add_gui_src(fm_matrix.cpp) -add_gui_src(input_source.cpp) -add_gui_src(input_edit.cpp) -add_gui_src(input_edit_adv.cpp) -add_gui_src(mixer_edit.cpp) -add_gui_src(mixer_edit_adv.cpp) -add_gui_src(output_edit.cpp) -add_gui_src(input_mix_group.cpp) -add_gui_src(input_mix_button.cpp) -add_gui_src(channel_bar.cpp) - -add_gui_src(list_line_button.cpp) - if(USBJ_EX) add_gui_src(model_usbjoystick.cpp) endif() - diff --git a/radio/src/gui/colorlcd/LvglWrapper.cpp b/radio/src/gui/colorlcd/LvglWrapper.cpp index 2e9c10c0758..c5819615624 100644 --- a/radio/src/gui/colorlcd/LvglWrapper.cpp +++ b/radio/src/gui/colorlcd/LvglWrapper.cpp @@ -306,32 +306,6 @@ int8_t rotaryEncoderGetAccel() { return 0; } #endif // defined(ROTARY_ENCODER_NAVIGATION) -// Return 32 bit version of color (for recolor of buttons) -uint32_t makeLvColor32(uint32_t colorFlags) -{ - auto color = COLOR_VAL(colorFlags); - return (GET_RED(color) << 16u) | (GET_GREEN(color) << 8) | GET_BLUE(color); -} - -// Create recolor version of string value -std::string makeRecolor(std::string value, uint32_t colorFlags) -{ - char s[32]; - snprintf(s, 32, "#%06" PRIx32 " %s#", makeLvColor32(colorFlags), value.c_str()); - return std::string(s); -} - -/** - * Helper function to translate a colorFlags value to a lv_color_t suitable - * for passing to an lv_obj function - * @param colorFlags a textFlags value. This value will contain the color shifted by 16 bits. - */ -lv_color_t makeLvColor(uint32_t colorFlags) -{ - auto color = COLOR_VAL(colorFlags); - return lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color)); -} - static void init_lvgl_drivers() { // Register the driver and save the created display object @@ -371,6 +345,9 @@ LvglWrapper::LvglWrapper() { init_lvgl_drivers(); + extern void lv_stb_init(); + lv_stb_init(); + // Create main window and load that screen auto window = MainWindow::instance(); window->setActiveScreen(); diff --git a/radio/src/gui/colorlcd/LvglWrapper.h b/radio/src/gui/colorlcd/LvglWrapper.h index d82c86f7f95..1babfc1195b 100644 --- a/radio/src/gui/colorlcd/LvglWrapper.h +++ b/radio/src/gui/colorlcd/LvglWrapper.h @@ -19,18 +19,13 @@ * GNU General Public License for more details. */ -#ifndef _LVGLWRAPPER_H_ -#define _LVGLWRAPPER_H_ +#pragma once #include #include "opentx_types.h" void initLvglTheme(); -uint32_t makeLvColor32(uint32_t colorFlags); -std::string makeRecolor(std::string value, uint32_t colorFlags); -lv_color_t makeLvColor(uint32_t colorFlags); - typedef std::function LvObjConstructor; class LvglWrapper @@ -57,5 +52,3 @@ class LvglWrapper // multiplication factor between 0 and 25 int8_t rotaryEncoderGetAccel(); - -#endif // _LVGLWRAPPER_H_ diff --git a/radio/src/gui/colorlcd/access_settings.cpp b/radio/src/gui/colorlcd/access_settings.cpp index f8308d2cb90..caa407b38bc 100644 --- a/radio/src/gui/colorlcd/access_settings.cpp +++ b/radio/src/gui/colorlcd/access_settings.cpp @@ -19,15 +19,60 @@ * GNU General Public License for more details. */ -#include "opentx.h" #include "access_settings.h" -#include "channel_bar.h" #include -#define SET_DIRTY() storageDirty(EE_MODEL) +#include "channel_bar.h" +#include "opentx.h" + +#define SET_DIRTY() storageDirty(EE_MODEL) + +namespace pxx2 +{ + +class BindWaitDialog : public BaseDialog +{ + public: + BindWaitDialog(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx); + + void checkEvents() override; + + void deleteLater(bool detach = true, bool trash = true) override; + + protected: + uint8_t moduleIdx; + uint8_t receiverIdx; +}; + +class RxOptions : public BaseDialog +{ + public: + RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx); + void checkEvents() override; -namespace pxx2 { + protected: + enum { + RO_Init = 0, + RO_ReadModuleInfo, + RO_ReadModuleSettings, + RO_ReadReceiverSettings, + RO_DisplaySettings, + RO_WriteSettings, + RO_WritingSettings, + }; + + uint8_t moduleIdx; + uint8_t receiverIdx; + uint8_t state = RO_Init; + + std::string statusText; + + uint8_t getRxSettingsState(); + + void update(); + void writeSettings(); +}; static void startBindWaitDialog(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx) @@ -80,7 +125,6 @@ BindRxChoiceMenu::BindRxChoiceMenu(Window* parent, uint8_t moduleIdx, bindInfo.selectedReceiverIndex = i; if (isModuleR9MAccess(moduleIdx) && modInfo.information.variant == PXX2_VARIANT_EU) { - auto& modSetup = getPXX2ModuleSetupBuffer(); if (modSetup.moduleSettings.txPower <= 14) { // with telemetry @@ -110,18 +154,6 @@ BindRxChoiceMenu::BindRxChoiceMenu(Window* parent, uint8_t moduleIdx, setCancelHandler([=]() { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; }); } -#if defined(HARDWARE_TOUCH) -bool BindRxChoiceMenu::onTouchEnd(coord_t x, coord_t y) -{ - // Note: onCancel() is not called when the menu is discarded - // by clicking outside the menu window and the onCancel - // handler is not accessible from here - moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; - deleteLater(); - return true; -} -#endif - static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; @@ -130,23 +162,18 @@ static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, BindWaitDialog::BindWaitDialog(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx) : - Dialog(parent, STR_BIND, rect_t{}), + BaseDialog(parent, STR_BIND, true), moduleIdx(moduleIdx), receiverIdx(receiverIdx) { - setCloseWhenClickOutside(true); - auto form = &content->form; - new StaticText(form, rect_t{}, STR_WAITING_FOR_RX, 0, COLOR_THEME_PRIMARY1); - - content->setWidth(LCD_W * 0.8); - content->updateSize(); + new StaticText(form, rect_t{}, STR_WAITING_FOR_RX, COLOR_THEME_PRIMARY1); setCloseHandler([=]() { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; }); } void BindWaitDialog::deleteLater(bool detach, bool trash) { - Dialog::deleteLater(detach, trash); + BaseDialog::deleteLater(detach, trash); } void BindWaitDialog::checkEvents() @@ -154,7 +181,6 @@ void BindWaitDialog::checkEvents() auto& bindInfo = getPXX2BindInformationBuffer(); if (moduleState[moduleIdx].mode == MODULE_MODE_NORMAL) { - // returned to normal after bind if (bindInfo.step > BIND_INIT) { removePXX2ReceiverIfEmpty(moduleIdx, receiverIdx); @@ -168,33 +194,32 @@ void BindWaitDialog::checkEvents() // pre-bind phase: fetching info for R9M auto& modSetup = getPXX2ModuleSetupBuffer(); - switch(bindInfo.step) { - case BIND_MODULE_TX_INFORMATION_REQUEST: - if (modSetup.moduleInformation.information.variant == PXX2_VARIANT_EU) { - // In EU mode we will need the power of the module to know if telemetry - // can be proposed - bindInfo.step = BIND_MODULE_TX_SETTINGS_REQUEST; + switch (bindInfo.step) { + case BIND_MODULE_TX_INFORMATION_REQUEST: + if (modSetup.moduleInformation.information.variant == PXX2_VARIANT_EU) { + // In EU mode we will need the power of the module to know if + // telemetry can be proposed + bindInfo.step = BIND_MODULE_TX_SETTINGS_REQUEST; #if defined(SIMU) - modSetup.moduleSettings.txPower = 14; + modSetup.moduleSettings.txPower = 14; #else - moduleState[moduleIdx].readModuleSettings(&modSetup.moduleSettings); + moduleState[moduleIdx].readModuleSettings(&modSetup.moduleSettings); #endif - } else { + } else { + bindInfo.step = 0; + moduleState[moduleIdx].startBind(&bindInfo); + } + break; + case BIND_MODULE_TX_SETTINGS_REQUEST: + // We just receive the module settings (for TX power) bindInfo.step = 0; moduleState[moduleIdx].startBind(&bindInfo); - } - break; - case BIND_MODULE_TX_SETTINGS_REQUEST: - // We just receive the module settings (for TX power) - bindInfo.step = 0; - moduleState[moduleIdx].startBind(&bindInfo); - break; + break; } return; } if (bindInfo.step == BIND_INIT && bindInfo.candidateReceiversCount > 0) { - // prevent module mode being reset to NORMAL before exiting setCloseHandler(nullptr); deleteLater(); @@ -204,11 +229,11 @@ void BindWaitDialog::checkEvents() return; } - Dialog::checkEvents(); + BaseDialog::checkEvents(); } -ReceiverButton::ReceiverButton(Window* parent, rect_t rect, - uint8_t moduleIdx, uint8_t receiverIdx) : +ReceiverButton::ReceiverButton(Window* parent, rect_t rect, uint8_t moduleIdx, + uint8_t receiverIdx) : TextButton(parent, rect, STR_BIND, std::bind(&ReceiverButton::pressBind, this)), moduleIdx(moduleIdx), @@ -308,45 +333,48 @@ void ReceiverButton::checkEvents() } RegisterDialog::RegisterDialog(Window* parent, uint8_t moduleIdx) : - Dialog(parent, STR_REGISTER, rect_t{}), moduleIdx(moduleIdx) + BaseDialog(parent, STR_REGISTER, true, DIALOG_DEFAULT_WIDTH, + LV_SIZE_CONTENT), + moduleIdx(moduleIdx) { - setCloseWhenClickOutside(true); - auto form = &content->form; - FlexGridLayout grid(line_col_dsc, line_row_dsc); // Register ID - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_REG_ID, 0, COLOR_THEME_PRIMARY1); + auto line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_REG_ID, COLOR_THEME_PRIMARY1); reg_id = new ModelTextEdit(line, rect_t{}, g_model.modelRegistrationID, sizeof(g_model.modelRegistrationID)); // UID - line = form->newLine(&grid); - new StaticText(line, rect_t{}, "UID", 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, "UID", COLOR_THEME_PRIMARY1); auto* modSetup = &(getPXX2ModuleSetupBuffer()); - uid = new NumberEdit(line, rect_t{}, 0, 2, GET_SET_DEFAULT(modSetup->registerLoopIndex)); + uid = new NumberEdit(line, rect_t{}, 0, 2, + GET_SET_DEFAULT(modSetup->registerLoopIndex)); // RX name - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_RX_NAME, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_RX_NAME, COLOR_THEME_PRIMARY1); - start(); // clears registration data buffer - rx_name = new ModelTextEdit(line, rect_t{}, modSetup->registerRxName, PXX2_LEN_RX_NAME); - //lv_textarea_set_text(rx_name->getLvObj(), STR_WAITING_FOR_RX); - lv_obj_add_state(rx_name->getLvObj(), LV_STATE_DISABLED); + start(); // clears registration data buffer + rx_name = new ModelTextEdit(line, rect_t{}, modSetup->registerRxName, + PXX2_LEN_RX_NAME); + // lv_textarea_set_text(rx_name->getLvObj(), STR_WAITING_FOR_RX); + rx_name->disable(); // Status - // line = form->newLine(&grid); - // new StaticText(line, rect_t{}, STR_STATUS, 0, COLOR_THEME_PRIMARY1); - // status = new StaticText(line, rect_t{}, STR_WAITING_FOR_RX, 0, COLOR_THEME_PRIMARY1); - - auto box = new FormWindow(form, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8)); - lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0); - box->padAll(lv_dpx(8)); - + // line = form->newLine(grid); + // new StaticText(line, rect_t{}, STR_STATUS, COLOR_THEME_PRIMARY1); + // status = new StaticText(line, rect_t{}, STR_WAITING_FOR_RX, + // COLOR_THEME_PRIMARY1); + + auto box = new Window(form, rect_t{}); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_MEDIUM); + lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, + 0); + box->padAll(PAD_MEDIUM); + new TextButton(box, rect_t{}, STR_CANCEL, [=]() -> int8_t { this->deleteLater(); return 0; @@ -356,20 +384,17 @@ RegisterDialog::RegisterDialog(Window* parent, uint8_t moduleIdx) : modSetup->registerStep = REGISTER_RX_NAME_SELECTED; return 0; }); - lv_obj_add_flag(btn_ok->getLvObj(), LV_OBJ_FLAG_HIDDEN); - - content->setWidth(LCD_W * 0.8); - content->updateSize(); + btn_ok->hide(); setCloseHandler([=]() { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; }); } void RegisterDialog::start() { - auto& pxx2Setup = getPXX2ModuleSetupBuffer(); - memclear(&pxx2Setup, sizeof(pxx2Setup)); - moduleState[moduleIdx].mode = MODULE_MODE_REGISTER; - old_registerStep = REGISTER_INIT; + auto& pxx2Setup = getPXX2ModuleSetupBuffer(); + memclear(&pxx2Setup, sizeof(pxx2Setup)); + moduleState[moduleIdx].mode = MODULE_MODE_REGISTER; + old_registerStep = REGISTER_INIT; } void RegisterDialog::checkEvents() @@ -385,14 +410,14 @@ void RegisterDialog::checkEvents() moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; } #endif - + if (old_registerStep != modSetup.registerStep) { old_registerStep = modSetup.registerStep; if (modSetup.registerStep == REGISTER_RX_NAME_RECEIVED) { - lv_obj_clear_state(rx_name->getLvObj(), LV_STATE_DISABLED); - lv_obj_clear_flag(btn_ok->getLvObj(), LV_OBJ_FLAG_HIDDEN); - // lv_obj_add_flag(status->getLvObj(), LV_OBJ_FLAG_HIDDEN); + rx_name->enable(); + btn_ok->show(); + // status->hide(); rx_name->update(); } else if (modSetup.registerStep == REGISTER_OK) { deleteLater(); @@ -403,20 +428,14 @@ void RegisterDialog::checkEvents() } } - Dialog::checkEvents(); + BaseDialog::checkEvents(); } -ModuleOptions::ModuleOptions(Window* parent, uint8_t moduleIdx): - Dialog(parent, STR_MODULE_OPTIONS, rect_t{}), - moduleIdx(moduleIdx) +ModuleOptions::ModuleOptions(Window* parent, uint8_t moduleIdx) : + BaseDialog(parent, STR_MODULE_OPTIONS, true), moduleIdx(moduleIdx) { - setCloseWhenClickOutside(true); - auto form = &content->form; new StaticText(form, rect_t{}, STR_WAITING_FOR_MODULE, COLOR_THEME_PRIMARY1); - content->setWidth(LCD_W * 0.8); - content->updateSize(); - #if defined(SIMU) auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); memclear(&hwSettings, sizeof(hwSettings)); @@ -460,7 +479,7 @@ void ModuleOptions::checkEvents() state = MO_WritingSettings; break; - case MO_WritingSettings: + case MO_WritingSettings: #if defined(SIMU) statusText.clear(); deleteLater(); @@ -473,11 +492,11 @@ void ModuleOptions::checkEvents() #endif break; - default: // MO_DisplaySettings + default: // MO_DisplaySettings break; } - Dialog::checkEvents(); + BaseDialog::checkEvents(); } uint8_t ModuleOptions::getModuleSettingsState() @@ -488,7 +507,6 @@ uint8_t ModuleOptions::getModuleSettingsState() void ModuleOptions::update() { - auto form = &content->form; form->clear(); auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); @@ -501,43 +519,42 @@ void ModuleOptions::update() hwSettings.modules[moduleIdx].information.variant = PXX2_VARIANT_FCC; } #endif - + uint8_t optionsAvailable = getPXX2ModuleOptions(modelId) & ((1 << MODULE_OPTION_EXTERNAL_ANTENNA) | (1 << MODULE_OPTION_POWER)); - FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); + FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); - auto line = form->newLine(&grid); + auto line = form->newLine(grid); new StaticText(line, rect_t{}, STR_MODULE); new StaticText(line, rect_t{}, getPXX2ModuleName(modelId)); if (!optionsAvailable) { // no options available - line = form->newLine(&grid); + line = form->newLine(grid); new StaticText(line, rect_t{}, STR_NO_TX_OPTIONS, 0); } else { // some options available if (optionsAvailable & (1 << MODULE_OPTION_EXTERNAL_ANTENNA)) { - - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_EXT_ANTENNA, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, - []() { - const auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); - return hwSettings.moduleSettings.externalAntenna; - }, - [&](uint8_t val) { - auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); - hwSettings.moduleSettings.externalAntenna = val; - }); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_EXT_ANTENNA, COLOR_THEME_PRIMARY1); + new ToggleSwitch( + line, rect_t{}, + []() { + const auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + return hwSettings.moduleSettings.externalAntenna; + }, + [&](uint8_t val) { + auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + hwSettings.moduleSettings.externalAntenna = val; + }); } if (optionsAvailable & (1 << MODULE_OPTION_POWER)) { - // TODO: use isTelemetryAvailable() to check if rebind is necessary - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_POWER, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_POWER, COLOR_THEME_PRIMARY1); auto txPower = new Choice( line, rect_t{}, 0, 30, []() { @@ -547,7 +564,7 @@ void ModuleOptions::update() [&](int val) { auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); hwSettings.moduleSettings.txPower = val; - //state = MO_WriteSettings; + // state = MO_WriteSettings; }); txPower->setTextHandler([](int val) { @@ -571,20 +588,22 @@ void ModuleOptions::update() txPower->setAvailableHandler([=](int val) { const auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); - return isPXX2PowerAvailable(hwSettings.modules[moduleIdx].information, val); + return isPXX2PowerAvailable(hwSettings.modules[moduleIdx].information, + val); }); } } - line = form->newLine(&grid); + line = form->newLine(grid); new DynamicText(line, rect_t{}, [=]() { return statusText; }); - line = form->newLine(&grid); + line = form->newLine(grid); - auto box = new FormWindow(form, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8)); - lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0); - box->padAll(lv_dpx(8)); + auto box = new Window(form, rect_t{}); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_MEDIUM); + lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, + 0); + box->padAll(PAD_MEDIUM); new TextButton(box, rect_t{}, STR_CANCEL, [=]() -> int8_t { this->deleteLater(); @@ -595,8 +614,6 @@ void ModuleOptions::update() this->writeSettings(); return 0; }); - - content->updateSize(); } void ModuleOptions::writeSettings() @@ -607,17 +624,12 @@ void ModuleOptions::writeSettings() } } -RxOptions::RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx): - Dialog(parent, STR_RECEIVER_OPTIONS, rect_t{}), - moduleIdx(moduleIdx), - receiverIdx(rxIdx) +RxOptions::RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx) : + BaseDialog(parent, STR_RECEIVER_OPTIONS, true), + moduleIdx(moduleIdx), + receiverIdx(rxIdx) { - setCloseWhenClickOutside(true); - auto form = &content->form; - new StaticText(form, rect_t{}, STR_WAITING_FOR_RX, 0, COLOR_THEME_PRIMARY1); - - content->setWidth(LCD_W * 0.8); - content->updateSize(); + new StaticText(form, rect_t{}, STR_WAITING_FOR_RX, COLOR_THEME_PRIMARY1); #if defined(SIMU) auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); @@ -626,10 +638,11 @@ RxOptions::RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx): hwSettings.receiverSettings.state = PXX2_SETTINGS_OK; moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; state = RO_ReadReceiverSettings; - auto& rxInfo = hwSettings.modules[moduleIdx].receivers[receiverIdx].information; + auto& rxInfo = + hwSettings.modules[moduleIdx].receivers[receiverIdx].information; rxInfo.capabilities = 0xFFFFFFFF; hwSettings.receiverSettings.outputsCount = 6; - for (int i=0; i<6; i++) { + for (int i = 0; i < 6; i++) { hwSettings.receiverSettings.outputsMapping[i] = i; } #endif @@ -661,7 +674,8 @@ void RxOptions::checkEvents() moduleState[moduleIdx].readModuleSettings(&hwSettings.moduleSettings); state = RO_ReadModuleSettings; } else { - moduleState[moduleIdx].readReceiverSettings(&hwSettings.receiverSettings); + moduleState[moduleIdx].readReceiverSettings( + &hwSettings.receiverSettings); state = RO_ReadReceiverSettings; } } @@ -670,7 +684,8 @@ void RxOptions::checkEvents() // this one does NOT timeout (see pxx2.cpp) if (moduleState[moduleIdx].mode == MODULE_MODE_NORMAL && hwSettings.moduleSettings.state == PXX2_SETTINGS_OK) { - moduleState[moduleIdx].readReceiverSettings(&hwSettings.receiverSettings); + moduleState[moduleIdx].readReceiverSettings( + &hwSettings.receiverSettings); state = RO_ReadReceiverSettings; } break; @@ -683,7 +698,8 @@ void RxOptions::checkEvents() break; case RO_WriteSettings: // TODO: ask for confirmation ??? - moduleState[moduleIdx].writeReceiverSettings(&hwSettings.receiverSettings); + moduleState[moduleIdx].writeReceiverSettings( + &hwSettings.receiverSettings); state = RO_WritingSettings; break; @@ -700,11 +716,11 @@ void RxOptions::checkEvents() #endif break; - default: // RO_DisplaySettings + default: // RO_DisplaySettings break; } - Dialog::checkEvents(); + BaseDialog::checkEvents(); } static uint8_t getShiftedChannel(int8_t moduleIdx, int ch) @@ -731,7 +747,7 @@ class OutputMappingChoice : public Choice auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); hwSettings.receiverSettings.outputsMapping[rx_pin] = val; } - + std::string getChannelText(int val) { if (val < channels) { @@ -743,34 +759,39 @@ class OutputMappingChoice : public Choice void addMenuItem(int item, Menu* menu, int val, int& selectedIx) { menu->addLineBuffered(textHandler(item), [=]() { setValue(item); }); - if (item == val) { selectedIx = menu->count() - 1; } + if (item == val) { + selectedIx = menu->count() - 1; + } } public: - OutputMappingChoice(Window* parent, uint32_t capabilities, uint8_t rx_model_id, - uint8_t module, uint8_t channels, uint8_t output_pin) : + OutputMappingChoice(Window* parent, uint32_t capabilities, + uint8_t rx_model_id, uint8_t module, uint8_t channels, + uint8_t output_pin) : Choice(parent, rect_t{}, 0, channels - 1, std::bind(&OutputMappingChoice::getOutputMapping, this), std::bind(&OutputMappingChoice::setOutputMapping, this, - std::placeholders::_1), 0), + std::placeholders::_1), + 0), capabilities(capabilities), ch_offset(getShiftedChannel(module, 0)), channels(channels), rx_pin(output_pin) { - if (isPXX2ReceiverOptionAvailable(rx_model_id, RECEIVER_OPTION_D_TELE_PORT)) { - setTextHandler([=] (int val) { - switch(val) { - case CH_MAP_SBUS_IN: - return std::string(STR_SBUSIN); - case CH_MAP_SBUS_OUT: - return std::string(STR_SBUSOUT); - case CH_MAP_SPORT: - return std::string(STR_SPORT); - case CH_MAP_FBUS: - return std::string(STR_FBUS); - default: - return getChannelText(val); + if (isPXX2ReceiverOptionAvailable(rx_model_id, + RECEIVER_OPTION_D_TELE_PORT)) { + setTextHandler([=](int val) { + switch (val) { + case CH_MAP_SBUS_IN: + return std::string(STR_SBUSIN); + case CH_MAP_SBUS_OUT: + return std::string(STR_SBUSOUT); + case CH_MAP_SPORT: + return std::string(STR_SPORT); + case CH_MAP_FBUS: + return std::string(STR_FBUS); + default: + return getChannelText(val); } }); setFillMenuHandler([=](Menu* menu, int val, int& selectedIx) { @@ -783,17 +804,17 @@ class OutputMappingChoice : public Choice }); return; } - + if (capabilities & (1 << RECEIVER_CAPABILITY_ENABLE_PWM_CH5_CH6)) { if (CH_ENABLE_SPORT == output_pin) { - setTextHandler([=] (int val) { + setTextHandler([=](int val) { if (val == channels) return std::string(STR_SPORT); return getChannelText(val); }); setMax(channels); return; } else if (CH_ENABLE_SBUS == output_pin) { - setTextHandler([=] (int val) { + setTextHandler([=](int val) { if (val == channels) return std::string(STR_SBUSOUT); return getChannelText(val); }); @@ -809,25 +830,24 @@ class OutputMappingChoice : public Choice void RxOptions::update() { - auto form = &content->form; - form->clear(); - auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); - auto& rxInfo = hwSettings.modules[moduleIdx].receivers[receiverIdx].information; + auto& rxInfo = + hwSettings.modules[moduleIdx].receivers[receiverIdx].information; uint8_t rxModelId = rxInfo.modelID; uint8_t rxVariant = rxInfo.variant; uint8_t capabilities = rxInfo.capabilities; - FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); + FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); - auto line = form->newLine(&grid); + auto line = form->newLine(grid); new StaticText(line, rect_t{}, STR_RECEIVER); new StaticText(line, rect_t{}, g_model.moduleData[moduleIdx].pxx2.receiverName[receiverIdx]); // PWM rate - line = form->newLine(&grid); - new StaticText(line, rect_t{}, isModuleR9MAccess(moduleIdx) ? "6.67ms PWM" : "7ms PWM"); + line = form->newLine(grid); + new StaticText(line, rect_t{}, + isModuleR9MAccess(moduleIdx) ? "6.67ms PWM" : "7ms PWM"); new ToggleSwitch( line, rect_t{}, []() { @@ -840,18 +860,18 @@ void RxOptions::update() }); // telemetry disabled - line = form->newLine(&grid); + line = form->newLine(grid); new StaticText(line, rect_t{}, STR_TELEMETRY_DISABLED); auto tele25mw = new ToggleSwitch( - line, rect_t{}, - []() { - auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); - return hwSettings.receiverSettings.telemetryDisabled; - }, - [](int val) { - auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); - hwSettings.receiverSettings.telemetryDisabled = val; - }); + line, rect_t{}, + []() { + auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + return hwSettings.receiverSettings.telemetryDisabled; + }, + [](int val) { + auto& hwSettings = getPXX2HardwareAndSettingsBuffer(); + hwSettings.receiverSettings.telemetryDisabled = val; + }); if (isModuleR9MAccess(moduleIdx) && rxVariant == PXX2_VARIANT_EU && hwSettings.moduleSettings.txPower > 14 /*25mW*/) { @@ -861,7 +881,7 @@ void RxOptions::update() if (capabilities & (1 << RECEIVER_CAPABILITY_TELEMETRY_25MW)) { // telemetry 25 mW - line = form->newLine(&grid); + line = form->newLine(grid); new StaticText(line, rect_t{}, "25mw Tele"); new ToggleSwitch( line, rect_t{}, @@ -877,9 +897,8 @@ void RxOptions::update() if (capabilities & ((1 << RECEIVER_CAPABILITY_FPORT) | (1 << RECEIVER_CAPABILITY_FPORT2))) { - // SPORT modes - line = form->newLine(&grid); + line = form->newLine(grid); new StaticText(line, rect_t{}, STR_PROTOCOL); auto sportModes = new Choice( line, rect_t{}, STR_SPORT_MODES, 0, 2, @@ -907,7 +926,7 @@ void RxOptions::update() } if (capabilities & (1 << RECEIVER_CAPABILITY_SBUS24)) { - line = form->newLine(&grid); + line = form->newLine(grid); new StaticText(line, rect_t{}, STR_SBUS24); new ToggleSwitch( line, rect_t{}, @@ -921,23 +940,26 @@ void RxOptions::update() }); } - auto outputsCount = min(16, hwSettings.receiverSettings.outputsCount); + auto outputsCount = + min(16, hwSettings.receiverSettings.outputsCount); for (uint8_t i = 0; i < outputsCount; i++) { - line = form->newLine(&grid); - std::string i_str = std::to_string(i+1); + line = form->newLine(grid); + std::string i_str = std::to_string(i + 1); new StaticText(line, rect_t{}, std::string(STR_PIN) + i_str); uint8_t channels = sentModuleChannels(moduleIdx); - new OutputMappingChoice(line, capabilities, rxModelId, moduleIdx, channels, i); + new OutputMappingChoice(line, capabilities, rxModelId, moduleIdx, channels, + i); } - line = form->newLine(&grid); + line = form->newLine(grid); new DynamicText(line, rect_t{}, [=]() { return statusText; }); - auto box = new FormWindow(form, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8)); - lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0); - box->padAll(lv_dpx(8)); + auto box = new Window(form, rect_t{}); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_MEDIUM); + lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, + 0); + box->padAll(PAD_MEDIUM); new TextButton(box, rect_t{}, STR_CANCEL, [=]() -> int8_t { this->deleteLater(); @@ -948,8 +970,6 @@ void RxOptions::update() this->writeSettings(); return 0; }); - - content->updateSize(); } void RxOptions::writeSettings() @@ -960,4 +980,4 @@ void RxOptions::writeSettings() } } -}; +}; // namespace pxx2 diff --git a/radio/src/gui/colorlcd/access_settings.h b/radio/src/gui/colorlcd/access_settings.h index 2717ddc22f4..cf10e514d7d 100644 --- a/radio/src/gui/colorlcd/access_settings.h +++ b/radio/src/gui/colorlcd/access_settings.h @@ -38,23 +38,6 @@ class BindRxChoiceMenu : public Menu protected: uint8_t moduleIdx; uint8_t receiverIdx; - -#if defined(HARDWARE_TOUCH) - bool onTouchEnd(coord_t x, coord_t y) override; -#endif -}; - -class BindWaitDialog : public Dialog -{ - public: - BindWaitDialog(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx); - void checkEvents() override; - - void deleteLater(bool detach = true, bool trash = true) override; - - protected: - uint8_t moduleIdx; - uint8_t receiverIdx; }; class ReceiverButton : public TextButton @@ -72,7 +55,7 @@ class ReceiverButton : public TextButton uint8_t receiverIdx; }; -class RegisterDialog : public Dialog +class RegisterDialog : public BaseDialog { public: RegisterDialog(Window* parent, uint8_t moduleIdx); @@ -90,7 +73,7 @@ class RegisterDialog : public Dialog Window* btn_ok = nullptr; }; -class ModuleOptions : public Dialog +class ModuleOptions : public BaseDialog { public: ModuleOptions(Window* parent, uint8_t moduleIdx); @@ -118,34 +101,4 @@ class ModuleOptions : public Dialog void writeSettings(); }; -class RxOptions : public Dialog -{ - public: - RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx); - void checkEvents() override; - - protected: - - enum { - RO_Init=0, - RO_ReadModuleInfo, - RO_ReadModuleSettings, - RO_ReadReceiverSettings, - RO_DisplaySettings, - RO_WriteSettings, - RO_WritingSettings, - }; - - uint8_t moduleIdx; - uint8_t receiverIdx; - uint8_t state = RO_Init; - - std::string statusText; - - uint8_t getRxSettingsState(); - - void update(); - void writeSettings(); -}; - }; diff --git a/radio/src/gui/colorlcd/afhds2a_settings.cpp b/radio/src/gui/colorlcd/afhds2a_settings.cpp index 7b926d9c430..65caac7473e 100644 --- a/radio/src/gui/colorlcd/afhds2a_settings.cpp +++ b/radio/src/gui/colorlcd/afhds2a_settings.cpp @@ -26,7 +26,7 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -class FSProtoOpts : public FormWindow +class FSProtoOpts : public Window { std::function _getMode; std::function _setMode; @@ -38,7 +38,7 @@ class FSProtoOpts : public FormWindow FSProtoOpts::FSProtoOpts(Window* parent, std::function getMode, std::function setMode) : - FormWindow(parent, rect_t{}), + Window(parent, rect_t{}), _getMode(std::move(getMode)), _setMode(std::move(setMode)) { @@ -65,18 +65,18 @@ FSProtoOpts::FSProtoOpts(Window* parent, std::function getMode, AFHDS2ASettings::AFHDS2ASettings(Window* parent, const FlexGridLayout& g, uint8_t moduleIdx) : - FormWindow(parent, rect_t{}), + Window(parent, rect_t{}), moduleIdx(moduleIdx), md(&g_model.moduleData[moduleIdx]), grid(g) { setFlexLayout(); - FormWindow::Line* line; + FormLine* line; // RX options: - line = newLine(&grid); - afhds2OptionsLabel = new StaticText(line, rect_t{}, STR_OPTIONS, 0, COLOR_THEME_PRIMARY1); + line = newLine(grid); + afhds2OptionsLabel = new StaticText(line, rect_t{}, STR_OPTIONS, COLOR_THEME_PRIMARY1); afhds2ProtoOpts = new FSProtoOpts( line, [=]() { return md->flysky.mode; }, @@ -84,7 +84,7 @@ AFHDS2ASettings::AFHDS2ASettings(Window* parent, const FlexGridLayout& g, #if defined(PCBNV14) if (getNV14RfFwVersion() >= 0x1000E) { - line = newLine(&grid); + line = newLine(grid); static const char* _rf_power[] = {"Default", "High"}; afhds2RFPowerText = new StaticText(line, rect_t{}, STR_MULTI_RFPOWER); afhds2RFPowerChoice = new Choice(line, rect_t{}, _rf_power, 0, 1, @@ -101,33 +101,33 @@ AFHDS2ASettings::AFHDS2ASettings(Window* parent, const FlexGridLayout& g, void AFHDS2ASettings::hideAFHDS2Options() { - lv_obj_add_flag(afhds2OptionsLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(afhds2ProtoOpts->getLvObj(), LV_OBJ_FLAG_HIDDEN); + afhds2OptionsLabel->hide(); + afhds2ProtoOpts->hide(); #if defined(PCBNV14) if (afhds2RFPowerText != nullptr) - lv_obj_add_flag(afhds2RFPowerText->getLvObj(), LV_OBJ_FLAG_HIDDEN); + afhds2RFPowerText->hide(); if (afhds2RFPowerChoice != nullptr) - lv_obj_add_flag(afhds2RFPowerChoice->getLvObj(), LV_OBJ_FLAG_HIDDEN); + afhds2RFPowerChoice->hide(); #endif } void AFHDS2ASettings::showAFHDS2Options() { - lv_obj_clear_flag(afhds2OptionsLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(afhds2ProtoOpts->getLvObj(), LV_OBJ_FLAG_HIDDEN); + afhds2OptionsLabel->show(); + afhds2ProtoOpts->show(); #if defined(PCBNV14) if (afhds2RFPowerText != nullptr) - lv_obj_clear_flag(afhds2RFPowerText->getLvObj(), LV_OBJ_FLAG_HIDDEN); + afhds2RFPowerText->show(); if (afhds2RFPowerChoice != nullptr) { - lv_obj_clear_flag(afhds2RFPowerChoice->getLvObj(), LV_OBJ_FLAG_HIDDEN); + afhds2RFPowerChoice->show(); lv_event_send(afhds2RFPowerChoice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } #endif } void AFHDS2ASettings::checkEvents() { - FormWindow::checkEvents(); + Window::checkEvents(); } void AFHDS2ASettings::update() diff --git a/radio/src/gui/colorlcd/afhds2a_settings.h b/radio/src/gui/colorlcd/afhds2a_settings.h index 4c278d7f131..69488b44547 100644 --- a/radio/src/gui/colorlcd/afhds2a_settings.h +++ b/radio/src/gui/colorlcd/afhds2a_settings.h @@ -27,7 +27,7 @@ struct ModuleData; -class AFHDS2ASettings : public FormWindow, public ModuleOptions +class AFHDS2ASettings : public Window, public ModuleOptions { uint8_t moduleIdx; ModuleData* md; diff --git a/radio/src/gui/colorlcd/afhds3_options.cpp b/radio/src/gui/colorlcd/afhds3_options.cpp index 9a749e340e8..8fa2b52f8d0 100644 --- a/radio/src/gui/colorlcd/afhds3_options.cpp +++ b/radio/src/gui/colorlcd/afhds3_options.cpp @@ -73,10 +73,9 @@ static void pwmfreq_changedV0(lv_event_t* e) } } PWMfrequencyChoice::PWMfrequencyChoice(Window* parent, uint8_t moduleIdx, uint8_t channelIdx) : - FormWindow(parent, rect_t{}) + Window(parent, rect_t{}) { - setFlexLayout(LV_FLEX_FLOW_ROW); - lv_obj_set_width(lvobj, LV_SIZE_CONTENT); + setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY, LV_SIZE_CONTENT); uint16_t &pwmvalue_type = _v1_pwmvalue_type[moduleIdx][channelIdx]; auto cfg = afhds3::getConfig(moduleIdx); auto vCfg = &cfg->v1; @@ -110,10 +109,9 @@ PWMfrequencyChoice::PWMfrequencyChoice(Window* parent, uint8_t moduleIdx, uint8_ } PWMfrequencyChoice::PWMfrequencyChoice(Window* parent, uint8_t moduleIdx ) : - FormWindow(parent, rect_t{}) + Window(parent, rect_t{}) { - setFlexLayout(LV_FLEX_FLOW_ROW); - lv_obj_set_width(lvobj, LV_SIZE_CONTENT); + setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY, LV_SIZE_CONTENT); uint16_t &pwmvalue_type = _v1_pwmvalue_type[moduleIdx][0]; auto cfg = afhds3::getConfig(moduleIdx); auto vCfg = &cfg->v0; @@ -161,21 +159,19 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) title += ")"; header.setTitle2(title); - auto form = new FormWindow(&body, rect_t{}); - form->setFlexLayout(); - form->padAll(lv_dpx(8)); + body.setFlexLayout(); - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); if (cfg->version == 0) { auto vCfg = &cfg->v0; - auto line = form->newLine(&grid); + auto line = body.newLine(grid); std::string temp_str = "PWM"; temp_str += TR_POWERMETER_FREQ; new StaticText(line, rect_t{}, temp_str); new PWMfrequencyChoice(line, moduleIdx); - line = form->newLine(&grid); + line = body.newLine(grid); temp_str = "PWM"; temp_str += " "; @@ -183,7 +179,7 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) new StaticText(line, rect_t{}, temp_str); new ToggleSwitch(line, rect_t{}, GET_SET_AND_SYNC(cfg, vCfg->PWMFrequency.Synchronized, afhds3::DirtyConfig::DC_RX_CMD_FREQUENCY_V0)); - line = form->newLine(&grid); + line = body.newLine(grid); temp_str = STR_CH; temp_str += " 1"; @@ -192,7 +188,7 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) afhds3::SES_ANALOG_OUTPUT_PWM, afhds3::SES_ANALOG_OUTPUT_PPM, GET_SET_AND_SYNC(cfg, vCfg->AnalogOutput, afhds3::DirtyConfig::DC_RX_CMD_OUT_PWM_PPM_MODE)); - line = form->newLine(&grid); + line = body.newLine(grid); new StaticText(line, rect_t{}, STR_SERIAL_BUS); new Choice(line, rect_t{}, _bus_types, 0, 2, GET_SET_AND_SYNC(cfg, cfg->others.ExternalBusType, afhds3::DirtyConfig::DC_RX_CMD_BUS_TYPE_V0)); @@ -201,10 +197,10 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) for (uint8_t i = 0; i < channel_num[vCfg->PhyMode]; i++) { std::string temp_str = STR_CH; temp_str += " " + std::to_string(i+1); - auto line = form->newLine(&grid); + auto line = body.newLine(grid); new StaticText(line, rect_t{}, temp_str); new PWMfrequencyChoice(line, moduleIdx, i); - line = form->newLine(&grid); + line = body.newLine(grid); temp_str = "PWM"; temp_str += " "; @@ -220,7 +216,7 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) } for (uint8_t i = 0; i < SES_NPT_NB_MAX_PORTS; i++) { - auto line = form->newLine(&grid); + auto line = body.newLine(grid); std::string portName = "NP"; portName += 'A' + i; new StaticText(line, rect_t{}, portName.c_str()); @@ -249,7 +245,7 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) }); } } - auto line = form->newLine(&grid); + auto line = body.newLine(grid); new StaticText(line, rect_t{}, STR_SIGNAL_OUTPUT); std::vector signed_strength_ch; signed_strength_ch.emplace_back(STR_OFF); diff --git a/radio/src/gui/colorlcd/afhds3_options.h b/radio/src/gui/colorlcd/afhds3_options.h index 0e2c83f7c15..b182ce2bed4 100644 --- a/radio/src/gui/colorlcd/afhds3_options.h +++ b/radio/src/gui/colorlcd/afhds3_options.h @@ -24,7 +24,7 @@ #include "page.h" #include "pulses/afhds3_config.h" -struct PWMfrequencyChoice : public FormWindow { +struct PWMfrequencyChoice : public Window { PWMfrequencyChoice(Window* parent, uint8_t moduleIdx, uint8_t channelIdx); PWMfrequencyChoice(Window* parent, uint8_t moduleIdx); void update() const; diff --git a/radio/src/gui/colorlcd/afhds3_settings.cpp b/radio/src/gui/colorlcd/afhds3_settings.cpp index 265c721cd43..36c3e93a2a2 100644 --- a/radio/src/gui/colorlcd/afhds3_settings.cpp +++ b/radio/src/gui/colorlcd/afhds3_settings.cpp @@ -20,80 +20,85 @@ */ #include "afhds3_settings.h" + #include "afhds3_options.h" #include "opentx.h" -static const char* const _afhds3_region[] = { "CE", "FCC" }; +static const char* const _afhds3_region[] = {"CE", "FCC"}; static const char* const _afhds3_phy_mode[] = { - // V0 - "Classic 18ch", - "C-Fast 10ch", - // V1 - "Routine 18ch", - "Fast 8ch", - "Lora 12ch", + // V0 + "Classic 18ch", + "C-Fast 10ch", + // V1 + "Routine 18ch", + "Fast 8ch", + "Lora 12ch", }; -#include "pulses/flysky.h" #include "pulses/afhds3.h" #include "pulses/afhds3_config.h" +#include "pulses/flysky.h" #define SET_DIRTY() storageDirty(EE_MODEL) AFHDS3Settings::AFHDS3Settings(Window* parent, const FlexGridLayout& g, uint8_t moduleIdx) : - FormWindow(parent, rect_t{}), + Window(parent, rect_t{}), moduleIdx(moduleIdx), md(&g_model.moduleData[moduleIdx]), grid(g) { setFlexLayout(); - FormWindow::Line* line; + FormLine* line; // Status - line = newLine(&grid); - afhds3StatusLabel = new StaticText(line, rect_t{}, STR_MODULE_STATUS, 0, COLOR_THEME_PRIMARY1); + line = newLine(grid); + afhds3StatusLabel = new StaticText(line, rect_t{}, STR_MODULE_STATUS, + COLOR_THEME_PRIMARY1); afhds3StatusText = new DynamicText(line, rect_t{}, [=] { - char msg[64] = ""; - getModuleStatusString(moduleIdx, msg); - return std::string(msg); - }); + char msg[64] = ""; + getModuleStatusString(moduleIdx, msg); + return std::string(msg); + }); // TYPE - line = newLine(&grid); - afhds3TypeLabel = new StaticText(line, rect_t{}, STR_TYPE, 0, COLOR_THEME_PRIMARY1); + line = newLine(grid); + afhds3TypeLabel = + new StaticText(line, rect_t{}, STR_TYPE, COLOR_THEME_PRIMARY1); - afhds3TypeForm = new FormWindow(line, rect_t{}); + afhds3TypeForm = new Window(line, rect_t{}); afhds3TypeForm->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP); - lv_obj_set_style_grid_cell_x_align(afhds3TypeForm->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); + lv_obj_set_style_grid_cell_x_align(afhds3TypeForm->getLvObj(), + LV_GRID_ALIGN_STRETCH, 0); - afhds3PhyMode = new Choice(afhds3TypeForm, rect_t{}, _afhds3_phy_mode, 0, afhds3::PHYMODE_MAX, - GET_SET_DEFAULT(md->afhds3.phyMode)); - lv_obj_set_style_bg_color(afhds3PhyMode->getLvObj(), makeLvColor(COLOR_THEME_DISABLED), LV_PART_MAIN | LV_STATE_DISABLED); + afhds3PhyMode = + new Choice(afhds3TypeForm, rect_t{}, _afhds3_phy_mode, 0, + afhds3::PHYMODE_MAX, GET_SET_DEFAULT(md->afhds3.phyMode)); - afhds3Emi = new Choice(afhds3TypeForm, rect_t{}, _afhds3_region, - afhds3::LNK_ES_CE, afhds3::LNK_ES_FCC, - GET_SET_DEFAULT(md->afhds3.emi)); - lv_obj_set_style_bg_color(afhds3Emi->getLvObj(), makeLvColor(COLOR_THEME_DISABLED), LV_PART_MAIN | LV_STATE_DISABLED); + afhds3Emi = + new Choice(afhds3TypeForm, rect_t{}, _afhds3_region, afhds3::LNK_ES_CE, + afhds3::LNK_ES_FCC, GET_SET_DEFAULT(md->afhds3.emi)); - new TextButton(afhds3TypeForm, rect_t{}, STR_MODULE_OPTIONS, - [=]() { - afhds3::applyModelConfig(moduleIdx); - new AFHDS3_Options(moduleIdx); - return 0; - }); + new TextButton(afhds3TypeForm, rect_t{}, STR_MODULE_OPTIONS, [=]() { + afhds3::applyModelConfig(moduleIdx); + new AFHDS3_Options(moduleIdx); + return 0; + }); if (moduleIdx == EXTERNAL_MODULE) { - line = newLine(&grid); + line = newLine(grid); auto cfg = afhds3::getConfig(moduleIdx); new StaticText(line, rect_t{}, STR_MULTI_RFPOWER); - afhds3RfPower = new Choice(line, rect_t{}, STR_AFHDS3_POWERS, 0, AFHDS3_FRM303_POWER_MAX, - GET_DEFAULT(md->afhds3.rfPower), - [=](int32_t newValue) { md->afhds3.rfPower = newValue; - cfg->others.dirtyFlag |= (uint32_t) 1 << afhds3::DirtyConfig::DC_RX_CMD_TX_PWR; - SET_DIRTY();}); + afhds3RfPower = new Choice( + line, rect_t{}, STR_AFHDS3_POWERS, 0, AFHDS3_FRM303_POWER_MAX, + GET_DEFAULT(md->afhds3.rfPower), [=](int32_t newValue) { + md->afhds3.rfPower = newValue; + cfg->others.dirtyFlag |= (uint32_t)1 + << afhds3::DirtyConfig::DC_RX_CMD_TX_PWR; + SET_DIRTY(); + }); } hideAFHDS3Options(); @@ -101,41 +106,39 @@ AFHDS3Settings::AFHDS3Settings(Window* parent, const FlexGridLayout& g, void AFHDS3Settings::hideAFHDS3Options() { - lv_obj_add_flag(afhds3StatusLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(afhds3StatusText->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(afhds3TypeLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(afhds3TypeForm->getLvObj(), LV_OBJ_FLAG_HIDDEN); + afhds3StatusLabel->hide(); + afhds3StatusText->hide(); + afhds3TypeLabel->hide(); + afhds3TypeForm->hide(); } void AFHDS3Settings::showAFHDS3Options() { - lv_obj_clear_flag(afhds3StatusLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(afhds3StatusText->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(afhds3TypeLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(afhds3TypeForm->getLvObj(), LV_OBJ_FLAG_HIDDEN); + afhds3StatusLabel->show(); + afhds3StatusText->show(); + afhds3TypeLabel->show(); + afhds3TypeForm->show(); lv_event_send(afhds3StatusText->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); lv_event_send(afhds3PhyMode->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); lv_event_send(afhds3Emi->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); if (moduleIdx == EXTERNAL_MODULE) { - lv_event_send(afhds3RfPower->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + lv_event_send(afhds3RfPower->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } - if (afhds3::getConfig(moduleIdx)->others.isConnected) - { - lv_obj_add_state(afhds3PhyMode->getLvObj(), LV_STATE_DISABLED); - lv_obj_add_state(afhds3Emi->getLvObj(), LV_STATE_DISABLED); - } - else - { - lv_obj_clear_state(afhds3PhyMode->getLvObj(), LV_STATE_DISABLED); - lv_obj_clear_state(afhds3Emi->getLvObj(), LV_STATE_DISABLED); + if (afhds3::getConfig(moduleIdx)->others.isConnected) { + afhds3PhyMode->disable(); + afhds3Emi->disable(); + } else { + afhds3PhyMode->enable(); + afhds3Emi->enable(); } } -void AFHDS3Settings::checkEvents() { +void AFHDS3Settings::checkEvents() +{ if (afhds3::getConfig(moduleIdx)->others.lastUpdated > lastRefresh) { update(); } - FormWindow::checkEvents(); + Window::checkEvents(); } void AFHDS3Settings::update() diff --git a/radio/src/gui/colorlcd/afhds3_settings.h b/radio/src/gui/colorlcd/afhds3_settings.h index 02e3112edd0..09dda58c673 100644 --- a/radio/src/gui/colorlcd/afhds3_settings.h +++ b/radio/src/gui/colorlcd/afhds3_settings.h @@ -27,7 +27,7 @@ struct ModuleData; -class AFHDS3Settings : public FormWindow, public ModuleOptions +class AFHDS3Settings : public Window, public ModuleOptions { uint8_t moduleIdx; ModuleData* md; @@ -37,7 +37,7 @@ class AFHDS3Settings : public FormWindow, public ModuleOptions Window* afhds3StatusLabel = nullptr; Window* afhds3StatusText = nullptr; Window* afhds3TypeLabel = nullptr; - FormWindow* afhds3TypeForm = nullptr; + Window* afhds3TypeForm = nullptr; Choice *afhds3PhyMode = nullptr; Choice *afhds3Emi = nullptr; Choice *afhds3RfPower = nullptr; diff --git a/radio/src/gui/colorlcd/bind_menu_d16.cpp b/radio/src/gui/colorlcd/bind_menu_d16.cpp index 1c8b8dddd1d..adcad43afd7 100644 --- a/radio/src/gui/colorlcd/bind_menu_d16.cpp +++ b/radio/src/gui/colorlcd/bind_menu_d16.cpp @@ -28,7 +28,7 @@ BindChoiceMenu::BindChoiceMenu(Window *parent, uint8_t moduleIdx, std::function onPress, - std::function onCancel) : + std::function onCancelFn) : Menu(parent), moduleIdx(moduleIdx), onPressHandler(std::move(onPress)) { if (isTelemAllowedOnBind(moduleIdx)) { @@ -47,7 +47,7 @@ BindChoiceMenu::BindChoiceMenu(Window *parent, uint8_t moduleIdx, setTitle(STR_SELECT_MODE); setCancelHandler([=] { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; - onCancel(); + onCancelFn(); }); } diff --git a/radio/src/gui/colorlcd/bitmaps.cpp b/radio/src/gui/colorlcd/bitmaps.cpp index 04d4e490402..ad45af07b89 100644 --- a/radio/src/gui/colorlcd/bitmaps.cpp +++ b/radio/src/gui/colorlcd/bitmaps.cpp @@ -19,12 +19,52 @@ * GNU General Public License for more details. */ -#include "opentx.h" +#include "bitmaps.h" -const uint8_t _LBM_POINT[] = { -#include "mask_point.lbm" -}; -IMPL_LZ4_BITMAP(LBM_POINT); +#include "libopenui.h" +#include "libopenui/thirdparty/lz4/lz4.h" +#include "opentx_helpers.h" + +LZ4BitmapBuffer::LZ4BitmapBuffer(uint8_t format, const LZ4Bitmap* lz4Data) : + BitmapBuffer(format, 0, 0, nullptr) +{ + _width = lz4Data->width; + _height = lz4Data->height; + + uint32_t pixels = _width * _height; + data = (uint16_t*)malloc(align32(pixels * sizeof(uint16_t))); + + LZ4_decompress_safe((const char*)lz4Data->data, (char*)data, + lz4Data->compressedSize, pixels * sizeof(uint16_t)); + data_end = data + pixels; +} + +LZ4BitmapBuffer::~LZ4BitmapBuffer() { free(data); } + +#if !defined(BOOT) + +MaskBitmap* _decompressed_mask(const uint8_t* lz4_compressed) +{ + const uint16_t* hdr = (const uint16_t*)lz4_compressed; + uint16_t width = hdr[0]; + uint16_t height = hdr[1]; + + size_t len = *(uint32_t*)&hdr[2]; + + // skip 8 bytes header + lz4_compressed += 8; + + uint32_t pixels = width * height; + MaskBitmap* raw = (MaskBitmap*)malloc(align32(pixels + 4)); + + raw->width = width; + raw->height = height; + + LZ4_decompress_safe((const char*)lz4_compressed, (char*)&raw->data, len, + pixels); + + return raw; +} static const uint8_t mask_menu_model[] = { #include "mask_menu_model.lbm" @@ -81,7 +121,7 @@ static const uint8_t mask_model_usb[] = { #include "mask_model_usb.lbm" }; static const uint8_t mask_menu_model_select[] = { -#include "mask_menu_model_select.lbm" //TODO: someone may want to make proper icon +#include "mask_menu_model_select.lbm" //TODO: someone may want to make proper icon }; static const uint8_t mask_monitor[] = { #include "mask_monitor.lbm" @@ -98,12 +138,6 @@ static const uint8_t mask_monitor_channels3[] = { static const uint8_t mask_monitor_channels4[] = { #include "mask_monitor_channels4.lbm" }; -static const uint8_t mask_monitor_inver[] = { -#include "mask_monitor_inver.lbm" -}; -static const uint8_t mask_monitor_lockch[] = { -#include "mask_monitor_lockch.lbm" -}; static const uint8_t mask_monitor_logsw[] = { #include "mask_monitor_logsw.lbm" }; @@ -185,109 +219,258 @@ static const uint8_t mask_theme_view9[] = { static const uint8_t mask_theme_view10[] = { #include "mask_theme_view10.lbm" }; -static const uint8_t stick_pointer[] = { -#include "alpha_stick_pointer.lbm" + +static const uint8_t mask_chan_locked[] = { +#include "mask_monitor_lockch.lbm" }; -static const uint8_t stick_background[] = { -#include "alpha_stick_background.lbm" +static const uint8_t mask_chan_inverted[] = { +#include "mask_monitor_inver.lbm" }; -BitmapBuffer * calibStick = nullptr; -BitmapBuffer * calibStickBackground = nullptr; -BitmapBuffer * chanMonLockedBitmap = nullptr; -BitmapBuffer * chanMonInvertedBitmap = nullptr; +static const uint8_t mask_shutdown_circle0[] = { +#include "mask_shutdown_circle0.lbm" +}; +static const uint8_t mask_shutdown_circle1[] = { +#include "mask_shutdown_circle1.lbm" +}; +static const uint8_t mask_shutdown_circle2[] = { +#include "mask_shutdown_circle2.lbm" +}; +static const uint8_t mask_shutdown_circle3[] = { +#include "mask_shutdown_circle3.lbm" +}; -struct _BuiltinBitmap { +static const uint8_t mask_shutdown[] = { +#include "mask_shutdown.lbm" +}; - BitmapFormats type; - const uint8_t* lz4_compressed_bitmap; - BitmapBuffer** uncompressed_bitmap; +const uint8_t mask_topleft_bg[] = { +#include "mask_topleft.lbm" }; -static const _BuiltinBitmap _builtinBitmaps[] = { - {BMP_ARGB4444, stick_pointer, &calibStick}, - {BMP_ARGB4444, stick_background, &calibStickBackground}, +const uint8_t mask_currentmenu_bg[] = { +#include "mask_currentmenu_bg.lbm" +}; +const uint8_t mask_currentmenu_shadow[] = { +#include "mask_currentmenu_shadow.lbm" +}; +const uint8_t mask_currentmenu_dot[] = { +#include "mask_currentmenu_dot.lbm" +}; - {BMP_8BIT, mask_monitor_lockch, &chanMonLockedBitmap}, - {BMP_8BIT, mask_monitor_inver, &chanMonInvertedBitmap}, +static const uint8_t mask_dot[] = { +#include "mask_dot.lbm" }; -void loadBuiltinBitmaps() -{ - for (const auto& bm : _builtinBitmaps) { - - delete *bm.uncompressed_bitmap; - *bm.uncompressed_bitmap = nullptr; - - if (bm.type == BMP_ARGB4444 || - bm.type == BMP_RGB565) { - *bm.uncompressed_bitmap = new LZ4Bitmap(bm.type, bm.lz4_compressed_bitmap); - } else if (bm.type == BMP_8BIT) { - *bm.uncompressed_bitmap = BitmapBuffer::load8bitMaskLZ4(bm.lz4_compressed_bitmap); - } - } -} +static const uint8_t mask_topmenu_usb[] = { +#include "mask_topmenu_usb.lbm" +}; +static const uint8_t mask_topmenu_vol0[] = { +#include "mask_volume_0.lbm" +}; +static const uint8_t mask_topmenu_vol1[] = { +#include "mask_volume_1.lbm" +}; +static const uint8_t mask_topmenu_vol2[] = { +#include "mask_volume_2.lbm" +}; +static const uint8_t mask_topmenu_vol3[] = { +#include "mask_volume_3.lbm" +}; +static const uint8_t mask_topmenu_vol4[] = { +#include "mask_volume_4.lbm" +}; +static const uint8_t mask_topmenu_vol_scale[] = { +#include "mask_volume_scale.lbm" +}; +static const uint8_t mask_topmenu_txbatt[] = { +#include "mask_txbat.lbm" +}; +#if defined(USB_CHARGER) +static const uint8_t mask_topmenu_txbatt_charging[] = { +#include "mask_txbat_charging.lbm" +}; +#endif +#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) +static const uint8_t mask_topmenu_antenna[] = { +#include "mask_antenna.lbm" +}; +#endif +#if defined(INTERNAL_GPS) +static const uint8_t mask_topmenu_gps[] = { +#include "mask_topmenu_gps_18.lbm" +}; +#endif + +static const uint8_t mask_error[] = { +#include "mask_error.lbm" +}; +static const uint8_t mask_busy[] = { +#include "mask_busy.lbm" +}; + +static const uint8_t mask_usb_plugged[] = { +#include "mask_usb_symbol.lbm" +}; + +static const uint8_t mask_timer[] = { +#include "mask_timer.lbm" +}; +static const uint8_t mask_timer_bg[] = { +#include "mask_timer_bg.lbm" +}; + +static const uint8_t mask_textline_curve[] = { +#include "mask_textline_curve.lbm" +}; +static const uint8_t mask_textline_fm[] = { +#include "mask_textline_fm.lbm" +}; + +static const uint8_t mask_mplex_add[] = { +#include "mask_mplex_add.lbm" +}; +static const uint8_t mask_mplex_multi[] = { +#include "mask_mplex_multi.lbm" +}; +static const uint8_t mask_mplex_replace[] = { +#include "mask_mplex_replace.lbm" +}; + +const uint8_t mask_round_title_left[]{ +#include "mask_round_title_left.lbm" +}; +const uint8_t mask_round_title_right[]{ +#include "mask_round_title_right.lbm" +}; struct _BuiltinIcon { - MenuIcons id; const uint8_t* lz4_compressed_bitmap; }; -static const _BuiltinIcon _builtinIcons[] = { - {ICON_EDGETX, mask_edgetx}, - {ICON_RADIO, mask_menu_radio}, - {ICON_RADIO_SETUP, mask_radio_setup}, - {ICON_RADIO_SD_MANAGER, mask_radio_sd_browser}, - {ICON_RADIO_TOOLS, mask_radio_tools}, - {ICON_RADIO_GLOBAL_FUNCTIONS, mask_radio_global_functions}, - {ICON_RADIO_TRAINER, mask_radio_trainer}, - {ICON_RADIO_HARDWARE, mask_radio_hardware}, - {ICON_RADIO_CALIBRATION, mask_radio_calibration}, - {ICON_RADIO_EDIT_THEME, mask_radio_edit_theme}, - {ICON_RADIO_VERSION, mask_radio_version}, - {ICON_MODEL, mask_menu_model}, - {ICON_MODEL_SETUP, mask_model_setup}, - {ICON_MODEL_HELI, mask_model_heli}, - {ICON_MODEL_FLIGHT_MODES, mask_model_flight_modes}, - {ICON_MODEL_INPUTS, mask_model_inputs}, - {ICON_MODEL_MIXER, mask_model_mixer}, - {ICON_MODEL_NOTES, mask_menu_notes}, - {ICON_MODEL_OUTPUTS, mask_model_outputs}, - {ICON_MODEL_CURVES, mask_model_curves}, - {ICON_MODEL_GVARS, mask_model_gvars}, - {ICON_MODEL_LOGICAL_SWITCHES, mask_model_logical_switches}, - {ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions}, - {ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts}, - {ICON_MODEL_TELEMETRY, mask_model_telemetry}, - {ICON_MODEL_USB, mask_model_usb}, - {ICON_MODEL_SELECT, mask_menu_model_select}, - {ICON_THEME, mask_menu_theme}, - {ICON_THEME_SETUP, mask_theme_setup}, - {ICON_THEME_VIEW1, mask_theme_view1}, - {ICON_THEME_VIEW2, mask_theme_view2}, - {ICON_THEME_VIEW3, mask_theme_view3}, - {ICON_THEME_VIEW4, mask_theme_view4}, - {ICON_THEME_VIEW5, mask_theme_view5}, - {ICON_THEME_VIEW6, mask_theme_view6}, - {ICON_THEME_VIEW7, mask_theme_view7}, - {ICON_THEME_VIEW8, mask_theme_view8}, - {ICON_THEME_VIEW9, mask_theme_view9}, - {ICON_THEME_VIEW10, mask_theme_view10}, - {ICON_THEME_ADD_VIEW, mask_theme_add_view}, - {ICON_STATS, mask_menu_stats}, - {ICON_STATS_THROTTLE_GRAPH, mask_stats_throttle_graph}, - {ICON_STATS_TIMERS, mask_stats_timers}, - {ICON_STATS_ANALOGS, mask_stats_analogs}, - {ICON_STATS_DEBUG, mask_stats_debug}, - {ICON_MONITOR, mask_monitor}, - {ICON_MONITOR_CHANNELS1, mask_monitor_channels1}, - {ICON_MONITOR_CHANNELS2, mask_monitor_channels2}, - {ICON_MONITOR_CHANNELS3, mask_monitor_channels3}, - {ICON_MONITOR_CHANNELS4, mask_monitor_channels4}, - {ICON_MONITOR_LOGICAL_SWITCHES, mask_monitor_logsw}, -}; - -const uint8_t* getBuiltinIcon(MenuIcons id) +#define BI(icon, mask) \ + { \ + mask \ + } + +// Note: Order must match EdgeTxIcon enum +static const _BuiltinIcon _builtinIcons[EDGETX_ICONS_COUNT] = { + BI(ICON_EDGETX, mask_edgetx), + BI(ICON_RADIO, mask_menu_radio), + BI(ICON_RADIO_SETUP, mask_radio_setup), + BI(ICON_RADIO_SD_MANAGER, mask_radio_sd_browser), + BI(ICON_RADIO_TOOLS, mask_radio_tools), + BI(ICON_RADIO_GLOBAL_FUNCTIONS, mask_radio_global_functions), + BI(ICON_RADIO_TRAINER, mask_radio_trainer), + BI(ICON_RADIO_HARDWARE, mask_radio_hardware), + BI(ICON_RADIO_CALIBRATION, mask_radio_calibration), + BI(ICON_RADIO_EDIT_THEME, mask_radio_edit_theme), + BI(ICON_RADIO_VERSION, mask_radio_version), + BI(ICON_MODEL, mask_menu_model), + BI(ICON_MODEL_SETUP, mask_model_setup), + BI(ICON_MODEL_HELI, mask_model_heli), + BI(ICON_MODEL_FLIGHT_MODES, mask_model_flight_modes), + BI(ICON_MODEL_INPUTS, mask_model_inputs), + BI(ICON_MODEL_MIXER, mask_model_mixer), + BI(ICON_MODEL_NOTES, mask_menu_notes), + BI(ICON_MODEL_OUTPUTS, mask_model_outputs), + BI(ICON_MODEL_CURVES, mask_model_curves), + BI(ICON_MODEL_GVARS, mask_model_gvars), + BI(ICON_MODEL_LOGICAL_SWITCHES, mask_model_logical_switches), + BI(ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions), + BI(ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts), + BI(ICON_MODEL_TELEMETRY, mask_model_telemetry), + BI(ICON_MODEL_USB, mask_model_usb), + BI(ICON_MODEL_SELECT, mask_menu_model_select), + BI(ICON_THEME, mask_menu_theme), + BI(ICON_THEME_SETUP, mask_theme_setup), + BI(ICON_THEME_VIEW1, mask_theme_view1), + BI(ICON_THEME_VIEW2, mask_theme_view2), + BI(ICON_THEME_VIEW3, mask_theme_view3), + BI(ICON_THEME_VIEW4, mask_theme_view4), + BI(ICON_THEME_VIEW5, mask_theme_view5), + BI(ICON_THEME_VIEW6, mask_theme_view6), + BI(ICON_THEME_VIEW7, mask_theme_view7), + BI(ICON_THEME_VIEW8, mask_theme_view8), + BI(ICON_THEME_VIEW9, mask_theme_view9), + BI(ICON_THEME_VIEW10, mask_theme_view10), + BI(ICON_THEME_ADD_VIEW, mask_theme_add_view), + BI(ICON_STATS, mask_menu_stats), + BI(ICON_STATS_THROTTLE_GRAPH, mask_stats_throttle_graph), + BI(ICON_STATS_TIMERS, mask_stats_timers), + BI(ICON_STATS_ANALOGS, mask_stats_analogs), + BI(ICON_STATS_DEBUG, mask_stats_debug), + BI(ICON_MONITOR, mask_monitor), + BI(ICON_MONITOR_CHANNELS1, mask_monitor_channels1), + BI(ICON_MONITOR_CHANNELS2, mask_monitor_channels2), + BI(ICON_MONITOR_CHANNELS3, mask_monitor_channels3), + BI(ICON_MONITOR_CHANNELS4, mask_monitor_channels4), + BI(ICON_MONITOR_LOGICAL_SWITCHES, mask_monitor_logsw), + + BI(ICON_CHAN_MONITOR_LOCKED, mask_chan_locked), + BI(ICON_CHAN_MONITOR_INVERTED, mask_chan_inverted), + + BI(ICON_SHUTDOWN_CIRCLE0, mask_shutdown_circle0), + BI(ICON_SHUTDOWN_CIRCLE1, mask_shutdown_circle1), + BI(ICON_SHUTDOWN_CIRCLE2, mask_shutdown_circle2), + BI(ICON_SHUTDOWN_CIRCLE3, mask_shutdown_circle3), + BI(ICON_SHUTDOWN, mask_shutdown), + + BI(ICON_TOPLEFT_BG, mask_topleft_bg), + BI(ICON_CURRENTMENU_BG, mask_currentmenu_bg), + BI(ICON_CURRENTMENU_SHADOW, mask_currentmenu_shadow), + BI(ICON_CURRENTMENU_DOT, mask_currentmenu_dot), + + BI(ICON_DOT, mask_dot), + + BI(ICON_TOPMENU_USB, mask_topmenu_usb), + BI(ICON_TOPMENU_VOLUME_0, mask_topmenu_vol0), + BI(ICON_TOPMENU_VOLUME_1, mask_topmenu_vol1), + BI(ICON_TOPMENU_VOLUME_2, mask_topmenu_vol2), + BI(ICON_TOPMENU_VOLUME_3, mask_topmenu_vol3), + BI(ICON_TOPMENU_VOLUME_4, mask_topmenu_vol4), + BI(ICON_TOPMENU_VOLUME_SCALE, mask_topmenu_vol_scale), + BI(ICON_TOPMENU_TXBATT, mask_topmenu_txbatt), +#if defined(USB_CHARGER) + BI(ICON_TOPMENU_TXBATT_CHARGE, mask_topmenu_txbatt_charging), +#endif +#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) + BI(ICON_TOPMENU_ANTENNA, mask_topmenu_antenna), +#endif +#if defined(INTERNAL_GPS) + BI(ICON_TOPMENU_GPS, mask_topmenu_gps), +#endif + + BI(ICON_ERROR, mask_error), + BI(ICON_BUSY, mask_busy), + + BI(ICON_USB_PLUGGED, mask_usb_plugged), + + BI(ICON_TIMER_BG, mask_timer_bg), + BI(ICON_TIMER, mask_timer), + + BI(ICON_TEXTLINE_CURVE, mask_textline_curve), + BI(ICON_TEXTLINE_FM, mask_textline_fm), + + BI(ICON_MPLEX_ADD, mask_mplex_add), + BI(ICON_MPLEX_MULTIPLY, mask_mplex_multi), + BI(ICON_MPLEX_REPLACE, mask_mplex_replace), + + BI(ICON_ROUND_TITLE_LEFT, mask_round_title_left), + BI(ICON_ROUND_TITLE_RIGHT, mask_round_title_right), +}; + +static MaskBitmap* _builtinIconsDecompressed[EDGETX_ICONS_COUNT] = {0}; + +const MaskBitmap* getBuiltinIcon(EdgeTxIcon id) { - return _builtinIcons[id].lz4_compressed_bitmap; + // Icons are stored LZ4 compressed and de-compresssed on first use + if (_builtinIconsDecompressed[id] == nullptr) { + _builtinIconsDecompressed[id] = + _decompressed_mask(_builtinIcons[id].lz4_compressed_bitmap); + } + + return _builtinIconsDecompressed[id]; } + +#endif diff --git a/radio/src/gui/colorlcd/bitmaps.h b/radio/src/gui/colorlcd/bitmaps.h index 5bcdc28d9be..d1ab4fcffb3 100644 --- a/radio/src/gui/colorlcd/bitmaps.h +++ b/radio/src/gui/colorlcd/bitmaps.h @@ -22,27 +22,134 @@ #pragma once #include "definitions.h" -#include "lz4_bitmaps.h" +#include "bitmapbuffer.h" -DEFINE_LZ4_BITMAP(LBM_POINT); +enum EdgeTxIcon { + ICON_EDGETX, + ICON_RADIO, + ICON_RADIO_SETUP, + ICON_RADIO_SD_MANAGER, + ICON_RADIO_TOOLS, + ICON_RADIO_GLOBAL_FUNCTIONS, + ICON_RADIO_TRAINER, + ICON_RADIO_HARDWARE, + ICON_RADIO_CALIBRATION, + ICON_RADIO_EDIT_THEME, + ICON_RADIO_VERSION, + ICON_MODEL, + ICON_MODEL_SETUP, + ICON_MODEL_HELI, + ICON_MODEL_FLIGHT_MODES, + ICON_MODEL_INPUTS, + ICON_MODEL_MIXER, + ICON_MODEL_NOTES, + ICON_MODEL_OUTPUTS, + ICON_MODEL_CURVES, + ICON_MODEL_GVARS, + ICON_MODEL_LOGICAL_SWITCHES, + ICON_MODEL_SPECIAL_FUNCTIONS, + ICON_MODEL_LUA_SCRIPTS, + ICON_MODEL_TELEMETRY, + ICON_MODEL_USB, + ICON_MODEL_SELECT, + ICON_THEME, + ICON_THEME_SETUP, + ICON_THEME_VIEW1, + ICON_THEME_VIEW2, + ICON_THEME_VIEW3, + ICON_THEME_VIEW4, + ICON_THEME_VIEW5, + ICON_THEME_VIEW6, + ICON_THEME_VIEW7, + ICON_THEME_VIEW8, + ICON_THEME_VIEW9, + ICON_THEME_VIEW10, + ICON_THEME_ADD_VIEW, + ICON_STATS, + ICON_STATS_THROTTLE_GRAPH, + ICON_STATS_TIMERS, + ICON_STATS_ANALOGS, + ICON_STATS_DEBUG, + ICON_MONITOR, + ICON_MONITOR_CHANNELS1, + ICON_MONITOR_CHANNELS2, + ICON_MONITOR_CHANNELS3, + ICON_MONITOR_CHANNELS4, + ICON_MONITOR_LOGICAL_SWITCHES, -// calibration bitmaps -extern BitmapBuffer * calibStick; -extern BitmapBuffer * calibStickBackground; + ICON_CHAN_MONITOR_LOCKED, + ICON_CHAN_MONITOR_INVERTED, -// Channels monitor bitmaps -extern BitmapBuffer * chanMonLockedBitmap; -extern BitmapBuffer * chanMonInvertedBitmap; + ICON_SHUTDOWN_CIRCLE0, + ICON_SHUTDOWN_CIRCLE1, + ICON_SHUTDOWN_CIRCLE2, + ICON_SHUTDOWN_CIRCLE3, + ICON_SHUTDOWN, -void loadBuiltinBitmaps(); -const uint8_t* getBuiltinIcon(MenuIcons id); + ICON_TOPLEFT_BG, + ICON_CURRENTMENU_BG, + ICON_CURRENTMENU_SHADOW, + ICON_CURRENTMENU_DOT, -PACK(struct _bitmap_mask { - uint16_t w; - uint16_t h; - uint8_t mask[0]; -}); + ICON_DOT, -#define MASK_WIDTH(m) (((_bitmap_mask*)m)->w) -#define MASK_HEIGHT(m) (((_bitmap_mask*)m)->h) -#define MASK_DATA(m) (((_bitmap_mask*)m)->mask) + ICON_TOPMENU_USB, + ICON_TOPMENU_VOLUME_0, + ICON_TOPMENU_VOLUME_1, + ICON_TOPMENU_VOLUME_2, + ICON_TOPMENU_VOLUME_3, + ICON_TOPMENU_VOLUME_4, + ICON_TOPMENU_VOLUME_SCALE, + ICON_TOPMENU_TXBATT, +#if defined(USB_CHARGER) + ICON_TOPMENU_TXBATT_CHARGE, +#endif +#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) + ICON_TOPMENU_ANTENNA, +#endif +#if defined(INTERNAL_GPS) + ICON_TOPMENU_GPS, +#endif + + ICON_ERROR, + ICON_BUSY, + + ICON_USB_PLUGGED, + + ICON_TIMER_BG, + ICON_TIMER, + + ICON_TEXTLINE_CURVE, + ICON_TEXTLINE_FM, + + ICON_MPLEX_ADD, + ICON_MPLEX_MULTIPLY, + ICON_MPLEX_REPLACE, + + ICON_ROUND_TITLE_LEFT, + ICON_ROUND_TITLE_RIGHT, + + EDGETX_ICONS_COUNT +}; + +struct MaskBitmap { + uint16_t width; + uint16_t height; + uint8_t data[]; +}; + +const MaskBitmap* getBuiltinIcon(EdgeTxIcon id); + +struct LZ4Bitmap { + uint16_t width; + uint16_t height; + uint32_t compressedSize; + uint8_t data[]; +}; + +class LZ4BitmapBuffer : public BitmapBuffer +{ + public: + LZ4BitmapBuffer(uint8_t format, const LZ4Bitmap* compressed_data); + ~LZ4BitmapBuffer(); +}; diff --git a/radio/src/gui/colorlcd/channel_bar.cpp b/radio/src/gui/colorlcd/channel_bar.cpp index ca0ce7f315d..7dd9187dbb6 100644 --- a/radio/src/gui/colorlcd/channel_bar.cpp +++ b/radio/src/gui/colorlcd/channel_bar.cpp @@ -21,169 +21,246 @@ #include "channel_bar.h" +#include "themes/etx_lv_theme.h" + #define VIEW_CHANNELS_LIMIT_PCT \ (g_model.extendedLimits ? LIMIT_EXT_PERCENT : LIMIT_STD_PERCENT) + #define CHANNELS_LIMIT (g_model.extendedLimits ? LIMIT_EXT_MAX : LIMIT_STD_MAX) -ChannelBar::ChannelBar(Window* parent, const rect_t& rect, uint8_t channel) : - Window(parent, rect), channel(channel) +ChannelBar::ChannelBar(Window* parent, const rect_t& rect, + std::function getValueFunc, LcdFlags barColor, + LcdFlags txtColor) : + Window(parent, rect), getValue(std::move(getValueFunc)) { - lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_PRIMARY2), 0); - lv_obj_set_style_bg_opa(lvobj, LV_OPA_COVER, 0); -} + etx_solid_bg(lvobj, COLOR_THEME_PRIMARY2_INDEX); -void MixerChannelBar::paint(BitmapBuffer * dc) -{ - int chanVal = calcRESXto100(ex_chans[channel]); - const int displayVal = chanVal; - - // this could be handled nicer, but slower, by checking actual range for this - // mixer - chanVal = - limit(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT); - - // Draw mixer bar - if (chanVal >= 0) { - dc->drawSolidFilledRect( - 0 + width() / 2, 0, - divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2), - height(), COLOR_THEME_FOCUS); - - dc->drawNumber(width() / 2 - 10, -2, displayVal, - FONT(XS) | COLOR_THEME_SECONDARY1 | RIGHT, 0, nullptr, "%"); - - } else if (chanVal < 0) { - const unsigned endpoint = width() / 2; - const unsigned size = - divRoundClosest(-chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2); - - dc->drawSolidFilledRect(endpoint - size, 0, size, height(), - COLOR_THEME_FOCUS); - - dc->drawNumber(10 + width() / 2, -2, displayVal, - FONT(XS) | COLOR_THEME_SECONDARY1, 0, nullptr, "%"); - } + bar = lv_obj_create(lvobj); + etx_solid_bg(bar, indexFromColor(barColor)); + lv_obj_set_pos(bar, width() / 2, 0); + lv_obj_set_size(bar, 0, height()); - if (drawMiddleBar) { - // Draw middle bar - dc->drawSolidVerticalLine(width() / 2, 0, height(), COLOR_THEME_SECONDARY1); - } + valText = lv_label_create(lvobj); + lv_obj_set_pos(valText, width() / 2 + 5, -2); + lv_obj_set_size(valText, 45, 12); + etx_obj_add_style(valText, styles->text_align_left, LV_PART_MAIN); + lv_obj_set_style_translate_x(valText, -54, LV_STATE_USER_1); + etx_obj_add_style(valText, styles->text_align_right, LV_STATE_USER_1); + etx_font(valText, FONT_XS_INDEX); + etx_txt_color(valText, indexFromColor(txtColor)); + lv_label_set_text(valText, ""); + + divPoints[0] = {(lv_coord_t)(width() / 2), 0}; + divPoints[1] = {(lv_coord_t)(width() / 2), (lv_coord_t)height()}; + + lv_obj_t* divLine = lv_line_create(lvobj); + etx_obj_add_style(divLine, styles->div_line, LV_PART_MAIN); + lv_line_set_points(divLine, divPoints, 2); } -void MixerChannelBar::checkEvents() +void ChannelBar::checkEvents() { Window::checkEvents(); - int newValue = ex_chans[channel]; + + int newValue = getValue(); + if (value != newValue) { value = newValue; - invalidate(); - } -} -static inline unsigned posOnBar(coord_t width, int value_to100) -{ - return divRoundClosest( - (value_to100 + VIEW_CHANNELS_LIMIT_PCT) * (width - 1), - VIEW_CHANNELS_LIMIT_PCT * 2); -} + lv_obj_enable_style_refresh(false); -static void drawOutputBarLimits(BitmapBuffer* dc, coord_t left, coord_t right, - LcdFlags color) -{ - dc->drawSolidVerticalLine(left, 0, BAR_HEIGHT, color); - dc->drawSolidHorizontalLine(left, 0, 3, color); - dc->drawSolidHorizontalLine(left, BAR_HEIGHT - 1, 3, color); + lv_label_set_text_fmt(valText, "%d%%", value); - dc->drawSolidVerticalLine(right, 0, BAR_HEIGHT, color); - dc->drawSolidHorizontalLine(right - 3, 0, 3, color); - dc->drawSolidHorizontalLine(right - 3, BAR_HEIGHT - 1, 3, color); -} + if (newValue < 0) + lv_obj_clear_state(valText, LV_STATE_USER_1); + else + lv_obj_add_state(valText, LV_STATE_USER_1); -void OutputChannelBar::paint(BitmapBuffer* dc) -{ - int chanVal = calcRESXto100(channelOutputs[channel]); - int displayVal = chanVal; + int chanVal = + limit(-VIEW_CHANNELS_LIMIT_PCT, value, VIEW_CHANNELS_LIMIT_PCT); + + uint16_t size = + divRoundClosest(abs(chanVal) * width(), VIEW_CHANNELS_LIMIT_PCT * 2); - chanVal = - limit(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT); + int16_t x = width() / 2 - ((chanVal > 0) ? 0 : size); - // Draw output bar - if (chanVal >= 0) { - dc->drawSolidFilledRect( - width() / 2, 0, - divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2), - height(), COLOR_THEME_ACTIVE); + lv_obj_set_pos(bar, x, 0); + lv_obj_set_size(bar, size, height()); + + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); + } +} - dc->drawNumber(width() / 2 - 10, -2, displayVal, - FONT(XS) | COLOR_THEME_SECONDARY1 | RIGHT, 0, nullptr, "%"); +//----------------------------------------------------------------------------- - } else if (chanVal < 0) { - unsigned endpoint = width() / 2; - unsigned size = - divRoundClosest(-chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2); +MixerChannelBar::MixerChannelBar(Window* parent, const rect_t& rect, + uint8_t channel) : + ChannelBar( + parent, rect, [=] { return calcRESXto100(ex_chans[channel]); }, + COLOR_THEME_FOCUS) +{ +} - dc->drawSolidFilledRect(endpoint - size, 0, size, height(), - COLOR_THEME_ACTIVE); +//----------------------------------------------------------------------------- - dc->drawNumber(width() / 2 + 10, -2, displayVal, - FONT(XS) | COLOR_THEME_SECONDARY1, 0, nullptr, "%"); +OutputChannelBar::OutputChannelBar(Window* parent, const rect_t& rect, + uint8_t channel, bool editColor, + bool drawLimits) : + ChannelBar( + parent, rect, + [=] { return calcRESXto100(channelOutputs[this->channel]); }, + COLOR_THEME_ACTIVE), + channel(channel), + drawLimits(drawLimits) +{ + if (drawLimits) { + leftLim = lv_line_create(lvobj); + if (editColor) + etx_obj_add_style(leftLim, styles->div_line_edit, LV_PART_MAIN); + else + etx_obj_add_style(leftLim, styles->div_line, LV_PART_MAIN); + rightLim = lv_line_create(lvobj); + if (editColor) + etx_obj_add_style(rightLim, styles->div_line_edit, LV_PART_MAIN); + else + etx_obj_add_style(rightLim, styles->div_line, LV_PART_MAIN); + drawLimitLines(true); } +} - // Draw middle bar - dc->drawSolidVerticalLine(width() / 2, 0, height(), COLOR_THEME_SECONDARY1); +static inline unsigned posOnBar(coord_t width, int value_to100) +{ + return divRoundClosest((value_to100 + VIEW_CHANNELS_LIMIT_PCT) * (width - 1), + VIEW_CHANNELS_LIMIT_PCT * 2); +} +void OutputChannelBar::drawLimitLines(bool forced) +{ if (drawLimits) { // Draw output limits bars - int limit = CHANNELS_LIMIT; + bool changed = forced; LimitData* ld = limitAddress(channel); - int32_t ldMax; int32_t ldMin; + int32_t ldMax; - if (GV_IS_GV_VALUE(ld->min, -limit, 0)) { - ldMin = limMin; + if (GV_IS_GV_VALUE(ld->min, -CHANNELS_LIMIT, 0)) { + ldMin = + GET_GVAR_PREC1(ld->min, -CHANNELS_LIMIT, 0, mixerCurrentFlightMode) + + LIMIT_STD_MAX; } else { ldMin = ld->min; } + if (limMin != ldMin) { + changed = true; + limMin = ldMin; + } - if (GV_IS_GV_VALUE(ld->max, 0, limit)) { - ldMax = limMax; + if (GV_IS_GV_VALUE(ld->max, 0, CHANNELS_LIMIT)) { + ldMax = + GET_GVAR_PREC1(ld->max, 0, CHANNELS_LIMIT, mixerCurrentFlightMode) - + LIMIT_STD_MAX; } else { ldMax = ld->max; } + if (limMax != ldMax) { + changed = true; + limMax = ldMax; + } + + if (changed) { + lv_coord_t left, right; + lv_coord_t h = height() - 1; + + if (ld->revert) { + left = posOnBar(width(), -100 - ldMax / 10); + right = posOnBar(width(), 100 - ldMin / 10); + } else { + left = posOnBar(width(), -100 + ldMin / 10); + right = posOnBar(width(), 100 + ldMax / 10); + } - if (ld && ld->revert) { - drawOutputBarLimits(dc, posOnBar(width(), -100 - ldMax / 10), - posOnBar(width(), 100 - ldMin / 10), - outputBarLimitsColor); - } else if (ld) { - drawOutputBarLimits(dc, posOnBar(width(), -100 + ldMin / 10), - posOnBar(width(), 100 + ldMax / 10), - outputBarLimitsColor); + limPoints[0] = {(lv_coord_t)(left + 3), 0}; + limPoints[1] = {(lv_coord_t)(left), 0}; + limPoints[2] = {(lv_coord_t)(left), h}; + limPoints[3] = {(lv_coord_t)(left + 3), h}; + limPoints[4] = {(lv_coord_t)(right - 2), 0}; + limPoints[5] = {(lv_coord_t)(right), 0}; + limPoints[6] = {(lv_coord_t)(right), h}; + limPoints[7] = {(lv_coord_t)(right - 2), h}; + // Workaround for bugs in LVGL line drawing + limPoints[8] = {(lv_coord_t)(right + 1), h}; + + lv_line_set_points(leftLim, &limPoints[0], 4); + lv_line_set_points(rightLim, &limPoints[4], 5); } } } void OutputChannelBar::checkEvents() { - Window::checkEvents(); - int newValue = channelOutputs[channel]; - if (value != newValue) { - value = newValue; - invalidate(); - } - int limit = CHANNELS_LIMIT; - LimitData* lim = limitAddress(channel); - - if (GV_IS_GV_VALUE(lim->min, -limit, 0)) { - int ldMin = GET_GVAR_PREC1(lim->min, -limit, 0, mixerCurrentFlightMode) + - LIMIT_STD_MAX; - if (limMin != ldMin) invalidate(); - limMin = ldMin; + ChannelBar::checkEvents(); + drawLimitLines(false); +} + +//----------------------------------------------------------------------------- + +ComboChannelBar::ComboChannelBar(Window* parent, const rect_t& rect, + uint8_t _channel, bool isInHeader) : + Window(parent, rect), channel(_channel) +{ + LcdFlags textColor = + isInHeader ? COLOR_THEME_PRIMARY2 : COLOR_THEME_SECONDARY1; + + outputChannelBar = new OutputChannelBar( + this, {LMARGIN, BAR_HEIGHT + TMARGIN, width() - LMARGIN, BAR_HEIGHT}, + channel, isInHeader); + + new MixerChannelBar( + this, + {LMARGIN, (2 * BAR_HEIGHT) + TMARGIN + 1, width() - LMARGIN, BAR_HEIGHT}, + channel); + + // Channel number + char chanString[] = TR_CH "32 "; + strAppendSigned(&chanString[2], channel + 1, 2); + new StaticText(this, {LMARGIN, 0, LV_SIZE_CONTENT, 12}, chanString, + textColor | FONT(XS) | LEFT); + + // Channel name + if (g_model.limitData[channel].name[0]) { + char nm[LEN_CHANNEL_NAME + 1]; + strAppend(nm, g_model.limitData[channel].name, LEN_CHANNEL_NAME); + new StaticText(this, {LMARGIN + 45, 0, LV_SIZE_CONTENT, 12}, nm, + textColor | FONT(XS) | LEFT); } - if (GV_IS_GV_VALUE(lim->max, 0, limit)) { - int ldMax = GET_GVAR_PREC1(lim->max, 0, limit, mixerCurrentFlightMode) - - LIMIT_STD_MAX; - if (limMax != ldMax) invalidate(); - limMax = ldMax; + + // Channel value in µS + new DynamicNumber( + this, {width() - 45, 0, 45, 12}, + [=] { return PPM_CH_CENTER(channel) + channelOutputs[channel] / 2; }, + textColor | FONT(XS) | RIGHT, "", STR_US); + + // Override icon +#if defined(OVERRIDE_CHANNEL_FUNCTION) + overrideIcon = new StaticIcon( + this, 0, 5, getBuiltinIcon(ICON_CHAN_MONITOR_LOCKED), textColor); + overrideIcon->show(safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED); +#endif + + // Channel reverted icon + LimitData* ld = limitAddress(channel); + if (ld && ld->revert) { + new StaticIcon(this, 0, 25, getBuiltinIcon(ICON_CHAN_MONITOR_INVERTED), + textColor); } } + +#if defined(OVERRIDE_CHANNEL_FUNCTION) +void ComboChannelBar::checkEvents() +{ + Window::checkEvents(); + + overrideIcon->show(safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED); +} +#endif diff --git a/radio/src/gui/colorlcd/channel_bar.h b/radio/src/gui/colorlcd/channel_bar.h index c4ae4ba76ff..d2a256ef5ef 100644 --- a/radio/src/gui/colorlcd/channel_bar.h +++ b/radio/src/gui/colorlcd/channel_bar.h @@ -21,152 +21,72 @@ #pragma once -#include "opentx.h" +#include "bitmaps.h" #include "libopenui.h" +#include "opentx.h" #include "static.h" constexpr coord_t ROW_HEIGHT = 42; constexpr coord_t BAR_HEIGHT = 13; -constexpr coord_t LEG_COLORBOX = 15; constexpr coord_t LMARGIN = 15; constexpr coord_t TMARGIN = 2; class ChannelBar : public Window { public: - ChannelBar(Window* parent, const rect_t& rect, uint8_t channel); - - void setChannel(uint8_t ch) - { - channel = ch; - invalidate(); - } + ChannelBar(Window* parent, const rect_t& rect, + std::function getValue, LcdFlags barColor, + LcdFlags textColor = COLOR_THEME_SECONDARY1); protected: - uint8_t channel = 0; + int16_t value = -10000; + std::function getValue; + lv_obj_t* valText = nullptr; + lv_point_t divPoints[2]; + lv_obj_t* bar = nullptr; + + void checkEvents() override; }; class MixerChannelBar : public ChannelBar { public: - using ChannelBar::ChannelBar; - - void setDrawMiddleBar(bool enable) { drawMiddleBar = enable; } - - void paint(BitmapBuffer* dc) override; - void checkEvents() override; - - protected: - bool drawMiddleBar = true; - int value = 0; + MixerChannelBar(Window* parent, const rect_t& rect, uint8_t channel); }; class OutputChannelBar : public ChannelBar { public: - using ChannelBar::ChannelBar; - - void setDrawLimits(bool enable) { drawLimits = enable; } - void setOutputBarLimitColor(uint32_t color) { outputBarLimitsColor = color; } - - void paint(BitmapBuffer* dc) override; - void checkEvents() override; + OutputChannelBar(Window* parent, const rect_t& rect, uint8_t channel, + bool editColor = false, bool drawLimits = true); protected: - int value = 0; + uint8_t channel = 0; int limMax = 0; int limMin = 0; bool drawLimits = true; - LcdFlags outputBarLimitsColor = COLOR_THEME_SECONDARY1; + lv_point_t limPoints[9]; + lv_obj_t* leftLim = nullptr; + lv_obj_t* rightLim = nullptr; + + void drawLimitLines(bool forced); + + void checkEvents() override; }; class ComboChannelBar : public Window { - public: - // using ChannelBar::ChannelBar; - ComboChannelBar(Window * parent, const rect_t & rect, uint8_t channel): - Window(parent, rect), channel(channel) - { - outputChannelBar = new OutputChannelBar( - this, {leftMargin, BAR_HEIGHT + TMARGIN, width() - leftMargin, BAR_HEIGHT}, - channel); - new MixerChannelBar( - this, - {leftMargin, (2 * BAR_HEIGHT) + TMARGIN + 1, width() - leftMargin, BAR_HEIGHT}, - channel); - } - - void setOutputChannelBarLimitColor(uint32_t color) - { - if (outputChannelBar != nullptr) { - outputChannelBar->setOutputBarLimitColor(color); - } - } - - void setTextColor(uint32_t color) - { - textColor = color; - invalidate(); - } - - void setLeftMargin(int margin) - { - leftMargin = margin; - } - - void paint(BitmapBuffer * dc) override - { - char chanString[] = TR_CH"32 "; - int usValue = PPM_CH_CENTER(channel) + channelOutputs[channel] / 2; - - // Channel number - strAppendSigned(&chanString[2], channel + 1, 2); - dc->drawText(leftMargin, 0, chanString, FONT(XS) | textColor | LEFT); - - // Channel name - dc->drawSizedText(leftMargin + 45, 0, g_model.limitData[channel].name, sizeof(g_model.limitData[channel].name), FONT(XS) | textColor | LEFT); - - // Channel value in µS - dc->drawNumber(width(), 0, usValue, FONT(XS) | textColor | RIGHT, 0, nullptr, STR_US); - - // Override icon -#if defined(OVERRIDE_CHANNEL_FUNCTION) - if (safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED) - dc->drawMask(0, 5, chanMonLockedBitmap, textColor); -#endif - - // Channel reverted icon - LimitData * ld = limitAddress(channel); - if (ld && ld->revert) { - dc->drawMask(0, 25, chanMonInvertedBitmap, textColor); - } - } + public: + // using ChannelBar::ChannelBar; + ComboChannelBar(Window* parent, const rect_t& rect, uint8_t channel, + bool isInHeader = false); - void checkEvents() override - { - Window::checkEvents(); - int newValue = channelOutputs[channel]; - if (value != newValue) { - value = newValue; - invalidate(); - } + protected: + uint8_t channel; + OutputChannelBar* outputChannelBar = nullptr; #if defined(OVERRIDE_CHANNEL_FUNCTION) - int newSafetyChValue = safetyCh[channel]; - if (safetyChValue != newSafetyChValue) - { - safetyChValue = newSafetyChValue; - invalidate(); - } -#endif - } + StaticIcon* overrideIcon = nullptr; - protected: - uint8_t channel; - OutputChannelBar *outputChannelBar = nullptr; - int value = 0; - int leftMargin = LMARGIN; - uint32_t textColor = COLOR_THEME_SECONDARY1; -#if defined(OVERRIDE_CHANNEL_FUNCTION) - int safetyChValue = OVERRIDE_CHANNEL_UNDEFINED; + void checkEvents() override; #endif }; diff --git a/radio/src/gui/colorlcd/channel_range.cpp b/radio/src/gui/colorlcd/channel_range.cpp index d2ea6c291cd..8d9ec89f5e6 100644 --- a/radio/src/gui/colorlcd/channel_range.cpp +++ b/radio/src/gui/colorlcd/channel_range.cpp @@ -20,55 +20,55 @@ */ #include "channel_range.h" + #include "opentx.h" #define SET_DIRTY() storageDirty(EE_MODEL) -inline int16_t ppmFrameLen(int8_t chCount) { - #define PPM_PULSE_LEN_MAX (4 * PPM_STEP_SIZE) // let's assume roughly 2ms max pulse length +inline int16_t ppmFrameLen(int8_t chCount) +{ +#define PPM_PULSE_LEN_MAX \ + (4 * PPM_STEP_SIZE) // let's assume roughly 2ms max pulse length - if(chCount > 0) - return((PPM_PULSE_LEN_MAX * chCount) + PPM_DEF_PERIOD); // for more than 8 channels update frame length - else - return(PPM_DEF_PERIOD); // else leave frame Length at default (22.5ms) + if (chCount > 0) + return ((PPM_PULSE_LEN_MAX * chCount) + + PPM_DEF_PERIOD); // for more than 8 channels update frame length + else + return (PPM_DEF_PERIOD); // else leave frame Length at default (22.5ms) } -void cb_value_changed(lv_event_t* e) { +void cb_value_changed(lv_event_t* e) +{ ChannelRange* chRangeEditObject = (ChannelRange*)lv_event_get_user_data(e); - if(!chRangeEditObject) - return; + if (!chRangeEditObject) return; - NumberEdit* ppmFrameLenEditObject = chRangeEditObject->getPpmFrameLenEditObject(); - if(!ppmFrameLenEditObject) - return; + NumberEdit* ppmFrameLenEditObject = + chRangeEditObject->getPpmFrameLenEditObject(); + if (!ppmFrameLenEditObject) return; - ppmFrameLenEditObject->setValue(ppmFrameLen(chRangeEditObject->getChannelsCount())); + ppmFrameLenEditObject->setValue( + ppmFrameLen(chRangeEditObject->getChannelsCount())); } -ChannelRange::ChannelRange(Window* parent) : - FormWindow(parent, rect_t{}) +ChannelRange::ChannelRange(Window* parent) : Window(parent, rect_t{}) { - setFlexLayout(LV_FLEX_FLOW_ROW); - lv_obj_set_width(lvobj, LV_SIZE_CONTENT); + padAll(PAD_TINY); + setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); } void ChannelRange::build() { - chStart = new NumberEdit(this, rect_t{}, 1, 1, GET_DEFAULT(1 + getChannelsStart())); + chStart = new NumberEdit(this, rect_t{0, 0, 80, 0}, 1, 1, + GET_DEFAULT(1 + getChannelsStart())); chStart->setSetValueHandler([=](int newValue) { setStart(newValue); }); chStart->setPrefix(STR_CH); -#if LCD_H > LCD_W - chStart->setWidth(LCD_W/3-10); -#endif - chEnd = new NumberEdit(this, rect_t{}, 8, 8, - GET_DEFAULT(getChannelsStart() + 8 + getChannelsCount())); + chEnd = + new NumberEdit(this, rect_t{0, 0, 80, 0}, 8, 8, + GET_DEFAULT(getChannelsStart() + 8 + getChannelsCount())); chEnd->setPrefix(STR_CH); chEnd->setSetValueHandler([=](int newValue) { setEnd(newValue); }); -#if LCD_H > LCD_W - chEnd->setWidth(LCD_W/3-10); -#endif } void ChannelRange::setStart(uint8_t newValue) @@ -110,11 +110,13 @@ void ChannelRange::update() updateEnd(); } -NumberEdit* ChannelRange::getPpmFrameLenEditObject() { +NumberEdit* ChannelRange::getPpmFrameLenEditObject() +{ return this->ppmFrameLenEditObject; } -void ChannelRange::setPpmFrameLenEditObject(NumberEdit* ppmFrameLenEditObject) { +void ChannelRange::setPpmFrameLenEditObject(NumberEdit* ppmFrameLenEditObject) +{ this->ppmFrameLenEditObject = ppmFrameLenEditObject; } @@ -125,7 +127,8 @@ ModuleChannelRange::ModuleChannelRange(Window* parent, uint8_t moduleIdx) : update(); // add callback to be notified when channel count changes - lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed, LV_EVENT_VALUE_CHANGED, (void *)this); + lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed, + LV_EVENT_VALUE_CHANGED, (void*)this); } void ModuleChannelRange::update() @@ -136,8 +139,7 @@ void ModuleChannelRange::update() auto max_mod_ch = maxModuleChannels(moduleIdx); chEnd->enable(min_mod_ch < max_mod_ch); - if (chEnd->getValue() > chEnd->getMax()) - chEnd->setValue(chEnd->getMax()); + if (chEnd->getValue() > chEnd->getMax()) chEnd->setValue(chEnd->getMax()); if (!isModulePXX2(moduleIdx)) { chEnd->setAvailableHandler(nullptr); @@ -165,7 +167,7 @@ void ModuleChannelRange::setChannelsStart(uint8_t val) int8_t ModuleChannelRange::getChannelsCount() { ModuleData* md = &g_model.moduleData[moduleIdx]; - return md->channelsCount; + return md->channelsCount; } void ModuleChannelRange::setChannelsCount(int8_t val) @@ -189,14 +191,14 @@ uint8_t ModuleChannelRange::getChannelsMax() return maxModuleChannels(moduleIdx); } -TrainerChannelRange::TrainerChannelRange(Window* parent) : - ChannelRange(parent) +TrainerChannelRange::TrainerChannelRange(Window* parent) : ChannelRange(parent) { build(); update(); // add callback to be notified when channel count changes - lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed, LV_EVENT_VALUE_CHANGED, (void *)this); + lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed, + LV_EVENT_VALUE_CHANGED, (void*)this); } uint8_t TrainerChannelRange::getChannelsStart() @@ -224,12 +226,6 @@ uint8_t TrainerChannelRange::getChannelsUsed() return 8 + getChannelsCount(); } -uint8_t TrainerChannelRange::getChannelsMin() -{ - return MIN_TRAINER_CHANNELS; -} +uint8_t TrainerChannelRange::getChannelsMin() { return MIN_TRAINER_CHANNELS; } -uint8_t TrainerChannelRange::getChannelsMax() -{ - return MAX_TRAINER_CHANNELS; -} +uint8_t TrainerChannelRange::getChannelsMax() { return MAX_TRAINER_CHANNELS; } diff --git a/radio/src/gui/colorlcd/channel_range.h b/radio/src/gui/colorlcd/channel_range.h index 042ce235be3..032c3fd9e63 100644 --- a/radio/src/gui/colorlcd/channel_range.h +++ b/radio/src/gui/colorlcd/channel_range.h @@ -24,7 +24,7 @@ #include "form.h" #include "numberedit.h" -class ChannelRange : public FormWindow +class ChannelRange : public Window { public: ChannelRange(Window* parent); @@ -46,7 +46,7 @@ class ChannelRange : public FormWindow NumberEdit* ppmFrameLenEditObject = nullptr; void build(); - + virtual uint8_t getChannelsStart() = 0; virtual void setChannelsStart(uint8_t val) = 0; diff --git a/radio/src/gui/colorlcd/color_editor.cpp b/radio/src/gui/colorlcd/color_editor.cpp index cca779edab9..1a8aeff2c10 100644 --- a/radio/src/gui/colorlcd/color_editor.cpp +++ b/radio/src/gui/colorlcd/color_editor.cpp @@ -19,163 +19,181 @@ * GNU General Public License for more details. */ #include "color_editor.h" -#include "font.h" + +#include "themes/etx_lv_theme.h" constexpr int BAR_MARGIN = 5; constexpr int BAR_TOP_MARGIN = 5; constexpr int BAR_HEIGHT_OFFSET = BAR_TOP_MARGIN + 25; -static const char * const RGBChars[MAX_BARS] = { "R", "G", "B" }; -static const char * const HSVChars[MAX_BARS] = { "H", "S", "V" }; +static const char* const RGBChars[MAX_BARS] = {"R", "G", "B"}; +static const char* const HSVChars[MAX_BARS] = {"H", "S", "V"}; + +typedef std::function getRGBFromPos; -void ColorBar::pressing(lv_event_t* e) +class ColorBar : public Window { - lv_obj_t* target = lv_event_get_target(e); - lv_indev_t* click_source = (lv_indev_t*)lv_event_get_param(e); - if (!click_source || - (lv_indev_get_type(click_source) != LV_INDEV_TYPE_POINTER)) - return; + public: + ColorBar(Window* parent, const rect_t& r, uint32_t value = 0, + uint32_t maxValue = 0, bool invert = false) : + Window(parent, r) + { + lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL); + + lv_group_add_obj((lv_group_t*)lv_group_get_default(), lvobj); + lv_obj_add_event_cb(lvobj, ColorBar::pressing, LV_EVENT_PRESSING, nullptr); + lv_obj_add_event_cb(lvobj, ColorBar::on_key, LV_EVENT_KEY, nullptr); + lv_obj_add_event_cb(lvobj, ColorBar::draw_end, LV_EVENT_DRAW_PART_END, + nullptr); + + etx_std_style(lvobj, LV_PART_MAIN, PAD_ZERO); + } + + int valueToScreen(int val) + { + auto h = height() - 4; // exclude border + + int scaledValue = (val * h + maxValue / 2) / maxValue; + if (invert) scaledValue = h - scaledValue; + return scaledValue; + } - lv_area_t obj_coords; - lv_obj_get_coords(target, &obj_coords); + uint32_t screenToValue(int pos) + { + auto h = height() - 4; // exclude border - lv_point_t point_act; - lv_indev_get_point(click_source, &point_act); + // range check + pos = min(pos, h); + pos = max(pos, 0); - lv_point_t rel_pos; - rel_pos.x = point_act.x - obj_coords.x1; - rel_pos.y = point_act.y - obj_coords.y1; + uint32_t scaledValue = ((pos * maxValue + h / 2) / h); + if (invert) scaledValue = maxValue - scaledValue; + return scaledValue; + } - TRACE("PRESSING [%d,%d]", rel_pos.x, rel_pos.y); + static void pressing(lv_event_t* e) + { + lv_obj_t* target = lv_event_get_target(e); + lv_indev_t* click_source = (lv_indev_t*)lv_event_get_param(e); + if (!click_source || + (lv_indev_get_type(click_source) != LV_INDEV_TYPE_POINTER)) + return; - ColorBar* bar = (ColorBar*)lv_obj_get_user_data(target); - if (!bar) return; + ColorBar* bar = (ColorBar*)lv_obj_get_user_data(target); + if (!bar) return; - bar->value = bar->screenToValue(rel_pos.y); - lv_event_send(target->parent, LV_EVENT_VALUE_CHANGED, nullptr); -} + lv_area_t obj_coords; + lv_obj_get_coords(target, &obj_coords); -void ColorBar::on_key(lv_event_t* e) -{ - lv_obj_t* obj = lv_event_get_target(e); - ColorBar* bar = (ColorBar*)lv_obj_get_user_data(obj); - if (!bar) return; - - uint32_t key = *(uint32_t*)lv_event_get_param(e); - if (key == LV_KEY_LEFT) { - if (bar->value > 0) { - uint32_t accel = rotaryEncoderGetAccel(); - bar->value--; - if (accel > 0) { - if (accel > bar->value) bar->value = 0; - else bar->value -= accel; + lv_point_t point_act; + lv_indev_get_point(click_source, &point_act); + + lv_point_t rel_pos; + rel_pos.x = point_act.x - obj_coords.x1; + rel_pos.y = point_act.y - obj_coords.y1; + + TRACE("PRESSING [%d,%d]", rel_pos.x, rel_pos.y); + + bar->value = bar->screenToValue(rel_pos.y); + lv_event_send(target->parent, LV_EVENT_VALUE_CHANGED, nullptr); + } + + static void on_key(lv_event_t* e) + { + lv_obj_t* obj = lv_event_get_target(e); + ColorBar* bar = (ColorBar*)lv_obj_get_user_data(obj); + if (!bar) return; + + uint32_t key = *(uint32_t*)lv_event_get_param(e); + if (key == LV_KEY_LEFT) { + if (bar->value > 0) { + uint32_t accel = rotaryEncoderGetAccel(); + bar->value--; + if (accel > 0) { + if (accel > bar->value) + bar->value = 0; + else + bar->value -= accel; + } + lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr); } - lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr); - } - } else if (key == LV_KEY_RIGHT) { - if (bar->value < bar->maxValue) { - uint32_t accel = rotaryEncoderGetAccel(); - bar->value++; - if (accel > 0) { - if (accel < bar->maxValue - bar->value) bar->value += accel; - else bar->value = bar->maxValue; + } else if (key == LV_KEY_RIGHT) { + if (bar->value < bar->maxValue) { + uint32_t accel = rotaryEncoderGetAccel(); + bar->value++; + if (accel > 0) { + if (accel < bar->maxValue - bar->value) + bar->value += accel; + else + bar->value = bar->maxValue; + } + lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr); } - lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr); } } -} -void ColorBar::draw_end(lv_event_t* e) -{ - lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e); - if (dsc->type != LV_OBJ_DRAW_PART_RECTANGLE) return; - - lv_obj_t* obj = lv_event_get_target(e); - ColorBar* bar = (ColorBar*)lv_obj_get_user_data(obj); - if (!bar) return; - - lv_draw_line_dsc_t line_dsc; - lv_draw_line_dsc_init(&line_dsc); - - line_dsc.width = 1; - line_dsc.opa = LV_OPA_100; - - auto area = dsc->draw_area; - lv_point_t p1, p2; - p1.x = area->x1; - p2.x = area->x2 + 1; - - // draw background gradient - for (auto y = area->y1; y <= area->y2; y++) { - p1.y = y; - p2.y = y; - auto c = bar->getRGB(bar->screenToValue(y - area->y1)); - line_dsc.color = lv_color_make(GET_RED(c), GET_GREEN(c), GET_BLUE(c)); - lv_draw_line(dsc->draw_ctx, &line_dsc, &p1, &p2); - } + static void draw_end(lv_event_t* e) + { + lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e); + if (dsc->type != LV_OBJ_DRAW_PART_RECTANGLE) return; + + lv_obj_t* obj = lv_event_get_target(e); + ColorBar* bar = (ColorBar*)lv_obj_get_user_data(obj); + if (!bar) return; + + lv_draw_line_dsc_t line_dsc; + lv_draw_line_dsc_init(&line_dsc); + + line_dsc.width = 1; + line_dsc.opa = LV_OPA_100; + + auto area = dsc->draw_area; + lv_point_t p1, p2; + int h = area->y2 - area->y1 - 4; + + // draw background gradient + for (int i = 0; i <= h; i += 1) { + p1.y = p2.y = i + area->y1 + 2; + if (i == 0 || i == h) { + p1.x = area->x1 + 3; + p2.x = area->x2 - 2; + } else { + p1.x = area->x1 + 2; + p2.x = area->x2 - 1; + } + auto c = bar->getRGB(bar->screenToValue(i)); + line_dsc.color = lv_color_make(GET_RED(c), GET_GREEN(c), GET_BLUE(c)); + lv_draw_line(dsc->draw_ctx, &line_dsc, &p1, &p2); + } - // draw cursor - lv_area_t cursor_area; - cursor_area.x1 = area->x1 + (lv_area_get_width(area) / 2) - 5; - cursor_area.x2 = cursor_area.x1 + 10 - 1; + // draw cursor + lv_area_t cursor_area; + cursor_area.x1 = area->x1 + (lv_area_get_width(area) / 2) - 5; + cursor_area.x2 = cursor_area.x1 + 10 - 1; - auto pos = bar->valueToScreen(bar->value); - cursor_area.y1 = area->y1 + pos - 5; - cursor_area.y2 = cursor_area.y1 + 10 - 1; + auto pos = bar->valueToScreen(bar->value); + cursor_area.y1 = area->y1 + pos - 3; + cursor_area.y2 = cursor_area.y1 + 10 - 1; - lv_draw_rect_dsc_t cursor_dsc; - lv_draw_rect_dsc_init(&cursor_dsc); + lv_draw_rect_dsc_t cursor_dsc; + lv_draw_rect_dsc_init(&cursor_dsc); - cursor_dsc.radius = LV_RADIUS_CIRCLE; - cursor_dsc.bg_opa = LV_OPA_100; - cursor_dsc.bg_color = makeLvColor(COLOR_THEME_PRIMARY2); - cursor_dsc.border_opa = LV_OPA_100; - cursor_dsc.border_color = makeLvColor(COLOR_THEME_PRIMARY1); - cursor_dsc.border_width = 1; + cursor_dsc.radius = LV_RADIUS_CIRCLE; + cursor_dsc.bg_opa = LV_OPA_100; + cursor_dsc.bg_color = makeLvColor(COLOR_THEME_PRIMARY2); + cursor_dsc.border_opa = LV_OPA_100; + cursor_dsc.border_color = makeLvColor(COLOR_THEME_PRIMARY1); + cursor_dsc.border_width = 1; - lv_draw_rect(dsc->draw_ctx, &cursor_dsc, &cursor_area); -} - -ColorBar::ColorBar(Window* parent, const rect_t& r, uint32_t value, - uint32_t maxValue, bool invert) : - FormField(parent, r) -{ - lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL); - - lv_group_add_obj((lv_group_t*)lv_group_get_default(), lvobj); - lv_obj_add_event_cb(lvobj, ColorBar::pressing, LV_EVENT_PRESSING, nullptr); - lv_obj_add_event_cb(lvobj, ColorBar::on_key, LV_EVENT_KEY, nullptr); - lv_obj_add_event_cb(lvobj, ColorBar::draw_end, LV_EVENT_DRAW_PART_END, nullptr); - - // normal - lv_obj_set_style_border_width(lvobj, 1, 0); - lv_obj_set_style_border_color(lvobj, makeLvColor(COLOR_THEME_PRIMARY1), 0); - lv_obj_set_style_border_opa(lvobj, LV_OPA_100, 0); - lv_obj_set_style_border_post(lvobj, true, 0); - - // focused - lv_obj_set_style_border_width(lvobj, 2, LV_STATE_FOCUSED); - lv_obj_set_style_border_color(lvobj, makeLvColor(COLOR_THEME_FOCUS), LV_STATE_FOCUSED); -} - -int ColorBar::valueToScreen(int val) -{ - int scaledValue = (((float)val / maxValue) * height()); - if (invert) scaledValue = height() - scaledValue; - return scaledValue; -} - -uint32_t ColorBar::screenToValue(int pos) -{ - // range check - pos = min(pos, height()); - pos = max(pos, 0); + lv_draw_rect(dsc->draw_ctx, &cursor_dsc, &cursor_area); + } - uint32_t scaledValue = (((float)pos / height()) * maxValue); - if (invert) scaledValue = maxValue - scaledValue; - return scaledValue; -} + uint32_t maxValue = 0; + uint32_t value = 0; + bool invert = false; + getRGBFromPos getRGB = nullptr; +}; BarColorType::BarColorType(Window* parent) { @@ -187,7 +205,7 @@ BarColorType::BarColorType(Window* parent) r.w = spacePerBar - BAR_MARGIN - 5; r.h = parent->height() - BAR_HEIGHT_OFFSET; - for ( int i=0; i < MAX_BARS; i++){ + for (int i = 0; i < MAX_BARS; i++) { r.x = leftPos + BAR_MARGIN; bars[i] = new ColorBar(parent, r); @@ -205,25 +223,27 @@ BarColorType::BarColorType(Window* parent) BarColorType::~BarColorType() { - for ( int i=0; i < MAX_BARS; i++) { + for (int i = 0; i < MAX_BARS; i++) { bars[i]->deleteLater(); - } + } }; -lv_obj_t* BarColorType::create_bar_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y) +lv_obj_t* BarColorType::create_bar_label(lv_obj_t* parent, lv_coord_t x, + lv_coord_t y) { lv_obj_t* obj = lv_label_create(parent); lv_obj_set_pos(obj, x, y); - lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_PRIMARY1), 0); - lv_obj_set_style_text_font(obj, getFont(FONT(XXS)), 0); + etx_txt_color(obj, COLOR_THEME_PRIMARY1_INDEX); + etx_font(obj, FONT_XXS_INDEX); return obj; } -lv_obj_t* BarColorType::create_bar_value_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y) +lv_obj_t* BarColorType::create_bar_value_label(lv_obj_t* parent, lv_coord_t x, + lv_coord_t y) { lv_obj_t* obj = lv_label_create(parent); lv_obj_set_pos(obj, x, y); - lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_PRIMARY1), 0); + etx_txt_color(obj, COLOR_THEME_PRIMARY1_INDEX); return obj; } @@ -238,12 +258,12 @@ void BarColorType::setText() } HSVColorType::HSVColorType(Window* parent, uint32_t color) : - BarColorType(parent) + BarColorType(parent) { auto r = GET_RED(color), g = GET_GREEN(color), b = GET_BLUE(color); float values[MAX_BARS]; RGBtoHSV(r, g, b, values[0], values[1], values[2]); - values[1] *= MAX_SATURATION; // convert the proper base + values[1] *= MAX_SATURATION; // convert the proper base values[2] *= MAX_BRIGHTNESS; for (auto i = 0; i < MAX_BARS; i++) { @@ -253,19 +273,19 @@ HSVColorType::HSVColorType(Window* parent, uint32_t color) : } // hue - bars[0]->getRGB = [=] (int pos) { + bars[0]->getRGB = [=](int pos) { auto rgb = HSVtoRGB(pos, bars[1]->value, bars[2]->value); return rgb; }; // saturation - bars[1]->getRGB = [=] (int pos) { + bars[1]->getRGB = [=](int pos) { auto rgb = HSVtoRGB(bars[0]->value, pos, bars[2]->value); return rgb; }; // brightness - bars[2]->getRGB = [=] (int pos) { + bars[2]->getRGB = [=](int pos) { auto rgb = HSVtoRGB(bars[0]->value, bars[1]->value, pos); return rgb; }; @@ -276,10 +296,7 @@ uint32_t HSVColorType::getRGB() return HSVtoRGB(bars[0]->value, bars[1]->value, bars[2]->value); } -const char* const* HSVColorType::getLabelChars() -{ - return HSVChars; -} +const char* const* HSVColorType::getLabelChars() { return HSVChars; } RGBColorType::RGBColorType(Window* parent, uint32_t color) : BarColorType(parent) @@ -306,74 +323,65 @@ uint32_t RGBColorType::getRGB() return RGB(bars[0]->value, bars[1]->value, bars[2]->value); } -const char* const* RGBColorType::getLabelChars() -{ - return RGBChars; -} +const char* const* RGBColorType::getLabelChars() { return RGBChars; } -void ThemeColorType::makeButton(Window* parent, uint32_t color) +void ThemeColorType::makeButton(Window* parent, uint16_t color) { auto btn = new TextButton(parent, rect_t{}, " "); + etx_bg_color(btn->getLvObj(), (LcdColorIndex)color); btn->setPressHandler([=]() { - auto cv = COLOR_VAL(color); + auto cv = lcdColorTable[color]; m_color = RGB(GET_RED(cv), GET_GREEN(cv), GET_BLUE(cv)); - lv_event_send(parent->getParent()->getParent()->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + lv_event_send(parent->getParent()->getParent()->getLvObj(), + LV_EVENT_VALUE_CHANGED, nullptr); return 0; }); - btn->padAll(lv_dpx(7)); - lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(color), LV_PART_MAIN); - lv_obj_add_style(btn->getLvObj(), &style, 0); } -void ThemeColorType::makeButtonsRow(Window* parent, uint32_t c1, uint32_t c2, uint32_t c3) +void ThemeColorType::makeButtonsRow(Window* parent, uint16_t c1, uint16_t c2, + uint16_t c3) { - auto hbox = new FormWindow(parent, rect_t{}); - hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); + auto hbox = new Window(parent, rect_t{}); + hbox->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM); + lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); makeButton(hbox, c1); makeButton(hbox, c2); - if (c3 != c2) - makeButton(hbox, c3); + if (c3 != c2) makeButton(hbox, c3); } -ThemeColorType::ThemeColorType(Window* parent, uint32_t color) : - ColorType() +ThemeColorType::ThemeColorType(Window* parent, uint32_t color) : ColorType() { m_color = color; - lv_style_init(&style); - lv_style_set_border_opa(&style, LV_OPA_100); - lv_style_set_border_width(&style, 2); - lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_GREY)); - - auto vbox = new FormWindow(parent, rect_t{}); - vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, lv_dpx(8)); - - makeButtonsRow(vbox, COLOR_THEME_PRIMARY1, COLOR_THEME_PRIMARY2, COLOR_THEME_PRIMARY3); - makeButtonsRow(vbox, COLOR_THEME_SECONDARY1, COLOR_THEME_SECONDARY2, COLOR_THEME_SECONDARY3); - makeButtonsRow(vbox, COLOR_THEME_FOCUS, COLOR_THEME_EDIT, COLOR_THEME_ACTIVE); - makeButtonsRow(vbox, COLOR_THEME_WARNING, COLOR_THEME_DISABLED, COLOR_THEME_DISABLED); + auto vbox = new Window(parent, rect_t{}); + vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_MEDIUM); + + makeButtonsRow(vbox, COLOR_THEME_PRIMARY1_INDEX, COLOR_THEME_PRIMARY2_INDEX, + COLOR_THEME_PRIMARY3_INDEX); + makeButtonsRow(vbox, COLOR_THEME_SECONDARY1_INDEX, + COLOR_THEME_SECONDARY2_INDEX, COLOR_THEME_SECONDARY3_INDEX); + makeButtonsRow(vbox, COLOR_THEME_FOCUS_INDEX, COLOR_THEME_EDIT_INDEX, + COLOR_THEME_ACTIVE_INDEX); + makeButtonsRow(vbox, COLOR_THEME_WARNING_INDEX, COLOR_THEME_DISABLED_INDEX, + COLOR_THEME_DISABLED_INDEX); } -uint32_t ThemeColorType::getRGB() -{ - return m_color; -} +uint32_t ThemeColorType::getRGB() { return m_color; } ///////////////////////////////////////////////////////////////////////// ////// ColorEditor Base class ///////////////////////////////////////////////////////////////////////// -ColorEditor::ColorEditor(Window *parent, const rect_t& rect, uint32_t color, - std::function setValue) : - FormWindow(parent, rect), - _setValue(std::move(setValue)), - _color(color) +ColorEditor::ColorEditor(Window* parent, const rect_t& rect, uint32_t color, + std::function setValue) : + Window(parent, rect), _setValue(std::move(setValue)), _color(color) { _colorType = new HSVColorType(this, color); _colorType->setText(); - lv_obj_add_event_cb(lvobj, ColorEditor::value_changed, LV_EVENT_VALUE_CHANGED, nullptr); + lv_obj_add_event_cb(lvobj, ColorEditor::value_changed, LV_EVENT_VALUE_CHANGED, + nullptr); } void ColorEditor::setColorEditorType(COLOR_EDITOR_TYPE colorType) @@ -392,6 +400,7 @@ void ColorEditor::setColorEditorType(COLOR_EDITOR_TYPE colorType) _colorType = new ThemeColorType(this, _color); setText(); } + // Update color bars invalidate(); } @@ -420,4 +429,3 @@ void ColorEditor::value_changed(lv_event_t* e) ColorEditor* edit = (ColorEditor*)lv_obj_get_user_data(target); if (edit) edit->setRGB(); } - diff --git a/radio/src/gui/colorlcd/color_editor.h b/radio/src/gui/colorlcd/color_editor.h index a5183b91d5f..027f238c27a 100644 --- a/radio/src/gui/colorlcd/color_editor.h +++ b/radio/src/gui/colorlcd/color_editor.h @@ -28,24 +28,8 @@ #include "listbox.h" constexpr int MAX_BARS = 3; -typedef std::function getRGBFromPos; -struct ColorBar : public FormField { - uint32_t maxValue = 0; - uint32_t value = 0; - bool invert = false; - getRGBFromPos getRGB = nullptr; - - ColorBar(Window* parent, const rect_t& r, uint32_t value = 0, - uint32_t maxValue = 0, bool invert = false); - - int valueToScreen(int value); - uint32_t screenToValue(int pos); - - static void pressing(lv_event_t* e); - static void on_key(lv_event_t* e); - static void draw_end(lv_event_t* e); -}; +class ColorBar; // ColorTypes() // A ColorType implements an editor for selecting a color. Currently we support HSV, RGB and SYS (choose from system defined colors) @@ -109,9 +93,8 @@ class ThemeColorType : public ColorType { protected: uint32_t m_color; - void makeButton(Window* parent, uint32_t color); - void makeButtonsRow(Window* parent, uint32_t c1, uint32_t c2, uint32_t c3); - lv_style_t style; + void makeButton(Window* parent, uint16_t color); + void makeButtonsRow(Window* parent, uint16_t c1, uint16_t c2, uint16_t c3); }; enum COLOR_EDITOR_TYPE @@ -122,7 +105,7 @@ enum COLOR_EDITOR_TYPE }; // the ColorEditor() control is a group of other controls -class ColorEditor : public FormWindow +class ColorEditor : public Window { public: ColorEditor(Window* parent, const rect_t& rect, uint32_t color, diff --git a/radio/src/gui/colorlcd/color_list.cpp b/radio/src/gui/colorlcd/color_list.cpp index a33c87abdd5..0c4bde67db3 100644 --- a/radio/src/gui/colorlcd/color_list.cpp +++ b/radio/src/gui/colorlcd/color_list.cpp @@ -18,32 +18,33 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + #include "color_list.h" + #include "color_editor.h" -#include "color_editor.h" +#include "themes/etx_lv_theme.h" -ColorList::ColorList( - Window *parent, const rect_t &rect, std::vector colors, - WindowFlags windowFlag, LcdFlags lcdFlags) : - ListBase(parent, rect, getColorListNames(colors)), - _colorList(colors), - _tp(ThemePersistance::instance()) +ColorList::ColorList(Window *parent, const rect_t &rect, + std::vector colors, LcdFlags lcdFlags) : + ListBox(parent, rect, getColorListNames(colors)), _colorList(colors) { setSelected(0); } -std::vector ColorList::getColorListNames(std::vector colors) +std::vector ColorList::getColorListNames( + std::vector colors) { std::vector names; char **colorNames = ThemePersistance::getColorNames(); for (auto color : colors) { names.emplace_back(colorNames[color.colorNumber]); } - + return names; } -void ColorList::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) +void ColorList::onDrawEnd(uint16_t row, uint16_t col, + lv_obj_draw_part_dsc_t *dsc) { lv_draw_rect_dsc_t rect_dsc; lv_draw_rect_dsc_init(&rect_dsc); @@ -65,8 +66,52 @@ void ColorList::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* ds rect_dsc.border_width = lv_dpx(1); uint16_t color = _colorList[row].colorValue; - rect_dsc.bg_color = lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color)); + rect_dsc.bg_color = + lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color)); rect_dsc.bg_opa = LV_OPA_100; lv_draw_rect(dsc->draw_ctx, &rect_dsc, &coords); } + +static void color_swatch_constructor(const lv_obj_class_t *class_p, + lv_obj_t *obj) +{ + etx_obj_add_style(obj, styles->bg_opacity_cover, LV_PART_MAIN); + etx_obj_add_style(obj, styles->border_thin, LV_PART_MAIN); + etx_obj_add_style(obj, styles->border_color_black, LV_PART_MAIN); +} + +static const lv_obj_class_t color_swatch_class = { + .base_class = &lv_obj_class, + .constructor_cb = color_swatch_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LV_SIZE_CONTENT, + .height_def = LV_SIZE_CONTENT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_obj_t), +}; + +static lv_obj_t *color_swatch_create(lv_obj_t *parent) +{ + return etx_create(&color_swatch_class, parent); +} + +ColorSwatch::ColorSwatch(Window *window, const rect_t &rect, uint32_t color) : + Window(window, rect, NO_FOCUS, 0, color_swatch_create) +{ + setColor(color); +} + +void ColorSwatch::setColor(uint32_t colorEntry) +{ + lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR2FLAGS(colorEntry)), + LV_PART_MAIN); +} + +void ColorSwatch::setColor(uint8_t r, uint8_t g, uint8_t b) +{ + lv_obj_set_style_bg_color(lvobj, lv_color_make(r, g, b), LV_PART_MAIN); +} diff --git a/radio/src/gui/colorlcd/color_list.h b/radio/src/gui/colorlcd/color_list.h index 4133a07bd6c..ed0b1b2c69e 100644 --- a/radio/src/gui/colorlcd/color_list.h +++ b/radio/src/gui/colorlcd/color_list.h @@ -18,21 +18,24 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + #pragma once + #include -#include #include +#include + #include "bitmapbuffer.h" #include "libopenui.h" -#include "theme_manager.h" #include "listbox.h" +#include "theme_manager.h" // a list of color theme names with their color to the right -class ColorList : public ListBase +class ColorList : public ListBox { public: - ColorList(Window *parent, const rect_t &rect, std::vector colors, - WindowFlags windowFlags = 0, LcdFlags lcdFlags = 0); + ColorList(Window* parent, const rect_t& rect, std::vector colors, + LcdFlags lcdFlags = 0); inline ColorEntry getSelectedColor() { @@ -46,14 +49,22 @@ class ColorList : public ListBase inline void setColorList(std::vector colorList) { this->_colorList = colorList; - ListBase::setNames(getColorListNames(colorList)); - invalidate(); + ListBox::setNames(getColorListNames(colorList)); } protected: std::vector _colorList; - ThemePersistance *_tp; void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc); }; +class ColorSwatch : public Window +{ + public: + ColorSwatch(Window* window, const rect_t& rect, uint32_t color); + + void setColor(uint32_t colorEntry); + void setColor(uint8_t r, uint8_t g, uint8_t b); + + protected: +}; diff --git a/radio/src/gui/colorlcd/color_picker.cpp b/radio/src/gui/colorlcd/color_picker.cpp index 569cedf2c3b..93772db5df7 100644 --- a/radio/src/gui/colorlcd/color_picker.cpp +++ b/radio/src/gui/colorlcd/color_picker.cpp @@ -20,81 +20,89 @@ */ #include "color_picker.h" + #include "color_editor.h" +#include "color_list.h" +#include "themes/etx_lv_theme.h" // based on LVGL default switch size constexpr lv_coord_t COLOR_PAD_WIDTH = (4 * LV_DPI_DEF) / 10; -constexpr lv_coord_t COLOR_PAD_HEIGHT = (4 * LV_DPI_DEF) / 17; +constexpr lv_coord_t COLOR_PAD_HEIGHT = 32; #if LCD_W > LCD_H // Landscape static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; + +#define COLOR_EDIT_WIDTH LCD_W * 0.8 + #else // Portrait static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; + +#define COLOR_EDIT_WIDTH LCD_W * 0.7 + #endif -class ColorEditorPopup : public Dialog +class ColorEditorPopup : public BaseDialog { - lv_obj_t* colorPad = nullptr; - lv_obj_t* hexStr = nullptr; + ColorSwatch* colorPad = nullptr; + StaticText* hexStr = nullptr; uint32_t m_color; void updateColor(uint32_t c) { m_color = c; - auto r = GET_RED(c), g = GET_GREEN(c), b = GET_BLUE(c); + uint8_t r = GET_RED(c), g = GET_GREEN(c), b = GET_BLUE(c); + + colorPad->setColor(r, g, b); - auto lvcolor = lv_color_make(r, g, b); - lv_obj_set_style_bg_color(colorPad, lvcolor, LV_PART_MAIN); - lv_label_set_text_fmt(hexStr, "%02X%02X%02X", - (uint16_t)r, (uint16_t)g, (uint16_t)b); + char s[10]; + sprintf(s, "%02X%02X%02X", r, g, b); + hexStr->setText(s); } - + public: ColorEditorPopup(Window* parent, uint32_t color, std::function _setValue) : - Dialog(parent, STR_COLOR_PICKER, rect_t{}) + BaseDialog(parent, STR_COLOR_PICKER, false, COLOR_EDIT_WIDTH, + LV_SIZE_CONTENT) { - lv_obj_set_style_bg_color(content->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0); - - auto form = &content->form; - FlexGridLayout grid(col_dsc, row_dsc); - auto line = form->newLine(&grid); + auto line = form->newLine(grid); - rect_t r{ 0, 0, 7 * LV_DPI_DEF / 5, 7 * LV_DPI_DEF / 5 }; - auto cedit = new ColorEditor(line, r, color, [=](uint32_t c) { updateColor(c); }); - lv_obj_set_style_grid_cell_x_align(cedit->getLvObj(), LV_GRID_ALIGN_CENTER, 0); + rect_t r{0, 0, 7 * LV_DPI_DEF / 5, 7 * LV_DPI_DEF / 5}; + auto cedit = + new ColorEditor(line, r, color, [=](uint32_t c) { updateColor(c); }); + lv_obj_set_style_grid_cell_x_align(cedit->getLvObj(), LV_GRID_ALIGN_CENTER, + 0); - auto vbox = new FormWindow(line, rect_t{}); - lv_obj_set_style_grid_cell_x_align(vbox->getLvObj(), LV_GRID_ALIGN_CENTER, 0); - vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, lv_dpx(8)); - vbox->setWidth(r.w); - vbox->setHeight(r.h); + auto vbox = new Window(line, rect_t{}); + lv_obj_set_style_grid_cell_x_align(vbox->getLvObj(), LV_GRID_ALIGN_CENTER, + 0); + vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_MEDIUM, r.w, r.h); - auto hbox = new FormWindow(vbox, rect_t{}); - hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); + auto hbox = new Window(vbox, rect_t{}); + hbox->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM); auto hbox_obj = hbox->getLvObj(); - lv_obj_set_flex_align(hbox_obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_SPACE_AROUND); + lv_obj_set_flex_align(hbox_obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, + LV_FLEX_ALIGN_SPACE_AROUND); - colorPad = window_create(hbox_obj); - lv_obj_set_style_bg_opa(colorPad, LV_OPA_100, LV_PART_MAIN); - lv_obj_set_size(colorPad, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT); + colorPad = new ColorSwatch(hbox, {0, 0, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT}, + COLOR_THEME_PRIMARY1); - hexStr = lv_label_create(hbox_obj); - lv_obj_set_style_text_font(hexStr, getFont(FONT(L)), LV_PART_MAIN); - lv_obj_set_style_text_color(hexStr, makeLvColor(COLOR_THEME_PRIMARY1), LV_PART_MAIN); + hexStr = new StaticText(hbox, {0, 0, 100, 0}, "", + COLOR_THEME_PRIMARY1 | FONT(L)); updateColor(color); - - hbox = new FormWindow(vbox, rect_t{}); - hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); + + hbox = new Window(vbox, rect_t{}); + hbox->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM); + lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); auto rgbBtn = new TextButton(hbox, rect_t{}, "RGB"); auto hsvBtn = new TextButton(hbox, rect_t{}, "HSV"); @@ -106,7 +114,7 @@ class ColorEditorPopup : public Dialog thmBtn->check(false); return 1; }); - rgbBtn->padAll(lv_dpx(8)); + rgbBtn->padAll(PAD_MEDIUM); hsvBtn->setPressHandler([=]() { cedit->setColorEditorType(HSV_COLOR_EDITOR); @@ -114,7 +122,7 @@ class ColorEditorPopup : public Dialog thmBtn->check(false); return 1; }); - hsvBtn->padAll(lv_dpx(8)); + hsvBtn->padAll(PAD_MEDIUM); thmBtn->setPressHandler([=]() { cedit->setColorEditorType(THM_COLOR_EDITOR); @@ -122,66 +130,45 @@ class ColorEditorPopup : public Dialog hsvBtn->check(false); return 1; }); - thmBtn->padAll(lv_dpx(8)); + thmBtn->padAll(PAD_MEDIUM); // color editor defaults to HSV hsvBtn->check(true); - - hbox = new FormWindow(vbox, rect_t{}); - hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_END, LV_FLEX_ALIGN_SPACE_BETWEEN); + + hbox = new Window(vbox, rect_t{}); + hbox->padTop(60); + hbox->setFlexLayout(LV_FLEX_FLOW_ROW, 20); + lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_END, LV_FLEX_ALIGN_SPACE_BETWEEN); lv_obj_set_flex_grow(hbox->getLvObj(), 1); - auto cancelBtn = new TextButton(hbox, rect_t{}, STR_CANCEL, [=]() -> int8_t { + new TextButton(hbox, rect_t{0, 0, 80, 0}, STR_CANCEL, [=]() -> int8_t { this->deleteLater(); return 0; }); - cancelBtn->padTop(lv_dpx(12)); - cancelBtn->padBottom(lv_dpx(12)); - lv_obj_set_flex_grow(cancelBtn->getLvObj(), 1); - auto okBtn = new TextButton(hbox, rect_t{}, STR_SAVE, [=]() -> int8_t { + new TextButton(hbox, rect_t{0, 0, 80, 0}, STR_SAVE, [=]() -> int8_t { if (_setValue) _setValue(m_color); this->deleteLater(); return 0; }); - okBtn->padTop(lv_dpx(12)); - okBtn->padBottom(lv_dpx(12)); - lv_obj_set_flex_grow(okBtn->getLvObj(), 1); - -#if LCD_W > LCD_H - content->setWidth(LCD_W * 0.9); -#else - content->setWidth(LCD_W * 0.8); -#endif - content->updateSize(); } }; -static void color_editor_popup(lv_event_t* e) -{ - auto picker = (ColorPicker*)lv_event_get_user_data(e); - if (picker) { - new ColorEditorPopup(picker, picker->getColor(), - [=](uint32_t c) { picker->setColor(c); }); - } -} - ColorPicker::ColorPicker(Window* parent, const rect_t& rect, std::function getValue, std::function setValue) : - FormField(parent, rect, 0, 0, etx_button_create), + Button(parent, {0, 0, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT}), setValue(std::move(setValue)) { - lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN); - lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_STATE_FOCUS_KEY); - - lv_obj_set_size(lvobj, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT); - lv_obj_add_event_cb(lvobj, color_editor_popup, LV_EVENT_CLICKED, this); - updateColor(getValue()); } +void ColorPicker::onClicked() +{ + new ColorEditorPopup(this, getColor(), [=](uint32_t c) { setColor(c); }); +} + void ColorPicker::setColor(uint32_t c) { setValue(c); @@ -192,7 +179,7 @@ void ColorPicker::updateColor(uint32_t c) { color = c; - auto lvcolor = lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color)); + auto lvcolor = + lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color)); lv_obj_set_style_bg_color(lvobj, lvcolor, LV_PART_MAIN); - lv_obj_set_style_bg_color(lvobj, lvcolor, LV_STATE_FOCUS_KEY); } diff --git a/radio/src/gui/colorlcd/color_picker.h b/radio/src/gui/colorlcd/color_picker.h index 5a1d6386d21..b120b751b4e 100644 --- a/radio/src/gui/colorlcd/color_picker.h +++ b/radio/src/gui/colorlcd/color_picker.h @@ -21,9 +21,9 @@ #pragma once -#include "form.h" +#include "button.h" -class ColorPicker : public FormField +class ColorPicker : public Button { uint32_t color; std::function setValue; @@ -37,4 +37,6 @@ class ColorPicker : public FormField void setColor(uint32_t c); uint32_t getColor() const { return color; } + + void onClicked() override; }; diff --git a/radio/src/gui/colorlcd/colors.cpp b/radio/src/gui/colorlcd/colors.cpp index ea9024340bb..da67682b5e3 100644 --- a/radio/src/gui/colorlcd/colors.cpp +++ b/radio/src/gui/colorlcd/colors.cpp @@ -20,86 +20,135 @@ */ #include "colors.h" -#include + #include -uint16_t lcdColorTable[LCD_COLOR_COUNT]; +#include + +const uint16_t defaultColors[] = { + RGB(0, 0, 0), // PRIMARY1 + RGB(255, 255, 255), // PRIMARY2 + RGB(12, 63, 102), // PRIMARY3 + RGB(18, 94, 153), // SECONDARY1 + RGB(182, 224, 242), // SECONDARY2 + RGB(228, 238, 242), // SECONDARY3 + RGB(20, 161, 229), // FOCUS + RGB(0, 153, 9), // EDIT + RGB(255, 222, 0), // ACTIVE + RGB(224, 0, 0), // WARNING + RGB(140, 140, 140), // DISABLED + RGB(170, 85, 0), // CUSTOM + RGB(0, 0, 0), // FIXED BLACK + RGB(255, 255, 255), // FIXED WHITE + RGB(128, 128, 128), // FIXED GREY +}; + +// Needs to be initialised at compile time so widget color options work +uint16_t lcdColorTable[] = { + RGB(0, 0, 0), // PRIMARY1 + RGB(255, 255, 255), // PRIMARY2 + RGB(12, 63, 102), // PRIMARY3 + RGB(18, 94, 153), // SECONDARY1 + RGB(182, 224, 242), // SECONDARY2 + RGB(228, 238, 242), // SECONDARY3 + RGB(20, 161, 229), // FOCUS + RGB(0, 153, 9), // EDIT + RGB(255, 222, 0), // ACTIVE + RGB(224, 0, 0), // WARNING + RGB(140, 140, 140), // DISABLED + RGB(170, 85, 0), // CUSTOM + RGB(0, 0, 0), // FIXED BLACK + RGB(255, 255, 255), // FIXED WHITE + RGB(128, 128, 128), // FIXED GREY +}; uint32_t HSVtoRGB(float H, float S, float V) { - if (H > 360 || H < 0 || S > 100 || S < 0 || V > 100 || V < 0) { - return 0; - } + if (H > 360 || H < 0 || S > 100 || S < 0 || V > 100 || V < 0) { + return 0; + } - float s = S / 100; - float v = V / 100; - float C = s * v; - float X = C * (1 - abs(fmod(H / 60.0, 2) - 1)); - float m = v - C; - float r, g, b; + float s = S / 100; + float v = V / 100; + float C = s * v; + float X = C * (1 - abs(fmod(H / 60.0, 2) - 1)); + float m = v - C; + float r, g, b; - if (H >= 0 && H < 60) { - r = C, g = X, b = 0; - } - else if (H >= 60 && H < 120) { - r = X, g = C, b = 0; - } - else if (H >= 120 && H < 180) { - r = 0, g = C, b = X; - } - else if (H >= 180 && H < 240) { - r = 0, g = X, b = C; - } - else if (H >= 240 && H < 300) { - r = X, g = 0, b = C; - } - else { - r = C, g = 0, b = X; - } - int R = (r + m) * 255; - int G = (g + m) * 255; - int B = (b + m) * 255; + if (H >= 0 && H < 60) { + r = C, g = X, b = 0; + } else if (H >= 60 && H < 120) { + r = X, g = C, b = 0; + } else if (H >= 120 && H < 180) { + r = 0, g = C, b = X; + } else if (H >= 180 && H < 240) { + r = 0, g = X, b = C; + } else if (H >= 240 && H < 300) { + r = X, g = 0, b = C; + } else { + r = C, g = 0, b = X; + } + int R = (r + m) * 255; + int G = (g + m) * 255; + int B = (b + m) * 255; - return RGB(R, G, B); + return RGB(R, G, B); } -void RGBtoHSV(uint8_t R, uint8_t G, uint8_t B, float& fH, float& fS, float& fV) +void RGBtoHSV(uint8_t R, uint8_t G, uint8_t B, float &fH, float &fS, float &fV) { - float fR = (float)R / 255; - float fG = (float)G / 255; - float fB = (float)B / 255; - float fCMax = std::max(std::max(fR, fG), fB); - float fCMin = std::min(std::min(fR, fG), fB); - float fDelta = fCMax - fCMin; - - if (fDelta > 0) { - if (fCMax == fR) { - fH = 60 * (fmod(((fG - fB) / fDelta), 6)); - } - else if (fCMax == fG) { - fH = 60 * (((fB - fR) / fDelta) + 2); - } - else if (fCMax == fB) { - fH = 60 * (((fR - fG) / fDelta) + 4); - } - - if (fCMax > 0) { - fS = fDelta / fCMax; - } - else { - fS = 0; - } - - fV = fCMax; - } - else { - fH = 0; - fS = 0; - fV = fCMax; + float fR = (float)R / 255; + float fG = (float)G / 255; + float fB = (float)B / 255; + float fCMax = std::max(std::max(fR, fG), fB); + float fCMin = std::min(std::min(fR, fG), fB); + float fDelta = fCMax - fCMin; + + if (fDelta > 0) { + if (fCMax == fR) { + fH = 60 * (fmod(((fG - fB) / fDelta), 6)); + } else if (fCMax == fG) { + fH = 60 * (((fB - fR) / fDelta) + 2); + } else if (fCMax == fB) { + fH = 60 * (((fR - fG) / fDelta) + 4); } - if (fH < 0) { - fH = 360 + fH; + if (fCMax > 0) { + fS = fDelta / fCMax; + } else { + fS = 0; } + + fV = fCMax; + } else { + fH = 0; + fS = 0; + fV = fCMax; + } + + if (fH < 0) { + fH = 360 + fH; + } +} + +// TODO: work out how to remove this function +LcdColorIndex indexFromColor(uint32_t lcdFlags) +{ + uint16_t color = COLOR_VAL(lcdFlags); + + for (uint8_t i = 0; i < TOTAL_COLOR_COUNT; i += 1) + if (lcdColorTable[i] == color) return (LcdColorIndex)i; + + return CUSTOM_COLOR_INDEX; } +/** + * Helper function to translate a colorFlags value to a lv_color_t suitable + * for passing to an lv_obj function + * @param colorFlags a textFlags value. This value will contain the color shifted by 16 bits. + */ +lv_color_t makeLvColor(uint32_t colorFlags) +{ + auto color = COLOR_VAL(colorFlags); + return lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color)); +} diff --git a/radio/src/gui/colorlcd/colors.h b/radio/src/gui/colorlcd/colors.h index db516d77547..97299e76f74 100644 --- a/radio/src/gui/colorlcd/colors.h +++ b/radio/src/gui/colorlcd/colors.h @@ -19,16 +19,15 @@ * GNU General Public License for more details. */ -#ifndef _COLORS_H_ -#define _COLORS_H_ +#pragma once + +#include #include "libopenui_defines.h" // TODO common code, not in target enum LcdColorIndex { - // this one first for when colour is not set - DEFAULT_COLOR_INDEX, - + // Variable colors COLOR_THEME_PRIMARY1_INDEX, COLOR_THEME_PRIMARY2_INDEX, COLOR_THEME_PRIMARY3_INDEX, @@ -42,52 +41,51 @@ enum LcdColorIndex { COLOR_THEME_DISABLED_INDEX, CUSTOM_COLOR_INDEX, - // this one MUST be last + // Variable count LCD_COLOR_COUNT, + + // Fixed Colors + COLOR_BLACK_INDEX = LCD_COLOR_COUNT, + COLOR_WHITE_INDEX, + COLOR_GREY_INDEX, + + TOTAL_COLOR_COUNT, }; -#define ARGB_SPLIT(color, a, r, g, b) \ +#define ARGB_SPLIT(color, a, r, g, b) \ uint16_t a = ((color) & 0xF000) >> 12; \ - uint16_t r = ((color) & 0x0F00) >> 8; \ - uint16_t g = ((color) & 0x00F0) >> 4; \ + uint16_t r = ((color) & 0x0F00) >> 8; \ + uint16_t g = ((color) & 0x00F0) >> 4; \ uint16_t b = ((color) & 0x000F) -#define RGB_SPLIT(color, r, g, b) \ +#define RGB_SPLIT(color, r, g, b) \ uint16_t r = ((color) & 0xF800) >> 11; \ - uint16_t g = ((color) & 0x07E0) >> 5; \ + uint16_t g = ((color) & 0x07E0) >> 5; \ uint16_t b = ((color) & 0x001F) #define ARGB_JOIN(a, r, g, b) \ - (((a&0xF) << 12) + ((r&0xF) << 8) + ((g&0xF) << 4) + (b&0xF)) + (((a & 0xF) << 12) + ((r & 0xF) << 8) + ((g & 0xF) << 4) + (b & 0xF)) -#define RGB_JOIN(r, g, b) \ - (((r) << 11) + ((g) << 5) + (b)) +#define RGB_JOIN(r, g, b) (((r) << 11) + ((g) << 5) + (b)) -#define GET_RED(color) \ - (((color) & 0xF800) >> 8) +#define GET_RED(color) (((color) & 0xF800) >> 8) -#define GET_GREEN(color) \ - (((color) & 0x07E0) >> 3) +#define GET_GREEN(color) (((color) & 0x07E0) >> 3) -#define GET_BLUE(color) \ - (((color) & 0x001F) << 3) +#define GET_BLUE(color) (((color) & 0x001F) << 3) -#define OPACITY_MAX 0x0Fu -#define OPACITY(value) ((value) & OPACITY_MAX) +#define OPACITY_MAX 0x0Fu +#define OPACITY(value) ((value) & OPACITY_MAX) -#define RGB(r, g, b) (uint16_t)((((r) & 0xF8) << 8) + (((g) & 0xFC) << 3) + (((b) & 0xF8) >> 3)) -#define ARGB(a, r, g, b) (uint16_t)((((a) & 0xF0) << 8) + (((r) & 0xF0) << 4) + (((g) & 0xF0) << 0) + (((b) & 0xF0) >> 4)) +#define RGB(r, g, b) \ + (uint16_t)((((r) & 0xF8) << 8) + (((g) & 0xFC) << 3) + (((b) & 0xF8) >> 3)) +#define ARGB(a, r, g, b) \ + (uint16_t)((((a) & 0xF0) << 8) + (((r) & 0xF0) << 4) + (((g) & 0xF0) << 0) + \ + (((b) & 0xF0) >> 4)) -#define COLOR2FLAGS(color) LcdFlags(unsigned(color) << 16u) -#define COLOR_VAL(flags) ((flags) >> 16u) -#define COLOR_MASK(flags) ((flags) & 0xFFFF0000u) - -// -// Basic color definitions -// - -#define WHITE RGB(0xFF, 0xFF, 0xFF) -#define BLACK RGB(0, 0, 0) +#define COLOR2FLAGS(color) LcdFlags(unsigned(color) << 16u) +#define COLOR_VAL(flags) ((flags) >> 16u) +#define COLOR_MASK(flags) ((flags) & 0xFFFF0000u) #define RGB_FLAG 0x8000u #define RGB2FLAGS(r, g, b) (COLOR2FLAGS(RGB(r, g, b)) | RGB_FLAG) @@ -95,33 +93,39 @@ enum LcdColorIndex { // // Indexed colors // -extern uint16_t lcdColorTable[LCD_COLOR_COUNT]; +extern uint16_t lcdColorTable[]; +extern const uint16_t defaultColors[]; inline void lcdSetColor(uint16_t color) { lcdColorTable[CUSTOM_COLOR_INDEX] = color; } -#define COLOR(index) \ - ((uint32_t) \ - lcdColorTable[unsigned(index & 0xFF) >= LCD_COLOR_COUNT \ - ? DEFAULT_COLOR_INDEX \ - : ((index & 0xFF) == 0 ? COLOR_THEME_PRIMARY1_INDEX \ - : unsigned(index & 0xFF))] \ +LcdColorIndex indexFromColor(uint32_t lcdFlags); + +#define COLOR(index) \ + ((uint32_t) \ + lcdColorTable[unsigned(index & 0xFF) >= TOTAL_COLOR_COUNT \ + ? COLOR_WHITE_INDEX \ + : unsigned(index & 0xFF)] \ << 16u) -#define COLOR_THEME_PRIMARY1 COLOR(COLOR_THEME_PRIMARY1_INDEX) -#define COLOR_THEME_PRIMARY2 COLOR(COLOR_THEME_PRIMARY2_INDEX) -#define COLOR_THEME_PRIMARY3 COLOR(COLOR_THEME_PRIMARY3_INDEX) -#define COLOR_THEME_SECONDARY1 COLOR(COLOR_THEME_SECONDARY1_INDEX) -#define COLOR_THEME_SECONDARY2 COLOR(COLOR_THEME_SECONDARY2_INDEX) -#define COLOR_THEME_SECONDARY3 COLOR(COLOR_THEME_SECONDARY3_INDEX) -#define COLOR_THEME_FOCUS COLOR(COLOR_THEME_FOCUS_INDEX) -#define COLOR_THEME_EDIT COLOR(COLOR_THEME_EDIT_INDEX) -#define COLOR_THEME_ACTIVE COLOR(COLOR_THEME_ACTIVE_INDEX) -#define COLOR_THEME_WARNING COLOR(COLOR_THEME_WARNING_INDEX) -#define COLOR_THEME_DISABLED COLOR(COLOR_THEME_DISABLED_INDEX) -#define CUSTOM_COLOR COLOR(CUSTOM_COLOR_INDEX) +#define COLOR_BLACK COLOR(COLOR_BLACK_INDEX) +#define COLOR_WHITE COLOR(COLOR_WHITE_INDEX) +#define COLOR_GREY COLOR(COLOR_GREY_INDEX) + +#define COLOR_THEME_PRIMARY1 COLOR(COLOR_THEME_PRIMARY1_INDEX) +#define COLOR_THEME_PRIMARY2 COLOR(COLOR_THEME_PRIMARY2_INDEX) +#define COLOR_THEME_PRIMARY3 COLOR(COLOR_THEME_PRIMARY3_INDEX) +#define COLOR_THEME_SECONDARY1 COLOR(COLOR_THEME_SECONDARY1_INDEX) +#define COLOR_THEME_SECONDARY2 COLOR(COLOR_THEME_SECONDARY2_INDEX) +#define COLOR_THEME_SECONDARY3 COLOR(COLOR_THEME_SECONDARY3_INDEX) +#define COLOR_THEME_FOCUS COLOR(COLOR_THEME_FOCUS_INDEX) +#define COLOR_THEME_EDIT COLOR(COLOR_THEME_EDIT_INDEX) +#define COLOR_THEME_ACTIVE COLOR(COLOR_THEME_ACTIVE_INDEX) +#define COLOR_THEME_WARNING COLOR(COLOR_THEME_WARNING_INDEX) +#define COLOR_THEME_DISABLED COLOR(COLOR_THEME_DISABLED_INDEX) +#define CUSTOM_COLOR COLOR(CUSTOM_COLOR_INDEX) #if defined(WINDOWS_INSPECT_BORDERS) #define WINDOWS_INSPECT_BORDER_COLOR COLOR_THEME_PRIMARY3 @@ -135,4 +139,4 @@ extern uint32_t HSVtoRGB(float H, float S, float V); extern void RGBtoHSV(uint8_t R, uint8_t G, uint8_t B, float& fH, float& fS, float& fV); -#endif // _COLORS_H_ +lv_color_t makeLvColor(uint32_t colorFlags); diff --git a/radio/src/gui/colorlcd/confirm_dialog.cpp b/radio/src/gui/colorlcd/confirm_dialog.cpp deleted file mode 100644 index 38c11396850..00000000000 --- a/radio/src/gui/colorlcd/confirm_dialog.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" -#include "confirm_dialog.h" -#include "static.h" - -ConfirmDialog::ConfirmDialog(Window* parent, const char* title, - const char* message, - std::function confirmHandler, - std::function cancelHandler) : - Dialog(parent, title, rect_t{}), - confirmHandler(std::move(confirmHandler)), - cancelHandler(std::move(cancelHandler)) -{ - auto form = &content->form; - auto msg = new StaticText(form, rect_t{}, message); - msg->padAll(lv_dpx(16)); - - lv_obj_set_style_bg_color(content->getLvObj(), - makeLvColor(COLOR_THEME_SECONDARY3), 0); - - auto box = new FormWindow(form, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW); - lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0); - - auto btn = new TextButton(box, rect_t{}, STR_NO, [=]() -> int8_t { - onCancel(); - return 0; - }); -#if LCD_W > LCD_H - btn->setWidth(LV_DPI_DEF); -#else - btn->setWidth(LV_DPI_DEF * 3 / 4); -#endif - - btn = new TextButton(box, rect_t{}, STR_YES, [=]() -> int8_t { - this->deleteLater(); - this->confirmHandler(); - return 0; - }); -#if LCD_W > LCD_H - btn->setWidth(LV_DPI_DEF); -#else - btn->setWidth(LV_DPI_DEF * 3 / 4); -#endif - - content->setWidth(LCD_W * 0.8); - content->updateSize(); -} - -void ConfirmDialog::onCancel() -{ - deleteLater(); - if (cancelHandler) cancelHandler(); -} diff --git a/radio/src/gui/colorlcd/confirm_dialog.h b/radio/src/gui/colorlcd/confirm_dialog.h deleted file mode 100644 index 6940af6221c..00000000000 --- a/radio/src/gui/colorlcd/confirm_dialog.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _CONFIRM_DIALOG_H_ -#define _CONFIRM_DIALOG_H_ - -#include "dialog.h" - -class ConfirmDialog : public Dialog -{ - public: - ConfirmDialog(Window* parent, const char* title, const char* message, - std::function confirmHandler, - std::function cancelHandler = nullptr); - - protected: - std::function confirmHandler; - std::function cancelHandler; - - void onCancel() override; -}; - -#endif // _CONFIRM_DIALOG_H_ diff --git a/radio/src/gui/colorlcd/crossfire_settings.cpp b/radio/src/gui/colorlcd/crossfire_settings.cpp index 6865c72579e..089f62d617f 100644 --- a/radio/src/gui/colorlcd/crossfire_settings.cpp +++ b/radio/src/gui/colorlcd/crossfire_settings.cpp @@ -30,14 +30,14 @@ CrossfireSettings::CrossfireSettings(Window* parent, const FlexGridLayout& g, uint8_t moduleIdx) : - FormWindow(parent, rect_t{}), md(&g_model.moduleData[moduleIdx]) + Window(parent, rect_t{}), md(&g_model.moduleData[moduleIdx]) { FlexGridLayout grid(g); setFlexLayout(); if (moduleIdx == EXTERNAL_MODULE) { - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_BAUDRATE, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_BAUDRATE, COLOR_THEME_PRIMARY1); new Choice( line, rect_t{}, STR_CRSF_BAUDRATE, 0, CROSSFIRE_MAX_INTERNAL_BAUDRATE, [=]() -> int { @@ -57,8 +57,8 @@ CrossfireSettings::CrossfireSettings(Window* parent, const FlexGridLayout& g, // 0, COLOR_THEME_PRIMARY1); } - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_STATUS, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_STATUS, COLOR_THEME_PRIMARY1); new DynamicText(line, rect_t{}, [=] { char msg[64] = ""; // sprintf(msg, "%d Hz %" PRIu32 " Err", 1000000 / getMixerSchedulerPeriod(), diff --git a/radio/src/gui/colorlcd/crossfire_settings.h b/radio/src/gui/colorlcd/crossfire_settings.h index 91ffcd53ebb..748f55d2138 100644 --- a/radio/src/gui/colorlcd/crossfire_settings.h +++ b/radio/src/gui/colorlcd/crossfire_settings.h @@ -26,7 +26,7 @@ struct ModuleData; -class CrossfireSettings : public FormWindow, public ModuleOptions +class CrossfireSettings : public Window, public ModuleOptions { ModuleData* md; diff --git a/radio/src/gui/colorlcd/curve.cpp b/radio/src/gui/colorlcd/curve.cpp index 14ee870db27..f955c472673 100644 --- a/radio/src/gui/colorlcd/curve.cpp +++ b/radio/src/gui/colorlcd/curve.cpp @@ -19,231 +19,241 @@ * GNU General Public License for more details. */ -#include "opentx.h" #include "curve.h" -#include "lcd.h" + #include "bitmaps.h" +#include "lcd.h" +#include "opentx.h" #include "strhelpers.h" -#include "font.h" #include "theme.h" -const uint8_t _LBM_CURVE_POINT[] = { -#include "mask_cvpoint.lbm" -}; - -const uint8_t _LBM_CURVE_POINT_CENTER[] = { -#include "mask_cvpoint_center.lbm" -}; - -const uint8_t _LBM_CURVE_COORD_SHADOW[] = { -#include "mask_coord_shadow.lbm" -}; - -IMPL_LZ4_BITMAP(LBM_CURVE_POINT); -IMPL_LZ4_BITMAP(LBM_CURVE_POINT_CENTER); -IMPL_LZ4_BITMAP(LBM_CURVE_COORD_SHADOW); +//----------------------------------------------------------------------------- -// Base curve rendering class to 'paint' the background and curve. -CurveRenderer::CurveRenderer(const rect_t & rect, std::function function): - rect(rect), - function(std::move(function)) +// Base curve rendering class to draw the background and curve. +CurveRenderer::CurveRenderer(Window* parent, const rect_t& rect, + std::function function) : + valueFunc(std::move(function)) { + dx = rect.x; + dy = rect.y; + dw = rect.w; + dh = rect.h; + + lv_obj_t* bgBox = lv_line_create(parent->getLvObj()); + etx_obj_add_style(bgBox, styles->graph_border, LV_PART_MAIN); + + lv_obj_t* axis1 = lv_line_create(parent->getLvObj()); + etx_obj_add_style(axis1, styles->graph_border, LV_PART_MAIN); + lv_obj_t* axis2 = lv_line_create(parent->getLvObj()); + etx_obj_add_style(axis2, styles->graph_border, LV_PART_MAIN); + + lv_obj_t* extra1 = lv_line_create(parent->getLvObj()); + etx_obj_add_style(extra1, styles->graph_dashed, LV_PART_MAIN); + lv_obj_t* extra2 = lv_line_create(parent->getLvObj()); + etx_obj_add_style(extra2, styles->graph_dashed, LV_PART_MAIN); + lv_obj_t* extra3 = lv_line_create(parent->getLvObj()); + etx_obj_add_style(extra3, styles->graph_dashed, LV_PART_MAIN); + lv_obj_t* extra4 = lv_line_create(parent->getLvObj()); + etx_obj_add_style(extra4, styles->graph_dashed, LV_PART_MAIN); + + // Outer box + bgPoints[0] = {dx, dy}; + bgPoints[1] = {(lv_coord_t)(dx + dw - 1), dy}; + bgPoints[2] = {(lv_coord_t)(dx + dw - 1), (lv_coord_t)(dy + dh - 1)}; + bgPoints[3] = {dx, (lv_coord_t)(dy + dh - 1)}; + bgPoints[4] = {dx, dy}; + + lv_line_set_points(bgBox, bgPoints, 5); + + // Axis lines + bgPoints[5] = {(lv_coord_t)(dx + dw / 2), dy}; + bgPoints[6] = {(lv_coord_t)(dx + dw / 2), (lv_coord_t)(dy + dh - 1)}; + bgPoints[7] = {dx, (lv_coord_t)(dy + dh / 2)}; + bgPoints[8] = {(lv_coord_t)(dx + dw - 1), (lv_coord_t)(dy + dh / 2)}; + + lv_line_set_points(axis1, &bgPoints[5], 2); + lv_line_set_points(axis2, &bgPoints[7], 2); + + // Extra lines + bgPoints[9] = {(lv_coord_t)(dx + dw / 4), dy}; + bgPoints[10] = {(lv_coord_t)(dx + dw / 4), (lv_coord_t)(dy + dh - 1)}; + bgPoints[11] = {(lv_coord_t)(dx + dw * 3 / 4), dy}; + bgPoints[12] = {(lv_coord_t)(dx + dw * 3 / 4), (lv_coord_t)(dy + dh - 1)}; + bgPoints[13] = {dx, (lv_coord_t)(dy + dh / 4)}; + bgPoints[14] = {(lv_coord_t)(dx + dw - 1), (lv_coord_t)(dy + dh / 4)}; + bgPoints[15] = {dx, (lv_coord_t)(dy + dh * 3 / 4)}; + bgPoints[16] = {(lv_coord_t)(dx + dw - 1), (lv_coord_t)(dy + dh * 3 / 4)}; + + lv_line_set_points(extra1, &bgPoints[9], 2); + lv_line_set_points(extra2, &bgPoints[11], 2); + lv_line_set_points(extra3, &bgPoints[13], 2); + lv_line_set_points(extra4, &bgPoints[15], 2); + + // Curve points + lnPoints = new lv_point_t[dw]; + + ptLine = lv_line_create(parent->getLvObj()); + etx_obj_add_style(ptLine, styles->graph_line, LV_PART_MAIN); + + update(); } -coord_t CurveRenderer::getPointY(int y) const +CurveRenderer::~CurveRenderer() { - return dy + limit(0, - dh / 2 - divRoundClosest(y * dh / 2, RESX), - dh - 1); + if (lnPoints) delete lnPoints; } -void CurveRenderer::drawBackground(BitmapBuffer * dc) +void CurveRenderer::update() { - dc->drawSolidFilledRect(rect.x, rect.y, rect.w, rect.h, COLOR_THEME_PRIMARY2); - - // Axis - dc->drawSolidHorizontalLine(dx, dy+dh/2, dw, COLOR_THEME_SECONDARY2); - dc->drawSolidVerticalLine(dx+dw/2, dy, dh, COLOR_THEME_SECONDARY2); - - // Extra lines - dc->drawVerticalLine(dx+dw/4, dy, dh, STASHED, COLOR_THEME_SECONDARY2); - dc->drawVerticalLine(dx+dw*3/4, dy, dh, STASHED, COLOR_THEME_SECONDARY2); - dc->drawHorizontalLine(dx, dy+dh/4, dw, STASHED, COLOR_THEME_SECONDARY2); - dc->drawHorizontalLine(dx, dy+dh*3/4, dw, STASHED, COLOR_THEME_SECONDARY2); + for (lv_coord_t x = 0; x < dw; x += 1) { + lv_coord_t y = + getPointY(valueFunc(divRoundClosest((x - dw / 2) * RESX, dw / 2))); + lnPoints[x] = {(lv_coord_t)(x + dx), y}; + } - // Outside border - dc->drawSolidRect(dx, dy, dw, dh, 1, COLOR_THEME_SECONDARY2); + lv_line_set_points(ptLine, lnPoints, dw); } -void CurveRenderer::drawCurve(BitmapBuffer * dc) +coord_t CurveRenderer::getPointY(int y) const { - auto prev = (coord_t) -1; - - for (int x = 0; x < dw; x++) { - coord_t y = getPointY(function(divRoundClosest((x - dw / 2) * RESX, dw / 2))); - if (prev >= 0) { - if (prev < y) { - for (int tmp = prev; tmp <= y; tmp++) { - dc->drawBitmapPattern(dx + x - 2, tmp - 2, LBM_POINT, COLOR_THEME_SECONDARY1); - } - } - else { - for (int tmp = y; tmp <= prev; tmp++) { - dc->drawBitmapPattern(dx + x - 2, tmp - 2, LBM_POINT, COLOR_THEME_SECONDARY1); - } - } - } - prev = y; - } + return dy + + limit(0, dh / 2 - divRoundClosest(y * dh / 2, RESX), dh - 1); } -void CurveRenderer::paint(BitmapBuffer * dc, uint8_t ofst) +//----------------------------------------------------------------------------- + +Curve::Curve(Window* parent, const rect_t& rect, + std::function function, std::function position) : + Window(parent, rect, NO_FOCUS), + base(this, + rect_t{(position ? 4 : 2), (position ? 4 : 2), + rect.w - (position ? 8 : 4), rect.h - (position ? 8 : 4)}, + function), + valueFunc(std::move(function)), + positionFunc(std::move(position)) { - dx = rect.x + 2 + ofst; - dy = rect.y + 2 + ofst; - dw = rect.w - 4 - ofst * 2; - dh = rect.h - 4 - ofst * 2; + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE); - drawBackground(dc); - drawCurve(dc); -} + etx_solid_bg(lvobj, COLOR_THEME_PRIMARY2_INDEX); -Curve::Curve(Window * parent, const rect_t & rect, std::function function, std::function position): - Window(parent, rect, OPAQUE), - base(rect_t{0, 0, rect.w, rect.h}, function), - function(std::move(function)), - position(std::move(position)) -{ + // Adjust border - if drawing points leave more space to prevent clipping of + // end points. + if (positionFunc) { + dx = 4; + dy = 4; + } else { + dx = 2; + dy = 2; + } + dw = rect.w - dx * 2; + dh = rect.h - dy * 2; + + for (int i = 0; i < 17; i += 1) { + auto p = lv_obj_create(lvobj); + etx_solid_bg(p, COLOR_THEME_PRIMARY2_INDEX); + etx_obj_add_style(p, styles->circle, LV_PART_MAIN); + etx_obj_add_style(p, styles->border, LV_PART_MAIN); + etx_obj_add_style(p, styles->border_color_dark, LV_PART_MAIN); + lv_obj_set_size(p, 9, 9); + lv_obj_add_flag(p, LV_OBJ_FLAG_HIDDEN); + pointDots[i] = p; + } + + if (positionFunc) { + posVLine = lv_line_create(lvobj); + etx_obj_add_style(posVLine, styles->graph_position_line, LV_PART_MAIN); + posHLine = lv_line_create(lvobj); + etx_obj_add_style(posHLine, styles->graph_position_line, LV_PART_MAIN); + + positionValue = new StaticText(this, {10, 10, LV_SIZE_CONTENT, 17}, "", + COLOR_THEME_PRIMARY1 | FONT(XS)); + positionValue->padLeft(PAD_TINY); + positionValue->padRight(PAD_TINY); + etx_solid_bg(positionValue->getLvObj(), COLOR_THEME_ACTIVE_INDEX); + + posPoint = lv_obj_create(lvobj); + etx_solid_bg(posPoint, COLOR_THEME_PRIMARY2_INDEX); + etx_obj_add_style(posPoint, styles->circle, LV_PART_MAIN); + etx_obj_add_style(posPoint, styles->border, LV_PART_MAIN); + etx_obj_add_style(posPoint, styles->border_color_active, LV_PART_MAIN); + lv_obj_set_size(posPoint, 9, 9); + + updatePosition(); + } } coord_t Curve::getPointX(int x) const { - return dx + limit(0, - dw / 2 + divRoundClosest(x * dw / 2, RESX), - dw - 1); + return dx + + limit(0, dw / 2 + divRoundClosest(x * dw / 2, RESX), dw - 1); } coord_t Curve::getPointY(int y) const { - return dy + limit(0, - dh / 2 - divRoundClosest(y * dh / 2, RESX), - dh - 1); + return dy + + limit(0, dh / 2 - divRoundClosest(y * dh / 2, RESX), dh - 1); } -void Curve::drawBackground(BitmapBuffer * dc) +void Curve::updatePosition() { - dc->clear(COLOR_THEME_PRIMARY2); + if (positionFunc) { + int valueX = positionFunc(); + int valueY = valueFunc(valueX); - // Axis - dc->drawSolidHorizontalLine(dx, dy+dh/2, dw, COLOR_THEME_SECONDARY2); - dc->drawSolidVerticalLine(dx+dw/2, dy, dh, COLOR_THEME_SECONDARY2); + char coords[16]; + strAppendSigned( + strAppend(strAppendSigned(coords, calcRESXto100(valueX)), ","), + calcRESXto100(valueY)); - // Extra lines - dc->drawVerticalLine(dx+dw/4, dy, dh, STASHED, COLOR_THEME_SECONDARY2); - dc->drawVerticalLine(dx+dw*3/4, dy, dh, STASHED, COLOR_THEME_SECONDARY2); - dc->drawHorizontalLine(dx, dy+dh/4, dw, STASHED, COLOR_THEME_SECONDARY2); - dc->drawHorizontalLine(dx, dy+dh*3/4, dw, STASHED, COLOR_THEME_SECONDARY2); - - // Outside border - dc->drawSolidRect(dx, dy, dw, dh, 1, COLOR_THEME_SECONDARY2); -} - -void Curve::drawCurve(BitmapBuffer * dc) -{ - auto prev = (coord_t) -1; - - for (int x = 0; x < dw; x++) { - coord_t y = getPointY(function(divRoundClosest((x - dw / 2) * RESX, dw / 2))); - if (prev >= 0) { - if (prev < y) { - for (int tmp = prev; tmp <= y; tmp++) { - dc->drawBitmapPattern(dx + x - 2, tmp - 2, LBM_POINT, COLOR_THEME_SECONDARY1); - } - } - else { - for (int tmp = y; tmp <= prev; tmp++) { - dc->drawBitmapPattern(dx + x - 2, tmp - 2, LBM_POINT, COLOR_THEME_SECONDARY1); - } - } - } - prev = y; - } -} - -void Curve::drawPosition(BitmapBuffer * dc) -{ - int valueX = position(); - int valueY = function(valueX); - - coord_t x = getPointX(valueX); - coord_t y = getPointY(valueY); + positionValue->setText(coords); - // the 2 lines - dc->drawSolidHorizontalLine(dx, y, dw, COLOR_THEME_ACTIVE); - dc->drawSolidVerticalLine(x, dy, dh, COLOR_THEME_ACTIVE); + lv_coord_t x = getPointX(valueX); + lv_coord_t y = getPointY(valueY); - // the point (white inside) - dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT, COLOR_THEME_ACTIVE); - dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT_CENTER, COLOR_THEME_PRIMARY2); + lv_obj_set_pos(posPoint, x - 4, y - 4); - char coords[16]; - strAppendSigned(strAppend(strAppendSigned(coords, calcRESXto100(valueX)), ","), calcRESXto100(valueY)); - dc->drawSolidFilledRect(10, 11, 2 + getTextWidth(coords, 0, FONT(XS)), 17, COLOR_THEME_ACTIVE); - dc->drawText(11, 10, coords, FONT(XS) | COLOR_THEME_PRIMARY1); -} - -void Curve::drawPoint(BitmapBuffer * dc, const CurvePoint & point) -{ - coord_t x = getPointX(point.coords.x); - coord_t y = getPointY(point.coords.y); + posLinePoints[0] = {x, dy}; + posLinePoints[1] = {x, (lv_coord_t)(dy + dh - 1)}; + posLinePoints[2] = {dx, y}; + posLinePoints[3] = {(lv_coord_t)(dx + dw - 1), y}; - dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT, point.flags); - dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT_CENTER, COLOR_THEME_SECONDARY3); + lv_line_set_points(posVLine, &posLinePoints[0], 2); + lv_line_set_points(posHLine, &posLinePoints[2], 2); + } } -void Curve::paint(BitmapBuffer * dc) +void Curve::addPoint(const point_t& point) { - // Adjust border - if drawing points leave more space to prevent clipping of end points. - if (points.size() > 0) { - dx = 4; - dy = 4; - } else { - dx = 2; - dy = 2; - } - dw = width() - dx * 2; - dh = height() - dy * 2; + int i = points.size(); + coord_t x = getPointX(point.x); + coord_t y = getPointY(point.y); + lv_obj_set_pos(pointDots[i], x - 4, y - 4); + lv_obj_clear_flag(pointDots[i], LV_OBJ_FLAG_HIDDEN); - base.paint(dc, dx-2); + points.push_back(point); - for (auto point: points) { - drawPoint(dc, point); - } - if (position) { - drawPosition(dc); - } -} - -void Curve::addPoint(const point_t & point, LcdFlags flags) -{ - points.push_back({point, flags}); - invalidate(); + update(); } void Curve::clearPoints() { points.clear(); - invalidate(); + for (int i = 0; i < 17; i += 1) + lv_obj_add_flag(pointDots[i], LV_OBJ_FLAG_HIDDEN); + + update(); } +void Curve::update() { base.update(); } + void Curve::checkEvents() { // Redraw if crosshair position has changed - if (position) { - int pos = position(); + if (positionFunc) { + int pos = positionFunc(); if (pos != lastPos) { lastPos = pos; - invalidate(); + updatePosition(); } } diff --git a/radio/src/gui/colorlcd/curve.h b/radio/src/gui/colorlcd/curve.h index 405a8cb35c3..3e78653574c 100644 --- a/radio/src/gui/colorlcd/curve.h +++ b/radio/src/gui/colorlcd/curve.h @@ -23,66 +23,66 @@ #include "window.h" -struct CurvePoint { - point_t coords; - LcdFlags flags; -}; +class StaticText; + +//----------------------------------------------------------------------------- class CurveRenderer { - public: - CurveRenderer(const rect_t & rect, std::function function); - - void paint(BitmapBuffer * dc, uint8_t ofst = 0); - - protected: - // Drawing rectangle position & size - uint8_t dx, dy, dw, dh; - rect_t rect; - std::function function; - void drawBackground(BitmapBuffer * dc); - void drawCurve(BitmapBuffer * dc); - coord_t getPointY(int y) const; + public: + CurveRenderer(Window* parent, const rect_t& rect, + std::function function); + ~CurveRenderer(); + + void update(); + + protected: + // Drawing rectangle position & size + lv_coord_t dx, dy, dw, dh; + std::function valueFunc; + lv_point_t bgPoints[17]; + lv_point_t* lnPoints = nullptr; + lv_obj_t* ptLine = nullptr; + + coord_t getPointY(int y) const; }; -class Curve: public Window +//----------------------------------------------------------------------------- + +class Curve : public Window { - public: - Curve(Window * parent, const rect_t & rect, std::function function, std::function position=nullptr); + public: + Curve(Window* parent, const rect_t& rect, std::function function, + std::function position = nullptr); #if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "Curve"; - } + std::string getName() const override { return "Curve"; } #endif - void checkEvents() override; - - void addPoint(const point_t & point, LcdFlags flags); + void addPoint(const point_t& point); + void clearPoints(); - void clearPoints(); + void update(); - void paint(BitmapBuffer * dc) override; + protected: + CurveRenderer base; + // Drawing rectangle position & size + uint8_t dx, dy, dw, dh; + int lastPos = 0; + std::function valueFunc; + std::function positionFunc; + std::list points; + StaticText* positionValue = nullptr; + lv_point_t posLinePoints[4]; + lv_obj_t* posVLine = nullptr; + lv_obj_t* posHLine = nullptr; + lv_obj_t* posPoint = nullptr; + lv_obj_t* pointDots[17] = { nullptr }; - protected: - CurveRenderer base; - // Drawing rectangle position & size - uint8_t dx, dy, dw, dh; - int lastPos = 0; - std::function function; - std::function position; - std::list points; - void drawBackground(BitmapBuffer * dc); - void drawCurve(BitmapBuffer * dc); - void drawPosition(BitmapBuffer * dc); - void drawPoint(BitmapBuffer * dc, const CurvePoint & point); - coord_t getPointX(int x) const; - coord_t getPointY(int y) const; -}; + void updatePosition(); -#include "lz4_bitmaps.h" + coord_t getPointX(int x) const; + coord_t getPointY(int y) const; -DEFINE_LZ4_BITMAP(LBM_CURVE_POINT); -DEFINE_LZ4_BITMAP(LBM_CURVE_POINT_CENTER); -DEFINE_LZ4_BITMAP(LBM_CURVE_COORD_SHADOW); + void checkEvents() override; +}; diff --git a/radio/src/gui/colorlcd/curve_param.cpp b/radio/src/gui/colorlcd/curve_param.cpp index 2339e1428a4..eaa45e9f9ff 100644 --- a/radio/src/gui/colorlcd/curve_param.cpp +++ b/radio/src/gui/colorlcd/curve_param.cpp @@ -50,8 +50,8 @@ CurveParam::CurveParam(Window* parent, const rect_t& rect, CurveRef* ref, std::function setRefValue) : Window(parent, rect), ref(ref), setRefValue(setRefValue) { + padAll(PAD_TINY); lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW_WRAP); - lv_obj_set_style_pad_column(lvobj, lv_dpx(4), 0); lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0); lv_obj_set_size(lvobj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); @@ -87,28 +87,21 @@ void CurveParam::update() { bool has_focus = act_field && act_field->hasFocus(); - auto value_obj = value_edit->getLvObj(); - auto func_obj = func_choice->getLvObj(); - auto cust_obj = cust_choice->getLvObj(); - - lv_obj_add_flag(value_obj, LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(func_obj, LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(cust_obj, LV_OBJ_FLAG_HIDDEN); + value_edit->hide(); + func_choice->hide(); + cust_choice->hide(); switch (ref->type) { case CURVE_REF_DIFF: case CURVE_REF_EXPO: - lv_obj_clear_flag(value_obj, LV_OBJ_FLAG_HIDDEN); act_field = value_edit; break; case CURVE_REF_FUNC: - lv_obj_clear_flag(func_obj, LV_OBJ_FLAG_HIDDEN); act_field = func_choice; break; case CURVE_REF_CUSTOM: - lv_obj_clear_flag(cust_obj, LV_OBJ_FLAG_HIDDEN); act_field = cust_choice; break; @@ -116,6 +109,8 @@ void CurveParam::update() return; } + act_field->show(); + auto act_obj = act_field->getLvObj(); if (has_focus) { lv_group_focus_obj(act_obj); diff --git a/radio/src/gui/colorlcd/curveedit.cpp b/radio/src/gui/colorlcd/curveedit.cpp index 8a9e8188aad..3feaffc0b0b 100644 --- a/radio/src/gui/colorlcd/curveedit.cpp +++ b/radio/src/gui/colorlcd/curveedit.cpp @@ -20,58 +20,72 @@ */ #include "curveedit.h" -#include "opentx.h" // TODO for applyCustomCurve + #include "libopenui.h" +#include "opentx.h" // TODO for applyCustomCurve +#include "themes/etx_lv_theme.h" -#define SET_DIRTY() storageDirty(EE_MODEL) +#define SET_DIRTY() storageDirty(EE_MODEL) -static const lv_coord_t default_col_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t default_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t default_col_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t default_row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; -CurveDataEdit::CurveDataEdit(Window * parent, const rect_t & rect, uint8_t index) : - Window(parent, rect), - index(index) +CurveDataEdit::CurveDataEdit(Window* parent, const rect_t& rect, + uint8_t index) : + Window(parent, rect), index(index) { - lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY3), 0); - lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_AUTO); + etx_scrollbar(lvobj); } #if LCD_W > LCD_H - #define NUM_BTN_WIDTH 44 +#define NUM_BTN_WIDTH 44 #else - #define NUM_BTN_WIDTH 48 +#define NUM_BTN_WIDTH 48 #endif -void CurveDataEdit::curvePointsRow(FormWindow::Line* parent, int start, int count, int curvePointsCount, bool isCustom) +void CurveDataEdit::curvePointsRow(FormLine* parent, int start, int count, + int curvePointsCount, bool isCustom) { - static const lv_coord_t points_col_dsc[] = {11, LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; - - auto form = new FormWindow(parent, rect_t{}); - form->padAll(0); + static const lv_coord_t points_col_dsc[] = {11, + LV_GRID_FR(1), + LV_GRID_FR(1), + LV_GRID_FR(1), + LV_GRID_FR(1), + LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; + + auto form = new Window(parent, rect_t{}); + form->padAll(PAD_ZERO); form->setFlexLayout(); - FlexGridLayout grid(points_col_dsc, default_row_dsc, 4); - - auto line = form->newLine(&grid); - line->padAll(0); + FlexGridLayout grid(points_col_dsc, default_row_dsc); + + auto line = form->newLine(grid); + line->padTop(-4); + line->padBottom(0); line->padLeft(4); line->padRight(4); - lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); + line->setHeight(12); + lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); - new StaticText(line, rect_t{}, "", CENTERED|COLOR_THEME_PRIMARY1); - // Point number + grid.nextCell(); for (int i = 0; i < count; i++) { - new StaticText(line, rect_t{}, std::to_string(i + start + 1), 0, FONT(XS) | CENTERED | COLOR_THEME_PRIMARY1); + (new StaticText(line, rect_t{}, std::to_string(i + start + 1), + FONT(XS) | CENTERED | COLOR_THEME_PRIMARY1)) + ->setHeight(10); } - line = form->newLine(&grid); - line->padAll(2); - line->padLeft(4); - line->padRight(4); - lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); + line = form->newLine(grid); + line->padAll(PAD_TINY); + line->setHeight(36); + lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); - new StaticText(line, rect_t{}, "X", 0, CENTERED|COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, "X", CENTERED | COLOR_THEME_PRIMARY1); int8_t* points = curveAddress(index); @@ -80,7 +94,9 @@ void CurveDataEdit::curvePointsRow(FormWindow::Line* parent, int start, int coun uint8_t i = 0; uint8_t c = count; if (start == 0) { - new StaticText(line, rect_t{}, "-100", 0, CENTERED | COLOR_THEME_SECONDARY1); + (new StaticText(line, rect_t{}, "-100", + CENTERED | COLOR_THEME_SECONDARY1)) + ->padTop(1); i += 1; } if ((start + count) == curvePointsCount) { @@ -90,56 +106,61 @@ void CurveDataEdit::curvePointsRow(FormWindow::Line* parent, int start, int coun for (; i < c; i++) { uint8_t px = i + start - 1; numEditX[px] = new NumberEdit( - line, rect_t{ 0, 0, NUM_BTN_WIDTH, 0 }, + line, rect_t{0, 0, NUM_BTN_WIDTH, 0}, (px == 0) ? -100 : points[curvePointsCount + px - 1], - (px == curvePointsCount - 3) ? 100 : points[curvePointsCount + px + 1], + (px == curvePointsCount - 3) ? 100 + : points[curvePointsCount + px + 1], GET_VALUE(points[curvePointsCount + px]), [=](int32_t newValue) { - points[curvePointsCount + px] = newValue; + points[curvePointsCount + px] = newValue; if (px > 0) { - numEditX[px-1]->setMax(newValue); + numEditX[px - 1]->setMax(newValue); } if (px < curvePointsCount - 3) { - numEditX[px+1]->setMin(newValue); + numEditX[px + 1]->setMin(newValue); } SET_DIRTY(); curveEdit->updatePreview(); - }, - 0, RIGHT); - lv_obj_set_grid_cell(numEditX[px]->getLvObj(), LV_GRID_ALIGN_CENTER, i+1, 1, LV_GRID_ALIGN_CENTER, 0, 1); - lv_textarea_set_align(numEditX[px]->getLvObj(), LV_TEXT_ALIGN_CENTER); + }); + lv_obj_set_grid_cell(numEditX[px]->getLvObj(), LV_GRID_ALIGN_CENTER, + i + 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); + lv_textarea_set_align(numEditX[px]->getLvObj(), LV_TEXT_ALIGN_CENTER); } if ((start + count) == curvePointsCount) { - new StaticText(line, rect_t{}, "100", 0, CENTERED | COLOR_THEME_SECONDARY1); + (new StaticText(line, rect_t{}, "100", + CENTERED | COLOR_THEME_SECONDARY1)) + ->padTop(1); } } else { for (uint8_t i = 0; i < count; i++) { - new StaticText(line, rect_t{}, - std::to_string(-100 + (200 * (i + start)) / (curvePointsCount - 1)), - 0, CENTERED | COLOR_THEME_SECONDARY1); + (new StaticText( + line, rect_t{0, 1, 0, 0}, + std::to_string(-100 + (200 * (i + start)) / (curvePointsCount - 1)), + CENTERED | COLOR_THEME_SECONDARY1)) + ->padTop(1); } } - line = form->newLine(&grid); - line->padAll(2); - line->padLeft(4); - line->padRight(4); - lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); + line = form->newLine(grid); + line->padAll(PAD_TINY); + line->setHeight(36); + lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); - new StaticText(line, rect_t{}, "Y", 0, CENTERED|COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, "Y", CENTERED | COLOR_THEME_PRIMARY1); // y value for (uint8_t i = 0; i < count; i++) { auto numedit = new NumberEdit( - line, rect_t{ 0, 0, NUM_BTN_WIDTH, 0 }, - -100, 100, GET_VALUE(points[i+start]), + line, rect_t{0, 0, NUM_BTN_WIDTH, 0}, -100, 100, + GET_VALUE(points[i + start]), [=](int32_t newValue) { - points[i+start] = newValue; + points[i + start] = newValue; SET_DIRTY(); curveEdit->updatePreview(); - }, - 0, RIGHT); - lv_obj_set_grid_cell(numedit->getLvObj(), LV_GRID_ALIGN_CENTER, i+1, 1, LV_GRID_ALIGN_CENTER, 0, 1); + }); + lv_obj_set_grid_cell(numedit->getLvObj(), LV_GRID_ALIGN_CENTER, i + 1, 1, + LV_GRID_ALIGN_CENTER, 0, 1); lv_textarea_set_align(numedit->getLvObj(), LV_TEXT_ALIGN_CENTER); } } @@ -150,23 +171,25 @@ void CurveDataEdit::update() memset(numEditX, 0, sizeof(numEditX)); - auto form = new FormWindow(this, rect_t{}); - form->padAll(0); + auto form = new Window(this, rect_t{}); + form->padAll(PAD_ZERO); form->padBottom(4); form->setFlexLayout(); - FlexGridLayout grid(default_col_dsc, default_row_dsc, 4); + FlexGridLayout grid(default_col_dsc, default_row_dsc); - CurveHeader & curve = g_model.curves[index]; + CurveHeader& curve = g_model.curves[index]; uint8_t curvePointsCount = 5 + curve.points; for (int i = 0; i < curvePointsCount; i += 5) { int count = 5; if (i + count > curvePointsCount) count = curvePointsCount - i; - auto line = form->newLine(&grid); - line->padAll(0); - lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); - curvePointsRow(line, i, count, curvePointsCount, curve.type == CURVE_TYPE_CUSTOM); + auto line = form->newLine(grid); + line->padAll(PAD_ZERO); + lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); + curvePointsRow(line, i, count, curvePointsCount, + curve.type == CURVE_TYPE_CUSTOM); } } @@ -183,13 +206,11 @@ mixsrc_t CurveEdit::currentSource = 0; bool CurveEdit::lockSource = false; CurveEdit::CurveEdit(Window* parent, const rect_t& rect, uint8_t index) : - FormField(parent, rect, NO_FOCUS), + Window(parent, rect, NO_FOCUS), preview( this, {0, 0, width(), height()}, [=](int x) -> int { return applyCustomCurve(x, index); }, - [=]()->int { - return getValue(CurveEdit::currentSource); - }), + [=]() -> int { return getValue(CurveEdit::currentSource); }), index(index), current(0) { @@ -201,11 +222,10 @@ CurveEdit::CurveEdit(Window* parent, const rect_t& rect, uint8_t index) : void CurveEdit::updatePreview() { preview.clearPoints(); - CurveHeader & curve = g_model.curves[index]; + CurveHeader& curve = g_model.curves[index]; for (uint8_t i = 0; i < 5 + curve.points; i++) { - preview.addPoint(getPoint(index, i), COLOR_THEME_SECONDARY1); + preview.addPoint(getPoint(index, i)); } - invalidate(); } void CurveEdit::checkEvents() @@ -223,18 +243,17 @@ void CurveEdit::checkEvents() TRACE("Applied source=%d", CurveEdit::currentSource); } } - FormField::checkEvents(); + Window::checkEvents(); } -CurveEditWindow::CurveEditWindow(uint8_t index): - Page(ICON_MODEL_CURVES), - index(index) +CurveEditWindow::CurveEditWindow(uint8_t index) : + Page(ICON_MODEL_CURVES, PAD_ZERO), index(index) { buildBody(&body); buildHeader(&header); } -void CurveEditWindow::buildHeader(Window * window) +void CurveEditWindow::buildHeader(Window* window) { header.setTitle(STR_MENUCURVES); char s[16]; @@ -242,29 +261,28 @@ void CurveEditWindow::buildHeader(Window * window) header.setTitle2(s); } -void CurveEditWindow::buildBody(FormWindow * window) +void CurveEditWindow::buildBody(Window* window) { - CurveHeader & curve = g_model.curves[index]; - int8_t * points = curveAddress(index); + CurveHeader& curve = g_model.curves[index]; + int8_t* points = curveAddress(index); - auto form = new FormWindow(window, rect_t{}); - form->padAll(0); - form->setFlexLayout(); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); + + FlexGridLayout grid(default_col_dsc, default_row_dsc, PAD_ZERO); - FlexGridLayout grid(default_col_dsc, default_row_dsc, 0); - - auto line = form->newLine(&grid); - line->padAll(0); - lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); + auto line = window->newLine(grid); + line->padAll(PAD_ZERO); + lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); -#if LCD_H > LCD_W // portrait +#if LCD_H > LCD_W // portrait lv_obj_set_flex_flow(line->getLvObj(), LV_FLEX_FLOW_COLUMN); coord_t curveWidth = window->width() - 88; coord_t boxWidth = window->width(); coord_t boxHeight = window->height() - curveWidth; #else lv_obj_set_flex_flow(line->getLvObj(), LV_FLEX_FLOW_ROW); - coord_t curveWidth = window->height() - 2 * PAGE_PADDING; + coord_t curveWidth = window->height() - 2 * PAD_MEDIUM; coord_t boxWidth = window->width() - curveWidth; coord_t boxHeight = window->height(); #endif @@ -272,24 +290,26 @@ void CurveEditWindow::buildBody(FormWindow * window) auto box = new Window(line, rect_t{}); box->setWidth(boxWidth); box->setHeight(boxHeight); - box->padAll(0); + box->padAll(PAD_ZERO); - static const lv_coord_t controls_col_dsc[] = {LV_GRID_FR(5), LV_GRID_FR(8), LV_GRID_FR(5), LV_GRID_TEMPLATE_LAST}; + static const lv_coord_t controls_col_dsc[] = { + LV_GRID_FR(5), LV_GRID_FR(8), LV_GRID_FR(5), LV_GRID_TEMPLATE_LAST}; - form = new FormWindow(box, rect_t{}); - form->padAll(0); - form->setFlexLayout(); + auto form = new Window(box, rect_t{}); + form->padAll(PAD_ZERO); + form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); + + FlexGridLayout iGrid(controls_col_dsc, default_row_dsc, PAD_ZERO); - FlexGridLayout iGrid(controls_col_dsc, default_row_dsc, 0); - - auto iLine = form->newLine(&iGrid); - iLine->padAll(4); - iLine->padBottom(0); - lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); + auto iLine = form->newLine(iGrid); + iLine->padAll(PAD_TINY); + lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); // Name - new StaticText(iLine, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); - new ModelTextEdit(iLine, rect_t{0, 0, 100, 0}, curve.name, sizeof(curve.name)); + new StaticText(iLine, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); + new ModelTextEdit(iLine, rect_t{0, 0, 100, 0}, curve.name, + sizeof(curve.name)); // Smooth auto smooth = new TextButton(iLine, rect_t{0, 0, 70, 0}, STR_SMOOTH, [=]() { @@ -298,71 +318,83 @@ void CurveEditWindow::buildBody(FormWindow * window) return g_model.curves[index].smooth; }); smooth->check(g_model.curves[index].smooth); - - iLine = form->newLine(&iGrid); - iLine->padAll(4); - iLine->padBottom(0); - lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); + + iLine = form->newLine(iGrid); + iLine->padAll(PAD_TINY); + lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); // Type - new StaticText(iLine, rect_t{}, STR_TYPE, 0, COLOR_THEME_PRIMARY1); - new Choice(iLine, rect_t{0, 0, 100, 0}, STR_CURVE_TYPES, 0, 1, GET_DEFAULT(g_model.curves[index].type), - [=](int32_t newValue) { - CurveHeader &curve = g_model.curves[index]; - if (newValue != curve.type) { - for (int i = 1; i < 4 + curve.points; i++) { - points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(-100 + i * 200 / (4 + curve.points)), index)); - } - if (moveCurve(index, newValue == CURVE_TYPE_CUSTOM ? 3 + curve.points : -3 - curve.points)) { - if (newValue == CURVE_TYPE_CUSTOM) { - resetCustomCurveX(points, 5 + curve.points); - } - curve.type = newValue; - } - SET_DIRTY(); - curveEdit->updatePreview(); - if (curveDataEdit) { - curveDataEdit->update(); - } - } - }); + new StaticText(iLine, rect_t{}, STR_TYPE, COLOR_THEME_PRIMARY1); + new Choice( + iLine, rect_t{0, 0, 100, 0}, STR_CURVE_TYPES, 0, 1, + GET_DEFAULT(g_model.curves[index].type), [=](int32_t newValue) { + CurveHeader& curve = g_model.curves[index]; + if (newValue != curve.type) { + for (int i = 1; i < 4 + curve.points; i++) { + points[i] = calcRESXto100(applyCustomCurve( + calc100toRESX(-100 + i * 200 / (4 + curve.points)), index)); + } + if (moveCurve(index, newValue == CURVE_TYPE_CUSTOM + ? 3 + curve.points + : -3 - curve.points)) { + if (newValue == CURVE_TYPE_CUSTOM) { + resetCustomCurveX(points, 5 + curve.points); + } + curve.type = newValue; + } + SET_DIRTY(); + curveEdit->updatePreview(); + if (curveDataEdit) { + curveDataEdit->update(); + } + } + }); // Points count - auto edit = new NumberEdit(iLine, rect_t{0, 0, 70, 0}, 2, 17, GET_DEFAULT(g_model.curves[index].points + 5), - [=](int32_t newValue) { - newValue -= 5; - CurveHeader &curve = g_model.curves[index]; - int newPoints[MAX_POINTS_PER_CURVE]; - newPoints[0] = points[0]; - newPoints[4 + newValue] = points[4 + curve.points]; - for (int i = 1; i < 4 + newValue; i++) - newPoints[i] = calcRESXto100(applyCustomCurve(-RESX + (i * 2 * RESX) / (4 + newValue), index)); - if (moveCurve(index, (newValue - curve.points) * (curve.type == CURVE_TYPE_CUSTOM ? 2 : 1))) { - for (int i = 0; i < 5 + newValue; i++) { - points[i] = newPoints[i]; - if (curve.type == CURVE_TYPE_CUSTOM && i != 0 && i != 4 + newValue) - points[5 + newValue + i - 1] = -100 + (i * 200) / (4 + newValue); - } - curve.points = newValue; - SET_DIRTY(); - curveEdit->updatePreview(); - if (curveDataEdit) { - curveDataEdit->update(); - } - } - }); + auto edit = new NumberEdit( + iLine, rect_t{0, 0, 70, 0}, 2, 17, + GET_DEFAULT(g_model.curves[index].points + 5), [=](int32_t newValue) { + newValue -= 5; + CurveHeader& curve = g_model.curves[index]; + int newPoints[MAX_POINTS_PER_CURVE]; + newPoints[0] = points[0]; + newPoints[4 + newValue] = points[4 + curve.points]; + for (int i = 1; i < 4 + newValue; i++) + newPoints[i] = calcRESXto100( + applyCustomCurve(-RESX + (i * 2 * RESX) / (4 + newValue), index)); + if (moveCurve(index, (newValue - curve.points) * + (curve.type == CURVE_TYPE_CUSTOM ? 2 : 1))) { + for (int i = 0; i < 5 + newValue; i++) { + points[i] = newPoints[i]; + if (curve.type == CURVE_TYPE_CUSTOM && i != 0 && i != 4 + newValue) + points[5 + newValue + i - 1] = -100 + (i * 200) / (4 + newValue); + } + curve.points = newValue; + SET_DIRTY(); + curveEdit->updatePreview(); + if (curveDataEdit) { + curveDataEdit->update(); + } + } + }); edit->setSuffix(STR_PTS); edit->setDefault(5); - iLine = form->newLine(&iGrid); - iLine->padAll(0); - lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); + iLine = form->newLine(iGrid); + iLine->padAll(PAD_ZERO); + iLine->padTop(PAD_SMALL); + iLine->padBottom(PAD_SMALL); + lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); - curveDataEdit = new CurveDataEdit(iLine, rect_t{ 0, 0, box->width(), box->height() - 72 }, index); + curveDataEdit = new CurveDataEdit( + iLine, rect_t{0, 0, box->width(), box->height() - 82}, index); // Curve editor - lv_obj_set_flex_align(line->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); - curveEdit = new CurveEdit(line, { 0, 0, curveWidth, curveWidth }, index); - + lv_obj_set_flex_align(line->getLvObj(), LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); + curveEdit = new CurveEdit(line, {0, 0, curveWidth, curveWidth}, index); + curveDataEdit->setCurveEdit(curveEdit); } diff --git a/radio/src/gui/colorlcd/curveedit.h b/radio/src/gui/colorlcd/curveedit.h index 433059bcf94..3760810c1ba 100644 --- a/radio/src/gui/colorlcd/curveedit.h +++ b/radio/src/gui/colorlcd/curveedit.h @@ -27,7 +27,7 @@ class NumberEdit; -class CurveEdit: public FormField +class CurveEdit: public Window { public: CurveEdit(Window * parent, const rect_t & rect, uint8_t index); @@ -40,7 +40,7 @@ class CurveEdit: public FormField preview.deleteLater(true, false); - FormField::deleteLater(detach, trash); + Window::deleteLater(detach, trash); } void updatePreview(); @@ -73,7 +73,7 @@ class CurveDataEdit : public Window CurveEdit * curveEdit; NumberEdit* numEditX[16]; - void curvePointsRow(FormWindow::Line* parent, int start, int count, int curvePointsCount, bool isCustom); + void curvePointsRow(FormLine* parent, int start, int count, int curvePointsCount, bool isCustom); }; class CurveEditWindow : public Page @@ -87,5 +87,5 @@ class CurveEditWindow : public Page CurveDataEdit * curveDataEdit = nullptr; void buildHeader(Window * window); - void buildBody(FormWindow * window); + void buildBody(Window * window); }; diff --git a/radio/src/gui/colorlcd/curves.cpp b/radio/src/gui/colorlcd/curves.cpp deleted file mode 100644 index 061f334af46..00000000000 --- a/radio/src/gui/colorlcd/curves.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" -#include "font.h" - -coord_t getCurveYCoord(FnFuncP fn, int x, int width) -{ - return limit(-width, -divRoundClosest(fn(divRoundClosest(x * RESX, width)) * width, RESX), +width); -} - -void drawFunction(BitmapBuffer * dc, FnFuncP fn, int x, int y, int width) -{ - int left = x - width; - int right = x + width; - - // Axis - dc->drawSolidHorizontalLine(left, y, width*2+1, COLOR_THEME_DISABLED); - dc->drawSolidVerticalLine(x, y-width, width*2, COLOR_THEME_DISABLED); - - // Extra lines - dc->drawVerticalLine(left+width/2, y-width, width*2, STASHED, COLOR_THEME_DISABLED); - dc->drawVerticalLine(right-width/2, y-width, width*2, STASHED, COLOR_THEME_DISABLED); - dc->drawHorizontalLine(left, y-width/2, width*2+1, STASHED, COLOR_THEME_DISABLED); - dc->drawHorizontalLine(left, y+width/2, width*2+1, STASHED, COLOR_THEME_DISABLED); - - // Outside border - dc->drawSolidVerticalLine(left, y-width, width*2, COLOR_THEME_SECONDARY1); - dc->drawSolidVerticalLine(right, y-width, width*2, COLOR_THEME_SECONDARY1); - dc->drawSolidHorizontalLine(left, y-width, width*2+1, COLOR_THEME_SECONDARY1); - dc->drawSolidHorizontalLine(left, y+width, width*2+1, COLOR_THEME_SECONDARY1); - - coord_t prev_yv = (coord_t)-1; - - for (int xv=-width; xv<=width; xv+=1) { - coord_t yv = y + getCurveYCoord(fn, xv, width); - if (prev_yv != (coord_t)-1) { - if (prev_yv < yv) { - for (int y=prev_yv; y<=yv; y+=1) { - dc->drawBitmapPattern(x+xv-2, y-2, LBM_POINT, COLOR_THEME_SECONDARY1); - } - } - else { - for (int y=yv; y<=prev_yv; y+=1) { - dc->drawBitmapPattern(x+xv-2, y-2, LBM_POINT, COLOR_THEME_SECONDARY1); - } - } - } - prev_yv = yv; - } -} - -void drawCurveVerticalScale(BitmapBuffer * dc, int x) -{ - for (int i=0; i<=20; i++) { - dc->drawSolidHorizontalLine(x, CURVE_CENTER_Y-CURVE_SIDE_WIDTH+i*CURVE_SIDE_WIDTH/10, 10, COLOR_THEME_SECONDARY1); - } -} - -void drawCurveHorizontalScale(BitmapBuffer * dc) -{ - for (int i=0; i<=20; i++) { - dc->drawSolidVerticalLine(CURVE_CENTER_X-CURVE_SIDE_WIDTH+i*CURVE_SIDE_WIDTH/10, CURVE_CENTER_Y+CURVE_SIDE_WIDTH+5, 10, COLOR_THEME_SECONDARY1); - } -} - -void drawCurveCoord(BitmapBuffer * dc, int x, int y, const char * text, bool active) -{ - dc->drawSolidFilledRect(x, y, CURVE_COORD_WIDTH, CURVE_COORD_HEIGHT, COLOR_THEME_WARNING); - dc->drawText(x+3+(CURVE_COORD_WIDTH - 1 - getTextWidth(text, 0, FONT(XS))) / 2, y + 1, text, LEFT|FONT(XS)|COLOR_THEME_SECONDARY3); - if (active) { - dc->drawBitmapPattern(x, y, LBM_CURVE_COORD_SHADOW, COLOR_THEME_SECONDARY1); - } -} - -void drawCurvePoint(BitmapBuffer * dc, int x, int y, LcdFlags color) -{ - dc->drawBitmapPattern(x, y, LBM_CURVE_POINT, color); - dc->drawBitmapPattern(x, y, LBM_CURVE_POINT_CENTER, COLOR_THEME_SECONDARY3); -} diff --git a/radio/src/gui/colorlcd/custom_failsafe.cpp b/radio/src/gui/colorlcd/custom_failsafe.cpp index c54b0d9a62c..403c6228a19 100644 --- a/radio/src/gui/colorlcd/custom_failsafe.cpp +++ b/radio/src/gui/colorlcd/custom_failsafe.cpp @@ -20,62 +20,51 @@ */ #include "custom_failsafe.h" + +#include "channel_bar.h" #include "opentx.h" +#include "themes/etx_lv_theme.h" -#define SET_DIRTY() storageDirty(EE_MODEL) +#define SET_DIRTY() storageDirty(EE_MODEL) class ChannelFailsafeBargraph : public Window { public: - ChannelFailsafeBargraph(Window* parent, const rect_t& rect, uint8_t moduleIdx, - uint8_t channel) : - Window(parent, rect), moduleIdx(moduleIdx), channel(channel) + ChannelFailsafeBargraph(Window* parent, const rect_t& rect, uint8_t channel) : + Window(parent, rect), channel(channel) { + etx_obj_add_style(lvobj, styles->border_thin, LV_PART_MAIN); + etx_obj_add_style(lvobj, styles->border_color_black, LV_PART_MAIN); + + outputsBar = new OutputChannelBar(this, {0, 1, width() - 2, BAR_HEIGHT}, + channel, false, false); + outputsBar->hide(); + + failsafeBar = new ChannelBar( + this, {0, BAR_HEIGHT + 3, width() - 2, BAR_HEIGHT}, + [=] { return calcRESXto100(g_model.failsafeChannels[channel]); }, + COLOR_THEME_WARNING, COLOR_THEME_WARNING); + failsafeBar->hide(); } void checkEvents() override { - invalidate(); Window::checkEvents(); - } - - void paint(BitmapBuffer* dc) override - { - int32_t failsafeValue = g_model.failsafeChannels[channel]; - int32_t channelValue = channelOutputs[channel]; - - const int lim = g_model.extendedLimits ? 1024 * LIMIT_EXT_PERCENT / 100 : 1024; - - coord_t x = 0; - dc->drawRect(x, 0, width(), height()); - if (failsafeValue == FAILSAFE_CHANNEL_HOLD || - failsafeValue == FAILSAFE_CHANNEL_NOPULSE) - return; - - const coord_t lenChannel = limit( - (uint8_t)1, uint8_t((abs(channelValue) * width() / 2 + lim / 2) / lim), - uint8_t(width() / 2)); + outputsBar->show( + g_model.failsafeChannels[channel] != FAILSAFE_CHANNEL_HOLD && + g_model.failsafeChannels[channel] != FAILSAFE_CHANNEL_NOPULSE); - const coord_t lenFailsafe = limit( - (uint8_t)1, uint8_t((abs(failsafeValue) * width() / 2 + lim / 2) / lim), - uint8_t(width() / 2)); - - x += width() / 2; - - const coord_t xChannel = (channelValue > 0) ? x : x + 1 - lenChannel; - const coord_t xFailsafe = (failsafeValue > 0) ? x : x + 1 - lenFailsafe; - - dc->drawSolidFilledRect(xChannel, +2, lenChannel, (height() / 2) - 3, - COLOR_THEME_SECONDARY1); - - dc->drawSolidFilledRect(xFailsafe, (height() / 2) + 1, lenFailsafe, - (height() / 2) - 3, COLOR_THEME_WARNING); + failsafeBar->show( + g_model.failsafeChannels[channel] != FAILSAFE_CHANNEL_HOLD && + g_model.failsafeChannels[channel] != FAILSAFE_CHANNEL_NOPULSE); } protected: - uint8_t moduleIdx; uint8_t channel; + + OutputChannelBar* outputsBar = nullptr; + ChannelBar* failsafeBar = nullptr; }; class ChannelFailsafeEdit : public NumberEdit @@ -94,12 +83,13 @@ class ChannelFailsafeEdit : public NumberEdit return formatNumberAsString(value, PREC1, 0, "", "%"); } } - -public: + + public: ChannelFailsafeEdit(Window* parent, uint8_t ch, int vmin, int vmax) : - NumberEdit(parent, rect_t{}, vmin, vmax, nullptr), channel(ch) + NumberEdit(parent, rect_t{}, vmin, vmax, nullptr), channel(ch) { - setGetValueHandler([=]() { return calcRESXto1000(g_model.failsafeChannels[ch]); }); + setGetValueHandler( + [=]() { return calcRESXto1000(g_model.failsafeChannels[ch]); }); setDisplayHandler([=](int) -> std::string { return getString(); }); update(); } @@ -112,11 +102,11 @@ class ChannelFailsafeEdit : public NumberEdit g_model.failsafeChannels[channel] = calc1000toRESX(value); SET_DIRTY(); }); - lv_obj_clear_state(lvobj, LV_STATE_DISABLED); + enable(); } else { // disable setter to avoid overwritting the value limited by vmin/vmax setSetValueHandler(nullptr); - lv_obj_add_state(lvobj, LV_STATE_DISABLED); + disable(); } SET_DIRTY(); NumberEdit::update(); @@ -154,17 +144,16 @@ class ChannelFailsafeEdit : public NumberEdit } }; -class ChannelFSCombo : public FormWindow +class ChannelFSCombo : public Window { ChannelFailsafeEdit* edit = nullptr; - -public: + + public: ChannelFSCombo(Window* parent, uint8_t ch, int vmin, int vmax) : - FormWindow(parent, rect_t{}) + Window(parent, rect_t{}) { - setFlexLayout(LV_FLEX_FLOW_ROW); - lv_obj_set_width(lvobj, LV_SIZE_CONTENT); - + setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY, LV_SIZE_CONTENT); + lv_obj_set_style_pad_column(lvobj, lv_dpx(4), 0); lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0); @@ -187,9 +176,8 @@ class ChannelFSCombo : public FormWindow void update() { edit->update(); } }; - -static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), LV_GRID_FR(3), - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), + LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; @@ -200,27 +188,22 @@ static void set_failsafe(lv_event_t* e) } #if LCD_H > LCD_W - #define FS_BARGRAPH_WIDTH (LV_DPI_DEF / 2) -#else - #define FS_BARGRAPH_WIDTH (LV_DPI_DEF) +#define FS_BARGRAPH_WIDTH (LV_DPI_DEF / 2) +#else +#define FS_BARGRAPH_WIDTH (LV_DPI_DEF) #endif - -FailSafePage::FailSafePage(uint8_t moduleIdx) : - Page(ICON_STATS_ANALOGS) +FailSafePage::FailSafePage(uint8_t moduleIdx) : Page(ICON_STATS_ANALOGS) { header.setTitle(STR_FAILSAFESET); - auto form = new FormWindow(&body, rect_t{}); - form->setFlexLayout(); - form->padAll(lv_dpx(8)); - form->padRow(lv_dpx(8)); + body.setFlexLayout(); - FlexGridLayout grid(line_col_dsc, line_row_dsc, 0); + FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); - auto btn = new TextButton(form, rect_t{}, STR_CHANNELS2FAILSAFE); + auto btn = new TextButton(&body, rect_t{}, STR_CHANNELS2FAILSAFE); lv_obj_set_width(btn->getLvObj(), lv_pct(100)); - + btn->setPressHandler([=]() { setCustomFailsafe(moduleIdx); AUDIO_WARNING1(); @@ -236,20 +219,18 @@ FailSafePage::FailSafePage(uint8_t moduleIdx) : g_model.extendedLimits ? 1024 * LIMIT_EXT_PERCENT / 100 : 1024); for (int ch = start_ch; ch < end_ch; ch++) { - // Channel name - auto line = form->newLine(&grid); + auto line = body.newLine(grid); const char* ch_label = getSourceString(MIXSRC_FIRST_CH + ch); - new StaticText(line, rect_t{}, ch_label, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, ch_label, COLOR_THEME_PRIMARY1); // Channel value auto combo = new ChannelFSCombo(line, ch, -lim, lim); lv_obj_add_event_cb(btn->getLvObj(), set_failsafe, LV_EVENT_CLICKED, combo); - + // Channel bargraph - auto bar = new ChannelFailsafeBargraph(line, rect_t{}, moduleIdx, ch); - bar->setWidth(FS_BARGRAPH_WIDTH); - bar->setHeight(LV_DPI_DEF / 5); + auto bar = new ChannelFailsafeBargraph( + line, rect_t{0, 0, FS_BARGRAPH_WIDTH, 32}, ch); lv_obj_set_style_grid_cell_x_align(bar->getLvObj(), LV_GRID_ALIGN_END, 0); } } diff --git a/radio/src/gui/colorlcd/draw_functions.cpp b/radio/src/gui/colorlcd/draw_functions.cpp deleted file mode 100644 index 26da6ec789a..00000000000 --- a/radio/src/gui/colorlcd/draw_functions.cpp +++ /dev/null @@ -1,544 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" -#include "lcd.h" -#include "theme_manager.h" -#include "libopenui.h" -#include "theme.h" - -#include "hal/watchdog_driver.h" - -coord_t drawStringWithIndex(BitmapBuffer * dc, coord_t x, coord_t y, const char * str, int idx, LcdFlags flags, const char * prefix, const char * suffix) -{ - char s[64]; - char * tmp = (prefix ? strAppend(s, prefix) : s); - tmp = strAppend(tmp, str); - tmp = strAppendUnsigned(tmp, abs(idx)); - if (suffix) - strAppend(tmp, suffix); - return dc->drawText(x, y, s, flags); -} - -void drawStatusText(BitmapBuffer * dc, const char * text) -{ - dc->drawText(MENUS_MARGIN_LEFT, MENU_FOOTER_TOP, text, COLOR_THEME_PRIMARY2); -} - -void drawVerticalScrollbar(BitmapBuffer * dc, coord_t x, coord_t y, coord_t h, uint16_t offset, uint16_t count, uint8_t visible) -{ - if (visible < count) { - dc->drawSolidVerticalLine(x, y, h, COLOR_THEME_PRIMARY3); - coord_t yofs = (h*offset + count/2) / count; - coord_t yhgt = (h*visible + count/2) / count; - if (yhgt + yofs > h) - yhgt = h - yofs; - dc->drawSolidFilledRect(x-1, y + yofs, 3, yhgt, COLOR_THEME_FOCUS); - } -} - -const uint8_t _LBM_TRIM_SHADOW[] = { -#include "mask_trim_shadow.lbm" -}; -STATIC_LZ4_BITMAP(LBM_TRIM_SHADOW); - -void drawTrimSquare(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags color) -{ - dc->drawSolidFilledRect(x, y, 15, 15, color); - dc->drawBitmapPattern(x, y, LBM_TRIM_SHADOW, COLOR_THEME_PRIMARY1); -} - -void drawGVarValue(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t gvar, gvar_t value, LcdFlags flags) -{ - uint8_t prec = g_model.gvars[gvar].prec; - if (prec > 0) { - flags |= (prec == 1 ? PREC1 : PREC2); - } - drawValueWithUnit(dc, x, y, value, g_model.gvars[gvar].unit ? UNIT_PERCENT : UNIT_RAW, flags); -} - -void drawValueOrGVar(BitmapBuffer* dc, coord_t x, coord_t y, gvar_t value, - gvar_t vmin, gvar_t vmax, LcdFlags flags, - const char* suffix, gvar_t offset) -{ - if (GV_IS_GV_VALUE(value, vmin, vmax)) { - int index = GV_INDEX_CALC_DELTA(value, GV_GET_GV1_VALUE(vmin, vmax)); - dc->drawText(x, y, getGVarString(index), flags); - } else { - dc->drawNumber(x, y, value + offset, flags, 0, nullptr, suffix); - } -} - -void drawSleepBitmap() -{ - LcdFlags fgColor; - LcdFlags bgColor; - - if (ThemePersistance::instance()->isDefaultTheme()) { - fgColor = COLOR2FLAGS(WHITE); - bgColor = COLOR2FLAGS(BLACK); - } else { - fgColor = COLOR_THEME_PRIMARY2; - bgColor = COLOR_THEME_SECONDARY1; - } - - lcdInitDirectDrawing(); - lcd->clear(bgColor); - - const BitmapBuffer* bitmap = EdgeTxTheme::instance()->shutdown; - if (bitmap) { - lcd->drawMask((LCD_W - bitmap->width()) / 2, (LCD_H - bitmap->height()) / 2, - bitmap, fgColor); - } - - lcdRefresh(); -} - -#define SHUTDOWN_CIRCLE_RADIUS 75 - -const uint8_t _LBM_SHUTDOWN_CIRCLE[] = { -#include "mask_shutdown_circle.lbm" -}; -STATIC_LZ4_BITMAP(LBM_SHUTDOWN_CIRCLE); - -const int8_t bmp_shutdown_xo[] = { - 0, 0, -SHUTDOWN_CIRCLE_RADIUS, -SHUTDOWN_CIRCLE_RADIUS -}; -const int8_t bmp_shutdown_yo[] = { - -SHUTDOWN_CIRCLE_RADIUS, 0, 0, -SHUTDOWN_CIRCLE_RADIUS -}; - -void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, - const char* message) -{ - static BitmapBuffer* shutdownSplashImg = nullptr; - if (totalDuration == 0) return; - - LcdFlags fgColor; - LcdFlags bgColor; - - if (ThemePersistance::instance()->isDefaultTheme()) { - fgColor = COLOR2FLAGS(WHITE); - bgColor = COLOR2FLAGS(BLACK); - } else { - fgColor = COLOR_THEME_PRIMARY2; - bgColor = COLOR_THEME_SECONDARY1; - } - - static const BitmapBuffer* shutdown = EdgeTxTheme::instance()->shutdown; - - lcdInitDirectDrawing(); - lcd->clear(bgColor); - - int quarter = duration / (totalDuration / 5); - - if (shutdown) { - if (!sdMounted()) sdInit(); - shutdownSplashImg = BitmapBuffer::loadBitmap( - BITMAPS_PATH "/" SHUTDOWN_SPLASH_FILE, BMP_RGB565); - - if (shutdownSplashImg) { - lcd->drawBitmap(0, 0, shutdownSplashImg); - } else { - lcd->drawMask((LCD_W - shutdown->width()) / 2, - (LCD_H - shutdown->height()) / 2, shutdown, fgColor); - - for (int i = 0; i <= 3 - quarter; i += 1) { - lcd->drawBitmapPattern( - LCD_W / 2 + bmp_shutdown_xo[i], LCD_H / 2 + bmp_shutdown_yo[i], - LBM_SHUTDOWN_CIRCLE, fgColor, i * SHUTDOWN_CIRCLE_RADIUS, - SHUTDOWN_CIRCLE_RADIUS); - } - } - } else { - for (int i = 1; i <= 4; i++) { - if (quarter >= i) { - lcd->drawSolidFilledRect(LCD_W / 2 - 70 + 24 * i, LCD_H / 2 - 10, 20, - 20, fgColor); - } - } - } - lcdRefresh(); - - // invalidate screen to enable quick return - // to normal display routine - lv_obj_invalidate(lv_scr_act()); -} - -void drawFatalErrorScreen(const char * message) -{ - backlightEnable(BACKLIGHT_LEVEL_MAX); - lcdInitDirectDrawing(); - lcd->clear(COLOR2FLAGS(BLACK)); - lcd->drawText(LCD_W/2, LCD_H/2-20, message, FONT(XL)|CENTERED|COLOR2FLAGS(WHITE)); - lcdRefresh(); - - // invalidate screen to enable quick return - // to normal display routine - lv_obj_invalidate(lv_scr_act()); -} - -void runFatalErrorScreen(const char * message) -{ - lcdInitDisplayDriver(); - - while (true) { - drawFatalErrorScreen(message); - WDG_RESET(); - - // loop as long as PWR button is pressed - while (true) { - uint32_t pwr_check = pwrCheck(); - if (pwr_check == e_power_off) { - boardOff(); - return; // only happens in SIMU, required for proper shutdown - } - else if (pwr_check == e_power_on) { - break; - } - WDG_RESET(); - } - } -} - -void drawCurveRef(BitmapBuffer * dc, coord_t x, coord_t y, const CurveRef & curve, LcdFlags flags) -{ - if (curve.value != 0) { - switch (curve.type) { - case CURVE_REF_DIFF: - x = dc->drawText(x, y, "D", flags); - drawValueOrGVar(dc, x, y, curve.value, -100, 100, LEFT | flags); - break; - - case CURVE_REF_EXPO: - x = dc->drawText(x, y, "E", flags); - drawValueOrGVar(dc, x, y, curve.value, -100, 100, LEFT | flags); - break; - - case CURVE_REF_FUNC: - dc->drawText(x, y, STR_VCURVEFUNC[curve.value], flags); - break; - - case CURVE_REF_CUSTOM: - dc->drawText(x, y, getCurveString(curve.value), flags); - break; - } - } -} - -void drawModelName(BitmapBuffer * dc, coord_t x, coord_t y, char * name, uint8_t id, LcdFlags att) -{ - uint8_t len = sizeof(g_model.header.name); - while (len>0 && !name[len-1]) --len; - if (len==0) { - drawStringWithIndex(dc, x, y, STR_MODEL, id+1, att|LEADING0); - } - else { - dc->drawSizedText(x, y, name, sizeof(g_model.header.name), att); - } -} - -void drawCurveName(BitmapBuffer * dc, coord_t x, coord_t y, int8_t idx, LcdFlags flags) -{ - char s[8]; - getCurveString(s, idx); - dc->drawText(x, y, s, flags); -} - -void drawSource(BitmapBuffer * dc, coord_t x, coord_t y, mixsrc_t idx, LcdFlags flags) -{ - char s[16]; - getSourceString(s, idx); - dc->drawText(x, y, s, flags); -} - -coord_t drawSwitch(BitmapBuffer * dc, coord_t x, coord_t y, int32_t idx, LcdFlags flags) -{ - return dc->drawText(x, y, getSwitchPositionName(idx), flags); -} - -void drawTrimMode(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t phase, uint8_t idx, LcdFlags att) -{ - trim_t v = getRawTrimValue(phase, idx); - unsigned int mode = v.mode; - unsigned int p = mode >> 1; - - if (mode == TRIM_MODE_NONE) { - dc->drawText(x, y, "--", att); - } else if (mode == TRIM_MODE_3POS) { - dc->drawText(x, y, "3P", att); - } else { - char s[2]; - s[0] = (mode % 2 == 0) ? ':' : '+'; - s[1] = '0'+p; - dc->drawSizedText(x, y, s, 2, att); - } -} - -void drawDate(BitmapBuffer * dc, coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags att) -{ - bool doTwoLines = false; - coord_t ox = x; - - if (att & FONT(XL)) { - att &= ~FONT_MASK; - doTwoLines = true; - } - - LcdFlags fl = att|LEADING0|LEFT; - - x = dc->drawNumber(x, y, telemetryItem.datetime.year, fl,4); - x = dc->drawText(x, y, "-", att); - x = dc->drawNumber(x, y, telemetryItem.datetime.month, fl, 2); - x = dc->drawText(x, y, "-", att); - x = dc->drawNumber(x, y, telemetryItem.datetime.day, fl, 2); - - if (doTwoLines) { - y += FH; x = ox; - } else { - x += 11; - } - - x = dc->drawNumber(x, y, telemetryItem.datetime.hour, fl, 2); - x = dc->drawText(x, y, ":", att); - x = dc->drawNumber(x, y, telemetryItem.datetime.min, fl, 2); - x = dc->drawText(x, y, ":", att); - dc->drawNumber(x, y, telemetryItem.datetime.sec, fl, 2); -} - -coord_t drawGPSCoord(BitmapBuffer * dc, coord_t x, coord_t y, int32_t value, const char * direction, LcdFlags flags, bool seconds=true) -{ - char s[32] = {}; - uint32_t absvalue = abs(value); - char * tmp = strAppendUnsigned(s, absvalue / 1000000); - tmp = strAppend(tmp, "°"); - absvalue = absvalue % 1000000; - absvalue *= 60; - if (g_eeGeneral.gpsFormat == 0 || !seconds) { - tmp = strAppendUnsigned(tmp, absvalue / 1000000, 2); - *tmp++ = '\''; - if (seconds) { - absvalue %= 1000000; - absvalue *= 60; - absvalue /= 100000; - tmp = strAppendUnsigned(tmp, absvalue / 10); - *tmp++ = '.'; - tmp = strAppendUnsigned(tmp, absvalue % 10); - *tmp++ = '"'; - } - } - else { - tmp = strAppendUnsigned(tmp, absvalue / 1000000, 2); - *tmp++ = '.'; - absvalue /= 1000; - tmp = strAppendUnsigned(tmp, absvalue, 3); - } - *tmp++ = direction[value>=0 ? 0 : 1]; - *tmp = '\0'; - x = dc->drawText(x, y, s, flags); - return x; -} - -void drawGPSPosition(BitmapBuffer * dc, coord_t x, coord_t y, int32_t longitude, int32_t latitude, LcdFlags flags) -{ - if (flags & PREC1) { - drawGPSCoord(dc, x, y, latitude, "NS", flags, true); - drawGPSCoord(dc, x, y + FH, longitude, "EW", flags, true); - } else { - if (flags & RIGHT) { - x = drawGPSCoord(dc, x, y, longitude, "EW", flags, true); - drawGPSCoord(dc, x - 5, y, latitude, "NS", flags, true); - } else { - x = drawGPSCoord(dc, x, y, latitude, "NS", flags, true); - drawGPSCoord(dc, x + 5, y, longitude, "EW", flags, true); - } - } -} - -void drawGPSSensorValue(BitmapBuffer * dc, coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags flags) -{ - drawGPSPosition(dc, x, y, telemetryItem.gps.longitude, telemetryItem.gps.latitude, flags); -} - -void drawSensorCustomValue(BitmapBuffer* dc, coord_t x, coord_t y, - uint8_t sensor, int32_t value, LcdFlags flags) -{ - if (sensor >= MAX_TELEMETRY_SENSORS) { - // Lua luaLcdDrawChannel() can call us with a bad value - return; - } - - TelemetryItem & telemetryItem = telemetryItems[sensor]; - TelemetrySensor & telemetrySensor = g_model.telemetrySensors[sensor]; - - if (telemetrySensor.unit == UNIT_DATETIME) { - drawDate(dc, x, y, telemetryItem, flags); - } - else if (telemetrySensor.unit == UNIT_GPS) { - drawGPSSensorValue(dc, x, y, telemetryItem, flags); - } - else if (telemetrySensor.unit == UNIT_TEXT) { - dc->drawSizedText(x, flags & FONT(XL) ? y + 1 : y, telemetryItem.text, - sizeof(telemetryItem.text), flags & ~FONT(XL)); - } else { - if (telemetrySensor.prec > 0) { - flags |= (telemetrySensor.prec==1 ? PREC1 : PREC2); - } - drawValueWithUnit(dc, x, y, value, - telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit, - flags); - } -} - -void drawTimer(BitmapBuffer * dc, coord_t x, coord_t y, int32_t tme, LcdFlags flags) -{ - char str[LEN_TIMER_STRING]; - TimerOptions timerOptions; - timerOptions.options = (flags & TIMEHOUR) != 0 ? SHOW_TIME : SHOW_TIMER; - getTimerString(str, tme, timerOptions); - dc->drawText(x, y, str, flags); -} - -void drawSourceValue(BitmapBuffer * dc, coord_t x, coord_t y, source_t source, LcdFlags flags) -{ - getvalue_t value = getValue(source); - drawSourceCustomValue(dc, x, y, source, value, flags); -} - -void drawSourceCustomValue(BitmapBuffer * dc, coord_t x, coord_t y, source_t source, int32_t value, LcdFlags flags) -{ - if (source >= MIXSRC_FIRST_TELEM) { - source = (source-MIXSRC_FIRST_TELEM) / 3; - drawSensorCustomValue(dc, x, y, source, value, flags); - } - else if (source >= MIXSRC_FIRST_TIMER || source == MIXSRC_TX_TIME) { - // TODO if (value < 0) flags |= BLINK|INVERS; - if (source == MIXSRC_TX_TIME) flags |= TIMEHOUR; - drawTimer(dc, x, y, value, flags); - } - else if (source == MIXSRC_TX_VOLTAGE) { - dc->drawNumber(x, y, value, flags|PREC1); - } -#if defined(INTERNAL_GPS) - else if (source == MIXSRC_TX_GPS) { - if (gpsData.fix) { - drawGPSPosition(dc, x, y, gpsData.longitude, gpsData.latitude, flags); - } - else { - x = dc->drawText(x, y, "sats: ", flags); - dc->drawNumber(x, y, gpsData.numSat, flags); - } - } -#endif -#if defined(GVARS) - else if (source >= MIXSRC_FIRST_GVAR && source <= MIXSRC_LAST_GVAR) { - drawGVarValue(dc, x, y, source - MIXSRC_FIRST_GVAR, value, flags); - } -#endif -#if defined(LUA_INPUTS) - else if (source >= MIXSRC_FIRST_LUA && source <= MIXSRC_LAST_LUA) { - dc->drawNumber(x, y, value, flags); - } -#endif - else if (source < MIXSRC_FIRST_CH) { - dc->drawNumber(x, y, calcRESXto100(value), flags); - } - else if (source <= MIXSRC_LAST_CH) { - if (g_eeGeneral.ppmunit == PPM_PERCENT_PREC1) { - dc->drawNumber(x, y, calcRESXto1000(value), flags|PREC1); - } else { - dc->drawNumber(x, y, calcRESXto100(value), flags); - } - } - else { - dc->drawNumber(x, y, value, flags); - } -} - -void drawValueWithUnit(BitmapBuffer * dc, coord_t x, coord_t y, int val, uint8_t unit, LcdFlags flags) -{ - if ((flags & NO_UNIT) || unit == UNIT_RAW) { - dc->drawNumber(x, y, val, flags & (~NO_UNIT)); - } - else { - dc->drawNumber(x, y, val, flags & (~NO_UNIT), 0, nullptr, TEXT_AT_INDEX(STR_VTELEMUNIT, unit).c_str()); - } -} - -void drawHexNumber(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t val, LcdFlags flags) -{ - for (int i = 12; i >= 0; i -= 4) { - char c = (val >> i) & 0x0F; - c += (c >= 10 ? 'A' - 10 : '0'); - x = dc->drawSizedText(x, y, &c, 1, flags); - } -} - -void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, const char * str, LcdFlags flags) -{ - coord_t x = left; - coord_t y = top; - coord_t line = getFontHeightCondensed(flags & 0xFFFF); - coord_t space = getTextWidth(" ", 1, flags); - coord_t word; - const char * nxt = str; - flags &= ~(VCENTERED | CENTERED | RIGHT); - - while (true) { - for (bool done = false; !done; nxt++) { - switch (nxt[0]) { - case '-': - case '/': - case ':': - case '(': - case '{': - case '[': - nxt++; - case ' ': - case '\n': - case '\0': - done = true; - } - } - nxt--; - word = getTextWidth(str, nxt - str, flags); - if (x + word > left + width && x > left) { - x = left; - y += line; - } - if (y + line > top + height) return; - dc->drawSizedText(x, y, str, nxt - str, flags); - x += word; - switch (nxt[0]) { - case '\0': - return; - case '\n': - x = left; - y += line; - nxt++; - break; - case ' ': - x += space; - nxt++; - } - str = nxt; - } -} diff --git a/radio/src/gui/colorlcd/draw_functions.h b/radio/src/gui/colorlcd/draw_functions.h deleted file mode 100644 index 908fc0796a5..00000000000 --- a/radio/src/gui/colorlcd/draw_functions.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _DRAW_FUNCTIONS_H_ -#define _DRAW_FUNCTIONS_H_ - -#include "dataconstants.h" -#include "telemetry/telemetry_sensors.h" -#include - -// libopenui defines TIMOUR as zero -#if !TIMEHOUR -#undef TIMEHOUR -#endif - -#if !defined(TIMEHOUR) -#define TIMEHOUR 0x2000 -#endif - -#define OPTION_MENU_NO_FOOTER 0x01 -#define OPTION_MENU_TITLE_BAR 0x02 -#define OPTION_MENU_NO_SCROLLBAR 0x04 - -#define OPTION_SLIDER_INVERS INVERS -#define OPTION_SLIDER_BLINK BLINK -#define OPTION_SLIDER_VERTICAL 0x04 -#define OPTION_SLIDER_EMPTY_BAR 0x08 -#define OPTION_SLIDER_DBL_COLOR 0x10 -#define OPTION_SLIDER_TICKS 0x20 -#define OPTION_SLIDER_BIG_TICKS 0x40 -#define OPTION_SLIDER_TRIM_BUTTON 0x80 -#define OPTION_SLIDER_NUMBER_BUTTON 0x100 -#define OPTION_SLIDER_SQUARE_BUTTON 0x200 - -coord_t drawStringWithIndex(BitmapBuffer * dc, coord_t x, coord_t y, const char * str, int idx, LcdFlags flags = 0, const char * prefix = nullptr, const char * suffix = nullptr); -void drawFatalErrorScreen(const char * message); -void clearFatalErrorScreen(); -void runFatalErrorScreen(const char * message); -void drawPower(coord_t x, coord_t y, int8_t dBm, LcdFlags att); -void drawSource(BitmapBuffer * dc, coord_t x, coord_t y, mixsrc_t idx, LcdFlags flags=0); -coord_t drawSwitch(BitmapBuffer * dc, coord_t x, coord_t y, int32_t idx, LcdFlags flags=0); -void drawTrimMode(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t phase, uint8_t idx, LcdFlags flags = 0); -void drawCurveRef(BitmapBuffer * dc, coord_t x, coord_t y, const CurveRef & curve, LcdFlags flags = 0); - -#if defined(FLIGHT_MODES) -void drawFlightMode(coord_t x, coord_t y, int8_t idx, LcdFlags att); -#endif - -void drawStatusText(BitmapBuffer * dc, const char * text); -void drawVerticalScrollbar(BitmapBuffer * dc, coord_t x, coord_t y, coord_t h, uint16_t offset, uint16_t count, uint8_t visible); -void drawProgressScreen(BitmapBuffer * dc, const char * title, const char * message, int num, int den); -void drawTrimSquare(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags color = COLOR_THEME_FOCUS); -void drawValueOrGVar(BitmapBuffer * dc, coord_t x, coord_t y, gvar_t value, gvar_t vmin, gvar_t vmax, LcdFlags flags = 0, const char* suffix = "%", gvar_t offset = 0); -void drawGVarValue(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t gvar, gvar_t value, LcdFlags flags = 0); -void drawTimer(BitmapBuffer * dc, coord_t x, coord_t y, int32_t tme, LcdFlags flags = 0); -void drawSourceValue(BitmapBuffer * dc, coord_t x, coord_t y, source_t source, LcdFlags flags = 0); -void drawSourceCustomValue(BitmapBuffer * dc, coord_t x, coord_t y, source_t source, int32_t value, LcdFlags flags); -void drawSensorCustomValue(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t sensor, int32_t value, LcdFlags flags = 0); -void drawGPSPosition(BitmapBuffer * dc, coord_t x, coord_t y, int32_t longitude, int32_t latitude, LcdFlags flags = 0); -void drawDate(BitmapBuffer * dc, coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags flags = 0); -void drawValueWithUnit(BitmapBuffer * dc, coord_t x, coord_t y, int val, uint8_t unit, LcdFlags flags = 0); -void drawHexNumber(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t val, LcdFlags flags = 0); -void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, const char * str, LcdFlags flags); -inline void drawChn(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t idx, LcdFlags flags) -{ - drawSource(dc, x, y, MIXSRC_FIRST_CH + idx - 1, flags); -} - -// Screen templates -void drawSplash(); -void drawSleepBitmap(); -void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, const char * message); -void clearShutdownAnimation(); - -// Main view standard widgets -void drawMainPots(); -void drawTrims(uint8_t flightMode); - -#endif // _DRAW_FUNCTIONS_H_ diff --git a/radio/src/gui/colorlcd/file_browser.cpp b/radio/src/gui/colorlcd/file_browser.cpp index 2a3aa4e5aa5..679a59d201f 100644 --- a/radio/src/gui/colorlcd/file_browser.cpp +++ b/radio/src/gui/colorlcd/file_browser.cpp @@ -21,7 +21,7 @@ #include "file_browser.h" #include "libopenui_file.h" -#include "font.h" +#include "fonts.h" #include #include @@ -166,8 +166,6 @@ FileBrowser::FileBrowser(Window* parent, const rect_t& rect, const char* dir) : { lv_obj_add_event_cb(lvobj, fb_event, LV_EVENT_ALL, nullptr); - setColumnCount(1); - f_chdir(dir); if (lv_obj_has_state(lvobj, LV_STATE_FOCUSED)) { diff --git a/radio/src/gui/colorlcd/file_browser.h b/radio/src/gui/colorlcd/file_browser.h index 29c3744f36d..66889df5c6c 100644 --- a/radio/src/gui/colorlcd/file_browser.h +++ b/radio/src/gui/colorlcd/file_browser.h @@ -36,16 +36,19 @@ class FileBrowser : public TableField void refresh(); void adjustWidth(); - - protected: - void onSelected(const char* name, bool is_dir); - void onPress(const char* name, bool is_dir); + + void onDrawBegin(uint16_t row, uint16_t col, + lv_obj_draw_part_dsc_t* dsc) override; + void onDrawEnd(uint16_t row, uint16_t col, + lv_obj_draw_part_dsc_t* dsc) override; // TableField methods void onSelected(uint16_t row, uint16_t col) override; void onPress(uint16_t row, uint16_t col) override; - void onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override; - void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override; + + protected: + void onSelected(const char* name, bool is_dir); + void onPress(const char* name, bool is_dir); private: const char* selected = nullptr; diff --git a/radio/src/gui/colorlcd/file_carosell.cpp b/radio/src/gui/colorlcd/file_carosell.cpp index 5e103fbba4e..ba1deb7d31a 100644 --- a/radio/src/gui/colorlcd/file_carosell.cpp +++ b/radio/src/gui/colorlcd/file_carosell.cpp @@ -27,12 +27,12 @@ extern inline tmr10ms_t getTicks() FileCarosell::FileCarosell(Window *parent, const rect_t &rect, std::vector fileNames) : - FormWindow(parent, rect, NO_FOCUS), + Window(parent, rect, NO_FOCUS), _fileNames(fileNames), - fp(new FilePreview(this, {0, 0, rect.w, rect.h}, false)) + fp(new FilePreview(this, {0, 0, rect.w, rect.h})) { timer = getTicks(); - message = new StaticText(this, {0, rect.h/2, rect.w, PAGE_LINE_HEIGHT}, "", 0, CENTERED | FONT(L) | COLOR_THEME_PRIMARY1); + message = new StaticText(this, {0, rect.h/2, rect.w, PAGE_LINE_HEIGHT}, "", CENTERED | FONT(L) | COLOR_THEME_PRIMARY1); setSelected(0); } @@ -65,7 +65,7 @@ void FileCarosell::setSelected(int n) void FileCarosell::checkEvents() { - FormWindow::checkEvents(); + Window::checkEvents(); uint32_t newTicks = getTicks(); diff --git a/radio/src/gui/colorlcd/file_carosell.h b/radio/src/gui/colorlcd/file_carosell.h index e11b05ecc65..dc674378e92 100644 --- a/radio/src/gui/colorlcd/file_carosell.h +++ b/radio/src/gui/colorlcd/file_carosell.h @@ -18,16 +18,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + #pragma once -#include "color_editor.h" + #include "file_preview.h" #include "file_carosell.h" -#include "tabsgroup.h" #define PAGE_INTERVAL ((1000 / 10) * 2) #define SHORT_PAGE_INTERVAL ((1000 / 20)) // 500 MS -class FileCarosell : public FormWindow +class FileCarosell : public Window { public: FileCarosell(Window *parent, const rect_t &rect, diff --git a/radio/src/gui/colorlcd/file_preview.cpp b/radio/src/gui/colorlcd/file_preview.cpp index 7a4d324734b..86e7f8ff853 100644 --- a/radio/src/gui/colorlcd/file_preview.cpp +++ b/radio/src/gui/colorlcd/file_preview.cpp @@ -20,61 +20,15 @@ */ #include "file_preview.h" -#include "sdcard.h" -FilePreview::FilePreview(Window *parent, const rect_t &rect, - bool drawCentered) : - Window(parent, rect), _drawCentered(drawCentered) +FilePreview::FilePreview(Window *parent, const rect_t &rect) : + StaticImage(parent, rect) { -} - -FilePreview::~FilePreview() -{ - if (bitmap != nullptr) delete bitmap; + hide(); } void FilePreview::setFile(const char *filename) { - if (bitmap != nullptr) delete bitmap; - bitmap = nullptr; - - if (filename) { - const char *ext = getFileExtension(filename); - if (ext && isExtensionMatching(ext, BITMAPS_EXT)) { - bitmap = BitmapBuffer::loadBitmap(filename); - } else { - bitmap = nullptr; - } - } - invalidate(); -} - -coord_t FilePreview::getBitmapWidth() const -{ - if (bitmap) return bitmap->width(); - return 0; -} - -coord_t FilePreview::getBitmapHeight() const -{ - if (bitmap) return bitmap->height(); - return 0; -} - -void FilePreview::paint(BitmapBuffer *dc) -{ - if (!bitmap) return; - - coord_t w = lv_obj_get_content_width(lvobj); - coord_t h = lv_obj_get_content_height(lvobj); - - coord_t bm_w = min(w, bitmap->width()); - coord_t bm_h = min(h, bitmap->height()); - - coord_t border_w = lv_obj_get_style_border_width(lvobj, 0); - coord_t x = border_w + lv_obj_get_style_pad_left(lvobj, 0); - coord_t y = border_w + lv_obj_get_style_pad_top(lvobj, 0); - - dc->setFormat(BMP_RGB565); - dc->drawScaledBitmap(bitmap, x + (w - bm_w) / 2, y + (h - bm_h) / 2, bm_w, bm_h); + setSource(filename); + show(hasImage()); } diff --git a/radio/src/gui/colorlcd/file_preview.h b/radio/src/gui/colorlcd/file_preview.h index 5a36d42630a..d1387e9e8f0 100644 --- a/radio/src/gui/colorlcd/file_preview.h +++ b/radio/src/gui/colorlcd/file_preview.h @@ -22,23 +22,14 @@ #pragma once #include "libopenui.h" -class FilePreview : public Window +class FilePreview : public StaticImage { public: - FilePreview(Window *parent, const rect_t &rect, bool drawCentered = true); - ~FilePreview(); + FilePreview(Window *parent, const rect_t &rect); #if defined(DEBUG_WINDOWS) std::string getName() const override { return "FilePreview"; } #endif void setFile(const char *filename); - coord_t getBitmapWidth() const; - coord_t getBitmapHeight() const; - - void paint(BitmapBuffer *dc) override; - - protected: - BitmapBuffer *bitmap = nullptr; - bool _drawCentered = true; }; diff --git a/radio/src/gui/colorlcd/fm_matrix.cpp b/radio/src/gui/colorlcd/fm_matrix.cpp index 919f8fc5a82..baf12173444 100644 --- a/radio/src/gui/colorlcd/fm_matrix.cpp +++ b/radio/src/gui/colorlcd/fm_matrix.cpp @@ -22,6 +22,7 @@ #include "fm_matrix.h" #include "opentx.h" +#include "themes/etx_lv_theme.h" template FMMatrix::FMMatrix(Window* parent, const rect_t& r, T* input) : @@ -47,9 +48,7 @@ FMMatrix::FMMatrix(Window* parent, const rect_t& r, T* input) : lv_obj_set_height(lvobj, 108); #endif - lv_obj_set_style_pad_all(lvobj, lv_dpx(4), LV_PART_MAIN); - lv_obj_set_style_pad_row(lvobj, lv_dpx(4), LV_PART_MAIN); - lv_obj_set_style_pad_column(lvobj, lv_dpx(4), LV_PART_MAIN); + padAll(PAD_SMALL); } template diff --git a/radio/src/gui/colorlcd/fonts.cpp b/radio/src/gui/colorlcd/fonts.cpp index fe5cfd9cf20..56149723274 100644 --- a/radio/src/gui/colorlcd/fonts.cpp +++ b/radio/src/gui/colorlcd/fonts.cpp @@ -22,7 +22,7 @@ #include #include -#include "font.h" +#include "fonts.h" #include "libopenui/thirdparty/lz4/lz4.h" #include "libopenui_defines.h" #include "lz4_fonts.h" diff --git a/radio/src/thirdparty/libopenui/src/font.h b/radio/src/gui/colorlcd/fonts.h similarity index 66% rename from radio/src/thirdparty/libopenui/src/font.h rename to radio/src/gui/colorlcd/fonts.h index 63c94bc81a1..1796954b120 100644 --- a/radio/src/thirdparty/libopenui/src/font.h +++ b/radio/src/gui/colorlcd/fonts.h @@ -19,10 +19,27 @@ #pragma once #include + #include "opentx_types.h" +enum FontIndex { + FONT_STD_INDEX, + FONT_BOLD_INDEX, + FONT_XXS_INDEX, + FONT_XS_INDEX, + FONT_L_INDEX, + FONT_XL_INDEX, + FONT_XXL_INDEX, + + // this one MUST be last + FONTS_COUNT +}; + +#define FONT_MASK 0x0F00u +#define FONT_INDEX(flags) ((FontIndex)(((flags) & FONT_MASK) >> 8u)) +#define FONT(xx) (unsigned(FONT_##xx##_INDEX) << 8u) + const lv_font_t* getFont(LcdFlags flags); uint8_t getFontHeight(LcdFlags flags); uint8_t getFontHeightCondensed(LcdFlags flags); -int getTextWidth(const char * s, int len = 0, LcdFlags flags = 0); - +int getTextWidth(const char* s, int len = 0, LcdFlags flags = 0); diff --git a/radio/src/gui/colorlcd/fullscreen_dialog.cpp b/radio/src/gui/colorlcd/fullscreen_dialog.cpp index 79a81972c0a..3112428e2e9 100644 --- a/radio/src/gui/colorlcd/fullscreen_dialog.cpp +++ b/radio/src/gui/colorlcd/fullscreen_dialog.cpp @@ -20,59 +20,62 @@ */ #include "fullscreen_dialog.h" + #include "LvglWrapper.h" +#include "libopenui.h" #include "mainwindow.h" #include "opentx.h" -#include "libopenui.h" #include "theme.h" - +#include "themes/etx_lv_theme.h" +#include "view_main.h" #include "hal/watchdog_driver.h" #if LCD_W > LCD_H -constexpr uint32_t ALERT_FRAME_TOP = 50; -constexpr uint32_t ALERT_FRAME_HEIGHT = (LCD_H - 120); -constexpr uint32_t ALERT_BITMAP_TOP = ALERT_FRAME_TOP + 25; -constexpr uint32_t ALERT_BITMAP_LEFT = 20; -constexpr uint32_t ALERT_TITLE_TOP = ALERT_FRAME_TOP + 5; -constexpr uint32_t ALERT_TITLE_LEFT = 146; -constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 85; -constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT; +constexpr uint32_t ALERT_FRAME_TOP = 50; +constexpr uint32_t ALERT_FRAME_HEIGHT = (LCD_H - 120); +constexpr uint32_t ALERT_BITMAP_TOP = ALERT_FRAME_TOP + 25; +constexpr uint32_t ALERT_BITMAP_LEFT = 20; +constexpr uint32_t ALERT_TITLE_TOP = ALERT_FRAME_TOP + 5; +constexpr uint32_t ALERT_TITLE_LEFT = 146; +constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 85; +constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT; #else -constexpr uint32_t ALERT_FRAME_TOP = 70; -constexpr uint32_t ALERT_FRAME_HEIGHT = (LCD_H - 2 * ALERT_FRAME_TOP); -constexpr uint32_t ALERT_BITMAP_TOP = ALERT_FRAME_TOP + 15; -constexpr uint32_t ALERT_BITMAP_LEFT = 15; -constexpr uint32_t ALERT_TITLE_TOP = ALERT_FRAME_TOP + 10; -constexpr uint32_t ALERT_TITLE_LEFT = 140; -constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 130; -constexpr uint32_t ALERT_MESSAGE_LEFT = 15; +constexpr uint32_t ALERT_FRAME_TOP = 70; +constexpr uint32_t ALERT_FRAME_HEIGHT = (LCD_H - 2 * ALERT_FRAME_TOP); +constexpr uint32_t ALERT_BITMAP_TOP = ALERT_FRAME_TOP + 15; +constexpr uint32_t ALERT_BITMAP_LEFT = 15; +constexpr uint32_t ALERT_TITLE_TOP = ALERT_FRAME_TOP + 10; +constexpr uint32_t ALERT_TITLE_LEFT = 140; +constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 130; +constexpr uint32_t ALERT_MESSAGE_LEFT = 15; #endif -static Window* _get_parent() -{ - Window* p = Layer::back(); - if (!p) p = MainWindow::instance(); - return p; -} - FullScreenDialog::FullScreenDialog( uint8_t type, std::string title, std::string message, std::string action, const std::function& confirmHandler) : - Window(_get_parent(), {0, 0, LCD_W, LCD_H}, OPAQUE), + Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}, OPAQUE), type(type), title(std::move(title)), message(std::move(message)), action(std::move(action)), confirmHandler(confirmHandler) { + // In case alert raised while splash screen is showing. + cancelSplash(); + + Window* p = Layer::back(); + if (p) p->hide(); + Layer::push(this); bringToTop(); build(); - lv_obj_add_event_cb(lvobj, FullScreenDialog::long_pressed, LV_EVENT_LONG_PRESSED, nullptr); - lv_obj_add_event_cb(lvobj, FullScreenDialog::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); + lv_obj_add_event_cb(lvobj, FullScreenDialog::long_pressed, + LV_EVENT_LONG_PRESSED, nullptr); + lv_obj_add_event_cb(lvobj, FullScreenDialog::on_draw, + LV_EVENT_DRAW_MAIN_BEGIN, nullptr); } void FullScreenDialog::on_draw(lv_event_t* e) @@ -88,9 +91,20 @@ void FullScreenDialog::on_draw(lv_event_t* e) void FullScreenDialog::build() { + auto div = new Window(this, {0, ALERT_FRAME_TOP, LCD_W, ALERT_FRAME_HEIGHT}, + NO_FOCUS); + etx_bg_color(div->getLvObj(), COLOR_THEME_PRIMARY2_INDEX); + etx_obj_add_style(div->getLvObj(), styles->bg_opacity_50, LV_PART_MAIN); + + new StaticIcon( + this, ALERT_BITMAP_LEFT, ALERT_BITMAP_TOP, + getBuiltinIcon((type == WARNING_TYPE_INFO) ? ICON_BUSY : ICON_ERROR), + COLOR_THEME_WARNING); + std::string t; if (type == WARNING_TYPE_ALERT) { -#if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || defined(TRANSLATIONS_CZ) +#if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || \ + defined(TRANSLATIONS_CZ) t = std::string(STR_WARNING) + "\n" + title; #else t = title + "\n" + STR_WARNING; @@ -98,69 +112,54 @@ void FullScreenDialog::build() } else if (!title.empty()) { t = title; } - new StaticText(this, - rect_t{ALERT_TITLE_LEFT, ALERT_TITLE_TOP, LCD_W - ALERT_TITLE_LEFT - PAGE_PADDING, LCD_H - ALERT_TITLE_TOP - PAGE_PADDING}, - t.c_str(), 0, COLOR_THEME_WARNING | FONT(XL)); - - messageLabel = new StaticText(this, - rect_t{ALERT_MESSAGE_LEFT, ALERT_MESSAGE_TOP, LCD_W - ALERT_MESSAGE_LEFT - PAGE_PADDING, LCD_H - ALERT_MESSAGE_TOP - PAGE_PADDING}, - message.c_str(), 0, COLOR_THEME_PRIMARY1 | FONT(BOLD)); + new StaticText(this, + rect_t{ALERT_TITLE_LEFT, ALERT_TITLE_TOP, + LCD_W - ALERT_TITLE_LEFT - PAD_MEDIUM, + LCD_H - ALERT_TITLE_TOP - PAD_MEDIUM}, + t.c_str(), COLOR_THEME_WARNING | FONT(XL)); + + messageLabel = + new StaticText(this, + rect_t{ALERT_MESSAGE_LEFT, ALERT_MESSAGE_TOP, + LCD_W - ALERT_MESSAGE_LEFT - PAD_MEDIUM, + LCD_H - ALERT_MESSAGE_TOP - PAD_MEDIUM}, + message.c_str(), COLOR_THEME_PRIMARY1 | FONT(BOLD)); if (!action.empty()) { - auto btn = new TextButton(this, { (LCD_W - 280) / 2, LCD_H - 48, 280, 40 }, action.c_str(), - [=]() { - closeDialog(); - return 0; - }, COLOR_THEME_PRIMARY1 | FONT(BOLD)); - lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0); - lv_obj_set_style_bg_opa(btn->getLvObj(), LV_OPA_COVER, 0); - lv_obj_set_style_text_color(btn->getLvObj(), makeLvColor(COLOR_THEME_PRIMARY1), 0); + auto btn = new TextButton( + this, {(LCD_W - 280) / 2, LCD_H - 48, 280, 40}, action.c_str(), + [=]() { + closeDialog(); + return 0; + }); + etx_bg_color(btn->getLvObj(), COLOR_THEME_SECONDARY3_INDEX); + etx_txt_color(btn->getLvObj(), COLOR_THEME_PRIMARY1_INDEX); } else { if (type == WARNING_TYPE_CONFIRM) { - auto btn = new TextButton(this, { LCD_W / 3 - 50, LCD_H - 48, 100, 40 }, STR_EXIT, - [=]() { - deleteLater(); - return 0; - }, COLOR_THEME_PRIMARY1 | FONT(BOLD)); - lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0); - lv_obj_set_style_bg_opa(btn->getLvObj(), LV_OPA_COVER, 0); - lv_obj_set_style_text_color(btn->getLvObj(), makeLvColor(COLOR_THEME_PRIMARY1), 0); - btn = new TextButton(this, { LCD_W * 2 / 3 - 50, LCD_H - 48, 100, 40 }, STR_OK, - [=]() { - closeDialog(); - return 0; - }, COLOR_THEME_PRIMARY1 | FONT(BOLD)); - lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0); - lv_obj_set_style_bg_opa(btn->getLvObj(), LV_OPA_COVER, 0); - lv_obj_set_style_text_color(btn->getLvObj(), makeLvColor(COLOR_THEME_PRIMARY1), 0); + auto btn = new TextButton( + this, {LCD_W / 3 - 50, LCD_H - 48, 100, 40}, STR_EXIT, + [=]() { + deleteLater(); + return 0; + }); + etx_bg_color(btn->getLvObj(), COLOR_THEME_SECONDARY3_INDEX); + etx_txt_color(btn->getLvObj(), COLOR_THEME_PRIMARY1_INDEX); + btn = new TextButton( + this, {LCD_W * 2 / 3 - 50, LCD_H - 48, 100, 40}, STR_OK, + [=]() { + closeDialog(); + return 0; + }); + etx_bg_color(btn->getLvObj(), COLOR_THEME_SECONDARY3_INDEX); + etx_txt_color(btn->getLvObj(), COLOR_THEME_PRIMARY1_INDEX); } } } -void FullScreenDialog::paint(BitmapBuffer * dc) -{ - EdgeTxTheme::instance()->drawBackground(dc); - - dc->drawFilledRect(0, ALERT_FRAME_TOP, LCD_W, ALERT_FRAME_HEIGHT, SOLID, - COLOR_THEME_PRIMARY2, OPACITY(8)); - - if (type == WARNING_TYPE_ALERT || type == WARNING_TYPE_ASTERISK) { - dc->drawMask(ALERT_BITMAP_LEFT, ALERT_BITMAP_TOP, - EdgeTxTheme::instance()->error, COLOR_THEME_WARNING); - } else if (type == WARNING_TYPE_INFO) { - dc->drawMask(ALERT_BITMAP_LEFT, ALERT_BITMAP_TOP, - EdgeTxTheme::instance()->busy, COLOR_THEME_WARNING); - } else { // confirmation - dc->drawMask(ALERT_BITMAP_LEFT, ALERT_BITMAP_TOP, - EdgeTxTheme::instance()->error, COLOR_THEME_WARNING); - } -} - void FullScreenDialog::closeDialog() { - if (confirmHandler) - confirmHandler(); - deleteLater(); + if (confirmHandler) confirmHandler(); + deleteLater(); } void FullScreenDialog::long_pressed(lv_event_t* e) @@ -183,10 +182,7 @@ void FullScreenDialog::onEvent(event_t event) } } -void FullScreenDialog::onCancel() -{ - deleteLater(); -} +void FullScreenDialog::onCancel() { deleteLater(); } void FullScreenDialog::checkEvents() { @@ -200,11 +196,12 @@ void FullScreenDialog::deleteLater(bool detach, bool trash) { if (running) { running = false; - } - else { + } else { Layer::pop(this); Window::deleteLater(detach, trash); } + Window* p = Layer::back(); + if (p) p->show(); } void FullScreenDialog::setMessage(std::string text) @@ -229,7 +226,7 @@ void FullScreenDialog::runForever(bool checkPwr) // reset input devices to avoid // RELEASED/CLICKED to be called in a loop lv_indev_reset(nullptr, nullptr); - + while (running) { resetBacklightTimeout(); @@ -253,7 +250,8 @@ void FullScreenDialog::runForever(bool checkPwr) deleteLater(); } -void raiseAlert(const char * title, const char * msg, const char * action, uint8_t sound) +void raiseAlert(const char* title, const char* msg, const char* action, + uint8_t sound) { TRACE("raiseAlert('%s')", msg); AUDIO_ERROR_MESSAGE(sound); diff --git a/radio/src/gui/colorlcd/fullscreen_dialog.h b/radio/src/gui/colorlcd/fullscreen_dialog.h index f166ebf5bce..312135aeb36 100644 --- a/radio/src/gui/colorlcd/fullscreen_dialog.h +++ b/radio/src/gui/colorlcd/fullscreen_dialog.h @@ -19,19 +19,10 @@ * GNU General Public License for more details. */ -#ifndef _FULLSCREEN_DIALOG_H_ -#define _FULLSCREEN_DIALOG_H_ +#pragma once #include "dialog.h" -enum DialogType { - WARNING_TYPE_ALERT, - WARNING_TYPE_ASTERISK, - WARNING_TYPE_CONFIRM, - WARNING_TYPE_INPUT, - WARNING_TYPE_INFO -}; - class StaticText; class FullScreenDialog : public Window @@ -50,8 +41,6 @@ class FullScreenDialog : public Window void setMessage(std::string text); - void paint(BitmapBuffer * dc) override; - void onEvent(event_t event) override; void onCancel() override; @@ -85,5 +74,3 @@ class FullScreenDialog : public Window static void long_pressed(lv_event_t* e); static void on_draw(lv_event_t* e); }; - -#endif // _FULLSCREEN_DIALOG_H_ diff --git a/radio/src/gui/colorlcd/getset_helpers.h b/radio/src/gui/colorlcd/getset_helpers.h index 428139c9b31..504706ef68e 100644 --- a/radio/src/gui/colorlcd/getset_helpers.h +++ b/radio/src/gui/colorlcd/getset_helpers.h @@ -19,26 +19,19 @@ * GNU General Public License for more details. */ -#ifndef _GETSET_HELPERS_H_ -#define _GETSET_HELPERS_H_ +#pragma once #define GET_VALUE(value) [=] { return value; } #define GET_DEFAULT(value) [=] { return value; } #define GET_INVERTED(value) [=] { return !value; } #define GET_VALUE_WITH_OFFSET(value, offset) [=] { return value + offset; } -#define GET_VALUE_WITH_BF(value, offset, bits) [=] { return bfGet(value, offset, bits); } #define SET_VALUE(value, _newValue) [=](int32_t newValue) { value = _newValue; SET_DIRTY(); } #define SET_DEFAULT(value) [=](int32_t newValue) { value = newValue; SET_DIRTY(); } #define SET_INVERTED(value) [=](uint8_t newValue) { value = !newValue; SET_DIRTY(); } #define SET_VALUE_WITH_OFFSET(value, offset) [=](int32_t newValue) { value = newValue - offset; SET_DIRTY(); } -#define SET_VALUE_WITH_BF(value, offset, bits) [=](uint16_t newValue) { bfSet(value, newValue, offset, bits); SET_DIRTY(); } #define GET_SET_DEFAULT(value) GET_DEFAULT(value), SET_DEFAULT(value) #define GET_SET_INVERTED(value) GET_INVERTED(value), SET_INVERTED(value) #define GET_SET_VALUE_WITH_OFFSET(value, offset) GET_VALUE_WITH_OFFSET(value, offset), SET_VALUE_WITH_OFFSET(value, offset) #define GET_SET_WITH_OFFSET(value, offset) GET_VALUE_WITH_OFFSET(value, offset), SET_VALUE_WITH_OFFSET(value, offset) -#define GET_SET_BF(value, offset, bits) GET_VALUE_WITH_BF(value, offset, bits), SET_VALUE_WITH_BF(value, offset, bits) - -#endif // _GETSET_HELPERS_H_ - diff --git a/radio/src/gui/colorlcd/gui.h b/radio/src/gui/colorlcd/gui.h deleted file mode 100644 index b8f9fcfa502..00000000000 --- a/radio/src/gui/colorlcd/gui.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _GUI_H_ -#define _GUI_H_ - -#include "gui_common.h" -#include "lcd.h" -#include "menus.h" -#include "popups.h" -#include "draw_functions.h" -#include "bitmaps.h" - -#define LOAD_MODEL_BITMAP() - -#if defined(FLIGHT_MODES) -void displayFlightModes(coord_t x, coord_t y, FlightModesType value, uint8_t attr); -FlightModesType editFlightModes(coord_t x, coord_t y, event_t event, FlightModesType value, uint8_t attr); -#else -#define displayFlightModes(...) -#endif - -// Curve functions -coord_t getCurveYCoord(FnFuncP fn, int x, int width); -void drawFunction(FnFuncP fn, int offset); -void drawCurveVerticalScale(int x); -void drawCurveHorizontalScale(); -void drawCurveCoord(int x, int y, const char * text, bool active=false); -void drawCurvePoint(int x, int y, LcdFlags color); - -extern WidgetsContainer * customScreens[MAX_CUSTOM_SCREENS]; - -void drawAlertBox(const char * title, const char * text, const char * action); -void showAlertBox(const char * title, const char * text, const char * action, uint8_t sound); - -#define IS_MAIN_VIEW_DISPLAYED() menuHandlers[0] == menuMainView -#define IS_TELEMETRY_VIEW_DISPLAYED() false -#define IS_OTHER_VIEW_DISPLAYED() false - -#endif // _GUI_H_ diff --git a/radio/src/gui/colorlcd/gvar_numberedit.cpp b/radio/src/gui/colorlcd/gvar_numberedit.cpp index 637c6c4d7a3..91c578d1f6c 100644 --- a/radio/src/gui/colorlcd/gvar_numberedit.cpp +++ b/radio/src/gui/colorlcd/gvar_numberedit.cpp @@ -43,8 +43,8 @@ GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin, textFlags(textFlags), voffset(voffset) { + padAll(PAD_TINY); lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW_WRAP); - lv_obj_set_style_pad_column(lvobj, lv_dpx(4), 0); lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0); lv_obj_set_size(lvobj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); @@ -68,7 +68,7 @@ GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin, num_field = new NumberEdit( this, rect_t{}, vmin, vmax, [=]() { return getValue() + voffset; }, - nullptr, windowFlags, textFlags); + nullptr, textFlags); num_field->setWidth(70); num_field->setDefault(vdefault); @@ -131,26 +131,23 @@ void GVarNumberEdit::update() { bool has_focus = act_field && act_field->hasFocus(); - auto gvar_obj = gvar_field->getLvObj(); - auto num_obj = num_field->getLvObj(); - - lv_obj_add_flag(gvar_obj, LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(num_obj, LV_OBJ_FLAG_HIDDEN); + gvar_field->hide(); + num_field->hide(); int32_t value = getValue(); if (GV_IS_GV_VALUE(value, vmin, vmax)) { // GVAR mode act_field = gvar_field; num_field->setSetValueHandler(nullptr); - lv_obj_clear_flag(gvar_obj, LV_OBJ_FLAG_HIDDEN); - lv_event_send(gvar_obj, LV_EVENT_VALUE_CHANGED, nullptr); + gvar_field->show(); + lv_event_send(gvar_field->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } else { // number edit mode act_field = num_field; num_field->setSetValueHandler( [=](int32_t newValue) { return setValue(newValue - voffset); }); num_field->setValue(value + voffset); - lv_obj_clear_flag(num_obj, LV_OBJ_FLAG_HIDDEN); + num_field->show(); } if (has_focus) { diff --git a/radio/src/gui/colorlcd/gvar_numberedit.h b/radio/src/gui/colorlcd/gvar_numberedit.h index 15570f84f5b..7253965d409 100644 --- a/radio/src/gui/colorlcd/gvar_numberedit.h +++ b/radio/src/gui/colorlcd/gvar_numberedit.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _GVAR_NUMBEREDIT_H_ -#define _GVAR_NUMBEREDIT_H_ +#pragma once #include "form.h" #include "choice.h" @@ -65,5 +64,3 @@ class GVarNumberEdit : public Window static void value_changed(lv_event_t* e); }; - -#endif // _GVAR_NUMBEREDIT_H_ diff --git a/radio/src/gui/colorlcd/hw_bluetooth.cpp b/radio/src/gui/colorlcd/hw_bluetooth.cpp index fadef719c1b..346d71d6fe1 100644 --- a/radio/src/gui/colorlcd/hw_bluetooth.cpp +++ b/radio/src/gui/colorlcd/hw_bluetooth.cpp @@ -20,6 +20,7 @@ */ #include "hw_bluetooth.h" + #include "opentx.h" #define SET_DIRTY() storageDirty(EE_GENERAL) @@ -29,108 +30,82 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3), static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -class BTDetailsDialog : public Dialog +class BTDetailsDialog : public BaseDialog { - StaticText* l_addr; - StaticText* r_addr; - - void setAddr(StaticText* label, const char* addr) - { - if (addr[0] == '\0') { - label->setText("---"); - } else { - label->setText(addr); - } - } - -public: - BTDetailsDialog(Window *parent) : - Dialog(parent, STR_BLUETOOTH, rect_t{}) + public: + BTDetailsDialog(Window* parent) : BaseDialog(parent, STR_BLUETOOTH, true) { - setCloseWhenClickOutside(true); - - auto form = &content->form; - form->setFlexLayout(); - FlexGridLayout grid(col_dsc, row_dsc); if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY) { - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_BLUETOOTH_PIN_CODE, 0, + auto line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_BLUETOOTH_PIN_CODE, COLOR_THEME_PRIMARY1); - new StaticText(line, rect_t{}, "000000", 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, "000000", COLOR_THEME_PRIMARY1); } // Local MAC - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_BLUETOOTH_LOCAL_ADDR, 0, + auto line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_BLUETOOTH_LOCAL_ADDR, COLOR_THEME_PRIMARY1); - l_addr = new StaticText(line, rect_t{}, "", 0, COLOR_THEME_PRIMARY1); + new DynamicText( + line, rect_t{}, + [=]() { + return std::string(bluetooth.localAddr[0] ? bluetooth.localAddr + : "---"); + }, + COLOR_THEME_PRIMARY1); // Remote MAC - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_BLUETOOTH_DIST_ADDR, 0, + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_BLUETOOTH_DIST_ADDR, COLOR_THEME_PRIMARY1); - r_addr = new StaticText(line, rect_t{}, "", 0, COLOR_THEME_PRIMARY1); - - content->setWidth(LCD_W * 0.8); - content->updateSize(); - } - - void checkEvents() override - { - setAddr(l_addr, bluetooth.localAddr); - setAddr(r_addr, bluetooth.distantAddr); + new DynamicText( + line, rect_t{}, + [=]() { + return std::string(bluetooth.distantAddr[0] ? bluetooth.distantAddr + : "---"); + }, + COLOR_THEME_PRIMARY1); } }; -static void bt_mode_changed(lv_event_t* e) +BluetoothConfigWindow::BluetoothConfigWindow(Window* parent, FlexGridLayout& grid) { - lv_obj_t* target = lv_event_get_target(e); - auto obj = (lv_obj_t*)lv_event_get_user_data(e); - auto choice = (Choice*)lv_obj_get_user_data(target); - if (!obj || !choice) return; + auto line = parent->newLine(grid); + new StaticText(line, rect_t{}, STR_MODE, COLOR_THEME_PRIMARY1); - if (choice->getIntValue() != BLUETOOTH_OFF) { - lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); - } -} - -BluetoothConfigWindow::BluetoothConfigWindow(Window *parent) : - FormWindow(parent, rect_t{}) -{ - setFlexLayout(); - FlexGridLayout grid(col_dsc, row_dsc, 2); - - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_MODE, 0, COLOR_THEME_PRIMARY1); - - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8)); + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_SMALL); lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); - auto mode = new Choice(box, rect_t{}, STR_BLUETOOTH_MODES, BLUETOOTH_OFF, - BLUETOOTH_TRAINER, GET_SET_DEFAULT(g_eeGeneral.bluetoothMode)); + auto mode = new Choice( + box, rect_t{}, STR_BLUETOOTH_MODES, BLUETOOTH_OFF, BLUETOOTH_TRAINER, + GET_DEFAULT(g_eeGeneral.bluetoothMode), [=](int value) { + g_eeGeneral.bluetoothMode = value; + settingsBtn->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF); + nameEdit->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF); + }); - auto btn = + settingsBtn = new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t { - new BTDetailsDialog(Layer::back()); + new BTDetailsDialog(parent); return 0; }); - btn->padAll(lv_dpx(4)); - btn->setWidth(LV_DPI_DEF / 2); + settingsBtn->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF); - lv_obj_add_event_cb(mode->getLvObj(), bt_mode_changed, - LV_EVENT_VALUE_CHANGED, btn->getLvObj()); - // BT radio name - line = newLine(&grid); - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); - new RadioTextEdit(line, rect_t{}, g_eeGeneral.bluetoothName, LEN_BLUETOOTH_NAME); + nameEdit = parent->newLine(grid); + new StaticText(nameEdit, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); - lv_obj_add_event_cb(mode->getLvObj(), bt_mode_changed, - LV_EVENT_VALUE_CHANGED, line->getLvObj()); + box = new Window(nameEdit, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_SMALL); + lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); + lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); + new RadioTextEdit(box, rect_t{}, g_eeGeneral.bluetoothName, + LEN_BLUETOOTH_NAME); + nameEdit->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF); } diff --git a/radio/src/gui/colorlcd/hw_bluetooth.h b/radio/src/gui/colorlcd/hw_bluetooth.h index 5e681872d73..08f83a29b38 100644 --- a/radio/src/gui/colorlcd/hw_bluetooth.h +++ b/radio/src/gui/colorlcd/hw_bluetooth.h @@ -23,8 +23,12 @@ #include "form.h" -class BluetoothConfigWindow : public FormWindow +class BluetoothConfigWindow { public: - BluetoothConfigWindow(Window* parent); + BluetoothConfigWindow(Window* parent, FlexGridLayout& grid); + + protected: + Window* settingsBtn = nullptr; + Window* nameEdit = nullptr; }; diff --git a/radio/src/gui/colorlcd/hw_extmodule.cpp b/radio/src/gui/colorlcd/hw_extmodule.cpp index b18d73df22a..c0da604e662 100644 --- a/radio/src/gui/colorlcd/hw_extmodule.cpp +++ b/radio/src/gui/colorlcd/hw_extmodule.cpp @@ -25,32 +25,16 @@ #define SET_DIRTY() storageDirty(EE_GENERAL) -static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3), - LV_GRID_TEMPLATE_LAST}; - -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; - -ExternalModuleWindow::ExternalModuleWindow(Window *parent) : - FormWindow::Line(parent), lastModule(g_eeGeneral.internalModule) +ExternalModuleWindow::ExternalModuleWindow(Window *parent, FlexGridLayout& grid) { - FlexGridLayout grid(col_dsc, row_dsc, 2); - setLayout(&grid); + auto line = parent->newLine(grid); - new StaticText(this, rect_t{}, STR_SAMPLE_MODE, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_SAMPLE_MODE, COLOR_THEME_PRIMARY1); - auto box = new FormWindow(this, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - new Choice(box, rect_t{}, STR_SAMPLE_MODES, 0, UART_SAMPLE_MODE_MAX, - getSampleMode, setSampleMode); -} - -int ExternalModuleWindow::getSampleMode() { return g_eeGeneral.uartSampleMode; } - -void ExternalModuleWindow::setSampleMode(int modeValue) -{ - g_eeGeneral.uartSampleMode = modeValue; - SET_DIRTY(); - restartModule(EXTERNAL_MODULE); + new Choice(line, rect_t{}, STR_SAMPLE_MODES, 0, UART_SAMPLE_MODE_MAX, + GET_DEFAULT(g_eeGeneral.uartSampleMode), [=](int modeValue) { + g_eeGeneral.uartSampleMode = modeValue; + SET_DIRTY(); + restartModule(EXTERNAL_MODULE); + }); } diff --git a/radio/src/gui/colorlcd/hw_extmodule.h b/radio/src/gui/colorlcd/hw_extmodule.h index b58510e981e..94d6157232b 100644 --- a/radio/src/gui/colorlcd/hw_extmodule.h +++ b/radio/src/gui/colorlcd/hw_extmodule.h @@ -23,15 +23,8 @@ #include "form.h" -class ExternalModuleWindow : public FormWindow::Line +class ExternalModuleWindow { public: - ExternalModuleWindow(Window* parent); - - protected: - uint8_t lastModule = 0; - lv_obj_t* br_box = nullptr; - - static int getSampleMode(); - static void setSampleMode(int modeValue); + ExternalModuleWindow(Window* parent, FlexGridLayout& grid); }; diff --git a/radio/src/gui/colorlcd/hw_inputs.cpp b/radio/src/gui/colorlcd/hw_inputs.cpp index 813a23d8d17..42d0faeeb4d 100644 --- a/radio/src/gui/colorlcd/hw_inputs.cpp +++ b/radio/src/gui/colorlcd/hw_inputs.cpp @@ -30,45 +30,46 @@ #define SET_DIRTY() storageDirty(EE_GENERAL) struct HWInputEdit : public RadioTextEdit { - HWInputEdit(Window* parent, char* name, size_t len) : - RadioTextEdit(parent, rect_t{}, name, len) + HWInputEdit(Window* parent, char* name, size_t len, coord_t x = 0, + coord_t y = 0) : + RadioTextEdit(parent, rect_t{x, y, 64, 32}, name, len) { - setWidth(LV_DPI_DEF / 2); } }; static const lv_coord_t col_two_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t col_three_dsc[] = {LV_GRID_FR(8), LV_GRID_FR(12), LV_GRID_FR(20), - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t col_three_dsc[] = { + LV_GRID_FR(8), LV_GRID_FR(12), LV_GRID_FR(20), LV_GRID_TEMPLATE_LAST}; #if LCD_W > LCD_H -static const lv_coord_t pots_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(2), LV_GRID_FR(5), - LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t pots_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(2), + LV_GRID_FR(5), LV_GRID_FR(2), + LV_GRID_TEMPLATE_LAST}; #else -static const lv_coord_t pots_col_dsc[] = {LV_GRID_FR(22), LV_GRID_FR(48), LV_GRID_FR(16), +static const lv_coord_t pots_col_dsc[] = {LV_GRID_FR(13), LV_GRID_FR(7), LV_GRID_TEMPLATE_LAST}; #endif static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -HWSticks::HWSticks(Window* parent) : FormWindow(parent, rect_t{}) +HWSticks::HWSticks(Window* parent) : Window(parent, rect_t{}) { - FlexGridLayout grid(col_two_dsc, row_dsc, 2); + FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY); setFlexLayout(); auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN); for (int i = 0; i < max_sticks; i++) { - auto line = newLine(&grid); - new StaticText(line, rect_t{}, analogGetCanonicalName(ADC_INPUT_MAIN, i), 0, + auto line = newLine(grid); + new StaticText(line, rect_t{}, analogGetCanonicalName(ADC_INPUT_MAIN, i), COLOR_THEME_PRIMARY1); new HWInputEdit(line, (char*)analogGetCustomLabel(ADC_INPUT_MAIN, i), LEN_ANA_NAME); } #if defined(STICK_DEAD_ZONE) - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_DEAD_ZONE, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_DEAD_ZONE, COLOR_THEME_PRIMARY1); auto dz = new Choice(line, rect_t{}, 0, 7, GET_SET_DEFAULT(g_eeGeneral.stickDeadZone)); dz->setTextHandler([](uint8_t value) { @@ -77,17 +78,39 @@ HWSticks::HWSticks(Window* parent) : FormWindow(parent, rect_t{}) #endif } -HWPots::HWPots(Window* parent) : FormWindow(parent, rect_t{}) -{ - FlexGridLayout grid(pots_col_dsc, row_dsc, 2); - setFlexLayout(); +// Absolute layout for Pots popup - due to performance issues with lv_textarea +// in a flex layout +#if LCD_W > LCD_H +#define P_LBL_X 0 +#define P_LBL_W ((coord_t)((DIALOG_DEFAULT_WIDTH - 30) * 2 / 11)) +#define P_NM_X (P_LBL_X + P_LBL_W + 6) +#define P_TYP_X (P_NM_X + 70) +#define P_TYP_W 160 +#define P_INV_X (P_TYP_X + P_TYP_W + 6) +#define P_INV_W 52 +#define P_Y(i) (i * 36 + 2) +#define P_OFST_Y 0 +#else +#define P_LBL_X 0 +#define P_LBL_W ((coord_t)((DIALOG_DEFAULT_WIDTH - 18) * 13 / 21)) +#define P_NM_X (P_LBL_X + P_LBL_W + 6) +#define P_TYP_X 0 +#define P_TYP_W P_LBL_W +#define P_INV_X (P_TYP_X + P_TYP_W + 6) +#define P_INV_W 52 +#define P_Y(i) (i * 72 + 2) +#define P_OFST_Y 36 +#endif +HWPots::HWPots(Window* parent) : + Window(parent, rect_t{0, 0, DIALOG_DEFAULT_WIDTH - 12, LV_SIZE_CONTENT}) +{ potsChanged = false; setCloseHandler([=]() { if (potsChanged) { - deleteCustomScreens(); - loadCustomScreens(); + LayoutFactory::deleteCustomScreens(); + LayoutFactory::loadCustomScreens(); } }); @@ -100,19 +123,15 @@ HWPots::HWPots(Window* parent) : FormWindow(parent, rect_t{}) // #if !defined(SIMU) && defined(RADIO_FAMILY_T16) // if (!globalData.flyskygimbals && (i >= (NUM_POTS - 2))) continue; // #endif - auto line = newLine(&grid); - new StaticText(line, rect_t{}, adcGetInputLabel(ADC_INPUT_FLEX, i), 0, - COLOR_THEME_PRIMARY1); + new StaticText(this, rect_t{P_LBL_X, P_Y(i) + 6, P_LBL_W, 32}, + adcGetInputLabel(ADC_INPUT_FLEX, i), COLOR_THEME_PRIMARY1); -#if LCD_H > LCD_W - line = newLine(&grid); -#endif + new HWInputEdit(this, (char*)analogGetCustomLabel(ADC_INPUT_FLEX, i), + LEN_ANA_NAME, P_NM_X, P_Y(i)); - new HWInputEdit(line, (char*)analogGetCustomLabel(ADC_INPUT_FLEX, i), - LEN_ANA_NAME); auto pot = new Choice( - line, rect_t{}, STR_POTTYPES, FLEX_NONE, FLEX_SWITCH, - [=]() -> int { return getPotType(i); }, + this, rect_t{P_TYP_X, P_Y(i) + P_OFST_Y, P_TYP_W, 32}, STR_POTTYPES, + FLEX_NONE, FLEX_SWITCH, [=]() -> int { return getPotType(i); }, [=](int newValue) { setPotType(i, newValue); switchFixFlexConfig(); @@ -122,7 +141,8 @@ HWPots::HWPots(Window* parent) : FormWindow(parent, rect_t{}) pot->setAvailableHandler([=](int val) { return isPotTypeAvailable(val); }); new ToggleSwitch( - line, rect_t{}, [=]() -> uint8_t { return (uint8_t)getPotInversion(i); }, + this, rect_t{P_INV_X, P_Y(i) + P_OFST_Y, P_INV_W, 32}, + [=]() -> uint8_t { return (uint8_t)getPotInversion(i); }, [=](int8_t newValue) { setPotInversion(i, newValue); SET_DIRTY(); @@ -130,11 +150,20 @@ HWPots::HWPots(Window* parent) : FormWindow(parent, rect_t{}) } } +// Absolute layout for Switches popup - due to performance issues with +// lv_textarea in a flex layout +#if LCD_W > LCD_H +#define SW_CTRL_W 86 +#else +#define SW_CTRL_W 75 +#endif + class SwitchDynamicLabel : public StaticText { public: - SwitchDynamicLabel(Window* parent, uint8_t index) : - StaticText(parent, rect_t{}, "", 0, COLOR_THEME_PRIMARY1), index(index) + SwitchDynamicLabel(Window* parent, uint8_t index, coord_t x, coord_t y) : + StaticText(parent, rect_t{x, y, SW_CTRL_W, 32}, "", COLOR_THEME_PRIMARY1), + index(index) { checkEvents(); } @@ -186,38 +215,36 @@ static void flex_channel_changed(lv_event_t* e) } } -HWSwitches::HWSwitches(Window* parent) : FormWindow(parent, rect_t{}) +HWSwitches::HWSwitches(Window* parent) : + Window(parent, rect_t{0, 0, DIALOG_DEFAULT_WIDTH - 12, LV_SIZE_CONTENT}) { - FlexGridLayout grid(col_three_dsc, row_dsc, 2); - setFlexLayout(); - auto max_switches = switchGetMaxSwitches(); for (int i = 0; i < max_switches; i++) { - auto line = newLine(&grid); - new SwitchDynamicLabel(line, i); - new HWInputEdit(line, (char*)switchGetCustomName(i), LEN_SWITCH_NAME); - - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(4)); - box->setWidth(lv_pct(45)); + new SwitchDynamicLabel(this, i, 2, i * 36 + 2); + new HWInputEdit(this, (char*)switchGetCustomName(i), LEN_SWITCH_NAME, + SW_CTRL_W + 8, i * 36 + 2); + coord_t x = SW_CTRL_W * 2 + 14; Choice* channel = nullptr; if (switchIsFlex(i)) { channel = new Choice( - box, rect_t{}, -1, adcGetMaxInputs(ADC_INPUT_FLEX) - 1, + this, rect_t{x, i * 36 + 2, SW_CTRL_W, 32}, -1, + adcGetMaxInputs(ADC_INPUT_FLEX) - 1, [=]() -> int { return switchGetFlexConfig(i); }, [=](int newValue) { switchConfigFlex(i, newValue); }); - channel->setAvailableHandler( - [=](int val) { return val < 0 || switchIsFlexInputAvailable(i, val); }); + channel->setAvailableHandler([=](int val) { + return val < 0 || switchIsFlexInputAvailable(i, val); + }); channel->setTextHandler([=](int val) -> std::string { if (val < 0) return STR_NONE; return adcGetInputLabel(ADC_INPUT_FLEX, val); }); + x += SW_CTRL_W + 6; } auto sw_cfg = new Choice( - box, rect_t{}, STR_SWTYPES, SWITCH_NONE, switchGetMaxType(i), - [=]() -> int { return SWITCH_CONFIG(i); }, + this, rect_t{x, i * 36 + 2, SW_CTRL_W, 32}, STR_SWTYPES, SWITCH_NONE, + switchGetMaxType(i), [=]() -> int { return SWITCH_CONFIG(i); }, [=](int newValue) { swconfig_t mask = (swconfig_t)SWITCH_CONFIG_MASK(i); g_eeGeneral.switchConfig = @@ -228,7 +255,8 @@ HWSwitches::HWSwitches(Window* parent) : FormWindow(parent, rect_t{}) if (channel) { lv_obj_t* obj = channel->getLvObj(); - lv_obj_add_event_cb(obj, flex_channel_changed, LV_EVENT_VALUE_CHANGED, sw_cfg); + lv_obj_add_event_cb(obj, flex_channel_changed, LV_EVENT_VALUE_CHANGED, + sw_cfg); lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); } } @@ -236,17 +264,9 @@ HWSwitches::HWSwitches(Window* parent) : FormWindow(parent, rect_t{}) template HWInputDialog::HWInputDialog(const char* title) : - Dialog(Layer::back(), std::string(), rect_t{}) + BaseDialog(Layer::back(), title, true) { - setCloseWhenClickOutside(true); - if (title) content->setTitle(title); - new T(&content->form); -#if LCD_W > LCD_H - content->setWidth(LCD_W * 0.8); -#else - content->setWidth(LCD_W * 0.95); -#endif - content->updateSize(); + new T(form); } template struct HWInputDialog; diff --git a/radio/src/gui/colorlcd/hw_inputs.h b/radio/src/gui/colorlcd/hw_inputs.h index 89c1e649866..7695bff2857 100644 --- a/radio/src/gui/colorlcd/hw_inputs.h +++ b/radio/src/gui/colorlcd/hw_inputs.h @@ -25,28 +25,28 @@ #include "dialog.h" #include "form.h" -struct HWSticks : public FormWindow { +struct HWSticks : public Window { HWSticks(Window* parent); }; -struct HWPots : public FormWindow { +struct HWPots : public Window { HWPots(Window* parent); bool potsChanged; }; -struct HWSwitches : public FormWindow { +struct HWSwitches : public Window { HWSwitches(Window* parent); }; template -struct HWInputDialog : public Dialog { +struct HWInputDialog : public BaseDialog { HWInputDialog(const char* title = nullptr); }; template TextButton* makeHWInputButton(Window* parent, const char* title) { - return new TextButton(parent, rect_t{}, title, [=]() { + return new TextButton(parent, rect_t{0, 0, 100, 0}, title, [=]() { new HWInputDialog(title); return 0; }); diff --git a/radio/src/gui/colorlcd/hw_intmodule.cpp b/radio/src/gui/colorlcd/hw_intmodule.cpp index 0a33207ac03..d9e0ecd68e1 100644 --- a/radio/src/gui/colorlcd/hw_intmodule.cpp +++ b/radio/src/gui/colorlcd/hw_intmodule.cpp @@ -20,51 +20,32 @@ */ #include "hw_intmodule.h" + #include "opentx.h" #if defined(CROSSFIRE) - #include "telemetry/crossfire.h" +#include "telemetry/crossfire.h" #endif #define SET_DIRTY() storageDirty(EE_GENERAL) -static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3), - LV_GRID_TEMPLATE_LAST}; - -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; - -InternalModuleWindow::InternalModuleWindow(Window *parent) : - FormWindow::Line(parent), - lastModule(g_eeGeneral.internalModule) +InternalModuleWindow::InternalModuleWindow(Window *parent, FlexGridLayout& grid) { - FlexGridLayout grid(col_dsc, row_dsc, 2); - setLayout(&grid); - - new StaticText(this, rect_t{}, STR_TYPE, 0, COLOR_THEME_PRIMARY1); - - auto box = new FormWindow(this, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - auto internalModule = new Choice( - box, rect_t{}, STR_MODULE_PROTOCOLS, MODULE_TYPE_NONE, - MODULE_TYPE_COUNT - 1, GET_DEFAULT(g_eeGeneral.internalModule), - [=](int type) { return setModuleType(type); }); + auto line = parent->newLine(grid); + new StaticText(line, rect_t{}, STR_TYPE, COLOR_THEME_PRIMARY1); + auto internalModule = + new Choice(line, rect_t{}, STR_MODULE_PROTOCOLS, MODULE_TYPE_NONE, + MODULE_TYPE_COUNT - 1, GET_DEFAULT(g_eeGeneral.internalModule), + [=](int type) { return setModuleType(type); }); internalModule->setAvailableHandler( [](int module) { return isInternalModuleSupported(module); }); #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) - auto pxx1_box = new FormWindow(box, rect_t{}); - pxx1_box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - - ant_box = pxx1_box->getLvObj(); - lv_obj_set_width(ant_box, LV_SIZE_CONTENT); - lv_obj_set_style_flex_cross_place(ant_box, LV_FLEX_ALIGN_CENTER, 0); - - new StaticText(pxx1_box, rect_t{}, STR_ANTENNA, 0, COLOR_THEME_PRIMARY1); + ant_box = parent->newLine(grid); + new StaticText(ant_box, rect_t{}, STR_ANTENNA, COLOR_THEME_PRIMARY1); new Choice( - pxx1_box, rect_t{}, STR_ANTENNA_MODES, ANTENNA_MODE_INTERNAL, + ant_box, rect_t{}, STR_ANTENNA_MODES, ANTENNA_MODE_INTERNAL, ANTENNA_MODE_EXTERNAL, GET_DEFAULT(g_eeGeneral.antennaMode), [](int antenna) { if (!isExternalAntennaEnabled() && @@ -87,16 +68,18 @@ InternalModuleWindow::InternalModuleWindow(Window *parent) : #endif #if defined(CROSSFIRE) - auto crsf_box = new FormWindow(box, rect_t{}); - crsf_box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - - br_box = crsf_box->getLvObj(); - lv_obj_set_width(br_box, LV_SIZE_CONTENT); - lv_obj_set_style_flex_cross_place(br_box, LV_FLEX_ALIGN_CENTER, 0); - - new StaticText(crsf_box, rect_t{}, STR_BAUDRATE, 0, COLOR_THEME_PRIMARY1); - new Choice(crsf_box, rect_t{}, STR_CRSF_BAUDRATE, 0, - CROSSFIRE_MAX_INTERNAL_BAUDRATE, getBaudrate, setBaudrate); + br_box = parent->newLine(grid); + new StaticText(br_box, rect_t{}, STR_BAUDRATE, COLOR_THEME_PRIMARY1); + new Choice( + br_box, rect_t{}, STR_CRSF_BAUDRATE, 0, CROSSFIRE_MAX_INTERNAL_BAUDRATE, + [=]() { + return CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate); + }, + [=](int val) { + g_eeGeneral.internalModuleBaudrate = CROSSFIRE_INDEX_TO_STORE(val); + restartModule(INTERNAL_MODULE); + SET_DIRTY(); + }); updateBaudrateLine(); #endif @@ -114,38 +97,16 @@ void InternalModuleWindow::setModuleType(int moduleType) SET_DIRTY(); } -#if defined(CROSSFIRE) -int InternalModuleWindow::getBaudrate() -{ - return CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate); -} - -void InternalModuleWindow::setBaudrate(int val) -{ - g_eeGeneral.internalModuleBaudrate = CROSSFIRE_INDEX_TO_STORE(val); - restartModule(INTERNAL_MODULE); - SET_DIRTY(); -} -#endif - void InternalModuleWindow::updateBaudrateLine() { #if defined(CROSSFIRE) - if (isInternalModuleCrossfire()) { - lv_obj_clear_flag(br_box, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(br_box, LV_OBJ_FLAG_HIDDEN); - } + br_box->show(isInternalModuleCrossfire()); #endif } void InternalModuleWindow::updateAntennaLine() { #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) - if (isInternalModuleAvailable(MODULE_TYPE_XJT_PXX1)) { - lv_obj_clear_flag(ant_box, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(ant_box, LV_OBJ_FLAG_HIDDEN); - } + ant_box->show(isInternalModuleAvailable(MODULE_TYPE_XJT_PXX1)); #endif } diff --git a/radio/src/gui/colorlcd/hw_intmodule.h b/radio/src/gui/colorlcd/hw_intmodule.h index ce2f744c9e1..75e0e707c2c 100644 --- a/radio/src/gui/colorlcd/hw_intmodule.h +++ b/radio/src/gui/colorlcd/hw_intmodule.h @@ -23,20 +23,14 @@ #include "form.h" -class InternalModuleWindow : public FormWindow::Line +class InternalModuleWindow { public: - InternalModuleWindow(Window *parent); + InternalModuleWindow(Window *parent, FlexGridLayout& grid); protected: - uint8_t lastModule = 0; - lv_obj_t* br_box = nullptr; - lv_obj_t* ant_box = nullptr; - -#if defined(CROSSFIRE) - static int getBaudrate(); - static void setBaudrate(int val); -#endif + Window* br_box = nullptr; + Window* ant_box = nullptr; void setModuleType(int moduleType); void updateBaudrateLine(); diff --git a/radio/src/gui/colorlcd/hw_serial.cpp b/radio/src/gui/colorlcd/hw_serial.cpp index ade534273ee..6d27e09cdc9 100644 --- a/radio/src/gui/colorlcd/hw_serial.cpp +++ b/radio/src/gui/colorlcd/hw_serial.cpp @@ -24,17 +24,8 @@ #define SET_DIRTY() storageDirty(EE_GENERAL) -static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3), - LV_GRID_TEMPLATE_LAST}; - -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; - -SerialConfigWindow::SerialConfigWindow(Window *parent, const rect_t &rect) : - FormWindow(parent, rect) +SerialConfigWindow::SerialConfigWindow(Window *parent, FlexGridLayout& grid) { - setFlexLayout(); - FlexGridLayout grid(col_dsc, row_dsc, 2); - bool display_ttl_warning = false; for (uint8_t port_nr = 0; port_nr < MAX_SERIAL_PORTS; port_nr++) { auto port = serialGetPort(port_nr); @@ -42,11 +33,12 @@ SerialConfigWindow::SerialConfigWindow(Window *parent, const rect_t &rect) : if (port_nr != SP_VCP) display_ttl_warning = true; - auto line = newLine(&grid); - new StaticText(line, rect_t{}, port->name, 0, COLOR_THEME_PRIMARY1); + auto line = parent->newLine(grid); + (new StaticText(line, rect_t{}, port->name, COLOR_THEME_PRIMARY1))->padLeft(PAD_SMALL); - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM); lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); @@ -62,7 +54,7 @@ SerialConfigWindow::SerialConfigWindow(Window *parent, const rect_t &rect) : [=](int value) { return isSerialModeAvailable(port_nr, value); }); if (port->set_pwr != nullptr) { - new StaticText(box, rect_t{}, STR_AUX_SERIAL_PORT_POWER, 0, + new StaticText(box, rect_t{}, STR_AUX_SERIAL_PORT_POWER, COLOR_THEME_PRIMARY1); new ToggleSwitch( box, rect_t{}, [=] { return serialGetPower(port_nr); }, @@ -75,7 +67,8 @@ SerialConfigWindow::SerialConfigWindow(Window *parent, const rect_t &rect) : if (display_ttl_warning) { grid.setColSpan(2); - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_TTL_WARNING, 0, COLOR_THEME_WARNING); + auto line = parent->newLine(grid); + (new StaticText(line, rect_t{}, STR_TTL_WARNING, COLOR_THEME_WARNING))->padLeft(PAD_SMALL); + grid.setColSpan(1); } } diff --git a/radio/src/gui/colorlcd/hw_serial.h b/radio/src/gui/colorlcd/hw_serial.h index 573111f38f0..e29dd772cdf 100644 --- a/radio/src/gui/colorlcd/hw_serial.h +++ b/radio/src/gui/colorlcd/hw_serial.h @@ -23,8 +23,8 @@ #include "form.h" -class SerialConfigWindow : public FormWindow +class SerialConfigWindow { public: - SerialConfigWindow(Window *parent, const rect_t &rect); + SerialConfigWindow(Window *parent, FlexGridLayout& grid); }; diff --git a/radio/src/gui/colorlcd/input_edit.cpp b/radio/src/gui/colorlcd/input_edit.cpp index 127b2335fc8..1e916e1bf72 100644 --- a/radio/src/gui/colorlcd/input_edit.cpp +++ b/radio/src/gui/colorlcd/input_edit.cpp @@ -20,57 +20,57 @@ */ #include "input_edit.h" -#include "input_edit_adv.h" #include "curve_param.h" +#include "curveedit.h" #include "gvar_numberedit.h" +#include "input_edit_adv.h" #include "input_source.h" -#include "curveedit.h" - #include "opentx.h" +#include "themes/etx_lv_theme.h" +#include "switchchoice.h" #define SET_DIRTY() storageDirty(EE_MODEL) +#if LCD_W > LCD_H +constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 140; +constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH; +#else +constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 176; +constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = 132; +#endif + InputEditWindow::InputEditWindow(int8_t input, uint8_t index) : - Page(ICON_MODEL_INPUTS), - input(input), - index(index) + Page(ICON_MODEL_INPUTS), input(input), index(index) { std::string title2(getSourceString(MIXSRC_FIRST_INPUT + input)); header.setTitle(STR_MENUINPUTS); header.setTitle2(title2); auto body_obj = body.getLvObj(); -#if LCD_H > LCD_W // portrait +#if LCD_H > LCD_W // portrait lv_obj_set_flex_flow(body_obj, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_pad_row(body_obj, lv_dpx(8), 0); -#else // landscape +#else // landscape lv_obj_set_flex_flow(body_obj, LV_FLEX_FLOW_ROW); - lv_obj_set_style_pad_column(body_obj, lv_dpx(8), 0); #endif lv_obj_set_style_flex_cross_place(body_obj, LV_FLEX_ALIGN_CENTER, 0); - - // TODO: would be better to set the padding on the preview window... - // ...but it doesn't support it yet. - lv_obj_set_style_pad_all(body_obj, lv_dpx(8), 0); auto box = new Window(&body, rect_t{}); auto box_obj = box->getLvObj(); lv_obj_set_flex_grow(box_obj, 2); - lv_obj_set_scrollbar_mode(box->getLvObj(), LV_SCROLLBAR_MODE_AUTO); + etx_scrollbar(box_obj); -#if LCD_H > LCD_W // portrait - box->setWidth(body.width() - 2*lv_dpx(8)); -#else // landscape - box->setHeight(body.height() - 2*lv_dpx(8)); +#if LCD_H > LCD_W // portrait + box->setWidth(body.width() - 2 * lv_dpx(8)); +#else // landscape + box->setHeight(body.height() - 2 * lv_dpx(8)); #endif - auto form = new FormWindow(box, rect_t{}); - auto form_obj = form->getLvObj(); - lv_obj_set_style_pad_all(form_obj, lv_dpx(8), 0); + auto form = new Window(box, rect_t{}); buildBody(form); - preview = new Curve(&body, rect_t{0, 0, INPUT_EDIT_CURVE_WIDTH, INPUT_EDIT_CURVE_HEIGHT}, + preview = new Curve( + &body, rect_t{0, 0, INPUT_EDIT_CURVE_WIDTH, INPUT_EDIT_CURVE_HEIGHT}, [=](int x) -> int { ExpoData* line = expoAddress(index); int16_t anas[MAX_INPUTS] = {0}; @@ -86,77 +86,78 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -void InputEditWindow::buildBody(FormWindow* form) +void InputEditWindow::buildBody(Window* form) { - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); form->setFlexLayout(); ExpoData* input = expoAddress(index); // Input Name - auto line = form->newLine(&grid); + auto line = form->newLine(grid); auto inputName = g_model.inputNames[input->chn]; - new StaticText(line, rect_t{}, STR_INPUTNAME, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_INPUTNAME, COLOR_THEME_PRIMARY1); new ModelTextEdit(line, rect_t{}, inputName, LEN_INPUT_NAME); // Line Name - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_EXPONAME, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_EXPONAME, COLOR_THEME_PRIMARY1); new ModelTextEdit(line, rect_t{}, input->name, LEN_EXPOMIX_NAME); // Source - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SOURCE, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_SOURCE, COLOR_THEME_PRIMARY1); auto src = new InputSource(line, input); lv_obj_set_style_grid_cell_x_align(src->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); // Weight - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_WEIGHT, 0, COLOR_THEME_PRIMARY1); - auto gvar = new GVarNumberEdit(line, rect_t{}, -100, 100, - GET_DEFAULT(input->weight), - [=](int32_t newValue) { - input->weight = newValue; - preview->invalidate(); - SET_DIRTY(); - }); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_WEIGHT, COLOR_THEME_PRIMARY1); + auto gvar = + new GVarNumberEdit(line, rect_t{}, -100, 100, GET_DEFAULT(input->weight), + [=](int32_t newValue) { + input->weight = newValue; + preview->update(); + SET_DIRTY(); + }); gvar->setSuffix("%"); // Offset - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_OFFSET, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_OFFSET, COLOR_THEME_PRIMARY1); gvar = new GVarNumberEdit(line, rect_t{}, -100, 100, - GET_DEFAULT(input->offset), - [=](int32_t newValue) { + GET_DEFAULT(input->offset), [=](int32_t newValue) { input->offset = newValue; - preview->invalidate(); + preview->update(); SET_DIRTY(); }); gvar->setSuffix("%"); // Switch - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SWITCH, 0, COLOR_THEME_PRIMARY1); - new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, - SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(input->swtch)); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_SWITCH, COLOR_THEME_PRIMARY1); + new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, + GET_SET_DEFAULT(input->swtch)); // Curve - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_CURVE, 0, COLOR_THEME_PRIMARY1); - auto param = new CurveParam(line, rect_t{}, &input->curve, - [=](int32_t newValue) { - input->curve.value = newValue; - preview->invalidate(); - SET_DIRTY(); - }); - lv_obj_set_style_grid_cell_x_align(param->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - line = form->newLine(); - lv_obj_set_style_pad_all(line->getLvObj(), lv_dpx(8), 0); - auto btn = new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t { - new InputEditAdvanced(this->input, index); - return 0; - }); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_CURVE, COLOR_THEME_PRIMARY1); + auto param = + new CurveParam(line, rect_t{}, &input->curve, [=](int32_t newValue) { + input->curve.value = newValue; + preview->update(); + SET_DIRTY(); + }); + lv_obj_set_style_grid_cell_x_align(param->getLvObj(), LV_GRID_ALIGN_STRETCH, + 0); + + line = form->newLine(grid); + line->padAll(PAD_LARGE); + auto btn = + new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t { + new InputEditAdvanced(this->input, index); + return 0; + }); lv_obj_set_width(btn->getLvObj(), lv_pct(100)); } diff --git a/radio/src/gui/colorlcd/input_edit.h b/radio/src/gui/colorlcd/input_edit.h index e1463df6d64..b6d4654dd38 100644 --- a/radio/src/gui/colorlcd/input_edit.h +++ b/radio/src/gui/colorlcd/input_edit.h @@ -37,7 +37,7 @@ class InputEditWindow : public Page uint8_t index; Curve* preview; - void buildBody(FormWindow *window); + void buildBody(Window *window); void deleteLater(bool detach = true, bool trash = true) override; }; diff --git a/radio/src/gui/colorlcd/input_edit_adv.cpp b/radio/src/gui/colorlcd/input_edit_adv.cpp index 0d1024588a3..9e031ec3aec 100644 --- a/radio/src/gui/colorlcd/input_edit_adv.cpp +++ b/radio/src/gui/colorlcd/input_edit_adv.cpp @@ -20,9 +20,10 @@ */ #include "input_edit_adv.h" -#include "fm_matrix.h" +#include "fm_matrix.h" #include "opentx.h" +#include "themes/etx_lv_theme.h" #define SET_DIRTY() storageDirty(EE_MODEL) @@ -37,17 +38,14 @@ InputEditAdvanced::InputEditAdvanced(uint8_t input_n, uint8_t index) : header.setTitle(STR_MENUINPUTS); header.setTitle2(title2); - rect_t r = rect_t{0, 0, body.width(), body.height()}; - auto form = new FormWindow(&body, r); - - FlexGridLayout grid(col_dsc, row_dsc, 2); - form->setFlexLayout(); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); + body.setFlexLayout(); ExpoData* input = expoAddress(index); // Side - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SIDE, 0, COLOR_THEME_PRIMARY1); + auto line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_SIDE, COLOR_THEME_PRIMARY1); new Choice( line, rect_t{}, STR_VCURVEFUNC, 1, 3, [=]() -> int16_t { return 4 - input->mode; }, @@ -57,8 +55,8 @@ InputEditAdvanced::InputEditAdvanced(uint8_t input_n, uint8_t index) : }); // Trim - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_TRIM, 0, COLOR_THEME_PRIMARY1); + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_TRIM, COLOR_THEME_PRIMARY1); auto c = new Choice(line, rect_t{}, -TRIM_OFF, -TRIM_LAST, GET_VALUE(-input->trimSource), SET_VALUE(input->trimSource, -newValue)); @@ -73,8 +71,8 @@ InputEditAdvanced::InputEditAdvanced(uint8_t input_n, uint8_t index) : // Flight modes if (modelFMEnabled()) { - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_FLMODE, 0, COLOR_THEME_PRIMARY1); + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_FLMODE, COLOR_THEME_PRIMARY1); new FMMatrix(line, rect_t{}, input); } } diff --git a/radio/src/gui/colorlcd/input_mix_button.cpp b/radio/src/gui/colorlcd/input_mix_button.cpp index e4879373ea6..642602c7b76 100644 --- a/radio/src/gui/colorlcd/input_mix_button.cpp +++ b/radio/src/gui/colorlcd/input_mix_button.cpp @@ -21,12 +21,7 @@ #include "input_mix_button.h" #include "opentx.h" - -// icon: 17 x 17 -static const uint8_t _mask_textline_fm[] = { -#include "mask_textline_fm.lbm" -}; -STATIC_LZ4_BITMAP(mask_textline_fm); +#include "bitmaps.h" // total: 92 x 17 #define FM_CANVAS_HEIGHT 17 @@ -129,13 +124,12 @@ void InputMixButton::setFlightModes(uint16_t modes) lv_canvas_fill_bg(fm_canvas, lv_color_black(), LV_OPA_TRANSP); - auto mask = (const uint8_t*)mask_textline_fm; - auto mask_hdr = (const uint16_t*)mask; - lv_coord_t w = mask_hdr[0]; - lv_coord_t h = mask_hdr[1]; + const MaskBitmap* mask = getBuiltinIcon(ICON_TEXTLINE_FM); + lv_coord_t w = mask->width; + lv_coord_t h = mask->height; coord_t x = 0; - lv_canvas_copy_buf(fm_canvas, mask + 4, x, 0, w, h); + lv_canvas_copy_buf(fm_canvas, mask->data, x, 0, w, h); x += 20; lv_draw_label_dsc_t label_dsc; diff --git a/radio/src/gui/colorlcd/input_mix_group.cpp b/radio/src/gui/colorlcd/input_mix_group.cpp index 7ddc0280c1c..66f9f9d7858 100644 --- a/radio/src/gui/colorlcd/input_mix_group.cpp +++ b/radio/src/gui/colorlcd/input_mix_group.cpp @@ -20,18 +20,46 @@ */ #include "input_mix_group.h" -#include "channel_bar.h" +#include + +#include "channel_bar.h" #include "opentx.h" +#include "themes/etx_lv_theme.h" -#include +static void input_mix_group_constructor(const lv_obj_class_t* class_p, + lv_obj_t* obj) +{ + etx_std_style(obj, LV_PART_MAIN, PAD_TINY); +} + +static const lv_obj_class_t input_mix_group_class = { + .base_class = &lv_obj_class, + .constructor_cb = input_mix_group_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LV_PCT(100), + .height_def = LV_SIZE_CONTENT, + .editable = LV_OBJ_CLASS_EDITABLE_FALSE, + .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, + .instance_size = sizeof(lv_obj_t), +}; + +static lv_obj_t* input_mix_group_create(lv_obj_t* parent) +{ + return etx_create(&input_mix_group_class, parent); +} static const lv_coord_t col_dsc[] = { - lv_coord_t(LV_DPI_DEF * 0.55), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST, + lv_coord_t(LV_DPI_DEF * 0.55), + LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST, }; static const lv_coord_t row_dsc[] = { - LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST, + LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST, }; void InputMixGroup::value_changed(lv_event_t* e) @@ -39,61 +67,60 @@ void InputMixGroup::value_changed(lv_event_t* e) auto obj = lv_event_get_target(e); auto group = (InputMixGroup*)lv_obj_get_user_data(obj); if (!group) return; - + lv_label_set_text(group->label, getSourceString(group->idx)); } InputMixGroup::InputMixGroup(Window* parent, mixsrc_t idx) : - Window(parent, rect_t{}, 0, 0, input_mix_group_create), idx(idx) + Window(parent, rect_t{}, NO_FOCUS, 0, input_mix_group_create), idx(idx) { + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE); + padAll(PAD_ZERO); + lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); lv_obj_set_grid_dsc_array(lvobj, col_dsc, row_dsc); lv_obj_add_event_cb(lvobj, InputMixGroup::value_changed, LV_EVENT_VALUE_CHANGED, nullptr); lv_obj_t* chText = nullptr; - if (idx >= MIXSRC_FIRST_CH && idx <= MIXSRC_LAST_CH - && g_model.limitData[idx - MIXSRC_FIRST_CH].name[0] != '\0') { + if (idx >= MIXSRC_FIRST_CH && idx <= MIXSRC_LAST_CH && + g_model.limitData[idx - MIXSRC_FIRST_CH].name[0] != '\0') { chText = lv_label_create(lvobj); - lv_label_set_text_fmt(chText, TR_CH "%" PRIu32, UINT32_C(idx - MIXSRC_FIRST_CH + 1)); - lv_obj_set_style_text_font(chText, getFont(FONT(XS)), 0); -#if LCD_H > LCD_W - lv_obj_set_style_pad_bottom(chText, -2, 0); -#endif - lv_obj_set_grid_cell(chText, - LV_GRID_ALIGN_START, 0, 1, - LV_GRID_ALIGN_END, 0, 1); + etx_font(chText, FONT_XS_INDEX); + lv_label_set_text_fmt(chText, TR_CH "%" PRIu32, + UINT32_C(idx - MIXSRC_FIRST_CH + 1)); + lv_obj_set_style_pad_left(chText, PAD_TINY, 0); + lv_obj_set_grid_cell(chText, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_END, + 0, 1); } label = lv_label_create(lvobj); - lv_obj_set_style_text_font(label, getFont(FONT(STD)), 0); -#if LCD_H > LCD_W - if(chText) - lv_obj_set_style_pad_top(label, -1, 0); -#endif + etx_font(label, FONT_STD_INDEX); + if (chText) lv_obj_set_style_pad_top(label, -1, 0); lv_label_set_text(label, getSourceString(idx)); - lv_obj_set_grid_cell(label, - LV_GRID_ALIGN_START, 0, 1, - chText?LV_GRID_ALIGN_START:LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_style_pad_left(label, PAD_TINY, 0); + lv_obj_set_grid_cell(label, LV_GRID_ALIGN_START, 0, 1, + chText ? LV_GRID_ALIGN_START : LV_GRID_ALIGN_CENTER, 0, + 1); auto box = window_create(lvobj); lv_obj_set_size(box, lv_pct(100), LV_SIZE_CONTENT); - lv_obj_set_grid_cell(box, - LV_GRID_ALIGN_STRETCH, 1, 1, - LV_GRID_ALIGN_START, 0, 1); - + lv_obj_set_grid_cell(box, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_START, 0, + 1); + line_container = window_create(box); lv_obj_set_size(line_container, lv_pct(100), LV_SIZE_CONTENT); lv_obj_set_flex_flow(line_container, LV_FLEX_FLOW_COLUMN); lv_obj_set_style_flex_cross_place(line_container, LV_FLEX_ALIGN_END, 0); - lv_obj_set_style_pad_row(line_container, lv_dpx(4), LV_PART_MAIN); + lv_obj_set_style_pad_all(line_container, PAD_TINY, LV_PART_MAIN); + lv_obj_set_style_pad_row(line_container, PAD_TINY, LV_PART_MAIN); } void InputMixGroup::enableMixerMonitor(uint8_t channel) { if (monitor != nullptr) return; - rect_t r{ 0, 0, 100, 14 }; + rect_t r{0, 0, 100, 14}; monitor = new MixerChannelBar(this, r, channel); lv_obj_t* mon_obj = monitor->getLvObj(); @@ -118,9 +145,8 @@ void InputMixGroup::addLine(Window* line, const uint8_t* symbol) bool InputMixGroup::removeLine(Window* line) { - auto l = std::find_if(lines.begin(), lines.begin(), [=](const Line& l) -> bool { - return l.win == line; - }); + auto l = std::find_if(lines.begin(), lines.begin(), + [=](const Line& l) -> bool { return l.win == line; }); if (l != lines.end()) { lines.erase(l); diff --git a/radio/src/gui/colorlcd/input_source.cpp b/radio/src/gui/colorlcd/input_source.cpp index 050d7318543..e56a298fbc3 100644 --- a/radio/src/gui/colorlcd/input_source.cpp +++ b/radio/src/gui/colorlcd/input_source.cpp @@ -20,7 +20,10 @@ */ #include "input_source.h" + #include "opentx.h" +#include "sourcechoice.h" +#include "switchchoice.h" #define SET_DIRTY() storageDirty(EE_MODEL) @@ -40,8 +43,7 @@ class SensorValue : public StaticText void checkEvents() override { - if (lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN)) - return; + if (lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN)) return; // TODO: check for telemetry available if (isTelemetryValue()) { @@ -49,7 +51,7 @@ class SensorValue : public StaticText if (lastSensorVal != sensorVal) { lastSensorVal = sensorVal; setText(std::to_string(lastSensorVal)); - } + } } else { setText("---"); } @@ -76,7 +78,7 @@ class SensorValue : public StaticText void InputSource::value_changed(lv_event_t *e) { auto obj = lv_event_get_target(e); - auto src = (InputSource*)lv_obj_get_user_data(obj); + auto src = (InputSource *)lv_obj_get_user_data(obj); if (!src) return; src->update(); @@ -86,39 +88,41 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -InputSource::InputSource(Window* parent, ExpoData* input) : - Window(parent, rect_t{}), input(input) +InputSource::InputSource(Window *parent, ExpoData *input) : + Window(parent, rect_t{}), input(input) { + padAll(PAD_TINY); lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_pad_row(lvobj, lv_dpx(4), 0); lv_obj_set_size(lvobj, lv_pct(100), LV_SIZE_CONTENT); - new SourceChoice( - this, rect_t{}, INPUTSRC_FIRST, INPUTSRC_LAST, GET_DEFAULT(input->srcRaw), - [=](int32_t newValue) { - input->srcRaw = newValue; - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); - SET_DIRTY(); - }); - lv_obj_add_event_cb(lvobj, InputSource::value_changed, LV_EVENT_VALUE_CHANGED, nullptr); - - sensor_form = new FormWindow(this, rect_t{}); + new SourceChoice(this, rect_t{}, INPUTSRC_FIRST, INPUTSRC_LAST, + GET_DEFAULT(input->srcRaw), [=](int32_t newValue) { + input->srcRaw = newValue; + lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); + SET_DIRTY(); + }); + lv_obj_add_event_cb(lvobj, InputSource::value_changed, LV_EVENT_VALUE_CHANGED, + nullptr); + + sensor_form = new Window(this, rect_t{}); + sensor_form->padAll(PAD_TINY); sensor_form->setFlexLayout(); FlexGridLayout grid(col_dsc, row_dsc); - auto line = sensor_form->newLine(&grid); + auto line = sensor_form->newLine(grid); + line->padAll(PAD_ZERO); // Value - new StaticText(line, rect_t{}, STR_VALUE, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_VALUE, COLOR_THEME_PRIMARY1); auto sensor = new SensorValue(line, rect_t{}, input); - // Scale - line = sensor_form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SCALE, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(line, rect_t{}, 0, + line = sensor_form->newLine(grid); + line->padAll(PAD_TINY); + new StaticText(line, rect_t{}, STR_SCALE, COLOR_THEME_PRIMARY1); + new NumberEdit(line, rect_t{0, 0, 60, 0}, 0, maxTelemValue(input->srcRaw - MIXSRC_FIRST_TELEM + 1), - GET_SET_DEFAULT(input->scale), 0, sensor->getSensorPrec()); + GET_SET_DEFAULT(input->scale), sensor->getSensorPrec()); update(); } @@ -129,13 +133,7 @@ void InputSource::update() input->trimSource = TRIM_OFF; } - if (!sensor_form) return; - auto sensor_form_obj = sensor_form->getLvObj(); - - if (input->srcRaw >= MIXSRC_FIRST_TELEM && - input->srcRaw <= MIXSRC_LAST_TELEM) { - lv_obj_clear_flag(sensor_form_obj, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(sensor_form_obj, LV_OBJ_FLAG_HIDDEN); - } + if (sensor_form) + sensor_form->show(input->srcRaw >= MIXSRC_FIRST_TELEM && + input->srcRaw <= MIXSRC_LAST_TELEM); } diff --git a/radio/src/gui/colorlcd/input_source.h b/radio/src/gui/colorlcd/input_source.h index d3f058d97a3..2353ecdfd0f 100644 --- a/radio/src/gui/colorlcd/input_source.h +++ b/radio/src/gui/colorlcd/input_source.h @@ -24,12 +24,12 @@ #include "window.h" struct ExpoData; -class FormWindow; +class Window; class InputSource : public Window { ExpoData* input; - FormWindow* sensor_form; + Window* sensor_form; void update(); static void value_changed(lv_event_t* e); diff --git a/radio/src/gui/colorlcd/layout.cpp b/radio/src/gui/colorlcd/layout.cpp index 8b5651da222..be5d16c8402 100644 --- a/radio/src/gui/colorlcd/layout.cpp +++ b/radio/src/gui/colorlcd/layout.cpp @@ -20,25 +20,19 @@ */ #include "opentx.h" -#include "view_main.h" -#include "topbar_impl.h" #include "theme.h" +#include "topbar_impl.h" +#include "view_main.h" -WidgetsContainer * customScreens[MAX_CUSTOM_SCREENS] = {}; +WidgetsContainer* customScreens[MAX_CUSTOM_SCREENS] = {}; -std::list & getRegisteredLayouts() +std::list& LayoutFactory::getRegisteredLayouts() { - static std::list layouts; + static std::list layouts; return layouts; } -void registerLayout(const LayoutFactory * factory) -{ - TRACE("register layout %s", factory->getId()); - getRegisteredLayouts().push_back(factory); -} - -const LayoutFactory * getLayoutFactory(const char * name) +const LayoutFactory* LayoutFactory::getLayoutFactory(const char* name) { auto it = getRegisteredLayouts().cbegin(); for (; it != getRegisteredLayouts().cend(); ++it) { @@ -52,10 +46,10 @@ const LayoutFactory * getLayoutFactory(const char * name) // // Loads a layout, but does not attach it to any window // -WidgetsContainer * -loadLayout(Window* parent, const char * name, LayoutPersistentData * persistentData) +WidgetsContainer* LayoutFactory::loadLayout( + Window* parent, const char* name, LayoutPersistentData* persistentData) { - const LayoutFactory * factory = getLayoutFactory(name); + const LayoutFactory* factory = getLayoutFactory(name); if (factory) { return factory->load(parent, persistentData); } @@ -65,7 +59,7 @@ loadLayout(Window* parent, const char * name, LayoutPersistentData * persistentD // // Detaches and deletes all custom screens // -void deleteCustomScreens() +void LayoutFactory::deleteCustomScreens() { for (auto& screen : customScreens) { if (screen) { @@ -75,15 +69,12 @@ void deleteCustomScreens() } } -extern const LayoutFactory * defaultLayout; - -void loadDefaultLayout() +void LayoutFactory::loadDefaultLayout() { auto& screen = customScreens[0]; auto& screenData = g_model.screenData[0]; if (screen == nullptr && defaultLayout != nullptr) { - strcpy(screenData.LayoutId, defaultLayout->getId()); auto viewMain = ViewMain::instance(); @@ -103,13 +94,12 @@ void loadDefaultLayout() // // Loads and attaches all configured custom screens // -void loadCustomScreens() +void LayoutFactory::loadCustomScreens() { unsigned i = 0; auto viewMain = ViewMain::instance(); while (i < MAX_CUSTOM_SCREENS) { - auto& screen = customScreens[i]; screen = loadLayout(viewMain, g_model.screenData[i].LayoutId, &g_model.screenData[i].layoutData); @@ -137,7 +127,7 @@ void loadCustomScreens() // else { // TODO: load some default view? // } - + viewMain->updateTopbarVisibility(); } @@ -147,11 +137,10 @@ void loadCustomScreens() // - new screen is configured into g_model // - the new screen is returned (not attached) // -WidgetsContainer * -createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex) +WidgetsContainer* LayoutFactory::createCustomScreen( + unsigned customScreenIndex) const { - if (!factory || (customScreenIndex >= MAX_CUSTOM_SCREENS)) - return nullptr; + if (customScreenIndex >= MAX_CUSTOM_SCREENS) return nullptr; auto& screen = customScreens[customScreenIndex]; auto& screenData = g_model.screenData[customScreenIndex]; @@ -162,19 +151,19 @@ createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex) } auto viewMain = ViewMain::instance(); - screen = factory->create(viewMain, &screenData.layoutData); + screen = create(viewMain, &screenData.layoutData); if (!screen) return nullptr; viewMain->addMainView(screen, customScreenIndex); - + auto dst = g_model.screenData[customScreenIndex].LayoutId; - auto src = factory->getId(); + auto src = getId(); strncpy(dst, src, sizeof(CustomScreenData::LayoutId)); - + return screen; } -void disposeCustomScreen(unsigned idx) +void LayoutFactory::disposeCustomScreen(unsigned idx) { // move custom screen data if (idx >= MAX_CUSTOM_SCREENS) { @@ -191,10 +180,9 @@ void disposeCustomScreen(unsigned idx) memset(dst, 0, len); } -LayoutFactory::LayoutFactory(const char * id, const char * name): - id(id), - name(name) +LayoutFactory::LayoutFactory(const char* id, const char* name) : + id(id), name(name) { - registerLayout(this); + TRACE("register layout %s", getId()); + getRegisteredLayouts().push_back(this); } - diff --git a/radio/src/gui/colorlcd/layout.h b/radio/src/gui/colorlcd/layout.h index 301b11a0c76..9c72ff148c3 100644 --- a/radio/src/gui/colorlcd/layout.h +++ b/radio/src/gui/colorlcd/layout.h @@ -22,22 +22,23 @@ #pragma once #include + +#include "dataconstants.h" #include "widgets_container.h" -#define MAX_LAYOUT_ZONES 10 -#define MAX_LAYOUT_OPTIONS 10 +#define MAX_LAYOUT_ZONES 10 +#define MAX_LAYOUT_OPTIONS 10 constexpr coord_t TRIM_LINE_WIDTH = 8; constexpr coord_t TRIM_SQUARE_SIZE = 17; constexpr coord_t MAIN_ZONE_BORDER = 10; -constexpr uint32_t LAYOUT_REFRESH = 1000 / 2; // 2 Hz - -class BitmapBuffer; +constexpr uint32_t LAYOUT_REFRESH = 1000 / 2; // 2 Hz #if !defined(YAML_GENERATOR) -typedef WidgetsContainerPersistentData LayoutPersistentData; +typedef WidgetsContainerPersistentData + LayoutPersistentData; #else struct LayoutPersistentData { - ZonePersistentData zones[MAX_LAYOUT_ZONES]; + ZonePersistentData zones[MAX_LAYOUT_ZONES]; ZoneOptionValueTyped options[MAX_LAYOUT_OPTIONS]; }; #endif @@ -54,39 +55,41 @@ class LayoutFactory virtual const ZoneOption* getOptions() const = 0; - virtual WidgetsContainer* create(Window* parent, - LayoutPersistentData* persistentData) const = 0; + virtual WidgetsContainer* create( + Window* parent, LayoutPersistentData* persistentData) const = 0; - virtual WidgetsContainer* load(Window* parent, - LayoutPersistentData* persistentData) const = 0; + virtual WidgetsContainer* load( + Window* parent, LayoutPersistentData* persistentData) const = 0; virtual void initPersistentData(LayoutPersistentData* persistentData, bool setDefault) const = 0; - protected: - const char* id; - const char* name; -}; + // Remove custom screen from the model + static void disposeCustomScreen(unsigned idx); -WidgetsContainer * loadLayout(Window* parent, const char * name, LayoutPersistentData * persistentData); + // delete all custom screens from memory + static void deleteCustomScreens(); -// intented for new models -void loadDefaultLayout(); + // intended for existing models + static void loadCustomScreens(); -// intended for existing models -void loadCustomScreens(); + // intented for new models + static void loadDefaultLayout(); -// delete all custom screens from memory -void deleteCustomScreens(); + // List of registered layout factories + static std::list& getRegisteredLayouts(); -WidgetsContainer * -createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex); + WidgetsContainer* createCustomScreen(unsigned customScreenIndex) const; -// Remove custom screen from the model -void disposeCustomScreen(unsigned idx); + protected: + const char* id; + const char* name; + + static WidgetsContainer* loadLayout(Window* parent, const char* name, + LayoutPersistentData* persistentData); + static const LayoutFactory* getLayoutFactory(const char* name); +}; -// Layout must register to be found -void registerLayout(const LayoutFactory * factory); +extern const LayoutFactory* defaultLayout; -// List of registered layout factories -std::list & getRegisteredLayouts(); +extern WidgetsContainer* customScreens[MAX_CUSTOM_SCREENS]; diff --git a/radio/src/gui/colorlcd/layouts/layout1+2.cpp b/radio/src/gui/colorlcd/layouts/layout1+2.cpp index 1241b741047..c1184529f94 100644 --- a/radio/src/gui/colorlcd/layouts/layout1+2.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1+2.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_FULL, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_FULL, LAYOUT_MAP_1QTR, LAYOUT_MAP_0, LAYOUT_MAP_3QTR, LAYOUT_MAP_FULL, LAYOUT_MAP_1QTR, @@ -30,4 +30,4 @@ static uint8_t zmap[] = { BaseLayoutFactory Layout1P2("Layout1P2", "1 + 2", defaultZoneOptions, - 3, zmap); + 3, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout1+3.cpp b/radio/src/gui/colorlcd/layouts/layout1+3.cpp index 9e17996a0a1..d8fe608fd73 100644 --- a/radio/src/gui/colorlcd/layouts/layout1+3.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1+3.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_FULL, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1THIRD, LAYOUT_MAP_HALF, LAYOUT_MAP_1THIRD, LAYOUT_MAP_HALF, LAYOUT_MAP_1THIRD, @@ -31,4 +31,4 @@ static uint8_t zmap[] = { BaseLayoutFactory Layout1P3("Layout1P3", "1 + 3", defaultZoneOptions, - 4, zmap); + 4, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout1x1.cpp b/radio/src/gui/colorlcd/layouts/layout1x1.cpp index 4413fb45edb..555379b007e 100644 --- a/radio/src/gui/colorlcd/layouts/layout1x1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1x1.cpp @@ -22,10 +22,10 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_FULL, LAYOUT_MAP_FULL, }; BaseLayoutFactory layout1x1("Layout1x1", STR_WIDGET_FULLSCREEN, defaultZoneOptions, - 1, zmap); + 1, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout1x2.cpp b/radio/src/gui/colorlcd/layouts/layout1x2.cpp index 783587471da..01c5964a3e4 100644 --- a/radio/src/gui/colorlcd/layouts/layout1x2.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1x2.cpp @@ -22,11 +22,11 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_FULL, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_FULL, LAYOUT_MAP_HALF, }; BaseLayoutFactory Layout1x2("Layout1x2", "1 x 2", defaultZoneOptions, - 2, zmap); + 2, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout1x3.cpp b/radio/src/gui/colorlcd/layouts/layout1x3.cpp index 817199aa219..d886f2d1a43 100644 --- a/radio/src/gui/colorlcd/layouts/layout1x3.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1x3.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_FULL, LAYOUT_MAP_1THIRD, LAYOUT_MAP_0, LAYOUT_MAP_1THIRD, LAYOUT_MAP_FULL, LAYOUT_MAP_1THIRD, LAYOUT_MAP_0, LAYOUT_MAP_2THIRD, LAYOUT_MAP_FULL, LAYOUT_MAP_1THIRD, @@ -30,4 +30,4 @@ static uint8_t zmap[] = { BaseLayoutFactory Layout1x3("Layout1x3", "1 x 3", defaultZoneOptions, - 3, zmap); + 3, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout1x4.cpp b/radio/src/gui/colorlcd/layouts/layout1x4.cpp index 35048d1227e..94bc3cac1f0 100644 --- a/radio/src/gui/colorlcd/layouts/layout1x4.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1x4.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_FULL, LAYOUT_MAP_1QTR, LAYOUT_MAP_0, LAYOUT_MAP_1QTR, LAYOUT_MAP_FULL, LAYOUT_MAP_1QTR, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_FULL, LAYOUT_MAP_1QTR, @@ -31,4 +31,4 @@ static uint8_t zmap[] = { BaseLayoutFactory Layout1x4("Layout1x4", "1 x 4", defaultZoneOptions, - 4, zmap); + 4, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout2+1.cpp b/radio/src/gui/colorlcd/layouts/layout2+1.cpp index aa3ae01c671..6c2c5b17a89 100644 --- a/radio/src/gui/colorlcd/layouts/layout2+1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2+1.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_FULL, // ordered to match previous implementation LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, @@ -30,6 +30,6 @@ static uint8_t zmap[] = { BaseLayoutFactory layout2P1("Layout2P1", "2 + 1", defaultZoneOptions, - 3, zmap); + 3, (uint8_t*)zmap); const LayoutFactory* defaultLayout = &layout2P1; diff --git a/radio/src/gui/colorlcd/layouts/layout2+3.cpp b/radio/src/gui/colorlcd/layouts/layout2+3.cpp index 0ac65af641c..b582e5241d0 100644 --- a/radio/src/gui/colorlcd/layouts/layout2+3.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2+3.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1THIRD, @@ -32,4 +32,4 @@ static uint8_t zmap[] = { BaseLayoutFactory Layout2P3("Layout2P3", "2 + 3", defaultZoneOptions, - 5, zmap); + 5, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout2x1.cpp b/radio/src/gui/colorlcd/layouts/layout2x1.cpp index 47b17bdb907..9570999b851 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x1.cpp @@ -22,11 +22,11 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_FULL, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_FULL, }; BaseLayoutFactory Layout2x1("Layout2x1", "2 x 1", defaultZoneOptions, - 2, zmap); + 2, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout2x2.cpp b/radio/src/gui/colorlcd/layouts/layout2x2.cpp index 42b5a0cbee6..ffe2574ceec 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x2.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x2.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, @@ -31,4 +31,4 @@ static uint8_t zmap[] = { BaseLayoutFactory layout2x2("Layout2x2", "2 x 2", defaultZoneOptions, - 4, zmap); + 4, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout2x3.cpp b/radio/src/gui/colorlcd/layouts/layout2x3.cpp index 0dd9ab7d9a2..8650514182d 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x3.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x3.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1THIRD, LAYOUT_MAP_0, LAYOUT_MAP_1THIRD, LAYOUT_MAP_HALF, LAYOUT_MAP_1THIRD, LAYOUT_MAP_0, LAYOUT_MAP_2THIRD, LAYOUT_MAP_HALF, LAYOUT_MAP_1THIRD, @@ -33,4 +33,4 @@ static uint8_t zmap[] = { BaseLayoutFactory layout2x3("Layout2x3", "2 x 3", defaultZoneOptions, - 6, zmap); + 6, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout2x4.cpp b/radio/src/gui/colorlcd/layouts/layout2x4.cpp index 363813234bd..8f405375ee6 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x4.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x4.cpp @@ -24,12 +24,11 @@ const ZoneOption OPTIONS_LAYOUT_2x4[] = { LAYOUT_COMMON_OPTIONS, - {"Panel1 background", ZoneOption::Bool}, - {" Color", ZoneOption::Color}, - {"Panel2 background", ZoneOption::Bool}, - {" Color", ZoneOption::Color}, - LAYOUT_OPTIONS_END -}; + {"Panel1 background", ZoneOption::Bool, OPTION_VALUE_BOOL(true)}, + {" Color", ZoneOption::Color, OPTION_VALUE_UNSIGNED(RGB(77, 112, 203))}, + {"Panel2 background", ZoneOption::Bool, OPTION_VALUE_BOOL(true)}, + {" Color", ZoneOption::Color, OPTION_VALUE_UNSIGNED(RGB(77, 112, 203))}, + LAYOUT_OPTIONS_END}; class Layout2x4 : public Layout { @@ -42,53 +41,81 @@ class Layout2x4 : public Layout }; Layout2x4(Window* parent, const LayoutFactory* factory, - Layout::PersistentData* persistentData, uint8_t zoneCount, uint8_t* zoneMap) : + Layout::PersistentData* persistentData, uint8_t zoneCount, + uint8_t* zoneMap) : Layout(parent, factory, persistentData, zoneCount, zoneMap) { + panel1 = lv_obj_create(lvobj); + lv_obj_set_style_bg_opa(panel1, LV_OPA_COVER, LV_PART_MAIN); + panel2 = lv_obj_create(lvobj); + lv_obj_set_style_bg_opa(panel2, LV_OPA_COVER, LV_PART_MAIN); + setPanels(); } - void create() override + protected: + rect_t mainZone = {0, 0, 0, 0}; + lv_obj_t* panel1 = nullptr; + lv_obj_t* panel2 = nullptr; + LcdFlags panel1Color = -1; + LcdFlags panel2Color = -1; + + void checkEvents() override { - Layout::create(); - getOptionValue(OPTION_PANEL1_BACKGROUND)->boolValue = true; - getOptionValue(OPTION_PANEL1_COLOR)->unsignedValue = RGB(77, 112, 203); - getOptionValue(OPTION_PANEL2_BACKGROUND)->boolValue = true; - getOptionValue(OPTION_PANEL2_COLOR)->unsignedValue = RGB(77, 112, 203); + setPanels(); + Layout::checkEvents(); } - void paint(BitmapBuffer* dc) override; -}; + void setPanels() + { + rect_t zone = Layout::getMainZone(); + if (mainZone.x != zone.x || mainZone.y != zone.y || mainZone.w != zone.w || + mainZone.h != zone.h) { + mainZone = zone; + lv_obj_set_pos(panel1, mainZone.x, mainZone.y); + lv_obj_set_size(panel1, mainZone.w / 2, mainZone.h); + lv_obj_set_pos(panel2, mainZone.x + mainZone.w / 2, mainZone.y); + lv_obj_set_size(panel2, mainZone.w / 2, mainZone.h); + } -void Layout2x4::paint(BitmapBuffer* dc) -{ - Layout::paint(dc); - rect_t fullScreen = Layout::getMainZone(); - fullScreen.w /= 2; - if (getOptionValue(OPTION_PANEL1_BACKGROUND)->boolValue) { - dc->drawSolidFilledRect( - fullScreen.x, fullScreen.y, fullScreen.w, fullScreen.h, - COLOR2FLAGS(getOptionValue(OPTION_PANEL1_COLOR)->unsignedValue)); - } + bool vis = getOptionValue(OPTION_PANEL1_BACKGROUND)->boolValue; + if (vis == lv_obj_has_flag(panel1, LV_OBJ_FLAG_HIDDEN)) { + if (vis) + lv_obj_clear_flag(panel1, LV_OBJ_FLAG_HIDDEN); + else + lv_obj_add_flag(panel1, LV_OBJ_FLAG_HIDDEN); + } + vis = getOptionValue(OPTION_PANEL2_BACKGROUND)->boolValue; + if (vis != lv_obj_has_flag(panel2, LV_OBJ_FLAG_HIDDEN)) { + if (vis) + lv_obj_clear_flag(panel2, LV_OBJ_FLAG_HIDDEN); + else + lv_obj_add_flag(panel2, LV_OBJ_FLAG_HIDDEN); + } - if (getOptionValue(OPTION_PANEL2_BACKGROUND)->boolValue) { - fullScreen.x += fullScreen.w; - dc->drawSolidFilledRect( - fullScreen.x, fullScreen.y, fullScreen.w, fullScreen.h, - COLOR2FLAGS(getOptionValue(OPTION_PANEL2_COLOR)->unsignedValue)); + LcdFlags color = + COLOR2FLAGS(getOptionValue(OPTION_PANEL1_COLOR)->unsignedValue); + if (color != panel1Color) { + panel1Color = color; + lv_obj_set_style_bg_color(panel1, makeLvColor(panel1Color), LV_PART_MAIN); + } + color = COLOR2FLAGS(getOptionValue(OPTION_PANEL2_COLOR)->unsignedValue); + if (color != panel2Color) { + panel2Color = color; + lv_obj_set_style_bg_color(panel2, makeLvColor(panel2Color), LV_PART_MAIN); + } } -} +}; -static uint8_t zmap[] = { - LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, - LAYOUT_MAP_0, LAYOUT_MAP_1QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, - LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, - LAYOUT_MAP_0, LAYOUT_MAP_3QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, - LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, +static const uint8_t zmap[] = { + LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, + LAYOUT_MAP_0, LAYOUT_MAP_1QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, + LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, + LAYOUT_MAP_0, LAYOUT_MAP_3QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, + LAYOUT_MAP_HALF, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_3QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, }; -BaseLayoutFactory layout2x4("Layout2x4", "2 x 4", - OPTIONS_LAYOUT_2x4, - 8, zmap); +BaseLayoutFactory layout2x4("Layout2x4", "2 x 4", OPTIONS_LAYOUT_2x4, + 8, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout4+2.cpp b/radio/src/gui/colorlcd/layouts/layout4+2.cpp index 2fe34471db4..14396d43de0 100644 --- a/radio/src/gui/colorlcd/layouts/layout4+2.cpp +++ b/radio/src/gui/colorlcd/layouts/layout4+2.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, LAYOUT_MAP_0, LAYOUT_MAP_1QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, @@ -33,4 +33,4 @@ static uint8_t zmap[] = { BaseLayoutFactory layout4P2("Layout4P2", "4 + 2", defaultZoneOptions, - 6, zmap); + 6, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout4+2b.cpp b/radio/src/gui/colorlcd/layouts/layout4+2b.cpp index 9019754935b..d9556ece2b2 100644 --- a/radio/src/gui/colorlcd/layouts/layout4+2b.cpp +++ b/radio/src/gui/colorlcd/layouts/layout4+2b.cpp @@ -22,7 +22,7 @@ #include "layout.h" #include "layout_factory_impl.h" -static uint8_t zmap[] = { +static const uint8_t zmap[] = { LAYOUT_MAP_0, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, LAYOUT_MAP_0, LAYOUT_MAP_1QTR, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, LAYOUT_MAP_0, LAYOUT_MAP_HALF, LAYOUT_MAP_HALF, LAYOUT_MAP_1QTR, @@ -33,4 +33,4 @@ static uint8_t zmap[] = { BaseLayoutFactory layout4P2B("Layout4P2B", "4 + 2B", defaultZoneOptions, - 6, zmap); + 6, (uint8_t*)zmap); diff --git a/radio/src/gui/colorlcd/layouts/layout_factory_impl.cpp b/radio/src/gui/colorlcd/layouts/layout_factory_impl.cpp index 6f22793b348..bad0cd0bcc0 100644 --- a/radio/src/gui/colorlcd/layouts/layout_factory_impl.cpp +++ b/radio/src/gui/colorlcd/layouts/layout_factory_impl.cpp @@ -20,39 +20,23 @@ */ #include "layout_factory_impl.h" -#include "layouts/trims.h" + #include "layouts/sliders.h" +#include "layouts/trims.h" #include "view_main.h" -Layout::Layout(Window* parent, const LayoutFactory * factory, PersistentData * persistentData, uint8_t zoneCount, uint8_t* zoneMap): - LayoutBase(parent, {0, 0, LCD_W, LCD_H}, persistentData), - factory(factory), - decoration(new ViewMainDecoration(this)), - zoneCount(zoneCount), - zoneMap(zoneMap) +Layout::Layout(Window* parent, const LayoutFactory* factory, + PersistentData* persistentData, uint8_t zoneCount, + uint8_t* zoneMap) : + LayoutBase(parent, {0, 0, LCD_W, LCD_H}, persistentData), + factory(factory), + decoration(new ViewMainDecoration(this)), + zoneCount(zoneCount), + zoneMap(zoneMap) { adjustLayout(); } -void Layout::create() -{ - memset(persistentData, 0, sizeof(PersistentData)); - - getOptionValue(LAYOUT_OPTION_TOPBAR)->boolValue = true; - getOptionValue(LAYOUT_OPTION_FM)->boolValue = true; - getOptionValue(LAYOUT_OPTION_SLIDERS)->boolValue = true; - getOptionValue(LAYOUT_OPTION_TRIMS)->boolValue = true; - getOptionValue(LAYOUT_OPTION_MIRRORED)->boolValue = false; -} - -#if defined(DEBUG_WINDOWS) -void Layout::paint(BitmapBuffer * dc) -{ - TRACE_WINDOWS("# painting -> %s", getWindowDebugString().c_str()); - LayoutBase::paint(dc); -} -#endif - void Layout::setTrimsVisible(bool visible) { decoration->setTrimsVisible(visible); @@ -68,23 +52,14 @@ void Layout::setFlightModeVisible(bool visible) decoration->setFlightModeVisible(visible); } -void Layout::updateFromTheme() -{ - // Hack to fix flight mode color on main view - // Required because theme is loaded after the main view has been created - if (decoration) - decoration->updateFromTheme(); -} - void Layout::adjustLayout() { // Check if deco setting are still up-to-date - uint8_t checkSettings = - (hasTopbar() ? DECORATION_TOPBAR : 0) | - (hasSliders() ? DECORATION_SLIDERS : 0) | - (hasTrims() ? DECORATION_TRIMS : 0) | - (hasFlightMode() ? DECORATION_FLIGHTMODE : 0) | - (isMirrored() ? DECORATION_MIRRORED : 0); + uint8_t checkSettings = (hasTopbar() ? DECORATION_TOPBAR : 0) | + (hasSliders() ? DECORATION_SLIDERS : 0) | + (hasTrims() ? DECORATION_TRIMS : 0) | + (hasFlightMode() ? DECORATION_FLIGHTMODE : 0) | + (isMirrored() ? DECORATION_MIRRORED : 0); if (checkSettings == decorationSettings) { // everything ok, exit! @@ -95,18 +70,27 @@ void Layout::adjustLayout() decorationSettings = checkSettings; // Set visible decoration - setSlidersVisible(hasSliders()); - setTrimsVisible(hasTrims()); - setFlightModeVisible(hasFlightMode()); + show(); +} - // and update relevant windows - updateZones(); +void Layout::show(bool visible) +{ + // Set visible decoration + setSlidersVisible(visible && hasSliders()); + setTrimsVisible(visible && hasTrims()); + setFlightModeVisible(visible && hasFlightMode()); + + if (visible) { + // and update relevant windows + updateZones(); + } } rect_t Layout::getMainZone() const { rect_t zone = decoration->getMainZone(); - if (decorationSettings & (DECORATION_SLIDERS|DECORATION_TRIMS|DECORATION_FLIGHTMODE)) { + if (decorationSettings & + (DECORATION_SLIDERS | DECORATION_TRIMS | DECORATION_FLIGHTMODE)) { // some decoration activated zone.x += MAIN_ZONE_BORDER; zone.y += MAIN_ZONE_BORDER; @@ -114,7 +98,7 @@ rect_t Layout::getMainZone() const zone.h -= 2 * MAIN_ZONE_BORDER; } return ViewMain::instance()->getMainZone(zone, hasTopbar()); -} +} rect_t Layout::getZone(unsigned int index) const { @@ -123,16 +107,14 @@ rect_t Layout::getZone(unsigned int index) const unsigned int i = index * 4; coord_t xo = z.w * zoneMap[i] / LAYOUT_MAP_DIV; - coord_t yo = z.h * zoneMap[i+1] / LAYOUT_MAP_DIV; - coord_t w = z.w * zoneMap[i+2] / LAYOUT_MAP_DIV; - coord_t h = z.h * zoneMap[i+3] / LAYOUT_MAP_DIV; + coord_t yo = z.h * zoneMap[i + 1] / LAYOUT_MAP_DIV; + coord_t w = z.w * zoneMap[i + 2] / LAYOUT_MAP_DIV; + coord_t h = z.h * zoneMap[i + 3] / LAYOUT_MAP_DIV; - if (isMirrored()) - xo = z.w - xo - w; + if (isMirrored()) xo = z.w - xo - w; - return { z.x + xo, z.y + yo, w, h }; + return {z.x + xo, z.y + yo, w, h}; } const ZoneOption defaultZoneOptions[] = {LAYOUT_COMMON_OPTIONS, LAYOUT_OPTIONS_END}; - diff --git a/radio/src/gui/colorlcd/layouts/layout_factory_impl.h b/radio/src/gui/colorlcd/layouts/layout_factory_impl.h index 3b9b2c75e88..d3aaca11593 100644 --- a/radio/src/gui/colorlcd/layouts/layout_factory_impl.h +++ b/radio/src/gui/colorlcd/layouts/layout_factory_impl.h @@ -69,11 +69,9 @@ class Layout: public LayoutBase { return "Layout"; } - - void paint(BitmapBuffer * dc) override; #endif - void create() override; + void create() override {} const LayoutFactory * getFactory() const { @@ -105,11 +103,9 @@ class Layout: public LayoutBase void setSlidersVisible(bool visible); void setFlightModeVisible(bool visible); - // Update from theme settings - void updateFromTheme() override; - // Updates settings for trims, sliders, pots, etc... void adjustLayout() override; + void show(bool visible = true) override; bool isLayout() override { return true; } diff --git a/radio/src/gui/colorlcd/layouts/sliders.cpp b/radio/src/gui/colorlcd/layouts/sliders.cpp index 799540de610..0a20c83ae18 100644 --- a/radio/src/gui/colorlcd/layouts/sliders.cpp +++ b/radio/src/gui/colorlcd/layouts/sliders.cpp @@ -20,74 +20,174 @@ */ #include "sliders.h" + +#include "bitmaps.h" +#include "hal/adc_driver.h" #include "opentx.h" #include "switches.h" -#include "hal/adc_driver.h" +static const lv_style_const_prop_t shadow1_props[] = { + // LV_STYLE_CONST_SHADOW_COLOR does not compile in GitHub ??? + {.prop = LV_STYLE_SHADOW_COLOR, .value {.color {.full = 0}}}, + LV_STYLE_CONST_SHADOW_OPA(LV_OPA_20), + LV_STYLE_CONST_SHADOW_OFS_X(1), + LV_STYLE_CONST_SHADOW_OFS_Y(1), + LV_STYLE_CONST_SHADOW_WIDTH(1), + LV_STYLE_PROP_INV, +}; +static LV_STYLE_CONST_MULTI_INIT(shadow1_style, shadow1_props); -constexpr coord_t MULTIPOS_H = 18; -constexpr coord_t MULTIPOS_W_SPACING = 12; -constexpr coord_t MULTIPOS_W = (6+1)*MULTIPOS_W_SPACING; +static const lv_style_const_prop_t shadow2_props[] = { + // LV_STYLE_CONST_SHADOW_COLOR does not compile in GitHub ??? + {.prop = LV_STYLE_SHADOW_COLOR, .value {.color {.full = 0}}}, + LV_STYLE_CONST_SHADOW_OPA(LV_OPA_40), + LV_STYLE_CONST_SHADOW_OFS_X(1), + LV_STYLE_CONST_SHADOW_OFS_Y(1), + LV_STYLE_CONST_SHADOW_WIDTH(1), + LV_STYLE_PROP_INV, +}; +static LV_STYLE_CONST_MULTI_INIT(shadow2_style, shadow2_props); + +SliderIcon::SliderIcon(Window* parent) : + Window(parent, rect_t{0, 0, 17, 17}, NO_FOCUS) +{ + auto shad = lv_obj_create(lvobj); + etx_obj_add_style(shad, shadow1_style, LV_PART_MAIN); + lv_obj_set_pos(shad, 1, 1); + lv_obj_set_size(shad, 15, 15); + + fill = lv_obj_create(lvobj); + etx_obj_add_style(fill, shadow2_style, LV_PART_MAIN); + lv_obj_set_pos(fill, 0, 0); + lv_obj_set_size(fill, 15, 15); + etx_solid_bg(fill, COLOR_THEME_FOCUS_INDEX); +} -MainViewSlider::MainViewSlider(Window* parent, const rect_t& rect, - uint8_t idx) : - Window(parent, rect), idx(idx) +MainViewSlider::MainViewSlider(Window* parent, const rect_t& rect, uint8_t idx, + bool isVertical) : + Window(parent, rect), idx(idx), isVertical(isVertical) { + if (isVertical) { + int sliderTicksCount = (height() - TRIM_SQUARE_SIZE) / SLIDER_TICK_SPACING; + tickPoints = new lv_point_t[(sliderTicksCount + 1) * 2]; + + lv_coord_t y = TRIM_SQUARE_SIZE / 2; + for (uint8_t i = 0; i <= sliderTicksCount; i++) { + if (i == 0 || i == sliderTicksCount / 2 || i == sliderTicksCount) { + tickPoints[i * 2] = {2, y}; + tickPoints[i * 2 + 1] = {15, y}; + } else { + tickPoints[i * 2] = {4, y}; + tickPoints[i * 2 + 1] = {13, y}; + } + auto line = lv_line_create(lvobj); + etx_obj_add_style(line, styles->div_line, LV_PART_MAIN); + lv_line_set_points(line, &tickPoints[i * 2], 2); + y += SLIDER_TICK_SPACING; + } + } else { + int sliderTicksCount = (width() - TRIM_SQUARE_SIZE) / SLIDER_TICK_SPACING; + tickPoints = new lv_point_t[(sliderTicksCount + 1) * 2]; + + lv_coord_t x = TRIM_SQUARE_SIZE / 2; + for (uint8_t i = 0; i <= sliderTicksCount; i++) { + if (i == 0 || i == sliderTicksCount / 2 || i == SLIDER_TICKS_COUNT) { + tickPoints[i * 2] = {x, 2}; + tickPoints[i * 2 + 1] = {x, 15}; + } else { + tickPoints[i * 2] = {x, 4}; + tickPoints[i * 2 + 1] = {x, 13}; + } + auto line = lv_line_create(lvobj); + etx_obj_add_style(line, styles->div_line, LV_PART_MAIN); + lv_line_set_points(line, &tickPoints[i * 2], 2); + x += SLIDER_TICK_SPACING; + } + } + + sliderIcon = new SliderIcon(this); + coord_t x = 0, y = 0; + if (isVertical) + y = (height() - TRIM_SQUARE_SIZE) / 2; + else + y = (width() - TRIM_SQUARE_SIZE) / 2; + lv_obj_set_pos(sliderIcon->getLvObj(), x, y); + + checkEvents(); +} + +void MainViewSlider::deleteLater(bool detach, bool trash) +{ + if (!deleted()) { + if (tickPoints) delete tickPoints; + Window::deleteLater(detach, trash); + } } void MainViewSlider::checkEvents() { Window::checkEvents(); + auto pot_idx = adcGetInputOffset(ADC_INPUT_FLEX) + idx; int16_t newValue = calibratedAnalogs[pot_idx]; if (value != newValue) { - value = newValue; - invalidate(); + value = newValue; + + coord_t x = 0, y = 0; + if (isVertical) { + y = divRoundClosest((height() - TRIM_SQUARE_SIZE) * (-value + RESX), + 2 * RESX); + } else { + x = divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value + RESX), + 2 * RESX); + } + lv_obj_set_pos(sliderIcon->getLvObj(), x, y); } } MainViewHorizontalSlider::MainViewHorizontalSlider(Window* parent, uint8_t idx) : - MainViewSlider(parent, rect_t{0, 0, HORIZONTAL_SLIDERS_WIDTH, TRIM_SQUARE_SIZE}, idx) + MainViewSlider(parent, + rect_t{0, 0, HORIZONTAL_SLIDERS_WIDTH, TRIM_SQUARE_SIZE}, + idx, false) { } -void MainViewHorizontalSlider::paint(BitmapBuffer * dc) +MainViewVerticalSlider::MainViewVerticalSlider(Window* parent, + const rect_t& rect, + uint8_t idx) : + MainViewSlider(parent, rect, idx, true) { - // The ticks - int sliderTicksCount = (width() - TRIM_SQUARE_SIZE) / SLIDER_TICK_SPACING; - coord_t x = TRIM_SQUARE_SIZE / 2; - for (uint8_t i = 0; i <= sliderTicksCount; i++) { - if (i == 0 || i == sliderTicksCount / 2 || i == SLIDER_TICKS_COUNT) - dc->drawSolidVerticalLine(x, 2, 13, COLOR_THEME_SECONDARY1); - else - dc->drawSolidVerticalLine(x, 4, 9, COLOR_THEME_SECONDARY1); - x += SLIDER_TICK_SPACING; - } - - // The square - x = divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value + RESX), 2 * RESX); - drawTrimSquare(dc, x, 0, COLOR_THEME_FOCUS); } -MainView6POS::MainView6POS(Window* parent, uint8_t idx) : - MainViewSlider(parent, rect_t{0, 0, MULTIPOS_W, MULTIPOS_H}, idx) -{ -} +constexpr coord_t MULTIPOS_H = 18; +constexpr coord_t MULTIPOS_W_SPACING = 12; +constexpr coord_t MULTIPOS_W = (6 + 1) * MULTIPOS_W_SPACING; -void MainView6POS::paint(BitmapBuffer * dc) +MainView6POS::MainView6POS(Window* parent, uint8_t idx) : + Window(parent, rect_t{0, 0, MULTIPOS_W, MULTIPOS_H}), idx(idx) { - coord_t x = MULTIPOS_W_SPACING/4; + char num[] = " "; + coord_t x = MULTIPOS_W_SPACING / 4 + TRIM_SQUARE_SIZE / 4; for (uint8_t value = 0; value < XPOTS_MULTIPOS_COUNT; value++) { - dc->drawNumber(x+TRIM_SQUARE_SIZE/4, 0, value+1, FONT(XS) | COLOR_THEME_SECONDARY1); + num[0] = value + '1'; + auto p = lv_label_create(lvobj); + lv_label_set_text(p, num); + lv_obj_set_size(p, 12, 12); + lv_obj_set_pos(p, x, 0); + etx_txt_color(p, COLOR_THEME_SECONDARY1_INDEX, LV_PART_MAIN); + etx_font(p, FONT_XS_INDEX, LV_PART_MAIN); x += MULTIPOS_W_SPACING; } - // The square - value = getXPotPosition(idx); - x = MULTIPOS_W_SPACING / 4 + MULTIPOS_W_SPACING * value; - drawTrimSquare(dc, x, 0, COLOR_THEME_FOCUS); - dc->drawNumber(x+MULTIPOS_W_SPACING/4, -2, value+1, FONT(BOLD) | COLOR_THEME_PRIMARY2); + posIcon = new SliderIcon(this); + posVal = lv_label_create(posIcon->getLvObj()); + lv_obj_set_pos(posVal, 3, -2); + lv_obj_set_size(posVal, 12, 12); + etx_txt_color(posVal, COLOR_THEME_PRIMARY2_INDEX, LV_PART_MAIN); + etx_font(posVal, FONT_BOLD_INDEX, LV_PART_MAIN); + + checkEvents(); } void MainView6POS::checkEvents() @@ -96,29 +196,12 @@ void MainView6POS::checkEvents() int16_t newValue = getXPotPosition(idx); if (value != newValue) { value = newValue; - invalidate(); - } -} -MainViewVerticalSlider::MainViewVerticalSlider(Window* parent, const rect_t& rect, uint8_t idx) : - MainViewSlider(parent, rect, idx) -{ -} + coord_t x = MULTIPOS_W_SPACING / 4 + MULTIPOS_W_SPACING * value; + lv_obj_set_pos(posIcon->getLvObj(), x, 0); -void MainViewVerticalSlider::paint(BitmapBuffer * dc) -{ - // The ticks - int sliderTicksCount = (height() - TRIM_SQUARE_SIZE) / SLIDER_TICK_SPACING; - coord_t y = TRIM_SQUARE_SIZE / 2; - for (uint8_t i = 0; i <= sliderTicksCount; i++) { - if (i == 0 || i == sliderTicksCount / 2 || i == sliderTicksCount) - dc->drawSolidHorizontalLine(2, y, 13, COLOR_THEME_SECONDARY1); - else - dc->drawSolidHorizontalLine(4, y, 9, COLOR_THEME_SECONDARY1); - y += SLIDER_TICK_SPACING; + char num[] = " "; + num[0] = value + '1'; + lv_label_set_text(posVal, num); } - - // The square - y = divRoundClosest((height() - TRIM_SQUARE_SIZE) * (-value + RESX), 2 * RESX); - drawTrimSquare(dc, 0, y, COLOR_THEME_FOCUS); } diff --git a/radio/src/gui/colorlcd/layouts/sliders.h b/radio/src/gui/colorlcd/layouts/sliders.h index c9f8661fc8c..b09054a596e 100644 --- a/radio/src/gui/colorlcd/layouts/sliders.h +++ b/radio/src/gui/colorlcd/layouts/sliders.h @@ -22,7 +22,6 @@ #pragma once #include "libopenui.h" -#include "trims.h" #if LCD_H > LCD_W constexpr uint8_t SLIDER_TICKS_COUNT = 30; @@ -30,39 +29,59 @@ constexpr uint8_t SLIDER_TICKS_COUNT = 30; constexpr uint8_t SLIDER_TICKS_COUNT = 40; #endif constexpr coord_t SLIDER_TICK_SPACING = 4; -constexpr coord_t HORIZONTAL_SLIDERS_WIDTH = SLIDER_TICKS_COUNT * SLIDER_TICK_SPACING + TRIM_SQUARE_SIZE; -constexpr coord_t VERTICAL_SLIDERS_HEIGHT = SLIDER_TICKS_COUNT * SLIDER_TICK_SPACING + TRIM_SQUARE_SIZE; +constexpr coord_t HORIZONTAL_SLIDERS_WIDTH = + SLIDER_TICKS_COUNT * SLIDER_TICK_SPACING + TRIM_SQUARE_SIZE; +constexpr coord_t VERTICAL_SLIDERS_HEIGHT = + SLIDER_TICKS_COUNT * SLIDER_TICK_SPACING + TRIM_SQUARE_SIZE; + +class SliderIcon : public Window +{ + public: + SliderIcon(Window* parent); + + protected: + lv_obj_t* fill = nullptr; +}; class MainViewSlider : public Window { public: - MainViewSlider(Window* parent, const rect_t& rect, uint8_t idx); + MainViewSlider(Window* parent, const rect_t& rect, uint8_t idx, + bool isVertical); void checkEvents() override; protected: uint8_t idx; - int16_t value = 0; + int16_t value = -10000; + bool isVertical; + SliderIcon* sliderIcon = nullptr; + lv_point_t* tickPoints = nullptr; + + void deleteLater(bool detach = true, bool trash = true) override; }; class MainViewHorizontalSlider : public MainViewSlider { public: - using MainViewSlider::MainViewSlider; MainViewHorizontalSlider(Window* parent, uint8_t idx); - void paint(BitmapBuffer* dc) override; }; -class MainView6POS : public MainViewSlider +class MainViewVerticalSlider : public MainViewSlider { - public: - MainView6POS(Window* parent, uint8_t idx); - void paint(BitmapBuffer * dc) override; - void checkEvents() override; + public: + MainViewVerticalSlider(Window* parent, const rect_t& rect, uint8_t idx); }; -class MainViewVerticalSlider : public MainViewSlider +class MainView6POS : public Window { - public: - MainViewVerticalSlider(Window* parent, const rect_t & rect, uint8_t idx); - void paint(BitmapBuffer * dc) override; + public: + MainView6POS(Window* parent, uint8_t idx); + + void checkEvents() override; + + protected: + uint8_t idx; + int16_t value = -10000; + SliderIcon* posIcon = nullptr; + lv_obj_t* posVal = nullptr; }; diff --git a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp index 82a8ba5c180..8e6e495838d 100644 --- a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp +++ b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp @@ -28,6 +28,9 @@ constexpr uint32_t TOPBAR_REFRESH = 1000 / 10; // 10 Hz TopBar::TopBar(Window * parent) : TopBarBase(parent, {0, 0, LCD_W, MENU_HEADER_HEIGHT}, &g_model.topbarData) { + etx_solid_bg(lvobj, COLOR_THEME_SECONDARY1_INDEX); + + headerIcon = new HeaderIcon(this, ICON_EDGETX); } unsigned int TopBar::getZonesCount() const @@ -77,12 +80,6 @@ coord_t TopBar::getVisibleHeight(float visible) const // 0.0 -> 1.0 return (coord_t)h; } -void TopBar::paint(BitmapBuffer * dc) -{ - dc->drawSolidFilledRect(0, 0, width(), height(), COLOR_THEME_SECONDARY1); - EdgeTxTheme::instance()->drawHeaderIcon(dc, ICON_EDGETX); -} - void TopBar::checkEvents() { uint32_t now = RTOS_GET_MS(); diff --git a/radio/src/gui/colorlcd/layouts/topbar_impl.h b/radio/src/gui/colorlcd/layouts/topbar_impl.h index 94e1753b221..ac24189be5d 100644 --- a/radio/src/gui/colorlcd/layouts/topbar_impl.h +++ b/radio/src/gui/colorlcd/layouts/topbar_impl.h @@ -24,6 +24,8 @@ #include "topbar.h" #include "layouts/layout_factory_impl.h" +class HeaderIcon; + typedef WidgetsContainerImpl TopBarBase; class TopBar: public TopBarBase @@ -50,8 +52,6 @@ class TopBar: public TopBarBase void setVisible(float visible); coord_t getVisibleHeight(float visible) const; // 0.0 -> 1.0 - void paint(BitmapBuffer * dc) override; - void checkEvents() override; bool isTopBar() override { return true; } @@ -60,4 +60,5 @@ class TopBar: public TopBarBase protected: uint32_t lastRefresh = 0; + HeaderIcon* headerIcon = nullptr; }; diff --git a/radio/src/gui/colorlcd/layouts/trims.cpp b/radio/src/gui/colorlcd/layouts/trims.cpp index 43f733853c6..5fa1f9172cf 100644 --- a/radio/src/gui/colorlcd/layouts/trims.cpp +++ b/radio/src/gui/colorlcd/layouts/trims.cpp @@ -20,16 +20,100 @@ */ #include "trims.h" -#include "sliders.h" -#include "input_mapping.h" +#include "bitmaps.h" +#include "input_mapping.h" #include "opentx.h" +#include "sliders.h" -MainViewTrim::MainViewTrim(Window * parent, const rect_t & rect, uint8_t idx): - Window(parent, rect), - idx(idx) +class TrimIcon : public SliderIcon +{ + public: + TrimIcon(Window* parent, bool isVertical) : SliderIcon(parent) + { + if (isVertical) { + barPoints[0] = {3, 4}; + barPoints[1] = {12, 4}; + barPoints[2] = {3, 10}; + barPoints[3] = {12, 10}; + } else { + barPoints[0] = {10, 3}; + barPoints[1] = {10, 12}; + barPoints[2] = {4, 3}; + barPoints[3] = {4, 12}; + } + + bar1 = lv_line_create(lvobj); + etx_obj_add_style(bar1, styles->div_line_white, LV_PART_MAIN); + lv_line_set_points(bar1, &barPoints[0], 2); + bar2 = lv_line_create(lvobj); + etx_obj_add_style(bar2, styles->div_line_white, LV_PART_MAIN); + lv_line_set_points(bar2, &barPoints[2], 2); + + etx_bg_color(fill, COLOR_THEME_ACTIVE_INDEX, LV_STATE_USER_1); + } + + void setState(int value) + { + if (value < TRIM_MIN || value > TRIM_MAX) + lv_obj_add_state(fill, LV_STATE_USER_1); + else + lv_obj_clear_state(fill, LV_STATE_USER_1); + + if (value >= 0) + lv_obj_clear_flag(bar1, LV_OBJ_FLAG_HIDDEN); + else + lv_obj_add_flag(bar1, LV_OBJ_FLAG_HIDDEN); + + if (value <= 0) + lv_obj_clear_flag(bar2, LV_OBJ_FLAG_HIDDEN); + else + lv_obj_add_flag(bar2, LV_OBJ_FLAG_HIDDEN); + } + + protected: + lv_obj_t* bar1 = nullptr; + lv_obj_t* bar2 = nullptr; + lv_point_t barPoints[4]; +}; + +MainViewTrim::MainViewTrim(Window* parent, const rect_t& rect, uint8_t idx, + bool isVertical) : + Window(parent, rect), idx(idx), isVertical(isVertical) { setRange(); + + trimBar = lv_obj_create(lvobj); + etx_solid_bg(trimBar, COLOR_THEME_SECONDARY1_INDEX); + etx_obj_add_style(trimBar, styles->rounded, LV_PART_MAIN); + if (isVertical) { + lv_obj_set_pos(trimBar, (TRIM_SQUARE_SIZE - TRIM_LINE_WIDTH) / 2, + TRIM_SQUARE_SIZE / 2); + lv_obj_set_size(trimBar, TRIM_LINE_WIDTH, + VERTICAL_SLIDERS_HEIGHT - TRIM_SQUARE_SIZE + 1); + } else { + lv_obj_set_pos(trimBar, TRIM_SQUARE_SIZE / 2, + (TRIM_SQUARE_SIZE - TRIM_LINE_WIDTH - 1) / 2); + lv_obj_set_size(trimBar, HORIZONTAL_SLIDERS_WIDTH - TRIM_SQUARE_SIZE + 1, + TRIM_LINE_WIDTH); + } + + trimIcon = new TrimIcon(this, isVertical); + coord_t x = 0, y = 0; + if (isVertical) + y = (height() - TRIM_SQUARE_SIZE) / 2; + else + y = (width() - TRIM_SQUARE_SIZE) / 2; + lv_obj_set_pos(trimIcon->getLvObj(), x, y); + + trimValue = new DynamicNumber( + this, {0, 0, TRIM_SQUARE_SIZE, 12}, + [=]() { return divRoundClosest(abs(value) * 100, trimMax); }, + COLOR_THEME_PRIMARY2 | FONT(XXS) | CENTERED); + etx_solid_bg(trimValue->getLvObj(), COLOR_THEME_SECONDARY1_INDEX); + trimValue->hide(); + + setPos(); } void MainViewTrim::setRange() @@ -37,131 +121,90 @@ void MainViewTrim::setRange() if (g_model.extendedTrims) { trimMin = TRIM_EXTENDED_MIN; trimMax = TRIM_EXTENDED_MAX; - } - else { + } else { trimMin = TRIM_MIN; trimMax = TRIM_MAX; } } -void MainViewTrim::checkEvents() -{ - Window::checkEvents(); - int8_t stickIndex = inputMappingConvertMode(idx); - int newValue = getTrimValue(mixerCurrentFlightMode, stickIndex); - - setRange(); - newValue = min(max(newValue, trimMin), trimMax); - - if (value != newValue || - (g_model.displayTrims == DISPLAY_TRIMS_CHANGE && showChange && trimsDisplayTimer == 0)) { - value = newValue; - invalidate(); - } -} - -void MainViewTrim::paint(BitmapBuffer * dc) +void MainViewTrim::setPos() { - // Trim line - drawLine(dc); - coord_t x = sx(); coord_t y = sy(); - // Trim square - drawTrimSquare(dc, x, y, - (value < TRIM_MIN || value > TRIM_MAX) - ? COLOR_THEME_ACTIVE /* TODO add a color */ - : COLOR_THEME_FOCUS); - drawMarkerLines(dc, x, y); + lv_obj_set_pos(trimIcon->getLvObj(), x, y); + trimIcon->setState(value); - // Trim value / small lines on the square if ((g_model.displayTrims == DISPLAY_TRIMS_ALWAYS) || - ((g_model.displayTrims == DISPLAY_TRIMS_CHANGE) && (trimsDisplayTimer > 0) && (trimsDisplayMask & (1 << idx)))) { + ((g_model.displayTrims == DISPLAY_TRIMS_CHANGE) && + (trimsDisplayTimer > 0) && (trimsDisplayMask & (1 << idx)))) { if (value) { + if (isVertical) { + x = 0; + y = (value > 0) ? VERTICAL_SLIDERS_HEIGHT * 4 / 5 + : VERTICAL_SLIDERS_HEIGHT / 5 - 11; + } else { + x = ((value < 0) ? HORIZONTAL_SLIDERS_WIDTH * 4 / 5 + : HORIZONTAL_SLIDERS_WIDTH / 5) - + TRIM_SQUARE_SIZE / 2; + y = (TRIM_SQUARE_SIZE - 12) / 2; + } + lv_obj_set_pos(trimValue->getLvObj(), x, y); + trimValue->show(); showChange = true; - drawValue(dc); + } else { + trimValue->hide(); } } else { showChange = false; + trimValue->hide(); } } -MainViewHorizontalTrim::MainViewHorizontalTrim(Window* parent, uint8_t idx) : - MainViewTrim(parent, rect_t{0, 0, HORIZONTAL_SLIDERS_WIDTH, TRIM_SQUARE_SIZE}, idx) -{ -} - -coord_t MainViewHorizontalTrim::sx() +void MainViewTrim::checkEvents() { - return divRoundClosest((HORIZONTAL_SLIDERS_WIDTH - TRIM_SQUARE_SIZE) * (value - trimMin), - trimMax - trimMin); -} + Window::checkEvents(); + int8_t stickIndex = inputMappingConvertMode(idx); + int newValue = getTrimValue(mixerCurrentFlightMode, stickIndex); -void MainViewHorizontalTrim::drawLine(BitmapBuffer * dc) -{ - // Trim line - dc->drawSolidFilledRect( - TRIM_SQUARE_SIZE / 2, (TRIM_SQUARE_SIZE - TRIM_LINE_WIDTH - 1) / 2, - HORIZONTAL_SLIDERS_WIDTH - TRIM_SQUARE_SIZE + 1, TRIM_LINE_WIDTH, COLOR_THEME_SECONDARY1); -} + setRange(); + newValue = min(max(newValue, trimMin), trimMax); -void MainViewHorizontalTrim::drawMarkerLines(BitmapBuffer * dc, coord_t x, coord_t y) -{ - // Small lines on the square - if (value >= 0) { - dc->drawSolidVerticalLine(x + 10, 3, 9, COLOR_THEME_PRIMARY2); - } - if (value <= 0) { - dc->drawSolidVerticalLine(x + 4, 3, 9, COLOR_THEME_PRIMARY2); + if (value != newValue || (g_model.displayTrims == DISPLAY_TRIMS_CHANGE && + showChange && trimsDisplayTimer == 0)) { + value = newValue; + setPos(); } } -void MainViewHorizontalTrim::drawValue(BitmapBuffer * dc) +coord_t MainViewTrim::sx() { - coord_t x = (value < 0) ? HORIZONTAL_SLIDERS_WIDTH * 4 / 5 : HORIZONTAL_SLIDERS_WIDTH / 5; - dc->drawSolidFilledRect(x - TRIM_SQUARE_SIZE/2, (TRIM_SQUARE_SIZE-12)/2, TRIM_SQUARE_SIZE, 12, COLOR_THEME_SECONDARY1); - dc->drawNumber(x, 2, - divRoundClosest(abs(value) * 100, trimMax), - FONT(XXS) | COLOR_THEME_PRIMARY2 | CENTERED); -} + if (isVertical) return 0; -MainViewVerticalTrim::MainViewVerticalTrim(Window* parent, uint8_t idx) : - MainViewTrim(parent, rect_t{0, 0, TRIM_SQUARE_SIZE, VERTICAL_SLIDERS_HEIGHT}, idx) -{ + return divRoundClosest( + (HORIZONTAL_SLIDERS_WIDTH - TRIM_SQUARE_SIZE) * (value - trimMin), + trimMax - trimMin); } -coord_t MainViewVerticalTrim::sy() +coord_t MainViewTrim::sy() { - return VERTICAL_SLIDERS_HEIGHT - TRIM_SQUARE_SIZE - - divRoundClosest((VERTICAL_SLIDERS_HEIGHT - TRIM_SQUARE_SIZE) * (value - trimMin), - trimMax - trimMin); -} + if (!isVertical) return 0; -void MainViewVerticalTrim::drawLine(BitmapBuffer * dc) -{ - // Trim line - dc->drawSolidFilledRect((TRIM_SQUARE_SIZE - TRIM_LINE_WIDTH) / 2, TRIM_SQUARE_SIZE / 2, - TRIM_LINE_WIDTH, VERTICAL_SLIDERS_HEIGHT - TRIM_SQUARE_SIZE + 1, - COLOR_THEME_SECONDARY1); + return divRoundClosest( + (VERTICAL_SLIDERS_HEIGHT - TRIM_SQUARE_SIZE) * (trimMax - value), + trimMax - trimMin); } -void MainViewVerticalTrim::drawMarkerLines(BitmapBuffer * dc, coord_t x, coord_t y) +MainViewHorizontalTrim::MainViewHorizontalTrim(Window* parent, uint8_t idx) : + MainViewTrim(parent, + rect_t{0, 0, HORIZONTAL_SLIDERS_WIDTH, TRIM_SQUARE_SIZE}, idx, + false) { - // Small lines on the square - if (value >= 0) { - dc->drawSolidHorizontalLine(3, y + 4, 9, COLOR_THEME_PRIMARY2); - } - if (value <= 0) { - dc->drawSolidHorizontalLine(3, y + 10, 9, COLOR_THEME_PRIMARY2); - } } -void MainViewVerticalTrim::drawValue(BitmapBuffer * dc) +MainViewVerticalTrim::MainViewVerticalTrim(Window* parent, uint8_t idx) : + MainViewTrim(parent, + rect_t{0, 0, TRIM_SQUARE_SIZE, VERTICAL_SLIDERS_HEIGHT}, idx, + true) { - coord_t y = (value > 0) ? VERTICAL_SLIDERS_HEIGHT * 4 / 5 : VERTICAL_SLIDERS_HEIGHT / 5 - 11; - dc->drawSolidFilledRect(0, y, TRIM_SQUARE_SIZE, 11, COLOR_THEME_SECONDARY1); - dc->drawNumber(TRIM_SQUARE_SIZE/2, y, - divRoundClosest(abs(value) * 100, trimMax), - FONT(XXS) | COLOR_THEME_PRIMARY2 | CENTERED); } diff --git a/radio/src/gui/colorlcd/layouts/trims.h b/radio/src/gui/colorlcd/layouts/trims.h index 8e346232052..9df1f90611d 100644 --- a/radio/src/gui/colorlcd/layouts/trims.h +++ b/radio/src/gui/colorlcd/layouts/trims.h @@ -23,51 +23,42 @@ #include "libopenui.h" +class TrimIcon; + class MainViewTrim : public Window { - public: - MainViewTrim(Window * parent, const rect_t & rect, uint8_t idx); - - void checkEvents() override; - void paint(BitmapBuffer * dc) override; + public: + MainViewTrim(Window* parent, const rect_t& rect, uint8_t idx, + bool isVertical); - protected: - uint8_t idx; - int value = 0; - bool showChange = false; - int trimMin = 0, trimMax = 0; + protected: + uint8_t idx; + int value = 0; + bool isVertical; + bool showChange = false; + int trimMin = 0, trimMax = 0; + TrimIcon* trimIcon = nullptr; + DynamicNumber* trimValue = nullptr; + lv_obj_t* trimBar = nullptr; - void setRange(); + void setRange(); + void setPos(); - virtual coord_t sx() { return 0; } - virtual coord_t sy() { return 0; } + void checkEvents() override; - virtual void drawLine(BitmapBuffer * dc) = 0; - virtual void drawMarkerLines(BitmapBuffer * dc, coord_t x, coord_t y) = 0; - virtual void drawValue(BitmapBuffer * dc) = 0; + coord_t sx(); + coord_t sy(); }; class MainViewHorizontalTrim : public MainViewTrim { - public: - using MainViewTrim::MainViewTrim; - MainViewHorizontalTrim(Window* parent, uint8_t idx); - - protected: - coord_t sx() override; - void drawLine(BitmapBuffer * dc) override; - void drawMarkerLines(BitmapBuffer * dc, coord_t x, coord_t y) override; - void drawValue(BitmapBuffer * dc) override; + public: + using MainViewTrim::MainViewTrim; + MainViewHorizontalTrim(Window* parent, uint8_t idx); }; class MainViewVerticalTrim : public MainViewTrim { - public: - MainViewVerticalTrim(Window* parent, uint8_t idx); - - protected: - coord_t sy() override; - void drawLine(BitmapBuffer * dc) override; - void drawMarkerLines(BitmapBuffer * dc, coord_t x, coord_t y) override; - void drawValue(BitmapBuffer * dc) override; + public: + MainViewVerticalTrim(Window* parent, uint8_t idx); }; diff --git a/radio/src/gui/colorlcd/lcd.cpp b/radio/src/gui/colorlcd/lcd.cpp index 3e70e34d674..adbbc635749 100644 --- a/radio/src/gui/colorlcd/lcd.cpp +++ b/radio/src/gui/colorlcd/lcd.cpp @@ -19,42 +19,37 @@ * GNU General Public License for more details. */ -#include "board.h" #include "lcd.h" -#include "dma2d.h" -#include "bitmapbuffer.h" + #include +#include "bitmapbuffer.h" +#include "board.h" +#include "dma2d.h" + pixel_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; -BitmapBuffer lcdBuffer1(BMP_RGB565, LCD_W, LCD_H, (uint16_t *)LCD_FIRST_FRAME_BUFFER); -BitmapBuffer lcdBuffer2(BMP_RGB565, LCD_W, LCD_H, (uint16_t *)LCD_SECOND_FRAME_BUFFER); - -BitmapBuffer * lcdFront = &lcdBuffer1; -BitmapBuffer * lcd = &lcdBuffer2; +BitmapBuffer lcdBuffer1(BMP_RGB565, LCD_W, LCD_H, + (uint16_t*)LCD_FIRST_FRAME_BUFFER); +BitmapBuffer lcdBuffer2(BMP_RGB565, LCD_W, LCD_H, + (uint16_t*)LCD_SECOND_FRAME_BUFFER); -extern BitmapBuffer * lcdFront; -extern BitmapBuffer * lcd; +BitmapBuffer* lcdFront = &lcdBuffer1; +BitmapBuffer* lcd = &lcdBuffer2; static lv_disp_draw_buf_t disp_buf; static lv_disp_drv_t disp_drv; static lv_disp_t* disp = nullptr; -static lv_area_t screen_area = { - 0, 0, LCD_W-1, LCD_H-1 -}; - // Call backs -static void (*lcd_wait_cb)(lv_disp_drv_t *) = nullptr; -static void (*lcd_flush_cb)(lv_disp_drv_t *, uint16_t* buffer, const rect_t& area) = nullptr; +static void (*lcd_wait_cb)(lv_disp_drv_t*) = nullptr; +static void (*lcd_flush_cb)(lv_disp_drv_t*, uint16_t* buffer, + const rect_t& area) = nullptr; -void lcdSetWaitCb(void (*cb)(lv_disp_drv_t *)) -{ - lcd_wait_cb = cb; -} +void lcdSetWaitCb(void (*cb)(lv_disp_drv_t*)) { lcd_wait_cb = cb; } -void lcdSetFlushCb(void (*cb)(lv_disp_drv_t *, uint16_t*, const rect_t&)) +void lcdSetFlushCb(void (*cb)(lv_disp_drv_t*, uint16_t*, const rect_t&)) { lcd_flush_cb = cb; } @@ -63,7 +58,8 @@ static lv_disp_drv_t* refr_disp = nullptr; #if !defined(LCD_VERTICAL_INVERT) && 0 // TODO: DMA copy would be possible (use function from draw_ctx??? -static void _copy_screen_area(uint16_t* dst, uint16_t* src, const lv_area_t& copy_area) +static void _copy_screen_area(uint16_t* dst, uint16_t* src, + const lv_area_t& copy_area) { lv_coord_t x1 = copy_area.x1; lv_coord_t y1 = copy_area.y1; @@ -81,7 +77,8 @@ static void _copy_screen_area(uint16_t* dst, uint16_t* src, const lv_area_t& cop } #endif -static void flushLcd(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) +static void flushLcd(lv_disp_drv_t* disp_drv, const lv_area_t* area, + lv_color_t* color_p) { #if !defined(LCD_VERTICAL_INVERT) // we're only interested in the last flush in direct mode @@ -90,12 +87,12 @@ static void flushLcd(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_ return; } #endif - + #if defined(DEBUG_WINDOWS) - if (area->x1 != 0 || area->x2 != LCD_W-1 || area->y1 != 0 || - area->y2 != LCD_H-1) { - TRACE("partial refresh @ 0x%p {%d,%d,%d,%d}", color_p, area->x1, - area->y1, area->x2, area->y2); + if (area->x1 != 0 || area->x2 != LCD_W - 1 || area->y1 != 0 || + area->y2 != LCD_H - 1) { + TRACE("partial refresh @ 0x%p {%d,%d,%d,%d}", color_p, area->x1, area->y1, + area->x2, area->y2); } else { TRACE("full refresh @ 0x%p", color_p); } @@ -104,9 +101,7 @@ static void flushLcd(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_ if (lcd_flush_cb) { refr_disp = disp_drv; - - rect_t copy_area = {area->x1, area->y1, - area->x2 - area->x1 + 1, + rect_t copy_area = {area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1}; lcd_flush_cb(disp_drv, (uint16_t*)color_p, copy_area); @@ -120,19 +115,19 @@ static void flushLcd(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_ dst = LCD_FIRST_FRAME_BUFFER; lv_disp_t* disp = _lv_refr_get_disp_refreshing(); - for(int i = 0; i < disp->inv_p; i++) { - if(disp->inv_area_joined[i]) continue; + for (int i = 0; i < disp->inv_p; i++) { + if (disp->inv_area_joined[i]) continue; const lv_area_t& refr_area = disp->inv_areas[i]; auto area_w = refr_area.x2 - refr_area.x1 + 1; auto area_h = refr_area.y2 - refr_area.y1 + 1; - DMACopyBitmap(dst, LCD_W, LCD_H, refr_area.x1, refr_area.y1, - src, LCD_W, LCD_H, refr_area.x1, refr_area.y1, - area_w, area_h); + DMACopyBitmap(dst, LCD_W, LCD_H, refr_area.x1, refr_area.y1, src, LCD_W, + LCD_H, refr_area.x1, refr_area.y1, area_w, area_h); } - DMAWait(); // wait for the last DMACopyBitmap to be completed before sending completion message + DMAWait(); // wait for the last DMACopyBitmap to be completed before + // sending completion message lv_disp_flush_ready(disp_drv); #endif } else { @@ -154,16 +149,17 @@ void lcdInitDisplayDriver() // Init hardware LCD driver lcdInit(); backlightInit(); - - lv_disp_draw_buf_init(&disp_buf, lcdFront->getData(), lcd->getData(), LCD_W*LCD_H); - lv_disp_drv_init(&disp_drv); /*Basic initialization*/ - disp_drv.draw_buf = &disp_buf; /*Set an initialized buffer*/ - disp_drv.flush_cb = flushLcd; /*Set a flush callback to draw to the display*/ - disp_drv.wait_cb = lcd_wait_cb; /*Set a wait callback*/ + lv_disp_draw_buf_init(&disp_buf, lcdFront->getData(), lcd->getData(), + LCD_W * LCD_H); + lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + + disp_drv.draw_buf = &disp_buf; /*Set an initialized buffer*/ + disp_drv.flush_cb = flushLcd; /*Set a flush callback to draw to the display*/ + disp_drv.wait_cb = lcd_wait_cb; /*Set a wait callback*/ - disp_drv.hor_res = LCD_W; /*Set the horizontal resolution in pixels*/ - disp_drv.ver_res = LCD_H; /*Set the vertical resolution in pixels*/ + disp_drv.hor_res = LCD_W; /*Set the horizontal resolution in pixels*/ + disp_drv.ver_res = LCD_H; /*Set the vertical resolution in pixels*/ disp_drv.full_refresh = 0; #if !defined(LCD_VERTICAL_INVERT) @@ -179,19 +175,22 @@ void lcdInitDisplayDriver() lv_obj_remove_style_all(lv_scr_act()); // transparent background: - // - this prevents LVGL overwritting things drawn directly into the bitmap buffer + // - this prevents LVGL overwritting things drawn directly into the bitmap + // buffer lv_disp_set_bg_opa(disp, LV_OPA_TRANSP); - + // allow drawing at any moment _lv_refr_set_disp_refreshing(disp); - - lv_draw_ctx_t * draw_ctx = disp->driver->draw_ctx; + + lv_draw_ctx_t* draw_ctx = disp->driver->draw_ctx; lcd->setDrawCtx(draw_ctx); lcdFront->setDrawCtx(draw_ctx); } void lcdInitDirectDrawing() { + static lv_area_t screen_area = {0, 0, LCD_W - 1, LCD_H - 1}; + lv_draw_ctx_t* draw_ctx = disp->driver->draw_ctx; draw_ctx->buf = disp->driver->draw_buf->buf_act; draw_ctx->buf_area = &screen_area; @@ -227,8 +226,7 @@ static void _draw_buf_flush(lv_disp_t* disp) * and driver is ready to receive the new buffer */ if (draw_buf->buf1 && draw_buf->buf2) { while (draw_buf->flushing) { - if (disp->driver->wait_cb) - disp->driver->wait_cb(disp->driver); + if (disp->driver->wait_cb) disp->driver->wait_cb(disp->driver); } } @@ -249,20 +247,14 @@ static void _draw_buf_flush(lv_disp_t* disp) } } -void lcdClear() -{ - lcd->clear(); -} +void lcdClear() { lcd->clear(); } -void lcdRefresh() -{ - _draw_buf_flush(disp); -} +void lcdRefresh() { _draw_buf_flush(disp); } void lcdFlushed() { // its possible to get here before flushLcd is ever called. - // so check for nullptr first. (Race condition if you put breakpoints in startup code) - if (refr_disp != nullptr) - lv_disp_flush_ready(refr_disp); + // so check for nullptr first. (Race condition if you put breakpoints in + // startup code) + if (refr_disp != nullptr) lv_disp_flush_ready(refr_disp); } diff --git a/radio/src/gui/colorlcd/lcd.h b/radio/src/gui/colorlcd/lcd.h index 46c234581da..7d2d6aaec4d 100644 --- a/radio/src/gui/colorlcd/lcd.h +++ b/radio/src/gui/colorlcd/lcd.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _LCD_H_ -#define _LCD_H_ +#pragma once #include "opentx_types.h" @@ -32,7 +31,6 @@ #if defined(BOOT) #define BLINK_ON_PHASE (0) #else - #define FAST_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<5)) #define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6)) #define SLOW_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<7)) #endif @@ -54,5 +52,3 @@ void lcdClear(); void lcdRefresh(); void lcdFlushed(); - -#endif // _LCD_H_ diff --git a/radio/src/gui/colorlcd/libopenui.h b/radio/src/gui/colorlcd/libopenui.h index 563c7127601..efee729edfa 100644 --- a/radio/src/gui/colorlcd/libopenui.h +++ b/radio/src/gui/colorlcd/libopenui.h @@ -24,33 +24,21 @@ #if !defined(BOOT) #include "libopenui_defines.h" #include "libopenui_file.h" -#include "font.h" +#include "myeeprom.h" +#include "fonts.h" #include "window.h" #include "mainwindow.h" #include "static.h" #include "button.h" #include "toggleswitch.h" #include "numberedit.h" -#include "timeedit.h" #include "choice.h" -#include "sourcechoice.h" -#include "switchchoice.h" -#include "filechoice.h" #include "textedit.h" #include "slider.h" #include "keyboard_text.h" #include "keyboard_number.h" -#include "tabsgroup.h" -#include "page.h" #include "menu.h" #include "dialog.h" -#include "fullscreen_dialog.h" -#include "message_dialog.h" -#include "confirm_dialog.h" -#include "dialog.h" #include "getset_helpers.h" -#include "curveedit.h" -#include "draw_functions.h" -#include "textedits.h" #include "LvglWrapper.h" #endif diff --git a/radio/src/gui/colorlcd/list_line_button.cpp b/radio/src/gui/colorlcd/list_line_button.cpp index cc2687331e8..10e3dae7e07 100644 --- a/radio/src/gui/colorlcd/list_line_button.cpp +++ b/radio/src/gui/colorlcd/list_line_button.cpp @@ -20,7 +20,33 @@ */ #include "list_line_button.h" + #include "opentx.h" +#include "themes/etx_lv_theme.h" + +static void input_mix_line_constructor(const lv_obj_class_t* class_p, + lv_obj_t* obj) +{ + etx_std_style(obj, LV_PART_MAIN, PAD_TINY); +} + +static const lv_obj_class_t input_mix_line_class = { + .base_class = &lv_btn_class, + .constructor_cb = input_mix_line_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LV_PCT(100), + .height_def = LV_SIZE_CONTENT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE, + .instance_size = sizeof(lv_btn_t), +}; + +static lv_obj_t* input_mix_line_create(lv_obj_t* parent) +{ + return etx_create(&input_mix_line_class, parent); +} void ListLineButton::value_changed(lv_event_t* e) { @@ -30,14 +56,15 @@ void ListLineButton::value_changed(lv_event_t* e) } ListLineButton::ListLineButton(Window* parent, uint8_t index) : - Button(parent, rect_t{}, nullptr, 0, 0, input_mix_line_create), + ButtonBase(parent, rect_t{}, nullptr, input_mix_line_create), index(index) { - lv_obj_add_event_cb(lvobj, ListLineButton::value_changed, LV_EVENT_VALUE_CHANGED, nullptr); + lv_obj_add_event_cb(lvobj, ListLineButton::value_changed, + LV_EVENT_VALUE_CHANGED, nullptr); } void ListLineButton::checkEvents() { check(isActive()); - Button::checkEvents(); + ButtonBase::checkEvents(); } diff --git a/radio/src/gui/colorlcd/list_line_button.h b/radio/src/gui/colorlcd/list_line_button.h index df81e3a62b5..95396b51cb6 100644 --- a/radio/src/gui/colorlcd/list_line_button.h +++ b/radio/src/gui/colorlcd/list_line_button.h @@ -24,7 +24,7 @@ #include "button.h" #include "opentx_types.h" -class ListLineButton : public Button +class ListLineButton : public ButtonBase { public: ListLineButton(Window* parent, uint8_t index); diff --git a/radio/src/gui/colorlcd/listbox.cpp b/radio/src/gui/colorlcd/listbox.cpp index 4a95701288d..6a9c84c0263 100644 --- a/radio/src/gui/colorlcd/listbox.cpp +++ b/radio/src/gui/colorlcd/listbox.cpp @@ -18,6 +18,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + #include "listbox.h" // TODO: @@ -28,19 +29,19 @@ // - when turned on, ESC gets out of the edit-mode // and ENTER gets into edit-mode // -void ListBase::event_cb(lv_event_t* e) +void ListBox::event_cb(lv_event_t* e) { static bool _nested = false; if (_nested) return; - + lv_event_code_t code = lv_event_get_code(e); lv_obj_t* obj = lv_event_get_target(e); if (!obj) return; - ListBase* lb = (ListBase*)lv_event_get_user_data(e); + ListBox* lb = (ListBox*)lv_event_get_user_data(e); if (!lb) return; - if (code == LV_EVENT_FOCUSED && lb->getAutoEdit()) { + if (code == LV_EVENT_FOCUSED && lb->autoEdit) { lv_group_set_editing((lv_group_t*)lv_obj_get_group(obj), true); } else if (code == LV_EVENT_DEFOCUSED) { // Hack to get rid of 'FOCUSED' event sent @@ -48,140 +49,139 @@ void ListBase::event_cb(lv_event_t* e) _nested = true; lv_group_set_editing((lv_group_t*)lv_obj_get_group(obj), false); _nested = false; - } - else if (code == LV_EVENT_LONG_PRESSED) { + } else if (code == LV_EVENT_LONG_PRESSED) { lb->onLongPressed(); lv_obj_clear_state(obj, LV_STATE_PRESSED); lv_indev_wait_release(lv_indev_get_act()); } } -ListBase::ListBase(Window* parent, const rect_t& rect, - const std::vector& names, uint8_t lineHeight, - WindowFlags windowFlags) : - TableField(parent, rect, windowFlags) +ListBox::ListBox(Window* parent, const rect_t& rect, + const std::vector& names, uint8_t lineHeight) : + TableField(parent, rect) { - lv_obj_add_event_cb(lvobj, ListBase::event_cb, LV_EVENT_ALL, this); + lv_obj_add_event_cb(lvobj, ListBox::event_cb, LV_EVENT_ALL, this); - setColumnCount(1); setColumnWidth(0, rect.w); setLineHeight(lineHeight); setNames(names); } -void ListBase::setAutoEdit(bool enable) +void ListBox::setAutoEdit(bool enable) { if (autoEdit == enable) return; autoEdit = enable; if (autoEdit && hasFocus()) { lv_group_t* g = (lv_group_t*)lv_obj_get_group(lvobj); - if (g) lv_group_set_editing(g, true); + if (g) lv_group_set_editing(g, true); } } -void ListBase::setName(uint16_t idx, const std::string& name) +void ListBox::setName(uint16_t idx, const std::string& name) { - lv_table_set_cell_value(lvobj, idx, 0, name.c_str()); + lv_table_set_cell_value(lvobj, idx, 0, name.c_str()); } -void ListBase::setNames(const std::vector& names) +void ListBox::setNames(const std::vector& names) { setRowCount(names.size()); uint16_t row = 0; - for (const auto& name: names) { + for (const auto& name : names) { setName(row, name); row++; - } + } } -void ListBase::setLineHeight(uint8_t height) +void ListBox::setLineHeight(uint8_t height) { lv_obj_set_style_max_height(lvobj, height, LV_PART_ITEMS); } -void ListBase::setSelected(int selected) -{ - select(selected, 0); -} +void ListBox::setSelected(int selected) { select(selected, 0); } -void ListBase::setSelected(std::set selected) +void ListBox::setSelected(std::set selected) { - if(!multiSelect) return; + if (!multiSelect) return; - for(int i=0; i < getRowCount(); i++) { - if(selected.find(i) != selected.end()) + for (int i = 0; i < getRowCount(); i++) { + if (selected.find(i) != selected.end()) lv_table_add_cell_ctrl(lvobj, i, 0, LV_TABLE_CELL_CTRL_CUSTOM_1); else lv_table_clear_cell_ctrl(lvobj, i, 0, LV_TABLE_CELL_CTRL_CUSTOM_1); } } -int ListBase::getSelected() const +int ListBox::getSelected() const { uint16_t row, col; lv_table_get_selected_cell(lvobj, &row, &col); - if (row != LV_TABLE_CELL_NONE) { return row; } + if (row != LV_TABLE_CELL_NONE) { + return row; + } return -1; } -std::set ListBase::getSelection() +std::set ListBox::getSelection() { - if(!multiSelect) return std::set(); + if (!multiSelect) return std::set(); std::set selectedIndexes; - for(int i=0; i < getRowCount(); i++) { - if(lv_table_has_cell_ctrl(lvobj, i, 0, LV_TABLE_CELL_CTRL_CUSTOM_1)) - selectedIndexes.insert(i); + for (int i = 0; i < getRowCount(); i++) { + if (lv_table_has_cell_ctrl(lvobj, i, 0, LV_TABLE_CELL_CTRL_CUSTOM_1)) + selectedIndexes.insert(i); } return selectedIndexes; } -void ListBase::setActiveItem(int item) +void ListBox::setActiveItem(int item) { if (item != activeItem) { activeItem = item; - invalidate(); } } -int ListBase::getActiveItem() const -{ - return activeItem; -} +int ListBox::getActiveItem() const { return activeItem; } -void ListBase::onPress(uint16_t row, uint16_t col) +void ListBox::onPress(uint16_t row, uint16_t col) { if (row == LV_TABLE_CELL_NONE) return; TRACE("SHORT_PRESS"); - if(multiSelect && row < getRowCount()) { + if (multiSelect && row < getRowCount()) { std::set lastSelection = getSelection(); - bool chk = lv_table_has_cell_ctrl(lvobj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1); - if(chk) lv_table_clear_cell_ctrl(lvobj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1); - else lv_table_add_cell_ctrl(lvobj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1); + bool chk = + lv_table_has_cell_ctrl(lvobj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1); + if (chk) + lv_table_clear_cell_ctrl(lvobj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1); + else + lv_table_add_cell_ctrl(lvobj, row, 0, LV_TABLE_CELL_CTRL_CUSTOM_1); - if(_multiSelectHandler) { - _multiSelectHandler(getSelection(),lastSelection); + if (_multiSelectHandler) { + _multiSelectHandler(getSelection(), lastSelection); } } else { - if (pressHandler) { pressHandler(); } + if (pressHandler) { + pressHandler(); + } } } -void ListBase::onLongPressed() +void ListBox::onLongPressed() { TRACE("LONG_PRESS"); - if (longPressHandler) { longPressHandler(); } + if (longPressHandler) { + longPressHandler(); + } } // TODO: !auto-edit -void ListBase::onClicked() +void ListBox::onClicked() { - if (!getAutoEdit()) { + if (!autoEdit) { lv_group_set_editing((lv_group_t*)lv_obj_get_group(lvobj), true); } else { @@ -189,21 +189,22 @@ void ListBase::onClicked() } } -void ListBase::onCancel() +void ListBox::onCancel() { lv_group_t* g = (lv_group_t*)lv_obj_get_group(lvobj); - if (!getAutoEdit() && lv_group_get_editing(g)) { + if (!autoEdit && lv_group_get_editing(g)) { lv_group_set_editing(g, false); } else { TableField::onCancel(); } } -void ListBase::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) +void ListBox::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) { if ((multiSelect == false && row != activeItem) || - (multiSelect == true && !lv_table_has_cell_ctrl(lvobj, dsc->id, 0, LV_TABLE_CELL_CTRL_CUSTOM_1))) - return; + (multiSelect == true && + !lv_table_has_cell_ctrl(lvobj, dsc->id, 0, LV_TABLE_CELL_CTRL_CUSTOM_1))) + return; lv_area_t coords; lv_coord_t area_h = lv_area_get_height(dsc->draw_area); diff --git a/radio/src/gui/colorlcd/listbox.h b/radio/src/gui/colorlcd/listbox.h index ea0d59ad0ee..917599211a0 100644 --- a/radio/src/gui/colorlcd/listbox.h +++ b/radio/src/gui/colorlcd/listbox.h @@ -18,31 +18,28 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + #pragma once -#include -#include -#include -#include #include +#include -#include "bitmapbuffer.h" #include "libopenui.h" -#include "touch.h" -// base class for lists of elements with names -class ListBase : public TableField +// Class for lists of elements with names +class ListBox : public TableField { std::function longPressHandler = nullptr; std::function pressHandler = nullptr; - std::function, std::set)> _multiSelectHandler = nullptr; + std::function, std::set)> + _multiSelectHandler = nullptr; bool autoEdit = false; public: - ListBase(Window* parent, const rect_t& rect, const std::vector& names, - uint8_t lineHeight = MENUS_LINE_HEIGHT, WindowFlags windowFlags = 0); + ListBox(Window* parent, const rect_t& rect, + const std::vector& names, + uint8_t lineHeight = MENUS_LINE_HEIGHT); - bool getAutoEdit() const { return autoEdit; } void setAutoEdit(bool enable); void setName(uint16_t idx, const std::string& name); @@ -55,14 +52,13 @@ class ListBase : public TableField int getSelected() const; std::set getSelection(); - void setMultiSelect(bool mode) { - multiSelect = mode; - } + void setMultiSelect(bool mode) { multiSelect = mode; } virtual void setActiveItem(int item); int getActiveItem() const; - void setMultiSelectHandler(std::function, std::set)> handler) + void setMultiSelectHandler( + std::function, std::set)> handler) { _multiSelectHandler = std::move(handler); } @@ -92,11 +88,6 @@ class ListBase : public TableField void onClicked() override; void onCancel() override; - void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override; -}; - -class ListBox : public ListBase -{ - public: - using ListBase::ListBase; + void onDrawEnd(uint16_t row, uint16_t col, + lv_obj_draw_part_dsc_t* dsc) override; }; diff --git a/radio/src/gui/colorlcd/lz4_bitmaps.cpp b/radio/src/gui/colorlcd/lz4_bitmaps.cpp deleted file mode 100644 index 98c6d64e462..00000000000 --- a/radio/src/gui/colorlcd/lz4_bitmaps.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "lz4_bitmaps.h" -#include "libopenui/thirdparty/lz4/lz4.h" -#include "opentx_helpers.h" - -const uint8_t* _decompressed_mask(const uint8_t* lz4_compressed, uint8_t** raw) -{ - if (*raw == nullptr) { - const uint16_t* hdr = (const uint16_t*)lz4_compressed; - uint16_t width = hdr[0]; - uint16_t height = hdr[1]; - - size_t len = *(uint32_t*)&hdr[2]; - - // skip 8 bytes header - lz4_compressed += 8; - - uint32_t pixels = width * height; - *raw = (uint8_t*)malloc(align32(pixels + 4)); - - uint16_t* raw_hdr = (uint16_t*)*raw; - raw_hdr[0] = width; - raw_hdr[1] = height; - - char* data = (char*)&raw_hdr[2]; - LZ4_decompress_safe((const char *)lz4_compressed, data, len, pixels); - } - - return *raw; -} diff --git a/radio/src/gui/colorlcd/lz4_bitmaps.h b/radio/src/gui/colorlcd/lz4_bitmaps.h deleted file mode 100644 index 2cbf991e70e..00000000000 --- a/radio/src/gui/colorlcd/lz4_bitmaps.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#pragma once - -#include - -// -// LZ4 bitmaps definitions -// - -#define DEFINE_LZ4_BITMAP(name) \ - struct _uncomp_##name { \ - static uint8_t* raw; \ - operator const uint8_t*(); \ - }; \ - extern _uncomp_##name name - -#define IMPL_LZ4_BITMAP(name) \ - _uncomp_##name::operator const uint8_t*() \ - { \ - return _decompressed_mask( _##name, &raw); \ - }; \ - uint8_t* _uncomp_##name::raw = nullptr; \ - _uncomp_##name name - -#define STATIC_LZ4_BITMAP(name) \ - DEFINE_LZ4_BITMAP(name); \ - IMPL_LZ4_BITMAP(name) - -const uint8_t* _decompressed_mask(const uint8_t* lz4_compressed, uint8_t** raw); diff --git a/radio/src/gui/colorlcd/menu_model.cpp b/radio/src/gui/colorlcd/menu_model.cpp index f166a8f1822..d18899fa92a 100644 --- a/radio/src/gui/colorlcd/menu_model.cpp +++ b/radio/src/gui/colorlcd/menu_model.cpp @@ -44,59 +44,32 @@ ModelMenu::ModelMenu() : TabsGroup(ICON_MODEL) { build(); } void ModelMenu::build() { - _modelHeliEnabled = modelHeliEnabled(); - _modelFMEnabled = modelFMEnabled(); - _modelCurvesEnabled = modelCurvesEnabled(); - _modelGVEnabled = modelGVEnabled(); - _modelLSEnabled = modelLSEnabled(); - _modelSFEnabled = modelSFEnabled(); - _modelCustomScriptsEnabled = modelCustomScriptsEnabled(); - _modelTelemetryEnabled = modelTelemetryEnabled(); - addTab(new ModelSetupPage()); #if defined(HELI) - if (_modelHeliEnabled) addTab(new ModelHeliPage()); + addTab(new ModelHeliPage()); #endif #if defined(FLIGHT_MODES) - if (_modelFMEnabled) addTab(new ModelFlightModesPage()); + addTab(new ModelFlightModesPage()); #endif addTab(new ModelInputsPage()); addTab(new ModelMixesPage()); addTab(new ModelOutputsPage()); - if (_modelCurvesEnabled) addTab(new ModelCurvesPage()); + addTab(new ModelCurvesPage()); #if defined(GVARS) - if (_modelGVEnabled) addTab(new ModelGVarsPage()); + addTab(new ModelGVarsPage()); #endif - if (_modelLSEnabled) addTab(new ModelLogicalSwitchesPage()); - if (_modelSFEnabled) addTab(new SpecialFunctionsPage(g_model.customFn)); + addTab(new ModelLogicalSwitchesPage()); + addTab(new SpecialFunctionsPage()); #if defined(LUA_MODEL_SCRIPTS) - if (_modelCustomScriptsEnabled) addTab(new ModelMixerScriptsPage()); + addTab(new ModelMixerScriptsPage()); #endif - if (_modelTelemetryEnabled) addTab(new ModelTelemetryPage()); + addTab(new ModelTelemetryPage()); #if defined(PCBNV14) || defined(PCBPL18) addGoToMonitorsButton(); #endif } -void ModelMenu::checkEvents() -{ - TabsGroup::checkEvents(); - - if (_modelHeliEnabled != modelHeliEnabled() || - _modelFMEnabled != modelFMEnabled() || - _modelCurvesEnabled != modelCurvesEnabled() || - _modelGVEnabled != modelGVEnabled() || - _modelLSEnabled != modelLSEnabled() || - _modelSFEnabled != modelSFEnabled() || - _modelCustomScriptsEnabled != modelCustomScriptsEnabled() || - _modelTelemetryEnabled != modelTelemetryEnabled()) { - removeAllTabs(); - build(); - setCurrentTab(0); - } -} - #if defined(PCBNV14) || defined(PCBPL18) void ModelMenu::addGoToMonitorsButton() { diff --git a/radio/src/gui/colorlcd/menu_model.h b/radio/src/gui/colorlcd/menu_model.h index b9a8846a0b5..297c74f556d 100644 --- a/radio/src/gui/colorlcd/menu_model.h +++ b/radio/src/gui/colorlcd/menu_model.h @@ -36,17 +36,8 @@ class ModelMenu : public TabsGroup #if defined(PCBNV14) || defined(PCBPL18) void addGoToMonitorsButton(void); #endif - bool _modelHeliEnabled = true; - bool _modelFMEnabled = true; - bool _modelCurvesEnabled = true; - bool _modelGVEnabled = true; - bool _modelLSEnabled = true; - bool _modelSFEnabled = true; - bool _modelCustomScriptsEnabled = true; - bool _modelTelemetryEnabled = true; void build(); - void checkEvents() override; #if defined(HARDWARE_KEYS) void onPressSYS() override; diff --git a/radio/src/gui/colorlcd/menu_radio.cpp b/radio/src/gui/colorlcd/menu_radio.cpp index ce65f1e31dd..63afc582e9c 100644 --- a/radio/src/gui/colorlcd/menu_radio.cpp +++ b/radio/src/gui/colorlcd/menu_radio.cpp @@ -43,35 +43,16 @@ RadioMenu::~RadioMenu() { storageCheck(true); } void RadioMenu::build() { - _radioThemesEnabled = radioThemesEnabled(); - _radioGFEnabled = radioGFEnabled(); - _radioTrainerEnabled = radioTrainerEnabled(); - addTab(new RadioToolsPage()); addTab(new RadioSdManagerPage()); addTab(new RadioSetupPage()); - if (_radioThemesEnabled) addTab(new ThemeSetupPage()); - if (_radioGFEnabled) addTab(new SpecialFunctionsPage(g_eeGeneral.customFn)); - if (_radioTrainerEnabled) addTab(new RadioTrainerPage()); + addTab(new ThemeSetupPage(this)); + addTab(new GlobalFunctionsPage()); + addTab(new RadioTrainerPage()); addTab(new RadioHardwarePage()); addTab(new RadioVersionPage()); } -void RadioMenu::checkEvents() -{ - TabsGroup::checkEvents(); - - if (_radioThemesEnabled != radioThemesEnabled() || - _radioGFEnabled != radioGFEnabled() || - _radioTrainerEnabled != radioTrainerEnabled()) { - removeAllTabs(); - build(); - // Need to set current tab twice to work properly. TODO: can this be fixed? - setCurrentTab(0); - setCurrentTab(2); - } -} - #if defined(HARDWARE_KEYS) void RadioMenu::onPressSYS() { setCurrentTab(0); } void RadioMenu::onLongPressSYS() { setCurrentTab(2); } diff --git a/radio/src/gui/colorlcd/menu_radio.h b/radio/src/gui/colorlcd/menu_radio.h index 316f42bb5a0..10495352ea2 100644 --- a/radio/src/gui/colorlcd/menu_radio.h +++ b/radio/src/gui/colorlcd/menu_radio.h @@ -30,12 +30,7 @@ class RadioMenu : public TabsGroup ~RadioMenu(); protected: - bool _radioThemesEnabled = true; - bool _radioGFEnabled = true; - bool _radioTrainerEnabled = true; - void build(); - void checkEvents() override; #if defined(HARDWARE_KEYS) void onPressSYS() override; diff --git a/radio/src/gui/colorlcd/menu_screen.cpp b/radio/src/gui/colorlcd/menu_screen.cpp index e01322695e5..3944c1f2476 100644 --- a/radio/src/gui/colorlcd/menu_screen.cpp +++ b/radio/src/gui/colorlcd/menu_screen.cpp @@ -32,37 +32,13 @@ ScreenMenu::ScreenMenu(int8_t tabIdx) : TabsGroup(ICON_THEME) { - updateTabs(tabIdx); - - setCloseHandler([] { - ViewMain::instance()->updateTopbarVisibility(); - storageDirty(EE_MODEL); - }); -} - -void ScreenMenu::updateTabs(int8_t tabIdx) -{ - removeAllTabs(); - addTab(new ScreenUserInterfacePage(this)); for (int index = 0; index < MAX_CUSTOM_SCREENS; index++) { if (customScreens[index]) { - auto tab = new ScreenSetupPage(this, getTabs(), index); - std::string title(STR_MAIN_VIEW_X); - if (index >= 9) { - title[title.size() - 2] = '1'; - title.back() = (index - 9) + '0'; - } else { - title[title.size() - 2] = index + '1'; - title.back() = ' '; - } - tab->setTitle(title); - tab->setIcon(ICON_THEME_VIEW1 + index); - - addTab(tab); + addTab(new ScreenSetupPage(this, index)); } else { - addTab(new ScreenAddPage(this, getTabs())); + addTab(new ScreenAddPage(this, tabCount())); break; } } @@ -76,6 +52,11 @@ void ScreenMenu::updateTabs(int8_t tabIdx) } setCurrentTab(tab); + + setCloseHandler([] { + ViewMain::instance()->updateTopbarVisibility(); + storageDirty(EE_MODEL); + }); } #if defined(HARDWARE_KEYS) diff --git a/radio/src/gui/colorlcd/menu_screen.h b/radio/src/gui/colorlcd/menu_screen.h index 16197ef6629..5eee67008d9 100644 --- a/radio/src/gui/colorlcd/menu_screen.h +++ b/radio/src/gui/colorlcd/menu_screen.h @@ -27,7 +27,6 @@ class ScreenMenu : public TabsGroup { public: ScreenMenu(int8_t tabIdx = -1); - void updateTabs(int8_t tabIdx); protected: #if defined(HARDWARE_KEYS) diff --git a/radio/src/gui/colorlcd/menus.h b/radio/src/gui/colorlcd/menus.h index 5feae9011e7..bc1a07536f0 100644 --- a/radio/src/gui/colorlcd/menus.h +++ b/radio/src/gui/colorlcd/menus.h @@ -19,84 +19,17 @@ * GNU General Public License for more details. */ -#ifndef _MENUS_H_ -#define _MENUS_H_ +#pragma once #include "keys.h" extern uint8_t menuCalibrationState; -enum MenuIcons { - ICON_EDGETX, - ICON_RADIO, - ICON_RADIO_SETUP, - ICON_RADIO_SD_MANAGER, - ICON_RADIO_TOOLS, - ICON_RADIO_GLOBAL_FUNCTIONS, - ICON_RADIO_TRAINER, - ICON_RADIO_HARDWARE, - ICON_RADIO_CALIBRATION, - ICON_RADIO_EDIT_THEME, - ICON_RADIO_VERSION, - ICON_MODEL, - ICON_MODEL_SETUP, - ICON_MODEL_HELI, - ICON_MODEL_FLIGHT_MODES, - ICON_MODEL_INPUTS, - ICON_MODEL_MIXER, - ICON_MODEL_NOTES, - ICON_MODEL_OUTPUTS, - ICON_MODEL_CURVES, - ICON_MODEL_GVARS, - ICON_MODEL_LOGICAL_SWITCHES, - ICON_MODEL_SPECIAL_FUNCTIONS, - ICON_MODEL_LUA_SCRIPTS, - ICON_MODEL_TELEMETRY, - ICON_MODEL_USB, - ICON_MODEL_SELECT, - ICON_THEME, - ICON_THEME_SETUP, - ICON_THEME_VIEW1, - ICON_THEME_VIEW2, - ICON_THEME_VIEW3, - ICON_THEME_VIEW4, - ICON_THEME_VIEW5, - ICON_THEME_VIEW6, - ICON_THEME_VIEW7, - ICON_THEME_VIEW8, - ICON_THEME_VIEW9, - ICON_THEME_VIEW10, - ICON_THEME_ADD_VIEW, - ICON_STATS, - ICON_STATS_THROTTLE_GRAPH, - ICON_STATS_TIMERS, - ICON_STATS_ANALOGS, - ICON_STATS_DEBUG, - ICON_MONITOR, - ICON_MONITOR_CHANNELS1, - ICON_MONITOR_CHANNELS2, - ICON_MONITOR_CHANNELS3, - ICON_MONITOR_CHANNELS4, - ICON_MONITOR_LOGICAL_SWITCHES, - MENUS_ICONS_COUNT -}; - - #define COPY_MODE 1 #define MOVE_MODE 2 -extern uint8_t s_copyMode; -extern int8_t s_copySrcRow; -extern int8_t s_copyTgtOfs; -extern uint8_t s_currIdx; + extern int8_t s_currCh; -extern uint8_t s_copySrcIdx; -extern uint8_t s_copySrcCh; uint8_t getExposCount(); void deleteExpo(uint8_t idx); void insertExpo(uint8_t idx, uint8_t input); - -typedef int (*FnFuncP) (int x); -void drawFunction(FnFuncP fn, int x, int y, int width); - -#endif // _MENUS_H_ diff --git a/radio/src/gui/colorlcd/message_dialog.cpp b/radio/src/gui/colorlcd/message_dialog.cpp deleted file mode 100644 index 0f312bbd04d..00000000000 --- a/radio/src/gui/colorlcd/message_dialog.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Source: - * https://github.com/opentx/libopenui - * - * This file is a part of libopenui library. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - */ - -#include "message_dialog.h" -#include "static.h" - -MessageDialog::MessageDialog(Window* parent, const char* title, - const char* message, const char* info, - LcdFlags messageFlags, LcdFlags infoFlags) : - Dialog(parent, title, {50, 73, LCD_W - 100, LCD_H - 146}) -{ - messageWidget = new StaticText( - this, - {0, coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), PAGE_LINE_HEIGHT}, - message, 0, messageFlags); - - infoWidget = new StaticText(this, - {0, 30 + coord_t(height() - PAGE_LINE_HEIGHT) / 2, - width(), PAGE_LINE_HEIGHT}, - info, 0, infoFlags); - setCloseWhenClickOutside(true); -} - -void MessageDialog::onClicked() -{ - deleteLater(); -} - -HelpDialog::HelpDialog(Window* parent, rect_t rect, const char* title, - const char* message, - LcdFlags messageFlags) : - Dialog(parent, title, rect) -{ - messageWidget = new StaticText( - content, - {0, 33, content->width(), content->height() - 33}, - message, 0, messageFlags); - messageWidget->padAll(6); - - setCloseWhenClickOutside(true); -} - -void HelpDialog::onClicked() -{ - deleteLater(); -} - -DynamicMessageDialog::DynamicMessageDialog( - Window* parent, const char* title, std::function textHandler, - const char* message, const int lineHeight, - const LcdFlags textFlags) : - Dialog(parent, title, {50, 73, LCD_W - 100, LCD_H - 146}) -{ - setWindowFlags(windowFlags); - - messageWidget = new StaticText( - this, - {0, coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), PAGE_LINE_HEIGHT}, - message, 0, CENTERED); - - infoWidget = new DynamicText( - this, - {0, 30 + coord_t(height() - PAGE_LINE_HEIGHT) / 2, width(), lineHeight}, - textHandler, textFlags); - - setCloseWhenClickOutside(true); -} - -void DynamicMessageDialog::onClicked() -{ - deleteLater(); -} diff --git a/radio/src/gui/colorlcd/message_dialog.h b/radio/src/gui/colorlcd/message_dialog.h deleted file mode 100644 index 55bb5e4195d..00000000000 --- a/radio/src/gui/colorlcd/message_dialog.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#pragma once - -#include "dialog.h" -#include "static.h" - -class MessageDialog : public Dialog -{ - public: - MessageDialog(Window* parent, const char* title, const char* message, - const char* info = "", LcdFlags messageFlags = CENTERED, - LcdFlags infoFlags = CENTERED); - - void setInfoText(std::string text) { infoWidget->setText(std::move(text)); } - - protected: - StaticText* messageWidget; - StaticText* infoWidget; - -#if defined(DEBUG_WINDOWS) - std::string getName() const override { return "MessageDialog"; } -#endif - - void onClicked() override; -}; - -class HelpDialog : public Dialog -{ - public: - HelpDialog(Window* parent, rect_t rect, const char* title, const char* message, - LcdFlags messageFlags = CENTERED); - - protected: - StaticText* messageWidget; - -#if defined(DEBUG_WINDOWS) - std::string getName() const override { return "HelpDialog"; } -#endif - - void onClicked() override; -}; - -class DynamicMessageDialog : public Dialog -{ - public: - DynamicMessageDialog(Window* parent, const char* title, - std::function textHandler, - const char* message = "", - const int lineHeight = PAGE_LINE_HEIGHT, - const LcdFlags textFlags = CENTERED); - // Attn.: FONT(XXL) is not supported by DynamicMessageDialog - - protected: - StaticText* messageWidget; - DynamicText* infoWidget; - -#if defined(DEBUG_WINDOWS) - std::string getName() const override { return "DynamicMessageDialog"; } -#endif - - void onClicked() override; -}; diff --git a/radio/src/gui/colorlcd/mixer_edit.cpp b/radio/src/gui/colorlcd/mixer_edit.cpp index 9167fb1c1e1..854de5dc028 100644 --- a/radio/src/gui/colorlcd/mixer_edit.cpp +++ b/radio/src/gui/colorlcd/mixer_edit.cpp @@ -20,24 +20,28 @@ */ #include "mixer_edit.h" -#include "mixer_edit_adv.h" + #include "channel_bar.h" -#include "gvar_numberedit.h" #include "curve_param.h" +#include "gvar_numberedit.h" +#include "mixer_edit_adv.h" #include "mixes.h" - #include "opentx.h" +#include "themes/etx_lv_theme.h" +#include "sourcechoice.h" +#include "switchchoice.h" +#include "curveedit.h" #define SET_DIRTY() storageDirty(EE_MODEL) #if (LCD_W > LCD_H) - #define MIX_STATUS_BAR_WIDTH 250 - #define MIX_STATUS_BAR_MARGIN 3 - #define MIX_RIGHT_MARGIN 0 +#define MIX_STATUS_BAR_WIDTH 250 +#define MIX_STATUS_BAR_MARGIN 3 +#define MIX_RIGHT_MARGIN 0 #else - #define MIX_STATUS_BAR_WIDTH 180 - #define MIX_STATUS_BAR_MARGIN 0 - #define MIX_RIGHT_MARGIN 3 +#define MIX_STATUS_BAR_WIDTH 180 +#define MIX_STATUS_BAR_MARGIN 0 +#define MIX_RIGHT_MARGIN 3 #endif class MixerEditStatusBar : public Window @@ -50,10 +54,7 @@ class MixerEditStatusBar : public Window new ComboChannelBar(this, {MIX_STATUS_BAR_MARGIN, 0, rect.w - (MIX_STATUS_BAR_MARGIN * 2), rect.h}, - channel); - channelBar->setLeftMargin(15); - channelBar->setTextColor(COLOR_THEME_PRIMARY2); - channelBar->setOutputChannelBarLimitColor(COLOR_THEME_EDIT); + channel, true); } protected: @@ -62,12 +63,9 @@ class MixerEditStatusBar : public Window }; MixEditWindow::MixEditWindow(int8_t channel, uint8_t index) : - Page(ICON_MODEL_MIXER), channel(channel), index(index) + Page(ICON_MODEL_MIXER, PAD_MEDIUM), channel(channel), index(index) { - auto form = new FormWindow(&body, rect_t{}); - lv_obj_set_style_pad_all(form->getLvObj(), lv_dpx(8), 0); - - buildBody(form); + buildBody(&body); buildHeader(&header); } @@ -96,54 +94,55 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; #endif -void MixEditWindow::buildBody(FormWindow* form) +void MixEditWindow::buildBody(Window *form) { - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); form->setFlexLayout(); MixData *mix = mixAddress(index); // Mix name - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); + auto line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); new ModelTextEdit(line, rect_t{}, mix->name, sizeof(mix->name)); // Source - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SOURCE, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_SOURCE, COLOR_THEME_PRIMARY1); new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST, GET_SET_DEFAULT(mix->srcRaw)); CurveEdit::SetCurrentSource(mix->srcRaw); // Weight - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_WEIGHT, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_WEIGHT, COLOR_THEME_PRIMARY1); auto gvar = new GVarNumberEdit(line, rect_t{}, MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight)); gvar->setSuffix("%"); // Offset - new StaticText(line, rect_t{}, STR_OFFSET, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_OFFSET, COLOR_THEME_PRIMARY1); gvar = new GVarNumberEdit(line, rect_t{}, MIX_OFFSET_MIN, MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset)); gvar->setSuffix("%"); // Switch - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SWITCH, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_SWITCH, COLOR_THEME_PRIMARY1); new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(mix->swtch)); // Curve - new StaticText(line, rect_t{}, STR_CURVE, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_CURVE, COLOR_THEME_PRIMARY1); new CurveParam(line, rect_t{}, &mix->curve, SET_DEFAULT(mix->curve.value)); - line = form->newLine(); - lv_obj_set_style_pad_all(line->getLvObj(), lv_dpx(8), 0); - auto btn = new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t { - new MixEditAdvanced(channel, index); - return 0; - }); + line = form->newLine(grid); + line->padAll(PAD_LARGE); + auto btn = + new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t { + new MixEditAdvanced(channel, index); + return 0; + }); lv_obj_set_width(btn->getLvObj(), lv_pct(100)); } diff --git a/radio/src/gui/colorlcd/mixer_edit.h b/radio/src/gui/colorlcd/mixer_edit.h index 201c1cfc0f0..43d4fcaf0d0 100644 --- a/radio/src/gui/colorlcd/mixer_edit.h +++ b/radio/src/gui/colorlcd/mixer_edit.h @@ -25,7 +25,7 @@ #include "form.h" #include "curve.h" -class FormWindow; +class Window; class MixEditWindow : public Page { @@ -37,7 +37,7 @@ class MixEditWindow : public Page uint8_t index; void buildHeader(Window *window); - void buildBody(FormWindow *window); + void buildBody(Window *window); void deleteLater(bool detach = true, bool trash = true) override; }; diff --git a/radio/src/gui/colorlcd/mixer_edit_adv.cpp b/radio/src/gui/colorlcd/mixer_edit_adv.cpp index faf8661fa42..b640f70f668 100644 --- a/radio/src/gui/colorlcd/mixer_edit_adv.cpp +++ b/radio/src/gui/colorlcd/mixer_edit_adv.cpp @@ -20,26 +20,24 @@ */ #include "mixer_edit_adv.h" -#include "numberedit.h" + #include "fm_matrix.h" #include "mixes.h" - +#include "numberedit.h" #include "opentx.h" +#include "themes/etx_lv_theme.h" #define SET_DIRTY() storageDirty(EE_MODEL) MixEditAdvanced::MixEditAdvanced(int8_t channel, uint8_t index) : - Page(ICON_MODEL_MIXER), channel(channel), index(index) + Page(ICON_MODEL_MIXER, PAD_MEDIUM), channel(channel), index(index) { std::string title(STR_MIXES); title += "\n"; title += getSourceString(MIXSRC_FIRST_CH + channel); header.setTitle(title); - auto form = new FormWindow(&body, rect_t{}); - lv_obj_set_style_pad_all(form->getLvObj(), lv_dpx(8), 0); - - buildBody(form); + buildBody(&body); } #if LCD_W > LCD_H @@ -54,60 +52,65 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; #endif -void MixEditAdvanced::buildBody(FormWindow* form) +void MixEditAdvanced::buildBody(Window* form) { - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); form->setFlexLayout(); - MixData *mix = mixAddress(index); + MixData* mix = mixAddress(index); // Advanced... - + // Multiplex - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_MULTPX, 0, COLOR_THEME_PRIMARY1); + auto line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_MULTPX, COLOR_THEME_PRIMARY1); new Choice(line, rect_t{}, STR_VMLTPX, 0, 2, GET_SET_DEFAULT(mix->mltpx)); // Flight modes if (modelFMEnabled()) { - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_FLMODE, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_FLMODE, COLOR_THEME_PRIMARY1); new FMMatrix(line, rect_t{}, mix); } // Trim - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_TRIM, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_TRIM, COLOR_THEME_PRIMARY1); new ToggleSwitch(line, rect_t{}, GET_SET_INVERTED(mix->carryTrim)); // Warning - new StaticText(line, rect_t{}, STR_MIXWARNING, 0, COLOR_THEME_PRIMARY1); - auto edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, 3, GET_SET_DEFAULT(mix->mixWarn)); + new StaticText(line, rect_t{}, STR_MIXWARNING, COLOR_THEME_PRIMARY1); + auto edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, 3, + GET_SET_DEFAULT(mix->mixWarn)); edit->setZeroText(STR_OFF); // Delay up - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_DELAYUP, 0, COLOR_THEME_PRIMARY1); - edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->delayUp), - SET_VALUE(mix->delayUp, newValue), 0, PREC1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_DELAYUP, COLOR_THEME_PRIMARY1); + edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, + GET_DEFAULT(mix->delayUp), + SET_VALUE(mix->delayUp, newValue), PREC1); edit->setSuffix("s"); // Delay down - new StaticText(line, rect_t{}, STR_DELAYDOWN, 0, COLOR_THEME_PRIMARY1); - edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->delayDown), - SET_VALUE(mix->delayDown, newValue), 0, PREC1); + new StaticText(line, rect_t{}, STR_DELAYDOWN, COLOR_THEME_PRIMARY1); + edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, + GET_DEFAULT(mix->delayDown), + SET_VALUE(mix->delayDown, newValue), PREC1); edit->setSuffix("s"); // Slow up - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SLOWUP, 0, COLOR_THEME_PRIMARY1); - edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->speedUp), - SET_VALUE(mix->speedUp, newValue), 0, PREC1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_SLOWUP, COLOR_THEME_PRIMARY1); + edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, + GET_DEFAULT(mix->speedUp), + SET_VALUE(mix->speedUp, newValue), PREC1); edit->setSuffix("s"); // Slow down - new StaticText(line, rect_t{}, STR_SLOWDOWN, 0, COLOR_THEME_PRIMARY1); - edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->speedDown), - SET_VALUE(mix->speedDown, newValue), 0, PREC1); + new StaticText(line, rect_t{}, STR_SLOWDOWN, COLOR_THEME_PRIMARY1); + edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, + GET_DEFAULT(mix->speedDown), + SET_VALUE(mix->speedDown, newValue), PREC1); edit->setSuffix("s"); } diff --git a/radio/src/gui/colorlcd/mixer_edit_adv.h b/radio/src/gui/colorlcd/mixer_edit_adv.h index ea4b53f3bb5..7e9fafcd091 100644 --- a/radio/src/gui/colorlcd/mixer_edit_adv.h +++ b/radio/src/gui/colorlcd/mixer_edit_adv.h @@ -25,7 +25,7 @@ #include "form.h" #include "curve.h" -class FormWindow; +class Window; class MixEditAdvanced : public Page { @@ -37,5 +37,5 @@ class MixEditAdvanced : public Page uint8_t index; void buildHeader(Window *window); - void buildBody(FormWindow *window); + void buildBody(Window *window); }; diff --git a/radio/src/gui/colorlcd/model_curves.cpp b/radio/src/gui/colorlcd/model_curves.cpp index 0d414b71335..16e118e4712 100644 --- a/radio/src/gui/colorlcd/model_curves.cpp +++ b/radio/src/gui/colorlcd/model_curves.cpp @@ -20,73 +20,90 @@ */ #include "model_curves.h" -#include "opentx.h" + +#include "curveedit.h" #include "libopenui.h" +#include "opentx.h" #define SET_DIRTY() storageDirty(EE_MODEL) -#define PREVIEW_PAD 9 -#define TITLE_H 20 -#define INFO_H 27 +#define PREVIEW_PAD 6 +#define TITLE_H 20 +#define INFO_H 27 #define CURVE_BTN_W 142 #define CURVE_BTH_H CURVE_BTN_W + TITLE_H + INFO_H - PREVIEW_PAD #if LCD_W > LCD_H - #define PER_ROW 3 +#define PER_ROW 3 #else - #define PER_ROW 2 +#define PER_ROW 2 #endif -DEFINE_LZ4_BITMAP(LBM_DOT); - -class CurveButton : public Button { - public: - CurveButton(Window * parent, const rect_t &rect, uint8_t index) : - Button(parent, rect, nullptr, 0, 0, etx_button_create), - index(index) - { - padAll(0); - preview = new CurveRenderer({PREVIEW_PAD, PREVIEW_PAD+TITLE_H, width() - PREVIEW_PAD*2, width() - PREVIEW_PAD*2}, - [=](int x) -> int { - return applyCustomCurve(x, index); - }); +class CurveButton : public Button +{ + public: + CurveButton(Window *parent, const rect_t &rect, uint8_t index) : + Button(parent, rect), index(index) + { + padAll(PAD_ZERO); + + // Title + char buf[32]; + char *s = strAppendStringWithIndex(buf, STR_CV, index + 1); + if (g_model.curves[index].name[0]) { + s = strAppend(s, ":"); + strAppend(s, g_model.curves[index].name, LEN_CURVE_NAME); } + title = new StaticText(this, {4, -1, width() - 12, 21}, buf, + COLOR_THEME_SECONDARY1 | CENTERED | FONT(BOLD)); + etx_txt_color(title->getLvObj(), COLOR_THEME_PRIMARY2_INDEX, + LV_PART_MAIN | LV_STATE_USER_1); + etx_solid_bg(title->getLvObj(), COLOR_THEME_SECONDARY2_INDEX); + etx_solid_bg(title->getLvObj(), COLOR_THEME_FOCUS_INDEX, + LV_PART_MAIN | LV_STATE_USER_1); + + hdrLeft = new StaticIcon(this, 0, 0, getBuiltinIcon(ICON_ROUND_TITLE_LEFT), + COLOR_THEME_SECONDARY2); + hdrRight = new StaticIcon(this, width() - 8, 0, + getBuiltinIcon(ICON_ROUND_TITLE_RIGHT), + COLOR_THEME_SECONDARY2); + + // Preview + preview = new CurveRenderer( + this, + {PREVIEW_PAD, PREVIEW_PAD + TITLE_H, width() - PREVIEW_PAD * 2 - 4, + width() - PREVIEW_PAD * 2 - 4}, + [=](int x) -> int { return applyCustomCurve(x, index); }); + + // Curve characteristics + CurveHeader &curve = g_model.curves[index]; + snprintf(buf, 32, "%s %d %s", STR_CURVE_TYPES[curve.type], 5 + curve.points, + STR_PTS); + new StaticText(this, {0, height() - INFO_H + 1, LV_PCT(100), 16}, buf, + COLOR_THEME_SECONDARY1 | CENTERED | FONT(BOLD)); + } - void paint(BitmapBuffer * dc) override - { - char buf[32]; - LcdFlags bg_color = hasFocus() ? COLOR_THEME_FOCUS : COLOR_THEME_SECONDARY2; - LcdFlags txt_color = hasFocus() ? COLOR_THEME_PRIMARY2 : COLOR_THEME_SECONDARY1; - - int w = width(); - - // Title bar background - dc->drawSolidFilledRect(8, 0, w - 16, 8, bg_color); - dc->drawSolidFilledRect(0, 8, w, TITLE_H-6, bg_color); - dc->drawBitmapPattern(0, 0, LBM_DOT, bg_color); - dc->drawBitmapPattern(w - 13, 0, LBM_DOT, bg_color); - - // Title - char *s = strAppendStringWithIndex(buf, STR_CV, index + 1); - if (g_model.curves[index].name[0]) { - s = strAppend(s, ":"); - strAppend(s, g_model.curves[index].name, LEN_CURVE_NAME); - } - - dc->drawText(w / 2, 1, buf, txt_color|CENTERED|FONT(BOLD)); - - // Curve preview - preview->paint(dc); - - // Curve characteristics - CurveHeader &curve = g_model.curves[index]; - snprintf(buf, 32, "%s %d %s", STR_CURVE_TYPES[curve.type], 5 + curve.points, STR_PTS); - dc->drawText(w / 2, height() - INFO_H + 1, buf, COLOR_THEME_SECONDARY1|CENTERED|FONT(BOLD)); + void update() { preview->update(); } + + protected: + uint8_t index; + StaticText *title; + CurveRenderer *preview; + StaticIcon *hdrLeft = nullptr; + StaticIcon *hdrRight = nullptr; + + void checkEvents() override + { + if (hasFocus()) { + lv_obj_add_state(title->getLvObj(), LV_STATE_USER_1); + hdrLeft->setColor(COLOR_THEME_FOCUS_INDEX); + hdrRight->setColor(COLOR_THEME_FOCUS_INDEX); + } else { + lv_obj_clear_state(title->getLvObj(), LV_STATE_USER_1); + hdrLeft->setColor(COLOR_THEME_SECONDARY2_INDEX); + hdrRight->setColor(COLOR_THEME_SECONDARY2_INDEX); } - - protected: - uint8_t index; - CurveRenderer* preview; + } }; // initialize a new curves points to the default for a 5 point @@ -100,8 +117,7 @@ void initPoints(const CurveHeader &curve, int8_t *points) } } -ModelCurvesPage::ModelCurvesPage() : - PageTab(STR_MENUCURVES, ICON_MODEL_CURVES) +ModelCurvesPage::ModelCurvesPage() : PageTab(STR_MENUCURVES, ICON_MODEL_CURVES) { } @@ -109,30 +125,28 @@ ModelCurvesPage::ModelCurvesPage() : // currently called from model_mixes.cpp on longpress. void ModelCurvesPage::pushEditCurve(int index) { - if (! isCurveUsed(index)) { + if (!isCurveUsed(index)) { CurveHeader &curve = g_model.curves[index]; - int8_t * points = curveAddress(index); + int8_t *points = curveAddress(index); initPoints(curve, points); } - + new CurveEditWindow(index); } -void ModelCurvesPage::rebuild(FormWindow * window) +void ModelCurvesPage::rebuild(Window *window) { window->clear(); build(window); } -void ModelCurvesPage::editCurve(FormWindow * window, uint8_t curve) +void ModelCurvesPage::editCurve(Window *window, uint8_t curve) { - Window * editWindow = new CurveEditWindow(curve); - editWindow->setCloseHandler([=]() { - rebuild(window); - }); + Window *editWindow = new CurveEditWindow(curve); + editWindow->setCloseHandler([=]() { rebuild(window); }); } -void ModelCurvesPage::presetMenu(FormWindow * window, uint8_t index) +void ModelCurvesPage::presetMenu(Window *window, uint8_t index) { Menu *menu = new Menu(window); menu->setTitle(STR_CURVE_PRESET); @@ -141,7 +155,7 @@ void ModelCurvesPage::presetMenu(FormWindow * window, uint8_t index) strAppend(strAppendSigned(label, angle), "°"); menu->addLineBuffered(label, [=]() { CurveHeader &curve = g_model.curves[index]; - int8_t * points = curveAddress(index); + int8_t *points = curveAddress(index); int dx = 2000 / (5 + curve.points - 1); for (uint8_t i = 0; i < 5 + curve.points; i++) { @@ -149,7 +163,7 @@ void ModelCurvesPage::presetMenu(FormWindow * window, uint8_t index) points[i] = divRoundClosest(angle * x, 450); } if (curve.type == CURVE_TYPE_CUSTOM) { - resetCustomCurveX(points, 5 + curve.points); + resetCustomCurveX(points, 5 + curve.points); } storageDirty(EE_MODEL); @@ -159,7 +173,7 @@ void ModelCurvesPage::presetMenu(FormWindow * window, uint8_t index) menu->updateLines(); } -void ModelCurvesPage::newCV(FormWindow *window, bool presetCV) +void ModelCurvesPage::newCV(Window *window, bool presetCV) { Menu *menu = new Menu(Layer::back()); menu->setTitle(STR_CURVE); @@ -168,24 +182,24 @@ void ModelCurvesPage::newCV(FormWindow *window, bool presetCV) // search for unused slot for (uint8_t i = 0; i < MAX_CURVES; i += 1) { if (!isCurveUsed(i)) { - strAppendUnsigned(&s[2], i + 1); - menu->addLineBuffered(s, [=]() { - focusIndex = i; - if (presetCV) { - presetMenu(window, i); - } else { - CurveHeader &curve = g_model.curves[i]; - int8_t *points = curveAddress(i); - initPoints(curve, points); - editCurve(window, i); - } - }); + strAppendUnsigned(&s[2], i + 1); + menu->addLineBuffered(s, [=]() { + focusIndex = i; + if (presetCV) { + presetMenu(window, i); + } else { + CurveHeader &curve = g_model.curves[i]; + int8_t *points = curveAddress(i); + initPoints(curve, points); + editCurve(window, i); + } + }); } } menu->updateLines(); } -void ModelCurvesPage::plusPopup(FormWindow * window) +void ModelCurvesPage::plusPopup(Window *window) { Menu *menu = new Menu(window); menu->setTitle(STR_NEW); @@ -193,58 +207,58 @@ void ModelCurvesPage::plusPopup(FormWindow * window) menu->addLine(STR_CURVE_PRESET, [=]() { newCV(window, true); }); } -void ModelCurvesPage::build(FormWindow * window) +void ModelCurvesPage::build(Window *window) { #if LCD_W > LCD_H - static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; + static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; #else - static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; + static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; #endif static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; - window->padAll(6); window->setFlexLayout(); FlexGridLayout grid(col_dsc, row_dsc); - - FormWindow::Line* line = nullptr; + + FormLine *line = nullptr; bool hasFocusButton = false; uint8_t curveIndex = 0; - CurveButton* firstCurveButton = nullptr; + CurveButton *firstCurveButton = nullptr; for (uint8_t index = 0; index < MAX_CURVES; index++) { if (isCurveUsed(index)) { if ((curveIndex % PER_ROW) == 0) { - line = window->newLine(&grid); - lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); + line = window->newLine(grid); + lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, + LV_GRID_ALIGN_SPACE_BETWEEN); } // Curve drawing - auto button = new CurveButton(line, rect_t{0, 0, CURVE_BTN_W, CURVE_BTH_H}, index); + auto button = + new CurveButton(line, rect_t{0, 0, CURVE_BTN_W, CURVE_BTH_H}, index); button->setPressHandler([=]() -> uint8_t { - Menu * menu = new Menu(window); - menu->setTitle(STR_CURVE); - menu->addLine(STR_EDIT, [=]() { - editCurve(window, index); - }); - menu->addLine(STR_CURVE_PRESET, [=]() { presetMenu(window, index); }); - menu->addLine(STR_MIRROR, [=]() { - curveMirror(index); - storageDirty(EE_MODEL); - button->invalidate(); - }); - menu->addLine(STR_CLEAR, [=]() { - curveClear(index); - storageDirty(EE_MODEL); - rebuild(window); - }); - return 0; + Menu *menu = new Menu(window); + menu->setTitle(STR_CURVE); + menu->addLine(STR_EDIT, [=]() { editCurve(window, index); }); + menu->addLine(STR_CURVE_PRESET, [=]() { presetMenu(window, index); }); + menu->addLine(STR_MIRROR, [=]() { + curveMirror(index); + storageDirty(EE_MODEL); + button->update(); + }); + menu->addLine(STR_CLEAR, [=]() { + curveClear(index); + storageDirty(EE_MODEL); + rebuild(window); + }); + return 0; }); button->setFocusHandler([=](bool hasFocus) { - if (hasFocus) - focusIndex = index; + if (hasFocus) focusIndex = index; }); button->setLongPressHandler([=]() -> uint8_t { @@ -264,7 +278,8 @@ void ModelCurvesPage::build(FormWindow * window) lv_group_focus_obj(button->getLvObj()); } - lv_obj_set_grid_cell(button->getLvObj(), LV_GRID_ALIGN_CENTER, curveIndex % PER_ROW, 1, LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_grid_cell(button->getLvObj(), LV_GRID_ALIGN_CENTER, + curveIndex % PER_ROW, 1, LV_GRID_ALIGN_CENTER, 0, 1); curveIndex += 1; } @@ -276,7 +291,7 @@ void ModelCurvesPage::build(FormWindow * window) if (curveIndex < MAX_CURVES) { if ((curveIndex % PER_ROW) == 0) { - line = window->newLine(&grid); + line = window->newLine(grid); lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); } diff --git a/radio/src/gui/colorlcd/model_curves.h b/radio/src/gui/colorlcd/model_curves.h index 58fc8a372af..89a1768d586 100644 --- a/radio/src/gui/colorlcd/model_curves.h +++ b/radio/src/gui/colorlcd/model_curves.h @@ -19,27 +19,28 @@ * GNU General Public License for more details. */ -#ifndef _MODEL_CURVES_H_ -#define _MODEL_CURVES_H_ +#pragma once +#include "opentx.h" #include "tabsgroup.h" -class ModelCurvesPage: public PageTab { - public: - ModelCurvesPage(); - static void pushEditCurve(int index); +class ModelCurvesPage : public PageTab +{ + public: + ModelCurvesPage(); + static void pushEditCurve(int index); - virtual void build(FormWindow * window) override; + bool isVisible() const override { return modelCurvesEnabled(); } - protected: - uint8_t focusIndex = -1; - Button* addButton = nullptr; + virtual void build(Window* window) override; - void rebuild(FormWindow * window); - void editCurve(FormWindow * window, uint8_t curve); - void presetMenu(FormWindow * window, uint8_t index); - void plusPopup(FormWindow * window); - void newCV(FormWindow * window, bool presetCV); -}; + protected: + uint8_t focusIndex = -1; + ButtonBase* addButton = nullptr; -#endif // _MODEL_CURVES_H_ + void rebuild(Window* window); + void editCurve(Window* window, uint8_t curve); + void presetMenu(Window* window, uint8_t index); + void plusPopup(Window* window); + void newCV(Window* window, bool presetCV); +}; diff --git a/radio/src/gui/colorlcd/model_flightmodes.cpp b/radio/src/gui/colorlcd/model_flightmodes.cpp index 274047a4745..0df9dccb00a 100644 --- a/radio/src/gui/colorlcd/model_flightmodes.cpp +++ b/radio/src/gui/colorlcd/model_flightmodes.cpp @@ -20,24 +20,26 @@ */ #include "model_flightmodes.h" -#include "opentx.h" + #include "libopenui.h" +#include "list_line_button.h" +#include "opentx.h" +#include "page.h" +#include "switchchoice.h" +#include "themes/etx_lv_theme.h" -#define SET_DIRTY() storageDirty(EE_MODEL) +#define SET_DIRTY() storageDirty(EE_MODEL) static std::string getFMTrimStr(uint8_t mode, bool spacer) { mode &= 0x1F; - if (mode == TRIM_MODE_NONE) - return "-"; - if (mode == TRIM_MODE_3POS) - return "3P"; + if (mode == TRIM_MODE_NONE) return "-"; + if (mode == TRIM_MODE_3POS) return "3P"; std::string str((mode & 1) ? "+" : "="); if (spacer) str += " "; mode >>= 1; - if (mode > MAX_FLIGHT_MODES - 1) - mode = MAX_FLIGHT_MODES - 1; - str += '0'+ mode; + if (mode > MAX_FLIGHT_MODES - 1) mode = MAX_FLIGHT_MODES - 1; + str += '0' + mode; return str; } @@ -50,150 +52,147 @@ static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, #if LCD_W > LCD_H #define TRIMS_PER_LINE 2 static const lv_coord_t trims_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; + LV_GRID_TEMPLATE_LAST}; #else #define TRIMS_PER_LINE 1 static const lv_coord_t trims_col_dsc[] = {LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; + LV_GRID_TEMPLATE_LAST}; #endif -class FlightModeEdit : public Page +class TrimEdit : public Window { public: - FlightModeEdit(uint8_t index) : - Page(ICON_MODEL_FLIGHT_MODES), - index(index) - { - std::string title2 = std::string(STR_FM) + std::to_string(index); - header.setTitle(STR_MENUFLIGHTMODES); - header.setTitle2(title2); - - FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); - auto form = new FormWindow(&body, rect_t{}); - form->padAll(8); - form->setFlexLayout(); - - FlightModeData* p_fm = &g_model.flightModeData[index]; - - // Flight mode name - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); - new ModelTextEdit(line, rect_t{}, p_fm->name, LEN_FLIGHT_MODE_NAME); - - if (index > 0) { - // Switch - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SWITCH, 0, COLOR_THEME_PRIMARY1); - new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, - GET_SET_DEFAULT(p_fm->swtch)); - } + TrimEdit(Window* parent, int trimId, int fmId) : + Window(parent, rect_t{}, NO_FOCUS), trimId(trimId), fmId(fmId) + { + padAll(PAD_TINY); + setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); - // Fade in - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_FADEIN, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(p_fm->fadeIn), - SET_VALUE(p_fm->fadeIn, newValue), 0, PREC1); + trim_t* tr = &g_model.flightModeData[fmId].trim[trimId]; - // Fade out - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_FADEOUT, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(p_fm->fadeOut), - SET_VALUE(p_fm->fadeOut, newValue), 0, PREC1); + lastTrim = tr->value; - // Trims - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_TRIMS, 0, COLOR_THEME_PRIMARY1); + auto tr_btn = new TextButton( + this, rect_t{0, 0, 65, 0}, getSourceString(MIXSRC_FIRST_TRIM + trimId), + [=]() { + tr->mode = (tr->mode == TRIM_MODE_NONE) ? 0 : TRIM_MODE_NONE; + tr_mode->setValue(tr->mode); + showControls(); + SET_DIRTY(); + return tr->mode == 0; + }); - FlexGridLayout trim_grid(trims_col_dsc, line_row_dsc); + if (tr->mode != TRIM_MODE_NONE) tr_btn->check(); - for (int t = 0; t < keysGetMaxTrims(); t++) { - lastTrim[t] = p_fm->trim[t].value; + tr_mode = new Choice(this, rect_t{0, 0, 70, 0}, 0, 2 * MAX_FLIGHT_MODES, + GET_DEFAULT(tr->mode), [=](int val) { + tr->mode = val; + showControls(); + SET_DIRTY(); + }); + tr_mode->setTextHandler( + [=](uint8_t mode) { return getFMTrimStr(mode, true); }); + tr_mode->setAvailableHandler([=](int mode) { + if (fmId > 0) + return ((mode & 1) == 0) || ((mode >> 1) != fmId) || + (mode == TRIM_MODE_3POS); + return (mode == 0) || (mode == TRIM_MODE_3POS); + }); + + tr_value = new NumberEdit( + this, rect_t{0, 0, 70, 0}, g_model.extendedTrims ? -512 : -128, + g_model.extendedTrims ? 512 : 128, GET_SET_DEFAULT(tr->value)); + + showControls(); + } - if ((t % TRIMS_PER_LINE) == 0) { - line = form->newLine(&trim_grid); - line->padLeft(10); - } + protected: + int trimId; + int fmId; + int lastTrim; + Choice* tr_mode = {nullptr}; + NumberEdit* tr_value = {nullptr}; - auto trim = new FormWindow(line, rect_t{}); - trim->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - - auto trim_obj = trim->getLvObj(); - lv_obj_set_style_pad_column(trim_obj, lv_dpx(8), 0); - lv_obj_set_style_flex_cross_place(trim_obj, LV_FLEX_ALIGN_CENTER, 0); - lv_obj_set_style_grid_cell_x_align(trim_obj, LV_GRID_ALIGN_STRETCH, 0); - - trim_t* tr = &p_fm->trim[t]; - auto tr_btn = new TextButton( - trim, rect_t{}, getSourceString(MIXSRC_FIRST_TRIM + t), - [=]() { - tr->mode = (tr->mode == TRIM_MODE_NONE) ? 0 : TRIM_MODE_NONE; - tr_mode[t]->setValue(tr->mode); - SET_DIRTY(); - showControls(t, tr->mode); - return tr->mode == 0; - }); - - if (tr->mode != TRIM_MODE_NONE) tr_btn->check(); - tr_btn->setWidth(LV_DPI_DEF / 2); - tr_btn->setHeight(33); - - tr_mode[t] = new Choice(trim, rect_t{}, 0, 2 * MAX_FLIGHT_MODES, - GET_DEFAULT(tr->mode), - [=](int val) { - tr->mode = val; - showControls(t, tr->mode); - SET_DIRTY(); - }); - tr_mode[t]->setTextHandler([=](uint8_t mode) { return getFMTrimStr(mode, true); }); - tr_mode[t]->setAvailableHandler([=](int mode) { - if (index > 0) - return ((mode & 1) == 0) || ((mode >> 1) != index) || (mode == TRIM_MODE_3POS); - return (mode == 0) || (mode == TRIM_MODE_3POS); - }); + void showControls() + { + uint8_t mode = g_model.flightModeData[fmId].trim[trimId].mode; - tr_value[t] = new NumberEdit(trim, rect_t{0, 0, 70, 0}, - g_model.extendedTrims ? -512 : -128, g_model.extendedTrims ? 512 : 128, - GET_SET_DEFAULT(tr->value)); + bool checked = (mode != TRIM_MODE_NONE); + bool showValue = (fmId == 0 && mode != TRIM_MODE_3POS) || ((mode & 1) || (mode >> 1 == fmId)); - // show trim value choice iff btn->checked() - showControls(t, tr->mode); - } - } + tr_mode->show(checked); + tr_value->show(checked && showValue); + } - void checkEvents() override - { - for (int i = 0; i < keysGetMaxTrims(); i += 1) { - const auto& fm = g_model.flightModeData[index]; - if (lastTrim[i] != fm.trim[i].value) { - lastTrim[i] = fm.trim[i].value; - tr_value[i]->setValue(lastTrim[i]); - } - } - Page::checkEvents(); + void checkEvents() override + { + const auto& fm = g_model.flightModeData[fmId]; + if (lastTrim != fm.trim[trimId].value) { + lastTrim = fm.trim[trimId].value; + tr_value->setValue(lastTrim); } + Window::checkEvents(); + } +}; - protected: - uint8_t index; - Choice* tr_mode[MAX_TRIMS] = {nullptr}; - NumberEdit* tr_value[MAX_TRIMS] = {nullptr}; - int lastTrim[MAX_TRIMS]; - - void showControls(int trim, uint8_t mode) - { - bool checked = (mode != TRIM_MODE_NONE); - bool showValue = (index == 0 && mode != TRIM_MODE_3POS) || ((mode & 1) || (mode >> 1 == index)); +class FlightModeEdit : public Page +{ + public: + FlightModeEdit(uint8_t index) : Page(ICON_MODEL_FLIGHT_MODES), index(index) + { + std::string title2 = std::string(STR_FM) + std::to_string(index); + header.setTitle(STR_MENUFLIGHTMODES); + header.setTitle2(title2); + + FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); + body.setFlexLayout(); + + FlightModeData* p_fm = &g_model.flightModeData[index]; + + // Flight mode name + auto line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); + new ModelTextEdit(line, rect_t{}, p_fm->name, LEN_FLIGHT_MODE_NAME); + + if (index > 0) { + // Switch + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_SWITCH, COLOR_THEME_PRIMARY1); + new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, + SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(p_fm->swtch)); + } - if (checked) { - lv_obj_clear_flag(tr_mode[trim]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(tr_mode[trim]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - if (checked && showValue) { - lv_obj_clear_flag(tr_value[trim]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(tr_value[trim]->getLvObj(), LV_OBJ_FLAG_HIDDEN); + // Fade in + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_FADEIN, COLOR_THEME_PRIMARY1); + new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(p_fm->fadeIn), + SET_VALUE(p_fm->fadeIn, newValue), PREC1); + + // Fade out + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_FADEOUT, COLOR_THEME_PRIMARY1); + new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(p_fm->fadeOut), + SET_VALUE(p_fm->fadeOut, newValue), PREC1); + + // Trims + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_TRIMS, COLOR_THEME_PRIMARY1); + + FlexGridLayout trim_grid(trims_col_dsc, line_row_dsc, PAD_SMALL); + + for (int t = 0; t < keysGetMaxTrims(); t++) { + if ((t % TRIMS_PER_LINE) == 0) { + line = body.newLine(trim_grid); + line->padAll(PAD_TINY); + line->padLeft(10); } + + new TrimEdit(line, t, index); } + } + + protected: + uint8_t index; }; #if LCD_W > LCD_H // Landscape @@ -222,171 +221,178 @@ class FlightModeEdit : public Page #endif -class FMStyle +static void fm_group_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) { - public: - FMStyle() {} - - void init() - { - if(!styleInitDone) - { - styleInitDone=true; - - lv_style_init(&fmTrimContStyle); - lv_style_set_pad_all(&fmTrimContStyle, 0); - lv_style_set_width(&fmTrimContStyle, TRIMC_W); - lv_style_set_height(&fmTrimContStyle, 32); - - lv_style_init(&fmIdStyle); - lv_style_set_text_font(&fmIdStyle, getFont(FONT(STD))); - lv_style_set_text_align(&fmIdStyle, LV_TEXT_ALIGN_LEFT); - lv_style_set_width(&fmIdStyle, FMID_W); - lv_style_set_pad_left(&fmIdStyle, 2); - - lv_style_init(&fmNameStyle); - lv_style_set_text_font(&fmNameStyle, getFont(FONT(XS))); - lv_style_set_text_align(&fmNameStyle, LV_TEXT_ALIGN_LEFT); - lv_style_set_width(&fmNameStyle, NAME_W); - - lv_style_init(&fmSwitchStyle); - lv_style_set_text_font(&fmSwitchStyle, getFont(FONT(STD))); - lv_style_set_text_align(&fmSwitchStyle, LV_TEXT_ALIGN_LEFT); - lv_style_set_width(&fmSwitchStyle, SWTCH_W); - - lv_style_init(&fmFadeStyle); - lv_style_set_text_font(&fmFadeStyle, getFont(FONT(STD))); - lv_style_set_text_align(&fmFadeStyle, LV_TEXT_ALIGN_RIGHT); - lv_style_set_width(&fmFadeStyle, FADE_W); - - lv_style_init(&fmTrimModeStyle); - lv_style_set_text_font(&fmTrimModeStyle, getFont(FONT(STD))); - lv_style_set_text_align(&fmTrimModeStyle, LV_TEXT_ALIGN_CENTER); - lv_style_set_width(&fmTrimModeStyle, TRIM_W); - lv_style_set_height(&fmTrimModeStyle, 16); - - fmTrimValueStyle = fmTrimModeStyle; - lv_style_init(&fmTrimValueStyle); - lv_style_set_text_font(&fmTrimValueStyle, getFont(FONT(XS))); - lv_style_set_text_align(&fmTrimValueStyle, LV_TEXT_ALIGN_CENTER); - lv_style_set_width(&fmTrimValueStyle, TRIM_W); - lv_style_set_height(&fmTrimValueStyle, 16); - } - - // Always update colors in case theme changes - lv_style_set_text_color(&fmIdStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&fmNameStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&fmSwitchStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&fmFadeStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&fmTrimModeStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&fmTrimValueStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - } - - lv_obj_t* newId(lv_obj_t* parent) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmIdStyle, LV_PART_MAIN); + etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW_WRAP); + lv_obj_set_style_flex_grow(obj, 2, LV_PART_MAIN); + lv_obj_set_height(obj, LV_SIZE_CONTENT); + lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_SPACE_AROUND); +} - return obj; - } +static const lv_obj_class_t fm_group_class = { + .base_class = &lv_obj_class, + .constructor_cb = fm_group_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LCD_W - 12, + .height_def = BTN_H, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_obj_t), +}; - lv_obj_t* newGroup(lv_obj_t* parent) - { - lv_obj_t* obj = lv_obj_create(parent); - lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW_WRAP); - lv_obj_set_style_flex_grow(obj, 2, LV_PART_MAIN); - lv_obj_set_style_pad_all(obj, 0, LV_PART_MAIN); - lv_obj_set_height(obj, LV_SIZE_CONTENT); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); - lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); - - return obj; - } +static void fm_trims_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); + lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); +} - lv_obj_t* newName(lv_obj_t* parent) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmNameStyle, LV_PART_MAIN); +static const lv_obj_class_t fm_trims_class = { + .base_class = &lv_obj_class, + .constructor_cb = fm_trims_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = TRIMC_W, + .height_def = 32, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_obj_t), +}; - return obj; - } +static void fm_id_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->pad_left_2, LV_PART_MAIN); + etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); +} - lv_obj_t* newSwitch(lv_obj_t* parent) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmSwitchStyle, LV_PART_MAIN); +static const lv_obj_class_t fm_id_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_id_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = FMID_W, + .height_def = PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; - return obj; - } +static void fm_name_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); + etx_font(obj, FONT_XS_INDEX); +} - lv_obj_t* newTrimCont(lv_obj_t* parent) - { - auto obj = lv_obj_create(parent); - lv_obj_add_style(obj, &fmTrimContStyle, LV_PART_MAIN); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); +static const lv_obj_class_t fm_name_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_name_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = NAME_W, + .height_def = PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; - return obj; - } +static void fm_switch_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); +} - lv_obj_t* newTrimMode(lv_obj_t* parent, int n) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmTrimModeStyle, LV_PART_MAIN); - lv_obj_set_pos(obj, n * TRIM_W, 0); +static const lv_obj_class_t fm_switch_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_switch_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = SWTCH_W, + .height_def = PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; - return obj; - } +static void fm_fade_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_right, LV_PART_MAIN); +} - lv_obj_t* newTrimValue(lv_obj_t* parent, int n) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmTrimValueStyle, LV_PART_MAIN); - lv_obj_set_pos(obj, n * TRIM_W, 16); +static const lv_obj_class_t fm_fade_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_fade_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = FADE_W, + .height_def = PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; - return obj; - } +static void fm_trim_mode_constructor(const lv_obj_class_t* class_p, + lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); +} - lv_obj_t* newFade(lv_obj_t* parent) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmFadeStyle, LV_PART_MAIN); +static const lv_obj_class_t fm_trim_mode_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_trim_mode_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = TRIM_W, + .height_def = 16, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; - return obj; - } +static void fm_trim_value_constructor(const lv_obj_class_t* class_p, + lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); + etx_font(obj, FONT_XS_INDEX); +} - private: - lv_style_t fmTrimContStyle; - lv_style_t fmIdStyle; - lv_style_t fmNameStyle; - lv_style_t fmSwitchStyle; - lv_style_t fmFadeStyle; - lv_style_t fmTrimModeStyle; - lv_style_t fmTrimValueStyle; - bool styleInitDone; +static const lv_obj_class_t fm_trim_value_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_trim_value_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = TRIM_W, + .height_def = 16, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), }; -static FMStyle fmStyle; - -class FlightModeBtn : public Button +class FlightModeBtn : public ListLineButton { public: - FlightModeBtn(Window* parent, int index) : - Button(parent, rect_t{}, nullptr, 0, 0, input_mix_line_create), - index(index) + FlightModeBtn(Window* parent, int index) : ListLineButton(parent, index) { - padTop(0); - padBottom(0); - padLeft(3); - padRight(6); + padAll(PAD_ZERO); + padColumn(PAD_SMALL); setHeight(BTN_H); lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); - lv_obj_set_style_pad_all(lvobj, 0, 0); - lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); + lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_SPACE_AROUND); check(isActive()); - lv_obj_add_event_cb(lvobj, FlightModeBtn::on_draw, - LV_EVENT_DRAW_MAIN_BEGIN, nullptr); + lv_obj_add_event_cb(lvobj, FlightModeBtn::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, + nullptr); } static void on_draw(lv_event_t* e) @@ -403,30 +409,31 @@ class FlightModeBtn : public Button void delayed_init(lv_event_t* e) { - lv_obj_enable_style_refresh(false); - - fmID = fmStyle.newId(lvobj); + fmID = etx_create(&fm_id_class, lvobj); + char label[8]; + getFlightModeString(label, index + 1); + lv_label_set_text(fmID, label); - lv_obj_t* container = fmStyle.newGroup(lvobj); + lv_obj_t* container = etx_create(&fm_group_class, lvobj); - fmName = fmStyle.newName(container); - fmSwitch = fmStyle.newSwitch(container); + fmName = etx_create(&fm_name_class, container); + fmSwitch = etx_create(&fm_switch_class, container); - lv_obj_t* trims_cont = fmStyle.newTrimCont(container); + lv_obj_t* trims_cont = etx_create(&fm_trims_class, container); for (int i = 0; i < keysGetMaxTrims(); i += 1) { - fmTrimMode[i] = fmStyle.newTrimMode(trims_cont, i); - fmTrimValue[i] = fmStyle.newTrimValue(trims_cont, i); + fmTrimMode[i] = etx_create(&fm_trim_mode_class, trims_cont); + lv_obj_set_pos(fmTrimMode[i], i * TRIM_W, 0); + fmTrimValue[i] = etx_create(&fm_trim_value_class, trims_cont); + lv_obj_set_pos(fmTrimValue[i], i * TRIM_W, 16); } - fmFadeIn = fmStyle.newFade(container); - fmFadeOut = fmStyle.newFade(container); + fmFadeIn = etx_create(&fm_fade_class, container); + fmFadeOut = etx_create(&fm_fade_class, container); init = true; refresh(); - lv_obj_enable_style_refresh(true); - lv_obj_update_layout(lvobj); if (e) { @@ -435,15 +442,11 @@ class FlightModeBtn : public Button } } - bool isActive() const - { - return (getFlightMode() == index); - } + bool isActive() const override { return (getFlightMode() == index); } void checkEvents() override { - Button::checkEvents(); - check(isActive()); + ListLineButton::checkEvents(); if (!refreshing && init) { refreshing = true; const auto& fm = g_model.flightModeData[index]; @@ -456,23 +459,20 @@ class FlightModeBtn : public Button bool showValue = (index == 0) || ((mode & 1) || (mode >> 1 == index)); if (checked && showValue) - lv_label_set_text(fmTrimValue[t], formatNumberAsString(fm.trim[t].value).c_str()); + lv_label_set_text(fmTrimValue[t], + formatNumberAsString(fm.trim[t].value).c_str()); } } refreshing = false; } } - void refresh() + void refresh() override { if (!init) return; const auto& fm = g_model.flightModeData[index]; - char label[8]; - getFlightModeString(label, index + 1); - lv_label_set_text(fmID, label); - if (fm.name[0] != '\0') { lv_label_set_text(fmName, fm.name); } else { @@ -480,6 +480,7 @@ class FlightModeBtn : public Button } if ((index > 0) && (fm.swtch != SWSRC_NONE)) { + char label[16]; getSwitchPositionName(label, fm.swtch); lv_label_set_text(fmSwitch, label); } else { @@ -494,19 +495,23 @@ class FlightModeBtn : public Button lv_label_set_text(fmTrimMode[i], getFMTrimStr(mode, false).c_str()); if (checked && showValue) - lv_label_set_text(fmTrimValue[i], formatNumberAsString(fm.trim[i].value).c_str()); + lv_label_set_text(fmTrimValue[i], + formatNumberAsString(fm.trim[i].value).c_str()); else lv_label_set_text(fmTrimValue[i], ""); } - lv_label_set_text(fmFadeIn, formatNumberAsString(fm.fadeIn, PREC1, 0, nullptr, "s").c_str()); - lv_label_set_text(fmFadeOut, formatNumberAsString(fm.fadeOut, PREC1, 0, nullptr, "s").c_str()); + lv_label_set_text( + fmFadeIn, + formatNumberAsString(fm.fadeIn, PREC1, 0, nullptr, "s").c_str()); + lv_label_set_text( + fmFadeOut, + formatNumberAsString(fm.fadeOut, PREC1, 0, nullptr, "s").c_str()); } protected: bool init = false; bool refreshing = false; - uint8_t index; lv_obj_t* fmID = nullptr; lv_obj_t* fmName = nullptr; @@ -518,42 +523,36 @@ class FlightModeBtn : public Button int lastTrim[MAX_TRIMS]; }; -ModelFlightModesPage::ModelFlightModesPage(): - PageTab(STR_MENUFLIGHTMODES, ICON_MODEL_FLIGHT_MODES) +ModelFlightModesPage::ModelFlightModesPage() : + PageTab(STR_MENUFLIGHTMODES, ICON_MODEL_FLIGHT_MODES, PAD_MEDIUM) { - fmStyle.init(); } -static const lv_coord_t fmt_col_dsc[] = {LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t fmt_col_dsc[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t fmt_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -void ModelFlightModesPage::build(FormWindow * window) +void ModelFlightModesPage::build(Window* form) { - window->padAll(4); - lv_obj_set_scrollbar_mode(window->getLvObj(), LV_SCROLLBAR_MODE_AUTO); - - FormWindow* form = new FormWindow(window, rect_t{}); - form->setFlexLayout(LV_FLEX_FLOW_COLUMN, 2); - form->padRow(lv_dpx(4)); + form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_SMALL); for (int i = 0; i < MAX_FLIGHT_MODES; i++) { auto btn = new FlightModeBtn(form, i); btn->setPressHandler([=]() { - new FlightModeEdit(i); - return 0; - }); + new FlightModeEdit(i); + return 0; + }); } - trimCheck = new TextButton(form, rect_t{0, 0, lv_pct(100), 40}, STR_CHECKTRIMS, [&]() -> uint8_t { - if (trimsCheckTimer) - trimsCheckTimer = 0; - else - trimsCheckTimer = 200; // 2 seconds trims cancelled - return trimsCheckTimer; - }); + trimCheck = new TextButton( + form, rect_t{0, 0, lv_pct(100), 40}, STR_CHECKTRIMS, [&]() -> uint8_t { + if (trimsCheckTimer) + trimsCheckTimer = 0; + else + trimsCheckTimer = 200; // 2 seconds trims cancelled + return trimsCheckTimer; + }); } void ModelFlightModesPage::checkEvents() diff --git a/radio/src/gui/colorlcd/model_flightmodes.h b/radio/src/gui/colorlcd/model_flightmodes.h index ba0be499ecf..cea2f7db1f3 100644 --- a/radio/src/gui/colorlcd/model_flightmodes.h +++ b/radio/src/gui/colorlcd/model_flightmodes.h @@ -19,16 +19,22 @@ * GNU General Public License for more details. */ +#pragma once + #include "tabsgroup.h" +#include "opentx.h" + +class ModelFlightModesPage : public PageTab +{ + public: + ModelFlightModesPage(); -class ModelFlightModesPage: public PageTab { - public: - ModelFlightModesPage(); + bool isVisible() const override { return modelFMEnabled(); } - void checkEvents() override; + void build(Window* window) override; - void build(FormWindow * window) override; + protected: + TextButton* trimCheck = nullptr; - protected: - TextButton* trimCheck = nullptr; + void checkEvents() override; }; diff --git a/radio/src/gui/colorlcd/model_gvars.cpp b/radio/src/gui/colorlcd/model_gvars.cpp index 87d8691fd64..953c5fce286 100644 --- a/radio/src/gui/colorlcd/model_gvars.cpp +++ b/radio/src/gui/colorlcd/model_gvars.cpp @@ -19,10 +19,14 @@ * GNU General Public License for more details. */ -#include "opentx.h" #include "model_gvars.h" + #include "libopenui.h" +#include "list_line_button.h" #include "numberedit.h" +#include "opentx.h" +#include "page.h" +#include "themes/etx_lv_theme.h" #define SET_DIRTY() storageDirty(EE_MODEL) @@ -40,148 +44,195 @@ #define GVAR_H (GVAR_VAL_H * 2) #endif +#define ETX_STATE_VALUE_SMALL_FONT LV_STATE_USER_1 + class GVarStyle { - public: - GVarStyle() {} - - void init() - { - if (!styleInitDone) - { - styleInitDone = true; - - lv_style_init(&fmContStyle); - lv_style_set_pad_all(&fmContStyle, 0); - lv_style_set_width(&fmContStyle, GVAR_VAL_W); - lv_style_set_height(&fmContStyle, GVAR_VAL_H); - lv_style_set_bg_opa(&fmContStyle, LV_OPA_COVER); - - lv_style_init(&fmContStyleChecked); - - lv_style_init(&fmLabelStyle); - if (modelFMEnabled()) - lv_style_set_height(&fmLabelStyle, PAGE_LINE_HEIGHT - 6); - lv_style_set_width(&fmLabelStyle, GVAR_VAL_W); - lv_style_set_text_font(&fmLabelStyle, getFont(FONT(XS))); - lv_style_set_text_align(&fmLabelStyle, LV_TEXT_ALIGN_CENTER); - - lv_style_init(&fmValueStyle); - lv_style_set_height(&fmValueStyle, PAGE_LINE_HEIGHT); - lv_style_set_width(&fmValueStyle, GVAR_VAL_W); - lv_style_set_text_font(&fmValueStyle, getFont(FONT(STD))); - lv_style_set_text_align(&fmValueStyle, LV_TEXT_ALIGN_CENTER); - - lv_style_init(&fmValueStyleSmall); - lv_style_set_text_font(&fmValueStyleSmall, getFont(FONT(XS))); - lv_style_set_pad_top(&fmValueStyleSmall, 3); - - lv_style_init(&fmNameStyle); - lv_style_set_width(&fmNameStyle, modelFMEnabled() ? GVAR_NAME_SIZE : GVAR_NAME_SIZE * 2); - lv_style_set_text_font(&fmNameStyle, getFont(FONT(STD))); - lv_style_set_text_align(&fmNameStyle, LV_TEXT_ALIGN_LEFT); - lv_style_set_pad_left(&fmNameStyle, 2); - } + public: + GVarStyle() {} + + void init() + { + if (!styleInitDone) { + styleInitDone = true; - // Always update colors in case theme changes - lv_style_set_bg_color(&fmContStyle, makeLvColor(COLOR_THEME_PRIMARY2)); - lv_style_set_bg_color(&fmContStyleChecked, makeLvColor(COLOR_THEME_ACTIVE)); - lv_style_set_text_color(&fmLabelStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&fmValueStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&fmNameStyle, makeLvColor(COLOR_THEME_SECONDARY1)); + lv_style_init(&gvLabelStyle); + lv_style_init(&gvNameStyle); } - lv_obj_t* newName(lv_obj_t* parent, const char* name) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmNameStyle, LV_PART_MAIN); - lv_label_set_text(obj, name); + // Update in case FM state changed + lv_style_set_width(&gvNameStyle, + modelFMEnabled() ? GVAR_NAME_SIZE : GVAR_NAME_SIZE * 2); + lv_style_set_height(&gvLabelStyle, modelFMEnabled() ? PAGE_LINE_HEIGHT - 6 + : PAGE_LINE_HEIGHT); + } - return obj; - } + lv_obj_t* newFMCont(lv_obj_t* parent, uint8_t flightMode); + lv_obj_t* newName(lv_obj_t* parent, const char* name); + lv_obj_t* newLabel(lv_obj_t* parent, const char* label); - lv_obj_t* newGroup(lv_obj_t* parent) - { - auto obj = lv_obj_create(parent); - lv_obj_set_width(obj, GVAR_VAL_W * GVAR_COLS); - lv_obj_set_height(obj, GVAR_H); - lv_obj_set_style_pad_all(obj, 0, LV_PART_MAIN); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); + lv_style_t gvNameStyle; + lv_style_t gvLabelStyle; - return obj; - } + private: + bool styleInitDone; +}; - lv_obj_t* newFMCont(lv_obj_t* parent, uint8_t flightMode) - { - auto obj = lv_obj_create(parent); - lv_obj_add_style(obj, &fmContStyle, LV_PART_MAIN); - lv_obj_add_style(obj, &fmContStyleChecked, LV_PART_MAIN|LV_STATE_CHECKED); - lv_obj_set_pos(obj, (flightMode%GVAR_COLS)*GVAR_VAL_W, (flightMode/GVAR_COLS)*GVAR_VAL_H); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); +static GVarStyle gvarStyle; - return obj; - } +static void gv_group_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); + lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); +} - lv_obj_t* newLabel(lv_obj_t* parent, const char* label) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmLabelStyle, LV_PART_MAIN); - lv_obj_set_pos(obj, 0, 0); - lv_label_set_text(obj, label); +static const lv_obj_class_t gv_group_class = { + .base_class = &lv_obj_class, + .constructor_cb = gv_group_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = GVAR_VAL_W * GVAR_COLS, + .height_def = GVAR_H, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_obj_t), +}; - return obj; - } +static void gv_fmcont_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); + etx_std_ctrl_colors(obj, LV_PART_MAIN); + lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); +} + +static const lv_obj_class_t gv_fmcont_class = { + .base_class = &lv_obj_class, + .constructor_cb = gv_fmcont_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = GVAR_VAL_W, + .height_def = GVAR_VAL_H, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_obj_t), +}; - lv_obj_t* newValue(lv_obj_t* parent) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &fmValueStyle, LV_PART_MAIN); - lv_obj_add_style(obj, &fmValueStyleSmall, LV_PART_MAIN|LV_STATE_USER_1); - lv_obj_set_pos(obj, 0, PAGE_LINE_HEIGHT - 6); +lv_obj_t* GVarStyle::newFMCont(lv_obj_t* parent, uint8_t flightMode) +{ + auto obj = etx_create(&gv_fmcont_class, parent); + lv_obj_set_pos(obj, (flightMode % GVAR_COLS) * GVAR_VAL_W, + (flightMode / GVAR_COLS) * GVAR_VAL_H); - return obj; - } + return obj; +} + +static void gv_name_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->pad_left_2, LV_PART_MAIN); + etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); + etx_obj_add_style(obj, gvarStyle.gvNameStyle, LV_PART_MAIN); +} - private: - lv_style_t fmNameStyle; - lv_style_t fmContStyle; - lv_style_t fmContStyleChecked; - lv_style_t fmLabelStyle; - lv_style_t fmValueStyle; - lv_style_t fmValueStyleSmall; - bool styleInitDone; +static const lv_obj_class_t gv_name_class = { + .base_class = &lv_label_class, + .constructor_cb = gv_name_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = GVAR_NAME_SIZE, + .height_def = PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), }; -static GVarStyle gvarStyle; +lv_obj_t* GVarStyle::newName(lv_obj_t* parent, const char* name) +{ + auto obj = etx_create(&gv_name_class, parent); + lv_label_set_text(obj, name); + + return obj; +} + +static void gv_label_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); + etx_font(obj, FONT_XS_INDEX); + etx_obj_add_style(obj, gvarStyle.gvLabelStyle, LV_PART_MAIN); + lv_obj_set_pos(obj, 0, 0); +} + +static const lv_obj_class_t gv_label_class = { + .base_class = &lv_label_class, + .constructor_cb = gv_label_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = GVAR_VAL_W, + .height_def = PAGE_LINE_HEIGHT - 6, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; + +lv_obj_t* GVarStyle::newLabel(lv_obj_t* parent, const char* label) +{ + auto obj = etx_create(&gv_label_class, parent); + lv_label_set_text(obj, label); + + return obj; +} + +static void gv_value_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); + etx_font(obj, FONT_XS_INDEX, LV_PART_MAIN | ETX_STATE_VALUE_SMALL_FONT); + lv_obj_set_pos(obj, 0, PAGE_LINE_HEIGHT - 6); +} + +static const lv_obj_class_t gv_value_class = { + .base_class = &lv_label_class, + .constructor_cb = gv_value_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = GVAR_VAL_W, + .height_def = PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; -class GVarButton : public Button +class GVarButton : public ListLineButton { public: GVarButton(Window* parent, const rect_t& rect, uint8_t gvar) : - Button(parent, rect, nullptr, 0, 0, input_mix_line_create), gvarIdx(gvar) + ListLineButton(parent, gvar) { + padAll(PAD_ZERO); + padColumn(PAD_MEDIUM); setHeight(BTN_H); lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); - lv_obj_set_style_pad_all(lvobj, 0, LV_PART_MAIN); - lv_obj_set_flex_align(lvobj, modelFMEnabled() ? LV_FLEX_ALIGN_CENTER : LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); - if (!modelFMEnabled()) - padLeft(8); + lv_obj_set_flex_align( + lvobj, !modelFMEnabled() ? LV_FLEX_ALIGN_CENTER : LV_FLEX_ALIGN_START, + LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); + if (!modelFMEnabled()) padLeft(8); - lv_obj_add_event_cb(lvobj, GVarButton::on_draw, - LV_EVENT_DRAW_MAIN_BEGIN, nullptr); + lv_obj_add_event_cb(lvobj, GVarButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, + nullptr); } static void on_draw(lv_event_t* e) { lv_obj_t* target = lv_event_get_target(e); auto line = (GVarButton*)lv_obj_get_user_data(target); - if (line) - line->build(e); + if (line) line->build(e); } protected: bool init = false; - uint8_t gvarIdx; uint8_t currentFlightMode = 0; // used for invalidation lv_obj_t* fmCont[MAX_FLIGHT_MODES]; lv_obj_t* valueTexts[MAX_FLIGHT_MODES]; @@ -189,9 +240,9 @@ class GVarButton : public Button int numFlightModes() { return modelFMEnabled() ? MAX_FLIGHT_MODES : 1; } - void checkEvents() + void checkEvents() override { - Button::checkEvents(); + ListLineButton::checkEvents(); if (init) { if (modelFMEnabled()) { uint8_t newFM = getFlightMode(); @@ -205,7 +256,7 @@ class GVarButton : public Button for (int flightMode = 0; flightMode < numFlightModes(); flightMode++) { FlightModeData* fmData = &g_model.flightModeData[flightMode]; - if (values[flightMode] != fmData->gvars[gvarIdx]) { + if (values[flightMode] != fmData->gvars[index]) { updateValueText(flightMode); } } @@ -218,12 +269,10 @@ class GVarButton : public Button currentFlightMode = getFlightMode(); - lv_obj_enable_style_refresh(false); - - gvarStyle.newName(lvobj, getGVarString(gvarIdx)); + gvarStyle.newName(lvobj, getGVarString(index)); if (modelFMEnabled()) { - lv_obj_t* container = gvarStyle.newGroup(lvobj); + auto container = etx_create(&gv_group_class, lvobj); for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { fmCont[flightMode] = gvarStyle.newFMCont(container, flightMode); @@ -235,7 +284,8 @@ class GVarButton : public Button getFlightModeString(label, flightMode + 1); gvarStyle.newLabel(fmCont[flightMode], label); - valueTexts[flightMode] = gvarStyle.newValue(fmCont[flightMode]); + valueTexts[flightMode] = + etx_create(&gv_value_class, fmCont[flightMode]); updateValueText(flightMode); } @@ -245,9 +295,7 @@ class GVarButton : public Button updateValueText(0); } - init = true; - - lv_obj_enable_style_refresh(true); + init =true; lv_obj_update_layout(lvobj); @@ -260,7 +308,7 @@ class GVarButton : public Button void updateValueText(uint8_t flightMode) { lv_obj_t* field = valueTexts[flightMode]; - gvar_t value = g_model.flightModeData[flightMode].gvars[gvarIdx]; + gvar_t value = g_model.flightModeData[flightMode].gvars[index]; values[flightMode] = value; if (value > GVAR_MAX) { @@ -271,9 +319,9 @@ class GVarButton : public Button lv_label_set_text(field, label); } else { - uint8_t unit = g_model.gvars[gvarIdx].unit; + uint8_t unit = g_model.gvars[index].unit; const char* suffix = (unit == 1) ? "%" : ""; - uint8_t prec = g_model.gvars[gvarIdx].prec; + uint8_t prec = g_model.gvars[index].prec; if (prec) lv_label_set_text_fmt(field, "%d.%01u%s", value / 10, (value < 0) ? (-value) % 10 : value % 10, suffix); @@ -281,13 +329,16 @@ class GVarButton : public Button lv_label_set_text_fmt(field, "%d%s", value, suffix); if (unit) { if (value <= -1000 || value >= 1000 || (prec && (value <= -100))) { - lv_obj_add_state(field, LV_STATE_USER_1); + lv_obj_add_state(field, ETX_STATE_VALUE_SMALL_FONT); } else { - lv_obj_clear_state(field, LV_STATE_USER_1); + lv_obj_clear_state(field, ETX_STATE_VALUE_SMALL_FONT); } } } } + + bool isActive() const override { return false; } + void refresh() override {} }; class GVarEditWindow : public Page @@ -304,7 +355,7 @@ class GVarEditWindow : public Page uint8_t index; gvar_t lastGVar = 0; bool refreshTitle = true; - uint8_t lastFlightMode = 255; // Force initial setting of header title + uint8_t lastFlightMode = 255; // Force initial setting of header title NumberEdit* min = nullptr; NumberEdit* max = nullptr; NumberEdit* values[MAX_FLIGHT_MODES] = {}; @@ -325,10 +376,8 @@ class GVarEditWindow : public Page auto curFM = getFlightMode(); auto fmData = &g_model.flightModeData[curFM]; - if (gVarInHeader && - ((lastFlightMode != curFM) || - (lastGVar != fmData->gvars[index]) || - refreshTitle)) { + if (gVarInHeader && ((lastFlightMode != curFM) || + (lastGVar != fmData->gvars[index]) || refreshTitle)) { char label[32]; refreshTitle = false; lastFlightMode = curFM; @@ -342,13 +391,6 @@ class GVarEditWindow : public Page strcat(label, getGVarValue(index, lastGVar, 0).c_str()); } gVarInHeader->setText(label); - if (modelFMEnabled()) { - for (auto& value : values) { - value->invalidate(); - } - } else { - values[0]->invalidate(); - } } } @@ -366,17 +408,13 @@ class GVarEditWindow : public Page min->setSuffix(suffix); max->setSuffix(suffix); - LcdFlags minFlags = min->getTextFlags(); - LcdFlags maxFlags = max->getTextFlags(); if (gvar->prec) { - minFlags |= PREC1; - maxFlags |= PREC1; + min->setTextFlag(PREC1); + max->setTextFlag(PREC1); } else { - minFlags &= ~PREC1; - maxFlags &= ~PREC1; + min->clearTextFlag(PREC1); + max->clearTextFlag(PREC1); } - min->setTextFlags(minFlags); - max->setTextFlags(maxFlags); min->update(); max->update(); @@ -397,12 +435,10 @@ class GVarEditWindow : public Page // Update value if outside min/max range values[fm]->setValue(values[fm]->getValue()); - LcdFlags flags = values[fm]->getTextFlags(); if (gvar->prec) - flags |= PREC1; + values[fm]->setTextFlag(PREC1); else - flags &= ~PREC1; - values[fm]->setTextFlags(flags); + values[fm]->clearTextFlag(PREC1); values[fm]->setDisplayHandler(nullptr); } else { @@ -418,11 +454,10 @@ class GVarEditWindow : public Page } values[fm]->setSuffix(suffix); - values[fm]->invalidate(); } } - void buildBody(FormWindow* window) + void buildBody(Window* window) { static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; @@ -430,21 +465,22 @@ class GVarEditWindow : public Page LV_GRID_TEMPLATE_LAST}; window->setFlexLayout(); - window->padAll(4); - FlexGridLayout grid(col_dsc, row_dsc, 2); - auto line = window->newLine(&grid); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); + + auto line = window->newLine(grid); GVarData* gvar = &g_model.gvars[index]; - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); grid.nextCell(); new ModelTextEdit(line, rect_t{}, gvar->name, LEN_GVAR_NAME); - line = window->newLine(&grid); + line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_UNIT, 0, COLOR_THEME_PRIMARY1); + static const char* const strUnits[] = { "-", "%" }; + new StaticText(line, rect_t{}, STR_UNIT, COLOR_THEME_PRIMARY1); grid.nextCell(); - new Choice(line, rect_t{}, "\001-%", 0, 1, GET_DEFAULT(gvar->unit), + new Choice(line, rect_t{}, strUnits, 0, 1, GET_DEFAULT(gvar->unit), [=](int16_t newValue) { refreshTitle = (gvar->unit != newValue); gvar->unit = newValue; @@ -452,9 +488,9 @@ class GVarEditWindow : public Page setProperties(); }); - line = window->newLine(&grid); + line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_PRECISION, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_PRECISION, COLOR_THEME_PRIMARY1); grid.nextCell(); new Choice(line, rect_t{}, STR_VPREC, 0, 1, GET_DEFAULT(gvar->prec), [=](int16_t newValue) { @@ -464,9 +500,9 @@ class GVarEditWindow : public Page setProperties(); }); - line = window->newLine(&grid); + line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_MIN, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_MIN, COLOR_THEME_PRIMARY1); grid.nextCell(); min = new NumberEdit( line, rect_t{}, GVAR_MIN, GVAR_MAX - gvar->max, @@ -478,9 +514,9 @@ class GVarEditWindow : public Page }); min->setAccelFactor(16); - line = window->newLine(&grid); + line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_MAX, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_MAX, COLOR_THEME_PRIMARY1); grid.nextCell(); max = new NumberEdit( line, rect_t{}, GVAR_MIN + gvar->min, GVAR_MAX, @@ -492,7 +528,7 @@ class GVarEditWindow : public Page }); max->setAccelFactor(16); - line = window->newLine(&grid); + line = window->newLine(grid); char flightModeName[16]; FlightModeData* fmData; @@ -507,9 +543,9 @@ class GVarEditWindow : public Page if (userNameLen > 0) { strcpy(flightModeName, fmData->name); } - new StaticText(line, rect_t{}, flightModeName, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, flightModeName, COLOR_THEME_PRIMARY1); } else { - new StaticText(line, rect_t{}, STR_VALUE, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_VALUE, COLOR_THEME_PRIMARY1); } if (flightMode > 0) { @@ -522,8 +558,6 @@ class GVarEditWindow : public Page lv_obj_set_style_grid_cell_x_align(cb->getLvObj(), LV_GRID_ALIGN_END, 0); lv_obj_invalidate(cb->getLvObj()); - cb->setLabel(STR_OWN); - } else { grid.nextCell(); } @@ -532,7 +566,7 @@ class GVarEditWindow : public Page line, rect_t{}, GVAR_MIN + gvar->min, GVAR_MAX + MAX_FLIGHT_MODES - 1, GET_SET_DEFAULT(fmData->gvars[index])); values[flightMode]->setAccelFactor(16); - line = window->newLine(&grid); + line = window->newLine(grid); } setProperties(); @@ -542,12 +576,13 @@ class GVarEditWindow : public Page } }; -ModelGVarsPage::ModelGVarsPage() : PageTab(STR_MENU_GLOBAL_VARS, ICON_MODEL_GVARS) +ModelGVarsPage::ModelGVarsPage() : + PageTab(STR_MENU_GLOBAL_VARS, ICON_MODEL_GVARS) { gvarStyle.init(); } -void ModelGVarsPage::rebuild(FormWindow* window) +void ModelGVarsPage::rebuild(Window* window) { auto scroll_y = lv_obj_get_scroll_y(window->getLvObj()); window->clear(); @@ -555,12 +590,12 @@ void ModelGVarsPage::rebuild(FormWindow* window) lv_obj_scroll_to_y(window->getLvObj(), scroll_y, LV_ANIM_OFF); } -void ModelGVarsPage::build(FormWindow* window) +void ModelGVarsPage::build(Window* window) { - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 2); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); for (uint8_t index = 0; index < MAX_GVARS; index++) { - Button* button = new GVarButton(window, rect_t{}, index); + auto button = new GVarButton(window, rect_t{}, index); button->setPressHandler([=]() { Menu* menu = new Menu(window); menu->addLine(STR_EDIT, [=]() { diff --git a/radio/src/gui/colorlcd/model_gvars.h b/radio/src/gui/colorlcd/model_gvars.h index 45a7973944f..5de3af004a3 100644 --- a/radio/src/gui/colorlcd/model_gvars.h +++ b/radio/src/gui/colorlcd/model_gvars.h @@ -21,16 +21,17 @@ #pragma once -#include "page.h" #include "tabsgroup.h" -#include "window.h" +#include "opentx.h" class ModelGVarsPage : public PageTab { public: ModelGVarsPage(); + bool isVisible() const override { return modelGVEnabled(); } + protected: - void build(FormWindow* window) override; - void rebuild(FormWindow* window); + void build(Window* window) override; + void rebuild(Window* window); }; diff --git a/radio/src/gui/colorlcd/model_heli.cpp b/radio/src/gui/colorlcd/model_heli.cpp index 44de63d9443..4a6af19bcd4 100644 --- a/radio/src/gui/colorlcd/model_heli.cpp +++ b/radio/src/gui/colorlcd/model_heli.cpp @@ -22,6 +22,7 @@ #include "model_heli.h" #include "opentx.h" #include "libopenui.h" +#include "sourcechoice.h" #define SET_DIRTY() storageDirty(EE_MODEL) @@ -42,56 +43,56 @@ ModelHeliPage::ModelHeliPage(): { } -void ModelHeliPage::build(FormWindow* form) +void ModelHeliPage::build(Window* form) { - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); form->setFlexLayout(); // Swash type - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SWASHTYPE, 0, COLOR_THEME_PRIMARY1); + auto line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_SWASHTYPE, COLOR_THEME_PRIMARY1); new Choice(line, rect_t{}, STR_VSWASHTYPE, 0, SWASH_TYPE_MAX, GET_SET_DEFAULT(g_model.swashR.type)); // Swash ring - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SWASHRING, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_SWASHRING, COLOR_THEME_PRIMARY1); new NumberEdit(line, rect_t{}, 0, 100, GET_SET_DEFAULT(g_model.swashR.value)); // Elevator source - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_ELEVATOR, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_ELEVATOR, COLOR_THEME_PRIMARY1); new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_CH, GET_SET_DEFAULT(g_model.swashR.elevatorSource)); // Elevator weight - auto w = new StaticText(line, rect_t{}, STR_WEIGHT, 0, COLOR_THEME_PRIMARY1); + auto w = new StaticText(line, rect_t{}, STR_WEIGHT, COLOR_THEME_PRIMARY1); lv_obj_set_style_grid_cell_x_align(w->getLvObj(), LV_GRID_ALIGN_END, 0); lv_obj_set_style_pad_right(w->getLvObj(), lv_dpx(8), 0); new NumberEdit(line, rect_t{}, -100, 100, GET_SET_DEFAULT(g_model.swashR.elevatorWeight)); // Aileron source - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_AILERON, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_AILERON, COLOR_THEME_PRIMARY1); new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_CH, GET_SET_DEFAULT(g_model.swashR.aileronSource)); // Aileron weight - w = new StaticText(line, rect_t{}, STR_WEIGHT, 0, COLOR_THEME_PRIMARY1); + w = new StaticText(line, rect_t{}, STR_WEIGHT, COLOR_THEME_PRIMARY1); lv_obj_set_style_grid_cell_x_align(w->getLvObj(), LV_GRID_ALIGN_END, 0); lv_obj_set_style_pad_right(w->getLvObj(), lv_dpx(8), 0); new NumberEdit(line, rect_t{}, -100, 100, GET_SET_DEFAULT(g_model.swashR.aileronWeight)); // Collective source - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_COLLECTIVE, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_COLLECTIVE, COLOR_THEME_PRIMARY1); new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_CH, GET_SET_DEFAULT(g_model.swashR.collectiveSource)); // Collective weight - w = new StaticText(line, rect_t{}, STR_WEIGHT, 0, COLOR_THEME_PRIMARY1); + w = new StaticText(line, rect_t{}, STR_WEIGHT, COLOR_THEME_PRIMARY1); lv_obj_set_style_grid_cell_x_align(w->getLvObj(), LV_GRID_ALIGN_END, 0); lv_obj_set_style_pad_right(w->getLvObj(), lv_dpx(8), 0); new NumberEdit(line, rect_t{}, -100, 100, diff --git a/radio/src/gui/colorlcd/model_heli.h b/radio/src/gui/colorlcd/model_heli.h index d20935ad7bc..1291b7538ad 100644 --- a/radio/src/gui/colorlcd/model_heli.h +++ b/radio/src/gui/colorlcd/model_heli.h @@ -19,11 +19,17 @@ * GNU General Public License for more details. */ +#pragma once + +#include "opentx.h" #include "tabsgroup.h" -class ModelHeliPage: public PageTab { - public: - ModelHeliPage(); +class ModelHeliPage : public PageTab +{ + public: + ModelHeliPage(); + + bool isVisible() const override { return modelHeliEnabled(); } - void build(FormWindow * window); + void build(Window* window) override; }; diff --git a/radio/src/gui/colorlcd/model_inputs.cpp b/radio/src/gui/colorlcd/model_inputs.cpp index 694fcce154b..009648e048f 100644 --- a/radio/src/gui/colorlcd/model_inputs.cpp +++ b/radio/src/gui/colorlcd/model_inputs.cpp @@ -84,8 +84,6 @@ void deleteExpo(uint8_t idx) // TODO port: avoid global s_currCh on ARM boards (as done here)... int8_t s_currCh; -uint8_t s_copyMode; -int8_t s_copySrcRow; void insertExpo(uint8_t idx, uint8_t input) { @@ -167,10 +165,6 @@ class InputLineButton : public InputMixButton ModelInputsPage::ModelInputsPage() : PageTab(STR_MENUINPUTS, ICON_MODEL_INPUTS) { - setOnSetVisibleHandler([=]() { - // reset clipboard - _copyMode = 0; - }); } bool ModelInputsPage::reachExposLimit() @@ -233,7 +227,7 @@ void ModelInputsPage::removeLine(InputMixButton* l) } } -InputMixGroup* ModelInputsPage::createGroup(FormWindow* form, mixsrc_t src) +InputMixGroup* ModelInputsPage::createGroup(Window* form, mixsrc_t src) { return new InputMixGroup(form, src); } @@ -464,11 +458,14 @@ void ModelInputsPage::pasteInputAfter(uint8_t dst_idx) pasteInput(dst_idx + 1, input); } -void ModelInputsPage::build(FormWindow* window) +void ModelInputsPage::build(Window* window) { + // reset clipboard + _copyMode = 0; + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 3); - form = new FormWindow(window, rect_t{}); + form = new Window(window, rect_t{}); form->setFlexLayout(LV_FLEX_FLOW_COLUMN, 3); auto btn = new TextButton(window, rect_t{}, LV_SYMBOL_PLUS, [=]() { diff --git a/radio/src/gui/colorlcd/model_inputs.h b/radio/src/gui/colorlcd/model_inputs.h index f20022906e4..3d66b26d38a 100644 --- a/radio/src/gui/colorlcd/model_inputs.h +++ b/radio/src/gui/colorlcd/model_inputs.h @@ -31,10 +31,10 @@ class ModelInputsPage : public PageTab public: ModelInputsPage(); - void build(FormWindow *window) override; + void build(Window *window) override; protected: - FormWindow* form = nullptr; + Window* form = nullptr; std::list groups; std::list lines; InputMixButton* _copySrc = nullptr; @@ -49,7 +49,7 @@ class ModelInputsPage : public PageTab virtual void addLineButton(uint8_t index); virtual void addLineButton(mixsrc_t src, uint8_t index); - virtual InputMixGroup* createGroup(FormWindow* form, mixsrc_t src); + virtual InputMixGroup* createGroup(Window* form, mixsrc_t src); virtual InputMixButton* createLineButton(InputMixGroup *group, uint8_t index); void newInput(); diff --git a/radio/src/gui/colorlcd/model_logical_switches.cpp b/radio/src/gui/colorlcd/model_logical_switches.cpp index f2a3acd6e9a..45d00251f78 100644 --- a/radio/src/gui/colorlcd/model_logical_switches.cpp +++ b/radio/src/gui/colorlcd/model_logical_switches.cpp @@ -20,12 +20,21 @@ */ #include "model_logical_switches.h" -#include "opentx.h" + #include "libopenui.h" +#include "list_line_button.h" +#include "opentx.h" +#include "page.h" +#include "sourcechoice.h" +#include "switchchoice.h" #include "switches.h" +#include "themes/etx_lv_theme.h" #define SET_DIRTY() storageDirty(EE_MODEL) +#define ETX_STATE_LS_ACTIVE LV_STATE_USER_1 +#define ETX_STATE_V1_SMALL_FONT LV_STATE_USER_1 + static const lv_coord_t col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t col_dsc2[] = {LV_GRID_FR(4), LV_GRID_FR(3), @@ -36,7 +45,7 @@ class LogicalSwitchEditPage : public Page { public: explicit LogicalSwitchEditPage(uint8_t index) : - Page(ICON_MODEL_LOGICAL_SWITCHES), index(index) + Page(ICON_MODEL_LOGICAL_SWITCHES, PAD_ZERO), index(index) { buildHeader(&header); buildBody(&body); @@ -45,7 +54,7 @@ class LogicalSwitchEditPage : public Page protected: uint8_t index; bool active = false; - FormWindow* logicalSwitchOneWindow = nullptr; + Window* logicalSwitchOneWindow = nullptr; StaticText* headerSwitchName = nullptr; NumberEdit* v2Edit = nullptr; @@ -59,12 +68,11 @@ class LogicalSwitchEditPage : public Page Page::checkEvents(); if (active != isActive()) { if (isActive()) { - lv_obj_add_state(headerSwitchName->getLvObj(), LV_STATE_USER_1); + lv_obj_add_state(headerSwitchName->getLvObj(), ETX_STATE_LS_ACTIVE); } else { - lv_obj_clear_state(headerSwitchName->getLvObj(), LV_STATE_USER_1); + lv_obj_clear_state(headerSwitchName->getLvObj(), ETX_STATE_LS_ACTIVE); } active = isActive(); - invalidate(); } } @@ -74,17 +82,16 @@ class LogicalSwitchEditPage : public Page headerSwitchName = header.setTitle2( getSwitchPositionName(SWSRC_FIRST_LOGICAL_SWITCH + index)); - lv_obj_set_style_text_color(headerSwitchName->getLvObj(), - makeLvColor(COLOR_THEME_ACTIVE), - LV_STATE_USER_1); - lv_obj_set_style_text_font(headerSwitchName->getLvObj(), - getFont(FONT(BOLD)), LV_STATE_USER_1); + etx_txt_color(headerSwitchName->getLvObj(), COLOR_THEME_ACTIVE_INDEX, + ETX_STATE_LS_ACTIVE); + etx_font(headerSwitchName->getLvObj(), FONT_BOLD_INDEX, ETX_STATE_LS_ACTIVE); } void getV2Range(LogicalSwitchData* cs, int16_t& v2_min, int16_t& v2_max) { getMixSrcRange(cs->v1, v2_min, v2_max); - if ((cs->func == LS_FUNC_APOS) || (cs->func == LS_FUNC_ANEG) || (cs->func == LS_FUNC_ADIFFEGREATER)) + if ((cs->func == LS_FUNC_APOS) || (cs->func == LS_FUNC_ANEG) || + (cs->func == LS_FUNC_ADIFFEGREATER)) v2_min = 0; } @@ -95,15 +102,15 @@ class LogicalSwitchEditPage : public Page logicalSwitchOneWindow->clear(); logicalSwitchOneWindow->setFlexLayout(); - FlexGridLayout grid(col_dsc, row_dsc, 2); - FlexGridLayout grid2(col_dsc2, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); + FlexGridLayout grid2(col_dsc2, row_dsc, PAD_TINY); LogicalSwitchData* cs = lswAddress(index); uint8_t cstate = lswFamily(cs->func); // V1 - auto line = logicalSwitchOneWindow->newLine(&grid); - new StaticText(line, rect_t{}, STR_V1, 0, COLOR_THEME_PRIMARY1); + auto line = logicalSwitchOneWindow->newLine(grid); + new StaticText(line, rect_t{}, STR_V1, COLOR_THEME_PRIMARY1); switch (cstate) { case LS_FAMILY_BOOL: case LS_FAMILY_STICKY: @@ -143,11 +150,11 @@ class LogicalSwitchEditPage : public Page // V2 if (cstate == LS_FAMILY_EDGE) { - line = logicalSwitchOneWindow->newLine(&grid2); + line = logicalSwitchOneWindow->newLine(grid2); } else { - line = logicalSwitchOneWindow->newLine(&grid); + line = logicalSwitchOneWindow->newLine(grid); } - new StaticText(line, rect_t{}, STR_V2, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_V2, COLOR_THEME_PRIMARY1); switch (cstate) { case LS_FAMILY_BOOL: case LS_FAMILY_STICKY: @@ -210,30 +217,30 @@ class LogicalSwitchEditPage : public Page } // AND switch - line = logicalSwitchOneWindow->newLine(&grid); - new StaticText(line, rect_t{}, STR_AND_SWITCH, 0, COLOR_THEME_PRIMARY1); + line = logicalSwitchOneWindow->newLine(grid); + new StaticText(line, rect_t{}, STR_AND_SWITCH, COLOR_THEME_PRIMARY1); choice = new SwitchChoice(line, rect_t{}, -MAX_LS_ANDSW, MAX_LS_ANDSW, GET_SET_DEFAULT(cs->andsw)); choice->setAvailableHandler(isSwitchAvailableInLogicalSwitches); // Duration - line = logicalSwitchOneWindow->newLine(&grid); - new StaticText(line, rect_t{}, STR_DURATION, 0, COLOR_THEME_PRIMARY1); + line = logicalSwitchOneWindow->newLine(grid); + new StaticText(line, rect_t{}, STR_DURATION, COLOR_THEME_PRIMARY1); auto edit = new NumberEdit(line, rect_t{}, 0, MAX_LS_DURATION, - GET_SET_DEFAULT(cs->duration), 0, PREC1); + GET_SET_DEFAULT(cs->duration), PREC1); edit->setZeroText("---"); edit->setDisplayHandler([](int32_t value) { return formatNumberAsString(value, PREC1, 0, nullptr, "s"); }); // Delay - line = logicalSwitchOneWindow->newLine(&grid); - new StaticText(line, rect_t{}, STR_DELAY, 0, COLOR_THEME_PRIMARY1); + line = logicalSwitchOneWindow->newLine(grid); + new StaticText(line, rect_t{}, STR_DELAY, COLOR_THEME_PRIMARY1); if (cstate == LS_FAMILY_EDGE) { - new StaticText(line, rect_t{}, STR_NA, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_NA, COLOR_THEME_PRIMARY1); } else { auto edit = new NumberEdit(line, rect_t{}, 0, MAX_LS_DELAY, - GET_SET_DEFAULT(cs->delay), 0, PREC1); + GET_SET_DEFAULT(cs->delay), PREC1); edit->setDisplayHandler([](int32_t value) { if (value == 0) return std::string("---"); return formatNumberAsString(value, PREC1, 0, nullptr, "s"); @@ -241,19 +248,19 @@ class LogicalSwitchEditPage : public Page } } - void buildBody(FormWindow* window) + void buildBody(Window* window) { window->setFlexLayout(); - window->padAll(0); window->padLeft(4); window->padRight(4); - FlexGridLayout grid(col_dsc, row_dsc, 2); + + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); LogicalSwitchData* cs = lswAddress(index); // LS Func - auto line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_FUNC, 0, COLOR_THEME_PRIMARY1); + auto line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_FUNC, COLOR_THEME_PRIMARY1); auto functionChoice = new Choice(line, rect_t{}, STR_VCSWFUNC, 0, LS_FUNC_MAX, GET_DEFAULT(cs->func)); functionChoice->setSetValueHandler([=](int32_t newValue) { @@ -271,7 +278,7 @@ class LogicalSwitchEditPage : public Page updateLogicalSwitchOneWindow(); }); - logicalSwitchOneWindow = new FormWindow(window, rect_t{}); + logicalSwitchOneWindow = new Window(window, rect_t{}); updateLogicalSwitchOneWindow(); } }; @@ -299,10 +306,12 @@ static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; #define V2_COL_CNT 1 #define ANDSW_ROW 0 #define ANDSW_COL 4 +#define LS_BUTTON_H 34 #else // Portrait -static const lv_coord_t b_col_dsc[] = {36, 58, 88, 54, 54, LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t b_col_dsc[] = {36, 58, 88, + 54, 54, LV_GRID_TEMPLATE_LAST}; static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; @@ -311,18 +320,21 @@ static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, #define V2_COL_CNT 2 #define ANDSW_ROW 1 #define ANDSW_COL 2 +#define LS_BUTTON_H 45 #endif -class LogicalSwitchButton : public Button +class LogicalSwitchButton : public ListLineButton { public: LogicalSwitchButton(Window* parent, const rect_t& rect, int lsIndex) : - Button(parent, rect, nullptr, 0, 0, input_mix_line_create), - lsIndex(lsIndex) + ListLineButton(parent, lsIndex) { + setHeight(LS_BUTTON_H); #if LCD_H > LCD_W - padTop(0); + padTop(PAD_ZERO); +#else + padTop(PAD_SMALL); #endif padLeft(3); padRight(3); @@ -355,42 +367,44 @@ class LogicalSwitchButton : public Button void delayed_init(lv_event_t* e) { lsName = lv_label_create(lvobj); - lv_obj_set_style_text_align(lsName, LV_TEXT_ALIGN_LEFT, 0); + etx_obj_add_style(lsName, styles->text_align_left, LV_PART_MAIN); lv_obj_set_grid_cell(lsName, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_CENTER, 0, NM_ROW_CNT); lsFunc = lv_label_create(lvobj); - lv_obj_set_style_text_align(lsFunc, LV_TEXT_ALIGN_LEFT, 0); + etx_obj_add_style(lsFunc, styles->text_align_left, LV_PART_MAIN); lv_obj_set_grid_cell(lsFunc, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 0, NM_ROW_CNT); lsV1 = lv_label_create(lvobj); - lv_obj_set_style_text_align(lsV1, LV_TEXT_ALIGN_CENTER, 0); + etx_obj_add_style(lsV1, styles->text_align_center, LV_PART_MAIN); + etx_font(lsV1, FONT_XS_INDEX, ETX_STATE_V1_SMALL_FONT); lv_obj_set_grid_cell(lsV1, LV_GRID_ALIGN_STRETCH, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1); lsV2 = lv_label_create(lvobj); - lv_obj_set_style_text_align(lsV2, LV_TEXT_ALIGN_CENTER, 0); + etx_obj_add_style(lsV2, styles->text_align_center, LV_PART_MAIN); lv_obj_set_grid_cell(lsV2, LV_GRID_ALIGN_STRETCH, 3, V2_COL_CNT, LV_GRID_ALIGN_CENTER, 0, 1); lsAnd = lv_label_create(lvobj); - lv_obj_set_style_text_align(lsAnd, LV_TEXT_ALIGN_CENTER, 0); + etx_obj_add_style(lsAnd, styles->text_align_center, LV_PART_MAIN); lv_obj_set_grid_cell(lsAnd, LV_GRID_ALIGN_STRETCH, ANDSW_COL, 1, LV_GRID_ALIGN_CENTER, ANDSW_ROW, 1); lsDuration = lv_label_create(lvobj); - lv_obj_set_style_text_align(lsDuration, LV_TEXT_ALIGN_CENTER, 0); + etx_obj_add_style(lsDuration, styles->text_align_center, LV_PART_MAIN); lv_obj_set_grid_cell(lsDuration, LV_GRID_ALIGN_STRETCH, ANDSW_COL + 1, 1, LV_GRID_ALIGN_CENTER, ANDSW_ROW, 1); lsDelay = lv_label_create(lvobj); - lv_obj_set_style_text_align(lsDelay, LV_TEXT_ALIGN_CENTER, 0); + etx_obj_add_style(lsDelay, styles->text_align_center, LV_PART_MAIN); lv_obj_set_grid_cell(lsDelay, LV_GRID_ALIGN_STRETCH, ANDSW_COL + 2, 1, LV_GRID_ALIGN_CENTER, ANDSW_ROW, 1); init = true; refresh(); + lv_obj_update_layout(lvobj); if (e) { @@ -399,27 +413,22 @@ class LogicalSwitchButton : public Button } } - bool isActive() const - { - return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + lsIndex); - } - - void checkEvents() override + bool isActive() const override { - Button::checkEvents(); - check(isActive()); + return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + index); } - void refresh() + void refresh() override { if (!init) return; char s[20]; - LogicalSwitchData* ls = lswAddress(lsIndex); + LogicalSwitchData* ls = lswAddress(index); uint8_t lsFamily = lswFamily(ls->func); - lv_label_set_text(lsName, getSwitchPositionName(SWSRC_FIRST_LOGICAL_SWITCH + lsIndex)); + lv_label_set_text( + lsName, getSwitchPositionName(SWSRC_FIRST_LOGICAL_SWITCH + index)); lv_label_set_text(lsFunc, STR_VCSWFUNC[ls->func]); // CSW params - V1 @@ -434,9 +443,14 @@ class LogicalSwitchButton : public Button PREC1, 0, nullptr, "s") .c_str()); break; - default: - lv_label_set_text(lsV1, getSourceString(ls->v1)); - break; + default: { + char* s = getSourceString(ls->v1); + if (getTextWidth(s, 0, FONT(STD)) > 88) + lv_obj_add_state(lsV1, ETX_STATE_V1_SMALL_FONT); + else + lv_obj_clear_state(lsV1, ETX_STATE_V1_SMALL_FONT); + lv_label_set_text(lsV1, s); + } break; } // CSW params - V2 @@ -492,7 +506,6 @@ class LogicalSwitchButton : public Button protected: bool init = false; - uint8_t lsIndex; lv_obj_t* lsName = nullptr; lv_obj_t* lsFunc = nullptr; @@ -503,18 +516,12 @@ class LogicalSwitchButton : public Button lv_obj_t* lsDelay = nullptr; }; -#if LCD_W > LCD_H -#define LS_BUTTON_H 34 -#else -#define LS_BUTTON_H 45 -#endif - ModelLogicalSwitchesPage::ModelLogicalSwitchesPage() : - PageTab(STR_MENULOGICALSWITCHES, ICON_MODEL_LOGICAL_SWITCHES) + PageTab(STR_MENULOGICALSWITCHES, ICON_MODEL_LOGICAL_SWITCHES, PAD_SMALL) { } -void ModelLogicalSwitchesPage::rebuild(FormWindow* window) +void ModelLogicalSwitchesPage::rebuild(Window* window) { // When window.clear() is called the last button on screen is given focus // (???) This causes the page to jump to the end when rebuilt. Set flag to @@ -525,7 +532,7 @@ void ModelLogicalSwitchesPage::rebuild(FormWindow* window) isRebuilding = false; } -void ModelLogicalSwitchesPage::newLS(FormWindow* window, bool pasteLS) +void ModelLogicalSwitchesPage::newLS(Window* window, bool pasteLS) { Menu* menu = new Menu(Layer::back()); menu->setTitle(STR_MENU_LOGICAL_SWITCHES); @@ -534,7 +541,8 @@ void ModelLogicalSwitchesPage::newLS(FormWindow* window, bool pasteLS) for (uint8_t i = 0; i < MAX_LOGICAL_SWITCHES; i++) { LogicalSwitchData* ls = lswAddress(i); if (ls->func == LS_FUNC_NONE) { - std::string ch_name(getSwitchPositionName(SWSRC_FIRST_LOGICAL_SWITCH + i)); + std::string ch_name( + getSwitchPositionName(SWSRC_FIRST_LOGICAL_SWITCH + i)); menu->addLineBuffered(ch_name.c_str(), [=]() { if (pasteLS) { *ls = clipboard.data.csw; @@ -556,7 +564,7 @@ void ModelLogicalSwitchesPage::newLS(FormWindow* window, bool pasteLS) menu->updateLines(); } -void ModelLogicalSwitchesPage::plusPopup(FormWindow* window) +void ModelLogicalSwitchesPage::plusPopup(Window* window) { if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH) { Menu* menu = new Menu(window); @@ -567,18 +575,16 @@ void ModelLogicalSwitchesPage::plusPopup(FormWindow* window) } } -void ModelLogicalSwitchesPage::build(FormWindow* window) +void ModelLogicalSwitchesPage::build(Window* window) { static const lv_coord_t l_col_dsc[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; - window->padAll(4); - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); - FlexGridLayout grid(l_col_dsc, row_dsc, 2); + FlexGridLayout grid(l_col_dsc, row_dsc, PAD_TINY); - FormWindow::Line* line; + FormLine* line; bool hasEmptySwitch = false; - Button* button; // Reset focusIndex after switching tabs if (!isRebuilding) focusIndex = prevFocusIndex; @@ -589,9 +595,10 @@ void ModelLogicalSwitchesPage::build(FormWindow* window) bool isActive = (ls->func != LS_FUNC_NONE); if (isActive) { - line = window->newLine(&grid); + line = window->newLine(grid); - button = new LogicalSwitchButton(line, rect_t{0, 0, window->width() - 12, LS_BUTTON_H}, i); + auto button = new LogicalSwitchButton( + line, rect_t{0, 0, window->width() - 12, LS_BUTTON_H}, i); button->setPressHandler([=]() { Menu* menu = new Menu(window); @@ -652,7 +659,7 @@ void ModelLogicalSwitchesPage::build(FormWindow* window) } if (hasEmptySwitch) { - line = window->newLine(&grid); + line = window->newLine(grid); addButton = new TextButton(line, rect_t{0, 0, window->width() - 12, LS_BUTTON_H}, LV_SYMBOL_PLUS, [=]() { diff --git a/radio/src/gui/colorlcd/model_logical_switches.h b/radio/src/gui/colorlcd/model_logical_switches.h index 5bb260d0d4b..f2c4dcfe0a4 100644 --- a/radio/src/gui/colorlcd/model_logical_switches.h +++ b/radio/src/gui/colorlcd/model_logical_switches.h @@ -19,27 +19,27 @@ * GNU General Public License for more details. */ -#ifndef _MODEL_LOGICAL_SWITCHES_H -#define _MODEL_LOGICAL_SWITCHES_H +#pragma once #include "tabsgroup.h" +#include "opentx.h" class ModelLogicalSwitchesPage : public PageTab { public: ModelLogicalSwitchesPage(); - virtual void build(FormWindow* window) override; + bool isVisible() const override { return modelLSEnabled(); } + + virtual void build(Window* window) override; protected: int8_t focusIndex = -1; int8_t prevFocusIndex = -1; bool isRebuilding = false; - Button* addButton = nullptr; + ButtonBase* addButton = nullptr; - void rebuild(FormWindow* window); - void newLS(FormWindow* window, bool pasteLS); - void plusPopup(FormWindow* window); + void rebuild(Window* window); + void newLS(Window* window, bool pasteLS); + void plusPopup(Window* window); }; - -#endif //_MODEL_LOGICAL_SWITCHES_H diff --git a/radio/src/gui/colorlcd/model_mixer_scripts.cpp b/radio/src/gui/colorlcd/model_mixer_scripts.cpp index 569e896cb74..1e792e253a7 100644 --- a/radio/src/gui/colorlcd/model_mixer_scripts.cpp +++ b/radio/src/gui/colorlcd/model_mixer_scripts.cpp @@ -19,165 +19,171 @@ * GNU General Public License for more details. */ -#include "opentx.h" - #include "model_mixer_scripts.h" + #include "dataconstants.h" +#include "filechoice.h" +#include "libopenui.h" +#include "list_line_button.h" #include "lua/lua_api.h" - -#include "translations.h" #include "menus.h" -#include "libopenui.h" +#include "opentx.h" +#include "page.h" +#include "sourcechoice.h" +#include "themes/etx_lv_theme.h" +#include "translations.h" #define SET_DIRTY() storageDirty(EE_MODEL) // Overview grid -static const lv_coord_t col_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t col_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; // Edit grid #if LCD_W > LCD_H static const lv_coord_t e_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), - LV_GRID_TEMPLATE_LAST}; + LV_GRID_TEMPLATE_LAST}; #else static const lv_coord_t e_col_dsc[] = {LV_GRID_FR(5), LV_GRID_FR(4), - LV_GRID_TEMPLATE_LAST}; + LV_GRID_TEMPLATE_LAST}; #endif // Line button grid static const lv_coord_t b_col_dsc[] = {40, 84, 84, LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST -}; + LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; - -class ScriptEditWindow : public Page { - public: - explicit ScriptEditWindow(uint8_t idx) : - Page(ICON_MODEL_LUA_SCRIPTS), - idx(idx) - { - buildBody(&body); - buildHeader(&header); - } +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; - protected: - const uint8_t idx; - bool update = false; +class ScriptEditWindow : public Page +{ + public: + explicit ScriptEditWindow(uint8_t idx) : + Page(ICON_MODEL_LUA_SCRIPTS), idx(idx) + { + buildBody(&body); + buildHeader(&header); + } - void checkEvents() override - { - if ((update) && (luaState == INTERPRETER_RUNNING)) { - TRACE("rebuilding ScriptEditWindow..."); - rebuildBody(&body); - update = false; - } - // note: 'update' is set from Page::checkEvents() - Page::checkEvents(); - } + protected: + const uint8_t idx; + bool update = false; - void buildHeader(Window * window) - { - header.setTitle(STR_MENUCUSTOMSCRIPTS); - header.setTitle2(std::string("LUA") + std::to_string(idx + 1)); + void checkEvents() override + { + if ((update) && (luaState == INTERPRETER_RUNNING)) { + TRACE("rebuilding ScriptEditWindow..."); + rebuildBody(&body); + update = false; } + // note: 'update' is set from Page::checkEvents() + Page::checkEvents(); + } + + void buildHeader(Window* window) + { + header.setTitle(STR_MENUCUSTOMSCRIPTS); + header.setTitle2(std::string("LUA") + std::to_string(idx + 1)); + } + + void buildBody(Window* window, bool focusScript = false) + { + window->setFlexLayout(); + + FlexGridLayout grid(e_col_dsc, row_dsc, PAD_TINY); - void buildBody(FormWindow * window, bool focusScript = false) - { - auto form = new FormWindow(window, rect_t{}); - form->setFlexLayout(); - form->padAll(4); - - FlexGridLayout grid(e_col_dsc, row_dsc, 2); - - // the general pattern seems to be using capture-by-value for the closures: so need to copy the pointers, not the objects - ScriptData* const sd = &(g_model.scriptsData[idx]); - ScriptInputsOutputs* const sio = &(scriptInputsOutputs[idx]); - - // File - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SCRIPT, 0, COLOR_THEME_PRIMARY1); - new FileChoice( - line, rect_t{}, SCRIPTS_MIXES_PATH, SCRIPTS_EXT, - LEN_SCRIPT_FILENAME, - [=]() { return stringFromNtString(sd->file); }, - [=](std::string newValue) { - clearStruct(*sd); - clearStruct(*sio); - if (!newValue.empty()) { - copyToUnTerminated(sd->file, newValue); - } - storageDirty(EE_MODEL); - LUA_LOAD_MODEL_SCRIPT(idx); // async reload ... - update = true; - }, true); - - // Custom name - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); - new ModelTextEdit(line, rect_t{}, sd->name, sizeof(sd->name)); - - if (sio->inputsCount > 0) { - line = form->newLine(&grid); - new Subtitle(line, STR_INPUTS); - - for (int i = 0; i < sio->inputsCount; i++) { - line = form->newLine(&grid); - ScriptInput& si = sio->inputs[i]; - auto lbl = new StaticText(line, rect_t{}, si.name, 0, COLOR_THEME_PRIMARY1); - lbl->padLeft(10); - if (si.type == INPUT_TYPE_VALUE) { - (new NumberEdit(line, rect_t{}, si.min, si.max, - GET_SET_WITH_OFFSET(sd->inputs[i].value, si.def)))->setDefault(si.def); - } else { - new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_TELEM, - GET_SET_DEFAULT(sd->inputs[i].source)); + // the general pattern seems to be using capture-by-value for the closures: + // so need to copy the pointers, not the objects + ScriptData* const sd = &(g_model.scriptsData[idx]); + ScriptInputsOutputs* const sio = &(scriptInputsOutputs[idx]); + + // File + auto line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_SCRIPT, COLOR_THEME_PRIMARY1); + new FileChoice( + line, rect_t{}, SCRIPTS_MIXES_PATH, SCRIPTS_EXT, LEN_SCRIPT_FILENAME, + [=]() { return stringFromNtString(sd->file); }, + [=](std::string newValue) { + clearStruct(*sd); + clearStruct(*sio); + if (!newValue.empty()) { + copyToUnTerminated(sd->file, newValue); } + storageDirty(EE_MODEL); + LUA_LOAD_MODEL_SCRIPT(idx); // async reload ... + update = true; + }, + true); + + // Custom name + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); + new ModelTextEdit(line, rect_t{}, sd->name, sizeof(sd->name)); + + if (sio->inputsCount > 0) { + line = window->newLine(grid); + new Subtitle(line, STR_INPUTS); + + for (int i = 0; i < sio->inputsCount; i++) { + line = window->newLine(grid); + ScriptInput& si = sio->inputs[i]; + auto lbl = + new StaticText(line, rect_t{}, si.name, COLOR_THEME_PRIMARY1); + lbl->padLeft(10); + if (si.type == INPUT_TYPE_VALUE) { + (new NumberEdit(line, rect_t{}, si.min, si.max, + GET_SET_WITH_OFFSET(sd->inputs[i].value, si.def))) + ->setDefault(si.def); + } else { + new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_TELEM, + GET_SET_DEFAULT(sd->inputs[i].source)); } } + } - if (sio->outputsCount > 0) { - line = form->newLine(&grid); - new Subtitle(line, STR_OUTPUTS); - - for (int i = 0; i < sio->outputsCount; i++) { - line = form->newLine(&grid); - ScriptOutput* so = &(sio->outputs[i]); - auto lbl = new DynamicText(line, rect_t{}, [=]() { - char s[16]; - getSourceString(s, MIXSRC_FIRST_LUA + (idx * MAX_SCRIPT_OUTPUTS) + i); - return std::string(s, sizeof(s) - 1); - }, COLOR_THEME_PRIMARY1); - lbl->padLeft(10); - new DynamicNumber(line, rect_t{}, [=]() { return calcRESXto1000(so->value); }, COLOR_THEME_PRIMARY1); - } + if (sio->outputsCount > 0) { + line = window->newLine(grid); + new Subtitle(line, STR_OUTPUTS); + + for (int i = 0; i < sio->outputsCount; i++) { + line = window->newLine(grid); + ScriptOutput* so = &(sio->outputs[i]); + auto lbl = new DynamicText( + line, rect_t{}, + [=]() { + char s[16]; + getSourceString( + s, MIXSRC_FIRST_LUA + (idx * MAX_SCRIPT_OUTPUTS) + i); + return std::string(s, sizeof(s) - 1); + }, + COLOR_THEME_PRIMARY1); + lbl->padLeft(10); + new DynamicNumber( + line, rect_t{}, [=]() { return calcRESXto1000(so->value); }, + COLOR_THEME_PRIMARY1); } } - - void rebuildBody(FormWindow * window) - { - auto scroll_y = lv_obj_get_scroll_y(window->getLvObj()); - window->clear(); - buildBody(window); - lv_obj_scroll_to_y(window->getLvObj(), scroll_y, LV_ANIM_OFF); - } + } + + void rebuildBody(Window* window) + { + auto scroll_y = lv_obj_get_scroll_y(window->getLvObj()); + window->clear(); + buildBody(window); + lv_obj_scroll_to_y(window->getLvObj(), scroll_y, LV_ANIM_OFF); + } }; -class ScriptLineButton : public Button +class ScriptLineButton : public ListLineButton { public: ScriptLineButton(Window* parent, const rect_t& rect, const ScriptData& scriptData, - const ScriptInternalData* runtimeData, - uint8_t index) : - Button(parent, rect, nullptr, 0, 0, input_mix_line_create), - index(index), + const ScriptInternalData* runtimeData, uint8_t index) : + ListLineButton(parent, index), scriptData(scriptData), runtimeData(runtimeData) { #if LCD_H > LCD_W - padTop(5); + padTop(5); #endif padLeft(3); padRight(3); @@ -187,12 +193,13 @@ class ScriptLineButton : public Button lv_obj_set_style_pad_column(lvobj, 4, 0); lv_obj_update_layout(parent->getLvObj()); - if(lv_obj_is_visible(lvobj)) delayed_init(nullptr); + if (lv_obj_is_visible(lvobj)) delayed_init(nullptr); - lv_obj_add_event_cb(lvobj, ScriptLineButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); + lv_obj_add_event_cb(lvobj, ScriptLineButton::on_draw, + LV_EVENT_DRAW_MAIN_BEGIN, nullptr); } - static void on_draw(lv_event_t * e) + static void on_draw(lv_event_t* e) { lv_obj_t* target = lv_event_get_target(e); auto line = (ScriptLineButton*)lv_obj_get_user_data(target); @@ -203,37 +210,42 @@ class ScriptLineButton : public Button line->refresh(); } } - + void delayed_init(lv_event_t* e) { auto lbl = lv_label_create(lvobj); - lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_LEFT, 0); - lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1); + etx_obj_add_style(lbl, styles->text_align_left, LV_PART_MAIN); + lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_CENTER, + 0, 1); - lv_label_set_text(lbl, (std::string("LUA") + std::to_string(index + 1)).c_str()); + lv_label_set_text(lbl, + (std::string("LUA") + std::to_string(index + 1)).c_str()); if (runtimeData) { char s[20]; lbl = lv_label_create(lvobj); - lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_LEFT, 0); - lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); + etx_obj_add_style(lbl, styles->text_align_left, LV_PART_MAIN); + lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_CENTER, + 0, 1); strAppend(s, scriptData.name, LEN_SCRIPT_NAME); lv_label_set_text(lbl, s); lbl = lv_label_create(lvobj); - lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_LEFT, 0); - lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1); + etx_obj_add_style(lbl, styles->text_align_left, LV_PART_MAIN); + lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_CENTER, + 0, 1); strAppend(s, scriptData.file, LEN_SCRIPT_FILENAME); lv_label_set_text(lbl, s); lbl = lv_label_create(lvobj); - lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_LEFT, 0); - lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 3, 1, LV_GRID_ALIGN_CENTER, 0, 1); + etx_obj_add_style(lbl, styles->text_align_left, LV_PART_MAIN); + lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 3, 1, LV_GRID_ALIGN_CENTER, + 0, 1); - // TODO: runtimeData->instructions has no value + // TODO: runtimeData->instructions has no value switch (runtimeData->state) { case SCRIPT_SYNTAX_ERROR: lv_label_set_text(lbl, STR_SCRIPT_ERROR); @@ -252,50 +264,49 @@ class ScriptLineButton : public Button init = true; refresh(); + lv_obj_update_layout(lvobj); - if(e) { + if (e) { auto param = lv_event_get_param(e); lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param); } } - void refresh() - { - } + bool isActive() const override { return false; } + void refresh() override {} protected: bool init = false; - uint8_t index; - const ScriptData& scriptData; + const ScriptData& scriptData; const ScriptInternalData* runtimeData; }; #define CM_BUTTON_H 34 ModelMixerScriptsPage::ModelMixerScriptsPage() : - PageTab(STR_MENUCUSTOMSCRIPTS, ICON_MODEL_LUA_SCRIPTS) + PageTab(STR_MENUCUSTOMSCRIPTS, ICON_MODEL_LUA_SCRIPTS) { } -void ModelMixerScriptsPage::rebuild(FormWindow * window, int8_t focusIdx) +void ModelMixerScriptsPage::rebuild(Window* window, int8_t focusIdx) { - auto scroll_y = lv_obj_get_scroll_y(window->getLvObj()); + auto scroll_y = lv_obj_get_scroll_y(window->getLvObj()); window->clear(); build(window, focusIdx); lv_obj_scroll_to_y(window->getLvObj(), scroll_y, LV_ANIM_OFF); } -void ModelMixerScriptsPage::build(FormWindow * window, int8_t focusIdx) +void ModelMixerScriptsPage::build(Window* window, int8_t focusIdx) { - window->padAll(4); - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); + window->padAll(PAD_SMALL); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); int8_t scriptIdx = 0; for (int8_t idx = 0; idx < MAX_SCRIPTS; idx++) { - auto line = window->newLine(&grid); + auto line = window->newLine(grid); ScriptInternalData* runtimeData = nullptr; ScriptData* const sd = &(g_model.scriptsData[idx]); @@ -304,8 +315,10 @@ void ModelMixerScriptsPage::build(FormWindow * window, int8_t focusIdx) if (sd->file[0] != '\0') { runtimeData = &(scriptInternalData[scriptIdx++]); } - - Button* const button = new ScriptLineButton(line, rect_t{0, 0, window->width() - 12, CM_BUTTON_H}, *sd, runtimeData, idx); + + auto button = new ScriptLineButton( + line, rect_t{0, 0, window->width() - 12, CM_BUTTON_H}, *sd, runtimeData, + idx); button->setPressHandler([=]() -> uint8_t { Menu* const menu = new Menu(window); @@ -313,8 +326,8 @@ void ModelMixerScriptsPage::build(FormWindow * window, int8_t focusIdx) if (runtimeData != nullptr) { menu->addLine(STR_DELETE, [=]() { - clearStruct(*sd); - clearStruct(*sio); + clearStruct(*sd); + clearStruct(*sio); LUA_LOAD_MODEL_SCRIPTS(); storageDirty(EE_MODEL); rebuild(window, idx); @@ -326,10 +339,8 @@ void ModelMixerScriptsPage::build(FormWindow * window, int8_t focusIdx) } } -void ModelMixerScriptsPage::editLine(FormWindow * window, uint8_t idx) +void ModelMixerScriptsPage::editLine(Window* window, uint8_t idx) { - Window * editWindow = new ScriptEditWindow(idx); - editWindow->setCloseHandler([=]() { - rebuild(window, idx); - }); + Window* editWindow = new ScriptEditWindow(idx); + editWindow->setCloseHandler([=]() { rebuild(window, idx); }); } diff --git a/radio/src/gui/colorlcd/model_mixer_scripts.h b/radio/src/gui/colorlcd/model_mixer_scripts.h index 8486a193c71..775d32c8247 100644 --- a/radio/src/gui/colorlcd/model_mixer_scripts.h +++ b/radio/src/gui/colorlcd/model_mixer_scripts.h @@ -22,18 +22,19 @@ #pragma once #include "tabsgroup.h" +#include "opentx.h" -class ModelMixerScriptsPage: public PageTab { - public: - ModelMixerScriptsPage(); +class ModelMixerScriptsPage : public PageTab +{ + public: + ModelMixerScriptsPage(); - virtual void build(FormWindow * window) override - { - build(window, 0); - } + bool isVisible() const override { return modelCustomScriptsEnabled(); } - protected: - void build(FormWindow * window, int8_t focusIdx); - void rebuild(FormWindow * window, int8_t focusIdx); - void editLine(FormWindow * window, uint8_t idx); + virtual void build(Window* window) override { build(window, 0); } + + protected: + void build(Window* window, int8_t focusIdx); + void rebuild(Window* window, int8_t focusIdx); + void editLine(Window* window, uint8_t idx); }; diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index 156661d8bf9..0168220d608 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -40,22 +40,6 @@ #define PASTE_BEFORE -2 #define PASTE_AFTER -1 -static const uint8_t _mask_mplex_add[] = { -#include "mask_mplex_add.lbm" -}; -STATIC_LZ4_BITMAP(mask_mplex_add); - -static const uint8_t _mask_mplex_multi[] = { -#include "mask_mplex_multi.lbm" -}; -STATIC_LZ4_BITMAP(mask_mplex_multi); - -static const uint8_t _mask_mplex_replace[] = { -#include "mask_mplex_replace.lbm" -}; -STATIC_LZ4_BITMAP(mask_mplex_replace); - - class MixLineButton : public InputMixButton { public: @@ -84,21 +68,21 @@ static void mix_draw_mplex(lv_event_t* e) if (dsc->part != LV_PART_MAIN) return; MixData* mix = mixAddress(btn->getIndex()); - const uint8_t* mask_map = nullptr; + const MaskBitmap* mask_map = nullptr; if (mix->mltpx == MLTPX_ADD) { - mask_map = mask_mplex_add; + mask_map = getBuiltinIcon(ICON_MPLEX_ADD); } else if (mix->mltpx == MLTPX_MUL) { - mask_map = mask_mplex_multi; + mask_map = getBuiltinIcon(ICON_MPLEX_MULTIPLY); } else if (mix->mltpx == MLTPX_REPL) { - mask_map = mask_mplex_replace; + mask_map = getBuiltinIcon(ICON_MPLEX_REPLACE); } else { return; } lv_area_t coords; lv_coord_t area_h = lv_area_get_height(&obj->coords); - lv_coord_t mask_w = MASK_WIDTH(mask_map); - lv_coord_t mask_h = MASK_HEIGHT(mask_map); + lv_coord_t mask_w = mask_map->width; + lv_coord_t mask_h = mask_map->height; lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); coords.x1 = obj->coords.x1 - mask_w - pad_left; @@ -114,7 +98,7 @@ static void mix_draw_mplex(lv_event_t* e) lv_draw_mask_map_param_t m; int16_t mask_id; - lv_draw_mask_map_init(&m, &coords, MASK_DATA(mask_map)); + lv_draw_mask_map_init(&m, &coords, mask_map->data); mask_id = lv_draw_mask_add(&m, NULL); // draw masked symbol @@ -201,7 +185,7 @@ InputMixGroup* ModelMixesPage::getGroupByIndex(uint8_t index) return getGroupBySrc(MIXSRC_FIRST_CH + ch); } -InputMixGroup* ModelMixesPage::createGroup(FormWindow* form, mixsrc_t src) +InputMixGroup* ModelMixesPage::createGroup(Window* form, mixsrc_t src) { auto group = new InputMixGroup(form, src); if (showMonitors) group->enableMixerMonitor(src - MIXSRC_FIRST_CH); @@ -387,24 +371,24 @@ void ModelMixesPage::pasteMixAfter(uint8_t dst_idx) pasteMix(dst_idx + 1, channel); } -void ModelMixesPage::build(FormWindow * window) +void ModelMixesPage::build(Window * window) { scroll_win = window->getParent(); window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 3); - form = new FormWindow(window, rect_t{}); + form = new Window(window, rect_t{}); form->setFlexLayout(LV_FLEX_FLOW_COLUMN, 3); - auto box = new FormWindow(window, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); + auto box = new Window(window, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL); box->padLeft(lv_dpx(8)); auto box_obj = box->getLvObj(); - lv_obj_set_width(box_obj, lv_pct(100)); lv_obj_set_style_flex_cross_place(box_obj, LV_FLEX_ALIGN_CENTER, 0); - new StaticText(box, rect_t{}, STR_SHOW_MIXER_MONITORS, 0, COLOR_THEME_PRIMARY1); + new StaticText(box, rect_t{}, STR_SHOW_MIXER_MONITORS, COLOR_THEME_PRIMARY1); new ToggleSwitch( box, rect_t{}, [=]() { return showMonitors; }, [=](uint8_t val) { enableMonitors(val); }); diff --git a/radio/src/gui/colorlcd/model_mixes.h b/radio/src/gui/colorlcd/model_mixes.h index 5f2c6376bd8..2c649d4c513 100644 --- a/radio/src/gui/colorlcd/model_mixes.h +++ b/radio/src/gui/colorlcd/model_mixes.h @@ -23,7 +23,6 @@ #include "model_inputs.h" - class ModelMixesPage : public ModelInputsPage { bool showMonitors = false; @@ -32,14 +31,14 @@ class ModelMixesPage : public ModelInputsPage public: ModelMixesPage(); - void build(FormWindow* window) override; + void build(Window* window) override; protected: InputMixGroup* getGroupByIndex(uint8_t index) override; void addLineButton(uint8_t index) override; void addLineButton(mixsrc_t src, uint8_t index) override; - InputMixGroup* createGroup(FormWindow* form, mixsrc_t src) override; + InputMixGroup* createGroup(Window* form, mixsrc_t src) override; InputMixButton* createLineButton(InputMixGroup* group, uint8_t index) override; diff --git a/radio/src/gui/colorlcd/model_outputs.cpp b/radio/src/gui/colorlcd/model_outputs.cpp index e40cd37d1ec..b8c684d105a 100644 --- a/radio/src/gui/colorlcd/model_outputs.cpp +++ b/radio/src/gui/colorlcd/model_outputs.cpp @@ -20,50 +20,43 @@ */ #include "model_outputs.h" -#include "output_edit.h" -#include "list_line_button.h" -#include "channel_bar.h" +#include "channel_bar.h" +#include "list_line_button.h" #include "opentx.h" +#include "output_edit.h" +#include "themes/etx_lv_theme.h" #define SET_DIRTY() storageDirty(EE_MODEL) -static const uint8_t _mask_textline_curve[] = { -#include "mask_textline_curve.lbm" -}; -STATIC_LZ4_BITMAP(mask_textline_curve); +#define ETX_STATE_MINMAX_BOLD LV_STATE_USER_1 +#define ETX_STATE_NAME_FONT_SMALL LV_STATE_USER_1 -#define CH_BAR_WIDTH 92 +#define CH_BAR_WIDTH 92 #define CH_BAR_HEIGHT 14 -#if LCD_W > LCD_H // Landscape +#if LCD_W > LCD_H // Landscape -#define CH_LINE_H 35 +#define CH_LINE_H 32 -#define CH_BAR_COL 7 +#define CH_BAR_COL 7 #define CH_BAR_COLSPAN 1 static const lv_coord_t col_dsc[] = { - 80, 50, 54, 44, 60, 18, 18, LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST -}; + 80, 50, 54, 44, 60, 18, 18, LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; -#else // Portrait +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; +#else // Portrait #define CH_LINE_H 50 -#define CH_BAR_COL 3 +#define CH_BAR_COL 3 #define CH_BAR_COLSPAN 3 static const lv_coord_t col_dsc[] = { - 80, 50, 60, 18, 18, LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST -}; + 80, 50, 60, 18, 18, LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_CONTENT, +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; #endif @@ -77,13 +70,10 @@ class OutputLineButton : public ListLineButton lv_obj_t* max = nullptr; lv_obj_t* offset = nullptr; lv_obj_t* center = nullptr; - lv_obj_t* curve = nullptr; + StaticIcon* curve = nullptr; OutputChannelBar* bar = nullptr; - static lv_img_dsc_t curveIcon; - static void loadCurveIcon(); - - static void on_draw(lv_event_t * e) + static void on_draw(lv_event_t* e) { lv_obj_t* target = lv_event_get_target(e); auto line = (OutputLineButton*)lv_obj_get_user_data(target); @@ -94,20 +84,20 @@ class OutputLineButton : public ListLineButton line->refresh(); } } - + void delayed_init(lv_event_t* e) { uint8_t col = 1, row = 0; min = lv_label_create(lvobj); - lv_obj_set_style_text_align(min, LV_TEXT_ALIGN_RIGHT, 0); - lv_obj_set_style_text_font(min, getFont(FONT(BOLD)), LV_STATE_USER_1); + etx_obj_add_style(min, styles->text_align_right, LV_PART_MAIN); + etx_font(min, FONT_BOLD_INDEX, ETX_STATE_MINMAX_BOLD); lv_obj_set_grid_cell(min, LV_GRID_ALIGN_END, col++, 1, LV_GRID_ALIGN_START, row, 1); max = lv_label_create(lvobj); - lv_obj_set_style_text_align(max, LV_TEXT_ALIGN_RIGHT, 0); - lv_obj_set_style_text_font(max, getFont(FONT(BOLD)), LV_STATE_USER_1); + etx_obj_add_style(max, styles->text_align_right, LV_PART_MAIN); + etx_font(max, FONT_BOLD_INDEX, ETX_STATE_MINMAX_BOLD); lv_obj_set_grid_cell(max, LV_GRID_ALIGN_END, col++, 1, LV_GRID_ALIGN_START, row, 1); @@ -130,37 +120,36 @@ class OutputLineButton : public ListLineButton lv_obj_set_grid_cell(revert, LV_GRID_ALIGN_START, col++, 1, LV_GRID_ALIGN_START, row, 1); - curve = lv_img_create(lvobj); - loadCurveIcon(); - lv_img_set_src(curve, &curveIcon); - lv_obj_set_style_img_recolor(curve, makeLvColor(COLOR_THEME_SECONDARY1), 0); - lv_obj_set_style_img_recolor_opa(curve, LV_OPA_COVER, 0); - lv_obj_set_grid_cell(curve, LV_GRID_ALIGN_START, col++, 1, + curve = new StaticIcon(this, 0, 0, getBuiltinIcon(ICON_TEXTLINE_CURVE), + COLOR_THEME_SECONDARY1); + lv_obj_set_grid_cell(curve->getLvObj(), LV_GRID_ALIGN_START, col++, 1, LV_GRID_ALIGN_START, row, 1); - bar = new OutputChannelBar(this, rect_t{}, index); - bar->setWidth(CH_BAR_WIDTH); - bar->setHeight(CH_BAR_HEIGHT); - bar->setDrawLimits(false); + bar = new OutputChannelBar(this, rect_t{0, 0, CH_BAR_WIDTH, CH_BAR_HEIGHT}, + index, false, false); lv_obj_set_grid_cell(bar->getLvObj(), LV_GRID_ALIGN_END, CH_BAR_COL, CH_BAR_COLSPAN, LV_GRID_ALIGN_CENTER, 0, 1); init = true; refresh(); + lv_obj_update_layout(lvobj); - if(e) { + if (e) { auto param = lv_event_get_param(e); lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param); } } - + public: OutputLineButton(Window* parent, uint8_t channel) : ListLineButton(parent, channel) { setHeight(CH_LINE_H); +#if LCD_W > LCD_H + padTop(4); +#endif lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); lv_obj_set_grid_dsc_array(lvobj, col_dsc, row_dsc); @@ -171,29 +160,29 @@ class OutputLineButton : public ListLineButton LV_GRID_ALIGN_CENTER, 0, 2); #else - lv_obj_set_style_text_font(source, getFont(FONT(XS)), 0); lv_obj_set_grid_cell(source, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1); + etx_font(source, FONT_XS_INDEX, ETX_STATE_NAME_FONT_SMALL); + lv_obj_set_style_pad_top(source, -5, ETX_STATE_NAME_FONT_SMALL); + lv_obj_set_style_text_line_space(source, -3, ETX_STATE_NAME_FONT_SMALL); #endif - lv_obj_add_event_cb(lvobj, OutputLineButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); + lv_obj_add_event_cb(lvobj, OutputLineButton::on_draw, + LV_EVENT_DRAW_MAIN_BEGIN, nullptr); } void refresh() override { if (!init) return; - + const LimitData* output = limitAddress(index); - if(g_model.limitData[index].name[0] != '\0') - { -#if LCD_W > LCD_H - lv_obj_set_style_text_line_space(source, -3, LV_PART_MAIN); - lv_obj_set_style_pad_top(source, -7, 0); - lv_obj_set_style_pad_bottom(source, -7, 0); -#endif - lv_label_set_text_fmt(source, "%s\n" TR_CH "%u", getSourceString(MIXSRC_FIRST_CH + index), index + 1); + if (g_model.limitData[index].name[0] != '\0') { + lv_obj_add_state(source, ETX_STATE_NAME_FONT_SMALL); + lv_label_set_text_fmt(source, "%s\n" TR_CH "%u", + getSourceString(MIXSRC_FIRST_CH + index), + index + 1); } else { - lv_obj_set_style_text_font(source, getFont(FONT(STD)), 0); + lv_obj_clear_state(source, ETX_STATE_NAME_FONT_SMALL); lv_label_set_text(source, getSourceString(MIXSRC_FIRST_CH + index)); } if (output->revert) { @@ -218,11 +207,7 @@ class OutputLineButton : public ListLineButton lv_label_set_text_fmt(center, "%d%s", PPM_CENTER + output->ppmCenter, output->symetrical ? " =" : STR_CHAR_DELTA); - if (output->curve) { - lv_obj_clear_flag(curve, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(curve, LV_OBJ_FLAG_HIDDEN); - } + curve->show(output->curve); } protected: @@ -243,90 +228,65 @@ class OutputLineButton : public ListLineButton int chanZero = output->ppmCenter; if (value < chanZero - 5) { - lv_obj_add_state(min, LV_STATE_USER_1); + lv_obj_add_state(min, ETX_STATE_MINMAX_BOLD); } else { - lv_obj_clear_state(min, LV_STATE_USER_1); + lv_obj_clear_state(min, ETX_STATE_MINMAX_BOLD); } if (value > chanZero + 5) { - lv_obj_add_state(max, LV_STATE_USER_1); + lv_obj_add_state(max, ETX_STATE_MINMAX_BOLD); } else { - lv_obj_clear_state(max, LV_STATE_USER_1); + lv_obj_clear_state(max, ETX_STATE_MINMAX_BOLD); } } } }; -lv_img_dsc_t OutputLineButton::curveIcon = { - .header = - { - .cf = LV_IMG_CF_ALPHA_8BIT, - .always_zero = 0, - .reserved = 0, - .w = 0, - .h = 0, - }, - .data_size = 0, - .data = nullptr, -}; - -void OutputLineButton::loadCurveIcon() -{ - if (curveIcon.data) return; - - auto mask = (const uint8_t*)mask_textline_curve; - auto mask_hdr = (const uint16_t*)mask; - mask += 4; - - auto w = mask_hdr[0]; - auto h = mask_hdr[1]; - curveIcon.header.w = w; - curveIcon.header.h = h; - curveIcon.data_size = w * h; - curveIcon.data = mask; -} - ModelOutputsPage::ModelOutputsPage() : - PageTab(STR_MENULIMITS, ICON_MODEL_OUTPUTS) + PageTab(STR_MENULIMITS, ICON_MODEL_OUTPUTS, PAD_TINY) { } -void ModelOutputsPage::build(FormWindow *window) +void ModelOutputsPage::build(Window* window) { - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 3); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); lv_obj_set_style_flex_cross_place(window->getLvObj(), LV_FLEX_ALIGN_START, 0); - auto box = new FormWindow(window, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8)); - box->padRow(4); + auto box = new Window(window, rect_t{}); + box->padAll(PAD_ZERO); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_ZERO); lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); - new TextButton(box, rect_t{}, STR_ADD_ALL_TRIMS_TO_SUBTRIMS, [=]() { + auto box2 = new Window(box, rect_t{}); + box2->padAll(PAD_TINY); + box2->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); + new TextButton(box2, rect_t{}, STR_ADD_ALL_TRIMS_TO_SUBTRIMS, [=]() { moveTrimsToOffsets(); - window->invalidate(); return 0; }); - auto box2 = new FormWindow(box, rect_t{}); - box2->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - box2->setWidth(LV_SIZE_CONTENT); + box2 = new Window(box, rect_t{}); + box2->padAll(PAD_TINY); + box2->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); lv_obj_set_style_flex_cross_place(box2->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); - new StaticText(box2, rect_t{}, STR_ELIMITS, 0, COLOR_THEME_PRIMARY1); + new StaticText(box2, rect_t{}, STR_ELIMITS, COLOR_THEME_PRIMARY1); new ToggleSwitch(box2, rect_t{}, GET_SET_DEFAULT(g_model.extendedLimits)); - for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) { + box = new Window(window, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); + lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); + for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) { // Channel settings - auto btn = new OutputLineButton(window, ch); + auto btn = new OutputLineButton(box, ch); LimitData* output = limitAddress(ch); btn->setPressHandler([=]() -> uint8_t { - Menu *menu = new Menu(window); - menu->addLine(STR_EDIT, [=]() { - editOutput(ch, btn); - }); + Menu* menu = new Menu(window); + menu->addLine(STR_EDIT, [=]() { editOutput(ch, btn); }); menu->addLine(STR_RESET, [=]() { output->min = 0; output->max = 0; diff --git a/radio/src/gui/colorlcd/model_outputs.h b/radio/src/gui/colorlcd/model_outputs.h index 8c5baa1fbb3..6c8738b19c1 100644 --- a/radio/src/gui/colorlcd/model_outputs.h +++ b/radio/src/gui/colorlcd/model_outputs.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _MODEL_OUTPUTS_H_ -#define _MODEL_OUTPUTS_H_ +#pragma once #include "tabsgroup.h" @@ -30,10 +29,8 @@ class ModelOutputsPage : public PageTab { public: ModelOutputsPage(); - void build(FormWindow* window) override; + void build(Window* window) override; protected: void editOutput(uint8_t channel, OutputLineButton* btn); }; - -#endif // _MODEL_OUTPUTS_H_ diff --git a/radio/src/gui/colorlcd/model_select.cpp b/radio/src/gui/colorlcd/model_select.cpp index c9d562f48e6..eb757cfc6c3 100644 --- a/radio/src/gui/colorlcd/model_select.cpp +++ b/radio/src/gui/colorlcd/model_select.cpp @@ -28,32 +28,28 @@ #include "model_templates.h" #include "opentx.h" #include "standalone_lua.h" +#include "themes/etx_lv_theme.h" #include "view_channels.h" inline tmr10ms_t getTicks() { return g_tmr10ms; } -constexpr coord_t MODEL_CELL_PADDING = 6; +constexpr coord_t MODEL_CELL_PADDING = 4; constexpr coord_t MODEL_SELECT_CELL_HEIGHT = 92; -constexpr int BUTTONS_HEIGHT = 32; +constexpr int BUTTONS_HEIGHT = 36; constexpr int MODEL_CELLS_PER_LINE = 2; #if LCD_W > LCD_H // Landscape constexpr int LABELS_WIDTH = 132; -constexpr int LAY_MARGIN = 5; constexpr coord_t MODEL_SELECT_CELL_WIDTH = - (LCD_W - LABELS_WIDTH - (MODEL_CELLS_PER_LINE + 1) * MODEL_CELL_PADDING) / - MODEL_CELLS_PER_LINE; + (LCD_W - 16 - LABELS_WIDTH) / MODEL_CELLS_PER_LINE; constexpr int LABELS_ROW = 0; constexpr int MODELS_COL = 1; constexpr int MODELS_ROW = 0; constexpr int MODELS_ROW_CNT = 2; constexpr int BUTTONS_ROW = 1; #else // Portrait -constexpr int LAY_MARGIN = 8; -constexpr int LABELS_HEIGHT = 140; -constexpr coord_t MODEL_SELECT_CELL_WIDTH = - (LCD_W - LAY_MARGIN - (MODEL_CELLS_PER_LINE + 1) * MODEL_CELL_PADDING) / - MODEL_CELLS_PER_LINE; +constexpr int LABELS_HEIGHT = 152; +constexpr coord_t MODEL_SELECT_CELL_WIDTH = (LCD_W - 16) / MODEL_CELLS_PER_LINE; constexpr int LABELS_ROW = 1; constexpr int MODELS_COL = 0; constexpr int MODELS_ROW = 0; @@ -64,68 +60,48 @@ constexpr int BUTTONS_ROW = 2; class ModelButton : public Button { public: - ModelButton(FormWindow *parent, const rect_t &rect, ModelCell *modelCell, + ModelButton(Window *parent, const rect_t &rect, ModelCell *modelCell, std::function setSelected) : - Button(parent, rect, nullptr, 0, 0, etx_button_create), + Button(parent, rect), modelCell(modelCell), m_setSelected(std::move(setSelected)) { - padAll(0); + padAll(PAD_ZERO); lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); setWidth(MODEL_SELECT_CELL_WIDTH); setHeight(MODEL_SELECT_CELL_HEIGHT); - LcdFlags bg_color = modelCell == modelslist.getCurrentModel() - ? COLOR_THEME_ACTIVE - : COLOR_THEME_PRIMARY2; + int bg_col_idx = modelCell == modelslist.getCurrentModel() + ? COLOR_THEME_ACTIVE_INDEX + : COLOR_THEME_PRIMARY2_INDEX; coord_t w = width() - 8; coord_t h = height() - 8; GET_FILENAME(filename, BITMAPS_PATH, modelCell->modelBitmap, ""); - const BitmapBuffer *bitmap = BitmapBuffer::loadBitmap(filename); - - if (bitmap) { - buffer = new BitmapBuffer(BMP_RGB565, w, h); - if (buffer) { - buffer->clear(bg_color); - buffer->drawScaledBitmap(bitmap, 0, 0, w, h); - delete bitmap; - - lv_obj_t *bm = lv_canvas_create(lvobj); - lv_obj_center(bm); - lv_canvas_set_buffer(bm, buffer->getData(), buffer->width(), - buffer->height(), LV_IMG_CF_TRUE_COLOR); - } - } + auto bitmap = new StaticImage(this, {0, 0, w, h}, filename); + bitmap->show(bitmap->hasImage()); - if (!buffer) { + if (!bitmap->hasImage()) { std::string errorMsg = "("; errorMsg += STR_NO_PICTURE; errorMsg += ")"; - new StaticText(this, {2, h / 2, w, 17}, errorMsg, 0, + new StaticText(this, {2, h / 2, w, 17}, errorMsg, CENTERED | COLOR_THEME_SECONDARY1 | FONT(XS)); } auto name = - new StaticText(this, {2, 2, width() - 8, 17}, modelCell->modelName, 0, + new StaticText(this, {2, 2, width() - 8, 17}, modelCell->modelName, CENTERED | COLOR_THEME_SECONDARY1); name->setHeight(17); - name->setBackgroudOpacity(LV_OPA_80); - name->setBackgroundColor(bg_color); + etx_bg_color(name->getLvObj(), (LcdColorIndex)bg_col_idx); + etx_obj_add_style(name->getLvObj(), styles->bg_opacity_75, LV_PART_MAIN); name->padTop(-3); check(modelCell == modelslist.getCurrentModel()); } - ~ModelButton() - { - if (buffer) { - delete buffer; - } - } - const char *modelFilename() { return modelCell->modelFilename; } ModelCell *getModelCell() const { return modelCell; } @@ -141,32 +117,28 @@ class ModelButton : public Button protected: bool loaded = false; ModelCell *modelCell; - BitmapBuffer *buffer = nullptr; std::function m_setSelected = nullptr; void onClicked() override { setFocused(); - Button::onClicked(); + ButtonBase::onClicked(); if (m_setSelected) m_setSelected(); } }; //----------------------------------------------------------------------------- -class ModelsPageBody : public FormWindow +class ModelsPageBody : public Window { public: - ModelsPageBody(Window *parent, const rect_t &rect) : FormWindow(parent, rect) + ModelsPageBody(Window *parent, const rect_t &rect) : Window(parent, rect) { - padAll(0); -#if LCD_W > LCD_H - padRight(LAY_MARGIN); -#else - padLeft(LAY_MARGIN); -#endif - setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, MODEL_CELL_PADDING); + padAll(PAD_TINY); + padLeft(PAD_MEDIUM); + // padRight(PAD_MEDIUM); padRow(MODEL_CELL_PADDING); + setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, MODEL_CELL_PADDING); } void update() @@ -415,56 +387,64 @@ class ModelsPageBody : public FormWindow //----------------------------------------------------------------------------- -class LabelDialog : public Dialog +class LabelDialog : public ModalWindow { public: LabelDialog(Window *parent, char *label, - std::function _saveHandler = nullptr) : - Dialog(parent, STR_ENTER_LABEL, rect_t{}), - saveHandler(std::move(_saveHandler)) + std::function _saveHandler = nullptr) : + ModalWindow(parent, false), saveHandler(std::move(_saveHandler)) { strncpy(this->label, label, LABEL_LENGTH); this->label[LABEL_LENGTH] = '\0'; - auto form = &content->form; - form->padRow(lv_dpx(8)); - - auto form_obj = form->getLvObj(); - lv_obj_set_style_flex_cross_place(form_obj, LV_FLEX_ALIGN_CENTER, 0); - - new TextEdit(form, rect_t{}, label, LABEL_LENGTH); - - auto box = new FormWindow(form, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW); - - auto box_obj = box->getLvObj(); - lv_obj_set_style_flex_main_place(box_obj, LV_FLEX_ALIGN_SPACE_EVENLY, 0); - - auto btn = new TextButton(box, rect_t{}, STR_SAVE, [=]() { - if (saveHandler != nullptr) saveHandler(label); + auto form = new Window(this, rect_t{}); + form->padAll(PAD_ZERO); + form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO, LCD_W * 0.8, + LV_SIZE_CONTENT); + etx_solid_bg(form->getLvObj()); + lv_obj_center(form->getLvObj()); + + auto hdr = new StaticText(form, {0, 0, LV_PCT(100), 0}, STR_ENTER_LABEL, + COLOR_THEME_PRIMARY2); + etx_solid_bg(hdr->getLvObj(), COLOR_THEME_SECONDARY1_INDEX); + hdr->padAll(PAD_MEDIUM); + + auto box = new Window(form, rect_t{}); + box->padAll(PAD_MEDIUM); + box->setFlexLayout(LV_FLEX_FLOW_ROW, 40, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_flex_align(box->getLvObj(), LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_BETWEEN); + + auto edit = new TextEdit(box, rect_t{0, 0, LV_PCT(100), 0}, this->label, + LABEL_LENGTH); + edit->padAll(PAD_MEDIUM); + + box = new Window(form, rect_t{}); + box->padAll(PAD_MEDIUM); + box->setFlexLayout(LV_FLEX_FLOW_ROW, 40, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_flex_align(box->getLvObj(), LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_BETWEEN); + + new TextButton(box, rect_t{0, 0, 96, 0}, STR_CANCEL, [=]() { deleteLater(); return 0; }); - btn->setWidth(100); - btn = new TextButton(box, rect_t{}, STR_CANCEL, [=]() { + new TextButton(box, rect_t{0, 0, 96, 0}, STR_SAVE, [=]() { + if (saveHandler != nullptr) saveHandler(this->label); deleteLater(); return 0; }); - btn->setWidth(100); - - content->setWidth(LCD_W * 0.8); - content->updateSize(); } protected: - std::function saveHandler; + std::function saveHandler; char label[LABEL_LENGTH + 1]; }; //----------------------------------------------------------------------------- -ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL) +ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL, PAD_ZERO) { buildHead(&header); buildBody(&body); @@ -620,7 +600,7 @@ void ModelLabelsWindow::buildHead(PageHeader *hdr) return 0; }); - btn->padAll(lv_dpx(4)); + btn->padAll(PAD_SMALL); // button placement hdr->padRight(lv_dpx(8)); @@ -638,13 +618,10 @@ static const lv_coord_t row_dsc[] = {LV_GRID_FR(1), LABELS_HEIGHT, BUTTONS_HEIGHT, LV_GRID_TEMPLATE_LAST}; #endif -void ModelLabelsWindow::buildBody(FormWindow *window) +void ModelLabelsWindow::buildBody(Window *window) { - window->padAll(LAY_MARGIN); - window->padRow(LAY_MARGIN); - window->padColumn(LAY_MARGIN); - window->padLeft(0); - window->padRight(0); + window->padTop(6); + window->padBottom(6); lv_obj_set_grid_dsc_array(window->getLvObj(), col_dsc, row_dsc); @@ -657,10 +634,12 @@ void ModelLabelsWindow::buildBody(FormWindow *window) // Labels auto box = new Window(window, rect_t{}); - box->padAll(0); - box->padLeft(LAY_MARGIN); + box->padAll(PAD_ZERO); + box->padLeft(6); #if LCD_H > LCD_W - box->padRight(LAY_MARGIN); + box->padRight(6); + box->padTop(6); + box->padBottom(6); #endif lv_obj_set_grid_cell(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_STRETCH, LABELS_ROW, 1); @@ -668,18 +647,18 @@ void ModelLabelsWindow::buildBody(FormWindow *window) new ListBox(box, rect_t{0, 0, LV_PCT(100), LV_PCT(100)}, getLabels()); auto lbl_obj = lblselector->getLvObj(); - // Sort Buttons + // Sort Button box = new Window(window, rect_t{}); - box->padAll(0); - box->padLeft(LAY_MARGIN); - box->padRight(LAY_MARGIN); + box->padAll(PAD_TINY); + box->padLeft(6); + box->padRight(6); lv_obj_set_grid_cell(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_STRETCH, BUTTONS_ROW, 1); - auto sortOrder = new Choice( + new Choice( box, {}, STR_SORT_ORDERS, NAME_ASC, DATE_DES, [=]() { return mdlselector->getSortOrder(); }, - [=](int newValue) { mdlselector->setSortOrder((ModelsSortBy)newValue); }); - sortOrder->setMenuTitle(STR_SORT_MODELS_BY); + [=](int newValue) { mdlselector->setSortOrder((ModelsSortBy)newValue); }, + STR_SORT_MODELS_BY); lv_obj_update_layout(mdl_obj); lblselector->setColumnWidth(0, lv_obj_get_content_width(lbl_obj)); @@ -687,8 +666,8 @@ void ModelLabelsWindow::buildBody(FormWindow *window) lblselector->setMultiSelect(true); lblselector->setSelected(modelslabels.filteredLabels()); updateFilteredLabels(modelslabels.filteredLabels(), false); - lv_obj_set_scrollbar_mode(lbl_obj, LV_SCROLLBAR_MODE_AUTO); - lv_obj_set_scrollbar_mode(mdl_obj, LV_SCROLLBAR_MODE_AUTO); + etx_scrollbar(lbl_obj); + etx_scrollbar(mdl_obj); lblselector->setMultiSelectHandler([=](std::set selected, std::set oldselection) { diff --git a/radio/src/gui/colorlcd/model_select.h b/radio/src/gui/colorlcd/model_select.h index 0ec1ffc01f5..50ffaed8b88 100644 --- a/radio/src/gui/colorlcd/model_select.h +++ b/radio/src/gui/colorlcd/model_select.h @@ -25,6 +25,7 @@ #include "listbox.h" #include "storage/modelslist.h" #include "tabsgroup.h" +#include "page.h" class ModelsPageBody; @@ -51,7 +52,7 @@ class ModelLabelsWindow : public Page void newModel(); void newLabel(); void buildHead(PageHeader *window); - void buildBody(FormWindow *window); + void buildBody(Window *window); void updateFilteredLabels(std::set selected, bool setdirty = true); void labelRefreshRequest(); void setTitle(); diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 2a60bb73255..47ff536e803 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -21,17 +21,18 @@ #include "model_setup.h" -#include "opentx.h" -#include "libopenui.h" #include "button_matrix.h" - -#include "storage/modelslist.h" -#include "trainer_setup.h" -#include "module_setup.h" +#include "filechoice.h" +#include "libopenui.h" +#include "preflight_checks.h" +#include "throttle_params.h" #include "timer_setup.h" +#include "trainer_setup.h" #include "trims_setup.h" -#include "throttle_params.h" -#include "preflight_checks.h" +#include "module_setup.h" +#include "opentx.h" +#include "storage/modelslist.h" +#include "themes/etx_lv_theme.h" #if defined(USBJ_EX) #include "model_usbjoystick.h" @@ -39,10 +40,10 @@ #include -#define SET_DIRTY() storageDirty(EE_MODEL) +#define SET_DIRTY() storageDirty(EE_MODEL) ModelSetupPage::ModelSetupPage() : - PageTab(STR_MENU_MODEL_SETUP, ICON_MODEL_SETUP) + PageTab(STR_MENU_MODEL_SETUP, ICON_MODEL_SETUP) { } @@ -58,7 +59,7 @@ static void onModelNameChanged() struct ModelNameEdit : public ModelTextEdit { ModelNameEdit(Window *parent, const rect_t &rect) : ModelTextEdit(parent, rect, g_model.header.name, - sizeof(g_model.header.name), 0) + sizeof(g_model.header.name)) { setChangeHandler(onModelNameChanged); } @@ -82,42 +83,41 @@ static void setModelBitmap(std::string newValue) struct ModelBitmapEdit : public FileChoice { ModelBitmapEdit(Window *parent, const rect_t &rect) : - FileChoice(parent, rect, BITMAPS_PATH, BITMAPS_EXT, - LEN_BITMAP_NAME, getModelBitmap, setModelBitmap) + FileChoice(parent, rect, BITMAPS_PATH, BITMAPS_EXT, LEN_BITMAP_NAME, + getModelBitmap, setModelBitmap) { } }; class SubScreenButton : public TextButton { - public: - SubScreenButton(Window* parent, const char* text, - std::function pressHandler, - std::function checkActive = nullptr) : - TextButton(parent, rect_t{}, text, [=]() -> uint8_t { - pressHandler(); - return 0; - }), + public: + SubScreenButton(Window *parent, const char *text, + std::function pressHandler, + std::function checkActive = nullptr) : + TextButton(parent, rect_t{}, text, + [=]() -> uint8_t { + pressHandler(); + return 0; + }), m_isActive(std::move(checkActive)) - { - // Room for two lines of text - setHeight(62); - setWidth((LCD_W - 30) / 3); + { + // Room for two lines of text + setHeight(62); + setWidth((LCD_W - 30) / 3); - lv_obj_set_width(label, lv_pct(100)); - lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); - lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); - } + lv_obj_set_width(label, lv_pct(100)); + etx_obj_add_style(label, styles->text_align_center, LV_PART_MAIN); + lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); - void checkEvents() override - { - check(isActive()); - } + setCheckHandler([=]() { check(isActive()); }); + check(isActive()); + } - protected: - std::function m_isActive = nullptr; + protected: + std::function m_isActive = nullptr; - virtual bool isActive() { return m_isActive ? m_isActive() : false; } + virtual bool isActive() { return m_isActive ? m_isActive() : false; } }; static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), @@ -127,214 +127,254 @@ static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, class ModelViewOptions : public Page { + public: + class OptChoice : Window + { public: - class OptChoice : FormWindow + OptChoice(Window *parent, const char *const values[], int vmin, int vmax, + std::function _getValue, + std::function _setValue, bool globalState) : + Window(parent, rect_t{}), + m_getValue(std::move(_getValue)), + m_setValue(std::move(_setValue)) { - public: - OptChoice(Window* parent, const char *const values[], int vmin, int vmax, - std::function _getValue, - std::function _setValue, - bool globalState) : - FormWindow(parent, rect_t{}), - m_getValue(std::move(_getValue)), - m_setValue(std::move(_setValue)) - { - setFlexLayout(LV_FLEX_FLOW_ROW, 4); - lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); - - new Choice(this, rect_t{}, values, vmin, vmax, - m_getValue, - [=](int newValue) { - m_setValue(newValue); - setState(); - }); - m_lbl = new StaticText(this, rect_t{}, STR_ADCFILTERVALUES[globalState ? 1: 2], 0, COLOR_THEME_SECONDARY1); - setState(); - } + padAll(PAD_TINY); + setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL); + lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_SPACE_AROUND); + + new Choice(this, rect_t{}, values, vmin, vmax, m_getValue, + [=](int newValue) { + m_setValue(newValue); + setState(); + }); + m_lbl = new StaticText(this, rect_t{}, + STR_ADCFILTERVALUES[globalState ? 1 : 2], COLOR_THEME_SECONDARY1); + setState(); + } - protected: - StaticText* m_lbl; - std::function m_getValue; - std::function m_setValue; - - void setState() - { - if (m_getValue() == 0) { - lv_obj_clear_flag(m_lbl->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(m_lbl->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - } - }; + protected: + StaticText *m_lbl; + std::function m_getValue; + std::function m_setValue; - ModelViewOptions() : Page(ICON_MODEL_SETUP) + void setState() { - header.setTitle(STR_MENU_MODEL_SETUP); - header.setTitle2(STR_ENABLED_FEATURES); + m_lbl->show(m_getValue() == 0); + } + }; + + FormLine* optLine(FlexGridLayout& grid) + { + auto line = body.newLine(grid); + line->padAll(PAD_ZERO); + line->padLeft(10); + return line; + } - body.padAll(8); + ModelViewOptions() : Page(ICON_MODEL_SETUP) + { + header.setTitle(STR_MENU_MODEL_SETUP); + header.setTitle2(STR_ENABLED_FEATURES); - auto form = new FormWindow(&body, rect_t{}); - form->setFlexLayout(); - form->padAll(4); + body.padAll(PAD_TINY); + body.setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); - FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); + FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_RADIO_MENU_TABS, 0, COLOR_THEME_PRIMARY1); + auto line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_RADIO_MENU_TABS, + COLOR_THEME_PRIMARY1); - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_THEME_EDITOR, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.radioThemesDisabled), g_eeGeneral.radioThemesDisabled); + line = optLine(grid); + new StaticText(line, rect_t{}, STR_THEME_EDITOR, COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.radioThemesDisabled), + g_eeGeneral.radioThemesDisabled); - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENUSPECIALFUNCS, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.radioGFDisabled), g_eeGeneral.radioGFDisabled); + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENUSPECIALFUNCS, + COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.radioGFDisabled), + g_eeGeneral.radioGFDisabled); - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENUTRAINER, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.radioTrainerDisabled), g_eeGeneral.radioTrainerDisabled); + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENUTRAINER, COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.radioTrainerDisabled), + g_eeGeneral.radioTrainerDisabled); - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_MODEL_MENU_TABS, 0, COLOR_THEME_PRIMARY1); + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_MODEL_MENU_TABS, + COLOR_THEME_PRIMARY1); #if defined(HELI) - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENUHELISETUP, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.modelHeliDisabled), g_eeGeneral.modelHeliDisabled); + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENUHELISETUP, COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.modelHeliDisabled), + g_eeGeneral.modelHeliDisabled); #endif #if defined(FLIGHT_MODES) - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENUFLIGHTMODES, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.modelFMDisabled), g_eeGeneral.modelFMDisabled); + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENUFLIGHTMODES, + COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.modelFMDisabled), + g_eeGeneral.modelFMDisabled); #endif #if defined(GVARS) - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENU_GLOBAL_VARS, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.modelGVDisabled), g_eeGeneral.modelGVDisabled); + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENU_GLOBAL_VARS, + COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.modelGVDisabled), + g_eeGeneral.modelGVDisabled); #endif - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENUCURVES, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.modelCurvesDisabled), g_eeGeneral.modelCurvesDisabled); - - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENULOGICALSWITCHES, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.modelLSDisabled), g_eeGeneral.modelLSDisabled); - - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENUCUSTOMFUNC, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.modelSFDisabled), g_eeGeneral.modelSFDisabled); + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENUCURVES, COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.modelCurvesDisabled), + g_eeGeneral.modelCurvesDisabled); + + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENULOGICALSWITCHES, + COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.modelLSDisabled), + g_eeGeneral.modelLSDisabled); + + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENUCUSTOMFUNC, COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.modelSFDisabled), + g_eeGeneral.modelSFDisabled); #if defined(LUA_MODEL_SCRIPTS) - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENUCUSTOMSCRIPTS, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.modelCustomScriptsDisabled), g_eeGeneral.modelCustomScriptsDisabled); + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENUCUSTOMSCRIPTS, + COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.modelCustomScriptsDisabled), + g_eeGeneral.modelCustomScriptsDisabled); #endif - line = form->newLine(&grid); - line->padLeft(10); - new StaticText(line, rect_t{}, STR_MENUTELEMETRY, 0, COLOR_THEME_PRIMARY1); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.modelTelemetryDisabled), g_eeGeneral.modelTelemetryDisabled); - } + line = optLine(grid); + new StaticText(line, rect_t{}, STR_MENUTELEMETRY, COLOR_THEME_PRIMARY1); + new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.modelTelemetryDisabled), + g_eeGeneral.modelTelemetryDisabled); + } }; -void ModelSetupPage::build(FormWindow * window) +void ModelSetupPage::build(Window *window) { window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); - FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); + FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); // Model name - auto line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_MODELNAME, 0, COLOR_THEME_PRIMARY1); + auto line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_MODELNAME, COLOR_THEME_PRIMARY1); new ModelNameEdit(line, rect_t{}); // Model labels - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_LABELS, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_LABELS, COLOR_THEME_PRIMARY1); auto curmod = modelslist.getCurrentModel(); - labelTextButton = - new TextButton(line, rect_t{}, modelslabels.getBulletLabelString(curmod ,STR_UNLABELEDMODEL), [=] () { - Menu *menu = new Menu(window, true); - menu->setTitle(STR_LABELS); - for (auto &label: modelslabels.getLabels()) { - menu->addLineBuffered(label, - [=] () { - if (!modelslabels.isLabelSelected(label, curmod)) - modelslabels.addLabelToModel(label, curmod); - else - modelslabels.removeLabelFromModel(label, curmod); - labelTextButton->setText(modelslabels.getBulletLabelString(curmod,STR_UNLABELEDMODEL)); - strncpy(g_model.header.labels, ModelMap::toCSV(modelslabels.getLabelsByModel(curmod)).c_str(),sizeof(g_model.header.labels)); - g_model.header.labels[sizeof(g_model.header.labels)-1] = '\0'; - SET_DIRTY(); - }, [=] () { - return modelslabels.isLabelSelected(label, curmod); - }); - } - menu->updateLines(); - return 0; - }); + labelTextButton = new TextButton( + line, rect_t{}, + modelslabels.getBulletLabelString(curmod, STR_UNLABELEDMODEL), [=]() { + Menu *menu = new Menu(window, true); + menu->setTitle(STR_LABELS); + for (auto &label : modelslabels.getLabels()) { + menu->addLineBuffered( + label, + [=]() { + if (!modelslabels.isLabelSelected(label, curmod)) + modelslabels.addLabelToModel(label, curmod); + else + modelslabels.removeLabelFromModel(label, curmod); + labelTextButton->setText(modelslabels.getBulletLabelString( + curmod, STR_UNLABELEDMODEL)); + strncpy(g_model.header.labels, + ModelMap::toCSV(modelslabels.getLabelsByModel(curmod)) + .c_str(), + sizeof(g_model.header.labels)); + g_model.header.labels[sizeof(g_model.header.labels) - 1] = '\0'; + SET_DIRTY(); + }, + [=]() { return modelslabels.isLabelSelected(label, curmod); }); + } + menu->updateLines(); + return 0; + }); // Bitmap - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_BITMAP, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_BITMAP, COLOR_THEME_PRIMARY1); // TODO: show bitmap thumbnail instead? new ModelBitmapEdit(line, rect_t{}); // Model ADC jitter filter - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_JITTER_FILTER, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_JITTER_FILTER, COLOR_THEME_PRIMARY1); new Choice(line, rect_t{}, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.jitterFilter)); - static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; + static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; - FlexGridLayout grid2(col_dsc, row_dsc, 4); + FlexGridLayout grid2(col_dsc, row_dsc); - line = window->newLine(&grid2); + line = window->newLine(grid2); line->padTop(8); // Modules - new SubScreenButton(line, STR_INTERNALRF, []() { new ModulePage(INTERNAL_MODULE); }, []() { return g_model.moduleData[INTERNAL_MODULE].type > 0; }); - new SubScreenButton(line, STR_EXTERNALRF, []() { new ModulePage(EXTERNAL_MODULE); }, []() { return g_model.moduleData[EXTERNAL_MODULE].type > 0; }); - new SubScreenButton(line, STR_TRAINER, []() { new TrainerPage(); }, []() { return g_model.trainerData.mode > 0; }); - - line = window->newLine(&grid2); + new SubScreenButton( + line, STR_INTERNALRF, []() { new ModulePage(INTERNAL_MODULE); }, + []() { return g_model.moduleData[INTERNAL_MODULE].type > 0; }); + new SubScreenButton( + line, STR_EXTERNALRF, []() { new ModulePage(EXTERNAL_MODULE); }, + []() { return g_model.moduleData[EXTERNAL_MODULE].type > 0; }); + new SubScreenButton( + line, STR_TRAINER, []() { new TrainerPage(); }, + []() { return g_model.trainerData.mode > 0; }); + + line = window->newLine(grid2); line->padTop(2); // Timer buttons - new SubScreenButton(line, TR_TIMER "1", []() { new TimerWindow(0); }, []() { return g_model.timers[0].mode > 0; }); - new SubScreenButton(line, TR_TIMER "2", []() { new TimerWindow(1); }, []() { return g_model.timers[1].mode > 0; }); - new SubScreenButton(line, TR_TIMER "3", []() { new TimerWindow(2); }, []() { return g_model.timers[2].mode > 0; }); - - line = window->newLine(&grid2); + new SubScreenButton( + line, TR_TIMER "1", []() { new TimerWindow(0); }, + []() { return g_model.timers[0].mode > 0; }); + new SubScreenButton( + line, TR_TIMER "2", []() { new TimerWindow(1); }, + []() { return g_model.timers[1].mode > 0; }); + new SubScreenButton( + line, TR_TIMER "3", []() { new TimerWindow(2); }, + []() { return g_model.timers[2].mode > 0; }); + + line = window->newLine(grid2); line->padTop(2); new SubScreenButton(line, STR_PREFLIGHT, []() { new PreflightChecks(); }); new SubScreenButton(line, STR_TRIMS, []() { new TrimsSetup(); }); new SubScreenButton(line, STR_THROTTLE_LABEL, []() { new ThrottleParams(); }); - line = window->newLine(&grid2); + line = window->newLine(grid2); line->padTop(2); - new SubScreenButton(line, STR_ENABLED_FEATURES, []() { new ModelViewOptions(); }); + new SubScreenButton(line, STR_ENABLED_FEATURES, + []() { new ModelViewOptions(); }); #if defined(USBJ_EX) - new SubScreenButton(line, STR_USBJOYSTICK_LABEL, []() { new ModelUSBJoystickPage(); }); + new SubScreenButton(line, STR_USBJOYSTICK_LABEL, + []() { new ModelUSBJoystickPage(); }); #endif } diff --git a/radio/src/gui/colorlcd/model_setup.h b/radio/src/gui/colorlcd/model_setup.h index 993a68d7991..6e7ad4e8589 100644 --- a/radio/src/gui/colorlcd/model_setup.h +++ b/radio/src/gui/colorlcd/model_setup.h @@ -25,7 +25,7 @@ class ModelSetupPage: public PageTab { public: ModelSetupPage(); - void build(FormWindow * window) override; + void build(Window * window) override; private: TextButton *labelTextButton = nullptr; }; diff --git a/radio/src/gui/colorlcd/model_telemetry.cpp b/radio/src/gui/colorlcd/model_telemetry.cpp index 28aec32c8c3..41320255ce8 100644 --- a/radio/src/gui/colorlcd/model_telemetry.cpp +++ b/radio/src/gui/colorlcd/model_telemetry.cpp @@ -21,17 +21,25 @@ #include "model_telemetry.h" -#include "opentx.h" +#include "fullscreen_dialog.h" #include "libopenui.h" +#include "list_line_button.h" +#include "opentx.h" +#include "page.h" +#include "sourcechoice.h" +#include "themes/etx_lv_theme.h" #define SET_DIRTY() storageDirty(EE_MODEL) +#define ETX_STATE_VALUE_SMALL_FONT LV_STATE_USER_1 +#define ETX_STATE_VALUE_STALE_WARN LV_STATE_USER_1 + std::string getSensorCustomValue(uint8_t sensor, int32_t value, LcdFlags flags); #if (LCD_H > LCD_W) || defined(TRANSLATIONS_CZ) -#define TWOCOLBUTTONS 1 +#define TWOCOLBUTTONS 1 #else -#define TWOCOLBUTTONS 0 +#define TWOCOLBUTTONS 0 #endif // Overview grid variants @@ -39,22 +47,22 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(14), LV_GRID_FR(6), LV_GRID_TEMPLATE_LAST}; #if TWOCOLBUTTONS static const lv_coord_t col_dsc4[] = {LV_GRID_FR(1), LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; + LV_GRID_TEMPLATE_LAST}; #else -static const lv_coord_t col_dsc4[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t col_dsc4[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; #endif -static const lv_coord_t col_dsc5[] = {LV_GRID_FR(5), LV_GRID_FR(4), LV_GRID_FR(4), LV_GRID_FR(4), - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t col_dsc5[] = {LV_GRID_FR(5), LV_GRID_FR(4), + LV_GRID_FR(4), LV_GRID_FR(4), + LV_GRID_TEMPLATE_LAST}; // Edit grid variants static const lv_coord_t e_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t e_col_dsc2[] = {LV_GRID_FR(4), LV_GRID_FR(3), LV_GRID_FR(3), - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t e_col_dsc2[] = {LV_GRID_FR(4), LV_GRID_FR(3), + LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; #define BTN_H 32 #define NUM_W 36 @@ -62,289 +70,353 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, class TSStyle { - public: - TSStyle() {} - - void init() - { - if (!styleInitDone) - { - styleInitDone = true; - - lv_style_init(&tsContStyle); - lv_style_set_pad_all(&tsContStyle, 0); - lv_style_set_width(&tsContStyle, NUM_W); - lv_style_set_height(&tsContStyle, BTN_H-4); - - lv_style_init(&tsNumStyle); - lv_style_set_text_font(&tsNumStyle, getFont(FONT(STD))); - lv_style_set_text_align(&tsNumStyle, LV_TEXT_ALIGN_CENTER); - lv_style_set_width(&tsNumStyle, NUM_W); - - lv_style_init(&tsNameStyle); - lv_style_set_text_font(&tsNameStyle, getFont(FONT(STD))); - lv_style_set_text_align(&tsNameStyle, LV_TEXT_ALIGN_LEFT); - lv_style_set_width(&tsNameStyle, NAME_W); - - lv_style_init(&tsFreshStyle); - lv_style_set_width(&tsFreshStyle, 8); - lv_style_set_height(&tsFreshStyle, 8); - lv_style_set_img_recolor_opa(&tsFreshStyle, LV_OPA_COVER); - - lv_style_init(&tsValueStyle); - lv_style_set_text_font(&tsValueStyle, getFont(FONT(STD))); - lv_style_set_text_align(&tsValueStyle, LV_TEXT_ALIGN_LEFT); - lv_style_set_width(&tsValueStyle, LV_SIZE_CONTENT); - - lv_style_init(&tsIdStyle); - lv_style_set_text_font(&tsIdStyle, getFont(FONT(XXS))); - lv_style_set_text_align(&tsIdStyle, LV_TEXT_ALIGN_CENTER); - lv_style_set_width(&tsIdStyle, NUM_W); - lv_style_set_height(&tsIdStyle, 11); - } + public: + TSStyle() {} + + void init() + { + if (!styleInitDone) { + styleInitDone = true; - // Always update colors in case theme changes - lv_style_set_text_color(&tsNumStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&tsNameStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&tsFreshStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_img_recolor(&tsFreshStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&tsValueStyle, makeLvColor(COLOR_THEME_SECONDARY1)); - lv_style_set_text_color(&tsIdStyle, makeLvColor(COLOR_THEME_SECONDARY1)); + lv_style_init(&tsFreshStyle); + lv_style_set_img_recolor_opa(&tsFreshStyle, LV_OPA_COVER); } - lv_obj_t* newGroup(lv_obj_t* parent) - { - auto obj = lv_obj_create(parent); - lv_obj_add_style(obj, &tsContStyle, LV_PART_MAIN); - lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); - lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); + // Always update colors in case theme changes + lv_style_set_img_recolor(&tsFreshStyle, + makeLvColor(COLOR_THEME_SECONDARY1)); + } - return obj; - } + lv_obj_t* newNum(lv_obj_t* parent, uint8_t index); + lv_obj_t* newId(lv_obj_t* parent, const char* id); + lv_obj_t* newName(lv_obj_t* parent, const char* name); + lv_obj_t* newValue(lv_obj_t* parent); - lv_obj_t* newNum(lv_obj_t* parent, uint8_t index) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &tsNumStyle, LV_PART_MAIN); - lv_label_set_text(obj, std::to_string(index+1).c_str()); + lv_style_t tsFreshStyle; - return obj; - } + private: + bool styleInitDone; +}; - lv_obj_t* newId(lv_obj_t* parent, const char* id) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &tsIdStyle, LV_PART_MAIN); - lv_label_set_text(obj, id); +static TSStyle tsStyle; - return obj; - } +static void ts_group_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_SPACE_AROUND); +} + +static const lv_obj_class_t ts_group_class = { + .base_class = &lv_obj_class, + .constructor_cb = ts_group_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = NUM_W, + .height_def = BTN_H - 4, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_obj_t), +}; - lv_obj_t* newName(lv_obj_t* parent, const char* name) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &tsNameStyle, LV_PART_MAIN); - lv_label_set_text(obj, name); +static const lv_obj_class_t ts_fresh_cont_class = { + .base_class = &lv_obj_class, + .constructor_cb = nullptr, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = 8, + .height_def = 8, + .editable = LV_OBJ_CLASS_EDITABLE_FALSE, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_obj_t), +}; - return obj; - } +static void ts_num_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); + etx_font(obj, FONT_XS_INDEX, ETX_STATE_VALUE_SMALL_FONT); +} - lv_obj_t* newFreshCont(lv_obj_t* parent) - { - auto obj = lv_obj_create(parent); - lv_obj_add_style(obj, &tsFreshStyle, LV_PART_MAIN); +static const lv_obj_class_t ts_num_class = { + .base_class = &lv_label_class, + .constructor_cb = ts_num_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = NUM_W, + .height_def = 0, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; - return obj; - } +lv_obj_t* TSStyle::newNum(lv_obj_t* parent, uint8_t index) +{ + auto obj = etx_create(&ts_num_class, parent); + lv_label_set_text(obj, std::to_string(index + 1).c_str()); - lv_obj_t* newFreshIcon(lv_obj_t* parent) - { - auto obj = lv_canvas_create(parent); - lv_obj_add_style(obj, &tsFreshStyle, LV_PART_MAIN); + return obj; +} - return obj; - } +static void ts_id_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); + etx_font(obj, FONT_XXS_INDEX); +} - lv_obj_t* newValue(lv_obj_t* parent) - { - auto obj = lv_label_create(parent); - lv_obj_add_style(obj, &tsValueStyle, LV_PART_MAIN); - lv_label_set_text(obj, ""); +static const lv_obj_class_t ts_id_class = { + .base_class = &lv_label_class, + .constructor_cb = ts_id_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = NUM_W, + .height_def = 11, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; - return obj; - } +lv_obj_t* TSStyle::newId(lv_obj_t* parent, const char* id) +{ + auto obj = etx_create(&ts_id_class, parent); + lv_label_set_text(obj, id); - private: - lv_style_t tsContStyle; - lv_style_t tsNumStyle; - lv_style_t tsNameStyle; - lv_style_t tsValueStyle; - lv_style_t tsIdStyle; - lv_style_t tsFreshStyle; - bool styleInitDone; + return obj; +} + +static void ts_name_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); +} + +static const lv_obj_class_t ts_name_class = { + .base_class = &lv_label_class, + .constructor_cb = ts_name_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = NAME_W, + .height_def = 0, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), }; -static TSStyle tsStyle; +lv_obj_t* TSStyle::newName(lv_obj_t* parent, const char* name) +{ + auto obj = etx_create(&ts_name_class, parent); + lv_label_set_text(obj, name); -static uint8_t const freshBitmap[] = { - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + return obj; +} + +static void ts_value_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); + etx_txt_color(obj, COLOR_THEME_WARNING_INDEX, ETX_STATE_VALUE_STALE_WARN); +} + +static const lv_obj_class_t ts_value_class = { + .base_class = &lv_label_class, + .constructor_cb = ts_value_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LV_SIZE_CONTENT, + .height_def = 0, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), }; -class SensorButton : public Button { - public: - SensorButton(Window * parent, const rect_t &rect, uint8_t index) : - Button(parent, rect, nullptr, 0, 0, input_mix_line_create), - index(index) - { - padTop(0); - padBottom(0); - padLeft(3); - padRight(3); - setHeight(BTN_H); - lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); - lv_obj_set_style_pad_all(lvobj, 0, 0); - lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); - - check(isActive()); - - lv_obj_add_event_cb(lvobj, SensorButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); - } +lv_obj_t* TSStyle::newValue(lv_obj_t* parent) +{ + auto obj = etx_create(&ts_value_class, parent); + lv_label_set_text(obj, ""); - protected: - bool init = false; - bool showId = false; - lv_obj_t* numLabel = nullptr; - lv_obj_t* idLabel = nullptr; - lv_obj_t* valLabel = nullptr; - lv_obj_t* fresh = nullptr; - uint32_t lastRefresh = 0; - uint8_t index; - - static void on_draw(lv_event_t * e) - { - lv_obj_t* target = lv_event_get_target(e); - auto line = (SensorButton*)lv_obj_get_user_data(target); - if (line) { - if (!line->init) - line->delayed_init(e); - else - line->refresh(); - } - } - - bool isActive() const - { - return telemetryItems[index].isAvailable(); - } + return obj; +} - void setNumIdState() - { - showId = g_model.showInstanceIds; - if (showId) { - lv_obj_clear_flag(idLabel, LV_OBJ_FLAG_HIDDEN); - lv_obj_set_style_text_font(numLabel, getFont(FONT(XS)), 0); - lv_obj_set_height(numLabel, 14); - } else { - lv_obj_add_flag(idLabel, LV_OBJ_FLAG_HIDDEN); - lv_obj_set_style_text_font(numLabel, getFont(FONT(STD)), 0); - lv_obj_set_height(numLabel, 22); - } +static void ts_fresh_icon_constructor(const lv_obj_class_t* class_p, + lv_obj_t* obj) +{ + static uint8_t const freshBitmap[] = { + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + }; + + etx_obj_add_style(obj, tsStyle.tsFreshStyle, LV_PART_MAIN); + lv_canvas_set_buffer(obj, (void*)freshBitmap, 8, 8, LV_IMG_CF_ALPHA_8BIT); + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); +} + +static const lv_obj_class_t ts_fresh_icon_class = { + .base_class = &lv_canvas_class, + .constructor_cb = ts_fresh_icon_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = 8, + .height_def = 8, + .editable = LV_OBJ_CLASS_EDITABLE_FALSE, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_canvas_t), +}; + +class SensorButton : public ListLineButton +{ + public: + SensorButton(Window* parent, const rect_t& rect, uint8_t index) : + ListLineButton(parent, index) + { + padAll(PAD_ZERO); + padColumn(PAD_SMALL); + setHeight(BTN_H); + lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); + lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_SPACE_AROUND); + + check(isActive()); + + lv_obj_add_event_cb(lvobj, SensorButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, + nullptr); + } + + protected: + bool init = false; + bool showId = false; + lv_obj_t* numLabel = nullptr; + lv_obj_t* idLabel = nullptr; + lv_obj_t* valLabel = nullptr; + lv_obj_t* fresh = nullptr; + uint32_t lastRefresh = 0; + + static void on_draw(lv_event_t* e) + { + lv_obj_t* target = lv_event_get_target(e); + auto line = (SensorButton*)lv_obj_get_user_data(target); + if (line) { + if (!line->init) + line->delayed_init(e); + else + line->refresh(); } + } + + bool isActive() const override { return telemetryItems[index].isAvailable(); } - void checkEvents() override - { - Button::checkEvents(); - check(isActive()); - refresh(); + void setNumIdState() + { + showId = g_model.showInstanceIds; + if (showId) { + lv_obj_clear_flag(idLabel, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_state(numLabel, ETX_STATE_VALUE_SMALL_FONT); + lv_obj_set_height(numLabel, 14); + } else { + lv_obj_add_flag(idLabel, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_state(numLabel, ETX_STATE_VALUE_SMALL_FONT); + lv_obj_set_height(numLabel, 22); } + } - void delayed_init(lv_event_t* e) - { - char s[20]; + void checkEvents() override + { + ListLineButton::checkEvents(); + refresh(); + } - auto box = tsStyle.newGroup(lvobj); + void delayed_init(lv_event_t* e) + { + char s[20]; - numLabel = tsStyle.newNum(box, index); + auto box = etx_create(&ts_group_class, lvobj); - TelemetrySensor * sensor = & g_model.telemetrySensors[index]; - if (sensor->type == TELEM_TYPE_CUSTOM) { - sprintf(s, "ID: %d", sensor->instance); - } else { - s[0] = 0; - } + numLabel = tsStyle.newNum(box, index); - idLabel = tsStyle.newId(box, s); + TelemetrySensor* sensor = &g_model.telemetrySensors[index]; + if (sensor->type == TELEM_TYPE_CUSTOM) { + sprintf(s, "ID: %d", sensor->instance); + } else { + s[0] = 0; + } - setNumIdState(); + idLabel = tsStyle.newId(box, s); - strAppend(s, g_model.telemetrySensors[index].label, TELEM_LABEL_LEN); - tsStyle.newName(lvobj, s); + setNumIdState(); - box = tsStyle.newFreshCont(lvobj); - fresh = tsStyle.newFreshIcon(box); - lv_canvas_set_buffer(fresh, (void*)freshBitmap, 8, 8, LV_IMG_CF_ALPHA_8BIT); - lv_obj_add_flag(fresh, LV_OBJ_FLAG_HIDDEN); + strAppend(s, g_model.telemetrySensors[index].label, TELEM_LABEL_LEN); + tsStyle.newName(lvobj, s); - valLabel = tsStyle.newValue(lvobj); + // Reserve space so layout does not change when icon hidden + box = etx_create(&ts_fresh_cont_class, lvobj); + fresh = etx_create(&ts_fresh_icon_class, box); - init = true; - refresh(); - lv_obj_update_layout(lvobj); + valLabel = tsStyle.newValue(lvobj); - if(e) { - auto param = lv_event_get_param(e); - lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param); - } - } + init = true; + refresh(); - void refresh() - { - if (!init) return; + lv_obj_update_layout(lvobj); - if (showId != g_model.showInstanceIds) - setNumIdState(); + if (e) { + auto param = lv_event_get_param(e); + lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param); + } + } - // Draw a 'fresh' marker - if (telemetryItems[index].isFresh()) - lv_obj_clear_flag(fresh, LV_OBJ_FLAG_HIDDEN); - else - lv_obj_add_flag(fresh, LV_OBJ_FLAG_HIDDEN); + void refresh() override + { + if (!init) return; + + if (showId != g_model.showInstanceIds) setNumIdState(); - uint32_t now = RTOS_GET_MS(); - TelemetryItem & telemetryItem = telemetryItems[index]; + // Draw a 'fresh' marker + if (telemetryItems[index].isFresh()) + lv_obj_clear_flag(fresh, LV_OBJ_FLAG_HIDDEN); + else + lv_obj_add_flag(fresh, LV_OBJ_FLAG_HIDDEN); - // Update value - if ((now - lastRefresh >= 200) || telemetryItem.isFresh()) { - // update at least every 200ms - lastRefresh = now; + uint32_t now = RTOS_GET_MS(); + TelemetryItem& telemetryItem = telemetryItems[index]; - std::string s; - LcdFlags color = COLOR_THEME_SECONDARY1; + // Update value + if ((now - lastRefresh >= 200) || telemetryItem.isFresh()) { + // update at least every 200ms + lastRefresh = now; - if (telemetryItem.isAvailable()) { - color = telemetryItem.isOld() ? COLOR_THEME_WARNING : color; - s = getSensorCustomValue(index, getValue(MIXSRC_FIRST_TELEM + 3 * index), LEFT); - } else { - s = "---"; - } + std::string s; + bool isOld = false; - lv_obj_set_style_text_color(valLabel, makeLvColor(color), 0); - lv_label_set_text(valLabel, s.c_str()); + if (telemetryItem.isAvailable()) { + isOld = telemetryItem.isOld(); + s = getSensorCustomValue( + index, getValue(MIXSRC_FIRST_TELEM + 3 * index), LEFT); + } else { + s = "---"; } + + if (isOld) + lv_obj_add_state(valLabel, ETX_STATE_VALUE_STALE_WARN); + else + lv_obj_clear_state(valLabel, ETX_STATE_VALUE_STALE_WARN); + + lv_label_set_text(valLabel, s.c_str()); } + } }; class SensorSourceChoice : public SourceChoice { public: - SensorSourceChoice(Window *window, const rect_t &rect, uint8_t *source, + SensorSourceChoice(Window* window, const rect_t& rect, uint8_t* source, IsValueAvailable isValueAvailable) : SourceChoice(window, rect, MIXSRC_NONE, MIXSRC_LAST_TELEM, GET_DEFAULT(*source ? MIXSRC_FIRST_TELEM + 3 * (*source - 1) @@ -364,382 +436,418 @@ class SensorSourceChoice : public SourceChoice } }; -class SensorEditWindow : public Page { - public: - explicit SensorEditWindow(uint8_t index) : - Page(ICON_MODEL_TELEMETRY), - index(index) - { - buildHeader(&header); - buildBody(&body); - } +class SensorEditWindow : public Page +{ + public: + explicit SensorEditWindow(uint8_t index) : + Page(ICON_MODEL_TELEMETRY, PAD_SMALL), index(index) + { + buildHeader(&header); + buildBody(&body); + } - protected: - uint8_t index; - uint32_t lastRefresh = 0; - StaticText * headerValue = nullptr; - - enum ParamTypes { - P_FORMULA = 0, - P_ID, - P_UNIT, - P_PREC, - P_CELLSENSOR, - P_GPSSENSOR, - P_CURRENTSENSOR, - P_CONSUMPTIONSOURCE, - P_CALC0, - P_BLADES, - P_RATIO, - P_CELLINDEX, - P_ALTSENSOR, - P_CALC1, - P_MULT, - P_OFFSET, - P_CALC2, - P_CALC3, - P_AUTOOFFSET, - P_ONLYPOS, - P_FILTER, - P_PERSISTENT, - P_COUNT, - }; - - FormWindow::Line* paramLines[P_COUNT] = {}; - - void buildHeader(Window * window) - { - std::string title2 = STR_SENSOR + std::to_string(index + 1) + " = " + STR_NA; - header.setTitle(STR_MENUTELEMETRY); - - headerValue = header.setTitle2(title2); - - lv_obj_set_style_text_color(headerValue->getLvObj(), makeLvColor(COLOR_THEME_WARNING), LV_STATE_USER_1); - } + protected: + uint8_t index; + uint32_t lastRefresh = 0; + StaticText* headerValue = nullptr; + + enum ParamTypes { + P_FORMULA = 0, + P_ID, + P_UNIT, + P_PREC, + P_CELLSENSOR, + P_GPSSENSOR, + P_CURRENTSENSOR, + P_CONSUMPTIONSOURCE, + P_CALC0, + P_BLADES, + P_RATIO, + P_CELLINDEX, + P_ALTSENSOR, + P_CALC1, + P_MULT, + P_OFFSET, + P_CALC2, + P_CALC3, + P_AUTOOFFSET, + P_ONLYPOS, + P_FILTER, + P_PERSISTENT, + P_COUNT, + }; + + FormLine* paramLines[P_COUNT] = {}; + + void buildHeader(Window* window) + { + std::string title2 = + STR_SENSOR + std::to_string(index + 1) + " = " + STR_NA; + header.setTitle(STR_MENUTELEMETRY); - void checkEvents() override - { - uint32_t now = RTOS_GET_MS(); - TelemetryItem & telemetryItem = telemetryItems[index]; - - if ((now - lastRefresh >= 200) || telemetryItem.isFresh()) { - // update at least every 200ms - lastRefresh = now; - - lv_obj_clear_state(headerValue->getLvObj(), LV_STATE_USER_1); - - if (telemetryItem.isAvailable()) { - if (telemetryItem.isOld()) - lv_obj_add_state(headerValue->getLvObj(), LV_STATE_USER_1); - std::string title2 = - STR_SENSOR + std::to_string(index + 1) + " = " + - getSensorCustomValue( - index, getValue(MIXSRC_FIRST_TELEM + 3 * index), LEFT); - headerValue->setText(title2); - } else { - headerValue->setText(STR_SENSOR + std::to_string(index + 1) + " = " + - STR_NA); - } + headerValue = header.setTitle2(title2); + + etx_txt_color(headerValue->getLvObj(), COLOR_THEME_WARNING_INDEX, + ETX_STATE_VALUE_STALE_WARN); + } + + void checkEvents() override + { + uint32_t now = RTOS_GET_MS(); + TelemetryItem& telemetryItem = telemetryItems[index]; + + if ((now - lastRefresh >= 200) || telemetryItem.isFresh()) { + // update at least every 200ms + lastRefresh = now; + + lv_obj_clear_state(headerValue->getLvObj(), ETX_STATE_VALUE_STALE_WARN); + + if (telemetryItem.isAvailable()) { + if (telemetryItem.isOld()) + lv_obj_add_state(headerValue->getLvObj(), ETX_STATE_VALUE_STALE_WARN); + std::string title2 = + STR_SENSOR + std::to_string(index + 1) + " = " + + getSensorCustomValue( + index, getValue(MIXSRC_FIRST_TELEM + 3 * index), LEFT); + headerValue->setText(title2); + } else { + headerValue->setText(STR_SENSOR + std::to_string(index + 1) + " = " + + STR_NA); } } + } - void updateSensorParameters() - { - TelemetrySensor * sensor = &g_model.telemetrySensors[index]; + void updateSensorParameters() + { + TelemetrySensor* sensor = &g_model.telemetrySensors[index]; - for (int i = P_FORMULA; i < P_COUNT; i += 1) { - lv_obj_add_flag(paramLines[i]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + for (int i = P_FORMULA; i < P_COUNT; i += 1) { + paramLines[i]->hide(); + } - if (sensor->type == TELEM_TYPE_CALCULATED) { - // Formula - lv_obj_clear_flag(paramLines[P_FORMULA]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else { - lv_obj_clear_flag(paramLines[P_ID]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + if (sensor->type == TELEM_TYPE_CALCULATED) { + // Formula + paramLines[P_FORMULA]->show(); + } else { + paramLines[P_ID]->show(); + } - // Unit - if ((sensor->type == TELEM_TYPE_CALCULATED && (sensor->formula == TELEM_FORMULA_DIST)) || sensor->isConfigurable()) { - lv_obj_clear_flag(paramLines[P_UNIT]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + // Unit + if ((sensor->type == TELEM_TYPE_CALCULATED && + (sensor->formula == TELEM_FORMULA_DIST)) || + sensor->isConfigurable()) { + paramLines[P_UNIT]->show(); + } - // Precision - if (sensor->isPrecConfigurable() && sensor->unit != UNIT_FAHRENHEIT) { - lv_obj_clear_flag(paramLines[P_PREC]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + // Precision + if (sensor->isPrecConfigurable() && sensor->unit != UNIT_FAHRENHEIT) { + paramLines[P_PREC]->show(); + } - // Params - if (sensor->unit < UNIT_FIRST_VIRTUAL) { - if (sensor->type == TELEM_TYPE_CALCULATED) { - if (sensor->formula == TELEM_FORMULA_CELL) { - lv_obj_clear_flag(paramLines[P_CELLSENSOR]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else if (sensor->formula == TELEM_FORMULA_DIST) { - lv_obj_clear_flag(paramLines[P_GPSSENSOR]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else if (sensor->formula == TELEM_FORMULA_CONSUMPTION) { - lv_obj_clear_flag(paramLines[P_CURRENTSENSOR]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else if (sensor->formula == TELEM_FORMULA_TOTALIZE) { - lv_obj_clear_flag(paramLines[P_CONSUMPTIONSOURCE]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else { - lv_obj_clear_flag(paramLines[P_CALC0]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + // Params + if (sensor->unit < UNIT_FIRST_VIRTUAL) { + if (sensor->type == TELEM_TYPE_CALCULATED) { + if (sensor->formula == TELEM_FORMULA_CELL) { + paramLines[P_CELLSENSOR]->show(); + } else if (sensor->formula == TELEM_FORMULA_DIST) { + paramLines[P_GPSSENSOR]->show(); + } else if (sensor->formula == TELEM_FORMULA_CONSUMPTION) { + paramLines[P_CURRENTSENSOR]->show(); + } else if (sensor->formula == TELEM_FORMULA_TOTALIZE) { + paramLines[P_CONSUMPTIONSOURCE]->show(); + } else { + paramLines[P_CALC0]->show(); } - else { - if (sensor->unit == UNIT_RPMS) { - lv_obj_clear_flag(paramLines[P_BLADES]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else { - lv_obj_clear_flag(paramLines[P_RATIO]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + } else { + if (sensor->unit == UNIT_RPMS) { + paramLines[P_BLADES]->show(); + } else { + paramLines[P_RATIO]->show(); } } + } - if (!(sensor->unit == UNIT_GPS || sensor->unit == UNIT_DATETIME || sensor->unit == UNIT_CELLS || - (sensor->type == TELEM_TYPE_CALCULATED && (sensor->formula == TELEM_FORMULA_CONSUMPTION || sensor->formula == TELEM_FORMULA_TOTALIZE)))) { - if (sensor->type == TELEM_TYPE_CALCULATED) { - if (sensor->formula == TELEM_FORMULA_CELL) { - lv_obj_clear_flag(paramLines[P_CELLINDEX]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else if (sensor->formula == TELEM_FORMULA_DIST) { - lv_obj_clear_flag(paramLines[P_ALTSENSOR]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else { - lv_obj_clear_flag(paramLines[P_CALC1]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - } - else if (sensor->unit == UNIT_RPMS) { - lv_obj_clear_flag(paramLines[P_MULT]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - else { - lv_obj_clear_flag(paramLines[P_OFFSET]->getLvObj(), LV_OBJ_FLAG_HIDDEN); + if (!(sensor->unit == UNIT_GPS || sensor->unit == UNIT_DATETIME || + sensor->unit == UNIT_CELLS || + (sensor->type == TELEM_TYPE_CALCULATED && + (sensor->formula == TELEM_FORMULA_CONSUMPTION || + sensor->formula == TELEM_FORMULA_TOTALIZE)))) { + if (sensor->type == TELEM_TYPE_CALCULATED) { + if (sensor->formula == TELEM_FORMULA_CELL) { + paramLines[P_CELLINDEX]->show(); + } else if (sensor->formula == TELEM_FORMULA_DIST) { + paramLines[P_ALTSENSOR]->show(); + } else { + paramLines[P_CALC1]->show(); } + } else if (sensor->unit == UNIT_RPMS) { + paramLines[P_MULT]->show(); + } else { + paramLines[P_OFFSET]->show(); } + } - if ((sensor->type == TELEM_TYPE_CALCULATED && sensor->formula < TELEM_FORMULA_MULTIPLY)) { - lv_obj_clear_flag(paramLines[P_CALC2]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(paramLines[P_CALC3]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + if ((sensor->type == TELEM_TYPE_CALCULATED && + sensor->formula < TELEM_FORMULA_MULTIPLY)) { + paramLines[P_CALC2]->show(); + paramLines[P_CALC3]->show(); + } - // Auto Offset - if (sensor->unit != UNIT_RPMS && sensor->isConfigurable()) { - lv_obj_clear_flag(paramLines[P_AUTOOFFSET]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + // Auto Offset + if (sensor->unit != UNIT_RPMS && sensor->isConfigurable()) { + paramLines[P_AUTOOFFSET]->show(); + } - if (sensor->isConfigurable()) { - // Only positive - lv_obj_clear_flag(paramLines[P_ONLYPOS]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - // Filter - lv_obj_clear_flag(paramLines[P_FILTER]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + if (sensor->isConfigurable()) { + // Only positive + paramLines[P_ONLYPOS]->show(); + // Filter + paramLines[P_FILTER]->show(); + } - if (sensor->type == TELEM_TYPE_CALCULATED) { - lv_obj_clear_flag(paramLines[P_PERSISTENT]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + if (sensor->type == TELEM_TYPE_CALCULATED) { + paramLines[P_PERSISTENT]->show(); } + } - void buildBody(FormWindow * window) - { - window->padAll(0); - lv_obj_set_scrollbar_mode(window->getLvObj(), LV_SCROLLBAR_MODE_AUTO); - - // Sensor one - auto form = new FormWindow(window, rect_t{}); - form->setFlexLayout(); - form->padAll(4); - - FlexGridLayout grid(e_col_dsc, row_dsc, 2); - FlexGridLayout grid2(e_col_dsc2, row_dsc, 2); - - TelemetrySensor * sensor = &g_model.telemetrySensors[index]; - - // Sensor name - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); - new ModelTextEdit(line, rect_t{}, sensor->label, sizeof(sensor->label)); - - // Type - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_TYPE, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_VSENSORTYPES, 0, 1, GET_DEFAULT(sensor->type), - [=](uint8_t newValue) { - sensor->type = newValue; - sensor->instance = 0; - if (sensor->type == TELEM_TYPE_CALCULATED) { - sensor->param = 0; - sensor->filter = 0; - sensor->autoOffset = 0; - } - SET_DIRTY(); - updateSensorParameters(); - }); - - // Parameters - paramLines[P_FORMULA] = form->newLine(&grid); - new StaticText(paramLines[P_FORMULA], rect_t{}, STR_FORMULA, 0, COLOR_THEME_PRIMARY1); - new Choice(paramLines[P_FORMULA], rect_t{}, STR_VFORMULAS, 0, TELEM_FORMULA_LAST, GET_DEFAULT(sensor->formula), - [=](uint8_t newValue) { - sensor->formula = newValue; - sensor->param = 0; - if (sensor->formula == TELEM_FORMULA_CELL) { - sensor->unit = UNIT_VOLTS; - sensor->prec = 2; - } - else if (sensor->formula == TELEM_FORMULA_DIST) { - sensor->unit = UNIT_DIST; - sensor->prec = 0; - } - else if (sensor->formula == TELEM_FORMULA_CONSUMPTION) { - sensor->unit = UNIT_MAH; - sensor->prec = 0; - } - SET_DIRTY(); - telemetryItems[index].clear(); - updateSensorParameters(); - }); - - paramLines[P_ID] = form->newLine(&grid2); - new StaticText(paramLines[P_ID], rect_t{}, STR_ID, 0, COLOR_THEME_PRIMARY1); - auto num = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xFFFF, GET_SET_DEFAULT(sensor->id)); + void buildBody(Window* window) + { + window->setFlexLayout(); + + FlexGridLayout grid(e_col_dsc, row_dsc, PAD_TINY); + FlexGridLayout grid2(e_col_dsc2, row_dsc, PAD_TINY); + + TelemetrySensor* sensor = &g_model.telemetrySensors[index]; + + // Sensor name + auto line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); + new ModelTextEdit(line, rect_t{}, sensor->label, sizeof(sensor->label)); + + // Type + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_TYPE, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_VSENSORTYPES, 0, 1, + GET_DEFAULT(sensor->type), [=](uint8_t newValue) { + sensor->type = newValue; + sensor->instance = 0; + if (sensor->type == TELEM_TYPE_CALCULATED) { + sensor->param = 0; + sensor->filter = 0; + sensor->autoOffset = 0; + } + SET_DIRTY(); + updateSensorParameters(); + }); + + // Parameters + paramLines[P_FORMULA] = window->newLine(grid); + new StaticText(paramLines[P_FORMULA], rect_t{}, STR_FORMULA, + COLOR_THEME_PRIMARY1); + new Choice(paramLines[P_FORMULA], rect_t{}, STR_VFORMULAS, 0, + TELEM_FORMULA_LAST, GET_DEFAULT(sensor->formula), + [=](uint8_t newValue) { + sensor->formula = newValue; + sensor->param = 0; + if (sensor->formula == TELEM_FORMULA_CELL) { + sensor->unit = UNIT_VOLTS; + sensor->prec = 2; + } else if (sensor->formula == TELEM_FORMULA_DIST) { + sensor->unit = UNIT_DIST; + sensor->prec = 0; + } else if (sensor->formula == TELEM_FORMULA_CONSUMPTION) { + sensor->unit = UNIT_MAH; + sensor->prec = 0; + } + SET_DIRTY(); + telemetryItems[index].clear(); + updateSensorParameters(); + }); + + paramLines[P_ID] = window->newLine(grid2); + new StaticText(paramLines[P_ID], rect_t{}, STR_ID, COLOR_THEME_PRIMARY1); + auto num = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xFFFF, + GET_SET_DEFAULT(sensor->id)); #if LCD_H > LCD_W - // Portrait layout - need to limit width of edit box - num->setWidth((lv_pct(28))); + // Portrait layout - need to limit width of edit box + num->setWidth((lv_pct(28))); #endif - num->setDisplayHandler([](int32_t value) { - char buf[4]; - buf[0] = hex2char((value & 0xf000) >> 12); - buf[1] = hex2char((value & 0x0f00) >> 8); - buf[2] = hex2char((value & 0x00f0) >> 4); - buf[3] = hex2char((value & 0x000f) >> 0); - return std::string(buf, sizeof(buf)); - }); - num = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xff, GET_SET_DEFAULT(sensor->instance)); + num->setDisplayHandler([](int32_t value) { + char buf[4]; + buf[0] = hex2char((value & 0xf000) >> 12); + buf[1] = hex2char((value & 0x0f00) >> 8); + buf[2] = hex2char((value & 0x00f0) >> 4); + buf[3] = hex2char((value & 0x000f) >> 0); + return std::string(buf, sizeof(buf)); + }); + num = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xff, + GET_SET_DEFAULT(sensor->instance)); #if LCD_H > LCD_W - // Portrait layout - need to limit width of edit box - num->setWidth(lv_pct(28)); + // Portrait layout - need to limit width of edit box + num->setWidth(lv_pct(28)); #endif - paramLines[P_UNIT] = form->newLine(&grid); - new StaticText(paramLines[P_UNIT], rect_t{}, STR_UNIT, 0, COLOR_THEME_PRIMARY1); - new Choice(paramLines[P_UNIT], rect_t{}, STR_VTELEMUNIT, 0, UNIT_MAX, GET_DEFAULT(sensor->unit), - [=](uint8_t newValue) { - sensor->unit = newValue; - if (sensor->unit == UNIT_FAHRENHEIT) { - sensor->prec = 0; - } - SET_DIRTY(); - telemetryItems[index].clear(); - updateSensorParameters(); - }); - - paramLines[P_PREC] = form->newLine(&grid); - new StaticText(paramLines[P_PREC], rect_t{}, STR_PRECISION, 0, COLOR_THEME_PRIMARY1); - new Choice(paramLines[P_PREC], rect_t{}, STR_VPREC, 0, 2, GET_DEFAULT(sensor->prec), - [=](uint8_t newValue) { - sensor->prec = newValue; - SET_DIRTY(); - telemetryItems[index].clear(); - updateSensorParameters(); - }); - - paramLines[P_CELLSENSOR] = form->newLine(&grid); - new StaticText(paramLines[P_CELLSENSOR], rect_t{}, STR_CELLSENSOR, 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_CELLSENSOR], rect_t{}, &sensor->cell.source, isCellsSensor); - - paramLines[P_GPSSENSOR] = form->newLine(&grid); - new StaticText(paramLines[P_GPSSENSOR], rect_t{}, STR_GPSSENSOR, 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_GPSSENSOR], rect_t{}, &sensor->dist.gps, isGPSSensor); - - paramLines[P_CURRENTSENSOR] = form->newLine(&grid); - new StaticText(paramLines[P_CURRENTSENSOR], rect_t{}, STR_CURRENTSENSOR, 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_CURRENTSENSOR], rect_t{}, &sensor->consumption.source, isSensorAvailable); - - paramLines[P_CONSUMPTIONSOURCE] = form->newLine(&grid); - new StaticText(paramLines[P_CONSUMPTIONSOURCE], rect_t{}, STR_SOURCE, 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_CONSUMPTIONSOURCE], rect_t{}, &sensor->consumption.source, isSensorAvailable); - - paramLines[P_CALC0] = form->newLine(&grid); - new StaticText(paramLines[P_CALC0], rect_t{}, STR_SOURCE + std::to_string(1), 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_CALC0], rect_t{}, (uint8_t *) &sensor->calc.sources[0], isSensorAvailable); - - paramLines[P_BLADES] = form->newLine(&grid); - new StaticText(paramLines[P_BLADES], rect_t{}, STR_BLADES, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(paramLines[P_BLADES], rect_t{}, 1, 30000, GET_SET_DEFAULT(sensor->custom.ratio)); - - paramLines[P_RATIO] = form->newLine(&grid); - new StaticText(paramLines[P_RATIO], rect_t{}, STR_RATIO, 0, COLOR_THEME_PRIMARY1); - auto edit = new NumberEdit(paramLines[P_RATIO], rect_t{}, 0, 30000, GET_SET_DEFAULT(sensor->custom.ratio), - 0, PREC1); - edit->setZeroText("-"); - - paramLines[P_CELLINDEX] = form->newLine(&grid); - new StaticText(paramLines[P_CELLINDEX], rect_t{}, STR_CELLINDEX, 0, COLOR_THEME_PRIMARY1); - new Choice(paramLines[P_CELLINDEX], rect_t{}, STR_VCELLINDEX, TELEM_CELL_INDEX_LOWEST, TELEM_CELL_INDEX_LAST, GET_SET_DEFAULT(sensor->cell.index)); - - paramLines[P_ALTSENSOR] = form->newLine(&grid); - new StaticText(paramLines[P_ALTSENSOR], rect_t{}, STR_ALTSENSOR, 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_ALTSENSOR], rect_t{}, &sensor->dist.alt, isAltSensor); - - paramLines[P_CALC1] = form->newLine(&grid); - new StaticText(paramLines[P_CALC1], rect_t{}, STR_SOURCE + std::to_string(2), 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_CALC1], rect_t{}, (uint8_t *) &sensor->calc.sources[1], isSensorAvailable); - - paramLines[P_MULT] = form->newLine(&grid); - new StaticText(paramLines[P_MULT], rect_t{}, STR_MULTIPLIER, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(paramLines[P_MULT], rect_t{}, 1, 30000, GET_SET_DEFAULT(sensor->custom.offset)); - - paramLines[P_OFFSET] = form->newLine(&grid); - new StaticText(paramLines[P_OFFSET], rect_t{}, STR_OFFSET, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(paramLines[P_OFFSET], rect_t{}, -30000, 30000, GET_SET_DEFAULT(sensor->custom.offset), - 0, (sensor->prec > 0) ? (sensor->prec == 2 ? PREC2 : PREC1) : 0); - - paramLines[P_CALC2] = form->newLine(&grid); - new StaticText(paramLines[P_CALC2], rect_t{}, STR_SOURCE + std::to_string(3), 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_CALC2], rect_t{}, (uint8_t *) &sensor->calc.sources[2], isSensorAvailable); - - paramLines[P_CALC3] = form->newLine(&grid); - new StaticText(paramLines[P_CALC3], rect_t{}, STR_SOURCE + std::to_string(4), 0, COLOR_THEME_PRIMARY1); - new SensorSourceChoice(paramLines[P_CALC3], rect_t{}, (uint8_t *) &sensor->calc.sources[3], isSensorAvailable); - - paramLines[P_AUTOOFFSET] = form->newLine(&grid); - new StaticText(paramLines[P_AUTOOFFSET], rect_t{}, STR_AUTOOFFSET, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(paramLines[P_AUTOOFFSET], rect_t{}, GET_SET_DEFAULT(sensor->autoOffset)); - - paramLines[P_ONLYPOS] = form->newLine(&grid); - new StaticText(paramLines[P_ONLYPOS], rect_t{}, STR_ONLYPOSITIVE, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(paramLines[P_ONLYPOS], rect_t{}, GET_SET_DEFAULT(sensor->onlyPositive)); - - paramLines[P_FILTER] = form->newLine(&grid); - new StaticText(paramLines[P_FILTER], rect_t{}, STR_FILTER, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(paramLines[P_FILTER], rect_t{}, GET_SET_DEFAULT(sensor->filter)); - - paramLines[P_PERSISTENT] = form->newLine(&grid); - new StaticText(paramLines[P_PERSISTENT], rect_t{}, STR_PERSISTENT, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(paramLines[P_PERSISTENT], rect_t{}, GET_DEFAULT(sensor->persistent), [=](int32_t newValue) { - sensor->persistent = newValue; - if (!sensor->persistent) - sensor->persistentValue = 0; - SET_DIRTY(); - }); - - // Logs - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_LOGS, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, GET_DEFAULT(sensor->logs), [=](int32_t newValue) { - sensor->logs = newValue; - logsClose(); - SET_DIRTY(); - }); - - updateSensorParameters(); - } + paramLines[P_UNIT] = window->newLine(grid); + new StaticText(paramLines[P_UNIT], rect_t{}, STR_UNIT, + COLOR_THEME_PRIMARY1); + new Choice(paramLines[P_UNIT], rect_t{}, STR_VTELEMUNIT, 0, UNIT_MAX, + GET_DEFAULT(sensor->unit), [=](uint8_t newValue) { + sensor->unit = newValue; + if (sensor->unit == UNIT_FAHRENHEIT) { + sensor->prec = 0; + } + SET_DIRTY(); + telemetryItems[index].clear(); + updateSensorParameters(); + }); + + paramLines[P_PREC] = window->newLine(grid); + new StaticText(paramLines[P_PREC], rect_t{}, STR_PRECISION, + COLOR_THEME_PRIMARY1); + new Choice(paramLines[P_PREC], rect_t{}, STR_VPREC, 0, 2, + GET_DEFAULT(sensor->prec), [=](uint8_t newValue) { + sensor->prec = newValue; + SET_DIRTY(); + telemetryItems[index].clear(); + updateSensorParameters(); + }); + + paramLines[P_CELLSENSOR] = window->newLine(grid); + new StaticText(paramLines[P_CELLSENSOR], rect_t{}, STR_CELLSENSOR, + COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_CELLSENSOR], rect_t{}, + &sensor->cell.source, isCellsSensor); + + paramLines[P_GPSSENSOR] = window->newLine(grid); + new StaticText(paramLines[P_GPSSENSOR], rect_t{}, STR_GPSSENSOR, + COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_GPSSENSOR], rect_t{}, &sensor->dist.gps, + isGPSSensor); + + paramLines[P_CURRENTSENSOR] = window->newLine(grid); + new StaticText(paramLines[P_CURRENTSENSOR], rect_t{}, STR_CURRENTSENSOR, + COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_CURRENTSENSOR], rect_t{}, + &sensor->consumption.source, isSensorAvailable); + + paramLines[P_CONSUMPTIONSOURCE] = window->newLine(grid); + new StaticText(paramLines[P_CONSUMPTIONSOURCE], rect_t{}, STR_SOURCE, + COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_CONSUMPTIONSOURCE], rect_t{}, + &sensor->consumption.source, isSensorAvailable); + + paramLines[P_CALC0] = window->newLine(grid); + new StaticText(paramLines[P_CALC0], rect_t{}, + STR_SOURCE + std::to_string(1), COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_CALC0], rect_t{}, + (uint8_t*)&sensor->calc.sources[0], + isSensorAvailable); + + paramLines[P_BLADES] = window->newLine(grid); + new StaticText(paramLines[P_BLADES], rect_t{}, STR_BLADES, + COLOR_THEME_PRIMARY1); + new NumberEdit(paramLines[P_BLADES], rect_t{}, 1, 30000, + GET_SET_DEFAULT(sensor->custom.ratio)); + + paramLines[P_RATIO] = window->newLine(grid); + new StaticText(paramLines[P_RATIO], rect_t{}, STR_RATIO, + COLOR_THEME_PRIMARY1); + auto edit = new NumberEdit(paramLines[P_RATIO], rect_t{}, 0, 30000, + GET_SET_DEFAULT(sensor->custom.ratio), PREC1); + edit->setZeroText("-"); + + paramLines[P_CELLINDEX] = window->newLine(grid); + new StaticText(paramLines[P_CELLINDEX], rect_t{}, STR_CELLINDEX, + COLOR_THEME_PRIMARY1); + new Choice(paramLines[P_CELLINDEX], rect_t{}, STR_VCELLINDEX, + TELEM_CELL_INDEX_LOWEST, TELEM_CELL_INDEX_LAST, + GET_SET_DEFAULT(sensor->cell.index)); + + paramLines[P_ALTSENSOR] = window->newLine(grid); + new StaticText(paramLines[P_ALTSENSOR], rect_t{}, STR_ALTSENSOR, + COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_ALTSENSOR], rect_t{}, &sensor->dist.alt, + isAltSensor); + + paramLines[P_CALC1] = window->newLine(grid); + new StaticText(paramLines[P_CALC1], rect_t{}, + STR_SOURCE + std::to_string(2), COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_CALC1], rect_t{}, + (uint8_t*)&sensor->calc.sources[1], + isSensorAvailable); + + paramLines[P_MULT] = window->newLine(grid); + new StaticText(paramLines[P_MULT], rect_t{}, STR_MULTIPLIER, + COLOR_THEME_PRIMARY1); + new NumberEdit(paramLines[P_MULT], rect_t{}, 1, 30000, + GET_SET_DEFAULT(sensor->custom.offset)); + + paramLines[P_OFFSET] = window->newLine(grid); + new StaticText(paramLines[P_OFFSET], rect_t{}, STR_OFFSET, + COLOR_THEME_PRIMARY1); + new NumberEdit( + paramLines[P_OFFSET], rect_t{}, -30000, 30000, + GET_SET_DEFAULT(sensor->custom.offset), + (sensor->prec > 0) ? (sensor->prec == 2 ? PREC2 : PREC1) : 0); + + paramLines[P_CALC2] = window->newLine(grid); + new StaticText(paramLines[P_CALC2], rect_t{}, + STR_SOURCE + std::to_string(3), COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_CALC2], rect_t{}, + (uint8_t*)&sensor->calc.sources[2], + isSensorAvailable); + + paramLines[P_CALC3] = window->newLine(grid); + new StaticText(paramLines[P_CALC3], rect_t{}, + STR_SOURCE + std::to_string(4), COLOR_THEME_PRIMARY1); + new SensorSourceChoice(paramLines[P_CALC3], rect_t{}, + (uint8_t*)&sensor->calc.sources[3], + isSensorAvailable); + + paramLines[P_AUTOOFFSET] = window->newLine(grid); + new StaticText(paramLines[P_AUTOOFFSET], rect_t{}, STR_AUTOOFFSET, + COLOR_THEME_PRIMARY1); + new ToggleSwitch(paramLines[P_AUTOOFFSET], rect_t{}, + GET_SET_DEFAULT(sensor->autoOffset)); + + paramLines[P_ONLYPOS] = window->newLine(grid); + new StaticText(paramLines[P_ONLYPOS], rect_t{}, STR_ONLYPOSITIVE, + COLOR_THEME_PRIMARY1); + new ToggleSwitch(paramLines[P_ONLYPOS], rect_t{}, + GET_SET_DEFAULT(sensor->onlyPositive)); + + paramLines[P_FILTER] = window->newLine(grid); + new StaticText(paramLines[P_FILTER], rect_t{}, STR_FILTER, + COLOR_THEME_PRIMARY1); + new ToggleSwitch(paramLines[P_FILTER], rect_t{}, + GET_SET_DEFAULT(sensor->filter)); + + paramLines[P_PERSISTENT] = window->newLine(grid); + new StaticText(paramLines[P_PERSISTENT], rect_t{}, STR_PERSISTENT, + COLOR_THEME_PRIMARY1); + new ToggleSwitch(paramLines[P_PERSISTENT], rect_t{}, + GET_DEFAULT(sensor->persistent), [=](int32_t newValue) { + sensor->persistent = newValue; + if (!sensor->persistent) sensor->persistentValue = 0; + SET_DIRTY(); + }); + + // Logs + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_LOGS, COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, GET_DEFAULT(sensor->logs), + [=](int32_t newValue) { + sensor->logs = newValue; + logsClose(); + SET_DIRTY(); + }); + + updateSensorParameters(); + } }; ModelTelemetryPage::ModelTelemetryPage() : - PageTab(STR_MENUTELEMETRY, ICON_MODEL_TELEMETRY) + PageTab(STR_MENUTELEMETRY, ICON_MODEL_TELEMETRY) { tsStyle.init(); } @@ -756,20 +864,17 @@ void ModelTelemetryPage::checkEvents() PageTab::checkEvents(); } -void ModelTelemetryPage::rebuild(FormWindow * window, int8_t focusSensorIndex) +void ModelTelemetryPage::rebuild(Window* window, int8_t focusSensorIndex) { buildSensorList(focusSensorIndex); lastKnownIndex = availableTelemetryIndex(); } - -void ModelTelemetryPage::editSensor(FormWindow * window, uint8_t index) +void ModelTelemetryPage::editSensor(Window* window, uint8_t index) { lastKnownIndex = -1; - Window * editWindow = new SensorEditWindow(index); - editWindow->setCloseHandler([=]() { - rebuild(window, index); - }); + Window* editWindow = new SensorEditWindow(index); + editWindow->setCloseHandler([=]() { rebuild(window, index); }); } void ModelTelemetryPage::buildSensorList(int8_t focusSensorIndex) @@ -786,28 +891,25 @@ void ModelTelemetryPage::buildSensorList(int8_t focusSensorIndex) if (!first) first = button; button->setPressHandler([=]() -> uint8_t { - Menu * menu = new Menu(window); - menu->addLine(STR_EDIT, [=]() { - editSensor(window, idx); - }); + Menu* menu = new Menu(window); + menu->addLine(STR_EDIT, [=]() { editSensor(window, idx); }); menu->addLine(STR_COPY, [=]() { auto newIndex = availableTelemetryIndex(); if (newIndex >= 0) { - TelemetrySensor &sourceSensor = g_model.telemetrySensors[idx]; - TelemetrySensor &newSensor = g_model.telemetrySensors[newIndex]; + TelemetrySensor& sourceSensor = g_model.telemetrySensors[idx]; + TelemetrySensor& newSensor = g_model.telemetrySensors[newIndex]; newSensor = sourceSensor; - TelemetryItem &sourceItem = telemetryItems[idx]; - TelemetryItem &newItem = telemetryItems[newIndex]; + TelemetryItem& sourceItem = telemetryItems[idx]; + TelemetryItem& newItem = telemetryItems[newIndex]; newItem = sourceItem; SET_DIRTY(); rebuild(window, newIndex); - } - else { + } else { new FullScreenDialog(WARNING_TYPE_ALERT, "", STR_TELEMETRYFULL); } }); menu->addLine(STR_DELETE, [=]() { - delTelemetryIndex(idx); // calls setDirty internally + delTelemetryIndex(idx); // calls setDirty internally for (uint8_t i = idx + 1; i < MAX_TELEMETRY_SENSORS; i += 1) { if (g_model.telemetrySensors[i].isAvailable()) { rebuild(window, i); @@ -820,7 +922,7 @@ void ModelTelemetryPage::buildSensorList(int8_t focusSensorIndex) return; } } - rebuild(window,-1); + rebuild(window, -1); }); return 0; }); @@ -837,13 +939,9 @@ void ModelTelemetryPage::buildSensorList(int8_t focusSensorIndex) else lv_group_focus_obj(discover->getLvObj()); } - + uint8_t sensorsCount = getTelemetrySensorsCount(); - if (sensorsCount > 0) { - lv_obj_clear_flag(deleteAll->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(deleteAll->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + deleteAll->show(sensorsCount > 0); } #if LCD_W > LCD_H @@ -852,25 +950,28 @@ void ModelTelemetryPage::buildSensorList(int8_t focusSensorIndex) #define NUM_EDIT_W 65 #endif -void ModelTelemetryPage::build(FormWindow * window) +void ModelTelemetryPage::build(Window* window) { - window->padAll(4); - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); + window->padAll(PAD_TINY); + window->padBottom(16); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); this->window = window; // Sensors new Subtitle(window, STR_TELEMETRY_SENSORS); - sensorWindow = new FormWindow(window, rect_t{}); - sensorWindow->padAll(0); - sensorWindow->setFlexLayout(LV_FLEX_FLOW_COLUMN, 4); + sensorWindow = new Window(window, rect_t{}); + sensorWindow->padAll(PAD_TINY); + sensorWindow->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); - FlexGridLayout grid4(col_dsc4, row_dsc, 4); + FlexGridLayout grid4(col_dsc4, row_dsc); // Autodiscover button - auto line = window->newLine(&grid4); - discover = new TextButton(line, rect_t{}, (allowNewSensors) ? STR_STOP_DISCOVER_SENSORS : STR_DISCOVER_SENSORS); + auto line = window->newLine(grid4); + discover = new TextButton( + line, rect_t{}, + (allowNewSensors) ? STR_STOP_DISCOVER_SENSORS : STR_DISCOVER_SENSORS); discover->setPressHandler([=]() { allowNewSensors = !allowNewSensors; if (allowNewSensors) { @@ -881,193 +982,165 @@ void ModelTelemetryPage::build(FormWindow * window) return 0; } }); - lv_obj_set_grid_cell(discover->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_grid_cell(discover->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 1, + LV_GRID_ALIGN_CENTER, 0, 1); discover->check(allowNewSensors); // New sensor button - auto b = new TextButton(line, rect_t{}, STR_TELEMETRY_NEWSENSOR, - [=]() -> uint8_t { - int idx = availableTelemetryIndex(); - if (idx >= 0) - editSensor(window, idx); - else - new FullScreenDialog(WARNING_TYPE_ALERT, "", STR_TELEMETRYFULL); - return 0; - }); - lv_obj_set_grid_cell(b->getLvObj(), LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); + auto b = + new TextButton(line, rect_t{}, STR_TELEMETRY_NEWSENSOR, [=]() -> uint8_t { + int idx = availableTelemetryIndex(); + if (idx >= 0) + editSensor(window, idx); + else + new FullScreenDialog(WARNING_TYPE_ALERT, "", STR_TELEMETRYFULL); + return 0; + }); + lv_obj_set_grid_cell(b->getLvObj(), LV_GRID_ALIGN_STRETCH, 1, 1, + LV_GRID_ALIGN_CENTER, 0, 1); #if TWOCOLBUTTONS - line = window->newLine(&grid4); + line = window->newLine(grid4); #endif // Delete all sensors button - deleteAll = new TextButton(line, rect_t{}, STR_DELETE_ALL_SENSORS, - [=]() -> uint8_t { - new ConfirmDialog(window, STR_DELETE_ALL_SENSORS, STR_CONFIRMDELETE, [=]() { - for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) { - delTelemetryIndex(i); - } - }); - return 0; - }); + deleteAll = + new TextButton(line, rect_t{}, STR_DELETE_ALL_SENSORS, [=]() -> uint8_t { + new ConfirmDialog(window, STR_DELETE_ALL_SENSORS, STR_CONFIRMDELETE, + [=]() { + for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) { + delTelemetryIndex(i); + } + }); + return 0; + }); #if TWOCOLBUTTONS deleteAll->setWidth((LCD_W - 16) / 2); - lv_obj_set_grid_cell(deleteAll->getLvObj(), LV_GRID_ALIGN_CENTER, 0, 2, LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_grid_cell(deleteAll->getLvObj(), LV_GRID_ALIGN_CENTER, 0, 2, + LV_GRID_ALIGN_CENTER, 0, 1); #else - lv_obj_set_grid_cell(deleteAll->getLvObj(), LV_GRID_ALIGN_STRETCH, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_grid_cell(deleteAll->getLvObj(), LV_GRID_ALIGN_STRETCH, 2, 1, + LV_GRID_ALIGN_CENTER, 0, 1); #endif - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); // Show instance IDs button - line = window->newLine(&grid); + line = window->newLine(grid); line->padLeft(10); - new StaticText(line, rect_t{}, STR_SHOW_INSTANCE_ID, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_SHOW_INSTANCE_ID, COLOR_THEME_PRIMARY1); new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_model.showInstanceIds)); // Ignore instance button - line = window->newLine(&grid); + line = window->newLine(grid); line->padLeft(10); - new StaticText(line, rect_t{}, STR_IGNORE_INSTANCE, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_IGNORE_INSTANCE, COLOR_THEME_PRIMARY1); new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_model.ignoreSensorIds)); // RX stat new Subtitle(window, getRxStatLabels()->label); - line = window->newLine(&grid); + line = window->newLine(grid); line->padLeft(10); - new StaticText(line, rect_t{}, STR_LOWALARM, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, 0, 100, GET_SET_DEFAULT(g_model.rfAlarms.warning)); + new StaticText(line, rect_t{}, STR_LOWALARM, COLOR_THEME_PRIMARY1); + new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, 0, 100, + GET_SET_DEFAULT(g_model.rfAlarms.warning)); - line = window->newLine(&grid); + line = window->newLine(grid); line->padLeft(10); - new StaticText(line, rect_t{}, STR_CRITICALALARM, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, 0, 100, GET_SET_DEFAULT(g_model.rfAlarms.critical)); + new StaticText(line, rect_t{}, STR_CRITICALALARM, COLOR_THEME_PRIMARY1); + new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, 0, 100, + GET_SET_DEFAULT(g_model.rfAlarms.critical)); - line = window->newLine(&grid); + line = window->newLine(grid); line->padLeft(10); - new StaticText(line, rect_t{}, STR_DISABLE_ALARM, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_model.disableTelemetryWarning)); + new StaticText(line, rect_t{}, STR_DISABLE_ALARM, COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, + GET_SET_DEFAULT(g_model.disableTelemetryWarning)); // Vario new Subtitle(window, STR_VARIO); - FlexGridLayout grid5(col_dsc5, row_dsc, 4); + FlexGridLayout grid5(col_dsc5, row_dsc); - line = window->newLine(&grid5); + line = window->newLine(grid5); line->padLeft(10); - new StaticText(line, rect_t{}, STR_SOURCE, 0, COLOR_THEME_PRIMARY1); - auto choice = new SourceChoice(line, rect_t{}, MIXSRC_NONE, MIXSRC_LAST_TELEM, - GET_DEFAULT(g_model.varioData.source ? MIXSRC_FIRST_TELEM + 3 * (g_model.varioData.source - 1) : MIXSRC_NONE), - SET_VALUE(g_model.varioData.source, newValue == MIXSRC_NONE ? 0 : (newValue - MIXSRC_FIRST_TELEM) / 3 + 1)); + new StaticText(line, rect_t{}, STR_SOURCE, COLOR_THEME_PRIMARY1); + auto choice = new SourceChoice( + line, rect_t{}, MIXSRC_NONE, MIXSRC_LAST_TELEM, + GET_DEFAULT(g_model.varioData.source + ? MIXSRC_FIRST_TELEM + 3 * (g_model.varioData.source - 1) + : MIXSRC_NONE), + SET_VALUE(g_model.varioData.source, + newValue == MIXSRC_NONE + ? 0 + : (newValue - MIXSRC_FIRST_TELEM) / 3 + 1)); choice->setAvailableHandler([=](int16_t value) { - if (value == MIXSRC_NONE) - return true; - if (value < MIXSRC_FIRST_TELEM) - return false; + if (value == MIXSRC_NONE) return true; + if (value < MIXSRC_FIRST_TELEM) return false; auto qr = div(value - MIXSRC_FIRST_TELEM, 3); return qr.rem == 0 && isSensorAvailable(qr.quot + 1); }); - line = window->newLine(&grid5); + line = window->newLine(grid5); line->padLeft(10); - new StaticText(line, rect_t{}, STR_RANGE, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_RANGE, COLOR_THEME_PRIMARY1); - auto vMin = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, -17, 17, GET_SET_WITH_OFFSET(g_model.varioData.min, -10)); - vMin->setAvailableHandler([](int val) { return val < g_model.varioData.max + 10; }); + auto vMin = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, -17, 17, + GET_SET_WITH_OFFSET(g_model.varioData.min, -10)); + vMin->setAvailableHandler( + [](int val) { return val < g_model.varioData.max + 10; }); - auto vMax = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, -17, 17, GET_SET_WITH_OFFSET(g_model.varioData.max, 10)); - vMax->setAvailableHandler([](int val) { return g_model.varioData.min - 10 < val; }); + auto vMax = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, -17, 17, + GET_SET_WITH_OFFSET(g_model.varioData.max, 10)); + vMax->setAvailableHandler( + [](int val) { return g_model.varioData.min - 10 < val; }); - line = window->newLine(&grid5); + line = window->newLine(grid5); line->padLeft(10); - new StaticText(line, rect_t{}, STR_CENTER, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, STR_CENTER, COLOR_THEME_PRIMARY1); - auto cMin = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, -15, 15, GET_SET_WITH_OFFSET(g_model.varioData.centerMin, -5), 0, PREC1); - cMin->setAvailableHandler([](int val) { return val < g_model.varioData.centerMax + 5; }); + auto cMin = new NumberEdit( + line, rect_t{0, 0, NUM_EDIT_W, 0}, -15, 15, + GET_SET_WITH_OFFSET(g_model.varioData.centerMin, -5), PREC1); + cMin->setAvailableHandler( + [](int val) { return val < g_model.varioData.centerMax + 5; }); - auto cMax = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, -15, 15, GET_SET_WITH_OFFSET(g_model.varioData.centerMax, 5), 0, PREC1); - cMax->setAvailableHandler([](int val) { return g_model.varioData.centerMin - 5 < val; }); + auto cMax = new NumberEdit( + line, rect_t{0, 0, NUM_EDIT_W, 0}, -15, 15, + GET_SET_WITH_OFFSET(g_model.varioData.centerMax, 5), PREC1); + cMax->setAvailableHandler( + [](int val) { return g_model.varioData.centerMin - 5 < val; }); - new Choice(line, rect_t{}, STR_VVARIOCENTER, 0, 1, GET_SET_DEFAULT(g_model.varioData.centerSilent)); + new Choice(line, rect_t{}, STR_VVARIOCENTER, 0, 1, + GET_SET_DEFAULT(g_model.varioData.centerSilent)); // Don't call this before the 'discover' button has been created buildSensorList(-1); } - -// Version of 'drawSensorCustomValue' and related functions that returns strings instead of drawing to screen +// Version of 'drawSensorCustomValue' and related functions that returns strings +// instead of drawing to screen // TODO: should this be moved somewhere else? -std::string getDate(TelemetryItem & telemetryItem) -{ - return - formatNumberAsString(telemetryItem.datetime.year, LEADING0|LEFT,4) + "-" + - formatNumberAsString(telemetryItem.datetime.month, LEADING0|LEFT, 2) + "-" + - formatNumberAsString(telemetryItem.datetime.day, LEADING0|LEFT, 2) + " " + - formatNumberAsString(telemetryItem.datetime.hour, LEADING0|LEFT, 2) + ":" + - formatNumberAsString(telemetryItem.datetime.min, LEADING0|LEFT, 2) + ":" + - formatNumberAsString(telemetryItem.datetime.sec, LEADING0|LEFT, 2); -} - -std::string getGPSCoord(int32_t value, const char * direction, bool seconds=true) -{ - char s[32] = {}; - uint32_t absvalue = abs(value); - char * tmp = strAppendUnsigned(s, absvalue / 1000000); - tmp = strAppend(tmp, "°"); - absvalue = absvalue % 1000000; - absvalue *= 60; - if (g_eeGeneral.gpsFormat == 0 || !seconds) { - tmp = strAppendUnsigned(tmp, absvalue / 1000000, 2); - *tmp++ = '\''; - if (seconds) { - absvalue %= 1000000; - absvalue *= 60; - absvalue /= 100000; - tmp = strAppendUnsigned(tmp, absvalue / 10); - *tmp++ = '.'; - tmp = strAppendUnsigned(tmp, absvalue % 10); - *tmp++ = '"'; - } - } - else { - tmp = strAppendUnsigned(tmp, absvalue / 1000000, 2); - *tmp++ = '.'; - absvalue /= 1000; - tmp = strAppendUnsigned(tmp, absvalue, 3); - } - *tmp++ = direction[value>=0 ? 0 : 1]; - *tmp = '\0'; - return std::string(s); -} - -std::string getGPSSensorValue(TelemetryItem & telemetryItem, LcdFlags flags) -{ - if (flags & RIGHT) - return getGPSCoord(telemetryItem.gps.longitude, "EW", true) + " " + getGPSCoord(telemetryItem.gps.latitude, "NS", true); - - return getGPSCoord(telemetryItem.gps.latitude, "NS", true) + " " + getGPSCoord(telemetryItem.gps.longitude, "EW", true); -} - std::string getSensorCustomValue(uint8_t sensor, int32_t value, LcdFlags flags) { - TelemetryItem & telemetryItem = telemetryItems[sensor]; - TelemetrySensor & telemetrySensor = g_model.telemetrySensors[sensor]; + TelemetryItem& telemetryItem = telemetryItems[sensor]; + TelemetrySensor& telemetrySensor = g_model.telemetrySensors[sensor]; if (telemetrySensor.unit == UNIT_DATETIME) { - return getDate(telemetryItem); - } - else if (telemetrySensor.unit == UNIT_GPS) { + return getTelemDate(telemetryItem) + " " + getTelemTime(telemetryItem); + } else if (telemetrySensor.unit == UNIT_GPS) { return getGPSSensorValue(telemetryItem, flags); - } - else if (telemetrySensor.unit == UNIT_TEXT) { + } else if (telemetrySensor.unit == UNIT_TEXT) { return std::string(telemetryItem.text); - } - else { + } else { if (telemetrySensor.prec > 0) { - flags |= (telemetrySensor.prec==1 ? PREC1 : PREC2); + flags |= (telemetrySensor.prec == 1 ? PREC1 : PREC2); } - return getValueWithUnit(value, telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit, flags); + return getValueWithUnit( + value, + telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit, + flags); } return std::string(""); diff --git a/radio/src/gui/colorlcd/model_telemetry.h b/radio/src/gui/colorlcd/model_telemetry.h index 89d97f2c0b9..eb9f4fa7410 100644 --- a/radio/src/gui/colorlcd/model_telemetry.h +++ b/radio/src/gui/colorlcd/model_telemetry.h @@ -19,29 +19,30 @@ * GNU General Public License for more details. */ -#ifndef _MODEL_TELEMETRY_H -#define _MODEL_TELEMETRY_H +#pragma once #include "tabsgroup.h" +#include "opentx.h" -class ModelTelemetryPage: public PageTab { - public: - ModelTelemetryPage(); +class ModelTelemetryPage : public PageTab +{ + public: + ModelTelemetryPage(); - void build(FormWindow * window) override; + bool isVisible() const override { return modelTelemetryEnabled(); } - void checkEvents() override; + void build(Window* window) override; - protected: - int lastKnownIndex = 0; - FormWindow* window = nullptr; - FormWindow* sensorWindow = nullptr; - TextButton* discover = nullptr; - TextButton* deleteAll = nullptr; + protected: + int lastKnownIndex = 0; + Window* window = nullptr; + Window* sensorWindow = nullptr; + TextButton* discover = nullptr; + TextButton* deleteAll = nullptr; - void editSensor(FormWindow * window, uint8_t index); - void rebuild(FormWindow * window, int8_t focusSensorIndex=-1); - void buildSensorList(int8_t focusSensorIndex=-1); -}; + void checkEvents() override; -#endif //_MODEL_TELEMETRY_H \ No newline at end of file + void editSensor(Window* window, uint8_t index); + void rebuild(Window* window, int8_t focusSensorIndex = -1); + void buildSensorList(int8_t focusSensorIndex = -1); +}; diff --git a/radio/src/gui/colorlcd/model_templates.cpp b/radio/src/gui/colorlcd/model_templates.cpp index c35e529a171..a003d2ab5b2 100644 --- a/radio/src/gui/colorlcd/model_templates.cpp +++ b/radio/src/gui/colorlcd/model_templates.cpp @@ -22,6 +22,9 @@ #include "model_templates.h" #include "standalone_lua.h" +#include "themes/etx_lv_theme.h" + +#define ETX_STATE_NO_INFO_COLOR LV_STATE_USER_1 static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; @@ -29,17 +32,14 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; TemplatePage::TemplatePage() : Page(ICON_MODEL_SELECT) { - auto form = new FormWindow(&body, rect_t{}); - form->setFlexLayout(); - form->padAll(4); + body.setFlexLayout(); - FlexGridLayout grid(col_dsc, row_dsc, 4); + FlexGridLayout grid(col_dsc, row_dsc); - auto line = form->newLine(&grid); + auto line = body.newLine(grid); - listWindow = new FormWindow(line, rect_t{}); - listWindow->setFlexLayout(LV_FLEX_FLOW_COLUMN, 8); - listWindow->setHeight(body.height() - 16); + listWindow = new Window(line, rect_t{}); + listWindow->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_LARGE, LV_PCT(100), body.height() - 16); lv_obj_set_flex_align(listWindow->getLvObj(), LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_SPACE_BETWEEN); lv_obj_set_grid_cell(listWindow->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 1, @@ -47,7 +47,9 @@ TemplatePage::TemplatePage() : Page(ICON_MODEL_SELECT) infoLabel = lv_label_create(line->getLvObj()); lv_obj_set_height(infoLabel, body.height() - 16); - lv_obj_set_style_text_align(infoLabel, LV_TEXT_ALIGN_LEFT, 0); + etx_obj_add_style(infoLabel, styles->text_align_left, LV_PART_MAIN); + etx_txt_color(infoLabel, COLOR_THEME_PRIMARY1_INDEX); + etx_txt_color(infoLabel, COLOR_THEME_DISABLED_INDEX, ETX_STATE_NO_INFO_COLOR); lv_obj_set_grid_cell(infoLabel, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); } @@ -67,12 +69,10 @@ void TemplatePage::updateInfo() if (infoText[0] == 0) { lv_label_set_text(infoLabel, STR_NO_INFORMATION); - lv_obj_set_style_text_color(infoLabel, makeLvColor(COLOR_THEME_DISABLED), - 0); + lv_obj_add_state(infoLabel, ETX_STATE_NO_INFO_COLOR); } else { lv_label_set_text(infoLabel, infoText); - lv_obj_set_style_text_color(infoLabel, makeLvColor(COLOR_THEME_PRIMARY1), - 0); + lv_obj_clear_state(infoLabel, ETX_STATE_NO_INFO_COLOR); } } @@ -91,7 +91,8 @@ void TemplatePage::onEvent(event_t event) class SelectTemplate : public TemplatePage { public: - SelectTemplate(SelectTemplateFolder* tp, std::string folder) : templateFolderPage(tp) + SelectTemplate(SelectTemplateFolder* tp, std::string folder) : + templateFolderPage(tp) { header.setTitle(STR_MANAGE_MODELS); header.setTitle2(STR_NEW_MODEL); @@ -104,7 +105,7 @@ class SelectTemplate : public TemplatePage DIR dir; FRESULT res = f_opendir(&dir, path); - Button* firstButton = nullptr; + ButtonBase* firstButton = nullptr; if (res == FR_OK) { // read all entries @@ -154,7 +155,7 @@ class SelectTemplate : public TemplatePage if (files.size() == 0) { new StaticText(listWindow, rect_t{0, 0, lv_pct(100), lv_pct(50)}, - STR_NO_TEMPLATES, 0, COLOR_THEME_PRIMARY1); + STR_NO_TEMPLATES, COLOR_THEME_PRIMARY1); } else { lv_group_focus_obj(firstButton->getLvObj()); } @@ -164,7 +165,8 @@ class SelectTemplate : public TemplatePage SelectTemplateFolder* templateFolderPage; }; -SelectTemplateFolder::SelectTemplateFolder(std::function update) +SelectTemplateFolder::SelectTemplateFolder( + std::function update) { this->update = update; @@ -233,7 +235,7 @@ SelectTemplateFolder::SelectTemplateFolder(std::functiongetLvObj()); diff --git a/radio/src/gui/colorlcd/model_templates.h b/radio/src/gui/colorlcd/model_templates.h index c91677cf2fc..6560e5baf75 100644 --- a/radio/src/gui/colorlcd/model_templates.h +++ b/radio/src/gui/colorlcd/model_templates.h @@ -24,6 +24,7 @@ #include #include "opentx.h" +#include "page.h" class TemplatePage : public Page { @@ -37,11 +38,11 @@ class TemplatePage : public Page #endif #if defined(DEBUG_WINDOWS) - std::string getName() const { return "TemplatePage"; } + std::string getName() const override { return "TemplatePage"; } #endif protected: - FormWindow* listWindow = nullptr; + Window* listWindow = nullptr; lv_obj_t* infoLabel = nullptr; static constexpr size_t LEN_INFO_TEXT = 300; diff --git a/radio/src/gui/colorlcd/model_usbjoystick.cpp b/radio/src/gui/colorlcd/model_usbjoystick.cpp index 59891be0270..ffd7dad0532 100644 --- a/radio/src/gui/colorlcd/model_usbjoystick.cpp +++ b/radio/src/gui/colorlcd/model_usbjoystick.cpp @@ -23,11 +23,15 @@ #include "button_matrix.h" #include "channel_bar.h" +#include "list_line_button.h" #include "opentx.h" +#include "themes/etx_lv_theme.h" #include "usb_joystick.h" #define SET_DIRTY() storageDirty(EE_MODEL) +#define ETX_STATE_COLLISION_WARN LV_STATE_USER_1 + #if LCD_W > LCD_H // Landscape static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), @@ -46,7 +50,7 @@ static const lv_coord_t ch_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), #define USBCH_CHN_ROWS 1 #define USBCH_BTN_MODE_COL 4 #define USBCH_BTN_MODE_ROW 0 -#define USBCH_LINE_HEIGHT PAGE_LINE_HEIGHT + 12 +#define USBCH_LINE_HEIGHT 32 static const lv_coord_t b_col_dsc[] = {LV_GRID_FR(10), 20, LV_GRID_FR(10), LV_GRID_FR(12), @@ -71,7 +75,7 @@ static const lv_coord_t ch_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), #define USBCH_CHN_ROWS 2 #define USBCH_BTN_MODE_COL 2 #define USBCH_BTN_MODE_ROW 1 -#define USBCH_LINE_HEIGHT 2 * PAGE_LINE_HEIGHT + 8 +#define USBCH_LINE_HEIGHT 48 static const lv_coord_t b_col_dsc[] = {LV_GRID_FR(1), 20, LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; @@ -95,10 +99,7 @@ class USBChannelEditStatusBar : public Window this, {USBCH_EDIT_STATUS_BAR_MARGIN, 0, rect.w - (USBCH_EDIT_STATUS_BAR_MARGIN * 2), rect.h}, - channel); - channelBar->setLeftMargin(15); - channelBar->setTextColor(COLOR_THEME_PRIMARY2); - channelBar->setOutputChannelBarLimitColor(COLOR_THEME_EDIT); + channel, true); } protected: @@ -135,7 +136,7 @@ class USBChannelButtonSel : public ButtonMatrix } update(); - lv_obj_set_style_radius(lvobj, LV_RADIUS_CIRCLE, LV_PART_ITEMS); + etx_obj_add_style(lvobj, styles->circle, LV_PART_ITEMS); lv_obj_add_event_cb(lvobj, btnsel_event_cb, LV_EVENT_DRAW_PART_BEGIN, this); @@ -223,21 +224,19 @@ static void btnsel_event_cb(lv_event_t* e) class USBChannelEditWindow : public Page { public: - USBChannelEditWindow(uint8_t channel) : Page(ICON_MODEL_USB), channel(channel) + USBChannelEditWindow(uint8_t channel) : Page(ICON_MODEL_USB, PAD_TINY), channel(channel) { - auto form = new FormWindow(&body, rect_t{}); - form->padAll(2); - form->padLeft(8); - form->padRight(8); + body.padLeft(8); + body.padRight(8); buildHeader(&header); - buildBody(form); + buildBody(&body); } protected: uint8_t channel; USBChannelEditStatusBar* statusBar = nullptr; - FormWindow* m_btnModeFrame = nullptr; + Window* m_btnModeFrame = nullptr; Window* m_axisModeLine = nullptr; Window* m_simModeLine = nullptr; USBChannelButtonSel* _BtnNumSel = nullptr; @@ -249,15 +248,9 @@ class USBChannelEditWindow : public Page { USBJoystickChData* cch = usbJChAddress(channel); - lv_obj_add_flag(m_btnModeFrame->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(m_axisModeLine->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(m_simModeLine->getLvObj(), LV_OBJ_FLAG_HIDDEN); - if (cch->mode == USBJOYS_CH_BUTTON) - lv_obj_clear_flag(m_btnModeFrame->getLvObj(), LV_OBJ_FLAG_HIDDEN); - else if (cch->mode == USBJOYS_CH_AXIS) - lv_obj_clear_flag(m_axisModeLine->getLvObj(), LV_OBJ_FLAG_HIDDEN); - else if (cch->mode == USBJOYS_CH_SIM) - lv_obj_clear_flag(m_simModeLine->getLvObj(), LV_OBJ_FLAG_HIDDEN); + m_btnModeFrame->show(cch->mode == USBJOYS_CH_BUTTON); + m_axisModeLine->show(cch->mode == USBJOYS_CH_AXIS); + m_simModeLine->show(cch->mode == USBJOYS_CH_SIM); if (m_btnPosChoice) m_btnPosChoice->enable((cch->param != USBJOYS_BTN_MODE_SW_EMU) && @@ -265,21 +258,21 @@ class USBChannelEditWindow : public Page if (collisionText) { collisionText->setText(""); - lv_obj_add_flag(collisionText->getLvObj(), LV_OBJ_FLAG_HIDDEN); + collisionText->hide(); if (cch->mode == USBJOYS_CH_BUTTON) { if (isUSBBtnNumCollision(channel)) { collisionText->setText(STR_USBJOYSTICK_BTN_COLLISION); - lv_obj_clear_flag(collisionText->getLvObj(), LV_OBJ_FLAG_HIDDEN); + collisionText->show(); } } else if (cch->mode == USBJOYS_CH_AXIS) { if (isUSBAxisCollision(channel)) { collisionText->setText(STR_USBJOYSTICK_AXIS_COLLISION); - lv_obj_clear_flag(collisionText->getLvObj(), LV_OBJ_FLAG_HIDDEN); + collisionText->show(); } } else if (cch->mode == USBJOYS_CH_SIM) { if (isUSBSimCollision(channel)) { collisionText->setText(STR_USBJOYSTICK_AXIS_COLLISION); - lv_obj_clear_flag(collisionText->getLvObj(), LV_OBJ_FLAG_HIDDEN); + collisionText->show(); } } } @@ -300,34 +293,34 @@ class USBChannelEditWindow : public Page channel); } - void buildBody(FormWindow* form) + void buildBody(Window* form) { - FlexGridLayout grid(ch_col_dsc, row_dsc, 2); - form->setFlexLayout(); + FlexGridLayout grid(ch_col_dsc, row_dsc, PAD_TINY); + form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); USBJoystickChData* cch = usbJChAddress(channel); - auto line = form->newLine(&grid); + auto line = form->newLine(grid); - new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_MODE, 0, + new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_MODE, COLOR_THEME_PRIMARY1); new Choice(line, rect_t{}, STR_VUSBJOYSTICK_CH_MODE, 0, USBJOYS_CH_LAST, GET_DEFAULT(cch->mode), SET_VALUE_WUPDATE(cch->mode)); #if LCD_H > LCD_W - line = form->newLine(&grid); + line = form->newLine(grid); #endif - new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_INVERSION, 0, + new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_INVERSION, COLOR_THEME_PRIMARY1); new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(cch->inversion)); - line = form->newLine(&grid); - m_btnModeFrame = new FormWindow(line, rect_t{}); + line = form->newLine(grid); + m_btnModeFrame = new Window(line, rect_t{}); m_btnModeFrame->setFlexLayout(); - line = m_btnModeFrame->newLine(&grid); - new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_BTNMODE, 0, + line = m_btnModeFrame->newLine(grid); + new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_BTNMODE, COLOR_THEME_PRIMARY1); new Choice(line, rect_t{}, STR_VUSBJOYSTICK_CH_BTNMODE, 0, USBJOYS_BTN_MODE_LAST, GET_DEFAULT(cch->param), @@ -342,45 +335,45 @@ class USBChannelEditWindow : public Page }); #if LCD_H > LCD_W - line = m_btnModeFrame->newLine(&grid); + line = m_btnModeFrame->newLine(grid); #endif - new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_SWPOS, 0, + new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_SWPOS, COLOR_THEME_PRIMARY1); m_btnPosChoice = new Choice(line, rect_t{}, STR_VUSBJOYSTICK_CH_SWPOS, 0, 7, GET_DEFAULT(cch->switch_npos), SET_VALUE_WUPDATE(cch->switch_npos)); - line = m_btnModeFrame->newLine(&grid); - new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_BTNNUM, 0, + line = m_btnModeFrame->newLine(grid); + new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_BTNNUM, COLOR_THEME_PRIMARY1); #if LCD_H > LCD_W - line = m_btnModeFrame->newLine(&grid); + line = m_btnModeFrame->newLine(grid); #endif _BtnNumSel = new USBChannelButtonSel(line, rect_t{}, channel, SET_VALUE_WUPDATE(cch->btn_num)); - m_axisModeLine = form->newLine(&grid); - new StaticText(m_axisModeLine, rect_t{}, STR_USBJOYSTICK_CH_AXIS, 0, + m_axisModeLine = form->newLine(grid); + new StaticText(m_axisModeLine, rect_t{}, STR_USBJOYSTICK_CH_AXIS, COLOR_THEME_PRIMARY1); new Choice(m_axisModeLine, rect_t{}, STR_VUSBJOYSTICK_CH_AXIS, 0, USBJOYS_AXIS_LAST, GET_DEFAULT(cch->param), SET_VALUE_WUPDATE(cch->param)); - m_simModeLine = form->newLine(&grid); - new StaticText(m_simModeLine, rect_t{}, STR_USBJOYSTICK_CH_SIM, 0, + m_simModeLine = form->newLine(grid); + new StaticText(m_simModeLine, rect_t{}, STR_USBJOYSTICK_CH_SIM, COLOR_THEME_PRIMARY1); new Choice(m_simModeLine, rect_t{}, STR_VUSBJOYSTICK_CH_SIM, 0, USBJOYS_SIM_LAST, GET_DEFAULT(cch->param), SET_VALUE_WUPDATE(cch->param)); - line = form->newLine(&grid); + line = form->newLine(grid); line->padTop(0); line->padBottom(0); collisionText = - new StaticText(line, rect_t{}, "", OPAQUE, + new StaticText(line, rect_t{}, "", FONT(BOLD) | COLOR_THEME_PRIMARY2 | CENTERED); - collisionText->setBackgroundColor(COLOR_THEME_WARNING); + etx_bg_color(collisionText->getLvObj(), COLOR_THEME_WARNING_INDEX); lv_obj_set_grid_cell(collisionText->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, USBCH_COLS, LV_GRID_ALIGN_CENTER, 0, 1); @@ -388,12 +381,11 @@ class USBChannelEditWindow : public Page } }; -class USBChannelLineButton : public Button +class USBChannelLineButton : public ListLineButton { public: USBChannelLineButton(Window* parent, uint8_t index) : - Button(parent, rect_t{}, nullptr, 0, 0, input_mix_line_create), - index(index) + ListLineButton(parent, index) { setHeight(USBCH_LINE_HEIGHT); #if LCD_W > LCD_H @@ -428,8 +420,8 @@ class USBChannelLineButton : public Button 0, USBCH_CHN_ROWS); m_inverse = - new StaticBitmap(this, rect_t{0, 0, 11, 16}, chanMonInvertedBitmap, - COLOR_THEME_SECONDARY1, false); + new StaticIcon(this, 0, 0, getBuiltinIcon(ICON_CHAN_MONITOR_INVERTED), + COLOR_THEME_SECONDARY1); lv_obj_set_grid_cell(m_inverse->getLvObj(), LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); @@ -438,6 +430,8 @@ class USBChannelLineButton : public Button LV_GRID_ALIGN_CENTER, 0, 1); m_param = lv_label_create(lvobj); + etx_txt_color(m_param, COLOR_THEME_WARNING_INDEX, ETX_STATE_COLLISION_WARN); + etx_font(m_param, FONT_BOLD_INDEX, ETX_STATE_COLLISION_WARN); lv_obj_set_grid_cell(m_param, LV_GRID_ALIGN_START, 3, 1, LV_GRID_ALIGN_CENTER, 0, 1); @@ -457,6 +451,7 @@ class USBChannelLineButton : public Button init = true; refresh(); + lv_obj_update_layout(lvobj); if (e) { @@ -465,7 +460,7 @@ class USBChannelLineButton : public Button } } - void refresh() + void refresh() override { if (!init) return; @@ -473,34 +468,30 @@ class USBChannelLineButton : public Button lv_label_set_text(m_mode, STR_VUSBJOYSTICK_CH_MODE[cch->mode]); - if (cch->inversion) - lv_obj_clear_flag(m_inverse->getLvObj(), LV_OBJ_FLAG_HIDDEN); - else - lv_obj_add_flag(m_inverse->getLvObj(), LV_OBJ_FLAG_HIDDEN); + m_inverse->show(cch->inversion); - LcdFlags warn = COLOR_THEME_SECONDARY1; - LcdFlags font = FONT(STD); const char* param = ""; - + bool hasCollision = false; + if (cch->mode == USBJOYS_CH_BUTTON) { param = STR_VUSBJOYSTICK_CH_BTNMODE[cch->param]; } else if (cch->mode == USBJOYS_CH_AXIS) { param = STR_VUSBJOYSTICK_CH_AXIS[cch->param]; if (isUSBAxisCollision(index)) { - warn = COLOR_THEME_WARNING; - font = FONT(BOLD); + hasCollision = true; } } else if (cch->mode == USBJOYS_CH_SIM) { param = STR_VUSBJOYSTICK_CH_SIM[cch->param]; if (isUSBSimCollision(index)) { - warn = COLOR_THEME_WARNING; - font = FONT(BOLD); + hasCollision = true; } } lv_label_set_text(m_param, param); - lv_obj_set_style_text_color(m_param, makeLvColor(warn), 0); - lv_obj_set_style_text_font(m_param, getFont(font), 0); + if (hasCollision) + lv_obj_add_state(m_param, ETX_STATE_COLLISION_WARN); + else + lv_obj_clear_state(m_param, ETX_STATE_COLLISION_WARN); if (cch->mode == USBJOYS_CH_BUTTON) { lv_label_set_text(m_btn_mode, @@ -514,28 +505,27 @@ class USBChannelLineButton : public Button else snprintf(str, 20, "%u", cch->btn_num); lv_label_set_text(m_btns, str); - if (isUSBBtnNumCollision(index)) { - warn = COLOR_THEME_WARNING; - font = FONT(BOLD); - } - lv_obj_set_style_text_color(m_btns, makeLvColor(warn), 0); - lv_obj_set_style_text_font(m_btns, getFont(font), 0); + if (isUSBBtnNumCollision(index)) + lv_obj_add_state(m_param, ETX_STATE_COLLISION_WARN); + else + lv_obj_clear_state(m_param, ETX_STATE_COLLISION_WARN); } else { lv_label_set_text(m_btn_mode, ""); lv_label_set_text(m_btns, ""); } } + bool isActive() const override { return false; } + protected: bool init = false; - uint8_t index; lv_obj_t* m_chn; lv_obj_t* m_mode; lv_obj_t* m_param; lv_obj_t* m_btn_mode; lv_obj_t* m_btns; - StaticBitmap* m_inverse; + StaticIcon* m_inverse; }; ModelUSBJoystickPage::ModelUSBJoystickPage() : Page(ICON_MODEL_USB) @@ -543,40 +533,38 @@ ModelUSBJoystickPage::ModelUSBJoystickPage() : Page(ICON_MODEL_USB) header.setTitle(STR_MENU_MODEL_SETUP); header.setTitle2(STR_USBJOYSTICK_LABEL); - auto form = new FormWindow(&body, rect_t{}); - form->padAll(lv_dpx(8)); - form->setFlexLayout(); - FlexGridLayout grid(line_col_dsc, row_dsc, 2); + body.setFlexLayout(); + FlexGridLayout grid(line_col_dsc, row_dsc, PAD_TINY); // Extended mode - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_USBJOYSTICK_EXTMODE, 0, + auto line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_USBJOYSTICK_EXTMODE, COLOR_THEME_PRIMARY1); new Choice(line, rect_t{}, STR_VUSBJOYSTICK_EXTMODE, 0, 1, GET_DEFAULT(g_model.usbJoystickExtMode), SET_VALUE_WUPDATE(g_model.usbJoystickExtMode)); #if LCD_H > LCD_W - line = form->newLine(&grid); + line = body.newLine(grid); #endif - _IfModeLabel = new StaticText(line, rect_t{}, STR_USBJOYSTICK_IF_MODE, 0, + _IfModeLabel = new StaticText(line, rect_t{}, STR_USBJOYSTICK_IF_MODE, COLOR_THEME_PRIMARY1); _IfMode = new Choice(line, rect_t{}, STR_VUSBJOYSTICK_IF_MODE, 0, USBJOYS_LAST, GET_DEFAULT(g_model.usbJoystickIfMode), SET_VALUE_WUPDATE(g_model.usbJoystickIfMode)); - line = form->newLine(&grid); + line = body.newLine(grid); _CircCoutoutLabel = new StaticText( - line, rect_t{}, STR_USBJOYSTICK_CIRC_COUTOUT, 0, COLOR_THEME_PRIMARY1); + line, rect_t{}, STR_USBJOYSTICK_CIRC_COUTOUT, COLOR_THEME_PRIMARY1); _CircCoutout = new Choice(line, rect_t{}, STR_VUSBJOYSTICK_CIRC_COUTOUT, 0, USBJOYS_LAST, GET_DEFAULT(g_model.usbJoystickCircularCut), SET_VALUE_WUPDATE(g_model.usbJoystickCircularCut)); #if LCD_H > LCD_W - line = form->newLine(&grid); + line = body.newLine(grid); #endif _ApplyBtn = @@ -586,10 +574,11 @@ ModelUSBJoystickPage::ModelUSBJoystickPage() : Page(ICON_MODEL_USB) return 0; }); - auto btngrp = new FormWindow(form, rect_t{}); + auto btngrp = new Window(&body, rect_t{}); + btngrp->padAll(PAD_TINY); _ChannelsGroup = btngrp; btngrp->setFlexLayout(); - btngrp->padRow(lv_dpx(4)); + btngrp->padRow(PAD_SMALL); for (uint8_t ch = 0; ch < USBJ_MAX_JOYSTICK_CHANNELS; ch++) { // Channel settings auto btn = new USBChannelLineButton(btngrp, ch); @@ -604,7 +593,6 @@ ModelUSBJoystickPage::ModelUSBJoystickPage() : Page(ICON_MODEL_USB) menu->addLine(STR_CLEAR, [=]() { memset(cch, 0, sizeof(USBJoystickChData)); SET_DIRTY(); - btn->invalidate(); }); } return 0; @@ -621,13 +609,10 @@ void ModelUSBJoystickPage::update() _CircCoutout, _ApplyBtn, _ChannelsGroup}; for (uint8_t i = 0; i < usbj_ctrls; i++) { - if (usbJoystickExtMode()) { - lv_obj_clear_flag(ctrls[i]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - _ApplyBtn->enable(usbJoystickSettingsChanged()); - } else { - lv_obj_add_flag(ctrls[i]->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + ctrls[i]->show(usbJoystickExtMode()); } + + _ApplyBtn->enable(usbJoystickSettingsChanged()); } void ModelUSBJoystickPage::editChannel(uint8_t channel, diff --git a/radio/src/gui/colorlcd/model_usbjoystick.h b/radio/src/gui/colorlcd/model_usbjoystick.h index 0d6ab5d24e8..76180888aeb 100644 --- a/radio/src/gui/colorlcd/model_usbjoystick.h +++ b/radio/src/gui/colorlcd/model_usbjoystick.h @@ -23,7 +23,7 @@ #include "page.h" -class FormWindow; +class Window; class USBChannelLineButton; class ModelUSBJoystickPage : public Page diff --git a/radio/src/gui/colorlcd/module_setup.cpp b/radio/src/gui/colorlcd/module_setup.cpp index 9220ee5782c..5940631093a 100644 --- a/radio/src/gui/colorlcd/module_setup.cpp +++ b/radio/src/gui/colorlcd/module_setup.cpp @@ -20,18 +20,18 @@ */ #include "module_setup.h" -#include "opentx.h" - -#include "form.h" -#include "choice.h" -#include "button.h" -#include "mixer_scheduler.h" #include "bind_menu_d16.h" +#include "button.h" +#include "channel_range.h" +#include "choice.h" #include "custom_failsafe.h" +#include "form.h" +#include "mixer_scheduler.h" +#include "opentx.h" #include "ppm_settings.h" -#include "channel_range.h" #include "storage/modelslist.h" +#include "themes/etx_lv_theme.h" #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) #include "pxx1_settings.h" @@ -42,8 +42,8 @@ #endif #if defined(CROSSFIRE) -#include "telemetry/crossfire.h" #include "crossfire_settings.h" +#include "telemetry/crossfire.h" #endif #if defined(AFHDS2) @@ -59,21 +59,22 @@ #endif #if defined(MULTIMODULE) +#include "io/multi_protolist.h" #include "mpm_settings.h" #include "multi_rfprotos.h" -#include "io/multi_protolist.h" #endif -#define SET_DIRTY() storageDirty(EE_MODEL) +#define SET_DIRTY() storageDirty(EE_MODEL) + +#define ETX_STATE_UNIQUE_ID_WARN LV_STATE_USER_1 static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; struct FailsafeChoice; -class ModuleWindow : public FormWindow +class ModuleWindow : public Window { public: ModuleWindow(Window* parent, uint8_t moduleIdx); @@ -89,72 +90,53 @@ class ModuleWindow : public FormWindow ModuleOptions* modOpts = nullptr; ChannelRange* chRange = nullptr; - NumberEdit *rxID = nullptr; - TextButton *bindButton = nullptr; - TextButton *rangeButton = nullptr; - TextButton *registerButton = nullptr; - Window *fsLine = nullptr; + NumberEdit* rxID = nullptr; + TextButton* bindButton = nullptr; + TextButton* rangeButton = nullptr; + TextButton* registerButton = nullptr; + Window* fsLine = nullptr; FailsafeChoice* fsChoice = nullptr; - Choice *rfPower = nullptr; - StaticText *idUnique = nullptr; + Choice* rfPower = nullptr; + StaticText* idUnique = nullptr; void startRSSIDialog(std::function closeHandler = nullptr); void updateIDStaticText(int mdIdx); }; -struct FailsafeChoice : public FormWindow { +struct FailsafeChoice : public Window { FailsafeChoice(Window* parent, uint8_t moduleIdx); void update() const; private: - lv_obj_t* c_obj; + uint8_t moduleIdx; + TextButton* optsBtn; }; -static void fs_changed(lv_event_t* e) -{ - auto obj = lv_event_get_target(e); - auto fs = (Choice*)lv_obj_get_user_data(obj); - if (!fs) return; - - auto btn_obj = (lv_obj_t*)lv_event_get_user_data(e); - if (!btn_obj) return; - - if (fs->getIntValue() == FAILSAFE_CUSTOM) { - lv_obj_clear_flag(btn_obj, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(btn_obj, LV_OBJ_FLAG_HIDDEN); - } -} - FailsafeChoice::FailsafeChoice(Window* parent, uint8_t moduleIdx) : - FormWindow(parent, rect_t{}) + Window(parent, rect_t{}), moduleIdx(moduleIdx) { - setFlexLayout(LV_FLEX_FLOW_ROW); - lv_obj_set_width(lvobj, LV_SIZE_CONTENT); + padAll(PAD_TINY); + setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); auto md = &g_model.moduleData[moduleIdx]; - auto choice = - new Choice(this, rect_t{}, STR_VFAILSAFE, 0, FAILSAFE_LAST, - GET_DEFAULT(md->failsafeMode), [=](int32_t newValue) { - md->failsafeMode = newValue; - SET_DIRTY(); - }); - - auto btn = new TextButton(this, rect_t{}, STR_SET, [=]() -> uint8_t { + new Choice(this, rect_t{}, STR_VFAILSAFE, 0, FAILSAFE_LAST, + GET_DEFAULT(md->failsafeMode), [=](int32_t newValue) { + md->failsafeMode = newValue; + optsBtn->show(newValue == FAILSAFE_CUSTOM); + SET_DIRTY(); + }); + + optsBtn = new TextButton(this, rect_t{}, STR_SET, [=]() -> uint8_t { new FailSafePage(moduleIdx); return 0; }); - - c_obj = choice->getLvObj(); - auto btn_obj = btn->getLvObj(); - lv_obj_add_event_cb(c_obj, fs_changed, LV_EVENT_VALUE_CHANGED, btn_obj); - lv_event_send(c_obj, LV_EVENT_VALUE_CHANGED, nullptr); + optsBtn->show(md->failsafeMode == FAILSAFE_CUSTOM); } void FailsafeChoice::update() const { - lv_event_send(c_obj, LV_EVENT_VALUE_CHANGED, nullptr); + optsBtn->show(g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_CUSTOM); } static void mw_refresh_cb(lv_event_t* e) @@ -167,8 +149,7 @@ static void mw_refresh_cb(lv_event_t* e) } ModuleWindow::ModuleWindow(Window* parent, uint8_t moduleIdx) : - FormWindow(parent, rect_t{}), - moduleIdx(moduleIdx) + Window(parent, rect_t{}), moduleIdx(moduleIdx) { setFlexLayout(); updateModule(); @@ -177,23 +158,22 @@ ModuleWindow::ModuleWindow(Window* parent, uint8_t moduleIdx) : void ModuleWindow::updateIDStaticText(int mdIdx) { - if(idUnique == nullptr) - return; + if (idUnique == nullptr) return; char buffer[50]; std::string idStr = STR_MODELIDUNIQUE; - if(!modelslist.isModelIdUnique(mdIdx, buffer, sizeof(buffer))) { + if (!modelslist.isModelIdUnique(mdIdx, buffer, sizeof(buffer))) { idStr = STR_MODELIDUSED; idStr = idStr + buffer; - idUnique->setTextFlags(COLOR_THEME_WARNING); + lv_obj_add_state(idUnique->getLvObj(), ETX_STATE_UNIQUE_ID_WARN); } else { - idUnique->setTextFlags(COLOR_THEME_PRIMARY1); + lv_obj_clear_state(idUnique->getLvObj(), ETX_STATE_UNIQUE_ID_WARN); } idUnique->setText(idStr); } void ModuleWindow::updateModule() { - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); clear(); modOpts = nullptr; @@ -240,22 +220,22 @@ void ModuleWindow::updateModule() #endif // Channel Range - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_CHANNELRANGE, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_CHANNELRANGE, COLOR_THEME_PRIMARY1); chRange = new ModuleChannelRange(line, moduleIdx); // Failsafe - fsLine = newLine(&grid); - new StaticText(fsLine, rect_t{}, STR_FAILSAFE, 0, COLOR_THEME_PRIMARY1); + fsLine = newLine(grid); + new StaticText(fsLine, rect_t{}, STR_FAILSAFE, COLOR_THEME_PRIMARY1); fsChoice = new FailsafeChoice(fsLine, moduleIdx); // PPM modules if (isModulePPM(moduleIdx)) { // PPM frame - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_PPMFRAME, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_PPMFRAME, COLOR_THEME_PRIMARY1); auto obj = new PpmFrameSettings(line, &md->ppm); - + // copy pointer to frame len edit object to channel range chRange->setPpmFrameLenEditObject(obj->getPpmFrameLenEditObject()); } @@ -266,22 +246,21 @@ void ModuleWindow::updateModule() if (!isModuleRFAccess(moduleIdx) && (isModuleModelIndexAvailable(moduleIdx) || isModuleBindRangeAvailable(moduleIdx))) { // Is Reciever ID Unique - if(isModuleModelIndexAvailable(moduleIdx)) { - auto line = newLine(&grid); - new StaticText(line, rect_t{},""); - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - lv_obj_set_width(box->getLvObj(), LV_SIZE_CONTENT); - idUnique = new StaticText(box, rect_t{}, "", 0, 0); + if (isModuleModelIndexAvailable(moduleIdx)) { + auto line = newLine(grid); + new StaticText(line, rect_t{}, ""); + idUnique = new StaticText(line, rect_t{}, "", COLOR_THEME_PRIMARY1); + etx_txt_color(idUnique->getLvObj(), COLOR_THEME_WARNING_INDEX, + ETX_STATE_UNIQUE_ID_WARN); updateIDStaticText(moduleIdx); } - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_RECEIVER, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_RECEIVER, COLOR_THEME_PRIMARY1); - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - lv_obj_set_width(box->getLvObj(), LV_SIZE_CONTENT); + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM, LV_SIZE_CONTENT); // Model index auto modelId = &g_model.header.modelId[moduleIdx]; @@ -302,7 +281,7 @@ void ModuleWindow::updateModule() }); if (isModuleBindRangeAvailable(moduleIdx)) { - bindButton = new TextButton(box, rect_t{},STR_MODULE_BIND); + bindButton = new TextButton(box, rect_t{}, STR_MODULE_BIND); bindButton->setPressHandler([=]() -> uint8_t { if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) { if (rangeButton) rangeButton->check(false); @@ -346,7 +325,6 @@ void ModuleWindow::updateModule() if (moduleState[moduleIdx].mode != MODULE_MODE_BIND) { if (bindButton->checked()) { bindButton->check(false); - this->invalidate(); } } #if defined(MULTIMODULE) @@ -403,11 +381,12 @@ void ModuleWindow::updateModule() else if (isModuleRFAccess(moduleIdx)) { // Register and Range buttons - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_MODULE, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_MODULE, COLOR_THEME_PRIMARY1); - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_LARGE); registerButton = new TextButton(box, rect_t{}, STR_REGISTER); registerButton->setPressHandler([=]() -> uint8_t { @@ -434,8 +413,8 @@ void ModuleWindow::updateModule() }); // Model index - line = newLine(&grid); - new StaticText(line, rect_t{}, STR_RECEIVER_NUM, 0, COLOR_THEME_PRIMARY1); + line = newLine(grid); + new StaticText(line, rect_t{}, STR_RECEIVER_NUM, COLOR_THEME_PRIMARY1); auto modelId = &g_model.header.modelId[moduleIdx]; new NumberEdit(line, rect_t{}, 0, getMaxRxNum(moduleIdx), GET_SET_DEFAULT(*modelId)); @@ -444,12 +423,13 @@ void ModuleWindow::updateModule() // R9M Power if (isModuleR9MNonAccess(moduleIdx)) { - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_RF_POWER, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_RF_POWER, COLOR_THEME_PRIMARY1); rfPower = new Choice(line, rect_t{}, 0, 0, GET_SET_DEFAULT(md->pxx.power)); - line = newLine(&grid); - new StaticText(line, rect_t{}, STR_MODULE_TELEMETRY, 0, COLOR_THEME_PRIMARY1); - new DynamicText(line, rect_t{}, [=] () { + line = newLine(grid); + new StaticText(line, rect_t{}, STR_MODULE_TELEMETRY, + COLOR_THEME_PRIMARY1); + new DynamicText(line, rect_t{}, [=]() { if (modulePortHasRx(moduleIdx)) { return std::string(STR_MODULE_TELEM_ON); } else { @@ -463,44 +443,43 @@ void ModuleWindow::updateModule() if (isModuleRFAccess(moduleIdx)) { for (uint8_t receiverIdx = 0; receiverIdx < PXX2_MAX_RECEIVERS_PER_MODULE; receiverIdx++) { - char label[] = TR_RECEIVER " X"; label[sizeof(label) - 2] = '1' + receiverIdx; - auto line = newLine(&grid); - new StaticText(line, rect_t{}, label, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, label, COLOR_THEME_PRIMARY1); new pxx2::ReceiverButton(line, rect_t{}, moduleIdx, receiverIdx); } } #endif // SBUS refresh rate if (isModuleSBUS(moduleIdx)) { - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_REFRESHRATE, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_REFRESHRATE, COLOR_THEME_PRIMARY1); - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW); + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL); auto edit = new NumberEdit( box, rect_t{}, SBUS_MIN_PERIOD, SBUS_MAX_PERIOD, - GET_DEFAULT((int16_t)md->sbus.refreshRate * - SBUS_STEPSIZE + + GET_DEFAULT((int16_t)md->sbus.refreshRate * SBUS_STEPSIZE + SBUS_DEF_PERIOD), SET_VALUE(md->sbus.refreshRate, (newValue - SBUS_DEF_PERIOD) / SBUS_STEPSIZE), - 0, PREC1); + PREC1); edit->setSuffix(STR_MS); edit->setStep(SBUS_STEPSIZE); new Choice(box, rect_t{}, STR_SBUS_INVERSION_VALUES, 0, 1, GET_SET_DEFAULT(md->sbus.noninverted)); #if defined(RADIO_TX16S) - new StaticText(this, rect_t{}, STR_WARN_5VOLTS, 0, COLOR_THEME_PRIMARY1); + new StaticText(this, rect_t{}, STR_WARN_5VOLTS, COLOR_THEME_PRIMARY1); #endif } if (isModuleGhost(moduleIdx)) { - auto line = newLine(&grid); - new StaticText(line, rect_t{}, "Raw 12 bits", 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, "Raw 12 bits", COLOR_THEME_PRIMARY1); new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(md->ghost.raw12bits)); } @@ -514,7 +493,7 @@ void ModuleWindow::updateSubType() updateRxID(); updateFailsafe(); - + if (rfPower) { if (isModuleR9M_LBT(moduleIdx)) { rfPower->setMax(R9M_LBT_POWER_MAX); @@ -531,10 +510,10 @@ void ModuleWindow::updateRxID() { if (rxID) { if (isModuleModelIndexAvailable(moduleIdx)) { - lv_obj_clear_flag(rxID->getLvObj(), LV_OBJ_FLAG_HIDDEN); + rxID->show(); rxID->update(); } else { - lv_obj_add_flag(rxID->getLvObj(), LV_OBJ_FLAG_HIDDEN); + rxID->hide(); } } } @@ -543,10 +522,10 @@ void ModuleWindow::updateFailsafe() { if (fsLine) { if (isModuleFailsafeAvailable(moduleIdx)) { - lv_obj_clear_flag(fsLine->getLvObj(), LV_OBJ_FLAG_HIDDEN); + fsLine->show(); fsChoice->update(); } else { - lv_obj_add_flag(fsLine->getLvObj(), LV_OBJ_FLAG_HIDDEN); + fsLine->hide(); } } } @@ -559,7 +538,7 @@ void ModuleWindow::startRSSIDialog(std::function closeHandler) return std::to_string((int)TELEMETRY_RSSI()) + getRxStatLabels()->unit; }, getRxStatLabels()->label, 50, - COLOR_THEME_SECONDARY1 | CENTERED | FONT(BOLD) | FONT(XL)); + COLOR_THEME_SECONDARY1 | CENTERED | FONT(XL)); rssiDialog->setCloseHandler([this, closeHandler]() { rangeButton->check(false); @@ -568,20 +547,20 @@ void ModuleWindow::startRSSIDialog(std::function closeHandler) }); } -class ModuleSubTypeChoice: public Choice +class ModuleSubTypeChoice : public Choice { uint8_t moduleIdx; -public: + public: ModuleSubTypeChoice(Window* parent, uint8_t moduleIdx); void update(); void openMenu() override; }; -ModuleSubTypeChoice::ModuleSubTypeChoice(Window *parent, uint8_t moduleIdx) : +ModuleSubTypeChoice::ModuleSubTypeChoice(Window* parent, uint8_t moduleIdx) : Choice(parent, rect_t{}, 0, 0, nullptr), moduleIdx(moduleIdx) { - ModuleData *md = &g_model.moduleData[moduleIdx]; + ModuleData* md = &g_model.moduleData[moduleIdx]; setGetValueHandler(GET_DEFAULT(md->subType)); } @@ -602,8 +581,7 @@ void ModuleSubTypeChoice::update() }); setAvailableHandler(nullptr); setTextHandler(nullptr); - } - else if (isModuleDSM2(moduleIdx)) { + } else if (isModuleDSM2(moduleIdx)) { setMin(DSM2_PROTO_LP45); setMax(DSM2_PROTO_DSMX); setValues(STR_DSM_PROTOCOLS); @@ -653,7 +631,7 @@ void ModuleSubTypeChoice::update() protos->triggerScan(); if (protos->isScanning()) { - new RfScanDialog(parent, protos, [=](){ update(); }); + new RfScanDialog(parent, protos, [=]() { update(); }); } else { TRACE("!protos->isScanning()"); } @@ -662,25 +640,26 @@ void ModuleSubTypeChoice::update() setGetValueHandler(GET_DEFAULT(md->multi.rfProtocol)); setSetValueHandler([=](int newValue) { - md->multi.rfProtocol = newValue; - md->subType = 0; - resetMultiProtocolsOptions(moduleIdx); + md->multi.rfProtocol = newValue; + md->subType = 0; + resetMultiProtocolsOptions(moduleIdx); - MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); - status.invalidate(); + MultiModuleStatus& status = getMultiModuleStatus(moduleIdx); + status.invalidate(); - uint32_t startUpdate = RTOS_GET_MS(); - while (!status.isValid() && (RTOS_GET_MS() - startUpdate < 250)); - SET_DIRTY(); - }); + uint32_t startUpdate = RTOS_GET_MS(); + while (!status.isValid() && (RTOS_GET_MS() - startUpdate < 250)) + ; + SET_DIRTY(); + }); } #endif else { - lv_obj_add_flag(lvobj, LV_OBJ_FLAG_HIDDEN); + hide(); return; } - lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_HIDDEN); + show(); // update choice value lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); @@ -692,20 +671,19 @@ void ModuleSubTypeChoice::openMenu() if (isModuleMultimodule(moduleIdx)) { auto menu = new Menu(this); - if (!menuTitle.empty()) menu->setTitle(menuTitle); + if (menuTitle) menu->setTitle(menuTitle); menu->setCloseHandler([=]() { setEditMode(false); }); setEditMode(true); - invalidate(); auto protos = MultiRfProtocols::instance(moduleIdx); - protos->fillList([=](const MultiRfProtocols::RfProto &p) { - addValue(p.label.c_str()); - menu->addLine(p.label.c_str(), [=]() { - setValue(p.proto); - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); - }); + protos->fillList([=](const MultiRfProtocols::RfProto& p) { + addValue(p.label.c_str()); + menu->addLine(p.label.c_str(), [=]() { + setValue(p.proto); + lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); }); + }); ModuleData* md = &g_model.moduleData[moduleIdx]; int idx = protos->getIndex(md->multi.rfProtocol); @@ -734,29 +712,27 @@ static void update_module_window(lv_event_t* e) ModulePage::ModulePage(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) { - const char* title2 = moduleIdx == INTERNAL_MODULE ? - STR_INTERNALRF : STR_EXTERNALRF; + const char* title2 = + moduleIdx == INTERNAL_MODULE ? STR_INTERNALRF : STR_EXTERNALRF; header.setTitle(STR_MENU_MODEL_SETUP); header.setTitle2(title2); - auto form = new FormWindow(&body, rect_t{}); - form->setFlexLayout(); - form->padAll(lv_dpx(8)); + body.setFlexLayout(); - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); // Module Type - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_MODE, 0, COLOR_THEME_PRIMARY1); + auto line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_MODE, COLOR_THEME_PRIMARY1); - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW); - lv_obj_set_width(box->getLvObj(), LV_SIZE_CONTENT); + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); ModuleData* md = &g_model.moduleData[moduleIdx]; - auto moduleChoice = new Choice(box, rect_t{}, STR_MODULE_PROTOCOLS, - MODULE_TYPE_NONE, MODULE_TYPE_COUNT - 1, - GET_DEFAULT(md->type)); + auto moduleChoice = + new Choice(box, rect_t{}, STR_MODULE_PROTOCOLS, MODULE_TYPE_NONE, + MODULE_TYPE_COUNT - 1, GET_DEFAULT(md->type)); moduleChoice->setAvailableHandler([=](int8_t moduleType) { return moduleIdx == INTERNAL_MODULE ? isInternalModuleAvailable(moduleType) @@ -764,7 +740,7 @@ ModulePage::ModulePage(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) }); auto subTypeChoice = new ModuleSubTypeChoice(box, moduleIdx); - auto moduleWindow = new ModuleWindow(form, moduleIdx); + auto moduleWindow = new ModuleWindow(&body, moduleIdx); // This needs to be after moduleWindow has been created moduleChoice->setSetValueHandler([=](int32_t newValue) { diff --git a/radio/src/gui/colorlcd/mpm_settings.cpp b/radio/src/gui/colorlcd/mpm_settings.cpp index eec23276827..5aa6dde78df 100644 --- a/radio/src/gui/colorlcd/mpm_settings.cpp +++ b/radio/src/gui/colorlcd/mpm_settings.cpp @@ -37,316 +37,294 @@ static void update_mpm_settings(lv_event_t* e) lv_event_send(ms->getParent()->getLvObj(), LV_EVENT_REFRESH, nullptr); } -struct MPMProtoOption : public FormWindow::Line -{ +class MPMProtoOption : public FormLine { + public: + MPMProtoOption(Window* form, FlexGridLayout& layout) : + FormLine(form, layout) + { + label = new StaticText(this, rect_t{}, "", COLOR_THEME_PRIMARY1); + + auto box = new Window(this, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); + + choice = new Choice(box, rect_t{}, 0, 0, nullptr); + edit = new NumberEdit(box, rect_t{}, 0, 0, nullptr); + cb = new ToggleSwitch(box, rect_t{}, nullptr, nullptr); + rssi = new DynamicNumber( + box, rect_t{}, [] { return (uint16_t)TELEMETRY_RSSI(); }, 0, + getRxStatLabels()->label, getRxStatLabels()->unit); + rssi->padTop(5); + } + + void update(const MultiRfProtocols::RfProto* rfProto, ModuleData* md, + uint8_t moduleIdx) + { + if (!rfProto || !getMultiOptionTitle(moduleIdx)) { + hide(); + return; + } + + show(); + + const char* title = getMultiOptionTitle(moduleIdx); + label->setText(title); + + choice->hide(); + edit->hide(); + cb->hide(); + rssi->hide(); + + int8_t min, max; + getMultiOptionValues(rfProto->proto, min, max); + + if (title == STR_MULTI_RFPOWER) { + choice->setValues(STR_MULTI_POWER); + choice->setMin(0); + choice->setMax(15); + choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); + choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); + choice->show(); + lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + } else if (title == STR_MULTI_TELEMETRY) { // Bayang + choice->setValues(STR_MULTI_BAYANG_OPTIONS); + choice->setMin(min); + choice->setMax(max); + choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); + choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); + choice->show(); + lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + } else if (title == + STR_MULTI_WBUS) { // e.g. WFLY2 but may not be used anymore + choice->setValues(STR_MULTI_WBUS_MODE); + choice->setMin(0); + choice->setMax(1); + choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); + choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); + choice->show(); + lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + } else if (rfProto->proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) { + edit->setMin(50); + edit->setMax(400); + edit->setGetValueHandler(GET_DEFAULT(50 + 5 * md->multi.optionValue)); + edit->setSetValueHandler( + SET_VALUE(md->multi.optionValue, (newValue - 50) / 5)); + edit->setStep(5); + edit->update(); + edit->show(); + } else if (rfProto->proto == MODULE_SUBTYPE_MULTI_DSM2) { + cb->setGetValueHandler([=]() { return md->multi.optionValue & 0x01; }); + cb->setSetValueHandler([=](int8_t newValue) { + md->multi.optionValue = (md->multi.optionValue & 0xFE) + newValue; + SET_DIRTY(); + }); + cb->update(); + cb->show(); + } else { + if (min == 0 && max == 1) { + cb->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); + cb->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); + cb->update(); + cb->show(); + } else { + edit->setMin(min); + edit->setMax(max); + edit->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); + edit->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); + edit->show(); + edit->update(); + if (title == STR_MULTI_RFTUNE) { + rssi->setPrefix(getRxStatLabels()->label); + rssi->setSuffix(getRxStatLabels()->unit); + rssi->show(); + } + } + } + } + + protected: StaticText* label; Choice* choice; NumberEdit* edit; ToggleSwitch* cb; DynamicNumber* rssi; - - MPMProtoOption(FormWindow* form, FlexGridLayout *layout); - void update(const MultiRfProtocols::RfProto* rfProto, ModuleData* md, uint8_t moduleIdx); }; -MPMProtoOption::MPMProtoOption(FormWindow* form, FlexGridLayout *layout) : - FormWindow::Line(form, layout) +static void subtype_event_cb(lv_event_t* e) { - if (layout) layout->resetPos(); - label = new StaticText(this, rect_t{}, "", 0, COLOR_THEME_PRIMARY1); - - auto box = new FormWindow(this, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, 4); - box->setWidth((LCD_W - 20) * 2 / 3); - - choice = new Choice(box, rect_t{}, 0, 0, nullptr); - edit = new NumberEdit(box, rect_t{}, 0, 0, nullptr); - cb = new ToggleSwitch(box, rect_t{}, nullptr, nullptr); - rssi = new DynamicNumber( - box, rect_t{}, [] { return (uint16_t)TELEMETRY_RSSI(); }, 0, getRxStatLabels()->label, getRxStatLabels()->unit); - rssi->padTop(5); + if (lv_event_get_param(e)) return; + auto obj = (lv_obj_t*)lv_event_get_user_data(e); + if (obj) lv_event_send(obj, LV_EVENT_VALUE_CHANGED, nullptr); } -void MPMProtoOption::update(const MultiRfProtocols::RfProto* rfProto, ModuleData* md, uint8_t moduleIdx) -{ - if (!rfProto || !getMultiOptionTitle(moduleIdx)) { - lv_obj_add_flag(lvobj, LV_OBJ_FLAG_HIDDEN); - return; +struct MPMSubtype : public FormLine { + MPMSubtype(Window* form, FlexGridLayout& layout, uint8_t moduleIdx) : + FormLine(form, layout) + { + this->moduleIdx = moduleIdx; + this->DSM2lastSubType = g_model.moduleData[this->moduleIdx].subType; + this->DSM2autoUpdated = false; + + new StaticText(this, rect_t{}, STR_RF_PROTOCOL, COLOR_THEME_PRIMARY1); + + auto md = &g_model.moduleData[moduleIdx]; + choice = new Choice( + this, rect_t{}, 0, 0, [=]() { return md->subType; }, + [=](int16_t newValue) { + md->subType = newValue; + if (!DSM2autoUpdated) // reset MPM options only if user triggered + resetMultiProtocolsOptions(moduleIdx); + DSM2autoUpdated = false; + SET_DIRTY(); + }); + + lv_obj_add_event_cb(choice->getLvObj(), subtype_event_cb, + LV_EVENT_VALUE_CHANGED, lvobj); } - lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_HIDDEN); - - const char *title = getMultiOptionTitle(moduleIdx); - label->setText(title); - - lv_obj_add_flag(choice->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(edit->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(cb->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(rssi->getLvObj(), LV_OBJ_FLAG_HIDDEN); + void update(const MultiRfProtocols::RfProto* rfProto, uint8_t moduleIdx) + { + if (!rfProto || rfProto->subProtos.size() == 0) { + hide(); + return; + } - int8_t min, max; - getMultiOptionValues(rfProto->proto, min, max); + choice->setValues(rfProto->subProtos); + choice->setMax(rfProto->subProtos.size() - 1); - if (title == STR_MULTI_RFPOWER) { - choice->setValues(STR_MULTI_POWER); - choice->setMin(0); - choice->setMax(15); - choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); - choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); - lv_obj_clear_flag(choice->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); - } else if (title == STR_MULTI_TELEMETRY) { // Bayang - choice->setValues(STR_MULTI_BAYANG_OPTIONS); - choice->setMin(min); - choice->setMax(max); - choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); - choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); - lv_obj_clear_flag(choice->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); - } else if (title == STR_MULTI_WBUS) { // e.g. WFLY2 but may not be used anymore - choice->setValues(STR_MULTI_WBUS_MODE); - choice->setMin(0); - choice->setMax(1); - choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); - choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); - lv_obj_clear_flag(choice->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); - } else if (rfProto->proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) { - edit->setMin(50); - edit->setMax(400); - edit->setGetValueHandler(GET_DEFAULT(50 + 5 * md->multi.optionValue)); - edit->setSetValueHandler(SET_VALUE(md->multi.optionValue, (newValue - 50) / 5)); - edit->setStep(5); - edit->update(); - lv_obj_clear_flag(edit->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } else if (rfProto->proto == MODULE_SUBTYPE_MULTI_DSM2) { - cb->setGetValueHandler([=]() { return md->multi.optionValue & 0x01; }); - cb->setSetValueHandler([=](int8_t newValue) { - md->multi.optionValue = (md->multi.optionValue & 0xFE) + newValue; - SET_DIRTY(); - }); - cb->update(); - lv_obj_clear_flag(cb->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } else { - if (min == 0 && max == 1) { - cb->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); - cb->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); - cb->update(); - lv_obj_clear_flag(cb->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } else { - edit->setMin(min); - edit->setMax(max); - edit->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); - edit->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); - lv_obj_clear_flag(edit->getLvObj(), LV_OBJ_FLAG_HIDDEN); - edit->update(); - if (title == STR_MULTI_RFTUNE) { - rssi->setPrefix(getRxStatLabels()->label); - rssi->setSuffix(getRxStatLabels()->unit); - lv_obj_clear_flag(rssi->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } - } - } -} + show(); -struct MPMSubtypeChoice : public Choice { - MPMSubtypeChoice(Window* parent, std::function get, - std::function set) : - Choice(parent, rect_t{}, 0, 0, get, set) - { + bool stop = true; + lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, &stop); } - std::string getLabelText() override + void checkEvents() { - if (_getValue) { - int val = _getValue(); - val -= vmin; - if (val >= 0 && val < (int)values.size()) { - return values[val]; - } else { - return std::to_string(val); + // + // DSM2: successful bind in auto mode changes DSM2 subType + // + ModuleData* md = &g_model.moduleData[this->moduleIdx]; + + if (md->multi.rfProtocol == + MODULE_SUBTYPE_MULTI_DSM2) { // do this only for DSM2 + uint8_t subType = md->subType; // fetch DSM2 subType + + if (subType != DSM2lastSubType) { // if DSM2 subType has auto changed + DSM2autoUpdated = true; // indicate this was not user triggered + DSM2lastSubType = subType; // memorize new DSM2 subType + choice->setValue(subType); // set new DSM2 subType + lv_event_send(choice->getLvObj(), LV_EVENT_REFRESH, + nullptr); // refresh subType field } } - return std::string(); } -}; - -struct MPMSubtype : public FormWindow::Line -{ - MPMSubtypeChoice* choice; - - MPMSubtype(FormWindow* form, FlexGridLayout *layout, uint8_t moduleIdx); - void update(const MultiRfProtocols::RfProto* rfProto, uint8_t moduleIdx); - void checkEvents(); - protected: - uint8_t moduleIdx; - uint8_t DSM2lastSubType; - bool DSM2autoUpdated; + protected: + Choice* choice; + uint8_t moduleIdx; + uint8_t DSM2lastSubType; + bool DSM2autoUpdated; }; -void MPMSubtype::checkEvents() { - // - // DSM2: successful bind in auto mode changes DSM2 subType - // - ModuleData* md = &g_model.moduleData[this->moduleIdx]; +struct MPMDSMCloned : public FormLine { + MPMDSMCloned(Window* form, FlexGridLayout& layout, uint8_t moduleIdx) : + FormLine(form, layout) + { + new StaticText(this, rect_t{}, STR_SUBTYPE, COLOR_THEME_PRIMARY1); - if(md->multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2) { // do this only for DSM2 - uint8_t subType = md->subType; // fetch DSM2 subType + auto md = &g_model.moduleData[moduleIdx]; + choice = new Choice(this, rect_t{}, STR_MULTI_DSM_CLONE, 0, 1, 0, 0); - if(subType != DSM2lastSubType) { // if DSM2 subType has auto changed - DSM2autoUpdated = true; // indicate this was not user triggered - DSM2lastSubType = subType; // memorize new DSM2 subType - choice->setValue(subType); // set new DSM2 subType - lv_event_send(choice->getLvObj(), LV_EVENT_REFRESH, nullptr); // refresh subType field - } + choice->setGetValueHandler( + GET_DEFAULT((md->multi.optionValue & 0x04) >> 2)); + choice->setSetValueHandler( + SET_VALUE(md->multi.optionValue, + (md->multi.optionValue & 0xFB) + (newValue << 2))); } -} - -static void subtype_event_cb(lv_event_t* e) -{ - if (lv_event_get_param(e)) return; - auto obj = (lv_obj_t*)lv_event_get_user_data(e); - if (obj) lv_event_send(obj, LV_EVENT_VALUE_CHANGED, nullptr); -} -MPMSubtype::MPMSubtype(FormWindow* form, FlexGridLayout* layout, - uint8_t moduleIdx) : - FormWindow::Line(form, layout) -{ - this->moduleIdx = moduleIdx; - this->DSM2lastSubType = g_model.moduleData[this->moduleIdx].subType; - this->DSM2autoUpdated = false; - - if (layout) layout->resetPos(); - new StaticText(this, rect_t{}, STR_RF_PROTOCOL, 0, COLOR_THEME_PRIMARY1); - - auto md = &g_model.moduleData[moduleIdx]; - choice = new MPMSubtypeChoice( - this, [=]() { return md->subType; }, - [=](int16_t newValue) { - md->subType = newValue; - if (!DSM2autoUpdated) // reset MPM options only if user triggered - resetMultiProtocolsOptions(moduleIdx); - DSM2autoUpdated = false; - SET_DIRTY(); - }); - - lv_obj_add_event_cb(choice->getLvObj(), subtype_event_cb, - LV_EVENT_VALUE_CHANGED, lvobj); -} - -void MPMSubtype::update(const MultiRfProtocols::RfProto* rfProto, uint8_t moduleIdx) -{ - if (!rfProto || rfProto->subProtos.size() == 0) { - lv_obj_add_flag(lvobj, LV_OBJ_FLAG_HIDDEN); - return; + void update() const + { + lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } - choice->setValues(rfProto->subProtos); - choice->setMax(rfProto->subProtos.size() - 1); - - lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_HIDDEN); - - bool stop=true; - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, &stop); -} - -struct MPMDSMCloned : public FormWindow::Line { - MPMDSMCloned(FormWindow* form, FlexGridLayout* layout, uint8_t moduleIdx); - void update() const { lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } - private: Choice* choice; }; -MPMDSMCloned::MPMDSMCloned(FormWindow* form, FlexGridLayout *layout, uint8_t moduleIdx) : - FormWindow::Line(form, layout) -{ - if (layout) layout->resetPos(); - new StaticText(this, rect_t{}, STR_SUBTYPE, 0, COLOR_THEME_PRIMARY1); +struct MPMServoRate : public FormLine { + MPMServoRate(Window* form, FlexGridLayout& layout, uint8_t moduleIdx) : + FormLine(form, layout) + { + new StaticText(this, rect_t{}, STR_MULTI_SERVOFREQ, + COLOR_THEME_PRIMARY1); - auto md = &g_model.moduleData[moduleIdx]; - choice = new Choice(this, rect_t{}, STR_MULTI_DSM_CLONE, 0, 1, 0, 0); + auto md = &g_model.moduleData[moduleIdx]; + choice = new Choice(this, rect_t{}, STR_MULTI_DSM_OPTIONS, 0, 1, 0, 0); - choice->setGetValueHandler(GET_DEFAULT((md->multi.optionValue & 0x04) >> 2)); - choice->setSetValueHandler(SET_VALUE( - md->multi.optionValue, (md->multi.optionValue & 0xFB) + (newValue << 2))); -} + choice->setGetValueHandler( + GET_DEFAULT((md->multi.optionValue & 0x02) >> 1)); + choice->setSetValueHandler( + SET_VALUE(md->multi.optionValue, + (md->multi.optionValue & 0xFD) + (newValue << 1))); + } -struct MPMServoRate : public FormWindow::Line { - MPMServoRate(FormWindow* form, FlexGridLayout* layout, uint8_t moduleIdx); - void update() const { lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } + void update() const + { + lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + } private: Choice* choice; }; -MPMServoRate::MPMServoRate(FormWindow* form, FlexGridLayout *layout, uint8_t moduleIdx) : - FormWindow::Line(form, layout) -{ - if (layout) layout->resetPos(); - new StaticText(this, rect_t{}, STR_MULTI_SERVOFREQ, 0, COLOR_THEME_PRIMARY1); - - auto md = &g_model.moduleData[moduleIdx]; - choice = new Choice(this, rect_t{}, STR_MULTI_DSM_OPTIONS, 0, 1, 0, 0); +struct MPMAutobind : public FormLine { + MPMAutobind(Window* form, FlexGridLayout& layout, uint8_t moduleIdx) : + FormLine(form, layout) + { + new StaticText(this, rect_t{}, STR_MULTI_AUTOBIND, COLOR_THEME_PRIMARY1); - choice->setGetValueHandler(GET_DEFAULT((md->multi.optionValue & 0x02) >> 1)); - choice->setSetValueHandler(SET_VALUE( - md->multi.optionValue, (md->multi.optionValue & 0xFD) + (newValue << 1))); -} + auto md = &g_model.moduleData[moduleIdx]; + cb = new ToggleSwitch(this, rect_t{}, + GET_SET_DEFAULT(md->multi.autoBindMode)); + } -struct MPMAutobind : public FormWindow::Line { - MPMAutobind(FormWindow* form, FlexGridLayout* layout, uint8_t moduleIdx); void update() const { cb->update(); } private: ToggleSwitch* cb; }; -MPMAutobind::MPMAutobind(FormWindow* form, FlexGridLayout *layout, uint8_t moduleIdx) : - FormWindow::Line(form, layout) -{ - if (layout) layout->resetPos(); - new StaticText(this, rect_t{}, STR_MULTI_AUTOBIND, 0, COLOR_THEME_PRIMARY1); +struct MPMChannelMap : public FormLine { + MPMChannelMap(Window* form, FlexGridLayout& layout, uint8_t moduleIdx) : + FormLine(form, layout) + { + new StaticText(this, rect_t{}, STR_DISABLE_CH_MAP, COLOR_THEME_PRIMARY1); - auto md = &g_model.moduleData[moduleIdx]; - cb = new ToggleSwitch(this, rect_t{}, GET_SET_DEFAULT(md->multi.autoBindMode)); -} + auto md = &g_model.moduleData[moduleIdx]; + cb = new ToggleSwitch(this, rect_t{}, + GET_SET_DEFAULT(md->multi.disableMapping)); + } + + void update(const MultiRfProtocols::RfProto* rfProto) + { + if (rfProto && rfProto->supportsDisableMapping()) { + show(); + cb->update(); + } else { + hide(); + } + } -struct MPMChannelMap : public FormWindow::Line -{ - MPMChannelMap(FormWindow* form, FlexGridLayout *layout, uint8_t moduleIdx); - void update(const MultiRfProtocols::RfProto* rfProto); private: ToggleSwitch* cb; }; -MPMChannelMap::MPMChannelMap(FormWindow* form, FlexGridLayout *layout, uint8_t moduleIdx) : - FormWindow::Line(form, layout) -{ - if (layout) layout->resetPos(); - new StaticText(this, rect_t{}, STR_DISABLE_CH_MAP, 0, COLOR_THEME_PRIMARY1); - - auto md = &g_model.moduleData[moduleIdx]; - cb = new ToggleSwitch(this, rect_t{}, GET_SET_DEFAULT(md->multi.disableMapping)); -} - -void MPMChannelMap::update(const MultiRfProtocols::RfProto* rfProto) -{ - if (rfProto && rfProto->supportsDisableMapping()) { - lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_HIDDEN); - cb->update(); - } else { - lv_obj_add_flag(lvobj, LV_OBJ_FLAG_HIDDEN); - } -} - -MultimoduleSettings::MultimoduleSettings(Window *parent, - const FlexGridLayout &g, +MultimoduleSettings::MultimoduleSettings(Window* parent, + const FlexGridLayout& g, uint8_t moduleIdx) : - FormWindow(parent, rect_t{}), md(&g_model.moduleData[moduleIdx]), - moduleIdx(moduleIdx) + Window(parent, rect_t{}), + md(&g_model.moduleData[moduleIdx]), + moduleIdx(moduleIdx) { FlexGridLayout grid(g); setFlexLayout(); @@ -354,14 +332,14 @@ MultimoduleSettings::MultimoduleSettings(Window *parent, // TODO: needs to be placed differently // MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); // if (status.protocolName[0] && status.isValid()) { - // new StaticText(this, grid.getFieldSlot(2, 1), status.protocolName, 0, + // new StaticText(this, grid.getFieldSlot(2, 1), status.protocolName, // COLOR_THEME_PRIMARY1); // grid.nextLine(); // } // Multimodule status - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_MODULE_STATUS, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_MODULE_STATUS, COLOR_THEME_PRIMARY1); new DynamicText( line, rect_t{}, [=] { @@ -371,29 +349,31 @@ MultimoduleSettings::MultimoduleSettings(Window *parent, }, COLOR_THEME_PRIMARY1); - st_line = new MPMSubtype(this, &grid, moduleIdx); + st_line = new MPMSubtype(this, grid, moduleIdx); lv_obj_add_event_cb(st_line->getLvObj(), update_mpm_settings, LV_EVENT_VALUE_CHANGED, this); - cl_line = new MPMDSMCloned(this, &grid, moduleIdx); - opt_line = new MPMProtoOption(this, &grid); - sr_line = new MPMServoRate(this, &grid, moduleIdx); - ab_line = new MPMAutobind(this, &grid, moduleIdx); + cl_line = new MPMDSMCloned(this, grid, moduleIdx); + opt_line = new MPMProtoOption(this, grid); + sr_line = new MPMServoRate(this, grid, moduleIdx); + ab_line = new MPMAutobind(this, grid, moduleIdx); // Low power mode - line = newLine(&grid); - new StaticText(line, rect_t{}, STR_MULTI_LOWPOWER, 0, COLOR_THEME_PRIMARY1); - lp_mode = new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(md->multi.lowPowerMode)); + line = newLine(grid); + new StaticText(line, rect_t{}, STR_MULTI_LOWPOWER, COLOR_THEME_PRIMARY1); + lp_mode = + new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(md->multi.lowPowerMode)); #if defined(MANUFACTURER_FRSKY) // Disable telemetry - line = newLine(&grid); - new StaticText(line, rect_t{}, STR_DISABLE_TELEM, 0, COLOR_THEME_PRIMARY1); - disable_telem = new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(md->multi.disableTelemetry)); + line = newLine(grid); + new StaticText(line, rect_t{}, STR_DISABLE_TELEM, COLOR_THEME_PRIMARY1); + disable_telem = new ToggleSwitch(line, rect_t{}, + GET_SET_DEFAULT(md->multi.disableTelemetry)); #endif - cm_line = new MPMChannelMap(this, &grid, moduleIdx); + cm_line = new MPMChannelMap(this, grid, moduleIdx); // Ensure elements properly initalised update(); @@ -409,20 +389,20 @@ void MultimoduleSettings::update() auto multi_proto = md->multi.rfProtocol; if (multi_proto == MODULE_SUBTYPE_MULTI_DSM2) { - lv_obj_clear_flag(sr_line->getLvObj(), LV_OBJ_FLAG_HIDDEN); + sr_line->show(); sr_line->update(); - lv_obj_add_flag(ab_line->getLvObj(), LV_OBJ_FLAG_HIDDEN); + ab_line->hide(); } else { - lv_obj_add_flag(sr_line->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(ab_line->getLvObj(), LV_OBJ_FLAG_HIDDEN); + sr_line->hide(); + ab_line->show(); ab_line->update(); } if (isMultiProtocolDSMCloneAvailable(moduleIdx)) { - lv_obj_clear_flag(cl_line->getLvObj(), LV_OBJ_FLAG_HIDDEN); + cl_line->show(); cl_line->update(); } else { - lv_obj_add_flag(cl_line->getLvObj(), LV_OBJ_FLAG_HIDDEN); + cl_line->hide(); } lp_mode->update(); diff --git a/radio/src/gui/colorlcd/mpm_settings.h b/radio/src/gui/colorlcd/mpm_settings.h index 30d385a8a7a..6a9b22e1207 100644 --- a/radio/src/gui/colorlcd/mpm_settings.h +++ b/radio/src/gui/colorlcd/mpm_settings.h @@ -34,7 +34,7 @@ struct MPMServoRate; struct MPMAutobind; struct MPMChannelMap; -class MultimoduleSettings : public FormWindow, public ModuleOptions +class MultimoduleSettings : public Window, public ModuleOptions { ModuleData* md; uint8_t moduleIdx; diff --git a/radio/src/gui/colorlcd/multi_rfprotos.cpp b/radio/src/gui/colorlcd/multi_rfprotos.cpp index 6024c34d7ac..8c3d4684bd2 100644 --- a/radio/src/gui/colorlcd/multi_rfprotos.cpp +++ b/radio/src/gui/colorlcd/multi_rfprotos.cpp @@ -49,6 +49,6 @@ void RfScanDialog::checkEvents() lastUpdate = RTOS_GET_MS(); } - Dialog::checkEvents(); + ProgressDialog::checkEvents(); } diff --git a/radio/src/gui/colorlcd/output_edit.cpp b/radio/src/gui/colorlcd/output_edit.cpp index 496acd1c14e..cd2b9f80024 100644 --- a/radio/src/gui/colorlcd/output_edit.cpp +++ b/radio/src/gui/colorlcd/output_edit.cpp @@ -20,21 +20,24 @@ */ #include "output_edit.h" + #include "channel_bar.h" #include "gvar_numberedit.h" - #include "opentx.h" +#include "themes/etx_lv_theme.h" #define SET_DIRTY() storageDirty(EE_MODEL) +#define ETX_STATE_MINMAX_HIGHLIGHT LV_STATE_USER_1 + #if (LCD_W > LCD_H) - #define OUTPUT_EDIT_STATUS_BAR_WIDTH 250 - #define OUTPUT_EDIT_STATUS_BAR_MARGIN 3 - #define OUTPUT_EDIT_RIGHT_MARGIN 0 +#define OUTPUT_EDIT_STATUS_BAR_WIDTH 250 +#define OUTPUT_EDIT_STATUS_BAR_MARGIN 3 +#define OUTPUT_EDIT_RIGHT_MARGIN 0 #else - #define OUTPUT_EDIT_STATUS_BAR_WIDTH 180 - #define OUTPUT_EDIT_STATUS_BAR_MARGIN 0 - #define OUTPUT_EDIT_RIGHT_MARGIN 3 +#define OUTPUT_EDIT_STATUS_BAR_WIDTH 180 +#define OUTPUT_EDIT_STATUS_BAR_MARGIN 0 +#define OUTPUT_EDIT_RIGHT_MARGIN 3 #endif class OutputEditStatusBar : public Window @@ -43,15 +46,11 @@ class OutputEditStatusBar : public Window OutputEditStatusBar(Window *parent, const rect_t &rect, int8_t channel) : Window(parent, rect), _channel(channel) { - channelBar = new ComboChannelBar(this, {OUTPUT_EDIT_STATUS_BAR_MARGIN, 0, rect.w - (OUTPUT_EDIT_STATUS_BAR_MARGIN * 2), rect.h}, channel); - channelBar->setLeftMargin(15); - channelBar->setTextColor(COLOR_THEME_PRIMARY2); - channelBar->setOutputChannelBarLimitColor(COLOR_THEME_EDIT); - } - - void paint(BitmapBuffer *dc) override - { - // dc->clear(COLOR_THEME_SECONDARY2); + channelBar = new ComboChannelBar( + this, + {OUTPUT_EDIT_STATUS_BAR_MARGIN, 0, + rect.w - (OUTPUT_EDIT_STATUS_BAR_MARGIN * 2), rect.h}, + channel, true); } protected: @@ -66,12 +65,8 @@ OutputEditWindow::OutputEditWindow(uint8_t channel) : header.setTitle(STR_MENULIMITS); header.setTitle2(title2); - auto form = new FormWindow(&body, rect_t{}); - auto form_obj = form->getLvObj(); - lv_obj_set_style_pad_all(form_obj, lv_dpx(8), 0); - buildBody(form); - buildHeader(&header); + buildBody(&body); } void OutputEditWindow::checkEvents() @@ -82,38 +77,21 @@ void OutputEditWindow::checkEvents() int chanVal = calcRESXto100(ex_chans[channel]); - if(chanVal < -DEADBAND) { - lv_obj_set_style_text_font(minEdit->getLvObj(), getFont(FONT(BOLD)), 0); - minText->setBackgroudOpacity(LV_OPA_COVER); - minText->setFont(FONT(BOLD)); - - lv_obj_set_style_text_font(maxEdit->getLvObj(), getFont(FONT(STD)), 0); - maxText->setBackgroudOpacity(LV_OPA_TRANSP); - maxText->setFont(FONT(STD)); + if (chanVal < -DEADBAND) { + lv_obj_add_state(minText->getLvObj(), ETX_STATE_MINMAX_HIGHLIGHT); + lv_obj_add_state(minEdit->getLvObj(), ETX_STATE_MINMAX_HIGHLIGHT); } else { - if(chanVal > DEADBAND) { - lv_obj_set_style_text_font(minEdit->getLvObj(), getFont(FONT(STD)), 0); - minText->setBackgroudOpacity(LV_OPA_TRANSP); - minText->setFont(FONT(STD)); - - lv_obj_set_style_text_font(maxEdit->getLvObj(), getFont(FONT(BOLD)), 0); - maxText->setBackgroudOpacity(LV_OPA_COVER); - maxText->setFont(FONT(BOLD)); - } else { - lv_obj_set_style_text_font(minEdit->getLvObj(), getFont(FONT(STD)), 0); - minText->setBackgroudOpacity(LV_OPA_TRANSP); - minText->setFont(FONT(STD)); - - lv_obj_set_style_text_font(maxEdit->getLvObj(), getFont(FONT(STD)), 0); - maxText->setBackgroudOpacity(LV_OPA_TRANSP); - maxText->setFont(FONT(STD)); - } + lv_obj_clear_state(minText->getLvObj(), ETX_STATE_MINMAX_HIGHLIGHT); + lv_obj_clear_state(minEdit->getLvObj(), ETX_STATE_MINMAX_HIGHLIGHT); } - minText->invalidate(); - maxText->invalidate(); - minEdit->invalidate(); - maxEdit->invalidate(); + if (chanVal > DEADBAND) { + lv_obj_add_state(maxText->getLvObj(), ETX_STATE_MINMAX_HIGHLIGHT); + lv_obj_add_state(maxEdit->getLvObj(), ETX_STATE_MINMAX_HIGHLIGHT); + } else { + lv_obj_clear_state(maxText->getLvObj(), ETX_STATE_MINMAX_HIGHLIGHT); + lv_obj_clear_state(maxEdit->getLvObj(), ETX_STATE_MINMAX_HIGHLIGHT); + } } Window::checkEvents(); @@ -141,80 +119,88 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; #endif -void OutputEditWindow::buildBody(FormWindow* form) +void OutputEditWindow::buildBody(Window *form) { - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); form->setFlexLayout(); int limit = (g_model.extendedLimits ? LIMIT_EXT_MAX : LIMIT_STD_MAX); LimitData *output = limitAddress(channel); // Name - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); + auto line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); new ModelTextEdit(line, rect_t{}, output->name, sizeof(output->name)); // Offset - new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_SUBTRIM, 0, + new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_SUBTRIM, COLOR_THEME_PRIMARY1); auto off = new GVarNumberEdit(line, rect_t{}, -LIMIT_STD_MAX, +LIMIT_STD_MAX, - GET_SET_DEFAULT(output->offset), PREC1); + GET_SET_DEFAULT(output->offset), PREC1); off->setFastStep(20); off->setAccelFactor(8); // Min - line = form->newLine(&grid); - minText = new StaticText(line, rect_t{}, TR_MIN, 0, COLOR_THEME_PRIMARY1); - minEdit = new GVarNumberEdit(line, rect_t{}, -limit, 0, GET_SET_DEFAULT(output->min), - PREC1, -LIMIT_STD_MAX, -limit); - minText->setBackgroundColor(COLOR_THEME_ACTIVE); + line = form->newLine(grid); + minText = new StaticText(line, rect_t{}, TR_MIN, COLOR_THEME_PRIMARY1); + etx_solid_bg(minText->getLvObj(), COLOR_THEME_ACTIVE_INDEX, ETX_STATE_MINMAX_HIGHLIGHT); + etx_font(minText->getLvObj(), FONT_BOLD_INDEX, ETX_STATE_MINMAX_HIGHLIGHT); + minEdit = new GVarNumberEdit(line, rect_t{}, -limit, 0, + GET_SET_DEFAULT(output->min), PREC1, + -LIMIT_STD_MAX, -limit); + etx_font(minEdit->getLvObj(), FONT_BOLD_INDEX, ETX_STATE_MINMAX_HIGHLIGHT); minEdit->setFastStep(20); minEdit->setAccelFactor(16); // Max - maxText = new StaticText(line, rect_t{}, TR_MAX, 0, COLOR_THEME_PRIMARY1); - maxEdit = new GVarNumberEdit(line, rect_t{}, 0, +limit, GET_SET_DEFAULT(output->max), - PREC1, +LIMIT_STD_MAX, limit); - maxText->setBackgroundColor(COLOR_THEME_ACTIVE); + maxText = new StaticText(line, rect_t{}, TR_MAX, COLOR_THEME_PRIMARY1); + etx_solid_bg(maxText->getLvObj(), COLOR_THEME_ACTIVE_INDEX, ETX_STATE_MINMAX_HIGHLIGHT); + etx_font(maxText->getLvObj(), FONT_BOLD_INDEX, ETX_STATE_MINMAX_HIGHLIGHT); + maxEdit = new GVarNumberEdit(line, rect_t{}, 0, +limit, + GET_SET_DEFAULT(output->max), PREC1, + +LIMIT_STD_MAX, limit); + etx_font(maxEdit->getLvObj(), FONT_BOLD_INDEX, ETX_STATE_MINMAX_HIGHLIGHT); maxEdit->setFastStep(20); maxEdit->setAccelFactor(16); // Direction - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_INVERTED, 0, COLOR_THEME_PRIMARY1); + line = form->newLine(grid); + new StaticText(line, rect_t{}, STR_INVERTED, COLOR_THEME_PRIMARY1); new ToggleSwitch(line, rect_t{}, GET_DEFAULT(output->revert), - [output, this](uint8_t newValue) { - output->revert = newValue; - SET_DIRTY(); - }); + [output, this](uint8_t newValue) { + output->revert = newValue; + SET_DIRTY(); + }); // Curve - new StaticText(line, rect_t{}, TR_CURVE, 0, COLOR_THEME_PRIMARY1); + new StaticText(line, rect_t{}, TR_CURVE, COLOR_THEME_PRIMARY1); auto edit = new NumberEdit(line, rect_t{}, -MAX_CURVES, +MAX_CURVES, GET_SET_DEFAULT(output->curve)); edit->setDisplayHandler( [](int32_t value) { return std::string(getCurveString(value)); }); // PPM center - line = form->newLine(&grid); - auto label = new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_PPMCENTER, 0, + line = form->newLine(grid); + auto label = new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_PPMCENTER, COLOR_THEME_PRIMARY1); lv_label_set_long_mode(label->getLvObj(), LV_LABEL_LONG_WRAP); - lv_obj_set_style_grid_cell_x_align(label->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); + lv_obj_set_style_grid_cell_x_align(label->getLvObj(), LV_GRID_ALIGN_STRETCH, + 0); - auto center = new NumberEdit(line, rect_t{}, PPM_CENTER - PPM_CENTER_MAX, - PPM_CENTER + PPM_CENTER_MAX, - GET_VALUE(output->ppmCenter + PPM_CENTER), - SET_VALUE(output->ppmCenter, newValue - PPM_CENTER)); + auto center = new NumberEdit( + line, rect_t{}, PPM_CENTER - PPM_CENTER_MAX, PPM_CENTER + PPM_CENTER_MAX, + GET_VALUE(output->ppmCenter + PPM_CENTER), + SET_VALUE(output->ppmCenter, newValue - PPM_CENTER)); center->setFastStep(20); center->setAccelFactor(8); center->setDefault(PPM_CENTER); // Subtrims mode - label = new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_SUBTRIMMODE, 0, + label = new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_SUBTRIMMODE, COLOR_THEME_PRIMARY1); lv_label_set_long_mode(label->getLvObj(), LV_LABEL_LONG_WRAP); - lv_obj_set_style_grid_cell_x_align(label->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); + lv_obj_set_style_grid_cell_x_align(label->getLvObj(), LV_GRID_ALIGN_STRETCH, + 0); new Choice(line, rect_t{}, STR_SUBTRIMMODES, 0, 1, GET_SET_DEFAULT(output->symetrical)); diff --git a/radio/src/gui/colorlcd/output_edit.h b/radio/src/gui/colorlcd/output_edit.h index 94796f0be24..c1261444986 100644 --- a/radio/src/gui/colorlcd/output_edit.h +++ b/radio/src/gui/colorlcd/output_edit.h @@ -49,5 +49,5 @@ class OutputEditWindow : public Page void checkEvents() override; void buildHeader(Window *window); - void buildBody(FormWindow *window); + void buildBody(Window *window); }; diff --git a/radio/src/gui/colorlcd/page.cpp b/radio/src/gui/colorlcd/page.cpp index 17589909217..2db8c989a2c 100644 --- a/radio/src/gui/colorlcd/page.cpp +++ b/radio/src/gui/colorlcd/page.cpp @@ -20,77 +20,69 @@ */ #include "page.h" -#include "mainwindow.h" + #include "keyboard_base.h" +#include "mainwindow.h" #include "opentx.h" #include "theme.h" +#include "themes/etx_lv_theme.h" -PageHeader::PageHeader(Page * parent, uint8_t icon): - FormWindow(parent, { 0, 0, LCD_W, MENU_HEADER_HEIGHT }, OPAQUE), - icon(icon) +PageHeader::PageHeader(Page* parent, EdgeTxIcon icon) : + Window(parent, {0, 0, LCD_W, MENU_HEADER_HEIGHT}, + NO_FOCUS | OPAQUE | DONT_TRASH), + icon(icon) { -#if defined(HARDWARE_TOUCH) - new Button(this, { 0, 0, MENU_HEADER_BACK_BUTTON_WIDTH, MENU_HEADER_BACK_BUTTON_HEIGHT }, - [=]() -> uint8_t { - parent->onCancel(); - return 0; - }, NO_FOCUS); -#endif + etx_solid_bg(lvobj, COLOR_THEME_SECONDARY1_INDEX); + + new HeaderIcon(this, icon); + title = new StaticText(this, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, - "", 0, COLOR_THEME_PRIMARY2); + "", COLOR_THEME_PRIMARY2); } StaticText* PageHeader::setTitle2(std::string txt) { if (title2 == nullptr) { - title2 = new StaticText(this, + title2 = new StaticText(this, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, - "", 0, COLOR_THEME_PRIMARY2); + "", COLOR_THEME_PRIMARY2); } title2->setText(std::move(txt)); return title2; } -void PageHeader::paint(BitmapBuffer * dc) -{ - EdgeTxTheme::instance()->drawPageHeaderBackground(dc, getIcon(), nullptr); - dc->drawSolidFilledRect(MENU_HEADER_HEIGHT, 0, LCD_W - MENU_HEADER_HEIGHT, - MENU_HEADER_HEIGHT, COLOR_THEME_SECONDARY1); -} - -static constexpr rect_t _get_body_rect() +Page::Page(EdgeTxIcon icon, PaddingSize padding) : + NavWindow(MainWindow::instance(), {0, 0, LCD_W, LCD_H}), + header(this, icon), + body(this, {0, MENU_HEADER_HEIGHT, LCD_W, LCD_H - MENU_HEADER_HEIGHT}, + NO_FOCUS | DONT_TRASH) { - return { 0, MENU_HEADER_HEIGHT, LCD_W, LCD_H - MENU_HEADER_HEIGHT }; -} + etx_solid_bg(lvobj); + lv_obj_set_style_max_height(body.getLvObj(), LCD_H - MENU_HEADER_HEIGHT, + LV_PART_MAIN); + etx_scrollbar(body.getLvObj()); -Page::Page(unsigned icon): - NavWindow(Layer::back(), {0, 0, LCD_W, LCD_H}, OPAQUE), - header(this, icon), - body(this, _get_body_rect()) -{ + Layer::back()->hide(); Layer::push(this); - lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY3), 0); + body.padAll(padding); - body.padAll(0); - lv_obj_set_scrollbar_mode(body.getLvObj(), LV_SCROLLBAR_MODE_AUTO); +#if defined(HARDWARE_TOUCH) + addBackButton(); +#endif } void Page::deleteLater(bool detach, bool trash) { Layer::pop(this); + Layer::back()->show(); - header.deleteLater(true, false); - body.deleteLater(true, false); Window::deleteLater(detach, trash); } -void Page::onCancel() -{ - deleteLater(); -} +void Page::onCancel() { deleteLater(); } void Page::onClicked() { Keyboard::hide(false); } diff --git a/radio/src/gui/colorlcd/page.h b/radio/src/gui/colorlcd/page.h index d1f301957b5..0cced1a94da 100644 --- a/radio/src/gui/colorlcd/page.h +++ b/radio/src/gui/colorlcd/page.h @@ -19,28 +19,26 @@ * GNU General Public License for more details. */ -#ifndef _PAGE_H_ -#define _PAGE_H_ +#pragma once -#include "window.h" +#include "bitmaps.h" #include "button.h" #include "static.h" +#include "window.h" class Page; -class PageHeader : public FormWindow +class PageHeader : public Window { public: - PageHeader(Page* parent, uint8_t icon); + PageHeader(Page* parent, EdgeTxIcon icon); - uint8_t getIcon() const { return icon; } + EdgeTxIcon getIcon() const { return icon; } void setTitle(std::string txt) { title->setText(std::move(txt)); } StaticText* setTitle2(std::string txt); - void paint(BitmapBuffer* dc) override; - protected: - uint8_t icon; + EdgeTxIcon icon; StaticText* title; StaticText* title2 = nullptr; }; @@ -48,7 +46,7 @@ class PageHeader : public FormWindow class Page : public NavWindow { public: - explicit Page(unsigned icon); + explicit Page(EdgeTxIcon icon, PaddingSize padding = PAD_MEDIUM); #if defined(DEBUG_WINDOWS) std::string getName() const override { return "Page"; } @@ -61,9 +59,7 @@ class Page : public NavWindow protected: PageHeader header; - FormWindow body; + Window body; bool bubbleEvents() override { return false; } }; - -#endif // _PAGE_H_ diff --git a/radio/src/gui/colorlcd/popups.cpp b/radio/src/gui/colorlcd/popups.cpp index 33c51466549..448b57ca0dd 100644 --- a/radio/src/gui/colorlcd/popups.cpp +++ b/radio/src/gui/colorlcd/popups.cpp @@ -19,12 +19,13 @@ * GNU General Public License for more details. */ -#include "opentx.h" #include "popups.h" + #include "libopenui.h" +#include "opentx.h" #include "pwr.h" - #include "hal/watchdog_driver.h" +#include "themes/etx_lv_theme.h" static void _run_popup_dialog(const char* title, const char* msg, const char* info = nullptr) @@ -37,11 +38,8 @@ static void _run_popup_dialog(const char* title, const char* msg, // RELEASED/CLICKED to be called in a loop lv_indev_reset(nullptr, nullptr); - auto md = new MessageDialog(MainWindow::instance(), title, msg); + auto md = new MessageDialog(MainWindow::instance(), title, msg, info); md->setCloseHandler([&]() { running = false; }); - if (info) { - md->setInfoText(std::string(info)); - } while (running) { // Allow power off while showing popup auto check = pwrCheck(); @@ -55,7 +53,7 @@ static void _run_popup_dialog(const char* title, const char* msg, WDG_RESET(); RTOS_WAIT_MS(1); continue; - } + } checkBacklight(); WDG_RESET(); @@ -65,12 +63,12 @@ static void _run_popup_dialog(const char* title, const char* msg, } } -void POPUP_INFORMATION(const char * message) +void POPUP_INFORMATION(const char* message) { _run_popup_dialog("Message", message); } -void POPUP_WARNING(const char * message, const char * info) +void POPUP_WARNING(const char* message, const char* info) { _run_popup_dialog("Warning", message, info); } @@ -89,11 +87,11 @@ void show_ui_popup() } } -void POPUP_WARNING_ON_UI_TASK(const char * message, const char * info, bool waitForClose) +void POPUP_WARNING_ON_UI_TASK(const char* message, const char* info, + bool waitForClose) { // if already in a popup, and we don't want to wait, ignore call - if (!waitForClose && ui_popup_active) - return; + if (!waitForClose && ui_popup_active) return; // Wait in case already in popup. while (ui_popup_active) { @@ -112,35 +110,72 @@ void POPUP_WARNING_ON_UI_TASK(const char * message, const char * info, bool wait } } +// Bubble popup style +static const lv_style_const_prop_t bubble_popup_props[] = { + LV_STYLE_CONST_BORDER_OPA(LV_OPA_COVER), + LV_STYLE_CONST_BORDER_WIDTH(3), + LV_STYLE_CONST_RADIUS(10), + LV_STYLE_PROP_INV, +}; +LV_STYLE_CONST_MULTI_INIT(bubble_popup, bubble_popup_props); + +static void bubble_popup_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->bg_opacity_cover, LV_PART_MAIN); + etx_obj_add_style(obj, styles->pad_small, LV_PART_MAIN); + etx_obj_add_style(obj, bubble_popup, LV_PART_MAIN); + etx_bg_color(obj, COLOR_WHITE_INDEX, LV_PART_MAIN); + etx_txt_color(obj, COLOR_BLACK_INDEX, LV_PART_MAIN); + etx_obj_add_style(obj, styles->border_color_black, LV_PART_MAIN); +} + +static const lv_obj_class_t bubble_popup_class = { + .base_class = &window_base_class, + .constructor_cb = bubble_popup_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LV_DPI_DEF, + .height_def = LV_DPI_DEF, + .editable = LV_OBJ_CLASS_EDITABLE_FALSE, + .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, + .instance_size = sizeof(lv_obj_t)}; + +static lv_obj_t* bubble_popup_create(lv_obj_t* parent) +{ + return etx_create(&bubble_popup_class, parent); +} + class BubbleDialog : public Window { - public: - BubbleDialog(const char* message, int timeout) : - Window(MainWindow::instance(), rect_t{50, LCD_H - 100, LCD_W - 100, 50}, OPAQUE, 0, etx_bubble_popup_create) - { - lv_obj_set_parent(lvobj, lv_layer_top()); - - auto label = lv_label_create(lvobj); - lv_label_set_text(label, message); - lv_obj_center(label); - lv_obj_set_width(label, lv_pct(100)); - lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); - lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); - - endTime = RTOS_GET_MS() + timeout; - } + public: + BubbleDialog(const char* message, int timeout) : + Window(MainWindow::instance(), rect_t{50, LCD_H - 100, LCD_W - 100, 50}, + OPAQUE, 0, bubble_popup_create) + { + lv_obj_set_parent(lvobj, lv_layer_top()); + + auto label = lv_label_create(lvobj); + lv_label_set_text(label, message); + lv_obj_center(label); + lv_obj_set_width(label, lv_pct(100)); + etx_obj_add_style(label, styles->text_align_center, LV_PART_MAIN); + lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); + + endTime = RTOS_GET_MS() + timeout; + } - bool isBubblePopup() override { return true; } + bool isBubblePopup() override { return true; } - void checkEvents() override - { - if (RTOS_GET_MS() >= endTime) { - deleteLater(); - } + void checkEvents() override + { + if (RTOS_GET_MS() >= endTime) { + deleteLater(); } + } - protected: - uint32_t endTime; + protected: + uint32_t endTime; }; void POPUP_BUBBLE(const char* message, uint32_t timeout) diff --git a/radio/src/gui/colorlcd/popups.h b/radio/src/gui/colorlcd/popups.h index 028a67018ad..645613f9955 100644 --- a/radio/src/gui/colorlcd/popups.h +++ b/radio/src/gui/colorlcd/popups.h @@ -21,13 +21,27 @@ #pragma once +#include + #include -typedef std::function ProgressHandler; +enum WarningType +{ + WARNING_TYPE_WAIT, + WARNING_TYPE_INFO, + WARNING_TYPE_ASTERISK, + WARNING_TYPE_CONFIRM, + WARNING_TYPE_INPUT, + WARNING_TYPE_ALERT +}; + +typedef std::function + ProgressHandler; -void POPUP_INFORMATION(const char * message); -void POPUP_WARNING(const char * message, const char * info = nullptr); -void POPUP_WARNING_ON_UI_TASK(const char * message, const char * info = nullptr, bool waitForClose = true); -void POPUP_BUBBLE(const char * message, uint32_t timeout); +void POPUP_INFORMATION(const char *message); +void POPUP_WARNING(const char *message, const char *info = nullptr); +void POPUP_WARNING_ON_UI_TASK(const char *message, const char *info = nullptr, + bool waitForClose = true); +void POPUP_BUBBLE(const char *message, uint32_t timeout); void show_ui_popup(); diff --git a/radio/src/gui/colorlcd/ppm_settings.cpp b/radio/src/gui/colorlcd/ppm_settings.cpp index 0233c142b72..5aef4e93bcc 100644 --- a/radio/src/gui/colorlcd/ppm_settings.cpp +++ b/radio/src/gui/colorlcd/ppm_settings.cpp @@ -20,30 +20,32 @@ */ #include "ppm_settings.h" + #include "opentx.h" #define SET_DIRTY() storageDirty(EE_MODEL) template PpmFrameSettings::PpmFrameSettings(Window* parent, T* ppm) : - FormWindow(parent, rect_t{}) + Window(parent, rect_t{}) { + padAll(PAD_TINY); setFlexLayout(LV_FLEX_FLOW_ROW); // PPM frame length auto edit = new NumberEdit( - this, rect_t{}, 125, 35 * PPM_STEP_SIZE + PPM_DEF_PERIOD, + this, rect_t{0, 0, 80, 0}, 125, 35 * PPM_STEP_SIZE + PPM_DEF_PERIOD, GET_DEFAULT(ppm->frameLength * PPM_STEP_SIZE + PPM_DEF_PERIOD), SET_VALUE(ppm->frameLength, (newValue - PPM_DEF_PERIOD) / PPM_STEP_SIZE), - 0, PREC1); + PREC1); edit->setStep(PPM_STEP_SIZE); edit->setSuffix(STR_MS); - + // memorize PPM frame length NumberEdit object this->ppmFrameLenEditObject = edit; // PPM frame delay - edit = new NumberEdit(this, rect_t{}, 100, 800, + edit = new NumberEdit(this, rect_t{0, 0, 80, 0}, 100, 800, GET_DEFAULT(ppm->delay * 50 + 300), SET_VALUE(ppm->delay, (newValue - 300) / 50)); edit->setStep(50); @@ -55,4 +57,4 @@ PpmFrameSettings::PpmFrameSettings(Window* parent, T* ppm) : // explicit instantiation to make linker happy template struct PpmFrameSettings; -template struct PpmFrameSettings; \ No newline at end of file +template struct PpmFrameSettings; diff --git a/radio/src/gui/colorlcd/ppm_settings.h b/radio/src/gui/colorlcd/ppm_settings.h index 4d55cdfe763..57b44b2f043 100644 --- a/radio/src/gui/colorlcd/ppm_settings.h +++ b/radio/src/gui/colorlcd/ppm_settings.h @@ -25,7 +25,7 @@ #include "numberedit.h" template -struct PpmFrameSettings : public FormWindow { +struct PpmFrameSettings : public Window { private: NumberEdit* ppmFrameLenEditObject = nullptr; diff --git a/radio/src/gui/colorlcd/preflight_checks.cpp b/radio/src/gui/colorlcd/preflight_checks.cpp index 0eb858f119d..f5a632d4cf1 100644 --- a/radio/src/gui/colorlcd/preflight_checks.cpp +++ b/radio/src/gui/colorlcd/preflight_checks.cpp @@ -26,6 +26,7 @@ #include "hal/switch_driver.h" #include "opentx.h" #include "strhelpers.h" +#include "themes/etx_lv_theme.h" #define SET_DIRTY() storageDirty(EE_MODEL) @@ -118,20 +119,18 @@ PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP) header.setTitle(STR_MENU_MODEL_SETUP); header.setTitle2(STR_PREFLIGHT); - auto form = new FormWindow(&body, rect_t{}); - form->setFlexLayout(); - form->padAll(8); - FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); + body.setFlexLayout(); + FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); // Display checklist - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_CHECKLIST, 0, COLOR_THEME_PRIMARY1); + auto line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_CHECKLIST, COLOR_THEME_PRIMARY1); auto chkList = new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_model.displayChecklist)); // Interactive checklist - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_CHECKLIST_INTERACTIVE, 0, + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_CHECKLIST_INTERACTIVE, COLOR_THEME_PRIMARY1); auto interactiveChkList = new ToggleSwitch( line, rect_t{}, GET_SET_DEFAULT(g_model.checklistInteractive)); @@ -144,20 +143,20 @@ PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP) }); // Throttle warning - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1); + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_THROTTLE_WARNING, COLOR_THEME_PRIMARY1); auto tw = new ToggleSwitch(line, rect_t{}, GET_SET_INVERTED(g_model.disableThrottleWarning)); // Custom Throttle warning (conditional on previous field) - line = form->newLine(&grid); + line = body.newLine(grid); make_conditional(line, tw); - new StaticText(line, rect_t{}, STR_CUSTOM_THROTTLE_WARNING, 0, + new StaticText(line, rect_t{}, STR_CUSTOM_THROTTLE_WARNING, COLOR_THEME_PRIMARY1); - auto box = new FormWindow::Line(line, window_create(line->getLvObj())); - lv_obj_set_layout(box->getLvObj(), LV_LAYOUT_FLEX); - box->setWidth(LCD_W / 2 - 15); + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY, LV_SIZE_CONTENT); auto cst_tw = new ToggleSwitch( box, rect_t{}, GET_SET_DEFAULT(g_model.enableCustomThrottleWarning)); @@ -169,9 +168,9 @@ PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP) make_conditional(cst_val, cst_tw); // Switch warnings (TODO: add display switch?) - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_SWITCHES, 0, COLOR_THEME_PRIMARY1); - line = form->newLine(&grid); + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_SWITCHES, COLOR_THEME_PRIMARY1); + line = body.newLine(grid); line->padTop(0); line->padLeft(4); new SwitchWarnMatrix(line, rect_t{}); @@ -185,14 +184,14 @@ PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP) } } if (pot_cnt > 0) { - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_POTWARNINGSTATE, 0, + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_POTWARNINGSTATE, COLOR_THEME_PRIMARY1); auto pots_wm = new Choice(line, rect_t{}, STR_PREFLIGHT_POTSLIDER_CHECK, 0, 2, GET_SET_DEFAULT(g_model.potsWarnMode)); // Pot warnings - line = form->newLine(&grid); + line = body.newLine(grid); line->padTop(0); line->padLeft(4); auto pwm = new PotWarnMatrix(line, rect_t{}); @@ -201,10 +200,10 @@ PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP) } // Center beeps - line = form->newLine(&grid); + line = body.newLine(grid); line->padTop(0); - new StaticText(line, rect_t{}, STR_BEEPCTR, 0, COLOR_THEME_PRIMARY1); - line = form->newLine(&grid); + new StaticText(line, rect_t{}, STR_BEEPCTR, COLOR_THEME_PRIMARY1); + line = body.newLine(grid); line->padLeft(4); new CenterBeepsMatrix(line, rect_t{}); } @@ -253,10 +252,7 @@ SwitchWarnMatrix::SwitchWarnMatrix(Window* parent, const rect_t& r) : uint8_t rows = ((btn_cnt - 1) / SW_BTNS) + 1; lv_obj_set_height(lvobj, (rows * 36) + 4); - lv_obj_set_style_pad_all(lvobj, 4, LV_PART_MAIN); - - lv_obj_set_style_pad_row(lvobj, 4, LV_PART_MAIN); - lv_obj_set_style_pad_column(lvobj, 4, LV_PART_MAIN); + padAll(PAD_SMALL); } void SwitchWarnMatrix::setTextAndState(uint8_t btn_id) @@ -318,10 +314,7 @@ PotWarnMatrix::PotWarnMatrix(Window* parent, const rect_t& r) : uint8_t rows = ((btn_cnt - 1) / SW_BTNS) + 1; lv_obj_set_height(lvobj, (rows * 36) + 4); - lv_obj_set_style_pad_all(lvobj, 4, LV_PART_MAIN); - - lv_obj_set_style_pad_row(lvobj, 4, LV_PART_MAIN); - lv_obj_set_style_pad_column(lvobj, 4, LV_PART_MAIN); + padAll(PAD_SMALL); } void PotWarnMatrix::setTextAndState(uint8_t btn_id) @@ -387,10 +380,7 @@ CenterBeepsMatrix::CenterBeepsMatrix(Window* parent, const rect_t& r) : uint8_t rows = ((btn_cnt - 1) / SW_BTNS) + 1; lv_obj_set_height(lvobj, (rows * 36) + 4); - lv_obj_set_style_pad_all(lvobj, 4, LV_PART_MAIN); - - lv_obj_set_style_pad_row(lvobj, 4, LV_PART_MAIN); - lv_obj_set_style_pad_column(lvobj, 4, LV_PART_MAIN); + padAll(PAD_SMALL); } void CenterBeepsMatrix::setTextAndState(uint8_t btn_id) diff --git a/radio/src/gui/colorlcd/preflight_checks.h b/radio/src/gui/colorlcd/preflight_checks.h index cad6c7f2561..f7a75e4b0f2 100644 --- a/radio/src/gui/colorlcd/preflight_checks.h +++ b/radio/src/gui/colorlcd/preflight_checks.h @@ -23,6 +23,7 @@ #include "page.h" -struct PreflightChecks : public Page { +class PreflightChecks : public Page { + public: PreflightChecks(); }; diff --git a/radio/src/gui/colorlcd/preview_window.cpp b/radio/src/gui/colorlcd/preview_window.cpp index d7130b7e840..2177284b42e 100644 --- a/radio/src/gui/colorlcd/preview_window.cpp +++ b/radio/src/gui/colorlcd/preview_window.cpp @@ -18,6 +18,180 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + #include "preview_window.h" +#include "libopenui.h" +#include "opentx.h" +#include "sliders.h" +#include "theme.h" +#include "themes/etx_lv_theme.h" +#include "trims.h" + +extern inline tmr10ms_t getTicks() { return g_tmr10ms; } + +#define PREVIEW_WINDOW_REFRESH_INTERVAL ((1000 / 10) * 1) + +// class to hold a color list and apply / restore it while drawing standard +// controls +class ColorMaintainer +{ + public: + void setColorList(std::vector colorList) + { + this->colorList.assign(colorList.begin(), colorList.end()); + } + + void applyColorValues() + { + // save old values; + for (auto i = 0; i < LCD_COLOR_COUNT; i++) { + oldColorVals[i] = lcdColorTable[i]; + } + + for (auto color : colorList) { + lcdColorTable[color.colorNumber] = color.colorValue; + } + + usePreviewStyle(); + } + + void restoreColorValues() + { + for (auto i = 0; i < LCD_COLOR_COUNT; i++) { + lcdColorTable[i] = oldColorVals[i]; + } + + useMainStyle(); + } + + protected: + uint32_t oldColorVals[LCD_COLOR_COUNT]; + std::vector colorList; +}; + +extern ColorMaintainer colorMaintainer; + +class ThemedCheckBox : public ToggleSwitch +{ + public: + ThemedCheckBox(Window *parent, rect_t rect, bool checked) : + ToggleSwitch( + parent, rect, [=]() { return checked; }, + [=](uint8_t value) { update(); }), + checked(checked) + { + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE); + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); + setFocusHandler([](bool focus) {}); + } + +#if defined(HARDWARE_KEYS) + void onEvent(event_t event) override { return parent->onEvent(event); } +#endif + + protected: + bool checked; +}; + ColorMaintainer colorMaintainer; + +class ThemedButton : public TextButton +{ + public: + ThemedButton(Window *window, const rect_t &rect, std::string text, + bool isChecked) : + TextButton(window, rect, text, nullptr) + { + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE); + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); + setPressHandler([=]() { return isChecked; }); + } + +#if defined(HARDWARE_KEYS) + void onEvent(event_t event) override { parent->onEvent(event); } +#endif +}; + +class ThemedTextEdit : public TextEdit +{ + public: + ThemedTextEdit(Window *parent, const rect_t &rect, const char *text, + bool edited) : + TextEdit(parent, rect, editText, strlen(text)) + { + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE); + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); + strcpy(editText, text); + lv_obj_add_state(lvobj, LV_STATE_FOCUSED); + if (edited) lv_obj_add_state(lvobj, LV_STATE_EDITED); + update(); + } + +#if defined(HARDWARE_KEYS) + void onEvent(event_t event) override { parent->onEvent(event); } +#endif + + protected: + char editText[50]; +}; + +PreviewWindow::PreviewWindow(Window *window, rect_t rect, + std::vector colorList) : + Window(window, rect, NO_FOCUS) +{ + // reset default group to avoid focus + lv_group_t *def_group = lv_group_get_default(); + lv_group_set_default(nullptr); + + setColorList(colorList); + colorMaintainer.applyColorValues(); + + etx_solid_bg(lvobj, COLOR_THEME_SECONDARY3_INDEX); + + auto topbar = new Window(this, {0, 0, LV_PCT(100), TOPBAR_ZONE_HEIGHT}); + etx_solid_bg(topbar->getLvObj(), COLOR_THEME_SECONDARY1_INDEX); + + new StaticIcon(topbar, 5, 5, getBuiltinIcon(ICON_RADIO), + COLOR_THEME_PRIMARY2); + new StaticIcon(topbar, 38, 5, getBuiltinIcon(ICON_RADIO_TOOLS), + COLOR_THEME_PRIMARY2); + new StaticIcon(topbar, 71, 5, getBuiltinIcon(ICON_RADIO_SETUP), + COLOR_THEME_PRIMARY2); + + new StaticText(this, {5, 44, 100, PAGE_LINE_HEIGHT}, STR_THEME_CHECKBOX, + COLOR_THEME_PRIMARY1); + new ThemedCheckBox(this, {100, 40, 40, 28}, true); + new ThemedCheckBox(this, {150, 40, 40, 28}, false); + (new ThemedButton(this, {210, 40, 100, 32}, STR_THEME_ACTIVE, true)) + ->check(true); + new ThemedButton(this, {210, 75, 100, 32}, STR_THEME_REGULAR, false); + new MainViewTrim(this, {5, 75, HORIZONTAL_SLIDERS_WIDTH, 20}, 0, false); + new MainViewSlider(this, {5, 97, HORIZONTAL_SLIDERS_WIDTH, 20}, 0, false); + new StaticText(this, {5, 122, 100, PAGE_LINE_HEIGHT}, STR_THEME_WARNING, + COLOR_THEME_WARNING); + new StaticText(this, {5, 144, 100, PAGE_LINE_HEIGHT}, STR_THEME_DISABLED, + COLOR_THEME_DISABLED); + + new ThemedTextEdit(this, {5, 170, 100, 0}, STR_THEME_EDIT, true); + new ThemedTextEdit(this, {110, 170, 100, 0}, STR_THEME_FOCUS, false); + ticks = 0; + + dateTime = new HeaderDateTime(this->getLvObj(), width() - 42, 4); + + lv_group_set_default(def_group); + + colorMaintainer.restoreColorValues(); +} + +void PreviewWindow::setColorList(std::vector colorList) +{ + colorMaintainer.setColorList(colorList); + // Force style update + colorMaintainer.applyColorValues(); + colorMaintainer.restoreColorValues(); + // Update preview colors + invalidate(); +} + +void PreviewWindow::checkEvents() { dateTime->update(); } diff --git a/radio/src/gui/colorlcd/preview_window.h b/radio/src/gui/colorlcd/preview_window.h index db34b1ec3b1..bdd462c5c14 100644 --- a/radio/src/gui/colorlcd/preview_window.h +++ b/radio/src/gui/colorlcd/preview_window.h @@ -19,286 +19,24 @@ * GNU General Public License for more details. */ -#ifndef PREVIEW_WINDOW_INCLUDE -#define PREVIEW_WINDOW_INCLUDE -#include +#pragma once -#include "libopenui.h" -#include "opentx.h" -#include "sliders.h" +#include "window.h" #include "theme_manager.h" -#include "themes/etx_lv_theme.h" -extern inline tmr10ms_t getTicks() { return g_tmr10ms; } - -#define PREVIEW_WINDOW_REFRESH_INTERVAL ((1000 / 10) * 1) - -// class to hold a color list and apply / restore it while drawing standard -// controls -class ColorMaintainer -{ - public: - void setColorList(std::vector colorList) - { - this->colorList.assign(colorList.begin(), colorList.end()); - } - - void applyColorValues() - { - // save old values; - for (auto i = 0; i < COLOR_COUNT; i++) { - oldColorVals[i] = lcdColorTable[i]; - } - - for (auto color : colorList) { - lcdColorTable[color.colorNumber] = color.colorValue; - } - - usePreviewStyle(); - } - - void restoreColorValues() - { - for (auto i = 0; i < COLOR_COUNT; i++) { - lcdColorTable[i] = oldColorVals[i]; - } - - useMainStyle(); - } - - protected: - uint32_t oldColorVals[COLOR_COUNT]; - std::vector colorList; -}; - -extern ColorMaintainer colorMaintainer; - -// override of controls to draw them using a selected theme -class ThemedStaticText : public StaticText -{ - public: - ThemedStaticText(FormWindow *window, const rect_t &rect, std::string text, - LcdColorIndex colorIndex) : - StaticText(window, rect, text, 0, COLOR(colorIndex)), - _colorIndex(colorIndex) - { - } - - void paint(BitmapBuffer *dc) override - { - colorMaintainer.applyColorValues(); - setTextFlags(COLOR(_colorIndex)); - StaticText::paint(dc); - colorMaintainer.restoreColorValues(); - } - - protected: - LcdColorIndex _colorIndex; -}; - -class ThemedCheckBox : public ToggleSwitch -{ - public: - ThemedCheckBox(Window *parent, rect_t rect, bool checked) : - ToggleSwitch( - parent, rect, [=]() { return checked; }, - [=](uint8_t value) { update(); }, NO_FOCUS), - checked(checked) - { - setFocusHandler([](bool focus) {}); - } - -#if defined(HARDWARE_KEYS) - void onEvent(event_t event) override { return parent->onEvent(event); } -#endif - - protected: - bool checked; -}; - -class ThemedMainViewHorizontalTrim : public MainViewHorizontalTrim -{ - public: - using MainViewHorizontalTrim::MainViewHorizontalTrim; - void paint(BitmapBuffer *dc) override - { - colorMaintainer.applyColorValues(); - MainViewHorizontalTrim::paint(dc); - colorMaintainer.restoreColorValues(); - } -}; - -class ThemedMainViewHorizontalSlider : public MainViewHorizontalSlider -{ - public: - using MainViewHorizontalSlider::MainViewHorizontalSlider; - void paint(BitmapBuffer *dc) override - { - colorMaintainer.applyColorValues(); - MainViewHorizontalSlider::paint(dc); - colorMaintainer.restoreColorValues(); - } -}; - -class ThemedButton : public TextButton -{ - public: - ThemedButton(FormWindow *window, const rect_t &rect, std::string text, - bool isChecked, WindowFlags windowFlags) : - TextButton(window, rect, text, nullptr, windowFlags | NO_FOCUS) - { - setPressHandler([=]() { return isChecked; }); - } - -#if defined(HARDWARE_KEYS) - void onEvent(event_t event) override { parent->onEvent(event); } -#endif -}; - -class ThemedTextEdit : public TextEdit -{ - public: - ThemedTextEdit(Window *parent, const rect_t &rect, const char *text, - bool edited) : - TextEdit(parent, rect, editText, strlen(text), NO_FOCUS) - { - strcpy(editText, text); - lv_obj_add_state(lvobj, LV_STATE_FOCUSED); - if (edited) lv_obj_add_state(lvobj, LV_STATE_EDITED); - update(); - } - -#if defined(HARDWARE_TOUCH) - bool onTouchEnd(coord_t x, coord_t y) override { return true; } -#endif - -#if defined(HARDWARE_KEYS) - void onEvent(event_t event) override { parent->onEvent(event); } -#endif - - protected: - char editText[50]; -}; +class HeaderDateTime; // display controls using the appropriate theme. -class PreviewWindow : public FormWindow +class PreviewWindow : public Window { public: - PreviewWindow(Window *window, rect_t rect, - std::vector colorList) : - FormWindow(window, rect, NO_FOCUS) - { - setColorList(colorList); - colorMaintainer.applyColorValues(); - - // reset default group to avoid focus - lv_group_t *def_group = lv_group_get_default(); - lv_group_set_default(nullptr); - - new ThemedStaticText(this, {5, 44, 100, PAGE_LINE_HEIGHT}, - STR_THEME_CHECKBOX, COLOR_THEME_PRIMARY1_INDEX); - new ThemedCheckBox(this, {100, 40, 40, 28}, true); - new ThemedCheckBox(this, {150, 40, 40, 28}, false); - new ThemedButton(this, {210, 40, 100, 32}, STR_THEME_ACTIVE, true, - BUTTON_CHECKED); - new ThemedButton(this, {210, 75, 100, 32}, STR_THEME_REGULAR, false, 0); - new ThemedMainViewHorizontalTrim(this, - {5, 75, HORIZONTAL_SLIDERS_WIDTH, 20}, 0); - new ThemedMainViewHorizontalSlider( - this, {5, 97, HORIZONTAL_SLIDERS_WIDTH, 20}, 0); - new ThemedStaticText(this, {5, 122, 100, PAGE_LINE_HEIGHT}, - STR_THEME_WARNING, COLOR_THEME_WARNING_INDEX); - new ThemedStaticText(this, {5, 144, 100, PAGE_LINE_HEIGHT}, - STR_THEME_DISABLED, COLOR_THEME_DISABLED_INDEX); + PreviewWindow(Window *window, rect_t rect, std::vector colorList); - new ThemedTextEdit(this, {5, 170, 100, 0}, STR_THEME_EDIT, true); - new ThemedTextEdit(this, {110, 170, 100, 0}, STR_THEME_FOCUS, false); - ticks = 0; - - lv_group_set_default(def_group); - - colorMaintainer.restoreColorValues(); - } - - void setColorList(std::vector colorList) - { - colorMaintainer.setColorList(colorList); - // Force style update - colorMaintainer.applyColorValues(); - colorMaintainer.restoreColorValues(); - invalidate(); - } - - BitmapBuffer *getBitmap(const uint8_t *maskData, uint32_t bgColor, - uint32_t fgColor, int *width) - { - auto mask = BitmapBuffer::load8bitMaskLZ4(maskData); - BitmapBuffer *newBm = - new BitmapBuffer(BMP_RGB565, mask->width(), mask->height()); - newBm->clear(bgColor); - newBm->drawMask(0, 0, mask, fgColor); - delete mask; - return newBm; - } - - void drawTime(BitmapBuffer *dc) - { - // time on top bar - struct gtm t; - char str[16]; - - gettime(&t); - int s = - snprintf(str, sizeof(str), "%d %s\n", t.tm_mday, STR_MONTHS[t.tm_mon]); - if (s > 0 && (size_t)s < sizeof(str) - 6 /* 00:00\0 */) { - getTimerString(str + s, getValue(MIXSRC_TX_TIME)); - } - dc->drawText(rect.w - 40, 5, str, COLOR_THEME_PRIMARY2 | FONT(XS)); - } - - void paint(BitmapBuffer *dc) override - { - colorMaintainer.applyColorValues(); - - // background - dc->clear(COLOR_THEME_SECONDARY3); - - // top bar background - dc->drawSolidFilledRect(0, 0, rect.w, TOPBAR_ZONE_HEIGHT, - COLOR_THEME_SECONDARY1); - - int width; - int x = 5; - // topbar icons - auto mask_menu_radio = getBuiltinIcon(ICON_RADIO); - auto bm = getBitmap(mask_menu_radio, COLOR_THEME_SECONDARY1, - COLOR_THEME_PRIMARY2, &width); - dc->drawBitmap(x, 5, bm); - x += MENU_HEADER_BUTTON_WIDTH + 2; - delete bm; - - dc->drawSolidFilledRect(x - 2, 0, MENU_HEADER_BUTTON_WIDTH + 2, - TOPBAR_ZONE_HEIGHT, COLOR_THEME_FOCUS); - auto mask_radio_tools = getBuiltinIcon(ICON_RADIO_TOOLS); - bm = getBitmap(mask_radio_tools, COLOR_THEME_FOCUS, COLOR_THEME_PRIMARY2, - &width); - dc->drawBitmap(x, 5, bm); - x += MENU_HEADER_BUTTON_WIDTH + 2; - delete bm; - - auto mask_radio_setup = getBuiltinIcon(ICON_RADIO_SETUP); - bm = getBitmap(mask_radio_setup, COLOR_THEME_SECONDARY1, - COLOR_THEME_PRIMARY2, &width); - dc->drawBitmap(x, 5, bm); - delete bm; - - drawTime(dc); - - colorMaintainer.restoreColorValues(); - } + void setColorList(std::vector colorList); protected: tmr10ms_t ticks; -}; + HeaderDateTime *dateTime; -#endif + void checkEvents() override; +}; diff --git a/radio/src/gui/colorlcd/pxx1_settings.cpp b/radio/src/gui/colorlcd/pxx1_settings.cpp index ce17c4ef39f..f8060bfac17 100644 --- a/radio/src/gui/colorlcd/pxx1_settings.cpp +++ b/radio/src/gui/colorlcd/pxx1_settings.cpp @@ -29,13 +29,13 @@ PXX1AntennaSettings::PXX1AntennaSettings(Window* parent, const FlexGridLayout& g, uint8_t moduleIdx) : - FormWindow(parent, rect_t{}), md(&g_model.moduleData[moduleIdx]) + Window(parent, rect_t{}), md(&g_model.moduleData[moduleIdx]) { FlexGridLayout grid(g); setFlexLayout(); - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_ANTENNA, 0, COLOR_THEME_PRIMARY1); + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_ANTENNA, COLOR_THEME_PRIMARY1); if (md->pxx.antennaMode == ANTENNA_MODE_PER_MODEL) { md->pxx.antennaMode = ANTENNA_MODE_INTERNAL; diff --git a/radio/src/gui/colorlcd/pxx1_settings.h b/radio/src/gui/colorlcd/pxx1_settings.h index 936c1df14b9..b8662b6da4e 100644 --- a/radio/src/gui/colorlcd/pxx1_settings.h +++ b/radio/src/gui/colorlcd/pxx1_settings.h @@ -26,7 +26,7 @@ struct ModuleData; -class PXX1AntennaSettings : public FormWindow, public ModuleOptions +class PXX1AntennaSettings : public Window, public ModuleOptions { ModuleData* md; diff --git a/radio/src/gui/colorlcd/radio_calibration.cpp b/radio/src/gui/colorlcd/radio_calibration.cpp index 8ddba702d29..bf97c7ee39f 100644 --- a/radio/src/gui/colorlcd/radio_calibration.cpp +++ b/radio/src/gui/colorlcd/radio_calibration.cpp @@ -19,73 +19,84 @@ * GNU General Public License for more details. */ -#include "opentx.h" #include "radio_calibration.h" + +#include "hal/adc_driver.h" +#include "opentx.h" #include "sliders.h" #include "view_main_decoration.h" -#include "hal/adc_driver.h" - -#define XPOT_DELTA 10 -#define XPOT_DELAY 5 /* cycles */ uint8_t menuCalibrationState; -class StickCalibrationWindow: public Window { - public: - StickCalibrationWindow(Window *parent, const rect_t &rect, uint8_t stickX, - uint8_t stickY) : - Window(parent, rect, REFRESH_ALWAYS), stickX(stickX), stickY(stickY) - { - setLeft(rect.x - calibStickBackground->width() / 2); - setTop(rect.y - calibStickBackground->height() / 2); - setWidth(calibStickBackground->width()); - setHeight(calibStickBackground->height()); - } - - void paint(BitmapBuffer * dc) override - { - dc->drawBitmap(0, 0, calibStickBackground); - int16_t x = calibratedAnalogs[stickX]; - int16_t y = calibratedAnalogs[stickY]; - dc->drawBitmap(width() / 2 - 9 + (bitmapSize / 2 * x) / RESX, - height() / 2 - 9 - (bitmapSize / 2 * y) / RESX, - calibStick); - } - - protected: - static constexpr coord_t bitmapSize = 68; - uint8_t stickX, stickY; +static const uint8_t stick_pointer[] = { +#include "alpha_stick_pointer.lbm" +}; +static const uint8_t stick_background[] = { +#include "alpha_stick_background.lbm" }; -RadioCalibrationPage::RadioCalibrationPage(bool initial): - Page(ICON_RADIO_CALIBRATION), - initial(initial) +class StickCalibrationWindow : public Window +{ + public: + StickCalibrationWindow(Window *parent, const rect_t &rect, uint8_t stickX, + uint8_t stickY) : + Window(parent, rect), stickX(stickX), stickY(stickY) + { + new StaticLZ4Image(this, 0, 0, (LZ4Bitmap *)stick_background); + calibStick = new StaticLZ4Image(this, 0, 0, (LZ4Bitmap *)stick_pointer); + } + + void checkEvents() override + { + int32_t x = calibratedAnalogs[stickX]; + int32_t y = calibratedAnalogs[stickY]; + coord_t dx = width() / 2 - 9 + (bitmapSize / 2 * x) / RESX; + coord_t dy = height() / 2 - 9 - (bitmapSize / 2 * y) / RESX; + lv_obj_set_pos(calibStick->getLvObj(), dx, dy); + } + + protected: + static constexpr coord_t bitmapSize = 68; + uint8_t stickX, stickY; + StaticLZ4Image *calibStick = nullptr; +}; + +RadioCalibrationPage::RadioCalibrationPage(bool initial) : + Page(ICON_RADIO_CALIBRATION), initial(initial) { buildHeader(&header); buildBody(&body); } -void RadioCalibrationPage::buildHeader(Window * window) +void RadioCalibrationPage::buildHeader(Window *window) { header.setTitle(STR_MENUCALIBRATION); text = header.setTitle2(STR_MENUTOSTART); } -void RadioCalibrationPage::buildBody(FormWindow * window) +void RadioCalibrationPage::buildBody(Window *window) { + window->padAll(PAD_ZERO); + menuCalibrationState = CALIB_START; // The two sticks - //TODO: dynamic placing + LZ4Bitmap *bg = (LZ4Bitmap *)stick_background; + new StickCalibrationWindow( - window, {window->width() / 3, window->height() / 2, 0, 0}, 0, 1); + window, + {window->width() / 3 - bg->width / 2, + window->height() / 2 - bg->height / 2, bg->width, bg->height}, + 0, 1); auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN); if (max_sticks > 2) { - new StickCalibrationWindow( - window, {(2 * window->width()) / 3, window->height() / 2, 0, 0}, 3, - 2); + new StickCalibrationWindow( + window, + {window->width() * 2 / 3 - bg->width / 2, + window->height() / 2 - bg->height / 2, bg->width, bg->height}, + 3, 2); } std::unique_ptr deco(new ViewMainDecoration(window)); @@ -95,10 +106,10 @@ void RadioCalibrationPage::buildBody(FormWindow * window) #if defined(PCBNV14) || defined(PCBPL18) new TextButton(window, {LCD_W - 120, LCD_H - 140, 90, 40}, "Next", - [=]() -> uint8_t { - nextStep(); - return 0; - }, OPAQUE | NO_FOCUS); + [=]() -> uint8_t { + nextStep(); + return 0; + }); #endif } @@ -108,16 +119,12 @@ void RadioCalibrationPage::checkEvents() if (menuCalibrationState == CALIB_SET_MIDPOINT) { adcCalibSetMidPoint(); - } - else if (menuCalibrationState == CALIB_MOVE_STICKS) { + } else if (menuCalibrationState == CALIB_MOVE_STICKS) { adcCalibSetMinMax(); } } -void RadioCalibrationPage::onClicked() -{ - nextStep(); -} +void RadioCalibrationPage::onClicked() { nextStep(); } void RadioCalibrationPage::onCancel() { @@ -132,8 +139,7 @@ void RadioCalibrationPage::onCancel() void RadioCalibrationPage::nextStep() { - if (menuCalibrationState == CALIB_FINISHED) - deleteLater(); + if (menuCalibrationState == CALIB_FINISHED) deleteLater(); menuCalibrationState++; @@ -153,8 +159,7 @@ void RadioCalibrationPage::nextStep() // initial calibration completed // -> exit - if (initial) - deleteLater(); + if (initial) deleteLater(); break; default: @@ -164,7 +169,4 @@ void RadioCalibrationPage::nextStep() } } -void startCalibration() -{ - new RadioCalibrationPage(true); -} +void startCalibration() { new RadioCalibrationPage(true); } diff --git a/radio/src/gui/colorlcd/radio_calibration.h b/radio/src/gui/colorlcd/radio_calibration.h index bea90705483..1be053bba56 100644 --- a/radio/src/gui/colorlcd/radio_calibration.h +++ b/radio/src/gui/colorlcd/radio_calibration.h @@ -37,7 +37,7 @@ class RadioCalibrationPage: public Page { bool initial; void nextStep(); void buildHeader(Window * window); - void buildBody(FormWindow * window); + void buildBody(Window * window); }; void startCalibration(); diff --git a/radio/src/gui/colorlcd/radio_diaganas.cpp b/radio/src/gui/colorlcd/radio_diaganas.cpp index 18ef7709ba9..190bba54aaf 100644 --- a/radio/src/gui/colorlcd/radio_diaganas.cpp +++ b/radio/src/gui/colorlcd/radio_diaganas.cpp @@ -19,434 +19,439 @@ * GNU General Public License for more details. */ -#include "opentx.h" #include "radio_diaganas.h" -#include "libopenui.h" + #include "hal/adc_driver.h" +#include "libopenui.h" +#include "opentx.h" +#include "themes/etx_lv_theme.h" // #if defined(IMU_LSM6DS33) // #include "imu_lsm6ds33.h" // #endif -#define STATSDEPTH 8 // ideally a value of power of 2 +#define STATSDEPTH 8 // ideally a value of power of 2 #if LCD_W > LCD_H #define GRIDCOLS 10 #define TSI2CEventsCol 5 -static const lv_coord_t col_dsc[] = {LV_GRID_FR(30), LV_GRID_FR(30), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40), - LV_GRID_FR(30), LV_GRID_FR(30), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40), - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t col_dsc[] = { + LV_GRID_FR(30), LV_GRID_FR(30), LV_GRID_FR(40), LV_GRID_FR(40), + LV_GRID_FR(40), LV_GRID_FR(30), LV_GRID_FR(30), LV_GRID_FR(40), + LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_TEMPLATE_LAST}; #else #define GRIDCOLS 5 #define TSI2CEventsCol 0 -static const lv_coord_t col_dsc[] = {LV_GRID_FR(30), LV_GRID_FR(30), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40), - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t col_dsc[] = {LV_GRID_FR(30), LV_GRID_FR(30), + LV_GRID_FR(40), LV_GRID_FR(40), + LV_GRID_FR(40), LV_GRID_TEMPLATE_LAST}; #endif static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -class AnaViewWindow: public FormWindow { - public: - AnaViewWindow(Window * parent): - FormWindow(parent, {0, 0, parent->width(), parent->height()}) - { - parent->padAll(0); - padAll(4); - padLeft(10); - padRight(10); - setFlexLayout(); +class AnaViewWindow : public Window +{ + public: + AnaViewWindow(Window* parent) : + Window(parent, {0, 0, parent->width(), parent->height()}), + grid(col_dsc, row_dsc, PAD_ZERO) + { + parent->padAll(PAD_ZERO); + padAll(PAD_SMALL); + padLeft(10); + padRight(10); + setFlexLayout(); + + line = newLine(grid); + } - grid = new FlexGridLayout(col_dsc, row_dsc, 0); - line = newLine(grid); - } - - virtual void build() - { - char s[10]; + virtual void build() + { + char s[10]; - auto pot_offset = adcGetInputOffset(ADC_INPUT_FLEX); - auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN) - + adcGetMaxInputs(ADC_INPUT_FLEX); + auto pot_offset = adcGetInputOffset(ADC_INPUT_FLEX); + auto max_inputs = + adcGetMaxInputs(ADC_INPUT_MAIN) + adcGetMaxInputs(ADC_INPUT_FLEX); - for (uint8_t i = 0; i < max_inputs; i++) { - if (i >= pot_offset && (POT_CONFIG(i - pot_offset) == FLEX_NONE)) - continue; + for (uint8_t i = 0; i < max_inputs; i++) { + if (i >= pot_offset && (POT_CONFIG(i - pot_offset) == FLEX_NONE)) + continue; #if LCD_W > LCD_H - if ((i & 1) == 0) - line = newLine(grid); + if ((i & 1) == 0) line = newLine(grid); #else - line = newLine(grid); + line = newLine(grid); #endif - lv_obj_set_style_pad_column(line->getLvObj(), 8, 0); - - sprintf(s, "%02d :", i + 1); - new StaticText(line, rect_t{}, s, COLOR_THEME_PRIMARY1); - - auto lbl = new DynamicText(line, rect_t{}, [=]() { - return std::to_string((int16_t)calibratedAnalogs[i] * 25 / 256); - }, COLOR_THEME_PRIMARY1); - lv_obj_set_style_text_align(lbl->getLvObj(), LV_TEXT_ALIGN_RIGHT, 0); - - lbl = new DynamicText(line, rect_t{}, [=]() { - return std::to_string((int16_t)column3(i)); - }, COLOR_THEME_PRIMARY1); - lv_obj_set_style_text_align(lbl->getLvObj(), LV_TEXT_ALIGN_RIGHT, 0); - - if (column4size() > 0) { - lbl = new DynamicText(line, rect_t{}, [=]() { - return std::string(column4prefix()) + std::to_string((int16_t)column4(i)); - }, COLOR_THEME_PRIMARY1); - lv_obj_set_style_text_align(lbl->getLvObj(), (column4size() == 2) ? LV_TEXT_ALIGN_LEFT : LV_TEXT_ALIGN_RIGHT, 0); + lv_obj_set_style_pad_column(line->getLvObj(), 8, 0); + + sprintf(s, "%02d :", i + 1); + new StaticText(line, rect_t{}, s, COLOR_THEME_PRIMARY1); + + auto lbl = new DynamicText( + line, rect_t{}, + [=]() { + return std::to_string((int16_t)calibratedAnalogs[i] * 25 / 256); + }, + COLOR_THEME_PRIMARY1); + etx_obj_add_style(lbl->getLvObj(), styles->text_align_right, LV_PART_MAIN); + + lbl = new DynamicText( + line, rect_t{}, [=]() { return std::to_string((int16_t)column3(i)); }, + COLOR_THEME_PRIMARY1); + etx_obj_add_style(lbl->getLvObj(), styles->text_align_right, LV_PART_MAIN); + + if (column4size() > 0) { + lbl = new DynamicText( + line, rect_t{}, + [=]() { + return std::string(column4prefix()) + + std::to_string((int16_t)column4(i)); + }, + COLOR_THEME_PRIMARY1); + etx_obj_add_style(lbl->getLvObj(), (column4size() == 2) ? styles->text_align_left : styles->text_align_right, LV_PART_MAIN); #if LCD_W > LCD_H - lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH, 3 + (i & 1) * 5, column4size(), LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH, + 3 + (i & 1) * 5, column4size(), + LV_GRID_ALIGN_CENTER, 0, 1); #else - lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH, 3, column4size(), LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH, 3, + column4size(), LV_GRID_ALIGN_CENTER, 0, 1); #endif - } else { - grid->nextCell(); - } - - if (column5size() > 0) { - lbl = new DynamicText(line, rect_t{}, [=]() { - return std::to_string((int16_t)column5(i)); - }, COLOR_THEME_PRIMARY1); - lv_obj_set_style_text_align(lbl->getLvObj(), LV_TEXT_ALIGN_LEFT, 0); - } else { - grid->nextCell(); - } + } else { + grid.nextCell(); } - } - void deleteLater(bool detach = true, bool trash = true) override - { - if (grid){ - delete grid; - grid = nullptr; + if (column5size() > 0) { + lbl = new DynamicText( + line, rect_t{}, + [=]() { return std::to_string((int16_t)column5(i)); }, + COLOR_THEME_PRIMARY1); + etx_obj_add_style(lbl->getLvObj(), styles->text_align_left, LV_PART_MAIN); + } else { + grid.nextCell(); } } - - void checkEvents() override - { - Window::checkEvents(); - } + } - protected: - FlexGridLayout* grid = nullptr; - FormWindow::Line* line = nullptr; + void checkEvents() override { Window::checkEvents(); } - virtual int16_t column3(int i) { return 0; } - virtual int16_t column4(int i) { return 0; } - virtual int column4size() { return 0; } - virtual const char* column4prefix() { return ""; } - virtual int16_t column5(int i) { return 0; } - virtual int column5size() { return 0; } + protected: + FlexGridLayout grid; + FormLine* line = nullptr; + + virtual int16_t column3(int i) { return 0; } + virtual int16_t column4(int i) { return 0; } + virtual int column4size() { return 0; } + virtual const char* column4prefix() { return ""; } + virtual int16_t column5(int i) { return 0; } + virtual int column5size() { return 0; } }; -class AnaCalibratedViewWindow: public AnaViewWindow { - public: - AnaCalibratedViewWindow(Window * parent): - AnaViewWindow(parent) - { - } - - void build() override - { - AnaViewWindow::build(); +class AnaCalibratedViewWindow : public AnaViewWindow +{ + public: + AnaCalibratedViewWindow(Window* parent) : AnaViewWindow(parent) {} + + void build() override + { + AnaViewWindow::build(); #if defined(HARDWARE_TOUCH) - line = newLine(grid); + touchLines[0] = lv_line_create(parent->getParent()->getLvObj()); + etx_obj_add_style(touchLines[0], styles->div_line_edit, LV_PART_MAIN); + lv_obj_add_flag(touchLines[0], LV_OBJ_FLAG_HIDDEN); + touchLines[1] = lv_line_create(parent->getParent()->getLvObj()); + etx_obj_add_style(touchLines[1], styles->div_line_edit, LV_PART_MAIN); + lv_obj_add_flag(touchLines[1], LV_OBJ_FLAG_HIDDEN); + + line = newLine(grid); #if LCD_H > LCD_W - line->padTop(20); + line->padTop(20); #else - line->padTop(2); + line->padTop(2); #endif - auto lbl = new DynamicText(line, rect_t{}, [=]() { - TouchState rawTouchState = getInternalTouchState(); - if (rawTouchState.event != TE_NONE && rawTouchState.event != TE_SLIDE_END) - return std::string(STR_TOUCH_PANEL) + " " + std::to_string(rawTouchState.x) + " : " + std::to_string(rawTouchState.y); - return std::string(""); - }, COLOR_THEME_PRIMARY1); - lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 5, LV_GRID_ALIGN_CENTER, 0, 1); + auto lbl = new DynamicText( + line, rect_t{}, + [=]() { + TouchState rawTouchState = getInternalTouchState(); + if (rawTouchState.event != TE_NONE && + rawTouchState.event != TE_SLIDE_END) + return std::string(STR_TOUCH_PANEL) + " " + + std::to_string(rawTouchState.x) + " : " + + std::to_string(rawTouchState.y); + return std::string(""); + }, + COLOR_THEME_PRIMARY1); + lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 5, + LV_GRID_ALIGN_CENTER, 0, 1); #if !defined(SIMU) && !defined(PCBNV14) && !defined(PCBPL18) - line = newLine(grid); - auto lbl2 = new StaticText(line, rect_t{}, std::string("Touch GT911 FW ver: ") + std::to_string(touchGT911fwver), COLOR_THEME_PRIMARY1); - lv_obj_set_grid_cell(lbl2->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 5, LV_GRID_ALIGN_CENTER, 0, 1); + line = newLine(grid); + auto lbl2 = new StaticText( + line, rect_t{}, + std::string("Touch GT911 FW ver: ") + std::to_string(touchGT911fwver), + COLOR_THEME_PRIMARY1); + lv_obj_set_grid_cell(lbl2->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 5, + LV_GRID_ALIGN_CENTER, 0, 1); #if LCD_H > LCD_W - line = newLine(grid); + line = newLine(grid); #endif - lbl2 = new StaticText(line, rect_t{}, "TSI2CEvents: " + std::to_string(touchGT911hiccups), COLOR_THEME_PRIMARY1); - lv_obj_set_grid_cell(lbl2->getLvObj(), LV_GRID_ALIGN_STRETCH, TSI2CEventsCol, 5, LV_GRID_ALIGN_CENTER, 0, 1); + lbl2 = new StaticText(line, rect_t{}, + "TSI2CEvents: " + std::to_string(touchGT911hiccups), + COLOR_THEME_PRIMARY1); + lv_obj_set_grid_cell(lbl2->getLvObj(), LV_GRID_ALIGN_STRETCH, + TSI2CEventsCol, 5, LV_GRID_ALIGN_CENTER, 0, 1); #endif -#endif // defined(HARDWARE_TOUCH) +#endif // defined(HARDWARE_TOUCH) - setHeight(parent->height()); - } + setHeight(parent->height()); + } #if defined(HARDWARE_TOUCH) - void checkEvents() override - { - AnaViewWindow::checkEvents(); - // will always force a full monitor window refresh - invalidate(); + void checkEvents() override + { + AnaViewWindow::checkEvents(); + + TouchState rawTouchState = getInternalTouchState(); + if (rawTouchState.event != TE_NONE && rawTouchState.event != TE_SLIDE_END) { + touchPts[0] = {(lv_coord_t)(rawTouchState.x - 10), (lv_coord_t)(rawTouchState.y - 8)}; + touchPts[1] = {(lv_coord_t)(rawTouchState.x + 10), (lv_coord_t)(rawTouchState.y + 8)}; + touchPts[2] = {(lv_coord_t)(rawTouchState.x - 10), (lv_coord_t)(rawTouchState.y + 8)}; + touchPts[3] = {(lv_coord_t)(rawTouchState.x + 10), (lv_coord_t)(rawTouchState.y - 8)}; + + lv_line_set_points(touchLines[0], &touchPts[0], 2); + lv_line_set_points(touchLines[1], &touchPts[2], 2); + lv_obj_clear_flag(touchLines[0], LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(touchLines[1], LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(touchLines[0], LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(touchLines[1], LV_OBJ_FLAG_HIDDEN); } + } - void paint(BitmapBuffer * dc) override - { - TouchState rawTouchState = getInternalTouchState(); - if (rawTouchState.event != TE_NONE && rawTouchState.event != TE_SLIDE_END) { - dc->drawLine(rawTouchState.x - 10, rawTouchState.y - 8 - 68, rawTouchState.x + 10, rawTouchState.y + 8 - 68, SOLID, 0); - dc->drawLine(rawTouchState.x - 10, rawTouchState.y + 8 - 68, rawTouchState.x + 10, rawTouchState.y - 8 - 68, SOLID, 0); - } - }; + void deleteLater(bool detach, bool trash) override + { + if (!deleted()) { + // Attached to parent->parent window + lv_obj_del(touchLines[0]); + lv_obj_del(touchLines[1]); + AnaViewWindow::deleteLater(detach, trash); + } + } #endif - protected: - int16_t column3(int i) override - { - return anaIn(i); - } + protected: +#if defined(HARDWARE_TOUCH) + lv_point_t touchPts[4]; + lv_obj_t* touchLines[2]; +#endif + int16_t column3(int i) override { return anaIn(i); } }; -class AnaFilteredDevViewWindow: public AnaViewWindow { - protected: - class Stats { - protected: - int16_t buffer[STATSDEPTH] = {0}; - uint8_t writePos = 0; - uint8_t filledElems = 0; - - int16_t intSqrt(int16_t val) - { - if (val < 0) - return 0; - if (val <= 1) - return val; - - // Try iteratively until i^2 >= val - int i = 1, retval = 1; - while (retval <= val) - { - i++; - retval = i * i; - } - return i - 1; - } - int16_t meanVal() - { - if (filledElems) - { - int sum = 0; - for (uint8_t i=0; i(ret, abs(buffer[i] - meanVal())); - return ret; - } else - return 0; - } - - int16_t stdDev() - { - if (filledElems) - { - int16_t mean=meanVal(); - int calc = 0; - for (uint8_t i=0; i= val + int i = 1, retval = 1; + while (retval <= val) { + i++; + retval = i * i; + } + return i - 1; + } + int16_t meanVal() { - return anaIn_diag(i); + if (filledElems) { + int sum = 0; + for (uint8_t i = 0; i < filledElems; i++) sum += buffer[i]; + return (int16_t)(sum / filledElems); + } else + return 0; } - const char* column4prefix() override { return "+/- "; } - int column4size() override { return 2; } + public: + Stats() {} - int16_t column4(int i) override + void clear() { - return stats[i].maxDev(); + writePos = 0; + filledElems = 0; } - public: - AnaFilteredDevViewWindow(Window * parent): - AnaViewWindow(parent) + // Always accept new data, discard old + void write(int16_t value) { - auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN) - + adcGetMaxInputs(ADC_INPUT_FLEX); - - for (uint8_t i = 0; i < max_inputs; i++) - stats[i].clear(); + buffer[writePos] = value; + writePos = (writePos + 1) % STATSDEPTH; + if (filledElems < STATSDEPTH) filledElems++; } - void checkEvents() override + uint16_t maxDev() { - auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN) - + adcGetMaxInputs(ADC_INPUT_FLEX); - - for (uint8_t i = 0; i < max_inputs; i++) { - stats[i].write(getAnalogValue(i)); - } - AnaViewWindow::checkEvents(); + if (filledElems) { + uint16_t ret = 0; + for (uint8_t i = 0; i < filledElems; i++) + ret = max(ret, abs(buffer[i] - meanVal())); + return ret; + } else + return 0; } -}; -class AnaUnfilteredRawViewWindow: public AnaViewWindow { - public: - AnaUnfilteredRawViewWindow(Window * parent): - AnaViewWindow(parent) + int16_t stdDev() { + if (filledElems) { + int16_t mean = meanVal(); + int calc = 0; + for (uint8_t i = 0; i < filledElems; i++) + calc += (buffer[i] - mean) * (buffer[i] - mean); + calc = intSqrt((int16_t)(calc / filledElems)); + return (int16_t)calc; + } else + return 0; } + }; - protected: - int16_t column3(int i) override - { - return getAnalogValue(i); + Stats stats[MAX_CALIB_ANALOG_INPUTS]; + + int16_t column3(int i) override { return anaIn_diag(i); } + + const char* column4prefix() override { return "+/- "; } + int column4size() override { return 2; } + + int16_t column4(int i) override { return stats[i].maxDev(); } + + public: + AnaFilteredDevViewWindow(Window* parent) : AnaViewWindow(parent) + { + auto max_inputs = + adcGetMaxInputs(ADC_INPUT_MAIN) + adcGetMaxInputs(ADC_INPUT_FLEX); + + for (uint8_t i = 0; i < max_inputs; i++) stats[i].clear(); + } + + void checkEvents() override + { + auto max_inputs = + adcGetMaxInputs(ADC_INPUT_MAIN) + adcGetMaxInputs(ADC_INPUT_FLEX); + + for (uint8_t i = 0; i < max_inputs; i++) { + stats[i].write(getAnalogValue(i)); } + AnaViewWindow::checkEvents(); + } }; -class AnaMinMaxViewWindow: public AnaViewWindow { - protected: - class MinMax { - protected: - bool noElements = true; - int16_t minvalue = INT16_MAX; - int16_t maxvalue = INT16_MIN; - - public: - MinMax() {} - - void clear() - { - minvalue = INT16_MAX; - maxvalue = INT16_MIN; - } - - // Always accept new data, discard old - void write(int16_t value) - { - if (value < minvalue) - minvalue = value; - if (value > maxvalue) - maxvalue = value; - } - - int16_t MinVal() - { - return minvalue; - } - - int16_t MaxVal() - { - return maxvalue; - } - - uint16_t Range() - { - if (maxvalue > minvalue) - return (uint16_t)(maxvalue - minvalue); - else - return 0; - } - }; - - MinMax minmax[MAX_CALIB_ANALOG_INPUTS]; - - int16_t column3(int i) override - { - return minmax[i].MinVal(); - } +class AnaUnfilteredRawViewWindow : public AnaViewWindow +{ + public: + AnaUnfilteredRawViewWindow(Window* parent) : AnaViewWindow(parent) {} - int column4size() override { return 1; } + protected: + int16_t column3(int i) override { return getAnalogValue(i); } +}; - int16_t column4(int i) override - { - return minmax[i].MaxVal(); - } +class AnaMinMaxViewWindow : public AnaViewWindow +{ + protected: + class MinMax + { + protected: + bool noElements = true; + int16_t minvalue = INT16_MAX; + int16_t maxvalue = INT16_MIN; - int column5size() override { return 1; } + public: + MinMax() {} - int16_t column5(int i) override + void clear() { - return minmax[i].Range(); + minvalue = INT16_MAX; + maxvalue = INT16_MIN; } - public: - AnaMinMaxViewWindow(Window * parent): - AnaViewWindow(parent) + // Always accept new data, discard old + void write(int16_t value) { - auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN) - + adcGetMaxInputs(ADC_INPUT_FLEX); - - for (uint8_t i = 0; i < max_inputs; i++) - minmax[i].clear(); + if (value < minvalue) minvalue = value; + if (value > maxvalue) maxvalue = value; } - - void build() override - { - line = newLine(grid); - auto ttl = new StaticText(line, rect_t{}, STR_ANADIAGS_MOVE, COLOR_THEME_PRIMARY1); - lv_obj_set_grid_cell(ttl->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, GRIDCOLS, LV_GRID_ALIGN_CENTER, 0, 1); - AnaViewWindow::build(); - } + int16_t MinVal() { return minvalue; } - void checkEvents() override + int16_t MaxVal() { return maxvalue; } + + uint16_t Range() { - auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN) - + adcGetMaxInputs(ADC_INPUT_FLEX); - - for (uint8_t i = 0; i < max_inputs; i++) { - minmax[i].write(getAnalogValue(i)); - } - AnaViewWindow::checkEvents(); + if (maxvalue > minvalue) + return (uint16_t)(maxvalue - minvalue); + else + return 0; + } + }; + + MinMax minmax[MAX_CALIB_ANALOG_INPUTS]; + + int16_t column3(int i) override { return minmax[i].MinVal(); } + + int column4size() override { return 1; } + + int16_t column4(int i) override { return minmax[i].MaxVal(); } + + int column5size() override { return 1; } + + int16_t column5(int i) override { return minmax[i].Range(); } + + public: + AnaMinMaxViewWindow(Window* parent) : AnaViewWindow(parent) + { + auto max_inputs = + adcGetMaxInputs(ADC_INPUT_MAIN) + adcGetMaxInputs(ADC_INPUT_FLEX); + + for (uint8_t i = 0; i < max_inputs; i++) minmax[i].clear(); + } + + void build() override + { + line = newLine(grid); + auto ttl = + new StaticText(line, rect_t{}, STR_ANADIAGS_MOVE, COLOR_THEME_PRIMARY1); + lv_obj_set_grid_cell(ttl->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, GRIDCOLS, + LV_GRID_ALIGN_CENTER, 0, 1); + + AnaViewWindow::build(); + } + + void checkEvents() override + { + auto max_inputs = + adcGetMaxInputs(ADC_INPUT_MAIN) + adcGetMaxInputs(ADC_INPUT_FLEX); + + for (uint8_t i = 0; i < max_inputs; i++) { + minmax[i].write(getAnalogValue(i)); } + AnaViewWindow::checkEvents(); + } }; class AnaCalibratedViewPage : public PageTab @@ -455,7 +460,8 @@ class AnaCalibratedViewPage : public PageTab AnaCalibratedViewPage() : PageTab(STR_ANADIAGS_CALIB, ICON_STATS_ANALOGS) {} protected: - void build(FormWindow* window) override { + void build(Window* window) override + { (new AnaCalibratedViewWindow(window))->build(); } }; @@ -463,10 +469,14 @@ class AnaCalibratedViewPage : public PageTab class AnaFilteredDevViewPage : public PageTab { public: - AnaFilteredDevViewPage() : PageTab(STR_ANADIAGS_FILTRAWDEV, ICON_STATS_THROTTLE_GRAPH) {} + AnaFilteredDevViewPage() : + PageTab(STR_ANADIAGS_FILTRAWDEV, ICON_STATS_THROTTLE_GRAPH) + { + } protected: - void build(FormWindow* window) override { + void build(Window* window) override + { (new AnaFilteredDevViewWindow(window))->build(); } }; @@ -474,10 +484,14 @@ class AnaFilteredDevViewPage : public PageTab class AnaUnfilteredRawViewPage : public PageTab { public: - AnaUnfilteredRawViewPage() : PageTab(STR_ANADIAGS_UNFILTRAW, ICON_RADIO_HARDWARE) {} + AnaUnfilteredRawViewPage() : + PageTab(STR_ANADIAGS_UNFILTRAW, ICON_RADIO_HARDWARE) + { + } protected: - void build(FormWindow* window) override { + void build(Window* window) override + { (new AnaUnfilteredRawViewWindow(window))->build(); } }; @@ -488,12 +502,14 @@ class AnaMinMaxViewPage : public PageTab AnaMinMaxViewPage() : PageTab(STR_ANADIAGS_MINMAX, ICON_RADIO_CALIBRATION) {} protected: - void build(FormWindow* window) override { + void build(Window* window) override + { (new AnaMinMaxViewWindow(window))->build(); } }; -RadioAnalogsDiagsViewPageGroup::RadioAnalogsDiagsViewPageGroup() : TabsGroup(ICON_STATS) +RadioAnalogsDiagsViewPageGroup::RadioAnalogsDiagsViewPageGroup() : + TabsGroup(ICON_STATS) { addTab(new AnaCalibratedViewPage()); addTab(new AnaFilteredDevViewPage()); diff --git a/radio/src/gui/colorlcd/radio_diagkeys.cpp b/radio/src/gui/colorlcd/radio_diagkeys.cpp index d8dee02bb92..289df17b302 100644 --- a/radio/src/gui/colorlcd/radio_diagkeys.cpp +++ b/radio/src/gui/colorlcd/radio_diagkeys.cpp @@ -19,16 +19,18 @@ * GNU General Public License for more details. */ -#include "opentx.h" #include "radio_diagkeys.h" -#include "libopenui.h" #include "hal/rotary_encoder.h" +#include "libopenui.h" +#include "opentx.h" #if defined(PCBPL18) -static const uint8_t _trimMap[MAX_TRIMS * 2] = {8, 9, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 0, 1, 6, 7}; +static const uint8_t _trimMap[MAX_TRIMS * 2] = {8, 9, 10, 11, 12, 13, 14, 15, + 2, 3, 4, 5, 0, 1, 6, 7}; #else -static const uint8_t _trimMap[MAX_TRIMS * 2] = {6, 7, 4, 5, 2, 3, 0, 1, 8, 9, 10, 11}; +static const uint8_t _trimMap[MAX_TRIMS * 2] = {6, 7, 4, 5, 2, 3, + 0, 1, 8, 9, 10, 11}; #endif static EnumKeys get_ith_key(uint8_t i) @@ -47,115 +49,196 @@ static EnumKeys get_ith_key(uint8_t i) class RadioKeyDiagsWindow : public Window { - public: - RadioKeyDiagsWindow(Window * parent, const rect_t &rect) : - Window(parent, rect) - { + public: + RadioKeyDiagsWindow(Window *parent, const rect_t &rect) : Window(parent, rect) + { + padAll(PAD_ZERO); + + coord_t colWidth = (width() - 24) / 3; + coord_t colHeight = height() - 12; + + Window* form; + coord_t x = 6; + + if (keysGetMaxKeys() > 0) { + form = new Window(parent, rect_t{x, 6, colWidth, colHeight}); + addKeys(form); + x += colWidth + 6; + } else { + colWidth = (width() - 18) / 2; } - void checkEvents() override - { - // will always force a full monitor window refresh - invalidate(); - } + form = new Window(parent, rect_t{x, 6, colWidth, colHeight}); + addSwitches(form); + x += colWidth + 6; - void displayTrimState(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t trim) - { - uint8_t t = keysGetTrimState(trim); - // TODO use drawChar when done - char status[2]; - status[0] = t + '0'; - status[1] = '\0'; - // TODO INVERS? - dc->drawText(x, y, status, COLOR_THEME_PRIMARY1); - } + form = + new Window(parent, rect_t{x, 6, colWidth, colHeight}); + addTrims(form); + } + + ~RadioKeyDiagsWindow() + { + delete keyValues; + delete switchValues; + delete trimValues; + } + + void addKeys(Window *form) + { + keyValues = new lv_obj_t *[keysGetMaxKeys()]; + lv_obj_t *obj = form->getLvObj(); + uint8_t i; + + // KEYS + for (i = 0; i < keysGetMaxKeys(); i++) { + auto k = get_ith_key(i); - void displayKeyState(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t key) - { - uint8_t t = keysGetState(key); - // TODO use drawChar when done - char status[2]; - status[0] = t + '0'; - status[1] = '\0'; - // TODO INVERS? - dc->drawText(x, y, status, COLOR_THEME_PRIMARY1); + auto lbl = lv_label_create(obj); + lv_label_set_text(lbl, keysGetLabel(k)); + lv_obj_set_pos(lbl, 0, i * FH); + + lbl = lv_label_create(obj); + lv_label_set_text(lbl, ""); + lv_obj_set_pos(lbl, 70, i * FH); + keyValues[i] = lbl; } - void paint(BitmapBuffer * dc) override - { - constexpr coord_t KEY_COLUMN = 6; -#if !defined(PCBNV14) - constexpr coord_t SWITCHES_COLUMN = LCD_W / 2 - 20; - constexpr coord_t TRIM_COLUMN = LCD_W - 120; -#else - constexpr coord_t SWITCHES_COLUMN = LCD_W / 3; - constexpr coord_t TRIM_COLUMN = 2 * LCD_W / 3; -#endif - constexpr coord_t TRIM_MINUS_COLUMN = TRIM_COLUMN + 60; - constexpr coord_t TRIM_PLUS_COLUMN = TRIM_MINUS_COLUMN + 20; - - dc->drawText(TRIM_COLUMN, 1, "Trims", COLOR_THEME_PRIMARY1); - dc->drawText(TRIM_MINUS_COLUMN, 1, "-", COLOR_THEME_PRIMARY1); - dc->drawText(TRIM_PLUS_COLUMN, 1, "+", COLOR_THEME_PRIMARY1); - - // KEYS - coord_t y = 1; - for (uint8_t i = 0; i < keysGetMaxKeys(); i++) { - auto k = get_ith_key(i); - dc->drawText(KEY_COLUMN, y, keysGetLabel(k), COLOR_THEME_PRIMARY1); - displayKeyState(dc, 70, y, k); - y += FH; - } #if defined(ROTARY_ENCODER_NAVIGATION) && !defined(USE_HATS_AS_KEYS) - y += FH; - dc->drawText(KEY_COLUMN, y, STR_ROTARY_ENCODER, COLOR_THEME_PRIMARY1); - dc->drawNumber(70, y, rotaryEncoderGetValue(), COLOR_THEME_PRIMARY1); + auto lbl = lv_label_create(obj); + lv_label_set_text(lbl, STR_ROTARY_ENCODER); + lv_obj_set_pos(lbl, 0, (i + 1) * FH); + + reValue = lv_label_create(obj); + lv_label_set_text(reValue, ""); + lv_obj_set_pos(reValue, 70, (i + 1) * FH); #endif - // SWITCHES - y = 1; - for (uint8_t i = 0; i < switchGetMaxSwitches(); i++) { - if (SWITCH_EXISTS(i)) { - getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i); - getvalue_t sw = ((val < 0) ? 3 * i + 1 : ((val == 0) ? 3 * i + 2 : 3 * i + 3)); - drawSwitch(dc, SWITCHES_COLUMN, y, sw, COLOR_THEME_PRIMARY1); - y +=FH; - } + } + + void addSwitches(Window *form) + { + switchValues = new lv_obj_t *[switchGetMaxSwitches()]; + lv_obj_t *obj = form->getLvObj(); + uint8_t i; + uint8_t row = 0; + + // SWITCHES + for (i = 0; i < switchGetMaxSwitches(); i++) { + if (SWITCH_EXISTS(i)) { + auto lbl = lv_label_create(obj); + lv_label_set_text(lbl, ""); + lv_obj_set_pos(lbl, 0, row * FH); + switchValues[i] = lbl; + row += 1; } + } + } - // TRIMS - for (uint8_t i = 0; i < keysGetMaxTrims() * 2; i++) { - coord_t y = 1 + FH + FH * (i / 2); - if (i & 1) { -#if defined(PCBPL18) - dc->drawText(TRIM_COLUMN, y, "TR", COLOR_THEME_PRIMARY1); - dc->drawNumber(TRIM_COLUMN + 20, y, i / 2 + 1, COLOR_THEME_PRIMARY1); -#else - dc->drawText(TRIM_COLUMN, y, "T", COLOR_THEME_PRIMARY1); - dc->drawNumber(TRIM_COLUMN + 10, y, i / 2 + 1, COLOR_THEME_PRIMARY1); + void addTrims(Window *form) + { + trimValues = new lv_obj_t *[keysGetMaxTrims() * 2]; + lv_obj_t *obj = form->getLvObj(); + char s[10]; + + auto lbl = lv_label_create(obj); + lv_label_set_text(lbl, STR_TRIMS); + lv_obj_set_pos(lbl, 0, 0); + lbl = lv_label_create(obj); + lv_label_set_text(lbl, "-"); + lv_obj_set_pos(lbl, 62, 0); + lbl = lv_label_create(obj); + lv_label_set_text(lbl, "+"); + lv_obj_set_pos(lbl, 75, 0); + + // TRIMS + for (uint8_t i = 0; i < keysGetMaxTrims(); i++) { + lbl = lv_label_create(obj); + formatNumberAsString(s, 10, i + 1, 0, 10, "T"); + lv_label_set_text(lbl, s); + lv_obj_set_pos(lbl, 4, i * FH + FH); + + lbl = lv_label_create(obj); + lv_label_set_text(lbl, ""); + lv_obj_set_pos(lbl, 60, i * FH + FH); + trimValues[i * 2] = lbl; + + lbl = lv_label_create(obj); + lv_label_set_text(lbl, ""); + lv_obj_set_pos(lbl, 75, i * FH + FH); + trimValues[i * 2 + 1] = lbl; + } + } + + void setKeyState() + { + char s[10] = "0"; + + for (uint8_t i = 0; i < keysGetMaxKeys(); i++) { + auto k = get_ith_key(i); + s[0] = keysGetState(k) + '0'; + lv_label_set_text(keyValues[i], s); + } + +#if defined(ROTARY_ENCODER_NAVIGATION) && !defined(USE_HATS_AS_KEYS) + formatNumberAsString(s, 10, rotaryEncoderGetValue()); + lv_label_set_text(reValue, s); #endif - } - displayTrimState(dc, i & 1 ? TRIM_PLUS_COLUMN : TRIM_MINUS_COLUMN, y, _trimMap[i]); + } + + void setSwitchState() + { + uint8_t i; + + for (i = 0; i < switchGetMaxSwitches(); i++) { + if (SWITCH_EXISTS(i)) { + getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i); + getvalue_t sw = + ((val < 0) ? 3 * i + 1 : ((val == 0) ? 3 * i + 2 : 3 * i + 3)); + lv_label_set_text(switchValues[i], getSwitchPositionName(sw)); } - }; + } + } + + void setTrimState() + { + char s[10] = "0"; + + for (uint8_t i = 0; i < keysGetMaxTrims() * 2; i++) { + s[0] = keysGetTrimState(i) + '0'; + lv_label_set_text(trimValues[_trimMap[i]], s); + } + } + + void checkEvents() override + { + setKeyState(); + setSwitchState(); + setTrimState(); + } - protected: + protected: + lv_obj_t **keyValues = nullptr; +#if defined(ROTARY_ENCODER_NAVIGATION) && !defined(USE_HATS_AS_KEYS) + lv_obj_t *reValue = nullptr; +#endif + lv_obj_t **switchValues = nullptr; + lv_obj_t **trimValues = nullptr; }; -void RadioKeyDiagsPage::buildHeader(Window * window) +void RadioKeyDiagsPage::buildHeader(Window *window) { header.setTitle(STR_RADIO_SETUP); header.setTitle2(STR_MENU_RADIO_SWITCHES); } -void RadioKeyDiagsPage::buildBody(Window * window) +void RadioKeyDiagsPage::buildBody(Window *window) { - new RadioKeyDiagsWindow(window, {0, 5, window->width() - 10, window->height() - 10}); + body.padAll(PAD_ZERO); + new RadioKeyDiagsWindow(window, {0, 0, window->width(), window->height()}); } -RadioKeyDiagsPage::RadioKeyDiagsPage() : - Page(ICON_MODEL_SETUP) +RadioKeyDiagsPage::RadioKeyDiagsPage() : Page(ICON_MODEL_SETUP) { buildHeader(&header); buildBody(&body); - // setFocus(SET_FOCUS_DEFAULT); } diff --git a/radio/src/gui/colorlcd/radio_ghost_module_config.cpp b/radio/src/gui/colorlcd/radio_ghost_module_config.cpp index 0120f1775ff..71dc44e5970 100644 --- a/radio/src/gui/colorlcd/radio_ghost_module_config.cpp +++ b/radio/src/gui/colorlcd/radio_ghost_module_config.cpp @@ -19,73 +19,91 @@ * GNU General Public License for more details. */ -#include "opentx.h" #include "radio_ghost_module_config.h" + #include "libopenui.h" +#include "opentx.h" #include "telemetry/ghost.h" #include "telemetry/ghost_menu.h" -class GhostModuleConfigWindow: public Window +class GhostModuleConfigWindow : public Window { - public: - GhostModuleConfigWindow(Window * parent, const rect_t & rect) : - Window(parent, rect, REFRESH_ALWAYS) - { - // setFocus(SET_FOCUS_DEFAULT); - } - - void paint(BitmapBuffer * dc) override - { + public: + GhostModuleConfigWindow(Window* parent, const rect_t& rect) : + Window(parent, rect) + { #if LCD_H > LCD_W - constexpr coord_t xOffset = 20; - constexpr coord_t xOffset2 = 140; + constexpr coord_t xOffset = 20; + constexpr coord_t xOffset2 = 140; #else - constexpr coord_t xOffset = 140; - constexpr coord_t xOffset2 = 260; + constexpr coord_t xOffset = 140; + constexpr coord_t xOffset2 = 260; #endif - constexpr coord_t yOffset = 20; - constexpr coord_t lineSpacing = 25; - - for (uint8_t line = 0; line < GHST_MENU_LINES; line++) { - if (reusableBuffer.ghostMenu.line[line].splitLine) { - if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_LABEL_SELECT) { - dc->drawSolidFilledRect(xOffset, yOffset + line * lineSpacing, getTextWidth(reusableBuffer.ghostMenu.line[line].menuText, 0,FONT(L)), getFontHeight(FONT(L)), FONT(L) | COLOR_THEME_FOCUS); - dc->drawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, FONT(L) | COLOR_THEME_SECONDARY3); - } - else { - dc->drawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, FONT(L)); - } - - if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_SELECT) { - dc->drawSolidFilledRect(xOffset, yOffset + line * lineSpacing, getTextWidth( &reusableBuffer.ghostMenu.line[line].menuText[reusableBuffer.ghostMenu.line[line].splitLine], 0,FONT(L)), getFontHeight(0), COLOR_THEME_FOCUS); - dc->drawText(xOffset, yOffset + line * lineSpacing, &reusableBuffer.ghostMenu.line[line].menuText[reusableBuffer.ghostMenu.line[line].splitLine], FONT(L) | COLOR_THEME_SECONDARY3); - } - else { - dc->drawText(xOffset2, yOffset + line * lineSpacing, &reusableBuffer.ghostMenu.line[line].menuText[reusableBuffer.ghostMenu.line[line].splitLine], FONT(L) | COLOR_THEME_SECONDARY1); - } - } - else { - if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_LABEL_SELECT) { - dc->drawSolidFilledRect(xOffset, yOffset + line * lineSpacing, getTextWidth(reusableBuffer.ghostMenu.line[line].menuText, 0, FONT(L)), getFontHeight(FONT(L)), COLOR_THEME_FOCUS); - dc->drawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, FONT(L) | COLOR_THEME_SECONDARY3); - } - else if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_EDIT) { - if (BLINK_ON_PHASE) { - dc->drawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, FONT(L)); - } - } - else { - dc->drawText(xOffset, yOffset + line * lineSpacing, reusableBuffer.ghostMenu.line[line].menuText, FONT(L) | COLOR_THEME_SECONDARY1); - } - } + constexpr coord_t yOffset = 20; + constexpr coord_t lineSpacing = 25; + coord_t h = getFontHeight(FONT(L)); + + for (int i = 0; i < GHST_MENU_LINES; i += 1) { + menuLines[i][0] = new StaticText( + this, {xOffset, yOffset + i * lineSpacing, LV_SIZE_CONTENT, h}, "", + FONT(L)); + etx_txt_color(menuLines[i][0]->getLvObj(), COLOR_THEME_SECONDARY1_INDEX, + LV_PART_MAIN); + etx_solid_bg(menuLines[i][0]->getLvObj(), COLOR_THEME_FOCUS_INDEX, + LV_STATE_USER_1); + etx_txt_color(menuLines[i][0]->getLvObj(), COLOR_THEME_SECONDARY3_INDEX, + LV_STATE_USER_1); + + menuLines[i][1] = new StaticText( + this, {xOffset2, yOffset + i * lineSpacing, LV_SIZE_CONTENT, h}, "", + FONT(L)); + etx_txt_color(menuLines[i][1]->getLvObj(), COLOR_THEME_SECONDARY1_INDEX, + LV_PART_MAIN); + etx_solid_bg(menuLines[i][1]->getLvObj(), COLOR_THEME_FOCUS_INDEX, + LV_STATE_USER_1); + etx_txt_color(menuLines[i][1]->getLvObj(), COLOR_THEME_SECONDARY3_INDEX, + LV_STATE_USER_1); + } + } + + protected: + StaticText* menuLines[GHST_MENU_LINES][2]; + + void checkEvents() override + { + for (uint8_t i = 0; i < GHST_MENU_LINES; i += 1) { + if (reusableBuffer.ghostMenu.line[i].splitLine) { + menuLines[i][0]->setText(reusableBuffer.ghostMenu.line[i].menuText); + if (reusableBuffer.ghostMenu.line[i].lineFlags & + GHST_LINE_FLAGS_LABEL_SELECT) + lv_obj_add_state(menuLines[i][0]->getLvObj(), LV_STATE_USER_1); + + menuLines[i][1]->setText(reusableBuffer.ghostMenu.line[i].menuText + + reusableBuffer.ghostMenu.line[i].splitLine); + if (reusableBuffer.ghostMenu.line[i].lineFlags & + GHST_LINE_FLAGS_VALUE_SELECT) + lv_obj_add_state(menuLines[i][1]->getLvObj(), LV_STATE_USER_1); + } else { + if (reusableBuffer.ghostMenu.line[i].lineFlags & + GHST_LINE_FLAGS_VALUE_EDIT && + BLINK_ON_PHASE) + menuLines[i][0]->setText(""); + else + menuLines[i][0]->setText(reusableBuffer.ghostMenu.line[i].menuText); + if (reusableBuffer.ghostMenu.line[i].lineFlags & + GHST_LINE_FLAGS_LABEL_SELECT) + lv_obj_add_state(menuLines[i][0]->getLvObj(), LV_STATE_USER_1); + + menuLines[i][1]->setText(""); } } - protected: + } }; static void ghostmoduleconfig_cb(lv_event_t* e) { - RadioGhostModuleConfig* ghostmoduleconfig = (RadioGhostModuleConfig*)lv_event_get_user_data(e); + RadioGhostModuleConfig* ghostmoduleconfig = + (RadioGhostModuleConfig*)lv_event_get_user_data(e); if (!ghostmoduleconfig || ghostmoduleconfig->deleted()) return; uint32_t key = lv_event_get_key(e); @@ -120,8 +138,7 @@ void RadioGhostModuleConfig::onCancel() #endif RadioGhostModuleConfig::RadioGhostModuleConfig(uint8_t moduleIdx) : - Page(ICON_RADIO_TOOLS), - moduleIdx(moduleIdx) + Page(ICON_RADIO_TOOLS), moduleIdx(moduleIdx) { init(); buildHeader(&header); @@ -136,14 +153,16 @@ RadioGhostModuleConfig::RadioGhostModuleConfig(uint8_t moduleIdx) : #endif } -void RadioGhostModuleConfig::buildHeader(Window * window) +void RadioGhostModuleConfig::buildHeader(Window* window) { header.setTitle("GHOST MODULE"); } -void RadioGhostModuleConfig::buildBody(FormWindow * window) +void RadioGhostModuleConfig::buildBody(Window* window) { - new GhostModuleConfigWindow(window, {0, 0, LCD_W, LCD_H - MENU_HEADER_HEIGHT - 5}); + window->padAll(PAD_ZERO); + new GhostModuleConfigWindow(window, + {0, 0, LCD_W, LCD_H - MENU_HEADER_HEIGHT - 5}); } #if defined(HARDWARE_KEYS) && !defined(PCBPL18) @@ -168,12 +187,13 @@ void RadioGhostModuleConfig::checkEvents() { Page::checkEvents(); - if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_UNOPENED) { // Handles situation where module is plugged after tools start + if (reusableBuffer.ghostMenu.menuStatus == + GHST_MENU_STATUS_UNOPENED) { // Handles situation where module is + // plugged after tools start reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE; reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN; moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL; - } - else if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_CLOSING) { + } else if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_CLOSING) { RTOS_WAIT_MS(10); deleteLater(); #if defined(TRIMS_EMULATE_BUTTONS) @@ -190,4 +210,3 @@ void RadioGhostModuleConfig::init() reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN; moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL; } - diff --git a/radio/src/gui/colorlcd/radio_ghost_module_config.h b/radio/src/gui/colorlcd/radio_ghost_module_config.h index 3d758ff37ea..0087e5c6e72 100644 --- a/radio/src/gui/colorlcd/radio_ghost_module_config.h +++ b/radio/src/gui/colorlcd/radio_ghost_module_config.h @@ -38,7 +38,7 @@ class RadioGhostModuleConfig: public Page uint8_t moduleIdx; void buildHeader(Window * window); - void buildBody(FormWindow * window); + void buildBody(Window * window); void init(); }; diff --git a/radio/src/gui/colorlcd/radio_hardware.cpp b/radio/src/gui/colorlcd/radio_hardware.cpp index f7f24c61b15..56d4311178a 100644 --- a/radio/src/gui/colorlcd/radio_hardware.cpp +++ b/radio/src/gui/colorlcd/radio_hardware.cpp @@ -20,17 +20,17 @@ */ #include "radio_hardware.h" -#include "radio_calibration.h" -#include "radio_diagkeys.h" -#include "radio_diaganas.h" -#include "opentx.h" -#include "libopenui.h" -#include "hal/adc_driver.h" -#include "hw_intmodule.h" +#include "hal/adc_driver.h" #include "hw_extmodule.h" -#include "hw_serial.h" #include "hw_inputs.h" +#include "hw_intmodule.h" +#include "hw_serial.h" +#include "libopenui.h" +#include "opentx.h" +#include "radio_calibration.h" +#include "radio_diaganas.h" +#include "radio_diagkeys.h" #if defined(BLUETOOTH) #include "hw_bluetooth.h" @@ -43,164 +43,182 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -RadioHardwarePage::RadioHardwarePage(): - PageTab(STR_HARDWARE, ICON_RADIO_HARDWARE) +static Window* hbox(Window* parent) { + auto box = new Window(parent, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL); + lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); + lv_obj_set_flex_align(box->getLvObj(), LV_FLEX_ALIGN_START, + LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); + + return box; } -void RadioHardwarePage::checkEvents() +RadioHardwarePage::RadioHardwarePage() : + PageTab(STR_HARDWARE, ICON_RADIO_HARDWARE) { - enableVBatBridge(); } -void RadioHardwarePage::build(FormWindow * window) +void RadioHardwarePage::checkEvents() { enableVBatBridge(); } + +class BatCalEdit : public NumberEdit +{ + public: + BatCalEdit(Window* parent, const rect_t& rect) : + NumberEdit(parent, rect, -127, 127, + GET_SET_DEFAULT(g_eeGeneral.txVoltageCalibration)) + { + setDisplayHandler([](int32_t value) { + return formatNumberAsString(getBatteryVoltage(), PREC2, 0, nullptr, "V"); + }); + lastBatVolts = getBatteryVoltage(); + } + + protected: + uint16_t lastBatVolts = 0; + + void checkEvents() override + { + if (getBatteryVoltage() != lastBatVolts) { + lastBatVolts = getBatteryVoltage(); + invalidate(); + } + } +}; + +void RadioHardwarePage::build(Window* window) { window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); - FlexGridLayout grid(col_dsc, row_dsc, 2); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); // TODO: sub-title? // Batt meter range - Range 3.0v to 16v - auto line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_BATTERY_RANGE, 0, COLOR_THEME_PRIMARY1); + auto line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_BATTERY_RANGE, COLOR_THEME_PRIMARY1); - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(4)); - lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - lv_obj_set_flex_align(box->getLvObj(), LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); - - auto batMin = - new NumberEdit(box, rect_t{0, 0, 80, 0}, -60 + 90, g_eeGeneral.vBatMax + 29 + 90, - GET_SET_WITH_OFFSET(g_eeGeneral.vBatMin, 90), 0, PREC1); + auto box = hbox(line); + auto batMin = new NumberEdit( + box, rect_t{0, 0, 80, 0}, -60 + 90, g_eeGeneral.vBatMax + 29 + 90, + GET_SET_WITH_OFFSET(g_eeGeneral.vBatMin, 90), PREC1); batMin->setSuffix("V"); new StaticText(box, rect_t{}, "-"); - auto batMax = - new NumberEdit(box, rect_t{0, 0, 80, 0}, g_eeGeneral.vBatMin - 29 + 120, 40 + 120, - GET_SET_WITH_OFFSET(g_eeGeneral.vBatMax, 120), 0, PREC1); + auto batMax = new NumberEdit( + box, rect_t{0, 0, 80, 0}, g_eeGeneral.vBatMin - 29 + 120, 40 + 120, + GET_SET_WITH_OFFSET(g_eeGeneral.vBatMax, 120), PREC1); batMax->setSuffix("V"); batMin->setSetValueHandler([=](int32_t newValue) { g_eeGeneral.vBatMin = newValue - 90; SET_DIRTY(); batMax->setMin(g_eeGeneral.vBatMin - 29 + 120); - batMax->invalidate(); }); batMax->setSetValueHandler([=](int32_t newValue) { g_eeGeneral.vBatMax = newValue - 120; SET_DIRTY(); batMin->setMax(g_eeGeneral.vBatMax + 29 + 90); - batMin->invalidate(); }); // Bat calibration - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_BATT_CALIB, 0, COLOR_THEME_PRIMARY1); - auto batCal = - new NumberEdit(line, rect_t{0, 0, 80, 0}, -127, 127, - GET_SET_DEFAULT(g_eeGeneral.txVoltageCalibration)); - batCal->setDisplayHandler([](int32_t value) { - return formatNumberAsString(getBatteryVoltage(), PREC2, 0, nullptr, "V"); - }); - batCal->setWindowFlags(REFRESH_ALWAYS); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_BATT_CALIB, COLOR_THEME_PRIMARY1); + box = hbox(line); + new BatCalEdit(box, rect_t{0, 0, 80, 0}); // RTC Batt check enable - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_RTC_CHECK, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_RTC_CHECK, COLOR_THEME_PRIMARY1); - box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); - lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); - new ToggleSwitch(box, rect_t{}, GET_SET_INVERTED(g_eeGeneral.disableRtcWarning )); + box = hbox(line); + new ToggleSwitch(box, rect_t{}, + GET_SET_INVERTED(g_eeGeneral.disableRtcWarning)); // RTC Batt display - new StaticText(box, rect_t{}, STR_VALUE, 0, COLOR_THEME_PRIMARY1); - new DynamicNumber(box, rect_t{}, [] { - return getRTCBatteryVoltage(); - }, COLOR_THEME_PRIMARY1 | PREC2, nullptr, "V"); + new StaticText(box, rect_t{}, STR_VALUE, COLOR_THEME_PRIMARY1); + new DynamicNumber( + box, rect_t{}, [] { return getRTCBatteryVoltage(); }, + COLOR_THEME_PRIMARY1 | PREC2, nullptr, "V"); // ADC filter - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_JITTER_FILTER, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, GET_SET_INVERTED(g_eeGeneral.noJitterFilter)); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_JITTER_FILTER, COLOR_THEME_PRIMARY1); + box = hbox(line); + new ToggleSwitch(box, rect_t{}, GET_SET_INVERTED(g_eeGeneral.noJitterFilter)); #if defined(AUDIO_MUTE_GPIO) // Mute audio - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_AUDIO_MUTE, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.audioMuteEnable)); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_AUDIO_MUTE, COLOR_THEME_PRIMARY1); + box = hbox(line); + new ToggleSwitch(box, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.audioMuteEnable)); #endif #if defined(HARDWARE_INTERNAL_MODULE) new Subtitle(window, STR_INTERNALRF); - auto intMod = new InternalModuleWindow(window); - intMod->padLeft(lv_dpx(8)); + line = window->newLine(grid); + line->padLeft(PAD_SMALL); + new InternalModuleWindow(line, grid); #endif #if defined(HARDWARE_EXTERNAL_MODULE) new Subtitle(window, STR_EXTERNALRF); - auto extMod = new ExternalModuleWindow(window); - extMod->padLeft(lv_dpx(8)); + line = window->newLine(grid); + line->padLeft(PAD_SMALL); + new ExternalModuleWindow(line, grid); #endif #if defined(BLUETOOTH) new Subtitle(window, STR_BLUETOOTH); - auto bt = new BluetoothConfigWindow(window); - bt->padLeft(lv_dpx(8)); + line = window->newLine(grid); + line->padLeft(PAD_SMALL); + new BluetoothConfigWindow(window, grid); #endif new Subtitle(window, STR_AUX_SERIAL_MODE); - auto serial = new SerialConfigWindow(window, rect_t{}); - serial->padLeft(lv_dpx(8)); + new SerialConfigWindow(window, grid); // Calibration new Subtitle(window, STR_INPUTS); - box = new FormWindow(window, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8)); - lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0); - box->padRow(lv_dpx(8)); - box->padAll(lv_dpx(8)); - - auto calib = new TextButton(box, rect_t{}, STR_CALIBRATION); - calib->setPressHandler([=]() -> uint8_t { - new RadioCalibrationPage(); - return 0; + box = new Window(window, rect_t{}); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_MEDIUM); + lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, + 0); + box->padAll(PAD_MEDIUM); + + new TextButton(box, rect_t{0, 0, 100, 0}, STR_CALIBRATION, [=]() -> uint8_t { + new RadioCalibrationPage(); + return 0; }); - lv_obj_set_style_min_width(calib->getLvObj(), LV_DPI_DEF, 0); // Sticks - auto btn = makeHWInputButton(box, STR_STICKS); - lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0); + makeHWInputButton(box, STR_STICKS); // Pots & Sliders - btn = makeHWInputButton(box, STR_POTS); - lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0); + makeHWInputButton(box, STR_POTS); // Switches - btn = makeHWInputButton(box, STR_SWITCHES); - lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0); - + makeHWInputButton(box, STR_SWITCHES); + // Debugs new Subtitle(window, STR_DEBUG); - box = new FormWindow(window, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8)); - lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0); - box->padRow(lv_dpx(8)); - box->padAll(lv_dpx(8)); + box = new Window(window, rect_t{}); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_MEDIUM); + lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, + 0); + box->padAll(PAD_MEDIUM); - btn = new TextButton(box, rect_t{}, STR_ANALOGS_BTN, [=]() -> uint8_t { + new TextButton(box, rect_t{0, 0, 100, 0}, STR_ANALOGS_BTN, [=]() -> uint8_t { new RadioAnalogsDiagsViewPageGroup(); return 0; }); - lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0); - btn = new TextButton(box, rect_t{}, STR_KEYS_BTN, [=]() -> uint8_t { + new TextButton(box, rect_t{0, 0, 100, 0}, STR_KEYS_BTN, [=]() -> uint8_t { new RadioKeyDiagsPage(); return 0; }); - lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0); } diff --git a/radio/src/gui/colorlcd/radio_hardware.h b/radio/src/gui/colorlcd/radio_hardware.h index d000e942db6..1f023de6c3c 100644 --- a/radio/src/gui/colorlcd/radio_hardware.h +++ b/radio/src/gui/colorlcd/radio_hardware.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _RADIO_HARDWARE_H_ -#define _RADIO_HARDWARE_H_ +#pragma once #include "tabsgroup.h" @@ -31,7 +30,5 @@ class RadioHardwarePage : public PageTab public: RadioHardwarePage(); - void build(FormWindow* window) override; + void build(Window* window) override; }; - -#endif //_RADIO_HARDWARE_H_ diff --git a/radio/src/gui/colorlcd/radio_sdmanager.cpp b/radio/src/gui/colorlcd/radio_sdmanager.cpp index a9eec1dea9d..d6fa2ac12d1 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.cpp +++ b/radio/src/gui/colorlcd/radio_sdmanager.cpp @@ -32,6 +32,8 @@ #include "file_preview.h" #include "file_browser.h" #include "progress.h" +#include "themes/etx_lv_theme.h" +#include "fullscreen_dialog.h" constexpr int WARN_FILE_LENGTH = 40 * 1024; @@ -61,12 +63,8 @@ class FileNameEditWindow : public Page void buildBody(Window *window) { - window->padAll(0); - - auto form = new FormWindow(window, rect_t()); - form->setFlexLayout(LV_FLEX_FLOW_COLUMN, 4); - form->padAll(4); - form->padTop(12); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_SMALL); + window->padTop(12); uint8_t nameLength; uint8_t extLength; @@ -87,8 +85,8 @@ class FileNameEditWindow : public Page reusableBuffer.sdManager.originalName[nameLength] = '\0'; auto newFileName = new TextEdit( - form, rect_t{0, 0, LCD_W-8, 0}, reusableBuffer.sdManager.originalName, - SD_SCREEN_FILE_LENGTH - extLength, LcdFlags(0)); + window, rect_t{0, 0, LV_PCT(100), 0}, reusableBuffer.sdManager.originalName, + SD_SCREEN_FILE_LENGTH - extLength); newFileName->setChangeHandler([=]() { char *newValue = reusableBuffer.sdManager.originalName; size_t totalSize = strlen(newValue); @@ -157,18 +155,13 @@ class FlashDialog: public FullScreenDialog class FrskyOtaFlashDialog; ModuleCallback onUpdateStateChangedCallbackFor(FrskyOtaFlashDialog* dialog); -class FrskyOtaFlashDialog : public Dialog +class FrskyOtaFlashDialog : public BaseDialog { public: - explicit FrskyOtaFlashDialog(Window* parent, std::string title) : - Dialog(parent, title, rect_t{}) + explicit FrskyOtaFlashDialog(Window* parent, const char* title) : + BaseDialog(parent, title, true) { - setCloseWhenClickOutside(true); - auto form = &content->form; - new StaticText(form, rect_t{}, STR_WAITING_FOR_RX, 0, COLOR_THEME_PRIMARY1); - - content->setWidth(LCD_W * 0.8); - content->updateSize(); + new StaticText(form, rect_t{}, STR_WAITING_FOR_RX, COLOR_THEME_PRIMARY1); } void flash(const char * filename, ModuleIndex module) @@ -256,7 +249,7 @@ class FrskyOtaFlashDialog : public Dialog } } - Dialog::checkEvents(); + BaseDialog::checkEvents(); } protected: @@ -288,12 +281,12 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; #endif -void RadioSdManagerPage::build(FormWindow * window) +void RadioSdManagerPage::build(Window * window) { - FlexGridLayout grid(col_dsc, row_dsc, 0); - window->padAll(0); + FlexGridLayout grid(col_dsc, row_dsc, PAD_ZERO); + window->padAll(PAD_ZERO); - FormWindow* form = new FormWindow(window, rect_t{}); + Window* form = new Window(window, rect_t{}); form->setWidth(window->width()); form->setHeight(window->height()); grid.apply(form); @@ -301,7 +294,6 @@ void RadioSdManagerPage::build(FormWindow * window) browser = new FileBrowser(form, rect_t{}, ROOT_PATH); grid.add(browser); grid.nextCell(); - lv_obj_set_scrollbar_mode(browser->getLvObj(), LV_SCROLLBAR_MODE_AUTO); auto obj = browser->getLvObj(); lv_obj_set_style_grid_cell_x_align(obj, LV_GRID_ALIGN_STRETCH, 0); @@ -309,16 +301,16 @@ void RadioSdManagerPage::build(FormWindow * window) // Adjust file browser width browser->adjustWidth(); - - preview = new FilePreview(form, rect_t{}); + +#if LCD_W > LCD_H + preview = new FilePreview(form, rect_t{0, 0, LCD_W * 2 / 5 - 8, LCD_H - 68}); +#else + preview = new FilePreview(form, rect_t{0, 0, LCD_W - 12, (LCD_H - 68) / 3 }); +#endif + preview->padAll(PAD_SMALL); grid.add(preview); grid.nextCell(); - obj = preview->getLvObj(); - lv_obj_set_style_pad_all(obj, lv_dpx(8), 0); - lv_obj_set_style_grid_cell_x_align(obj, LV_GRID_ALIGN_STRETCH, 0); - lv_obj_set_style_grid_cell_y_align(obj, LV_GRID_ALIGN_STRETCH, 0); - browser->setFileAction([=](const char* path, const char* name, const char* fullpath) { fileAction(path, name, fullpath); }); @@ -382,9 +374,9 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name, sprintf(buf, " %s %dkB. %s", STR_FILE_SIZE, fileLength / 1024, STR_FILE_OPEN); new ConfirmDialog(window, STR_WARNING, buf, - [=] { new ViewTextWindow(path, name); }); + [=] { new ViewTextWindow(path, name, ICON_RADIO_SD_MANAGER); }); } else { - new ViewTextWindow(path, name); + new ViewTextWindow(path, name, ICON_RADIO_SD_MANAGER); } } }); diff --git a/radio/src/gui/colorlcd/radio_sdmanager.h b/radio/src/gui/colorlcd/radio_sdmanager.h index dc0f925b454..b0c728c6a58 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.h +++ b/radio/src/gui/colorlcd/radio_sdmanager.h @@ -33,7 +33,7 @@ class RadioSdManagerPage : public PageTab public: RadioSdManagerPage(); - void build(FormWindow* window) override; + void build(Window* window) override; protected: void fileAction(const char* path, const char* name, const char* fullpath); diff --git a/radio/src/gui/colorlcd/radio_setup.cpp b/radio/src/gui/colorlcd/radio_setup.cpp index 0821b0013ba..73b652fea1a 100644 --- a/radio/src/gui/colorlcd/radio_setup.cpp +++ b/radio/src/gui/colorlcd/radio_setup.cpp @@ -22,213 +22,202 @@ #define LANGUAGE_PACKS_DEFINITION #include "radio_setup.h" -#include "opentx.h" -#include "libopenui.h" -#include "input_mapping.h" -#include "tasks/mixer_task.h" #include "hal/adc_driver.h" #include "hal/usb_driver.h" +#include "input_mapping.h" +#include "libopenui.h" +#include "opentx.h" +#include "page.h" +#include "tasks/mixer_task.h" -#define SET_DIRTY() storageDirty(EE_GENERAL) +#define SET_DIRTY() storageDirty(EE_GENERAL) static const lv_coord_t col_two_dsc[] = {LV_GRID_FR(19), LV_GRID_FR(21), - LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t col_four_dsc[] = {LV_GRID_FR(19), LV_GRID_FR(7), LV_GRID_FR(7), LV_GRID_FR(7), - LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; - -class DateTimeWindow : public FormWindow { - public: - DateTimeWindow(Window* parent, const rect_t & rect) : - FormWindow(parent, rect) - { - build(); - } + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; + +// Absolute layout for date/time setion due to slow performance +// of lv_textarea in a flex layout. +#if LCD_W > LCD_H +#define DT_EDT_W 80 +#define DT_EDT_X 220 +#define DT_LBL_W 200 +#else +#define DT_EDT_W 52 +#define DT_EDT_X 144 +#define DT_LBL_W 140 +#endif - void checkEvents() override - { - FormWindow::checkEvents(); +class DateTimeWindow : public Window +{ + public: + DateTimeWindow(Window* parent, const rect_t& rect) : + Window(parent, {0, 0, LCD_W - 12, 74}) + { + build(); + } - if (seconds && (get_tmr10ms() - lastRefresh >= 10)) { - lastRefresh = get_tmr10ms(); + void checkEvents() override + { + Window::checkEvents(); - gettime(&m_tm); - if (m_tm.tm_year != m_last_tm.tm_year) { - m_last_tm.tm_year = m_tm.tm_year; - year->update(); - } - if (m_tm.tm_mon != m_last_tm.tm_mon) { - m_last_tm.tm_mon = m_tm.tm_mon; - month->update(); - } - if (m_tm.tm_mday != m_last_tm.tm_mday) { - m_last_tm.tm_mday = m_tm.tm_mday; - day->update(); - } - if (m_tm.tm_hour != m_last_tm.tm_hour) { - m_last_tm.tm_hour = m_tm.tm_hour; - hour->update(); - } - if (m_tm.tm_min != m_last_tm.tm_min) { - m_last_tm.tm_min = m_tm.tm_min; - minutes->update(); - } - if (m_tm.tm_sec != m_last_tm.tm_sec) { - m_last_tm.tm_sec = m_tm.tm_sec; - seconds->update(); - } + if (seconds && (get_tmr10ms() - lastRefresh >= 10)) { + lastRefresh = get_tmr10ms(); + + gettime(&m_tm); + if (m_tm.tm_year != m_last_tm.tm_year) { + m_last_tm.tm_year = m_tm.tm_year; + year->update(); + } + if (m_tm.tm_mon != m_last_tm.tm_mon) { + m_last_tm.tm_mon = m_tm.tm_mon; + month->update(); + } + if (m_tm.tm_mday != m_last_tm.tm_mday) { + m_last_tm.tm_mday = m_tm.tm_mday; + day->update(); + } + if (m_tm.tm_hour != m_last_tm.tm_hour) { + m_last_tm.tm_hour = m_tm.tm_hour; + hour->update(); + } + if (m_tm.tm_min != m_last_tm.tm_min) { + m_last_tm.tm_min = m_tm.tm_min; + minutes->update(); + } + if (m_tm.tm_sec != m_last_tm.tm_sec) { + m_last_tm.tm_sec = m_tm.tm_sec; + seconds->update(); } } + } - protected: - struct gtm m_tm; - struct gtm m_last_tm; - tmr10ms_t lastRefresh = 0; - NumberEdit* year = nullptr; - NumberEdit* month = nullptr; - NumberEdit* day = nullptr; - NumberEdit* hour = nullptr; - NumberEdit* minutes = nullptr; - NumberEdit* seconds = nullptr; - - int8_t daysInMonth() - { - static const int8_t dmon[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - int16_t year = TM_YEAR_BASE + m_tm.tm_year; - int8_t days_in_month = dmon[m_tm.tm_mon]; - if ((m_tm.tm_mon == 1) && (((year % 4 == 0) && (year % 100 != 0)) || (year%400==0))) - days_in_month += 1; - return days_in_month; - } + protected: + struct gtm m_tm; + struct gtm m_last_tm; + tmr10ms_t lastRefresh = 0; + NumberEdit* year = nullptr; + NumberEdit* month = nullptr; + NumberEdit* day = nullptr; + NumberEdit* hour = nullptr; + NumberEdit* minutes = nullptr; + NumberEdit* seconds = nullptr; + + int8_t daysInMonth() + { + static const int8_t dmon[] = {31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + int16_t year = TM_YEAR_BASE + m_tm.tm_year; + int8_t days_in_month = dmon[m_tm.tm_mon]; + if ((m_tm.tm_mon == 1) && + (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))) + days_in_month += 1; + return days_in_month; + } - void setDaysInMonth() - { - if (day) { - day->setMax(daysInMonth()); - if (m_tm.tm_mday > day->getMax()) { - // Update stored day value if > actual days in month - // Will be written to RTC via SET_LOAD_DATETIME call after returning - // UI will update on next iteration of checkEvents - m_tm.tm_mday = day->getMax(); - } - } + void setDaysInMonth() + { + if (day) { + day->setMax(daysInMonth()); + if (m_tm.tm_mday > day->getMax()) { + // Update stored day value if > actual days in month + // Will be written to RTC via SET_LOAD_DATETIME call after returning + // UI will update on next iteration of checkEvents + m_tm.tm_mday = day->getMax(); + } } + } - void build() - { - setFlexLayout(); - FlexGridLayout grid(col_four_dsc, row_dsc, 2); - - gettime(&m_tm); - m_last_tm = m_tm; - - // Date - auto line = newLine(&grid); - new StaticText(line, rect_t{}, STR_DATE, 0, COLOR_THEME_PRIMARY1); - year = new NumberEdit(line, rect_t{}, 2023, 2037, - [=]() -> int32_t { - return TM_YEAR_BASE + m_tm.tm_year; - }, - [=](int32_t newValue) { - m_last_tm.tm_year = m_tm.tm_year = newValue - TM_YEAR_BASE; - setDaysInMonth(); - SET_LOAD_DATETIME(&m_tm); - }); - lv_obj_set_style_grid_cell_x_align(year->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - month = new NumberEdit(line, rect_t{}, 1, 12, - [=]() -> int32_t { - return 1 + m_tm.tm_mon; - }, - [=](int32_t newValue) { - m_last_tm.tm_mon = m_tm.tm_mon = newValue - 1; - setDaysInMonth(); - SET_LOAD_DATETIME(&m_tm); - }); - month->setDisplayHandler([](int32_t value) { - return formatNumberAsString(value, LEADING0); - }); - lv_obj_set_style_grid_cell_x_align(month->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - day = new NumberEdit(line, rect_t{}, 1, daysInMonth(), - [=]() -> int32_t { - return m_tm.tm_mday; - }, - [=](int32_t newValue) { - m_last_tm.tm_mday = m_tm.tm_mday = newValue; - SET_LOAD_DATETIME(&m_tm); - }); - day->setDisplayHandler([](int32_t value) { - return formatNumberAsString(value, LEADING0, 2); - }); - lv_obj_set_style_grid_cell_x_align(day->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - // Time - line = newLine(&grid); - new StaticText(line, rect_t{}, STR_TIME, 0, COLOR_THEME_PRIMARY1); - hour = new NumberEdit(line, rect_t{}, 0, 23, - [=]() -> int32_t { - return m_tm.tm_hour; - }, - [=](int32_t newValue) { - m_last_tm.tm_hour = m_tm.tm_hour = newValue; - SET_LOAD_DATETIME(&m_tm); - }); - hour->setDisplayHandler([](int32_t value) { - return formatNumberAsString(value, LEADING0, 2); - }); - lv_obj_set_style_grid_cell_x_align(hour->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - minutes = new NumberEdit(line, rect_t{}, 0, 59, - [=]() -> int32_t { - return m_tm.tm_min; - }, - [=](int32_t newValue) { - m_last_tm.tm_min = m_tm.tm_min = newValue; - SET_LOAD_DATETIME(&m_tm); - }); - minutes->setDisplayHandler([](int32_t value) { - return formatNumberAsString(value, LEADING0, 2); - }); - lv_obj_set_style_grid_cell_x_align(minutes->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - seconds = new NumberEdit(line, rect_t{}, 0, 59, - [=]() -> int32_t { - return m_tm.tm_sec; - }, - [=](int32_t newValue) { - m_last_tm.tm_sec = m_tm.tm_sec = newValue; - SET_LOAD_DATETIME(&m_tm); - }); - seconds->setDisplayHandler([](int value) { - return formatNumberAsString(value, LEADING0, 2); - }); - lv_obj_set_style_grid_cell_x_align(seconds->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - // Spacer - line = newLine(&grid); - } + void build() + { + gettime(&m_tm); + m_last_tm = m_tm; + + // Date + new StaticText(this, rect_t{2, 8, DT_LBL_W, 21}, STR_DATE, + COLOR_THEME_PRIMARY1); + year = new NumberEdit( + this, rect_t{DT_EDT_X, 2, DT_EDT_W, 32}, 2023, 2037, + [=]() -> int32_t { return TM_YEAR_BASE + m_tm.tm_year; }, + [=](int32_t newValue) { + m_last_tm.tm_year = m_tm.tm_year = newValue - TM_YEAR_BASE; + setDaysInMonth(); + SET_LOAD_DATETIME(&m_tm); + }); + + month = new NumberEdit( + this, rect_t{DT_EDT_X + DT_EDT_W + 2, 2, DT_EDT_W, 32}, 1, 12, + [=]() -> int32_t { return 1 + m_tm.tm_mon; }, + [=](int32_t newValue) { + m_last_tm.tm_mon = m_tm.tm_mon = newValue - 1; + setDaysInMonth(); + SET_LOAD_DATETIME(&m_tm); + }); + month->setDisplayHandler( + [](int32_t value) { return formatNumberAsString(value, LEADING0); }); + + day = new NumberEdit( + this, rect_t{DT_EDT_X + 2 * DT_EDT_W + 4, 2, DT_EDT_W, 32}, 1, + daysInMonth(), [=]() -> int32_t { return m_tm.tm_mday; }, + [=](int32_t newValue) { + m_last_tm.tm_mday = m_tm.tm_mday = newValue; + SET_LOAD_DATETIME(&m_tm); + }); + day->setDisplayHandler( + [](int32_t value) { return formatNumberAsString(value, LEADING0, 2); }); + + // Time + new StaticText(this, rect_t{2, 46, DT_LBL_W, 21}, STR_TIME, + COLOR_THEME_PRIMARY1); + hour = new NumberEdit( + this, rect_t{DT_EDT_X, 40, DT_EDT_W, 32}, 0, 23, + [=]() -> int32_t { return m_tm.tm_hour; }, + [=](int32_t newValue) { + m_last_tm.tm_hour = m_tm.tm_hour = newValue; + SET_LOAD_DATETIME(&m_tm); + }); + hour->setDisplayHandler( + [](int32_t value) { return formatNumberAsString(value, LEADING0, 2); }); + + minutes = new NumberEdit( + this, rect_t{DT_EDT_X + DT_EDT_W + 2, 40, DT_EDT_W, 32}, 0, 59, + [=]() -> int32_t { return m_tm.tm_min; }, + [=](int32_t newValue) { + m_last_tm.tm_min = m_tm.tm_min = newValue; + SET_LOAD_DATETIME(&m_tm); + }); + minutes->setDisplayHandler( + [](int32_t value) { return formatNumberAsString(value, LEADING0, 2); }); + + seconds = new NumberEdit( + this, rect_t{DT_EDT_X + DT_EDT_W * 2 + 4, 40, DT_EDT_W, 32}, 0, 59, + [=]() -> int32_t { return m_tm.tm_sec; }, + [=](int32_t newValue) { + m_last_tm.tm_sec = m_tm.tm_sec = newValue; + SET_LOAD_DATETIME(&m_tm); + }); + seconds->setDisplayHandler( + [](int value) { return formatNumberAsString(value, LEADING0, 2); }); + } }; -class WindowButtonGroup : public FormWindow +class WindowButtonGroup : public Window { public: - typedef std::function PageFct; + typedef std::function PageFct; typedef std::pair PageDef; - typedef std::list PageDefs; + typedef std::list PageDefs; - WindowButtonGroup( - Window* parent, const rect_t& rect, PageDefs pages) : - FormWindow(parent, rect), - pages(pages) + WindowButtonGroup(Window* parent, const rect_t& rect, PageDefs pages) : + Window(parent, rect), pages(pages) { - padBottom(4); - setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8)); + padTop(PAD_TINY); + padBottom(PAD_SMALL); + setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_LARGE); lv_obj_set_style_flex_main_place(lvobj, LV_FLEX_ALIGN_SPACE_EVENLY, 0); - padRow(lv_dpx(8)); - padBottom(4); + padRow(PAD_MEDIUM); + padBottom(PAD_SMALL); for (auto& entry : pages) { auto btn = new TextButton(this, rect_t{}, entry.first, [&, entry]() { @@ -245,446 +234,492 @@ class WindowButtonGroup : public FormWindow class SubPage : public Page { - public: - SubPage(MenuIcons icon, const char* title, bool isFlex = true) : Page(icon) - { - header.setTitle(STR_RADIO_SETUP); - header.setTitle2(title); - - if (isFlex) - body.setFlexLayout(); + public: + SubPage(EdgeTxIcon icon, const char* title) : Page(icon) + { + header.setTitle(STR_RADIO_SETUP); + header.setTitle2(title); - body.padAll(8); - } + body.setFlexLayout(); + } }; -class SoundPage : public SubPage { - public: - SoundPage() : SubPage(ICON_RADIO_SETUP, STR_SOUND_LABEL, false) - { - FlexGridLayout grid(col_two_dsc, row_dsc, 2); - - auto form = new FormWindow(&body, rect_t{}); - form->setFlexLayout(); - form->padAll(0); - - auto line = form->newLine(&grid); - - // Beeps mode - new StaticText(line, rect_t{}, STR_SPEAKER, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_VBEEPMODE, -2, 1, GET_SET_DEFAULT(g_eeGeneral.beepMode)); - line = form->newLine(&grid); - - // Main volume - new StaticText(line, rect_t{}, STR_VOLUME, 0, COLOR_THEME_PRIMARY1); - new Slider(line, lv_pct(50), -VOLUME_LEVEL_DEF, VOLUME_LEVEL_MAX-VOLUME_LEVEL_DEF, GET_SET_DEFAULT(g_eeGeneral.speakerVolume)); - line = form->newLine(&grid); - - // Beeps volume - new StaticText(line, rect_t{}, STR_BEEP_VOLUME, 0, COLOR_THEME_PRIMARY1); - new Slider(line, lv_pct(50), -2, +2, GET_SET_DEFAULT(g_eeGeneral.beepVolume)); - line = form->newLine(&grid); - - // Beeps length - new StaticText(line, rect_t{}, STR_BEEP_LENGTH, 0, COLOR_THEME_PRIMARY1); - new Slider(line, lv_pct(50), -2, +2, GET_SET_DEFAULT(g_eeGeneral.beepLength)); - line = form->newLine(&grid); - - // Beeps pitch - new StaticText(line, rect_t{}, STR_BEEP_PITCH, 0, COLOR_THEME_PRIMARY1); - auto edit = new NumberEdit(line, rect_t{}, 0, 300, - GET_DEFAULT(15 * g_eeGeneral.speakerPitch), - [=](int32_t newValue) { - g_eeGeneral.speakerPitch = newValue / 15; - SET_DIRTY(); - }); - edit->setStep(15); - edit->setPrefix("+"); - edit->setSuffix("Hz"); - line = form->newLine(&grid); - - // Wav volume - new StaticText(line, rect_t{}, STR_WAV_VOLUME, 0, COLOR_THEME_PRIMARY1); - new Slider(line, lv_pct(50), -2, +2, GET_SET_DEFAULT(g_eeGeneral.wavVolume)); - line = form->newLine(&grid); - - // Background volume - new StaticText(line, rect_t{}, STR_BG_VOLUME, 0, COLOR_THEME_PRIMARY1); - new Slider(line, lv_pct(50), -2, +2, GET_SET_DEFAULT(g_eeGeneral.backgroundVolume)); - - } +class SoundPage : public SubPage +{ + public: + SoundPage() : SubPage(ICON_RADIO_SETUP, STR_SOUND_LABEL) + { + FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY); + + auto line = body.newLine(grid); + + // Beeps mode + new StaticText(line, rect_t{}, STR_SPEAKER, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_VBEEPMODE, -2, 1, + GET_SET_DEFAULT(g_eeGeneral.beepMode)); + line = body.newLine(grid); + + // Main volume + new StaticText(line, rect_t{}, STR_VOLUME, COLOR_THEME_PRIMARY1); + new Slider(line, lv_pct(50), -VOLUME_LEVEL_DEF, + VOLUME_LEVEL_MAX - VOLUME_LEVEL_DEF, + GET_SET_DEFAULT(g_eeGeneral.speakerVolume)); + line = body.newLine(grid); + + // Beeps volume + new StaticText(line, rect_t{}, STR_BEEP_VOLUME, COLOR_THEME_PRIMARY1); + new Slider(line, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.beepVolume)); + line = body.newLine(grid); + + // Beeps length + new StaticText(line, rect_t{}, STR_BEEP_LENGTH, COLOR_THEME_PRIMARY1); + new Slider(line, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.beepLength)); + line = body.newLine(grid); + + // Beeps pitch + new StaticText(line, rect_t{}, STR_BEEP_PITCH, COLOR_THEME_PRIMARY1); + auto edit = new NumberEdit(line, rect_t{}, 0, 300, + GET_DEFAULT(15 * g_eeGeneral.speakerPitch), + [=](int32_t newValue) { + g_eeGeneral.speakerPitch = newValue / 15; + SET_DIRTY(); + }); + edit->setStep(15); + edit->setPrefix("+"); + edit->setSuffix("Hz"); + line = body.newLine(grid); + + // Wav volume + new StaticText(line, rect_t{}, STR_WAV_VOLUME, COLOR_THEME_PRIMARY1); + new Slider(line, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.wavVolume)); + line = body.newLine(grid); + + // Background volume + new StaticText(line, rect_t{}, STR_BG_VOLUME, COLOR_THEME_PRIMARY1); + new Slider(line, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.backgroundVolume)); + } }; #if defined(VARIO) -class VarioPage : public SubPage { - public: - VarioPage() : SubPage(ICON_RADIO_SETUP, STR_VARIO) - { - FlexGridLayout grid(col_two_dsc, row_dsc, 4); - - auto line = body.newLine(&grid); - - // Vario volume - new StaticText(line, rect_t{}, STR_VOLUME, 0, COLOR_THEME_PRIMARY1); - new Slider(line, lv_pct(50), -2, +2, GET_SET_DEFAULT(g_eeGeneral.varioVolume)); - line = body.newLine(&grid); - - new StaticText(line, rect_t{}, STR_PITCH_AT_ZERO, 0, COLOR_THEME_PRIMARY1); - auto edit = new NumberEdit(line, rect_t{}, VARIO_FREQUENCY_ZERO - 400, VARIO_FREQUENCY_ZERO + 400, - GET_DEFAULT(VARIO_FREQUENCY_ZERO + (g_eeGeneral.varioPitch * 10)), - SET_VALUE(g_eeGeneral.varioPitch, (newValue - VARIO_FREQUENCY_ZERO) / 10)); - edit->setStep(10); - edit->setSuffix("Hz"); - line = body.newLine(&grid); - - new StaticText(line, rect_t{}, STR_PITCH_AT_MAX, 0, COLOR_THEME_PRIMARY1); - edit = new NumberEdit(line, rect_t{}, 900, 2500, - GET_DEFAULT(VARIO_FREQUENCY_ZERO + (g_eeGeneral.varioPitch * 10) + VARIO_FREQUENCY_RANGE + (g_eeGeneral.varioRange * 10)), - SET_VALUE(g_eeGeneral.varioRange, (newValue - VARIO_FREQUENCY_ZERO - VARIO_FREQUENCY_RANGE) / 10 - g_eeGeneral.varioPitch )); - edit->setStep(10); - edit->setSuffix("Hz"); - line = body.newLine(&grid); - - new StaticText(line, rect_t{}, STR_REPEAT_AT_ZERO, 0, COLOR_THEME_PRIMARY1); - edit = new NumberEdit(line, rect_t{}, 200, 1000, - GET_DEFAULT(VARIO_REPEAT_ZERO + (g_eeGeneral.varioRepeat * 10)), - SET_VALUE(g_eeGeneral.varioRepeat, (newValue - VARIO_REPEAT_ZERO) / 10)); - edit->setStep(10); - edit->setSuffix("ms"); - line = body.newLine(&grid); - } +class VarioPage : public SubPage +{ + public: + VarioPage() : SubPage(ICON_RADIO_SETUP, STR_VARIO) + { + FlexGridLayout grid(col_two_dsc, row_dsc); + + auto line = body.newLine(grid); + + // Vario volume + new StaticText(line, rect_t{}, STR_VOLUME, COLOR_THEME_PRIMARY1); + new Slider(line, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.varioVolume)); + line = body.newLine(grid); + + new StaticText(line, rect_t{}, STR_PITCH_AT_ZERO, COLOR_THEME_PRIMARY1); + auto edit = new NumberEdit( + line, rect_t{}, VARIO_FREQUENCY_ZERO - 400, VARIO_FREQUENCY_ZERO + 400, + GET_DEFAULT(VARIO_FREQUENCY_ZERO + (g_eeGeneral.varioPitch * 10)), + SET_VALUE(g_eeGeneral.varioPitch, + (newValue - VARIO_FREQUENCY_ZERO) / 10)); + edit->setStep(10); + edit->setSuffix("Hz"); + line = body.newLine(grid); + + new StaticText(line, rect_t{}, STR_PITCH_AT_MAX, COLOR_THEME_PRIMARY1); + edit = new NumberEdit( + line, rect_t{}, 900, 2500, + GET_DEFAULT(VARIO_FREQUENCY_ZERO + (g_eeGeneral.varioPitch * 10) + + VARIO_FREQUENCY_RANGE + (g_eeGeneral.varioRange * 10)), + SET_VALUE( + g_eeGeneral.varioRange, + (newValue - VARIO_FREQUENCY_ZERO - VARIO_FREQUENCY_RANGE) / 10 - + g_eeGeneral.varioPitch)); + edit->setStep(10); + edit->setSuffix("Hz"); + line = body.newLine(grid); + + new StaticText(line, rect_t{}, STR_REPEAT_AT_ZERO, COLOR_THEME_PRIMARY1); + edit = new NumberEdit( + line, rect_t{}, 200, 1000, + GET_DEFAULT(VARIO_REPEAT_ZERO + (g_eeGeneral.varioRepeat * 10)), + SET_VALUE(g_eeGeneral.varioRepeat, + (newValue - VARIO_REPEAT_ZERO) / 10)); + edit->setStep(10); + edit->setSuffix("ms"); + line = body.newLine(grid); + } }; #endif #if defined(HAPTIC) -class HapticPage : public SubPage { - public: - HapticPage() : SubPage(ICON_RADIO_SETUP, STR_HAPTIC_LABEL) - { - FlexGridLayout grid(col_two_dsc, row_dsc, 4); - - auto line = body.newLine(&grid); - - // Haptic mode - new StaticText(line, rect_t{}, STR_MODE, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_VBEEPMODE, -2, 1, GET_SET_DEFAULT(g_eeGeneral.hapticMode)); - line = body.newLine(&grid); - - // Haptic duration - new StaticText(line, rect_t{}, STR_LENGTH, 0, COLOR_THEME_PRIMARY1); - new Slider(line, lv_pct(50), -2, +2, GET_SET_DEFAULT(g_eeGeneral.hapticLength)); - line = body.newLine(&grid); - - // Haptic strength - new StaticText(line, rect_t{}, STR_STRENGTH, 0, COLOR_THEME_PRIMARY1); - new Slider(line, lv_pct(50), -2, +2, GET_SET_DEFAULT(g_eeGeneral.hapticStrength)); - line = body.newLine(&grid); - } +class HapticPage : public SubPage +{ + public: + HapticPage() : SubPage(ICON_RADIO_SETUP, STR_HAPTIC_LABEL) + { + FlexGridLayout grid(col_two_dsc, row_dsc); + + auto line = body.newLine(grid); + + // Haptic mode + new StaticText(line, rect_t{}, STR_MODE, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_VBEEPMODE, -2, 1, + GET_SET_DEFAULT(g_eeGeneral.hapticMode)); + line = body.newLine(grid); + + // Haptic duration + new StaticText(line, rect_t{}, STR_LENGTH, COLOR_THEME_PRIMARY1); + new Slider(line, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.hapticLength)); + line = body.newLine(grid); + + // Haptic strength + new StaticText(line, rect_t{}, STR_STRENGTH, COLOR_THEME_PRIMARY1); + new Slider(line, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.hapticStrength)); + line = body.newLine(grid); + } }; #endif -class AlarmsPage : public SubPage { - public: - AlarmsPage() : SubPage(ICON_RADIO_SETUP, STR_ALARMS_LABEL) - { - FlexGridLayout grid(col_two_dsc, row_dsc, 4); - - auto line = body.newLine(&grid); - // Battery warning - new StaticText(line, rect_t{}, STR_BATTERYWARNING, 0, COLOR_THEME_PRIMARY1); - auto edit = new NumberEdit(line, rect_t{}, 30, 120, GET_SET_DEFAULT(g_eeGeneral.vBatWarn), 0, PREC1); - edit->setSuffix("V"); - line = body.newLine(&grid); - - // Inactivity alarm - new StaticText(line, rect_t{}, STR_INACTIVITYALARM, 0, COLOR_THEME_PRIMARY1); - edit = new NumberEdit(line, rect_t{}, 0, 250, GET_SET_DEFAULT(g_eeGeneral.inactivityTimer)); - - edit->setDisplayHandler([=](int value) -> std::string { - std::string suffix(STR_MINUTE_PLURAL2); - if (value == 1) { - suffix = std::string(STR_MINUTE_SINGULAR); - } else if (value < g_use_plural2) { - const int secondDecimal = (value / 10) % 10; - if (secondDecimal != 1) { - const int firstDecimal = value % 10; - if (firstDecimal) { - if (firstDecimal < g_min_plural2 && - firstDecimal == g_use_singular_in_plural) { - suffix = std::string(STR_MINUTE_SINGULAR); - } else if (firstDecimal <= g_max_plural2 && - firstDecimal != g_use_plural2_special_case) { - suffix = std::string(STR_MINUTE_PLURAL1); - } +class AlarmsPage : public SubPage +{ + public: + AlarmsPage() : SubPage(ICON_RADIO_SETUP, STR_ALARMS_LABEL) + { + FlexGridLayout grid(col_two_dsc, row_dsc); + + auto line = body.newLine(grid); + // Battery warning + new StaticText(line, rect_t{}, STR_BATTERYWARNING, COLOR_THEME_PRIMARY1); + auto edit = new NumberEdit(line, rect_t{}, 30, 120, + GET_SET_DEFAULT(g_eeGeneral.vBatWarn), PREC1); + edit->setSuffix("V"); + line = body.newLine(grid); + + // Inactivity alarm + new StaticText(line, rect_t{}, STR_INACTIVITYALARM, COLOR_THEME_PRIMARY1); + edit = new NumberEdit(line, rect_t{}, 0, 250, + GET_SET_DEFAULT(g_eeGeneral.inactivityTimer)); + + edit->setDisplayHandler([=](int value) -> std::string { + std::string suffix(STR_MINUTE_PLURAL2); + if (value == 1) { + suffix = std::string(STR_MINUTE_SINGULAR); + } else if (value < g_use_plural2) { + const int secondDecimal = (value / 10) % 10; + if (secondDecimal != 1) { + const int firstDecimal = value % 10; + if (firstDecimal) { + if (firstDecimal < g_min_plural2 && + firstDecimal == g_use_singular_in_plural) { + suffix = std::string(STR_MINUTE_SINGULAR); + } else if (firstDecimal <= g_max_plural2 && + firstDecimal != g_use_plural2_special_case) { + suffix = std::string(STR_MINUTE_PLURAL1); } } } - suffix = " " + suffix; - return formatNumberAsString(value, 0, 0, nullptr, suffix.c_str()); - }); - line = body.newLine(&grid); - - // Alarms warning - new StaticText(line, rect_t{}, STR_ALARMWARNING, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, - GET_SET_INVERTED(g_eeGeneral.disableAlarmWarning)); - line = body.newLine(&grid); - - // RSSI shutdown alarm - new StaticText(line, rect_t{}, STR_RSSI_SHUTDOWN_ALARM, 0, - COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, - GET_SET_INVERTED(g_eeGeneral.disableRssiPoweroffAlarm)); - line = body.newLine(&grid); - } + } + suffix = " " + suffix; + return formatNumberAsString(value, 0, 0, nullptr, suffix.c_str()); + }); + line = body.newLine(grid); + + // Alarms warning + new StaticText(line, rect_t{}, STR_ALARMWARNING, COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, + GET_SET_INVERTED(g_eeGeneral.disableAlarmWarning)); + line = body.newLine(grid); + + // RSSI shutdown alarm + new StaticText(line, rect_t{}, STR_RSSI_SHUTDOWN_ALARM, + COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, + GET_SET_INVERTED(g_eeGeneral.disableRssiPoweroffAlarm)); + line = body.newLine(grid); + } }; -class BacklightPage : public SubPage { - public: - BacklightPage() : SubPage(ICON_RADIO_SETUP, STR_BACKLIGHT_LABEL) - { - FlexGridLayout grid(col_two_dsc, row_dsc, 4); - - auto line = body.newLine(&grid); - - // Backlight mode - new StaticText(line, rect_t{}, STR_MODE, 0, COLOR_THEME_PRIMARY1); - - auto blMode = new Choice(line, rect_t{}, STR_VBLMODE, - e_backlight_mode_off, e_backlight_mode_on, - GET_DEFAULT(g_eeGeneral.backlightMode), - [=](int32_t newValue) { - g_eeGeneral.backlightMode = newValue; - updateBacklightControls(); - SET_DIRTY(); - }); - - blMode->setAvailableHandler( - [=](int newValue) { return newValue != e_backlight_mode_off; }); - - backlightTimeout = body.newLine(&grid); - - // Delay - new StaticText(backlightTimeout, rect_t{}, STR_BACKLIGHT_TIMER, 0, COLOR_THEME_PRIMARY1); - auto edit = new NumberEdit(backlightTimeout, rect_t{}, 5, 600, - GET_DEFAULT(g_eeGeneral.lightAutoOff * 5), - SET_VALUE(g_eeGeneral.lightAutoOff, newValue / 5)); - edit->setStep(5); - edit->setSuffix("s"); - - backlightOnBright = body.newLine(&grid); - - // Backlight ON bright - new StaticText(backlightOnBright, rect_t{}, STR_BLONBRIGHTNESS, 0, COLOR_THEME_PRIMARY1); - backlightOnSlider = new Slider(backlightOnBright, lv_pct(50), BACKLIGHT_LEVEL_MIN, BACKLIGHT_LEVEL_MAX, - [=]() -> int32_t { - return BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright; - }, - [=](int32_t newValue) { - if(newValue >= g_eeGeneral.blOffBright || g_eeGeneral.backlightMode == e_backlight_mode_on) { - g_eeGeneral.backlightBright = BACKLIGHT_LEVEL_MAX - newValue; - } else { - g_eeGeneral.backlightBright = BACKLIGHT_LEVEL_MAX - g_eeGeneral.blOffBright; - backlightOnSlider->update(); - } - SET_DIRTY(); - }); +class BacklightPage : public SubPage +{ + public: + BacklightPage() : SubPage(ICON_RADIO_SETUP, STR_BACKLIGHT_LABEL) + { + FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY); + + auto line = body.newLine(grid); + + // Backlight mode + new StaticText(line, rect_t{}, STR_MODE, COLOR_THEME_PRIMARY1); + + auto blMode = new Choice( + line, rect_t{}, STR_VBLMODE, e_backlight_mode_off, e_backlight_mode_on, + GET_DEFAULT(g_eeGeneral.backlightMode), [=](int32_t newValue) { + g_eeGeneral.backlightMode = newValue; + updateBacklightControls(); + SET_DIRTY(); + }); + + blMode->setAvailableHandler( + [=](int newValue) { return newValue != e_backlight_mode_off; }); + + backlightTimeout = body.newLine(grid); + + // Delay + new StaticText(backlightTimeout, rect_t{}, STR_BACKLIGHT_TIMER, + COLOR_THEME_PRIMARY1); + auto edit = + new NumberEdit(backlightTimeout, rect_t{}, 5, 600, + GET_DEFAULT(g_eeGeneral.lightAutoOff * 5), + SET_VALUE(g_eeGeneral.lightAutoOff, newValue / 5)); + edit->setStep(5); + edit->setSuffix("s"); + + backlightOnBright = body.newLine(grid); + + // Backlight ON bright + new StaticText(backlightOnBright, rect_t{}, STR_BLONBRIGHTNESS, + COLOR_THEME_PRIMARY1); + backlightOnSlider = new Slider( + backlightOnBright, lv_pct(50), BACKLIGHT_LEVEL_MIN, BACKLIGHT_LEVEL_MAX, + [=]() -> int32_t { + return BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright; + }, + [=](int32_t newValue) { + if (newValue >= g_eeGeneral.blOffBright || + g_eeGeneral.backlightMode == e_backlight_mode_on) { + g_eeGeneral.backlightBright = BACKLIGHT_LEVEL_MAX - newValue; + } else { + g_eeGeneral.backlightBright = + BACKLIGHT_LEVEL_MAX - g_eeGeneral.blOffBright; + backlightOnSlider->update(); + } + SET_DIRTY(); + }); + + backlightOffBright = body.newLine(grid); + + // Backlight OFF bright + new StaticText(backlightOffBright, rect_t{}, STR_BLOFFBRIGHTNESS, + COLOR_THEME_PRIMARY1); + backlightOffSlider = new Slider( + backlightOffBright, lv_pct(50), BACKLIGHT_LEVEL_MIN, + BACKLIGHT_LEVEL_MAX, GET_DEFAULT(g_eeGeneral.blOffBright), + [=](int32_t newValue) { + int32_t onBright = BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright; + if (newValue <= onBright || + g_eeGeneral.backlightMode == e_backlight_mode_off) { + g_eeGeneral.blOffBright = newValue; + } else { + g_eeGeneral.blOffBright = onBright; + backlightOffSlider->update(); + } + SET_DIRTY(); + }); - backlightOffBright = body.newLine(&grid); - - // Backlight OFF bright - new StaticText(backlightOffBright, rect_t{}, STR_BLOFFBRIGHTNESS, 0, COLOR_THEME_PRIMARY1); - backlightOffSlider = new Slider(backlightOffBright, lv_pct(50), BACKLIGHT_LEVEL_MIN, BACKLIGHT_LEVEL_MAX, GET_DEFAULT(g_eeGeneral.blOffBright), - [=](int32_t newValue) { - int32_t onBright = BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright; - if(newValue <= onBright || g_eeGeneral.backlightMode == e_backlight_mode_off) { - g_eeGeneral.blOffBright = newValue; - } else { - g_eeGeneral.blOffBright = onBright; - backlightOffSlider->update(); - } - SET_DIRTY(); - }); + line = body.newLine(grid); - line = body.newLine(&grid); +#if defined(KEYS_BACKLIGHT_GPIO) + // Keys backlight + new StaticText(line, rect_t{}, STR_KEYS_BACKLIGHT, COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, + GET_SET_DEFAULT(g_eeGeneral.keysBacklight)); + line = body.newLine(grid); +#endif - #if defined(KEYS_BACKLIGHT_GPIO) - // Keys backlight - new StaticText(line, rect_t{}, STR_KEYS_BACKLIGHT, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.keysBacklight)); - line = body.newLine(&grid); - #endif + // Flash beep + new StaticText(line, rect_t{}, STR_ALARM, COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.alarmsFlash)); + line = body.newLine(grid); - // Flash beep - new StaticText(line, rect_t{}, STR_ALARM, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.alarmsFlash)); - line = body.newLine(&grid); + updateBacklightControls(); + } - updateBacklightControls(); - } + protected: + Window* backlightTimeout = nullptr; + Window* backlightOnBright = nullptr; + Window* backlightOffBright = nullptr; + Slider* backlightOffSlider = nullptr; + Slider* backlightOnSlider = nullptr; - protected: - Window* backlightTimeout = nullptr; - Window* backlightOnBright = nullptr; - Window* backlightOffBright = nullptr; - Slider* backlightOffSlider = nullptr; - Slider* backlightOnSlider = nullptr; - - void updateBacklightControls() - { - switch(g_eeGeneral.backlightMode) - { + void updateBacklightControls() + { + switch (g_eeGeneral.backlightMode) { case e_backlight_mode_off: - lv_obj_add_flag(backlightTimeout->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(backlightOnBright->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(backlightOffBright->getLvObj(), LV_OBJ_FLAG_HIDDEN); + backlightTimeout->hide(); + backlightOnBright->hide(); + backlightOffBright->show(); break; case e_backlight_mode_keys: case e_backlight_mode_sticks: case e_backlight_mode_all: - default: - { - lv_obj_clear_flag(backlightTimeout->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(backlightOnBright->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(backlightOffBright->getLvObj(), LV_OBJ_FLAG_HIDDEN); + default: { + backlightTimeout->show(); + backlightOnBright->show(); + backlightOffBright->show(); int32_t onBright = BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright; - if(onBright < g_eeGeneral.blOffBright) - g_eeGeneral.backlightBright = BACKLIGHT_LEVEL_MAX - g_eeGeneral.blOffBright; + if (onBright < g_eeGeneral.blOffBright) + g_eeGeneral.backlightBright = + BACKLIGHT_LEVEL_MAX - g_eeGeneral.blOffBright; break; } case e_backlight_mode_on: - lv_obj_add_flag(backlightTimeout->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(backlightOnBright->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(backlightOffBright->getLvObj(), LV_OBJ_FLAG_HIDDEN); + backlightTimeout->hide(); + backlightOnBright->show(); + backlightOffBright->hide(); break; - } - resetBacklightTimeout(); } + resetBacklightTimeout(); + } }; -class GpsPage : public SubPage { - public: - GpsPage() : SubPage(ICON_RADIO_SETUP, STR_GPS) - { - FlexGridLayout grid(col_two_dsc, row_dsc, 4); - - tzIndex = timezoneIndex(g_eeGeneral.timezone, g_eeGeneral.timezoneMinutes); - - auto line = body.newLine(&grid); - // Timezone - new StaticText(line, rect_t{}, STR_TIMEZONE, 0, COLOR_THEME_PRIMARY1); - auto tz = new NumberEdit(line, rect_t{}, minTimezone(), maxTimezone(), - GET_DEFAULT(tzIndex), - [=](int newTz) { - tzIndex = newTz; - g_eeGeneral.timezone = timezoneHour(newTz); - g_eeGeneral.timezoneMinutes = timezoneMinute(newTz); - SET_DIRTY(); - }); - tz->setDisplayHandler([](int32_t tz) { - return timezoneDisplay(tz); - }); - line = body.newLine(&grid); - - // Adjust RTC (from telemetry) - new StaticText(line, rect_t{}, STR_ADJUST_RTC, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.adjustRTC)); - line = body.newLine(&grid); - - // GPS format - new StaticText(line, rect_t{}, STR_GPS_COORDS_FORMAT, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_GPSFORMAT, 0, 1, GET_SET_DEFAULT(g_eeGeneral.gpsFormat)); - line = body.newLine(&grid); - } +class GpsPage : public SubPage +{ + public: + GpsPage() : SubPage(ICON_RADIO_SETUP, STR_GPS) + { + FlexGridLayout grid(col_two_dsc, row_dsc); + + tzIndex = timezoneIndex(g_eeGeneral.timezone, g_eeGeneral.timezoneMinutes); + + auto line = body.newLine(grid); + // Timezone + new StaticText(line, rect_t{}, STR_TIMEZONE, COLOR_THEME_PRIMARY1); + auto tz = new NumberEdit(line, rect_t{}, minTimezone(), maxTimezone(), + GET_DEFAULT(tzIndex), [=](int newTz) { + tzIndex = newTz; + g_eeGeneral.timezone = timezoneHour(newTz); + g_eeGeneral.timezoneMinutes = + timezoneMinute(newTz); + SET_DIRTY(); + }); + tz->setDisplayHandler([](int32_t tz) { return timezoneDisplay(tz); }); + line = body.newLine(grid); + + // Adjust RTC (from telemetry) + new StaticText(line, rect_t{}, STR_ADJUST_RTC, COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.adjustRTC)); + line = body.newLine(grid); + + // GPS format + new StaticText(line, rect_t{}, STR_GPS_COORDS_FORMAT, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_GPSFORMAT, 0, 1, + GET_SET_DEFAULT(g_eeGeneral.gpsFormat)); + line = body.newLine(grid); + } - protected: - int tzIndex; + protected: + int tzIndex; }; class ViewOptionsPage : public SubPage { - private: - const lv_coord_t opt_col_dsc[4] = {LV_GRID_FR(5), LV_GRID_FR(2), LV_GRID_FR(4), LV_GRID_TEMPLATE_LAST}; - - void viewOption(FormWindow::Line *line, const char* name, std::function getValue, std::function setValue, uint8_t modelOption) - { - line->padLeft(10); - new StaticText(line, rect_t{}, name, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, getValue, setValue); - if (modelOption != OVERRIDE_GLOBAL) { - std::string s(STR_MODEL); - s += " - "; - s += STR_ADCFILTERVALUES[modelOption]; - new StaticText(line, rect_t{}, s.c_str(), 0, COLOR_THEME_SECONDARY1); - } - } + private: + const lv_coord_t opt_col_dsc[4] = {LV_GRID_FR(5), LV_GRID_FR(2), + LV_GRID_FR(4), LV_GRID_TEMPLATE_LAST}; - public: - ViewOptionsPage() : SubPage(ICON_RADIO_SETUP, STR_ENABLED_FEATURES, false) - { - FlexGridLayout grid(opt_col_dsc, row_dsc, 2); + void viewOption(FormLine* line, const char* name, + std::function getValue, + std::function setValue, uint8_t modelOption) + { + line->padLeft(10); + new StaticText(line, rect_t{}, name, COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, getValue, setValue); + if (modelOption != OVERRIDE_GLOBAL) { + std::string s(STR_MODEL); + s += " - "; + s += STR_ADCFILTERVALUES[modelOption]; + new StaticText(line, rect_t{}, s.c_str(), COLOR_THEME_SECONDARY1); + } + } - auto form = new FormWindow(&body, rect_t{}); - form->setFlexLayout(); - form->padAll(0); + public: + ViewOptionsPage() : SubPage(ICON_RADIO_SETUP, STR_ENABLED_FEATURES) + { + FlexGridLayout grid(opt_col_dsc, row_dsc, PAD_TINY); - auto line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_RADIO_MENU_TABS, 0, COLOR_THEME_PRIMARY1); + auto line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_RADIO_MENU_TABS, COLOR_THEME_PRIMARY1); - line = form->newLine(&grid); - viewOption(line, STR_THEME_EDITOR, GET_SET_INVERTED(g_eeGeneral.radioThemesDisabled), g_model.radioThemesDisabled); + line = body.newLine(grid); + viewOption(line, STR_THEME_EDITOR, + GET_SET_INVERTED(g_eeGeneral.radioThemesDisabled), + g_model.radioThemesDisabled); - line = form->newLine(&grid); - viewOption(line, STR_MENUSPECIALFUNCS, GET_SET_INVERTED(g_eeGeneral.radioGFDisabled), g_model.radioGFDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENUSPECIALFUNCS, + GET_SET_INVERTED(g_eeGeneral.radioGFDisabled), + g_model.radioGFDisabled); - line = form->newLine(&grid); - viewOption(line, STR_MENUTRAINER, GET_SET_INVERTED(g_eeGeneral.radioTrainerDisabled), g_model.radioTrainerDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENUTRAINER, + GET_SET_INVERTED(g_eeGeneral.radioTrainerDisabled), + g_model.radioTrainerDisabled); - line = form->newLine(&grid); - new StaticText(line, rect_t{}, STR_MODEL_MENU_TABS, 0, COLOR_THEME_PRIMARY1); + line = body.newLine(grid); + new StaticText(line, rect_t{}, STR_MODEL_MENU_TABS, COLOR_THEME_PRIMARY1); #if defined(HELI) - line = form->newLine(&grid); - viewOption(line, STR_MENUHELISETUP, GET_SET_INVERTED(g_eeGeneral.modelHeliDisabled), g_model.modelHeliDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENUHELISETUP, + GET_SET_INVERTED(g_eeGeneral.modelHeliDisabled), + g_model.modelHeliDisabled); #endif #if defined(FLIGHT_MODES) - line = form->newLine(&grid); - viewOption(line, STR_MENUFLIGHTMODES, GET_SET_INVERTED(g_eeGeneral.modelFMDisabled), g_model.modelFMDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENUFLIGHTMODES, + GET_SET_INVERTED(g_eeGeneral.modelFMDisabled), + g_model.modelFMDisabled); #endif #if defined(GVARS) - line = form->newLine(&grid); - viewOption(line, STR_MENU_GLOBAL_VARS, GET_SET_INVERTED(g_eeGeneral.modelGVDisabled), g_model.modelGVDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENU_GLOBAL_VARS, + GET_SET_INVERTED(g_eeGeneral.modelGVDisabled), + g_model.modelGVDisabled); #endif - line = form->newLine(&grid); - viewOption(line, STR_MENUCURVES, GET_SET_INVERTED(g_eeGeneral.modelCurvesDisabled), g_model.modelCurvesDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENUCURVES, + GET_SET_INVERTED(g_eeGeneral.modelCurvesDisabled), + g_model.modelCurvesDisabled); - line = form->newLine(&grid); - viewOption(line, STR_MENULOGICALSWITCHES, GET_SET_INVERTED(g_eeGeneral.modelLSDisabled), g_model.modelLSDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENULOGICALSWITCHES, + GET_SET_INVERTED(g_eeGeneral.modelLSDisabled), + g_model.modelLSDisabled); - line = form->newLine(&grid); - viewOption(line, STR_MENUCUSTOMFUNC, GET_SET_INVERTED(g_eeGeneral.modelSFDisabled), g_model.modelSFDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENUCUSTOMFUNC, + GET_SET_INVERTED(g_eeGeneral.modelSFDisabled), + g_model.modelSFDisabled); #if defined(LUA_MODEL_SCRIPTS) - line = form->newLine(&grid); - viewOption(line, STR_MENUCUSTOMSCRIPTS, GET_SET_INVERTED(g_eeGeneral.modelCustomScriptsDisabled), g_model.modelCustomScriptsDisabled); + line = body.newLine(grid); + viewOption(line, STR_MENUCUSTOMSCRIPTS, + GET_SET_INVERTED(g_eeGeneral.modelCustomScriptsDisabled), + g_model.modelCustomScriptsDisabled); #endif - line = form->newLine(&grid); - viewOption(line, STR_MENUTELEMETRY, GET_SET_INVERTED(g_eeGeneral.modelTelemetryDisabled), g_model.modelTelemetryDisabled); - } + line = body.newLine(grid); + viewOption(line, STR_MENUTELEMETRY, + GET_SET_INVERTED(g_eeGeneral.modelTelemetryDisabled), + g_model.modelTelemetryDisabled); + } }; -RadioSetupPage::RadioSetupPage(): - PageTab(STR_RADIO_SETUP, ICON_RADIO_SETUP) -{ -} +RadioSetupPage::RadioSetupPage() : PageTab(STR_RADIO_SETUP, ICON_RADIO_SETUP) {} -void RadioSetupPage::build(FormWindow * window) +void RadioSetupPage::build(Window* window) { - FlexGridLayout grid(col_two_dsc, row_dsc, 2); + FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY); window->setFlexLayout(); // Date & time picker including labels @@ -692,70 +727,69 @@ void RadioSetupPage::build(FormWindow * window) // Sub-pages new WindowButtonGroup(window, rect_t{}, { - {STR_SOUND_LABEL, []() { new SoundPage(); }}, + {STR_SOUND_LABEL, []() { new SoundPage(); }}, #if defined(VARIO) - {STR_VARIO, []() { new VarioPage(); }}, + {STR_VARIO, []() { new VarioPage(); }}, #endif #if defined(HAPTIC) - {STR_HAPTIC_LABEL, []() { new HapticPage(); }}, + {STR_HAPTIC_LABEL, []() { new HapticPage(); }}, #endif - {STR_ALARMS_LABEL, []() { new AlarmsPage(); }}, - {STR_BACKLIGHT_LABEL, []() { new BacklightPage(); }}, - {STR_GPS, [](){new GpsPage();}}, - {STR_ENABLED_FEATURES, [](){new ViewOptionsPage();}}, -}); + {STR_ALARMS_LABEL, []() { new AlarmsPage(); }}, + {STR_BACKLIGHT_LABEL, []() { new BacklightPage(); }}, + {STR_GPS, []() { new GpsPage(); }}, + {STR_ENABLED_FEATURES, []() { new ViewOptionsPage(); }}, + }); // Splash screen - auto line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_SPLASHSCREEN, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_SPLASHSCREEN_DELAYS, 0, 7, - [=]() -> int32_t { - return 3 - g_eeGeneral.splashMode; - }, - [=](int32_t newValue) { - g_eeGeneral.splashMode = 3 - newValue; - SET_DIRTY(); - }); + auto line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_SPLASHSCREEN, COLOR_THEME_PRIMARY1); + new Choice( + line, rect_t{}, STR_SPLASHSCREEN_DELAYS, 0, 7, + [=]() -> int32_t { return 3 - g_eeGeneral.splashMode; }, + [=](int32_t newValue) { + g_eeGeneral.splashMode = 3 - newValue; + SET_DIRTY(); + }); // Play startup sound - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_PLAY_HELLO, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_PLAY_HELLO, COLOR_THEME_PRIMARY1); new ToggleSwitch(line, rect_t{}, GET_SET_INVERTED(g_eeGeneral.dontPlayHello)); #if defined(PWR_BUTTON_PRESS) // Pwr Off Delay { - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_PWR_OFF_DELAY, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_PWR_OFF_DELAYS, 0, 3, - [=]() -> int32_t { - return 2 - g_eeGeneral.pwrOffSpeed; - }, - [=](int32_t newValue) { - g_eeGeneral.pwrOffSpeed = 2 - newValue; - SET_DIRTY(); - }); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_PWR_OFF_DELAY, COLOR_THEME_PRIMARY1); + new Choice( + line, rect_t{}, STR_PWR_OFF_DELAYS, 0, 3, + [=]() -> int32_t { return 2 - g_eeGeneral.pwrOffSpeed; }, + [=](int32_t newValue) { + g_eeGeneral.pwrOffSpeed = 2 - newValue; + SET_DIRTY(); + }); } #endif #if defined(PXX2) // Owner ID { - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_OWNER_ID, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_OWNER_ID, COLOR_THEME_PRIMARY1); new RadioTextEdit(line, rect_t{}, g_eeGeneral.ownerRegistrationID, PXX2_LEN_REGISTRATION_ID); } #endif // Country code - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_COUNTRY_CODE, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_COUNTRY_CODES, 0, 2, GET_SET_DEFAULT(g_eeGeneral.countryCode)); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_COUNTRY_CODE, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_COUNTRY_CODES, 0, 2, + GET_SET_DEFAULT(g_eeGeneral.countryCode)); // Audio language - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_VOICE_LANGUAGE, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_VOICE_LANGUAGE, COLOR_THEME_PRIMARY1); auto choice = new Choice(line, rect_t{}, 0, DIM(languagePacks) - 2, GET_VALUE(currentLanguagePackIdx), [](uint8_t newValue) { @@ -768,14 +802,16 @@ void RadioSetupPage::build(FormWindow * window) [](uint8_t value) { return languagePacks[value]->name; }); // Imperial units - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_UNITS_SYSTEM, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_VUNITSSYSTEM, 0, 1, GET_SET_DEFAULT(g_eeGeneral.imperial)); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_UNITS_SYSTEM, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_VUNITSSYSTEM, 0, 1, + GET_SET_DEFAULT(g_eeGeneral.imperial)); // PPM units - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_UNITS_PPM, 0, COLOR_THEME_PRIMARY1); - new Choice(line, rect_t{}, STR_PPMUNIT, PPM_PERCENT_PREC0, PPM_PERCENT_PREC1, GET_SET_DEFAULT(g_eeGeneral.ppmunit)); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_UNITS_PPM, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_PPMUNIT, PPM_PERCENT_PREC0, PPM_PERCENT_PREC1, + GET_SET_DEFAULT(g_eeGeneral.ppmunit)); #if defined(FAI_CHOICE) /* case ITEM_SETUP_FAI: @@ -784,9 +820,8 @@ void RadioSetupPage::build(FormWindow * window) lcdDrawText(RADIO_SETUP_2ND_COLUMN, y, "Locked in FAI Mode"); } else { - g_eeGeneral.fai = editCheckBox(g_eeGeneral.fai, RADIO_SETUP_2ND_COLUMN, y, attr, event); - if (attr && checkIncDec_Ret) { - g_eeGeneral.fai = false; + g_eeGeneral.fai = editCheckBox(g_eeGeneral.fai, RADIO_SETUP_2ND_COLUMN, y, + attr, event); if (attr && checkIncDec_Ret) { g_eeGeneral.fai = false; POPUP_CONFIRMATION("FAI mode?"); } } @@ -794,46 +829,47 @@ void RadioSetupPage::build(FormWindow * window) #endif // Switches delay - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_SWITCHES_DELAY, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_SWITCHES_DELAY, COLOR_THEME_PRIMARY1); auto edit = - new NumberEdit(line, rect_t{}, 0, 100, + new NumberEdit(line, rect_t{0, 0, 80, 32}, 0, 100, GET_SET_VALUE_WITH_OFFSET(g_eeGeneral.switchesDelay, 15)); edit->setDisplayHandler([](int32_t value) { return formatNumberAsString(value * 10, 0, 0, nullptr, STR_MS); }); // USB mode - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_USBMODE, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_USBMODE, COLOR_THEME_PRIMARY1); new Choice(line, rect_t{}, STR_USBMODES, USB_UNSELECTED_MODE, USB_MAX_MODE, GET_SET_DEFAULT(g_eeGeneral.USBMode)); #if defined(ROTARY_ENCODER_NAVIGATION) && !defined(USE_HATS_AS_KEYS) - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_ROTARY_ENC_MODE, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_ROTARY_ENC_MODE, COLOR_THEME_PRIMARY1); new Choice(line, rect_t{}, STR_ROTARY_ENC_OPT, ROTARY_ENCODER_MODE_NORMAL, ROTARY_ENCODER_MODE_INVERT_BOTH, GET_SET_DEFAULT(g_eeGeneral.rotEncMode)); #endif #if defined(USE_HATS_AS_KEYS) - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_HATSMODE, 0, COLOR_THEME_PRIMARY1); - auto box = new FormWindow(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW, 4); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_HATSMODE, COLOR_THEME_PRIMARY1); + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY); new Choice(box, rect_t{}, STR_HATSOPT, HATSMODE_TRIMS_ONLY, HATSMODE_SWITCHABLE, GET_SET_DEFAULT(g_eeGeneral.hatsMode)); new TextButton(box, rect_t{}, "?", [=]() { - new HelpDialog(window, {50, 100, LCD_W - 100, LCD_H - 200}, - STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, LEFT); + new MessageDialog(window, STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "", + LEFT); return 0; }); #endif // RX channel order - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_DEF_CHAN_ORD, 0, + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_DEF_CHAN_ORD, COLOR_THEME_PRIMARY1); // RAET->AETR uint8_t mains = adcGetMaxInputs(ADC_INPUT_MAIN); @@ -850,8 +886,8 @@ void RadioSetupPage::build(FormWindow * window) }); // Stick mode - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_MODE, 0, COLOR_THEME_PRIMARY1); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_MODE, COLOR_THEME_PRIMARY1); choice = new Choice(line, rect_t{}, 0, 3, GET_DEFAULT(g_eeGeneral.stickMode), [=](uint8_t newValue) { mixerTaskStop(); @@ -869,7 +905,8 @@ void RadioSetupPage::build(FormWindow * window) }); // Model quick select - line = window->newLine(&grid); - new StaticText(line, rect_t{}, STR_MODEL_QUICK_SELECT, 0, COLOR_THEME_PRIMARY1); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.modelQuickSelect)); + line = window->newLine(grid); + new StaticText(line, rect_t{}, STR_MODEL_QUICK_SELECT, COLOR_THEME_PRIMARY1); + new ToggleSwitch(line, rect_t{}, + GET_SET_DEFAULT(g_eeGeneral.modelQuickSelect)); } diff --git a/radio/src/gui/colorlcd/radio_setup.h b/radio/src/gui/colorlcd/radio_setup.h index eccb20038ec..1d4026507ce 100644 --- a/radio/src/gui/colorlcd/radio_setup.h +++ b/radio/src/gui/colorlcd/radio_setup.h @@ -25,5 +25,5 @@ class RadioSetupPage: public PageTab { public: RadioSetupPage(); - void build(FormWindow * window) override; + void build(Window * window) override; }; diff --git a/radio/src/gui/colorlcd/radio_spectrum_analyser.cpp b/radio/src/gui/colorlcd/radio_spectrum_analyser.cpp index 34f6ac114b4..0ea3bf9c606 100644 --- a/radio/src/gui/colorlcd/radio_spectrum_analyser.cpp +++ b/radio/src/gui/colorlcd/radio_spectrum_analyser.cpp @@ -20,21 +20,21 @@ */ #include "radio_spectrum_analyser.h" -#include "opentx.h" + #include "libopenui.h" +#include "opentx.h" -#define SET_DIRTY() storageDirty(EE_GENERAL) +#define SET_DIRTY() storageDirty(EE_GENERAL) constexpr coord_t SPECTRUM_HEIGHT = 180; constexpr coord_t SCALE_HEIGHT = 15; constexpr coord_t FOOTER_HEIGHT = 32; -static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -coord_t getAverage(uint8_t number, const uint8_t * value) +coord_t getAverage(uint8_t number, const uint8_t* value) { uint16_t sum = 0; for (uint8_t i = 0; i < number; i++) { @@ -43,205 +43,312 @@ coord_t getAverage(uint8_t number, const uint8_t * value) return sum / number; } -class SpectrumFooterWindow: public FormWindow +class SpectrumFooterWindow : public Window { - public: - SpectrumFooterWindow(FormWindow * parent, const rect_t & rect, int moduleIdx) : - FormWindow(parent, rect) - { - setFlexLayout(); - padAll(0); - padLeft(4); - padRight(4); - - FlexGridLayout grid(col_dsc, row_dsc, 4); - - auto line = newLine(&grid); - line->padAll(0); - - if (isModuleMultimodule(moduleIdx)) { - char label[16]; - - // Frequency - sprintf(label,"T: %dMHz", int(reusableBuffer.spectrumAnalyser.freq / 1000000)); - new StaticText(line, rect_t{0, 0, lv_pct(30), FOOTER_HEIGHT}, label); - - // Span - sprintf(label,"S: %dMHz", int(reusableBuffer.spectrumAnalyser.span / 1000000)); - new StaticText(line, rect_t{0, 0, lv_pct(30), FOOTER_HEIGHT}, label); - } - else { - // Frequency - auto freq = new NumberEdit(line, rect_t{0, 0, lv_pct(30), FOOTER_HEIGHT}, reusableBuffer.spectrumAnalyser.freqMin, - reusableBuffer.spectrumAnalyser.freqMax, - GET_DEFAULT(reusableBuffer.spectrumAnalyser.freq / 1000000), - SET_VALUE(reusableBuffer.spectrumAnalyser.freq, newValue * 1000000)); - freq->setSuffix("MHz"); - freq->setPrefix("F: "); - - // Span - auto span = new NumberEdit(line, rect_t{0, 0, lv_pct(30), FOOTER_HEIGHT}, 1, reusableBuffer.spectrumAnalyser.spanMax, - GET_DEFAULT(reusableBuffer.spectrumAnalyser.span / 1000000), - SET_VALUE(reusableBuffer.spectrumAnalyser.span, newValue * 1000000)); - span->setSuffix("MHz"); - span->setPrefix("S: "); - } + public: + SpectrumFooterWindow(Window* parent, const rect_t& rect, int moduleIdx) : + Window(parent, rect) + { + setFlexLayout(); + padAll(PAD_ZERO); + padLeft(4); + padRight(4); + + FlexGridLayout grid(col_dsc, row_dsc); - // Tracker - auto tracker = new NumberEdit(line, rect_t{0, 0, lv_pct(30), LV_SIZE_CONTENT}, (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2) / 1000000, - (reusableBuffer.spectrumAnalyser.freq + reusableBuffer.spectrumAnalyser.span / 2) / 1000000, - GET_DEFAULT(reusableBuffer.spectrumAnalyser.track / 1000000), - SET_VALUE(reusableBuffer.spectrumAnalyser.track, newValue * 1000000)); - tracker->setSuffix("MHz"); - tracker->setPrefix("T: "); - tracker->setDefault(reusableBuffer.spectrumAnalyser.freqDefault); + auto line = newLine(grid); + line->padAll(PAD_ZERO); + + if (isModuleMultimodule(moduleIdx)) { + char label[16]; + + // Frequency + sprintf(label, "T: %dMHz", + int(reusableBuffer.spectrumAnalyser.freq / 1000000)); + (new StaticText(line, rect_t{0, 0, lv_pct(30), FOOTER_HEIGHT}, label)) + ->padTop(PAD_MEDIUM); + + // Span + sprintf(label, "S: %dMHz", + int(reusableBuffer.spectrumAnalyser.span / 1000000)); + (new StaticText(line, rect_t{0, 0, lv_pct(30), FOOTER_HEIGHT}, label)) + ->padTop(PAD_MEDIUM); + } else { + // Frequency + auto freq = new NumberEdit( + line, rect_t{0, 0, lv_pct(30), FOOTER_HEIGHT}, + reusableBuffer.spectrumAnalyser.freqMin, + reusableBuffer.spectrumAnalyser.freqMax, + GET_DEFAULT(reusableBuffer.spectrumAnalyser.freq / 1000000), + SET_VALUE(reusableBuffer.spectrumAnalyser.freq, newValue * 1000000)); + freq->setSuffix("MHz"); + freq->setPrefix("F: "); + + // Span + auto span = new NumberEdit( + line, rect_t{0, 0, lv_pct(30), FOOTER_HEIGHT}, 1, + reusableBuffer.spectrumAnalyser.spanMax, + GET_DEFAULT(reusableBuffer.spectrumAnalyser.span / 1000000), + SET_VALUE(reusableBuffer.spectrumAnalyser.span, newValue * 1000000)); + span->setSuffix("MHz"); + span->setPrefix("S: "); } + + // Tracker + auto tracker = new NumberEdit( + line, rect_t{0, 0, lv_pct(30), LV_SIZE_CONTENT}, + (reusableBuffer.spectrumAnalyser.freq - + reusableBuffer.spectrumAnalyser.span / 2) / + 1000000, + (reusableBuffer.spectrumAnalyser.freq + + reusableBuffer.spectrumAnalyser.span / 2) / + 1000000, + GET_DEFAULT(reusableBuffer.spectrumAnalyser.track / 1000000), + SET_VALUE(reusableBuffer.spectrumAnalyser.track, newValue * 1000000)); + tracker->setSuffix("MHz"); + tracker->setPrefix("T: "); + tracker->setDefault(reusableBuffer.spectrumAnalyser.freqDefault); + } }; -class SpectrumScaleWindow: public Window +class SpectrumScaleWindow : public Window { - public: - SpectrumScaleWindow(Window * parent, const rect_t & rect) : - Window(parent, rect) - { - // This window will be automatically invalidated because it's between the frequency analyser (always invalidated) and the modified field + public: + SpectrumScaleWindow(Window* parent, const rect_t& rect) : Window(parent, rect) + { + etx_solid_bg(lvobj, COLOR_THEME_SECONDARY2_INDEX); + + build(); + } + + void build() + { + // Draw text scale + char s[16]; + uint32_t startFreq = reusableBuffer.spectrumAnalyser.freq - + reusableBuffer.spectrumAnalyser.span / 2; + for (uint32_t frequency = (startFreq / 10000000) * 10000000 + 10000000;; + frequency += 10000000) { + int x = (frequency - startFreq) / reusableBuffer.spectrumAnalyser.step; + if (x >= LCD_W - 1) break; + formatNumberAsString(s, 16, frequency / 1000000, 16); + new StaticText(this, {x - 16, 0, 32, 15}, s, + FONT(XS) | CENTERED | COLOR_THEME_PRIMARY1); } + } - void paint(BitmapBuffer * dc) override - { - dc->drawSolidFilledRect(0, 0, width(), height(), COLOR_THEME_SECONDARY2); - - // Draw tracker - int offset = reusableBuffer.spectrumAnalyser.track - (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2); - int x = limit(0, offset / reusableBuffer.spectrumAnalyser.step, width() - 1); - dc->drawSolidVerticalLine(x, 0, height(), COLOR_THEME_PRIMARY1); - - // Draw text scale - for (uint32_t frequency = - ((reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2) / 10000000) * 10000000 + 10000000;; frequency += 10000000) { - offset = frequency - (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2); - x = offset / reusableBuffer.spectrumAnalyser.step; - if (x >= LCD_W - 1) - break; - if ((frequency / 1000000) % 2 == 0) { - dc->drawNumber(x, 0, frequency / 1000000, FONT(XS) | CENTERED); - } - } + void checkEvents() override + { + if (lastFreq != reusableBuffer.spectrumAnalyser.freq || + lastSpan != reusableBuffer.spectrumAnalyser.span) { + lastFreq = reusableBuffer.spectrumAnalyser.freq; + lastSpan = reusableBuffer.spectrumAnalyser.span; + clear(); + build(); } + } + + protected: + uint32_t lastFreq = 0; + uint32_t lastSpan = 0; }; -class SpectrumWindow: public Window +class SpectrumWindow : public Window { - public: - SpectrumWindow(Window * parent, const rect_t & rect) : - Window(parent, rect, REFRESH_ALWAYS) - { + public: + SpectrumWindow(Window* parent, const rect_t& rect) : + Window(parent, rect) + { + lv_style_init(&style); + lv_style_set_line_width(&style, 3); + lv_style_set_line_opa(&style, LV_OPA_COVER); + lv_style_set_line_color(&style, makeLvColor(COLOR_THEME_ACTIVE)); + + lv_coord_t w = width() - 1; + for (int i = 0; i < SPECTRUM_HEIGHT / 40; i += 1) { + lv_coord_t y = height() - 40 - (i * 40); + hAxisPts[i * 2] = {0, y}; + hAxisPts[i * 2 + 1] = {w, y}; + auto line = lv_line_create(lvobj); + etx_obj_add_style(line, styles->graph_dashed, LV_PART_MAIN); + lv_line_set_points(line, &hAxisPts[i * 2], 2); } - void paint(BitmapBuffer * dc) override - { - if (TELEMETRY_STREAMING()) { - dc->drawText(width() / 2, height() / 2, STR_TURN_OFF_RECEIVER, CENTERED); - return; - } - -#if defined(SIMU) - // Geneate random data for simu - for (coord_t x= 0; x < width(); x++) { - uint8_t power = rand() % 80; - reusableBuffer.spectrumAnalyser.bars[x] = power; - reusableBuffer.spectrumAnalyser.bars[x+1] = power; - if (power > reusableBuffer.spectrumAnalyser.max[x]) { - reusableBuffer.spectrumAnalyser.max[x] = power; - reusableBuffer.spectrumAnalyser.max[x+1] = power; - } - } -#endif + for (int i = 0; i < 8; i += 1) { + auto line = lv_line_create(lvobj); + etx_obj_add_style(line, styles->graph_dashed, LV_PART_MAIN); + lv_obj_add_flag(line, LV_OBJ_FLAG_HIDDEN); + vAxisLines[i] = line; + } - coord_t SCALE_TOP = height() - MENU_FOOTER_HEIGHT; + for (int i = 0; i < width() / 4; i += 1) { + auto line = lv_line_create(lvobj); + etx_obj_add_style(line, styles->div_line_black, LV_PART_MAIN); + maxLines[i] = line; - // Draw fixed part (scale,..) - for (uint32_t frequency = ((reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2) / 10000000) * 10000000 + 10000000; ; frequency += 10000000) { - int offset = frequency - (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2); - int x = offset / reusableBuffer.spectrumAnalyser.step; - if (x >= LCD_W - 1) - break; - dc->drawVerticalLine(x, 0, height(), STASHED, COLOR_THEME_SECONDARY2); - } + line = lv_line_create(lvobj); + lv_obj_add_style(line, &style, LV_PART_MAIN); + barLines[i] = line; + } - for (uint8_t power = 20;; power += 20) { - int y = SCALE_TOP - 1 - limit(0, power << 1, SCALE_TOP); - if (y <= 0) - break; - dc->drawHorizontalLine(0, y, width(), STASHED, COLOR_THEME_SECONDARY2); - } + warning = new StaticText( + this, {0, height() / 2 - 20, lv_pct(100), LV_SIZE_CONTENT}, + STR_TURN_OFF_RECEIVER, COLOR_THEME_PRIMARY1 | CENTERED | FONT(XL)); + warning->show(TELEMETRY_STREAMING()); + } - // Draw spectrum data - constexpr uint8_t step = 4; + void checkEvents() override + { + lv_coord_t SCALE_TOP = height(); + constexpr uint8_t step = 4; + lv_coord_t x; + int i; - for (coord_t xv = 0; xv < width(); xv += step) { - coord_t yv = SCALE_TOP - 1 - limit(0, getAverage(step, &reusableBuffer.spectrumAnalyser.bars[xv]) << 1, SCALE_TOP); - coord_t max_yv = SCALE_TOP - 1 - limit(0, getAverage(step, &reusableBuffer.spectrumAnalyser.max[xv]) << 1, SCALE_TOP); + warning->show(TELEMETRY_STREAMING()); - // Signal bar - dc->drawSolidFilledRect(xv, yv, step - 1, SCALE_TOP - yv, COLOR_THEME_ACTIVE); - // lcdDrawSolidRect(xv, yv, step - 1, SCALE_TOP - yv, 1, TEXT_COLOR); + if (TELEMETRY_STREAMING()) return; - // Signal max - dc->drawSolidHorizontalLine(xv, max_yv, step - 1, COLOR_THEME_PRIMARY1); +#if defined(SIMU) + // Geneate random data for simu + for (coord_t x = 0; x < width() - 1; x++) { + uint8_t power = rand() % 80; + reusableBuffer.spectrumAnalyser.bars[x] = power; + reusableBuffer.spectrumAnalyser.bars[x + 1] = power; + if (power > reusableBuffer.spectrumAnalyser.max[x]) { + reusableBuffer.spectrumAnalyser.max[x] = power; + reusableBuffer.spectrumAnalyser.max[x + 1] = power; + } + } +#endif - // Decay max values - if (max_yv < yv) { // Those value are INVERTED (MENU_FOOTER_TOP - value) - for (uint8_t i = 0; i < step; i++) { - reusableBuffer.spectrumAnalyser.max[xv + i] = max(0, reusableBuffer.spectrumAnalyser.max[xv + i] - 1); - } + for (x = 0, i = 0; x < width(); x += step, i += 2) { + lv_coord_t yv = + SCALE_TOP - 1 - + limit(0, + getAverage(step, &reusableBuffer.spectrumAnalyser.bars[x]) + << 1, + SCALE_TOP); + lv_coord_t max_yv = + SCALE_TOP - 1 - + limit( + 0, getAverage(step, &reusableBuffer.spectrumAnalyser.max[x]) << 1, + SCALE_TOP); + + maxPts[i] = {x, max_yv}; + maxPts[i + 1] = {(lv_coord_t)(x + 3), max_yv}; + lv_line_set_points(maxLines[i / 2], &maxPts[i], 2); + + barPts[i] = {(lv_coord_t)(x + 1), yv}; + barPts[i + 1] = {(lv_coord_t)(x + 1), SCALE_TOP}; + lv_line_set_points(barLines[i / 2], &barPts[i], 2); + + // Decay max values + if (max_yv < yv) { + for (uint8_t n = 0; n < step; n += 1) { + reusableBuffer.spectrumAnalyser.max[x + n] = + max(0, reusableBuffer.spectrumAnalyser.max[x + n] - 1); } } + } - // Draw tracker - int offset = reusableBuffer.spectrumAnalyser.track - (reusableBuffer.spectrumAnalyser.freq - reusableBuffer.spectrumAnalyser.span / 2); - int x = limit(0, offset / reusableBuffer.spectrumAnalyser.step, width() - 1); - dc->drawSolidVerticalLine(x, 0, height(), COLOR_THEME_PRIMARY1); + if (lastFreq != reusableBuffer.spectrumAnalyser.freq || + lastSpan != reusableBuffer.spectrumAnalyser.span) { + lastFreq = reusableBuffer.spectrumAnalyser.freq; + lastSpan = reusableBuffer.spectrumAnalyser.span; + + int i = 0; + lv_coord_t h = height() - 1; + uint32_t startFreq = reusableBuffer.spectrumAnalyser.freq - + reusableBuffer.spectrumAnalyser.span / 2; + for (uint32_t frequency = (startFreq / 10000000) * 10000000 + 10000000;; + frequency += 10000000) { + lv_coord_t x = (frequency - startFreq) / reusableBuffer.spectrumAnalyser.step; + if (x >= LCD_W - 1) break; + vAxisPts[i * 2] = {x, 0}; + vAxisPts[i * 2 + 1] = {x, h}; + lv_line_set_points(vAxisLines[i], &vAxisPts[i * 2], 2); + lv_obj_clear_flag(vAxisLines[i], LV_OBJ_FLAG_HIDDEN); + i += 1; + } + for (; i < 8; i += 1) { + lv_obj_add_flag(vAxisLines[i], LV_OBJ_FLAG_HIDDEN); + } } - protected: + Window::checkEvents(); + } + protected: + lv_style_t style; + lv_point_t maxPts[2 * LCD_W / 4]; + lv_point_t barPts[2 * LCD_W / 4]; + lv_point_t hAxisPts[2 * SPECTRUM_HEIGHT / 40]; + lv_point_t vAxisPts[2 * 8]; + lv_obj_t* maxLines[LCD_W / 4]; + lv_obj_t* barLines[LCD_W / 4]; + lv_obj_t* vAxisLines[8]; + StaticText* warning = nullptr; + + uint32_t lastFreq = 0; + uint32_t lastSpan = 0; }; - RadioSpectrumAnalyser::RadioSpectrumAnalyser(uint8_t moduleIdx) : - Page(ICON_RADIO_TOOLS), - moduleIdx(moduleIdx) + Page(ICON_RADIO_TOOLS, PAD_ZERO), moduleIdx(moduleIdx) { setCloseHandler([=]() { stop(); }); init(); buildHeader(&header); buildBody(&body); start(); + + trackLine = lv_line_create(lvobj); + etx_obj_add_style(trackLine, styles->div_line_black, LV_PART_MAIN); } -void RadioSpectrumAnalyser::buildHeader(Window * window) +void RadioSpectrumAnalyser::buildHeader(Window* window) { header.setTitle(STR_MENUTOOLS); header.setTitle2(STR_MENU_SPECTRUM_ANALYSER); } -void RadioSpectrumAnalyser::buildBody(FormWindow * window) +void RadioSpectrumAnalyser::buildBody(Window* window) { new SpectrumWindow(window, {0, 0, LCD_W, SPECTRUM_HEIGHT}); new SpectrumScaleWindow(window, {0, SPECTRUM_HEIGHT, LCD_W, SCALE_HEIGHT}); - new SpectrumFooterWindow(window, {0, SPECTRUM_HEIGHT + SCALE_HEIGHT, LCD_W, FOOTER_HEIGHT}, moduleIdx); + new SpectrumFooterWindow( + window, {0, SPECTRUM_HEIGHT + SCALE_HEIGHT, LCD_W, FOOTER_HEIGHT}, + moduleIdx); +} + +void RadioSpectrumAnalyser::checkEvents() +{ + int32_t offset = reusableBuffer.spectrumAnalyser.track - + (reusableBuffer.spectrumAnalyser.freq - + reusableBuffer.spectrumAnalyser.span / 2); + if (offset < 0) offset = 0; + int16_t x = + limit(0, offset / reusableBuffer.spectrumAnalyser.step, width() - 1); + if (x != trackX) { + trackX = x; + trackPts[0] = {(lv_coord_t)x, 45}; + trackPts[1] = {(lv_coord_t)x, (lv_coord_t)(height() - 32)}; + lv_line_set_points(trackLine, trackPts, 2); + } + Page::checkEvents(); } void RadioSpectrumAnalyser::init() { - memclear(&reusableBuffer.spectrumAnalyser, sizeof(reusableBuffer.spectrumAnalyser)); + memclear(&reusableBuffer.spectrumAnalyser, + sizeof(reusableBuffer.spectrumAnalyser)); #if defined(INTERNAL_MODULE_MULTI) if (moduleIdx == INTERNAL_MODULE && g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_NONE) { reusableBuffer.spectrumAnalyser.moduleOFF = true; - // this needs to be set BEFORE the module is set to prevent proto list scanning + // this needs to be set BEFORE the module is set to prevent proto list + // scanning moduleState[moduleIdx].mode = MODULE_MODE_SPECTRUM_ANALYSER; setModuleType(INTERNAL_MODULE, MODULE_TYPE_MULTIMODULE); } else { @@ -255,24 +362,25 @@ void RadioSpectrumAnalyser::init() reusableBuffer.spectrumAnalyser.freqDefault = 890; reusableBuffer.spectrumAnalyser.freqMin = 850; reusableBuffer.spectrumAnalyser.freqMax = 930; - } - else { + } else { if (isModuleMultimodule(moduleIdx)) { reusableBuffer.spectrumAnalyser.spanDefault = 80; // 80MHz - } - else { + } else { reusableBuffer.spectrumAnalyser.spanDefault = 40; // 40MHz } reusableBuffer.spectrumAnalyser.spanMax = 80; - reusableBuffer.spectrumAnalyser.freqDefault = 2440; // 2440MHz + reusableBuffer.spectrumAnalyser.freqDefault = 2440; // 2440MHz reusableBuffer.spectrumAnalyser.freqMin = 2400; reusableBuffer.spectrumAnalyser.freqMax = 2485; } - reusableBuffer.spectrumAnalyser.span = reusableBuffer.spectrumAnalyser.spanDefault * 1000000; - reusableBuffer.spectrumAnalyser.freq = reusableBuffer.spectrumAnalyser.freqDefault * 1000000; + reusableBuffer.spectrumAnalyser.span = + reusableBuffer.spectrumAnalyser.spanDefault * 1000000; + reusableBuffer.spectrumAnalyser.freq = + reusableBuffer.spectrumAnalyser.freqDefault * 1000000; reusableBuffer.spectrumAnalyser.track = reusableBuffer.spectrumAnalyser.freq; - reusableBuffer.spectrumAnalyser.step = reusableBuffer.spectrumAnalyser.span / LCD_W; + reusableBuffer.spectrumAnalyser.step = + reusableBuffer.spectrumAnalyser.span / LCD_W; reusableBuffer.spectrumAnalyser.dirty = true; } @@ -298,7 +406,4 @@ void RadioSpectrumAnalyser::stop() setModuleType(INTERNAL_MODULE, MODULE_TYPE_NONE); } #endif - /* wait 1s to resume normal operation before leaving */ - // watchdogSuspend(1000); - // RTOS_WAIT_MS(1000); } diff --git a/radio/src/gui/colorlcd/radio_spectrum_analyser.h b/radio/src/gui/colorlcd/radio_spectrum_analyser.h index 40c9fb94662..14c371cfb83 100644 --- a/radio/src/gui/colorlcd/radio_spectrum_analyser.h +++ b/radio/src/gui/colorlcd/radio_spectrum_analyser.h @@ -19,24 +19,26 @@ * GNU General Public License for more details. */ -#ifndef _RADIO_SPECTRUM_ANALYSER_H -#define _RADIO_SPECTRUM_ANALYSER_H +#pragma once #include "page.h" -class RadioSpectrumAnalyser: public Page +class RadioSpectrumAnalyser : public Page { - public: - explicit RadioSpectrumAnalyser(uint8_t moduleIdx); + public: + explicit RadioSpectrumAnalyser(uint8_t moduleIdx); - protected: - uint8_t moduleIdx; + protected: + uint8_t moduleIdx; + lv_point_t trackPts[2]; + lv_obj_t* trackLine = nullptr; + int16_t trackX = -1; - void buildHeader(Window * window); - void buildBody(FormWindow * window); - void init(); - void start(); - void stop(); -}; + void buildHeader(Window* window); + void buildBody(Window* window); + void init(); + void start(); + void stop(); -#endif // _RADIO_SPECTRUM_ANALYSER_H + void checkEvents() override; +}; diff --git a/radio/src/gui/colorlcd/radio_theme.cpp b/radio/src/gui/colorlcd/radio_theme.cpp index 0b94911c07d..bf5d524c947 100644 --- a/radio/src/gui/colorlcd/radio_theme.cpp +++ b/radio/src/gui/colorlcd/radio_theme.cpp @@ -18,36 +18,33 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + #include "radio_theme.h" -#include +#include "color_editor.h" +#include "color_list.h" #include "libopenui.h" #include "opentx.h" -#include "file_preview.h" -#include "theme_manager.h" -#include "view_main.h" -#include "color_list.h" -#include "listbox.h" +#include "page.h" #include "preview_window.h" +#include "themes/etx_lv_theme.h" constexpr int COLOR_PREVIEW_SIZE = 18; #if LCD_W > LCD_H - constexpr int LIST_WIDTH = ((LCD_W - 12) / 2 - COLOR_PREVIEW_SIZE); - constexpr int COLOR_LIST_WIDTH = ((LCD_W * 3)/10); +constexpr int LIST_WIDTH = ((LCD_W - 12) / 2 - COLOR_PREVIEW_SIZE); +constexpr int COLOR_LIST_WIDTH = ((LCD_W * 3) / 10); #else - constexpr int LIST_HEIGHT = (LCD_H / 2 - 38); - constexpr int COLOR_LIST_HEIGHT = (LCD_H / 2 - 24); +constexpr int LIST_HEIGHT = (LCD_H / 2 - 38); +constexpr int COLOR_LIST_HEIGHT = (LCD_H / 2 - 24); #endif #if LCD_W > LCD_H -constexpr int BUTTON_WIDTH = 75; -constexpr rect_t detailsDialogRect = {30, 30, LCD_W - 60, LCD_H - 60}; +constexpr int BUTTON_WIDTH = 75; constexpr int COLOR_BOX_WIDTH = 45; #else -constexpr int BUTTON_WIDTH = 65; -constexpr rect_t detailsDialogRect = {10, 50, LCD_W - 20, 220}; +constexpr int BUTTON_WIDTH = 65; constexpr int COLOR_BOX_WIDTH = 55; #endif @@ -58,425 +55,389 @@ constexpr int COLOR_BOX_HEIGHT = 30; constexpr int BOX_MARGIN = 2; constexpr int MAX_BOX_WIDTH = 15; - -class ThemeColorPreview : public FormWindow +class ThemeColorPreview : public Window { - public: - ThemeColorPreview(Window *parent, const rect_t &rect, std::vector colorList) : - FormWindow(parent, rect, NO_FOCUS), - colorList(colorList) - { - padAll(0); + public: + ThemeColorPreview(Window *parent, const rect_t &rect, + std::vector colorList) : + Window(parent, rect, NO_FOCUS), colorList(colorList) + { + padAll(PAD_ZERO); #if LCD_W > LCD_H - setFlexLayout(LV_FLEX_FLOW_COLUMN, BOX_MARGIN); + setFlexLayout(LV_FLEX_FLOW_COLUMN, BOX_MARGIN); #else - setFlexLayout(LV_FLEX_FLOW_ROW, BOX_MARGIN); + setFlexLayout(LV_FLEX_FLOW_ROW, BOX_MARGIN); #endif - build(); - } + build(); + } - void build() - { - clear(); - setBoxWidth(); - int size = (boxWidth + BOX_MARGIN) * colorList.size() - BOX_MARGIN; + void build() + { + clear(); + setBoxWidth(); + int size = (boxWidth + BOX_MARGIN) * colorList.size() - BOX_MARGIN; #if LCD_W > LCD_H - padTop((height() - size) / 2); + padTop((height() - size) / 2); #else - padLeft((width() - size) / 2); + padLeft((width() - size) / 2); #endif - for (auto color: colorList) { - auto c = lv_obj_create(lvobj); - lv_obj_set_size(c, boxWidth, boxWidth); - lv_obj_set_style_border_width(c, 1, 0); - lv_obj_set_style_border_color(c, makeLvColor(COLOR2FLAGS(BLACK)), 0); - lv_obj_set_style_border_opa(c, LV_OPA_100, 0); - lv_obj_set_style_bg_color(c, makeLvColor(COLOR2FLAGS(color.colorValue)), 0); - lv_obj_set_style_bg_opa(c, LV_OPA_100, 0); - } + for (auto color : colorList) { + new ColorSwatch(this, {0, 0, boxWidth, boxWidth}, color.colorValue); } + } - void setColorList(std::vector colorList) - { - this->colorList = colorList; - build(); - } + void setColorList(std::vector colorList) + { + this->colorList = colorList; + build(); + } - protected: - std::vector colorList; - int boxWidth = MAX_BOX_WIDTH; + protected: + std::vector colorList; + int boxWidth = MAX_BOX_WIDTH; - void setBoxWidth() - { + void setBoxWidth() + { #if LCD_W > LCD_H - boxWidth = (height() - (colorList.size() - 1) * BOX_MARGIN) / colorList.size(); + boxWidth = + (height() - (colorList.size() - 1) * BOX_MARGIN) / colorList.size(); #else - boxWidth = (width() - (colorList.size() - 1) * BOX_MARGIN) / colorList.size(); + boxWidth = + (width() - (colorList.size() - 1) * BOX_MARGIN) / colorList.size(); #endif - boxWidth = min(boxWidth, MAX_BOX_WIDTH); - } + boxWidth = min(boxWidth, MAX_BOX_WIDTH); + } }; - static const lv_coord_t d_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t b_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -class ThemeDetailsDialog: public Dialog +class ThemeDetailsDialog : public BaseDialog { - public: - ThemeDetailsDialog(Window *parent, ThemeFile theme, std::function saveHandler = nullptr) : - Dialog(parent, STR_EDIT_THEME_DETAILS, detailsDialogRect), + public: + ThemeDetailsDialog( + Window *parent, ThemeFile theme, + std::function saveHandler = nullptr) : + BaseDialog(parent, STR_EDIT_THEME_DETAILS, false, DIALOG_DEFAULT_WIDTH, + LV_SIZE_CONTENT), theme(theme), saveHandler(saveHandler) - { - content->form.padAll(4); - content->form.padLeft(8); - content->form.padRight(8); - - lv_obj_set_style_bg_color(content->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0); - lv_obj_set_style_bg_opa(content->getLvObj(), LV_OPA_100, LV_PART_MAIN); - auto form = new FormWindow(&content->form, rect_t{}); - form->setFlexLayout(); - - FlexGridLayout grid(d_col_dsc, row_dsc, 2); - - auto line = form->newLine(&grid); - line->padAll(0); - - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); - auto te = new TextEdit(line, rect_t{}, this->theme.getName(), SELECTED_THEME_NAME_LEN); - lv_obj_set_grid_cell(te->getLvObj(), LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); - - line = form->newLine(&grid); - line->padAll(0); - line->padTop(2); - - new StaticText(line, rect_t{}, STR_AUTHOR, 0, COLOR_THEME_PRIMARY1); - te = new TextEdit(line, rect_t{}, this->theme.getAuthor(), AUTHOR_LENGTH); - lv_obj_set_grid_cell(te->getLvObj(), LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); - - FlexGridLayout grid2(b_col_dsc, row_dsc, 2); - - line = form->newLine(&grid2); - line->padAll(0); - - new StaticText(line, rect_t{}, STR_DESCRIPTION, 0, COLOR_THEME_PRIMARY1); - line = form->newLine(&grid2); - line->padAll(0); - te = new TextEdit(line, rect_t{}, this->theme.getInfo(), INFO_LENGTH); - lv_obj_set_grid_cell(te->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 2, LV_GRID_ALIGN_CENTER, 0, 1); - - line = form->newLine(&grid2); - line->padAll(0); - line->padTop(10); - - auto button = new TextButton(line, rect_t{0, 0, lv_pct(30), 32}, STR_SAVE, [=] () { - if (saveHandler != nullptr) - saveHandler(this->theme); - deleteLater(); - return 0; - }); - lv_obj_set_grid_cell(button->getLvObj(), LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1); - - button = new TextButton(line, rect_t{0, 0, lv_pct(30), 32}, STR_CANCEL, [=] () { - deleteLater(); - return 0; - }); - lv_obj_set_grid_cell(button->getLvObj(), LV_GRID_ALIGN_CENTER, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); - } - - protected: - ThemeFile theme; - std::function saveHandler = nullptr; -}; - -class ColorSquare : public Window -{ - public: - ColorSquare(Window *window, const rect_t &rect, uint32_t color, WindowFlags windowFlags = 0) : - Window(window, rect, windowFlags | NO_FOCUS), - _color(color) - { - swatch = lv_obj_create(lvobj); - lv_obj_set_size(swatch, width(), height()); - lv_obj_set_style_border_width(swatch, 1, 0); - lv_obj_set_style_border_color(swatch, makeLvColor(COLOR2FLAGS(BLACK)), 0); - lv_obj_set_style_border_opa(swatch, LV_OPA_100, 0); - lv_obj_set_style_bg_color(swatch, makeLvColor(COLOR2FLAGS(_color)), 0); - lv_obj_set_style_bg_opa(swatch, LV_OPA_100, 0); - } - - void setColorToEdit(uint32_t colorEntry) - { - _color = colorEntry; - lv_obj_set_style_bg_color(swatch, makeLvColor(COLOR2FLAGS(_color)), 0); - } + { + FlexGridLayout grid(d_col_dsc, row_dsc, PAD_TINY); + + auto line = form->newLine(grid); + line->padAll(PAD_TINY); + + new StaticText(line, rect_t{}, STR_NAME, COLOR_THEME_PRIMARY1); + auto te = new TextEdit(line, rect_t{}, this->theme.getName(), + SELECTED_THEME_NAME_LEN); + lv_obj_set_grid_cell(te->getLvObj(), LV_GRID_ALIGN_STRETCH, 1, 1, + LV_GRID_ALIGN_CENTER, 0, 1); + + line = form->newLine(grid); + line->padAll(PAD_TINY); + line->padTop(2); + + new StaticText(line, rect_t{}, STR_AUTHOR, COLOR_THEME_PRIMARY1); + te = new TextEdit(line, rect_t{}, this->theme.getAuthor(), AUTHOR_LENGTH); + lv_obj_set_grid_cell(te->getLvObj(), LV_GRID_ALIGN_STRETCH, 1, 1, + LV_GRID_ALIGN_CENTER, 0, 1); + + FlexGridLayout grid2(b_col_dsc, row_dsc, PAD_TINY); + + line = form->newLine(grid2); + line->padAll(PAD_TINY); + + new StaticText(line, rect_t{}, STR_DESCRIPTION, COLOR_THEME_PRIMARY1); + line = form->newLine(grid2); + line->padAll(PAD_TINY); + te = new TextEdit(line, rect_t{}, this->theme.getInfo(), INFO_LENGTH); + lv_obj_set_grid_cell(te->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 2, + LV_GRID_ALIGN_CENTER, 0, 1); + + line = form->newLine(grid2); + line->padAll(PAD_TINY); + line->padTop(10); + + auto button = + new TextButton(line, rect_t{0, 0, lv_pct(30), 32}, STR_CANCEL, [=]() { + deleteLater(); + return 0; + }); + lv_obj_set_grid_cell(button->getLvObj(), LV_GRID_ALIGN_CENTER, 0, 1, + LV_GRID_ALIGN_CENTER, 0, 1); + + button = + new TextButton(line, rect_t{0, 0, lv_pct(30), 32}, STR_SAVE, [=]() { + if (saveHandler != nullptr) saveHandler(this->theme); + deleteLater(); + return 0; + }); + lv_obj_set_grid_cell(button->getLvObj(), LV_GRID_ALIGN_CENTER, 1, 1, + LV_GRID_ALIGN_CENTER, 0, 1); + } - protected: - uint32_t _color; - lv_obj_t *swatch; + protected: + ThemeFile theme; + std::function saveHandler = nullptr; }; class ColorEditPage : public Page { - public: - ColorEditPage(ThemeFile *theme, LcdColorIndex indexOfColor, - std::function updateHandler = nullptr) : - Page(ICON_RADIO_EDIT_THEME), + public: + ColorEditPage(ThemeFile *theme, LcdColorIndex indexOfColor, + std::function updateHandler = nullptr) : + Page(ICON_RADIO_EDIT_THEME, PAD_SMALL), _updateHandler(std::move(updateHandler)), _indexOfColor(indexOfColor), _theme(theme) - { - buildBody(&body); - buildHead(&header); - } + { + buildHead(&header); + buildBody(&body); + } - void setActiveColorBar(int activeTab) - { - if (activeTab >= 0 && _activeTab <= (int)_tabs.size()) { - _activeTab = activeTab; - for (auto i = 0; i < (int) _tabs.size(); i++) - _tabs[i]->check(i == _activeTab); - _colorEditor->setColorEditorType(_activeTab == 1 ? HSV_COLOR_EDITOR : RGB_COLOR_EDITOR); - } + void setActiveColorBar(int activeTab) + { + if (activeTab >= 0 && _activeTab <= (int)_tabs.size()) { + _activeTab = activeTab; + for (auto i = 0; i < (int)_tabs.size(); i++) + _tabs[i]->check(i == _activeTab); + _colorEditor->setColorEditorType(_activeTab == 1 ? HSV_COLOR_EDITOR + : RGB_COLOR_EDITOR); } + } - protected: - std::function _updateHandler; - LcdColorIndex _indexOfColor; - ThemeFile *_theme; - TextButton *_cancelButton; - ColorEditor *_colorEditor; - PreviewWindow *_previewWindow = nullptr; - std::vector