feat(color): More compact Flight Mode list and edit views (#3344)

* Flight mode list and edit changes:
- Update trim ranges in Companion to match radio.
- Move trims setup to main edit view instead of dialog popup.
- Show/edit current trim value for each trim (if enabled)

* Show flight mode list view like logical switches.

* Update FM trim values in edit window if trim is changed (via trim switch).

* Use styles for layout

* Remove grid layouts - use flex flow as it is faster.

* Speed up page build time.
Reduces build time on TX16S Mk2 from ~320ms to ~25ms.

* Fix touch screen events.
This commit is contained in:
philmoz
2023-03-27 11:43:44 +10:00
committed by GitHub
parent 7e581d00dd
commit ebef94d993
4 changed files with 447 additions and 229 deletions
@@ -575,9 +575,9 @@ int OpenTxFirmware::getCapability(::Capability capability)
case ExtraInputs:
return 1;
case TrimsRange:
return 125;
return 128;
case ExtendedTrimsRange:
return 500;
return 512;
case Simulation:
return 1;
case NumCurves:
+439 -225
View File
@@ -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);
}
+6 -1
View File
@@ -25,5 +25,10 @@ class ModelFlightModesPage: public PageTab {
public:
ModelFlightModesPage();
void build(FormWindow * window);
void checkEvents() override;
void build(FormWindow * window) override;
protected:
TextButton* trimCheck = nullptr;
};
-1
View File
@@ -75,7 +75,6 @@ enum SwitchContext
int circularIncDec(int current, int inc, int min, int max, IsValueAvailable isValueAvailable=nullptr);
int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable);
bool isTrimModeAvailable(int mode);
bool isInputAvailable(int input);
bool isSourceAvailableInInputs(int source);
bool isThrottleSourceAvailable(int source);