popup.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "popup.h"
  2. #include <gui/elements.h>
  3. #include <furi.h>
  4. struct Popup {
  5. View* view;
  6. void* context;
  7. PopupCallback callback;
  8. osTimerId_t timer;
  9. uint32_t timer_period_in_ms;
  10. bool timer_enabled;
  11. };
  12. typedef struct {
  13. const char* text;
  14. uint8_t x;
  15. uint8_t y;
  16. Align horizontal;
  17. Align vertical;
  18. } TextElement;
  19. typedef struct {
  20. uint8_t x;
  21. uint8_t y;
  22. const Icon* icon;
  23. } IconElement;
  24. typedef struct {
  25. TextElement header;
  26. TextElement text;
  27. IconElement icon;
  28. } PopupModel;
  29. static void popup_view_draw_callback(Canvas* canvas, void* _model) {
  30. PopupModel* model = _model;
  31. // Prepare canvas
  32. canvas_clear(canvas);
  33. canvas_set_color(canvas, ColorBlack);
  34. if(model->icon.icon != NULL) {
  35. canvas_draw_icon(canvas, model->icon.x, model->icon.y, model->icon.icon);
  36. }
  37. // Draw header
  38. if(model->header.text != NULL) {
  39. canvas_set_font(canvas, FontPrimary);
  40. elements_multiline_text_aligned(
  41. canvas,
  42. model->header.x,
  43. model->header.y,
  44. model->header.horizontal,
  45. model->header.vertical,
  46. model->header.text);
  47. }
  48. // Draw text
  49. if(model->text.text != NULL) {
  50. canvas_set_font(canvas, FontSecondary);
  51. elements_multiline_text_aligned(
  52. canvas,
  53. model->text.x,
  54. model->text.y,
  55. model->text.horizontal,
  56. model->text.vertical,
  57. model->text.text);
  58. }
  59. }
  60. static void popup_timer_callback(void* context) {
  61. furi_assert(context);
  62. Popup* popup = context;
  63. if(popup->callback) {
  64. popup->callback(popup->context);
  65. }
  66. }
  67. static bool popup_view_input_callback(InputEvent* event, void* context) {
  68. Popup* popup = context;
  69. bool consumed = false;
  70. // Process key presses only
  71. if(event->type == InputTypeShort && popup->callback) {
  72. popup->callback(popup->context);
  73. consumed = true;
  74. }
  75. return consumed;
  76. }
  77. void popup_start_timer(void* context) {
  78. Popup* popup = context;
  79. if(popup->timer_enabled) {
  80. uint32_t timer_period = popup->timer_period_in_ms / (1000.0f / osKernelGetTickFreq());
  81. if(timer_period == 0) timer_period = 1;
  82. if(osTimerStart(popup->timer, timer_period) != osOK) {
  83. furi_assert(0);
  84. };
  85. }
  86. }
  87. void popup_stop_timer(void* context) {
  88. Popup* popup = context;
  89. osTimerStop(popup->timer);
  90. }
  91. Popup* popup_alloc() {
  92. Popup* popup = malloc(sizeof(Popup));
  93. popup->view = view_alloc();
  94. popup->timer = osTimerNew(popup_timer_callback, osTimerOnce, popup, NULL);
  95. furi_assert(popup->timer);
  96. popup->timer_period_in_ms = 1000;
  97. popup->timer_enabled = false;
  98. view_set_context(popup->view, popup);
  99. view_allocate_model(popup->view, ViewModelTypeLockFree, sizeof(PopupModel));
  100. view_set_draw_callback(popup->view, popup_view_draw_callback);
  101. view_set_input_callback(popup->view, popup_view_input_callback);
  102. view_set_enter_callback(popup->view, popup_start_timer);
  103. view_set_exit_callback(popup->view, popup_stop_timer);
  104. with_view_model(
  105. popup->view, (PopupModel * model) {
  106. model->header.text = NULL;
  107. model->header.x = 0;
  108. model->header.y = 0;
  109. model->header.horizontal = AlignLeft;
  110. model->header.vertical = AlignBottom;
  111. model->text.text = NULL;
  112. model->text.x = 0;
  113. model->text.y = 0;
  114. model->text.horizontal = AlignLeft;
  115. model->text.vertical = AlignBottom;
  116. model->icon.x = 0;
  117. model->icon.y = 0;
  118. model->icon.icon = NULL;
  119. return true;
  120. });
  121. return popup;
  122. }
  123. void popup_free(Popup* popup) {
  124. furi_assert(popup);
  125. osTimerDelete(popup->timer);
  126. view_free(popup->view);
  127. free(popup);
  128. }
  129. View* popup_get_view(Popup* popup) {
  130. furi_assert(popup);
  131. return popup->view;
  132. }
  133. void popup_set_callback(Popup* popup, PopupCallback callback) {
  134. furi_assert(popup);
  135. popup->callback = callback;
  136. }
  137. void popup_set_context(Popup* popup, void* context) {
  138. furi_assert(popup);
  139. popup->context = context;
  140. }
  141. void popup_set_header(
  142. Popup* popup,
  143. const char* text,
  144. uint8_t x,
  145. uint8_t y,
  146. Align horizontal,
  147. Align vertical) {
  148. furi_assert(popup);
  149. with_view_model(
  150. popup->view, (PopupModel * model) {
  151. model->header.text = text;
  152. model->header.x = x;
  153. model->header.y = y;
  154. model->header.horizontal = horizontal;
  155. model->header.vertical = vertical;
  156. return true;
  157. });
  158. }
  159. void popup_set_text(
  160. Popup* popup,
  161. const char* text,
  162. uint8_t x,
  163. uint8_t y,
  164. Align horizontal,
  165. Align vertical) {
  166. furi_assert(popup);
  167. with_view_model(
  168. popup->view, (PopupModel * model) {
  169. model->text.text = text;
  170. model->text.x = x;
  171. model->text.y = y;
  172. model->text.horizontal = horizontal;
  173. model->text.vertical = vertical;
  174. return true;
  175. });
  176. }
  177. void popup_set_icon(Popup* popup, uint8_t x, uint8_t y, const Icon* icon) {
  178. furi_assert(popup);
  179. with_view_model(
  180. popup->view, (PopupModel * model) {
  181. model->icon.x = x;
  182. model->icon.y = y;
  183. model->icon.icon = icon;
  184. return true;
  185. });
  186. }
  187. void popup_set_timeout(Popup* popup, uint32_t timeout_in_ms) {
  188. furi_assert(popup);
  189. popup->timer_period_in_ms = timeout_in_ms;
  190. }
  191. void popup_enable_timeout(Popup* popup) {
  192. popup->timer_enabled = true;
  193. }
  194. void popup_disable_timeout(Popup* popup) {
  195. popup->timer_enabled = false;
  196. }
  197. void popup_reset(Popup* popup) {
  198. furi_assert(popup);
  199. with_view_model(
  200. popup->view, (PopupModel * model) {
  201. memset(&model->header, 0, sizeof(model->header));
  202. memset(&model->text, 0, sizeof(model->text));
  203. memset(&model->icon, 0, sizeof(model->icon));
  204. return false;
  205. });
  206. popup->callback = NULL;
  207. popup->context = NULL;
  208. popup->timer_enabled = false;
  209. popup->timer_period_in_ms = 0;
  210. }