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
31 #include "appevents.h"
42 #include "settings_list.h"
43 #include "option_select.h"
49 #include "menus/exported_menus.h"
51 #include "root_menu.h"
54 #include "quickscreen.h"
55 #include "shortcuts.h"
57 #ifdef HAVE_LCD_BITMAP
63 #include "buttonbar.h"
66 /* used to allow for dynamic menus */
67 #define MAX_MENU_SUBITEMS 64
68 static struct menu_item_ex
*current_submenus_menu
;
69 static int current_subitems
[MAX_MENU_SUBITEMS
];
70 static int current_subitems_count
= 0;
71 static int talk_menu_item(int selected_item
, void *data
);
73 static void get_menu_callback(const struct menu_item_ex
*m
,
74 menu_callback_type
*menu_callback
)
76 if (m
->flags
&(MENU_HAS_DESC
|MENU_DYNAMIC_DESC
))
77 *menu_callback
= m
->callback_and_desc
->menu_callback
;
79 *menu_callback
= m
->menu_callback
;
82 static int get_menu_selection(int selected_item
, const struct menu_item_ex
*menu
)
84 int type
= (menu
->flags
&MENU_TYPE_MASK
);
85 if ((type
== MT_MENU
|| type
== MT_RETURN_ID
)
86 && (selected_item
<current_subitems_count
))
87 return current_subitems
[selected_item
];
90 static int find_menu_selection(int selected
)
93 for (i
=0; i
< current_subitems_count
; i
++)
94 if (current_subitems
[i
] == selected
)
98 static const char* get_menu_item_name(int selected_item
,
103 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
104 int type
= (menu
->flags
&MENU_TYPE_MASK
);
105 selected_item
= get_menu_selection(selected_item
, menu
);
108 /* only MT_MENU or MT_RETURN_ID is allowed in here */
109 if (type
== MT_RETURN_ID
)
111 if (menu
->flags
&MENU_DYNAMIC_DESC
)
112 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
113 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
114 return menu
->strings
[selected_item
];
117 menu
= menu
->submenus
[selected_item
];
119 if ((menu
->flags
&MENU_DYNAMIC_DESC
) && (type
!= MT_SETTING_W_TEXT
))
120 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
121 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
123 type
= (menu
->flags
&MENU_TYPE_MASK
);
124 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
126 const struct settings_list
*v
127 = find_setting(menu
->variable
, NULL
);
129 return str(v
->lang_id
);
130 else return "Not Done yet!";
132 return P2STR(menu
->callback_and_desc
->desc
);
134 #ifdef HAVE_LCD_BITMAP
135 static enum themable_icons
menu_get_icon(int selected_item
, void * data
)
137 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
138 int menu_icon
= Icon_NOICON
;
139 selected_item
= get_menu_selection(selected_item
, menu
);
141 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
)
143 return Icon_Menu_functioncall
;
145 menu
= menu
->submenus
[selected_item
];
146 if (menu
->flags
&MENU_HAS_DESC
)
147 menu_icon
= menu
->callback_and_desc
->icon_id
;
148 else if (menu
->flags
&MENU_DYNAMIC_DESC
)
149 menu_icon
= menu
->menu_get_name_and_icon
->icon_id
;
151 if (menu_icon
== Icon_NOICON
)
153 switch (menu
->flags
&MENU_TYPE_MASK
)
156 case MT_SETTING_W_TEXT
:
157 menu_icon
= Icon_Menu_setting
;
160 menu_icon
= Icon_Submenu
;
162 case MT_FUNCTION_CALL
:
163 case MT_RETURN_VALUE
:
164 menu_icon
= Icon_Menu_functioncall
;
172 static void init_menu_lists(const struct menu_item_ex
*menu
,
173 struct gui_synclist
*lists
, int selected
, bool callback
,
174 struct viewport parent
[NB_SCREENS
])
176 int i
, count
= MENU_GET_COUNT(menu
->flags
);
177 int type
= (menu
->flags
&MENU_TYPE_MASK
);
178 menu_callback_type menu_callback
= NULL
;
180 current_subitems_count
= 0;
182 if (type
== MT_RETURN_ID
)
183 get_menu_callback(menu
, &menu_callback
);
185 for (i
=0; i
<count
; i
++)
187 if (type
!= MT_RETURN_ID
)
188 get_menu_callback(menu
->submenus
[i
],&menu_callback
);
191 if (menu_callback(ACTION_REQUEST_MENUITEM
,
192 type
==MT_RETURN_ID
? (void*)(intptr_t)i
: menu
->submenus
[i
])
193 != ACTION_EXIT_MENUITEM
)
195 current_subitems
[current_subitems_count
] = i
;
196 current_subitems_count
++;
201 current_subitems
[current_subitems_count
] = i
;
202 current_subitems_count
++;
205 current_submenus_menu
= (struct menu_item_ex
*)menu
;
207 gui_synclist_init(lists
,get_menu_item_name
,(void*)menu
,false,1, parent
);
208 #ifdef HAVE_LCD_BITMAP
209 if (menu
->callback_and_desc
->icon_id
== Icon_NOICON
)
210 icon
= Icon_Submenu_Entered
;
212 icon
= menu
->callback_and_desc
->icon_id
;
213 gui_synclist_set_title(lists
, P2STR(menu
->callback_and_desc
->desc
), icon
);
214 gui_synclist_set_icon_callback(lists
, global_settings
.show_icons
?menu_get_icon
:NULL
);
217 gui_synclist_set_icon_callback(lists
, NULL
);
219 if(global_settings
.talk_menu
)
220 gui_synclist_set_voice_callback(lists
, talk_menu_item
);
221 gui_synclist_set_nb_items(lists
,current_subitems_count
);
222 gui_synclist_limit_scroll(lists
,true);
223 gui_synclist_select_item(lists
, find_menu_selection(selected
));
225 get_menu_callback(menu
,&menu_callback
);
226 if (callback
&& menu_callback
)
227 menu_callback(ACTION_ENTER_MENUITEM
,menu
);
230 static int talk_menu_item(int selected_item
, void *data
)
232 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
236 int sel
= get_menu_selection(selected_item
, menu
);
238 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
240 type
= menu
->submenus
[sel
]->flags
&MENU_TYPE_MASK
;
241 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
242 talk_setting(menu
->submenus
[sel
]->variable
);
245 if (menu
->submenus
[sel
]->flags
&(MENU_DYNAMIC_DESC
))
247 int (*list_speak_item
)(int selected_item
, void * data
)
248 = menu
->submenus
[sel
]->menu_get_name_and_icon
->
251 list_speak_item(sel
, menu
->submenus
[sel
]->
252 menu_get_name_and_icon
->
257 str
= menu
->submenus
[sel
]->menu_get_name_and_icon
->
258 list_get_name(sel
, menu
->submenus
[sel
]->
259 menu_get_name_and_icon
->
260 list_get_name_data
, buffer
);
265 id
= P2ID(menu
->submenus
[sel
]->callback_and_desc
->desc
);
270 else if(((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
))
272 if ((menu
->flags
&MENU_DYNAMIC_DESC
) == 0)
274 unsigned char *s
= (unsigned char *)menu
->strings
[sel
];
275 /* string list, try to talk it if ID2P was used */
284 void do_setting_screen(const struct settings_list
*setting
, const char * title
,
285 struct viewport parent
[NB_SCREENS
])
287 char padded_title
[MAX_PATH
];
288 /* Pad the title string by repeating it. This is needed
289 so the scroll settings title can actually be used to
291 if (setting
->flags
&F_PADTITLE
)
294 if (setting
->lang_id
== -1)
295 title
= (char*)setting
->cfg_vals
;
297 title
= P2STR((unsigned char*)title
);
299 while (i
< MAX_PATH
-1)
301 int padlen
= MIN(len
, MAX_PATH
-1-i
);
302 memcpy(&padded_title
[i
], title
, padlen
);
305 padded_title
[i
++] = ' ';
307 padded_title
[i
] = '\0';
308 title
= padded_title
;
311 option_screen((struct settings_list
*)setting
, parent
,
312 setting
->flags
&F_TEMPVAR
, (char*)title
);
316 void do_setting_from_menu(const struct menu_item_ex
*temp
,
317 struct viewport parent
[NB_SCREENS
])
321 const struct settings_list
*setting
=
322 find_setting(temp
->variable
, &setting_id
);
323 if (temp
&& ((temp
->flags
&MENU_TYPE_MASK
) == MT_SETTING_W_TEXT
))
324 title
= temp
->callback_and_desc
->desc
;
326 title
= ID2P(setting
->lang_id
);
327 do_setting_screen(setting
, title
, parent
);
331 int do_menu(const struct menu_item_ex
*start_menu
, int *start_selected
,
332 struct viewport parent
[NB_SCREENS
], bool hide_theme
)
334 int selected
= start_selected
? *start_selected
: 0;
336 struct gui_synclist lists
;
337 const struct menu_item_ex
*temp
, *menu
= start_menu
;
340 int old_audio_status
= audio_status();
342 #ifdef HAVE_TOUCHSCREEN
343 /* plugins possibly have grid mode active. force global settings in lists */
344 enum touchscreen_mode tsm
= touchscreen_get_mode();
345 touchscreen_set_mode(global_settings
.touch_mode
);
349 viewportmanager_theme_enable(i
, !hide_theme
, NULL
);
351 const struct menu_item_ex
*menu_stack
[MAX_MENUS
];
352 int menu_stack_selected_item
[MAX_MENUS
];
354 bool in_stringlist
, done
= false;
355 struct viewport
*vps
= NULL
;
356 #ifdef HAVE_BUTTONBAR
357 struct gui_buttonbar buttonbar
;
358 gui_buttonbar_init(&buttonbar
);
359 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
360 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
362 menu_callback_type menu_callback
= NULL
;
364 /* if hide_theme is true, assume parent has been fixed before passed into
365 * this function, e.g. with viewport_set_defaults(parent, screen) */
366 init_menu_lists(menu
, &lists
, selected
, true, parent
);
367 vps
= *(lists
.parent
);
368 in_stringlist
= ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
);
369 /* load the callback, and only reload it if menu changes */
370 get_menu_callback(menu
, &menu_callback
);
372 gui_synclist_draw(&lists
);
373 gui_synclist_speak_item(&lists
);
374 #ifdef HAVE_BUTTONBAR
377 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
378 gui_buttonbar_draw(&buttonbar
);
383 int new_audio_status
;
384 redraw_lists
= false;
387 #ifdef HAVE_BUTTONBAR
388 gui_buttonbar_draw(&buttonbar
);
391 #if CONFIG_CODEC == SWCODEC
392 keyclick_set_callback(gui_synclist_keyclick_callback
, &lists
);
394 action
= get_action(CONTEXT_MAINMENU
,
395 list_do_action_timeout(&lists
, HZ
));
397 /* query audio status to see if it changed */
398 new_audio_status
= audio_status();
399 if (old_audio_status
!= new_audio_status
)
400 { /* force a redraw if anything changed the audio status
403 old_audio_status
= new_audio_status
;
405 /* HZ so the status bar redraws corectly */
409 int old_action
= action
;
410 action
= menu_callback(action
, menu
);
411 if (action
== ACTION_EXIT_AFTER_THIS_MENUITEM
)
414 ret
= MENU_SELECTED_EXIT
; /* will exit after returning
417 else if (action
== ACTION_REDRAW
)
424 if (gui_synclist_do_button(&lists
, &action
, LIST_WRAP_UNLESS_HELD
))
426 #ifdef HAVE_QUICKSCREEN
427 else if (action
== ACTION_STD_QUICKSCREEN
)
429 quick_screen_quick(action
);
433 #ifdef HAVE_RECORDING
434 else if (action
== ACTION_STD_REC
)
436 ret
= GO_TO_RECSCREEN
;
440 else if (action
== ACTION_TREE_WPS
)
442 ret
= GO_TO_PREVIOUS_MUSIC
;
445 else if (action
== ACTION_TREE_STOP
)
447 redraw_lists
= list_stop_handler();
449 else if (action
== ACTION_STD_CONTEXT
)
451 if (menu
== &root_menu_
)
453 ret
= GO_TO_ROOTITEM_CONTEXT
;
456 else if (!in_stringlist
)
459 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
),menu
);
460 temp
= menu
->submenus
[selected
];
461 type
= (temp
->flags
&MENU_TYPE_MASK
);
462 if ((type
== MT_SETTING_W_TEXT
|| type
== MT_SETTING
))
464 #ifdef HAVE_QUICKSCREEN
465 MENUITEM_STRINGLIST(quickscreen_able_option
,
466 ID2P(LANG_ONPLAY_MENU_TITLE
), NULL
,
467 ID2P(LANG_RESET_SETTING
),
468 ID2P(LANG_TOP_QS_ITEM
),
469 ID2P(LANG_LEFT_QS_ITEM
),
470 ID2P(LANG_BOTTOM_QS_ITEM
),
471 ID2P(LANG_RIGHT_QS_ITEM
),
472 ID2P(LANG_ADD_TO_FAVES
));
474 MENUITEM_STRINGLIST(notquickscreen_able_option
,
475 ID2P(LANG_ONPLAY_MENU_TITLE
), NULL
,
476 ID2P(LANG_RESET_SETTING
));
477 const struct menu_item_ex
*menu
;
478 int menu_selection
= 0;
479 const struct settings_list
*setting
=
480 find_setting(temp
->variable
, NULL
);
481 #ifdef HAVE_QUICKSCREEN
482 if (is_setting_quickscreenable(setting
))
483 menu
= &quickscreen_able_option
;
486 menu
= ¬quickscreen_able_option
;
487 switch (do_menu(menu
, &menu_selection
, NULL
, false))
491 case 0: /* reset setting */
492 reset_setting(setting
, setting
->setting
);
494 #ifdef HAVE_QUICKSCREEN
495 case 1: /* set as top QS item */
496 set_as_qs_item(setting
, QUICKSCREEN_TOP
);
498 case 2: /* set as left QS item */
499 set_as_qs_item(setting
, QUICKSCREEN_LEFT
);
501 case 3: /* set as bottom QS item */
502 set_as_qs_item(setting
, QUICKSCREEN_BOTTOM
);
504 case 4: /* set as right QS item */
505 set_as_qs_item(setting
, QUICKSCREEN_RIGHT
);
507 case 5: /* Add to faves. Same limitation on which can be
508 added to the shortcuts menu as the quickscreen */
509 shortcuts_add(SHORTCUT_SETTING
, (void*)setting
);
512 } /* swicth(do_menu()) */
515 } /* else if (!in_stringlist) */
517 else if (action
== ACTION_STD_MENU
)
519 if (menu
!= &root_menu_
)
522 ret
= GO_TO_PREVIOUS
;
525 else if (action
== ACTION_STD_CANCEL
)
527 bool exiting_menu
= false;
528 in_stringlist
= false;
529 /* might be leaving list, so stop scrolling */
530 gui_synclist_scroll_stop(&lists
);
532 menu_callback(ACTION_EXIT_MENUITEM
, menu
);
534 if (menu
->flags
&MENU_EXITAFTERTHISMENU
)
536 else if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
541 menu
= menu_stack
[stack_top
];
542 if (!exiting_menu
&& (menu
->flags
&MENU_EXITAFTERTHISMENU
))
545 init_menu_lists(menu
, &lists
,
546 menu_stack_selected_item
[stack_top
], false, vps
);
548 /* new menu, so reload the callback */
549 get_menu_callback(menu
, &menu_callback
);
551 else if (menu
!= &root_menu_
)
553 ret
= GO_TO_PREVIOUS
;
557 else if (action
== ACTION_STD_OK
)
560 /* entering an item that may not be a list, so stop scrolling */
561 gui_synclist_scroll_stop(&lists
);
562 #ifdef HAVE_BUTTONBAR
565 gui_buttonbar_unset(&buttonbar
);
566 gui_buttonbar_draw(&buttonbar
);
569 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
570 temp
= menu
->submenus
[selected
];
573 type
= (menu
->flags
&MENU_TYPE_MASK
);
576 type
= (temp
->flags
&MENU_TYPE_MASK
);
577 get_menu_callback(temp
, &menu_callback
);
580 action
= menu_callback(ACTION_ENTER_MENUITEM
,temp
);
581 if (action
== ACTION_EXIT_MENUITEM
)
588 if (stack_top
< MAX_MENUS
)
590 menu_stack
[stack_top
] = menu
;
591 menu_stack_selected_item
[stack_top
] = selected
;
594 init_menu_lists(menu
, &lists
, 0, true, vps
);
597 case MT_FUNCTION_CALL
:
600 if (temp
->flags
&MENU_FUNC_USEPARAM
)
601 return_value
= temp
->function
->function_w_param(
602 temp
->function
->param
);
604 return_value
= temp
->function
->function();
605 if (!(menu
->flags
&MENU_EXITAFTERTHISMENU
) ||
606 (temp
->flags
&MENU_EXITAFTERTHISMENU
))
608 init_menu_lists(menu
, &lists
, selected
, true, vps
);
610 if (temp
->flags
&MENU_FUNC_CHECK_RETVAL
)
612 if (return_value
!= 0)
621 case MT_SETTING_W_TEXT
:
623 do_setting_from_menu(temp
, vps
);
624 send_event(GUI_EVENT_ACTIONUPDATE
, (void*)1); /* force a redraw */
633 else if (stack_top
< MAX_MENUS
)
635 menu_stack
[stack_top
] = menu
;
636 menu_stack_selected_item
[stack_top
] = selected
;
639 init_menu_lists(menu
,&lists
,0,false, vps
);
640 in_stringlist
= true;
643 case MT_RETURN_VALUE
:
651 menu_callback(ACTION_EXIT_MENUITEM
,temp
);
653 if (current_submenus_menu
!= menu
)
654 init_menu_lists(menu
,&lists
,selected
,true,vps
);
655 /* callback was changed, so reload the menu's callback */
656 get_menu_callback(menu
, &menu_callback
);
657 if ((menu
->flags
&MENU_EXITAFTERTHISMENU
) &&
658 !(temp
->flags
&MENU_EXITAFTERTHISMENU
))
663 #ifdef HAVE_BUTTONBAR
666 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
667 gui_buttonbar_draw(&buttonbar
);
673 switch(default_event_handler(action
))
675 case SYS_USB_CONNECTED
:
676 ret
= MENU_ATTACHED_USB
;
679 case SYS_CALL_HUNG_UP
:
680 case BUTTON_MULTIMEDIA_PLAYPAUSE
:
681 /* remove splash from playlist_resume() */
687 if (redraw_lists
&& !done
)
690 menu_callback(ACTION_REDRAW
, menu
);
691 gui_synclist_draw(&lists
);
692 gui_synclist_speak_item(&lists
);
697 /* make sure the start_selected variable is set to
698 the selected item from the menu do_menu() was called from */
701 menu
= menu_stack
[0];
702 init_menu_lists(menu
,&lists
,menu_stack_selected_item
[0],true, vps
);
704 *start_selected
= get_menu_selection(
705 gui_synclist_get_sel_pos(&lists
), menu
);
709 viewportmanager_theme_undo(i
, false);
710 #ifdef HAVE_TOUCHSCREEN
711 touchscreen_set_mode(tsm
);