chore(color): lvgl performance improvements (#4861)

This commit is contained in:
philmoz
2024-04-25 11:23:33 +10:00
committed by GitHub
parent 55944ab92d
commit c7cf2d371a
23 changed files with 891 additions and 1249 deletions
+5 -3
View File
@@ -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)
-2
View File
@@ -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
-157
View File
@@ -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;
}
}
-45
View File
@@ -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);
};
-134
View File
@@ -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 <algorithm>
#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);
}
-67
View File
@@ -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 <list>
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<Window*> 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<InputMixGroupBase*> groups;
InputMixGroupBase* getGroupBySrc(mixsrc_t src);
void removeGroup(InputMixGroupBase* g);
};
+310 -2
View File
@@ -21,6 +21,8 @@
#include "list_line_button.h"
#include <algorithm>
#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;
}
}
}
+75
View File
@@ -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<InputMixButtonBase*> lines;
};
class InputMixPageBase : public PageTab
{
public:
InputMixPageBase(const char* title, EdgeTxIcon icon) : PageTab(title, icon) {}
protected:
std::list<InputMixButtonBase*> lines;
InputMixButtonBase* _copySrc = nullptr;
Window* form = nullptr;
uint8_t _copyMode = 0;
std::list<InputMixGroupBase*> 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);
};
+1 -1
View File
@@ -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};
+47 -79
View File
@@ -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
+33 -155
View File
@@ -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)
+48 -90
View File
@@ -23,15 +23,8 @@
#include <algorithm>
#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);
}
+6 -22
View File
@@ -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 <list>
class ModelInputsPage : public InputMixPageBase
{
@@ -41,18 +32,11 @@ class ModelInputsPage : public InputMixPageBase
void build(Window *window) override;
protected:
std::list<InputMixButton*> 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);
@@ -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
+82 -181
View File
@@ -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);
}
+6 -29
View File
@@ -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 <list>
class ModelMixesPage : public InputMixPageBase
{
@@ -48,20 +32,13 @@ class ModelMixesPage : public InputMixPageBase
void build(Window* window) override;
protected:
std::list<MixLineButton*> 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);
+93 -79
View File
@@ -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 {
+24 -70
View File
@@ -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
+50 -58
View File
@@ -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
+2 -12
View File
@@ -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) {
+1 -1
View File
@@ -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);
+45 -3
View File
@@ -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<const WidgetFactory*>& WidgetFactory::getRegisteredWidgets()
{
static std::list<const WidgetFactory*> widgets;
+5
View File
@@ -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;