/ src / display / screen_ui / display_screen_ui_list_menu.c
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  }