From dc3778a685835ff6db12db9e784af01de2165656 Mon Sep 17 00:00:00 2001 From: Jonathan Gordon Date: Sat, 14 Aug 2010 15:17:59 +0000 Subject: Rework the skin playlist viewer so it uses the same drawing code as everything else. This should mean that all text tags now work as expected. The 2nd code param is no longer needed so drop it (you can use conditionals and sublines and stuff in the one code param. example: %Vp(1, %?it<%in -%it|%fn>) <- show the next tracks strating from the first next track and show info if it is avilable or the filename. Basic cuesheet support here, and will load upcoming track tags from the database if you have load to ram enabled. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27814 a1c6a512-1295-4272-9138-f99709370657 --- apps/gui/skin_engine/skin_display.c | 190 +---------------------------------- apps/gui/skin_engine/skin_display.h | 3 +- apps/gui/skin_engine/skin_parser.c | 3 +- apps/gui/skin_engine/skin_render.c | 112 ++++++++++++++++++++- apps/gui/skin_engine/skin_tokens.c | 114 +++++++++++++++------ apps/gui/skin_engine/wps_internals.h | 13 +-- 6 files changed, 198 insertions(+), 237 deletions(-) (limited to 'apps/gui/skin_engine') diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c index d0044b14d8..53b568ad53 100644 --- a/apps/gui/skin_engine/skin_display.c +++ b/apps/gui/skin_engine/skin_display.c @@ -205,191 +205,6 @@ void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb) } } -void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer) -{ - struct wps_state *state = gwps->state; - int lines = viewport_get_nb_lines(viewer->vp); - int line_height = font_get(viewer->vp->font)->height; - int cur_pos, max; - int start_item; - int i; - bool scroll = false; - struct wps_token *token; - int x, length, alignment = SKIN_TOKEN_ALIGN_LEFT; - - struct mp3entry *pid3; - char buf[MAX_PATH*2], tempbuf[MAX_PATH], filename_buf[MAX_PATH + 1]; - const char *filename; -#if CONFIG_TUNER - if (current_screen() == GO_TO_FM) - { - cur_pos = radio_current_preset(); - start_item = cur_pos + viewer->start_offset; - max = start_item+radio_preset_count(); - } - else -#endif - { - cur_pos = playlist_get_display_index(); - max = playlist_amount()+1; - start_item = MAX(0, cur_pos + viewer->start_offset); - } - - gwps->display->set_viewport(viewer->vp); - for(i=start_item; (i-start_item)id3; - } - else if (i == cur_pos+1) - { - pid3 = state->nid3; - } -#if CONFIG_CODEC == SWCODEC - else if (i>cur_pos) - { -#ifdef HAVE_TC_RAMCACHE - if (tagcache_fill_tags(&viewer->tempid3, filename)) - { - pid3 = &viewer->tempid3; - } - else -#endif - if (!audio_peek_track(&pid3, i-cur_pos)) - pid3 = NULL; - } -#endif - else - { - pid3 = NULL; - } - line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO; - } - unsigned int line_len = 0; - if (viewer->lines[line]->children_count == 0) - return; - struct skin_element *element = viewer->lines[line]->children[0]; - buf[0] = '\0'; - while (element && line_len < sizeof(buf)) - { - const char *out = NULL; - if (element->type == TEXT) - { - line_len = strlcat(buf, (char*)element->data, sizeof(buf)); - element = element->next; - continue; - } - if (element->type != TAG) - { - element = element->next; - continue; - } - if (element->tag->type == SKIN_TOKEN_SUBLINE_SCROLL) - scroll = true; - token = (struct wps_token*)element->data; - out = get_id3_token(token, pid3, tempbuf, sizeof(tempbuf), -1, NULL); -#if CONFIG_TUNER - if (!out) - out = get_radio_token(token, i-cur_pos, - tempbuf, sizeof(tempbuf), -1, NULL); -#endif - if (out) - { - line_len = strlcat(buf, out, sizeof(buf)); - element = element->next; - continue; - } - - switch (token->type) - { - case SKIN_TOKEN_ALIGN_CENTER: - case SKIN_TOKEN_ALIGN_LEFT: - case SKIN_TOKEN_ALIGN_LEFT_RTL: - case SKIN_TOKEN_ALIGN_RIGHT: - case SKIN_TOKEN_ALIGN_RIGHT_RTL: - alignment = token->type; - tempbuf[0] = '\0'; - break; - case SKIN_TOKEN_PLAYLIST_POSITION: - snprintf(tempbuf, sizeof(tempbuf), "%d", i); - break; - case SKIN_TOKEN_FILE_NAME: - get_dir(tempbuf, sizeof(tempbuf), filename, 0); - break; - case SKIN_TOKEN_FILE_PATH: - snprintf(tempbuf, sizeof(tempbuf), "%s", filename); - break; - default: - tempbuf[0] = '\0'; - break; - } - if (tempbuf[0]) - { - line_len = strlcat(buf, tempbuf, sizeof(buf)); - } - element = element->next; - } - - int vpwidth = viewer->vp->width; - length = gwps->display->getstringsize(buf, NULL, NULL); - if (scroll && length >= vpwidth) - { - gwps->display->puts_scroll(0, (i-start_item), buf ); - } - else - { - if (length >= vpwidth) - x = 0; - else - { - switch (alignment) - { - case SKIN_TOKEN_ALIGN_CENTER: - x = (vpwidth-length)/2; - break; - case SKIN_TOKEN_ALIGN_LEFT_RTL: - if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) - { - x = vpwidth - length; - break; - } - case SKIN_TOKEN_ALIGN_LEFT: - x = 0; - break; - case SKIN_TOKEN_ALIGN_RIGHT_RTL: - if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) - { - x = 0; - break; - } - case SKIN_TOKEN_ALIGN_RIGHT: - x = vpwidth - length; - break; - default: - x = 0; - break; - } - } - gwps->display->putsxy(x, (i-start_item)*line_height, buf ); - } - } -} - - /* clears the area where the image was shown */ void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) { @@ -618,7 +433,8 @@ void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size) /* Evaluate the conditional that is at *token_index and return whether a skip has ocurred. *token_index is updated with the new position. */ -int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options) +int evaluate_conditional(struct gui_wps *gwps, int offset, + struct conditional *conditional, int num_options) { if (!gwps) return false; @@ -633,7 +449,7 @@ int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int intval = num_options; /* get_token_value needs to know the number of options in the enum */ - value = get_token_value(gwps, conditional->token, + value = get_token_value(gwps, conditional->token, offset, result, sizeof(result), &intval); /* intval is now the number of the enum option we want to read, diff --git a/apps/gui/skin_engine/skin_display.h b/apps/gui/skin_engine/skin_display.h index 81274a7391..67b7bfdf27 100644 --- a/apps/gui/skin_engine/skin_display.h +++ b/apps/gui/skin_engine/skin_display.h @@ -44,7 +44,8 @@ void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size); /* Evaluate the conditional that is at *token_index and return whether a skip has ocurred. *token_index is updated with the new position. */ -int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options); +int evaluate_conditional(struct gui_wps *gwps, int offset, + struct conditional *conditional, int num_options); /* Display a line appropriately according to its alignment format. format_align contains the text, separated between left, center and right. line is the index of the line on the screen. diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c index 8bc7edf9c3..8fca8724f6 100644 --- a/apps/gui/skin_engine/skin_parser.c +++ b/apps/gui/skin_engine/skin_parser.c @@ -385,8 +385,7 @@ static int parse_playlistview(struct skin_element *element, viewer->vp = &curr_vp->vp; viewer->show_icons = true; viewer->start_offset = element->params[0].data.number; - viewer->lines[0] = element->params[1].data.code; - viewer->lines[1] = element->params[2].data.code; + viewer->line = element->params[1].data.code; token->value.data = (void*)viewer; diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c index 3cc506b800..18b37ca22f 100644 --- a/apps/gui/skin_engine/skin_render.c +++ b/apps/gui/skin_engine/skin_render.c @@ -39,8 +39,12 @@ #if CONFIG_TUNER #include "radio.h" #endif +#include "viewport.h" +#include "cuesheet.h" #include "language.h" #include "playback.h" +#include "playlist.h" +#include "misc.h" #define MAX_LINE 1024 @@ -59,11 +63,18 @@ struct skin_draw_info { char *buf; size_t buf_size; + + int offset; /* used by the playlist viewer */ }; typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info); bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info); +static void skin_render_playlistviewer(struct playlistviewer* viewer, + struct gui_wps *gwps, + struct skin_viewport* skin_viewport, + unsigned long refresh_type); + static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info, struct skin_element *element, struct viewport* vp) @@ -159,7 +170,8 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info, char buf[16]; const char *out; int a = img->num_subimages; - out = get_token_value(gwps, id->token, buf, sizeof(buf), &a); + out = get_token_value(gwps, id->token, info->offset, + buf, sizeof(buf), &a); /* NOTE: get_token_value() returns values starting at 1! */ if (a == -1) @@ -207,7 +219,8 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info, break; case SKIN_TOKEN_VIEWPORT_CUSTOMLIST: if (do_refresh) - draw_playlist_viewer_list(gwps, token->value.data); + skin_render_playlistviewer(token->value.data, gwps, + info->skin_vp, info->refresh_type); break; #endif /* HAVE_LCD_BITMAP */ @@ -377,7 +390,8 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i case CONDITIONAL: conditional = (struct conditional*)child->data; last_value = conditional->last_value; - value = evaluate_conditional(info->gwps, conditional, child->children_count); + value = evaluate_conditional(info->gwps, info->offset, + conditional, child->children_count); if (value != 1 && value >= child->children_count) value = child->children_count-1; @@ -435,7 +449,8 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i if (!do_non_text_tags(info->gwps, info, child, &info->skin_vp->vp)) { const char *value = get_token_value(info->gwps, child->data, - tempbuf, sizeof(tempbuf), NULL); + info->offset, tempbuf, + sizeof(tempbuf), NULL); if (value) { needs_update = needs_update || @@ -520,7 +535,8 @@ static void skin_render_viewport(struct skin_element* viewport, struct gui_wps * .no_line_break = false, .line_scrolls = false, .refresh_type = refresh_type, - .skin_vp = skin_viewport + .skin_vp = skin_viewport, + .offset = 0 }; struct align_pos * align = &info.align; @@ -647,3 +663,89 @@ void skin_render(struct gui_wps *gwps, unsigned refresh_mode) display->set_viewport(NULL); display->update(); } + + +static void skin_render_playlistviewer(struct playlistviewer* viewer, + struct gui_wps *gwps, + struct skin_viewport* skin_viewport, + unsigned long refresh_type) +{ + struct screen *display = gwps->display; + char linebuf[MAX_LINE]; + skin_render_func func = skin_render_line; + struct skin_element* line; + struct skin_draw_info info = { + .gwps = gwps, + .buf = linebuf, + .buf_size = sizeof(linebuf), + .line_number = 0, + .no_line_break = false, + .line_scrolls = false, + .refresh_type = refresh_type, + .skin_vp = skin_viewport, + .offset = viewer->start_offset + }; + + struct align_pos * align = &info.align; + bool needs_update; + int cur_pos, start_item, max; + int nb_lines = viewport_get_nb_lines(viewer->vp); +#if CONFIG_TUNER + if (current_screen() == GO_TO_FM) + { + cur_pos = radio_current_preset(); + start_item = cur_pos + viewer->start_offset; + max = start_item+radio_preset_count(); + } + else +#endif + { + struct cuesheet *cue = gwps->state->id3 ? gwps->state->id3->cuesheet:NULL; + cur_pos = playlist_get_display_index(); + max = playlist_amount()+1; + if (cue) + max += cue->track_count; + start_item = MAX(0, cur_pos + viewer->start_offset); + } + if (max-start_item > nb_lines) + max = start_item + nb_lines; + + line = viewer->line; + while (start_item < max) + { + linebuf[0] = '\0'; + info.no_line_break = false; + info.line_scrolls = false; + info.force_redraw = false; + + info.cur_align_start = info.buf; + align->left = info.buf; + align->center = NULL; + align->right = NULL; + + + if (line->type == LINE_ALTERNATOR) + func = skin_render_alternator; + else if (line->type == LINE) + func = skin_render_line; + + needs_update = func(line, &info); + + /* only update if the line needs to be, and there is something to write */ + if (refresh_type && needs_update) + { + if (info.line_scrolls) + { + /* if the line is a scrolling one we don't want to update + too often, so that it has the time to scroll */ + if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw) + write_line(display, align, info.line_number, true); + } + else + write_line(display, align, info.line_number, false); + } + info.line_number++; + info.offset++; + start_item++; + } +} diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c index ebe9ac50b1..8218358769 100644 --- a/apps/gui/skin_engine/skin_tokens.c +++ b/apps/gui/skin_engine/skin_tokens.c @@ -53,6 +53,7 @@ #include "tdspeed.h" #endif #include "viewport.h" +#include "tagcache.h" #include "wps_internals.h" #include "root_menu.h" @@ -192,9 +193,39 @@ const char *get_cuesheetid3_token(struct wps_token *token, struct mp3entry *id3, return NULL; } +const char* get_filename_token(struct wps_token *token, char* filename, + char *buf, int buf_size) +{ + if (filename) + { + switch (token->type) + { + case SKIN_TOKEN_FILE_PATH: + return filename; + case SKIN_TOKEN_FILE_NAME: + if (get_dir(buf, buf_size, filename, 0)) { + /* Remove extension */ + char* sep = strrchr(buf, '.'); + if (NULL != sep) { + *sep = 0; + } + return buf; + } + return NULL; + case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION: + return get_dir(buf, buf_size, filename, 0); + case SKIN_TOKEN_FILE_DIRECTORY: + return get_dir(buf, buf_size, filename, token->value.i); + default: + return NULL; + } + } + return NULL; +} + /* All tokens which only need the info to return a value go in here */ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, - char *buf, int buf_size, int limit, int *intval) + char *filename, char *buf, int buf_size, int limit, int *intval) { struct wps_state *state = &wps_state; if (id3) @@ -260,8 +291,6 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, return NULL; case SKIN_TOKEN_METADATA_COMMENT: return id3->comment; - case SKIN_TOKEN_FILE_PATH: - return id3->path; case SKIN_TOKEN_FILE_BITRATE: if(id3->bitrate) snprintf(buf, buf_size, "%d", id3->bitrate); @@ -328,25 +357,11 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, id3->frequency / 1000, (id3->frequency % 1000) / 100); return buf; - case SKIN_TOKEN_FILE_NAME: - if (get_dir(buf, buf_size, id3->path, 0)) { - /* Remove extension */ - char* sep = strrchr(buf, '.'); - if (NULL != sep) { - *sep = 0; - } - return buf; - } - return NULL; - case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION: - return get_dir(buf, buf_size, id3->path, 0); + case SKIN_TOKEN_FILE_VBR: + return (id3->vbr) ? "(avg)" : NULL; case SKIN_TOKEN_FILE_SIZE: snprintf(buf, buf_size, "%ld", id3->filesize / 1024); return buf; - case SKIN_TOKEN_FILE_VBR: - return (id3->vbr) ? "(avg)" : NULL; - case SKIN_TOKEN_FILE_DIRECTORY: - return get_dir(buf, buf_size, id3->path, token->value.i); #ifdef HAVE_TAGCACHE case SKIN_TOKEN_DATABASE_PLAYCOUNT: @@ -367,7 +382,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, #endif default: - return NULL; + return get_filename_token(token, id3->path, buf, buf_size); } } else /* id3 == NULL, handle the error based on the expected return type */ @@ -388,7 +403,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, *intval = 0; return "0"; default: - return NULL; + return get_filename_token(token, filename, buf, buf_size); } } return buf; @@ -498,6 +513,41 @@ const char *get_radio_token(struct wps_token *token, int preset_offset, } #endif +static struct mp3entry* get_mp3entry_from_offset(struct gui_wps *gwps, + int offset, char **filename) +{ + struct mp3entry* pid3 = NULL; + struct cuesheet *cue = gwps->state->id3 ? gwps->state->id3->cuesheet:NULL; + const char *fname = NULL; + if (cue && cue->curr_track_idx + offset < cue->track_count) + pid3 = gwps->state->id3; + else if (offset == 0) + pid3 = gwps->state->id3; + else if (offset == 1) + pid3 = gwps->state->nid3; + else + { + static struct mp3entry tempid3; + static char filename_buf[MAX_PATH + 1]; + fname = playlist_peek(offset, filename_buf, sizeof(filename_buf)); + *filename = (char*)fname; +#if CONFIG_CODEC == SWCODEC +#ifdef HAVE_TC_RAMCACHE + if (tagcache_fill_tags(&tempid3, fname)) + { + pid3 = &tempid3; + } + else +#endif + { + if (!audio_peek_track(&pid3, offset)) + pid3 = NULL; + } +#endif + } + return pid3; +} + /* Return the tags value as text. buf should be used as temp storage if needed. intval is used with conditionals/enums: when this function is called, @@ -508,7 +558,7 @@ const char *get_radio_token(struct wps_token *token, int preset_offset, When not treating a conditional/enum, intval should be NULL. */ const char *get_token_value(struct gui_wps *gwps, - struct wps_token *token, + struct wps_token *token, int offset, char *buf, int buf_size, int *intval) { @@ -520,15 +570,14 @@ const char *get_token_value(struct gui_wps *gwps, struct mp3entry *id3; /* Think very carefully about using this. maybe get_id3_token() is the better place? */ const char *out_text = NULL; + char *filename = NULL; if (!data || !state) return NULL; - - if (token->next) - id3 = state->nid3; - else - id3 = state->id3; + id3 = get_mp3entry_from_offset(gwps, token->next? 1: offset, &filename); + if (id3) + filename = id3->path; #if CONFIG_RTC struct tm* tm = NULL; @@ -552,17 +601,18 @@ const char *get_token_value(struct gui_wps *gwps, *intval = -1; } - if (state->id3 && state->id3->cuesheet) + if (id3 && id3 == state->id3 && id3->cuesheet ) { - out_text = get_cuesheetid3_token(token, state->id3, token->next?1:0, buf, buf_size); + out_text = get_cuesheetid3_token(token, id3, + token->next?1:offset, buf, buf_size); if (out_text) return out_text; } - out_text = get_id3_token(token, id3, buf, buf_size, limit, intval); + out_text = get_id3_token(token, id3, filename, buf, buf_size, limit, intval); if (out_text) return out_text; #if CONFIG_TUNER - out_text = get_radio_token(token, 0, buf, buf_size, limit, intval); + out_text = get_radio_token(token, offset, buf, buf_size, limit, intval); if (out_text) return out_text; #endif @@ -596,7 +646,7 @@ const char *get_token_value(struct gui_wps *gwps, return playlist_name(NULL, buf, buf_size); case SKIN_TOKEN_PLAYLIST_POSITION: - snprintf(buf, buf_size, "%d", playlist_get_display_index()); + snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset); return buf; case SKIN_TOKEN_PLAYLIST_SHUFFLE: diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h index e1516bd8fd..ccae11b91a 100644 --- a/apps/gui/skin_engine/wps_internals.h +++ b/apps/gui/skin_engine/wps_internals.h @@ -194,18 +194,11 @@ struct touchregion { }; #endif -enum info_line_type { - TRACK_HAS_INFO = 0, - TRACK_HAS_NO_INFO -}; struct playlistviewer { struct viewport *vp; bool show_icons; int start_offset; -#ifdef HAVE_TC_RAMCACHE - struct mp3entry tempid3; -#endif - struct skin_element *lines[2]; + struct skin_element *line; }; @@ -334,7 +327,7 @@ char *get_image_filename(const char *start, const char* bmpdir, /***** wps_tokens.c ******/ const char *get_token_value(struct gui_wps *gwps, - struct wps_token *token, + struct wps_token *token, int offset, char *buf, int buf_size, int *intval); @@ -342,7 +335,7 @@ const char *get_token_value(struct gui_wps *gwps, const char *get_cuesheetid3_token(struct wps_token *token, struct mp3entry *id3, int offset_tracks, char *buf, int buf_size); const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, - char *buf, int buf_size, int limit, int *intval); + char *filename, char *buf, int buf_size, int limit, int *intval); #if CONFIG_TUNER const char *get_radio_token(struct wps_token *token, int preset_offset, char *buf, int buf_size, int limit, int *intval); -- cgit v1.2.3