view_composed.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "gui/view.h"
  2. #include "furi/memmgr.h"
  3. #include "view_composed.h"
  4. #include "view_i.h"
  5. typedef struct {
  6. View* bottom;
  7. View* top;
  8. bool top_enabled;
  9. } ViewComposedModel;
  10. struct ViewComposed {
  11. View* view;
  12. };
  13. static void view_composed_draw(Canvas* canvas, void* model);
  14. static bool view_composed_input(InputEvent* event, void* context);
  15. static void view_composed_update_callback(View* view_top_or_bottom, void* context) {
  16. furi_assert(view_top_or_bottom);
  17. furi_assert(context);
  18. View* view_composed_view = context;
  19. view_composed_view->update_callback(
  20. view_composed_view, view_composed_view->update_callback_context);
  21. }
  22. static void view_composed_enter(void* context) {
  23. furi_assert(context);
  24. ViewComposed* view_composed = context;
  25. ViewComposedModel* model = view_get_model(view_composed->view);
  26. /* if more than 1 composed views hold same view it has to reassign update_callback_context */
  27. if(model->bottom) {
  28. view_set_update_callback_context(model->bottom, view_composed->view);
  29. if(model->bottom->enter_callback) {
  30. model->bottom->enter_callback(model->bottom->context);
  31. }
  32. }
  33. if(model->top) {
  34. view_set_update_callback_context(model->top, view_composed->view);
  35. if(model->top->enter_callback) {
  36. model->top->enter_callback(model->top->context);
  37. }
  38. }
  39. view_commit_model(view_composed->view, false);
  40. }
  41. static void view_composed_exit(void* context) {
  42. furi_assert(context);
  43. ViewComposed* view_composed = context;
  44. ViewComposedModel* model = view_get_model(view_composed->view);
  45. if(model->bottom) {
  46. if(model->bottom->exit_callback) {
  47. model->bottom->exit_callback(model->bottom->context);
  48. }
  49. }
  50. if(model->top) {
  51. if(model->top->exit_callback) {
  52. model->top->exit_callback(model->top->context);
  53. }
  54. }
  55. view_commit_model(view_composed->view, false);
  56. }
  57. ViewComposed* view_composed_alloc(void) {
  58. ViewComposed* view_composed = furi_alloc(sizeof(ViewComposed));
  59. view_composed->view = view_alloc();
  60. view_allocate_model(view_composed->view, ViewModelTypeLocking, sizeof(ViewComposedModel));
  61. view_set_draw_callback(view_composed->view, view_composed_draw);
  62. view_set_input_callback(view_composed->view, view_composed_input);
  63. view_set_context(view_composed->view, view_composed);
  64. view_set_enter_callback(view_composed->view, view_composed_enter);
  65. view_set_exit_callback(view_composed->view, view_composed_exit);
  66. return view_composed;
  67. }
  68. void view_composed_free(ViewComposed* view_composed) {
  69. furi_assert(view_composed);
  70. ViewComposedModel* view_composed_model = view_get_model(view_composed->view);
  71. view_set_update_callback(view_composed_model->bottom, NULL);
  72. view_set_update_callback_context(view_composed_model->bottom, NULL);
  73. view_set_update_callback(view_composed_model->top, NULL);
  74. view_set_update_callback_context(view_composed_model->top, NULL);
  75. view_commit_model(view_composed->view, true);
  76. view_free(view_composed->view);
  77. free(view_composed);
  78. }
  79. static void view_composed_draw(Canvas* canvas, void* model) {
  80. furi_assert(model);
  81. ViewComposedModel* view_composed_model = model;
  82. view_draw(view_composed_model->bottom, canvas);
  83. if(view_composed_model->top_enabled && view_composed_model->top) {
  84. view_draw(view_composed_model->top, canvas);
  85. }
  86. }
  87. static bool view_composed_input(InputEvent* event, void* context) {
  88. furi_assert(event);
  89. furi_assert(context);
  90. ViewComposed* view_composed = context;
  91. ViewComposedModel* view_composed_model = view_get_model(view_composed->view);
  92. bool consumed = false;
  93. if(view_composed_model->top_enabled && view_composed_model->top) {
  94. consumed = view_input(view_composed_model->top, event);
  95. }
  96. if(!consumed) {
  97. consumed = view_input(view_composed_model->bottom, event);
  98. }
  99. view_commit_model(view_composed->view, false);
  100. return consumed;
  101. }
  102. void view_composed_top_enable(ViewComposed* view_composed, bool enable) {
  103. furi_assert(view_composed);
  104. ViewComposedModel* view_composed_model = view_get_model(view_composed->view);
  105. bool update = (view_composed_model->top_enabled != enable);
  106. view_composed_model->top_enabled = enable;
  107. view_commit_model(view_composed->view, update);
  108. }
  109. void view_composed_tie_views(ViewComposed* view_composed, View* view_bottom, View* view_top) {
  110. furi_assert(view_composed);
  111. furi_assert(view_bottom);
  112. ViewComposedModel* view_composed_model = view_get_model(view_composed->view);
  113. if(view_composed_model->bottom) {
  114. view_set_update_callback(view_composed_model->bottom, NULL);
  115. view_set_update_callback_context(view_composed_model->bottom, NULL);
  116. }
  117. if(view_composed_model->top) {
  118. view_set_update_callback(view_composed_model->top, NULL);
  119. view_set_update_callback_context(view_composed_model->top, NULL);
  120. }
  121. view_composed_model->bottom = view_bottom;
  122. view_set_update_callback(view_bottom, view_composed_update_callback);
  123. view_set_update_callback_context(view_bottom, view_composed->view);
  124. view_composed_model->top = view_top;
  125. view_set_update_callback(view_top, view_composed_update_callback);
  126. view_set_update_callback_context(view_top, view_composed->view);
  127. view_commit_model(view_composed->view, true);
  128. }
  129. View* view_composed_get_view(ViewComposed* view_composed) {
  130. furi_assert(view_composed);
  131. return view_composed->view;
  132. }