view_controller.hpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #pragma once
  2. #include "view_modules/generic_view_module.h"
  3. #include <map>
  4. #include <core/check.h>
  5. #include <gui/view_dispatcher.h>
  6. #include <callback-connector.h>
  7. #include "typeindex_no_rtti.hpp"
  8. /**
  9. * @brief Controller for switching application views and handling inputs and events
  10. *
  11. * @tparam TApp application class
  12. * @tparam TViewModules variadic list of ViewModules
  13. */
  14. template <typename TApp, typename... TViewModules>
  15. class ViewController {
  16. public:
  17. ViewController() {
  18. event_queue = furi_message_queue_alloc(10, sizeof(typename TApp::Event));
  19. view_dispatcher = view_dispatcher_alloc();
  20. previous_view_callback_pointer = cbc::obtain_connector(
  21. this, &ViewController<TApp, TViewModules...>::previous_view_callback);
  22. [](...) {
  23. }((this->add_view(ext::make_type_index<TViewModules>().hash_code(), new TViewModules()),
  24. 0)...);
  25. gui = static_cast<Gui*>(furi_record_open("gui"));
  26. };
  27. ~ViewController() {
  28. for(auto& it : holder) {
  29. view_dispatcher_remove_view(view_dispatcher, static_cast<uint32_t>(it.first));
  30. delete it.second;
  31. }
  32. view_dispatcher_free(view_dispatcher);
  33. furi_message_queue_free(event_queue);
  34. }
  35. /**
  36. * @brief Get ViewModule pointer
  37. *
  38. * @tparam T Concrete ViewModule class
  39. * @return T* ViewModule pointer
  40. */
  41. template <typename T>
  42. T* get() {
  43. uint32_t view_index = ext::make_type_index<T>().hash_code();
  44. furi_check(holder.count(view_index) != 0);
  45. return static_cast<T*>(holder[view_index]);
  46. }
  47. /**
  48. * @brief Get ViewModule pointer by cast
  49. *
  50. * @tparam T Concrete ViewModule class
  51. * @return T* ViewModule pointer
  52. */
  53. template <typename T>
  54. operator T*() {
  55. uint32_t view_index = ext::make_type_index<T>().hash_code();
  56. furi_check(holder.count(view_index) != 0);
  57. return static_cast<T*>(holder[view_index]);
  58. }
  59. /**
  60. * @brief Switch view to ViewModule
  61. *
  62. * @tparam T Concrete ViewModule class
  63. * @return T* ViewModule pointer
  64. */
  65. template <typename T>
  66. void switch_to() {
  67. uint32_t view_index = ext::make_type_index<T>().hash_code();
  68. furi_check(holder.count(view_index) != 0);
  69. view_dispatcher_switch_to_view(view_dispatcher, view_index);
  70. }
  71. /**
  72. * @brief Receive event from app event queue
  73. *
  74. * @param event event pointer
  75. */
  76. void receive_event(typename TApp::Event* event) {
  77. if(furi_message_queue_get(event_queue, event, 100) != FuriStatusOk) {
  78. event->type = TApp::EventType::Tick;
  79. }
  80. }
  81. /**
  82. * @brief Send event to app event queue
  83. *
  84. * @param event event pointer
  85. */
  86. void send_event(typename TApp::Event* event) {
  87. FuriStatus result = furi_message_queue_put(event_queue, event, FuriWaitForever);
  88. furi_check(result == FuriStatusOk);
  89. }
  90. void attach_to_gui(ViewDispatcherType type) {
  91. view_dispatcher_attach_to_gui(view_dispatcher, gui, type);
  92. }
  93. private:
  94. /**
  95. * @brief ViewModulesHolder
  96. *
  97. */
  98. std::map<size_t, GenericViewModule*> holder;
  99. /**
  100. * @brief App event queue
  101. *
  102. */
  103. FuriMessageQueue* event_queue;
  104. /**
  105. * @brief Main ViewDispatcher pointer
  106. *
  107. */
  108. ViewDispatcher* view_dispatcher;
  109. /**
  110. * @brief Gui record pointer
  111. *
  112. */
  113. Gui* gui;
  114. /**
  115. * @brief Previous view callback fn pointer
  116. *
  117. */
  118. ViewNavigationCallback previous_view_callback_pointer;
  119. /**
  120. * @brief Previous view callback fn
  121. *
  122. * @param context not used
  123. * @return uint32_t VIEW_IGNORE
  124. */
  125. uint32_t previous_view_callback(void* context) {
  126. (void)context;
  127. typename TApp::Event event;
  128. event.type = TApp::EventType::Back;
  129. if(event_queue != NULL) {
  130. send_event(&event);
  131. }
  132. return VIEW_IGNORE;
  133. }
  134. /**
  135. * @brief Add ViewModule to holder
  136. *
  137. * @param view_index view index in holder
  138. * @param view_module view module pointer
  139. */
  140. void add_view(size_t view_index, GenericViewModule* view_module) {
  141. furi_check(holder.count(view_index) == 0);
  142. holder[view_index] = view_module;
  143. View* view = view_module->get_view();
  144. view_dispatcher_add_view(view_dispatcher, static_cast<uint32_t>(view_index), view);
  145. view_set_previous_callback(view, previous_view_callback_pointer);
  146. }
  147. };