diff --git a/radio/src/gui/colorlcd/controls/channel_range.cpp b/radio/src/gui/colorlcd/controls/channel_range.cpp index bdf10714b..4c083b425 100644 --- a/radio/src/gui/colorlcd/controls/channel_range.cpp +++ b/radio/src/gui/colorlcd/controls/channel_range.cpp @@ -37,19 +37,6 @@ inline int16_t ppmFrameLen(int8_t chCount) return (PPM_DEF_PERIOD); // else leave frame Length at default (22.5ms) } -void cb_value_changed(lv_event_t* e) -{ - ChannelRange* chRangeEditObject = (ChannelRange*)lv_event_get_user_data(e); - if (!chRangeEditObject) return; - - NumberEdit* ppmFrameLenEditObject = - chRangeEditObject->getPpmFrameLenEditObject(); - if (!ppmFrameLenEditObject) return; - - ppmFrameLenEditObject->setValue( - ppmFrameLen(chRangeEditObject->getChannelsCount())); -} - ChannelRange::ChannelRange(Window* parent) : Window(parent, rect_t{}) { padAll(PAD_TINY); @@ -68,7 +55,12 @@ void ChannelRange::build() GET_DEFAULT(getChannelsStart() + 8 + getChannelsCount())); chEnd->setPrefix(STR_CH); - chEnd->setSetValueHandler([=](int newValue) { setEnd(newValue); }); + chEnd->setSetValueHandler([=](int newValue) { + setEnd(newValue); + + if (ppmFrameLenEditObject) + ppmFrameLenEditObject->setValue(ppmFrameLen(getChannelsCount())); + }); } void ChannelRange::setStart(uint8_t newValue) @@ -110,11 +102,6 @@ void ChannelRange::update() updateEnd(); } -NumberEdit* ChannelRange::getPpmFrameLenEditObject() -{ - return this->ppmFrameLenEditObject; -} - void ChannelRange::setPpmFrameLenEditObject(NumberEdit* ppmFrameLenEditObject) { this->ppmFrameLenEditObject = ppmFrameLenEditObject; @@ -125,10 +112,6 @@ ModuleChannelRange::ModuleChannelRange(Window* parent, uint8_t moduleIdx) : { build(); update(); - - // add callback to be notified when channel count changes - lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed, - LV_EVENT_VALUE_CHANGED, (void*)this); } void ModuleChannelRange::update() @@ -195,10 +178,6 @@ TrainerChannelRange::TrainerChannelRange(Window* parent) : ChannelRange(parent) { build(); update(); - - // add callback to be notified when channel count changes - lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed, - LV_EVENT_VALUE_CHANGED, (void*)this); } uint8_t TrainerChannelRange::getChannelsStart() diff --git a/radio/src/gui/colorlcd/controls/channel_range.h b/radio/src/gui/colorlcd/controls/channel_range.h index dd5e47ea9..a49b43500 100644 --- a/radio/src/gui/colorlcd/controls/channel_range.h +++ b/radio/src/gui/colorlcd/controls/channel_range.h @@ -39,7 +39,6 @@ class ChannelRange : public Window virtual int8_t getChannelsCount() = 0; void setPpmFrameLenEditObject(NumberEdit* ppmFrameLenEditObject); - NumberEdit* getPpmFrameLenEditObject(); protected: NumberEdit* chStart; diff --git a/radio/src/gui/colorlcd/controls/gvar_numberedit.cpp b/radio/src/gui/colorlcd/controls/gvar_numberedit.cpp index 3e9e34704..d9d8c7924 100644 --- a/radio/src/gui/colorlcd/controls/gvar_numberedit.cpp +++ b/radio/src/gui/colorlcd/controls/gvar_numberedit.cpp @@ -22,15 +22,6 @@ #include "gvar_numberedit.h" #include "edgetx.h" -void GVarNumberEdit::value_changed(lv_event_t* e) -{ - auto obj = lv_event_get_target(e); - auto edit = (GVarNumberEdit*)lv_obj_get_user_data(obj); - if (!edit) return; - - edit->update(); -} - GVarNumberEdit::GVarNumberEdit(Window* parent, int32_t vmin, int32_t vmax, std::function getValue, std::function setValue, @@ -78,9 +69,6 @@ GVarNumberEdit::GVarNumberEdit(Window* parent, int32_t vmin, } #endif - lv_obj_add_event_cb(lvobj, GVarNumberEdit::value_changed, - LV_EVENT_VALUE_CHANGED, nullptr); - // update field type based on value update(); } @@ -131,8 +119,8 @@ void GVarNumberEdit::update() // GVAR mode act_field = gvar_field; num_field->setSetValueHandler(nullptr); + gvar_field->update(); gvar_field->show(); - lv_event_send(gvar_field->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } else { // number edit mode act_field = num_field; diff --git a/radio/src/gui/colorlcd/controls/input_source.cpp b/radio/src/gui/colorlcd/controls/input_source.cpp index 010798064..c296839e7 100644 --- a/radio/src/gui/colorlcd/controls/input_source.cpp +++ b/radio/src/gui/colorlcd/controls/input_source.cpp @@ -75,15 +75,6 @@ class SensorValue : public StaticText ExpoData *input; }; -void InputSource::value_changed(lv_event_t *e) -{ - auto obj = lv_event_get_target(e); - auto src = (InputSource *)lv_obj_get_user_data(obj); - if (!src) return; - - src->update(); -} - 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}; @@ -99,10 +90,9 @@ InputSource::InputSource(Window *parent, ExpoData *input) : this, rect_t{}, INPUTSRC_FIRST, INPUTSRC_LAST, GET_DEFAULT(input->srcRaw), [=](int32_t newValue) { input->srcRaw = newValue; - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); + update(); SET_DIRTY(); }, true); - lv_obj_add_event_cb(lvobj, InputSource::value_changed, LV_EVENT_VALUE_CHANGED, nullptr); sensor_form = new Window(this, rect_t{}); sensor_form->padAll(PAD_TINY); diff --git a/radio/src/gui/colorlcd/controls/input_source.h b/radio/src/gui/colorlcd/controls/input_source.h index 2353ecdfd..6669b9ad0 100644 --- a/radio/src/gui/colorlcd/controls/input_source.h +++ b/radio/src/gui/colorlcd/controls/input_source.h @@ -32,7 +32,6 @@ class InputSource : public Window Window* sensor_form; void update(); - static void value_changed(lv_event_t* e); public: InputSource(Window* parent, ExpoData* input); diff --git a/radio/src/gui/colorlcd/controls/source_numberedit.cpp b/radio/src/gui/colorlcd/controls/source_numberedit.cpp index 6c7768d7c..3a862fb02 100644 --- a/radio/src/gui/colorlcd/controls/source_numberedit.cpp +++ b/radio/src/gui/colorlcd/controls/source_numberedit.cpp @@ -24,15 +24,6 @@ #include "edgetx.h" #include "sourcechoice.h" -void SourceNumberEdit::value_changed(lv_event_t* e) -{ - auto obj = lv_event_get_target(e); - auto edit = (SourceNumberEdit*)lv_obj_get_user_data(obj); - if (!edit) return; - - edit->update(); -} - SourceNumberEdit::SourceNumberEdit(Window* parent, int32_t vmin, int32_t vmax, std::function getValue, @@ -43,6 +34,7 @@ SourceNumberEdit::SourceNumberEdit(Window* parent, Window(parent, {0, 0, NUM_EDIT_W + SRC_BTN_W + PAD_TINY * 3, EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_TINY * 2}), vmin(vmin), vmax(vmax), + sourceMin(sourceMin), getValue(getValue), setValue(setValue), textFlags(textFlags), @@ -87,9 +79,6 @@ SourceNumberEdit::SourceNumberEdit(Window* parent, }); m_srcBtn->check(isSource()); - lv_obj_add_event_cb(lvobj, SourceNumberEdit::value_changed, - LV_EVENT_VALUE_CHANGED, nullptr); - // update field type based on value update(); } @@ -107,7 +96,7 @@ void SourceNumberEdit::switchSourceMode() v.rawValue = getValue(); v.isSource = !v.isSource; // TODO: convert value??? - v.value = 0; + v.value = v.isSource ? sourceMin : 0; setValue(v.rawValue); // update field type based on value @@ -131,7 +120,6 @@ void SourceNumberEdit::update() act_field = source_field; source_field->show(); source_field->update(); - lv_event_send(source_field->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); } else { // number edit mode act_field = num_field; diff --git a/radio/src/gui/colorlcd/controls/source_numberedit.h b/radio/src/gui/colorlcd/controls/source_numberedit.h index 4f12a415e..1fb798a0a 100644 --- a/radio/src/gui/colorlcd/controls/source_numberedit.h +++ b/radio/src/gui/colorlcd/controls/source_numberedit.h @@ -56,6 +56,7 @@ class SourceNumberEdit : public Window int32_t vmin; int32_t vmax; + int16_t sourceMin; std::function getValue; std::function setValue; LcdFlags textFlags; diff --git a/radio/src/gui/colorlcd/libui/choice.cpp b/radio/src/gui/colorlcd/libui/choice.cpp index f704e62dc..166a94f2a 100644 --- a/radio/src/gui/colorlcd/libui/choice.cpp +++ b/radio/src/gui/colorlcd/libui/choice.cpp @@ -46,20 +46,6 @@ static lv_obj_t* choice_create(lv_obj_t* parent) return etx_create(&choice_class, parent); } -void ChoiceBase::changedCB(lv_event_t* e) -{ - auto code = lv_event_get_code(e); - - if (code == LV_EVENT_VALUE_CHANGED) { - lv_obj_t* target = lv_event_get_target(e); - if (target != nullptr) { - ChoiceBase* cb = (ChoiceBase*)lv_obj_get_user_data(target); - if (cb) - cb->update(); - } - } -} - ChoiceBase::ChoiceBase(Window* parent, const rect_t& rect, int vmin, int vmax, const char* title, std::function _getValue, @@ -83,8 +69,6 @@ ChoiceBase::ChoiceBase(Window* parent, const rect_t& rect, label = lv_label_create(lvobj); lv_obj_set_pos(label, type == CHOICE_TYPE_DROPOWN ? ICON_W - 2 : ICON_W, PAD_TINY); etx_font(label, FONT_XS_INDEX, LV_STATE_USER_1); - - lv_obj_add_event_cb(lvobj, changedCB, LV_EVENT_VALUE_CHANGED, this); } std::string Choice::getLabelText() diff --git a/radio/src/gui/colorlcd/libui/choice.h b/radio/src/gui/colorlcd/libui/choice.h index ad6b5ee02..d819aaed0 100644 --- a/radio/src/gui/colorlcd/libui/choice.h +++ b/radio/src/gui/colorlcd/libui/choice.h @@ -65,8 +65,6 @@ class ChoiceBase : public FormField std::function textHandler; virtual std::string getLabelText() = 0; - - static void changedCB(lv_event_t *e); }; class Choice : public ChoiceBase diff --git a/radio/src/gui/colorlcd/libui/slider.cpp b/radio/src/gui/colorlcd/libui/slider.cpp index 8f67a6db6..f45a5f50e 100644 --- a/radio/src/gui/colorlcd/libui/slider.cpp +++ b/radio/src/gui/colorlcd/libui/slider.cpp @@ -68,7 +68,7 @@ static lv_obj_t* slider_create(lv_obj_t* parent) return etx_create(&slider_class, parent); } -static void slider_changed_cb(lv_event_t* e) +void Slider::slider_changed_cb(lv_event_t* e) { if (lv_event_get_code(e) == LV_EVENT_VALUE_CHANGED) { Slider* sl = (Slider*)lv_event_get_user_data(e); @@ -95,7 +95,7 @@ Slider::Slider(Window* parent, coord_t width, int32_t vmin, int32_t vmax, slider = (new FormField(this, rect_t{}, slider_create))->getLvObj(); lv_obj_set_width(slider, lv_pct(100)); - lv_obj_add_event_cb(slider, slider_changed_cb, LV_EVENT_VALUE_CHANGED, this); + lv_obj_add_event_cb(slider, Slider::slider_changed_cb, LV_EVENT_VALUE_CHANGED, this); lv_slider_set_range(slider, vmin, vmax); lv_obj_add_event_cb(lvobj, Slider::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, diff --git a/radio/src/gui/colorlcd/libui/slider.h b/radio/src/gui/colorlcd/libui/slider.h index c454c3ba7..f7e0d29e3 100644 --- a/radio/src/gui/colorlcd/libui/slider.h +++ b/radio/src/gui/colorlcd/libui/slider.h @@ -47,6 +47,7 @@ class Slider : public Window std::function _getValue; std::function _setValue; + static void slider_changed_cb(lv_event_t* e); static void on_draw(lv_event_t* e); void delayedInit(); diff --git a/radio/src/gui/colorlcd/libui/toggleswitch.cpp b/radio/src/gui/colorlcd/libui/toggleswitch.cpp index 46c8920ef..e7a920e1c 100644 --- a/radio/src/gui/colorlcd/libui/toggleswitch.cpp +++ b/radio/src/gui/colorlcd/libui/toggleswitch.cpp @@ -66,7 +66,7 @@ static lv_obj_t* switch_create(lv_obj_t* parent) return etx_create(&switch_class, parent); } -static void toggleswitch_event_handler(lv_event_t* e) +void ToggleSwitch::toggleswitch_event_handler(lv_event_t* e) { lv_obj_t* target = lv_event_get_target(e); ToggleSwitch* cb = (ToggleSwitch*)lv_obj_get_user_data(target); @@ -83,7 +83,7 @@ ToggleSwitch::ToggleSwitch(Window* parent, const rect_t& rect, { update(); - lv_obj_add_event_cb(lvobj, toggleswitch_event_handler, LV_EVENT_VALUE_CHANGED, + lv_obj_add_event_cb(lvobj, ToggleSwitch::toggleswitch_event_handler, LV_EVENT_VALUE_CHANGED, this); } diff --git a/radio/src/gui/colorlcd/libui/toggleswitch.h b/radio/src/gui/colorlcd/libui/toggleswitch.h index 6ada607a0..a5d613da5 100644 --- a/radio/src/gui/colorlcd/libui/toggleswitch.h +++ b/radio/src/gui/colorlcd/libui/toggleswitch.h @@ -53,4 +53,6 @@ class ToggleSwitch : public FormField protected: std::function _getValue; std::function _setValue; + + static void toggleswitch_event_handler(lv_event_t* e); }; diff --git a/radio/src/gui/colorlcd/model/model_logical_switches.cpp b/radio/src/gui/colorlcd/model/model_logical_switches.cpp index 9c584a386..bab7bf2e1 100644 --- a/radio/src/gui/colorlcd/model/model_logical_switches.cpp +++ b/radio/src/gui/colorlcd/model/model_logical_switches.cpp @@ -623,10 +623,7 @@ void ModelLogicalSwitchesPage::build(Window* window) menu->addLine(STR_EDIT, [=]() { Window* lsWindow = new LogicalSwitchEditPage(i); lsWindow->setCloseHandler([=]() { - if (isActive) - lv_event_send(button->getLvObj(), LV_EVENT_VALUE_CHANGED, - nullptr); - else + if (!isActive) rebuild(window); }); }); diff --git a/radio/src/gui/colorlcd/model/special_functions.cpp b/radio/src/gui/colorlcd/model/special_functions.cpp index b3c047928..84651a220 100644 --- a/radio/src/gui/colorlcd/model/special_functions.cpp +++ b/radio/src/gui/colorlcd/model/special_functions.cpp @@ -720,9 +720,7 @@ void FunctionsPage::pasteSpecialFunction(Window *window, uint8_t index, if (CFN_FUNC(cfn) == FUNC_PLAY_SCRIPT) LUA_LOAD_MODEL_SCRIPTS(); storageDirty(EE_MODEL); focusIndex = index; - if (button) - lv_event_send(button->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); - else + if (!button) rebuild(window); } @@ -734,9 +732,7 @@ void FunctionsPage::editSpecialFunction(Window *window, uint8_t index, CustomFunctionData *cfn = customFunctionData(index); if (cfn->swtch != 0) { focusIndex = index; - if (button) - lv_event_send(button->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); - else + if (!button) rebuild(window); } }); diff --git a/radio/src/gui/colorlcd/module/afhds2a_settings.cpp b/radio/src/gui/colorlcd/module/afhds2a_settings.cpp index 6b97e2c35..1df089829 100644 --- a/radio/src/gui/colorlcd/module/afhds2a_settings.cpp +++ b/radio/src/gui/colorlcd/module/afhds2a_settings.cpp @@ -117,7 +117,7 @@ void AFHDS2ASettings::showAFHDS2Options() afhds2RFPowerChoice->show(showRFPower); if (showRFPower && (showRFPower != hasRFPower)) { hasRFPower = showRFPower; - lv_event_send(afhds2RFPowerChoice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + afhds2RFPowerChoice->update(); } #endif } diff --git a/radio/src/gui/colorlcd/module/afhds2a_settings.h b/radio/src/gui/colorlcd/module/afhds2a_settings.h index 906eb3c81..9f16f92a8 100644 --- a/radio/src/gui/colorlcd/module/afhds2a_settings.h +++ b/radio/src/gui/colorlcd/module/afhds2a_settings.h @@ -24,6 +24,7 @@ #include "window.h" #include "module_setup.h" +class Choice; struct ModuleData; class AFHDS2ASettings : public Window, public ModuleOptions @@ -37,7 +38,7 @@ class AFHDS2ASettings : public Window, public ModuleOptions #if defined(PCBNV14) bool hasRFPower = false; Window* afhds2RFPowerText = nullptr; - Window* afhds2RFPowerChoice = nullptr; + Choice* afhds2RFPowerChoice = nullptr; #endif void hideAFHDS2Options(); void showAFHDS2Options(); diff --git a/radio/src/gui/colorlcd/module/afhds3_settings.cpp b/radio/src/gui/colorlcd/module/afhds3_settings.cpp index a2fa3801a..a51fc3b6d 100644 --- a/radio/src/gui/colorlcd/module/afhds3_settings.cpp +++ b/radio/src/gui/colorlcd/module/afhds3_settings.cpp @@ -118,11 +118,10 @@ void AFHDS3Settings::showAFHDS3Options() afhds3StatusText->show(); afhds3TypeLabel->show(); afhds3TypeForm->show(); - lv_event_send(afhds3StatusText->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); - lv_event_send(afhds3PhyMode->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); - lv_event_send(afhds3Emi->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + afhds3PhyMode->update(); + afhds3Emi->update(); if (moduleIdx == EXTERNAL_MODULE) { - lv_event_send(afhds3RfPower->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + afhds3RfPower->update(); } if (afhds3::getConfig(moduleIdx)->others.isConnected) { afhds3PhyMode->disable(); diff --git a/radio/src/gui/colorlcd/module/module_setup.cpp b/radio/src/gui/colorlcd/module/module_setup.cpp index 8caec7815..405a4d72f 100644 --- a/radio/src/gui/colorlcd/module/module_setup.cpp +++ b/radio/src/gui/colorlcd/module/module_setup.cpp @@ -72,16 +72,418 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; -struct FailsafeChoice; +struct FailsafeChoice : public Window { + FailsafeChoice(Window* parent, uint8_t moduleIdx) : + Window(parent, rect_t{}), moduleIdx(moduleIdx) + { + padAll(PAD_TINY); + setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); + + auto md = &g_model.moduleData[moduleIdx]; + new Choice(this, rect_t{}, STR_VFAILSAFE, 0, FAILSAFE_LAST, + GET_DEFAULT(md->failsafeMode), [=](int32_t newValue) { + md->failsafeMode = newValue; + optsBtn->show(newValue == FAILSAFE_CUSTOM); + SET_DIRTY(); + }); + + optsBtn = new TextButton(this, rect_t{}, STR_SET, [=]() -> uint8_t { + new FailSafePage(moduleIdx); + return 0; + }); + optsBtn->show(md->failsafeMode == FAILSAFE_CUSTOM); + } + + void update() const + { + optsBtn->show(g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_CUSTOM); + } + + private: + uint8_t moduleIdx; + TextButton* optsBtn; +}; class ModuleWindow : public Window { public: - ModuleWindow(Window* parent, uint8_t moduleIdx); - void updateModule(); - void updateSubType(); - void updateRxID(); - void updateFailsafe(); + ModuleWindow(Window* parent, uint8_t moduleIdx) : + Window(parent, rect_t{}), moduleIdx(moduleIdx) + { + setFlexLayout(); + updateModule(); + lv_obj_add_event_cb(lvobj, ModuleWindow::mw_refresh_cb, LV_EVENT_REFRESH, this); + } + + void updateModule() + { + FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); + clear(); + + modOpts = nullptr; + chRange = nullptr; + rxID = nullptr; + bindButton = nullptr; + rangeButton = nullptr; + registerButton = nullptr; + fsLine = nullptr; + fsChoice = nullptr; + rfPower = nullptr; + + // Module parameters + ModuleData* md = &g_model.moduleData[moduleIdx]; + + if (md->type == MODULE_TYPE_NONE) { + return; + } + #if defined(CROSSFIRE) + else if (isModuleCrossfire(moduleIdx)) { + modOpts = new CrossfireSettings(this, grid, moduleIdx); + } + #endif + #if defined(AFHDS2) + else if (isModuleAFHDS2A(moduleIdx)) { + modOpts = new AFHDS2ASettings(this, grid, moduleIdx); + } + #endif + #if defined(AFHDS3) + else if (isModuleAFHDS3(moduleIdx)) { + modOpts = new AFHDS3Settings(this, grid, moduleIdx); + } + #endif + #if defined(MULTIMODULE) + else if (isModuleMultimodule(moduleIdx)) { + modOpts = new MultimoduleSettings(this, grid, moduleIdx); + } + #endif + #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) + else if (moduleIdx == INTERNAL_MODULE && isModuleXJT(moduleIdx) && + g_eeGeneral.antennaMode == ANTENNA_MODE_PER_MODEL) { + modOpts = new PXX1AntennaSettings(this, grid, moduleIdx); + } + #endif + + // Channel Range + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_CHANNELRANGE); + chRange = new ModuleChannelRange(line, moduleIdx); + + // Failsafe + fsLine = newLine(grid); + new StaticText(fsLine, rect_t{}, STR_FAILSAFE); + fsChoice = new FailsafeChoice(fsLine, moduleIdx); + + // PPM modules + if (isModulePPM(moduleIdx)) { + // PPM frame + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_PPMFRAME); + auto obj = new PpmFrameSettings(line, &md->ppm); + + // copy pointer to frame len edit object to channel range + chRange->setPpmFrameLenEditObject(obj->getPpmFrameLenEditObject()); + } + + // Generic module parameters + + // Bind and Range buttons + if (!isModuleRFAccess(moduleIdx) && (isModuleModelIndexAvailable(moduleIdx) || + isModuleBindRangeAvailable(moduleIdx))) { + // Is Reciever ID Unique + if (isModuleModelIndexAvailable(moduleIdx)) { + auto line = newLine(grid); + new StaticText(line, rect_t{}, ""); + idUnique = new StaticText(line, rect_t{}, ""); + etx_txt_color(idUnique->getLvObj(), COLOR_THEME_WARNING_INDEX, + ETX_STATE_UNIQUE_ID_WARN); + updateIDStaticText(moduleIdx); + } + + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_RECEIVER); + + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM, LV_SIZE_CONTENT); + + // Model index + auto modelId = &g_model.header.modelId[moduleIdx]; + rxID = new NumberEdit(box, {0, 0, NUM_W, 0}, 0, getMaxRxNum(moduleIdx), + GET_DEFAULT(*modelId), [=](int32_t newValue) { + if (newValue != *modelId) { + *modelId = newValue; + modelslist.updateCurrentModelCell(); + updateIDStaticText(moduleIdx); + #if defined(CROSSFIRE) + if (isModuleCrossfire(moduleIdx)) { + moduleState[moduleIdx].counter = + CRSF_FRAME_MODELID; + } + #endif + SET_DIRTY(); + } + }); + + if (isModuleBindRangeAvailable(moduleIdx) || isModuleCrossfire(moduleIdx)) { + bindButton = new TextButton(box, rect_t{}, STR_MODULE_BIND); + bindButton->setPressHandler([=]() -> uint8_t { + if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) { + if (rangeButton) rangeButton->check(false); + } + if (moduleState[moduleIdx].mode == MODULE_MODE_BIND) { + moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; + #if defined(MULTIMODULE) + if (isModuleMultimodule(moduleIdx)) { + setMultiBindStatus(moduleIdx, MULTI_BIND_NONE); + } + #endif + #if defined(AFHDS2) + if (isModuleAFHDS2A(moduleIdx)) resetPulsesAFHDS2(); + #endif + if (isModuleDSMP(moduleIdx)) restartModule(moduleIdx); + return 0; + } else { + if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx) || + IS_R9_MULTI(moduleIdx)) { + new BindChoiceMenu( + Layer::back(), moduleIdx, [=]() { bindButton->check(true); }, + [=]() { bindButton->check(false); }); + return 0; + } + #if defined(MULTIMODULE) + if (isModuleMultimodule(moduleIdx)) { + setMultiBindStatus(moduleIdx, MULTI_BIND_INITIATED); + } + #endif + moduleState[moduleIdx].mode = MODULE_MODE_BIND; + if (isModuleELRS(moduleIdx)) + AUDIO_PLAY(AU_SPECIAL_SOUND_CHEEP); // Since ELRS bind is just one frame, we need to play the sound manually + #if defined(AFHDS2) + if (isModuleAFHDS2A(moduleIdx)) { + resetPulsesAFHDS2(); + } + #endif + return 1; + } + return 0; + }); + bindButton->setCheckHandler([=]() { + if (moduleState[moduleIdx].mode != MODULE_MODE_BIND) { + if (bindButton->checked()) { + bindButton->check(false); + } + } + #if defined(MULTIMODULE) + if (isModuleMultimodule(moduleIdx) && + getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { + setMultiBindStatus(moduleIdx, MULTI_BIND_NONE); + moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; + bindButton->check(false); + } + #endif + }); + + if (isModuleRangeAvailable(moduleIdx)) { + rangeButton = new TextButton(box, rect_t{}, STR_MODULE_RANGE); + rangeButton->setPressHandler([=]() -> uint8_t { + if (moduleState[moduleIdx].mode == MODULE_MODE_BIND) { + bindButton->check(false); + moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; + } + if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) { + moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; + return 0; + } else { + moduleState[moduleIdx].mode = MODULE_MODE_RANGECHECK; + #if defined(AFHDS2) + if (isModuleAFHDS2A(moduleIdx)) { + resetPulsesAFHDS2(); + } + #endif + startRSSIDialog([=]() { + #if defined(AFHDS2) + if (isModuleAFHDS2A(moduleIdx)) { + resetPulsesAFHDS2(); + } + #endif + }); + return 1; + } + }); + } + + #if defined(PXX2) + if (isModuleISRM(moduleIdx)) { + auto options = new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS); + options->setPressHandler([=]() { + new pxx2::ModuleOptions(Layer::back(), moduleIdx); + return 0; + }); + } + #endif + } + } + #if defined(PXX2) + else if (isModuleRFAccess(moduleIdx)) { + + // Register and Range buttons + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_MODULE); + + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_LARGE); + + registerButton = new TextButton(box, rect_t{}, STR_REGISTER); + registerButton->setPressHandler([=]() -> uint8_t { + new pxx2::RegisterDialog(Layer::back(), moduleIdx); + return 0; + }); + + rangeButton = new TextButton(box, rect_t{}, STR_MODULE_RANGE); + rangeButton->setPressHandler([=]() -> uint8_t { + if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) { + moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; + return 0; + } else { + moduleState[moduleIdx].mode = MODULE_MODE_RANGECHECK; + startRSSIDialog(); + return 1; + } + }); + + auto options = new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS); + options->setPressHandler([=]() { + new pxx2::ModuleOptions(Layer::back(), moduleIdx); + return 0; + }); + + // Model index + line = newLine(grid); + new StaticText(line, rect_t{}, STR_RECEIVER_NUM); + auto modelId = &g_model.header.modelId[moduleIdx]; + new NumberEdit(line, rect_t{}, 0, getMaxRxNum(moduleIdx), + GET_SET_DEFAULT(*modelId)); + } + #endif + + // R9M Power + if (isModuleR9MNonAccess(moduleIdx)) { + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_RF_POWER); + rfPower = new Choice(line, rect_t{}, 0, 0, GET_SET_DEFAULT(md->pxx.power)); + line = newLine(grid); + new StaticText(line, rect_t{}, STR_MODULE_TELEMETRY); + new DynamicText(line, rect_t{}, [=]() { + if (modulePortHasRx(moduleIdx)) { + return std::string(STR_MODULE_TELEM_ON); + } else { + return std::string(STR_DISABLE_INTERNAL); + } + }); + } + + #if defined(PXX2) + // Receivers + if (isModuleRFAccess(moduleIdx)) { + for (uint8_t receiverIdx = 0; receiverIdx < PXX2_MAX_RECEIVERS_PER_MODULE; + receiverIdx++) { + char label[] = TR_RECEIVER " X"; + label[sizeof(label) - 2] = '1' + receiverIdx; + + auto line = newLine(grid); + new StaticText(line, rect_t{}, label); + new pxx2::ReceiverButton(line, rect_t{}, moduleIdx, receiverIdx); + } + } + #endif + // SBUS refresh rate + if (isModuleSBUS(moduleIdx)) { + auto line = newLine(grid); + new StaticText(line, rect_t{}, STR_REFRESHRATE); + + auto box = new Window(line, rect_t{}); + box->padAll(PAD_TINY); + box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL); + + auto edit = new NumberEdit( + box, rect_t{}, SBUS_MIN_PERIOD, SBUS_MAX_PERIOD, + GET_DEFAULT((int16_t)md->sbus.refreshRate * SBUS_STEPSIZE + + SBUS_DEF_PERIOD), + SET_VALUE(md->sbus.refreshRate, + (newValue - SBUS_DEF_PERIOD) / SBUS_STEPSIZE), + PREC1); + edit->setSuffix(STR_MS); + edit->setStep(SBUS_STEPSIZE); + new Choice(box, rect_t{}, STR_SBUS_INVERSION_VALUES, 0, 1, + GET_SET_DEFAULT(md->sbus.noninverted)); + #if defined(RADIO_TX16S) + new StaticText(this, rect_t{}, STR_WARN_5VOLTS); + #endif + } + + if (isModuleGhost(moduleIdx)) { + auto line = newLine(grid); + new StaticText(line, rect_t{}, "Raw 12 bits"); + new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(md->ghost.raw12bits)); + } + + updateSubType(); + } + + void updateSubType() + { + if (modOpts) modOpts->update(); + if (chRange) chRange->update(); + + updateRxID(); + updateFailsafe(); + + if (rfPower) { + if (isModuleR9M_LBT(moduleIdx)) { + rfPower->setMax(R9M_LBT_POWER_MAX); + rfPower->setValues(STR_R9M_LBT_POWER_VALUES); + } else { + rfPower->setMax(R9M_FCC_POWER_MAX); + rfPower->setValues(STR_R9M_FCC_POWER_VALUES); + } + rfPower->update(); + } + } + + void updateRxID() + { + if (rxID) { + if (isModuleModelIndexAvailable(moduleIdx)) { + rxID->show(); + rxID->update(); + } else { + rxID->hide(); + } + } + } + + void updateFailsafe() + { + if (fsLine) { + if (isModuleFailsafeAvailable(moduleIdx)) { + fsLine->show(); + fsChoice->update(); + } else { + fsLine->hide(); + } + } + } + + void updateLayout() + { + if (isModuleISRM(moduleIdx)) + updateModule(); + else + updateSubType(); + + pulsesModuleSettingsUpdate(moduleIdx); + } uint8_t getModuleIdx() const { return moduleIdx; } @@ -101,565 +503,107 @@ class ModuleWindow : public Window Choice* rfPower = nullptr; StaticText* idUnique = nullptr; - void startRSSIDialog(std::function closeHandler = nullptr); + void startRSSIDialog(std::function closeHandler = nullptr) + { + auto rssiDialog = new DynamicMessageDialog( + parent, STR_RANGE_TEST, + [=]() { + return std::to_string((int)TELEMETRY_RSSI()) + getRxStatLabels()->unit; + }, + getRxStatLabels()->label, 50, + COLOR_THEME_SECONDARY1_INDEX, CENTERED | FONT(XL)); - void updateIDStaticText(int mdIdx); + rssiDialog->setCloseHandler([this, closeHandler]() { + rangeButton->check(false); + moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; + if (closeHandler) closeHandler(); + }); + } - void checkEvents() override; + void updateIDStaticText(int mdIdx) + { + if (idUnique == nullptr) return; + char buffer[50]; + std::string idStr = STR_MODELIDUNIQUE; + if (!modelslist.isModelIdUnique(mdIdx, buffer, sizeof(buffer))) { + idStr = STR_MODELIDUSED; + idStr = idStr + buffer; + lv_obj_add_state(idUnique->getLvObj(), ETX_STATE_UNIQUE_ID_WARN); + } else { + lv_obj_clear_state(idUnique->getLvObj(), ETX_STATE_UNIQUE_ID_WARN); + } + idUnique->setText(idStr); + } + + void checkEvents() override + { + if (bindButton != nullptr) { + if (TELEMETRY_STREAMING() && isModuleELRS(moduleIdx)) + bindButton->setText(STR_MODULE_UNBIND); + else if (isModuleELRS(moduleIdx)) + bindButton->setText(STR_MODULE_BIND); + + bindButton->show(isModuleBindRangeAvailable(moduleIdx)); + } + Window::checkEvents(); + } + + static void mw_refresh_cb(lv_event_t* e) + { + auto mw = (ModuleWindow*)lv_event_get_user_data(e); + if (mw) { + mw->updateRxID(); + mw->updateFailsafe(); + } + } }; -struct FailsafeChoice : public Window { - FailsafeChoice(Window* parent, uint8_t moduleIdx); - void update() const; - - private: - uint8_t moduleIdx; - TextButton* optsBtn; -}; - -FailsafeChoice::FailsafeChoice(Window* parent, uint8_t moduleIdx) : - Window(parent, rect_t{}), moduleIdx(moduleIdx) -{ - padAll(PAD_TINY); - setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT); - - auto md = &g_model.moduleData[moduleIdx]; - new Choice(this, rect_t{}, STR_VFAILSAFE, 0, FAILSAFE_LAST, - GET_DEFAULT(md->failsafeMode), [=](int32_t newValue) { - md->failsafeMode = newValue; - optsBtn->show(newValue == FAILSAFE_CUSTOM); - SET_DIRTY(); - }); - - optsBtn = new TextButton(this, rect_t{}, STR_SET, [=]() -> uint8_t { - new FailSafePage(moduleIdx); - return 0; - }); - optsBtn->show(md->failsafeMode == FAILSAFE_CUSTOM); -} - -void FailsafeChoice::update() const -{ - optsBtn->show(g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_CUSTOM); -} - -static void mw_refresh_cb(lv_event_t* e) -{ - auto mw = (ModuleWindow*)lv_event_get_user_data(e); - if (mw) { - mw->updateRxID(); - mw->updateFailsafe(); - } -} - -ModuleWindow::ModuleWindow(Window* parent, uint8_t moduleIdx) : - Window(parent, rect_t{}), moduleIdx(moduleIdx) -{ - setFlexLayout(); - updateModule(); - lv_obj_add_event_cb(lvobj, mw_refresh_cb, LV_EVENT_REFRESH, this); -} - -void ModuleWindow::checkEvents() -{ - if (bindButton != nullptr) { - if (TELEMETRY_STREAMING() && isModuleELRS(moduleIdx)) - bindButton->setText(STR_MODULE_UNBIND); - else if (isModuleELRS(moduleIdx)) - bindButton->setText(STR_MODULE_BIND); - - bindButton->show(isModuleBindRangeAvailable(moduleIdx)); - } - Window::checkEvents(); -} - -void ModuleWindow::updateIDStaticText(int mdIdx) -{ - if (idUnique == nullptr) return; - char buffer[50]; - std::string idStr = STR_MODELIDUNIQUE; - if (!modelslist.isModelIdUnique(mdIdx, buffer, sizeof(buffer))) { - idStr = STR_MODELIDUSED; - idStr = idStr + buffer; - lv_obj_add_state(idUnique->getLvObj(), ETX_STATE_UNIQUE_ID_WARN); - } else { - lv_obj_clear_state(idUnique->getLvObj(), ETX_STATE_UNIQUE_ID_WARN); - } - idUnique->setText(idStr); -} - -void ModuleWindow::updateModule() -{ - FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY); - clear(); - - modOpts = nullptr; - chRange = nullptr; - rxID = nullptr; - bindButton = nullptr; - rangeButton = nullptr; - registerButton = nullptr; - fsLine = nullptr; - fsChoice = nullptr; - rfPower = nullptr; - - // Module parameters - ModuleData* md = &g_model.moduleData[moduleIdx]; - - if (md->type == MODULE_TYPE_NONE) { - return; - } -#if defined(CROSSFIRE) - else if (isModuleCrossfire(moduleIdx)) { - modOpts = new CrossfireSettings(this, grid, moduleIdx); - } -#endif -#if defined(AFHDS2) - else if (isModuleAFHDS2A(moduleIdx)) { - modOpts = new AFHDS2ASettings(this, grid, moduleIdx); - } -#endif -#if defined(AFHDS3) - else if (isModuleAFHDS3(moduleIdx)) { - modOpts = new AFHDS3Settings(this, grid, moduleIdx); - } -#endif -#if defined(MULTIMODULE) - else if (isModuleMultimodule(moduleIdx)) { - modOpts = new MultimoduleSettings(this, grid, moduleIdx); - } -#endif -#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) - else if (moduleIdx == INTERNAL_MODULE && isModuleXJT(moduleIdx) && - g_eeGeneral.antennaMode == ANTENNA_MODE_PER_MODEL) { - modOpts = new PXX1AntennaSettings(this, grid, moduleIdx); - } -#endif - - // Channel Range - auto line = newLine(grid); - new StaticText(line, rect_t{}, STR_CHANNELRANGE); - chRange = new ModuleChannelRange(line, moduleIdx); - - // Failsafe - fsLine = newLine(grid); - new StaticText(fsLine, rect_t{}, STR_FAILSAFE); - fsChoice = new FailsafeChoice(fsLine, moduleIdx); - - // PPM modules - if (isModulePPM(moduleIdx)) { - // PPM frame - auto line = newLine(grid); - new StaticText(line, rect_t{}, STR_PPMFRAME); - auto obj = new PpmFrameSettings(line, &md->ppm); - - // copy pointer to frame len edit object to channel range - chRange->setPpmFrameLenEditObject(obj->getPpmFrameLenEditObject()); - } - - // Generic module parameters - - // Bind and Range buttons - if (!isModuleRFAccess(moduleIdx) && (isModuleModelIndexAvailable(moduleIdx) || - isModuleBindRangeAvailable(moduleIdx))) { - // Is Reciever ID Unique - if (isModuleModelIndexAvailable(moduleIdx)) { - auto line = newLine(grid); - new StaticText(line, rect_t{}, ""); - idUnique = new StaticText(line, rect_t{}, ""); - etx_txt_color(idUnique->getLvObj(), COLOR_THEME_WARNING_INDEX, - ETX_STATE_UNIQUE_ID_WARN); - updateIDStaticText(moduleIdx); - } - - auto line = newLine(grid); - new StaticText(line, rect_t{}, STR_RECEIVER); - - auto box = new Window(line, rect_t{}); - box->padAll(PAD_TINY); - box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM, LV_SIZE_CONTENT); - - // Model index - auto modelId = &g_model.header.modelId[moduleIdx]; - rxID = new NumberEdit(box, {0, 0, NUM_W, 0}, 0, getMaxRxNum(moduleIdx), - GET_DEFAULT(*modelId), [=](int32_t newValue) { - if (newValue != *modelId) { - *modelId = newValue; - modelslist.updateCurrentModelCell(); - updateIDStaticText(moduleIdx); -#if defined(CROSSFIRE) - if (isModuleCrossfire(moduleIdx)) { - moduleState[moduleIdx].counter = - CRSF_FRAME_MODELID; - } -#endif - SET_DIRTY(); - } - }); - - if (isModuleBindRangeAvailable(moduleIdx) || isModuleCrossfire(moduleIdx)) { - bindButton = new TextButton(box, rect_t{}, STR_MODULE_BIND); - bindButton->setPressHandler([=]() -> uint8_t { - if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) { - if (rangeButton) rangeButton->check(false); - } - if (moduleState[moduleIdx].mode == MODULE_MODE_BIND) { - moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; -#if defined(MULTIMODULE) - if (isModuleMultimodule(moduleIdx)) { - setMultiBindStatus(moduleIdx, MULTI_BIND_NONE); - } -#endif -#if defined(AFHDS2) - if (isModuleAFHDS2A(moduleIdx)) resetPulsesAFHDS2(); -#endif - if (isModuleDSMP(moduleIdx)) restartModule(moduleIdx); - return 0; - } else { - if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx) || - IS_R9_MULTI(moduleIdx)) { - new BindChoiceMenu( - Layer::back(), moduleIdx, [=]() { bindButton->check(true); }, - [=]() { bindButton->check(false); }); - return 0; - } -#if defined(MULTIMODULE) - if (isModuleMultimodule(moduleIdx)) { - setMultiBindStatus(moduleIdx, MULTI_BIND_INITIATED); - } -#endif - moduleState[moduleIdx].mode = MODULE_MODE_BIND; - if (isModuleELRS(moduleIdx)) - AUDIO_PLAY(AU_SPECIAL_SOUND_CHEEP); // Since ELRS bind is just one frame, we need to play the sound manually -#if defined(AFHDS2) - if (isModuleAFHDS2A(moduleIdx)) { - resetPulsesAFHDS2(); - } -#endif - return 1; - } - return 0; - }); - bindButton->setCheckHandler([=]() { - if (moduleState[moduleIdx].mode != MODULE_MODE_BIND) { - if (bindButton->checked()) { - bindButton->check(false); - } - } -#if defined(MULTIMODULE) - if (isModuleMultimodule(moduleIdx) && - getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) { - setMultiBindStatus(moduleIdx, MULTI_BIND_NONE); - moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; - bindButton->check(false); - } -#endif - }); - - if (isModuleRangeAvailable(moduleIdx)) { - rangeButton = new TextButton(box, rect_t{}, STR_MODULE_RANGE); - rangeButton->setPressHandler([=]() -> uint8_t { - if (moduleState[moduleIdx].mode == MODULE_MODE_BIND) { - bindButton->check(false); - moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; - } - if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) { - moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; - return 0; - } else { - moduleState[moduleIdx].mode = MODULE_MODE_RANGECHECK; -#if defined(AFHDS2) - if (isModuleAFHDS2A(moduleIdx)) { - resetPulsesAFHDS2(); - } -#endif - startRSSIDialog([=]() { -#if defined(AFHDS2) - if (isModuleAFHDS2A(moduleIdx)) { - resetPulsesAFHDS2(); - } -#endif - }); - return 1; - } - }); - } - -#if defined(PXX2) - if (isModuleISRM(moduleIdx)) { - auto options = new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS); - options->setPressHandler([=]() { - new pxx2::ModuleOptions(Layer::back(), moduleIdx); - return 0; - }); - } -#endif - } - } -#if defined(PXX2) - else if (isModuleRFAccess(moduleIdx)) { - - // Register and Range buttons - auto line = newLine(grid); - new StaticText(line, rect_t{}, STR_MODULE); - - auto box = new Window(line, rect_t{}); - box->padAll(PAD_TINY); - box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_LARGE); - - registerButton = new TextButton(box, rect_t{}, STR_REGISTER); - registerButton->setPressHandler([=]() -> uint8_t { - new pxx2::RegisterDialog(Layer::back(), moduleIdx); - return 0; - }); - - rangeButton = new TextButton(box, rect_t{}, STR_MODULE_RANGE); - rangeButton->setPressHandler([=]() -> uint8_t { - if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) { - moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; - return 0; - } else { - moduleState[moduleIdx].mode = MODULE_MODE_RANGECHECK; - startRSSIDialog(); - return 1; - } - }); - - auto options = new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS); - options->setPressHandler([=]() { - new pxx2::ModuleOptions(Layer::back(), moduleIdx); - return 0; - }); - - // Model index - line = newLine(grid); - new StaticText(line, rect_t{}, STR_RECEIVER_NUM); - auto modelId = &g_model.header.modelId[moduleIdx]; - new NumberEdit(line, rect_t{}, 0, getMaxRxNum(moduleIdx), - GET_SET_DEFAULT(*modelId)); - } -#endif - - // R9M Power - if (isModuleR9MNonAccess(moduleIdx)) { - auto line = newLine(grid); - new StaticText(line, rect_t{}, STR_RF_POWER); - rfPower = new Choice(line, rect_t{}, 0, 0, GET_SET_DEFAULT(md->pxx.power)); - line = newLine(grid); - new StaticText(line, rect_t{}, STR_MODULE_TELEMETRY); - new DynamicText(line, rect_t{}, [=]() { - if (modulePortHasRx(moduleIdx)) { - return std::string(STR_MODULE_TELEM_ON); - } else { - return std::string(STR_DISABLE_INTERNAL); - } - }); - } - -#if defined(PXX2) - // Receivers - if (isModuleRFAccess(moduleIdx)) { - for (uint8_t receiverIdx = 0; receiverIdx < PXX2_MAX_RECEIVERS_PER_MODULE; - receiverIdx++) { - char label[] = TR_RECEIVER " X"; - label[sizeof(label) - 2] = '1' + receiverIdx; - - auto line = newLine(grid); - new StaticText(line, rect_t{}, label); - new pxx2::ReceiverButton(line, rect_t{}, moduleIdx, receiverIdx); - } - } -#endif - // SBUS refresh rate - if (isModuleSBUS(moduleIdx)) { - auto line = newLine(grid); - new StaticText(line, rect_t{}, STR_REFRESHRATE); - - auto box = new Window(line, rect_t{}); - box->padAll(PAD_TINY); - box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL); - - auto edit = new NumberEdit( - box, rect_t{}, SBUS_MIN_PERIOD, SBUS_MAX_PERIOD, - GET_DEFAULT((int16_t)md->sbus.refreshRate * SBUS_STEPSIZE + - SBUS_DEF_PERIOD), - SET_VALUE(md->sbus.refreshRate, - (newValue - SBUS_DEF_PERIOD) / SBUS_STEPSIZE), - PREC1); - edit->setSuffix(STR_MS); - edit->setStep(SBUS_STEPSIZE); - new Choice(box, rect_t{}, STR_SBUS_INVERSION_VALUES, 0, 1, - GET_SET_DEFAULT(md->sbus.noninverted)); -#if defined(RADIO_TX16S) - new StaticText(this, rect_t{}, STR_WARN_5VOLTS); -#endif - } - - if (isModuleGhost(moduleIdx)) { - auto line = newLine(grid); - new StaticText(line, rect_t{}, "Raw 12 bits"); - new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(md->ghost.raw12bits)); - } - - updateSubType(); -} - -void ModuleWindow::updateSubType() -{ - if (modOpts) modOpts->update(); - if (chRange) chRange->update(); - - updateRxID(); - updateFailsafe(); - - if (rfPower) { - if (isModuleR9M_LBT(moduleIdx)) { - rfPower->setMax(R9M_LBT_POWER_MAX); - rfPower->setValues(STR_R9M_LBT_POWER_VALUES); - } else { - rfPower->setMax(R9M_FCC_POWER_MAX); - rfPower->setValues(STR_R9M_FCC_POWER_VALUES); - } - lv_event_send(rfPower->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); - } -} - -void ModuleWindow::updateRxID() -{ - if (rxID) { - if (isModuleModelIndexAvailable(moduleIdx)) { - rxID->show(); - rxID->update(); - } else { - rxID->hide(); - } - } -} - -void ModuleWindow::updateFailsafe() -{ - if (fsLine) { - if (isModuleFailsafeAvailable(moduleIdx)) { - fsLine->show(); - fsChoice->update(); - } else { - fsLine->hide(); - } - } -} - -void ModuleWindow::startRSSIDialog(std::function closeHandler) -{ - auto rssiDialog = new DynamicMessageDialog( - parent, STR_RANGE_TEST, - [=]() { - return std::to_string((int)TELEMETRY_RSSI()) + getRxStatLabels()->unit; - }, - getRxStatLabels()->label, 50, - COLOR_THEME_SECONDARY1_INDEX, CENTERED | FONT(XL)); - - rssiDialog->setCloseHandler([this, closeHandler]() { - rangeButton->check(false); - moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; - if (closeHandler) closeHandler(); - }); -} - class ModuleSubTypeChoice : public Choice { - uint8_t moduleIdx; - public: - ModuleSubTypeChoice(Window* parent, uint8_t moduleIdx); - void update(); - void openMenu() override; -}; - -ModuleSubTypeChoice::ModuleSubTypeChoice(Window* parent, uint8_t moduleIdx) : - Choice(parent, rect_t{}, 0, 0, nullptr), moduleIdx(moduleIdx) -{ - ModuleData* md = &g_model.moduleData[moduleIdx]; - setGetValueHandler(GET_DEFAULT(md->subType)); -} - -void ModuleSubTypeChoice::update() -{ - ModuleData* md = &g_model.moduleData[moduleIdx]; - - if (isModuleXJT(moduleIdx)) { - setMin(MODULE_SUBTYPE_PXX1_ACCST_D16); - setMax(MODULE_SUBTYPE_PXX1_LAST); - setValues(STR_XJT_ACCST_RF_PROTOCOLS); - setGetValueHandler(GET_DEFAULT(md->subType)); - setSetValueHandler([=](int32_t newValue) { - md->subType = newValue; - md->channelsStart = 0; - md->channelsCount = defaultModuleChannels_M8(moduleIdx); - SET_DIRTY(); - }); - setAvailableHandler(nullptr); - setTextHandler(nullptr); - } else if (isModuleDSM2(moduleIdx)) { - setMin(DSM2_PROTO_LP45); - setMax(DSM2_PROTO_DSMX); - setValues(STR_DSM_PROTOCOLS); - setGetValueHandler(GET_DEFAULT(md->subType)); - setSetValueHandler(SET_DEFAULT(md->subType)); - setAvailableHandler(nullptr); - setTextHandler(nullptr); + ModuleSubTypeChoice(Window* parent, uint8_t moduleIdx) : + Choice(parent, rect_t{}, 0, 0, + [=]() { return getSubTypeValue(); }, + [=](int32_t newValue) { setSubTypeValue(newValue); }), + moduleIdx(moduleIdx) + { } + + int getSubTypeValue() + { + if (isModuleXJT(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleR9MNonAccess(moduleIdx) #if defined(PPM) - else if (isModulePPM(moduleIdx)) { - setMin(PPM_PROTO_TLM_NONE); - setMax(PPM_PROTO_TLM_MLINK); - setValues(STR_PPM_PROTOCOLS); - setGetValueHandler(GET_DEFAULT(md->subType)); - setSetValueHandler(SET_DEFAULT(md->subType)); - setAvailableHandler(nullptr); - setTextHandler(nullptr); - } + || isModulePPM(moduleIdx) #endif - else if (isModuleR9MNonAccess(moduleIdx)) { - setMin(MODULE_SUBTYPE_R9M_FCC); - setMax(MODULE_SUBTYPE_R9M_LAST); - setValues(STR_R9M_REGION); - setGetValueHandler(GET_DEFAULT(md->subType)); - setSetValueHandler(SET_DEFAULT(md->subType)); - setAvailableHandler(nullptr); - setTextHandler(nullptr); - } #if defined(PXX2) - else if (isModuleISRM(moduleIdx)) { - setMin(MODULE_SUBTYPE_ISRM_PXX2_ACCESS); - setMax(MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16); - setValues(STR_ISRM_RF_PROTOCOLS); - setGetValueHandler(GET_DEFAULT(md->subType)); - setSetValueHandler(SET_DEFAULT(md->subType)); - setAvailableHandler(nullptr); - setTextHandler(nullptr); - } + || isModuleISRM(moduleIdx) #endif -#if defined(MULTIMODULE) - else if (isModuleMultimodule(moduleIdx)) { - setMin(0); - setMax(0); - values.clear(); - - auto protos = MultiRfProtocols::instance(moduleIdx); - protos->triggerScan(); - - if (protos->isScanning()) { - new RfScanDialog(parent, protos, [=]() { update(); }); + ) { + return g_model.moduleData[moduleIdx].subType; } else { - TRACE("!protos->isScanning()"); + return g_model.moduleData[moduleIdx].multi.rfProtocol; } + } - setTextHandler([=](int value) { return protos->getProtoLabel(value); }); - - setGetValueHandler(GET_DEFAULT(md->multi.rfProtocol)); - setSetValueHandler([=](int newValue) { - md->multi.rfProtocol = newValue; - md->subType = 0; + void setSubTypeValue(int32_t newValue) + { + if (isModuleXJT(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleR9MNonAccess(moduleIdx) +#if defined(PPM) + || isModulePPM(moduleIdx) +#endif +#if defined(PXX2) + || isModuleISRM(moduleIdx) +#endif + ) { + if (isModuleXJT(moduleIdx)) { + g_model.moduleData[moduleIdx].channelsStart = 0; + g_model.moduleData[moduleIdx].channelsCount = defaultModuleChannels_M8(moduleIdx); + } + g_model.moduleData[moduleIdx].subType = newValue; + SET_DIRTY(); + } else { + g_model.moduleData[moduleIdx].multi.rfProtocol = newValue; + g_model.moduleData[moduleIdx].subType = 0; resetMultiProtocolsOptions(moduleIdx); MultiModuleStatus& status = getMultiModuleStatus(moduleIdx); @@ -669,49 +613,109 @@ void ModuleSubTypeChoice::update() while (!status.isValid() && (RTOS_GET_MS() - startUpdate < 250)) ; SET_DIRTY(); - }); - } -#endif - else { - hide(); - return; + } + + if (moduleWindow) + moduleWindow->updateLayout(); } - show(); - - // update choice value - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); -} - -void ModuleSubTypeChoice::openMenu() -{ -#if defined(MULTIMODULE) - if (isModuleMultimodule(moduleIdx)) { - auto menu = new Menu(this); - - if (menuTitle) menu->setTitle(menuTitle); - menu->setCloseHandler([=]() { setEditMode(false); }); - - setEditMode(true); - - auto protos = MultiRfProtocols::instance(moduleIdx); - protos->fillList([=](const MultiRfProtocols::RfProto& p) { - addValue(p.label.c_str()); - menu->addLine(p.label.c_str(), [=]() { - setValue(p.proto); - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); - }); - }); - - ModuleData* md = &g_model.moduleData[moduleIdx]; - int idx = protos->getIndex(md->multi.rfProtocol); - if (idx >= 0) menu->select(idx); - } else -#endif + void updateLayout() { - Choice::openMenu(); + if (isModuleXJT(moduleIdx)) { + setMin(MODULE_SUBTYPE_PXX1_ACCST_D16); + setMax(MODULE_SUBTYPE_PXX1_LAST); + setValues(STR_XJT_ACCST_RF_PROTOCOLS); + setTextHandler(nullptr); + } else if (isModuleDSM2(moduleIdx)) { + setMin(DSM2_PROTO_LP45); + setMax(DSM2_PROTO_DSMX); + setValues(STR_DSM_PROTOCOLS); + setTextHandler(nullptr); + } +#if defined(PPM) + else if (isModulePPM(moduleIdx)) { + setMin(PPM_PROTO_TLM_NONE); + setMax(PPM_PROTO_TLM_MLINK); + setValues(STR_PPM_PROTOCOLS); + setTextHandler(nullptr); + } +#endif + else if (isModuleR9MNonAccess(moduleIdx)) { + setMin(MODULE_SUBTYPE_R9M_FCC); + setMax(MODULE_SUBTYPE_R9M_LAST); + setValues(STR_R9M_REGION); + setTextHandler(nullptr); + } +#if defined(PXX2) + else if (isModuleISRM(moduleIdx)) { + setMin(MODULE_SUBTYPE_ISRM_PXX2_ACCESS); + setMax(MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16); + setValues(STR_ISRM_RF_PROTOCOLS); + setTextHandler(nullptr); + } +#endif +#if defined(MULTIMODULE) + else if (isModuleMultimodule(moduleIdx)) { + setMin(0); + setMax(0); + values.clear(); + + auto protos = MultiRfProtocols::instance(moduleIdx); + protos->triggerScan(); + + if (protos->isScanning()) { + new RfScanDialog(parent, protos, [=]() { updateLayout(); }); + } else { + TRACE("!protos->isScanning()"); + } + + setTextHandler([=](int value) { return protos->getProtoLabel(value); }); + } +#endif + else { + hide(); + return; + } + + update(); + show(); } -} + + void openMenu() override + { +#if defined(MULTIMODULE) + if (isModuleMultimodule(moduleIdx)) { + auto menu = new Menu(this); + + if (menuTitle) menu->setTitle(menuTitle); + menu->setCloseHandler([=]() { setEditMode(false); }); + + setEditMode(true); + + auto protos = MultiRfProtocols::instance(moduleIdx); + protos->fillList([=](const MultiRfProtocols::RfProto& p) { + addValue(p.label.c_str()); + menu->addLine(p.label.c_str(), [=]() { + setValue(p.proto); + }); + }); + + ModuleData* md = &g_model.moduleData[moduleIdx]; + int idx = protos->getIndex(md->multi.rfProtocol); + if (idx >= 0) menu->select(idx); + } else +#endif + { + Choice::openMenu(); + } + } + + void setModuleWindow(ModuleWindow* w) { moduleWindow = w; } + + protected: + uint8_t moduleIdx; + ModuleWindow* moduleWindow = nullptr; +}; static void update_module_window(lv_event_t* e) { @@ -760,19 +764,18 @@ ModulePage::ModulePage(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) auto subTypeChoice = new ModuleSubTypeChoice(box, moduleIdx); auto moduleWindow = new ModuleWindow(body, moduleIdx); + subTypeChoice->setModuleWindow(moduleWindow); + // This needs to be after moduleWindow has been created moduleChoice->setSetValueHandler([=](int32_t newValue) { setModuleType(moduleIdx, newValue); moduleWindow->updateModule(); - subTypeChoice->update(); + subTypeChoice->updateLayout(); SET_DIRTY(); }); - lv_obj_add_event_cb(subTypeChoice->getLvObj(), update_module_window, - LV_EVENT_VALUE_CHANGED, moduleWindow); - // Call this last in case it opens the 'Scanning' popup. - subTypeChoice->update(); + subTypeChoice->updateLayout(); } diff --git a/radio/src/gui/colorlcd/module/mpm_settings.cpp b/radio/src/gui/colorlcd/module/mpm_settings.cpp index 30d9b97d3..70f661e57 100644 --- a/radio/src/gui/colorlcd/module/mpm_settings.cpp +++ b/radio/src/gui/colorlcd/module/mpm_settings.cpp @@ -28,15 +28,6 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -static void update_mpm_settings(lv_event_t* e) -{ - MultimoduleSettings* ms = (MultimoduleSettings*)lv_event_get_user_data(e); - if (!ms) return; - - ms->update(); - lv_event_send(ms->getParent()->getLvObj(), LV_EVENT_REFRESH, nullptr); -} - class MPMProtoOption : public FormLine { public: MPMProtoOption(Window* form, FlexGridLayout& layout) : @@ -85,7 +76,7 @@ class MPMProtoOption : public FormLine { choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); choice->show(); - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + choice->update(); } else if (title == STR_MULTI_TELEMETRY) { // Bayang choice->setValues(STR_MULTI_BAYANG_OPTIONS); choice->setMin(min); @@ -93,7 +84,7 @@ class MPMProtoOption : public FormLine { choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); choice->show(); - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + choice->update(); } else if (title == STR_MULTI_WBUS) { // e.g. WFLY2 but may not be used anymore choice->setValues(STR_MULTI_WBUS_MODE); @@ -102,7 +93,7 @@ class MPMProtoOption : public FormLine { choice->setGetValueHandler(GET_DEFAULT(md->multi.optionValue)); choice->setSetValueHandler(SET_DEFAULT(md->multi.optionValue)); choice->show(); - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + choice->update(); } else if (rfProto->proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) { edit->setMin(50); edit->setMax(400); @@ -150,16 +141,9 @@ class MPMProtoOption : public FormLine { DynamicNumber* rssi; }; -static void subtype_event_cb(lv_event_t* e) -{ - if (lv_event_get_param(e)) return; - auto obj = (lv_obj_t*)lv_event_get_user_data(e); - if (obj) lv_event_send(obj, LV_EVENT_VALUE_CHANGED, nullptr); -} - struct MPMSubtype : public FormLine { - MPMSubtype(Window* form, FlexGridLayout& layout, uint8_t moduleIdx) : - FormLine(form, layout) + MPMSubtype(MultimoduleSettings* parent, FlexGridLayout& layout, uint8_t moduleIdx) : + FormLine(parent, layout) { this->moduleIdx = moduleIdx; this->DSM2lastSubType = g_model.moduleData[this->moduleIdx].subType; @@ -176,10 +160,8 @@ struct MPMSubtype : public FormLine { resetMultiProtocolsOptions(moduleIdx); DSM2autoUpdated = false; SET_DIRTY(); + parent->update(); }); - - lv_obj_add_event_cb(choice->getLvObj(), subtype_event_cb, - LV_EVENT_VALUE_CHANGED, lvobj); } void update(const MultiRfProtocols::RfProto* rfProto, uint8_t moduleIdx) @@ -193,9 +175,6 @@ struct MPMSubtype : public FormLine { choice->setMax(rfProto->subProtos.size() - 1); show(); - - bool stop = true; - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, &stop); } void checkEvents() @@ -213,8 +192,6 @@ struct MPMSubtype : public FormLine { DSM2autoUpdated = true; // indicate this was not user triggered DSM2lastSubType = subType; // memorize new DSM2 subType choice->setValue(subType); // set new DSM2 subType - lv_event_send(choice->getLvObj(), LV_EVENT_REFRESH, - nullptr); // refresh subType field } } } @@ -244,7 +221,7 @@ struct MPMDSMCloned : public FormLine { void update() const { - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + choice->update(); } private: @@ -269,7 +246,7 @@ struct MPMServoRate : public FormLine { void update() const { - lv_event_send(choice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr); + choice->update(); } private: @@ -349,9 +326,6 @@ MultimoduleSettings::MultimoduleSettings(Window* parent, st_line = new MPMSubtype(this, grid, moduleIdx); - lv_obj_add_event_cb(st_line->getLvObj(), update_mpm_settings, - LV_EVENT_VALUE_CHANGED, this); - cl_line = new MPMDSMCloned(this, grid, moduleIdx); opt_line = new MPMProtoOption(this, grid); sr_line = new MPMServoRate(this, grid, moduleIdx); diff --git a/radio/src/gui/colorlcd/radio/hw_inputs.cpp b/radio/src/gui/colorlcd/radio/hw_inputs.cpp index 2698ad3b8..248098758 100644 --- a/radio/src/gui/colorlcd/radio/hw_inputs.cpp +++ b/radio/src/gui/colorlcd/radio/hw_inputs.cpp @@ -58,6 +58,8 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; HWSticks::HWSticks(Window* parent) : Window(parent, rect_t{}) { + padAll(PAD_TINY); + FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY); setFlexLayout(); @@ -83,6 +85,8 @@ HWSticks::HWSticks(Window* parent) : Window(parent, rect_t{}) HWPots::HWPots(Window* parent) : Window(parent, rect_t{0, 0, DIALOG_DEFAULT_WIDTH - 12, LV_SIZE_CONTENT}) { + padAll(PAD_TINY); + potsChanged = false; setCloseHandler([=]() { @@ -150,8 +154,8 @@ HWPots::HWPots(Window* parent) : class SwitchDynamicLabel : public StaticText { public: - SwitchDynamicLabel(Window* parent, uint8_t index, coord_t x, coord_t y) : - StaticText(parent, rect_t{x, y, HWSwitches::SW_CTRL_W, 0}, ""), + SwitchDynamicLabel(Window* parent, uint8_t index, coord_t x, coord_t y, coord_t w) : + StaticText(parent, rect_t{x, y, w, 0}, ""), index(index) { checkEvents(); @@ -188,41 +192,28 @@ class SwitchDynamicLabel : public StaticText uint8_t lastpos = 0xff; }; -static void flex_channel_changed(lv_event_t* e) +class HWSwitch { - auto target = lv_event_get_target(e); - auto channel = (Choice*)lv_obj_get_user_data(target); - - auto sw_cfg = (Choice*)lv_event_get_user_data(e); - lv_obj_t* sw_cfg_obj = sw_cfg->getLvObj(); - - if (channel->getIntValue() < 0) { - lv_obj_add_flag(sw_cfg_obj, LV_OBJ_FLAG_HIDDEN); - sw_cfg->setValue(0); - } else { - lv_obj_clear_flag(sw_cfg_obj, LV_OBJ_FLAG_HIDDEN); - } -} - -HWSwitches::HWSwitches(Window* parent) : - Window(parent, rect_t{0, 0, DIALOG_DEFAULT_WIDTH - 12, LV_SIZE_CONTENT}) -{ - auto max_switches = switchGetMaxSwitches(); - for (int i = 0; i < max_switches; i++) { - new SwitchDynamicLabel(this, i, PAD_TINY, i * SW_CTRL_H + PAD_TINY); - new HWInputEdit(this, (char*)switchGetCustomName(i), LEN_SWITCH_NAME, - SW_CTRL_W + 8, i * SW_CTRL_H + PAD_TINY); + public: + HWSwitch(Window* parent, int swnum, coord_t y) + { + new SwitchDynamicLabel(parent, swnum, PAD_TINY, y + PAD_MEDIUM, SW_CTRL_W); + new HWInputEdit(parent, (char*)switchGetCustomName(swnum), LEN_SWITCH_NAME, + SW_CTRL_W + 8, y); coord_t x = SW_CTRL_W * PAD_TINY + 14; - Choice* channel = nullptr; - if (switchIsFlex(i)) { + + if (switchIsFlex(swnum)) { channel = new Choice( - this, rect_t{x, i * SW_CTRL_H + PAD_TINY, SW_CTRL_W, 0}, -1, + parent, {x, y, SW_CTRL_W, 0}, -1, adcGetMaxInputs(ADC_INPUT_FLEX) - 1, - [=]() -> int { return switchGetFlexConfig(i); }, - [=](int newValue) { switchConfigFlex(i, newValue); }); + [=]() -> int { return switchGetFlexConfig(swnum); }, + [=](int newValue) { + switchConfigFlex(swnum, newValue); + updateLayout(); + }); channel->setAvailableHandler([=](int val) { - return val < 0 || switchIsFlexInputAvailable(i, val); + return val < 0 || switchIsFlexInputAvailable(swnum, val); }); channel->setTextHandler([=](int val) -> std::string { if (val < 0) return STR_NONE; @@ -231,25 +222,47 @@ HWSwitches::HWSwitches(Window* parent) : x += SW_CTRL_W + 6; } - auto sw_cfg = new Choice( - this, rect_t{x, i * SW_CTRL_H + PAD_TINY, SW_CTRL_W, 0}, - STR_SWTYPES, SWITCH_NONE, switchGetMaxType(i), - [=]() -> int { return SWITCH_CONFIG(i); }, + sw_cfg = new Choice( + parent, {x, y, SW_CTRL_W, 0}, + STR_SWTYPES, SWITCH_NONE, switchGetMaxType(swnum), + [=]() -> int { return SWITCH_CONFIG(swnum); }, [=](int newValue) { - swconfig_t mask = (swconfig_t)SWITCH_CONFIG_MASK(i); + swconfig_t mask = (swconfig_t)SWITCH_CONFIG_MASK(swnum); g_eeGeneral.switchConfig = (g_eeGeneral.switchConfig & ~mask) | - ((swconfig_t(newValue) & SW_CFG_MASK) << (SW_CFG_BITS * i)); + ((swconfig_t(newValue) & SW_CFG_MASK) << (SW_CFG_BITS * swnum)); SET_DIRTY(); }); + updateLayout(); + } + + void updateLayout() + { if (channel) { - lv_obj_t* obj = channel->getLvObj(); - lv_obj_add_event_cb(obj, flex_channel_changed, LV_EVENT_VALUE_CHANGED, - sw_cfg); - lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); + sw_cfg->show(channel->getIntValue() >= 0); + if (channel->getIntValue() < 0) + sw_cfg->setValue(0); } } + + static LAYOUT_VAL(SW_CTRL_W, 86, 75) + static LAYOUT_VAL(SW_CTRL_H, 36, 36) + + protected: + Choice* channel = nullptr; + Choice* sw_cfg = nullptr; +}; + +HWSwitches::HWSwitches(Window* parent) : + Window(parent, rect_t{0, 0, DIALOG_DEFAULT_WIDTH - 12, LV_SIZE_CONTENT}) +{ + padAll(PAD_TINY); + + auto max_switches = switchGetMaxSwitches(); + for (int i = 0; i < max_switches; i++) { + new HWSwitch(this, i, i * HWSwitch::SW_CTRL_H + PAD_TINY); + } } template diff --git a/radio/src/gui/colorlcd/radio/hw_inputs.h b/radio/src/gui/colorlcd/radio/hw_inputs.h index cdd87d941..70fe96a9f 100644 --- a/radio/src/gui/colorlcd/radio/hw_inputs.h +++ b/radio/src/gui/colorlcd/radio/hw_inputs.h @@ -62,11 +62,6 @@ class HWSwitches : public Window { public: HWSwitches(Window* parent); - - // Absolute layout for Switches popup - due to performance issues with - // lv_textarea in a flex layout - static LAYOUT_VAL(SW_CTRL_W, 86, 75) - static LAYOUT_VAL(SW_CTRL_H, 36, 36) }; template diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 24aea068c..1607a3d30 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -317,7 +317,7 @@ bool checkSourceAvailable(int source, uint32_t sourceTypes) if (source < 0) source = -source; - for (int i = 0 ; i < DIM(sourceChecks); i += 1) { + for (size_t i = 0 ; i < DIM(sourceChecks); i += 1) { if (sourceChecks[i].type & sourceTypes && source >= sourceChecks[i].first && source <= sourceChecks[i].last) { return sourceChecks[i].check(source - sourceChecks[i].first); } diff --git a/radio/src/pulses/flysky.cpp b/radio/src/pulses/flysky.cpp index bec148251..602b7137c 100644 --- a/radio/src/pulses/flysky.cpp +++ b/radio/src/pulses/flysky.cpp @@ -21,8 +21,6 @@ * Dedicate for FlySky NV14 board. */ -#pragma once - #include "edgetx.h" #include "flysky.h"