view_controller.hpp 4.4 KB

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