diff --git a/radio/src/thirdparty/libopenui/src/choice.cpp b/radio/src/thirdparty/libopenui/src/choice.cpp index 760ea2386..5edbfce6c 100644 --- a/radio/src/thirdparty/libopenui/src/choice.cpp +++ b/radio/src/thirdparty/libopenui/src/choice.cpp @@ -79,10 +79,10 @@ std::string Choice::getLabelText() { std::string text; - if (textHandler != nullptr) - text = textHandler(getValue()); - else if (getValue) { - int val = getValue(); + if (textHandler != nullptr) { + if (_getValue) { text = textHandler(_getValue()); } + } else if (_getValue) { + int val = _getValue(); val -= vmin; if (val >= 0 && val < (int)values.size()) { text = values[val]; @@ -92,25 +92,26 @@ std::string Choice::getLabelText() return text; } -Choice::Choice(Window* parent, const rect_t & rect, int vmin, int vmax, - std::function getValue, std::function setValue, WindowFlags windowFlags) : - ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags), - vmin(vmin), - vmax(vmax), - getValue(std::move(getValue)), - setValue(std::move(setValue)) +Choice::Choice(Window* parent, const rect_t& rect, int vmin, int vmax, + std::function _getValue, + std::function _setValue, WindowFlags windowFlags) : + ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags), + vmin(vmin), + vmax(vmax), + _getValue(std::move(_getValue)), + _setValue(std::move(_setValue)) { lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); } Choice::Choice(Window* parent, const rect_t& rect, const char* const values[], - int vmin, int vmax, std::function getValue, - std::function setValue, WindowFlags windowFlags) : + int vmin, int vmax, std::function _getValue, + std::function _setValue, WindowFlags windowFlags) : ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags), vmin(vmin), vmax(vmax), - getValue(std::move(getValue)), - setValue(std::move(setValue)) + _getValue(std::move(_getValue)), + _setValue(std::move(_setValue)) { setValues(values); lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); @@ -118,26 +119,26 @@ 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, + std::function _getValue, std::function _setValue, WindowFlags windowFlags) : ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags), values(std::move(values)), vmin(vmin), vmax(vmax), - getValue(std::move(getValue)), - setValue(std::move(setValue)) + _getValue(std::move(_getValue)), + _setValue(std::move(_setValue)) { lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); } Choice::Choice(Window* parent, const rect_t& rect, const char* values, int vmin, - int vmax, std::function getValue, - std::function setValue, WindowFlags windowFlags) : + int vmax, std::function _getValue, + std::function _setValue, WindowFlags windowFlags) : ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags), vmin(vmin), vmax(vmax), - getValue(std::move(getValue)), - setValue(std::move(setValue)) + _getValue(std::move(_getValue)), + _setValue(std::move(_setValue)) { if (values) { uint8_t len = values[0]; @@ -181,60 +182,51 @@ void Choice::setValues(const char * const values[]) } } +void Choice::setValue(int val) +{ + lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); + if (_setValue) _setValue(val); +} + void Choice::onClicked() { onKeyPress(); openMenu(); } +void Choice::fillMenu(Menu *menu, const FilterFct& filter) +{ + menu->removeLines(); + auto value = _getValue(); + + int count = 0; + for (int i = vmin; i <= vmax; ++i) { + if (filter && !filter(i)) continue; + if (isValueAvailable && !isValueAvailable(i)) continue; + if (textHandler) { + menu->addLine(textHandler(i), [=]() { setValue(i); }); + } else if (unsigned(i - vmin) < values.size()) { + menu->addLine(values[i - vmin], [=]() { setValue(i); }); + } else { + menu->addLine(std::to_string(i), [=]() { setValue(i); }); + } + if (value == i) { menu->select(count); } + ++count; + } +} + void Choice::openMenu() { setEditMode(true); // this needs to be done first before menu is created. auto menu = new Menu(this); - if (!menuTitle.empty()) - menu->setTitle(menuTitle); + if (!menuTitle.empty()) menu->setTitle(menuTitle); - auto value = getValue(); - int count = 0; - int current = -1; - - for (int i = vmin; i <= vmax; ++i) { - if (isValueAvailable && !isValueAvailable(i)) - continue; - if (textHandler) { - menu->addLine(textHandler(i), [=]() { - setValue(i); - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); - }); - } - else if (unsigned(i - vmin) < values.size()) { - menu->addLine(values[i - vmin], [=]() { - setValue(i); - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); - }); - } - else { - menu->addLine(std::to_string(i), [=]() { - setValue(i); - lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr); - }); - } - if (value == i) { - current = count; - } - ++count; - } - - if (current >= 0) { - menu->select(current); - } + fillMenu(menu); if (beforeDisplayMenuHandler) { beforeDisplayMenuHandler(menu); } - menu->setCloseHandler([=]() { - setEditMode(false); - }); + menu->setCloseHandler([=]() { setEditMode(false); }); } diff --git a/radio/src/thirdparty/libopenui/src/choice.h b/radio/src/thirdparty/libopenui/src/choice.h index 14337ee62..d349a11f8 100644 --- a/radio/src/thirdparty/libopenui/src/choice.h +++ b/radio/src/thirdparty/libopenui/src/choice.h @@ -31,39 +31,39 @@ enum ChoiceType { class ChoiceBase : public FormField { - public: - ChoiceBase(Window* parent, const rect_t & rect, ChoiceType type = CHOICE_TYPE_DROPOWN, WindowFlags windowFlags = 0); + public: + ChoiceBase(Window *parent, const rect_t &rect, + ChoiceType type = CHOICE_TYPE_DROPOWN, + WindowFlags windowFlags = 0); - inline ChoiceType getType() const - { - return type; - } + inline ChoiceType getType() const { return type; } + + protected: + ChoiceType type; + lv_obj_t* label; - protected: - friend void choice_changed_cb(lv_event_t *e); - ChoiceType type; - lv_obj_t *label; - virtual std::string getLabelText() { return ""; }; + 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, + 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, + 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, + 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, + int vmax, std::function _getValue, + std::function _setValue = nullptr, WindowFlags windowFlags = 0); void addValue(const char *value); @@ -90,12 +90,12 @@ class Choice: public ChoiceBase { void setSetValueHandler(std::function handler) { - setValue = std::move(handler); + _setValue = std::move(handler); } void setGetValueHandler(std::function handler) { - getValue = std::move(handler); + _getValue = std::move(handler); } void setAvailableHandler(std::function handler) @@ -135,10 +135,8 @@ class Choice: public ChoiceBase { return value; } - int getIntValue() const - { - return getValue(); - } + void setValue(int val); + int getIntValue() const { return _getValue(); } unsigned getValuesCount() const { @@ -169,16 +167,21 @@ class Choice: public ChoiceBase { } protected: + friend class MenuToolbar; + std::string getLabelText() override; std::vector values; int vmin = 0; int vmax = 0; std::string menuTitle; - std::function getValue; - std::function setValue; + std::function _getValue; + std::function _setValue; std::function isValueAvailable; std::function textHandler; std::function beforeDisplayMenuHandler; + typedef std::function FilterFct; + void fillMenu(Menu *menu, const FilterFct& filter = nullptr); + virtual void openMenu(); }; diff --git a/radio/src/thirdparty/libopenui/src/menu.cpp b/radio/src/thirdparty/libopenui/src/menu.cpp index a97d5dc28..2c17b86b1 100644 --- a/radio/src/thirdparty/libopenui/src/menu.cpp +++ b/radio/src/thirdparty/libopenui/src/menu.cpp @@ -279,8 +279,9 @@ void Menu::removeLines() void Menu::onEvent(event_t event) { #if defined(HARDWARE_KEYS) - if (toolbar && (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN) || - event == EVT_KEY_BREAK(KEY_PGUP))) { + if (toolbar && + (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN) || + event == EVT_KEY_BREAK(KEY_PGUP))) { toolbar->onEvent(event); } #endif diff --git a/radio/src/thirdparty/libopenui/src/menu.h b/radio/src/thirdparty/libopenui/src/menu.h index b765f681c..f838187b3 100644 --- a/radio/src/thirdparty/libopenui/src/menu.h +++ b/radio/src/thirdparty/libopenui/src/menu.h @@ -174,12 +174,7 @@ class Menu: public ModalWindow waitHandler = std::move(handler); } - // void setFocusBody(uint8_t flag = SET_FOCUS_DEFAULT) - // { - // content->body.setFocus(flag); - // } - - void setToolbar(Window * window); + void setToolbar(Window* window); void setTitle(std::string text); @@ -221,8 +216,7 @@ class Menu: public ModalWindow } protected: - friend void menuBodyEventCallback(lv_event_t *); - MenuWindowContent * content; + MenuWindowContent* content; bool multiple; Window * toolbar = nullptr; std::function waitHandler; diff --git a/radio/src/thirdparty/libopenui/src/menutoolbar.cpp b/radio/src/thirdparty/libopenui/src/menutoolbar.cpp index aff6fcb9e..536dd37e4 100644 --- a/radio/src/thirdparty/libopenui/src/menutoolbar.cpp +++ b/radio/src/thirdparty/libopenui/src/menutoolbar.cpp @@ -18,8 +18,17 @@ */ #include "menutoolbar.h" +#include "choice.h" #include "font.h" +MenuToolbarButton::MenuToolbarButton(Window* parent, const rect_t& rect, + const char* picto) : + Button(parent, rect, nullptr, 0, 0, window_create), picto(picto) +{ + lv_obj_add_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); + lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS); +} + void MenuToolbarButton::paint(BitmapBuffer * dc) { if (checked()) { @@ -35,3 +44,98 @@ void MenuToolbarButton::paint(BitmapBuffer * dc) picto, CENTERED | COLOR_THEME_PRIMARY1); } } + +MenuToolbar::MenuToolbar(Choice* choice, Menu* menu) : + Window(menu, MENUS_TOOLBAR_RECT, NO_SCROLLBAR), + choice(choice), + menu(menu), + group(lv_group_create()) +{ + lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN); +} + +MenuToolbar::~MenuToolbar() +{ + lv_group_del(group); +} + +void MenuToolbar::onEvent(event_t event) +{ + lv_obj_t* obj = lv_group_get_focused(group); + if (obj) { + auto btn = (MenuToolbarButton*)lv_obj_get_user_data(obj); + if (btn) { btn->check(false); } + } + + if (event == EVT_KEY_BREAK(KEY_PGDN)) { + lv_group_focus_next(group); + } else if (event == EVT_KEY_LONG(KEY_PGDN) || + event == EVT_KEY_BREAK(KEY_PGUP)) { + lv_group_focus_prev(group); + } + + obj = lv_group_get_focused(group); + if (!obj) { + choice->fillMenu(menu); + } else { + auto btn = (MenuToolbarButton*)lv_obj_get_user_data(obj); + if (btn) btn->onClicked(); + } +} + +static rect_t _get_button_rect(size_t buttons) +{ + coord_t y = buttons * MENUS_TOOLBAR_BUTTON_WIDTH; + return {0, y, MENUS_TOOLBAR_BUTTON_WIDTH, MENUS_TOOLBAR_BUTTON_WIDTH}; +} + +bool MenuToolbar::filterMenu(MenuToolbarButton* btn, int16_t filtermin, + int16_t filtermax) +{ + btn->check(!btn->checked()); + + Choice::FilterFct filter = nullptr; + if (btn->checked()) { + filter = [=](int16_t index) { + return index >= filtermin && index <= filtermax; + }; + } + + choice->fillMenu(menu, filter); + return btn->checked(); +} + +typedef std::function IsValueAvailable; +static int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable) +{ + int retval = 0; + for (int i = min; i <= max; i++) { + if (isValueAvailable(i)) { + retval = i; + break; + } + } + return retval; +} + + +void MenuToolbar::addButton(const char* picto, int16_t filtermin, + int16_t filtermax) +{ + int vmin = choice->vmin; + int vmax = choice->vmax; + + if (vmin > filtermin || vmax < filtermin) return; + + if (choice->isValueAvailable && + getFirstAvailable(filtermin, filtermax, choice->isValueAvailable) == 0) + return; + + rect_t r = _get_button_rect(children.size()); + auto button = new MenuToolbarButton(this, r, picto); + + button->setPressHandler( + std::bind(&MenuToolbar::filterMenu, this, button, filtermin, filtermax)); + + lv_group_add_obj(group, button->getLvObj()); +} diff --git a/radio/src/thirdparty/libopenui/src/menutoolbar.h b/radio/src/thirdparty/libopenui/src/menutoolbar.h index 3e1236e06..cbec1830d 100644 --- a/radio/src/thirdparty/libopenui/src/menutoolbar.h +++ b/radio/src/thirdparty/libopenui/src/menutoolbar.h @@ -21,140 +21,35 @@ #include "button.h" #include "menu.h" -#include -int getFirstAvailable(int min, int max, std::functionisValueAvailable); +class Choice; -class MenuToolbarButton: public Button { - public: - MenuToolbarButton(FormGroup * window, const rect_t & rect, const char* picto): - Button(window, rect, nullptr), - picto(picto) - { - } +class MenuToolbarButton : public Button +{ + public: + MenuToolbarButton(Window* parent, const rect_t& rect, const char* picto); + void paint(BitmapBuffer* dc) override; - void paint(BitmapBuffer * dc) override; - - protected: - const char* picto; + protected: + const char* picto; }; -template -class MenuToolbar: public FormGroup { - friend T; +class MenuToolbar : public Window +{ + // friend Menu; - public: - MenuToolbar(T * choice, Menu * menu): - FormGroup(menu, MENUS_TOOLBAR_RECT, NO_SCROLLBAR), - choice(choice), - menu(menu) - { - lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN); - } + public: + MenuToolbar(Choice* choice, Menu* menu); + ~MenuToolbar(); - void paint(BitmapBuffer * dc) override - { -// dc->clear(COLOR_THEME_SECONDARY3); - } + void onEvent(event_t event) override; -#if defined(HARDWARE_KEYS) - void onEvent(event_t event) override - { -// if (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN) || event == EVT_KEY_BREAK(KEY_PGUP)) { -// #if defined(HARDWARE_TOUCH) -// if (current != children.end()) { -// static_cast(*current)->onTouchEnd(0,0); -// } -// #endif -// current = IS_KEY_LONG(event) || event == EVT_KEY_BREAK(KEY_PGUP) ? -// current == children.end() ? -// --current: -// current == children.begin() ? -// children.end() : -// --current : -// current == children.end() ? -// children.begin() : -// ++current; + protected: + Choice* choice; + Menu* menu; -// if (IS_KEY_LONG(event)) -// killEvents(event); + lv_group_t* group; -// if (current != children.end()) { -// auto button = static_cast(*current); -// #if defined(HARDWARE_TOUCH) -// button->onTouchEnd(0,0); -// #endif -// scrollTo(button); -// } -// else { -// lv_obj_scroll_to_y(lvobj, 0, LV_ANIM_OFF); -// } -// } - } -#endif - -#if defined(HARDWARE_TOUCH) - bool onTouchEnd(coord_t x, coord_t y) override - { - Window::onTouchEnd(x, y); - return true; // = don't close the menu (inverted so that click outside the menu closes it) - } -#endif - - protected: - std::list::iterator current = children.end(); - T * choice; - Menu * menu; - coord_t y = 0; - std::vector menuButtons; - - void addButton(const char* picto, int16_t filtermin, int16_t filtermax) - { - int vmin = choice->vmin; - int vmax = choice->vmax; - - if (vmin > filtermin || vmax < filtermin) - return; - - if (choice->isValueAvailable && - getFirstAvailable(filtermin, filtermax, choice->isValueAvailable) == - 0) - return; - - auto button = new MenuToolbarButton( - this, {0, y, MENUS_TOOLBAR_BUTTON_WIDTH, MENUS_TOOLBAR_BUTTON_WIDTH}, - picto); - button->setPressHandler([=]() { - auto val = choice->getValue(); - button->check(!button->checked()); - - if (button->checked()) { - choice->fillMenu(menu, val, [=](int16_t index) { - return index >= filtermin && index <= filtermax; - }); - } else { - choice->fillMenu(menu, val); - } - // menu->setFocusBody(); - - // set current for page key procesing - current = std::find_if(children.begin(), children.end(), [button](Window *o) { return o == button; }); - - // clear all checked but the current button - for (auto b : menuButtons) { - if (b != button) - b->check(false); - } - - return button->checked(); - }); - - menuButtons.emplace_back(button); - - - y += MENUS_TOOLBAR_BUTTON_WIDTH; - - } + void addButton(const char* picto, int16_t filtermin, int16_t filtermax); + bool filterMenu(MenuToolbarButton* btn, int16_t filtermin, int16_t filtermax); }; - -