1 #include "menu.h"
2 #include "creation.h"
3 #include "layout.h"
4 #include "list.h"
5 
6 form_t *root_form = 0;
7 
menu_set_form(form_t * form)8 void menu_set_form(form_t *form)
9 {
10 	root_form = form;
11 }
12 
menu_draw_help(item_t * item)13 void menu_draw_help(item_t *item)
14 {
15 	char
16 		buffer[80*4],
17 		*p_text,
18 		*p_break,
19 		*p_start;
20 
21 	int
22 		line = 20;
23 
24 	bool in_word=true;
25 
26 	if (!item) return;
27 
28 	video_clear_box(1,20,78,4,' ',MENUATTR_NORMAL);
29 
30 	if (item->help_text)
31 	{
32 		/* Reformat help so that it word-wraps */
33 		buffer[0] = 0;
34 
35 		strcpy(buffer, item->help_text);
36 
37 		p_text  = p_break = p_start = buffer;
38 		in_word = true;
39 
40 		for (;;)
41 		{
42 			if (*p_text == ' ' && in_word == true)
43 			{
44 				in_word = false;
45 				p_break = p_text;
46 			}
47 			else if (*p_text != ' ')
48 			{
49 				in_word = true;
50 			}
51 			if ((p_text - p_start >= 72) || *p_text == 0) // flush
52 			{
53 				if (*p_text == '\0') p_break = p_text;
54 				*p_break = 0;
55 				video_draw_text(2,line++, MENUATTR_NORMAL, p_start, -1);
56 				if (*p_text == '\0') return;
57 				p_break++;
58 				while (p_break < p_text && *p_break == ' ')
59 				{
60 					p_break++;
61 				}
62 				p_start = p_break;
63 				if (*p_break == '\0') return;
64 			}
65 			else p_text++;
66 		}
67 	}
68 }
69 
menu_draw(menu_t * menu)70 void menu_draw(menu_t *menu)
71 {
72 	if (menu && menu->needs_layout)
73 	{
74 		menu_layout(menu);
75 	}
76 	if (menu)
77 	{
78 		item_t *item = (item_t *)(menu->item_list.first);
79 
80 		if (menu->type == MENUTYPE_POPUP)
81 		{
82 			video_clear_box(menu->x-1, menu->y-1, menu->w, menu->h, ' ', MENUATTR_NORMAL);
83 		}
84 
85 		while (item)
86 		{
87 			item->f_render(menu, item,
88 						   (item->disabled==true)?MENUATTR_DISABLED:
89 						   (item == menu->current_item)?MENUATTR_HILITE : MENUATTR_ITEM);
90 			item = (item_t *)(item->link.next);
91 		}
92 		if (menu->type == MENUTYPE_FORM)
93 		{
94 			menu_draw_help(menu->current_item);
95 		}
96 		else
97 		{
98 			video_draw_box(SINGLE_BOX, MENUATTR_NORMAL, NULL, 0, menu->x-1, menu->y-1,
99 						   menu->w+2, menu->h+3);
100 		}
101 	}
102 }
103 
menu_draw_form(form_t * form)104 void menu_draw_form(form_t *form)
105 {
106 	char
107 		*title;
108 	menu_t
109 		*menu = form->current_menu;
110 
111 	/* Prefer current menu title if set, otherwise use the form title */
112 	if (menu && menu->menu_title) title = menu->menu_title;
113 	else if (form->form_title) title = form->form_title;
114 	else title = NULL; //"Untitled";
115 
116 	video_draw_box(SINGLE_BOX, MENUATTR_NORMAL, title, 1, 0,0, 80, 19);
117 	video_draw_box(SINGLE_BOX, MENUATTR_NORMAL, NULL, 0, 0, 19, 80, 6);
118 
119 	/* If we have a menu, draw it too */
120 	if (menu)
121 	{
122 		video_clear_box(1, 3, 78, 15, ' ', MENUATTR_NORMAL);
123 		menu_draw(menu);
124 	}
125 }
126 
menu_draw_current_form(void)127 void menu_draw_current_form(void)
128 {
129 	menu_draw_form(root_form);
130 }
131 
menu_form_switch_menu(form_t * form,char * name)132 void menu_form_switch_menu(form_t *form, char *name)
133 {
134 	menu_t *menu = menu_form_find_menu(form, name);
135 	if (!menu)
136 		return;
137 	menu_form_set_menu(form, menu);
138 }
139 
menu_form_popup(form_t * form,menu_t * menu)140 void menu_form_popup(form_t *form, menu_t* menu)
141 {
142 	if (menu && MENUTYPE_POPUP == menu->type)
143 	{
144 		form->popup_save = form->current_menu;
145 		form->popup_item_save = form->current_menu->current_item;
146 		form->current_menu = menu;
147 		menu_draw(menu);
148 	}
149 }
150 
menu_form_popup_name(form_t * form,char * name)151 void menu_form_popup_name(form_t *form, char *name)
152 {
153 	menu_t *menu = menu_form_find_menu(form, name);
154 	if (!menu)
155 		return;
156 	menu_form_popup(form, menu);
157 }
158 
menu_form_popdown(form_t * form)159 void menu_form_popdown(form_t *form)
160 {
161 	if (form->current_menu && form->current_menu->type == MENUTYPE_POPUP)
162 	{
163 		form->current_menu = form->popup_save;
164 		if (form->current_menu)
165 			form->current_menu->current_item = form->popup_item_save;
166 		video_clear_box(1, 3, 78, 15, ' ', MENUATTR_NORMAL);
167 		if (form->current_menu)
168 			menu_draw(form->current_menu);
169 	}
170 }
171 
menu_set_active_item(menu_t * menu,int nr)172 void menu_set_active_item(menu_t *menu, int nr)
173 {
174 	item_t
175 		*item = (item_t *)(menu->item_list.first);
176 
177 	while (item && nr > 0)
178 	{
179 		nr--;
180 		item = (item_t *)(item->link.next);
181 	}
182 	if (nr == 0)
183 	{
184 		menu->current_item = item;
185 	}
186 }
187 
menu_perform_save(form_t * form)188 static void menu_perform_save(form_t *form)
189 {
190 	menu_t
191 		*menu;
192 
193 	menu = (menu_t *)(form->menu_list.first);
194 	while (menu)
195 	{
196 		item_t
197 			*item;
198 
199 		item = (item_t *)(menu->item_list.first);
200 		while (item)
201 		{
202 			if (item->f_save) item->f_save(menu, item);
203 			item = (item_t *)(item->link.next);
204 		}
205 		menu = (menu_t *)(menu->link.next);
206 	}
207 }
208 
209 static int leave_select = -1;
210 
leave_func(item_t * item,void * dummy,int arg)211 void leave_func(item_t *item, void *dummy, int arg)
212 {
213 	leave_select = arg;
214 }
215 
make_leave_menu(form_t * form)216 menu_t *make_leave_menu(form_t *form)
217 {
218 	menu_t
219 		*menu = new_menu(MENUTYPE_POPUP, "Exit Menu", form, NULL);
220 
221 	if (menu)
222 	{
223 		item_t
224 			*item;
225 		item = menu_item_create(ITEMTYPE_FUNC, menu, "Save settings and exit", leave_func, NULL, EXIT_SAVE_PERMANENT);
226 		item = menu_item_create(ITEMTYPE_FUNC, menu, "Use settings for this session only", leave_func, NULL, EXIT_AND_SAVE);
227 		item = menu_item_create(ITEMTYPE_FUNC, menu, "Leave without saving", leave_func, NULL, EXIT_AND_NO_SAVE);
228 		//item = menu_item_create(ITEMTYPE_FUNC, menu, "Return to menu", leave_func, NULL, EXIT_NOT);
229 		item = menu_item_create(ITEMTYPE_FUNC, menu, "Abort boot and enter U-Boot shell", leave_func, NULL, EXIT_TO_SHELL);
230 	}
231 
232 	menu_form_add_menu(form, menu);
233 
234 	menu_set_position(menu, 6, 6);
235 
236 	return menu;
237 }
238 
239 
menu_handle_single_key(form_t * form,int key)240 bool menu_handle_single_key(form_t *form, int key)
241 {
242 	/*
243 	   Keys below 10 or so are specially mapped by us to mean one of the functions
244 	   of the menu system (like next item, prev item etc). All other keys are verbatim
245 	   keypresses that might be needed for e.g. string entry
246 	*/
247 	item_t
248 				*c_item,
249 				*n_item;
250 	menu_t
251 				*menu = form->current_menu;
252 
253 	switch(key)
254 	{
255 		case KEY_NEXT_ITEM:
256 			/* Move one item forward */
257 			c_item = menu->current_item;
258 			n_item = (item_t *)(c_item->link.next);
259 			while (n_item && n_item->disabled == true)
260 			{
261 				n_item = (item_t *)(n_item->link.next);
262 			}
263 
264 			if (n_item)
265 			{
266 				/* redraw the old item un-highlit */
267 				c_item->f_render(menu, c_item, MENUATTR_ITEM);
268 				n_item->f_render(menu, n_item, MENUATTR_HILITE);
269 				menu_draw_help(n_item);
270 				menu->current_item = n_item;
271 			}
272 			break;
273 		case KEY_PREV_ITEM:
274 			/* Move one item backward */
275 			c_item = menu->current_item;
276 			n_item = (item_t *)(c_item->link.prev);
277 			while (n_item && n_item->disabled == true)
278 			{
279 				n_item = (item_t *)(n_item->link.prev);
280 			}
281 			if (n_item)
282 			{
283 				/* redraw the old item un-highlit */
284 				c_item->f_render(menu, c_item, MENUATTR_ITEM);
285 				n_item->f_render(menu, n_item, MENUATTR_HILITE);
286 				menu_draw_help(n_item);
287 				menu->current_item = n_item;
288 			}
289 			break;
290 		case KEY_ABORT:
291 			if (menu->type == MENUTYPE_POPUP)
292 			{
293 				menu_form_popdown(form);
294 			}
295 			else
296 			{
297 				if (menu->parent_menu)
298 				{
299 					menu_form_switch_menu(menu->parent_form, menu->parent_menu);
300 				}
301 				else
302 				{
303 					/* TODO: Implement exit from menu */
304 					menu_form_popup_name(root_form, "Exit Menu");
305 					return true;
306 				}
307 			}
308 			break;
309 		default:
310 			if (menu->current_item)
311 			{
312 				menu->current_item->f_invoke(menu, menu->current_item, key);
313 			}
314 			if (key == KEY_ACTIVATE && menu->type == MENUTYPE_POPUP)
315 			{
316 				menu_form_popdown(form);
317 				/* Check if we want to exit */
318 				if (leave_select != -1)
319 				{
320 					switch(leave_select)
321 					{
322 						case EXIT_AND_NO_SAVE:
323 							return false;
324 						case EXIT_SAVE_PERMANENT:
325 							menu_perform_save(form);
326 #ifndef SIM
327 							saveenv();
328 #endif
329 							return false;
330 						case EXIT_AND_SAVE:
331 							menu_perform_save(form);
332 							return false;
333 						case EXIT_NOT:
334 							return true;
335 						case EXIT_TO_SHELL:
336 							{
337 								char *mboot = getenv("menuboot_cmd");
338 								if ((mboot) && (strlen(mboot)>2)) SETENV("menuboot_cmd", "noboot");
339 								else SETENV("menuboot_cmd", "boota");
340 								return false;
341 							}
342 					}
343 				}
344 			}
345 			break;
346 	}
347 
348 	return true;
349 }
350 
351 
menu_do(bool do_leave_menu)352 void menu_do(bool do_leave_menu)
353 {
354 	bool running=true;
355 	int key;
356 
357 	running = true;
358 	leave_select = -1;
359 
360 	if (do_leave_menu)
361 		make_leave_menu(root_form);
362 
363 	if (root_form)
364 	{
365 		menu_draw_form(root_form);
366 
367 		while (running)
368 		{
369 			key = video_get_key();
370 			running = menu_handle_single_key(root_form, key);
371 		}
372 	}
373 }
374 
375