loader_menu.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #include <gui/gui.h>
  2. #include <gui/view_dispatcher.h>
  3. #include <gui/modules/menu.h>
  4. #include <gui/modules/submenu.h>
  5. #include <assets_icons.h>
  6. #include <applications.h>
  7. #include "loader_menu.h"
  8. #define TAG "LoaderMenu"
  9. struct LoaderMenu {
  10. Gui* gui;
  11. ViewDispatcher* view_dispatcher;
  12. Menu* primary_menu;
  13. Submenu* settings_menu;
  14. void (*closed_callback)(void*);
  15. void* closed_callback_context;
  16. void (*click_callback)(const char*, void*);
  17. void* click_callback_context;
  18. FuriThread* thread;
  19. };
  20. typedef enum {
  21. LoaderMenuViewPrimary,
  22. LoaderMenuViewSettings,
  23. } LoaderMenuView;
  24. static int32_t loader_menu_thread(void* p);
  25. LoaderMenu* loader_menu_alloc() {
  26. LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu));
  27. loader_menu->gui = furi_record_open(RECORD_GUI);
  28. loader_menu->view_dispatcher = view_dispatcher_alloc();
  29. loader_menu->primary_menu = menu_alloc();
  30. loader_menu->settings_menu = submenu_alloc();
  31. loader_menu->thread = NULL;
  32. return loader_menu;
  33. }
  34. void loader_menu_free(LoaderMenu* loader_menu) {
  35. furi_assert(loader_menu);
  36. // check if thread is running
  37. furi_assert(!loader_menu->thread);
  38. submenu_free(loader_menu->settings_menu);
  39. menu_free(loader_menu->primary_menu);
  40. view_dispatcher_free(loader_menu->view_dispatcher);
  41. furi_record_close(RECORD_GUI);
  42. free(loader_menu);
  43. }
  44. void loader_menu_start(LoaderMenu* loader_menu) {
  45. furi_assert(loader_menu);
  46. furi_assert(!loader_menu->thread);
  47. loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu);
  48. furi_thread_start(loader_menu->thread);
  49. }
  50. void loader_menu_stop(LoaderMenu* loader_menu) {
  51. furi_assert(loader_menu);
  52. furi_assert(loader_menu->thread);
  53. view_dispatcher_stop(loader_menu->view_dispatcher);
  54. furi_thread_join(loader_menu->thread);
  55. furi_thread_free(loader_menu->thread);
  56. loader_menu->thread = NULL;
  57. }
  58. void loader_menu_set_closed_callback(
  59. LoaderMenu* loader_menu,
  60. void (*callback)(void*),
  61. void* context) {
  62. loader_menu->closed_callback = callback;
  63. loader_menu->closed_callback_context = context;
  64. }
  65. void loader_menu_set_click_callback(
  66. LoaderMenu* loader_menu,
  67. void (*callback)(const char*, void*),
  68. void* context) {
  69. loader_menu->click_callback = callback;
  70. loader_menu->click_callback_context = context;
  71. }
  72. static void loader_menu_callback(void* context, uint32_t index) {
  73. LoaderMenu* loader_menu = context;
  74. const char* name = FLIPPER_APPS[index].name;
  75. if(loader_menu->click_callback) {
  76. loader_menu->click_callback(name, loader_menu->click_callback_context);
  77. }
  78. }
  79. static void loader_menu_settings_menu_callback(void* context, uint32_t index) {
  80. LoaderMenu* loader_menu = context;
  81. const char* name = FLIPPER_SETTINGS_APPS[index].name;
  82. if(loader_menu->click_callback) {
  83. loader_menu->click_callback(name, loader_menu->click_callback_context);
  84. }
  85. }
  86. static void loader_menu_switch_to_settings(void* context, uint32_t index) {
  87. UNUSED(index);
  88. LoaderMenu* loader_menu = context;
  89. view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings);
  90. }
  91. static uint32_t loader_menu_switch_to_primary(void* context) {
  92. UNUSED(context);
  93. return LoaderMenuViewPrimary;
  94. }
  95. static uint32_t loader_menu_exit(void* context) {
  96. UNUSED(context);
  97. return VIEW_NONE;
  98. }
  99. static void loader_menu_build_menu(LoaderMenu* loader_menu) {
  100. size_t i;
  101. for(i = 0; i < FLIPPER_APPS_COUNT; i++) {
  102. menu_add_item(
  103. loader_menu->primary_menu,
  104. FLIPPER_APPS[i].name,
  105. FLIPPER_APPS[i].icon,
  106. i,
  107. loader_menu_callback,
  108. (void*)loader_menu);
  109. }
  110. menu_add_item(
  111. loader_menu->primary_menu,
  112. "Settings",
  113. &A_Settings_14,
  114. i++,
  115. loader_menu_switch_to_settings,
  116. loader_menu);
  117. };
  118. static void loader_menu_build_submenu(LoaderMenu* loader_menu) {
  119. for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
  120. submenu_add_item(
  121. loader_menu->settings_menu,
  122. FLIPPER_SETTINGS_APPS[i].name,
  123. i,
  124. loader_menu_settings_menu_callback,
  125. loader_menu);
  126. }
  127. }
  128. static int32_t loader_menu_thread(void* p) {
  129. LoaderMenu* loader_menu = p;
  130. furi_assert(loader_menu);
  131. loader_menu_build_menu(loader_menu);
  132. loader_menu_build_submenu(loader_menu);
  133. view_dispatcher_attach_to_gui(
  134. loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen);
  135. // Primary menu
  136. View* primary_view = menu_get_view(loader_menu->primary_menu);
  137. view_set_context(primary_view, loader_menu->primary_menu);
  138. view_set_previous_callback(primary_view, loader_menu_exit);
  139. view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view);
  140. // Settings menu
  141. View* settings_view = submenu_get_view(loader_menu->settings_menu);
  142. view_set_context(settings_view, loader_menu->settings_menu);
  143. view_set_previous_callback(settings_view, loader_menu_switch_to_primary);
  144. view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view);
  145. view_dispatcher_enable_queue(loader_menu->view_dispatcher);
  146. view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary);
  147. // run view dispatcher
  148. view_dispatcher_run(loader_menu->view_dispatcher);
  149. view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary);
  150. view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings);
  151. if(loader_menu->closed_callback) {
  152. loader_menu->closed_callback(loader_menu->closed_callback_context);
  153. }
  154. return 0;
  155. }