From 22a4e671177dba07015ff28419763d8f35bc1dd2 Mon Sep 17 00:00:00 2001 From: philmoz Date: Thu, 21 Sep 2023 19:47:46 +1000 Subject: [PATCH] feat(color): Add support for information bubble popups (#3903) * Add information bubble popup window. * Use fixed BLACK and WHITE colors. --- radio/src/gui/colorlcd/popups.cpp | 36 ++++++++++++++++++ radio/src/gui/colorlcd/popups.h | 1 + .../src/gui/colorlcd/themes/etx_lv_theme.cpp | 37 +++++++++++++++++++ .../thirdparty/libopenui/src/mainwindow.cpp | 7 ++++ .../libopenui/src/widgets/etx_obj_create.h | 1 + radio/src/thirdparty/libopenui/src/window.h | 2 + 6 files changed, 84 insertions(+) diff --git a/radio/src/gui/colorlcd/popups.cpp b/radio/src/gui/colorlcd/popups.cpp index 2aaf51f4d..3a35b8c07 100644 --- a/radio/src/gui/colorlcd/popups.cpp +++ b/radio/src/gui/colorlcd/popups.cpp @@ -111,3 +111,39 @@ void POPUP_WARNING_ON_UI_TASK(const char * message, const char * info, bool wait } } } + +class BubbleDialog : public Window +{ + public: + BubbleDialog(const char* message, int timeout) : + Window(MainWindow::instance(), rect_t{50, LCD_H - 100, LCD_W - 100, 50}, OPAQUE, 0, etx_bubble_popup_create) + { + lv_obj_set_parent(lvobj, lv_layer_top()); + + auto label = lv_label_create(lvobj); + lv_label_set_text(label, message); + lv_obj_center(label); + lv_obj_set_width(label, lv_pct(100)); + lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); + lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); + + endTime = RTOS_GET_MS() + timeout; + } + + bool isBubblePopup() override { return true; } + + void checkEvents() override + { + if (RTOS_GET_MS() >= endTime) { + deleteLater(); + } + } + + protected: + uint32_t endTime; +}; + +void POPUP_BUBBLE(const char* message, uint32_t timeout) +{ + new BubbleDialog(message, timeout); +} diff --git a/radio/src/gui/colorlcd/popups.h b/radio/src/gui/colorlcd/popups.h index 7cc4b9e89..028a67018 100644 --- a/radio/src/gui/colorlcd/popups.h +++ b/radio/src/gui/colorlcd/popups.h @@ -28,5 +28,6 @@ typedef std::function ProgressHandle void POPUP_INFORMATION(const char * message); void POPUP_WARNING(const char * message, const char * info = nullptr); void POPUP_WARNING_ON_UI_TASK(const char * message, const char * info = nullptr, bool waitForClose = true); +void POPUP_BUBBLE(const char * message, uint32_t timeout); void show_ui_popup(); diff --git a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp index c47ace5a4..99bff6ba2 100644 --- a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp +++ b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp @@ -107,6 +107,8 @@ typedef struct { lv_style_t cb_marker; lv_style_t cb_marker_checked; + // Bubble popup + lv_style_t bubble_popup; } my_theme_styles_t; /********************** @@ -327,6 +329,14 @@ static void style_init(void) lv_style_init(&styles.cb_marker_checked); lv_style_set_bg_img_src(&styles.cb_marker_checked, LV_SYMBOL_OK); lv_style_set_text_font(&styles.cb_marker_checked, theme.font_small); + + // Bubble popup + lv_style_init(&styles.bubble_popup); + lv_style_set_bg_opa(&styles.bubble_popup, LV_OPA_COVER); + lv_style_set_pad_all(&styles.bubble_popup, 4); + lv_style_set_border_opa(&styles.bubble_popup, LV_OPA_COVER); + lv_style_set_border_width(&styles.bubble_popup, 3); + lv_style_set_radius(&styles.bubble_popup, 10); } // Always update colors in case theme changes @@ -395,6 +405,10 @@ static void style_init(void) lv_style_set_border_color(&styles.cb_marker_checked, makeLvColor(COLOR_THEME_SECONDARY1)); lv_style_set_bg_color(&styles.cb_marker_checked, makeLvColor(COLOR_THEME_SECONDARY1)); lv_style_set_text_color(&styles.cb_marker_checked, makeLvColor(COLOR_THEME_PRIMARY2)); + + lv_style_set_bg_color(&styles.bubble_popup, makeLvColor(COLOR2FLAGS(WHITE))); + lv_style_set_border_color(&styles.bubble_popup, makeLvColor(COLOR2FLAGS(BLACK))); + lv_style_set_text_color(&styles.bubble_popup, makeLvColor(COLOR2FLAGS(BLACK))); } /********************** @@ -598,6 +612,11 @@ void etx_checkbox_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) lv_obj_add_style(obj, &styles.disabled, LV_PART_INDICATOR | LV_STATE_DISABLED); } +void bubble_popup_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) +{ + lv_obj_add_style(obj, &styles.bubble_popup, 0); +} + } // Object classes @@ -796,6 +815,19 @@ const lv_obj_class_t etx_checkbox_class = { .instance_size = sizeof(lv_checkbox_t), }; +const lv_obj_class_t etx_bubble_popup_class = { + .base_class = &window_base_class, + .constructor_cb = bubble_popup_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LV_DPI_DEF, + .height_def = LV_DPI_DEF, + .editable = LV_OBJ_CLASS_EDITABLE_FALSE, + .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, + .instance_size = sizeof(lv_obj_t) +}; + // Event handlers static void field_edit_event(const lv_obj_class_t* class_p, lv_event_t* e) { @@ -913,6 +945,11 @@ lv_obj_t* etx_choice_create(lv_obj_t* parent) return etx_create(&etx_choice_class, parent); } +lv_obj_t* etx_bubble_popup_create(lv_obj_t* parent) +{ + return etx_create(&etx_bubble_popup_class, parent); +} + lv_obj_t* etx_bar_create(lv_obj_t* parent) { return etx_create(&etx_bar_class, parent); diff --git a/radio/src/thirdparty/libopenui/src/mainwindow.cpp b/radio/src/thirdparty/libopenui/src/mainwindow.cpp index 939e57eeb..da340e140 100644 --- a/radio/src/thirdparty/libopenui/src/mainwindow.cpp +++ b/radio/src/thirdparty/libopenui/src/mainwindow.cpp @@ -43,6 +43,13 @@ void MainWindow::run(bool trash) auto opaque = Layer::getFirstOpaque(); if (opaque) opaque->checkEvents(); + auto copy = children; + for (auto child: copy) { + if (!child->deleted() && child->isBubblePopup()) { + child->checkEvents(); + } + } + if (trash) emptyTrash(); auto delta = ticksNow() - start; 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 e7c2902ee..ba71c6a80 100644 --- a/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h +++ b/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h @@ -41,6 +41,7 @@ lv_obj_t* etx_modal_content_create(lv_obj_t* parent); lv_obj_t* etx_modal_title_create(lv_obj_t* parent); lv_obj_t* etx_bar_create(lv_obj_t* parent); lv_obj_t* etx_checkbox_create(lv_obj_t* parent); +lv_obj_t* etx_bubble_popup_create(lv_obj_t* parent); lv_obj_t* input_mix_line_create(lv_obj_t* parent); lv_obj_t* input_mix_group_create(lv_obj_t* parent); diff --git a/radio/src/thirdparty/libopenui/src/window.h b/radio/src/thirdparty/libopenui/src/window.h index 0eb72d082..4f464a81b 100644 --- a/radio/src/thirdparty/libopenui/src/window.h +++ b/radio/src/thirdparty/libopenui/src/window.h @@ -204,6 +204,8 @@ class Window virtual bool isTopBar() { return false; } virtual bool isWidgetsContainer() { return false; } + virtual bool isBubblePopup() { return false; } + protected: static std::list trash;