display_screen_ui_list_menu.c
1 #include "display_screen_ui.h" 2 3 #include <stdio.h> 4 5 #define UI_NAME list_menu 6 7 static lv_obj_t* screen = NULL; 8 static lv_obj_t* window = NULL; 9 static lv_obj_t* back_button = NULL; 10 static lv_obj_t* options = NULL; 11 static lv_group_t* active_group = NULL; 12 13 static ui_common_simple_cb back_clicked = NULL; 14 static lv_event_cb_t option_clicked = NULL; 15 16 static menu_option_desc_t* menuOptions = NULL; 17 static size_t menuOptionsCount = 0; 18 static int32_t menuSelectedOption = -1; 19 20 static char menuTitle[LV_FS_MAX_PATH_LENGTH] = "<Untitled Menu>"; 21 22 static void display_screen_ui_list_menu_refresh_options(); 23 static void display_screen_ui_list_menu_back_event(lv_obj_t* obj, lv_event_t e); 24 static void display_screen_ui_list_menu_options_event(lv_obj_t* obj, lv_event_t e); 25 static void display_screen_ui_list_menu_option_button_event(lv_obj_t* obj, lv_event_t e); 26 27 UI_DECLARE_CREATE(UI_NAME) 28 { 29 if (screen != NULL) 30 { 31 back_clicked = NULL; 32 option_clicked = NULL; 33 menuOptionsCount = 0; 34 display_screen_ui_list_menu_refresh_options(); 35 return screen; 36 } 37 38 screen = lv_obj_create(NULL, NULL); 39 40 // window 41 window = lv_win_create(screen, NULL); 42 43 // header 44 lv_win_set_title(window, menuTitle); 45 46 // back button 47 back_button = lv_win_add_btn_left(window, LV_SYMBOL_LEFT); 48 lv_obj_set_event_cb(back_button, display_screen_ui_list_menu_back_event); 49 ui_common_set_window_button_style(back_button); 50 51 // main content 52 lv_page_set_scrl_layout(lv_win_get_content(window), LV_LAYOUT_PRETTY_MID); 53 display_screen_ui_list_menu_refresh_options(); 54 55 return screen; 56 } 57 58 UI_DECLARE_ACTIVATE(UI_NAME) 59 { 60 lv_scr_load(screen); 61 lv_group_set_focus_cb(group, NULL); 62 lv_group_remove_all_objs(group); 63 64 // hide the back button if there's no handler. 65 if (back_clicked != NULL) 66 { 67 lv_obj_set_hidden(back_button, false); 68 lv_group_add_obj(group, back_button); 69 } 70 else 71 { 72 lv_obj_set_hidden(back_button, true); 73 } 74 75 lv_group_add_obj(group, options); 76 77 lv_group_focus_obj(options); 78 79 active_group = group; 80 ui_common_cb_set_active_group(group); 81 82 // add status widget 83 ui_status_widget_get(screen); 84 } 85 86 void UI_DECLARE_FUNCTION(UI_NAME, set_options)(menu_option_desc_t new_options[], size_t num_options) 87 { 88 menuOptions = new_options; 89 menuOptionsCount = num_options; 90 display_screen_ui_list_menu_refresh_options(); 91 } 92 93 void UI_DECLARE_FUNCTION(UI_NAME, set_title)(const char* title) 94 { 95 lv_snprintf(menuTitle, LV_FS_MAX_PATH_LENGTH, "%s", title); 96 97 if (window == NULL) 98 { 99 return; 100 } 101 102 lv_win_set_title(window, menuTitle); 103 } 104 105 void UI_DECLARE_FUNCTION(UI_NAME, set_back_clicked_cb)(ui_common_simple_cb callback) 106 { 107 back_clicked = callback; 108 } 109 110 void UI_DECLARE_FUNCTION(UI_NAME, set_option_clicked_cb)(lv_event_cb_t callback) 111 { 112 option_clicked = callback; 113 } 114 115 static void display_screen_ui_list_menu_back_event(lv_obj_t* obj, lv_event_t e) 116 { 117 if (e == LV_EVENT_CLICKED) 118 { 119 if (back_clicked != NULL) 120 { 121 back_clicked(); 122 } 123 } 124 else 125 { 126 ui_common_up_down_focus_cb(obj, e); 127 } 128 } 129 130 static void display_screen_ui_list_menu_options_event(lv_obj_t* list, lv_event_t e) 131 { 132 if (e == LV_EVENT_KEY) 133 { 134 // check to see if we are at the end of the list and should focus on something else. 135 136 uint32_t key = *((uint32_t*)lv_event_get_data()); 137 138 bool prevKey = key == LV_KEY_UP || key == LV_KEY_LEFT || key == LV_KEY_PREV; 139 bool nextKey = key == LV_KEY_DOWN || key == LV_KEY_RIGHT || key == LV_KEY_NEXT; 140 141 if (prevKey && menuSelectedOption == 0) 142 { 143 // at top, move focus 144 lv_group_focus_prev(active_group); 145 } 146 else if (nextKey && menuSelectedOption == lv_list_get_size(list) - 1) 147 { 148 // at end, move focus 149 lv_group_focus_next(active_group); 150 } 151 else 152 { 153 // update selected option 154 lv_obj_t* selected = lv_list_get_btn_selected(list); 155 if (selected != NULL) 156 { 157 menuSelectedOption = lv_list_get_btn_index(list, selected); 158 } 159 } 160 } 161 } 162 163 static void display_screen_ui_list_menu_option_button_event(lv_obj_t* obj, lv_event_t e) 164 { 165 if (e == LV_EVENT_CLICKED) 166 { 167 // does the menu item have a specific callback? 168 menu_option_desc_t* menu_data = (menu_option_desc_t*)obj->user_data; 169 if (menu_data->click_cb != NULL) 170 { 171 lv_group_t* g = (lv_group_t*)lv_obj_get_group(options); 172 menu_data->click_cb(menu_data, g); 173 } 174 175 // general callback 176 if (option_clicked != NULL) 177 { 178 option_clicked(obj, e); 179 } 180 } 181 } 182 183 static void display_screen_ui_list_menu_refresh_options() 184 { 185 // can't refresh if we don't have a screen. 186 if (screen == NULL) 187 { 188 return; 189 } 190 191 if (options == NULL) 192 { 193 options = lv_list_create(window, NULL); 194 lv_list_set_scroll_propagation(options, true); 195 196 lv_obj_set_event_cb(options, display_screen_ui_list_menu_options_event); 197 198 lv_obj_t* content = lv_win_get_content(window); 199 200 // fit this control on the screen nicely! 201 lv_disp_size_t disp_size = lv_disp_get_size_category(NULL); 202 lv_coord_t grid_h = lv_page_get_height_grid(content, 1, 1); 203 lv_coord_t grid_w; 204 if (disp_size <= LV_DISP_SIZE_SMALL) grid_w = lv_page_get_width_grid(content, 1, 1); 205 else grid_w = lv_page_get_width_grid(content, 2, 1); 206 lv_obj_set_size(options, grid_w, grid_h); 207 } 208 else 209 { 210 // delete any existing options 211 lv_list_clean(options); 212 menuSelectedOption = -1; 213 } 214 215 for (size_t scan = 0; scan < menuOptionsCount; ++scan) 216 { 217 menu_option_desc_t* opt = &menuOptions[scan]; 218 lv_obj_t* btn = lv_list_add_btn(options, opt->prefix, opt->option); 219 lv_label_set_long_mode(lv_list_get_btn_label(btn), LV_LABEL_LONG_DOT); 220 lv_obj_set_click(btn, true); 221 lv_obj_set_event_cb(btn, display_screen_ui_list_menu_option_button_event); 222 btn->user_data = opt; 223 } 224 225 if (menuOptionsCount > 0) 226 { 227 menuSelectedOption = 0; 228 } 229 }