scene_controller.hpp 6.8 KB

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