From 5a420c381abb1cc926481d33c88206e01c239292 Mon Sep 17 00:00:00 2001 From: KlausMu Date: Sun, 21 Apr 2024 17:53:28 +0200 Subject: [PATCH 1/6] reorganized deletion and creation of tabs --- .../ESP32/preferencesStorage_hal_esp32.cpp | 39 +- .../ESP32/preferencesStorage_hal_esp32.h | 10 +- .../preferencesStorage_hal_windows_linux.cpp | 57 ++- .../preferencesStorage_hal_windows_linux.h | 10 +- .../src/applicationInternal/gui/guiBase.cpp | 55 ++- .../src/applicationInternal/gui/guiBase.h | 5 +- .../gui/guiMemoryOptimizer.cpp | 440 ++++++++++-------- .../gui/guiMemoryOptimizer.h | 26 +- .../hardware/hardwarePresenter.cpp | 22 +- .../hardware/hardwarePresenter.h | 10 +- Platformio/src/applicationInternal/keys.cpp | 17 +- .../scenes/sceneHandler.cpp | 48 +- .../applicationInternal/scenes/sceneHandler.h | 2 +- .../scenes/sceneRegistry.cpp | 60 +-- .../scenes/sceneRegistry.h | 4 +- Platformio/src/guis/gui_numpad.cpp | 4 +- Platformio/src/main.cpp | 2 +- 17 files changed, 469 insertions(+), 342 deletions(-) diff --git a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp index 6666e4b..2577482 100644 --- a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp +++ b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp @@ -4,8 +4,9 @@ Preferences preferences; -std::string currentScene; -std::string currentGUIname; +std::string activeScene; +std::string activeGUIname; +int activeGUIlist; void init_preferences_HAL(void) { // Restore settings from internal flash memory @@ -17,10 +18,11 @@ void init_preferences_HAL(void) { // from tft.h set_backlightBrightness_HAL(preferences.getUChar("blBrightness")); // from here - currentScene = std::string(preferences.getString("currentScene").c_str()); - currentGUIname = std::string(preferences.getString("currentGUIname").c_str()); + activeScene = std::string(preferences.getString("currentScene").c_str()); + activeGUIname = std::string(preferences.getString("currentGUIname").c_str()); + activeGUIlist =(preferences.getInt("currentGUIlist")); - // Serial.printf("Preferences restored: brightness %d, GUI %s, scene %s\r\n", get_backlightBrightness_HAL(), get_currentGUIname().c_str(), get_currentScene().c_str()); + // Serial.printf("Preferences restored: brightness %d, GUI %s, scene %s\r\n", get_backlightBrightness_HAL(), get_activeGUIname().c_str(), get_activeScene().c_str()); } else { // Serial.printf("No preferences to restore\r\n"); } @@ -35,23 +37,30 @@ void save_preferences_HAL(void) { preferences.putUInt("slpTimeout", get_sleepTimeout_HAL()); preferences.putUChar("blBrightness", get_backlightBrightness_HAL()); // from here - preferences.putString("currentScene", currentScene.c_str()); - preferences.putString("currentGUIname", currentGUIname.c_str()); + preferences.putString("currentScene", activeScene.c_str()); + preferences.putString("currentGUIname", activeGUIname.c_str()); + preferences.putInt("currentGUIlist", activeGUIlist); if (!preferences.getBool("alreadySetUp")) { preferences.putBool("alreadySetUp", true); } preferences.end(); } -std::string get_currentScene_HAL() { - return currentScene; +std::string get_activeScene_HAL() { + return activeScene; } -void set_currentScene_HAL(std::string aCurrentScene) { - currentScene = aCurrentScene; +void set_activeScene_HAL(std::string anActiveScene) { + activeScene = anActiveScene; } -std::string get_currentGUIname_HAL(){ - return currentGUIname; +std::string get_activeGUIname_HAL(){ + return activeGUIname; } -void set_currentGUIname_HAL(std::string aCurrentGUIname) { - currentGUIname = aCurrentGUIname; +void set_activeGUIname_HAL(std::string anActiveGUIname) { + activeGUIname = anActiveGUIname; +} +int get_activeGUIlist_HAL() { + return activeGUIlist; +} +void set_activeGUIlist_HAL(int anActiveGUIlist) { + activeGUIlist = anActiveGUIlist; } diff --git a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h index f94f0f4..9f4d98e 100644 --- a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h +++ b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h @@ -5,7 +5,9 @@ void init_preferences_HAL(void); void save_preferences_HAL(void); -std::string get_currentScene_HAL(); -void set_currentScene_HAL(std::string aCurrentScene); -std::string get_currentGUIname_HAL(); -void set_currentGUIname_HAL(std::string aCurrentGUIname); +std::string get_activeScene_HAL(); +void set_activeScene_HAL(std::string anActiveScene); +std::string get_activeGUIname_HAL(); +void set_activeGUIname_HAL(std::string anActiveGUIname); +int get_activeGUIlist_HAL(); +void set_activeGUIlist_HAL(int anActiveGUIlist); diff --git a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp index af5d257..5d45c89 100644 --- a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp +++ b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp @@ -1,31 +1,50 @@ #include -std::string currentScene; -std::string currentGUIname; +enum GUIlists { +// MAIN_GUI_LIST: we are in the main_gui_list (with the scene selector as first gui), either if a scene is active or not +// SCENE_GUI_LIST: a scene is active and we are not in the main_gui_list. In that case, we try to use the scene specific gui list, if the scene defined one. + MAIN_GUI_LIST, + SCENE_GUI_LIST +}; + +/* +Possible example: +main_gui_list : "Scene selection", "Smart Home", "Settings", "IR Receiver"}; + +"Off" : +"TV" : "Numpad" +"Fire TV" : "Numpad", "Settings" +"Chromecast" : +"Apple TV" : "Apple TV", "Settings", "IR Receiver" +*/ +std::string activeScene; +std::string activeGUIname; +int activeGUIlist; void init_preferences_HAL(void) { + // set some values for tests + activeScene = ""; // "Off", "TV", "Fire TV", "Chromecast", "Apple TV"; + activeGUIname = ""; // "Scene selection", "Smart Home", "Settings", "IR Receiver" // "Numpad", "Apple TV" + activeGUIlist = MAIN_GUI_LIST; // // MAIN_GUI_LIST, SCENE_GUI_LIST; } void save_preferences_HAL(void) { } -std::string get_currentScene_HAL() { - // if (currentScene == "") { - // // set here something if you need it for a test at startup - // return "Apple TV"; - // } else - {return currentScene;} - +std::string get_activeScene_HAL() { + return activeScene; } -void set_currentScene_HAL(std::string aCurrentScene) { - currentScene = aCurrentScene; +void set_activeScene_HAL(std::string anActiveScene) { + activeScene = anActiveScene; } -std::string get_currentGUIname_HAL(){ - // if (currentGUIname == "") { - // // set here something if you need it for a test at startup - // return "IR Receiver"; // "Numpad"; // "Apple TV"; - // } else - {return currentGUIname;} +std::string get_activeGUIname_HAL(){ + return activeGUIname; } -void set_currentGUIname_HAL(std::string aCurrentGUIname) { - currentGUIname = aCurrentGUIname; +void set_activeGUIname_HAL(std::string anActiveGUIname) { + activeGUIname = anActiveGUIname; +} +int get_activeGUIlist_HAL() { + return activeGUIlist; +} +void set_activeGUIlist_HAL(int anActiveGUIlist) { + activeGUIlist = anActiveGUIlist; } diff --git a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h index f94f0f4..9f4d98e 100644 --- a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h +++ b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h @@ -5,7 +5,9 @@ void init_preferences_HAL(void); void save_preferences_HAL(void); -std::string get_currentScene_HAL(); -void set_currentScene_HAL(std::string aCurrentScene); -std::string get_currentGUIname_HAL(); -void set_currentGUIname_HAL(std::string aCurrentGUIname); +std::string get_activeScene_HAL(); +void set_activeScene_HAL(std::string anActiveScene); +std::string get_activeGUIname_HAL(); +void set_activeGUIname_HAL(std::string anActiveGUIname); +int get_activeGUIlist_HAL(); +void set_activeGUIlist_HAL(int anActiveGUIlist); diff --git a/Platformio/src/applicationInternal/gui/guiBase.cpp b/Platformio/src/applicationInternal/gui/guiBase.cpp index b96d232..c8e9f86 100644 --- a/Platformio/src/applicationInternal/gui/guiBase.cpp +++ b/Platformio/src/applicationInternal/gui/guiBase.cpp @@ -13,8 +13,6 @@ lv_obj_t* BluetoothLabel = NULL; lv_obj_t* BattPercentageLabel = NULL; lv_obj_t* BattIconLabel = NULL; lv_obj_t* SceneLabel = NULL; -uint32_t currentTabID = -1; // id of the current tab -uint32_t oldTabID = -1; lv_obj_t* tabview = NULL; // page indicator @@ -28,8 +26,8 @@ lv_style_t panel_style; lv_style_t style_red_border; #endif -void guis_doTabCreationAtStartup(); -void guis_doAfterSliding(int oldTabID, int newTabID, bool newGuiList); +void guis_doTabCreationOnStartup(); +void guis_doTabCreationAfterSliding(int newTabID); // Helper Functions ----------------------------------------------------------------------------------------------------------------------- @@ -87,28 +85,28 @@ void tabview_content_is_scrolling_event_cb(lv_event_t* e){ // ----------------------- static bool waitBeforeActionAfterSlidingAnimationEnded = false; static unsigned long waitBeforeActionAfterSlidingAnimationEnded_timerStart; +static int newTabID_forLateTabCreation; // This is the callback when the animation of the tab sliding ended static void tabview_animation_ready_cb(lv_anim_t* a) { // Unfortunately, the animation has not completely ended here. We cannot do the recreation of the tabs here. // We have to wait some more milliseconds or at least one cycle of lv_timer_handler(); // calling lv_timer_handler(); here does not help // lv_timer_handler(); - // guis_doAfterSliding(oldTabID, currentTabID, false); + // guis_doTabCreationAfterSliding(newTabID_forLateTabCreation); waitBeforeActionAfterSlidingAnimationEnded = true; waitBeforeActionAfterSlidingAnimationEnded_timerStart = millis(); } -// Update currentTabID when a new tab is selected +// Update gui when a new tab is selected // this is a callback if the tabview is changed (LV_EVENT_VALUE_CHANGED) // Sent when a new tab is selected by sliding or clicking the tab button. lv_tabview_get_tab_act(tabview) returns the zero based index of the current tab. void tabview_tab_changed_event_cb(lv_event_t* e) { if (lv_event_get_code(e) == LV_EVENT_VALUE_CHANGED) { - oldTabID = currentTabID; - currentTabID = lv_tabview_get_tab_act(lv_event_get_target(e)); + int newTabID = lv_tabview_get_tab_active((lv_obj_t*)lv_event_get_target(e)); - // Wait until the animation ended, then call "guis_doAfterSliding(oldTabID, currentTabID, false);" + // Wait until the animation ended, then call "guis_doTabCreationAfterSliding(newTabID);" // https://forum.lvgl.io/t/delete-a-tab-after-the-tabview-scroll-animation-is-complete/3155/4 lv_obj_t* myTabview = lv_event_get_target(e); lv_obj_t* tabContainer = lv_tabview_get_content(myTabview); @@ -116,11 +114,12 @@ void tabview_tab_changed_event_cb(lv_event_t* e) { if(anim) { // Swipe is not yet complete. User released the touch screen, an animation will bring it to the end. // That's the normal (and only?) case for the tft touchscreen + newTabID_forLateTabCreation = newTabID; lv_anim_set_ready_cb(anim, tabview_animation_ready_cb); } else { // Swipe is complete, no additional animation is needed. Most likely only possible in simulator Serial.println("Change of tab detected, without animation at the end. Will directly do my job after sliding."); - guis_doAfterSliding(oldTabID, currentTabID, false); + guis_doTabCreationAfterSliding(newTabID); } } } @@ -154,8 +153,8 @@ void init_gui(void) { lv_obj_set_style_bg_color(lv_scr_act(), lv_color_black(), LV_PART_MAIN); // set default height and position of main widgets setMainWidgetsHeightAndPosition(); - // At startup, set current GUI according to get_currentGUIname(), and create the content of that tab (and the previous and the next) for the first time - guis_doTabCreationAtStartup(); + // On startup, set current GUIname and GUIlist according to last state before going to sleep + guis_doTabCreationOnStartup(); // memoryUsage bar init_gui_memoryUsage_bar(); // status bar @@ -288,12 +287,12 @@ void gui_loop(void) { waitBeforeActionAfterSlidingAnimationEnded = false; } else if (waitOneLoop) { waitOneLoop = false; - guis_doAfterSliding(oldTabID, currentTabID, false); + guis_doTabCreationAfterSliding(newTabID_forLateTabCreation); }; // // as alternative, we could wait some milliseconds. But one cycle of gui_loop() works well. // if (waitBeforeActionAfterSlidingAnimationEnded) { // if (millis() - waitBeforeActionAfterSlidingAnimationEnded_timerStart >= 5) { - // guis_doAfterSliding(oldTabID, currentTabID, false); + // guis_doTabCreationAfterSliding(newTabID_forLateTabCreation); // waitBeforeActionAfterSlidingAnimationEnded = false; // } // } @@ -301,19 +300,25 @@ void gui_loop(void) { lv_timer_handler(); } -void guis_doTabCreationAtStartup() { - gui_memoryOptimizer_prepare_startup(); - - guis_doAfterSliding(-1, -1, false); -} - -void guis_doAfterSliding(int oldTabID, int newTabID, bool newGuiList) { - // With parameter newGuiList it is signaled that we are changing from a scene specific list to the main list or vice versa - // In that case, we have to do special treatment because we are not simply sliding to the left or to the right, but we start newly with a different gui list. - gui_memoryOptimizer_doAfterSliding_deletionAndCreation(&tabview, oldTabID, newTabID, newGuiList, &panel, &img1, &img2); - +// ------------------------------------------------------------------------------------------------------------ +// There are several reasons why the tabs could get recreated. All are going through these functions in "guiBase.cpp", which are calling functions in "guiMemoryOptimizer.cpp" +// 1. tab creation on startup (called by init_gui()) +void guis_doTabCreationOnStartup() { + Serial.printf("Startup: try to resume at scene \"%s\" with GUI \"%s\"\r\n", gui_memoryOptimizer_getActiveSceneName().c_str(), gui_memoryOptimizer_getActiveGUIname().c_str()); + gui_memoryOptimizer_onStartup(&tabview, &panel, &img1, &img2); doLogMemoryUsage(); } +// 2. tab creation after sliding (called by tabview_tab_changed_event_cb()) +void guis_doTabCreationAfterSliding(int newTabID) { + gui_memoryOptimizer_afterSliding(&tabview, &panel, &img1, &img2, newTabID); + doLogMemoryUsage(); +} +// 3. after gui list has changed (called by handleScene()), when switching between main_gui_list and scene specific list +void guis_doTabCreationAfterGUIlistChanged(GUIlists newGUIlist) { + gui_memoryOptimizer_afterGUIlistChanged(&tabview, &panel, &img1, &img2, newGUIlist); + doLogMemoryUsage(); +} +// ------------------------------------------------------------------------------------------------------------ void setActiveTab(uint32_t index, lv_anim_enable_t anim_en, bool send_tab_changed_event) { // unsigned long startTime = millis(); diff --git a/Platformio/src/applicationInternal/gui/guiBase.h b/Platformio/src/applicationInternal/gui/guiBase.h index eb7ceab..2a8c2a0 100644 --- a/Platformio/src/applicationInternal/gui/guiBase.h +++ b/Platformio/src/applicationInternal/gui/guiBase.h @@ -1,6 +1,7 @@ #pragma once #include +#include "applicationInternal/gui/guiMemoryOptimizer.h" // used by memoryUsage.cpp extern lv_obj_t* MemoryUsageLabel; @@ -15,7 +16,6 @@ extern lv_style_t panel_style; extern int tabviewTop; extern int tabviewHeight; extern int panelHeight; -extern uint32_t currentTabID; // used by almost all gui_*.cpp extern lv_color_t color_primary; @@ -32,10 +32,9 @@ void tabview_content_is_scrolling_event_cb(lv_event_t* e); void tabview_tab_changed_event_cb(lv_event_t* e); void sceneLabel_or_pageIndicator_event_cb(lv_event_t* e); void pageIndicator_navigate_event_cb(lv_event_t* e); +void guis_doTabCreationAfterGUIlistChanged(GUIlists newGUIlist); void setActiveTab(uint32_t index, lv_anim_enable_t anim_en, bool send_tab_changed_event = false); // used by memoryUsage.cpp void showMemoryUsageBar(bool showBar); // used by commandHandler to show WiFi status void showWiFiConnected(bool connected); - -void guis_doAfterSliding(int oldTabID, int newTabID, bool newGuiList); diff --git a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp index 8c03a70..e3a1643 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp @@ -1,47 +1,90 @@ #include #include "applicationInternal/gui/guiBase.h" +#include "applicationInternal/gui/guiMemoryOptimizer.h" #include "applicationInternal/gui/guiRegistry.h" -#include "applicationInternal/scenes/sceneRegistry.h" #include "applicationInternal/hardware/hardwarePresenter.h" +#include "applicationInternal/scenes/sceneRegistry.h" -struct tab_in_memory { +struct t_gui_on_tab { lv_obj_t* tab; - int listIndex; - std::string guiName; + std::string GUIname; + int gui_list_index; + int gui_list_index_previous; }; -tab_in_memory tabs_in_memory[3] = {{NULL, -1, ""}, {NULL, -1, ""}, {NULL, -1, ""}}; -// holds the ids of the tabs we had in memory before, so that we can determine the next or previous id -int tabs_in_memory_previous_listIndex[3]= {-1 , -1, -1}; +struct t_gui_state { + // the next three are saved in the preferenceStorage every time they change + std::string activeScene_internalDontUse; + std::string activeGUIname_internalDontUse; + GUIlists activeGUIlist_internalDontUse; + // --- + int activeTabID = -1; // id of the active tab (one of 0,1,2) + int oldTabID = -1; // id of the tab before swiping (one of 0,1,2) + t_gui_on_tab gui_on_tab[3] = {{NULL, "", -1, -1}, {NULL, "", -1, -1}, {NULL, "", -1, -1}}; +}; +t_gui_state gui_state; + +// Both the gui_state and the preferenceStorage should know at any time the current state (scene, GUIname, and GUIlist) +// preferenceStorage should know it because when going to sleep, it should persist the state in NVM. +// So whenever values change, it should be done through these functions. +// On startup, the gui_state is set by gui_memoryOptimizer_onStartup() +std::string gui_memoryOptimizer_getActiveSceneName() { + gui_state.activeScene_internalDontUse = get_activeScene(); + return gui_state.activeScene_internalDontUse; +} +void gui_memoryOptimizer_setActiveSceneName(std::string aSceneName) { + gui_state.activeScene_internalDontUse = aSceneName; + set_activeScene(aSceneName); +} +std::string gui_memoryOptimizer_getActiveGUIname() { + gui_state.activeGUIname_internalDontUse = get_activeGUIname(); + return gui_state.activeGUIname_internalDontUse; +} +void gui_memoryOptimizer_setActiveGUIname(std::string aGUIname) { + gui_state.activeGUIname_internalDontUse = aGUIname; + set_activeGUIname(aGUIname); +} +GUIlists gui_memoryOptimizer_getActiveGUIlist() { + gui_state.activeGUIlist_internalDontUse = (GUIlists)get_activeGUIlist(); + return gui_state.activeGUIlist_internalDontUse; +} +void gui_memoryOptimizer_setActiveGUIlist(GUIlists aGUIlist) { + gui_state.activeGUIlist_internalDontUse = aGUIlist; + set_activeGUIlist(aGUIlist); +} + +int gui_memoryOptimizer_getActiveTabID() { + return gui_state.activeTabID; +} bool gui_memoryOptimizer_isTabIDInMemory(int tabID) { // range check if ((tabID < 0) || (tabID >= 3)) { return false; } - return (tabs_in_memory[tabID].listIndex != -1); + return (gui_state.gui_on_tab[tabID].gui_list_index != -1); } -bool gui_memoryOptimizer_isGUInameInMemory(std::string guiName) { +bool gui_memoryOptimizer_isGUInameInMemory(std::string GUIname) { for (uint8_t index=0; index <= 2; index++) { - if (tabs_in_memory[index].guiName == guiName) { + if (gui_state.gui_on_tab[index].GUIname == GUIname) { return true; } } return false; } -void notify_active_tabs_before_delete() { +void notify_active_tabs_before_delete(t_gui_state *gui_state) { Serial.printf(" Will notify tabs about deletion\r\n"); std::string nameOfTab; for (int index=0; index <= 2; index++) { - if (tabs_in_memory[index].listIndex == -1) { + if (gui_state->gui_on_tab[index].gui_list_index == -1) { Serial.printf(" Will not notify tab %d about deletion because it does not exist\r\n", index); continue; } - // For deletion, do not use the listIndex, but the name of the gui. + // For deletion, do not use the gui_list_index, but the name of the gui. // The gui_list might have changed (when switching from a scene specific list to the main list or vice versa), so index could have changed as well. - nameOfTab = tabs_in_memory[index].guiName; + nameOfTab = gui_state->gui_on_tab[index].GUIname; if (nameOfTab == "") { Serial.printf(" Will not notify tab %d about deletion because it is not set\r\n", index); } else if (registered_guis_byName_map.count(nameOfTab) == 0) { @@ -53,7 +96,7 @@ void notify_active_tabs_before_delete() { } } -void clear_tabview(lv_obj_t* tabview) { +void clear_tabview(lv_obj_t* tabview, t_gui_state *gui_state) { if (tabview != NULL) { // first remove events for the tabview lv_obj_remove_event_cb(tabview, tabview_tab_changed_event_cb); @@ -63,10 +106,10 @@ void clear_tabview(lv_obj_t* tabview) { tabview = NULL; } - // set struct tabs_in_memory to NULL - tabs_in_memory[0] = {NULL, -1, ""}; - tabs_in_memory[1] = {NULL, -1, ""}; - tabs_in_memory[2] = {NULL, -1, ""}; + // the gui_list_index_previous is needed for setGUIlistIndicesToBeShown_afterSlide(); + gui_state->gui_on_tab[0] = {NULL, "", -1, gui_state->gui_on_tab[0].gui_list_index}; + gui_state->gui_on_tab[1] = {NULL, "", -1, gui_state->gui_on_tab[1].gui_list_index}; + gui_state->gui_on_tab[2] = {NULL, "", -1, gui_state->gui_on_tab[2].gui_list_index}; } @@ -114,162 +157,161 @@ lv_obj_t* create_panel() { std::string get_name_of_gui_to_be_shown(int index) { if (index == -1) { return ""; - } else if (index <= get_gui_list(get_currentScene())->size() -1) { - return get_gui_list(get_currentScene())->at(index); + } else if (index <= get_gui_list_active()->size() -1) { + return get_gui_list_active()->at(index); } else { return ""; } } -void create_new_tab(lv_obj_t* tabview, uint32_t tabs_in_memory_index) { - std::string nameOfTab = get_name_of_gui_to_be_shown(tabs_in_memory[tabs_in_memory_index].listIndex); +void create_new_tab(lv_obj_t* tabview, t_gui_on_tab *gui_on_tab) { + std::string nameOfTab = get_name_of_gui_to_be_shown(gui_on_tab->gui_list_index); if (nameOfTab == "") { - Serial.printf(" Will not create new tab at index %d because no name was provided\r\n", tabs_in_memory_index); + Serial.printf(" Will not create new tab because no name was provided\r\n"); } else if (registered_guis_byName_map.count(nameOfTab) == 0) { - Serial.printf(" Will not create new tab at index %d because name %s was not found in registry\r\n", tabs_in_memory_index, nameOfTab.c_str()); + Serial.printf(" Will not create new tab because name %s was not found in registry\r\n", nameOfTab.c_str()); } else { - Serial.printf(" Will create tab with name \"%s\" at index %d\r\n", nameOfTab.c_str(), tabs_in_memory_index); + Serial.printf(" Will create tab with name \"%s\" \r\n", nameOfTab.c_str()); // save name of tab for deletion later - tabs_in_memory[tabs_in_memory_index].guiName = nameOfTab; - // create tab and save pointer to tab in tabs_in_memory - tabs_in_memory[tabs_in_memory_index].tab = lv_tabview_add_tab(tabview, nameOfTab.c_str()); + gui_on_tab->GUIname = nameOfTab; + // create tab and save pointer to tab in gui_on_tab + gui_on_tab->tab = lv_tabview_add_tab(tabview, nameOfTab.c_str()); // let the gui create it's content - registered_guis_byName_map.at(nameOfTab).this_create_tab_content(tabs_in_memory[tabs_in_memory_index].tab); + registered_guis_byName_map.at(nameOfTab).this_create_tab_content(gui_on_tab->tab); } } -void doTabCreation_strategyMax3(lv_obj_t* tabview, uint32_t oldTabID, uint32_t newTabID) { - // create up to three tabs and the content of the tabs - /* - example: gui_list: 0 1 2 3 4 - in memory active - 0 1 -1 0 <- first state, special case - also the initial state - 0 1 2 1 - 1 2 3 1 - 2 3 4 1 - 3 4 -1 1 <- last state, special case - */ +// create up to three tabs and the content of the tabs +/* +example: gui_list: 0 1 2 3 4 +in memory active +0 1 -1 0 <- first state, special case - also the initial state +0 1 2 1 +1 2 3 1 +2 3 4 1 +3 4 -1 1 <- last state, special case +*/ +void setGUIlistIndicesToBeShown_forSpecificGUIlistIndex(int gui_list_index, t_gui_state *gui_state) { + // Set the gui_list_indeces to be shown for a specific gui_list_index + if (gui_list_index == 0) { + // first state + Serial.printf(" GUIlistIndices: will resume at specific index with \"first state\"\r\n"); + gui_state->gui_on_tab[0] = {NULL, "", 0}; + // take care if there is only one gui in list + gui_state->gui_on_tab[1] = {NULL, "", get_gui_list_active()->size() >= 2 ? 1 : -1}; + gui_state->gui_on_tab[2] = {NULL, "", -1}; + gui_state->activeTabID = 0; + } else if (gui_list_index == get_gui_list_active()->size() -1) { + // last state + Serial.printf(" GUIlistIndices: will resume at specific index with \"last state\"\r\n"); + gui_state->gui_on_tab[0] = {NULL, "", gui_list_index -1}; + gui_state->gui_on_tab[1] = {NULL, "", gui_list_index}; + gui_state->gui_on_tab[2] = {NULL, "", -1}; + gui_state->activeTabID = 1; + } else { + // any other state + Serial.printf(" GUIlistIndices: will resume at specific index with \"state between\"\r\n"); + gui_state->gui_on_tab[0] = {NULL, "", gui_list_index -1}; + gui_state->gui_on_tab[1] = {NULL, "", gui_list_index}; + gui_state->gui_on_tab[2] = {NULL, "", gui_list_index +1}; + gui_state->activeTabID = 1; + } +} - int tabToBeActivated = -1; +void setGUIlistIndicesToBeShown_forFirstGUIinGUIlist(t_gui_state *gui_state) { + Serial.printf(" GUIlistIndices: will show the first gui from \"gui_list\" as initial state\r\n"); + // take care if there is no gui in list + gui_state->gui_on_tab[0] = {NULL, "", get_gui_list_active()->size() != 0 ? 0 : -1}; + // take care if there is only one gui in list + gui_state->gui_on_tab[1] = {NULL, "", get_gui_list_active()->size() >= 2 ? 1 : -1}; + gui_state->gui_on_tab[2] = {NULL, "", -1}; + gui_state->activeTabID = 0; +} + +void setGUIlistIndicesToBeShown_afterSlide(t_gui_state *gui_state) { int oldListIndex = -1; - - if ((oldTabID == -1) && (newTabID == -1)) { - // This is the initialization after the ESP32 has booted. - - if ((tabs_in_memory_previous_listIndex[0] < get_gui_list(get_currentScene())->size()) && (tabs_in_memory_previous_listIndex[0] != -1)) { - // In gui_memoryOptimizer_prepare_startup, the index of get_currentGUIname() in gui_list was saved, if found. - // We can resume at this old state. - oldListIndex = tabs_in_memory_previous_listIndex[0] ; - if (oldListIndex == 0) { - // first state - Serial.printf(" Startup: will resume where we went to sleep with \"first state\"\r\n"); - tabs_in_memory[0] = {NULL, 0}; - // take care if there is only one gui in list - tabs_in_memory[1] = {NULL, get_gui_list(get_currentScene())->size() >= 2 ? 1 : -1}; - tabs_in_memory[2] = {NULL, -1}; - tabToBeActivated = 0; - } else if (oldListIndex == get_gui_list(get_currentScene())->size() -1) { - // last state - Serial.printf(" Startup: will resume where we went to sleep with \"last state\"\r\n"); - tabs_in_memory[0] = {NULL, oldListIndex -1}; - tabs_in_memory[1] = {NULL, oldListIndex}; - tabs_in_memory[2] = {NULL, -1}; - tabToBeActivated = 1; - } else { - // any other state - Serial.printf(" Startup: will resume where we went to sleep with \"state between\"\r\n"); - tabs_in_memory[0] = {NULL, oldListIndex -1}; - tabs_in_memory[1] = {NULL, oldListIndex}; - tabs_in_memory[2] = {NULL, oldListIndex +1}; - tabToBeActivated = 1; - } - } else { - Serial.printf(" Startup: cannot resume old state, so we will show the first tabs from \"gui_list\" as initial state\r\n"); - // take care if there is no gui in list - tabs_in_memory[0] = {NULL, get_gui_list(get_currentScene())->size() != 0 ? 0 : -1}; - // take care if there is only one gui in list - tabs_in_memory[1] = {NULL, get_gui_list(get_currentScene())->size() >= 2 ? 1 : -1}; - tabs_in_memory[2] = {NULL, -1}; - tabToBeActivated = 0; - } - } else if (oldTabID > newTabID) { + + if (gui_state->oldTabID > gui_state->activeTabID) { // swipe to previous item in list Serial.printf(" Will swipe to previous item in list\r\n"); - oldListIndex = tabs_in_memory_previous_listIndex[1]; + oldListIndex = gui_state->gui_on_tab[1].gui_list_index_previous; if ((oldListIndex == 1)) { // next state is the "first state" - tabs_in_memory[0] = {NULL, 0}; - tabs_in_memory[1] = {NULL, 1}; - tabs_in_memory[2] = {NULL, -1}; - tabToBeActivated = 0; + gui_state->gui_on_tab[0] = {NULL, "", 0}; + gui_state->gui_on_tab[1] = {NULL, "", 1}; + gui_state->gui_on_tab[2] = {NULL, "", -1}; + gui_state->activeTabID = 0; } else { - tabs_in_memory[0] = {NULL, oldListIndex -2}; - tabs_in_memory[1] = {NULL, oldListIndex -1}; - tabs_in_memory[2] = {NULL, oldListIndex}; - tabToBeActivated = 1; + gui_state->gui_on_tab[0] = {NULL, "", oldListIndex -2}; + gui_state->gui_on_tab[1] = {NULL, "", oldListIndex -1}; + gui_state->gui_on_tab[2] = {NULL, "", oldListIndex}; + gui_state->activeTabID = 1; } } else { // swipe to next item in list Serial.printf(" Will swipe to next item in list\r\n"); - if (tabs_in_memory_previous_listIndex[2] == -1) { + if (gui_state->gui_on_tab[2].gui_list_index_previous == -1) { // last state was the first state - oldListIndex = tabs_in_memory_previous_listIndex[0]; // is always 0 + oldListIndex = gui_state->gui_on_tab[0].gui_list_index_previous; // is always 0 } else { - oldListIndex = tabs_in_memory_previous_listIndex[1]; + oldListIndex = gui_state->gui_on_tab[1].gui_list_index_previous; } - if (oldListIndex == get_gui_list(get_currentScene())->size() -2) { + if (oldListIndex == get_gui_list_active()->size() -2) { // next state is the "last state" - tabs_in_memory[0] = {NULL, oldListIndex}; - tabs_in_memory[1] = {NULL, oldListIndex +1}; - tabs_in_memory[2] = {NULL, -1}; - tabToBeActivated = 1; + gui_state->gui_on_tab[0] = {NULL, "", oldListIndex}; + gui_state->gui_on_tab[1] = {NULL, "", oldListIndex +1}; + gui_state->gui_on_tab[2] = {NULL, "", -1}; + gui_state->activeTabID = 1; } else { - tabs_in_memory[0] = {NULL, oldListIndex}; - tabs_in_memory[1] = {NULL, oldListIndex +1}; - tabs_in_memory[2] = {NULL, oldListIndex +2}; - tabToBeActivated = 1; + gui_state->gui_on_tab[0] = {NULL, "", oldListIndex}; + gui_state->gui_on_tab[1] = {NULL, "", oldListIndex +1}; + gui_state->gui_on_tab[2] = {NULL, "", oldListIndex +2}; + gui_state->activeTabID = 1; } } + +} +void doTabCreation_strategyMax3(lv_obj_t* tabview, t_gui_state *gui_state) { + // create the tabs - Serial.printf(" Will create tabs. List indices of the three tabs are %d, %d, %d, tab nr %d will be activated\r\n", tabs_in_memory[0].listIndex, tabs_in_memory[1].listIndex, tabs_in_memory[2].listIndex, tabToBeActivated); + Serial.printf(" Will create tabs. List indices of the three tabs are %d, %d, %d, tab nr %d will be activated\r\n", gui_state->gui_on_tab[0].gui_list_index, gui_state->gui_on_tab[1].gui_list_index, gui_state->gui_on_tab[2].gui_list_index, gui_state->activeTabID); for (int i=0; i<3; i++) { - create_new_tab(tabview, i); + create_new_tab(tabview, &gui_state->gui_on_tab[i]); } - if (get_gui_list(get_currentScene())->size() > 0) { - std::string nameOfNewActiveTab = get_gui_list(get_currentScene())->at(tabs_in_memory[tabToBeActivated].listIndex); + if (get_gui_list_active()->size() > 0) { + std::string nameOfNewActiveTab = get_gui_list_active()->at(gui_state->gui_on_tab[gui_state->activeTabID].gui_list_index); Serial.printf(" New visible tab is \"%s\"\r\n", nameOfNewActiveTab.c_str()); - // set the tab we swiped to as active - setActiveTab(tabToBeActivated, LV_ANIM_OFF); - set_currentGUIname(nameOfNewActiveTab); - currentTabID = tabToBeActivated; + // set active tab + setActiveTab(gui_state->activeTabID, LV_ANIM_OFF); + gui_memoryOptimizer_setActiveGUIname(nameOfNewActiveTab); } } LV_IMG_DECLARE(gradientLeft); LV_IMG_DECLARE(gradientRight); -void getBreadcrumpPosition(uint8_t* breadcrumpPosition, std::string nameOfTab) { +void getBreadcrumpPosition(uint8_t* breadcrumpPosition, std::string nameOfGUI) { *breadcrumpPosition = 0; - gui_list currentGUIlist = get_gui_list(get_currentScene()); + gui_list gui_list_active = get_gui_list_active(); uint8_t counter = 0; - for (std::vector::iterator it = currentGUIlist->begin() ; it != currentGUIlist->end(); ++it) { + for (std::vector::iterator it = gui_list_active->begin() ; it != gui_list_active->end(); ++it) { counter++; - if (*it == nameOfTab) { + if (*it == nameOfGUI) { *breadcrumpPosition = counter; return; } } } -void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv_obj_t* img2) { +void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv_obj_t* img2, t_gui_state *gui_state) { Serial.printf(" Will fill panel with page indicators\r\n"); - if (get_gui_list(get_currentScene())->size() == 0) { + if (get_gui_list_active()->size() == 0) { Serial.printf(" no tab available, so no page indicators\r\n"); // at least add the style lv_obj_add_style(panel, &panel_style, 0); @@ -301,33 +343,33 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv btn = lv_btn_create(panel); lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_size(btn, 150, lv_pct(100)); - if (tabs_in_memory[0].listIndex == 0) { + if (gui_state->gui_on_tab[0].gui_list_index == 0) { lv_obj_set_style_bg_color(btn, lv_color_black(), LV_PART_MAIN); } else { lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); } - uint8_t breadcrumpLength = get_gui_list(get_currentScene())->size(); + uint8_t breadcrumpLength = get_gui_list_active()->size(); uint8_t breadcrumpDotSize = 8; // should be an even number uint8_t breadcrumpDotDistance = 2; // should be an even number int8_t breadcrumpStartPositionX = (-1) * (breadcrumpLength -1) * (breadcrumpDotSize + breadcrumpDotDistance) / 2; // create the panel content for the three guis (or less) which are currently in memory - std::string nameOfTab; + std::string nameOfGUI; uint8_t breadcrumpPosition; for (int i=0; i<3; i++) { - if (tabs_in_memory[i].listIndex != -1) { - nameOfTab = tabs_in_memory[i].guiName; - getBreadcrumpPosition(&breadcrumpPosition, nameOfTab); + if (gui_state->gui_on_tab[i].gui_list_index != -1) { + nameOfGUI = gui_state->gui_on_tab[i].GUIname; + getBreadcrumpPosition(&breadcrumpPosition, nameOfGUI); // Create actual buttons for every tab lv_obj_t* btn = lv_btn_create(panel); // only if this is the button for the currently active tab, make it clickable to get to scene selection gui - if (nameOfTab == get_currentGUIname()) { + if (nameOfGUI == gui_memoryOptimizer_getActiveGUIname()) { lv_obj_add_flag(btn, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_event_cb(btn, sceneLabel_or_pageIndicator_event_cb, LV_EVENT_CLICKED, NULL); - } else if ((i==0 || i==1) && (tabs_in_memory[i+1].listIndex != -1)) { + } else if ((i==0 || i==1) && (gui_state->gui_on_tab[i+1].gui_list_index != -1)) { // this is the button on the previous tab, which can be seen on the active tab // activate click to prev tab lv_obj_add_flag(btn, LV_OBJ_FLAG_CLICKABLE); @@ -367,7 +409,7 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv } lv_obj_t* label = lv_label_create(btn); lv_obj_set_style_text_font(label, &lv_font_montserrat_10, LV_PART_MAIN); - lv_label_set_text_fmt(label, "%s", nameOfTab.c_str()); + lv_label_set_text_fmt(label, "%s", nameOfGUI.c_str()); lv_obj_align(label, LV_ALIGN_BOTTOM_MID, 0, 6); } @@ -377,8 +419,8 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv btn = lv_btn_create(panel); lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_size(btn, 150, lv_pct(100)); - // 4 at last position 4 at middle position only one tab available overall - if ((tabs_in_memory[2].listIndex == get_gui_list(get_currentScene())->size()-1) || (tabs_in_memory[1].listIndex == get_gui_list(get_currentScene())->size()-1) || (tabs_in_memory[1].listIndex == -1)) { + // 4 at last position 4 at middle position only one tab available overall + if ((gui_state->gui_on_tab[2].gui_list_index == get_gui_list_active()->size()-1) || (gui_state->gui_on_tab[1].gui_list_index == get_gui_list_active()->size()-1) || (gui_state->gui_on_tab[1].gui_list_index == -1)) { lv_obj_set_style_bg_color(btn, lv_color_black(), LV_PART_MAIN); } else { lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); @@ -419,71 +461,76 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv } -void gui_memoryOptimizer_prepare_startup() { - // find index of get_currentGUIname() in gui_list - for (int i=0; isize(); i++) { - if (get_gui_list(get_currentScene())->at(i) == get_currentGUIname()) { - Serial.printf("Startup: found GUI with name \"%s\" in \"gui_list\" at position %d\r\n", get_currentGUIname().c_str(), i); - // save position so that "guis_doAfterSliding" can use it - tabs_in_memory[0].listIndex = i; - } - } +void gui_memoryOptimizer_notifyAndClear(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, t_gui_state *gui_state) { - // if the gui was not found in main_gui_list, try to find it in scene specific list - if (tabs_in_memory[0].listIndex == -1) { - useSceneGUIlist = true; - for (int i=0; isize(); i++) { - if (get_gui_list(get_currentScene())->at(i) == get_currentGUIname()) { - Serial.printf("Startup: found GUI with name \"%s\" in scene specific \"gui_list\" at position %d\r\n", get_currentGUIname().c_str(), i); - // save position so that "guis_doAfterSliding" can use it - tabs_in_memory[0].listIndex = i; - } - } - } - - // if the gui was still not found, reset useSceneGUIlist - if (tabs_in_memory[0].listIndex == -1) { - useSceneGUIlist = false; - } + // 1. notify old guis that they will be deleted so that they can persist their state if needed + notify_active_tabs_before_delete(gui_state); + // 2. clear current tabview and save gui_list_index_previous (needed for swipe) + clear_tabview(*tabview, gui_state); + // 3. clear current panel for page indicator + clear_panel(*panel, *img1, *img2); } -void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, int oldTabID, int newTabID, bool newGuiList, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2) { +void gui_memoryOptimizer_doContentCreation(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, t_gui_state *gui_state); + +// find the position of the current GUI in the gui list which was active last (both were automatically saved in the preferences) +void gui_memoryOptimizer_onStartup(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2) { + + // Get last state from preferences and save it in gui_state + // So it is ok to call them without using the return values. + gui_memoryOptimizer_getActiveSceneName(); + gui_memoryOptimizer_getActiveGUIname(); + gui_memoryOptimizer_getActiveGUIlist(); + + // 1. find last used gui + int gui_list_index = -1; + // find index of gui_memoryOptimizer_getActiveGUIname() in gui_list_active + for (int i=0; isize(); i++) { + if (get_gui_list_active()->at(i) == gui_memoryOptimizer_getActiveGUIname()) { + Serial.printf("Startup: found GUI with name \"%s\" in \"gui_list_active\" at position %d\r\n", gui_memoryOptimizer_getActiveGUIname().c_str(), i); + gui_list_index = i; + break; + } + } + + // 2. set gui_list_indices and the tab to be activated + if ((gui_list_index >= 0) && (gui_list_index < get_gui_list_active()->size())) { + // gui was found + setGUIlistIndicesToBeShown_forSpecificGUIlistIndex(gui_list_index, &gui_state); + + } else { + // gui was not found + Serial.printf("Startup: GUI with name \"%s\" was not found. Will start with first GUI of main_gui_list\r\n", gui_memoryOptimizer_getActiveGUIname().c_str()); + gui_memoryOptimizer_setActiveGUIlist(MAIN_GUI_LIST); + setGUIlistIndicesToBeShown_forFirstGUIinGUIlist(&gui_state); + + } + + // 3. create content + gui_memoryOptimizer_doContentCreation(tabview, panel, img1, img2, &gui_state); + +} + +void gui_memoryOptimizer_afterSliding(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, int newTabID) { + // Here the magic for dynamic creation and deletion of lvgl objects happens to keep memory usage low. // The next and previous tab must always be available in the tabview, because they can already been seen during the animation. // And you always need 3 tabs, otherwise you even could not slide to the next or previous tab. // So we always have 3 tabs. // After the animation, the tabview and hence all tabs are deleted and recreated. - // With parameter newGuiList it is signaled that we are changing from a scene specific list to the main list or vice versa - // In that case, we have to do special treatment because we are not simply sliding to the left or to the right, but we start newly with a different gui list. - // only called by guis_doTabCreationAtStartup(): - // oldTabID = -1, newTabID = -1, newGuiList = false - // called by handleScene() - // oldTabID = -1, newTabID = -1, newGuiList = true - Serial.printf("--- Start of tab deletion and creation\r\n"); - bool isInitialization = ((oldTabID == -1) && (newTabID == -1)); - if (isInitialization) { - Serial.printf("Startup: will initially create the tabs to be shown\r\n"); - } else { - Serial.printf("Changing from oldTabID %d \"%s\" to newTabID %d \"%s\"\r\n", - oldTabID, get_gui_list(get_currentScene())->at(tabs_in_memory[oldTabID].listIndex).c_str(), - newTabID, get_gui_list(get_currentScene())->at(tabs_in_memory[newTabID].listIndex).c_str()); - } + gui_state.oldTabID = gui_state.activeTabID; + gui_state.activeTabID = newTabID; - // Save the ids of the tabs we had in memory before. This is only used by doTabCreation_strategyMax3() to know where we come from and where we have to go to. - for (int i=0; i<3; i++) { - tabs_in_memory_previous_listIndex[i] = tabs_in_memory[i].listIndex; - } + Serial.printf("Changing from oldTabID %d \"%s\" to newTabID %d \"%s\"\r\n", + gui_state.oldTabID, gui_state.gui_on_tab[gui_state.oldTabID].GUIname.c_str(), + gui_state.activeTabID, gui_state.gui_on_tab[gui_state.activeTabID].GUIname.c_str()); - // the old tabs need to be notified that they will be deleted so that they can persist their state if needed - notify_active_tabs_before_delete(); - // clear current tabview - clear_tabview(*tabview); - // clear current panel for page indicator - clear_panel(*panel, *img1, *img2); + // 1. notify old guis and clear tabview and panel + gui_memoryOptimizer_notifyAndClear(tabview, panel, img1, img2, &gui_state); // only optional: delete and create the whole screen. Not necessary. // Only used for a test. init_gui_status_bar() would need to be called again at a suitable place, because the status bar would also be deleted. @@ -494,25 +541,44 @@ void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, // lv_scr_load(newscr); // lv_obj_del(oldscr); - if (newGuiList) { - // If we are switching to a new gui list, then we need to set tabs_in_memory_previous_listIndex[0] = -1; - // Doing so, doTabCreation_strategyMax3() knows that we cannot resume an old state. - tabs_in_memory_previous_listIndex[0] = -1; - } + // 2. set gui_list_indices and the tab to be activated + setGUIlistIndicesToBeShown_afterSlide(&gui_state); + // 3. create content + gui_memoryOptimizer_doContentCreation(tabview, panel, img1, img2, &gui_state); +} + +void gui_memoryOptimizer_afterGUIlistChanged(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, GUIlists newGUIlist) { + + Serial.printf("--- Will change to new gui_list\r\n"); + + // 1. notify old guis and clear tabview and panel + gui_memoryOptimizer_notifyAndClear(tabview, panel, img1, img2, &gui_state); + + // 2. set gui_list_indices and the tab to be activated + gui_memoryOptimizer_setActiveGUIlist(newGUIlist); + setGUIlistIndicesToBeShown_forFirstGUIinGUIlist(&gui_state); + + // 3. create content + gui_memoryOptimizer_doContentCreation(tabview, panel, img1, img2, &gui_state); + +} + +void gui_memoryOptimizer_doContentCreation(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, t_gui_state *gui_state) { // recreate the tabview lv_obj_t* newTabview = create_tabview(); *tabview = newTabview; + // Create the tabs. Use strategy "3 tabs at maximum" to keep memory usage low. // Set the tab we swiped to as active - doTabCreation_strategyMax3(*tabview, oldTabID, newTabID); + doTabCreation_strategyMax3(*tabview, gui_state); // Create the panel for the page indicator. Panel itself takes about 2136 bytes for three tabs. lv_obj_t* newPanel = create_panel(); *panel = newPanel; *img1 = lv_img_create(lv_scr_act()); *img2 = lv_img_create(lv_scr_act()); - fillPanelWithPageIndicator_strategyMax3(*panel, *img1, *img2); + fillPanelWithPageIndicator_strategyMax3(*panel, *img1, *img2, gui_state); // now, as the correct tab is active, register again the events for the tabview lv_obj_add_event_cb(*tabview, tabview_tab_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL); diff --git a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h index 83a87c4..47ec812 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h @@ -1,6 +1,26 @@ #pragma once +#include +#include -void gui_memoryOptimizer_prepare_startup(); -void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, int oldTabID, int newTabID, bool newGuiList, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2); +enum GUIlists { +// MAIN_GUI_LIST: we are in the main_gui_list (with the scene selector as first gui), either if a scene is active or not +// SCENE_GUI_LIST: a scene is active and we are not in the main_gui_list. In that case, we try to use the scene specific gui list, if the scene defined one. + MAIN_GUI_LIST, + SCENE_GUI_LIST +}; + +void gui_memoryOptimizer_onStartup(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2); +void gui_memoryOptimizer_afterSliding(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, int newTabID); +void gui_memoryOptimizer_afterGUIlistChanged(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, GUIlists newGUIlist); + +int gui_memoryOptimizer_getActiveTabID(); bool gui_memoryOptimizer_isTabIDInMemory(int tabID); -bool gui_memoryOptimizer_isGUInameInMemory(std::string guiName); +bool gui_memoryOptimizer_isGUInameInMemory(std::string GUIname); + +std::string gui_memoryOptimizer_getActiveSceneName(); +void gui_memoryOptimizer_setActiveSceneName(std::string aSceneName); +std::string gui_memoryOptimizer_getActiveGUIname(); +void gui_memoryOptimizer_setActiveGUIname(std::string aGUIname); +GUIlists gui_memoryOptimizer_getActiveGUIlist(); +void gui_memoryOptimizer_setActiveGUIlist(GUIlists aGUIlist); + diff --git a/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp b/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp index eeb20b3..4a78631 100644 --- a/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp +++ b/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp @@ -26,17 +26,23 @@ void init_preferences(void) { void save_preferences(void) { save_preferences_HAL(); }; -std::string get_currentScene() { - return get_currentScene_HAL(); +std::string get_activeScene() { + return get_activeScene_HAL(); } -void set_currentScene(std::string aCurrentScene) { - set_currentScene_HAL(aCurrentScene); +void set_activeScene(std::string anActiveScene) { + set_activeScene_HAL(anActiveScene); } -std::string get_currentGUIname() { - return get_currentGUIname_HAL(); +std::string get_activeGUIname() { + return get_activeGUIname_HAL(); } -void set_currentGUIname(std::string aCurrentGUIname) { - set_currentGUIname_HAL(aCurrentGUIname); +void set_activeGUIname(std::string anActiveGUIname) { + set_activeGUIname_HAL(anActiveGUIname); +} +int get_activeGUIlist() { + return get_activeGUIlist_HAL(); +} +void set_activeGUIlist(int anActiveGUIlist) { + set_activeGUIlist_HAL(anActiveGUIlist); } // --- user led --------------------------------------------------------------- diff --git a/Platformio/src/applicationInternal/hardware/hardwarePresenter.h b/Platformio/src/applicationInternal/hardware/hardwarePresenter.h index 1145f1c..f01111e 100644 --- a/Platformio/src/applicationInternal/hardware/hardwarePresenter.h +++ b/Platformio/src/applicationInternal/hardware/hardwarePresenter.h @@ -10,10 +10,12 @@ void init_hardware_general(void); // --- preferences ------------------------------------------------------------ void init_preferences(void); void save_preferences(void); -std::string get_currentScene(); -void set_currentScene(std::string aCurrentScene); -std::string get_currentGUIname(); -void set_currentGUIname(std::string aCurrentGUIname); +std::string get_activeScene(); +void set_activeScene(std::string anActiveScene); +std::string get_activeGUIname(); +void set_activeGUIname(std::string anActiveGUIname); +int get_activeGUIlist(); +void set_activeGUIlist(int anActiveGUIlist); // --- user led --------------------------------------------------------------- void init_userled(void); diff --git a/Platformio/src/applicationInternal/keys.cpp b/Platformio/src/applicationInternal/keys.cpp index 75f2241..f46cdcb 100644 --- a/Platformio/src/applicationInternal/keys.cpp +++ b/Platformio/src/applicationInternal/keys.cpp @@ -1,7 +1,8 @@ #include +#include "applicationInternal/gui/guiMemoryOptimizer.h" +#include "applicationInternal/hardware/hardwarePresenter.h" #include "applicationInternal/scenes/sceneRegistry.h" #include "applicationInternal/commandHandler.h" -#include "applicationInternal/hardware/hardwarePresenter.h" const uint8_t ROWS = 5; //five rows const uint8_t COLS = 5; //five columns @@ -33,7 +34,7 @@ void doShortPress(char keyChar, int keyCode){ if ((currentMillis - lastTimeSent[keyCode/ROWS][keyCode%ROWS]) > repeatRate) { lastTimeSent[keyCode/ROWS][keyCode%ROWS] = currentMillis; - uint16_t command = get_command_short(get_currentScene(), keyChar); + uint16_t command = get_command_short(gui_memoryOptimizer_getActiveSceneName(), keyChar); if (command != COMMAND_UNKNOWN) { Serial.printf("key: key '%c', will use command '%u'\r\n", keyChar, command); executeCommand(command); @@ -44,7 +45,7 @@ void doShortPress(char keyChar, int keyCode){ } void doLongPress(char keyChar, int keyCode){ - uint16_t command = get_command_long(get_currentScene(), keyChar); + uint16_t command = get_command_long(gui_memoryOptimizer_getActiveSceneName(), keyChar); if (command != COMMAND_UNKNOWN) { Serial.printf("key: key '%c' (long press), will use command '%u'\r\n", keyChar, command); executeCommand(command); @@ -70,11 +71,11 @@ void keypad_loop(void) { if (keypad_keys[i].kstate == PRESSED) { // Serial.println("pressed"); - if ((get_key_repeatMode(get_currentScene(), keyChar) == SHORT) && (lastKeyState[keyCode/ROWS][keyCode%ROWS] != PRESSED)) { + if ((get_key_repeatMode(gui_memoryOptimizer_getActiveSceneName(), keyChar) == SHORT) && (lastKeyState[keyCode/ROWS][keyCode%ROWS] != PRESSED)) { // Serial.printf("key: PRESSED of SHORT key %c (%d)\r\n", keyChar, keyCode); doShortPress(keyChar, keyCode); - } else if ((get_key_repeatMode(get_currentScene(), keyChar) == SHORT_REPEATED) && (lastKeyState[keyCode/ROWS][keyCode%ROWS] != PRESSED)) { // here do not repeat it too early, do the repeat only in HOLD + } else if ((get_key_repeatMode(gui_memoryOptimizer_getActiveSceneName(), keyChar) == SHORT_REPEATED) && (lastKeyState[keyCode/ROWS][keyCode%ROWS] != PRESSED)) { // here do not repeat it too early, do the repeat only in HOLD // Serial.printf("key: PRESSED of SHORT_REPEATED key %c (%d)\r\n", keyChar, keyCode); doShortPress(keyChar, keyCode); @@ -84,13 +85,13 @@ void keypad_loop(void) { } else if (keypad_keys[i].kstate == HOLD) { // Serial.println("hold"); - if ((get_key_repeatMode(get_currentScene(), keyChar) == SHORTorLONG) && (lastKeyState[keyCode/ROWS][keyCode%ROWS] != HOLD)) { + if ((get_key_repeatMode(gui_memoryOptimizer_getActiveSceneName(), keyChar) == SHORTorLONG) && (lastKeyState[keyCode/ROWS][keyCode%ROWS] != HOLD)) { // Serial.printf("key: HOLD of SHORTorLONG key %c (%d)\r\n", keyChar, keyCode); // Serial.printf("will set keyIsHold to TRUE for keycode %d\r\n", keyCode); keyIsHold[keyCode/ROWS][keyCode%ROWS] = true; doLongPress(keyChar, keyCode); - } else if (get_key_repeatMode(get_currentScene(), keyChar) == SHORT_REPEATED) { // this is the only case where we do not check the lastKeyState, because here it is intended to repeat the action + } else if (get_key_repeatMode(gui_memoryOptimizer_getActiveSceneName(), keyChar) == SHORT_REPEATED) { // this is the only case where we do not check the lastKeyState, because here it is intended to repeat the action // Serial.printf("key: HOLD of SHORT_REPEATED key %c (%d)\r\n", keyChar, keyCode); doShortPress(keyChar, keyCode); @@ -99,7 +100,7 @@ void keypad_loop(void) { } else if (keypad_keys[i].kstate == RELEASED) { // Serial.println("released"); - if ((get_key_repeatMode(get_currentScene(), keyChar) == SHORTorLONG) && !keyIsHold[keyCode/ROWS][keyCode%ROWS] && (lastKeyState[keyCode/ROWS][keyCode%ROWS] != RELEASED)) { + if ((get_key_repeatMode(gui_memoryOptimizer_getActiveSceneName(), keyChar) == SHORTorLONG) && !keyIsHold[keyCode/ROWS][keyCode%ROWS] && (lastKeyState[keyCode/ROWS][keyCode%ROWS] != RELEASED)) { // Serial.printf("value of keyIsHold for keycode %d is %d\r\n", keyCode, keyIsHold[keyCode/ROWS][keyCode%ROWS]); // Serial.printf("key: RELEASED of SHORTorLONG key %c (%d)\r\n", keyChar, keyCode); doShortPress(keyChar, keyCode); diff --git a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp index 8e35b94..fc0f4aa 100644 --- a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp @@ -7,6 +7,12 @@ #include "applicationInternal/commandHandler.h" #include "scenes/scene__default.h" +void setLabelActiveScene() { + if ((SceneLabel != NULL) && sceneExists(gui_memoryOptimizer_getActiveSceneName())) { + lv_label_set_text(SceneLabel, gui_memoryOptimizer_getActiveSceneName().c_str()); + } +} + void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = "") { // FORCE can be either as second payload in commandData @@ -25,27 +31,26 @@ void handleScene(uint16_t command, commandData commandData, std::string addition // do not really switch scene, but show sceneSelection gui. From that on, we are in the main_gui_list. if (scene_name == scene_name_selection) { - useSceneGUIlist = false; - guis_doAfterSliding(-1, -1, true); + guis_doTabCreationAfterGUIlistChanged(MAIN_GUI_LIST); return; } // do not switch scene, but navigate to the prev or next gui in the currently active list of guis if ((scene_name == scene_gui_next) || (scene_name == scene_gui_prev)) { if (scene_name == scene_gui_prev) { - if (currentTabID == 0) { + if (gui_memoryOptimizer_getActiveTabID() == 0) { Serial.println("scene: cannot navigate to prev gui, because there is none"); } else { Serial.println("scene: will navigate to prev gui"); - setActiveTab(currentTabID -1, LV_ANIM_ON, true); + setActiveTab(gui_memoryOptimizer_getActiveTabID() -1, LV_ANIM_ON, true); } } else if (scene_name == scene_gui_next) { - if (!gui_memoryOptimizer_isTabIDInMemory(currentTabID +1)) { + if (!gui_memoryOptimizer_isTabIDInMemory(gui_memoryOptimizer_getActiveTabID() +1)) { Serial.println("scene: cannot navigate to next gui, because there is none"); } else { Serial.println("scene: will navigate to next gui"); - setActiveTab(currentTabID +1, LV_ANIM_ON, true); + setActiveTab(gui_memoryOptimizer_getActiveTabID() +1, LV_ANIM_ON, true); } } @@ -57,15 +62,15 @@ void handleScene(uint16_t command, commandData commandData, std::string addition Serial.printf("scene: cannot start scene %s, because it is unknown\r\n", scene_name.c_str()); return; } else { - Serial.printf("scene: will switch from old scene %s to new scene %s\r\n", get_currentScene().c_str(), scene_name.c_str()); + Serial.printf("scene: will switch from old scene %s to new scene %s\r\n", gui_memoryOptimizer_getActiveSceneName().c_str(), scene_name.c_str()); } // do not activate the same scene again, only when forced to do so (e.g. by long press on the gui or when selected by hardware key) bool callEndAndStartSequences; - if ((scene_name == get_currentScene()) && ((isForcePayload != "FORCE") && (additionalPayload != "FORCE"))) { + if ((scene_name == gui_memoryOptimizer_getActiveSceneName()) && ((isForcePayload != "FORCE") && (additionalPayload != "FORCE"))) { Serial.printf("scene: will not start scene again, because it is already active\r\n"); callEndAndStartSequences = false; - } else if ((scene_name == get_currentScene()) && ((isForcePayload == "FORCE") || (additionalPayload == "FORCE"))) { + } else if ((scene_name == gui_memoryOptimizer_getActiveSceneName()) && ((isForcePayload == "FORCE") || (additionalPayload == "FORCE"))) { Serial.printf("scene: scene is already active, but FORCE was set, so start scene again\r\n"); callEndAndStartSequences = true; } else { @@ -78,13 +83,13 @@ void handleScene(uint16_t command, commandData commandData, std::string addition if (callEndAndStartSequences) { // end old scene - if (!sceneExists(get_currentScene()) && (get_currentScene() != "")) { - Serial.printf("scene: WARNING: cannot end scene %s, because it is unknown\r\n", get_currentScene().c_str()); + if (!sceneExists(gui_memoryOptimizer_getActiveSceneName()) && (gui_memoryOptimizer_getActiveSceneName() != "")) { + Serial.printf("scene: WARNING: cannot end scene %s, because it is unknown\r\n", gui_memoryOptimizer_getActiveSceneName().c_str()); } else { - if (get_currentScene() != "") { - Serial.printf("scene: will call end sequence for scene %s\r\n", get_currentScene().c_str()); - scene_end_sequence_from_registry(get_currentScene()); + if (gui_memoryOptimizer_getActiveSceneName() != "") { + Serial.printf("scene: will call end sequence for scene %s\r\n", gui_memoryOptimizer_getActiveSceneName().c_str()); + scene_end_sequence_from_registry(gui_memoryOptimizer_getActiveSceneName()); } } @@ -94,19 +99,12 @@ void handleScene(uint16_t command, commandData commandData, std::string addition scene_start_sequence_from_registry(scene_name); } - set_currentScene(scene_name); + gui_memoryOptimizer_setActiveSceneName(scene_name); - if (SceneLabel != NULL) {lv_label_set_text(SceneLabel, get_currentScene().c_str());} + if (SceneLabel != NULL) {lv_label_set_text(SceneLabel, gui_memoryOptimizer_getActiveSceneName().c_str());} - Serial.printf("scene: scene handling finished, new scene %s is active\r\n", get_currentScene().c_str()); + Serial.printf("scene: scene handling finished, new scene %s is active\r\n", gui_memoryOptimizer_getActiveSceneName().c_str()); - useSceneGUIlist = true; - // recreate the gui based on the current scene - guis_doAfterSliding(-1, -1, true); + guis_doTabCreationAfterGUIlistChanged(SCENE_GUI_LIST); } -void setLabelCurrentScene() { - if ((SceneLabel != NULL) && sceneExists(get_currentScene())) { - lv_label_set_text(SceneLabel, get_currentScene().c_str()); - } -} diff --git a/Platformio/src/applicationInternal/scenes/sceneHandler.h b/Platformio/src/applicationInternal/scenes/sceneHandler.h index 16c6c7b..ef2e217 100644 --- a/Platformio/src/applicationInternal/scenes/sceneHandler.h +++ b/Platformio/src/applicationInternal/scenes/sceneHandler.h @@ -3,5 +3,5 @@ #include #include "applicationInternal/commandHandler.h" +void setLabelActiveScene(); void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = ""); -void setLabelCurrentScene(); diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp index c1be9d8..50162ec 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp @@ -1,16 +1,12 @@ #include #include -#include "applicationInternal/commandHandler.h" -#include "applicationInternal/scenes/sceneRegistry.h" +#include "applicationInternal/gui/guiMemoryOptimizer.h" #include "applicationInternal/hardware/hardwarePresenter.h" +#include "applicationInternal/scenes/sceneRegistry.h" +#include "applicationInternal/commandHandler.h" // scenes #include "scenes/scene__default.h" -// If useSceneGUIlist == true, then a scene is active and we are not in the main_gui_list (with the scene selector as first gui). -// In that case, we try to use the scene specific gui list, if the scene defined one. -// If useSceneGUIlist == false, then we are in the main_gui_list, either if a scene is active or not. -bool useSceneGUIlist = false; - // https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work struct scene_definition { scene_setKeys this_scene_setKeys; @@ -90,7 +86,7 @@ void scene_end_sequence_from_registry(std::string sceneName) { repeatModes get_key_repeatMode(std::string sceneName, char keyChar) { try { - // look if the map of the current scene has a definition for it + // look if the map of the active scene has a definition for it if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_repeatModes->count(keyChar) > 0)) { // Serial.printf("get_key_repeatMode: will use key from scene %s\r\n", sceneName.c_str()); return registered_scenes.at(sceneName).this_key_repeatModes->at(keyChar); @@ -114,7 +110,7 @@ repeatModes get_key_repeatMode(std::string sceneName, char keyChar) { uint16_t get_command_short(std::string sceneName, char keyChar) { try { - // look if the map of the current scene has a definition for it + // look if the map of the active scene has a definition for it if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_commands_short->count(keyChar) > 0)) { // Serial.printf("get_command_short: will use key from scene %s\r\n", sceneName.c_str()); return registered_scenes.at(sceneName).this_key_commands_short->at(keyChar); @@ -139,7 +135,7 @@ uint16_t get_command_short(std::string sceneName, char keyChar) { uint16_t get_command_long(std::string sceneName, char keyChar) { try { - // look if the map of the current scene has a definition for it + // look if the map of the active scene has a definition for it if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_commands_long->count(keyChar) > 0)) { // Serial.printf("get_command_long: will use key from scene %s\r\n", sceneName.c_str()); return registered_scenes.at(sceneName).this_key_commands_long->at(keyChar); @@ -162,40 +158,44 @@ uint16_t get_command_long(std::string sceneName, char keyChar) { } -gui_list get_gui_list(std::string sceneName) { +gui_list get_gui_list(GUIlists gui_list) { try { - // If useSceneGUIlist == true, then a scene is active and we are not in the main_gui_list (with the scene selector as first gui). + // If gui_list == MAIN_GUI_LIST, then we are in the main_gui_list, either if a scene is active or not. + // If gui_list == SCENE_GUI_LIST, then a scene is active and we are not in the main_gui_list (with the scene selector as first gui). // In that case, we try to use the scene specific gui list, if the scene defined one. - // If useSceneGUIlist == false, then we are in the main_gui_list, either if a scene is active or not. - #if (USE_SCENE_SPECIFIC_GUI_LIST != 0) - // look if the current scene has a definition for a gui list - if (useSceneGUIlist && - (registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_gui_list != NULL)) { - // Serial.printf("get_gui_list: will use gui_list from scene %s\r\n", sceneName.c_str()); - return registered_scenes.at(sceneName).this_gui_list; - - // if there is no scene specific gui list, simply return the main_gui_list - } else { - // Serial.printf("get_gui_list: will use main_gui_list\r\n"); + if (gui_list == MAIN_GUI_LIST) { return &main_gui_list; - - } - #else - // never use scene specific gui list - return &main_gui_list; - #endif + + } else { + #if (USE_SCENE_SPECIFIC_GUI_LIST != 0) + // look if the active scene has a definition for a gui list + if ((registered_scenes.count(gui_memoryOptimizer_getActiveSceneName()) > 0) && (registered_scenes.at(gui_memoryOptimizer_getActiveSceneName()).this_gui_list != NULL)) { + // Serial.printf("get_gui_list: will use gui_list from scene %s\r\n", sceneName.c_str()); + return registered_scenes.at(gui_memoryOptimizer_getActiveSceneName()).this_gui_list; + } else { + // no scene specific gui list was defined + return &main_gui_list; + } + #else + // never use scene specific gui list + return &main_gui_list; + #endif + } } catch (const std::out_of_range& oor) { Serial.printf("get_gui_list: internal error, sceneName not registered\r\n"); return NULL; } +} +gui_list get_gui_list_active() { + return get_gui_list(gui_memoryOptimizer_getActiveGUIlist()); } uint16_t get_activate_scene_command(std::string sceneName) { try { - // look if the current scene is known + // look if the active scene is known if ((registered_scenes.count(sceneName) > 0)) { // Serial.printf("get_activate_scene_command: will use activate_scene_command from scene %s\r\n", sceneName.c_str()); return registered_scenes.at(sceneName).this_activate_scene_command; diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.h b/Platformio/src/applicationInternal/scenes/sceneRegistry.h index dbc8f56..beb045a 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.h +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.h @@ -6,8 +6,6 @@ #include #include "applicationInternal/keys.h" -extern bool useSceneGUIlist; - typedef std::vector t_gui_list; typedef std::vector t_scene_list; @@ -37,7 +35,7 @@ void scene_end_sequence_from_registry(std::string sceneName); repeatModes get_key_repeatMode(std::string sceneName, char keyChar); uint16_t get_command_short(std::string sceneName, char keyChar); uint16_t get_command_long(std::string sceneName, char keyChar); -gui_list get_gui_list(std::string sceneName); +gui_list get_gui_list_active(); uint16_t get_activate_scene_command(std::string sceneName); scene_list get_scenes_on_sceneSelectionGUI(); void set_scenes_on_sceneSelectionGUI(t_scene_list a_scene_list); diff --git a/Platformio/src/guis/gui_numpad.cpp b/Platformio/src/guis/gui_numpad.cpp index 6bb2e96..a853ffa 100644 --- a/Platformio/src/guis/gui_numpad.cpp +++ b/Platformio/src/guis/gui_numpad.cpp @@ -18,12 +18,12 @@ static void virtualKeypad_event_cb(lv_event_t* e) { int user_data = (intptr_t)(target->user_data); // send corrensponding number - if (get_currentScene() == scene_name_TV) { + if (gui_memoryOptimizer_getActiveSceneName() == scene_name_TV) { uint16_t virtualKeyMapTVNumbers[10] = {SAMSUNG_NUM_1, SAMSUNG_NUM_2, SAMSUNG_NUM_3, SAMSUNG_NUM_4, SAMSUNG_NUM_5, SAMSUNG_NUM_6, SAMSUNG_NUM_7, SAMSUNG_NUM_8, SAMSUNG_NUM_9, SAMSUNG_NUM_0}; uint16_t command = virtualKeyMapTVNumbers[user_data]; executeCommand(command); - } else if (get_currentScene() == scene_name_fireTV) { + } else if (gui_memoryOptimizer_getActiveSceneName() == scene_name_fireTV) { int virtualKeyMapFireTVNumbers[10] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0}; int number = virtualKeyMapFireTVNumbers[user_data]; std::string numberStr = std::to_string(number); diff --git a/Platformio/src/main.cpp b/Platformio/src/main.cpp index 0515123..33ff548 100644 --- a/Platformio/src/main.cpp +++ b/Platformio/src/main.cpp @@ -125,7 +125,7 @@ int main(int argc, char *argv[]) { #endif // init GUI - will initialize tft, touch and lvgl init_gui(); - setLabelCurrentScene(); + setLabelActiveScene(); gui_loop(); // Run the LVGL UI once before the loop takes over // setup the Inertial Measurement Unit (IMU) for motion detection. Has to be after init_gui(), otherwise I2C will not work From d833827fabe18d79794b7f3f12430ab3e1c3d0cb Mon Sep 17 00:00:00 2001 From: KlausMu Date: Mon, 22 Apr 2024 17:12:47 +0200 Subject: [PATCH 2/6] navigate to specific GUI and back to last position in previous gui list --- .../ESP32/preferencesStorage_hal_esp32.cpp | 9 + .../ESP32/preferencesStorage_hal_esp32.h | 2 + .../preferencesStorage_hal_windows_linux.cpp | 10 +- .../preferencesStorage_hal_windows_linux.h | 2 + .../applicationInternal/commandHandler.cpp | 7 + .../src/applicationInternal/commandHandler.h | 1 + .../src/applicationInternal/gui/guiBase.cpp | 13 +- .../src/applicationInternal/gui/guiBase.h | 7 +- .../gui/guiMemoryOptimizer.cpp | 162 ++++++++++++++++-- .../gui/guiMemoryOptimizer.h | 2 + .../hardware/hardwarePresenter.cpp | 6 + .../hardware/hardwarePresenter.h | 2 + .../scenes/sceneHandler.cpp | 72 ++++++-- .../applicationInternal/scenes/sceneHandler.h | 1 + .../scenes/sceneRegistry.cpp | 17 +- .../scenes/sceneRegistry.h | 3 + .../misc/device_smarthome/gui_smarthome.cpp | 4 + .../misc/device_smarthome/gui_smarthome.h | 1 + Platformio/src/main.cpp | 21 +-- Platformio/src/scenes/scene_TV.cpp | 2 +- Platformio/src/scenes/scene__default.cpp | 16 +- Platformio/src/scenes/scene__default.h | 14 +- 22 files changed, 320 insertions(+), 54 deletions(-) diff --git a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp index 2577482..e60fe0d 100644 --- a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp +++ b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp @@ -7,6 +7,7 @@ Preferences preferences; std::string activeScene; std::string activeGUIname; int activeGUIlist; +int lastActiveGUIlistIndex; void init_preferences_HAL(void) { // Restore settings from internal flash memory @@ -21,6 +22,7 @@ void init_preferences_HAL(void) { activeScene = std::string(preferences.getString("currentScene").c_str()); activeGUIname = std::string(preferences.getString("currentGUIname").c_str()); activeGUIlist =(preferences.getInt("currentGUIlist")); + lastActiveGUIlistIndex = (preferences.getInt("lastActiveIndex")); // Serial.printf("Preferences restored: brightness %d, GUI %s, scene %s\r\n", get_backlightBrightness_HAL(), get_activeGUIname().c_str(), get_activeScene().c_str()); } else { @@ -40,6 +42,7 @@ void save_preferences_HAL(void) { preferences.putString("currentScene", activeScene.c_str()); preferences.putString("currentGUIname", activeGUIname.c_str()); preferences.putInt("currentGUIlist", activeGUIlist); + preferences.putInt("lastActiveIndex", lastActiveGUIlistIndex); if (!preferences.getBool("alreadySetUp")) { preferences.putBool("alreadySetUp", true); } @@ -64,3 +67,9 @@ int get_activeGUIlist_HAL() { void set_activeGUIlist_HAL(int anActiveGUIlist) { activeGUIlist = anActiveGUIlist; } +int get_lastActiveGUIlistIndex_HAL() { + return lastActiveGUIlistIndex; +} +void set_lastActiveGUIlistIndex_HAL(int aGUIlistIndex) { + lastActiveGUIlistIndex = aGUIlistIndex; +} diff --git a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h index 9f4d98e..e223648 100644 --- a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h +++ b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h @@ -11,3 +11,5 @@ std::string get_activeGUIname_HAL(); void set_activeGUIname_HAL(std::string anActiveGUIname); int get_activeGUIlist_HAL(); void set_activeGUIlist_HAL(int anActiveGUIlist); +int get_lastActiveGUIlistIndex_HAL(); +void set_lastActiveGUIlistIndex_HAL(int aGUIlistIndex); diff --git a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp index 5d45c89..be907c2 100644 --- a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp +++ b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp @@ -20,12 +20,14 @@ main_gui_list : "Scene selection", "Smart Home", "Settings", "IR Receiver"}; std::string activeScene; std::string activeGUIname; int activeGUIlist; +int lastActiveGUIlistIndex; void init_preferences_HAL(void) { // set some values for tests activeScene = ""; // "Off", "TV", "Fire TV", "Chromecast", "Apple TV"; activeGUIname = ""; // "Scene selection", "Smart Home", "Settings", "IR Receiver" // "Numpad", "Apple TV" - activeGUIlist = MAIN_GUI_LIST; // // MAIN_GUI_LIST, SCENE_GUI_LIST; + activeGUIlist = MAIN_GUI_LIST; // MAIN_GUI_LIST, SCENE_GUI_LIST; + lastActiveGUIlistIndex = 0; } void save_preferences_HAL(void) { } @@ -48,3 +50,9 @@ int get_activeGUIlist_HAL() { void set_activeGUIlist_HAL(int anActiveGUIlist) { activeGUIlist = anActiveGUIlist; } +int get_lastActiveGUIlistIndex_HAL() { + return lastActiveGUIlistIndex; +} +void set_lastActiveGUIlistIndex_HAL(int aGUIlistIndex) { + lastActiveGUIlistIndex = aGUIlistIndex; +} diff --git a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h index 9f4d98e..e223648 100644 --- a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h +++ b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h @@ -11,3 +11,5 @@ std::string get_activeGUIname_HAL(); void set_activeGUIname_HAL(std::string anActiveGUIname); int get_activeGUIlist_HAL(); void set_activeGUIlist_HAL(int anActiveGUIlist); +int get_lastActiveGUIlistIndex_HAL(); +void set_lastActiveGUIlistIndex_HAL(int aGUIlistIndex); diff --git a/Platformio/src/applicationInternal/commandHandler.cpp b/Platformio/src/applicationInternal/commandHandler.cpp index a9924b5..e158343 100644 --- a/Platformio/src/applicationInternal/commandHandler.cpp +++ b/Platformio/src/applicationInternal/commandHandler.cpp @@ -232,6 +232,13 @@ void executeCommandWithData(uint16_t command, commandData commandData, std::stri break; } + case GUI: { + // let the sceneHandler find and show the gui + Serial.printf("execute: will send gui command to the sceneHandler\r\n"); + handleGUI(command, commandData, additionalPayload); + break; + } + case SPECIAL: { if (command == MY_SPECIAL_COMMAND) { // do your special command here diff --git a/Platformio/src/applicationInternal/commandHandler.h b/Platformio/src/applicationInternal/commandHandler.h index 75b0a6b..29bd0d6 100644 --- a/Platformio/src/applicationInternal/commandHandler.h +++ b/Platformio/src/applicationInternal/commandHandler.h @@ -94,6 +94,7 @@ extern uint16_t KEYBOARD_VOLUME_DECREMENT; enum commandHandlers { SPECIAL, SCENE, + GUI, IR, #if (ENABLE_WIFI_AND_MQTT == 1) MQTT, diff --git a/Platformio/src/applicationInternal/gui/guiBase.cpp b/Platformio/src/applicationInternal/gui/guiBase.cpp index c8e9f86..dac2306 100644 --- a/Platformio/src/applicationInternal/gui/guiBase.cpp +++ b/Platformio/src/applicationInternal/gui/guiBase.cpp @@ -265,6 +265,7 @@ void init_gui_status_bar() { lv_obj_align(SceneLabel, LV_ALIGN_TOP_MID, 0, labelsPositionTopStatusbar); lv_obj_set_style_text_font(SceneLabel, &lv_font_montserrat_12, LV_PART_MAIN); lv_obj_add_flag(SceneLabel, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_user_data(SceneLabel,(void *)(intptr_t)0); lv_obj_add_event_cb(SceneLabel, sceneLabel_or_pageIndicator_event_cb, LV_EVENT_CLICKED, NULL); // Battery ---------------------------------------------------------------------- @@ -304,7 +305,6 @@ void gui_loop(void) { // There are several reasons why the tabs could get recreated. All are going through these functions in "guiBase.cpp", which are calling functions in "guiMemoryOptimizer.cpp" // 1. tab creation on startup (called by init_gui()) void guis_doTabCreationOnStartup() { - Serial.printf("Startup: try to resume at scene \"%s\" with GUI \"%s\"\r\n", gui_memoryOptimizer_getActiveSceneName().c_str(), gui_memoryOptimizer_getActiveGUIname().c_str()); gui_memoryOptimizer_onStartup(&tabview, &panel, &img1, &img2); doLogMemoryUsage(); } @@ -318,6 +318,17 @@ void guis_doTabCreationAfterGUIlistChanged(GUIlists newGUIlist) { gui_memoryOptimizer_afterGUIlistChanged(&tabview, &panel, &img1, &img2, newGUIlist); doLogMemoryUsage(); } +// 4. navigate to a specific GUI in gui_list +void guis_doTabCreationForSpecificGUI(GUIlists GUIlist, int gui_list_index) { + gui_memoryOptimizer_navigateToGUI(&tabview, &panel, &img1, &img2, GUIlist, gui_list_index); + doLogMemoryUsage(); +} +// 5. navigate back to last active gui of previous gui_list +void guis_doTabCreationForNavigateToLastActiveGUIofPreviousGUIlist() { + gui_memoryOptimizer_navigateToLastActiveGUIofPreviousGUIlist(&tabview, &panel, &img1, &img2); + doLogMemoryUsage(); +} + // ------------------------------------------------------------------------------------------------------------ void setActiveTab(uint32_t index, lv_anim_enable_t anim_en, bool send_tab_changed_event) { diff --git a/Platformio/src/applicationInternal/gui/guiBase.h b/Platformio/src/applicationInternal/gui/guiBase.h index 2a8c2a0..ffaade2 100644 --- a/Platformio/src/applicationInternal/gui/guiBase.h +++ b/Platformio/src/applicationInternal/gui/guiBase.h @@ -24,15 +24,20 @@ extern lv_color_t color_primary; extern lv_style_t style_red_border; #endif -// used by main.cpp and sceneHandler.cpp +// used by main.cpp void init_gui(void); +// used by main.cpp and sceneHandler.cpp void gui_loop(void); // used by guiMemoryOptimizer.cpp void tabview_content_is_scrolling_event_cb(lv_event_t* e); void tabview_tab_changed_event_cb(lv_event_t* e); void sceneLabel_or_pageIndicator_event_cb(lv_event_t* e); void pageIndicator_navigate_event_cb(lv_event_t* e); +// used by sceneHandler.cpp void guis_doTabCreationAfterGUIlistChanged(GUIlists newGUIlist); +void guis_doTabCreationForSpecificGUI(GUIlists GUIlist, int gui_list_index); +void guis_doTabCreationForNavigateToLastActiveGUIofPreviousGUIlist(); +// used by guiMemoryOptimizer.cpp and sceneHandler.cpp void setActiveTab(uint32_t index, lv_anim_enable_t anim_en, bool send_tab_changed_event = false); // used by memoryUsage.cpp void showMemoryUsageBar(bool showBar); diff --git a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp index e3a1643..718377b 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp @@ -12,7 +12,7 @@ struct t_gui_on_tab { int gui_list_index_previous; }; struct t_gui_state { - // the next three are saved in the preferenceStorage every time they change + // the next three and the last are saved in the preferenceStorage every time they change std::string activeScene_internalDontUse; std::string activeGUIname_internalDontUse; GUIlists activeGUIlist_internalDontUse; @@ -20,6 +20,9 @@ struct t_gui_state { int activeTabID = -1; // id of the active tab (one of 0,1,2) int oldTabID = -1; // id of the tab before swiping (one of 0,1,2) t_gui_on_tab gui_on_tab[3] = {{NULL, "", -1, -1}, {NULL, "", -1, -1}, {NULL, "", -1, -1}}; + // the last active gui of scene. Will be stored to easily navigate back to it with guis_doTabCreationForNavigateToLastActiveGUIofPreviousGUIlist() + GUIlists last_active_gui_list = (GUIlists)-1; + int last_active_gui_list_index_internalDontUse = -1; }; t_gui_state gui_state; @@ -51,6 +54,14 @@ void gui_memoryOptimizer_setActiveGUIlist(GUIlists aGUIlist) { gui_state.activeGUIlist_internalDontUse = aGUIlist; set_activeGUIlist(aGUIlist); } +int gui_memoryOptimizer_getLastActiveGUIlistIndex() { + gui_state.last_active_gui_list_index_internalDontUse = get_lastActiveGUIlistIndex(); + return gui_state.last_active_gui_list_index_internalDontUse; +} +void gui_memoryOptimizer_setLastActiveGUIlistIndex(int aGUIlistIndex) { + gui_state.last_active_gui_list_index_internalDontUse = aGUIlistIndex; + set_lastActiveGUIlistIndex(aGUIlistIndex); +} int gui_memoryOptimizer_getActiveTabID() { return gui_state.activeTabID; @@ -349,10 +360,28 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); } - uint8_t breadcrumpLength = get_gui_list_active()->size(); - uint8_t breadcrumpDotSize = 8; // should be an even number + uint8_t breadcrumpDotSize = 8; // should be an even number uint8_t breadcrumpDotDistance = 2; // should be an even number - int8_t breadcrumpStartPositionX = (-1) * (breadcrumpLength -1) * (breadcrumpDotSize + breadcrumpDotDistance) / 2; + uint8_t breadcrumpMainGuiListLength = get_gui_list(MAIN_GUI_LIST)->size(); + int8_t breadcrumpMainGuiListStartPositionX = (-1) * (breadcrumpMainGuiListLength -1) * (breadcrumpDotSize + breadcrumpDotDistance) / 2; + uint8_t breadcrumpSceneGuiListLength = get_gui_list(SCENE_GUI_LIST)->size(); + int8_t breadcrumpSceneGuiListStartPositionX = (-1) * (breadcrumpSceneGuiListLength -1) * (breadcrumpDotSize + breadcrumpDotDistance) / 2; + #if (USE_SCENE_SPECIFIC_GUI_LIST != 0) + bool show_scene_gui_list = get_scene_has_gui_list(gui_memoryOptimizer_getActiveSceneName()); + #else + bool show_scene_gui_list = false; + #endif + int8_t breadcrumpMainGuiList_yPos; + int8_t breadcrumpSceneGuiList_yPos; + int8_t nameOfGUI_yPos; + if (!show_scene_gui_list) { + breadcrumpMainGuiList_yPos = -6; + nameOfGUI_yPos = 6; + } else { + breadcrumpMainGuiList_yPos = -8; + breadcrumpSceneGuiList_yPos = -1; + nameOfGUI_yPos = 8; + } // create the panel content for the three guis (or less) which are currently in memory std::string nameOfGUI; @@ -364,9 +393,10 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv // Create actual buttons for every tab lv_obj_t* btn = lv_btn_create(panel); - // only if this is the button for the currently active tab, make it clickable to get to scene selection gui if (nameOfGUI == gui_memoryOptimizer_getActiveGUIname()) { + // only if this is the button for the currently active tab, make it clickable to get to scene selection gui lv_obj_add_flag(btn, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_user_data(btn,(void *)(intptr_t)2); lv_obj_add_event_cb(btn, sceneLabel_or_pageIndicator_event_cb, LV_EVENT_CLICKED, NULL); } else if ((i==0 || i==1) && (gui_state->gui_on_tab[i+1].gui_list_index != -1)) { @@ -389,28 +419,63 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); - // create a breadcrump dot for each gui in the list - for (int j=0; j= 0) && (gui_list_index < get_gui_list(GUIlist)->size()))) { + Serial.printf(" cannot navigate to GUI because gui_list_index \"%d\" is out of range\r\n", gui_list_index); + return; + } + + if (gui_state.last_active_gui_list != GUIlist) { + // we are changing the gui_list, so save the last_active_gui_list_index + gui_memoryOptimizer_setLastActiveGUIlistIndex(gui_state.gui_on_tab[gui_state.activeTabID].gui_list_index); + } + + // 1. notify old guis and clear tabview and panel + gui_memoryOptimizer_notifyAndClear(tabview, panel, img1, img2, &gui_state); + + // 2. set gui_list_indices and the tab to be activated + gui_memoryOptimizer_setActiveGUIlist(GUIlist); + setGUIlistIndicesToBeShown_forSpecificGUIlistIndex(gui_list_index, &gui_state); + + // 3. create content + gui_memoryOptimizer_doContentCreation(tabview, panel, img1, img2, &gui_state); + +} + +// 5. navigate back to last gui in scene +void gui_memoryOptimizer_navigateToLastActiveGUIofPreviousGUIlist(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2) { + + #if (USE_SCENE_SPECIFIC_GUI_LIST == 0) + Serial.printf("--- Cannot navigate to last GUI from scene, because scene specific gui lists are not enabled\r\n"); + return; + #endif + + if (gui_memoryOptimizer_getLastActiveGUIlistIndex() == -1) { + Serial.printf("--- Cannot navigate to last GUI from scene, because it is not set\r\n"); + return; + } else { + Serial.printf("--- Will navigate to last GUI from scene\r\n"); + } + + // navigate to the other gui_list + if (gui_memoryOptimizer_getActiveGUIlist() == MAIN_GUI_LIST) { + gui_memoryOptimizer_navigateToGUI(tabview, panel, img1, img2, SCENE_GUI_LIST, gui_memoryOptimizer_getLastActiveGUIlistIndex()); + } else { + gui_memoryOptimizer_navigateToGUI(tabview, panel, img1, img2, MAIN_GUI_LIST, gui_memoryOptimizer_getLastActiveGUIlistIndex()); + } + +} + + void gui_memoryOptimizer_doContentCreation(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, t_gui_state *gui_state) { // recreate the tabview lv_obj_t* newTabview = create_tabview(); @@ -586,6 +715,11 @@ void gui_memoryOptimizer_doContentCreation(lv_obj_t** tabview, lv_obj_t** panel, // Initialize scroll position of the page indicator lv_event_send(lv_tabview_get_content(*tabview), LV_EVENT_SCROLL, NULL); + // gui_memoryOptimizer_doContentCreation() is called as last step every time the 3 tabs are recreated. + // Save here the last_active_gui_list. If the used list changes in a future navigation, save the last_active_gui_list_index + // so that we can use SCENE_BACK_TO_PREVIOUS_GUI_LIST + gui_state->last_active_gui_list = gui_memoryOptimizer_getActiveGUIlist(); + Serial.printf("------------ End of tab deletion and creation\r\n"); } diff --git a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h index 47ec812..f163c54 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h @@ -12,6 +12,8 @@ enum GUIlists { void gui_memoryOptimizer_onStartup(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2); void gui_memoryOptimizer_afterSliding(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, int newTabID); void gui_memoryOptimizer_afterGUIlistChanged(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, GUIlists newGUIlist); +void gui_memoryOptimizer_navigateToGUI(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, GUIlists GUIlist, int gui_list_index); +void gui_memoryOptimizer_navigateToLastActiveGUIofPreviousGUIlist(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2); int gui_memoryOptimizer_getActiveTabID(); bool gui_memoryOptimizer_isTabIDInMemory(int tabID); diff --git a/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp b/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp index 4a78631..fff5de7 100644 --- a/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp +++ b/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp @@ -44,6 +44,12 @@ int get_activeGUIlist() { void set_activeGUIlist(int anActiveGUIlist) { set_activeGUIlist_HAL(anActiveGUIlist); } +int get_lastActiveGUIlistIndex() { + return get_lastActiveGUIlistIndex_HAL(); +} +void set_lastActiveGUIlistIndex(int aGUIlistIndex) { + set_lastActiveGUIlistIndex_HAL(aGUIlistIndex); +} // --- user led --------------------------------------------------------------- void init_userled(void) { diff --git a/Platformio/src/applicationInternal/hardware/hardwarePresenter.h b/Platformio/src/applicationInternal/hardware/hardwarePresenter.h index f01111e..74c8e48 100644 --- a/Platformio/src/applicationInternal/hardware/hardwarePresenter.h +++ b/Platformio/src/applicationInternal/hardware/hardwarePresenter.h @@ -16,6 +16,8 @@ std::string get_activeGUIname(); void set_activeGUIname(std::string anActiveGUIname); int get_activeGUIlist(); void set_activeGUIlist(int anActiveGUIlist); +int get_lastActiveGUIlistIndex(); +void set_lastActiveGUIlistIndex(int aGUIlistIndex); // --- user led --------------------------------------------------------------- void init_userled(void); diff --git a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp index fc0f4aa..8ea033c 100644 --- a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp @@ -13,29 +13,21 @@ void setLabelActiveScene() { } } -void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = "") { +void navigateBackToSceneGUIlist(); - // FORCE can be either as second payload in commandData - // e.g. register_command(&SCENE_TV_FORCE , makeCommandData(SCENE, {scene_name_TV, "FORCE"})); - // or as additionalPayload, used by gui_sceneSelection.cpp - // e.g. executeCommand(activate_scene_command, "FORCE"); +void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = "") { auto current = commandData.commandPayloads.begin(); std::string scene_name = *current; - // we can have a second payload - std::string isForcePayload = ""; - ++current; - if (current != commandData.commandPayloads.end()) { - isForcePayload = *current; - } - // do not really switch scene, but show sceneSelection gui. From that on, we are in the main_gui_list. + // --- do not switch scene, but show scene selection gui. From that on, we are in the main_gui_list. ---------------- if (scene_name == scene_name_selection) { + Serial.println("scene: will show scene selection gui"); guis_doTabCreationAfterGUIlistChanged(MAIN_GUI_LIST); return; } - // do not switch scene, but navigate to the prev or next gui in the currently active list of guis + // --- do not switch scene, but navigate to the prev or next gui in the currently active list of guis --------------- if ((scene_name == scene_gui_next) || (scene_name == scene_gui_prev)) { if (scene_name == scene_gui_prev) { if (gui_memoryOptimizer_getActiveTabID() == 0) { @@ -57,6 +49,33 @@ void handleScene(uint16_t command, commandData commandData, std::string addition return; } + // --- do not switch scene. Switch to the other gui list ------------------------------------------------------------ + if (scene_name == scene_back_to_previous_gui_list) { + + if (get_scene_has_gui_list(gui_memoryOptimizer_getActiveSceneName())) { + Serial.println("scene: will navigate back to last active gui from previous gui list"); + guis_doTabCreationForNavigateToLastActiveGUIofPreviousGUIlist(); + } else { + Serial.println("scene: cannot navigate back to last active gui from previous gui list, because no scene specific gui list was defined"); + } + + return; + } + + // --- This is the normal case. We navigate to a new scene ---------------------------------------------------------- + + // FORCE can be either as second payload in commandData + // e.g. register_command(&SCENE_TV_FORCE , makeCommandData(SCENE, {scene_name_TV, "FORCE"})); + // or as additionalPayload, used by gui_sceneSelection.cpp + // e.g. executeCommand(activate_scene_command, "FORCE"); + + // we can have a second payload + std::string isForcePayload = ""; + ++current; + if (current != commandData.commandPayloads.end()) { + isForcePayload = *current; + } + // check if we know the new scene if (!sceneExists(scene_name)) { Serial.printf("scene: cannot start scene %s, because it is unknown\r\n", scene_name.c_str()); @@ -108,3 +127,30 @@ void handleScene(uint16_t command, commandData commandData, std::string addition guis_doTabCreationAfterGUIlistChanged(SCENE_GUI_LIST); } +void handleGUI(uint16_t command, commandData commandData, std::string additionalPayload = "") { + + auto current = commandData.commandPayloads.begin(); + std::string GUIname = *current; + + // 1. check if the gui is known in the main_gui_list + int gui_list_index = -1; + // find index of gui_memoryOptimizer_getActiveGUIname() in gui_list_active + for (int i=0; i < main_gui_list.size(); i++) { + if (main_gui_list.at(i) == GUIname) { + Serial.printf("handleGUI: found GUI with name \"%s\" in \"main_gui_list\" at position %d\r\n", GUIname.c_str(), i); + gui_list_index = i; + break; + } + } + + // 2. call guiBase.cpp + if ((gui_list_index >= 0) && (gui_list_index < main_gui_list.size())) { + guis_doTabCreationForSpecificGUI(MAIN_GUI_LIST, gui_list_index); + + } else { + // gui was not found + Serial.printf("handleGUI: GUI with name \"%s\" was not found. Cannot navigate to that GUI\r\n", GUIname.c_str()); + return; + } + +} diff --git a/Platformio/src/applicationInternal/scenes/sceneHandler.h b/Platformio/src/applicationInternal/scenes/sceneHandler.h index ef2e217..5aba73d 100644 --- a/Platformio/src/applicationInternal/scenes/sceneHandler.h +++ b/Platformio/src/applicationInternal/scenes/sceneHandler.h @@ -5,3 +5,4 @@ void setLabelActiveScene(); void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = ""); +void handleGUI (uint16_t command, commandData commandData, std::string additionalPayload = ""); diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp index 50162ec..ceec140 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp @@ -195,7 +195,7 @@ gui_list get_gui_list_active() { uint16_t get_activate_scene_command(std::string sceneName) { try { - // look if the active scene is known + // look if the scene is known if ((registered_scenes.count(sceneName) > 0)) { // Serial.printf("get_activate_scene_command: will use activate_scene_command from scene %s\r\n", sceneName.c_str()); return registered_scenes.at(sceneName).this_activate_scene_command; @@ -214,6 +214,21 @@ uint16_t get_activate_scene_command(std::string sceneName) { } +bool get_scene_has_gui_list(std::string sceneName) { + try { + // look if the scene is known + if ((registered_scenes.count(sceneName) > 0)) { + return (registered_scenes.at(sceneName).this_gui_list != NULL); + } else { + return false; + } + } + catch (const std::out_of_range& oor) { + Serial.printf("get_scene_has_gui_list: internal error, sceneName not registered\r\n"); + return false; + } +} + scene_list get_scenes_on_sceneSelectionGUI() { return &scenes_on_sceneSelectionGUI; } diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.h b/Platformio/src/applicationInternal/scenes/sceneRegistry.h index beb045a..05ebfbf 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.h +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.h @@ -5,6 +5,7 @@ #include #include #include "applicationInternal/keys.h" +#include "applicationInternal/gui/guiMemoryOptimizer.h" typedef std::vector t_gui_list; typedef std::vector t_scene_list; @@ -35,8 +36,10 @@ void scene_end_sequence_from_registry(std::string sceneName); repeatModes get_key_repeatMode(std::string sceneName, char keyChar); uint16_t get_command_short(std::string sceneName, char keyChar); uint16_t get_command_long(std::string sceneName, char keyChar); +gui_list get_gui_list(GUIlists gui_list); gui_list get_gui_list_active(); uint16_t get_activate_scene_command(std::string sceneName); +bool get_scene_has_gui_list(std::string sceneName); scene_list get_scenes_on_sceneSelectionGUI(); void set_scenes_on_sceneSelectionGUI(t_scene_list a_scene_list); diff --git a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp index 4ddc7cc..4cc1e13 100644 --- a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp +++ b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp @@ -20,6 +20,8 @@ static bool lightToggleBstate = false; static int32_t sliderAvalue = 0; static int32_t sliderBvalue = 0; +uint16_t GUI_SMARTHOME_ACTIVATE; + // Smart Home Toggle Event handler static void smartHomeToggle_event_cb(lv_event_t* e){ std::string payload; @@ -160,4 +162,6 @@ void notify_tab_before_delete_smarthome(void) { void register_gui_smarthome(void){ register_gui(std::string(tabName_smarthome), & create_tab_content_smarthome, & notify_tab_before_delete_smarthome); + + register_command(&GUI_SMARTHOME_ACTIVATE, makeCommandData(GUI, {std::string(tabName_smarthome)})); } diff --git a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.h b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.h index 26feb93..3c1a58c 100644 --- a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.h +++ b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.h @@ -3,4 +3,5 @@ #include const char * const tabName_smarthome = "Smart Home"; +extern uint16_t GUI_SMARTHOME_ACTIVATE; void register_gui_smarthome(void); diff --git a/Platformio/src/main.cpp b/Platformio/src/main.cpp index 33ff548..f6d9d41 100644 --- a/Platformio/src/main.cpp +++ b/Platformio/src/main.cpp @@ -102,16 +102,6 @@ int main(int argc, char *argv[]) { #endif register_keyboardCommands(); - // register the scenes and their key_commands_* - register_scene_defaultKeys(); - register_scene_TV(); - register_scene_fireTV(); - register_scene_chromecast(); - register_scene_appleTV(); - register_scene_allOff(); - // Only show these scenes on the sceneSelection gui. If you don't set this explicitely, by default all registered scenes are shown. - set_scenes_on_sceneSelectionGUI({scene_name_TV, scene_name_fireTV, scene_name_chromecast, scene_name_appleTV}); - // register the GUIs. They will be displayed in the order they have been registered. register_gui_sceneSelection(); register_gui_irReceiver(); @@ -123,6 +113,17 @@ int main(int argc, char *argv[]) { #if (USE_SCENE_SPECIFIC_GUI_LIST != 0) main_gui_list = {tabName_sceneSelection, tabName_smarthome, tabName_settings, tabName_irReceiver}; #endif + + // register the scenes and their key_commands_* + register_scene_defaultKeys(); + register_scene_TV(); + register_scene_fireTV(); + register_scene_chromecast(); + register_scene_appleTV(); + register_scene_allOff(); + // Only show these scenes on the sceneSelection gui. If you don't set this explicitely, by default all registered scenes are shown. + set_scenes_on_sceneSelectionGUI({scene_name_TV, scene_name_fireTV, scene_name_chromecast, scene_name_appleTV}); + // init GUI - will initialize tft, touch and lvgl init_gui(); setLabelActiveScene(); diff --git a/Platformio/src/scenes/scene_TV.cpp b/Platformio/src/scenes/scene_TV.cpp index 7f74bb1..fecdcde 100644 --- a/Platformio/src/scenes/scene_TV.cpp +++ b/Platformio/src/scenes/scene_TV.cpp @@ -33,7 +33,7 @@ void scene_setKeys_TV() { key_commands_short_TV = { - {KEY_STOP, SAMSUNG_REWIND }, {KEY_REWI, SAMSUNG_PAUSE }, {KEY_PLAY, SAMSUNG_PLAY }, {KEY_FORW, SAMSUNG_FASTFORWARD}, + {KEY_STOP, SAMSUNG_PAUSE }, {KEY_REWI, SAMSUNG_REWIND }, {KEY_PLAY, SAMSUNG_PLAY }, {KEY_FORW, SAMSUNG_FASTFORWARD}, {KEY_CONF, SAMSUNG_GUIDE }, {KEY_INFO, SAMSUNG_MENU }, {KEY_UP, SAMSUNG_UP }, {KEY_LEFT, SAMSUNG_LEFT }, {KEY_OK, SAMSUNG_SELECT }, {KEY_RIGHT, SAMSUNG_RIGHT }, diff --git a/Platformio/src/scenes/scene__default.cpp b/Platformio/src/scenes/scene__default.cpp index 848aafe..c4b69dc 100644 --- a/Platformio/src/scenes/scene__default.cpp +++ b/Platformio/src/scenes/scene__default.cpp @@ -4,6 +4,7 @@ #include "applicationInternal/commandHandler.h" // devices #include "devices/AVreceiver/device_yamahaAmp/device_yamahaAmp.h" +#include "devices/misc/device_smarthome/gui_smarthome.h" // scenes #include "scene__default.h" #include "scenes/scene_allOff.h" @@ -14,9 +15,11 @@ uint16_t SCENE_SELECTION; std::string scene_name_selection = "sceneSelection"; +uint16_t SCENE_BACK_TO_PREVIOUS_GUI_LIST; +std::string scene_back_to_previous_gui_list = "backToPreviousList"; uint16_t GUI_PREV; -uint16_t GUI_NEXT; std::string scene_gui_prev = "GUI_prev"; +uint16_t GUI_NEXT; std::string scene_gui_next = "GUI_next"; std::map key_repeatModes_default; @@ -45,14 +48,14 @@ void register_scene_defaultKeys(void) { key_commands_short_default = { {KEY_OFF, SCENE_ALLOFF_FORCE}, - /*{KEY_STOP, COMMAND_UNKNOWN }, {KEY_REWI, COMMAND_UNKNOWN }, {KEY_PLAY, COMMAND_UNKNOWN }, {KEY_FORW, COMMAND_UNKNOWN },*/ + {KEY_STOP, GUI_SMARTHOME_ACTIVATE},/*{KEY_REWI, COMMAND_UNKNOWN }, {KEY_PLAY, COMMAND_UNKNOWN }, {KEY_FORW, COMMAND_UNKNOWN },*/ /*{KEY_CONF, COMMAND_UNKNOWN }, {KEY_INFO, COMMAND_UNKNOWN },*/ /* {KEY_UP, COMMAND_UNKNOWN },*/ {KEY_LEFT, GUI_PREV }, /* {KEY_OK, COMMAND_UNKNOWN },*/ {KEY_RIGHT, GUI_NEXT }, /* {KEY_DOWN, COMMAND_UNKNOWN },*/ {KEY_BACK, SCENE_SELECTION }, /*{KEY_SRC, COMMAND_UNKNOWN },*/ {KEY_VOLUP, YAMAHA_VOL_PLUS }, {KEY_MUTE, YAMAHA_MUTE_TOGGLE}, /*{KEY_CHUP, COMMAND_UNKNOWN },*/ - {KEY_VOLDO, YAMAHA_VOL_MINUS }, /* {KEY_REC, COMMAND_UNKNOWN },*/ /*{KEY_CHDOW, COMMAND_UNKNOWN },*/ + {KEY_VOLDO, YAMAHA_VOL_MINUS }, {KEY_REC, SCENE_BACK_TO_PREVIOUS_GUI_LIST }, /*{KEY_CHDOW, COMMAND_UNKNOWN },*/ {KEY_RED, SCENE_TV_FORCE }, {KEY_GREEN, SCENE_FIRETV_FORCE}, {KEY_YELLO, SCENE_CHROMECAST_FORCE},{KEY_BLUE, SCENE_APPLETV_FORCE}, }; @@ -61,8 +64,9 @@ void register_scene_defaultKeys(void) { }; - register_command(&SCENE_SELECTION, makeCommandData(SCENE, {scene_name_selection})); - register_command(&GUI_PREV , makeCommandData(SCENE, {scene_gui_prev})); - register_command(&GUI_NEXT , makeCommandData(SCENE, {scene_gui_next})); + register_command(&SCENE_SELECTION , makeCommandData(SCENE, {scene_name_selection})); + register_command(&SCENE_BACK_TO_PREVIOUS_GUI_LIST, makeCommandData(SCENE, {scene_back_to_previous_gui_list})); + register_command(&GUI_PREV , makeCommandData(SCENE, {scene_gui_prev})); + register_command(&GUI_NEXT , makeCommandData(SCENE, {scene_gui_next})); } diff --git a/Platformio/src/scenes/scene__default.h b/Platformio/src/scenes/scene__default.h index 7078a2f..00c1194 100644 --- a/Platformio/src/scenes/scene__default.h +++ b/Platformio/src/scenes/scene__default.h @@ -6,12 +6,14 @@ #include "applicationInternal/keys.h" #include "applicationInternal/scenes/sceneRegistry.h" -extern uint16_t SCENE_SELECTION; // command -extern std::string scene_name_selection; // payload: name of this fake default scene -extern uint16_t GUI_PREV; // command -extern uint16_t GUI_NEXT; // command -extern std::string scene_gui_prev; // payload: name of this fake scene -extern std::string scene_gui_next; // payload: name of this fake scene +extern uint16_t SCENE_SELECTION; // command +extern std::string scene_name_selection; // payload: name of this fake default scene +extern uint16_t SCENE_BACK_TO_PREVIOUS_GUI_LIST; // command +extern std::string scene_back_to_previous_gui_list; // payload: name of this fake scene +extern uint16_t GUI_PREV; // command +extern std::string scene_gui_prev; // payload: name of this fake scene +extern uint16_t GUI_NEXT; // command +extern std::string scene_gui_next; // payload: name of this fake scene extern std::map key_repeatModes_default; extern std::map key_commands_short_default; From 267e39bf934d38b053dd58045b7cc744ec7d8e1a Mon Sep 17 00:00:00 2001 From: KlausMu Date: Mon, 22 Apr 2024 21:52:48 +0200 Subject: [PATCH 3/6] allow gui specific key bindings --- .../applicationInternal/gui/guiRegistry.cpp | 31 ++++++++++++++-- .../src/applicationInternal/gui/guiRegistry.h | 18 ++++++++-- Platformio/src/applicationInternal/keys.h | 7 ++++ .../scenes/sceneRegistry.cpp | 35 ++++++++++++++++--- .../scenes/sceneRegistry.h | 5 --- .../misc/device_smarthome/gui_smarthome.cpp | 29 ++++++++++++--- Platformio/src/main.cpp | 3 +- 7 files changed, 108 insertions(+), 20 deletions(-) diff --git a/Platformio/src/applicationInternal/gui/guiRegistry.cpp b/Platformio/src/applicationInternal/gui/guiRegistry.cpp index 29acd28..b2c30fd 100644 --- a/Platformio/src/applicationInternal/gui/guiRegistry.cpp +++ b/Platformio/src/applicationInternal/gui/guiRegistry.cpp @@ -6,6 +6,7 @@ #include "guiRegistry.h" #include "applicationInternal/gui/guiBase.h" #include "applicationInternal/hardware/hardwarePresenter.h" +#include "applicationInternal/scenes/sceneRegistry.h" #include "scenes/scene__default.h" // ------------------------------------------------------------------------------------ @@ -15,14 +16,30 @@ std::map registered_guis_byName_map; // ------------------------------------------------------------------------------------ -void register_gui(std::string a_name, create_tab_content a_create_tab_content, notify_tab_before_delete a_notify_tab_before_delete) { +void register_gui( + std::string a_name, + create_tab_content a_create_tab_content, + notify_tab_before_delete a_notify_tab_before_delete, + gui_setKeys a_gui_setKeys, + key_repeatModes a_key_repeatModes, + key_commands_short a_key_commands_short, + key_commands_long a_key_commands_long + ) { if (registered_guis_byName_map.count(a_name) > 0) { Serial.printf("ERROR!!!: you cannot register two guis having the same name '%s'\r\n", a_name.c_str()); return; } - gui_definition new_gui_definition = gui_definition{a_name, a_create_tab_content, a_notify_tab_before_delete}; + gui_definition new_gui_definition = gui_definition{ + a_name, + a_create_tab_content, + a_notify_tab_before_delete, + a_gui_setKeys, + a_key_repeatModes, + a_key_commands_short, + a_key_commands_long + }; // put the gui_definition in a map that can be accessed by name registered_guis_byName_map[a_name] = new_gui_definition; @@ -31,4 +48,14 @@ void register_gui(std::string a_name, create_tab_content a_create_tab_content, n // Can be overwritten by scenes to have their own gui_list. main_gui_list.insert(main_gui_list.end(), {std::string(a_name)}); + // Whenever a new gui is registered, a new gui command could have been defined. + // But this new gui command could have been already been used before in the key definition of another gui. The command at this time was 0, which is undefined. + // So we have to set the keys again for all guis that have been registered before. + // Loop over all registered guis and call setKeys() + for (std::map::iterator it = registered_guis_byName_map.begin(); it != registered_guis_byName_map.end(); ++it) { + if (it->second.this_gui_setKeys != NULL) { + it->second.this_gui_setKeys(); + } + } + } diff --git a/Platformio/src/applicationInternal/gui/guiRegistry.h b/Platformio/src/applicationInternal/gui/guiRegistry.h index cbe541f..c4a6296 100644 --- a/Platformio/src/applicationInternal/gui/guiRegistry.h +++ b/Platformio/src/applicationInternal/gui/guiRegistry.h @@ -22,19 +22,31 @@ #include #include #include +#include "applicationInternal/keys.h" typedef void (*create_tab_content)(lv_obj_t* tab); typedef void (*notify_tab_before_delete)(void); +typedef void (*gui_setKeys)(void); // https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work struct gui_definition { std::string this_name; create_tab_content this_create_tab_content; notify_tab_before_delete this_notify_tab_before_delete; - uint32_t this_tabID; - lv_obj_t* this_tab; + gui_setKeys this_gui_setKeys; + key_repeatModes this_key_repeatModes; + key_commands_short this_key_commands_short; + key_commands_long this_key_commands_long; }; extern std::map registered_guis_byName_map; -void register_gui(std::string a_name, create_tab_content a_create_tab_content, notify_tab_before_delete a_notify_tab_before_delete); +void register_gui( + std::string a_name, + create_tab_content a_create_tab_content, + notify_tab_before_delete a_notify_tab_before_delete, + gui_setKeys a_gui_setKeys = NULL, + key_repeatModes a_key_repeatModes = NULL, + key_commands_short a_key_commands_short = NULL, + key_commands_long a_key_commands_long = NULL + ); diff --git a/Platformio/src/applicationInternal/keys.h b/Platformio/src/applicationInternal/keys.h index f38be73..f2004f5 100644 --- a/Platformio/src/applicationInternal/keys.h +++ b/Platformio/src/applicationInternal/keys.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + enum repeatModes { // only as fallback REPEAT_MODE_UNKNOWN, @@ -15,4 +18,8 @@ enum repeatModes { SHORTorLONG, }; +typedef std::map *key_repeatModes; +typedef std::map *key_commands_short; +typedef std::map *key_commands_long; + void keypad_loop(void); diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp index ceec140..53c8f5b 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp @@ -1,6 +1,7 @@ #include #include #include "applicationInternal/gui/guiMemoryOptimizer.h" +#include "applicationInternal/gui/guiRegistry.h" #include "applicationInternal/hardware/hardwarePresenter.h" #include "applicationInternal/scenes/sceneRegistry.h" #include "applicationInternal/commandHandler.h" @@ -51,14 +52,20 @@ void register_scene( scenes_on_sceneSelectionGUI.insert(scenes_on_sceneSelectionGUI.end(), {std::string(a_scene_name)}); // Whenever a new scene is registered, normally a new scene command has been defined immediately before (e.g. see register_scene_TV()). - // But this new scene command could have been already been used before in the key definition of another scene. The command at this time was 0, which is undefined. - // So we have to set the keys again for all scenes that have been registered before. + // But this new scene command could have been already been used before in the key definition of another scene or a gui. The command at this time was 0, which is undefined. + // So we have to set the keys again for all scenes and guis that have been registered before. // 1. set again the defaultKeys register_scene_defaultKeys(); // 2. loop over all registered scenes and call setKeys() for (std::map::iterator it = registered_scenes.begin(); it != registered_scenes.end(); ++it) { it->second.this_scene_setKeys(); } + // 3. loop over all registered guis and call setKeys() + for (std::map::iterator it = registered_guis_byName_map.begin(); it != registered_guis_byName_map.end(); ++it) { + if (it->second.this_gui_setKeys != NULL) { + it->second.this_gui_setKeys(); + } + } } @@ -86,8 +93,14 @@ void scene_end_sequence_from_registry(std::string sceneName) { repeatModes get_key_repeatMode(std::string sceneName, char keyChar) { try { + // look if the map of the active gui has a definition for it + std::string GUIname = gui_memoryOptimizer_getActiveGUIname(); + if ((registered_guis_byName_map.count(GUIname) > 0) && (registered_guis_byName_map.at(GUIname).this_key_repeatModes != NULL) && (registered_guis_byName_map.at(GUIname).this_key_repeatModes->count(keyChar) > 0)) { + // Serial.printf("get_key_repeatMode: will use key from gui %s\r\n", GUIname.c_str()); + return registered_guis_byName_map.at(GUIname).this_key_repeatModes->at(keyChar); + // look if the map of the active scene has a definition for it - if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_repeatModes->count(keyChar) > 0)) { + } else if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_repeatModes->count(keyChar) > 0)) { // Serial.printf("get_key_repeatMode: will use key from scene %s\r\n", sceneName.c_str()); return registered_scenes.at(sceneName).this_key_repeatModes->at(keyChar); @@ -110,8 +123,14 @@ repeatModes get_key_repeatMode(std::string sceneName, char keyChar) { uint16_t get_command_short(std::string sceneName, char keyChar) { try { + // look if the map of the active gui has a definition for it + std::string GUIname = gui_memoryOptimizer_getActiveGUIname(); + if ((registered_guis_byName_map.count(GUIname) > 0) && (registered_guis_byName_map.at(GUIname).this_key_commands_short != NULL) && (registered_guis_byName_map.at(GUIname).this_key_commands_short->count(keyChar) > 0)) { + // Serial.printf("get_command_short: will use key from gui %s\r\n", GUIname.c_str()); + return registered_guis_byName_map.at(GUIname).this_key_commands_short->at(keyChar); + // look if the map of the active scene has a definition for it - if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_commands_short->count(keyChar) > 0)) { + } else if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_commands_short->count(keyChar) > 0)) { // Serial.printf("get_command_short: will use key from scene %s\r\n", sceneName.c_str()); return registered_scenes.at(sceneName).this_key_commands_short->at(keyChar); @@ -135,8 +154,14 @@ uint16_t get_command_short(std::string sceneName, char keyChar) { uint16_t get_command_long(std::string sceneName, char keyChar) { try { + // look if the map of the active gui has a definition for it + std::string GUIname = gui_memoryOptimizer_getActiveGUIname(); + if ((registered_guis_byName_map.count(GUIname) > 0) && (registered_guis_byName_map.at(GUIname).this_key_commands_long != NULL) && (registered_guis_byName_map.at(GUIname).this_key_commands_long->count(keyChar) > 0)) { + // Serial.printf("get_command_long: will use key from gui %s\r\n", GUIname.c_str()); + return registered_guis_byName_map.at(GUIname).this_key_commands_long->at(keyChar); + // look if the map of the active scene has a definition for it - if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_commands_long->count(keyChar) > 0)) { + } else if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_commands_long->count(keyChar) > 0)) { // Serial.printf("get_command_long: will use key from scene %s\r\n", sceneName.c_str()); return registered_scenes.at(sceneName).this_key_commands_long->at(keyChar); diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.h b/Platformio/src/applicationInternal/scenes/sceneRegistry.h index 05ebfbf..06c3d64 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.h +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.h @@ -1,8 +1,6 @@ #pragma once #include -#include -#include #include #include "applicationInternal/keys.h" #include "applicationInternal/gui/guiMemoryOptimizer.h" @@ -13,9 +11,6 @@ typedef std::vector t_scene_list; typedef void (*scene_setKeys)(void); typedef void (*scene_start_sequence)(void); typedef void (*scene_end_sequence)(void); -typedef std::map *key_repeatModes; -typedef std::map *key_commands_short; -typedef std::map *key_commands_long; typedef t_gui_list *gui_list; typedef t_scene_list *scene_list; diff --git a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp index 4cc1e13..90a072d 100644 --- a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp +++ b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp @@ -1,11 +1,13 @@ #include -#include "applicationInternal/hardware/hardwarePresenter.h" #include "applicationInternal/gui/guiBase.h" #include "applicationInternal/gui/guiRegistry.h" -#include "devices/misc/device_smarthome/gui_smarthome.h" - +#include "applicationInternal/hardware/hardwarePresenter.h" +#include "applicationInternal/scenes/sceneRegistry.h" #include "applicationInternal/commandHandler.h" +#include "applicationInternal/keys.h" +#include "devices/misc/device_smarthome/gui_smarthome.h" #include "devices/misc/device_smarthome/device_smarthome.h" +#include "scenes/scene__default.h" // LVGL declarations LV_IMG_DECLARE(lightbulb); @@ -22,6 +24,10 @@ static int32_t sliderBvalue = 0; uint16_t GUI_SMARTHOME_ACTIVATE; +std::map key_repeatModes_smarthome = {}; +std::map key_commands_short_smarthome = {}; +std::map key_commands_long_smarthome = {}; + // Smart Home Toggle Event handler static void smartHomeToggle_event_cb(lv_event_t* e){ std::string payload; @@ -160,8 +166,23 @@ void notify_tab_before_delete_smarthome(void) { sliderBvalue = lv_slider_get_value(sliderB); } +void gui_setKeys_smarthome() { + key_commands_short_smarthome = { + {KEY_STOP, SCENE_SELECTION}, + }; +} + void register_gui_smarthome(void){ - register_gui(std::string(tabName_smarthome), & create_tab_content_smarthome, & notify_tab_before_delete_smarthome); + + register_gui( + std::string(tabName_smarthome), + & create_tab_content_smarthome, + & notify_tab_before_delete_smarthome, + & gui_setKeys_smarthome, + & key_repeatModes_smarthome, + & key_commands_short_smarthome, + & key_commands_long_smarthome + ); register_command(&GUI_SMARTHOME_ACTIVATE, makeCommandData(GUI, {std::string(tabName_smarthome)})); } diff --git a/Platformio/src/main.cpp b/Platformio/src/main.cpp index f6d9d41..0037358 100644 --- a/Platformio/src/main.cpp +++ b/Platformio/src/main.cpp @@ -102,7 +102,8 @@ int main(int argc, char *argv[]) { #endif register_keyboardCommands(); - // register the GUIs. They will be displayed in the order they have been registered. + // Register the GUIs. They will be displayed in the order they have been registered. + // GUIs must be registered before the scenes, because only the scenes re-register key bindings to commands which have been defined after the key binding (see register_scene()) register_gui_sceneSelection(); register_gui_irReceiver(); register_gui_settings(); From 749f13417ee591319e3a9a404fdefe0869fe10d1 Mon Sep 17 00:00:00 2001 From: KlausMu Date: Tue, 23 Apr 2024 14:37:16 +0200 Subject: [PATCH 4/6] support of "showSpecificGUI" in sceneHandler --- .../src/applicationInternal/gui/guiBase.cpp | 4 +- .../gui/guiMemoryOptimizer.cpp | 56 +++++++------------ .../scenes/sceneHandler.cpp | 37 +++++++----- .../scenes/sceneRegistry.cpp | 41 +++++++------- .../scenes/sceneRegistry.h | 6 +- .../misc/device_smarthome/gui_smarthome.cpp | 2 +- 6 files changed, 70 insertions(+), 76 deletions(-) diff --git a/Platformio/src/applicationInternal/gui/guiBase.cpp b/Platformio/src/applicationInternal/gui/guiBase.cpp index dac2306..50d2933 100644 --- a/Platformio/src/applicationInternal/gui/guiBase.cpp +++ b/Platformio/src/applicationInternal/gui/guiBase.cpp @@ -104,7 +104,7 @@ static void tabview_animation_ready_cb(lv_anim_t* a) { void tabview_tab_changed_event_cb(lv_event_t* e) { if (lv_event_get_code(e) == LV_EVENT_VALUE_CHANGED) { - int newTabID = lv_tabview_get_tab_active((lv_obj_t*)lv_event_get_target(e)); + int newTabID = lv_tabview_get_tab_act((lv_obj_t*)lv_event_get_target(e)); // Wait until the animation ended, then call "guis_doTabCreationAfterSliding(newTabID);" // https://forum.lvgl.io/t/delete-a-tab-after-the-tabview-scroll-animation-is-complete/3155/4 @@ -313,7 +313,7 @@ void guis_doTabCreationAfterSliding(int newTabID) { gui_memoryOptimizer_afterSliding(&tabview, &panel, &img1, &img2, newTabID); doLogMemoryUsage(); } -// 3. after gui list has changed (called by handleScene()), when switching between main_gui_list and scene specific list +// 3. after gui list has changed (called by handleScene()), when switching between main_gui_list and scene specific list. Will show first GUi in list void guis_doTabCreationAfterGUIlistChanged(GUIlists newGUIlist) { gui_memoryOptimizer_afterGUIlistChanged(&tabview, &panel, &img1, &img2, newGUIlist); doLogMemoryUsage(); diff --git a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp index 718377b..b8fa535 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp @@ -168,8 +168,8 @@ lv_obj_t* create_panel() { std::string get_name_of_gui_to_be_shown(int index) { if (index == -1) { return ""; - } else if (index <= get_gui_list_active()->size() -1) { - return get_gui_list_active()->at(index); + } else if (index <= get_gui_list_active_withFallback()->size() -1) { + return get_gui_list_active_withFallback()->at(index); } else { return ""; } @@ -210,10 +210,10 @@ void setGUIlistIndicesToBeShown_forSpecificGUIlistIndex(int gui_list_index, t_gu Serial.printf(" GUIlistIndices: will resume at specific index with \"first state\"\r\n"); gui_state->gui_on_tab[0] = {NULL, "", 0}; // take care if there is only one gui in list - gui_state->gui_on_tab[1] = {NULL, "", get_gui_list_active()->size() >= 2 ? 1 : -1}; + gui_state->gui_on_tab[1] = {NULL, "", get_gui_list_active_withFallback()->size() >= 2 ? 1 : -1}; gui_state->gui_on_tab[2] = {NULL, "", -1}; gui_state->activeTabID = 0; - } else if (gui_list_index == get_gui_list_active()->size() -1) { + } else if (gui_list_index == get_gui_list_active_withFallback()->size() -1) { // last state Serial.printf(" GUIlistIndices: will resume at specific index with \"last state\"\r\n"); gui_state->gui_on_tab[0] = {NULL, "", gui_list_index -1}; @@ -233,9 +233,9 @@ void setGUIlistIndicesToBeShown_forSpecificGUIlistIndex(int gui_list_index, t_gu void setGUIlistIndicesToBeShown_forFirstGUIinGUIlist(t_gui_state *gui_state) { Serial.printf(" GUIlistIndices: will show the first gui from \"gui_list\" as initial state\r\n"); // take care if there is no gui in list - gui_state->gui_on_tab[0] = {NULL, "", get_gui_list_active()->size() != 0 ? 0 : -1}; + gui_state->gui_on_tab[0] = {NULL, "", get_gui_list_active_withFallback()->size() != 0 ? 0 : -1}; // take care if there is only one gui in list - gui_state->gui_on_tab[1] = {NULL, "", get_gui_list_active()->size() >= 2 ? 1 : -1}; + gui_state->gui_on_tab[1] = {NULL, "", get_gui_list_active_withFallback()->size() >= 2 ? 1 : -1}; gui_state->gui_on_tab[2] = {NULL, "", -1}; gui_state->activeTabID = 0; } @@ -268,7 +268,7 @@ void setGUIlistIndicesToBeShown_afterSlide(t_gui_state *gui_state) { } else { oldListIndex = gui_state->gui_on_tab[1].gui_list_index_previous; } - if (oldListIndex == get_gui_list_active()->size() -2) { + if (oldListIndex == get_gui_list_active_withFallback()->size() -2) { // next state is the "last state" gui_state->gui_on_tab[0] = {NULL, "", oldListIndex}; gui_state->gui_on_tab[1] = {NULL, "", oldListIndex +1}; @@ -292,8 +292,8 @@ void doTabCreation_strategyMax3(lv_obj_t* tabview, t_gui_state *gui_state) { create_new_tab(tabview, &gui_state->gui_on_tab[i]); } - if (get_gui_list_active()->size() > 0) { - std::string nameOfNewActiveTab = get_gui_list_active()->at(gui_state->gui_on_tab[gui_state->activeTabID].gui_list_index); + if (get_gui_list_active_withFallback()->size() > 0) { + std::string nameOfNewActiveTab = get_gui_list_active_withFallback()->at(gui_state->gui_on_tab[gui_state->activeTabID].gui_list_index); Serial.printf(" New visible tab is \"%s\"\r\n", nameOfNewActiveTab.c_str()); // set active tab @@ -305,24 +305,10 @@ void doTabCreation_strategyMax3(lv_obj_t* tabview, t_gui_state *gui_state) { LV_IMG_DECLARE(gradientLeft); LV_IMG_DECLARE(gradientRight); -void getBreadcrumpPosition(uint8_t* breadcrumpPosition, std::string nameOfGUI) { - *breadcrumpPosition = 0; - - gui_list gui_list_active = get_gui_list_active(); - uint8_t counter = 0; - for (std::vector::iterator it = gui_list_active->begin() ; it != gui_list_active->end(); ++it) { - counter++; - if (*it == nameOfGUI) { - *breadcrumpPosition = counter; - return; - } - } -} - void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv_obj_t* img2, t_gui_state *gui_state) { Serial.printf(" Will fill panel with page indicators\r\n"); - if (get_gui_list_active()->size() == 0) { + if (get_gui_list_active_withFallback()->size() == 0) { Serial.printf(" no tab available, so no page indicators\r\n"); // at least add the style lv_obj_add_style(panel, &panel_style, 0); @@ -362,9 +348,9 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv uint8_t breadcrumpDotSize = 8; // should be an even number uint8_t breadcrumpDotDistance = 2; // should be an even number - uint8_t breadcrumpMainGuiListLength = get_gui_list(MAIN_GUI_LIST)->size(); + uint8_t breadcrumpMainGuiListLength = get_gui_list_withFallback(MAIN_GUI_LIST)->size(); int8_t breadcrumpMainGuiListStartPositionX = (-1) * (breadcrumpMainGuiListLength -1) * (breadcrumpDotSize + breadcrumpDotDistance) / 2; - uint8_t breadcrumpSceneGuiListLength = get_gui_list(SCENE_GUI_LIST)->size(); + uint8_t breadcrumpSceneGuiListLength = get_gui_list_withFallback(SCENE_GUI_LIST)->size(); int8_t breadcrumpSceneGuiListStartPositionX = (-1) * (breadcrumpSceneGuiListLength -1) * (breadcrumpDotSize + breadcrumpDotDistance) / 2; #if (USE_SCENE_SPECIFIC_GUI_LIST != 0) bool show_scene_gui_list = get_scene_has_gui_list(gui_memoryOptimizer_getActiveSceneName()); @@ -389,11 +375,11 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv for (int i=0; i<3; i++) { if (gui_state->gui_on_tab[i].gui_list_index != -1) { nameOfGUI = gui_state->gui_on_tab[i].GUIname; - getBreadcrumpPosition(&breadcrumpPosition, nameOfGUI); + breadcrumpPosition = gui_state->gui_on_tab[i].gui_list_index +1; // Create actual buttons for every tab lv_obj_t* btn = lv_btn_create(panel); - if (nameOfGUI == gui_memoryOptimizer_getActiveGUIname()) { + if (i == gui_state->activeTabID) { // only if this is the button for the currently active tab, make it clickable to get to scene selection gui lv_obj_add_flag(btn, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_user_data(btn,(void *)(intptr_t)2); @@ -484,8 +470,8 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv btn = lv_btn_create(panel); lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_size(btn, 150, lv_pct(100)); - // 4 at last position 4 at middle position only one tab available overall - if ((gui_state->gui_on_tab[2].gui_list_index == get_gui_list_active()->size()-1) || (gui_state->gui_on_tab[1].gui_list_index == get_gui_list_active()->size()-1) || (gui_state->gui_on_tab[1].gui_list_index == -1)) { + // 4 at last position 4 at middle position only one tab available overall + if ((gui_state->gui_on_tab[2].gui_list_index == get_gui_list_active_withFallback()->size()-1) || (gui_state->gui_on_tab[1].gui_list_index == get_gui_list_active_withFallback()->size()-1) || (gui_state->gui_on_tab[1].gui_list_index == -1)) { lv_obj_set_style_bg_color(btn, lv_color_black(), LV_PART_MAIN); } else { lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); @@ -555,8 +541,8 @@ void gui_memoryOptimizer_onStartup(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_ // 1. find last used gui int gui_list_index = -1; // find index of gui_memoryOptimizer_getActiveGUIname() in gui_list_active - for (int i=0; isize(); i++) { - if (get_gui_list_active()->at(i) == gui_memoryOptimizer_getActiveGUIname()) { + for (int i=0; isize(); i++) { + if (get_gui_list_active_withFallback()->at(i) == gui_memoryOptimizer_getActiveGUIname()) { Serial.printf("Startup: found GUI with name \"%s\" in \"gui_list_active\" at position %d\r\n", gui_memoryOptimizer_getActiveGUIname().c_str(), i); gui_list_index = i; break; @@ -564,7 +550,7 @@ void gui_memoryOptimizer_onStartup(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_ } // 2. set gui_list_indices and the tab to be activated - if ((gui_list_index >= 0) && (gui_list_index < get_gui_list_active()->size())) { + if ((gui_list_index >= 0) && (gui_list_index < get_gui_list_active_withFallback()->size())) { // gui was found setGUIlistIndicesToBeShown_forSpecificGUIlistIndex(gui_list_index, &gui_state); @@ -619,7 +605,7 @@ void gui_memoryOptimizer_afterSliding(lv_obj_t** tabview, lv_obj_t** panel, lv_o } -// 3. after gui list has changed (called by handleScene()), when switching between main_gui_list and scene specific list +// 3. after gui list has changed (called by handleScene()), when switching between main_gui_list and scene specific list. Will show first GUi in list void gui_memoryOptimizer_afterGUIlistChanged(lv_obj_t** tabview, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2, GUIlists newGUIlist) { Serial.printf("--- Will change to new gui_list\r\n"); @@ -646,7 +632,7 @@ void gui_memoryOptimizer_navigateToGUI(lv_obj_t** tabview, lv_obj_t** panel, lv_ Serial.printf("--- Will navigate to specific GUI\r\n"); - if ( !((gui_list_index >= 0) && (gui_list_index < get_gui_list(GUIlist)->size()))) { + if ( !((gui_list_index >= 0) && (gui_list_index < get_gui_list_withFallback(GUIlist)->size()))) { Serial.printf(" cannot navigate to GUI because gui_list_index \"%d\" is out of range\r\n", gui_list_index); return; } diff --git a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp index 8ea033c..3e77910 100644 --- a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp @@ -5,6 +5,7 @@ #include "applicationInternal/scenes/sceneRegistry.h" #include "applicationInternal/hardware/hardwarePresenter.h" #include "applicationInternal/commandHandler.h" +#include "guis/gui_sceneSelection.h" #include "scenes/scene__default.h" void setLabelActiveScene() { @@ -13,7 +14,7 @@ void setLabelActiveScene() { } } -void navigateBackToSceneGUIlist(); +void showSpecificGUI(GUIlists GUIlist, std::string GUIname); void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = "") { @@ -23,7 +24,7 @@ void handleScene(uint16_t command, commandData commandData, std::string addition // --- do not switch scene, but show scene selection gui. From that on, we are in the main_gui_list. ---------------- if (scene_name == scene_name_selection) { Serial.println("scene: will show scene selection gui"); - guis_doTabCreationAfterGUIlistChanged(MAIN_GUI_LIST); + showSpecificGUI(MAIN_GUI_LIST, tabName_sceneSelection); return; } @@ -127,30 +128,38 @@ void handleScene(uint16_t command, commandData commandData, std::string addition guis_doTabCreationAfterGUIlistChanged(SCENE_GUI_LIST); } -void handleGUI(uint16_t command, commandData commandData, std::string additionalPayload = "") { +void showSpecificGUI(GUIlists GUIlist, std::string GUIname) { + gui_list gui_list_for_search = get_gui_list_withFallback(GUIlist); - auto current = commandData.commandPayloads.begin(); - std::string GUIname = *current; - - // 1. check if the gui is known in the main_gui_list + // 1. search for gui in the gui list int gui_list_index = -1; - // find index of gui_memoryOptimizer_getActiveGUIname() in gui_list_active - for (int i=0; i < main_gui_list.size(); i++) { - if (main_gui_list.at(i) == GUIname) { - Serial.printf("handleGUI: found GUI with name \"%s\" in \"main_gui_list\" at position %d\r\n", GUIname.c_str(), i); + for (int i=0; i < gui_list_for_search->size(); i++) { + if (gui_list_for_search->at(i) == GUIname) { + Serial.printf("showSpecificGUI: found GUI with name \"%s\" in %s at position %d\r\n", GUIname.c_str(), GUIlist == MAIN_GUI_LIST ? "\"main_gui_list\"" : "\"scene gui list\"", i); gui_list_index = i; break; } } // 2. call guiBase.cpp - if ((gui_list_index >= 0) && (gui_list_index < main_gui_list.size())) { - guis_doTabCreationForSpecificGUI(MAIN_GUI_LIST, gui_list_index); + if ((gui_list_index >= 0) && (gui_list_index < gui_list_for_search->size())) { + guis_doTabCreationForSpecificGUI(GUIlist, gui_list_index); } else { // gui was not found - Serial.printf("handleGUI: GUI with name \"%s\" was not found. Cannot navigate to that GUI\r\n", GUIname.c_str()); + Serial.printf("showSpecificGUI: GUI with name \"%s\" was not found in gui list %s. Cannot navigate to that GUI\r\n", GUIname.c_str(), GUIlist == MAIN_GUI_LIST ? "\"main_gui_list\"" : "\"scene gui list\""); return; } +} + +void handleGUI(uint16_t command, commandData commandData, std::string additionalPayload = "") { + + auto current = commandData.commandPayloads.begin(); + GUIlists GUIlist = (GUIlists)std::stoi(*current); + + current = std::next(current, 1); + std::string GUIname = *current; + + showSpecificGUI(GUIlist, GUIname); } diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp index 53c8f5b..74f354e 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp @@ -183,11 +183,10 @@ uint16_t get_command_long(std::string sceneName, char keyChar) { } -gui_list get_gui_list(GUIlists gui_list) { +gui_list get_gui_list_withFallback(GUIlists gui_list) { try { - // If gui_list == MAIN_GUI_LIST, then we are in the main_gui_list, either if a scene is active or not. - // If gui_list == SCENE_GUI_LIST, then a scene is active and we are not in the main_gui_list (with the scene selector as first gui). - // In that case, we try to use the scene specific gui list, if the scene defined one. + // If gui_list == MAIN_GUI_LIST, then we want the main_gui_list, either if a scene is active or not. + // If gui_list == SCENE_GUI_LIST, then we want the scene gui list. If none is defined, return main_gui_list as fallback. if (gui_list == MAIN_GUI_LIST) { return &main_gui_list; @@ -214,8 +213,23 @@ gui_list get_gui_list(GUIlists gui_list) { } } -gui_list get_gui_list_active() { - return get_gui_list(gui_memoryOptimizer_getActiveGUIlist()); +gui_list get_gui_list_active_withFallback() { + return get_gui_list_withFallback(gui_memoryOptimizer_getActiveGUIlist()); +} + +bool get_scene_has_gui_list(std::string sceneName) { + try { + // look if the scene is known + if ((registered_scenes.count(sceneName) > 0)) { + return (registered_scenes.at(sceneName).this_gui_list != NULL); + } else { + return false; + } + } + catch (const std::out_of_range& oor) { + Serial.printf("get_scene_has_gui_list: internal error, sceneName not registered\r\n"); + return false; + } } uint16_t get_activate_scene_command(std::string sceneName) { @@ -239,21 +253,6 @@ uint16_t get_activate_scene_command(std::string sceneName) { } -bool get_scene_has_gui_list(std::string sceneName) { - try { - // look if the scene is known - if ((registered_scenes.count(sceneName) > 0)) { - return (registered_scenes.at(sceneName).this_gui_list != NULL); - } else { - return false; - } - } - catch (const std::out_of_range& oor) { - Serial.printf("get_scene_has_gui_list: internal error, sceneName not registered\r\n"); - return false; - } -} - scene_list get_scenes_on_sceneSelectionGUI() { return &scenes_on_sceneSelectionGUI; } diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.h b/Platformio/src/applicationInternal/scenes/sceneRegistry.h index 06c3d64..a89d43e 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.h +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.h @@ -31,10 +31,10 @@ void scene_end_sequence_from_registry(std::string sceneName); repeatModes get_key_repeatMode(std::string sceneName, char keyChar); uint16_t get_command_short(std::string sceneName, char keyChar); uint16_t get_command_long(std::string sceneName, char keyChar); -gui_list get_gui_list(GUIlists gui_list); -gui_list get_gui_list_active(); -uint16_t get_activate_scene_command(std::string sceneName); +gui_list get_gui_list_withFallback(GUIlists gui_list); +gui_list get_gui_list_active_withFallback(); bool get_scene_has_gui_list(std::string sceneName); +uint16_t get_activate_scene_command(std::string sceneName); scene_list get_scenes_on_sceneSelectionGUI(); void set_scenes_on_sceneSelectionGUI(t_scene_list a_scene_list); diff --git a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp index 90a072d..f736070 100644 --- a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp +++ b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp @@ -184,5 +184,5 @@ void register_gui_smarthome(void){ & key_commands_long_smarthome ); - register_command(&GUI_SMARTHOME_ACTIVATE, makeCommandData(GUI, {std::string(tabName_smarthome)})); + register_command(&GUI_SMARTHOME_ACTIVATE, makeCommandData(GUI, {std::to_string(MAIN_GUI_LIST), std::string(tabName_smarthome)})); } From 17ee1f06d02f38133bd8182ac7b19736a77c5927 Mon Sep 17 00:00:00 2001 From: KlausMu Date: Tue, 23 Apr 2024 15:12:25 +0200 Subject: [PATCH 5/6] add device gui for yamahaAmp --- .../device_yamahaAmp/gui_yamahaAmp.cpp | 46 +++++++++++++++++++ .../device_yamahaAmp/gui_yamahaAmp.h | 4 ++ Platformio/src/main.cpp | 4 +- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Platformio/src/devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.cpp create mode 100644 Platformio/src/devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.h diff --git a/Platformio/src/devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.cpp b/Platformio/src/devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.cpp new file mode 100644 index 0000000..0d35762 --- /dev/null +++ b/Platformio/src/devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.cpp @@ -0,0 +1,46 @@ +#include +#include "applicationInternal/gui/guiBase.h" +#include "applicationInternal/gui/guiRegistry.h" +#include "applicationInternal/commandHandler.h" +#include "devices/AVreceiver/device_yamahaAmp/device_yamahaAmp.h" +#include "devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.h" + +static void button_clicked_event_cb(lv_event_t* e) { + int user_data = (intptr_t)(e->user_data); + + if (user_data == 0) { + executeCommand(YAMAHA_STANDARD); + } + +} + +void create_tab_content_yamahaAmp(lv_obj_t* tab) { + + // Add content to the sceneSelection tab + + lv_obj_set_layout(tab, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(tab, LV_FLEX_FLOW_COLUMN); + lv_obj_set_scrollbar_mode(tab, LV_SCROLLBAR_MODE_ACTIVE); + + // -- create a button for "standard" ---------------------------------------- + lv_obj_t* button = lv_btn_create(tab); + lv_obj_set_size(button, 80, 40); + lv_obj_set_style_radius(button, 10, LV_PART_MAIN); + lv_obj_set_style_bg_color(button, color_primary, LV_PART_MAIN); + lv_obj_add_event_cb(button, button_clicked_event_cb, LV_EVENT_CLICKED, (void *)(intptr_t) 0); + + lv_obj_t* label = lv_label_create(button); + lv_label_set_text(label, "Standard"); + lv_obj_center(label); + +} + +void notify_tab_before_delete_yamahaAmp(void) { + // remember to set all pointers to lvgl objects to NULL if they might be accessed from outside. + // They must check if object is NULL and must not use it if so + +} + +void register_gui_yamahaAmp(void){ + register_gui(std::string(tabName_yamahaAmp), & create_tab_content_yamahaAmp, & notify_tab_before_delete_yamahaAmp); +} diff --git a/Platformio/src/devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.h b/Platformio/src/devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.h new file mode 100644 index 0000000..776653c --- /dev/null +++ b/Platformio/src/devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.h @@ -0,0 +1,4 @@ +#pragma once + +const char * const tabName_yamahaAmp = "Yamaha Amp"; +void register_gui_yamahaAmp(void); diff --git a/Platformio/src/main.cpp b/Platformio/src/main.cpp index 0037358..f39b5ab 100644 --- a/Platformio/src/main.cpp +++ b/Platformio/src/main.cpp @@ -31,6 +31,7 @@ #include "guis/gui_irReceiver.h" #include "guis/gui_settings.h" #include "guis/gui_numpad.h" +#include "devices/AVreceiver/device_yamahaAmp/gui_yamahaAmp.h" #include "devices/mediaPlayer/device_appleTV/gui_appleTV.h" #include "devices/misc/device_smarthome/gui_smarthome.h" #include "applicationInternal/keys.h" @@ -110,9 +111,10 @@ int main(int argc, char *argv[]) { register_gui_appleTV(); register_gui_numpad(); register_gui_smarthome(); + register_gui_yamahaAmp(); // Only show these GUIs in the main gui list. If you don't set this explicitely, by default all registered guis are shown. #if (USE_SCENE_SPECIFIC_GUI_LIST != 0) - main_gui_list = {tabName_sceneSelection, tabName_smarthome, tabName_settings, tabName_irReceiver}; + main_gui_list = {tabName_yamahaAmp, tabName_sceneSelection, tabName_smarthome, tabName_settings, tabName_irReceiver}; #endif // register the scenes and their key_commands_* From 8f0ceeb72babfd0822c1dcb4892fabb83335a32d Mon Sep 17 00:00:00 2001 From: KlausMu Date: Thu, 25 Apr 2024 22:22:36 +0200 Subject: [PATCH 6/6] set keys again both for new guis and new scenes --- .../applicationInternal/gui/guiRegistry.cpp | 19 ++++++++++--- .../src/applicationInternal/gui/guiRegistry.h | 2 ++ .../scenes/sceneRegistry.cpp | 28 +------------------ .../scenes/sceneRegistry.h | 14 ++++++++++ Platformio/src/main.cpp | 1 - 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Platformio/src/applicationInternal/gui/guiRegistry.cpp b/Platformio/src/applicationInternal/gui/guiRegistry.cpp index b2c30fd..ed628a4 100644 --- a/Platformio/src/applicationInternal/gui/guiRegistry.cpp +++ b/Platformio/src/applicationInternal/gui/guiRegistry.cpp @@ -48,10 +48,21 @@ void register_gui( // Can be overwritten by scenes to have their own gui_list. main_gui_list.insert(main_gui_list.end(), {std::string(a_name)}); - // Whenever a new gui is registered, a new gui command could have been defined. - // But this new gui command could have been already been used before in the key definition of another gui. The command at this time was 0, which is undefined. - // So we have to set the keys again for all guis that have been registered before. - // Loop over all registered guis and call setKeys() + setKeysForAllRegisteredGUIsAndScenes(); + +} + +void setKeysForAllRegisteredGUIsAndScenes() { + // Whenever a new gui or scene is registered, a new gui or scene command could have been defined in the gui or scene. + // But this new command could have already been used before in the key definition of another gui or scene. The command at this time was 0, which is undefined. + // So we have to set the keys again for all guis and scenes that have been registered before. + // 1. set again the defaultKeys + register_scene_defaultKeys(); + // 2. loop over all registered scenes and call setKeys() + for (std::map::iterator it = registered_scenes.begin(); it != registered_scenes.end(); ++it) { + it->second.this_scene_setKeys(); + } + // 3. loop over all registered guis and call setKeys() for (std::map::iterator it = registered_guis_byName_map.begin(); it != registered_guis_byName_map.end(); ++it) { if (it->second.this_gui_setKeys != NULL) { it->second.this_gui_setKeys(); diff --git a/Platformio/src/applicationInternal/gui/guiRegistry.h b/Platformio/src/applicationInternal/gui/guiRegistry.h index c4a6296..26b81a6 100644 --- a/Platformio/src/applicationInternal/gui/guiRegistry.h +++ b/Platformio/src/applicationInternal/gui/guiRegistry.h @@ -50,3 +50,5 @@ void register_gui( key_commands_short a_key_commands_short = NULL, key_commands_long a_key_commands_long = NULL ); + +void setKeysForAllRegisteredGUIsAndScenes(); \ No newline at end of file diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp index 74f354e..81df397 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp @@ -8,18 +8,6 @@ // scenes #include "scenes/scene__default.h" -// https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work -struct scene_definition { - scene_setKeys this_scene_setKeys; - scene_start_sequence this_scene_start_sequence; - scene_end_sequence this_scene_end_sequence; - key_repeatModes this_key_repeatModes; - key_commands_short this_key_commands_short; - key_commands_long this_key_commands_long; - gui_list this_gui_list; - uint16_t this_activate_scene_command; -}; - std::map registered_scenes; t_scene_list scenes_on_sceneSelectionGUI; @@ -51,21 +39,7 @@ void register_scene( // Can be overwritten in main.cpp scenes_on_sceneSelectionGUI.insert(scenes_on_sceneSelectionGUI.end(), {std::string(a_scene_name)}); - // Whenever a new scene is registered, normally a new scene command has been defined immediately before (e.g. see register_scene_TV()). - // But this new scene command could have been already been used before in the key definition of another scene or a gui. The command at this time was 0, which is undefined. - // So we have to set the keys again for all scenes and guis that have been registered before. - // 1. set again the defaultKeys - register_scene_defaultKeys(); - // 2. loop over all registered scenes and call setKeys() - for (std::map::iterator it = registered_scenes.begin(); it != registered_scenes.end(); ++it) { - it->second.this_scene_setKeys(); - } - // 3. loop over all registered guis and call setKeys() - for (std::map::iterator it = registered_guis_byName_map.begin(); it != registered_guis_byName_map.end(); ++it) { - if (it->second.this_gui_setKeys != NULL) { - it->second.this_gui_setKeys(); - } - } + setKeysForAllRegisteredGUIsAndScenes(); } diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.h b/Platformio/src/applicationInternal/scenes/sceneRegistry.h index a89d43e..8ff50c4 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.h +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.h @@ -14,6 +14,20 @@ typedef void (*scene_end_sequence)(void); typedef t_gui_list *gui_list; typedef t_scene_list *scene_list; +// https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work +struct scene_definition { + scene_setKeys this_scene_setKeys; + scene_start_sequence this_scene_start_sequence; + scene_end_sequence this_scene_end_sequence; + key_repeatModes this_key_repeatModes; + key_commands_short this_key_commands_short; + key_commands_long this_key_commands_long; + gui_list this_gui_list; + uint16_t this_activate_scene_command; +}; + +extern std::map registered_scenes; + void register_scene( std::string a_scene_name, scene_setKeys a_scene_setKeys, diff --git a/Platformio/src/main.cpp b/Platformio/src/main.cpp index f39b5ab..13962b7 100644 --- a/Platformio/src/main.cpp +++ b/Platformio/src/main.cpp @@ -104,7 +104,6 @@ int main(int argc, char *argv[]) { register_keyboardCommands(); // Register the GUIs. They will be displayed in the order they have been registered. - // GUIs must be registered before the scenes, because only the scenes re-register key bindings to commands which have been defined after the key binding (see register_scene()) register_gui_sceneSelection(); register_gui_irReceiver(); register_gui_settings();