diff --git a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp index 6666e4b..e60fe0d 100644 --- a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp +++ b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.cpp @@ -4,8 +4,10 @@ Preferences preferences; -std::string currentScene; -std::string currentGUIname; +std::string activeScene; +std::string activeGUIname; +int activeGUIlist; +int lastActiveGUIlistIndex; void init_preferences_HAL(void) { // Restore settings from internal flash memory @@ -17,10 +19,12 @@ 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")); + lastActiveGUIlistIndex = (preferences.getInt("lastActiveIndex")); - // 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 +39,37 @@ 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); + preferences.putInt("lastActiveIndex", lastActiveGUIlistIndex); 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; +} +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 f94f0f4..e223648 100644 --- a/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h +++ b/Platformio/hardware/ESP32/preferencesStorage_hal_esp32.h @@ -5,7 +5,11 @@ 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); +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 af5d257..be907c2 100644 --- a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp +++ b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp @@ -1,31 +1,58 @@ #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; +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; + lastActiveGUIlistIndex = 0; } 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; +} +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 f94f0f4..e223648 100644 --- a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h +++ b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.h @@ -5,7 +5,11 @@ 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); +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 0a0c0fd..c3948de 100644 --- a/Platformio/src/applicationInternal/gui/guiBase.cpp +++ b/Platformio/src/applicationInternal/gui/guiBase.cpp @@ -15,8 +15,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 @@ -30,8 +28,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 ----------------------------------------------------------------------------------------------------------------------- @@ -89,28 +87,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_active((lv_obj_t*)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_obj_t*)lv_event_get_target(e); lv_obj_t* tabContainer = lv_tabview_get_content(myTabview); @@ -118,11 +116,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_completed_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); } } } @@ -156,8 +155,8 @@ void init_gui(void) { lv_obj_set_style_bg_color(lv_screen_active(), 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 @@ -272,6 +271,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 ---------------------------------------------------------------------- @@ -294,12 +294,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; // } // } @@ -307,19 +307,35 @@ 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() { + 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. Will show first GUi in list +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) { // unsigned long startTime = millis(); diff --git a/Platformio/src/applicationInternal/gui/guiBase.h b/Platformio/src/applicationInternal/gui/guiBase.h index d78cffa..01fdb05 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_span_t* MemoryUsageSpanHeap; @@ -17,7 +18,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; @@ -26,18 +26,22 @@ 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); // 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 a401ecf..278f3e5 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp @@ -1,47 +1,101 @@ #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 and the last 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}}; + // 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; + +// 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_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; +} 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 +107,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 +117,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}; } @@ -116,162 +170,147 @@ 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_withFallback()->size() -1) { + return get_gui_list_active_withFallback()->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_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_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}; + 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_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_withFallback()->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_withFallback()->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_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 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_IMAGE_DECLARE(gradientLeft); LV_IMAGE_DECLARE(gradientRight); -void getBreadcrumpPosition(uint8_t* breadcrumpPosition, std::string nameOfTab) { - *breadcrumpPosition = 0; - - gui_list currentGUIlist = get_gui_list(get_currentScene()); - uint8_t counter = 0; - for (std::vector::iterator it = currentGUIlist->begin() ; it != currentGUIlist->end(); ++it) { - counter++; - if (*it == nameOfTab) { - *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_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); @@ -303,33 +342,52 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv btn = lv_button_create(panel); lv_obj_remove_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 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_withFallback(MAIN_GUI_LIST)->size(); + int8_t breadcrumpMainGuiListStartPositionX = (-1) * (breadcrumpMainGuiListLength -1) * (breadcrumpDotSize + breadcrumpDotDistance) / 2; + 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()); + #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 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; + breadcrumpPosition = gui_state->gui_on_tab[i].gui_list_index +1; // Create actual buttons for every tab lv_obj_t* btn = lv_button_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 (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); 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); @@ -349,28 +407,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; jsize()-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_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); @@ -423,71 +516,81 @@ 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); + +// 1. tab creation on startup (called by init_gui()) +// 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) { + + Serial.printf("Startup: try to resume at scene \"%s\" with GUI \"%s\"\r\n", gui_memoryOptimizer_getActiveSceneName().c_str(), gui_memoryOptimizer_getActiveGUIname().c_str()); + + // 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(); + gui_memoryOptimizer_getLastActiveGUIlistIndex(); + + // 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_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; + } + } + + // 2. set gui_list_indices and the tab to be activated + if ((gui_list_index >= 0) && (gui_list_index < get_gui_list_active_withFallback()->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); + +} + +// 2. tab creation after sliding (called by tabview_tab_changed_event_cb()) +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. @@ -498,25 +601,103 @@ void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, // lv_screen_load(newscr); // lv_obj_delete(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); + +} + +// 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"); + + if (gui_state.last_active_gui_list != newGUIlist) { + // 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(newGUIlist); + setGUIlistIndicesToBeShown_forFirstGUIinGUIlist(&gui_state); + + // 3. create content + gui_memoryOptimizer_doContentCreation(tabview, panel, img1, img2, &gui_state); + +} + +// 4. navigate to a specific GUI in gui_list +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) { + + Serial.printf("--- Will navigate to specific GUI\r\n"); + + 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; + } + + 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(); *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_image_create(lv_screen_active()); *img2 = lv_image_create(lv_screen_active()); - 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); @@ -524,6 +705,11 @@ void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, // Initialize scroll position of the page indicator lv_obj_send_event(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 83a87c4..f163c54 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h @@ -1,6 +1,28 @@ #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); +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); -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/gui/guiRegistry.cpp b/Platformio/src/applicationInternal/gui/guiRegistry.cpp index 29acd28..ed628a4 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,25 @@ 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)}); + 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 cbe541f..26b81a6 100644 --- a/Platformio/src/applicationInternal/gui/guiRegistry.h +++ b/Platformio/src/applicationInternal/gui/guiRegistry.h @@ -22,19 +22,33 @@ #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 + ); + +void setKeysForAllRegisteredGUIsAndScenes(); \ No newline at end of file diff --git a/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp b/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp index eeb20b3..fff5de7 100644 --- a/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp +++ b/Platformio/src/applicationInternal/hardware/hardwarePresenter.cpp @@ -26,17 +26,29 @@ 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); +} +int get_lastActiveGUIlistIndex() { + return get_lastActiveGUIlistIndex_HAL(); +} +void set_lastActiveGUIlistIndex(int aGUIlistIndex) { + set_lastActiveGUIlistIndex_HAL(aGUIlistIndex); } // --- user led --------------------------------------------------------------- diff --git a/Platformio/src/applicationInternal/hardware/hardwarePresenter.h b/Platformio/src/applicationInternal/hardware/hardwarePresenter.h index 1145f1c..74c8e48 100644 --- a/Platformio/src/applicationInternal/hardware/hardwarePresenter.h +++ b/Platformio/src/applicationInternal/hardware/hardwarePresenter.h @@ -10,10 +10,14 @@ 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); +int get_lastActiveGUIlistIndex(); +void set_lastActiveGUIlistIndex(int aGUIlistIndex); // --- 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/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/sceneHandler.cpp b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp index 8e35b94..3e77910 100644 --- a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp @@ -5,17 +5,71 @@ #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() { + if ((SceneLabel != NULL) && sceneExists(gui_memoryOptimizer_getActiveSceneName())) { + lv_label_set_text(SceneLabel, gui_memoryOptimizer_getActiveSceneName().c_str()); + } +} + +void showSpecificGUI(GUIlists GUIlist, std::string GUIname); + void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = "") { + auto current = commandData.commandPayloads.begin(); + std::string scene_name = *current; + + // --- 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"); + showSpecificGUI(MAIN_GUI_LIST, tabName_sceneSelection); + 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 (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(gui_memoryOptimizer_getActiveTabID() -1, LV_ANIM_ON, true); + } + + } else if (scene_name == scene_gui_next) { + 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(gui_memoryOptimizer_getActiveTabID() +1, LV_ANIM_ON, true); + } + + } + 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"); - auto current = commandData.commandPayloads.begin(); - std::string scene_name = *current; // we can have a second payload std::string isForcePayload = ""; ++current; @@ -23,49 +77,20 @@ void handleScene(uint16_t command, commandData commandData, std::string addition isForcePayload = *current; } - // 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); - 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) { - 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); - } - - } else if (scene_name == scene_gui_next) { - if (!gui_memoryOptimizer_isTabIDInMemory(currentTabID +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); - } - - } - return; - } - // 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()); 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 +103,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 +119,47 @@ 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()); +void showSpecificGUI(GUIlists GUIlist, std::string GUIname) { + gui_list gui_list_for_search = get_gui_list_withFallback(GUIlist); + + // 1. search for gui in the gui list + int gui_list_index = -1; + 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 < gui_list_for_search->size())) { + guis_doTabCreationForSpecificGUI(GUIlist, gui_list_index); + + } else { + // gui was not found + 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/sceneHandler.h b/Platformio/src/applicationInternal/scenes/sceneHandler.h index 16c6c7b..5aba73d 100644 --- a/Platformio/src/applicationInternal/scenes/sceneHandler.h +++ b/Platformio/src/applicationInternal/scenes/sceneHandler.h @@ -3,5 +3,6 @@ #include #include "applicationInternal/commandHandler.h" +void setLabelActiveScene(); void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = ""); -void setLabelCurrentScene(); +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 c1be9d8..81df397 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp @@ -1,28 +1,13 @@ #include #include -#include "applicationInternal/commandHandler.h" -#include "applicationInternal/scenes/sceneRegistry.h" +#include "applicationInternal/gui/guiMemoryOptimizer.h" +#include "applicationInternal/gui/guiRegistry.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; - 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; @@ -54,15 +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. 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. - // 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(); - } + setKeysForAllRegisteredGUIsAndScenes(); } @@ -90,8 +67,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 current scene has a definition for it - if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_repeatModes->count(keyChar) > 0)) { + // 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 + } 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); @@ -114,8 +97,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 current scene has a definition for it - if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_commands_short->count(keyChar) > 0)) { + // 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 + } 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); @@ -139,8 +128,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 current scene has a definition for it - if ((registered_scenes.count(sceneName) > 0) && (registered_scenes.at(sceneName).this_key_commands_long->count(keyChar) > 0)) { + // 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 + } 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); @@ -162,40 +157,58 @@ uint16_t get_command_long(std::string sceneName, char keyChar) { } -gui_list get_gui_list(std::string sceneName) { +gui_list get_gui_list_withFallback(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). - // 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 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 (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_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) { try { - // look if the current 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; diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.h b/Platformio/src/applicationInternal/scenes/sceneRegistry.h index dbc8f56..8ff50c4 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.h +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.h @@ -1,12 +1,9 @@ #pragma once #include -#include -#include #include #include "applicationInternal/keys.h" - -extern bool useSceneGUIlist; +#include "applicationInternal/gui/guiMemoryOptimizer.h" typedef std::vector t_gui_list; typedef std::vector t_scene_list; @@ -14,12 +11,23 @@ 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; +// 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, @@ -37,7 +45,9 @@ 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_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/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/devices/misc/device_smarthome/gui_smarthome.cpp b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp index d1ffdf3..72bf376 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_IMAGE_DECLARE(lightbulb); @@ -20,6 +22,12 @@ static bool lightToggleBstate = false; static int32_t sliderAvalue = 0; 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; @@ -158,6 +166,23 @@ void notify_tab_before_delete_smarthome(void) { sliderBvalue = lv_slider_get_value(sliderB); } -void register_gui_smarthome(void){ - register_gui(std::string(tabName_smarthome), & create_tab_content_smarthome, & notify_tab_before_delete_smarthome); +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, + & gui_setKeys_smarthome, + & key_repeatModes_smarthome, + & key_commands_short_smarthome, + & key_commands_long_smarthome + ); + + register_command(&GUI_SMARTHOME_ACTIVATE, makeCommandData(GUI, {std::to_string(MAIN_GUI_LIST), 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/guis/gui_numpad.cpp b/Platformio/src/guis/gui_numpad.cpp index fdc4831..dc42d65 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..13962b7 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" @@ -102,6 +103,19 @@ int main(int argc, char *argv[]) { #endif register_keyboardCommands(); + // Register the GUIs. They will be displayed in the order they have been registered. + register_gui_sceneSelection(); + register_gui_irReceiver(); + register_gui_settings(); + 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_yamahaAmp, tabName_sceneSelection, tabName_smarthome, tabName_settings, tabName_irReceiver}; + #endif + // register the scenes and their key_commands_* register_scene_defaultKeys(); register_scene_TV(); @@ -112,20 +126,9 @@ int main(int argc, char *argv[]) { // 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(); - register_gui_settings(); - register_gui_appleTV(); - register_gui_numpad(); - register_gui_smarthome(); - // 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}; - #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 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;