Fix a dircache NULL-pointer dereference.
[kugel-rb.git] / apps / playlist_viewer.c
blobe2be36ce5d518f8beb12cb4cd7846fae6e9953d6
1 /***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 * $Id$
11 * Copyright (C) 2003 Hardeep Sidhu
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 * Kevin Ferrare 2005/10/16
24 * multi-screen support, rewrote a lot of code
26 #include <string.h>
27 #include <sprintf.h>
28 #include "playlist.h"
29 #include "audio.h"
30 #include "screens.h"
31 #include "settings.h"
32 #include "icons.h"
33 #include "menu.h"
34 #include "plugin.h"
35 #include "keyboard.h"
36 #include "filetypes.h"
37 #include "onplay.h"
38 #include "talk.h"
39 #include "misc.h"
40 #include "action.h"
41 #include "debug.h"
42 #include "backlight.h"
44 #include "lang.h"
46 #include "playlist_viewer.h"
47 #include "playlist_catalog.h"
48 #include "icon.h"
49 #include "list.h"
50 #include "splash.h"
51 #include "playlist_menu.h"
53 /* Maximum number of tracks we can have loaded at one time */
54 #define MAX_PLAYLIST_ENTRIES 200
56 /* The number of items between the selected one and the end/start of
57 * the buffer under which the buffer must reload */
58 #define MIN_BUFFER_MARGIN (screens[0].getnblines()+1)
60 /* Information about a specific track */
61 struct playlist_entry {
62 char *name; /* Formatted track name */
63 int index; /* Playlist index */
64 int display_index; /* Display index */
65 bool queued; /* Is track queued? */
66 bool skipped; /* Is track marked as bad? */
69 enum direction
71 FORWARD,
72 BACKWARD
75 struct playlist_buffer
77 char *name_buffer; /* Buffer used to store track names */
78 int buffer_size; /* Size of name buffer */
80 int first_index; /* Real index of first track loaded inside
81 the buffer */
83 enum direction direction; /* Direction of the buffer (if the buffer
84 was loaded BACKWARD, the last track in
85 the buffer has a real index < to the
86 real index of the the first track)*/
88 struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES];
89 int num_loaded; /* Number of track entries loaded in buffer */
92 /* Global playlist viewer settings */
93 struct playlist_viewer {
94 struct playlist_info* playlist; /* playlist being viewed */
95 int num_tracks; /* Number of tracks in playlist */
96 int current_playing_track; /* Index of current playing track */
97 int selected_track; /* The selected track, relative (first is 0) */
98 int moving_track; /* The track to move, relative (first is 0)
99 or -1 if nothing is currently being moved */
100 int moving_playlist_index; /* Playlist-relative index (as opposed to
101 viewer-relative index) of moving track */
102 struct playlist_buffer buffer;
105 static struct playlist_viewer viewer;
107 /* Used when viewing playlists on disk */
108 static struct playlist_info temp_playlist;
110 static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
111 int names_buffer_size);
112 static void playlist_buffer_load_entries(struct playlist_buffer * pb, int index,
113 enum direction direction);
114 static int playlist_entry_load(struct playlist_entry *entry, int index,
115 char* name_buffer, int remaining_size);
117 static struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer *pb,
118 int index);
120 static bool playlist_viewer_init(struct playlist_viewer * viewer,
121 const char* filename, bool reload);
123 static void format_name(char* dest, const char* src);
124 static void format_line(const struct playlist_entry* track, char* str,
125 int len);
127 static bool update_playlist(bool force);
128 static int onplay_menu(int index);
129 static bool viewer_menu(void);
130 static int save_playlist_func(void);
132 static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
133 int names_buffer_size)
135 pb->name_buffer=names_buffer;
136 pb->buffer_size=names_buffer_size;
137 pb->first_index=0;
138 pb->num_loaded=0;
142 * Loads the entries following 'index' in the playlist buffer
144 static void playlist_buffer_load_entries(struct playlist_buffer *pb, int index,
145 enum direction direction)
147 int num_entries = viewer.num_tracks;
148 char* p = pb->name_buffer;
149 int remaining = pb->buffer_size;
150 int i;
152 pb->first_index = index;
153 if (num_entries > MAX_PLAYLIST_ENTRIES)
154 num_entries = MAX_PLAYLIST_ENTRIES;
156 for(i=0; i<num_entries; i++)
158 int len = playlist_entry_load(&(pb->tracks[i]), index, p, remaining);
159 if (len < 0)
161 /* Out of name buffer space */
162 num_entries = i;
163 break;
166 p += len;
167 remaining -= len;
169 if(direction==FORWARD)
170 index++;
171 else
172 index--;
173 index+=viewer.num_tracks;
174 index%=viewer.num_tracks;
176 pb->direction=direction;
177 pb->num_loaded = i;
180 static void playlist_buffer_load_entries_screen(struct playlist_buffer * pb,
181 enum direction direction)
183 if(direction==FORWARD)
185 int min_start=viewer.selected_track-2*screens[0].getnblines();
186 while(min_start<0)
187 min_start+=viewer.num_tracks;
188 min_start %= viewer.num_tracks;
189 playlist_buffer_load_entries(pb, min_start, FORWARD);
191 else
193 int max_start=viewer.selected_track+2*screens[0].getnblines();
194 max_start%=viewer.num_tracks;
195 playlist_buffer_load_entries(pb, max_start, BACKWARD);
199 static int playlist_entry_load(struct playlist_entry *entry, int index,
200 char* name_buffer, int remaining_size)
202 struct playlist_track_info info;
203 int len;
205 /* Playlist viewer orders songs based on display index. We need to
206 convert to real playlist index to access track */
207 index = (index + playlist_get_first_index(viewer.playlist)) %
208 viewer.num_tracks;
209 if (playlist_get_track_info(viewer.playlist, index, &info) < 0)
210 return -1;
212 len = strlen(info.filename) + 1;
214 if (len <= remaining_size)
216 strcpy(name_buffer, info.filename);
218 entry->name = name_buffer;
219 entry->index = info.index;
220 entry->display_index = info.display_index;
221 entry->queued = info.attr & PLAYLIST_ATTR_QUEUED;
222 entry->skipped = info.attr & PLAYLIST_ATTR_SKIPPED;
223 return len;
225 return -1;
228 static int playlist_buffer_get_index(struct playlist_buffer *pb, int index)
230 int buffer_index;
231 if(pb->direction==FORWARD)
233 if(index>=pb->first_index)
234 buffer_index=index-pb->first_index;
235 else /* rotation : track0 in buffer + requested track */
236 buffer_index=(viewer.num_tracks-pb->first_index)+(index);
238 else
240 if(index<=pb->first_index)
241 buffer_index=pb->first_index-index;
242 else /* rotation : track0 in buffer + dist from the last track
243 to the requested track (num_tracks-requested track) */
244 buffer_index=(pb->first_index)+(viewer.num_tracks-index);
246 return(buffer_index);
249 #define distance(a, b) \
250 a>b? (a) - (b) : (b) - (a)
251 static bool playlist_buffer_needs_reload(struct playlist_buffer* pb,
252 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 const char* filename, bool reload)
278 char* buffer;
279 size_t buffer_size;
280 bool is_playing = audio_status() & (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE);
281 bool have_list = filename || is_playing;
282 if (!have_list && (global_status.resume_index != -1))
284 /* Try to restore the list from control file */
285 have_list = (playlist_resume() != -1);
287 if (!have_list && (playlist_amount() > 0))
289 /*If dynamic playlist still exists, view it anyway even
290 if playback has reached the end of the playlist */
291 have_list = true;
293 if (!have_list)
295 /* Nothing to view, exit */
296 splash(HZ, str(LANG_CATALOG_NO_PLAYLISTS));
297 return false;
300 buffer = plugin_get_buffer(&buffer_size);
301 if (!buffer)
302 return false;
304 if (!filename)
305 viewer->playlist = NULL;
306 else
308 /* Viewing playlist on disk */
309 const char *dir, *file;
310 char *temp_ptr;
311 char *index_buffer = NULL;
312 ssize_t index_buffer_size = 0;
314 viewer->playlist = &temp_playlist;
316 /* Separate directory from filename */
317 temp_ptr = strrchr(filename+1,'/');
318 if (temp_ptr)
320 *temp_ptr = 0;
321 dir = filename;
322 file = temp_ptr + 1;
324 else
326 dir = "/";
327 file = filename+1;
330 if (is_playing)
332 /* Something is playing, use half the plugin buffer for playlist
333 indices */
334 index_buffer_size = buffer_size / 2;
335 index_buffer = buffer;
338 playlist_create_ex(viewer->playlist, dir, file, index_buffer,
339 index_buffer_size, buffer+index_buffer_size,
340 buffer_size-index_buffer_size);
342 if (temp_ptr)
343 *temp_ptr = '/';
345 buffer += index_buffer_size;
346 buffer_size -= index_buffer_size;
348 playlist_buffer_init(&viewer->buffer, buffer, buffer_size );
350 viewer->moving_track = -1;
351 viewer->moving_playlist_index = -1;
353 if (!reload)
355 if (viewer->playlist)
356 viewer->selected_track = 0;
357 else
358 viewer->selected_track = playlist_get_display_index() - 1;
361 if (!update_playlist(true))
362 return false;
363 return true;
366 /* Format trackname for display purposes */
367 static void format_name(char* dest, const char* src)
369 switch (global_settings.playlist_viewer_track_display)
371 case 0:
372 default:
374 /* Only display the filename */
375 char* p = strrchr(src, '/');
377 strcpy(dest, p+1);
379 /* Remove the extension */
380 strrsplt(dest, '.');
382 break;
384 case 1:
385 /* Full path */
386 strcpy(dest, src);
387 break;
391 /* Format display line */
392 static void format_line(const struct playlist_entry* track, char* str,
393 int len)
395 char name[MAX_PATH];
396 char *skipped = "";
398 format_name(name, track->name);
400 if (track->skipped)
401 skipped = "(ERR) ";
403 if (global_settings.playlist_viewer_indices)
404 /* Display playlist index */
405 snprintf(str, len, "%d. %s%s", track->display_index, skipped, name);
406 else
407 snprintf(str, len, "%s%s", skipped, name);
411 /* Update playlist in case something has changed or forced */
412 static bool update_playlist(bool force)
414 if (!viewer.playlist)
415 playlist_get_resume_info(&viewer.current_playing_track);
416 else
417 viewer.current_playing_track = -1;
418 int nb_tracks=playlist_amount_ex(viewer.playlist);
419 force=force || nb_tracks != viewer.num_tracks;
420 if (force)
422 /* Reload tracks */
423 viewer.num_tracks = nb_tracks;
424 if (viewer.num_tracks <= 0)
426 global_status.resume_index = -1;
427 global_status.resume_offset = -1;
428 return false;
430 playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD);
431 if (viewer.buffer.num_loaded <= 0)
433 global_status.resume_index = -1;
434 global_status.resume_offset = -1;
435 return false;
438 return true;
441 /* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen.
442 Returns -1 if USB attached, 0 if no playlist change, and 1 if playlist
443 changed. */
444 static int onplay_menu(int index)
446 int result, ret = 0;
447 struct playlist_entry * current_track=
448 playlist_buffer_get_track(&viewer.buffer, index);
449 MENUITEM_STRINGLIST(menu_items, ID2P(LANG_PLAYLIST), NULL,
450 ID2P(LANG_REMOVE), ID2P(LANG_MOVE),
451 ID2P(LANG_CATALOG_ADD_TO), ID2P(LANG_CATALOG_ADD_TO_NEW),
452 ID2P(LANG_PLAYLISTVIEWER_SETTINGS));
453 bool current = (current_track->index == viewer.current_playing_track);
455 result = do_menu(&menu_items, NULL, NULL, false);
456 if (result == MENU_ATTACHED_USB)
458 ret = -1;
460 else if (result >= 0)
462 /* Abort current move */
463 viewer.moving_track = -1;
464 viewer.moving_playlist_index = -1;
466 switch (result)
468 case 0:
469 /* delete track */
470 playlist_delete(viewer.playlist, current_track->index);
471 if (current)
473 if (playlist_amount_ex(viewer.playlist) <= 0)
474 audio_stop();
475 else
477 /* Start playing new track except if it's the lasttrack
478 track in the playlist and repeat mode is disabled */
479 current_track =
480 playlist_buffer_get_track(&viewer.buffer, index);
481 if (current_track->display_index!=viewer.num_tracks ||
482 global_settings.repeat_mode == REPEAT_ALL)
484 #if CONFIG_CODEC != SWCODEC
485 talk_buffer_steal(); /* will use the mp3 buffer */
486 #endif
487 audio_play(0);
488 viewer.current_playing_track = -1;
492 ret = 1;
493 break;
494 case 1:
495 /* move track */
496 viewer.moving_track = index;
497 viewer.moving_playlist_index = current_track->index;
498 ret = 0;
499 break;
500 case 2: /* add to catalog */
501 case 3: /* add to a new one */
502 catalog_add_to_a_playlist(current_track->name,
503 FILE_ATTR_AUDIO,
504 result==3, NULL);
505 ret = 0;
506 break;
507 case 4: /* playlist viewer settings */
508 /* true on usb connect */
509 ret = viewer_menu() ? -1 : 0;
510 break;
513 return ret;
516 /* Menu of viewer options. Invoked via F1(r) or Menu(p). */
517 MENUITEM_SETTING(show_icons, &global_settings.playlist_viewer_icons, NULL);
518 MENUITEM_SETTING(show_indices, &global_settings.playlist_viewer_indices, NULL);
519 MENUITEM_SETTING(track_display,
520 &global_settings.playlist_viewer_track_display, NULL);
521 MENUITEM_FUNCTION(save_playlist_item, 0, ID2P(LANG_SAVE_DYNAMIC_PLAYLIST),
522 save_playlist_func, 0, NULL, Icon_NOICON);
523 MAKE_MENU(viewer_settings_menu, ID2P(LANG_PLAYLISTVIEWER_SETTINGS),
524 NULL, Icon_Playlist,
525 &show_icons, &show_indices, &track_display, &save_playlist_item);
526 static bool viewer_menu(void)
528 return do_menu(&viewer_settings_menu, NULL, NULL, false) == MENU_ATTACHED_USB;
531 /* Save playlist to disk */
532 static int save_playlist_func(void)
534 save_playlist_screen(viewer.playlist);
535 return 0;
538 /* View current playlist */
539 enum playlist_viewer_result playlist_viewer(void)
541 return playlist_viewer_ex(NULL);
544 static int get_track_num( struct playlist_viewer * local_viewer,
545 int selected_item )
547 if( local_viewer->moving_track >= 0 )
549 if( local_viewer->selected_track == selected_item )
551 return local_viewer->moving_track;
553 else if( local_viewer->selected_track > selected_item
554 && selected_item >= local_viewer->moving_track )
556 return selected_item+1; /* move down */
558 else if( local_viewer->selected_track < selected_item
559 && selected_item <= local_viewer->moving_track )
561 return selected_item-1; /* move up */
564 return selected_item;
567 static const char* playlist_callback_name(int selected_item,
568 void *data,
569 char *buffer,
570 size_t buffer_len)
572 struct playlist_viewer * local_viewer = (struct playlist_viewer *)data;
574 int track_num = get_track_num(local_viewer, selected_item);
575 struct playlist_entry *track =
576 playlist_buffer_get_track(&(local_viewer->buffer), track_num);
578 format_line(track, buffer, buffer_len);
580 return(buffer);
584 static enum themable_icons playlist_callback_icons(int selected_item,
585 void *data)
587 struct playlist_viewer * local_viewer=(struct playlist_viewer *)data;
589 int track_num = get_track_num(local_viewer, selected_item);
590 struct playlist_entry *track=
591 playlist_buffer_get_track(&(local_viewer->buffer), track_num);
593 if (track->index == local_viewer->current_playing_track)
595 /* Current playing track */
596 return Icon_Audio;
598 else if (track->index == local_viewer->moving_playlist_index)
600 /* Track we are moving */
601 return Icon_Moving;
603 else if (track->queued)
605 /* Queued track */
606 return Icon_Queued;
608 else
609 return Icon_NOICON;
612 /* Main viewer function. Filename identifies playlist to be viewed. If NULL,
613 view current playlist. */
614 enum playlist_viewer_result playlist_viewer_ex(const char* filename)
616 enum playlist_viewer_result ret = PLAYLIST_VIEWER_OK;
617 bool exit=false; /* exit viewer */
618 int button;
619 struct gui_synclist playlist_lists;
620 if (!playlist_viewer_init(&viewer, filename, false))
621 goto exit;
623 gui_synclist_init(&playlist_lists, playlist_callback_name,
624 &viewer, false, 1, NULL);
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_set_title(&playlist_lists, str(LANG_PLAYLIST), Icon_Playlist);
630 gui_synclist_select_item(&playlist_lists, viewer.selected_track);
631 gui_synclist_draw(&playlist_lists);
632 while (!exit)
634 int track;
636 if (global_status.resume_index != -1 && !viewer.playlist)
637 playlist_get_resume_info(&track);
638 else
639 track = -1;
641 if (track != viewer.current_playing_track ||
642 playlist_amount_ex(viewer.playlist) != viewer.num_tracks)
644 /* Playlist has changed (new track started?) */
645 if (!update_playlist(false))
646 goto exit;
647 /*Needed because update_playlist gives wrong value when
648 playing is stopped*/
649 viewer.current_playing_track = track;
650 gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
652 gui_synclist_draw(&playlist_lists);
655 /* Timeout so we can determine if play status has changed */
656 button = get_action(CONTEXT_TREE,HZ/2);
657 if( (gui_synclist_do_button(&playlist_lists, &button,LIST_WRAP_UNLESS_HELD)) )
659 viewer.selected_track=gui_synclist_get_sel_pos(&playlist_lists);
660 if(playlist_buffer_needs_reload(&viewer.buffer,
661 viewer.selected_track))
662 playlist_buffer_load_entries_screen(&viewer.buffer,
663 button==ACTION_STD_NEXT?
664 FORWARD
666 BACKWARD
668 gui_synclist_draw(&playlist_lists);
670 switch (button)
672 case ACTION_TREE_WPS:
673 case ACTION_STD_CANCEL:
675 if (viewer.moving_track >= 0)
677 viewer.selected_track = viewer.moving_track;
678 gui_synclist_select_item(&playlist_lists, viewer.moving_track);
679 viewer.moving_track = -1;
680 viewer.moving_playlist_index = -1;
681 gui_synclist_draw(&playlist_lists);
683 else
684 exit = true;
685 break;
687 case ACTION_STD_OK:
689 struct playlist_entry * current_track =
690 playlist_buffer_get_track(&viewer.buffer,
691 viewer.selected_track);
692 if (viewer.moving_track >= 0)
694 /* Move track */
695 int ret_val;
697 ret_val = playlist_move(viewer.playlist,
698 viewer.moving_playlist_index,
699 current_track->index);
700 if (ret_val < 0)
701 splashf(HZ, (unsigned char *)"%s %s", str(LANG_MOVE),
702 str(LANG_FAILED));
703 update_playlist(true);
704 viewer.moving_track = -1;
705 viewer.moving_playlist_index = -1;
707 else if (!viewer.playlist)
709 /* play new track */
710 playlist_start(current_track->index, 0);
711 update_playlist(false);
713 else
715 /* New playlist */
716 if (playlist_set_current(viewer.playlist) < 0)
717 goto exit;
719 playlist_start(current_track->index, 0);
721 /* Our playlist is now the current list */
722 if (!playlist_viewer_init(&viewer, NULL, true))
723 goto exit;
725 gui_synclist_draw(&playlist_lists);
727 break;
729 case ACTION_STD_CONTEXT:
731 /* ON+PLAY menu */
732 int ret_val;
734 ret_val = onplay_menu(viewer.selected_track);
736 if (ret_val < 0)
738 ret = PLAYLIST_VIEWER_USB;
739 goto exit;
741 else if (ret_val > 0)
743 /* Playlist changed */
744 gui_synclist_del_item(&playlist_lists);
745 update_playlist(true);
746 if (viewer.num_tracks <= 0)
747 exit = true;
748 if(viewer.selected_track >= viewer.num_tracks)
749 viewer.selected_track = viewer.num_tracks-1;
751 gui_synclist_draw(&playlist_lists);
752 break;
754 case ACTION_STD_MENU:
755 ret = PLAYLIST_VIEWER_MAINMENU;
756 goto exit;
757 default:
758 if(default_event_handler(button) == SYS_USB_CONNECTED)
760 ret = PLAYLIST_VIEWER_USB;
761 goto exit;
763 break;
767 exit:
768 if (viewer.playlist)
769 playlist_close(viewer.playlist);
770 return ret;
773 static const char* playlist_search_callback_name(int selected_item, void * data,
774 char *buffer, size_t buffer_len)
776 (void)buffer_len; /* this should probably be used */
777 int *found_indicies = (int*)data;
778 static struct playlist_track_info track;
779 playlist_get_track_info(viewer.playlist, found_indicies[selected_item], &track);
780 format_name(buffer, track.filename);
781 return buffer;
784 bool search_playlist(void)
786 char search_str[32] = "";
787 bool ret = false, exit = false;
788 int i, playlist_count;
789 int found_indicies[MAX_PLAYLIST_ENTRIES];
790 int found_indicies_count = 0, last_found_count = -1;
791 int button;
792 struct gui_synclist playlist_lists;
793 struct playlist_track_info track;
795 if (!playlist_viewer_init(&viewer, 0, false))
796 return ret;
797 if (kbd_input(search_str, sizeof(search_str)) < 0)
798 return ret;
799 lcd_clear_display();
800 playlist_count = playlist_amount_ex(viewer.playlist);
802 cpu_boost(true);
804 for (i=0; (i<playlist_count)&&(found_indicies_count<MAX_PLAYLIST_ENTRIES); i++)
806 if (found_indicies_count != last_found_count)
808 splashf(0, str(LANG_PLAYLIST_SEARCH_MSG), found_indicies_count,
809 str(LANG_OFF_ABORT));
810 last_found_count = found_indicies_count;
813 if (action_userabort(TIMEOUT_NOBLOCK))
814 break;
816 playlist_get_track_info(viewer.playlist, i, &track);
818 if (strcasestr(track.filename,search_str))
819 found_indicies[found_indicies_count++] = track.index;
821 yield();
824 cpu_boost(false);
826 if (!found_indicies_count)
828 return ret;
830 backlight_on();
832 gui_synclist_init(&playlist_lists, playlist_search_callback_name,
833 found_indicies, false, 1, NULL);
834 gui_synclist_set_title(&playlist_lists, str(LANG_SEARCH_RESULTS), NOICON);
835 gui_synclist_set_icon_callback(&playlist_lists, NULL);
836 gui_synclist_set_nb_items(&playlist_lists, found_indicies_count);
837 gui_synclist_select_item(&playlist_lists, 0);
838 gui_synclist_draw(&playlist_lists);
839 while (!exit)
841 button = get_action(CONTEXT_LIST, HZ/4);
842 if (gui_synclist_do_button(&playlist_lists, &button, LIST_WRAP_UNLESS_HELD))
843 continue;
844 switch (button)
846 case ACTION_STD_CANCEL:
847 exit = true;
848 break;
850 case ACTION_STD_OK:
851 playlist_start(
852 found_indicies[gui_synclist_get_sel_pos(&playlist_lists)]
853 ,0);
854 exit = 1;
855 break;
857 default:
858 if(default_event_handler(button) == SYS_USB_CONNECTED)
860 ret = true;
861 exit = true;
863 break;
866 return ret;