diff --git a/radio/src/boards/generic_stm32/linker/stm32f429_sdram/layout.ld b/radio/src/boards/generic_stm32/linker/stm32f429_sdram/layout.ld index 1f83dbe3bb1..b36039941b3 100644 --- a/radio/src/boards/generic_stm32/linker/stm32f429_sdram/layout.ld +++ b/radio/src/boards/generic_stm32/linker/stm32f429_sdram/layout.ld @@ -9,7 +9,7 @@ MAIN_STACK_SIZE = 8192; BOOTLOADER_SIZE = 0x20000; /* Minimum Heap Size (indicative) */ -MIN_HEAP_SIZE = 4096K; +MIN_HEAP_SIZE = 0; /* SDRAM definitions */ SDRAM_START = DEFINED(__sdram_start) ? __sdram_start : 0xD0000000; diff --git a/radio/src/gui/colorlcd/LvglWrapper.cpp b/radio/src/gui/colorlcd/LvglWrapper.cpp index 293eed71465..ea5a41ec520 100644 --- a/radio/src/gui/colorlcd/LvglWrapper.cpp +++ b/radio/src/gui/colorlcd/LvglWrapper.cpp @@ -331,13 +331,19 @@ static void init_lvgl_drivers() void initLvglTheme() { + static lv_theme_t theme; + /* Initialize the ETX theme */ - lv_theme_t* th = etx_lv_theme_init( - NULL, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), - LV_FONT_DEFAULT); + theme.disp = NULL; + theme.color_primary = lv_palette_main(LV_PALETTE_BLUE); + theme.color_secondary = lv_palette_main(LV_PALETTE_RED); + theme.font_small = LV_FONT_DEFAULT; + theme.font_normal = LV_FONT_DEFAULT; + theme.font_large = LV_FONT_DEFAULT; + theme.flags = 0; /* Assign the theme to the current display*/ - lv_disp_set_theme(NULL, th); + lv_disp_set_theme(NULL, &theme); } LvglWrapper::LvglWrapper() diff --git a/radio/src/gui/colorlcd/access_settings.cpp b/radio/src/gui/colorlcd/access_settings.cpp index 05356b3f01b..03fa10d4bc2 100644 --- a/radio/src/gui/colorlcd/access_settings.cpp +++ b/radio/src/gui/colorlcd/access_settings.cpp @@ -370,7 +370,6 @@ RegisterDialog::RegisterDialog(Window* parent, uint8_t moduleIdx) : 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 diff --git a/radio/src/gui/colorlcd/channel_bar.cpp b/radio/src/gui/colorlcd/channel_bar.cpp index aa7c986a6a6..8ce12dfc8c2 100644 --- a/radio/src/gui/colorlcd/channel_bar.cpp +++ b/radio/src/gui/colorlcd/channel_bar.cpp @@ -41,11 +41,13 @@ ChannelBar::ChannelBar(Window* parent, const rect_t& rect, lv_obj_set_pos(bar, width() / 2, 0); lv_obj_set_size(bar, 0, height()); + coord_t yo = (height() < 10) ? -1 : VAL_YO; + valText = lv_label_create(lvobj); - lv_obj_set_pos(valText, width() / 2 + 5, -2); - lv_obj_set_size(valText, 45, 12); + lv_obj_set_pos(valText, width() / 2 + VAL_XO, yo); + lv_obj_set_size(valText, VAL_W, VAL_H); etx_obj_add_style(valText, styles->text_align_left, LV_PART_MAIN); - lv_obj_set_style_translate_x(valText, -54, LV_STATE_USER_1); + lv_obj_set_style_translate_x(valText, VAL_XT, 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)); @@ -70,8 +72,6 @@ void ChannelBar::checkEvents() if (value != newValue) { value = newValue; - lv_obj_enable_style_refresh(false); - lv_label_set_text_fmt(valText, "%d%%", value); if (newValue < 0) @@ -89,9 +89,6 @@ void ChannelBar::checkEvents() 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); } } @@ -216,31 +213,31 @@ ComboChannelBar::ComboChannelBar(Window* parent, const rect_t& rect, isInHeader ? COLOR_THEME_PRIMARY2 : COLOR_THEME_SECONDARY1; outputChannelBar = new OutputChannelBar( - this, {LMARGIN, BAR_HEIGHT + TMARGIN, width() - LMARGIN, BAR_HEIGHT}, + this, {ChannelBar::LMARGIN, ChannelBar::BAR_HEIGHT + ChannelBar::TMARGIN, width() - ChannelBar::LMARGIN, ChannelBar::BAR_HEIGHT}, channel, isInHeader); new MixerChannelBar( this, - {LMARGIN, (2 * BAR_HEIGHT) + TMARGIN + 1, width() - LMARGIN, BAR_HEIGHT}, + {ChannelBar::LMARGIN, (2 * ChannelBar::BAR_HEIGHT) + ChannelBar::TMARGIN + 1, width() - ChannelBar::LMARGIN, ChannelBar::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, + new StaticText(this, {ChannelBar::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, + new StaticText(this, {ChannelBar::LMARGIN + ChannelBar::VAL_W, 0, LV_SIZE_CONTENT, ChannelBar::VAL_H}, nm, textColor | FONT(XS) | LEFT); } // Channel value in µS new DynamicNumber( - this, {width() - 45, 0, 45, 12}, + this, {width() - ChannelBar::VAL_W, 0, ChannelBar::VAL_W, ChannelBar::VAL_H}, [=] { return PPM_CH_CENTER(channel) + channelOutputs[channel] / 2; }, textColor | FONT(XS) | RIGHT, "", STR_US); @@ -254,7 +251,7 @@ ComboChannelBar::ComboChannelBar(Window* parent, const rect_t& rect, // Channel reverted icon LimitData* ld = limitAddress(channel); if (ld && ld->revert) { - new StaticIcon(this, 0, 25, ICON_CHAN_MONITOR_INVERTED, + new StaticIcon(this, 0, ICON_SZ, ICON_CHAN_MONITOR_INVERTED, textColor); } } diff --git a/radio/src/gui/colorlcd/channel_bar.h b/radio/src/gui/colorlcd/channel_bar.h index cf399c7c3f0..5713dcd4148 100644 --- a/radio/src/gui/colorlcd/channel_bar.h +++ b/radio/src/gui/colorlcd/channel_bar.h @@ -23,11 +23,6 @@ #include "opentx.h" -constexpr coord_t ROW_HEIGHT = 42; -constexpr coord_t BAR_HEIGHT = 13; -constexpr coord_t LMARGIN = 15; -constexpr coord_t TMARGIN = 2; - class ChannelBar : public Window { public: @@ -35,6 +30,16 @@ class ChannelBar : public Window std::function getValue, LcdFlags barColor, LcdFlags textColor = COLOR_THEME_SECONDARY1); + static LAYOUT_VAL(BAR_HEIGHT, 13, 13) + static LAYOUT_VAL(LMARGIN, 15, 15) + static LAYOUT_VAL(TMARGIN, 2, 2) + + static LAYOUT_VAL(VAL_W, 45, 45) + static LAYOUT_VAL(VAL_H, 12, 12) + static LAYOUT_VAL(VAL_XO, 5, 5) + static LAYOUT_VAL(VAL_YO, -2, -2) + static LAYOUT_VAL(VAL_XT, -54, -54) + protected: int16_t value = -10000; std::function getValue; @@ -78,6 +83,8 @@ class ComboChannelBar : public Window ComboChannelBar(Window* parent, const rect_t& rect, uint8_t channel, bool isInHeader = false); + static LAYOUT_VAL(ICON_SZ, 25, 25) + protected: uint8_t channel; OutputChannelBar* outputChannelBar = nullptr; diff --git a/radio/src/gui/colorlcd/color_editor.cpp b/radio/src/gui/colorlcd/color_editor.cpp index aef0a018538..0757abfe55a 100644 --- a/radio/src/gui/colorlcd/color_editor.cpp +++ b/radio/src/gui/colorlcd/color_editor.cpp @@ -23,11 +23,6 @@ #include "button.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"}; @@ -170,12 +165,12 @@ class ColorBar : public Window // 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; + cursor_area.x1 = area->x1 + (lv_area_get_width(area) / 2) - ColorEditor::CRSR_SZ / 2; + cursor_area.x2 = cursor_area.x1 + ColorEditor::CRSR_SZ - 1; auto pos = bar->valueToScreen(bar->value); - cursor_area.y1 = area->y1 + pos - 3; - cursor_area.y2 = cursor_area.y1 + 10 - 1; + cursor_area.y1 = area->y1 + pos - ColorEditor::CRSR_YO; + cursor_area.y2 = cursor_area.y1 + ColorEditor::CRSR_SZ - 1; lv_draw_rect_dsc_t cursor_dsc; lv_draw_rect_dsc_init(&cursor_dsc); @@ -274,12 +269,12 @@ BarColorType::BarColorType(Window* parent) int leftPos = 0; rect_t r; - r.y = BAR_TOP_MARGIN; - r.w = spacePerBar - BAR_MARGIN - 5; - r.h = parent->height() - BAR_HEIGHT_OFFSET; + r.y = ColorEditor::BAR_TOP_MARGIN; + r.w = spacePerBar - ColorEditor::BAR_MARGIN - 5; + r.h = parent->height() - (ColorEditor::BAR_TOP_MARGIN + ColorEditor::BAR_HEIGHT_OFFSET); for (int i = 0; i < MAX_BARS; i++) { - r.x = leftPos + BAR_MARGIN; + r.x = leftPos + ColorEditor::BAR_MARGIN; bars[i] = new ColorBar(parent, r); leftPos += spacePerBar; @@ -289,8 +284,8 @@ BarColorType::BarColorType(Window* parent) auto x = bar->left(); auto y = bar->bottom(); - barLabels[i] = create_bar_label(parent->getLvObj(), x, y + 9); - barValLabels[i] = create_bar_value_label(parent->getLvObj(), x + 10, y + 3); + barLabels[i] = create_bar_label(parent->getLvObj(), x, y + ColorEditor::LBL_YO); + barValLabels[i] = create_bar_value_label(parent->getLvObj(), x + ColorEditor::VAL_XO, y + ColorEditor::VAL_YO); } } diff --git a/radio/src/gui/colorlcd/color_editor.h b/radio/src/gui/colorlcd/color_editor.h index 2c3f0e7d866..854ec897a72 100644 --- a/radio/src/gui/colorlcd/color_editor.h +++ b/radio/src/gui/colorlcd/color_editor.h @@ -45,6 +45,15 @@ class ColorEditor : public Window void setColorEditorType(COLOR_EDITOR_TYPE colorType); + static LAYOUT_VAL(BAR_MARGIN, 5, 5) + static LAYOUT_VAL(BAR_TOP_MARGIN, 5, 5) + static LAYOUT_VAL(BAR_HEIGHT_OFFSET, 25, 25) + static LAYOUT_VAL(LBL_YO, 9, 9) + static LAYOUT_VAL(VAL_XO, 10, 10) + static LAYOUT_VAL(VAL_YO, 3, 3) + static LAYOUT_VAL(CRSR_SZ, 10, 10) + static LAYOUT_VAL(CRSR_YO, 3, 3) + protected: ColorType* _colorType = nullptr; std::function _setValue; diff --git a/radio/src/gui/colorlcd/color_picker.cpp b/radio/src/gui/colorlcd/color_picker.cpp index 7f2c9348f76..97e27c94608 100644 --- a/radio/src/gui/colorlcd/color_picker.cpp +++ b/radio/src/gui/colorlcd/color_picker.cpp @@ -25,26 +25,18 @@ #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 = 32; - -#if LCD_W > LCD_H +#if !PORTRAIT_LCD // 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 BaseDialog @@ -74,7 +66,7 @@ class ColorEditorPopup : public BaseDialog FlexGridLayout grid(col_dsc, row_dsc); auto line = form->newLine(grid); - rect_t r{0, 0, 7 * LV_DPI_DEF / 5, 7 * LV_DPI_DEF / 5}; + rect_t r{0, 0, CE_SZ, CE_SZ}; 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, @@ -94,7 +86,7 @@ class ColorEditorPopup : public BaseDialog colorPad = new ColorSwatch(hbox, {0, 0, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT}, COLOR_THEME_PRIMARY1); - hexStr = new StaticText(hbox, {0, 0, 100, 0}, "", COLOR_THEME_PRIMARY1 | FONT(L)); + hexStr = new StaticText(hbox, {0, 0, CVAL_W, 0}, "", COLOR_THEME_PRIMARY1 | FONT(L)); updateColor(color); @@ -135,29 +127,38 @@ class ColorEditorPopup : public BaseDialog hsvBtn->check(true); hbox = new Window(vbox, rect_t{}); - hbox->padTop(60); - hbox->setFlexLayout(LV_FLEX_FLOW_ROW, 20); + hbox->padTop(BTN_PAD_TOP); + hbox->setFlexLayout(LV_FLEX_FLOW_ROW, BTN_PAD_ROW); 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); - new TextButton(hbox, rect_t{0, 0, 80, 0}, STR_CANCEL, [=]() -> int8_t { + new TextButton(hbox, rect_t{0, 0, BTN_W, 0}, STR_CANCEL, [=]() -> int8_t { this->deleteLater(); return 0; }); - new TextButton(hbox, rect_t{0, 0, 80, 0}, STR_SAVE, [=]() -> int8_t { + new TextButton(hbox, rect_t{0, 0, BTN_W, 0}, STR_SAVE, [=]() -> int8_t { if (_setValue) _setValue(m_color); this->deleteLater(); return 0; }); } + + static LAYOUT_VAL(CE_SZ, 182, 182) + static LAYOUT_VAL(COLOR_EDIT_WIDTH, LCD_W * 0.8, LCD_W * 0.7) + static LAYOUT_VAL(COLOR_PAD_WIDTH, 52, 52) + static LAYOUT_VAL(COLOR_PAD_HEIGHT, 32, 32) + static LAYOUT_VAL(CVAL_W, 100, 100) + static LAYOUT_VAL(BTN_W, 80, 80) + static LAYOUT_VAL(BTN_PAD_TOP, 60, 60) + static LAYOUT_VAL(BTN_PAD_ROW, 20, 20) }; ColorPicker::ColorPicker(Window* parent, const rect_t& rect, std::function getValue, std::function setValue) : - Button(parent, {0, 0, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT}), + Button(parent, {0, 0, ColorEditorPopup::COLOR_PAD_WIDTH, ColorEditorPopup::COLOR_PAD_HEIGHT}), setValue(std::move(setValue)) { updateColor(getValue()); diff --git a/radio/src/gui/colorlcd/curve_param.cpp b/radio/src/gui/colorlcd/curve_param.cpp index eaa45e9f9ff..340f415c889 100644 --- a/radio/src/gui/colorlcd/curve_param.cpp +++ b/radio/src/gui/colorlcd/curve_param.cpp @@ -67,7 +67,7 @@ CurveParam::CurveParam(Window* parent, const rect_t& rect, CurveRef* ref, // CURVE_REF_DIFF // CURVE_REF_EXPO - value_edit = new GVarNumberEdit(this, rect_t{}, -100, 100, GET_DEFAULT(ref->value), setRefValue); + value_edit = new GVarNumberEdit(this, -100, 100, GET_DEFAULT(ref->value), setRefValue); value_edit->setSuffix("%"); // CURVE_REF_FUNC diff --git a/radio/src/gui/colorlcd/curveedit.cpp b/radio/src/gui/colorlcd/curveedit.cpp index 939e957a09f..4300d2b353a 100644 --- a/radio/src/gui/colorlcd/curveedit.cpp +++ b/radio/src/gui/colorlcd/curveedit.cpp @@ -39,7 +39,7 @@ CurveDataEdit::CurveDataEdit(Window* parent, const rect_t& rect, etx_scrollbar(lvobj); } -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define NUM_BTN_WIDTH 44 #else #define NUM_BTN_WIDTH 48 @@ -277,7 +277,7 @@ void CurveEditWindow::buildBody(Window* window) lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN); -#if LCD_H > LCD_W // portrait +#if PORTRAIT_LCD lv_obj_set_flex_flow(line->getLvObj(), LV_FLEX_FLOW_COLUMN); coord_t curveWidth = window->width() - 88; coord_t boxWidth = window->width(); @@ -310,7 +310,7 @@ void CurveEditWindow::buildBody(Window* window) // Name new StaticText(iLine, rect_t{}, STR_NAME); - new ModelTextEdit(iLine, rect_t{0, 0, 100, 0}, curve.name, + new ModelTextEdit(iLine, rect_t{}, curve.name, sizeof(curve.name)); // Smooth diff --git a/radio/src/gui/colorlcd/custom_failsafe.cpp b/radio/src/gui/colorlcd/custom_failsafe.cpp index 10531899621..cbf0db9b7ec 100644 --- a/radio/src/gui/colorlcd/custom_failsafe.cpp +++ b/radio/src/gui/colorlcd/custom_failsafe.cpp @@ -36,12 +36,12 @@ class ChannelFailsafeBargraph : public Window 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}, + outputsBar = new OutputChannelBar(this, {0, 1, width() - 2, ChannelBar::BAR_HEIGHT}, channel, false, false); outputsBar->hide(); failsafeBar = new ChannelBar( - this, {0, BAR_HEIGHT + 3, width() - 2, BAR_HEIGHT}, + this, {0, ChannelBar::BAR_HEIGHT + 3, width() - 2, ChannelBar::BAR_HEIGHT}, [=] { return calcRESXto100(g_model.failsafeChannels[channel]); }, COLOR_THEME_WARNING, COLOR_THEME_WARNING); failsafeBar->hide(); @@ -187,7 +187,7 @@ static void set_failsafe(lv_event_t* e) if (combo) combo->update(); } -#if LCD_H > LCD_W +#if PORTRAIT_LCD #define FS_BARGRAPH_WIDTH (LV_DPI_DEF / 2) #else #define FS_BARGRAPH_WIDTH (LV_DPI_DEF) diff --git a/radio/src/gui/colorlcd/file_carosell.cpp b/radio/src/gui/colorlcd/file_carosell.cpp index 595060a7841..c493c2c5e62 100644 --- a/radio/src/gui/colorlcd/file_carosell.cpp +++ b/radio/src/gui/colorlcd/file_carosell.cpp @@ -35,7 +35,7 @@ FileCarosell::FileCarosell(Window *parent, const rect_t &rect, { setWindowFlag(NO_FOCUS); - message = new StaticText(this, {0, rect.h/2, rect.w, PAGE_LINE_HEIGHT}, "", CENTERED | FONT(L) | COLOR_THEME_PRIMARY1); + message = new StaticText(this, {0, rect.h/2, rect.w, EdgeTxStyles::PAGE_LINE_HEIGHT}, "", CENTERED | FONT(L) | COLOR_THEME_PRIMARY1); setFileNames(fileNames); } diff --git a/radio/src/gui/colorlcd/fm_matrix.cpp b/radio/src/gui/colorlcd/fm_matrix.cpp index baf12173444..bcd712a50dc 100644 --- a/radio/src/gui/colorlcd/fm_matrix.cpp +++ b/radio/src/gui/colorlcd/fm_matrix.cpp @@ -24,15 +24,19 @@ #include "opentx.h" #include "themes/etx_lv_theme.h" +#if PORTRAIT_LCD +#define FM_COLS 3 +#define FM_ROWS 3 +#else +#define FM_COLS 5 +#define FM_ROWS 2 +#endif + template FMMatrix::FMMatrix(Window* parent, const rect_t& r, T* input) : ButtonMatrix(parent, r), input(input) { -#if LCD_W > LCD_H - initBtnMap(5, MAX_FLIGHT_MODES); -#else - initBtnMap(3, MAX_FLIGHT_MODES); -#endif + initBtnMap(FM_COLS, MAX_FLIGHT_MODES); for (int i = 0; i < MAX_FLIGHT_MODES; i++) { setTextAndState(i); @@ -40,13 +44,8 @@ FMMatrix::FMMatrix(Window* parent, const rect_t& r, T* input) : update(); -#if LCD_W > LCD_H - lv_obj_set_width(lvobj, 258); - lv_obj_set_height(lvobj, 73); -#else - lv_obj_set_width(lvobj, 156); - lv_obj_set_height(lvobj, 108); -#endif + lv_obj_set_width(lvobj, FM_COLS * (FM_BTN_W + 3) + 3); + lv_obj_set_height(lvobj, FM_ROWS * (EdgeTxStyles::UI_ELEMENT_HEIGHT + 3) +3); padAll(PAD_SMALL); } diff --git a/radio/src/gui/colorlcd/fm_matrix.h b/radio/src/gui/colorlcd/fm_matrix.h index 382b532c91d..df41727343c 100644 --- a/radio/src/gui/colorlcd/fm_matrix.h +++ b/radio/src/gui/colorlcd/fm_matrix.h @@ -33,6 +33,8 @@ struct FMMatrix : public ButtonMatrix { void onPress(uint8_t btn_id); bool isActive(uint8_t btn_id); void setTextAndState(uint8_t btn_id); + + static LAYOUT_VAL(FM_BTN_W, 48, 48) }; extern template struct FMMatrix; diff --git a/radio/src/gui/colorlcd/fullscreen_dialog.cpp b/radio/src/gui/colorlcd/fullscreen_dialog.cpp index 3421a0bf558..e501bad6fba 100644 --- a/radio/src/gui/colorlcd/fullscreen_dialog.cpp +++ b/radio/src/gui/colorlcd/fullscreen_dialog.cpp @@ -30,7 +30,7 @@ #include "view_main.h" #include "hal/watchdog_driver.h" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD 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; diff --git a/radio/src/gui/colorlcd/gvar_numberedit.cpp b/radio/src/gui/colorlcd/gvar_numberedit.cpp index 40332147be8..61e7dd4316a 100644 --- a/radio/src/gui/colorlcd/gvar_numberedit.cpp +++ b/radio/src/gui/colorlcd/gvar_numberedit.cpp @@ -31,11 +31,11 @@ void GVarNumberEdit::value_changed(lv_event_t* e) edit->update(); } -GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin, +GVarNumberEdit::GVarNumberEdit(Window* parent, int32_t vmin, int32_t vmax, std::function getValue, std::function setValue, LcdFlags textFlags, int32_t voffset, int32_t vdefault) : - Window(parent, rect), + Window(parent, {0, 0, NUM_EDIT_W + GV_BTN_W + PAD_TINY * 3, EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_TINY * 2}), vmin(vmin), vmax(vmax), getValue(getValue), @@ -44,13 +44,10 @@ GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin, voffset(voffset) { padAll(PAD_TINY); - lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW_WRAP); - lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0); - lv_obj_set_size(lvobj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); // GVAR field gvar_field = new Choice( - this, rect_t{}, -MAX_GVARS, MAX_GVARS - 1, + this, {0, 0, NUM_EDIT_W, 0}, -MAX_GVARS, MAX_GVARS - 1, [=]() { uint16_t gvar1 = GV_GET_GV1_VALUE(vmin, vmax); return GV_INDEX_CALC_DELTA(getValue(), gvar1); @@ -64,19 +61,17 @@ GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin, }); gvar_field->setTextHandler( [=](int32_t value) { return getGVarString(value); }); - gvar_field->setWidth(70); num_field = new NumberEdit( - this, rect_t{}, vmin, vmax, [=]() { return getValue() + voffset; }, + this, {0, 0, NUM_EDIT_W, 0}, vmin, vmax, [=]() { return getValue() + voffset; }, nullptr); num_field->setTextFlag(textFlags); - num_field->setWidth(70); num_field->setDefault(vdefault); #if defined(GVARS) // The GVAR button if (modelGVEnabled()) { - m_gvBtn = new TextButton(this, rect_t{}, STR_GV, [=]() { + m_gvBtn = new TextButton(this, {NUM_EDIT_W + PAD_TINY, 0, GV_BTN_W, 0}, STR_GV, [=]() { switchGVarMode(); return GV_IS_GV_VALUE(getValue(), vmin, vmax); }); diff --git a/radio/src/gui/colorlcd/gvar_numberedit.h b/radio/src/gui/colorlcd/gvar_numberedit.h index 7253965d409..79a6a8f2aed 100644 --- a/radio/src/gui/colorlcd/gvar_numberedit.h +++ b/radio/src/gui/colorlcd/gvar_numberedit.h @@ -26,14 +26,12 @@ #include "numberedit.h" #include "gvars.h" -constexpr coord_t GVAR_BUTTON_WIDTH = 30; - class TextButton; class GVarNumberEdit : public Window { public: - GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin, int32_t vmax, + GVarNumberEdit(Window* parent, int32_t vmin, int32_t vmax, std::function getValue, std::function setValue, LcdFlags textFlags = 0, int32_t voffset = 0, int32_t vdefault = 0); @@ -43,7 +41,10 @@ class GVarNumberEdit : public Window void setFastStep(int value) { num_field->setFastStep(value); } void setAccelFactor(int value) { num_field->setAccelFactor(value); } - + + static LAYOUT_VAL(NUM_EDIT_W, 70, 70) + static LAYOUT_VAL(GV_BTN_W, 40, 40) + protected: Choice* gvar_field = nullptr; NumberEdit* num_field = nullptr; diff --git a/radio/src/gui/colorlcd/hw_bluetooth.cpp b/radio/src/gui/colorlcd/hw_bluetooth.cpp index 2434c81fbe7..721b9e0d3d4 100644 --- a/radio/src/gui/colorlcd/hw_bluetooth.cpp +++ b/radio/src/gui/colorlcd/hw_bluetooth.cpp @@ -78,7 +78,7 @@ BluetoothConfigWindow::BluetoothConfigWindow(Window* parent, FlexGridLayout& gri 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( + new Choice( box, rect_t{}, STR_BLUETOOTH_MODES, BLUETOOTH_OFF, BLUETOOTH_TRAINER, GET_DEFAULT(g_eeGeneral.bluetoothMode), [=](int value) { g_eeGeneral.bluetoothMode = value; diff --git a/radio/src/gui/colorlcd/hw_inputs.cpp b/radio/src/gui/colorlcd/hw_inputs.cpp index 18d6c9d71d7..fa875b8a30f 100644 --- a/radio/src/gui/colorlcd/hw_inputs.cpp +++ b/radio/src/gui/colorlcd/hw_inputs.cpp @@ -32,9 +32,12 @@ struct HWInputEdit : public RadioTextEdit { 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) + RadioTextEdit(parent, rect_t{x, y, HW_INP_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, name, + len) { } + + static LAYOUT_VAL(HW_INP_W, 64, 64) }; static const lv_coord_t col_two_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), @@ -42,7 +45,7 @@ static const lv_coord_t col_two_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), 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 +#if !PORTRAIT_LCD 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}; @@ -77,30 +80,6 @@ HWSticks::HWSticks(Window* parent) : Window(parent, rect_t{}) #endif } -// 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}) { @@ -122,15 +101,17 @@ HWPots::HWPots(Window* parent) : // #if !defined(SIMU) && defined(RADIO_FAMILY_T16) // if (!globalData.flyskygimbals && (i >= (NUM_POTS - 2))) continue; // #endif - new StaticText(this, rect_t{P_LBL_X, P_Y(i) + 6, P_LBL_W, 32}, + new StaticText(this, + rect_t{P_LBL_X, P_Y(i) + 6, P_LBL_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, adcGetInputLabel(ADC_INPUT_FLEX, i)); new HWInputEdit(this, (char*)analogGetCustomLabel(ADC_INPUT_FLEX, i), LEN_ANA_NAME, P_NM_X, P_Y(i)); auto pot = new Choice( - 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); }, + this, rect_t{P_TYP_X, P_Y(i) + P_OFST_Y, P_TYP_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, + STR_POTTYPES, FLEX_NONE, FLEX_SWITCH, + [=]() -> int { return getPotType(i); }, [=](int newValue) { setPotType(i, newValue); switchFixFlexConfig(); @@ -140,7 +121,7 @@ HWPots::HWPots(Window* parent) : pot->setAvailableHandler([=](int val) { return isPotTypeAvailable(val); }); new ToggleSwitch( - this, rect_t{P_INV_X, P_Y(i) + P_OFST_Y, P_INV_W, 32}, + this, rect_t{P_INV_X, P_Y(i) + P_OFST_Y, P_INV_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, [=]() -> uint8_t { return (uint8_t)getPotInversion(i); }, [=](int8_t newValue) { setPotInversion(i, newValue); @@ -149,19 +130,11 @@ HWPots::HWPots(Window* parent) : } } -// 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, coord_t x, coord_t y) : - StaticText(parent, rect_t{x, y, SW_CTRL_W, 32}, ""), + StaticText(parent, rect_t{x, y, HWSwitches::SW_CTRL_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, ""), index(index) { checkEvents(); @@ -219,15 +192,15 @@ HWSwitches::HWSwitches(Window* parent) : { auto max_switches = switchGetMaxSwitches(); for (int i = 0; i < max_switches; i++) { - new SwitchDynamicLabel(this, i, 2, i * 36 + 2); + new SwitchDynamicLabel(this, i, 2, i * SW_CTRL_H + 2); new HWInputEdit(this, (char*)switchGetCustomName(i), LEN_SWITCH_NAME, - SW_CTRL_W + 8, i * 36 + 2); + SW_CTRL_W + 8, i * SW_CTRL_H + 2); coord_t x = SW_CTRL_W * 2 + 14; Choice* channel = nullptr; if (switchIsFlex(i)) { channel = new Choice( - this, rect_t{x, i * 36 + 2, SW_CTRL_W, 32}, -1, + this, rect_t{x, i * SW_CTRL_H + 2, SW_CTRL_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, -1, adcGetMaxInputs(ADC_INPUT_FLEX) - 1, [=]() -> int { return switchGetFlexConfig(i); }, [=](int newValue) { switchConfigFlex(i, newValue); }); @@ -242,8 +215,9 @@ HWSwitches::HWSwitches(Window* parent) : } auto sw_cfg = new Choice( - this, rect_t{x, i * 36 + 2, SW_CTRL_W, 32}, STR_SWTYPES, SWITCH_NONE, - switchGetMaxType(i), [=]() -> int { return SWITCH_CONFIG(i); }, + this, rect_t{x, i * SW_CTRL_H + 2, SW_CTRL_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, + 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 = diff --git a/radio/src/gui/colorlcd/hw_inputs.h b/radio/src/gui/colorlcd/hw_inputs.h index 7695bff2857..ed26f14f1fe 100644 --- a/radio/src/gui/colorlcd/hw_inputs.h +++ b/radio/src/gui/colorlcd/hw_inputs.h @@ -32,22 +32,32 @@ struct HWSticks : public Window { struct HWPots : public Window { HWPots(Window* parent); bool potsChanged; + + // Absolute layout for Pots popup - due to performance issues with lv_textarea + // in a flex layout + static LAYOUT_VAL(P_LBL_X, 0, 0) + static LAYOUT_VAL(P_LBL_W, (DIALOG_DEFAULT_WIDTH - 45) * 2 / 11, (DIALOG_DEFAULT_WIDTH - 18) * 13 / 21) + static constexpr coord_t P_NM_X = P_LBL_X + P_LBL_W + PAD_MEDIUM; + static LAYOUT_VAL(P_NM_W, 70, 70) + static LAYOUT_VAL(P_TYP_X, P_NM_X + P_NM_W, 0) + static LAYOUT_VAL(P_TYP_W, 160, P_LBL_W) + static constexpr coord_t P_INV_X = P_TYP_X + P_TYP_W + PAD_MEDIUM; + static LAYOUT_VAL(P_INV_W, 52, 52) + static LAYOUT_VAL(P_ROW_H, 36, 72) + static LAYOUT_VAL(P_OFST_Y, 0, 36) + #define P_Y(i) (i * P_ROW_H + 2) }; struct HWSwitches : public Window { HWSwitches(Window* parent); + + // Absolute layout for Switches popup - due to performance issues with + // lv_textarea in a flex layout + static LAYOUT_VAL(SW_CTRL_W, 86, 75) + static LAYOUT_VAL(SW_CTRL_H, 36, 36) }; template struct HWInputDialog : public BaseDialog { HWInputDialog(const char* title = nullptr); }; - -template -TextButton* makeHWInputButton(Window* parent, const char* 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_serial.cpp b/radio/src/gui/colorlcd/hw_serial.cpp index a24c5570742..bcab1fe3214 100644 --- a/radio/src/gui/colorlcd/hw_serial.cpp +++ b/radio/src/gui/colorlcd/hw_serial.cpp @@ -63,8 +63,8 @@ SerialConfigWindow::SerialConfigWindow(Window *parent, FlexGridLayout& grid) if (port_nr != SP_VCP) { grid.setColSpan(2); auto line = parent->newLine(grid); - line->padLeft(20); - line->padBottom(6); + line->padLeft(WARN_PADL); + line->padBottom(WARN_PADB); new StaticText(line, rect_t{}, STR_TTL_WARNING, COLOR_THEME_WARNING); grid.setColSpan(1); } diff --git a/radio/src/gui/colorlcd/hw_serial.h b/radio/src/gui/colorlcd/hw_serial.h index e29dd772cdf..26d5d64d6a1 100644 --- a/radio/src/gui/colorlcd/hw_serial.h +++ b/radio/src/gui/colorlcd/hw_serial.h @@ -27,4 +27,7 @@ class SerialConfigWindow { public: SerialConfigWindow(Window *parent, FlexGridLayout& grid); + + static LAYOUT_VAL(WARN_PADL, 20, 20); + static LAYOUT_VAL(WARN_PADB, 6, 6); }; diff --git a/radio/src/gui/colorlcd/input_edit.cpp b/radio/src/gui/colorlcd/input_edit.cpp index c50fa302965..c407b4202aa 100644 --- a/radio/src/gui/colorlcd/input_edit.cpp +++ b/radio/src/gui/colorlcd/input_edit.cpp @@ -32,14 +32,6 @@ #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) { @@ -48,7 +40,7 @@ InputEditWindow::InputEditWindow(int8_t input, uint8_t index) : header->setTitle2(title2); auto body_obj = body->getLvObj(); -#if LCD_H > LCD_W // portrait +#if PORTRAIT_LCD // portrait lv_obj_set_flex_flow(body_obj, LV_FLEX_FLOW_COLUMN); #else // landscape lv_obj_set_flex_flow(body_obj, LV_FLEX_FLOW_ROW); @@ -60,10 +52,10 @@ InputEditWindow::InputEditWindow(int8_t input, uint8_t index) : lv_obj_set_flex_grow(box_obj, 2); etx_scrollbar(box_obj); -#if LCD_H > LCD_W // portrait - box->setWidth(body->width() - 2 * lv_dpx(8)); +#if PORTRAIT_LCD // portrait + box->setWidth(body->width() - 2 * PAD_MEDIUM); #else // landscape - box->setHeight(body->height() - 2 * lv_dpx(8)); + box->setHeight(body->height() - 2 * PAD_MEDIUM); #endif auto form = new Window(box, rect_t{}); @@ -89,7 +81,7 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; void InputEditWindow::buildBody(Window* form) { FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); - form->setFlexLayout(); + form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); ExpoData* input = expoAddress(index); @@ -114,7 +106,7 @@ void InputEditWindow::buildBody(Window* form) line = form->newLine(grid); new StaticText(line, rect_t{}, STR_WEIGHT); auto gvar = - new GVarNumberEdit(line, rect_t{}, -100, 100, GET_DEFAULT(input->weight), + new GVarNumberEdit(line, -100, 100, GET_DEFAULT(input->weight), [=](int32_t newValue) { input->weight = newValue; preview->update(); @@ -125,7 +117,7 @@ void InputEditWindow::buildBody(Window* form) // Offset line = form->newLine(grid); new StaticText(line, rect_t{}, STR_OFFSET); - gvar = new GVarNumberEdit(line, rect_t{}, -100, 100, + gvar = new GVarNumberEdit(line, -100, 100, GET_DEFAULT(input->offset), [=](int32_t newValue) { input->offset = newValue; preview->update(); diff --git a/radio/src/gui/colorlcd/input_edit.h b/radio/src/gui/colorlcd/input_edit.h index b6d4654dd38..8af4e588a19 100644 --- a/radio/src/gui/colorlcd/input_edit.h +++ b/radio/src/gui/colorlcd/input_edit.h @@ -32,6 +32,9 @@ class InputEditWindow : public Page public: InputEditWindow(int8_t input, uint8_t index); + static LAYOUT_VAL(INPUT_EDIT_CURVE_WIDTH, 140, 176) + static LAYOUT_VAL(INPUT_EDIT_CURVE_HEIGHT, INPUT_EDIT_CURVE_WIDTH, 132) + protected: uint8_t input; uint8_t index; diff --git a/radio/src/gui/colorlcd/layout.h b/radio/src/gui/colorlcd/layout.h index 9c72ff148c3..51e72a1086e 100644 --- a/radio/src/gui/colorlcd/layout.h +++ b/radio/src/gui/colorlcd/layout.h @@ -28,9 +28,7 @@ #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 #if !defined(YAML_GENERATOR) @@ -81,6 +79,12 @@ class LayoutFactory WidgetsContainer* createCustomScreen(unsigned customScreenIndex) const; + static LAYOUT_VAL(TRIM_LINE_WIDTH, 8, 8) + static LAYOUT_VAL(TRIM_SQUARE_SIZE, 17, 17) + + static LAYOUT_VAL(BM_W, 51, 22) + static LAYOUT_VAL(BM_H, 25, 34) + protected: const char* id; const char* name; diff --git a/radio/src/gui/colorlcd/layouts/layout_factory_impl.h b/radio/src/gui/colorlcd/layouts/layout_factory_impl.h index 6a955c58dad..e7b03f7e0dc 100644 --- a/radio/src/gui/colorlcd/layouts/layout_factory_impl.h +++ b/radio/src/gui/colorlcd/layouts/layout_factory_impl.h @@ -111,6 +111,8 @@ class Layout: public LayoutBase bool isAppMode() { return decorationSettings == DECORATION_NONE && zoneCount == 1; } + static LAYOUT_VAL(MAIN_ZONE_BORDER, 10, 10) + protected: const LayoutFactory * factory = nullptr; std::unique_ptr decoration; @@ -140,14 +142,6 @@ class Layout: public LayoutBase rect_t getZone(unsigned int index) const override; }; -#if LCD_W > LCD_H -#define BM_W 51 -#define BM_H 25 -#else -#define BM_W 22 -#define BM_H 34 -#endif - template class BaseLayoutFactory: public LayoutFactory { diff --git a/radio/src/gui/colorlcd/layouts/sliders.cpp b/radio/src/gui/colorlcd/layouts/sliders.cpp index 0963f0593e6..d0534910449 100644 --- a/radio/src/gui/colorlcd/layouts/sliders.cpp +++ b/radio/src/gui/colorlcd/layouts/sliders.cpp @@ -49,19 +49,19 @@ static const lv_style_const_prop_t shadow2_props[] = { static LV_STYLE_CONST_MULTI_INIT(shadow2_style, shadow2_props); SliderIcon::SliderIcon(Window* parent) : - Window(parent, rect_t{0, 0, 17, 17}) + Window(parent, rect_t{0, 0, MainViewSlider::SL_SZ + 2, MainViewSlider::SL_SZ + 2}) { setWindowFlag(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); + lv_obj_set_size(shad, MainViewSlider::SL_SZ, MainViewSlider::SL_SZ); 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); + lv_obj_set_size(fill, MainViewSlider::SL_SZ, MainViewSlider::SL_SZ); etx_solid_bg(fill, COLOR_THEME_FOCUS_INDEX); } @@ -70,17 +70,17 @@ MainViewSlider::MainViewSlider(Window* parent, const rect_t& rect, uint8_t idx, Window(parent, rect), idx(idx), isVertical(isVertical) { if (isVertical) { - int sliderTicksCount = (height() - TRIM_SQUARE_SIZE) / SLIDER_TICK_SPACING; + int sliderTicksCount = (height() - LayoutFactory::TRIM_SQUARE_SIZE) / SLIDER_TICK_SPACING; tickPoints = new lv_point_t[(sliderTicksCount + 1) * 2]; - lv_coord_t y = TRIM_SQUARE_SIZE / 2; + lv_coord_t y = LayoutFactory::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}; + tickPoints[i * 2] = {SL_TK, y}; + tickPoints[i * 2 + 1] = {SL_SZ, y}; } else { - tickPoints[i * 2] = {4, y}; - tickPoints[i * 2 + 1] = {13, y}; + tickPoints[i * 2] = {SL_TK + 2, y}; + tickPoints[i * 2 + 1] = {SL_SZ - 2, y}; } auto line = lv_line_create(lvobj); etx_obj_add_style(line, styles->div_line, LV_PART_MAIN); @@ -88,17 +88,17 @@ MainViewSlider::MainViewSlider(Window* parent, const rect_t& rect, uint8_t idx, y += SLIDER_TICK_SPACING; } } else { - int sliderTicksCount = (width() - TRIM_SQUARE_SIZE) / SLIDER_TICK_SPACING; + int sliderTicksCount = (width() - LayoutFactory::TRIM_SQUARE_SIZE) / SLIDER_TICK_SPACING; tickPoints = new lv_point_t[(sliderTicksCount + 1) * 2]; - lv_coord_t x = TRIM_SQUARE_SIZE / 2; + lv_coord_t x = LayoutFactory::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}; + tickPoints[i * 2] = {x, SL_TK}; + tickPoints[i * 2 + 1] = {x, SL_SZ}; } else { - tickPoints[i * 2] = {x, 4}; - tickPoints[i * 2 + 1] = {x, 13}; + tickPoints[i * 2] = {x, SL_TK + 2}; + tickPoints[i * 2 + 1] = {x, SL_SZ - 2}; } auto line = lv_line_create(lvobj); etx_obj_add_style(line, styles->div_line, LV_PART_MAIN); @@ -110,9 +110,9 @@ MainViewSlider::MainViewSlider(Window* parent, const rect_t& rect, uint8_t idx, sliderIcon = new SliderIcon(this); coord_t x = 0, y = 0; if (isVertical) - y = (height() - TRIM_SQUARE_SIZE) / 2; + y = (height() - LayoutFactory::TRIM_SQUARE_SIZE) / 2; else - y = (width() - TRIM_SQUARE_SIZE) / 2; + y = (width() - LayoutFactory::TRIM_SQUARE_SIZE) / 2; lv_obj_set_pos(sliderIcon->getLvObj(), x, y); checkEvents(); @@ -137,10 +137,10 @@ void MainViewSlider::checkEvents() coord_t x = 0, y = 0; if (isVertical) { - y = divRoundClosest((height() - TRIM_SQUARE_SIZE) * (-value + RESX), + y = divRoundClosest((height() - LayoutFactory::TRIM_SQUARE_SIZE) * (-value + RESX), 2 * RESX); } else { - x = divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value + RESX), + x = divRoundClosest((width() - LayoutFactory::TRIM_SQUARE_SIZE) * (value + RESX), 2 * RESX); } lv_obj_set_pos(sliderIcon->getLvObj(), x, y); @@ -150,7 +150,7 @@ void MainViewSlider::checkEvents() MainViewHorizontalSlider::MainViewHorizontalSlider(Window* parent, uint8_t idx) : MainViewSlider(parent, - rect_t{0, 0, HORIZONTAL_SLIDERS_WIDTH, TRIM_SQUARE_SIZE}, + rect_t{0, 0, HORIZONTAL_SLIDERS_WIDTH, LayoutFactory::TRIM_SQUARE_SIZE}, idx, false) { } @@ -162,20 +162,16 @@ MainViewVerticalSlider::MainViewVerticalSlider(Window* parent, { } -constexpr coord_t MULTIPOS_H = 18; -constexpr coord_t MULTIPOS_W_SPACING = 12; -constexpr coord_t MULTIPOS_W = (6 + 1) * MULTIPOS_W_SPACING; - MainView6POS::MainView6POS(Window* parent, uint8_t idx) : Window(parent, rect_t{0, 0, MULTIPOS_W, MULTIPOS_H}), idx(idx) { char num[] = " "; - coord_t x = MULTIPOS_W_SPACING / 4 + TRIM_SQUARE_SIZE / 4; + coord_t x = MULTIPOS_W_SPACING / 4 + LayoutFactory::TRIM_SQUARE_SIZE / 4; for (uint8_t value = 0; value < XPOTS_MULTIPOS_COUNT; value++) { 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_size(p, MULTIPOS_SZ, MULTIPOS_SZ); 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); @@ -184,8 +180,8 @@ MainView6POS::MainView6POS(Window* parent, uint8_t idx) : posIcon = new SliderIcon(this); posVal = lv_label_create(posIcon->getLvObj()); - lv_obj_set_pos(posVal, 3, -2); - lv_obj_set_size(posVal, 12, 12); + lv_obj_set_pos(posVal, MULTIPOS_XO, -2); + lv_obj_set_size(posVal, MULTIPOS_SZ, MULTIPOS_SZ); etx_txt_color(posVal, COLOR_THEME_PRIMARY2_INDEX, LV_PART_MAIN); etx_font(posVal, FONT_BOLD_INDEX, LV_PART_MAIN); diff --git a/radio/src/gui/colorlcd/layouts/sliders.h b/radio/src/gui/colorlcd/layouts/sliders.h index b09054a596e..2a063832813 100644 --- a/radio/src/gui/colorlcd/layouts/sliders.h +++ b/radio/src/gui/colorlcd/layouts/sliders.h @@ -23,17 +23,6 @@ #include "libopenui.h" -#if LCD_H > LCD_W -constexpr uint8_t SLIDER_TICKS_COUNT = 30; -#else -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; - class SliderIcon : public Window { public: @@ -50,6 +39,16 @@ class MainViewSlider : public Window bool isVertical); void checkEvents() override; + static LAYOUT_VAL(SLIDER_TICKS_COUNT, 40, 30) + static LAYOUT_VAL(SLIDER_TICK_SPACING, 4, 4) + static constexpr coord_t HORIZONTAL_SLIDERS_WIDTH = + SLIDER_TICKS_COUNT * SLIDER_TICK_SPACING + LayoutFactory::TRIM_SQUARE_SIZE; + static constexpr coord_t VERTICAL_SLIDERS_HEIGHT = + SLIDER_TICKS_COUNT * SLIDER_TICK_SPACING + LayoutFactory::TRIM_SQUARE_SIZE; + + static LAYOUT_VAL(SL_SZ, 15, 15) + static LAYOUT_VAL(SL_TK, 2, 2) + protected: uint8_t idx; int16_t value = -10000; @@ -79,6 +78,12 @@ class MainView6POS : public Window void checkEvents() override; + static LAYOUT_VAL(MULTIPOS_H, 18, 18) + static LAYOUT_VAL(MULTIPOS_W_SPACING, 12, 12) + static LAYOUT_VAL(MULTIPOS_SZ, 12, 12) + static LAYOUT_VAL(MULTIPOS_XO, 3, 3) + static constexpr coord_t MULTIPOS_W = (6 + 1) * MULTIPOS_W_SPACING; + protected: uint8_t idx; int16_t value = -10000; diff --git a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp index eff77dc1a44..46afc2a5c48 100644 --- a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp +++ b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp @@ -41,7 +41,7 @@ class TopBarEdgeTx : public HeaderIcon }; TopBar::TopBar(Window * parent) : - TopBarBase(parent, {0, 0, LCD_W, MENU_HEADER_HEIGHT}, &g_model.topbarData) + TopBarBase(parent, {0, 0, LCD_W, EdgeTxStyles::MENU_HEADER_HEIGHT}, &g_model.topbarData) { etx_solid_bg(lvobj, COLOR_THEME_SECONDARY1_INDEX); @@ -55,15 +55,15 @@ unsigned int TopBar::getZonesCount() const rect_t TopBar::getZone(unsigned int index) const { -#if LCD_H > LCD_W +#if PORTRAIT_LCD if (index == MAX_TOPBAR_ZONES - 1) { - coord_t size = LCD_W - 48 - (MAX_TOPBAR_ZONES - 1) * (TOPBAR_ZONE_WIDTH + TOPBAR_ZONE_HMARGIN); + coord_t size = LCD_W - HDR_DATE_XO - (MAX_TOPBAR_ZONES - 1) * (TOPBAR_ZONE_WIDTH + TOPBAR_ZONE_HMARGIN); return {LCD_W - size, TOPBAR_ZONE_VMARGIN, size, TOPBAR_ZONE_HEIGHT}; } #endif return { - coord_t(48 + (TOPBAR_ZONE_WIDTH + TOPBAR_ZONE_HMARGIN) * index), + coord_t(MENU_HEADER_BUTTONS_LEFT + 1 + (TOPBAR_ZONE_WIDTH + TOPBAR_ZONE_HMARGIN) * index), TOPBAR_ZONE_VMARGIN, TOPBAR_ZONE_WIDTH, TOPBAR_ZONE_HEIGHT @@ -73,13 +73,13 @@ rect_t TopBar::getZone(unsigned int index) const void TopBar::setVisible(float visible) // 0.0 -> 1.0 { if (visible == 0.0) { - setTop(-(int)MENU_HEADER_HEIGHT); + setTop(-(int)EdgeTxStyles::MENU_HEADER_HEIGHT); } else if (visible == 1.0) { setTop(0); } else if (visible > 0.0 && visible < 1.0){ - float top = - (float)MENU_HEADER_HEIGHT * (1.0 - visible); + float top = - (float)EdgeTxStyles::MENU_HEADER_HEIGHT * (1.0 - visible); setTop((coord_t)top); } } @@ -90,10 +90,10 @@ coord_t TopBar::getVisibleHeight(float visible) const // 0.0 -> 1.0 return 0; } else if (visible == 1.0) { - return MENU_HEADER_HEIGHT; + return EdgeTxStyles::MENU_HEADER_HEIGHT; } - float h = (float)MENU_HEADER_HEIGHT * visible; + float h = (float)EdgeTxStyles::MENU_HEADER_HEIGHT * visible; return (coord_t)h; } diff --git a/radio/src/gui/colorlcd/layouts/topbar_impl.h b/radio/src/gui/colorlcd/layouts/topbar_impl.h index 8eafc2913c4..004f70b8fb6 100644 --- a/radio/src/gui/colorlcd/layouts/topbar_impl.h +++ b/radio/src/gui/colorlcd/layouts/topbar_impl.h @@ -60,6 +60,14 @@ class TopBar: public TopBarBase void removeWidget(unsigned int index) override; + static LAYOUT_VAL(TOPBAR_ZONE_WIDTH, 70, 70) + static LAYOUT_VAL(TOPBAR_ZONE_VMARGIN, 3, 3) + static LAYOUT_VAL(TOPBAR_ZONE_HMARGIN, 2, 2) + static constexpr coord_t TOPBAR_ZONE_HEIGHT = EdgeTxStyles::MENU_HEADER_HEIGHT - 2 * TOPBAR_ZONE_VMARGIN; + + static LAYOUT_VAL(HDR_DATE_XO, 48, 48) + static LAYOUT_VAL(MENU_HEADER_BUTTONS_LEFT, 47, 47) + 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 618b667c6d8..9a65158d7d6 100644 --- a/radio/src/gui/colorlcd/layouts/trims.cpp +++ b/radio/src/gui/colorlcd/layouts/trims.cpp @@ -87,27 +87,27 @@ MainViewTrim::MainViewTrim(Window* parent, const rect_t& rect, uint8_t idx, 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); + lv_obj_set_pos(trimBar, (LayoutFactory::TRIM_SQUARE_SIZE - LayoutFactory::TRIM_LINE_WIDTH) / 2, + LayoutFactory::TRIM_SQUARE_SIZE / 2); + lv_obj_set_size(trimBar, LayoutFactory::TRIM_LINE_WIDTH, + MainViewSlider::VERTICAL_SLIDERS_HEIGHT - LayoutFactory::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); + lv_obj_set_pos(trimBar, LayoutFactory::TRIM_SQUARE_SIZE / 2, + (LayoutFactory::TRIM_SQUARE_SIZE - LayoutFactory::TRIM_LINE_WIDTH - 1) / 2); + lv_obj_set_size(trimBar, MainViewSlider::HORIZONTAL_SLIDERS_WIDTH - LayoutFactory::TRIM_SQUARE_SIZE + 1, + LayoutFactory::TRIM_LINE_WIDTH); } trimIcon = new TrimIcon(this, isVertical); coord_t x = 0, y = 0; if (isVertical) - y = (height() - TRIM_SQUARE_SIZE) / 2; + y = (height() - LayoutFactory::TRIM_SQUARE_SIZE) / 2; else - y = (width() - TRIM_SQUARE_SIZE) / 2; + y = (width() - LayoutFactory::TRIM_SQUARE_SIZE) / 2; lv_obj_set_pos(trimIcon->getLvObj(), x, y); trimValue = new DynamicNumber( - this, {0, 0, TRIM_SQUARE_SIZE, 12}, + this, {0, 0, LayoutFactory::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); @@ -141,13 +141,13 @@ void MainViewTrim::setPos() if (value) { if (isVertical) { x = 0; - y = (value > 0) ? VERTICAL_SLIDERS_HEIGHT * 4 / 5 - : VERTICAL_SLIDERS_HEIGHT / 5 - 11; + y = (value > 0) ? MainViewSlider::VERTICAL_SLIDERS_HEIGHT * 4 / 5 + : MainViewSlider::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; + x = ((value < 0) ? MainViewSlider::HORIZONTAL_SLIDERS_WIDTH * 4 / 5 + : MainViewSlider::HORIZONTAL_SLIDERS_WIDTH / 5) - + LayoutFactory::TRIM_SQUARE_SIZE / 2; + y = (LayoutFactory::TRIM_SQUARE_SIZE - 12) / 2; } lv_obj_set_pos(trimValue->getLvObj(), x, y); trimValue->show(); @@ -208,7 +208,7 @@ coord_t MainViewTrim::sx() if (isVertical) return 0; return divRoundClosest( - (HORIZONTAL_SLIDERS_WIDTH - TRIM_SQUARE_SIZE) * (value - trimMin), + (MainViewSlider::HORIZONTAL_SLIDERS_WIDTH - LayoutFactory::TRIM_SQUARE_SIZE) * (value - trimMin), trimMax - trimMin); } @@ -217,20 +217,20 @@ coord_t MainViewTrim::sy() if (!isVertical) return 0; return divRoundClosest( - (VERTICAL_SLIDERS_HEIGHT - TRIM_SQUARE_SIZE) * (trimMax - value), + (MainViewSlider::VERTICAL_SLIDERS_HEIGHT - LayoutFactory::TRIM_SQUARE_SIZE) * (trimMax - value), trimMax - trimMin); } MainViewHorizontalTrim::MainViewHorizontalTrim(Window* parent, uint8_t idx) : MainViewTrim(parent, - rect_t{0, 0, HORIZONTAL_SLIDERS_WIDTH, TRIM_SQUARE_SIZE}, idx, + rect_t{0, 0, MainViewSlider::HORIZONTAL_SLIDERS_WIDTH, LayoutFactory::TRIM_SQUARE_SIZE}, idx, false) { } MainViewVerticalTrim::MainViewVerticalTrim(Window* parent, uint8_t idx) : MainViewTrim(parent, - rect_t{0, 0, TRIM_SQUARE_SIZE, VERTICAL_SLIDERS_HEIGHT}, idx, + rect_t{0, 0, LayoutFactory::TRIM_SQUARE_SIZE, MainViewSlider::VERTICAL_SLIDERS_HEIGHT}, idx, true) { } diff --git a/radio/src/gui/colorlcd/lcd.cpp b/radio/src/gui/colorlcd/lcd.cpp index adbbc635749..f3fbe7e8ff0 100644 --- a/radio/src/gui/colorlcd/lcd.cpp +++ b/radio/src/gui/colorlcd/lcd.cpp @@ -26,6 +26,7 @@ #include "bitmapbuffer.h" #include "board.h" #include "dma2d.h" +#include "themes/etx_lv_theme.h" pixel_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; @@ -107,27 +108,6 @@ static void flushLcd(lv_disp_drv_t* disp_drv, const lv_area_t* area, lcd_flush_cb(disp_drv, (uint16_t*)color_p, copy_area); #if !defined(LCD_VERTICAL_INVERT) - uint16_t* src = (uint16_t*)color_p; - uint16_t* dst = nullptr; - if ((uint16_t*)color_p == LCD_FIRST_FRAME_BUFFER) - dst = LCD_SECOND_FRAME_BUFFER; - else - 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; - - 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); - } - DMAWait(); // wait for the last DMACopyBitmap to be completed before - // sending completion message lv_disp_flush_ready(disp_drv); #endif } else { @@ -141,6 +121,9 @@ void lcdInitDisplayDriver() if (disp != nullptr) return; lv_init(); +#if !defined(BOOT) + useMainStyle(); +#endif // Clear buffers first memset(LCD_FIRST_FRAME_BUFFER, 0, sizeof(LCD_FIRST_FRAME_BUFFER)); @@ -160,11 +143,12 @@ void lcdInitDisplayDriver() 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) + disp_drv.full_refresh = 1; disp_drv.direct_mode = 1; #else + disp_drv.full_refresh = 0; disp_drv.direct_mode = 0; #endif diff --git a/radio/src/gui/colorlcd/list_line_button.cpp b/radio/src/gui/colorlcd/list_line_button.cpp index bbd2bf2d171..708480cd163 100644 --- a/radio/src/gui/colorlcd/list_line_button.cpp +++ b/radio/src/gui/colorlcd/list_line_button.cpp @@ -61,46 +61,11 @@ void ListLineButton::checkEvents() ButtonBase::checkEvents(); } -// total: 92 x 17 -#define FM_CANVAS_HEIGHT 17 -#define FM_CANVAS_WIDTH 92 - -#if LCD_W > LCD_H // Landscape - -#define BTN_W 389 - -#define SRC_W 70 -#define OPT_W 171 -#define FM_X (OPT_X + OPT_W + 2) -#define FM_Y (WGT_Y + 2) - -#else // Portrait - -#define BTN_W 229 - -#define SRC_W 69 -#define OPT_W 106 -#define FM_X 12 -#define FM_Y (WGT_Y + WGT_H + 2) - -#endif - -#define WGT_X 2 -#define WGT_Y 2 -#define WGT_W 42 -#define WGT_H 21 -#define SRC_X (WGT_X + WGT_W + 2) -#define SRC_Y WGT_Y -#define SRC_H WGT_H -#define OPT_X (SRC_X + SRC_W + 2) -#define OPT_Y WGT_Y -#define OPT_H WGT_H - InputMixButtonBase::InputMixButtonBase(Window* parent, uint8_t index) : ListLineButton(parent, index) { setWidth(BTN_W); - setHeight(BTN_H); + setHeight(ListLineButton::BTN_H); padAll(PAD_ZERO); weight = lv_label_create(lvobj); @@ -146,8 +111,8 @@ void InputMixButtonBase::setFlightModes(uint16_t modes) free(fm_buffer); fm_canvas = nullptr; fm_buffer = nullptr; -#if LCD_H > LCD_W - setHeight(BTN_H); +#if PORTRAIT_LCD + setHeight(ListLineButton::BTN_H); #endif return; } @@ -158,8 +123,8 @@ void InputMixButtonBase::setFlightModes(uint16_t modes) lv_canvas_set_buffer(fm_canvas, fm_buffer, FM_CANVAS_WIDTH, FM_CANVAS_HEIGHT, LV_IMG_CF_ALPHA_8BIT); lv_obj_set_pos(fm_canvas, FM_X, FM_Y); -#if LCD_H > LCD_W - setHeight(BTN_H + FM_CANVAS_HEIGHT + 2); +#if PORTRAIT_LCD + setHeight(ListLineButton::BTN_H + FM_CANVAS_HEIGHT + 2); #endif lv_obj_set_style_img_recolor(fm_canvas, makeLvColor(COLOR_THEME_SECONDARY1), @@ -175,7 +140,7 @@ void InputMixButtonBase::setFlightModes(uint16_t modes) coord_t x = 0; lv_canvas_copy_buf(fm_canvas, mask->data, x, 0, w, h); - x += 20; + x += (w + PAD_TINY); lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); @@ -193,11 +158,11 @@ void InputMixButtonBase::setFlightModes(uint16_t modes) if (fm_modes & (1 << i)) { label_dsc.color = lv_color_make(0x7f, 0x7f, 0x7f); } else { - lv_canvas_draw_rect(fm_canvas, x, 0, 8, 3, &rect_dsc); + lv_canvas_draw_rect(fm_canvas, x, 0, FM_W, 3, &rect_dsc); label_dsc.color = lv_color_white(); } - lv_canvas_draw_text(fm_canvas, x, 0, 8, &label_dsc, s); - x += 8; + lv_canvas_draw_text(fm_canvas, x, 0, FM_W, &label_dsc, s); + x += FM_W; } } @@ -212,7 +177,7 @@ static const lv_obj_class_t group_class = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = LCD_W - 12, + .width_def = ListLineButton::GRP_W, .height_def = LV_SIZE_CONTENT, .editable = LV_OBJ_CLASS_EDITABLE_FALSE, .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, @@ -238,12 +203,12 @@ InputMixGroupBase::InputMixGroupBase(Window* parent, mixsrc_t idx) : void InputMixGroupBase::adjustHeight() { - if (getLineCount() == 0) setHeight(InputMixButtonBase::BTN_H + 8); + if (getLineCount() == 0) setHeight(ListLineButton::BTN_H + 8); coord_t y = 2; for (auto it = lines.cbegin(); it != lines.cend(); ++it) { auto line = *it; - line->updatePos(LN_X, y); + line->updatePos(InputMixButtonBase::LN_X, y); y += line->height() + 2; } setHeight(y + 4); diff --git a/radio/src/gui/colorlcd/list_line_button.h b/radio/src/gui/colorlcd/list_line_button.h index b649b856f39..fab50457f18 100644 --- a/radio/src/gui/colorlcd/list_line_button.h +++ b/radio/src/gui/colorlcd/list_line_button.h @@ -37,6 +37,9 @@ class ListLineButton : public ButtonBase virtual void refresh() = 0; + static LAYOUT_VAL(BTN_H, 29, 29) + static constexpr coord_t GRP_W = LCD_W - PAD_MEDIUM * 2; + protected: uint8_t index; @@ -53,11 +56,31 @@ class InputMixButtonBase : public ListLineButton void setSource(mixsrc_t idx); void setFlightModes(uint16_t modes); - static constexpr coord_t BTN_H = 29; - virtual void updatePos(coord_t x, coord_t y) = 0; virtual void swapLvglGroup(InputMixButtonBase* line2) = 0; + // total: 90 x 17 + static LAYOUT_VAL(FM_CANVAS_HEIGHT, 17, 17) + static LAYOUT_VAL(FM_CANVAS_WIDTH, 90, 90) + + static LAYOUT_VAL(BTN_W, 389, 229) + static constexpr coord_t WGT_X = PAD_TINY; + static constexpr coord_t WGT_Y = PAD_TINY; + static LAYOUT_VAL(WGT_W, 43, 43) + static LAYOUT_VAL(WGT_H, 21, 21) + static constexpr coord_t SRC_X = WGT_X + WGT_W + PAD_TINY; + static constexpr coord_t SRC_Y = WGT_Y; + static LAYOUT_VAL(SRC_W, 70, 69) + static constexpr coord_t SRC_H = WGT_H; + static constexpr coord_t OPT_X = SRC_X + SRC_W + PAD_TINY; + static constexpr coord_t OPT_Y = WGT_Y; + static LAYOUT_VAL(OPT_W, 171, 106) + static constexpr coord_t OPT_H = WGT_H; + static LAYOUT_VAL(LN_X, 73, 73) + static LAYOUT_VAL(FM_X, (OPT_X + OPT_W + PAD_TINY), 12) + static LAYOUT_VAL(FM_Y, (WGT_Y + PAD_TINY), (WGT_Y + WGT_H + PAD_TINY)) + static LAYOUT_VAL(FM_W, 8, 8) + protected: lv_obj_t* fm_canvas = nullptr; @@ -84,8 +107,6 @@ class InputMixGroupBase : public Window void refresh(); protected: - static constexpr coord_t LN_X = 73; - mixsrc_t idx; lv_obj_t* label; std::list lines; diff --git a/radio/src/gui/colorlcd/listbox.cpp b/radio/src/gui/colorlcd/listbox.cpp index a1dc5400eea..a1faf0526ca 100644 --- a/radio/src/gui/colorlcd/listbox.cpp +++ b/radio/src/gui/colorlcd/listbox.cpp @@ -109,10 +109,10 @@ void ListBox::setSelected(int selected, bool force) 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); @@ -224,8 +224,7 @@ void ListBox::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) label_dsc.align = LV_TEXT_ALIGN_RIGHT; const char* sym = LV_SYMBOL_OK; - if (getSelectedSymbol) - sym = getSelectedSymbol(row); + if (getSelectedSymbol) sym = getSelectedSymbol(row); lv_coord_t w = 30; lv_coord_t h = 12; diff --git a/radio/src/gui/colorlcd/listbox.h b/radio/src/gui/colorlcd/listbox.h index cdce9e76bdd..35d094c051d 100644 --- a/radio/src/gui/colorlcd/listbox.h +++ b/radio/src/gui/colorlcd/listbox.h @@ -31,7 +31,8 @@ class ListBox : public TableField { std::function longPressHandler = nullptr; std::function pressHandler = nullptr; - std::function, std::set)> _multiSelectHandler = nullptr; + std::function, std::set)> + _multiSelectHandler = nullptr; std::function getSelectedSymbol = nullptr; bool autoEdit = false; @@ -85,6 +86,8 @@ class ListBox : public TableField std::string getName() const override { return "ListBox"; } #endif + static LAYOUT_VAL(MENUS_LINE_HEIGHT, 35, 35) + protected: static void event_cb(lv_event_t* e); int activeItem = -1; diff --git a/radio/src/gui/colorlcd/menu_model.cpp b/radio/src/gui/colorlcd/menu_model.cpp index 753b72060e4..67f32fa22e6 100644 --- a/radio/src/gui/colorlcd/menu_model.cpp +++ b/radio/src/gui/colorlcd/menu_model.cpp @@ -70,19 +70,6 @@ void ModelMenu::build() #endif } -#if defined(PCBNV14) || defined(PCBPL18) -void ModelMenu::addGoToMonitorsButton() -{ - new TextButton( - getHeaderWindow(), - {LCD_W / 2 + 6, MENU_TITLE_TOP + 1, LCD_W / 2 - 8, MENU_TITLE_HEIGHT - 2}, - STR_OPEN_CHANNEL_MONITORS, [=]() { - pushEvent(EVT_KEY_BREAK(KEY_MODEL)); - return 0; - }); -} -#endif - #if defined(HARDWARE_KEYS) void ModelMenu::onPressSYS() { diff --git a/radio/src/gui/colorlcd/menu_model.h b/radio/src/gui/colorlcd/menu_model.h index 297c74f556d..827ebf3bc01 100644 --- a/radio/src/gui/colorlcd/menu_model.h +++ b/radio/src/gui/colorlcd/menu_model.h @@ -33,10 +33,6 @@ class ModelMenu : public TabsGroup #endif protected: -#if defined(PCBNV14) || defined(PCBPL18) - void addGoToMonitorsButton(void); -#endif - void build(); #if defined(HARDWARE_KEYS) diff --git a/radio/src/gui/colorlcd/mixer_edit.cpp b/radio/src/gui/colorlcd/mixer_edit.cpp index ae2dd043ff4..a64a26c11e5 100644 --- a/radio/src/gui/colorlcd/mixer_edit.cpp +++ b/radio/src/gui/colorlcd/mixer_edit.cpp @@ -34,16 +34,6 @@ #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 -#else -#define MIX_STATUS_BAR_WIDTH 180 -#define MIX_STATUS_BAR_MARGIN 0 -#define MIX_RIGHT_MARGIN 3 -#endif - class MixerEditStatusBar : public Window { public: @@ -57,6 +47,8 @@ class MixerEditStatusBar : public Window channel, true); } + static LAYOUT_VAL(MIX_STATUS_BAR_MARGIN, 3, 0) + protected: ComboChannelBar *channelBar; int8_t _channel; @@ -78,11 +70,11 @@ void MixEditWindow::buildHeader(Window *window) new MixerEditStatusBar( window, {window->getRect().w - MIX_STATUS_BAR_WIDTH - MIX_RIGHT_MARGIN, 0, - MIX_STATUS_BAR_WIDTH, MENU_HEADER_HEIGHT}, + MIX_STATUS_BAR_WIDTH, EdgeTxStyles::MENU_HEADER_HEIGHT}, channel); } -#if LCD_W > LCD_H +#if !PORTRAIT_LCD static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_FR(1), LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST}; @@ -116,13 +108,13 @@ void MixEditWindow::buildBody(Window *form) // Weight line = form->newLine(grid); new StaticText(line, rect_t{}, STR_WEIGHT); - auto gvar = new GVarNumberEdit(line, rect_t{}, MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, + auto gvar = new GVarNumberEdit(line, MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight)); gvar->setSuffix("%"); // Offset new StaticText(line, rect_t{}, STR_OFFSET); - gvar = new GVarNumberEdit(line, rect_t{}, MIX_OFFSET_MIN, MIX_OFFSET_MAX, + gvar = new GVarNumberEdit(line, MIX_OFFSET_MIN, MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset)); gvar->setSuffix("%"); diff --git a/radio/src/gui/colorlcd/mixer_edit.h b/radio/src/gui/colorlcd/mixer_edit.h index 660baa304c0..47fbb287e45 100644 --- a/radio/src/gui/colorlcd/mixer_edit.h +++ b/radio/src/gui/colorlcd/mixer_edit.h @@ -30,6 +30,9 @@ class MixEditWindow : public Page public: MixEditWindow(int8_t channel, uint8_t index); + static LAYOUT_VAL(MIX_STATUS_BAR_WIDTH, 250, 180) + static LAYOUT_VAL(MIX_RIGHT_MARGIN, 0, 3) + protected: uint8_t channel; uint8_t index; diff --git a/radio/src/gui/colorlcd/mixer_edit_adv.cpp b/radio/src/gui/colorlcd/mixer_edit_adv.cpp index f14714145a3..2edf92434a6 100644 --- a/radio/src/gui/colorlcd/mixer_edit_adv.cpp +++ b/radio/src/gui/colorlcd/mixer_edit_adv.cpp @@ -40,7 +40,7 @@ MixEditAdvanced::MixEditAdvanced(int8_t channel, uint8_t index) : buildBody(body); } -#if LCD_W > LCD_H +#if !PORTRAIT_LCD static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; @@ -80,27 +80,27 @@ void MixEditAdvanced::buildBody(Window* form) // Warning new StaticText(line, rect_t{}, STR_MIXWARNING); - auto edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, 3, + auto edit = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 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); - edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, + edit = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 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); - edit = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, + edit = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->delayDown), SET_VALUE(mix->delayDown, newValue), PREC1); edit->setSuffix("s"); // Slow up/down precision -#if LCD_W > LCD_H +#if !PORTRAIT_LCD grid.setColSpan(2); #endif line = form->newLine(grid); @@ -115,20 +115,20 @@ void MixEditAdvanced::buildBody(Window* form) slowDn->update(); SET_DIRTY(); }); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD grid.setColSpan(1); #endif // Slow up line = form->newLine(grid); new StaticText(line, rect_t{}, STR_SLOWUP); - slowUp = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->speedUp), + slowUp = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->speedUp), SET_VALUE(mix->speedUp, newValue), mix->speedPrec ? PREC2 : PREC1); slowUp->setSuffix("s"); // Slow down new StaticText(line, rect_t{}, STR_SLOWDOWN); - slowDn = new NumberEdit(line, rect_t{0, 0, 100, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->speedDown), + slowDn = new NumberEdit(line, rect_t{0, 0, NUM_EDIT_W, 0}, 0, DELAY_MAX, GET_DEFAULT(mix->speedDown), SET_VALUE(mix->speedDown, newValue), mix->speedPrec ? PREC2 : PREC1); slowDn->setSuffix("s"); } diff --git a/radio/src/gui/colorlcd/mixer_edit_adv.h b/radio/src/gui/colorlcd/mixer_edit_adv.h index b1cafe8a9d1..e77231c24bb 100644 --- a/radio/src/gui/colorlcd/mixer_edit_adv.h +++ b/radio/src/gui/colorlcd/mixer_edit_adv.h @@ -33,6 +33,8 @@ class MixEditAdvanced : public Page public: MixEditAdvanced(int8_t channel, uint8_t index); + static LAYOUT_VAL(NUM_EDIT_W, 100, 100) + protected: uint8_t channel; uint8_t index; diff --git a/radio/src/gui/colorlcd/model_curves.cpp b/radio/src/gui/colorlcd/model_curves.cpp index e7672d70a16..c7b29962dac 100644 --- a/radio/src/gui/colorlcd/model_curves.cpp +++ b/radio/src/gui/colorlcd/model_curves.cpp @@ -27,16 +27,10 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -#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 -#else +#if PORTRAIT_LCD #define PER_ROW 2 +#else +#define PER_ROW 3 #endif class CurveButton : public Button @@ -54,7 +48,7 @@ class CurveButton : public Button s = strAppend(s, ":"); strAppend(s, g_model.curves[index].name, LEN_CURVE_NAME); } - title = new StaticText(this, {4, -1, width() - 12, 21}, buf, + title = new StaticText(this, {4, -1, width() - 12, TITLE_H + 1}, buf, COLOR_THEME_SECONDARY1 | CENTERED | FONT(BOLD)); etx_txt_color(title->getLvObj(), COLOR_THEME_PRIMARY2_INDEX, LV_PART_MAIN | LV_STATE_USER_1); @@ -71,8 +65,8 @@ class CurveButton : public Button // Preview preview = new CurveRenderer( this, - {PREVIEW_PAD, PREVIEW_PAD + TITLE_H, width() - PREVIEW_PAD * 2 - 4, - width() - PREVIEW_PAD * 2 - 4}, + {PAD_MEDIUM, PAD_MEDIUM + TITLE_H, width() - PAD_MEDIUM * 2 - 4, + width() - PAD_MEDIUM * 2 - 4}, [=](int x) -> int { return applyCustomCurve(x, index); }); // Curve characteristics @@ -85,6 +79,11 @@ class CurveButton : public Button void update() { preview->update(); } + static LAYOUT_VAL(TITLE_H, 20, 20) + static LAYOUT_VAL(INFO_H, 27, 27) + static LAYOUT_VAL(CURVE_BTN_W, 142, 142) + static constexpr coord_t CURVE_BTH_H = CURVE_BTN_W + TITLE_H + INFO_H - PAD_MEDIUM; + protected: uint8_t index; StaticText *title; @@ -209,7 +208,7 @@ void ModelCurvesPage::plusPopup(Window *window) void ModelCurvesPage::build(Window *window) { -#if LCD_W > LCD_H +#if !PORTRAIT_LCD static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; #else @@ -239,7 +238,7 @@ void ModelCurvesPage::build(Window *window) // Curve drawing auto button = - new CurveButton(line, rect_t{0, 0, CURVE_BTN_W, CURVE_BTH_H}, index); + new CurveButton(line, rect_t{0, 0, CurveButton::CURVE_BTN_W, CurveButton::CURVE_BTH_H}, index); button->setPressHandler([=]() -> uint8_t { Menu *menu = new Menu(window); menu->setTitle(STR_CURVE); @@ -296,7 +295,7 @@ void ModelCurvesPage::build(Window *window) LV_GRID_ALIGN_SPACE_BETWEEN); } - addButton = new TextButton(line, rect_t{0, 0, CURVE_BTN_W, CURVE_BTH_H}, + addButton = new TextButton(line, rect_t{0, 0, CurveButton::CURVE_BTN_W, CurveButton::CURVE_BTH_H}, LV_SYMBOL_PLUS, [=]() { plusPopup(window); return 0; diff --git a/radio/src/gui/colorlcd/model_flightmodes.cpp b/radio/src/gui/colorlcd/model_flightmodes.cpp index 531c7ce02ca..76c1df4f034 100644 --- a/radio/src/gui/colorlcd/model_flightmodes.cpp +++ b/radio/src/gui/colorlcd/model_flightmodes.cpp @@ -49,7 +49,7 @@ static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #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}; @@ -75,7 +75,7 @@ class TrimEdit : public Window lastTrim = tr->value; auto tr_btn = new TextButton( - this, rect_t{0, 0, 65, 0}, getSourceString(MIXSRC_FIRST_TRIM + trimId), + this, rect_t{0, 0, TR_BTN_W, 0}, getSourceString(MIXSRC_FIRST_TRIM + trimId), [=]() { tr->mode = (tr->mode == TRIM_MODE_NONE) ? 0 : TRIM_MODE_NONE; tr_mode->setValue(tr->mode); @@ -86,7 +86,7 @@ class TrimEdit : public Window if (tr->mode != TRIM_MODE_NONE) tr_btn->check(); - tr_mode = new Choice(this, rect_t{0, 0, 70, 0}, 0, 2 * MAX_FLIGHT_MODES, + tr_mode = new Choice(this, rect_t{0, 0, TR_MODE_W, 0}, 0, 2 * MAX_FLIGHT_MODES, GET_DEFAULT(tr->mode), [=](int val) { tr->mode = val; showControls(); @@ -102,12 +102,15 @@ class TrimEdit : public Window }); tr_value = new NumberEdit( - this, rect_t{0, 0, 70, 0}, g_model.extendedTrims ? -512 : -128, + this, rect_t{0, 0, TR_MODE_W, 0}, g_model.extendedTrims ? -512 : -128, g_model.extendedTrims ? 512 : 128, GET_SET_DEFAULT(tr->value)); showControls(); } + static LAYOUT_VAL(TR_BTN_W, 65, 65) + static LAYOUT_VAL(TR_MODE_W, 70, 70) + protected: int trimId; int fmId; @@ -197,155 +200,6 @@ class FlightModeEdit : public Page uint8_t index; }; -#if LCD_W > LCD_H // Landscape - -#define BTN_H 36 -#define FMID_W 36 -#define NAME_W 95 -#define NAME_Y 8 -#define SWTCH_Y 6 -#define MAX_FMTRIMS 6 -#define TRIM_W 30 -#define TRIM_X (SWTCH_X + SWTCH_W + 2) -#define TRIM_Y 0 -#define FADE_Y 6 - -#else // Portrait - -#define BTN_H 56 -#define FMID_W 46 -#define NAME_W 160 -#define NAME_Y 0 -#define SWTCH_Y 0 -#define MAX_FMTRIMS 4 -#define TRIM_W 40 -#define TRIM_X (FMID_X + FMID_W + 2) -#define TRIM_Y 20 -#define FADE_Y 24 - -#endif - -#define FMID_X 2 -#define FMID_Y (BTN_H / 2 - 12) -#define NAME_X (FMID_X + FMID_W + 2) -#define SWTCH_W 50 -#define SWTCH_X (NAME_X + NAME_W + 2) -#define TRIMC_W (MAX_FMTRIMS * TRIM_W) -#define FADE_W 45 -#define FADE_X (TRIM_X + TRIMC_W + 2) - -static void fm_id_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 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), -}; - -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); -} - -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), -}; - -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); -} - -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), -}; - -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); -} - -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), -}; - -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); -} - -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), -}; - -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); -} - -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), -}; - class FlightModeBtn : public ListLineButton { public: @@ -355,8 +209,6 @@ class FlightModeBtn : public ListLineButton padColumn(PAD_ZERO); setHeight(BTN_H); - check(isActive()); - lv_obj_add_event_cb(lvobj, FlightModeBtn::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); } @@ -376,6 +228,10 @@ class FlightModeBtn : public ListLineButton { init = true; + lv_obj_enable_style_refresh(false); + + check(isActive()); + fmID = etx_create(&fm_id_class, lvobj); lv_obj_set_pos(fmID, FMID_X, FMID_Y); char label[8]; @@ -391,7 +247,7 @@ class FlightModeBtn : public ListLineButton fmTrimMode[i] = etx_create(&fm_trim_mode_class, lvobj); lv_obj_set_pos(fmTrimMode[i], TRIM_X + i * TRIM_W, TRIM_Y); fmTrimValue[i] = etx_create(&fm_trim_value_class, lvobj); - lv_obj_set_pos(fmTrimValue[i], TRIM_X + i * TRIM_W, TRIM_Y + 16); + lv_obj_set_pos(fmTrimValue[i], TRIM_X + i * TRIM_W, TRIM_Y + TRIM_H); } fmFadeIn = etx_create(&fm_fade_class, lvobj); @@ -399,27 +255,36 @@ class FlightModeBtn : public ListLineButton fmFadeOut = etx_create(&fm_fade_class, lvobj); lv_obj_set_pos(fmFadeOut, FADE_X + FADE_W + 1, FADE_Y); lv_obj_update_layout(lvobj); + + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); } bool isActive() const override { return (getFlightMode() == index); } + void setTrimValue(uint8_t t) + { + lastTrim[t] = g_model.flightModeData[index].trim[t].value; + + uint8_t mode = g_model.flightModeData[index].trim[t].mode; + bool checked = (mode != TRIM_MODE_NONE); + bool showValue = (index == 0) || ((mode & 1) || (mode >> 1 == index)); + + if (checked && showValue) + lv_label_set_text(fmTrimValue[t], + formatNumberAsString(lastTrim[t]).c_str()); + else + lv_label_set_text(fmTrimValue[t], ""); + } + void checkEvents() override { ListLineButton::checkEvents(); if (!refreshing && init) { refreshing = true; - const auto& fm = g_model.flightModeData[index]; for (int t = 0; t < keysGetMaxTrims(); t += 1) { - if (lastTrim[t] != fm.trim[t].value) { - lastTrim[t] = fm.trim[t].value; - - uint8_t mode = fm.trim[t].mode; - bool checked = (mode != TRIM_MODE_NONE); - 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()); + if (lastTrim[t] != g_model.flightModeData[index].trim[t].value) { + setTrimValue(t); } } refreshing = false; @@ -447,17 +312,8 @@ class FlightModeBtn : public ListLineButton } for (int i = 0; i < keysGetMaxTrims(); i += 1) { - uint8_t mode = fm.trim[i].mode; - bool checked = (mode != TRIM_MODE_NONE); - bool showValue = (index == 0) || ((mode & 1) || (mode >> 1 == index)); - - 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()); - else - lv_label_set_text(fmTrimValue[i], ""); + setTrimValue(i); + lv_label_set_text(fmTrimMode[i], getFMTrimStr(fm.trim[i].mode, false).c_str()); } lv_label_set_text( @@ -468,6 +324,26 @@ class FlightModeBtn : public ListLineButton formatNumberAsString(fm.fadeOut, PREC1, 0, nullptr, "s").c_str()); } + static LAYOUT_VAL(BTN_H, 36, 56) + static LAYOUT_VAL(MAX_FMTRIMS, 6, 4) + static constexpr coord_t FMID_X = PAD_TINY; + static LAYOUT_VAL(FMID_Y, 6, 16) + static LAYOUT_VAL(FMID_W, 36, 46) + static constexpr coord_t NAME_X = FMID_X + FMID_W + PAD_TINY; + static LAYOUT_VAL(NAME_Y, 8, 0) + static LAYOUT_VAL(NAME_W, 95, 160) + static constexpr coord_t SWTCH_X = NAME_X + NAME_W + PAD_TINY; + static LAYOUT_VAL(SWTCH_Y, 6, 0) + static LAYOUT_VAL(SWTCH_W, 50, 50) + static LAYOUT_VAL(TRIM_X, SWTCH_X + SWTCH_W + PAD_TINY, FMID_X + FMID_W + PAD_TINY) + static LAYOUT_VAL(TRIM_Y, 0, 20) + static LAYOUT_VAL(TRIM_W, 30, 40) + static LAYOUT_VAL(TRIM_H, 16, 16) + static constexpr coord_t TRIMC_W = MAX_FMTRIMS * TRIM_W; + static constexpr coord_t FADE_X = TRIM_X + TRIMC_W + PAD_TINY; + static LAYOUT_VAL(FADE_Y, 6, 24) + static LAYOUT_VAL(FADE_W, 45, 45) + protected: bool init = false; bool refreshing = false; @@ -479,7 +355,126 @@ class FlightModeBtn : public ListLineButton lv_obj_t* fmTrimValue[MAX_FMTRIMS] = {nullptr}; lv_obj_t* fmFadeIn = nullptr; lv_obj_t* fmFadeOut = nullptr; - int lastTrim[MAX_FMTRIMS]; + int lastTrim[MAX_FMTRIMS] = {0}; + + static const lv_obj_class_t fm_id_class; + static const lv_obj_class_t fm_name_class; + static const lv_obj_class_t fm_switch_class; + static const lv_obj_class_t fm_fade_class; + static const lv_obj_class_t fm_trim_mode_class; + static const lv_obj_class_t fm_trim_value_class; +}; + +static void fm_id_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); +} + +const lv_obj_class_t FlightModeBtn::fm_id_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_id_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = FlightModeBtn::FMID_W, + .height_def = EdgeTxStyles::PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; + +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); +} + +const lv_obj_class_t FlightModeBtn::fm_name_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_name_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = FlightModeBtn::NAME_W, + .height_def = EdgeTxStyles::PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; + +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); +} + +const lv_obj_class_t FlightModeBtn::fm_switch_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_switch_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = FlightModeBtn::SWTCH_W, + .height_def = EdgeTxStyles::PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; + +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); +} + +const lv_obj_class_t FlightModeBtn::fm_fade_class = { + .base_class = &lv_label_class, + .constructor_cb = fm_fade_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = FlightModeBtn::FADE_W, + .height_def = EdgeTxStyles::PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; + +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); +} + +const lv_obj_class_t FlightModeBtn::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 = FlightModeBtn::TRIM_W, + .height_def = FlightModeBtn::TRIM_H, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; + +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); +} + +const lv_obj_class_t FlightModeBtn::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 = FlightModeBtn::TRIM_W, + .height_def = FlightModeBtn::TRIM_H, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), }; ModelFlightModesPage::ModelFlightModesPage() : @@ -499,8 +494,8 @@ void ModelFlightModesPage::build(Window* form) for (int i = 0; i < MAX_FLIGHT_MODES; i++) { auto btn = new FlightModeBtn(form, i); - lv_obj_set_pos(btn->getLvObj(), 6, i * (BTN_H + 3) + 4); - btn->setWidth(LCD_W - 12); + lv_obj_set_pos(btn->getLvObj(), PAD_MEDIUM, i * (FlightModeBtn::BTN_H + 3) + 4); + btn->setWidth(ListLineButton::GRP_W); btn->setPressHandler([=]() { new FlightModeEdit(i); @@ -509,7 +504,7 @@ void ModelFlightModesPage::build(Window* form) } trimCheck = new TextButton( - form, rect_t{6, MAX_FLIGHT_MODES * (BTN_H + 3) + 8, LCD_W - 12, 40}, STR_CHECKTRIMS, [&]() -> uint8_t { + form, rect_t{6, MAX_FLIGHT_MODES * (FlightModeBtn::BTN_H + 3) + PAD_LARGE, ListLineButton::GRP_W, TRIM_CHK_H}, STR_CHECKTRIMS, [&]() -> uint8_t { if (trimsCheckTimer) trimsCheckTimer = 0; else diff --git a/radio/src/gui/colorlcd/model_flightmodes.h b/radio/src/gui/colorlcd/model_flightmodes.h index cea2f7db1f3..0c47feef51c 100644 --- a/radio/src/gui/colorlcd/model_flightmodes.h +++ b/radio/src/gui/colorlcd/model_flightmodes.h @@ -33,6 +33,8 @@ class ModelFlightModesPage : public PageTab void build(Window* window) override; + static LAYOUT_VAL(TRIM_CHK_H, 40, 40) + protected: TextButton* trimCheck = nullptr; diff --git a/radio/src/gui/colorlcd/model_gvars.cpp b/radio/src/gui/colorlcd/model_gvars.cpp index 24fd7186692..f456be3e492 100644 --- a/radio/src/gui/colorlcd/model_gvars.cpp +++ b/radio/src/gui/colorlcd/model_gvars.cpp @@ -30,18 +30,6 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -#define GVAR_NAME_SIZE 48 -#define GVAR_VAL_H (PAGE_LINE_HEIGHT * 2 - 6) -#if LCD_W > LCD_H -#define BTN_H 38 -#define GVAR_VAL_W 45 -#define GVAR_COLS MAX_FLIGHT_MODES -#else -#define BTN_H (modelFMEnabled() ? 72 : 38) -#define GVAR_VAL_W 50 -#define GVAR_COLS 5 -#endif - #define ETX_STATE_VALUE_SMALL_FONT LV_STATE_USER_1 void getFMExtName(char* dest, int8_t idx) @@ -57,55 +45,15 @@ void getFMExtName(char* dest, int8_t idx) } } -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_solid_bg(obj, COLOR_THEME_ACTIVE_INDEX, LV_STATE_CHECKED); -} - -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), -}; - -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); - etx_solid_bg(obj, COLOR_THEME_ACTIVE_INDEX, LV_STATE_CHECKED); -} - -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 ListLineButton { public: - GVarButton(Window* parent, const rect_t& rect, uint8_t gvar) : + GVarButton(Window* parent, uint8_t gvar) : ListLineButton(parent, gvar) { padAll(PAD_ZERO); setHeight(BTN_H); - if (!modelFMEnabled()) padLeft(8); + if (!modelFMEnabled()) padLeft(PAD_LARGE); lv_obj_add_event_cb(lvobj, GVarButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); @@ -118,10 +66,21 @@ class GVarButton : public ListLineButton if (line) line->build(); } + static LAYOUT_VAL(GVAR_NAME_SIZE, 44, 44) + static constexpr coord_t GVAR_VAL_H = EdgeTxStyles::PAGE_LINE_HEIGHT + 2; + static LAYOUT_VAL(GVAR_VAL_W, 45, 50) + static LAYOUT_VAL(GVAR_COLS, MAX_FLIGHT_MODES, 5) + static LAYOUT_VAL(BTN_H, EdgeTxStyles::UI_ELEMENT_HEIGHT, 50) + static LAYOUT_VAL(GVAR_NM_Y, 4, 13) + static LAYOUT_VAL(GVAR_YO, 4, 2) + static LAYOUT_VAL(HDR_H, EdgeTxStyles::PAGE_LINE_HEIGHT + 2, EdgeTxStyles::PAGE_LINE_HEIGHT * 2 + 2) + + static const lv_obj_class_t gv_label_class; + static const lv_obj_class_t gv_value_class; + protected: bool init = false; uint8_t currentFlightMode = 0; // used for checking updates - lv_obj_t* labelTexts[MAX_FLIGHT_MODES]; lv_obj_t* valueTexts[MAX_FLIGHT_MODES]; gvar_t values[MAX_FLIGHT_MODES]; @@ -135,9 +94,7 @@ class GVarButton : public ListLineButton uint8_t newFM = getFlightMode(); if (currentFlightMode != newFM) { lv_obj_add_state(valueTexts[newFM], LV_STATE_CHECKED); - lv_obj_add_state(labelTexts[newFM], LV_STATE_CHECKED); lv_obj_clear_state(valueTexts[currentFlightMode], LV_STATE_CHECKED); - lv_obj_clear_state(labelTexts[currentFlightMode], LV_STATE_CHECKED); currentFlightMode = newFM; } @@ -158,43 +115,38 @@ class GVarButton : public ListLineButton init =true; + lv_obj_enable_style_refresh(false); + currentFlightMode = getFlightMode(); auto nm = lv_label_create(lvobj); lv_label_set_text(nm, getGVarString(index)); - lv_obj_set_pos(nm, 2, (BTN_H - PAGE_LINE_HEIGHT - 4) / 2); - lv_obj_set_size(nm, GVAR_NAME_SIZE, PAGE_LINE_HEIGHT); + lv_obj_set_pos(nm, PAD_TINY, GVAR_NM_Y); + lv_obj_set_size(nm, GVAR_NAME_SIZE, EdgeTxStyles::PAGE_LINE_HEIGHT); if (modelFMEnabled()) { - char label[16] = {}; - for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { - getFlightModeString(label, flightMode + 1); - - labelTexts[flightMode] = etx_create(&gv_label_class, lvobj); - lv_label_set_text(labelTexts[flightMode], label); - lv_obj_set_pos(labelTexts[flightMode], (flightMode % GVAR_COLS) * GVAR_VAL_W + GVAR_NAME_SIZE + 4, - (flightMode / GVAR_COLS) * GVAR_VAL_H); - valueTexts[flightMode] = etx_create(&gv_value_class, lvobj); lv_obj_set_pos(valueTexts[flightMode], (flightMode % GVAR_COLS) * GVAR_VAL_W + GVAR_NAME_SIZE + 4, - (flightMode / GVAR_COLS) * GVAR_VAL_H + PAGE_LINE_HEIGHT - 6); + (flightMode / GVAR_COLS) * GVAR_VAL_H + GVAR_YO); if (flightMode == currentFlightMode) { lv_obj_add_state(valueTexts[flightMode], LV_STATE_CHECKED); - lv_obj_add_state(labelTexts[flightMode], LV_STATE_CHECKED); } updateValueText(flightMode); } } else { valueTexts[0] = lv_label_create(lvobj); - lv_obj_set_pos(valueTexts[0], GVAR_NAME_SIZE + 6, (BTN_H - PAGE_LINE_HEIGHT - 4) / 2); + lv_obj_set_pos(valueTexts[0], GVAR_NAME_SIZE + PAD_MEDIUM, (BTN_H - EdgeTxStyles::PAGE_LINE_HEIGHT - PAD_SMALL) / 2); updateValueText(0); } lv_obj_update_layout(lvobj); + + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); } void updateValueText(uint8_t flightMode) @@ -233,6 +185,114 @@ class GVarButton : public ListLineButton void refresh() override {} }; +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_solid_bg(obj, COLOR_THEME_ACTIVE_INDEX, LV_STATE_CHECKED); +} + +const lv_obj_class_t GVarButton::gv_label_class = { + .base_class = &lv_label_class, + .constructor_cb = gv_label_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = GVarButton::GVAR_VAL_W, + .height_def = EdgeTxStyles::PAGE_LINE_HEIGHT - PAD_MEDIUM, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; + +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); + etx_solid_bg(obj, COLOR_THEME_ACTIVE_INDEX, LV_STATE_CHECKED); +} + +const lv_obj_class_t GVarButton::gv_value_class = { + .base_class = &lv_label_class, + .constructor_cb = gv_value_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = GVarButton::GVAR_VAL_W, + .height_def = EdgeTxStyles::PAGE_LINE_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_label_t), +}; + +class GVarHeader : public Window +{ + public: + GVarHeader(Window* parent) : + Window(parent, {0, 0, LCD_W, GVarButton::HDR_H}) + { + padAll(PAD_ZERO); + etx_solid_bg(lvobj, COLOR_THEME_SECONDARY3_INDEX); + + lv_obj_add_event_cb(lvobj, GVarHeader::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 = (GVarHeader*)lv_obj_get_user_data(target); + if (line) line->build(); + } + + protected: + bool init = false; + uint8_t currentFlightMode = 0; // used for checking updates + lv_obj_t* labelTexts[MAX_FLIGHT_MODES]; + + int numFlightModes() { return modelFMEnabled() ? MAX_FLIGHT_MODES : 1; } + + void checkEvents() override + { + Window::checkEvents(); + if (init) { + uint8_t newFM = getFlightMode(); + if (currentFlightMode != newFM) { + lv_obj_add_state(labelTexts[newFM], LV_STATE_CHECKED); + lv_obj_clear_state(labelTexts[currentFlightMode], LV_STATE_CHECKED); + + currentFlightMode = newFM; + } + } + } + + void build() + { + if (init) return; + + init =true; + + currentFlightMode = getFlightMode(); + + char label[16] = {}; + + for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { + getFlightModeString(label, flightMode + 1); + + labelTexts[flightMode] = etx_create(&GVarButton::gv_value_class, lvobj); + lv_label_set_text(labelTexts[flightMode], label); + lv_obj_set_pos(labelTexts[flightMode], (flightMode % GVarButton::GVAR_COLS) * GVarButton::GVAR_VAL_W + GVarButton::GVAR_NAME_SIZE + 12, + (flightMode / GVarButton::GVAR_COLS) * EdgeTxStyles::PAGE_LINE_HEIGHT + 1); + + if (flightMode == currentFlightMode) { + lv_obj_add_state(labelTexts[flightMode], LV_STATE_CHECKED); + } + } + + lv_obj_update_layout(lvobj); + } +}; + class GVarEditWindow : public Page { public: @@ -472,20 +532,34 @@ ModelGVarsPage::ModelGVarsPage() : { } +void ModelGVarsPage::cleanup() +{ + if (hdr) + hdr->deleteLater(); + hdr = nullptr; +} + void ModelGVarsPage::rebuild(Window* window) { auto scroll_y = lv_obj_get_scroll_y(window->getLvObj()); window->clear(); + cleanup(); build(window); lv_obj_scroll_to_y(window->getLvObj(), scroll_y, LV_ANIM_OFF); } void ModelGVarsPage::build(Window* window) { - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); + coord_t yo = 0; + if (modelFMEnabled()) { + hdr = new GVarHeader(window->getParent()); + lv_obj_set_pos(hdr->getLvObj(), 0, TabsGroup::MENU_TITLE_TOP + TabsGroup::MENU_TITLE_HEIGHT); + yo = GVarButton::HDR_H - 4; + } for (uint8_t index = 0; index < MAX_GVARS; index++) { - auto button = new GVarButton(window, rect_t{}, index); + auto button = new GVarButton(window, index); + lv_obj_set_pos(button->getLvObj(), 0, yo + index * (GVarButton::BTN_H + PAD_TINY)); 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 5de3af004a3..c09da19f62b 100644 --- a/radio/src/gui/colorlcd/model_gvars.h +++ b/radio/src/gui/colorlcd/model_gvars.h @@ -31,7 +31,11 @@ class ModelGVarsPage : public PageTab bool isVisible() const override { return modelGVEnabled(); } + void cleanup() override; + protected: + Window* hdr = nullptr; + 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 a7b77c5c35e..8346d0034c5 100644 --- a/radio/src/gui/colorlcd/model_heli.cpp +++ b/radio/src/gui/colorlcd/model_heli.cpp @@ -26,7 +26,7 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -#if LCD_W > LCD_H // landscape +#if !PORTRAIT_LCD // landscape static const lv_coord_t col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; diff --git a/radio/src/gui/colorlcd/model_inputs.cpp b/radio/src/gui/colorlcd/model_inputs.cpp index 688262b4cf1..4c1db5628de 100644 --- a/radio/src/gui/colorlcd/model_inputs.cpp +++ b/radio/src/gui/colorlcd/model_inputs.cpp @@ -400,10 +400,10 @@ void ModelInputsPage::build(Window* window) // reset clipboard _copyMode = 0; - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 3); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); form = new Window(window, rect_t{}); - form->setFlexLayout(LV_FLEX_FLOW_COLUMN, 3); + form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); auto btn = new TextButton(window, rect_t{}, LV_SYMBOL_PLUS, [=]() { newInput(); diff --git a/radio/src/gui/colorlcd/model_logical_switches.cpp b/radio/src/gui/colorlcd/model_logical_switches.cpp index b3f5631d3d4..8409f0a036b 100644 --- a/radio/src/gui/colorlcd/model_logical_switches.cpp +++ b/radio/src/gui/colorlcd/model_logical_switches.cpp @@ -294,54 +294,6 @@ void getsEdgeDelayParam(char* s, LogicalSwitchData* ls) .c_str()); } -#if LCD_W > LCD_H // Landscape - -#define LS_BUTTON_H 32 - -#define NM_Y 4 -#define NM_W 30 -#define FN_W 50 -#define V1_Y NM_Y -#define AND_X (V2_X + V2_W + 2) -#define AND_Y NM_Y -#define DUR_W 40 - -#else // Portrait - -#define LS_BUTTON_H 44 - -#define NM_Y 10 -#define NM_W 36 -#define FN_W 58 -#define V1_Y 0 -#define AND_X (FN_X + FN_W + 2) -#define AND_Y 20 -#define DUR_W 54 - -#endif - -#define NM_X 2 -#define NM_H 20 -#define FN_X (NM_X + NM_W + 2) -#define FN_Y NM_Y -#define FN_H NM_H -#define V1_X (FN_X + FN_W + 2) -#define V1_W 88 -#define V1_H NM_H -#define V2_X (V1_X + V1_W + 2) -#define V2_Y V1_Y -#define V2_W 110 -#define V2_H NM_H -#define AND_W 88 -#define AND_H NM_H -#define DUR_X (AND_X + AND_W + 2) -#define DUR_Y AND_Y -#define DUR_H NM_H -#define DEL_X (DUR_X + DUR_W + 2) -#define DEL_Y AND_Y -#define DEL_H NM_H -#define DEL_W DUR_W - class LogicalSwitchButton : public ListLineButton { public: @@ -372,6 +324,8 @@ class LogicalSwitchButton : public ListLineButton { init = true; + lv_obj_enable_style_refresh(false); + lsName = lv_label_create(lvobj); etx_obj_add_style(lsName, styles->text_align_left, LV_PART_MAIN); lv_obj_set_pos(lsName, NM_X, NM_Y); @@ -409,6 +363,9 @@ class LogicalSwitchButton : public ListLineButton lv_obj_set_size(lsDelay, DEL_W, DEL_H); lv_obj_update_layout(lvobj); + + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); } bool isActive() const override @@ -502,6 +459,37 @@ class LogicalSwitchButton : public ListLineButton } } + static LAYOUT_VAL(LS_BUTTON_H, 32, 44) + + static constexpr coord_t NM_X = PAD_TINY; + static LAYOUT_VAL(NM_Y, 4, 10) + static LAYOUT_VAL(NM_W, 30, 36) + static LAYOUT_VAL(NM_H, 20, 20) + static constexpr coord_t FN_X = NM_X + NM_W + PAD_TINY; + static constexpr coord_t FN_Y = NM_Y; + static LAYOUT_VAL(FN_W, 50, 58) + static constexpr coord_t FN_H = NM_H; + static constexpr coord_t V1_X = FN_X + FN_W + PAD_TINY; + static LAYOUT_VAL(V1_Y, NM_Y, 0) + static LAYOUT_VAL(V1_W, 88, 88) + static constexpr coord_t V1_H = NM_H; + static constexpr coord_t V2_X = V1_X + V1_W + PAD_TINY; + static constexpr coord_t V2_Y = V1_Y; + static LAYOUT_VAL(V2_W, 110, 110) + static constexpr coord_t V2_H = NM_H; + static LAYOUT_VAL(AND_X, V2_X + V2_W + PAD_TINY, FN_X + FN_W + PAD_TINY) + static LAYOUT_VAL(AND_Y, NM_Y, 20) + static constexpr coord_t AND_W = V1_W; + static constexpr coord_t AND_H = NM_H; + static constexpr coord_t DUR_X = AND_X + AND_W + PAD_TINY; + static constexpr coord_t DUR_Y = AND_Y; + static LAYOUT_VAL(DUR_W, 40, 54) + static constexpr coord_t DUR_H = NM_H; + static constexpr coord_t DEL_X = DUR_X + DUR_W + PAD_TINY; + static constexpr coord_t DEL_Y = AND_Y; + static constexpr coord_t DEL_H = NM_H; + static constexpr coord_t DEL_W = DUR_W; + protected: bool init = false; @@ -596,7 +584,7 @@ void ModelLogicalSwitchesPage::build(Window* window) line = window->newLine(grid); auto button = new LogicalSwitchButton( - line, rect_t{0, 0, window->width() - 12, LS_BUTTON_H}, i); + line, rect_t{0, 0, window->width() - 12, LogicalSwitchButton::LS_BUTTON_H}, i); button->setPressHandler([=]() { Menu* menu = new Menu(window); @@ -659,7 +647,7 @@ void ModelLogicalSwitchesPage::build(Window* window) if (hasEmptySwitch) { line = window->newLine(grid); addButton = - new TextButton(line, rect_t{0, 0, window->width() - 12, LS_BUTTON_H}, + new TextButton(line, rect_t{0, 0, window->width() - 12, LogicalSwitchButton::LS_BUTTON_H}, LV_SYMBOL_PLUS, [=]() { plusPopup(window); return 0; diff --git a/radio/src/gui/colorlcd/model_mixer_scripts.cpp b/radio/src/gui/colorlcd/model_mixer_scripts.cpp index fc4873b2af3..ad641d25824 100644 --- a/radio/src/gui/colorlcd/model_mixer_scripts.cpp +++ b/radio/src/gui/colorlcd/model_mixer_scripts.cpp @@ -39,7 +39,7 @@ static const lv_coord_t col_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; // Edit grid -#if LCD_W > LCD_H +#if !PORTRAIT_LCD static const lv_coord_t e_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST}; #else @@ -181,7 +181,7 @@ class ScriptLineButton : public ListLineButton scriptData(scriptData), runtimeData(runtimeData) { -#if LCD_H > LCD_W +#if PORTRAIT_LCD padTop(5); #endif padLeft(3); @@ -192,7 +192,7 @@ class ScriptLineButton : public ListLineButton 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(); lv_obj_add_event_cb(lvobj, ScriptLineButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); @@ -204,14 +204,15 @@ class ScriptLineButton : public ListLineButton auto line = (ScriptLineButton*)lv_obj_get_user_data(target); if (line) { if (!line->init) - line->delayed_init(e); - else - line->refresh(); + line->delayed_init(); + line->refresh(); } } - void delayed_init(lv_event_t* e) + void delayed_init() { + init = true; + auto lbl = lv_label_create(lvobj); 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, @@ -261,15 +262,7 @@ class ScriptLineButton : public ListLineButton } } - init = true; - refresh(); - lv_obj_update_layout(lvobj); - - if (e) { - auto param = lv_event_get_param(e); - lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param); - } } bool isActive() const override { return false; } diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index 8cc086656e2..f7f46e7c249 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -33,7 +33,7 @@ class MPlexIcon : public Window { public: MPlexIcon(Window* parent, uint8_t index) : - Window(parent, {0, 0, 25, 29}), + Window(parent, {0, 0, MPLEX_ICON_W, MPLEX_ICON_H}), index(index) { MixData* mix = mixAddress(index); @@ -67,6 +67,9 @@ class MPlexIcon : public Window index = i; } + static LAYOUT_VAL(MPLEX_ICON_W, 25, 25) + static LAYOUT_VAL(MPLEX_ICON_H, 29, 29) + protected: uint8_t index; StaticIcon* icon = nullptr; @@ -136,8 +139,8 @@ class MixLineButton : public InputMixButtonBase void updatePos(coord_t x, coord_t y) override { setPos(x, y); - mplex->setPos(x - 28, y); - mplex->show(y > BTN_H); + mplex->setPos(x - MPLEX_XO, y); + mplex->show(y > ListLineButton::BTN_H); } lv_obj_t* mplexLvObj() const { return mplex->getLvObj(); } @@ -160,6 +163,8 @@ class MixLineButton : public InputMixButtonBase } } + static LAYOUT_VAL(MPLEX_XO, 28, 28) + protected: MPlexIcon* mplex = nullptr; @@ -174,7 +179,7 @@ class MixGroup : public InputMixGroupBase { adjustHeight(); - lv_obj_set_pos(label, 2, -1); + lv_obj_set_pos(label, PAD_TINY, -1); lv_obj_t* chText = nullptr; if (idx >= MIXSRC_FIRST_CH && idx <= MIXSRC_LAST_CH && @@ -183,7 +188,7 @@ class MixGroup : public InputMixGroupBase 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_pos(chText, 2, 17); + lv_obj_set_pos(chText, PAD_TINY, CHNUM_Y); } refresh(); @@ -192,7 +197,7 @@ class MixGroup : public InputMixGroupBase void enableMixerMonitor() { if (!monitor) - monitor = new MixerChannelBar(this, {LCD_W - 118, 1, 100, 14}, idx - MIXSRC_FIRST_CH); + monitor = new MixerChannelBar(this, {LCD_W - CHBAR_XO, 1, CHBAR_W, CHBAR_H}, idx - MIXSRC_FIRST_CH); monitorVisible = true; monitor->show(); adjustHeight(); @@ -207,15 +212,20 @@ class MixGroup : public InputMixGroupBase void adjustHeight() override { - coord_t y = monitorVisible ? 17 : 2; + coord_t y = monitorVisible ? CHNUM_Y : PAD_TINY; for (auto it = lines.cbegin(); it != lines.cend(); ++it) { auto line = *it; - line->updatePos(LN_X, y); + line->updatePos(InputMixButtonBase::LN_X, y); y += line->height() + 2; } setHeight(y + 4); } + static LAYOUT_VAL(CHNUM_Y, 17, 17) + static LAYOUT_VAL(CHBAR_XO, 118, 118) + static LAYOUT_VAL(CHBAR_W, 100, 100) + static LAYOUT_VAL(CHBAR_H, 14, 14) + protected: MixerChannelBar* monitor = nullptr; bool monitorVisible = false; diff --git a/radio/src/gui/colorlcd/model_outputs.cpp b/radio/src/gui/colorlcd/model_outputs.cpp index 89a24785894..c710cef49e3 100644 --- a/radio/src/gui/colorlcd/model_outputs.cpp +++ b/radio/src/gui/colorlcd/model_outputs.cpp @@ -32,55 +32,6 @@ #define ETX_STATE_MINMAX_BOLD LV_STATE_USER_1 #define ETX_STATE_NAME_FONT_SMALL LV_STATE_USER_1 -#define CH_BAR_WIDTH 100 -#define CH_BAR_HEIGHT 16 - -#if LCD_W > LCD_H // Landscape - -#define CH_LINE_H 32 - -#define MIN_Y 4 -#define MAX_W 52 -#define OFF_X (MAX_X + MAX_W + 2) -#define OFF_Y 4 -#define OFF_W 44 -#define BAR_Y 6 - -#else // Portrait - -#define CH_LINE_H 50 - -#define MIN_Y 2 -#define MAX_W 60 -#define OFF_X (SRC_X + SRC_W + 2) -#define OFF_Y 24 -#define OFF_W 52 -#define BAR_Y 4 - -#endif - -#define SRC_X 2 -#define SRC_Y 1 -#define SRC_W 80 -#define SRC_H (CH_LINE_H - 6) -#define MIN_X (SRC_X + SRC_W + 2) -#define MIN_W 52 -#define MIN_H 20 -#define MAX_X (MIN_X + MIN_W + 2) -#define MAX_Y MIN_Y -#define MAX_H 20 -#define OFF_H 20 -#define CTR_X (OFF_X + OFF_W + 2) -#define CTR_Y OFF_Y -#define CTR_W 60 -#define CTR_H 20 -#define REV_X (CTR_X + CTR_W + 2) -#define REV_Y CTR_Y -#define REV_W 16 -#define CRV_X (REV_X + REV_W + 2) -#define CRV_Y (REV_Y + 1) -#define BAR_X (LCD_W - CH_BAR_WIDTH - 17) - class OutputLineButton : public ListLineButton { bool init = false; @@ -92,14 +43,15 @@ class OutputLineButton : public ListLineButton lv_obj_t* offset = nullptr; lv_obj_t* center = nullptr; StaticIcon* curve = nullptr; - OutputChannelBar* bar = nullptr; 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); if (line) { - if (!line->init) line->delayed_init(); + if (!line->init) + line->delayed_init(); + line->refresh(); } } @@ -107,6 +59,18 @@ class OutputLineButton : public ListLineButton { init = true; + lv_obj_enable_style_refresh(false); + + source = lv_label_create(lvobj); + lv_obj_set_pos(source, SRC_X, SRC_Y); + lv_obj_set_size(source, SRC_W, SRC_H); + +#if LCD_W > LCD_H + etx_font(source, FONT_XS_INDEX, ETX_STATE_NAME_FONT_SMALL); + lv_obj_set_style_pad_top(source, -2, ETX_STATE_NAME_FONT_SMALL); + lv_obj_set_style_text_line_space(source, -3, ETX_STATE_NAME_FONT_SMALL); +#endif + min = lv_label_create(lvobj); etx_obj_add_style(min, styles->text_align_right, LV_PART_MAIN); etx_font(min, FONT_BOLD_INDEX, ETX_STATE_MINMAX_BOLD); @@ -136,13 +100,15 @@ class OutputLineButton : public ListLineButton curve = new StaticIcon(this, CRV_X, CRV_Y, ICON_TEXTLINE_CURVE, COLOR_THEME_SECONDARY1); - bar = new OutputChannelBar(this, rect_t{BAR_X, BAR_Y, CH_BAR_WIDTH, CH_BAR_HEIGHT}, + new OutputChannelBar(this, rect_t{BAR_X, PAD_MEDIUM, CH_BAR_WIDTH, CH_BAR_HEIGHT}, index, false, false); - refresh(); checkEvents(); lv_obj_update_layout(lvobj); + + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); } public: @@ -152,16 +118,6 @@ class OutputLineButton : public ListLineButton setHeight(CH_LINE_H); padAll(PAD_ZERO); - source = lv_label_create(lvobj); - lv_obj_set_pos(source, SRC_X, SRC_Y); - lv_obj_set_size(source, SRC_W, SRC_H); - -#if LCD_W > LCD_H - etx_font(source, FONT_XS_INDEX, ETX_STATE_NAME_FONT_SMALL); - lv_obj_set_style_pad_top(source, -2, 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); } @@ -205,6 +161,38 @@ class OutputLineButton : public ListLineButton curve->show(output->curve); } + static LAYOUT_VAL(CH_LINE_H, 32, 50) + static LAYOUT_VAL(CH_BAR_WIDTH, 100, 100) + static LAYOUT_VAL(CH_BAR_HEIGHT, 16, 16) + static LAYOUT_VAL(BAR_XO, 17, 17) + static constexpr coord_t BAR_X = LCD_W - CH_BAR_WIDTH - BAR_XO; + + static constexpr coord_t SRC_X = PAD_TINY; + static constexpr coord_t SRC_Y = 1; + static LAYOUT_VAL(SRC_W, 80, 80) + static constexpr coord_t SRC_H = CH_LINE_H - PAD_MEDIUM; + static constexpr coord_t MIN_X = SRC_X + SRC_W + PAD_TINY; + static LAYOUT_VAL(MIN_Y, 4, 2) + static LAYOUT_VAL(MIN_W, 52, 52) + static LAYOUT_VAL(MIN_H, 20, 20) + static constexpr coord_t MAX_X = MIN_X + MIN_W + PAD_TINY; + static constexpr coord_t MAX_Y = MIN_Y; + static LAYOUT_VAL(MAX_W, 52, 60) + static constexpr coord_t MAX_H = MIN_H; + static LAYOUT_VAL(OFF_X, MAX_X + MAX_W + PAD_TINY, SRC_X + SRC_W + PAD_TINY) + static LAYOUT_VAL(OFF_Y, MIN_Y, 24) + static LAYOUT_VAL(OFF_W, 44, 52) + static constexpr coord_t OFF_H = MIN_H; + static constexpr coord_t CTR_X = OFF_X + OFF_W + PAD_TINY; + static constexpr coord_t CTR_Y = OFF_Y; + static LAYOUT_VAL(CTR_W, 60, 60) + static constexpr coord_t CTR_H = MIN_H; + static constexpr coord_t REV_X = CTR_X + CTR_W + PAD_TINY; + static constexpr coord_t REV_Y = CTR_Y; + static LAYOUT_VAL(REV_W, 16, 16) + static constexpr coord_t CRV_X = REV_X + REV_W + PAD_TINY; + static constexpr coord_t CRV_Y = REV_Y + 1; + protected: int value = -10000; @@ -242,34 +230,6 @@ ModelOutputsPage::ModelOutputsPage() : { } -#if LCD_W > LCD_H - -#define ADD_TRIMS_W ((LCD_W / 2) - 10) -#define EXLIM_X (ADD_TRIMS_X + ADD_TRIMS_W + 4) -#define EXLIM_Y 10 -#define EXLIMCB_Y 4 - -#else - -#define ADD_TRIMS_W (LCD_W - 12) -#define EXLIM_X 6 -#define EXLIM_Y (ADD_TRIMS_X + ADD_TRIMS_H + 8) -#define EXLIMCB_Y (ADD_TRIMS_X + ADD_TRIMS_H + 2) - -#endif - -#define ADD_TRIMS_X 6 -#define ADD_TRIMS_Y 4 -#define ADD_TRIMS_H 32 -#define EXLIM_W (EXLIMCB_X - EXLIM_X - 4) -#define EXLIM_H 20 -#define EXLIMCB_X (LCD_W - 58) -#define EXLIMCB_W 52 -#define EXLIMCB_H 32 -#define TRIMB_X 6 -#define TRIMB_Y (EXLIMCB_Y + EXLIMCB_H + 3) -#define TRIMB_W (LCD_W - 12) - void ModelOutputsPage::build(Window* window) { window->padAll(PAD_ZERO); @@ -286,7 +246,7 @@ void ModelOutputsPage::build(Window* window) for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) { // Channel settings auto btn = new OutputLineButton(window, ch); - lv_obj_set_pos(btn->getLvObj(), TRIMB_X, TRIMB_Y + (ch * (CH_LINE_H + 2))); + lv_obj_set_pos(btn->getLvObj(), TRIMB_X, TRIMB_Y + (ch * (OutputLineButton::CH_LINE_H + 2))); btn->setWidth(TRIMB_W); LimitData* output = limitAddress(ch); diff --git a/radio/src/gui/colorlcd/model_outputs.h b/radio/src/gui/colorlcd/model_outputs.h index 6c8738b19c1..0d571a08240 100644 --- a/radio/src/gui/colorlcd/model_outputs.h +++ b/radio/src/gui/colorlcd/model_outputs.h @@ -31,6 +31,23 @@ class ModelOutputsPage : public PageTab ModelOutputsPage(); void build(Window* window) override; + static constexpr coord_t ADD_TRIMS_X = PAD_MEDIUM; + static constexpr coord_t ADD_TRIMS_Y = PAD_SMALL; + static LAYOUT_VAL(ADD_TRIMS_W, (LCD_W / 2) - 10, LCD_W - 12) + static constexpr coord_t ADD_TRIMS_H = EdgeTxStyles::UI_ELEMENT_HEIGHT; + static LAYOUT_VAL(EXLIM_XO, 58, 58) + static constexpr coord_t EXLIMCB_X = LCD_W - EXLIM_XO; + static LAYOUT_VAL(EXLIMCB_Y, 4, ADD_TRIMS_X + ADD_TRIMS_H + 2) + static LAYOUT_VAL(EXLIMCB_W, 52, 52) + static constexpr coord_t EXLIMCB_H = EdgeTxStyles::UI_ELEMENT_HEIGHT; + static LAYOUT_VAL(EXLIM_X, ADD_TRIMS_X + ADD_TRIMS_W + PAD_SMALL, 6) + static LAYOUT_VAL(EXLIM_Y, 10, ADD_TRIMS_X + ADD_TRIMS_H + 8) + static constexpr coord_t EXLIM_W = EXLIMCB_X - EXLIM_X - PAD_SMALL; + static LAYOUT_VAL(EXLIM_H, 20, 20) + static constexpr coord_t TRIMB_X = PAD_MEDIUM; + static constexpr coord_t TRIMB_Y = EXLIMCB_Y + EXLIMCB_H + PAD_MEDIUM / 2; + static constexpr coord_t TRIMB_W = LCD_W - PAD_MEDIUM * 2; + protected: void editOutput(uint8_t channel, OutputLineButton* btn); }; diff --git a/radio/src/gui/colorlcd/model_select.cpp b/radio/src/gui/colorlcd/model_select.cpp index e0f8622eacf..07cd546d818 100644 --- a/radio/src/gui/colorlcd/model_select.cpp +++ b/radio/src/gui/colorlcd/model_select.cpp @@ -33,44 +33,28 @@ inline tmr10ms_t getTicks() { return g_tmr10ms; } -constexpr int BUTTONS_HEIGHT = 36; - struct ModelButtonLayout { uint16_t width; uint16_t height; uint16_t padding; bool hasImage; uint16_t font; + uint16_t columns; }; +static LAYOUT_VAL(L0_W, 165, 147) +static LAYOUT_VAL(L0_H, 92, 92) +static LAYOUT_VAL(L1_W, 108, 96) +static LAYOUT_VAL(L1_H, 61, 61) +static LAYOUT_VAL(L3_W, 336, 300) + ModelButtonLayout modelLayouts[] = { -#if LCD_W > LCD_H // Landscape - {165, 92, 6, true, FONT(STD)}, - {108, 61, 6, true, FONT(XS)}, - {165, 32, 4, false, FONT(STD)}, - {336, 32, 4, false, FONT(STD)}, -#else // Portrait - {147, 92, 6, true, FONT(STD)}, - {96, 61, 6, true, FONT(XS)}, - {147, 32, 4, false, FONT(STD)}, - {300, 32, 4, false, FONT(STD)}, -#endif + {L0_W, L0_H, PAD_SMALL, true, FONT(STD), 2}, + {L1_W, L1_H, PAD_SMALL, true, FONT(XS), 3}, + {L0_W, EdgeTxStyles::UI_ELEMENT_HEIGHT, PAD_SMALL, false, FONT(STD), 2}, + {L3_W, EdgeTxStyles::UI_ELEMENT_HEIGHT, PAD_SMALL, false, FONT(STD), 1}, }; -#if LCD_W > LCD_H // Landscape -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 LABELS_ROW = 1; -constexpr int MODELS_COL = 0; -constexpr int MODELS_ROW = 0; -constexpr int MODELS_ROW_CNT = 1; -constexpr int BUTTONS_ROW = 2; -#endif - class ModelButton : public Button { public: @@ -84,8 +68,6 @@ class ModelButton : public Button padAll(PAD_ZERO); lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); - setWidth(modelLayouts[layout].width); - setHeight(modelLayouts[layout].height); check(modelCell == modelslist.getCurrentModel()); @@ -185,17 +167,12 @@ class ModelsPageBody : public Window ModelsPageBody(Window *parent, const rect_t &rect) : Window(parent, rect) { padAll(PAD_TINY); - padLeft(PAD_MEDIUM); } void update() { clear(); - setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, - modelLayouts[g_eeGeneral.modelSelectLayout].padding); - padRow(modelLayouts[g_eeGeneral.modelSelectLayout].padding); - ModelsVector models; if (selectedLabels.size()) { models = modelslabels.getModelsInLabels(selectedLabels); @@ -211,9 +188,18 @@ class ModelsPageBody : public Window ModelButton *firstButton = nullptr; ModelButton *focusedButton = nullptr; + int n = 0; + int cols = modelLayouts[g_eeGeneral.modelSelectLayout].columns; + coord_t w = modelLayouts[g_eeGeneral.modelSelectLayout].width; + coord_t h = modelLayouts[g_eeGeneral.modelSelectLayout].height; + for (auto &model : models) { + coord_t x = (n % cols) * (w + PAD_TINY); + coord_t y = (n / cols) * (h + PAD_TINY); + n += 1; + auto button = new ModelButton( - this, rect_t{}, model, [=]() { focusedModel = model; }, + this, {x, y, w, h}, model, [=]() { focusedModel = model; }, g_eeGeneral.modelSelectLayout); if (!firstButton) firstButton = button; @@ -447,74 +433,12 @@ class ModelsPageBody : public Window //----------------------------------------------------------------------------- -class LabelDialog : public ModalWindow -{ - public: - LabelDialog(Window *parent, char *label, - std::function _saveHandler = nullptr) : - ModalWindow(parent, false), saveHandler(std::move(_saveHandler)) - { - strncpy(this->label, label, LABEL_LENGTH); - this->label[LABEL_LENGTH] = '\0'; - - 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; - }); - - new TextButton(box, rect_t{0, 0, 96, 0}, STR_SAVE, [=]() { - if (saveHandler != nullptr) saveHandler(this->label); - deleteLater(); - return 0; - }); - } - - void onCancel() override - { - deleteLater(); - } - - protected: - std::function saveHandler; - char label[LABEL_LENGTH + 1]; -}; - -//----------------------------------------------------------------------------- - class ModelLayoutButton : public IconButton { public: - ModelLayoutButton(Window *parent, uint8_t layout, + ModelLayoutButton(Window *parent, coord_t x, coord_t y, uint8_t layout, std::function pressHandler) : - IconButton(parent, (EdgeTxIcon)(ICON_MODEL_GRID_LARGE + layout), + IconButton(parent, (EdgeTxIcon)(ICON_MODEL_GRID_LARGE + layout), x, y, pressHandler), layout(layout) { @@ -526,7 +450,6 @@ class ModelLayoutButton : public IconButton { layout = newLayout; setIcon((EdgeTxIcon)(ICON_MODEL_GRID_LARGE + layout)); - // invalidate(); } protected: @@ -535,7 +458,7 @@ class ModelLayoutButton : public IconButton //----------------------------------------------------------------------------- -ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL, PAD_ZERO) +ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL, PAD_ZERO, true) { buildHead(header); buildBody(body); @@ -556,6 +479,8 @@ ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL, PAD_ZERO) lblselector->setSelected(getLabels().size() - 1); } } + + enableRefresh(); } #if defined(HARDWARE_KEYS) @@ -676,7 +601,7 @@ void ModelLabelsWindow::newModel() void ModelLabelsWindow::newLabel() { tmpLabel[0] = '\0'; - new LabelDialog(this, tmpLabel, [=](std::string label) { + new LabelDialog(this, tmpLabel, LABEL_LENGTH, STR_ENTER_LABEL, [=](std::string label) { int newlabindex = modelslabels.addLabel(label); if (newlabindex >= 0) { std::set newset; @@ -697,7 +622,7 @@ void ModelLabelsWindow::buildHead(Window *hdr) setTitle(); // new model button - auto btn = new TextButton(hdr, rect_t{0, 0, 60, 32}, STR_NEW, [=]() { + new TextButton(hdr, {LCD_W - NEW_BTN_W - PAD_LARGE, LAYOUT_BTN_YO, NEW_BTN_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, STR_NEW, [=]() { auto menu = new Menu(this); menu->setTitle(STR_CREATE_NEW); menu->addLine(STR_NEW_MODEL, [=]() { newModel(); }); @@ -705,13 +630,7 @@ void ModelLabelsWindow::buildHead(Window *hdr) return 0; }); - btn->padAll(PAD_SMALL); - - // button placement - hdr->padRight(lv_dpx(8)); - lv_obj_align(btn->getLvObj(), LV_ALIGN_RIGHT_MID, 0, 0); - - mdlLayout = new ModelLayoutButton(this, g_eeGeneral.modelSelectLayout, [=]() { + mdlLayout = new ModelLayoutButton(this, LCD_W - LAYOUT_BTN_XO, LAYOUT_BTN_YO, g_eeGeneral.modelSelectLayout, [=]() { uint8_t l = mdlLayout->getLayout(); l = (l + 1) & 3; mdlLayout->setLayout(l); @@ -720,74 +639,37 @@ void ModelLabelsWindow::buildHead(Window *hdr) mdlselector->update(); return 0; }); - lv_obj_set_pos(mdlLayout->getLvObj(), LCD_W - 105, 6); } -#if LCD_W > LCD_H -constexpr int LABELS_WIDTH = 132; -static const lv_coord_t col_dsc[] = {LABELS_WIDTH, LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_FR(1), BUTTONS_HEIGHT, - LV_GRID_TEMPLATE_LAST}; -#else -constexpr int LABELS_HEIGHT = 140; -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(1), LABELS_HEIGHT, - BUTTONS_HEIGHT, LV_GRID_TEMPLATE_LAST}; -#endif - void ModelLabelsWindow::buildBody(Window *window) { - window->padTop(6); - window->padBottom(6); - - lv_obj_set_grid_dsc_array(window->getLvObj(), col_dsc, row_dsc); - // Models List - mdlselector = new ModelsPageBody(window, rect_t{}); + mdlselector = new ModelsPageBody(window, {MDLS_X, MDLS_Y, MDLS_W, MDLS_H}); mdlselector->setLblRefreshFunc([=]() { labelRefreshRequest(); }); auto mdl_obj = mdlselector->getLvObj(); - lv_obj_set_grid_cell(mdl_obj, LV_GRID_ALIGN_STRETCH, MODELS_COL, 1, - LV_GRID_ALIGN_STRETCH, MODELS_ROW, MODELS_ROW_CNT); + lv_obj_set_style_max_width(mdl_obj, MDLS_W, LV_PART_MAIN); + lv_obj_set_style_max_height(mdl_obj, MDLS_H, LV_PART_MAIN); + etx_scrollbar(mdl_obj); if (mdlselector->getSortOrder() == NO_SORT) mdlselector->setSortOrder(NAME_ASC); // Labels - auto box = new Window(window, rect_t{}); - box->padAll(PAD_ZERO); - box->padLeft(6); -#if LCD_H > LCD_W - 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); lblselector = - new ListBox(box, rect_t{0, 0, LV_PCT(100), LV_PCT(100)}, getLabels()); + new ListBox(window, rect_t{PAD_SMALL, LABELS_Y, LABELS_WIDTH, LABELS_HEIGHT}, getLabels()); lblselector->setSmallSelectMarker(); auto lbl_obj = lblselector->getLvObj(); + etx_scrollbar(lbl_obj); + + lblselector->setColumnWidth(0, LABELS_WIDTH); // Sort Button - box = new Window(window, rect_t{}); - 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); new Choice( - box, {}, STR_SORT_ORDERS, NAME_ASC, DATE_DES, + window, {PAD_SMALL, LABELS_Y + LABELS_HEIGHT + PAD_SMALL, SORT_BUTTON_W, 0}, STR_SORT_ORDERS, NAME_ASC, DATE_DES, [=]() { return mdlselector->getSortOrder(); }, [=](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)); - - etx_scrollbar(lbl_obj); - etx_scrollbar(mdl_obj); - std::set filteredLabels = modelslabels.filteredLabels(); if (g_eeGeneral.labelSingleSelect == 0) { @@ -868,7 +750,7 @@ void ModelLabelsWindow::buildBody(Window *window) auto oldLabel = labels[selected]; strncpy(tmpLabel, oldLabel.c_str(), LABEL_LENGTH); tmpLabel[LABEL_LENGTH] = '\0'; - new LabelDialog(this, tmpLabel, [=](std::string newLabel) { + new LabelDialog(this, tmpLabel, LABEL_LENGTH, STR_ENTER_LABEL, [=](std::string newLabel) { if (newLabel.size() > 0) { auto rndialog = new ProgressDialog(this, STR_RENAME_LABEL, [=]() {}); diff --git a/radio/src/gui/colorlcd/model_select.h b/radio/src/gui/colorlcd/model_select.h index c08f8a15ef6..98dca981918 100644 --- a/radio/src/gui/colorlcd/model_select.h +++ b/radio/src/gui/colorlcd/model_select.h @@ -33,6 +33,18 @@ class ModelLabelsWindow : public Page public: ModelLabelsWindow(); + static LAYOUT_VAL(NEW_BTN_W, 60, 60) + static constexpr coord_t LAYOUT_BTN_XO = NEW_BTN_W + PAD_LARGE * 2 + EdgeTxStyles::UI_ELEMENT_HEIGHT; + static LAYOUT_VAL(LAYOUT_BTN_YO, 6, 6) + static LAYOUT_VAL(MDLS_X, 137, 4) + static LAYOUT_VAL(MDLS_Y, 4, 4) + static LAYOUT_VAL(MDLS_W, 343, LCD_W - PAD_MEDIUM) + static LAYOUT_VAL(MDLS_H, 219, 219) + static LAYOUT_VAL(LABELS_Y, PAD_SMALL, MDLS_Y + MDLS_H + PAD_SMALL) + static LAYOUT_VAL(LABELS_WIDTH, 131, LCD_W - PAD_SMALL * 2) + static LAYOUT_VAL(LABELS_HEIGHT, 181, 166) + static LAYOUT_VAL(SORT_BUTTON_W, LABELS_WIDTH, 120) + protected: ModelsSortBy sort = DEFAULT_MODEL_SORT; char tmpLabel[LABEL_LENGTH + 1] = "\0"; diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 200cd8cc084..702236383a2 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -97,189 +97,125 @@ struct ModelBitmapEdit : public FileChoice { } }; -class SubScreenButton : public TextButton +static void viewOption(Window* parent, coord_t x, coord_t y, + std::function getValue, + std::function setValue, bool globalState) { - 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); - - 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); - - setCheckHandler([=]() { check(isActive()); }); - check(isActive()); - } - - protected: - std::function m_isActive = nullptr; - - 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), - LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; + auto lbl = new StaticText(parent, {x + ModelSetupPage::OPTS_W + PAD_MEDIUM, y + PAD_SMALL + 1, 0, 0}, + STR_ADCFILTERVALUES[globalState ? 1 : 2], COLOR_THEME_SECONDARY1); + new Choice(parent, {x, y, ModelSetupPage::OPTS_W, 0}, STR_ADCFILTERVALUES, 0, 2, getValue, + [=](int newValue) { + setValue(newValue); + lbl->show(newValue == 0); + }); + lbl->show(getValue() == 0); +} -class ModelViewOptions : public Page -{ - public: - class OptChoice : Window +static SetupLineDef viewOptionsPageSetupLines[] = { + { + STR_RADIO_MENU_TABS, nullptr, + }, { - public: - 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)) - { - 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(); + STR_THEME_EDITOR, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.radioThemesDisabled), + g_eeGeneral.radioThemesDisabled); } - - protected: - StaticText *m_lbl; - std::function m_getValue; - std::function m_setValue; - - void setState() - { - m_lbl->show(m_getValue() == 0); + }, + { + STR_MENUSPECIALFUNCS, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.radioGFDisabled), + g_eeGeneral.radioGFDisabled); } - }; - - FormLine* optLine(FlexGridLayout& grid) + }, { - auto line = body->newLine(grid); - line->padAll(PAD_ZERO); - line->padLeft(10); - return line; - } - - ModelViewOptions() : Page(ICON_MODEL_SETUP) + STR_MENUTRAINER, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.radioTrainerDisabled), + g_eeGeneral.radioTrainerDisabled); + } + }, + { + STR_MODEL_MENU_TABS, nullptr, + }, { - header->setTitle(STR_MENU_MODEL_SETUP); - header->setTitle2(STR_ENABLED_FEATURES); - - body->padAll(PAD_TINY); - body->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); - - FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); - - auto line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_RADIO_MENU_TABS); - - line = optLine(grid); - new StaticText(line, rect_t{}, STR_THEME_EDITOR); - 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_MENUSPECIALFUNCS); - 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_MENUTRAINER); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, - GET_SET_DEFAULT(g_model.radioTrainerDisabled), - g_eeGeneral.radioTrainerDisabled); - - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_MODEL_MENU_TABS); - #if defined(HELI) - line = optLine(grid); - new StaticText(line, rect_t{}, STR_MENUHELISETUP); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, - GET_SET_DEFAULT(g_model.modelHeliDisabled), - g_eeGeneral.modelHeliDisabled); + STR_MENUHELISETUP, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.modelHeliDisabled), + g_eeGeneral.modelHeliDisabled); + } + }, #endif - #if defined(FLIGHT_MODES) - line = optLine(grid); - new StaticText(line, rect_t{}, STR_MENUFLIGHTMODES); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, - GET_SET_DEFAULT(g_model.modelFMDisabled), - g_eeGeneral.modelFMDisabled); + { + STR_MENUFLIGHTMODES, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.modelFMDisabled), + g_eeGeneral.modelFMDisabled); + } + }, #endif - #if defined(GVARS) - line = optLine(grid); - new StaticText(line, rect_t{}, STR_MENU_GLOBAL_VARS); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, - GET_SET_DEFAULT(g_model.modelGVDisabled), - g_eeGeneral.modelGVDisabled); + { + STR_MENU_GLOBAL_VARS, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.modelGVDisabled), + g_eeGeneral.modelGVDisabled); + } + }, #endif - - line = optLine(grid); - new StaticText(line, rect_t{}, STR_MENUCURVES); - 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); - 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); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, - GET_SET_DEFAULT(g_model.modelSFDisabled), - g_eeGeneral.modelSFDisabled); - + { + STR_MENUCURVES, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.modelCurvesDisabled), + g_eeGeneral.modelCurvesDisabled); + } + }, + { + STR_MENULOGICALSWITCHES, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.modelLSDisabled), + g_eeGeneral.modelLSDisabled); + } + }, + { + STR_MENUCUSTOMFUNC, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.modelSFDisabled), + g_eeGeneral.modelSFDisabled); + } + }, #if defined(LUA_MODEL_SCRIPTS) - line = optLine(grid); - new StaticText(line, rect_t{}, STR_MENUCUSTOMSCRIPTS); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, - GET_SET_DEFAULT(g_model.modelCustomScriptsDisabled), - g_eeGeneral.modelCustomScriptsDisabled); + { + STR_MENUCUSTOMSCRIPTS, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.modelCustomScriptsDisabled), + g_eeGeneral.modelCustomScriptsDisabled); + } + }, #endif - - line = optLine(grid); - new StaticText(line, rect_t{}, STR_MENUTELEMETRY); - new OptChoice(line, STR_ADCFILTERVALUES, 0, 2, - GET_SET_DEFAULT(g_model.modelTelemetryDisabled), - g_eeGeneral.modelTelemetryDisabled); - } + { + STR_MENUTELEMETRY, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_DEFAULT(g_model.modelTelemetryDisabled), + g_eeGeneral.modelTelemetryDisabled); + } + }, }; -#if LCD_W > LCD_H -#define SW_BTNS 8 -#define SW_BTN_W 56 -#else -#define SW_BTNS 4 -#define SW_BTN_W 72 -#endif - struct CenterBeepsMatrix : public ButtonMatrix { CenterBeepsMatrix(Window* parent, const rect_t& rect) : ButtonMatrix(parent, rect) @@ -351,139 +287,106 @@ struct CenterBeepsMatrix : public ButtonMatrix { setChecked(btn_id); } + static LAYOUT_VAL(SW_BTNS, 8, 4) + static LAYOUT_VAL(SW_BTN_W, 56, 72) + static LAYOUT_VAL(SW_BTN_H, 36, 36) + private: uint8_t max_analogs; uint8_t ana_idx[MAX_ANALOG_INPUTS]; }; -class ModelOtherOptions : public Page -{ - public: - ModelOtherOptions() : Page(ICON_MODEL_SETUP) - { - header->setTitle(STR_MENU_MODEL_SETUP); - header->setTitle2(STR_MENU_OTHER); - - body->padAll(PAD_SMALL); - - body->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); - - FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_SMALL); - - // Model ADC jitter filter - auto line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_JITTER_FILTER); - new Choice(line, rect_t{}, STR_ADCFILTERVALUES, 0, 2, +static SetupLineDef otherPageSetupLines[] = { + { + STR_JITTER_FILTER, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.jitterFilter)); + } + }, + { + STR_BEEPCTR, [](Window* parent, coord_t x, coord_t y) {} + }, + { + nullptr, + [](Window* parent, coord_t x, coord_t y) { + new CenterBeepsMatrix(parent, {PAD_MEDIUM, y, 0, 0}); + } + }, +}; - // Center beeps - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_BEEPCTR); - line = body->newLine(grid); - line->padLeft(4); - new CenterBeepsMatrix(line, rect_t{}); +static SetupLineDef setupLines[] = { + { + // Model name + STR_MODELNAME, + [](Window* parent, coord_t x, coord_t y) { + new ModelNameEdit(parent, {x, y, ModelSetupPage::NAM_W, 0}); + } + }, + { + // Model labels + STR_LABELS, + [](Window* parent, coord_t x, coord_t y) { + auto curmod = modelslist.getCurrentModel(); + TextButton* btn = new TextButton(parent, {x, y, 0, 0}, modelslabels.getBulletLabelString(curmod, STR_UNLABELEDMODEL)); + btn->setPressHandler([=]() { + Menu *menu = new Menu(MainWindow::instance(), 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); + btn->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; + }); } + }, + { + // Model bitmap + STR_BITMAP, + [](Window* parent, coord_t x, coord_t y) { + // TODO: show bitmap thumbnail instead? + new ModelBitmapEdit(parent, {x, y, 0, 0}); + } + }, }; void ModelSetupPage::build(Window * window) { - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); - - FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); - - // Model name - auto line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_MODELNAME); - new ModelNameEdit(line, {0, 0, LCD_W / 2 - 20, 0}); - - // Model labels - line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_LABELS); - 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; - }); - - // Bitmap - line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_BITMAP); - // TODO: show bitmap thumbnail instead? - new ModelBitmapEdit(line, rect_t{}); - - 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); - - 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); - 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); - 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->padTop(2); - - new SubScreenButton(line, STR_ENABLED_FEATURES, - []() { new ModelViewOptions(); }); - + coord_t y = SetupLine::showLines(window, 0, SubPage::EDT_X, padding, setupLines, DIM(setupLines)); + + new SetupButtonGroup(window, {0, y, LCD_W - padding * 2, 0}, nullptr, BTN_COLS, PAD_TINY, { + // Modules + {STR_INTERNALRF, []() { new ModulePage(INTERNAL_MODULE); }, []() { return g_model.moduleData[INTERNAL_MODULE].type > 0; }}, + {STR_EXTERNALRF, []() { new ModulePage(EXTERNAL_MODULE); }, []() { return g_model.moduleData[EXTERNAL_MODULE].type > 0; }}, + {STR_TRAINER, []() { new TrainerPage(); }, []() { return g_model.trainerData.mode > 0; }}, + // Timer buttons + {TR_TIMER "1", []() { new TimerWindow(0); }, []() { return g_model.timers[0].mode > 0; }}, + {TR_TIMER "2", []() { new TimerWindow(1); }, []() { return g_model.timers[1].mode > 0; }}, + {TR_TIMER "3", []() { new TimerWindow(2); }, []() { return g_model.timers[2].mode > 0; }}, + + {STR_PREFLIGHT, []() { new PreflightChecks(); }}, + {STR_TRIMS, []() { new TrimsSetup(); }}, + {STR_THROTTLE_LABEL, []() { new ThrottleParams(); }}, + {STR_ENABLED_FEATURES, []() { new SubPage(ICON_MODEL_SETUP, STR_MENU_MODEL_SETUP, STR_ENABLED_FEATURES, viewOptionsPageSetupLines, DIM(viewOptionsPageSetupLines)); }}, #if defined(USBJ_EX) - new SubScreenButton(line, STR_USBJOYSTICK_LABEL, - []() { new ModelUSBJoystickPage(); }); + {STR_USBJOYSTICK_LABEL, []() { new ModelUSBJoystickPage(); }}, #endif - - new SubScreenButton(line, STR_MENU_OTHER, []() { new ModelOtherOptions(); }); + {STR_MENU_OTHER, []() { new SubPage(ICON_MODEL_SETUP, STR_MENU_MODEL_SETUP, STR_MENU_OTHER, otherPageSetupLines, DIM(otherPageSetupLines)); }}, + }, BTN_H); } diff --git a/radio/src/gui/colorlcd/model_setup.h b/radio/src/gui/colorlcd/model_setup.h index 15f38172c03..627ed77092a 100644 --- a/radio/src/gui/colorlcd/model_setup.h +++ b/radio/src/gui/colorlcd/model_setup.h @@ -24,10 +24,16 @@ #include "tabsgroup.h" class ModelSetupPage: public PageTab { - public: - ModelSetupPage(); + public: + ModelSetupPage(); - void build(Window * window) override; - private: - TextButton *labelTextButton = nullptr; + void build(Window * window) override; + + static LAYOUT_VAL(BTN_COLS, 3, 3) + static LAYOUT_VAL(BTN_H, 62, 62) + static LAYOUT_VAL(OPTS_W, 100, 100) + static LAYOUT_VAL(NAM_W, 200, 140) + + private: + TextButton *labelTextButton = nullptr; }; diff --git a/radio/src/gui/colorlcd/model_telemetry.cpp b/radio/src/gui/colorlcd/model_telemetry.cpp index 496de81c2a1..9a1b3df4c85 100644 --- a/radio/src/gui/colorlcd/model_telemetry.cpp +++ b/radio/src/gui/colorlcd/model_telemetry.cpp @@ -36,7 +36,7 @@ std::string getSensorCustomValue(uint8_t sensor, int32_t value, LcdFlags flags); -#if (LCD_H > LCD_W) || defined(TRANSLATIONS_CZ) +#if (PORTRAIT_LCD) || defined(TRANSLATIONS_CZ) #define TWOCOLBUTTONS 1 #else #define TWOCOLBUTTONS 0 @@ -64,10 +64,6 @@ static const lv_coord_t e_col_dsc2[] = {LV_GRID_FR(4), LV_GRID_FR(3), static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -#define BTN_H 32 -#define NUM_W 36 -#define NAME_W 56 - class TSStyle { public: @@ -94,6 +90,13 @@ class TSStyle lv_style_t tsFreshStyle; + static LAYOUT_VAL(NUM_W, 36, 36) + static LAYOUT_VAL(NUM_H, 20, 20) + static LAYOUT_VAL(NAME_W, 56, 56) + static LAYOUT_VAL(ID_Y, 17, 17) + static LAYOUT_VAL(ID_H, 11, 11) + static LAYOUT_VAL(FRSH_Y, 10, 10) + private: bool styleInitDone; }; @@ -112,8 +115,8 @@ static const lv_obj_class_t ts_num_class = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = NUM_W, - .height_def = 20, + .width_def = TSStyle::NUM_W, + .height_def = TSStyle::NUM_H, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_label_t), @@ -139,8 +142,8 @@ static const lv_obj_class_t ts_id_class = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = NUM_W, - .height_def = 11, + .width_def = TSStyle::NUM_W, + .height_def = TSStyle::ID_H, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_label_t), @@ -165,8 +168,8 @@ static const lv_obj_class_t ts_name_class = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = NAME_W, - .height_def = 20, + .width_def = TSStyle::NAME_W, + .height_def = TSStyle::NUM_H, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_label_t), @@ -193,7 +196,7 @@ static const lv_obj_class_t ts_value_class = { .user_data = nullptr, .event_cb = nullptr, .width_def = LV_SIZE_CONTENT, - .height_def = 20, + .height_def = TSStyle::NUM_H, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_label_t), @@ -220,7 +223,7 @@ static void ts_fresh_icon_constructor(const lv_obj_class_t* class_p, }; 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_canvas_set_buffer(obj, (void*)freshBitmap, PAD_LARGE, PAD_LARGE, LV_IMG_CF_ALPHA_8BIT); lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); } @@ -230,8 +233,8 @@ static const lv_obj_class_t ts_fresh_icon_class = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = 8, - .height_def = 8, + .width_def = PAD_LARGE, + .height_def = PAD_LARGE, .editable = LV_OBJ_CLASS_EDITABLE_FALSE, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_canvas_t), @@ -244,7 +247,7 @@ class SensorButton : public ListLineButton ListLineButton(parent, index) { padAll(PAD_ZERO); - setHeight(BTN_H); + setHeight(EdgeTxStyles::UI_ELEMENT_HEIGHT); check(isActive()); @@ -260,6 +263,7 @@ class SensorButton : public ListLineButton lv_obj_t* valLabel = nullptr; lv_obj_t* fresh = nullptr; uint32_t lastRefresh = 0; + std::string valString; static void on_draw(lv_event_t* e) { @@ -267,8 +271,7 @@ class SensorButton : public ListLineButton auto line = (SensorButton*)lv_obj_get_user_data(target); if (line) { if (!line->init) - line->delayed_init(e); - line->refresh(); + line->delayed_init(); } } @@ -294,36 +297,41 @@ class SensorButton : public ListLineButton refresh(); } - void delayed_init(lv_event_t* e) + void delayed_init() { char s[20]; init = true; + lv_obj_enable_style_refresh(false); + numLabel = tsStyle.newNum(lvobj, index); - lv_obj_set_pos(numLabel, 2, 3); + lv_obj_set_pos(numLabel, PAD_TINY, PAD_MEDIUM/2); TelemetrySensor* sensor = &g_model.telemetrySensors[index]; if (sensor->type == TELEM_TYPE_CUSTOM) { sprintf(s, "ID: %d", sensor->instance); idLabel = tsStyle.newId(lvobj, s); - lv_obj_set_pos(idLabel, 2, 17); + lv_obj_set_pos(idLabel, PAD_TINY, TSStyle::ID_Y); } setNumIdState(); strAppend(s, g_model.telemetrySensors[index].label, TELEM_LABEL_LEN); lv_obj_t* nm = tsStyle.newName(lvobj, s); - lv_obj_set_pos(nm, NUM_W + 4, 3); + lv_obj_set_pos(nm, TSStyle::NUM_W + PAD_SMALL, PAD_MEDIUM/2); fresh = etx_create(&ts_fresh_icon_class, lvobj); - lv_obj_set_pos(fresh, NUM_W + NAME_W + 6, 10); + lv_obj_set_pos(fresh, TSStyle::NUM_W + TSStyle::NAME_W + PAD_MEDIUM, TSStyle::FRSH_Y); valLabel = tsStyle.newValue(lvobj); - lv_obj_set_pos(valLabel, NUM_W + NAME_W + 16, 3); + lv_obj_set_pos(valLabel, TSStyle::NUM_W + TSStyle::NAME_W + PAD_LARGE * 2, PAD_MEDIUM/2); lv_obj_update_layout(lvobj); + + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); } void refresh() override @@ -362,7 +370,10 @@ class SensorButton : public ListLineButton else lv_obj_clear_state(valLabel, ETX_STATE_VALUE_STALE_WARN); - lv_label_set_text(valLabel, s.c_str()); + if (valString != s) { + valString = s; + lv_label_set_text(valLabel, s.c_str()); + } } } }; @@ -669,7 +680,7 @@ class SensorEditWindow : public Page new StaticText(paramLines[P_ID], rect_t{}, STR_ID); auto num = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xFFFF, GET_SET_DEFAULT(sensor->id)); -#if LCD_H > LCD_W +#if PORTRAIT_LCD // Portrait layout - need to limit width of edit box num->setWidth((lv_pct(28))); #endif @@ -683,7 +694,7 @@ class SensorEditWindow : public Page }); num = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xff, GET_SET_DEFAULT(sensor->instance)); -#if LCD_H > LCD_W +#if PORTRAIT_LCD // Portrait layout - need to limit width of edit box num->setWidth(lv_pct(28)); #endif @@ -928,12 +939,6 @@ void ModelTelemetryPage::buildSensorList(int8_t focusSensorIndex) deleteAll->show(sensorsCount > 0); } -#if LCD_W > LCD_H -#define NUM_EDIT_W 100 -#else -#define NUM_EDIT_W 65 -#endif - void ModelTelemetryPage::build(Window* window) { window->padAll(PAD_TINY); diff --git a/radio/src/gui/colorlcd/model_telemetry.h b/radio/src/gui/colorlcd/model_telemetry.h index eb9f4fa7410..15258304561 100644 --- a/radio/src/gui/colorlcd/model_telemetry.h +++ b/radio/src/gui/colorlcd/model_telemetry.h @@ -33,6 +33,8 @@ class ModelTelemetryPage : public PageTab void build(Window* window) override; + static LAYOUT_VAL(NUM_EDIT_W, 100, 65) + protected: int lastKnownIndex = 0; Window* window = nullptr; diff --git a/radio/src/gui/colorlcd/model_templates.cpp b/radio/src/gui/colorlcd/model_templates.cpp index 0a306b40b6c..ecf81e9112b 100644 --- a/radio/src/gui/colorlcd/model_templates.cpp +++ b/radio/src/gui/colorlcd/model_templates.cpp @@ -135,7 +135,7 @@ class SelectTemplate : public TemplatePage for (auto name : files) { auto tb = new TextButton( - listWindow, rect_t{0, 0, lv_pct(100), PAGE_LINE_HEIGHT * 2}, name, + listWindow, rect_t{0, 0, lv_pct(100), EdgeTxStyles::PAGE_LINE_HEIGHT * 2}, name, [=]() -> uint8_t { deleteLater(); templateFolderPage->doUpdate(folder, name); @@ -176,7 +176,7 @@ SelectTemplateFolder::SelectTemplateFolder( header->setTitle2(STR_NEW_MODEL); auto tfb = new TextButton(listWindow, - rect_t{0, 0, lv_pct(100), PAGE_LINE_HEIGHT * 2}, + rect_t{0, 0, lv_pct(100), EdgeTxStyles::PAGE_LINE_HEIGHT * 2}, STR_BLANK_MODEL, [=]() -> uint8_t { doUpdate("", ""); return 0; @@ -215,7 +215,7 @@ SelectTemplateFolder::SelectTemplateFolder( if (!strcasecmp(name.c_str(), "WIZARD") == 0) { #endif auto tfb = new TextButton( - listWindow, rect_t{0, 0, lv_pct(100), PAGE_LINE_HEIGHT * 2}, name, + listWindow, rect_t{0, 0, lv_pct(100), EdgeTxStyles::PAGE_LINE_HEIGHT * 2}, name, [=]() -> uint8_t { new SelectTemplate(this, name); return 0; diff --git a/radio/src/gui/colorlcd/model_usbjoystick.cpp b/radio/src/gui/colorlcd/model_usbjoystick.cpp index 1e020635157..dbbb67821d8 100644 --- a/radio/src/gui/colorlcd/model_usbjoystick.cpp +++ b/radio/src/gui/colorlcd/model_usbjoystick.cpp @@ -32,7 +32,7 @@ #define ETX_STATE_COLLISION_WARN LV_STATE_USER_1 -#if LCD_W > LCD_H // Landscape +#if !PORTRAIT_LCD // Landscape static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), @@ -289,7 +289,7 @@ class USBChannelEditWindow : public Page window, {window->getRect().w - USBCH_EDIT_STATUS_BAR_WIDTH - USBCH_EDIT_RIGHT_MARGIN, - 0, USBCH_EDIT_STATUS_BAR_WIDTH, MENU_HEADER_HEIGHT}, + 0, USBCH_EDIT_STATUS_BAR_WIDTH, EdgeTxStyles::MENU_HEADER_HEIGHT}, channel); } @@ -306,7 +306,7 @@ class USBChannelEditWindow : public Page 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 +#if PORTRAIT_LCD line = form->newLine(grid); #endif @@ -331,7 +331,7 @@ class USBChannelEditWindow : public Page this->update(); }); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = m_btnModeFrame->newLine(grid); #endif @@ -342,7 +342,7 @@ class USBChannelEditWindow : public Page line = m_btnModeFrame->newLine(grid); new StaticText(line, rect_t{}, STR_USBJOYSTICK_CH_BTNNUM); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = m_btnModeFrame->newLine(grid); #endif _BtnNumSel = new USBChannelButtonSel(line, rect_t{}, channel, @@ -381,7 +381,7 @@ class USBChannelLineButton : public ListLineButton ListLineButton(parent, index) { setHeight(USBCH_LINE_HEIGHT); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD padTop(4); #endif @@ -400,14 +400,15 @@ class USBChannelLineButton : public ListLineButton auto line = (USBChannelLineButton*)lv_obj_get_user_data(target); if (line) { if (!line->init) - line->delayed_init(e); - else - line->refresh(); + line->delayed_init(); + line->refresh(); } } - void delayed_init(lv_event_t* e) + void delayed_init() { + init = true; + m_chn = lv_label_create(lvobj); lv_obj_set_grid_cell(m_chn, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_CENTER, 0, USBCH_CHN_ROWS); @@ -442,15 +443,7 @@ class USBChannelLineButton : public ListLineButton lv_label_set_text(m_btn_mode, ""); lv_label_set_text(m_btns, ""); - init = true; - refresh(); - lv_obj_update_layout(lvobj); - - if (e) { - auto param = lv_event_get_param(e); - lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param); - } } void refresh() override @@ -536,7 +529,7 @@ ModelUSBJoystickPage::ModelUSBJoystickPage() : Page(ICON_MODEL_USB) GET_DEFAULT(g_model.usbJoystickExtMode), SET_VALUE_WUPDATE(g_model.usbJoystickExtMode)); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = body->newLine(grid); #endif @@ -554,7 +547,7 @@ ModelUSBJoystickPage::ModelUSBJoystickPage() : Page(ICON_MODEL_USB) GET_DEFAULT(g_model.usbJoystickCircularCut), SET_VALUE_WUPDATE(g_model.usbJoystickCircularCut)); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = body->newLine(grid); #endif diff --git a/radio/src/gui/colorlcd/output_edit.cpp b/radio/src/gui/colorlcd/output_edit.cpp index 6a70d45e92e..b41a9761462 100644 --- a/radio/src/gui/colorlcd/output_edit.cpp +++ b/radio/src/gui/colorlcd/output_edit.cpp @@ -30,15 +30,10 @@ #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 -#else -#define OUTPUT_EDIT_STATUS_BAR_WIDTH 180 -#define OUTPUT_EDIT_STATUS_BAR_MARGIN 0 -#define OUTPUT_EDIT_RIGHT_MARGIN 3 -#endif +// deadband in % for switching direction of Min/Max text and value field highlighting +// 0 = no deadband +// 1..100 = [-DEADBAND; DEADBAND] +#define DEADBAND 0 // deadband in % for switching direction of Min/Max text and value field highlighting // 0 = no deadband @@ -58,6 +53,8 @@ class OutputEditStatusBar : public Window channel, true); } + static LAYOUT_VAL(OUTPUT_EDIT_STATUS_BAR_MARGIN, 3, 0) + protected: ComboChannelBar *channelBar; int8_t _channel; @@ -108,11 +105,11 @@ void OutputEditWindow::buildHeader(Window *window) window, {window->getRect().w - OUTPUT_EDIT_STATUS_BAR_WIDTH - OUTPUT_EDIT_RIGHT_MARGIN, - 0, OUTPUT_EDIT_STATUS_BAR_WIDTH, MENU_HEADER_HEIGHT}, + 0, OUTPUT_EDIT_STATUS_BAR_WIDTH, EdgeTxStyles::MENU_HEADER_HEIGHT}, channel); } -#if LCD_W > LCD_H +#if !PORTRAIT_LCD static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; @@ -139,7 +136,7 @@ void OutputEditWindow::buildBody(Window *form) // Offset new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_SUBTRIM); - auto off = new GVarNumberEdit(line, rect_t{}, -LIMIT_STD_MAX, +LIMIT_STD_MAX, + auto off = new GVarNumberEdit(line, -LIMIT_STD_MAX, +LIMIT_STD_MAX, GET_SET_DEFAULT(output->offset), PREC1); off->setFastStep(20); off->setAccelFactor(8); @@ -149,7 +146,7 @@ void OutputEditWindow::buildBody(Window *form) minText = new StaticText(line, rect_t{}, TR_MIN); 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, + minEdit = new GVarNumberEdit(line, -limit, 0, GET_SET_DEFAULT(output->min), PREC1, -LIMIT_STD_MAX, -limit); etx_font(minEdit->getLvObj(), FONT_BOLD_INDEX, ETX_STATE_MINMAX_HIGHLIGHT); @@ -160,7 +157,7 @@ void OutputEditWindow::buildBody(Window *form) maxText = new StaticText(line, rect_t{}, TR_MAX); 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, + maxEdit = new GVarNumberEdit(line, 0, +limit, GET_SET_DEFAULT(output->max), PREC1, +LIMIT_STD_MAX, limit); etx_font(maxEdit->getLvObj(), FONT_BOLD_INDEX, ETX_STATE_MINMAX_HIGHLIGHT); diff --git a/radio/src/gui/colorlcd/output_edit.h b/radio/src/gui/colorlcd/output_edit.h index eeb0aa0e5da..95556c9897a 100644 --- a/radio/src/gui/colorlcd/output_edit.h +++ b/radio/src/gui/colorlcd/output_edit.h @@ -31,6 +31,9 @@ class OutputEditWindow : public Page public: explicit OutputEditWindow(uint8_t channel); + static LAYOUT_VAL(OUTPUT_EDIT_STATUS_BAR_WIDTH, 250, 180) + static LAYOUT_VAL(OUTPUT_EDIT_RIGHT_MARGIN, 0, 3) + protected: uint8_t channel; int value = 0; diff --git a/radio/src/gui/colorlcd/page.cpp b/radio/src/gui/colorlcd/page.cpp index cb450628907..e8537b7e6bf 100644 --- a/radio/src/gui/colorlcd/page.cpp +++ b/radio/src/gui/colorlcd/page.cpp @@ -26,7 +26,7 @@ #include "view_main.h" PageHeader::PageHeader(Page* parent, EdgeTxIcon icon) : - Window(parent, {0, 0, LCD_W, MENU_HEADER_HEIGHT}), + Window(parent, {0, 0, LCD_W, EdgeTxStyles::MENU_HEADER_HEIGHT}), icon(icon) { setWindowFlag(NO_FOCUS | OPAQUE); @@ -37,7 +37,7 @@ PageHeader::PageHeader(Page* parent, EdgeTxIcon icon) : title = new StaticText(this, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, - LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, + LCD_W - PAGE_TITLE_LEFT, EdgeTxStyles::PAGE_LINE_HEIGHT}, "", COLOR_THEME_PRIMARY2); } @@ -45,24 +45,27 @@ StaticText* PageHeader::setTitle2(std::string txt) { if (title2 == nullptr) { title2 = new StaticText(this, - {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, - LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, + {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + EdgeTxStyles::PAGE_LINE_HEIGHT, + LCD_W - PAGE_TITLE_LEFT, EdgeTxStyles::PAGE_LINE_HEIGHT}, "", COLOR_THEME_PRIMARY2); } title2->setText(std::move(txt)); return title2; } -Page::Page(EdgeTxIcon icon, PaddingSize padding) : +Page::Page(EdgeTxIcon icon, PaddingSize padding, bool pauseRefresh) : NavWindow(MainWindow::instance(), {0, 0, LCD_W, LCD_H}) { + if (pauseRefresh) + lv_obj_enable_style_refresh(false); + header = new PageHeader(this, icon); body = new Window(this, - {0, MENU_HEADER_HEIGHT, LCD_W, LCD_H - MENU_HEADER_HEIGHT}); + {0, EdgeTxStyles::MENU_HEADER_HEIGHT, LCD_W, LCD_H - EdgeTxStyles::MENU_HEADER_HEIGHT}); body->setWindowFlag(NO_FOCUS); etx_solid_bg(lvobj); - lv_obj_set_style_max_height(body->getLvObj(), LCD_H - MENU_HEADER_HEIGHT, + lv_obj_set_style_max_height(body->getLvObj(), LCD_H - EdgeTxStyles::MENU_HEADER_HEIGHT, LV_PART_MAIN); etx_scrollbar(body->getLvObj()); @@ -93,3 +96,38 @@ void Page::checkEvents() ViewMain::instance()->runBackground(); NavWindow::checkEvents(); } + +void Page::enableRefresh() +{ + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); +} + +SubPage::SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, bool pauseRefresh) : + Page(icon, PAD_SMALL, pauseRefresh) +{ + body->padBottom(PAD_LARGE * 2); + + header->setTitle(title); + header->setTitle2(subtitle); +} + +SubPage::SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, SetupLineDef* setupLines, int lineCount) : + Page(icon, PAD_SMALL, true) +{ + body->padBottom(PAD_LARGE * 2); + + header->setTitle(title); + header->setTitle2(subtitle); + + SetupLine::showLines(body, y, EDT_X, PAD_SMALL, setupLines, lineCount); + + enableRefresh(); +} + +Window* SubPage::setupLine(const char* title, std::function createEdit, coord_t lblYOffset) +{ + auto w = new SetupLine(body, y, EDT_X, PAD_SMALL, title, createEdit, lblYOffset); + y += w->height(); + return w; +} diff --git a/radio/src/gui/colorlcd/page.h b/radio/src/gui/colorlcd/page.h index cc23a16486a..80660f95489 100644 --- a/radio/src/gui/colorlcd/page.h +++ b/radio/src/gui/colorlcd/page.h @@ -35,6 +35,9 @@ class PageHeader : public Window void setTitle(std::string txt) { title->setText(std::move(txt)); } StaticText* setTitle2(std::string txt); + static LAYOUT_VAL(PAGE_TITLE_LEFT, 50, 50) + static constexpr coord_t PAGE_TITLE_TOP = 2; + protected: EdgeTxIcon icon; StaticText* title; @@ -44,7 +47,7 @@ class PageHeader : public Window class Page : public NavWindow { public: - explicit Page(EdgeTxIcon icon, PaddingSize padding = PAD_MEDIUM); + explicit Page(EdgeTxIcon icon, PaddingSize padding = PAD_MEDIUM, bool pauseRefresh = false); #if defined(DEBUG_WINDOWS) std::string getName() const override { return "Page"; } @@ -55,6 +58,8 @@ class Page : public NavWindow void deleteLater(bool detach = true, bool trash = true) override; + void enableRefresh(); + protected: PageHeader* header = nullptr; Window* body = nullptr; @@ -62,3 +67,17 @@ class Page : public NavWindow void checkEvents() override; bool bubbleEvents() override { return false; } }; + +class SubPage : public Page +{ + public: + SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, bool pauseRefresh = false); + SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, SetupLineDef* setupLines, int lineCount); + + Window* setupLine(const char* title, std::function createEdit, coord_t lblYOffset = 0); + + static LAYOUT_VAL(EDT_X, 220, 144) + + protected: + coord_t y = 0; +}; diff --git a/radio/src/gui/colorlcd/popups.h b/radio/src/gui/colorlcd/popups.h index fdcf1eecb73..f093e635f84 100644 --- a/radio/src/gui/colorlcd/popups.h +++ b/radio/src/gui/colorlcd/popups.h @@ -21,6 +21,8 @@ #pragma once +#include + #include #include "libopenui.h" diff --git a/radio/src/gui/colorlcd/preflight_checks.cpp b/radio/src/gui/colorlcd/preflight_checks.cpp index c82107489c2..9265c7be60d 100644 --- a/radio/src/gui/colorlcd/preflight_checks.cpp +++ b/radio/src/gui/colorlcd/preflight_checks.cpp @@ -30,137 +30,206 @@ #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) +class SwitchWarnMatrix : public ButtonMatrix { - auto target = lv_event_get_target(e); - auto obj = (lv_obj_t*)lv_event_get_user_data(e); + public: + SwitchWarnMatrix(Window* parent, const rect_t& rect) : + ButtonMatrix(parent, rect) + { + // Setup button layout & texts + uint8_t btn_cnt = 0; + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { + if (SWITCH_WARNING_ALLOWED(i)) { + sw_idx[btn_cnt] = i; + btn_cnt++; + } + } - 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); - } -} + initBtnMap(min((int)btn_cnt, SW_BTNS), btn_cnt); -static void make_conditional(Window* w, ToggleSwitch* cb) -{ - lv_obj_t* w_obj = w->getLvObj(); - if (!cb->getValue()) { - lv_obj_add_flag(w_obj, LV_OBJ_FLAG_HIDDEN); + uint8_t btn_id = 0; + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { + if (SWITCH_WARNING_ALLOWED(i)) { + setTextAndState(btn_id); + btn_id++; + } + } + + update(); + + lv_obj_set_width(lvobj, min((int)btn_cnt, SW_BTNS) * SW_BTN_W + PAD_SMALL); + + uint8_t rows = ((btn_cnt - 1) / SW_BTNS) + 1; + setHeight((rows * SW_BTN_H) + PAD_SMALL); + + padAll(PAD_SMALL); } - lv_obj_t* cb_obj = cb->getLvObj(); - lv_obj_add_event_cb(cb_obj, cb_changed, LV_EVENT_VALUE_CHANGED, w_obj); -} + void onPress(uint8_t btn_id) + { + if (btn_id >= MAX_SWITCHES) return; + auto sw = sw_idx[btn_id]; -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); + swarnstate_t newstate = bfGet(g_model.switchWarning, 3 * sw, 3); + if (newstate == 1 && SWITCH_CONFIG(sw) != SWITCH_3POS) + newstate = 3; + else + newstate = (newstate + 1) % 4; + + g_model.switchWarning = + bfSet(g_model.switchWarning, newstate, 3 * sw, 3); + SET_DIRTY(); + + setTextAndState(btn_id); } -} -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); + bool isActive(uint8_t btn_id) + { + if (btn_id >= MAX_SWITCHES) return false; + return bfGet(g_model.switchWarning, 3 * sw_idx[btn_id], 3) != 0; } - lv_obj_t* choice_obj = choice->getLvObj(); - lv_obj_add_event_cb(choice_obj, choice_changed, LV_EVENT_VALUE_CHANGED, - w_obj); -} + void setTextAndState(uint8_t btn_id) + { + swsrc_t index = sw_idx[btn_id]; + auto warn_pos = g_model.switchWarning >> (3 * index) & 0x07; + std::string s = std::string(switchGetName(index)) + + std::string(getSwitchWarnSymbol(warn_pos)); + setText(btn_id, s.c_str()); + setChecked(btn_id); + } -struct SwitchWarnMatrix : public ButtonMatrix { - SwitchWarnMatrix(Window* parent, const rect_t& rect); - void onPress(uint8_t btn_id); - bool isActive(uint8_t btn_id); - void setTextAndState(uint8_t btn_id); + static LAYOUT_VAL(SW_BTNS, 8, 4) + static LAYOUT_VAL(SW_BTN_W, 56, 72) + static LAYOUT_VAL(SW_BTN_H, 36, 36) private: uint8_t sw_idx[MAX_SWITCHES]; }; -struct PotWarnMatrix : public ButtonMatrix { - PotWarnMatrix(Window* parent, const rect_t& rect); - void onPress(uint8_t btn_id); - bool isActive(uint8_t btn_id); - void setTextAndState(uint8_t btn_id); +class PotWarnMatrix : public ButtonMatrix +{ + public: + PotWarnMatrix(Window* parent, const rect_t& rect) : + ButtonMatrix(parent, rect) + { + // Setup button layout & texts + uint8_t btn_cnt = 0; + for (uint8_t i = 0; i < MAX_POTS; i++) { + if (IS_POT_AVAILABLE(i)) { + pot_idx[btn_cnt] = i; + btn_cnt++; + } + } + + initBtnMap(min((int)btn_cnt, SwitchWarnMatrix::SW_BTNS), btn_cnt); + + uint8_t btn_id = 0; + for (uint16_t i = 0; i < MAX_POTS; i++) { + if (IS_POT_AVAILABLE(i)) { + setTextAndState(btn_id); + btn_id++; + } + } + + update(); + + lv_obj_set_width(lvobj, min((int)btn_cnt, SwitchWarnMatrix::SW_BTNS) * SwitchWarnMatrix::SW_BTN_W + PAD_SMALL); + + uint8_t rows = ((btn_cnt - 1) / SwitchWarnMatrix::SW_BTNS) + 1; + setHeight((rows * SwitchWarnMatrix::SW_BTN_H) + PAD_SMALL); + + padAll(PAD_SMALL); + } + + void onPress(uint8_t btn_id) + { + if (btn_id >= MAX_POTS) return; + auto pot = pot_idx[btn_id]; + + g_model.potsWarnEnabled ^= (1 << pot); + if ((g_model.potsWarnMode == POTS_WARN_MANUAL) && + (g_model.potsWarnEnabled & (1 << pot))) { + SAVE_POT_POSITION(pot); + } + setTextAndState(btn_id); + SET_DIRTY(); + } + + bool isActive(uint8_t btn_id) + { + if (btn_id >= MAX_POTS) return false; + return (g_model.potsWarnEnabled & (1 << pot_idx[btn_id])) != 0; + } + + void setTextAndState(uint8_t btn_id) + { + setText(btn_id, getPotLabel(pot_idx[btn_id])); + setChecked(btn_id); + } private: uint8_t pot_idx[MAX_POTS]; }; -PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP) +PreflightChecks::PreflightChecks() : SubPage(ICON_MODEL_SETUP, STR_MENU_MODEL_SETUP, STR_PREFLIGHT) { - header->setTitle(STR_MENU_MODEL_SETUP); - header->setTitle2(STR_PREFLIGHT); - body->setFlexLayout(); - FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); // Display checklist - auto line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_CHECKLIST); - auto chkList = new ToggleSwitch(line, rect_t{}, - GET_SET_DEFAULT(g_model.displayChecklist)); + setupLine(STR_CHECKLIST, + [=](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_DEFAULT(g_model.displayChecklist), + [=](uint8_t newValue) { + g_model.displayChecklist = newValue; + SET_DIRTY(); + interactive->enable(g_model.displayChecklist); + }); + }); // Interactive checklist - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_CHECKLIST_INTERACTIVE); - auto interactiveChkList = new ToggleSwitch( - line, rect_t{}, GET_SET_DEFAULT(g_model.checklistInteractive)); - if (!chkList->getValue()) interactiveChkList->disable(); - chkList->setSetValueHandler([=](int32_t newValue) { - g_model.displayChecklist = newValue; - SET_DIRTY(); - (g_model.displayChecklist) ? interactiveChkList->enable() - : interactiveChkList->disable(); - }); + setupLine(STR_CHECKLIST_INTERACTIVE, + [=](Window* parent, coord_t x, coord_t y) { + interactive = new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_model.checklistInteractive)); + interactive->enable(g_model.displayChecklist); + }); // Throttle warning - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_THROTTLE_WARNING); - auto tw = new ToggleSwitch(line, rect_t{}, - GET_SET_INVERTED(g_model.disableThrottleWarning)); + setupLine(STR_THROTTLE_WARNING, + [=](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_INVERTED(g_model.disableThrottleWarning), + [=](uint8_t newValue) { + g_model.disableThrottleWarning = !newValue; + SET_DIRTY(); + customThrottle->show(!g_model.disableThrottleWarning); + }); + }); // Custom Throttle warning (conditional on previous field) - line = body->newLine(grid); - make_conditional(line, tw); - - new StaticText(line, rect_t{}, STR_CUSTOM_THROTTLE_WARNING); - 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)); - - // 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); + customThrottle = setupLine(STR_CUSTOM_THROTTLE_WARNING, + [=](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_DEFAULT(g_model.enableCustomThrottleWarning), + [=](uint8_t newValue) { + g_model.enableCustomThrottleWarning = newValue; + SET_DIRTY(); + customThrottleValue->show(g_model.enableCustomThrottleWarning); + }); + + // Custom Throttle warning value + customThrottleValue = new NumberEdit(parent, {x + ToggleSwitch::TOGGLE_W + PAD_SMALL, 0, 0}, -100, 100, + GET_SET_DEFAULT(g_model.customThrottleWarningPosition)); + customThrottleValue->show(g_model.enableCustomThrottleWarning); + }); // Switch warnings (TODO: add display switch?) - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_SWITCHES); - line = body->newLine(grid); - line->padTop(0); - line->padLeft(4); - new SwitchWarnMatrix(line, rect_t{}); + setupLine(STR_SWITCHES, [](Window*, coord_t, coord_t){}); + setupLine(nullptr, + [=](Window* parent, coord_t x, coord_t y) { + auto w = new SwitchWarnMatrix(parent, rect_t{PAD_SMALL, y, 0, 0}); + parent->setHeight(w->height() + PAD_TINY * 2); + }); // Pots and sliders warning if (adcGetMaxInputs(ADC_INPUT_FLEX) > 0) { @@ -171,152 +240,24 @@ PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP) } } if (pot_cnt > 0) { - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_POTWARNINGSTATE); - auto pots_wm = new Choice(line, rect_t{}, STR_PREFLIGHT_POTSLIDER_CHECK, - 0, 2, GET_SET_DEFAULT(g_model.potsWarnMode)); + setupLine(STR_POTWARNINGSTATE, + [=](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_PREFLIGHT_POTSLIDER_CHECK, + 0, 2, GET_DEFAULT(g_model.potsWarnMode), + [=](int newValue) { + g_model.potsWarnMode = newValue; + SET_DIRTY(); + potsWarnMatrix->show(g_model.potsWarnMode > 0); + }); + }); // Pot warnings - line = body->newLine(grid); - line->padTop(0); - line->padLeft(4); - auto pwm = new PotWarnMatrix(line, rect_t{}); - make_conditional(pwm, pots_wm); + potsWarnMatrix = setupLine(nullptr, + [=](Window* parent, coord_t x, coord_t y) { + auto w = new PotWarnMatrix(parent, {PAD_SMALL, y, 0, 0}); + parent->setHeight(w->height() + PAD_TINY * 2); + }); + potsWarnMatrix->show(g_model.potsWarnMode > 0); } } } - -static std::string switchWarninglabel(swsrc_t index) -{ - auto warn_pos = g_model.switchWarning >> (3 * index) & 0x07; - return std::string(switchGetName(index)) + - std::string(getSwitchWarnSymbol(warn_pos)); -} - -#if LCD_W > LCD_H -#define SW_BTNS 8 -#define SW_BTN_W 56 -#else -#define SW_BTNS 4 -#define SW_BTN_W 72 -#endif - -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 < MAX_SWITCHES; i++) { - if (SWITCH_WARNING_ALLOWED(i)) { - sw_idx[btn_cnt] = i; - btn_cnt++; - } - } - - initBtnMap(min((int)btn_cnt, SW_BTNS), btn_cnt); - - uint8_t btn_id = 0; - for (uint8_t i = 0; i < MAX_SWITCHES; i++) { - if (SWITCH_WARNING_ALLOWED(i)) { - setTextAndState(btn_id); - btn_id++; - } - } - - update(); - - lv_obj_set_width(lvobj, min((int)btn_cnt, SW_BTNS) * SW_BTN_W + 4); - - uint8_t rows = ((btn_cnt - 1) / SW_BTNS) + 1; - lv_obj_set_height(lvobj, (rows * 36) + 4); - - padAll(PAD_SMALL); -} - -void SwitchWarnMatrix::setTextAndState(uint8_t btn_id) -{ - setText(btn_id, switchWarninglabel(sw_idx[btn_id]).c_str()); - setChecked(btn_id); -} - -void SwitchWarnMatrix::onPress(uint8_t btn_id) -{ - if (btn_id >= MAX_SWITCHES) return; - auto sw = sw_idx[btn_id]; - - swarnstate_t newstate = bfGet(g_model.switchWarning, 3 * sw, 3); - if (newstate == 1 && SWITCH_CONFIG(sw) != SWITCH_3POS) - newstate = 3; - else - newstate = (newstate + 1) % 4; - - g_model.switchWarning = - bfSet(g_model.switchWarning, newstate, 3 * sw, 3); - SET_DIRTY(); - - setTextAndState(btn_id); -} - -bool SwitchWarnMatrix::isActive(uint8_t btn_id) -{ - if (btn_id >= MAX_SWITCHES) return false; - return bfGet(g_model.switchWarning, 3 * sw_idx[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 (uint8_t i = 0; i < MAX_POTS; i++) { - if (IS_POT_AVAILABLE(i)) { - pot_idx[btn_cnt] = i; - btn_cnt++; - } - } - - initBtnMap(min((int)btn_cnt, SW_BTNS), btn_cnt); - - uint8_t btn_id = 0; - for (uint16_t i = 0; i < MAX_POTS; i++) { - if (IS_POT_AVAILABLE(i)) { - setTextAndState(btn_id); - btn_id++; - } - } - - update(); - - lv_obj_set_width(lvobj, min((int)btn_cnt, SW_BTNS) * SW_BTN_W + 4); - - uint8_t rows = ((btn_cnt - 1) / SW_BTNS) + 1; - lv_obj_set_height(lvobj, (rows * 36) + 4); - - padAll(PAD_SMALL); -} - -void PotWarnMatrix::setTextAndState(uint8_t btn_id) -{ - setText(btn_id, getPotLabel(pot_idx[btn_id])); - setChecked(btn_id); -} - -void PotWarnMatrix::onPress(uint8_t btn_id) -{ - if (btn_id >= MAX_POTS) return; - auto pot = pot_idx[btn_id]; - - g_model.potsWarnEnabled ^= (1 << pot); - if ((g_model.potsWarnMode == POTS_WARN_MANUAL) && - (g_model.potsWarnEnabled & (1 << pot))) { - SAVE_POT_POSITION(pot); - } - setTextAndState(btn_id); - SET_DIRTY(); -} - -bool PotWarnMatrix::isActive(uint8_t btn_id) -{ - if (btn_id >= MAX_POTS) return false; - return (g_model.potsWarnEnabled & (1 << pot_idx[btn_id])) != 0; -} diff --git a/radio/src/gui/colorlcd/preflight_checks.h b/radio/src/gui/colorlcd/preflight_checks.h index f7a75e4b0f2..d8eaf94935c 100644 --- a/radio/src/gui/colorlcd/preflight_checks.h +++ b/radio/src/gui/colorlcd/preflight_checks.h @@ -23,7 +23,17 @@ #include "page.h" -class PreflightChecks : public Page { +class ToggleSwitch; +class NumberEdit; + +class PreflightChecks : public SubPage +{ public: PreflightChecks(); + + protected: + ToggleSwitch* interactive = nullptr; + Window* customThrottle = nullptr; + NumberEdit* customThrottleValue = nullptr; + Window* potsWarnMatrix = nullptr; }; diff --git a/radio/src/gui/colorlcd/preview_window.cpp b/radio/src/gui/colorlcd/preview_window.cpp index 4ac9f914ab9..3566c97573f 100644 --- a/radio/src/gui/colorlcd/preview_window.cpp +++ b/radio/src/gui/colorlcd/preview_window.cpp @@ -27,6 +27,7 @@ #include "theme.h" #include "themes/etx_lv_theme.h" #include "trims.h" +#include "topbar_impl.h" extern inline tmr10ms_t getTicks() { return g_tmr10ms; } @@ -118,14 +119,10 @@ class ThemedTextEdit : public TextEdit public: ThemedTextEdit(Window *parent, const rect_t &rect, const char *text, bool edited) : - TextEdit(parent, rect, editText, strlen(text)) + TextEdit(parent, rect, editText, 0) { - 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(); + preview(edited, editText, strlen(editText)); } #if defined(HARDWARE_KEYS) @@ -151,34 +148,34 @@ PreviewWindow::PreviewWindow(Window *window, rect_t rect, etx_solid_bg(lvobj, COLOR_THEME_SECONDARY3_INDEX); - auto topbar = new Window(this, {0, 0, LV_PCT(100), TOPBAR_ZONE_HEIGHT}); + auto topbar = new Window(this, {0, 0, LV_PCT(100), TopBar::TOPBAR_ZONE_HEIGHT}); etx_solid_bg(topbar->getLvObj(), COLOR_THEME_SECONDARY1_INDEX); - new StaticIcon(topbar, 5, 5, ICON_RADIO, + new StaticIcon(topbar, ICON_X1, ICON_Y, ICON_RADIO, COLOR_THEME_PRIMARY2); - new StaticIcon(topbar, 38, 5, ICON_RADIO_TOOLS, + new StaticIcon(topbar, ICON_X2, ICON_Y, ICON_RADIO_TOOLS, COLOR_THEME_PRIMARY2); - new StaticIcon(topbar, 71, 5, ICON_RADIO_SETUP, + new StaticIcon(topbar, ICON_X3, ICON_Y, ICON_RADIO_SETUP, COLOR_THEME_PRIMARY2); - new StaticText(this, {5, 44, 100, PAGE_LINE_HEIGHT}, STR_THEME_CHECKBOX); - 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)) + new StaticText(this, {ICON_X1, CBT_Y, CBT_W, EdgeTxStyles::PAGE_LINE_HEIGHT}, STR_THEME_CHECKBOX); + new ThemedCheckBox(this, {CB1_X, CB_Y, CB_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, true); + new ThemedCheckBox(this, {CB2_X, CB_Y, CB_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, false); + (new ThemedButton(this, {BTN_X, BTN1_Y, BTN_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 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, + new ThemedButton(this, {BTN_X, BTN2_Y, BTN_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, STR_THEME_REGULAR, false); + new MainViewTrim(this, {ICON_X1, TRIM_Y, MainViewSlider::HORIZONTAL_SLIDERS_WIDTH, TRIM_H}, 0, false); + new MainViewSlider(this, {ICON_X1, SLIDER_Y, MainViewSlider::HORIZONTAL_SLIDERS_WIDTH, TRIM_H}, 0, false); + new StaticText(this, {ICON_X1, TXT1_Y, TXT_W, EdgeTxStyles::PAGE_LINE_HEIGHT}, STR_THEME_WARNING, COLOR_THEME_WARNING); - new StaticText(this, {5, 144, 100, PAGE_LINE_HEIGHT}, STR_THEME_DISABLED, + new StaticText(this, {ICON_X1, TXT2_Y, TXT_W, EdgeTxStyles::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); + new ThemedTextEdit(this, {ICON_X1, EDT_Y, TXT_W, 0}, STR_THEME_EDIT, true); + new ThemedTextEdit(this, {EDT2_X, EDT_Y, TXT_W, 0}, STR_THEME_FOCUS, false); ticks = 0; - dateTime = new HeaderDateTime(this->getLvObj(), width() - 42, 4); + dateTime = new HeaderDateTime(this->getLvObj(), width() - DATE_XO, PAD_SMALL); lv_group_set_default(def_group); diff --git a/radio/src/gui/colorlcd/preview_window.h b/radio/src/gui/colorlcd/preview_window.h index bdd462c5c14..2cdb39b243e 100644 --- a/radio/src/gui/colorlcd/preview_window.h +++ b/radio/src/gui/colorlcd/preview_window.h @@ -34,6 +34,30 @@ class PreviewWindow : public Window void setColorList(std::vector colorList); + static LAYOUT_VAL(ICON_X1, 5, 5) + static LAYOUT_VAL(ICON_X2, 38, 38) + static LAYOUT_VAL(ICON_X3, 71, 71) + static LAYOUT_VAL(ICON_Y, 5, 5) + static LAYOUT_VAL(DATE_XO, 44, 44) + static LAYOUT_VAL(CBT_Y, 44, 44) + static LAYOUT_VAL(CBT_W, 100, 100) + static LAYOUT_VAL(CB1_X, 100, 100) + static LAYOUT_VAL(CB2_X, 154, 154) + static LAYOUT_VAL(CB_Y, 40, 40) + static LAYOUT_VAL(CB_W, 50, 50) + static LAYOUT_VAL(BTN_X, 210, 210) + static LAYOUT_VAL(BTN1_Y, 40, 40) + static LAYOUT_VAL(BTN2_Y, 79, 79) + static LAYOUT_VAL(BTN_W, 100, 100) + static LAYOUT_VAL(TRIM_Y, 79, 79) + static LAYOUT_VAL(TRIM_H, 20, 20) + static LAYOUT_VAL(SLIDER_Y, 101, 101) + static LAYOUT_VAL(TXT1_Y, 122, 122) + static LAYOUT_VAL(TXT2_Y, 144, 144) + static LAYOUT_VAL(TXT_W, 100, 100) + static LAYOUT_VAL(EDT2_X, 114, 114) + static LAYOUT_VAL(EDT_Y, 170, 170) + protected: tmr10ms_t ticks; HeaderDateTime *dateTime; diff --git a/radio/src/gui/colorlcd/radio_calibration.cpp b/radio/src/gui/colorlcd/radio_calibration.cpp index 4b2f682154b..26ba379e60b 100644 --- a/radio/src/gui/colorlcd/radio_calibration.cpp +++ b/radio/src/gui/colorlcd/radio_calibration.cpp @@ -52,13 +52,15 @@ class StickCalibrationWindow : public Window { 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; + coord_t dx = width() / 2 - CAL_CTR + (CAL_SIZ / 2 * x) / RESX; + coord_t dy = height() / 2 - CAL_CTR - (CAL_SIZ / 2 * y) / RESX; lv_obj_set_pos(calibStick->getLvObj(), dx, dy); } + static LAYOUT_VAL(CAL_CTR, 9, 9) + static LAYOUT_VAL(CAL_SIZ, 68, 68) + protected: - static constexpr coord_t bitmapSize = 68; uint8_t stickX, stickY; StaticLZ4Image *calibStick = nullptr; }; diff --git a/radio/src/gui/colorlcd/radio_diaganas.cpp b/radio/src/gui/colorlcd/radio_diaganas.cpp index c0271fbfa38..5cf63920c32 100644 --- a/radio/src/gui/colorlcd/radio_diaganas.cpp +++ b/radio/src/gui/colorlcd/radio_diaganas.cpp @@ -32,7 +32,7 @@ #define STATSDEPTH 8 // ideally a value of power of 2 -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define GRIDCOLS 10 #define TSI2CEventsCol 5 @@ -83,7 +83,7 @@ class AnaViewWindow : public Window if (i >= pot_offset && (POT_CONFIG(i - pot_offset) == FLEX_NONE)) continue; -#if LCD_W > LCD_H +#if !PORTRAIT_LCD if ((i & 1) == 0) line = newLine(grid); #else line = newLine(grid); @@ -116,7 +116,7 @@ class AnaViewWindow : public Window }, 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 +#if !PORTRAIT_LCD lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH, 3 + (i & 1) * 5, column4size(), LV_GRID_ALIGN_CENTER, 0, 1); @@ -172,7 +172,7 @@ class AnaCalibratedViewWindow : public AnaViewWindow lv_obj_add_flag(touchLines[1], LV_OBJ_FLAG_HIDDEN); line = newLine(grid); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line->padTop(20); #else line->padTop(2); @@ -202,7 +202,7 @@ class AnaCalibratedViewWindow : public AnaViewWindow lv_obj_set_grid_cell(lbl2->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 5, LV_GRID_ALIGN_CENTER, 0, 1); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = newLine(grid); #endif lbl2 = new StaticText(line, rect_t{}, diff --git a/radio/src/gui/colorlcd/radio_diagkeys.cpp b/radio/src/gui/colorlcd/radio_diagkeys.cpp index 514ebd7c3cb..f00a1c49cf2 100644 --- a/radio/src/gui/colorlcd/radio_diagkeys.cpp +++ b/radio/src/gui/colorlcd/radio_diagkeys.cpp @@ -98,22 +98,22 @@ class RadioKeyDiagsWindow : public Window auto lbl = lv_label_create(obj); lv_label_set_text(lbl, keysGetLabel(k)); - lv_obj_set_pos(lbl, 0, i * FH); + lv_obj_set_pos(lbl, 0, i * EdgeTxStyles::PAGE_LINE_HEIGHT); lbl = lv_label_create(obj); lv_label_set_text(lbl, ""); - lv_obj_set_pos(lbl, 70, i * FH); + lv_obj_set_pos(lbl, 70, i * EdgeTxStyles::PAGE_LINE_HEIGHT); keyValues[i] = lbl; } #if defined(ROTARY_ENCODER_NAVIGATION) && !defined(USE_HATS_AS_KEYS) auto lbl = lv_label_create(obj); lv_label_set_text(lbl, STR_ROTARY_ENCODER); - lv_obj_set_pos(lbl, 0, (i + 1) * FH); + lv_obj_set_pos(lbl, 0, (i + 1) * EdgeTxStyles::PAGE_LINE_HEIGHT); reValue = lv_label_create(obj); lv_label_set_text(reValue, ""); - lv_obj_set_pos(reValue, 70, (i + 1) * FH); + lv_obj_set_pos(reValue, 70, (i + 1) * EdgeTxStyles::PAGE_LINE_HEIGHT); #endif } @@ -129,7 +129,7 @@ class RadioKeyDiagsWindow : public Window if (SWITCH_EXISTS(i)) { auto lbl = lv_label_create(obj); lv_label_set_text(lbl, ""); - lv_obj_set_pos(lbl, 0, row * FH); + lv_obj_set_pos(lbl, 0, row * EdgeTxStyles::PAGE_LINE_HEIGHT); switchValues[i] = lbl; row += 1; } @@ -157,16 +157,16 @@ class RadioKeyDiagsWindow : public Window 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); + lv_obj_set_pos(lbl, 4, i * EdgeTxStyles::PAGE_LINE_HEIGHT + EdgeTxStyles::PAGE_LINE_HEIGHT); lbl = lv_label_create(obj); lv_label_set_text(lbl, ""); - lv_obj_set_pos(lbl, 60, i * FH + FH); + lv_obj_set_pos(lbl, 60, i * EdgeTxStyles::PAGE_LINE_HEIGHT + EdgeTxStyles::PAGE_LINE_HEIGHT); trimValues[i * 2] = lbl; lbl = lv_label_create(obj); lv_label_set_text(lbl, ""); - lv_obj_set_pos(lbl, 75, i * FH + FH); + lv_obj_set_pos(lbl, 75, i * EdgeTxStyles::PAGE_LINE_HEIGHT + EdgeTxStyles::PAGE_LINE_HEIGHT); trimValues[i * 2 + 1] = lbl; } } diff --git a/radio/src/gui/colorlcd/radio_ghost_module_config.cpp b/radio/src/gui/colorlcd/radio_ghost_module_config.cpp index 8e6414f3572..4ceb3c1ea65 100644 --- a/radio/src/gui/colorlcd/radio_ghost_module_config.cpp +++ b/radio/src/gui/colorlcd/radio_ghost_module_config.cpp @@ -32,7 +32,7 @@ class GhostModuleConfigWindow : public Window GhostModuleConfigWindow(Window* parent, const rect_t& rect) : Window(parent, rect) { -#if LCD_H > LCD_W +#if PORTRAIT_LCD constexpr coord_t xOffset = 20; constexpr coord_t xOffset2 = 140; #else @@ -162,7 +162,7 @@ void RadioGhostModuleConfig::buildBody(Window* window) { window->padAll(PAD_ZERO); new GhostModuleConfigWindow(window, - {0, 0, LCD_W, LCD_H - MENU_HEADER_HEIGHT - 5}); + {0, 0, LCD_W, LCD_H - EdgeTxStyles::MENU_HEADER_HEIGHT - 5}); } #if defined(HARDWARE_KEYS) && !defined(PCBPL18) diff --git a/radio/src/gui/colorlcd/radio_hardware.cpp b/radio/src/gui/colorlcd/radio_hardware.cpp index 2105611d8f6..c825187adbd 100644 --- a/radio/src/gui/colorlcd/radio_hardware.cpp +++ b/radio/src/gui/colorlcd/radio_hardware.cpp @@ -31,6 +31,7 @@ #include "radio_calibration.h" #include "radio_diaganas.h" #include "radio_diagkeys.h" +#include "radio_setup.h" #if defined(BLUETOOTH) #include "hw_bluetooth.h" @@ -38,30 +39,29 @@ #define SET_DIRTY() storageDirty(EE_GENERAL) +#if PORTRAIT_LCD +static const lv_coord_t col_dsc[] = {LV_GRID_FR(13), LV_GRID_FR(19), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; +#else 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_CONTENT, LV_GRID_TEMPLATE_LAST}; +#endif -static Window* hbox(Window* parent) +RadioHardwarePage::RadioHardwarePage() : + PageTab(STR_HARDWARE, ICON_RADIO_HARDWARE, PAD_TINY) { - 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; + enableVBatBridge(); } -RadioHardwarePage::RadioHardwarePage() : - PageTab(STR_HARDWARE, ICON_RADIO_HARDWARE) +void RadioHardwarePage::cleanup() { + disableVBatBridge(); } -void RadioHardwarePage::checkEvents() { enableVBatBridge(); } - class BatCalEdit : public NumberEdit { public: @@ -87,74 +87,84 @@ class BatCalEdit : public NumberEdit } }; +static SetupLineDef setupLines[] = { + { + // Batt meter range - Range 3.0v to 16v + STR_BATTERY_RANGE, + [](Window* parent, coord_t x, coord_t y) { + auto batMin = new NumberEdit( + parent, {x, y, RadioHardwarePage::NUM_EDIT_W, 0}, -60 + 90, g_eeGeneral.vBatMax + 29 + 90, + GET_SET_WITH_OFFSET(g_eeGeneral.vBatMin, 90), PREC1); + batMin->setSuffix("V"); + new StaticText(parent, {x + RadioHardwarePage::NUM_EDIT_W + PAD_SMALL, y + PAD_SMALL + 1, PAD_LARGE, EdgeTxStyles::PAGE_LINE_HEIGHT}, "-"); + auto batMax = new NumberEdit( + parent, {x + RadioHardwarePage::NUM_EDIT_W + PAD_LARGE + PAD_SMALL, y, RadioHardwarePage::NUM_EDIT_W, 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->setSetValueHandler([=](int32_t newValue) { + g_eeGeneral.vBatMax = newValue - 120; + SET_DIRTY(); + batMin->setMax(g_eeGeneral.vBatMax + 29 + 90); + }); + } + }, + { + // Bat calibration + STR_BATT_CALIB, + [](Window* parent, coord_t x, coord_t y) { + new BatCalEdit(parent, {x, y, RadioHardwarePage::NUM_EDIT_W, 0}); + } + }, + { + // RTC Batt check enable + STR_RTC_CHECK, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_SET_INVERTED(g_eeGeneral.disableRtcWarning)); + + // RTC Batt display + std::string s(STR_VALUE); + s += " "; + new DynamicNumber( + parent, {x + ToggleSwitch::TOGGLE_W + PAD_SMALL, y + PAD_SMALL + 1, 0, 0}, [] { return getRTCBatteryVoltage(); }, + COLOR_THEME_PRIMARY1 | PREC2, s.c_str(), "V"); + } + }, + { + // ADC filter + STR_JITTER_FILTER, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_INVERTED(g_eeGeneral.noJitterFilter)); + } + }, +#if defined(AUDIO_MUTE_GPIO) + { + // Mute audio + STR_AUDIO_MUTE, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_eeGeneral.audioMuteEnable)); + } + }, +#endif +}; + void RadioHardwarePage::build(Window* window) { - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); - - FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); // TODO: sub-title? + SetupLine::showLines(window, 0, SubPage::EDT_X, padding, setupLines, DIM(setupLines)); - // Batt meter range - Range 3.0v to 16v - auto line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_BATTERY_RANGE); - - 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), PREC1); - batMax->setSuffix("V"); - - batMin->setSetValueHandler([=](int32_t newValue) { - g_eeGeneral.vBatMin = newValue - 90; - SET_DIRTY(); - batMax->setMin(g_eeGeneral.vBatMin - 29 + 120); - }); - - batMax->setSetValueHandler([=](int32_t newValue) { - g_eeGeneral.vBatMax = newValue - 120; - SET_DIRTY(); - batMin->setMax(g_eeGeneral.vBatMax + 29 + 90); - }); - - // Bat calibration - line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_BATT_CALIB); - 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); - - box = hbox(line); - new ToggleSwitch(box, rect_t{}, - GET_SET_INVERTED(g_eeGeneral.disableRtcWarning)); - - // RTC Batt display - new StaticText(box, rect_t{}, STR_VALUE); - new DynamicNumber( - box, rect_t{}, [] { return getRTCBatteryVoltage(); }, - COLOR_THEME_PRIMARY1 | PREC2, nullptr, "V"); + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); - // ADC filter - line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_JITTER_FILTER); - 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); - box = hbox(line); - new ToggleSwitch(box, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.audioMuteEnable)); -#endif + FormLine* line; #if defined(HARDWARE_INTERNAL_MODULE) new Subtitle(window, STR_INTERNALRF); @@ -181,44 +191,16 @@ void RadioHardwarePage::build(Window* window) new SerialConfigWindow(window, grid); // Calibration - new Subtitle(window, STR_INPUTS); - - 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; + new SetupButtonGroup(window, {0, 0, LCD_W - padding * 2, 0}, STR_INPUTS, BTN_COLS, PAD_ZERO, { + {STR_CALIBRATION, []() { new RadioCalibrationPage(); }}, + {STR_STICKS, []() { new HWInputDialog(STR_STICKS); }}, + {STR_POTS, []() { new HWInputDialog(STR_POTS); }}, + {STR_SWITCHES, []() { new HWInputDialog(STR_SWITCHES); }}, }); - // Sticks - makeHWInputButton(box, STR_STICKS); - - // Pots & Sliders - makeHWInputButton(box, STR_POTS); - - // Switches - makeHWInputButton(box, STR_SWITCHES); - // Debugs - new Subtitle(window, STR_DEBUG); - - 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_ANALOGS_BTN, [=]() -> uint8_t { - new RadioAnalogsDiagsViewPageGroup(); - return 0; - }); - - new TextButton(box, rect_t{0, 0, 100, 0}, STR_KEYS_BTN, [=]() -> uint8_t { - new RadioKeyDiagsPage(); - return 0; + new SetupButtonGroup(window, {0, 0, LCD_W - padding * 2, 0}, STR_DEBUG, BTN_COLS, PAD_ZERO, { + {STR_ANALOGS_BTN, []() { new RadioAnalogsDiagsViewPageGroup(); }}, + {STR_KEYS_BTN, []() { new RadioKeyDiagsPage(); }}, }); } diff --git a/radio/src/gui/colorlcd/radio_hardware.h b/radio/src/gui/colorlcd/radio_hardware.h index 1f023de6c3c..a56414a8267 100644 --- a/radio/src/gui/colorlcd/radio_hardware.h +++ b/radio/src/gui/colorlcd/radio_hardware.h @@ -25,10 +25,14 @@ class RadioHardwarePage : public PageTab { - void checkEvents() override; - public: RadioHardwarePage(); void build(Window* window) override; + + static LAYOUT_VAL(NUM_EDIT_W, 80, 80) + static LAYOUT_VAL(BTN_COLS, 4, 3) + + protected: + void cleanup() override; }; diff --git a/radio/src/gui/colorlcd/radio_sdmanager.cpp b/radio/src/gui/colorlcd/radio_sdmanager.cpp index 30c654814e7..719d1c2b2fb 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.cpp +++ b/radio/src/gui/colorlcd/radio_sdmanager.cpp @@ -40,69 +40,6 @@ constexpr int WARN_FILE_LENGTH = 40 * 1024; #define CELL_CTRL_DIR LV_TABLE_CELL_CTRL_CUSTOM_1 #define CELL_CTRL_FILE LV_TABLE_CELL_CTRL_CUSTOM_2 -class FileNameEditWindow : public Page -{ - public: - FileNameEditWindow(const std::string iName) : - Page(ICON_RADIO_SD_MANAGER), name(std::move(iName)) - { - buildHeader(header); - buildBody(body); - }; - -#if defined(DEBUG_WINDOWS) - std::string getName() const override { return "FileNameEditWindow"; } -#endif - protected: - const std::string name; - - void buildHeader(Window *window) - { - header->setTitle(STR_RENAME_FILE); - } - - void buildBody(Window *window) - { - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_SMALL); - window->padTop(12); - - uint8_t nameLength; - uint8_t extLength; - char extension[LEN_FILE_EXTENSION_MAX + 1]; - memset(extension, 0, sizeof(extension)); - const char *ext = - getFileExtension(name.c_str(), 0, 0, &nameLength, &extLength); - - if (extLength > LEN_FILE_EXTENSION_MAX) extLength = LEN_FILE_EXTENSION_MAX; - if (ext) strncpy(extension, ext, extLength); - - const uint8_t maxNameLength = SD_SCREEN_FILE_LENGTH - extLength; - nameLength -= extLength; - if (nameLength > maxNameLength) nameLength = maxNameLength; - memset(reusableBuffer.sdManager.originalName, 0, SD_SCREEN_FILE_LENGTH); - - strncpy(reusableBuffer.sdManager.originalName, name.c_str(), nameLength); - reusableBuffer.sdManager.originalName[nameLength] = '\0'; - - auto newFileName = new TextEdit( - 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); - char changedName[SD_SCREEN_FILE_LENGTH + 1]; - memset(changedName, 0, sizeof(changedName)); - strncpy(changedName, newValue, totalSize); - changedName[totalSize] = '\0'; - if (extLength) { - strncpy(changedName + totalSize, extension, extLength); - } - changedName[totalSize + extLength] = '\0'; - f_rename((const TCHAR *)name.c_str(), (const TCHAR *)changedName); - }); - }; -}; - RadioSdManagerPage::RadioSdManagerPage() : PageTab(STR_SD_CARD, ICON_RADIO_SD_MANAGER) { @@ -273,7 +210,7 @@ ModuleCallback onUpdateStateChangedCallbackFor(FrskyOtaFlashDialog* dialog) { #endif // PXX2 -#if LCD_W > LCD_H // landscape +#if !PORTRAIT_LCD // landscape static const lv_coord_t col_dsc[] = {LV_GRID_FR(3), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; #else // portrait @@ -302,7 +239,7 @@ void RadioSdManagerPage::build(Window * window) // Adjust file browser width browser->adjustWidth(); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD 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 }); @@ -513,8 +450,23 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name, }); } menu->addLine(STR_RENAME_FILE, [=]() { - auto few = new FileNameEditWindow(name); - few->setCloseHandler([=]() { browser->refresh(); }); + uint8_t nameLength; + uint8_t extLength; + + const char *ext = getFileExtension(name, 0, 0, &nameLength, &extLength); + + const uint8_t maxNameLength = SD_SCREEN_FILE_LENGTH - extLength; + nameLength = min((uint8_t)(nameLength - extLength), maxNameLength); + + std::string fname(name, nameLength); + std::string extension(""); + if (ext) extension = ext; + + new LabelDialog(Layer::back(), fname.c_str(), maxNameLength, STR_RENAME_FILE, [=](std::string label) { + label += extension; + f_rename((const TCHAR *)name, (const TCHAR *)label.c_str()); + browser->refresh(); + }); }); menu->addLine(STR_DELETE_FILE, [=]() { f_unlink(fullpath); diff --git a/radio/src/gui/colorlcd/radio_setup.cpp b/radio/src/gui/colorlcd/radio_setup.cpp index 0cf844554cd..78966d857ad 100644 --- a/radio/src/gui/colorlcd/radio_setup.cpp +++ b/radio/src/gui/colorlcd/radio_setup.cpp @@ -38,24 +38,13 @@ 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 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 - class DateTimeWindow : public Window { public: DateTimeWindow(Window* parent, const rect_t& rect) : - Window(parent, {0, 0, LCD_W - 12, 74}) + Window(parent, rect) { + padAll(PAD_ZERO); build(); } @@ -67,34 +56,30 @@ class DateTimeWindow : public Window 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; + if (m_tm.tm_year != m_last_tm.tm_year) year->update(); - } - if (m_tm.tm_mon != m_last_tm.tm_mon) { - m_last_tm.tm_mon = m_tm.tm_mon; + if (m_tm.tm_mon != m_last_tm.tm_mon) month->update(); - } - if (m_tm.tm_mday != m_last_tm.tm_mday) { - m_last_tm.tm_mday = m_tm.tm_mday; + if (m_tm.tm_mday != m_last_tm.tm_mday) day->update(); - } - if (m_tm.tm_hour != m_last_tm.tm_hour) { - m_last_tm.tm_hour = m_tm.tm_hour; + if (m_tm.tm_hour != m_last_tm.tm_hour) hour->update(); - } - if (m_tm.tm_min != m_last_tm.tm_min) { - m_last_tm.tm_min = m_tm.tm_min; + if (m_tm.tm_min != m_last_tm.tm_min) minutes->update(); - } - if (m_tm.tm_sec != m_last_tm.tm_sec) { - m_last_tm.tm_sec = m_tm.tm_sec; + if (m_tm.tm_sec != m_last_tm.tm_sec) seconds->update(); - } + m_last_tm = m_tm; } } + // Absolute layout for date/time setion due to slow performance + // of lv_textarea in a flex layout. + static LAYOUT_VAL(DT_EDT_W, 80, 52) + static LAYOUT_VAL(DT_Y1, PAD_TINY, PAD_TINY) + static LAYOUT_VAL(DT_Y2, DT_Y1 + EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_MEDIUM, DT_Y1 + EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_MEDIUM) + protected: + bool init = false; struct gtm m_tm; struct gtm m_last_tm; tmr10ms_t lastRefresh = 0; @@ -136,9 +121,9 @@ class DateTimeWindow : public Window m_last_tm = m_tm; // Date - new StaticText(this, rect_t{2, 8, DT_LBL_W, 21}, STR_DATE); + new StaticText(this, rect_t{PAD_TINY, DT_Y1 + PAD_MEDIUM, SubPage::EDT_X - PAD_TINY - PAD_SMALL, EdgeTxStyles::PAGE_LINE_HEIGHT}, STR_DATE); year = new NumberEdit( - this, rect_t{DT_EDT_X, 2, DT_EDT_W, 32}, 2023, 2037, + this, rect_t{SubPage::EDT_X, DT_Y1, DT_EDT_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 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; @@ -147,7 +132,7 @@ class DateTimeWindow : public Window }); month = new NumberEdit( - this, rect_t{DT_EDT_X + DT_EDT_W + 2, 2, DT_EDT_W, 32}, 1, 12, + this, rect_t{SubPage::EDT_X + DT_EDT_W + PAD_TINY, DT_Y1, DT_EDT_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 1, 12, [=]() -> int32_t { return 1 + m_tm.tm_mon; }, [=](int32_t newValue) { m_last_tm.tm_mon = m_tm.tm_mon = newValue - 1; @@ -158,7 +143,7 @@ class DateTimeWindow : public Window [](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, + this, rect_t{SubPage::EDT_X + 2 * DT_EDT_W + PAD_SMALL, DT_Y1, DT_EDT_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 1, daysInMonth(), [=]() -> int32_t { return m_tm.tm_mday; }, [=](int32_t newValue) { m_last_tm.tm_mday = m_tm.tm_mday = newValue; @@ -168,9 +153,9 @@ class DateTimeWindow : public Window [](int32_t value) { return formatNumberAsString(value, LEADING0, 2); }); // Time - new StaticText(this, rect_t{2, 46, DT_LBL_W, 21}, STR_TIME); + new StaticText(this, rect_t{PAD_TINY, DT_Y2 + PAD_MEDIUM, SubPage::EDT_X - PAD_TINY - PAD_SMALL, EdgeTxStyles::PAGE_LINE_HEIGHT}, STR_TIME); hour = new NumberEdit( - this, rect_t{DT_EDT_X, 40, DT_EDT_W, 32}, 0, 23, + this, rect_t{SubPage::EDT_X, DT_Y2, DT_EDT_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 0, 23, [=]() -> int32_t { return m_tm.tm_hour; }, [=](int32_t newValue) { m_last_tm.tm_hour = m_tm.tm_hour = newValue; @@ -180,7 +165,7 @@ class DateTimeWindow : public Window [](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, + this, rect_t{SubPage::EDT_X + DT_EDT_W + PAD_TINY, DT_Y2, DT_EDT_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 0, 59, [=]() -> int32_t { return m_tm.tm_min; }, [=](int32_t newValue) { m_last_tm.tm_min = m_tm.tm_min = newValue; @@ -190,7 +175,7 @@ class DateTimeWindow : public Window [](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, + this, rect_t{SubPage::EDT_X + DT_EDT_W * 2 + PAD_SMALL, DT_Y2, DT_EDT_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 0, 59, [=]() -> int32_t { return m_tm.tm_sec; }, [=](int32_t newValue) { m_last_tm.tm_sec = m_tm.tm_sec = newValue; @@ -201,345 +186,308 @@ class DateTimeWindow : public Window } }; -class WindowButtonGroup : public Window -{ - public: - typedef std::function PageFct; - typedef std::pair PageDef; - typedef std::list PageDefs; - - WindowButtonGroup(Window* parent, const rect_t& rect, PageDefs pages) : - Window(parent, rect), pages(pages) - { - 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(PAD_MEDIUM); - padBottom(PAD_SMALL); - - for (auto& entry : pages) { - auto btn = new TextButton(this, rect_t{}, entry.first, [&, entry]() { - entry.second(); - return 0; - }); - lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0); - } - } - - protected: - PageDefs pages; -}; - -class SubPage : public Page -{ - public: - SubPage(EdgeTxIcon icon, const char* title) : Page(icon) +static SetupLineDef soundPageSetupLines[] = { { - header->setTitle(STR_RADIO_SETUP); - header->setTitle2(title); - - body->setFlexLayout(); - } -}; - -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); - new Choice(line, rect_t{}, STR_VBEEPMODE, -2, 1, - GET_SET_DEFAULT(g_eeGeneral.beepMode)); - line = body->newLine(grid); - + STR_SPEAKER, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_VBEEPMODE, -2, 1, + GET_SET_DEFAULT(g_eeGeneral.beepMode)); + } + }, + { // Main volume - new StaticText(line, rect_t{}, STR_VOLUME); - 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); - + STR_VOLUME, + [](Window* parent, coord_t x, coord_t y) { + (new Slider(parent, lv_pct(50), -VOLUME_LEVEL_DEF, + VOLUME_LEVEL_MAX - VOLUME_LEVEL_DEF, + GET_SET_DEFAULT(g_eeGeneral.speakerVolume)))->setPos(x, y); + } + }, + { // Beeps volume - new StaticText(line, rect_t{}, STR_BEEP_VOLUME); - new Slider(line, lv_pct(50), -2, +2, - GET_SET_DEFAULT(g_eeGeneral.beepVolume)); - line = body->newLine(grid); - + STR_BEEP_VOLUME, + [](Window* parent, coord_t x, coord_t y) { + (new Slider(parent, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.beepVolume)))->setPos(x, y); + } + }, + { // Beeps length - new StaticText(line, rect_t{}, STR_BEEP_LENGTH); - new Slider(line, lv_pct(50), -2, +2, - GET_SET_DEFAULT(g_eeGeneral.beepLength)); - line = body->newLine(grid); - + STR_BEEP_LENGTH, + [](Window* parent, coord_t x, coord_t y) { + (new Slider(parent, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.beepLength)))->setPos(x, y); + } + }, + { // Beeps pitch - new StaticText(line, rect_t{}, STR_BEEP_PITCH); - 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); - + STR_BEEP_PITCH, + [](Window* parent, coord_t x, coord_t y) { + auto edit = new NumberEdit(parent, rect_t{x, y, RadioSetupPage::NUM_W, 0}, 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"); + } + }, + { // Wav volume - new StaticText(line, rect_t{}, STR_WAV_VOLUME); - new Slider(line, lv_pct(50), -2, +2, - GET_SET_DEFAULT(g_eeGeneral.wavVolume)); - line = body->newLine(grid); - + STR_WAV_VOLUME, + [](Window* parent, coord_t x, coord_t y) { + (new Slider(parent, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.wavVolume)))->setPos(x, y); + } + }, + { // Background volume - new StaticText(line, rect_t{}, STR_BG_VOLUME); - new Slider(line, lv_pct(50), -2, +2, - GET_SET_DEFAULT(g_eeGeneral.backgroundVolume)); - } + STR_BG_VOLUME, + [](Window* parent, coord_t x, coord_t y) { + (new Slider(parent, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.backgroundVolume)))->setPos(x, y); + } + }, }; #if defined(VARIO) -class VarioPage : public SubPage -{ - public: - VarioPage() : SubPage(ICON_RADIO_SETUP, STR_VARIO) +static SetupLineDef varioPageSetupLines[] = { { - FlexGridLayout grid(col_two_dsc, row_dsc); - - auto line = body->newLine(grid); - // Vario volume - new StaticText(line, rect_t{}, STR_VOLUME); - 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); - 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); - 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); - 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); - } + STR_VOLUME, + [](Window* parent, coord_t x, coord_t y) { + (new Slider(parent, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.varioVolume)))->setPos(x, y); + } + }, + { + STR_PITCH_AT_ZERO, + [](Window* parent, coord_t x, coord_t y) { + auto edit = new NumberEdit( + parent, {x, y, RadioSetupPage::NUM_W, 0}, 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"); + } + }, + { + STR_PITCH_AT_MAX, + [](Window* parent, coord_t x, coord_t y) { + auto edit = new NumberEdit( + parent, {x, y, RadioSetupPage::NUM_W, 0}, 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"); + } + }, + { + STR_REPEAT_AT_ZERO, + [](Window* parent, coord_t x, coord_t y) { + auto edit = new NumberEdit( + parent, {x, y, RadioSetupPage::NUM_W, 0}, 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"); + } + }, }; #endif #if defined(HAPTIC) -class HapticPage : public SubPage -{ - public: - HapticPage() : SubPage(ICON_RADIO_SETUP, STR_HAPTIC_LABEL) +static SetupLineDef hapticPageSetupLines[] = { { - FlexGridLayout grid(col_two_dsc, row_dsc); - - auto line = body->newLine(grid); - // Haptic mode - new StaticText(line, rect_t{}, STR_MODE); - new Choice(line, rect_t{}, STR_VBEEPMODE, -2, 1, - GET_SET_DEFAULT(g_eeGeneral.hapticMode)); - line = body->newLine(grid); - + STR_MODE, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_VBEEPMODE, -2, 1, + GET_SET_DEFAULT(g_eeGeneral.hapticMode)); + } + }, + { // Haptic duration - new StaticText(line, rect_t{}, STR_LENGTH); - new Slider(line, lv_pct(50), -2, +2, - GET_SET_DEFAULT(g_eeGeneral.hapticLength)); - line = body->newLine(grid); - + STR_LENGTH, + [](Window* parent, coord_t x, coord_t y) { + (new Slider(parent, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.hapticLength)))->setPos(x, y); + } + }, + { // Haptic strength - new StaticText(line, rect_t{}, STR_STRENGTH); - new Slider(line, lv_pct(50), -2, +2, - GET_SET_DEFAULT(g_eeGeneral.hapticStrength)); - line = body->newLine(grid); - } + STR_STRENGTH, + [](Window* parent, coord_t x, coord_t y) { + (new Slider(parent, lv_pct(50), -2, +2, + GET_SET_DEFAULT(g_eeGeneral.hapticStrength)))->setPos(x, y); + } + }, }; #endif -class AlarmsPage : public SubPage -{ - public: - AlarmsPage() : SubPage(ICON_RADIO_SETUP, STR_ALARMS_LABEL) +static SetupLineDef alarmsPageSetupLines[] = { { - FlexGridLayout grid(col_two_dsc, row_dsc); - - auto line = body->newLine(grid); // Battery warning - new StaticText(line, rect_t{}, STR_BATTERYWARNING); - auto edit = new NumberEdit(line, rect_t{}, 30, 120, - GET_SET_DEFAULT(g_eeGeneral.vBatWarn), PREC1); - edit->setSuffix("V"); - line = body->newLine(grid); - + STR_BATTERYWARNING, + [](Window* parent, coord_t x, coord_t y) { + auto edit = new NumberEdit(parent, {x, y, RadioSetupPage::NUM_W, 0}, 30, 120, + GET_SET_DEFAULT(g_eeGeneral.vBatWarn), PREC1); + edit->setSuffix("V"); + } + }, + { // Inactivity alarm - new StaticText(line, rect_t{}, STR_INACTIVITYALARM); - 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); + STR_INACTIVITYALARM, + [](Window* parent, coord_t x, coord_t y) { + auto edit = new NumberEdit(parent, {x, y, RadioSetupPage::NUM_W * 3 / 2, 0}, 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); - + suffix = " " + suffix; + return formatNumberAsString(value, 0, 0, nullptr, suffix.c_str()); + }); + } + }, + { // Alarms warning - new StaticText(line, rect_t{}, STR_ALARMWARNING); - new ToggleSwitch(line, rect_t{}, - GET_SET_INVERTED(g_eeGeneral.disableAlarmWarning)); - line = body->newLine(grid); - + STR_ALARMWARNING, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_SET_INVERTED(g_eeGeneral.disableAlarmWarning)); + } + }, + { // RSSI shutdown alarm - new StaticText(line, rect_t{}, STR_RSSI_SHUTDOWN_ALARM); - new ToggleSwitch(line, rect_t{}, - GET_SET_INVERTED(g_eeGeneral.disableRssiPoweroffAlarm)); - line = body->newLine(grid); - + STR_RSSI_SHUTDOWN_ALARM, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_SET_INVERTED(g_eeGeneral.disableRssiPoweroffAlarm)); + } + }, + { // Trainer shutdown alarm - new StaticText(line, rect_t{}, STR_TRAINER_SHUTDOWN_ALARM); - new ToggleSwitch(line, rect_t{}, - GET_SET_INVERTED(g_eeGeneral.disableTrainerPoweroffAlarm)); - line = body->newLine(grid); - } + STR_TRAINER_SHUTDOWN_ALARM, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_SET_INVERTED(g_eeGeneral.disableTrainerPoweroffAlarm)); + } + }, }; class BacklightPage : public SubPage { public: - BacklightPage() : SubPage(ICON_RADIO_SETUP, STR_BACKLIGHT_LABEL) + BacklightPage() : SubPage(ICON_RADIO_SETUP, STR_RADIO_SETUP, STR_BACKLIGHT_LABEL, true) { - FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY); - - auto line = body->newLine(grid); + body->setFlexLayout(); // Backlight mode - new StaticText(line, rect_t{}, STR_MODE); - - 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(); + setupLine(STR_MODE, [=](Window* parent, coord_t x, coord_t y) { + auto blMode = new Choice( + parent, {x, y, 0, 0}, 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; }); }); - blMode->setAvailableHandler( - [=](int newValue) { return newValue != e_backlight_mode_off; }); - - backlightTimeout = body->newLine(grid); - // Delay - new StaticText(backlightTimeout, rect_t{}, STR_BACKLIGHT_TIMER); - 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); + backlightTimeout = setupLine(STR_BACKLIGHT_TIMER, [=](Window* parent, coord_t x, coord_t y) { + auto edit = + new NumberEdit(parent, {x, y, RadioSetupPage::NUM_W, 0}, 5, 600, + GET_DEFAULT(g_eeGeneral.lightAutoOff * 5), + SET_VALUE(g_eeGeneral.lightAutoOff, newValue / 5)); + edit->setStep(5); + edit->setSuffix("s"); + }); // Backlight ON bright - new StaticText(backlightOnBright, rect_t{}, STR_BLONBRIGHTNESS); - 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(); + backlightOnBright = setupLine(STR_BLONBRIGHTNESS, [=](Window* parent, coord_t x, coord_t y) { + backlightOnSlider = new Slider( + parent, 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(); + }); + backlightOnSlider->setPos(x, y); }); - backlightOffBright = body->newLine(grid); - // Backlight OFF bright - new StaticText(backlightOffBright, rect_t{}, STR_BLOFFBRIGHTNESS); - 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 = setupLine(STR_BLOFFBRIGHTNESS, [=](Window* parent, coord_t x, coord_t y) { + backlightOffSlider = new Slider( + parent, 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(); + }); + backlightOffSlider->setPos(x, y); }); - line = body->newLine(grid); - #if defined(KEYS_BACKLIGHT_GPIO) // Keys backlight - new StaticText(line, rect_t{}, STR_KEYS_BACKLIGHT); - new ToggleSwitch(line, rect_t{}, - GET_SET_DEFAULT(g_eeGeneral.keysBacklight)); - line = body->newLine(grid); + setupLine(STR_KEYS_BACKLIGHT, [=](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_SET_DEFAULT(g_eeGeneral.keysBacklight)); + }); #endif // Flash beep - new StaticText(line, rect_t{}, STR_ALARM); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.alarmsFlash)); - line = body->newLine(grid); + setupLine(STR_ALARM, [=](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_eeGeneral.alarmsFlash)); + }); updateBacklightControls(); + + enableRefresh(); } protected: @@ -580,193 +528,204 @@ class BacklightPage : public SubPage } }; -class GpsPage : public SubPage -{ - public: - GpsPage() : SubPage(ICON_RADIO_SETUP, STR_GPS) +static SetupLineDef gpsPageSetupLines[] = { { - 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); - 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); - + STR_TIMEZONE, + [](Window* parent, coord_t x, coord_t y) { + auto tz = new NumberEdit(parent, {x, y, RadioSetupPage::NUM_W, 0}, minTimezone(), maxTimezone(), + []() { + return timezoneIndex(g_eeGeneral.timezone, g_eeGeneral.timezoneMinutes); + }, + [](int newTz) { + g_eeGeneral.timezone = timezoneHour(newTz); + g_eeGeneral.timezoneMinutes = + timezoneMinute(newTz); + SET_DIRTY(); + }); + tz->setDisplayHandler([](int32_t tz) { return timezoneDisplay(tz); }); + } + }, + { // Adjust RTC (from telemetry) - new StaticText(line, rect_t{}, STR_ADJUST_RTC); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_eeGeneral.adjustRTC)); - line = body->newLine(grid); - + STR_ADJUST_RTC, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_eeGeneral.adjustRTC)); + } + }, + { // GPS format - new StaticText(line, rect_t{}, STR_GPS_COORDS_FORMAT); - new Choice(line, rect_t{}, STR_GPSFORMAT, 0, 1, - GET_SET_DEFAULT(g_eeGeneral.gpsFormat)); - line = body->newLine(grid); - } - - protected: - int tzIndex; + STR_GPS_COORDS_FORMAT, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_GPSFORMAT, 0, 1, + GET_SET_DEFAULT(g_eeGeneral.gpsFormat)); + } + }, }; -class ViewOptionsPage : public SubPage +static void viewOption(Window* parent, coord_t x, coord_t y, + std::function getValue, + std::function setValue, uint8_t modelOption) { - 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(FormLine* line, const char* name, - std::function getValue, - std::function setValue, uint8_t modelOption) - { - line->padLeft(10); - new StaticText(line, rect_t{}, name); - 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); - } + new ToggleSwitch(parent, {x, y, 0, 0}, getValue, setValue); + if (modelOption != OVERRIDE_GLOBAL) { + std::string s(STR_MODEL); + s += " - "; + s += STR_ADCFILTERVALUES[modelOption]; + new StaticText(parent, {x + ToggleSwitch::TOGGLE_W + PAD_MEDIUM, y + PAD_SMALL + 1, 0, 0}, s.c_str(), COLOR_THEME_SECONDARY1); } +} - public: - ViewOptionsPage() : SubPage(ICON_RADIO_SETUP, STR_ENABLED_FEATURES) +static SetupLineDef viewOptionsPageSetupLines[] = { + { + STR_RADIO_MENU_TABS, nullptr, + }, + { + STR_THEME_EDITOR, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.radioThemesDisabled), + g_model.radioThemesDisabled); + } + }, + { + STR_MENUSPECIALFUNCS, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.radioGFDisabled), + g_model.radioGFDisabled); + } + }, + { + STR_MENUTRAINER, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.radioTrainerDisabled), + g_model.radioTrainerDisabled); + } + }, + { + STR_MODEL_MENU_TABS, nullptr, + }, { - FlexGridLayout grid(opt_col_dsc, row_dsc, PAD_TINY); - - auto line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_RADIO_MENU_TABS); - - line = body->newLine(grid); - viewOption(line, STR_THEME_EDITOR, - GET_SET_INVERTED(g_eeGeneral.radioThemesDisabled), - g_model.radioThemesDisabled); - - line = body->newLine(grid); - viewOption(line, STR_MENUSPECIALFUNCS, - GET_SET_INVERTED(g_eeGeneral.radioGFDisabled), - g_model.radioGFDisabled); - - line = body->newLine(grid); - viewOption(line, STR_MENUTRAINER, - GET_SET_INVERTED(g_eeGeneral.radioTrainerDisabled), - g_model.radioTrainerDisabled); - - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_MODEL_MENU_TABS); - #if defined(HELI) - line = body->newLine(grid); - viewOption(line, STR_MENUHELISETUP, - GET_SET_INVERTED(g_eeGeneral.modelHeliDisabled), - g_model.modelHeliDisabled); + STR_MENUHELISETUP, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.modelHeliDisabled), + g_model.modelHeliDisabled); + } + }, #endif - #if defined(FLIGHT_MODES) - line = body->newLine(grid); - viewOption(line, STR_MENUFLIGHTMODES, - GET_SET_INVERTED(g_eeGeneral.modelFMDisabled), - g_model.modelFMDisabled); + { + STR_MENUFLIGHTMODES, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.modelFMDisabled), + g_model.modelFMDisabled); + } + }, #endif - #if defined(GVARS) - line = body->newLine(grid); - viewOption(line, STR_MENU_GLOBAL_VARS, - GET_SET_INVERTED(g_eeGeneral.modelGVDisabled), - g_model.modelGVDisabled); + { + STR_MENU_GLOBAL_VARS, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.modelGVDisabled), + g_model.modelGVDisabled); + } + }, #endif - - line = body->newLine(grid); - viewOption(line, STR_MENUCURVES, - GET_SET_INVERTED(g_eeGeneral.modelCurvesDisabled), - g_model.modelCurvesDisabled); - - line = body->newLine(grid); - viewOption(line, STR_MENULOGICALSWITCHES, - GET_SET_INVERTED(g_eeGeneral.modelLSDisabled), - g_model.modelLSDisabled); - - line = body->newLine(grid); - viewOption(line, STR_MENUCUSTOMFUNC, - GET_SET_INVERTED(g_eeGeneral.modelSFDisabled), - g_model.modelSFDisabled); - + { + STR_MENUCURVES, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.modelCurvesDisabled), + g_model.modelCurvesDisabled); + } + }, + { + STR_MENULOGICALSWITCHES, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.modelLSDisabled), + g_model.modelLSDisabled); + } + }, + { + STR_MENUCUSTOMFUNC, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.modelSFDisabled), + g_model.modelSFDisabled); + } + }, #if defined(LUA_MODEL_SCRIPTS) - line = body->newLine(grid); - viewOption(line, STR_MENUCUSTOMSCRIPTS, - GET_SET_INVERTED(g_eeGeneral.modelCustomScriptsDisabled), - g_model.modelCustomScriptsDisabled); + { + STR_MENUCUSTOMSCRIPTS, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.modelCustomScriptsDisabled), + g_model.modelCustomScriptsDisabled); + } + }, #endif - - line = body->newLine(grid); - viewOption(line, STR_MENUTELEMETRY, - GET_SET_INVERTED(g_eeGeneral.modelTelemetryDisabled), - g_model.modelTelemetryDisabled); - } + { + STR_MENUTELEMETRY, + [](Window* parent, coord_t x, coord_t y) { + viewOption(parent, x, y, + GET_SET_INVERTED(g_eeGeneral.modelTelemetryDisabled), + g_model.modelTelemetryDisabled); + } + }, }; class ManageModelsSetupPage : public SubPage { public: - ManageModelsSetupPage() : SubPage(ICON_MODEL, STR_MANAGE_MODELS) + ManageModelsSetupPage() : SubPage(ICON_MODEL, STR_RADIO_SETUP, STR_MANAGE_MODELS, true) { - FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY); + body->setFlexLayout(); // Model quick select - auto line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_MODEL_QUICK_SELECT); - new ToggleSwitch(line, rect_t{}, - GET_SET_DEFAULT(g_eeGeneral.modelQuickSelect)); + setupLine(STR_MODEL_QUICK_SELECT, [=](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_SET_DEFAULT(g_eeGeneral.modelQuickSelect)); + }); // Label single/multi select - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_LABELS_SELECT); - new Choice(line, rect_t{}, STR_LABELS_SELECT_MODE, 0, 1, - GET_DEFAULT(g_eeGeneral.labelSingleSelect), - [=](int newValue) { - g_eeGeneral.labelSingleSelect = newValue; - modelslabels.clearFilter(); - SET_DIRTY(); - }); + setupLine(STR_LABELS_SELECT, [=](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_LABELS_SELECT_MODE, 0, 1, + GET_DEFAULT(g_eeGeneral.labelSingleSelect), + [=](int newValue) { + g_eeGeneral.labelSingleSelect = newValue; + modelslabels.clearFilter(); + SET_DIRTY(); + }); + }); // Label multi select matching mode - multiSelectMatch = body->newLine(grid); - new StaticText(multiSelectMatch, rect_t{}, STR_LABELS_MATCH); - new Choice(multiSelectMatch, rect_t{}, STR_LABELS_MATCH_MODE, 0, 1, - GET_SET_DEFAULT(g_eeGeneral.labelMultiMode)); + multiSelectMatch = setupLine(STR_LABELS_MATCH, [=](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_LABELS_MATCH_MODE, 0, 1, + GET_SET_DEFAULT(g_eeGeneral.labelMultiMode)); + }); // Favorites multi select matching mode - favSelectMatch = body->newLine(grid); - new StaticText(favSelectMatch, rect_t{}, STR_FAV_MATCH); - new Choice(favSelectMatch, rect_t{}, STR_FAV_MATCH_MODE, 0, 1, - GET_SET_DEFAULT(g_eeGeneral.favMultiMode)); + favSelectMatch = setupLine(STR_FAV_MATCH, [=](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_FAV_MATCH_MODE, 0, 1, + GET_SET_DEFAULT(g_eeGeneral.favMultiMode)); + }); checkEvents(); + + enableRefresh(); } void checkEvents() override { - if (g_eeGeneral.labelSingleSelect) { - lv_obj_add_flag(multiSelectMatch->getLvObj(), LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(favSelectMatch->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_clear_flag(multiSelectMatch->getLvObj(), LV_OBJ_FLAG_HIDDEN); - if (g_eeGeneral.labelMultiMode == 0) - lv_obj_add_flag(favSelectMatch->getLvObj(), LV_OBJ_FLAG_HIDDEN); - else - lv_obj_clear_flag(favSelectMatch->getLvObj(), LV_OBJ_FLAG_HIDDEN); - } + multiSelectMatch->show(!g_eeGeneral.labelSingleSelect); + favSelectMatch->show(!g_eeGeneral.labelSingleSelect && (g_eeGeneral.labelMultiMode != 0)); } protected: @@ -774,199 +733,204 @@ class ManageModelsSetupPage : public SubPage Window* favSelectMatch = nullptr; }; -RadioSetupPage::RadioSetupPage(): - PageTab(STR_RADIO_SETUP, ICON_RADIO_SETUP) -{ -} - -void RadioSetupPage::build(Window* window) -{ - FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY); - window->setFlexLayout(); - - // Date & time picker including labels - new DateTimeWindow(window, rect_t{}); - - // TODO: sort out all caps title strings VS quick menu strings - std::string manageModelsTitle(STR_MAIN_MENU_MANAGE_MODELS); - std::replace(manageModelsTitle.begin(), manageModelsTitle.end(), '\n', ' '); - - // Sub-pages - new WindowButtonGroup(window, rect_t{}, { - {STR_SOUND_LABEL, []() { new SoundPage(); }}, -#if defined(VARIO) - {STR_VARIO, []() { new VarioPage(); }}, -#endif -#if defined(HAPTIC) - {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(); }}, - {manageModelsTitle.c_str(), []() { new ManageModelsSetupPage(); }}, - }); - - // Splash screen - auto line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_SPLASHSCREEN); - 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); - new ToggleSwitch(line, rect_t{}, GET_SET_INVERTED(g_eeGeneral.dontPlayHello)); - +static SetupLineDef setupLines[] = { + { + // Splash screen + STR_SPLASHSCREEN, + [](Window* parent, coord_t x, coord_t y) { + new Choice( + parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 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 + STR_PLAY_HELLO, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 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); - 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(); - }); - } + // Pwr Off Delay + STR_PWR_OFF_DELAY, + [](Window* parent, coord_t x, coord_t y) { + new Choice( + parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 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); - 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); - 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); - auto choice = - new Choice(line, rect_t{}, 0, DIM(languagePacks) - 2, - GET_VALUE(currentLanguagePackIdx), [](uint8_t newValue) { - currentLanguagePackIdx = newValue; - currentLanguagePack = languagePacks[currentLanguagePackIdx]; - strncpy(g_eeGeneral.ttsLanguage, currentLanguagePack->id, 2); - SET_DIRTY(); - }); - choice->setTextHandler( - [](uint8_t value) { return languagePacks[value]->name; }); - - // Imperial units - line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_UNITS_SYSTEM); - 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); - 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: - lcdDrawText(MENUS_MARGIN_LEFT, y, "FAI Mode"); - if (g_eeGeneral.fai) { - 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; - POPUP_CONFIRMATION("FAI mode?"); - } + // Owner ID + STR_OWNER_ID, + [](Window* parent, coord_t x, coord_t y) { + new RadioTextEdit(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, g_eeGeneral.ownerRegistrationID, + PXX2_LEN_REGISTRATION_ID); } - break;*/ + }, #endif - - // Switches delay - line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_SWITCHES_DELAY); - auto edit = - 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); - new Choice(line, rect_t{}, STR_USBMODES, USB_UNSELECTED_MODE, USB_MAX_MODE, - GET_SET_DEFAULT(g_eeGeneral.USBMode)); - + { + // Country code + STR_COUNTRY_CODE, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, STR_COUNTRY_CODES, 0, 2, + GET_SET_DEFAULT(g_eeGeneral.countryCode)); + } + }, + { + // Audio language + STR_VOICE_LANGUAGE, + [](Window* parent, coord_t x, coord_t y) { + auto choice = + new Choice(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 0, DIM(languagePacks) - 2, + GET_VALUE(currentLanguagePackIdx), [](uint8_t newValue) { + currentLanguagePackIdx = newValue; + currentLanguagePack = languagePacks[currentLanguagePackIdx]; + strncpy(g_eeGeneral.ttsLanguage, currentLanguagePack->id, 2); + SET_DIRTY(); + }); + choice->setTextHandler( + [](uint8_t value) { return languagePacks[value]->name; }); + } + }, + { + // Imperial units + STR_UNITS_SYSTEM, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, STR_VUNITSSYSTEM, 0, 1, + GET_SET_DEFAULT(g_eeGeneral.imperial)); + } + }, + { + // PPM units + STR_UNITS_PPM, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, STR_PPMUNIT, PPM_PERCENT_PREC0, PPM_PERCENT_PREC1, + GET_SET_DEFAULT(g_eeGeneral.ppmunit)); + } + }, + { + // Switches delay + STR_SWITCHES_DELAY, + [](Window* parent, coord_t x, coord_t y) { + auto edit = + new NumberEdit(parent, {x, y, RadioSetupPage::NUM_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 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 + STR_USBMODE, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 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); - new Choice(line, rect_t{}, STR_ROTARY_ENC_OPT, ROTARY_ENCODER_MODE_NORMAL, - ROTARY_ENCODER_MODE_INVERT_BOTH, - GET_SET_DEFAULT(g_eeGeneral.rotEncMode)); + { + STR_ROTARY_ENC_MODE, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 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); - 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 MessageDialog(window, STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "", - LEFT); - return 0; - }); + { + STR_HATSMODE, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 120, EdgeTxStyles::UI_ELEMENT_HEIGHT}, STR_HATSOPT, HATSMODE_TRIMS_ONLY, + HATSMODE_SWITCHABLE, GET_SET_DEFAULT(g_eeGeneral.hatsMode)); + new TextButton(parent, {x + 120 + PAD_MEDIUM, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, "?", [=]() { + new MessageDialog(parent, STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "", + LEFT); + return 0; + }); + } + }, #endif + { + // RX channel order + STR_DEF_CHAN_ORD, + [](Window* parent, coord_t x, coord_t y) { + uint8_t mains = adcGetMaxInputs(ADC_INPUT_MAIN); + auto max_order = inputMappingGetMaxChannelOrder() - 1; + auto choice = new Choice(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 0, max_order, + GET_SET_DEFAULT(g_eeGeneral.templateSetup)); + + choice->setTextHandler([=](uint8_t value) { + std::string s; + for (uint8_t i = 0; i < mains; i++) { + s += getAnalogShortLabel(inputMappingChannelOrder(value, i)); + } + return s; + }); + } + }, + { + // Stick mode + STR_MODE, + [](Window* parent, coord_t x, coord_t y) { + auto choice = new Choice(parent, {x, y, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT}, 0, 3, GET_DEFAULT(g_eeGeneral.stickMode), + [=](uint8_t newValue) { + mixerTaskStop(); + g_eeGeneral.stickMode = newValue; + SET_DIRTY(); + checkThrottleStick(); + mixerTaskStart(); + }); + choice->setTextHandler([](uint8_t value) { + auto stick0 = inputMappingConvertMode(value, 0); + auto stick1 = inputMappingConvertMode(value, 1); + return std::to_string(1 + value) + ": " + STR_LEFT_STICK + " = " + + std::string(getMainControlLabel(stick0)) + "+" + + std::string(getMainControlLabel(stick1)); + }); + } + }, +}; + +RadioSetupPage::RadioSetupPage() : PageTab(STR_RADIO_SETUP, ICON_RADIO_SETUP, PAD_TINY) {} + +void RadioSetupPage::build(Window* window) +{ + coord_t y = 0; + Window * w; - // RX channel order - line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_DEF_CHAN_ORD); // RAET->AETR - - uint8_t mains = adcGetMaxInputs(ADC_INPUT_MAIN); - auto max_order = inputMappingGetMaxChannelOrder() - 1; - choice = new Choice(line, rect_t{}, 0, max_order, - GET_SET_DEFAULT(g_eeGeneral.templateSetup)); - - choice->setTextHandler([=](uint8_t value) { - std::string s; - for (uint8_t i = 0; i < mains; i++) { - s += getAnalogShortLabel(inputMappingChannelOrder(value, i)); - } - return s; - }); - - // Stick mode - line = window->newLine(grid); - new StaticText(line, rect_t{}, STR_MODE); - choice = new Choice(line, rect_t{}, 0, 3, GET_DEFAULT(g_eeGeneral.stickMode), - [=](uint8_t newValue) { - mixerTaskStop(); - g_eeGeneral.stickMode = newValue; - SET_DIRTY(); - checkThrottleStick(); - mixerTaskStart(); - }); - choice->setTextHandler([](uint8_t value) { - auto stick0 = inputMappingConvertMode(value, 0); - auto stick1 = inputMappingConvertMode(value, 1); - return std::to_string(1 + value) + ": " + STR_LEFT_STICK + " = " + - std::string(getMainControlLabel(stick0)) + "+" + - std::string(getMainControlLabel(stick1)); - }); + // Date & time picker including labels + w = new DateTimeWindow(window, {0, y, LCD_W - padding * 2, EdgeTxStyles::UI_ELEMENT_HEIGHT * 2 + PAD_TINY * 2 + PAD_MEDIUM}); + y += w->height() + padding; + + // Sub-pages + w = new SetupButtonGroup(window, {0, y, LCD_W - padding * 2, 0}, nullptr, BTN_COLS, PAD_TINY, { + {STR_SOUND_LABEL, []() { new SubPage(ICON_RADIO_SETUP, STR_RADIO_SETUP, STR_SOUND_LABEL, soundPageSetupLines, DIM(soundPageSetupLines)); }}, +#if defined(VARIO) + {STR_VARIO, []() { new SubPage(ICON_RADIO_SETUP, STR_RADIO_SETUP, STR_VARIO, varioPageSetupLines, DIM(varioPageSetupLines)); }}, +#endif +#if defined(HAPTIC) + {STR_HAPTIC_LABEL, []() { new SubPage(ICON_RADIO_SETUP, STR_RADIO_SETUP, STR_HAPTIC_LABEL, hapticPageSetupLines, DIM(hapticPageSetupLines)); }}, +#endif + {STR_ALARMS_LABEL, []() { new SubPage(ICON_RADIO_SETUP, STR_RADIO_SETUP, STR_ALARMS_LABEL, alarmsPageSetupLines, DIM(alarmsPageSetupLines)); }}, + {STR_BACKLIGHT_LABEL, []() { new BacklightPage(); }}, + {STR_GPS, []() { new SubPage(ICON_RADIO_SETUP, STR_RADIO_SETUP, STR_GPS, gpsPageSetupLines, DIM(gpsPageSetupLines)); }}, + {STR_ENABLED_FEATURES, []() { new SubPage(ICON_RADIO_SETUP, STR_RADIO_SETUP, STR_ENABLED_FEATURES, viewOptionsPageSetupLines, DIM(viewOptionsPageSetupLines)); }}, + {STR_MAIN_MENU_MANAGE_MODELS, []() { new ManageModelsSetupPage(); }}, + }, BTN_H); + y += w->height() + padding; + + SetupLine::showLines(window, y, SubPage::EDT_X, padding, setupLines, DIM(setupLines)); } diff --git a/radio/src/gui/colorlcd/radio_setup.h b/radio/src/gui/colorlcd/radio_setup.h index 1c267e89c7b..3a1cd0bd23c 100644 --- a/radio/src/gui/colorlcd/radio_setup.h +++ b/radio/src/gui/colorlcd/radio_setup.h @@ -24,8 +24,12 @@ #include "tabsgroup.h" class RadioSetupPage: public PageTab { - public: - RadioSetupPage(); + public: + RadioSetupPage(); - void build(Window * window) override; + void build(Window * window) override; + + static LAYOUT_VAL(NUM_W, 80, 80) + static LAYOUT_VAL(BTN_COLS, 3, 2) + static LAYOUT_VAL(BTN_H, 62, 62) }; diff --git a/radio/src/gui/colorlcd/radio_theme.cpp b/radio/src/gui/colorlcd/radio_theme.cpp index 06a2b6af93a..3868906319f 100644 --- a/radio/src/gui/colorlcd/radio_theme.cpp +++ b/radio/src/gui/colorlcd/radio_theme.cpp @@ -30,32 +30,6 @@ #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); -#else -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 int COLOR_BOX_WIDTH = 45; -#else -constexpr int BUTTON_WIDTH = 65; - -constexpr int COLOR_BOX_WIDTH = 55; -#endif - -constexpr int BUTTON_HEIGHT = 30; -constexpr int COLOR_BOX_HEIGHT = 30; - -constexpr int BOX_MARGIN = 2; -constexpr int MAX_BOX_WIDTH = 15; - class ThemeColorPreview : public Window { public: @@ -66,7 +40,7 @@ class ThemeColorPreview : public Window setWindowFlag(NO_FOCUS); padAll(PAD_ZERO); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD setFlexLayout(LV_FLEX_FLOW_COLUMN, BOX_MARGIN); #else setFlexLayout(LV_FLEX_FLOW_ROW, BOX_MARGIN); @@ -79,7 +53,7 @@ class ThemeColorPreview : public Window clear(); setBoxWidth(); int size = (boxWidth + BOX_MARGIN) * colorList.size() - BOX_MARGIN; -#if LCD_W > LCD_H +#if !PORTRAIT_LCD padTop((height() - size) / 2); #else padLeft((width() - size) / 2); @@ -95,13 +69,16 @@ class ThemeColorPreview : public Window build(); } + static LAYOUT_VAL(MAX_BOX_WIDTH, 15, 15) + static constexpr int BOX_MARGIN = 2; + protected: std::vector colorList; int boxWidth = MAX_BOX_WIDTH; void setBoxWidth() { -#if LCD_W > LCD_H +#if !PORTRAIT_LCD boxWidth = (height() - (colorList.size() - 1) * BOX_MARGIN) / colorList.size(); #else @@ -166,7 +143,7 @@ class ThemeDetailsDialog : public BaseDialog line->padTop(10); auto button = - new TextButton(line, rect_t{0, 0, lv_pct(30), 32}, STR_CANCEL, [=]() { + new TextButton(line, rect_t{0, 0, lv_pct(30), 0}, STR_CANCEL, [=]() { deleteLater(); return 0; }); @@ -174,7 +151,7 @@ class ThemeDetailsDialog : public BaseDialog LV_GRID_ALIGN_CENTER, 0, 1); button = - new TextButton(line, rect_t{0, 0, lv_pct(30), 32}, STR_SAVE, [=]() { + new TextButton(line, rect_t{0, 0, lv_pct(30), 0}, STR_SAVE, [=]() { if (saveHandler != nullptr) if (!saveHandler(this->theme)) return 0; @@ -215,6 +192,17 @@ class ColorEditPage : public Page } } + static LAYOUT_VAL(COLOR_BOX_WIDTH, 45, 55) + static LAYOUT_VAL(COLOR_BOX_HEIGHT, 30, 30) + static LAYOUT_VAL(HEX_STR_W, 95, 95) + static LAYOUT_VAL(BUTTON_WIDTH, 75, 65) + +#if PORTRAIT_LCD + static constexpr int COLOR_LIST_HEIGHT = (LCD_H / 2 - 24); +#else + static constexpr int COLOR_LIST_WIDTH = ((LCD_W * 3) / 10); +#endif + protected: std::function _updateHandler; LcdColorIndex _indexOfColor; @@ -247,22 +235,22 @@ class ColorEditPage : public Page void buildBody(Window *form) { form->padAll(PAD_SMALL); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD form->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL); - rect_t r = {0, 0, COLOR_LIST_WIDTH, form->height() - 8}; + rect_t r = {0, 0, COLOR_LIST_WIDTH, form->height() - PAD_LARGE}; #else form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_SMALL); - rect_t r = {0, 0, form->width() - 9, COLOR_LIST_HEIGHT}; + rect_t r = {0, 0, form->width() - PAD_LARGE, COLOR_LIST_HEIGHT}; #endif Window *colForm = new Window(form, r); colForm->padAll(PAD_ZERO); colForm->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_SMALL, r.w); -#if LCD_W > LCD_H - r.w = form->width() - COLOR_LIST_WIDTH - 12; +#if !PORTRAIT_LCD + r.w = form->width() - COLOR_LIST_WIDTH - PAD_MEDIUM * 2; #else - r.h = form->height() - COLOR_LIST_HEIGHT - 12; + r.h = form->height() - COLOR_LIST_HEIGHT - PAD_MEDIUM * 2; #endif _previewWindow = new PreviewWindow(form, r, _theme->getColorList()); @@ -296,7 +284,7 @@ class ColorEditPage : public Page colBoxForm, r, _theme->getColorEntryByIndex(_indexOfColor)->colorValue); // hexBox - r.w = 95; + r.w = HEX_STR_W; _hexBox = new StaticText(colBoxForm, r, "", COLOR_THEME_PRIMARY1 | FONT(L) | RIGHT); setHexStr(_theme->getColorEntryByIndex(_indexOfColor)->colorValue); } @@ -307,14 +295,14 @@ class ColorEditPage : public Page header->setTitle(STR_EDIT_COLOR); auto t2 = header->setTitle2(ThemePersistance::getColorNames()[(int)_indexOfColor]); -#if LCD_H > LCD_W +#if PORTRAIT_LCD etx_font(t2->getLvObj(), FONT_XS_INDEX); #else LV_UNUSED(t2); #endif // page tabs - rect_t r = {LCD_W - 2 * (BUTTON_WIDTH + 5), 6, BUTTON_WIDTH, BUTTON_HEIGHT}; + rect_t r = {LCD_W - 2 * (BUTTON_WIDTH + 5), PAD_MEDIUM, BUTTON_WIDTH, EdgeTxStyles::UI_ELEMENT_HEIGHT}; _tabs.emplace_back(new TextButton(window, r, "RGB", [=]() { setActiveColorBar(0); return 1; @@ -384,12 +372,12 @@ class ThemeEditPage : public Page // page title header->setTitle(STR_EDIT_THEME); _themeName = header->setTitle2(_theme.getName()); -#if LCD_H > LCD_W +#if PORTRAIT_LCD etx_font(_themeName->getLvObj(), FONT_XS_INDEX); #endif // save and cancel - rect_t r = {LCD_W - (BUTTON_WIDTH + 5), 6, BUTTON_WIDTH, BUTTON_HEIGHT}; + rect_t r = {LCD_W - (ColorEditPage::BUTTON_WIDTH + 5), PAD_MEDIUM, ColorEditPage::BUTTON_WIDTH, EdgeTxStyles::UI_ELEMENT_HEIGHT}; new TextButton(window, r, STR_DETAILS, [=]() { new ThemeDetailsDialog(page, _theme, [=](ThemeFile t) { _theme.setAuthor(t.getAuthor()); @@ -408,22 +396,22 @@ class ThemeEditPage : public Page void buildBody(Window *form) { form->padAll(PAD_SMALL); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD form->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL); - rect_t r = {0, 0, COLOR_LIST_WIDTH, form->height() - 8}; + rect_t r = {0, 0, ColorEditPage::COLOR_LIST_WIDTH, form->height() - PAD_LARGE}; #else form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_SMALL); - rect_t r = {0, 0, form->width() - 8, COLOR_LIST_HEIGHT}; + rect_t r = {0, 0, form->width() - 8, ColorEditPage::COLOR_LIST_HEIGHT}; #endif _cList = new ColorList(form, r, _theme.getColorList()); _cList->setLongPressHandler([=]() { editColorPage(); }); _cList->setPressHandler([=]() { editColorPage(); }); -#if LCD_W > LCD_H - r.w = form->width() - COLOR_LIST_WIDTH - 12; +#if !PORTRAIT_LCD + r.w = form->width() - ColorEditPage::COLOR_LIST_WIDTH - PAD_MEDIUM * 2; #else - r.h = form->height() - COLOR_LIST_HEIGHT - 12; + r.h = form->height() - ColorEditPage::COLOR_LIST_HEIGHT - PAD_MEDIUM * 2; #endif _previewWindow = new PreviewWindow(form, r, _theme.getColorList()); } @@ -617,7 +605,7 @@ void ThemeSetupPage::build(Window *window) window->padAll(PAD_SMALL); pageWindow = window; -#if LCD_W > LCD_H +#if !PORTRAIT_LCD window->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY); #else window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); @@ -634,14 +622,14 @@ void ThemeSetupPage::build(Window *window) authorText = nullptr; // create listbox and setup menus -#if LCD_W > LCD_H +#if !PORTRAIT_LCD rect_t r = {0, 0, LIST_WIDTH, window->height() - 8}; #else rect_t r = {0, 0, window->width() - 8, LIST_HEIGHT}; #endif setupListbox(window, r, tp); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD r.w = COLOR_PREVIEW_SIZE; #else r.h = COLOR_PREVIEW_SIZE; @@ -653,7 +641,7 @@ void ThemeSetupPage::build(Window *window) themeColorPreview = new ThemeColorPreview(window, r, colorList); themeColorPreview->setWidth(r.w); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD r.w = window->width() - LIST_WIDTH - COLOR_PREVIEW_SIZE - 12; r.h = window->height() - 8; #else diff --git a/radio/src/gui/colorlcd/radio_theme.h b/radio/src/gui/colorlcd/radio_theme.h index c593861dca5..05178f489c7 100644 --- a/radio/src/gui/colorlcd/radio_theme.h +++ b/radio/src/gui/colorlcd/radio_theme.h @@ -41,6 +41,13 @@ class ThemeSetupPage : public PageTab bool isVisible() const override { return radioThemesEnabled(); } + static LAYOUT_VAL(COLOR_PREVIEW_SIZE, 18, 18) +#if PORTRAIT_LCD + static constexpr int LIST_HEIGHT = (LCD_H / 2 - 38); +#else + static constexpr int LIST_WIDTH = ((LCD_W - PAD_MEDIUM * 2) / 2 - COLOR_PREVIEW_SIZE); +#endif + protected: TabsGroup *tabsGroup = nullptr; Window *pageWindow = nullptr; diff --git a/radio/src/gui/colorlcd/radio_tools.cpp b/radio/src/gui/colorlcd/radio_tools.cpp index 02a6b5deafe..5d60c83fc67 100644 --- a/radio/src/gui/colorlcd/radio_tools.cpp +++ b/radio/src/gui/colorlcd/radio_tools.cpp @@ -180,16 +180,19 @@ struct ToolButton : public TextButton { return 0; }) { - if (LCD_W > LCD_H) - setWidth((LCD_W - 24) / 3); // 3 columns on landscape - else - setWidth((LCD_W - 18) / 2); // 2 columns on portrait - setHeight(48); +#if !PORTRAIT_LCD + setWidth((LCD_W - 24) / 3); // 3 columns on landscape +#else + setWidth((LCD_W - 18) / 2); // 2 columns on portrait +#endif + setHeight(TOOLS_BTN_H); 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); } + + static LAYOUT_VAL(TOOLS_BTN_H, 48, 48) }; void RadioToolsPage::rebuild(Window* window) diff --git a/radio/src/gui/colorlcd/radio_trainer.cpp b/radio/src/gui/colorlcd/radio_trainer.cpp index 4be9c3fad21..9971f779024 100644 --- a/radio/src/gui/colorlcd/radio_trainer.cpp +++ b/radio/src/gui/colorlcd/radio_trainer.cpp @@ -34,17 +34,14 @@ RadioTrainerPage::RadioTrainerPage() : { } -#if LCD_W > LCD_H +#if !PORTRAIT_LCD static const lv_coord_t col_dsc[] = {LV_GRID_FR(7), LV_GRID_FR(13), LV_GRID_FR(10), LV_GRID_FR(10), LV_GRID_FR(10), LV_GRID_TEMPLATE_LAST}; - -#define NUM_EDIT_W 80 #else static const lv_coord_t col_dsc[] = {LV_GRID_FR(7), LV_GRID_FR(15), LV_GRID_FR(9), LV_GRID_FR(9), LV_GRID_TEMPLATE_LAST}; -#define NUM_EDIT_W 65 #endif static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; @@ -54,7 +51,7 @@ void RadioTrainerPage::build(Window* form) form->padAll(PAD_SMALL); if (SLAVE_MODE()) { - form->setHeight(MENU_BODY_HEIGHT); + form->setHeight(TabsGroup::MENU_BODY_HEIGHT); auto txt = new StaticText(form, rect_t{}, STR_SLAVE, FONT(L)); lv_obj_align(txt->getLvObj(), LV_ALIGN_CENTER, 0, 0); } else { @@ -75,7 +72,7 @@ void RadioTrainerPage::build(Window* form) GET_SET_DEFAULT(td->studWeight)); weight->setSuffix("%"); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = form->newLine(grid); line->padLeft(30); line->padBottom(8); @@ -93,7 +90,7 @@ void RadioTrainerPage::build(Window* form) } auto line = form->newLine(grid); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line->padTop(10); #else line->padTop(6); @@ -113,7 +110,7 @@ void RadioTrainerPage::build(Window* form) lv_obj_set_grid_cell(multiplier->getLvObj(), LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = form->newLine(grid); line->padTop(10); #endif @@ -126,7 +123,7 @@ void RadioTrainerPage::build(Window* form) SET_DIRTY(); return 0; }); -#if LCD_H > LCD_W +#if PORTRAIT_LCD lv_obj_set_grid_cell(btn->getLvObj(), LV_GRID_ALIGN_STRETCH, 1, 2, LV_GRID_ALIGN_CENTER, 0, 1); #else diff --git a/radio/src/gui/colorlcd/radio_trainer.h b/radio/src/gui/colorlcd/radio_trainer.h index 969a083a9c0..c54c1309163 100644 --- a/radio/src/gui/colorlcd/radio_trainer.h +++ b/radio/src/gui/colorlcd/radio_trainer.h @@ -32,4 +32,6 @@ class RadioTrainerPage : public PageTab bool isVisible() const override { return radioTrainerEnabled(); } void build(Window* window) override; + + static LAYOUT_VAL(NUM_EDIT_W, 80, 65) }; diff --git a/radio/src/gui/colorlcd/screen_setup.cpp b/radio/src/gui/colorlcd/screen_setup.cpp index 8bbff3160c9..9261ef93c04 100644 --- a/radio/src/gui/colorlcd/screen_setup.cpp +++ b/radio/src/gui/colorlcd/screen_setup.cpp @@ -44,7 +44,7 @@ class LayoutChoice : public Button LayoutChoice(Window* parent, LayoutFactoryGetter getValue, LayoutFactorySetter setValue) : - Button(parent, {0, 0, BM_W + 12, BM_H + 12}), + Button(parent, {0, 0, LayoutFactory::BM_W + 12, LayoutFactory::BM_H + 12}), getValue(std::move(getValue)), _setValue(std::move(setValue)) { @@ -171,7 +171,7 @@ void ScreenAddPage::build(Window* window) }); } -#if LCD_W > LCD_H +#if !PORTRAIT_LCD static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; #else @@ -236,7 +236,7 @@ void ScreenSetupPage::build(Window* window) Window* btn = new LayoutChoice(line, getFactory, setLayout); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = window->newLine(grid); grid.nextCell(); #endif diff --git a/radio/src/gui/colorlcd/screen_user_interface.cpp b/radio/src/gui/colorlcd/screen_user_interface.cpp index be9a54164e1..a61136f2f14 100644 --- a/radio/src/gui/colorlcd/screen_user_interface.cpp +++ b/radio/src/gui/colorlcd/screen_user_interface.cpp @@ -25,7 +25,7 @@ #include "menu_screen.h" #include "theme_manager.h" -#if LCD_W > LCD_H // landscape +#if !PORTRAIT_LCD // landscape // form grid static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), @@ -93,7 +93,7 @@ class ThemeView : public Window lv_obj_set_width(description->getLvObj(), lv_pct(100)); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD preview = new FilePreview(line, rect_t{0, 0, LCD_W / 2, LCD_H / 2}); #else preview = new FilePreview(line, rect_t{0, 0, LCD_W - 12, LCD_H / 2}); diff --git a/radio/src/gui/colorlcd/select_fab_carousel.cpp b/radio/src/gui/colorlcd/select_fab_carousel.cpp index 3cd813f2c2d..7f58648fba8 100644 --- a/radio/src/gui/colorlcd/select_fab_carousel.cpp +++ b/radio/src/gui/colorlcd/select_fab_carousel.cpp @@ -25,17 +25,13 @@ #include "button.h" #include "static.h" -constexpr coord_t FAB_BUTTON_INNER_WIDTH = FAB_BUTTON_WIDTH - 4; -constexpr coord_t FAB_ICON_SIZE = 52; -constexpr coord_t FAB_ICON_INNER_SIZE = 52 - 4; - static void etx_quick_button_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) { etx_obj_add_style(obj, styles->border_transparent, LV_PART_MAIN); etx_obj_add_style(obj, styles->rounded, LV_PART_MAIN); etx_txt_color(obj, COLOR_WHITE_INDEX, LV_PART_MAIN); - etx_obj_add_style(obj, styles->pad_large, LV_PART_MAIN); + etx_obj_add_style(obj, styles->pad_medium, LV_PART_MAIN); etx_obj_add_style(obj, styles->border, LV_PART_MAIN | LV_STATE_FOCUSED); etx_obj_add_style(obj, styles->border_color_white, @@ -48,8 +44,8 @@ static const lv_obj_class_t etx_quick_button_class = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = FAB_BUTTON_WIDTH, - .height_def = FAB_BUTTON_HEIGHT, + .width_def = SelectFabCarousel::FAB_BUTTON_WIDTH, + .height_def = SelectFabCarousel::FAB_BUTTON_HEIGHT, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE, .instance_size = sizeof(lv_btn_t), @@ -78,8 +74,8 @@ static const lv_obj_class_t etx_quick_icon_class = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = FAB_ICON_SIZE, - .height_def = FAB_ICON_SIZE, + .width_def = SelectFabCarousel::FAB_ICON_SIZE, + .height_def = SelectFabCarousel::FAB_ICON_SIZE, .editable = LV_OBJ_CLASS_EDITABLE_FALSE, .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, .instance_size = sizeof(lv_obj_t), @@ -101,16 +97,16 @@ class SelectFabButton : public ButtonBase auto iconLayout = new Window(this, - {(FAB_BUTTON_INNER_WIDTH - FAB_ICON_SIZE) / 2, - (FAB_BUTTON_INNER_WIDTH - FAB_ICON_SIZE) / 2 - 2, - FAB_ICON_SIZE, FAB_ICON_SIZE}, + {(SelectFabCarousel::FAB_BUTTON_INNER_WIDTH - SelectFabCarousel::FAB_ICON_SIZE) / 2, + (SelectFabCarousel::FAB_BUTTON_INNER_WIDTH - SelectFabCarousel::FAB_ICON_SIZE) / 2 - 2, + SelectFabCarousel::FAB_ICON_SIZE, SelectFabCarousel::FAB_ICON_SIZE}, etx_quick_icon_create); iconLayout->setWindowFlag(NO_FOCUS); (new StaticIcon(iconLayout, 0, 0, icon, COLOR_WHITE)) - ->center(FAB_ICON_INNER_SIZE, FAB_ICON_INNER_SIZE); + ->center(SelectFabCarousel::FAB_ICON_SIZE - 4, SelectFabCarousel::FAB_ICON_SIZE - 4); - new StaticText(this, {0, FAB_BUTTON_HEIGHT - 48, FAB_BUTTON_INNER_WIDTH, 0}, + new StaticText(this, {0, SelectFabCarousel::FAB_BUTTON_HEIGHT - SelectFabCarousel::FAB_TXT_YO, SelectFabCarousel::FAB_BUTTON_INNER_WIDTH, 0}, title, COLOR_WHITE | CENTERED); } diff --git a/radio/src/gui/colorlcd/select_fab_carousel.h b/radio/src/gui/colorlcd/select_fab_carousel.h index 56a0fcce27e..35cb5891000 100644 --- a/radio/src/gui/colorlcd/select_fab_carousel.h +++ b/radio/src/gui/colorlcd/select_fab_carousel.h @@ -24,9 +24,6 @@ #include "form.h" #include "bitmaps.h" -constexpr coord_t FAB_BUTTON_WIDTH = 80; -constexpr coord_t FAB_BUTTON_HEIGHT = 114; - class SelectFabCarousel : public Window { public: @@ -39,4 +36,12 @@ class SelectFabCarousel : public Window // Add a new button to the carousel void addButton(EdgeTxIcon icon, const char* title, std::function pressHandler); + + static LAYOUT_VAL(FAB_BUTTON_WIDTH, 80, 80) + static LAYOUT_VAL(FAB_BUTTON_HEIGHT, 114, 114) + + static LAYOUT_VAL(FAB_ICON_SIZE, 52, 52) + static LAYOUT_VAL(FAB_TXT_YO, 48, 48) + static LAYOUT_VAL(FAB_PAD, 4, 4) + static constexpr coord_t FAB_BUTTON_INNER_WIDTH = FAB_BUTTON_WIDTH - PAD_MEDIUM; }; diff --git a/radio/src/gui/colorlcd/sourcechoice.cpp b/radio/src/gui/colorlcd/sourcechoice.cpp index 190bf599cbb..b2ddab04202 100644 --- a/radio/src/gui/colorlcd/sourcechoice.cpp +++ b/radio/src/gui/colorlcd/sourcechoice.cpp @@ -29,7 +29,7 @@ #include "strhelpers.h" #include "switches.h" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define FILTER_COLUMNS 3 #else #define FILTER_COLUMNS 2 diff --git a/radio/src/gui/colorlcd/special_functions.cpp b/radio/src/gui/colorlcd/special_functions.cpp index d8e0f59a790..9a3b885b618 100644 --- a/radio/src/gui/colorlcd/special_functions.cpp +++ b/radio/src/gui/colorlcd/special_functions.cpp @@ -32,46 +32,6 @@ #define SET_DIRTY() setDirty() -#if LCD_W > LCD_H - -#define SF_BUTTON_H 32 - -#define NM_X 2 -#define NM_Y 4 -#define NM_W 43 -#define SW_Y NM_Y -#define SW_W 70 -#define FN_X (SW_X + SW_W + 2) -#define FN_Y NM_Y -#define FN_W 277 -#define RP_W 40 - -#else - -#define SF_BUTTON_H 44 - -#define NM_X 2 -#define NM_Y 10 -#define NM_W 40 -#define SW_Y 0 -#define SW_W 198 -#define FN_X (NM_X + NM_W + 2) -#define FN_Y 20 -#define FN_W SW_W -#define RP_W 34 - -#endif - -#define NM_H 20 -#define SW_X (NM_X + NM_W + 2) -#define SW_H NM_H -#define FN_H NM_H -#define RP_X (FN_X + FN_W + 2) -#define RP_Y NM_Y -#define RP_H NM_H -#define EN_X (RP_X + RP_W + 5) -#define EN_Y NM_Y + 2 - //----------------------------------------------------------------------------- static const char *_failsafe_module[] = { @@ -104,8 +64,8 @@ static const lv_obj_class_t sf_enable_state = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = 16, - .height_def = 16, + .width_def = FunctionLineButton::EN_SZ, + .height_def = FunctionLineButton::EN_SZ, .editable = LV_OBJ_CLASS_EDITABLE_FALSE, .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, .instance_size = sizeof(lv_obj_t), @@ -121,7 +81,7 @@ FunctionLineButton::FunctionLineButton(Window *parent, const rect_t &rect, uint8_t index, const char *prefix) : ListLineButton(parent, index), cfn(cfn), prefix(prefix) { - setHeight(SF_BUTTON_H); + setHeight(FunctionsPage::SF_BUTTON_H); padAll(PAD_ZERO); lv_obj_add_event_cb(lvobj, FunctionLineButton::on_draw, @@ -143,6 +103,8 @@ void FunctionLineButton::delayed_init() { init = true; + lv_obj_enable_style_refresh(false); + sfName = lv_label_create(lvobj); lv_obj_set_pos(sfName, NM_X, NM_Y); lv_obj_set_size(sfName, NM_W, NM_H); @@ -165,6 +127,9 @@ void FunctionLineButton::delayed_init() lv_obj_set_pos(sfEnable, EN_X, EN_Y); lv_obj_update_layout(lvobj); + + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); } void FunctionLineButton::refresh() @@ -334,10 +299,10 @@ void FunctionEditPage::on_draw(lv_event_t *e) { lv_obj_t *target = lv_event_get_target(e); auto page = (FunctionEditPage *)lv_obj_get_user_data(target); - if (page) page->delayed_init(e); + if (page) page->delayed_init(); } -void FunctionEditPage::delayed_init(lv_event_t *e) +void FunctionEditPage::delayed_init() { if (!init) { init = true; @@ -777,7 +742,7 @@ void FunctionsPage::plusPopup(Window *window) void FunctionsPage::build(Window *window) { -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define PER_ROW 6 static const lv_coord_t l_col_dsc[] = { LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), diff --git a/radio/src/gui/colorlcd/special_functions.h b/radio/src/gui/colorlcd/special_functions.h index 81033e21f25..7bdc7a5c206 100644 --- a/radio/src/gui/colorlcd/special_functions.h +++ b/radio/src/gui/colorlcd/special_functions.h @@ -50,6 +50,26 @@ class FunctionLineButton : public ListLineButton void refresh() override; + static constexpr coord_t NM_X = PAD_TINY; + static LAYOUT_VAL(NM_Y, 4, 10) + static LAYOUT_VAL(NM_W, 43, 40) + static LAYOUT_VAL(NM_H, 20, 20) + static constexpr coord_t SW_X = NM_X + NM_W + PAD_TINY; + static LAYOUT_VAL(SW_Y, NM_Y, 0) + static LAYOUT_VAL(SW_W, 70, 198) + static constexpr coord_t SW_H = NM_H; + static LAYOUT_VAL(FN_X, SW_X + SW_W + PAD_TINY, NM_X + NM_W + PAD_TINY) + static LAYOUT_VAL(FN_Y, NM_Y, 20) + static LAYOUT_VAL(FN_W, 278, SW_W) + static LAYOUT_VAL(RP_W, 40, 34) + static constexpr coord_t FN_H = NM_H; + static constexpr coord_t RP_X = FN_X + FN_W + PAD_TINY; + static constexpr coord_t RP_Y = NM_Y; + static constexpr coord_t RP_H = NM_H; + static constexpr coord_t EN_X = RP_X + RP_W + PAD_TINY; + static constexpr coord_t EN_Y = NM_Y + PAD_TINY_GAP; + static LAYOUT_VAL(EN_SZ, 16, 16) + protected: bool init = false; const CustomFunctionData *cfn; @@ -74,7 +94,7 @@ class FunctionEditPage : public Page static void on_draw(lv_event_t *e); - void delayed_init(lv_event_t *e); + void delayed_init(); protected: bool init = false; @@ -114,6 +134,8 @@ class FunctionsPage : public PageTab void build(Window* window) override; + static LAYOUT_VAL(SF_BUTTON_H, 32, 44) + protected: int8_t focusIndex = -1; int8_t prevFocusIndex = -1; diff --git a/radio/src/gui/colorlcd/standalone_lua.cpp b/radio/src/gui/colorlcd/standalone_lua.cpp index c186789bdf5..5a594a3909c 100644 --- a/radio/src/gui/colorlcd/standalone_lua.cpp +++ b/radio/src/gui/colorlcd/standalone_lua.cpp @@ -45,7 +45,7 @@ void LuaPopup::paint(BitmapBuffer* dc, uint8_t type, const char* text, dc->drawSolidFilledRect(0, POPUP_HEADER_HEIGHT, rect.w, rect.h - POPUP_HEADER_HEIGHT, COLOR_THEME_SECONDARY3); - dc->drawText(FIELD_PADDING_LEFT, POPUP_HEADER_HEIGHT + PAGE_LINE_HEIGHT, info, + dc->drawText(FIELD_PADDING_LEFT, POPUP_HEADER_HEIGHT + EdgeTxStyles::PAGE_LINE_HEIGHT, info, COLOR_THEME_SECONDARY1); } diff --git a/radio/src/gui/colorlcd/startup_shutdown.cpp b/radio/src/gui/colorlcd/startup_shutdown.cpp index b2a56785ab1..85ebb6b4a6c 100644 --- a/radio/src/gui/colorlcd/startup_shutdown.cpp +++ b/radio/src/gui/colorlcd/startup_shutdown.cpp @@ -31,23 +31,25 @@ extern void checkSpeakerVolume(); #if defined(VERSION_TAG) const std::string ver_str = "" VERSION_TAG; const std::string nam_str = "" CODENAME; -#if LCD_W > LCD_H -#define TXT_Y 204 -#else +#if PORTRAIT_LCD #define TXT_Y 404 +#else +#define TXT_Y (LCD_H * 3 / 4) #endif #else const std::string ver_str = "" VERSION; const std::string nam_str = "" VERSION_SUFFIX; const std::string git_str = "(" GIT_STR ")"; -#if LCD_W > LCD_H -#define TXT_Y 180 -#else +#if PORTRAIT_LCD #define TXT_Y 380 +#else +#define TXT_Y (LCD_H * 2 / 3) #endif #endif -#if LCD_W > LCD_H +static LAYOUT_VAL(TXT_H, 24, 24) + +#if !PORTRAIT_LCD #define TXT_X (LCD_W * 4 / 5) #define IMG_X (LCD_W / 3) #define IMG_Y (LCD_H / 2) @@ -102,12 +104,11 @@ void drawSplash() new StaticLZ4Image(splashScreen, IMG_X - logo->width / 2, IMG_Y - logo->height / 2, logo); - new StaticText(splashScreen, {TXT_X - 100, TXT_Y, 200, 24}, ver_str.c_str(), - COLOR_GREY | CENTERED); - new StaticText(splashScreen, {TXT_X - 100, TXT_Y + 24, 200, 24}, + new StaticText(splashScreen, {TXT_X - 100, TXT_Y, 200, 24}, ver_str.c_str(), COLOR_GREY | CENTERED); + new StaticText(splashScreen, {TXT_X - 100, TXT_Y + TXT_H, 200, TXT_H}, nam_str.c_str(), COLOR_GREY | CENTERED); #if !defined(VERSION_TAG) - new StaticText(splashScreen, {TXT_X - 100, TXT_Y + 48, 200, 24}, + new StaticText(splashScreen, {TXT_X - 100, TXT_Y + TXT_H * 2, 200, TXT_H}, git_str.c_str(), COLOR_GREY | CENTERED); #endif } @@ -132,7 +133,6 @@ void cancelSplash() splashScreen->deleteLater(); splashScreen = nullptr; MainWindow::instance()->setActiveScreen(); - lv_refr_now(nullptr); splashStartTime = 0; } } @@ -147,7 +147,7 @@ void waitSplash() #endif // defined(SIMU) splashStartTime += SPLASH_TIMEOUT; - do { + while (splashStartTime >= get_tmr10ms()) { LvglWrapper::instance()->run(); MainWindow::instance()->run(); WDG_RESET(); @@ -166,7 +166,7 @@ void waitSplash() break; } #endif // defined(SIMU) - } while (splashStartTime >= get_tmr10ms()); + } // Reset timer so special/global functions set to !1x don't get triggered START_SILENCE_PERIOD(); @@ -192,7 +192,8 @@ void drawSleepBitmap() if (shutdownWindow) { shutdownWindow->clear(); } else { - shutdownWindow = new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); + shutdownWindow = + new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); shutdownWindow->setWindowFlag(OPAQUE); etx_solid_bg(shutdownWindow->getLvObj(), COLOR_THEME_PRIMARY1_INDEX); } @@ -219,7 +220,8 @@ void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, if (totalDuration == 0) return; if (shutdownWindow == nullptr) { - shutdownWindow = new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); + shutdownWindow = + new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); shutdownWindow->setWindowFlag(OPAQUE); etx_solid_bg(shutdownWindow->getLvObj(), COLOR_THEME_PRIMARY1_INDEX); @@ -257,7 +259,8 @@ void drawFatalErrorScreen(const char* message) static Window* fatalErrorWindow = nullptr; if (!fatalErrorWindow) { - fatalErrorWindow = new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); + fatalErrorWindow = + new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); fatalErrorWindow->setWindowFlag(OPAQUE); etx_solid_bg(fatalErrorWindow->getLvObj(), COLOR_BLACK_INDEX); diff --git a/radio/src/gui/colorlcd/tabsgroup.cpp b/radio/src/gui/colorlcd/tabsgroup.cpp index 994e73ced8d..236dfb483ef 100644 --- a/radio/src/gui/colorlcd/tabsgroup.cpp +++ b/radio/src/gui/colorlcd/tabsgroup.cpp @@ -24,6 +24,7 @@ #include "theme.h" #include "themes/etx_lv_theme.h" #include "view_main.h" +#include "topbar_impl.h" #if defined(HARDWARE_TOUCH) #include "keyboard_base.h" @@ -36,12 +37,15 @@ class SelectedTabIcon : public StaticIcon StaticIcon(parent, 0, 0, ICON_CURRENTMENU_SHADOW, COLOR_THEME_PRIMARY1) { new StaticIcon(this, 0, 0, ICON_CURRENTMENU_BG, COLOR_THEME_FOCUS); - new StaticIcon(this, 10, 39, ICON_CURRENTMENU_DOT, COLOR_THEME_PRIMARY2); + new StaticIcon(this, SEL_DOT_X, SEL_DOT_Y, ICON_CURRENTMENU_DOT, COLOR_THEME_PRIMARY2); } #if defined(DEBUG_WINDOWS) std::string getName() const override { return "SelectedTabIcon"; } #endif + + static LAYOUT_VAL(SEL_DOT_X, 10, 10) + static LAYOUT_VAL(SEL_DOT_Y, 39, 39) }; class TabCarouselButton : public ButtonBase @@ -54,7 +58,7 @@ class TabCarouselButton : public ButtonBase selected->hide(); lastIcon = getIcon(); - icon = new StaticIcon(this, 2, 7, lastIcon, COLOR_THEME_PRIMARY2); + icon = new StaticIcon(this, 2, ICON_Y, lastIcon, COLOR_THEME_PRIMARY2); show(isVisible()); } @@ -71,6 +75,8 @@ class TabCarouselButton : public ButtonBase EdgeTxIcon getIcon() const { return pageTab->getIcon(); } PageTab* page() const { return pageTab; } + static LAYOUT_VAL(ICON_Y, 7, 7) + protected: PageTab* pageTab; EdgeTxIcon lastIcon; @@ -84,7 +90,7 @@ class TabCarouselButton : public ButtonBase if (lastIcon != getIcon()) { lastIcon = getIcon(); icon->deleteLater(); - icon = new StaticIcon(this, 2, 7, lastIcon, COLOR_THEME_PRIMARY2); + icon = new StaticIcon(this, 2, ICON_Y, lastIcon, COLOR_THEME_PRIMARY2); } ButtonBase::checkEvents(); } @@ -95,13 +101,13 @@ class TabsCarousel : public Window public: TabsCarousel(Window* parent, TabsGroup* menu) : Window(parent, - {MENU_HEADER_BUTTONS_LEFT, 0, - LCD_W - 51 - MENU_HEADER_BUTTONS_LEFT, MENU_HEADER_HEIGHT + 10}), + {TopBar::MENU_HEADER_BUTTONS_LEFT, 0, + LCD_W - HDR_DATE_FULL_WIDTH - TopBar::MENU_HEADER_BUTTONS_LEFT, EdgeTxStyles::MENU_HEADER_HEIGHT + 10}), menu(menu) { setWindowFlag(NO_FOCUS); - lv_obj_set_style_max_width(lvobj, LCD_W - 51 - MENU_HEADER_BUTTONS_LEFT, + lv_obj_set_style_max_width(lvobj, LCD_W - HDR_DATE_FULL_WIDTH - TopBar::MENU_HEADER_BUTTONS_LEFT, LV_PART_MAIN); padAll(PAD_ZERO); @@ -148,7 +154,7 @@ class TabsCarousel : public Window void addTab(PageTab* page) { TabCarouselButton* btn = new TabCarouselButton( - this, {0, 0, MENU_HEADER_BUTTON_WIDTH + 3, MENU_TITLE_TOP + 5}, page); + this, {0, 0, MENU_HEADER_BUTTON_WIDTH + 3, TabsGroup::MENU_TITLE_TOP + 5}, page); btn->setPressHandler([=]() { menu->setCurrentTab(getIndex(btn->getIcon())); return true; @@ -182,6 +188,9 @@ class TabsCarousel : public Window } return -1; } + + static LAYOUT_VAL(MENU_HEADER_BUTTON_WIDTH, 33, 33) + static LAYOUT_VAL(HDR_DATE_FULL_WIDTH, 51, 51) }; #if defined(DEBUG) @@ -209,7 +218,8 @@ class TabsGroupHeader : public Window public: TabsGroupHeader(TabsGroup* menu, EdgeTxIcon icon) : - Window(menu, {0, 0, LCD_W, MENU_BODY_TOP}), icon(icon) + Window(menu, {0, 0, LCD_W, TabsGroup::MENU_BODY_TOP}), + icon(icon) { setWindowFlag(NO_FOCUS | OPAQUE); @@ -219,20 +229,20 @@ class TabsGroupHeader : public Window auto sep = lv_obj_create(lvobj); etx_solid_bg(sep); - lv_obj_set_pos(sep, 0, MENU_HEADER_HEIGHT); - lv_obj_set_size(sep, LCD_W, MENU_TITLE_TOP - MENU_HEADER_HEIGHT); + lv_obj_set_pos(sep, 0, EdgeTxStyles::MENU_HEADER_HEIGHT); + lv_obj_set_size(sep, LCD_W, TabsGroup::MENU_TITLE_TOP - EdgeTxStyles::MENU_HEADER_HEIGHT); titleLabel = lv_label_create(lvobj); etx_txt_color(titleLabel, COLOR_THEME_PRIMARY2_INDEX); lv_obj_set_style_pad_left(titleLabel, PAD_MEDIUM, LV_PART_MAIN); lv_obj_set_style_pad_top(titleLabel, 1, LV_PART_MAIN); - lv_obj_set_pos(titleLabel, 0, MENU_TITLE_TOP); - lv_obj_set_size(titleLabel, LCD_W, MENU_TITLE_HEIGHT); + lv_obj_set_pos(titleLabel, 0, TabsGroup::MENU_TITLE_TOP); + lv_obj_set_size(titleLabel, LCD_W, TabsGroup::MENU_TITLE_HEIGHT); setTitle(""); carousel = new TabsCarousel(this, menu); - dateTime = new HeaderDateTime(lvobj, LCD_W - 48, 6); + dateTime = new HeaderDateTime(lvobj, LCD_W - DATE_XO, DATE_Y); } void setTitle(const char* title) { lv_label_set_text(titleLabel, title); } @@ -241,6 +251,9 @@ class TabsGroupHeader : public Window std::string getName() const override { return "TabsGroupHeader"; } #endif + static LAYOUT_VAL(DATE_XO, 48, 48) + static LAYOUT_VAL(DATE_Y, 6, 6) + protected: EdgeTxIcon icon; TabsCarousel* carousel = nullptr; @@ -261,7 +274,8 @@ TabsGroup::TabsGroup(EdgeTxIcon icon) : NavWindow(MainWindow::instance(), {0, 0, LCD_W, LCD_H}) { header = new TabsGroupHeader(this, icon); - body = new Window(this, {0, MENU_BODY_TOP, LCD_W, MENU_BODY_HEIGHT}); + body = + new Window(this, {0, MENU_BODY_TOP, LCD_W, MENU_BODY_HEIGHT}); body->setWindowFlag(NO_FOCUS); etx_solid_bg(lvobj); @@ -319,7 +333,11 @@ void TabsGroup::setVisibleTab(PageTab* tab) if (tab != currentTab && !deleted()) { header->setTitle(tab->title.c_str()); + lv_obj_enable_style_refresh(false); + body->clear(); + if (currentTab) + currentTab->cleanup(); currentTab = tab; #if defined(DEBUG) @@ -336,8 +354,12 @@ void TabsGroup::setVisibleTab(PageTab* tab) LV_PART_MAIN); body->padAll(tab->padding); + tab->build(body); + lv_obj_enable_style_refresh(true); + lv_obj_refresh_style(body->getLvObj(), LV_PART_ANY, LV_STYLE_PROP_ANY); + #if defined(DEBUG) end_ms = RTOS_GET_MS(); #endif @@ -362,4 +384,15 @@ void TabsGroup::onClicked() { Keyboard::hide(false); } void TabsGroup::onCancel() { deleteLater(); } -Window* TabsGroup::getHeaderWindow() { return header; } +#if defined(PCBNV14) || defined(PCBPL18) +void TabsGroup::addGoToMonitorsButton() +{ + new TextButton( + header, + {LCD_W / 2 + 6, MENU_TITLE_TOP + 1, LCD_W / 2 - 8, MENU_TITLE_HEIGHT - 2}, + STR_OPEN_CHANNEL_MONITORS, [=]() { + pushEvent(EVT_KEY_FIRST(KEY_MODEL)); + return 0; + }); +} +#endif diff --git a/radio/src/gui/colorlcd/tabsgroup.h b/radio/src/gui/colorlcd/tabsgroup.h index 30b71bf4c40..49543f48f27 100644 --- a/radio/src/gui/colorlcd/tabsgroup.h +++ b/radio/src/gui/colorlcd/tabsgroup.h @@ -54,6 +54,7 @@ class PageTab EdgeTxIcon getIcon() const { return icon; } virtual void update(uint8_t index) {} + virtual void cleanup() {} protected: std::string title; @@ -87,7 +88,10 @@ class TabsGroup : public NavWindow void onClicked() override; void onCancel() override; - Window* getHeaderWindow(); + static LAYOUT_VAL(MENU_TITLE_TOP, 48, 48) + static LAYOUT_VAL(MENU_TITLE_HEIGHT, 21, 21) + static constexpr coord_t MENU_BODY_TOP = MENU_TITLE_TOP + MENU_TITLE_HEIGHT; + static constexpr coord_t MENU_BODY_HEIGHT = LCD_H - MENU_BODY_TOP; protected: TabsGroupHeader* header = nullptr; @@ -100,4 +104,8 @@ class TabsGroup : public NavWindow void onPressPGUP() override; void onPressPGDN() override; #endif + +#if defined(PCBNV14) || defined(PCBPL18) + void addGoToMonitorsButton(void); +#endif }; diff --git a/radio/src/gui/colorlcd/theme.cpp b/radio/src/gui/colorlcd/theme.cpp index 774a2751131..7ed5c74b7b5 100644 --- a/radio/src/gui/colorlcd/theme.cpp +++ b/radio/src/gui/colorlcd/theme.cpp @@ -23,6 +23,7 @@ #include "libopenui.h" #include "theme_manager.h" +#include "topbar_impl.h" EdgeTxTheme* EdgeTxTheme::_instance = nullptr; @@ -64,14 +65,14 @@ HeaderDateTime::HeaderDateTime(lv_obj_t* parent, coord_t x, coord_t y) { date = lv_label_create(parent); lv_obj_set_pos(date, x, y); - lv_obj_set_size(date, 45, 12); + lv_obj_set_size(date, HDR_DATE_WIDTH, HDR_DATE_HEIGHT); lv_obj_set_style_text_align(date, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN); etx_txt_color(date, COLOR_THEME_PRIMARY2_INDEX); etx_font(date, FONT_XS_INDEX); time = lv_label_create(parent); - lv_obj_set_pos(time, x, y + 15); - lv_obj_set_size(time, 45, 12); + lv_obj_set_pos(time, x, y + HDR_DATE_LINE2); + lv_obj_set_size(time, HDR_DATE_WIDTH, HDR_DATE_HEIGHT); lv_obj_set_style_text_align(time, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN); etx_txt_color(time, COLOR_THEME_PRIMARY2_INDEX); etx_font(time, FONT_XS_INDEX); @@ -119,7 +120,7 @@ UsbSDConnected::UsbSDConnected() : setWindowFlag(OPAQUE); etx_solid_bg(lvobj, COLOR_THEME_PRIMARY1_INDEX); - dateTime = new HeaderDateTime(lvobj, LCD_W - 48, 6); + dateTime = new HeaderDateTime(lvobj, LCD_W - TopBar::HDR_DATE_XO, HDR_DATE_Y); auto icon = new StaticIcon(this, 0, 0, ICON_USB_PLUGGED, COLOR_THEME_PRIMARY2); lv_obj_center(icon->getLvObj()); diff --git a/radio/src/gui/colorlcd/theme.h b/radio/src/gui/colorlcd/theme.h index 826248f075b..415ba6d7fcb 100644 --- a/radio/src/gui/colorlcd/theme.h +++ b/radio/src/gui/colorlcd/theme.h @@ -54,6 +54,10 @@ class HeaderDateTime void update(); void setColor(uint32_t color); + static LAYOUT_VAL(HDR_DATE_WIDTH, 45, 45) + static LAYOUT_VAL(HDR_DATE_HEIGHT, 12, 12) + static LAYOUT_VAL(HDR_DATE_LINE2, 15, 15) + protected: lv_obj_t *date = nullptr; lv_obj_t *time = nullptr; @@ -73,6 +77,8 @@ class UsbSDConnected : public Window void checkEvents() override; + static LAYOUT_VAL(HDR_DATE_Y, 6, 6) + protected: HeaderDateTime* dateTime = nullptr; }; diff --git a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp index d3075152b84..af07b3f4e0f 100644 --- a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp +++ b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp @@ -29,8 +29,6 @@ extern lv_color_t makeLvColor(uint32_t colorFlags); -static lv_theme_t theme; - /********************** * Constant Styles **********************/ @@ -71,9 +69,12 @@ LV_STYLE_CONST_SINGLE_INIT(EdgeTxStyles::pad_left_2, LV_STYLE_PAD_LEFT, 2); // Scrollbar const lv_style_const_prop_t scrollbar_props[] = { LV_STYLE_CONST_BG_OPA(LV_OPA_50), - LV_STYLE_CONST_PAD_TOP(3), LV_STYLE_CONST_PAD_BOTTOM(3), - LV_STYLE_CONST_PAD_LEFT(3), LV_STYLE_CONST_PAD_RIGHT(3), - LV_STYLE_CONST_WIDTH(4), LV_STYLE_PROP_INV, + LV_STYLE_CONST_PAD_TOP(3), + LV_STYLE_CONST_PAD_BOTTOM(3), + LV_STYLE_CONST_PAD_LEFT(3), + LV_STYLE_CONST_PAD_RIGHT(3), + LV_STYLE_CONST_WIDTH(PAD_SMALL), + LV_STYLE_PROP_INV, }; LV_STYLE_CONST_MULTI_INIT(EdgeTxStyles::scrollbar, scrollbar_props); @@ -95,40 +96,54 @@ const lv_style_const_prop_t pad_tiny_props[] = { LV_STYLE_CONST_MULTI_INIT(EdgeTxStyles::pad_tiny, pad_tiny_props); const lv_style_const_prop_t pad_small_props[] = { - LV_STYLE_CONST_PAD_TOP(4), LV_STYLE_CONST_PAD_BOTTOM(4), - LV_STYLE_CONST_PAD_LEFT(4), LV_STYLE_CONST_PAD_RIGHT(4), - LV_STYLE_CONST_PAD_ROW(4), LV_STYLE_CONST_PAD_COLUMN(4), + LV_STYLE_CONST_PAD_TOP(PAD_SMALL), + LV_STYLE_CONST_PAD_BOTTOM(PAD_SMALL), + LV_STYLE_CONST_PAD_LEFT(PAD_SMALL), + LV_STYLE_CONST_PAD_RIGHT(PAD_SMALL), + LV_STYLE_CONST_PAD_ROW(PAD_SMALL), + LV_STYLE_CONST_PAD_COLUMN(PAD_SMALL), LV_STYLE_PROP_INV, }; LV_STYLE_CONST_MULTI_INIT(EdgeTxStyles::pad_small, pad_small_props); const lv_style_const_prop_t pad_medium_props[] = { - LV_STYLE_CONST_PAD_TOP(6), LV_STYLE_CONST_PAD_BOTTOM(6), - LV_STYLE_CONST_PAD_LEFT(6), LV_STYLE_CONST_PAD_RIGHT(6), - LV_STYLE_CONST_PAD_ROW(4), LV_STYLE_CONST_PAD_COLUMN(4), + LV_STYLE_CONST_PAD_TOP(PAD_MEDIUM), + LV_STYLE_CONST_PAD_BOTTOM(PAD_MEDIUM), + LV_STYLE_CONST_PAD_LEFT(PAD_MEDIUM), + LV_STYLE_CONST_PAD_RIGHT(PAD_MEDIUM), + LV_STYLE_CONST_PAD_ROW(PAD_SMALL), + LV_STYLE_CONST_PAD_COLUMN(PAD_SMALL), LV_STYLE_PROP_INV, }; LV_STYLE_CONST_MULTI_INIT(EdgeTxStyles::pad_medium, pad_medium_props); const lv_style_const_prop_t pad_large_props[] = { - LV_STYLE_CONST_PAD_TOP(8), LV_STYLE_CONST_PAD_BOTTOM(8), - LV_STYLE_CONST_PAD_LEFT(8), LV_STYLE_CONST_PAD_RIGHT(8), - LV_STYLE_CONST_PAD_ROW(4), LV_STYLE_CONST_PAD_COLUMN(4), + LV_STYLE_CONST_PAD_TOP(PAD_LARGE), + LV_STYLE_CONST_PAD_BOTTOM(PAD_LARGE), + LV_STYLE_CONST_PAD_LEFT(PAD_LARGE), + LV_STYLE_CONST_PAD_RIGHT(PAD_LARGE), + LV_STYLE_CONST_PAD_ROW(PAD_SMALL), + LV_STYLE_CONST_PAD_COLUMN(PAD_SMALL), LV_STYLE_PROP_INV, }; LV_STYLE_CONST_MULTI_INIT(EdgeTxStyles::pad_large, pad_large_props); const lv_style_const_prop_t pad_button_props[] = { - LV_STYLE_CONST_PAD_TOP(2), LV_STYLE_CONST_PAD_BOTTOM(2), - LV_STYLE_CONST_PAD_LEFT(6), LV_STYLE_CONST_PAD_RIGHT(6), - LV_STYLE_CONST_PAD_ROW(2), LV_STYLE_CONST_PAD_COLUMN(2), + LV_STYLE_CONST_PAD_TOP(2), + LV_STYLE_CONST_PAD_BOTTOM(2), + LV_STYLE_CONST_PAD_LEFT(PAD_MEDIUM), + LV_STYLE_CONST_PAD_RIGHT(PAD_MEDIUM), + LV_STYLE_CONST_PAD_ROW(2), + LV_STYLE_CONST_PAD_COLUMN(2), LV_STYLE_PROP_INV, }; LV_STYLE_CONST_MULTI_INIT(EdgeTxStyles::pad_button, pad_button_props); const lv_style_const_prop_t pad_textarea_props[] = { - LV_STYLE_CONST_PAD_TOP(4), LV_STYLE_CONST_PAD_BOTTOM(3), - LV_STYLE_CONST_PAD_LEFT(4), LV_STYLE_CONST_PAD_RIGHT(4), + LV_STYLE_CONST_PAD_TOP(PAD_SMALL), + LV_STYLE_CONST_PAD_BOTTOM(PAD_SMALL - 1), + LV_STYLE_CONST_PAD_LEFT(PAD_SMALL), + LV_STYLE_CONST_PAD_RIGHT(PAD_SMALL), LV_STYLE_PROP_INV, }; LV_STYLE_CONST_MULTI_INIT(EdgeTxStyles::pad_textarea, pad_textarea_props); @@ -304,8 +319,7 @@ void EdgeTxStyles::applyColors() } lv_style_set_line_color(&graph_border, makeLvColor(COLOR_THEME_SECONDARY2)); - lv_style_set_line_color(&graph_dashed, - makeLvColor(COLOR_THEME_SECONDARY2)); + lv_style_set_line_color(&graph_dashed, makeLvColor(COLOR_THEME_SECONDARY2)); lv_style_set_line_color(&graph_line, makeLvColor(COLOR_THEME_SECONDARY1)); lv_style_set_line_color(&graph_position_line, makeLvColor(COLOR_THEME_ACTIVE)); @@ -333,41 +347,33 @@ void EdgeTxStyles::applyColors() lv_style_set_arc_color(&arc_color, makeLvColor(COLOR_THEME_SECONDARY1)); } -static EdgeTxStyles mainStyles; -static EdgeTxStyles* previewStyles; -EdgeTxStyles* styles = &mainStyles; +static EdgeTxStyles *mainStyles = nullptr; +static EdgeTxStyles* previewStyles = nullptr; +EdgeTxStyles* styles = nullptr; /********************** * GLOBAL FUNCTIONS **********************/ -lv_theme_t* etx_lv_theme_init(lv_disp_t* disp, lv_color_t color_primary, - lv_color_t color_secondary, const lv_font_t* font) -{ - theme.disp = disp; - theme.color_primary = color_primary; - theme.color_secondary = color_secondary; - theme.font_small = font; - theme.font_normal = font; - theme.font_large = font; - theme.flags = 0; - - styles->init(); - - if (disp == NULL || lv_disp_get_theme(disp) == &theme) - lv_obj_report_style_change(NULL); - - return (lv_theme_t*)&theme; -} - void usePreviewStyle() { - if (!previewStyles) previewStyles = new EdgeTxStyles(); + if (!previewStyles) { + previewStyles = new EdgeTxStyles(); + previewStyles->init(); + } styles = previewStyles; - styles->init(); + styles->applyColors(); } -void useMainStyle() { styles = &mainStyles; } +void useMainStyle() +{ + if (!mainStyles) { + mainStyles = new EdgeTxStyles(); + mainStyles->init(); + } + styles = mainStyles; + styles->applyColors(); +} /********************** * Custom object creation @@ -495,9 +501,21 @@ void etx_scrollbar(lv_obj_t* obj) lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_AUTO); } -void etx_textarea_style(lv_obj_t* obj) +// Object creators + +lv_obj_t* etx_create(const lv_obj_class_t* class_p, lv_obj_t* parent) +{ + lv_obj_t* obj = lv_obj_class_create_obj(class_p, parent); + lv_obj_class_init_obj(obj); + + return obj; +} + +static void textarea_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) { - etx_std_settings(obj, LV_PART_MAIN); + etx_obj_add_style(obj, styles->border, LV_PART_MAIN); + etx_obj_add_style(obj, styles->border_color_normal, LV_PART_MAIN); + etx_obj_add_style(obj, styles->rounded, LV_PART_MAIN); etx_std_ctrl_colors(obj, LV_PART_MAIN); etx_obj_add_style(obj, styles->pad_textarea, LV_PART_MAIN); @@ -516,12 +534,20 @@ void etx_textarea_style(lv_obj_t* obj) lv_obj_set_height(ta->label, 21); } -// Object creators +static const lv_obj_class_t textarea_class = { + .base_class = &lv_textarea_class, + .constructor_cb = textarea_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = 0, + .height_def = EdgeTxStyles::UI_ELEMENT_HEIGHT, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, + .instance_size = sizeof(lv_textarea_t), +}; -lv_obj_t* etx_create(const lv_obj_class_t* class_p, lv_obj_t* parent) +lv_obj_t* etx_textarea_create(lv_obj_t* parent) { - lv_obj_t* obj = lv_obj_class_create_obj(class_p, parent); - lv_obj_class_init_obj(obj); - - return obj; + return etx_create(&textarea_class, parent); } diff --git a/radio/src/gui/colorlcd/themes/etx_lv_theme.h b/radio/src/gui/colorlcd/themes/etx_lv_theme.h index 75b1fd736e1..933f9012521 100644 --- a/radio/src/gui/colorlcd/themes/etx_lv_theme.h +++ b/radio/src/gui/colorlcd/themes/etx_lv_theme.h @@ -28,27 +28,40 @@ #include "colors.h" #include "fonts.h" -#include "window.h" + +/********************* + * Layout + *********************/ + +enum PaddingSize { + PAD_ZERO = 0, + PAD_TINY = 2, + PAD_TINY_GAP = 2, + PAD_SMALL = 4, + PAD_MEDIUM = 6, + PAD_LARGE = 8 +}; + +// Macros for setting up layout values +// LAYOUT_VAL - 2 values - landscape, portrait + +#if LANDSCAPE_LCD +#define LAYOUT_VAL(name, landscape, portrait) \ + constexpr coord_t name = landscape; +#else +#define LAYOUT_VAL(name, landscape, portrait) \ + constexpr coord_t name = portrait; +#endif /********************** * GLOBAL PROTOTYPES **********************/ -/** - * Initialize the theme - * @param color_primary the primary color of the theme - * @param color_secondary the secondary color for the theme - * @param font pointer to a font to use. - * @return a pointer to reference this theme later - */ -lv_theme_t* etx_lv_theme_init(lv_disp_t* disp, lv_color_t color_primary, - lv_color_t color_secondary, - const lv_font_t* font); - void usePreviewStyle(); void useMainStyle(); lv_obj_t* etx_create(const lv_obj_class_t* class_p, lv_obj_t* parent); +lv_obj_t* etx_textarea_create(lv_obj_t* parent); lv_obj_t* window_create(lv_obj_t* parent); void etx_std_style(lv_obj_t* obj, lv_style_selector_t selector = LV_PART_MAIN, @@ -80,13 +93,10 @@ void etx_txt_color(lv_obj_t* obj, LcdColorIndex colorIdx, void etx_img_color(lv_obj_t* obj, LcdColorIndex colorIdx, lv_style_selector_t selector = LV_PART_MAIN); -void etx_textarea_style(lv_obj_t* obj); - // Create a style with a single property #define LV_STYLE_CONST_SINGLE_INIT(var_name, prop, value) \ const lv_style_t var_name = {.v_p = {.value1 = {.num = value}}, \ .prop1 = prop, \ - .is_const = 0, \ .has_group = 1 << ((prop & 0x1FF) >> 4), \ .prop_cnt = 1} @@ -94,10 +104,9 @@ void etx_textarea_style(lv_obj_t* obj); // Copied from lv_style.h and modified to compile with ARM GCC C++ #define LV_STYLE_CONST_MULTI_INIT(var_name, prop_array) \ const lv_style_t var_name = {.v_p = {.const_props = prop_array}, \ - .prop1 = 0, \ - .is_const = 1, \ + .prop1 = LV_STYLE_PROP_ANY, \ .has_group = 0xFF, \ - .prop_cnt = 0} + .prop_cnt = (sizeof(prop_array) / sizeof((prop_array)[0]))} extern const lv_obj_class_t window_base_class; extern const lv_obj_class_t field_edit_class; @@ -169,6 +178,10 @@ class EdgeTxStyles void init(); void applyColors(); + static LAYOUT_VAL(PAGE_LINE_HEIGHT, 20, 20) + static LAYOUT_VAL(UI_ELEMENT_HEIGHT, 32, 32) + static LAYOUT_VAL(MENU_HEADER_HEIGHT, 45, 45) + protected: bool initDone = false; }; diff --git a/radio/src/gui/colorlcd/throttle_params.cpp b/radio/src/gui/colorlcd/throttle_params.cpp index a47d921aba5..a737ead87de 100644 --- a/radio/src/gui/colorlcd/throttle_params.cpp +++ b/radio/src/gui/colorlcd/throttle_params.cpp @@ -26,64 +26,52 @@ #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 SetupLineDef setupLines[] = { + { + // Throttle reversed + STR_THROTTLEREVERSE, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_model.throttleReversed)); + } + }, + { + // Throttle source + STR_TTRACE, + [](Window* parent, coord_t x, coord_t y) { + auto sc = new SourceChoice(parent, {x, y, 0, 0}, 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(); + } + }); + sc->setAvailableHandler(isThrottleSourceAvailable); + } + }, + { + // Throttle trim + STR_TTRIM, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_model.thrTrim)); + } + }, + { + // Throttle trim source + STR_TTRIM_SW, + [](Window* parent, coord_t x, coord_t y) { + new SourceChoice( + parent, {x, y, 0, 0}, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM, + []() { return g_model.getThrottleStickTrimSource(); }, + [](int16_t src) { + g_model.setThrottleStickTrimSource(src); + SET_DIRTY(); + }); + } + }, +}; -static int16_t getThrottleSource() +ThrottleParams::ThrottleParams() : SubPage(ICON_MODEL_SETUP, STR_MENU_MODEL_SETUP, STR_THROTTLE_LABEL, setupLines, DIM(setupLines)) { - 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) -{ - header->setTitle(STR_MENU_MODEL_SETUP); - header->setTitle2(STR_THROTTLE_LABEL); - - body->setFlexLayout(); - FlexGridLayout grid(line_col_dsc, line_row_dsc); - - // Throttle reversed - auto line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_THROTTLEREVERSE); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_model.throttleReversed)); - - // Throttle source - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_TTRACE); - auto sc = new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_CH, - getThrottleSource, setThrottleSource); - sc->setAvailableHandler(isThrottleSourceAvailable); - - // Throttle trim - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_TTRIM); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_model.thrTrim)); - - // Throttle trim source - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_TTRIM_SW); - new SourceChoice( - line, rect_t{}, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM, - getThrottleTrimSource, setThrottleTrimSource); } diff --git a/radio/src/gui/colorlcd/throttle_params.h b/radio/src/gui/colorlcd/throttle_params.h index 86997affc22..0d481b90421 100644 --- a/radio/src/gui/colorlcd/throttle_params.h +++ b/radio/src/gui/colorlcd/throttle_params.h @@ -23,6 +23,8 @@ #include "page.h" -struct ThrottleParams : public Page { +class ThrottleParams : public SubPage +{ + public: ThrottleParams(); }; diff --git a/radio/src/gui/colorlcd/timer_setup.cpp b/radio/src/gui/colorlcd/timer_setup.cpp index 2f8fe020562..8a5c59e4876 100644 --- a/radio/src/gui/colorlcd/timer_setup.cpp +++ b/radio/src/gui/colorlcd/timer_setup.cpp @@ -27,128 +27,93 @@ #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 std::function timerValueUpdater(uint8_t timer) -{ - return [=](uint32_t value) { - TimerData* p_timer = &g_model.timers[timer]; - p_timer->start = value; - timerSet(timer, value); - SET_DIRTY(); - }; -} - -static void timer_start_changed(lv_event_t* e) -{ - lv_obj_t* target = lv_event_get_target(e); - auto obj = (lv_obj_t*)lv_event_get_user_data(e); - auto val = (TimeEdit*)lv_obj_get_user_data(target); - - if (!obj || !val) return; - - if (val->getValue() > 0) { - lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); - } -} - -TimerWindow::TimerWindow(uint8_t timer) : Page(ICON_STATS_TIMERS) +TimerWindow::TimerWindow(uint8_t timer) : + SubPage(ICON_STATS_TIMERS, STR_MENU_MODEL_SETUP, (std::string(STR_TIMER) + std::to_string(timer + 1)).c_str()) { - std::string title2 = std::string(STR_TIMER) + std::to_string(timer + 1); - header->setTitle(STR_MENU_MODEL_SETUP); - header->setTitle2(title2); - body->setFlexLayout(); - FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY); - TimerData* p_timer = &g_model.timers[timer]; // Timer name - auto line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_NAME); - new ModelTextEdit(line, rect_t{}, p_timer->name, LEN_TIMER_NAME); + setupLine(STR_NAME, + [=](Window* parent, coord_t x, coord_t y) { + new ModelTextEdit(parent, {x, y, 0, 0}, p_timer->name, LEN_TIMER_NAME); + }); // Timer mode - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_MODE); - new Choice(line, rect_t{}, STR_TIMER_MODES, 0, TMRMODE_MAX, - GET_SET_DEFAULT(p_timer->mode)); + setupLine(STR_MODE, + [=](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_TIMER_MODES, 0, TMRMODE_MAX, + GET_SET_DEFAULT(p_timer->mode)); + }); // Timer switch - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_SWITCH); - new SwitchChoice(line, rect_t{}, SWSRC_FIRST, SWSRC_LAST, - GET_SET_DEFAULT(p_timer->swtch)); + setupLine(STR_SWITCH, + [=](Window* parent, coord_t x, coord_t y) { + new SwitchChoice(parent, rect_t{x, y, 0, 0}, SWSRC_FIRST, SWSRC_LAST, + GET_SET_DEFAULT(p_timer->swtch)); + }); // Timer start value - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_START); - auto timerValue = - new TimeEdit(line, rect_t{}, 0, TIMER_MAX, - GET_DEFAULT(p_timer->start), timerValueUpdater(timer)); - timerValue->setAccelFactor(16); + setupLine(STR_START, + [=](Window* parent, coord_t x, coord_t y) { + auto timerValue = new TimeEdit(parent, {x, y, 0, 0}, 0, TIMER_MAX, + GET_DEFAULT(p_timer->start), [=](int newValue) { + p_timer->start = newValue; + timerSet(timer, newValue); + timerDirLine->show(newValue > 0); + SET_DIRTY(); + }); + timerValue->setAccelFactor(16); + }); // Timer direction - auto timerDirLine = body->newLine(grid); - new StaticText(timerDirLine, rect_t{}, STR_LIMITS_HEADERS_DIRECTION); - new Choice(timerDirLine, rect_t{}, STR_TIMER_DIR, 0, 1, - GET_SET_DEFAULT(p_timer->showElapsed)); - - if (timerValue->getValue() == 0) { - timerDirLine->hide(); - } + timerDirLine = setupLine(STR_LIMITS_HEADERS_DIRECTION, + [=](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_TIMER_DIR, 0, 1, + GET_SET_DEFAULT(p_timer->showElapsed)); + }); + timerDirLine->show(p_timer->start> 0); // Timer minute beep - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_MINUTEBEEP); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(p_timer->minuteBeep)); + setupLine(STR_MINUTEBEEP, + [=](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(p_timer->minuteBeep)); + }); // Timer countdown - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_BEEPCOUNTDOWN); - - auto box = new Window(line, rect_t{}); - box->padAll(PAD_TINY); - box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY, LV_SIZE_CONTENT); - - new Choice( - box, rect_t{}, STR_VBEEPCOUNTDOWN, COUNTDOWN_SILENT, COUNTDOWN_COUNT - 1, - [=]() -> int { - int value = p_timer->countdownBeep; - if (p_timer->extraHaptic) { - value += (COUNTDOWN_NON_HAPTIC_LAST + 1); - } - return (value); - }, - [=](int value) { - if (value > COUNTDOWN_NON_HAPTIC_LAST + 1) { - p_timer->extraHaptic = 1; - p_timer->countdownBeep = value - (COUNTDOWN_NON_HAPTIC_LAST + 1); - } else { - p_timer->extraHaptic = 0; - p_timer->countdownBeep = value; - } - SET_DIRTY(); - TRACE("value=%d\tcountdownBeep = %d\textraHaptic = %d", value, - p_timer->countdownBeep, p_timer->extraHaptic); - }); - - new Choice(box, rect_t{}, STR_COUNTDOWNVALUES, 0, 3, - GET_SET_WITH_OFFSET(p_timer->countdownStart, 2)); + setupLine(STR_BEEPCOUNTDOWN, + [=](Window* parent, coord_t x, coord_t y) { + new Choice( + parent, rect_t{x, y, COUNTDOWN_W, 0}, STR_VBEEPCOUNTDOWN, COUNTDOWN_SILENT, COUNTDOWN_COUNT - 1, + [=]() -> int { + int value = p_timer->countdownBeep; + if (p_timer->extraHaptic) { + value += (COUNTDOWN_NON_HAPTIC_LAST + 1); + } + return (value); + }, + [=](int value) { + if (value > COUNTDOWN_NON_HAPTIC_LAST + 1) { + p_timer->extraHaptic = 1; + p_timer->countdownBeep = value - (COUNTDOWN_NON_HAPTIC_LAST + 1); + } else { + p_timer->extraHaptic = 0; + p_timer->countdownBeep = value; + } + SET_DIRTY(); + TRACE("value=%d\tcountdownBeep = %d\textraHaptic = %d", value, + p_timer->countdownBeep, p_timer->extraHaptic); + }); + + new Choice(parent, {x + COUNTDOWN_VAL_XO, y + COUNTDOWN_VAL_YO, 0, 0}, STR_COUNTDOWNVALUES, 0, 3, + GET_SET_WITH_OFFSET(p_timer->countdownStart, 2)); + }, COUNTDOWN_LBL_YO); // Timer persistent - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_PERSISTENT); - - new Choice(line, rect_t{}, STR_VPERSISTENT, 0, 2, - GET_SET_DEFAULT(p_timer->persistent)); - - lv_obj_add_event_cb(timerValue->getLvObj(), timer_start_changed, - LV_EVENT_VALUE_CHANGED, timerDirLine->getLvObj()); + setupLine(STR_PERSISTENT, + [=](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_VPERSISTENT, 0, 2, + GET_SET_DEFAULT(p_timer->persistent)); + }); } diff --git a/radio/src/gui/colorlcd/timer_setup.h b/radio/src/gui/colorlcd/timer_setup.h index 28222f3d21d..9feae57022e 100644 --- a/radio/src/gui/colorlcd/timer_setup.h +++ b/radio/src/gui/colorlcd/timer_setup.h @@ -23,6 +23,16 @@ #include "page.h" -struct TimerWindow : public Page { +class TimerWindow : public SubPage +{ + public: TimerWindow(uint8_t timer); + + static LAYOUT_VAL(COUNTDOWN_W, 144, 144) + static LAYOUT_VAL(COUNTDOWN_LBL_YO, 0, (EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_TINY) / 2) + static LAYOUT_VAL(COUNTDOWN_VAL_XO, COUNTDOWN_W + PAD_SMALL, 0) + static LAYOUT_VAL(COUNTDOWN_VAL_YO, 0, EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_TINY) + + protected: + Window* timerDirLine = nullptr; }; diff --git a/radio/src/gui/colorlcd/topbar.h b/radio/src/gui/colorlcd/topbar.h index c703ea34555..20ae95694ce 100644 --- a/radio/src/gui/colorlcd/topbar.h +++ b/radio/src/gui/colorlcd/topbar.h @@ -23,11 +23,6 @@ #include "layout.h" -constexpr coord_t TOPBAR_ZONE_WIDTH = 70; -constexpr coord_t TOPBAR_ZONE_VMARGIN = 3; -constexpr coord_t TOPBAR_ZONE_HMARGIN = 2; -constexpr coord_t TOPBAR_ZONE_HEIGHT = MENU_HEADER_HEIGHT - 2 * TOPBAR_ZONE_VMARGIN; - class ScreenMenu; class TopBar; diff --git a/radio/src/gui/colorlcd/trims_setup.cpp b/radio/src/gui/colorlcd/trims_setup.cpp index dee05cc2889..c565b147e1a 100644 --- a/radio/src/gui/colorlcd/trims_setup.cpp +++ b/radio/src/gui/colorlcd/trims_setup.cpp @@ -25,68 +25,60 @@ #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) -{ - header->setTitle(STR_MENU_MODEL_SETUP); - header->setTitle2(STR_TRIMS); - - body->setFlexLayout(); - body->padAll(PAD_LARGE); - FlexGridLayout grid(line_col_dsc, line_row_dsc); - - // Reset trims - auto line = body->newLine(grid); - line->padBottom(4); - auto btn = new TextButton(line, rect_t{}, STR_RESET_BTN, []() -> uint8_t { - resetTrims(); - return 0; - }); - auto btn_obj = btn->getLvObj(); - lv_obj_set_width(btn_obj, lv_pct(100)); - +static SetupLineDef setupLines[] = { + { + // Reset trims + nullptr, + [](Window* parent, coord_t x, coord_t y) { + new TextButton(parent, {PAD_TINY, y, LCD_W - PAD_MEDIUM * 2, 0}, STR_RESET_BTN, []() -> uint8_t { + for (auto &fm : g_model.flightModeData) memclear(&fm.trim, sizeof(fm.trim)); + SET_DIRTY(); + AUDIO_WARNING1(); + return 0; + }); + } + }, #if defined(USE_HATS_AS_KEYS) - // Hats mode for NV14/EL18 - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_HATSMODE); - 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_GLOBAL, - GET_SET_DEFAULT(g_model.hatsMode)); - new TextButton(box, rect_t{}, "?", [=]() { - new MessageDialog(this, STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "", - LEFT); - return 0; - }); + { + // Hats mode for NV14/EL18 + STR_HATSMODE, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, TrimsSetup::HATSMODE_W, 0}, STR_HATSOPT, HATSMODE_TRIMS_ONLY, HATSMODE_GLOBAL, + GET_SET_DEFAULT(g_model.hatsMode)); + new TextButton(parent, {x + TrimsSetup::HATSMODE_W + PAD_SMALL, y, 0, 0}, "?", [=]() { + new MessageDialog(parent, STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "", + LEFT); + return 0; + }); + } + }, #endif + { + // Trim step + STR_TRIMINC, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_VTRIMINC, -2, 2, + GET_SET_DEFAULT(g_model.trimInc)); + } + }, + { + // Extended trims + STR_ETRIMS, + [](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_model.extendedTrims)); + } + }, + { + // Display trims + // TODO: move to "Screen setup" ? + STR_DISPLAY_TRIMS, + [](Window* parent, coord_t x, coord_t y) { + new Choice(parent, {x, y, 0, 0}, STR_VDISPLAYTRIMS, 0, 2, + GET_SET_DEFAULT(g_model.displayTrims)); + } + }, +}; - // Trim step - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_TRIMINC); - 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); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(g_model.extendedTrims)); - - // Display trims - // TODO: move to "Screen setup" ? - line = body->newLine(grid); - new StaticText(line, rect_t{}, STR_DISPLAY_TRIMS); - new Choice(line, rect_t{}, STR_VDISPLAYTRIMS, 0, 2, - GET_SET_DEFAULT(g_model.displayTrims)); +TrimsSetup::TrimsSetup() : SubPage(ICON_MODEL_SETUP, STR_MENU_MODEL_SETUP, STR_TRIMS, setupLines, DIM(setupLines)) +{ } diff --git a/radio/src/gui/colorlcd/trims_setup.h b/radio/src/gui/colorlcd/trims_setup.h index d5845d3a9b1..9313d947a1b 100644 --- a/radio/src/gui/colorlcd/trims_setup.h +++ b/radio/src/gui/colorlcd/trims_setup.h @@ -23,6 +23,10 @@ #include "page.h" -struct TrimsSetup : public Page { +class TrimsSetup : public SubPage +{ + public: TrimsSetup(); + + static LAYOUT_VAL(HATSMODE_W, 120, 120) }; diff --git a/radio/src/gui/colorlcd/view_channels.cpp b/radio/src/gui/colorlcd/view_channels.cpp index 47e27b2c955..6f8692b745c 100644 --- a/radio/src/gui/colorlcd/view_channels.cpp +++ b/radio/src/gui/colorlcd/view_channels.cpp @@ -89,7 +89,7 @@ class ChannelsViewPage : public PageTab // Channels bars for (uint8_t chan = pageIndex * 8; chan < 8 + pageIndex * 8; chan++) { -#if LCD_H > LCD_W +#if PORTRAIT_LCD coord_t width = window->width() - (hmargin * 2); coord_t xPos = hmargin; coord_t yPos = (chan % 8) * @@ -100,7 +100,7 @@ class ChannelsViewPage : public PageTab coord_t yPos = (chan % 4) * ((window->height() - 23) / 4); #endif - new ComboChannelBar(window, {xPos, yPos, width, 3 * BAR_HEIGHT + 3}, + new ComboChannelBar(window, {xPos, yPos, width, 3 * ChannelBar::BAR_HEIGHT + 3}, chan); } diff --git a/radio/src/gui/colorlcd/view_logical_switches.cpp b/radio/src/gui/colorlcd/view_logical_switches.cpp index a1b29597acf..a0e31138055 100644 --- a/radio/src/gui/colorlcd/view_logical_switches.cpp +++ b/radio/src/gui/colorlcd/view_logical_switches.cpp @@ -25,14 +25,18 @@ #include "switches.h" #include "themes/etx_lv_theme.h" -#if LCD_W > LCD_H // Landscape +#if PORTRAIT_LCD -#define BTN_MATRIX_COL 8 -#define BTN_HEIGHT 20 -#define FOOTER_HEIGHT 20 -#define V2_COL_CNT 1 -#define ANDSW_ROW 0 -#define ANDSW_COL 3 +static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; + +// Footer grid +static const lv_coord_t f_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; + +#else // Landscape // Switch grid static const lv_coord_t col_dsc[] = { @@ -44,24 +48,6 @@ static const lv_coord_t col_dsc[] = { static const lv_coord_t f_col_dsc[] = { 60, LV_GRID_FR(1), 112, LV_GRID_FR(1), 50, 50, LV_GRID_TEMPLATE_LAST}; -#else // Portrait - -#define BTN_MATRIX_COL 4 -#define BTN_HEIGHT 21 -#define FOOTER_HEIGHT 40 -#define V2_COL_CNT 2 -#define ANDSW_ROW 1 -#define ANDSW_COL 1 - -static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), - LV_GRID_FR(1), LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; - -// Footer grid -static const lv_coord_t f_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), - 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_CONTENT, @@ -78,8 +64,8 @@ class LogicalSwitchDisplayFooter : public Window setWindowFlag(OPAQUE); padAll(PAD_ZERO); - padLeft(4); - padRight(4); + padLeft(PAD_SMALL); + padRight(PAD_SMALL); etx_solid_bg(lvobj, COLOR_THEME_SECONDARY1_INDEX); lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); @@ -211,6 +197,10 @@ class LogicalSwitchDisplayFooter : public Window refresh(); } + static LAYOUT_VAL(V2_COL_CNT, 1, 2) + static LAYOUT_VAL(ANDSW_ROW, 0, 1) + static LAYOUT_VAL(ANDSW_COL, 3, 1) + protected: unsigned lsIndex = 0; lv_obj_t* lsFunc = nullptr; @@ -276,9 +266,9 @@ void LogicalSwitchesViewPage::build(Window* window) for (uint8_t i = 0; i < MAX_LOGICAL_SWITCHES; i++) { if ((i % BTN_MATRIX_COL) == 0) { line = form->newLine(grid); - lv_obj_set_style_pad_all(line->getLvObj(), 1, 0); - line->padLeft(4); - line->padRight(4); + lv_obj_set_style_pad_all(line->getLvObj(), BTN_PAD, LV_PART_MAIN); + line->padLeft(PAD_SMALL); + line->padRight(PAD_SMALL); } LogicalSwitchData* ls = lswAddress(i); diff --git a/radio/src/gui/colorlcd/view_logical_switches.h b/radio/src/gui/colorlcd/view_logical_switches.h index 776aeca251f..f63c39a7b7c 100644 --- a/radio/src/gui/colorlcd/view_logical_switches.h +++ b/radio/src/gui/colorlcd/view_logical_switches.h @@ -30,6 +30,11 @@ class LogicalSwitchesViewPage : public PageTab public: LogicalSwitchesViewPage(); + static LAYOUT_VAL(FOOTER_HEIGHT, 20, 40) + static LAYOUT_VAL(BTN_HEIGHT, 20, 21) + static LAYOUT_VAL(BTN_PAD, 1, 2) + static LAYOUT_VAL(BTN_MATRIX_COL, 8, 4) + protected: void build(Window* window) override; LogicalSwitchDisplayFooter* footer = nullptr; diff --git a/radio/src/gui/colorlcd/view_main_decoration.cpp b/radio/src/gui/colorlcd/view_main_decoration.cpp index 6868f4af492..12f73bcf014 100644 --- a/radio/src/gui/colorlcd/view_main_decoration.cpp +++ b/radio/src/gui/colorlcd/view_main_decoration.cpp @@ -148,34 +148,34 @@ void ViewMainDecoration::createSliders(Window* ml, Window* mr, Window* bl, Windo // create containers for the sliders, so that they are at the borders of the display // on top of each other, when there are two sliders to display per side auto leftPots = create_layout_box(ml, LV_ALIGN_LEFT_MID, LV_FLEX_FLOW_COLUMN); - leftPots->setHeight(VERTICAL_SLIDERS_HEIGHT); + leftPots->setHeight(MainViewSlider::HORIZONTAL_SLIDERS_WIDTH); auto rightPots = create_layout_box(mr, LV_ALIGN_RIGHT_MID, LV_FLEX_FLOW_COLUMN); - rightPots->setHeight(VERTICAL_SLIDERS_HEIGHT); + rightPots->setHeight(MainViewSlider::VERTICAL_SLIDERS_HEIGHT); - coord_t lsh = (IS_POT_AVAILABLE(pot + 2)) ? VERTICAL_SLIDERS_HEIGHT / 2 : VERTICAL_SLIDERS_HEIGHT; - coord_t rsh = (IS_POT_AVAILABLE(pot + 3)) ? VERTICAL_SLIDERS_HEIGHT / 2 : VERTICAL_SLIDERS_HEIGHT; + coord_t lsh = (IS_POT_AVAILABLE(pot + 2)) ? MainViewSlider::HORIZONTAL_SLIDERS_WIDTH / 2 : MainViewSlider::HORIZONTAL_SLIDERS_WIDTH; + coord_t rsh = (IS_POT_AVAILABLE(pot + 3)) ? MainViewSlider::HORIZONTAL_SLIDERS_WIDTH / 2 : MainViewSlider::HORIZONTAL_SLIDERS_WIDTH; if (IS_POT_AVAILABLE(pot)) { - sliders[sl] = new MainViewVerticalSlider(leftPots, rect_t{0, 0, TRIM_SQUARE_SIZE, lsh}, pot); + sliders[sl] = new MainViewVerticalSlider(leftPots, rect_t{0, 0, LayoutFactory::TRIM_SQUARE_SIZE, lsh}, pot); sl += 1; } pot += 1; if (IS_POT_AVAILABLE(pot)) { - sliders[sl] = new MainViewVerticalSlider(rightPots, rect_t{0, 0, TRIM_SQUARE_SIZE, rsh}, pot); + sliders[sl] = new MainViewVerticalSlider(rightPots, rect_t{0, 0, LayoutFactory::TRIM_SQUARE_SIZE, rsh}, pot); sl += 1; } pot += 1; if (IS_POT_AVAILABLE(pot)) { - sliders[sl] = new MainViewVerticalSlider(leftPots, rect_t{0, 0, TRIM_SQUARE_SIZE, lsh}, pot); + sliders[sl] = new MainViewVerticalSlider(leftPots, rect_t{0, 0, LayoutFactory::TRIM_SQUARE_SIZE, lsh}, pot); sl += 1; } pot += 1; if (IS_POT_AVAILABLE(pot)) { - sliders[sl] = new MainViewVerticalSlider(rightPots, rect_t{0, 0, TRIM_SQUARE_SIZE, rsh}, pot); + sliders[sl] = new MainViewVerticalSlider(rightPots, rect_t{0, 0, LayoutFactory::TRIM_SQUARE_SIZE, rsh}, pot); } } } diff --git a/radio/src/gui/colorlcd/view_main_menu.cpp b/radio/src/gui/colorlcd/view_main_menu.cpp index deb63f13358..a17490c43ef 100644 --- a/radio/src/gui/colorlcd/view_main_menu.cpp +++ b/radio/src/gui/colorlcd/view_main_menu.cpp @@ -58,12 +58,12 @@ static lv_obj_t* etx_modal_dialog_create(lv_obj_t* parent) return etx_create(&etx_modal_dialog_class, parent); } -#if LCD_W > LCD_H -#define VM_W (FAB_BUTTON_WIDTH * 4 + 16) -#define VM_H (FAB_BUTTON_HEIGHT * 2 + 16) +#if !PORTRAIT_LCD +#define VM_W (SelectFabCarousel::FAB_BUTTON_WIDTH * 4 + PAD_LARGE * 2) +#define VM_H (SelectFabCarousel::FAB_BUTTON_HEIGHT * 2 + PAD_LARGE * 2) #else -#define VM_W (FAB_BUTTON_WIDTH * 3 + 16) -#define VM_H (FAB_BUTTON_HEIGHT * 3 + 16) +#define VM_W (SelectFabCarousel::FAB_BUTTON_WIDTH * 3 + PAD_LARGE * 2) +#define VM_H (SelectFabCarousel::FAB_BUTTON_HEIGHT * 3 + PAD_LARGE * 2) #endif ViewMainMenu::ViewMainMenu(Window* parent, std::function closeHandler) : @@ -76,9 +76,9 @@ ViewMainMenu::ViewMainMenu(Window* parent, std::function closeHandler) : coord_t width = VM_W; bool hasNotes = modelHasNotes(); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD if (hasNotes) - width += FAB_BUTTON_WIDTH; + width += SelectFabCarousel::FAB_BUTTON_WIDTH; #endif auto box = diff --git a/radio/src/gui/colorlcd/view_statistics.cpp b/radio/src/gui/colorlcd/view_statistics.cpp index 501e7aef7e4..03429395ecf 100644 --- a/radio/src/gui/colorlcd/view_statistics.cpp +++ b/radio/src/gui/colorlcd/view_statistics.cpp @@ -57,7 +57,7 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; -#if LCD_W > LCD_H +#if !PORTRAIT_LCD static const lv_coord_t dbg_4col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), LV_GRID_FR(3), LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST}; @@ -72,7 +72,7 @@ static const lv_coord_t dbg_3col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define CV_SCALE 3 #define DBG_B_WIDTH (LCD_W - 20) / 4 #else @@ -252,7 +252,7 @@ void DebugViewPage::build(Window* window) { window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO); -#if LCD_W > LCD_H +#if !PORTRAIT_LCD FlexGridLayout grid(dbg_4col_dsc, row_dsc, PAD_ZERO); FlexGridLayout grid2(dbg_4col_dsc, row_dsc, PAD_ZERO); #else @@ -291,7 +291,7 @@ void DebugViewPage::build(Window* window) // LUA timing data new StaticText(line, rect_t{}, STR_LUA_SCRIPTS_LABEL); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = window->newLine(grid); line->padAll(PAD_ZERO); line->padLeft(10); @@ -305,7 +305,7 @@ void DebugViewPage::build(Window* window) line = window->newLine(grid); line->padAll(PAD_ZERO); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line->padLeft(10); #else grid.nextCell(); @@ -319,7 +319,7 @@ void DebugViewPage::build(Window* window) line, rect_t{0, 0, DBG_B_WIDTH, DBG_B_HEIGHT}, [] { return luaGetMemUsed(lsWidgets); }, STR_MEM_USED_WIDGET); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = window->newLine(grid); line->padAll(PAD_ZERO); line->padLeft(10); @@ -335,7 +335,7 @@ void DebugViewPage::build(Window* window) // Stacks data new StaticText(line, rect_t{}, STR_FREE_STACK); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = window->newLine(grid2); line->padAll(PAD_ZERO); line->padLeft(10); @@ -371,7 +371,7 @@ void DebugViewPage::build(Window* window) line->padAll(PAD_TINY); new StaticText(line, rect_t{}, STR_INT_GPS_LABEL); -#if LCD_H > LCD_W +#if PORTRAIT_LCD line = window->newLine(grid2); line->padAll(PAD_ZERO); line->padLeft(10); diff --git a/radio/src/gui/colorlcd/widget_settings.cpp b/radio/src/gui/colorlcd/widget_settings.cpp index 144ef05ee42..db2001ba6a3 100644 --- a/radio/src/gui/colorlcd/widget_settings.cpp +++ b/radio/src/gui/colorlcd/widget_settings.cpp @@ -188,4 +188,4 @@ void WidgetSettings::onCancel() { widget->update(); deleteLater(); -} \ No newline at end of file +} diff --git a/radio/src/gui/colorlcd/widgets/radio_info.cpp b/radio/src/gui/colorlcd/widgets/radio_info.cpp index f4263d206a1..2be88d1e412 100644 --- a/radio/src/gui/colorlcd/widgets/radio_info.cpp +++ b/radio/src/gui/colorlcd/widgets/radio_info.cpp @@ -25,11 +25,6 @@ #include "widget.h" #include "widgets_container_impl.h" -#define W_AUDIO_X 0 -#define W_USB_X 32 -#define W_LOG_X 32 -#define W_RSSI_X 40 - class TopBarWidget : public Widget { public: @@ -48,45 +43,50 @@ class RadioInfoWidget : public TopBarWidget TopBarWidget(factory, parent, rect, persistentData) { // Logs - logsIcon = new StaticIcon(this, W_LOG_X, 3, ICON_DOT, COLOR_THEME_PRIMARY2); + logsIcon = new StaticIcon(this, W_LOG_X, W_LOG_Y, ICON_DOT, + COLOR_THEME_PRIMARY2); logsIcon->hide(); - usbIcon = new StaticIcon(this, W_USB_X, 5, ICON_TOPMENU_USB, - COLOR_THEME_PRIMARY2); + usbIcon = + new StaticIcon(this, W_USB_X, W_USB_Y, ICON_TOPMENU_USB, + COLOR_THEME_PRIMARY2); usbIcon->hide(); #if defined(AUDIO) - audioScale = - new StaticIcon(this, W_AUDIO_X + 15, 2, ICON_TOPMENU_VOLUME_SCALE, - COLOR_THEME_PRIMARY3); + audioScale = new StaticIcon(this, W_AUDIO_SCALE_X, 2, + ICON_TOPMENU_VOLUME_SCALE, + COLOR_THEME_PRIMARY3); for (int i = 0; i < 5; i += 1) { - audioVol[i] = new StaticIcon(this, W_AUDIO_X, 2, - (EdgeTxIcon)(ICON_TOPMENU_VOLUME_0 + i), - COLOR_THEME_PRIMARY2); + audioVol[i] = new StaticIcon( + this, W_AUDIO_X, 2, + (EdgeTxIcon)(ICON_TOPMENU_VOLUME_0 + i), + COLOR_THEME_PRIMARY2); audioVol[i]->hide(); } audioVol[0]->show(); #endif - batteryIcon = new StaticIcon(this, W_AUDIO_X, 25, ICON_TOPMENU_TXBATT, + batteryIcon = new StaticIcon(this, W_AUDIO_X, W_BATT_Y, + ICON_TOPMENU_TXBATT, COLOR_THEME_PRIMARY2); #if defined(USB_CHARGER) - batteryChargeIcon = - new StaticIcon(this, W_AUDIO_X + 25, 23, ICON_TOPMENU_TXBATT_CHARGE, - COLOR_THEME_PRIMARY2); + batteryChargeIcon = new StaticIcon( + this, W_BATT_CHG_X, W_BATT_CHG_Y, + ICON_TOPMENU_TXBATT_CHARGE, COLOR_THEME_PRIMARY2); batteryChargeIcon->hide(); #endif #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) - extAntenna = new StaticIcon(this, W_RSSI_X - 4, 1, ICON_TOPMENU_ANTENNA, + extAntenna = new StaticIcon(this, W_RSSI_X - 4, 1, + ICON_TOPMENU_ANTENNA, COLOR_THEME_PRIMARY2); extAntenna->hide(); #endif batteryFill = lv_obj_create(lvobj); lv_obj_set_pos(batteryFill, W_AUDIO_X + 1, 26); - lv_obj_set_size(batteryFill, 20, 9); + lv_obj_set_size(batteryFill, W_BATT_FILL_W, W_BATT_FILL_H); lv_obj_set_style_bg_opa(batteryFill, LV_OPA_COVER, LV_PART_MAIN); update(); @@ -95,8 +95,9 @@ class RadioInfoWidget : public TopBarWidget for (unsigned int i = 0; i < DIM(rssiBarsHeight); i++) { uint8_t height = rssiBarsHeight[i]; rssiBars[i] = lv_obj_create(lvobj); - lv_obj_set_pos(rssiBars[i], W_RSSI_X + i * 6, 35 - height); - lv_obj_set_size(rssiBars[i], 4, height); + lv_obj_set_pos(rssiBars[i], W_RSSI_X + i * W_RSSI_BAR_SZ, + W_RSSI_BAR_H - height); + lv_obj_set_size(rssiBars[i], W_RSSI_BAR_W, height); etx_solid_bg(rssiBars[i], COLOR_THEME_PRIMARY3_INDEX); etx_bg_color(rssiBars[i], COLOR_THEME_PRIMARY2_INDEX, LV_STATE_USER_1); } @@ -160,10 +161,10 @@ class RadioInfoWidget : public TopBarWidget #endif // Battery level - uint8_t bars = GET_TXBATT_BARS(20); + uint8_t bars = GET_TXBATT_BARS(W_BATT_FILL_W); if (bars != lastBatt) { lastBatt = bars; - lv_obj_set_size(batteryFill, bars, 9); + lv_obj_set_size(batteryFill, bars, W_BATT_FILL_H); if (bars >= 12) { lv_obj_clear_state(batteryFill, LV_STATE_USER_1 | LV_STATE_USER_2); } else if (bars >= 5) { @@ -191,6 +192,22 @@ class RadioInfoWidget : public TopBarWidget static const ZoneOption options[]; + static constexpr coord_t W_AUDIO_X = 0; + static LAYOUT_VAL(W_AUDIO_SCALE_X, 15, 15) + static LAYOUT_VAL(W_USB_X, 32, 32) + static LAYOUT_VAL(W_USB_Y, 5, 5) + static LAYOUT_VAL(W_LOG_X, 32, 32) + static LAYOUT_VAL(W_LOG_Y, 3, 3) + static LAYOUT_VAL(W_RSSI_X, 40, 40) + static LAYOUT_VAL(W_RSSI_BAR_W, 4, 4) + static LAYOUT_VAL(W_RSSI_BAR_H, 35, 35) + static LAYOUT_VAL(W_RSSI_BAR_SZ, 6, 6) + static LAYOUT_VAL(W_BATT_Y, 25, 25) + static LAYOUT_VAL(W_BATT_FILL_W, 20, 20) + static LAYOUT_VAL(W_BATT_FILL_H, 9, 9) + static LAYOUT_VAL(W_BATT_CHG_X, 25, 25) + static LAYOUT_VAL(W_BATT_CHG_Y, 23, 23) + protected: uint8_t lastVol = 0; uint8_t lastBatt = 0; @@ -221,13 +238,6 @@ const ZoneOption RadioInfoWidget::options[] = { BaseWidgetFactory RadioInfoWidget("Radio Info", RadioInfoWidget::options, STR_RADIO_INFO_WIDGET); -// Adjustment to make main view date/time align with model/radio settings views -#if LCD_W > LCD_H -#define DT_OFFSET 24 -#else -#define DT_OFFSET 8 -#endif - class DateTimeWidget : public TopBarWidget { public: @@ -235,7 +245,7 @@ class DateTimeWidget : public TopBarWidget const rect_t& rect, Widget::PersistentData* persistentData) : TopBarWidget(factory, parent, rect, persistentData) { - dateTime = new HeaderDateTime(lvobj, DT_OFFSET, 3); + dateTime = new HeaderDateTime(lvobj, DT_X, DT_Y); update(); } @@ -264,6 +274,10 @@ class DateTimeWidget : public TopBarWidget int8_t lastMinute = -1; static const ZoneOption options[]; + + // Adjustment to make main view date/time align with model/radio settings views + static LAYOUT_VAL(DT_X, 24, 8) + static LAYOUT_VAL(DT_Y, 3, 3) }; const ZoneOption DateTimeWidget::options[] = { @@ -285,8 +299,9 @@ class InternalGPSWidget : public TopBarWidget Widget::PersistentData* persistentData) : TopBarWidget(factory, parent, rect, persistentData) { - icon = new StaticIcon(this, width() / 2 - 10, 19, ICON_TOPMENU_GPS, - COLOR_THEME_PRIMARY3); + icon = + new StaticIcon(this, width() / 2 - 10, 19, + ICON_TOPMENU_GPS, COLOR_THEME_PRIMARY3); numSats = new DynamicNumber( this, {0, 1, width(), 12}, [=] { return gpsData.numSat; }, diff --git a/radio/src/gui/colorlcd/widgets/timer.cpp b/radio/src/gui/colorlcd/widgets/timer.cpp index b0624c1e9a2..a6d5c88cfda 100644 --- a/radio/src/gui/colorlcd/widgets/timer.cpp +++ b/radio/src/gui/colorlcd/widgets/timer.cpp @@ -70,13 +70,13 @@ class TimerWidget : public Widget // Timer value - on large widgets unit0 = createUnitLabel(); - lv_obj_set_pos(unit0, 111, 33); + lv_obj_set_pos(unit0, U0_X, U0_Y); unit1 = createUnitLabel(); - lv_obj_set_pos(unit1, 161, 33); + lv_obj_set_pos(unit1, U1_X, U1_Y); digits0 = createDigitsLabel(); - lv_obj_set_pos(digits0, 76, 31); + lv_obj_set_pos(digits0, D0_X, D0_Y); digits1 = createDigitsLabel(); - lv_obj_set_pos(digits1, 126, 31); + lv_obj_set_pos(digits1, D1_X, D1_Y); timerArc = lv_arc_create(lvobj); lv_arc_set_rotation(timerArc, 270); @@ -87,11 +87,11 @@ class TimerWidget : public Widget lv_obj_remove_style(timerArc, NULL, LV_PART_KNOB); lv_obj_clear_flag(timerArc, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_pos(timerArc, 2, 3); - lv_obj_set_size(timerArc, 64, 64); + lv_obj_set_size(timerArc, TMR_ARC_SZ, TMR_ARC_SZ); lv_obj_set_style_arc_opa(timerArc, LV_OPA_TRANSP, LV_PART_MAIN); - lv_obj_set_style_arc_width(timerArc, 10, LV_PART_MAIN); + lv_obj_set_style_arc_width(timerArc, TMR_ARC_W, LV_PART_MAIN); lv_obj_set_style_arc_opa(timerArc, LV_OPA_COVER, LV_PART_INDICATOR); - lv_obj_set_style_arc_width(timerArc, 10, LV_PART_INDICATOR); + lv_obj_set_style_arc_width(timerArc, TMR_ARC_W, LV_PART_INDICATOR); etx_obj_add_style(timerArc, styles->arc_color, LV_PART_INDICATOR); lv_obj_add_flag(timerArc, LV_OBJ_FLAG_HIDDEN); @@ -192,6 +192,21 @@ class TimerWidget : public Widget static const ZoneOption options[]; + static LAYOUT_VAL(TMR_LRG_W, 180, 180) + static LAYOUT_VAL(TMR_ARC_SZ, 64, 64) + static LAYOUT_VAL(TMR_ARC_W, 10, 10) + static LAYOUT_VAL(NM_LRG_X, 78, 78) + static LAYOUT_VAL(NM_LRG_Y, 19, 19) + static LAYOUT_VAL(NM_LRG_W, 93, 93) + static LAYOUT_VAL(U0_X, 111, 111) + static LAYOUT_VAL(U0_Y, 33, 33) + static LAYOUT_VAL(U1_X, 161, 161) + static LAYOUT_VAL(U1_Y, 33, 33) + static LAYOUT_VAL(D0_X, 76, 76) + static LAYOUT_VAL(D0_Y, 31, 31) + static LAYOUT_VAL(D1_X, 126, 126) + static LAYOUT_VAL(D1_Y, 31, 31) + protected: tmrval_t lastValue = 0; uint32_t lastStartValue = 0; @@ -217,14 +232,14 @@ class TimerWidget : public Widget bool hasName = ZLEN(timerData.name) > 0; - if (width() >= 180 && height() >= 70) { + if (width() >= TMR_LRG_W && height() >= 70) { isLarge = true; if (hasName) lv_obj_clear_state(nameLabel, EXT_NAME_ALIGN_RIGHT); else lv_obj_add_state(nameLabel, EXT_NAME_ALIGN_RIGHT); - lv_obj_set_pos(nameLabel, 78, 19); - lv_obj_set_width(nameLabel, 93); + lv_obj_set_pos(nameLabel, NM_LRG_X, NM_LRG_Y); + lv_obj_set_width(nameLabel, NM_LRG_W); lv_obj_clear_state(nameLabel, ETX_NAME_COLOR_WHITE); lv_obj_add_flag(valLabel, LV_OBJ_FLAG_HIDDEN); diff --git a/radio/src/gui/colorlcd/widgets/value.cpp b/radio/src/gui/colorlcd/widgets/value.cpp index 75ca6dbd9ee..b2d2b66b503 100644 --- a/radio/src/gui/colorlcd/widgets/value.cpp +++ b/radio/src/gui/colorlcd/widgets/value.cpp @@ -159,6 +159,9 @@ class ValueWidget : public Widget lv_obj_t* valueShadow; LcdFlags valueFlags = 0; + static LAYOUT_VAL(VAL_Y1, 14, 14) + static LAYOUT_VAL(VAL_Y2, 18, 18) + void update() override { // get source from options[0] @@ -179,7 +182,7 @@ class ValueWidget : public Widget lv_coord_t labelX = 0; lv_coord_t labelY = 0; lv_coord_t valueX = 0; - lv_coord_t valueY = 14; + lv_coord_t valueY = VAL_Y1; // Set font to L lv_obj_clear_state(value, ETX_STATE_LARGE_FONT); @@ -204,7 +207,7 @@ class ValueWidget : public Widget valueX = (valAlign == ALIGN_LEFT) ? 4 : (valAlign == ALIGN_CENTER) ? 1 : -4; - valueY = 18; + valueY = VAL_Y2; if (field >= MIXSRC_FIRST_TELEM) { if (!isGPSSensor(1 + (field - MIXSRC_FIRST_TELEM) / 3)) { // Set font to XL diff --git a/radio/src/gui/colorlcd/widgets_container.h b/radio/src/gui/colorlcd/widgets_container.h index 01450b325cc..80bc6ae38fb 100644 --- a/radio/src/gui/colorlcd/widgets_container.h +++ b/radio/src/gui/colorlcd/widgets_container.h @@ -27,11 +27,8 @@ #define WIDGET_NAME_LEN 12 #define MAX_WIDGET_OPTIONS 5 // Name? -#if LCD_W > LCD_H -#define MAX_TOPBAR_ZONES 6 -#else -#define MAX_TOPBAR_ZONES 4 -#endif +static LAYOUT_VAL(MAX_TOPBAR_ZONES, 6, 4) + #define MAX_TOPBAR_OPTIONS 1 // just because of VC++ which doesn't like 0-size arrays :( // Common 'ZoneOptionValue's among all layouts diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index a13c62a30e7..d0a2d184cf5 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -3063,7 +3063,7 @@ LROT_BEGIN(etxcst, NULL, 0) LROT_NUMENTRY( TEXT_SIZE, ZoneOption::TextSize ) LROT_NUMENTRY( ALIGNMENT, ZoneOption::Align ) LROT_NUMENTRY( SWITCH, ZoneOption::Switch ) - LROT_NUMENTRY( MENU_HEADER_HEIGHT, COLOR2FLAGS(MENU_HEADER_HEIGHT) ) + LROT_NUMENTRY( MENU_HEADER_HEIGHT, COLOR2FLAGS(EdgeTxStyles::MENU_HEADER_HEIGHT) ) // Colors gui/colorlcd/colors.h LROT_NUMENTRY( COLOR_THEME_PRIMARY1, COLOR2FLAGS(COLOR_THEME_PRIMARY1_INDEX) ) diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index 007792d8e6e..3bc53b1eadf 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -735,7 +735,7 @@ void displayLuaError(bool firstCall = false) coord_t w = 0.75 * LCD_W; coord_t left = (LCD_W - w) / 2; -#if (LCD_W > LCD_H) +#if (!PORTRAIT_LCD) coord_t hh = getFontHeight(FONT(XL)) + 4; #else coord_t hh = getFontHeight(FONT(L)) + 4; @@ -750,7 +750,7 @@ void displayLuaError(bool firstCall = false) luaLcdBuffer->drawSolidFilledRect(left, top - hh, w, hh, COLOR_THEME_SECONDARY1); luaLcdBuffer->drawSolidFilledRect(left, top, w, h, COLOR_THEME_SECONDARY3); -#if (LCD_W > LCD_H) +#if (!PORTRAIT_LCD) luaLcdBuffer->drawText(left + 10, top - hh + 2, title, FONT(XL) | COLOR_THEME_PRIMARY2); luaLcdBuffer->drawTextLines(left + 10, top + 5, w - 20, h - 10, lua_warning_info, FONT(L) | COLOR_THEME_PRIMARY1); #else diff --git a/radio/src/lv_conf.h b/radio/src/lv_conf.h index 4c793159492..1b2174c6dd8 100644 --- a/radio/src/lv_conf.h +++ b/radio/src/lv_conf.h @@ -1,6 +1,6 @@ /** * @file lv_conf.h - * Configuration file for v8.2.0 + * Configuration file for v8.4.0 */ /* @@ -29,9 +29,9 @@ /*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/ #define LV_COLOR_16_SWAP 0 -/*Enable more complex drawing routines to manage screens transparency. - *Can be used if the UI is above another layer, e.g. an OSD menu or video player. - *Requires `LV_COLOR_DEPTH = 32` colors and the screen's `bg_opa` should be set to non LV_OPA_COVER value*/ +/*Enable features to draw on transparent background. + *It's required if opa, and transform_* style properties are used. + *Can be also used if the UI is above another layer, e.g. an OSD menu or video player.*/ #define LV_COLOR_SCREEN_TRANSP 0 /* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently. @@ -46,10 +46,14 @@ *=========================*/ /*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/ +#if defined(BOOT) #define LV_MEM_CUSTOM 1 +#else +#define LV_MEM_CUSTOM 0 +#endif #if LV_MEM_CUSTOM == 0 /*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/ - #define LV_MEM_SIZE (8U * 1024U) /*[bytes]*/ + #define LV_MEM_SIZE (1024U * 1024U) /*[bytes]*/ /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/ #define LV_MEM_ADR 0 /*0: unused*/ @@ -57,6 +61,8 @@ #if LV_MEM_ADR == 0 //#define LV_MEM_POOL_INCLUDE your_alloc_library /* Uncomment if using an external allocator*/ //#define LV_MEM_POOL_ALLOC your_alloc /* Uncomment if using an external allocator*/ + #define LV_MEM_POOL_INCLUDE + #define LV_MEM_POOL_ALLOC sbrk #endif #else /*LV_MEM_CUSTOM*/ @@ -89,6 +95,9 @@ #if LV_TICK_CUSTOM #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ + /*If using lvgl as ESP32 component*/ + // #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h" + // #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL)) #endif /*LV_TICK_CUSTOM*/ /*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. @@ -126,33 +135,49 @@ #define LV_CIRCLE_CACHE_SIZE 4 #endif /*LV_DRAW_COMPLEX*/ +/** + * "Simple layers" are used when a widget has `style_opa < 255` to buffer the widget into a layer + * and blend it as an image with the given opacity. + * Note that `bg_opa`, `text_opa` etc don't require buffering into layer) + * The widget can be buffered in smaller chunks to avoid using large buffers. + * + * - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it + * - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated. + * + * Both buffer sizes are in bytes. + * "Transformed layers" (where transform_angle/zoom properties are used) use larger buffers + * and can't be drawn in chunks. So these settings affects only widgets with opacity. + */ +#define LV_LAYER_SIMPLE_BUF_SIZE (24 * 1024) +#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024) + /*Default image cache size. Image caching keeps the images opened. *If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added) *With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images. *However the opened images might consume additional RAM. *0: to disable caching*/ -#define LV_IMG_CACHE_DEF_SIZE 8 +#define LV_IMG_CACHE_DEF_SIZE 8 /*Number of stops allowed per gradient. Increase this to allow more stops. *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ -#define LV_GRADIENT_MAX_STOPS 2 +#define LV_GRADIENT_MAX_STOPS 2 /*Default gradient buffer size. *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. *LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes. *If the cache is too small the map will be allocated only while it's required for the drawing. *0 mean no caching.*/ -#define LV_GRAD_CACHE_DEF_SIZE 0 +#define LV_GRAD_CACHE_DEF_SIZE 0 /*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display) *LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ -#define LV_DITHER_GRADIENT 0 +#define LV_DITHER_GRADIENT 0 #if LV_DITHER_GRADIENT /*Add support for error diffusion dithering. *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. *The increase in memory consumption is (24 bits * object's width)*/ - #define LV_DITHER_ERROR_DIFFUSION 0 + #define LV_DITHER_ERROR_DIFFUSION 0 #endif /*Maximum buffer size to allocate for rotation. @@ -163,6 +188,9 @@ * GPU *-----------*/ +/*Use Arm's 2D acceleration library Arm-2D */ +#define LV_USE_GPU_ARM2D 0 + /*Use STM32's DMA2D (aka Chrom Art) GPU*/ #if defined(SIMU) #define LV_USE_GPU_STM32_DMA2D 0 @@ -171,23 +199,22 @@ #endif #if LV_USE_GPU_STM32_DMA2D /*Must be defined to include path of CMSIS header of target processor - e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ - #define LV_GPU_DMA2D_CMSIS_INCLUDE "stm32f4xx.h" - #if !defined(DMA2D_NLR_PL_Pos) - #define DMA2D_NLR_PL_Pos 16 - #endif - #if !defined(DMA2D_NLR_NL_Pos) - #define DMA2D_NLR_NL_Pos 0 - #endif - #if !defined(DMA2D_CR_START_Msk) - #define DMA2D_CR_START_Msk DMA2D_CR_START - #endif - #if !defined(DMA2D_FGPFCCR_AM_Pos) - #define DMA2D_FGPFCCR_AM_Pos 16 - #endif - #if !defined(DMA2D_FGPFCCR_ALPHA_Pos) - #define DMA2D_FGPFCCR_ALPHA_Pos 24 - #endif + e.g. "stm32f7xx.h" or "stm32f4xx.h"*/ + #define LV_GPU_DMA2D_CMSIS_INCLUDE "thirdparty/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h" +#endif + +/*Enable RA6M3 G2D GPU*/ +#define LV_USE_GPU_RA6M3_G2D 0 +#if LV_USE_GPU_RA6M3_G2D + /*include path of target processor + e.g. "hal_data.h"*/ + #define LV_GPU_RA6M3_G2D_INCLUDE "hal_data.h" +#endif + +/*Use SWM341's DMA2D GPU*/ +#define LV_USE_GPU_SWM341_DMA2D 0 +#if LV_USE_GPU_SWM341_DMA2D + #define LV_GPU_SWM341_DMA2D_INCLUDE "SWM341.h" #endif /*Use NXP's PXP GPU iMX RTxxx platforms*/ @@ -452,7 +479,11 @@ #define LV_FONT_FMT_TXT_LARGE 0 /*Enables/disables support for compressed fonts.*/ +#if defined(BOOT) #define LV_USE_FONT_COMPRESSED 1 +#else +#define LV_USE_FONT_COMPRESSED 0 +#endif /*Enable subpixel rendering*/ #define LV_USE_FONT_SUBPX 0 @@ -461,6 +492,9 @@ #define LV_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/ #endif +/*Enable drawing placeholders when glyph dsc is not found*/ +#define LV_USE_FONT_PLACEHOLDER 1 + /*================= * TEXT SETTINGS *=================*/ @@ -516,8 +550,6 @@ #if !defined(BOOT) #define LV_USE_ARC 1 -#define LV_USE_ANIMIMG 0 - #define LV_USE_BAR 1 #define LV_USE_BTN 1 @@ -563,6 +595,8 @@ /*----------- * Widgets *----------*/ +#define LV_USE_ANIMIMG 0 + #define LV_USE_CALENDAR 0 #if LV_USE_CALENDAR #define LV_CALENDAR_WEEK_STARTS_MONDAY 0 @@ -595,6 +629,12 @@ #define LV_USE_MSGBOX 0 +#define LV_USE_SPAN 0 +#if LV_USE_SPAN + /*A line text can contain maximum num of span descriptor */ + #define LV_SPAN_SNIPPET_STACK_SIZE 64 +#endif + #define LV_USE_SPINBOX 0 #define LV_USE_SPINNER 0 @@ -605,12 +645,6 @@ #define LV_USE_WIN 0 -#define LV_USE_SPAN 0 -#if LV_USE_SPAN - /*A line text can contain maximum num of span descriptor */ - #define LV_SPAN_SNIPPET_STACK_SIZE 64 -#endif - /*----------- * Themes *----------*/ @@ -647,7 +681,6 @@ #else #define LV_USE_ARC 0 -#define LV_USE_ANIMIMG 0 #define LV_USE_BAR 0 #define LV_USE_BTN 0 #define LV_USE_BTNMATRIX 0 @@ -662,6 +695,7 @@ #define LV_USE_SWITCH 0 #define LV_USE_TEXTAREA 0 /*Requires: lv_label*/ #define LV_USE_TABLE 0 +#define LV_USE_ANIMIMG 0 #define LV_USE_CALENDAR 0 #define LV_USE_CHART 0 #define LV_USE_COLORWHEEL 0 @@ -672,12 +706,12 @@ #define LV_USE_MENU 0 #define LV_USE_METER 0 #define LV_USE_MSGBOX 0 +#define LV_USE_SPAN 0 #define LV_USE_SPINBOX 0 #define LV_USE_SPINNER 0 #define LV_USE_TABVIEW 0 #define LV_USE_TILEVIEW 0 #define LV_USE_WIN 0 -#define LV_USE_SPAN 0 #define LV_USE_THEME_DEFAULT 0 #define LV_USE_THEME_BASIC 0 #define LV_USE_THEME_MONO 0 @@ -695,7 +729,7 @@ #if LV_USE_FS_STDIO #define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ #define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ - #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ + #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ #endif /*API for open, read, etc*/ @@ -703,20 +737,20 @@ #if LV_USE_FS_POSIX #define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ #define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ - #define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ + #define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ #endif /*API for CreateFile, ReadFile, etc*/ #define LV_USE_FS_WIN32 0 #if LV_USE_FS_WIN32 - #define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ #define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ #define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ #endif /*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/ #if defined(BOOT) -#define LV_USE_FS_FATFS 0 +#define LV_USE_FS_FATFS 0 #if LV_USE_FS_FATFS #define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ #define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ @@ -729,6 +763,13 @@ #endif #endif +/*API for LittleFS (library needs to be added separately). Uses lfs_file_open, lfs_file_read, etc*/ +#define LV_USE_FS_LITTLEFS 0 +#if LV_USE_FS_LITTLEFS + #define LV_FS_LITTLEFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_LITTLEFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + /*PNG decoder library*/ #define LV_USE_PNG 0 @@ -767,15 +808,22 @@ #endif #endif +/*Tiny TTF library*/ +#define LV_USE_TINY_TTF 0 +#if LV_USE_TINY_TTF + /*Load TTF data from files*/ + #define LV_TINY_TTF_FILE_SUPPORT 0 +#endif + /*Rlottie library*/ #define LV_USE_RLOTTIE 0 /*FFmpeg library for image decoding and playing videos *Supports all major image formats so do not enable other image decoder with it*/ -#define LV_USE_FFMPEG 0 +#define LV_USE_FFMPEG 0 #if LV_USE_FFMPEG /*Dump input information to stderr*/ - #define LV_FFMPEG_AV_DUMP_FORMAT 0 + #define LV_FFMPEG_DUMP_FORMAT 0 #endif /*----------- @@ -786,10 +834,37 @@ #define LV_USE_SNAPSHOT 1 /*1: Enable Monkey test*/ -#define LV_USE_MONKEY 0 +#define LV_USE_MONKEY 0 /*1: Enable grid navigation*/ -#define LV_USE_GRIDNAV 0 +#define LV_USE_GRIDNAV 0 + +/*1: Enable lv_obj fragment*/ +#define LV_USE_FRAGMENT 0 + +/*1: Support using images as font in label or span widgets */ +#define LV_USE_IMGFONT 0 + +/*1: Enable a published subscriber based messaging system */ +#define LV_USE_MSG 0 + +/*1: Enable Pinyin input method*/ +/*Requires: lv_keyboard*/ +#define LV_USE_IME_PINYIN 0 +#if LV_USE_IME_PINYIN + /*1: Use default thesaurus*/ + /*If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesauruss*/ + #define LV_IME_PINYIN_USE_DEFAULT_DICT 1 + /*Set the maximum number of candidate panels that can be displayed*/ + /*This needs to be adjusted according to the size of the screen*/ + #define LV_IME_PINYIN_CAND_TEXT_NUM 6 + + /*Use 9 key input(k9)*/ + #define LV_IME_PINYIN_USE_K9_MODE 1 + #if LV_IME_PINYIN_USE_K9_MODE == 1 + #define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3 + #endif // LV_IME_PINYIN_USE_K9_MODE +#endif /*================== * EXAMPLES @@ -803,28 +878,32 @@ ====================*/ /*Show some widget. It might be required to increase `LV_MEM_SIZE` */ -#define LV_USE_DEMO_WIDGETS 0 +#define LV_USE_DEMO_WIDGETS 0 #if LV_USE_DEMO_WIDGETS -#define LV_DEMO_WIDGETS_SLIDESHOW 0 +#define LV_DEMO_WIDGETS_SLIDESHOW 0 #endif /*Demonstrate the usage of encoder and keyboard*/ -#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 +#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 /*Benchmark your system*/ -#define LV_USE_DEMO_BENCHMARK 0 +#define LV_USE_DEMO_BENCHMARK 0 +#if LV_USE_DEMO_BENCHMARK +/*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/ +#define LV_DEMO_BENCHMARK_RGB565A8 0 +#endif /*Stress test for LVGL*/ -#define LV_USE_DEMO_STRESS 0 +#define LV_USE_DEMO_STRESS 0 /*Music player demo*/ -#define LV_USE_DEMO_MUSIC 0 +#define LV_USE_DEMO_MUSIC 0 #if LV_USE_DEMO_MUSIC -# define LV_DEMO_MUSIC_SQUARE 0 -# define LV_DEMO_MUSIC_LANDSCAPE 0 -# define LV_DEMO_MUSIC_ROUND 0 -# define LV_DEMO_MUSIC_LARGE 0 -# define LV_DEMO_MUSIC_AUTO_PLAY 0 + #define LV_DEMO_MUSIC_SQUARE 0 + #define LV_DEMO_MUSIC_LANDSCAPE 0 + #define LV_DEMO_MUSIC_ROUND 0 + #define LV_DEMO_MUSIC_LARGE 0 + #define LV_DEMO_MUSIC_AUTO_PLAY 0 #endif /*--END OF LV_CONF_H--*/ diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 88c18a37467..75f9c7567d6 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -690,7 +690,9 @@ union ReusableBuffer #if defined(SDCARD) struct { +#if defined(NUM_BODY_LINES) char lines[NUM_BODY_LINES][SD_SCREEN_FILE_LENGTH+1+1]; // the last char is used to store the flags (directory) of the line +#endif uint32_t available; uint16_t offset; uint16_t count; diff --git a/radio/src/storage/modelslist.h b/radio/src/storage/modelslist.h index 98c5485020e..9866e49a5af 100644 --- a/radio/src/storage/modelslist.h +++ b/radio/src/storage/modelslist.h @@ -48,7 +48,7 @@ #define DEFAULT_MODEL_SORT NAME_ASC -#if LCD_W > LCD_H // Landscape +#if !PORTRAIT_LCD // Landscape #define LABEL_TRUNCATE_LENGTH 21 #else #define LABEL_TRUNCATE_LENGTH 16 diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index a5b7e8c4883..7fe8e4c9813 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -1059,6 +1059,8 @@ #define BT_EN_GPIO_PIN LL_GPIO_PIN_10 // PG.10 #endif +#define PORTRAIT_LCD false +#define LANDSCAPE_LCD true #define LCD_W 480 #define LCD_H 272 #define LCD_PHYS_H LCD_H diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp index 6ffa7b16142..b8b028d89a4 100644 --- a/radio/src/targets/horus/lcd_driver.cpp +++ b/radio/src/targets/horus/lcd_driver.cpp @@ -159,8 +159,8 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, lv_area_t refr_area; lv_area_copy(&refr_area, &disp->inv_areas[i]); - //TRACE("{%d,%d,%d,%d}", refr_area.x1, - // refr_area.y1, refr_area.x2, refr_area.y2); + // TRACE("Vert invert refresh {%d,%d,%d,%d}", refr_area.x1, + // refr_area.y1, refr_area.x2 - refr_area.x1 + 1, refr_area.y2 - refr_area.y1 + 1); _rotate_area_180(refr_area); diff --git a/radio/src/targets/nv14/hal.h b/radio/src/targets/nv14/hal.h index 355633ef14e..9ae06f05afc 100644 --- a/radio/src/targets/nv14/hal.h +++ b/radio/src/targets/nv14/hal.h @@ -571,6 +571,9 @@ #define MIXER_SCHEDULER_TIMER_IRQn TIM8_BRK_TIM12_IRQn #define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_BRK_TIM12_IRQHandler +#define PORTRAIT_LCD true +#define LANDSCAPE_LCD false + #define LCD_W 320 #define LCD_H 480 diff --git a/radio/src/targets/pl18/hal.h b/radio/src/targets/pl18/hal.h index c819089bb0a..8d48f7e2bd9 100644 --- a/radio/src/targets/pl18/hal.h +++ b/radio/src/targets/pl18/hal.h @@ -696,6 +696,9 @@ #define MIXER_SCHEDULER_TIMER_IRQn TIM8_BRK_TIM12_IRQn #define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_BRK_TIM12_IRQHandler +#define PORTRAIT_LCD false +#define LANDSCAPE_LCD true + #define LCD_W 480 #define LCD_H 320 diff --git a/radio/src/tests/images/color/primitives_EN_320x480.png b/radio/src/tests/images/color/primitives_EN_320x480.png index 982541571dc..2ef25205ae4 100644 Binary files a/radio/src/tests/images/color/primitives_EN_320x480.png and b/radio/src/tests/images/color/primitives_EN_320x480.png differ diff --git a/radio/src/tests/images/color/primitives_EN_480x272.png b/radio/src/tests/images/color/primitives_EN_480x272.png index e8ce337140e..3a278a7b2d7 100644 Binary files a/radio/src/tests/images/color/primitives_EN_480x272.png and b/radio/src/tests/images/color/primitives_EN_480x272.png differ diff --git a/radio/src/tests/images/color/primitives_EN_480x320.png b/radio/src/tests/images/color/primitives_EN_480x320.png index 365a2a20fb2..5f36385a4df 100644 Binary files a/radio/src/tests/images/color/primitives_EN_480x320.png and b/radio/src/tests/images/color/primitives_EN_480x320.png differ diff --git a/radio/src/tests/images/color/transparency_EN_320x480.png b/radio/src/tests/images/color/transparency_EN_320x480.png index 24ddce74b14..44d47f2cd7e 100644 Binary files a/radio/src/tests/images/color/transparency_EN_320x480.png and b/radio/src/tests/images/color/transparency_EN_320x480.png differ diff --git a/radio/src/tests/images/color/transparency_EN_480x272.png b/radio/src/tests/images/color/transparency_EN_480x272.png index 4511a8f65ba..3c3d21057fd 100644 Binary files a/radio/src/tests/images/color/transparency_EN_480x272.png and b/radio/src/tests/images/color/transparency_EN_480x272.png differ diff --git a/radio/src/tests/images/color/transparency_EN_480x320.png b/radio/src/tests/images/color/transparency_EN_480x320.png index 2eceb5bc458..3c371e56ef7 100644 Binary files a/radio/src/tests/images/color/transparency_EN_480x320.png and b/radio/src/tests/images/color/transparency_EN_480x320.png differ diff --git a/radio/src/thirdparty/libopenui/src/bitmapbuffer_draw_extra.cpp b/radio/src/thirdparty/libopenui/src/bitmapbuffer_draw_extra.cpp index 383e6f85d4c..dd390cb9f58 100644 --- a/radio/src/thirdparty/libopenui/src/bitmapbuffer_draw_extra.cpp +++ b/radio/src/thirdparty/libopenui/src/bitmapbuffer_draw_extra.cpp @@ -154,7 +154,7 @@ void BitmapBuffer::drawGPSPosition(coord_t x, coord_t y, int32_t longitude, { if (flags & PREC1) { drawGPSCoord(x, y, latitude, "NS", flags, true); - drawGPSCoord(x, y + FH, longitude, "EW", flags, true); + drawGPSCoord(x, y + EdgeTxStyles::PAGE_LINE_HEIGHT, longitude, "EW", flags, true); } else { if (flags & RIGHT) { x = drawGPSCoord(x, y, longitude, "EW", flags, true); @@ -181,7 +181,7 @@ void BitmapBuffer::drawDate(coord_t x, coord_t y, TelemetryItem &telemetryItem, x = drawText(x, y, s.c_str(), att); if (doTwoLines) { - y += FH; + y += EdgeTxStyles::PAGE_LINE_HEIGHT; x = ox; } else { x += 11; diff --git a/radio/src/thirdparty/libopenui/src/button.cpp b/radio/src/thirdparty/libopenui/src/button.cpp index 6d4ce298812..99e86bbc838 100644 --- a/radio/src/thirdparty/libopenui/src/button.cpp +++ b/radio/src/thirdparty/libopenui/src/button.cpp @@ -34,7 +34,7 @@ const lv_obj_class_t button_class = { .user_data = nullptr, .event_cb = nullptr, .width_def = LV_SIZE_CONTENT, - .height_def = 32, + .height_def = EdgeTxStyles::UI_ELEMENT_HEIGHT, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE, .instance_size = sizeof(lv_btn_t), @@ -54,7 +54,8 @@ Button::Button(Window* parent, const rect_t& rect, ButtonBase::ButtonBase(Window* parent, const rect_t& rect, std::function pressHandler, LvglCreate objConstruct) : - FormField(parent, rect, 0, objConstruct ? objConstruct : lv_btn_create), + FormField(parent, rect, 0, + objConstruct ? objConstruct : lv_btn_create), pressHandler(std::move(pressHandler)) { lv_obj_add_event_cb(lvobj, ButtonBase::long_pressed, LV_EVENT_LONG_PRESSED, @@ -106,20 +107,21 @@ void ButtonBase::long_pressed(lv_event_t* e) TextButton::TextButton(Window* parent, const rect_t& rect, std::string text, std::function pressHandler) : - ButtonBase(parent, rect, pressHandler, button_create), text(std::move(text)) + ButtonBase(parent, rect, pressHandler, button_create), + text(std::move(text)) { label = lv_label_create(lvobj); lv_label_set_text(label, this->text.c_str()); lv_obj_center(label); } -IconButton::IconButton(Window* parent, EdgeTxIcon icon, +IconButton::IconButton(Window* parent, EdgeTxIcon icon, coord_t x, coord_t y, std::function pressHandler) : - ButtonBase(parent, {0, 0, 32, 32}, pressHandler, button_create) + ButtonBase(parent, {x, y, EdgeTxStyles::UI_ELEMENT_HEIGHT, EdgeTxStyles::UI_ELEMENT_HEIGHT}, pressHandler, button_create) { padAll(PAD_ZERO); iconImage = new StaticIcon(this, 0, 0, icon, COLOR_THEME_SECONDARY1); - iconImage->center(28, 28); + iconImage->center(EdgeTxStyles::UI_ELEMENT_HEIGHT - 4, EdgeTxStyles::UI_ELEMENT_HEIGHT - 4); } void IconButton::setIcon(EdgeTxIcon icon) { iconImage->setIcon(icon); } diff --git a/radio/src/thirdparty/libopenui/src/button.h b/radio/src/thirdparty/libopenui/src/button.h index bee05a899f4..920339c6b01 100644 --- a/radio/src/thirdparty/libopenui/src/button.h +++ b/radio/src/thirdparty/libopenui/src/button.h @@ -96,6 +96,13 @@ class TextButton : public ButtonBase } } + void setWrap() + { + 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); + } + protected: lv_obj_t* label = nullptr; @@ -105,7 +112,7 @@ class TextButton : public ButtonBase class IconButton : public ButtonBase { public: - IconButton(Window* parent, EdgeTxIcon icon, + IconButton(Window* parent, EdgeTxIcon icon, coord_t x, coord_t y, std::function pressHandler = nullptr); void setIcon(EdgeTxIcon icon); diff --git a/radio/src/thirdparty/libopenui/src/choice.cpp b/radio/src/thirdparty/libopenui/src/choice.cpp index 195b35b363d..ab879cd9235 100644 --- a/radio/src/thirdparty/libopenui/src/choice.cpp +++ b/radio/src/thirdparty/libopenui/src/choice.cpp @@ -36,7 +36,7 @@ static const lv_obj_class_t choice_class = { .user_data = nullptr, .event_cb = nullptr, .width_def = LV_SIZE_CONTENT, - .height_def = 32, + .height_def = EdgeTxStyles::UI_ELEMENT_HEIGHT, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_obj_t), @@ -66,23 +66,19 @@ void choice_changed_cb(lv_event_t* e) ChoiceBase::ChoiceBase(Window* parent, const rect_t& rect, ChoiceType type) : FormField(parent, rect, 0, choice_create), type(type) { - lv_obj_set_layout(lvobj, LV_LAYOUT_FLEX); - lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); - lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, - LV_FLEX_ALIGN_SPACE_AROUND); + // add the image + lv_obj_t* img = lv_img_create(lvobj); + lv_img_set_src( + img, type == CHOICE_TYPE_DROPOWN ? LV_SYMBOL_DOWN : LV_SYMBOL_DIRECTORY); + lv_obj_set_pos(img, 0, PAD_TINY); lv_obj_add_event_cb(lvobj, choice_changed_cb, LV_EVENT_VALUE_CHANGED, lvobj); label = lv_label_create(lvobj); + lv_obj_set_pos(label, ICON_W, PAD_TINY); lv_group_t* def_group = lv_group_get_default(); - if (def_group) { + if (def_group) lv_group_add_obj(def_group, lvobj); - } - - // add the image - lv_obj_t* img = lv_img_create(lvobj); - lv_img_set_src( - img, type == CHOICE_TYPE_DROPOWN ? LV_SYMBOL_DOWN : LV_SYMBOL_DIRECTORY); } std::string Choice::getLabelText() @@ -188,7 +184,8 @@ void Choice::onClicked() void Choice::fillMenu(Menu* menu, const FilterFct& filter) { - menu->removeLines(); + if (menu->count() > 0) + menu->removeLines(); auto value = getIntValue(); int count = 0; diff --git a/radio/src/thirdparty/libopenui/src/choice.h b/radio/src/thirdparty/libopenui/src/choice.h index 179a3673871..b21be834867 100644 --- a/radio/src/thirdparty/libopenui/src/choice.h +++ b/radio/src/thirdparty/libopenui/src/choice.h @@ -32,8 +32,6 @@ typedef struct { class Menu; -constexpr int CHOICE_LABEL_MARGIN_RIGHT = 10; - enum ChoiceType { CHOICE_TYPE_DROPOWN, CHOICE_TYPE_FOLDER, @@ -47,6 +45,8 @@ class ChoiceBase : public FormField void setChoiceType(ChoiceType t) { type = t; } + static LAYOUT_VAL(ICON_W, 18, 18) + protected: ChoiceType type; lv_obj_t *label; diff --git a/radio/src/thirdparty/libopenui/src/dialog.cpp b/radio/src/thirdparty/libopenui/src/dialog.cpp index 851dec1d877..dab721b37b4 100644 --- a/radio/src/thirdparty/libopenui/src/dialog.cpp +++ b/radio/src/thirdparty/libopenui/src/dialog.cpp @@ -165,3 +165,52 @@ void ConfirmDialog::onCancel() deleteLater(); if (cancelHandler) cancelHandler(); } + +//----------------------------------------------------------------------------- + +LabelDialog::LabelDialog(Window *parent, const char *label, int length, const char* title, + std::function _saveHandler) : + ModalWindow(parent, false), saveHandler(std::move(_saveHandler)) +{ + assert(length <= MAX_LABEL_LENGTH); + + strncpy(this->label, label, length); + this->label[length] = '\0'; + + 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}, title, + 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); + + new TextEdit(box, rect_t{0, 0, LV_PCT(100), 0}, this->label, length); + + 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; + }); + + new TextButton(box, rect_t{0, 0, 96, 0}, STR_SAVE, [=]() { + if (saveHandler != nullptr) saveHandler(this->label); + deleteLater(); + return 0; + }); +} diff --git a/radio/src/thirdparty/libopenui/src/dialog.h b/radio/src/thirdparty/libopenui/src/dialog.h index c1c852000a2..d8ef6021235 100644 --- a/radio/src/thirdparty/libopenui/src/dialog.h +++ b/radio/src/thirdparty/libopenui/src/dialog.h @@ -97,7 +97,7 @@ class DynamicMessageDialog : public BaseDialog DynamicMessageDialog(Window* parent, const char* title, std::function textHandler, const char* message = "", - const int lineHeight = PAGE_LINE_HEIGHT, + const int lineHeight = EdgeTxStyles::PAGE_LINE_HEIGHT, const LcdFlags textFlags = CENTERED); // Attn.: FONT(XXL) is not supported by DynamicMessageDialog @@ -127,3 +127,20 @@ class ConfirmDialog : public BaseDialog void onCancel() override; }; + +//----------------------------------------------------------------------------- + +class LabelDialog : public ModalWindow +{ + public: + LabelDialog(Window *parent, const char *label, int length, const char* title, + std::function _saveHandler = nullptr); + + static constexpr int MAX_LABEL_LENGTH = 255; + + void onCancel() override { deleteLater(); } + + protected: + std::function saveHandler; + char label[MAX_LABEL_LENGTH + 1]; +}; diff --git a/radio/src/thirdparty/libopenui/src/form.cpp b/radio/src/thirdparty/libopenui/src/form.cpp index 3bf3b971121..e6791bfea72 100644 --- a/radio/src/thirdparty/libopenui/src/form.cpp +++ b/radio/src/thirdparty/libopenui/src/form.cpp @@ -39,12 +39,6 @@ void FlexGridLayout::add(Window* w) } } -FormField::FormField(const rect_t& rect, LcdFlags textFlags) : - Window(rect) -{ - setTextFlag(textFlags); -} - FormField::FormField(Window* parent, const rect_t& rect, LcdFlags textFlags, LvglCreate objConstruct) : Window(parent, rect, objConstruct) @@ -53,12 +47,6 @@ FormField::FormField(Window* parent, const rect_t& rect, LcdFlags textFlags, lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS); } -void FormField::setupLVGL() -{ - Window::setupLVGL(); - lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS); -} - void FormField::setEditMode(bool newEditMode) { editMode = newEditMode; diff --git a/radio/src/thirdparty/libopenui/src/form.h b/radio/src/thirdparty/libopenui/src/form.h index 6134265e9f6..850547e4aad 100644 --- a/radio/src/thirdparty/libopenui/src/form.h +++ b/radio/src/thirdparty/libopenui/src/form.h @@ -77,12 +77,9 @@ class FlexGridLayout class FormField : public Window { public: - FormField(const rect_t& rect, LcdFlags textFlags); FormField(Window* parent, const rect_t& rect, LcdFlags textFlags = 0, LvglCreate objConstruct = nullptr); - void setupLVGL() override; - virtual void changeEnd(bool forceChanged = false) { if (changeHandler) { diff --git a/radio/src/thirdparty/libopenui/src/keyboard_number.cpp b/radio/src/thirdparty/libopenui/src/keyboard_number.cpp index 868d53a5925..f8fa1d9daf9 100644 --- a/radio/src/thirdparty/libopenui/src/keyboard_number.cpp +++ b/radio/src/thirdparty/libopenui/src/keyboard_number.cpp @@ -155,7 +155,7 @@ NumberKeyboard::NumberKeyboard() : Keyboard(KEYBOARD_HEIGHT) NumberKeyboard::~NumberKeyboard() { _instance = nullptr; } -void NumberKeyboard::show(NumberEdit* field) +void NumberKeyboard::show(FormField* field) { if (!_instance) _instance = new NumberKeyboard(); diff --git a/radio/src/thirdparty/libopenui/src/keyboard_number.h b/radio/src/thirdparty/libopenui/src/keyboard_number.h index 7feeae575e2..c06ad23db5e 100644 --- a/radio/src/thirdparty/libopenui/src/keyboard_number.h +++ b/radio/src/thirdparty/libopenui/src/keyboard_number.h @@ -20,8 +20,6 @@ #include "keyboard_base.h" -class NumberEdit; - class NumberKeyboard : public Keyboard { public: @@ -32,7 +30,7 @@ class NumberKeyboard : public Keyboard std::string getName() const override { return "NumberKeyboard"; } #endif - static void show(NumberEdit* field); + static void show(FormField* field); void handleEvent(const char* btn); diff --git a/radio/src/thirdparty/libopenui/src/libopenui_defines.h b/radio/src/thirdparty/libopenui/src/libopenui_defines.h index 11ca5102f43..f1289d0ff4c 100644 --- a/radio/src/thirdparty/libopenui/src/libopenui_defines.h +++ b/radio/src/thirdparty/libopenui/src/libopenui_defines.h @@ -24,23 +24,6 @@ #include "keys.h" #include "opentx_types.h" -constexpr uint32_t MENU_HEADER_BUTTON_WIDTH = 33; -constexpr uint32_t MENU_HEADER_BUTTONS_LEFT = 47; - -constexpr uint32_t MENU_HEADER_HEIGHT = 45; -constexpr uint32_t MENU_TITLE_TOP = 48; -constexpr uint32_t MENU_TITLE_HEIGHT = 21; -constexpr uint32_t MENU_BODY_TOP = MENU_TITLE_TOP + MENU_TITLE_HEIGHT; -constexpr uint32_t MENU_BODY_HEIGHT = LCD_H - MENU_BODY_TOP; -constexpr uint32_t MENUS_MARGIN_LEFT = 6; - -constexpr uint32_t PAGE_LINE_HEIGHT = 20; -constexpr uint32_t FH = PAGE_LINE_HEIGHT; -constexpr uint32_t NUM_BODY_LINES = MENU_BODY_HEIGHT / PAGE_LINE_HEIGHT; - -constexpr uint32_t PAGE_TITLE_TOP = 2; -constexpr uint32_t PAGE_TITLE_LEFT = 50; - // Used by Lua API #define INVERS 0x01u #define BLINK 0x1000u @@ -65,11 +48,3 @@ constexpr uint32_t PAGE_TITLE_LEFT = 50; #define NO_UNIT 0x40u #define LV_OBJ_FLAG_ENCODER_ACCEL LV_OBJ_FLAG_USER_1 - -constexpr coord_t MENUS_LINE_HEIGHT = 35; - -#if LCD_W > LCD_H -constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 7) + 8; -#else -constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 10); -#endif diff --git a/radio/src/thirdparty/libopenui/src/menutoolbar.cpp b/radio/src/thirdparty/libopenui/src/menutoolbar.cpp index e565177778f..0458b8a846e 100644 --- a/radio/src/thirdparty/libopenui/src/menutoolbar.cpp +++ b/radio/src/thirdparty/libopenui/src/menutoolbar.cpp @@ -65,7 +65,7 @@ MenuToolbarButton::MenuToolbarButton(Window* parent, const rect_t& rect, } MenuToolbar::MenuToolbar(Choice* choice, Menu* menu, const int columns) : - Window(menu, {0, 0, 76, MENUS_MAX_HEIGHT}), + Window(menu, {0, 0, 0, MENUS_MAX_HEIGHT}), choice(choice), menu(menu), filterColumns(columns), diff --git a/radio/src/thirdparty/libopenui/src/menutoolbar.h b/radio/src/thirdparty/libopenui/src/menutoolbar.h index 70166cd7b3a..6d287e56fe0 100644 --- a/radio/src/thirdparty/libopenui/src/menutoolbar.h +++ b/radio/src/thirdparty/libopenui/src/menutoolbar.h @@ -20,6 +20,7 @@ #include "button.h" #include "choice.h" +#include "listbox.h" class Menu; @@ -44,6 +45,14 @@ class MenuToolbar : public Window virtual void longPress() {} + static LAYOUT_VAL(MENUS_TOOLBAR_BUTTON_WIDTH, 32, 32) + +#if PORTRAIT_LCD + static constexpr coord_t MENUS_MAX_HEIGHT = (ListBox::MENUS_LINE_HEIGHT * 10); +#else + static constexpr coord_t MENUS_MAX_HEIGHT = (ListBox::MENUS_LINE_HEIGHT * 7) + 8; +#endif + protected: Choice* choice; Choice::FilterFct filter; diff --git a/radio/src/thirdparty/libopenui/src/numberedit.cpp b/radio/src/thirdparty/libopenui/src/numberedit.cpp index 25fa05751dd..bd779a47ab1 100644 --- a/radio/src/thirdparty/libopenui/src/numberedit.cpp +++ b/radio/src/thirdparty/libopenui/src/numberedit.cpp @@ -23,170 +23,350 @@ #include "strhelpers.h" #include "themes/etx_lv_theme.h" -static void numberedit_cb(lv_event_t* e) +class NumberArea : public FormField { - NumberEdit* numEdit = (NumberEdit*)lv_event_get_user_data(e); - if (!numEdit || numEdit->deleted()) return; - - uint32_t key = lv_event_get_key(e); - switch (key) { - case LV_KEY_LEFT: - numEdit->onEvent(EVT_ROTARY_LEFT); - break; - case LV_KEY_RIGHT: - numEdit->onEvent(EVT_ROTARY_RIGHT); - break; - } -} - -NumberEdit::NumberEdit(Window* parent, const rect_t& rect, int vmin, int vmax, - std::function getValue, - std::function setValue, LcdFlags textFlags) : - FormField(rect, textFlags), - vmin(vmin), - vmax(vmax), - _getValue(std::move(getValue)), - _setValue(std::move(setValue)) -{ - lv_obj_enable_style_refresh(false); - - // Workaround for performance issues with lv_textarea - create on top layer - // not this window then reparent to this window after setup finished - this->parent = parent; - lvobj = lv_textarea_create(lv_layer_top()); - - // Do this first - before any styles are applied, otherwise it is very slow - update(); - - etx_textarea_style(lvobj); + public: + NumberArea(Window* parent, const rect_t& rect, int vmin, int vmax, + std::function getValue, + std::function setValue = nullptr, + LcdFlags textFlags = 0) : + FormField(parent, rect, textFlags, etx_textarea_create), + vmin(vmin), + vmax(vmax), + _getValue(std::move(getValue)), + _setValue(std::move(setValue)) + { + if (rect.w == 0) setWidth(DEF_W); - etx_obj_add_style(lvobj, styles->text_align_right, LV_PART_MAIN); + etx_obj_add_style(lvobj, styles->text_align_right, LV_PART_MAIN); - // Allow encoder acceleration - lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL); + // Allow encoder acceleration + lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL); - lv_obj_add_event_cb(lvobj, numberedit_cb, LV_EVENT_KEY, this); + lv_obj_add_event_cb(lvobj, NumberArea::numberedit_cb, LV_EVENT_KEY, this); - lv_obj_set_parent(lvobj, parent->getLvObj()); - setupLVGL(); - - if (rect.w == 0) setWidth(100); + update(); + } - lv_obj_enable_style_refresh(true); - lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); -} +#if defined(DEBUG_WINDOWS) + std::string getName() const override + { + return "NumberArea(" + std::to_string(getValue()) + ")"; + } +#endif -void NumberEdit::onEvent(event_t event) -{ - TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), - event); + void onEvent(event_t event) override + { + TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), + event); - if (editMode) { - switch (event) { + if (editMode) { + switch (event) { #if defined(HARDWARE_KEYS) - case EVT_ROTARY_RIGHT: { - int value = getValue(); - auto step = getStep(); - step += (rotaryEncoderGetAccel() * getAccelFactor()) / 8; - do { + case EVT_ROTARY_RIGHT: { + int value = getValue(); + auto step = vstep; + step += (rotaryEncoderGetAccel() * accelFactor) / 8; + do { #if defined(USE_HATS_AS_KEYS) - value -= step; + value -= step; #else - value += step; + value += step; #endif - } while (isValueAvailable && !isValueAvailable(value) && value <= vmax); - if (value <= vmax) { - setValue(value); - } else { - setValue(vmax); - onKeyError(); + } while (isValueAvailable && !isValueAvailable(value) && + value <= vmax); + if (value <= vmax) { + setValue(value); + } else { + setValue(vmax); + onKeyError(); + } + return; } - return; - } - case EVT_ROTARY_LEFT: { - int value = getValue(); - auto step = getStep(); - step += (rotaryEncoderGetAccel() * getAccelFactor()) / 8; - do { + case EVT_ROTARY_LEFT: { + int value = getValue(); + auto step = vstep; + step += (rotaryEncoderGetAccel() * accelFactor) / 8; + do { #if defined(USE_HATS_AS_KEYS) - value += step; + value += step; #else - value -= step; + value -= step; #endif - } while (isValueAvailable && !isValueAvailable(value) && value >= vmin); - if (value >= vmin) { - setValue(value); - } else { - setValue(vmin); - onKeyError(); + } while (isValueAvailable && !isValueAvailable(value) && + value >= vmin); + if (value >= vmin) { + setValue(value); + } else { + setValue(vmin); + onKeyError(); + } + return; } - return; - } #endif - case EVT_VIRTUAL_KEY_PLUS: - setValue(getValue() + getStep()); - break; + case EVT_VIRTUAL_KEY_PLUS: + setValue(getValue() + vstep); + break; - case EVT_VIRTUAL_KEY_MINUS: - setValue(getValue() - getStep()); - break; + case EVT_VIRTUAL_KEY_MINUS: + setValue(getValue() - vstep); + break; - case EVT_VIRTUAL_KEY_FORWARD: - setValue(getValue() + getFastStep() * getStep()); - break; + case EVT_VIRTUAL_KEY_FORWARD: + setValue(getValue() + fastStep * vstep); + break; - case EVT_VIRTUAL_KEY_BACKWARD: - setValue(getValue() - getFastStep() * getStep()); - break; + case EVT_VIRTUAL_KEY_BACKWARD: + setValue(getValue() - fastStep * vstep); + break; - case EVT_VIRTUAL_KEY_DEFAULT: - setValue(getDefault()); - break; + case EVT_VIRTUAL_KEY_DEFAULT: + setValue(vdefault); + break; - case EVT_VIRTUAL_KEY_MAX: - setValue(getMax()); - break; + case EVT_VIRTUAL_KEY_MAX: + setValue(vmax); + break; - case EVT_VIRTUAL_KEY_MIN: - setValue(getMin()); - break; + case EVT_VIRTUAL_KEY_MIN: + setValue(vmin); + break; + + case EVT_VIRTUAL_KEY_SIGN: + setValue(-getValue()); + break; + } + } + + FormField::onEvent(event); + } + + void onClicked() override + { + lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + if (indev_type == LV_INDEV_TYPE_POINTER) { + setEditMode(true); + } else { + FormField::onClicked(); + } + } + + void setMin(int value) { vmin = value; } + void setMax(int value) { vmax = value; } + void setDefault(int value) { vdefault = value; } + void setStep(int value) { vstep = value; } + void setFastStep(int value) { fastStep = value; } + void setAccelFactor(int value) { accelFactor = value; } + void setValue(int value) + { + auto newValue = limit(vmin, value, vmax); + if (newValue != currentValue) { + currentValue = newValue; + if (_setValue != nullptr) { + _setValue(currentValue); + } + } + updateDisplay(); + } + + int32_t getValue() const { return _getValue != nullptr ? _getValue() : 0; } + + void setPrefix(std::string value) { prefix = std::move(value); } + + void setSuffix(std::string value) { suffix = std::move(value); } + + void setZeroText(std::string value) { zeroText = std::move(value); } + + void setAvailableHandler(std::function handler) + { + isValueAvailable = std::move(handler); + } + + void setSetValueHandler(std::function handler) + { + _setValue = std::move(handler); + } + + void setGetValueHandler(std::function handler) + { + _getValue = std::move(handler); + } + + void setDisplayHandler(std::function function) + { + displayFunction = std::move(function); + } + + void setCancelHandler(std::function handler) + { + cancelHandler = std::move(handler); + } + + void openKeyboard() { NumberKeyboard::show(this); } + void directEdit() { FormField::onClicked(); } + + void update() + { + if (_getValue == nullptr) return; + currentValue = _getValue(); + updateDisplay(); + } + + static LAYOUT_VAL(DEF_W, 100, 100) - case EVT_VIRTUAL_KEY_SIGN: - setValue(-getValue()); + protected: + int vdefault = 0; + int vmin; + int vmax; + int vstep = 1; + int fastStep = 10; + int accelFactor = 4; + int currentValue; + std::string prefix; + std::string suffix; + std::string zeroText; + std::function _getValue; + std::function _setValue; + std::function displayFunction; + std::function isValueAvailable; + std::function cancelHandler = nullptr; + + void updateDisplay() + { + if (lvobj != nullptr) { + std::string str; + if (displayFunction != nullptr) { + str = displayFunction(currentValue); + } else if (!zeroText.empty() && currentValue == 0) { + str = zeroText; + } else { + str = formatNumberAsString(currentValue, textFlags, 0, prefix.c_str(), + suffix.c_str()); + } + lv_textarea_set_text(lvobj, str.c_str()); + } + } + + void onCancel() override + { + if (cancelHandler) + cancelHandler(); + else + FormField::onCancel(); + } + + static void numberedit_cb(lv_event_t* e) + { + NumberArea* numEdit = (NumberArea*)lv_event_get_user_data(e); + if (!numEdit || numEdit->deleted()) return; + + uint32_t key = lv_event_get_key(e); + switch (key) { + case LV_KEY_LEFT: + numEdit->onEvent(EVT_ROTARY_LEFT); + break; + case LV_KEY_RIGHT: + numEdit->onEvent(EVT_ROTARY_RIGHT); break; } } +}; + +/* + The lv_textarea object is slow. To avoid too much overhead on views with multiple + edit fields, the text area is initially displayed as a button. When the button + is pressed, a text area object is created over the top of the button in order + to edit the value. +*/ +NumberEdit::NumberEdit(Window* parent, const rect_t& rect, int vmin, int vmax, + std::function getValue, + std::function setValue, LcdFlags textFlags) : + TextButton(parent, rect, "", + [=]() { + openEdit(); + return 0; + }), + _getValue(std::move(getValue)), + _setValue(std::move(setValue)), + vmin(vmin), + vmax(vmax) +{ + if (rect.w == 0) setWidth(NumberArea::DEF_W); + + setTextFlag(textFlags); + + lv_obj_set_width(label, width() - PAD_MEDIUM * 2 - 2); + etx_obj_add_style(label, styles->text_align_right, LV_PART_MAIN); - FormField::onEvent(event); + update(); } -void NumberEdit::onClicked() +void NumberEdit::openEdit() { - lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); + if (edit == nullptr) { + edit = new NumberArea( + this, + {-(PAD_MEDIUM + 2), -(PAD_TINY + 2), + lv_obj_get_width(lvobj), lv_obj_get_height(lvobj)}, + this->vmin, this->vmax, _getValue, _setValue, textFlags); + edit->setChangeHandler([=]() { + update(); + lv_group_focus_obj(lvobj); + edit->hide(); + }); + edit->setCancelHandler([=]() { + lv_group_focus_obj(lvobj); + edit->hide(); + }); + } + edit->setTextFlag(textFlags); + edit->setSetValueHandler(_setValue); + edit->setGetValueHandler(_getValue); + edit->setAvailableHandler(isValueAvailable); + edit->setDisplayHandler(displayFunction); + edit->setDefault(vdefault); + edit->setMin(vmin); + edit->setMax(vmax); + edit->setStep(step); + edit->setFastStep(fastStep); + edit->setAccelFactor(accelFactor); + edit->setPrefix(prefix); + edit->setSuffix(suffix); + edit->setZeroText(zeroText); + edit->update(); + edit->show(); + lv_group_focus_obj(edit->getLvObj()); + lv_indev_type_t indev_type = + lv_indev_get_type(lv_indev_get_act()); if (indev_type == LV_INDEV_TYPE_POINTER) { - NumberKeyboard::show(this); - return; + edit->openKeyboard(); + } else { + edit->directEdit(); } + lv_obj_add_state(lvobj, LV_STATE_FOCUSED); +} - FormField::onClicked(); +void NumberEdit::update() +{ + if (_getValue == nullptr) return; + currentValue = _getValue(); + updateDisplay(); } void NumberEdit::updateDisplay() { - if (lvobj != nullptr) { - std::string str; - if (displayFunction != nullptr) { - str = displayFunction(currentValue); - } else if (!zeroText.empty() && currentValue == 0) { - str = zeroText; - } else { - str = formatNumberAsString(currentValue, textFlags, 0, prefix.c_str(), - suffix.c_str()); - } - lv_textarea_set_text(lvobj, str.c_str()); + std::string str; + if (displayFunction != nullptr) { + str = displayFunction(currentValue); + } else if (!zeroText.empty() && currentValue == 0) { + str = zeroText; + } else { + str = formatNumberAsString(currentValue, textFlags, 0, prefix.c_str(), + suffix.c_str()); } + setText(str); } void NumberEdit::setValue(int value) @@ -199,14 +379,5 @@ void NumberEdit::setValue(int value) } } updateDisplay(); -} - -void NumberEdit::update() -{ - if (_getValue == nullptr) return; - auto newValue = _getValue(); - if (newValue != currentValue) { - currentValue = newValue; - } - updateDisplay(); + if (edit) edit->setValue(value); } diff --git a/radio/src/thirdparty/libopenui/src/numberedit.h b/radio/src/thirdparty/libopenui/src/numberedit.h index a17e05e34f2..da7ca7da78a 100644 --- a/radio/src/thirdparty/libopenui/src/numberedit.h +++ b/radio/src/thirdparty/libopenui/src/numberedit.h @@ -19,148 +19,95 @@ #pragma once #include "form.h" +#include "button.h" -class NumberEdit: public FormField +class NumberArea; + +class NumberEdit : public TextButton { - public: - NumberEdit(Window* parent, const rect_t& rect, int vmin, int vmax, - std::function getValue, - std::function setValue = nullptr, - LcdFlags textFlags = 0); + public: + NumberEdit(Window* parent, const rect_t& rect, int vmin, int vmax, + std::function getValue, + std::function setValue = nullptr, + LcdFlags textFlags = 0); #if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "NumberEdit(" + std::to_string(getValue()) + ")"; - } + std::string getName() const override + { + return "NumberEdit"; + } #endif - void setAvailableHandler(std::function handler) - { - isValueAvailable = std::move(handler); - } - - void onEvent(event_t event) override; - void onClicked() override; - - void setMin(int value) - { - vmin = value; - } - - void setMax(int value) - { - vmax = value; - } - - void setDefault(int value) - { - vdefault = value; - } - - int32_t getMin() const - { - return vmin; - } - - int32_t getMax() const - { - return vmax; - } - - int32_t getDefault() const - { - return vdefault; - } - - void setStep(int value) - { - step = value; - } - - int32_t getStep() const - { - return step; - } - - void setFastStep(int value) - { - fastStep = value; - } - - int32_t getFastStep() const - { - return fastStep; - } - - void setAccelFactor(int value) - { - accelFactor = value; - } - - int32_t getAccelFactor() const - { - return accelFactor; - } - - void setValue(int value); - - void setPrefix(std::string value) - { - prefix = std::move(value); - update(); - } - - void setSuffix(std::string value) - { - suffix = std::move(value); - update(); - } - - void setZeroText(std::string value) - { - zeroText = std::move(value); - update(); - } - - void setSetValueHandler(std::function handler) - { - _setValue = std::move(handler); - } - - void setGetValueHandler(std::function handler) - { - _getValue = std::move(handler); - } - - int32_t getValue() const - { - return _getValue != nullptr ? _getValue() : 0; - } - - void setDisplayHandler(std::function function) - { - displayFunction = std::move(function); - update(); - } - - virtual void update(); - - protected: - int vdefault = 0; - int vmin; - int vmax; - int step = 1; - int fastStep = 10; - int accelFactor = 4; - int currentValue; - std::string prefix; - std::string suffix; - std::string zeroText; - std::function _getValue; - std::function _setValue; - std::function displayFunction; - std::function isValueAvailable; - - void updateDisplay(); + virtual void update(); + + int32_t getMax() const { return vmax; } + + void setMin(int value) { vmin = value; } + void setMax(int value) { vmax = value; } + void setDefault(int value) { vdefault = value; } + void setStep(int value) { step = value; } + void setFastStep(int value) { fastStep = value; } + void setAccelFactor(int value) { accelFactor = value; } + void setValue(int value); + + void setPrefix(std::string value) + { + prefix = std::move(value); + update(); + } + + void setSuffix(std::string value) + { + suffix = std::move(value); + update(); + } + + void setZeroText(std::string value) + { + zeroText = std::move(value); + update(); + } + + void setAvailableHandler(std::function handler) + { + isValueAvailable = std::move(handler); + } + + void setDisplayHandler(std::function function) + { + displayFunction = std::move(function); + update(); + } + + void setSetValueHandler(std::function handler) + { + _setValue = std::move(handler); + } + + void setGetValueHandler(std::function handler) + { + _getValue = std::move(handler); + } + + int32_t getValue() const { return _getValue != nullptr ? _getValue() : 0; } + + protected: + NumberArea* edit = nullptr; + std::function _getValue; + std::function _setValue; + int vdefault = 0; + int vmin; + int vmax; + int step = 1; + int fastStep = 10; + int accelFactor = 4; + int currentValue; + std::string prefix; + std::string suffix; + std::string zeroText; + std::function displayFunction; + std::function isValueAvailable; + + void updateDisplay(); + void openEdit(); }; diff --git a/radio/src/thirdparty/libopenui/src/progress.cpp b/radio/src/thirdparty/libopenui/src/progress.cpp index 9a287c1487e..3488dcc9506 100644 --- a/radio/src/thirdparty/libopenui/src/progress.cpp +++ b/radio/src/thirdparty/libopenui/src/progress.cpp @@ -36,7 +36,7 @@ static const lv_obj_class_t bar_class = { .user_data = nullptr, .event_cb = nullptr, .width_def = LV_PCT(100), - .height_def = 32, + .height_def = EdgeTxStyles::UI_ELEMENT_HEIGHT, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_bar_t), diff --git a/radio/src/thirdparty/libopenui/src/static.cpp b/radio/src/thirdparty/libopenui/src/static.cpp index 38a71554f4a..43e11f66e87 100644 --- a/radio/src/thirdparty/libopenui/src/static.cpp +++ b/radio/src/thirdparty/libopenui/src/static.cpp @@ -45,7 +45,6 @@ StaticText::StaticText(Window* parent, const rect_t& rect, std::string txt, LV_PART_MAIN); lv_label_set_text(lvobj, text.c_str()); if (rect.h == 0) lv_obj_set_height(lvobj, LV_SIZE_CONTENT); - lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); } #if defined(DEBUG_WINDOWS) diff --git a/radio/src/thirdparty/libopenui/src/textedit.cpp b/radio/src/thirdparty/libopenui/src/textedit.cpp index 302b3a63cf0..e1dee05c114 100644 --- a/radio/src/thirdparty/libopenui/src/textedit.cpp +++ b/radio/src/thirdparty/libopenui/src/textedit.cpp @@ -27,80 +27,169 @@ #include "menu.h" #endif -TextEdit::TextEdit(Window* parent, const rect_t& rect, char* value, - uint8_t length) : - FormField(rect, 0), value(value), length(length) +class TextArea : public FormField { - lv_obj_enable_style_refresh(false); + public: + TextArea(Window* parent, const rect_t& rect, char* value, uint8_t length) : + FormField(parent, rect, 0, etx_textarea_create), value(value), length(length) + { + lv_textarea_set_max_length(lvobj, length); + lv_textarea_set_placeholder_text(lvobj, "---"); - // Workaround for performance issues with lv_textarea - create on top layer - // not this window then reparent to this window after setup finished - this->parent = parent; - lvobj = lv_textarea_create(lv_layer_top()); + if (rect.w == 0) setWidth(DEF_W); - // Do this first - before any styles are applied, otherwise it is very slow - update(); + update(); + } - etx_textarea_style(lvobj); +#if defined(DEBUG_WINDOWS) + std::string getName() const override { return "TextArea"; } +#endif - lv_textarea_set_max_length(lvobj, length); - lv_textarea_set_placeholder_text(lvobj, "---"); + void update() + { + // value may not be null-terminated + std::string txt(value, length); + lv_textarea_set_text(lvobj, txt.c_str()); + } - lv_obj_set_parent(lvobj, parent->getLvObj()); - setupLVGL(); + void onClicked() override { + setEditMode(true); + } - if (rect.w == 0) setWidth(100); + void openKeyboard() { + TextKeyboard::show(this); + } - lv_obj_enable_style_refresh(true); - lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); -} + void setCancelHandler(std::function handler) + { + cancelHandler = std::move(handler); + } -void TextEdit::update() -{ - // value may not be null-terminated - std::string txt(value, length); - lv_textarea_set_text(lvobj, txt.c_str()); -} + static LAYOUT_VAL(DEF_W, 100, 100) + + protected: + char* value; + uint8_t length; + std::function cancelHandler = nullptr; + + void trim() + { + for (int i = length - 1; i >= 0; i--) { + if (value[i] == ' ' || value[i] == '\0') + value[i] = '\0'; + else + break; + } + } -void TextEdit::trim() -{ - for (int i = length - 1; i >= 0; i--) { - if (value[i] == ' ' || value[i] == '\0') - value[i] = '\0'; + void changeEnd(bool forceChanged = false) override + { + if (lvobj == nullptr) return; + + bool changed = false; + auto text = lv_textarea_get_text(lvobj); + if (strncmp(value, text, length) != 0) { + changed = true; + } + + if (changed || forceChanged) { + strncpy(value, text, length); + trim(); + FormField::changeEnd(); + } else if (cancelHandler) { + cancelHandler(); + } + } + + void onCancel() override + { + if (cancelHandler) + cancelHandler(); else - break; + FormField::onCancel(); } -} +}; -void TextEdit::changeEnd(bool forceChanged) +/* + The lv_textarea object is slow. To avoid too much overhead on views with multiple + edit fields, the text area is initially displayed as a button. When the button + is pressed, a text area object is created over the top of the button in order + to edit the value. +*/ +TextEdit::TextEdit(Window* parent, const rect_t& rect, char* text, + uint8_t length, + std::function updateHandler) : + TextButton(parent, rect, "", [=]() { + openEdit(); + return 0; + }), + updateHandler(updateHandler), text(text), length(length) { - if (lvobj == nullptr) return; + if (rect.w == 0) setWidth(TextArea::DEF_W); + + update(); + lv_obj_align(label, LV_ALIGN_OUT_LEFT_MID, 0, PAD_TINY); +} - bool changed = false; - auto text = lv_textarea_get_text(lvobj); - if (strncmp(value, text, length) != 0) { - changed = true; +void TextEdit::update() +{ + if (text[0]) { + std::string s(text, length); + setText(s); + } else { + setText("---"); } +} - if (changed || forceChanged) { - strncpy(value, text, length); - trim(); - FormField::changeEnd(); +void TextEdit::openEdit() +{ + if (edit == nullptr) { + edit = new TextArea(this, + {-(PAD_MEDIUM + 2), -(PAD_TINY + 2), + lv_obj_get_width(lvobj), lv_obj_get_height(lvobj)}, + text, length); + edit->setChangeHandler([=]() { + std::string s(text, length); + setText(s); + if (updateHandler) updateHandler(); + lv_group_focus_obj(lvobj); + edit->hide(); + }); + edit->setCancelHandler([=]() { + lv_group_focus_obj(lvobj); + edit->hide(); + }); } + edit->show(); + lv_group_focus_obj(edit->getLvObj()); + edit->openKeyboard(); + lv_obj_add_state(lvobj, LV_STATE_FOCUSED); } -void TextEdit::onClicked() { TextKeyboard::show(this); } +void TextEdit::preview(bool edited, char* text, uint8_t length) +{ + edit = new TextArea(this, + {-(PAD_MEDIUM + 2), -(PAD_TINY + 2), width(), height()}, + text, length); + lv_group_focus_obj(edit->getLvObj()); + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE); + lv_obj_clear_flag(edit->getLvObj(), LV_OBJ_FLAG_CLICKABLE); + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); + lv_obj_clear_flag(edit->getLvObj(), LV_OBJ_FLAG_CLICK_FOCUSABLE); + lv_obj_add_state(edit->getLvObj(), LV_STATE_FOCUSED); + if (edited) lv_obj_add_state(edit->getLvObj(), LV_STATE_EDITED); +} ModelTextEdit::ModelTextEdit(Window* parent, const rect_t& rect, char* value, uint8_t length) : - TextEdit(parent, rect, value, length) + TextEdit(parent, rect, value, length, + []() { storageDirty(EE_MODEL); }) { - setChangeHandler([]() { storageDirty(EE_MODEL); }); } RadioTextEdit::RadioTextEdit(Window* parent, const rect_t& rect, char* value, uint8_t length) : - TextEdit(parent, rect, value, length) + TextEdit(parent, rect, value, length, + []() { storageDirty(EE_GENERAL); }) { - setChangeHandler([]() { storageDirty(EE_GENERAL); }); } diff --git a/radio/src/thirdparty/libopenui/src/textedit.h b/radio/src/thirdparty/libopenui/src/textedit.h index f0ac4a2778e..55e69f9fa07 100644 --- a/radio/src/thirdparty/libopenui/src/textedit.h +++ b/radio/src/thirdparty/libopenui/src/textedit.h @@ -19,31 +19,32 @@ #pragma once #include "form.h" +#include "button.h" -class TextEdit : public FormField +class TextArea; + +class TextEdit : public TextButton { public: - TextEdit(Window* parent, const rect_t& rect, char* value, uint8_t length); + TextEdit(Window* parent, const rect_t& rect, char* text, uint8_t length, + std::function updateHandler = nullptr); #if defined(DEBUG_WINDOWS) - std::string getName() const override { return "TextEdit"; } + std::string getName() const override { return "TextEdit \"" + text + "\""; } #endif - uint8_t getMaxLength() const { return length; } - char* getData() const { return value; } - + void preview(bool edited, char* text, uint8_t length); void update(); - protected: - static void event_cb(lv_event_t* e); + static LAYOUT_VAL(DEF_W, 100, 100) - char* value; + protected: + std::function updateHandler = nullptr; + TextArea* edit = nullptr; + char* text; uint8_t length; - void trim(); - - void changeEnd(bool forceChanged = false) override; - void onClicked() override; + void openEdit(); }; class ModelTextEdit : public TextEdit diff --git a/radio/src/thirdparty/libopenui/src/toggleswitch.cpp b/radio/src/thirdparty/libopenui/src/toggleswitch.cpp index d459f2c24d1..3a046e942b6 100644 --- a/radio/src/thirdparty/libopenui/src/toggleswitch.cpp +++ b/radio/src/thirdparty/libopenui/src/toggleswitch.cpp @@ -55,8 +55,8 @@ static const lv_obj_class_t switch_class = { .destructor_cb = nullptr, .user_data = nullptr, .event_cb = nullptr, - .width_def = 0, - .height_def = 32, + .width_def = ToggleSwitch::TOGGLE_W, + .height_def = EdgeTxStyles::UI_ELEMENT_HEIGHT, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_switch_t), diff --git a/radio/src/thirdparty/libopenui/src/toggleswitch.h b/radio/src/thirdparty/libopenui/src/toggleswitch.h index 70bde0391f7..6ada607a025 100644 --- a/radio/src/thirdparty/libopenui/src/toggleswitch.h +++ b/radio/src/thirdparty/libopenui/src/toggleswitch.h @@ -47,7 +47,9 @@ class ToggleSwitch : public FormField } void update() const; - + + static LAYOUT_VAL(TOGGLE_W, 52, 52) + protected: std::function _getValue; std::function _setValue; diff --git a/radio/src/thirdparty/libopenui/src/window.cpp b/radio/src/thirdparty/libopenui/src/window.cpp index 95ab645948c..f1bb8c79ede 100644 --- a/radio/src/thirdparty/libopenui/src/window.cpp +++ b/radio/src/thirdparty/libopenui/src/window.cpp @@ -20,6 +20,7 @@ #include "button.h" #include "form.h" +#include "static.h" #include "themes/etx_lv_theme.h" std::list Window::trash; @@ -103,11 +104,6 @@ Window::Window(Window *parent, const rect_t &rect, LvglCreate objConstruct) : if (objConstruct == nullptr) objConstruct = window_create; lvobj = objConstruct(lv_parent); - Window::setupLVGL(); -} - -void Window::setupLVGL() -{ lv_obj_set_user_data(lvobj, this); lv_obj_add_event_cb(lvobj, Window::window_event_cb, LV_EVENT_ALL, nullptr); @@ -115,7 +111,6 @@ void Window::setupLVGL() if (rect.w) lv_obj_set_width(lvobj, rect.w); if (rect.h) lv_obj_set_height(lvobj, rect.h); - // lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_OFF); lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLL_ELASTIC); if (parent) { @@ -382,7 +377,7 @@ void Window::enable(bool enabled) void Window::addBackButton() { new ButtonBase( - this, {0, 0, MENU_HEADER_HEIGHT, MENU_HEADER_HEIGHT}, + this, {0, 0, EdgeTxStyles::MENU_HEADER_HEIGHT, EdgeTxStyles::MENU_HEADER_HEIGHT}, [=]() -> uint8_t { onCancel(); return 0; @@ -439,3 +434,94 @@ NavWindow::NavWindow(Window *parent, const rect_t &rect, { setWindowFlag(OPAQUE); } + +SetupButtonGroup::SetupButtonGroup(Window* parent, const rect_t& rect, const char* title, int cols, + PaddingSize padding, PageDefs pages, coord_t btnHeight) : + Window(parent, rect) +{ + padAll(padding); + + coord_t buttonWidth = (width() - PAD_SMALL * (cols + 1) - PAD_TINY * 2) / cols; + + int rows = (pages.size() + cols - 1) / cols; + int height = rows * btnHeight + (rows - 1) * PAD_MEDIUM + PAD_TINY * 2; + if (title) { + height += EdgeTxStyles::PAGE_LINE_HEIGHT + PAD_TINY; + } + setHeight(height); + + if (title) + new Subtitle(this, title); + + int n = 0; + int remaining = pages.size(); + coord_t yo = title ? EdgeTxStyles::PAGE_LINE_HEIGHT + PAD_TINY : 0; + coord_t xw = buttonWidth + PAD_SMALL; + coord_t xo = (width() - (cols * xw - PAD_SMALL)) / 2; + coord_t x, y; + for (auto& entry : pages) { + if (remaining < cols && (n % cols == 0)) { + coord_t space = ((cols - remaining) * xw) / (remaining + 1); + xw += space; + xo += space; + } + x = xo + (n % cols) * xw; + y = yo + (n / cols) * (btnHeight + PAD_MEDIUM); + + // TODO: sort out all caps title strings VS quick menu strings + std::string title(entry.title); + for (std::string::iterator it = title.begin(); it != title.end(); ++it) { + if (*it == '\n') + *it = ' '; + } + + auto btn = new TextButton(this, rect_t{x, y, buttonWidth, btnHeight}, title, [&, entry]() { + entry.createPage(); + return 0; + }); + btn->setWrap(); + if (entry.isActive) btn->setCheckHandler([=]() { btn->check(entry.isActive()); }); + n += 1; + remaining -= 1; + } +} + +SetupLine::SetupLine(Window* parent, coord_t y, coord_t col2, PaddingSize padding, const char* title, + std::function createEdit, coord_t lblYOffset) : + Window(parent, {0, y, LCD_W - padding * 2, 0}) +{ + padAll(PAD_ZERO); + coord_t titleY = PAD_MEDIUM + 1 + lblYOffset; + coord_t titleH = EdgeTxStyles::PAGE_LINE_HEIGHT; + coord_t h = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_TINY * 2 + lblYOffset * 2; + if (createEdit) { + coord_t editY = PAD_TINY; + coord_t lblWidth = col2 - PAD_SMALL - PAD_TINY; + if (title) { + if (getTextWidth(title) >= lblWidth) { + h += PAD_MEDIUM; + titleY = 0; + titleH = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_TINY + 1; + editY = PAD_SMALL + 1; + } + new StaticText(this, {PAD_TINY, titleY, lblWidth, titleH}, title); + } + setHeight(h); + createEdit(this, col2, editY); + } else { + setHeight(h); + new StaticText(this, {0, titleY, 0, titleH}, title, COLOR_THEME_PRIMARY1 | FONT(BOLD)); + } +} + +coord_t SetupLine::showLines(Window* parent, coord_t y, coord_t col2, PaddingSize padding, SetupLineDef* setupLines, int lineCount) +{ + Window* w; + + for (int i = 0; i < lineCount; i += 1) { + w = new SetupLine(parent, y, col2, padding, setupLines[i].title, setupLines[i].createEdit); + y += w->height() + padding; + } + + return y; +} diff --git a/radio/src/thirdparty/libopenui/src/window.h b/radio/src/thirdparty/libopenui/src/window.h index 3b84ff17bbd..8f61a96caab 100644 --- a/radio/src/thirdparty/libopenui/src/window.h +++ b/radio/src/thirdparty/libopenui/src/window.h @@ -26,6 +26,7 @@ #include "bitmapbuffer.h" #include "libopenui_defines.h" #include "opentx_helpers.h" +#include "themes/etx_lv_theme.h" typedef uint32_t WindowFlags; @@ -33,14 +34,6 @@ typedef uint32_t WindowFlags; #undef OPAQUE #endif -enum PaddingSize { - PAD_ZERO = 0, - PAD_TINY = 2, - PAD_SMALL = 4, - PAD_MEDIUM = 6, - PAD_LARGE = 8 -}; - constexpr WindowFlags OPAQUE = 1u << 0u; constexpr WindowFlags NO_FOCUS = 1u << 1u; @@ -55,8 +48,6 @@ class Window Window(const rect_t &rect); Window(Window *parent, const rect_t &rect, LvglCreate objConstruct = nullptr); - virtual void setupLVGL(); - virtual ~Window(); #if defined(DEBUG_WINDOWS) @@ -91,11 +82,8 @@ class Window void setRect(rect_t value) { rect = value; - lv_obj_enable_style_refresh(false); lv_obj_set_pos(lvobj, rect.x, rect.y); lv_obj_set_size(lvobj, rect.w, rect.h); - lv_obj_enable_style_refresh(true); - lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY); } void setWidth(coord_t value) @@ -181,7 +169,7 @@ class Window virtual bool isBubblePopup() { return false; } void setFlexLayout(lv_flex_flow_t flow = LV_FLEX_FLOW_COLUMN, - lv_coord_t padding = 2, coord_t width = LV_PCT(100), + lv_coord_t padding = PAD_TINY, coord_t width = LV_PCT(100), coord_t height = LV_SIZE_CONTENT); FormLine *newLine(FlexGridLayout &layout); @@ -238,3 +226,40 @@ class NavWindow : public Window virtual bool bubbleEvents() { return true; } void onEvent(event_t event) override; }; + +struct PageButtonDef { + const char* title; + std::function createPage; + std::function isActive; + + PageButtonDef(const char* title, std::function createPage, std::function isActive = nullptr) : + title(title), createPage(std::move(createPage)), isActive(std::move(isActive)) + {} +}; + +class SetupButtonGroup : public Window +{ + public: + typedef std::list PageDefs; + + SetupButtonGroup(Window* parent, const rect_t& rect, const char* title, int cols, + PaddingSize padding, PageDefs pages, coord_t btnHeight = EdgeTxStyles::UI_ELEMENT_HEIGHT); + + protected: +}; + +struct SetupLineDef { + const char* title; + std::function createEdit; +}; + +class SetupLine : public Window +{ + public: + SetupLine(Window* parent, coord_t y, coord_t col2, PaddingSize padding, const char* title, + std::function createEdit, coord_t lblYOffset = 0); + + static coord_t showLines(Window* parent, coord_t y, coord_t col2, PaddingSize padding, SetupLineDef* setupLines, int lineCount); + + protected: +}; diff --git a/radio/src/thirdparty/libopenui/thirdparty/CMakeLists.txt b/radio/src/thirdparty/libopenui/thirdparty/CMakeLists.txt index 303deb2c809..b9750185b5a 100644 --- a/radio/src/thirdparty/libopenui/thirdparty/CMakeLists.txt +++ b/radio/src/thirdparty/libopenui/thirdparty/CMakeLists.txt @@ -20,6 +20,7 @@ set(LVGL_SOURCES_MINIMAL draw/sw/lv_draw_sw_gradient.c draw/sw/lv_draw_sw.c draw/sw/lv_draw_sw_blend.c + draw/sw/lv_draw_sw_layer.c draw/sw/lv_draw_sw_letter.c draw/sw/lv_draw_sw_arc.c draw/sw/lv_draw_sw_polygon.c @@ -27,7 +28,10 @@ set(LVGL_SOURCES_MINIMAL draw/sw/lv_draw_sw_line.c draw/sw/lv_draw_sw_dither.c draw/sw/lv_draw_sw_rect.c + draw/sw/lv_draw_sw_transform.c + draw/lv_draw_layer.c draw/lv_draw_line.c + draw/lv_draw_transform.c draw/lv_draw.c draw/lv_img_buf.c draw/lv_draw_rect.c @@ -186,5 +190,9 @@ endforeach() foreach(LVGL_FILE ${LVGL_SOURCES}) set(LVGL_SRC_FILES ${LVGL_SRC_FILES} ${LVGL_SRC_DIR}/${LVGL_FILE}) endforeach() + +foreach(LVGL_FILE ${LVGL_SRC_FILES}) + SET_SOURCE_FILES_PROPERTIES( ${LVGL_FILE} PROPERTIES COMPILE_FLAGS -O3 ) +endforeach() set(SRC ${SRC} ${LVGL_SRC_FILES}) diff --git a/radio/src/thirdparty/libopenui/thirdparty/lvgl b/radio/src/thirdparty/libopenui/thirdparty/lvgl index ca2684d58da..189c2bf5c56 160000 --- a/radio/src/thirdparty/libopenui/thirdparty/lvgl +++ b/radio/src/thirdparty/libopenui/thirdparty/lvgl @@ -1 +1 @@ -Subproject commit ca2684d58da8fb2eb3e34f63154f58962bd7a8c9 +Subproject commit 189c2bf5c56d78ac7d502ae09cc4e8744697cc3d diff --git a/radio/src/translations/cn.h b/radio/src/translations/cn.h index e24ac1a551b..354d82e5e90 100644 --- a/radio/src/translations/cn.h +++ b/radio/src/translations/cn.h @@ -296,7 +296,7 @@ #define TR_ELEVATOR TR("俯仰源", "俯仰混控源") #define TR_SWASHRING "斜盘行程" #define TR_MODE "模式" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "左摇杆" #else #define TR_LEFT_STICK "左摇杆" @@ -1151,7 +1151,7 @@ #define TR_USE_THEME_COLOR "使用主题颜色" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "将所有微调导入中点偏移值" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "打开通道监视器" #else #define TR_OPEN_CHANNEL_MONITORS "通道监视" diff --git a/radio/src/translations/cz.h b/radio/src/translations/cz.h index 6078562dd42..11046bd11d6 100644 --- a/radio/src/translations/cz.h +++ b/radio/src/translations/cz.h @@ -311,7 +311,7 @@ #define TR_ELEVATOR TR3("Podélná cykl.", "Podélná cykl.", "Podélná cyklika") #define TR_SWASHRING "Cyklika" #define TR_MODE "Mód" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Vlevo" #else #define TR_LEFT_STICK "Vlevo" @@ -1168,7 +1168,7 @@ #define TR_USE_THEME_COLOR "Použít barevný motiv" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Trimy do subtrimů" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Otevřít monitor kanálů" #else #define TR_OPEN_CHANNEL_MONITORS "Otevřít mon. kanálů" diff --git a/radio/src/translations/da.h b/radio/src/translations/da.h index 87a9d773b55..f5b1ad69d77 100644 --- a/radio/src/translations/da.h +++ b/radio/src/translations/da.h @@ -51,7 +51,7 @@ #define TR_TRNCHN "KA1","KA2","KA3","KA4" #define TR_AUX_SERIAL_MODES "FRA","Telem spejlet","Telemetri ind","SBUS træner","LUA","CLI","GPS","Debug","SpaceMouse","Eksternt modul" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_SWTYPES "Ingen", "2 pos skift","2 position","3 position" #else #define TR_SWTYPES "Ingen","Skift","2POS","3POS" @@ -304,7 +304,7 @@ #define TR_ELEVATOR TR("Long. cyc.", "Long. cyc. kilde") #define TR_SWASHRING "Swash ring" #define TR_MODE TR("Tils.","Tilstand") -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Venstre" #else #define TR_LEFT_STICK "Ven" @@ -1122,7 +1122,7 @@ #define TR_WIDGET_SETTINGS "Widget indstilinger" #define TR_REMOVE_SCREEN "Slet skærm" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_SETUP_WIDGETS "Opsæt widget" #else #define TR_SETUP_WIDGETS "Widget" @@ -1167,7 +1167,7 @@ #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Tilføj alle trim til subtrim" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Åbn kanal monitor" #else #define TR_OPEN_CHANNEL_MONITORS "Åbn kanal mon." diff --git a/radio/src/translations/de.h b/radio/src/translations/de.h index 50ed5d63620..b56a1458e3b 100644 --- a/radio/src/translations/de.h +++ b/radio/src/translations/de.h @@ -302,7 +302,7 @@ #define TR_ELEVATOR "Nick Quelle" #define TR_SWASHRING TR("Ring Begrenz", "Ring Begrenzung") #define TR_MODE "Modus" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Links" #else #define TR_LEFT_STICK "Li" @@ -1159,7 +1159,7 @@ #define TR_USE_THEME_COLOR "Farbe des Themes verwenden" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Alle Trimmungen übernehmen" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Öffne Kanalmonitor" #else #define TR_OPEN_CHANNEL_MONITORS "Öffne Kanalmon." diff --git a/radio/src/translations/en.h b/radio/src/translations/en.h index 71c1df42f81..ae192287ff8 100644 --- a/radio/src/translations/en.h +++ b/radio/src/translations/en.h @@ -301,7 +301,7 @@ #define TR_ELEVATOR TR("Long. cyc.", "Long. cyc. source") #define TR_SWASHRING "Swash Ring" #define TR_MODE "Mode" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Left" #else #define TR_LEFT_STICK "Left" @@ -1156,7 +1156,7 @@ #define TR_USE_THEME_COLOR "Use theme color" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Add all Trims to Subtrims" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Open Channel Monitor" #else #define TR_OPEN_CHANNEL_MONITORS "Open Channel Mon." diff --git a/radio/src/translations/es.h b/radio/src/translations/es.h index 84d11bc36df..869e8b70163 100644 --- a/radio/src/translations/es.h +++ b/radio/src/translations/es.h @@ -299,7 +299,7 @@ #define TR_ELEVATOR TR("Col. long. ", "Fuente col. longitudinal") #define TR_SWASHRING "Ciclico" #define TR_MODE "Modo" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Izquierdo" #else #define TR_LEFT_STICK "Izq" @@ -1156,7 +1156,7 @@ #define TR_USE_THEME_COLOR "Use theme color" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Add all Trims to Subtrims" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Open Channel Monitor" #else #define TR_OPEN_CHANNEL_MONITORS "Open Channel Mon." diff --git a/radio/src/translations/fi.h b/radio/src/translations/fi.h index ca437831c40..e5b98f49a4b 100644 --- a/radio/src/translations/fi.h +++ b/radio/src/translations/fi.h @@ -313,7 +313,7 @@ #define TR_ELEVATOR TR("Long. cyc.", "Long. cyc. source") #define TR_SWASHRING "Swash Ring" #define TR_MODE "Mode" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Vasemmalle" #else #define TR_LEFT_STICK "Va" @@ -1170,7 +1170,7 @@ #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Add all Trims to Subtrims" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Open Channel Monitor" #else #define TR_OPEN_CHANNEL_MONITORS "Open Channel Mon." diff --git a/radio/src/translations/fr.h b/radio/src/translations/fr.h index 326d07eff92..a611c494529 100644 --- a/radio/src/translations/fr.h +++ b/radio/src/translations/fr.h @@ -308,7 +308,7 @@ #define TR_ELEVATOR "Source cyc. lon." #define TR_SWASHRING TR("Limite Cycl.", "Limite du cyclique") #define TR_MODE "Mode" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Gauche" #else #define TR_LEFT_STICK "Gauche" @@ -1173,7 +1173,7 @@ #define TR_USE_THEME_COLOR "Utiliser couleur du thème" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Ajouter tous trims aux sub-trims" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Ouvrir Monit. de Canal" #else #define TR_OPEN_CHANNEL_MONITORS "Ouvrir Mon. de Canal" diff --git a/radio/src/translations/he.h b/radio/src/translations/he.h index bc9ef8cf349..5932d3d0197 100644 --- a/radio/src/translations/he.h +++ b/radio/src/translations/he.h @@ -305,7 +305,7 @@ #define TR_ELEVATOR TR("Long. cyc.", "Long. cyc. source") #define TR_SWASHRING "Swash Ring" #define TR_MODE "Mode" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Left" #else #define TR_LEFT_STICK "Left" @@ -1155,7 +1155,7 @@ #define TR_USE_THEME_COLOR "Use theme color" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "מיכרוז כל הקיזוזים" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "פתח מצג ערוצים" #else #define TR_OPEN_CHANNEL_MONITORS "פתח מצג ערוצים." diff --git a/radio/src/translations/it.h b/radio/src/translations/it.h index f566bffef64..c54b22d8211 100644 --- a/radio/src/translations/it.h +++ b/radio/src/translations/it.h @@ -301,7 +301,7 @@ #define TR_ELEVATOR TR("Cic. long.", "Sorg. cic. long.") #define TR_SWASHRING "Anello Ciclico" #define TR_MODE "Modo" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Sinistro" #else #define TR_LEFT_STICK "Sx" @@ -1150,7 +1150,7 @@ #define TR_USE_THEME_COLOR "Usa colore tema" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Agg. Trim a Subtrim" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Apri Monitor Canali" #else #define TR_OPEN_CHANNEL_MONITORS "Apri Mon. Canali" diff --git a/radio/src/translations/jp.h b/radio/src/translations/jp.h index 7ddebe9d180..2246ccaa7e9 100644 --- a/radio/src/translations/jp.h +++ b/radio/src/translations/jp.h @@ -300,7 +300,7 @@ #define TR_ELEVATOR TR("Long. cyc.", "Long. cyc. ソース") #define TR_SWASHRING "スワッシュリング" #define TR_MODE "モード" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "左スティック" #else #define TR_LEFT_STICK "左スティック" @@ -1155,7 +1155,7 @@ #define TR_USE_THEME_COLOR "テーマ色を使用" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "サブトリムにすべてのトリムを追加" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "チャンネルモニター起動" #else #define TR_OPEN_CHANNEL_MONITORS "Open Channel Mon." diff --git a/radio/src/translations/nl.h b/radio/src/translations/nl.h index cfb0991617b..80eed888830 100644 --- a/radio/src/translations/nl.h +++ b/radio/src/translations/nl.h @@ -298,7 +298,7 @@ #define TR_ELEVATOR TR("Long. cyc.", "Long. cyc. source") #define TR_SWASHRING "Swash Ring" #define TR_MODE "Mode" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Linkerkant" #else #define TR_LEFT_STICK "Li" @@ -1162,7 +1162,7 @@ #define TR_USE_THEME_COLOR "Use theme color" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Add all Trims to Subtrims" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Open Channel Monitor" #else #define TR_OPEN_CHANNEL_MONITORS "Open Channel Mon." diff --git a/radio/src/translations/pl.h b/radio/src/translations/pl.h index 3b6f9bc52f4..72f153f6d24 100644 --- a/radio/src/translations/pl.h +++ b/radio/src/translations/pl.h @@ -298,7 +298,7 @@ #define TR_ELEVATOR TR("Long. cyc.", "Long. cyc. source") #define TR_SWASHRING "Tarcza " #define TR_MODE "Tryb" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Lewy" #else #define TR_LEFT_STICK "Lewy" @@ -1155,7 +1155,7 @@ #define TR_USE_THEME_COLOR "Użyj koloru szablonu" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Dodaj trymy do podtrymów" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Otwórz Monitor kanałów" #else #define TR_OPEN_CHANNEL_MONITORS "Otwórz Mon. kanałów" diff --git a/radio/src/translations/pt.h b/radio/src/translations/pt.h index 0eb4042acc5..178243b1058 100644 --- a/radio/src/translations/pt.h +++ b/radio/src/translations/pt.h @@ -304,7 +304,7 @@ #define TR_ELEVATOR TR("Arfagem", "Org. cíclico Arfagem") #define TR_SWASHRING "Swash Ring" #define TR_MODE "Modo" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Esq" #else #define TR_LEFT_STICK "Esq" @@ -1159,7 +1159,7 @@ #define TR_USE_THEME_COLOR "Use theme color" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Add all Trims to Subtrims" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Open Channel Monitor" #else #define TR_OPEN_CHANNEL_MONITORS "Open Channel Mon." diff --git a/radio/src/translations/ru.h b/radio/src/translations/ru.h index 139ccf93a8a..08df4c71880 100644 --- a/radio/src/translations/ru.h +++ b/radio/src/translations/ru.h @@ -303,7 +303,7 @@ #define TR_ELEVATOR TR("Тангаж", "Тангаж") #define TR_SWASHRING "Поворот" #define TR_MODE "Режим" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Лев" #else #define TR_LEFT_STICK "Лев" @@ -1158,7 +1158,7 @@ #define TR_USE_THEME_COLOR "Используйте цвет темы" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Добав все трим в субтрим" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Монитор откр кан" #else #define TR_OPEN_CHANNEL_MONITORS "Мон открыт кан" diff --git a/radio/src/translations/se.h b/radio/src/translations/se.h index d307bcc0267..ad0ae0bb77d 100644 --- a/radio/src/translations/se.h +++ b/radio/src/translations/se.h @@ -55,7 +55,7 @@ #define TR_TRNCHN "KA1","KA2","KA3","KA4" #define TR_AUX_SERIAL_MODES "AV","Speglad telemetri","Telemetri in","SBUS Lärare","LUA","CLI","GPS","Debug","SpaceMouse","Extern modul" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_SWTYPES "Ingen", "2 pos flipp","2 pos","3 pos" #else #define TR_SWTYPES "Ingen","Flipp","2 pos","3 pos" @@ -314,7 +314,7 @@ #define TR_ELEVATOR "Höjdroderkälla" #define TR_SWASHRING "Swashring" #define TR_MODE "Typ" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Vänster" #else #define TR_LEFT_STICK "Vä" @@ -1150,7 +1150,7 @@ #define TR_WIDGET_FULLSCREEN "Hel skärm" #define TR_REMOVE_SCREEN "Ta bort huvudvy" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_SETUP_WIDGETS "Konfigurera widgets" #else #define TR_SETUP_WIDGETS "Konfig. widgets" @@ -1191,7 +1191,7 @@ #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Addera alla trimmar till subtrimmar" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Öppna kanalmonitorn" #else #define TR_OPEN_CHANNEL_MONITORS "Öppna kanalmon." diff --git a/radio/src/translations/tw.h b/radio/src/translations/tw.h index bb125e95a81..171b8bfc18e 100644 --- a/radio/src/translations/tw.h +++ b/radio/src/translations/tw.h @@ -301,7 +301,7 @@ #define TR_ELEVATOR TR("俯仰源", "俯仰混控源") #define TR_SWASHRING "斜盤行程" #define TR_MODE "模式" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "左搖桿" #else #define TR_LEFT_STICK "左搖桿" @@ -1156,7 +1156,7 @@ #define TR_USE_THEME_COLOR "使用主題顏色" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "將所有微調導入中點偏移值" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "打開通道監視器" #else #define TR_OPEN_CHANNEL_MONITORS "通道監視" diff --git a/radio/src/translations/ua.h b/radio/src/translations/ua.h index eb31dcfc78e..c7bb683a493 100644 --- a/radio/src/translations/ua.h +++ b/radio/src/translations/ua.h @@ -303,7 +303,7 @@ #define TR_ELEVATOR TR("Тангаж", "Тангаж") #define TR_SWASHRING "Поворот" #define TR_MODE "Режим" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_LEFT_STICK "Ліво" #else #define TR_LEFT_STICK "Ліво" @@ -1158,7 +1158,7 @@ #define TR_USE_THEME_COLOR "Використ. колір теми" #define TR_ADD_ALL_TRIMS_TO_SUBTRIMS "Додати всі трими до субтримів" -#if LCD_W > LCD_H +#if !PORTRAIT_LCD #define TR_OPEN_CHANNEL_MONITORS "Відкрити монітори каналів" #else #define TR_OPEN_CHANNEL_MONITORS "Відкр. мон.кан."