int_input.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. #include "int_input.h"
  2. #include <gui/elements.h>
  3. #include <furi.h>
  4. #include <assets_icons.h>
  5. /** IntInput type */
  6. struct IntInput {
  7. View* view;
  8. };
  9. typedef struct {
  10. const uint8_t value;
  11. const uint8_t x;
  12. const uint8_t y;
  13. } IntInputKey;
  14. typedef struct {
  15. const char* header;
  16. uint8_t* bytes;
  17. uint8_t bytes_count;
  18. IntInputCallback input_callback;
  19. IntChangedCallback changed_callback;
  20. void* callback_context;
  21. bool selected_high_nibble;
  22. uint8_t selected_byte;
  23. int8_t selected_row; // row -2 - mini_editor, -1 - input, row 0 & 1 - keyboard
  24. uint8_t selected_column;
  25. uint8_t first_visible_byte;
  26. } IntInputModel;
  27. static const uint8_t keyboard_origin_x = 7;
  28. static const uint8_t keyboard_origin_y = 31;
  29. static const uint8_t keyboard_row_count = 2;
  30. static const uint8_t enter_symbol = '\r';
  31. static const uint8_t backspace_symbol = '\b';
  32. static const uint8_t max_drawable_bytes = 8;
  33. static const IntInputKey keyboard_keys_row_1[] = {
  34. {'0', 0, 12},
  35. {'1', 11, 12},
  36. {'2', 22, 12},
  37. {'3', 33, 12},
  38. {'4', 44, 12},
  39. {backspace_symbol, 103, 4},
  40. };
  41. static const IntInputKey keyboard_keys_row_2[] = {
  42. {'5', 0, 26},
  43. {'6', 11, 26},
  44. {'7', 22, 26},
  45. {'8', 33, 26},
  46. {'9', 44, 26},
  47. {enter_symbol, 95, 17},
  48. };
  49. /** Get row size
  50. *
  51. * @param row_index Index of row
  52. *
  53. * @return uint8_t Row size
  54. */
  55. static uint8_t int_input_get_row_size(uint8_t row_index) {
  56. uint8_t row_size = 0;
  57. switch(row_index + 1) {
  58. case 1:
  59. row_size = COUNT_OF(keyboard_keys_row_1);
  60. break;
  61. case 2:
  62. row_size = COUNT_OF(keyboard_keys_row_2);
  63. break;
  64. default:
  65. furi_crash();
  66. }
  67. return row_size;
  68. }
  69. /** Get row pointer
  70. *
  71. * @param row_index Index of row
  72. *
  73. * @return const IntInputKey* Row pointer
  74. */
  75. static const IntInputKey* int_input_get_row(uint8_t row_index) {
  76. const IntInputKey* row = NULL;
  77. switch(row_index + 1) {
  78. case 1:
  79. row = keyboard_keys_row_1;
  80. break;
  81. case 2:
  82. row = keyboard_keys_row_2;
  83. break;
  84. default:
  85. furi_crash();
  86. }
  87. return row;
  88. }
  89. /** Get text from nibble
  90. *
  91. * @param byte byte value
  92. * @param high_nibble Get from high nibble, otherwise low nibble
  93. *
  94. * @return char nibble text
  95. */
  96. static char int_input_get_nibble_text(uint8_t byte, bool high_nibble) {
  97. if(high_nibble) {
  98. byte = byte >> 4;
  99. }
  100. byte = byte & 0x0F;
  101. switch(byte & 0x0F) {
  102. case 0x0:
  103. case 0x1:
  104. case 0x2:
  105. case 0x3:
  106. case 0x4:
  107. case 0x5:
  108. case 0x6:
  109. case 0x7:
  110. case 0x8:
  111. case 0x9:
  112. byte = byte + '0';
  113. break;
  114. case 0xA:
  115. case 0xB:
  116. case 0xC:
  117. case 0xD:
  118. case 0xE:
  119. case 0xF:
  120. byte = byte - 0xA + 'A';
  121. break;
  122. default:
  123. byte = '!';
  124. break;
  125. }
  126. return byte;
  127. }
  128. const char num_to_char[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
  129. /** Draw input box (common view)
  130. *
  131. * @param canvas The canvas
  132. * @param model The model
  133. */
  134. static void int_input_draw_input(Canvas* canvas, IntInputModel* model) {
  135. const uint8_t text_x = 8;
  136. const uint8_t text_y = 25;
  137. const uint8_t text_y2 = 40;
  138. const bool draw_index_line =
  139. (model->selected_row == -2) &&
  140. (model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes + 1) <= 100);
  141. elements_slightly_rounded_frame(canvas, 6, 14, 116, 15);
  142. canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5);
  143. canvas_draw_icon(canvas, 123, 19, &I_ButtonRightSmall_3x5);
  144. for(uint8_t i = model->first_visible_byte;
  145. i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes);
  146. i++) {
  147. uint8_t byte_position = i - model->first_visible_byte;
  148. if(i == model->selected_byte) {
  149. canvas_draw_frame(canvas, text_x + byte_position * 14, text_y - 9, 15, 11);
  150. if(model->selected_row == -2) {
  151. canvas_draw_icon(
  152. canvas, text_x + 6 + byte_position * 14, text_y - 14, &I_arrow_nano_up);
  153. canvas_draw_icon(
  154. canvas, text_x + 6 + byte_position * 14, text_y + 5, &I_arrow_nano_down);
  155. }
  156. if(model->selected_high_nibble) {
  157. canvas_draw_glyph(
  158. canvas,
  159. text_x + 8 + byte_position * 14,
  160. text_y,
  161. int_input_get_nibble_text(model->bytes[i], false));
  162. canvas_draw_box(canvas, text_x + 1 + byte_position * 14, text_y - 8, 7, 9);
  163. canvas_invert_color(canvas);
  164. canvas_draw_line(
  165. canvas,
  166. text_x + 14 + byte_position * 14,
  167. text_y - 6,
  168. text_x + 14 + byte_position * 14,
  169. text_y - 2);
  170. canvas_draw_glyph(
  171. canvas,
  172. text_x + 2 + byte_position * 14,
  173. text_y,
  174. int_input_get_nibble_text(model->bytes[i], true));
  175. canvas_invert_color(canvas);
  176. } else {
  177. canvas_draw_box(canvas, text_x + 7 + byte_position * 14, text_y - 8, 7, 9);
  178. canvas_draw_glyph(
  179. canvas,
  180. text_x + 2 + byte_position * 14,
  181. text_y,
  182. int_input_get_nibble_text(model->bytes[i], true));
  183. canvas_invert_color(canvas);
  184. canvas_draw_line(
  185. canvas,
  186. text_x + byte_position * 14,
  187. text_y - 6,
  188. text_x + byte_position * 14,
  189. text_y - 2);
  190. canvas_draw_glyph(
  191. canvas,
  192. text_x + 8 + byte_position * 14,
  193. text_y,
  194. int_input_get_nibble_text(model->bytes[i], false));
  195. canvas_invert_color(canvas);
  196. }
  197. } else {
  198. if(model->first_visible_byte > 0 && i == model->first_visible_byte) {
  199. canvas_draw_icon(
  200. canvas,
  201. text_x + 2 + byte_position * 14,
  202. text_y - 7,
  203. &I_More_data_placeholder_5x7);
  204. } else {
  205. canvas_draw_glyph(
  206. canvas,
  207. text_x + 2 + byte_position * 14,
  208. text_y,
  209. int_input_get_nibble_text(model->bytes[i], true));
  210. }
  211. if(model->bytes_count - model->first_visible_byte > max_drawable_bytes &&
  212. i == model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes) - 1) {
  213. canvas_draw_icon(
  214. canvas,
  215. text_x + 8 + byte_position * 14,
  216. text_y - 7,
  217. &I_More_data_placeholder_5x7);
  218. } else {
  219. canvas_draw_glyph(
  220. canvas,
  221. text_x + 8 + byte_position * 14,
  222. text_y,
  223. int_input_get_nibble_text(model->bytes[i], false));
  224. }
  225. }
  226. if(draw_index_line) {
  227. canvas_draw_icon(canvas, 1, text_y + 8, &I_Hashmark_7x7);
  228. canvas_draw_glyph(
  229. canvas, text_x + 2 + byte_position * 14, text_y2, num_to_char[(i + 1) / 10]);
  230. canvas_draw_glyph(
  231. canvas, text_x + 8 + byte_position * 14, text_y2, num_to_char[(i + 1) % 10]);
  232. }
  233. }
  234. if((model->selected_row == -2) &&
  235. (model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes + 1) > 100)) {
  236. char str[20];
  237. canvas_set_font(canvas, FontSecondary);
  238. snprintf(str, 20, "Selected index");
  239. canvas_draw_str(canvas, text_x, text_y2, str);
  240. canvas_set_font(canvas, FontPrimary);
  241. snprintf(str, 20, "%u", (model->selected_byte + 1));
  242. canvas_draw_str(canvas, text_x + 75, text_y2, str);
  243. }
  244. }
  245. /** Draw input box (selected view)
  246. *
  247. * @param canvas The canvas
  248. * @param model The model
  249. */
  250. static void int_input_draw_input_selected(Canvas* canvas, IntInputModel* model) {
  251. const uint8_t text_x = 7;
  252. const uint8_t text_y = 25;
  253. canvas_draw_box(canvas, 0, 12, 127, 19);
  254. canvas_invert_color(canvas);
  255. elements_slightly_rounded_frame(canvas, 6, 14, 115, 15);
  256. canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5);
  257. canvas_draw_icon(canvas, 122, 19, &I_ButtonRightSmall_3x5);
  258. for(uint8_t i = model->first_visible_byte;
  259. i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes);
  260. i++) {
  261. uint8_t byte_position = i - model->first_visible_byte;
  262. if(i == model->selected_byte) {
  263. canvas_draw_box(canvas, text_x + 1 + byte_position * 14, text_y - 9, 13, 11);
  264. canvas_invert_color(canvas);
  265. canvas_draw_glyph(
  266. canvas,
  267. text_x + 2 + byte_position * 14,
  268. text_y,
  269. int_input_get_nibble_text(model->bytes[i], true));
  270. canvas_draw_glyph(
  271. canvas,
  272. text_x + 8 + byte_position * 14,
  273. text_y,
  274. int_input_get_nibble_text(model->bytes[i], false));
  275. canvas_invert_color(canvas);
  276. } else {
  277. if(model->first_visible_byte > 0 && i == model->first_visible_byte) {
  278. canvas_draw_icon(
  279. canvas,
  280. text_x + 2 + byte_position * 14,
  281. text_y - 7,
  282. &I_More_data_placeholder_5x7);
  283. } else {
  284. canvas_draw_glyph(
  285. canvas,
  286. text_x + 2 + byte_position * 14,
  287. text_y,
  288. int_input_get_nibble_text(model->bytes[i], true));
  289. }
  290. if(model->bytes_count - model->first_visible_byte > max_drawable_bytes &&
  291. i == model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes) - 1) {
  292. canvas_draw_icon(
  293. canvas,
  294. text_x + 8 + byte_position * 14,
  295. text_y - 7,
  296. &I_More_data_placeholder_5x7);
  297. } else {
  298. canvas_draw_glyph(
  299. canvas,
  300. text_x + 8 + byte_position * 14,
  301. text_y,
  302. int_input_get_nibble_text(model->bytes[i], false));
  303. }
  304. }
  305. }
  306. canvas_invert_color(canvas);
  307. }
  308. /** Set nibble at position
  309. *
  310. * @param data where to set nibble
  311. * @param position byte position
  312. * @param value char value
  313. * @param high_nibble set high nibble
  314. */
  315. /*static void int_input_set_nibble(uint8_t* data, uint8_t position, char value, bool high_nibble) {
  316. switch(value) {
  317. case '0':
  318. case '1':
  319. case '2':
  320. case '3':
  321. case '4':
  322. case '5':
  323. case '6':
  324. case '7':
  325. case '8':
  326. case '9':
  327. value = value - '0';
  328. break;
  329. case 'A':
  330. case 'B':
  331. case 'C':
  332. case 'D':
  333. case 'E':
  334. case 'F':
  335. value = value - 'A' + 10;
  336. break;
  337. default:
  338. value = 0;
  339. break;
  340. }
  341. if(high_nibble) {
  342. data[position] &= 0x0F;
  343. data[position] |= value << 4;
  344. } else {
  345. data[position] &= 0xF0;
  346. data[position] |= value;
  347. }
  348. }*/
  349. /** What currently selected
  350. *
  351. * @param model The model
  352. *
  353. * @return true - keyboard selected, false - input selected
  354. */
  355. static bool int_input_keyboard_selected(IntInputModel* model) {
  356. return model->selected_row >= 0;
  357. }
  358. /** Do transition from keyboard
  359. *
  360. * @param model The model
  361. */
  362. static void int_input_transition_from_keyboard(IntInputModel* model) {
  363. model->selected_row += 1;
  364. model->selected_high_nibble = true;
  365. }
  366. /** Increase selected byte position
  367. *
  368. * @param model The model
  369. */
  370. static void int_input_inc_selected_byte(IntInputModel* model) {
  371. if(model->selected_byte < model->bytes_count - 1) {
  372. model->selected_byte += 1;
  373. if(model->bytes_count > max_drawable_bytes) {
  374. if(model->selected_byte - model->first_visible_byte > (max_drawable_bytes - 2)) {
  375. if(model->first_visible_byte < model->bytes_count - max_drawable_bytes) {
  376. model->first_visible_byte++;
  377. }
  378. }
  379. }
  380. }
  381. }
  382. static void int_input_inc_selected_byte_mini(IntInputModel* model) {
  383. if((model->selected_byte < model->bytes_count - 1) || model->selected_high_nibble) {
  384. if(!model->selected_high_nibble) {
  385. model->selected_high_nibble = !model->selected_high_nibble; //-V547
  386. int_input_inc_selected_byte(model);
  387. } else {
  388. model->selected_high_nibble = !model->selected_high_nibble; //-V547
  389. }
  390. }
  391. }
  392. /** Decrease selected byte position
  393. *
  394. * @param model The model
  395. */
  396. static void int_input_dec_selected_byte(IntInputModel* model) {
  397. if(model->selected_byte > 0) {
  398. model->selected_byte -= 1;
  399. furi_assert(model->selected_byte >= model->first_visible_byte);
  400. if(model->selected_byte - model->first_visible_byte < 1) {
  401. if(model->first_visible_byte > 0) {
  402. model->first_visible_byte--;
  403. }
  404. }
  405. }
  406. }
  407. static void int_input_dec_selected_byte_mini(IntInputModel* model) {
  408. if(model->selected_byte > 0 || !model->selected_high_nibble) {
  409. if(model->selected_high_nibble) {
  410. model->selected_high_nibble = !model->selected_high_nibble; //-V547
  411. int_input_dec_selected_byte(model);
  412. } else {
  413. model->selected_high_nibble = !model->selected_high_nibble; //-V547
  414. }
  415. }
  416. }
  417. /** Call input callback
  418. *
  419. * @param model The model
  420. */
  421. static void int_input_call_input_callback(IntInputModel* model) {
  422. if(model->input_callback != NULL) {
  423. model->input_callback(model->callback_context);
  424. }
  425. }
  426. /** Call changed callback
  427. *
  428. * @param model The model
  429. */
  430. static void int_input_call_changed_callback(IntInputModel* model) {
  431. if(model->changed_callback != NULL) {
  432. model->changed_callback(model->callback_context);
  433. }
  434. }
  435. /** Clear selected byte
  436. *
  437. * @param model The model
  438. */
  439. static void int_input_clear_selected_byte(IntInputModel* model) {
  440. model->bytes[model->selected_byte] = 0;
  441. model->selected_high_nibble = true;
  442. int_input_dec_selected_byte(model);
  443. int_input_call_changed_callback(model);
  444. }
  445. /** Handle up button
  446. *
  447. * @param model The model
  448. */
  449. static void int_input_handle_up(IntInputModel* model) {
  450. if(model->selected_row > -2) {
  451. model->selected_row -= 1;
  452. } else if(model->selected_row == -2) {
  453. if(!model->selected_high_nibble) {
  454. model->bytes[model->selected_byte] = (model->bytes[model->selected_byte] & 0xF0) |
  455. ((model->bytes[model->selected_byte] + 1) & 0x0F);
  456. } else {
  457. model->bytes[model->selected_byte] =
  458. ((model->bytes[model->selected_byte] + 0x10) & 0xF0) |
  459. (model->bytes[model->selected_byte] & 0x0F);
  460. }
  461. int_input_call_changed_callback(model);
  462. }
  463. }
  464. /** Handle down button
  465. *
  466. * @param model The model
  467. */
  468. static void int_input_handle_down(IntInputModel* model) {
  469. if(model->selected_row != -2) {
  470. if(int_input_keyboard_selected(model)) {
  471. if(model->selected_row < keyboard_row_count - 1) {
  472. model->selected_row += 1;
  473. }
  474. } else {
  475. int_input_transition_from_keyboard(model);
  476. }
  477. } else {
  478. if(!model->selected_high_nibble) {
  479. model->bytes[model->selected_byte] = (model->bytes[model->selected_byte] & 0xF0) |
  480. ((model->bytes[model->selected_byte] - 1) & 0x0F);
  481. } else {
  482. model->bytes[model->selected_byte] =
  483. ((model->bytes[model->selected_byte] - 0x10) & 0xF0) |
  484. (model->bytes[model->selected_byte] & 0x0F);
  485. }
  486. int_input_call_changed_callback(model);
  487. }
  488. }
  489. /** Handle left button
  490. *
  491. * @param model The model
  492. */
  493. static void int_input_handle_left(IntInputModel* model) {
  494. if(int_input_keyboard_selected(model)) {
  495. if(model->selected_column > 0) {
  496. model->selected_column -= 1;
  497. } else {
  498. model->selected_column = int_input_get_row_size(model->selected_row) - 1;
  499. }
  500. } else {
  501. if(model->selected_row != -2) {
  502. int_input_dec_selected_byte(model);
  503. } else {
  504. int_input_dec_selected_byte_mini(model);
  505. }
  506. }
  507. }
  508. /** Handle right button
  509. *
  510. * @param model The model
  511. */
  512. static void int_input_handle_right(IntInputModel* model) {
  513. if(int_input_keyboard_selected(model)) {
  514. if(model->selected_column < int_input_get_row_size(model->selected_row) - 1) {
  515. model->selected_column += 1;
  516. } else {
  517. model->selected_column = 0;
  518. }
  519. } else {
  520. if(model->selected_row != -2) {
  521. int_input_inc_selected_byte(model);
  522. } else {
  523. int_input_inc_selected_byte_mini(model);
  524. }
  525. }
  526. }
  527. /** Handle OK button
  528. *
  529. * @param model The model
  530. */
  531. static void int_input_handle_ok(IntInputModel* model) {
  532. if(int_input_keyboard_selected(model)) {
  533. uint8_t value = int_input_get_row(model->selected_row)[model->selected_column].value;
  534. if(value == enter_symbol) {
  535. int_input_call_input_callback(model);
  536. } else if(value == backspace_symbol) {
  537. int_input_clear_selected_byte(model);
  538. } else {
  539. /*int_input_set_nibble(
  540. model->bytes, model->selected_byte, value, model->selected_high_nibble);
  541. if(model->selected_high_nibble == true) {
  542. model->selected_high_nibble = false;
  543. } else {
  544. int_input_inc_selected_byte(model);
  545. model->selected_high_nibble = true;
  546. }
  547. int_input_call_changed_callback(model);*/
  548. }
  549. } else if(model->selected_row == -2) {
  550. int_input_call_input_callback(model);
  551. } else {
  552. int_input_transition_from_keyboard(model);
  553. }
  554. }
  555. /** Draw callback
  556. *
  557. * @param canvas The canvas
  558. * @param _model The model
  559. */
  560. static void int_input_view_draw_callback(Canvas* canvas, void* _model) {
  561. IntInputModel* model = _model;
  562. canvas_clear(canvas);
  563. canvas_set_color(canvas, ColorBlack);
  564. canvas_set_font(canvas, FontKeyboard);
  565. if(model->selected_row == -1) {
  566. int_input_draw_input_selected(canvas, model);
  567. } else {
  568. int_input_draw_input(canvas, model);
  569. }
  570. if(model->selected_row == -2) {
  571. canvas_set_font(canvas, FontSecondary);
  572. canvas_draw_icon(canvas, 3, 1, &I_Pin_back_arrow_10x8);
  573. canvas_draw_str_aligned(canvas, 16, 9, AlignLeft, AlignBottom, "back to keyboard");
  574. elements_button_center(canvas, "Save");
  575. } else {
  576. // Draw the header
  577. canvas_set_font(canvas, FontSecondary);
  578. if(model->selected_row == -1) {
  579. canvas_draw_str(canvas, 10, 9, "Move up for alternate input");
  580. canvas_draw_icon(canvas, 3, 4, &I_SmallArrowUp_3x5);
  581. } else {
  582. canvas_draw_str(canvas, 2, 9, model->header);
  583. }
  584. canvas_set_font(canvas, FontKeyboard);
  585. // Draw keyboard
  586. for(uint8_t row = 0; row < keyboard_row_count; row++) {
  587. const uint8_t column_count = int_input_get_row_size(row);
  588. const IntInputKey* keys = int_input_get_row(row);
  589. for(size_t column = 0; column < column_count; column++) {
  590. if(keys[column].value == enter_symbol) {
  591. canvas_set_color(canvas, ColorBlack);
  592. if(model->selected_row == row && model->selected_column == column) {
  593. canvas_draw_icon(
  594. canvas,
  595. keyboard_origin_x + keys[column].x,
  596. keyboard_origin_y + keys[column].y,
  597. &I_KeySaveSelected_24x11);
  598. } else {
  599. canvas_draw_icon(
  600. canvas,
  601. keyboard_origin_x + keys[column].x,
  602. keyboard_origin_y + keys[column].y,
  603. &I_KeySave_24x11);
  604. }
  605. } else if(keys[column].value == backspace_symbol) {
  606. canvas_set_color(canvas, ColorBlack);
  607. if(model->selected_row == row && model->selected_column == column) {
  608. canvas_draw_icon(
  609. canvas,
  610. keyboard_origin_x + keys[column].x,
  611. keyboard_origin_y + keys[column].y,
  612. &I_KeyBackspaceSelected_16x9);
  613. } else {
  614. canvas_draw_icon(
  615. canvas,
  616. keyboard_origin_x + keys[column].x,
  617. keyboard_origin_y + keys[column].y,
  618. &I_KeyBackspace_16x9);
  619. }
  620. } else {
  621. if(model->selected_row == row && model->selected_column == column) {
  622. canvas_set_color(canvas, ColorBlack);
  623. canvas_draw_box(
  624. canvas,
  625. keyboard_origin_x + keys[column].x - 3,
  626. keyboard_origin_y + keys[column].y - 10,
  627. 11,
  628. 13);
  629. canvas_set_color(canvas, ColorWhite);
  630. } else if(
  631. model->selected_row == -1 && row == 0 &&
  632. model->selected_column == column) {
  633. canvas_set_color(canvas, ColorBlack);
  634. canvas_draw_frame(
  635. canvas,
  636. keyboard_origin_x + keys[column].x - 3,
  637. keyboard_origin_y + keys[column].y - 10,
  638. 11,
  639. 13);
  640. } else {
  641. canvas_set_color(canvas, ColorBlack);
  642. }
  643. canvas_draw_glyph(
  644. canvas,
  645. keyboard_origin_x + keys[column].x,
  646. keyboard_origin_y + keys[column].y,
  647. keys[column].value);
  648. }
  649. }
  650. }
  651. }
  652. }
  653. /** Input callback
  654. *
  655. * @param event The event
  656. * @param context The context
  657. *
  658. * @return true
  659. * @return false
  660. */
  661. static bool int_input_view_input_callback(InputEvent* event, void* context) {
  662. IntInput* int_input = context;
  663. furi_assert(int_input);
  664. bool consumed = false;
  665. if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
  666. switch(event->key) {
  667. case InputKeyLeft:
  668. with_view_model(
  669. int_input->view, IntInputModel * model, { int_input_handle_left(model); }, true);
  670. consumed = true;
  671. break;
  672. case InputKeyRight:
  673. with_view_model(
  674. int_input->view,
  675. IntInputModel * model,
  676. { int_input_handle_right(model); },
  677. true);
  678. consumed = true;
  679. break;
  680. case InputKeyUp:
  681. with_view_model(
  682. int_input->view, IntInputModel * model, { int_input_handle_up(model); }, true);
  683. consumed = true;
  684. break;
  685. case InputKeyDown:
  686. with_view_model(
  687. int_input->view, IntInputModel * model, { int_input_handle_down(model); }, true);
  688. consumed = true;
  689. break;
  690. case InputKeyOk:
  691. with_view_model(
  692. int_input->view, IntInputModel * model, { int_input_handle_ok(model); }, true);
  693. consumed = true;
  694. break;
  695. default:
  696. break;
  697. }
  698. }
  699. if(event->type == InputTypeShort && event->key == InputKeyBack) {
  700. // Back to keyboard
  701. with_view_model(
  702. int_input->view,
  703. IntInputModel * model,
  704. {
  705. if(model->selected_row == -2) {
  706. model->selected_row += 1;
  707. consumed = true;
  708. };
  709. },
  710. true);
  711. }
  712. if((event->type == InputTypeLong || event->type == InputTypeRepeat) &&
  713. event->key == InputKeyBack) {
  714. with_view_model(
  715. int_input->view,
  716. IntInputModel * model,
  717. { int_input_clear_selected_byte(model); },
  718. true);
  719. consumed = true;
  720. }
  721. return consumed;
  722. }
  723. /** Reset all input-related data in model
  724. *
  725. * @param model The model
  726. */
  727. static void int_input_reset_model_input_data(IntInputModel* model) {
  728. model->bytes = NULL;
  729. model->bytes_count = 0;
  730. model->selected_high_nibble = true;
  731. model->selected_byte = 0;
  732. model->selected_row = 0;
  733. model->selected_column = 0;
  734. model->first_visible_byte = 0;
  735. }
  736. IntInput* int_input_alloc() {
  737. IntInput* int_input = malloc(sizeof(IntInput));
  738. int_input->view = view_alloc();
  739. view_set_context(int_input->view, int_input);
  740. view_allocate_model(int_input->view, ViewModelTypeLocking, sizeof(IntInputModel));
  741. view_set_draw_callback(int_input->view, int_input_view_draw_callback);
  742. view_set_input_callback(int_input->view, int_input_view_input_callback);
  743. with_view_model(
  744. int_input->view,
  745. IntInputModel * model,
  746. {
  747. model->header = "";
  748. model->input_callback = NULL;
  749. model->changed_callback = NULL;
  750. model->callback_context = NULL;
  751. int_input_reset_model_input_data(model);
  752. },
  753. true);
  754. return int_input;
  755. }
  756. void int_input_free(IntInput* int_input) {
  757. furi_assert(int_input);
  758. view_free(int_input->view);
  759. free(int_input);
  760. }
  761. View* int_input_get_view(IntInput* int_input) {
  762. furi_assert(int_input);
  763. return int_input->view;
  764. }
  765. void int_input_set_result_callback(
  766. IntInput* int_input,
  767. IntInputCallback input_callback,
  768. IntChangedCallback changed_callback,
  769. void* callback_context,
  770. uint8_t* bytes,
  771. uint8_t bytes_count) {
  772. with_view_model(
  773. int_input->view,
  774. IntInputModel * model,
  775. {
  776. int_input_reset_model_input_data(model);
  777. model->input_callback = input_callback;
  778. model->changed_callback = changed_callback;
  779. model->callback_context = callback_context;
  780. model->bytes = bytes;
  781. model->bytes_count = bytes_count;
  782. },
  783. true);
  784. }
  785. void int_input_set_header_text(IntInput* int_input, const char* text) {
  786. with_view_model(
  787. int_input->view, IntInputModel * model, { model->header = text; }, true);
  788. }