rockbox/apps/playlist_viewer.c
Miika Pekkarinen c52f7f1b5e iRiver: Fixed broken items skipping on playlist: Now skipping and
marking them as bad instead of deleting the entries from playlist.
Faster buffered track skipping and preventing glitches from previous
tracks (still something might occur though, please report them).


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7647 a1c6a512-1295-4272-9138-f99709370657
2005-10-21 06:40:45 +00:00

1072 lines
31 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 "audio.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"
#include "action.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_VIEWER_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? */
bool skipped; /* Is track marked as bad? */
};
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);
static int onplay_menu(int index);
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 = audio_status() & AUDIO_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;
tracks[pos].skipped = info.attr & PLAYLIST_ATTR_SKIPPED;
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];
char *skipped = "";
format_name(name, track->name);
if (track->skipped)
skipped = "(ERR) ";
if (global_settings.playlist_viewer_indices)
/* Display playlist index */
snprintf(str, len, "%d. %s%s", track->display_index, skipped, name);
else
snprintf(str, len, "%s%s", skipped, 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_mono_bitmap(bitmap_icons_6x8[Icon_Audio],
CURSOR_X * 6 + CURSOR_WIDTH,
MARGIN_Y+(i*viewer.line_height) + offset, 6, 8);
#else
lcd_putc(LINE_X-1, i, Icon_Audio);
#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;
}
/* 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 */
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 */
audio_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, CONTEXT_TREE);
if (!viewer.playlist)
ret = 1;
else
ret = 0;
break;
}
}
}
menu_exit(m);
return ret;
}
/* 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_VIEWER_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, lastbutton = BUTTON_NONE;
if (!initialize(filename, false))
goto exit;
old_cursor_pos = viewer.cursor_pos;
while (!exit)
{
int track;
if (!viewer.playlist && !(audio_status() & AUDIO_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_set_drawmode(DRMODE_COMPLEMENT);
lcd_fillrect(
MARGIN_X, MARGIN_Y+(viewer.cursor_pos*viewer.line_height),
LCD_WIDTH, viewer.line_height);
lcd_set_drawmode(DRMODE_SOLID);
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:
#ifdef TREE_OFF
case TREE_OFF:
#endif
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;
#ifdef TREE_PGUP
case TREE_PGUP:
case TREE_PGUP | BUTTON_REPEAT:
/* Pageup */
scroll_display(-viewer.num_display_lines);
update = true;
break;
case TREE_PGDN:
case TREE_PGDN | BUTTON_REPEAT:
/* Pagedown */
scroll_display(viewer.num_display_lines);
update = true;
break;
#endif
case TREE_RUN:
#ifdef TREE_RUN_PRE
if (lastbutton != TREE_RUN_PRE)
break;
#endif
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)
{
/* play new track */
playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0);
update_playlist(false);
}
else
{
/* 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_CONTEXT:
#ifdef TREE_CONTEXT2
case TREE_CONTEXT2:
#endif
{
/* 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;
}
lastbutton = button;
}
exit:
if (viewer.playlist)
playlist_close(viewer.playlist);
return ret;
}