variable-item-list.c 9.2 KB

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