A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Robert E. Hak
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21/*
222005 Kevin Ferrare :
23 - Multi screen support
24 - Rewrote/removed a lot of code now useless with the new gui API
25*/
26#include <stdbool.h>
27#include <stdlib.h>
28#include "config.h"
29#include "system.h"
30
31#include "appevents.h"
32#include "lcd.h"
33#include "font.h"
34#include "file.h"
35#include "menu.h"
36#include "button.h"
37#include "kernel.h"
38#include "debug.h"
39#include "usb.h"
40#include "panic.h"
41#include "settings.h"
42#include "settings_list.h"
43#include "option_select.h"
44#include "screens.h"
45#include "talk.h"
46#include "lang.h"
47#include "misc.h"
48#include "action.h"
49#include "menus/exported_menus.h"
50#include "string.h"
51#include "root_menu.h"
52#include "audio.h"
53#include "viewport.h"
54#include "quickscreen.h"
55#include "shortcuts.h"
56
57#include "icons.h"
58
59/* gui api */
60#include "list.h"
61
62#define MAX_MENUS 8
63/* used to allow for dynamic menus */
64#define MAX_MENU_SUBITEMS 64
65static struct menu_item_ex *current_submenus_menu;
66static int current_subitems[MAX_MENU_SUBITEMS];
67static int current_subitems_count = 0;
68static int talk_menu_item(int selected_item, void *data);
69
70struct menu_data_t
71{
72 const struct menu_item_ex *menu;
73 int selected;
74};
75
76static int empty_menu_callback(int action, const struct menu_item_ex *this_item, struct gui_synclist *this_list)
77{
78 return action;
79 (void)this_item;
80 (void)this_list;
81}
82
83static void get_menu_callback(const struct menu_item_ex *m,
84 menu_callback_type *menu_callback)
85{
86 if (m->flags&(MENU_HAS_DESC|MENU_DYNAMIC_DESC))
87 *menu_callback= m->callback_and_desc->menu_callback;
88 else
89 *menu_callback = m->menu_callback;
90
91 if (!*menu_callback)
92 *menu_callback = &empty_menu_callback;
93}
94
95static bool query_audio_status(int *old_audio_status)
96{
97 bool redraw_list = false;
98 /* query audio status to see if it changed */
99 int new_audio_status = audio_status();
100 if (*old_audio_status != new_audio_status)
101 { /* force a redraw if anything changed the audio status from outside */
102 *old_audio_status = new_audio_status;
103 redraw_list = true;
104 }
105 return redraw_list;
106}
107
108static int get_menu_selection(int selected_item, const struct menu_item_ex *menu)
109{
110 int type = (menu->flags&MENU_TYPE_MASK);
111 if ((type == MT_MENU || type == MT_RETURN_ID)
112 && (selected_item<current_subitems_count))
113 return current_subitems[selected_item];
114 return selected_item;
115}
116static int find_menu_selection(int selected)
117{
118 int i;
119 for (i=0; i< current_subitems_count; i++)
120 if (current_subitems[i] == selected)
121 return i;
122 return 0;
123}
124static const char* get_menu_item_name(int selected_item,
125 void * data,
126 char *buffer,
127 size_t buffer_len)
128{
129 const char *name;
130 const struct menu_item_ex *menu = (const struct menu_item_ex *)data;
131 int type = (menu->flags&MENU_TYPE_MASK);
132 selected_item = get_menu_selection(selected_item, menu);
133
134 /* only MT_MENU or MT_RETURN_ID is allowed in here */
135 if (type == MT_RETURN_ID)
136 {
137 if (menu->flags&MENU_DYNAMIC_DESC)
138 {
139 name = menu->menu_get_name_and_icon->list_get_name(selected_item,
140 menu->menu_get_name_and_icon->list_get_name_data, buffer, buffer_len);
141 }
142 else
143 name = menu->strings[selected_item];
144
145 if (P2ID((unsigned char *)name) > VOICEONLY_DELIMITER)
146 name = "";
147
148 return name;
149 }
150 if (type == MT_MENU)
151 menu = menu->submenus[selected_item];
152
153 if ((menu->flags&MENU_DYNAMIC_DESC) && (type != MT_SETTING_W_TEXT))
154 return menu->menu_get_name_and_icon->list_get_name(selected_item,
155 menu->menu_get_name_and_icon->list_get_name_data, buffer, buffer_len);
156
157 type = (menu->flags&MENU_TYPE_MASK);
158 if ((type == MT_SETTING) || (type == MT_SETTING_W_TEXT))
159 {
160 const struct settings_list *v = find_setting(menu->variable);
161 if (v)
162 return str(v->lang_id);
163 else return "Not Done yet!";
164 }
165 return P2STR(menu->callback_and_desc->desc);
166}
167
168static enum themable_icons menu_get_icon(int selected_item, void * data)
169{
170 const struct menu_item_ex *menu = (const struct menu_item_ex *)data;
171 int menu_icon = Icon_NOICON;
172 int type = (menu->flags&MENU_TYPE_MASK);
173 selected_item = get_menu_selection(selected_item, menu);
174
175 if (type == MT_RETURN_ID)
176 {
177 return Icon_Menu_functioncall;
178 }
179 if (type == MT_MENU)
180 menu = menu->submenus[selected_item];
181
182 if (menu->flags&MENU_HAS_DESC)
183 menu_icon = menu->callback_and_desc->icon_id;
184 else if (menu->flags&MENU_DYNAMIC_DESC)
185 menu_icon = menu->menu_get_name_and_icon->icon_id;
186
187 if (menu_icon == Icon_NOICON)
188 {
189 unsigned int flags = (menu->flags&MENU_TYPE_MASK);
190 if(flags == MT_MENU)
191 menu_icon = Icon_Submenu;
192 else if (flags == MT_SETTING || flags == MT_SETTING_W_TEXT)
193 menu_icon = Icon_Menu_setting;
194 else if (flags == MT_FUNCTION_CALL || flags == MT_RETURN_VALUE)
195 menu_icon = Icon_Menu_functioncall;
196 }
197 return menu_icon;
198}
199
200static int init_menu_lists(const struct menu_item_ex *menu,
201 struct gui_synclist *lists, int selected, bool callback,
202 struct viewport parent[NB_SCREENS])
203{
204 if (!menu || !lists)
205 {
206 panicf("init_menu_lists, NULL pointer");
207 return 0;
208 }
209
210 int i;
211 int start_action = ACTION_ENTER_MENUITEM;
212 int count = MIN(MENU_GET_COUNT(menu->flags), MAX_MENU_SUBITEMS);
213 int type = (menu->flags&MENU_TYPE_MASK);
214 menu_callback_type menu_callback = &empty_menu_callback;
215 int icon;
216 char * title;
217 current_subitems_count = 0;
218
219 if (type == MT_RETURN_ID)
220 get_menu_callback(menu, &menu_callback);
221
222 for (i=0; i<count; i++)
223 {
224 if (type != MT_RETURN_ID)
225 get_menu_callback(menu->submenus[i],&menu_callback);
226
227 if (menu_callback(ACTION_REQUEST_MENUITEM,
228 type==MT_RETURN_ID ? (void*)(intptr_t)i: menu->submenus[i], lists)
229 != ACTION_EXIT_MENUITEM)
230 {
231 current_subitems[current_subitems_count] = i;
232 current_subitems_count++;
233 }
234 }
235
236 current_submenus_menu = (struct menu_item_ex *)menu;
237
238 gui_synclist_init(lists,get_menu_item_name,(void*)menu,false,1, parent);
239
240 if (menu->flags&MENU_HAS_DESC)
241 {
242 icon = menu->callback_and_desc->icon_id;
243 title = P2STR(menu->callback_and_desc->desc);
244 }
245 else if (menu->flags&MENU_DYNAMIC_DESC)
246 {
247 char buffer[80];
248 icon = menu->menu_get_name_and_icon->icon_id;
249 title = menu->menu_get_name_and_icon->
250 list_get_name(-1, menu->menu_get_name_and_icon->
251 list_get_name_data, buffer, sizeof(buffer));
252 }
253 else
254 {
255 icon = Icon_NOICON;
256 title = "";
257 }
258
259 if (icon == Icon_NOICON)
260 icon = Icon_Submenu_Entered;
261 gui_synclist_set_title(lists, title, icon);
262 gui_synclist_set_icon_callback(lists, global_settings.show_icons?menu_get_icon:NULL);
263 if(global_settings.talk_menu)
264 gui_synclist_set_voice_callback(lists, talk_menu_item);
265 gui_synclist_set_nb_items(lists,current_subitems_count);
266 gui_synclist_select_item(lists, find_menu_selection(selected));
267
268 get_menu_callback(menu,&menu_callback);
269 if (callback)
270 start_action = menu_callback(start_action, menu, lists);
271
272 return start_action;
273}
274
275static int talk_menu_item(int selected_item, void *data)
276{
277 const struct menu_item_ex *menu = (const struct menu_item_ex *)data;
278 int id = -1;
279 int type;
280 unsigned char *str;
281 int sel = get_menu_selection(selected_item, menu);
282
283 if ((menu->flags&MENU_TYPE_MASK) == MT_MENU)
284 {
285 type = menu->submenus[sel]->flags&MENU_TYPE_MASK;
286 if ((type == MT_SETTING) || (type == MT_SETTING_W_TEXT))
287 talk_setting(menu->submenus[sel]->variable);
288 else
289 {
290 if (menu->submenus[sel]->flags&(MENU_DYNAMIC_DESC))
291 {
292 int (*list_speak_item)(int selected_item, void * data)
293 = menu->submenus[sel]->menu_get_name_and_icon->
294 list_speak_item;
295 if(list_speak_item)
296 list_speak_item(sel, menu->submenus[sel]->
297 menu_get_name_and_icon->
298 list_get_name_data);
299 else
300 {
301 char buffer[80];
302 str = menu->submenus[sel]->menu_get_name_and_icon->
303 list_get_name(sel, menu->submenus[sel]->
304 menu_get_name_and_icon->
305 list_get_name_data, buffer, sizeof(buffer));
306 id = P2ID(str);
307 }
308 }
309 else
310 id = P2ID(menu->submenus[sel]->callback_and_desc->desc);
311 if (id != -1)
312 talk_id(id,false);
313 }
314 }
315 else if(((menu->flags&MENU_TYPE_MASK) == MT_RETURN_ID))
316 {
317 if ((menu->flags&MENU_DYNAMIC_DESC) == 0)
318 {
319 unsigned char *s = (unsigned char *)menu->strings[sel];
320 /* string list, try to talk it if ID2P was used */
321 id = P2ID(s);
322 if (id != -1)
323 talk_id(id,false);
324 }
325 }
326 return 0;
327}
328
329void do_setting_screen(const struct settings_list *setting, const char * title,
330 struct viewport parent[NB_SCREENS])
331{
332 char padded_title[MAX_PATH];
333 /* Pad the title string by repeating it. This is needed
334 so the scroll settings title can actually be used to
335 test the setting */
336 if (setting->flags&F_PADTITLE)
337 {
338 int i = 0, len;
339 title = P2STR((unsigned char*)title);
340 len = strlen(title);
341 while (i < MAX_PATH-1)
342 {
343 int padlen = MIN(len, MAX_PATH-1-i);
344 memcpy(&padded_title[i], title, padlen);
345 i += padlen;
346 if (i<MAX_PATH-1)
347 padded_title[i++] = ' ';
348 }
349 padded_title[i] = '\0';
350 title = padded_title;
351 }
352
353 option_screen((struct settings_list *)setting, parent,
354 setting->flags&F_TEMPVAR, (char*)title);
355}
356
357
358void do_setting_from_menu(const struct menu_item_ex *temp,
359 struct viewport parent[NB_SCREENS])
360{
361 char *title;
362 if (!temp)
363 {
364 panicf("do_setting_from_menu, NULL pointer");
365 return;
366 }
367 const struct settings_list *setting = find_setting(temp->variable);
368
369 if ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT)
370 title = temp->callback_and_desc->desc;
371 else
372 title = ID2P(setting->lang_id);
373
374 do_setting_screen(setting, title, parent);
375}
376
377/* display a menu */
378int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
379 struct viewport parent[NB_SCREENS], bool hide_theme)
380{
381 int selected = start_selected? *start_selected : 0;
382 int ret = 0;
383 int action;
384 int start_action;
385 struct gui_synclist lists;
386 const struct menu_item_ex *temp = NULL;
387 const struct menu_item_ex *menu = start_menu;
388
389 bool in_stringlist, done = false;
390 bool redraw_lists;
391
392 int old_audio_status = audio_status();
393
394#ifdef HAVE_TOUCHSCREEN
395 /* plugins possibly have grid mode active. force global settings in lists */
396 enum touchscreen_mode tsm = touchscreen_get_mode();
397 enum touchscreen_mode old_global_mode = global_settings.touch_mode;
398 touchscreen_set_mode(global_settings.touch_mode);
399#endif
400
401 FOR_NB_SCREENS(i)
402 viewportmanager_theme_enable(i, !hide_theme, NULL);
403
404 struct menu_data_t mstack[MAX_MENUS]; /* menu, selected */
405 int stack_top = 0;
406
407 struct viewport *vps = NULL;
408 menu_callback_type menu_callback = &empty_menu_callback;
409
410 /* if hide_theme is true, assume parent has been fixed before passed into
411 * this function, e.g. with viewport_set_defaults(parent, screen)
412 * start_action allows an action to be processed
413 * by menu logic by bypassing get_action on the initial run */
414 start_action = init_menu_lists(menu, &lists, selected, true, parent);
415 vps = *(lists.parent);
416 in_stringlist = ((menu->flags&MENU_TYPE_MASK) == MT_RETURN_ID);
417 /* load the callback, and only reload it if menu changes */
418 get_menu_callback(menu, &menu_callback);
419
420 gui_synclist_draw(&lists);
421 gui_synclist_speak_item(&lists);
422
423 while (!done)
424 {
425 keyclick_set_callback(gui_synclist_keyclick_callback, &lists);
426
427 if (UNLIKELY(start_action != ACTION_ENTER_MENUITEM))
428 {
429 action = start_action;
430 start_action = ACTION_ENTER_MENUITEM;
431 }
432 else
433 action = get_action(CONTEXT_MAINMENU|ALLOW_SOFTLOCK,
434 list_do_action_timeout(&lists, HZ));
435 /* HZ so the status bar redraws corectly */
436
437 /* query audio status to see if it changed */
438 redraw_lists = query_audio_status(&old_audio_status);
439
440#ifdef HAVE_TOUCHSCREEN
441 /* need to translate touch actions *first* so the menu callback has
442 * a chance to intercept before it hits the list's do_button. */
443 if (action == ACTION_TOUCHSCREEN)
444 action = gui_synclist_do_touchscreen(&lists);
445#endif
446
447 int new_action = menu_callback(action, menu, &lists);
448 if (new_action == ACTION_EXIT_AFTER_THIS_MENUITEM)
449 ret = MENU_SELECTED_EXIT; /* exit after return from selection */
450 else if (new_action == ACTION_REDRAW)
451 redraw_lists = true;
452 else
453 action = new_action;
454
455 if (LIKELY(gui_synclist_do_button(&lists, &action)))
456 continue;
457#ifdef HAVE_QUICKSCREEN
458 else if (action == ACTION_STD_QUICKSCREEN)
459 {
460 if (global_settings.shortcuts_replaces_qs ||
461 quick_screen_quick(action) == QUICKSCREEN_GOTO_SHORTCUTS_MENU)
462 {
463 int last_screen = global_status.last_screen;
464 global_status.last_screen = GO_TO_SHORTCUTMENU;
465 int shortcut_ret = do_shortcut_menu(NULL);
466 if (shortcut_ret == GO_TO_PREVIOUS)
467 global_status.last_screen = last_screen;
468 else
469 {
470 ret = shortcut_ret;
471 done = true;
472 }
473 }
474 if (!done)
475 init_menu_lists(menu, &lists, lists.selected_item, false, vps);
476 redraw_lists = true;
477 }
478#endif
479#ifdef HAVE_RECORDING
480 else if (action == ACTION_STD_REC)
481 {
482 ret = GO_TO_RECSCREEN;
483 done = true;
484 }
485#endif
486 else if (action == ACTION_TREE_WPS)
487 {
488 ret = GO_TO_PREVIOUS_MUSIC;
489 done = true;
490 }
491 else if (action == ACTION_TREE_STOP)
492 {
493 redraw_lists = list_stop_handler();
494 }
495 else if (action == ACTION_STD_CONTEXT)
496 {
497 if (menu == &root_menu_)
498 {
499 ret = GO_TO_ROOTITEM_CONTEXT;
500 done = true;
501 }
502 else if (!in_stringlist)
503 {
504 int type = (menu->flags&MENU_TYPE_MASK);
505 selected = get_menu_selection(gui_synclist_get_sel_pos(&lists),menu);
506 if (type == MT_MENU)
507 {
508 temp = menu->submenus[selected];
509 type = (temp->flags&MENU_TYPE_MASK);
510 }
511 else
512 type = -1;
513
514 if (type == MT_SETTING_W_TEXT || type == MT_SETTING)
515 {
516 const struct menu_item_ex *context_menu;
517 const struct settings_list *setting =
518 find_setting(temp->variable);
519
520 MENUITEM_STRINGLIST(settings_op_menu,
521 ID2P(LANG_ONPLAY_MENU_TITLE), NULL,
522 ID2P(LANG_RESET_SETTING),
523#ifndef HAVE_QUICKSCREEN
524 );
525 context_menu = &settings_op_menu;
526#else
527 ID2P(LANG_TOP_QS_ITEM),
528 ID2P(LANG_LEFT_QS_ITEM),
529 ID2P(LANG_BOTTOM_QS_ITEM),
530 ID2P(LANG_RIGHT_QS_ITEM),
531 ID2P(LANG_ADD_CURRENT_TO_FAVES),
532 ID2P(LANG_ADD_TO_FAVES));
533
534 /* re-use the strings and desc from the settings_op_menu */
535 static const struct menu_item_ex non_quickscreen_op_menu =
536 {MT_RETURN_ID|MENU_HAS_DESC|MENU_ITEM_COUNT(1),
537 { .strings = settings_op_menu_},
538 {.callback_and_desc = &settings_op_menu__}};
539
540 if (is_setting_quickscreenable(setting))
541 context_menu = &settings_op_menu;
542 else
543 {
544 context_menu = &non_quickscreen_op_menu;
545 }
546#endif
547 int msel = do_menu(context_menu, NULL, NULL, false);
548
549 switch (msel)
550 {
551 case GO_TO_PREVIOUS:
552 break;
553 case 0: /* reset setting */
554 reset_setting(setting, setting->setting);
555 settings_save();
556 settings_apply(false);
557 break;
558#ifdef HAVE_QUICKSCREEN
559 case 1: /* set as top QS item */
560 global_settings.qs_items[QUICKSCREEN_TOP] = setting;
561 break;
562 case 2: /* set as left QS item */
563 global_settings.qs_items[QUICKSCREEN_LEFT] = setting;
564 break;
565 case 3: /* set as bottom QS item */
566 global_settings.qs_items[QUICKSCREEN_BOTTOM] = setting;
567 break;
568 case 4: /* set as right QS item */
569 global_settings.qs_items[QUICKSCREEN_RIGHT] = setting;
570 break;
571 case 5: /* Add current value of setting to faves.
572 Same limitation on which can be
573 added to the shortcuts menu as the quickscreen */
574 shortcuts_add(SHORTCUT_SETTING_APPLY, (void*)setting);
575 break;
576 case 6: /* Add to faves. Same limitation on which can be
577 added to the shortcuts menu as the quickscreen */
578 shortcuts_add(SHORTCUT_SETTING, (void*)setting);
579 break;
580#endif
581 } /* switch(do_menu()) */
582 if (menu->flags & MENU_EXITAFTERTHISMENU)
583 done = true; /* in case onplay menu contains setting */
584 redraw_lists = true;
585 }
586 } /* else if (!in_stringlist) */
587 }
588 else if (action == ACTION_STD_MENU)
589 {
590 if (menu != &root_menu_)
591 ret = GO_TO_ROOT;
592 else
593 ret = GO_TO_PREVIOUS;
594 done = true;
595 }
596 else if (action == ACTION_STD_CANCEL)
597 {
598 /* might be leaving list, so stop scrolling */
599 gui_synclist_scroll_stop(&lists);
600
601 bool exiting_menu = false;
602 in_stringlist = false;
603
604 menu_callback(ACTION_EXIT_MENUITEM, menu, &lists);
605
606 if (menu->flags&MENU_EXITAFTERTHISMENU)
607 done = true;
608 else if ((menu->flags&MENU_TYPE_MASK) == MT_MENU)
609 exiting_menu = true;
610
611 if (stack_top > 0)
612 {
613 stack_top--;
614 menu = mstack[stack_top].menu;
615 int msel = mstack[stack_top].selected;
616 if (!exiting_menu && (menu->flags&MENU_EXITAFTERTHISMENU))
617 done = true;
618 else
619 init_menu_lists(menu, &lists, msel, false, vps);
620 redraw_lists = true;
621 /* new menu, so reload the callback */
622 get_menu_callback(menu, &menu_callback);
623 }
624 else if (menu != &root_menu_)
625 {
626 ret = GO_TO_PREVIOUS;
627 done = true;
628 }
629 }
630 else if (action == ACTION_STD_OK)
631 {
632 /* entering an item that may not be a list, so stop scrolling */
633 gui_synclist_scroll_stop(&lists);
634 redraw_lists = true;
635
636 int type = (menu->flags&MENU_TYPE_MASK);
637 selected = get_menu_selection(gui_synclist_get_sel_pos(&lists), menu);
638 if (type == MT_MENU)
639 temp = menu->submenus[selected];
640 else if (!in_stringlist)
641 type = -1;
642
643 if (!in_stringlist && temp)
644 {
645 type = (temp->flags&MENU_TYPE_MASK);
646 get_menu_callback(temp, &menu_callback);
647 action = menu_callback(ACTION_ENTER_MENUITEM, temp, &lists);
648 if (action == ACTION_EXIT_MENUITEM)
649 break;
650 }
651 switch (type)
652 {
653 case MT_MENU:
654 if (stack_top < MAX_MENUS)
655 {
656 mstack[stack_top].menu = menu;
657 mstack[stack_top].selected = selected;
658 stack_top++;
659 menu = temp;
660 init_menu_lists(menu, &lists, 0, true, vps);
661 }
662 break;
663 case MT_FUNCTION_CALL_W_PARAM:
664 case MT_FUNCTION_CALL:
665 {
666 int return_value;
667 if (type == MT_FUNCTION_CALL_W_PARAM)
668 {
669 return_value = temp->function_param->function_w_param(
670 temp->function_param->param);
671 }
672 else
673 {
674 return_value = temp->function->function();
675 }
676 if (!(menu->flags&MENU_EXITAFTERTHISMENU) ||
677 (temp->flags&MENU_EXITAFTERTHISMENU))
678 {
679 /* Reload menu but don't run the calback again FS#8117 */
680 init_menu_lists(menu, &lists, selected, false, vps);
681 }
682 if (temp->flags&MENU_FUNC_CHECK_RETVAL)
683 {
684 if (return_value != 0)
685 {
686 done = true;
687 ret = return_value;
688 }
689 }
690 break;
691 }
692 case MT_SETTING:
693 case MT_SETTING_W_TEXT:
694 {
695 do_setting_from_menu(temp, vps);
696 init_menu_lists(menu, &lists, selected, false, vps);
697 redraw_lists = true;
698
699 break;
700 }
701 case MT_RETURN_ID:
702 if (in_stringlist)
703 {
704 done = true;
705 ret = selected;
706 }
707 else if (stack_top < MAX_MENUS)
708 {
709 mstack[stack_top].menu = menu;
710 mstack[stack_top].selected = selected;
711 stack_top++;
712 menu = temp;
713 init_menu_lists(menu,&lists,0,false, vps);
714 in_stringlist = true;
715 }
716 break;
717 case MT_RETURN_VALUE:
718 ret = temp->value;
719 done = true;
720 break;
721
722 default:
723 ret = GO_TO_PREVIOUS;
724 done = true;
725 break;
726 }
727 if (type != MT_MENU)
728 {
729 menu_callback(ACTION_EXIT_MENUITEM, temp, &lists);
730 }
731 if (current_submenus_menu != menu)
732 init_menu_lists(menu,&lists,selected,true,vps);
733 /* callback was changed, so reload the menu's callback */
734 get_menu_callback(menu, &menu_callback);
735 if ((menu->flags&MENU_EXITAFTERTHISMENU) &&
736 !(temp->flags&MENU_EXITAFTERTHISMENU))
737 {
738 done = true;
739 break;
740 }
741 }
742 else
743 {
744 if (action == SYS_USB_CONNECTED)
745 gui_synclist_scroll_stop(&lists);
746
747 switch(default_event_handler(action))
748 {
749 case SYS_USB_CONNECTED:
750 ret = MENU_ATTACHED_USB;
751 done = true;
752 break;
753 case SYS_CALL_HUNG_UP:
754 case BUTTON_MULTIMEDIA_PLAYPAUSE:
755 /* remove splash from playlist_resume() */
756 redraw_lists = true;
757 break;
758 }
759 }
760
761 if (redraw_lists && !done)
762 {
763 if (menu_callback(ACTION_REDRAW, menu, &lists) != ACTION_REDRAW)
764 continue;
765
766
767 gui_synclist_set_title(&lists, lists.title, lists.title_icon);
768 gui_synclist_draw(&lists);
769 gui_synclist_speak_item(&lists);
770 }
771 }
772
773 if (start_selected)
774 {
775 /* make sure the start_selected variable is set to
776 the selected item from the menu do_menu() was called from */
777 if (stack_top > 0)
778 {
779 menu = mstack[0].menu;
780 init_menu_lists(menu,&lists,mstack[0].selected,true, vps);
781 }
782 *start_selected = get_menu_selection(
783 gui_synclist_get_sel_pos(&lists), menu);
784 }
785
786 FOR_NB_SCREENS(i)
787 {
788 viewportmanager_theme_undo(i, false);
789 skinlist_set_cfg(i, NULL); /* Bugfix dangling reference in skin_draw() */
790 }
791#ifdef HAVE_TOUCHSCREEN
792 /* This is needed because this function runs the settings menu and we do
793 * not want to switch back to the old mode if the user intentionally went
794 * to a different one. This is a very hacky way to do this... */
795 if(!(global_settings.touch_mode != (int)old_global_mode &&
796 tsm == old_global_mode))
797 touchscreen_set_mode(tsm);
798#endif
799 return ret;
800}