uart_text_input.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. // from https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/uart_terminal/uart_text_input.c
  2. // all credits to xMasterX for the code
  3. #include "uart_text_input.h"
  4. #include <gui/elements.h>
  5. #include "web_crawler_icons.h"
  6. #include <furi.h>
  7. struct UART_TextInput
  8. {
  9. View *view;
  10. FuriTimer *timer;
  11. };
  12. typedef struct
  13. {
  14. const char text;
  15. const uint8_t x;
  16. const uint8_t y;
  17. } UART_TextInputKey;
  18. typedef struct
  19. {
  20. const char *header;
  21. char *text_buffer;
  22. size_t text_buffer_size;
  23. bool clear_default_text;
  24. UART_TextInputCallback callback;
  25. void *callback_context;
  26. uint8_t selected_row;
  27. uint8_t selected_column;
  28. UART_TextInputValidatorCallback validator_callback;
  29. void *validator_callback_context;
  30. FuriString *validator_text;
  31. bool valadator_message_visible;
  32. } UART_TextInputModel;
  33. static const uint8_t keyboard_origin_x = 1;
  34. static const uint8_t keyboard_origin_y = 29;
  35. static const uint8_t keyboard_row_count = 4;
  36. #define mode_AT "Send AT command to UART"
  37. #define ENTER_KEY '\r'
  38. #define BACKSPACE_KEY '\b'
  39. static const UART_TextInputKey keyboard_keys_row_1[] = {
  40. {'{', 1, 0},
  41. {'(', 9, 0},
  42. {'[', 17, 0},
  43. {'|', 25, 0},
  44. {'@', 33, 0},
  45. {'&', 41, 0},
  46. {'#', 49, 0},
  47. {';', 57, 0},
  48. {'^', 65, 0},
  49. {'*', 73, 0},
  50. {'`', 81, 0},
  51. {'"', 89, 0},
  52. {'~', 97, 0},
  53. {'\'', 105, 0},
  54. {'.', 113, 0},
  55. {'/', 120, 0},
  56. };
  57. static const UART_TextInputKey keyboard_keys_row_2[] = {
  58. {'q', 1, 10},
  59. {'w', 9, 10},
  60. {'e', 17, 10},
  61. {'r', 25, 10},
  62. {'t', 33, 10},
  63. {'y', 41, 10},
  64. {'u', 49, 10},
  65. {'i', 57, 10},
  66. {'o', 65, 10},
  67. {'p', 73, 10},
  68. {'0', 81, 10},
  69. {'1', 89, 10},
  70. {'2', 97, 10},
  71. {'3', 105, 10},
  72. {'=', 113, 10},
  73. {'-', 120, 10},
  74. };
  75. static const UART_TextInputKey keyboard_keys_row_3[] = {
  76. {'a', 1, 21},
  77. {'s', 9, 21},
  78. {'d', 18, 21},
  79. {'f', 25, 21},
  80. {'g', 33, 21},
  81. {'h', 41, 21},
  82. {'j', 49, 21},
  83. {'k', 57, 21},
  84. {'l', 65, 21},
  85. {BACKSPACE_KEY, 72, 13},
  86. {'4', 89, 21},
  87. {'5', 97, 21},
  88. {'6', 105, 21},
  89. {'$', 113, 21},
  90. {'%', 120, 21},
  91. };
  92. static const UART_TextInputKey keyboard_keys_row_4[] = {
  93. {'z', 1, 33},
  94. {'x', 9, 33},
  95. {'c', 18, 33},
  96. {'v', 25, 33},
  97. {'b', 33, 33},
  98. {'n', 41, 33},
  99. {'m', 49, 33},
  100. {'_', 57, 33},
  101. {ENTER_KEY, 64, 24},
  102. {'7', 89, 33},
  103. {'8', 97, 33},
  104. {'9', 105, 33},
  105. {'!', 113, 33},
  106. {'+', 120, 33},
  107. };
  108. static uint8_t get_row_size(uint8_t row_index)
  109. {
  110. uint8_t row_size = 0;
  111. switch (row_index + 1)
  112. {
  113. case 1:
  114. row_size = sizeof(keyboard_keys_row_1) / sizeof(UART_TextInputKey);
  115. break;
  116. case 2:
  117. row_size = sizeof(keyboard_keys_row_2) / sizeof(UART_TextInputKey);
  118. break;
  119. case 3:
  120. row_size = sizeof(keyboard_keys_row_3) / sizeof(UART_TextInputKey);
  121. break;
  122. case 4:
  123. row_size = sizeof(keyboard_keys_row_4) / sizeof(UART_TextInputKey);
  124. break;
  125. }
  126. return row_size;
  127. }
  128. static const UART_TextInputKey *get_row(uint8_t row_index)
  129. {
  130. const UART_TextInputKey *row = NULL;
  131. switch (row_index + 1)
  132. {
  133. case 1:
  134. row = keyboard_keys_row_1;
  135. break;
  136. case 2:
  137. row = keyboard_keys_row_2;
  138. break;
  139. case 3:
  140. row = keyboard_keys_row_3;
  141. break;
  142. case 4:
  143. row = keyboard_keys_row_4;
  144. break;
  145. }
  146. return row;
  147. }
  148. static char get_selected_char(UART_TextInputModel *model)
  149. {
  150. return get_row(model->selected_row)[model->selected_column].text;
  151. }
  152. static bool char_is_lowercase(char letter)
  153. {
  154. return (letter >= 0x61 && letter <= 0x7A);
  155. }
  156. static bool char_is_uppercase(char letter)
  157. {
  158. return (letter >= 0x41 && letter <= 0x5A);
  159. }
  160. static char char_to_lowercase(const char letter)
  161. {
  162. switch (letter)
  163. {
  164. case ' ':
  165. return 0x5f;
  166. break;
  167. case ')':
  168. return 0x28;
  169. break;
  170. case '}':
  171. return 0x7b;
  172. break;
  173. case ']':
  174. return 0x5b;
  175. break;
  176. case '\\':
  177. return 0x2f;
  178. break;
  179. case ':':
  180. return 0x3b;
  181. break;
  182. case ',':
  183. return 0x2e;
  184. break;
  185. case '?':
  186. return 0x21;
  187. break;
  188. case '>':
  189. return 0x3c;
  190. break;
  191. }
  192. if (char_is_uppercase(letter))
  193. {
  194. return (letter + 0x20);
  195. }
  196. else
  197. {
  198. return letter;
  199. }
  200. }
  201. static char char_to_uppercase(const char letter)
  202. {
  203. switch (letter)
  204. {
  205. case '_':
  206. return 0x20;
  207. break;
  208. case '(':
  209. return 0x29;
  210. break;
  211. case '{':
  212. return 0x7d;
  213. break;
  214. case '[':
  215. return 0x5d;
  216. break;
  217. case '/':
  218. return 0x5c;
  219. break;
  220. case ';':
  221. return 0x3a;
  222. break;
  223. case '.':
  224. return 0x2c;
  225. break;
  226. case '!':
  227. return 0x3f;
  228. break;
  229. case '<':
  230. return 0x3e;
  231. break;
  232. }
  233. if (char_is_lowercase(letter))
  234. {
  235. return (letter - 0x20);
  236. }
  237. else
  238. {
  239. return letter;
  240. }
  241. }
  242. static void uart_text_input_backspace_cb(UART_TextInputModel *model)
  243. {
  244. uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer);
  245. if (text_length > 0)
  246. {
  247. model->text_buffer[text_length - 1] = 0;
  248. }
  249. }
  250. static void uart_text_input_view_draw_callback(Canvas *canvas, void *_model)
  251. {
  252. UART_TextInputModel *model = _model;
  253. // uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0;
  254. uint8_t needed_string_width = canvas_width(canvas) - 8;
  255. uint8_t start_pos = 4;
  256. const char *text = model->text_buffer;
  257. canvas_clear(canvas);
  258. canvas_set_color(canvas, ColorBlack);
  259. canvas_draw_str(canvas, 2, 7, model->header);
  260. elements_slightly_rounded_frame(canvas, 1, 8, 126, 12);
  261. if (canvas_string_width(canvas, text) > needed_string_width)
  262. {
  263. canvas_draw_str(canvas, start_pos, 17, "...");
  264. start_pos += 6;
  265. needed_string_width -= 8;
  266. }
  267. while (text != 0 && canvas_string_width(canvas, text) > needed_string_width)
  268. {
  269. text++;
  270. }
  271. if (model->clear_default_text)
  272. {
  273. elements_slightly_rounded_box(
  274. canvas, start_pos - 1, 14, canvas_string_width(canvas, text) + 2, 10);
  275. canvas_set_color(canvas, ColorWhite);
  276. }
  277. else
  278. {
  279. canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 18, "|");
  280. canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 18, "|");
  281. }
  282. canvas_draw_str(canvas, start_pos, 17, text);
  283. canvas_set_font(canvas, FontKeyboard);
  284. for (uint8_t row = 0; row <= keyboard_row_count; row++)
  285. {
  286. const uint8_t column_count = get_row_size(row);
  287. const UART_TextInputKey *keys = get_row(row);
  288. for (size_t column = 0; column < column_count; column++)
  289. {
  290. if (keys[column].text == ENTER_KEY)
  291. {
  292. canvas_set_color(canvas, ColorBlack);
  293. if (model->selected_row == row && model->selected_column == column)
  294. {
  295. canvas_draw_icon(
  296. canvas,
  297. keyboard_origin_x + keys[column].x,
  298. keyboard_origin_y + keys[column].y,
  299. &I_KeySaveSelected_24x11);
  300. }
  301. else
  302. {
  303. canvas_draw_icon(
  304. canvas,
  305. keyboard_origin_x + keys[column].x,
  306. keyboard_origin_y + keys[column].y,
  307. &I_KeySave_24x11);
  308. }
  309. }
  310. else if (keys[column].text == BACKSPACE_KEY)
  311. {
  312. canvas_set_color(canvas, ColorBlack);
  313. if (model->selected_row == row && model->selected_column == column)
  314. {
  315. canvas_draw_icon(
  316. canvas,
  317. keyboard_origin_x + keys[column].x,
  318. keyboard_origin_y + keys[column].y,
  319. &I_KeyBackspaceSelected_16x9);
  320. }
  321. else
  322. {
  323. canvas_draw_icon(
  324. canvas,
  325. keyboard_origin_x + keys[column].x,
  326. keyboard_origin_y + keys[column].y,
  327. &I_KeyBackspace_16x9);
  328. }
  329. }
  330. else
  331. {
  332. if (model->selected_row == row && model->selected_column == column)
  333. {
  334. canvas_set_color(canvas, ColorBlack);
  335. canvas_draw_box(
  336. canvas,
  337. keyboard_origin_x + keys[column].x - 1,
  338. keyboard_origin_y + keys[column].y - 8,
  339. 7,
  340. 10);
  341. canvas_set_color(canvas, ColorWhite);
  342. }
  343. else
  344. {
  345. canvas_set_color(canvas, ColorBlack);
  346. }
  347. if (0 == strcmp(model->header, mode_AT))
  348. {
  349. canvas_draw_glyph(
  350. canvas,
  351. keyboard_origin_x + keys[column].x,
  352. keyboard_origin_y + keys[column].y,
  353. char_to_uppercase(keys[column].text));
  354. }
  355. else
  356. {
  357. canvas_draw_glyph(
  358. canvas,
  359. keyboard_origin_x + keys[column].x,
  360. keyboard_origin_y + keys[column].y,
  361. keys[column].text);
  362. }
  363. }
  364. }
  365. }
  366. if (model->valadator_message_visible)
  367. {
  368. canvas_set_font(canvas, FontSecondary);
  369. canvas_set_color(canvas, ColorWhite);
  370. canvas_draw_box(canvas, 8, 10, 110, 48);
  371. canvas_set_color(canvas, ColorBlack);
  372. canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42);
  373. canvas_draw_rframe(canvas, 8, 8, 112, 50, 3);
  374. canvas_draw_rframe(canvas, 9, 9, 110, 48, 2);
  375. elements_multiline_text(canvas, 62, 20, furi_string_get_cstr(model->validator_text));
  376. canvas_set_font(canvas, FontKeyboard);
  377. }
  378. }
  379. static void
  380. uart_text_input_handle_up(UART_TextInput *uart_text_input, UART_TextInputModel *model)
  381. {
  382. UNUSED(uart_text_input);
  383. if (model->selected_row > 0)
  384. {
  385. model->selected_row--;
  386. if (model->selected_column > get_row_size(model->selected_row) - 6)
  387. {
  388. model->selected_column = model->selected_column + 1;
  389. }
  390. }
  391. }
  392. static void
  393. uart_text_input_handle_down(UART_TextInput *uart_text_input, UART_TextInputModel *model)
  394. {
  395. UNUSED(uart_text_input);
  396. if (model->selected_row < keyboard_row_count - 1)
  397. {
  398. model->selected_row++;
  399. if (model->selected_column > get_row_size(model->selected_row) - 4)
  400. {
  401. model->selected_column = model->selected_column - 1;
  402. }
  403. }
  404. }
  405. static void
  406. uart_text_input_handle_left(UART_TextInput *uart_text_input, UART_TextInputModel *model)
  407. {
  408. UNUSED(uart_text_input);
  409. if (model->selected_column > 0)
  410. {
  411. model->selected_column--;
  412. }
  413. else
  414. {
  415. model->selected_column = get_row_size(model->selected_row) - 1;
  416. }
  417. }
  418. static void
  419. uart_text_input_handle_right(UART_TextInput *uart_text_input, UART_TextInputModel *model)
  420. {
  421. UNUSED(uart_text_input);
  422. if (model->selected_column < get_row_size(model->selected_row) - 1)
  423. {
  424. model->selected_column++;
  425. }
  426. else
  427. {
  428. model->selected_column = 0;
  429. }
  430. }
  431. static void uart_text_input_handle_ok(
  432. UART_TextInput *uart_text_input,
  433. UART_TextInputModel *model,
  434. bool shift)
  435. {
  436. char selected = get_selected_char(model);
  437. uint8_t text_length = strlen(model->text_buffer);
  438. if (0 == strcmp(model->header, mode_AT))
  439. {
  440. selected = char_to_uppercase(selected);
  441. }
  442. if (shift)
  443. {
  444. if (0 == strcmp(model->header, mode_AT))
  445. {
  446. selected = char_to_lowercase(selected);
  447. }
  448. else
  449. {
  450. selected = char_to_uppercase(selected);
  451. }
  452. }
  453. if (selected == ENTER_KEY)
  454. {
  455. if (model->validator_callback &&
  456. (!model->validator_callback(
  457. model->text_buffer, model->validator_text, model->validator_callback_context)))
  458. {
  459. model->valadator_message_visible = true;
  460. furi_timer_start(uart_text_input->timer, furi_kernel_get_tick_frequency() * 4);
  461. }
  462. else if (model->callback != 0 && text_length > 0)
  463. {
  464. model->callback(model->callback_context);
  465. }
  466. }
  467. else if (selected == BACKSPACE_KEY)
  468. {
  469. uart_text_input_backspace_cb(model);
  470. }
  471. else
  472. {
  473. if (model->clear_default_text)
  474. {
  475. text_length = 0;
  476. }
  477. if (text_length < (model->text_buffer_size - 1))
  478. {
  479. model->text_buffer[text_length] = selected;
  480. model->text_buffer[text_length + 1] = 0;
  481. }
  482. }
  483. model->clear_default_text = false;
  484. }
  485. static bool uart_text_input_view_input_callback(InputEvent *event, void *context)
  486. {
  487. UART_TextInput *uart_text_input = context;
  488. furi_assert(uart_text_input);
  489. bool consumed = false;
  490. // Acquire model
  491. UART_TextInputModel *model = view_get_model(uart_text_input->view);
  492. if ((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) &&
  493. model->valadator_message_visible)
  494. {
  495. model->valadator_message_visible = false;
  496. consumed = true;
  497. }
  498. else if (event->type == InputTypeShort)
  499. {
  500. consumed = true;
  501. switch (event->key)
  502. {
  503. case InputKeyUp:
  504. uart_text_input_handle_up(uart_text_input, model);
  505. break;
  506. case InputKeyDown:
  507. uart_text_input_handle_down(uart_text_input, model);
  508. break;
  509. case InputKeyLeft:
  510. uart_text_input_handle_left(uart_text_input, model);
  511. break;
  512. case InputKeyRight:
  513. uart_text_input_handle_right(uart_text_input, model);
  514. break;
  515. case InputKeyOk:
  516. uart_text_input_handle_ok(uart_text_input, model, false);
  517. break;
  518. default:
  519. consumed = false;
  520. break;
  521. }
  522. }
  523. else if (event->type == InputTypeLong)
  524. {
  525. consumed = true;
  526. switch (event->key)
  527. {
  528. case InputKeyUp:
  529. uart_text_input_handle_up(uart_text_input, model);
  530. break;
  531. case InputKeyDown:
  532. uart_text_input_handle_down(uart_text_input, model);
  533. break;
  534. case InputKeyLeft:
  535. uart_text_input_handle_left(uart_text_input, model);
  536. break;
  537. case InputKeyRight:
  538. uart_text_input_handle_right(uart_text_input, model);
  539. break;
  540. case InputKeyOk:
  541. uart_text_input_handle_ok(uart_text_input, model, true);
  542. break;
  543. case InputKeyBack:
  544. uart_text_input_backspace_cb(model);
  545. break;
  546. default:
  547. consumed = false;
  548. break;
  549. }
  550. }
  551. else if (event->type == InputTypeRepeat)
  552. {
  553. consumed = true;
  554. switch (event->key)
  555. {
  556. case InputKeyUp:
  557. uart_text_input_handle_up(uart_text_input, model);
  558. break;
  559. case InputKeyDown:
  560. uart_text_input_handle_down(uart_text_input, model);
  561. break;
  562. case InputKeyLeft:
  563. uart_text_input_handle_left(uart_text_input, model);
  564. break;
  565. case InputKeyRight:
  566. uart_text_input_handle_right(uart_text_input, model);
  567. break;
  568. case InputKeyBack:
  569. uart_text_input_backspace_cb(model);
  570. break;
  571. default:
  572. consumed = false;
  573. break;
  574. }
  575. }
  576. // Commit model
  577. view_commit_model(uart_text_input->view, consumed);
  578. return consumed;
  579. }
  580. void uart_text_input_timer_callback(void *context)
  581. {
  582. furi_assert(context);
  583. UART_TextInput *uart_text_input = context;
  584. with_view_model(
  585. uart_text_input->view,
  586. UART_TextInputModel * model,
  587. { model->valadator_message_visible = false; },
  588. true);
  589. }
  590. UART_TextInput *uart_text_input_alloc()
  591. {
  592. UART_TextInput *uart_text_input = malloc(sizeof(UART_TextInput));
  593. uart_text_input->view = view_alloc();
  594. view_set_context(uart_text_input->view, uart_text_input);
  595. view_allocate_model(uart_text_input->view, ViewModelTypeLocking, sizeof(UART_TextInputModel));
  596. view_set_draw_callback(uart_text_input->view, uart_text_input_view_draw_callback);
  597. view_set_input_callback(uart_text_input->view, uart_text_input_view_input_callback);
  598. uart_text_input->timer =
  599. furi_timer_alloc(uart_text_input_timer_callback, FuriTimerTypeOnce, uart_text_input);
  600. with_view_model(
  601. uart_text_input->view,
  602. UART_TextInputModel * model,
  603. { model->validator_text = furi_string_alloc(); },
  604. false);
  605. uart_text_input_reset(uart_text_input);
  606. return uart_text_input;
  607. }
  608. void uart_text_input_free(UART_TextInput *uart_text_input)
  609. {
  610. furi_assert(uart_text_input);
  611. with_view_model(
  612. uart_text_input->view,
  613. UART_TextInputModel * model,
  614. { furi_string_free(model->validator_text); },
  615. false);
  616. // Send stop command
  617. furi_timer_stop(uart_text_input->timer);
  618. // Release allocated memory
  619. furi_timer_free(uart_text_input->timer);
  620. view_free(uart_text_input->view);
  621. free(uart_text_input);
  622. }
  623. void uart_text_input_reset(UART_TextInput *uart_text_input)
  624. {
  625. furi_assert(uart_text_input);
  626. with_view_model(
  627. uart_text_input->view,
  628. UART_TextInputModel * model,
  629. {
  630. model->text_buffer_size = 0;
  631. model->header = "";
  632. model->selected_row = 0;
  633. model->selected_column = 0;
  634. model->clear_default_text = false;
  635. model->text_buffer = NULL;
  636. model->text_buffer_size = 0;
  637. model->callback = NULL;
  638. model->callback_context = NULL;
  639. model->validator_callback = NULL;
  640. model->validator_callback_context = NULL;
  641. furi_string_reset(model->validator_text);
  642. model->valadator_message_visible = false;
  643. },
  644. true);
  645. }
  646. View *uart_text_input_get_view(UART_TextInput *uart_text_input)
  647. {
  648. furi_assert(uart_text_input);
  649. return uart_text_input->view;
  650. }
  651. void uart_text_input_set_result_callback(
  652. UART_TextInput *uart_text_input,
  653. UART_TextInputCallback callback,
  654. void *callback_context,
  655. char *text_buffer,
  656. size_t text_buffer_size,
  657. bool clear_default_text)
  658. {
  659. with_view_model(
  660. uart_text_input->view,
  661. UART_TextInputModel * model,
  662. {
  663. model->callback = callback;
  664. model->callback_context = callback_context;
  665. model->text_buffer = text_buffer;
  666. model->text_buffer_size = text_buffer_size;
  667. model->clear_default_text = clear_default_text;
  668. if (text_buffer && text_buffer[0] != '\0')
  669. {
  670. // Set focus on Save
  671. model->selected_row = 2;
  672. model->selected_column = 8;
  673. }
  674. },
  675. true);
  676. }
  677. void uart_text_input_set_validator(
  678. UART_TextInput *uart_text_input,
  679. UART_TextInputValidatorCallback callback,
  680. void *callback_context)
  681. {
  682. with_view_model(
  683. uart_text_input->view,
  684. UART_TextInputModel * model,
  685. {
  686. model->validator_callback = callback;
  687. model->validator_callback_context = callback_context;
  688. },
  689. true);
  690. }
  691. UART_TextInputValidatorCallback
  692. uart_text_input_get_validator_callback(UART_TextInput *uart_text_input)
  693. {
  694. UART_TextInputValidatorCallback validator_callback = NULL;
  695. with_view_model(
  696. uart_text_input->view,
  697. UART_TextInputModel * model,
  698. { validator_callback = model->validator_callback; },
  699. false);
  700. return validator_callback;
  701. }
  702. void *uart_text_input_get_validator_callback_context(UART_TextInput *uart_text_input)
  703. {
  704. void *validator_callback_context = NULL;
  705. with_view_model(
  706. uart_text_input->view,
  707. UART_TextInputModel * model,
  708. { validator_callback_context = model->validator_callback_context; },
  709. false);
  710. return validator_callback_context;
  711. }
  712. void uart_text_input_set_header_text(UART_TextInput *uart_text_input, const char *text)
  713. {
  714. with_view_model(
  715. uart_text_input->view, UART_TextInputModel * model, { model->header = text; }, true);
  716. }