diff --git a/radio/src/gui/colorlcd/sourcechoice.cpp b/radio/src/gui/colorlcd/sourcechoice.cpp index ff6a95bdf..b46e4c9a5 100644 --- a/radio/src/gui/colorlcd/sourcechoice.cpp +++ b/radio/src/gui/colorlcd/sourcechoice.cpp @@ -20,74 +20,104 @@ */ #include "sourcechoice.h" -#include "menutoolbar.h" -#include "menu.h" + #include "dataconstants.h" -#include "lcd.h" -#include "strhelpers.h" #include "draw_functions.h" +#include "lcd.h" +#include "menu.h" +#include "menutoolbar.h" #include "opentx.h" +#include "strhelpers.h" #include "switches.h" +#if LCD_W > LCD_H +#define FILTER_COLUMNS 3 +#else +#define FILTER_COLUMNS 2 +#endif + class SourceChoiceMenuToolbar : public MenuToolbar { - public: - SourceChoiceMenuToolbar(SourceChoice * choice, Menu * menu): - MenuToolbar(choice, menu) - { - addButton(STR_CHAR_INPUT, MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT); + public: + SourceChoiceMenuToolbar(SourceChoice *choice, Menu *menu) : + MenuToolbar(choice, menu, FILTER_COLUMNS) + { + addButton(STR_CHAR_INPUT, MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT, nullptr, + STR_MENU_INPUTS); #if defined(LUA_MODEL_SCRIPTS) - if (modelCustomScriptsEnabled()) - addButton(STR_CHAR_LUA, MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA); + if (modelCustomScriptsEnabled()) + addButton(STR_CHAR_LUA, MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA, nullptr, + STR_MENU_LUA); #endif #if defined(PCBHORUS) - auto lastSource = MIXSRC_LAST_SPACEMOUSE; + auto lastSource = MIXSRC_LAST_SPACEMOUSE; #elif defined(IMU) - auto lastSource = MIXSRC_TILT_Y; + auto lastSource = MIXSRC_TILT_Y; #else - auto lastSource = MIXSRC_LAST_STICK; + auto lastSource = MIXSRC_LAST_STICK; #endif - addButton(STR_CHAR_STICK, MIXSRC_FIRST_STICK, lastSource, [=](int16_t index) { - if (index >= MIXSRC_FIRST_POT && index <= MIXSRC_LAST_POT) - return false; + addButton( + STR_CHAR_STICK, MIXSRC_FIRST_STICK, lastSource, + [=](int16_t index) { + if (index >= MIXSRC_FIRST_POT && index <= MIXSRC_LAST_POT) + return false; #if MAX_AXIS > 0 - if (index >= MIXSRC_FIRST_AXIS && index <= MIXSRC_LAST_AXIS) - return false; + if (index >= MIXSRC_FIRST_AXIS && index <= MIXSRC_LAST_AXIS) + return false; #endif - return index >= MIXSRC_FIRST_STICK && index <= lastSource; - }); - addButton(STR_CHAR_POT, MIXSRC_FIRST_POT, MIXSRC_LAST_POT); - addButton(STR_CHAR_FUNCTION, MIXSRC_MIN, MIXSRC_LAST_TIMER, [=](int16_t index) { - return (index >= MIXSRC_MIN && index <= MIXSRC_MAX) || (index >= MIXSRC_TX_VOLTAGE && index <= MIXSRC_LAST_TIMER); - }); + return index >= MIXSRC_FIRST_STICK && index <= lastSource; + }, + STR_MENU_STICKS); + addButton(STR_CHAR_POT, MIXSRC_FIRST_POT, MIXSRC_LAST_POT, nullptr, + STR_MENU_POTS); + addButton( + STR_CHAR_FUNCTION, MIXSRC_MIN, MIXSRC_LAST_TIMER, + [=](int16_t index) { + return (index >= MIXSRC_MIN && index <= MIXSRC_MAX) || + (index >= MIXSRC_TX_VOLTAGE && index <= MIXSRC_LAST_TIMER); + }, + STR_MENU_OTHER); #if defined(HELI) - if (modelHeliEnabled()) - addButton(STR_CHAR_CYC, MIXSRC_FIRST_HELI, MIXSRC_LAST_HELI); + if (modelHeliEnabled()) + addButton(STR_CHAR_CYC, MIXSRC_FIRST_HELI, MIXSRC_LAST_HELI, nullptr, + STR_MENU_HELI); #endif - addButton(STR_CHAR_TRIM, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM); - addButton(STR_CHAR_SWITCH, MIXSRC_FIRST_SWITCH, MIXSRC_LAST_SWITCH); - if (modelLSEnabled()) - addButton(STR_CHAR_SWITCH, MIXSRC_FIRST_LOGICAL_SWITCH, MIXSRC_LAST_LOGICAL_SWITCH); - addButton(STR_CHAR_TRAINER, MIXSRC_FIRST_TRAINER, MIXSRC_LAST_TRAINER); - addButton(STR_CHAR_CHANNEL, MIXSRC_FIRST_CH, MIXSRC_LAST_CH); + addButton(STR_CHAR_TRIM, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM, nullptr, + STR_MENU_TRIMS); + addButton(STR_CHAR_SWITCH, MIXSRC_FIRST_SWITCH, MIXSRC_LAST_SWITCH, nullptr, + STR_MENU_SWITCHES); + if (modelLSEnabled()) + addButton("LS", MIXSRC_FIRST_LOGICAL_SWITCH, MIXSRC_LAST_LOGICAL_SWITCH, + nullptr, STR_MENU_LOGICAL_SWITCHES); + addButton(STR_CHAR_TRAINER, MIXSRC_FIRST_TRAINER, MIXSRC_LAST_TRAINER, + nullptr, STR_MENU_TRAINER); + addButton(STR_CHAR_CHANNEL, MIXSRC_FIRST_CH, MIXSRC_LAST_CH, nullptr, + STR_MENU_CHANNELS); #if defined(GVARS) - if (modelGVEnabled()) - addButton(STR_CHAR_SLIDER, MIXSRC_FIRST_GVAR, MIXSRC_LAST_GVAR); + if (modelGVEnabled()) + addButton(STR_CHAR_SLIDER, MIXSRC_FIRST_GVAR, MIXSRC_LAST_GVAR, nullptr, + STR_MENU_GVARS); #endif - if (modelTelemetryEnabled()) - addButton(STR_CHAR_TELEMETRY, MIXSRC_FIRST_TELEM, MIXSRC_LAST_TELEM); - } + if (modelTelemetryEnabled()) + addButton(STR_CHAR_TELEMETRY, MIXSRC_FIRST_TELEM, MIXSRC_LAST_TELEM, + nullptr, STR_MENU_TELEMETRY); + + if ((nxtBtnPos > filterColumns) && choice->isValueAvailable && + choice->isValueAvailable(0)) + addButton(STR_SELECT_MENU_CLR, 0, 0, nullptr, nullptr, true); + } }; // defined in gui/gui_common.cpp uint8_t switchToMix(uint8_t source); -SourceChoice::SourceChoice(Window* parent, const rect_t &rect, int16_t vmin, +SourceChoice::SourceChoice(Window *parent, const rect_t &rect, int16_t vmin, int16_t vmax, std::function getValue, std::function setValue, WindowFlags windowFlags, LcdFlags textFlags) : Choice(parent, rect, vmin, vmax, getValue, setValue) { + setMenuTitle(STR_SOURCE); setBeforeDisplayMenuHandler([=](Menu *menu) { auto tb = new SourceChoiceMenuToolbar(this, menu); menu->setToolbar(tb); @@ -122,5 +152,5 @@ SourceChoice::SourceChoice(Window* parent, const rect_t &rect, int16_t vmin, return std::string(getSourceString(value)); }); - setAvailableHandler([](int v){ return isSourceAvailable(v); }); + setAvailableHandler([](int v) { return isSourceAvailable(v); }); } diff --git a/radio/src/gui/colorlcd/sourcechoice.h b/radio/src/gui/colorlcd/sourcechoice.h index 3b2e8592d..3edad4e9d 100644 --- a/radio/src/gui/colorlcd/sourcechoice.h +++ b/radio/src/gui/colorlcd/sourcechoice.h @@ -25,6 +25,8 @@ #include "choice.h" #include "form.h" +class SourceChoiceMenuToolbar; + bool isSourceAvailable(int source); class SourceChoice : public Choice @@ -35,6 +37,9 @@ class SourceChoice : public Choice std::function setValue, WindowFlags windowFlags = 0, LcdFlags textFlags = 0); + protected: + friend SourceChoiceMenuToolbar; + #if defined(DEBUG_WINDOWS) std::string getName() const override { return "SourceChoice"; } #endif diff --git a/radio/src/gui/colorlcd/switchchoice.cpp b/radio/src/gui/colorlcd/switchchoice.cpp index 50165e848..c72dcd555 100644 --- a/radio/src/gui/colorlcd/switchchoice.cpp +++ b/radio/src/gui/colorlcd/switchchoice.cpp @@ -32,22 +32,69 @@ class SwitchChoiceMenuToolbar : public MenuToolbar { public: SwitchChoiceMenuToolbar(SwitchChoice* choice, Menu* menu) : - MenuToolbar(choice, menu) + MenuToolbar(choice, menu, 2) { - addButton(STR_CHAR_SWITCH, SWSRC_FIRST_SWITCH, SWSRC_LAST_MULTIPOS_SWITCH); - addButton(STR_CHAR_TRIM, SWSRC_FIRST_TRIM, SWSRC_LAST_TRIM); - addButton(STR_CHAR_SWITCH, SWSRC_FIRST_LOGICAL_SWITCH, SWSRC_LAST_LOGICAL_SWITCH); - addButton(STR_CHAR_TELEMETRY, SWSRC_FIRST_SENSOR, SWSRC_LAST_SENSOR); + addButton(STR_CHAR_SWITCH, SWSRC_FIRST_SWITCH, SWSRC_LAST_MULTIPOS_SWITCH, + nullptr, STR_MENU_SWITCHES); + addButton(STR_CHAR_TRIM, SWSRC_FIRST_TRIM, SWSRC_LAST_TRIM, nullptr, + STR_MENU_TRIMS); + addButton("LS", SWSRC_FIRST_LOGICAL_SWITCH, SWSRC_LAST_LOGICAL_SWITCH, + nullptr, STR_MENU_LOGICAL_SWITCHES); + addButton("FM", SWSRC_FIRST_FLIGHT_MODE, SWSRC_LAST_FLIGHT_MODE, nullptr, + STR_FLIGHT_MODE); + addButton(STR_CHAR_TELEMETRY, SWSRC_FIRST_SENSOR, SWSRC_LAST_SENSOR, + nullptr, STR_MENU_TELEMETRY); #if defined(DEBUG_LATENCY) auto lastSource = SWSRC_LATENCY_TOGGLE; #else auto lastSource = SWSRC_RADIO_ACTIVITY; #endif - addButton(STR_CHAR_FUNCTION, SWSRC_TELEMETRY_STREAMING, lastSource, [=](int16_t index) { - index = abs(index); - return index == 0 || (index >= SWSRC_TELEMETRY_STREAMING && index <= lastSource && !(index >= SWSRC_FIRST_SENSOR && index <= SWSRC_LAST_SENSOR)); + addButton( + STR_CHAR_FUNCTION, SWSRC_ON, lastSource, + [=](int16_t index) { + index = abs(index); + return index == 0 || index == SWSRC_ON || index == SWSRC_ONE || + (index >= SWSRC_TELEMETRY_STREAMING && index <= lastSource && + !(index >= SWSRC_FIRST_SENSOR && index <= SWSRC_LAST_SENSOR)); + }, + STR_MENU_OTHER); + + if ((nxtBtnPos > filterColumns) && choice->isValueAvailable && + choice->isValueAvailable(0)) + addButton(STR_SELECT_MENU_CLR, 0, 0, nullptr, nullptr, true); + +#if defined(HARDWARE_TOUCH) + coord_t y = + height() - MENUS_TOOLBAR_BUTTON_WIDTH - MENUS_TOOLBAR_BUTTON_PADDING; + coord_t w = width() - MENUS_TOOLBAR_BUTTON_PADDING * 2; + + invertBtn = new MenuToolbarButton( + this, {MENUS_TOOLBAR_BUTTON_PADDING, y, w, MENUS_TOOLBAR_BUTTON_WIDTH}, + STR_SELECT_MENU_INV); + invertBtn->check(choice->inverted); + + invertBtn->setPressHandler([=]() { + lv_obj_clear_state(invertBtn->getLvObj(), LV_STATE_FOCUSED); + longPress(); + return choice->inverted; }); +#endif } + + void longPress() + { + SwitchChoice* switchChoice = (SwitchChoice*)choice; + switchChoice->inverted = !switchChoice->inverted; + auto idx = menu->selection(); + switchChoice->fillMenu(menu, filter); + menu->select(idx); +#if defined(HARDWARE_TOUCH) + invertBtn->check(switchChoice->inverted); +#endif + } + + protected: + MenuToolbarButton* invertBtn = nullptr; }; void SwitchChoice::LongPressHandler(void* data) @@ -61,12 +108,33 @@ void SwitchChoice::LongPressHandler(void* data) } } +void SwitchChoice::setValue(int value) +{ + if (inMenu) { + if (inverted) value = -value; + inMenu = false; + } + Choice::setValue(value); +} + +int SwitchChoice::getIntValue() const +{ + int value = Choice::getIntValue(); + if (inMenu) value = abs(value); + return value; +} + SwitchChoice::SwitchChoice(Window* parent, const rect_t& rect, int vmin, int vmax, std::function getValue, std::function setValue) : - Choice(parent, rect, vmin, vmax, getValue, setValue) + Choice(parent, rect, 0, vmax, getValue, setValue) { + setMenuTitle(STR_SWITCH); + setBeforeDisplayMenuHandler([=](Menu* menu) { + inverted = getValue() < 0; + inMenu = true; + auto tb = new SwitchChoiceMenuToolbar(this, menu); menu->setToolbar(tb); @@ -94,6 +162,8 @@ SwitchChoice::SwitchChoice(Window* parent, const rect_t& rect, int vmin, }); setTextHandler([=](int value) { + if (inMenu && inverted) value = -value; + if (isValueAvailable && !isValueAvailable(value)) return std::to_string(0); // we will fix this later diff --git a/radio/src/gui/colorlcd/switchchoice.h b/radio/src/gui/colorlcd/switchchoice.h index f58dfbe38..8d941b66f 100644 --- a/radio/src/gui/colorlcd/switchchoice.h +++ b/radio/src/gui/colorlcd/switchchoice.h @@ -25,6 +25,8 @@ #include "choice.h" #include "form.h" +class SwitchChoiceMenuToolbar; + class SwitchChoice : public Choice { public: @@ -35,6 +37,14 @@ class SwitchChoice : public Choice static void LongPressHandler(void* data); protected: + friend SwitchChoiceMenuToolbar; + + bool inverted = false; + bool inMenu = false; + + void setValue(int value) override; + int getIntValue() const override; + #if defined(DEBUG_WINDOWS) std::string getName() const override { return "SwitchChoice"; } #endif diff --git a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp index 29ebefd2c..a62b5e1db 100644 --- a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp +++ b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp @@ -820,6 +820,19 @@ const lv_obj_class_t etx_button_class = { .instance_size = sizeof(lv_btn_t), }; +const lv_obj_class_t etx_menu_button_class = { + .base_class = &lv_btn_class, + .constructor_cb = etx_button_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LV_SIZE_CONTENT, + .height_def = 32, + .editable = LV_OBJ_CLASS_EDITABLE_INHERIT, + .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, + .instance_size = sizeof(lv_btn_t), +}; + const lv_obj_class_t etx_choice_class = { .base_class = &lv_obj_class, .constructor_cb = etx_choice_constructor, @@ -983,6 +996,11 @@ lv_obj_t* etx_button_create(lv_obj_t* parent) return etx_create(&etx_button_class, parent); } +lv_obj_t* etx_menu_button_create(lv_obj_t* parent) +{ + return etx_create(&etx_menu_button_class, parent); +} + lv_obj_t* etx_choice_create(lv_obj_t* parent) { return etx_create(&etx_choice_class, parent); diff --git a/radio/src/targets/horus/libopenui_config.h b/radio/src/targets/horus/libopenui_config.h index 9830de204..1abe40395 100644 --- a/radio/src/targets/horus/libopenui_config.h +++ b/radio/src/targets/horus/libopenui_config.h @@ -32,10 +32,6 @@ constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT; constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 132; constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH; -constexpr coord_t MENUS_LINE_HEIGHT = 35; -constexpr coord_t MENUS_WIDTH = 200; -constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 7); - -constexpr rect_t MENUS_TOOLBAR_RECT = { 100, 51, 30, 209 }; +constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 7) + 8; #define ROTARY_ENCODER_SPEED() rotencSpeed diff --git a/radio/src/targets/nv14/libopenui_config.h b/radio/src/targets/nv14/libopenui_config.h index 21fc2f17e..9d88bc779 100644 --- a/radio/src/targets/nv14/libopenui_config.h +++ b/radio/src/targets/nv14/libopenui_config.h @@ -32,11 +32,7 @@ constexpr uint32_t ALERT_MESSAGE_LEFT = 15; constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 176; constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = 132; -constexpr coord_t MENUS_LINE_HEIGHT = 35; -constexpr coord_t MENUS_WIDTH = 200; constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 10); -constexpr rect_t MENUS_TOOLBAR_RECT = { 35, (LCD_H - MENUS_MAX_HEIGHT) / 2, 50, MENUS_MAX_HEIGHT }; - // Disable rotary encoder, as the NV14 does not have one #define ROTARY_ENCODER_SPEED() 0 diff --git a/radio/src/thirdparty/libopenui/src/choice.cpp b/radio/src/thirdparty/libopenui/src/choice.cpp index b69c96b0d..d7f52b737 100644 --- a/radio/src/thirdparty/libopenui/src/choice.cpp +++ b/radio/src/thirdparty/libopenui/src/choice.cpp @@ -17,17 +17,18 @@ */ #include "choice.h" + #include "menu.h" #include "theme.h" -void choice_changed_cb(lv_event_t *e) +void choice_changed_cb(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); + lv_obj_t* target = lv_event_get_target(e); if (target != nullptr) { - ChoiceBase *cb = (ChoiceBase*)lv_obj_get_user_data(target); + ChoiceBase* cb = (ChoiceBase*)lv_obj_get_user_data(target); if (cb) { std::string text = cb->getLabelText(); lv_label_set_text(cb->label, text.c_str()); @@ -38,20 +39,19 @@ void choice_changed_cb(lv_event_t *e) ChoiceBase::ChoiceBase(Window* parent, const rect_t& rect, ChoiceType type, WindowFlags windowFlags) : - FormField(parent, rect, windowFlags, 0, etx_choice_create), - type(type) + FormField(parent, rect, windowFlags, 0, etx_choice_create), type(type) { -// lv_obj_set_height(lvobj, LV_SIZE_CONTENT); -// lv_obj_set_width(lvobj, LV_SIZE_CONTENT); + // lv_obj_set_height(lvobj, LV_SIZE_CONTENT); + // lv_obj_set_width(lvobj, LV_SIZE_CONTENT); lv_obj_set_layout(lvobj, LV_LAYOUT_FLEX); lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW); lv_obj_add_event_cb(lvobj, choice_changed_cb, LV_EVENT_VALUE_CHANGED, lvobj); label = lv_label_create(lvobj); - - lv_group_t * def_group = lv_group_get_default(); - if(def_group) { - lv_group_add_obj(def_group, lvobj); + + lv_group_t* def_group = lv_group_get_default(); + if (def_group) { + lv_group_add_obj(def_group, lvobj); } lv_obj_set_style_pad_left(label, FIELD_PADDING_LEFT, LV_PART_MAIN); @@ -60,8 +60,9 @@ ChoiceBase::ChoiceBase(Window* parent, const rect_t& rect, ChoiceType type, // lv_obj_set // add the image - lv_obj_t *img = lv_img_create(lvobj); - lv_img_set_src(img, type == CHOICE_TYPE_DROPOWN ? LV_SYMBOL_DOWN : LV_SYMBOL_DIRECTORY); + lv_obj_t* img = lv_img_create(lvobj); + lv_img_set_src( + img, type == CHOICE_TYPE_DROPOWN ? LV_SYMBOL_DOWN : LV_SYMBOL_DIRECTORY); lv_obj_set_align(img, LV_ALIGN_RIGHT_MID); } @@ -70,7 +71,9 @@ std::string Choice::getLabelText() std::string text; if (textHandler != nullptr) { - if (_getValue) { text = textHandler(_getValue()); } + if (_getValue) { + text = textHandler(_getValue()); + } } else if (_getValue) { int val = _getValue(); val -= vmin; @@ -78,7 +81,7 @@ std::string Choice::getLabelText() text = values[val]; } } - + return text; } @@ -111,8 +114,8 @@ Choice::Choice(Window* parent, const rect_t& rect, const char* const values[], Choice::Choice(Window* parent, const rect_t& rect, std::vector values, int vmin, int vmax, - std::function _getValue, std::function _setValue, - WindowFlags windowFlags) : + std::function _getValue, + std::function _setValue, WindowFlags windowFlags) : ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags), values(std::move(values)), vmin(vmin), @@ -146,17 +149,16 @@ Choice::Choice(Window* parent, const rect_t& rect, const char* values, int vmin, lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); } -void Choice::addValue(const char * value) +void Choice::addValue(const char* value) { values.emplace_back(value); vmax += 1; } -void Choice::addValues(const char * const values[], uint8_t count) +void Choice::addValues(const char* const values[], uint8_t count) { this->values.reserve(this->values.size() + count); - for (uint8_t i = 0; i < count; i++) - this->values.emplace_back(values[i]); + for (uint8_t i = 0; i < count; i++) this->values.emplace_back(values[i]); vmax += count; } @@ -165,7 +167,7 @@ void Choice::setValues(std::vector values) this->values = std::move(values); } -void Choice::setValues(const char * const values[]) +void Choice::setValues(const char* const values[]) { this->values.clear(); if (values) { @@ -186,18 +188,17 @@ void Choice::setValue(int val) void Choice::onClicked() { - if (!longPressData.isLongPressed) - openMenu(); + if (!longPressData.isLongPressed) openMenu(); } -void Choice::fillMenu(Menu *menu, const FilterFct& filter) +void Choice::fillMenu(Menu* menu, const FilterFct& filter) { menu->removeLines(); - auto value = _getValue(); + auto value = getIntValue(); int count = 0; int selectedIx = -1; - int selectedIx0 = -1; + selectedIx0 = -1; for (int i = vmin; i <= vmax; ++i) { if (filter && !filter(i)) continue; if (isValueAvailable && !isValueAvailable(i)) continue; @@ -208,8 +209,12 @@ void Choice::fillMenu(Menu *menu, const FilterFct& filter) } else { menu->addLineBuffered(std::to_string(i), [=]() { setValue(i); }); } - if (value == i) { selectedIx = count; } - if (i == 0) { selectedIx0 = count; } + if (value == i) { + selectedIx = count; + } + if (i == 0) { + selectedIx0 = count; + } ++count; } if (fillMenuHandler) { @@ -234,12 +239,12 @@ void Choice::openMenu() auto menu = new Menu(this); if (!menuTitle.empty()) menu->setTitle(menuTitle); - fillMenu(menu); - if (beforeDisplayMenuHandler) { beforeDisplayMenuHandler(menu); } + fillMenu(menu); + menu->setCloseHandler([=]() { setEditMode(false); }); } diff --git a/radio/src/thirdparty/libopenui/src/choice.h b/radio/src/thirdparty/libopenui/src/choice.h index a5ca313f0..11568fbb2 100644 --- a/radio/src/thirdparty/libopenui/src/choice.h +++ b/radio/src/thirdparty/libopenui/src/choice.h @@ -19,12 +19,13 @@ #pragma once #include + #include "form.h" -typedef void (*lvHandler_t)(void*); +typedef void (*lvHandler_t)(void *); typedef struct { - void* userData; + void *userData; bool isLongPressed; lvHandler_t lv_LongPressHandler; } lv_eventData_t; @@ -44,168 +45,165 @@ class ChoiceBase : public FormField ChoiceBase(Window *parent, const rect_t &rect, ChoiceType type = CHOICE_TYPE_DROPOWN, WindowFlags windowFlags = 0); - + protected: ChoiceType type; - lv_obj_t* label; + lv_obj_t *label; friend void choice_changed_cb(lv_event_t *e); virtual std::string getLabelText() { return ""; }; }; -class Choice: public ChoiceBase { - public: - Choice(Window* parent, const rect_t &rect, int vmin, int vmax, - std::function _getValue, - std::function _setValue = nullptr, - WindowFlags windowFlags = 0); - Choice(Window* parent, const rect_t &rect, - std::vector values, int vmin, int vmax, - std::function _getValue, - std::function _setValue = nullptr, - WindowFlags windowFlags = 0); - Choice(Window* parent, const rect_t &rect, const char *const values[], - int vmin, int vmax, std::function _getValue, - std::function _setValue = nullptr, - WindowFlags windowFlags = 0); - Choice(Window* parent, const rect_t &rect, const char *values, int vmin, - int vmax, std::function _getValue, - std::function _setValue = nullptr, - WindowFlags windowFlags = 0); +class Choice : public ChoiceBase +{ + public: + Choice(Window *parent, const rect_t &rect, int vmin, int vmax, + std::function _getValue, + std::function _setValue = nullptr, + WindowFlags windowFlags = 0); + Choice(Window *parent, const rect_t &rect, std::vector values, + int vmin, int vmax, std::function _getValue, + std::function _setValue = nullptr, + WindowFlags windowFlags = 0); + Choice(Window *parent, const rect_t &rect, const char *const values[], + int vmin, int vmax, std::function _getValue, + std::function _setValue = nullptr, + WindowFlags windowFlags = 0); + Choice(Window *parent, const rect_t &rect, const char *values, int vmin, + int vmax, std::function _getValue, + std::function _setValue = nullptr, + WindowFlags windowFlags = 0); - void addValue(const char *value); + void addValue(const char *value); - void addValues(const char *const values[], uint8_t count); + void addValues(const char *const values[], uint8_t count); - void setValues(std::vector values); + void setValues(std::vector values); - void setValues(const char *const values[]); + void setValues(const char *const values[]); #if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "Choice"; - } + std::string getName() const override { return "Choice"; } #endif - void onClicked() override; + void onClicked() override; - void setFillMenuHandler(std::function handler) - { - fillMenuHandler = std::move(handler); - } - - void setBeforeDisplayMenuHandler(std::function handler) - { - beforeDisplayMenuHandler = std::move(handler); + void setFillMenuHandler(std::function handler) + { + fillMenuHandler = std::move(handler); + } + + void setBeforeDisplayMenuHandler(std::function handler) + { + beforeDisplayMenuHandler = std::move(handler); + } + + void setSetValueHandler(std::function handler) + { + _setValue = std::move(handler); + } + + void setGetValueHandler(std::function handler) + { + _getValue = std::move(handler); + } + + void setAvailableHandler(std::function handler) + { + isValueAvailable = std::move(handler); + } + + unsigned getIndexFromValue(int value) const + { + if (!isValueAvailable) { + return value - vmin; } - void setSetValueHandler(std::function handler) - { - _setValue = std::move(handler); - } - - void setGetValueHandler(std::function handler) - { - _getValue = std::move(handler); - } - - void setAvailableHandler(std::function handler) - { - isValueAvailable = std::move(handler); - } - - unsigned getIndexFromValue(int value) const - { - if (!isValueAvailable) { - return value - vmin; + unsigned index = 0; + for (int i = vmin; i < value; i++) { + if (isValueAvailable(i)) { + index++; } + } + return index; + } - unsigned index = 0; - for (int i = vmin; i < value; i++) { - if (isValueAvailable(i)) { - index++; - } - } - return index; + int getValueFromIndex(int index) const + { + if (!isValueAvailable) { + return vmin + index; } - int getValueFromIndex(int index) const - { - if (!isValueAvailable) { - return vmin + index; - } - - int value = vmin - 1; - while (index >= 0) { - index--; + int value = vmin - 1; + while (index >= 0) { + index--; + value++; + while (value < vmax && !isValueAvailable(value)) { value++; - while (value < vmax && !isValueAvailable(value)) { - value++; - } } - return value; } + return value; + } - void setValue(int val); - int getIntValue() const { return _getValue(); } + virtual void setValue(int val); + virtual int getIntValue() const { return _getValue(); } - unsigned getValuesCount() const - { - return getIndexFromValue(vmax + 1); - } + unsigned getValuesCount() const { return getIndexFromValue(vmax + 1); } - void setTextHandler(std::function handler) - { - textHandler = std::move(handler); - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); - } + void setTextHandler(std::function handler) + { + textHandler = std::move(handler); + lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); + } - void setMenuTitle(std::string value) - { - menuTitle = std::move(value); - } + void setMenuTitle(std::string value) { menuTitle = std::move(value); } + std::string getMenuTitle() const { return menuTitle; } - void setMin(int value) - { - vmin = value; - invalidate(); - } + void setMin(int value) + { + vmin = value; + invalidate(); + } - void setMax(int value) - { - vmax = value; - invalidate(); - } + void setMax(int value) + { + vmax = value; + invalidate(); + } - void set_lv_LongPressHandler(lvHandler_t longPressHandler, void* data); + int getMin() const { return vmin; } + int getMax() const { return vmax; } - protected: - friend class MenuToolbar; + void set_lv_LongPressHandler(lvHandler_t longPressHandler, void *data); - std::string getLabelText() override; - std::vector values; - int vmin = 0; - int vmax = 0; - std::string menuTitle; - std::function _getValue; - std::function _setValue; - std::function isValueAvailable; - std::function textHandler; - std::function fillMenuHandler; - std::function beforeDisplayMenuHandler; + int selectedIx0 = 0; - typedef std::function FilterFct; - void fillMenu(Menu *menu, const FilterFct& filter = nullptr); + protected: + friend class MenuToolbar; - virtual void openMenu(); + std::string getLabelText() override; + std::vector values; + int vmin = 0; + int vmax = 0; + std::string menuTitle; + std::function _getValue; + std::function _setValue; + std::function isValueAvailable; + std::function textHandler; + std::function fillMenuHandler; + std::function beforeDisplayMenuHandler; - lv_eventData_t longPressData; - std::function longPressHandler = nullptr; + typedef std::function FilterFct; + void fillMenu(Menu *menu, const FilterFct &filter = nullptr); - static void ClickHandler(lv_event_t* e) - { - auto ch = (Choice*)lv_event_get_user_data(e); - if (ch) ch->longPressData.isLongPressed = false; - } + virtual void openMenu(); + + lv_eventData_t longPressData; + std::function longPressHandler = nullptr; + + static void ClickHandler(lv_event_t *e) + { + auto ch = (Choice *)lv_event_get_user_data(e); + if (ch) ch->longPressData.isLongPressed = false; + } }; diff --git a/radio/src/thirdparty/libopenui/src/libopenui_defines.h b/radio/src/thirdparty/libopenui/src/libopenui_defines.h index 20198b855..a3ce4c621 100644 --- a/radio/src/thirdparty/libopenui/src/libopenui_defines.h +++ b/radio/src/thirdparty/libopenui/src/libopenui_defines.h @@ -41,8 +41,8 @@ enum FontIndex constexpr uint32_t MENU_HEADER_BUTTON_WIDTH = 33; constexpr uint32_t MENU_HEADER_BUTTONS_LEFT = 47; -constexpr uint32_t MENUS_TOOLBAR_BUTTON_WIDTH = 30; -constexpr uint32_t MENUS_TOOLBAR_BUTTON_PADDING = 3; +constexpr uint32_t MENUS_TOOLBAR_BUTTON_WIDTH = 32; +constexpr uint32_t MENUS_TOOLBAR_BUTTON_PADDING = 4; constexpr uint32_t MENU_HEADER_HEIGHT = 45; constexpr uint32_t MENU_TITLE_TOP = 48; @@ -108,5 +108,8 @@ constexpr coord_t MODEL_SELECT_FOOTER_HEIGHT = 24; #define LV_OBJ_FLAG_ENCODER_ACCEL LV_OBJ_FLAG_USER_1 +constexpr coord_t MENUS_LINE_HEIGHT = 35; +constexpr coord_t MENUS_WIDTH = 200; + #include "libopenui_config.h" diff --git a/radio/src/thirdparty/libopenui/src/menu.cpp b/radio/src/thirdparty/libopenui/src/menu.cpp index fa73534ce..69f93c515 100644 --- a/radio/src/thirdparty/libopenui/src/menu.cpp +++ b/radio/src/thirdparty/libopenui/src/menu.cpp @@ -17,12 +17,15 @@ */ #include "menu.h" -#include "font.h" -#include "theme.h" #include -void MenuBody::onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) +#include "font.h" +#include "menutoolbar.h" +#include "theme.h" + +void MenuBody::onDrawBegin(uint16_t row, uint16_t col, + lv_obj_draw_part_dsc_t* dsc) { lv_canvas_t* icon = (lv_canvas_t*)lines[row].getIcon(); if (!icon) return; @@ -32,15 +35,16 @@ void MenuBody::onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* d dsc->label_dsc->ofs_x = img->w + cell_left; } -void MenuBody::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) +void MenuBody::onDrawEnd(uint16_t row, uint16_t col, + lv_obj_draw_part_dsc_t* dsc) { - if(row >= lines.size()) return; + if (row >= lines.size()) return; lv_obj_t* icon = lines[row].getIcon(); if (icon) { lv_draw_img_dsc_t img_dsc; lv_draw_img_dsc_init(&img_dsc); - + lv_img_dsc_t* img = lv_canvas_get_img(icon); lv_area_t coords; @@ -51,12 +55,11 @@ void MenuBody::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc coords.x2 = coords.x1 + img->header.w - 1; coords.y1 = dsc->draw_area->y1 + (area_h - img->header.h) / 2; coords.y2 = coords.y1 + img->header.h - 1; - + lv_draw_img(dsc->draw_ctx, &img_dsc, &coords, img); } - if(lines[row].isChecked != nullptr && - lines[row].isChecked()) { + if (lines[row].isChecked != nullptr && lines[row].isChecked()) { lv_area_t coords; lv_coord_t area_h = lv_area_get_height(dsc->draw_area); lv_coord_t cell_right = lv_obj_get_style_pad_right(lvobj, LV_PART_ITEMS); @@ -65,17 +68,28 @@ void MenuBody::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc coords.x2 = coords.x1 + font_h; coords.y1 = dsc->draw_area->y1 + (area_h - font_h) / 2; coords.y2 = coords.y1 + font_h - 1; - lv_draw_label(dsc->draw_ctx, dsc->label_dsc, &coords, LV_SYMBOL_OK, nullptr); + lv_draw_label(dsc->draw_ctx, dsc->label_dsc, &coords, LV_SYMBOL_OK, + nullptr); } } -static void _force_editing(lv_group_t* g) +static void _force_editing(lv_group_t* g) { lv_group_set_editing(g, true); } + +static void localLongPressHandler(lv_event_t* e) { - lv_group_set_editing(g, true); + MenuBody* menuBody = (MenuBody*)lv_event_get_user_data(e); + if (menuBody) menuBody->longPress(); } -MenuBody::MenuBody(Window * parent, const rect_t & rect): - TableField(parent, rect) +void MenuBody::longPress() +{ + isLongPressed = true; + Menu* menu = getParentMenu(); + if (menu) menu->longPress(); +} + +MenuBody::MenuBody(Window* parent, const rect_t& rect) : + TableField(parent, rect) { // Allow encoder acceleration lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL); @@ -96,9 +110,12 @@ MenuBody::MenuBody(Window * parent, const rect_t & rect): }); lv_group_set_editing(g, true); } + + lv_obj_add_event_cb(lvobj, localLongPressHandler, LV_EVENT_LONG_PRESSED, + this); } -void MenuBody::addLine(const std::string &text, std::function onPress, +void MenuBody::addLine(const std::string& text, std::function onPress, std::function isChecked, bool update) { lines.emplace_back(text, std::move(onPress), std::move(isChecked), nullptr); @@ -109,16 +126,15 @@ void MenuBody::addLine(const std::string &text, std::function onPress, } } -void MenuBody::addLine(const uint8_t *icon_mask, const std::string &text, +void MenuBody::addLine(const uint8_t* icon_mask, const std::string& text, std::function onPress, - std::function isChecked, - bool update) + std::function isChecked, bool update) { lv_obj_t* canvas = lv_canvas_create(nullptr); lines.emplace_back(text, std::move(onPress), std::move(isChecked), canvas); - lv_coord_t w = *((uint16_t *)icon_mask); - lv_coord_t h = *(((uint16_t *)icon_mask)+1); + lv_coord_t w = *((uint16_t*)icon_mask); + lv_coord_t h = *(((uint16_t*)icon_mask) + 1); void* buf = (void*)(icon_mask + 4); lv_canvas_set_buffer(canvas, buf, w, h, LV_IMG_CF_ALPHA_8BIT); @@ -131,7 +147,7 @@ void MenuBody::addLine(const uint8_t *icon_mask, const std::string &text, void MenuBody::updateLines() { setRowCount(lines.size()); - for(unsigned int idx = 0; idx < lines.size(); idx++) { + for (unsigned int idx = 0; idx < lines.size(); idx++) { lv_table_set_cell_value(lvobj, idx, 0, lines[idx].text.c_str()); } } @@ -146,14 +162,11 @@ void MenuBody::removeLines() lv_obj_scroll_to_y(lvobj, 0, LV_ANIM_OFF); } -coord_t MenuBody::getContentHeight() -{ - return lv_obj_get_self_height(lvobj); -} +coord_t MenuBody::getContentHeight() { return lv_obj_get_self_height(lvobj); } void MenuBody::onPress(size_t index) { - Menu *menu = getParentMenu(); + Menu* menu = getParentMenu(); if (index < lines.size()) { if (menu->multiple) { if (selectedIndex == (int)index) @@ -196,15 +209,14 @@ void MenuBody::setIndex(int index) table->col_act = LV_TABLE_CELL_NONE; return; } - + table->row_act = index; table->col_act = 0; lv_coord_t h_before = 0; - for (uint16_t i = 0; i < table->row_act; i++) - h_before += table->row_h[i]; + for (uint16_t i = 0; i < table->row_act; i++) h_before += table->row_h[i]; - lv_coord_t row_h = table->row_h[table->row_act]; + lv_coord_t row_h = table->row_h[table->row_act]; lv_coord_t scroll_y = lv_obj_get_scroll_y(lvobj); lv_obj_update_layout(lvobj); @@ -225,24 +237,16 @@ void MenuBody::setIndex(int index) void MenuBody::onPress(uint16_t row, uint16_t col) { - onPress(row); + if (!isLongPressed) onPress(row); + isLongPressed = false; } -void MenuBody::selectNext(MENU_DIRECTION direction) -{ - // look for the next non separator line - int index = selectedIndex + direction; - setIndex(rangeCheck(index)); -} - - void MenuBody::onEvent(event_t event) { #if defined(HARDWARE_KEYS) if (event == EVT_KEY_BREAK(KEY_EXIT)) { onCancel(); - } - else { + } else { TableField::onEvent(event); } #endif @@ -250,7 +254,7 @@ void MenuBody::onEvent(event_t event) void MenuBody::onCancel() { - if(_onCancel) _onCancel(); + if (_onCancel) _onCancel(); TableField::onCancel(); } @@ -274,14 +278,14 @@ void MenuWindowContent::deleteLater(bool detach, bool trash) ModalWindowContent::deleteLater(detach, trash); } -Menu::Menu(Window * parent, bool multiple): - ModalWindow(parent, true), - content(new MenuWindowContent(this)), - multiple(multiple) +Menu::Menu(Window* parent, bool multiple) : + ModalWindow(parent, true), + content(new MenuWindowContent(this)), + multiple(multiple) { } -void Menu::setToolbar(Window * window) +void Menu::setToolbar(MenuToolbar* window) { toolbar = window; updatePosition(); @@ -293,10 +297,10 @@ void Menu::setToolbar(Window * window) void Menu::setOutline(Window* obj) { lv_obj_set_style_outline_width(obj->getLvObj(), 2, LV_PART_MAIN); - lv_obj_set_style_outline_color(obj->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN); - lv_obj_set_style_outline_opa(obj->getLvObj(), LV_OPA_100, LV_PART_MAIN); - lv_obj_set_style_outline_pad(obj->getLvObj(), 1, LV_PART_MAIN); - + lv_obj_set_style_outline_color( + obj->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN); + lv_obj_set_style_outline_opa(obj->getLvObj(), LV_OPA_100, LV_PART_MAIN); + lv_obj_set_style_outline_pad(obj->getLvObj(), 1, LV_PART_MAIN); } void Menu::updatePosition() @@ -304,10 +308,10 @@ void Menu::updatePosition() coord_t height = content->body.getContentHeight(); if (toolbar) { - content->setLeft((LCD_W - content->width() + toolbar->width())/2); + content->setLeft((LCD_W - content->width() + toolbar->width()) / 2); setOutline(toolbar); } else { - content->setLeft((LCD_W - content->width())/2); + content->setLeft((LCD_W - content->width()) / 2); auto headerHeight = content->getHeaderHeight(); auto bodyHeight = min(height, MENUS_MAX_HEIGHT - headerHeight); content->setTop((LCD_H - headerHeight - bodyHeight) / 2); @@ -324,32 +328,35 @@ void Menu::setTitle(std::string text) updatePosition(); } -void Menu::addLine(const std::string &text, std::function onPress, +void Menu::addLine(const std::string& text, std::function onPress, std::function isChecked) { content->body.addLine(text, std::move(onPress), std::move(isChecked)); updatePosition(); } -void Menu::addLine(const uint8_t *icon_mask, const std::string &text, +void Menu::addLine(const uint8_t* icon_mask, const std::string& text, std::function onPress, std::function isChecked) { - content->body.addLine(icon_mask, text, std::move(onPress), std::move(isChecked)); + content->body.addLine(icon_mask, text, std::move(onPress), + std::move(isChecked)); updatePosition(); } -void Menu::addLineBuffered(const std::string &text, std::function onPress, - std::function isChecked) +void Menu::addLineBuffered(const std::string& text, + std::function onPress, + std::function isChecked) { content->body.addLine(text, std::move(onPress), std::move(isChecked), false); } -void Menu::addLineBuffered(const uint8_t *icon_mask, const std::string &text, - std::function onPress, - std::function isChecked) +void Menu::addLineBuffered(const uint8_t* icon_mask, const std::string& text, + std::function onPress, + std::function isChecked) { - content->body.addLine(icon_mask, text, std::move(onPress), std::move(isChecked), false); + content->body.addLine(icon_mask, text, std::move(onPress), + std::move(isChecked), false); } void Menu::updateLines() @@ -367,20 +374,21 @@ void Menu::removeLines() void Menu::onEvent(event_t event) { #if defined(HARDWARE_KEYS) - if (toolbar && - (event == EVT_KEY_BREAK(KEY_PAGEDN) || + if (toolbar && (event == EVT_KEY_BREAK(KEY_PAGEDN) || #if defined(KEYS_GPIO_REG_PAGEUP) - event == EVT_KEY_BREAK(KEY_PAGEUP) + event == EVT_KEY_BREAK(KEY_PAGEUP) #else - event == EVT_KEY_LONG(KEY_PAGEDN) + event == EVT_KEY_LONG(KEY_PAGEDN) #endif - )) { + )) { toolbar->onEvent(event); } #endif } -void Menu::onCancel() +void Menu::onCancel() { deleteLater(); } + +void Menu::longPress() { - deleteLater(); + if (toolbar) toolbar->longPress(); } diff --git a/radio/src/thirdparty/libopenui/src/menu.h b/radio/src/thirdparty/libopenui/src/menu.h index 037d28971..9ca2efa2e 100644 --- a/radio/src/thirdparty/libopenui/src/menu.h +++ b/radio/src/thirdparty/libopenui/src/menu.h @@ -18,51 +18,49 @@ #pragma once -#include #include -#include #include +#include +#include #include "modal_window.h" #include "table.h" class Menu; class MenuWindowContent; +class MenuToolbar; struct lvobj_delete { constexpr lvobj_delete() = default; - void operator()(lv_obj_t* obj) const { - lv_obj_del(obj); - } + void operator()(lv_obj_t *obj) const { lv_obj_del(obj); } }; -class MenuBody: public TableField +class MenuBody : public TableField { friend class MenuWindowContent; friend class Menu; - enum MENU_DIRECTION - { - DIRECTION_UP = 1, - DIRECTION_DOWN = -1 - }; + enum MENU_DIRECTION { DIRECTION_UP = 1, DIRECTION_DOWN = -1 }; class MenuLine { friend class MenuBody; public: - MenuLine(const std::string& text, std::function onPress, std::function isChecked, - lv_obj_t *icon) : - text(text), onPress(std::move(onPress)), isChecked(std::move(isChecked)), icon(icon) + MenuLine(const std::string &text, std::function onPress, + std::function isChecked, lv_obj_t *icon) : + text(text), + onPress(std::move(onPress)), + isChecked(std::move(isChecked)), + icon(icon) { } MenuLine(MenuLine &) = delete; MenuLine(MenuLine &&) = default; - lv_obj_t* getIcon() { return icon.get(); } - + lv_obj_t *getIcon() { return icon.get(); } + protected: std::string text; std::function onPress; @@ -70,175 +68,157 @@ class MenuBody: public TableField std::unique_ptr icon; }; - public: - MenuBody(Window * parent, const rect_t & rect); + public: + MenuBody(Window *parent, const rect_t &rect); #if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "MenuBody"; - } + std::string getName() const override { return "MenuBody"; } #endif - void setIndex(int index); + void setIndex(int index); - int selection() const - { - return selectedIndex; - } + int selection() const { return selectedIndex; } - int count() const - { - return lines.size(); - } + int count() const { return lines.size(); } - void onEvent(event_t event) override; - void onCancel() override; + void onEvent(event_t event) override; + void onCancel() override; - void addLine(const std::string &text, std::function onPress, - std::function isChecked, bool update = true); + void addLine(const std::string &text, std::function onPress, + std::function isChecked, bool update = true); - void addLine(const uint8_t *icon_mask, const std::string &text, - std::function onPress, - std::function isChecked, - bool update = true); + void addLine(const uint8_t *icon_mask, const std::string &text, + std::function onPress, std::function isChecked, + bool update = true); - void updateLines(); + void updateLines(); - void removeLines(); + void removeLines(); - void setCancelHandler(std::function handler) - { - _onCancel = std::move(handler); - } + void setCancelHandler(std::function handler) + { + _onCancel = std::move(handler); + } - coord_t getContentHeight(); + coord_t getContentHeight(); - void onPress(size_t index); - - protected: - void onPress(uint16_t row, uint16_t col) override; - void onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override; - void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override; + void onPress(size_t index); + void longPress(); - void selectNext(MENU_DIRECTION direction); - int rangeCheck(int); + protected: + bool isLongPressed = false; - std::vector lines; - int selectedIndex = 0; - std::function _onCancel; + void onPress(uint16_t row, uint16_t col) override; + void onDrawBegin(uint16_t row, uint16_t col, + lv_obj_draw_part_dsc_t *dsc) override; + void onDrawEnd(uint16_t row, uint16_t col, + lv_obj_draw_part_dsc_t *dsc) override; - inline Menu * getParentMenu(); + int rangeCheck(int); + + std::vector lines; + int selectedIndex = 0; + std::function _onCancel; + + inline Menu *getParentMenu(); + + void onSelected(uint16_t row, uint16_t col) override { selectedIndex = row; } }; -class MenuWindowContent: public ModalWindowContent +class MenuWindowContent : public ModalWindowContent { friend class Menu; - public: - explicit MenuWindowContent(Menu * parent); + public: + explicit MenuWindowContent(Menu *parent); - coord_t getHeaderHeight() const; + coord_t getHeaderHeight() const; - void deleteLater(bool detach = true, bool trash = true) override; + void deleteLater(bool detach = true, bool trash = true) override; #if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "MenuWindowContent"; - } + std::string getName() const override { return "MenuWindowContent"; } #endif - protected: - MenuBody body; + protected: + MenuBody body; }; -class Menu: public ModalWindow +class Menu : public ModalWindow { friend class MenuBody; - public: - explicit Menu(Window * parent, bool multiple = false); + public: + explicit Menu(Window *parent, bool multiple = false); #if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "Menu"; - } + std::string getName() const override { return "Menu"; } #endif - - void setCancelHandler(std::function handler) - { - content->body.setCancelHandler(std::move(handler)); + + void setCancelHandler(std::function handler) + { + content->body.setCancelHandler(std::move(handler)); + } + + void setWaitHandler(std::function handler) + { + waitHandler = std::move(handler); + } + + void setToolbar(MenuToolbar *window); + + void setTitle(std::string text); + + void addLine(const std::string &text, std::function onPress, + std::function isChecked = nullptr); + + void addLine(const uint8_t *icon_mask, const std::string &text, + std::function onPress, + std::function isChecked = nullptr); + + void addLineBuffered(const std::string &text, std::function onPress, + std::function isChecked = nullptr); + + void addLineBuffered(const uint8_t *icon_mask, const std::string &text, + std::function onPress, + std::function isChecked = nullptr); + + void updateLines(); + + void addSeparator(); + + void removeLines(); + + unsigned count() const { return content->body.count(); } + + int selection() const { return content->body.selection(); } + + void select(int index) { content->body.setIndex(index); } + + void onEvent(event_t event) override; + void onCancel() override; + + void checkEvents() override + { + ModalWindow::checkEvents(); + if (waitHandler) { + waitHandler(); } + } - void setWaitHandler(std::function handler) - { - waitHandler = std::move(handler); - } + void longPress(); - void setToolbar(Window* window); + protected: + MenuWindowContent *content; + bool multiple; + MenuToolbar *toolbar = nullptr; + std::function waitHandler; + void updatePosition(); - void setTitle(std::string text); - - void addLine(const std::string &text, std::function onPress, - std::function isChecked = nullptr); - - void addLine(const uint8_t *icon_mask, const std::string &text, - std::function onPress, - std::function isChecked = nullptr); - - void addLineBuffered(const std::string &text, std::function onPress, - std::function isChecked = nullptr); - - void addLineBuffered(const uint8_t *icon_mask, const std::string &text, - std::function onPress, - std::function isChecked = nullptr); - - void updateLines(); - - void addSeparator(); - - void removeLines(); - - unsigned count() const - { - return content->body.count(); - } - - int selection() const - { - return content->body.selection(); - } - - void select(int index) - { - content->body.setIndex(index); - } - - void onEvent(event_t event) override; - void onCancel() override; - - void checkEvents() override - { - ModalWindow::checkEvents(); - if (waitHandler) { - waitHandler(); - } - } - - protected: - MenuWindowContent* content; - bool multiple; - Window * toolbar = nullptr; - std::function waitHandler; - void updatePosition(); - - void setOutline(Window* obj); + void setOutline(Window *obj); }; -Menu * MenuBody::getParentMenu() +Menu *MenuBody::getParentMenu() { return static_cast(getParent()->getParent()); } - diff --git a/radio/src/thirdparty/libopenui/src/menutoolbar.cpp b/radio/src/thirdparty/libopenui/src/menutoolbar.cpp index 74142858e..a6b9c809c 100644 --- a/radio/src/thirdparty/libopenui/src/menutoolbar.cpp +++ b/radio/src/thirdparty/libopenui/src/menutoolbar.cpp @@ -17,8 +17,9 @@ */ #include "menutoolbar.h" -#include "choice.h" + #include "font.h" +#include "translations.h" static void toolbar_btn_defocus(lv_event_t* event) { @@ -29,56 +30,49 @@ static void toolbar_btn_defocus(lv_event_t* event) MenuToolbarButton::MenuToolbarButton(Window* parent, const rect_t& rect, const char* picto) : - Button(parent, rect, nullptr, 0, 0, window_create), picto(picto) + Button(parent, rect, nullptr, 0, 0, etx_menu_button_create) { lv_obj_add_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS); lv_obj_add_event_cb(lvobj, toolbar_btn_defocus, LV_EVENT_DEFOCUSED, nullptr); + + auto label = lv_label_create(lvobj); + lv_label_set_text(label, picto); + lv_obj_center(label); } -void MenuToolbarButton::paint(BitmapBuffer * dc) -{ - lv_coord_t width = lv_obj_get_content_width(lvobj); - if (checked()) { - dc->drawSolidFilledRect( - MENUS_TOOLBAR_BUTTON_PADDING, MENUS_TOOLBAR_BUTTON_PADDING, - width - 2 * MENUS_TOOLBAR_BUTTON_PADDING, - MENUS_TOOLBAR_BUTTON_WIDTH - 2 * MENUS_TOOLBAR_BUTTON_PADDING, - COLOR_THEME_FOCUS); - dc->drawText(width / 2, (rect.h - getFontHeight(FONT(L))) / 2 + 2, - picto, FONT(L) | CENTERED | COLOR_THEME_PRIMARY2); - } else { - dc->drawText(width / 2, (rect.h - getFontHeight(FONT(L))) / 2 + 2, - picto, FONT(L) | CENTERED | COLOR_THEME_PRIMARY1); - } -} - -MenuToolbar::MenuToolbar(Choice* choice, Menu* menu) : - Window(menu, MENUS_TOOLBAR_RECT, OPAQUE), +MenuToolbar::MenuToolbar(Choice* choice, Menu* menu, const int columns) : + Window(menu, {0, (LCD_H - MENUS_MAX_HEIGHT) / 2, 76, MENUS_MAX_HEIGHT}, + OPAQUE), choice(choice), menu(menu), + filterColumns(columns), group(lv_group_create()) { - lv_group_add_obj(group, lvobj); + lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY3), 0); + + setWidth((MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING) * + columns + + MENUS_TOOLBAR_BUTTON_PADDING); + + addButton(STR_SELECT_MENU_ALL, choice->getMin(), choice->getMax(), nullptr, + nullptr, true); } -MenuToolbar::~MenuToolbar() -{ - lv_group_del(group); -} +MenuToolbar::~MenuToolbar() { lv_group_del(group); } void MenuToolbar::resetFilter() { if (lv_group_get_focused(group) != lvobj) { lv_group_focus_obj(lvobj); choice->fillMenu(menu); + menu->setTitle(choice->menuTitle); } } void MenuToolbar::onEvent(event_t event) { - if (event == EVT_KEY_BREAK(KEY_PAGEDN)) { lv_group_focus_next(group); } @@ -90,54 +84,70 @@ void MenuToolbar::onEvent(event_t event) #endif lv_group_focus_prev(group); } - + auto obj = lv_group_get_focused(group); - if (!obj) { - choice->fillMenu(menu); - } else { - lv_event_send(obj, LV_EVENT_CLICKED, nullptr); - } + lv_event_send(obj, LV_EVENT_CLICKED, nullptr); } -rect_t MenuToolbar::getButtonRect(size_t buttons) +rect_t MenuToolbar::getButtonRect(bool wideButton) { - coord_t y = buttons * (MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING); - return {0, y, LV_PCT(100), MENUS_TOOLBAR_BUTTON_WIDTH}; + if (wideButton && (nxtBtnPos % filterColumns)) + nxtBtnPos = nxtBtnPos - (nxtBtnPos % filterColumns) + filterColumns; + coord_t x = (nxtBtnPos % filterColumns) * + (MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING) + + MENUS_TOOLBAR_BUTTON_PADDING; + coord_t y = (nxtBtnPos / filterColumns) * + (MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING) + + MENUS_TOOLBAR_BUTTON_PADDING; + coord_t w = + wideButton ? (MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING) * + (filterColumns - 1) + + MENUS_TOOLBAR_BUTTON_WIDTH + : MENUS_TOOLBAR_BUTTON_WIDTH; + nxtBtnPos += wideButton ? filterColumns : 1; + return {x, y, w, MENUS_TOOLBAR_BUTTON_WIDTH}; } bool MenuToolbar::filterMenu(MenuToolbarButton* btn, int16_t filtermin, - int16_t filtermax, const FilterFct& filterFunc) + int16_t filtermax, const Choice::FilterFct& filterFunc, + const char* title) { btn->check(!btn->checked()); - Choice::FilterFct filter = nullptr; + filter = nullptr; if (btn->checked()) { + if (title) + menu->setTitle(title); + else + menu->setTitle(choice->menuTitle); filter = [=](int16_t index) { - if (filterFunc) - return filterFunc(index); + if (filterFunc) return filterFunc(index); return index == 0 || (abs(index) >= filtermin && abs(index) <= filtermax); }; + lv_group_focus_obj(btn->getLvObj()); + choice->fillMenu(menu, filter); + } else { + lv_event_send(allBtn->getLvObj(), LV_EVENT_CLICKED, nullptr); } - choice->fillMenu(menu, filter); return btn->checked(); } typedef std::function IsValueAvailable; -static int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable) +static bool checkFirstAvailable(int min, int max, + IsValueAvailable isValueAvailable) { - int retval = 0; for (int i = min; i <= max; i++) { if (isValueAvailable(i)) { - retval = i; - break; + return true; } } - return retval; + return false; } void MenuToolbar::addButton(const char* picto, int16_t filtermin, - int16_t filtermax, const FilterFct& filterFunc) + int16_t filtermax, const Choice::FilterFct& filterFunc, + const char* title, bool wideButton) { int vmin = choice->vmin; int vmax = choice->vmax; @@ -145,19 +155,19 @@ void MenuToolbar::addButton(const char* picto, int16_t filtermin, if (vmin > filtermin || vmax < filtermin) return; if (choice->isValueAvailable && - getFirstAvailable(filtermin, filtermax, choice->isValueAvailable) == 0) + !checkFirstAvailable(filtermin, filtermax, choice->isValueAvailable)) return; - rect_t r = getButtonRect(children.size()); + rect_t r = getButtonRect(wideButton); auto button = new MenuToolbarButton(this, r, picto); - button->setPressHandler( - std::bind(&MenuToolbar::filterMenu, this, button, filtermin, filtermax, filterFunc)); + button->setPressHandler(std::bind(&MenuToolbar::filterMenu, this, button, + filtermin, filtermax, filterFunc, title)); lv_group_add_obj(group, button->getLvObj()); -} -void MenuToolbar::onClicked() -{ - choice->fillMenu(menu); + if (children.size() == 1) { + allBtn = button; + lv_event_send(allBtn->getLvObj(), LV_EVENT_CLICKED, nullptr); + } } diff --git a/radio/src/thirdparty/libopenui/src/menutoolbar.h b/radio/src/thirdparty/libopenui/src/menutoolbar.h index 4207ca5f8..3cfe62c6f 100644 --- a/radio/src/thirdparty/libopenui/src/menutoolbar.h +++ b/radio/src/thirdparty/libopenui/src/menutoolbar.h @@ -19,6 +19,7 @@ #pragma once #include "button.h" +#include "choice.h" #include "menu.h" class Choice; @@ -27,10 +28,8 @@ class MenuToolbarButton : public Button { public: MenuToolbarButton(Window* parent, const rect_t& rect, const char* picto); - void paint(BitmapBuffer* dc) override; protected: - const char* picto; }; class MenuToolbar : public Window @@ -38,23 +37,29 @@ class MenuToolbar : public Window // friend Menu; public: - MenuToolbar(Choice* choice, Menu* menu); + MenuToolbar(Choice* choice, Menu* menu, const int columns); ~MenuToolbar(); void resetFilter(); void onEvent(event_t event) override; + virtual void longPress() {} + protected: Choice* choice; + Choice::FilterFct filter; Menu* menu; - typedef std::function FilterFct; + int nxtBtnPos = 0; + int filterColumns = 0; + MenuToolbarButton* allBtn = nullptr; lv_group_t* group; - void addButton(const char* picto, int16_t filtermin, int16_t filtermax, const FilterFct& filterFunc = nullptr); - bool filterMenu(MenuToolbarButton* btn, int16_t filtermin, int16_t filtermax, const FilterFct& filterFunc = nullptr); + void addButton(const char* picto, int16_t filtermin, int16_t filtermax, + const Choice::FilterFct& filterFunc = nullptr, + const char* title = nullptr, bool wideButton = false); + bool filterMenu(MenuToolbarButton* btn, int16_t filtermin, int16_t filtermax, + const Choice::FilterFct& filterFunc, const char* title); - rect_t getButtonRect(size_t buttons); - - void onClicked() override; + rect_t getButtonRect(bool wideButton); }; diff --git a/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h b/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h index ba71c6a80..8212b625e 100644 --- a/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h +++ b/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h @@ -35,6 +35,7 @@ lv_obj_t* etx_switch_create(lv_obj_t* parent); lv_obj_t* etx_slider_create(lv_obj_t* parent); lv_obj_t* etx_btnmatrix_create(lv_obj_t* parent); lv_obj_t* etx_button_create(lv_obj_t* parent); +lv_obj_t* etx_menu_button_create(lv_obj_t* parent); lv_obj_t* etx_choice_create(lv_obj_t* parent); lv_obj_t* etx_modal_create(lv_obj_t* parent); lv_obj_t* etx_modal_content_create(lv_obj_t* parent); diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index ce4c512ff..ac2322179 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -1083,3 +1083,7 @@ const char STR_STICK_NAMES2[] = TR_STICK_NAMES2; const char STR_STICK_NAMES3[] = TR_STICK_NAMES3; const char STR_SURFACE_NAMES0[] = TR_SURFACE_NAMES0; const char STR_SURFACE_NAMES1[] = TR_SURFACE_NAMES1; + +const char STR_SELECT_MENU_ALL[] = TR_SELECT_MENU_ALL; +const char STR_SELECT_MENU_CLR[] = TR_SELECT_MENU_CLR; +const char STR_SELECT_MENU_INV[] = TR_SELECT_MENU_INV; diff --git a/radio/src/translations.h b/radio/src/translations.h index 2c37bce35..e5aa2ef5c 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -1262,5 +1262,9 @@ extern const char* const STR_VUSBJOYSTICK_CIRC_COUTOUT[]; extern const char STR_USBJOYSTICK_APPLY_CHANGES[]; #endif +extern const char STR_SELECT_MENU_ALL[]; +extern const char STR_SELECT_MENU_CLR[]; +extern const char STR_SELECT_MENU_INV[]; + #endif // _TRANSLATIONS_H_ diff --git a/radio/src/translations/cn.h b/radio/src/translations/cn.h index 953b0dc39..7528be77f 100644 --- a/radio/src/translations/cn.h +++ b/radio/src/translations/cn.h @@ -1240,3 +1240,7 @@ #define TR_ENABLED_FEATURES "启用的功能" #define TR_RADIO_MENU_TABS "系统功能选项卡" #define TR_MODEL_MENU_TABS "模型功能选项卡" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/cz.h b/radio/src/translations/cz.h index 29303bb2f..fb65c14d3 100644 --- a/radio/src/translations/cz.h +++ b/radio/src/translations/cz.h @@ -1261,3 +1261,7 @@ #define TR_ENABLED_FEATURES "Aktivní funkce" #define TR_RADIO_MENU_TABS "Rádiové menu záložky" #define TR_MODEL_MENU_TABS "Model menu záložky" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/da.h b/radio/src/translations/da.h index 6cbe97479..3a53e611b 100644 --- a/radio/src/translations/da.h +++ b/radio/src/translations/da.h @@ -1266,3 +1266,7 @@ #define TR_ENABLED_FEATURES "Aktiverede funktioner" #define TR_RADIO_MENU_TABS "Radio menu tab" #define TR_MODEL_MENU_TABS "Model menu tab" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/de.h b/radio/src/translations/de.h index 06e313b3d..a25c2cb62 100644 --- a/radio/src/translations/de.h +++ b/radio/src/translations/de.h @@ -1252,3 +1252,7 @@ #define TR_ENABLED_FEATURES "Menüpunkte" #define TR_RADIO_MENU_TABS "Sender Menüpunkte" #define TR_MODEL_MENU_TABS "Modell Menüpunkte" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/en.h b/radio/src/translations/en.h index a6e7cef0e..5cf319a42 100644 --- a/radio/src/translations/en.h +++ b/radio/src/translations/en.h @@ -1249,3 +1249,7 @@ #define TR_ENABLED_FEATURES "Enabled Features" #define TR_RADIO_MENU_TABS "Radio Menu Tabs" #define TR_MODEL_MENU_TABS "Model Menu Tabs" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/es.h b/radio/src/translations/es.h index 82857dd59..c1a364d9d 100644 --- a/radio/src/translations/es.h +++ b/radio/src/translations/es.h @@ -1254,3 +1254,7 @@ #define TR_ENABLED_FEATURES "Enabled Features" #define TR_RADIO_MENU_TABS "Radio Menu Tabs" #define TR_MODEL_MENU_TABS "Model Menu Tabs" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/fi.h b/radio/src/translations/fi.h index 42fffdc54..3c48a95bc 100644 --- a/radio/src/translations/fi.h +++ b/radio/src/translations/fi.h @@ -1270,3 +1270,7 @@ #define TR_ENABLED_FEATURES "Enabled Features" #define TR_RADIO_MENU_TABS "Radio Menu Tabs" #define TR_MODEL_MENU_TABS "Model Menu Tabs" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/fr.h b/radio/src/translations/fr.h index fc116ae33..6139433c7 100644 --- a/radio/src/translations/fr.h +++ b/radio/src/translations/fr.h @@ -1274,3 +1274,7 @@ #define TR_ENABLED_FEATURES TR("Fonctions activées", "Fonctionnalités activées") #define TR_RADIO_MENU_TABS "Onglets Menu Radio" #define TR_MODEL_MENU_TABS "Onglets Menu Modèles" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/he.h b/radio/src/translations/he.h index 31016d2bd..674e0b499 100644 --- a/radio/src/translations/he.h +++ b/radio/src/translations/he.h @@ -1258,3 +1258,7 @@ #define TR_ENABLED_FEATURES "אפשר יכולות" #define TR_RADIO_MENU_TABS "לשוניות תפריט רדיו" #define TR_MODEL_MENU_TABS "לשוניות תפריט מודל" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/it.h b/radio/src/translations/it.h index d6b2c564f..2f5f2ef6e 100644 --- a/radio/src/translations/it.h +++ b/radio/src/translations/it.h @@ -1249,3 +1249,7 @@ #define TR_RADIO_MENU_TABS "Schede del Menu Radio" #define TR_MODEL_MENU_TABS "Schede del Menu Modello" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/jp.h b/radio/src/translations/jp.h index 500dad692..4e70a8191 100644 --- a/radio/src/translations/jp.h +++ b/radio/src/translations/jp.h @@ -1244,3 +1244,7 @@ #define TR_ENABLED_FEATURES "有効機能" #define TR_RADIO_MENU_TABS "送信機メニュータブ" #define TR_MODEL_MENU_TABS "モデルメニュータブ" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/nl.h b/radio/src/translations/nl.h index c66c12ad9..204769af9 100644 --- a/radio/src/translations/nl.h +++ b/radio/src/translations/nl.h @@ -1261,3 +1261,7 @@ #define TR_ENABLED_FEATURES "Enabled Features" #define TR_RADIO_MENU_TABS "Radio Menu Tabs" #define TR_MODEL_MENU_TABS "Model Menu Tabs" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/pl.h b/radio/src/translations/pl.h index 7fbab149a..cc25c4123 100644 --- a/radio/src/translations/pl.h +++ b/radio/src/translations/pl.h @@ -1248,3 +1248,7 @@ #define TR_ENABLED_FEATURES "Włączone opcje" #define TR_RADIO_MENU_TABS "Zakładki menu radia" #define TR_MODEL_MENU_TABS "Zakładki menu modelu" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/pt.h b/radio/src/translations/pt.h index f16dd8c4a..1b06ca4df 100644 --- a/radio/src/translations/pt.h +++ b/radio/src/translations/pt.h @@ -1252,3 +1252,7 @@ #define TR_ENABLED_FEATURES "Recursos ativos" #define TR_RADIO_MENU_TABS "Abas opcoes radio" #define TR_MODEL_MENU_TABS "Abas opcoes modelo" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/se.h b/radio/src/translations/se.h index 51ee8231f..7767a5aad 100644 --- a/radio/src/translations/se.h +++ b/radio/src/translations/se.h @@ -1287,3 +1287,7 @@ #define TR_ENABLED_FEATURES "Aktiverade funktioner" #define TR_RADIO_MENU_TABS "Radiomenyflikar" #define TR_MODEL_MENU_TABS "Modellmenyflikar" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert" diff --git a/radio/src/translations/tw.h b/radio/src/translations/tw.h index 77da538ff..c0fdc3d89 100644 --- a/radio/src/translations/tw.h +++ b/radio/src/translations/tw.h @@ -1246,3 +1246,7 @@ #define TR_ENABLED_FEATURES "啟用的功能" #define TR_RADIO_MENU_TABS "系統功能選項卡" #define TR_MODEL_MENU_TABS "模型功能選項卡" + +#define TR_SELECT_MENU_ALL "All" +#define TR_SELECT_MENU_CLR "Clear" +#define TR_SELECT_MENU_INV "Invert"