From 66c500799cc99cbd22eb9a309d162c287d1fce70 Mon Sep 17 00:00:00 2001 From: "kkoenig1@optonline.com" Date: Sun, 6 Feb 2022 08:54:57 -0500 Subject: [PATCH] menu and modal almost working --- radio/src/thirdparty/libopenui/src/menu.cpp | 153 ++++++++++++------ radio/src/thirdparty/libopenui/src/menu.h | 21 +-- .../thirdparty/libopenui/src/modal_window.cpp | 27 +++- .../thirdparty/libopenui/src/modal_window.h | 20 +-- 4 files changed, 132 insertions(+), 89 deletions(-) diff --git a/radio/src/thirdparty/libopenui/src/menu.cpp b/radio/src/thirdparty/libopenui/src/menu.cpp index 952c7e614..950e411ee 100644 --- a/radio/src/thirdparty/libopenui/src/menu.cpp +++ b/radio/src/thirdparty/libopenui/src/menu.cpp @@ -21,6 +21,62 @@ #include "font.h" #include "theme.h" +LvglWidgetFactory menuBodyWidgetFactory = { [] (lv_obj_t *parent) { + return lv_list_create(parent); +}, nullptr}; + +void menuBodyEventCallback(lv_event_t *e) +{ + auto code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + lv_obj_t *target = lv_event_get_target(e); + if (target != nullptr) { + long index = (long)lv_event_get_user_data(e); + MenuBody *mb = (MenuBody *) lv_obj_get_user_data(lv_obj_get_parent(target)); + Menu *menu = mb->getParentMenu(); + if (index < (int)mb->lines.size()) { + onKeyPress(); + if (menu->multiple) { + if (mb->selectedIndex == index) + mb->lines[index].onPress(); + else + mb->setIndex(index); + } + else { + mb->setIndex(index); + menu->deleteLater(); + mb->lines[index].onPress(); + } + } + } + } +} + +MenuBody::MenuBody(Window * parent, const rect_t & rect): + Window(parent, rect, OPAQUE, 0, &menuBodyWidgetFactory) +{ + setPageHeight(MENUS_LINE_HEIGHT); +} + +void MenuBody::addLine(const std::string & text, std::function onPress, std::function isChecked) +{ + lines.emplace_back(text, std::move(onPress), std::move(isChecked)); + lv_obj_t *btn = lv_list_add_btn(lvobj, nullptr, text.c_str()); + lv_obj_set_style_bg_color(btn, makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN | LV_STATE_CHECKED); + lv_obj_set_style_bg_color(btn, makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN | LV_STATE_CHECKED | LV_STATE_FOCUSED); + lv_obj_set_style_bg_opa(btn, LV_OPA_100, LV_PART_MAIN); + lv_obj_set_style_bg_opa(btn, LV_OPA_100, LV_PART_MAIN | LV_STATE_CHECKED); + lv_obj_set_style_bg_opa(btn, LV_OPA_100, LV_PART_MAIN | LV_STATE_CHECKED | LV_STATE_FOCUSED); + lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE); + lv_obj_add_event_cb(btn, menuBodyEventCallback, LV_EVENT_CLICKED, (void *) (lines.size() - 1)); + lv_obj_set_style_text_color(lvobj, makeLvColor(COLOR_THEME_PRIMARY2), LV_PART_MAIN | LV_STATE_FOCUSED); +} + +void MenuBody::removeLines() +{ + lines.clear(); + lv_obj_clean(lvobj); +} // ensure index is in range and also handle wrapping index int MenuBody::rangeCheck(int index) @@ -35,17 +91,14 @@ int MenuBody::rangeCheck(int index) void MenuBody::setIndex(int index) { - selectedIndex = index; - // calculate the correct scroll postion based on there being separators - int scrollY = 0; - for (int i = 0; i < selectedIndex; i++) - scrollY += lines[i].lineHeight(); + if (index < (int)lines.size()) { + selectedIndex = index; - if (innerHeight > height()) { - lv_obj_scroll_to_y(lvobj, scrollY - 3 * MENUS_LINE_HEIGHT, LV_ANIM_OFF); + lv_obj_t *btn = lv_obj_get_child(lvobj, selectedIndex); + if (btn != nullptr) { + lv_obj_add_state(btn, LV_STATE_CHECKED); + } } - - invalidate(); } void MenuBody::select(int index) @@ -166,42 +219,42 @@ bool MenuBody::onTouchEnd(coord_t /*x*/, coord_t y) void MenuBody::paint(BitmapBuffer * dc) { - dc->clear(COLOR_THEME_PRIMARY2); + // dc->clear(COLOR_THEME_PRIMARY2); - int y = 0; - for (int i = 0; i < (signed)lines.size(); i++) { - auto& line = lines[i]; - LcdFlags flags = COLOR_THEME_PRIMARY3 | MENU_FONT; + // int y = 0; + // for (int i = 0; i < (signed)lines.size(); i++) { + // auto& line = lines[i]; + // LcdFlags flags = COLOR_THEME_PRIMARY3 | MENU_FONT; - // draw selection if appropriate - if (selectedIndex == i && ! line.isSeparator) { - flags = COLOR_THEME_PRIMARY2 | MENU_FONT; - if (COLOR_THEME_FOCUS != COLOR_THEME_PRIMARY2) { - dc->drawSolidFilledRect(0, y, width(), - MENUS_LINE_HEIGHT, COLOR_THEME_FOCUS); - } - } + // // draw selection if appropriate + // if (selectedIndex == i && ! line.isSeparator) { + // flags = COLOR_THEME_PRIMARY2 | MENU_FONT; + // if (COLOR_THEME_FOCUS != COLOR_THEME_PRIMARY2) { + // dc->drawSolidFilledRect(0, y, width(), + // MENUS_LINE_HEIGHT, COLOR_THEME_FOCUS); + // } + // } - if (line.isSeparator) { - dc->drawHorizontalLine(5, y + MENUS_SEPARATOR_HEIGHT / 2, width() - 10, 255, COLOR_THEME_SECONDARY1); - } else if (line.drawLine) { - line.drawLine(dc, 0, y, COLOR_THEME_PRIMARY3); - } else { - const char* text = line.text.data(); - dc->drawText(10, - y + (MENUS_LINE_HEIGHT - getFontHeight(MENU_FONT)) / 2, - text[0] == '\0' ? "---" : text, flags); - } + // if (line.isSeparator) { + // dc->drawHorizontalLine(5, y + MENUS_SEPARATOR_HEIGHT / 2, width() - 10, 255, COLOR_THEME_SECONDARY1); + // } else if (line.drawLine) { + // line.drawLine(dc, 0, y, COLOR_THEME_PRIMARY3); + // } else { + // const char* text = line.text.data(); + // dc->drawText(10, + // y + (MENUS_LINE_HEIGHT - getFontHeight(MENU_FONT)) / 2, + // text[0] == '\0' ? "---" : text, flags); + // } - Menu* menu = getParentMenu(); - if (menu->multiple && line.isChecked) { - theme->drawCheckBox(dc, line.isChecked(), width() - 35, - y + (MENUS_LINE_HEIGHT - 20) / 2, - 0); - } + // Menu* menu = getParentMenu(); + // if (menu->multiple && line.isChecked) { + // theme->drawCheckBox(dc, line.isChecked(), width() - 35, + // y + (MENUS_LINE_HEIGHT - 20) / 2, + // 0); + // } - y += line.lineHeight(); - } + // y += line.lineHeight(); + // } } MenuWindowContent::MenuWindowContent(Menu* parent) : @@ -214,17 +267,17 @@ MenuWindowContent::MenuWindowContent(Menu* parent) : void MenuWindowContent::paint(BitmapBuffer * dc) { - // the background - dc->clear(COLOR_THEME_SECONDARY1); + // // the background + // dc->clear(COLOR_THEME_SECONDARY1); - // the title - if (!title.empty()) { - dc->drawText(MENUS_WIDTH / 2, - (POPUP_HEADER_HEIGHT - getFontHeight(MENU_HEADER_FONT)) / 2, - title.c_str(), CENTERED | MENU_HEADER_FONT | COLOR_THEME_PRIMARY2); - dc->drawSolidHorizontalLine(0, POPUP_HEADER_HEIGHT - 1, MENUS_WIDTH, - COLOR_THEME_SECONDARY2); - } + // // the title + // if (!title.empty()) { + // dc->drawText(MENUS_WIDTH / 2, + // (POPUP_HEADER_HEIGHT - getFontHeight(MENU_HEADER_FONT)) / 2, + // title.c_str(), CENTERED | MENU_HEADER_FONT | COLOR_THEME_PRIMARY2); + // dc->drawSolidHorizontalLine(0, POPUP_HEADER_HEIGHT - 1, MENUS_WIDTH, + // COLOR_THEME_SECONDARY2); + // } } Menu::Menu(Window * parent, bool multiple): diff --git a/radio/src/thirdparty/libopenui/src/menu.h b/radio/src/thirdparty/libopenui/src/menu.h index cf16aff9e..1285f8f96 100644 --- a/radio/src/thirdparty/libopenui/src/menu.h +++ b/radio/src/thirdparty/libopenui/src/menu.h @@ -69,6 +69,7 @@ class MenuBody: public Window MenuLine(MenuLine &&) = default; protected: + friend void menuBodyEventCallback(lv_event_t *e); bool isSeparator = false; coord_t height = MENUS_LINE_HEIGHT; std::string text; @@ -78,11 +79,7 @@ class MenuBody: public Window }; public: - MenuBody(Window * parent, const rect_t & rect): - Window(parent, rect, OPAQUE) - { - setPageHeight(MENUS_LINE_HEIGHT); - } + MenuBody(Window * parent, const rect_t & rect); #if defined(DEBUG_WINDOWS) std::string getName() const override @@ -116,11 +113,7 @@ class MenuBody: public Window bool onTouchEnd(coord_t x, coord_t y) override; #endif - void addLine(const std::string & text, std::function onPress, std::function isChecked) - { - lines.emplace_back(text, std::move(onPress), std::move(isChecked)); - invalidate(); - } + void addLine(const std::string & text, std::function onPress, std::function isChecked); void addCustomLine(std::function drawLine, std::function onPress, std::function isChecked) { @@ -133,11 +126,7 @@ class MenuBody: public Window lines.emplace_back(true); } - void removeLines() - { - lines.clear(); - invalidate(); - } + void removeLines(); void setCancelHandler(std::function handler) { @@ -147,6 +136,7 @@ class MenuBody: public Window void paint(BitmapBuffer * dc) override; protected: + friend void menuBodyEventCallback(lv_event_t *); void selectNext(MENU_DIRECTION direction); int rangeCheck(int); void setIndex(int index); @@ -264,6 +254,7 @@ class Menu: public ModalWindow void paint(BitmapBuffer * dc) override; protected: + friend void menuBodyEventCallback(lv_event_t *); MenuWindowContent * content; bool multiple; Window * toolbar = nullptr; diff --git a/radio/src/thirdparty/libopenui/src/modal_window.cpp b/radio/src/thirdparty/libopenui/src/modal_window.cpp index b33983164..1ca084510 100644 --- a/radio/src/thirdparty/libopenui/src/modal_window.cpp +++ b/radio/src/thirdparty/libopenui/src/modal_window.cpp @@ -26,6 +26,10 @@ ModalWindow::ModalWindow(Window * parent, bool closeWhenClickOutside): Window(parent->getFullScreenWindow(), {0, 0, LCD_W, LCD_H}), closeWhenClickOutside(closeWhenClickOutside) { + lv_obj_set_parent(lvobj, lv_layer_top()); + lv_obj_set_style_bg_color(lvobj, lv_color_black(), LV_PART_MAIN); + lv_obj_set_style_bg_opa(lvobj, LV_OPA_50, LV_PART_MAIN); + lv_obj_add_flag(lv_layer_top(), LV_OBJ_FLAG_CLICKABLE); Layer::push(this); } @@ -33,20 +37,33 @@ void ModalWindow::deleteLater(bool detach, bool trash) { if (_deleted) return; - + + lv_obj_clear_flag(lv_layer_top(), LV_OBJ_FLAG_CLICKABLE); Layer::pop(this); Window::deleteLater(detach, trash); } +#if defined(HARDWARE_TOUCH) +bool ModalWindow::onTouchEnd(coord_t x, coord_t y) +{ + if (closeWhenClickOutside) { + onKeyPress(); + deleteLater(); + } + return true; +} +#endif + + void ModalWindow::paint(BitmapBuffer * dc) { - dc->drawFilledRect(0, 0, width(), height(), SOLID, BLACK, OPACITY(6)); + // dc->drawFilledRect(0, 0, width(), height(), SOLID, BLACK, OPACITY(6)); } void ModalWindowContent::paint(BitmapBuffer * dc) { - dc->drawSolidFilledRect(0, 0, width(), POPUP_HEADER_HEIGHT, COLOR_THEME_SECONDARY1); - dc->drawText(FIELD_PADDING_LEFT, (POPUP_HEADER_HEIGHT - getFontHeight(FONT(STD))) / 2, title.c_str(), COLOR_THEME_PRIMARY2); - dc->drawSolidFilledRect(0, POPUP_HEADER_HEIGHT, width(), height() - POPUP_HEADER_HEIGHT, COLOR_THEME_SECONDARY3); + // dc->drawSolidFilledRect(0, 0, width(), POPUP_HEADER_HEIGHT, COLOR_THEME_SECONDARY1); + // dc->drawText(FIELD_PADDING_LEFT, (POPUP_HEADER_HEIGHT - getFontHeight(FONT(STD))) / 2, title.c_str(), COLOR_THEME_PRIMARY2); + // dc->drawSolidFilledRect(0, POPUP_HEADER_HEIGHT, width(), height() - POPUP_HEADER_HEIGHT, COLOR_THEME_SECONDARY3); } diff --git a/radio/src/thirdparty/libopenui/src/modal_window.h b/radio/src/thirdparty/libopenui/src/modal_window.h index e4580e689..fedaeea77 100644 --- a/radio/src/thirdparty/libopenui/src/modal_window.h +++ b/radio/src/thirdparty/libopenui/src/modal_window.h @@ -38,25 +38,7 @@ class ModalWindow: public Window void paint(BitmapBuffer * dc) override; #if defined(HARDWARE_TOUCH) - bool onTouchStart(coord_t /*x*/, coord_t /*y*/) override - { - return true; - } - - bool onTouchEnd(coord_t x, coord_t y) override - { - if (!Window::onTouchEnd(x, y) && closeWhenClickOutside) { - onKeyPress(); - deleteLater(); - } - return true; - } - - bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override - { - Window::onTouchSlide(x, y, startX, startY, slideX, slideY); - return true; - } + bool onTouchEnd(coord_t x, coord_t y) override; #endif void setCloseWhenClickOutside(bool value = true)