Merge branch 'main' into lvgl_9.1

This commit is contained in:
KlausMu 2024-05-09 08:03:35 +02:00
commit d69913c323
29 changed files with 977 additions and 450 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -1,31 +1,58 @@
#include <string>
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;
}

View File

@ -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);

View File

@ -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

View File

@ -94,6 +94,7 @@ extern uint16_t KEYBOARD_VOLUME_DECREMENT;
enum commandHandlers {
SPECIAL,
SCENE,
GUI,
IR,
#if (ENABLE_WIFI_AND_MQTT == 1)
MQTT,

View File

@ -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();

View File

@ -1,6 +1,7 @@
#pragma once
#include <lvgl.h>
#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);

View File

@ -1,47 +1,101 @@
#include <lvgl.h>
#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<std::string>::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; j<breadcrumpLength; j++) {
// create a breadcrump dot for each gui in the main_gui_list
for (int j=0; j<breadcrumpMainGuiListLength; j++) {
lv_obj_t* dot = lv_obj_create(btn);
lv_obj_set_size(dot, breadcrumpDotSize, breadcrumpDotSize);
lv_obj_set_style_radius(dot, LV_RADIUS_CIRCLE, LV_PART_MAIN);
// hightlight dot if it is the one for the currently active tab
if (j == (breadcrumpPosition-1)) {
lv_obj_set_style_bg_color(dot, lv_color_lighten(color_primary, 200), LV_PART_MAIN);
#if (USE_SCENE_SPECIFIC_GUI_LIST != 0)
if ( ((gui_memoryOptimizer_getActiveGUIlist() == MAIN_GUI_LIST) || !get_scene_has_gui_list(gui_memoryOptimizer_getActiveSceneName()))
#else
if ( true
#endif
&& (j == (breadcrumpPosition-1))) {
lv_obj_set_style_bg_color(dot, lv_color_lighten(color_primary, 255), LV_PART_MAIN);
} else if ((gui_memoryOptimizer_getActiveGUIlist() == SCENE_GUI_LIST) && get_scene_has_gui_list(gui_memoryOptimizer_getActiveSceneName()) && (j == gui_memoryOptimizer_getLastActiveGUIlistIndex())) {
// hightlight dot a little bit if it is at least the one which was last active in the other gui list
lv_obj_set_style_bg_color(dot, lv_color_lighten(color_primary, 140), LV_PART_MAIN);
} else {
lv_obj_set_style_bg_color(dot, lv_color_lighten(color_primary, 100), LV_PART_MAIN);
lv_obj_set_style_bg_color(dot, lv_color_lighten(color_primary, 30), LV_PART_MAIN);
}
lv_obj_align(dot, LV_ALIGN_TOP_MID, breadcrumpStartPositionX +j*(breadcrumpDotSize + breadcrumpDotDistance), -6);
lv_obj_align(dot, LV_ALIGN_TOP_MID, breadcrumpMainGuiListStartPositionX +j*(breadcrumpDotSize + breadcrumpDotDistance), breadcrumpMainGuiList_yPos);
// this dot needs to get clickable again
lv_obj_set_user_data(dot,(void *)(intptr_t)1);
lv_obj_add_flag(dot, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_flag(dot, LV_OBJ_FLAG_EVENT_BUBBLE);
}
// create a breadcrump dot for each gui in the scene gui list, if there is one
if (show_scene_gui_list) {
for (int j=0; j<breadcrumpSceneGuiListLength; j++) {
lv_obj_t* dot = lv_obj_create(btn);
lv_obj_set_size(dot, breadcrumpDotSize, breadcrumpDotSize);
lv_obj_set_style_radius(dot, LV_RADIUS_CIRCLE, LV_PART_MAIN);
if ((gui_memoryOptimizer_getActiveGUIlist() == SCENE_GUI_LIST) && (j == (breadcrumpPosition-1))) {
// hightlight dot if it is the one for the currently active tab
lv_obj_set_style_bg_color(dot, lv_color_lighten(color_primary, 255), LV_PART_MAIN);
} else if ((gui_memoryOptimizer_getActiveGUIlist() == MAIN_GUI_LIST) && (j == gui_memoryOptimizer_getLastActiveGUIlistIndex())) {
// hightlight dot a little bit if it is at least the one which was last active in the other gui list
lv_obj_set_style_bg_color(dot, lv_color_lighten(color_primary, 140), LV_PART_MAIN);
} else {
lv_obj_set_style_bg_color(dot, lv_color_lighten(color_primary, 30), LV_PART_MAIN);
}
lv_obj_align(dot, LV_ALIGN_TOP_MID, breadcrumpSceneGuiListStartPositionX +j*(breadcrumpDotSize + breadcrumpDotDistance), breadcrumpSceneGuiList_yPos);
// this dot needs to get clickable again
lv_obj_set_user_data(dot,(void *)(intptr_t)1);
lv_obj_add_flag(dot, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_flag(dot, LV_OBJ_FLAG_EVENT_BUBBLE);
}
}
// create a label for nameOfGUI
lv_obj_t* label = lv_label_create(btn);
lv_obj_set_style_text_font(label, &lv_font_montserrat_10, LV_PART_MAIN);
lv_label_set_text_fmt(label, "%s", nameOfTab.c_str());
lv_obj_align(label, LV_ALIGN_BOTTOM_MID, 0, 6);
lv_label_set_text_fmt(label, "%s", nameOfGUI.c_str());
lv_obj_align(label, LV_ALIGN_BOTTOM_MID, 0, nameOfGUI_yPos);
}
}
@ -379,8 +472,8 @@ 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));
// 4 at last position 4 at middle position only one tab available overall
if ((tabs_in_memory[2].listIndex == get_gui_list(get_currentScene())->size()-1) || (tabs_in_memory[1].listIndex == get_gui_list(get_currentScene())->size()-1) || (tabs_in_memory[1].listIndex == -1)) {
// 4 at last position 4 at middle position only one tab available overall
if ((gui_state->gui_on_tab[2].gui_list_index == get_gui_list_active_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; i<get_gui_list(get_currentScene())->size(); 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; i<get_gui_list(get_currentScene())->size(); 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; i<get_gui_list_active_withFallback()->size(); 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");
}

View File

@ -1,6 +1,28 @@
#pragma once
#include <string>
#include <lvgl.h>
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);

View File

@ -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<std::string, gui_definition> 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<std::string, scene_definition>::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<std::string, gui_definition>::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();
}
}
}

View File

@ -22,19 +22,33 @@
#include <vector>
#include <map>
#include <lvgl.h>
#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<std::string, gui_definition> 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();

View File

@ -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 ---------------------------------------------------------------

View File

@ -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);

View File

@ -1,7 +1,8 @@
#include <string>
#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);

View File

@ -1,5 +1,8 @@
#pragma once
#include <map>
#include <stdint.h>
enum repeatModes {
// only as fallback
REPEAT_MODE_UNKNOWN,
@ -15,4 +18,8 @@ enum repeatModes {
SHORTorLONG,
};
typedef std::map<char, repeatModes> *key_repeatModes;
typedef std::map<char, uint16_t> *key_commands_short;
typedef std::map<char, uint16_t> *key_commands_long;
void keypad_loop(void);

View File

@ -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);
}

View File

@ -3,5 +3,6 @@
#include <string>
#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 = "");

View File

@ -1,28 +1,13 @@
#include <map>
#include <stdexcept>
#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<std::string, scene_definition> 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<std::string, scene_definition>::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;

View File

@ -1,12 +1,9 @@
#pragma once
#include <string>
#include <stdint.h>
#include <map>
#include <vector>
#include "applicationInternal/keys.h"
extern bool useSceneGUIlist;
#include "applicationInternal/gui/guiMemoryOptimizer.h"
typedef std::vector<std::string> t_gui_list;
typedef std::vector<std::string> t_scene_list;
@ -14,12 +11,23 @@ typedef std::vector<std::string> t_scene_list;
typedef void (*scene_setKeys)(void);
typedef void (*scene_start_sequence)(void);
typedef void (*scene_end_sequence)(void);
typedef std::map<char, repeatModes> *key_repeatModes;
typedef std::map<char, uint16_t> *key_commands_short;
typedef std::map<char, uint16_t> *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<std::string, scene_definition> 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);

View File

@ -0,0 +1,46 @@
#include <lvgl.h>
#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);
}

View File

@ -0,0 +1,4 @@
#pragma once
const char * const tabName_yamahaAmp = "Yamaha Amp";
void register_gui_yamahaAmp(void);

View File

@ -1,11 +1,13 @@
#include <lvgl.h>
#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<char, repeatModes> key_repeatModes_smarthome = {};
std::map<char, uint16_t> key_commands_short_smarthome = {};
std::map<char, uint16_t> 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)}));
}

View File

@ -3,4 +3,5 @@
#include <lvgl.h>
const char * const tabName_smarthome = "Smart Home";
extern uint16_t GUI_SMARTHOME_ACTIVATE;
void register_gui_smarthome(void);

View File

@ -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);

View File

@ -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

View File

@ -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 },

View File

@ -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<char, repeatModes> 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}));
}

View File

@ -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<char, repeatModes> key_repeatModes_default;
extern std::map<char, uint16_t> key_commands_short_default;