xremote_custom_view.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*!
  2. * @file flipper-xremote/views/xremote_custom_view.c
  3. @license This project is released under the GNU GPLv3 License
  4. * @copyright (c) 2023 Sandro Kalatozishvili (s.kalatoz@gmail.com)
  5. *
  6. * @brief Custom layout UI and view functionality for remote buttons.
  7. */
  8. #include "xremote_custom_view.h"
  9. #include "../xremote_app.h"
  10. static void xremote_custom_view_draw_vertical(Canvas* canvas, XRemoteViewModel* model) {
  11. XRemoteAppButtons* buttons = model->context;
  12. FuriString* text = model->hold && model->ok_pressed ? buttons->custom_ok_hold :
  13. buttons->custom_ok;
  14. xremote_canvas_draw_button_wide(
  15. canvas, model->ok_pressed, 0, 27, furi_string_get_cstr(text), XRemoteIconEnter);
  16. text = model->hold && model->up_pressed ? buttons->custom_up_hold : buttons->custom_up;
  17. xremote_canvas_draw_button_wide(
  18. canvas, model->up_pressed, 0, 45, furi_string_get_cstr(text), XRemoteIconArrowUp);
  19. text = model->hold && model->down_pressed ? buttons->custom_down_hold : buttons->custom_down;
  20. xremote_canvas_draw_button_wide(
  21. canvas, model->down_pressed, 0, 63, furi_string_get_cstr(text), XRemoteIconArrowDown);
  22. text = model->hold && model->left_pressed ? buttons->custom_left_hold : buttons->custom_left;
  23. xremote_canvas_draw_button_wide(
  24. canvas, model->left_pressed, 0, 81, furi_string_get_cstr(text), XRemoteIconArrowLeft);
  25. text = model->hold && model->right_pressed ? buttons->custom_right_hold :
  26. buttons->custom_right;
  27. xremote_canvas_draw_button_wide(
  28. canvas, model->right_pressed, 0, 99, furi_string_get_cstr(text), XRemoteIconArrowRight);
  29. }
  30. static void xremote_custom_view_draw_horizontal(Canvas* canvas, XRemoteViewModel* model) {
  31. XRemoteAppButtons* buttons = model->context;
  32. FuriString* text = model->hold && model->ok_pressed ? buttons->custom_ok_hold :
  33. buttons->custom_ok;
  34. xremote_canvas_draw_button_wide(
  35. canvas, model->ok_pressed, 0, 7, furi_string_get_cstr(text), XRemoteIconEnter);
  36. text = model->hold && model->up_pressed ? buttons->custom_up_hold : buttons->custom_up;
  37. xremote_canvas_draw_button_wide(
  38. canvas, model->up_pressed, 0, 25, furi_string_get_cstr(text), XRemoteIconArrowUp);
  39. text = model->hold && model->down_pressed ? buttons->custom_down_hold : buttons->custom_down;
  40. xremote_canvas_draw_button_wide(
  41. canvas, model->down_pressed, 0, 43, furi_string_get_cstr(text), XRemoteIconArrowDown);
  42. text = model->hold && model->left_pressed ? buttons->custom_left_hold : buttons->custom_left;
  43. xremote_canvas_draw_button_wide(
  44. canvas, model->left_pressed, 64, 20, furi_string_get_cstr(text), XRemoteIconArrowLeft);
  45. text = model->hold && model->right_pressed ? buttons->custom_right_hold :
  46. buttons->custom_right;
  47. xremote_canvas_draw_button_wide(
  48. canvas, model->right_pressed, 64, 38, furi_string_get_cstr(text), XRemoteIconArrowRight);
  49. }
  50. static void xremote_custom_view_draw_page_name(Canvas* canvas, ViewOrientation orientation) {
  51. Align align = orientation == ViewOrientationHorizontal ? AlignRight : AlignLeft;
  52. uint8_t x = orientation == ViewOrientationHorizontal ? 128 : 0;
  53. uint8_t y = orientation == ViewOrientationHorizontal ? 10 : 12;
  54. elements_multiline_text_aligned(canvas, x, y, align, AlignTop, "Custom");
  55. }
  56. static void xremote_custom_view_draw_callback(Canvas* canvas, void* context) {
  57. furi_assert(context);
  58. XRemoteViewModel* model = context;
  59. XRemoteAppButtons* buttons = model->context;
  60. XRemoteAppContext* app_ctx = buttons->app_ctx;
  61. const char* exit_str = xremote_app_context_get_exit_str(app_ctx);
  62. ViewOrientation orientation = app_ctx->app_settings->orientation;
  63. XRemoteViewDrawFunction xremote_custom_view_draw_body;
  64. xremote_custom_view_draw_body = orientation == ViewOrientationVertical ?
  65. xremote_custom_view_draw_vertical :
  66. xremote_custom_view_draw_horizontal;
  67. xremote_canvas_draw_header(canvas, orientation, NULL);
  68. xremote_custom_view_draw_page_name(canvas, orientation);
  69. xremote_custom_view_draw_body(canvas, model);
  70. xremote_canvas_draw_exit_footer(canvas, orientation, exit_str);
  71. }
  72. static void xremote_custom_view_process(XRemoteView* view, InputEvent* event) {
  73. with_view_model(
  74. xremote_view_get_view(view),
  75. XRemoteViewModel * model,
  76. {
  77. XRemoteAppButtons* buttons = xremote_view_get_context(view);
  78. XRemoteAppContext* app_ctx = buttons->app_ctx;
  79. XRemoteAppExit exit_behavior = app_ctx->app_settings->exit_behavior;
  80. model->context = buttons;
  81. if(event->type == InputTypeShort) {
  82. InfraredRemoteButton* button = NULL;
  83. if(event->key == InputKeyOk) {
  84. const char* button_name = furi_string_get_cstr(buttons->custom_ok);
  85. button = xremote_view_get_button_by_name(view, button_name);
  86. if(xremote_view_press_button(view, button)) model->ok_pressed = true;
  87. } else if(event->key == InputKeyUp) {
  88. const char* button_name = furi_string_get_cstr(buttons->custom_up);
  89. button = xremote_view_get_button_by_name(view, button_name);
  90. if(xremote_view_press_button(view, button)) model->up_pressed = true;
  91. } else if(event->key == InputKeyDown) {
  92. const char* button_name = furi_string_get_cstr(buttons->custom_down);
  93. button = xremote_view_get_button_by_name(view, button_name);
  94. if(xremote_view_press_button(view, button)) model->down_pressed = true;
  95. } else if(event->key == InputKeyLeft) {
  96. const char* button_name = furi_string_get_cstr(buttons->custom_left);
  97. button = xremote_view_get_button_by_name(view, button_name);
  98. if(xremote_view_press_button(view, button)) model->left_pressed = true;
  99. } else if(event->key == InputKeyRight) {
  100. const char* button_name = furi_string_get_cstr(buttons->custom_right);
  101. button = xremote_view_get_button_by_name(view, button_name);
  102. if(xremote_view_press_button(view, button)) model->right_pressed = true;
  103. } else if(event->key == InputKeyBack && exit_behavior == XRemoteAppExitHold) {
  104. button = xremote_view_get_button_by_name(view, XREMOTE_COMMAND_BACK);
  105. if(xremote_view_press_button(view, button)) model->back_pressed = true;
  106. }
  107. } else if(event->type == InputTypeLong) {
  108. InfraredRemoteButton* button = NULL;
  109. model->hold = true;
  110. if(event->key == InputKeyOk) {
  111. const char* button_name = furi_string_get_cstr(buttons->custom_ok_hold);
  112. button = xremote_view_get_button_by_name(view, button_name);
  113. if(xremote_view_press_button(view, button)) model->ok_pressed = true;
  114. } else if(event->key == InputKeyUp) {
  115. const char* button_name = furi_string_get_cstr(buttons->custom_up_hold);
  116. button = xremote_view_get_button_by_name(view, button_name);
  117. if(xremote_view_press_button(view, button)) model->up_pressed = true;
  118. } else if(event->key == InputKeyDown) {
  119. const char* button_name = furi_string_get_cstr(buttons->custom_down_hold);
  120. button = xremote_view_get_button_by_name(view, button_name);
  121. if(xremote_view_press_button(view, button)) model->down_pressed = true;
  122. } else if(event->key == InputKeyLeft) {
  123. const char* button_name = furi_string_get_cstr(buttons->custom_left_hold);
  124. button = xremote_view_get_button_by_name(view, button_name);
  125. if(xremote_view_press_button(view, button)) model->left_pressed = true;
  126. } else if(event->key == InputKeyRight) {
  127. const char* button_name = furi_string_get_cstr(buttons->custom_right_hold);
  128. button = xremote_view_get_button_by_name(view, button_name);
  129. if(xremote_view_press_button(view, button)) model->right_pressed = true;
  130. } else if(event->key == InputKeyBack && exit_behavior == XRemoteAppExitPress) {
  131. button = xremote_view_get_button_by_name(view, XREMOTE_COMMAND_BACK);
  132. if(xremote_view_press_button(view, button)) model->back_pressed = true;
  133. }
  134. } else if(event->type == InputTypeRelease) {
  135. model->hold = false;
  136. if(event->key == InputKeyOk)
  137. model->ok_pressed = false;
  138. else if(event->key == InputKeyUp)
  139. model->up_pressed = false;
  140. else if(event->key == InputKeyDown)
  141. model->down_pressed = false;
  142. else if(event->key == InputKeyLeft)
  143. model->left_pressed = false;
  144. else if(event->key == InputKeyRight)
  145. model->right_pressed = false;
  146. else if(event->key == InputKeyBack)
  147. model->back_pressed = false;
  148. }
  149. },
  150. true);
  151. }
  152. static bool xremote_custom_view_input_callback(InputEvent* event, void* context) {
  153. furi_assert(context);
  154. XRemoteView* view = (XRemoteView*)context;
  155. XRemoteAppContext* app_ctx = xremote_view_get_app_context(view);
  156. XRemoteAppExit exit_behavior = app_ctx->app_settings->exit_behavior;
  157. if(event->key == InputKeyBack) {
  158. if(event->type == InputTypeShort && exit_behavior == XRemoteAppExitPress)
  159. return false;
  160. else if(event->type == InputTypeLong && exit_behavior == XRemoteAppExitHold)
  161. return false;
  162. }
  163. xremote_custom_view_process(view, event);
  164. return true;
  165. }
  166. XRemoteView* xremote_custom_view_alloc(void* app_ctx, void* model_ctx) {
  167. XRemoteView* view = xremote_view_alloc(
  168. app_ctx, xremote_custom_view_input_callback, xremote_custom_view_draw_callback);
  169. xremote_view_set_context(view, model_ctx, NULL);
  170. with_view_model(
  171. xremote_view_get_view(view),
  172. XRemoteViewModel * model,
  173. {
  174. model->context = model_ctx;
  175. model->up_pressed = false;
  176. model->down_pressed = false;
  177. model->left_pressed = false;
  178. model->right_pressed = false;
  179. model->back_pressed = false;
  180. model->ok_pressed = false;
  181. model->hold = false;
  182. },
  183. true);
  184. return view;
  185. }