scene-controller.hpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #include <map>
  2. #include <forward_list>
  3. #include <initializer_list>
  4. #define GENERIC_SCENE_ENUM_VALUES Exit, Start
  5. #define GENERIC_EVENT_ENUM_VALUES Tick, Back
  6. /**
  7. * @brief Controller for scene navigation in application
  8. *
  9. * @tparam TScene generic scene class
  10. * @tparam TApp application class
  11. */
  12. template <typename TScene, typename TApp> class SceneController {
  13. public:
  14. /**
  15. * @brief Add scene to scene container
  16. *
  17. * @param scene_index scene index
  18. * @param scene_pointer scene object pointer
  19. */
  20. void add_scene(typename TApp::SceneType scene_index, TScene* scene_pointer) {
  21. furi_check(scenes.count(scene_index) == 0);
  22. scenes[scene_index] = scene_pointer;
  23. }
  24. /**
  25. * @brief Switch to next scene and store current scene in previous scenes list
  26. *
  27. * @param scene_index next scene index
  28. * @param need_restore true, if we want the scene to restore its parameters
  29. */
  30. void switch_to_next_scene(typename TApp::SceneType scene_index, bool need_restore = false) {
  31. previous_scenes_list.push_front(current_scene_index);
  32. switch_to_scene(scene_index, need_restore);
  33. }
  34. /**
  35. * @brief Switch to next scene without ability to return to current scene
  36. *
  37. * @param scene_index next scene index
  38. * @param need_restore true, if we want the scene to restore its parameters
  39. */
  40. void switch_to_scene(typename TApp::SceneType scene_index, bool need_restore = false) {
  41. if(scene_index != TApp::SceneType::Exit) {
  42. scenes[current_scene_index]->on_exit(app);
  43. current_scene_index = scene_index;
  44. scenes[current_scene_index]->on_enter(app, need_restore);
  45. }
  46. }
  47. /**
  48. * @brief Search the scene in the list of previous scenes and switch to it
  49. *
  50. * @param scene_index_list list of scene indexes to which you want to switch
  51. */
  52. bool search_and_switch_to_previous_scene(
  53. const std::initializer_list<typename TApp::SceneType>& scene_index_list) {
  54. auto previous_scene_index = TApp::SceneType::Exit;
  55. bool scene_found = false;
  56. bool result = false;
  57. while(!scene_found) {
  58. previous_scene_index = get_previous_scene_index();
  59. for(const auto& element : scene_index_list) {
  60. if(previous_scene_index == element) {
  61. scene_found = true;
  62. result = true;
  63. break;
  64. }
  65. if(previous_scene_index == TApp::SceneType::Exit) {
  66. scene_found = true;
  67. break;
  68. }
  69. }
  70. }
  71. if(result) {
  72. switch_to_scene(previous_scene_index, true);
  73. }
  74. return result;
  75. }
  76. bool search_and_switch_to_another_scene(
  77. const std::initializer_list<typename TApp::SceneType>& scene_index_list,
  78. typename TApp::SceneType scene_index) {
  79. auto previous_scene_index = TApp::SceneType::Exit;
  80. bool scene_found = false;
  81. bool result = false;
  82. while(!scene_found) {
  83. previous_scene_index = get_previous_scene_index();
  84. for(const auto& element : scene_index_list) {
  85. if(previous_scene_index == element) {
  86. scene_found = true;
  87. result = true;
  88. break;
  89. }
  90. if(previous_scene_index == TApp::SceneType::Exit) {
  91. scene_found = true;
  92. break;
  93. }
  94. }
  95. }
  96. if(result) {
  97. switch_to_scene(scene_index, true);
  98. }
  99. return result;
  100. }
  101. bool
  102. has_previous_scene(const std::initializer_list<typename TApp::SceneType>& scene_index_list) {
  103. bool result = false;
  104. for(auto const& previous_element : previous_scenes_list) {
  105. for(const auto& element : scene_index_list) {
  106. if(previous_element == element) {
  107. result = true;
  108. break;
  109. }
  110. if(previous_element == TApp::SceneType::Exit) {
  111. break;
  112. }
  113. }
  114. if(result) break;
  115. }
  116. return result;
  117. }
  118. /**
  119. * @brief Start application main cycle
  120. *
  121. * @param tick_length_ms tick event length in milliseconds
  122. */
  123. void process(
  124. uint32_t tick_length_ms = 100,
  125. typename TApp::SceneType start_scene_index = TApp::SceneType::Start) {
  126. typename TApp::Event event;
  127. bool consumed;
  128. bool exit = false;
  129. current_scene_index = start_scene_index;
  130. scenes[current_scene_index]->on_enter(app, false);
  131. while(!exit) {
  132. app->view_controller.receive_event(&event);
  133. consumed = scenes[current_scene_index]->on_event(app, &event);
  134. if(!consumed) {
  135. if(event.type == TApp::EventType::Back) {
  136. exit = switch_to_previous_scene();
  137. }
  138. }
  139. };
  140. scenes[current_scene_index]->on_exit(app);
  141. }
  142. /**
  143. * @brief Switch to previous scene
  144. *
  145. * @param count how many steps back
  146. * @return true if app need to exit
  147. */
  148. bool switch_to_previous_scene(uint8_t count = 1) {
  149. auto previous_scene_index = TApp::SceneType::Start;
  150. for(uint8_t i = 0; i < count; i++) previous_scene_index = get_previous_scene_index();
  151. if(previous_scene_index == TApp::SceneType::Exit) return true;
  152. switch_to_scene(previous_scene_index, true);
  153. return false;
  154. }
  155. /**
  156. * @brief Construct a new Scene Controller object
  157. *
  158. * @param app_pointer pointer to application class
  159. */
  160. SceneController(TApp* app_pointer) {
  161. app = app_pointer;
  162. current_scene_index = TApp::SceneType::Exit;
  163. }
  164. /**
  165. * @brief Destroy the Scene Controller object
  166. *
  167. */
  168. ~SceneController() {
  169. for(auto& it : scenes) delete it.second;
  170. }
  171. private:
  172. /**
  173. * @brief Scenes pointers container
  174. *
  175. */
  176. std::map<typename TApp::SceneType, TScene*> scenes;
  177. /**
  178. * @brief List of indexes of previous scenes
  179. *
  180. */
  181. std::forward_list<typename TApp::SceneType> previous_scenes_list;
  182. /**
  183. * @brief Current scene index holder
  184. *
  185. */
  186. typename TApp::SceneType current_scene_index;
  187. /**
  188. * @brief Application pointer holder
  189. *
  190. */
  191. TApp* app;
  192. /**
  193. * @brief Get the previous scene index
  194. *
  195. * @return previous scene index
  196. */
  197. typename TApp::SceneType get_previous_scene_index() {
  198. auto scene_index = TApp::SceneType::Exit;
  199. if(!previous_scenes_list.empty()) {
  200. scene_index = previous_scenes_list.front();
  201. previous_scenes_list.pop_front();
  202. }
  203. return scene_index;
  204. }
  205. };