variable-item-list.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include "variable-item-list.h"
  2. #include "gui/canvas.h"
  3. #include <m-array.h>
  4. #include <furi.h>
  5. #include <gui/elements.h>
  6. #include <stdint.h>
  7. struct VariableItem {
  8. const char* label;
  9. uint8_t current_value_index;
  10. string_t current_value_text;
  11. uint8_t values_count;
  12. VariableItemChangeCallback change_callback;
  13. void* context;
  14. };
  15. ARRAY_DEF(VariableItemArray, VariableItem, M_POD_OPLIST);
  16. struct VariableItemList {
  17. View* view;
  18. VariableItemListEnterCallback callback;
  19. void* context;
  20. };
  21. typedef struct {
  22. VariableItemArray_t items;
  23. uint8_t position;
  24. uint8_t window_position;
  25. } VariableItemListModel;
  26. static void variable_item_list_process_up(VariableItemList* variable_item_list);
  27. static void variable_item_list_process_down(VariableItemList* variable_item_list);
  28. static void variable_item_list_process_left(VariableItemList* variable_item_list);
  29. static void variable_item_list_process_right(VariableItemList* variable_item_list);
  30. static void variable_item_list_process_ok(VariableItemList* variable_item_list);
  31. static void variable_item_list_draw_callback(Canvas* canvas, void* _model) {
  32. VariableItemListModel* model = _model;
  33. const uint8_t item_height = 16;
  34. const uint8_t item_width = 123;
  35. canvas_clear(canvas);
  36. uint8_t position = 0;
  37. VariableItemArray_it_t it;
  38. canvas_set_font(canvas, FontSecondary);
  39. for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it);
  40. VariableItemArray_next(it)) {
  41. uint8_t item_position = position - model->window_position;
  42. uint8_t items_on_screen = 4;
  43. uint8_t y_offset = 0;
  44. if(item_position < items_on_screen) {
  45. const VariableItem* item = VariableItemArray_cref(it);
  46. uint8_t item_y = y_offset + (item_position * item_height);
  47. uint8_t item_text_y = item_y + item_height - 4;
  48. if(position == model->position) {
  49. canvas_set_color(canvas, ColorBlack);
  50. elements_slightly_rounded_box(canvas, 0, item_y + 1, item_width, item_height - 2);
  51. canvas_set_color(canvas, ColorWhite);
  52. } else {
  53. canvas_set_color(canvas, ColorBlack);
  54. }
  55. canvas_draw_str(canvas, 6, item_text_y, item->label);
  56. if(item->current_value_index > 0) {
  57. canvas_draw_str(canvas, 73, item_text_y, "<");
  58. }
  59. canvas_draw_str(canvas, 80, item_text_y, string_get_cstr(item->current_value_text));
  60. if(item->current_value_index < (item->values_count - 1)) {
  61. canvas_draw_str(canvas, 115, item_text_y, ">");
  62. }
  63. }
  64. position++;
  65. }
  66. elements_scrollbar(canvas, model->position, VariableItemArray_size(model->items));
  67. }
  68. static bool variable_item_list_input_callback(InputEvent* event, void* context) {
  69. VariableItemList* variable_item_list = context;
  70. furi_assert(variable_item_list);
  71. bool consumed = false;
  72. if(event->type == InputTypeShort) {
  73. switch(event->key) {
  74. case InputKeyUp:
  75. consumed = true;
  76. variable_item_list_process_up(variable_item_list);
  77. break;
  78. case InputKeyDown:
  79. consumed = true;
  80. variable_item_list_process_down(variable_item_list);
  81. break;
  82. case InputKeyLeft:
  83. consumed = true;
  84. variable_item_list_process_left(variable_item_list);
  85. break;
  86. case InputKeyRight:
  87. consumed = true;
  88. variable_item_list_process_right(variable_item_list);
  89. break;
  90. case InputKeyOk:
  91. variable_item_list_process_ok(variable_item_list);
  92. break;
  93. default:
  94. break;
  95. }
  96. }
  97. return consumed;
  98. }
  99. void variable_item_list_process_up(VariableItemList* variable_item_list) {
  100. with_view_model(
  101. variable_item_list->view, (VariableItemListModel * model) {
  102. uint8_t items_on_screen = 4;
  103. if(model->position > 0) {
  104. model->position--;
  105. if(((model->position - model->window_position) < 1) &&
  106. model->window_position > 0) {
  107. model->window_position--;
  108. }
  109. } else {
  110. model->position = VariableItemArray_size(model->items) - 1;
  111. if(model->position > (items_on_screen - 1)) {
  112. model->window_position = model->position - (items_on_screen - 1);
  113. }
  114. }
  115. return true;
  116. });
  117. }
  118. void variable_item_list_process_down(VariableItemList* variable_item_list) {
  119. with_view_model(
  120. variable_item_list->view, (VariableItemListModel * model) {
  121. uint8_t items_on_screen = 4;
  122. if(model->position < (VariableItemArray_size(model->items) - 1)) {
  123. model->position++;
  124. if((model->position - model->window_position) > (items_on_screen - 2) &&
  125. model->window_position <
  126. (VariableItemArray_size(model->items) - items_on_screen)) {
  127. model->window_position++;
  128. }
  129. } else {
  130. model->position = 0;
  131. model->window_position = 0;
  132. }
  133. return true;
  134. });
  135. }
  136. VariableItem* variable_item_list_get_selected_item(VariableItemListModel* model) {
  137. VariableItem* item = NULL;
  138. VariableItemArray_it_t it;
  139. uint8_t position = 0;
  140. for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it);
  141. VariableItemArray_next(it)) {
  142. if(position == model->position) {
  143. break;
  144. }
  145. position++;
  146. }
  147. item = VariableItemArray_ref(it);
  148. furi_assert(item);
  149. return item;
  150. }
  151. void variable_item_list_process_left(VariableItemList* variable_item_list) {
  152. with_view_model(
  153. variable_item_list->view, (VariableItemListModel * model) {
  154. VariableItem* item = variable_item_list_get_selected_item(model);
  155. if(item->current_value_index > 0) {
  156. item->current_value_index--;
  157. if(item->change_callback) {
  158. item->change_callback(item);
  159. }
  160. }
  161. return true;
  162. });
  163. }
  164. void variable_item_list_process_right(VariableItemList* variable_item_list) {
  165. with_view_model(
  166. variable_item_list->view, (VariableItemListModel * model) {
  167. VariableItem* item = variable_item_list_get_selected_item(model);
  168. if(item->current_value_index < (item->values_count - 1)) {
  169. item->current_value_index++;
  170. if(item->change_callback) {
  171. item->change_callback(item);
  172. }
  173. }
  174. return true;
  175. });
  176. }
  177. void variable_item_list_process_ok(VariableItemList* variable_item_list) {
  178. with_view_model(
  179. variable_item_list->view, (VariableItemListModel * model) {
  180. if(variable_item_list->callback) {
  181. variable_item_list->callback(variable_item_list->context, model->position);
  182. }
  183. return false;
  184. });
  185. }
  186. VariableItemList* variable_item_list_alloc() {
  187. VariableItemList* variable_item_list = furi_alloc(sizeof(VariableItemList));
  188. variable_item_list->view = view_alloc();
  189. view_set_context(variable_item_list->view, variable_item_list);
  190. view_allocate_model(
  191. variable_item_list->view, ViewModelTypeLocking, sizeof(VariableItemListModel));
  192. view_set_draw_callback(variable_item_list->view, variable_item_list_draw_callback);
  193. view_set_input_callback(variable_item_list->view, variable_item_list_input_callback);
  194. with_view_model(
  195. variable_item_list->view, (VariableItemListModel * model) {
  196. VariableItemArray_init(model->items);
  197. model->position = 0;
  198. model->window_position = 0;
  199. return true;
  200. });
  201. return variable_item_list;
  202. }
  203. void variable_item_list_free(VariableItemList* variable_item_list) {
  204. furi_assert(variable_item_list);
  205. with_view_model(
  206. variable_item_list->view, (VariableItemListModel * model) {
  207. VariableItemArray_it_t it;
  208. for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it);
  209. VariableItemArray_next(it)) {
  210. string_clear(VariableItemArray_ref(it)->current_value_text);
  211. }
  212. VariableItemArray_clear(model->items);
  213. return false;
  214. });
  215. view_free(variable_item_list->view);
  216. free(variable_item_list);
  217. }
  218. void variable_item_list_clean(VariableItemList* variable_item_list) {
  219. furi_assert(variable_item_list);
  220. with_view_model(
  221. variable_item_list->view, (VariableItemListModel * model) {
  222. VariableItemArray_it_t it;
  223. for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it);
  224. VariableItemArray_next(it)) {
  225. string_clean(VariableItemArray_ref(it)->current_value_text);
  226. }
  227. VariableItemArray_clean(model->items);
  228. return false;
  229. });
  230. }
  231. View* variable_item_list_get_view(VariableItemList* variable_item_list) {
  232. furi_assert(variable_item_list);
  233. return variable_item_list->view;
  234. }
  235. VariableItem* variable_item_list_add(
  236. VariableItemList* variable_item_list,
  237. const char* label,
  238. uint8_t values_count,
  239. VariableItemChangeCallback change_callback,
  240. void* context) {
  241. VariableItem* item = NULL;
  242. furi_assert(label);
  243. furi_assert(variable_item_list);
  244. with_view_model(
  245. variable_item_list->view, (VariableItemListModel * model) {
  246. item = VariableItemArray_push_new(model->items);
  247. item->label = label;
  248. item->values_count = values_count;
  249. item->change_callback = change_callback;
  250. item->context = context;
  251. item->current_value_index = 0;
  252. string_init(item->current_value_text);
  253. return true;
  254. });
  255. return item;
  256. }
  257. void variable_item_list_set_enter_callback(
  258. VariableItemList* variable_item_list,
  259. VariableItemListEnterCallback callback,
  260. void* context) {
  261. furi_assert(callback);
  262. with_view_model(
  263. variable_item_list->view, (VariableItemListModel * model) {
  264. variable_item_list->callback = callback;
  265. variable_item_list->context = context;
  266. return false;
  267. });
  268. }
  269. void variable_item_set_current_value_index(VariableItem* item, uint8_t current_value_index) {
  270. item->current_value_index = current_value_index;
  271. }
  272. void variable_item_set_current_value_text(VariableItem* item, const char* current_value_text) {
  273. string_set_str(item->current_value_text, current_value_text);
  274. }
  275. uint8_t variable_item_get_current_value_index(VariableItem* item) {
  276. return item->current_value_index;
  277. }
  278. void* variable_item_get_context(VariableItem* item) {
  279. return item->context;
  280. }