remote.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. #include "remote.h"
  2. #include "../subghz_remote_app_i.h"
  3. #include <input/input.h>
  4. #include <gui/elements.h>
  5. #include <lib/toolbox/path.h>
  6. #define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 30
  7. #define SUBREM_VIEW_REMOTE_LEFT_OFFSET 10
  8. #define SUBREM_VIEW_REMOTE_RIGHT_OFFSET 0
  9. struct SubRemViewRemote {
  10. View* view;
  11. SubRemViewRemoteCallback callback;
  12. void* context;
  13. };
  14. typedef struct {
  15. char* labels[SubRemSubKeyNameMaxCount];
  16. SubRemViewRemoteState state;
  17. uint8_t pressed_btn;
  18. bool is_external;
  19. } SubRemViewRemoteModel;
  20. void subrem_view_remote_set_callback(
  21. SubRemViewRemote* subrem_view_remote,
  22. SubRemViewRemoteCallback callback,
  23. void* context) {
  24. furi_assert(subrem_view_remote);
  25. subrem_view_remote->callback = callback;
  26. subrem_view_remote->context = context;
  27. }
  28. void subrem_view_remote_update_data_labels(
  29. SubRemViewRemote* subrem_view_remote,
  30. SubRemSubFilePreset** subs_presets) {
  31. furi_assert(subrem_view_remote);
  32. furi_assert(subs_presets);
  33. FuriString* labels[SubRemSubKeyNameMaxCount];
  34. SubRemSubFilePreset* sub_preset;
  35. for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
  36. sub_preset = subs_presets[i];
  37. switch(sub_preset->load_state) {
  38. case SubRemLoadSubStateOK:
  39. if(!furi_string_empty(sub_preset->label)) {
  40. labels[i] = furi_string_alloc_set(sub_preset->label);
  41. } else if(!furi_string_empty(sub_preset->file_path)) {
  42. labels[i] = furi_string_alloc();
  43. path_extract_filename(sub_preset->file_path, labels[i], true);
  44. } else {
  45. labels[i] = furi_string_alloc_set("Empty Label");
  46. }
  47. break;
  48. case SubRemLoadSubStateErrorNoFile:
  49. labels[i] = furi_string_alloc_set("[X] Can't open file");
  50. break;
  51. case SubRemLoadSubStateErrorFreq:
  52. case SubRemLoadSubStateErrorMod:
  53. case SubRemLoadSubStateErrorProtocol:
  54. labels[i] = furi_string_alloc_set("[X] Error in .sub file");
  55. break;
  56. default:
  57. labels[i] = furi_string_alloc_set("");
  58. break;
  59. }
  60. }
  61. with_view_model(
  62. subrem_view_remote->view,
  63. SubRemViewRemoteModel * model,
  64. {
  65. for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
  66. strncpy(
  67. model->labels[i],
  68. furi_string_get_cstr(labels[i]),
  69. SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
  70. }
  71. },
  72. true);
  73. for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
  74. furi_string_free(labels[i]);
  75. }
  76. }
  77. void subrem_view_remote_set_state(
  78. SubRemViewRemote* subrem_view_remote,
  79. SubRemViewRemoteState state,
  80. uint8_t presed_btn) {
  81. furi_assert(subrem_view_remote);
  82. with_view_model(
  83. subrem_view_remote->view,
  84. SubRemViewRemoteModel * model,
  85. {
  86. model->state = state;
  87. model->pressed_btn = presed_btn;
  88. },
  89. true);
  90. }
  91. void subrem_view_remote_set_radio(SubRemViewRemote* subrem_view_remote, bool external) {
  92. furi_assert(subrem_view_remote);
  93. with_view_model(
  94. subrem_view_remote->view,
  95. SubRemViewRemoteModel * model,
  96. { model->is_external = external; },
  97. true);
  98. }
  99. void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) {
  100. canvas_clear(canvas);
  101. canvas_set_color(canvas, ColorBlack);
  102. // Statusbar
  103. canvas_draw_icon(canvas, 0, 0, &I_status_bar);
  104. if(model->state == SubRemViewRemoteStateOFF) {
  105. canvas_invert_color(canvas);
  106. canvas_draw_rbox(canvas, 12, 0, 52 - 12, 13, 2);
  107. canvas_invert_color(canvas);
  108. canvas_draw_rframe(canvas, 12, 0, 52 - 12, 13, 2);
  109. canvas_draw_str_aligned(canvas, 32, 3, AlignCenter, AlignTop, "Preview");
  110. } else {
  111. canvas_draw_icon(
  112. canvas,
  113. 0,
  114. 2,
  115. (model->is_external) ? &I_External_antenna_20x12 : &I_Internal_antenna_20x12);
  116. canvas_draw_icon(canvas, 50, 0, &I_Status_cube_14x14);
  117. if(model->state == SubRemViewRemoteStateSending) {
  118. canvas_draw_icon_ex(canvas, 52, 3, &I_Pin_arrow_up_7x9, IconRotation90);
  119. }
  120. }
  121. //Icons for Labels
  122. const uint8_t list_y = 14;
  123. canvas_draw_icon(canvas, 1, list_y + 5, &I_ButtonUp_7x4);
  124. canvas_draw_icon(canvas, 1, list_y + 15, &I_ButtonDown_7x4);
  125. canvas_draw_icon(canvas, 2, list_y + 23, &I_ButtonLeft_4x7);
  126. canvas_draw_icon(canvas, 2, list_y + 33, &I_ButtonRight_4x7);
  127. canvas_draw_icon(canvas, 0, list_y + 42, &I_Ok_btn_9x9);
  128. //Labels
  129. canvas_set_font(canvas, FontSecondary);
  130. uint8_t y = list_y;
  131. for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
  132. elements_text_box(
  133. canvas,
  134. SUBREM_VIEW_REMOTE_LEFT_OFFSET,
  135. y + 2,
  136. 64 - SUBREM_VIEW_REMOTE_LEFT_OFFSET - SUBREM_VIEW_REMOTE_RIGHT_OFFSET,
  137. 12,
  138. AlignLeft,
  139. AlignBottom,
  140. model->labels[i],
  141. false);
  142. y += 10;
  143. }
  144. if(model->state != SubRemViewRemoteStateOFF) {
  145. // D-pad 59x62
  146. const uint8_t d_pad_x = 3;
  147. const uint8_t d_pad_y = 66;
  148. canvas_draw_icon(canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 0 * (20 + 1), &I_up);
  149. canvas_draw_icon(canvas, d_pad_x + 0 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_left);
  150. canvas_draw_icon(canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_ok);
  151. canvas_draw_icon(canvas, d_pad_x + 2 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_right);
  152. canvas_draw_icon(canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 2 * (20 + 1), &I_down);
  153. if(model->state == SubRemViewRemoteStateSending) {
  154. switch(model->pressed_btn) {
  155. case SubRemSubKeyNameUp:
  156. canvas_draw_icon(
  157. canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 0 * (20 + 1), &I_up_hover);
  158. break;
  159. case SubRemSubKeyNameDown:
  160. canvas_draw_icon(
  161. canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 2 * (20 + 1), &I_down_hover);
  162. break;
  163. case SubRemSubKeyNameLeft:
  164. canvas_draw_icon(
  165. canvas, d_pad_x + 0 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_left_hover);
  166. break;
  167. case SubRemSubKeyNameRight:
  168. canvas_draw_icon(
  169. canvas, d_pad_x + 2 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_right_hover);
  170. break;
  171. case SubRemSubKeyNameOk:
  172. canvas_draw_icon(
  173. canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_ok_hover);
  174. break;
  175. default:
  176. break;
  177. }
  178. }
  179. } else {
  180. canvas_draw_icon(canvas, 2, 128 - 11, &I_ButtonLeft_4x7);
  181. canvas_draw_str_aligned(canvas, 8, 128 - 4, AlignLeft, AlignBottom, "Back");
  182. canvas_draw_icon(canvas, 58, 128 - 11, &I_ButtonRight_4x7);
  183. canvas_draw_str_aligned(canvas, 56, 128 - 4, AlignRight, AlignBottom, "Save");
  184. }
  185. }
  186. bool subrem_view_remote_input(InputEvent* event, void* context) {
  187. furi_assert(context);
  188. SubRemViewRemote* subrem_view_remote = context;
  189. if(event->key == InputKeyBack && event->type == InputTypeLong) {
  190. subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context);
  191. return true;
  192. } else if(event->key == InputKeyBack && event->type == InputTypeShort) {
  193. with_view_model(
  194. subrem_view_remote->view,
  195. SubRemViewRemoteModel * model,
  196. { model->pressed_btn = 0; },
  197. true);
  198. subrem_view_remote->callback(
  199. SubRemCustomEventViewRemoteForcedStop, subrem_view_remote->context);
  200. return true;
  201. } else if(event->key == InputKeyBack) {
  202. return true;
  203. }
  204. // BACK button processing end
  205. if(event->key == InputKeyUp && event->type == InputTypePress) {
  206. subrem_view_remote->callback(
  207. SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context);
  208. return true;
  209. } else if(event->key == InputKeyDown && event->type == InputTypePress) {
  210. subrem_view_remote->callback(
  211. SubRemCustomEventViewRemoteStartDOWN, subrem_view_remote->context);
  212. return true;
  213. } else if(event->key == InputKeyLeft && event->type == InputTypePress) {
  214. subrem_view_remote->callback(
  215. SubRemCustomEventViewRemoteStartLEFT, subrem_view_remote->context);
  216. return true;
  217. } else if(event->key == InputKeyRight && event->type == InputTypePress) {
  218. subrem_view_remote->callback(
  219. SubRemCustomEventViewRemoteStartRIGHT, subrem_view_remote->context);
  220. return true;
  221. } else if(event->key == InputKeyOk && event->type == InputTypePress) {
  222. subrem_view_remote->callback(
  223. SubRemCustomEventViewRemoteStartOK, subrem_view_remote->context);
  224. return true;
  225. } else if(event->type == InputTypeRelease) {
  226. subrem_view_remote->callback(SubRemCustomEventViewRemoteStop, subrem_view_remote->context);
  227. return true;
  228. }
  229. return true;
  230. }
  231. void subrem_view_remote_enter(void* context) {
  232. furi_assert(context);
  233. }
  234. void subrem_view_remote_exit(void* context) {
  235. furi_assert(context);
  236. }
  237. SubRemViewRemote* subrem_view_remote_alloc(void) {
  238. SubRemViewRemote* subrem_view_remote = malloc(sizeof(SubRemViewRemote));
  239. // View allocation and configuration
  240. subrem_view_remote->view = view_alloc();
  241. view_allocate_model(
  242. subrem_view_remote->view, ViewModelTypeLocking, sizeof(SubRemViewRemoteModel));
  243. view_set_context(subrem_view_remote->view, subrem_view_remote);
  244. view_set_orientation(subrem_view_remote->view, ViewOrientationVertical);
  245. view_set_draw_callback(subrem_view_remote->view, (ViewDrawCallback)subrem_view_remote_draw);
  246. view_set_input_callback(subrem_view_remote->view, subrem_view_remote_input);
  247. view_set_enter_callback(subrem_view_remote->view, subrem_view_remote_enter);
  248. view_set_exit_callback(subrem_view_remote->view, subrem_view_remote_exit);
  249. with_view_model(
  250. subrem_view_remote->view,
  251. SubRemViewRemoteModel * model,
  252. {
  253. model->state = SubRemViewRemoteStateIdle;
  254. for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
  255. model->labels[i] = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
  256. strcpy(model->labels[i], "");
  257. }
  258. model->pressed_btn = 0;
  259. model->is_external = false;
  260. },
  261. true);
  262. return subrem_view_remote;
  263. }
  264. void subrem_view_remote_free(SubRemViewRemote* subghz_remote) {
  265. furi_assert(subghz_remote);
  266. with_view_model(
  267. subghz_remote->view,
  268. SubRemViewRemoteModel * model,
  269. {
  270. for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
  271. free(model->labels[i]);
  272. }
  273. },
  274. true);
  275. view_free(subghz_remote->view);
  276. free(subghz_remote);
  277. }
  278. View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote) {
  279. furi_assert(subrem_view_remote);
  280. return subrem_view_remote->view;
  281. }