A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 800 lines 28 kB view raw
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}