diff --git a/apps/SOURCES b/apps/SOURCES index 807f3ded9d..143d9d50ea 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -84,9 +84,10 @@ gui/statusbar.c gui/yesno.c gui/viewport.c +gui/skin_engine/skin_buffer.c gui/skin_engine/wps_debug.c gui/skin_engine/skin_display.c -gui/skin_engine/wps_parser.c +gui/skin_engine/skin_parser.c gui/skin_engine/skin_tokens.c #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) diff --git a/apps/gui/skin_engine/skin_buffer.c b/apps/gui/skin_engine/skin_buffer.c new file mode 100644 index 0000000000..2d10a931ec --- /dev/null +++ b/apps/gui/skin_engine/skin_buffer.c @@ -0,0 +1,100 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: wps_parser.c 19880 2009-01-29 20:49:43Z mcuelenaere $ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * Copyright (C) 2009 Jonathan Gordon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include "config.h" +#include "buffer.h" +#include "settings.h" +#include "screen_access.h" + +/* skin buffer management. + * This module is used to allocate space in a single global skin buffer for + * tokens for both/all screens. + * + * This is mostly just copy/paste from firmware/buffer.c + */ + +#define IMG_BUFSIZE (((LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \ + + (2*LCD_HEIGHT*LCD_WIDTH/8)) * NB_SCREENS) + +static unsigned char buffer_start[IMG_BUFSIZE], *buffer_pos = NULL; +static size_t buf_size = IMG_BUFSIZE; + +void skin_buffer_init(void) +{ +#if 0 /* this will go in again later probably */ + if (buffer_start == NULL) + { + buf_size = IMG_BUFSIZE;/* global_settings.skin_buf_size */ + + buffer_start = buffer_alloc(buf_size); + buffer_pos = buffer_start; + } + else +#endif + { + /* reset the buffer.... */ + buffer_pos = buffer_start; + } +} + +/* get the number of bytes currently being used */ +size_t skin_buffer_usage(void) +{ + return buffer_pos-buffer_start; +} + +/* Allocate size bytes from the buffer */ +void* skin_buffer_alloc(size_t size) +{ + void* retval = buffer_pos; + if (skin_buffer_usage()+size >= buf_size) + { + return NULL; + } + buffer_pos += size; + /* 32-bit aligned */ + buffer_pos = (void *)(((unsigned long)buffer_pos + 3) & ~3); + return retval; +} + +/* Get a pointer to the skin buffer and the count of how much is free + * used to do your own buffer management. + * Any memory used will be overwritten next time wps_buffer_alloc() + * is called unless skin_buffer_increment() is called first + */ +void* skin_buffer_grab(size_t *freespace) +{ + *freespace = buf_size - skin_buffer_usage(); + return buffer_pos; +} + +/* Use after skin_buffer_grab() to specify how much buffer was used */ +void skin_buffer_increment(size_t used) +{ + buffer_pos += used; + /* 32-bit aligned */ + buffer_pos = (void *)(((unsigned long)buffer_pos + 3) & ~3); +} + diff --git a/apps/gui/skin_engine/skin_buffer.h b/apps/gui/skin_engine/skin_buffer.h new file mode 100644 index 0000000000..779f575689 --- /dev/null +++ b/apps/gui/skin_engine/skin_buffer.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: wps_parser.c 19880 2009-01-29 20:49:43Z mcuelenaere $ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * Copyright (C) 2009 Jonathan Gordon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _SKIN_BUFFER_H_ +#define _SKIN_BUFFER_H_ + + +#include +#include +#include + +/* int the global buffer */ +void skin_buffer_init(void); + +/* get the number of bytes currently being used */ +size_t skin_buffer_usage(void); + +/* Allocate size bytes from the buffer */ +void* skin_buffer_alloc(size_t size); + + +/* Get a pointer to the skin buffer and the count of how much is free + * used to do your own buffer management. + * Any memory used will be overwritten next time wps_buffer_alloc() + * is called unless skin_buffer_increment() is called first + */ +void* skin_buffer_grab(size_t *freespace); + +/* Use after skin_buffer_grab() to specify how much buffer was used */ +void skin_buffer_increment(size_t used); + +#endif /* _SKIN_BUFFER_H_ */ diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c index bf342116a6..4e264b0489 100644 --- a/apps/gui/skin_engine/skin_display.c +++ b/apps/gui/skin_engine/skin_display.c @@ -68,34 +68,16 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode); -#ifdef HAVE_LCD_BITMAP -/* Clear the WPS image cache */ -static void wps_images_clear(struct wps_data *data) -{ - int i; - /* set images to unloaded and not displayed */ - for (i = 0; i < MAX_IMAGES; i++) - { - data->img[i].loaded = false; - data->img[i].display = -1; - data->img[i].always_display = false; - data->img[i].num_subimages = 1; - } -} -#endif - /* initial setup of wps_data */ void skin_data_init(struct wps_data *wps_data) { #ifdef HAVE_LCD_BITMAP - wps_images_clear(wps_data); wps_data->wps_sb_tag = false; wps_data->show_sb_on_wps = false; - wps_data->img_buf_ptr = wps_data->img_buf; /* where in image buffer */ - wps_data->img_buf_free = IMG_BUFSIZE; /* free space in image buffer */ wps_data->peak_meter_enabled = false; + wps_data->images = NULL; + wps_data->progressbars = NULL; /* progress bars */ - wps_data->progressbar_count = 0; #else /* HAVE_LCD_CHARCELLS */ int i; for (i = 0; i < 8; i++) @@ -191,41 +173,38 @@ static void draw_progressbar(struct gui_wps *gwps, } /* clears the area where the image was shown */ -static void clear_image_pos(struct gui_wps *gwps, int n) +static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) { if(!gwps) return; - struct wps_data *data = gwps->data; gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - gwps->display->fillrect(data->img[n].x, data->img[n].y, - data->img[n].bm.width, data->img[n].subimage_height); + gwps->display->fillrect(img->x, img->y, img->bm.width, img->subimage_height); gwps->display->set_drawmode(DRMODE_SOLID); } -static void wps_draw_image(struct gui_wps *gwps, int n, int subimage) +static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage) { struct screen *display = gwps->display; - struct wps_data *data = gwps->data; - if(data->img[n].always_display) + if(img->always_display) display->set_drawmode(DRMODE_FG); else display->set_drawmode(DRMODE_SOLID); #if LCD_DEPTH > 1 - if(data->img[n].bm.format == FORMAT_MONO) { + if(img->bm.format == FORMAT_MONO) { #endif - display->mono_bitmap_part(data->img[n].bm.data, - 0, data->img[n].subimage_height * subimage, - data->img[n].bm.width, data->img[n].x, - data->img[n].y, data->img[n].bm.width, - data->img[n].subimage_height); + display->mono_bitmap_part(img->bm.data, + 0, img->subimage_height * subimage, + img->bm.width, img->x, + img->y, img->bm.width, + img->subimage_height); #if LCD_DEPTH > 1 } else { - display->transparent_bitmap_part((fb_data *)data->img[n].bm.data, - 0, data->img[n].subimage_height * subimage, - data->img[n].bm.width, data->img[n].x, - data->img[n].y, data->img[n].bm.width, - data->img[n].subimage_height); + display->transparent_bitmap_part((fb_data *)img->bm.data, + 0, img->subimage_height * subimage, + img->bm.width, img->x, + img->y, img->bm.width, + img->subimage_height); } #endif } @@ -235,22 +214,25 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp) if(!gwps || !gwps->data || !gwps->display) return; - int n; struct wps_data *data = gwps->data; struct screen *display = gwps->display; + struct skin_token_list *list = data->images; - for (n = 0; n < MAX_IMAGES; n++) + while (list) { - if (data->img[n].loaded) + struct gui_img *img = (struct gui_img*)list->token->value.data; + if (img->loaded) { - if (data->img[n].display >= 0) + if (img->display >= 0) { - wps_draw_image(gwps, n, data->img[n].display); - } else if (data->img[n].always_display && data->img[n].vp == vp) + wps_draw_image(gwps, img, img->display); + } + else if (img->always_display && img->vp == vp) { - wps_draw_image(gwps, n, 0); + wps_draw_image(gwps, img, 0); } } + list = list->next; } display->set_drawmode(DRMODE_SOLID); } @@ -484,7 +466,7 @@ static bool evaluate_conditional(struct gui_wps *gwps, int *token_index) #ifdef HAVE_LCD_BITMAP /* clear all pictures in the conditional and nested ones */ if (data->tokens[i].type == WPS_TOKEN_IMAGE_PRELOAD_DISPLAY) - clear_image_pos(gwps, data->tokens[i].value.i & 0xFF); + clear_image_pos(gwps, find_image(data->tokens[i].value.i&0xFF, gwps->data)); #endif #ifdef HAVE_ALBUMART if (data->tokens[i].type == WPS_TOKEN_ALBUMART_DISPLAY) @@ -494,7 +476,20 @@ static bool evaluate_conditional(struct gui_wps *gwps, int *token_index) return true; } - +struct gui_img* find_image(int n, struct wps_data *data) +{ + struct skin_token_list *list = data->images; + while (list) + { + struct gui_img *img = (struct gui_img *)list->token->value.data; + if (img->id == n) + return img; + list = list->next; + } + return NULL; +} + + /* Read a (sub)line to the given alignment format buffer. linebuf is the buffer where the data is actually stored. align is the alignment format that'll be used to display the text. @@ -544,12 +539,12 @@ static bool get_line(struct gui_wps *gwps, #ifdef HAVE_LCD_BITMAP case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY: { - struct gui_img *img = data->img; int n = data->tokens[i].value.i & 0xFF; int subimage = data->tokens[i].value.i >> 8; + struct gui_img *img = find_image(n, data); - if (n >= 0 && n < MAX_IMAGES && img[n].loaded) - img[n].display = subimage; + if (img && img->loaded) + img->display = subimage; break; } #endif @@ -992,9 +987,12 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode) #ifdef HAVE_LCD_BITMAP /* Set images to not to be displayed */ - for (i = 0; i < MAX_IMAGES; i++) + struct skin_token_list *imglist = data->images; + while (imglist) { - data->img[i].display = -1; + struct gui_img *img = (struct gui_img *)imglist->token->value.data; + img->display = -1; + imglist = imglist->next; } #endif /* dont redraw the viewport if its disabled */ diff --git a/apps/gui/skin_engine/skin_engine.h b/apps/gui/skin_engine/skin_engine.h index 1f5236fc15..3ec7b93a9d 100644 --- a/apps/gui/skin_engine/skin_engine.h +++ b/apps/gui/skin_engine/skin_engine.h @@ -23,6 +23,8 @@ #ifndef _SKIN_ENGINE_H #define _SKIN_ENGINE_H +#include "skin_buffer.h" + #include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */ diff --git a/apps/gui/skin_engine/wps_parser.c b/apps/gui/skin_engine/skin_parser.c similarity index 92% rename from apps/gui/skin_engine/wps_parser.c rename to apps/gui/skin_engine/skin_parser.c index 4a41a26c7d..4445ee86c3 100644 --- a/apps/gui/skin_engine/wps_parser.c +++ b/apps/gui/skin_engine/skin_parser.c @@ -355,6 +355,40 @@ static const struct wps_tag all_tags[] = { /* the array MUST end with an empty string (first char is \0) */ }; + +/* add a wpsll item to the list chain. ALWAYS appended because some of the + * chains require the order to be kept. + */ +static void add_to_ll_chain(struct skin_token_list **list, struct skin_token_list *item) +{ + if (*list == NULL) + *list = item; + else + { + struct skin_token_list *t = *list; + while (t->next) + t = t->next; + t->next = item; + } +} +/* create and init a new wpsll item. + * passing NULL to token will alloc a new one. + */ +static struct skin_token_list *new_skin_token_list_item(struct wps_token *token, + void* token_data) +{ + struct skin_token_list *llitem = skin_buffer_alloc(sizeof(struct skin_token_list)); + if (!token) + token = skin_buffer_alloc(sizeof(struct wps_token)); + if (!llitem || !token) + return NULL; + llitem->next = NULL; + llitem->token = token; + if (token_data) + llitem->token->value.data = token_data; + return llitem; +} + /* Returns the number of chars that should be skipped to jump immediately after the first eol, i.e. to the start of the next line */ static int skip_end_of_line(const char *wps_bufptr) @@ -406,37 +440,6 @@ static int parse_statusbar_disable(const char *wps_bufptr, return skip_end_of_line(wps_bufptr); } -static bool load_bitmap(struct wps_data *wps_data, - char* filename, - struct bitmap *bm) -{ - int format; -#ifdef HAVE_REMOTE_LCD - if (wps_data->remote_wps) - format = FORMAT_ANY|FORMAT_REMOTE; - else -#endif - format = FORMAT_ANY|FORMAT_TRANSPARENT; - - int ret = read_bmp_file(filename, bm, - wps_data->img_buf_free, - format,NULL); - - if (ret > 0) - { -#if LCD_DEPTH == 16 - if (ret % 2) ret++; - /* Always consume an even number of bytes */ -#endif - wps_data->img_buf_ptr += ret; - wps_data->img_buf_free -= ret; - - return true; - } - else - return false; -} - static int get_image_id(int c) { if(c >= 'a' && c <= 'z') @@ -472,9 +475,9 @@ static int parse_image_display(const char *wps_bufptr, struct wps_token *token, struct wps_data *wps_data) { - (void)wps_data; int n = get_image_id(wps_bufptr[0]); int subimage; + struct gui_img *img;; if (n == -1) { @@ -484,8 +487,9 @@ static int parse_image_display(const char *wps_bufptr, if ((subimage = get_image_id(wps_bufptr[1])) != -1) { + img = find_image(n, wps_data); /* Sanity check */ - if (subimage >= wps_data->img[n].num_subimages) + if (!img || subimage >= img->num_subimages) return WPS_ERROR_INVALID_PARAM; /* Store sub-image number to display in high bits */ @@ -508,6 +512,7 @@ static int parse_image_load(const char *wps_bufptr, const char* id; const char *newline; int x,y; + struct gui_img *img; /* format: %x|n|filename.bmp|x|y| or %xl|n|filename.bmp|x|y| @@ -530,24 +535,28 @@ static int parse_image_load(const char *wps_bufptr, n = get_image_id(*id); /* check the image number and load state */ - if(n < 0 || n >= MAX_IMAGES || wps_data->img[n].loaded) + if(n < 0 || find_image(n, wps_data)) { /* Invalid image ID */ return WPS_ERROR_INVALID_PARAM; } - + img = skin_buffer_alloc(sizeof(struct gui_img)); + if (!img) + return WPS_ERROR_INVALID_PARAM; /* save a pointer to the filename */ - bmp_names[n] = filename; - - wps_data->img[n].x = x; - wps_data->img[n].y = y; + img->bm.data = (char*)filename; + img->id = n; + img->x = x; + img->y = y; + img->num_subimages = 1; + img->always_display = false; /* save current viewport */ - wps_data->img[n].vp = &wps_data->viewports[wps_data->num_viewports].vp; + img->vp = &wps_data->viewports[wps_data->num_viewports].vp; if (token->type == WPS_TOKEN_IMAGE_DISPLAY) { - wps_data->img[n].always_display = true; + img->always_display = true; } else { @@ -556,11 +565,15 @@ static int parse_image_load(const char *wps_bufptr, newline = strchr(ptr, '\n'); pos = strchr(ptr, '|'); if (pos && pos < newline) - wps_data->img[n].num_subimages = atoi(ptr); + img->num_subimages = atoi(ptr); - if (wps_data->img[n].num_subimages <= 0) + if (img->num_subimages <= 0) return WPS_ERROR_INVALID_PARAM; } + struct skin_token_list *item = new_skin_token_list_item(NULL, img); + if (!item) + return WPS_ERROR_INVALID_PARAM; + add_to_ll_chain(&wps_data->images, item); /* Skip the rest of the line */ return skip_end_of_line(wps_bufptr); @@ -781,7 +794,6 @@ static int parse_progressbar(const char *wps_bufptr, struct wps_token *token, struct wps_data *wps_data) { - (void)token; /* Kill warnings */ /* %pb or %pb|filename|x|y|width|height| using - for any of the params uses "sane" values */ #ifdef HAVE_LCD_BITMAP @@ -796,7 +808,12 @@ static int parse_progressbar(const char *wps_bufptr, int x, y, height, width; uint32_t set = 0; const char *ptr = wps_bufptr; - struct progressbar *pb; + struct progressbar *pb = skin_buffer_alloc(sizeof(struct progressbar)); + struct skin_token_list *item = new_skin_token_list_item(token, pb); + + if (!pb || !item) + return WPS_ERROR_INVALID_PARAM; + struct viewport *vp = &wps_data->viewports[wps_data->num_viewports].vp; #ifndef __PCTOOL__ int font_height = font_get(vp->font)->height; @@ -806,11 +823,8 @@ static int parse_progressbar(const char *wps_bufptr, int line_num = wps_data->num_lines - wps_data->viewports[wps_data->num_viewports].first_line; - if (wps_data->progressbar_count >= MAX_PROGRESSBARS) - return WPS_ERROR_INVALID_PARAM; - - pb = &wps_data->progressbar[wps_data->progressbar_count]; pb->have_bitmap_pb = false; + pb->bm.data = NULL; /* no bitmap specified */ if (*wps_bufptr != '|') /* regular old style */ { @@ -820,7 +834,7 @@ static int parse_progressbar(const char *wps_bufptr, pb->y = -line_num - 1; /* Will be computed during the rendering */ wps_data->viewports[wps_data->num_viewports].pb = pb; - wps_data->progressbar_count++; + add_to_ll_chain(&wps_data->progressbars, item); return 0; } ptr = wps_bufptr + 1; @@ -830,7 +844,7 @@ static int parse_progressbar(const char *wps_bufptr, return WPS_ERROR_INVALID_PARAM; if (LIST_VALUE_PARSED(set, PB_FILENAME)) /* filename */ - bmp_names[PROGRESSBAR_BMP+wps_data->progressbar_count] = filename; + pb->bm.data = (char*)filename; if (LIST_VALUE_PARSED(set, PB_X)) /* x */ pb->x = x; @@ -865,7 +879,7 @@ static int parse_progressbar(const char *wps_bufptr, pb->y = -line_num - 1; /* Will be computed during the rendering */ wps_data->viewports[wps_data->num_viewports].pb = pb; - wps_data->progressbar_count++; + add_to_ll_chain(&wps_data->progressbars, item); /* Skip the rest of the line */ return skip_end_of_line(wps_bufptr)-1; @@ -1250,9 +1264,6 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr) { if (!data || !wps_bufptr || !*wps_bufptr) return false; - - char *stringbuf = data->string_buffer; - int stringbuf_used = 0; enum wps_parse_error fail = PARSE_OK; int ret; line = 1; @@ -1404,42 +1415,45 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr) } /* look if we already have that string */ - char **str; - int i; - bool found; - for (i = 0, str = data->strings, found = false; - i < data->num_strings && - !(found = (strlen(*str) == len && - strncmp(string_start, *str, len) == 0)); - i++, str++); + char *str; + bool found = false; + struct skin_token_list *list = data->strings; + while (list) + { + str = (char*)list->token->value.data; + found = (strlen(str) == len && + strncmp(string_start, str, len) == 0); + if (found) + break; /* break here because the list item is + used if its found */ + list = list->next; + } /* If a matching string is found, found is true and i is the index of the string. If not, found is false */ if (!found) { /* new string */ - - if (stringbuf_used + len > STRING_BUFFER_SIZE - 1 - || data->num_strings >= WPS_MAX_STRINGS) - { - /* too many strings or characters */ - fail = PARSE_FAIL_LIMITS_EXCEEDED; - break; + str = (char*)skin_buffer_alloc(len+1); + if (!str) + { + fail = PARSE_FAIL_LIMITS_EXCEEDED; + break; } - - strlcpy(stringbuf, string_start, len+1); - - data->strings[data->num_strings] = stringbuf; - stringbuf += len + 1; - stringbuf_used += len + 1; - data->tokens[data->num_tokens].value.i = - data->num_strings; - data->num_strings++; + strlcpy(str, string_start, len+1); + struct skin_token_list *item = + new_skin_token_list_item(&data->tokens[data->num_tokens], str); + if(!item) + { + fail = PARSE_FAIL_LIMITS_EXCEEDED; + break; + } + add_to_ll_chain(&data->strings, item); } else { /* another occurrence of an existing string */ - data->tokens[data->num_tokens].value.i = i; + data->tokens[data->num_tokens].value.data = list->token->value.data; } data->tokens[data->num_tokens].type = WPS_TOKEN_STRING; data->num_tokens++; @@ -1480,54 +1494,75 @@ static void wps_reset(struct wps_data *data) } #ifdef HAVE_LCD_BITMAP +static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir) +{ + (void)wps_data; /* only needed for remote targets */ + bool loaded = false; + char img_path[MAX_PATH]; + get_image_filename(bitmap->data, bmpdir, + img_path, sizeof(img_path)); + + /* load the image */ + int format; +#ifdef HAVE_REMOTE_LCD + if (wps_data->remote_wps) + format = FORMAT_ANY|FORMAT_REMOTE; + else +#endif + format = FORMAT_ANY|FORMAT_TRANSPARENT; + + size_t max_buf; + char* imgbuf = (char*)skin_buffer_grab(&max_buf); + bitmap->data = imgbuf; + int ret = read_bmp_file(img_path, bitmap, max_buf, format, NULL); + + if (ret > 0) + { + skin_buffer_increment(ret); + loaded = true; + } + else + { + /* Abort if we can't load an image */ + DEBUGF("ERR: Failed to load image - %s\n",img_path); + loaded = false; + } + return loaded; +} static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir) { - char img_path[MAX_PATH]; - struct bitmap *bitmap; - bool *loaded; - int n; - for (n = 0; n < BACKDROP_BMP; n++) + struct skin_token_list *list; + /* do the progressbars */ + list = wps_data->progressbars; + while (list) { - if (bmp_names[n]) + struct progressbar *pb = (struct progressbar*)list->token->value.data; + if (pb->bm.data) { - get_image_filename(bmp_names[n], bmpdir, - img_path, sizeof(img_path)); - - if (n >= PROGRESSBAR_BMP ) { - /* progressbar bitmap */ - bitmap = &wps_data->progressbar[n-PROGRESSBAR_BMP].bm; - loaded = &wps_data->progressbar[n-PROGRESSBAR_BMP].have_bitmap_pb; - } else { - /* regular bitmap */ - bitmap = &wps_data->img[n].bm; - loaded = &wps_data->img[n].loaded; - } - - /* load the image */ - bitmap->data = wps_data->img_buf_ptr; - if (load_bitmap(wps_data, img_path, bitmap)) - { - *loaded = true; - - /* Calculate and store height if this image has sub-images */ - if (n < MAX_IMAGES) - wps_data->img[n].subimage_height = wps_data->img[n].bm.height / - wps_data->img[n].num_subimages; - } - else - { - /* Abort if we can't load an image */ - DEBUGF("ERR: Failed to load image %d - %s\n",n,img_path); - return false; - } + pb->have_bitmap_pb = load_skin_bmp(wps_data, &pb->bm, bmpdir); } + list = list->next; + } + /* regular images */ + list = wps_data->images; + while (list) + { + struct gui_img *img = (struct gui_img*)list->token->value.data; + if (img->bm.data) + { + img->loaded = load_skin_bmp(wps_data, &img->bm, bmpdir); + if (img->loaded) + img->subimage_height = img->bm.height / img->num_subimages; + } + list = list->next; } #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) if (bmp_names[BACKDROP_BMP]) { int screen = SCREEN_MAIN; + char img_path[MAX_PATH]; get_image_filename(bmp_names[BACKDROP_BMP], bmpdir, img_path, sizeof(img_path)); #if defined(HAVE_REMOTE_LCD) diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c index b1163aa88a..386dc5ded8 100644 --- a/apps/gui/skin_engine/skin_tokens.c +++ b/apps/gui/skin_engine/skin_tokens.c @@ -167,7 +167,7 @@ const char *get_token_value(struct gui_wps *gwps, return &(token->value.c); case WPS_TOKEN_STRING: - return data->strings[token->value.i]; + return (char*)token->value.data; case WPS_TOKEN_TRACK_TIME_ELAPSED: format_time(buf, buf_size, diff --git a/apps/gui/skin_engine/skin_tokens.h b/apps/gui/skin_engine/skin_tokens.h new file mode 100644 index 0000000000..ea59053c7a --- /dev/null +++ b/apps/gui/skin_engine/skin_tokens.h @@ -0,0 +1,218 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: wps_internals.h 22223 2009-08-09 17:30:05Z jdgordon $ + * + * Copyright (C) 2007 Nicolas Pennequin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _SKIN_TOKENS_H_ +#define _SKIN_TOKENS_H_ + +#include + + +enum wps_token_type { + WPS_NO_TOKEN, /* for WPS tags we don't want to save as tokens */ + WPS_TOKEN_UNKNOWN, + + /* Markers */ + WPS_TOKEN_CHARACTER, + WPS_TOKEN_STRING, + + /* Alignment */ + WPS_TOKEN_ALIGN_LEFT, + WPS_TOKEN_ALIGN_CENTER, + WPS_TOKEN_ALIGN_RIGHT, + + /* Sublines */ + WPS_TOKEN_SUBLINE_TIMEOUT, + + /* Battery */ + WPS_TOKEN_BATTERY_PERCENT, + WPS_TOKEN_BATTERY_VOLTS, + WPS_TOKEN_BATTERY_TIME, + WPS_TOKEN_BATTERY_CHARGER_CONNECTED, + WPS_TOKEN_BATTERY_CHARGING, + WPS_TOKEN_BATTERY_SLEEPTIME, + + /* Sound */ +#if (CONFIG_CODEC != MAS3507D) + WPS_TOKEN_SOUND_PITCH, +#endif +#if (CONFIG_CODEC == SWCODEC) + WPS_TOKEN_REPLAYGAIN, + WPS_TOKEN_CROSSFADE, +#endif + + /* Time */ + + WPS_TOKEN_RTC_PRESENT, + + /* The begin/end values allow us to know if a token is an RTC one. + New RTC tokens should be added between the markers. */ + + WPS_TOKENS_RTC_BEGIN, /* just the start marker, not an actual token */ + + WPS_TOKEN_RTC_DAY_OF_MONTH, + WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, + WPS_TOKEN_RTC_12HOUR_CFG, + WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED, + WPS_TOKEN_RTC_HOUR_24, + WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED, + WPS_TOKEN_RTC_HOUR_12, + WPS_TOKEN_RTC_MONTH, + WPS_TOKEN_RTC_MINUTE, + WPS_TOKEN_RTC_SECOND, + WPS_TOKEN_RTC_YEAR_2_DIGITS, + WPS_TOKEN_RTC_YEAR_4_DIGITS, + WPS_TOKEN_RTC_AM_PM_UPPER, + WPS_TOKEN_RTC_AM_PM_LOWER, + WPS_TOKEN_RTC_WEEKDAY_NAME, + WPS_TOKEN_RTC_MONTH_NAME, + WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON, + WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN, + + WPS_TOKENS_RTC_END, /* just the end marker, not an actual token */ + + /* Conditional */ + WPS_TOKEN_CONDITIONAL, + WPS_TOKEN_CONDITIONAL_START, + WPS_TOKEN_CONDITIONAL_OPTION, + WPS_TOKEN_CONDITIONAL_END, + + /* Database */ +#ifdef HAVE_TAGCACHE + WPS_TOKEN_DATABASE_PLAYCOUNT, + WPS_TOKEN_DATABASE_RATING, + WPS_TOKEN_DATABASE_AUTOSCORE, +#endif + + /* File */ + WPS_TOKEN_FILE_BITRATE, + WPS_TOKEN_FILE_CODEC, + WPS_TOKEN_FILE_FREQUENCY, + WPS_TOKEN_FILE_FREQUENCY_KHZ, + WPS_TOKEN_FILE_NAME, + WPS_TOKEN_FILE_NAME_WITH_EXTENSION, + WPS_TOKEN_FILE_PATH, + WPS_TOKEN_FILE_SIZE, + WPS_TOKEN_FILE_VBR, + WPS_TOKEN_FILE_DIRECTORY, + +#ifdef HAVE_LCD_BITMAP + /* Image */ + WPS_TOKEN_IMAGE_BACKDROP, + WPS_TOKEN_IMAGE_PROGRESS_BAR, + WPS_TOKEN_IMAGE_PRELOAD, + WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, + WPS_TOKEN_IMAGE_DISPLAY, +#endif + +#ifdef HAVE_ALBUMART + /* Albumart */ + WPS_TOKEN_ALBUMART_DISPLAY, + WPS_TOKEN_ALBUMART_FOUND, +#endif + + /* Metadata */ + WPS_TOKEN_METADATA_ARTIST, + WPS_TOKEN_METADATA_COMPOSER, + WPS_TOKEN_METADATA_ALBUM_ARTIST, + WPS_TOKEN_METADATA_GROUPING, + WPS_TOKEN_METADATA_ALBUM, + WPS_TOKEN_METADATA_GENRE, + WPS_TOKEN_METADATA_DISC_NUMBER, + WPS_TOKEN_METADATA_TRACK_NUMBER, + WPS_TOKEN_METADATA_TRACK_TITLE, + WPS_TOKEN_METADATA_VERSION, + WPS_TOKEN_METADATA_YEAR, + WPS_TOKEN_METADATA_COMMENT, + + /* Mode */ + WPS_TOKEN_REPEAT_MODE, + WPS_TOKEN_PLAYBACK_STATUS, + + WPS_TOKEN_MAIN_HOLD, + +#ifdef HAS_REMOTE_BUTTON_HOLD + WPS_TOKEN_REMOTE_HOLD, +#endif + + /* Progressbar */ + WPS_TOKEN_PROGRESSBAR, +#ifdef HAVE_LCD_CHARCELLS + WPS_TOKEN_PLAYER_PROGRESSBAR, +#endif + +#ifdef HAVE_LCD_BITMAP + /* Peakmeter */ + WPS_TOKEN_PEAKMETER, +#endif + + /* Volume level */ + WPS_TOKEN_VOLUME, + + /* Current track */ + WPS_TOKEN_TRACK_ELAPSED_PERCENT, + WPS_TOKEN_TRACK_TIME_ELAPSED, + WPS_TOKEN_TRACK_TIME_REMAINING, + WPS_TOKEN_TRACK_LENGTH, + + /* Playlist */ + WPS_TOKEN_PLAYLIST_ENTRIES, + WPS_TOKEN_PLAYLIST_NAME, + WPS_TOKEN_PLAYLIST_POSITION, + WPS_TOKEN_PLAYLIST_SHUFFLE, + +#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) + /* Virtual LED */ + WPS_TOKEN_VLED_HDD, +#endif + + /* Viewport display */ + WPS_VIEWPORT_ENABLE, + + /* buttons */ + WPS_TOKEN_BUTTON_VOLUME, + WPS_TOKEN_LASTTOUCH, + + /* Setting option */ + WPS_TOKEN_SETTING, +}; + +struct wps_token { + unsigned char type; /* enough to store the token type */ + + /* Whether the tag (e.g. track name or the album) refers the + current or the next song (false=current, true=next) */ + bool next; + + union { + char c; + unsigned short i; + void* data; + } value; +}; + +struct skin_token_list { + struct wps_token *token; + struct skin_token_list *next; +}; + + +#endif + diff --git a/apps/gui/skin_engine/wps_debug.c b/apps/gui/skin_engine/wps_debug.c index 02a2cc3de9..c4a73a7cfb 100644 --- a/apps/gui/skin_engine/wps_debug.c +++ b/apps/gui/skin_engine/wps_debug.c @@ -23,6 +23,7 @@ #include #include +#include "wps.h" #include "wps_internals.h" #ifdef __PCTOOL__ #ifdef WPSEDITOR @@ -548,15 +549,18 @@ static void print_line_info(struct wps_data *data) DEBUGF("\n"); } } - +#if 0 +/* NOTE: this is probaly not even needed anymore */ static void print_wps_strings(struct wps_data *data) { int i, len, total_len = 0, buf_used = 0; if (wps_verbose_level > 1) DEBUGF("Strings:\n"); - for (i = 0; i < data->num_strings; i++) + struct skin_token_list *strings = data->strings; + while (strings) { - len = strlen(data->strings[i]); + char* str = (char*)strings->token->value.data; + len = strlen(str); total_len += len; buf_used += len + 1; if (wps_verbose_level > 1) @@ -575,6 +579,7 @@ static void print_wps_strings(struct wps_data *data) } } #endif +#endif void print_debug_info(struct wps_data *data, enum wps_parse_error fail, int line) { @@ -582,7 +587,7 @@ void print_debug_info(struct wps_data *data, enum wps_parse_error fail, int line if (debug_wps && wps_verbose_level) { dump_wps_tokens(data); - print_wps_strings(data); + /* print_wps_strings(data); */ print_line_info(data); } #endif /* SIMULATOR */ diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h index ffebed7bad..bb68e578ab 100644 --- a/apps/gui/skin_engine/wps_internals.h +++ b/apps/gui/skin_engine/wps_internals.h @@ -31,7 +31,7 @@ #define TIMEOUT_UNIT (HZ/10) /* I.e. 0.1 sec */ #define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* In TIMEOUT_UNIT's */ - +#include "skin_tokens.h" /* TODO: sort this mess out */ @@ -77,6 +77,7 @@ #ifdef HAVE_LCD_BITMAP struct gui_img { + short int id; struct bitmap bm; struct viewport* vp; /* The viewport to display this image in */ short int x; /* x-pos */ @@ -88,6 +89,7 @@ struct gui_img { bool always_display; /* not using the preload/display mechanism */ }; + struct progressbar { /* regular pb */ short x; @@ -153,187 +155,6 @@ enum wps_parse_error { PARSE_FAIL_LIMITS_EXCEEDED, }; -enum wps_token_type { - WPS_NO_TOKEN, /* for WPS tags we don't want to save as tokens */ - WPS_TOKEN_UNKNOWN, - - /* Markers */ - WPS_TOKEN_CHARACTER, - WPS_TOKEN_STRING, - - /* Alignment */ - WPS_TOKEN_ALIGN_LEFT, - WPS_TOKEN_ALIGN_CENTER, - WPS_TOKEN_ALIGN_RIGHT, - - /* Sublines */ - WPS_TOKEN_SUBLINE_TIMEOUT, - - /* Battery */ - WPS_TOKEN_BATTERY_PERCENT, - WPS_TOKEN_BATTERY_VOLTS, - WPS_TOKEN_BATTERY_TIME, - WPS_TOKEN_BATTERY_CHARGER_CONNECTED, - WPS_TOKEN_BATTERY_CHARGING, - WPS_TOKEN_BATTERY_SLEEPTIME, - - /* Sound */ -#if (CONFIG_CODEC != MAS3507D) - WPS_TOKEN_SOUND_PITCH, -#endif -#if (CONFIG_CODEC == SWCODEC) - WPS_TOKEN_REPLAYGAIN, - WPS_TOKEN_CROSSFADE, -#endif - - /* Time */ - - WPS_TOKEN_RTC_PRESENT, - - /* The begin/end values allow us to know if a token is an RTC one. - New RTC tokens should be added between the markers. */ - - WPS_TOKENS_RTC_BEGIN, /* just the start marker, not an actual token */ - - WPS_TOKEN_RTC_DAY_OF_MONTH, - WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, - WPS_TOKEN_RTC_12HOUR_CFG, - WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED, - WPS_TOKEN_RTC_HOUR_24, - WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED, - WPS_TOKEN_RTC_HOUR_12, - WPS_TOKEN_RTC_MONTH, - WPS_TOKEN_RTC_MINUTE, - WPS_TOKEN_RTC_SECOND, - WPS_TOKEN_RTC_YEAR_2_DIGITS, - WPS_TOKEN_RTC_YEAR_4_DIGITS, - WPS_TOKEN_RTC_AM_PM_UPPER, - WPS_TOKEN_RTC_AM_PM_LOWER, - WPS_TOKEN_RTC_WEEKDAY_NAME, - WPS_TOKEN_RTC_MONTH_NAME, - WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON, - WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN, - - WPS_TOKENS_RTC_END, /* just the end marker, not an actual token */ - - /* Conditional */ - WPS_TOKEN_CONDITIONAL, - WPS_TOKEN_CONDITIONAL_START, - WPS_TOKEN_CONDITIONAL_OPTION, - WPS_TOKEN_CONDITIONAL_END, - - /* Database */ -#ifdef HAVE_TAGCACHE - WPS_TOKEN_DATABASE_PLAYCOUNT, - WPS_TOKEN_DATABASE_RATING, - WPS_TOKEN_DATABASE_AUTOSCORE, -#endif - - /* File */ - WPS_TOKEN_FILE_BITRATE, - WPS_TOKEN_FILE_CODEC, - WPS_TOKEN_FILE_FREQUENCY, - WPS_TOKEN_FILE_FREQUENCY_KHZ, - WPS_TOKEN_FILE_NAME, - WPS_TOKEN_FILE_NAME_WITH_EXTENSION, - WPS_TOKEN_FILE_PATH, - WPS_TOKEN_FILE_SIZE, - WPS_TOKEN_FILE_VBR, - WPS_TOKEN_FILE_DIRECTORY, - -#ifdef HAVE_LCD_BITMAP - /* Image */ - WPS_TOKEN_IMAGE_BACKDROP, - WPS_TOKEN_IMAGE_PROGRESS_BAR, - WPS_TOKEN_IMAGE_PRELOAD, - WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, - WPS_TOKEN_IMAGE_DISPLAY, -#endif - -#ifdef HAVE_ALBUMART - /* Albumart */ - WPS_TOKEN_ALBUMART_DISPLAY, - WPS_TOKEN_ALBUMART_FOUND, -#endif - - /* Metadata */ - WPS_TOKEN_METADATA_ARTIST, - WPS_TOKEN_METADATA_COMPOSER, - WPS_TOKEN_METADATA_ALBUM_ARTIST, - WPS_TOKEN_METADATA_GROUPING, - WPS_TOKEN_METADATA_ALBUM, - WPS_TOKEN_METADATA_GENRE, - WPS_TOKEN_METADATA_DISC_NUMBER, - WPS_TOKEN_METADATA_TRACK_NUMBER, - WPS_TOKEN_METADATA_TRACK_TITLE, - WPS_TOKEN_METADATA_VERSION, - WPS_TOKEN_METADATA_YEAR, - WPS_TOKEN_METADATA_COMMENT, - - /* Mode */ - WPS_TOKEN_REPEAT_MODE, - WPS_TOKEN_PLAYBACK_STATUS, - - WPS_TOKEN_MAIN_HOLD, - -#ifdef HAS_REMOTE_BUTTON_HOLD - WPS_TOKEN_REMOTE_HOLD, -#endif - - /* Progressbar */ - WPS_TOKEN_PROGRESSBAR, -#ifdef HAVE_LCD_CHARCELLS - WPS_TOKEN_PLAYER_PROGRESSBAR, -#endif - -#ifdef HAVE_LCD_BITMAP - /* Peakmeter */ - WPS_TOKEN_PEAKMETER, -#endif - - /* Volume level */ - WPS_TOKEN_VOLUME, - - /* Current track */ - WPS_TOKEN_TRACK_ELAPSED_PERCENT, - WPS_TOKEN_TRACK_TIME_ELAPSED, - WPS_TOKEN_TRACK_TIME_REMAINING, - WPS_TOKEN_TRACK_LENGTH, - - /* Playlist */ - WPS_TOKEN_PLAYLIST_ENTRIES, - WPS_TOKEN_PLAYLIST_NAME, - WPS_TOKEN_PLAYLIST_POSITION, - WPS_TOKEN_PLAYLIST_SHUFFLE, - -#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) - /* Virtual LED */ - WPS_TOKEN_VLED_HDD, -#endif - - /* Viewport display */ - WPS_VIEWPORT_ENABLE, - - /* buttons */ - WPS_TOKEN_BUTTON_VOLUME, - WPS_TOKEN_LASTTOUCH, - - /* Setting option */ - WPS_TOKEN_SETTING, -}; - -struct wps_token { - unsigned char type; /* enough to store the token type */ - - /* Whether the tag (e.g. track name or the album) refers the - current or the next song (false=current, true=next) */ - bool next; - - union { - char c; - unsigned short i; - } value; -}; /* Description of a subline on the WPS */ struct wps_subline { @@ -406,15 +227,11 @@ struct touchregion { struct wps_data { #ifdef HAVE_LCD_BITMAP - struct gui_img img[MAX_IMAGES]; - unsigned char img_buf[IMG_BUFSIZE]; - unsigned char* img_buf_ptr; - int img_buf_free; bool wps_sb_tag; bool show_sb_on_wps; - struct progressbar progressbar[MAX_PROGRESSBARS]; - short progressbar_count; + struct skin_token_list *images; + struct skin_token_list *progressbars; bool peak_meter_enabled; @@ -465,9 +282,7 @@ struct wps_data int num_tokens; struct wps_token tokens[WPS_MAX_TOKENS]; - char string_buffer[STRING_BUFFER_SIZE]; - char *strings[WPS_MAX_STRINGS]; - int num_strings; + struct skin_token_list *strings; bool wps_loaded; @@ -533,4 +348,8 @@ const char *get_token_value(struct gui_wps *gwps, char *buf, int buf_size, int *intval); + + +struct gui_img* find_image(int n, struct wps_data *data); + #endif diff --git a/apps/settings.c b/apps/settings.c index bd2958e4e2..72e5a012e4 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -70,6 +70,7 @@ #include "radio.h" #endif #include "wps.h" +#include "skin_engine/skin_engine.h" #if CONFIG_CODEC == MAS3507D void dac_line_in(bool enable); @@ -818,6 +819,8 @@ void settings_apply(bool read_disk) if (read_disk) { + /* re-initialize the skin buffer before we start reloading skins */ + skin_buffer_init(); #ifdef HAVE_LCD_BITMAP /* fonts need to be loaded before the WPS */