ui.c 5.6 KB

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