multi_converter_mode_display.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include "multi_converter_mode_display.h"
  2. #define MULTI_CONVERTER_DISPLAY_KEYS 18 // [0] to [F] + [BACK] + [SELECT]
  3. #define MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE 0 // long press
  4. #define MULTI_CONVERTER_DISPLAY_KEY_COMMA 1 // long press
  5. #define MULTI_CONVERTER_DISPLAY_KEY_DEL 16
  6. #define MULTI_CONVERTER_DISPLAY_KEY_SELECT 17
  7. #define MULTI_CONVERTER_DISPLAY_CHAR_COMMA '.'
  8. #define MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE '-'
  9. #define MULTI_CONVERTER_DISPLAY_CHAR_DEL '<'
  10. #define MULTI_CONVERTER_DISPLAY_CHAR_SELECT '#'
  11. #define MULTI_CONVERTER_DISPLAY_CHAR_BLANK ' '
  12. #define MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN 3
  13. #define MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT 8
  14. void multi_converter_mode_display_convert(MultiConverterState* const multi_converter_state) {
  15. // 1.- if origin == destination (in theory user won't be allowed to choose the same options, but it's kinda "valid"...)
  16. // just copy buffer_orig to buffer_dest and that's it
  17. if(multi_converter_state->unit_type_orig == multi_converter_state->unit_type_dest) {
  18. memcpy(
  19. multi_converter_state->buffer_dest,
  20. multi_converter_state->buffer_orig,
  21. MULTI_CONVERTER_NUMBER_DIGITS);
  22. return;
  23. }
  24. // 2.- origin_buffer has not null functions
  25. if(multi_converter_get_unit(multi_converter_state->unit_type_orig).convert_function == NULL ||
  26. multi_converter_get_unit(multi_converter_state->unit_type_orig).allowed_function == NULL)
  27. return;
  28. // 3.- valid destination type (using allowed_destinations function)
  29. if(!multi_converter_get_unit(multi_converter_state->unit_type_orig)
  30. .allowed_function(multi_converter_state->unit_type_dest))
  31. return;
  32. multi_converter_get_unit(multi_converter_state->unit_type_orig)
  33. .convert_function(multi_converter_state);
  34. }
  35. void multi_converter_mode_display_draw(
  36. Canvas* const canvas,
  37. const MultiConverterState* multi_converter_state) {
  38. canvas_set_color(canvas, ColorBlack);
  39. // ORIGIN
  40. canvas_set_font(canvas, FontPrimary);
  41. canvas_draw_str(
  42. canvas, 2, 10, multi_converter_get_unit(multi_converter_state->unit_type_orig).mini_name);
  43. canvas_set_font(canvas, FontPrimary);
  44. canvas_draw_str(canvas, 2 + 30, 10, multi_converter_state->buffer_orig);
  45. // DESTINATION
  46. canvas_set_font(canvas, FontPrimary);
  47. canvas_draw_str(
  48. canvas,
  49. 2,
  50. 10 + 12,
  51. multi_converter_get_unit(multi_converter_state->unit_type_dest).mini_name);
  52. canvas_set_font(canvas, FontPrimary);
  53. canvas_draw_str(canvas, 2 + 30, 10 + 12, multi_converter_state->buffer_dest);
  54. // SEPARATOR_LINE
  55. canvas_draw_line(canvas, 2, 25, 128 - 3, 25);
  56. // KEYBOARD
  57. uint8_t _x = 5;
  58. uint8_t _y = 25 + 15; // line + 10
  59. for(int i = 0; i < MULTI_CONVERTER_DISPLAY_KEYS; i++) {
  60. char g;
  61. if(i < 10)
  62. g = (i + '0');
  63. else if(i < 16)
  64. g = ((i - 10) + 'A');
  65. else if(i == MULTI_CONVERTER_DISPLAY_KEY_DEL)
  66. g = MULTI_CONVERTER_DISPLAY_CHAR_DEL;
  67. else
  68. g = MULTI_CONVERTER_DISPLAY_CHAR_SELECT;
  69. uint8_t g_w = canvas_glyph_width(canvas, g);
  70. if(i < 16 &&
  71. i > multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys -
  72. 1) {
  73. // some units won't use the full [0] - [F] keyboard, in those situations just hide the char
  74. // (won't be selectable anyway, so no worries here; this is just about drawing stuff)
  75. g = MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
  76. }
  77. // currently hover key is highlighted
  78. if((multi_converter_state->display).key == i) {
  79. canvas_draw_box(
  80. canvas,
  81. _x - MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN,
  82. _y - (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
  83. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN),
  84. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w +
  85. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN,
  86. MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
  87. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2);
  88. canvas_set_color(canvas, ColorWhite);
  89. } else {
  90. canvas_draw_frame(
  91. canvas,
  92. _x - MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN,
  93. _y - (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
  94. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN),
  95. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w +
  96. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN,
  97. MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
  98. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2);
  99. }
  100. // draw key
  101. canvas_draw_glyph(canvas, _x, _y, g);
  102. // certain keys have long_press features, draw whatever they're using there too
  103. if(i == MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE) {
  104. canvas_draw_box(
  105. canvas,
  106. _x + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w - 4,
  107. _y + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN - 2,
  108. 4,
  109. 2);
  110. } else if(i == MULTI_CONVERTER_DISPLAY_KEY_COMMA) {
  111. canvas_draw_box(
  112. canvas,
  113. _x + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN + g_w - 2,
  114. _y + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN - 2,
  115. 2,
  116. 2);
  117. }
  118. // back to black
  119. canvas_set_color(canvas, ColorBlack);
  120. if(i < 8) {
  121. _x += g_w + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2 + 2;
  122. } else if(i == 8) {
  123. _y += (MULTI_CONVERTER_DISPLAY_KEY_CHAR_HEIGHT +
  124. MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2) +
  125. 3;
  126. _x = 8; // some padding at the beginning on second line
  127. } else {
  128. _x += g_w + MULTI_CONVERTER_DISPLAY_KEY_FRAME_MARGIN * 2 + 1;
  129. }
  130. }
  131. }
  132. void multi_converter_mode_display_navigation(
  133. InputKey key,
  134. MultiConverterState* const multi_converter_state) {
  135. // first move to keyboard position, then check if the ORIGIN allows that specific key, if not jump to the "closest one"
  136. switch(key) {
  137. default:
  138. break;
  139. case InputKeyUp:
  140. case InputKeyDown:
  141. if((multi_converter_state->display).key >= 9)
  142. (multi_converter_state->display).key -= 9;
  143. else
  144. (multi_converter_state->display).key += 9;
  145. break;
  146. case InputKeyLeft:
  147. case InputKeyRight:
  148. (multi_converter_state->display).key += (key == InputKeyLeft ? -1 : 1);
  149. if((multi_converter_state->display).key > MULTI_CONVERTER_DISPLAY_KEYS - 1)
  150. (multi_converter_state->display).key = 0;
  151. else if((multi_converter_state->display).key < 0)
  152. (multi_converter_state->display).key = MULTI_CONVERTER_DISPLAY_KEYS - 1;
  153. break;
  154. }
  155. // if destination key is disabled by max_number_keys, move to the closest one
  156. // (this could be improved with more accurate keys movements, probably...)
  157. if(multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys >= 16)
  158. return; // weird, since this means "do not show any number on the keyboard, but just in case..."
  159. int8_t i = -1;
  160. if(key == InputKeyRight || key == InputKeyDown) i = 1;
  161. while((multi_converter_state->display).key < 16 &&
  162. (multi_converter_state->display).key >
  163. multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys -
  164. 1) {
  165. (multi_converter_state->display).key += i;
  166. if((multi_converter_state->display).key > MULTI_CONVERTER_DISPLAY_KEYS - 1)
  167. (multi_converter_state->display).key = 0;
  168. else if((multi_converter_state->display).key < 0)
  169. (multi_converter_state->display).key = MULTI_CONVERTER_DISPLAY_KEYS - 1;
  170. }
  171. }
  172. void multi_converter_mode_display_reset(MultiConverterState* const multi_converter_state) {
  173. // clean the buffers
  174. for(int i = 0; i < MULTI_CONVERTER_NUMBER_DIGITS; i++) {
  175. multi_converter_state->buffer_orig[i] = MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
  176. multi_converter_state->buffer_dest[i] = MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
  177. }
  178. // reset the display flags and index
  179. multi_converter_state->display.cursor = 0;
  180. multi_converter_state->display.key = 0;
  181. multi_converter_state->display.comma = 0;
  182. multi_converter_state->display.negative = 0;
  183. }
  184. void multi_converter_mode_display_toggle_negative(
  185. MultiConverterState* const multi_converter_state) {
  186. if(multi_converter_get_unit(multi_converter_state->unit_type_orig).allow_negative) {
  187. if(!(multi_converter_state->display).negative) {
  188. // shift origin buffer one to right + add the "-" sign (last digit will be lost)
  189. for(int i = MULTI_CONVERTER_NUMBER_DIGITS - 1; i > 0; i--) {
  190. // we could avoid the blanks, but nevermind
  191. multi_converter_state->buffer_orig[i] = multi_converter_state->buffer_orig[i - 1];
  192. }
  193. multi_converter_state->buffer_orig[0] = MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE;
  194. // only increment cursor if we're not out of bound
  195. if((multi_converter_state->display).cursor < MULTI_CONVERTER_NUMBER_DIGITS)
  196. (multi_converter_state->display).cursor++;
  197. } else {
  198. // shift origin buffer one to left, append ' ' on the end
  199. for(int i = 0; i < MULTI_CONVERTER_NUMBER_DIGITS - 1; i++) {
  200. if(multi_converter_state->buffer_orig[i] == MULTI_CONVERTER_DISPLAY_CHAR_BLANK)
  201. break;
  202. multi_converter_state->buffer_orig[i] = multi_converter_state->buffer_orig[i + 1];
  203. }
  204. multi_converter_state->buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS - 1] =
  205. MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
  206. (multi_converter_state->display).cursor--;
  207. }
  208. // toggle flag
  209. (multi_converter_state->display).negative ^= 1;
  210. }
  211. }
  212. void multi_converter_mode_display_add_comma(MultiConverterState* const multi_converter_state) {
  213. if(!multi_converter_get_unit(multi_converter_state->unit_type_orig).allow_comma ||
  214. (multi_converter_state->display).comma || !(multi_converter_state->display).cursor ||
  215. ((multi_converter_state->display).cursor == (MULTI_CONVERTER_NUMBER_DIGITS - 1)))
  216. return; // maybe not allowerd; or one comma already in place; also cannot add commas as first or last chars
  217. // set flag to one
  218. (multi_converter_state->display).comma = 1;
  219. multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] =
  220. MULTI_CONVERTER_DISPLAY_CHAR_COMMA;
  221. (multi_converter_state->display).cursor++;
  222. }
  223. void multi_converter_mode_display_add_number(MultiConverterState* const multi_converter_state) {
  224. if((multi_converter_state->display).key >
  225. multi_converter_get_unit(multi_converter_state->unit_type_orig).max_number_keys - 1)
  226. return;
  227. if((multi_converter_state->display).key < 10) {
  228. multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] =
  229. (multi_converter_state->display).key + '0';
  230. } else {
  231. multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] =
  232. ((multi_converter_state->display).key - 10) + 'A';
  233. }
  234. (multi_converter_state->display).cursor++;
  235. }
  236. MultiConverterModeTrigger multi_converter_mode_display_ok(
  237. uint8_t long_press,
  238. MultiConverterState* const multi_converter_state) {
  239. if((multi_converter_state->display).key < MULTI_CONVERTER_DISPLAY_KEY_DEL) {
  240. if((multi_converter_state->display).cursor >= MULTI_CONVERTER_NUMBER_DIGITS)
  241. return None; // limit reached, ignore
  242. // long press on 0 toggle NEGATIVE if allowed, on 1 adds COMMA if allowed
  243. if(long_press) {
  244. if((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_NEGATIVE) {
  245. // toggle negative
  246. multi_converter_mode_display_toggle_negative(multi_converter_state);
  247. } else if((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_COMMA) {
  248. // add comma
  249. multi_converter_mode_display_add_comma(multi_converter_state);
  250. }
  251. } else {
  252. // regular keys
  253. multi_converter_mode_display_add_number(multi_converter_state);
  254. }
  255. multi_converter_mode_display_convert(multi_converter_state);
  256. } else if((multi_converter_state->display).key == MULTI_CONVERTER_DISPLAY_KEY_DEL) {
  257. if((multi_converter_state->display).cursor > 0) (multi_converter_state->display).cursor--;
  258. if(multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] ==
  259. MULTI_CONVERTER_DISPLAY_CHAR_COMMA)
  260. (multi_converter_state->display).comma = 0;
  261. if(multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] ==
  262. MULTI_CONVERTER_DISPLAY_CHAR_NEGATIVE)
  263. (multi_converter_state->display).negative = 0;
  264. multi_converter_state->buffer_orig[(multi_converter_state->display).cursor] =
  265. MULTI_CONVERTER_DISPLAY_CHAR_BLANK;
  266. multi_converter_mode_display_convert(multi_converter_state);
  267. } else { // MULTI_CONVERTER_DISPLAY_KEY_SELECT
  268. return Reset;
  269. }
  270. return None;
  271. }