popup.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. FuriTimer* 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 =
  81. popup->timer_period_in_ms / (1000.0f / furi_kernel_get_tick_frequency());
  82. if(timer_period == 0) timer_period = 1;
  83. if(furi_timer_start(popup->timer, timer_period) != FuriStatusOk) {
  84. furi_assert(0);
  85. };
  86. }
  87. }
  88. void popup_stop_timer(void* context) {
  89. Popup* popup = context;
  90. furi_timer_stop(popup->timer);
  91. }
  92. Popup* popup_alloc() {
  93. Popup* popup = malloc(sizeof(Popup));
  94. popup->view = view_alloc();
  95. popup->timer = furi_timer_alloc(popup_timer_callback, FuriTimerTypeOnce, popup);
  96. furi_assert(popup->timer);
  97. popup->timer_period_in_ms = 1000;
  98. popup->timer_enabled = false;
  99. view_set_context(popup->view, popup);
  100. view_allocate_model(popup->view, ViewModelTypeLockFree, sizeof(PopupModel));
  101. view_set_draw_callback(popup->view, popup_view_draw_callback);
  102. view_set_input_callback(popup->view, popup_view_input_callback);
  103. view_set_enter_callback(popup->view, popup_start_timer);
  104. view_set_exit_callback(popup->view, popup_stop_timer);
  105. with_view_model(
  106. popup->view, (PopupModel * model) {
  107. model->header.text = NULL;
  108. model->header.x = 0;
  109. model->header.y = 0;
  110. model->header.horizontal = AlignLeft;
  111. model->header.vertical = AlignBottom;
  112. model->text.text = NULL;
  113. model->text.x = 0;
  114. model->text.y = 0;
  115. model->text.horizontal = AlignLeft;
  116. model->text.vertical = AlignBottom;
  117. model->icon.x = 0;
  118. model->icon.y = 0;
  119. model->icon.icon = NULL;
  120. return true;
  121. });
  122. return popup;
  123. }
  124. void popup_free(Popup* popup) {
  125. furi_assert(popup);
  126. furi_timer_free(popup->timer);
  127. view_free(popup->view);
  128. free(popup);
  129. }
  130. View* popup_get_view(Popup* popup) {
  131. furi_assert(popup);
  132. return popup->view;
  133. }
  134. void popup_set_callback(Popup* popup, PopupCallback callback) {
  135. furi_assert(popup);
  136. popup->callback = callback;
  137. }
  138. void popup_set_context(Popup* popup, void* context) {
  139. furi_assert(popup);
  140. popup->context = context;
  141. }
  142. void popup_set_header(
  143. Popup* popup,
  144. const char* text,
  145. uint8_t x,
  146. uint8_t y,
  147. Align horizontal,
  148. Align vertical) {
  149. furi_assert(popup);
  150. with_view_model(
  151. popup->view, (PopupModel * model) {
  152. model->header.text = text;
  153. model->header.x = x;
  154. model->header.y = y;
  155. model->header.horizontal = horizontal;
  156. model->header.vertical = vertical;
  157. return true;
  158. });
  159. }
  160. void popup_set_text(
  161. Popup* popup,
  162. const char* text,
  163. uint8_t x,
  164. uint8_t y,
  165. Align horizontal,
  166. Align vertical) {
  167. furi_assert(popup);
  168. with_view_model(
  169. popup->view, (PopupModel * model) {
  170. model->text.text = text;
  171. model->text.x = x;
  172. model->text.y = y;
  173. model->text.horizontal = horizontal;
  174. model->text.vertical = vertical;
  175. return true;
  176. });
  177. }
  178. void popup_set_icon(Popup* popup, uint8_t x, uint8_t y, const Icon* icon) {
  179. furi_assert(popup);
  180. with_view_model(
  181. popup->view, (PopupModel * model) {
  182. model->icon.x = x;
  183. model->icon.y = y;
  184. model->icon.icon = icon;
  185. return true;
  186. });
  187. }
  188. void popup_set_timeout(Popup* popup, uint32_t timeout_in_ms) {
  189. furi_assert(popup);
  190. popup->timer_period_in_ms = timeout_in_ms;
  191. }
  192. void popup_enable_timeout(Popup* popup) {
  193. popup->timer_enabled = true;
  194. }
  195. void popup_disable_timeout(Popup* popup) {
  196. popup->timer_enabled = false;
  197. }
  198. void popup_reset(Popup* popup) {
  199. furi_assert(popup);
  200. with_view_model(
  201. popup->view, (PopupModel * model) {
  202. memset(&model->header, 0, sizeof(model->header));
  203. memset(&model->text, 0, sizeof(model->text));
  204. memset(&model->icon, 0, sizeof(model->icon));
  205. return false;
  206. });
  207. popup->callback = NULL;
  208. popup->context = NULL;
  209. popup->timer_enabled = false;
  210. popup->timer_period_in_ms = 0;
  211. }