|
|
|
@@ -22,309 +22,518 @@
|
|
|
|
|
#include "model_flightmodes.h"
|
|
|
|
|
#include "opentx.h"
|
|
|
|
|
#include "libopenui.h"
|
|
|
|
|
#include "lvgl_widgets/input_mix_line.h"
|
|
|
|
|
|
|
|
|
|
#define SET_DIRTY() storageDirty(EE_MODEL)
|
|
|
|
|
|
|
|
|
|
#define LABEL_RIGHT_MARGIN 5
|
|
|
|
|
|
|
|
|
|
bool isTrimModeAvailable(int mode)
|
|
|
|
|
static std::string getFMTrimStr(uint8_t mode, bool spacer)
|
|
|
|
|
{
|
|
|
|
|
return (mode < 0 || (mode%2) == 0 || (mode/2) != 0); //ToDo menuVerticalPosition
|
|
|
|
|
mode &= 0x1F;
|
|
|
|
|
if (mode == TRIM_MODE_NONE)
|
|
|
|
|
return "-";
|
|
|
|
|
std::string str((mode & 1) ? "+" : "=");
|
|
|
|
|
if (spacer) str += " ";
|
|
|
|
|
mode >>= 1;
|
|
|
|
|
if (mode > MAX_FLIGHT_MODES - 1)
|
|
|
|
|
mode = MAX_FLIGHT_MODES - 1;
|
|
|
|
|
str += '0'+ mode;
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct FlightModeEdit : public Page {
|
|
|
|
|
FlightModeEdit(uint8_t index);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
|
|
|
|
|
static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
|
|
|
|
|
// static const lv_coord_t trims_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
|
|
|
|
|
// LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
#if LCD_W > LCD_H
|
|
|
|
|
#define TRIMS_PER_LINE 2
|
|
|
|
|
static const lv_coord_t trims_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
#else
|
|
|
|
|
#define TRIMS_PER_LINE 1
|
|
|
|
|
static const lv_coord_t trims_col_dsc[] = {LV_GRID_FR(1),
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static const lv_coord_t trims_row_dsc[] = {LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
|
|
|
|
|
static void btn_changed(lv_event_t* e)
|
|
|
|
|
class FlightModeEdit : public Page
|
|
|
|
|
{
|
|
|
|
|
auto target = lv_event_get_target(e);
|
|
|
|
|
auto btn = (Button*)lv_obj_get_user_data(target);
|
|
|
|
|
auto obj = (lv_obj_t*)lv_event_get_user_data(e);
|
|
|
|
|
public:
|
|
|
|
|
FlightModeEdit(uint8_t index) :
|
|
|
|
|
Page(ICON_MODEL_FLIGHT_MODES),
|
|
|
|
|
index(index)
|
|
|
|
|
{
|
|
|
|
|
std::string title2 = std::string(STR_FM) + std::to_string(index);
|
|
|
|
|
header.setTitle(STR_MENUFLIGHTMODES);
|
|
|
|
|
header.setTitle2(title2);
|
|
|
|
|
|
|
|
|
|
if (!btn->checked()) {
|
|
|
|
|
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
|
} else {
|
|
|
|
|
lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
|
lv_event_send(obj, LV_EVENT_VALUE_CHANGED, nullptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
body.padAll(lv_dpx(8));
|
|
|
|
|
lv_obj_set_scrollbar_mode(body.getLvObj(), LV_SCROLLBAR_MODE_AUTO);
|
|
|
|
|
|
|
|
|
|
static void make_conditional(Window* w, Button* btn)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_t* w_obj = w->getLvObj();
|
|
|
|
|
if (!btn->checked()) { lv_obj_add_flag(w_obj, LV_OBJ_FLAG_HIDDEN); }
|
|
|
|
|
FlexGridLayout grid(line_col_dsc, line_row_dsc, 2);
|
|
|
|
|
auto form = new FormWindow(&body, rect_t{});
|
|
|
|
|
form->setFlexLayout();
|
|
|
|
|
|
|
|
|
|
lv_obj_t* btn_obj = btn->getLvObj();
|
|
|
|
|
lv_obj_add_event_cb(btn_obj, btn_changed, LV_EVENT_CLICKED, w_obj);
|
|
|
|
|
}
|
|
|
|
|
FlightModeData* p_fm = &g_model.flightModeData[index];
|
|
|
|
|
|
|
|
|
|
// Flight mode name
|
|
|
|
|
auto line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new ModelTextEdit(line, rect_t{}, p_fm->name, LEN_FLIGHT_MODE_NAME);
|
|
|
|
|
|
|
|
|
|
static std::string getFMTrimStr(uint8_t mode)
|
|
|
|
|
{
|
|
|
|
|
char str[4];
|
|
|
|
|
if (index > 0) {
|
|
|
|
|
// Switch
|
|
|
|
|
line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_SWITCH, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES,
|
|
|
|
|
GET_SET_DEFAULT(p_fm->swtch));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mode &= 0x1F;
|
|
|
|
|
// Fade in
|
|
|
|
|
line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_FADEIN, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(p_fm->fadeIn),
|
|
|
|
|
SET_VALUE(p_fm->fadeIn, newValue), 0, PREC1);
|
|
|
|
|
|
|
|
|
|
if (mode & 1) str[0] = '+';
|
|
|
|
|
else str[0] = '=';
|
|
|
|
|
str[1] = ' ';
|
|
|
|
|
// Fade out
|
|
|
|
|
line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_FADEOUT, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(p_fm->fadeOut),
|
|
|
|
|
SET_VALUE(p_fm->fadeOut, newValue), 0, PREC1);
|
|
|
|
|
|
|
|
|
|
mode >>= 1;
|
|
|
|
|
if (mode > MAX_FLIGHT_MODES - 1) mode = MAX_FLIGHT_MODES - 1;
|
|
|
|
|
str[2] = '0' + mode;
|
|
|
|
|
str[3] = '\0';
|
|
|
|
|
// Trims
|
|
|
|
|
line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_TRIMS, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
FlexGridLayout trim_grid(trims_col_dsc, line_row_dsc);
|
|
|
|
|
|
|
|
|
|
struct FMTrimSettings : public Dialog {
|
|
|
|
|
FMTrimSettings(Window* parent, FlightModeData* p_fm) :
|
|
|
|
|
Dialog(parent->getFullScreenWindow(), STR_TRIMS, rect_t{})
|
|
|
|
|
{
|
|
|
|
|
setCloseWhenClickOutside(true);
|
|
|
|
|
auto form = &content->form;
|
|
|
|
|
for (int t = 0; t < NUM_TRIMS; t++) {
|
|
|
|
|
lastTrim[t] = p_fm->trim[t].value;
|
|
|
|
|
|
|
|
|
|
FlexGridLayout trim_grid(line_col_dsc, trims_row_dsc);
|
|
|
|
|
auto line = form->newLine(&trim_grid);
|
|
|
|
|
if ((t % TRIMS_PER_LINE) == 0) {
|
|
|
|
|
line = form->newLine(&trim_grid);
|
|
|
|
|
line->padLeft(10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int t = 0; t < NUM_TRIMS; t++) {
|
|
|
|
|
auto trim = new FormGroup(line, rect_t{});
|
|
|
|
|
trim->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
|
|
|
|
|
|
|
|
|
auto trim = new FormGroup(line, rect_t{});
|
|
|
|
|
trim->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
|
|
|
|
auto trim_obj = trim->getLvObj();
|
|
|
|
|
lv_obj_set_style_pad_column(trim_obj, lv_dpx(8), 0);
|
|
|
|
|
lv_obj_set_style_flex_cross_place(trim_obj, LV_FLEX_ALIGN_CENTER, 0);
|
|
|
|
|
lv_obj_set_style_grid_cell_x_align(trim_obj, LV_GRID_ALIGN_STRETCH, 0);
|
|
|
|
|
|
|
|
|
|
auto trim_obj = trim->getLvObj();
|
|
|
|
|
lv_obj_set_style_pad_column(trim_obj, lv_dpx(8), 0);
|
|
|
|
|
lv_obj_set_style_flex_cross_place(trim_obj, LV_FLEX_ALIGN_CENTER, 0);
|
|
|
|
|
lv_obj_set_style_grid_cell_x_align(trim_obj, LV_GRID_ALIGN_STRETCH, 0);
|
|
|
|
|
|
|
|
|
|
trim_t* tr = &p_fm->trim[t];
|
|
|
|
|
auto btn = new TextButton(
|
|
|
|
|
trim, rect_t{}, getSourceString(MIXSRC_FIRST_TRIM + t),
|
|
|
|
|
[=]() {
|
|
|
|
|
if (tr->mode == TRIM_MODE_NONE) {
|
|
|
|
|
tr->mode = 0;
|
|
|
|
|
trim_t* tr = &p_fm->trim[t];
|
|
|
|
|
auto tr_btn = new TextButton(
|
|
|
|
|
trim, rect_t{}, getSourceString(MIXSRC_FIRST_TRIM + t),
|
|
|
|
|
[=]() {
|
|
|
|
|
tr->mode = (tr->mode == TRIM_MODE_NONE) ? 0 : TRIM_MODE_NONE;
|
|
|
|
|
tr_mode[t]->setValue(tr->mode);
|
|
|
|
|
SET_DIRTY();
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
tr->mode = TRIM_MODE_NONE;
|
|
|
|
|
SET_DIRTY();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
showControls(t, tr->mode);
|
|
|
|
|
return tr->mode == 0;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (tr->mode != TRIM_MODE_NONE) btn->check();
|
|
|
|
|
btn->setWidth(LV_DPI_DEF / 2);
|
|
|
|
|
btn->setHeight(LV_DPI_DEF / 4);
|
|
|
|
|
if (tr->mode != TRIM_MODE_NONE) tr_btn->check();
|
|
|
|
|
tr_btn->setWidth(LV_DPI_DEF / 2);
|
|
|
|
|
tr_btn->setHeight(33);
|
|
|
|
|
|
|
|
|
|
auto tr_mode = new Choice(trim, rect_t{}, 0, 2 * MAX_FLIGHT_MODES - 1,
|
|
|
|
|
GET_SET_DEFAULT(tr->mode));
|
|
|
|
|
tr_mode->setTextHandler(getFMTrimStr);
|
|
|
|
|
tr_mode[t] = new Choice(trim, rect_t{}, 0, 2 * MAX_FLIGHT_MODES - 1,
|
|
|
|
|
GET_DEFAULT(tr->mode),
|
|
|
|
|
[=](int val) {
|
|
|
|
|
tr->mode = val;
|
|
|
|
|
showControls(t, tr->mode);
|
|
|
|
|
});
|
|
|
|
|
tr_mode[t]->setTextHandler([=](uint8_t mode) { return getFMTrimStr(mode, true); });
|
|
|
|
|
tr_mode[t]->setAvailableHandler([=](int mode) {
|
|
|
|
|
return ((mode & 1) == 0) || ((mode >> 1) != index);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// show trim value choice iff btn->checked()
|
|
|
|
|
make_conditional(tr_mode, btn);
|
|
|
|
|
tr_value[t] = new NumberEdit(trim, rect_t{},
|
|
|
|
|
g_model.extendedTrims ? -512 : -128, g_model.extendedTrims ? 512 : 128,
|
|
|
|
|
GET_SET_DEFAULT(tr->value));
|
|
|
|
|
|
|
|
|
|
// show trim value choice iff btn->checked()
|
|
|
|
|
showControls(t, tr->mode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
content->setWidth(LCD_W * 0.8);
|
|
|
|
|
content->updateSize();
|
|
|
|
|
}
|
|
|
|
|
void checkEvents() override
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < NUM_TRIMS; i += 1) {
|
|
|
|
|
const auto& fm = g_model.flightModeData[index];
|
|
|
|
|
if (lastTrim[i] != fm.trim[i].value) {
|
|
|
|
|
lastTrim[i] = fm.trim[i].value;
|
|
|
|
|
tr_value[i]->setValue(lastTrim[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
uint8_t index;
|
|
|
|
|
Choice* tr_mode[NUM_TRIMS] = {nullptr};
|
|
|
|
|
NumberEdit* tr_value[NUM_TRIMS] = {nullptr};
|
|
|
|
|
int lastTrim[NUM_TRIMS];
|
|
|
|
|
|
|
|
|
|
void showControls(int trim, uint8_t mode)
|
|
|
|
|
{
|
|
|
|
|
bool checked = (mode != TRIM_MODE_NONE);
|
|
|
|
|
bool showValue = (index == 0) || ((mode & 1) || (mode >> 1 == index));
|
|
|
|
|
|
|
|
|
|
if (checked && (index > 0)) {
|
|
|
|
|
lv_obj_clear_flag(tr_mode[trim]->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
|
|
|
|
} else {
|
|
|
|
|
lv_obj_add_flag(tr_mode[trim]->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
if (checked && showValue) {
|
|
|
|
|
lv_obj_clear_flag(tr_value[trim]->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
|
|
|
|
} else {
|
|
|
|
|
lv_obj_add_flag(tr_value[trim]->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FlightModeEdit::FlightModeEdit(uint8_t index) :
|
|
|
|
|
Page(ICON_MODEL_FLIGHT_MODES)
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
|
|
#else // Portrait
|
|
|
|
|
|
|
|
|
|
#define BTN_H 58
|
|
|
|
|
#define TRIM_W 40
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
class FMStyle
|
|
|
|
|
{
|
|
|
|
|
std::string title2 = std::string(STR_FM) + std::to_string(index);
|
|
|
|
|
header.setTitle(STR_MENUFLIGHTMODES);
|
|
|
|
|
header.setTitle2(title2);
|
|
|
|
|
public:
|
|
|
|
|
FMStyle() {}
|
|
|
|
|
|
|
|
|
|
FlexGridLayout grid(line_col_dsc, line_row_dsc, 2);
|
|
|
|
|
auto form = new FormWindow(&body, rect_t{});
|
|
|
|
|
form->setFlexLayout();
|
|
|
|
|
void init()
|
|
|
|
|
{
|
|
|
|
|
if(!styleInitDone)
|
|
|
|
|
{
|
|
|
|
|
styleInitDone=true;
|
|
|
|
|
|
|
|
|
|
FlightModeData* p_fm = &g_model.flightModeData[index];
|
|
|
|
|
|
|
|
|
|
// Flight mode name
|
|
|
|
|
auto line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new ModelTextEdit(line, rect_t{}, p_fm->name, LEN_FLIGHT_MODE_NAME);
|
|
|
|
|
lv_style_init(&fmTrimContStyle);
|
|
|
|
|
lv_style_set_pad_all(&fmTrimContStyle, 0);
|
|
|
|
|
lv_style_set_width(&fmTrimContStyle, TRIMC_W);
|
|
|
|
|
lv_style_set_height(&fmTrimContStyle, 32);
|
|
|
|
|
|
|
|
|
|
if (index > 0) {
|
|
|
|
|
// Switch
|
|
|
|
|
line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_SWITCH, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES,
|
|
|
|
|
GET_SET_DEFAULT(p_fm->swtch));
|
|
|
|
|
}
|
|
|
|
|
lv_style_init(&fmIdStyle);
|
|
|
|
|
lv_style_set_text_font(&fmIdStyle, getFont(FONT(STD)));
|
|
|
|
|
lv_style_set_text_color(&fmIdStyle, makeLvColor(COLOR_THEME_SECONDARY1));
|
|
|
|
|
lv_style_set_text_align(&fmIdStyle, LV_TEXT_ALIGN_LEFT);
|
|
|
|
|
lv_style_set_width(&fmIdStyle, FMID_W);
|
|
|
|
|
lv_style_set_pad_left(&fmIdStyle, 2);
|
|
|
|
|
|
|
|
|
|
// Fade in
|
|
|
|
|
line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_FADEIN, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(p_fm->fadeIn),
|
|
|
|
|
SET_VALUE(p_fm->fadeIn, newValue), 0, PREC1);
|
|
|
|
|
lv_style_init(&fmNameStyle);
|
|
|
|
|
lv_style_set_text_font(&fmNameStyle, getFont(FONT(XS)));
|
|
|
|
|
lv_style_set_text_color(&fmNameStyle, makeLvColor(COLOR_THEME_SECONDARY1));
|
|
|
|
|
lv_style_set_text_align(&fmNameStyle, LV_TEXT_ALIGN_LEFT);
|
|
|
|
|
lv_style_set_width(&fmNameStyle, NAME_W);
|
|
|
|
|
|
|
|
|
|
// Fade out
|
|
|
|
|
line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_FADEOUT, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(p_fm->fadeOut),
|
|
|
|
|
SET_VALUE(p_fm->fadeOut, newValue), 0, PREC1);
|
|
|
|
|
lv_style_init(&fmSwitchStyle);
|
|
|
|
|
lv_style_set_text_font(&fmSwitchStyle, getFont(FONT(STD)));
|
|
|
|
|
lv_style_set_text_color(&fmSwitchStyle, makeLvColor(COLOR_THEME_SECONDARY1));
|
|
|
|
|
lv_style_set_text_align(&fmSwitchStyle, LV_TEXT_ALIGN_LEFT);
|
|
|
|
|
lv_style_set_width(&fmSwitchStyle, SWTCH_W);
|
|
|
|
|
|
|
|
|
|
// Trims
|
|
|
|
|
line = form->newLine(&grid);
|
|
|
|
|
new StaticText(line, rect_t{}, STR_TRIMS, 0, COLOR_THEME_PRIMARY1);
|
|
|
|
|
new TextButton(line, rect_t{}, STR_SETUP, [=]() {
|
|
|
|
|
new FMTrimSettings(this, p_fm);
|
|
|
|
|
return 0;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
lv_style_init(&fmFadeStyle);
|
|
|
|
|
lv_style_set_text_font(&fmFadeStyle, getFont(FONT(STD)));
|
|
|
|
|
lv_style_set_text_color(&fmFadeStyle, makeLvColor(COLOR_THEME_SECONDARY1));
|
|
|
|
|
lv_style_set_text_align(&fmFadeStyle, LV_TEXT_ALIGN_RIGHT);
|
|
|
|
|
lv_style_set_width(&fmFadeStyle, FADE_W);
|
|
|
|
|
|
|
|
|
|
class FlightModeBtn: public Button
|
|
|
|
|
{
|
|
|
|
|
uint8_t index;
|
|
|
|
|
bool active = false;
|
|
|
|
|
lv_style_init(&fmTrimModeStyle);
|
|
|
|
|
lv_style_set_text_font(&fmTrimModeStyle, getFont(FONT(STD)));
|
|
|
|
|
lv_style_set_text_color(&fmTrimModeStyle, makeLvColor(COLOR_THEME_SECONDARY1));
|
|
|
|
|
lv_style_set_text_align(&fmTrimModeStyle, LV_TEXT_ALIGN_CENTER);
|
|
|
|
|
lv_style_set_width(&fmTrimModeStyle, TRIM_W);
|
|
|
|
|
lv_style_set_height(&fmTrimModeStyle, 16);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
FlightModeBtn(Window * parent, uint8_t index);
|
|
|
|
|
void checkEvents() override;
|
|
|
|
|
void paint(BitmapBuffer* dc) override;
|
|
|
|
|
fmTrimValueStyle = fmTrimModeStyle;
|
|
|
|
|
lv_style_init(&fmTrimValueStyle);
|
|
|
|
|
lv_style_set_text_font(&fmTrimValueStyle, getFont(FONT(XS)));
|
|
|
|
|
lv_style_set_text_color(&fmTrimValueStyle, makeLvColor(COLOR_THEME_SECONDARY1));
|
|
|
|
|
lv_style_set_text_align(&fmTrimValueStyle, LV_TEXT_ALIGN_CENTER);
|
|
|
|
|
lv_style_set_width(&fmTrimValueStyle, TRIM_W);
|
|
|
|
|
lv_style_set_height(&fmTrimValueStyle, 16);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isActive() { return active; }
|
|
|
|
|
void onPress() override;
|
|
|
|
|
void setTrimContStyle(lv_obj_t* obj)
|
|
|
|
|
{
|
|
|
|
|
init();
|
|
|
|
|
lv_obj_add_style(obj, &fmTrimContStyle, LV_PART_MAIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setIdStyle(lv_obj_t* obj)
|
|
|
|
|
{
|
|
|
|
|
init();
|
|
|
|
|
lv_obj_add_style(obj, &fmIdStyle, LV_PART_MAIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setNameStyle(lv_obj_t* obj)
|
|
|
|
|
{
|
|
|
|
|
init();
|
|
|
|
|
lv_obj_add_style(obj, &fmNameStyle, LV_PART_MAIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setSwitchStyle(lv_obj_t* obj)
|
|
|
|
|
{
|
|
|
|
|
init();
|
|
|
|
|
lv_obj_add_style(obj, &fmSwitchStyle, LV_PART_MAIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setFadeStyle(lv_obj_t* obj)
|
|
|
|
|
{
|
|
|
|
|
init();
|
|
|
|
|
lv_obj_add_style(obj, &fmFadeStyle, LV_PART_MAIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setTrimModeStyle(lv_obj_t* obj)
|
|
|
|
|
{
|
|
|
|
|
init();
|
|
|
|
|
lv_obj_add_style(obj, &fmTrimModeStyle, LV_PART_MAIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setTrimValueStyle(lv_obj_t* obj)
|
|
|
|
|
{
|
|
|
|
|
init();
|
|
|
|
|
lv_obj_add_style(obj, &fmTrimValueStyle, LV_PART_MAIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
lv_style_t fmTrimContStyle;
|
|
|
|
|
lv_style_t fmIdStyle;
|
|
|
|
|
lv_style_t fmNameStyle;
|
|
|
|
|
lv_style_t fmSwitchStyle;
|
|
|
|
|
lv_style_t fmFadeStyle;
|
|
|
|
|
lv_style_t fmTrimModeStyle;
|
|
|
|
|
lv_style_t fmTrimValueStyle;
|
|
|
|
|
bool styleInitDone;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void fm_draw_begin(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
auto fmg = (FlightModeBtn*)lv_event_get_user_data(e);
|
|
|
|
|
if (!fmg) return;
|
|
|
|
|
static FMStyle fmStyle;
|
|
|
|
|
|
|
|
|
|
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
|
|
|
|
|
if (fmg->isActive()) {
|
|
|
|
|
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_ACTIVE);
|
|
|
|
|
} else {
|
|
|
|
|
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_PRIMARY2);
|
|
|
|
|
class FlightModeBtn : public Button
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FlightModeBtn(Window* parent, int index) :
|
|
|
|
|
Button(parent, rect_t{}, nullptr, 0, 0, input_mix_line_create),
|
|
|
|
|
index(index)
|
|
|
|
|
{
|
|
|
|
|
padTop(0);
|
|
|
|
|
padBottom(0);
|
|
|
|
|
padLeft(3);
|
|
|
|
|
padRight(6);
|
|
|
|
|
setHeight(BTN_H);
|
|
|
|
|
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW);
|
|
|
|
|
lv_obj_set_style_pad_all(lvobj, 0, 0);
|
|
|
|
|
lv_obj_set_flex_align(lvobj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
|
|
|
|
|
|
|
|
|
check(isActive());
|
|
|
|
|
|
|
|
|
|
lv_obj_add_event_cb(lvobj, FlightModeBtn::on_draw,
|
|
|
|
|
LV_EVENT_DRAW_MAIN_BEGIN, nullptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FlightModeBtn::FlightModeBtn(Window * parent, uint8_t index) :
|
|
|
|
|
Button(parent, rect_t{}, nullptr, 0, 0, lv_btn_create),
|
|
|
|
|
index(index)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_CLICKABLE);
|
|
|
|
|
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, 0);
|
|
|
|
|
|
|
|
|
|
lv_obj_set_style_grid_cell_x_align(lvobj, LV_GRID_ALIGN_STRETCH, 0);
|
|
|
|
|
lv_obj_set_width(lvobj, lv_pct(100));
|
|
|
|
|
lv_obj_set_height(lvobj, LV_DPI_DEF / 3);
|
|
|
|
|
|
|
|
|
|
lv_obj_add_event_cb(lvobj, fm_draw_begin, LV_EVENT_DRAW_PART_BEGIN, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FlightModeBtn::checkEvents()
|
|
|
|
|
{
|
|
|
|
|
bool newActive = (getFlightMode() == index);
|
|
|
|
|
if (newActive != active) {
|
|
|
|
|
active = newActive;
|
|
|
|
|
invalidate();
|
|
|
|
|
static void on_draw(lv_event_t* e)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_t* target = lv_event_get_target(e);
|
|
|
|
|
auto line = (FlightModeBtn*)lv_obj_get_user_data(target);
|
|
|
|
|
if (line) {
|
|
|
|
|
if (!line->init)
|
|
|
|
|
line->delayed_init(e);
|
|
|
|
|
else
|
|
|
|
|
line->refresh();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FlightModeBtn::paint(BitmapBuffer* dc)
|
|
|
|
|
{
|
|
|
|
|
coord_t x=8, y=0;
|
|
|
|
|
void delayed_init(lv_event_t* e)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_enable_style_refresh(false);
|
|
|
|
|
|
|
|
|
|
LcdFlags txt_flags;
|
|
|
|
|
if (active) {
|
|
|
|
|
txt_flags = FONT(BOLD) | COLOR_THEME_PRIMARY1;
|
|
|
|
|
} else {
|
|
|
|
|
txt_flags = FONT(STD) | COLOR_THEME_SECONDARY1;
|
|
|
|
|
fmID = lv_label_create(lvobj);
|
|
|
|
|
fmStyle.setIdStyle(fmID);
|
|
|
|
|
|
|
|
|
|
lv_obj_t* container = lv_obj_create(lvobj);
|
|
|
|
|
lv_obj_set_flex_flow(container, LV_FLEX_FLOW_ROW_WRAP);
|
|
|
|
|
lv_obj_set_style_flex_grow(container, 2, LV_PART_MAIN);
|
|
|
|
|
lv_obj_set_style_pad_all(container, 0, LV_PART_MAIN);
|
|
|
|
|
lv_obj_set_height(container, LV_SIZE_CONTENT);
|
|
|
|
|
lv_obj_set_user_data(container, this);
|
|
|
|
|
lv_obj_add_flag(container, LV_OBJ_FLAG_EVENT_BUBBLE);
|
|
|
|
|
lv_obj_set_flex_align(container, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
|
|
|
|
|
|
|
|
|
fmName = lv_label_create(container);
|
|
|
|
|
fmStyle.setNameStyle(fmName);
|
|
|
|
|
|
|
|
|
|
fmSwitch = lv_label_create(container);
|
|
|
|
|
fmStyle.setSwitchStyle(fmSwitch);
|
|
|
|
|
|
|
|
|
|
lv_obj_t* trims_cont = lv_obj_create(container);
|
|
|
|
|
fmStyle.setTrimContStyle(trims_cont);
|
|
|
|
|
lv_obj_set_user_data(trims_cont, this);
|
|
|
|
|
lv_obj_add_flag(trims_cont, LV_OBJ_FLAG_EVENT_BUBBLE);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_TRIMS; i += 1) {
|
|
|
|
|
fmTrimMode[i] = lv_label_create(trims_cont);
|
|
|
|
|
fmStyle.setTrimModeStyle(fmTrimMode[i]);
|
|
|
|
|
lv_obj_set_pos(fmTrimMode[i], i*TRIM_W, 0);
|
|
|
|
|
|
|
|
|
|
fmTrimValue[i] = lv_label_create(trims_cont);
|
|
|
|
|
fmStyle.setTrimValueStyle(fmTrimValue[i]);
|
|
|
|
|
lv_obj_set_pos(fmTrimValue[i], i*TRIM_W, 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmFadeIn = lv_label_create(container);
|
|
|
|
|
fmStyle.setFadeStyle(fmFadeIn);
|
|
|
|
|
|
|
|
|
|
fmFadeOut = lv_label_create(container);
|
|
|
|
|
fmStyle.setFadeStyle(fmFadeOut);
|
|
|
|
|
|
|
|
|
|
init = true;
|
|
|
|
|
refresh();
|
|
|
|
|
|
|
|
|
|
lv_obj_enable_style_refresh(true);
|
|
|
|
|
|
|
|
|
|
lv_obj_update_layout(lvobj);
|
|
|
|
|
|
|
|
|
|
if (e) {
|
|
|
|
|
auto param = lv_event_get_param(e);
|
|
|
|
|
lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto h = lv_obj_get_height(lvobj);
|
|
|
|
|
y = (h - getFontHeight(txt_flags)) / 2;
|
|
|
|
|
|
|
|
|
|
const auto& fm = g_model.flightModeData[index];
|
|
|
|
|
if (fm.name[0] != '\0') {
|
|
|
|
|
dc->drawSizedText(x, y, fm.name, sizeof(fm.name), txt_flags);
|
|
|
|
|
} else {
|
|
|
|
|
bool isActive() const
|
|
|
|
|
{
|
|
|
|
|
return (getFlightMode() == index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void checkEvents() override
|
|
|
|
|
{
|
|
|
|
|
Button::checkEvents();
|
|
|
|
|
check(isActive());
|
|
|
|
|
if (!refreshing && init) {
|
|
|
|
|
refreshing = true;
|
|
|
|
|
const auto& fm = g_model.flightModeData[index];
|
|
|
|
|
for (int t = 0; t < NUM_TRIMS; t += 1) {
|
|
|
|
|
if (lastTrim[t] != fm.trim[t].value) {
|
|
|
|
|
lastTrim[t] = fm.trim[t].value;
|
|
|
|
|
|
|
|
|
|
uint8_t mode = fm.trim[t].mode;
|
|
|
|
|
bool checked = (mode != TRIM_MODE_NONE);
|
|
|
|
|
bool showValue = (index == 0) || ((mode & 1) || (mode >> 1 == index));
|
|
|
|
|
|
|
|
|
|
if (checked && showValue)
|
|
|
|
|
lv_label_set_text(fmTrimValue[t], formatNumberAsString(fm.trim[t].value).c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
refreshing = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void refresh()
|
|
|
|
|
{
|
|
|
|
|
if (!init) return;
|
|
|
|
|
|
|
|
|
|
const auto& fm = g_model.flightModeData[index];
|
|
|
|
|
|
|
|
|
|
char label[8];
|
|
|
|
|
getFlightModeString(label, index + 1);
|
|
|
|
|
dc->drawSizedText(x, y, label, sizeof(label), txt_flags);
|
|
|
|
|
lv_label_set_text(fmID, label);
|
|
|
|
|
|
|
|
|
|
if (fm.name[0] != '\0') {
|
|
|
|
|
lv_label_set_text(fmName, fm.name);
|
|
|
|
|
} else {
|
|
|
|
|
lv_label_set_text(fmName, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((index > 0) && (fm.swtch != SWSRC_NONE)) {
|
|
|
|
|
getSwitchPositionName(label, fm.swtch);
|
|
|
|
|
lv_label_set_text(fmSwitch, label);
|
|
|
|
|
} else {
|
|
|
|
|
lv_label_set_text(fmSwitch, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_TRIMS; i += 1) {
|
|
|
|
|
uint8_t mode = fm.trim[i].mode;
|
|
|
|
|
bool checked = (mode != TRIM_MODE_NONE);
|
|
|
|
|
bool showValue = (index == 0) || ((mode & 1) || (mode >> 1 == index));
|
|
|
|
|
|
|
|
|
|
lv_label_set_text(fmTrimMode[i], getFMTrimStr(mode, false).c_str());
|
|
|
|
|
|
|
|
|
|
if (checked && showValue)
|
|
|
|
|
lv_label_set_text(fmTrimValue[i], formatNumberAsString(fm.trim[i].value).c_str());
|
|
|
|
|
else
|
|
|
|
|
lv_label_set_text(fmTrimValue[i], "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lv_label_set_text(fmFadeIn, formatNumberAsString(fm.fadeIn, PREC1, 0, nullptr, "s").c_str());
|
|
|
|
|
lv_label_set_text(fmFadeOut, formatNumberAsString(fm.fadeOut, PREC1, 0, nullptr, "s").c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((index > 0) && (fm.swtch != SWSRC_NONE)) {
|
|
|
|
|
char sw[8];
|
|
|
|
|
getSwitchPositionName(sw, fm.swtch);
|
|
|
|
|
protected:
|
|
|
|
|
bool init = false;
|
|
|
|
|
bool refreshing = false;
|
|
|
|
|
uint8_t index;
|
|
|
|
|
|
|
|
|
|
x = lv_obj_get_width(lvobj) - 8;
|
|
|
|
|
dc->drawSizedText(x, y, sw, sizeof(sw), txt_flags | RIGHT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FlightModeBtn::onPress()
|
|
|
|
|
{
|
|
|
|
|
new FlightModeEdit(index);
|
|
|
|
|
}
|
|
|
|
|
lv_obj_t* fmID = nullptr;
|
|
|
|
|
lv_obj_t* fmName = nullptr;
|
|
|
|
|
lv_obj_t* fmSwitch = nullptr;
|
|
|
|
|
lv_obj_t* fmTrimMode[NUM_TRIMS] = {nullptr};
|
|
|
|
|
lv_obj_t* fmTrimValue[NUM_TRIMS] = {nullptr};
|
|
|
|
|
lv_obj_t* fmFadeIn = nullptr;
|
|
|
|
|
lv_obj_t* fmFadeOut = nullptr;
|
|
|
|
|
int lastTrim[NUM_TRIMS];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ModelFlightModesPage::ModelFlightModesPage():
|
|
|
|
|
PageTab(STR_MENUFLIGHTMODES, ICON_MODEL_FLIGHT_MODES)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if LCD_W > LCD_H
|
|
|
|
|
// FM table: 3 x 3
|
|
|
|
|
static const lv_coord_t fmt_col_dsc[] = {LV_GRID_FR(1),
|
|
|
|
|
LV_GRID_FR(1),
|
|
|
|
|
LV_GRID_FR(1),
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
|
|
|
|
|
static const lv_coord_t fmt_row_dsc[] = {LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
#else
|
|
|
|
|
// FM table: 2 x 5
|
|
|
|
|
static const lv_coord_t fmt_col_dsc[] = {LV_GRID_FR(1),
|
|
|
|
|
LV_GRID_FR(1),
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
|
|
|
|
|
static const lv_coord_t fmt_row_dsc[] = {LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_CONTENT,
|
|
|
|
|
LV_GRID_TEMPLATE_LAST};
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void ModelFlightModesPage::build(FormWindow * window)
|
|
|
|
|
{
|
|
|
|
|
window->setFlexLayout();
|
|
|
|
|
window->padRow(lv_dpx(8));
|
|
|
|
|
|
|
|
|
|
lv_obj_t* obj = window->getLvObj();
|
|
|
|
|
lv_obj_set_style_flex_cross_place(obj, LV_FLEX_ALIGN_CENTER, 0);
|
|
|
|
|
window->padAll(4);
|
|
|
|
|
lv_obj_set_scrollbar_mode(window->getLvObj(), LV_SCROLLBAR_MODE_AUTO);
|
|
|
|
|
|
|
|
|
|
FormWindow* form = new FormWindow(window, rect_t{});
|
|
|
|
|
form->setFlexLayout(LV_FLEX_FLOW_COLUMN, 2);
|
|
|
|
|
form->padRow(lv_dpx(4));
|
|
|
|
|
|
|
|
|
|
FlexGridLayout grid(fmt_col_dsc, fmt_row_dsc, 0);
|
|
|
|
|
auto fm_box = window->newLine(&grid);
|
|
|
|
|
fm_box->padRow(lv_dpx(2));
|
|
|
|
|
fm_box->padColumn(lv_dpx(2));
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_FLIGHT_MODES; i++) {
|
|
|
|
|
new FlightModeBtn(fm_box, i);
|
|
|
|
|
auto btn = new FlightModeBtn(form, i);
|
|
|
|
|
btn->setPressHandler([=]() {
|
|
|
|
|
new FlightModeEdit(i);
|
|
|
|
|
return 0;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new TextButton(window, rect_t{}, STR_CHECKTRIMS, [&]() -> uint8_t {
|
|
|
|
|
trimCheck = new TextButton(form, rect_t{0, 0, lv_pct(100), 40}, STR_CHECKTRIMS, [&]() -> uint8_t {
|
|
|
|
|
if (trimsCheckTimer)
|
|
|
|
|
trimsCheckTimer = 0;
|
|
|
|
|
else
|
|
|
|
@@ -332,3 +541,8 @@ void ModelFlightModesPage::build(FormWindow * window)
|
|
|
|
|
return trimsCheckTimer;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ModelFlightModesPage::checkEvents()
|
|
|
|
|
{
|
|
|
|
|
trimCheck->check(trimsCheckTimer > 0);
|
|
|
|
|
}
|
|
|
|
|