view_stack.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #include "gui/view.h"
  2. #include "furi/memmgr.h"
  3. #include "view_stack.h"
  4. #include "view_i.h"
  5. #define MAX_VIEWS 3
  6. typedef struct {
  7. View* views[MAX_VIEWS];
  8. } ViewStackModel;
  9. struct ViewStack {
  10. View* view;
  11. };
  12. static void view_stack_draw(Canvas* canvas, void* model);
  13. static bool view_stack_input(InputEvent* event, void* context);
  14. static void view_stack_update_callback(View* view_top_or_bottom, void* context) {
  15. furi_assert(view_top_or_bottom);
  16. furi_assert(context);
  17. View* view_stack_view = context;
  18. if(view_stack_view->update_callback) {
  19. view_stack_view->update_callback(
  20. view_stack_view, view_stack_view->update_callback_context);
  21. }
  22. }
  23. static void view_stack_enter(void* context) {
  24. furi_assert(context);
  25. ViewStack* view_stack = context;
  26. ViewStackModel* model = view_get_model(view_stack->view);
  27. /* if more than 1 Stack View hold same view they have to reassign update_callback_context */
  28. for(int i = 0; i < MAX_VIEWS; ++i) {
  29. if(model->views[i]) {
  30. view_set_update_callback_context(model->views[i], view_stack->view);
  31. if(model->views[i]->enter_callback) {
  32. model->views[i]->enter_callback(model->views[i]->context);
  33. }
  34. }
  35. }
  36. view_commit_model(view_stack->view, false);
  37. }
  38. static void view_stack_exit(void* context) {
  39. furi_assert(context);
  40. ViewStack* view_stack = context;
  41. ViewStackModel* model = view_get_model(view_stack->view);
  42. for(int i = 0; i < MAX_VIEWS; ++i) {
  43. if(model->views[i] && model->views[i]->exit_callback) {
  44. model->views[i]->exit_callback(model->views[i]->context);
  45. }
  46. }
  47. view_commit_model(view_stack->view, false);
  48. }
  49. ViewStack* view_stack_alloc(void) {
  50. ViewStack* view_stack = malloc(sizeof(ViewStack));
  51. view_stack->view = view_alloc();
  52. view_allocate_model(view_stack->view, ViewModelTypeLocking, sizeof(ViewStackModel));
  53. view_set_draw_callback(view_stack->view, view_stack_draw);
  54. view_set_input_callback(view_stack->view, view_stack_input);
  55. view_set_context(view_stack->view, view_stack);
  56. view_set_enter_callback(view_stack->view, view_stack_enter);
  57. view_set_exit_callback(view_stack->view, view_stack_exit);
  58. return view_stack;
  59. }
  60. void view_stack_free(ViewStack* view_stack) {
  61. furi_assert(view_stack);
  62. ViewStackModel* model = view_get_model(view_stack->view);
  63. for(int i = 0; i < MAX_VIEWS; ++i) {
  64. if(model->views[i]) {
  65. view_set_update_callback(model->views[i], NULL);
  66. view_set_update_callback_context(model->views[i], NULL);
  67. }
  68. }
  69. view_commit_model(view_stack->view, false);
  70. view_free(view_stack->view);
  71. free(view_stack);
  72. }
  73. static void view_stack_draw(Canvas* canvas, void* _model) {
  74. furi_assert(_model);
  75. ViewStackModel* model = _model;
  76. for(int i = 0; i < MAX_VIEWS; ++i) {
  77. if(model->views[i]) {
  78. view_draw(model->views[i], canvas);
  79. }
  80. }
  81. }
  82. static bool view_stack_input(InputEvent* event, void* context) {
  83. furi_assert(event);
  84. furi_assert(context);
  85. ViewStack* view_stack = context;
  86. bool consumed = false;
  87. ViewStackModel* model = view_get_model(view_stack->view);
  88. for(int i = MAX_VIEWS - 1; i >= 0; i--) {
  89. if(model->views[i] && view_input(model->views[i], event)) {
  90. consumed = true;
  91. break;
  92. }
  93. }
  94. view_commit_model(view_stack->view, false);
  95. return consumed;
  96. }
  97. void view_stack_add_view(ViewStack* view_stack, View* view) {
  98. furi_assert(view_stack);
  99. furi_assert(view);
  100. bool result = false;
  101. ViewStackModel* model = view_get_model(view_stack->view);
  102. for(int i = 0; i < MAX_VIEWS; ++i) {
  103. if(!model->views[i]) {
  104. model->views[i] = view;
  105. view_set_update_callback(model->views[i], view_stack_update_callback);
  106. view_set_update_callback_context(model->views[i], view_stack->view);
  107. if(view->enter_callback) {
  108. view->enter_callback(view->context);
  109. }
  110. result = true;
  111. break;
  112. }
  113. }
  114. view_commit_model(view_stack->view, result);
  115. furi_assert(result);
  116. }
  117. void view_stack_remove_view(ViewStack* view_stack, View* view) {
  118. furi_assert(view_stack);
  119. furi_assert(view);
  120. /* Removing view on-the-go is dangerous, but it is protected with
  121. * Locking model, so system is consistent at any time. */
  122. bool result = false;
  123. ViewStackModel* model = view_get_model(view_stack->view);
  124. for(int i = 0; i < MAX_VIEWS; ++i) {
  125. if(model->views[i] == view) {
  126. if(view->exit_callback) {
  127. view->exit_callback(view->context);
  128. }
  129. view_set_update_callback(model->views[i], NULL);
  130. view_set_update_callback_context(model->views[i], NULL);
  131. model->views[i] = NULL;
  132. result = true;
  133. break;
  134. }
  135. }
  136. view_commit_model(view_stack->view, result);
  137. furi_assert(result);
  138. }
  139. View* view_stack_get_view(ViewStack* view_stack) {
  140. furi_assert(view_stack);
  141. return view_stack->view;
  142. }