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 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. FURI_LOG_D("INT_INPUT", "%d", selected);
  247. //}
  248. }
  249. model->clear_default_text = false;
  250. }
  251. /** Draw callback
  252. *
  253. * @param canvas The canvas
  254. * @param _model The model
  255. */
  256. static void int_input_view_draw_callback(Canvas* canvas, void* _model) {
  257. IntInputModel* model = _model;
  258. uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0;
  259. UNUSED(text_length);
  260. //uint8_t needed_string_width = canvas_width(canvas) - 8;
  261. //uint8_t start_pos = 4;
  262. //const char* text = model->text_buffer;
  263. canvas_clear(canvas);
  264. canvas_set_color(canvas, ColorBlack);
  265. int_input_draw_input(canvas, model);
  266. canvas_set_font(canvas, FontSecondary);
  267. canvas_draw_str(canvas, 2, 9, model->header);
  268. canvas_set_font(canvas, FontKeyboard);
  269. // Draw keyboard
  270. for(uint8_t row = 0; row < keyboard_row_count; row++) {
  271. const uint8_t column_count = int_input_get_row_size(row);
  272. const IntInputKey* keys = int_input_get_row(row);
  273. for(size_t column = 0; column < column_count; column++) {
  274. if(keys[column].text == enter_symbol) {
  275. canvas_set_color(canvas, ColorBlack);
  276. if(model->selected_row == row && model->selected_column == column) {
  277. canvas_draw_icon(
  278. canvas,
  279. keyboard_origin_x + keys[column].x,
  280. keyboard_origin_y + keys[column].y,
  281. &I_KeySaveSelected_24x11);
  282. } else {
  283. canvas_draw_icon(
  284. canvas,
  285. keyboard_origin_x + keys[column].x,
  286. keyboard_origin_y + keys[column].y,
  287. &I_KeySave_24x11);
  288. }
  289. } else if(keys[column].text == backspace_symbol) {
  290. canvas_set_color(canvas, ColorBlack);
  291. if(model->selected_row == row && model->selected_column == column) {
  292. canvas_draw_icon(
  293. canvas,
  294. keyboard_origin_x + keys[column].x,
  295. keyboard_origin_y + keys[column].y,
  296. &I_KeyBackspaceSelected_16x9);
  297. } else {
  298. canvas_draw_icon(
  299. canvas,
  300. keyboard_origin_x + keys[column].x,
  301. keyboard_origin_y + keys[column].y,
  302. &I_KeyBackspace_16x9);
  303. }
  304. } else {
  305. if(model->selected_row == row && model->selected_column == column) {
  306. canvas_set_color(canvas, ColorBlack);
  307. canvas_draw_box(
  308. canvas,
  309. keyboard_origin_x + keys[column].x - 3,
  310. keyboard_origin_y + keys[column].y - 10,
  311. 11,
  312. 13);
  313. canvas_set_color(canvas, ColorWhite);
  314. } else if(
  315. model->selected_row == -1 && row == 0 &&
  316. model->selected_column == column) {
  317. canvas_set_color(canvas, ColorBlack);
  318. canvas_draw_frame(
  319. canvas,
  320. keyboard_origin_x + keys[column].x - 3,
  321. keyboard_origin_y + keys[column].y - 10,
  322. 11,
  323. 13);
  324. } else {
  325. canvas_set_color(canvas, ColorBlack);
  326. }
  327. canvas_draw_glyph(
  328. canvas,
  329. keyboard_origin_x + keys[column].x,
  330. keyboard_origin_y + keys[column].y,
  331. keys[column].text);
  332. }
  333. }
  334. }
  335. }
  336. /** Input callback
  337. *
  338. * @param event The event
  339. * @param context The context
  340. *
  341. * @return true
  342. * @return false
  343. */
  344. static bool int_input_view_input_callback(InputEvent* event, void* context) {
  345. IntInput* int_input = context;
  346. furi_assert(int_input);
  347. bool consumed = false;
  348. // Fetch the model
  349. IntInputModel* model = view_get_model(int_input->view);
  350. if(event->type == InputTypeShort || event->type == InputTypeLong || event->type == InputTypeRepeat) {
  351. consumed = true;
  352. switch(event->key) {
  353. case InputKeyLeft:
  354. int_input_handle_left(model);
  355. break;
  356. case InputKeyRight:
  357. int_input_handle_right(model);
  358. break;
  359. case InputKeyUp:
  360. int_input_handle_up(model);
  361. break;
  362. case InputKeyDown:
  363. int_input_handle_down(model);
  364. break;
  365. case InputKeyOk:
  366. int_input_handle_ok(model);
  367. break;
  368. default:
  369. consumed = false;
  370. break;
  371. }
  372. }
  373. // commit view
  374. view_commit_model(int_input->view, consumed);
  375. return consumed;
  376. }
  377. void int_input_reset(IntInput* int_input) {
  378. FURI_LOG_D("INT_INPUT", "Resetting Model");
  379. furi_assert(int_input);
  380. with_view_model(
  381. int_input->view,
  382. IntInputModel * model,
  383. {
  384. model->header = "";
  385. model->selected_row = 0;
  386. model->selected_column = 0;
  387. model->clear_default_text = false;
  388. model->text_buffer = "";
  389. model->text_buffer_size = 0;
  390. model->callback = NULL;
  391. model->callback_context = NULL;
  392. },
  393. true);
  394. }
  395. IntInput* int_input_alloc() {
  396. IntInput* int_input = malloc(sizeof(IntInput));
  397. int_input->view = view_alloc();
  398. view_set_context(int_input->view, int_input);
  399. view_allocate_model(int_input->view, ViewModelTypeLocking, sizeof(IntInputModel));
  400. view_set_draw_callback(int_input->view, int_input_view_draw_callback);
  401. view_set_input_callback(int_input->view, int_input_view_input_callback);
  402. int_input_reset(int_input);
  403. return int_input;
  404. }
  405. void int_input_free(IntInput* int_input) {
  406. furi_assert(int_input);
  407. view_free(int_input->view);
  408. free(int_input);
  409. }
  410. View* int_input_get_view(IntInput* int_input) {
  411. furi_assert(int_input);
  412. return int_input->view;
  413. }
  414. void int_input_set_result_callback(
  415. IntInput* int_input,
  416. IntInputCallback callback,
  417. void* callback_context,
  418. char* text_buffer,
  419. size_t text_buffer_size,
  420. bool clear_default_text) {
  421. with_view_model(
  422. int_input->view,
  423. IntInputModel * model,
  424. {
  425. model->callback = callback;
  426. model->callback_context = callback_context;
  427. model->text_buffer = text_buffer;
  428. model->text_buffer_size = text_buffer_size;
  429. model->clear_default_text = clear_default_text;
  430. },
  431. true);
  432. }
  433. void int_input_set_header_text(IntInput* int_input, const char* text) {
  434. with_view_model(
  435. int_input->view,
  436. IntInputModel * model,
  437. {
  438. model->header = text;
  439. },
  440. true);
  441. }