ui.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved
  2. * See the LICENSE file for information about the license. */
  3. #include "app.h"
  4. /* =========================== Subview handling ================================
  5. * Note that these are not the Flipper subviews, but the subview system
  6. * implemented inside ProtoView.
  7. * ========================================================================== */
  8. /* Return the ID of the currently selected subview, of the current
  9. * view. */
  10. int ui_get_current_subview(ProtoViewApp *app) {
  11. return app->current_subview[app->current_view];
  12. }
  13. /* Called by view rendering callback that has subviews, to show small triangles
  14. * facing down/up if there are other subviews the user can access with up
  15. * and down. */
  16. void ui_show_available_subviews(Canvas *canvas, ProtoViewApp *app,
  17. int last_subview)
  18. {
  19. int subview = ui_get_current_subview(app);
  20. if (subview != 0)
  21. canvas_draw_triangle(canvas,120,5,8,5,CanvasDirectionBottomToTop);
  22. if (subview != last_subview-1)
  23. canvas_draw_triangle(canvas,120,59,8,5,CanvasDirectionTopToBottom);
  24. }
  25. /* Handle up/down keys when we are in a subview. If the function catched
  26. * such keypress, it returns true, so that the actual view input callback
  27. * knows it can just return ASAP without doing anything. */
  28. bool ui_process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subview) {
  29. int subview = ui_get_current_subview(app);
  30. if (input.type == InputTypePress) {
  31. if (input.key == InputKeyUp) {
  32. if (subview != 0)
  33. app->current_subview[app->current_view]--;
  34. return true;
  35. } else if (input.key == InputKeyDown) {
  36. if (subview != last_subview-1)
  37. app->current_subview[app->current_view]++;
  38. return true;
  39. }
  40. }
  41. return false;
  42. }
  43. /* ============================= Text input ====================================
  44. * Normally we just use our own private UI widgets. However for the text input
  45. * widget, that is quite complex, visualizes a keyboard and must be standardized
  46. * for user coherent experience, we use the one provided by the Flipper
  47. * framework. The following two functions allow to show the keyboard to get
  48. * text and later dismiss it.
  49. * ========================================================================== */
  50. /* Show the keyboard, take the user input and store it into the specified
  51. * 'buffer' of 'buflen' total bytes. When the user is done, the done_callback
  52. * is called passing the application context to it. Such callback needs
  53. * to do whatever it wants with the input buffer and dismissi the keyboard
  54. * calling: dismiss_keyboard(app);
  55. *
  56. * Note: if the buffer is not a null-termined zero string, what it contains will
  57. * be used as initial input for the user. */
  58. void ui_show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen,
  59. void (*done_callback)(void*))
  60. {
  61. app->show_text_input = true;
  62. app->text_input_buffer = buffer;
  63. app->text_input_buffer_len = buflen;
  64. app->text_input_done_callback = done_callback;
  65. }
  66. void ui_dismiss_keyboard(ProtoViewApp *app) {
  67. view_dispatcher_stop(app->view_dispatcher);
  68. }
  69. /* ================================= Alert ================================== */
  70. /* Set an alert message to be shown over any currently active view, for
  71. * the specified amount of time of 'ttl' milliseconds. */
  72. void ui_show_alert(ProtoViewApp *app, const char *text, uint32_t ttl) {
  73. app->alert_dismiss_time = furi_get_tick() + furi_ms_to_ticks(ttl);
  74. snprintf(app->alert_text,ALERT_MAX_LEN,"%s",text);
  75. }
  76. /* Cancel the alert before its time has elapsed. */
  77. void ui_dismiss_alert(ProtoViewApp *app) {
  78. app->alert_dismiss_time = 0;
  79. }
  80. /* Show the alert if an alert is set. This is called after the currently
  81. * active view displayed its stuff, so we overwrite the screen with the
  82. * alert message. */
  83. void ui_draw_alert_if_needed(Canvas *canvas, ProtoViewApp *app) {
  84. if (app->alert_dismiss_time == 0) {
  85. /* No active alert. */
  86. return;
  87. } else if (app->alert_dismiss_time < furi_get_tick()) {
  88. /* Alert just expired. */
  89. ui_dismiss_alert(app);
  90. return;
  91. }
  92. /* Show the alert. A box with black border and a text inside. */
  93. canvas_set_font(canvas, FontPrimary);
  94. uint8_t w = canvas_string_width(canvas, app->alert_text);
  95. uint8_t h = 8; // Font height.
  96. uint8_t text_x = 64-(w/2);
  97. uint8_t text_y = 32+4;
  98. uint8_t padding = 3;
  99. canvas_set_color(canvas,ColorBlack);
  100. canvas_draw_box(canvas,text_x-padding,text_y-padding-h,w+padding*2,h+padding*2);
  101. canvas_set_color(canvas,ColorWhite);
  102. canvas_draw_box(canvas,text_x-padding+1,text_y-padding-h+1,w+padding*2-2,h+padding*2-2);
  103. canvas_set_color(canvas,ColorBlack);
  104. canvas_draw_str(canvas,text_x,text_y,app->alert_text);
  105. }
  106. /* =========================== Canvas extensions ============================ */
  107. void canvas_draw_str_with_border(Canvas* canvas, uint8_t x, uint8_t y, const char* str, Color text_color, Color border_color)
  108. {
  109. struct {
  110. uint8_t x; uint8_t y;
  111. } dir[8] = {
  112. {-1,-1},
  113. {0,-1},
  114. {1,-1},
  115. {1,0},
  116. {1,1},
  117. {0,1},
  118. {-1,1},
  119. {-1,0}
  120. };
  121. /* Rotate in all the directions writing the same string to create a
  122. * border, then write the actual string in the other color in the
  123. * middle. */
  124. canvas_set_color(canvas, border_color);
  125. for (int j = 0; j < 8; j++)
  126. canvas_draw_str(canvas,x+dir[j].x,y+dir[j].y,str);
  127. canvas_set_color(canvas, text_color);
  128. canvas_draw_str(canvas,x,y,str);
  129. canvas_set_color(canvas, ColorBlack);
  130. }