From 8632c038f8662c2959233ce330a595692199fde3 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 25 Aug 2020 09:27:03 +0200 Subject: [PATCH] Multiple selection in Menu --- radio/src/thirdparty/libopenui/src/menu.cpp | 50 ++++++++++++++++----- radio/src/thirdparty/libopenui/src/menu.h | 39 ++++++++++------ 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/radio/src/thirdparty/libopenui/src/menu.cpp b/radio/src/thirdparty/libopenui/src/menu.cpp index 89253ae16..ddadf0cd8 100644 --- a/radio/src/thirdparty/libopenui/src/menu.cpp +++ b/radio/src/thirdparty/libopenui/src/menu.cpp @@ -36,21 +36,25 @@ void MenuBody::onEvent(event_t event) TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event); if (event == EVT_ROTARY_RIGHT) { - if (lines.size() > 0) + if (!lines.empty()) select(int((selectedIndex + 1) % lines.size())); } else if (event == EVT_ROTARY_LEFT) { - if (lines.size() > 0) + if (!lines.empty()) select(int(selectedIndex == 0 ? lines.size() - 1 : selectedIndex - 1)); } else if (event == EVT_KEY_BREAK(KEY_ENTER)) { - if (lines.size() > 0) { + if (!lines.empty()) { if (selectedIndex < 0) { select(0); } else { Window::onEvent(event); // the window above will be closed on event lines[selectedIndex].onPress(); + Menu * menu = getParentMenu(); + if (menu->multiple) { + menu->invalidate(); + } } } } @@ -68,11 +72,23 @@ void MenuBody::onEvent(event_t event) #if defined(HARDWARE_TOUCH) bool MenuBody::onTouchEnd(coord_t /*x*/, coord_t y) { + Menu * menu = getParentMenu(); int index = y / MENUS_LINE_HEIGHT; if (index < (int)lines.size()) { - lines[index].onPress(); + if (menu->multiple) { + if (selectedIndex == index) + lines[index].onPress(); + else + select(index); + menu->invalidate(); + } + else { + lines[index].onPress(); + } + } + if (!menu->multiple) { + menu->deleteLater(); } - getParent()->getParent()->deleteLater(); return true; } #endif @@ -95,6 +111,12 @@ void MenuBody::paint(BitmapBuffer * dc) const char * text = line.text.data(); dc->drawText(10, i * MENUS_LINE_HEIGHT + (MENUS_LINE_HEIGHT - 20) / 2, text[0] == '\0' ? "---" : text, flags); } + + Menu * menu = getParentMenu(); + if (menu->multiple && line.isChecked && line.isChecked()) { + theme->drawCheckBox(dc, 1, width() - 35, i * MENUS_LINE_HEIGHT + (MENUS_LINE_HEIGHT - 20) / 2, 0); + } + if (i > 0) { dc->drawSolidHorizontalLine(0, i * MENUS_LINE_HEIGHT - 1, MENUS_WIDTH, MENU_LINE_COLOR); } @@ -120,9 +142,10 @@ void MenuWindowContent::paint(BitmapBuffer * dc) } } -Menu::Menu(Window * parent): +Menu::Menu(Window * parent, bool multiple): ModalWindow(parent), - content(createMenuWindow(this)) + content(createMenuWindow(this)), + multiple(multiple) { } @@ -146,15 +169,15 @@ 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)); + content->body.addLine(text, std::move(onPress), std::move(isChecked)); updatePosition(); } -void Menu::addCustomLine(std::function drawLine, std::function onPress) +void Menu::addCustomLine(std::function drawLine, std::function onPress, std::function isChecked) { - content->body.addCustomLine(std::move(drawLine), std::move(onPress)); + content->body.addCustomLine(std::move(drawLine), std::move(onPress), std::move(isChecked)); updatePosition(); } @@ -170,7 +193,10 @@ void Menu::onEvent(event_t event) if (toolbar && (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN))) { toolbar->onEvent(event); } - else if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) { + else if (event == EVT_KEY_BREAK(KEY_EXIT)) { + deleteLater(); + } + else if (event == EVT_KEY_BREAK(KEY_ENTER) && !multiple) { deleteLater(); } } diff --git a/radio/src/thirdparty/libopenui/src/menu.h b/radio/src/thirdparty/libopenui/src/menu.h index aac85d94f..e1398bef7 100644 --- a/radio/src/thirdparty/libopenui/src/menu.h +++ b/radio/src/thirdparty/libopenui/src/menu.h @@ -28,7 +28,7 @@ class Menu; class MenuWindowContent; -class MenuBody: public Window { +class MenuBody : public Window { friend class MenuWindowContent; friend class Menu; @@ -36,15 +36,17 @@ class MenuBody: public Window { friend class MenuBody; public: - MenuLine(std::string text, std::function onPress): + MenuLine(std::string text, std::function onPress, std::function isChecked): text(std::move(text)), - onPress(std::move(onPress)) + onPress(std::move(onPress)), + isChecked(std::move(isChecked)) { } - MenuLine(std::function drawLine, std::function onPress): + MenuLine(std::function drawLine, std::function onPress, std::function isChecked): drawLine(std::move(drawLine)), - onPress(std::move(onPress)) + onPress(std::move(onPress)), + isChecked(std::move(isChecked)) { } @@ -56,6 +58,7 @@ class MenuBody: public Window { std::string text; std::function drawLine; std::function onPress; + std::function isChecked; }; public: @@ -92,15 +95,15 @@ class MenuBody: public Window { bool onTouchEnd(coord_t x, coord_t y) override; #endif - void addLine(const std::string & text, std::function onPress) + void addLine(const std::string & text, std::function onPress, std::function isChecked) { - lines.emplace_back(text, onPress); + lines.emplace_back(text, onPress, isChecked); invalidate(); } - void addCustomLine(std::function drawLine, std::function onPress) + void addCustomLine(std::function drawLine, std::function onPress, std::function isChecked) { - lines.emplace_back(drawLine, onPress); + lines.emplace_back(drawLine, onPress, isChecked); invalidate(); } @@ -125,6 +128,8 @@ class MenuBody: public Window { int selectedIndex = 0; #endif std::function onCancel; + + inline Menu * getParentMenu(); }; class MenuWindowContent: public ModalWindowContent { @@ -152,12 +157,14 @@ class MenuWindowContent: public ModalWindowContent { }; class Menu: public ModalWindow { + friend class MenuBody; + public: - explicit Menu(Window * parent); + explicit Menu(Window * parent, bool multiple = false); void setCancelHandler(std::function handler) { - content->body.setCancelHandler(handler); + content->body.setCancelHandler(std::move(handler)); } void setWaitHandler(std::function handler) @@ -175,9 +182,9 @@ class Menu: public ModalWindow { void setTitle(std::string text); - void addLine(const std::string & text, std::function onPress); + void addLine(const std::string & text, std::function onPress, std::function isChecked = nullptr); - void addCustomLine(std::function drawLine, std::function onPress); + void addCustomLine(std::function drawLine, std::function onPress, std::function isChecked = nullptr); void removeLines(); @@ -205,9 +212,15 @@ class Menu: public ModalWindow { protected: MenuWindowContent * content; + bool multiple; Window * toolbar = nullptr; std::function waitHandler; void updatePosition(); }; +Menu * MenuBody::getParentMenu() +{ + return static_cast(getParent()->getParent()); +} + #endif // _MENU_H_