diff --git a/cmake/Macros.cmake b/cmake/Macros.cmake index 683e96a53..abd851d73 100644 --- a/cmake/Macros.cmake +++ b/cmake/Macros.cmake @@ -120,15 +120,17 @@ function(AddHWGenTarget input template output) # Inputs set(INPUT_JSON ${CMAKE_CURRENT_BINARY_DIR}/${input}) set(TEMPLATE ${RADIO_DIRECTORY}/util/hw_defs/${template}.jinja) - set(LEGACY_JSON ${RADIO_DIRECTORY}/util/hw_defs/legacy_names.py) + set(GEN_PY_DEPS + ${RADIO_DIRECTORY}/util/hw_defs/generator.py + ${RADIO_DIRECTORY}/util/hw_defs/legacy_names.py + ) # Command set(GEN_JSON ${GEN_JSON} -t ${TEMPLATE} -T ${FLAVOUR} ${INPUT_JSON}) add_custom_command(OUTPUT ${output} COMMAND ${GEN_JSON} > ${output} - DEPENDS ${INPUT_JSON} ${LEGACY_JSON} ${TEMPLATE} - ) + DEPENDS ${INPUT_JSON} ${TEMPLATE} ${GEN_PY_DEPS}) endfunction() macro(AddHeadersSources) diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index 2202c7fd2..23f8cde46 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -71,8 +71,6 @@ set(GUI_SRC gvar_numberedit.cpp input_edit_adv.cpp input_edit.cpp - input_mix_button.cpp - input_mix_group.cpp input_source.cpp mixer_edit_adv.cpp mixer_edit.cpp diff --git a/radio/src/gui/colorlcd/input_mix_button.cpp b/radio/src/gui/colorlcd/input_mix_button.cpp deleted file mode 100644 index 642602c7b..000000000 --- a/radio/src/gui/colorlcd/input_mix_button.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "input_mix_button.h" -#include "opentx.h" -#include "bitmaps.h" - -// total: 92 x 17 -#define FM_CANVAS_HEIGHT 17 -#define FM_CANVAS_WIDTH 92 - -#if LCD_W > LCD_H // Landscape -static const lv_coord_t col_dsc[] = { - LV_GRID_FR(7), // weight - LV_GRID_FR(12), // source - LV_GRID_FR(29), // opts - FM_CANVAS_WIDTH, // flight modes - LV_GRID_TEMPLATE_LAST -}; - -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; -#else // Portrait -static const lv_coord_t col_dsc[] = { - LV_GRID_FR(13), // weight - LV_GRID_FR(21), // source - LV_GRID_FR(32), // opts - LV_GRID_TEMPLATE_LAST -}; - -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, - LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; -#endif - -InputMixButton::InputMixButton(Window* parent, uint8_t index) : - ListLineButton(parent, index) -{ - lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); - lv_obj_set_grid_dsc_array(lvobj, col_dsc, row_dsc); - - weight = lv_label_create(lvobj); - lv_obj_set_grid_cell(weight, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 0, 1); - - source = lv_label_create(lvobj); - lv_obj_set_grid_cell(source, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_START, 0, 1); - - opts = lv_label_create(lvobj); -#if LCD_W > LCD_H // Landscape - lv_obj_set_grid_cell(opts, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_START, 0, 1); -#else - lv_obj_set_grid_cell(opts, LV_GRID_ALIGN_STRETCH, 2, 1, LV_GRID_ALIGN_START, 0, 2); -#endif -} - -InputMixButton::~InputMixButton() -{ - if (fm_buffer) free(fm_buffer); -} - -void InputMixButton::setWeight(gvar_t value, gvar_t min, gvar_t max) -{ - char s[32]; - getValueOrGVarString(s, sizeof(s), value, min, max, 0, "%"); - lv_label_set_text(weight, s); -} - -void InputMixButton::setSource(mixsrc_t idx) -{ - char* s = getSourceString(idx); - lv_label_set_text(source, s); -} - -void InputMixButton::setFlightModes(uint16_t modes) -{ - if (!modelFMEnabled()) return; - if (modes == fm_modes) return; - fm_modes = modes; - - if (!fm_modes) { - if (!fm_canvas) return; - lv_obj_del(fm_canvas); - free(fm_buffer); - fm_canvas = nullptr; - fm_buffer = nullptr; - return; - } - - if (!fm_canvas) { - fm_canvas = lv_canvas_create(lvobj); - fm_buffer = malloc(FM_CANVAS_WIDTH * FM_CANVAS_HEIGHT); - lv_canvas_set_buffer(fm_canvas, fm_buffer, FM_CANVAS_WIDTH, - FM_CANVAS_HEIGHT, LV_IMG_CF_ALPHA_8BIT); - -#if LCD_W > LCD_H // Landscape - lv_obj_set_grid_cell(fm_canvas, LV_GRID_ALIGN_START, 3, 1, - LV_GRID_ALIGN_CENTER, 0, 1); -#else - lv_obj_set_grid_cell(fm_canvas, LV_GRID_ALIGN_CENTER, 0, 2, - LV_GRID_ALIGN_CENTER, 1, 1); -#endif - - lv_obj_set_style_img_recolor(fm_canvas, makeLvColor(COLOR_THEME_SECONDARY1), 0); - lv_obj_set_style_img_recolor_opa(fm_canvas, LV_OPA_COVER, 0); - } - - lv_canvas_fill_bg(fm_canvas, lv_color_black(), LV_OPA_TRANSP); - - const MaskBitmap* mask = getBuiltinIcon(ICON_TEXTLINE_FM); - lv_coord_t w = mask->width; - lv_coord_t h = mask->height; - - coord_t x = 0; - lv_canvas_copy_buf(fm_canvas, mask->data, x, 0, w, h); - x += 20; - - lv_draw_label_dsc_t label_dsc; - lv_draw_label_dsc_init(&label_dsc); - - lv_draw_rect_dsc_t rect_dsc; - lv_draw_rect_dsc_init(&rect_dsc); - rect_dsc.bg_opa = LV_OPA_COVER; - - const lv_font_t* font = getFont(FONT(XS)); - label_dsc.font = font; - - for (int i = 0; i < MAX_FLIGHT_MODES; i++) { - char s[] = " "; - s[0] = '0' + i; - 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); - label_dsc.color = lv_color_white(); - } - lv_canvas_draw_text(fm_canvas, x, 0, 8, &label_dsc, s); - x += 8; - } -} diff --git a/radio/src/gui/colorlcd/input_mix_button.h b/radio/src/gui/colorlcd/input_mix_button.h deleted file mode 100644 index f30964810..000000000 --- a/radio/src/gui/colorlcd/input_mix_button.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#pragma once - -#include "list_line_button.h" -#include "opentx_types.h" - -class InputMixButton : public ListLineButton -{ - public: - InputMixButton(Window* parent, uint8_t index); - ~InputMixButton(); - - protected: - lv_obj_t* fm_canvas = nullptr; - void* fm_buffer = nullptr; - uint16_t fm_modes = 0; - - lv_obj_t* weight; - lv_obj_t* source; - lv_obj_t* opts; - - void setWeight(gvar_t value, gvar_t min, gvar_t max); - void setSource(mixsrc_t idx); - void setFlightModes(uint16_t modes); -}; diff --git a/radio/src/gui/colorlcd/input_mix_group.cpp b/radio/src/gui/colorlcd/input_mix_group.cpp deleted file mode 100644 index cda4eb01e..000000000 --- a/radio/src/gui/colorlcd/input_mix_group.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "input_mix_group.h" - -#include - -#include "opentx.h" -#include "themes/etx_lv_theme.h" - -static void input_mix_group_constructor(const lv_obj_class_t* class_p, - lv_obj_t* obj) -{ - etx_std_style(obj, LV_PART_MAIN, PAD_TINY); -} - -static const lv_obj_class_t input_mix_group_class = { - .base_class = &lv_obj_class, - .constructor_cb = input_mix_group_constructor, - .destructor_cb = nullptr, - .user_data = nullptr, - .event_cb = nullptr, - .width_def = LV_PCT(100), - .height_def = LV_SIZE_CONTENT, - .editable = LV_OBJ_CLASS_EDITABLE_FALSE, - .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, - .instance_size = sizeof(lv_obj_t), -}; - -static lv_obj_t* input_mix_group_create(lv_obj_t* parent) -{ - return etx_create(&input_mix_group_class, parent); -} - -static const lv_coord_t col_dsc[] = { - 71, - LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST, -}; - -static const lv_coord_t row_dsc[] = { - LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST, -}; - -InputMixGroupBase::InputMixGroupBase(Window* parent, mixsrc_t idx, - const lv_coord_t* gridCols) : - Window(parent, rect_t{}, input_mix_group_create), idx(idx) -{ - setWindowFlag(NO_FOCUS); - - lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE); - padAll(PAD_ZERO); - - if (!gridCols) gridCols = col_dsc; - lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); - lv_obj_set_grid_dsc_array(lvobj, gridCols, row_dsc); - - label = lv_label_create(lvobj); - etx_font(label, FONT_STD_INDEX); - lv_obj_set_style_pad_left(label, PAD_TINY, 0); - lv_obj_set_grid_cell(label, LV_GRID_ALIGN_START, 0, 1, - LV_GRID_ALIGN_CENTER, 0, 1); - refresh(); - - line_container = window_create(lvobj); - lv_obj_set_size(line_container, lv_pct(100), LV_SIZE_CONTENT); - lv_obj_set_flex_flow(line_container, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_flex_cross_place(line_container, LV_FLEX_ALIGN_END, 0); - lv_obj_set_style_pad_all(line_container, PAD_TINY, LV_PART_MAIN); - lv_obj_set_style_pad_row(line_container, PAD_TINY, LV_PART_MAIN); - lv_obj_set_grid_cell(line_container, LV_GRID_ALIGN_STRETCH, 1, 1, - LV_GRID_ALIGN_START, 0, 1); -} - -void InputMixGroupBase::refresh() -{ - lv_label_set_text(label, getSourceString(idx)); -} - -void InputMixGroupBase::addLine(Window* line) -{ - lines.emplace_back(line); - lv_obj_set_parent(line->getLvObj(), line_container); -} - -bool InputMixGroupBase::removeLine(Window* line) -{ - auto l = std::find_if(lines.begin(), lines.begin(), - [=](const Window* l) -> bool { return l == line; }); - - if (l != lines.end()) { - lines.erase(l); - return true; - } - - return false; -} - -InputMixGroupBase* InputMixPageBase::getGroupBySrc(mixsrc_t src) -{ - auto g = std::find_if( - groups.begin(), groups.end(), - [=](InputMixGroupBase* g) -> bool { return g->getMixSrc() == src; }); - - if (g != groups.end()) return *g; - - return nullptr; -} - -void InputMixPageBase::removeGroup(InputMixGroupBase* g) -{ - auto group = std::find_if(groups.begin(), groups.end(), - [=](InputMixGroupBase* lh) -> bool { return lh == g; }); - if (group != groups.end()) groups.erase(group); -} diff --git a/radio/src/gui/colorlcd/input_mix_group.h b/radio/src/gui/colorlcd/input_mix_group.h deleted file mode 100644 index 12f06d308..000000000 --- a/radio/src/gui/colorlcd/input_mix_group.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#pragma once - -#include "tabsgroup.h" -#include "opentx_types.h" - -#include - -class MixerChannelBar; - -class InputMixGroupBase : public Window -{ - public: - InputMixGroupBase(Window* parent, mixsrc_t idx, - const lv_coord_t* gridCols = nullptr); - - mixsrc_t getMixSrc() { return idx; } - size_t getLineCount() { return lines.size(); } - - void addLine(Window* line); - bool removeLine(Window* line); - - void refresh(); - - protected: - mixsrc_t idx; - std::list lines; - - lv_obj_t* label; - lv_obj_t* line_container; -}; - -class InputMixPageBase : public PageTab -{ - public: - InputMixPageBase(std::string title, EdgeTxIcon icon) : - PageTab(title, icon) {} - - protected: - Window* form = nullptr; - uint8_t _copyMode = 0; - std::list groups; - - InputMixGroupBase* getGroupBySrc(mixsrc_t src); - - void removeGroup(InputMixGroupBase* g); -}; diff --git a/radio/src/gui/colorlcd/list_line_button.cpp b/radio/src/gui/colorlcd/list_line_button.cpp index 4a6592bb3..bbd2bf2d1 100644 --- a/radio/src/gui/colorlcd/list_line_button.cpp +++ b/radio/src/gui/colorlcd/list_line_button.cpp @@ -21,6 +21,8 @@ #include "list_line_button.h" +#include + #include "opentx.h" #include "themes/etx_lv_theme.h" @@ -49,8 +51,7 @@ static lv_obj_t* input_mix_line_create(lv_obj_t* parent) } ListLineButton::ListLineButton(Window* parent, uint8_t index) : - ButtonBase(parent, rect_t{}, nullptr, input_mix_line_create), - index(index) + ButtonBase(parent, rect_t{}, nullptr, input_mix_line_create), index(index) { } @@ -59,3 +60,310 @@ void ListLineButton::checkEvents() check(isActive()); 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); + padAll(PAD_ZERO); + + weight = lv_label_create(lvobj); + lv_obj_set_pos(weight, WGT_X, WGT_Y); + lv_obj_set_size(weight, WGT_W, WGT_H); + + source = lv_label_create(lvobj); + lv_obj_set_pos(source, SRC_X, SRC_Y); + lv_obj_set_size(source, SRC_W, SRC_H); + + opts = lv_label_create(lvobj); + lv_obj_set_pos(opts, OPT_X, OPT_Y); + lv_obj_set_size(opts, OPT_W, OPT_H); +} + +InputMixButtonBase::~InputMixButtonBase() +{ + if (fm_buffer) free(fm_buffer); +} + +void InputMixButtonBase::setWeight(gvar_t value, gvar_t min, gvar_t max) +{ + char s[32]; + getValueOrGVarString(s, sizeof(s), value, min, max, 0, "%"); + lv_label_set_text(weight, s); +} + +void InputMixButtonBase::setSource(mixsrc_t idx) +{ + char* s = getSourceString(idx); + lv_label_set_text(source, s); +} + +void InputMixButtonBase::setFlightModes(uint16_t modes) +{ + if (!modelFMEnabled()) return; + if (modes == fm_modes) return; + fm_modes = modes; + + if (!fm_modes) { + if (!fm_canvas) return; + lv_obj_del(fm_canvas); + free(fm_buffer); + fm_canvas = nullptr; + fm_buffer = nullptr; +#if LCD_H > LCD_W + setHeight(BTN_H); +#endif + return; + } + + if (!fm_canvas) { + fm_canvas = lv_canvas_create(lvobj); + fm_buffer = malloc(FM_CANVAS_WIDTH * FM_CANVAS_HEIGHT); + 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); +#endif + + lv_obj_set_style_img_recolor(fm_canvas, makeLvColor(COLOR_THEME_SECONDARY1), + 0); + lv_obj_set_style_img_recolor_opa(fm_canvas, LV_OPA_COVER, 0); + } + + lv_canvas_fill_bg(fm_canvas, lv_color_black(), LV_OPA_TRANSP); + + const MaskBitmap* mask = getBuiltinIcon(ICON_TEXTLINE_FM); + lv_coord_t w = mask->width; + lv_coord_t h = mask->height; + + coord_t x = 0; + lv_canvas_copy_buf(fm_canvas, mask->data, x, 0, w, h); + x += 20; + + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + + lv_draw_rect_dsc_t rect_dsc; + lv_draw_rect_dsc_init(&rect_dsc); + rect_dsc.bg_opa = LV_OPA_COVER; + + const lv_font_t* font = getFont(FONT(XS)); + label_dsc.font = font; + + for (int i = 0; i < MAX_FLIGHT_MODES; i++) { + char s[] = " "; + s[0] = '0' + i; + 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); + label_dsc.color = lv_color_white(); + } + lv_canvas_draw_text(fm_canvas, x, 0, 8, &label_dsc, s); + x += 8; + } +} + +static void group_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) +{ + etx_std_style(obj, LV_PART_MAIN, PAD_TINY); +} + +static const lv_obj_class_t group_class = { + .base_class = &lv_obj_class, + .constructor_cb = group_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LCD_W - 12, + .height_def = LV_SIZE_CONTENT, + .editable = LV_OBJ_CLASS_EDITABLE_FALSE, + .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, + .instance_size = sizeof(lv_obj_t), +}; + +static lv_obj_t* group_create(lv_obj_t* parent) +{ + return etx_create(&group_class, parent); +} + +InputMixGroupBase::InputMixGroupBase(Window* parent, mixsrc_t idx) : + Window(parent, rect_t{}, group_create), idx(idx) +{ + setWindowFlag(NO_FOCUS); + + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE); + padAll(PAD_ZERO); + + label = lv_label_create(lvobj); + etx_font(label, FONT_STD_INDEX); +} + +void InputMixGroupBase::adjustHeight() +{ + if (getLineCount() == 0) setHeight(InputMixButtonBase::BTN_H + 8); + + coord_t y = 2; + for (auto it = lines.cbegin(); it != lines.cend(); ++it) { + auto line = *it; + line->updatePos(LN_X, y); + y += line->height() + 2; + } + setHeight(y + 4); +} + +void InputMixGroupBase::addLine(InputMixButtonBase* line) +{ + auto l = std::find_if(lines.begin(), lines.end(), + [=](const InputMixButtonBase* l) -> bool { + return line->getIndex() <= l->getIndex(); + }); + + if (l != lines.end()) + lines.insert(l, line); + else + lines.emplace_back(line); + + adjustHeight(); +} + +bool InputMixGroupBase::removeLine(InputMixButtonBase* line) +{ + auto l = std::find_if( + lines.begin(), lines.end(), + [=](const InputMixButtonBase* l) -> bool { return l == line; }); + + if (l != lines.end()) { + lines.erase(l); + adjustHeight(); + return true; + } + + return false; +} + +void InputMixGroupBase::refresh() +{ + lv_label_set_text(label, getSourceString(idx)); +} + +InputMixGroupBase* InputMixPageBase::getGroupBySrc(mixsrc_t src) +{ + auto g = std::find_if( + groups.begin(), groups.end(), + [=](InputMixGroupBase* g) -> bool { return g->getMixSrc() == src; }); + + if (g != groups.end()) return *g; + + return nullptr; +} + +void InputMixPageBase::removeGroup(InputMixGroupBase* g) +{ + auto group = std::find_if(groups.begin(), groups.end(), + [=](InputMixGroupBase* lh) -> bool { return lh == g; }); + if (group != groups.end()) groups.erase(group); +} + +InputMixButtonBase* InputMixPageBase::getLineByIndex(uint8_t index) +{ + auto l = std::find_if(lines.begin(), lines.end(), [=](InputMixButtonBase* l) { + return l->getIndex() == index; + }); + + if (l != lines.end()) return *l; + + return nullptr; +} + +void InputMixPageBase::removeLine(InputMixButtonBase* l) +{ + auto line = std::find_if(lines.begin(), lines.end(), + [=](InputMixButtonBase* lh) -> bool { return lh == l; }); + if (line == lines.end()) return; + + line = lines.erase(line); + while (line != lines.end()) { + (*line)->setIndex((*line)->getIndex() - 1); + ++line; + } +} + +void InputMixPageBase::addLineButton(mixsrc_t src, uint8_t index) +{ + InputMixGroupBase* group_w = getGroupBySrc(src); + if (!group_w) { + group_w = createGroup(form, src); + // insertion sort + groups.emplace_back(group_w); + auto g = groups.rbegin(); + if (g != groups.rend()) { + auto g_prev = g; + ++g_prev; + while (g_prev != groups.rend()) { + if ((*g_prev)->getMixSrc() < (*g)->getMixSrc()) break; + lv_obj_swap((*g)->getLvObj(), (*g_prev)->getLvObj()); + std::swap(*g, *g_prev); + ++g; + ++g_prev; + } + } + } + + // create new line button + auto btn = createLineButton(group_w, index); + lv_group_focus_obj(btn->getLvObj()); + + // insertion sort for the focus group + auto l = lines.rbegin(); + if (l != lines.rend()) { + auto l_prev = l; + ++l_prev; + while (l_prev != lines.rend()) { + if ((*l_prev)->getIndex() < (*l)->getIndex()) break; + (*l)->swapLvglGroup(*l_prev); + std::swap(*l, *l_prev); + // Inc index of elements after + (*l)->setIndex((*l)->getIndex() + 1); + ++l; + ++l_prev; + } + } +} diff --git a/radio/src/gui/colorlcd/list_line_button.h b/radio/src/gui/colorlcd/list_line_button.h index 5756e067c..6261c4ec9 100644 --- a/radio/src/gui/colorlcd/list_line_button.h +++ b/radio/src/gui/colorlcd/list_line_button.h @@ -23,6 +23,7 @@ #include "button.h" #include "opentx_types.h" +#include "tabsgroup.h" class ListLineButton : public ButtonBase { @@ -41,3 +42,77 @@ class ListLineButton : public ButtonBase virtual bool isActive() const = 0; }; + +class InputMixButtonBase : public ListLineButton +{ + public: + InputMixButtonBase(Window* parent, uint8_t index); + ~InputMixButtonBase(); + + void setWeight(gvar_t value, gvar_t min, gvar_t max); + 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; + + protected: + + lv_obj_t* fm_canvas = nullptr; + void* fm_buffer = nullptr; + uint16_t fm_modes = 0; + + lv_obj_t* weight = nullptr; + lv_obj_t* source = nullptr; + lv_obj_t* opts = nullptr; +}; + +class InputMixGroupBase : public Window +{ + public: + InputMixGroupBase(Window* parent, mixsrc_t idx); + + mixsrc_t getMixSrc() { return idx; } + size_t getLineCount() { return lines.size(); } + + void adjustHeight(); + void addLine(InputMixButtonBase* line); + bool removeLine(InputMixButtonBase* line); + + void refresh(); + + protected: + static constexpr coord_t LN_X = 73; + + mixsrc_t idx; + lv_obj_t* label; + std::list lines; +}; + +class InputMixPageBase : public PageTab +{ + public: + InputMixPageBase(const char* title, EdgeTxIcon icon) : PageTab(title, icon) {} + + protected: + std::list lines; + InputMixButtonBase* _copySrc = nullptr; + Window* form = nullptr; + uint8_t _copyMode = 0; + std::list groups; + + virtual void addLineButton(uint8_t index) = 0; + void addLineButton(mixsrc_t src, uint8_t index); + + InputMixButtonBase* getLineByIndex(uint8_t index); + InputMixGroupBase* getGroupBySrc(mixsrc_t src); + virtual InputMixGroupBase* getGroupByIndex(uint8_t index) = 0; + + virtual InputMixButtonBase* createLineButton(InputMixGroupBase* group, uint8_t index) = 0; + virtual InputMixGroupBase* createGroup(Window* form, mixsrc_t src) = 0; + + void removeLine(InputMixButtonBase* l); + void removeGroup(InputMixGroupBase* g); +}; diff --git a/radio/src/gui/colorlcd/mixer_edit_adv.cpp b/radio/src/gui/colorlcd/mixer_edit_adv.cpp index e6bfb4d7a..f14714145 100644 --- a/radio/src/gui/colorlcd/mixer_edit_adv.cpp +++ b/radio/src/gui/colorlcd/mixer_edit_adv.cpp @@ -46,7 +46,7 @@ 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}; #else -static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), +static const lv_coord_t col_dsc[] = {LV_GRID_FR(12), LV_GRID_FR(13), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; diff --git a/radio/src/gui/colorlcd/model_flightmodes.cpp b/radio/src/gui/colorlcd/model_flightmodes.cpp index 7c863bbfa..531c7ce02 100644 --- a/radio/src/gui/colorlcd/model_flightmodes.cpp +++ b/radio/src/gui/colorlcd/model_flightmodes.cpp @@ -200,75 +200,42 @@ class FlightModeEdit : public Page #if LCD_W > LCD_H // Landscape #define BTN_H 36 -#define TRIM_W 30 #define FMID_W 36 #define NAME_W 95 -#define SWTCH_W 50 -#define FADE_W 45 -#define TRIMC_W 180 -#define FMID_TOP 6 -#define LBL_TOP 6 +#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 58 -#define TRIM_W 40 +#define BTN_H 56 #define FMID_W 46 #define NAME_W 160 -#define SWTCH_W 50 -#define FADE_W 45 -#define TRIMC_W 160 -#define FMID_TOP 24 -#define LBL_TOP 0 +#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 -static void fm_group_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) -{ - etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); - lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW_WRAP); - lv_obj_set_style_flex_grow(obj, 2, LV_PART_MAIN); - lv_obj_set_height(obj, LV_SIZE_CONTENT); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); - lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, - LV_FLEX_ALIGN_SPACE_AROUND); -} - -static const lv_obj_class_t fm_group_class = { - .base_class = &lv_obj_class, - .constructor_cb = fm_group_constructor, - .destructor_cb = nullptr, - .user_data = nullptr, - .event_cb = nullptr, - .width_def = LCD_W - 12, - .height_def = BTN_H, - .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, - .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, - .instance_size = sizeof(lv_obj_t), -}; - -static void fm_trims_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) -{ - etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); -} - -static const lv_obj_class_t fm_trims_class = { - .base_class = &lv_obj_class, - .constructor_cb = fm_trims_constructor, - .destructor_cb = nullptr, - .user_data = nullptr, - .event_cb = nullptr, - .width_def = TRIMC_W, - .height_def = 32, - .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, - .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, - .instance_size = sizeof(lv_obj_t), -}; +#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->pad_left_2, LV_PART_MAIN); etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); } @@ -385,11 +352,8 @@ class FlightModeBtn : public ListLineButton FlightModeBtn(Window* parent, int index) : ListLineButton(parent, index) { padAll(PAD_ZERO); - padColumn(PAD_SMALL); + padColumn(PAD_ZERO); setHeight(BTN_H); - 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); check(isActive()); @@ -413,27 +377,27 @@ class FlightModeBtn : public ListLineButton init = true; fmID = etx_create(&fm_id_class, lvobj); + lv_obj_set_pos(fmID, FMID_X, FMID_Y); char label[8]; getFlightModeString(label, index + 1); lv_label_set_text(fmID, label); - lv_obj_t* container = etx_create(&fm_group_class, lvobj); + fmName = etx_create(&fm_name_class, lvobj); + lv_obj_set_pos(fmName, NAME_X, NAME_Y); + fmSwitch = etx_create(&fm_switch_class, lvobj); + lv_obj_set_pos(fmSwitch, SWTCH_X, SWTCH_Y); - fmName = etx_create(&fm_name_class, container); - fmSwitch = etx_create(&fm_switch_class, container); - - lv_obj_t* trims_cont = etx_create(&fm_trims_class, container); - - for (int i = 0; i < keysGetMaxTrims(); i += 1) { - fmTrimMode[i] = etx_create(&fm_trim_mode_class, trims_cont); - lv_obj_set_pos(fmTrimMode[i], i * TRIM_W, 0); - fmTrimValue[i] = etx_create(&fm_trim_value_class, trims_cont); - lv_obj_set_pos(fmTrimValue[i], i * TRIM_W, 16); + for (int i = 0; i < keysGetMaxTrims() && i < MAX_FMTRIMS; i += 1) { + 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); } - fmFadeIn = etx_create(&fm_fade_class, container); - fmFadeOut = etx_create(&fm_fade_class, container); - + fmFadeIn = etx_create(&fm_fade_class, lvobj); + lv_obj_set_pos(fmFadeIn, FADE_X, FADE_Y); + fmFadeOut = etx_create(&fm_fade_class, lvobj); + lv_obj_set_pos(fmFadeOut, FADE_X + FADE_W + 1, FADE_Y); lv_obj_update_layout(lvobj); } @@ -511,11 +475,11 @@ class FlightModeBtn : public ListLineButton lv_obj_t* fmID = nullptr; lv_obj_t* fmName = nullptr; lv_obj_t* fmSwitch = nullptr; - lv_obj_t* fmTrimMode[MAX_TRIMS] = {nullptr}; - lv_obj_t* fmTrimValue[MAX_TRIMS] = {nullptr}; + lv_obj_t* fmTrimMode[MAX_FMTRIMS] = {nullptr}; + lv_obj_t* fmTrimValue[MAX_FMTRIMS] = {nullptr}; lv_obj_t* fmFadeIn = nullptr; lv_obj_t* fmFadeOut = nullptr; - int lastTrim[MAX_TRIMS]; + int lastTrim[MAX_FMTRIMS]; }; ModelFlightModesPage::ModelFlightModesPage() : @@ -530,10 +494,14 @@ static const lv_coord_t fmt_row_dsc[] = {LV_GRID_CONTENT, void ModelFlightModesPage::build(Window* form) { - form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_SMALL); + form->padAll(PAD_ZERO); + form->padBottom(PAD_LARGE); 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); + btn->setPressHandler([=]() { new FlightModeEdit(i); return 0; @@ -541,7 +509,7 @@ void ModelFlightModesPage::build(Window* form) } trimCheck = new TextButton( - form, rect_t{0, 0, lv_pct(100), 40}, STR_CHECKTRIMS, [&]() -> uint8_t { + form, rect_t{6, MAX_FLIGHT_MODES * (BTN_H + 3) + 8, LCD_W - 12, 40}, STR_CHECKTRIMS, [&]() -> uint8_t { if (trimsCheckTimer) trimsCheckTimer = 0; else diff --git a/radio/src/gui/colorlcd/model_gvars.cpp b/radio/src/gui/colorlcd/model_gvars.cpp index bb886aaf8..24fd71866 100644 --- a/radio/src/gui/colorlcd/model_gvars.cpp +++ b/radio/src/gui/colorlcd/model_gvars.cpp @@ -30,18 +30,16 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -#define GVAR_NAME_SIZE 44 +#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 -#define GVAR_H GVAR_VAL_H #else -#define BTN_H 72 +#define BTN_H (modelFMEnabled() ? 72 : 38) #define GVAR_VAL_W 50 #define GVAR_COLS 5 -#define GVAR_H (GVAR_VAL_H * 2) #endif #define ETX_STATE_VALUE_SMALL_FONT LV_STATE_USER_1 @@ -59,122 +57,11 @@ void getFMExtName(char* dest, int8_t idx) } } -class GVarStyle -{ - public: - GVarStyle() {} - - void init() - { - if (!styleInitDone) { - styleInitDone = true; - - lv_style_init(&gvLabelStyle); - lv_style_init(&gvNameStyle); - } - - // Update in case FM state changed - lv_style_set_width(&gvNameStyle, - modelFMEnabled() ? GVAR_NAME_SIZE : GVAR_NAME_SIZE * 2); - lv_style_set_height(&gvLabelStyle, modelFMEnabled() ? PAGE_LINE_HEIGHT - 6 - : PAGE_LINE_HEIGHT); - } - - lv_obj_t* newFMCont(lv_obj_t* parent, uint8_t flightMode); - lv_obj_t* newName(lv_obj_t* parent, const char* name); - lv_obj_t* newLabel(lv_obj_t* parent, const char* label); - - lv_style_t gvNameStyle; - lv_style_t gvLabelStyle; - - private: - bool styleInitDone; -}; - -static GVarStyle gvarStyle; - -static void gv_group_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) -{ - etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); -} - -static const lv_obj_class_t gv_group_class = { - .base_class = &lv_obj_class, - .constructor_cb = gv_group_constructor, - .destructor_cb = nullptr, - .user_data = nullptr, - .event_cb = nullptr, - .width_def = GVAR_VAL_W * GVAR_COLS, - .height_def = GVAR_H, - .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, - .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, - .instance_size = sizeof(lv_obj_t), -}; - -static void gv_fmcont_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) -{ - etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); - etx_std_ctrl_colors(obj, LV_PART_MAIN); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); -} - -static const lv_obj_class_t gv_fmcont_class = { - .base_class = &lv_obj_class, - .constructor_cb = gv_fmcont_constructor, - .destructor_cb = nullptr, - .user_data = nullptr, - .event_cb = nullptr, - .width_def = GVAR_VAL_W, - .height_def = GVAR_VAL_H, - .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, - .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, - .instance_size = sizeof(lv_obj_t), -}; - -lv_obj_t* GVarStyle::newFMCont(lv_obj_t* parent, uint8_t flightMode) -{ - auto obj = etx_create(&gv_fmcont_class, parent); - lv_obj_set_pos(obj, (flightMode % GVAR_COLS) * GVAR_VAL_W, - (flightMode / GVAR_COLS) * GVAR_VAL_H); - - return obj; -} - -static void gv_name_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) -{ - etx_obj_add_style(obj, styles->pad_left_2, LV_PART_MAIN); - etx_obj_add_style(obj, styles->text_align_left, LV_PART_MAIN); - etx_obj_add_style(obj, gvarStyle.gvNameStyle, LV_PART_MAIN); -} - -static const lv_obj_class_t gv_name_class = { - .base_class = &lv_label_class, - .constructor_cb = gv_name_constructor, - .destructor_cb = nullptr, - .user_data = nullptr, - .event_cb = nullptr, - .width_def = GVAR_NAME_SIZE, - .height_def = PAGE_LINE_HEIGHT, - .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, - .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, - .instance_size = sizeof(lv_label_t), -}; - -lv_obj_t* GVarStyle::newName(lv_obj_t* parent, const char* name) -{ - auto obj = etx_create(&gv_name_class, parent); - lv_label_set_text(obj, name); - - return obj; -} - static void gv_label_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) { etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); etx_font(obj, FONT_XS_INDEX); - etx_obj_add_style(obj, gvarStyle.gvLabelStyle, LV_PART_MAIN); - lv_obj_set_pos(obj, 0, 0); + etx_solid_bg(obj, COLOR_THEME_ACTIVE_INDEX, LV_STATE_CHECKED); } static const lv_obj_class_t gv_label_class = { @@ -190,19 +77,11 @@ static const lv_obj_class_t gv_label_class = { .instance_size = sizeof(lv_label_t), }; -lv_obj_t* GVarStyle::newLabel(lv_obj_t* parent, const char* label) -{ - auto obj = etx_create(&gv_label_class, parent); - lv_label_set_text(obj, label); - - return obj; -} - static void gv_value_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) { etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); etx_font(obj, FONT_XS_INDEX, LV_PART_MAIN | ETX_STATE_VALUE_SMALL_FONT); - lv_obj_set_pos(obj, 0, PAGE_LINE_HEIGHT - 6); + etx_solid_bg(obj, COLOR_THEME_ACTIVE_INDEX, LV_STATE_CHECKED); } static const lv_obj_class_t gv_value_class = { @@ -225,12 +104,7 @@ class GVarButton : public ListLineButton ListLineButton(parent, gvar) { padAll(PAD_ZERO); - padColumn(PAD_MEDIUM); setHeight(BTN_H); - lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); - lv_obj_set_flex_align( - lvobj, !modelFMEnabled() ? LV_FLEX_ALIGN_CENTER : LV_FLEX_ALIGN_START, - LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND); if (!modelFMEnabled()) padLeft(8); lv_obj_add_event_cb(lvobj, GVarButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, @@ -241,13 +115,13 @@ class GVarButton : public ListLineButton { lv_obj_t* target = lv_event_get_target(e); auto line = (GVarButton*)lv_obj_get_user_data(target); - if (line) line->build(e); + if (line) line->build(); } protected: bool init = false; - uint8_t currentFlightMode = 0; // used for invalidation - lv_obj_t* fmCont[MAX_FLIGHT_MODES]; + 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]; @@ -260,8 +134,10 @@ class GVarButton : public ListLineButton if (modelFMEnabled()) { uint8_t newFM = getFlightMode(); if (currentFlightMode != newFM) { - lv_obj_add_state(fmCont[newFM], LV_STATE_CHECKED); - lv_obj_clear_state(fmCont[currentFlightMode], LV_STATE_CHECKED); + 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; } @@ -276,46 +152,49 @@ class GVarButton : public ListLineButton } } - void build(lv_event_t* e) + void build() { if (init) return; + init =true; + currentFlightMode = getFlightMode(); - gvarStyle.newName(lvobj, getGVarString(index)); + 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); if (modelFMEnabled()) { - auto container = etx_create(&gv_group_class, lvobj); + char label[16] = {}; for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { - fmCont[flightMode] = gvarStyle.newFMCont(container, flightMode); - if (flightMode == currentFlightMode) { - lv_obj_add_state(fmCont[flightMode], LV_STATE_CHECKED); - } - - char label[16] = {}; getFlightModeString(label, flightMode + 1); - gvarStyle.newLabel(fmCont[flightMode], label); - valueTexts[flightMode] = - etx_create(&gv_value_class, fmCont[flightMode]); + 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); + + 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); updateValueText(0); } - init =true; - lv_obj_update_layout(lvobj); - - if (e) { - auto param = lv_event_get_param(e); - lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param); - } } void updateValueText(uint8_t flightMode) @@ -591,7 +470,6 @@ class GVarEditWindow : public Page ModelGVarsPage::ModelGVarsPage() : PageTab(STR_MENU_GLOBAL_VARS, ICON_MODEL_GVARS) { - gvarStyle.init(); } void ModelGVarsPage::rebuild(Window* window) diff --git a/radio/src/gui/colorlcd/model_inputs.cpp b/radio/src/gui/colorlcd/model_inputs.cpp index 0ff0c3e71..688262b4c 100644 --- a/radio/src/gui/colorlcd/model_inputs.cpp +++ b/radio/src/gui/colorlcd/model_inputs.cpp @@ -23,15 +23,8 @@ #include -#include "choice.h" -#include "gvar_numberedit.h" #include "hal/adc_driver.h" #include "input_edit.h" -#include "input_mapping.h" -#include "input_mix_button.h" -#include "input_mix_group.h" -#include "libopenui.h" -#include "model_curves.h" #include "opentx.h" #include "tasks/mixer_task.h" @@ -104,10 +97,14 @@ void insertExpo(uint8_t idx, uint8_t input) storageDirty(EE_MODEL); } -class InputLineButton : public InputMixButton +class InputLineButton : public InputMixButtonBase { public: - using InputMixButton::InputMixButton; + InputLineButton(Window* parent, uint8_t index) : + InputMixButtonBase(parent, index) + { + check(isActive()); + } void refresh() override { @@ -159,10 +156,45 @@ class InputLineButton : public InputMixButton setFlightModes(line.flightModes); } + void updatePos(coord_t x, coord_t y) override + { + setPos(x, y); + } + + void swapLvglGroup(InputMixButtonBase* line2) override + { + InputLineButton* swapWith = (InputLineButton*)line2; + + // Swap elements (focus + line list) + lv_obj_t* obj1 = getLvObj(); + lv_obj_t* obj2 = swapWith->getLvObj(); + if (lv_obj_get_parent(obj1) == lv_obj_get_parent(obj2)) { + // same input group: swap obj + focus group + lv_obj_swap(obj1, obj2); + } else { + // different input group: swap only focus group + lv_group_swap_obj(obj1, obj2); + } + } + protected: bool isActive() const override { return isExpoActive(index); } }; +class InputGroup : public InputMixGroupBase +{ + public: + InputGroup(Window* parent, mixsrc_t idx) : + InputMixGroupBase(parent, idx) + { + adjustHeight(); + + lv_obj_set_pos(label, 2, 4); + + refresh(); + } +}; + ModelInputsPage::ModelInputsPage() : InputMixPageBase(STR_MENUINPUTS, ICON_MODEL_INPUTS) { } @@ -176,45 +208,21 @@ bool ModelInputsPage::reachExposLimit() return false; } -InputGroup* ModelInputsPage::getGroupByIndex(uint8_t index) +InputMixGroupBase* ModelInputsPage::getGroupByIndex(uint8_t index) { ExpoData* expo = expoAddress(index); if (!EXPO_VALID(expo)) return nullptr; int input = expo->chn; - return (InputGroup*)getGroupBySrc(MIXSRC_FIRST_INPUT + input); + return getGroupBySrc(MIXSRC_FIRST_INPUT + input); } -InputMixButton* ModelInputsPage::getLineByIndex(uint8_t index) -{ - auto l = std::find_if(lines.begin(), lines.end(), [=](InputMixButton* l) { - return l->getIndex() == index; - }); - - if (l != lines.end()) return *l; - - return nullptr; -} - -void ModelInputsPage::removeLine(InputMixButton* l) -{ - auto line = std::find_if(lines.begin(), lines.end(), - [=](InputMixButton* lh) -> bool { return lh == l; }); - if (line == lines.end()) return; - - line = lines.erase(line); - while (line != lines.end()) { - (*line)->setIndex((*line)->getIndex() - 1); - ++line; - } -} - -InputGroup* ModelInputsPage::createGroup(Window* form, mixsrc_t src) +InputMixGroupBase* ModelInputsPage::createGroup(Window* form, mixsrc_t src) { return new InputGroup(form, src); } -InputMixButton* ModelInputsPage::createLineButton(InputGroup* group, +InputMixButtonBase* ModelInputsPage::createLineButton(InputMixGroupBase* group, uint8_t index) { auto button = new InputLineButton(group, index); @@ -274,58 +282,7 @@ void ModelInputsPage::addLineButton(uint8_t index) if (!EXPO_VALID(expo)) return; int input = expo->chn; - addLineButton(MIXSRC_FIRST_INPUT + input, index); -} - -void ModelInputsPage::addLineButton(mixsrc_t src, uint8_t index) -{ - InputGroup* group_w = (InputGroup*)getGroupBySrc(src); - if (!group_w) { - group_w = createGroup(form, src); - // insertion sort - groups.emplace_back(group_w); - auto g = groups.rbegin(); - if (g != groups.rend()) { - auto g_prev = g; - ++g_prev; - while (g_prev != groups.rend()) { - if ((*g_prev)->getMixSrc() < (*g)->getMixSrc()) break; - lv_obj_swap((*g)->getLvObj(), (*g_prev)->getLvObj()); - std::swap(*g, *g_prev); - ++g; - ++g_prev; - } - } - } - - // create new line button - auto btn = createLineButton(group_w, index); - lv_group_focus_obj(btn->getLvObj()); - - // insertion sort for the focus group - auto l = lines.rbegin(); - if (l != lines.rend()) { - auto l_prev = l; - ++l_prev; - while (l_prev != lines.rend()) { - if ((*l_prev)->getIndex() < (*l)->getIndex()) break; - // Swap elements (focus + line list) - lv_obj_t* obj1 = (*l)->getLvObj(); - lv_obj_t* obj2 = (*l_prev)->getLvObj(); - if (lv_obj_get_parent(obj1) == lv_obj_get_parent(obj2)) { - // same input group: swap obj + focus group - lv_obj_swap(obj1, obj2); - } else { - // different input group: swap only focus group - lv_group_swap_obj(obj1, obj2); - } - std::swap(*l, *l_prev); - // Inc index of elements after - (*l)->setIndex((*l)->getIndex() + 1); - ++l; - ++l_prev; - } - } + InputMixPageBase::addLineButton(MIXSRC_FIRST_INPUT + input, index); } void ModelInputsPage::newInput() @@ -370,13 +327,14 @@ void ModelInputsPage::editInput(uint8_t input, uint8_t index) edit->setCloseHandler([=]() { line->refresh(); group->refresh(); + group->adjustHeight(); }); } void ModelInputsPage::insertInput(uint8_t input, uint8_t index) { ::insertExpo(index, input); - addLineButton(MIXSRC_FIRST_INPUT + input, index); + InputMixPageBase::addLineButton(MIXSRC_FIRST_INPUT + input, index); editInput(input, index); } diff --git a/radio/src/gui/colorlcd/model_inputs.h b/radio/src/gui/colorlcd/model_inputs.h index e5ce8b25e..a72359046 100644 --- a/radio/src/gui/colorlcd/model_inputs.h +++ b/radio/src/gui/colorlcd/model_inputs.h @@ -21,17 +21,8 @@ #pragma once -#include "tabsgroup.h" -#include "input_mix_group.h" - -class InputMixButton; - -class InputGroup : public InputMixGroupBase -{ - public: - InputGroup(Window* parent, mixsrc_t idx) : - InputMixGroupBase(parent, idx) {} -}; +#include "list_line_button.h" +#include class ModelInputsPage : public InputMixPageBase { @@ -41,18 +32,11 @@ class ModelInputsPage : public InputMixPageBase void build(Window *window) override; protected: - std::list lines; - InputMixButton* _copySrc = nullptr; - - InputGroup* getGroupByIndex(uint8_t index); - InputMixButton* getLineByIndex(uint8_t index); - - void removeLine(InputMixButton* l); + InputMixGroupBase* getGroupByIndex(uint8_t index) override; - void addLineButton(uint8_t index); - void addLineButton(mixsrc_t src, uint8_t index); - InputGroup* createGroup(Window* form, mixsrc_t src); - InputMixButton* createLineButton(InputGroup *group, uint8_t index); + void addLineButton(uint8_t index) override; + InputMixGroupBase* createGroup(Window* form, mixsrc_t src) override; + InputMixButtonBase* createLineButton(InputMixGroupBase *group, uint8_t index) override; void newInput(); void editInput(uint8_t input, uint8_t index); diff --git a/radio/src/gui/colorlcd/model_logical_switches.cpp b/radio/src/gui/colorlcd/model_logical_switches.cpp index 1370190e5..fefba82be 100644 --- a/radio/src/gui/colorlcd/model_logical_switches.cpp +++ b/radio/src/gui/colorlcd/model_logical_switches.cpp @@ -296,33 +296,52 @@ void getsEdgeDelayParam(char* s, LogicalSwitchData* ls) #if LCD_W > LCD_H // Landscape -static const lv_coord_t b_col_dsc[] = {30, 50, 88, 110, - 88, 40, 40, LV_GRID_TEMPLATE_LAST}; +#define LS_BUTTON_H 32 -static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; - -#define NM_ROW_CNT 1 -#define V2_COL_CNT 1 -#define ANDSW_ROW 0 -#define ANDSW_COL 4 -#define LS_BUTTON_H 34 +#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 -static const lv_coord_t b_col_dsc[] = {36, 58, 88, - 54, 54, LV_GRID_TEMPLATE_LAST}; +#define LS_BUTTON_H 44 -static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; - -#define NM_ROW_CNT 2 -#define V2_COL_CNT 2 -#define ANDSW_ROW 1 -#define ANDSW_COL 2 -#define LS_BUTTON_H 45 +#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: @@ -330,23 +349,10 @@ class LogicalSwitchButton : public ListLineButton ListLineButton(parent, lsIndex) { setHeight(LS_BUTTON_H); -#if LCD_H > LCD_W - padTop(PAD_ZERO); -#else - padTop(PAD_SMALL); -#endif - padLeft(3); - padRight(3); - lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); - lv_obj_set_grid_dsc_array(lvobj, b_col_dsc, b_row_dsc); - lv_obj_set_style_pad_row(lvobj, 0, 0); - lv_obj_set_style_pad_column(lvobj, 2, 0); + padAll(PAD_ZERO); check(isActive()); - lv_obj_update_layout(parent->getLvObj()); - if (lv_obj_is_visible(lvobj)) delayed_init(nullptr); - lv_obj_add_event_cb(lvobj, LogicalSwitchButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); } @@ -357,59 +363,52 @@ class LogicalSwitchButton : public ListLineButton auto line = (LogicalSwitchButton*)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; + lsName = lv_label_create(lvobj); etx_obj_add_style(lsName, styles->text_align_left, LV_PART_MAIN); - lv_obj_set_grid_cell(lsName, LV_GRID_ALIGN_STRETCH, 0, 1, - LV_GRID_ALIGN_CENTER, 0, NM_ROW_CNT); + lv_obj_set_pos(lsName, NM_X, NM_Y); + lv_obj_set_size(lsName, NM_W, NM_H); lsFunc = lv_label_create(lvobj); etx_obj_add_style(lsFunc, styles->text_align_left, LV_PART_MAIN); - lv_obj_set_grid_cell(lsFunc, LV_GRID_ALIGN_STRETCH, 1, 1, - LV_GRID_ALIGN_CENTER, 0, NM_ROW_CNT); + lv_obj_set_pos(lsFunc, FN_X, FN_Y); + lv_obj_set_size(lsFunc, FN_W, FN_H); lsV1 = lv_label_create(lvobj); etx_obj_add_style(lsV1, styles->text_align_center, LV_PART_MAIN); etx_font(lsV1, FONT_XS_INDEX, ETX_STATE_V1_SMALL_FONT); - lv_obj_set_grid_cell(lsV1, LV_GRID_ALIGN_STRETCH, 2, 1, - LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_pos(lsV1, V1_X, V1_Y); + lv_obj_set_size(lsV1, V1_W, V1_H); lsV2 = lv_label_create(lvobj); etx_obj_add_style(lsV2, styles->text_align_center, LV_PART_MAIN); - lv_obj_set_grid_cell(lsV2, LV_GRID_ALIGN_STRETCH, 3, V2_COL_CNT, - LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_pos(lsV2, V2_X, V2_Y); + lv_obj_set_size(lsV2, V2_W, V2_H); lsAnd = lv_label_create(lvobj); etx_obj_add_style(lsAnd, styles->text_align_center, LV_PART_MAIN); - lv_obj_set_grid_cell(lsAnd, LV_GRID_ALIGN_STRETCH, ANDSW_COL, 1, - LV_GRID_ALIGN_CENTER, ANDSW_ROW, 1); + lv_obj_set_pos(lsAnd, AND_X, AND_Y); + lv_obj_set_size(lsAnd, AND_W, AND_H); lsDuration = lv_label_create(lvobj); etx_obj_add_style(lsDuration, styles->text_align_center, LV_PART_MAIN); - lv_obj_set_grid_cell(lsDuration, LV_GRID_ALIGN_STRETCH, ANDSW_COL + 1, 1, - LV_GRID_ALIGN_CENTER, ANDSW_ROW, 1); + lv_obj_set_pos(lsDuration, DUR_X, DUR_Y); + lv_obj_set_size(lsDuration, DUR_W, DUR_H); lsDelay = lv_label_create(lvobj); etx_obj_add_style(lsDelay, styles->text_align_center, LV_PART_MAIN); - lv_obj_set_grid_cell(lsDelay, LV_GRID_ALIGN_STRETCH, ANDSW_COL + 2, 1, - LV_GRID_ALIGN_CENTER, ANDSW_ROW, 1); - - init = true; - refresh(); + lv_obj_set_pos(lsDelay, DEL_X, DEL_Y); + lv_obj_set_size(lsDelay, DEL_W, DEL_H); 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 diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index d9838bc3a..eb913d48a 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -21,8 +21,6 @@ #include "model_mixes.h" #include "opentx.h" -#include "input_mix_group.h" -#include "input_mix_button.h" #include "mixer_edit.h" #include "mixes.h" #include "channel_bar.h" @@ -31,96 +29,6 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -static const lv_coord_t col_dsc[] = { - 45, - LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST, -}; - -static const lv_coord_t col_dsc2[] = { - 26, - LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST, -}; - -static const lv_coord_t row_dsc[] = { - LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST, -}; - -MixGroup::MixGroup(Window* parent, mixsrc_t idx) : - InputMixGroupBase(parent, idx, col_dsc) -{ - lv_obj_t* chText = nullptr; - if (idx >= MIXSRC_FIRST_CH && idx <= MIXSRC_LAST_CH && - g_model.limitData[idx - MIXSRC_FIRST_CH].name[0] != '\0') { - chText = lv_label_create(lvobj); - etx_font(chText, FONT_XS_INDEX); - lv_label_set_text_fmt(chText, TR_CH "%" PRIu32, - UINT32_C(idx - MIXSRC_FIRST_CH + 1)); - lv_obj_set_style_pad_left(chText, PAD_TINY, 0); - lv_obj_set_grid_cell(chText, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_END, - 0, 1); - } - - lv_obj_set_style_pad_top(label, -1, 0); - - lv_obj_set_grid_cell(label, LV_GRID_ALIGN_START, 0, 1, - LV_GRID_ALIGN_START, 0, 1); - - lv_obj_t* outer = line_container; - lv_obj_set_style_pad_all(outer, PAD_ZERO, LV_PART_MAIN); - lv_obj_set_style_pad_row(outer, PAD_ZERO, LV_PART_MAIN); - - monitor = new MixerChannelBar(this, {0, 0, 100, 14}, idx - MIXSRC_FIRST_CH); - lv_obj_set_parent(monitor->getLvObj(), outer); - lv_obj_set_style_translate_x(monitor->getLvObj(), -6, LV_PART_MAIN); - lv_obj_set_grid_cell(monitor->getLvObj(), LV_GRID_ALIGN_END, 0, 1, LV_GRID_ALIGN_START, - 0, 1); - monitor->hide(); - - lv_obj_t* inner = window_create(outer); - lv_obj_set_size(inner, lv_pct(100), LV_SIZE_CONTENT); - lv_obj_set_layout(inner, LV_LAYOUT_GRID); - lv_obj_set_grid_dsc_array(inner, col_dsc2, row_dsc); - lv_obj_set_style_pad_all(inner, PAD_ZERO, LV_PART_MAIN); - lv_obj_set_style_pad_row(inner, PAD_ZERO, LV_PART_MAIN); - - mplex_container = window_create(inner); - lv_obj_set_size(mplex_container, lv_pct(100), LV_SIZE_CONTENT); - lv_obj_set_flex_flow(mplex_container, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_flex_cross_place(mplex_container, LV_FLEX_ALIGN_END, 0); - lv_obj_set_style_pad_ver(mplex_container, PAD_TINY, LV_PART_MAIN); - lv_obj_set_style_pad_hor(mplex_container, PAD_ZERO, LV_PART_MAIN); - lv_obj_set_style_pad_row(mplex_container, PAD_TINY, LV_PART_MAIN); - lv_obj_set_grid_cell(mplex_container, LV_GRID_ALIGN_STRETCH, 0, 1, - LV_GRID_ALIGN_START, 0, 1); - - line_container = window_create(inner); - lv_obj_set_size(line_container, lv_pct(100), LV_SIZE_CONTENT); - lv_obj_set_flex_flow(line_container, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_flex_cross_place(line_container, LV_FLEX_ALIGN_END, 0); - lv_obj_set_style_pad_all(line_container, PAD_TINY, LV_PART_MAIN); - lv_obj_set_style_pad_row(line_container, PAD_TINY, LV_PART_MAIN); - lv_obj_set_grid_cell(line_container, LV_GRID_ALIGN_STRETCH, 1, 1, - LV_GRID_ALIGN_START, 0, 1); -} - -void MixGroup::enableMixerMonitor() -{ - monitor->show(); -} - -void MixGroup::disableMixerMonitor() -{ - monitor->hide(); -} - -void MixGroup::addMPlex(Window* mplex) -{ - lv_obj_set_parent(mplex->getLvObj(), mplex_container); -} - class MPlexIcon : public Window { public: @@ -164,19 +72,20 @@ class MPlexIcon : public Window StaticIcon* icon = nullptr; }; -class MixLineButton : public InputMixButton +class MixLineButton : public InputMixButtonBase { public: MixLineButton(Window* parent, uint8_t index, MPlexIcon* mplex) : - InputMixButton(parent, index), + InputMixButtonBase(parent, index), mplex(mplex) { + check(isActive()); } void deleteLater(bool detach = true, bool trash = true) override { if (mplex) mplex->deleteLater(detach, trash); - InputMixButton::deleteLater(detach, trash); + ListLineButton::deleteLater(detach, trash); } void refresh() override @@ -220,17 +129,87 @@ class MixLineButton : public InputMixButton void setIndex(uint8_t i) override { - InputMixButton::setIndex(i); + ListLineButton::setIndex(i); mplex->setIndex(i); } + void updatePos(coord_t x, coord_t y) override + { + setPos(x, y); + mplex->setPos(x - 28, y); + mplex->show(y > BTN_H); + } + lv_obj_t* mplexLvObj() const { return mplex->getLvObj(); } + void swapLvglGroup(InputMixButtonBase* line2) override + { + MixLineButton* swapWith = (MixLineButton*)line2; + + // Swap elements (focus + line list) + lv_obj_t* obj1 = getLvObj(); + lv_obj_t* obj2 = swapWith->getLvObj(); + if (lv_obj_get_parent(obj1) == lv_obj_get_parent(obj2)) { + // same input group: swap obj + focus group + lv_obj_swap(obj1, obj2); + lv_obj_swap(mplexLvObj(), swapWith->mplexLvObj()); + } else { + // different input group: swap only focus group + lv_group_swap_obj(obj1, obj2); + lv_group_swap_obj(mplexLvObj(), swapWith->mplexLvObj()); + } + } + protected: MPlexIcon* mplex = nullptr; + bool isActive() const override { return isMixActive(index); } }; +class MixGroup : public InputMixGroupBase +{ + public: + MixGroup(Window* parent, mixsrc_t idx) : + InputMixGroupBase(parent, idx) + { + adjustHeight(); + + lv_obj_set_pos(label, 2, -1); + + lv_obj_t* chText = nullptr; + if (idx >= MIXSRC_FIRST_CH && idx <= MIXSRC_LAST_CH && + g_model.limitData[idx - MIXSRC_FIRST_CH].name[0] != '\0') { + chText = lv_label_create(lvobj); + 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); + } + + refresh(); + } + + void enableMixerMonitor() + { + if (!monitor) + monitor = new MixerChannelBar(this, {LCD_W - 118, 1, 100, 14}, idx - MIXSRC_FIRST_CH); + monitorVisible = true; + monitor->show(); + adjustHeight(); + } + + void disableMixerMonitor() + { + monitorVisible = false; + monitor->hide(); + adjustHeight(); + } + + protected: + MixerChannelBar* monitor = nullptr; + bool monitorVisible = false; +}; + ModelMixesPage::ModelMixesPage() : InputMixPageBase(STR_MIXES, ICON_MODEL_MIXER) { } @@ -244,51 +223,25 @@ bool ModelMixesPage::reachMixesLimit() return false; } -MixGroup* ModelMixesPage::getGroupByIndex(uint8_t index) +InputMixGroupBase* ModelMixesPage::getGroupByIndex(uint8_t index) { MixData* mix = mixAddress(index); if (is_memclear(mix, sizeof(MixData))) return nullptr; int ch = mix->destCh; - return (MixGroup*)getGroupBySrc(MIXSRC_FIRST_CH + ch); + return getGroupBySrc(MIXSRC_FIRST_CH + ch); } -MixLineButton* ModelMixesPage::getLineByIndex(uint8_t index) -{ - auto l = std::find_if(lines.begin(), lines.end(), [=](MixLineButton* l) { - return l->getIndex() == index; - }); - - if (l != lines.end()) return *l; - - return nullptr; -} - -void ModelMixesPage::removeLine(MixLineButton* l) -{ - auto line = std::find_if(lines.begin(), lines.end(), - [=](MixLineButton* lh) -> bool { return lh == l; }); - if (line == lines.end()) return; - - line = lines.erase(line); - while (line != lines.end()) { - (*line)->setIndex((*line)->getIndex() - 1); - ++line; - } -} - -MixGroup* ModelMixesPage::createGroup(Window* form, mixsrc_t src) +InputMixGroupBase* ModelMixesPage::createGroup(Window* form, mixsrc_t src) { auto group = new MixGroup(form, src); if (showMonitors) group->enableMixerMonitor(); return group; } -MixLineButton* ModelMixesPage::createLineButton(MixGroup *group, uint8_t index) +InputMixButtonBase* ModelMixesPage::createLineButton(InputMixGroupBase *group, uint8_t index) { auto mplex = new MPlexIcon(group, index); - group->addMPlex(mplex); - auto button = new MixLineButton(group, index, mplex); button->refresh(); @@ -346,60 +299,7 @@ void ModelMixesPage::addLineButton(uint8_t index) if (is_memclear(mix, sizeof(MixData))) return; int channel = mix->destCh; - addLineButton(MIXSRC_FIRST_CH + channel, index); -} - -void ModelMixesPage::addLineButton(mixsrc_t src, uint8_t index) -{ - MixGroup* group_w = (MixGroup*)getGroupBySrc(src); - if (!group_w) { - group_w = createGroup(form, src); - // insertion sort - groups.emplace_back(group_w); - auto g = groups.rbegin(); - if (g != groups.rend()) { - auto g_prev = g; - ++g_prev; - while (g_prev != groups.rend()) { - if ((*g_prev)->getMixSrc() < (*g)->getMixSrc()) break; - lv_obj_swap((*g)->getLvObj(), (*g_prev)->getLvObj()); - std::swap(*g, *g_prev); - ++g; - ++g_prev; - } - } - } - - // create new line button - auto btn = createLineButton(group_w, index); - lv_group_focus_obj(btn->getLvObj()); - - // insertion sort for the focus group - auto l = lines.rbegin(); - if (l != lines.rend()) { - auto l_prev = l; - ++l_prev; - while (l_prev != lines.rend()) { - if ((*l_prev)->getIndex() < (*l)->getIndex()) break; - // Swap elements (focus + line list) - lv_obj_t* obj1 = (*l)->getLvObj(); - lv_obj_t* obj2 = (*l_prev)->getLvObj(); - if (lv_obj_get_parent(obj1) == lv_obj_get_parent(obj2)) { - // same input group: swap obj + focus group - lv_obj_swap(obj1, obj2); - lv_obj_swap((*l)->mplexLvObj(), (*l_prev)->mplexLvObj()); - } else { - // different input group: swap only focus group - lv_group_swap_obj(obj1, obj2); - lv_group_swap_obj((*l)->mplexLvObj(), (*l_prev)->mplexLvObj()); - } - std::swap(*l, *l_prev); - // Inc index of elements after - (*l)->setIndex((*l)->getIndex() + 1); - ++l; - ++l_prev; - } - } + InputMixPageBase::addLineButton(MIXSRC_FIRST_CH + channel, index); } void ModelMixesPage::newMix() @@ -443,6 +343,7 @@ void ModelMixesPage::editMix(uint8_t channel, uint8_t index) } else { line->refresh(); } + (getGroupByIndex(index))->adjustHeight(); }); } @@ -451,7 +352,7 @@ void ModelMixesPage::insertMix(uint8_t channel, uint8_t index) _copyMode = 0; ::insertMix(index, channel); - addLineButton(MIXSRC_FIRST_CH + channel, index); + InputMixPageBase::addLineButton(MIXSRC_FIRST_CH + channel, index); editMix(channel, index); } diff --git a/radio/src/gui/colorlcd/model_mixes.h b/radio/src/gui/colorlcd/model_mixes.h index 512b4ea15..2477d353d 100644 --- a/radio/src/gui/colorlcd/model_mixes.h +++ b/radio/src/gui/colorlcd/model_mixes.h @@ -21,24 +21,8 @@ #pragma once -#include "input_mix_group.h" - -class MixLineButton; - -class MixGroup : public InputMixGroupBase -{ - public: - MixGroup(Window* parent, mixsrc_t idx); - - void enableMixerMonitor(); - void disableMixerMonitor(); - - void addMPlex(Window* mplex); - - protected: - MixerChannelBar* monitor = nullptr; - lv_obj_t* mplex_container; -}; +#include "list_line_button.h" +#include class ModelMixesPage : public InputMixPageBase { @@ -48,20 +32,13 @@ class ModelMixesPage : public InputMixPageBase void build(Window* window) override; protected: - std::list lines; - MixLineButton* _copySrc = nullptr; - bool showMonitors = false; - MixGroup* getGroupByIndex(uint8_t index); - MixLineButton* getLineByIndex(uint8_t index); + InputMixGroupBase* getGroupByIndex(uint8_t index) override; - void removeLine(MixLineButton* l); - - void addLineButton(uint8_t index); - void addLineButton(mixsrc_t src, uint8_t index); - MixGroup* createGroup(Window* form, mixsrc_t src); - MixLineButton* createLineButton(MixGroup* group, uint8_t index); + void addLineButton(uint8_t index) override; + InputMixGroupBase* createGroup(Window* form, mixsrc_t src) override; + InputMixButtonBase* createLineButton(InputMixGroupBase* group, uint8_t index) override; void newMix(); void editMix(uint8_t input, uint8_t index); diff --git a/radio/src/gui/colorlcd/model_outputs.cpp b/radio/src/gui/colorlcd/model_outputs.cpp index c2926bc5a..89a247858 100644 --- a/radio/src/gui/colorlcd/model_outputs.cpp +++ b/radio/src/gui/colorlcd/model_outputs.cpp @@ -32,34 +32,55 @@ #define ETX_STATE_MINMAX_BOLD LV_STATE_USER_1 #define ETX_STATE_NAME_FONT_SMALL LV_STATE_USER_1 -#define CH_BAR_WIDTH 92 -#define CH_BAR_HEIGHT 14 +#define CH_BAR_WIDTH 100 +#define CH_BAR_HEIGHT 16 #if LCD_W > LCD_H // Landscape #define CH_LINE_H 32 -#define CH_BAR_COL 7 -#define CH_BAR_COLSPAN 1 +#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 -static const lv_coord_t col_dsc[] = { - 80, 50, 54, 44, 60, 18, 18, LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; - -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; #else // Portrait #define CH_LINE_H 50 -#define CH_BAR_COL 3 -#define CH_BAR_COLSPAN 3 +#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 -static const lv_coord_t col_dsc[] = { - 80, 50, 60, 18, 18, LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; - -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; #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; @@ -84,52 +105,42 @@ class OutputLineButton : public ListLineButton void delayed_init() { - uint8_t col = 1, row = 0; + init = true; 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); - lv_obj_set_grid_cell(min, LV_GRID_ALIGN_END, col++, 1, LV_GRID_ALIGN_START, - row, 1); + lv_obj_set_pos(min, MIN_X, MIN_Y); + lv_obj_set_size(min, MIN_W, MIN_H); max = lv_label_create(lvobj); etx_obj_add_style(max, styles->text_align_right, LV_PART_MAIN); etx_font(max, FONT_BOLD_INDEX, ETX_STATE_MINMAX_BOLD); - lv_obj_set_grid_cell(max, LV_GRID_ALIGN_END, col++, 1, LV_GRID_ALIGN_START, - row, 1); - -#if LCD_H > LCD_W - col = 1; - row++; -#endif + lv_obj_set_pos(max, MAX_X, MAX_Y); + lv_obj_set_size(max, MAX_W, MAX_H); offset = lv_label_create(lvobj); - lv_obj_set_grid_cell(offset, LV_GRID_ALIGN_END, col++, 1, - LV_GRID_ALIGN_START, row, 1); + etx_obj_add_style(offset, styles->text_align_right, LV_PART_MAIN); + lv_obj_set_pos(offset, OFF_X, OFF_Y); + lv_obj_set_size(offset, OFF_W, OFF_H); center = lv_label_create(lvobj); - lv_obj_set_style_pad_left(center, 8, 0); - lv_obj_set_grid_cell(center, LV_GRID_ALIGN_START, col++, 1, - LV_GRID_ALIGN_START, row, 1); + etx_obj_add_style(center, styles->text_align_right, LV_PART_MAIN); + lv_obj_set_pos(center, CTR_X, CTR_Y); + lv_obj_set_size(center, CTR_W, CTR_H); revert = lv_img_create(lvobj); lv_img_set_src(revert, LV_SYMBOL_SHUFFLE); - lv_obj_set_grid_cell(revert, LV_GRID_ALIGN_START, col++, 1, - LV_GRID_ALIGN_START, row, 1); + lv_obj_set_pos(revert, REV_X, REV_Y); curve = - new StaticIcon(this, 0, 0, ICON_TEXTLINE_CURVE, COLOR_THEME_SECONDARY1); - lv_obj_set_grid_cell(curve->getLvObj(), LV_GRID_ALIGN_START, col++, 1, - LV_GRID_ALIGN_START, row, 1); + new StaticIcon(this, CRV_X, CRV_Y, ICON_TEXTLINE_CURVE, COLOR_THEME_SECONDARY1); - bar = new OutputChannelBar(this, rect_t{0, 0, CH_BAR_WIDTH, CH_BAR_HEIGHT}, + bar = new OutputChannelBar(this, rect_t{BAR_X, BAR_Y, CH_BAR_WIDTH, CH_BAR_HEIGHT}, index, false, false); - lv_obj_set_grid_cell(bar->getLvObj(), LV_GRID_ALIGN_END, CH_BAR_COL, - CH_BAR_COLSPAN, LV_GRID_ALIGN_CENTER, 0, 1); - - init = true; refresh(); + checkEvents(); lv_obj_update_layout(lvobj); } @@ -139,23 +150,15 @@ class OutputLineButton : public ListLineButton ListLineButton(parent, channel) { setHeight(CH_LINE_H); -#if LCD_W > LCD_H - padTop(4); -#endif - lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); - lv_obj_set_grid_dsc_array(lvobj, col_dsc, row_dsc); + 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_H > LCD_W - lv_obj_set_grid_cell(source, LV_GRID_ALIGN_START, 0, 1, - LV_GRID_ALIGN_CENTER, 0, 2); - -#else - lv_obj_set_grid_cell(source, LV_GRID_ALIGN_START, 0, 1, - LV_GRID_ALIGN_CENTER, 0, 1); +#if LCD_W > LCD_H etx_font(source, FONT_XS_INDEX, ETX_STATE_NAME_FONT_SMALL); - lv_obj_set_style_pad_top(source, -5, ETX_STATE_NAME_FONT_SMALL); + lv_obj_set_style_pad_top(source, -2, ETX_STATE_NAME_FONT_SMALL); lv_obj_set_style_text_line_space(source, -3, ETX_STATE_NAME_FONT_SMALL); #endif @@ -203,7 +206,7 @@ class OutputLineButton : public ListLineButton } protected: - int value = 0; + int value = -10000; bool isActive() const override { return false; } @@ -239,41 +242,52 @@ 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->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); + window->padAll(PAD_ZERO); + window->padBottom(PAD_LARGE); - lv_obj_set_style_flex_cross_place(window->getLvObj(), LV_FLEX_ALIGN_START, 0); - - auto box = new Window(window, rect_t{}); - box->padAll(PAD_ZERO); - box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_ZERO); - lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); - - auto box2 = new Window(box, rect_t{}); - box2->padAll(PAD_TINY); - box2->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); - new TextButton(box2, rect_t{}, STR_ADD_ALL_TRIMS_TO_SUBTRIMS, [=]() { + new TextButton(window, {ADD_TRIMS_X, ADD_TRIMS_Y, ADD_TRIMS_W, ADD_TRIMS_H}, STR_ADD_ALL_TRIMS_TO_SUBTRIMS, [=]() { moveTrimsToOffsets(); return 0; }); - box2 = new Window(box, rect_t{}); - box2->padAll(PAD_TINY); - box2->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); - lv_obj_set_style_flex_cross_place(box2->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); - - new StaticText(box2, rect_t{}, STR_ELIMITS); - new ToggleSwitch(box2, rect_t{}, GET_SET_DEFAULT(g_model.extendedLimits)); - - box = new Window(window, rect_t{}); - box->padAll(PAD_TINY); - box->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY); - lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0); + new StaticText(window, {EXLIM_X, EXLIM_Y, EXLIM_W, EXLIM_H}, STR_ELIMITS, RIGHT); + new ToggleSwitch(window, {EXLIMCB_X, EXLIMCB_Y, EXLIMCB_W, EXLIMCB_H}, GET_SET_DEFAULT(g_model.extendedLimits)); for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) { // Channel settings - auto btn = new OutputLineButton(box, ch); + auto btn = new OutputLineButton(window, ch); + lv_obj_set_pos(btn->getLvObj(), TRIMB_X, TRIMB_Y + (ch * (CH_LINE_H + 2))); + btn->setWidth(TRIMB_W); LimitData* output = limitAddress(ch); btn->setPressHandler([=]() -> uint8_t { diff --git a/radio/src/gui/colorlcd/model_telemetry.cpp b/radio/src/gui/colorlcd/model_telemetry.cpp index 14ec829c8..947483d0c 100644 --- a/radio/src/gui/colorlcd/model_telemetry.cpp +++ b/radio/src/gui/colorlcd/model_telemetry.cpp @@ -100,40 +100,6 @@ class TSStyle static TSStyle tsStyle; -static void ts_group_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) -{ - etx_obj_add_style(obj, styles->pad_zero, LV_PART_MAIN); - lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); - lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, - LV_FLEX_ALIGN_SPACE_AROUND); -} - -static const lv_obj_class_t ts_group_class = { - .base_class = &lv_obj_class, - .constructor_cb = ts_group_constructor, - .destructor_cb = nullptr, - .user_data = nullptr, - .event_cb = nullptr, - .width_def = NUM_W, - .height_def = BTN_H - 4, - .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, - .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, - .instance_size = sizeof(lv_obj_t), -}; - -static const lv_obj_class_t ts_fresh_cont_class = { - .base_class = &lv_obj_class, - .constructor_cb = nullptr, - .destructor_cb = nullptr, - .user_data = nullptr, - .event_cb = nullptr, - .width_def = 8, - .height_def = 8, - .editable = LV_OBJ_CLASS_EDITABLE_FALSE, - .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, - .instance_size = sizeof(lv_obj_t), -}; - static void ts_num_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj) { etx_obj_add_style(obj, styles->text_align_center, LV_PART_MAIN); @@ -147,7 +113,7 @@ static const lv_obj_class_t ts_num_class = { .user_data = nullptr, .event_cb = nullptr, .width_def = NUM_W, - .height_def = 0, + .height_def = 20, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_label_t), @@ -200,7 +166,7 @@ static const lv_obj_class_t ts_name_class = { .user_data = nullptr, .event_cb = nullptr, .width_def = NAME_W, - .height_def = 0, + .height_def = 20, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_label_t), @@ -227,7 +193,7 @@ static const lv_obj_class_t ts_value_class = { .user_data = nullptr, .event_cb = nullptr, .width_def = LV_SIZE_CONTENT, - .height_def = 0, + .height_def = 20, .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, .group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT, .instance_size = sizeof(lv_label_t), @@ -278,11 +244,7 @@ class SensorButton : public ListLineButton ListLineButton(parent, index) { padAll(PAD_ZERO); - padColumn(PAD_SMALL); setHeight(BTN_H); - lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); - lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, - LV_FLEX_ALIGN_SPACE_AROUND); check(isActive()); @@ -306,8 +268,7 @@ class SensorButton : public ListLineButton if (line) { if (!line->init) line->delayed_init(e); - else - line->refresh(); + line->refresh(); } } @@ -315,15 +276,15 @@ class SensorButton : public ListLineButton void setNumIdState() { - showId = g_model.showInstanceIds; - if (showId) { - lv_obj_clear_flag(idLabel, LV_OBJ_FLAG_HIDDEN); - lv_obj_add_state(numLabel, ETX_STATE_VALUE_SMALL_FONT); - lv_obj_set_height(numLabel, 14); - } else { - lv_obj_add_flag(idLabel, LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_state(numLabel, ETX_STATE_VALUE_SMALL_FONT); - lv_obj_set_height(numLabel, 22); + if (idLabel) { + showId = g_model.showInstanceIds; + if (showId) { + lv_obj_clear_flag(idLabel, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_state(numLabel, ETX_STATE_VALUE_SMALL_FONT); + } else { + lv_obj_add_flag(idLabel, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_state(numLabel, ETX_STATE_VALUE_SMALL_FONT); + } } } @@ -337,39 +298,32 @@ class SensorButton : public ListLineButton { char s[20]; - auto box = etx_create(&ts_group_class, lvobj); + init = true; - numLabel = tsStyle.newNum(box, index); + numLabel = tsStyle.newNum(lvobj, index); + lv_obj_set_pos(numLabel, 2, 3); TelemetrySensor* sensor = &g_model.telemetrySensors[index]; if (sensor->type == TELEM_TYPE_CUSTOM) { sprintf(s, "ID: %d", sensor->instance); - } else { - s[0] = 0; - } - idLabel = tsStyle.newId(box, s); + idLabel = tsStyle.newId(lvobj, s); + lv_obj_set_pos(idLabel, 2, 17); + } setNumIdState(); strAppend(s, g_model.telemetrySensors[index].label, TELEM_LABEL_LEN); - tsStyle.newName(lvobj, s); + lv_obj_t* nm = tsStyle.newName(lvobj, s); + lv_obj_set_pos(nm, NUM_W + 4, 3); - // Reserve space so layout does not change when icon hidden - box = etx_create(&ts_fresh_cont_class, lvobj); - fresh = etx_create(&ts_fresh_icon_class, box); + fresh = etx_create(&ts_fresh_icon_class, lvobj); + lv_obj_set_pos(fresh, NUM_W + NAME_W + 6, 10); valLabel = tsStyle.newValue(lvobj); - - init = true; - refresh(); + lv_obj_set_pos(valLabel, NUM_W + NAME_W + 16, 3); 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 diff --git a/radio/src/gui/colorlcd/special_functions.cpp b/radio/src/gui/colorlcd/special_functions.cpp index 216637dc0..d31e6ce50 100644 --- a/radio/src/gui/colorlcd/special_functions.cpp +++ b/radio/src/gui/colorlcd/special_functions.cpp @@ -33,42 +33,47 @@ #define SET_DIRTY() setDirty() #if LCD_W > LCD_H -#define SF_BUTTON_H 34 + +#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 45 + +#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 -static const lv_coord_t col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), - LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; +#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 //----------------------------------------------------------------------------- -#if LCD_W > LCD_H - -static const lv_coord_t b_col_dsc[] = {43, 70, LV_GRID_FR(1), - 40, 30, LV_GRID_TEMPLATE_LAST}; - -static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; - -#define NM_ROW_CNT 1 -#define FUNC_COL 2 -#define FUNC_ROW 0 - -#else - -static const lv_coord_t b_col_dsc[] = {40, LV_GRID_FR(1), 34, 24, - LV_GRID_TEMPLATE_LAST}; - -static const lv_coord_t b_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; - -#define NM_ROW_CNT 2 -#define FUNC_COL 1 -#define FUNC_ROW 1 - -#endif - static const char *_failsafe_module[] = { "Int.", "Ext.", @@ -117,16 +122,7 @@ FunctionLineButton::FunctionLineButton(Window *parent, const rect_t &rect, ListLineButton(parent, index), cfn(cfn), prefix(prefix) { setHeight(SF_BUTTON_H); -#if LCD_H > LCD_W - padTop(PAD_ZERO); -#else - padTop(PAD_SMALL); -#endif - padLeft(4); - lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); - lv_obj_set_grid_dsc_array(lvobj, b_col_dsc, b_row_dsc); - lv_obj_set_style_pad_row(lvobj, 0, 0); - lv_obj_set_style_pad_column(lvobj, 4, 0); + padAll(PAD_ZERO); lv_obj_add_event_cb(lvobj, FunctionLineButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr); @@ -139,8 +135,7 @@ void FunctionLineButton::on_draw(lv_event_t *e) if (line) { if (!line->init) line->delayed_init(); - else - line->refresh(); + line->refresh(); } } @@ -149,32 +144,25 @@ void FunctionLineButton::delayed_init() init = true; sfName = lv_label_create(lvobj); - etx_obj_add_style(sfName, styles->text_align_left, LV_PART_MAIN); - lv_obj_set_grid_cell(sfName, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_CENTER, - 0, NM_ROW_CNT); + lv_obj_set_pos(sfName, NM_X, NM_Y); + lv_obj_set_size(sfName, NM_W, NM_H); sfSwitch = lv_label_create(lvobj); - etx_obj_add_style(sfSwitch, styles->text_align_center, LV_PART_MAIN); - lv_obj_set_grid_cell(sfSwitch, LV_GRID_ALIGN_START, 1, 1, - LV_GRID_ALIGN_CENTER, 0, 1); + lv_obj_set_pos(sfSwitch, SW_X, SW_Y); + lv_obj_set_size(sfSwitch, SW_W, SW_H); sfFunc = lv_label_create(lvobj); - etx_obj_add_style(sfFunc, styles->text_align_left, LV_PART_MAIN); - lv_obj_set_grid_cell(sfFunc, LV_GRID_ALIGN_START, FUNC_COL, 1, - LV_GRID_ALIGN_CENTER, FUNC_ROW, 1); + lv_obj_set_pos(sfFunc, FN_X, FN_Y); + lv_obj_set_size(sfFunc, FN_W, FN_H); sfRepeat = lv_label_create(lvobj); - etx_obj_add_style(sfRepeat, styles->text_align_left, LV_PART_MAIN); - lv_obj_set_grid_cell(sfRepeat, LV_GRID_ALIGN_CENTER, FUNC_COL + 1, 1, - LV_GRID_ALIGN_CENTER, 0, NM_ROW_CNT); + lv_obj_set_pos(sfRepeat, RP_X, RP_Y); + lv_obj_set_size(sfRepeat, RP_W, RP_H); sfEnable = sf_enable_state_create(lvobj); lv_obj_clear_flag(sfEnable, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_user_data(sfEnable, this); - lv_obj_set_grid_cell(sfEnable, LV_GRID_ALIGN_CENTER, FUNC_COL + 2, 1, - LV_GRID_ALIGN_CENTER, 0, NM_ROW_CNT); - - refresh(); + lv_obj_set_pos(sfEnable, EN_X, EN_Y); lv_obj_update_layout(lvobj); } @@ -322,6 +310,10 @@ void FunctionLineButton::refresh() //----------------------------------------------------------------------------- +static const lv_coord_t col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; + #define ETX_STATE_SF_ACTIVE LV_STATE_USER_1 #define SD_LOGS_PERIOD_MIN 1 // 0.1s fastest period diff --git a/radio/src/gui/colorlcd/view_main.cpp b/radio/src/gui/colorlcd/view_main.cpp index c6dca8b5f..0d38d60e1 100644 --- a/radio/src/gui/colorlcd/view_main.cpp +++ b/radio/src/gui/colorlcd/view_main.cpp @@ -308,18 +308,8 @@ bool ViewMain::enableWidgetSelect(bool enable) for (uint32_t i = 0; i < cont->getZonesCount(); i++) { Widget* widget = cont->getWidget(i); - if (!widget) continue; - if (enable) { - widget->setFocusHandler([=](bool hasFocus) { - if (hasFocus) - widget->bringToTop(); - refreshWidgetSelectTimer(); - }); - lv_group_add_obj(lv_group_get_default(), widget->getLvObj()); - } else { - widget->setFocusHandler(nullptr); - lv_group_remove_obj(widget->getLvObj()); - } + if (widget) + widget->enableFocus(enable); } if (enable) { diff --git a/radio/src/gui/colorlcd/view_main.h b/radio/src/gui/colorlcd/view_main.h index 8a3b557f4..bf8772df3 100644 --- a/radio/src/gui/colorlcd/view_main.h +++ b/radio/src/gui/colorlcd/view_main.h @@ -75,6 +75,7 @@ class ViewMain : public NavWindow void show(bool visible = true) override; void runBackground(); + void refreshWidgetSelectTimer(); protected: static ViewMain* _instance; @@ -96,7 +97,6 @@ class ViewMain : public NavWindow void setTopbarVisible(float visible); void openMenu(); - void refreshWidgetSelectTimer(); static void long_pressed(lv_event_t* e); static void ws_timer(lv_timer_t* t); diff --git a/radio/src/gui/colorlcd/widget.cpp b/radio/src/gui/colorlcd/widget.cpp index 715a55956..e4cc0c520 100644 --- a/radio/src/gui/colorlcd/widget.cpp +++ b/radio/src/gui/colorlcd/widget.cpp @@ -39,9 +39,6 @@ Widget::Widget(const WidgetFactory* factory, Window* parent, const rect_t& rect, lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLLABLE); lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); - etx_obj_add_style(lvobj, styles->border, LV_STATE_FOCUSED); - etx_obj_add_style(lvobj, styles->border_color_focus, LV_STATE_FOCUSED); - if (parent->isTopBar()) fsAllowed = false; setPressHandler([&]() -> uint8_t { @@ -153,6 +150,51 @@ const ZoneOption* Widget::getOptions() const return getFactory()->getOptions(); } +void Widget::enableFocus(bool enable) +{ + if (enable) { + if (!focusBorder) { + lv_style_init(&borderStyle); + lv_style_set_line_width(&borderStyle, 2); + lv_style_set_line_opa(&borderStyle, LV_OPA_COVER); + lv_style_set_line_color(&borderStyle, makeLvColor(COLOR_THEME_FOCUS)); + + borderPts[0] = {1, 1}; + borderPts[1] = {(lv_coord_t)(width() - 1), 1}; + borderPts[2] = {(lv_coord_t)(width() - 1), (lv_coord_t)(height() - 1)}; + borderPts[3] = {1, (lv_coord_t)(height() - 1)}; + borderPts[4] = {1, 1}; + + focusBorder = lv_line_create(lvobj); + lv_obj_add_style(focusBorder, &borderStyle, LV_PART_MAIN); + lv_line_set_points(focusBorder, borderPts, 5); + + if (!hasFocus()) { + lv_obj_add_flag(focusBorder, LV_OBJ_FLAG_HIDDEN); + } + + setFocusHandler([=](bool hasFocus) { + if (hasFocus) { + bringToTop(); + lv_obj_clear_flag(focusBorder, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(focusBorder, LV_OBJ_FLAG_HIDDEN); + } + ViewMain::instance()->refreshWidgetSelectTimer(); + }); + + lv_group_add_obj(lv_group_get_default(), lvobj); + } + } else { + if (focusBorder) { + lv_obj_del(focusBorder); + setFocusHandler(nullptr); + lv_group_remove_obj(lvobj); + } + focusBorder = nullptr; + } +} + std::list& WidgetFactory::getRegisteredWidgets() { static std::list widgets; diff --git a/radio/src/gui/colorlcd/widget.h b/radio/src/gui/colorlcd/widget.h index a4d75b3d0..7327512ab 100644 --- a/radio/src/gui/colorlcd/widget.h +++ b/radio/src/gui/colorlcd/widget.h @@ -89,11 +89,16 @@ class Widget : public ButtonBase // Update widget 'zone' data (for Lua widgets) virtual void updateZoneRect(rect_t rect) {} + void enableFocus(bool enable); + protected: const WidgetFactory* factory; PersistentData* persistentData; bool fullscreen = false; bool fsAllowed = true; + lv_obj_t* focusBorder = nullptr; + lv_style_t borderStyle; + lv_point_t borderPts[5]; void onCancel() override; void onLongPress() override;