From 90a098f3c8770f75bc1c3b3f98e294ec87c5afd3 Mon Sep 17 00:00:00 2001 From: KlausMu Date: Mon, 25 Mar 2024 22:08:51 +0100 Subject: [PATCH] gui for scene selection --- .../preferencesStorage_hal_windows_linux.cpp | 13 +- Platformio/platformio.ini | 5 + .../applicationInternal/commandHandler.cpp | 2 + .../src/applicationInternal/commandHandler.h | 2 + .../src/applicationInternal/gui/guiBase.cpp | 47 ++++- .../src/applicationInternal/gui/guiBase.h | 3 + .../gui/guiMemoryOptimizer.cpp | 183 +++++++++++++----- .../gui/guiMemoryOptimizer.h | 2 +- .../applicationInternal/gui/guiRegistry.cpp | 10 +- .../src/applicationInternal/gui/guiRegistry.h | 1 - Platformio/src/applicationInternal/keys.cpp | 2 - .../scenes/sceneHandler.cpp | 62 ++++-- .../scenes/sceneRegistry.cpp | 101 +++++++++- .../scenes/sceneRegistry.h | 16 +- .../TV/device_samsungTV/device_samsungTV.cpp | 4 +- .../TV/device_samsungTV/device_samsungTV.h | 2 +- .../misc/device_smarthome/gui_smarthome.cpp | 2 +- .../devices/misc/device_specialCommands.cpp | 1 - .../src/devices/misc/device_specialCommands.h | 1 - Platformio/src/guis/gui_sceneSelection.cpp | 130 +++++++++++++ Platformio/src/guis/gui_sceneSelection.h | 6 + Platformio/src/guis/gui_settings.cpp | 4 +- Platformio/src/main.cpp | 27 ++- Platformio/src/scenes/scene_TV.cpp | 13 +- Platformio/src/scenes/scene_TV.h | 2 + Platformio/src/scenes/scene__defaultKeys.cpp | 21 +- Platformio/src/scenes/scene__defaultKeys.h | 7 + Platformio/src/scenes/scene_allOff.cpp | 8 +- Platformio/src/scenes/scene_allOff.h | 2 + Platformio/src/scenes/scene_appleTV.cpp | 86 ++++++++ Platformio/src/scenes/scene_appleTV.h | 12 ++ Platformio/src/scenes/scene_chromecast.cpp | 10 +- Platformio/src/scenes/scene_chromecast.h | 2 + Platformio/src/scenes/scene_fireTV.cpp | 11 +- Platformio/src/scenes/scene_fireTV.h | 2 + README.md | 5 +- 36 files changed, 684 insertions(+), 123 deletions(-) create mode 100644 Platformio/src/guis/gui_sceneSelection.cpp create mode 100644 Platformio/src/guis/gui_sceneSelection.h create mode 100644 Platformio/src/scenes/scene_appleTV.cpp create mode 100644 Platformio/src/scenes/scene_appleTV.h diff --git a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp index 864771a..af5d257 100644 --- a/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp +++ b/Platformio/hardware/windows_linux/preferencesStorage_hal_windows_linux.cpp @@ -9,13 +9,22 @@ void save_preferences_HAL(void) { } std::string get_currentScene_HAL() { - return currentScene; + // if (currentScene == "") { + // // set here something if you need it for a test at startup + // return "Apple TV"; + // } else + {return currentScene;} + } void set_currentScene_HAL(std::string aCurrentScene) { currentScene = aCurrentScene; } std::string get_currentGUIname_HAL(){ - return currentGUIname; + // if (currentGUIname == "") { + // // set here something if you need it for a test at startup + // return "IR Receiver"; // "Numpad"; // "Apple TV"; + // } else + {return currentGUIname;} } void set_currentGUIname_HAL(std::string aCurrentGUIname) { currentGUIname = aCurrentGUIname; diff --git a/Platformio/platformio.ini b/Platformio/platformio.ini index ed93a0a..28d7766 100644 --- a/Platformio/platformio.ini +++ b/Platformio/platformio.ini @@ -23,6 +23,7 @@ build_flags = -D ENABLE_KEYBOARD_MQTT=0 -D ENABLE_BLUETOOTH=1 -D ENABLE_KEYBOARD_BLE=1 + -D USE_SCENE_SPECIFIC_GUI_LIST=1 -D SCR_WIDTH=${env.custom_screen_width} -D SCR_HEIGHT=${env.custom_screen_heigth} ;-- lvgl ------------------------------------------------------------------ @@ -68,6 +69,10 @@ build_flags = ; lvgl variant 2: ; or define where lv_conf.h is, relative to the `lvgl` folder ;-D LV_CONF_PATH=../../../../src/gui_general_and_keys/lv_conf.h + ; --- interesting lvgl debug infos (OSD) + ;-D LV_USE_PERF_MONITOR=1 + ;-D LV_USE_MEM_MONITOR=1 + ;-D LV_USE_REFR_DEBUG=1 [env:esp32] platform = espressif32 diff --git a/Platformio/src/applicationInternal/commandHandler.cpp b/Platformio/src/applicationInternal/commandHandler.cpp index c881e75..a9924b5 100644 --- a/Platformio/src/applicationInternal/commandHandler.cpp +++ b/Platformio/src/applicationInternal/commandHandler.cpp @@ -12,6 +12,8 @@ // show received IR and MQTT messages #include "guis/gui_irReceiver.h" +uint16_t COMMAND_UNKNOWN; + uint16_t KEYBOARD_DUMMY_UP ; //"Keyboard_dummy_up" uint16_t KEYBOARD_DUMMY_DOWN ; //"Keyboard_dummy_down" uint16_t KEYBOARD_DUMMY_RIGHT ; //"Keyboard_dummy_right" diff --git a/Platformio/src/applicationInternal/commandHandler.h b/Platformio/src/applicationInternal/commandHandler.h index 1bf73a1..75b0a6b 100644 --- a/Platformio/src/applicationInternal/commandHandler.h +++ b/Platformio/src/applicationInternal/commandHandler.h @@ -7,6 +7,8 @@ #include "devices/keyboard/device_keyboard_mqtt/device_keyboard_mqtt.h" #include "devices/keyboard/device_keyboard_ble/device_keyboard_ble.h" +extern uint16_t COMMAND_UNKNOWN; + /* Depending on which keyboard is enabled (BLE or MQTT), we define KEYBOARD_UP, KEYBOARD_DOWN and so on. These defines are used in keys.cpp, gui*.cpp and commandHandler.cpp diff --git a/Platformio/src/applicationInternal/gui/guiBase.cpp b/Platformio/src/applicationInternal/gui/guiBase.cpp index 9c310b2..750e6f7 100644 --- a/Platformio/src/applicationInternal/gui/guiBase.cpp +++ b/Platformio/src/applicationInternal/gui/guiBase.cpp @@ -2,6 +2,9 @@ #include "applicationInternal/hardware/hardwarePresenter.h" #include "applicationInternal/memoryUsage.h" #include "applicationInternal/gui/guiMemoryOptimizer.h" +// for changing to scene Selection gui +#include "applicationInternal/commandHandler.h" +#include "scenes/scene__defaultKeys.h" lv_color_t color_primary = lv_color_hex(0x303030); // gray lv_obj_t* MemoryUsageLabel = NULL; @@ -26,10 +29,26 @@ lv_style_t style_red_border; #endif void guis_doTabCreationAtStartup(); -void guis_doAfterSliding(int oldTabID, int newTabID); +void guis_doAfterSliding(int oldTabID, int newTabID, bool newGuiList); // Helper Functions ----------------------------------------------------------------------------------------------------------------------- +// callback when sceneLabel or pageIndicator was clicked +void sceneLabel_or_pageIndicator_event_cb(lv_event_t* e) { + Serial.println("- Scene selection: sceneLabel or pageIndicator clicked received for navigating to scene selection page"); + executeCommand(SCENE_SELECTION); +} + +// callback for swipe down event to navigate to the scene selection page +void screen_gesture_event_cb(lv_event_t* e) { + lv_obj_t* screen = lv_event_get_current_target(e); + lv_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act()); + if (dir == LV_DIR_BOTTOM) { + Serial.println("- Scene selection: swipe down received for navigating to scene selection page"); + executeCommand(SCENE_SELECTION); + } +} + // Set the page indicator (panel) scroll position relative to the tabview content scroll position // this is a callback if the CONTENT of the tabview is scrolled (LV_EVENT_SCROLL) void tabview_content_is_scrolling_event_cb(lv_event_t* e){ @@ -62,7 +81,7 @@ static void tabview_animation_ready_cb(lv_anim_t* a) { // 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); + // guis_doAfterSliding(oldTabID, currentTabID, false); waitBeforeActionAfterSlidingAnimationEnded = true; waitBeforeActionAfterSlidingAnimationEnded_timerStart = millis(); @@ -77,7 +96,7 @@ void tabview_tab_changed_event_cb(lv_event_t* e) { oldTabID = currentTabID; currentTabID = lv_tabview_get_tab_act(lv_event_get_target(e)); - // Wait until the animation ended, then call "guis_doAfterSliding(oldTabID, currentTabID);" + // Wait until the animation ended, then call "guis_doAfterSliding(oldTabID, currentTabID, false);" // https://forum.lvgl.io/t/delete-a-tab-after-the-tabview-scroll-animation-is-complete/3155/4 lv_obj_t* myTabview = lv_event_get_target(e); lv_obj_t* tabContainer = lv_tabview_get_content(myTabview); @@ -91,7 +110,7 @@ void tabview_tab_changed_event_cb(lv_event_t* e) { } 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); + guis_doAfterSliding(oldTabID, currentTabID, false); } } } @@ -131,6 +150,10 @@ void init_gui(void) { init_gui_memoryUsage_bar(); // status bar init_gui_status_bar(); + + // register callback for swipe down event to navigate to the scene selection page + lv_obj_add_event_cb(lv_scr_act(), screen_gesture_event_cb, LV_EVENT_GESTURE, NULL); + } int panelHeight; @@ -205,6 +228,7 @@ void init_gui_memoryUsage_bar() { void init_gui_status_bar() { // Create a status bar at the top ------------------------------------------------------------------------- statusbar = lv_btn_create(lv_scr_act()); + lv_obj_clear_flag(statusbar, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_size(statusbar, SCR_WIDTH, statusbarHeight); lv_obj_set_style_shadow_width(statusbar, 0, LV_PART_MAIN); lv_obj_set_style_bg_color(statusbar, lv_color_black(), LV_PART_MAIN); @@ -231,6 +255,9 @@ void init_gui_status_bar() { lv_label_set_text(SceneLabel, ""); 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_add_event_cb(SceneLabel, sceneLabel_or_pageIndicator_event_cb, LV_EVENT_CLICKED, NULL); + // Battery ---------------------------------------------------------------------- BattPercentageLabel = lv_label_create(statusbar); lv_label_set_text(BattPercentageLabel, ""); @@ -251,12 +278,12 @@ void gui_loop(void) { waitBeforeActionAfterSlidingAnimationEnded = false; } else if (waitOneLoop) { waitOneLoop = false; - guis_doAfterSliding(oldTabID, currentTabID); + guis_doAfterSliding(oldTabID, currentTabID, false); }; // // 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); + // guis_doAfterSliding(oldTabID, currentTabID, false); // waitBeforeActionAfterSlidingAnimationEnded = false; // } // } @@ -267,11 +294,13 @@ void gui_loop(void) { void guis_doTabCreationAtStartup() { gui_memoryOptimizer_prepare_startup(); - guis_doAfterSliding(-1, -1); + guis_doAfterSliding(-1, -1, false); } -void guis_doAfterSliding(int oldTabID, int newTabID) { - gui_memoryOptimizer_doAfterSliding_deletionAndCreation(&tabview, oldTabID, newTabID, &panel, &img1, &img2); +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); doLogMemoryUsage(); } diff --git a/Platformio/src/applicationInternal/gui/guiBase.h b/Platformio/src/applicationInternal/gui/guiBase.h index 9540b94..20c8f84 100644 --- a/Platformio/src/applicationInternal/gui/guiBase.h +++ b/Platformio/src/applicationInternal/gui/guiBase.h @@ -30,8 +30,11 @@ 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 setActiveTab(uint32_t index, lv_anim_enable_t anim_en); // 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 6f75154..913a15a 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.cpp @@ -1,13 +1,16 @@ #include #include "applicationInternal/gui/guiBase.h" #include "applicationInternal/gui/guiRegistry.h" +#include "applicationInternal/scenes/sceneRegistry.h" #include "applicationInternal/hardware/hardwarePresenter.h" struct tab_in_memory { lv_obj_t* tab; int listIndex; + std::string guiName; }; -tab_in_memory tabs_in_memory[3] = {{NULL, -1}, {NULL, -1}, {NULL, -1}}; +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}; void notify_active_tabs_before_delete() { @@ -19,7 +22,9 @@ void notify_active_tabs_before_delete() { continue; } - nameOfTab = list_of_guis_to_be_shown.at(tabs_in_memory[index].listIndex); + // For deletion, do not use the listIndex, 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; 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) { @@ -42,9 +47,9 @@ void clear_tabview(lv_obj_t* tabview) { } // 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}; + tabs_in_memory[0] = {NULL, -1, ""}; + tabs_in_memory[1] = {NULL, -1, ""}; + tabs_in_memory[2] = {NULL, -1, ""}; } @@ -79,7 +84,8 @@ lv_obj_t* create_tabview() { lv_obj_t* create_panel() { // Create a page indicator at the bottom ------------------------------------------------------------------ lv_obj_t* panel = lv_obj_create(lv_scr_act()); - lv_obj_clear_flag(panel, LV_OBJ_FLAG_CLICKABLE); // This indicator will not be clickable + lv_obj_clear_flag(panel, LV_OBJ_FLAG_CLICKABLE); // This indicator will not be clickable + lv_obj_clear_flag(panel, LV_OBJ_FLAG_SCROLLABLE); // This indicator will not be scrollable lv_obj_set_size(panel, SCR_WIDTH, panelHeight); lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW); lv_obj_align(panel, LV_ALIGN_BOTTOM_MID, 0, 0); @@ -91,8 +97,8 @@ lv_obj_t* create_panel() { std::string get_name_of_gui_to_be_shown(int index) { if (index == -1) { return ""; - } else if (index <= list_of_guis_to_be_shown.size() -1) { - return list_of_guis_to_be_shown.at(index); + } else if (index <= get_gui_list(get_currentScene())->size() -1) { + return get_gui_list(get_currentScene())->at(index); } else { return ""; } @@ -107,6 +113,8 @@ void create_new_tab(lv_obj_t* tabview, uint32_t tabs_in_memory_index) { 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()); } else { Serial.printf(" Will create tab with name \"%s\" at index %d\r\n", nameOfTab.c_str(), tabs_in_memory_index); + // 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()); // let the gui create it's content @@ -117,7 +125,7 @@ void create_new_tab(lv_obj_t* tabview, uint32_t tabs_in_memory_index) { 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: list_of_guis_to_be_shown: 0 1 2 3 4 + 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 @@ -132,8 +140,8 @@ void doTabCreation_strategyMax3(lv_obj_t* tabview, uint32_t oldTabID, uint32_t n if ((oldTabID == -1) && (newTabID == -1)) { // This is the initialization after the ESP32 has booted. - if ((tabs_in_memory_previous_listIndex[0] < list_of_guis_to_be_shown.size()) && (tabs_in_memory_previous_listIndex[0] != -1)) { - // In gui_memoryOptimizer_prepare_startup, the index of get_currentGUIname() in list_of_guis_to_be_shown was saved, if found. + 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) { @@ -141,10 +149,10 @@ void doTabCreation_strategyMax3(lv_obj_t* tabview, uint32_t oldTabID, uint32_t n 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, list_of_guis_to_be_shown.size() >= 2 ? 1 : -1}; + 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 == list_of_guis_to_be_shown.size() -1) { + } 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}; @@ -160,11 +168,11 @@ void doTabCreation_strategyMax3(lv_obj_t* tabview, uint32_t oldTabID, uint32_t n tabToBeActivated = 1; } } else { - Serial.printf(" Startup: cannot resume old state, so we will show the first tabs from \"list_of_guis_to_be_shown\" as initial state\r\n"); + 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, list_of_guis_to_be_shown.size() != 0 ? 0 : -1}; + 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, list_of_guis_to_be_shown.size() >= 2 ? 1 : -1}; + tabs_in_memory[1] = {NULL, get_gui_list(get_currentScene())->size() >= 2 ? 1 : -1}; tabs_in_memory[2] = {NULL, -1}; tabToBeActivated = 0; } @@ -193,7 +201,7 @@ void doTabCreation_strategyMax3(lv_obj_t* tabview, uint32_t oldTabID, uint32_t n } else { oldListIndex = tabs_in_memory_previous_listIndex[1]; } - if (oldListIndex == list_of_guis_to_be_shown.size() -2) { + if (oldListIndex == get_gui_list(get_currentScene())->size() -2) { // next state is the "last state" tabs_in_memory[0] = {NULL, oldListIndex}; tabs_in_memory[1] = {NULL, oldListIndex +1}; @@ -212,9 +220,9 @@ void doTabCreation_strategyMax3(lv_obj_t* tabview, uint32_t oldTabID, uint32_t n for (int i=0; i<3; i++) { create_new_tab(tabview, i); } - - if (list_of_guis_to_be_shown.size() > 0) { - std::string nameOfNewActiveTab = list_of_guis_to_be_shown.at(tabs_in_memory[tabToBeActivated].listIndex); + + if (get_gui_list(get_currentScene())->size() > 0) { + std::string nameOfNewActiveTab = get_gui_list(get_currentScene())->at(tabs_in_memory[tabToBeActivated].listIndex); Serial.printf(" New visible tab is \"%s\"\r\n", nameOfNewActiveTab.c_str()); // set the tab we swiped to as active @@ -227,10 +235,24 @@ void doTabCreation_strategyMax3(lv_obj_t* tabview, uint32_t oldTabID, uint32_t n LV_IMG_DECLARE(gradientLeft); LV_IMG_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) { Serial.printf(" Will fill panel with page indicators\r\n"); - if (list_of_guis_to_be_shown.size() == 0) { + if (get_gui_list(get_currentScene())->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); @@ -250,14 +272,14 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv There needs to be two more screen indicators because of their different size (158 for page indicator, 240 for whole tab) In some cases they need to have color black, if they are before the first tab or after the last tab. In all other cases, they have color "color_primary". See this list: - example: list_of_guis_to_be_shown: 0 1 2 3 4 + example: gui_list: 0 1 2 3 4 in memory color active 0 1 -1 b p p p 0 <- first state, special case - also the initial state 0 1 2 b p p p p 1 1 2 3 p p p p p 1 2 3 4 p p p p b 1 3 4 -1 p p p b 1 <- last state, special case -*/ +*/ // first page indicator before the first tab btn = lv_btn_create(panel); lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); @@ -268,21 +290,54 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); } + uint8_t breadcrumpLength = get_gui_list(get_currentScene())->size(); + uint8_t breadcrumpDotSize = 8; // should be an even number + uint8_t breadcrumpDotDistance = 2; // should be an even number + int8_t breadcrumpStartPositionX = (-1) * (breadcrumpLength -1) * (breadcrumpDotSize + breadcrumpDotDistance) / 2; + // create the panel content for the three guis (or less) which are currently in memory std::string nameOfTab; + uint8_t breadcrumpPosition; for (int i=0; i<3; i++) { if (tabs_in_memory[i].listIndex != -1) { - nameOfTab = get_name_of_gui_to_be_shown(tabs_in_memory[i].listIndex); + nameOfTab = tabs_in_memory[i].guiName; + getBreadcrumpPosition(&breadcrumpPosition, nameOfTab); - // Create actual (non-clickable) buttons for every tab + // Create actual buttons for every tab lv_obj_t* btn = lv_btn_create(panel); - lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); + // only if this is the button for the currently active tab, make it clickable to get to scene selection gui + if (nameOfTab == get_currentGUIname()) { + lv_obj_add_flag(btn, LV_OBJ_FLAG_CLICKABLE); + lv_obj_add_event_cb(btn, sceneLabel_or_pageIndicator_event_cb, LV_EVENT_CLICKED, NULL); + } lv_obj_set_size(btn, 150, lv_pct(100)); - lv_obj_t* label = lv_label_create(btn); - lv_label_set_text_fmt(label, "%s", nameOfTab.c_str()); - lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); + lv_obj_remove_style(btn, NULL, LV_STATE_PRESSED); 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)) { 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); } - + // This small hidden button enables the page indicator to scroll further btn = lv_btn_create(panel); lv_obj_set_size(btn, 50, lv_pct(100)); lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN); - + // creation of style was moved to init_gui(void) // otherwise repeated calls of lv_style_init will lead to a memory leak of about 46 bytes each time // https://docs.lvgl.io/8.3/overview/style.html?highlight=lv_style_t#initialize-styles-and-set-get-properties @@ -333,54 +388,86 @@ void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv } void gui_memoryOptimizer_prepare_startup() { - // find index of get_currentGUIname() in list_of_guis_to_be_shown - 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; } } + // 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; + } + } -void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, int oldTabID, int newTabID, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** 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) { // 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, list_of_guis_to_be_shown.at(tabs_in_memory[oldTabID].listIndex).c_str(), - newTabID, list_of_guis_to_be_shown.at(tabs_in_memory[newTabID].listIndex).c_str()); + 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()); } - - // save the ids of the tabs we had in memory before + + // 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; } - + // the old tabs need to be notified that they will be deleted so that they can persist their state if needed - if (!isInitialization) notify_active_tabs_before_delete(); - // clear current tabview + notify_active_tabs_before_delete(); + // clear current tabview clear_tabview(*tabview); // clear current panel for page indicator clear_panel(*panel, *img1, *img2); // 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. - // lv_obj_t * oldscr = lv_scr_act(); + // lv_obj_t* oldscr = lv_scr_act(); // // create new screen - // lv_obj_t * newscr = lv_obj_create(NULL); + // lv_obj_t* newscr = lv_obj_create(NULL); // // load this new screen // lv_scr_load(newscr); // lv_obj_del(oldscr); + if (newGuiList) { + // If we are switching to a new gui list, then we need to set tabs_in_memory_previous_listIndex[0] = -1; + // Doing so, doTabCreation_strategyMax3() knows that we cannot resume an old state. + tabs_in_memory_previous_listIndex[0] = -1; + } + // recreate the tabview lv_obj_t* newTabview = create_tabview(); *tabview = newTabview; @@ -401,4 +488,6 @@ void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, // Initialize scroll position of the page indicator lv_event_send(lv_tabview_get_content(*tabview), LV_EVENT_SCROLL, NULL); + 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 e3a2a13..ddf4372 100644 --- a/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h +++ b/Platformio/src/applicationInternal/gui/guiMemoryOptimizer.h @@ -1,4 +1,4 @@ #pragma once void gui_memoryOptimizer_prepare_startup(); -void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, int oldTabID, int newTabID, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** 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); diff --git a/Platformio/src/applicationInternal/gui/guiRegistry.cpp b/Platformio/src/applicationInternal/gui/guiRegistry.cpp index e11c5d9..fa9f8e5 100644 --- a/Platformio/src/applicationInternal/gui/guiRegistry.cpp +++ b/Platformio/src/applicationInternal/gui/guiRegistry.cpp @@ -6,13 +6,11 @@ #include "guiRegistry.h" #include "applicationInternal/gui/guiBase.h" #include "applicationInternal/hardware/hardwarePresenter.h" +#include "scenes/scene__defaultKeys.h" // ------------------------------------------------------------------------------------ // this is a map of the registered_guis that can be accessed by name std::map registered_guis_byName_map; -// This is the list of the guis that we want to be available when swiping. Need not to be all the guis that have been registered, can be only a subset. -// You can swipe through these guis. Will be in the order you place them here in the vector. -std::vector list_of_guis_to_be_shown; // ------------------------------------------------------------------------------------ @@ -29,8 +27,8 @@ void register_gui(std::string a_name, create_tab_content a_create_tab_content, n // put the gui_definition in a map that can be accessed by name registered_guis_byName_map[a_name] = new_gui_definition; - // By default, put all registered guis in the sequence of guis to be shown - // Later we will have scene specific sequences of guis - list_of_guis_to_be_shown.insert(list_of_guis_to_be_shown.end(), {std::string(a_name)}); + // By default, put all registered guis in the sequence of guis to be shown of the default scene + // Can be overwritten by scenes to have their own gui_list. + main_gui_list.insert(main_gui_list.end(), {std::string(a_name)}); } diff --git a/Platformio/src/applicationInternal/gui/guiRegistry.h b/Platformio/src/applicationInternal/gui/guiRegistry.h index d691a85..cbe541f 100644 --- a/Platformio/src/applicationInternal/gui/guiRegistry.h +++ b/Platformio/src/applicationInternal/gui/guiRegistry.h @@ -36,6 +36,5 @@ struct gui_definition { }; extern std::map registered_guis_byName_map; -extern std::vector list_of_guis_to_be_shown; void register_gui(std::string a_name, create_tab_content a_create_tab_content, notify_tab_before_delete a_notify_tab_before_delete); diff --git a/Platformio/src/applicationInternal/keys.cpp b/Platformio/src/applicationInternal/keys.cpp index 5700bcc..75f2241 100644 --- a/Platformio/src/applicationInternal/keys.cpp +++ b/Platformio/src/applicationInternal/keys.cpp @@ -1,7 +1,5 @@ #include -#include "devices/misc/device_specialCommands.h" #include "applicationInternal/scenes/sceneRegistry.h" -#include "applicationInternal/scenes/sceneHandler.h" #include "applicationInternal/commandHandler.h" #include "applicationInternal/hardware/hardwarePresenter.h" diff --git a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp index 73c1426..18cd5dd 100644 --- a/Platformio/src/applicationInternal/scenes/sceneHandler.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneHandler.cpp @@ -4,11 +4,30 @@ #include "applicationInternal/scenes/sceneRegistry.h" #include "applicationInternal/hardware/hardwarePresenter.h" #include "applicationInternal/commandHandler.h" +#include "scenes/scene__defaultKeys.h" void handleScene(uint16_t command, commandData commandData, std::string additionalPayload = "") { + // 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; + if (current != commandData.commandPayloads.end()) { + isForcePayload = *current; + } + + // do not really switch scene, but show sceneSelection gui. From that on, we are in the main_gui_list. + if (scene_name == scene_name_selection) { + useSceneGUIlist = false; + guis_doAfterSliding(-1, -1, true); + return; + } // check if we know the new scene if (!sceneExists(scene_name)) { @@ -18,30 +37,49 @@ void handleScene(uint16_t command, commandData commandData, std::string addition Serial.printf("scene: will switch from old scene %s to new scene %s\r\n", get_currentScene().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"))) { + 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"))) { + Serial.printf("scene: scene is already active, but FORCE was set, so start scene again\r\n"); + callEndAndStartSequences = true; + } else { + // this is the default when switching to a different scene + callEndAndStartSequences = true; + } + if (SceneLabel != NULL) {lv_label_set_text(SceneLabel, "changing...");} gui_loop(); - // 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()); - - } 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 (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()); + + } 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()); + } + } + // start new scene + Serial.printf("scene: will call start sequence for scene %s\r\n", scene_name.c_str()); + scene_start_sequence_from_registry(scene_name); } - // start new scene - Serial.printf("scene: will call start sequence for scene %s\r\n", scene_name.c_str()); - scene_start_sequence_from_registry(scene_name); - set_currentScene(scene_name); if (SceneLabel != NULL) {lv_label_set_text(SceneLabel, get_currentScene().c_str());} Serial.printf("scene: scene handling finished, new scene %s is active\r\n", get_currentScene().c_str()); + + useSceneGUIlist = true; + // recreate the gui based on the current scene + guis_doAfterSliding(-1, -1, true); } void setLabelCurrentScene() { diff --git a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp index f4aedf4..22b3950 100644 --- a/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp +++ b/Platformio/src/applicationInternal/scenes/sceneRegistry.cpp @@ -1,11 +1,16 @@ #include #include -#include "devices/misc/device_specialCommands.h" +#include "applicationInternal/commandHandler.h" #include "applicationInternal/scenes/sceneRegistry.h" #include "applicationInternal/hardware/hardwarePresenter.h" // scenes #include "scenes/scene__defaultKeys.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; @@ -14,9 +19,12 @@ struct scene_definition { 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; void register_scene( std::string a_scene_name, @@ -25,17 +33,27 @@ void register_scene( scene_end_sequence a_scene_end_sequence, key_repeatModes a_key_repeatModes, key_commands_short a_key_commands_short, - key_commands_long a_key_commands_long) { + key_commands_long a_key_commands_long, + gui_list a_gui_list, + uint16_t a_activate_scene_command) { + // put the scene_definition in a map that can be accessed by name registered_scenes[a_scene_name] = scene_definition{ a_scene_setKeys, a_scene_start_sequence, a_scene_end_sequence, a_key_repeatModes, a_key_commands_short, - a_key_commands_long + a_key_commands_long, + a_gui_list, + a_activate_scene_command }; + // Additionally, put all registered scenes in a sequence of scenes to be shown in the sceneSelection gui. + // Exactly in the order they have been registered. + // 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. @@ -98,17 +116,17 @@ 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)) { - Serial.printf("get_command_short: will use key from scene %s\r\n", sceneName.c_str()); + // 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); // look if there is a default definition } else if (key_commands_short_default.count(keyChar) > 0) { - Serial.printf("get_command_short: will use default key\r\n"); + // Serial.printf("get_command_short: will use default key\r\n"); return key_commands_short_default.at(keyChar); // no key definition found } else { - Serial.printf("get_command_short: WARNING no key definition found\r\n"); + // Serial.printf("get_command_short: WARNING no key definition found\r\n"); return COMMAND_UNKNOWN; } } @@ -123,17 +141,17 @@ 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)) { - Serial.printf("get_command_long: will use key from scene %s\r\n", sceneName.c_str()); + // 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); // look if there is a default definition } else if (key_commands_long_default.count(keyChar) > 0) { - Serial.printf("get_command_long: will use default key\r\n"); + // Serial.printf("get_command_long: will use default key\r\n"); return key_commands_long_default.at(keyChar); // no key definition found } else { - Serial.printf("get_command_long: WARNING no key definition found\r\n"); + // Serial.printf("get_command_long: WARNING no key definition found\r\n"); return COMMAND_UNKNOWN; } } @@ -144,6 +162,71 @@ uint16_t get_command_long(std::string sceneName, char keyChar) { } +gui_list get_gui_list(std::string sceneName) { + 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 (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"); + 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; + } + +} + +uint16_t get_activate_scene_command(std::string sceneName) { + try { + // look if the current 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; + + // if the scene is not know, simply return 0 + } else { + // Serial.printf("get_activate_scene_command: will return 0\r\n"); + return 0; + + } + } + catch (const std::out_of_range& oor) { + Serial.printf("get_activate_scene_command: internal error, sceneName not registered\r\n"); + return 0; + } + +} + +scene_list get_scenes_on_sceneSelectionGUI() { + return &scenes_on_sceneSelectionGUI; +} + +void set_scenes_on_sceneSelectionGUI(t_scene_list a_scene_list) { + scenes_on_sceneSelectionGUI.clear(); + for (int i=0; i #include #include +#include #include "applicationInternal/keys.h" +extern bool useSceneGUIlist; + +typedef std::vector t_gui_list; +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; void register_scene( std::string a_scene_name, @@ -19,7 +27,9 @@ void register_scene( scene_end_sequence a_scene_end_sequence, key_repeatModes a_key_repeatModes, key_commands_short a_key_commands_short, - key_commands_long a_key_commands_long); + key_commands_long a_key_commands_long, + gui_list a_gui_list = NULL, + uint16_t a_activate_scene_command = 0); bool sceneExists(std::string sceneName); void scene_start_sequence_from_registry(std::string sceneName); @@ -27,6 +37,10 @@ void scene_end_sequence_from_registry(std::string sceneName); repeatModes get_key_repeatMode(std::string sceneName, char keyChar); uint16_t get_command_short(std::string sceneName, char keyChar); uint16_t get_command_long(std::string sceneName, char keyChar); +gui_list get_gui_list(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); extern char KEY_OFF ; extern char KEY_STOP ; diff --git a/Platformio/src/devices/TV/device_samsungTV/device_samsungTV.cpp b/Platformio/src/devices/TV/device_samsungTV/device_samsungTV.cpp index 302ed77..e94271c 100644 --- a/Platformio/src/devices/TV/device_samsungTV/device_samsungTV.cpp +++ b/Platformio/src/devices/TV/device_samsungTV/device_samsungTV.cpp @@ -57,7 +57,7 @@ uint16_t SAMSUNG_POWER_OFF ; //"Samsung_power_off"; uint16_t SAMSUNG_POWER_ON ; //"Samsung_power_on"; uint16_t SAMSUNG_INPUT_HDMI_1 ; //"Samsung_input_hdmi_1"; uint16_t SAMSUNG_INPUT_HDMI_2 ; //"Samsung_input_hdmi_2"; -// uint16_t SAMSUNG_INPUT_HDMI_3 ; //"Samsung_input_hdmi_3"; +uint16_t SAMSUNG_INPUT_HDMI_3 ; //"Samsung_input_hdmi_3"; // uint16_t SAMSUNG_INPUT_HDMI_4 ; //"Samsung_input_hdmi_4"; // uint16_t SAMSUNG_INPUT_COMPONENT ; //"Samsung_input_component"; uint16_t SAMSUNG_INPUT_TV ; //"Samsung_input_tv"; @@ -121,7 +121,7 @@ void register_device_samsungTV() { register_command(&SAMSUNG_POWER_ON , makeCommandData(IR, {std::to_string(IR_PROTOCOL_SAMSUNG), "0xE0E09966"})); register_command(&SAMSUNG_INPUT_HDMI_1 , makeCommandData(IR, {std::to_string(IR_PROTOCOL_SAMSUNG), "0xE0E09768"})); register_command(&SAMSUNG_INPUT_HDMI_2 , makeCommandData(IR, {std::to_string(IR_PROTOCOL_SAMSUNG), "0xE0E07D82"})); - // register_command(&SAMSUNG_INPUT_HDMI_3 , makeCommandData(IR, {std::to_string(IR_PROTOCOL_SAMSUNG), "0xE0E043BC"})); + register_command(&SAMSUNG_INPUT_HDMI_3 , makeCommandData(IR, {std::to_string(IR_PROTOCOL_SAMSUNG), "0xE0E043BC"})); // register_command(&SAMSUNG_INPUT_HDMI_4 , makeCommandData(IR, {std::to_string(IR_PROTOCOL_SAMSUNG), "0xE0E0A35C"})); // register_command(&SAMSUNG_INPUT_COMPONENT , makeCommandData(IR, {std::to_string(IR_PROTOCOL_SAMSUNG), "0xE0E0619E"})); register_command(&SAMSUNG_INPUT_TV , makeCommandData(IR, {std::to_string(IR_PROTOCOL_SAMSUNG), "0xE0E0D827"})); diff --git a/Platformio/src/devices/TV/device_samsungTV/device_samsungTV.h b/Platformio/src/devices/TV/device_samsungTV/device_samsungTV.h index 54c6573..39baeb9 100644 --- a/Platformio/src/devices/TV/device_samsungTV/device_samsungTV.h +++ b/Platformio/src/devices/TV/device_samsungTV/device_samsungTV.h @@ -54,7 +54,7 @@ extern uint16_t SAMSUNG_POWER_OFF; extern uint16_t SAMSUNG_POWER_ON; extern uint16_t SAMSUNG_INPUT_HDMI_1; extern uint16_t SAMSUNG_INPUT_HDMI_2; -// extern uint16_t SAMSUNG_INPUT_HDMI_3; +extern uint16_t SAMSUNG_INPUT_HDMI_3; // extern uint16_t SAMSUNG_INPUT_HDMI_4; // extern uint16_t SAMSUNG_INPUT_COMPONENT; extern uint16_t SAMSUNG_INPUT_TV; diff --git a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp index 6749311..4ddc7cc 100644 --- a/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp +++ b/Platformio/src/devices/misc/device_smarthome/gui_smarthome.cpp @@ -35,7 +35,7 @@ static void smartHomeToggle_event_cb(lv_event_t* e){ // Smart Home Slider Event handler static void smartHomeSlider_event_cb(lv_event_t* e){ - lv_obj_t * slider = lv_event_get_target(e); + lv_obj_t* slider = lv_event_get_target(e); char payload[8]; sprintf(payload, "%.2f", float(lv_slider_get_value(slider))); std::string payload_str(payload); diff --git a/Platformio/src/devices/misc/device_specialCommands.cpp b/Platformio/src/devices/misc/device_specialCommands.cpp index 7bf976b..b3cb600 100644 --- a/Platformio/src/devices/misc/device_specialCommands.cpp +++ b/Platformio/src/devices/misc/device_specialCommands.cpp @@ -1,7 +1,6 @@ #include "applicationInternal/commandHandler.h" #include "device_specialCommands.h" -uint16_t COMMAND_UNKNOWN ; uint16_t MY_SPECIAL_COMMAND; //"My_special_command"; // uint16_t TRIGGER_UPDATE_OF_OMOTE_SMART_HOME_DEVICES; diff --git a/Platformio/src/devices/misc/device_specialCommands.h b/Platformio/src/devices/misc/device_specialCommands.h index d9df102..9c5e8a6 100644 --- a/Platformio/src/devices/misc/device_specialCommands.h +++ b/Platformio/src/devices/misc/device_specialCommands.h @@ -2,7 +2,6 @@ #include -extern uint16_t COMMAND_UNKNOWN; extern uint16_t MY_SPECIAL_COMMAND; // extern uint16_t TRIGGER_UPDATE_OF_OMOTE_SMART_HOME_DEVICES; diff --git a/Platformio/src/guis/gui_sceneSelection.cpp b/Platformio/src/guis/gui_sceneSelection.cpp new file mode 100644 index 0000000..db28aa5 --- /dev/null +++ b/Platformio/src/guis/gui_sceneSelection.cpp @@ -0,0 +1,130 @@ +#include +#include "applicationInternal/hardware/hardwarePresenter.h" +#include "applicationInternal/gui/guiBase.h" +#include "applicationInternal/gui/guiRegistry.h" +#include "applicationInternal/scenes/sceneRegistry.h" +#include "applicationInternal/commandHandler.h" +#include "guis/gui_sceneSelection.h" + +static uint16_t activate_scene_command; +static bool doForceScene; +//void activate_scene_async(void *command) { +// executeCommand(activate_scene_command); +//} +void activate_scene_cb(lv_timer_t *timer) { + uint16_t scene_command_including_force = (uintptr_t)(timer->user_data); + // get the force flag from the highest bit + uint16_t activate_scene_command = scene_command_including_force & 0x7FFF; + bool doForceScene = (scene_command_including_force & 0x8000) == 0x8000; + if (doForceScene) { + executeCommand(activate_scene_command, "FORCE"); + } else { + executeCommand(activate_scene_command); + } +} + +static int lastShortClickedReceived; +static unsigned long int lastShortClickedReceivedTime; + +static void sceneSelection_event_cb(lv_event_t* e) { + + int user_data = (intptr_t)(e->user_data); + + // we will receive the following events in that order: + // LV_EVENT_PRESSED + // LV_EVENT_RELEASED + // only on short press: LV_EVENT_SHORT_CLICKED + // both on short press and long press: LV_EVENT_CLICKED + // if (lv_event_get_code(e) == LV_EVENT_PRESSED) { + // Serial.println("pressed"); + // } + // if (lv_event_get_code(e) == LV_EVENT_RELEASED) { + // Serial.println("released"); + // } + if (lv_event_get_code(e) == LV_EVENT_SHORT_CLICKED) { + lastShortClickedReceived = user_data; + lastShortClickedReceivedTime = millis(); + // Serial.println("short clicked, will see what happens next"); + return; + + } else if (lv_event_get_code(e) == LV_EVENT_CLICKED) { + if ((lastShortClickedReceived == user_data) && (millis() - lastShortClickedReceivedTime < 10)) { + // Serial.println("clicked, will send short click"); + doForceScene = false; + } else { + // Serial.println("clicked, will send long click"); + doForceScene = true; + } + } else { + return; + } + + std::string scene_name = get_scenes_on_sceneSelectionGUI()->at(user_data); + + activate_scene_command = get_activate_scene_command(scene_name); + if (activate_scene_command != 0) { + // this line is needed + if (SceneLabel != NULL) {lv_label_set_text(SceneLabel, "changing...");} + // Problem: screen will not get updated and show "changing..." if "executeCommand(activate_scene_command);" is called here + // test 1 (does not work): call lv_timer_handler(); + // lv_timer_handler(); + // test 2 (does not work): async_call + // lv_async_call(activate_scene_async, &activate_scene_command); + // test 3: lv_timer_create() + // needs to run only once, and a very short period of 5 ms to wait until first run is enough + + uint16_t scene_command_including_force; + if (doForceScene) { + // put the force flag into the highest bit + scene_command_including_force = activate_scene_command | 0x8000; + Serial.printf("Scene with index %d and name %s was FORCE selected\r\n", user_data, scene_name.c_str()); + } else { + scene_command_including_force = activate_scene_command; + Serial.printf("Scene with index %d and name %s was selected\r\n", user_data, scene_name.c_str()); + } + lv_timer_t *my_timer = lv_timer_create(activate_scene_cb, 20, (void *)(uintptr_t) scene_command_including_force); + lv_timer_set_repeat_count(my_timer, 1); + + } else { + Serial.printf("Cannot activate scene %s, because command was not found\r\n", scene_name.c_str()); + } +} + +void create_tab_content_sceneSelection(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 each scene ---------------------------------------- + scene_list scenes = get_scenes_on_sceneSelectionGUI(); + if ((scenes != NULL) && (scenes->size() > 0)) { + for (int i=0; isize(); i++) { + lv_obj_t* button = lv_btn_create(tab); + lv_obj_set_size(button, lv_pct(100), 42); + lv_obj_set_style_radius(button, 30, LV_PART_MAIN); + lv_obj_set_style_bg_color(button, color_primary, LV_PART_MAIN); + lv_obj_add_event_cb(button, sceneSelection_event_cb, LV_EVENT_CLICKED, (void *)(intptr_t)i); + lv_obj_add_event_cb(button, sceneSelection_event_cb, LV_EVENT_SHORT_CLICKED, (void *)(intptr_t)i); + //lv_obj_add_event_cb(button, sceneSelection_event_cb, LV_EVENT_PRESSED, (void *)(intptr_t)i); + //lv_obj_add_event_cb(button, sceneSelection_event_cb, LV_EVENT_RELEASED, (void *)(intptr_t)i); + + lv_obj_t* label = lv_label_create(button); + lv_label_set_text(label, scenes->at(i).c_str()); + lv_obj_center(label); + } + } + +} + +void notify_tab_before_delete_sceneSelection(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_sceneSelection(void){ + register_gui(std::string(tabName_sceneSelection), & create_tab_content_sceneSelection, & notify_tab_before_delete_sceneSelection); +} diff --git a/Platformio/src/guis/gui_sceneSelection.h b/Platformio/src/guis/gui_sceneSelection.h new file mode 100644 index 0000000..5829d4b --- /dev/null +++ b/Platformio/src/guis/gui_sceneSelection.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +const char * const tabName_sceneSelection = "Scene selection"; +void register_gui_sceneSelection(void); diff --git a/Platformio/src/guis/gui_settings.cpp b/Platformio/src/guis/gui_settings.cpp index 64de040..e56a4cb 100644 --- a/Platformio/src/guis/gui_settings.cpp +++ b/Platformio/src/guis/gui_settings.cpp @@ -15,7 +15,7 @@ lv_obj_t* objBattSettingsPercentage; // Slider Event handler static void bl_slider_event_cb(lv_event_t* e){ - lv_obj_t * slider = lv_event_get_target(e); + lv_obj_t* slider = lv_event_get_target(e); int32_t slider_value = lv_slider_get_value(slider); if (slider_value < 60) {slider_value = 60;} if (slider_value > 255) {slider_value = 255;} @@ -29,7 +29,7 @@ static void WakeEnableSetting_event_cb(lv_event_t* e){ // timout event handler static void timout_event_cb(lv_event_t* e){ - lv_obj_t * drop = lv_event_get_target(e); + lv_obj_t* drop = lv_event_get_target(e); uint16_t selected = lv_dropdown_get_selected(drop); switch (selected) { case 0: {set_sleepTimeout( 10000); break;} diff --git a/Platformio/src/main.cpp b/Platformio/src/main.cpp index 28bf7ac..2f93580 100644 --- a/Platformio/src/main.cpp +++ b/Platformio/src/main.cpp @@ -16,6 +16,7 @@ // register gui and keys #include "applicationInternal/gui/guiBase.h" #include "applicationInternal/gui/guiRegistry.h" +#include "guis/gui_sceneSelection.h" #include "guis/gui_irReceiver.h" #include "guis/gui_settings.h" #include "guis/gui_numpad.h" @@ -29,6 +30,7 @@ #include "scenes/scene_TV.h" #include "scenes/scene_fireTV.h" #include "scenes/scene_chromecast.h" +#include "scenes/scene_appleTV.h" #include "applicationInternal/scenes/sceneHandler.h" #if defined(ARDUINO) @@ -79,26 +81,35 @@ int main(int argc, char *argv[]) { #endif register_keyboardCommands(); + // register the scenes and their key_commands_* + register_scene_defaultKeys(); + register_scene_TV(); + register_scene_fireTV(); + register_scene_chromecast(); + register_scene_appleTV(); + register_scene_allOff(); + // Only show these scenes on the sceneSelection gui. If you don't set this explicitely, by default all registered scenes are shown. + set_scenes_on_sceneSelectionGUI({scene_name_TV, scene_name_fireTV, scene_name_chromecast, scene_name_appleTV}); + // register the GUIs. They will be displayed in the order they have been registered. + register_gui_sceneSelection(); register_gui_irReceiver(); 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(); 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 init_IMU(); - // register the scenes and their key_commands_* - register_scene_defaultKeys(); - register_scene_allOff(); - register_scene_TV(); - register_scene_fireTV(); - register_scene_chromecast(); - setLabelCurrentScene(); - // init WiFi - needs to be after init_gui() because WifiLabel must be available #if (ENABLE_WIFI_AND_MQTT == 1) init_mqtt(); diff --git a/Platformio/src/scenes/scene_TV.cpp b/Platformio/src/scenes/scene_TV.cpp index 3ea7a6f..7f74bb1 100644 --- a/Platformio/src/scenes/scene_TV.cpp +++ b/Platformio/src/scenes/scene_TV.cpp @@ -7,8 +7,11 @@ #include "devices/TV/device_samsungTV/device_samsungTV.h" #include "devices/AVreceiver/device_yamahaAmp/device_yamahaAmp.h" #include "applicationInternal/commandHandler.h" +// guis +#include "guis/gui_numpad.h" -uint16_t SCENE_TV ; //"Scene_tv" +uint16_t SCENE_TV ; //"Scene_tv" +uint16_t SCENE_TV_FORCE ; //"Scene_tv_force" std::map key_repeatModes_TV; std::map key_commands_short_TV; @@ -64,9 +67,11 @@ void scene_end_sequence_TV(void) { } std::string scene_name_TV = "TV"; +t_gui_list scene_TV_gui_list = {tabName_numpad}; void register_scene_TV(void) { - register_command(&SCENE_TV , makeCommandData(SCENE, {scene_name_TV})); + register_command(&SCENE_TV, makeCommandData(SCENE, {scene_name_TV})); + register_command(&SCENE_TV_FORCE, makeCommandData(SCENE, {scene_name_TV, "FORCE"})); register_scene( scene_name_TV, @@ -75,5 +80,7 @@ void register_scene_TV(void) { & scene_end_sequence_TV, & key_repeatModes_TV, & key_commands_short_TV, - & key_commands_long_TV); + & key_commands_long_TV, + & scene_TV_gui_list, + SCENE_TV); } diff --git a/Platformio/src/scenes/scene_TV.h b/Platformio/src/scenes/scene_TV.h index f24cab5..6a62606 100644 --- a/Platformio/src/scenes/scene_TV.h +++ b/Platformio/src/scenes/scene_TV.h @@ -4,6 +4,8 @@ #include extern uint16_t SCENE_TV; +// FORCE sends the start sequence again even if scene is already active +extern uint16_t SCENE_TV_FORCE; extern std::string scene_name_TV; void register_scene_TV_commands(void); diff --git a/Platformio/src/scenes/scene__defaultKeys.cpp b/Platformio/src/scenes/scene__defaultKeys.cpp index 71d0550..4ea8105 100644 --- a/Platformio/src/scenes/scene__defaultKeys.cpp +++ b/Platformio/src/scenes/scene__defaultKeys.cpp @@ -1,19 +1,30 @@ #include #include "applicationInternal/keys.h" #include "applicationInternal/scenes/sceneRegistry.h" +#include "applicationInternal/commandHandler.h" // devices -#include "devices/misc/device_specialCommands.h" #include "devices/AVreceiver/device_yamahaAmp/device_yamahaAmp.h" // scenes +#include "scene__defaultKeys.h" #include "scenes/scene_allOff.h" #include "scenes/scene_TV.h" #include "scenes/scene_fireTV.h" #include "scenes/scene_chromecast.h" +#include "scenes/scene_appleTV.h" + +uint16_t SCENE_SELECTION; +std::string scene_name_selection = "sceneSelection"; std::map key_repeatModes_default; std::map key_commands_short_default; std::map key_commands_long_default; +// This is the main list of guis we want to be shown when swiping. Need not to be all the guis that have been registered, can be only a subset. +// You can swipe through these guis. Will be in the order you place them here in the vector. +// By default, it is a list of the guis that have been registered in main.cpp +// If a scene defines a scene specific gui list, this will be used instead as long as the scene is active and we don't explicitely navigate back to main_gui_list +t_gui_list main_gui_list; + void register_scene_defaultKeys(void) { key_repeatModes_default = { {KEY_OFF, SHORT }, @@ -29,16 +40,16 @@ void register_scene_defaultKeys(void) { }; key_commands_short_default = { - {KEY_OFF, SCENE_ALLOFF }, + {KEY_OFF, SCENE_ALLOFF_FORCE}, /*{KEY_STOP, COMMAND_UNKNOWN }, {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, COMMAND_UNKNOWN }, {KEY_OK, COMMAND_UNKNOWN }, {KEY_RIGHT, COMMAND_UNKNOWN },*/ /* {KEY_DOWN, COMMAND_UNKNOWN },*/ - /*{KEY_BACK, COMMAND_UNKNOWN }, {KEY_SRC, 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_RED, SCENE_TV }, {KEY_GREEN, SCENE_FIRETV }, {KEY_YELLO, SCENE_CHROMECAST }, {KEY_BLUE, YAMAHA_STANDARD }, + {KEY_RED, SCENE_TV_FORCE }, {KEY_GREEN, SCENE_FIRETV_FORCE}, {KEY_YELLO, SCENE_CHROMECAST_FORCE},{KEY_BLUE, SCENE_APPLETV_FORCE}, }; key_commands_long_default = { @@ -46,4 +57,6 @@ void register_scene_defaultKeys(void) { }; + register_command(&SCENE_SELECTION , makeCommandData(SCENE, {scene_name_selection})); + } diff --git a/Platformio/src/scenes/scene__defaultKeys.h b/Platformio/src/scenes/scene__defaultKeys.h index 4e513d9..2322716 100644 --- a/Platformio/src/scenes/scene__defaultKeys.h +++ b/Platformio/src/scenes/scene__defaultKeys.h @@ -4,8 +4,15 @@ #include #include #include "applicationInternal/keys.h" +#include "applicationInternal/scenes/sceneRegistry.h" + +extern uint16_t SCENE_SELECTION; // command +extern std::string scene_name_selection; // name of this fake default scene extern std::map key_repeatModes_default; extern std::map key_commands_short_default; extern std::map key_commands_long_default; + +extern t_gui_list main_gui_list; + void register_scene_defaultKeys(void); diff --git a/Platformio/src/scenes/scene_allOff.cpp b/Platformio/src/scenes/scene_allOff.cpp index f4e8a8f..1091c62 100644 --- a/Platformio/src/scenes/scene_allOff.cpp +++ b/Platformio/src/scenes/scene_allOff.cpp @@ -9,6 +9,7 @@ #include "applicationInternal/commandHandler.h" uint16_t SCENE_ALLOFF ; //"Scene_allOff" +uint16_t SCENE_ALLOFF_FORCE; //"Scene_allOff_force" std::map key_repeatModes_allOff; std::map key_commands_short_allOff; @@ -77,7 +78,8 @@ void scene_end_sequence_allOff(void) { std::string scene_name_allOff = "Off"; void register_scene_allOff(void) { - register_command(&SCENE_ALLOFF , makeCommandData(SCENE, {scene_name_allOff})); + register_command(&SCENE_ALLOFF , makeCommandData(SCENE, {scene_name_allOff})); + register_command(&SCENE_ALLOFF_FORCE, makeCommandData(SCENE, {scene_name_allOff, "FORCE"})); register_scene( scene_name_allOff, @@ -86,5 +88,7 @@ void register_scene_allOff(void) { & scene_end_sequence_allOff, & key_repeatModes_allOff, & key_commands_short_allOff, - & key_commands_long_allOff); + & key_commands_long_allOff, + NULL, + SCENE_ALLOFF); } diff --git a/Platformio/src/scenes/scene_allOff.h b/Platformio/src/scenes/scene_allOff.h index e373e5a..0b89ea0 100644 --- a/Platformio/src/scenes/scene_allOff.h +++ b/Platformio/src/scenes/scene_allOff.h @@ -4,6 +4,8 @@ #include extern uint16_t SCENE_ALLOFF; +// FORCE sends the start sequence again even if scene is already active +extern uint16_t SCENE_ALLOFF_FORCE; extern std::string scene_name_allOff; void register_scene_allOff_commands(void); diff --git a/Platformio/src/scenes/scene_appleTV.cpp b/Platformio/src/scenes/scene_appleTV.cpp new file mode 100644 index 0000000..686ea5e --- /dev/null +++ b/Platformio/src/scenes/scene_appleTV.cpp @@ -0,0 +1,86 @@ +#include +#include "scenes/scene_appleTV.h" +#include "applicationInternal/keys.h" +#include "applicationInternal/scenes/sceneRegistry.h" +#include "applicationInternal/hardware/hardwarePresenter.h" +// devices +#include "devices/TV/device_samsungTV/device_samsungTV.h" +#include "devices/AVreceiver/device_yamahaAmp/device_yamahaAmp.h" +#include "applicationInternal/commandHandler.h" +// guis +#include "devices/mediaPlayer/device_appleTV/gui_appleTV.h" + +uint16_t SCENE_APPLETV ; //"Scene_appleTV" +uint16_t SCENE_APPLETV_FORCE; //"Scene_appleTV_force" + +std::map key_repeatModes_appleTV; +std::map key_commands_short_appleTV; +std::map key_commands_long_appleTV; + +void scene_setKeys_appleTV() { + key_repeatModes_appleTV = { + + + + + + + + + + + }; + + key_commands_short_appleTV = { + + + + + + + + + + + }; + + key_commands_long_appleTV = { + + + }; + +} + +void scene_start_sequence_appleTV(void) { + executeCommand(SAMSUNG_POWER_ON); + delay(500); + executeCommand(YAMAHA_POWER_ON); + delay(1500); + executeCommand(YAMAHA_INPUT_DVD); + delay(3000); + executeCommand(SAMSUNG_INPUT_HDMI_3); + +} + +void scene_end_sequence_appleTV(void) { + +} + +std::string scene_name_appleTV = "Apple TV"; +t_gui_list scene_appleTV_gui_list = {tabName_appleTV}; + +void register_scene_appleTV(void) { + register_command(&SCENE_APPLETV, makeCommandData(SCENE, {scene_name_appleTV})); + register_command(&SCENE_APPLETV_FORCE, makeCommandData(SCENE, {scene_name_appleTV, "FORCE"})); + + register_scene( + scene_name_appleTV, + & scene_setKeys_appleTV, + & scene_start_sequence_appleTV, + & scene_end_sequence_appleTV, + & key_repeatModes_appleTV, + & key_commands_short_appleTV, + & key_commands_long_appleTV, + & scene_appleTV_gui_list, + SCENE_APPLETV); +} diff --git a/Platformio/src/scenes/scene_appleTV.h b/Platformio/src/scenes/scene_appleTV.h new file mode 100644 index 0000000..3ac3a5e --- /dev/null +++ b/Platformio/src/scenes/scene_appleTV.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +extern uint16_t SCENE_APPLETV; +// FORCE sends the start sequence again even if scene is already active +extern uint16_t SCENE_APPLETV_FORCE; + +extern std::string scene_name_appleTV; +void register_scene_appleTV_commands(void); +void register_scene_appleTV(void); diff --git a/Platformio/src/scenes/scene_chromecast.cpp b/Platformio/src/scenes/scene_chromecast.cpp index 78361c0..1f08038 100644 --- a/Platformio/src/scenes/scene_chromecast.cpp +++ b/Platformio/src/scenes/scene_chromecast.cpp @@ -8,7 +8,8 @@ #include "devices/AVreceiver/device_yamahaAmp/device_yamahaAmp.h" #include "applicationInternal/commandHandler.h" -uint16_t SCENE_CHROMECAST ; //"Scene_chromecast" +uint16_t SCENE_CHROMECAST ; //"Scene_chromecast" +uint16_t SCENE_CHROMECAST_FORCE; //"Scene_chromecast_force" std::map key_repeatModes_chromecast; std::map key_commands_short_chromecast; @@ -66,7 +67,8 @@ void scene_end_sequence_chromecast(void) { std::string scene_name_chromecast = "Chromecast"; void register_scene_chromecast(void) { - register_command(&SCENE_CHROMECAST , makeCommandData(SCENE, {scene_name_chromecast})); + register_command(&SCENE_CHROMECAST, makeCommandData(SCENE, {scene_name_chromecast})); + register_command(&SCENE_CHROMECAST_FORCE, makeCommandData(SCENE, {scene_name_chromecast, "FORCE"})); register_scene( scene_name_chromecast, @@ -75,5 +77,7 @@ void register_scene_chromecast(void) { & scene_end_sequence_chromecast, & key_repeatModes_chromecast, & key_commands_short_chromecast, - & key_commands_long_chromecast); + & key_commands_long_chromecast, + NULL, + SCENE_CHROMECAST); } diff --git a/Platformio/src/scenes/scene_chromecast.h b/Platformio/src/scenes/scene_chromecast.h index 3271a68..5ce5ef7 100644 --- a/Platformio/src/scenes/scene_chromecast.h +++ b/Platformio/src/scenes/scene_chromecast.h @@ -4,6 +4,8 @@ #include extern uint16_t SCENE_CHROMECAST; +// FORCE sends the start sequence again even if scene is already active +extern uint16_t SCENE_CHROMECAST_FORCE; extern std::string scene_name_chromecast; void register_scene_chromecast_commands(void); diff --git a/Platformio/src/scenes/scene_fireTV.cpp b/Platformio/src/scenes/scene_fireTV.cpp index 4f2a61f..3979688 100644 --- a/Platformio/src/scenes/scene_fireTV.cpp +++ b/Platformio/src/scenes/scene_fireTV.cpp @@ -7,8 +7,11 @@ #include "devices/TV/device_samsungTV/device_samsungTV.h" #include "devices/AVreceiver/device_yamahaAmp/device_yamahaAmp.h" #include "applicationInternal/commandHandler.h" +// guis +#include "guis/gui_numpad.h" uint16_t SCENE_FIRETV ; //"Scene_firetv" +uint16_t SCENE_FIRETV_FORCE; //"Scene_firetv_force" std::map key_repeatModes_fireTV; std::map key_commands_short_fireTV; @@ -73,9 +76,11 @@ void scene_end_sequence_fireTV(void) { } std::string scene_name_fireTV = "Fire TV"; +t_gui_list scene_fireTV_gui_list = {tabName_numpad}; void register_scene_fireTV(void) { - register_command(&SCENE_FIRETV , makeCommandData(SCENE, {scene_name_fireTV})); + register_command(&SCENE_FIRETV, makeCommandData(SCENE, {scene_name_fireTV})); + register_command(&SCENE_FIRETV_FORCE, makeCommandData(SCENE, {scene_name_fireTV, "FORCE"})); register_scene( scene_name_fireTV, @@ -84,5 +89,7 @@ void register_scene_fireTV(void) { & scene_end_sequence_fireTV, & key_repeatModes_fireTV, & key_commands_short_fireTV, - & key_commands_long_fireTV); + & key_commands_long_fireTV, + & scene_fireTV_gui_list, + SCENE_FIRETV); } diff --git a/Platformio/src/scenes/scene_fireTV.h b/Platformio/src/scenes/scene_fireTV.h index 2e8efc9..4bb0dce 100644 --- a/Platformio/src/scenes/scene_fireTV.h +++ b/Platformio/src/scenes/scene_fireTV.h @@ -4,6 +4,8 @@ #include extern uint16_t SCENE_FIRETV; +// FORCE sends the start sequence again even if scene is already active +extern uint16_t SCENE_FIRETV_FORCE; extern std::string scene_name_fireTV; void register_scene_fireTV_commands(void); diff --git a/README.md b/README.md index 4c856c6..3281562 100644 --- a/README.md +++ b/README.md @@ -74,9 +74,8 @@ The [housing and buttons](https://github.com/CoretechR/OMOTE/tree/main/CAD) can Short term goals - [x] simulator for creating pages in Windows, WSL2 and Linux -- [ ] scene selector page as start page -- [ ] available gui pages based on the currently active scene. Hide pages not needed in a scene -- [ ] make gui actions context sensitive for the currently active scene +- [x] scene selector page as start page +- [x] available gui pages based on the currently active scene. Hide pages not needed in a scene Long term goals (not yet scheduled) - [ ] Easier configuration