rockbox/apps/playlist_viewer.c

1062 lines
30 KiB
C

/***************************************************************************
*
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2003 Hardeep Sidhu
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <string.h>
#include <sprintf.h>
#include "playlist.h"
#include "mpeg.h"
#include "screens.h"
#include "status.h"
#include "settings.h"
#include "icons.h"
#include "menu.h"
#include "plugin.h"
#include "keyboard.h"
#include "tree.h"
#include "onplay.h"
#include "talk.h"
#include "misc.h"
#ifdef HAVE_LCD_BITMAP
#include "widgets.h"
#endif
#include "lang.h"
#include "playlist_viewer.h"
/* Defines for LCD display purposes. Taken from tree.c */
#ifdef HAVE_LCD_BITMAP
#define CURSOR_X (global_settings.scrollbar && \
viewer.num_tracks>viewer.num_display_lines?1:0)
#define CURSOR_Y 0
#define CURSOR_WIDTH (global_settings.invert_cursor ? 0 : 4)
#define ICON_WIDTH ((viewer.char_width > 6) ? viewer.char_width : 6)
#define MARGIN_X ((global_settings.scrollbar && \
viewer.num_tracks > viewer.num_display_lines ? \
SCROLLBAR_WIDTH : 0) + CURSOR_WIDTH + \
(global_settings.playlist_viewer_icons ? \
ICON_WIDTH : 0))
#define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0)
#define LINE_X 0
#define LINE_Y (global_settings.statusbar ? 1 : 0)
#define SCROLLBAR_X 0
#define SCROLLBAR_Y lcd_getymargin()
#define SCROLLBAR_WIDTH 6
#else
#define MARGIN_X 0
#define MARGIN_Y 0
#define LINE_X 2
#define LINE_Y 0
#define CURSOR_X 0
#define CURSOR_Y 0
#endif
/* Maximum number of tracks we can have loaded at one time */
#define MAX_PLAYLIST_ENTRIES 200
/* Default playlist name for saving */
#define DEFAULT_PLAYLIST_NAME "/viewer.m3u"
/* Index of track on display line _pos */
#define INDEX(_pos) (viewer.first_display_index - viewer.first_index + (_pos))
/* Global playlist viewer settings */
struct playlist_viewer_info {
struct playlist_info* playlist; /* playlist being viewed */
char *name_buffer; /* Buffer used to store track names */
int buffer_size; /* Size of name buffer */
int num_display_lines; /* Number of lines on lcd */
int line_height; /* Height (in pixels) of display line */
int char_width; /* Width (in pixels) of a character */
int num_tracks; /* Number of tracks in playlist */
int current_playing_track; /* Index of current playing track */
int num_loaded; /* Number of track entries loaded in viewer */
int first_index; /* Index of first loaded track */
int last_index; /* Index of last loaded track */
int first_display_index; /* Index of first track on display */
int last_display_index; /* Index of last track on display */
int cursor_pos; /* Line number of cursor */
int move_track; /* Playlist index of track to move or -1 */
};
/* Information about a specific track */
struct playlist_entry {
char *name; /* Formatted track name */
int index; /* Playlist index */
int display_index; /* Display index */
bool queued; /* Is track queued? */
};
static struct playlist_viewer_info viewer;
static struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES];
/* Used when viewing playlists on disk */
static struct playlist_info temp_playlist;
static bool initialize(char* filename, bool reload);
static void load_playlist_entries(int start_index);
static void load_playlist_entries_r(int end_index);
static int load_entry(int index, int pos, char* p, int size);
static void format_name(char* dest, const char* src);
static void format_line(const struct playlist_entry* track, char* str, int len);
static void display_playlist(void);
static void update_display_line(int line, bool scroll);
static void scroll_display(int lines);
static void update_first_index(void);
static bool update_playlist(bool force);
#ifdef TREE_SHIFT
static int onplay_menu(int index);
#endif
static bool viewer_menu(void);
static bool show_icons(void);
static bool show_indices(void);
static bool track_display(void);
static bool save_playlist(void);
/* Initialize the playlist viewer. */
static bool initialize(char* filename, bool reload)
{
char* buffer;
int buffer_size;
bool is_playing = mpeg_status() & MPEG_STATUS_PLAY;
if (!filename && !is_playing)
/* Nothing is playing, exit */
return false;
buffer = plugin_get_buffer(&buffer_size);
if (!buffer)
return false;
if (!filename)
viewer.playlist = NULL;
else
{
/* Viewing playlist on disk */
char *dir, *file, *temp_ptr;
char *index_buffer = NULL;
int index_buffer_size = 0;
viewer.playlist = &temp_playlist;
/* Separate directory from filename */
temp_ptr = strrchr(filename+1,'/');
if (temp_ptr)
{
*temp_ptr = 0;
dir = filename;
file = temp_ptr + 1;
}
else
{
dir = "/";
file = filename+1;
}
if (is_playing)
{
/* Something is playing, use half the plugin buffer for playlist
indices */
index_buffer_size = buffer_size / 2;
index_buffer = buffer;
}
playlist_create_ex(viewer.playlist, dir, file, index_buffer,
index_buffer_size, buffer+index_buffer_size,
buffer_size-index_buffer_size);
if (temp_ptr)
*temp_ptr = '/';
buffer += index_buffer_size;
buffer_size -= index_buffer_size;
}
viewer.name_buffer = buffer;
viewer.buffer_size = buffer_size;
#ifdef HAVE_LCD_BITMAP
{
char icon_chars[] = "MQ"; /* characters used as icons */
unsigned int i;
viewer.char_width = 0;
viewer.line_height = 0;
/* Use icon characters to calculate largest possible width/height so
that we set proper margins */
for (i=0; i<sizeof(icon_chars); i++)
{
char str[2];
int w, h;
snprintf(str, sizeof(str), "%c", icon_chars[i]);
lcd_getstringsize(str, &w, &h);
if (w > viewer.char_width)
viewer.char_width = w;
if (h > viewer.line_height)
{
viewer.line_height = h;
viewer.num_display_lines = (LCD_HEIGHT - MARGIN_Y)/h;
}
}
}
#else
viewer.num_display_lines = 2;
viewer.char_width = 1;
viewer.line_height = 1;
#endif
viewer.move_track = -1;
if (!reload)
{
viewer.cursor_pos = 0;
if (!viewer.playlist)
/* Start displaying at current playing track */
viewer.first_display_index = playlist_get_display_index() - 1;
else
viewer.first_display_index = 0;
update_first_index();
}
if (!update_playlist(true))
return false;
return true;
}
/* Load tracks starting at start_index */
static void load_playlist_entries(int start_index)
{
int num_entries = viewer.num_tracks - start_index;
char* p = viewer.name_buffer;
int remaining = viewer.buffer_size;
int i;
viewer.first_index = start_index;
if (num_entries > MAX_PLAYLIST_ENTRIES)
num_entries = MAX_PLAYLIST_ENTRIES;
for(i=0; i<num_entries; i++, start_index++)
{
int len = load_entry(start_index, i, p, remaining);
if (len < 0)
{
/* Out of name buffer space */
num_entries = i;
break;
}
p += len;
remaining -= len;
}
viewer.num_loaded = num_entries;
viewer.last_index = viewer.first_index + (viewer.num_loaded - 1);
}
/* Load tracks in reverse, ending at end_index */
static void load_playlist_entries_r(int end_index)
{
int num_entries = end_index;
char* p = viewer.name_buffer;
int remaining = viewer.buffer_size;
int i;
viewer.last_index = end_index;
if (num_entries >= MAX_PLAYLIST_ENTRIES)
num_entries = MAX_PLAYLIST_ENTRIES-1;
for(i=num_entries; i>=0; i--, end_index--)
{
int len = load_entry(end_index, i, p, remaining);
if (len < 0)
{
int j;
/* Out of name buffer space */
num_entries -= i;
/* Shift loaded tracks up such that first track is index 0 */
for (j=0; j<num_entries; j++, i++)
{
tracks[j].name = tracks[i].name;
tracks[j].index = tracks[i].index;
tracks[j].display_index = tracks[i].display_index;
tracks[j].queued = tracks[i].queued;
}
break;
}
p += len;
remaining -= len;
}
viewer.first_index = viewer.last_index - num_entries;
num_entries++;
if (!viewer.first_index &&
num_entries < viewer.num_tracks &&
num_entries < MAX_PLAYLIST_ENTRIES)
{
/* Lets see if we can load more data at the end of the list */
int max = viewer.num_tracks;
if (max > MAX_PLAYLIST_ENTRIES)
max = MAX_PLAYLIST_ENTRIES;
for (i = num_entries; i<max; i++)
{
int len = load_entry(num_entries, num_entries, p, remaining);
if (len < 0)
/* Out of name buffer space */
break;
p += len;
remaining -= len;
num_entries++;
viewer.last_index++;
}
}
viewer.num_loaded = num_entries;
}
/* Load track at playlist index. pos is the position in the tracks array and
p is a pointer to the name buffer (max size), Returns -1 if buffer is
full. */
static int load_entry(int index, int pos, char* p, int size)
{
struct playlist_track_info info;
int len;
int result = 0;
/* Playlist viewer orders songs based on display index. We need to
convert to real playlist index to access track */
index = (index + playlist_get_first_index(viewer.playlist)) %
viewer.num_tracks;
if (playlist_get_track_info(viewer.playlist, index, &info) < 0)
return -1;
len = strlen(info.filename) + 1;
if (len <= size)
{
strcpy(p, info.filename);
tracks[pos].name = p;
tracks[pos].index = info.index;
tracks[pos].display_index = info.display_index;
tracks[pos].queued = info.attr & PLAYLIST_ATTR_QUEUED;
result = len;
}
else
result = -1;
return result;
}
/* Format trackname for display purposes */
static void format_name(char* dest, const char* src)
{
switch (global_settings.playlist_viewer_track_display)
{
case 0:
default:
{
/* Only display the mp3 filename */
char* p = strrchr(src, '/');
int len;
strcpy(dest, p+1);
len = strlen(dest);
/* Remove the extension */
if (!strcasecmp(&dest[len-4], ".mp3") ||
!strcasecmp(&dest[len-4], ".mp2") ||
!strcasecmp(&dest[len-4], ".mpa"))
dest[len-4] = '\0';
break;
}
case 1:
/* Full path */
strcpy(dest, src);
break;
}
}
/* Format display line */
static void format_line(const struct playlist_entry* track, char* str, int len)
{
char name[MAX_PATH];
format_name(name, track->name);
if (global_settings.playlist_viewer_indices)
/* Display playlist index */
snprintf(str, len, "%d. %s", track->display_index, name);
else
snprintf(str, len, "%s", name);
}
/* Display tracks on screen */
static void display_playlist(void)
{
int i;
int num_display_tracks =
viewer.last_display_index - viewer.first_display_index;
lcd_clear_display();
#ifdef HAVE_LCD_BITMAP
lcd_setmargins(MARGIN_X, MARGIN_Y);
lcd_setfont(FONT_UI);
#endif
for (i=0; i<=num_display_tracks; i++)
{
if (global_settings.playlist_viewer_icons)
{
/* Icons */
if (tracks[INDEX(i)].index == viewer.current_playing_track)
{
/* Current playing track */
#ifdef HAVE_LCD_BITMAP
int offset=0;
if ( viewer.line_height > 8 )
offset = (viewer.line_height - 8) / 2;
lcd_bitmap(bitmap_icons_6x8[File],
CURSOR_X * 6 + CURSOR_WIDTH,
MARGIN_Y+(i*viewer.line_height) + offset,
6, 8, true);
#else
lcd_putc(LINE_X-1, i, File);
#endif
}
else if (tracks[INDEX(i)].index == viewer.move_track)
{
/* Track we are moving */
#ifdef HAVE_LCD_BITMAP
lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH,
MARGIN_Y+(i*viewer.line_height), "M");
#else
lcd_putc(LINE_X-1, i, 'M');
#endif
}
else if (tracks[INDEX(i)].queued)
{
/* Queued track */
#ifdef HAVE_LCD_BITMAP
lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH,
MARGIN_Y+(i*viewer.line_height), "Q");
#else
lcd_putc(LINE_X-1, i, 'Q');
#endif
}
}
update_display_line(i, false);
}
#ifdef HAVE_LCD_BITMAP
if (global_settings.scrollbar &&
(viewer.num_tracks > viewer.num_display_lines))
scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1,
LCD_HEIGHT - SCROLLBAR_Y, viewer.num_tracks-1,
viewer.first_display_index, viewer.last_display_index,
VERTICAL);
#endif
put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true);
status_draw(true);
}
/* Scroll cursor or display by num lines */
static void scroll_display(int lines)
{
int new_index = viewer.first_display_index + viewer.cursor_pos + lines;
bool pagescroll = false;
bool wrap = false;
put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false);
if (lines > 1 || lines < -1)
pagescroll = true;
if (new_index < 0)
{
/* Wrap around if not pageup */
if (pagescroll)
new_index = 0;
else
{
new_index += viewer.num_tracks;
viewer.cursor_pos = viewer.num_display_lines-1;
wrap = true;
}
}
else if (new_index >= viewer.num_tracks)
{
/* Wrap around if not pagedown */
if (pagescroll)
new_index = viewer.num_tracks - 1;
else
{
new_index -= viewer.num_tracks;
viewer.cursor_pos = 0;
wrap = true;
}
}
if (new_index >= viewer.first_display_index &&
new_index <= viewer.last_display_index)
{
/* Just update the cursor */
viewer.cursor_pos = new_index - viewer.first_display_index;
}
else
{
/* New track is outside of display */
if (wrap)
viewer.first_display_index = new_index;
else
viewer.first_display_index = viewer.first_display_index + lines;
if (viewer.first_display_index < 0)
viewer.first_display_index = 0;
viewer.last_display_index =
viewer.first_display_index + (viewer.num_display_lines - 1);
if (viewer.last_display_index >= viewer.num_tracks)
{
/* display as many tracks as possible on screen */
if (viewer.first_display_index > 0)
{
viewer.first_display_index -=
(viewer.last_display_index - viewer.num_tracks + 1);
if (viewer.first_display_index < 0)
viewer.first_display_index = 0;
}
viewer.last_display_index = viewer.num_tracks - 1;
}
if (viewer.cursor_pos >
(viewer.last_display_index - viewer.first_display_index))
viewer.cursor_pos =
viewer.last_display_index - viewer.first_display_index;
/* Load more data if needed */
if (viewer.first_display_index < viewer.first_index)
load_playlist_entries_r(viewer.last_display_index);
else if (viewer.last_display_index > viewer.last_index)
load_playlist_entries(viewer.first_display_index);
display_playlist();
}
put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true);
}
/* Update lcd line. Scroll line if requested */
static void update_display_line(int line, bool scroll)
{
char str[MAX_PATH + 16];
format_line(&tracks[INDEX(line)], str, sizeof(str));
if (scroll)
{
#ifdef HAVE_LCD_BITMAP
if (global_settings.invert_cursor)
lcd_puts_scroll_style(LINE_X, line, str, STYLE_INVERT);
else
#endif
lcd_puts_scroll(LINE_X, line, str);
}
else
lcd_puts(LINE_X, line, str);
}
/* Update first index, if necessary, to put as much as possible on the
screen */
static void update_first_index(void)
{
/* viewer.num_tracks may be invalid at this point */
int num_tracks = playlist_amount_ex(viewer.playlist);
if ((num_tracks - viewer.first_display_index) < viewer.num_display_lines)
{
/* Try to display as much as possible */
int old_index = viewer.first_display_index;
viewer.first_display_index = num_tracks - viewer.num_display_lines;
if (viewer.first_display_index < 0)
viewer.first_display_index = 0;
/* Cursor should still point at current track */
viewer.cursor_pos += old_index - viewer.first_display_index;
}
}
/* Update playlist in case something has changed or forced */
static bool update_playlist(bool force)
{
if (!viewer.playlist)
playlist_get_resume_info(&viewer.current_playing_track);
else
viewer.current_playing_track = -1;
if (force || playlist_amount_ex(viewer.playlist) != viewer.num_tracks)
{
int index;
/* Reload tracks */
viewer.num_tracks = playlist_amount_ex(viewer.playlist);
if (viewer.num_tracks < 0)
return false;
index = viewer.first_display_index;
load_playlist_entries(index);
if (viewer.num_loaded <= 0)
return false;
viewer.first_display_index = viewer.first_index;
viewer.last_display_index =
viewer.first_index + viewer.num_display_lines - 1;
if (viewer.last_display_index >= viewer.num_tracks)
viewer.last_display_index = viewer.num_tracks - 1;
}
display_playlist();
return true;
}
#ifdef TREE_SHIFT
/* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen.
Returns -1 if USB attached, 0 if no playlist change, and 1 if playlist
changed. */
static int onplay_menu(int index)
{
struct menu_item items[3]; /* increase this if you add entries! */
int m, i=0, result, ret = 0;
bool current = (tracks[index].index == viewer.current_playing_track);
items[i].desc = ID2P(LANG_REMOVE);
i++;
items[i].desc = ID2P(LANG_MOVE);
i++;
items[i].desc = ID2P(LANG_FILE_OPTIONS);
i++;
m = menu_init(items, i, NULL, NULL, NULL, NULL);
result = menu_show(m);
if (result == MENU_ATTACHED_USB)
ret = -1;
else if (result >= 0)
{
/* Abort current move */
viewer.move_track = -1;
switch (result)
{
case 0:
/* delete track */
if (current)
mpeg_stop();
playlist_delete(viewer.playlist, tracks[index].index);
if (current)
{
/* Start playing new track except if it's the last track
in the playlist and repeat mode is disabled */
if (tracks[index].display_index != viewer.num_tracks ||
global_settings.repeat_mode == REPEAT_ALL)
{
talk_buffer_steal(); /* will use the mp3 buffer */
mpeg_play(0);
viewer.current_playing_track = -1;
}
}
ret = 1;
break;
case 1:
/* move track */
viewer.move_track = tracks[index].index;
ret = 0;
break;
case 2:
{
onplay(tracks[index].name, TREE_ATTR_MPA);
if (!viewer.playlist)
ret = 1;
else
ret = 0;
break;
}
}
}
menu_exit(m);
return ret;
}
#endif
/* Menu of viewer options. Invoked via F1(r) or Menu(p). */
static bool viewer_menu(void)
{
int m;
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_SHOW_ICONS), show_icons },
{ ID2P(LANG_SHOW_INDICES), show_indices },
{ ID2P(LANG_TRACK_DISPLAY), track_display },
{ ID2P(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL );
result = menu_run(m);
menu_exit(m);
settings_save();
return result;
}
/* Show icons in viewer? */
static bool show_icons(void)
{
return set_bool(str(LANG_SHOW_ICONS),
&global_settings.playlist_viewer_icons);
}
/* Show indices of tracks? */
static bool show_indices(void)
{
return set_bool(str(LANG_SHOW_INDICES),
&global_settings.playlist_viewer_indices);
}
/* How to display a track */
static bool track_display(void)
{
static const struct opt_items names[] = {
{ STR(LANG_DISPLAY_TRACK_NAME_ONLY) },
{ STR(LANG_DISPLAY_FULL_PATH) }
};
return set_option(str(LANG_TRACK_DISPLAY),
&global_settings.playlist_viewer_track_display, INT, names, 2, NULL);
}
/* Save playlist to disk */
static bool save_playlist(void)
{
char filename[MAX_PATH+1];
strncpy(filename, DEFAULT_PLAYLIST_NAME, sizeof(filename));
if (!kbd_input(filename, sizeof(filename)))
{
playlist_save(viewer.playlist, filename);
/* reload in case playlist was saved to cwd */
reload_directory();
}
return false;
}
/* View current playlist */
bool playlist_viewer(void)
{
return playlist_viewer_ex(NULL);
}
/* Main viewer function. Filename identifies playlist to be viewed. If NULL,
view current playlist. */
bool playlist_viewer_ex(char* filename)
{
bool ret = false; /* return value */
bool exit=false; /* exit viewer */
bool update=true; /* update display */
bool cursor_on=true; /* used for flashing cursor */
int old_cursor_pos; /* last cursor position */
int button;
if (!initialize(filename, false))
goto exit;
old_cursor_pos = viewer.cursor_pos;
while (!exit)
{
int track;
if (!viewer.playlist && !(mpeg_status() & MPEG_STATUS_PLAY))
{
/* Play has stopped */
#ifdef HAVE_LCD_CHARCELLS
splash(HZ, true, str(LANG_END_PLAYLIST_PLAYER));
#else
splash(HZ, true, str(LANG_END_PLAYLIST_RECORDER));
#endif
goto exit;
}
if (viewer.move_track != -1 || !cursor_on)
{
/* Flash cursor to identify that we are moving a track */
cursor_on = !cursor_on;
#ifdef HAVE_LCD_BITMAP
if (global_settings.invert_cursor)
{
lcd_invertrect(
MARGIN_X, MARGIN_Y+(viewer.cursor_pos*viewer.line_height),
LCD_WIDTH, viewer.line_height);
lcd_invertscroll(LINE_X, viewer.cursor_pos);
}
else
put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos,
cursor_on);
lcd_update_rect(
0, MARGIN_Y + (viewer.cursor_pos * viewer.line_height),
LCD_WIDTH, viewer.line_height);
#else
put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, cursor_on);
lcd_update();
#endif
}
if (!viewer.playlist)
playlist_get_resume_info(&track);
else
track = -1;
if (track != viewer.current_playing_track ||
playlist_amount_ex(viewer.playlist) != viewer.num_tracks)
{
/* Playlist has changed (new track started?) */
update_first_index();
if (!update_playlist(false))
goto exit;
else
update = true;
/* Abort move on playlist change */
viewer.move_track = -1;
}
/* Timeout so we can determine if play status has changed */
button = button_get_w_tmo(HZ/2);
switch (button)
{
case TREE_EXIT:
exit = true;
break;
case TREE_PREV:
case TREE_PREV | BUTTON_REPEAT:
scroll_display(-1);
update = true;
break;
case TREE_NEXT:
case TREE_NEXT | BUTTON_REPEAT:
scroll_display(1);
update = true;
break;
case TREE_SHIFT | TREE_PREV:
case TREE_SHIFT | TREE_PREV | BUTTON_REPEAT:
/* Pageup */
scroll_display(-viewer.num_display_lines);
update = true;
break;
case TREE_SHIFT | TREE_NEXT:
case TREE_SHIFT | TREE_NEXT | BUTTON_REPEAT:
/* Pagedown */
scroll_display(viewer.num_display_lines);
update = true;
break;
case TREE_RUN:
if (viewer.move_track >= 0)
{
/* Move track */
int ret;
ret = playlist_move(viewer.playlist, viewer.move_track,
tracks[INDEX(viewer.cursor_pos)].index);
if (ret < 0)
splash(HZ, true, str(LANG_MOVE_FAILED));
update_playlist(true);
viewer.move_track = -1;
}
else if (!viewer.playlist)
{
/* Stop current track and play new track */
mpeg_stop();
playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0);
update_playlist(false);
}
else
{
/* Play track from playlist on disk */
mpeg_stop();
/* New playlist */
if (playlist_set_current(viewer.playlist) < 0)
goto exit;
playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0);
/* Our playlist is now the current list */
if (!initialize(NULL, true))
goto exit;
}
display_playlist();
update = true;
break;
case TREE_SHIFT | TREE_RUN:
{
/* ON+PLAY menu */
int ret;
ret = onplay_menu(INDEX(viewer.cursor_pos));
if (ret < 0)
{
ret = true;
goto exit;
}
else if (ret > 0)
{
/* Playlist changed */
update_first_index();
update_playlist(false);
if (viewer.num_tracks <= 0)
exit = true;
}
else
display_playlist();
update = true;
break;
}
case TREE_MENU:
if (viewer_menu())
{
ret = true;
goto exit;
}
display_playlist();
update = true;
break;
case BUTTON_NONE:
status_draw(false);
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
{
ret = true;
goto exit;
}
break;
}
if (update && !exit)
{
lcd_stop_scroll();
if (viewer.cursor_pos >
(viewer.last_display_index - viewer.first_display_index))
{
/* Cursor position is invalid */
put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false);
viewer.cursor_pos =
viewer.last_display_index - viewer.first_display_index;
put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true);
}
if (viewer.cursor_pos != old_cursor_pos &&
old_cursor_pos <=
(viewer.last_display_index - viewer.first_display_index))
/* Stop scrolling previous line */
update_display_line(old_cursor_pos, false);
/* Scroll line at new cursor position */
update_display_line(viewer.cursor_pos, true);
lcd_update();
old_cursor_pos = viewer.cursor_pos;
cursor_on = true;
update = false;
}
}
exit:
if (viewer.playlist)
playlist_close(viewer.playlist);
return ret;
}