1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
43 #include "statusbar.h"
44 #include "playlist_viewer.h"
47 #include "filetypes.h"
56 #ifdef HAVE_LCD_BITMAP
59 #include "main_menu.h"
60 #include "sound_menu.h"
61 #if CONFIG_CODEC == SWCODEC
64 #include "playlist_menu.h"
65 #include "playlist_catalog.h"
71 static char* selected_file
= NULL
;
72 static int selected_file_attr
= 0;
73 static int onplay_result
= ONPLAY_OK
;
74 static char clipboard_selection
[MAX_PATH
];
75 static int clipboard_selection_attr
= 0;
76 static bool clipboard_is_copy
= false;
78 /* For playlist options */
79 struct playlist_args
{
84 /* ----------------------------------------------------------------------- */
85 /* Displays the bookmark menu options for the user to decide. This is an */
86 /* interface function. */
87 /* ----------------------------------------------------------------------- */
88 static bool bookmark_menu(void)
92 struct menu_item items
[3];
96 if ((audio_status() & AUDIO_STATUS_PLAY
))
98 items
[i
].desc
= ID2P(LANG_BOOKMARK_MENU_CREATE
);
99 items
[i
].function
= bookmark_create_menu
;
102 if (bookmark_exist())
104 items
[i
].desc
= ID2P(LANG_BOOKMARK_MENU_LIST
);
105 items
[i
].function
= bookmark_load_menu
;
110 m
=menu_init( items
, i
, NULL
, NULL
, NULL
, NULL
);
112 #ifdef HAVE_LCD_CHARCELLS
113 status_set_param(true);
115 result
= menu_run(m
);
116 #ifdef HAVE_LCD_CHARCELLS
117 status_set_param(false);
126 static bool list_viewers(void)
128 struct menu_item menu
[16];
132 i
=filetype_load_menu(menu
,sizeof(menu
)/sizeof(*menu
));
135 m
= menu_init( menu
, i
, NULL
, NULL
, NULL
, NULL
);
136 result
= menu_show(m
);
139 ret
= filetype_load_plugin((char *)menu
[result
].desc
,selected_file
);
143 /* FIX: translation! */
144 gui_syncsplash(HZ
*2, true, (unsigned char *)"No viewers found");
147 if (ret
== PLUGIN_USB_CONNECTED
)
148 onplay_result
= ONPLAY_RELOAD_DIR
;
153 static bool shuffle_playlist(void)
155 playlist_sort(NULL
, true);
156 playlist_randomise(NULL
, current_tick
, true);
161 static bool save_playlist(void)
163 save_playlist_screen(NULL
);
167 static bool add_to_playlist(int position
, bool queue
)
169 bool new_playlist
= !(audio_status() & AUDIO_STATUS_PLAY
);
171 (char *)str(LANG_RECURSE_DIRECTORY_QUESTION
),
174 struct text_message message
={lines
, 2};
176 gui_syncsplash(0, true, str(LANG_WAIT
));
179 playlist_create(NULL
, NULL
);
181 /* always set seed before inserting shuffled */
182 if (position
== PLAYLIST_INSERT_SHUFFLED
)
186 if (context
== CONTEXT_ID3DB
)
188 tagtree_insert_selection_playlist(position
, queue
);
193 if ((selected_file_attr
& TREE_ATTR_MASK
) == TREE_ATTR_MPA
)
194 playlist_insert_track(NULL
, selected_file
, position
, queue
, true);
195 else if (selected_file_attr
& ATTR_DIRECTORY
)
197 bool recurse
= false;
199 if (global_settings
.recursive_dir_insert
!= RECURSE_ASK
)
200 recurse
= (bool)global_settings
.recursive_dir_insert
;
203 /* Ask if user wants to recurse directory */
204 recurse
= (gui_syncyesno_run(&message
, NULL
, NULL
)==YESNO_YES
);
207 playlist_insert_directory(NULL
, selected_file
, position
, queue
,
210 else if ((selected_file_attr
& TREE_ATTR_MASK
) == TREE_ATTR_M3U
)
211 playlist_insert_playlist(NULL
, selected_file
, position
, queue
);
214 if (new_playlist
&& (playlist_amount() > 0))
216 /* nothing is currently playing so begin playing what we just
218 if (global_settings
.playlist_shuffle
)
219 playlist_shuffle(current_tick
, -1);
221 gui_syncstatusbar_draw(&statusbars
, false);
222 onplay_result
= ONPLAY_START_PLAY
;
228 static bool view_playlist(void)
230 bool was_playing
= audio_status() & AUDIO_STATUS_PLAY
;
233 result
= playlist_viewer_ex(selected_file
);
235 if (!was_playing
&& (audio_status() & AUDIO_STATUS_PLAY
) &&
236 onplay_result
== ONPLAY_OK
)
237 /* playlist was started from viewer */
238 onplay_result
= ONPLAY_START_PLAY
;
243 static bool cat_add_to_a_playlist(void)
245 return catalog_add_to_a_playlist(selected_file
, selected_file_attr
,
249 static bool cat_add_to_a_new_playlist(void)
251 return catalog_add_to_a_playlist(selected_file
, selected_file_attr
, true);
254 static bool cat_playlist_options(void)
256 struct menu_item items
[3];
260 if ((audio_status() & AUDIO_STATUS_PLAY
&& context
== CONTEXT_WPS
) ||
261 context
== CONTEXT_TREE
)
263 if (context
== CONTEXT_WPS
)
265 items
[i
].desc
= ID2P(LANG_CATALOG_VIEW
);
266 items
[i
].function
= catalog_view_playlists
;
270 items
[i
].desc
= ID2P(LANG_CATALOG_ADD_TO
);
271 items
[i
].function
= cat_add_to_a_playlist
;
273 items
[i
].desc
= ID2P(LANG_CATALOG_ADD_TO_NEW
);
274 items
[i
].function
= cat_add_to_a_new_playlist
;
278 m
= menu_init( items
, i
, NULL
, NULL
, NULL
, NULL
);
279 result
= menu_show(m
);
281 ret
= items
[result
].function();
287 /* Sub-menu for playlist options */
288 static bool playlist_options(void)
290 struct menu_item items
[13];
291 struct playlist_args args
[13]; /* increase these 2 if you add entries! */
292 int m
, i
=0, pstart
=0, result
;
295 if ((selected_file_attr
& TREE_ATTR_MASK
) == TREE_ATTR_M3U
&&
296 context
== CONTEXT_TREE
)
298 items
[i
].desc
= ID2P(LANG_VIEW
);
299 items
[i
].function
= view_playlist
;
304 if (audio_status() & AUDIO_STATUS_PLAY
&&
305 context
== CONTEXT_WPS
)
307 items
[i
].desc
= ID2P(LANG_VIEW_DYNAMIC_PLAYLIST
);
308 items
[i
].function
= playlist_viewer
;
312 items
[i
].desc
= ID2P(LANG_SEARCH_IN_PLAYLIST
);
313 items
[i
].function
= search_playlist
;
317 items
[i
].desc
= ID2P(LANG_SAVE_DYNAMIC_PLAYLIST
);
318 items
[i
].function
= save_playlist
;
322 items
[i
].desc
= ID2P(LANG_SHUFFLE_PLAYLIST
);
323 items
[i
].function
= shuffle_playlist
;
328 if (context
== CONTEXT_TREE
|| context
== CONTEXT_ID3DB
)
330 if (audio_status() & AUDIO_STATUS_PLAY
)
332 items
[i
].desc
= ID2P(LANG_INSERT
);
333 args
[i
].position
= PLAYLIST_INSERT
;
334 args
[i
].queue
= false;
337 items
[i
].desc
= ID2P(LANG_INSERT_FIRST
);
338 args
[i
].position
= PLAYLIST_INSERT_FIRST
;
339 args
[i
].queue
= false;
342 items
[i
].desc
= ID2P(LANG_INSERT_LAST
);
343 args
[i
].position
= PLAYLIST_INSERT_LAST
;
344 args
[i
].queue
= false;
347 items
[i
].desc
= ID2P(LANG_INSERT_SHUFFLED
);
348 args
[i
].position
= PLAYLIST_INSERT_SHUFFLED
;
349 args
[i
].queue
= false;
352 items
[i
].desc
= ID2P(LANG_QUEUE
);
353 args
[i
].position
= PLAYLIST_INSERT
;
354 args
[i
].queue
= true;
357 items
[i
].desc
= ID2P(LANG_QUEUE_FIRST
);
358 args
[i
].position
= PLAYLIST_INSERT_FIRST
;
359 args
[i
].queue
= true;
362 items
[i
].desc
= ID2P(LANG_QUEUE_LAST
);
363 args
[i
].position
= PLAYLIST_INSERT_LAST
;
364 args
[i
].queue
= true;
367 items
[i
].desc
= ID2P(LANG_QUEUE_SHUFFLED
);
368 args
[i
].position
= PLAYLIST_INSERT_SHUFFLED
;
369 args
[i
].queue
= true;
372 items
[i
].desc
= ID2P(LANG_REPLACE
);
373 args
[i
].position
= PLAYLIST_REPLACE
;
374 args
[i
].queue
= false;
377 else if (((selected_file_attr
& TREE_ATTR_MASK
) == TREE_ATTR_MPA
) ||
378 (selected_file_attr
& ATTR_DIRECTORY
))
380 items
[i
].desc
= ID2P(LANG_INSERT
);
381 args
[i
].position
= PLAYLIST_INSERT_LAST
;
382 args
[i
].queue
= false;
385 if (selected_file_attr
& ATTR_DIRECTORY
)
387 items
[i
].desc
= ID2P(LANG_INSERT_SHUFFLED
);
388 args
[i
].position
= PLAYLIST_INSERT_SHUFFLED
;
389 args
[i
].queue
= false;
395 m
= menu_init( items
, i
, NULL
, NULL
, NULL
, NULL
);
396 result
= menu_show(m
);
397 if (result
>= 0 && result
< pstart
)
398 ret
= items
[result
].function();
399 else if (result
>= pstart
)
400 ret
= add_to_playlist(args
[result
].position
, args
[result
].queue
);
407 /* helper function to remove a non-empty directory */
408 static int remove_dir(char* dirname
, int len
)
412 int dirlen
= strlen(dirname
);
415 dir
= opendir(dirname
);
417 return -1; /* open error */
421 struct dirent
* entry
;
422 /* walk through the directory content */
423 entry
= readdir(dir
);
427 dirname
[dirlen
] ='\0';
429 screens
[i
].puts(0,1,dirname
);
431 /* append name to current directory */
432 snprintf(dirname
+dirlen
, len
-dirlen
, "/%s", entry
->d_name
);
433 if (entry
->attribute
& ATTR_DIRECTORY
)
434 { /* remove a subdirectory */
435 if (!strcmp((char *)entry
->d_name
, ".") ||
436 !strcmp((char *)entry
->d_name
, ".."))
437 continue; /* skip these */
439 /* inform the user which dir we're deleting */
441 result
= remove_dir(dirname
, len
); /* recursion */
443 break; /* or better continue, delete what we can? */
446 { /* remove a file */
448 screens
[i
].puts_scroll(0,2,entry
->d_name
);
449 result
= remove(dirname
);
451 #ifdef HAVE_LCD_BITMAP
455 if(ACTION_STD_CANCEL
== get_action(CONTEXT_STD
,TIMEOUT_NOBLOCK
))
457 gui_syncsplash(HZ
, true, str(LANG_MENU_SETTING_CANCEL
));
465 { /* remove the now empty directory */
466 dirname
[dirlen
] = '\0'; /* terminate to original length */
468 result
= rmdir(dirname
);
475 /* share code for file and directory deletion, saves space */
476 static bool delete_handler(bool is_dir
)
479 (char *)str(LANG_REALLY_DELETE
),
483 (char *)str(LANG_DELETED
),
487 struct text_message message
={lines
, 2};
488 struct text_message yes_message
={yes_lines
, 2};
489 if(gui_syncyesno_run(&message
, &yes_message
, NULL
)!=YESNO_YES
)
494 char pathname
[MAX_PATH
]; /* space to go deep */
496 strncpy(pathname
, selected_file
, sizeof pathname
);
497 res
= remove_dir(pathname
, sizeof(pathname
));
501 res
= remove(selected_file
);
504 onplay_result
= ONPLAY_RELOAD_DIR
;
510 static bool delete_file(void)
512 return delete_handler(false);
515 static bool delete_dir(void)
517 return delete_handler(true);
521 static bool set_backdrop(void)
524 if(load_main_backdrop(selected_file
)) {
525 gui_syncsplash(HZ
, true, str(LANG_BACKDROP_LOADED
));
526 set_file(selected_file
, (char *)global_settings
.backdrop_file
, MAX_FILENAME
);
527 show_main_backdrop();
530 gui_syncsplash(HZ
, true, str(LANG_BACKDROP_FAILED
));
536 static bool rename_file(void)
538 char newname
[MAX_PATH
];
539 char* ptr
= strrchr(selected_file
, '/') + 1;
540 int pathlen
= (ptr
- selected_file
);
541 strncpy(newname
, selected_file
, sizeof newname
);
542 if (!kbd_input(newname
+ pathlen
, (sizeof newname
)-pathlen
)) {
543 if (!strlen(newname
+ pathlen
) ||
544 (rename(selected_file
, newname
) < 0)) {
546 lcd_puts(0,0,str(LANG_RENAME
));
547 lcd_puts(0,1,str(LANG_FAILED
));
552 onplay_result
= ONPLAY_RELOAD_DIR
;
558 static bool create_dir(void)
560 char dirname
[MAX_PATH
];
565 cwd
= getcwd(NULL
, 0);
566 memset(dirname
, 0, sizeof dirname
);
568 snprintf(dirname
, sizeof dirname
, "%s/",
571 pathlen
= strlen(dirname
);
572 rc
= kbd_input(dirname
+ pathlen
, (sizeof dirname
)-pathlen
);
576 rc
= mkdir(dirname
, 0);
578 gui_syncsplash(HZ
, true, (unsigned char *)"%s %s",
579 str(LANG_CREATE_DIR
), str(LANG_FAILED
));
581 onplay_result
= ONPLAY_RELOAD_DIR
;
587 static bool properties(void)
589 if(PLUGIN_USB_CONNECTED
== filetype_load_plugin("properties",
591 onplay_result
= ONPLAY_RELOAD_DIR
;
595 /* Store the current selection in the clipboard */
596 static bool clipboard_clip(bool copy
)
598 clipboard_selection
[0] = 0;
599 strncpy(clipboard_selection
, selected_file
, MAX_PATH
);
600 clipboard_selection_attr
= selected_file_attr
;
601 clipboard_is_copy
= copy
;
606 static bool clipboard_cut(void)
608 return clipboard_clip(false);
611 static bool clipboard_copy(void)
613 return clipboard_clip(true);
616 /* Paste a file to a new directory. Will overwrite always. */
617 static bool clipboard_pastefile(const char *src
, const char *target
, bool copy
)
619 int src_fd
, target_fd
, buffersize
, size
, bytesread
, byteswritten
;
624 /* See if we can get the plugin buffer for the file copy buffer */
625 buffer
= (char *) plugin_get_buffer(&buffersize
);
626 if (buffer
== NULL
|| buffersize
< 512) {
627 /* Not large enough, try for a disk sector worth of stack instead */
629 buffer
= (char *) __builtin_alloca(buffersize
);
632 if (buffer
== NULL
) {
636 buffersize
&= ~0x1ff; /* Round buffer size to multiple of sector size */
638 src_fd
= open(src
, O_RDONLY
);
641 target_fd
= creat(target
, O_WRONLY
);
643 if (target_fd
>= 0) {
646 size
= filesize(src_fd
);
653 bytesread
= read(src_fd
, buffer
, buffersize
);
655 if (bytesread
== -1) {
662 while(bytesread
> 0) {
663 byteswritten
= write(target_fd
, buffer
, bytesread
);
665 if (byteswritten
== -1) {
671 bytesread
-= byteswritten
;
677 /* Copy failed. Cleanup. */
686 result
= rename(src
, target
) == 0;
687 #ifdef HAVE_MULTIVOLUME
689 if (errno
== EXDEV
) {
690 /* Failed because cross volume rename doesn't work. Copy instead */
691 result
= clipboard_pastefile(src
, target
, true);
694 result
= remove(src
);
704 /* Paste a directory to a new location. Designed to be called by clipboard_paste */
705 static bool clipboard_pastedirectory(char *src
, int srclen
, char *target
, int targetlen
, bool copy
)
708 int srcdirlen
= strlen(src
);
709 int targetdirlen
= strlen(target
);
713 /* Check if the target exists */
714 fd
= open(target
, O_RDONLY
);
719 /* Just move the directory */
720 result
= rename(src
, target
) == 0;
722 #ifdef HAVE_MULTIVOLUME
723 if (!result
&& errno
== EXDEV
) {
724 /* Try a copy as we're going across devices */
725 result
= clipboard_pastedirectory(src
, srclen
, target
, targetlen
, true);
727 /* If it worked, remove the source directory */
729 remove_dir(src
, srclen
);
735 /* Make a directory to copy things to */
736 result
= mkdir(target
, 0) == 0;
740 /* Check if something went wrong already */
745 srcdir
= opendir(src
);
750 /* This loop will exit as soon as there's a problem */
753 struct dirent
* entry
;
754 /* walk through the directory content */
755 entry
= readdir(srcdir
);
759 /* append name to current directory */
760 snprintf(src
+srcdirlen
, srclen
-srcdirlen
, "/%s", entry
->d_name
);
761 snprintf(target
+targetdirlen
, targetlen
-targetdirlen
, "/%s", entry
->d_name
);
763 DEBUGF("Copy %s to %s\n", src
, target
);
765 if (entry
->attribute
& ATTR_DIRECTORY
)
766 { /* copy/move a subdirectory */
767 if (!strcmp((char *)entry
->d_name
, ".") ||
768 !strcmp((char *)entry
->d_name
, ".."))
769 continue; /* skip these */
771 result
= clipboard_pastedirectory(src
, srclen
, target
, targetlen
, copy
); /* recursion */
774 { /* copy/move a file */
775 result
= clipboard_pastefile(src
, target
, copy
);
782 src
[srcdirlen
] = '\0'; /* terminate to original length */
783 target
[targetdirlen
] = '\0'; /* terminate to original length */
789 /* Paste the clipboard to the current directory */
790 static bool clipboard_paste(void)
792 char target
[MAX_PATH
];
797 unsigned char *lines
[]={str(LANG_REALLY_OVERWRITE
)};
798 struct text_message message
={(char **)lines
, 1};
800 /* Get the name of the current directory */
801 cwd
= getcwd(NULL
, 0);
802 snprintf(target
, sizeof target
, "%s", cwd
[1] ? cwd
: "");
804 /* Figure out the name of the selection */
805 nameptr
= strrchr(clipboard_selection
, '/');
807 /* Paste the name on to the current directory to give us our final target */
808 strcat(target
, nameptr
);
810 /* Check if we're going to overwrite */
811 target_fd
= open(target
, O_RDONLY
);
814 /* If the target existed but they choose not to overwite, exit */
815 if (target_fd
>= 0 &&
816 (gui_syncyesno_run(&message
, NULL
, NULL
) == YESNO_NO
)) {
820 /* Now figure out what we're doing */
821 if (clipboard_selection_attr
& ATTR_DIRECTORY
) {
822 /* Recursion. Set up external stack */
823 char srcpath
[MAX_PATH
];
824 char targetpath
[MAX_PATH
];
826 strncpy(srcpath
, clipboard_selection
, sizeof srcpath
);
827 strncpy(targetpath
, target
, sizeof targetpath
);
829 success
= clipboard_pastedirectory(srcpath
, sizeof(srcpath
), target
, sizeof(targetpath
), clipboard_is_copy
);
831 success
= clipboard_pastefile(clipboard_selection
, target
, clipboard_is_copy
);
836 /* Reset everything */
837 clipboard_selection
[0] = 0;
838 clipboard_selection_attr
= 0;
839 clipboard_is_copy
= false;
841 /* Force reload of the current directory */
842 onplay_result
= ONPLAY_RELOAD_DIR
;
844 gui_syncsplash(HZ
, true, (unsigned char *)"%s %s",
845 str(LANG_PASTE
), str(LANG_FAILED
));
851 static bool exit_to_main
;
853 /* catch MENU_EXIT_MENU within context menu to call the main menu afterwards */
854 static int onplay_callback(int key
, int menu
)
858 if (key
== ACTION_STD_MENU
)
864 int onplay(char* file
, int attr
, int from
)
866 #if CONFIG_CODEC == SWCODEC
867 struct menu_item items
[14]; /* increase this if you add entries! */
869 struct menu_item items
[12];
876 onplay_result
= ONPLAY_OK
;
878 exit_to_main
= false;
879 selected_file
= file
;
880 selected_file_attr
= attr
;
882 if (context
== CONTEXT_WPS
)
884 items
[i
].desc
= ID2P(LANG_SOUND_SETTINGS
);
885 items
[i
].function
= sound_menu
;
889 if (context
== CONTEXT_WPS
||
890 context
== CONTEXT_TREE
||
891 context
== CONTEXT_ID3DB
)
893 items
[i
].desc
= ID2P(LANG_PLAYLIST
);
894 items
[i
].function
= playlist_options
;
896 items
[i
].desc
= ID2P(LANG_CATALOG
);
897 items
[i
].function
= cat_playlist_options
;
901 if (context
== CONTEXT_WPS
)
903 items
[i
].desc
= ID2P(LANG_BOOKMARK_MENU
);
904 items
[i
].function
= bookmark_menu
;
910 if (context
== CONTEXT_WPS
)
912 items
[i
].desc
= ID2P(LANG_MENU_SHOW_ID3_INFO
);
913 items
[i
].function
= browse_id3
;
915 /* if(rundb_initialized)
917 items[i].desc = ID2P(LANG_MENU_SET_RATING);
918 items[i].function = set_rating;
923 #ifdef HAVE_MULTIVOLUME
924 if (!(attr
& ATTR_VOLUME
)) /* no rename+delete for volumes */
927 if (context
== CONTEXT_TREE
)
929 items
[i
].desc
= ID2P(LANG_RENAME
);
930 items
[i
].function
= rename_file
;
933 items
[i
].desc
= ID2P(LANG_CUT
);
934 items
[i
].function
= clipboard_cut
;
937 items
[i
].desc
= ID2P(LANG_COPY
);
938 items
[i
].function
= clipboard_copy
;
941 if (clipboard_selection
[0] != 0) /* Something in the clipboard? */
943 items
[i
].desc
= ID2P(LANG_PASTE
);
944 items
[i
].function
= clipboard_paste
;
949 if (!(attr
& ATTR_DIRECTORY
) && context
== CONTEXT_TREE
)
951 items
[i
].desc
= ID2P(LANG_DELETE
);
952 items
[i
].function
= delete_file
;
956 suffix
= strrchr(file
, '.');
959 if (strcasecmp(suffix
, ".bmp") == 0)
961 items
[i
].desc
= ID2P(LANG_SET_AS_BACKDROP
);
962 items
[i
].function
= set_backdrop
;
970 if (context
== CONTEXT_TREE
)
972 items
[i
].desc
= ID2P(LANG_DELETE_DIR
);
973 items
[i
].function
= delete_dir
;
979 if (!(attr
& ATTR_DIRECTORY
))
981 items
[i
].desc
= ID2P(LANG_ONPLAY_OPEN_WITH
);
982 items
[i
].function
= list_viewers
;
988 if (strlen(clipboard_selection
) != 0)
990 items
[i
].desc
= ID2P(LANG_PASTE
);
991 items
[i
].function
= clipboard_paste
;
996 if (context
== CONTEXT_TREE
)
998 items
[i
].desc
= ID2P(LANG_CREATE_DIR
);
999 items
[i
].function
= create_dir
;
1002 items
[i
].desc
= ID2P(LANG_PROPERTIES
);
1003 items
[i
].function
= properties
;
1007 if (context
== CONTEXT_WPS
)
1009 #ifdef HAVE_PITCHSCREEN
1010 /* Pitch screen access */
1011 items
[i
].desc
= ID2P(LANG_PITCH
);
1012 items
[i
].function
= pitch_screen
;
1015 #if CONFIG_CODEC == SWCODEC
1016 /* Equalizer menu items */
1017 items
[i
].desc
= ID2P(LANG_EQUALIZER_GRAPHICAL
);
1018 items
[i
].function
= eq_menu_graphical
;
1020 items
[i
].desc
= ID2P(LANG_EQUALIZER_BROWSE
);
1021 items
[i
].function
= eq_browse_presets
;
1026 /* DIY menu handling, since we want to exit after selection */
1029 m
= menu_init( items
, i
, onplay_callback
, NULL
, NULL
, NULL
);
1030 result
= menu_show(m
);
1032 items
[result
].function();
1036 result
= main_menu();
1038 #ifdef HAVE_LCD_BITMAP
1039 if (global_settings
.statusbar
)
1040 lcd_setmargins(0, STATUSBAR_HEIGHT
);
1042 lcd_setmargins(0, 0);
1046 return onplay_result
;