scene_manager.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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 = furi_alloc(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 = furi_alloc(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. uint32_t scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  41. return scene_manager->scene_handlers->on_event_handlers[scene_id](
  42. scene_manager->context, event);
  43. }
  44. bool scene_manager_handle_back_event(SceneManager* scene_manager) {
  45. furi_assert(scene_manager);
  46. SceneManagerEvent event = {
  47. .type = SceneManagerEventTypeBack,
  48. };
  49. uint32_t scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  50. bool consumed =
  51. scene_manager->scene_handlers->on_event_handlers[scene_id](scene_manager->context, event);
  52. if(!consumed) {
  53. consumed = scene_manager_previous_scene(scene_manager);
  54. }
  55. return consumed;
  56. }
  57. void scene_manager_handle_tick_event(SceneManager* scene_manager) {
  58. furi_assert(scene_manager);
  59. SceneManagerEvent event = {
  60. .type = SceneManagerEventTypeTick,
  61. };
  62. uint32_t scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  63. scene_manager->scene_handlers->on_event_handlers[scene_id](scene_manager->context, event);
  64. }
  65. void scene_manager_next_scene(SceneManager* scene_manager, uint32_t next_scene_id) {
  66. furi_assert(scene_manager);
  67. furi_assert(next_scene_id < scene_manager->scene_handlers->scene_num);
  68. // Check if it is not the first scene
  69. if(SceneManagerIdStack_size(scene_manager->scene_id_stack)) {
  70. uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  71. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  72. }
  73. // Add next scene and run on_enter
  74. SceneManagerIdStack_push_back(scene_manager->scene_id_stack, next_scene_id);
  75. scene_manager->scene_handlers->on_enter_handlers[next_scene_id](scene_manager->context);
  76. }
  77. bool scene_manager_previous_scene(SceneManager* scene_manager) {
  78. furi_assert(scene_manager);
  79. uint32_t cur_scene_id = 0;
  80. SceneManagerIdStack_pop_back(&cur_scene_id, scene_manager->scene_id_stack);
  81. // Handle exit from start scene separately
  82. if(SceneManagerIdStack_size(scene_manager->scene_id_stack) == 0) {
  83. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  84. return false;
  85. }
  86. uint32_t prev_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  87. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  88. scene_manager->scene_handlers->on_enter_handlers[prev_scene_id](scene_manager->context);
  89. return true;
  90. }
  91. bool scene_manager_search_and_switch_to_previous_scene(
  92. SceneManager* scene_manager,
  93. uint32_t scene_id) {
  94. furi_assert(scene_manager);
  95. uint32_t prev_scene_id = 0;
  96. uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  97. SceneManagerIdStack_it_t scene_it;
  98. SceneManagerIdStack_it_last(scene_it, scene_manager->scene_id_stack);
  99. // Search scene with given id in navigation stack
  100. bool scene_found = false;
  101. while(!scene_found) {
  102. SceneManagerIdStack_previous(scene_it);
  103. if(SceneManagerIdStack_end_p(scene_it)) {
  104. return false;
  105. }
  106. prev_scene_id = *SceneManagerIdStack_ref(scene_it);
  107. if(prev_scene_id == scene_id) {
  108. scene_found = true;
  109. }
  110. }
  111. // Remove all scene id from navigation stack
  112. SceneManagerIdStack_next(scene_it);
  113. SceneManagerIdStack_pop_until(scene_manager->scene_id_stack, scene_it);
  114. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  115. scene_manager->scene_handlers->on_enter_handlers[prev_scene_id](scene_manager->context);
  116. return true;
  117. }
  118. bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id) {
  119. furi_assert(scene_manager);
  120. bool scene_found = false;
  121. uint32_t prev_scene_id;
  122. SceneManagerIdStack_it_t scene_it;
  123. SceneManagerIdStack_it_last(scene_it, scene_manager->scene_id_stack);
  124. // Perform search in scene stack
  125. while(!scene_found) {
  126. SceneManagerIdStack_previous(scene_it);
  127. if(SceneManagerIdStack_end_p(scene_it)) {
  128. break;
  129. }
  130. prev_scene_id = *SceneManagerIdStack_ref(scene_it);
  131. if(prev_scene_id == scene_id) {
  132. scene_found = true;
  133. }
  134. }
  135. return scene_found;
  136. }
  137. bool scene_manager_search_and_switch_to_another_scene(
  138. SceneManager* scene_manager,
  139. uint32_t scene_id) {
  140. furi_assert(scene_manager);
  141. furi_assert(scene_id < scene_manager->scene_handlers->scene_num);
  142. uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  143. SceneManagerIdStack_it_t scene_it;
  144. SceneManagerIdStack_it(scene_it, scene_manager->scene_id_stack);
  145. SceneManagerIdStack_next(scene_it);
  146. // Remove all scene id from navigation stack until first scene
  147. SceneManagerIdStack_pop_until(scene_manager->scene_id_stack, scene_it);
  148. // Add next scene
  149. SceneManagerIdStack_push_back(scene_manager->scene_id_stack, scene_id);
  150. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  151. scene_manager->scene_handlers->on_enter_handlers[scene_id](scene_manager->context);
  152. return true;
  153. }
  154. void scene_manager_stop(SceneManager* scene_manager) {
  155. furi_assert(scene_manager);
  156. if(SceneManagerIdStack_size(scene_manager->scene_id_stack)) {
  157. uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
  158. scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
  159. }
  160. }