forked from len0rd/rockbox
FS#10898 - Add a playlist viewer to the WPS. http://www.rockbox.org/wiki/CustomWPS#Playlist_viewer for an exaplanation how to use it.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24220 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
8b926e98f8
commit
dc0ba917fa
6 changed files with 253 additions and 1 deletions
|
|
@ -35,6 +35,8 @@
|
|||
#include "statusbar.h"
|
||||
#include "scrollbar.h"
|
||||
#include "screen_access.h"
|
||||
#include "playlist.h"
|
||||
#include "playback.h"
|
||||
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
#include "peakmeter.h"
|
||||
|
|
@ -163,6 +165,94 @@ static void draw_progressbar(struct gui_wps *gwps,
|
|||
cue_draw_markers(display, state->id3->cuesheet, length,
|
||||
pb->x, pb->x + pb->width, y+1, pb->height-2);
|
||||
}
|
||||
bool audio_peek_track(struct mp3entry* id3, int offset);
|
||||
static void draw_playlist_viewer_list(struct gui_wps *gwps,
|
||||
struct playlistviewer *viewer)
|
||||
{
|
||||
int lines = viewport_get_nb_lines(viewer->vp);
|
||||
int line_height = font_get(viewer->vp->font)->height;
|
||||
int cur_playlist_pos = playlist_get_display_index();
|
||||
int start_item = MAX(0, cur_playlist_pos + viewer->start_offset);
|
||||
int i;
|
||||
|
||||
struct mp3entry *pid3, id3;
|
||||
char buf[MAX_PATH*2], tempbuf[MAX_PATH];
|
||||
|
||||
|
||||
gwps->display->set_viewport(viewer->vp);
|
||||
for(i=start_item; (i-start_item)<lines && i<playlist_amount(); i++)
|
||||
{
|
||||
if (i == cur_playlist_pos)
|
||||
{
|
||||
pid3 = audio_current_track();
|
||||
}
|
||||
else if (i == cur_playlist_pos+1)
|
||||
{
|
||||
pid3 = audio_next_track();
|
||||
}
|
||||
else if ((i>cur_playlist_pos) && audio_peek_track(&id3, i-cur_playlist_pos))
|
||||
{
|
||||
pid3 = &id3;
|
||||
}
|
||||
else
|
||||
pid3 = NULL;
|
||||
|
||||
int line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO;
|
||||
int token = 0, cur_string = 0;
|
||||
char *filename = playlist_peek(i-cur_playlist_pos);
|
||||
buf[0] = '\0';
|
||||
while (token < viewer->lines[line].count)
|
||||
{
|
||||
switch (viewer->lines[line].tokens[token])
|
||||
{
|
||||
case WPS_TOKEN_STRING:
|
||||
case WPS_TOKEN_CHARACTER:
|
||||
strcat(buf, viewer->lines[line].strings[cur_string++]);
|
||||
break;
|
||||
case WPS_TOKEN_PLAYLIST_POSITION:
|
||||
snprintf(tempbuf, sizeof(tempbuf), "%d", i);
|
||||
strcat(buf, tempbuf);
|
||||
break;
|
||||
case WPS_TOKEN_FILE_NAME:
|
||||
get_dir(tempbuf, sizeof(tempbuf), filename, 0);
|
||||
strcat(buf, tempbuf);
|
||||
break;
|
||||
case WPS_TOKEN_FILE_PATH:
|
||||
strcat(buf, filename);
|
||||
break;
|
||||
case WPS_TOKEN_METADATA_ARTIST:
|
||||
if (pid3)
|
||||
strcat(buf, pid3->artist ? pid3->artist : "");
|
||||
break;
|
||||
case WPS_TOKEN_METADATA_TRACK_TITLE:
|
||||
if (pid3)
|
||||
strcat(buf, pid3->title ? pid3->title : "");
|
||||
break;
|
||||
case WPS_TOKEN_TRACK_LENGTH:
|
||||
if (pid3)
|
||||
{
|
||||
format_time(tempbuf, sizeof(tempbuf), pid3->length);
|
||||
strcat(buf, tempbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
token++;
|
||||
}
|
||||
|
||||
if (viewer->lines[line].scroll)
|
||||
{
|
||||
gwps->display->puts_scroll(0, (i-start_item), buf );
|
||||
}
|
||||
else
|
||||
{
|
||||
gwps->display->putsxy(0, (i-start_item)*line_height, buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* clears the area where the image was shown */
|
||||
static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img)
|
||||
|
|
@ -595,6 +685,11 @@ static bool get_line(struct gui_wps *gwps,
|
|||
}
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
case WPS_VIEWPORT_CUSTOMLIST:
|
||||
draw_playlist_viewer_list(gwps, data->tokens[i].value.data);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
/* get the value of the tag and copy it to the buffer */
|
||||
|
|
|
|||
|
|
@ -160,6 +160,8 @@ int parse_languagedirection(const char *wps_bufptr,
|
|||
#ifdef HAVE_LCD_BITMAP
|
||||
static int parse_viewport_display(const char *wps_bufptr,
|
||||
struct wps_token *token, struct wps_data *wps_data);
|
||||
static int parse_playlistview(const char *wps_bufptr,
|
||||
struct wps_token *token, struct wps_data *wps_data);
|
||||
static int parse_viewport(const char *wps_bufptr,
|
||||
struct wps_token *token, struct wps_data *wps_data);
|
||||
static int parse_statusbar_enable(const char *wps_bufptr,
|
||||
|
|
@ -373,6 +375,9 @@ static const struct wps_tag all_tags[] = {
|
|||
|
||||
{ WPS_VIEWPORT_ENABLE, "Vd", WPS_REFRESH_DYNAMIC,
|
||||
parse_viewport_display },
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
{ WPS_VIEWPORT_CUSTOMLIST, "Vp", WPS_REFRESH_STATIC, parse_playlistview },
|
||||
#endif
|
||||
{ WPS_NO_TOKEN, "V", 0, parse_viewport },
|
||||
|
||||
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
|
||||
|
|
@ -714,6 +719,119 @@ static int parse_viewport_display(const char *wps_bufptr,
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
int parse_playlistview_text(struct playlistviewer *viewer,
|
||||
enum info_line_type line, char* text)
|
||||
{
|
||||
int cur_string = 0;
|
||||
const struct wps_tag *tag;
|
||||
int taglen = 0;
|
||||
const char *start = text;
|
||||
if (*text != '|')
|
||||
return -1;
|
||||
text++;
|
||||
viewer->lines[line].count = 0;
|
||||
viewer->lines[line].scroll = false;
|
||||
while (*text != '|')
|
||||
{
|
||||
if (*text == '%') /* it is a token of some type */
|
||||
{
|
||||
text++;
|
||||
taglen = 0;
|
||||
switch(*text)
|
||||
{
|
||||
case '%':
|
||||
case '<':
|
||||
case '|':
|
||||
case '>':
|
||||
case ';':
|
||||
case '#':
|
||||
/* escaped characters */
|
||||
viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_CHARACTER;
|
||||
viewer->lines[line].strings[cur_string][0] = *text;
|
||||
viewer->lines[line].strings[cur_string++][0] = '\0';
|
||||
break;
|
||||
default:
|
||||
for (tag = all_tags;
|
||||
strncmp(text, tag->name, strlen(tag->name)) != 0;
|
||||
tag++) ;
|
||||
/* %s isnt stored as a tag so manually check for it */
|
||||
if (tag->type == WPS_NO_TOKEN)
|
||||
{
|
||||
if (!strncmp(tag->name, "s", 1))
|
||||
{
|
||||
viewer->lines[line].scroll = true;
|
||||
taglen = 1;
|
||||
}
|
||||
}
|
||||
else if (tag->type == WPS_TOKEN_UNKNOWN)
|
||||
{
|
||||
int i = 0;
|
||||
/* just copy the string */
|
||||
viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_STRING;
|
||||
while (i<(MAX_PLAYLISTLINE_STRLEN-1) && text[i] != '|' && text[i] != '%')
|
||||
{
|
||||
viewer->lines[line].strings[cur_string][i] = text[i];
|
||||
i++;
|
||||
}
|
||||
viewer->lines[line].strings[cur_string][i] = '\0';
|
||||
cur_string++;
|
||||
taglen = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
taglen = strlen(tag->name);
|
||||
viewer->lines[line].tokens[viewer->lines[line].count++] = tag->type;
|
||||
}
|
||||
text += taglen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* regular string */
|
||||
int i = 0;
|
||||
/* just copy the string */
|
||||
viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_STRING;
|
||||
while (i<(MAX_PLAYLISTLINE_STRLEN-1) && text[i] != '|' && text[i] != '%')
|
||||
{
|
||||
viewer->lines[line].strings[cur_string][i] = text[i];
|
||||
i++;
|
||||
}
|
||||
viewer->lines[line].strings[cur_string][i] = '\0';
|
||||
cur_string++;
|
||||
text += i;
|
||||
}
|
||||
}
|
||||
return text - start;
|
||||
}
|
||||
|
||||
|
||||
static int parse_playlistview(const char *wps_bufptr,
|
||||
struct wps_token *token, struct wps_data *wps_data)
|
||||
{
|
||||
(void)wps_data;
|
||||
/* %Vp|<use icons>|<start offset>|info line text|no info text| */
|
||||
struct playlistviewer *viewer = skin_buffer_alloc(sizeof(struct playlistviewer));
|
||||
char *ptr = strchr(wps_bufptr, '|');
|
||||
int length;
|
||||
if (!viewer || !ptr)
|
||||
return WPS_ERROR_INVALID_PARAM;
|
||||
viewer->vp = &curr_vp->vp;
|
||||
viewer->show_icons = true;
|
||||
viewer->start_offset = atoi(ptr+1);
|
||||
token->value.data = (void*)viewer;
|
||||
ptr = strchr(ptr+1, '|');
|
||||
length = parse_playlistview_text(viewer, TRACK_HAS_INFO, ptr);
|
||||
if (length < 0)
|
||||
return WPS_ERROR_INVALID_PARAM;
|
||||
length = parse_playlistview_text(viewer, TRACK_HAS_NO_INFO, ptr+length);
|
||||
if (length < 0)
|
||||
return WPS_ERROR_INVALID_PARAM;
|
||||
|
||||
return skip_end_of_line(wps_bufptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int parse_viewport(const char *wps_bufptr,
|
||||
struct wps_token *token,
|
||||
struct wps_data *wps_data)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ static char* get_codectype(const struct mp3entry* id3)
|
|||
*
|
||||
* Returns buf if the desired level was found, NULL otherwise.
|
||||
*/
|
||||
static char* get_dir(char* buf, int buf_size, const char* path, int level)
|
||||
char* get_dir(char* buf, int buf_size, const char* path, int level)
|
||||
{
|
||||
const char* sep;
|
||||
const char* last_sep;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ enum wps_token_type {
|
|||
|
||||
/* Viewport display */
|
||||
WPS_VIEWPORT_ENABLE,
|
||||
WPS_VIEWPORT_CUSTOMLIST,
|
||||
|
||||
/* Battery */
|
||||
TOKEN_MARKER_BATTERY,
|
||||
|
|
@ -237,6 +238,7 @@ struct skin_token_list {
|
|||
struct skin_token_list *next;
|
||||
};
|
||||
|
||||
char* get_dir(char* buf, int buf_size, const char* path, int level);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -225,6 +225,26 @@ struct touchregion {
|
|||
};
|
||||
#endif
|
||||
|
||||
#define MAX_PLAYLISTLINE_TOKENS 16
|
||||
#define MAX_PLAYLISTLINE_STRINGS 8
|
||||
#define MAX_PLAYLISTLINE_STRLEN 8
|
||||
enum info_line_type {
|
||||
TRACK_HAS_INFO = 0,
|
||||
TRACK_HAS_NO_INFO
|
||||
};
|
||||
struct playlistviewer {
|
||||
struct viewport *vp;
|
||||
bool show_icons;
|
||||
int start_offset;
|
||||
struct {
|
||||
enum wps_token_type tokens[MAX_PLAYLISTLINE_TOKENS];
|
||||
char strings[MAX_PLAYLISTLINE_STRINGS][MAX_PLAYLISTLINE_STRLEN];
|
||||
int count;
|
||||
bool scroll;
|
||||
} lines[2];
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_ALBUMART
|
||||
struct skin_albumart {
|
||||
|
|
|
|||
|
|
@ -629,6 +629,23 @@ struct mp3entry* audio_next_track(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool audio_peek_track(struct mp3entry* id3, int offset)
|
||||
{
|
||||
int next_idx;
|
||||
int new_offset = ci.new_track + wps_offset + offset;
|
||||
|
||||
if (!audio_have_tracks())
|
||||
return false;
|
||||
next_idx = (track_ridx + new_offset) & MAX_TRACK_MASK;
|
||||
|
||||
if (tracks[next_idx].id3_hid >= 0)
|
||||
{
|
||||
bufread(tracks[next_idx].id3_hid, sizeof(struct mp3entry), id3);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ALBUMART
|
||||
int playback_current_aa_hid(int slot)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue