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
33 #include "backlight.h"
41 #include "settings_list.h"
42 #include "option_select.h"
49 #include "menus/exported_menus.h"
51 #include "root_menu.h"
53 #include "gwps-common.h" /* for fade() */
56 #include "quickscreen.h"
58 #ifdef HAVE_LCD_BITMAP
64 #include "statusbar.h"
65 #include "buttonbar.h"
68 /* used to allow for dynamic menus */
69 #define MAX_MENU_SUBITEMS 64
70 static struct menu_item_ex
*current_submenus_menu
;
71 static int current_subitems
[MAX_MENU_SUBITEMS
];
72 static int current_subitems_count
= 0;
73 static int talk_menu_item(int selected_item
, void *data
);
75 static void get_menu_callback(const struct menu_item_ex
*m
,
76 menu_callback_type
*menu_callback
)
78 if (m
->flags
&(MENU_HAS_DESC
|MENU_DYNAMIC_DESC
))
79 *menu_callback
= m
->callback_and_desc
->menu_callback
;
81 *menu_callback
= m
->menu_callback
;
84 static int get_menu_selection(int selected_item
, const struct menu_item_ex
*menu
)
86 int type
= (menu
->flags
&MENU_TYPE_MASK
);
87 if (type
== MT_MENU
&& (selected_item
<current_subitems_count
))
88 return current_subitems
[selected_item
];
91 static int find_menu_selection(int selected
)
94 for (i
=0; i
< current_subitems_count
; i
++)
95 if (current_subitems
[i
] == selected
)
99 static char * get_menu_item_name(int selected_item
,
104 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
105 int type
= (menu
->flags
&MENU_TYPE_MASK
);
106 selected_item
= get_menu_selection(selected_item
, menu
);
109 /* only MT_MENU or MT_RETURN_ID is allowed in here */
110 if (type
== MT_RETURN_ID
)
112 if (menu
->flags
&MENU_DYNAMIC_DESC
)
113 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
114 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
115 return (char*)menu
->strings
[selected_item
];
118 menu
= menu
->submenus
[selected_item
];
120 if ((menu
->flags
&MENU_DYNAMIC_DESC
) && (type
!= MT_SETTING_W_TEXT
))
121 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
122 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
124 type
= (menu
->flags
&MENU_TYPE_MASK
);
125 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
127 const struct settings_list
*v
128 = find_setting(menu
->variable
, NULL
);
130 return str(v
->lang_id
);
131 else return "Not Done yet!";
133 return P2STR(menu
->callback_and_desc
->desc
);
135 #ifdef HAVE_LCD_BITMAP
136 static int menu_get_icon(int selected_item
, void * data
)
138 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
139 int menu_icon
= Icon_NOICON
;
140 selected_item
= get_menu_selection(selected_item
, menu
);
142 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
)
144 return Icon_Menu_functioncall
;
146 menu
= menu
->submenus
[selected_item
];
147 if (menu
->flags
&MENU_HAS_DESC
)
148 menu_icon
= menu
->callback_and_desc
->icon_id
;
149 else if (menu
->flags
&MENU_DYNAMIC_DESC
)
150 menu_icon
= menu
->menu_get_name_and_icon
->icon_id
;
152 if (menu_icon
== Icon_NOICON
)
154 switch (menu
->flags
&MENU_TYPE_MASK
)
157 case MT_SETTING_W_TEXT
:
158 menu_icon
= Icon_Menu_setting
;
161 menu_icon
= Icon_Submenu
;
163 case MT_FUNCTION_CALL
:
164 case MT_RETURN_VALUE
:
165 menu_icon
= Icon_Menu_functioncall
;
173 static void init_menu_lists(const struct menu_item_ex
*menu
,
174 struct gui_synclist
*lists
, int selected
, bool callback
,
175 struct viewport parent
[NB_SCREENS
])
177 int i
, count
= MENU_GET_COUNT(menu
->flags
);
178 int type
= (menu
->flags
&MENU_TYPE_MASK
);
179 menu_callback_type menu_callback
= NULL
;
181 current_subitems_count
= 0;
183 if (type
== MT_RETURN_ID
)
184 get_menu_callback(menu
, &menu_callback
);
186 for (i
=0; i
<count
; i
++)
188 if (type
!= MT_RETURN_ID
)
189 get_menu_callback(menu
->submenus
[i
],&menu_callback
);
192 if (menu_callback(ACTION_REQUEST_MENUITEM
,
193 type
==MT_RETURN_ID
? (void*)(intptr_t)i
: menu
->submenus
[i
])
194 != ACTION_EXIT_MENUITEM
)
196 current_subitems
[current_subitems_count
] = i
;
197 current_subitems_count
++;
202 current_subitems
[current_subitems_count
] = i
;
203 current_subitems_count
++;
206 current_submenus_menu
= (struct menu_item_ex
*)menu
;
208 gui_synclist_init(lists
,get_menu_item_name
,(void*)menu
,false,1, parent
);
209 #ifdef HAVE_LCD_BITMAP
210 if (menu
->callback_and_desc
->icon_id
== Icon_NOICON
)
211 icon
= Icon_Submenu_Entered
;
213 icon
= menu
->callback_and_desc
->icon_id
;
214 gui_synclist_set_title(lists
, P2STR(menu
->callback_and_desc
->desc
), icon
);
215 gui_synclist_set_icon_callback(lists
, menu_get_icon
);
218 gui_synclist_set_icon_callback(lists
, NULL
);
220 if(global_settings
.talk_menu
)
221 gui_synclist_set_voice_callback(lists
, talk_menu_item
);
222 gui_synclist_set_nb_items(lists
,current_subitems_count
);
223 gui_synclist_limit_scroll(lists
,true);
224 gui_synclist_select_item(lists
, find_menu_selection(selected
));
226 get_menu_callback(menu
,&menu_callback
);
227 if (callback
&& menu_callback
)
228 menu_callback(ACTION_ENTER_MENUITEM
,menu
);
229 gui_synclist_draw(lists
);
230 gui_synclist_speak_item(lists
);
233 static int talk_menu_item(int selected_item
, void *data
)
235 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
239 int sel
= get_menu_selection(selected_item
, menu
);
241 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
243 type
= menu
->submenus
[sel
]->flags
&MENU_TYPE_MASK
;
244 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
245 talk_setting(menu
->submenus
[sel
]->variable
);
248 if (menu
->submenus
[sel
]->flags
&(MENU_DYNAMIC_DESC
))
250 int (*list_speak_item
)(int selected_item
, void * data
)
251 = menu
->submenus
[sel
]->menu_get_name_and_icon
->
254 list_speak_item(sel
, menu
->submenus
[sel
]->
255 menu_get_name_and_icon
->
260 str
= menu
->submenus
[sel
]->menu_get_name_and_icon
->
261 list_get_name(sel
, menu
->submenus
[sel
]->
262 menu_get_name_and_icon
->
263 list_get_name_data
, buffer
);
268 id
= P2ID(menu
->submenus
[sel
]->callback_and_desc
->desc
);
273 else if(((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
))
275 if ((menu
->flags
&MENU_DYNAMIC_DESC
) == 0)
277 unsigned char *s
= (unsigned char *)menu
->strings
[sel
];
278 /* string list, try to talk it if ID2P was used */
286 /* this is used to reload the default menu viewports when the
287 theme changes. nothing happens if the menu is using a supplied parent vp */
288 static void init_default_menu_viewports(struct viewport parent
[NB_SCREENS
], bool hide_bars
)
293 viewport_set_defaults(&parent
[i
], i
);
294 /* viewport_set_defaults() fixes the vp for the bars, so resize */
297 if (global_settings
.statusbar
)
299 parent
[i
].y
-= STATUSBAR_HEIGHT
;
300 parent
[i
].height
+= STATUSBAR_HEIGHT
;
304 #ifdef HAVE_BUTTONBAR
305 if (!hide_bars
&& global_settings
.buttonbar
)
306 parent
[0].height
-= BUTTONBAR_HEIGHT
;
310 bool do_setting_from_menu(const struct menu_item_ex
*temp
,
311 struct viewport parent
[NB_SCREENS
])
313 int setting_id
, oldval
;
314 const struct settings_list
*setting
= find_setting(
318 char padded_title
[MAX_PATH
];
319 int var_type
= setting
->flags
&F_T_MASK
;
320 if (var_type
== F_T_INT
|| var_type
== F_T_UINT
)
322 oldval
= *(int*)setting
->setting
;
324 else if (var_type
== F_T_BOOL
)
326 oldval
= *(bool*)setting
->setting
;
330 if ((temp
->flags
&MENU_TYPE_MASK
) == MT_SETTING_W_TEXT
)
331 title
= temp
->callback_and_desc
->desc
;
333 title
= ID2P(setting
->lang_id
);
335 /* Pad the title string by repeating it. This is needed
336 so the scroll settings title can actually be used to
338 if (setting
->flags
&F_PADTITLE
)
341 if (setting
->lang_id
== -1)
342 title
= (char*)setting
->cfg_vals
;
344 title
= P2STR((unsigned char*)title
);
346 while (i
< MAX_PATH
-1)
348 int padlen
= MIN(len
, MAX_PATH
-1-i
);
349 strncpy(&padded_title
[i
], title
, padlen
);
352 padded_title
[i
++] = ' ';
354 padded_title
[i
] = '\0';
355 title
= padded_title
;
358 option_screen((struct settings_list
*)setting
, parent
,
359 setting
->flags
&F_TEMPVAR
, title
);
360 if (var_type
== F_T_INT
|| var_type
== F_T_UINT
)
362 return oldval
!= *(int*)setting
->setting
;
364 else if (var_type
== F_T_BOOL
)
366 return oldval
!= *(bool*)setting
->setting
;
372 int do_menu(const struct menu_item_ex
*start_menu
, int *start_selected
,
373 struct viewport parent
[NB_SCREENS
], bool hide_bars
)
375 int selected
= start_selected
? *start_selected
: 0;
377 struct gui_synclist lists
;
378 const struct menu_item_ex
*temp
, *menu
;
382 const struct menu_item_ex
*menu_stack
[MAX_MENUS
];
383 int menu_stack_selected_item
[MAX_MENUS
];
385 bool in_stringlist
, done
= false;
387 struct viewport
*vps
, menu_vp
[NB_SCREENS
]; /* menu_vp will hopefully be phased out */
388 #ifdef HAVE_BUTTONBAR
389 struct gui_buttonbar buttonbar
;
390 gui_buttonbar_init(&buttonbar
);
391 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
392 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
395 menu_callback_type menu_callback
= NULL
;
396 if (start_menu
== NULL
)
398 else menu
= start_menu
;
400 init_default_menu_viewports(menu_vp
, hide_bars
);
405 /* if hide_bars == true we assume the viewport is correctly sized */
413 screens
[i
].set_viewport(&vps
[i
]);
414 screens
[i
].clear_viewport();
415 screens
[i
].set_viewport(NULL
);
417 init_menu_lists(menu
, &lists
, selected
, true, vps
);
418 in_stringlist
= ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
);
420 /* load the callback, and only reload it if menu changes */
421 get_menu_callback(menu
, &menu_callback
);
424 #ifdef HAVE_BUTTONBAR
427 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
428 gui_buttonbar_draw(&buttonbar
);
433 redraw_lists
= false;
436 gui_syncstatusbar_draw(&statusbars
, true);
438 action
= get_action(CONTEXT_MAINMENU
,
439 list_do_action_timeout(&lists
, HZ
));
440 /* HZ so the status bar redraws corectly */
444 int old_action
= action
;
445 action
= menu_callback(action
, menu
);
446 if (action
== ACTION_EXIT_AFTER_THIS_MENUITEM
)
449 ret
= MENU_SELECTED_EXIT
; /* will exit after returning
452 else if (action
== ACTION_REDRAW
)
459 if (gui_synclist_do_button(&lists
, &action
, LIST_WRAP_UNLESS_HELD
))
461 if (action
== ACTION_NONE
)
463 #ifdef HAVE_QUICKSCREEN
464 else if (action
== ACTION_STD_QUICKSCREEN
)
466 quick_screen_quick(action
);
470 #ifdef HAVE_RECORDING
471 else if (action
== ACTION_STD_REC
)
473 ret
= GO_TO_RECSCREEN
;
477 else if (action
== ACTION_TREE_WPS
)
479 ret
= GO_TO_PREVIOUS_MUSIC
;
482 else if (action
== ACTION_TREE_STOP
)
484 redraw_lists
= list_stop_handler();
486 else if (action
== ACTION_STD_CONTEXT
)
488 if (menu
== &root_menu_
)
490 ret
= GO_TO_ROOTITEM_CONTEXT
;
493 else if (!in_stringlist
)
496 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
497 temp
= menu
->submenus
[selected
];
498 type
= (temp
->flags
&MENU_TYPE_MASK
);
499 if ((type
== MT_SETTING_W_TEXT
|| type
== MT_SETTING
))
501 #ifdef HAVE_QUICKSCREEN
502 MENUITEM_STRINGLIST(quickscreen_able_option
,
503 ID2P(LANG_ONPLAY_MENU_TITLE
), NULL
,
504 ID2P(LANG_RESET_SETTING
),
505 ID2P(LANG_LEFT_QS_ITEM
),
506 ID2P(LANG_BOTTOM_QS_ITEM
),
507 ID2P(LANG_RIGHT_QS_ITEM
));
509 MENUITEM_STRINGLIST(notquickscreen_able_option
,
510 ID2P(LANG_ONPLAY_MENU_TITLE
), NULL
,
511 ID2P(LANG_RESET_SETTING
));
512 const struct menu_item_ex
*menu
;
513 int menu_selection
= 0;
514 const struct settings_list
*setting
=
515 find_setting(temp
->variable
, NULL
);
516 #ifdef HAVE_QUICKSCREEN
517 if (is_setting_quickscreenable(setting
))
518 menu
= &quickscreen_able_option
;
521 menu
= ¬quickscreen_able_option
;
522 switch (do_menu(menu
, &menu_selection
, NULL
, false))
526 case 0: /* reset setting */
527 reset_setting(setting
, setting
->setting
);
529 #ifdef HAVE_QUICKSCREEN
531 case 1: /* set as left QS item */
532 set_as_qs_item(setting
, QUICKSCREEN_LEFT
);
534 case 2: /* set as bottom QS item */
535 set_as_qs_item(setting
, QUICKSCREEN_BOTTOM
);
537 case 3: /* set as right QS item */
538 set_as_qs_item(setting
, QUICKSCREEN_RIGHT
);
541 } /* swicth(do_menu()) */
544 } /* else if (!in_stringlist) */
546 else if (action
== ACTION_STD_MENU
)
548 if (menu
!= &root_menu_
)
551 ret
= GO_TO_PREVIOUS
;
554 else if (action
== ACTION_STD_CANCEL
)
556 bool exiting_menu
= false;
557 in_stringlist
= false;
558 /* might be leaving list, so stop scrolling */
561 screens
[i
].stop_scroll();
564 menu_callback(ACTION_EXIT_MENUITEM
, menu
);
566 if (menu
->flags
&MENU_EXITAFTERTHISMENU
)
568 else if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
573 menu
= menu_stack
[stack_top
];
574 if (!exiting_menu
&& (menu
->flags
&MENU_EXITAFTERTHISMENU
))
577 init_menu_lists(menu
, &lists
,
578 menu_stack_selected_item
[stack_top
], false, vps
);
579 /* new menu, so reload the callback */
580 get_menu_callback(menu
, &menu_callback
);
582 else if (menu
!= &root_menu_
)
584 ret
= GO_TO_PREVIOUS
;
588 else if (action
== ACTION_STD_OK
)
591 /* entering an item that may not be a list, so stop scrolling */
594 screens
[i
].stop_scroll();
596 #ifdef HAVE_BUTTONBAR
599 gui_buttonbar_unset(&buttonbar
);
600 gui_buttonbar_draw(&buttonbar
);
603 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
604 temp
= menu
->submenus
[selected
];
607 type
= (menu
->flags
&MENU_TYPE_MASK
);
610 type
= (temp
->flags
&MENU_TYPE_MASK
);
611 get_menu_callback(temp
, &menu_callback
);
614 action
= menu_callback(ACTION_ENTER_MENUITEM
,temp
);
615 if (action
== ACTION_EXIT_MENUITEM
)
622 if (stack_top
< MAX_MENUS
)
624 menu_stack
[stack_top
] = menu
;
625 menu_stack_selected_item
[stack_top
] = selected
;
627 init_menu_lists(temp
, &lists
, 0, true, vps
);
628 redraw_lists
= false; /* above does the redraw */
632 case MT_FUNCTION_CALL
:
635 if (temp
->flags
&MENU_FUNC_USEPARAM
)
636 return_value
= temp
->function
->function_w_param(
637 temp
->function
->param
);
639 return_value
= temp
->function
->function();
640 if (!(menu
->flags
&MENU_EXITAFTERTHISMENU
) || (temp
->flags
&MENU_EXITAFTERTHISMENU
))
642 init_menu_lists(menu
, &lists
, selected
, true, vps
);
644 if (temp
->flags
&MENU_FUNC_CHECK_RETVAL
)
646 if (return_value
!= 0)
655 case MT_SETTING_W_TEXT
:
657 if (do_setting_from_menu(temp
, menu_vp
))
659 init_menu_lists(menu
, &lists
, selected
, true,vps
);
660 redraw_lists
= false; /* above does the redraw */
670 else if (stack_top
< MAX_MENUS
)
672 menu_stack
[stack_top
] = menu
;
673 menu_stack_selected_item
[stack_top
] = selected
;
676 init_menu_lists(menu
,&lists
,0,false, vps
);
677 redraw_lists
= false; /* above does the redraw */
678 in_stringlist
= true;
681 case MT_RETURN_VALUE
:
689 menu_callback(ACTION_EXIT_MENUITEM
,temp
);
691 if (current_submenus_menu
!= menu
)
692 init_menu_lists(menu
,&lists
,selected
,true,vps
);
693 /* callback was changed, so reload the menu's callback */
694 get_menu_callback(menu
, &menu_callback
);
695 if ((menu
->flags
&MENU_EXITAFTERTHISMENU
) &&
696 !(temp
->flags
&MENU_EXITAFTERTHISMENU
))
701 #ifdef HAVE_BUTTONBAR
704 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
705 gui_buttonbar_draw(&buttonbar
);
709 else if(default_event_handler(action
) == SYS_USB_CONNECTED
)
711 ret
= MENU_ATTACHED_USB
;
715 if (redraw_lists
&& !done
)
718 menu_callback(ACTION_REDRAW
, menu
);
719 gui_synclist_draw(&lists
);
720 gui_synclist_speak_item(&lists
);
725 /* make sure the start_selected variable is set to
726 the selected item from the menu do_menu() was called from */
729 menu
= menu_stack
[0];
730 init_menu_lists(menu
,&lists
,menu_stack_selected_item
[0],true, vps
);
732 *start_selected
= get_menu_selection(
733 gui_synclist_get_sel_pos(&lists
), menu
);