flipperzero-firmware/lib/app-scened-template/scene-controller.hpp
SG 0b14db4fb3
C++ apps: templated scene controller (#517)
* C++ apps: templated scene controller
* templated app: fix type names
* templated app: text store component
* Applications: add "Templated Scene" application
* templated app: refractoring
* Gui module byte input: fix docs
* templated app: new byte input scene
* templated app: dialog ex view module
* templated app: popup view module
* templated app: dialog-ex view module, fix docs
* templated app: text input view module
* Gui module text input: fix docs
* Furi: duplicated include
* templated app: record holder (controller) class
* templated app: view modules can now be accessed via cast
* templated app: remove unused includes
* templated app: fix return code
2021-06-15 14:01:56 +03:00

178 lines
5.0 KiB
C++

#include <map>
#include <forward_list>
#include <initializer_list>
#define GENERIC_SCENE_ENUM_VALUES Uninitalized, Exit, Start
#define GENERIC_EVENT_ENUM_VALUES Tick, Back
/**
* @brief Controller for scene navigation in application
*
* @tparam TScene generic scene class
* @tparam TApp application class
*/
template <typename TScene, typename TApp> class SceneController {
public:
/**
* @brief Add scene to scene container
*
* @param scene_index scene index
* @param scene_pointer scene object pointer
*/
void add_scene(typename TApp::SceneType scene_index, TScene* scene_pointer) {
furi_check(scenes.count(scene_index) == 0);
scenes[scene_index] = scene_pointer;
}
/**
* @brief Switch to next scene and store current scene in previous scenes list
*
* @param scene_index next scene index
* @param need_restore true, if we want the scene to restore its parameters
*/
void switch_to_next_scene(typename TApp::SceneType scene_index, bool need_restore = false) {
previous_scenes_list.push_front(current_scene_index);
switch_to_scene(scene_index, need_restore);
}
/**
* @brief Switch to next scene without ability to return to current scene
*
* @param scene_index next scene index
* @param need_restore true, if we want the scene to restore its parameters
*/
void switch_to_scene(typename TApp::SceneType scene_index, bool need_restore = false) {
if(scene_index != TApp::SceneType::Exit) {
scenes[current_scene_index]->on_exit(app);
current_scene_index = scene_index;
scenes[current_scene_index]->on_enter(app, need_restore);
}
}
/**
* @brief Search the scene in the list of previous scenes and switch to it
*
* @param scene_index_list list of scene indexes to which you want to switch
*/
void search_and_switch_to_previous_scene(
const std::initializer_list<typename TApp::SceneType>& scene_index_list) {
auto previous_scene_index = TApp::SceneType::Start;
bool scene_found = false;
while(!scene_found) {
previous_scene_index = get_previous_scene_index();
for(const auto& element : scene_index_list) {
if(previous_scene_index == element) {
scene_found = true;
break;
}
}
}
switch_to_scene(previous_scene_index, true);
}
/**
* @brief Start application main cycle
*
* @param tick_length_ms tick event length in milliseconds
*/
void process(uint32_t tick_length_ms = 100) {
typename TApp::Event event;
bool consumed;
bool exit = false;
current_scene_index = TApp::SceneType::Start;
scenes[current_scene_index]->on_enter(app, false);
while(!exit) {
app->view_controller.receive_event(&event);
consumed = scenes[current_scene_index]->on_event(app, &event);
if(!consumed) {
if(event.type == TApp::EventType::Back) {
exit = switch_to_previous_scene();
}
}
};
scenes[current_scene_index]->on_exit(app);
}
/**
* @brief Switch to previous scene
*
* @param count how many steps back
* @return true if app need to exit
*/
bool switch_to_previous_scene(uint8_t count = 1) {
auto previous_scene_index = TApp::SceneType::Start;
for(uint8_t i = 0; i < count; i++) previous_scene_index = get_previous_scene_index();
if(previous_scene_index == TApp::SceneType::Exit) return true;
switch_to_scene(previous_scene_index, true);
return false;
}
/**
* @brief Construct a new Scene Controller object
*
* @param app_pointer pointer to application class
*/
SceneController(TApp* app_pointer) {
app = app_pointer;
current_scene_index = TApp::SceneType::Uninitalized;
}
/**
* @brief Destroy the Scene Controller object
*
*/
~SceneController() {
for(auto& it : scenes) delete it.second;
}
private:
/**
* @brief Scenes pointers container
*
*/
std::map<typename TApp::SceneType, TScene*> scenes;
/**
* @brief List of indexes of previous scenes
*
*/
std::forward_list<typename TApp::SceneType> previous_scenes_list;
/**
* @brief Current scene index holder
*
*/
typename TApp::SceneType current_scene_index;
/**
* @brief Application pointer holder
*
*/
TApp* app;
/**
* @brief Get the previous scene index
*
* @return previous scene index
*/
typename TApp::SceneType get_previous_scene_index() {
auto scene_index = TApp::SceneType::Exit;
if(!previous_scenes_list.empty()) {
scene_index = previous_scenes_list.front();
previous_scenes_list.pop_front();
}
return scene_index;
}
};