1 /***************************************************************************
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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
35 #include "filetypes.h"
41 #include "backlight.h"
45 #include "playlist_viewer.h"
46 #include "playlist_catalog.h"
50 #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? */
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
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
,
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
,
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
;
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
;
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
);
159 /* Out of name buffer space */
167 if(direction
== FORWARD
)
171 index
+= viewer
.num_tracks
;
172 index
%= viewer
.num_tracks
;
174 pb
->direction
= direction
;
178 /* playlist_buffer_load_entries_screen()
179 * This function is called when the currently selected item gets too close
180 * to the start or the end of the loaded part of the playlis, or when
181 * the list callback requests a playlist item that has not been loaded yet
183 * reference_track is either the currently selected track, or the track that
184 * has been requested by the callback, and has not been loaded yet.
186 static void playlist_buffer_load_entries_screen(struct playlist_buffer
* pb
,
187 enum direction direction
,
190 if (direction
== FORWARD
)
192 int min_start
= reference_track
-2*screens
[0].getnblines();
193 while (min_start
< 0)
194 min_start
+= viewer
.num_tracks
;
195 min_start
%= viewer
.num_tracks
;
196 playlist_buffer_load_entries(pb
, min_start
, FORWARD
);
200 int max_start
= reference_track
+2*screens
[0].getnblines();
201 max_start
%= viewer
.num_tracks
;
202 playlist_buffer_load_entries(pb
, max_start
, BACKWARD
);
206 static int playlist_entry_load(struct playlist_entry
*entry
, int index
,
207 char* name_buffer
, int remaining_size
)
209 struct playlist_track_info info
;
212 /* Playlist viewer orders songs based on display index. We need to
213 convert to real playlist index to access track */
214 index
= (index
+ playlist_get_first_index(viewer
.playlist
)) %
216 if (playlist_get_track_info(viewer
.playlist
, index
, &info
) < 0)
219 len
= strlen(info
.filename
) + 1;
221 if (len
<= remaining_size
)
223 strcpy(name_buffer
, info
.filename
);
225 entry
->name
= name_buffer
;
226 entry
->index
= info
.index
;
227 entry
->display_index
= info
.display_index
;
228 entry
->queued
= info
.attr
& PLAYLIST_ATTR_QUEUED
;
229 entry
->skipped
= info
.attr
& PLAYLIST_ATTR_SKIPPED
;
235 static int playlist_buffer_get_index(struct playlist_buffer
*pb
, int index
)
238 if (pb
->direction
== FORWARD
)
240 if (index
>= pb
->first_index
)
241 buffer_index
= index
-pb
->first_index
;
242 else /* rotation : track0 in buffer + requested track */
243 buffer_index
= viewer
.num_tracks
-pb
->first_index
+index
;
247 if (index
<= pb
->first_index
)
248 buffer_index
= pb
->first_index
-index
;
249 else /* rotation : track0 in buffer + dist from the last track
250 to the requested track (num_tracks-requested track) */
251 buffer_index
= pb
->first_index
+viewer
.num_tracks
-index
;
256 #define distance(a, b) \
257 a>b? (a) - (b) : (b) - (a)
258 static bool playlist_buffer_needs_reload(struct playlist_buffer
* pb
,
261 if (pb
->num_loaded
== viewer
.num_tracks
)
263 int selected_index
= playlist_buffer_get_index(pb
, track_index
);
264 int first_buffer_index
= playlist_buffer_get_index(pb
, pb
->first_index
);
265 int distance_beginning
= distance(selected_index
, first_buffer_index
);
266 if (distance_beginning
< MIN_BUFFER_MARGIN
)
269 if (pb
->num_loaded
- distance_beginning
< MIN_BUFFER_MARGIN
)
274 static struct playlist_entry
* playlist_buffer_get_track(struct playlist_buffer
*pb
,
277 int buffer_index
= playlist_buffer_get_index(pb
, index
);
278 /* Make sure that we are not returning an invalid pointer.
279 In some cases, when scrolling really fast, it could happen that a reqested track
280 has not been pre-loaded */
281 if (buffer_index
< 0) {
282 playlist_buffer_load_entries_screen(&viewer
.buffer
,
283 pb
->direction
== FORWARD
? BACKWARD
: FORWARD
,
286 } else if (buffer_index
>= pb
->num_loaded
) {
287 playlist_buffer_load_entries_screen(&viewer
.buffer
,
291 buffer_index
= playlist_buffer_get_index(pb
, index
);
292 if (buffer_index
< 0 || buffer_index
>= pb
->num_loaded
) {
293 /* This really shouldn't happen. If this happens, then
294 the name_buffer is probably too small to store enough
295 titles to fill the screen, and preload data in the short
298 If this happens then scrolling performance will probably
299 be quite low, but it's better then having Data Abort errors */
300 playlist_buffer_load_entries(pb
, index
, FORWARD
);
301 buffer_index
= playlist_buffer_get_index(pb
, index
);
303 return &(pb
->tracks
[buffer_index
]);
306 /* Initialize the playlist viewer. */
307 static bool playlist_viewer_init(struct playlist_viewer
* viewer
,
308 const char* filename
, bool reload
)
312 bool is_playing
= audio_status() & (AUDIO_STATUS_PLAY
| AUDIO_STATUS_PAUSE
);
313 bool have_list
= filename
|| is_playing
;
314 if (!have_list
&& (global_status
.resume_index
!= -1))
316 /* Try to restore the list from control file */
317 have_list
= (playlist_resume() != -1);
319 if (!have_list
&& (playlist_amount() > 0))
321 /*If dynamic playlist still exists, view it anyway even
322 if playback has reached the end of the playlist */
327 /* Nothing to view, exit */
328 splash(HZ
, str(LANG_CATALOG_NO_PLAYLISTS
));
332 buffer
= plugin_get_buffer(&buffer_size
);
337 viewer
->playlist
= NULL
;
340 /* Viewing playlist on disk */
341 const char *dir
, *file
;
343 char *index_buffer
= NULL
;
344 ssize_t index_buffer_size
= 0;
346 viewer
->playlist
= &temp_playlist
;
348 /* Separate directory from filename */
349 temp_ptr
= strrchr(filename
+1,'/');
364 /* Something is playing, use half the plugin buffer for playlist
366 index_buffer_size
= buffer_size
/ 2;
367 index_buffer
= buffer
;
370 playlist_create_ex(viewer
->playlist
, dir
, file
, index_buffer
,
371 index_buffer_size
, buffer
+index_buffer_size
,
372 buffer_size
-index_buffer_size
);
377 buffer
+= index_buffer_size
;
378 buffer_size
-= index_buffer_size
;
380 playlist_buffer_init(&viewer
->buffer
, buffer
, buffer_size
);
382 viewer
->moving_track
= -1;
383 viewer
->moving_playlist_index
= -1;
387 if (viewer
->playlist
)
388 viewer
->selected_track
= 0;
390 viewer
->selected_track
= playlist_get_display_index() - 1;
393 if (!update_playlist(true))
398 /* Format trackname for display purposes */
399 static void format_name(char* dest
, const char* src
)
401 switch (global_settings
.playlist_viewer_track_display
)
406 /* Only display the filename */
407 char* p
= strrchr(src
, '/');
411 /* Remove the extension */
423 /* Format display line */
424 static void format_line(const struct playlist_entry
* track
, char* str
,
430 format_name(name
, track
->name
);
435 if (global_settings
.playlist_viewer_indices
)
436 /* Display playlist index */
437 snprintf(str
, len
, "%d. %s%s", track
->display_index
, skipped
, name
);
439 snprintf(str
, len
, "%s%s", skipped
, name
);
443 /* Update playlist in case something has changed or forced */
444 static bool update_playlist(bool force
)
446 if (!viewer
.playlist
)
447 playlist_get_resume_info(&viewer
.current_playing_track
);
449 viewer
.current_playing_track
= -1;
450 int nb_tracks
= playlist_amount_ex(viewer
.playlist
);
451 force
= force
|| nb_tracks
!= viewer
.num_tracks
;
455 viewer
.num_tracks
= nb_tracks
;
456 if (viewer
.num_tracks
<= 0)
458 global_status
.resume_index
= -1;
459 global_status
.resume_offset
= -1;
462 playlist_buffer_load_entries_screen(&viewer
.buffer
, FORWARD
,
463 viewer
.selected_track
);
464 if (viewer
.buffer
.num_loaded
<= 0)
466 global_status
.resume_index
= -1;
467 global_status
.resume_offset
= -1;
474 /* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen.
475 Returns -1 if USB attached, 0 if no playlist change, and 1 if playlist
477 static int onplay_menu(int index
)
480 struct playlist_entry
* current_track
=
481 playlist_buffer_get_track(&viewer
.buffer
, index
);
482 MENUITEM_STRINGLIST(menu_items
, ID2P(LANG_PLAYLIST
), NULL
,
483 ID2P(LANG_CURRENT_PLAYLIST
), ID2P(LANG_CATALOG
),
484 ID2P(LANG_REMOVE
), ID2P(LANG_MOVE
), ID2P(LANG_SHUFFLE
),
485 ID2P(LANG_SAVE_DYNAMIC_PLAYLIST
));
486 bool current
= (current_track
->index
== viewer
.current_playing_track
);
488 result
= do_menu(&menu_items
, NULL
, NULL
, false);
489 if (result
== MENU_ATTACHED_USB
)
493 else if (result
>= 0)
495 /* Abort current move */
496 viewer
.moving_track
= -1;
497 viewer
.moving_playlist_index
= -1;
503 onplay_show_playlist_menu(current_track
->name
);
508 onplay_show_playlist_cat_menu(current_track
->name
);
513 playlist_delete(viewer
.playlist
, current_track
->index
);
516 if (playlist_amount_ex(viewer
.playlist
) <= 0)
520 /* Start playing new track except if it's the lasttrack
521 track in the playlist and repeat mode is disabled */
523 playlist_buffer_get_track(&viewer
.buffer
, index
);
524 if (current_track
->display_index
!=viewer
.num_tracks
||
525 global_settings
.repeat_mode
== REPEAT_ALL
)
528 viewer
.current_playing_track
= -1;
536 viewer
.moving_track
= index
;
537 viewer
.moving_playlist_index
= current_track
->index
;
542 playlist_randomise(viewer
.playlist
, current_tick
, false);
547 save_playlist_screen(viewer
.playlist
);
555 /* View current playlist */
556 enum playlist_viewer_result
playlist_viewer(void)
558 return playlist_viewer_ex(NULL
);
561 static int get_track_num(struct playlist_viewer
*local_viewer
,
564 if (local_viewer
->moving_track
>= 0)
566 if (local_viewer
->selected_track
== selected_item
)
568 return local_viewer
->moving_track
;
570 else if (local_viewer
->selected_track
> selected_item
571 && selected_item
>= local_viewer
->moving_track
)
573 return selected_item
+1; /* move down */
575 else if (local_viewer
->selected_track
< selected_item
576 && selected_item
<= local_viewer
->moving_track
)
578 return selected_item
-1; /* move up */
581 return selected_item
;
584 static const char* playlist_callback_name(int selected_item
,
589 struct playlist_viewer
*local_viewer
= (struct playlist_viewer
*)data
;
591 int track_num
= get_track_num(local_viewer
, selected_item
);
592 struct playlist_entry
*track
=
593 playlist_buffer_get_track(&(local_viewer
->buffer
), track_num
);
595 format_line(track
, buffer
, buffer_len
);
601 static enum themable_icons
playlist_callback_icons(int selected_item
,
604 struct playlist_viewer
*local_viewer
= (struct playlist_viewer
*)data
;
606 int track_num
= get_track_num(local_viewer
, selected_item
);
607 struct playlist_entry
*track
=
608 playlist_buffer_get_track(&(local_viewer
->buffer
), track_num
);
610 if (track
->index
== local_viewer
->current_playing_track
)
612 /* Current playing track */
615 else if (track
->index
== local_viewer
->moving_playlist_index
)
617 /* Track we are moving */
620 else if (track
->queued
)
629 static int playlist_callback_voice(int selected_item
, void *data
)
631 struct playlist_viewer
*local_viewer
= (struct playlist_viewer
*)data
;
633 int track_num
= get_track_num(local_viewer
, selected_item
);
634 struct playlist_entry
*track
=
635 playlist_buffer_get_track(&(local_viewer
->buffer
), track_num
);
637 bool enqueue
= false;
639 if (global_settings
.talk_file_clip
|| global_settings
.talk_file
== 2)
641 if (global_settings
.playlist_viewer_indices
)
643 talk_number(track
->display_index
, false);
646 talk_file_or_spell(NULL
, track
->name
, NULL
, enqueue
);
648 else if (global_settings
.talk_file
== 1) /* as numbers */
650 talk_id(VOICE_FILE
, false);
651 talk_number(track
->display_index
, true);
657 /* Main viewer function. Filename identifies playlist to be viewed. If NULL,
658 view current playlist. */
659 enum playlist_viewer_result
playlist_viewer_ex(const char* filename
)
661 enum playlist_viewer_result ret
= PLAYLIST_VIEWER_OK
;
662 bool exit
= false; /* exit viewer */
665 struct gui_synclist playlist_lists
;
666 if (!playlist_viewer_init(&viewer
, filename
, false))
669 push_current_activity(ACTIVITY_PLAYLISTVIEWER
);
670 gui_synclist_init(&playlist_lists
, playlist_callback_name
,
671 &viewer
, false, 1, NULL
);
672 gui_synclist_set_voice_callback(&playlist_lists
, playlist_callback_voice
);
673 gui_synclist_set_icon_callback(&playlist_lists
,
674 global_settings
.playlist_viewer_icons
?
675 &playlist_callback_icons
:NULL
);
676 gui_synclist_set_nb_items(&playlist_lists
, viewer
.num_tracks
);
677 gui_synclist_set_title(&playlist_lists
, str(LANG_PLAYLIST
), Icon_Playlist
);
678 gui_synclist_select_item(&playlist_lists
, viewer
.selected_track
);
679 gui_synclist_draw(&playlist_lists
);
680 gui_synclist_speak_item(&playlist_lists
);
685 if (global_status
.resume_index
!= -1 && !viewer
.playlist
)
686 playlist_get_resume_info(&track
);
690 if (track
!= viewer
.current_playing_track
||
691 playlist_amount_ex(viewer
.playlist
) != viewer
.num_tracks
)
693 /* Playlist has changed (new track started?) */
694 if (!update_playlist(false))
696 /*Needed because update_playlist gives wrong value when
698 viewer
.current_playing_track
= track
;
699 gui_synclist_set_nb_items(&playlist_lists
, viewer
.num_tracks
);
701 gui_synclist_draw(&playlist_lists
);
704 /* Timeout so we can determine if play status has changed */
705 bool res
= list_do_action(CONTEXT_TREE
, HZ
/2,
706 &playlist_lists
, &button
, LIST_WRAP_UNLESS_HELD
);
707 /* during moving, another redraw is going to be needed,
708 * since viewer.selected_track is updated too late (after the first draw)
709 * drawing the moving item needs it */
710 viewer
.selected_track
=gui_synclist_get_sel_pos(&playlist_lists
);
713 bool reload
= playlist_buffer_needs_reload(&viewer
.buffer
,
714 viewer
.selected_track
);
716 playlist_buffer_load_entries_screen(&viewer
.buffer
,
717 button
== ACTION_STD_NEXT
? FORWARD
: BACKWARD
,
718 viewer
.selected_track
);
719 if (reload
|| viewer
.moving_track
>= 0)
720 gui_synclist_draw(&playlist_lists
);
724 case ACTION_TREE_WPS
:
725 case ACTION_STD_CANCEL
:
727 if (viewer
.moving_track
>= 0)
729 viewer
.selected_track
= viewer
.moving_track
;
730 gui_synclist_select_item(&playlist_lists
, viewer
.moving_track
);
731 viewer
.moving_track
= -1;
732 viewer
.moving_playlist_index
= -1;
733 gui_synclist_draw(&playlist_lists
);
738 ret
= PLAYLIST_VIEWER_CANCEL
;
744 struct playlist_entry
* current_track
=
745 playlist_buffer_get_track(&viewer
.buffer
,
746 viewer
.selected_track
);
748 if (viewer
.moving_track
>= 0)
753 ret_val
= playlist_move(viewer
.playlist
,
754 viewer
.moving_playlist_index
,
755 current_track
->index
);
757 splashf(HZ
, (unsigned char *)"%s %s", str(LANG_MOVE
),
759 update_playlist(true);
760 viewer
.moving_track
= -1;
761 viewer
.moving_playlist_index
= -1;
764 else if (!viewer
.playlist
)
767 if (!global_settings
.party_mode
)
769 playlist_start(current_track
->index
, 0);
770 update_playlist(false);
773 else if (!global_settings
.party_mode
)
775 int start_index
= current_track
->index
;
776 if (!warn_on_pl_erase())
778 gui_synclist_draw(&playlist_lists
);
782 if (playlist_set_current(viewer
.playlist
) < 0)
784 if (global_settings
.playlist_shuffle
)
785 start_index
= playlist_shuffle(current_tick
, start_index
);
786 playlist_start(start_index
, 0);
788 /* Our playlist is now the current list */
789 if (!playlist_viewer_init(&viewer
, NULL
, true))
793 gui_synclist_draw(&playlist_lists
);
797 case ACTION_STD_CONTEXT
:
802 ret_val
= onplay_menu(viewer
.selected_track
);
806 ret
= PLAYLIST_VIEWER_USB
;
809 else if (ret_val
> 0)
811 /* Playlist changed */
812 gui_synclist_del_item(&playlist_lists
);
813 update_playlist(true);
814 if (viewer
.num_tracks
<= 0)
816 if (viewer
.selected_track
>= viewer
.num_tracks
)
817 viewer
.selected_track
= viewer
.num_tracks
-1;
820 gui_synclist_draw(&playlist_lists
);
823 case ACTION_STD_MENU
:
824 ret
= PLAYLIST_VIEWER_MAINMENU
;
827 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
829 ret
= PLAYLIST_VIEWER_USB
;
837 pop_current_activity();
840 if(dirty
&& yesno_pop(ID2P(LANG_SAVE_CHANGES
)))
841 save_playlist_screen(viewer
.playlist
);
842 playlist_close(viewer
.playlist
);
847 static const char* playlist_search_callback_name(int selected_item
, void * data
,
848 char *buffer
, size_t buffer_len
)
850 (void)buffer_len
; /* this should probably be used */
851 int *found_indicies
= (int*)data
;
852 static struct playlist_track_info track
;
853 playlist_get_track_info(viewer
.playlist
, found_indicies
[selected_item
], &track
);
854 format_name(buffer
, track
.filename
);
858 bool search_playlist(void)
860 char search_str
[32] = "";
861 bool ret
= false, exit
= false;
862 int i
, playlist_count
;
863 int found_indicies
[MAX_PLAYLIST_ENTRIES
];
864 int found_indicies_count
= 0, last_found_count
= -1;
866 struct gui_synclist playlist_lists
;
867 struct playlist_track_info track
;
869 if (!playlist_viewer_init(&viewer
, 0, false))
871 if (kbd_input(search_str
, sizeof(search_str
)) < 0)
874 playlist_count
= playlist_amount_ex(viewer
.playlist
);
878 for (i
= 0; i
< playlist_count
&&
879 found_indicies_count
< MAX_PLAYLIST_ENTRIES
; i
++)
881 if (found_indicies_count
!= last_found_count
)
883 splashf(0, str(LANG_PLAYLIST_SEARCH_MSG
), found_indicies_count
,
884 str(LANG_OFF_ABORT
));
885 last_found_count
= found_indicies_count
;
888 if (action_userabort(TIMEOUT_NOBLOCK
))
891 playlist_get_track_info(viewer
.playlist
, i
, &track
);
893 if (strcasestr(track
.filename
,search_str
))
894 found_indicies
[found_indicies_count
++] = track
.index
;
901 if (!found_indicies_count
)
907 gui_synclist_init(&playlist_lists
, playlist_search_callback_name
,
908 found_indicies
, false, 1, NULL
);
909 gui_synclist_set_title(&playlist_lists
, str(LANG_SEARCH_RESULTS
), NOICON
);
910 gui_synclist_set_icon_callback(&playlist_lists
, NULL
);
911 gui_synclist_set_nb_items(&playlist_lists
, found_indicies_count
);
912 gui_synclist_select_item(&playlist_lists
, 0);
913 gui_synclist_draw(&playlist_lists
);
916 if (list_do_action(CONTEXT_LIST
, HZ
/4,
917 &playlist_lists
, &button
, LIST_WRAP_UNLESS_HELD
))
921 case ACTION_STD_CANCEL
:
927 int sel
= gui_synclist_get_sel_pos(&playlist_lists
);
928 playlist_start(found_indicies
[sel
], 0);
934 if (default_event_handler(button
) == SYS_USB_CONNECTED
)