1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Robert E. Hak
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 - Multi screen support
24 - Rewrote/removed a lot of code now useless with the new gui API
40 #include "settings_list.h"
41 #include "option_select.h"
47 #include "menus/exported_menus.h"
49 #include "root_menu.h"
52 #include "quickscreen.h"
54 #ifdef HAVE_LCD_BITMAP
60 #include "buttonbar.h"
63 /* used to allow for dynamic menus */
64 #define MAX_MENU_SUBITEMS 64
65 static struct menu_item_ex
*current_submenus_menu
;
66 static int current_subitems
[MAX_MENU_SUBITEMS
];
67 static int current_subitems_count
= 0;
68 static int talk_menu_item(int selected_item
, void *data
);
70 static void get_menu_callback(const struct menu_item_ex
*m
,
71 menu_callback_type
*menu_callback
)
73 if (m
->flags
&(MENU_HAS_DESC
|MENU_DYNAMIC_DESC
))
74 *menu_callback
= m
->callback_and_desc
->menu_callback
;
76 *menu_callback
= m
->menu_callback
;
79 static int get_menu_selection(int selected_item
, const struct menu_item_ex
*menu
)
81 int type
= (menu
->flags
&MENU_TYPE_MASK
);
82 if ((type
== MT_MENU
|| type
== MT_RETURN_ID
)
83 && (selected_item
<current_subitems_count
))
84 return current_subitems
[selected_item
];
87 static int find_menu_selection(int selected
)
90 for (i
=0; i
< current_subitems_count
; i
++)
91 if (current_subitems
[i
] == selected
)
95 static char * get_menu_item_name(int selected_item
,
100 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
101 int type
= (menu
->flags
&MENU_TYPE_MASK
);
102 selected_item
= get_menu_selection(selected_item
, menu
);
105 /* only MT_MENU or MT_RETURN_ID is allowed in here */
106 if (type
== MT_RETURN_ID
)
108 if (menu
->flags
&MENU_DYNAMIC_DESC
)
109 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
110 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
111 return (char*)menu
->strings
[selected_item
];
114 menu
= menu
->submenus
[selected_item
];
116 if ((menu
->flags
&MENU_DYNAMIC_DESC
) && (type
!= MT_SETTING_W_TEXT
))
117 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
118 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
120 type
= (menu
->flags
&MENU_TYPE_MASK
);
121 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
123 const struct settings_list
*v
124 = find_setting(menu
->variable
, NULL
);
126 return str(v
->lang_id
);
127 else return "Not Done yet!";
129 return P2STR(menu
->callback_and_desc
->desc
);
131 #ifdef HAVE_LCD_BITMAP
132 static enum themable_icons
menu_get_icon(int selected_item
, void * data
)
134 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
135 int menu_icon
= Icon_NOICON
;
136 selected_item
= get_menu_selection(selected_item
, menu
);
138 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
)
140 return Icon_Menu_functioncall
;
142 menu
= menu
->submenus
[selected_item
];
143 if (menu
->flags
&MENU_HAS_DESC
)
144 menu_icon
= menu
->callback_and_desc
->icon_id
;
145 else if (menu
->flags
&MENU_DYNAMIC_DESC
)
146 menu_icon
= menu
->menu_get_name_and_icon
->icon_id
;
148 if (menu_icon
== Icon_NOICON
)
150 switch (menu
->flags
&MENU_TYPE_MASK
)
153 case MT_SETTING_W_TEXT
:
154 menu_icon
= Icon_Menu_setting
;
157 menu_icon
= Icon_Submenu
;
159 case MT_FUNCTION_CALL
:
160 case MT_RETURN_VALUE
:
161 menu_icon
= Icon_Menu_functioncall
;
169 static void init_menu_lists(const struct menu_item_ex
*menu
,
170 struct gui_synclist
*lists
, int selected
, bool callback
,
171 struct viewport parent
[NB_SCREENS
])
173 int i
, count
= MENU_GET_COUNT(menu
->flags
);
174 int type
= (menu
->flags
&MENU_TYPE_MASK
);
175 menu_callback_type menu_callback
= NULL
;
177 current_subitems_count
= 0;
179 if (type
== MT_RETURN_ID
)
180 get_menu_callback(menu
, &menu_callback
);
182 for (i
=0; i
<count
; i
++)
184 if (type
!= MT_RETURN_ID
)
185 get_menu_callback(menu
->submenus
[i
],&menu_callback
);
188 if (menu_callback(ACTION_REQUEST_MENUITEM
,
189 type
==MT_RETURN_ID
? (void*)(intptr_t)i
: menu
->submenus
[i
])
190 != ACTION_EXIT_MENUITEM
)
192 current_subitems
[current_subitems_count
] = i
;
193 current_subitems_count
++;
198 current_subitems
[current_subitems_count
] = i
;
199 current_subitems_count
++;
202 current_submenus_menu
= (struct menu_item_ex
*)menu
;
204 gui_synclist_init(lists
,get_menu_item_name
,(void*)menu
,false,1, parent
);
205 #ifdef HAVE_LCD_BITMAP
206 if (menu
->callback_and_desc
->icon_id
== Icon_NOICON
)
207 icon
= Icon_Submenu_Entered
;
209 icon
= menu
->callback_and_desc
->icon_id
;
210 gui_synclist_set_title(lists
, P2STR(menu
->callback_and_desc
->desc
), icon
);
211 gui_synclist_set_icon_callback(lists
, menu_get_icon
);
214 gui_synclist_set_icon_callback(lists
, NULL
);
216 if(global_settings
.talk_menu
)
217 gui_synclist_set_voice_callback(lists
, talk_menu_item
);
218 gui_synclist_set_nb_items(lists
,current_subitems_count
);
219 gui_synclist_limit_scroll(lists
,true);
220 gui_synclist_select_item(lists
, find_menu_selection(selected
));
222 get_menu_callback(menu
,&menu_callback
);
223 if (callback
&& menu_callback
)
224 menu_callback(ACTION_ENTER_MENUITEM
,menu
);
225 gui_synclist_draw(lists
);
226 gui_synclist_speak_item(lists
);
229 static int talk_menu_item(int selected_item
, void *data
)
231 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
235 int sel
= get_menu_selection(selected_item
, menu
);
237 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
239 type
= menu
->submenus
[sel
]->flags
&MENU_TYPE_MASK
;
240 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
241 talk_setting(menu
->submenus
[sel
]->variable
);
244 if (menu
->submenus
[sel
]->flags
&(MENU_DYNAMIC_DESC
))
246 int (*list_speak_item
)(int selected_item
, void * data
)
247 = menu
->submenus
[sel
]->menu_get_name_and_icon
->
250 list_speak_item(sel
, menu
->submenus
[sel
]->
251 menu_get_name_and_icon
->
256 str
= menu
->submenus
[sel
]->menu_get_name_and_icon
->
257 list_get_name(sel
, menu
->submenus
[sel
]->
258 menu_get_name_and_icon
->
259 list_get_name_data
, buffer
);
264 id
= P2ID(menu
->submenus
[sel
]->callback_and_desc
->desc
);
269 else if(((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
))
271 if ((menu
->flags
&MENU_DYNAMIC_DESC
) == 0)
273 unsigned char *s
= (unsigned char *)menu
->strings
[sel
];
274 /* string list, try to talk it if ID2P was used */
283 void do_setting_from_menu(const struct menu_item_ex
*temp
,
284 struct viewport parent
[NB_SCREENS
])
286 int setting_id
, oldval
;
287 const struct settings_list
*setting
= find_setting(
291 char padded_title
[MAX_PATH
];
292 int var_type
= setting
->flags
&F_T_MASK
;
293 if (var_type
== F_T_INT
|| var_type
== F_T_UINT
)
295 oldval
= *(int*)setting
->setting
;
297 else if (var_type
== F_T_BOOL
)
299 oldval
= *(bool*)setting
->setting
;
303 if ((temp
->flags
&MENU_TYPE_MASK
) == MT_SETTING_W_TEXT
)
304 title
= temp
->callback_and_desc
->desc
;
306 title
= ID2P(setting
->lang_id
);
308 /* Pad the title string by repeating it. This is needed
309 so the scroll settings title can actually be used to
311 if (setting
->flags
&F_PADTITLE
)
314 if (setting
->lang_id
== -1)
315 title
= (char*)setting
->cfg_vals
;
317 title
= P2STR((unsigned char*)title
);
319 while (i
< MAX_PATH
-1)
321 int padlen
= MIN(len
, MAX_PATH
-1-i
);
322 memcpy(&padded_title
[i
], title
, padlen
);
325 padded_title
[i
++] = ' ';
327 padded_title
[i
] = '\0';
328 title
= padded_title
;
331 option_screen((struct settings_list
*)setting
, parent
,
332 setting
->flags
&F_TEMPVAR
, title
);
336 int do_menu(const struct menu_item_ex
*start_menu
, int *start_selected
,
337 struct viewport parent
[NB_SCREENS
], bool hide_bars
)
339 int selected
= start_selected
? *start_selected
: 0;
341 struct gui_synclist lists
;
342 const struct menu_item_ex
*temp
, *menu
;
345 int oldbars
= viewportmanager_get_statusbar();
346 viewportmanager_set_statusbar(hide_bars
? VP_SB_HIDE_ALL
: oldbars
);
348 const struct menu_item_ex
*menu_stack
[MAX_MENUS
];
349 int menu_stack_selected_item
[MAX_MENUS
];
351 bool in_stringlist
, done
= false;
352 struct viewport
*vps
= NULL
;
353 #ifdef HAVE_BUTTONBAR
354 struct gui_buttonbar buttonbar
;
355 gui_buttonbar_init(&buttonbar
);
356 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
357 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
360 menu_callback_type menu_callback
= NULL
;
361 if (start_menu
== NULL
)
363 else menu
= start_menu
;
365 /* if hide_bars is true, assume parent has been fixed before passed into
366 * this function, e.g. with viewport_set_defaults(parent, screen) */
367 init_menu_lists(menu
, &lists
, selected
, true, parent
);
368 vps
= *(lists
.parent
);
369 in_stringlist
= ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
);
370 /* load the callback, and only reload it if menu changes */
371 get_menu_callback(menu
, &menu_callback
);
374 #ifdef HAVE_BUTTONBAR
377 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
378 gui_buttonbar_draw(&buttonbar
);
383 redraw_lists
= false;
386 #ifdef HAVE_BUTTONBAR
387 gui_buttonbar_draw(&buttonbar
);
390 action
= get_action(CONTEXT_MAINMENU
,
391 list_do_action_timeout(&lists
, HZ
));
392 /* HZ so the status bar redraws corectly */
396 int old_action
= action
;
397 action
= menu_callback(action
, menu
);
398 if (action
== ACTION_EXIT_AFTER_THIS_MENUITEM
)
401 ret
= MENU_SELECTED_EXIT
; /* will exit after returning
404 else if (action
== ACTION_REDRAW
)
411 if (gui_synclist_do_button(&lists
, &action
, LIST_WRAP_UNLESS_HELD
))
413 if (action
== ACTION_NONE
)
415 #ifdef HAVE_QUICKSCREEN
416 else if (action
== ACTION_STD_QUICKSCREEN
)
418 quick_screen_quick(action
);
422 #ifdef HAVE_RECORDING
423 else if (action
== ACTION_STD_REC
)
425 ret
= GO_TO_RECSCREEN
;
429 else if (action
== ACTION_TREE_WPS
)
431 ret
= GO_TO_PREVIOUS_MUSIC
;
434 else if (action
== ACTION_TREE_STOP
)
436 redraw_lists
= list_stop_handler();
438 else if (action
== ACTION_STD_CONTEXT
)
440 if (menu
== &root_menu_
)
442 ret
= GO_TO_ROOTITEM_CONTEXT
;
445 else if (!in_stringlist
)
448 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
),menu
);
449 temp
= menu
->submenus
[selected
];
450 type
= (temp
->flags
&MENU_TYPE_MASK
);
451 if ((type
== MT_SETTING_W_TEXT
|| type
== MT_SETTING
))
453 #ifdef HAVE_QUICKSCREEN
454 MENUITEM_STRINGLIST(quickscreen_able_option
,
455 ID2P(LANG_ONPLAY_MENU_TITLE
), NULL
,
456 ID2P(LANG_RESET_SETTING
),
457 ID2P(LANG_LEFT_QS_ITEM
),
458 ID2P(LANG_BOTTOM_QS_ITEM
),
459 ID2P(LANG_RIGHT_QS_ITEM
));
461 MENUITEM_STRINGLIST(notquickscreen_able_option
,
462 ID2P(LANG_ONPLAY_MENU_TITLE
), NULL
,
463 ID2P(LANG_RESET_SETTING
));
464 const struct menu_item_ex
*menu
;
465 int menu_selection
= 0;
466 const struct settings_list
*setting
=
467 find_setting(temp
->variable
, NULL
);
468 #ifdef HAVE_QUICKSCREEN
469 if (is_setting_quickscreenable(setting
))
470 menu
= &quickscreen_able_option
;
473 menu
= ¬quickscreen_able_option
;
474 switch (do_menu(menu
, &menu_selection
, NULL
, false))
478 case 0: /* reset setting */
479 reset_setting(setting
, setting
->setting
);
481 #ifdef HAVE_QUICKSCREEN
483 case 1: /* set as left QS item */
484 set_as_qs_item(setting
, QUICKSCREEN_LEFT
);
486 case 2: /* set as bottom QS item */
487 set_as_qs_item(setting
, QUICKSCREEN_BOTTOM
);
489 case 3: /* set as right QS item */
490 set_as_qs_item(setting
, QUICKSCREEN_RIGHT
);
493 } /* swicth(do_menu()) */
496 } /* else if (!in_stringlist) */
498 else if (action
== ACTION_STD_MENU
)
500 if (menu
!= &root_menu_
)
503 ret
= GO_TO_PREVIOUS
;
506 else if (action
== ACTION_STD_CANCEL
)
508 bool exiting_menu
= false;
509 in_stringlist
= false;
510 /* might be leaving list, so stop scrolling */
513 screens
[i
].stop_scroll();
516 menu_callback(ACTION_EXIT_MENUITEM
, menu
);
518 if (menu
->flags
&MENU_EXITAFTERTHISMENU
)
520 else if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
525 menu
= menu_stack
[stack_top
];
526 if (!exiting_menu
&& (menu
->flags
&MENU_EXITAFTERTHISMENU
))
529 init_menu_lists(menu
, &lists
,
530 menu_stack_selected_item
[stack_top
], false, vps
);
531 /* new menu, so reload the callback */
532 get_menu_callback(menu
, &menu_callback
);
534 else if (menu
!= &root_menu_
)
536 ret
= GO_TO_PREVIOUS
;
540 else if (action
== ACTION_STD_OK
)
543 /* entering an item that may not be a list, so stop scrolling */
546 screens
[i
].stop_scroll();
548 #ifdef HAVE_BUTTONBAR
551 gui_buttonbar_unset(&buttonbar
);
552 gui_buttonbar_draw(&buttonbar
);
555 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
556 temp
= menu
->submenus
[selected
];
559 type
= (menu
->flags
&MENU_TYPE_MASK
);
562 type
= (temp
->flags
&MENU_TYPE_MASK
);
563 get_menu_callback(temp
, &menu_callback
);
566 action
= menu_callback(ACTION_ENTER_MENUITEM
,temp
);
567 if (action
== ACTION_EXIT_MENUITEM
)
574 if (stack_top
< MAX_MENUS
)
576 menu_stack
[stack_top
] = menu
;
577 menu_stack_selected_item
[stack_top
] = selected
;
579 init_menu_lists(temp
, &lists
, 0, true, vps
);
580 redraw_lists
= false; /* above does the redraw */
584 case MT_FUNCTION_CALL
:
587 if (temp
->flags
&MENU_FUNC_USEPARAM
)
588 return_value
= temp
->function
->function_w_param(
589 temp
->function
->param
);
591 return_value
= temp
->function
->function();
592 if (!(menu
->flags
&MENU_EXITAFTERTHISMENU
) ||
593 (temp
->flags
&MENU_EXITAFTERTHISMENU
))
595 init_menu_lists(menu
, &lists
, selected
, true, vps
);
597 if (temp
->flags
&MENU_FUNC_CHECK_RETVAL
)
599 if (return_value
!= 0)
608 case MT_SETTING_W_TEXT
:
610 do_setting_from_menu(temp
, vps
);
619 else if (stack_top
< MAX_MENUS
)
621 menu_stack
[stack_top
] = menu
;
622 menu_stack_selected_item
[stack_top
] = selected
;
625 init_menu_lists(menu
,&lists
,0,false, vps
);
626 redraw_lists
= false; /* above does the redraw */
627 in_stringlist
= true;
630 case MT_RETURN_VALUE
:
638 menu_callback(ACTION_EXIT_MENUITEM
,temp
);
640 if (current_submenus_menu
!= menu
)
641 init_menu_lists(menu
,&lists
,selected
,true,vps
);
642 /* callback was changed, so reload the menu's callback */
643 get_menu_callback(menu
, &menu_callback
);
644 if ((menu
->flags
&MENU_EXITAFTERTHISMENU
) &&
645 !(temp
->flags
&MENU_EXITAFTERTHISMENU
))
650 #ifdef HAVE_BUTTONBAR
653 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
654 gui_buttonbar_draw(&buttonbar
);
658 else if(default_event_handler(action
) == SYS_USB_CONNECTED
)
660 ret
= MENU_ATTACHED_USB
;
664 if (redraw_lists
&& !done
)
667 menu_callback(ACTION_REDRAW
, menu
);
668 gui_synclist_draw(&lists
);
669 gui_synclist_speak_item(&lists
);
674 /* make sure the start_selected variable is set to
675 the selected item from the menu do_menu() was called from */
678 menu
= menu_stack
[0];
679 init_menu_lists(menu
,&lists
,menu_stack_selected_item
[0],true, vps
);
681 *start_selected
= get_menu_selection(
682 gui_synclist_get_sel_pos(&lists
), menu
);
684 viewportmanager_set_statusbar(oldbars
);