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); diff --git a/lib/skin_parser/tag_table.c b/lib/skin_parser/tag_table.c index 4f201ec911..e7e30b1609 100644 --- a/lib/skin_parser/tag_table.c +++ b/lib/skin_parser/tag_table.c @@ -178,7 +178,7 @@ static const struct tag_info legal_tags[] = { SKIN_TOKEN_VIEWPORT_ENABLE, "Vd" , "S", SKIN_REFRESH_STATIC }, { SKIN_TOKEN_UIVIEWPORT_ENABLE, "VI" , "S", SKIN_REFRESH_STATIC }, - { SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "ICC", SKIN_REFRESH_DYNAMIC|NOBREAK }, + { SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "IC", SKIN_REFRESH_DYNAMIC|NOBREAK }, { SKIN_TOKEN_LIST_TITLE_TEXT, "Lt" , "", SKIN_REFRESH_DYNAMIC }, { SKIN_TOKEN_LIST_TITLE_ICON, "Li" , "", SKIN_REFRESH_DYNAMIC },