Use two lined display in properties.
[maemo-rb.git] / apps / playlist_viewer.c
blob68732adcbc59e63dfe7595e4effef4074b623629
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 "playlist.h"
28 #include "audio.h"
29 #include "screens.h"
30 #include "settings.h"
31 #include "icons.h"
32 #include "menu.h"
33 #include "plugin.h"
34 #include "keyboard.h"
35 #include "filetypes.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 "splash.h"
50 #include "playlist_menu.h"
51 #include "yesno.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);
130 static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
131 int names_buffer_size)
133 pb->name_buffer = names_buffer;
134 pb->buffer_size = names_buffer_size;
135 pb->first_index = 0;
136 pb->num_loaded = 0;
140 * Loads the entries following 'index' in the playlist buffer
142 static void playlist_buffer_load_entries(struct playlist_buffer *pb, int index,
143 enum direction direction)
145 int num_entries = viewer.num_tracks;
146 char* p = pb->name_buffer;
147 int remaining = pb->buffer_size;
148 int i;
150 pb->first_index = index;
151 if (num_entries > MAX_PLAYLIST_ENTRIES)
152 num_entries = MAX_PLAYLIST_ENTRIES;
154 for (i = 0; i < num_entries; i++)
156 int len = playlist_entry_load(&(pb->tracks[i]), index, p, remaining);
157 if (len < 0)
159 /* Out of name buffer space */
160 num_entries = i;
161 break;
164 p += len;
165 remaining -= len;
167 if(direction == FORWARD)
168 index++;
169 else
170 index--;
171 index += viewer.num_tracks;
172 index %= viewer.num_tracks;
174 pb->direction = direction;
175 pb->num_loaded = i;
178 static void playlist_buffer_load_entries_screen(struct playlist_buffer * pb,
179 enum direction direction)
181 if (direction == FORWARD)
183 int min_start = viewer.selected_track-2*screens[0].getnblines();
184 while (min_start < 0)
185 min_start += viewer.num_tracks;
186 min_start %= viewer.num_tracks;
187 playlist_buffer_load_entries(pb, min_start, FORWARD);
189 else
191 int max_start = viewer.selected_track+2*screens[0].getnblines();
192 max_start %= viewer.num_tracks;
193 playlist_buffer_load_entries(pb, max_start, BACKWARD);
197 static int playlist_entry_load(struct playlist_entry *entry, int index,
198 char* name_buffer, int remaining_size)
200 struct playlist_track_info info;
201 int len;
203 /* Playlist viewer orders songs based on display index. We need to
204 convert to real playlist index to access track */
205 index = (index + playlist_get_first_index(viewer.playlist)) %
206 viewer.num_tracks;
207 if (playlist_get_track_info(viewer.playlist, index, &info) < 0)
208 return -1;
210 len = strlen(info.filename) + 1;
212 if (len <= remaining_size)
214 strcpy(name_buffer, info.filename);
216 entry->name = name_buffer;
217 entry->index = info.index;
218 entry->display_index = info.display_index;
219 entry->queued = info.attr & PLAYLIST_ATTR_QUEUED;
220 entry->skipped = info.attr & PLAYLIST_ATTR_SKIPPED;
221 return len;
223 return -1;
226 static int playlist_buffer_get_index(struct playlist_buffer *pb, int index)
228 int buffer_index;
229 if (pb->direction == FORWARD)
231 if (index >= pb->first_index)
232 buffer_index = index-pb->first_index;
233 else /* rotation : track0 in buffer + requested track */
234 buffer_index = viewer.num_tracks-pb->first_index+index;
236 else
238 if (index <= pb->first_index)
239 buffer_index = pb->first_index-index;
240 else /* rotation : track0 in buffer + dist from the last track
241 to the requested track (num_tracks-requested track) */
242 buffer_index = pb->first_index+viewer.num_tracks-index;
244 return buffer_index;
247 #define distance(a, b) \
248 a>b? (a) - (b) : (b) - (a)
249 static bool playlist_buffer_needs_reload(struct playlist_buffer* pb,
250 int track_index)
252 if (pb->num_loaded == viewer.num_tracks)
253 return false;
254 int selected_index = playlist_buffer_get_index(pb, track_index);
255 int first_buffer_index = playlist_buffer_get_index(pb, pb->first_index);
256 int distance_beginning = distance(selected_index, first_buffer_index);
257 if (distance_beginning < MIN_BUFFER_MARGIN)
258 return true;
260 if (pb->num_loaded - distance_beginning < MIN_BUFFER_MARGIN)
261 return true;
262 return false;
265 static struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer *pb,
266 int index)
268 int buffer_index = playlist_buffer_get_index(pb, index);
269 return &(pb->tracks[buffer_index]);
272 /* Initialize the playlist viewer. */
273 static bool playlist_viewer_init(struct playlist_viewer * viewer,
274 const char* filename, bool reload)
276 char* buffer;
277 size_t buffer_size;
278 bool is_playing = audio_status() & (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE);
279 bool have_list = filename || is_playing;
280 if (!have_list && (global_status.resume_index != -1))
282 /* Try to restore the list from control file */
283 have_list = (playlist_resume() != -1);
285 if (!have_list && (playlist_amount() > 0))
287 /*If dynamic playlist still exists, view it anyway even
288 if playback has reached the end of the playlist */
289 have_list = true;
291 if (!have_list)
293 /* Nothing to view, exit */
294 splash(HZ, str(LANG_CATALOG_NO_PLAYLISTS));
295 return false;
298 buffer = plugin_get_buffer(&buffer_size);
299 if (!buffer)
300 return false;
302 if (!filename)
303 viewer->playlist = NULL;
304 else
306 /* Viewing playlist on disk */
307 const char *dir, *file;
308 char *temp_ptr;
309 char *index_buffer = NULL;
310 ssize_t index_buffer_size = 0;
312 viewer->playlist = &temp_playlist;
314 /* Separate directory from filename */
315 temp_ptr = strrchr(filename+1,'/');
316 if (temp_ptr)
318 *temp_ptr = 0;
319 dir = filename;
320 file = temp_ptr + 1;
322 else
324 dir = "/";
325 file = filename+1;
328 if (is_playing)
330 /* Something is playing, use half the plugin buffer for playlist
331 indices */
332 index_buffer_size = buffer_size / 2;
333 index_buffer = buffer;
336 playlist_create_ex(viewer->playlist, dir, file, index_buffer,
337 index_buffer_size, buffer+index_buffer_size,
338 buffer_size-index_buffer_size);
340 if (temp_ptr)
341 *temp_ptr = '/';
343 buffer += index_buffer_size;
344 buffer_size -= index_buffer_size;
346 playlist_buffer_init(&viewer->buffer, buffer, buffer_size);
348 viewer->moving_track = -1;
349 viewer->moving_playlist_index = -1;
351 if (!reload)
353 if (viewer->playlist)
354 viewer->selected_track = 0;
355 else
356 viewer->selected_track = playlist_get_display_index() - 1;
359 if (!update_playlist(true))
360 return false;
361 return true;
364 /* Format trackname for display purposes */
365 static void format_name(char* dest, const char* src)
367 switch (global_settings.playlist_viewer_track_display)
369 case 0:
370 default:
372 /* Only display the filename */
373 char* p = strrchr(src, '/');
375 strcpy(dest, p+1);
377 /* Remove the extension */
378 strrsplt(dest, '.');
380 break;
382 case 1:
383 /* Full path */
384 strcpy(dest, src);
385 break;
389 /* Format display line */
390 static void format_line(const struct playlist_entry* track, char* str,
391 int len)
393 char name[MAX_PATH];
394 char *skipped = "";
396 format_name(name, track->name);
398 if (track->skipped)
399 skipped = "(ERR) ";
401 if (global_settings.playlist_viewer_indices)
402 /* Display playlist index */
403 snprintf(str, len, "%d. %s%s", track->display_index, skipped, name);
404 else
405 snprintf(str, len, "%s%s", skipped, name);
409 /* Update playlist in case something has changed or forced */
410 static bool update_playlist(bool force)
412 if (!viewer.playlist)
413 playlist_get_resume_info(&viewer.current_playing_track);
414 else
415 viewer.current_playing_track = -1;
416 int nb_tracks = playlist_amount_ex(viewer.playlist);
417 force = force || nb_tracks != viewer.num_tracks;
418 if (force)
420 /* Reload tracks */
421 viewer.num_tracks = nb_tracks;
422 if (viewer.num_tracks <= 0)
424 global_status.resume_index = -1;
425 global_status.resume_offset = -1;
426 return false;
428 playlist_buffer_load_entries_screen(&viewer.buffer, FORWARD);
429 if (viewer.buffer.num_loaded <= 0)
431 global_status.resume_index = -1;
432 global_status.resume_offset = -1;
433 return false;
436 return true;
439 /* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen.
440 Returns -1 if USB attached, 0 if no playlist change, and 1 if playlist
441 changed. */
442 static int onplay_menu(int index)
444 int result, ret = 0;
445 struct playlist_entry * current_track =
446 playlist_buffer_get_track(&viewer.buffer, index);
447 MENUITEM_STRINGLIST(menu_items, ID2P(LANG_PLAYLIST), NULL,
448 ID2P(LANG_CURRENT_PLAYLIST), ID2P(LANG_CATALOG),
449 ID2P(LANG_REMOVE), ID2P(LANG_MOVE), ID2P(LANG_SHUFFLE),
450 ID2P(LANG_SAVE_DYNAMIC_PLAYLIST));
451 bool current = (current_track->index == viewer.current_playing_track);
453 result = do_menu(&menu_items, NULL, NULL, false);
454 if (result == MENU_ATTACHED_USB)
456 ret = -1;
458 else if (result >= 0)
460 /* Abort current move */
461 viewer.moving_track = -1;
462 viewer.moving_playlist_index = -1;
464 switch (result)
466 case 0:
467 /* playlist */
468 onplay_show_playlist_menu(current_track->name);
469 ret = 0;
470 break;
471 case 1:
472 /* add to catalog */
473 onplay_show_playlist_cat_menu(current_track->name);
474 ret = 0;
475 break;
476 case 2:
477 /* delete track */
478 playlist_delete(viewer.playlist, current_track->index);
479 if (current)
481 if (playlist_amount_ex(viewer.playlist) <= 0)
482 audio_stop();
483 else
485 /* Start playing new track except if it's the lasttrack
486 track in the playlist and repeat mode is disabled */
487 current_track =
488 playlist_buffer_get_track(&viewer.buffer, index);
489 if (current_track->display_index!=viewer.num_tracks ||
490 global_settings.repeat_mode == REPEAT_ALL)
492 audio_play(0);
493 viewer.current_playing_track = -1;
497 ret = 1;
498 break;
499 case 3:
500 /* move track */
501 viewer.moving_track = index;
502 viewer.moving_playlist_index = current_track->index;
503 ret = 0;
504 break;
505 case 4:
506 /* shuffle */
507 playlist_randomise(viewer.playlist, current_tick, false);
508 ret = 1;
509 break;
510 case 5:
511 /* save playlist */
512 save_playlist_screen(viewer.playlist);
513 ret = 0;
514 break;
517 return ret;
520 /* View current playlist */
521 enum playlist_viewer_result playlist_viewer(void)
523 return playlist_viewer_ex(NULL);
526 static int get_track_num(struct playlist_viewer *local_viewer,
527 int selected_item)
529 if (local_viewer->moving_track >= 0)
531 if (local_viewer->selected_track == selected_item)
533 return local_viewer->moving_track;
535 else if (local_viewer->selected_track > selected_item
536 && selected_item >= local_viewer->moving_track)
538 return selected_item+1; /* move down */
540 else if (local_viewer->selected_track < selected_item
541 && selected_item <= local_viewer->moving_track)
543 return selected_item-1; /* move up */
546 return selected_item;
549 static const char* playlist_callback_name(int selected_item,
550 void *data,
551 char *buffer,
552 size_t buffer_len)
554 struct playlist_viewer *local_viewer = (struct playlist_viewer *)data;
556 int track_num = get_track_num(local_viewer, selected_item);
557 struct playlist_entry *track =
558 playlist_buffer_get_track(&(local_viewer->buffer), track_num);
560 format_line(track, buffer, buffer_len);
562 return(buffer);
566 static enum themable_icons playlist_callback_icons(int selected_item,
567 void *data)
569 struct playlist_viewer *local_viewer = (struct playlist_viewer *)data;
571 int track_num = get_track_num(local_viewer, selected_item);
572 struct playlist_entry *track =
573 playlist_buffer_get_track(&(local_viewer->buffer), track_num);
575 if (track->index == local_viewer->current_playing_track)
577 /* Current playing track */
578 return Icon_Audio;
580 else if (track->index == local_viewer->moving_playlist_index)
582 /* Track we are moving */
583 return Icon_Moving;
585 else if (track->queued)
587 /* Queued track */
588 return Icon_Queued;
590 else
591 return Icon_NOICON;
594 static int playlist_callback_voice(int selected_item, void *data)
596 struct playlist_viewer *local_viewer = (struct playlist_viewer *)data;
598 int track_num = get_track_num(local_viewer, selected_item);
599 struct playlist_entry *track =
600 playlist_buffer_get_track(&(local_viewer->buffer), track_num);
602 bool enqueue = false;
604 if (global_settings.talk_file_clip || global_settings.talk_file == 2)
606 if (global_settings.playlist_viewer_indices)
608 talk_number(track->display_index, false);
609 enqueue = true;
611 talk_file_or_spell(NULL, track->name, NULL, enqueue);
613 else if (global_settings.talk_file == 1) /* as numbers */
615 talk_id(VOICE_FILE, false);
616 talk_number(track->display_index, true);
619 return 0;
622 /* Main viewer function. Filename identifies playlist to be viewed. If NULL,
623 view current playlist. */
624 enum playlist_viewer_result playlist_viewer_ex(const char* filename)
626 enum playlist_viewer_result ret = PLAYLIST_VIEWER_OK;
627 bool exit = false; /* exit viewer */
628 int button;
629 bool dirty = false;
630 struct gui_synclist playlist_lists;
631 if (!playlist_viewer_init(&viewer, filename, false))
632 goto exit;
634 push_current_activity(ACTIVITY_PLAYLISTVIEWER);
635 gui_synclist_init(&playlist_lists, playlist_callback_name,
636 &viewer, false, 1, NULL);
637 gui_synclist_set_voice_callback(&playlist_lists, playlist_callback_voice);
638 gui_synclist_set_icon_callback(&playlist_lists,
639 global_settings.playlist_viewer_icons?
640 &playlist_callback_icons:NULL);
641 gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
642 gui_synclist_set_title(&playlist_lists, str(LANG_PLAYLIST), Icon_Playlist);
643 gui_synclist_select_item(&playlist_lists, viewer.selected_track);
644 gui_synclist_draw(&playlist_lists);
645 gui_synclist_speak_item(&playlist_lists);
646 while (!exit)
648 int track;
650 if (global_status.resume_index != -1 && !viewer.playlist)
651 playlist_get_resume_info(&track);
652 else
653 track = -1;
655 if (track != viewer.current_playing_track ||
656 playlist_amount_ex(viewer.playlist) != viewer.num_tracks)
658 /* Playlist has changed (new track started?) */
659 if (!update_playlist(false))
660 goto exit;
661 /*Needed because update_playlist gives wrong value when
662 playing is stopped*/
663 viewer.current_playing_track = track;
664 gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
666 gui_synclist_draw(&playlist_lists);
669 /* Timeout so we can determine if play status has changed */
670 bool res = list_do_action(CONTEXT_TREE, HZ/2,
671 &playlist_lists, &button, LIST_WRAP_UNLESS_HELD);
672 /* during moving, another redraw is going to be needed,
673 * since viewer.selected_track is updated too late (after the first draw)
674 * drawing the moving item needs it */
675 viewer.selected_track=gui_synclist_get_sel_pos(&playlist_lists);
676 if (res)
678 bool reload = playlist_buffer_needs_reload(&viewer.buffer,
679 viewer.selected_track);
680 if (reload)
681 playlist_buffer_load_entries_screen(&viewer.buffer,
682 button == ACTION_STD_NEXT ? FORWARD : BACKWARD);
683 if (reload || viewer.moving_track >= 0)
684 gui_synclist_draw(&playlist_lists);
686 switch (button)
688 case ACTION_TREE_WPS:
689 case ACTION_STD_CANCEL:
691 if (viewer.moving_track >= 0)
693 viewer.selected_track = viewer.moving_track;
694 gui_synclist_select_item(&playlist_lists, viewer.moving_track);
695 viewer.moving_track = -1;
696 viewer.moving_playlist_index = -1;
697 gui_synclist_draw(&playlist_lists);
699 else
701 exit = true;
702 ret = PLAYLIST_VIEWER_CANCEL;
704 break;
706 case ACTION_STD_OK:
708 struct playlist_entry * current_track =
709 playlist_buffer_get_track(&viewer.buffer,
710 viewer.selected_track);
712 if (viewer.moving_track >= 0)
714 /* Move track */
715 int ret_val;
717 ret_val = playlist_move(viewer.playlist,
718 viewer.moving_playlist_index,
719 current_track->index);
720 if (ret_val < 0)
721 splashf(HZ, (unsigned char *)"%s %s", str(LANG_MOVE),
722 str(LANG_FAILED));
723 update_playlist(true);
724 viewer.moving_track = -1;
725 viewer.moving_playlist_index = -1;
726 dirty = true;
728 else if (!viewer.playlist)
730 /* play new track */
731 if (!global_settings.party_mode)
733 playlist_start(current_track->index, 0);
734 update_playlist(false);
737 else if (!global_settings.party_mode)
739 int start_index = current_track->index;
740 if (!warn_on_pl_erase())
742 gui_synclist_draw(&playlist_lists);
743 break;
745 /* New playlist */
746 if (playlist_set_current(viewer.playlist) < 0)
747 goto exit;
748 if (global_settings.playlist_shuffle)
749 start_index = playlist_shuffle(current_tick, start_index);
750 playlist_start(start_index, 0);
752 /* Our playlist is now the current list */
753 if (!playlist_viewer_init(&viewer, NULL, true))
754 goto exit;
755 exit = true;
757 gui_synclist_draw(&playlist_lists);
759 break;
761 case ACTION_STD_CONTEXT:
763 /* ON+PLAY menu */
764 int ret_val;
766 ret_val = onplay_menu(viewer.selected_track);
768 if (ret_val < 0)
770 ret = PLAYLIST_VIEWER_USB;
771 goto exit;
773 else if (ret_val > 0)
775 /* Playlist changed */
776 gui_synclist_del_item(&playlist_lists);
777 update_playlist(true);
778 if (viewer.num_tracks <= 0)
779 exit = true;
780 if (viewer.selected_track >= viewer.num_tracks)
781 viewer.selected_track = viewer.num_tracks-1;
782 dirty = true;
784 gui_synclist_draw(&playlist_lists);
785 break;
787 case ACTION_STD_MENU:
788 ret = PLAYLIST_VIEWER_MAINMENU;
789 goto exit;
790 default:
791 if(default_event_handler(button) == SYS_USB_CONNECTED)
793 ret = PLAYLIST_VIEWER_USB;
794 goto exit;
796 break;
800 exit:
801 pop_current_activity();
802 if (viewer.playlist)
804 if(dirty && yesno_pop(ID2P(LANG_SAVE_CHANGES)))
805 save_playlist_screen(viewer.playlist);
806 playlist_close(viewer.playlist);
808 return ret;
811 static const char* playlist_search_callback_name(int selected_item, void * data,
812 char *buffer, size_t buffer_len)
814 (void)buffer_len; /* this should probably be used */
815 int *found_indicies = (int*)data;
816 static struct playlist_track_info track;
817 playlist_get_track_info(viewer.playlist, found_indicies[selected_item], &track);
818 format_name(buffer, track.filename);
819 return buffer;
822 bool search_playlist(void)
824 char search_str[32] = "";
825 bool ret = false, exit = false;
826 int i, playlist_count;
827 int found_indicies[MAX_PLAYLIST_ENTRIES];
828 int found_indicies_count = 0, last_found_count = -1;
829 int button;
830 struct gui_synclist playlist_lists;
831 struct playlist_track_info track;
833 if (!playlist_viewer_init(&viewer, 0, false))
834 return ret;
835 if (kbd_input(search_str, sizeof(search_str)) < 0)
836 return ret;
837 lcd_clear_display();
838 playlist_count = playlist_amount_ex(viewer.playlist);
840 cpu_boost(true);
842 for (i = 0; i < playlist_count &&
843 found_indicies_count < MAX_PLAYLIST_ENTRIES; i++)
845 if (found_indicies_count != last_found_count)
847 splashf(0, str(LANG_PLAYLIST_SEARCH_MSG), found_indicies_count,
848 str(LANG_OFF_ABORT));
849 last_found_count = found_indicies_count;
852 if (action_userabort(TIMEOUT_NOBLOCK))
853 break;
855 playlist_get_track_info(viewer.playlist, i, &track);
857 if (strcasestr(track.filename,search_str))
858 found_indicies[found_indicies_count++] = track.index;
860 yield();
863 cpu_boost(false);
865 if (!found_indicies_count)
867 return ret;
869 backlight_on();
871 gui_synclist_init(&playlist_lists, playlist_search_callback_name,
872 found_indicies, false, 1, NULL);
873 gui_synclist_set_title(&playlist_lists, str(LANG_SEARCH_RESULTS), NOICON);
874 gui_synclist_set_icon_callback(&playlist_lists, NULL);
875 gui_synclist_set_nb_items(&playlist_lists, found_indicies_count);
876 gui_synclist_select_item(&playlist_lists, 0);
877 gui_synclist_draw(&playlist_lists);
878 while (!exit)
880 if (list_do_action(CONTEXT_LIST, HZ/4,
881 &playlist_lists, &button, LIST_WRAP_UNLESS_HELD))
882 continue;
883 switch (button)
885 case ACTION_STD_CANCEL:
886 exit = true;
887 break;
889 case ACTION_STD_OK:
891 int sel = gui_synclist_get_sel_pos(&playlist_lists);
892 playlist_start(found_indicies[sel], 0);
893 exit = 1;
895 break;
897 default:
898 if (default_event_handler(button) == SYS_USB_CONNECTED)
900 ret = true;
901 exit = true;
903 break;
906 return ret;