scene_manager.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include "scene_manager_i.h"
  2. #include <furi.h>
  3. SceneManager* scene_manager_alloc(const SceneManagerHandlers* app_scene_handlers, void* context) {
  4. furi_assert(context);
  5. SceneManager* scene_manager = malloc(sizeof(SceneManager));
  6. // Set SceneManager context and scene handlers
  7. scene_manager->context = context;
  8. scene_manager->scene_handlers = app_scene_handlers;
  9. // Allocate all scenes
  10. scene_manager->scene = malloc(sizeof(AppScene) * app_scene_handlers->scene_num);
  11. // Initialize ScaneManager array for navigation
  12. SceneManagerIdStack_init(scene_manager->scene_id_stack);
  13. return scene_manager;
  14. }
  15. void scene_manager_free(SceneManager* scene_manager) {
  16. furi_assert(scene_manager);
  17. // Clear ScaneManager array
  18. SceneManagerIdStack_clear(scene_manager->scene_id_stack);
  19. // Clear allocated scenes
  20. free(scene_manager->scene);
  21. // Free SceneManager structure
  22. free(scene_manager);
  23. }
  24. void scene_manager_set_scene_state(SceneManager* scene_manager, uint32_t scene_id, uint32_t state) {
  25. furi_assert(scene_manager);
  26. furi_assert(scene_id < scene_manager->scene_handlers->scene_num);
  27. scene_manager->scene[scene_id].state = state;
  28. }
  29. uint32_t scene_manager_get_scene_state(SceneManager* scene_manager, uint32_t scene_id) {
  30. furi_assert(scene_manager);
  31. furi_assert(scene_id < scene_manager->scene_handlers->scene_num);
  32. return scene_manager->scene[scene_id].state;
  33. }
  34. bool scene_manager_handle_custom_event(SceneManager* scene_manager, uint32_t custom_event) {
  35. furi_assert(scene_manager);
  36. SceneManagerEvent event = {
  37. .type = SceneManagerEventTypeCustom,
  38. .event = custom_event,
  39. };
  40. bool result = false;
  41. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  42. uint32_t* scene_id_p = SceneManagerIdStack_back(scene_manager->scene_id_stack);
  43. uint32_t scene_id = *scene_id_p;
  44. result = scene_manager->scene_handlers->on_event_handlers[scene_id](
  45. scene_manager->context, event);
  46. }
  47. return result;
  48. }
  49. bool scene_manager_handle_back_event(SceneManager* scene_manager) {
  50. furi_assert(scene_manager);
  51. SceneManagerEvent event = {
  52. .type = SceneManagerEventTypeBack,
  53. };
  54. bool consumed = false;
  55. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  56. uint32_t* scene_id_p = SceneManagerIdStack_back(scene_manager->scene_id_stack);
  57. uint32_t scene_id = *scene_id_p;
  58. consumed = scene_manager->scene_handlers->on_event_handlers[scene_id](
  59. scene_manager->context, event);
  60. }
  61. if(!consumed) {
  62. consumed = scene_manager_previous_scene(scene_manager);
  63. }
  64. return consumed;
  65. }
  66. void scene_manager_handle_tick_event(SceneManager* scene_manager) {
  67. furi_assert(scene_manager);
  68. SceneManagerEvent event = {
  69. .type = SceneManagerEventTypeTick,
  70. };
  71. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  72. uint32_t* scene_id_p = SceneManagerIdStack_back(scene_manager->scene_id_stack);
  73. uint32_t scene_id = *scene_id_p;
  74. scene_manager->scene_handlers->on_event_handlers[scene_id](scene_manager->context, event);
  75. }
  76. }
  77. void scene_manager_next_scene(SceneManager* scene_manager, uint32_t next_scene_id) {
  78. furi_assert(scene_manager);
  79. furi_assert(next_scene_id < scene_manager->scene_handlers->scene_num);
  80. // Check if it is not the first scene
  81. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  82. uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  83. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  84. }
  85. // Add next scene and run on_enter
  86. SceneManagerIdStack_push_back(scene_manager->scene_id_stack, next_scene_id);
  87. scene_manager->scene_handlers->on_enter_handlers[next_scene_id](scene_manager->context);
  88. }
  89. bool scene_manager_previous_scene(SceneManager* scene_manager) {
  90. furi_assert(scene_manager);
  91. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  92. uint32_t cur_scene_id = 0;
  93. SceneManagerIdStack_pop_back(&cur_scene_id, scene_manager->scene_id_stack);
  94. // Handle exit from start scene separately
  95. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) == 0) {
  96. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  97. return false;
  98. }
  99. uint32_t prev_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  100. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  101. scene_manager->scene_handlers->on_enter_handlers[prev_scene_id](scene_manager->context);
  102. return true;
  103. } else {
  104. return false;
  105. }
  106. }
  107. bool scene_manager_search_and_switch_to_previous_scene(
  108. SceneManager* scene_manager,
  109. uint32_t scene_id) {
  110. furi_assert(scene_manager);
  111. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  112. uint32_t prev_scene_id = 0;
  113. uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  114. SceneManagerIdStack_it_t scene_it;
  115. SceneManagerIdStack_it_last(scene_it, scene_manager->scene_id_stack);
  116. // Search scene with given id in navigation stack
  117. bool scene_found = false;
  118. while(!scene_found) {
  119. SceneManagerIdStack_previous(scene_it);
  120. if(SceneManagerIdStack_end_p(scene_it)) {
  121. return false;
  122. }
  123. prev_scene_id = *SceneManagerIdStack_ref(scene_it);
  124. if(prev_scene_id == scene_id) {
  125. scene_found = true;
  126. }
  127. }
  128. // Remove all scene id from navigation stack
  129. SceneManagerIdStack_next(scene_it);
  130. SceneManagerIdStack_pop_until(scene_manager->scene_id_stack, scene_it);
  131. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  132. scene_manager->scene_handlers->on_enter_handlers[prev_scene_id](scene_manager->context);
  133. return true;
  134. } else {
  135. return false;
  136. }
  137. }
  138. bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id) {
  139. furi_assert(scene_manager);
  140. bool scene_found = false;
  141. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  142. uint32_t prev_scene_id;
  143. SceneManagerIdStack_it_t scene_it;
  144. SceneManagerIdStack_it_last(scene_it, scene_manager->scene_id_stack);
  145. // Perform search in scene stack
  146. while(!scene_found) {
  147. SceneManagerIdStack_previous(scene_it);
  148. if(SceneManagerIdStack_end_p(scene_it)) {
  149. break;
  150. }
  151. prev_scene_id = *SceneManagerIdStack_ref(scene_it);
  152. if(prev_scene_id == scene_id) {
  153. scene_found = true;
  154. }
  155. }
  156. }
  157. return scene_found;
  158. }
  159. bool scene_manager_search_and_switch_to_another_scene(
  160. SceneManager* scene_manager,
  161. uint32_t scene_id) {
  162. furi_assert(scene_manager);
  163. furi_assert(scene_id < scene_manager->scene_handlers->scene_num);
  164. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  165. uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  166. SceneManagerIdStack_it_t scene_it;
  167. SceneManagerIdStack_it(scene_it, scene_manager->scene_id_stack);
  168. SceneManagerIdStack_next(scene_it);
  169. // Remove all scene id from navigation stack until first scene
  170. SceneManagerIdStack_pop_until(scene_manager->scene_id_stack, scene_it);
  171. // Add next scene
  172. SceneManagerIdStack_push_back(scene_manager->scene_id_stack, scene_id);
  173. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  174. scene_manager->scene_handlers->on_enter_handlers[scene_id](scene_manager->context);
  175. return true;
  176. } else {
  177. return false;
  178. }
  179. }
  180. void scene_manager_stop(SceneManager* scene_manager) {
  181. furi_assert(scene_manager);
  182. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) > 0) {
  183. uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  184. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  185. }
  186. }