From 02e4f9b361581fe4ce1249cd5529b8cf6e897d1a Mon Sep 17 00:00:00 2001 From: philmoz Date: Sat, 10 Jan 2026 13:29:59 +1100 Subject: [PATCH] fix(color): Lua widgets may not update when quick menu is open (#6967) --- radio/src/gui/colorlcd/libui/mainwindow.cpp | 3 ++ radio/src/gui/colorlcd/libui/page.cpp | 6 --- radio/src/gui/colorlcd/libui/page.h | 1 - radio/src/gui/colorlcd/libui/window.cpp | 9 ++++ radio/src/gui/colorlcd/libui/window.h | 1 + radio/src/gui/colorlcd/mainview/view_main.cpp | 33 ++++++------ radio/src/gui/colorlcd/mainview/view_main.h | 23 ++------ radio/src/gui/colorlcd/mainview/widget.h | 4 +- .../colorlcd/mainview/widgets_container.cpp | 13 +++-- .../gui/colorlcd/mainview/widgets_container.h | 2 +- .../gui/colorlcd/setup_menus/pagegroup.cpp | 1 - radio/src/lua/lua_widget.cpp | 54 +++++++------------ radio/src/lua/lua_widget.h | 3 +- 13 files changed, 69 insertions(+), 84 deletions(-) diff --git a/radio/src/gui/colorlcd/libui/mainwindow.cpp b/radio/src/gui/colorlcd/libui/mainwindow.cpp index 50e0652eb..bed6a91ae 100644 --- a/radio/src/gui/colorlcd/libui/mainwindow.cpp +++ b/radio/src/gui/colorlcd/libui/mainwindow.cpp @@ -23,6 +23,7 @@ #include "layout.h" #include "etx_lv_theme.h" #include "sdcard.h" +#include "view_main.h" // timers_driver.h uint32_t timersGetMsTick(); @@ -57,6 +58,8 @@ void MainWindow::run(bool trash) { auto start = timersGetMsTick(); + ViewMain::refreshWidgets(); + auto opaque = Layer::getFirstOpaque(); if (opaque) { opaque->checkEvents(); diff --git a/radio/src/gui/colorlcd/libui/page.cpp b/radio/src/gui/colorlcd/libui/page.cpp index 293661e63..e18a2771f 100644 --- a/radio/src/gui/colorlcd/libui/page.cpp +++ b/radio/src/gui/colorlcd/libui/page.cpp @@ -133,12 +133,6 @@ void Page::onCancel() void Page::onClicked() { Keyboard::hide(false); } -void Page::checkEvents() -{ - ViewMain::instance()->runBackground(); - NavWindow::checkEvents(); -} - void Page::enableRefresh() { lv_obj_enable_style_refresh(true); diff --git a/radio/src/gui/colorlcd/libui/page.h b/radio/src/gui/colorlcd/libui/page.h index ad7199042..2ded5f507 100644 --- a/radio/src/gui/colorlcd/libui/page.h +++ b/radio/src/gui/colorlcd/libui/page.h @@ -63,7 +63,6 @@ class Page : public NavWindow Window* body = nullptr; QuickMenu* quickMenu = nullptr; - void checkEvents() override; bool bubbleEvents() override { return false; } NavWindow* navWindow(); diff --git a/radio/src/gui/colorlcd/libui/window.cpp b/radio/src/gui/colorlcd/libui/window.cpp index b0dcf11b0..2008c56d4 100644 --- a/radio/src/gui/colorlcd/libui/window.cpp +++ b/radio/src/gui/colorlcd/libui/window.cpp @@ -430,6 +430,15 @@ bool Window::isVisible() return !_deleted && lvobj && !lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN); } +bool Window::isOnScreen() +{ + // Check window is at least partially visible + if (!isVisible()) return false; + lv_area_t a; + lv_obj_get_coords(lvobj, &a); + return a.x2 >= 0 && a.x1 < LCD_W && a.y2 >= 0 && a.y1 < LCD_H; +} + void Window::enable(bool enabled) { if (!_deleted && lvobj) { diff --git a/radio/src/gui/colorlcd/libui/window.h b/radio/src/gui/colorlcd/libui/window.h index 61d558adb..4d8df68ae 100644 --- a/radio/src/gui/colorlcd/libui/window.h +++ b/radio/src/gui/colorlcd/libui/window.h @@ -187,6 +187,7 @@ class Window virtual void show(bool visible = true); void hide() { show(false); } bool isVisible(); + bool isOnScreen(); virtual void enable(bool enabled = true); void disable() { enable(false); } diff --git a/radio/src/gui/colorlcd/mainview/view_main.cpp b/radio/src/gui/colorlcd/mainview/view_main.cpp index 83f85fc20..8bd0443c1 100644 --- a/radio/src/gui/colorlcd/mainview/view_main.cpp +++ b/radio/src/gui/colorlcd/mainview/view_main.cpp @@ -76,6 +76,12 @@ static void tile_view_scroll_end(lv_event_t* e) ViewMain* ViewMain::_instance = nullptr; +ViewMain* ViewMain::instance() +{ + if (!_instance) _instance = new ViewMain(); + return _instance; +} + ViewMain::ViewMain() : NavWindow(MainWindow::instance(), MainWindow::instance()->getRect()) { @@ -178,16 +184,6 @@ void ViewMain::previousMainView() TopBar* ViewMain::getTopbar() { return topbar; } -void ViewMain::enableTopbar() -{ - if (topbar) topbar->show(); -} - -void ViewMain::disableTopbar() -{ - if (topbar) topbar->hide(); -} - void ViewMain::updateTopbarVisibility() { if (!tile_view) return; @@ -409,11 +405,18 @@ void ViewMain::hideTopBarEdgeTxButton() topbar->setEdgeTxButtonVisible(0.0); } -void ViewMain::runBackground() +void ViewMain::_refreshWidgets() { - topbar->runBackground(); - for (int i = 0; i < MAX_CUSTOM_SCREENS; i += 1) { - if (customScreens[i]) - customScreens[i]->runBackground(); + if (!_deleted) { + topbar->refreshWidgets(isVisible && hasTopbar()); + for (int i = 0; i < MAX_CUSTOM_SCREENS; i += 1) { + if (customScreens[i]) + customScreens[i]->refreshWidgets(isVisible); + } } } + +void ViewMain::refreshWidgets() +{ + if (_instance) _instance->_refreshWidgets(); +} diff --git a/radio/src/gui/colorlcd/mainview/view_main.h b/radio/src/gui/colorlcd/mainview/view_main.h index 98aef440d..dc78c81c9 100644 --- a/radio/src/gui/colorlcd/mainview/view_main.h +++ b/radio/src/gui/colorlcd/mainview/view_main.h @@ -25,8 +25,6 @@ #include "window.h" class QuickMenu; -class SetupWidgetsPage; -class SetupTopBarWidgetsPage; class TopBar; class ViewMain : public NavWindow @@ -37,14 +35,7 @@ class ViewMain : public NavWindow public: ~ViewMain() override; - static ViewMain* instance() - { - if (!_instance) _instance = new ViewMain(); - - return _instance; - } - - static ViewMain* getInstance() { return _instance; } + static ViewMain* instance(); #if defined(DEBUG_WINDOWS) std::string getName() const override { return "ViewMain"; } @@ -52,8 +43,6 @@ class ViewMain : public NavWindow void addMainView(WidgetsContainer* view, uint32_t viewId); - void enableTopbar(); - void disableTopbar(); void updateTopbarVisibility(); bool enableWidgetSelect(bool enable); @@ -76,7 +65,6 @@ class ViewMain : public NavWindow bool onLongPress() override; void show(bool visible = true) override; - bool viewIsVisible() const { return isVisible; } void showTopBarEdgeTxButton(); void hideTopBarEdgeTxButton(); @@ -85,9 +73,10 @@ class ViewMain : public NavWindow bool isAppMode(); bool isAppMode(unsigned view); - void runBackground(); void refreshWidgetSelectTimer(); + static void refreshWidgets(); + protected: static ViewMain* _instance; @@ -100,14 +89,12 @@ class ViewMain : public NavWindow void deleteLater(bool detach = true, bool trash = true) override; - // Widget setup requires special permissions ;-) - friend class SetupWidgetsPage; - friend class SetupTopBarWidgetsPage; - // Set topbar visibility [0.0 -> 1.0] void setTopbarVisible(float visible); void setEdgeTxButtonVisible(float visible); + void _refreshWidgets(); + static void ws_timer(lv_timer_t* t); #if defined(HARDWARE_KEYS) diff --git a/radio/src/gui/colorlcd/mainview/widget.h b/radio/src/gui/colorlcd/mainview/widget.h index ac63d0668..2a80c90c2 100644 --- a/radio/src/gui/colorlcd/mainview/widget.h +++ b/radio/src/gui/colorlcd/mainview/widget.h @@ -108,8 +108,10 @@ class Widget : public ButtonBase // Called when the widget options have changed virtual void update(); - // Called at regular time interval, even if the widget cannot be seen + // Called at regular time interval if the widget is hidden or off screen virtual void background() {} + // Called at regular time interval if the widget is visible and on screen + virtual void foreground() {} // Update widget 'zone' data (for Lua widgets) virtual void updateZoneRect(rect_t rect, bool updateUI = true) diff --git a/radio/src/gui/colorlcd/mainview/widgets_container.cpp b/radio/src/gui/colorlcd/mainview/widgets_container.cpp index 0027add38..e9847db0b 100644 --- a/radio/src/gui/colorlcd/mainview/widgets_container.cpp +++ b/radio/src/gui/colorlcd/mainview/widgets_container.cpp @@ -83,11 +83,16 @@ void WidgetsContainer::showWidgets(bool visible) } } -void WidgetsContainer::runBackground() +void WidgetsContainer::refreshWidgets(bool inForeground) { - for (int i = 0; i < zoneCount; i++) { - if (widgets[i]) { - widgets[i]->background(); + if (!_deleted) { + for (int i = 0; i < zoneCount; i++) { + if (widgets[i]) { + if ((inForeground && widgets[i]->isOnScreen()) || widgets[i]->isFullscreen()) + widgets[i]->foreground(); + else + widgets[i]->background(); + } } } } diff --git a/radio/src/gui/colorlcd/mainview/widgets_container.h b/radio/src/gui/colorlcd/mainview/widgets_container.h index e3e7a8a65..20f76b92a 100644 --- a/radio/src/gui/colorlcd/mainview/widgets_container.h +++ b/radio/src/gui/colorlcd/mainview/widgets_container.h @@ -41,7 +41,7 @@ class WidgetsContainer: public Window void updateZones(); void showWidgets(bool visible = true); void hideWidgets() { showWidgets(false); } - void runBackground(); + void refreshWidgets(bool inForeground); virtual bool isLayout() { return false; } virtual bool isAppMode() const { return false; } diff --git a/radio/src/gui/colorlcd/setup_menus/pagegroup.cpp b/radio/src/gui/colorlcd/setup_menus/pagegroup.cpp index e51f97381..4ee9097f2 100644 --- a/radio/src/gui/colorlcd/setup_menus/pagegroup.cpp +++ b/radio/src/gui/colorlcd/setup_menus/pagegroup.cpp @@ -320,7 +320,6 @@ void PageGroupBase::checkEvents() if (currentTab) { currentTab->checkEvents(); } - ViewMain::instance()->runBackground(); } void PageGroupBase::onClicked() { Keyboard::hide(false); } diff --git a/radio/src/lua/lua_widget.cpp b/radio/src/lua/lua_widget.cpp index d3e9402fb..225a64c83 100644 --- a/radio/src/lua/lua_widget.cpp +++ b/radio/src/lua/lua_widget.cpp @@ -195,7 +195,6 @@ void LuaEventHandler::removeHandler(Window* w) void LuaWidget::redraw_cb(lv_event_t* e) { lv_obj_t* target = lv_event_get_target(e); - if (lv_obj_has_flag(target, LV_OBJ_FLAG_HIDDEN)) return; LuaWidget* widget = (LuaWidget*)lv_obj_get_user_data(target); @@ -292,47 +291,35 @@ void LuaWidget::onCancel() LuaScriptManager::onCancelEvent(); } -void LuaWidget::checkEvents() +void LuaWidget::foreground() { - Widget::checkEvents(); - if (closeFS) { closeFS = false; setFullscreen(false); } - // refresh() has not been called - if (!refreshed) - background(); - - refreshed = false; - - if (useLvglLayout()) { - if (!lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN)) { - lv_area_t a; - lv_obj_get_coords(lvobj, &a); - // Check widget is at least partially visible - if (a.x2 >= 0 && a.x1 < LCD_W) { - auto save = luaScriptManager; - PROTECT_LUA() { - luaScriptManager = this; - refresh(nullptr); - if (!errorMessage) { - if (!callRefs(lsWidgets)) { - setErrorMessage("function"); - } + // Check widget is at least partially visible + if (isOnScreen()) { + if (useLvglLayout()) { + auto save = luaScriptManager; + PROTECT_LUA() { + luaScriptManager = this; + refresh(nullptr); + if (!errorMessage) { + if (!callRefs(lsWidgets)) { + setErrorMessage("function"); } - refreshInstructionsPercent = instructionsPercent; - } else { - setErrorMessage("function"); } - luaScriptManager = save; - UNPROTECT_LUA(); + refreshInstructionsPercent = instructionsPercent; + } else { + setErrorMessage("function"); } + luaScriptManager = save; + UNPROTECT_LUA(); + } else { + // Force call to redraw_cb() + invalidate(); } - } else { - // Force call to redraw_cb() - invalidate(); } #if defined(DEBUG_WINDOWS) @@ -537,9 +524,6 @@ void LuaWidget::refresh(BitmapBuffer* dc) // Remove LCD luaLcdAllowed = lla; luaLcdBuffer = nullptr; - - // mark as refreshed - refreshed = true; } void LuaWidget::background() diff --git a/radio/src/lua/lua_widget.h b/radio/src/lua/lua_widget.h index d88cd937a..638c07eb4 100644 --- a/radio/src/lua/lua_widget.h +++ b/radio/src/lua/lua_widget.h @@ -122,6 +122,7 @@ class LuaWidget : public Widget, public LuaScriptManager const char* getErrorMessage() const override; void update() override; void background() override; + void foreground() override; void clear() override; @@ -148,12 +149,10 @@ class LuaWidget : public Widget, public LuaScriptManager int zoneRectDataRef; int optionsDataRef; char* errorMessage; - bool refreshed = false; // Window interface void onClicked() override; void onCancel() override; - void checkEvents() override; void onEvent(event_t event) override; // Widget interface