From 7a1231753ae75cdbb6916d1c916dcc35ef90c158 Mon Sep 17 00:00:00 2001 From: philmoz Date: Sat, 28 Jan 2023 13:28:18 +1100 Subject: [PATCH] feat(color): Change global variables layout to better match other pages (#3116) * Change global variables layout to better match other pages. * Move internal classes for global variable page from .h to .cpp file. Convert header text in edit page to StaticText object and remove 'paint' function. * Fix build error. * chore: Formatting --- radio/src/gui/colorlcd/model_gvars.cpp | 727 +++++++++++++------------ radio/src/gui/colorlcd/model_gvars.h | 87 +-- radio/src/strhelpers.cpp | 19 + radio/src/strhelpers.h | 3 + 4 files changed, 397 insertions(+), 439 deletions(-) diff --git a/radio/src/gui/colorlcd/model_gvars.cpp b/radio/src/gui/colorlcd/model_gvars.cpp index fad2f8e33..719deb3cc 100644 --- a/radio/src/gui/colorlcd/model_gvars.cpp +++ b/radio/src/gui/colorlcd/model_gvars.cpp @@ -22,421 +22,430 @@ #include "opentx.h" #include "model_gvars.h" #include "libopenui.h" +#include "numberedit.h" +#include "lvgl_widgets/input_mix_line.h" -#define SET_DIRTY() storageDirty(EE_MODEL) +#define SET_DIRTY() storageDirty(EE_MODEL) #define TEXT_LEFT_MARGIN 2 -#define GVAR_NAME_SIZE 45 +#define GVAR_NAME_SIZE 44 +#if LCD_W > LCD_H +#define GVAR_VAL_SIZE 45 +#define GVAR_TTL_OFST 6 +#else +#define GVAR_VAL_SIZE 50 +#define GVAR_TTL_OFST 24 +#endif -static const lv_coord_t btn_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(2), - LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t btn_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; - -GVarButton::GVarButton(FormGroup * parent, const rect_t &rect, uint8_t gvar) : - Button(parent, rect, nullptr, 0, 0, lv_btn_create), - gvarIdx(gvar) +class GVarButton : public Button { - setHeight(LV_SIZE_CONTENT); - setWidth(LV_PCT(100)); + public: + GVarButton(FormGroup* parent, const rect_t& rect, uint8_t gvar) : + Button(parent, rect, nullptr, 0, 0, input_mix_line_create), gvarIdx(gvar) + { + setHeight(LV_SIZE_CONTENT); + setWidth(LV_PCT(100)); - build(); -} - -void GVarButton::checkEvents() -{ - Button::checkEvents(); - uint8_t newFM = getFlightMode(); - if (currentFlightMode != newFM) { - uint8_t lastFM = currentFlightMode; - currentFlightMode = newFM; - - labels[lastFM]->setFont(FONT(STD)); - labels[currentFlightMode]->setFont(FONT(BOLD)); - updateValueText(lastFM); - updateValueText(currentFlightMode); + build(); } - for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { - FlightModeData * fmData = &g_model.flightModeData[flightMode]; - if(values[flightMode] != fmData->gvars[gvarIdx]) - { + + protected: + void checkEvents() + { + Button::checkEvents(); + uint8_t newFM = getFlightMode(); + if (currentFlightMode != newFM) { + uint8_t lastFM = currentFlightMode; + currentFlightMode = newFM; + + labels[lastFM]->setBackgroundColor(COLOR_THEME_PRIMARY2); + labels[currentFlightMode]->setBackgroundColor(COLOR_THEME_SECONDARY3); + updateValueText(lastFM); + updateValueText(currentFlightMode); + } + for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { + FlightModeData* fmData = &g_model.flightModeData[flightMode]; + if (values[flightMode] != fmData->gvars[gvarIdx]) { + updateValueText(flightMode); + } + } + } + + protected: + uint8_t gvarIdx; + int lines; + int32_t gvarSum = 0; // used for invalidation + uint8_t currentFlightMode = 0; // used for invalidation + StaticText* labels[MAX_FLIGHT_MODES]; + StaticText* valueTexts[MAX_FLIGHT_MODES]; + gvar_t values[MAX_FLIGHT_MODES]; + + void build() + { + lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); + lv_obj_set_style_pad_all(lvobj, 0, LV_PART_MAIN); + + auto t = + new StaticText(this, rect_t{0, 0, GVAR_NAME_SIZE, PAGE_LINE_HEIGHT}, + getGVarString(gvarIdx), 0, COLOR_THEME_SECONDARY1); + t->padLeft(1); + t->padTop(GVAR_TTL_OFST); + + Window* container = new Window(this, rect_t{}); + lv_obj_set_style_pad_all(container->getLvObj(), 0, LV_PART_MAIN); + lv_obj_set_style_flex_grow(container->getLvObj(), 2, LV_PART_MAIN); + lv_obj_set_height(container->getLvObj(), LV_SIZE_CONTENT); + lv_obj_set_flex_flow(container->getLvObj(), LV_FLEX_FLOW_ROW_WRAP); + + for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { + Window* fmCont = new Window(container, rect_t{}); + fmCont->padAll(0); + + lv_obj_set_width(fmCont->getLvObj(), GVAR_VAL_SIZE); + lv_obj_set_height(fmCont->getLvObj(), PAGE_LINE_HEIGHT * 2 - 6); + lv_obj_set_flex_flow(fmCont->getLvObj(), LV_FLEX_FLOW_COLUMN); + + char label[16] = {}; + getFlightModeString(label, flightMode + 1); + + labels[flightMode] = new StaticText(fmCont, rect_t{}, label, 0, + COLOR_THEME_SECONDARY1 | CENTERED); + labels[flightMode]->setHeight(PAGE_LINE_HEIGHT - 6); + labels[flightMode]->setWidth(GVAR_VAL_SIZE); + labels[flightMode]->setFont(FONT(XS)); + labels[flightMode]->setBackgroundColor(COLOR_THEME_PRIMARY2); + labels[flightMode]->setBackgroudOpacity(LV_OPA_COVER); + + valueTexts[flightMode] = new StaticText( + fmCont, rect_t{}, "", 0, COLOR_THEME_SECONDARY1 | CENTERED); + StaticText* valText = valueTexts[flightMode]; + if (flightMode == currentFlightMode) { + labels[flightMode]->setBackgroundColor(COLOR_THEME_SECONDARY3); + } + + lv_obj_set_style_flex_track_place(valText->getLvObj(), LV_FLEX_ALIGN_END, + LV_PART_MAIN); + valText->setWidth(GVAR_VAL_SIZE); + valText->setBackgroundColor(COLOR_THEME_PRIMARY2); + valText->setBackgroudOpacity(LV_OPA_COVER); + valText->setHeight(PAGE_LINE_HEIGHT); + valText->setFont(FONT(STD)); + updateValueText(flightMode); } } -} -void GVarButton::build() -{ - lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); - lv_obj_set_style_pad_all(lvobj, 0, LV_PART_MAIN); - lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN); - lv_obj_set_style_bg_opa(lvobj, LV_OPA_COVER, LV_PART_MAIN); + void updateValueText(uint8_t flightMode) + { + StaticText* field = valueTexts[flightMode]; + gvar_t value = g_model.flightModeData[flightMode].gvars[gvarIdx]; + values[flightMode] = value; - auto t = new StaticText(this, rect_t{}, getGVarString(gvarIdx), 0, COLOR_THEME_PRIMARY1); - t->setWidth(GVAR_NAME_SIZE); - Window* container = new Window(this, rect_t{}); - lv_obj_set_style_pad_all(container->getLvObj(), 0, LV_PART_MAIN); - lv_obj_set_style_flex_grow(container->getLvObj(), 2, LV_PART_MAIN); - lv_obj_set_height(container->getLvObj(), LV_SIZE_CONTENT); - lv_obj_set_flex_flow(container->getLvObj(), LV_FLEX_FLOW_ROW_WRAP); + if (value > GVAR_MAX) { + uint8_t fm = value - GVAR_MAX - 1; + if (fm >= flightMode) fm += 1; + char label[16] = {}; + getFlightModeString(label, fm + 1); - for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { - Window* fmCont = new Window(container, rect_t{}); - - lv_obj_set_width(fmCont->getLvObj(), GVAR_NAME_SIZE); - lv_obj_set_height(fmCont->getLvObj(), PAGE_LINE_HEIGHT*2); - lv_obj_set_style_pad_hor(fmCont->getLvObj(), 3, LV_PART_MAIN); - - char label[16] = {}; - getFlightModeString(label, flightMode + 1); - lv_obj_set_flex_flow(fmCont->getLvObj(), LV_FLEX_FLOW_COLUMN); - - labels[flightMode] = new StaticText(fmCont, rect_t{}, label, 0, COLOR_THEME_PRIMARY1|CENTERED); - labels[flightMode]->setHeight(PAGE_LINE_HEIGHT); - labels[flightMode]->setWidth(GVAR_NAME_SIZE); - - valueTexts[flightMode] = new StaticText(fmCont, rect_t{}, "", 0, COLOR_THEME_PRIMARY1|CENTERED); - StaticText* valText = valueTexts[flightMode]; - if (flightMode == currentFlightMode) - { - labels[flightMode]->setFont(FONT(BOLD)); - valText->setFont(FONT(BOLD)); - } - - lv_obj_set_style_flex_track_place(valText->getLvObj(), LV_FLEX_ALIGN_END, LV_PART_MAIN); - valText->setWidth(GVAR_NAME_SIZE); - valText->setBackgroundColor(COLOR_THEME_PRIMARY2); - valText->setBackgroudOpacity(LV_OPA_COVER); - valText->setHeight(PAGE_LINE_HEIGHT); - - updateValueText(flightMode); - } -} - -void GVarButton::updateValueText(uint8_t flightMode) -{ - StaticText* field = valueTexts[flightMode]; - gvar_t value = g_model.flightModeData[flightMode].gvars[gvarIdx]; - values[flightMode] = value; - - if (value > GVAR_MAX) { - uint8_t fm = value - GVAR_MAX - 1; - if (fm >= flightMode) - fm += 1; - char label[16] = {}; - getFlightModeString(label, fm + 1); - - lv_label_set_text(field->getLvObj(), label); - - if(flightMode == currentFlightMode) - field->setFont(FONT(BOLD)); - else - field->setFont(FONT(STD)); - } else { - uint8_t unit = g_model.gvars[gvarIdx].unit; - const char * suffix = (unit == 1) ? "%": ""; - uint8_t prec = g_model.gvars[gvarIdx].prec; - if(prec) - lv_label_set_text_fmt(field->getLvObj(), "%d.%01u%s", value/10, (value<0)?(-value)%10:value%10, suffix); - else - lv_label_set_text_fmt(field->getLvObj(), "%d%s", value, suffix); - if(unit) - { - if (value <= -1000 || value >= 1000 - || (prec && (value <= -100)) ) { - field->setFont(FONT(XS)); - } else if (value <= -100) { - field->setFont(FONT(STD)); - } else { - if(flightMode == currentFlightMode) - field->setFont(FONT(BOLD)); - else - field->setFont(FONT(STD)); - } + lv_label_set_text(field->getLvObj(), label); } else { - if(value > -1000 && flightMode == currentFlightMode) - field->setFont(FONT(BOLD)); + uint8_t unit = g_model.gvars[gvarIdx].unit; + const char* suffix = (unit == 1) ? "%" : ""; + uint8_t prec = g_model.gvars[gvarIdx].prec; + if (prec) + lv_label_set_text_fmt(field->getLvObj(), "%d.%01u%s", value / 10, + (value < 0) ? (-value) % 10 : value % 10, suffix); else - field->setFont(FONT(STD)); + lv_label_set_text_fmt(field->getLvObj(), "%d%s", value, suffix); + if (unit) { + if (value <= -1000 || value >= 1000 || (prec && (value <= -100))) { + field->setFont(FONT(XS)); + } else if (value <= -100) { + field->setFont(FONT(STD)); + } + } } + if (flightMode == currentFlightMode) + field->setBackgroundColor(COLOR_THEME_SECONDARY3); + else + field->setBackgroundColor(COLOR_THEME_PRIMARY2); } -} +}; -void GVarRenderer::paint(BitmapBuffer * dc) +class GVarEditWindow : public Page { - lastFlightMode = getFlightMode(); - FlightModeData * fmData = &g_model.flightModeData[lastFlightMode]; - lastGVar = fmData->gvars[index]; - coord_t x = drawStringWithIndex(dc, 0, FIELD_PADDING_TOP, STR_GV, index + 1, - COLOR_THEME_PRIMARY2, nullptr, "="); - if (lastGVar > GVAR_MAX) { - uint8_t fm = lastGVar - GVAR_MAX - 1; - if (fm >= lastFlightMode) - fm++; - char label[16]; - getFlightModeString(label, fm + 1); - dc->drawSizedText(x, FIELD_PADDING_TOP, label, strlen(label), COLOR_THEME_PRIMARY2); - } else { - drawGVarValue(dc, x, FIELD_PADDING_TOP, index, lastGVar, COLOR_THEME_PRIMARY2); + public: + explicit GVarEditWindow(uint8_t gvarIndex) : + Page(ICON_MODEL_GVARS), index(gvarIndex) + { + buildHeader(&header); + buildBody(&body); } -} -void GVarRenderer::checkEvents() -{ - if (lastFlightMode != getFlightMode()) { - invalidate(); - updated = true; - } - if (lastGVar != g_model.flightModeData[getFlightMode()].gvars[index]) { - invalidate(); - updated = true; - } -} + protected: + uint8_t index; + gvar_t lastGVar = 0; + uint8_t lastFlightMode = 0; + NumberEdit* min = nullptr; + NumberEdit* max = nullptr; + NumberEdit* values[MAX_FLIGHT_MODES] = {}; + StaticText* gVarInHeader = nullptr; -bool GVarRenderer::isUpdated() -{ - if (!updated) - return false; - updated = false; - return true; -} - -void GVarEditWindow::buildHeader(Window * window) -{ - header.setTitle(STR_GLOBAL_VAR); - gVarInHeader = - new GVarRenderer(window, + void buildHeader(Window* window) + { + header.setTitle(STR_GLOBAL_VAR); + gVarInHeader = + new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, - index); -} + "", 0, COLOR_THEME_PRIMARY2); + } -void GVarEditWindow::checkEvents() -{ - Page::checkEvents(); - if (gVarInHeader && gVarInHeader->isUpdated()) { - for (auto & value : values) { - value->invalidate(); + void checkEvents() + { + Page::checkEvents(); + if (gVarInHeader && + ((lastFlightMode != getFlightMode()) || + (lastGVar != g_model.flightModeData[getFlightMode()].gvars[index]))) { + char label[32]; + lastFlightMode = getFlightMode(); + FlightModeData* fmData = &g_model.flightModeData[lastFlightMode]; + lastGVar = fmData->gvars[index]; + sprintf(label, "%s%d=", STR_GV, index + 1); + if (lastGVar > GVAR_MAX) { + uint8_t fm = lastGVar - GVAR_MAX - 1; + if (fm >= lastFlightMode) fm++; + getFlightModeString(label + strlen(label), fm + 1); + } else { + strcat(label, getGVarValue(index, lastGVar, 0).c_str()); + } + gVarInHeader->setText(label); + for (auto& value : values) { + value->invalidate(); + } } } -} -void GVarEditWindow::setProperties(int onlyForFlightMode) -{ - GVarData * gvar = &g_model.gvars[index]; - int32_t minValue = GVAR_MIN + gvar->min; - int32_t maxValue = GVAR_MAX - gvar->max; - const char * suffix = gvar->unit ? "%" : ""; + void setProperties(int onlyForFlightMode = -1) + { + GVarData* gvar = &g_model.gvars[index]; + int32_t minValue = GVAR_MIN + gvar->min; + int32_t maxValue = GVAR_MAX - gvar->max; + const char* suffix = gvar->unit ? "%" : ""; - LcdFlags prec = gvar->prec ? PREC1 : 0; - if (min && max) { - min->setMax(maxValue); - max->setMin(minValue); + LcdFlags prec = gvar->prec ? PREC1 : 0; + if (min && max) { + min->setMax(maxValue); + max->setMin(minValue); - min->setSuffix(suffix); - max->setSuffix(suffix); + min->setSuffix(suffix); + max->setSuffix(suffix); - LcdFlags minFlags = min->getTextFlags(); - LcdFlags maxFlags = max->getTextFlags(); - if(gvar->prec) { - minFlags |= PREC1; - maxFlags |= PREC1; - } else { - minFlags &= ~PREC1; - maxFlags &= ~PREC1; + LcdFlags minFlags = min->getTextFlags(); + LcdFlags maxFlags = max->getTextFlags(); + if (gvar->prec) { + minFlags |= PREC1; + maxFlags |= PREC1; + } else { + minFlags &= ~PREC1; + maxFlags &= ~PREC1; + } + min->setTextFlags(minFlags); + max->setTextFlags(maxFlags); + + min->update(); + max->update(); } - min->setTextFlags(minFlags); - max->setTextFlags(maxFlags); + FlightModeData* fmData; + for (int fm = 0; fm < MAX_FLIGHT_MODES; fm++) { + if (values[fm] == nullptr) // KLK: the order of calls has changed and + // this might not be initialized yet. + continue; - min->update(); - max->update(); - } - FlightModeData * fmData; - for (int fm = 0; fm < MAX_FLIGHT_MODES; fm++) { - if (values[fm] == nullptr) // KLK: the order of calls has changed and this might not be initialized yet. - continue; + if (onlyForFlightMode >= 0 && fm != onlyForFlightMode) continue; + fmData = &g_model.flightModeData[fm]; - if (onlyForFlightMode >= 0 && fm != onlyForFlightMode) - continue; - fmData = &g_model.flightModeData[fm]; + // custom value + if (fmData->gvars[index] <= GVAR_MAX || fm == 0) { + values[fm]->setMin(GVAR_MIN + gvar->min); + values[fm]->setMax(GVAR_MAX - gvar->max); - // custom value - if (fmData->gvars[index] <= GVAR_MAX || fm == 0) { - values[fm]->setMin(GVAR_MIN + gvar->min); - values[fm]->setMax(GVAR_MAX - gvar->max); + LcdFlags flags = values[fm]->getTextFlags(); + if (gvar->prec) + flags |= PREC1; + else + flags &= ~PREC1; + values[fm]->setTextFlags(flags); - LcdFlags flags = values[fm]->getTextFlags(); - if(gvar->prec) - flags |= PREC1; - else - flags &= ~PREC1; - values[fm]->setTextFlags(flags); - - values[fm]->setDisplayHandler(nullptr); - } - else { - values[fm]->setMin(GVAR_MAX + 1); - values[fm]->setMax(GVAR_MAX + MAX_FLIGHT_MODES - 1); - values[fm]->setDisplayHandler([=](int32_t value) { + values[fm]->setDisplayHandler(nullptr); + } else { + values[fm]->setMin(GVAR_MAX + 1); + values[fm]->setMax(GVAR_MAX + MAX_FLIGHT_MODES - 1); + values[fm]->setDisplayHandler([=](int32_t value) { uint8_t targetFlightMode = value - GVAR_MAX - 1; - if (targetFlightMode >= fm) - targetFlightMode++; + if (targetFlightMode >= fm) targetFlightMode++; char label[16]; getFlightModeString(label, targetFlightMode + 1); return std::string(label); - }); - } - - values[fm]->setSuffix(suffix); - values[fm]->invalidate(); - } - if (gVarInHeader) gVarInHeader->invalidate(); -} - -static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(2), - LV_GRID_TEMPLATE_LAST}; -static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, - LV_GRID_TEMPLATE_LAST}; - - -void GVarEditWindow::buildBody(FormWindow * window) -{ - window->setFlexLayout(); - FlexGridLayout grid(col_dsc, row_dsc, 2); - auto line = window->newLine(&grid); - - GVarData * gvar = &g_model.gvars[index]; - - new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); - grid.nextCell(); - Window* input = new ModelTextEdit(line, rect_t{}, gvar->name, LEN_GVAR_NAME); - lv_obj_set_style_grid_cell_x_align(input->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - line = window->newLine(&grid); - - new StaticText(line, rect_t{}, STR_UNIT, 0, COLOR_THEME_PRIMARY1); - grid.nextCell(); - input = new Choice(line, rect_t{}, "\001-%", 0, 1, GET_DEFAULT(gvar->unit), - [=](int16_t newValue) { - gvar->unit = newValue; - SET_DIRTY(); - setProperties(); - } - ); - lv_obj_set_style_grid_cell_x_align(input->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - line = window->newLine(&grid); - - new StaticText(line, rect_t{}, STR_PRECISION, 0, COLOR_THEME_PRIMARY1); - grid.nextCell(); - input = new Choice(line, rect_t{}, STR_VPREC, 0, 1, GET_DEFAULT(gvar->prec), - [=](int16_t newValue) { - gvar->prec = newValue; - SET_DIRTY(); - setProperties(); - } - ); - lv_obj_set_style_grid_cell_x_align(input->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - line = window->newLine(&grid); - - new StaticText(line, rect_t{}, STR_MIN, 0, COLOR_THEME_PRIMARY1); - grid.nextCell(); - min = new NumberEdit(line, rect_t{}, GVAR_MIN, GVAR_MAX - gvar->max, - [=] { return gvar->min + GVAR_MIN; }, - [=](int32_t newValue) { - gvar->min = newValue - GVAR_MIN; - SET_DIRTY(); - setProperties(); - } - ); - min->setAccelFactor(16); - lv_obj_set_style_grid_cell_x_align(min->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - line = window->newLine(&grid); - - new StaticText(line, rect_t{}, STR_MAX, 0, COLOR_THEME_PRIMARY1); - grid.nextCell(); - max = new NumberEdit(line, rect_t{}, GVAR_MIN + gvar->min, GVAR_MAX, - [=] { return GVAR_MAX - gvar->max; }, - [=](int32_t newValue) { - gvar->max = GVAR_MAX - newValue; - SET_DIRTY(); - setProperties(); - } - ); - max->setAccelFactor(16); - lv_obj_set_style_grid_cell_x_align(max->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); - - line = window->newLine(&grid); - char flightModeName[16]; - FlightModeData * fmData; - - for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { - fmData = &g_model.flightModeData[flightMode]; - getFlightModeString(flightModeName, flightMode + 1); - - int userNameLen = zlen(fmData->name, LEN_FLIGHT_MODE_NAME); - - if (userNameLen > 0) { - strcpy(flightModeName, fmData->name); - } - new StaticText(line, rect_t{}, flightModeName, 0, COLOR_THEME_PRIMARY1); - if (flightMode > 0) { - auto cb = new CheckBox(line, rect_t{}, - [=] { return fmData->gvars[index] <= GVAR_MAX; }, [=](uint8_t checked) { - fmData->gvars[index] = checked ? 0 : GVAR_MAX + 1; - setProperties(flightMode); }); - lv_obj_set_style_grid_cell_x_align(cb->getLvObj(), LV_GRID_ALIGN_END, 0); - lv_obj_invalidate(cb->getLvObj()); - cb->setLabel(STR_OWN); + } - } else { - grid.nextCell(); + values[fm]->setSuffix(suffix); + values[fm]->invalidate(); } - - values[flightMode] = new NumberEdit(line, rect_t{}, GVAR_MIN + gvar->min, GVAR_MAX + MAX_FLIGHT_MODES - 1, - GET_SET_DEFAULT(fmData->gvars[index])); - values[flightMode]->setAccelFactor(16); - line = window->newLine(&grid); + if (gVarInHeader) gVarInHeader->invalidate(); } - setProperties(); - lv_obj_set_height(window->getLvObj(), LCD_H - lv_obj_get_height(header.getLvObj())); - lv_obj_set_height(lvobj, LCD_H); -} + void buildBody(FormWindow* window) + { + static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; + static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; -void ModelGVarsPage::rebuild(FormWindow * window) + window->setFlexLayout(); + window->padAll(4); + FlexGridLayout grid(col_dsc, row_dsc, 2); + auto line = window->newLine(&grid); + + GVarData* gvar = &g_model.gvars[index]; + + new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); + grid.nextCell(); + Window* input = + new ModelTextEdit(line, rect_t{}, gvar->name, LEN_GVAR_NAME); + lv_obj_set_style_grid_cell_x_align(input->getLvObj(), LV_GRID_ALIGN_STRETCH, + 0); + + line = window->newLine(&grid); + + new StaticText(line, rect_t{}, STR_UNIT, 0, COLOR_THEME_PRIMARY1); + grid.nextCell(); + input = new Choice(line, rect_t{}, "\001-%", 0, 1, GET_DEFAULT(gvar->unit), + [=](int16_t newValue) { + gvar->unit = newValue; + SET_DIRTY(); + setProperties(); + }); + lv_obj_set_style_grid_cell_x_align(input->getLvObj(), LV_GRID_ALIGN_STRETCH, + 0); + + line = window->newLine(&grid); + + new StaticText(line, rect_t{}, STR_PRECISION, 0, COLOR_THEME_PRIMARY1); + grid.nextCell(); + input = new Choice(line, rect_t{}, STR_VPREC, 0, 1, GET_DEFAULT(gvar->prec), + [=](int16_t newValue) { + gvar->prec = newValue; + SET_DIRTY(); + setProperties(); + }); + lv_obj_set_style_grid_cell_x_align(input->getLvObj(), LV_GRID_ALIGN_STRETCH, + 0); + + line = window->newLine(&grid); + + new StaticText(line, rect_t{}, STR_MIN, 0, COLOR_THEME_PRIMARY1); + grid.nextCell(); + min = new NumberEdit( + line, rect_t{}, GVAR_MIN, GVAR_MAX - gvar->max, + [=] { return gvar->min + GVAR_MIN; }, + [=](int32_t newValue) { + gvar->min = newValue - GVAR_MIN; + SET_DIRTY(); + setProperties(); + }); + min->setAccelFactor(16); + lv_obj_set_style_grid_cell_x_align(min->getLvObj(), LV_GRID_ALIGN_STRETCH, + 0); + + line = window->newLine(&grid); + + new StaticText(line, rect_t{}, STR_MAX, 0, COLOR_THEME_PRIMARY1); + grid.nextCell(); + max = new NumberEdit( + line, rect_t{}, GVAR_MIN + gvar->min, GVAR_MAX, + [=] { return GVAR_MAX - gvar->max; }, + [=](int32_t newValue) { + gvar->max = GVAR_MAX - newValue; + SET_DIRTY(); + setProperties(); + }); + max->setAccelFactor(16); + lv_obj_set_style_grid_cell_x_align(max->getLvObj(), LV_GRID_ALIGN_STRETCH, + 0); + + line = window->newLine(&grid); + char flightModeName[16]; + FlightModeData* fmData; + + for (int flightMode = 0; flightMode < MAX_FLIGHT_MODES; flightMode++) { + fmData = &g_model.flightModeData[flightMode]; + getFlightModeString(flightModeName, flightMode + 1); + + int userNameLen = zlen(fmData->name, LEN_FLIGHT_MODE_NAME); + + if (userNameLen > 0) { + strcpy(flightModeName, fmData->name); + } + new StaticText(line, rect_t{}, flightModeName, 0, COLOR_THEME_PRIMARY1); + if (flightMode > 0) { + auto cb = new CheckBox( + line, rect_t{}, [=] { return fmData->gvars[index] <= GVAR_MAX; }, + [=](uint8_t checked) { + fmData->gvars[index] = checked ? 0 : GVAR_MAX + 1; + setProperties(flightMode); + }); + lv_obj_set_style_grid_cell_x_align(cb->getLvObj(), LV_GRID_ALIGN_END, + 0); + lv_obj_invalidate(cb->getLvObj()); + cb->setLabel(STR_OWN); + + } else { + grid.nextCell(); + } + + values[flightMode] = new NumberEdit( + line, rect_t{}, GVAR_MIN + gvar->min, GVAR_MAX + MAX_FLIGHT_MODES - 1, + GET_SET_DEFAULT(fmData->gvars[index])); + values[flightMode]->setAccelFactor(16); + line = window->newLine(&grid); + } + + setProperties(); + lv_obj_set_height(window->getLvObj(), + LCD_H - lv_obj_get_height(header.getLvObj())); + lv_obj_set_height(lvobj, LCD_H); + } +}; + +void ModelGVarsPage::rebuild(FormWindow* window) { - auto scroll_y = lv_obj_get_scroll_y(window->getLvObj()); + auto scroll_y = lv_obj_get_scroll_y(window->getLvObj()); window->clear(); build(window); lv_obj_scroll_to_y(window->getLvObj(), scroll_y, LV_ANIM_OFF); } -void ModelGVarsPage::build(FormWindow * window) +void ModelGVarsPage::build(FormWindow* window) { - window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 1); + window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 2); for (uint8_t index = 0; index < MAX_GVARS; index++) { - Button * button = new GVarButton(window, rect_t{}, index); + Button* button = new GVarButton(window, rect_t{}, index); button->setPressHandler([=]() { - Menu * menu = new Menu(window); - menu->addLine(STR_EDIT, [=]() { - Window * editWindow = new GVarEditWindow(index); - editWindow->setCloseHandler([=]() { - rebuild(window); - }); - }); - menu->addLine(STR_CLEAR, [=]() { - for (auto & flightMode : g_model.flightModeData) { - flightMode.gvars[index] = 0; - } - storageDirty(EE_MODEL); - }); - return 0; + Menu* menu = new Menu(window); + menu->addLine(STR_EDIT, [=]() { + Window* editWindow = new GVarEditWindow(index); + editWindow->setCloseHandler([=]() { rebuild(window); }); + }); + menu->addLine(STR_CLEAR, [=]() { + for (auto& flightMode : g_model.flightModeData) { + flightMode.gvars[index] = 0; + } + storageDirty(EE_MODEL); + }); + return 0; }); - } } diff --git a/radio/src/gui/colorlcd/model_gvars.h b/radio/src/gui/colorlcd/model_gvars.h index 8fad0b637..7663defd1 100644 --- a/radio/src/gui/colorlcd/model_gvars.h +++ b/radio/src/gui/colorlcd/model_gvars.h @@ -21,89 +21,16 @@ #pragma once -#include "tabsgroup.h" #include "page.h" +#include "tabsgroup.h" #include "window.h" -#include "numberedit.h" -class GVarButton: public Button +class ModelGVarsPage : public PageTab { - public: - GVarButton(FormGroup * parent, const rect_t & rect, uint8_t gvar); - - protected: - void checkEvents() override; - - protected: - uint8_t gvarIdx; - int lines; - int32_t gvarSum = 0; // used for invalidation - uint8_t currentFlightMode = 0; // used for invalidation - StaticText* labels[MAX_FLIGHT_MODES]; - StaticText* valueTexts[MAX_FLIGHT_MODES]; - gvar_t values[MAX_FLIGHT_MODES]; - - void build(); - void updateValueText(uint8_t flightMode); + public: + ModelGVarsPage() : PageTab(STR_MENU_GLOBAL_VARS, ICON_MODEL_GVARS) {} -}; - -class ModelGVarsPage: public PageTab -{ - public: - ModelGVarsPage(): - PageTab(STR_MENU_GLOBAL_VARS, ICON_MODEL_GVARS) - { - } - - protected: - void build(FormWindow * window) override; - void rebuild(FormWindow * window); -}; - -class GVarRenderer: public Window -{ - friend class GVarEditWindow; - - public: - GVarRenderer(Window * window, rect_t rect, uint8_t gvarIndex) : - Window(window, rect), - index(gvarIndex) - { - } - - protected: - void paint(BitmapBuffer * dc) override; - void checkEvents() override; - bool isUpdated(); - - protected: - uint8_t index; - gvar_t lastGVar = 0; - uint8_t lastFlightMode = 0; - bool updated = false; -}; - - -class GVarEditWindow: public Page -{ - public: - explicit GVarEditWindow(uint8_t gvarIndex) : - Page(ICON_MODEL_GVARS), - index(gvarIndex) - { - buildHeader(&header); - buildBody(&body); - } - - protected: - uint8_t index; - NumberEdit * min = nullptr; - NumberEdit * max = nullptr; - NumberEdit * values[MAX_FLIGHT_MODES] = {}; - GVarRenderer * gVarInHeader = nullptr; - void buildHeader(Window * window); - void buildBody(FormWindow * window); - void setProperties(int onlyForFlightMode = -1); - void checkEvents() override; + protected: + void build(FormWindow* window) override; + void rebuild(FormWindow* window); }; diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp index b16c70f75..4d48920d9 100644 --- a/radio/src/strhelpers.cpp +++ b/radio/src/strhelpers.cpp @@ -908,6 +908,25 @@ char *getSourceCustomValueString(source_t source, int32_t val, LcdFlags flags) return getSourceCustomValueString(tmpHelpersString, source, val, flags); } +std::string getValueWithUnit(int val, uint8_t unit, LcdFlags flags) +{ + if ((flags & NO_UNIT) || unit == UNIT_RAW) + return formatNumberAsString(val, flags & (~NO_UNIT)); + + return formatNumberAsString(val, flags & (~NO_UNIT), 0, nullptr, + STR_VTELEMUNIT[unit]); +} + +std::string getGVarValue(uint8_t gvar, gvar_t value, LcdFlags flags) +{ + uint8_t prec = g_model.gvars[gvar].prec; + if (prec > 0) { + flags |= (prec == 1 ? PREC1 : PREC2); + } + return getValueWithUnit( + value, g_model.gvars[gvar].unit ? UNIT_PERCENT : UNIT_RAW, flags); +} + #endif // defined(LIBOPENUI) #endif // !defined(BOOT) diff --git a/radio/src/strhelpers.h b/radio/src/strhelpers.h index 08d2eaa88..3c90ec8b3 100644 --- a/radio/src/strhelpers.h +++ b/radio/src/strhelpers.h @@ -152,4 +152,7 @@ int strncasecmp(char (&s1)[L1], const char *const s2) return strncasecmp(s1, s2, L1); } +std::string getValueWithUnit(int val, uint8_t unit, LcdFlags flags); +std::string getGVarValue(uint8_t gvar, gvar_t value, LcdFlags flags); + #endif // _STRHELPERS_H_