From ace7cfbe9dc4b7316b09121f8d883a4b315c1598 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Mon, 9 May 2022 11:37:42 +0200 Subject: [PATCH] simplify model setup screen --- radio/src/gui/colorlcd/CMakeLists.txt | 3 + radio/src/gui/colorlcd/LvglWrapper.cpp | 9 +- radio/src/gui/colorlcd/model_setup.cpp | 400 ++++++-------------- radio/src/gui/colorlcd/module_setup.cpp | 41 ++ radio/src/gui/colorlcd/module_setup.h | 28 +- radio/src/gui/colorlcd/page.cpp | 5 + radio/src/gui/colorlcd/page.h | 2 + radio/src/gui/colorlcd/preflight_checks.cpp | 343 +++++++++++++++++ radio/src/gui/colorlcd/preflight_checks.h | 28 ++ radio/src/gui/colorlcd/throttle_params.cpp | 91 +++++ radio/src/gui/colorlcd/throttle_params.h | 28 ++ radio/src/gui/colorlcd/timer_setup.cpp | 10 - radio/src/gui/colorlcd/timer_setup.h | 5 - radio/src/gui/colorlcd/trainer_setup.cpp | 53 +++ radio/src/gui/colorlcd/trainer_setup.h | 43 +-- radio/src/gui/colorlcd/trims_setup.cpp | 74 ++++ radio/src/gui/colorlcd/trims_setup.h | 28 ++ radio/src/gui/gui_common.cpp | 2 +- radio/src/thirdparty/libopenui | 2 +- 19 files changed, 826 insertions(+), 369 deletions(-) create mode 100644 radio/src/gui/colorlcd/preflight_checks.cpp create mode 100644 radio/src/gui/colorlcd/preflight_checks.h create mode 100644 radio/src/gui/colorlcd/throttle_params.cpp create mode 100644 radio/src/gui/colorlcd/throttle_params.h create mode 100644 radio/src/gui/colorlcd/trims_setup.cpp create mode 100644 radio/src/gui/colorlcd/trims_setup.h diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index 41e3088cb..6d4e8546b 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -56,6 +56,9 @@ set(GUI_SRC custom_failsafe.cpp module_setup.cpp timer_setup.cpp + trims_setup.cpp + throttle_params.cpp + preflight_checks.cpp model_setup.cpp model_flightmodes.cpp model_inputs.cpp diff --git a/radio/src/gui/colorlcd/LvglWrapper.cpp b/radio/src/gui/colorlcd/LvglWrapper.cpp index 0b3de24cd..adddc7c8f 100644 --- a/radio/src/gui/colorlcd/LvglWrapper.cpp +++ b/radio/src/gui/colorlcd/LvglWrapper.cpp @@ -51,8 +51,13 @@ TouchState getLastTochState() extern "C" void keyboardDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data) { // if there is a keyboard event then call checkevents - if (isEvent()) - MainWindow::instance()->checkEvents(); + if (isEvent()) { + event_t evt = getWindowEvent(); + auto focusWindow = Window::getFocus(); + if (focusWindow) { + focusWindow->onEvent(evt); + } + } } static void copy_ts_to_indev_data(const TouchState &st, lv_indev_data_t *data) diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 28f305f54..edfd7622e 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -23,30 +23,20 @@ #include "opentx.h" #include "libopenui.h" +#include "button_matrix.h" + #include "storage/modelslist.h" #include "trainer_setup.h" #include "module_setup.h" #include "timer_setup.h" +#include "trims_setup.h" +#include "throttle_params.h" +#include "preflight_checks.h" #include #define SET_DIRTY() storageDirty(EE_MODEL) -std::string switchWarninglabel(swsrc_t index) -{ - static const char *switchPositions[] = { - " ", - STR_CHAR_UP, - "-", - STR_CHAR_DOWN, - }; - - return TEXT_AT_INDEX(STR_VSRCRAW, - (index + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1)) + - std::string( - switchPositions[g_model.switchWarningState >> (3 * index) & 0x07]); -} - ModelSetupPage::ModelSetupPage() : PageTab(STR_MENU_MODEL_SETUP, ICON_MODEL_SETUP) { @@ -87,293 +77,133 @@ static void setModelBitmap(std::string newValue) } struct ModelBitmapEdit : public FileChoice { - ModelBitmapEdit(FormGroup *parent, const rect_t &rect) : + ModelBitmapEdit(Window *parent, const rect_t &rect) : FileChoice(parent, rect, BITMAPS_PATH, BITMAPS_EXT, sizeof(g_model.header.bitmap), getModelBitmap, setModelBitmap) { } }; +struct SubScreenButtonMatrix : public ButtonMatrix { + SubScreenButtonMatrix(Window* parent, const rect_t& rect); + void onPress(uint8_t btn_id) override; + bool isActive(uint8_t btn_id) override; +}; + +static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; + void ModelSetupPage::build(FormWindow * window) { - FormGridLayout grid; - grid.spacer(PAGE_PADDING); + window->setFlexLayout(); + FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); // Model name - new StaticText(window, grid.getLabelSlot(), STR_MODELNAME, 0, COLOR_THEME_PRIMARY1); - new ModelNameEdit(window, grid.getFieldSlot()); - grid.nextLine(); + auto line = window->newLine(&grid); + new StaticText(line, rect_t{}, STR_MODELNAME, 0, COLOR_THEME_PRIMARY1); + new ModelNameEdit(line, rect_t{}); // Bitmap - new StaticText(window, grid.getLabelSlot(), STR_BITMAP, 0, COLOR_THEME_PRIMARY1); - new ModelBitmapEdit(window, grid.getFieldSlot()); - grid.nextLine(); - - for (uint8_t i = 0; i < TIMERS; i++) - new TimerButton(window, grid.getSlot(3, i), i); - grid.nextLine(); + line = window->newLine(&grid); + new StaticText(line, rect_t{}, STR_BITMAP, 0, COLOR_THEME_PRIMARY1); + // TODO: show bitmap thumbnail instead? + new ModelBitmapEdit(line, rect_t{}); // Extended limits - new StaticText(window, grid.getLabelSlot(), STR_ELIMITS, 0, COLOR_THEME_PRIMARY1); - new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.extendedLimits)); - grid.nextLine(); - - // Extended trims - new StaticText(window, grid.getLabelSlot(), STR_ETRIMS, 0, COLOR_THEME_PRIMARY1); - new CheckBox(window, grid.getFieldSlot(2, 0), GET_SET_DEFAULT(g_model.extendedTrims)); - new TextButton(window, grid.getFieldSlot(2, 1), STR_RESET_BTN, - []() -> uint8_t { - for (auto &flightModeData : g_model.flightModeData) { - memclear(&flightModeData, TRIMS_ARRAY_SIZE); - } - SET_DIRTY(); - AUDIO_WARNING1(); - return 0; - }); - grid.nextLine(); - - // Display trims - new StaticText(window, grid.getLabelSlot(), STR_DISPLAY_TRIMS, 0, COLOR_THEME_PRIMARY1); - new Choice(window, grid.getFieldSlot(), "\006No\0 ChangeYes", 0, 2, GET_SET_DEFAULT(g_model.displayTrims)); - grid.nextLine(); - - // Trim step - new StaticText(window, grid.getLabelSlot(), STR_TRIMINC, 0, COLOR_THEME_PRIMARY1); - new Choice(window, grid.getFieldSlot(), STR_VTRIMINC, -2, 2, GET_SET_DEFAULT(g_model.trimInc)); - grid.nextLine(); - - // Throttle parameters - { - new Subtitle(window, grid.getLineSlot(), STR_THROTTLE_LABEL, 0, COLOR_THEME_PRIMARY1); - grid.nextLine(); - - // Throttle reversed - new StaticText(window, grid.getLabelSlot(true), STR_THROTTLEREVERSE, 0, COLOR_THEME_PRIMARY1); - new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.throttleReversed)); - grid.nextLine(); - - // Throttle source - new StaticText(window, grid.getLabelSlot(true), STR_TTRACE, 0, COLOR_THEME_PRIMARY1); - auto sc = new SourceChoice( - window, grid.getFieldSlot(), 0, MIXSRC_LAST_CH, - [=]() { return throttleSource2Source(g_model.thrTraceSrc); }, - [=](int16_t src) { - int16_t val = source2ThrottleSource(src); - if (val >= 0) { - g_model.thrTraceSrc = val; - SET_DIRTY(); - } - }, 0, COLOR_THEME_PRIMARY1); - sc->setAvailableHandler(isThrottleSourceAvailable); - grid.nextLine(); - - // Throttle trim - new StaticText(window, grid.getLabelSlot(true), STR_TTRIM, 0, COLOR_THEME_PRIMARY1); - new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.thrTrim)); - grid.nextLine(); - - // Throttle trim source - new StaticText(window, grid.getLabelSlot(true), STR_TTRIM_SW, 0, COLOR_THEME_PRIMARY1); - new SourceChoice( - window, grid.getFieldSlot(), MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM, - [=]() { return g_model.getThrottleStickTrimSource(); }, - [=](int16_t src) { g_model.setThrottleStickTrimSource(src); }, 0, COLOR_THEME_PRIMARY1); - grid.nextLine(); - } - - // Preflight parameters - { - new Subtitle(window, grid.getLineSlot(), STR_PREFLIGHT, 0, COLOR_THEME_PRIMARY1); - grid.nextLine(); - - // Display checklist - new StaticText(window, grid.getLabelSlot(true), STR_CHECKLIST, 0, COLOR_THEME_PRIMARY1); - new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.displayChecklist)); - grid.nextLine(); - - // Throttle warning - new StaticText(window, grid.getLabelSlot(true), STR_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1); - new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(g_model.disableThrottleWarning)); - grid.nextLine(); - - // Custom Throttle warning - new StaticText(window, grid.getLabelSlot(true), STR_CUSTOM_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1); - new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.enableCustomThrottleWarning)); - grid.nextLine(); - // Custom Throttle warning value - new StaticText(window, grid.getLabelSlot(true), STR_CUSTOM_THROTTLE_WARNING_VAL, 0, COLOR_THEME_PRIMARY1); - new NumberEdit(window, grid.getFieldSlot(), -100, 100, GET_SET_DEFAULT(g_model.customThrottleWarningPosition)); - grid.nextLine(); - - // Switches warning - new StaticText(window, grid.getLabelSlot(true), STR_SWITCHWARNING, 0, COLOR_THEME_PRIMARY1); - auto group = new FormGroup(window, grid.getFieldSlot(), FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST); - GridLayout switchesGrid(group); - for (int i = 0, j = 0; i < NUM_SWITCHES; i++) { - if (SWITCH_EXISTS(i)) { - if (j > 0 && (j % 3) == 0) - switchesGrid.nextLine(); - auto button = new TextButton(group, switchesGrid.getSlot(3, j % 3), switchWarninglabel(i), nullptr, - OPAQUE | (bfGet(g_model.switchWarningState, 3 * i, 3) == 0 ? 0 : BUTTON_CHECKED)); - button->setPressHandler([button, i] { - swarnstate_t newstate = bfGet(g_model.switchWarningState, 3 * i, 3); - if (newstate == 1 && SWITCH_CONFIG(i) != SWITCH_3POS) - newstate = 3; - else - newstate = (newstate + 1) % 4; - g_model.switchWarningState = bfSet(g_model.switchWarningState, newstate, 3 * i, 3); - SET_DIRTY(); - button->setText(switchWarninglabel(i)); - return newstate > 0; - }); - j++; - } - } - grid.addWindow(group); - - // Pots and sliders warning -#if NUM_POTS + NUM_SLIDERS - { - new StaticText(window, grid.getLabelSlot(true), STR_POTWARNINGSTATE, 0, COLOR_THEME_PRIMARY1); - new Choice(window, grid.getFieldSlot(), {"OFF", "ON", "AUTO"}, 0, 2, - GET_SET_DEFAULT(g_model.potsWarnMode)); - grid.nextLine(); - -#if (NUM_POTS) - { - new StaticText(window, grid.getLabelSlot(true), STR_POTWARNING, 0, COLOR_THEME_PRIMARY1); - auto group = - new FormGroup(window, grid.getFieldSlot(), - FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST); - GridLayout centerGrid(group); - for (int i = POT_FIRST, j = 0, k = 0; i <= POT_LAST; i++, k++) { - char s[8]; - if ((IS_POT(i) || IS_POT_MULTIPOS(i)) && IS_POT_AVAILABLE(i)) { - if (j > 0 && ((j % 4) == 0)) centerGrid.nextLine(); - - auto button = new TextButton( - group, centerGrid.getSlot(4, j % 4), - getStringAtIndex(s, STR_VSRCRAW, i + 1), nullptr, - OPAQUE | ((g_model.potsWarnEnabled & (1 << k)) ? BUTTON_CHECKED - : 0)); - button->setPressHandler([button, k] { - g_model.potsWarnEnabled ^= (1 << k); - if ((g_model.potsWarnMode == POTS_WARN_MANUAL) && - (g_model.potsWarnEnabled & (1 << k))) { - SAVE_POT_POSITION(k); - } - button->check(g_model.potsWarnEnabled & (1 << k) ? true : false); - SET_DIRTY(); - return (g_model.potsWarnEnabled & (1 << k) ? 1 : 0); - }); - j++; - } else { - g_model.potsWarnEnabled &= ~(1 << k); - } - } - grid.addWindow(group); - } -#endif - -#if (NUM_SLIDERS) - { - new StaticText(window, grid.getLabelSlot(true), STR_SLIDERWARNING, 0, COLOR_THEME_PRIMARY1); - auto group = - new FormGroup(window, grid.getFieldSlot(), - FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST); - GridLayout centerGrid(group); - for (int i = SLIDER_FIRST, j = 0, k = NUM_POTS; i <= SLIDER_LAST; i++, k++) { - char s[8]; - if ((IS_SLIDER(i))) { - if (j > 0 && ((j % 4) == 0)) centerGrid.nextLine(); - - auto *button = new TextButton( - group, centerGrid.getSlot(4, j % 4), - getStringAtIndex(s, STR_VSRCRAW, i + 1), nullptr, - OPAQUE | ((g_model.potsWarnEnabled & (1 << k)) ? BUTTON_CHECKED - : 0)); - button->setPressHandler([button, k] { - g_model.potsWarnEnabled ^= (1 << (k)); - if ((g_model.potsWarnMode == POTS_WARN_MANUAL) && - (g_model.potsWarnEnabled & (1 << k))) { - SAVE_POT_POSITION(k); - } - button->check(g_model.potsWarnEnabled & (1 << k) ? true : false); - SET_DIRTY(); - return (g_model.potsWarnEnabled & (1 << k) ? 1 : 0); - }); - j++; - } - } - grid.addWindow(group); - } -#endif - } - #endif - } - - grid.nextLine(); - - // Center beeps - { - new StaticText(window, grid.getLabelSlot(false), STR_BEEPCTR, 0, COLOR_THEME_PRIMARY1); - auto group = new FormGroup(window, grid.getFieldSlot(), FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST); - GridLayout centerGrid(group); - for (int i = 0, j = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) { - char s[2]; - if (i < NUM_STICKS || (IS_POT_SLIDER_AVAILABLE(i) && !IS_POT_MULTIPOS(i))) { // multipos cannot be centered - if (j > 0 && (j % 6) == 0) - centerGrid.nextLine(); - - new TextButton( - group, centerGrid.getSlot(6, j % 6), - getStringAtIndex(s, STR_RETA123, i), - [=]() -> uint8_t { - BFBIT_FLIP(g_model.beepANACenter, bfBit(i)); - SET_DIRTY(); - return (bfSingleBitGet(g_model.beepANACenter, i) ? 1 : 0); - }, - OPAQUE | (bfSingleBitGet(g_model.beepANACenter, i) - ? BUTTON_CHECKED - : 0)); - j++; - } - } - grid.addWindow(group); - } + // TODO: move to "Outputs" screen ? + line = window->newLine(&grid); + new StaticText(line, rect_t{}, STR_ELIMITS, 0, COLOR_THEME_PRIMARY1); + new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.extendedLimits)); // Global functions - new StaticText(window, grid.getLabelSlot(), STR_USE_GLOBAL_FUNCS, 0, COLOR_THEME_PRIMARY1); - new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(g_model.noGlobalFunctions)); - grid.nextLine(); + line = window->newLine(&grid); + new StaticText(line, rect_t{}, STR_USE_GLOBAL_FUNCS, 0, COLOR_THEME_PRIMARY1); + new CheckBox(line, rect_t{}, GET_SET_INVERTED(g_model.noGlobalFunctions)); - { - // Model ADC jitter filter - new StaticText(window, grid.getLabelSlot(), STR_JITTER_FILTER, 0, COLOR_THEME_PRIMARY1); - new Choice(window, grid.getFieldSlot(), STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.jitterFilter)); - grid.nextLine(); - } - - // Internal module - { - new Subtitle(window, grid.getLineSlot(), TR_INTERNALRF, 0, COLOR_THEME_PRIMARY1); - grid.nextLine(); - grid.addWindow(new ModuleWindow(window, {0, grid.getWindowHeight(), LCD_W, 0}, INTERNAL_MODULE)); - } - - // External module - { - new Subtitle(window, grid.getLineSlot(), TR_EXTERNALRF, 0, COLOR_THEME_PRIMARY1); - grid.nextLine(); - grid.addWindow(new ModuleWindow(window, {0, grid.getWindowHeight(), LCD_W, 0}, EXTERNAL_MODULE)); - } - - // Trainer - { - new Subtitle(window, grid.getLineSlot(), STR_TRAINER, 0, COLOR_THEME_PRIMARY1); - grid.nextLine(); - grid.addWindow(new TrainerModuleWindow(window, {0, grid.getWindowHeight(), LCD_W, 0})); - } + // Model ADC jitter filter + line = window->newLine(&grid); + new StaticText(line, rect_t{}, STR_JITTER_FILTER, 0, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_ADCFILTERVALUES, 0, 2, + GET_SET_DEFAULT(g_model.jitterFilter)); + // Sub-screens + new SubScreenButtonMatrix(window, rect_t{}); } +#define MAX_SUBSCREEN_BTNS 9 + +SubScreenButtonMatrix::SubScreenButtonMatrix(Window* parent, const rect_t& r) : + ButtonMatrix(parent, r) +{ + initBtnMap(3, MAX_SUBSCREEN_BTNS); + + setText(0, STR_INTERNALRF); + setText(1, STR_EXTERNALRF); + setText(2, STR_TRAINER); + + setText(3, STR_PREFLIGHT); + setText(4, STR_TRIMS); + setText(5, STR_THROTTLE_LABEL); + setText(6, TR_TIMER "1"); + setText(7, TR_TIMER "2"); + setText(8, TR_TIMER "3"); + update(); + + lv_btnmatrix_set_btn_width(lvobj, 3, 2); + lv_obj_set_width(lvobj, lv_pct(100)); + lv_obj_set_height(lvobj, (4 * LV_DPI_DEF) / 3); + + lv_obj_set_style_bg_opa(lvobj, LV_OPA_0, LV_PART_MAIN); + lv_obj_set_style_pad_all(lvobj, LV_DPI_DEF / 10, LV_PART_MAIN); + + lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_FOCUSED); + lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_EDITED); +} + +void SubScreenButtonMatrix::onPress(uint8_t btn_id) +{ + if (btn_id >= MAX_SUBSCREEN_BTNS) return; + + Window* w = nullptr; + switch (btn_id) { + case 0: + w = new ModulePage(INTERNAL_MODULE); + break; + case 1: + w = new ModulePage(EXTERNAL_MODULE); + break; + case 2: + w = new TrainerPage(); + break; + case 3: + w = new PreflightChecks(); + break; + case 4: + w = new TrimsSetup(); + break; + case 5: + w = new ThrottleParams(); + break; + default: + w = new TimerWindow((uint8_t)(btn_id - 6)); + break; + } + + if (w) w->setFocus(); +} + +bool SubScreenButtonMatrix::isActive(uint8_t btn_id) +{ + if (btn_id == 0) + return g_model.moduleData[INTERNAL_MODULE].type > 0; + + if (btn_id == 1) + return g_model.moduleData[EXTERNAL_MODULE].type > 0; + + if (btn_id == 2) + return g_model.trainerData.mode > 0; + + return false; +} diff --git a/radio/src/gui/colorlcd/module_setup.cpp b/radio/src/gui/colorlcd/module_setup.cpp index b1655d0d0..bddcd2785 100644 --- a/radio/src/gui/colorlcd/module_setup.cpp +++ b/radio/src/gui/colorlcd/module_setup.cpp @@ -22,6 +22,11 @@ #include "module_setup.h" #include "opentx.h" +#include "form.h" +#include "choice.h" +#include "button.h" +#include "gridlayout.h" + #include "mixer_scheduler.h" #include "multi_rfprotos.h" #include "io/multi_protolist.h" @@ -35,6 +40,29 @@ #define SET_DIRTY() storageDirty(EE_MODEL) +class ModuleWindow : public FormGroup +{ + public: + ModuleWindow(FormWindow *parent, const rect_t &rect, uint8_t moduleIdx); + + protected: + uint8_t moduleIdx; + bool hasFailsafe = false; + + Choice *moduleChoice = nullptr; + Choice *rfChoice = nullptr; + TextButton *bindButton = nullptr; + TextButton *rangeButton = nullptr; + TextButton *registerButton = nullptr; + Choice *failSafeChoice = nullptr; + + void addChannelRange(FormGridLayout &grid); + void startRSSIDialog(std::function closeHandler = nullptr); + + void update(); + void checkEvents() override; +}; + ModuleWindow::ModuleWindow(FormWindow *parent, const rect_t &rect, uint8_t moduleIdx) : FormGroup(parent, rect, FORWARD_SCROLL | NO_FOCUS | FORM_FORWARD_FOCUS), @@ -882,3 +910,16 @@ void ModuleWindow::checkEvents() FormGroup::checkEvents(); } + +ModulePage::ModulePage(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) +{ + const char* title = moduleIdx == INTERNAL_MODULE ? + STR_INTERNALRF : STR_EXTERNALRF; + + new StaticText(&header, + {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, + PAGE_LINE_HEIGHT}, + title, 0, COLOR_THEME_PRIMARY2); + + new ModuleWindow(&body, {0, 0, width(), 0}, moduleIdx); +} diff --git a/radio/src/gui/colorlcd/module_setup.h b/radio/src/gui/colorlcd/module_setup.h index 9bd095349..80e8b99ac 100644 --- a/radio/src/gui/colorlcd/module_setup.h +++ b/radio/src/gui/colorlcd/module_setup.h @@ -21,30 +21,8 @@ #pragma once -#include "form.h" -#include "choice.h" -#include "button.h" -#include "gridlayout.h" +#include "page.h" -class ModuleWindow : public FormGroup -{ - public: - ModuleWindow(FormWindow *parent, const rect_t &rect, uint8_t moduleIdx); - - protected: - uint8_t moduleIdx; - bool hasFailsafe = false; - - Choice *moduleChoice = nullptr; - Choice *rfChoice = nullptr; - TextButton *bindButton = nullptr; - TextButton *rangeButton = nullptr; - TextButton *registerButton = nullptr; - Choice *failSafeChoice = nullptr; - - void addChannelRange(FormGridLayout &grid); - void startRSSIDialog(std::function closeHandler = nullptr); - - void update(); - void checkEvents() override; +struct ModulePage : public Page { + ModulePage(uint8_t moduleIdx); }; diff --git a/radio/src/gui/colorlcd/page.cpp b/radio/src/gui/colorlcd/page.cpp index 6ecd88624..27b53aecb 100644 --- a/radio/src/gui/colorlcd/page.cpp +++ b/radio/src/gui/colorlcd/page.cpp @@ -67,6 +67,11 @@ void Page::deleteLater(bool detach, bool trash) Window::deleteLater(detach, trash); } +void Page::setFocus(uint8_t flag, Window * from) +{ + body.setFocus(flag, from); +} + void Page::paint(BitmapBuffer * dc) { dc->clear(COLOR_THEME_SECONDARY3); diff --git a/radio/src/gui/colorlcd/page.h b/radio/src/gui/colorlcd/page.h index e8a56398f..bee5469a3 100644 --- a/radio/src/gui/colorlcd/page.h +++ b/radio/src/gui/colorlcd/page.h @@ -114,6 +114,8 @@ class Page: public Window } #endif + void setFocus(uint8_t flag = SET_FOCUS_DEFAULT, Window * from = nullptr) override; + void paint(BitmapBuffer * dc) override; protected: diff --git a/radio/src/gui/colorlcd/preflight_checks.cpp b/radio/src/gui/colorlcd/preflight_checks.cpp new file mode 100644 index 000000000..8907b2be1 --- /dev/null +++ b/radio/src/gui/colorlcd/preflight_checks.cpp @@ -0,0 +1,343 @@ +/* + * 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 "preflight_checks.h" +#include "button_matrix.h" +#include "opentx.h" + +#define SET_DIRTY() storageDirty(EE_MODEL) + +static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; + +static void cb_changed(lv_event_t* e) +{ + auto target = lv_event_get_target(e); + auto obj = (lv_obj_t*)lv_event_get_user_data(e); + + if (lv_obj_has_state(target, LV_STATE_CHECKED)) { + lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); + } +} + +static void make_conditional(Window* w, CheckBox* cb) +{ + lv_obj_t* w_obj = w->getLvObj(); + if (!cb->getValue()) { lv_obj_add_flag(w_obj, LV_OBJ_FLAG_HIDDEN); } + + lv_obj_t* cb_obj = cb->getLvObj(); + lv_obj_add_event_cb(cb_obj, cb_changed, LV_EVENT_VALUE_CHANGED, w_obj); +} + +static void choice_changed(lv_event_t* e) +{ + auto target = lv_event_get_target(e); + auto choice = (Choice*)lv_obj_get_user_data(target); + auto obj = (lv_obj_t*)lv_event_get_user_data(e); + + if (choice->getIntValue() != 0) { + lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); + } +} + +static void make_conditional(Window* w, Choice* choice) +{ + lv_obj_t* w_obj = w->getLvObj(); + if (choice->getIntValue() == 0) { lv_obj_add_flag(w_obj, LV_OBJ_FLAG_HIDDEN); } + + lv_obj_t* choice_obj = choice->getLvObj(); + lv_obj_add_event_cb(choice_obj, choice_changed, LV_EVENT_VALUE_CHANGED, w_obj); +} + +struct SwitchWarnMatrix : public ButtonMatrix { + SwitchWarnMatrix(Window* parent, const rect_t& rect); + void onPress(uint8_t btn_id); + bool isActive(uint8_t btn_id); +}; + +struct PotWarnMatrix : public ButtonMatrix { + PotWarnMatrix(Window* parent, const rect_t& rect); + void onPress(uint8_t btn_id); + bool isActive(uint8_t btn_id); +}; + +PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP) +{ + new StaticText(&header, + {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, + PAGE_LINE_HEIGHT}, + STR_PREFLIGHT, 0, COLOR_THEME_PRIMARY2); + + auto form = new FormWindow(&body, rect_t{0, 0, body.width(), body.height()}, + NO_FOCUS | FORM_FORWARD_FOCUS); + form->setFlexLayout(); + FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); + + // Display checklist + auto line = form->newLine(&grid); + new StaticText(line, rect_t{}, STR_CHECKLIST, 0, COLOR_THEME_PRIMARY1); + new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.displayChecklist)); + + // Throttle warning + line = form->newLine(&grid); + new StaticText(line, rect_t{}, STR_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1); + auto tw = new CheckBox(line, rect_t{}, GET_SET_INVERTED(g_model.disableThrottleWarning)); + + // Custom Throttle warning (conditional on previous field) + line = form->newLine(&grid); + make_conditional(line, tw); + + new StaticText(line, rect_t{}, STR_CUSTOM_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1); + auto box = new FormGroup::Line(line, lv_obj_create(line->getLvObj()), nullptr, form); + lv_obj_set_layout(box->getLvObj(), LV_LAYOUT_FLEX); + + auto cst_tw = new CheckBox( + box, rect_t{}, GET_SET_DEFAULT(g_model.enableCustomThrottleWarning)); + + // Custom Throttle warning value + auto cst_val = + new NumberEdit(box, rect_t{}, -100, 100, + GET_SET_DEFAULT(g_model.customThrottleWarningPosition)); + make_conditional(cst_val, cst_tw); + + // Switch warnings (TODO: add display switch?) + new SwitchWarnMatrix(form, rect_t{}); + + // Pots and sliders warning +#if NUM_POTS + NUM_SLIDERS + line = form->newLine(&grid); + new StaticText(line, rect_t{}, STR_POTWARNINGSTATE, 0, COLOR_THEME_PRIMARY1); + auto pots_wm = new Choice(line, rect_t{}, {"OFF", "ON", "AUTO"}, 0, 2, + GET_SET_DEFAULT(g_model.potsWarnMode)); +#if (NUM_POTS) + // Pot warnings + auto pwm = new PotWarnMatrix(form, rect_t{}); + make_conditional(pwm, pots_wm); +#endif + +// #if (NUM_SLIDERS) +// { +// new StaticText(window, grid.getLabelSlot(true), STR_SLIDERWARNING, 0, +// COLOR_THEME_PRIMARY1); +// auto group = new FormGroup(window, grid.getFieldSlot(), +// FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST); +// GridLayout centerGrid(group); +// for (int i = SLIDER_FIRST, j = 0, k = NUM_POTS; i <= SLIDER_LAST; +// i++, k++) { +// char s[8]; +// if ((IS_SLIDER(i))) { +// if (j > 0 && ((j % 4) == 0)) centerGrid.nextLine(); + +// auto *button = new TextButton( +// group, centerGrid.getSlot(4, j % 4), +// getStringAtIndex(s, STR_VSRCRAW, i + 1), nullptr, +// OPAQUE | +// ((g_model.potsWarnEnabled & (1 << k)) ? BUTTON_CHECKED : 0)); +// button->setPressHandler([button, k] { +// g_model.potsWarnEnabled ^= (1 << (k)); +// if ((g_model.potsWarnMode == POTS_WARN_MANUAL) && +// (g_model.potsWarnEnabled & (1 << k))) { +// SAVE_POT_POSITION(k); +// } +// button->check(g_model.potsWarnEnabled & (1 << k) ? true : false); +// SET_DIRTY(); +// return (g_model.potsWarnEnabled & (1 << k) ? 1 : 0); +// }); +// j++; +// } +// } +// grid.addWindow(group); +// } +// #endif +// } +#endif + + // // Center beeps + // { + // new StaticText(window, grid.getLabelSlot(false), STR_BEEPCTR, 0, + // COLOR_THEME_PRIMARY1); + // auto group = new FormGroup(window, grid.getFieldSlot(), + // FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST); + // GridLayout centerGrid(group); + // for (int i = 0, j = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) { + // char s[2]; + // if (i < NUM_STICKS || + // (IS_POT_SLIDER_AVAILABLE(i) && + // !IS_POT_MULTIPOS(i))) { // multipos cannot be centered + // if (j > 0 && (j % 6) == 0) centerGrid.nextLine(); + + // new TextButton( + // group, centerGrid.getSlot(6, j % 6), + // getStringAtIndex(s, STR_RETA123, i), + // [=]() -> uint8_t { + // BFBIT_FLIP(g_model.beepANACenter, bfBit(i)); + // SET_DIRTY(); + // return (bfSingleBitGet(g_model.beepANACenter, i) + // ? 1 + // : 0); + // }, + // OPAQUE | (bfSingleBitGet(g_model.beepANACenter, i) + // ? BUTTON_CHECKED + // : 0)); + // j++; + // } + // } + // grid.addWindow(group); + // } +} + +// // Max 12 switches +// #define MAX_SW_WARN 12 + +// static const char* sw_warn_map[] = { +// "0", "1", "2", "3", "\n", +// "4", "5", "6", "7", "\n", +// "8", "9", "0", "1", "" +// }; +// static_assert(NUM_SWITCHES <= MAX_SW_WARN, "Max 12 switches supported"); + +static std::string switchWarninglabel(swsrc_t index) +{ + auto warn_pos = g_model.switchWarningState >> (3 * index) & 0x07; + return TEXT_AT_INDEX(STR_VSRCRAW, + (index + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1)) + + std::string(getSwitchWarnSymbol(warn_pos)); +} + +SwitchWarnMatrix::SwitchWarnMatrix(Window* parent, const rect_t& r) : + ButtonMatrix(parent, r) +{ + // Setup button layout & texts + uint8_t btn_cnt = 0; + for (uint8_t i = 0; i < NUM_SWITCHES; i++) + if (SWITCH_EXISTS(i)) btn_cnt++; + + initBtnMap(4, btn_cnt); + + for (uint8_t i = 0; i < NUM_SWITCHES; i++) { + if (SWITCH_EXISTS(i)) { + std::string txt = switchWarninglabel(i); + setText(i, txt.c_str()); + } + } + update(); + + lv_obj_set_width(lvobj, LV_DPI_DEF * 2); + + uint8_t rows = ((btn_cnt - 1) / 4) + 1; + lv_obj_set_height(lvobj, (rows * LV_DPI_DEF) / 3); + + lv_obj_set_style_bg_opa(lvobj, LV_OPA_0, LV_PART_MAIN); + + lv_obj_set_style_pad_all(lvobj, 4, LV_PART_MAIN); + lv_obj_set_style_pad_left(lvobj, LV_DPI_DEF / 10, 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); + + lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_FOCUSED); + lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_EDITED); +} + +void SwitchWarnMatrix::onPress(uint8_t btn_id) +{ + if (btn_id >= NUM_SWITCHES) return; + + swarnstate_t newstate = bfGet(g_model.switchWarningState, 3 * btn_id, 3); + if (newstate == 1 && SWITCH_CONFIG(btn_id) != SWITCH_3POS) + newstate = 3; + else + newstate = (newstate + 1) % 4; + + g_model.switchWarningState = + bfSet(g_model.switchWarningState, newstate, 3 * btn_id, 3); + SET_DIRTY(); + + // TODO: save state in object + std::string txt = switchWarninglabel(btn_id); + setText(btn_id, txt.c_str()); +} + +bool SwitchWarnMatrix::isActive(uint8_t btn_id) +{ + return bfGet(g_model.switchWarningState, 3 * btn_id, 3) != 0; +} + +PotWarnMatrix::PotWarnMatrix(Window* parent, const rect_t& r) : + ButtonMatrix(parent, r) +{ + // Setup button layout & texts + uint8_t btn_cnt = 0; + for (uint16_t i = POT_FIRST; i <= POT_LAST; i++) { + if ((IS_POT(i) || IS_POT_MULTIPOS(i)) && IS_POT_AVAILABLE(i)) btn_cnt++; + } + + initBtnMap(3, btn_cnt); + + uint8_t btn_id = 0; + for (uint16_t i = POT_FIRST; i <= POT_LAST; i++) { + if ((IS_POT(i) || IS_POT_MULTIPOS(i)) && IS_POT_AVAILABLE(i)) { + setText(btn_id, STR_VSRCRAW[btn_id + POT_FIRST + 1]); + btn_id++; + } + } + update(); + + lv_obj_set_width(lvobj, (LV_DPI_DEF * 3) / 2); + + uint8_t rows = ((btn_cnt - 1) / 4) + 1; + lv_obj_set_height(lvobj, (rows * LV_DPI_DEF) / 3); + + lv_obj_set_style_bg_opa(lvobj, LV_OPA_0, LV_PART_MAIN); + + lv_obj_set_style_pad_all(lvobj, 4, LV_PART_MAIN); + lv_obj_set_style_pad_left(lvobj, LV_DPI_DEF / 10, 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); + + lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_FOCUSED); + lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_EDITED); +} + +void PotWarnMatrix::onPress(uint8_t btn_id) +{ + if (btn_id >= NUM_POTS) return; + + g_model.potsWarnEnabled ^= (1 << btn_id); + if ((g_model.potsWarnMode == POTS_WARN_MANUAL) && + (g_model.potsWarnEnabled & (1 << btn_id))) { + SAVE_POT_POSITION(btn_id); + } + SET_DIRTY(); +} + +bool PotWarnMatrix::isActive(uint8_t btn_id) +{ + return (g_model.potsWarnEnabled & (1 << btn_id)) != 0; +} + diff --git a/radio/src/gui/colorlcd/preflight_checks.h b/radio/src/gui/colorlcd/preflight_checks.h new file mode 100644 index 000000000..cad6c7f25 --- /dev/null +++ b/radio/src/gui/colorlcd/preflight_checks.h @@ -0,0 +1,28 @@ +/* + * 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 "page.h" + +struct PreflightChecks : public Page { + PreflightChecks(); +}; diff --git a/radio/src/gui/colorlcd/throttle_params.cpp b/radio/src/gui/colorlcd/throttle_params.cpp new file mode 100644 index 000000000..657a7b772 --- /dev/null +++ b/radio/src/gui/colorlcd/throttle_params.cpp @@ -0,0 +1,91 @@ +/* + * 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 "throttle_params.h" +#include "opentx.h" + +#define SET_DIRTY() storageDirty(EE_MODEL) + +static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; + +static int16_t getThrottleSource() +{ + return throttleSource2Source(g_model.thrTraceSrc); +} + +static void setThrottleSource(int16_t src) +{ + int16_t val = source2ThrottleSource(src); + if (val >= 0) { + g_model.thrTraceSrc = val; + SET_DIRTY(); + } +} + +static int16_t getThrottleTrimSource() +{ + return g_model.getThrottleStickTrimSource(); +} + +static void setThrottleTrimSource(int16_t src) +{ + g_model.setThrottleStickTrimSource(src); +} + +ThrottleParams::ThrottleParams() : Page(ICON_MODEL_SETUP) +{ + new StaticText(&header, + {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, + PAGE_LINE_HEIGHT}, + STR_THROTTLE_LABEL, 0, COLOR_THEME_PRIMARY2); + + body.setFlexLayout(); + FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); + + // Throttle reversed + auto line = body.newLine(&grid); + new StaticText(line, rect_t{}, STR_THROTTLEREVERSE, 0, COLOR_THEME_PRIMARY1); + new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.throttleReversed)); + + // Throttle source + line = body.newLine(&grid); + new StaticText(line, rect_t{}, STR_TTRACE, 0, COLOR_THEME_PRIMARY1); + auto sc = new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_CH, + getThrottleSource, setThrottleSource, + 0, COLOR_THEME_PRIMARY1); + sc->setAvailableHandler(isThrottleSourceAvailable); + + // Throttle trim + line = body.newLine(&grid); + new StaticText(line, rect_t{}, STR_TTRIM, 0, COLOR_THEME_PRIMARY1); + new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.thrTrim)); + + // Throttle trim source + line = body.newLine(&grid); + new StaticText(line, rect_t{}, STR_TTRIM_SW, 0, COLOR_THEME_PRIMARY1); + new SourceChoice( + line, rect_t{}, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM, + getThrottleTrimSource, setThrottleTrimSource, 0, + COLOR_THEME_PRIMARY1); +} diff --git a/radio/src/gui/colorlcd/throttle_params.h b/radio/src/gui/colorlcd/throttle_params.h new file mode 100644 index 000000000..86997affc --- /dev/null +++ b/radio/src/gui/colorlcd/throttle_params.h @@ -0,0 +1,28 @@ +/* + * 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 "page.h" + +struct ThrottleParams : public Page { + ThrottleParams(); +}; diff --git a/radio/src/gui/colorlcd/timer_setup.cpp b/radio/src/gui/colorlcd/timer_setup.cpp index e4047596a..d21f7b85f 100644 --- a/radio/src/gui/colorlcd/timer_setup.cpp +++ b/radio/src/gui/colorlcd/timer_setup.cpp @@ -24,16 +24,6 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -TimerButton::TimerButton(Window* parent, const rect_t& rect, uint8_t timer) : - TextButton(parent, rect, std::string(STR_TIMER) + std::to_string(timer + 1)) -{ - // TODO: add start time - setPressHandler([=]() { - new TimerWindow(timer); - return false; - }); -} - // TODO: translation const char* STR_TIMER_MODES[] = {"OFF", "ON", "Start", "Throttle", "Throttle %", "Throttle Start"}; diff --git a/radio/src/gui/colorlcd/timer_setup.h b/radio/src/gui/colorlcd/timer_setup.h index 6b38ddeb9..28222f3d2 100644 --- a/radio/src/gui/colorlcd/timer_setup.h +++ b/radio/src/gui/colorlcd/timer_setup.h @@ -22,11 +22,6 @@ #pragma once #include "page.h" -#include "button.h" - -struct TimerButton : public TextButton { - TimerButton(Window* parent, const rect_t& rect, uint8_t timer); -}; struct TimerWindow : public Page { TimerWindow(uint8_t timer); diff --git a/radio/src/gui/colorlcd/trainer_setup.cpp b/radio/src/gui/colorlcd/trainer_setup.cpp index a0bab5f7e..6f044389f 100644 --- a/radio/src/gui/colorlcd/trainer_setup.cpp +++ b/radio/src/gui/colorlcd/trainer_setup.cpp @@ -24,6 +24,49 @@ #define SET_DIRTY() storageDirty(EE_MODEL) +#include "form.h" +#include "menu.h" +#include "static.h" +#include "button.h" +#include "numberedit.h" + +#if defined(BLUETOOTH) +#include "bluetooth.h" +#endif + +class TrChoice; + +class TrainerModuleWindow : public FormGroup +{ + public: + TrainerModuleWindow(FormWindow *parent, const rect_t &rect); + + void checkEvents() override; + void update(); + + protected: + TrChoice *trainerChoice = nullptr; + NumberEdit *channelStart = nullptr; + NumberEdit *channelEnd = nullptr; + bool trChoiceOpen = false; +#if defined(BLUETOOTH) + StaticText *btChannelEnd = nullptr; + StaticText *btDistAddress = nullptr; + TextButton *btMasterButton = nullptr; + Menu *btPopUpMenu = nullptr; + bool btCanceled = false; + + private: + bool popupopen = false; + int devicecount = 0; + uint8_t lastbluetoothstate = BLUETOOTH_STATE_OFF; + + void btDiscoverMenuItemChosen(); + void btDiscoverMenuAddItem(const char *itm); + +#endif +}; + class TrChoice : public Choice { public: @@ -283,3 +326,13 @@ void TrainerModuleWindow::btDiscoverMenuAddItem(const char *itm) itm, std::bind(&TrainerModuleWindow::btDiscoverMenuItemChosen, this)); } #endif + +TrainerPage::TrainerPage() : Page(ICON_MODEL_SETUP) +{ + new StaticText(&header, + {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, + PAGE_LINE_HEIGHT}, + STR_TRAINER, 0, COLOR_THEME_PRIMARY2); + + new TrainerModuleWindow(&body, {0, 0, width(), 0}); +} diff --git a/radio/src/gui/colorlcd/trainer_setup.h b/radio/src/gui/colorlcd/trainer_setup.h index 7f2ae1eb5..269588951 100644 --- a/radio/src/gui/colorlcd/trainer_setup.h +++ b/radio/src/gui/colorlcd/trainer_setup.h @@ -21,45 +21,8 @@ #pragma once -#include "form.h" -#include "menu.h" -#include "static.h" -#include "button.h" -#include "numberedit.h" +#include "page.h" -#if defined(BLUETOOTH) -#include "bluetooth.h" -#endif - -class TrChoice; - -class TrainerModuleWindow : public FormGroup -{ - public: - TrainerModuleWindow(FormWindow *parent, const rect_t &rect); - - void checkEvents() override; - void update(); - - protected: - TrChoice *trainerChoice = nullptr; - NumberEdit *channelStart = nullptr; - NumberEdit *channelEnd = nullptr; - bool trChoiceOpen = false; -#if defined(BLUETOOTH) - StaticText *btChannelEnd = nullptr; - StaticText *btDistAddress = nullptr; - TextButton *btMasterButton = nullptr; - Menu *btPopUpMenu = nullptr; - bool btCanceled = false; - - private: - bool popupopen = false; - int devicecount = 0; - uint8_t lastbluetoothstate = BLUETOOTH_STATE_OFF; - - void btDiscoverMenuItemChosen(); - void btDiscoverMenuAddItem(const char *itm); - -#endif +struct TrainerPage: public Page { + TrainerPage(); }; diff --git a/radio/src/gui/colorlcd/trims_setup.cpp b/radio/src/gui/colorlcd/trims_setup.cpp new file mode 100644 index 000000000..084e43024 --- /dev/null +++ b/radio/src/gui/colorlcd/trims_setup.cpp @@ -0,0 +1,74 @@ +/* + * 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 "trims_setup.h" +#include "opentx.h" + +#define SET_DIRTY() storageDirty(EE_MODEL) + +static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; + +static void resetTrims() +{ + for (auto &fm : g_model.flightModeData) memclear(&fm.trim, sizeof(fm.trim)); + SET_DIRTY(); + AUDIO_WARNING1(); +} + +TrimsSetup::TrimsSetup() : Page(ICON_MODEL_SETUP) +{ + new StaticText(&header, + {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, + PAGE_LINE_HEIGHT}, + STR_TRIMS, 0, COLOR_THEME_PRIMARY2); + + body.setFlexLayout(); + FlexGridLayout grid(line_col_dsc, line_row_dsc, 2); + + // Trim step + auto line = body.newLine(&grid); + new StaticText(line, rect_t{}, STR_TRIMINC, 0, + COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_VTRIMINC, -2, 2, + GET_SET_DEFAULT(g_model.trimInc)); + + // Extended trims + line = body.newLine(&grid); + new StaticText(line, rect_t{}, STR_ETRIMS, 0, COLOR_THEME_PRIMARY1); + new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.extendedTrims)); + + // Reset trims + line = body.newLine(&grid); + new TextButton(line, rect_t{}, STR_RESET_BTN, []() -> uint8_t { + resetTrims(); + return 0; + }); + + // Display trims + // TODO: move to "Screen setup" ? + line = body.newLine(&grid); + new StaticText(line, rect_t{}, STR_DISPLAY_TRIMS, 0, COLOR_THEME_PRIMARY1); + new Choice(line, rect_t{}, STR_VDISPLAYTRIMS, 0, 2, + GET_SET_DEFAULT(g_model.displayTrims)); +} diff --git a/radio/src/gui/colorlcd/trims_setup.h b/radio/src/gui/colorlcd/trims_setup.h new file mode 100644 index 000000000..d5845d3a9 --- /dev/null +++ b/radio/src/gui/colorlcd/trims_setup.h @@ -0,0 +1,28 @@ +/* + * 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 "page.h" + +struct TrimsSetup : public Page { + TrimsSetup(); +}; diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 3f32252d8..3e37d2688 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -1001,7 +1001,7 @@ const char* STR_SUBTYPE_HUBSAN[] = {"H107","H301","H501"}; const char* STR_SUBTYPE_FRSKY[] = {"D16","D8","D16 8ch","V8","LBT(EU)","LBT 8ch","D8Cloned","D16Cloned"}; const char* STR_SUBTYPE_HISKY[] = {"Std","HK310"}; const char* STR_SUBTYPE_V2X2[] = {"Std","JXD506","MR101"}; -const char* STR_SUBTYPE_DSM[] = {"2 1F","2 2F","X 1F,""X 2F,""Auto","R 1F"}; +const char* STR_SUBTYPE_DSM[] = {"2 1F","2 2F","X 1F","X 2F","Auto","R 1F"}; const char* STR_SUBTYPE_DEVO[] = {"8ch","10ch","12ch","6ch","7ch"}; const char* STR_SUBTYPE_YD717[] = {"Std","SkyWlkr","Syma X4","XINXUN","NIHUI"}; const char* STR_SUBTYPE_KN[] = {"WLtoys","FeiLun"}; diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index a877a5ff4..5bd6a5dda 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit a877a5ff4bad39752e7b0fbaa804e3ed522860ef +Subproject commit 5bd6a5ddac7ef5e5a11bfb3de81ec7bc5cc13608