mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
Added viewer for currently playing playlist. Accessed from Menu->Playlist Options->View Current Playlist.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4124 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
c882d45ebb
commit
00acdfa6ef
12 changed files with 1111 additions and 44 deletions
|
@ -1660,7 +1660,7 @@ new:
|
||||||
|
|
||||||
id: LANG_SAVE_DYNAMIC_PLAYLIST
|
id: LANG_SAVE_DYNAMIC_PLAYLIST
|
||||||
desc: in playlist menu.
|
desc: in playlist menu.
|
||||||
eng: "Save Dynamic Playlist"
|
eng: "Save Current Playlist"
|
||||||
new:
|
new:
|
||||||
|
|
||||||
id: LANG_PLAYLIST_MENU
|
id: LANG_PLAYLIST_MENU
|
||||||
|
@ -1827,3 +1827,18 @@ id: LANG_FM_BUTTONBAR_RECORD
|
||||||
desc: in main menu
|
desc: in main menu
|
||||||
eng: "Record"
|
eng: "Record"
|
||||||
new:
|
new:
|
||||||
|
|
||||||
|
id: LANG_VIEW_DYNAMIC_PLAYLIST
|
||||||
|
desc: in playlist menu.
|
||||||
|
eng: "View Current Playlist"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_MOVE
|
||||||
|
desc: The verb/action Move
|
||||||
|
eng: "Move"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_MOVE_FAILED
|
||||||
|
desc: Error message displayed in playlist viewer
|
||||||
|
eng: "Move failed"
|
||||||
|
new:
|
||||||
|
|
171
apps/playlist.c
171
apps/playlist.c
|
@ -146,6 +146,7 @@ static int format_track_path(char *dest, char *src, int buf_length, int max,
|
||||||
static void display_playlist_count(int count, char *fmt);
|
static void display_playlist_count(int count, char *fmt);
|
||||||
static void display_buffer_full(void);
|
static void display_buffer_full(void);
|
||||||
static int flush_pending_control(void);
|
static int flush_pending_control(void);
|
||||||
|
static int rotate_index(int index);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove any files and indices associated with the playlist
|
* remove any files and indices associated with the playlist
|
||||||
|
@ -679,11 +680,7 @@ static int get_next_index(int steps)
|
||||||
{
|
{
|
||||||
case REPEAT_OFF:
|
case REPEAT_OFF:
|
||||||
{
|
{
|
||||||
/* Rotate indices such that first_index is considered index 0 to
|
current_index = rotate_index(current_index);
|
||||||
simplify next calculation */
|
|
||||||
current_index -= playlist.first_index;
|
|
||||||
if (current_index < 0)
|
|
||||||
current_index += playlist.amount;
|
|
||||||
|
|
||||||
next_index = current_index+steps;
|
next_index = current_index+steps;
|
||||||
if ((next_index < 0) || (next_index >= playlist.amount))
|
if ((next_index < 0) || (next_index >= playlist.amount))
|
||||||
|
@ -992,6 +989,18 @@ static int flush_pending_control(void)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rotate indices such that first_index is index 0
|
||||||
|
*/
|
||||||
|
static int rotate_index(int index)
|
||||||
|
{
|
||||||
|
index -= playlist.first_index;
|
||||||
|
if (index < 0)
|
||||||
|
index += playlist.amount;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize playlist entries at startup
|
* Initialize playlist entries at startup
|
||||||
*/
|
*/
|
||||||
|
@ -1604,21 +1613,104 @@ int playlist_insert_playlist(char *filename, int position, bool queue)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* delete track at specified index */
|
/*
|
||||||
|
* Delete track at specified index. If index is PLAYLIST_DELETE_CURRENT then
|
||||||
|
* we want to delete the current playing track.
|
||||||
|
*/
|
||||||
int playlist_delete(int index)
|
int playlist_delete(int index)
|
||||||
{
|
{
|
||||||
int result;
|
int result = 0;
|
||||||
|
|
||||||
if (playlist.control_fd < 0)
|
if (playlist.control_fd < 0)
|
||||||
{
|
{
|
||||||
splash(HZ*2, 0, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
|
splash(HZ*2, 0, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index == PLAYLIST_DELETE_CURRENT)
|
||||||
|
index = playlist.index;
|
||||||
|
|
||||||
|
result = remove_track_from_playlist(index, true);
|
||||||
|
|
||||||
|
if (result != -1)
|
||||||
|
mpeg_flush_and_reload_tracks();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move track at index to new_index. Tracks between the two are shifted
|
||||||
|
* appropriately. Returns 0 on success and -1 on failure.
|
||||||
|
*/
|
||||||
|
int playlist_move(int index, int new_index)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
int seek;
|
||||||
|
bool control_file;
|
||||||
|
bool queue;
|
||||||
|
bool current = false;
|
||||||
|
int r = rotate_index(new_index);
|
||||||
|
char filename[MAX_PATH];
|
||||||
|
|
||||||
|
if (index == new_index)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (index == playlist.index)
|
||||||
|
/* Moving the current track */
|
||||||
|
current = true;
|
||||||
|
|
||||||
|
control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK;
|
||||||
|
queue = playlist.indices[index] & PLAYLIST_QUEUE_MASK;
|
||||||
|
seek = playlist.indices[index] & PLAYLIST_SEEK_MASK;
|
||||||
|
|
||||||
|
if (get_filename(seek, control_file, filename, sizeof(filename)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Delete track from original position */
|
||||||
result = remove_track_from_playlist(index, true);
|
result = remove_track_from_playlist(index, true);
|
||||||
|
|
||||||
if (result != -1)
|
if (result != -1)
|
||||||
mpeg_flush_and_reload_tracks();
|
{
|
||||||
|
/* We want to insert the track at the position that was specified by
|
||||||
|
new_index. This may be different then new_index because of the
|
||||||
|
shifting that occurred after the delete */
|
||||||
|
if (r == 0)
|
||||||
|
/* First index */
|
||||||
|
new_index = PLAYLIST_PREPEND;
|
||||||
|
else if (r == playlist.amount)
|
||||||
|
/* Append */
|
||||||
|
new_index = PLAYLIST_INSERT_LAST;
|
||||||
|
else
|
||||||
|
/* Calculate index of desired position */
|
||||||
|
new_index = (r+playlist.first_index)%playlist.amount;
|
||||||
|
|
||||||
|
result = add_track_to_playlist(filename, new_index, queue, -1);
|
||||||
|
|
||||||
|
if (result != -1)
|
||||||
|
{
|
||||||
|
if (current)
|
||||||
|
{
|
||||||
|
/* Moved the current track */
|
||||||
|
switch (new_index)
|
||||||
|
{
|
||||||
|
case PLAYLIST_PREPEND:
|
||||||
|
playlist.index = playlist.first_index;
|
||||||
|
break;
|
||||||
|
case PLAYLIST_INSERT_LAST:
|
||||||
|
playlist.index = playlist.first_index - 1;
|
||||||
|
if (playlist.index < 0)
|
||||||
|
playlist.index += playlist.amount;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
playlist.index = new_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fsync(playlist.control_fd);
|
||||||
|
mpeg_flush_and_reload_tracks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1763,21 +1855,13 @@ int playlist_next(int steps)
|
||||||
index = get_next_index(steps);
|
index = get_next_index(steps);
|
||||||
playlist.index = index;
|
playlist.index = index;
|
||||||
|
|
||||||
if (playlist.last_insert_pos >= 0)
|
if (playlist.last_insert_pos >= 0 && steps > 0)
|
||||||
{
|
{
|
||||||
/* check to see if we've gone beyond the last inserted track */
|
/* check to see if we've gone beyond the last inserted track */
|
||||||
int rot_index = index;
|
int cur = rotate_index(index);
|
||||||
int rot_last_pos = playlist.last_insert_pos;
|
int last_pos = rotate_index(playlist.last_insert_pos);
|
||||||
|
|
||||||
rot_index -= playlist.first_index;
|
if (cur > last_pos)
|
||||||
if (rot_index < 0)
|
|
||||||
rot_index += playlist.amount;
|
|
||||||
|
|
||||||
rot_last_pos -= playlist.first_index;
|
|
||||||
if (rot_last_pos < 0)
|
|
||||||
rot_last_pos += playlist.amount;
|
|
||||||
|
|
||||||
if (rot_index > rot_last_pos)
|
|
||||||
{
|
{
|
||||||
/* reset last inserted track */
|
/* reset last inserted track */
|
||||||
playlist.last_insert_pos = -1;
|
playlist.last_insert_pos = -1;
|
||||||
|
@ -1826,16 +1910,18 @@ int playlist_get_resume_info(short *resume_index)
|
||||||
index into the playlist */
|
index into the playlist */
|
||||||
int playlist_get_display_index(void)
|
int playlist_get_display_index(void)
|
||||||
{
|
{
|
||||||
int index = playlist.index;
|
|
||||||
|
|
||||||
/* first_index should always be index 0 for display purposes */
|
/* first_index should always be index 0 for display purposes */
|
||||||
index -= playlist.first_index;
|
int index = rotate_index(playlist.index);
|
||||||
if (index < 0)
|
|
||||||
index += playlist.amount;
|
|
||||||
|
|
||||||
return (index+1);
|
return (index+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* returns index of first track in playlist */
|
||||||
|
int playlist_get_first_index(void)
|
||||||
|
{
|
||||||
|
return playlist.first_index;
|
||||||
|
}
|
||||||
|
|
||||||
/* returns number of tracks in playlist (includes queued/inserted tracks) */
|
/* returns number of tracks in playlist (includes queued/inserted tracks) */
|
||||||
int playlist_amount(void)
|
int playlist_amount(void)
|
||||||
{
|
{
|
||||||
|
@ -1860,6 +1946,39 @@ char *playlist_name(char *buf, int buf_size)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fills info structure with information about track at specified index.
|
||||||
|
Returns 0 on success and -1 on failure */
|
||||||
|
int playlist_get_track_info(int index, struct playlist_track_info* info)
|
||||||
|
{
|
||||||
|
int seek;
|
||||||
|
bool control_file;
|
||||||
|
|
||||||
|
if (index < 0 || index >= playlist.amount)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK;
|
||||||
|
seek = playlist.indices[index] & PLAYLIST_SEEK_MASK;
|
||||||
|
|
||||||
|
if (get_filename(seek, control_file, info->filename,
|
||||||
|
sizeof(info->filename)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
info->attr = 0;
|
||||||
|
|
||||||
|
if (control_file)
|
||||||
|
{
|
||||||
|
if (playlist.indices[index] & PLAYLIST_QUEUE_MASK)
|
||||||
|
info->attr |= PLAYLIST_ATTR_QUEUED;
|
||||||
|
else
|
||||||
|
info->attr |= PLAYLIST_ATTR_INSERTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->index = index;
|
||||||
|
info->display_index = rotate_index(index) + 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* save the current dynamic playlist to specified file */
|
/* save the current dynamic playlist to specified file */
|
||||||
int playlist_save(char *filename)
|
int playlist_save(char *filename)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,17 @@ struct playlist_info
|
||||||
struct mutex control_mutex; /* mutex for control file access */
|
struct mutex control_mutex; /* mutex for control file access */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PLAYLIST_ATTR_QUEUED 0x01
|
||||||
|
#define PLAYLIST_ATTR_INSERTED 0x02
|
||||||
|
|
||||||
|
struct playlist_track_info
|
||||||
|
{
|
||||||
|
char filename[MAX_PATH]; /* path name of mp3 file */
|
||||||
|
int attr; /* playlist attributes for track */
|
||||||
|
int index; /* index of track in playlist */
|
||||||
|
int display_index; /* index of track for display */
|
||||||
|
};
|
||||||
|
|
||||||
void playlist_init(void);
|
void playlist_init(void);
|
||||||
int playlist_create(char *dir, char *file);
|
int playlist_create(char *dir, char *file);
|
||||||
int playlist_resume(void);
|
int playlist_resume(void);
|
||||||
|
@ -56,6 +67,7 @@ int playlist_insert_directory(char *dirname, int position, bool queue,
|
||||||
bool recurse);
|
bool recurse);
|
||||||
int playlist_insert_playlist(char *filename, int position, bool queue);
|
int playlist_insert_playlist(char *filename, int position, bool queue);
|
||||||
int playlist_delete(int index);
|
int playlist_delete(int index);
|
||||||
|
int playlist_move(int index, int new_index);
|
||||||
int playlist_shuffle(int random_seed, int start_index);
|
int playlist_shuffle(int random_seed, int start_index);
|
||||||
int playlist_randomise(unsigned int seed, bool start_current);
|
int playlist_randomise(unsigned int seed, bool start_current);
|
||||||
int playlist_sort(bool start_current);
|
int playlist_sort(bool start_current);
|
||||||
|
@ -65,8 +77,10 @@ char *playlist_peek(int steps);
|
||||||
int playlist_next(int steps);
|
int playlist_next(int steps);
|
||||||
int playlist_get_resume_info(short *resume_index);
|
int playlist_get_resume_info(short *resume_index);
|
||||||
int playlist_get_display_index(void);
|
int playlist_get_display_index(void);
|
||||||
|
int playlist_get_first_index(void);
|
||||||
int playlist_amount(void);
|
int playlist_amount(void);
|
||||||
char *playlist_name(char *buf, int buf_size);
|
char *playlist_name(char *buf, int buf_size);
|
||||||
|
int playlist_get_track_info(int index, struct playlist_track_info* info);
|
||||||
int playlist_save(char *filename);
|
int playlist_save(char *filename);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -76,4 +90,8 @@ enum {
|
||||||
PLAYLIST_INSERT_FIRST = -4
|
PLAYLIST_INSERT_FIRST = -4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PLAYLIST_DELETE_CURRENT = -1
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __PLAYLIST_H__ */
|
#endif /* __PLAYLIST_H__ */
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "playlist_viewer.h"
|
||||||
|
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
|
@ -64,9 +65,10 @@ bool playlist_menu(void)
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
struct menu_items items[] = {
|
struct menu_items items[] = {
|
||||||
{ str(LANG_CREATE_PLAYLIST), create_playlist },
|
{ str(LANG_CREATE_PLAYLIST), create_playlist },
|
||||||
{ str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
|
{ str(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer },
|
||||||
{ str(LANG_RECURSE_DIRECTORY), recurse_directory },
|
{ str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
|
||||||
|
{ str(LANG_RECURSE_DIRECTORY), recurse_directory },
|
||||||
};
|
};
|
||||||
|
|
||||||
m = menu_init( items, sizeof items / sizeof(struct menu_items) );
|
m = menu_init( items, sizeof items / sizeof(struct menu_items) );
|
||||||
|
|
848
apps/playlist_viewer.c
Normal file
848
apps/playlist_viewer.c
Normal file
|
@ -0,0 +1,848 @@
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
* __________ __ ___.
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#ifdef HAVE_LCD_BITMAP
|
||||||
|
#include "widgets.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "lang.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 + ICON_WIDTH)
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* 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 {
|
||||||
|
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 */
|
||||||
|
short 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];
|
||||||
|
|
||||||
|
#ifdef HAVE_LCD_BITMAP
|
||||||
|
extern unsigned char bitmap_icons_6x8[LastIcon][6];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool initialize(void);
|
||||||
|
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, char* src);
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Initialize the playlist viewer */
|
||||||
|
static bool initialize(void)
|
||||||
|
{
|
||||||
|
if (!(mpeg_status() & MPEG_STATUS_PLAY))
|
||||||
|
/* Nothing is playing, exit */
|
||||||
|
return false;
|
||||||
|
|
||||||
|
viewer.name_buffer = plugin_get_buffer(&viewer.buffer_size);
|
||||||
|
if (!viewer.name_buffer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#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.cursor_pos = 0;
|
||||||
|
viewer.move_track = -1;
|
||||||
|
|
||||||
|
/* Start displaying at current playing track */
|
||||||
|
viewer.first_display_index = playlist_get_display_index() - 1;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
char name[MAX_PATH];
|
||||||
|
|
||||||
|
/* 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.num_tracks;
|
||||||
|
if (playlist_get_track_info(index, &info) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
format_name(name, info.filename);
|
||||||
|
|
||||||
|
len = strlen(name) + 1;
|
||||||
|
|
||||||
|
if (len <= size)
|
||||||
|
{
|
||||||
|
strcpy(p, name);
|
||||||
|
|
||||||
|
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, char* src)
|
||||||
|
{
|
||||||
|
char* p = strrchr(src, '/');
|
||||||
|
int len;
|
||||||
|
|
||||||
|
/* Only display the mp3 filename */
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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++)
|
||||||
|
{
|
||||||
|
/* 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];
|
||||||
|
|
||||||
|
snprintf(str, sizeof(str), "%d. %s",
|
||||||
|
tracks[INDEX(line)].display_index,
|
||||||
|
tracks[INDEX(line)].name);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
playlist_get_resume_info(&viewer.current_playing_track);
|
||||||
|
|
||||||
|
if (force || playlist_amount() != viewer.num_tracks)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
/* Reload tracks */
|
||||||
|
viewer.num_tracks = playlist_amount();
|
||||||
|
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_items menu[2]; /* increase this if you add entries! */
|
||||||
|
int m, i=0, result, ret = 0;
|
||||||
|
bool current = (tracks[index].index == viewer.current_playing_track);
|
||||||
|
|
||||||
|
menu[i].desc = str(LANG_DELETE);
|
||||||
|
i++;
|
||||||
|
|
||||||
|
menu[i].desc = str(LANG_MOVE);
|
||||||
|
i++;
|
||||||
|
|
||||||
|
m = menu_init(menu, i);
|
||||||
|
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(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)
|
||||||
|
{
|
||||||
|
mpeg_play(0);
|
||||||
|
viewer.current_playing_track = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* move track */
|
||||||
|
viewer.move_track = tracks[index].index;
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_exit(m);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main viewer function */
|
||||||
|
bool playlist_viewer(void)
|
||||||
|
{
|
||||||
|
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())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
old_cursor_pos = viewer.cursor_pos;
|
||||||
|
|
||||||
|
while (!exit)
|
||||||
|
{
|
||||||
|
short track;
|
||||||
|
|
||||||
|
/* Timeout so we can determine if play status has changed */
|
||||||
|
button = button_get_w_tmo(HZ/2);
|
||||||
|
|
||||||
|
if (!(mpeg_status() & MPEG_STATUS_PLAY))
|
||||||
|
{
|
||||||
|
/* Play has stopped */
|
||||||
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
|
splash(HZ, 0, true, str(LANG_END_PLAYLIST_PLAYER));
|
||||||
|
#else
|
||||||
|
splash(HZ, 0, true, str(LANG_END_PLAYLIST_RECORDER));
|
||||||
|
#endif
|
||||||
|
status_set_playmode(STATUS_STOP);
|
||||||
|
return false;;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
playlist_get_resume_info(&track);
|
||||||
|
|
||||||
|
if (track != viewer.current_playing_track ||
|
||||||
|
playlist_amount() != viewer.num_tracks)
|
||||||
|
{
|
||||||
|
/* Playlist has changed (new track started?) */
|
||||||
|
update_first_index();
|
||||||
|
if (!update_playlist(false))
|
||||||
|
exit = true;
|
||||||
|
else
|
||||||
|
update = true;
|
||||||
|
|
||||||
|
/* Abort move on playlist change */
|
||||||
|
viewer.move_track = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_RECORDER_KEYPAD
|
||||||
|
case BUTTON_OFF:
|
||||||
|
case BUTTON_LEFT:
|
||||||
|
#else
|
||||||
|
case BUTTON_STOP:
|
||||||
|
#endif
|
||||||
|
exit = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef HAVE_RECORDER_KEYPAD
|
||||||
|
case BUTTON_UP:
|
||||||
|
case BUTTON_UP | BUTTON_REPEAT:
|
||||||
|
#else
|
||||||
|
case BUTTON_LEFT:
|
||||||
|
case BUTTON_LEFT | BUTTON_REPEAT:
|
||||||
|
#endif
|
||||||
|
scroll_display(-1);
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef HAVE_RECORDER_KEYPAD
|
||||||
|
case BUTTON_DOWN:
|
||||||
|
case BUTTON_DOWN | BUTTON_REPEAT:
|
||||||
|
#else
|
||||||
|
case BUTTON_RIGHT:
|
||||||
|
case BUTTON_RIGHT | BUTTON_REPEAT:
|
||||||
|
#endif
|
||||||
|
scroll_display(1);
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef HAVE_RECORDER_KEYPAD
|
||||||
|
case BUTTON_ON | BUTTON_UP:
|
||||||
|
case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
|
||||||
|
#else
|
||||||
|
case BUTTON_ON | BUTTON_LEFT:
|
||||||
|
case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT:
|
||||||
|
#endif
|
||||||
|
/* Pageup */
|
||||||
|
scroll_display(-viewer.num_display_lines);
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef HAVE_RECORDER_KEYPAD
|
||||||
|
case BUTTON_ON | BUTTON_DOWN:
|
||||||
|
case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT:
|
||||||
|
#else
|
||||||
|
case BUTTON_ON | BUTTON_RIGHT:
|
||||||
|
case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT:
|
||||||
|
#endif
|
||||||
|
/* Pagedown */
|
||||||
|
scroll_display(viewer.num_display_lines);
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef HAVE_RECORDER_KEYPAD
|
||||||
|
case BUTTON_RIGHT:
|
||||||
|
#endif
|
||||||
|
case BUTTON_PLAY:
|
||||||
|
if (viewer.move_track >= 0)
|
||||||
|
{
|
||||||
|
/* Move track */
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = playlist_move(viewer.move_track,
|
||||||
|
tracks[INDEX(viewer.cursor_pos)].index);
|
||||||
|
if (ret < 0)
|
||||||
|
splash(HZ, 0, true, str(LANG_MOVE_FAILED));
|
||||||
|
|
||||||
|
update_playlist(true);
|
||||||
|
viewer.move_track = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Stop current track and play new track */
|
||||||
|
mpeg_stop();
|
||||||
|
playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0);
|
||||||
|
status_set_playmode(STATUS_PLAY);
|
||||||
|
update_playlist(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
display_playlist();
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_ON | BUTTON_PLAY:
|
||||||
|
{
|
||||||
|
/* ON+PLAY menu */
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = onplay_menu(INDEX(viewer.cursor_pos));
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
/* USB attached */
|
||||||
|
return true;
|
||||||
|
else if (ret > 0)
|
||||||
|
{
|
||||||
|
/* Playlist changed */
|
||||||
|
update_first_index();
|
||||||
|
update_playlist(true);
|
||||||
|
if (viewer.num_tracks <= 0)
|
||||||
|
exit = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
display_playlist();
|
||||||
|
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SYS_USB_CONNECTED:
|
||||||
|
usb_screen();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
26
apps/playlist_viewer.h
Normal file
26
apps/playlist_viewer.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
* __________ __ ___.
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _PLAYLIST_VIEWER_H_
|
||||||
|
#define _PLAYLIST_VIEWER_H_
|
||||||
|
|
||||||
|
bool playlist_viewer(void);
|
||||||
|
|
||||||
|
#endif
|
29
apps/wps.c
29
apps/wps.c
|
@ -578,8 +578,6 @@ static bool menu(void)
|
||||||
status_set_param(false);
|
status_set_param(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wps_display(id3);
|
|
||||||
wps_refresh(id3, 0, WPS_REFRESH_ALL);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,6 +625,7 @@ int wps_show(void)
|
||||||
bool ignore_keyup = true;
|
bool ignore_keyup = true;
|
||||||
bool restore = false;
|
bool restore = false;
|
||||||
bool exit = false;
|
bool exit = false;
|
||||||
|
bool update_track = false;
|
||||||
|
|
||||||
id3 = NULL;
|
id3 = NULL;
|
||||||
current_track_path[0] = '\0';
|
current_track_path[0] = '\0';
|
||||||
|
@ -902,6 +901,7 @@ int wps_show(void)
|
||||||
if (menu())
|
if (menu())
|
||||||
return SYS_USB_CONNECTED;
|
return SYS_USB_CONNECTED;
|
||||||
|
|
||||||
|
update_track = true;
|
||||||
restore = true;
|
restore = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -939,18 +939,24 @@ int wps_show(void)
|
||||||
return SYS_USB_CONNECTED;
|
return SYS_USB_CONNECTED;
|
||||||
|
|
||||||
case BUTTON_NONE: /* Timeout */
|
case BUTTON_NONE: /* Timeout */
|
||||||
if (update())
|
update_track = true;
|
||||||
{
|
|
||||||
/* set dir browser to current playing song */
|
|
||||||
if (global_settings.browse_current &&
|
|
||||||
current_track_path[0] != '\0')
|
|
||||||
set_current_file(current_track_path);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (update_track)
|
||||||
|
{
|
||||||
|
if (update())
|
||||||
|
{
|
||||||
|
/* set dir browser to current playing song */
|
||||||
|
if (global_settings.browse_current &&
|
||||||
|
current_track_path[0] != '\0')
|
||||||
|
set_current_file(current_track_path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
update_track = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (exit) {
|
if (exit) {
|
||||||
#ifdef HAVE_LCD_CHARCELLS
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
status_set_record(false);
|
status_set_record(false);
|
||||||
|
@ -975,7 +981,6 @@ int wps_show(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( button )
|
if ( button )
|
||||||
ata_spin();
|
ata_spin();
|
||||||
|
|
||||||
|
|
|
@ -543,6 +543,29 @@ void lcd_invertrect (int x, int y, int nx, int ny)
|
||||||
INVERT_PIXEL((x + i), (y + j));
|
INVERT_PIXEL((x + i), (y + j));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reverse the invert setting of the scrolling line (if any) at given char
|
||||||
|
position. Setting will go into affect next time line scrolls. */
|
||||||
|
void lcd_invertscroll(int x, int y)
|
||||||
|
{
|
||||||
|
struct scrollinfo* s;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
for ( index = 0; index < SCROLLABLE_LINES; index++ ) {
|
||||||
|
/* is this a scrolling line? */
|
||||||
|
if ( !(scrolling_lines&(1<<index)) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s = &scroll[index];
|
||||||
|
|
||||||
|
if (s->startx == x && s->starty == y)
|
||||||
|
{
|
||||||
|
/* Found the line */
|
||||||
|
s->invert = !s->invert;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void lcd_drawline( int x1, int y1, int x2, int y2 )
|
void lcd_drawline( int x1, int y1, int x2, int y2 )
|
||||||
{
|
{
|
||||||
int numpixels;
|
int numpixels;
|
||||||
|
|
|
@ -126,6 +126,7 @@ extern void lcd_clearrect (int x, int y, int nx, int ny);
|
||||||
extern void lcd_fillrect (int x, int y, int nx, int ny);
|
extern void lcd_fillrect (int x, int y, int nx, int ny);
|
||||||
extern void lcd_drawrect (int x, int y, int nx, int ny);
|
extern void lcd_drawrect (int x, int y, int nx, int ny);
|
||||||
extern void lcd_invertrect (int x, int y, int nx, int ny);
|
extern void lcd_invertrect (int x, int y, int nx, int ny);
|
||||||
|
extern void lcd_invertscroll(int x, int y);
|
||||||
extern void lcd_drawline( int x1, int y1, int x2, int y2 );
|
extern void lcd_drawline( int x1, int y1, int x2, int y2 );
|
||||||
extern void lcd_clearline( int x1, int y1, int x2, int y2 );
|
extern void lcd_clearline( int x1, int y1, int x2, int y2 );
|
||||||
extern void lcd_drawpixel(int x, int y);
|
extern void lcd_drawpixel(int x, int y);
|
||||||
|
|
|
@ -101,7 +101,7 @@ FIRMSRCS = $(LCDSRSC) id3.c mp3data.c usb.c mpeg.c powermgmt.c power.c \
|
||||||
APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \
|
APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \
|
||||||
playlist.c wps.c wps-display.c settings.c status.c \
|
playlist.c wps.c wps-display.c settings.c status.c \
|
||||||
screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\
|
screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\
|
||||||
misc.c plugin.c
|
misc.c plugin.c playlist_viewer.c
|
||||||
|
|
||||||
MENUS = settings_menu.c sound_menu.c playlist_menu.c
|
MENUS = settings_menu.c sound_menu.c playlist_menu.c
|
||||||
|
|
||||||
|
@ -200,6 +200,9 @@ $(OBJDIR)/onplay.o: $(APPDIR)/onplay.c
|
||||||
$(OBJDIR)/playlist.o: $(APPDIR)/playlist.c
|
$(OBJDIR)/playlist.o: $(APPDIR)/playlist.c
|
||||||
$(CC) $(APPCFLAGS) -c $< -o $@
|
$(CC) $(APPCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/playlist_viewer.o: $(APPDIR)/playlist_viewer.c
|
||||||
|
$(CC) $(APPCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(OBJDIR)/plugin.o: $(APPDIR)/plugin.c plugin-win32.h
|
$(OBJDIR)/plugin.o: $(APPDIR)/plugin.c plugin-win32.h
|
||||||
$(CC) $(APPCFLAGS) -c $< -o $@
|
$(CC) $(APPCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
|
|
@ -365,6 +365,10 @@ SOURCE=..\..\apps\playlist_menu.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\apps\playlist_viewer.c
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=..\..\apps\plugin.c
|
SOURCE=..\..\apps\plugin.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
|
@ -101,7 +101,7 @@ FIRMSRCS = $(LCDSRSC) id3.c debug.c usb.c mpeg.c power.c\
|
||||||
APPS = main.c tree.c menu.c credits.c main_menu.c language.c\
|
APPS = main.c tree.c menu.c credits.c main_menu.c language.c\
|
||||||
playlist.c wps.c wps-display.c settings.c status.c icons.c\
|
playlist.c wps.c wps-display.c settings.c status.c icons.c\
|
||||||
screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\
|
screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\
|
||||||
misc.c plugin.c
|
misc.c plugin.c playlist_viewer.c
|
||||||
|
|
||||||
MENUS = settings_menu.c sound_menu.c playlist_menu.c
|
MENUS = settings_menu.c sound_menu.c playlist_menu.c
|
||||||
|
|
||||||
|
@ -197,6 +197,9 @@ $(OBJDIR)/onplay.o: $(APPDIR)/onplay.c
|
||||||
$(OBJDIR)/playlist.o: $(APPDIR)/playlist.c
|
$(OBJDIR)/playlist.o: $(APPDIR)/playlist.c
|
||||||
$(CC) $(APPCFLAGS) -c $< -o $@
|
$(CC) $(APPCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/playlist_viewer.o: $(APPDIR)/playlist_viewer.c
|
||||||
|
$(CC) $(APPCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(OBJDIR)/build.lang: $(APPDIR)/lang/$(LANGUAGE).lang
|
$(OBJDIR)/build.lang: $(APPDIR)/lang/$(LANGUAGE).lang
|
||||||
perl $(TOOLSDIR)/uplang $(APPDIR)/lang/english.lang $< > $@
|
perl $(TOOLSDIR)/uplang $(APPDIR)/lang/english.lang $< > $@
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue