summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/gui/skin_engine/skin_display.c95
-rw-r--r--apps/gui/skin_engine/skin_parser.c118
-rw-r--r--apps/gui/skin_engine/skin_tokens.c2
-rw-r--r--apps/gui/skin_engine/skin_tokens.h2
-rw-r--r--apps/gui/skin_engine/wps_internals.h20
-rw-r--r--apps/playback.c17
6 files changed, 253 insertions, 1 deletions
diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c
index b8cc75e10a..e781d43372 100644
--- a/apps/gui/skin_engine/skin_display.c
+++ b/apps/gui/skin_engine/skin_display.c
@@ -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 */
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index c7bca24d1e..7efd169092 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -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)
diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c
index 794d7f4456..9b54361321 100644
--- a/apps/gui/skin_engine/skin_tokens.c
+++ b/apps/gui/skin_engine/skin_tokens.c
@@ -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;
diff --git a/apps/gui/skin_engine/skin_tokens.h b/apps/gui/skin_engine/skin_tokens.h
index 25acfdacef..5778f95808 100644
--- a/apps/gui/skin_engine/skin_tokens.h
+++ b/apps/gui/skin_engine/skin_tokens.h
@@ -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
diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h
index bd0c1c01c7..362f3947e7 100644
--- a/apps/gui/skin_engine/wps_internals.h
+++ b/apps/gui/skin_engine/wps_internals.h
@@ -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 {
diff --git a/apps/playback.c b/apps/playback.c
index ff20172d83..fca21ae1fb 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -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)
{