Revert change 13001, since it causes the metadata to be re-read for partially buffere...
[kugel-rb.git] / apps / playlist_viewer.c
blobd065ad32ced267237b36563430f54df8b2f85ba6
1 /***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 * $Id$
11 * Copyright (C) 2003 Hardeep Sidhu
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
21 * Kevin Ferrare 2005/10/16
22 * multi-screen support, rewrote a lot of code
24 #include <string.h>
25 #include <sprintf.h>
26 #include "playlist.h"
27 #include "audio.h"
28 #include "screens.h"
29 #include "status.h"
30 #include "settings.h"
31 #include "icons.h"
32 #include "menu.h"
33 #include "plugin.h"
34 #include "keyboard.h"
35 #include "tree.h"
36 #include "onplay.h"
37 #include "talk.h"
38 #include "misc.h"
39 #include "action.h"
40 #include "debug.h"
41 #include "backlight.h"
43 #include "lang.h"
45 #include "playlist_viewer.h"
46 #include "playlist_catalog.h"
47 #include "icon.h"
48 #include "list.h"
49 #include "statusbar.h"
50 #include "splash.h"
51 #include "playlist_menu.h"
52 #include "action.h"
54 /* Maximum number of tracks we can have loaded at one time */
55 #define MAX_PLAYLIST_ENTRIES 200
57 /* The number of items between the selected one and the end/start of
58 * the buffer under which the buffer must reload */
59 #define MIN_BUFFER_MARGIN (screens[0].nb_lines+1)
61 /* Information about a specific track */
62 struct playlist_entry {
63 char *name; /* Formatted track name */
64 int index; /* Playlist index */
65 int display_index; /* Display index */
66 bool queued; /* Is track queued? */
67 bool skipped; /* Is track marked as bad? */
70 enum direction
72 FORWARD,
73 BACKWARD
76 struct playlist_buffer
78 char *name_buffer; /* Buffer used to store track names */
79 int buffer_size; /* Size of name buffer */
81 int first_index; /* Real index of first track loaded inside
82 the buffer */
84 enum direction direction; /* Direction of the buffer (if the buffer
85 was loaded BACKWARD, the last track in
86 the buffer has a real index < to the
87 real index of the the first track)*/
89 struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES];
90 int num_loaded; /* Number of track entries loaded in buffer */
93 /* Global playlist viewer settings */
94 struct playlist_viewer {
95 struct playlist_info* playlist; /* playlist being viewed */
96 int num_tracks; /* Number of tracks in playlist */
97 int current_playing_track; /* Index of current playing track */
98 int selected_track; /* The selected track, relative (first is 0)*/
99 int move_track; /* Playlist index of track to move or -1 */
100 struct playlist_buffer buffer;
103 static struct playlist_viewer viewer;
105 /* Used when viewing playlists on disk */
106 static struct playlist_info temp_playlist;
108 static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
109 int names_buffer_size);
110 static void playlist_buffer_load_entries(struct playlist_buffer * pb, int index,
111 enum direction direction);
112 static int playlist_entry_load(struct playlist_entry *entry, int index,
113 char* name_buffer, int remaining_size);
115 static struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer *pb,
116 int index);
118 static bool playlist_viewer_init(struct playlist_viewer * viewer,
119 char* filename, bool reload);
121 static void format_name(char* dest, const char* src);
122 static void format_line(const struct playlist_entry* track, char* str,
123 int len);
125 static bool update_playlist(bool force);
126 static int onplay_menu(int index);
127 static bool viewer_menu(void);
128 static bool show_icons(void);
129 static bool show_indices(void);
130 static bool track_display(void);
131 static bool save_playlist(void);
133 static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
134 int names_buffer_size)
136 pb->name_buffer=names_buffer;
137 pb->buffer_size=names_buffer_size;
138 pb->first_index=0;
139 pb->num_loaded=0;
143 * Loads the entries following 'index' in the playlist buffer
145 static void playlist_buffer_load_entries(struct playlist_buffer *pb, int index,
146 enum direction direction)
148 int num_entries = viewer.num_tracks;
149 char* p = pb->name_buffer;
150 int remaining = pb->buffer_size;
151 int i;
153 pb->first_index = index;
154 if (num_entries > MAX_PLAYLIST_ENTRIES)
155 num_entries = MAX_PLAYLIST_ENTRIES;
157 for(i=0; i<num_entries; i++)
159 int len = playlist_entry_load(&(pb->tracks[i]), index, p, remaining);
160 if (len < 0)
162 /* Out of name buffer space */
163 num_entries = i;
164 break;
167 p += len;
168 remaining -= len;
170 if(direction==FORWARD)
171 index++;
172 else
173 index--;
174 index+=viewer.num_tracks;
175 index%=viewer.num_tracks;
177 pb->direction=direction;
178 pb->num_loaded = i;
181 static void playlist_buffer_load_entries_screen(struct playlist_buffer * pb,
182 enum direction direction)
184 if(direction==FORWARD)
186 int min_start=viewer.selected_track-2*screens[0].nb_lines;
187 while(min_start<0)
188 min_start+=viewer.num_tracks;
189 min_start %= viewer.num_tracks;
190 playlist_buffer_load_entries(pb, min_start, FORWARD);
192 else
194 int max_start=viewer.selected_track+2*screens[0].nb_lines;
195 max_start%=viewer.num_tracks;
196 playlist_buffer_load_entries(pb, max_start, BACKWARD);
200 static int playlist_entry_load(struct playlist_entry *entry, int index,
201 char* name_buffer, int remaining_size)
203 struct playlist_track_info info;
204 int len;
206 /* Playlist viewer orders songs based on display index. We need to
207 convert to real playlist index to access track */
208 index = (index + playlist_get_first_index(viewer.playlist)) %
209 viewer.num_tracks;
210 if (playlist_get_track_info(viewer.playlist, index, &info) < 0)
211 return -1;
213 len = strlen(info.filename) + 1;
215 if (len <= remaining_size)
217 strcpy(name_buffer, info.filename);
219 entry->name = name_buffer;
220 entry->index = info.index;
221 entry->display_index = info.display_index;
222 entry->queued = info.attr & PLAYLIST_ATTR_QUEUED;
223 entry->skipped = info.attr & PLAYLIST_ATTR_SKIPPED;
224 return len;
226 return -1;
229 static int playlist_buffer_get_index(struct playlist_buffer *pb, int index )
231 int buffer_index;
232 if(pb->direction==FORWARD)
234 if(index>=pb->first_index)
235 buffer_index=index-pb->first_index;
236 else /* rotation : track0 in buffer + requested track */
237 buffer_index=(viewer.num_tracks-pb->first_index)+(index);
239 else
241 if(index<=pb->first_index)
242 buffer_index=pb->first_index-index;
243 else /* rotation : track0 in buffer + dist from the last track
244 to the requested track (num_tracks-requested track) */
245 buffer_index=(pb->first_index)+(viewer.num_tracks-index);
247 return(buffer_index);
250 #define distance(a, b) \
251 a>b? (a) - (b) : (b) - (a)
252 static bool playlist_buffer_needs_reload(struct playlist_buffer* pb, int track_index)
254 if(pb->num_loaded==viewer.num_tracks)
255 return(false);
256 int selected_index=playlist_buffer_get_index(pb, track_index);
257 int first_buffer_index=playlist_buffer_get_index(pb, pb->first_index);
258 int distance_beginning=distance(selected_index, first_buffer_index);
259 if(distance_beginning<MIN_BUFFER_MARGIN)
260 return(true);
262 if(pb->num_loaded - distance_beginning < MIN_BUFFER_MARGIN)
263 return(true);
264 return(false);
267 static struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer *pb,
268 int index)
270 int buffer_index=playlist_buffer_get_index(pb, index);
271 return(&(pb->tracks[buffer_index]));
274 /* Initialize the playlist viewer. */
275 static bool playlist_viewer_init(struct playlist_viewer * viewer,
276 char* filename, bool reload)
278 char* buffer;
279 int buffer_size;
280 bool is_playing = audio_status() & AUDIO_STATUS_PLAY;
282 if (!filename && !is_playing)
283 /* Nothing is playing, exit */
284 return false;
286 buffer = plugin_get_buffer(&buffer_size);
287 if (!buffer)
288 return false;
290 if (!filename)
291 viewer->playlist = NULL;
292 else
294 /* Viewing playlist on disk */
295 char *dir, *file, *temp_ptr;
296 char *index_buffer = NULL;
297 int index_buffer_size = 0;
299 viewer->playlist = &temp_playlist;
301 /* Separate directory from filename */
302 temp_ptr = strrchr(filename+1,'/');
303 if (temp_ptr)
305 *temp_ptr = 0;
306 dir = filename;
307 file = temp_ptr + 1;
309 else
311 dir = "/";
312 file = filename+1;
315 if (is_playing)
317 /* Something is playing, use half the plugin buffer for playlist
318 indices */
319 index_buffer_size = buffer_size / 2;
320 index_buffer = buffer;
323 playlist_create_ex(viewer->playlist, dir, file, index_buffer,
324 index_buffer_size, buffer+index_buffer_size,
325 buffer_size-index_buffer_size);
327 if (temp_ptr)
328 *temp_ptr = '/';
330 buffer += index_buffer_size;
331 buffer_size -= index_buffer_size;
333 playlist_buffer_init(&viewer->buffer, buffer, buffer_size );
335 viewer->move_track = -1;
337 if (!reload)
339 if (viewer->playlist)
340 viewer->selected_track = 0;
341 else
342 viewer->selected_track = playlist_get_display_index() - 1;
345 if (!update_playlist(true))
346 return false;
347 return true;
350 /* Format trackname for display purposes */
351 static void format_name(char* dest, const char* src)
353 switch (global_settings.playlist_viewer_track_display)
355 case 0:
356 default:
358 /* Only display the filename */
359 char* p = strrchr(src, '/');
361 strcpy(dest, p+1);
363 /* Remove the extension */
364 char* q = strrchr(dest, '.');
366 if (q != NULL)
367 *q = '\0';
369 break;
371 case 1:
372 /* Full path */
373 strcpy(dest, src);
374 break;
378 /* Format display line */
379 static void format_line(const struct playlist_entry* track, char* str,
380 int len)
382 char name[MAX_PATH];
383 char *skipped = "";
385 format_name(name, track->name);
387 if (track->skipped)
388 skipped = "(ERR) ";
390 if (global_settings.playlist_viewer_indices)
391 /* Display playlist index */
392 snprintf(str, len, "%d. %s%s", track->display_index, skipped, name);
393 else
394 snprintf(str, len, "%s%s", skipped, name);
398 /* Update playlist in case something has changed or forced */
399 static bool update_playlist(bool force)
401 if (!viewer.playlist)
402 playlist_get_resume_info(&viewer.current_playing_track);
403 else
404 viewer.current_playing_track = -1;
405 int nb_tracks=playlist_amount_ex(viewer.playlist);
406 force=force || nb_tracks != viewer.num_tracks;
407 if (force)
409 /* Reload tracks */
410 viewer.num_tracks = nb_tracks;
411 if (viewer.num_tracks <= 0)
412 return false;
413 playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD);
414 if (viewer.buffer.num_loaded <= 0)
415 return false;
417 return true;
420 /* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen.
421 Returns -1 if USB attached, 0 if no playlist change, and 1 if playlist
422 changed. */
423 static int onplay_menu(int index)
425 struct menu_item items[4]; /* increase this if you add entries! */
426 int m, i=0, result, ret = 0;
427 struct playlist_entry * current_track=
428 playlist_buffer_get_track(&viewer.buffer, index);
429 bool current = (current_track->index == viewer.current_playing_track);
431 items[i].desc = ID2P(LANG_REMOVE);
432 i++;
434 items[i].desc = ID2P(LANG_MOVE);
435 i++;
437 items[i].desc = ID2P(LANG_CATALOG_ADD_TO);
438 i++;
440 items[i].desc = ID2P(LANG_CATALOG_ADD_TO_NEW);
441 i++;
443 m = menu_init(items, i, NULL, str(LANG_PLAYLIST_MENU), NULL, NULL);
444 result = menu_show(m);
445 if (result == MENU_ATTACHED_USB)
447 ret = -1;
449 else if (result >= 0)
451 /* Abort current move */
452 viewer.move_track = -1;
454 switch (result)
456 case 0:
457 /* delete track */
458 playlist_delete(viewer.playlist, current_track->index);
459 if (current)
461 if (playlist_amount_ex(viewer.playlist) <= 0)
462 audio_stop();
463 else
465 /* Start playing new track except if it's the lasttrack
466 track in the playlist and repeat mode is disabled */
467 current_track =
468 playlist_buffer_get_track(&viewer.buffer, index);
469 if (current_track->display_index!=viewer.num_tracks ||
470 global_settings.repeat_mode == REPEAT_ALL)
472 #if CONFIG_CODEC != SWCODEC
473 talk_buffer_steal(); /* will use the mp3 buffer */
474 #endif
475 audio_play(0);
476 viewer.current_playing_track = -1;
480 ret = 1;
481 break;
482 case 1:
483 /* move track */
484 viewer.move_track = current_track->index;
485 ret = 0;
486 break;
487 case 2: /* add to catalog */
488 case 3: /* add to a new one */
489 catalog_add_to_a_playlist(current_track->name,
490 TREE_ATTR_MPA,
491 result==3 );
492 ret = 0;
493 break;
496 menu_exit(m);
497 return ret;
500 /* Menu of viewer options. Invoked via F1(r) or Menu(p). */
501 static bool viewer_menu(void)
503 int m;
504 bool result;
506 static const struct menu_item items[] = {
507 { ID2P(LANG_SHOW_ICONS), show_icons },
508 { ID2P(LANG_SHOW_INDICES), show_indices },
509 { ID2P(LANG_TRACK_DISPLAY), track_display },
510 { ID2P(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
513 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
514 NULL, NULL, NULL );
515 result = menu_run(m);
516 menu_exit(m);
518 settings_save();
520 return result;
523 /* Show icons in viewer? */
524 static bool show_icons(void)
526 return set_bool((char *)str(LANG_SHOW_ICONS),
527 &global_settings.playlist_viewer_icons);
530 /* Show indices of tracks? */
531 static bool show_indices(void)
533 return set_bool((char *)str(LANG_SHOW_INDICES),
534 &global_settings.playlist_viewer_indices);
537 /* How to display a track */
538 static bool track_display(void)
540 static const struct opt_items names[] = {
541 { STR(LANG_DISPLAY_TRACK_NAME_ONLY) },
542 { STR(LANG_DISPLAY_FULL_PATH) }
545 return set_option((char *)str(LANG_TRACK_DISPLAY),
546 &global_settings.playlist_viewer_track_display, INT, names, 2,
547 NULL);
550 /* Save playlist to disk */
551 static bool save_playlist(void)
553 save_playlist_screen(viewer.playlist);
554 return false;
557 /* View current playlist */
558 bool playlist_viewer(void)
560 return playlist_viewer_ex(NULL);
563 static char *playlist_callback_name(int selected_item, void *data, char *buffer)
565 struct playlist_viewer * local_viewer = (struct playlist_viewer *)data;
566 struct playlist_entry *track=
567 playlist_buffer_get_track(&(local_viewer->buffer), selected_item);
568 format_line(track, buffer, MAX_PATH);
569 return(buffer);
573 static void playlist_callback_icons(int selected_item, void *data, ICON * icon)
575 struct playlist_viewer * local_viewer=(struct playlist_viewer *)data;
576 struct playlist_entry *track=
577 playlist_buffer_get_track(&(local_viewer->buffer), selected_item);
578 if (track->index == local_viewer->current_playing_track)
580 /* Current playing track */
581 #ifdef HAVE_LCD_BITMAP
582 *icon=bitmap_icons_6x8[Icon_Audio];
583 #else
584 *icon=Icon_Audio;
585 #endif
587 else if (track->index == local_viewer->move_track)
589 /* Track we are moving */
590 #ifdef HAVE_LCD_BITMAP
591 *icon=bitmap_icons_6x8[Icon_Moving];
592 #else
593 *icon=Icon_Moving;
594 #endif
596 else if (track->queued)
598 /* Queued track */
599 #ifdef HAVE_LCD_BITMAP
600 *icon=bitmap_icons_6x8[Icon_Queued];
601 #else
602 *icon=Icon_Queued;
603 #endif
605 else
606 #ifdef HAVE_LCD_BITMAP
607 *icon=0;
608 #else
609 *icon=-1;
610 #endif
613 /* Main viewer function. Filename identifies playlist to be viewed. If NULL,
614 view current playlist. */
615 bool playlist_viewer_ex(char* filename)
617 bool ret = false; /* return value */
618 bool exit=false; /* exit viewer */
619 int button;
620 struct gui_synclist playlist_lists;
621 if (!playlist_viewer_init(&viewer, filename, false))
622 goto exit;
624 gui_synclist_init(&playlist_lists, playlist_callback_name, &viewer, false, 1);
625 gui_synclist_set_icon_callback(&playlist_lists,
626 global_settings.playlist_viewer_icons?
627 &playlist_callback_icons:NULL);
628 gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
629 gui_synclist_select_item(&playlist_lists, viewer.selected_track);
630 gui_synclist_set_title(&playlist_lists, str(LANG_PLAYLIST_MENU),
631 #ifdef HAVE_LCD_BITMAP
632 bitmap_icons_6x8[Icon_Playlist]
633 #else
634 NOICON
635 #endif
637 gui_synclist_draw(&playlist_lists);
638 action_signalscreenchange();
639 while (!exit)
641 int track;
642 if (!viewer.playlist && !(audio_status() & AUDIO_STATUS_PLAY))
644 /* Play has stopped */
645 #ifdef HAVE_LCD_CHARCELLS
646 gui_syncsplash(HZ, str(LANG_END_PLAYLIST_PLAYER));
647 #else
648 gui_syncsplash(HZ, str(LANG_END_PLAYLIST_RECORDER));
649 #endif
650 goto exit;
653 if (viewer.move_track != -1)
654 gui_synclist_flash(&playlist_lists);
656 if (!viewer.playlist)
657 playlist_get_resume_info(&track);
658 else
659 track = -1;
661 if (track != viewer.current_playing_track ||
662 playlist_amount_ex(viewer.playlist) != viewer.num_tracks)
664 /* Playlist has changed (new track started?) */
665 if (!update_playlist(false))
666 goto exit;
667 gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
668 /* Abort move on playlist change */
669 viewer.move_track = -1;
670 gui_synclist_draw(&playlist_lists);
673 /* Timeout so we can determine if play status has changed */
674 button = get_action(CONTEXT_TREE,HZ/2);
675 int list_action;
676 if( (list_action=gui_synclist_do_button(&playlist_lists, button,LIST_WRAP_UNLESS_HELD))!=0 )
678 viewer.selected_track=gui_synclist_get_sel_pos(&playlist_lists);
679 if(playlist_buffer_needs_reload(&viewer.buffer,
680 viewer.selected_track))
681 playlist_buffer_load_entries_screen(&viewer.buffer,
682 list_action==ACTION_STD_NEXT?
683 FORWARD
685 BACKWARD
688 switch (button)
690 case ACTION_STD_CANCEL:
691 exit = true;
692 break;
693 case ACTION_STD_OK:
695 struct playlist_entry * current_track =
696 playlist_buffer_get_track(&viewer.buffer,
697 viewer.selected_track);
698 if (viewer.move_track >= 0)
700 /* Move track */
701 int ret;
703 ret = playlist_move(viewer.playlist, viewer.move_track,
704 current_track->index);
705 if (ret < 0)
706 gui_syncsplash(HZ, str(LANG_MOVE_FAILED));
708 update_playlist(true);
709 viewer.move_track = -1;
711 else if (!viewer.playlist)
713 /* play new track */
714 playlist_start(current_track->index, 0);
715 update_playlist(false);
717 else
719 /* New playlist */
720 if (playlist_set_current(viewer.playlist) < 0)
721 goto exit;
723 playlist_start(current_track->index, 0);
725 /* Our playlist is now the current list */
726 if (!playlist_viewer_init(&viewer, NULL, true))
727 goto exit;
729 gui_synclist_draw(&playlist_lists);
731 break;
733 case ACTION_STD_CONTEXT:
735 /* ON+PLAY menu */
736 int ret;
738 ret = onplay_menu(viewer.selected_track);
740 if (ret < 0)
742 ret = true;
743 goto exit;
745 else if (ret > 0)
747 /* Playlist changed */
748 gui_synclist_del_item(&playlist_lists);
749 update_playlist(true);
750 if (viewer.num_tracks <= 0)
751 exit = true;
753 gui_synclist_draw(&playlist_lists);
754 break;
756 case ACTION_STD_MENU:
757 if (viewer_menu())
759 ret = true;
760 goto exit;
762 gui_synclist_set_icon_callback(
763 &playlist_lists,
764 global_settings.playlist_viewer_icons?
765 &playlist_callback_icons:NULL
767 gui_synclist_draw(&playlist_lists);
768 break;
770 case ACTION_NONE:
771 gui_syncstatusbar_draw(&statusbars, false);
772 break;
774 default:
775 if(default_event_handler(button) == SYS_USB_CONNECTED)
777 ret = true;
778 goto exit;
780 break;
784 exit:
785 if (viewer.playlist)
786 playlist_close(viewer.playlist);
787 action_signalscreenchange();
788 return ret;
791 static char *playlist_search_callback_name(int selected_item, void * data, char *buffer)
793 int *found_indicies = (int*)data;
794 static struct playlist_track_info track;
795 playlist_get_track_info(viewer.playlist,found_indicies[selected_item],&track);
796 format_name(buffer,track.filename);
797 return(buffer);
801 static void playlist_search_callback_icons(int selected_item, void * data, ICON * icon)
803 (void)selected_item;
804 (void)data;
805 #ifdef HAVE_LCD_BITMAP
806 *icon=0;
807 #else
808 *icon=-1;
809 #endif
811 bool search_playlist(void)
813 char search_str[32] = "";
814 bool ret = false, exit = false;
815 int i, playlist_count;
816 int found_indicies[MAX_PLAYLIST_ENTRIES],found_indicies_count = 0;
817 int button;
818 struct gui_synclist playlist_lists;
819 struct playlist_track_info track;
821 if (!playlist_viewer_init(&viewer, 0, false))
822 return ret;
823 if (kbd_input(search_str,sizeof(search_str)) == -1)
824 return ret;
825 lcd_clear_display();
826 playlist_count = playlist_amount_ex(viewer.playlist);
827 for (i=0;(i<playlist_count)&&(found_indicies_count<MAX_PLAYLIST_ENTRIES);i++)
829 gui_syncsplash(0, str(LANG_PLAYLIST_SEARCH_MSG),found_indicies_count,
830 #if CONFIG_KEYPAD == PLAYER_PAD
831 str(LANG_STOP_ABORT)
832 #else
833 str(LANG_OFF_ABORT)
834 #endif
836 if (action_userabort(TIMEOUT_NOBLOCK))
837 return ret;
838 playlist_get_track_info(viewer.playlist,i,&track);
839 if (strcasestr(track.filename,search_str))
841 found_indicies[found_indicies_count++] = track.index;
844 if (!found_indicies_count)
846 return ret;
848 backlight_on();
849 gui_synclist_init(&playlist_lists, playlist_search_callback_name,
850 found_indicies, false, 1);
851 gui_synclist_set_icon_callback(&playlist_lists,
852 global_settings.playlist_viewer_icons?
853 &playlist_search_callback_icons:NULL);
854 gui_synclist_set_nb_items(&playlist_lists, found_indicies_count);
855 gui_synclist_select_item(&playlist_lists, 0);
856 gui_synclist_draw(&playlist_lists);
857 while (!exit)
859 button = get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
860 if (gui_synclist_do_button(&playlist_lists, button,LIST_WRAP_UNLESS_HELD))
861 continue;
862 switch (button)
864 case ACTION_STD_CANCEL:
865 exit = true;
866 break;
868 case ACTION_STD_OK:
869 playlist_start(
870 found_indicies[gui_synclist_get_sel_pos(&playlist_lists)]
871 ,0);
872 exit = 1;
873 break;
874 case ACTION_NONE:
875 break;
876 default:
877 if(default_event_handler(button) == SYS_USB_CONNECTED)
879 ret = true;
880 exit = true;
882 break;
885 action_signalscreenchange();
886 return ret;