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 ****************************************************************************/
42 #include "statusbar.h"
43 #include "playlist_viewer.h"
46 #include "filetypes.h"
55 #ifdef HAVE_LCD_BITMAP
58 #include "main_menu.h"
59 #include "sound_menu.h"
61 #if CONFIG_CODEC == SWCODEC
64 #include "playlist_menu.h"
67 static char* selected_file
= NULL
;
68 static int selected_file_attr
= 0;
69 static int onplay_result
= ONPLAY_OK
;
71 /* For playlist options */
72 struct playlist_args
{
77 /* ----------------------------------------------------------------------- */
78 /* Displays the bookmark menu options for the user to decide. This is an */
79 /* interface function. */
80 /* ----------------------------------------------------------------------- */
81 bool bookmark_menu(void)
85 struct menu_item items
[3];
89 if ((audio_status() & AUDIO_STATUS_PLAY
))
91 items
[i
].desc
= ID2P(LANG_BOOKMARK_MENU_CREATE
);
92 items
[i
].function
= bookmark_create_menu
;
97 items
[i
].desc
= ID2P(LANG_BOOKMARK_MENU_LIST
);
98 items
[i
].function
= bookmark_load_menu
;
103 m
=menu_init( items
, i
, NULL
, NULL
, NULL
, NULL
);
105 #ifdef HAVE_LCD_CHARCELLS
106 status_set_param(true);
108 result
= menu_run(m
);
109 #ifdef HAVE_LCD_CHARCELLS
110 status_set_param(false);
119 static bool list_viewers(void)
121 struct menu_item menu
[16];
125 i
=filetype_load_menu(menu
,sizeof(menu
)/sizeof(*menu
));
128 m
= menu_init( menu
, i
, NULL
, NULL
, NULL
, NULL
);
129 result
= menu_show(m
);
132 ret
= filetype_load_plugin((char *)menu
[result
].desc
,selected_file
);
136 /* FIX: translation! */
137 gui_syncsplash(HZ
*2, true, (unsigned char *)"No viewers found");
140 if (ret
== PLUGIN_USB_CONNECTED
)
141 onplay_result
= ONPLAY_RELOAD_DIR
;
146 static bool shuffle_playlist(void)
148 playlist_sort(NULL
, true);
149 playlist_randomise(NULL
, current_tick
, true);
154 static bool save_playlist(void)
156 save_playlist_screen(NULL
);
160 static bool add_to_playlist(int position
, bool queue
)
162 bool new_playlist
= !(audio_status() & AUDIO_STATUS_PLAY
);
165 playlist_create(NULL
, NULL
);
167 if ((selected_file_attr
& TREE_ATTR_MASK
) == TREE_ATTR_MPA
)
168 playlist_insert_track(NULL
, selected_file
, position
, queue
);
169 else if (selected_file_attr
& ATTR_DIRECTORY
)
171 bool recurse
= false;
173 if (global_settings
.recursive_dir_insert
!= RECURSE_ASK
)
174 recurse
= (bool)global_settings
.recursive_dir_insert
;
177 /* Ask if user wants to recurse directory */
181 lcd_puts_scroll(0, 0, str(LANG_RECURSE_DIRECTORY_QUESTION
));
182 lcd_puts_scroll(0, 1, (unsigned char *)selected_file
);
184 #ifdef HAVE_LCD_BITMAP
185 lcd_puts(0, 3, str(LANG_CONFIRM_WITH_PLAY_RECORDER
));
186 lcd_puts(0, 4, str(LANG_CANCEL_WITH_ANY_RECORDER
));
192 int btn
= button_get(true);
200 /* ignore button releases */
201 if (!(btn
& BUTTON_REL
))
208 playlist_insert_directory(NULL
, selected_file
, position
, queue
,
211 else if ((selected_file_attr
& TREE_ATTR_MASK
) == TREE_ATTR_M3U
)
212 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 /* Sub-menu for playlist options */
244 static bool playlist_options(void)
246 struct menu_item items
[13];
247 struct playlist_args args
[13]; /* increase these 2 if you add entries! */
248 int m
, i
=0, pstart
=0, result
;
251 if ((selected_file_attr
& TREE_ATTR_MASK
) == TREE_ATTR_M3U
&&
252 context
== CONTEXT_TREE
)
254 items
[i
].desc
= ID2P(LANG_VIEW
);
255 items
[i
].function
= view_playlist
;
260 if (audio_status() & AUDIO_STATUS_PLAY
&&
261 context
== CONTEXT_WPS
)
263 items
[i
].desc
= ID2P(LANG_VIEW_DYNAMIC_PLAYLIST
);
264 items
[i
].function
= playlist_viewer
;
268 items
[i
].desc
= ID2P(LANG_SEARCH_IN_PLAYLIST
);
269 items
[i
].function
= search_playlist
;
273 items
[i
].desc
= ID2P(LANG_SAVE_DYNAMIC_PLAYLIST
);
274 items
[i
].function
= save_playlist
;
278 items
[i
].desc
= ID2P(LANG_SHUFFLE_PLAYLIST
);
279 items
[i
].function
= shuffle_playlist
;
284 if (context
== CONTEXT_TREE
|| context
== CONTEXT_ID3DB
)
286 if (audio_status() & AUDIO_STATUS_PLAY
)
288 items
[i
].desc
= ID2P(LANG_INSERT
);
289 args
[i
].position
= PLAYLIST_INSERT
;
290 args
[i
].queue
= false;
293 items
[i
].desc
= ID2P(LANG_INSERT_FIRST
);
294 args
[i
].position
= PLAYLIST_INSERT_FIRST
;
295 args
[i
].queue
= false;
298 items
[i
].desc
= ID2P(LANG_INSERT_LAST
);
299 args
[i
].position
= PLAYLIST_INSERT_LAST
;
300 args
[i
].queue
= false;
303 items
[i
].desc
= ID2P(LANG_INSERT_SHUFFLED
);
304 args
[i
].position
= PLAYLIST_INSERT_SHUFFLED
;
305 args
[i
].queue
= false;
308 items
[i
].desc
= ID2P(LANG_QUEUE
);
309 args
[i
].position
= PLAYLIST_INSERT
;
310 args
[i
].queue
= true;
313 items
[i
].desc
= ID2P(LANG_QUEUE_FIRST
);
314 args
[i
].position
= PLAYLIST_INSERT_FIRST
;
315 args
[i
].queue
= true;
318 items
[i
].desc
= ID2P(LANG_QUEUE_LAST
);
319 args
[i
].position
= PLAYLIST_INSERT_LAST
;
320 args
[i
].queue
= true;
323 items
[i
].desc
= ID2P(LANG_QUEUE_SHUFFLED
);
324 args
[i
].position
= PLAYLIST_INSERT_SHUFFLED
;
325 args
[i
].queue
= true;
328 else if (((selected_file_attr
& TREE_ATTR_MASK
) == TREE_ATTR_MPA
) ||
329 (selected_file_attr
& ATTR_DIRECTORY
))
331 items
[i
].desc
= ID2P(LANG_INSERT
);
332 args
[i
].position
= PLAYLIST_INSERT
;
333 args
[i
].queue
= false;
338 m
= menu_init( items
, i
, NULL
, NULL
, NULL
, NULL
);
339 result
= menu_show(m
);
340 if (result
>= 0 && result
< pstart
)
341 ret
= items
[result
].function();
342 else if (result
>= pstart
)
343 ret
= add_to_playlist(args
[result
].position
, args
[result
].queue
);
350 /* helper function to remove a non-empty directory */
351 static int remove_dir(char* dirname
, int len
)
355 int dirlen
= strlen(dirname
);
357 dir
= opendir(dirname
);
359 return -1; /* open error */
363 struct dirent
* entry
;
364 /* walk through the directory content */
365 entry
= readdir(dir
);
369 /* append name to current directory */
370 snprintf(dirname
+dirlen
, len
-dirlen
, "/%s", entry
->d_name
);
372 if (entry
->attribute
& ATTR_DIRECTORY
)
373 { /* remove a subdirectory */
374 if (!strcmp((char *)entry
->d_name
, ".") ||
375 !strcmp((char *)entry
->d_name
, ".."))
376 continue; /* skip these */
378 result
= remove_dir(dirname
, len
); /* recursion */
380 break; /* or better continue, delete what we can? */
383 { /* remove a file */
384 result
= remove(dirname
);
390 { /* remove the now empty directory */
391 dirname
[dirlen
] = '\0'; /* terminate to original length */
393 result
= rmdir(dirname
);
400 /* share code for file and directory deletion, saves space */
401 static bool delete_handler(bool is_dir
)
404 (char *)str(LANG_REALLY_DELETE
),
408 (char *)str(LANG_DELETED
),
412 struct text_message message
={lines
, 2};
413 struct text_message yes_message
={yes_lines
, 2};
414 if(gui_syncyesno_run(&message
, &yes_message
, NULL
)!=YESNO_YES
)
419 char pathname
[MAX_PATH
]; /* space to go deep */
420 strncpy(pathname
, selected_file
, sizeof pathname
);
421 res
= remove_dir(pathname
, sizeof(pathname
));
424 res
= remove(selected_file
);
427 onplay_result
= ONPLAY_RELOAD_DIR
;
433 static bool delete_file(void)
435 return delete_handler(false);
438 static bool delete_dir(void)
440 return delete_handler(true);
443 #ifdef HAVE_LCD_COLOR
444 static bool set_backdrop(void)
450 bm
.data
=(char*)&main_backdrop
[0][0];
451 ret
= read_bmp_file(selected_file
, &bm
,
452 sizeof(main_backdrop
), FORMAT_NATIVE
);
454 if ((ret
> 0) && (bm
.width
== LCD_WIDTH
)
455 && (bm
.height
== LCD_HEIGHT
)) {
456 lcd_set_backdrop(&main_backdrop
[0][0]);
457 gui_syncsplash(HZ
, true, str(LANG_BACKDROP_LOADED
));
458 set_file(selected_file
, (char *)global_settings
.backdrop_file
, MAX_FILENAME
);
461 lcd_set_backdrop(NULL
);
462 gui_syncsplash(HZ
, true, str(LANG_BACKDROP_FAILED
));
468 static bool rename_file(void)
470 char newname
[MAX_PATH
];
471 char* ptr
= strrchr(selected_file
, '/') + 1;
472 int pathlen
= (ptr
- selected_file
);
473 strncpy(newname
, selected_file
, sizeof newname
);
474 if (!kbd_input(newname
+ pathlen
, (sizeof newname
)-pathlen
)) {
475 if (!strlen(newname
+ pathlen
) ||
476 (rename(selected_file
, newname
) < 0)) {
478 lcd_puts(0,0,str(LANG_RENAME
));
479 lcd_puts(0,1,str(LANG_FAILED
));
484 onplay_result
= ONPLAY_RELOAD_DIR
;
490 bool create_dir(void)
492 char dirname
[MAX_PATH
];
497 cwd
= getcwd(NULL
, 0);
498 memset(dirname
, 0, sizeof dirname
);
500 snprintf(dirname
, sizeof dirname
, "%s/",
503 pathlen
= strlen(dirname
);
504 rc
= kbd_input(dirname
+ pathlen
, (sizeof dirname
)-pathlen
);
508 rc
= mkdir(dirname
, 0);
510 gui_syncsplash(HZ
, true, (unsigned char *)"%s %s",
511 str(LANG_CREATE_DIR
), str(LANG_FAILED
));
513 onplay_result
= ONPLAY_RELOAD_DIR
;
519 static bool exit_to_main
;
521 /* catch MENU_EXIT_MENU within context menu to call the main menu afterwards */
522 static int onplay_callback(int key
, int menu
)
526 if (key
== MENU_EXIT_MENU
527 #ifdef MENU_RC_EXIT_MENU
528 || key
== MENU_RC_EXIT_MENU
536 int onplay(char* file
, int attr
, int from
)
538 #if CONFIG_CODEC == SWCODEC
539 struct menu_item items
[10]; /* increase this if you add entries! */
541 struct menu_item items
[8];
544 #ifdef HAVE_LCD_COLOR
548 onplay_result
= ONPLAY_OK
;
550 exit_to_main
= false;
551 selected_file
= file
;
552 selected_file_attr
= attr
;
554 if (context
== CONTEXT_WPS
)
556 items
[i
].desc
= ID2P(LANG_SOUND_SETTINGS
);
557 items
[i
].function
= sound_menu
;
561 if (context
== CONTEXT_WPS
||
562 context
== CONTEXT_TREE
||
563 ((context
== CONTEXT_ID3DB
) &&
564 (attr
& TREE_ATTR_MASK
) == TREE_ATTR_MPA
))
566 items
[i
].desc
= ID2P(LANG_PLAYLIST
);
567 items
[i
].function
= playlist_options
;
571 if (context
== CONTEXT_WPS
)
573 items
[i
].desc
= ID2P(LANG_BOOKMARK_MENU
);
574 items
[i
].function
= bookmark_menu
;
580 if (context
== CONTEXT_WPS
)
582 items
[i
].desc
= ID2P(LANG_MENU_SHOW_ID3_INFO
);
583 items
[i
].function
= browse_id3
;
585 if(rundb_initialized
) {
586 items
[i
].desc
= ID2P(LANG_MENU_SET_RATING
);
587 items
[i
].function
= set_rating
;
592 #ifdef HAVE_MULTIVOLUME
593 if (!(attr
& ATTR_VOLUME
)) /* no rename+delete for volumes */
596 if (context
== CONTEXT_TREE
)
598 items
[i
].desc
= ID2P(LANG_RENAME
);
599 items
[i
].function
= rename_file
;
603 if (!(attr
& ATTR_DIRECTORY
) && context
== CONTEXT_TREE
)
605 items
[i
].desc
= ID2P(LANG_DELETE
);
606 items
[i
].function
= delete_file
;
609 #ifdef HAVE_LCD_COLOR
610 suffix
= strrchr(file
, '.');
612 if (strcasecmp(suffix
, ".bmp") == 0) {
613 items
[i
].desc
= ID2P(LANG_SET_AS_BACKDROP
);
614 items
[i
].function
= set_backdrop
;
622 if (context
== CONTEXT_TREE
)
624 items
[i
].desc
= ID2P(LANG_DELETE_DIR
);
625 items
[i
].function
= delete_dir
;
631 if (!(attr
& ATTR_DIRECTORY
))
633 items
[i
].desc
= ID2P(LANG_ONPLAY_OPEN_WITH
);
634 items
[i
].function
= list_viewers
;
639 if (context
== CONTEXT_TREE
)
641 items
[i
].desc
= ID2P(LANG_CREATE_DIR
);
642 items
[i
].function
= create_dir
;
646 #if CONFIG_CODEC == SWCODEC
647 /* Equalizer menu items */
648 if (context
== CONTEXT_WPS
)
650 items
[i
].desc
= ID2P(LANG_EQUALIZER_GRAPHICAL
);
651 items
[i
].function
= eq_menu_graphical
;
653 items
[i
].desc
= ID2P(LANG_EQUALIZER_BROWSE
);
654 items
[i
].function
= eq_browse_presets
;
659 /* DIY menu handling, since we want to exit after selection */
662 m
= menu_init( items
, i
, onplay_callback
, NULL
, NULL
, NULL
);
663 result
= menu_show(m
);
665 items
[result
].function();
669 result
= main_menu();
671 #ifdef HAVE_LCD_BITMAP
672 if (global_settings
.statusbar
)
673 lcd_setmargins(0, STATUSBAR_HEIGHT
);
675 lcd_setmargins(0, 0);
679 return onplay_result
;