chore(color): lvgl performance improvements (#4861)
This commit is contained in:
+5
-3
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user