int_input.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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 char text;
  11. const uint8_t x;
  12. const uint8_t y;
  13. } IntInputKey;
  14. typedef struct {
  15. const char* header;
  16. char* text_buffer;
  17. size_t text_buffer_size;
  18. bool clear_default_text;
  19. IntInputCallback input_callback;
  20. //IntChangedCallback changed_callback;
  21. void* callback_context;
  22. int8_t selected_row;
  23. uint8_t selected_column;
  24. } IntInputModel;
  25. static const uint8_t keyboard_origin_x = 7;
  26. static const uint8_t keyboard_origin_y = 31;
  27. static const uint8_t keyboard_row_count = 2;
  28. static const uint8_t enter_symbol = '\r';
  29. static const uint8_t backspace_symbol = '\b';
  30. //static const uint8_t max_drawable_digits = 4;
  31. static const IntInputKey keyboard_keys_row_1[] = {
  32. {'0', 0, 12},
  33. {'1', 11, 12},
  34. {'2', 22, 12},
  35. {'3', 33, 12},
  36. {'4', 44, 12},
  37. {backspace_symbol, 103, 4},
  38. };
  39. static const IntInputKey keyboard_keys_row_2[] = {
  40. {'5', 0, 26},
  41. {'6', 11, 26},
  42. {'7', 22, 26},
  43. {'8', 33, 26},
  44. {'9', 44, 26},
  45. {enter_symbol, 95, 17},
  46. };
  47. /** Get row size
  48. *
  49. * @param row_index Index of row
  50. *
  51. * @return uint8_t Row size
  52. */
  53. static uint8_t int_input_get_row_size(uint8_t row_index) {
  54. uint8_t row_size = 0;
  55. switch(row_index + 1) {
  56. case 1:
  57. row_size = COUNT_OF(keyboard_keys_row_1);
  58. break;
  59. case 2:
  60. row_size = COUNT_OF(keyboard_keys_row_2);
  61. break;
  62. default:
  63. furi_crash();
  64. }
  65. return row_size;
  66. }
  67. /** Get row pointer
  68. *
  69. * @param row_index Index of row
  70. *
  71. * @return const IntInputKey* Row pointer
  72. */
  73. static const IntInputKey* int_input_get_row(uint8_t row_index) {
  74. const IntInputKey* row = NULL;
  75. switch(row_index + 1) {
  76. case 1:
  77. row = keyboard_keys_row_1;
  78. break;
  79. case 2:
  80. row = keyboard_keys_row_2;
  81. break;
  82. default:
  83. furi_crash();
  84. }
  85. return row;
  86. }
  87. /** Draw input box (common view)
  88. *
  89. * @param canvas The canvas
  90. * @param model The model
  91. */
  92. static void int_input_draw_input(Canvas* canvas, IntInputModel* model) {
  93. //const uint8_t text_x = 8;
  94. //const uint8_t text_y = 25;
  95. //const uint8_t text_y2 = 40;
  96. UNUSED(model);
  97. elements_slightly_rounded_frame(canvas, 6, 14, 116, 15);
  98. //canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5);
  99. //canvas_draw_icon(canvas, 123, 19, &I_ButtonRightSmall_3x5);
  100. /*for(uint8_t i = model->first_visible_byte;
  101. i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes);
  102. i++) {
  103. uint8_t byte_position = i - model->first_visible_byte;
  104. if(i == model->selected_byte) {
  105. canvas_draw_frame(canvas, text_x + byte_position * 14, text_y - 9, 15, 11);
  106. if(model->selected_row == -2) {
  107. canvas_draw_icon(
  108. canvas, text_x + 6 + byte_position * 14, text_y - 14, &I_arrow_nano_up);
  109. canvas_draw_icon(
  110. canvas, text_x + 6 + byte_position * 14, text_y + 5, &I_arrow_nano_down);
  111. }
  112. if(model->selected_high_nibble) {
  113. canvas_draw_glyph(
  114. canvas,
  115. text_x + 8 + byte_position * 14,
  116. text_y,
  117. int_input_get_nibble_text(model->bytes[i], false));
  118. canvas_draw_box(canvas, text_x + 1 + byte_position * 14, text_y - 8, 7, 9);
  119. canvas_invert_color(canvas);
  120. canvas_draw_line(
  121. canvas,
  122. text_x + 14 + byte_position * 14,
  123. text_y - 6,
  124. text_x + 14 + byte_position * 14,
  125. text_y - 2);
  126. canvas_draw_glyph(
  127. canvas,
  128. text_x + 2 + byte_position * 14,
  129. text_y,
  130. int_input_get_nibble_text(model->bytes[i], true));
  131. canvas_invert_color(canvas);
  132. } else {
  133. canvas_draw_box(canvas, text_x + 7 + byte_position * 14, text_y - 8, 7, 9);
  134. canvas_draw_glyph(
  135. canvas,
  136. text_x + 2 + byte_position * 14,
  137. text_y,
  138. int_input_get_nibble_text(model->bytes[i], true));
  139. canvas_invert_color(canvas);
  140. canvas_draw_line(
  141. canvas,
  142. text_x + byte_position * 14,
  143. text_y - 6,
  144. text_x + byte_position * 14,
  145. text_y - 2);
  146. canvas_draw_glyph(
  147. canvas,
  148. text_x + 8 + byte_position * 14,
  149. text_y,
  150. int_input_get_nibble_text(model->bytes[i], false));
  151. canvas_invert_color(canvas);
  152. }
  153. } else {
  154. if(model->first_visible_byte > 0 && i == model->first_visible_byte) {
  155. canvas_draw_icon(
  156. canvas,
  157. text_x + 2 + byte_position * 14,
  158. text_y - 7,
  159. &I_More_data_placeholder_5x7);
  160. } else {
  161. canvas_draw_glyph(
  162. canvas,
  163. text_x + 2 + byte_position * 14,
  164. text_y,
  165. int_input_get_nibble_text(model->bytes[i], true));
  166. }
  167. if(model->bytes_count - model->first_visible_byte > max_drawable_bytes &&
  168. i == model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes) - 1) {
  169. canvas_draw_icon(
  170. canvas,
  171. text_x + 8 + byte_position * 14,
  172. text_y - 7,
  173. &I_More_data_placeholder_5x7);
  174. } else {
  175. canvas_draw_glyph(
  176. canvas,
  177. text_x + 8 + byte_position * 14,
  178. text_y,
  179. int_input_get_nibble_text(model->bytes[i], false));
  180. }
  181. }
  182. }*/
  183. }
  184. /** Handle up button
  185. *
  186. * @param model The model
  187. */
  188. static void int_input_handle_up(IntInputModel* model) {
  189. if(model->selected_row > 0) {
  190. model->selected_row--;
  191. }
  192. }
  193. /** Handle down button
  194. *
  195. * @param model The model
  196. */
  197. static void int_input_handle_down(IntInputModel* model) {
  198. if(model->selected_row < keyboard_row_count - 1) {
  199. model->selected_row += 1;
  200. }
  201. }
  202. /** Handle left button
  203. *
  204. * @param model The model
  205. */
  206. static void int_input_handle_left(IntInputModel* model) {
  207. if(model->selected_column > 0) {
  208. model->selected_column--;
  209. } else {
  210. model->selected_column = int_input_get_row_size(model->selected_row) - 1;
  211. }
  212. }
  213. /** Handle right button
  214. *
  215. * @param model The model
  216. */
  217. static void int_input_handle_right(IntInputModel* model) {
  218. if(model->selected_column < int_input_get_row_size(model->selected_row) - 1) {
  219. model->selected_column++;
  220. } else {
  221. model->selected_column = 0;
  222. }
  223. }
  224. /** Handle OK button
  225. *
  226. * @param model The model
  227. */
  228. static void int_input_handle_ok(IntInputModel* model) {
  229. char selected = int_input_get_row(model->selected_row)[model->selected_column].text;
  230. size_t text_length = strlen(model->text_buffer);
  231. UNUSED(text_length);
  232. if(selected == enter_symbol) {
  233. // int_input_call_input_callback(model);
  234. } else if(selected == backspace_symbol) {
  235. //int_input_clear_selected_byte(model);
  236. } else {
  237. if (model->clear_default_text) {
  238. text_length = 0;
  239. }
  240. if(text_length < (model->text_buffer_size - 1)) {
  241. //model->text_buffer[text_length] = selected;
  242. //model->text_buffer[text_length + 1] = 0;
  243. //FURI_LOG_D("INT_INPUT", model->text_buffer);
  244. FURI_LOG_D("INT_INPUT", "%u", text_length);
  245. FURI_LOG_D("INT_INPUT", "%u", model->text_buffer_size);
  246. }
  247. }
  248. model->clear_default_text = false;
  249. }
  250. /** Draw callback
  251. *
  252. * @param canvas The canvas
  253. * @param _model The model
  254. */
  255. static void int_input_view_draw_callback(Canvas* canvas, void* _model) {
  256. IntInputModel* model = _model;
  257. uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0;
  258. UNUSED(text_length);
  259. //uint8_t needed_string_width = canvas_width(canvas) - 8;
  260. //uint8_t start_pos = 4;
  261. //const char* text = model->text_buffer;
  262. canvas_clear(canvas);
  263. canvas_set_color(canvas, ColorBlack);
  264. int_input_draw_input(canvas, model);
  265. canvas_set_font(canvas, FontSecondary);
  266. canvas_draw_str(canvas, 2, 9, model->header);
  267. canvas_set_font(canvas, FontKeyboard);
  268. // Draw keyboard
  269. for(uint8_t row = 0; row < keyboard_row_count; row++) {
  270. const uint8_t column_count = int_input_get_row_size(row);
  271. const IntInputKey* keys = int_input_get_row(row);
  272. for(size_t column = 0; column < column_count; column++) {
  273. if(keys[column].text == enter_symbol) {
  274. canvas_set_color(canvas, ColorBlack);
  275. if(model->selected_row == row && model->selected_column == column) {
  276. canvas_draw_icon(
  277. canvas,
  278. keyboard_origin_x + keys[column].x,
  279. keyboard_origin_y + keys[column].y,
  280. &I_KeySaveSelected_24x11);
  281. } else {
  282. canvas_draw_icon(
  283. canvas,
  284. keyboard_origin_x + keys[column].x,
  285. keyboard_origin_y + keys[column].y,
  286. &I_KeySave_24x11);
  287. }
  288. } else if(keys[column].text == backspace_symbol) {
  289. canvas_set_color(canvas, ColorBlack);
  290. if(model->selected_row == row && model->selected_column == column) {
  291. canvas_draw_icon(
  292. canvas,
  293. keyboard_origin_x + keys[column].x,
  294. keyboard_origin_y + keys[column].y,
  295. &I_KeyBackspaceSelected_16x9);
  296. } else {
  297. canvas_draw_icon(
  298. canvas,
  299. keyboard_origin_x + keys[column].x,
  300. keyboard_origin_y + keys[column].y,
  301. &I_KeyBackspace_16x9);
  302. }
  303. } else {
  304. if(model->selected_row == row && model->selected_column == column) {
  305. canvas_set_color(canvas, ColorBlack);
  306. canvas_draw_box(
  307. canvas,
  308. keyboard_origin_x + keys[column].x - 3,
  309. keyboard_origin_y + keys[column].y - 10,
  310. 11,
  311. 13);
  312. canvas_set_color(canvas, ColorWhite);
  313. } else if(
  314. model->selected_row == -1 && row == 0 &&
  315. model->selected_column == column) {
  316. canvas_set_color(canvas, ColorBlack);
  317. canvas_draw_frame(
  318. canvas,
  319. keyboard_origin_x + keys[column].x - 3,
  320. keyboard_origin_y + keys[column].y - 10,
  321. 11,
  322. 13);
  323. } else {
  324. canvas_set_color(canvas, ColorBlack);
  325. }
  326. canvas_draw_glyph(
  327. canvas,
  328. keyboard_origin_x + keys[column].x,
  329. keyboard_origin_y + keys[column].y,
  330. keys[column].text);
  331. }
  332. }
  333. }
  334. }
  335. /** Input callback
  336. *
  337. * @param event The event
  338. * @param context The context
  339. *
  340. * @return true
  341. * @return false
  342. */
  343. static bool int_input_view_input_callback(InputEvent* event, void* context) {
  344. IntInput* int_input = context;
  345. furi_assert(int_input);
  346. bool consumed = false;
  347. // Fetch the model
  348. IntInputModel* model = view_get_model(int_input->view);
  349. if(event->type == InputTypeShort || event->type == InputTypeLong || event->type == InputTypeRepeat) {
  350. consumed = true;
  351. switch(event->key) {
  352. case InputKeyLeft:
  353. int_input_handle_left(model);
  354. break;
  355. case InputKeyRight:
  356. int_input_handle_right(model);
  357. break;
  358. case InputKeyUp:
  359. int_input_handle_up(model);
  360. break;
  361. case InputKeyDown:
  362. int_input_handle_down(model);
  363. break;
  364. case InputKeyOk:
  365. int_input_handle_ok(model);
  366. break;
  367. default:
  368. break;
  369. }
  370. }
  371. // commit view
  372. view_commit_model(int_input->view, consumed);
  373. return consumed;
  374. }
  375. /** Reset all input-related data in model
  376. *
  377. * @param model The model
  378. */
  379. static void int_input_reset_model_input_data(IntInputModel* model) {
  380. model->selected_row = 0;
  381. model->selected_column = 0;
  382. }
  383. IntInput* int_input_alloc() {
  384. IntInput* int_input = malloc(sizeof(IntInput));
  385. int_input->view = view_alloc();
  386. view_set_context(int_input->view, int_input);
  387. view_allocate_model(int_input->view, ViewModelTypeLocking, sizeof(IntInputModel));
  388. view_set_draw_callback(int_input->view, int_input_view_draw_callback);
  389. view_set_input_callback(int_input->view, int_input_view_input_callback);
  390. with_view_model(
  391. int_input->view,
  392. IntInputModel * model,
  393. {
  394. model->header = "";
  395. model->input_callback = NULL;
  396. // model->changed_callback = NULL;
  397. model->callback_context = NULL;
  398. int_input_reset_model_input_data(model);
  399. },
  400. true);
  401. return int_input;
  402. }
  403. void int_input_free(IntInput* int_input) {
  404. furi_assert(int_input);
  405. view_free(int_input->view);
  406. free(int_input);
  407. }
  408. View* int_input_get_view(IntInput* int_input) {
  409. furi_assert(int_input);
  410. return int_input->view;
  411. }
  412. void int_input_set_result_callback(
  413. IntInput* int_input,
  414. IntInputCallback input_callback,
  415. //IntChangedCallback changed_callback,
  416. void* callback_context,
  417. char* text_buffer,
  418. size_t text_buffer_size,
  419. bool clear_default_text) {
  420. //UNUSED(changed_callback);
  421. with_view_model(
  422. int_input->view,
  423. IntInputModel * model,
  424. {
  425. int_input_reset_model_input_data(model);
  426. model->input_callback = input_callback;
  427. model->callback_context = callback_context;
  428. model->text_buffer = text_buffer;
  429. model->text_buffer_size = text_buffer_size;
  430. model->clear_default_text = clear_default_text;
  431. },
  432. true);
  433. }
  434. void int_input_set_header_text(IntInput* int_input, const char* text) {
  435. with_view_model(
  436. int_input->view,
  437. IntInputModel * model,
  438. {
  439. model->header = text;
  440. },
  441. true);
  442. }