diff options
author | Jonathan Gordon <rockbox@jdgordon.info> | 2010-07-29 12:37:48 +0000 |
---|---|---|
committer | Jonathan Gordon <rockbox@jdgordon.info> | 2010-07-29 12:37:48 +0000 |
commit | 2d31d77a8ba231cb03ec35863c4c4ce2024f6509 (patch) | |
tree | b85ca1bede3e83695619064ee9a323f0a8da1865 | |
parent | e436483b66a931fef6436e9cd3e69eb2b3ff1f7b (diff) | |
download | rockbox-2d31d77a8ba231cb03ec35863c4c4ce2024f6509.tar.gz rockbox-2d31d77a8ba231cb03ec35863c4c4ce2024f6509.zip |
FS#11470 - new skin code, finally svn uses the new parser from the theme editor. This means that a skin that passes the editor WILL pass svn and checkwps (unless the target runs out of skin buffer or something.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27613 a1c6a512-1295-4272-9138-f99709370657
44 files changed, 2103 insertions, 3324 deletions
diff --git a/apps/SOURCES b/apps/SOURCES index 181c780fb6..d15ba5bf6a 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -94,13 +94,12 @@ gui/yesno.c gui/viewport.c gui/skin_engine/skin_backdrops.c -gui/skin_engine/skin_buffer.c -gui/skin_engine/wps_debug.c gui/skin_engine/skin_display.c #ifdef HAVE_LCD_BITMAP gui/skin_engine/skin_fonts.c #endif gui/skin_engine/skin_parser.c +gui/skin_engine/skin_render.c gui/skin_engine/skin_tokens.c #ifdef HAVE_TOUCHSCREEN gui/skin_engine/skin_touchsupport.c diff --git a/apps/cuesheet.c b/apps/cuesheet.c index cadb2ab8f6..a262b12d73 100644 --- a/apps/cuesheet.c +++ b/apps/cuesheet.c @@ -363,20 +363,22 @@ const char *get_cuesheetid3_token(struct wps_token *token, struct mp3entry *id3, } switch (token->type) { - case WPS_TOKEN_METADATA_ARTIST: + case SKIN_TOKEN_METADATA_ARTIST: return *track->performer ? track->performer : NULL; - case WPS_TOKEN_METADATA_COMPOSER: + case SKIN_TOKEN_METADATA_COMPOSER: return *track->songwriter ? track->songwriter : NULL; - case WPS_TOKEN_METADATA_ALBUM: + case SKIN_TOKEN_METADATA_ALBUM: return *cue->title ? cue->title : NULL; - case WPS_TOKEN_METADATA_ALBUM_ARTIST: + case SKIN_TOKEN_METADATA_ALBUM_ARTIST: return *cue->performer ? cue->performer : NULL; - case WPS_TOKEN_METADATA_TRACK_TITLE: + case SKIN_TOKEN_METADATA_TRACK_TITLE: return *track->title ? track->title : NULL; - case WPS_TOKEN_METADATA_TRACK_NUMBER: + case SKIN_TOKEN_METADATA_TRACK_NUMBER: snprintf(buf, buf_size, "%d/%d", cue->curr_track_idx+offset_tracks+1, cue->track_count); return buf; + default: + return NULL; } return NULL; } diff --git a/apps/gui/skin_engine/skin_backdrops.c b/apps/gui/skin_engine/skin_backdrops.c index a32bfbe589..4288e0a7b4 100644 --- a/apps/gui/skin_engine/skin_backdrops.c +++ b/apps/gui/skin_engine/skin_backdrops.c @@ -24,9 +24,9 @@ #include <stdlib.h> #include "string-extra.h" #include "settings.h" -#include "skin_buffer.h" #include "wps_internals.h" #include "skin_engine.h" +#include "skin_buffer.h" #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) @@ -100,7 +100,7 @@ char* skin_backdrop_load(char* backdrop, char *bmpdir, enum screen_type screen) if (!bdrop) return NULL; /* too many backdrops loaded */ - bdrop->buffer = skin_buffer_alloc(buf_size); + bdrop->buffer = (char*)skin_buffer_alloc(buf_size); if (!bdrop->buffer) return NULL; loaded = screens[screen].backdrop_load(filename, bdrop->buffer); diff --git a/apps/gui/skin_engine/skin_buffer.c b/apps/gui/skin_engine/skin_buffer.c deleted file mode 100644 index d503b83e42..0000000000 --- a/apps/gui/skin_engine/skin_buffer.c +++ /dev/null @@ -1,170 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * 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 <stdio.h> -#include <string.h> -#include <stdlib.h> -#include "config.h" -#include "buffer.h" -#include "settings.h" -#include "screen_access.h" -#include "skin_engine.h" -#include "wps_internals.h" -#include "skin_tokens.h" -#include "skin_buffer.h" -#include "skin_fonts.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 - * - * - * MAIN_ and REMOTE_BUFFER are just for reasonable size calibration, - * both screens can use the whole buffer as they need; it's not split - * between screens - * - * Buffer can be allocated from either "end" of the global buffer. - * items with unknown sizes get allocated from the start (0->) (data) - * items with known sizes get allocated from the end (<-buf_size) (tokens) - * After loading 2 skins the buffer will look like this: - * |tokens skin1|images skin1|tokens s2|images s2|---SPACE---|data skin2|data skin1| - * Make sure to never start allocating from the beginning before letting us know - * how much was used. and RESPECT THE buf_free RETURN VALUES! - * - */ - - -#ifdef HAVE_LCD_BITMAP -#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \ - + (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES)) - -#if (NB_SCREENS > 1) -#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \ - + (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES)) -#else -#define REMOTE_BUFFER 0 -#endif - - -#define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER + SKIN_FONT_SIZE) + \ - (WPS_MAX_TOKENS * sizeof(struct wps_token)) -#endif - -#ifdef HAVE_LCD_CHARCELLS -#define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \ - (WPS_MAX_TOKENS * sizeof(struct wps_token)) -#endif - -static unsigned char buffer[SKIN_BUFFER_SIZE]; -static unsigned char *buffer_front = NULL; /* start of the free space, - increases with allocation*/ -static unsigned char *buffer_back = NULL; /* end of the free space - decreases with allocation */ -static size_t buf_size = SKIN_BUFFER_SIZE; - -void skin_buffer_init(void) -{ -#if 0 /* this will go in again later probably */ - if (buffer == NULL) - { - buf_size = SKIN_BUFFER_SIZE;/* global_settings.skin_buf_size */ - - buffer = buffer_alloc(buf_size); - buffer_front = buffer; - buffer_back = bufer + buf_size; - } - else -#endif - { - /* reset the buffer.... */ - buffer_front = buffer; - buffer_back = buffer + buf_size; - } -} - -/* get the number of bytes currently being used */ -size_t skin_buffer_usage(void) -{ - return buf_size - (buffer_back-buffer_front); -} - -size_t skin_buffer_freespace(void) -{ - return buffer_back-buffer_front; -} - -/* Allocate size bytes from the buffer - * allocates from the back end (data end) - */ -void* skin_buffer_alloc(size_t size) -{ - if (skin_buffer_freespace() <= size) - { - return NULL; - } - buffer_back -= size; - /* 32-bit aligned */ - buffer_back = (void *)(((unsigned long)buffer_back) & ~3); - - memset(buffer_back, 0, size); - return buffer_back; -} - -/* 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 - * - * This is from the start of the buffer, it is YOUR responsility to make - * sure you dont ever use more then *freespace, and bear in mind this will only - * be valid untill skin_buffer_alloc() is next called... - * so call skin_buffer_increment() and skin_buffer_freespace() regularly - */ -void* skin_buffer_grab(size_t *freespace) -{ - *freespace = buf_size - skin_buffer_usage(); - return buffer_front; -} - -/* Use after skin_buffer_grab() to specify how much buffer was used */ -void skin_buffer_increment(size_t used, bool align) -{ - buffer_front += used; - if (align) - { - /* 32-bit aligned */ - buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3); - } -} - -/* free previously skin_buffer_increment()'ed space. This just moves the pointer - * back 'used' bytes so make sure you actually want to do this */ -void skin_buffer_free_from_front(size_t used) -{ - buffer_front -= used; - /* 32-bit aligned */ - buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3); -} - - diff --git a/apps/gui/skin_engine/skin_buffer.h b/apps/gui/skin_engine/skin_buffer.h deleted file mode 100644 index 521631f03b..0000000000 --- a/apps/gui/skin_engine/skin_buffer.h +++ /dev/null @@ -1,64 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * 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 <stdio.h> -#include <string.h> -#include <stdlib.h> - -/* int the global buffer */ -void skin_buffer_init(void); - -/* get the number of bytes currently being used */ -size_t skin_buffer_usage(void); -size_t skin_buffer_freespace(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 - * - * This is from the start of the buffer, it is YOUR responsility to make - * sure you dont ever use more then *freespace, and bear in mind this will only - * be valid untill skin_buffer_alloc() is next called... - * so call skin_buffer_increment() and skin_buffer_freespace() regularly - */ -void* skin_buffer_grab(size_t *freespace); - -/* Use after skin_buffer_grab() to specify how much buffer was used. - * align should always be true unless there is a possibility that you will need - * more space *immediatly* after the previous allocation. (i.e in an array). - * NEVER leave the buffer unaligned */ -void skin_buffer_increment(size_t used, bool align); - -/* free previously skin_buffer_increment()'ed space. This just moves the pointer - * back 'used' bytes so make sure you actually want to do this */ -void skin_buffer_free_from_front(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 3d3a654c30..559ae8519f 100644 --- a/apps/gui/skin_engine/skin_display.c +++ b/apps/gui/skin_engine/skin_display.c @@ -69,25 +69,22 @@ #include "skin_engine.h" #include "statusbar-skinned.h" -static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode); +void skin_render(struct gui_wps *gwps, unsigned refresh_mode); /* update a skinned screen, update_type is WPS_REFRESH_* values. * Usually it should only be WPS_REFRESH_NON_STATIC * A full update will be done if required (state.do_full_update == true) */ -bool skin_update(struct gui_wps *gwps, unsigned int update_type) +void skin_update(struct gui_wps *gwps, unsigned int update_type) { - bool retval; - /* This maybe shouldnt be here, but while the skin is only used to - * display the music screen this is better than whereever we are being - * called from. This is also safe for skined screen which dont use the id3 */ + /* This maybe shouldnt be here, + * This is also safe for skined screen which dont use the id3 */ struct mp3entry *id3 = gwps->state->id3; bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false); gwps->sync_data->do_full_update |= cuesheet_update; - retval = skin_redraw(gwps, gwps->sync_data->do_full_update ? - WPS_REFRESH_ALL : update_type); - return retval; + skin_render(gwps, gwps->sync_data->do_full_update ? + SKIN_REFRESH_ALL : update_type); } #ifdef HAVE_LCD_BITMAP @@ -124,8 +121,7 @@ void skin_statusbar_changed(struct gui_wps *skin) } } -static void draw_progressbar(struct gui_wps *gwps, - struct progressbar *pb) +void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb) { struct screen *display = gwps->display; struct viewport *vp = pb->vp; @@ -143,17 +139,17 @@ static void draw_progressbar(struct gui_wps *gwps, /* center the pb in the line, but only if the line is higher than the pb */ int center = (line_height-height)/2; /* if Y was not set calculate by font height,Y is -line_number-1 */ - y = (-y -1)*line_height + (0 > center ? 0 : center); + y = line*line_height + (0 > center ? 0 : center); } - if (pb->type == WPS_TOKEN_VOLUMEBAR) + if (pb->type == SKIN_TOKEN_VOLUMEBAR) { int minvol = sound_min(SOUND_VOLUME); int maxvol = sound_max(SOUND_VOLUME); length = maxvol-minvol; elapsed = global_settings.volume-minvol; } - else if (pb->type == WPS_TOKEN_BATTERY_PERCENTBAR) + else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR) { length = 100; elapsed = battery_level(); @@ -185,7 +181,7 @@ static void draw_progressbar(struct gui_wps *gwps, gui_scrollbar_draw(display, pb->x, y, pb->width, height, length, 0, elapsed, HORIZONTAL); - if (pb->type == WPS_TOKEN_PROGRESSBAR) + if (pb->type == SKIN_TOKEN_PROGRESSBAR) { if (id3 && id3->length) { @@ -208,8 +204,7 @@ static void draw_progressbar(struct gui_wps *gwps, } } -static void draw_playlist_viewer_list(struct gui_wps *gwps, - struct playlistviewer *viewer) +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); @@ -217,8 +212,9 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps, int cur_pos, max; int start_item; int i; - struct wps_token token; - int x, length, alignment = WPS_TOKEN_ALIGN_LEFT; + 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]; @@ -281,51 +277,58 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps, } line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO; } - int j = 0, cur_string = 0; 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 (j < viewer->lines[line].count && line_len < sizeof(buf)) + while (element && line_len < sizeof(buf)) { const char *out = NULL; - token.type = viewer->lines[line].tokens[j]; - token.value.i = 0; - token.next = false; - out = get_id3_token(&token, pid3, tempbuf, sizeof(tempbuf), -1, 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, + out = get_radio_token(token, i-cur_pos, tempbuf, sizeof(tempbuf), -1, NULL); #endif if (out) { line_len = strlcat(buf, out, sizeof(buf)); - j++; + element = element->next; continue; } - switch (viewer->lines[line].tokens[j]) + switch (token->type) { - case WPS_TOKEN_ALIGN_CENTER: - case WPS_TOKEN_ALIGN_LEFT: - case WPS_TOKEN_ALIGN_LEFT_RTL: - case WPS_TOKEN_ALIGN_RIGHT: - case WPS_TOKEN_ALIGN_RIGHT_RTL: - alignment = viewer->lines[line].tokens[j]; + 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 WPS_TOKEN_STRING: - case WPS_TOKEN_CHARACTER: - snprintf(tempbuf, sizeof(tempbuf), "%s", - viewer->lines[line].strings[cur_string]); - cur_string++; - break; - case WPS_TOKEN_PLAYLIST_POSITION: + case SKIN_TOKEN_PLAYLIST_POSITION: snprintf(tempbuf, sizeof(tempbuf), "%d", i); break; - case WPS_TOKEN_FILE_NAME: + case SKIN_TOKEN_FILE_NAME: get_dir(tempbuf, sizeof(tempbuf), filename, 0); break; - case WPS_TOKEN_FILE_PATH: + case SKIN_TOKEN_FILE_PATH: snprintf(tempbuf, sizeof(tempbuf), "%s", filename); break; default: @@ -336,12 +339,12 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps, { line_len = strlcat(buf, tempbuf, sizeof(buf)); } - j++; + element = element->next; } int vpwidth = viewer->vp->width; length = gwps->display->getstringsize(buf, NULL, NULL); - if (viewer->lines[line].scroll && length >= vpwidth) + if (scroll && length >= vpwidth) { gwps->display->puts_scroll(0, (i-start_item), buf ); } @@ -353,25 +356,25 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps, { switch (alignment) { - case WPS_TOKEN_ALIGN_CENTER: + case SKIN_TOKEN_ALIGN_CENTER: x = (vpwidth-length)/2; break; - case WPS_TOKEN_ALIGN_LEFT_RTL: + case SKIN_TOKEN_ALIGN_LEFT_RTL: if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) { x = vpwidth - length; break; } - case WPS_TOKEN_ALIGN_LEFT: + case SKIN_TOKEN_ALIGN_LEFT: x = 0; break; - case WPS_TOKEN_ALIGN_RIGHT_RTL: + case SKIN_TOKEN_ALIGN_RIGHT_RTL: if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) { x = 0; break; } - case WPS_TOKEN_ALIGN_RIGHT: + case SKIN_TOKEN_ALIGN_RIGHT: x = vpwidth - length; break; default: @@ -386,7 +389,7 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps, /* clears the area where the image was shown */ -static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) +void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) { if(!gwps) return; @@ -395,7 +398,7 @@ static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) gwps->display->set_drawmode(DRMODE_SOLID); } -static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage) +void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage) { struct screen *display = gwps->display; if(img->always_display) @@ -423,7 +426,8 @@ static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subima #endif } -static void wps_display_images(struct gui_wps *gwps, struct viewport* vp) + +void wps_display_images(struct gui_wps *gwps, struct viewport* vp) { if(!gwps || !gwps->data || !gwps->display) return; @@ -451,18 +455,10 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp) #ifdef HAVE_ALBUMART /* now draw the AA */ if (data->albumart && data->albumart->vp == vp - && data->albumart->draw) + && data->albumart->draw_handle >= 0) { - int handle = playback_current_aa_hid(data->playback_aa_slot); -#if CONFIG_TUNER - if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) - { - struct dim dim = {data->albumart->width, data->albumart->height}; - handle = radio_get_art_hid(&dim); - } -#endif - draw_album_art(gwps, handle, false); - data->albumart->draw = false; + draw_album_art(gwps, data->albumart->draw_handle, false); + data->albumart->draw_handle = -1; } #endif @@ -471,7 +467,7 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp) #else /* HAVE_LCD_CHARCELL */ -static bool draw_player_progress(struct gui_wps *gwps) +bool draw_player_progress(struct gui_wps *gwps) { struct wps_state *state = gwps->state; struct screen *display = gwps->display; @@ -508,7 +504,7 @@ static bool draw_player_progress(struct gui_wps *gwps) return true; } -static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size) +void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size) { static const unsigned char numbers[10][4] = { {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */ @@ -613,44 +609,25 @@ static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size) #endif /* HAVE_LCD_CHARCELL */ -/* Return the index to the end token for the conditional token at index. - The conditional token can be either a start token or a separator - (i.e. option) token. -*/ -static int find_conditional_end(struct wps_data *data, int index) -{ - int ret = index; - while (data->tokens[ret].type != WPS_TOKEN_CONDITIONAL_END) - ret = data->tokens[ret].value.i; - - /* ret now is the index to the end token for the conditional. */ - return ret; -} - /* Evaluate the conditional that is at *token_index and return whether a skip has ocurred. *token_index is updated with the new position. */ -static bool evaluate_conditional(struct gui_wps *gwps, int *token_index) +int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options) { if (!gwps) return false; - struct wps_data *data = gwps->data; - - int i, cond_end; - int cond_index = *token_index; char result[128]; const char *value; - unsigned char num_options = data->tokens[cond_index].value.i & 0xFF; - unsigned char prev_val = (data->tokens[cond_index].value.i & 0xFF00) >> 8; - /* treat ?xx<true> constructs as if they had 2 options. */ + /* treat ?xx<true> constructs as if they had 2 options. + * (i.e ?xx<true|false>) */ if (num_options < 2) num_options = 2; int intval = num_options; /* get_token_value needs to know the number of options in the enum */ - value = get_token_value(gwps, &data->tokens[cond_index + 1], + value = get_token_value(gwps, conditional->token, result, sizeof(result), &intval); /* intval is now the number of the enum option we want to read, @@ -659,334 +636,18 @@ static bool evaluate_conditional(struct gui_wps *gwps, int *token_index) intval = (value && *value) ? 1 : num_options; else if (intval > num_options || intval < 1) intval = num_options; - - data->tokens[cond_index].value.i = (intval << 8) + num_options; - - /* skip to the appropriate enum case */ - int next = cond_index + 2; - for (i = 1; i < intval; i++) - { - next = data->tokens[next].value.i; - } - *token_index = next; - - if (prev_val == intval) - { - /* Same conditional case as previously. Return without clearing the - pictures */ - return false; - } - - cond_end = find_conditional_end(data, cond_index + 2); - for (i = cond_index + 3; i < cond_end; i++) - { -#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, find_image(data->tokens[i].value.i&0xFF, data)); - else if (data->tokens[i].type == WPS_TOKEN_VOLUMEBAR || - data->tokens[i].type == WPS_TOKEN_PROGRESSBAR || - data->tokens[i].type == WPS_TOKEN_BATTERY_PERCENTBAR ) - { - struct progressbar *bar = (struct progressbar*)data->tokens[i].value.data; - bar->draw = false; - } - else if (data->tokens[i].type == WPS_TOKEN_PEAKMETER) - { - data->peak_meter_enabled = false; - } -#endif -#ifdef HAVE_ALBUMART - if (data->albumart && data->tokens[i].type == WPS_TOKEN_ALBUMART_DISPLAY) - { - draw_album_art(gwps, - playback_current_aa_hid(data->playback_aa_slot), true); - data->albumart->draw = false; - } -#endif - } - - return true; -} - - -/* 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. - The return value indicates whether the line needs to be updated. -*/ -static bool get_line(struct gui_wps *gwps, - struct skin_subline *subline, - struct align_pos *align, - char *linebuf, - int linebuf_size, - unsigned refresh_mode) -{ - struct wps_data *data = gwps->data; - - char temp_buf[128]; - char *buf = linebuf; /* will always point to the writing position */ - char *linebuf_end = linebuf + linebuf_size - 1; - bool update = false; - int i; - (void)refresh_mode; /* silence warning on charcell */ - - /* alignment-related variables */ - int cur_align; - char* cur_align_start; - cur_align_start = buf; - cur_align = WPS_ALIGN_LEFT; - align->left = NULL; - align->center = NULL; - align->right = NULL; - /* Process all tokens of the desired subline */ - for (i = subline->first_token_idx; - i <= subline->last_token_idx; i++) - { - switch(data->tokens[i].type) - { - case WPS_TOKEN_CONDITIONAL: - /* place ourselves in the right conditional case */ - update |= evaluate_conditional(gwps, &i); - break; - - case WPS_TOKEN_CONDITIONAL_OPTION: - /* we've finished in the curent conditional case, - skip to the end of the conditional structure */ - i = find_conditional_end(data, i); - break; -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) - case WPS_TOKEN_VIEWPORT_FGCOLOUR: - { - struct viewport_colour *col = data->tokens[i].value.data; - col->vp->fg_pattern = col->colour; - } - break; - case WPS_TOKEN_VIEWPORT_BGCOLOUR: - { - struct viewport_colour *col = data->tokens[i].value.data; - col->vp->bg_pattern = col->colour; - } - break; -#endif -#ifdef HAVE_LCD_BITMAP - case WPS_TOKEN_PEAKMETER: - data->peak_meter_enabled = true; - break; - case WPS_TOKEN_VOLUMEBAR: - case WPS_TOKEN_BATTERY_PERCENTBAR: - case WPS_TOKEN_PROGRESSBAR: - { - struct progressbar *bar = (struct progressbar*)data->tokens[i].value.data; - bar->draw = true; - } - break; - case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY: - { - char n = data->tokens[i].value.i & 0xFF; - int subimage = data->tokens[i].value.i >> 8; - struct gui_img *img = find_image(n, data); - - if (img && img->loaded) - img->display = subimage; - break; - } - case WPS_TOKEN_DRAW_INBUILTBAR: - gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]), - refresh_mode == WPS_REFRESH_ALL, - data->tokens[i].value.data); - break; -#endif - - case WPS_TOKEN_ALIGN_LEFT: - case WPS_TOKEN_ALIGN_LEFT_RTL: - case WPS_TOKEN_ALIGN_CENTER: - case WPS_TOKEN_ALIGN_RIGHT: - case WPS_TOKEN_ALIGN_RIGHT_RTL: - /* remember where the current aligned text started */ - switch (cur_align) - { - case WPS_ALIGN_LEFT: - align->left = cur_align_start; - break; - - case WPS_ALIGN_CENTER: - align->center = cur_align_start; - break; - - case WPS_ALIGN_RIGHT: - align->right = cur_align_start; - break; - } - /* start a new alignment */ - switch (data->tokens[i].type) - { - case WPS_TOKEN_ALIGN_LEFT: - cur_align = WPS_ALIGN_LEFT; - break; - case WPS_TOKEN_ALIGN_LEFT_RTL: - cur_align = lang_is_rtl() ? WPS_ALIGN_RIGHT : - WPS_ALIGN_LEFT; - break; - case WPS_TOKEN_ALIGN_CENTER: - cur_align = WPS_ALIGN_CENTER; - break; - case WPS_TOKEN_ALIGN_RIGHT: - cur_align = WPS_ALIGN_RIGHT; - break; - case WPS_TOKEN_ALIGN_RIGHT_RTL: - cur_align = lang_is_rtl() ? WPS_ALIGN_LEFT : - WPS_ALIGN_RIGHT; - break; - default: - break; - } - *buf++ = 0; - cur_align_start = buf; - break; - case WPS_VIEWPORT_ENABLE: - { - char label = data->tokens[i].value.i; - char temp = VP_DRAW_HIDEABLE; - /* viewports are allowed to share id's so find and enable - * all of them */ - struct skin_token_list *list = data->viewports; - while (list) - { - struct skin_viewport *vp = - (struct skin_viewport *)list->token->value.data; - if (vp->label == label) - { - if (vp->hidden_flags&VP_DRAW_WASHIDDEN) - temp |= VP_DRAW_WASHIDDEN; - vp->hidden_flags = temp; - } - list = list->next; - } - } - break; -#ifdef HAVE_LCD_BITMAP - case WPS_TOKEN_UIVIEWPORT_ENABLE: - sb_set_info_vp(gwps->display->screen_type, - data->tokens[i].value.i|VP_INFO_LABEL); - break; - 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 */ - const char *value = get_token_value(gwps, &data->tokens[i], - temp_buf, sizeof(temp_buf), NULL); - if (value) - { - update = true; - while (*value && (buf < linebuf_end)) - *buf++ = *value++; - } - break; - } - } - } - - /* close the current alignment */ - switch (cur_align) - { - case WPS_ALIGN_LEFT: - align->left = cur_align_start; - break; - - case WPS_ALIGN_CENTER: - align->center = cur_align_start; - break; - - case WPS_ALIGN_RIGHT: - align->right = cur_align_start; - break; - } - - return update; -} -static void get_subline_timeout(struct gui_wps *gwps, struct skin_subline *subline) -{ - struct wps_data *data = gwps->data; - int i; - subline->time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER; - - for (i = subline->first_token_idx; - i <= subline->last_token_idx; i++) - { - switch(data->tokens[i].type) - { - case WPS_TOKEN_CONDITIONAL: - /* place ourselves in the right conditional case */ - evaluate_conditional(gwps, &i); - break; - - case WPS_TOKEN_CONDITIONAL_OPTION: - /* we've finished in the curent conditional case, - skip to the end of the conditional structure */ - i = find_conditional_end(data, i); - break; - - case WPS_TOKEN_SUBLINE_TIMEOUT: - subline->time_mult = data->tokens[i].value.i; - break; - - default: - break; - } - } + + conditional->last_value = intval -1; + return intval -1; } -/* Calculates which subline should be displayed for the specified line - Returns true iff the subline must be refreshed */ -static bool update_curr_subline(struct gui_wps *gwps, struct skin_line *line) -{ - /* shortcut this whole thing if we need to reset the line completly */ - if (line->curr_subline == NULL) - { - line->subline_expire_time = current_tick; - line->curr_subline = &line->sublines; - if (!line->curr_subline->next) - { - line->subline_expire_time += 100*HZ; - } - else - { - get_subline_timeout(gwps, line->curr_subline); - line->subline_expire_time += TIMEOUT_UNIT*line->curr_subline->time_mult; - } - return true; - } - /* if time to advance to next sub-line */ - if (TIME_AFTER(current_tick, line->subline_expire_time - 1)) - { - /* if there is only one subline, there is no need to search for a new one */ - if (&line->sublines == line->curr_subline && - line->curr_subline->next == NULL) - { - line->subline_expire_time += 100 * HZ; - return false; - } - if (line->curr_subline->next) - line->curr_subline = line->curr_subline->next; - else - line->curr_subline = &line->sublines; - get_subline_timeout(gwps, line->curr_subline); - line->subline_expire_time = current_tick + TIMEOUT_UNIT*line->curr_subline->time_mult; - return true; - } - return false; -} /* 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. scroll indicates whether the line is a scrolling one or not. */ -static void write_line(struct screen *display, +void write_line(struct screen *display, struct align_pos *format_align, int line, bool scroll) @@ -1143,244 +804,30 @@ static void write_line(struct screen *display, } } -static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode) +#ifdef HAVE_LCD_BITMAP +void draw_peakmeters(struct gui_wps *gwps, int line_number, + struct viewport *viewport) { struct wps_data *data = gwps->data; - struct screen *display = gwps->display; - - if (!data || !display || !gwps->state) - return false; - - unsigned flags; - char linebuf[MAX_PATH]; - - struct align_pos align; - align.left = NULL; - align.center = NULL; - align.right = NULL; - - - struct skin_token_list *viewport_list; - - bool update_line, new_subline_refresh; - - /* reset to first subline if refresh all flag is set */ - if (refresh_mode == WPS_REFRESH_ALL) + if (!data->peak_meter_enabled) { - struct skin_line *line; - struct skin_viewport *skin_viewport = find_viewport(VP_DEFAULT_LABEL, data); - - if (!(skin_viewport->hidden_flags & VP_NEVER_VISIBLE)) - { - display->set_viewport(&skin_viewport->vp); - display->clear_viewport(); - } - - for (viewport_list = data->viewports; - viewport_list; viewport_list = viewport_list->next) - { - skin_viewport = - (struct skin_viewport *)viewport_list->token->value.data; - for(line = skin_viewport->lines; line; line = line->next) - { - line->curr_subline = NULL; - } - } + peak_meter_enable(false); } - -#ifdef HAVE_LCD_CHARCELLS - int i; - for (i = 0; i < 8; i++) - { - if (data->wps_progress_pat[i] == 0) - data->wps_progress_pat[i] = display->get_locked_pattern(); - } -#endif - - /* disable any viewports which are conditionally displayed. - * If we are only refreshing the peak meter then don't change the viewport - * enabled flags as this will stop scrolling. viewports cant be - * toggled in this refresh mode anyway (FS#10215)*/ - if (refresh_mode != WPS_REFRESH_PEAK_METER) - { - for (viewport_list = data->viewports; - viewport_list; viewport_list = viewport_list->next) - { - struct skin_viewport *skin_viewport = - (struct skin_viewport *)viewport_list->token->value.data; - if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) - { - continue; - } - if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE) - { - if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN) - skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; - else - skin_viewport->hidden_flags |= VP_DRAW_HIDDEN; - } - } - } - for (viewport_list = data->viewports; - viewport_list; viewport_list = viewport_list->next) + else { - struct skin_viewport *skin_viewport = - (struct skin_viewport *)viewport_list->token->value.data; - unsigned vp_refresh_mode = refresh_mode; -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) - skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour; - skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour; -#endif - display->set_viewport(&skin_viewport->vp); - - int hidden_vp = 0; + int h = font_get(viewport->font)->height; + int peak_meter_y = line_number * h; -#ifdef HAVE_LCD_BITMAP - /* Set images to not to be displayed */ - struct skin_token_list *imglist = data->images; - while (imglist) - { - 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 */ - if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) - { /* don't draw anything into this one */ - vp_refresh_mode = 0; hidden_vp = true; - } - else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN)) - { - if (!(skin_viewport->hidden_flags&VP_DRAW_WASHIDDEN)) - display->scroll_stop(&skin_viewport->vp); - skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; - continue; - } - else if (((skin_viewport->hidden_flags& - (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)) - == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))) - { - vp_refresh_mode = WPS_REFRESH_ALL; - skin_viewport->hidden_flags = VP_DRAW_HIDEABLE; - } - - if (vp_refresh_mode == WPS_REFRESH_ALL) - { - display->clear_viewport(); + /* The user might decide to have the peak meter in the last + line so that it is only displayed if no status bar is + visible. If so we neither want do draw nor enable the + peak meter. */ + if (peak_meter_y + h <= viewport->y+viewport->height) { + peak_meter_enable(true); + peak_meter_screen(gwps->display, 0, peak_meter_y, + MIN(h, viewport->y+viewport->height - peak_meter_y)); } - - /* loop over the lines for this viewport */ - struct skin_line *line; - /* %V() doesnt eat the \n which means the first line of text - * is actually going to be one line down. so set line_count to -1 - * unless we are using the default viewport which doesnt have this problem */ - int line_count = skin_viewport->label==VP_DEFAULT_LABEL?0:-1; - - for (line = skin_viewport->lines; line; line = line->next, line_count++) - { - struct skin_subline *subline; - memset(linebuf, 0, sizeof(linebuf)); - update_line = false; - - /* get current subline for the line */ - new_subline_refresh = update_curr_subline(gwps, line); - subline = line->curr_subline; - flags = line->curr_subline->line_type; - - if (vp_refresh_mode == WPS_REFRESH_ALL || (flags & vp_refresh_mode) - || new_subline_refresh || hidden_vp) - { - /* get_line tells us if we need to update the line */ - update_line = get_line(gwps, subline, &align, - linebuf, sizeof(linebuf), vp_refresh_mode); - } -#ifdef HAVE_LCD_BITMAP - /* peakmeter */ - if (flags & vp_refresh_mode & WPS_REFRESH_PEAK_METER) - { - if (!data->peak_meter_enabled) - { - peak_meter_enable(false); - } - else - { - /* the peakmeter should be alone on its line */ - update_line = false; - - int h = font_get(skin_viewport->vp.font)->height; - int peak_meter_y = line_count* h; - - /* The user might decide to have the peak meter in the last - line so that it is only displayed if no status bar is - visible. If so we neither want do draw nor enable the - peak meter. */ - if (peak_meter_y + h <= skin_viewport->vp.y+skin_viewport->vp.height) { - peak_meter_enable(true); - peak_meter_screen(gwps->display, 0, peak_meter_y, - MIN(h, skin_viewport->vp.y+skin_viewport->vp.height - peak_meter_y)); - } - } - } - -#else /* HAVE_LCD_CHARCELL */ - - /* progressbar */ - if (flags & vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) - { - if (data->full_line_progressbar) - draw_player_fullbar(gwps, linebuf, sizeof(linebuf)); - else - draw_player_progress(gwps); - } -#endif - - if (line_count>= 0 && update_line && !hidden_vp && - /* conditionals clear the line which means if the %Vd is put into the default - viewport there will be a blank line. - To get around this we dont allow any actual drawing to happen in the - deault vp if other vp's are defined */ - ((skin_viewport->label != VP_DEFAULT_LABEL && viewport_list->next) || - !viewport_list->next)) - { - if (flags & WPS_REFRESH_SCROLL) - { - /* if the line is a scrolling one we don't want to update - too often, so that it has the time to scroll */ - if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh) - write_line(display, &align, line_count, true); - } - else - write_line(display, &align, line_count, false); - } - } -#ifdef HAVE_LCD_BITMAP - /* progressbar */ - if (vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) - { - struct skin_token_list *bar = gwps->data->progressbars; - while (bar) - { - struct progressbar *thisbar = (struct progressbar*)bar->token->value.data; - if (thisbar->vp == &skin_viewport->vp && thisbar->draw) - { - draw_progressbar(gwps, thisbar); - } - bar = bar->next; - } - } - /* Now display any images in this viewport */ - if (!hidden_vp) - wps_display_images(gwps, &skin_viewport->vp); -#endif } - - /* Restore the default viewport */ - display->set_viewport(NULL); - - display->update(); - - return true; } bool skin_has_sbs(enum screen_type screen, struct wps_data *data) @@ -1396,6 +843,7 @@ bool skin_has_sbs(enum screen_type screen, struct wps_data *data) #endif return draw; } +#endif /* do the button loop as often as required for the peak meters to update * with a good refresh rate. @@ -1434,7 +882,7 @@ int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout) FOR_NB_SCREENS(i) { if(gwps[i].data->peak_meter_enabled) - skin_update(&gwps[i], WPS_REFRESH_PEAK_METER); + skin_update(&gwps[i], SKIN_REFRESH_PEAK_METER); next_refresh += HZ / PEAK_METER_FPS; } } diff --git a/apps/gui/skin_engine/skin_display.h b/apps/gui/skin_engine/skin_display.h new file mode 100644 index 0000000000..81274a7391 --- /dev/null +++ b/apps/gui/skin_engine/skin_display.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002-2007 Björn Stenberg + * Copyright (C) 2007-2008 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. + * + ****************************************************************************/ +#include "config.h" +#include <stdio.h> +#include "wps_internals.h" +#include "skin_engine.h" +#include "statusbar-skinned.h" + +#ifndef _SKIN_DISPLAY_H_ +#define _SKIN_DISPLAY_H_ + + +#ifdef HAVE_LCD_BITMAP +void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb); +void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer); +/* clears the area where the image was shown */ +void clear_image_pos(struct gui_wps *gwps, struct gui_img *img); +void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage); +void wps_display_images(struct gui_wps *gwps, struct viewport* vp); +#else +bool draw_player_progress(struct gui_wps *gwps); +void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size); +#endif + +/* 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); +/* 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. + scroll indicates whether the line is a scrolling one or not. +*/ +void write_line(struct screen *display, + struct align_pos *format_align, + int line, + bool scroll); +void draw_peakmeters(struct gui_wps *gwps, int line_number, + struct viewport *viewport); +#endif diff --git a/apps/gui/skin_engine/skin_engine.h b/apps/gui/skin_engine/skin_engine.h index 69991ab587..9845d8ca8a 100644 --- a/apps/gui/skin_engine/skin_engine.h +++ b/apps/gui/skin_engine/skin_engine.h @@ -23,7 +23,10 @@ #ifndef _SKIN_ENGINE_H #define _SKIN_ENGINE_H -#include "skin_buffer.h" +#ifndef PLUGIN + +#include "skin_fonts.h" +#include "tag_table.h" #include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */ @@ -39,13 +42,37 @@ enum skinnable_screens { }; +#ifdef HAVE_LCD_BITMAP +#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \ + + (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES)) + +#if (NB_SCREENS > 1) +#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \ + + (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES)) +#else +#define REMOTE_BUFFER 0 +#endif + + +#define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER + SKIN_FONT_SIZE) + \ + (WPS_MAX_TOKENS * \ + (sizeof(struct wps_token) + (sizeof(struct skin_element)))) +#endif + +#ifdef HAVE_LCD_CHARCELLS +#define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \ + (WPS_MAX_TOKENS * \ + (sizeof(struct wps_token) + (sizeof(struct skin_element)))) +#endif + + #ifdef HAVE_TOUCHSCREEN int skin_get_touchaction(struct wps_data *data, int* edge_offset); void skin_disarm_touchregions(struct wps_data *data); #endif /* Do a update_type update of the skinned screen */ -bool skin_update(struct gui_wps *gwps, unsigned int update_type); +void skin_update(struct gui_wps *gwps, unsigned int update_type); /* * setup up the skin-data from a format-buffer (isfile = false) @@ -72,3 +99,5 @@ void skin_backdrop_init(void); */ int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout); #endif + +#endif diff --git a/apps/gui/skin_engine/skin_fonts.c b/apps/gui/skin_engine/skin_fonts.c index f446a9948b..92a6a22ccf 100644 --- a/apps/gui/skin_engine/skin_fonts.c +++ b/apps/gui/skin_engine/skin_fonts.c @@ -88,7 +88,7 @@ int skin_font_load(char* font_name) pf = &font->font; if (!font->buffer) { - pf->buffer_start = skin_buffer_alloc(SKIN_FONT_SIZE); + pf->buffer_start = (char*)skin_buffer_alloc(SKIN_FONT_SIZE); if (!pf->buffer_start) return -1; font->buffer = pf->buffer_start; diff --git a/apps/gui/skin_engine/skin_fonts.h b/apps/gui/skin_engine/skin_fonts.h index 6e3634e740..2988b43415 100644 --- a/apps/gui/skin_engine/skin_fonts.h +++ b/apps/gui/skin_engine/skin_fonts.h @@ -27,7 +27,6 @@ #include "file.h" #include "settings.h" #include "font.h" -#include "skin_buffer.h" #ifndef _SKINFONTS_H_ #define _SKINFONTS_H_ diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c index a62791e397..52e7e1155c 100644 --- a/apps/gui/skin_engine/skin_parser.c +++ b/apps/gui/skin_engine/skin_parser.c @@ -8,6 +8,7 @@ * $Id$ * * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr + * 2010 Jonathan Gordon * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,6 +29,10 @@ #include "plugin.h" #include "viewport.h" +#include "skin_buffer.h" +#include "skin_parser.h" +#include "tag_table.h" + #ifdef __PCTOOL__ #ifdef WPSEDITOR #include "proxy.h" @@ -71,377 +76,29 @@ #define WPS_ERROR_INVALID_PARAM -1 -/* which screen are we parsing for? */ -static enum screen_type curr_screen; - -/* level of current conditional. - -1 means we're not in a conditional. */ -static int level = -1; - -/* index of the last WPS_TOKEN_CONDITIONAL_OPTION - or WPS_TOKEN_CONDITIONAL_START in current level */ -static int lastcond[WPS_MAX_COND_LEVEL]; - -/* index of the WPS_TOKEN_CONDITIONAL in current level */ -static int condindex[WPS_MAX_COND_LEVEL]; - -/* number of condtional options in current level */ -static int numoptions[WPS_MAX_COND_LEVEL]; - -/* line number, debug only */ -static int line_number; - -/* the current viewport */ -static struct skin_viewport *curr_vp; -/* the current line, linked to the above viewport */ -static struct skin_line *curr_line; - -static int follow_lang_direction = 0; - -#if defined(DEBUG) || defined(SIMULATOR) -/* debugging function */ -extern void print_debug_info(struct wps_data *data, int fail, int line); -extern void debug_skin_usage(void); -#endif - -/* Function for parsing of details for a token. At the moment the - function is called, the token type has already been set. The - function must fill in the details and possibly add more tokens - to the token array. It should return the number of chars that - has been consumed. - - wps_bufptr points to the char following the tag (i.e. where - details begin). - token is the pointer to the 'main' token being parsed - */ -typedef int (*wps_tag_parse_func)(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); - -struct wps_tag { - enum wps_token_type type; - const char name[3]; - unsigned char refresh_type; - const wps_tag_parse_func parse_func; -}; -static int skip_end_of_line(const char *wps_bufptr); -/* prototypes of all special parse functions : */ -static int parse_timeout(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_progressbar(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_dir_level(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_setting_and_lang(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); - - -static int parse_languagedirection(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data) -{ - (void)wps_bufptr; - (void)token; - (void)wps_data; - follow_lang_direction = 2; /* 2 because it is decremented immediatly after - this token is parsed, after the next token it - will be 0 again. */ - return 0; -} -#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, - struct wps_token *token, struct wps_data *wps_data); -static int parse_statusbar_disable(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_statusbar_inbuilt(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_image_display(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_image_load(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_font_load(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -#endif /*HAVE_LCD_BITMAP */ -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) -static int parse_viewportcolour(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_image_special(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -#endif -#ifdef HAVE_ALBUMART -static int parse_albumart_load(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_albumart_display(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -#endif /* HAVE_ALBUMART */ -#ifdef HAVE_TOUCHSCREEN -static int parse_touchregion(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -#else -static int fulline_tag_not_supported(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data) +static bool isdefault(struct skin_tag_parameter *param) { - (void)token; (void)wps_data; - return skip_end_of_line(wps_bufptr); + return param->type == DEFAULT; } -#define parse_touchregion fulline_tag_not_supported -#endif -#ifdef CONFIG_RTC -#define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC -#else -#define WPS_RTC_REFRESH WPS_REFRESH_STATIC -#endif -/* array of available tags - those with more characters have to go first - (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */ -static const struct wps_tag all_tags[] = { - - { WPS_TOKEN_ALIGN_CENTER, "ac", 0, NULL }, - { WPS_TOKEN_ALIGN_LEFT, "al", 0, NULL }, - { WPS_TOKEN_ALIGN_LEFT_RTL, "aL", 0, NULL }, - { WPS_TOKEN_ALIGN_RIGHT, "ar", 0, NULL }, - { WPS_TOKEN_ALIGN_RIGHT_RTL, "aR", 0, NULL }, - { WPS_NO_TOKEN, "ax", 0, parse_languagedirection }, - - { WPS_TOKEN_BATTERY_PERCENT, "bl", WPS_REFRESH_DYNAMIC, parse_progressbar }, - { WPS_TOKEN_BATTERY_VOLTS, "bv", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_BATTERY_TIME, "bt", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_BATTERY_SLEEPTIME, "bs", WPS_REFRESH_DYNAMIC, NULL }, -#if CONFIG_CHARGING >= CHARGING_MONITOR - { WPS_TOKEN_BATTERY_CHARGING, "bc", WPS_REFRESH_DYNAMIC, NULL }, -#endif -#if CONFIG_CHARGING - { WPS_TOKEN_BATTERY_CHARGER_CONNECTED,"bp", WPS_REFRESH_DYNAMIC, NULL }, -#endif -#ifdef HAVE_USB_POWER - { WPS_TOKEN_USB_POWERED, "bu", WPS_REFRESH_DYNAMIC, NULL }, -#endif - { WPS_TOKEN_RTC_PRESENT , "cc", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_RTC_DAY_OF_MONTH, "cd", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,"ce", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_12HOUR_CFG, "cf", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_HOUR_24, "ck", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_HOUR_12, "cl", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_MONTH, "cm", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_MINUTE, "cM", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_SECOND, "cS", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_YEAR_2_DIGITS, "cy", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_YEAR_4_DIGITS, "cY", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_AM_PM_UPPER, "cP", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_AM_PM_LOWER, "cp", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_WEEKDAY_NAME, "ca", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_MONTH_NAME, "cb", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", WPS_RTC_REFRESH, NULL }, - - /* current file */ - { WPS_TOKEN_FILE_BITRATE, "fb", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_CODEC, "fc", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY, "ff", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY_KHZ, "fk", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_NAME, "fn", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_PATH, "fp", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_SIZE, "fs", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_VBR, "fv", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_DIRECTORY, "d", WPS_REFRESH_STATIC, - parse_dir_level }, - - /* next file */ - { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_STATIC, - parse_dir_level }, - - /* current metadata */ - { WPS_TOKEN_METADATA_ARTIST, "ia", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_COMPOSER, "ic", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM, "id", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM_ARTIST, "iA", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_GROUPING, "iG", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_GENRE, "ig", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_DISC_NUMBER, "ik", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_NUMBER, "in", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_TITLE, "it", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_VERSION, "iv", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_YEAR, "iy", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_COMMENT, "iC", WPS_REFRESH_STATIC, NULL }, - - /* next metadata */ - { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_STATIC, NULL }, - -#if (CONFIG_CODEC != MAS3507D) - { WPS_TOKEN_SOUND_PITCH, "Sp", WPS_REFRESH_DYNAMIC, NULL }, -#endif -#if (CONFIG_CODEC == SWCODEC) - { WPS_TOKEN_SOUND_SPEED, "Ss", WPS_REFRESH_DYNAMIC, NULL }, -#endif -#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) - { WPS_TOKEN_VLED_HDD, "lh", WPS_REFRESH_DYNAMIC, NULL }, -#endif - - { WPS_TOKEN_MAIN_HOLD, "mh", WPS_REFRESH_DYNAMIC, NULL }, - -#ifdef HAS_REMOTE_BUTTON_HOLD - { WPS_TOKEN_REMOTE_HOLD, "mr", WPS_REFRESH_DYNAMIC, NULL }, -#else - { WPS_TOKEN_UNKNOWN, "mr", 0, NULL }, -#endif - - { WPS_TOKEN_REPEAT_MODE, "mm", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_PLAYBACK_STATUS, "mp", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_BUTTON_VOLUME, "mv", WPS_REFRESH_DYNAMIC, - parse_timeout }, - -#ifdef HAVE_LCD_BITMAP - { WPS_TOKEN_PEAKMETER, "pm", WPS_REFRESH_PEAK_METER, NULL }, -#else - { WPS_TOKEN_PLAYER_PROGRESSBAR, "pf", - WPS_REFRESH_DYNAMIC | WPS_REFRESH_PLAYER_PROGRESS, parse_progressbar }, -#endif - { WPS_TOKEN_PROGRESSBAR, "pb", WPS_REFRESH_PLAYER_PROGRESS, - parse_progressbar }, - - { WPS_TOKEN_VOLUME, "pv", WPS_REFRESH_DYNAMIC, - parse_progressbar }, - - { WPS_TOKEN_TRACK_ELAPSED_PERCENT, "px", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TRACK_TIME_ELAPSED, "pc", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TRACK_TIME_REMAINING, "pr", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TRACK_LENGTH, "pt", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_TRACK_STARTING, "pS", WPS_REFRESH_DYNAMIC, parse_timeout }, - { WPS_TOKEN_TRACK_ENDING, "pE", WPS_REFRESH_DYNAMIC, parse_timeout }, - - { WPS_TOKEN_PLAYLIST_POSITION, "pp", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PLAYLIST_ENTRIES, "pe", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PLAYLIST_NAME, "pn", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PLAYLIST_SHUFFLE, "ps", WPS_REFRESH_DYNAMIC, NULL }, - -#ifdef HAVE_TAGCACHE - { WPS_TOKEN_DATABASE_PLAYCOUNT, "rp", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_DATABASE_RATING, "rr", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_DATABASE_AUTOSCORE, "ra", WPS_REFRESH_DYNAMIC, NULL }, -#endif - -#if CONFIG_CODEC == SWCODEC - { WPS_TOKEN_REPLAYGAIN, "rg", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_CROSSFADE, "xf", WPS_REFRESH_DYNAMIC, NULL }, -#endif - - { WPS_TOKEN_HAVE_TUNER, "tp", WPS_REFRESH_STATIC, NULL }, -#if CONFIG_TUNER /* Re-uses the 't' and 'T' prefixes, be careful about doubleups */ - { WPS_TOKEN_TUNER_TUNED, "tt", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TUNER_SCANMODE, "tm", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TUNER_STEREO, "ts", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TUNER_MINFREQ, "ta", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_TUNER_MAXFREQ, "tb", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_TUNER_CURFREQ, "tf", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_PRESET_ID, "Ti", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PRESET_NAME, "Tn", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PRESET_FREQ, "Tf", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PRESET_COUNT, "Tc", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_HAVE_RDS, "tx", WPS_REFRESH_STATIC, NULL }, -#ifdef HAVE_RDS_CAP - { WPS_TOKEN_RDS_NAME, "ty", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_RDS_TEXT, "tz", WPS_REFRESH_DYNAMIC, NULL }, -#endif -#endif /* CONFIG_TUNER */ - - { WPS_NO_TOKEN, "s", WPS_REFRESH_SCROLL, NULL }, - { WPS_TOKEN_SUBLINE_TIMEOUT, "t", 0, parse_timeout }, +/* which screen are we parsing for? */ +static enum screen_type curr_screen; -#ifdef HAVE_LCD_BITMAP - { WPS_NO_TOKEN, "we", 0, parse_statusbar_enable }, - { WPS_NO_TOKEN, "wd", 0, parse_statusbar_disable }, - { WPS_TOKEN_DRAW_INBUILTBAR, "wi", WPS_REFRESH_DYNAMIC, parse_statusbar_inbuilt }, +/* the current viewport */ +static struct skin_element *curr_viewport_element; +static struct skin_viewport *curr_vp; - { WPS_NO_TOKEN, "xl", 0, parse_image_load }, +struct line *curr_line; - { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", WPS_REFRESH_STATIC, - parse_image_display }, +static int follow_lang_direction = 0; - { WPS_TOKEN_IMAGE_DISPLAY, "x", 0, parse_image_load }, - { WPS_NO_TOKEN, "Fl", 0, parse_font_load }, -#ifdef HAVE_ALBUMART - { WPS_NO_TOKEN, "Cl", 0, parse_albumart_load }, - { WPS_TOKEN_ALBUMART_DISPLAY, "Cd", WPS_REFRESH_STATIC, parse_albumart_display }, - { WPS_TOKEN_ALBUMART_FOUND, "C", WPS_REFRESH_STATIC, NULL }, -#endif +typedef int (*parse_function)(struct skin_element *element, + struct wps_token *token, + struct wps_data *wps_data); - { WPS_VIEWPORT_ENABLE, "Vd", WPS_REFRESH_DYNAMIC, - parse_viewport_display }, - { WPS_TOKEN_UIVIEWPORT_ENABLE, "VI", WPS_REFRESH_STATIC, - parse_viewport_display }, #ifdef HAVE_LCD_BITMAP - { WPS_VIEWPORT_CUSTOMLIST, "Vp", WPS_REFRESH_STATIC, parse_playlistview }, - { WPS_TOKEN_LIST_TITLE_TEXT, "Lt", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_LIST_TITLE_ICON, "Li", WPS_REFRESH_DYNAMIC, NULL }, -#endif -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) - { WPS_TOKEN_VIEWPORT_FGCOLOUR, "Vf", WPS_REFRESH_STATIC, parse_viewportcolour }, - { WPS_TOKEN_VIEWPORT_BGCOLOUR, "Vb", WPS_REFRESH_STATIC, parse_viewportcolour }, -#endif - { WPS_NO_TOKEN, "V", 0, parse_viewport }, - -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) - { WPS_TOKEN_IMAGE_BACKDROP, "X", 0, parse_image_special }, -#endif -#endif - - { WPS_TOKEN_SETTING, "St", WPS_REFRESH_DYNAMIC, - parse_setting_and_lang }, - { WPS_TOKEN_TRANSLATEDSTRING, "Sx", WPS_REFRESH_STATIC, - parse_setting_and_lang }, - { WPS_TOKEN_LANG_IS_RTL , "Sr", WPS_REFRESH_STATIC, NULL }, - - { WPS_TOKEN_LASTTOUCH, "Tl", WPS_REFRESH_DYNAMIC, parse_timeout }, - { WPS_TOKEN_CURRENT_SCREEN, "cs", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_NO_TOKEN, "T", 0, parse_touchregion }, - - - /* Recording Tokens */ - { WPS_TOKEN_HAVE_RECORDING, "Rp", WPS_REFRESH_STATIC, NULL }, -#ifdef HAVE_RECORDING - { WPS_TOKEN_IS_RECORDING, "Rr", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_REC_FREQ, "Rf", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_REC_ENCODER, "Re", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_REC_BITRATE, "Rb", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_REC_MONO, "Rm", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_REC_SECONDS, "Rs", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_REC_MINUTES, "Rn", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_REC_HOURS, "Rh", WPS_REFRESH_DYNAMIC, NULL }, -#endif - { WPS_TOKEN_UNKNOWN, "", 0, NULL } - /* the array MUST end with an empty string (first char is \0) */ -}; - - /* add a skin_token_list item to the list chain. ALWAYS appended because some of the * chains require the order to be kept. */ @@ -459,7 +116,6 @@ static void add_to_ll_chain(struct skin_token_list **list, struct skin_token_lis } /* traverse the image linked-list for an image */ -#ifdef HAVE_LCD_BITMAP struct gui_img* find_image(char label, struct wps_data *data) { struct skin_token_list *list = data->images; @@ -478,10 +134,10 @@ struct gui_img* find_image(char label, struct wps_data *data) /* traverse the viewport linked list for a viewport */ struct skin_viewport* find_viewport(char label, struct wps_data *data) { - struct skin_token_list *list = data->viewports; + struct skin_element *list = data->tree; while (list) { - struct skin_viewport *vp = (struct skin_viewport *)list->token->value.data; + struct skin_viewport *vp = (struct skin_viewport *)list->data; if (vp->label == label) return vp; list = list->next; @@ -489,6 +145,7 @@ struct skin_viewport* find_viewport(char label, struct wps_data *data) return NULL; } +#ifdef HAVE_LCD_BITMAP /* create and init a new wpsll item. * passing NULL to token will alloc a new one. @@ -498,9 +155,10 @@ struct skin_viewport* find_viewport(char label, struct wps_data *data) 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)); + struct skin_token_list *llitem = + (struct skin_token_list *)skin_buffer_alloc(sizeof(struct skin_token_list)); if (!token) - token = skin_buffer_alloc(sizeof(struct wps_token)); + token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token)); if (!llitem || !token) return NULL; llitem->next = NULL; @@ -510,108 +168,36 @@ static struct skin_token_list *new_skin_token_list_item(struct wps_token *token, 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) -{ - line_number++; - int skip = 0; - while(*(wps_bufptr + skip) != '\n') - skip++; - return ++skip; -} - -/* Starts a new subline in the current line during parsing */ -static bool skin_start_new_subline(struct skin_line *line, int curr_token) -{ - struct skin_subline *subline = skin_buffer_alloc(sizeof(struct skin_subline)); - if (!subline) - return false; - - subline->first_token_idx = curr_token; - subline->next = NULL; - - subline->line_type = 0; - subline->time_mult = 0; - - line->curr_subline->last_token_idx = curr_token-1; - line->curr_subline->next = subline; - line->curr_subline = subline; - return true; -} - -static bool skin_start_new_line(struct skin_viewport *vp, int curr_token) +static int parse_statusbar_tags(struct skin_element* element, + struct wps_token *token, + struct wps_data *wps_data) { - struct skin_line *line = skin_buffer_alloc(sizeof(struct skin_line)); - struct skin_subline *subline = NULL; - if (!line) - return false; - - /* init the subline */ - subline = &line->sublines; - subline->first_token_idx = curr_token; - subline->next = NULL; - subline->line_type = 0; - subline->time_mult = 0; - - /* init the new line */ - line->curr_subline = &line->sublines; - line->next = NULL; - line->subline_expire_time = 0; - - /* connect to curr_line and vp pointers. - * 1) close the previous lines subline - * 2) connect to vp pointer - * 3) connect to curr_line global pointer - */ - if (curr_line) + (void)element; + if (token->type == SKIN_TOKEN_DRAW_INBUILTBAR) { - curr_line->curr_subline->last_token_idx = curr_token - 1; - curr_line->next = line; - curr_line->curr_subline = NULL; + token->value.data = (void*)&curr_vp->vp; } - curr_line = line; - if (!vp->lines) - vp->lines = line; - return true; -} - -#ifdef HAVE_LCD_BITMAP - -static int parse_statusbar_enable(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)token; /* Kill warnings */ - wps_data->wps_sb_tag = true; - wps_data->show_sb_on_wps = true; - struct skin_viewport *default_vp = find_viewport(VP_DEFAULT_LABEL, wps_data); - viewport_set_defaults(&default_vp->vp, curr_screen); - default_vp->vp.font = FONT_UI; - return skip_end_of_line(wps_bufptr); -} - -static int parse_statusbar_disable(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)token; /* Kill warnings */ - wps_data->wps_sb_tag = true; - wps_data->show_sb_on_wps = false; - struct skin_viewport *default_vp = find_viewport(VP_DEFAULT_LABEL, wps_data); - viewport_set_fullscreen(&default_vp->vp, curr_screen); - default_vp->vp.font = FONT_UI; - return skip_end_of_line(wps_bufptr); -} - -static int parse_statusbar_inbuilt(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data) -{ - (void)wps_data; - token->value.data = (void*)&curr_vp->vp; - return skip_end_of_line(wps_bufptr); + else + { + struct skin_element *def_vp = wps_data->tree; + struct skin_viewport *default_vp = def_vp->data; + if (def_vp->params_count == 0) + { + wps_data->wps_sb_tag = true; + wps_data->show_sb_on_wps = (token->type == SKIN_TOKEN_ENABLE_THEME); + } + if (wps_data->show_sb_on_wps) + { + viewport_set_defaults(&default_vp->vp, curr_screen); + } + else + { + viewport_set_fullscreen(&default_vp->vp, curr_screen); + } + } + return 0; } - + static int get_image_id(int c) { if(c >= 'a' && c <= 'z') @@ -625,32 +211,20 @@ static int get_image_id(int c) char *get_image_filename(const char *start, const char* bmpdir, char *buf, int buf_size) { - const char *end = start; - int bmpdirlen = strlen(bmpdir); - - while (*end && *end != ',' && *end != ')') - end++; - if ( !end || (end - start) >= (buf_size - bmpdirlen - 2) ) - { - buf[0] = '\0'; - return NULL; - } - - strcpy(buf, bmpdir); - buf[bmpdirlen] = '/'; - memcpy( &buf[bmpdirlen + 1], start, end - start); - buf[bmpdirlen + 1 + end - start] = 0; - + snprintf(buf, buf_size, "%s/%s", bmpdir, start); + return buf; } -static int parse_image_display(const char *wps_bufptr, +static int parse_image_display(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { - char label = wps_bufptr[1]; + char *text = element->params[0].data.text; + char label = text[0]; + char sublabel = text[1]; int subimage; - struct gui_img *img;; + struct gui_img *img; /* sanity check */ img = find_image(label, wps_data); @@ -660,7 +234,7 @@ static int parse_image_display(const char *wps_bufptr, return WPS_ERROR_INVALID_PARAM; } - if ((subimage = get_image_id(wps_bufptr[2])) != -1) + if ((subimage = get_image_id(sublabel)) != -1) { if (subimage >= img->num_subimages) return WPS_ERROR_INVALID_PARAM; @@ -674,32 +248,24 @@ static int parse_image_display(const char *wps_bufptr, } } -static int parse_image_load(const char *wps_bufptr, +static int parse_image_load(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { - const char *ptr = wps_bufptr; const char* filename; const char* id; int x,y; struct gui_img *img; - /* format: %x|n|filename.bmp|x|y| - or %xl|n|filename.bmp|x|y| - or %xl|n|filename.bmp|x|y|num_subimages| + /* format: %x(n,filename.bmp,x,y) + or %xl(n,filename.bmp,x,y) + or %xl(n,filename.bmp,x,y,num_subimages) */ - if (*ptr != '(') - return WPS_ERROR_INVALID_PARAM; - - ptr++; - - if (!(ptr = parse_list("ssdd", NULL, ',', ptr, &id, &filename, &x, &y))) - return WPS_ERROR_INVALID_PARAM; - - /* Check there is a terminating ) */ - if (*ptr != ')' && *ptr != ',') - return WPS_ERROR_INVALID_PARAM; + id = element->params[0].data.text; + filename = element->params[1].data.text; + x = element->params[2].data.number; + y = element->params[3].data.number; /* check the image number and load state */ if(find_image(*id, wps_data)) @@ -707,7 +273,7 @@ static int parse_image_load(const char *wps_bufptr, /* Invalid image ID */ return WPS_ERROR_INVALID_PARAM; } - img = skin_buffer_alloc(sizeof(struct gui_img)); + img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img)); if (!img) return WPS_ERROR_INVALID_PARAM; /* save a pointer to the filename */ @@ -717,62 +283,44 @@ static int parse_image_load(const char *wps_bufptr, img->y = y; img->num_subimages = 1; img->always_display = false; + // img->just_drawn = false; + img->display = -1; /* save current viewport */ img->vp = &curr_vp->vp; - if (token->type == WPS_TOKEN_IMAGE_DISPLAY) + if (token->type == SKIN_TOKEN_IMAGE_DISPLAY) { img->always_display = true; } - else if (*ptr == ',') + else if (element->params_count == 5) { - /* Parse the (optional) number of sub-images */ - ptr++; - img->num_subimages = atoi(ptr); + img->num_subimages = element->params[4].data.number; if (img->num_subimages <= 0) return WPS_ERROR_INVALID_PARAM; - /* Check there is a terminating ) */ - while(isdigit(*ptr)) - ptr++; - if (*ptr != ')') - return WPS_ERROR_INVALID_PARAM; } - struct skin_token_list *item = new_skin_token_list_item(NULL, img); + struct skin_token_list *item = + (struct skin_token_list *)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); + return 0; } struct skin_font { int id; /* the id from font_load */ char *name; /* filename without path and extension */ }; static struct skin_font skinfonts[MAXUSERFONTS]; -static int parse_font_load(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data) +static int parse_font_load(struct skin_element *element, + struct wps_token *token, + struct wps_data *wps_data) { (void)wps_data; (void)token; - const char *ptr = wps_bufptr; - int id; - char *filename; - - if (*ptr != '(') - return WPS_ERROR_INVALID_PARAM; - - ptr++; - - if (!(ptr = parse_list("ds", NULL, ',', ptr, &id, &filename))) - return WPS_ERROR_INVALID_PARAM; - - /* Check there is a terminating ) */ - if (*ptr != ')') - return WPS_ERROR_INVALID_PARAM; - - if (id <= FONT_UI || id >= MAXFONTS-1) - return WPS_ERROR_INVALID_PARAM; + int id = element->params[0].data.number; + char *filename = element->params[1].data.text; + char *ptr; + #if defined(DEBUG) || defined(SIMULATOR) if (skinfonts[id-FONT_FIRSTUSERFONT].name != NULL) { @@ -782,286 +330,65 @@ static int parse_font_load(const char *wps_bufptr, /* make sure the filename contains .fnt, * we dont actually use it, but require it anyway */ ptr = strchr(filename, '.'); - if (!ptr || strncmp(ptr, ".fnt)", 5)) + if (!ptr || strncmp(ptr, ".fnt", 4)) return WPS_ERROR_INVALID_PARAM; skinfonts[id-FONT_FIRSTUSERFONT].id = -1; skinfonts[id-FONT_FIRSTUSERFONT].name = filename; - return skip_end_of_line(wps_bufptr); + return 0; } -static int parse_viewport_display(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)wps_data; - char letter = wps_bufptr[1]; - - if (letter < 'a' || letter > 'z') - { - /* invalid viewport tag */ - return WPS_ERROR_INVALID_PARAM; - } - token->value.i = letter; - return 3; -} - #ifdef HAVE_LCD_BITMAP -static 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 != ',' && *text != ')') - { - if (*text == '%') /* it is a token of some type */ - { - text++; - taglen = 0; - switch(*text) - { - case '%': - case '<': - case '|': - 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++][1] = '\0'; - text++; - 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] != ')' && 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 - { - if (tag->parse_func) - { - /* unsupported tag, reject */ - return -1; - } - 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] != ')' && 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) +static int parse_playlistview(struct skin_element *element, + 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) + struct playlistviewer *viewer = + (struct playlistviewer *)skin_buffer_alloc(sizeof(struct playlistviewer)); + if (!viewer) return WPS_ERROR_INVALID_PARAM; viewer->vp = &curr_vp->vp; viewer->show_icons = true; - viewer->start_offset = atoi(ptr+1); + viewer->start_offset = element->params[0].data.number; + viewer->lines[0] = element->params[1].data.code; + viewer->lines[1] = element->params[2].data.code; + 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); + + return 0; } #endif -static int parse_viewport(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)token; /* Kill warnings */ - const char *ptr = wps_bufptr; - - struct skin_viewport *skin_vp = skin_buffer_alloc(sizeof(struct skin_viewport)); - - /* check for the optional letter to signify its a hideable viewport */ - /* %Vl|<label>|<rest of tags>| */ - skin_vp->hidden_flags = 0; - skin_vp->label = VP_NO_LABEL; - skin_vp->lines = NULL; - if (curr_line) - { - curr_line->curr_subline->last_token_idx = wps_data->num_tokens - - (wps_data->num_tokens > 0 ? 1 : 0); - } - - curr_line = NULL; - if (!skin_start_new_line(skin_vp, wps_data->num_tokens)) - return WPS_ERROR_INVALID_PARAM; - - if (*ptr == 'i') - { - if (*(ptr+1) == '(') - { - char label = *(ptr+2); - if (label >= 'a' && label <= 'z') - { - skin_vp->hidden_flags = VP_NEVER_VISIBLE; - skin_vp->label = VP_INFO_LABEL|label; - ptr += 3; - } - else - { - if (label != '-') - return WPS_ERROR_INVALID_PARAM; - skin_vp->label = VP_INFO_LABEL|VP_DEFAULT_LABEL; - skin_vp->hidden_flags = VP_NEVER_VISIBLE; - ptr += 3; - } - } - else - return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */ - } - else if (*ptr == 'l') - { - if (*(ptr+1) == '(') - { - char label = *(ptr+2); - if (label >= 'a' && label <= 'z') - { - skin_vp->hidden_flags = VP_DRAW_HIDEABLE; - skin_vp->label = label; - } - else - return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */ - ptr += 3; - } - } - if (*ptr != ',' && *ptr != '(') - return WPS_ERROR_INVALID_PARAM; - - ptr++; - struct viewport *vp = &skin_vp->vp; - /* format: %V|x|y|width|height|font| */ - if (!(ptr = viewport_parse_viewport(vp, curr_screen, ptr, ','))) - return WPS_ERROR_INVALID_PARAM; - - /* Check for trailing ) */ - if (*ptr != ')') - return WPS_ERROR_INVALID_PARAM; - ptr++; - - if (follow_lang_direction && lang_is_rtl()) - { - vp->flags |= VP_FLAG_ALIGN_RIGHT; - vp->x = screens[curr_screen].lcdwidth - vp->width - vp->x; - } - else - vp->flags &= ~VP_FLAG_ALIGN_RIGHT; /* ignore right-to-left languages */ - #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) - skin_vp->start_fgcolour = vp->fg_pattern; - skin_vp->start_bgcolour = vp->bg_pattern; -#endif - struct skin_token_list *list = new_skin_token_list_item(NULL, skin_vp); - if (!list) - return WPS_ERROR_INVALID_PARAM; - add_to_ll_chain(&wps_data->viewports, list); - curr_vp = skin_vp; - /* Skip the rest of the line */ - return ptr-wps_bufptr; -} -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) -static int parse_viewportcolour(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data) +static int parse_viewportcolour(struct skin_element *element, + struct wps_token *token, + struct wps_data *wps_data) { (void)wps_data; - const char *ptr = wps_bufptr; - int i; - bool found_text; - struct viewport_colour *colour = skin_buffer_alloc(sizeof(struct viewport_colour)); - uint32_t set; - if (*ptr != '(' || !colour) - return -1; - ptr++; - if (!(ptr = parse_list("c", &set, ',', ptr, &colour->colour))) - return -1; - if (*ptr != ')') + struct skin_tag_parameter *param = element->params; + struct viewport_colour *colour = + (struct viewport_colour *)skin_buffer_alloc(sizeof(struct viewport_colour)); + if (!colour) return -1; - if (!set) + if (isdefault(param)) + { colour->colour = get_viewport_default_colour(curr_screen, - token->type == WPS_TOKEN_VIEWPORT_FGCOLOUR); - colour->vp = &curr_vp->vp; - token->value.data = colour; - /* If there havnt been any text tags between the %V() line and here use - * the colour as the viewport colour. fixes scrolling lines not - * having the correct colour */ - i = curr_vp->lines->sublines.first_token_idx; - found_text = false; - while (!found_text && i< curr_vp->lines->sublines.last_token_idx) + token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR); + } + else { - if (wps_data->tokens[i++].type != WPS_TOKEN_CHARACTER && - wps_data->tokens[i++].type != WPS_TOKEN_VIEWPORT_FGCOLOUR && - wps_data->tokens[i++].type != WPS_TOKEN_VIEWPORT_BGCOLOUR ) - found_text = true; + if (!parse_color(param->data.text, &colour->colour)) + return -1; } - if (!found_text) + colour->vp = &curr_vp->vp; + token->value.data = colour; + if (element->line == curr_viewport_element->line) { - if (token->type == WPS_TOKEN_VIEWPORT_FGCOLOUR) + if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR) { curr_vp->start_fgcolour = colour->colour; curr_vp->vp.fg_pattern = colour->colour; @@ -1072,72 +399,54 @@ static int parse_viewportcolour(const char *wps_bufptr, curr_vp->vp.bg_pattern = colour->colour; } } - ptr++; - return ptr - wps_bufptr; + return 0; } -static int parse_image_special(const char *wps_bufptr, +static int parse_image_special(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { (void)wps_data; /* kill warning */ (void)token; - const char *pos = NULL; - const char *newline; bool error = false; - pos = strchr(wps_bufptr + 1, ')'); - newline = strchr(wps_bufptr, '\n'); - - error = (pos > newline); - #if LCD_DEPTH > 1 - if (token->type == WPS_TOKEN_IMAGE_BACKDROP) + if (token->type == SKIN_TOKEN_IMAGE_BACKDROP) { + char *filename = element->params[0].data.text; /* format: %X|filename.bmp| or %Xd */ - if (!strncmp(wps_bufptr, "(d)", 3)) + if (!strcmp(filename, "d")) { wps_data->backdrop = NULL; - return skip_end_of_line(wps_bufptr); + return 0; } else if (!error) - wps_data->backdrop = (char*)wps_bufptr + 1; + { + wps_data->backdrop = filename; + } } #endif - if (error) - return WPS_ERROR_INVALID_PARAM; /* Skip the rest of the line */ - return skip_end_of_line(wps_bufptr); + return error ? WPS_ERROR_INVALID_PARAM : 0; } #endif #endif /* HAVE_LCD_BITMAP */ -static int parse_setting_and_lang(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) +static int parse_setting_and_lang(struct skin_element *element, + struct wps_token *token, + struct wps_data *wps_data) { /* NOTE: both the string validations that happen in here will * automatically PASS on checkwps because its too hard to get - * settings_list.c and englinsh.lang built for it. + * settings_list.c and english.lang built for it. * If that ever changes remove the #ifndef __PCTOOL__'s here */ (void)wps_data; - const char *ptr = wps_bufptr; - const char *end; - int i = 0; - char temp[64]; - - /* Find the setting's cfg_name */ - if (*ptr != '(') - return WPS_ERROR_INVALID_PARAM; - ptr++; - end = strchr(ptr,')'); - if (!end || (size_t)(end-ptr+1) > sizeof temp) - return WPS_ERROR_INVALID_PARAM; - strlcpy(temp, ptr,end-ptr+1); + char *temp = element->params[0].data.text; + int i; - if (token->type == WPS_TOKEN_TRANSLATEDSTRING) + if (token->type == SKIN_TOKEN_TRANSLATEDSTRING) { #ifndef __PCTOOL__ i = lang_english_to_id(temp); @@ -1159,170 +468,104 @@ static int parse_setting_and_lang(const char *wps_bufptr, } /* Store the setting number */ token->value.i = i; - - /* Skip the rest of the line */ - return end-ptr+2; -} - - -static int parse_dir_level(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - char val[] = { wps_bufptr[1], '\0' }; - if (wps_bufptr[0] != '(' || wps_bufptr[2] != ')') - return WPS_ERROR_INVALID_PARAM; - token->value.i = atoi(val); - (void)wps_data; /* Kill warnings */ - return 3; + return 0; } -static int parse_timeout(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) +static int parse_timeout_tag(struct skin_element *element, + struct wps_token *token, + struct wps_data *wps_data) { - int skip = 0; + (void)wps_data; int val = 0; - bool have_point = false; - bool have_tenth = false; - - (void)wps_data; /* Kill the warning */ - if (*wps_bufptr == '(') - { - wps_bufptr++; - skip++; - while ( isdigit(*wps_bufptr) || *wps_bufptr == '.' ) - { - if (*wps_bufptr != '.') - { - val *= 10; - val += *wps_bufptr - '0'; - if (have_point) - { - have_tenth = true; - wps_bufptr++; - skip++; - break; - } - } - else - have_point = true; - - wps_bufptr++; - skip++; - } - if (*wps_bufptr != ')') - return -1; - skip++; - } - if (have_tenth == false) - val *= 10; - - if (val == 0 && skip == 0) + if (element->params_count == 0) { - /* decide what to do if no value was specified */ switch (token->type) { - case WPS_TOKEN_SUBLINE_TIMEOUT: + case SKIN_TOKEN_SUBLINE_TIMEOUT: return -1; - case WPS_TOKEN_BUTTON_VOLUME: - case WPS_TOKEN_TRACK_STARTING: - case WPS_TOKEN_TRACK_ENDING: + case SKIN_TOKEN_BUTTON_VOLUME: + case SKIN_TOKEN_TRACK_STARTING: + case SKIN_TOKEN_TRACK_ENDING: + case SKIN_TOKEN_LASTTOUCH: val = 10; break; + default: + break; } } + else + val = element->params[0].data.number; token->value.i = val; - - return skip; + if (token->type == SKIN_TOKEN_SUBLINE_TIMEOUT) + curr_line->timeout = val * TIMEOUT_UNIT; + return 0; } -static int parse_progressbar(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) +static int parse_progressbar_tag(struct skin_element* element, + struct wps_token *token, + struct wps_data *wps_data) { - /* %pb or %pb|filename|x|y|width|height| - using - for any of the params uses "sane" values */ #ifdef HAVE_LCD_BITMAP - enum { - PB_X = 0, - PB_Y, - PB_WIDTH, - PB_HEIGHT, - PB_FILENAME, - }; - const char *filename; - int x, y, height, width; - uint32_t set = 0; - const char *ptr = wps_bufptr; - 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 progressbar *pb; + struct skin_token_list *item; struct viewport *vp = &curr_vp->vp; - /* we need to know what line number (viewport relative) this pb is, - * so count them... */ - int line_num = -1; - struct skin_line *line = curr_vp->lines; - while (line) - { - line_num++; - line = line->next; - } - if (curr_vp->label != VP_DEFAULT_LABEL) - line_num--; + struct skin_tag_parameter *param = element->params; + + if (element->params_count == 0 && + element->tag->type != SKIN_TOKEN_PROGRESSBAR) + return 0; /* nothing to do */ + pb = (struct progressbar*)skin_buffer_alloc(sizeof(struct progressbar)); + + token->value.data = pb; + + if (!pb) + return WPS_ERROR_INVALID_PARAM; pb->vp = vp; pb->have_bitmap_pb = false; pb->bm.data = NULL; /* no bitmap specified */ pb->follow_lang_direction = follow_lang_direction > 0; - pb->draw = false; - - if (*wps_bufptr != '(') /* regular old style */ + + if (element->params_count == 0) { pb->x = 0; pb->width = vp->width; pb->height = SYSFONT_HEIGHT-2; - pb->y = -line_num - 1; /* Will be computed during the rendering */ - if (token->type == WPS_TOKEN_VOLUME || token->type == WPS_TOKEN_BATTERY_PERCENT) - return 0; /* dont add it, let the regular token handling do the work */ - pb->type = token->type; - add_to_ll_chain(&wps_data->progressbars, item); + pb->y = -1; /* Will be computed during the rendering */ + pb->type = element->tag->type; return 0; } - ptr = wps_bufptr + 1; - - if (!(ptr = parse_list("dddds", &set, ',', ptr, - &x, &y, &width, &height, &filename))) - return WPS_ERROR_INVALID_PARAM; - - if (LIST_VALUE_PARSED(set, PB_FILENAME)) /* filename */ - pb->bm.data = (char*)filename; - - if (LIST_VALUE_PARSED(set, PB_X)) /* x */ - pb->x = x; + + item = new_skin_token_list_item(token, pb); + if (!item) + return -1; + add_to_ll_chain(&wps_data->progressbars, item); + + /* (x,y,width,height,filename) */ + if (!isdefault(param)) + pb->x = param->data.number; else pb->x = vp->x; - - if (LIST_VALUE_PARSED(set, PB_WIDTH)) /* width */ - { - /* A zero width causes a divide-by-zero error later, so reject it */ - if (width == 0) - return WPS_ERROR_INVALID_PARAM; - - pb->width = width; - } + param++; + + if (!isdefault(param)) + pb->y = param->data.number; + else + pb->y = -1; /* computed at rendering */ + param++; + + if (!isdefault(param)) + pb->width = param->data.number; else pb->width = vp->width - pb->x; - - if (LIST_VALUE_PARSED(set, PB_HEIGHT)) /* height, default to font height */ + param++; + + if (!isdefault(param)) { /* A zero height makes no sense - reject it */ - if (height == 0) + if (param->data.number == 0) return WPS_ERROR_INVALID_PARAM; - pb->height = height; + pb->height = param->data.number; } else { @@ -1337,30 +580,26 @@ static int parse_progressbar(const char *wps_bufptr, #endif } } - - if (LIST_VALUE_PARSED(set, PB_Y)) /* y */ - pb->y = y; - else - pb->y = -line_num - 1; /* Will be computed during the rendering */ - - if (*ptr != ')') - return WPS_ERROR_INVALID_PARAM; - - add_to_ll_chain(&wps_data->progressbars, item); - if (token->type == WPS_TOKEN_VOLUME) - token->type = WPS_TOKEN_VOLUMEBAR; - else if (token->type == WPS_TOKEN_BATTERY_PERCENT) - token->type = WPS_TOKEN_BATTERY_PERCENTBAR; + param++; + if (!isdefault(param)) + pb->bm.data = param->data.text; + + + if (token->type == SKIN_TOKEN_VOLUME) + token->type = SKIN_TOKEN_VOLUMEBAR; + else if (token->type == SKIN_TOKEN_BATTERY_PERCENT) + token->type = SKIN_TOKEN_BATTERY_PERCENTBAR; pb->type = token->type; - - return ptr+1-wps_bufptr; + + return 0; + #else - (void)wps_bufptr; - if (token->type != WPS_TOKEN_VOLUME && - token->type != WPS_TOKEN_BATTERY_PERCENTBAR) + (void)element; + if (token->type == SKIN_TOKEN_PROGRESSBAR || + token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR) { wps_data->full_line_progressbar = - token->type == WPS_TOKEN_PLAYER_PROGRESSBAR; + token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR; } return 0; @@ -1368,32 +607,32 @@ static int parse_progressbar(const char *wps_bufptr, } #ifdef HAVE_ALBUMART -static int parse_albumart_load(const char *wps_bufptr, +static int parse_albumart_load(struct skin_element* element, struct wps_token *token, struct wps_data *wps_data) { - const char *ptr = wps_bufptr; struct dim dimensions; int albumart_slot; bool swap_for_rtl = lang_is_rtl() && follow_lang_direction; - struct skin_albumart *aa = skin_buffer_alloc(sizeof(struct skin_albumart)); + struct skin_albumart *aa = + (struct skin_albumart *)skin_buffer_alloc(sizeof(struct skin_albumart)); (void)token; /* silence warning */ if (!aa) - return skip_end_of_line(wps_bufptr); + return -1; /* reset albumart info in wps */ aa->width = -1; aa->height = -1; aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ - aa->vp = &curr_vp->vp; - if (*ptr != '(') - return WPS_ERROR_INVALID_PARAM; - ptr++; - /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */ - if (!(ptr = parse_list("dddd", NULL,',',ptr, &aa->x, &aa->y, &aa->width, &aa->height))) - return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */ + aa->x = element->params[0].data.number; + aa->y = element->params[1].data.number; + aa->width = element->params[2].data.number; + aa->height = element->params[3].data.number; + + aa->vp = &curr_vp->vp; + aa->draw_handle = -1; /* if we got here, we parsed everything ok .. ! */ if (aa->width < 0) @@ -1410,7 +649,6 @@ static int parse_albumart_load(const char *wps_bufptr, aa->x = LCD_WIDTH - (aa->x + aa->width); aa->state = WPS_ALBUMART_LOAD; - aa->draw = false; wps_data->albumart = aa; dimensions.width = aa->width; @@ -1420,11 +658,10 @@ static int parse_albumart_load(const char *wps_bufptr, if (0 <= albumart_slot) wps_data->playback_aa_slot = albumart_slot; - - if (*ptr == ',') + + if (element->params_count > 4 && !isdefault(&element->params[4])) { - ptr++; - switch (*ptr) + switch (*element->params[4].data.text) { case 'l': case 'L': @@ -1445,12 +682,10 @@ static int parse_albumart_load(const char *wps_bufptr, aa->xalign = WPS_ALBUMART_ALIGN_RIGHT; break; } - ptr++; } - if (*ptr == ',') + if (element->params_count > 5 && !isdefault(&element->params[5])) { - ptr++; - switch (*ptr) + switch (*element->params[5].data.text) { case 't': case 'T': @@ -1465,32 +700,10 @@ static int parse_albumart_load(const char *wps_bufptr, aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM; break; } - ptr++; } - if (*ptr != ')') - return WPS_ERROR_INVALID_PARAM; - - return skip_end_of_line(wps_bufptr); + return 0; } -static int parse_albumart_display(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)wps_bufptr; - (void)token; - if (wps_data->albumart) - { - wps_data->albumart->vp = &curr_vp->vp; - } -#if 0 - /* the old code did this so keep it here for now... - * this is to allow the posibility to showing the next tracks AA! */ - if (wps_bufptr+1 == 'n') - return 1; -#endif - return 0; -}; #endif /* HAVE_ALBUMART */ #ifdef HAVE_TOUCHSCREEN @@ -1520,8 +733,9 @@ static const struct touchaction touchactions[] = { #endif }; -static int parse_touchregion(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data) +static int parse_touchregion(struct skin_element *element, + struct wps_token *token, + struct wps_data *wps_data) { (void)token; unsigned i, imax; @@ -1533,7 +747,7 @@ static int parse_touchregion(const char *wps_bufptr, int x,y,w,h; char temp[20]; - /* format: %T|x|y|width|height|action| + /* format: %T(x,y,width,height,action) * if action starts with & the area must be held to happen * action is one of: * play - play/pause playback @@ -1554,35 +768,22 @@ static int parse_touchregion(const char *wps_bufptr, * voldown - decrease volume by one step */ - - if (*ptr != '(') - return WPS_ERROR_INVALID_PARAM; - ptr++; - - if (!(ptr = parse_list("dddds", NULL, ',', ptr, &x, &y, &w, &h, &action))) - return WPS_ERROR_INVALID_PARAM; - - /* Check there is a terminating ) */ - if (*ptr != ')') - return WPS_ERROR_INVALID_PARAM; - - region = skin_buffer_alloc(sizeof(struct touchregion)); + + region = (struct touchregion*)skin_buffer_alloc(sizeof(struct touchregion)); if (!region) return WPS_ERROR_INVALID_PARAM; /* should probably do some bounds checking here with the viewport... but later */ region->action = ACTION_NONE; - region->x = x; - region->y = y; - region->width = w; - region->height = h; + region->x = element->params[0].data.number; + region->y = element->params[1].data.number; + region->width = element->params[2].data.number; + region->height = element->params[3].data.number; region->wvp = curr_vp; region->armed = false; region->reverse_bar = false; + action = element->params[4].data.text; - end = strchr(action, ')'); - if (!end || (size_t)(end-action+1) > sizeof temp) - return WPS_ERROR_INVALID_PARAM; strlcpy(temp, action, end-action+1); action = temp; @@ -1625,449 +826,46 @@ static int parse_touchregion(const char *wps_bufptr, if (!item) return WPS_ERROR_INVALID_PARAM; add_to_ll_chain(&wps_data->touchregions, item); - return skip_end_of_line(wps_bufptr); + return 0; } #endif -/* Parse a generic token from the given string. Return the length read */ -static int parse_token(const char *wps_bufptr, struct wps_data *wps_data) +static bool check_feature_tag(const int type) { - int skip = 0, taglen = 0, ret; - struct wps_token *token = wps_data->tokens + wps_data->num_tokens; - const struct wps_tag *tag; - memset(token, 0, sizeof(*token)); - - switch(*wps_bufptr) - { - - case '%': - case '<': - case '|': - case '>': - case ';': - case '#': - case ')': - case '(': - case ',': - /* escaped characters */ - token->type = WPS_TOKEN_CHARACTER; - token->value.c = *wps_bufptr; - taglen = 1; - wps_data->num_tokens++; - break; - - case '?': - /* conditional tag */ - token->type = WPS_TOKEN_CONDITIONAL; - level++; - condindex[level] = wps_data->num_tokens; - numoptions[level] = 1; - wps_data->num_tokens++; - ret = parse_token(wps_bufptr + 1, wps_data); - if (ret < 0) return ret; - taglen = 1 + ret; - break; - - default: - /* find what tag we have */ - for (tag = all_tags; - strncmp(wps_bufptr, tag->name, strlen(tag->name)) != 0; - tag++) ; - - taglen = (tag->type != WPS_TOKEN_UNKNOWN) ? strlen(tag->name) : 2; - token->type = tag->type; - curr_line->curr_subline->line_type |= tag->refresh_type; - - /* if the tag has a special parsing function, we call it */ - if (tag->parse_func) - { - ret = tag->parse_func(wps_bufptr + taglen, token, wps_data); - if (ret < 0) return ret; - skip += ret; - } - - /* Some tags we don't want to save as tokens */ - if (tag->type == WPS_NO_TOKEN) - break; - - /* tags that start with 'F', 'I' or 'D' are for the next file */ - if ( *(tag->name) == 'I' || *(tag->name) == 'F' || - *(tag->name) == 'D') - token->next = true; - - wps_data->num_tokens++; - break; - } - - skip += taglen; - return skip; -} - - -/* - * Returns the number of bytes to skip the buf pointer to access the false - * branch in a _binary_ conditional - * - * That is: - * - before the '|' if we have a false branch, (%?<true|false> -> %?<|false>) - * - or before the closing '>' if there's no false branch (%?<true> -> %?<>) - * - * depending on the features of a target it's not called from check_feature_tag, - * hence the __attribute__ or it issues compiler warnings - * - **/ - -static int find_false_branch(const char *wps_bufptr) __attribute__((unused)); -static int find_false_branch(const char *wps_bufptr) -{ - const char *buf = wps_bufptr; - /* wps_bufptr is after the opening '<', hence level = 1*/ - int level = 1; - char ch; - do - { - ch = *buf; - if (ch == '%') - { /* filter out the characters we check later if they're printed - * as literals */ - ch = *(++buf); - if (ch == '<' || ch == '>' || ch == '|') - continue; - /* else: some tags/printed literals we skip over */ - } - else if (ch == '<') /* nested conditional */ - level++; - else if (ch == '>') - { /* closed our or a nested conditional, - * do NOT skip over the '>' so that wps_parse() sees it for closing - * if it is the closing one for our conditional */ - level--; - } - else if (ch == '|' && level == 1) - { /* we found our separator, point before and get out */ - break; - } - /* if level is 0, we don't have a false branch */ - } while (level > 0 && *(++buf)); - - return buf - wps_bufptr; -} - -/* - * returns the number of bytes to get the appropriate branch of a binary - * conditional - * - * That means: - * - if a feature is available, it returns 0 to not skip anything - * - if the feature is not available, skip to the false branch and don't - * parse the true branch at all - * - * */ -static int check_feature_tag(const char *wps_bufptr, const int type) -{ - (void)wps_bufptr; switch (type) { - case WPS_TOKEN_RTC_PRESENT: + case SKIN_TOKEN_RTC_PRESENT: #if CONFIG_RTC - return 0; + return true; #else - return find_false_branch(wps_bufptr); -#endif /* CONFIG_RTC */ - - case WPS_TOKEN_HAVE_RECORDING: + return false; +#endif + case SKIN_TOKEN_HAVE_RECORDING: #ifdef HAVE_RECORDING - return 0; + return true; #else - return find_false_branch(wps_bufptr); -#endif /* HAVE_RECORDING */ - - case WPS_TOKEN_HAVE_TUNER: + return false; +#endif + case SKIN_TOKEN_HAVE_TUNER: #if CONFIG_TUNER if (radio_hardware_present()) - return 0; -#endif /* CONFIG_TUNER */ - return find_false_branch(wps_bufptr); + return true; +#endif + return false; #if CONFIG_TUNER - case WPS_TOKEN_HAVE_RDS: + case SKIN_TOKEN_HAVE_RDS: #ifdef HAVE_RDS_CAP - return 0; + return true; #else - return find_false_branch(wps_bufptr); + return false; #endif /* HAVE_RDS_CAP */ #endif /* CONFIG_TUNER */ default: /* not a tag we care about, just don't skip */ - return 0; - } -} - - -/* Parses the WPS. - data is the pointer to the structure where the parsed WPS should be stored. - It is initialised. - wps_bufptr points to the string containing the WPS tags */ -#define TOKEN_BLOCK_SIZE 128 -static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug) -{ - if (!data || !wps_bufptr || !*wps_bufptr) - return false; - enum wps_parse_error fail = PARSE_OK; - int ret; - int max_tokens = TOKEN_BLOCK_SIZE; - size_t buf_free = 0; - line_number = 0; - level = -1; - - /* allocate enough RAM for a reasonable skin, grow as needed. - * Free any used RAM before loading the images to be 100% RAM efficient */ - data->tokens = (struct wps_token *)skin_buffer_grab(&buf_free); - if (sizeof(struct wps_token)*max_tokens >= buf_free) - return false; - skin_buffer_increment(max_tokens * sizeof(struct wps_token), false); - data->num_tokens = 0; - -#if LCD_DEPTH > 1 - /* Backdrop defaults to the setting unless %X is used, so set it now */ - if (global_settings.backdrop_file[0]) - { - data->backdrop = "-"; - } -#endif - - while (*wps_bufptr && !fail) - { - if (follow_lang_direction) - follow_lang_direction--; - /* first make sure there is enough room for tokens */ - if (max_tokens <= data->num_tokens + 5) - { - int extra_tokens = TOKEN_BLOCK_SIZE; - size_t needed = extra_tokens * sizeof(struct wps_token); - /* do some smarts here to grow the array a bit */ - if (skin_buffer_freespace() < needed) - { - fail = PARSE_FAIL_LIMITS_EXCEEDED; - break; - } - skin_buffer_increment(needed, false); - max_tokens += extra_tokens; - } - - switch(*wps_bufptr++) - { - - /* Regular tag */ - case '%': - if ((ret = parse_token(wps_bufptr, data)) < 0) - { - fail = PARSE_FAIL_COND_INVALID_PARAM; - break; - } - else if (level >= WPS_MAX_COND_LEVEL - 1) - { - fail = PARSE_FAIL_LIMITS_EXCEEDED; - break; - } - wps_bufptr += ret; - break; - - /* Alternating sublines separator */ - case ';': - if (level >= 0) /* there are unclosed conditionals */ - { - fail = PARSE_FAIL_UNCLOSED_COND; - break; - } - - if (!skin_start_new_subline(curr_line, data->num_tokens)) - fail = PARSE_FAIL_LIMITS_EXCEEDED; - - break; - - /* Conditional list start */ - case '<': - if (data->tokens[data->num_tokens-2].type != WPS_TOKEN_CONDITIONAL) - { - fail = PARSE_FAIL_COND_SYNTAX_ERROR; - break; - } - wps_bufptr += check_feature_tag(wps_bufptr, - data->tokens[data->num_tokens-1].type); - data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_START; - lastcond[level] = data->num_tokens++; - break; - - /* Conditional list end */ - case '>': - if (level < 0) /* not in a conditional, invalid char */ - { - fail = PARSE_FAIL_INVALID_CHAR; - break; - } - - data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_END; - if (lastcond[level]) - data->tokens[lastcond[level]].value.i = data->num_tokens; - else - { - fail = PARSE_FAIL_COND_SYNTAX_ERROR; - break; - } - - lastcond[level] = 0; - data->num_tokens++; - data->tokens[condindex[level]].value.i = numoptions[level]; - level--; - break; - - /* Conditional list option */ - case '|': - if (level < 0) /* not in a conditional, invalid char */ - { - fail = PARSE_FAIL_INVALID_CHAR; - break; - } - - data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_OPTION; - if (lastcond[level]) - data->tokens[lastcond[level]].value.i = data->num_tokens; - else - { - fail = PARSE_FAIL_COND_SYNTAX_ERROR; - break; - } - - lastcond[level] = data->num_tokens; - numoptions[level]++; - data->num_tokens++; - break; - - /* Comment */ - case '#': - if (level >= 0) /* there are unclosed conditionals */ - { - fail = PARSE_FAIL_UNCLOSED_COND; - break; - } - - wps_bufptr += skip_end_of_line(wps_bufptr); - break; - - /* End of this line */ - case '\n': - if (level >= 0) /* there are unclosed conditionals */ - { - fail = PARSE_FAIL_UNCLOSED_COND; - break; - } - /* add a new token for the \n so empty lines are correct */ - data->tokens[data->num_tokens].type = WPS_TOKEN_CHARACTER; - data->tokens[data->num_tokens].value.c = '\n'; - data->tokens[data->num_tokens].next = false; - data->num_tokens++; - - if (!skin_start_new_line(curr_vp, data->num_tokens)) - { - fail = PARSE_FAIL_LIMITS_EXCEEDED; - break; - } - line_number++; - - break; - - /* String */ - default: - { - unsigned int len = 1; - const char *string_start = wps_bufptr - 1; - - /* find the length of the string */ - while (*wps_bufptr && *wps_bufptr != '#' && - *wps_bufptr != '%' && *wps_bufptr != ';' && - *wps_bufptr != '<' && *wps_bufptr != '>' && - *wps_bufptr != '|' && *wps_bufptr != '\n') - { - wps_bufptr++; - len++; - } - - /* look if we already have that string */ - 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 */ - str = (char*)skin_buffer_alloc(len+1); - if (!str) - { - fail = PARSE_FAIL_LIMITS_EXCEEDED; - break; - } - 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.data = list->token->value.data; - } - data->tokens[data->num_tokens].type = WPS_TOKEN_STRING; - data->num_tokens++; - } - break; - } - } - - if (!fail && level >= 0) /* there are unclosed conditionals */ - fail = PARSE_FAIL_UNCLOSED_COND; - - if (*wps_bufptr && !fail) - /* one of the limits of the while loop was exceeded */ - fail = PARSE_FAIL_LIMITS_EXCEEDED; - - /* Success! */ - curr_line->curr_subline->last_token_idx = data->num_tokens; - data->tokens[data->num_tokens++].type = WPS_NO_TOKEN; - /* freeup unused tokens */ - skin_buffer_free_from_front(sizeof(struct wps_token) - * (max_tokens - data->num_tokens)); - -#ifdef DEBUG_SKIN_ENGINE - if (debug) - { - print_debug_info(data, fail, line_number); - debug_skin_usage(); + return true; } -#else - (void)debug; -#endif - - return (fail == 0); } - /* * initial setup of wps_data; does reset everything * except fields which need to survive, i.e. @@ -2075,6 +873,7 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug) **/ static void skin_data_reset(struct wps_data *wps_data) { + wps_data->tree = NULL; #ifdef HAVE_LCD_BITMAP wps_data->images = NULL; wps_data->progressbars = NULL; @@ -2085,8 +884,6 @@ static void skin_data_reset(struct wps_data *wps_data) #ifdef HAVE_TOUCHSCREEN wps_data->touchregions = NULL; #endif - wps_data->viewports = NULL; - wps_data->strings = NULL; #ifdef HAVE_ALBUMART wps_data->albumart = NULL; if (wps_data->playback_aa_slot >= 0) @@ -2095,8 +892,6 @@ static void skin_data_reset(struct wps_data *wps_data) wps_data->playback_aa_slot = -1; } #endif - wps_data->tokens = NULL; - wps_data->num_tokens = 0; #ifdef HAVE_LCD_BITMAP wps_data->peak_meter_enabled = false; @@ -2119,6 +914,7 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char { (void)wps_data; /* only needed for remote targets */ char img_path[MAX_PATH]; + int fd; get_image_filename(bitmap->data, bmpdir, img_path, sizeof(img_path)); @@ -2131,14 +927,24 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char #endif format = FORMAT_ANY|FORMAT_TRANSPARENT; - size_t max_buf; - char* imgbuf = (char*)skin_buffer_grab(&max_buf); + fd = open(img_path, O_RDONLY); + if (fd < 0) + return false; + size_t buf_size = read_bmp_file(img_path, bitmap, 0, + format|FORMAT_RETURN_SIZE, NULL); + char* imgbuf = (char*)skin_buffer_alloc(buf_size); + if (!imgbuf) + { + close(fd); + return NULL; + } + lseek(fd, 0, SEEK_SET); bitmap->data = imgbuf; - int ret = read_bmp_file(img_path, bitmap, max_buf, format, NULL); + int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL); + close(fd); if (ret > 0) { - skin_buffer_increment(ret, true); return true; } else @@ -2204,14 +1010,14 @@ static bool skin_load_fonts(struct wps_data *data) { /* don't spit out after the first failue to aid debugging */ bool success = true; - struct skin_token_list *vp_list; + struct skin_element *vp_list; int font_id; /* walk though each viewport and assign its font */ - for(vp_list = data->viewports; vp_list; vp_list = vp_list->next) + for(vp_list = data->tree; vp_list; vp_list = vp_list->next) { /* first, find the viewports that have a non-sys/ui-font font */ struct skin_viewport *skin_vp = - (struct skin_viewport*)vp_list->token->value.data; + (struct skin_viewport*)vp_list->data; struct viewport *vp = &skin_vp->vp; @@ -2250,6 +1056,7 @@ static bool skin_load_fonts(struct wps_data *data) { DEBUGF("Unable to load font %d: '%s.fnt'\n", font_id, font->name); + font->name = NULL; /* to stop trying to load it again if we fail */ success = false; font->name = NULL; continue; @@ -2262,6 +1069,277 @@ static bool skin_load_fonts(struct wps_data *data) } #endif /* HAVE_LCD_BITMAP */ +static int convert_viewport(struct wps_data *data, struct skin_element* element) +{ + struct skin_viewport *skin_vp = + (struct skin_viewport *)skin_buffer_alloc(sizeof(struct skin_viewport)); + struct screen *display = &screens[curr_screen]; + + if (!skin_vp) + return CALLBACK_ERROR; + + skin_vp->hidden_flags = 0; + skin_vp->label = VP_NO_LABEL; + element->data = skin_vp; + curr_vp = skin_vp; + curr_viewport_element = element; + + viewport_set_defaults(&skin_vp->vp, curr_screen); + +#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) + skin_vp->start_fgcolour = skin_vp->vp.fg_pattern; + skin_vp->start_bgcolour = skin_vp->vp.bg_pattern; +#endif + + + struct skin_tag_parameter *param = element->params; + if (element->params_count == 0) /* default viewport */ + { + if (!data->tree) /* first viewport in the skin */ + data->tree = element; + skin_vp->label = VP_DEFAULT_LABEL; + return CALLBACK_OK; + } + + if (element->params_count == 6) + { + if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD) + { + if (isdefault(param)) + { + skin_vp->hidden_flags = VP_NEVER_VISIBLE; + skin_vp->label = VP_INFO_LABEL|VP_DEFAULT_LABEL; + } + else + { + skin_vp->hidden_flags = VP_NEVER_VISIBLE; + skin_vp->label = VP_INFO_LABEL|param->data.text[0]; + } + } + else + { + skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN; + skin_vp->label = param->data.text[0]; + } + param++; + } + /* x */ + if (!isdefault(param)) + { + skin_vp->vp.x = param->data.number; + if (param->data.number < 0) + skin_vp->vp.x += display->lcdwidth; + } + param++; + /* y */ + if (!isdefault(param)) + { + skin_vp->vp.y = param->data.number; + if (param->data.number < 0) + skin_vp->vp.y += display->lcdheight; + } + param++; + /* width */ + if (!isdefault(param)) + { + skin_vp->vp.width = param->data.number; + if (param->data.number < 0) + skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x; + } + else + { + skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x; + } + param++; + /* height */ + if (!isdefault(param)) + { + skin_vp->vp.height = param->data.number; + if (param->data.number < 0) + skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y; + } + else + { + skin_vp->vp.height = display->lcdheight - skin_vp->vp.y; + } + param++; +#ifdef HAVE_LCD_BITMAP + /* font */ + if (!isdefault(param)) + { + skin_vp->vp.font = param->data.number; + } +#endif + + return CALLBACK_OK; + +} + +int skin_element_callback(struct skin_element* element, void* data) +{ + struct wps_data *wps_data = (struct wps_data *)data; + struct wps_token *token; + parse_function function = NULL; + + switch (element->type) + { + /* IMPORTANT: element params are shared, so copy them if needed + * or use then NOW, dont presume they have a long lifespan + */ + case TAG: + { + token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token)); + memset(token, 0, sizeof(*token)); + token->type = element->tag->type; + + if ((element->tag->flags&SKIN_REFRESH_ALL) == SKIN_RTC_REFRESH) + { +#ifdef CONFIG_RTC + curr_line->update_mode |= SKIN_REFRESH_DYNAMIC; +#else + curr_line->update_mode |= SKIN_REFRESH_STATIC; +#endif + } + else + curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL; + + element->data = token; + + /* Some tags need special handling for the tag, so add them here */ + switch (token->type) + { + case SKIN_TOKEN_ALIGN_LANGDIRECTION: + follow_lang_direction = 2; + break; + case SKIN_TOKEN_PROGRESSBAR: + case SKIN_TOKEN_VOLUME: + case SKIN_TOKEN_BATTERY_PERCENT: + case SKIN_TOKEN_PLAYER_PROGRESSBAR: + function = parse_progressbar_tag; + break; + case SKIN_TOKEN_SUBLINE_TIMEOUT: + case SKIN_TOKEN_BUTTON_VOLUME: + case SKIN_TOKEN_TRACK_STARTING: + case SKIN_TOKEN_TRACK_ENDING: + case SKIN_TOKEN_LASTTOUCH: + function = parse_timeout_tag; + break; +#ifdef HAVE_LCD_BITMAP + case SKIN_TOKEN_DISABLE_THEME: + case SKIN_TOKEN_ENABLE_THEME: + case SKIN_TOKEN_DRAW_INBUILTBAR: + function = parse_statusbar_tags; + break; +#endif + case SKIN_TOKEN_FILE_DIRECTORY: + token->value.i = element->params[0].data.number; + break; +#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) + case SKIN_TOKEN_VIEWPORT_FGCOLOUR: + case SKIN_TOKEN_VIEWPORT_BGCOLOUR: + function = parse_viewportcolour; + break; + case SKIN_TOKEN_IMAGE_BACKDROP: + function = parse_image_special; + break; +#endif + case SKIN_TOKEN_TRANSLATEDSTRING: + case SKIN_TOKEN_SETTING: + function = parse_setting_and_lang; + break; +#ifdef HAVE_LCD_BITMAP + case SKIN_TOKEN_VIEWPORT_CUSTOMLIST: + function = parse_playlistview; + break; + case SKIN_TOKEN_LOAD_FONT: + function = parse_font_load; + break; + case SKIN_TOKEN_VIEWPORT_ENABLE: + case SKIN_TOKEN_UIVIEWPORT_ENABLE: + token->value.i = element->params[0].data.text[0]; + break; + case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: + function = parse_image_display; + break; + case SKIN_TOKEN_IMAGE_PRELOAD: + case SKIN_TOKEN_IMAGE_DISPLAY: + function = parse_image_load; + break; +#endif +#ifdef HAVE_TOUCHSCREEN + case SKIN_TOKEN_TOUCHREGION: + function = parse_touchregion; + break; +#endif +#ifdef HAVE_ALBUMART + case SKIN_TOKEN_ALBUMART_DISPLAY: + if (wps_data->albumart) + wps_data->albumart->vp = &curr_vp->vp; + break; + case SKIN_TOKEN_ALBUMART_LOAD: + function = parse_albumart_load; + break; +#endif + default: + break; + } + if (function) + { + if (function(element, token, wps_data) < 0) + return CALLBACK_ERROR; + } + /* tags that start with 'F', 'I' or 'D' are for the next file */ + if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' || + *(element->tag->name) == 'D') + token->next = true; + if (follow_lang_direction > 0 ) + follow_lang_direction--; + break; + } + case VIEWPORT: + return convert_viewport(wps_data, element); + case LINE: + { + struct line *line = + (struct line *)skin_buffer_alloc(sizeof(struct line)); + line->update_mode = SKIN_REFRESH_STATIC; + line->timeout = DEFAULT_SUBLINE_TIME_MULTIPLIER * TIMEOUT_UNIT; + curr_line = line; + element->data = line; + } + break; + case LINE_ALTERNATOR: + { + struct line_alternator *alternator = + (struct line_alternator *)skin_buffer_alloc(sizeof(struct line_alternator)); + alternator->current_line = 0; +#ifndef __PCTOOL__ + alternator->last_change_tick = current_tick; +#endif + element->data = alternator; + } + break; + case CONDITIONAL: + { + struct conditional *conditional = + (struct conditional *)skin_buffer_alloc(sizeof(struct conditional)); + conditional->last_value = -1; + conditional->token = element->data; + element->data = conditional; + if (!check_feature_tag(element->tag->type)) + { + return FEATURE_NOT_AVAILABLE; + } + return CALLBACK_OK; + } + case TEXT: + curr_line->update_mode |= SKIN_REFRESH_STATIC; + break; + default: + break; + } + return CALLBACK_OK; +} /* to setup up the wps-data from a format-buffer (isfile = false) from a (wps-)file (isfile = true)*/ @@ -2298,37 +1376,13 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data, } #endif + skin_data_reset(wps_data); wps_data->wps_loaded = false; curr_screen = screen; - - /* alloc default viewport, will be fixed up later */ - curr_vp = skin_buffer_alloc(sizeof(struct skin_viewport)); - if (!curr_vp) - return false; - struct skin_token_list *list = new_skin_token_list_item(NULL, curr_vp); - if (!list) - return false; - add_to_ll_chain(&wps_data->viewports, list); - - - /* Initialise the first (default) viewport */ - curr_vp->label = VP_DEFAULT_LABEL; - curr_vp->hidden_flags = 0; - curr_vp->lines = NULL; - - viewport_set_defaults(&curr_vp->vp, screen); -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) - curr_vp->start_fgcolour = curr_vp->vp.fg_pattern; - curr_vp->start_bgcolour = curr_vp->vp.bg_pattern; -#endif -#ifdef HAVE_LCD_BITMAP - curr_vp->vp.font = FONT_UI; -#endif - curr_line = NULL; - if (!skin_start_new_line(curr_vp, 0)) - return false; + curr_vp = NULL; + curr_viewport_element = NULL; if (isfile) { @@ -2364,9 +1418,15 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data, { wps_buffer = (char*)buf; } - /* parse the WPS source */ - if (!wps_parse(wps_data, wps_buffer, isfile)) { +#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + wps_data->backdrop = "-"; +#endif + /* parse the skin source */ + skin_buffer_save_position(); + wps_data->tree = skin_parse(wps_buffer, skin_element_callback, wps_data); + if (!wps_data->tree) { skin_data_reset(wps_data); + skin_buffer_restore_position(); return false; } @@ -2387,6 +1447,7 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data, !skin_load_fonts(wps_data)) { skin_data_reset(wps_data); + skin_buffer_restore_position(); return false; } #endif @@ -2410,8 +1471,8 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data, #endif wps_data->wps_loaded = true; #ifdef DEBUG_SKIN_ENGINE - if (isfile && debug_wps) - debug_skin_usage(); + // if (isfile && debug_wps) + // debug_skin_usage(); #endif return true; } diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c new file mode 100644 index 0000000000..e05f97ff4e --- /dev/null +++ b/apps/gui/skin_engine/skin_render.c @@ -0,0 +1,614 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: skin_parser.c 26752 2010-06-10 21:22:16Z bieber $ + * + * Copyright (C) 2010 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <ctype.h> +#include "strlcat.h" + +#include "config.h" +#include "kernel.h" +#ifdef HAVE_ALBUMART +#include "albumart.h" +#endif +#include "skin_display.h" +#include "skin_engine.h" +#include "skin_parser.h" +#include "tag_table.h" +#include "skin_scan.h" +#if CONFIG_TUNER +#include "radio.h" +#endif +#include "language.h" +#include "playback.h" + + +#define MAX_LINE 1024 + +struct skin_draw_info { + struct gui_wps *gwps; + struct skin_viewport *skin_vp; + int line_number; + unsigned long refresh_type; + + char* cur_align_start; + struct align_pos align; + bool no_line_break; + bool line_scrolls; + bool force_redraw; + + char *buf; + size_t buf_size; +}; + +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 bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info, + struct skin_element *element, struct viewport* vp) +{ +#ifndef HAVE_LCD_BITMAP + (void)vp; /* silence warnings */ +#endif + struct wps_token *token = (struct wps_token *)element->data; + struct wps_data *data = gwps->data; + bool do_refresh = (element->tag->flags & info->refresh_type) > 0; + switch (token->type) + { +#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) + case SKIN_TOKEN_VIEWPORT_FGCOLOUR: + { + struct viewport_colour *col = token->value.data; + col->vp->fg_pattern = col->colour; + } + break; + case SKIN_TOKEN_VIEWPORT_BGCOLOUR: + { + struct viewport_colour *col = token->value.data; + col->vp->bg_pattern = col->colour; + } + break; +#endif + case SKIN_TOKEN_VIEWPORT_ENABLE: + { + char label = token->value.i; + char temp = VP_DRAW_HIDEABLE; + struct skin_element *viewport = gwps->data->tree; + while (viewport) + { + struct skin_viewport *skinvp = (struct skin_viewport*)viewport->data; + if (skinvp->label == label) + { + if (skinvp->hidden_flags&VP_DRAW_HIDDEN) + { + temp |= VP_DRAW_WASHIDDEN; + } + skinvp->hidden_flags = temp; + } + viewport = viewport->next; + } + } + break; +#ifdef HAVE_LCD_BITMAP + case SKIN_TOKEN_UIVIEWPORT_ENABLE: + sb_set_info_vp(gwps->display->screen_type, + token->value.i|VP_INFO_LABEL); + break; + case SKIN_TOKEN_PEAKMETER: + data->peak_meter_enabled = true; + if (do_refresh) + draw_peakmeters(gwps, info->line_number, vp); + break; +#endif + case SKIN_TOKEN_VOLUMEBAR: + case SKIN_TOKEN_BATTERY_PERCENTBAR: + case SKIN_TOKEN_PROGRESSBAR: + { +#ifdef HAVE_LCD_BITMAP + struct progressbar *bar = (struct progressbar*)token->value.data; + if (do_refresh) + draw_progressbar(gwps, info->line_number, bar); +#else /* HAVE_LCD_CHARCELL */ + if (do_refresh) + { + if (data->full_line_progressbar) + draw_player_fullbar(gwps, info->buf, info->buf_size); + else + draw_player_progress(gwps); + } +#endif + } + break; +#ifdef HAVE_LCD_BITMAP + case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: + { + char n = token->value.i & 0xFF; + int subimage = token->value.i >> 8; + struct gui_img *img = find_image(n, data); + if (img && img->loaded) + img->display = subimage; + break; + } +#ifdef HAVE_ALBUMART + case SKIN_TOKEN_ALBUMART_DISPLAY: + /* now draw the AA */ + if (data->albumart) + { + int handle = playback_current_aa_hid(data->playback_aa_slot); +#if CONFIG_TUNER + if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) + { + struct dim dim = {data->albumart->width, data->albumart->height}; + handle = radio_get_art_hid(&dim); + } +#endif + data->albumart->draw_handle = handle; + } + break; +#endif + case SKIN_TOKEN_DRAW_INBUILTBAR: + gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]), + info->refresh_type == SKIN_REFRESH_ALL, + token->value.data); + break; + case SKIN_TOKEN_VIEWPORT_CUSTOMLIST: + if (do_refresh) + draw_playlist_viewer_list(gwps, token->value.data); + break; + +#endif /* HAVE_LCD_BITMAP */ + default: + return false; + } + return true; +} + + + +static void do_tags_in_hidden_conditional(struct skin_element* branch, + struct skin_draw_info *info) +{ +#ifdef HAVE_LCD_BITMAP + struct gui_wps *gwps = info->gwps; + struct wps_data *data = gwps->data; +#endif + /* Tags here are ones which need to be "turned off" or cleared + * if they are in a conditional branch which isnt being used */ + if (branch->type == LINE_ALTERNATOR) + { + int i; + for (i=0; i<branch->children_count; i++) + { + do_tags_in_hidden_conditional(branch->children[i], info); + } + } + else if (branch->type == LINE && branch->children_count) + { + struct skin_element *child = branch->children[0]; + struct wps_token *token; + while (child) + { + if (child->type == CONDITIONAL) + { + int i; + for (i=0; i<child->children_count; i++) + { + do_tags_in_hidden_conditional(child->children[i], info); + } + child = child->next; + continue; + } + else if (child->type != TAG || !child->data) + { + child = child->next; + continue; + } + token = (struct wps_token *)child->data; +#ifdef HAVE_LCD_BITMAP + /* clear all pictures in the conditional and nested ones */ + if (token->type == SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY) + { + struct gui_img *img = find_image(token->value.i&0xFF, data); + clear_image_pos(gwps, img); + } + else if (token->type == SKIN_TOKEN_PEAKMETER) + { + data->peak_meter_enabled = false; + } + else if (token->type == SKIN_TOKEN_VIEWPORT_ENABLE) + { + char label = token->value.i&0x7f; + struct skin_element *viewport; + for (viewport = data->tree; + viewport; + viewport = viewport->next) + { + struct skin_viewport *skin_viewport = (struct skin_viewport*)viewport->data; + if ((skin_viewport->label&0x7f) != label) + continue; + if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) + { + continue; + } + if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE) + { + if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN) + skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; + else + { + gwps->display->set_viewport(&skin_viewport->vp); + gwps->display->clear_viewport(); + gwps->display->scroll_stop(&skin_viewport->vp); + gwps->display->set_viewport(&info->skin_vp->vp); + skin_viewport->hidden_flags |= VP_DRAW_HIDDEN; + } + } + } + } +#endif +#ifdef HAVE_ALBUMART + else if (data->albumart && token->type == SKIN_TOKEN_ALBUMART_DISPLAY) + { + draw_album_art(gwps, + playback_current_aa_hid(data->playback_aa_slot), true); + } +#endif + child = child->next; + } + } +} + +static void fix_line_alignment(struct skin_draw_info *info, struct skin_element *element) +{ + struct align_pos *align = &info->align; + char *cur_pos = info->cur_align_start + strlen(info->cur_align_start); + switch (element->tag->type) + { + case SKIN_TOKEN_ALIGN_LEFT: + *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; + align->left = cur_pos; + info->cur_align_start = cur_pos; + break; + case SKIN_TOKEN_ALIGN_LEFT_RTL: + *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; + if (lang_is_rtl()) + align->right = cur_pos; + else + align->left = cur_pos; + info->cur_align_start = cur_pos; + break; + case SKIN_TOKEN_ALIGN_CENTER: + *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; + align->center = cur_pos; + info->cur_align_start = cur_pos; + break; + case SKIN_TOKEN_ALIGN_RIGHT: + *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; + align->right = cur_pos; + info->cur_align_start = cur_pos; + break; + case SKIN_TOKEN_ALIGN_RIGHT_RTL: + *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; + if (lang_is_rtl()) + align->left = cur_pos; + else + align->right = cur_pos; + info->cur_align_start = cur_pos; + break; + default: + break; + } +} + +/* Draw a LINE element onto the display */ +bool skin_render_line(struct skin_element* line, struct skin_draw_info *info) +{ + bool needs_update = false; + int last_value, value; + + if (line->children_count == 0) + return false; /* empty line, do nothing */ + + struct skin_element *child = line->children[0]; + struct conditional *conditional; + skin_render_func func = skin_render_line; + char tempbuf[128]; + int old_refresh_mode = info->refresh_type; + while (child) + { + tempbuf[0] = '\0'; + switch (child->type) + { + case CONDITIONAL: + conditional = (struct conditional*)child->data; + last_value = conditional->last_value; + value = evaluate_conditional(info->gwps, conditional, child->children_count); + + if (value != 1 && value >= child->children_count) + value = child->children_count-1; + if (child->children_count == 1) + { + /* special handling so + * %?aa<true> and %?<true|false> need special handlng here */ + + if (value == 1) /* tag is false */ + { + /* we are in a false branch of a %?aa<true> conditional */ + if (last_value == 0) + do_tags_in_hidden_conditional(child->children[0], info); + break; + } + value = 0; + } + else + { + if (last_value >= 0 && value != last_value && last_value < child->children_count) + do_tags_in_hidden_conditional(child->children[last_value], info); + } + if (child->children[value]->type == LINE_ALTERNATOR) + { + func = skin_render_alternator; + } + else if (child->children[value]->type == LINE) + func = skin_render_line; + + if (value != last_value) + { + info->refresh_type = SKIN_REFRESH_ALL; + info->force_redraw = true; + } + + if (func(child->children[value], info)) + needs_update = true; + else + needs_update = needs_update || (last_value != value); + + info->refresh_type = old_refresh_mode; + break; + case TAG: + if (child->tag->flags & NOBREAK) + info->no_line_break = true; + if (child->tag->type == SKIN_TOKEN_SUBLINE_SCROLL) + info->line_scrolls = true; + + fix_line_alignment(info, child); + + if (!child->data) + { + break; + } + 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); + if (value) + { + needs_update = needs_update || + ((child->tag->flags&info->refresh_type)!=0); + strlcat(info->cur_align_start, value, + info->buf_size - (info->cur_align_start-info->buf)); + } + } + break; + case TEXT: + strlcat(info->cur_align_start, child->data, + info->buf_size - (info->cur_align_start-info->buf)); + needs_update = needs_update || + (info->refresh_type&SKIN_REFRESH_STATIC) != 0; + break; + case COMMENT: + default: + break; + } + + child = child->next; + } + return needs_update; +} + +bool skin_render_alternator(struct skin_element* element, struct skin_draw_info *info) +{ + bool changed_lines = false; + struct line_alternator *alternator = (struct line_alternator*)element->data; + unsigned old_refresh = info->refresh_type; + if (info->refresh_type == SKIN_REFRESH_ALL) + { + alternator->current_line = 0; + alternator->last_change_tick = current_tick; + changed_lines = true; + } + else + { + struct skin_element *current_line = element->children[alternator->current_line]; + struct line *line = (struct line *)current_line->data; + int next_change = alternator->last_change_tick + line->timeout; + if (TIME_AFTER(current_tick, next_change)) + { + alternator->current_line++; + if (alternator->current_line >= element->children_count) + alternator->current_line = 0; + alternator->last_change_tick = current_tick; + changed_lines = true; + } + } + if (element->children[alternator->current_line]->children_count == 0) + { + /* skip empty sublines */ + alternator->current_line++; + if (alternator->current_line >= element->children_count) + alternator->current_line = 0; + changed_lines = true; + } + + if (changed_lines) + { + info->refresh_type = SKIN_REFRESH_ALL; + info->force_redraw = true; + } + bool ret = skin_render_line(element->children[alternator->current_line], info); + info->refresh_type = old_refresh; + return changed_lines || ret; +} + +void skin_render_viewport(struct skin_element* viewport, 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 = viewport; + 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 + }; + + struct align_pos * align = &info.align; + bool needs_update; +#ifdef HAVE_LCD_BITMAP + /* Set images to not to be displayed */ + struct skin_token_list *imglist = gwps->data->images; + while (imglist) + { + struct gui_img *img = (struct gui_img *)imglist->token->value.data; + img->display = -1; + imglist = imglist->next; + } +#endif + + while (line) + { + 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); + } + if (!info.no_line_break) + info.line_number++; + line = line->next; + } +#ifdef HAVE_LCD_BITMAP + wps_display_images(gwps, &skin_viewport->vp); +#endif +} + +void skin_render(struct gui_wps *gwps, unsigned refresh_mode) +{ + struct wps_data *data = gwps->data; + struct screen *display = gwps->display; + + struct skin_element* viewport = data->tree; + struct skin_viewport* skin_viewport; + + int old_refresh_mode = refresh_mode; + +#ifdef HAVE_LCD_CHARCELLS + int i; + for (i = 0; i < 8; i++) + { + if (data->wps_progress_pat[i] == 0) + data->wps_progress_pat[i] = display->get_locked_pattern(); + } +#endif + viewport = data->tree; + skin_viewport = (struct skin_viewport *)viewport->data; + if (skin_viewport->label == VP_DEFAULT_LABEL && viewport->next) + refresh_mode = 0; + + for (viewport = data->tree; + viewport; + viewport = viewport->next) + { + /* SETUP */ + skin_viewport = (struct skin_viewport*)viewport->data; + unsigned vp_refresh_mode = refresh_mode; +#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) + skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour; + skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour; +#endif + + /* dont redraw the viewport if its disabled */ + if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) + { /* don't draw anything into this one */ + vp_refresh_mode = 0; + } + else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN)) + { + skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; + continue; + } + else if (((skin_viewport->hidden_flags& + (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)) + == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))) + { + vp_refresh_mode = SKIN_REFRESH_ALL; + skin_viewport->hidden_flags = VP_DRAW_HIDEABLE; + } + + display->set_viewport(&skin_viewport->vp); + if ((vp_refresh_mode&SKIN_REFRESH_ALL) == SKIN_REFRESH_ALL) + { + display->clear_viewport(); + } + /* render */ + skin_render_viewport(viewport->children[0], gwps, + skin_viewport, vp_refresh_mode); + refresh_mode = old_refresh_mode; + } + + /* Restore the default viewport */ + display->set_viewport(NULL); + display->update(); +} diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c index b0a55ca13c..c5e1ebc831 100644 --- a/apps/gui/skin_engine/skin_tokens.c +++ b/apps/gui/skin_engine/skin_tokens.c @@ -167,19 +167,19 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, unsigned long elapsed = id3->elapsed + state->ff_rewind_count; switch (token->type) { - case WPS_TOKEN_METADATA_ARTIST: + case SKIN_TOKEN_METADATA_ARTIST: return id3->artist; - case WPS_TOKEN_METADATA_COMPOSER: + case SKIN_TOKEN_METADATA_COMPOSER: return id3->composer; - case WPS_TOKEN_METADATA_ALBUM: + case SKIN_TOKEN_METADATA_ALBUM: return id3->album; - case WPS_TOKEN_METADATA_ALBUM_ARTIST: + case SKIN_TOKEN_METADATA_ALBUM_ARTIST: return id3->albumartist; - case WPS_TOKEN_METADATA_GROUPING: + case SKIN_TOKEN_METADATA_GROUPING: return id3->grouping; - case WPS_TOKEN_METADATA_GENRE: + case SKIN_TOKEN_METADATA_GENRE: return id3->genre_string; - case WPS_TOKEN_METADATA_DISC_NUMBER: + case SKIN_TOKEN_METADATA_DISC_NUMBER: if (id3->disc_string) return id3->disc_string; if (id3->discnum) { @@ -187,7 +187,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, return buf; } return NULL; - case WPS_TOKEN_METADATA_TRACK_NUMBER: + case SKIN_TOKEN_METADATA_TRACK_NUMBER: if (id3->track_string) return id3->track_string; if (id3->tracknum) { @@ -195,9 +195,9 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, return buf; } return NULL; - case WPS_TOKEN_METADATA_TRACK_TITLE: + case SKIN_TOKEN_METADATA_TRACK_TITLE: return id3->title; - case WPS_TOKEN_METADATA_VERSION: + case SKIN_TOKEN_METADATA_VERSION: switch (id3->id3version) { case ID3_VER_1_0: @@ -214,7 +214,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, break; } return NULL; - case WPS_TOKEN_METADATA_YEAR: + case SKIN_TOKEN_METADATA_YEAR: if( id3->year_string ) return id3->year_string; if (id3->year) { @@ -222,29 +222,29 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, return buf; } return NULL; - case WPS_TOKEN_METADATA_COMMENT: + case SKIN_TOKEN_METADATA_COMMENT: return id3->comment; - case WPS_TOKEN_FILE_PATH: + case SKIN_TOKEN_FILE_PATH: return id3->path; - case WPS_TOKEN_FILE_BITRATE: + case SKIN_TOKEN_FILE_BITRATE: if(id3->bitrate) snprintf(buf, buf_size, "%d", id3->bitrate); else return "?"; return buf; - case WPS_TOKEN_TRACK_TIME_ELAPSED: + case SKIN_TOKEN_TRACK_TIME_ELAPSED: format_time(buf, buf_size, elapsed); return buf; - case WPS_TOKEN_TRACK_TIME_REMAINING: + case SKIN_TOKEN_TRACK_TIME_REMAINING: format_time(buf, buf_size, length - elapsed); return buf; - case WPS_TOKEN_TRACK_LENGTH: + case SKIN_TOKEN_TRACK_LENGTH: format_time(buf, buf_size, length); return buf; - case WPS_TOKEN_TRACK_ELAPSED_PERCENT: + case SKIN_TOKEN_TRACK_ELAPSED_PERCENT: if (length <= 0) return NULL; @@ -255,14 +255,14 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, snprintf(buf, buf_size, "%lu", 100 * elapsed / length); return buf; - case WPS_TOKEN_TRACK_STARTING: + case SKIN_TOKEN_TRACK_STARTING: { unsigned long time = token->value.i * 1000; if (elapsed < time) return "starting"; } return NULL; - case WPS_TOKEN_TRACK_ENDING: + case SKIN_TOKEN_TRACK_ENDING: { unsigned long time = token->value.i * 1000; if (length - elapsed < time) @@ -270,7 +270,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, } return NULL; - case WPS_TOKEN_FILE_CODEC: + case SKIN_TOKEN_FILE_CODEC: if (intval) { if(id3->codectype == AFMT_UNKNOWN) @@ -280,10 +280,10 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, } return get_codectype(id3); - case WPS_TOKEN_FILE_FREQUENCY: + case SKIN_TOKEN_FILE_FREQUENCY: snprintf(buf, buf_size, "%ld", id3->frequency); return buf; - case WPS_TOKEN_FILE_FREQUENCY_KHZ: + case SKIN_TOKEN_FILE_FREQUENCY_KHZ: /* ignore remainders < 100, so 22050 Hz becomes just 22k */ if ((id3->frequency % 1000) < 100) snprintf(buf, buf_size, "%ld", id3->frequency / 1000); @@ -292,7 +292,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, id3->frequency / 1000, (id3->frequency % 1000) / 100); return buf; - case WPS_TOKEN_FILE_NAME: + case SKIN_TOKEN_FILE_NAME: if (get_dir(buf, buf_size, id3->path, 0)) { /* Remove extension */ char* sep = strrchr(buf, '.'); @@ -302,28 +302,28 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, return buf; } return NULL; - case WPS_TOKEN_FILE_NAME_WITH_EXTENSION: + case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION: return get_dir(buf, buf_size, id3->path, 0); - case WPS_TOKEN_FILE_SIZE: + case SKIN_TOKEN_FILE_SIZE: snprintf(buf, buf_size, "%ld", id3->filesize / 1024); return buf; - case WPS_TOKEN_FILE_VBR: + case SKIN_TOKEN_FILE_VBR: return (id3->vbr) ? "(avg)" : NULL; - case WPS_TOKEN_FILE_DIRECTORY: + case SKIN_TOKEN_FILE_DIRECTORY: return get_dir(buf, buf_size, id3->path, token->value.i); #ifdef HAVE_TAGCACHE - case WPS_TOKEN_DATABASE_PLAYCOUNT: + case SKIN_TOKEN_DATABASE_PLAYCOUNT: if (intval) *intval = id3->playcount + 1; snprintf(buf, buf_size, "%ld", id3->playcount); return buf; - case WPS_TOKEN_DATABASE_RATING: + case SKIN_TOKEN_DATABASE_RATING: if (intval) *intval = id3->rating + 1; snprintf(buf, buf_size, "%d", id3->rating); return buf; - case WPS_TOKEN_DATABASE_AUTOSCORE: + case SKIN_TOKEN_DATABASE_AUTOSCORE: if (intval) *intval = id3->score + 1; snprintf(buf, buf_size, "%d", id3->score); @@ -340,13 +340,13 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, { /* Most tokens expect NULL on error so leave that for the default case, * The ones that expect "0" need to be handled */ - case WPS_TOKEN_FILE_FREQUENCY: - case WPS_TOKEN_FILE_FREQUENCY_KHZ: - case WPS_TOKEN_FILE_SIZE: + case SKIN_TOKEN_FILE_FREQUENCY: + case SKIN_TOKEN_FILE_FREQUENCY_KHZ: + case SKIN_TOKEN_FILE_SIZE: #ifdef HAVE_TAGCACHE - case WPS_TOKEN_DATABASE_PLAYCOUNT: - case WPS_TOKEN_DATABASE_RATING: - case WPS_TOKEN_DATABASE_AUTOSCORE: + case SKIN_TOKEN_DATABASE_PLAYCOUNT: + case SKIN_TOKEN_DATABASE_RATING: + case SKIN_TOKEN_DATABASE_AUTOSCORE: #endif if (intval) *intval = 0; @@ -397,30 +397,30 @@ const char *get_radio_token(struct wps_token *token, int preset_offset, switch (token->type) { /* Radio/tuner tokens */ - case WPS_TOKEN_TUNER_TUNED: + case SKIN_TOKEN_TUNER_TUNED: if (tuner_get(RADIO_TUNED)) return "t"; return NULL; - case WPS_TOKEN_TUNER_SCANMODE: + case SKIN_TOKEN_TUNER_SCANMODE: if (radio_scan_mode()) return "s"; return NULL; - case WPS_TOKEN_TUNER_STEREO: + case SKIN_TOKEN_TUNER_STEREO: if (radio_is_stereo()) return "s"; return NULL; - case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */ + case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */ return format_freq_MHz(region_data->freq_min, region_data->freq_step, buf, buf_size); - case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */ + case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */ return format_freq_MHz(region_data->freq_max, region_data->freq_step, buf, buf_size); - case WPS_TOKEN_TUNER_CURFREQ: + case SKIN_TOKEN_TUNER_CURFREQ: return format_freq_MHz(radio_current_frequency(), region_data->freq_step, buf, buf_size); - case WPS_TOKEN_PRESET_NAME: - case WPS_TOKEN_PRESET_FREQ: - case WPS_TOKEN_PRESET_ID: + case SKIN_TOKEN_PRESET_NAME: + case SKIN_TOKEN_PRESET_FREQ: + case SKIN_TOKEN_PRESET_ID: { int preset_count = radio_preset_count(); int cur_preset = radio_current_preset(); @@ -431,30 +431,32 @@ const char *get_radio_token(struct wps_token *token, int preset_offset, preset %= preset_count; if (preset < 0) preset += preset_count; - if (token->type == WPS_TOKEN_PRESET_NAME) + if (token->type == SKIN_TOKEN_PRESET_NAME) snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name); - else if (token->type == WPS_TOKEN_PRESET_FREQ) + else if (token->type == SKIN_TOKEN_PRESET_FREQ) format_freq_MHz(radio_get_preset(preset)->frequency, region_data->freq_step, buf, buf_size); else snprintf(buf, buf_size, "%d", preset + 1); return buf; } - case WPS_TOKEN_PRESET_COUNT: + case SKIN_TOKEN_PRESET_COUNT: snprintf(buf, buf_size, "%d", radio_preset_count()); if (intval) *intval = radio_preset_count(); return buf; - case WPS_TOKEN_HAVE_RDS: + case SKIN_TOKEN_HAVE_RDS: #ifdef HAVE_RDS_CAP return "rds"; - case WPS_TOKEN_RDS_NAME: + case SKIN_TOKEN_RDS_NAME: return tuner_get_rds_info(RADIO_RDS_NAME); - case WPS_TOKEN_RDS_TEXT: + case SKIN_TOKEN_RDS_TEXT: return tuner_get_rds_info(RADIO_RDS_TEXT); #else - return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */ + return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */ #endif /* HAVE_RDS_CAP */ + default: + return NULL; } return NULL; } @@ -497,8 +499,8 @@ const char *get_token_value(struct gui_wps *gwps, /* if the token is an RTC one, update the time and do the necessary checks */ - if (token->type >= WPS_TOKENS_RTC_BEGIN - && token->type <= WPS_TOKENS_RTC_END) + if (token->type >= SKIN_TOKENS_RTC_BEGIN + && token->type <= SKIN_TOKENS_RTC_END) { tm = get_time(); @@ -531,44 +533,44 @@ const char *get_token_value(struct gui_wps *gwps, switch (token->type) { - case WPS_TOKEN_CHARACTER: + case SKIN_TOKEN_CHARACTER: if (token->value.c == '\n') return NULL; return &(token->value.c); - case WPS_TOKEN_STRING: + case SKIN_TOKEN_STRING: return (char*)token->value.data; - case WPS_TOKEN_TRANSLATEDSTRING: + case SKIN_TOKEN_TRANSLATEDSTRING: return (char*)P2STR(ID2P(token->value.i)); - case WPS_TOKEN_PLAYLIST_ENTRIES: + case SKIN_TOKEN_PLAYLIST_ENTRIES: snprintf(buf, buf_size, "%d", playlist_amount()); return buf; - case WPS_TOKEN_LIST_TITLE_TEXT: + case SKIN_TOKEN_LIST_TITLE_TEXT: return (char*)token->value.data; - case WPS_TOKEN_LIST_TITLE_ICON: + case SKIN_TOKEN_LIST_TITLE_ICON: if (intval) *intval = token->value.i; snprintf(buf, buf_size, "%d", token->value.i); return buf; - case WPS_TOKEN_PLAYLIST_NAME: + case SKIN_TOKEN_PLAYLIST_NAME: return playlist_name(NULL, buf, buf_size); - case WPS_TOKEN_PLAYLIST_POSITION: + case SKIN_TOKEN_PLAYLIST_POSITION: snprintf(buf, buf_size, "%d", playlist_get_display_index()); return buf; - case WPS_TOKEN_PLAYLIST_SHUFFLE: + case SKIN_TOKEN_PLAYLIST_SHUFFLE: if ( global_settings.playlist_shuffle ) return "s"; else return NULL; break; - case WPS_TOKEN_VOLUME: + case SKIN_TOKEN_VOLUME: snprintf(buf, buf_size, "%d", global_settings.volume); if (intval) { @@ -593,7 +595,7 @@ const char *get_token_value(struct gui_wps *gwps, } return buf; #ifdef HAVE_ALBUMART - case WPS_TOKEN_ALBUMART_FOUND: + case SKIN_TOKEN_ALBUMART_FOUND: if (data->albumart) { int handle = -1; @@ -609,16 +611,9 @@ const char *get_token_value(struct gui_wps *gwps, return "C"; } return NULL; - - case WPS_TOKEN_ALBUMART_DISPLAY: - if (!data->albumart) - return NULL; - if (!data->albumart->draw) - data->albumart->draw = true; - return NULL; #endif - case WPS_TOKEN_BATTERY_PERCENT: + case SKIN_TOKEN_BATTERY_PERCENT: { int l = battery_level(); @@ -641,14 +636,14 @@ const char *get_token_value(struct gui_wps *gwps, } } - case WPS_TOKEN_BATTERY_VOLTS: + case SKIN_TOKEN_BATTERY_VOLTS: { unsigned int v = battery_voltage(); snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10); return buf; } - case WPS_TOKEN_BATTERY_TIME: + case SKIN_TOKEN_BATTERY_TIME: { int t = battery_time(); if (t >= 0) @@ -659,7 +654,7 @@ const char *get_token_value(struct gui_wps *gwps, } #if CONFIG_CHARGING - case WPS_TOKEN_BATTERY_CHARGER_CONNECTED: + case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED: { if(charger_input_state==CHARGER) return "p"; @@ -668,7 +663,7 @@ const char *get_token_value(struct gui_wps *gwps, } #endif #if CONFIG_CHARGING >= CHARGING_MONITOR - case WPS_TOKEN_BATTERY_CHARGING: + case SKIN_TOKEN_BATTERY_CHARGING: { if (charge_state == CHARGING || charge_state == TOPOFF) { return "c"; @@ -678,12 +673,12 @@ const char *get_token_value(struct gui_wps *gwps, } #endif #ifdef HAVE_USB_POWER - case WPS_TOKEN_USB_POWERED: + case SKIN_TOKEN_USB_POWERED: if (usb_powered()) return "u"; return NULL; #endif - case WPS_TOKEN_BATTERY_SLEEPTIME: + case SKIN_TOKEN_BATTERY_SLEEPTIME: { if (get_sleep_timer() == 0) return NULL; @@ -694,7 +689,7 @@ const char *get_token_value(struct gui_wps *gwps, } } - case WPS_TOKEN_PLAYBACK_STATUS: + case SKIN_TOKEN_PLAYBACK_STATUS: { int status = current_playmode(); /* music */ @@ -734,13 +729,13 @@ const char *get_token_value(struct gui_wps *gwps, return buf; } - case WPS_TOKEN_REPEAT_MODE: + case SKIN_TOKEN_REPEAT_MODE: if (intval) *intval = global_settings.repeat_mode + 1; snprintf(buf, buf_size, "%d", global_settings.repeat_mode); return buf; - case WPS_TOKEN_RTC_PRESENT: + case SKIN_TOKEN_RTC_PRESENT: #if CONFIG_RTC return "c"; #else @@ -748,41 +743,41 @@ const char *get_token_value(struct gui_wps *gwps, #endif #if CONFIG_RTC - case WPS_TOKEN_RTC_12HOUR_CFG: + case SKIN_TOKEN_RTC_12HOUR_CFG: if (intval) *intval = global_settings.timeformat + 1; snprintf(buf, buf_size, "%d", global_settings.timeformat); return buf; - case WPS_TOKEN_RTC_DAY_OF_MONTH: + case SKIN_TOKEN_RTC_DAY_OF_MONTH: /* d: day of month (01..31) */ snprintf(buf, buf_size, "%02d", tm->tm_mday); if (intval) *intval = tm->tm_mday - 1; return buf; - case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: + case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: /* e: day of month, blank padded ( 1..31) */ snprintf(buf, buf_size, "%2d", tm->tm_mday); if (intval) *intval = tm->tm_mday - 1; return buf; - case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED: + case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED: /* H: hour (00..23) */ snprintf(buf, buf_size, "%02d", tm->tm_hour); if (intval) *intval = tm->tm_hour; return buf; - case WPS_TOKEN_RTC_HOUR_24: + case SKIN_TOKEN_RTC_HOUR_24: /* k: hour ( 0..23) */ snprintf(buf, buf_size, "%2d", tm->tm_hour); if (intval) *intval = tm->tm_hour; return buf; - case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED: + case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED: /* I: hour (01..12) */ snprintf(buf, buf_size, "%02d", (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12); @@ -790,7 +785,7 @@ const char *get_token_value(struct gui_wps *gwps, *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12; return buf; - case WPS_TOKEN_RTC_HOUR_12: + case SKIN_TOKEN_RTC_HOUR_12: /* l: hour ( 1..12) */ snprintf(buf, buf_size, "%2d", (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12); @@ -798,107 +793,107 @@ const char *get_token_value(struct gui_wps *gwps, *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12; return buf; - case WPS_TOKEN_RTC_MONTH: + case SKIN_TOKEN_RTC_MONTH: /* m: month (01..12) */ if (intval) *intval = tm->tm_mon + 1; snprintf(buf, buf_size, "%02d", tm->tm_mon + 1); return buf; - case WPS_TOKEN_RTC_MINUTE: + case SKIN_TOKEN_RTC_MINUTE: /* M: minute (00..59) */ snprintf(buf, buf_size, "%02d", tm->tm_min); if (intval) *intval = tm->tm_min; return buf; - case WPS_TOKEN_RTC_SECOND: + case SKIN_TOKEN_RTC_SECOND: /* S: second (00..59) */ snprintf(buf, buf_size, "%02d", tm->tm_sec); if (intval) *intval = tm->tm_sec; return buf; - case WPS_TOKEN_RTC_YEAR_2_DIGITS: + case SKIN_TOKEN_RTC_YEAR_2_DIGITS: /* y: last two digits of year (00..99) */ snprintf(buf, buf_size, "%02d", tm->tm_year % 100); if (intval) *intval = tm->tm_year % 100; return buf; - case WPS_TOKEN_RTC_YEAR_4_DIGITS: + case SKIN_TOKEN_RTC_YEAR_4_DIGITS: /* Y: year (1970...) */ snprintf(buf, buf_size, "%04d", tm->tm_year + 1900); if (intval) *intval = tm->tm_year + 1900; return buf; - case WPS_TOKEN_RTC_AM_PM_UPPER: + case SKIN_TOKEN_RTC_AM_PM_UPPER: /* p: upper case AM or PM indicator */ if (intval) *intval = tm->tm_hour/12 == 0 ? 0 : 1; return tm->tm_hour/12 == 0 ? "AM" : "PM"; - case WPS_TOKEN_RTC_AM_PM_LOWER: + case SKIN_TOKEN_RTC_AM_PM_LOWER: /* P: lower case am or pm indicator */ if (intval) *intval = tm->tm_hour/12 == 0 ? 0 : 1; return tm->tm_hour/12 == 0 ? "am" : "pm"; - case WPS_TOKEN_RTC_WEEKDAY_NAME: + case SKIN_TOKEN_RTC_WEEKDAY_NAME: /* a: abbreviated weekday name (Sun..Sat) */ return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday); - case WPS_TOKEN_RTC_MONTH_NAME: + case SKIN_TOKEN_RTC_MONTH_NAME: /* b: abbreviated month name (Jan..Dec) */ return str(LANG_MONTH_JANUARY + tm->tm_mon); - case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON: + case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON: /* u: day of week (1..7); 1 is Monday */ if (intval) *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday; snprintf(buf, buf_size, "%1d", tm->tm_wday + 1); return buf; - case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN: + case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN: /* w: day of week (0..6); 0 is Sunday */ if (intval) *intval = tm->tm_wday + 1; snprintf(buf, buf_size, "%1d", tm->tm_wday); return buf; #else - case WPS_TOKEN_RTC_DAY_OF_MONTH: - case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: - case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED: - case WPS_TOKEN_RTC_HOUR_24: - case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED: - case WPS_TOKEN_RTC_HOUR_12: - case WPS_TOKEN_RTC_MONTH: - case WPS_TOKEN_RTC_MINUTE: - case WPS_TOKEN_RTC_SECOND: - case WPS_TOKEN_RTC_AM_PM_UPPER: - case WPS_TOKEN_RTC_AM_PM_LOWER: - case WPS_TOKEN_RTC_YEAR_2_DIGITS: + case SKIN_TOKEN_RTC_DAY_OF_MONTH: + case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: + case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED: + case SKIN_TOKEN_RTC_HOUR_24: + case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED: + case SKIN_TOKEN_RTC_HOUR_12: + case SKIN_TOKEN_RTC_MONTH: + case SKIN_TOKEN_RTC_MINUTE: + case SKIN_TOKEN_RTC_SECOND: + case SKIN_TOKEN_RTC_AM_PM_UPPER: + case SKIN_TOKEN_RTC_AM_PM_LOWER: + case SKIN_TOKEN_RTC_YEAR_2_DIGITS: return "--"; - case WPS_TOKEN_RTC_YEAR_4_DIGITS: + case SKIN_TOKEN_RTC_YEAR_4_DIGITS: return "----"; - case WPS_TOKEN_RTC_WEEKDAY_NAME: - case WPS_TOKEN_RTC_MONTH_NAME: + case SKIN_TOKEN_RTC_WEEKDAY_NAME: + case SKIN_TOKEN_RTC_MONTH_NAME: return "---"; - case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON: - case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN: + case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON: + case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN: return "-"; #endif #ifdef HAVE_LCD_CHARCELLS - case WPS_TOKEN_PROGRESSBAR: + case SKIN_TOKEN_PROGRESSBAR: { char *end = utf8encode(data->wps_progress_pat[0], buf); *end = '\0'; return buf; } - case WPS_TOKEN_PLAYER_PROGRESSBAR: + case SKIN_TOKEN_PLAYER_PROGRESSBAR: if(is_new_player()) { /* we need 11 characters (full line) for @@ -916,7 +911,7 @@ const char *get_token_value(struct gui_wps *gwps, #if (CONFIG_CODEC == SWCODEC) - case WPS_TOKEN_CROSSFADE: + case SKIN_TOKEN_CROSSFADE: #ifdef HAVE_CROSSFADE if (intval) *intval = global_settings.crossfade + 1; @@ -926,7 +921,7 @@ const char *get_token_value(struct gui_wps *gwps, #endif return buf; - case WPS_TOKEN_REPLAYGAIN: + case SKIN_TOKEN_REPLAYGAIN: { int val; @@ -974,7 +969,7 @@ const char *get_token_value(struct gui_wps *gwps, #endif /* (CONFIG_CODEC == SWCODEC) */ #if (CONFIG_CODEC != MAS3507D) - case WPS_TOKEN_SOUND_PITCH: + case SKIN_TOKEN_SOUND_PITCH: { int32_t pitch = sound_get_pitch(); snprintf(buf, buf_size, "%ld.%ld", @@ -989,7 +984,7 @@ const char *get_token_value(struct gui_wps *gwps, #endif #if CONFIG_CODEC == SWCODEC - case WPS_TOKEN_SOUND_SPEED: + case SKIN_TOKEN_SOUND_SPEED: { int32_t pitch = sound_get_pitch(); int32_t speed; @@ -1007,7 +1002,7 @@ const char *get_token_value(struct gui_wps *gwps, } #endif - case WPS_TOKEN_MAIN_HOLD: + case SKIN_TOKEN_MAIN_HOLD: #ifdef HAS_BUTTON_HOLD if (button_hold()) #else @@ -1018,7 +1013,7 @@ const char *get_token_value(struct gui_wps *gwps, return NULL; #ifdef HAS_REMOTE_BUTTON_HOLD - case WPS_TOKEN_REMOTE_HOLD: + case SKIN_TOKEN_REMOTE_HOLD: if (remote_button_hold()) return "r"; else @@ -1026,20 +1021,20 @@ const char *get_token_value(struct gui_wps *gwps, #endif #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) - case WPS_TOKEN_VLED_HDD: + case SKIN_TOKEN_VLED_HDD: if(led_read(HZ/2)) return "h"; else return NULL; #endif - case WPS_TOKEN_BUTTON_VOLUME: + case SKIN_TOKEN_BUTTON_VOLUME: if (global_status.last_volume_change && TIME_BEFORE(current_tick, global_status.last_volume_change + token->value.i * TIMEOUT_UNIT)) return "v"; return NULL; - case WPS_TOKEN_LASTTOUCH: + case SKIN_TOKEN_LASTTOUCH: { #ifdef HAVE_TOUCHSCREEN unsigned int last_touch = touchscreen_last_touch(); @@ -1051,7 +1046,7 @@ const char *get_token_value(struct gui_wps *gwps, } return NULL; - case WPS_TOKEN_SETTING: + case SKIN_TOKEN_SETTING: { const struct settings_list *s = settings+token->value.i; if (intval) @@ -1120,14 +1115,14 @@ const char *get_token_value(struct gui_wps *gwps, cfg_to_string(token->value.i,buf,buf_size); return buf; } - case WPS_TOKEN_HAVE_TUNER: + case SKIN_TOKEN_HAVE_TUNER: #if CONFIG_TUNER if (radio_hardware_present()) return "r"; #endif return NULL; /* Recording tokens */ - case WPS_TOKEN_HAVE_RECORDING: + case SKIN_TOKEN_HAVE_RECORDING: #ifdef HAVE_RECORDING return "r"; #else @@ -1135,11 +1130,11 @@ const char *get_token_value(struct gui_wps *gwps, #endif #ifdef HAVE_RECORDING - case WPS_TOKEN_IS_RECORDING: + case SKIN_TOKEN_IS_RECORDING: if (audio_status() == AUDIO_STATUS_RECORD) return "r"; return NULL; - case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */ + case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */ { #if CONFIG_CODEC == SWCODEC unsigned long samprk; @@ -1227,7 +1222,7 @@ const char *get_token_value(struct gui_wps *gwps, return buf; } #if CONFIG_CODEC == SWCODEC - case WPS_TOKEN_REC_ENCODER: + case SKIN_TOKEN_REC_ENCODER: { int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */ if (intval) @@ -1248,7 +1243,7 @@ const char *get_token_value(struct gui_wps *gwps, break; } #endif - case WPS_TOKEN_REC_BITRATE: + case SKIN_TOKEN_REC_BITRATE: #if CONFIG_CODEC == SWCODEC if (global_settings.rec_format == REC_FORMAT_MPA_L3) { @@ -1317,12 +1312,12 @@ const char *get_token_value(struct gui_wps *gwps, snprintf(buf, buf_size, "%d", global_settings.rec_quality); return buf; #endif - case WPS_TOKEN_REC_MONO: + case SKIN_TOKEN_REC_MONO: if (!global_settings.rec_channels) return "m"; return NULL; - case WPS_TOKEN_REC_SECONDS: + case SKIN_TOKEN_REC_SECONDS: { int time = (audio_recorded_time() / HZ) % 60; if (intval) @@ -1330,7 +1325,7 @@ const char *get_token_value(struct gui_wps *gwps, snprintf(buf, buf_size, "%02d", time); return buf; } - case WPS_TOKEN_REC_MINUTES: + case SKIN_TOKEN_REC_MINUTES: { int time = (audio_recorded_time() / HZ) / 60; if (intval) @@ -1338,7 +1333,7 @@ const char *get_token_value(struct gui_wps *gwps, snprintf(buf, buf_size, "%02d", time); return buf; } - case WPS_TOKEN_REC_HOURS: + case SKIN_TOKEN_REC_HOURS: { int time = (audio_recorded_time() / HZ) / 3600; if (intval) @@ -1349,7 +1344,7 @@ const char *get_token_value(struct gui_wps *gwps, #endif /* HAVE_RECORDING */ - case WPS_TOKEN_CURRENT_SCREEN: + case SKIN_TOKEN_CURRENT_SCREEN: { int curr_screen = current_screen(); @@ -1390,7 +1385,7 @@ const char *get_token_value(struct gui_wps *gwps, return buf; } - case WPS_TOKEN_LANG_IS_RTL: + case SKIN_TOKEN_LANG_IS_RTL: return lang_is_rtl() ? "r" : NULL; default: diff --git a/apps/gui/skin_engine/skin_tokens.h b/apps/gui/skin_engine/skin_tokens.h index 47311312db..d259fe431c 100644 --- a/apps/gui/skin_engine/skin_tokens.h +++ b/apps/gui/skin_engine/skin_tokens.h @@ -23,243 +23,11 @@ #define _SKIN_TOKENS_H_ #include <stdbool.h> - - -enum wps_token_type { - - TOKEN_MARKER_CONTROL_TOKENS = -1, - WPS_NO_TOKEN = 0, /* for WPS tags we don't want to save as tokens */ - WPS_TOKEN_UNKNOWN, - - /* Markers */ - WPS_TOKEN_CHARACTER, - WPS_TOKEN_STRING, - WPS_TOKEN_TRANSLATEDSTRING, - - /* Alignment */ - WPS_TOKEN_ALIGN_LEFT, - WPS_TOKEN_ALIGN_LEFT_RTL, - WPS_TOKEN_ALIGN_CENTER, - WPS_TOKEN_ALIGN_RIGHT, - WPS_TOKEN_ALIGN_RIGHT_RTL, - - /* Sublines */ - WPS_TOKEN_SUBLINE_TIMEOUT, - - /* Conditional */ - WPS_TOKEN_CONDITIONAL, - WPS_TOKEN_CONDITIONAL_START, - WPS_TOKEN_CONDITIONAL_OPTION, - WPS_TOKEN_CONDITIONAL_END, - - /* Viewport display */ - WPS_VIEWPORT_ENABLE, - WPS_VIEWPORT_CUSTOMLIST, - WPS_TOKEN_UIVIEWPORT_ENABLE, - WPS_TOKEN_VIEWPORT_FGCOLOUR, - WPS_TOKEN_VIEWPORT_BGCOLOUR, - - /* Battery */ - TOKEN_MARKER_BATTERY, - WPS_TOKEN_BATTERY_PERCENT, - WPS_TOKEN_BATTERY_PERCENTBAR, - WPS_TOKEN_BATTERY_VOLTS, - WPS_TOKEN_BATTERY_TIME, - WPS_TOKEN_BATTERY_CHARGER_CONNECTED, - WPS_TOKEN_BATTERY_CHARGING, - WPS_TOKEN_BATTERY_SLEEPTIME, - WPS_TOKEN_USB_POWERED, - - /* Sound */ - TOKEN_MARKER_SOUND, -#if (CONFIG_CODEC != MAS3507D) - WPS_TOKEN_SOUND_PITCH, -#endif -#if (CONFIG_CODEC == SWCODEC) - WPS_TOKEN_SOUND_SPEED, - WPS_TOKEN_REPLAYGAIN, - WPS_TOKEN_CROSSFADE, -#endif - - /* Time */ - TOKEN_MARKER_RTC, - 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 */ - - /* Database */ - TOKEN_MARKER_DATABASE, -#ifdef HAVE_TAGCACHE - WPS_TOKEN_DATABASE_PLAYCOUNT, - WPS_TOKEN_DATABASE_RATING, - WPS_TOKEN_DATABASE_AUTOSCORE, -#endif - - /* File */ - TOKEN_MARKER_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, - - /* Image */ - TOKEN_MARKER_IMAGES, -#ifdef HAVE_LCD_BITMAP - 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 */ - TOKEN_MARKER_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, - - TOKEN_MARKER_PLAYBACK_INFO, - /* Mode */ - WPS_TOKEN_REPEAT_MODE, - WPS_TOKEN_PLAYBACK_STATUS, - /* Progressbar */ - WPS_TOKEN_PROGRESSBAR, -#ifdef HAVE_LCD_CHARCELLS - WPS_TOKEN_PLAYER_PROGRESSBAR, -#endif -#ifdef HAVE_LCD_BITMAP - /* Peakmeter */ - WPS_TOKEN_PEAKMETER, -#endif - - /* Current track */ - WPS_TOKEN_TRACK_ELAPSED_PERCENT, - WPS_TOKEN_TRACK_TIME_ELAPSED, - WPS_TOKEN_TRACK_TIME_REMAINING, - WPS_TOKEN_TRACK_LENGTH, - WPS_TOKEN_TRACK_STARTING, - WPS_TOKEN_TRACK_ENDING, - - /* Playlist */ - TOKEN_MARKER_PLAYLIST, - WPS_TOKEN_PLAYLIST_ENTRIES, - WPS_TOKEN_PLAYLIST_NAME, - WPS_TOKEN_PLAYLIST_POSITION, - WPS_TOKEN_PLAYLIST_SHUFFLE, - - - /* buttons */ - TOKEN_MARKER_MISC, - WPS_TOKEN_DRAW_INBUILTBAR, - WPS_TOKEN_LIST_TITLE_TEXT, - WPS_TOKEN_LIST_TITLE_ICON, - WPS_TOKEN_BUTTON_VOLUME, - WPS_TOKEN_LASTTOUCH, -#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) - /* Virtual LED */ - WPS_TOKEN_VLED_HDD, -#endif - /* Volume level */ - WPS_TOKEN_VOLUME, - WPS_TOKEN_VOLUMEBAR, - /* hold */ - WPS_TOKEN_MAIN_HOLD, -#ifdef HAS_REMOTE_BUTTON_HOLD - WPS_TOKEN_REMOTE_HOLD, -#endif - - /* Setting option */ - WPS_TOKEN_SETTING, - WPS_TOKEN_CURRENT_SCREEN, - WPS_TOKEN_LANG_IS_RTL, - - /* Recording Tokens */ - TOKEN_MARKER_RECORDING, - WPS_TOKEN_HAVE_RECORDING, - WPS_TOKEN_IS_RECORDING, - WPS_TOKEN_REC_FREQ, - WPS_TOKEN_REC_ENCODER, - WPS_TOKEN_REC_BITRATE, /* SWCODEC: MP3 bitrate, HWCODEC: MP3 "quality" */ - WPS_TOKEN_REC_MONO, - WPS_TOKEN_REC_SECONDS, - WPS_TOKEN_REC_MINUTES, - WPS_TOKEN_REC_HOURS, - - - /* Radio Tokens */ - TOKEN_MARKER_TUNER, - WPS_TOKEN_HAVE_TUNER, -#if CONFIG_TUNER - WPS_TOKEN_TUNER_TUNED, - WPS_TOKEN_TUNER_SCANMODE, - WPS_TOKEN_TUNER_STEREO, - WPS_TOKEN_TUNER_MINFREQ, /* changes based on "region" */ - WPS_TOKEN_TUNER_MAXFREQ, /* changes based on "region" */ - WPS_TOKEN_TUNER_CURFREQ, - WPS_TOKEN_PRESET_ID, /* "id" of this preset.. really the array element number */ - WPS_TOKEN_PRESET_NAME, - WPS_TOKEN_PRESET_FREQ, - WPS_TOKEN_PRESET_COUNT, - /* RDS tokens */ - WPS_TOKEN_HAVE_RDS, -#ifdef HAVE_RDS_CAP - WPS_TOKEN_RDS_NAME, - WPS_TOKEN_RDS_TEXT, -#endif -#endif /* CONFIG_TUNER */ - - - TOKEN_MARKER_END, /* this needs to be the last value in this enum */ -}; +#include "tag_table.h" struct wps_token { - unsigned char type; /* enough to store the token type */ - + enum skin_token_type 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; diff --git a/apps/gui/skin_engine/wps_debug.c b/apps/gui/skin_engine/wps_debug.c index 59e8542eff..2ab7e5ab4e 100644 --- a/apps/gui/skin_engine/wps_debug.c +++ b/apps/gui/skin_engine/wps_debug.c @@ -26,7 +26,6 @@ #include <stdio.h> #include <string.h> -#include "skin_buffer.h" #include "settings_list.h" #ifdef __PCTOOL__ #ifdef WPSEDITOR diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h index f3f83370f4..ec37560e79 100644 --- a/apps/gui/skin_engine/wps_internals.h +++ b/apps/gui/skin_engine/wps_internals.h @@ -24,6 +24,8 @@ #ifndef _WPS_ENGINE_INTERNALS_ #define _WPS_ENGINE_INTERNALS_ + + /* Timeout unit expressed in HZ. In WPS, all timeouts are given in seconds (possibly with a decimal fraction) but stored as integer values. E.g. 2.5 is stored as 25. This means 25 tenth of a second, i.e. 25 units. @@ -32,6 +34,8 @@ #define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* In TIMEOUT_UNIT's */ #include "skin_tokens.h" +#include "tag_table.h" +#include "skin_parser.h" /* TODO: sort this mess out */ @@ -40,19 +44,6 @@ #include "statusbar.h" #include "metadata.h" -/* constants used in line_type and as refresh_mode for wps_refresh */ -#define WPS_REFRESH_STATIC (1u<<0) /* line doesn't change over time */ -#define WPS_REFRESH_DYNAMIC (1u<<1) /* line may change (e.g. time flag) */ -#define WPS_REFRESH_SCROLL (1u<<2) /* line scrolls */ -#define WPS_REFRESH_PLAYER_PROGRESS (1u<<3) /* line contains a progress bar */ -#define WPS_REFRESH_PEAK_METER (1u<<4) /* line contains a peak meter */ -#define WPS_REFRESH_STATUSBAR (1u<<5) /* refresh statusbar */ -#define WPS_REFRESH_ALL (0xffffffffu) /* to refresh all line types */ - -/* to refresh only those lines that change over time */ -#define WPS_REFRESH_NON_STATIC (WPS_REFRESH_DYNAMIC| \ - WPS_REFRESH_PLAYER_PROGRESS| \ - WPS_REFRESH_PEAK_METER) /* alignments */ #define WPS_ALIGN_RIGHT 32 #define WPS_ALIGN_CENTER 64 @@ -82,16 +73,16 @@ struct gui_img { short int y; /* y-pos */ short int num_subimages; /* number of sub-images */ short int subimage_height; /* height of each sub-image */ - short int display; /* -1 for no display, 0..n to display a subimage */ struct bitmap bm; char label; bool loaded; /* load state */ bool always_display; /* not using the preload/display mechanism */ + int display; }; struct progressbar { - enum wps_token_type type; + enum skin_token_type type; struct viewport *vp; /* regular pb */ short x; @@ -105,8 +96,6 @@ struct progressbar { /*progressbar image*/ struct bitmap bm; bool have_bitmap_pb; - - bool draw; }; #endif @@ -157,45 +146,6 @@ enum wps_parse_error { PARSE_FAIL_LIMITS_EXCEEDED, }; - -/* Description of a subline on the WPS */ -struct skin_subline { - - /* Index of the first token for this subline in the token array. - Tokens of this subline end where tokens for the next subline - begin. */ - unsigned short first_token_idx; - unsigned short last_token_idx; - - /* Bit or'ed WPS_REFRESH_xxx */ - unsigned char line_type; - - /* How long the subline should be displayed, in 10ths of sec */ - unsigned char time_mult; - - /* pointer to the next subline in this line */ - struct skin_subline *next; -}; - -/* Description of a line on the WPS. A line is a set of sublines. - A subline is displayed for a certain amount of time. After that, - the next subline of the line is displayed. And so on. */ -struct skin_line { - - /* Linked list of all the sublines on this line, - * a line *must* have at least one subline so no need to add an extra pointer */ - struct skin_subline sublines; - /* pointer to the current subline */ - struct skin_subline *curr_subline; - - /* When the next subline of this line should be displayed - (absolute time value in ticks) */ - long subline_expire_time; - - /* pointer to the next line */ - struct skin_line *next; -}; - #define VP_DRAW_HIDEABLE 0x1 #define VP_DRAW_HIDDEN 0x2 #define VP_DRAW_WASHIDDEN 0x4 @@ -206,7 +156,6 @@ struct skin_line { #define VP_INFO_LABEL 0x80 struct skin_viewport { struct viewport vp; /* The LCD viewport struct */ - struct skin_line *lines; char hidden_flags; char label; unsigned start_fgcolour; @@ -236,9 +185,6 @@ 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 @@ -250,36 +196,50 @@ struct playlistviewer { #ifdef HAVE_TC_RAMCACHE struct mp3entry tempid3; #endif - struct { - enum wps_token_type tokens[MAX_PLAYLISTLINE_TOKENS]; - char strings[MAX_PLAYLISTLINE_STRINGS][MAX_PLAYLISTLINE_STRLEN]; - int count; - bool scroll; - } lines[2]; + struct skin_element *lines[2]; }; #ifdef HAVE_ALBUMART struct skin_albumart { /* Album art support */ - struct viewport *vp;/* The viewport this is in */ int x; int y; int width; int height; - bool draw; unsigned char xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT */ unsigned char yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */ unsigned char state; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */ + + struct viewport *vp; + int draw_handle; }; #endif + +struct line { + int timeout; /* if inside a line alternator */ + unsigned update_mode; +}; + +struct line_alternator { + int current_line; + unsigned long last_change_tick; +}; + +struct conditional { + int last_value; + struct wps_token *token; +}; + + /* wps_data this struct holds all necessary data which describes the viewable content of a wps */ struct wps_data { + struct skin_element *tree; #ifdef HAVE_LCD_BITMAP struct skin_token_list *images; struct skin_token_list *progressbars; @@ -291,16 +251,10 @@ struct wps_data #ifdef HAVE_TOUCHSCREEN struct skin_token_list *touchregions; #endif - struct skin_token_list *viewports; - struct skin_token_list *strings; #ifdef HAVE_ALBUMART struct skin_albumart *albumart; int playback_aa_slot; #endif - struct wps_token *tokens; - /* Total number of tokens in the WPS. During WPS parsing, this is - the index of the token being parsed. */ - int num_tokens; #ifdef HAVE_LCD_BITMAP bool peak_meter_enabled; diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c index 168b17fa38..8eb082d50f 100644 --- a/apps/gui/statusbar-skinned.c +++ b/apps/gui/statusbar-skinned.c @@ -27,6 +27,9 @@ #include "appevents.h" #include "screens.h" #include "screen_access.h" +#include "strlcpy.h" +#include "skin_parser.h" +#include "skin_buffer.h" #include "skin_engine/skin_engine.h" #include "skin_engine/wps_internals.h" #include "viewport.h" @@ -45,26 +48,55 @@ static struct wps_sync_data sb_skin_sync_data = { .do_full_update = false /* initial setup of wps_data */ static int update_delay = DEFAULT_UPDATE_DELAY; - -bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen) +struct wps_token *found_token; +static int set_title_worker(char* title, enum themable_icons icon, + struct wps_data *data, struct skin_element *root) { - int i; - bool retval = false; - for(i=0; i<sb_skin_data[screen].num_tokens; i++) + int retval = 0; + struct skin_element *element = root; + while (element) { - if (sb_skin_data[screen].tokens[i].type == WPS_TOKEN_LIST_TITLE_TEXT) + struct wps_token *token = NULL; + if (element->type == CONDITIONAL) + { + struct conditional *cond = (struct conditional *)element->data; + token = cond->token; + } + else if (element->type == TAG) + { + token = (struct wps_token *)element->data; + } + if (token) { - sb_skin_data[screen].tokens[i].value.data = title; - retval = true; + if (token->type == SKIN_TOKEN_LIST_TITLE_TEXT) + { + found_token = token; + token->value.data = title; + retval = 1; + } + else if (token->type == SKIN_TOKEN_LIST_TITLE_ICON) + { + /* Icon_NOICON == -1 which the skin engine wants at position 1, so + 2 */ + token->value.i = icon+2; + } } - else if (sb_skin_data[screen].tokens[i].type == WPS_TOKEN_LIST_TITLE_ICON) + if (element->children_count) { - /* Icon_NOICON == -1 which the skin engine wants at position 1, so + 2 */ - sb_skin_data[screen].tokens[i].value.i = icon+2; + int i; + for (i=0; i<element->children_count; i++) + retval |= set_title_worker(title, icon, data, element->children[i]); } + element = element->next; } return retval; } + +bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen) +{ + bool retval = set_title_worker(title, icon, &sb_skin_data[screen], + sb_skin_data[screen].tree) > 0; + return retval; +} void sb_skin_data_load(enum screen_type screen, const char *buf, bool isfile) @@ -75,18 +107,22 @@ void sb_skin_data_load(enum screen_type screen, const char *buf, bool isfile) success = buf && skin_data_load(screen, data, buf, isfile); if (success) - { /* hide the sb's default viewport because it has nasty effect with stuff + { + /* hide the sb's default viewport because it has nasty effect with stuff * not part of the statusbar, * hence .sbs's without any other vps are unsupported*/ struct skin_viewport *vp = find_viewport(VP_DEFAULT_LABEL, data); - struct skin_token_list *next_vp = data->viewports->next; - - if (!next_vp) - { /* no second viewport, let parsing fail */ - success = false; + struct skin_element *next_vp = data->tree->next; + + if (vp) + { + if (!next_vp) + { /* no second viewport, let parsing fail */ + success = false; + } + /* hide this viewport, forever */ + vp->hidden_flags = VP_NEVER_VISIBLE; } - /* hide this viewport, forever */ - vp->hidden_flags = VP_NEVER_VISIBLE; sb_set_info_vp(screen, VP_INFO_LABEL|VP_DEFAULT_LABEL); } @@ -135,7 +171,7 @@ bool sb_set_backdrop(enum screen_type screen, char* filename) else #endif buf_size = LCD_BACKDROP_BYTES; - sb_skin[screen].data->backdrop = skin_buffer_alloc(buf_size); + sb_skin[screen].data->backdrop = (char*)skin_buffer_alloc(buf_size); if (!sb_skin[screen].data->backdrop) return false; } @@ -150,6 +186,8 @@ void sb_skin_update(enum screen_type screen, bool force) { static long next_update[NB_SCREENS] = {0}; int i = screen; + if (!sb_skin_data[screen].wps_loaded) + return; if (TIME_AFTER(current_tick, next_update[i]) || force) { #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) @@ -158,7 +196,7 @@ void sb_skin_update(enum screen_type screen, bool force) if (lcd_active() || (i != SCREEN_MAIN)) #endif skin_update(&sb_skin[i], force? - WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); + SKIN_REFRESH_ALL : SKIN_REFRESH_NON_STATIC); next_update[i] = current_tick + update_delay; /* don't update too often */ sb_skin[SCREEN_MAIN].sync_data->do_full_update = false; } @@ -216,7 +254,30 @@ void sb_create_from_settings(enum screen_type screen) if (ptr2[0] && ptr2[0] != '-') /* from ui viewport setting */ { + char *comma = ptr; + int param_count = 0; len = snprintf(ptr, remaining, "%%ax%%Vi(-,%s)\n", ptr2); + /* The config put the colours at the end of the viewport, + * they need to be stripped for the skin code though */ + do { + param_count++; + comma = strchr(comma+1, ','); + + } while (comma && param_count < 6); + if (comma) + { + char *end = comma; + char fg[8], bg[8]; + int i = 0; + comma++; + while (*comma != ',') + fg[i++] = *comma++; + fg[i] = '\0'; comma++; i=0; + while (*comma != ')') + bg[i++] = *comma++; + bg[i] = '\0'; + len += snprintf(end, remaining-len, ") %%Vf(%s) %%Vb(%s)\n", fg, bg); + } } else { diff --git a/apps/gui/theme_settings.c b/apps/gui/theme_settings.c index f3628f60db..e9862eda3a 100644 --- a/apps/gui/theme_settings.c +++ b/apps/gui/theme_settings.c @@ -30,14 +30,21 @@ #include "settings.h" #include "wps.h" #include "file.h" +#include "buffer.h" #if CONFIG_TUNER #include "radio.h" #endif #include "skin_engine/skin_engine.h" -#include "skin_engine/skin_fonts.h" +#include "skin_buffer.h" #include "statusbar-skinned.h" #include "bootchart.h" +static char *skin_buffer = NULL; +void theme_init_buffer(void) +{ + skin_buffer = buffer_alloc(SKIN_BUFFER_SIZE); +} + /* call this after loading a .wps/.rwps or other skin files, so that the * skin buffer is reset properly @@ -71,9 +78,10 @@ void settings_apply_skins(void) { char buf[MAX_PATH]; /* re-initialize the skin buffer before we start reloading skins */ - skin_buffer_init(); enum screen_type screen = SCREEN_MAIN; unsigned int i; + + skin_buffer_init(skin_buffer, SKIN_BUFFER_SIZE); #ifdef HAVE_LCD_BITMAP skin_backdrop_init(); skin_font_init(); diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c index 7d79e5f04a..2b1cc9eb05 100644 --- a/apps/gui/viewport.c +++ b/apps/gui/viewport.c @@ -310,13 +310,6 @@ static void set_default_align_flags(struct viewport *vp) #endif /* HAVE_LCD_BITMAP */ #endif /* __PCTOOL__ */ -#ifdef HAVE_LCD_COLOR -#define ARG_STRING(_depth) ((_depth) == 2 ? "dddddgg":"dddddcc") -#else -#define ARG_STRING(_depth) "dddddgg" -#endif - - void viewport_set_fullscreen(struct viewport *vp, const enum screen_type screen) { @@ -416,81 +409,4 @@ int get_viewport_default_colour(enum screen_type screen, bool fgcolour) #endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */ } -const char* viewport_parse_viewport(struct viewport *vp, - enum screen_type screen, - const char *bufptr, - const char separator) -{ - /* parse the list to the viewport struct */ - const char *ptr = bufptr; - uint32_t set = 0; - - enum { - PL_X = 0, - PL_Y, - PL_WIDTH, - PL_HEIGHT, - PL_FONT, - }; - - if (!(ptr = parse_list("ddddd", &set, separator, ptr, - &vp->x, &vp->y, &vp->width, &vp->height, &vp->font))) - return NULL; - - /* X and Y *must* be set */ - if (!LIST_VALUE_PARSED(set, PL_X) || !LIST_VALUE_PARSED(set, PL_Y)) - return NULL; - /* check for negative values */ - if (vp->x < 0) - vp->x += screens[screen].lcdwidth; - if (vp->y < 0) - vp->y += screens[screen].lcdheight; - - /* fix defaults, - * and negative width/height which means "extend to edge minus value */ - if (!LIST_VALUE_PARSED(set, PL_WIDTH)) - vp->width = screens[screen].lcdwidth - vp->x; - else if (vp->width < 0) - vp->width = (vp->width + screens[screen].lcdwidth) - vp->x; - if (!LIST_VALUE_PARSED(set, PL_HEIGHT)) - vp->height = screens[screen].lcdheight - vp->y; - else if (vp->height < 0) - vp->height = (vp->height + screens[screen].lcdheight) - vp->y; - -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) - vp->fg_pattern = get_viewport_default_colour(screen, true); - vp->bg_pattern = get_viewport_default_colour(screen, false); -#endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */ - -#ifdef HAVE_LCD_COLOR - vp->lss_pattern = global_settings.lss_color; - vp->lse_pattern = global_settings.lse_color; - vp->lst_pattern = global_settings.lst_color; -#endif - - /* Validate the viewport dimensions - we know that the numbers are - non-negative integers, ignore bars and assume the viewport takes them - * into account */ - if ((vp->x >= screens[screen].lcdwidth) || - ((vp->x + vp->width) > screens[screen].lcdwidth) || - (vp->y >= screens[screen].lcdheight) || - ((vp->y + vp->height) > screens[screen].lcdheight)) - { - return NULL; - } - - /* Default to using the user font if the font was an invalid number or '-' - * font 1 is *always* the UI font for the current screen - * 2 is always the first extra font */ - if (!LIST_VALUE_PARSED(set, PL_FONT)) - vp->font = FONT_UI; - - /* Set the defaults for fields not user-specified */ - vp->drawmode = DRMODE_SOLID; -#ifndef __PCTOOL__ - set_default_align_flags(vp); -#endif - - return ptr; -} #endif diff --git a/apps/gui/viewport.h b/apps/gui/viewport.h index 943cac2451..51ab35e575 100644 --- a/apps/gui/viewport.h +++ b/apps/gui/viewport.h @@ -74,25 +74,4 @@ bool viewport_point_within_vp(const struct viewport *vp, #endif /* __PCTOOL__ */ -#ifdef HAVE_LCD_BITMAP - -/* - * Parse a viewport definition (vp_def), which looks like: - * - * Screens with depth > 1: - * X|Y|width|height|font|foregorund color|background color - * Screens with depth = 1: - * X|Y|width|height|font - * - * | is a separator and can be specified via the parameter - * - * Returns the pointer to the char after the last character parsed - * if everything went OK or NULL if an error happened (some values - * not specified in the definition) - */ -const char* viewport_parse_viewport(struct viewport *vp, - enum screen_type screen, - const char *vp_def, - const char separator); -#endif /* HAVE_LCD_BITMAP */ #endif /* __VIEWPORT_H__ */ diff --git a/apps/gui/wps.c b/apps/gui/wps.c index a582afa76b..7dca6454e0 100644 --- a/apps/gui/wps.c +++ b/apps/gui/wps.c @@ -175,7 +175,7 @@ void fade(bool fade_in, bool updatewps) if (updatewps) { FOR_NB_SCREENS(i) - skin_update(&gui_wps[i], WPS_REFRESH_NON_STATIC); + skin_update(&gui_wps[i], SKIN_REFRESH_NON_STATIC); } sleep(1); } @@ -191,7 +191,7 @@ void fade(bool fade_in, bool updatewps) if (updatewps) { FOR_NB_SCREENS(i) - skin_update(&gui_wps[i], WPS_REFRESH_NON_STATIC); + skin_update(&gui_wps[i], SKIN_REFRESH_NON_STATIC); } sleep(1); } @@ -212,7 +212,7 @@ void fade(bool fade_in, bool updatewps) static bool update_onvol_change(struct gui_wps * gwps) { - skin_update(gwps, WPS_REFRESH_NON_STATIC); + skin_update(gwps, SKIN_REFRESH_NON_STATIC); #ifdef HAVE_LCD_CHARCELLS splashf(0, "Vol: %3d dB", @@ -372,8 +372,8 @@ bool ffwd_rew(int button) FOR_NB_SCREENS(i) { skin_update(&gui_wps[i], - WPS_REFRESH_PLAYER_PROGRESS | - WPS_REFRESH_DYNAMIC); + SKIN_REFRESH_PLAYER_PROGRESS | + SKIN_REFRESH_DYNAMIC); } break; @@ -390,7 +390,7 @@ bool ffwd_rew(int button) #endif #ifdef HAVE_LCD_CHARCELLS FOR_NB_SCREENS(i) - skin_update(&gui_wps[i], WPS_REFRESH_ALL); + skin_update(&gui_wps[i], SKIN_REFRESH_ALL); #endif exit = true; break; @@ -662,7 +662,7 @@ static void gwps_enter_wps(void) display->backdrop_show(gwps->data->backdrop); #endif display->clear_display(); - skin_update(gwps, WPS_REFRESH_ALL); + skin_update(gwps, SKIN_REFRESH_ALL); #ifdef HAVE_TOUCHSCREEN skin_disarm_touchregions(gui_wps[i].data); @@ -1116,7 +1116,7 @@ long gui_wps_show(void) #endif { skin_update(&gui_wps[i], wps_sync_data.do_full_update ? - WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); + SKIN_REFRESH_ALL : SKIN_REFRESH_NON_STATIC); } } wps_sync_data.do_full_update = false; diff --git a/apps/main.c b/apps/main.c index f1f30ce2b5..6c6d09cbaa 100644 --- a/apps/main.c +++ b/apps/main.c @@ -357,6 +357,7 @@ static void init(void) tree_mem_init(); filetype_init(); playlist_init(); + theme_init_buffer(); #if CONFIG_CODEC != SWCODEC mp3_init( global_settings.volume, @@ -639,6 +640,7 @@ static void init(void) #if CONFIG_CODEC == SWCODEC tdspeed_init(); #endif /* CONFIG_CODEC == SWCODEC */ + theme_init_buffer(); #if CONFIG_CODEC != SWCODEC /* No buffer allocation (see buffer.c) may take place after the call to diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c index 2a4b344e3b..a64b1f8e47 100644 --- a/apps/menus/main_menu.c +++ b/apps/menus/main_menu.c @@ -48,7 +48,7 @@ #include "version.h" #include "time.h" #include "wps.h" -#include "skin_engine/skin_buffer.h" +#include "skin_buffer.h" static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG}; diff --git a/apps/misc.c b/apps/misc.c index bae8dfbd07..c378133ab2 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -937,142 +937,23 @@ int hex_to_rgb(const char* hex, int* color) #endif /* HAVE_LCD_COLOR */ #ifdef HAVE_LCD_BITMAP -/* A simplified scanf - used (at time of writing) by wps parsing functions. - - fmt - char array specifying the format of each list option. Valid values - are: d - int - s - string (sets pointer to string, without copying) - c - hex colour (RGB888 - e.g. ff00ff) - g - greyscale "colour" (0-3) - set_vals - if not NULL 1 is set in the bitplace if the item was read OK - 0 if not read. - first item is LSB, (max 32 items! ) - Stops parseing if an item is invalid unless the item == '-' - sep - list separator (e.g. ',' or '|') - str - string to parse, must be terminated by 0 or sep - ... - pointers to store the parsed values - - return value - pointer to char after parsed data, 0 if there was an error. - -*/ - /* '0'-'3' are ASCII 0x30 to 0x33 */ #define is0123(x) (((x) & 0xfc) == 0x30) -const char* parse_list(const char *fmt, uint32_t *set_vals, - const char sep, const char* str, ...) +bool parse_color(char *text, int *value) { - va_list ap; - const char* p = str, *f = fmt; - const char** s; - int* d; - bool set, is_negative; - int i=0; - - va_start(ap, str); - if (set_vals) - *set_vals = 0; - while (*fmt) - { - /* Check for separator, if we're not at the start */ - if (f != fmt) - { - if (*p != sep) - goto err; - p++; - } - set = false; - switch (*fmt++) - { - case 's': /* string - return a pointer to it (not a copy) */ - s = va_arg(ap, const char **); - - *s = p; - while (*p && *p != sep && *p != ')') - p++; - set = (s[0][0]!='-') && (s[0][1]!=sep && s[0][1]!=')') ; - break; - - case 'd': /* int */ - is_negative = false; - d = va_arg(ap, int*); - - if (*p == '-' && isdigit(*(p+1))) - { - is_negative = true; - p++; - } - if (!isdigit(*p)) - { - if (!set_vals || *p != '-') - goto err; - p++; - } - else - { - *d = *p++ - '0'; - while (isdigit(*p)) - *d = (*d * 10) + (*p++ - '0'); - set = true; - if (is_negative) - *d *= -1; - } - - break; - + (void)text; (void)value; /* silence warnings on mono bitmap */ #ifdef HAVE_LCD_COLOR - case 'c': /* colour (rrggbb - e.g. f3c1a8) */ - d = va_arg(ap, int*); - - if (hex_to_rgb(p, d) < 0) - { - if (!set_vals || *p != '-') - goto err; - p++; - } - else - { - p += 6; - set = true; - } - - break; + if (hex_to_rgb(text, value) < 0) + return false; #endif #if LCD_DEPTH == 2 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2) - case 'g': /* greyscale colour (0-3) */ - d = va_arg(ap, int*); - - if (!is0123(*p)) - { - if (!set_vals || *p != '-') - goto err; - p++; - } - else - { - *d = *p++ - '0'; - set = true; - } - - break; + if (!is0123(*text)) + return false; + *value = *text - '0'; #endif - - default: /* Unknown format type */ - goto err; - break; - } - if (set_vals && set) - *set_vals |= BIT_N(i); - i++; - } - - va_end(ap); - return p; - -err: - va_end(ap); - return NULL; + return true; } /* only used in USB HID and set_time screen */ diff --git a/apps/misc.h b/apps/misc.h index 34f754bda3..58a9085d55 100644 --- a/apps/misc.h +++ b/apps/misc.h @@ -94,16 +94,7 @@ bool dir_exists(const char *path); char *strip_extension(char* buffer, int buffer_size, const char *filename); #ifdef HAVE_LCD_BITMAP -/* A simplified scanf */ -/* - * Checks whether the value at position 'position' was really read - * during a call to 'parse_list' - * - position: 0-based number of the value - * - valid_vals: value after the call to 'parse_list' - */ -#define LIST_VALUE_PARSED(setvals, position) ((setvals) & BIT_N(position)) -const char* parse_list(const char *fmt, uint32_t *set_vals, - const char sep, const char* str, ...); +bool parse_color(char *text, int *value); /* only used in USB HID and set_time screen */ #if defined(USB_ENABLE_HID) || (CONFIG_RTC != 0) diff --git a/apps/radio/radio.c b/apps/radio/radio.c index 65a34f1d2a..17f3d89bfc 100644 --- a/apps/radio/radio.c +++ b/apps/radio/radio.c @@ -800,8 +800,8 @@ int radio_screen(void) if (restore) fms_fix_displays(FMS_ENTER); FOR_NB_SCREENS(i) - skin_update(fms_get(i), restore ? WPS_REFRESH_ALL : - WPS_REFRESH_NON_STATIC); + skin_update(fms_get(i), restore ? SKIN_REFRESH_ALL : + SKIN_REFRESH_NON_STATIC); restore = false; } } diff --git a/apps/recorder/albumart.h b/apps/recorder/albumart.h index 51f456d175..0f50979a1a 100644 --- a/apps/recorder/albumart.h +++ b/apps/recorder/albumart.h @@ -35,9 +35,11 @@ bool find_albumart(const struct mp3entry *id3, char *buf, int buflen, struct dim *dim); -/* Draw the album art bitmap from the given handle ID onto the given WPS. +#ifndef PLUGIN +/* Draw the album art bitmap from the given handle ID onto the given Skin. Call with clear = true to clear the bitmap instead of drawing it. */ void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear); +#endif bool search_albumart_files(const struct mp3entry *id3, const char *size_string, char *buf, int buflen); diff --git a/apps/settings.h b/apps/settings.h index 1cf43d9a2c..63305b5ae7 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -260,6 +260,7 @@ void sound_settings_apply(void); * skin buffer is reset properly */ void settings_apply_skins(void); +void theme_init_buffer(void); void settings_apply(bool read_disk); void settings_apply_pm_range(void); diff --git a/lib/skin_parser/SOURCES b/lib/skin_parser/SOURCES index 3024797255..37a6e9a03c 100644 --- a/lib/skin_parser/SOURCES +++ b/lib/skin_parser/SOURCES @@ -1,6 +1,6 @@ skin_buffer.c skin_parser.c -#ifndef ROCKBOX +#if !defined(ROCKBOX) || defined(__PCTOOL__) skin_debug.c #endif skin_scan.c diff --git a/lib/skin_parser/skin_buffer.c b/lib/skin_parser/skin_buffer.c index 05cdc0ce03..69d9d273bd 100644 --- a/lib/skin_parser/skin_buffer.c +++ b/lib/skin_parser/skin_buffer.c @@ -24,21 +24,19 @@ #include <string.h> #include <stdlib.h> +#include "skin_buffer.h" + #ifdef ROCKBOX -#define SKIN_BUFFER_SIZE (400*1024) /* Excessivly large for now */ -static unsigned char buffer[SKIN_BUFFER_SIZE]; -static unsigned char *buffer_front = NULL; /* start of the free space, - increases with allocation*/ +static size_t buf_size; +static unsigned char *buffer_start = NULL; +static unsigned char *buffer_front = NULL; #endif -void skin_buffer_init(void) +void skin_buffer_init(char* buffer, size_t size) { #if defined(ROCKBOX) - { - /* reset the buffer.... */ - buffer_front = buffer; - //TODO: buf_size = size; - } + buffer_start = buffer_front = buffer; + buf_size = size; #endif } @@ -46,7 +44,9 @@ void skin_buffer_init(void) void* skin_buffer_alloc(size_t size) { void *retval = NULL; -#ifdef ROCKBOX +#ifdef ROCKBOX + if (size > skin_buffer_freespace()) + return NULL; retval = buffer_front; buffer_front += size; /* 32-bit aligned */ @@ -62,10 +62,22 @@ void* skin_buffer_alloc(size_t size) /* get the number of bytes currently being used */ size_t skin_buffer_usage(void) { - return buffer_front - buffer; + return buffer_front - buffer_start; } size_t skin_buffer_freespace(void) { - return SKIN_BUFFER_SIZE - skin_buffer_usage(); + return buf_size - skin_buffer_usage(); +} + +static unsigned char *saved_buffer_pos = NULL; +void skin_buffer_save_position(void) +{ + saved_buffer_pos = buffer_front; +} + +void skin_buffer_restore_position(void) +{ + if (saved_buffer_pos) + buffer_front = saved_buffer_pos; } #endif diff --git a/lib/skin_parser/skin_buffer.h b/lib/skin_parser/skin_buffer.h index ff477da539..1698b8afb2 100644 --- a/lib/skin_parser/skin_buffer.h +++ b/lib/skin_parser/skin_buffer.h @@ -25,11 +25,15 @@ #include <stdlib.h> #ifndef _SKIN_BUFFFER_H_ #define _SKIN_BUFFFER_H_ -void skin_buffer_init(size_t size); +void skin_buffer_init(char* buffer, size_t size); /* Allocate size bytes from the buffer */ void* skin_buffer_alloc(size_t size); /* get the number of bytes currently being used */ size_t skin_buffer_usage(void); size_t skin_buffer_freespace(void); + +/* save and restore a buffer position incase a skin fails to load */ +void skin_buffer_save_position(void); +void skin_buffer_restore_position(void); #endif diff --git a/lib/skin_parser/skin_debug.c b/lib/skin_parser/skin_debug.c index c03b32e910..88ad209cce 100644 --- a/lib/skin_parser/skin_debug.c +++ b/lib/skin_parser/skin_debug.c @@ -35,6 +35,7 @@ extern char* skin_start; /* Global error variables */ int error_line; int error_col; +char *error_line_start; char* error_message; /* Debugging functions */ @@ -48,6 +49,7 @@ void skin_error(enum skin_errorcode error, char* cursor) cursor--; error_col++; } + error_line_start = cursor+1; error_line = skin_line; @@ -285,4 +287,42 @@ void skin_debug_indent() for(i = 0; i < debug_indent_level; i++) printf(" "); } + #endif + +#define MIN(a,b) ((a<b)?(a):(b)) +void skin_error_format_message() +{ + int i; + char text[128]; + char* line_end = strchr(error_line_start, '\n'); + int len = MIN(line_end - error_line_start, 80); + if (!line_end) + len = strlen(error_line_start); + printf("Error on line %d.\n", error_line); + error_col--; + if (error_col <= 10) + { + strncpy(text, error_line_start, len); + text[len] = '\0'; + } + else + { + int j; + /* make it fit nicely.. "<start few chars>...<10 chars><error>" */ + strncpy(text, error_line_start, 6); + i = 5; + text[i++] = '.'; + text[i++] = '.'; + text[i++] = '.'; + for (j=error_col-10; error_line_start[j] && error_line_start[j] != '\n'; j++) + text[i++] = error_line_start[j]; + text[i] = '\0'; + error_col = 18; + } + printf("%s\n", text); + for (i=0; i<error_col; i++) + text[i] = ' '; + snprintf(&text[i],64, "^ \'%s\' Here", error_message); + printf("%s\n", text); +} diff --git a/lib/skin_parser/skin_debug.h b/lib/skin_parser/skin_debug.h index fbff5cbb4c..c3538083d2 100644 --- a/lib/skin_parser/skin_debug.h +++ b/lib/skin_parser/skin_debug.h @@ -28,8 +28,12 @@ extern "C" { #endif +#if !defined(ROCKBOX) || defined(__PCTOOL__) +#define SKINPARSER_DEBUG +#endif + #include "skin_parser.h" -#ifndef ROCKBOX +#ifdef SKINPARSER_DEBUG /* Debugging functions */ void skin_error(enum skin_errorcode error, char* cursor); int skin_error_line(void); @@ -37,6 +41,7 @@ int skin_error_col(void); char* skin_error_message(void); void skin_clear_errors(void); void skin_debug_tree(struct skin_element* root); +void skin_error_format_message(); /* Auxiliary debug functions */ void skin_debug_params(int count, struct skin_tag_parameter params[]); @@ -46,7 +51,7 @@ void skin_debug_indent(void); #define skin_error(...) #define skin_clear_errors() -#endif /* !ROCKBOX */ +#endif /* SKINPARSER_DEBUG */ #ifdef __cplusplus diff --git a/lib/skin_parser/skin_parser.c b/lib/skin_parser/skin_parser.c index 3e23067258..13c7b55e5e 100644 --- a/lib/skin_parser/skin_parser.c +++ b/lib/skin_parser/skin_parser.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include <stdio.h> +#include <stdbool.h> #include <string.h> #include <ctype.h> #include <stdbool.h> @@ -37,6 +38,11 @@ int skin_line = 0; char* skin_start = 0; int viewport_line = 0; +#ifdef ROCKBOX +static skin_callback callback = NULL; +static void* callback_data; +#endif + /* Auxiliary parsing functions (not visible at global scope) */ static struct skin_element* skin_parse_viewport(char** document); static struct skin_element* skin_parse_line(char** document); @@ -55,10 +61,23 @@ static int skin_parse_comment(struct skin_element* element, char** document); static struct skin_element* skin_parse_code_as_arg(char** document); +static void skip_whitespace(char** document) +{ + while(**document == ' ' || **document == '\t') + (*document)++; +} +#ifdef ROCKBOX +struct skin_element* skin_parse(const char* document, + skin_callback cb, void* cb_data) + +{ + callback = cb; + callback_data = cb_data; +#else struct skin_element* skin_parse(const char* document) { - +#endif struct skin_element* root = NULL; struct skin_element* last = NULL; @@ -94,7 +113,6 @@ struct skin_element* skin_parse(const char* document) last = last->next; } - return root; } @@ -107,6 +125,8 @@ static struct skin_element* skin_parse_viewport(char** document) struct skin_element* retval = NULL; retval = skin_alloc_element(); + if (!retval) + return NULL; retval->type = VIEWPORT; retval->children_count = 1; retval->line = skin_line; @@ -129,11 +149,18 @@ static struct skin_element* skin_parse_viewport(char** document) skin_line++; } } +#ifdef ROCKBOX + else if (callback) + { + if (callback(retval, callback_data) == CALLBACK_ERROR) + return NULL; + } +#endif retval->children_count = 1; retval->children = skin_alloc_children(1); - - + if (!retval->children) + return NULL; do { @@ -199,7 +226,6 @@ static struct skin_element* skin_parse_viewport(char** document) return NULL; } - /* Making sure last is at the end */ while(last->next) last = last->next; @@ -245,6 +271,8 @@ static struct skin_element* skin_parse_line_optional(char** document, /* A wrapper for the line */ retval = skin_alloc_element(); + if (!retval) + return NULL; retval->type = LINE; retval->line = skin_line; if(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM @@ -261,7 +289,24 @@ static struct skin_element* skin_parse_line_optional(char** document, } if(retval->children_count > 0) + { retval->children = skin_alloc_children(1); + if (!retval->children) + return NULL; + } + +#ifdef ROCKBOX + if (callback) + { + switch (callback(retval, callback_data)) + { + case CALLBACK_ERROR: + return NULL; + default: + break; + } + } +#endif while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM && !((*cursor == ARGLISTSEPERATESYM @@ -275,11 +320,15 @@ static struct skin_element* skin_parse_line_optional(char** document, if(root) { current->next = skin_alloc_element(); + if (!current->next) + return NULL; current = current->next; } else { current = skin_alloc_element(); + if (!current) + return NULL; root = current; } @@ -306,9 +355,10 @@ static struct skin_element* skin_parse_line_optional(char** document, } } + /* Moving up the calling function's pointer */ *document = cursor; - + if(root) retval->children[0] = root; return retval; @@ -328,6 +378,8 @@ static struct skin_element* skin_parse_sublines_optional(char** document, int i; retval = skin_alloc_element(); + if (!retval) + return NULL; retval->type = LINE_ALTERNATOR; retval->next = NULL; retval->line = skin_line; @@ -374,6 +426,8 @@ static struct skin_element* skin_parse_sublines_optional(char** document, /* ...and then we parse them */ retval->children_count = sublines; retval->children = skin_alloc_children(sublines); + if (!retval->children) + return NULL; cursor = *document; for(i = 0; i < sublines; i++) @@ -392,6 +446,13 @@ static struct skin_element* skin_parse_sublines_optional(char** document, } } +#ifdef ROCKBOX + if (callback) + { + if (callback(retval, callback_data) == CALLBACK_ERROR) + return NULL; + } +#endif *document = cursor; return retval; @@ -458,6 +519,14 @@ static int skin_parse_tag(struct skin_element* element, char** document) || (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM) || (star && *cursor != ARGLISTOPENSYM)) { + +#ifdef ROCKBOX + if (callback) + { + if (callback(element, callback_data) == CALLBACK_ERROR) + return 0; + } +#endif *document = cursor; return 1; } @@ -507,6 +576,8 @@ static int skin_parse_tag(struct skin_element* element, char** document) cursor = bookmark; /* Restoring the cursor */ element->params_count = num_args; element->params = skin_alloc_params(num_args); + if (!element->params) + return 0; /* Now we have to actually parse each argument */ for(i = 0; i < num_args; i++) @@ -587,7 +658,6 @@ static int skin_parse_tag(struct skin_element* element, char** document) } if (have_tenth == false) val *= 10; - element->params[i].type = DECIMAL; element->params[i].data.number = val; } @@ -644,7 +714,13 @@ static int skin_parse_tag(struct skin_element* element, char** document) skin_error(INSUFFICIENT_ARGS, cursor); return 0; } - +#ifdef ROCKBOX + if (callback) + { + if (callback(element, callback_data) == CALLBACK_ERROR) + return 0; + } +#endif *document = cursor; return 1; @@ -691,6 +767,8 @@ static int skin_parse_text(struct skin_element* element, char** document, element->line = skin_line; element->next = NULL; element->data = text = skin_alloc_string(length); + if (!element->data) + return 0; for(dest = 0; dest < length; dest++) { @@ -702,6 +780,14 @@ static int skin_parse_text(struct skin_element* element, char** document, cursor++; } text[length] = '\0'; + +#ifdef ROCKBOX + if (callback) + { + if (callback(element, callback_data) == CALLBACK_ERROR) + return 0; + } +#endif *document = cursor; @@ -715,14 +801,40 @@ static int skin_parse_conditional(struct skin_element* element, char** document) char* bookmark; int children = 1; int i; + +#ifdef ROCKBOX + bool feature_available = true; + char *false_branch = NULL; +#endif - element->type = CONDITIONAL; + /* Some conditional tags allow for target feature checking, + * so to handle that call the callback as usual with type == TAG + * then call it a second time with type == CONDITIONAL and check the return + * value */ + element->type = TAG; element->line = skin_line; /* Parsing the tag first */ if(!skin_parse_tag(element, &cursor)) return 0; + element->type = CONDITIONAL; +#ifdef ROCKBOX + if (callback) + { + switch (callback(element, callback_data)) + { + case FEATURE_NOT_AVAILABLE: + feature_available = false; + break; + case CALLBACK_ERROR: + return 0; + default: + break; + } + } +#endif + /* Counting the children */ if(*(cursor++) != ENUMLISTOPENSYM) { @@ -751,16 +863,35 @@ static int skin_parse_conditional(struct skin_element* element, char** document) { children++; cursor++; +#ifdef ROCKBOX + if (false_branch == NULL && !feature_available) + { + false_branch = cursor; + children--; + } +#endif } else { cursor++; } } +#ifdef ROCKBOX + if (*cursor == ENUMLISTCLOSESYM && + false_branch == NULL && !feature_available) + { + false_branch = cursor+1; + children--; + } + /* if we are skipping the true branch fix that up */ + cursor = false_branch ? false_branch : bookmark; +#else cursor = bookmark; - +#endif /* Parsing the children */ element->children = skin_alloc_children(children); + if (!element->children) + return 0; element->children_count = children; for(i = 0; i < children; i++) @@ -809,6 +940,8 @@ static int skin_parse_comment(struct skin_element* element, char** document) element->data = NULL; #else element->data = text = skin_alloc_string(length); + if (!element->data) + return 0; /* We copy from one char past cursor to leave out the # */ memcpy((void*)text, (void*)(cursor + 1), sizeof(char) * (length-1)); @@ -877,6 +1010,8 @@ struct skin_element* skin_alloc_element() { struct skin_element* retval = (struct skin_element*) skin_buffer_alloc(sizeof(struct skin_element)); + if (!retval) + return NULL; retval->type = UNKNOWN; retval->next = NULL; retval->tag = NULL; @@ -886,9 +1021,21 @@ struct skin_element* skin_alloc_element() return retval; } - +/* On a ROCKBOX build we try to save space as much as possible + * so if we can, use a shared param pool which should be more then large + * enough for any tag. params should be used straight away by the callback + * so this is safe. + */ struct skin_tag_parameter* skin_alloc_params(int count) { +#ifdef ROCKBOX + static struct skin_tag_parameter params[MAX_TAG_PARAMS]; + if (count <= MAX_TAG_PARAMS) + { + memset(params, 0, sizeof(params)); + return params; + } +#endif size_t size = sizeof(struct skin_tag_parameter) * count; return (struct skin_tag_parameter*)skin_buffer_alloc(size); diff --git a/lib/skin_parser/skin_parser.h b/lib/skin_parser/skin_parser.h index ad10f90125..8514dfdd0e 100644 --- a/lib/skin_parser/skin_parser.h +++ b/lib/skin_parser/skin_parser.h @@ -115,14 +115,27 @@ struct skin_element struct skin_element* next; }; +enum skin_cb_returnvalue +{ + CALLBACK_ERROR = -666, + FEATURE_NOT_AVAILABLE, + CALLBACK_OK = 0, + /* > 0 reserved for future use */ +}; +typedef int (*skin_callback)(struct skin_element* element, void* data); + /*********************************************************************** ***** Functions ******************************************************* **********************************************************************/ /* Parses a WPS document and returns a list of skin_element structures. */ +#ifdef ROCKBOX +struct skin_element* skin_parse(const char* document, + skin_callback callback, void* callback_data); +#else struct skin_element* skin_parse(const char* document); - +#endif /* Memory management functions */ struct skin_element* skin_alloc_element(void); struct skin_element** skin_alloc_children(int count); diff --git a/lib/skin_parser/skin_scan.c b/lib/skin_parser/skin_scan.c index 6b5c189b9f..d18f2224b3 100644 --- a/lib/skin_parser/skin_scan.c +++ b/lib/skin_parser/skin_scan.c @@ -40,12 +40,6 @@ void skip_comment(char** document) (*document)++; } -void skip_whitespace(char** document) -{ - while(**document == ' ' || **document == '\t') - (*document)++; -} - void skip_arglist(char** document) { if(**document == ARGLISTOPENSYM) @@ -132,6 +126,8 @@ char* scan_string(char** document) /* Copying the string */ cursor = *document; buffer = skin_alloc_string(length); + if (!buffer) + return NULL; buffer[length] = '\0'; for(i = 0; i < length; i++) { diff --git a/lib/skin_parser/skin_scan.h b/lib/skin_parser/skin_scan.h index b1d04a6e34..72d4475767 100644 --- a/lib/skin_parser/skin_scan.h +++ b/lib/skin_parser/skin_scan.h @@ -30,7 +30,6 @@ extern "C" /* Scanning functions */ void skip_comment(char** document); -void skip_whitespace(char** document); void skip_arglist(char** document); void skip_enumlist(char** document); char* scan_string(char** document); diff --git a/lib/skin_parser/tag_table.c b/lib/skin_parser/tag_table.c index dd8df63997..a7e3378d24 100644 --- a/lib/skin_parser/tag_table.c +++ b/lib/skin_parser/tag_table.c @@ -33,182 +33,181 @@ struct tag_info legal_tags[] = { SKIN_TOKEN_ALIGN_RIGHT_RTL, "aR", "", 0 }, { SKIN_TOKEN_ALIGN_LANGDIRECTION, "ax", "", 0 }, - { SKIN_TOKEN_BATTERY_PERCENT, "bl" , BAR_PARAMS, 0 }, - { SKIN_TOKEN_BATTERY_VOLTS, "bv", "", 0 }, - { SKIN_TOKEN_BATTERY_TIME, "bt", "", 0 }, - { SKIN_TOKEN_BATTERY_SLEEPTIME, "bs", "", 0 }, - { SKIN_TOKEN_BATTERY_CHARGING, "bc", "", 0 }, - { SKIN_TOKEN_BATTERY_CHARGER_CONNECTED, "bp", "", 0 }, - { SKIN_TOKEN_USB_POWERED, "bu", "", 0 }, - - - { SKIN_TOKEN_RTC_PRESENT, "cc", "", 0 }, - { SKIN_TOKEN_RTC_DAY_OF_MONTH, "cd", "", 0 }, - { SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, "ce", "", 0 }, - { SKIN_TOKEN_RTC_12HOUR_CFG, "cf", "", 0 }, - { SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", "", 0 }, - { SKIN_TOKEN_RTC_HOUR_24, "ck", "", 0 }, - { SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", "", 0 }, - { SKIN_TOKEN_RTC_HOUR_12, "cl", "", 0 }, - { SKIN_TOKEN_RTC_MONTH, "cm", "", 0 }, - { SKIN_TOKEN_RTC_MINUTE, "cM", "", 0 }, - { SKIN_TOKEN_RTC_SECOND, "cS", "", 0 }, - { SKIN_TOKEN_RTC_YEAR_2_DIGITS, "cy", "", 0 }, - { SKIN_TOKEN_RTC_YEAR_4_DIGITS, "cY", "", 0 }, - { SKIN_TOKEN_RTC_AM_PM_UPPER, "cP", "", 0 }, - { SKIN_TOKEN_RTC_AM_PM_LOWER, "cp", "", 0 }, - { SKIN_TOKEN_RTC_WEEKDAY_NAME, "ca", "", 0 }, - { SKIN_TOKEN_RTC_MONTH_NAME, "cb", "", 0 }, - { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", "", 0 }, - { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", "", 0 }, + { SKIN_TOKEN_BATTERY_PERCENT, "bl" , BAR_PARAMS, SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_BATTERY_VOLTS, "bv", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_BATTERY_TIME, "bt", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_BATTERY_SLEEPTIME, "bs", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_BATTERY_CHARGING, "bc", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_BATTERY_CHARGER_CONNECTED, "bp", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_USB_POWERED, "bu", "", SKIN_REFRESH_DYNAMIC }, + + + { SKIN_TOKEN_RTC_PRESENT, "cc", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_RTC_DAY_OF_MONTH, "cd", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, "ce", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_12HOUR_CFG, "cf", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_HOUR_24, "ck", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_HOUR_12, "cl", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_MONTH, "cm", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_MINUTE, "cM", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_SECOND, "cS", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_YEAR_2_DIGITS, "cy", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_YEAR_4_DIGITS, "cY", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_AM_PM_UPPER, "cP", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_AM_PM_LOWER, "cp", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_WEEKDAY_NAME, "ca", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_MONTH_NAME, "cb", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", "", SKIN_RTC_REFRESH }, + { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", "", SKIN_RTC_REFRESH }, - { SKIN_TOKEN_FILE_BITRATE, "fb", "", 0 }, - { SKIN_TOKEN_FILE_CODEC, "fc", "", 0 }, - { SKIN_TOKEN_FILE_FREQUENCY, "ff", "", 0 }, - { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "fk", "", 0 }, - { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", "", 0 }, - { SKIN_TOKEN_FILE_NAME, "fn", "", 0 }, - { SKIN_TOKEN_FILE_PATH, "fp", "", 0 }, - { SKIN_TOKEN_FILE_SIZE, "fs", "", 0 }, - { SKIN_TOKEN_FILE_VBR, "fv", "", 0 }, - { SKIN_TOKEN_FILE_DIRECTORY, "d" , "I", 0 }, - - { SKIN_TOKEN_FILE_BITRATE, "Fb", "", 0 }, - { SKIN_TOKEN_FILE_CODEC, "Fc", "", 0 }, - { SKIN_TOKEN_FILE_FREQUENCY, "Ff", "", 0 }, - { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "Fk", "", 0 }, - { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", "", 0 }, - { SKIN_TOKEN_FILE_NAME, "Fn", "", 0 }, - { SKIN_TOKEN_FILE_PATH, "Fp", "", 0 }, - { SKIN_TOKEN_FILE_SIZE, "Fs", "", 0 }, - { SKIN_TOKEN_FILE_VBR, "Fv", "", 0 }, - { SKIN_TOKEN_FILE_DIRECTORY, "D" , "I", 0 }, - - - { SKIN_TOKEN_METADATA_ARTIST, "ia", "", 0 }, - { SKIN_TOKEN_METADATA_COMPOSER, "ic", "", 0 }, - { SKIN_TOKEN_METADATA_ALBUM, "id", "", 0 }, - { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "iA", "", 0 }, - { SKIN_TOKEN_METADATA_GROUPING, "iG", "", 0 }, - { SKIN_TOKEN_METADATA_GENRE, "ig", "", 0 }, - { SKIN_TOKEN_METADATA_DISC_NUMBER, "ik", "", 0 }, - { SKIN_TOKEN_METADATA_TRACK_NUMBER, "in", "", 0 }, - { SKIN_TOKEN_METADATA_TRACK_TITLE, "it", "", 0 }, - { SKIN_TOKEN_METADATA_VERSION, "iv", "", 0 }, - { SKIN_TOKEN_METADATA_YEAR, "iy", "", 0 }, - { SKIN_TOKEN_METADATA_COMMENT, "iC", "", 0 }, - - { SKIN_TOKEN_METADATA_ARTIST, "Ia", "", 0 }, - { SKIN_TOKEN_METADATA_COMPOSER, "Ic", "", 0 }, - { SKIN_TOKEN_METADATA_ALBUM, "Id", "", 0 }, - { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "IA", "", 0 }, - { SKIN_TOKEN_METADATA_GROUPING, "IG", "", 0 }, - { SKIN_TOKEN_METADATA_GENRE, "Ig", "", 0 }, - { SKIN_TOKEN_METADATA_DISC_NUMBER, "Ik", "", 0 }, - { SKIN_TOKEN_METADATA_TRACK_NUMBER, "In", "", 0 }, - { SKIN_TOKEN_METADATA_TRACK_TITLE, "It", "", 0 }, - { SKIN_TOKEN_METADATA_VERSION, "Iv", "", 0 }, - { SKIN_TOKEN_METADATA_YEAR, "Iy", "", 0 }, - { SKIN_TOKEN_METADATA_COMMENT, "IC", "", 0 }, - - { SKIN_TOKEN_SOUND_PITCH, "Sp", "", 0 }, - { SKIN_TOKEN_SOUND_SPEED, "Ss", "", 0 }, - - { SKIN_TOKEN_VLED_HDD, "lh", "", 0 }, - - { SKIN_TOKEN_MAIN_HOLD, "mh", "", 0 }, - { SKIN_TOKEN_REMOTE_HOLD, "mr", "", 0 }, - { SKIN_TOKEN_REPEAT_MODE, "mm", "", 0 }, - { SKIN_TOKEN_PLAYBACK_STATUS, "mp", "", 0 }, - { SKIN_TOKEN_BUTTON_VOLUME, "mv", "|D", 0 }, - - { SKIN_TOKEN_PEAKMETER, "pm", "", 0 }, - { SKIN_TOKEN_PLAYER_PROGRESSBAR, "pf", "", 0 }, - { SKIN_TOKEN_PROGRESSBAR, "pb" , BAR_PARAMS, 0 }, - { SKIN_TOKEN_VOLUME, "pv" , BAR_PARAMS, 0 }, - - { SKIN_TOKEN_TRACK_ELAPSED_PERCENT, "px", "", 0 }, - { SKIN_TOKEN_TRACK_TIME_ELAPSED, "pc", "", 0 }, - { SKIN_TOKEN_TRACK_TIME_REMAINING, "pr", "", 0 }, - { SKIN_TOKEN_TRACK_LENGTH, "pt", "", 0 }, - { SKIN_TOKEN_TRACK_STARTING, "pS" , "|D", 0 }, - { SKIN_TOKEN_TRACK_ENDING, "pE" , "|D", 0 }, - { SKIN_TOKEN_PLAYLIST_POSITION, "pp", "", 0 }, - { SKIN_TOKEN_PLAYLIST_ENTRIES, "pe", "", 0 }, - { SKIN_TOKEN_PLAYLIST_NAME, "pn", "", 0 }, - { SKIN_TOKEN_PLAYLIST_SHUFFLE, "ps", "", 0 }, - - { SKIN_TOKEN_DATABASE_PLAYCOUNT, "rp", "", 0 }, - { SKIN_TOKEN_DATABASE_RATING, "rr", "", 0 }, - { SKIN_TOKEN_DATABASE_AUTOSCORE, "ra", "", 0 }, - - { SKIN_TOKEN_REPLAYGAIN, "rg", "", 0 }, - { SKIN_TOKEN_CROSSFADE, "xf", "", 0 }, - - { SKIN_TOKEN_HAVE_TUNER, "tp", "", 0 }, - { SKIN_TOKEN_TUNER_TUNED, "tt", "", 0 }, - { SKIN_TOKEN_TUNER_SCANMODE, "tm", "", 0 }, - { SKIN_TOKEN_TUNER_STEREO, "ts", "", 0 }, - { SKIN_TOKEN_TUNER_MINFREQ, "ta", "", 0 }, - { SKIN_TOKEN_TUNER_MAXFREQ, "tb", "", 0 }, - { SKIN_TOKEN_TUNER_CURFREQ, "tf", "", 0 }, - { SKIN_TOKEN_PRESET_ID, "Ti", "", 0 }, - { SKIN_TOKEN_PRESET_NAME, "Tn", "", 0 }, - { SKIN_TOKEN_PRESET_FREQ, "Tf", "", 0 }, - { SKIN_TOKEN_PRESET_COUNT, "Tc", "", 0 }, - { SKIN_TOKEN_HAVE_RDS, "tx", "", 0 }, - { SKIN_TOKEN_RDS_NAME, "ty", "", 0 }, - { SKIN_TOKEN_RDS_TEXT, "tz", "", 0 }, - - { SKIN_TOKEN_SUBLINE_SCROLL, "s", "", 0 }, + { SKIN_TOKEN_FILE_BITRATE, "fb", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_CODEC, "fc", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_FREQUENCY, "ff", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "fk", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_NAME, "fn", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_PATH, "fp", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_SIZE, "fs", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_VBR, "fv", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_DIRECTORY, "d" , "I", SKIN_REFRESH_STATIC }, + + { SKIN_TOKEN_FILE_BITRATE, "Fb", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_CODEC, "Fc", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_FREQUENCY, "Ff", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "Fk", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_NAME, "Fn", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_PATH, "Fp", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_SIZE, "Fs", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_VBR, "Fv", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_FILE_DIRECTORY, "D" , "I", SKIN_REFRESH_STATIC }, + + + { SKIN_TOKEN_METADATA_ARTIST, "ia", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_COMPOSER, "ic", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_ALBUM, "id", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "iA", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_GROUPING, "iG", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_GENRE, "ig", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_DISC_NUMBER, "ik", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_TRACK_NUMBER, "in", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_TRACK_TITLE, "it", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_VERSION, "iv", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_YEAR, "iy", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_COMMENT, "iC", "", SKIN_REFRESH_STATIC }, + + { SKIN_TOKEN_METADATA_ARTIST, "Ia", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_COMPOSER, "Ic", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_ALBUM, "Id", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "IA", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_GROUPING, "IG", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_GENRE, "Ig", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_DISC_NUMBER, "Ik", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_TRACK_NUMBER, "In", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_TRACK_TITLE, "It", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_VERSION, "Iv", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_YEAR, "Iy", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_METADATA_COMMENT, "IC", "", SKIN_REFRESH_STATIC }, + + { SKIN_TOKEN_SOUND_PITCH, "Sp", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_SOUND_SPEED, "Ss", "", SKIN_REFRESH_DYNAMIC }, + + { SKIN_TOKEN_VLED_HDD, "lh", "", SKIN_REFRESH_DYNAMIC }, + + { SKIN_TOKEN_MAIN_HOLD, "mh", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REMOTE_HOLD, "mr", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REPEAT_MODE, "mm", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_PLAYBACK_STATUS, "mp", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_BUTTON_VOLUME, "mv", "|D", SKIN_REFRESH_DYNAMIC }, + + { SKIN_TOKEN_PEAKMETER, "pm", "", SKIN_REFRESH_PEAK_METER }, + { SKIN_TOKEN_PLAYER_PROGRESSBAR, "pf", "", SKIN_REFRESH_DYNAMIC|SKIN_REFRESH_PLAYER_PROGRESS }, + { SKIN_TOKEN_PROGRESSBAR, "pb" , BAR_PARAMS, SKIN_REFRESH_PLAYER_PROGRESS }, + { SKIN_TOKEN_VOLUME, "pv" , BAR_PARAMS, SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TRACK_ELAPSED_PERCENT, "px", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TRACK_TIME_ELAPSED, "pc", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TRACK_TIME_REMAINING, "pr", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TRACK_LENGTH, "pt", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_TRACK_STARTING, "pS" , "|D", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TRACK_ENDING, "pE" , "|D", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_PLAYLIST_POSITION, "pp", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_PLAYLIST_ENTRIES, "pe", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_PLAYLIST_NAME, "pn", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_PLAYLIST_SHUFFLE, "ps", "", SKIN_REFRESH_DYNAMIC }, + + { SKIN_TOKEN_DATABASE_PLAYCOUNT, "rp", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_DATABASE_RATING, "rr", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_DATABASE_AUTOSCORE, "ra", "", SKIN_REFRESH_DYNAMIC }, + + { SKIN_TOKEN_REPLAYGAIN, "rg", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_CROSSFADE, "xf", "", SKIN_REFRESH_DYNAMIC }, + + { SKIN_TOKEN_HAVE_TUNER, "tp", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_TUNER_TUNED, "tt", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TUNER_SCANMODE, "tm", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TUNER_STEREO, "ts", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TUNER_MINFREQ, "ta", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_TUNER_MAXFREQ, "tb", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_TUNER_CURFREQ, "tf", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_PRESET_ID, "Ti", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_PRESET_NAME, "Tn", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_PRESET_FREQ, "Tf", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_PRESET_COUNT, "Tc", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_HAVE_RDS, "tx", "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_RDS_NAME, "ty", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_RDS_TEXT, "tz", "", SKIN_REFRESH_DYNAMIC }, + + { SKIN_TOKEN_SUBLINE_SCROLL, "s", "", SKIN_REFRESH_SCROLL }, { SKIN_TOKEN_SUBLINE_TIMEOUT, "t" , "D", 0 }, + + { SKIN_TOKEN_ENABLE_THEME, "we", "", 0|NOBREAK }, + { SKIN_TOKEN_DISABLE_THEME, "wd", "", 0|NOBREAK }, + { SKIN_TOKEN_DRAW_INBUILTBAR, "wi", "", SKIN_REFRESH_STATIC|NOBREAK }, - { SKIN_TOKEN_ENABLE_THEME, "we", "", NOBREAK }, - { SKIN_TOKEN_DISABLE_THEME, "wd", "", NOBREAK }, - { SKIN_TOKEN_DRAW_INBUILTBAR, "wi", "", NOBREAK }, - - { SKIN_TOKEN_IMAGE_PRELOAD, "xl", "SFII|I", NOBREAK }, + { SKIN_TOKEN_IMAGE_PRELOAD, "xl", "SFII|I", 0|NOBREAK }, { SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", "S", 0 }, - { SKIN_TOKEN_IMAGE_PRELOAD, "x", "SFII", NOBREAK }, + { SKIN_TOKEN_IMAGE_DISPLAY, "x", "SFII", 0|NOBREAK }, - { SKIN_TOKEN_LOAD_FONT, "Fl" , "IF", NOBREAK }, - { SKIN_TOKEN_ALBUMART_LOAD, "Cl" , "IIII|ss", NOBREAK }, - { SKIN_TOKEN_ALBUMART_DISPLAY, "Cd" , "", 0 }, - { SKIN_TOKEN_ALBUMART_FOUND, "C" , "", 0 }, + { SKIN_TOKEN_LOAD_FONT, "Fl" , "IF", 0|NOBREAK }, + { SKIN_TOKEN_ALBUMART_LOAD, "Cl" , "IIII|ss", 0|NOBREAK }, + { SKIN_TOKEN_ALBUMART_DISPLAY, "Cd" , "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_ALBUMART_FOUND, "C" , "", SKIN_REFRESH_STATIC }, - { SKIN_TOKEN_VIEWPORT_ENABLE, "Vd" , "S", 0 }, - { SKIN_TOKEN_UIVIEWPORT_ENABLE, "VI" , "S", 0 }, + { SKIN_TOKEN_VIEWPORT_ENABLE, "Vd" , "S", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_UIVIEWPORT_ENABLE, "VI" , "S", SKIN_REFRESH_STATIC }, - { SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "ICC", NOBREAK }, - { SKIN_TOKEN_LIST_TITLE_TEXT, "Lt" , "", 0 }, - { SKIN_TOKEN_LIST_TITLE_ICON, "Li" , "", 0 }, + { SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "ICC", SKIN_REFRESH_DYNAMIC|NOBREAK }, + { SKIN_TOKEN_LIST_TITLE_TEXT, "Lt" , "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_LIST_TITLE_ICON, "Li" , "", SKIN_REFRESH_DYNAMIC }, - { SKIN_TOKEN_VIEWPORT_FGCOLOUR, "Vf" , "S", NOBREAK }, - { SKIN_TOKEN_VIEWPORT_BGCOLOUR, "Vb" , "S", NOBREAK }, + { SKIN_TOKEN_VIEWPORT_FGCOLOUR, "Vf" , "s", SKIN_REFRESH_STATIC|NOBREAK }, + { SKIN_TOKEN_VIEWPORT_BGCOLOUR, "Vb" , "s", SKIN_REFRESH_STATIC|NOBREAK }, { SKIN_TOKEN_VIEWPORT_CONDITIONAL, "Vl" , "SIIiii", 0 }, { SKIN_TOKEN_UIVIEWPORT_LOAD, "Vi" , "sIIiii", 0 }, { SKIN_TOKEN_VIEWPORT_LOAD, "V" , "IIiii", 0 }, - { SKIN_TOKEN_IMAGE_BACKDROP, "X" , "f", NOBREAK }, - - { SKIN_TOKEN_SETTING, "St" , "S", 0 }, - { SKIN_TOKEN_TRANSLATEDSTRING, "Sx" , "S", 0 }, - { SKIN_TOKEN_LANG_IS_RTL, "Sr" , "", 0 }, - - { SKIN_TOKEN_LASTTOUCH, "Tl" , "|D", 0 }, - { SKIN_TOKEN_CURRENT_SCREEN, "cs", "", 0 }, - { SKIN_TOKEN_TOUCHREGION, "T" , "IIiiS", NOBREAK }, - - { SKIN_TOKEN_HAVE_RECORDING, "Rp" , "", 0 }, - { SKIN_TOKEN_IS_RECORDING, "Rr" , "", 0 }, - { SKIN_TOKEN_REC_FREQ, "Rf" , "", 0 }, - { SKIN_TOKEN_REC_ENCODER, "Re" , "", 0 }, - { SKIN_TOKEN_REC_BITRATE, "Rb" , "", 0 }, - { SKIN_TOKEN_REC_MONO, "Rm" , "", 0 }, - { SKIN_TOKEN_REC_SECONDS, "Rs" , "", 0 }, - { SKIN_TOKEN_REC_MINUTES, "Rn" , "", 0 }, - { SKIN_TOKEN_REC_HOURS, "Rh" , "", 0 }, + { SKIN_TOKEN_IMAGE_BACKDROP, "X" , "f", SKIN_REFRESH_STATIC|NOBREAK }, + + { SKIN_TOKEN_SETTING, "St" , "S", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TRANSLATEDSTRING, "Sx" , "S", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_LANG_IS_RTL, "Sr" , "", SKIN_REFRESH_STATIC }, + + { SKIN_TOKEN_LASTTOUCH, "Tl" , "|D", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_CURRENT_SCREEN, "cs", "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_TOUCHREGION, "T" , "IIiiS", 0|NOBREAK }, + + { SKIN_TOKEN_HAVE_RECORDING, "Rp" , "", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_IS_RECORDING, "Rr" , "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REC_FREQ, "Rf" , "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REC_ENCODER, "Re" , "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REC_BITRATE, "Rb" , "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REC_MONO, "Rm" , "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REC_SECONDS, "Rs" , "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REC_MINUTES, "Rn" , "", SKIN_REFRESH_DYNAMIC }, + { SKIN_TOKEN_REC_HOURS, "Rh" , "", SKIN_REFRESH_DYNAMIC }, { SKIN_TOKEN_UNKNOWN, "" , "", 0 } /* Keep this here to mark the end of the table */ diff --git a/lib/skin_parser/tag_table.h b/lib/skin_parser/tag_table.h index f84d4ac762..dde1487d13 100644 --- a/lib/skin_parser/tag_table.h +++ b/lib/skin_parser/tag_table.h @@ -27,12 +27,31 @@ extern "C" { #endif +#define MAX_TAG_PARAMS 12 + + /* Flag to tell the renderer not to insert a line break */ #define NOBREAK 0x1 +/* constants used in line_type and as refresh_mode for wps_refresh */ +#define SKIN_REFRESH_SHIFT 16 +#define SKIN_REFRESH_STATIC (1u<<SKIN_REFRESH_SHIFT) /* line doesn't change over time */ +#define SKIN_REFRESH_DYNAMIC (1u<<(SKIN_REFRESH_SHIFT+1)) /* line may change (e.g. time flag) */ +#define SKIN_REFRESH_SCROLL (1u<<(SKIN_REFRESH_SHIFT+2)) /* line scrolls */ +#define SKIN_REFRESH_PLAYER_PROGRESS (1u<<(SKIN_REFRESH_SHIFT+3)) /* line contains a progress bar */ +#define SKIN_REFRESH_PEAK_METER (1u<<(SKIN_REFRESH_SHIFT+4)) /* line contains a peak meter */ +#define SKIN_REFRESH_STATUSBAR (1u<<(SKIN_REFRESH_SHIFT+5)) /* refresh statusbar */ +#define SKIN_RTC_REFRESH (1u<<(SKIN_REFRESH_SHIFT+6)) /* refresh rtc, convert at parse time */ +#define SKIN_REFRESH_ALL (0xffffu<<SKIN_REFRESH_SHIFT) /* to refresh all line types */ + +/* to refresh only those lines that change over time */ +#define SKIN_REFRESH_NON_STATIC (SKIN_REFRESH_DYNAMIC| \ + SKIN_REFRESH_PLAYER_PROGRESS| \ + SKIN_REFRESH_PEAK_METER) enum skin_token_type { + SKIN_TOKEN_NO_TOKEN, SKIN_TOKEN_UNKNOWN, /* Markers */ @@ -91,7 +110,7 @@ enum skin_token_type { /* The begin/end values allow us to know if a token is an RTC one. New RTC tokens should be added between the markers. */ - SKIN_TOKENs_RTC_BEGIN, /* just the start marker, not an actual token */ + SKIN_TOKENS_RTC_BEGIN, /* just the start marker, not an actual token */ SKIN_TOKEN_RTC_DAY_OF_MONTH, SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, diff --git a/tools/checkwps/SOURCES b/tools/checkwps/SOURCES index 48ed53b330..3e12d1f74e 100644 --- a/tools/checkwps/SOURCES +++ b/tools/checkwps/SOURCES @@ -1,7 +1,6 @@ ../../apps/gui/skin_engine/wps_debug.c ../../apps/gui/skin_engine/skin_parser.c ../../apps/gui/skin_engine/skin_backdrops.c -../../apps/gui/skin_engine/skin_buffer.c #ifdef HAVE_LCD_BITMAP ../../apps/gui/skin_engine/skin_fonts.c #endif diff --git a/tools/checkwps/checkwps.c b/tools/checkwps/checkwps.c index 94136e02f0..e00fb724bc 100644 --- a/tools/checkwps/checkwps.c +++ b/tools/checkwps/checkwps.c @@ -26,6 +26,8 @@ #include "checkwps.h" #include "resize.h" #include "wps.h" +#include "skin_buffer.h" +#include "skin_debug.h" #include "skin_engine.h" #include "wps_internals.h" #include "settings.h" @@ -237,6 +239,8 @@ int main(int argc, char **argv) struct wps_data wps; enum screen_type screen = SCREEN_MAIN; struct screen* wps_screen; + + char* buffer = NULL; /* No arguments -> print the help text * Also print the help text upon -h or --help */ @@ -261,13 +265,19 @@ int main(int argc, char **argv) wps_verbose_level++; } } + buffer = malloc(SKIN_BUFFER_SIZE); + if (!buffer) + { + printf("mallloc fail!\n"); + return 1; + } - skin_buffer_init(); + skin_buffer_init(buffer, SKIN_BUFFER_SIZE); #ifdef HAVE_LCD_BITMAP skin_font_init(); #endif - /* Go through every wps that was thrown at us, error out at the first + /* Go through every skin that was thrown at us, error out at the first * flawed wps */ while (argv[filearg]) { printf("Checking %s...\n", argv[filearg]); @@ -285,6 +295,7 @@ int main(int argc, char **argv) if (!res) { printf("WPS parsing failure\n"); + skin_error_format_message(); return 3; } diff --git a/tools/checkwps/checkwps.make b/tools/checkwps/checkwps.make index 0db643bc84..e09ce25aec 100644 --- a/tools/checkwps/checkwps.make +++ b/tools/checkwps/checkwps.make @@ -26,6 +26,6 @@ GCCOPTS+=-D__PCTOOL__ .SECONDEXPANSION: # $$(OBJ) is not populated until after this -$(BUILDDIR)/$(BINARY): $$(OBJ) +$(BUILDDIR)/$(BINARY): $$(OBJ) $$(SKINLIB) @echo LD $(BINARY) - $(SILENT)$(HOSTCC) $(INCLUDE) $(FLAGS) -o $@ $+ + $(SILENT)$(HOSTCC) $(INCLUDE) $(FLAGS) -L$(BUILDDIR)/lib -lskin_parser -o $@ $+ diff --git a/tools/root.make b/tools/root.make index e53c452022..d90b40f0c6 100644 --- a/tools/root.make +++ b/tools/root.make @@ -70,6 +70,7 @@ else ifneq (,$(findstring bootbox,$(APPSDIR))) include $(APPSDIR)/bootbox.make else ifneq (,$(findstring checkwps,$(APPSDIR))) include $(APPSDIR)/checkwps.make + include $(ROOTDIR)/lib/skin_parser/skin_parser.make else ifneq (,$(findstring database,$(APPSDIR))) include $(APPSDIR)/database.make else @@ -170,7 +171,8 @@ $(BUILDDIR)/rockbox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) $$(L $(BUILDDIR)/rombox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) $$(LINKROM) $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \ $(VOICESPEEXLIB) $(FIRMLIB) -lgcc $(GLOBAL_LDOPTS) \ - -L$(BUILDDIR)/firmware -T$(LINKROM) -Wl,-Map,$(BUILDDIR)/rombox.map + -L$(BUILDDIR)/lib -lskin_parser \ + -L$(BUILDDIR)/firmware -T$(LINKROM) -Wl,-Map,$(BUILDDIR)/rombox.map $(BUILDDIR)/rockbox.bin : $(BUILDDIR)/rockbox.elf $(call PRINTS,OC $(@F))$(OC) $(if $(filter yes, $(USE_ELF)), -S -x, -O binary) $< $@ diff --git a/utils/newparser/skin_render.c b/utils/newparser/skin_render.c index 1690455086..09c9ca1355 100644 --- a/utils/newparser/skin_render.c +++ b/utils/newparser/skin_render.c @@ -43,7 +43,7 @@ static void do_tags_in_hidden_conditional(struct skin_element* branch) { /* Tags here are ones which need to be "turned off" or cleared * if they are in a conditional branch which isnt being used */ - if (branch->type == SUBLINES) + if (branch->type == LINE_ALTERNATOR) { int i; for (i=0; i<branch->children_count; i++) @@ -71,7 +71,6 @@ static void do_tags_in_hidden_conditional(struct skin_element* branch) break; case SKIN_TOKEN_IMAGE_DISPLAY: case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: - printf("disable image\n"); /* clear images */ break; default: @@ -109,7 +108,7 @@ void skin_render_line(struct skin_element* line, do_tags_in_hidden_conditional(child->children[last_value]); last_value = value; - if (child->children[value]->type == SUBLINES) + if (child->children[value]->type == LINE_ALTERNATOR) func = skin_render_alternator; else if (child->children[value]->type == LINE) func = skin_render_line; |