summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/SOURCES3
-rw-r--r--apps/cuesheet.c14
-rw-r--r--apps/gui/skin_engine/skin_backdrops.c4
-rw-r--r--apps/gui/skin_engine/skin_buffer.c170
-rw-r--r--apps/gui/skin_engine/skin_buffer.h64
-rw-r--r--apps/gui/skin_engine/skin_display.c728
-rw-r--r--apps/gui/skin_engine/skin_display.h59
-rw-r--r--apps/gui/skin_engine/skin_engine.h33
-rw-r--r--apps/gui/skin_engine/skin_fonts.c2
-rw-r--r--apps/gui/skin_engine/skin_fonts.h1
-rw-r--r--apps/gui/skin_engine/skin_parser.c2057
-rw-r--r--apps/gui/skin_engine/skin_render.c614
-rw-r--r--apps/gui/skin_engine/skin_tokens.c279
-rw-r--r--apps/gui/skin_engine/skin_tokens.h238
-rw-r--r--apps/gui/skin_engine/wps_debug.c1
-rw-r--r--apps/gui/skin_engine/wps_internals.h102
-rw-r--r--apps/gui/statusbar-skinned.c103
-rw-r--r--apps/gui/theme_settings.c12
-rw-r--r--apps/gui/viewport.c84
-rw-r--r--apps/gui/viewport.h21
-rw-r--r--apps/gui/wps.c16
-rw-r--r--apps/main.c2
-rw-r--r--apps/menus/main_menu.c2
-rw-r--r--apps/misc.c135
-rw-r--r--apps/misc.h11
-rw-r--r--apps/radio/radio.c4
-rw-r--r--apps/recorder/albumart.h4
-rw-r--r--apps/settings.h1
-rw-r--r--lib/skin_parser/SOURCES2
-rw-r--r--lib/skin_parser/skin_buffer.c38
-rw-r--r--lib/skin_parser/skin_buffer.h6
-rw-r--r--lib/skin_parser/skin_debug.c40
-rw-r--r--lib/skin_parser/skin_debug.h9
-rw-r--r--lib/skin_parser/skin_parser.c169
-rw-r--r--lib/skin_parser/skin_parser.h15
-rw-r--r--lib/skin_parser/skin_scan.c8
-rw-r--r--lib/skin_parser/skin_scan.h1
-rw-r--r--lib/skin_parser/tag_table.c325
-rw-r--r--lib/skin_parser/tag_table.h21
-rw-r--r--tools/checkwps/SOURCES1
-rw-r--r--tools/checkwps/checkwps.c15
-rw-r--r--tools/checkwps/checkwps.make4
-rw-r--r--tools/root.make4
-rw-r--r--utils/newparser/skin_render.c5
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
94gui/viewport.c 94gui/viewport.c
95 95
96gui/skin_engine/skin_backdrops.c 96gui/skin_engine/skin_backdrops.c
97gui/skin_engine/skin_buffer.c
98gui/skin_engine/wps_debug.c
99gui/skin_engine/skin_display.c 97gui/skin_engine/skin_display.c
100#ifdef HAVE_LCD_BITMAP 98#ifdef HAVE_LCD_BITMAP
101gui/skin_engine/skin_fonts.c 99gui/skin_engine/skin_fonts.c
102#endif 100#endif
103gui/skin_engine/skin_parser.c 101gui/skin_engine/skin_parser.c
102gui/skin_engine/skin_render.c
104gui/skin_engine/skin_tokens.c 103gui/skin_engine/skin_tokens.c
105#ifdef HAVE_TOUCHSCREEN 104#ifdef HAVE_TOUCHSCREEN
106gui/skin_engine/skin_touchsupport.c 105gui/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,
363 } 363 }
364 switch (token->type) 364 switch (token->type)
365 { 365 {
366 case WPS_TOKEN_METADATA_ARTIST: 366 case SKIN_TOKEN_METADATA_ARTIST:
367 return *track->performer ? track->performer : NULL; 367 return *track->performer ? track->performer : NULL;
368 case WPS_TOKEN_METADATA_COMPOSER: 368 case SKIN_TOKEN_METADATA_COMPOSER:
369 return *track->songwriter ? track->songwriter : NULL; 369 return *track->songwriter ? track->songwriter : NULL;
370 case WPS_TOKEN_METADATA_ALBUM: 370 case SKIN_TOKEN_METADATA_ALBUM:
371 return *cue->title ? cue->title : NULL; 371 return *cue->title ? cue->title : NULL;
372 case WPS_TOKEN_METADATA_ALBUM_ARTIST: 372 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
373 return *cue->performer ? cue->performer : NULL; 373 return *cue->performer ? cue->performer : NULL;
374 case WPS_TOKEN_METADATA_TRACK_TITLE: 374 case SKIN_TOKEN_METADATA_TRACK_TITLE:
375 return *track->title ? track->title : NULL; 375 return *track->title ? track->title : NULL;
376 case WPS_TOKEN_METADATA_TRACK_NUMBER: 376 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
377 snprintf(buf, buf_size, "%d/%d", 377 snprintf(buf, buf_size, "%d/%d",
378 cue->curr_track_idx+offset_tracks+1, cue->track_count); 378 cue->curr_track_idx+offset_tracks+1, cue->track_count);
379 return buf; 379 return buf;
380 default:
381 return NULL;
380 } 382 }
381 return NULL; 383 return NULL;
382} 384}
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 @@
24#include <stdlib.h> 24#include <stdlib.h>
25#include "string-extra.h" 25#include "string-extra.h"
26#include "settings.h" 26#include "settings.h"
27#include "skin_buffer.h"
28#include "wps_internals.h" 27#include "wps_internals.h"
29#include "skin_engine.h" 28#include "skin_engine.h"
29#include "skin_buffer.h"
30 30
31#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) 31#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
32 32
@@ -100,7 +100,7 @@ char* skin_backdrop_load(char* backdrop, char *bmpdir, enum screen_type screen)
100 if (!bdrop) 100 if (!bdrop)
101 return NULL; /* too many backdrops loaded */ 101 return NULL; /* too many backdrops loaded */
102 102
103 bdrop->buffer = skin_buffer_alloc(buf_size); 103 bdrop->buffer = (char*)skin_buffer_alloc(buf_size);
104 if (!bdrop->buffer) 104 if (!bdrop->buffer)
105 return NULL; 105 return NULL;
106 loaded = screens[screen].backdrop_load(filename, bdrop->buffer); 106 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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 * Copyright (C) 2009 Jonathan Gordon
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include <stdio.h>
24#include <string.h>
25#include <stdlib.h>
26#include "config.h"
27#include "buffer.h"
28#include "settings.h"
29#include "screen_access.h"
30#include "skin_engine.h"
31#include "wps_internals.h"
32#include "skin_tokens.h"
33#include "skin_buffer.h"
34#include "skin_fonts.h"
35
36/* skin buffer management.
37 * This module is used to allocate space in a single global skin buffer for
38 * tokens for both/all screens.
39 *
40 * This is mostly just copy/paste from firmware/buffer.c
41 *
42 *
43 * MAIN_ and REMOTE_BUFFER are just for reasonable size calibration,
44 * both screens can use the whole buffer as they need; it's not split
45 * between screens
46 *
47 * Buffer can be allocated from either "end" of the global buffer.
48 * items with unknown sizes get allocated from the start (0->) (data)
49 * items with known sizes get allocated from the end (<-buf_size) (tokens)
50 * After loading 2 skins the buffer will look like this:
51 * |tokens skin1|images skin1|tokens s2|images s2|---SPACE---|data skin2|data skin1|
52 * Make sure to never start allocating from the beginning before letting us know
53 * how much was used. and RESPECT THE buf_free RETURN VALUES!
54 *
55 */
56
57
58#ifdef HAVE_LCD_BITMAP
59#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
60 + (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES))
61
62#if (NB_SCREENS > 1)
63#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
64 + (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES))
65#else
66#define REMOTE_BUFFER 0
67#endif
68
69
70#define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER + SKIN_FONT_SIZE) + \
71 (WPS_MAX_TOKENS * sizeof(struct wps_token))
72#endif
73
74#ifdef HAVE_LCD_CHARCELLS
75#define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \
76 (WPS_MAX_TOKENS * sizeof(struct wps_token))
77#endif
78
79static unsigned char buffer[SKIN_BUFFER_SIZE];
80static unsigned char *buffer_front = NULL; /* start of the free space,
81 increases with allocation*/
82static unsigned char *buffer_back = NULL; /* end of the free space
83 decreases with allocation */
84static size_t buf_size = SKIN_BUFFER_SIZE;
85
86void skin_buffer_init(void)
87{
88#if 0 /* this will go in again later probably */
89 if (buffer == NULL)
90 {
91 buf_size = SKIN_BUFFER_SIZE;/* global_settings.skin_buf_size */
92
93 buffer = buffer_alloc(buf_size);
94 buffer_front = buffer;
95 buffer_back = bufer + buf_size;
96 }
97 else
98#endif
99 {
100 /* reset the buffer.... */
101 buffer_front = buffer;
102 buffer_back = buffer + buf_size;
103 }
104}
105
106/* get the number of bytes currently being used */
107size_t skin_buffer_usage(void)
108{
109 return buf_size - (buffer_back-buffer_front);
110}
111
112size_t skin_buffer_freespace(void)
113{
114 return buffer_back-buffer_front;
115}
116
117/* Allocate size bytes from the buffer
118 * allocates from the back end (data end)
119 */
120void* skin_buffer_alloc(size_t size)
121{
122 if (skin_buffer_freespace() <= size)
123 {
124 return NULL;
125 }
126 buffer_back -= size;
127 /* 32-bit aligned */
128 buffer_back = (void *)(((unsigned long)buffer_back) & ~3);
129
130 memset(buffer_back, 0, size);
131 return buffer_back;
132}
133
134/* Get a pointer to the skin buffer and the count of how much is free
135 * used to do your own buffer management.
136 * Any memory used will be overwritten next time wps_buffer_alloc()
137 * is called unless skin_buffer_increment() is called first
138 *
139 * This is from the start of the buffer, it is YOUR responsility to make
140 * sure you dont ever use more then *freespace, and bear in mind this will only
141 * be valid untill skin_buffer_alloc() is next called...
142 * so call skin_buffer_increment() and skin_buffer_freespace() regularly
143 */
144void* skin_buffer_grab(size_t *freespace)
145{
146 *freespace = buf_size - skin_buffer_usage();
147 return buffer_front;
148}
149
150/* Use after skin_buffer_grab() to specify how much buffer was used */
151void skin_buffer_increment(size_t used, bool align)
152{
153 buffer_front += used;
154 if (align)
155 {
156 /* 32-bit aligned */
157 buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3);
158 }
159}
160
161/* free previously skin_buffer_increment()'ed space. This just moves the pointer
162 * back 'used' bytes so make sure you actually want to do this */
163void skin_buffer_free_from_front(size_t used)
164{
165 buffer_front -= used;
166 /* 32-bit aligned */
167 buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3);
168}
169
170
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 * Copyright (C) 2009 Jonathan Gordon
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#ifndef _SKIN_BUFFER_H_
24#define _SKIN_BUFFER_H_
25
26
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30
31/* int the global buffer */
32void skin_buffer_init(void);
33
34/* get the number of bytes currently being used */
35size_t skin_buffer_usage(void);
36size_t skin_buffer_freespace(void);
37
38/* Allocate size bytes from the buffer */
39void* skin_buffer_alloc(size_t size);
40
41
42/* Get a pointer to the skin buffer and the count of how much is free
43 * used to do your own buffer management.
44 * Any memory used will be overwritten next time wps_buffer_alloc()
45 * is called unless skin_buffer_increment() is called first
46 *
47 * This is from the start of the buffer, it is YOUR responsility to make
48 * sure you dont ever use more then *freespace, and bear in mind this will only
49 * be valid untill skin_buffer_alloc() is next called...
50 * so call skin_buffer_increment() and skin_buffer_freespace() regularly
51 */
52void* skin_buffer_grab(size_t *freespace);
53
54/* Use after skin_buffer_grab() to specify how much buffer was used.
55 * align should always be true unless there is a possibility that you will need
56 * more space *immediatly* after the previous allocation. (i.e in an array).
57 * NEVER leave the buffer unaligned */
58void skin_buffer_increment(size_t used, bool align);
59
60/* free previously skin_buffer_increment()'ed space. This just moves the pointer
61 * back 'used' bytes so make sure you actually want to do this */
62void skin_buffer_free_from_front(size_t used);
63
64#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 @@
69#include "skin_engine.h" 69#include "skin_engine.h"
70#include "statusbar-skinned.h" 70#include "statusbar-skinned.h"
71 71
72static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode); 72void skin_render(struct gui_wps *gwps, unsigned refresh_mode);
73 73
74/* update a skinned screen, update_type is WPS_REFRESH_* values. 74/* update a skinned screen, update_type is WPS_REFRESH_* values.
75 * Usually it should only be WPS_REFRESH_NON_STATIC 75 * Usually it should only be WPS_REFRESH_NON_STATIC
76 * A full update will be done if required (state.do_full_update == true) 76 * A full update will be done if required (state.do_full_update == true)
77 */ 77 */
78bool skin_update(struct gui_wps *gwps, unsigned int update_type) 78void skin_update(struct gui_wps *gwps, unsigned int update_type)
79{ 79{
80 bool retval; 80 /* This maybe shouldnt be here,
81 /* This maybe shouldnt be here, but while the skin is only used to 81 * This is also safe for skined screen which dont use the id3 */
82 * display the music screen this is better than whereever we are being
83 * called from. This is also safe for skined screen which dont use the id3 */
84 struct mp3entry *id3 = gwps->state->id3; 82 struct mp3entry *id3 = gwps->state->id3;
85 bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false); 83 bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false);
86 gwps->sync_data->do_full_update |= cuesheet_update; 84 gwps->sync_data->do_full_update |= cuesheet_update;
87 85
88 retval = skin_redraw(gwps, gwps->sync_data->do_full_update ? 86 skin_render(gwps, gwps->sync_data->do_full_update ?
89 WPS_REFRESH_ALL : update_type); 87 SKIN_REFRESH_ALL : update_type);
90 return retval;
91} 88}
92 89
93#ifdef HAVE_LCD_BITMAP 90#ifdef HAVE_LCD_BITMAP
@@ -124,8 +121,7 @@ void skin_statusbar_changed(struct gui_wps *skin)
124 } 121 }
125} 122}
126 123
127static void draw_progressbar(struct gui_wps *gwps, 124void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
128 struct progressbar *pb)
129{ 125{
130 struct screen *display = gwps->display; 126 struct screen *display = gwps->display;
131 struct viewport *vp = pb->vp; 127 struct viewport *vp = pb->vp;
@@ -143,17 +139,17 @@ static void draw_progressbar(struct gui_wps *gwps,
143 /* center the pb in the line, but only if the line is higher than the pb */ 139 /* center the pb in the line, but only if the line is higher than the pb */
144 int center = (line_height-height)/2; 140 int center = (line_height-height)/2;
145 /* if Y was not set calculate by font height,Y is -line_number-1 */ 141 /* if Y was not set calculate by font height,Y is -line_number-1 */
146 y = (-y -1)*line_height + (0 > center ? 0 : center); 142 y = line*line_height + (0 > center ? 0 : center);
147 } 143 }
148 144
149 if (pb->type == WPS_TOKEN_VOLUMEBAR) 145 if (pb->type == SKIN_TOKEN_VOLUMEBAR)
150 { 146 {
151 int minvol = sound_min(SOUND_VOLUME); 147 int minvol = sound_min(SOUND_VOLUME);
152 int maxvol = sound_max(SOUND_VOLUME); 148 int maxvol = sound_max(SOUND_VOLUME);
153 length = maxvol-minvol; 149 length = maxvol-minvol;
154 elapsed = global_settings.volume-minvol; 150 elapsed = global_settings.volume-minvol;
155 } 151 }
156 else if (pb->type == WPS_TOKEN_BATTERY_PERCENTBAR) 152 else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR)
157 { 153 {
158 length = 100; 154 length = 100;
159 elapsed = battery_level(); 155 elapsed = battery_level();
@@ -185,7 +181,7 @@ static void draw_progressbar(struct gui_wps *gwps,
185 gui_scrollbar_draw(display, pb->x, y, pb->width, height, 181 gui_scrollbar_draw(display, pb->x, y, pb->width, height,
186 length, 0, elapsed, HORIZONTAL); 182 length, 0, elapsed, HORIZONTAL);
187 183
188 if (pb->type == WPS_TOKEN_PROGRESSBAR) 184 if (pb->type == SKIN_TOKEN_PROGRESSBAR)
189 { 185 {
190 if (id3 && id3->length) 186 if (id3 && id3->length)
191 { 187 {
@@ -208,8 +204,7 @@ static void draw_progressbar(struct gui_wps *gwps,
208 } 204 }
209} 205}
210 206
211static void draw_playlist_viewer_list(struct gui_wps *gwps, 207void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer)
212 struct playlistviewer *viewer)
213{ 208{
214 struct wps_state *state = gwps->state; 209 struct wps_state *state = gwps->state;
215 int lines = viewport_get_nb_lines(viewer->vp); 210 int lines = viewport_get_nb_lines(viewer->vp);
@@ -217,8 +212,9 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
217 int cur_pos, max; 212 int cur_pos, max;
218 int start_item; 213 int start_item;
219 int i; 214 int i;
220 struct wps_token token; 215 bool scroll = false;
221 int x, length, alignment = WPS_TOKEN_ALIGN_LEFT; 216 struct wps_token *token;
217 int x, length, alignment = SKIN_TOKEN_ALIGN_LEFT;
222 218
223 struct mp3entry *pid3; 219 struct mp3entry *pid3;
224 char buf[MAX_PATH*2], tempbuf[MAX_PATH]; 220 char buf[MAX_PATH*2], tempbuf[MAX_PATH];
@@ -281,51 +277,58 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
281 } 277 }
282 line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO; 278 line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO;
283 } 279 }
284 int j = 0, cur_string = 0;
285 unsigned int line_len = 0; 280 unsigned int line_len = 0;
281 if (viewer->lines[line]->children_count == 0)
282 return;
283 struct skin_element *element = viewer->lines[line]->children[0];
286 buf[0] = '\0'; 284 buf[0] = '\0';
287 while (j < viewer->lines[line].count && line_len < sizeof(buf)) 285 while (element && line_len < sizeof(buf))
288 { 286 {
289 const char *out = NULL; 287 const char *out = NULL;
290 token.type = viewer->lines[line].tokens[j]; 288 if (element->type == TEXT)
291 token.value.i = 0; 289 {
292 token.next = false; 290 line_len = strlcat(buf, (char*)element->data, sizeof(buf));
293 out = get_id3_token(&token, pid3, tempbuf, sizeof(tempbuf), -1, NULL); 291 element = element->next;
292 continue;
293 }
294 if (element->type != TAG)
295 {
296 element = element->next;
297 continue;
298 }
299 if (element->tag->type == SKIN_TOKEN_SUBLINE_SCROLL)
300 scroll = true;
301 token = (struct wps_token*)element->data;
302 out = get_id3_token(token, pid3, tempbuf, sizeof(tempbuf), -1, NULL);
294#if CONFIG_TUNER 303#if CONFIG_TUNER
295 if (!out) 304 if (!out)
296 out = get_radio_token(&token, i-cur_pos, 305 out = get_radio_token(token, i-cur_pos,
297 tempbuf, sizeof(tempbuf), -1, NULL); 306 tempbuf, sizeof(tempbuf), -1, NULL);
298#endif 307#endif
299 if (out) 308 if (out)
300 { 309 {
301 line_len = strlcat(buf, out, sizeof(buf)); 310 line_len = strlcat(buf, out, sizeof(buf));
302 j++; 311 element = element->next;
303 continue; 312 continue;
304 } 313 }
305 314
306 switch (viewer->lines[line].tokens[j]) 315 switch (token->type)
307 { 316 {
308 case WPS_TOKEN_ALIGN_CENTER: 317 case SKIN_TOKEN_ALIGN_CENTER:
309 case WPS_TOKEN_ALIGN_LEFT: 318 case SKIN_TOKEN_ALIGN_LEFT:
310 case WPS_TOKEN_ALIGN_LEFT_RTL: 319 case SKIN_TOKEN_ALIGN_LEFT_RTL:
311 case WPS_TOKEN_ALIGN_RIGHT: 320 case SKIN_TOKEN_ALIGN_RIGHT:
312 case WPS_TOKEN_ALIGN_RIGHT_RTL: 321 case SKIN_TOKEN_ALIGN_RIGHT_RTL:
313 alignment = viewer->lines[line].tokens[j]; 322 alignment = token->type;
314 tempbuf[0] = '\0'; 323 tempbuf[0] = '\0';
315 break; 324 break;
316 case WPS_TOKEN_STRING: 325 case SKIN_TOKEN_PLAYLIST_POSITION:
317 case WPS_TOKEN_CHARACTER:
318 snprintf(tempbuf, sizeof(tempbuf), "%s",
319 viewer->lines[line].strings[cur_string]);
320 cur_string++;
321 break;
322 case WPS_TOKEN_PLAYLIST_POSITION:
323 snprintf(tempbuf, sizeof(tempbuf), "%d", i); 326 snprintf(tempbuf, sizeof(tempbuf), "%d", i);
324 break; 327 break;
325 case WPS_TOKEN_FILE_NAME: 328 case SKIN_TOKEN_FILE_NAME:
326 get_dir(tempbuf, sizeof(tempbuf), filename, 0); 329 get_dir(tempbuf, sizeof(tempbuf), filename, 0);
327 break; 330 break;
328 case WPS_TOKEN_FILE_PATH: 331 case SKIN_TOKEN_FILE_PATH:
329 snprintf(tempbuf, sizeof(tempbuf), "%s", filename); 332 snprintf(tempbuf, sizeof(tempbuf), "%s", filename);
330 break; 333 break;
331 default: 334 default:
@@ -336,12 +339,12 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
336 { 339 {
337 line_len = strlcat(buf, tempbuf, sizeof(buf)); 340 line_len = strlcat(buf, tempbuf, sizeof(buf));
338 } 341 }
339 j++; 342 element = element->next;
340 } 343 }
341 344
342 int vpwidth = viewer->vp->width; 345 int vpwidth = viewer->vp->width;
343 length = gwps->display->getstringsize(buf, NULL, NULL); 346 length = gwps->display->getstringsize(buf, NULL, NULL);
344 if (viewer->lines[line].scroll && length >= vpwidth) 347 if (scroll && length >= vpwidth)
345 { 348 {
346 gwps->display->puts_scroll(0, (i-start_item), buf ); 349 gwps->display->puts_scroll(0, (i-start_item), buf );
347 } 350 }
@@ -353,25 +356,25 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
353 { 356 {
354 switch (alignment) 357 switch (alignment)
355 { 358 {
356 case WPS_TOKEN_ALIGN_CENTER: 359 case SKIN_TOKEN_ALIGN_CENTER:
357 x = (vpwidth-length)/2; 360 x = (vpwidth-length)/2;
358 break; 361 break;
359 case WPS_TOKEN_ALIGN_LEFT_RTL: 362 case SKIN_TOKEN_ALIGN_LEFT_RTL:
360 if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) 363 if (lang_is_rtl() && VP_IS_RTL(viewer->vp))
361 { 364 {
362 x = vpwidth - length; 365 x = vpwidth - length;
363 break; 366 break;
364 } 367 }
365 case WPS_TOKEN_ALIGN_LEFT: 368 case SKIN_TOKEN_ALIGN_LEFT:
366 x = 0; 369 x = 0;
367 break; 370 break;
368 case WPS_TOKEN_ALIGN_RIGHT_RTL: 371 case SKIN_TOKEN_ALIGN_RIGHT_RTL:
369 if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) 372 if (lang_is_rtl() && VP_IS_RTL(viewer->vp))
370 { 373 {
371 x = 0; 374 x = 0;
372 break; 375 break;
373 } 376 }
374 case WPS_TOKEN_ALIGN_RIGHT: 377 case SKIN_TOKEN_ALIGN_RIGHT:
375 x = vpwidth - length; 378 x = vpwidth - length;
376 break; 379 break;
377 default: 380 default:
@@ -386,7 +389,7 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
386 389
387 390
388/* clears the area where the image was shown */ 391/* clears the area where the image was shown */
389static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) 392void clear_image_pos(struct gui_wps *gwps, struct gui_img *img)
390{ 393{
391 if(!gwps) 394 if(!gwps)
392 return; 395 return;
@@ -395,7 +398,7 @@ static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img)
395 gwps->display->set_drawmode(DRMODE_SOLID); 398 gwps->display->set_drawmode(DRMODE_SOLID);
396} 399}
397 400
398static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage) 401void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage)
399{ 402{
400 struct screen *display = gwps->display; 403 struct screen *display = gwps->display;
401 if(img->always_display) 404 if(img->always_display)
@@ -423,7 +426,8 @@ static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subima
423#endif 426#endif
424} 427}
425 428
426static void wps_display_images(struct gui_wps *gwps, struct viewport* vp) 429
430void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
427{ 431{
428 if(!gwps || !gwps->data || !gwps->display) 432 if(!gwps || !gwps->data || !gwps->display)
429 return; 433 return;
@@ -451,18 +455,10 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
451#ifdef HAVE_ALBUMART 455#ifdef HAVE_ALBUMART
452 /* now draw the AA */ 456 /* now draw the AA */
453 if (data->albumart && data->albumart->vp == vp 457 if (data->albumart && data->albumart->vp == vp
454 && data->albumart->draw) 458 && data->albumart->draw_handle >= 0)
455 { 459 {
456 int handle = playback_current_aa_hid(data->playback_aa_slot); 460 draw_album_art(gwps, data->albumart->draw_handle, false);
457#if CONFIG_TUNER 461 data->albumart->draw_handle = -1;
458 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
459 {
460 struct dim dim = {data->albumart->width, data->albumart->height};
461 handle = radio_get_art_hid(&dim);
462 }
463#endif
464 draw_album_art(gwps, handle, false);
465 data->albumart->draw = false;
466 } 462 }
467#endif 463#endif
468 464
@@ -471,7 +467,7 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
471 467
472#else /* HAVE_LCD_CHARCELL */ 468#else /* HAVE_LCD_CHARCELL */
473 469
474static bool draw_player_progress(struct gui_wps *gwps) 470bool draw_player_progress(struct gui_wps *gwps)
475{ 471{
476 struct wps_state *state = gwps->state; 472 struct wps_state *state = gwps->state;
477 struct screen *display = gwps->display; 473 struct screen *display = gwps->display;
@@ -508,7 +504,7 @@ static bool draw_player_progress(struct gui_wps *gwps)
508 return true; 504 return true;
509} 505}
510 506
511static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size) 507void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
512{ 508{
513 static const unsigned char numbers[10][4] = { 509 static const unsigned char numbers[10][4] = {
514 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */ 510 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
@@ -613,44 +609,25 @@ static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
613 609
614#endif /* HAVE_LCD_CHARCELL */ 610#endif /* HAVE_LCD_CHARCELL */
615 611
616/* Return the index to the end token for the conditional token at index.
617 The conditional token can be either a start token or a separator
618 (i.e. option) token.
619*/
620static int find_conditional_end(struct wps_data *data, int index)
621{
622 int ret = index;
623 while (data->tokens[ret].type != WPS_TOKEN_CONDITIONAL_END)
624 ret = data->tokens[ret].value.i;
625
626 /* ret now is the index to the end token for the conditional. */
627 return ret;
628}
629
630/* Evaluate the conditional that is at *token_index and return whether a skip 612/* Evaluate the conditional that is at *token_index and return whether a skip
631 has ocurred. *token_index is updated with the new position. 613 has ocurred. *token_index is updated with the new position.
632*/ 614*/
633static bool evaluate_conditional(struct gui_wps *gwps, int *token_index) 615int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options)
634{ 616{
635 if (!gwps) 617 if (!gwps)
636 return false; 618 return false;
637 619
638 struct wps_data *data = gwps->data;
639
640 int i, cond_end;
641 int cond_index = *token_index;
642 char result[128]; 620 char result[128];
643 const char *value; 621 const char *value;
644 unsigned char num_options = data->tokens[cond_index].value.i & 0xFF;
645 unsigned char prev_val = (data->tokens[cond_index].value.i & 0xFF00) >> 8;
646 622
647 /* treat ?xx<true> constructs as if they had 2 options. */ 623 /* treat ?xx<true> constructs as if they had 2 options.
624 * (i.e ?xx<true|false>) */
648 if (num_options < 2) 625 if (num_options < 2)
649 num_options = 2; 626 num_options = 2;
650 627
651 int intval = num_options; 628 int intval = num_options;
652 /* get_token_value needs to know the number of options in the enum */ 629 /* get_token_value needs to know the number of options in the enum */
653 value = get_token_value(gwps, &data->tokens[cond_index + 1], 630 value = get_token_value(gwps, conditional->token,
654 result, sizeof(result), &intval); 631 result, sizeof(result), &intval);
655 632
656 /* intval is now the number of the enum option we want to read, 633 /* 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)
659 intval = (value && *value) ? 1 : num_options; 636 intval = (value && *value) ? 1 : num_options;
660 else if (intval > num_options || intval < 1) 637 else if (intval > num_options || intval < 1)
661 intval = num_options; 638 intval = num_options;
662 639
663 data->tokens[cond_index].value.i = (intval << 8) + num_options; 640 conditional->last_value = intval -1;
664 641 return intval -1;
665 /* skip to the appropriate enum case */
666 int next = cond_index + 2;
667 for (i = 1; i < intval; i++)
668 {
669 next = data->tokens[next].value.i;
670 }
671 *token_index = next;
672
673 if (prev_val == intval)
674 {
675 /* Same conditional case as previously. Return without clearing the
676 pictures */
677 return false;
678 }
679
680 cond_end = find_conditional_end(data, cond_index + 2);
681 for (i = cond_index + 3; i < cond_end; i++)
682 {
683#ifdef HAVE_LCD_BITMAP
684 /* clear all pictures in the conditional and nested ones */
685 if (data->tokens[i].type == WPS_TOKEN_IMAGE_PRELOAD_DISPLAY)
686 clear_image_pos(gwps, find_image(data->tokens[i].value.i&0xFF, data));
687 else if (data->tokens[i].type == WPS_TOKEN_VOLUMEBAR ||
688 data->tokens[i].type == WPS_TOKEN_PROGRESSBAR ||
689 data->tokens[i].type == WPS_TOKEN_BATTERY_PERCENTBAR )
690 {
691 struct progressbar *bar = (struct progressbar*)data->tokens[i].value.data;
692 bar->draw = false;
693 }
694 else if (data->tokens[i].type == WPS_TOKEN_PEAKMETER)
695 {
696 data->peak_meter_enabled = false;
697 }
698#endif
699#ifdef HAVE_ALBUMART
700 if (data->albumart && data->tokens[i].type == WPS_TOKEN_ALBUMART_DISPLAY)
701 {
702 draw_album_art(gwps,
703 playback_current_aa_hid(data->playback_aa_slot), true);
704 data->albumart->draw = false;
705 }
706#endif
707 }
708
709 return true;
710}
711
712
713/* Read a (sub)line to the given alignment format buffer.
714 linebuf is the buffer where the data is actually stored.
715 align is the alignment format that'll be used to display the text.
716 The return value indicates whether the line needs to be updated.
717*/
718static bool get_line(struct gui_wps *gwps,
719 struct skin_subline *subline,
720 struct align_pos *align,
721 char *linebuf,
722 int linebuf_size,
723 unsigned refresh_mode)
724{
725 struct wps_data *data = gwps->data;
726
727 char temp_buf[128];
728 char *buf = linebuf; /* will always point to the writing position */
729 char *linebuf_end = linebuf + linebuf_size - 1;
730 bool update = false;
731 int i;
732 (void)refresh_mode; /* silence warning on charcell */
733
734 /* alignment-related variables */
735 int cur_align;
736 char* cur_align_start;
737 cur_align_start = buf;
738 cur_align = WPS_ALIGN_LEFT;
739 align->left = NULL;
740 align->center = NULL;
741 align->right = NULL;
742 /* Process all tokens of the desired subline */
743 for (i = subline->first_token_idx;
744 i <= subline->last_token_idx; i++)
745 {
746 switch(data->tokens[i].type)
747 {
748 case WPS_TOKEN_CONDITIONAL:
749 /* place ourselves in the right conditional case */
750 update |= evaluate_conditional(gwps, &i);
751 break;
752
753 case WPS_TOKEN_CONDITIONAL_OPTION:
754 /* we've finished in the curent conditional case,
755 skip to the end of the conditional structure */
756 i = find_conditional_end(data, i);
757 break;
758#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
759 case WPS_TOKEN_VIEWPORT_FGCOLOUR:
760 {
761 struct viewport_colour *col = data->tokens[i].value.data;
762 col->vp->fg_pattern = col->colour;
763 }
764 break;
765 case WPS_TOKEN_VIEWPORT_BGCOLOUR:
766 {
767 struct viewport_colour *col = data->tokens[i].value.data;
768 col->vp->bg_pattern = col->colour;
769 }
770 break;
771#endif
772#ifdef HAVE_LCD_BITMAP
773 case WPS_TOKEN_PEAKMETER:
774 data->peak_meter_enabled = true;
775 break;
776 case WPS_TOKEN_VOLUMEBAR:
777 case WPS_TOKEN_BATTERY_PERCENTBAR:
778 case WPS_TOKEN_PROGRESSBAR:
779 {
780 struct progressbar *bar = (struct progressbar*)data->tokens[i].value.data;
781 bar->draw = true;
782 }
783 break;
784 case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY:
785 {
786 char n = data->tokens[i].value.i & 0xFF;
787 int subimage = data->tokens[i].value.i >> 8;
788 struct gui_img *img = find_image(n, data);
789
790 if (img && img->loaded)
791 img->display = subimage;
792 break;
793 }
794 case WPS_TOKEN_DRAW_INBUILTBAR:
795 gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]),
796 refresh_mode == WPS_REFRESH_ALL,
797 data->tokens[i].value.data);
798 break;
799#endif
800
801 case WPS_TOKEN_ALIGN_LEFT:
802 case WPS_TOKEN_ALIGN_LEFT_RTL:
803 case WPS_TOKEN_ALIGN_CENTER:
804 case WPS_TOKEN_ALIGN_RIGHT:
805 case WPS_TOKEN_ALIGN_RIGHT_RTL:
806 /* remember where the current aligned text started */
807 switch (cur_align)
808 {
809 case WPS_ALIGN_LEFT:
810 align->left = cur_align_start;
811 break;
812
813 case WPS_ALIGN_CENTER:
814 align->center = cur_align_start;
815 break;
816
817 case WPS_ALIGN_RIGHT:
818 align->right = cur_align_start;
819 break;
820 }
821 /* start a new alignment */
822 switch (data->tokens[i].type)
823 {
824 case WPS_TOKEN_ALIGN_LEFT:
825 cur_align = WPS_ALIGN_LEFT;
826 break;
827 case WPS_TOKEN_ALIGN_LEFT_RTL:
828 cur_align = lang_is_rtl() ? WPS_ALIGN_RIGHT :
829 WPS_ALIGN_LEFT;
830 break;
831 case WPS_TOKEN_ALIGN_CENTER:
832 cur_align = WPS_ALIGN_CENTER;
833 break;
834 case WPS_TOKEN_ALIGN_RIGHT:
835 cur_align = WPS_ALIGN_RIGHT;
836 break;
837 case WPS_TOKEN_ALIGN_RIGHT_RTL:
838 cur_align = lang_is_rtl() ? WPS_ALIGN_LEFT :
839 WPS_ALIGN_RIGHT;
840 break;
841 default:
842 break;
843 }
844 *buf++ = 0;
845 cur_align_start = buf;
846 break;
847 case WPS_VIEWPORT_ENABLE:
848 {
849 char label = data->tokens[i].value.i;
850 char temp = VP_DRAW_HIDEABLE;
851 /* viewports are allowed to share id's so find and enable
852 * all of them */
853 struct skin_token_list *list = data->viewports;
854 while (list)
855 {
856 struct skin_viewport *vp =
857 (struct skin_viewport *)list->token->value.data;
858 if (vp->label == label)
859 {
860 if (vp->hidden_flags&VP_DRAW_WASHIDDEN)
861 temp |= VP_DRAW_WASHIDDEN;
862 vp->hidden_flags = temp;
863 }
864 list = list->next;
865 }
866 }
867 break;
868#ifdef HAVE_LCD_BITMAP
869 case WPS_TOKEN_UIVIEWPORT_ENABLE:
870 sb_set_info_vp(gwps->display->screen_type,
871 data->tokens[i].value.i|VP_INFO_LABEL);
872 break;
873 case WPS_VIEWPORT_CUSTOMLIST:
874 draw_playlist_viewer_list(gwps, data->tokens[i].value.data);
875 break;
876#endif
877 default:
878 {
879 /* get the value of the tag and copy it to the buffer */
880 const char *value = get_token_value(gwps, &data->tokens[i],
881 temp_buf, sizeof(temp_buf), NULL);
882 if (value)
883 {
884 update = true;
885 while (*value && (buf < linebuf_end))
886 *buf++ = *value++;
887 }
888 break;
889 }
890 }
891 }
892
893 /* close the current alignment */
894 switch (cur_align)
895 {
896 case WPS_ALIGN_LEFT:
897 align->left = cur_align_start;
898 break;
899
900 case WPS_ALIGN_CENTER:
901 align->center = cur_align_start;
902 break;
903
904 case WPS_ALIGN_RIGHT:
905 align->right = cur_align_start;
906 break;
907 }
908
909 return update;
910}
911static void get_subline_timeout(struct gui_wps *gwps, struct skin_subline *subline)
912{
913 struct wps_data *data = gwps->data;
914 int i;
915 subline->time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER;
916
917 for (i = subline->first_token_idx;
918 i <= subline->last_token_idx; i++)
919 {
920 switch(data->tokens[i].type)
921 {
922 case WPS_TOKEN_CONDITIONAL:
923 /* place ourselves in the right conditional case */
924 evaluate_conditional(gwps, &i);
925 break;
926
927 case WPS_TOKEN_CONDITIONAL_OPTION:
928 /* we've finished in the curent conditional case,
929 skip to the end of the conditional structure */
930 i = find_conditional_end(data, i);
931 break;
932
933 case WPS_TOKEN_SUBLINE_TIMEOUT:
934 subline->time_mult = data->tokens[i].value.i;
935 break;
936
937 default:
938 break;
939 }
940 }
941} 642}
942 643
943/* Calculates which subline should be displayed for the specified line
944 Returns true iff the subline must be refreshed */
945static bool update_curr_subline(struct gui_wps *gwps, struct skin_line *line)
946{
947 /* shortcut this whole thing if we need to reset the line completly */
948 if (line->curr_subline == NULL)
949 {
950 line->subline_expire_time = current_tick;
951 line->curr_subline = &line->sublines;
952 if (!line->curr_subline->next)
953 {
954 line->subline_expire_time += 100*HZ;
955 }
956 else
957 {
958 get_subline_timeout(gwps, line->curr_subline);
959 line->subline_expire_time += TIMEOUT_UNIT*line->curr_subline->time_mult;
960 }
961 return true;
962 }
963 /* if time to advance to next sub-line */
964 if (TIME_AFTER(current_tick, line->subline_expire_time - 1))
965 {
966 /* if there is only one subline, there is no need to search for a new one */
967 if (&line->sublines == line->curr_subline &&
968 line->curr_subline->next == NULL)
969 {
970 line->subline_expire_time += 100 * HZ;
971 return false;
972 }
973 if (line->curr_subline->next)
974 line->curr_subline = line->curr_subline->next;
975 else
976 line->curr_subline = &line->sublines;
977 get_subline_timeout(gwps, line->curr_subline);
978 line->subline_expire_time = current_tick + TIMEOUT_UNIT*line->curr_subline->time_mult;
979 return true;
980 }
981 return false;
982}
983 644
984/* Display a line appropriately according to its alignment format. 645/* Display a line appropriately according to its alignment format.
985 format_align contains the text, separated between left, center and right. 646 format_align contains the text, separated between left, center and right.
986 line is the index of the line on the screen. 647 line is the index of the line on the screen.
987 scroll indicates whether the line is a scrolling one or not. 648 scroll indicates whether the line is a scrolling one or not.
988*/ 649*/
989static void write_line(struct screen *display, 650void write_line(struct screen *display,
990 struct align_pos *format_align, 651 struct align_pos *format_align,
991 int line, 652 int line,
992 bool scroll) 653 bool scroll)
@@ -1143,244 +804,30 @@ static void write_line(struct screen *display,
1143 } 804 }
1144} 805}
1145 806
1146static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode) 807#ifdef HAVE_LCD_BITMAP
808void draw_peakmeters(struct gui_wps *gwps, int line_number,
809 struct viewport *viewport)
1147{ 810{
1148 struct wps_data *data = gwps->data; 811 struct wps_data *data = gwps->data;
1149 struct screen *display = gwps->display; 812 if (!data->peak_meter_enabled)
1150
1151 if (!data || !display || !gwps->state)
1152 return false;
1153
1154 unsigned flags;
1155 char linebuf[MAX_PATH];
1156
1157 struct align_pos align;
1158 align.left = NULL;
1159 align.center = NULL;
1160 align.right = NULL;
1161
1162
1163 struct skin_token_list *viewport_list;
1164
1165 bool update_line, new_subline_refresh;
1166
1167 /* reset to first subline if refresh all flag is set */
1168 if (refresh_mode == WPS_REFRESH_ALL)
1169 { 813 {
1170 struct skin_line *line; 814 peak_meter_enable(false);
1171 struct skin_viewport *skin_viewport = find_viewport(VP_DEFAULT_LABEL, data);
1172
1173 if (!(skin_viewport->hidden_flags & VP_NEVER_VISIBLE))
1174 {
1175 display->set_viewport(&skin_viewport->vp);
1176 display->clear_viewport();
1177 }
1178
1179 for (viewport_list = data->viewports;
1180 viewport_list; viewport_list = viewport_list->next)
1181 {
1182 skin_viewport =
1183 (struct skin_viewport *)viewport_list->token->value.data;
1184 for(line = skin_viewport->lines; line; line = line->next)
1185 {
1186 line->curr_subline = NULL;
1187 }
1188 }
1189 } 815 }
1190 816 else
1191#ifdef HAVE_LCD_CHARCELLS
1192 int i;
1193 for (i = 0; i < 8; i++)
1194 {
1195 if (data->wps_progress_pat[i] == 0)
1196 data->wps_progress_pat[i] = display->get_locked_pattern();
1197 }
1198#endif
1199
1200 /* disable any viewports which are conditionally displayed.
1201 * If we are only refreshing the peak meter then don't change the viewport
1202 * enabled flags as this will stop scrolling. viewports cant be
1203 * toggled in this refresh mode anyway (FS#10215)*/
1204 if (refresh_mode != WPS_REFRESH_PEAK_METER)
1205 {
1206 for (viewport_list = data->viewports;
1207 viewport_list; viewport_list = viewport_list->next)
1208 {
1209 struct skin_viewport *skin_viewport =
1210 (struct skin_viewport *)viewport_list->token->value.data;
1211 if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
1212 {
1213 continue;
1214 }
1215 if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE)
1216 {
1217 if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN)
1218 skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
1219 else
1220 skin_viewport->hidden_flags |= VP_DRAW_HIDDEN;
1221 }
1222 }
1223 }
1224 for (viewport_list = data->viewports;
1225 viewport_list; viewport_list = viewport_list->next)
1226 { 817 {
1227 struct skin_viewport *skin_viewport = 818 int h = font_get(viewport->font)->height;
1228 (struct skin_viewport *)viewport_list->token->value.data; 819 int peak_meter_y = line_number * h;
1229 unsigned vp_refresh_mode = refresh_mode;
1230#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
1231 skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour;
1232 skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour;
1233#endif
1234 display->set_viewport(&skin_viewport->vp);
1235
1236 int hidden_vp = 0;
1237 820
1238#ifdef HAVE_LCD_BITMAP 821 /* The user might decide to have the peak meter in the last
1239 /* Set images to not to be displayed */ 822 line so that it is only displayed if no status bar is
1240 struct skin_token_list *imglist = data->images; 823 visible. If so we neither want do draw nor enable the
1241 while (imglist) 824 peak meter. */
1242 { 825 if (peak_meter_y + h <= viewport->y+viewport->height) {
1243 struct gui_img *img = (struct gui_img *)imglist->token->value.data; 826 peak_meter_enable(true);
1244 img->display = -1; 827 peak_meter_screen(gwps->display, 0, peak_meter_y,
1245 imglist = imglist->next; 828 MIN(h, viewport->y+viewport->height - peak_meter_y));
1246 }
1247#endif
1248 /* dont redraw the viewport if its disabled */
1249 if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
1250 { /* don't draw anything into this one */
1251 vp_refresh_mode = 0; hidden_vp = true;
1252 }
1253 else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN))
1254 {
1255 if (!(skin_viewport->hidden_flags&VP_DRAW_WASHIDDEN))
1256 display->scroll_stop(&skin_viewport->vp);
1257 skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
1258 continue;
1259 }
1260 else if (((skin_viewport->hidden_flags&
1261 (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))
1262 == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)))
1263 {
1264 vp_refresh_mode = WPS_REFRESH_ALL;
1265 skin_viewport->hidden_flags = VP_DRAW_HIDEABLE;
1266 }
1267
1268 if (vp_refresh_mode == WPS_REFRESH_ALL)
1269 {
1270 display->clear_viewport();
1271 } 829 }
1272
1273 /* loop over the lines for this viewport */
1274 struct skin_line *line;
1275 /* %V() doesnt eat the \n which means the first line of text
1276 * is actually going to be one line down. so set line_count to -1
1277 * unless we are using the default viewport which doesnt have this problem */
1278 int line_count = skin_viewport->label==VP_DEFAULT_LABEL?0:-1;
1279
1280 for (line = skin_viewport->lines; line; line = line->next, line_count++)
1281 {
1282 struct skin_subline *subline;
1283 memset(linebuf, 0, sizeof(linebuf));
1284 update_line = false;
1285
1286 /* get current subline for the line */
1287 new_subline_refresh = update_curr_subline(gwps, line);
1288 subline = line->curr_subline;
1289 flags = line->curr_subline->line_type;
1290
1291 if (vp_refresh_mode == WPS_REFRESH_ALL || (flags & vp_refresh_mode)
1292 || new_subline_refresh || hidden_vp)
1293 {
1294 /* get_line tells us if we need to update the line */
1295 update_line = get_line(gwps, subline, &align,
1296 linebuf, sizeof(linebuf), vp_refresh_mode);
1297 }
1298#ifdef HAVE_LCD_BITMAP
1299 /* peakmeter */
1300 if (flags & vp_refresh_mode & WPS_REFRESH_PEAK_METER)
1301 {
1302 if (!data->peak_meter_enabled)
1303 {
1304 peak_meter_enable(false);
1305 }
1306 else
1307 {
1308 /* the peakmeter should be alone on its line */
1309 update_line = false;
1310
1311 int h = font_get(skin_viewport->vp.font)->height;
1312 int peak_meter_y = line_count* h;
1313
1314 /* The user might decide to have the peak meter in the last
1315 line so that it is only displayed if no status bar is
1316 visible. If so we neither want do draw nor enable the
1317 peak meter. */
1318 if (peak_meter_y + h <= skin_viewport->vp.y+skin_viewport->vp.height) {
1319 peak_meter_enable(true);
1320 peak_meter_screen(gwps->display, 0, peak_meter_y,
1321 MIN(h, skin_viewport->vp.y+skin_viewport->vp.height - peak_meter_y));
1322 }
1323 }
1324 }
1325
1326#else /* HAVE_LCD_CHARCELL */
1327
1328 /* progressbar */
1329 if (flags & vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
1330 {
1331 if (data->full_line_progressbar)
1332 draw_player_fullbar(gwps, linebuf, sizeof(linebuf));
1333 else
1334 draw_player_progress(gwps);
1335 }
1336#endif
1337
1338 if (line_count>= 0 && update_line && !hidden_vp &&
1339 /* conditionals clear the line which means if the %Vd is put into the default
1340 viewport there will be a blank line.
1341 To get around this we dont allow any actual drawing to happen in the
1342 deault vp if other vp's are defined */
1343 ((skin_viewport->label != VP_DEFAULT_LABEL && viewport_list->next) ||
1344 !viewport_list->next))
1345 {
1346 if (flags & WPS_REFRESH_SCROLL)
1347 {
1348 /* if the line is a scrolling one we don't want to update
1349 too often, so that it has the time to scroll */
1350 if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh)
1351 write_line(display, &align, line_count, true);
1352 }
1353 else
1354 write_line(display, &align, line_count, false);
1355 }
1356 }
1357#ifdef HAVE_LCD_BITMAP
1358 /* progressbar */
1359 if (vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
1360 {
1361 struct skin_token_list *bar = gwps->data->progressbars;
1362 while (bar)
1363 {
1364 struct progressbar *thisbar = (struct progressbar*)bar->token->value.data;
1365 if (thisbar->vp == &skin_viewport->vp && thisbar->draw)
1366 {
1367 draw_progressbar(gwps, thisbar);
1368 }
1369 bar = bar->next;
1370 }
1371 }
1372 /* Now display any images in this viewport */
1373 if (!hidden_vp)
1374 wps_display_images(gwps, &skin_viewport->vp);
1375#endif
1376 } 830 }
1377
1378 /* Restore the default viewport */
1379 display->set_viewport(NULL);
1380
1381 display->update();
1382
1383 return true;
1384} 831}
1385 832
1386bool skin_has_sbs(enum screen_type screen, struct wps_data *data) 833bool 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)
1396#endif 843#endif
1397 return draw; 844 return draw;
1398} 845}
846#endif
1399 847
1400/* do the button loop as often as required for the peak meters to update 848/* do the button loop as often as required for the peak meters to update
1401 * with a good refresh rate. 849 * with a good refresh rate.
@@ -1434,7 +882,7 @@ int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout)
1434 FOR_NB_SCREENS(i) 882 FOR_NB_SCREENS(i)
1435 { 883 {
1436 if(gwps[i].data->peak_meter_enabled) 884 if(gwps[i].data->peak_meter_enabled)
1437 skin_update(&gwps[i], WPS_REFRESH_PEAK_METER); 885 skin_update(&gwps[i], SKIN_REFRESH_PEAK_METER);
1438 next_refresh += HZ / PEAK_METER_FPS; 886 next_refresh += HZ / PEAK_METER_FPS;
1439 } 887 }
1440 } 888 }
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002-2007 Björn Stenberg
11 * Copyright (C) 2007-2008 Nicolas Pennequin
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include "config.h"
23#include <stdio.h>
24#include "wps_internals.h"
25#include "skin_engine.h"
26#include "statusbar-skinned.h"
27
28#ifndef _SKIN_DISPLAY_H_
29#define _SKIN_DISPLAY_H_
30
31
32#ifdef HAVE_LCD_BITMAP
33void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb);
34void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer);
35/* clears the area where the image was shown */
36void clear_image_pos(struct gui_wps *gwps, struct gui_img *img);
37void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage);
38void wps_display_images(struct gui_wps *gwps, struct viewport* vp);
39#else
40bool draw_player_progress(struct gui_wps *gwps);
41void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size);
42#endif
43
44/* Evaluate the conditional that is at *token_index and return whether a skip
45 has ocurred. *token_index is updated with the new position.
46*/
47int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options);
48/* Display a line appropriately according to its alignment format.
49 format_align contains the text, separated between left, center and right.
50 line is the index of the line on the screen.
51 scroll indicates whether the line is a scrolling one or not.
52*/
53void write_line(struct screen *display,
54 struct align_pos *format_align,
55 int line,
56 bool scroll);
57void draw_peakmeters(struct gui_wps *gwps, int line_number,
58 struct viewport *viewport);
59#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 @@
23#ifndef _SKIN_ENGINE_H 23#ifndef _SKIN_ENGINE_H
24#define _SKIN_ENGINE_H 24#define _SKIN_ENGINE_H
25 25
26#include "skin_buffer.h" 26#ifndef PLUGIN
27
28#include "skin_fonts.h"
29#include "tag_table.h"
27 30
28#include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */ 31#include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */
29 32
@@ -39,13 +42,37 @@ enum skinnable_screens {
39}; 42};
40 43
41 44
45#ifdef HAVE_LCD_BITMAP
46#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
47 + (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES))
48
49#if (NB_SCREENS > 1)
50#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
51 + (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES))
52#else
53#define REMOTE_BUFFER 0
54#endif
55
56
57#define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER + SKIN_FONT_SIZE) + \
58 (WPS_MAX_TOKENS * \
59 (sizeof(struct wps_token) + (sizeof(struct skin_element))))
60#endif
61
62#ifdef HAVE_LCD_CHARCELLS
63#define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \
64 (WPS_MAX_TOKENS * \
65 (sizeof(struct wps_token) + (sizeof(struct skin_element))))
66#endif
67
68
42#ifdef HAVE_TOUCHSCREEN 69#ifdef HAVE_TOUCHSCREEN
43int skin_get_touchaction(struct wps_data *data, int* edge_offset); 70int skin_get_touchaction(struct wps_data *data, int* edge_offset);
44void skin_disarm_touchregions(struct wps_data *data); 71void skin_disarm_touchregions(struct wps_data *data);
45#endif 72#endif
46 73
47/* Do a update_type update of the skinned screen */ 74/* Do a update_type update of the skinned screen */
48bool skin_update(struct gui_wps *gwps, unsigned int update_type); 75void skin_update(struct gui_wps *gwps, unsigned int update_type);
49 76
50/* 77/*
51 * setup up the skin-data from a format-buffer (isfile = false) 78 * setup up the skin-data from a format-buffer (isfile = false)
@@ -72,3 +99,5 @@ void skin_backdrop_init(void);
72 */ 99 */
73int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout); 100int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout);
74#endif 101#endif
102
103#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)
88 pf = &font->font; 88 pf = &font->font;
89 if (!font->buffer) 89 if (!font->buffer)
90 { 90 {
91 pf->buffer_start = skin_buffer_alloc(SKIN_FONT_SIZE); 91 pf->buffer_start = (char*)skin_buffer_alloc(SKIN_FONT_SIZE);
92 if (!pf->buffer_start) 92 if (!pf->buffer_start)
93 return -1; 93 return -1;
94 font->buffer = pf->buffer_start; 94 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 @@
27#include "file.h" 27#include "file.h"
28#include "settings.h" 28#include "settings.h"
29#include "font.h" 29#include "font.h"
30#include "skin_buffer.h"
31 30
32#ifndef _SKINFONTS_H_ 31#ifndef _SKINFONTS_H_
33#define _SKINFONTS_H_ 32#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 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr 10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr
11 * 2010 Jonathan Gordon
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -28,6 +29,10 @@
28#include "plugin.h" 29#include "plugin.h"
29#include "viewport.h" 30#include "viewport.h"
30 31
32#include "skin_buffer.h"
33#include "skin_parser.h"
34#include "tag_table.h"
35
31#ifdef __PCTOOL__ 36#ifdef __PCTOOL__
32#ifdef WPSEDITOR 37#ifdef WPSEDITOR
33#include "proxy.h" 38#include "proxy.h"
@@ -71,377 +76,29 @@
71 76
72#define WPS_ERROR_INVALID_PARAM -1 77#define WPS_ERROR_INVALID_PARAM -1
73 78
74/* which screen are we parsing for? */
75static enum screen_type curr_screen;
76
77/* level of current conditional.
78 -1 means we're not in a conditional. */
79static int level = -1;
80
81/* index of the last WPS_TOKEN_CONDITIONAL_OPTION
82 or WPS_TOKEN_CONDITIONAL_START in current level */
83static int lastcond[WPS_MAX_COND_LEVEL];
84
85/* index of the WPS_TOKEN_CONDITIONAL in current level */
86static int condindex[WPS_MAX_COND_LEVEL];
87
88/* number of condtional options in current level */
89static int numoptions[WPS_MAX_COND_LEVEL];
90
91/* line number, debug only */
92static int line_number;
93
94/* the current viewport */
95static struct skin_viewport *curr_vp;
96/* the current line, linked to the above viewport */
97static struct skin_line *curr_line;
98
99static int follow_lang_direction = 0;
100
101#if defined(DEBUG) || defined(SIMULATOR)
102/* debugging function */
103extern void print_debug_info(struct wps_data *data, int fail, int line);
104extern void debug_skin_usage(void);
105#endif
106
107/* Function for parsing of details for a token. At the moment the
108 function is called, the token type has already been set. The
109 function must fill in the details and possibly add more tokens
110 to the token array. It should return the number of chars that
111 has been consumed.
112
113 wps_bufptr points to the char following the tag (i.e. where
114 details begin).
115 token is the pointer to the 'main' token being parsed
116 */
117typedef int (*wps_tag_parse_func)(const char *wps_bufptr,
118 struct wps_token *token, struct wps_data *wps_data);
119
120struct wps_tag {
121 enum wps_token_type type;
122 const char name[3];
123 unsigned char refresh_type;
124 const wps_tag_parse_func parse_func;
125};
126static int skip_end_of_line(const char *wps_bufptr);
127/* prototypes of all special parse functions : */
128static int parse_timeout(const char *wps_bufptr,
129 struct wps_token *token, struct wps_data *wps_data);
130static int parse_progressbar(const char *wps_bufptr,
131 struct wps_token *token, struct wps_data *wps_data);
132static int parse_dir_level(const char *wps_bufptr,
133 struct wps_token *token, struct wps_data *wps_data);
134static int parse_setting_and_lang(const char *wps_bufptr,
135 struct wps_token *token, struct wps_data *wps_data);
136
137
138static int parse_languagedirection(const char *wps_bufptr,
139 struct wps_token *token, struct wps_data *wps_data)
140{
141 (void)wps_bufptr;
142 (void)token;
143 (void)wps_data;
144 follow_lang_direction = 2; /* 2 because it is decremented immediatly after
145 this token is parsed, after the next token it
146 will be 0 again. */
147 return 0;
148}
149 79
150#ifdef HAVE_LCD_BITMAP 80static bool isdefault(struct skin_tag_parameter *param)
151static int parse_viewport_display(const char *wps_bufptr,
152 struct wps_token *token, struct wps_data *wps_data);
153static int parse_playlistview(const char *wps_bufptr,
154 struct wps_token *token, struct wps_data *wps_data);
155static int parse_viewport(const char *wps_bufptr,
156 struct wps_token *token, struct wps_data *wps_data);
157static int parse_statusbar_enable(const char *wps_bufptr,
158 struct wps_token *token, struct wps_data *wps_data);
159static int parse_statusbar_disable(const char *wps_bufptr,
160 struct wps_token *token, struct wps_data *wps_data);
161static int parse_statusbar_inbuilt(const char *wps_bufptr,
162 struct wps_token *token, struct wps_data *wps_data);
163static int parse_image_display(const char *wps_bufptr,
164 struct wps_token *token, struct wps_data *wps_data);
165static int parse_image_load(const char *wps_bufptr,
166 struct wps_token *token, struct wps_data *wps_data);
167static int parse_font_load(const char *wps_bufptr,
168 struct wps_token *token, struct wps_data *wps_data);
169#endif /*HAVE_LCD_BITMAP */
170#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
171static int parse_viewportcolour(const char *wps_bufptr,
172 struct wps_token *token, struct wps_data *wps_data);
173static int parse_image_special(const char *wps_bufptr,
174 struct wps_token *token, struct wps_data *wps_data);
175#endif
176#ifdef HAVE_ALBUMART
177static int parse_albumart_load(const char *wps_bufptr,
178 struct wps_token *token, struct wps_data *wps_data);
179static int parse_albumart_display(const char *wps_bufptr,
180 struct wps_token *token, struct wps_data *wps_data);
181#endif /* HAVE_ALBUMART */
182#ifdef HAVE_TOUCHSCREEN
183static int parse_touchregion(const char *wps_bufptr,
184 struct wps_token *token, struct wps_data *wps_data);
185#else
186static int fulline_tag_not_supported(const char *wps_bufptr,
187 struct wps_token *token, struct wps_data *wps_data)
188{ 81{
189 (void)token; (void)wps_data; 82 return param->type == DEFAULT;
190 return skip_end_of_line(wps_bufptr);
191} 83}
192#define parse_touchregion fulline_tag_not_supported
193#endif
194#ifdef CONFIG_RTC
195#define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
196#else
197#define WPS_RTC_REFRESH WPS_REFRESH_STATIC
198#endif
199 84
200/* array of available tags - those with more characters have to go first
201 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
202static const struct wps_tag all_tags[] = {
203
204 { WPS_TOKEN_ALIGN_CENTER, "ac", 0, NULL },
205 { WPS_TOKEN_ALIGN_LEFT, "al", 0, NULL },
206 { WPS_TOKEN_ALIGN_LEFT_RTL, "aL", 0, NULL },
207 { WPS_TOKEN_ALIGN_RIGHT, "ar", 0, NULL },
208 { WPS_TOKEN_ALIGN_RIGHT_RTL, "aR", 0, NULL },
209 { WPS_NO_TOKEN, "ax", 0, parse_languagedirection },
210
211 { WPS_TOKEN_BATTERY_PERCENT, "bl", WPS_REFRESH_DYNAMIC, parse_progressbar },
212 { WPS_TOKEN_BATTERY_VOLTS, "bv", WPS_REFRESH_DYNAMIC, NULL },
213 { WPS_TOKEN_BATTERY_TIME, "bt", WPS_REFRESH_DYNAMIC, NULL },
214 { WPS_TOKEN_BATTERY_SLEEPTIME, "bs", WPS_REFRESH_DYNAMIC, NULL },
215#if CONFIG_CHARGING >= CHARGING_MONITOR
216 { WPS_TOKEN_BATTERY_CHARGING, "bc", WPS_REFRESH_DYNAMIC, NULL },
217#endif
218#if CONFIG_CHARGING
219 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED,"bp", WPS_REFRESH_DYNAMIC, NULL },
220#endif
221#ifdef HAVE_USB_POWER
222 { WPS_TOKEN_USB_POWERED, "bu", WPS_REFRESH_DYNAMIC, NULL },
223#endif
224 85
225 { WPS_TOKEN_RTC_PRESENT , "cc", WPS_REFRESH_STATIC, NULL }, 86/* which screen are we parsing for? */
226 { WPS_TOKEN_RTC_DAY_OF_MONTH, "cd", WPS_RTC_REFRESH, NULL }, 87static enum screen_type curr_screen;
227 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,"ce", WPS_RTC_REFRESH, NULL },
228 { WPS_TOKEN_RTC_12HOUR_CFG, "cf", WPS_RTC_REFRESH, NULL },
229 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", WPS_RTC_REFRESH, NULL },
230 { WPS_TOKEN_RTC_HOUR_24, "ck", WPS_RTC_REFRESH, NULL },
231 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", WPS_RTC_REFRESH, NULL },
232 { WPS_TOKEN_RTC_HOUR_12, "cl", WPS_RTC_REFRESH, NULL },
233 { WPS_TOKEN_RTC_MONTH, "cm", WPS_RTC_REFRESH, NULL },
234 { WPS_TOKEN_RTC_MINUTE, "cM", WPS_RTC_REFRESH, NULL },
235 { WPS_TOKEN_RTC_SECOND, "cS", WPS_RTC_REFRESH, NULL },
236 { WPS_TOKEN_RTC_YEAR_2_DIGITS, "cy", WPS_RTC_REFRESH, NULL },
237 { WPS_TOKEN_RTC_YEAR_4_DIGITS, "cY", WPS_RTC_REFRESH, NULL },
238 { WPS_TOKEN_RTC_AM_PM_UPPER, "cP", WPS_RTC_REFRESH, NULL },
239 { WPS_TOKEN_RTC_AM_PM_LOWER, "cp", WPS_RTC_REFRESH, NULL },
240 { WPS_TOKEN_RTC_WEEKDAY_NAME, "ca", WPS_RTC_REFRESH, NULL },
241 { WPS_TOKEN_RTC_MONTH_NAME, "cb", WPS_RTC_REFRESH, NULL },
242 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", WPS_RTC_REFRESH, NULL },
243 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", WPS_RTC_REFRESH, NULL },
244
245 /* current file */
246 { WPS_TOKEN_FILE_BITRATE, "fb", WPS_REFRESH_STATIC, NULL },
247 { WPS_TOKEN_FILE_CODEC, "fc", WPS_REFRESH_STATIC, NULL },
248 { WPS_TOKEN_FILE_FREQUENCY, "ff", WPS_REFRESH_STATIC, NULL },
249 { WPS_TOKEN_FILE_FREQUENCY_KHZ, "fk", WPS_REFRESH_STATIC, NULL },
250 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", WPS_REFRESH_STATIC, NULL },
251 { WPS_TOKEN_FILE_NAME, "fn", WPS_REFRESH_STATIC, NULL },
252 { WPS_TOKEN_FILE_PATH, "fp", WPS_REFRESH_STATIC, NULL },
253 { WPS_TOKEN_FILE_SIZE, "fs", WPS_REFRESH_STATIC, NULL },
254 { WPS_TOKEN_FILE_VBR, "fv", WPS_REFRESH_STATIC, NULL },
255 { WPS_TOKEN_FILE_DIRECTORY, "d", WPS_REFRESH_STATIC,
256 parse_dir_level },
257
258 /* next file */
259 { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_STATIC, NULL },
260 { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_STATIC, NULL },
261 { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_STATIC, NULL },
262 { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_STATIC, NULL },
263 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_STATIC, NULL },
264 { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_STATIC, NULL },
265 { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_STATIC, NULL },
266 { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_STATIC, NULL },
267 { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_STATIC, NULL },
268 { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_STATIC,
269 parse_dir_level },
270
271 /* current metadata */
272 { WPS_TOKEN_METADATA_ARTIST, "ia", WPS_REFRESH_STATIC, NULL },
273 { WPS_TOKEN_METADATA_COMPOSER, "ic", WPS_REFRESH_STATIC, NULL },
274 { WPS_TOKEN_METADATA_ALBUM, "id", WPS_REFRESH_STATIC, NULL },
275 { WPS_TOKEN_METADATA_ALBUM_ARTIST, "iA", WPS_REFRESH_STATIC, NULL },
276 { WPS_TOKEN_METADATA_GROUPING, "iG", WPS_REFRESH_STATIC, NULL },
277 { WPS_TOKEN_METADATA_GENRE, "ig", WPS_REFRESH_STATIC, NULL },
278 { WPS_TOKEN_METADATA_DISC_NUMBER, "ik", WPS_REFRESH_STATIC, NULL },
279 { WPS_TOKEN_METADATA_TRACK_NUMBER, "in", WPS_REFRESH_STATIC, NULL },
280 { WPS_TOKEN_METADATA_TRACK_TITLE, "it", WPS_REFRESH_STATIC, NULL },
281 { WPS_TOKEN_METADATA_VERSION, "iv", WPS_REFRESH_STATIC, NULL },
282 { WPS_TOKEN_METADATA_YEAR, "iy", WPS_REFRESH_STATIC, NULL },
283 { WPS_TOKEN_METADATA_COMMENT, "iC", WPS_REFRESH_STATIC, NULL },
284
285 /* next metadata */
286 { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_STATIC, NULL },
287 { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_STATIC, NULL },
288 { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_STATIC, NULL },
289 { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_STATIC, NULL },
290 { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_STATIC, NULL },
291 { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_STATIC, NULL },
292 { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_STATIC, NULL },
293 { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_STATIC, NULL },
294 { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_STATIC, NULL },
295 { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_STATIC, NULL },
296 { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_STATIC, NULL },
297 { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_STATIC, NULL },
298
299#if (CONFIG_CODEC != MAS3507D)
300 { WPS_TOKEN_SOUND_PITCH, "Sp", WPS_REFRESH_DYNAMIC, NULL },
301#endif
302#if (CONFIG_CODEC == SWCODEC)
303 { WPS_TOKEN_SOUND_SPEED, "Ss", WPS_REFRESH_DYNAMIC, NULL },
304#endif
305#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
306 { WPS_TOKEN_VLED_HDD, "lh", WPS_REFRESH_DYNAMIC, NULL },
307#endif
308
309 { WPS_TOKEN_MAIN_HOLD, "mh", WPS_REFRESH_DYNAMIC, NULL },
310
311#ifdef HAS_REMOTE_BUTTON_HOLD
312 { WPS_TOKEN_REMOTE_HOLD, "mr", WPS_REFRESH_DYNAMIC, NULL },
313#else
314 { WPS_TOKEN_UNKNOWN, "mr", 0, NULL },
315#endif
316
317 { WPS_TOKEN_REPEAT_MODE, "mm", WPS_REFRESH_DYNAMIC, NULL },
318 { WPS_TOKEN_PLAYBACK_STATUS, "mp", WPS_REFRESH_DYNAMIC, NULL },
319 { WPS_TOKEN_BUTTON_VOLUME, "mv", WPS_REFRESH_DYNAMIC,
320 parse_timeout },
321
322#ifdef HAVE_LCD_BITMAP
323 { WPS_TOKEN_PEAKMETER, "pm", WPS_REFRESH_PEAK_METER, NULL },
324#else
325 { WPS_TOKEN_PLAYER_PROGRESSBAR, "pf",
326 WPS_REFRESH_DYNAMIC | WPS_REFRESH_PLAYER_PROGRESS, parse_progressbar },
327#endif
328 { WPS_TOKEN_PROGRESSBAR, "pb", WPS_REFRESH_PLAYER_PROGRESS,
329 parse_progressbar },
330
331 { WPS_TOKEN_VOLUME, "pv", WPS_REFRESH_DYNAMIC,
332 parse_progressbar },
333
334 { WPS_TOKEN_TRACK_ELAPSED_PERCENT, "px", WPS_REFRESH_DYNAMIC, NULL },
335 { WPS_TOKEN_TRACK_TIME_ELAPSED, "pc", WPS_REFRESH_DYNAMIC, NULL },
336 { WPS_TOKEN_TRACK_TIME_REMAINING, "pr", WPS_REFRESH_DYNAMIC, NULL },
337 { WPS_TOKEN_TRACK_LENGTH, "pt", WPS_REFRESH_STATIC, NULL },
338 { WPS_TOKEN_TRACK_STARTING, "pS", WPS_REFRESH_DYNAMIC, parse_timeout },
339 { WPS_TOKEN_TRACK_ENDING, "pE", WPS_REFRESH_DYNAMIC, parse_timeout },
340
341 { WPS_TOKEN_PLAYLIST_POSITION, "pp", WPS_REFRESH_STATIC, NULL },
342 { WPS_TOKEN_PLAYLIST_ENTRIES, "pe", WPS_REFRESH_STATIC, NULL },
343 { WPS_TOKEN_PLAYLIST_NAME, "pn", WPS_REFRESH_STATIC, NULL },
344 { WPS_TOKEN_PLAYLIST_SHUFFLE, "ps", WPS_REFRESH_DYNAMIC, NULL },
345
346#ifdef HAVE_TAGCACHE
347 { WPS_TOKEN_DATABASE_PLAYCOUNT, "rp", WPS_REFRESH_DYNAMIC, NULL },
348 { WPS_TOKEN_DATABASE_RATING, "rr", WPS_REFRESH_DYNAMIC, NULL },
349 { WPS_TOKEN_DATABASE_AUTOSCORE, "ra", WPS_REFRESH_DYNAMIC, NULL },
350#endif
351
352#if CONFIG_CODEC == SWCODEC
353 { WPS_TOKEN_REPLAYGAIN, "rg", WPS_REFRESH_STATIC, NULL },
354 { WPS_TOKEN_CROSSFADE, "xf", WPS_REFRESH_DYNAMIC, NULL },
355#endif
356
357 { WPS_TOKEN_HAVE_TUNER, "tp", WPS_REFRESH_STATIC, NULL },
358#if CONFIG_TUNER /* Re-uses the 't' and 'T' prefixes, be careful about doubleups */
359 { WPS_TOKEN_TUNER_TUNED, "tt", WPS_REFRESH_DYNAMIC, NULL },
360 { WPS_TOKEN_TUNER_SCANMODE, "tm", WPS_REFRESH_DYNAMIC, NULL },
361 { WPS_TOKEN_TUNER_STEREO, "ts", WPS_REFRESH_DYNAMIC, NULL },
362 { WPS_TOKEN_TUNER_MINFREQ, "ta", WPS_REFRESH_STATIC, NULL },
363 { WPS_TOKEN_TUNER_MAXFREQ, "tb", WPS_REFRESH_STATIC, NULL },
364 { WPS_TOKEN_TUNER_CURFREQ, "tf", WPS_REFRESH_DYNAMIC, NULL },
365 { WPS_TOKEN_PRESET_ID, "Ti", WPS_REFRESH_STATIC, NULL },
366 { WPS_TOKEN_PRESET_NAME, "Tn", WPS_REFRESH_STATIC, NULL },
367 { WPS_TOKEN_PRESET_FREQ, "Tf", WPS_REFRESH_STATIC, NULL },
368 { WPS_TOKEN_PRESET_COUNT, "Tc", WPS_REFRESH_STATIC, NULL },
369 { WPS_TOKEN_HAVE_RDS, "tx", WPS_REFRESH_STATIC, NULL },
370#ifdef HAVE_RDS_CAP
371 { WPS_TOKEN_RDS_NAME, "ty", WPS_REFRESH_DYNAMIC, NULL },
372 { WPS_TOKEN_RDS_TEXT, "tz", WPS_REFRESH_DYNAMIC, NULL },
373#endif
374#endif /* CONFIG_TUNER */
375
376 { WPS_NO_TOKEN, "s", WPS_REFRESH_SCROLL, NULL },
377 { WPS_TOKEN_SUBLINE_TIMEOUT, "t", 0, parse_timeout },
378 88
379#ifdef HAVE_LCD_BITMAP 89/* the current viewport */
380 { WPS_NO_TOKEN, "we", 0, parse_statusbar_enable }, 90static struct skin_element *curr_viewport_element;
381 { WPS_NO_TOKEN, "wd", 0, parse_statusbar_disable }, 91static struct skin_viewport *curr_vp;
382 { WPS_TOKEN_DRAW_INBUILTBAR, "wi", WPS_REFRESH_DYNAMIC, parse_statusbar_inbuilt },
383 92
384 { WPS_NO_TOKEN, "xl", 0, parse_image_load }, 93struct line *curr_line;
385 94
386 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", WPS_REFRESH_STATIC, 95static int follow_lang_direction = 0;
387 parse_image_display },
388 96
389 { WPS_TOKEN_IMAGE_DISPLAY, "x", 0, parse_image_load }, 97typedef int (*parse_function)(struct skin_element *element,
390 { WPS_NO_TOKEN, "Fl", 0, parse_font_load }, 98 struct wps_token *token,
391#ifdef HAVE_ALBUMART 99 struct wps_data *wps_data);
392 { WPS_NO_TOKEN, "Cl", 0, parse_albumart_load },
393 { WPS_TOKEN_ALBUMART_DISPLAY, "Cd", WPS_REFRESH_STATIC, parse_albumart_display },
394 { WPS_TOKEN_ALBUMART_FOUND, "C", WPS_REFRESH_STATIC, NULL },
395#endif
396 100
397 { WPS_VIEWPORT_ENABLE, "Vd", WPS_REFRESH_DYNAMIC,
398 parse_viewport_display },
399 { WPS_TOKEN_UIVIEWPORT_ENABLE, "VI", WPS_REFRESH_STATIC,
400 parse_viewport_display },
401#ifdef HAVE_LCD_BITMAP 101#ifdef HAVE_LCD_BITMAP
402 { WPS_VIEWPORT_CUSTOMLIST, "Vp", WPS_REFRESH_STATIC, parse_playlistview },
403 { WPS_TOKEN_LIST_TITLE_TEXT, "Lt", WPS_REFRESH_DYNAMIC, NULL },
404 { WPS_TOKEN_LIST_TITLE_ICON, "Li", WPS_REFRESH_DYNAMIC, NULL },
405#endif
406#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
407 { WPS_TOKEN_VIEWPORT_FGCOLOUR, "Vf", WPS_REFRESH_STATIC, parse_viewportcolour },
408 { WPS_TOKEN_VIEWPORT_BGCOLOUR, "Vb", WPS_REFRESH_STATIC, parse_viewportcolour },
409#endif
410 { WPS_NO_TOKEN, "V", 0, parse_viewport },
411
412#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
413 { WPS_TOKEN_IMAGE_BACKDROP, "X", 0, parse_image_special },
414#endif
415#endif
416
417 { WPS_TOKEN_SETTING, "St", WPS_REFRESH_DYNAMIC,
418 parse_setting_and_lang },
419 { WPS_TOKEN_TRANSLATEDSTRING, "Sx", WPS_REFRESH_STATIC,
420 parse_setting_and_lang },
421 { WPS_TOKEN_LANG_IS_RTL , "Sr", WPS_REFRESH_STATIC, NULL },
422
423 { WPS_TOKEN_LASTTOUCH, "Tl", WPS_REFRESH_DYNAMIC, parse_timeout },
424 { WPS_TOKEN_CURRENT_SCREEN, "cs", WPS_REFRESH_DYNAMIC, NULL },
425 { WPS_NO_TOKEN, "T", 0, parse_touchregion },
426
427
428 /* Recording Tokens */
429 { WPS_TOKEN_HAVE_RECORDING, "Rp", WPS_REFRESH_STATIC, NULL },
430#ifdef HAVE_RECORDING
431 { WPS_TOKEN_IS_RECORDING, "Rr", WPS_REFRESH_DYNAMIC, NULL },
432 { WPS_TOKEN_REC_FREQ, "Rf", WPS_REFRESH_DYNAMIC, NULL },
433 { WPS_TOKEN_REC_ENCODER, "Re", WPS_REFRESH_DYNAMIC, NULL },
434 { WPS_TOKEN_REC_BITRATE, "Rb", WPS_REFRESH_DYNAMIC, NULL },
435 { WPS_TOKEN_REC_MONO, "Rm", WPS_REFRESH_DYNAMIC, NULL },
436 { WPS_TOKEN_REC_SECONDS, "Rs", WPS_REFRESH_DYNAMIC, NULL },
437 { WPS_TOKEN_REC_MINUTES, "Rn", WPS_REFRESH_DYNAMIC, NULL },
438 { WPS_TOKEN_REC_HOURS, "Rh", WPS_REFRESH_DYNAMIC, NULL },
439#endif
440 { WPS_TOKEN_UNKNOWN, "", 0, NULL }
441 /* the array MUST end with an empty string (first char is \0) */
442};
443
444
445/* add a skin_token_list item to the list chain. ALWAYS appended because some of the 102/* add a skin_token_list item to the list chain. ALWAYS appended because some of the
446 * chains require the order to be kept. 103 * chains require the order to be kept.
447 */ 104 */
@@ -459,7 +116,6 @@ static void add_to_ll_chain(struct skin_token_list **list, struct skin_token_lis
459} 116}
460 117
461/* traverse the image linked-list for an image */ 118/* traverse the image linked-list for an image */
462#ifdef HAVE_LCD_BITMAP
463struct gui_img* find_image(char label, struct wps_data *data) 119struct gui_img* find_image(char label, struct wps_data *data)
464{ 120{
465 struct skin_token_list *list = data->images; 121 struct skin_token_list *list = data->images;
@@ -478,10 +134,10 @@ struct gui_img* find_image(char label, struct wps_data *data)
478/* traverse the viewport linked list for a viewport */ 134/* traverse the viewport linked list for a viewport */
479struct skin_viewport* find_viewport(char label, struct wps_data *data) 135struct skin_viewport* find_viewport(char label, struct wps_data *data)
480{ 136{
481 struct skin_token_list *list = data->viewports; 137 struct skin_element *list = data->tree;
482 while (list) 138 while (list)
483 { 139 {
484 struct skin_viewport *vp = (struct skin_viewport *)list->token->value.data; 140 struct skin_viewport *vp = (struct skin_viewport *)list->data;
485 if (vp->label == label) 141 if (vp->label == label)
486 return vp; 142 return vp;
487 list = list->next; 143 list = list->next;
@@ -489,6 +145,7 @@ struct skin_viewport* find_viewport(char label, struct wps_data *data)
489 return NULL; 145 return NULL;
490} 146}
491 147
148#ifdef HAVE_LCD_BITMAP
492 149
493/* create and init a new wpsll item. 150/* create and init a new wpsll item.
494 * passing NULL to token will alloc a new one. 151 * passing NULL to token will alloc a new one.
@@ -498,9 +155,10 @@ struct skin_viewport* find_viewport(char label, struct wps_data *data)
498static struct skin_token_list *new_skin_token_list_item(struct wps_token *token, 155static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
499 void* token_data) 156 void* token_data)
500{ 157{
501 struct skin_token_list *llitem = skin_buffer_alloc(sizeof(struct skin_token_list)); 158 struct skin_token_list *llitem =
159 (struct skin_token_list *)skin_buffer_alloc(sizeof(struct skin_token_list));
502 if (!token) 160 if (!token)
503 token = skin_buffer_alloc(sizeof(struct wps_token)); 161 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
504 if (!llitem || !token) 162 if (!llitem || !token)
505 return NULL; 163 return NULL;
506 llitem->next = NULL; 164 llitem->next = NULL;
@@ -510,108 +168,36 @@ static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
510 return llitem; 168 return llitem;
511} 169}
512 170
513/* Returns the number of chars that should be skipped to jump 171static int parse_statusbar_tags(struct skin_element* element,
514 immediately after the first eol, i.e. to the start of the next line */ 172 struct wps_token *token,
515static int skip_end_of_line(const char *wps_bufptr) 173 struct wps_data *wps_data)
516{
517 line_number++;
518 int skip = 0;
519 while(*(wps_bufptr + skip) != '\n')
520 skip++;
521 return ++skip;
522}
523
524/* Starts a new subline in the current line during parsing */
525static bool skin_start_new_subline(struct skin_line *line, int curr_token)
526{
527 struct skin_subline *subline = skin_buffer_alloc(sizeof(struct skin_subline));
528 if (!subline)
529 return false;
530
531 subline->first_token_idx = curr_token;
532 subline->next = NULL;
533
534 subline->line_type = 0;
535 subline->time_mult = 0;
536
537 line->curr_subline->last_token_idx = curr_token-1;
538 line->curr_subline->next = subline;
539 line->curr_subline = subline;
540 return true;
541}
542
543static bool skin_start_new_line(struct skin_viewport *vp, int curr_token)
544{ 174{
545 struct skin_line *line = skin_buffer_alloc(sizeof(struct skin_line)); 175 (void)element;
546 struct skin_subline *subline = NULL; 176 if (token->type == SKIN_TOKEN_DRAW_INBUILTBAR)
547 if (!line)
548 return false;
549
550 /* init the subline */
551 subline = &line->sublines;
552 subline->first_token_idx = curr_token;
553 subline->next = NULL;
554 subline->line_type = 0;
555 subline->time_mult = 0;
556
557 /* init the new line */
558 line->curr_subline = &line->sublines;
559 line->next = NULL;
560 line->subline_expire_time = 0;
561
562 /* connect to curr_line and vp pointers.
563 * 1) close the previous lines subline
564 * 2) connect to vp pointer
565 * 3) connect to curr_line global pointer
566 */
567 if (curr_line)
568 { 177 {
569 curr_line->curr_subline->last_token_idx = curr_token - 1; 178 token->value.data = (void*)&curr_vp->vp;
570 curr_line->next = line;
571 curr_line->curr_subline = NULL;
572 } 179 }
573 curr_line = line; 180 else
574 if (!vp->lines) 181 {
575 vp->lines = line; 182 struct skin_element *def_vp = wps_data->tree;
576 return true; 183 struct skin_viewport *default_vp = def_vp->data;
577} 184 if (def_vp->params_count == 0)
578 185 {
579#ifdef HAVE_LCD_BITMAP 186 wps_data->wps_sb_tag = true;
580 187 wps_data->show_sb_on_wps = (token->type == SKIN_TOKEN_ENABLE_THEME);
581static int parse_statusbar_enable(const char *wps_bufptr, 188 }
582 struct wps_token *token, 189 if (wps_data->show_sb_on_wps)
583 struct wps_data *wps_data) 190 {
584{ 191 viewport_set_defaults(&default_vp->vp, curr_screen);
585 (void)token; /* Kill warnings */ 192 }
586 wps_data->wps_sb_tag = true; 193 else
587 wps_data->show_sb_on_wps = true; 194 {
588 struct skin_viewport *default_vp = find_viewport(VP_DEFAULT_LABEL, wps_data); 195 viewport_set_fullscreen(&default_vp->vp, curr_screen);
589 viewport_set_defaults(&default_vp->vp, curr_screen); 196 }
590 default_vp->vp.font = FONT_UI; 197 }
591 return skip_end_of_line(wps_bufptr); 198 return 0;
592}
593
594static int parse_statusbar_disable(const char *wps_bufptr,
595 struct wps_token *token,
596 struct wps_data *wps_data)
597{
598 (void)token; /* Kill warnings */
599 wps_data->wps_sb_tag = true;
600 wps_data->show_sb_on_wps = false;
601 struct skin_viewport *default_vp = find_viewport(VP_DEFAULT_LABEL, wps_data);
602 viewport_set_fullscreen(&default_vp->vp, curr_screen);
603 default_vp->vp.font = FONT_UI;
604 return skip_end_of_line(wps_bufptr);
605}
606
607static int parse_statusbar_inbuilt(const char *wps_bufptr,
608 struct wps_token *token, struct wps_data *wps_data)
609{
610 (void)wps_data;
611 token->value.data = (void*)&curr_vp->vp;
612 return skip_end_of_line(wps_bufptr);
613} 199}
614 200
615static int get_image_id(int c) 201static int get_image_id(int c)
616{ 202{
617 if(c >= 'a' && c <= 'z') 203 if(c >= 'a' && c <= 'z')
@@ -625,32 +211,20 @@ static int get_image_id(int c)
625char *get_image_filename(const char *start, const char* bmpdir, 211char *get_image_filename(const char *start, const char* bmpdir,
626 char *buf, int buf_size) 212 char *buf, int buf_size)
627{ 213{
628 const char *end = start; 214 snprintf(buf, buf_size, "%s/%s", bmpdir, start);
629 int bmpdirlen = strlen(bmpdir); 215
630
631 while (*end && *end != ',' && *end != ')')
632 end++;
633 if ( !end || (end - start) >= (buf_size - bmpdirlen - 2) )
634 {
635 buf[0] = '\0';
636 return NULL;
637 }
638
639 strcpy(buf, bmpdir);
640 buf[bmpdirlen] = '/';
641 memcpy( &buf[bmpdirlen + 1], start, end - start);
642 buf[bmpdirlen + 1 + end - start] = 0;
643
644 return buf; 216 return buf;
645} 217}
646 218
647static int parse_image_display(const char *wps_bufptr, 219static int parse_image_display(struct skin_element *element,
648 struct wps_token *token, 220 struct wps_token *token,
649 struct wps_data *wps_data) 221 struct wps_data *wps_data)
650{ 222{
651 char label = wps_bufptr[1]; 223 char *text = element->params[0].data.text;
224 char label = text[0];
225 char sublabel = text[1];
652 int subimage; 226 int subimage;
653 struct gui_img *img;; 227 struct gui_img *img;
654 228
655 /* sanity check */ 229 /* sanity check */
656 img = find_image(label, wps_data); 230 img = find_image(label, wps_data);
@@ -660,7 +234,7 @@ static int parse_image_display(const char *wps_bufptr,
660 return WPS_ERROR_INVALID_PARAM; 234 return WPS_ERROR_INVALID_PARAM;
661 } 235 }
662 236
663 if ((subimage = get_image_id(wps_bufptr[2])) != -1) 237 if ((subimage = get_image_id(sublabel)) != -1)
664 { 238 {
665 if (subimage >= img->num_subimages) 239 if (subimage >= img->num_subimages)
666 return WPS_ERROR_INVALID_PARAM; 240 return WPS_ERROR_INVALID_PARAM;
@@ -674,32 +248,24 @@ static int parse_image_display(const char *wps_bufptr,
674 } 248 }
675} 249}
676 250
677static int parse_image_load(const char *wps_bufptr, 251static int parse_image_load(struct skin_element *element,
678 struct wps_token *token, 252 struct wps_token *token,
679 struct wps_data *wps_data) 253 struct wps_data *wps_data)
680{ 254{
681 const char *ptr = wps_bufptr;
682 const char* filename; 255 const char* filename;
683 const char* id; 256 const char* id;
684 int x,y; 257 int x,y;
685 struct gui_img *img; 258 struct gui_img *img;
686 259
687 /* format: %x|n|filename.bmp|x|y| 260 /* format: %x(n,filename.bmp,x,y)
688 or %xl|n|filename.bmp|x|y| 261 or %xl(n,filename.bmp,x,y)
689 or %xl|n|filename.bmp|x|y|num_subimages| 262 or %xl(n,filename.bmp,x,y,num_subimages)
690 */ 263 */
691 264
692 if (*ptr != '(') 265 id = element->params[0].data.text;
693 return WPS_ERROR_INVALID_PARAM; 266 filename = element->params[1].data.text;
694 267 x = element->params[2].data.number;
695 ptr++; 268 y = element->params[3].data.number;
696
697 if (!(ptr = parse_list("ssdd", NULL, ',', ptr, &id, &filename, &x, &y)))
698 return WPS_ERROR_INVALID_PARAM;
699
700 /* Check there is a terminating ) */
701 if (*ptr != ')' && *ptr != ',')
702 return WPS_ERROR_INVALID_PARAM;
703 269
704 /* check the image number and load state */ 270 /* check the image number and load state */
705 if(find_image(*id, wps_data)) 271 if(find_image(*id, wps_data))
@@ -707,7 +273,7 @@ static int parse_image_load(const char *wps_bufptr,
707 /* Invalid image ID */ 273 /* Invalid image ID */
708 return WPS_ERROR_INVALID_PARAM; 274 return WPS_ERROR_INVALID_PARAM;
709 } 275 }
710 img = skin_buffer_alloc(sizeof(struct gui_img)); 276 img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img));
711 if (!img) 277 if (!img)
712 return WPS_ERROR_INVALID_PARAM; 278 return WPS_ERROR_INVALID_PARAM;
713 /* save a pointer to the filename */ 279 /* save a pointer to the filename */
@@ -717,62 +283,44 @@ static int parse_image_load(const char *wps_bufptr,
717 img->y = y; 283 img->y = y;
718 img->num_subimages = 1; 284 img->num_subimages = 1;
719 img->always_display = false; 285 img->always_display = false;
286 // img->just_drawn = false;
287 img->display = -1;
720 288
721 /* save current viewport */ 289 /* save current viewport */
722 img->vp = &curr_vp->vp; 290 img->vp = &curr_vp->vp;
723 291
724 if (token->type == WPS_TOKEN_IMAGE_DISPLAY) 292 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
725 { 293 {
726 img->always_display = true; 294 img->always_display = true;
727 } 295 }
728 else if (*ptr == ',') 296 else if (element->params_count == 5)
729 { 297 {
730 /* Parse the (optional) number of sub-images */ 298 img->num_subimages = element->params[4].data.number;
731 ptr++;
732 img->num_subimages = atoi(ptr);
733 if (img->num_subimages <= 0) 299 if (img->num_subimages <= 0)
734 return WPS_ERROR_INVALID_PARAM; 300 return WPS_ERROR_INVALID_PARAM;
735 /* Check there is a terminating ) */
736 while(isdigit(*ptr))
737 ptr++;
738 if (*ptr != ')')
739 return WPS_ERROR_INVALID_PARAM;
740 } 301 }
741 struct skin_token_list *item = new_skin_token_list_item(NULL, img); 302 struct skin_token_list *item =
303 (struct skin_token_list *)new_skin_token_list_item(NULL, img);
742 if (!item) 304 if (!item)
743 return WPS_ERROR_INVALID_PARAM; 305 return WPS_ERROR_INVALID_PARAM;
744 add_to_ll_chain(&wps_data->images, item); 306 add_to_ll_chain(&wps_data->images, item);
745 307
746 /* Skip the rest of the line */ 308 return 0;
747 return skip_end_of_line(wps_bufptr);
748} 309}
749struct skin_font { 310struct skin_font {
750 int id; /* the id from font_load */ 311 int id; /* the id from font_load */
751 char *name; /* filename without path and extension */ 312 char *name; /* filename without path and extension */
752}; 313};
753static struct skin_font skinfonts[MAXUSERFONTS]; 314static struct skin_font skinfonts[MAXUSERFONTS];
754static int parse_font_load(const char *wps_bufptr, 315static int parse_font_load(struct skin_element *element,
755 struct wps_token *token, struct wps_data *wps_data) 316 struct wps_token *token,
317 struct wps_data *wps_data)
756{ 318{
757 (void)wps_data; (void)token; 319 (void)wps_data; (void)token;
758 const char *ptr = wps_bufptr; 320 int id = element->params[0].data.number;
759 int id; 321 char *filename = element->params[1].data.text;
760 char *filename; 322 char *ptr;
761 323
762 if (*ptr != '(')
763 return WPS_ERROR_INVALID_PARAM;
764
765 ptr++;
766
767 if (!(ptr = parse_list("ds", NULL, ',', ptr, &id, &filename)))
768 return WPS_ERROR_INVALID_PARAM;
769
770 /* Check there is a terminating ) */
771 if (*ptr != ')')
772 return WPS_ERROR_INVALID_PARAM;
773
774 if (id <= FONT_UI || id >= MAXFONTS-1)
775 return WPS_ERROR_INVALID_PARAM;
776#if defined(DEBUG) || defined(SIMULATOR) 324#if defined(DEBUG) || defined(SIMULATOR)
777 if (skinfonts[id-FONT_FIRSTUSERFONT].name != NULL) 325 if (skinfonts[id-FONT_FIRSTUSERFONT].name != NULL)
778 { 326 {
@@ -782,286 +330,65 @@ static int parse_font_load(const char *wps_bufptr,
782 /* make sure the filename contains .fnt, 330 /* make sure the filename contains .fnt,
783 * we dont actually use it, but require it anyway */ 331 * we dont actually use it, but require it anyway */
784 ptr = strchr(filename, '.'); 332 ptr = strchr(filename, '.');
785 if (!ptr || strncmp(ptr, ".fnt)", 5)) 333 if (!ptr || strncmp(ptr, ".fnt", 4))
786 return WPS_ERROR_INVALID_PARAM; 334 return WPS_ERROR_INVALID_PARAM;
787 skinfonts[id-FONT_FIRSTUSERFONT].id = -1; 335 skinfonts[id-FONT_FIRSTUSERFONT].id = -1;
788 skinfonts[id-FONT_FIRSTUSERFONT].name = filename; 336 skinfonts[id-FONT_FIRSTUSERFONT].name = filename;
789 337
790 return skip_end_of_line(wps_bufptr); 338 return 0;
791} 339}
792 340
793 341
794static int parse_viewport_display(const char *wps_bufptr,
795 struct wps_token *token,
796 struct wps_data *wps_data)
797{
798 (void)wps_data;
799 char letter = wps_bufptr[1];
800
801 if (letter < 'a' || letter > 'z')
802 {
803 /* invalid viewport tag */
804 return WPS_ERROR_INVALID_PARAM;
805 }
806 token->value.i = letter;
807 return 3;
808}
809
810#ifdef HAVE_LCD_BITMAP 342#ifdef HAVE_LCD_BITMAP
811static int parse_playlistview_text(struct playlistviewer *viewer,
812 enum info_line_type line, char* text)
813{
814 int cur_string = 0;
815 const struct wps_tag *tag;
816 int taglen = 0;
817 const char *start = text;
818 if (*text != ',')
819 return -1;
820 text++;
821 viewer->lines[line].count = 0;
822 viewer->lines[line].scroll = false;
823 while (*text != ',' && *text != ')')
824 {
825 if (*text == '%') /* it is a token of some type */
826 {
827 text++;
828 taglen = 0;
829 switch(*text)
830 {
831 case '%':
832 case '<':
833 case '|':
834 case '>':
835 case ';':
836 case '#':
837 case '(':
838 case ')':
839 case ',':
840 /* escaped characters */
841 viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_CHARACTER;
842 viewer->lines[line].strings[cur_string][0] = *text;
843 viewer->lines[line].strings[cur_string++][1] = '\0';
844 text++;
845 break;
846 default:
847 for (tag = all_tags;
848 strncmp(text, tag->name, strlen(tag->name)) != 0;
849 tag++) ;
850 /* %s isnt stored as a tag so manually check for it */
851 if (tag->type == WPS_NO_TOKEN)
852 {
853 if (!strncmp(tag->name, "s", 1))
854 {
855 viewer->lines[line].scroll = true;
856 taglen = 1;
857 }
858 }
859 else if (tag->type == WPS_TOKEN_UNKNOWN)
860 {
861 int i = 0;
862 /* just copy the string */
863 viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_STRING;
864 while (i<(MAX_PLAYLISTLINE_STRLEN-1) && text[i] != ',' && text[i] != ')' && text[i] != '%')
865 {
866 viewer->lines[line].strings[cur_string][i] = text[i];
867 i++;
868 }
869 viewer->lines[line].strings[cur_string][i] = '\0';
870 cur_string++;
871 taglen = i;
872 }
873 else
874 {
875 if (tag->parse_func)
876 {
877 /* unsupported tag, reject */
878 return -1;
879 }
880 taglen = strlen(tag->name);
881 viewer->lines[line].tokens[viewer->lines[line].count++] = tag->type;
882 }
883 text += taglen;
884 }
885 }
886 else
887 {
888 /* regular string */
889 int i = 0;
890 /* just copy the string */
891 viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_STRING;
892 while (i<(MAX_PLAYLISTLINE_STRLEN-1) && text[i] != ',' && text[i] != ')' && text[i] != '%')
893 {
894 viewer->lines[line].strings[cur_string][i] = text[i];
895 i++;
896 }
897 viewer->lines[line].strings[cur_string][i] = '\0';
898 cur_string++;
899 text += i;
900 }
901 }
902 return text - start;
903}
904 343
905static int parse_playlistview(const char *wps_bufptr, 344static int parse_playlistview(struct skin_element *element,
906 struct wps_token *token, struct wps_data *wps_data) 345 struct wps_token *token,
346 struct wps_data *wps_data)
907{ 347{
908 (void)wps_data; 348 (void)wps_data;
909 /* %Vp|<use icons>|<start offset>|info line text|no info text| */ 349 struct playlistviewer *viewer =
910 struct playlistviewer *viewer = skin_buffer_alloc(sizeof(struct playlistviewer)); 350 (struct playlistviewer *)skin_buffer_alloc(sizeof(struct playlistviewer));
911 char *ptr = strchr(wps_bufptr, '('); 351 if (!viewer)
912 int length;
913 if (!viewer || !ptr)
914 return WPS_ERROR_INVALID_PARAM; 352 return WPS_ERROR_INVALID_PARAM;
915 viewer->vp = &curr_vp->vp; 353 viewer->vp = &curr_vp->vp;
916 viewer->show_icons = true; 354 viewer->show_icons = true;
917 viewer->start_offset = atoi(ptr+1); 355 viewer->start_offset = element->params[0].data.number;
356 viewer->lines[0] = element->params[1].data.code;
357 viewer->lines[1] = element->params[2].data.code;
358
918 token->value.data = (void*)viewer; 359 token->value.data = (void*)viewer;
919 ptr = strchr(ptr+1, ','); 360
920 length = parse_playlistview_text(viewer, TRACK_HAS_INFO, ptr); 361 return 0;
921 if (length < 0)
922 return WPS_ERROR_INVALID_PARAM;
923 length = parse_playlistview_text(viewer, TRACK_HAS_NO_INFO, ptr+length);
924 if (length < 0)
925 return WPS_ERROR_INVALID_PARAM;
926
927 return skip_end_of_line(wps_bufptr);
928} 362}
929#endif 363#endif
930 364
931static int parse_viewport(const char *wps_bufptr,
932 struct wps_token *token,
933 struct wps_data *wps_data)
934{
935 (void)token; /* Kill warnings */
936 const char *ptr = wps_bufptr;
937
938 struct skin_viewport *skin_vp = skin_buffer_alloc(sizeof(struct skin_viewport));
939
940 /* check for the optional letter to signify its a hideable viewport */
941 /* %Vl|<label>|<rest of tags>| */
942 skin_vp->hidden_flags = 0;
943 skin_vp->label = VP_NO_LABEL;
944 skin_vp->lines = NULL;
945 if (curr_line)
946 {
947 curr_line->curr_subline->last_token_idx = wps_data->num_tokens
948 - (wps_data->num_tokens > 0 ? 1 : 0);
949 }
950
951 curr_line = NULL;
952 if (!skin_start_new_line(skin_vp, wps_data->num_tokens))
953 return WPS_ERROR_INVALID_PARAM;
954
955 if (*ptr == 'i')
956 {
957 if (*(ptr+1) == '(')
958 {
959 char label = *(ptr+2);
960 if (label >= 'a' && label <= 'z')
961 {
962 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
963 skin_vp->label = VP_INFO_LABEL|label;
964 ptr += 3;
965 }
966 else
967 {
968 if (label != '-')
969 return WPS_ERROR_INVALID_PARAM;
970 skin_vp->label = VP_INFO_LABEL|VP_DEFAULT_LABEL;
971 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
972 ptr += 3;
973 }
974 }
975 else
976 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */
977 }
978 else if (*ptr == 'l')
979 {
980 if (*(ptr+1) == '(')
981 {
982 char label = *(ptr+2);
983 if (label >= 'a' && label <= 'z')
984 {
985 skin_vp->hidden_flags = VP_DRAW_HIDEABLE;
986 skin_vp->label = label;
987 }
988 else
989 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */
990 ptr += 3;
991 }
992 }
993 if (*ptr != ',' && *ptr != '(')
994 return WPS_ERROR_INVALID_PARAM;
995
996 ptr++;
997 struct viewport *vp = &skin_vp->vp;
998 /* format: %V|x|y|width|height|font| */
999 if (!(ptr = viewport_parse_viewport(vp, curr_screen, ptr, ',')))
1000 return WPS_ERROR_INVALID_PARAM;
1001
1002 /* Check for trailing ) */
1003 if (*ptr != ')')
1004 return WPS_ERROR_INVALID_PARAM;
1005 ptr++;
1006
1007 if (follow_lang_direction && lang_is_rtl())
1008 {
1009 vp->flags |= VP_FLAG_ALIGN_RIGHT;
1010 vp->x = screens[curr_screen].lcdwidth - vp->width - vp->x;
1011 }
1012 else
1013 vp->flags &= ~VP_FLAG_ALIGN_RIGHT; /* ignore right-to-left languages */
1014
1015#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) 365#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1016 skin_vp->start_fgcolour = vp->fg_pattern;
1017 skin_vp->start_bgcolour = vp->bg_pattern;
1018#endif
1019 366
1020 struct skin_token_list *list = new_skin_token_list_item(NULL, skin_vp); 367static int parse_viewportcolour(struct skin_element *element,
1021 if (!list) 368 struct wps_token *token,
1022 return WPS_ERROR_INVALID_PARAM; 369 struct wps_data *wps_data)
1023 add_to_ll_chain(&wps_data->viewports, list);
1024 curr_vp = skin_vp;
1025 /* Skip the rest of the line */
1026 return ptr-wps_bufptr;
1027}
1028#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1029static int parse_viewportcolour(const char *wps_bufptr,
1030 struct wps_token *token, struct wps_data *wps_data)
1031{ 370{
1032 (void)wps_data; 371 (void)wps_data;
1033 const char *ptr = wps_bufptr; 372 struct skin_tag_parameter *param = element->params;
1034 int i; 373 struct viewport_colour *colour =
1035 bool found_text; 374 (struct viewport_colour *)skin_buffer_alloc(sizeof(struct viewport_colour));
1036 struct viewport_colour *colour = skin_buffer_alloc(sizeof(struct viewport_colour)); 375 if (!colour)
1037 uint32_t set;
1038 if (*ptr != '(' || !colour)
1039 return -1;
1040 ptr++;
1041 if (!(ptr = parse_list("c", &set, ',', ptr, &colour->colour)))
1042 return -1;
1043 if (*ptr != ')')
1044 return -1; 376 return -1;
1045 if (!set) 377 if (isdefault(param))
378 {
1046 colour->colour = get_viewport_default_colour(curr_screen, 379 colour->colour = get_viewport_default_colour(curr_screen,
1047 token->type == WPS_TOKEN_VIEWPORT_FGCOLOUR); 380 token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
1048 colour->vp = &curr_vp->vp; 381 }
1049 token->value.data = colour; 382 else
1050 /* If there havnt been any text tags between the %V() line and here use
1051 * the colour as the viewport colour. fixes scrolling lines not
1052 * having the correct colour */
1053 i = curr_vp->lines->sublines.first_token_idx;
1054 found_text = false;
1055 while (!found_text && i< curr_vp->lines->sublines.last_token_idx)
1056 { 383 {
1057 if (wps_data->tokens[i++].type != WPS_TOKEN_CHARACTER && 384 if (!parse_color(param->data.text, &colour->colour))
1058 wps_data->tokens[i++].type != WPS_TOKEN_VIEWPORT_FGCOLOUR && 385 return -1;
1059 wps_data->tokens[i++].type != WPS_TOKEN_VIEWPORT_BGCOLOUR )
1060 found_text = true;
1061 } 386 }
1062 if (!found_text) 387 colour->vp = &curr_vp->vp;
388 token->value.data = colour;
389 if (element->line == curr_viewport_element->line)
1063 { 390 {
1064 if (token->type == WPS_TOKEN_VIEWPORT_FGCOLOUR) 391 if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
1065 { 392 {
1066 curr_vp->start_fgcolour = colour->colour; 393 curr_vp->start_fgcolour = colour->colour;
1067 curr_vp->vp.fg_pattern = colour->colour; 394 curr_vp->vp.fg_pattern = colour->colour;
@@ -1072,72 +399,54 @@ static int parse_viewportcolour(const char *wps_bufptr,
1072 curr_vp->vp.bg_pattern = colour->colour; 399 curr_vp->vp.bg_pattern = colour->colour;
1073 } 400 }
1074 } 401 }
1075 ptr++; 402 return 0;
1076 return ptr - wps_bufptr;
1077} 403}
1078 404
1079static int parse_image_special(const char *wps_bufptr, 405static int parse_image_special(struct skin_element *element,
1080 struct wps_token *token, 406 struct wps_token *token,
1081 struct wps_data *wps_data) 407 struct wps_data *wps_data)
1082{ 408{
1083 (void)wps_data; /* kill warning */ 409 (void)wps_data; /* kill warning */
1084 (void)token; 410 (void)token;
1085 const char *pos = NULL;
1086 const char *newline;
1087 bool error = false; 411 bool error = false;
1088 412
1089 pos = strchr(wps_bufptr + 1, ')');
1090 newline = strchr(wps_bufptr, '\n');
1091
1092 error = (pos > newline);
1093
1094#if LCD_DEPTH > 1 413#if LCD_DEPTH > 1
1095 if (token->type == WPS_TOKEN_IMAGE_BACKDROP) 414 if (token->type == SKIN_TOKEN_IMAGE_BACKDROP)
1096 { 415 {
416 char *filename = element->params[0].data.text;
1097 /* format: %X|filename.bmp| or %Xd */ 417 /* format: %X|filename.bmp| or %Xd */
1098 if (!strncmp(wps_bufptr, "(d)", 3)) 418 if (!strcmp(filename, "d"))
1099 { 419 {
1100 wps_data->backdrop = NULL; 420 wps_data->backdrop = NULL;
1101 return skip_end_of_line(wps_bufptr); 421 return 0;
1102 } 422 }
1103 else if (!error) 423 else if (!error)
1104 wps_data->backdrop = (char*)wps_bufptr + 1; 424 {
425 wps_data->backdrop = filename;
426 }
1105 } 427 }
1106#endif 428#endif
1107 if (error)
1108 return WPS_ERROR_INVALID_PARAM;
1109 /* Skip the rest of the line */ 429 /* Skip the rest of the line */
1110 return skip_end_of_line(wps_bufptr); 430 return error ? WPS_ERROR_INVALID_PARAM : 0;
1111} 431}
1112#endif 432#endif
1113 433
1114#endif /* HAVE_LCD_BITMAP */ 434#endif /* HAVE_LCD_BITMAP */
1115 435
1116static int parse_setting_and_lang(const char *wps_bufptr, 436static int parse_setting_and_lang(struct skin_element *element,
1117 struct wps_token *token, 437 struct wps_token *token,
1118 struct wps_data *wps_data) 438 struct wps_data *wps_data)
1119{ 439{
1120 /* NOTE: both the string validations that happen in here will 440 /* NOTE: both the string validations that happen in here will
1121 * automatically PASS on checkwps because its too hard to get 441 * automatically PASS on checkwps because its too hard to get
1122 * settings_list.c and englinsh.lang built for it. 442 * settings_list.c and english.lang built for it.
1123 * If that ever changes remove the #ifndef __PCTOOL__'s here 443 * If that ever changes remove the #ifndef __PCTOOL__'s here
1124 */ 444 */
1125 (void)wps_data; 445 (void)wps_data;
1126 const char *ptr = wps_bufptr; 446 char *temp = element->params[0].data.text;
1127 const char *end; 447 int i;
1128 int i = 0;
1129 char temp[64];
1130
1131 /* Find the setting's cfg_name */
1132 if (*ptr != '(')
1133 return WPS_ERROR_INVALID_PARAM;
1134 ptr++;
1135 end = strchr(ptr,')');
1136 if (!end || (size_t)(end-ptr+1) > sizeof temp)
1137 return WPS_ERROR_INVALID_PARAM;
1138 strlcpy(temp, ptr,end-ptr+1);
1139 448
1140 if (token->type == WPS_TOKEN_TRANSLATEDSTRING) 449 if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
1141 { 450 {
1142#ifndef __PCTOOL__ 451#ifndef __PCTOOL__
1143 i = lang_english_to_id(temp); 452 i = lang_english_to_id(temp);
@@ -1159,170 +468,104 @@ static int parse_setting_and_lang(const char *wps_bufptr,
1159 } 468 }
1160 /* Store the setting number */ 469 /* Store the setting number */
1161 token->value.i = i; 470 token->value.i = i;
1162 471 return 0;
1163 /* Skip the rest of the line */
1164 return end-ptr+2;
1165}
1166
1167
1168static int parse_dir_level(const char *wps_bufptr,
1169 struct wps_token *token,
1170 struct wps_data *wps_data)
1171{
1172 char val[] = { wps_bufptr[1], '\0' };
1173 if (wps_bufptr[0] != '(' || wps_bufptr[2] != ')')
1174 return WPS_ERROR_INVALID_PARAM;
1175 token->value.i = atoi(val);
1176 (void)wps_data; /* Kill warnings */
1177 return 3;
1178} 472}
1179 473
1180static int parse_timeout(const char *wps_bufptr, 474static int parse_timeout_tag(struct skin_element *element,
1181 struct wps_token *token, 475 struct wps_token *token,
1182 struct wps_data *wps_data) 476 struct wps_data *wps_data)
1183{ 477{
1184 int skip = 0; 478 (void)wps_data;
1185 int val = 0; 479 int val = 0;
1186 bool have_point = false; 480 if (element->params_count == 0)
1187 bool have_tenth = false;
1188
1189 (void)wps_data; /* Kill the warning */
1190 if (*wps_bufptr == '(')
1191 {
1192 wps_bufptr++;
1193 skip++;
1194 while ( isdigit(*wps_bufptr) || *wps_bufptr == '.' )
1195 {
1196 if (*wps_bufptr != '.')
1197 {
1198 val *= 10;
1199 val += *wps_bufptr - '0';
1200 if (have_point)
1201 {
1202 have_tenth = true;
1203 wps_bufptr++;
1204 skip++;
1205 break;
1206 }
1207 }
1208 else
1209 have_point = true;
1210
1211 wps_bufptr++;
1212 skip++;
1213 }
1214 if (*wps_bufptr != ')')
1215 return -1;
1216 skip++;
1217 }
1218 if (have_tenth == false)
1219 val *= 10;
1220
1221 if (val == 0 && skip == 0)
1222 { 481 {
1223 /* decide what to do if no value was specified */
1224 switch (token->type) 482 switch (token->type)
1225 { 483 {
1226 case WPS_TOKEN_SUBLINE_TIMEOUT: 484 case SKIN_TOKEN_SUBLINE_TIMEOUT:
1227 return -1; 485 return -1;
1228 case WPS_TOKEN_BUTTON_VOLUME: 486 case SKIN_TOKEN_BUTTON_VOLUME:
1229 case WPS_TOKEN_TRACK_STARTING: 487 case SKIN_TOKEN_TRACK_STARTING:
1230 case WPS_TOKEN_TRACK_ENDING: 488 case SKIN_TOKEN_TRACK_ENDING:
489 case SKIN_TOKEN_LASTTOUCH:
1231 val = 10; 490 val = 10;
1232 break; 491 break;
492 default:
493 break;
1233 } 494 }
1234 } 495 }
496 else
497 val = element->params[0].data.number;
1235 token->value.i = val; 498 token->value.i = val;
1236 499 if (token->type == SKIN_TOKEN_SUBLINE_TIMEOUT)
1237 return skip; 500 curr_line->timeout = val * TIMEOUT_UNIT;
501 return 0;
1238} 502}
1239 503
1240static int parse_progressbar(const char *wps_bufptr, 504static int parse_progressbar_tag(struct skin_element* element,
1241 struct wps_token *token, 505 struct wps_token *token,
1242 struct wps_data *wps_data) 506 struct wps_data *wps_data)
1243{ 507{
1244 /* %pb or %pb|filename|x|y|width|height|
1245 using - for any of the params uses "sane" values */
1246#ifdef HAVE_LCD_BITMAP 508#ifdef HAVE_LCD_BITMAP
1247 enum { 509 struct progressbar *pb;
1248 PB_X = 0, 510 struct skin_token_list *item;
1249 PB_Y,
1250 PB_WIDTH,
1251 PB_HEIGHT,
1252 PB_FILENAME,
1253 };
1254 const char *filename;
1255 int x, y, height, width;
1256 uint32_t set = 0;
1257 const char *ptr = wps_bufptr;
1258 struct progressbar *pb = skin_buffer_alloc(sizeof(struct progressbar));
1259 struct skin_token_list *item = new_skin_token_list_item(token, pb);
1260
1261 if (!pb || !item)
1262 return WPS_ERROR_INVALID_PARAM;
1263
1264 struct viewport *vp = &curr_vp->vp; 511 struct viewport *vp = &curr_vp->vp;
1265 /* we need to know what line number (viewport relative) this pb is, 512 struct skin_tag_parameter *param = element->params;
1266 * so count them... */ 513
1267 int line_num = -1; 514 if (element->params_count == 0 &&
1268 struct skin_line *line = curr_vp->lines; 515 element->tag->type != SKIN_TOKEN_PROGRESSBAR)
1269 while (line) 516 return 0; /* nothing to do */
1270 { 517 pb = (struct progressbar*)skin_buffer_alloc(sizeof(struct progressbar));
1271 line_num++; 518
1272 line = line->next; 519 token->value.data = pb;
1273 } 520
1274 if (curr_vp->label != VP_DEFAULT_LABEL) 521 if (!pb)
1275 line_num--; 522 return WPS_ERROR_INVALID_PARAM;
1276 pb->vp = vp; 523 pb->vp = vp;
1277 pb->have_bitmap_pb = false; 524 pb->have_bitmap_pb = false;
1278 pb->bm.data = NULL; /* no bitmap specified */ 525 pb->bm.data = NULL; /* no bitmap specified */
1279 pb->follow_lang_direction = follow_lang_direction > 0; 526 pb->follow_lang_direction = follow_lang_direction > 0;
1280 pb->draw = false; 527
1281 528 if (element->params_count == 0)
1282 if (*wps_bufptr != '(') /* regular old style */
1283 { 529 {
1284 pb->x = 0; 530 pb->x = 0;
1285 pb->width = vp->width; 531 pb->width = vp->width;
1286 pb->height = SYSFONT_HEIGHT-2; 532 pb->height = SYSFONT_HEIGHT-2;
1287 pb->y = -line_num - 1; /* Will be computed during the rendering */ 533 pb->y = -1; /* Will be computed during the rendering */
1288 if (token->type == WPS_TOKEN_VOLUME || token->type == WPS_TOKEN_BATTERY_PERCENT) 534 pb->type = element->tag->type;
1289 return 0; /* dont add it, let the regular token handling do the work */
1290 pb->type = token->type;
1291 add_to_ll_chain(&wps_data->progressbars, item);
1292 return 0; 535 return 0;
1293 } 536 }
1294 ptr = wps_bufptr + 1; 537
1295 538 item = new_skin_token_list_item(token, pb);
1296 if (!(ptr = parse_list("dddds", &set, ',', ptr, 539 if (!item)
1297 &x, &y, &width, &height, &filename))) 540 return -1;
1298 return WPS_ERROR_INVALID_PARAM; 541 add_to_ll_chain(&wps_data->progressbars, item);
1299 542
1300 if (LIST_VALUE_PARSED(set, PB_FILENAME)) /* filename */ 543 /* (x,y,width,height,filename) */
1301 pb->bm.data = (char*)filename; 544 if (!isdefault(param))
1302 545 pb->x = param->data.number;
1303 if (LIST_VALUE_PARSED(set, PB_X)) /* x */
1304 pb->x = x;
1305 else 546 else
1306 pb->x = vp->x; 547 pb->x = vp->x;
1307 548 param++;
1308 if (LIST_VALUE_PARSED(set, PB_WIDTH)) /* width */ 549
1309 { 550 if (!isdefault(param))
1310 /* A zero width causes a divide-by-zero error later, so reject it */ 551 pb->y = param->data.number;
1311 if (width == 0) 552 else
1312 return WPS_ERROR_INVALID_PARAM; 553 pb->y = -1; /* computed at rendering */
1313 554 param++;
1314 pb->width = width; 555
1315 } 556 if (!isdefault(param))
557 pb->width = param->data.number;
1316 else 558 else
1317 pb->width = vp->width - pb->x; 559 pb->width = vp->width - pb->x;
1318 560 param++;
1319 if (LIST_VALUE_PARSED(set, PB_HEIGHT)) /* height, default to font height */ 561
562 if (!isdefault(param))
1320 { 563 {
1321 /* A zero height makes no sense - reject it */ 564 /* A zero height makes no sense - reject it */
1322 if (height == 0) 565 if (param->data.number == 0)
1323 return WPS_ERROR_INVALID_PARAM; 566 return WPS_ERROR_INVALID_PARAM;
1324 567
1325 pb->height = height; 568 pb->height = param->data.number;
1326 } 569 }
1327 else 570 else
1328 { 571 {
@@ -1337,30 +580,26 @@ static int parse_progressbar(const char *wps_bufptr,
1337#endif 580#endif
1338 } 581 }
1339 } 582 }
1340 583 param++;
1341 if (LIST_VALUE_PARSED(set, PB_Y)) /* y */ 584 if (!isdefault(param))
1342 pb->y = y; 585 pb->bm.data = param->data.text;
1343 else 586
1344 pb->y = -line_num - 1; /* Will be computed during the rendering */ 587
1345 588 if (token->type == SKIN_TOKEN_VOLUME)
1346 if (*ptr != ')') 589 token->type = SKIN_TOKEN_VOLUMEBAR;
1347 return WPS_ERROR_INVALID_PARAM; 590 else if (token->type == SKIN_TOKEN_BATTERY_PERCENT)
1348 591 token->type = SKIN_TOKEN_BATTERY_PERCENTBAR;
1349 add_to_ll_chain(&wps_data->progressbars, item);
1350 if (token->type == WPS_TOKEN_VOLUME)
1351 token->type = WPS_TOKEN_VOLUMEBAR;
1352 else if (token->type == WPS_TOKEN_BATTERY_PERCENT)
1353 token->type = WPS_TOKEN_BATTERY_PERCENTBAR;
1354 pb->type = token->type; 592 pb->type = token->type;
1355 593
1356 return ptr+1-wps_bufptr; 594 return 0;
595
1357#else 596#else
1358 (void)wps_bufptr; 597 (void)element;
1359 if (token->type != WPS_TOKEN_VOLUME && 598 if (token->type == SKIN_TOKEN_PROGRESSBAR ||
1360 token->type != WPS_TOKEN_BATTERY_PERCENTBAR) 599 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR)
1361 { 600 {
1362 wps_data->full_line_progressbar = 601 wps_data->full_line_progressbar =
1363 token->type == WPS_TOKEN_PLAYER_PROGRESSBAR; 602 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR;
1364 } 603 }
1365 return 0; 604 return 0;
1366 605
@@ -1368,32 +607,32 @@ static int parse_progressbar(const char *wps_bufptr,
1368} 607}
1369 608
1370#ifdef HAVE_ALBUMART 609#ifdef HAVE_ALBUMART
1371static int parse_albumart_load(const char *wps_bufptr, 610static int parse_albumart_load(struct skin_element* element,
1372 struct wps_token *token, 611 struct wps_token *token,
1373 struct wps_data *wps_data) 612 struct wps_data *wps_data)
1374{ 613{
1375 const char *ptr = wps_bufptr;
1376 struct dim dimensions; 614 struct dim dimensions;
1377 int albumart_slot; 615 int albumart_slot;
1378 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction; 616 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction;
1379 struct skin_albumart *aa = skin_buffer_alloc(sizeof(struct skin_albumart)); 617 struct skin_albumart *aa =
618 (struct skin_albumart *)skin_buffer_alloc(sizeof(struct skin_albumart));
1380 (void)token; /* silence warning */ 619 (void)token; /* silence warning */
1381 if (!aa) 620 if (!aa)
1382 return skip_end_of_line(wps_bufptr); 621 return -1;
1383 622
1384 /* reset albumart info in wps */ 623 /* reset albumart info in wps */
1385 aa->width = -1; 624 aa->width = -1;
1386 aa->height = -1; 625 aa->height = -1;
1387 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ 626 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1388 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ 627 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1389 aa->vp = &curr_vp->vp;
1390 628
1391 if (*ptr != '(') 629 aa->x = element->params[0].data.number;
1392 return WPS_ERROR_INVALID_PARAM; 630 aa->y = element->params[1].data.number;
1393 ptr++; 631 aa->width = element->params[2].data.number;
1394 /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */ 632 aa->height = element->params[3].data.number;
1395 if (!(ptr = parse_list("dddd", NULL,',',ptr, &aa->x, &aa->y, &aa->width, &aa->height))) 633
1396 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */ 634 aa->vp = &curr_vp->vp;
635 aa->draw_handle = -1;
1397 636
1398 /* if we got here, we parsed everything ok .. ! */ 637 /* if we got here, we parsed everything ok .. ! */
1399 if (aa->width < 0) 638 if (aa->width < 0)
@@ -1410,7 +649,6 @@ static int parse_albumart_load(const char *wps_bufptr,
1410 aa->x = LCD_WIDTH - (aa->x + aa->width); 649 aa->x = LCD_WIDTH - (aa->x + aa->width);
1411 650
1412 aa->state = WPS_ALBUMART_LOAD; 651 aa->state = WPS_ALBUMART_LOAD;
1413 aa->draw = false;
1414 wps_data->albumart = aa; 652 wps_data->albumart = aa;
1415 653
1416 dimensions.width = aa->width; 654 dimensions.width = aa->width;
@@ -1420,11 +658,10 @@ static int parse_albumart_load(const char *wps_bufptr,
1420 658
1421 if (0 <= albumart_slot) 659 if (0 <= albumart_slot)
1422 wps_data->playback_aa_slot = albumart_slot; 660 wps_data->playback_aa_slot = albumart_slot;
1423 661
1424 if (*ptr == ',') 662 if (element->params_count > 4 && !isdefault(&element->params[4]))
1425 { 663 {
1426 ptr++; 664 switch (*element->params[4].data.text)
1427 switch (*ptr)
1428 { 665 {
1429 case 'l': 666 case 'l':
1430 case 'L': 667 case 'L':
@@ -1445,12 +682,10 @@ static int parse_albumart_load(const char *wps_bufptr,
1445 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT; 682 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1446 break; 683 break;
1447 } 684 }
1448 ptr++;
1449 } 685 }
1450 if (*ptr == ',') 686 if (element->params_count > 5 && !isdefault(&element->params[5]))
1451 { 687 {
1452 ptr++; 688 switch (*element->params[5].data.text)
1453 switch (*ptr)
1454 { 689 {
1455 case 't': 690 case 't':
1456 case 'T': 691 case 'T':
@@ -1465,32 +700,10 @@ static int parse_albumart_load(const char *wps_bufptr,
1465 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM; 700 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM;
1466 break; 701 break;
1467 } 702 }
1468 ptr++;
1469 } 703 }
1470 if (*ptr != ')') 704 return 0;
1471 return WPS_ERROR_INVALID_PARAM;
1472
1473 return skip_end_of_line(wps_bufptr);
1474} 705}
1475 706
1476static int parse_albumart_display(const char *wps_bufptr,
1477 struct wps_token *token,
1478 struct wps_data *wps_data)
1479{
1480 (void)wps_bufptr;
1481 (void)token;
1482 if (wps_data->albumart)
1483 {
1484 wps_data->albumart->vp = &curr_vp->vp;
1485 }
1486#if 0
1487 /* the old code did this so keep it here for now...
1488 * this is to allow the posibility to showing the next tracks AA! */
1489 if (wps_bufptr+1 == 'n')
1490 return 1;
1491#endif
1492 return 0;
1493};
1494#endif /* HAVE_ALBUMART */ 707#endif /* HAVE_ALBUMART */
1495 708
1496#ifdef HAVE_TOUCHSCREEN 709#ifdef HAVE_TOUCHSCREEN
@@ -1520,8 +733,9 @@ static const struct touchaction touchactions[] = {
1520#endif 733#endif
1521}; 734};
1522 735
1523static int parse_touchregion(const char *wps_bufptr, 736static int parse_touchregion(struct skin_element *element,
1524 struct wps_token *token, struct wps_data *wps_data) 737 struct wps_token *token,
738 struct wps_data *wps_data)
1525{ 739{
1526 (void)token; 740 (void)token;
1527 unsigned i, imax; 741 unsigned i, imax;
@@ -1533,7 +747,7 @@ static int parse_touchregion(const char *wps_bufptr,
1533 int x,y,w,h; 747 int x,y,w,h;
1534 char temp[20]; 748 char temp[20];
1535 749
1536 /* format: %T|x|y|width|height|action| 750 /* format: %T(x,y,width,height,action)
1537 * if action starts with & the area must be held to happen 751 * if action starts with & the area must be held to happen
1538 * action is one of: 752 * action is one of:
1539 * play - play/pause playback 753 * play - play/pause playback
@@ -1554,35 +768,22 @@ static int parse_touchregion(const char *wps_bufptr,
1554 * voldown - decrease volume by one step 768 * voldown - decrease volume by one step
1555 */ 769 */
1556 770
1557 771
1558 if (*ptr != '(') 772 region = (struct touchregion*)skin_buffer_alloc(sizeof(struct touchregion));
1559 return WPS_ERROR_INVALID_PARAM;
1560 ptr++;
1561
1562 if (!(ptr = parse_list("dddds", NULL, ',', ptr, &x, &y, &w, &h, &action)))
1563 return WPS_ERROR_INVALID_PARAM;
1564
1565 /* Check there is a terminating ) */
1566 if (*ptr != ')')
1567 return WPS_ERROR_INVALID_PARAM;
1568
1569 region = skin_buffer_alloc(sizeof(struct touchregion));
1570 if (!region) 773 if (!region)
1571 return WPS_ERROR_INVALID_PARAM; 774 return WPS_ERROR_INVALID_PARAM;
1572 775
1573 /* should probably do some bounds checking here with the viewport... but later */ 776 /* should probably do some bounds checking here with the viewport... but later */
1574 region->action = ACTION_NONE; 777 region->action = ACTION_NONE;
1575 region->x = x; 778 region->x = element->params[0].data.number;
1576 region->y = y; 779 region->y = element->params[1].data.number;
1577 region->width = w; 780 region->width = element->params[2].data.number;
1578 region->height = h; 781 region->height = element->params[3].data.number;
1579 region->wvp = curr_vp; 782 region->wvp = curr_vp;
1580 region->armed = false; 783 region->armed = false;
1581 region->reverse_bar = false; 784 region->reverse_bar = false;
785 action = element->params[4].data.text;
1582 786
1583 end = strchr(action, ')');
1584 if (!end || (size_t)(end-action+1) > sizeof temp)
1585 return WPS_ERROR_INVALID_PARAM;
1586 strlcpy(temp, action, end-action+1); 787 strlcpy(temp, action, end-action+1);
1587 action = temp; 788 action = temp;
1588 789
@@ -1625,449 +826,46 @@ static int parse_touchregion(const char *wps_bufptr,
1625 if (!item) 826 if (!item)
1626 return WPS_ERROR_INVALID_PARAM; 827 return WPS_ERROR_INVALID_PARAM;
1627 add_to_ll_chain(&wps_data->touchregions, item); 828 add_to_ll_chain(&wps_data->touchregions, item);
1628 return skip_end_of_line(wps_bufptr); 829 return 0;
1629} 830}
1630#endif 831#endif
1631 832
1632/* Parse a generic token from the given string. Return the length read */ 833static bool check_feature_tag(const int type)
1633static int parse_token(const char *wps_bufptr, struct wps_data *wps_data)
1634{ 834{
1635 int skip = 0, taglen = 0, ret;
1636 struct wps_token *token = wps_data->tokens + wps_data->num_tokens;
1637 const struct wps_tag *tag;
1638 memset(token, 0, sizeof(*token));
1639
1640 switch(*wps_bufptr)
1641 {
1642
1643 case '%':
1644 case '<':
1645 case '|':
1646 case '>':
1647 case ';':
1648 case '#':
1649 case ')':
1650 case '(':
1651 case ',':
1652 /* escaped characters */
1653 token->type = WPS_TOKEN_CHARACTER;
1654 token->value.c = *wps_bufptr;
1655 taglen = 1;
1656 wps_data->num_tokens++;
1657 break;
1658
1659 case '?':
1660 /* conditional tag */
1661 token->type = WPS_TOKEN_CONDITIONAL;
1662 level++;
1663 condindex[level] = wps_data->num_tokens;
1664 numoptions[level] = 1;
1665 wps_data->num_tokens++;
1666 ret = parse_token(wps_bufptr + 1, wps_data);
1667 if (ret < 0) return ret;
1668 taglen = 1 + ret;
1669 break;
1670
1671 default:
1672 /* find what tag we have */
1673 for (tag = all_tags;
1674 strncmp(wps_bufptr, tag->name, strlen(tag->name)) != 0;
1675 tag++) ;
1676
1677 taglen = (tag->type != WPS_TOKEN_UNKNOWN) ? strlen(tag->name) : 2;
1678 token->type = tag->type;
1679 curr_line->curr_subline->line_type |= tag->refresh_type;
1680
1681 /* if the tag has a special parsing function, we call it */
1682 if (tag->parse_func)
1683 {
1684 ret = tag->parse_func(wps_bufptr + taglen, token, wps_data);
1685 if (ret < 0) return ret;
1686 skip += ret;
1687 }
1688
1689 /* Some tags we don't want to save as tokens */
1690 if (tag->type == WPS_NO_TOKEN)
1691 break;
1692
1693 /* tags that start with 'F', 'I' or 'D' are for the next file */
1694 if ( *(tag->name) == 'I' || *(tag->name) == 'F' ||
1695 *(tag->name) == 'D')
1696 token->next = true;
1697
1698 wps_data->num_tokens++;
1699 break;
1700 }
1701
1702 skip += taglen;
1703 return skip;
1704}
1705
1706
1707/*
1708 * Returns the number of bytes to skip the buf pointer to access the false
1709 * branch in a _binary_ conditional
1710 *
1711 * That is:
1712 * - before the '|' if we have a false branch, (%?<true|false> -> %?<|false>)
1713 * - or before the closing '>' if there's no false branch (%?<true> -> %?<>)
1714 *
1715 * depending on the features of a target it's not called from check_feature_tag,
1716 * hence the __attribute__ or it issues compiler warnings
1717 *
1718 **/
1719
1720static int find_false_branch(const char *wps_bufptr) __attribute__((unused));
1721static int find_false_branch(const char *wps_bufptr)
1722{
1723 const char *buf = wps_bufptr;
1724 /* wps_bufptr is after the opening '<', hence level = 1*/
1725 int level = 1;
1726 char ch;
1727 do
1728 {
1729 ch = *buf;
1730 if (ch == '%')
1731 { /* filter out the characters we check later if they're printed
1732 * as literals */
1733 ch = *(++buf);
1734 if (ch == '<' || ch == '>' || ch == '|')
1735 continue;
1736 /* else: some tags/printed literals we skip over */
1737 }
1738 else if (ch == '<') /* nested conditional */
1739 level++;
1740 else if (ch == '>')
1741 { /* closed our or a nested conditional,
1742 * do NOT skip over the '>' so that wps_parse() sees it for closing
1743 * if it is the closing one for our conditional */
1744 level--;
1745 }
1746 else if (ch == '|' && level == 1)
1747 { /* we found our separator, point before and get out */
1748 break;
1749 }
1750 /* if level is 0, we don't have a false branch */
1751 } while (level > 0 && *(++buf));
1752
1753 return buf - wps_bufptr;
1754}
1755
1756/*
1757 * returns the number of bytes to get the appropriate branch of a binary
1758 * conditional
1759 *
1760 * That means:
1761 * - if a feature is available, it returns 0 to not skip anything
1762 * - if the feature is not available, skip to the false branch and don't
1763 * parse the true branch at all
1764 *
1765 * */
1766static int check_feature_tag(const char *wps_bufptr, const int type)
1767{
1768 (void)wps_bufptr;
1769 switch (type) 835 switch (type)
1770 { 836 {
1771 case WPS_TOKEN_RTC_PRESENT: 837 case SKIN_TOKEN_RTC_PRESENT:
1772#if CONFIG_RTC 838#if CONFIG_RTC
1773 return 0; 839 return true;
1774#else 840#else
1775 return find_false_branch(wps_bufptr); 841 return false;
1776#endif /* CONFIG_RTC */ 842#endif
1777 843 case SKIN_TOKEN_HAVE_RECORDING:
1778 case WPS_TOKEN_HAVE_RECORDING:
1779#ifdef HAVE_RECORDING 844#ifdef HAVE_RECORDING
1780 return 0; 845 return true;
1781#else 846#else
1782 return find_false_branch(wps_bufptr); 847 return false;
1783#endif /* HAVE_RECORDING */ 848#endif
1784 849 case SKIN_TOKEN_HAVE_TUNER:
1785 case WPS_TOKEN_HAVE_TUNER:
1786#if CONFIG_TUNER 850#if CONFIG_TUNER
1787 if (radio_hardware_present()) 851 if (radio_hardware_present())
1788 return 0; 852 return true;
1789#endif /* CONFIG_TUNER */ 853#endif
1790 return find_false_branch(wps_bufptr); 854 return false;
1791 855
1792#if CONFIG_TUNER 856#if CONFIG_TUNER
1793 case WPS_TOKEN_HAVE_RDS: 857 case SKIN_TOKEN_HAVE_RDS:
1794#ifdef HAVE_RDS_CAP 858#ifdef HAVE_RDS_CAP
1795 return 0; 859 return true;
1796#else 860#else
1797 return find_false_branch(wps_bufptr); 861 return false;
1798#endif /* HAVE_RDS_CAP */ 862#endif /* HAVE_RDS_CAP */
1799#endif /* CONFIG_TUNER */ 863#endif /* CONFIG_TUNER */
1800 default: /* not a tag we care about, just don't skip */ 864 default: /* not a tag we care about, just don't skip */
1801 return 0; 865 return true;
1802 }
1803}
1804
1805
1806/* Parses the WPS.
1807 data is the pointer to the structure where the parsed WPS should be stored.
1808 It is initialised.
1809 wps_bufptr points to the string containing the WPS tags */
1810#define TOKEN_BLOCK_SIZE 128
1811static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
1812{
1813 if (!data || !wps_bufptr || !*wps_bufptr)
1814 return false;
1815 enum wps_parse_error fail = PARSE_OK;
1816 int ret;
1817 int max_tokens = TOKEN_BLOCK_SIZE;
1818 size_t buf_free = 0;
1819 line_number = 0;
1820 level = -1;
1821
1822 /* allocate enough RAM for a reasonable skin, grow as needed.
1823 * Free any used RAM before loading the images to be 100% RAM efficient */
1824 data->tokens = (struct wps_token *)skin_buffer_grab(&buf_free);
1825 if (sizeof(struct wps_token)*max_tokens >= buf_free)
1826 return false;
1827 skin_buffer_increment(max_tokens * sizeof(struct wps_token), false);
1828 data->num_tokens = 0;
1829
1830#if LCD_DEPTH > 1
1831 /* Backdrop defaults to the setting unless %X is used, so set it now */
1832 if (global_settings.backdrop_file[0])
1833 {
1834 data->backdrop = "-";
1835 }
1836#endif
1837
1838 while (*wps_bufptr && !fail)
1839 {
1840 if (follow_lang_direction)
1841 follow_lang_direction--;
1842 /* first make sure there is enough room for tokens */
1843 if (max_tokens <= data->num_tokens + 5)
1844 {
1845 int extra_tokens = TOKEN_BLOCK_SIZE;
1846 size_t needed = extra_tokens * sizeof(struct wps_token);
1847 /* do some smarts here to grow the array a bit */
1848 if (skin_buffer_freespace() < needed)
1849 {
1850 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1851 break;
1852 }
1853 skin_buffer_increment(needed, false);
1854 max_tokens += extra_tokens;
1855 }
1856
1857 switch(*wps_bufptr++)
1858 {
1859
1860 /* Regular tag */
1861 case '%':
1862 if ((ret = parse_token(wps_bufptr, data)) < 0)
1863 {
1864 fail = PARSE_FAIL_COND_INVALID_PARAM;
1865 break;
1866 }
1867 else if (level >= WPS_MAX_COND_LEVEL - 1)
1868 {
1869 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1870 break;
1871 }
1872 wps_bufptr += ret;
1873 break;
1874
1875 /* Alternating sublines separator */
1876 case ';':
1877 if (level >= 0) /* there are unclosed conditionals */
1878 {
1879 fail = PARSE_FAIL_UNCLOSED_COND;
1880 break;
1881 }
1882
1883 if (!skin_start_new_subline(curr_line, data->num_tokens))
1884 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1885
1886 break;
1887
1888 /* Conditional list start */
1889 case '<':
1890 if (data->tokens[data->num_tokens-2].type != WPS_TOKEN_CONDITIONAL)
1891 {
1892 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1893 break;
1894 }
1895 wps_bufptr += check_feature_tag(wps_bufptr,
1896 data->tokens[data->num_tokens-1].type);
1897 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_START;
1898 lastcond[level] = data->num_tokens++;
1899 break;
1900
1901 /* Conditional list end */
1902 case '>':
1903 if (level < 0) /* not in a conditional, invalid char */
1904 {
1905 fail = PARSE_FAIL_INVALID_CHAR;
1906 break;
1907 }
1908
1909 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_END;
1910 if (lastcond[level])
1911 data->tokens[lastcond[level]].value.i = data->num_tokens;
1912 else
1913 {
1914 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1915 break;
1916 }
1917
1918 lastcond[level] = 0;
1919 data->num_tokens++;
1920 data->tokens[condindex[level]].value.i = numoptions[level];
1921 level--;
1922 break;
1923
1924 /* Conditional list option */
1925 case '|':
1926 if (level < 0) /* not in a conditional, invalid char */
1927 {
1928 fail = PARSE_FAIL_INVALID_CHAR;
1929 break;
1930 }
1931
1932 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_OPTION;
1933 if (lastcond[level])
1934 data->tokens[lastcond[level]].value.i = data->num_tokens;
1935 else
1936 {
1937 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1938 break;
1939 }
1940
1941 lastcond[level] = data->num_tokens;
1942 numoptions[level]++;
1943 data->num_tokens++;
1944 break;
1945
1946 /* Comment */
1947 case '#':
1948 if (level >= 0) /* there are unclosed conditionals */
1949 {
1950 fail = PARSE_FAIL_UNCLOSED_COND;
1951 break;
1952 }
1953
1954 wps_bufptr += skip_end_of_line(wps_bufptr);
1955 break;
1956
1957 /* End of this line */
1958 case '\n':
1959 if (level >= 0) /* there are unclosed conditionals */
1960 {
1961 fail = PARSE_FAIL_UNCLOSED_COND;
1962 break;
1963 }
1964 /* add a new token for the \n so empty lines are correct */
1965 data->tokens[data->num_tokens].type = WPS_TOKEN_CHARACTER;
1966 data->tokens[data->num_tokens].value.c = '\n';
1967 data->tokens[data->num_tokens].next = false;
1968 data->num_tokens++;
1969
1970 if (!skin_start_new_line(curr_vp, data->num_tokens))
1971 {
1972 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1973 break;
1974 }
1975 line_number++;
1976
1977 break;
1978
1979 /* String */
1980 default:
1981 {
1982 unsigned int len = 1;
1983 const char *string_start = wps_bufptr - 1;
1984
1985 /* find the length of the string */
1986 while (*wps_bufptr && *wps_bufptr != '#' &&
1987 *wps_bufptr != '%' && *wps_bufptr != ';' &&
1988 *wps_bufptr != '<' && *wps_bufptr != '>' &&
1989 *wps_bufptr != '|' && *wps_bufptr != '\n')
1990 {
1991 wps_bufptr++;
1992 len++;
1993 }
1994
1995 /* look if we already have that string */
1996 char *str;
1997 bool found = false;
1998 struct skin_token_list *list = data->strings;
1999 while (list)
2000 {
2001 str = (char*)list->token->value.data;
2002 found = (strlen(str) == len &&
2003 strncmp(string_start, str, len) == 0);
2004 if (found)
2005 break; /* break here because the list item is
2006 used if its found */
2007 list = list->next;
2008 }
2009 /* If a matching string is found, found is true and i is
2010 the index of the string. If not, found is false */
2011
2012 if (!found)
2013 {
2014 /* new string */
2015 str = (char*)skin_buffer_alloc(len+1);
2016 if (!str)
2017 {
2018 fail = PARSE_FAIL_LIMITS_EXCEEDED;
2019 break;
2020 }
2021 strlcpy(str, string_start, len+1);
2022 struct skin_token_list *item =
2023 new_skin_token_list_item(&data->tokens[data->num_tokens], str);
2024 if(!item)
2025 {
2026 fail = PARSE_FAIL_LIMITS_EXCEEDED;
2027 break;
2028 }
2029 add_to_ll_chain(&data->strings, item);
2030 }
2031 else
2032 {
2033 /* another occurrence of an existing string */
2034 data->tokens[data->num_tokens].value.data = list->token->value.data;
2035 }
2036 data->tokens[data->num_tokens].type = WPS_TOKEN_STRING;
2037 data->num_tokens++;
2038 }
2039 break;
2040 }
2041 }
2042
2043 if (!fail && level >= 0) /* there are unclosed conditionals */
2044 fail = PARSE_FAIL_UNCLOSED_COND;
2045
2046 if (*wps_bufptr && !fail)
2047 /* one of the limits of the while loop was exceeded */
2048 fail = PARSE_FAIL_LIMITS_EXCEEDED;
2049
2050 /* Success! */
2051 curr_line->curr_subline->last_token_idx = data->num_tokens;
2052 data->tokens[data->num_tokens++].type = WPS_NO_TOKEN;
2053 /* freeup unused tokens */
2054 skin_buffer_free_from_front(sizeof(struct wps_token)
2055 * (max_tokens - data->num_tokens));
2056
2057#ifdef DEBUG_SKIN_ENGINE
2058 if (debug)
2059 {
2060 print_debug_info(data, fail, line_number);
2061 debug_skin_usage();
2062 } 866 }
2063#else
2064 (void)debug;
2065#endif
2066
2067 return (fail == 0);
2068} 867}
2069 868
2070
2071/* 869/*
2072 * initial setup of wps_data; does reset everything 870 * initial setup of wps_data; does reset everything
2073 * except fields which need to survive, i.e. 871 * 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)
2075 **/ 873 **/
2076static void skin_data_reset(struct wps_data *wps_data) 874static void skin_data_reset(struct wps_data *wps_data)
2077{ 875{
876 wps_data->tree = NULL;
2078#ifdef HAVE_LCD_BITMAP 877#ifdef HAVE_LCD_BITMAP
2079 wps_data->images = NULL; 878 wps_data->images = NULL;
2080 wps_data->progressbars = NULL; 879 wps_data->progressbars = NULL;
@@ -2085,8 +884,6 @@ static void skin_data_reset(struct wps_data *wps_data)
2085#ifdef HAVE_TOUCHSCREEN 884#ifdef HAVE_TOUCHSCREEN
2086 wps_data->touchregions = NULL; 885 wps_data->touchregions = NULL;
2087#endif 886#endif
2088 wps_data->viewports = NULL;
2089 wps_data->strings = NULL;
2090#ifdef HAVE_ALBUMART 887#ifdef HAVE_ALBUMART
2091 wps_data->albumart = NULL; 888 wps_data->albumart = NULL;
2092 if (wps_data->playback_aa_slot >= 0) 889 if (wps_data->playback_aa_slot >= 0)
@@ -2095,8 +892,6 @@ static void skin_data_reset(struct wps_data *wps_data)
2095 wps_data->playback_aa_slot = -1; 892 wps_data->playback_aa_slot = -1;
2096 } 893 }
2097#endif 894#endif
2098 wps_data->tokens = NULL;
2099 wps_data->num_tokens = 0;
2100 895
2101#ifdef HAVE_LCD_BITMAP 896#ifdef HAVE_LCD_BITMAP
2102 wps_data->peak_meter_enabled = false; 897 wps_data->peak_meter_enabled = false;
@@ -2119,6 +914,7 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char
2119{ 914{
2120 (void)wps_data; /* only needed for remote targets */ 915 (void)wps_data; /* only needed for remote targets */
2121 char img_path[MAX_PATH]; 916 char img_path[MAX_PATH];
917 int fd;
2122 get_image_filename(bitmap->data, bmpdir, 918 get_image_filename(bitmap->data, bmpdir,
2123 img_path, sizeof(img_path)); 919 img_path, sizeof(img_path));
2124 920
@@ -2131,14 +927,24 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char
2131#endif 927#endif
2132 format = FORMAT_ANY|FORMAT_TRANSPARENT; 928 format = FORMAT_ANY|FORMAT_TRANSPARENT;
2133 929
2134 size_t max_buf; 930 fd = open(img_path, O_RDONLY);
2135 char* imgbuf = (char*)skin_buffer_grab(&max_buf); 931 if (fd < 0)
932 return false;
933 size_t buf_size = read_bmp_file(img_path, bitmap, 0,
934 format|FORMAT_RETURN_SIZE, NULL);
935 char* imgbuf = (char*)skin_buffer_alloc(buf_size);
936 if (!imgbuf)
937 {
938 close(fd);
939 return NULL;
940 }
941 lseek(fd, 0, SEEK_SET);
2136 bitmap->data = imgbuf; 942 bitmap->data = imgbuf;
2137 int ret = read_bmp_file(img_path, bitmap, max_buf, format, NULL); 943 int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
2138 944
945 close(fd);
2139 if (ret > 0) 946 if (ret > 0)
2140 { 947 {
2141 skin_buffer_increment(ret, true);
2142 return true; 948 return true;
2143 } 949 }
2144 else 950 else
@@ -2204,14 +1010,14 @@ static bool skin_load_fonts(struct wps_data *data)
2204{ 1010{
2205 /* don't spit out after the first failue to aid debugging */ 1011 /* don't spit out after the first failue to aid debugging */
2206 bool success = true; 1012 bool success = true;
2207 struct skin_token_list *vp_list; 1013 struct skin_element *vp_list;
2208 int font_id; 1014 int font_id;
2209 /* walk though each viewport and assign its font */ 1015 /* walk though each viewport and assign its font */
2210 for(vp_list = data->viewports; vp_list; vp_list = vp_list->next) 1016 for(vp_list = data->tree; vp_list; vp_list = vp_list->next)
2211 { 1017 {
2212 /* first, find the viewports that have a non-sys/ui-font font */ 1018 /* first, find the viewports that have a non-sys/ui-font font */
2213 struct skin_viewport *skin_vp = 1019 struct skin_viewport *skin_vp =
2214 (struct skin_viewport*)vp_list->token->value.data; 1020 (struct skin_viewport*)vp_list->data;
2215 struct viewport *vp = &skin_vp->vp; 1021 struct viewport *vp = &skin_vp->vp;
2216 1022
2217 1023
@@ -2250,6 +1056,7 @@ static bool skin_load_fonts(struct wps_data *data)
2250 { 1056 {
2251 DEBUGF("Unable to load font %d: '%s.fnt'\n", 1057 DEBUGF("Unable to load font %d: '%s.fnt'\n",
2252 font_id, font->name); 1058 font_id, font->name);
1059 font->name = NULL; /* to stop trying to load it again if we fail */
2253 success = false; 1060 success = false;
2254 font->name = NULL; 1061 font->name = NULL;
2255 continue; 1062 continue;
@@ -2262,6 +1069,277 @@ static bool skin_load_fonts(struct wps_data *data)
2262} 1069}
2263 1070
2264#endif /* HAVE_LCD_BITMAP */ 1071#endif /* HAVE_LCD_BITMAP */
1072static int convert_viewport(struct wps_data *data, struct skin_element* element)
1073{
1074 struct skin_viewport *skin_vp =
1075 (struct skin_viewport *)skin_buffer_alloc(sizeof(struct skin_viewport));
1076 struct screen *display = &screens[curr_screen];
1077
1078 if (!skin_vp)
1079 return CALLBACK_ERROR;
1080
1081 skin_vp->hidden_flags = 0;
1082 skin_vp->label = VP_NO_LABEL;
1083 element->data = skin_vp;
1084 curr_vp = skin_vp;
1085 curr_viewport_element = element;
1086
1087 viewport_set_defaults(&skin_vp->vp, curr_screen);
1088
1089#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1090 skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
1091 skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
1092#endif
1093
1094
1095 struct skin_tag_parameter *param = element->params;
1096 if (element->params_count == 0) /* default viewport */
1097 {
1098 if (!data->tree) /* first viewport in the skin */
1099 data->tree = element;
1100 skin_vp->label = VP_DEFAULT_LABEL;
1101 return CALLBACK_OK;
1102 }
1103
1104 if (element->params_count == 6)
1105 {
1106 if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
1107 {
1108 if (isdefault(param))
1109 {
1110 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1111 skin_vp->label = VP_INFO_LABEL|VP_DEFAULT_LABEL;
1112 }
1113 else
1114 {
1115 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1116 skin_vp->label = VP_INFO_LABEL|param->data.text[0];
1117 }
1118 }
1119 else
1120 {
1121 skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN;
1122 skin_vp->label = param->data.text[0];
1123 }
1124 param++;
1125 }
1126 /* x */
1127 if (!isdefault(param))
1128 {
1129 skin_vp->vp.x = param->data.number;
1130 if (param->data.number < 0)
1131 skin_vp->vp.x += display->lcdwidth;
1132 }
1133 param++;
1134 /* y */
1135 if (!isdefault(param))
1136 {
1137 skin_vp->vp.y = param->data.number;
1138 if (param->data.number < 0)
1139 skin_vp->vp.y += display->lcdheight;
1140 }
1141 param++;
1142 /* width */
1143 if (!isdefault(param))
1144 {
1145 skin_vp->vp.width = param->data.number;
1146 if (param->data.number < 0)
1147 skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
1148 }
1149 else
1150 {
1151 skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x;
1152 }
1153 param++;
1154 /* height */
1155 if (!isdefault(param))
1156 {
1157 skin_vp->vp.height = param->data.number;
1158 if (param->data.number < 0)
1159 skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
1160 }
1161 else
1162 {
1163 skin_vp->vp.height = display->lcdheight - skin_vp->vp.y;
1164 }
1165 param++;
1166#ifdef HAVE_LCD_BITMAP
1167 /* font */
1168 if (!isdefault(param))
1169 {
1170 skin_vp->vp.font = param->data.number;
1171 }
1172#endif
1173
1174 return CALLBACK_OK;
1175
1176}
1177
1178int skin_element_callback(struct skin_element* element, void* data)
1179{
1180 struct wps_data *wps_data = (struct wps_data *)data;
1181 struct wps_token *token;
1182 parse_function function = NULL;
1183
1184 switch (element->type)
1185 {
1186 /* IMPORTANT: element params are shared, so copy them if needed
1187 * or use then NOW, dont presume they have a long lifespan
1188 */
1189 case TAG:
1190 {
1191 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
1192 memset(token, 0, sizeof(*token));
1193 token->type = element->tag->type;
1194
1195 if ((element->tag->flags&SKIN_REFRESH_ALL) == SKIN_RTC_REFRESH)
1196 {
1197#ifdef CONFIG_RTC
1198 curr_line->update_mode |= SKIN_REFRESH_DYNAMIC;
1199#else
1200 curr_line->update_mode |= SKIN_REFRESH_STATIC;
1201#endif
1202 }
1203 else
1204 curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL;
1205
1206 element->data = token;
1207
1208 /* Some tags need special handling for the tag, so add them here */
1209 switch (token->type)
1210 {
1211 case SKIN_TOKEN_ALIGN_LANGDIRECTION:
1212 follow_lang_direction = 2;
1213 break;
1214 case SKIN_TOKEN_PROGRESSBAR:
1215 case SKIN_TOKEN_VOLUME:
1216 case SKIN_TOKEN_BATTERY_PERCENT:
1217 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1218 function = parse_progressbar_tag;
1219 break;
1220 case SKIN_TOKEN_SUBLINE_TIMEOUT:
1221 case SKIN_TOKEN_BUTTON_VOLUME:
1222 case SKIN_TOKEN_TRACK_STARTING:
1223 case SKIN_TOKEN_TRACK_ENDING:
1224 case SKIN_TOKEN_LASTTOUCH:
1225 function = parse_timeout_tag;
1226 break;
1227#ifdef HAVE_LCD_BITMAP
1228 case SKIN_TOKEN_DISABLE_THEME:
1229 case SKIN_TOKEN_ENABLE_THEME:
1230 case SKIN_TOKEN_DRAW_INBUILTBAR:
1231 function = parse_statusbar_tags;
1232 break;
1233#endif
1234 case SKIN_TOKEN_FILE_DIRECTORY:
1235 token->value.i = element->params[0].data.number;
1236 break;
1237#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1238 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
1239 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
1240 function = parse_viewportcolour;
1241 break;
1242 case SKIN_TOKEN_IMAGE_BACKDROP:
1243 function = parse_image_special;
1244 break;
1245#endif
1246 case SKIN_TOKEN_TRANSLATEDSTRING:
1247 case SKIN_TOKEN_SETTING:
1248 function = parse_setting_and_lang;
1249 break;
1250#ifdef HAVE_LCD_BITMAP
1251 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
1252 function = parse_playlistview;
1253 break;
1254 case SKIN_TOKEN_LOAD_FONT:
1255 function = parse_font_load;
1256 break;
1257 case SKIN_TOKEN_VIEWPORT_ENABLE:
1258 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
1259 token->value.i = element->params[0].data.text[0];
1260 break;
1261 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
1262 function = parse_image_display;
1263 break;
1264 case SKIN_TOKEN_IMAGE_PRELOAD:
1265 case SKIN_TOKEN_IMAGE_DISPLAY:
1266 function = parse_image_load;
1267 break;
1268#endif
1269#ifdef HAVE_TOUCHSCREEN
1270 case SKIN_TOKEN_TOUCHREGION:
1271 function = parse_touchregion;
1272 break;
1273#endif
1274#ifdef HAVE_ALBUMART
1275 case SKIN_TOKEN_ALBUMART_DISPLAY:
1276 if (wps_data->albumart)
1277 wps_data->albumart->vp = &curr_vp->vp;
1278 break;
1279 case SKIN_TOKEN_ALBUMART_LOAD:
1280 function = parse_albumart_load;
1281 break;
1282#endif
1283 default:
1284 break;
1285 }
1286 if (function)
1287 {
1288 if (function(element, token, wps_data) < 0)
1289 return CALLBACK_ERROR;
1290 }
1291 /* tags that start with 'F', 'I' or 'D' are for the next file */
1292 if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' ||
1293 *(element->tag->name) == 'D')
1294 token->next = true;
1295 if (follow_lang_direction > 0 )
1296 follow_lang_direction--;
1297 break;
1298 }
1299 case VIEWPORT:
1300 return convert_viewport(wps_data, element);
1301 case LINE:
1302 {
1303 struct line *line =
1304 (struct line *)skin_buffer_alloc(sizeof(struct line));
1305 line->update_mode = SKIN_REFRESH_STATIC;
1306 line->timeout = DEFAULT_SUBLINE_TIME_MULTIPLIER * TIMEOUT_UNIT;
1307 curr_line = line;
1308 element->data = line;
1309 }
1310 break;
1311 case LINE_ALTERNATOR:
1312 {
1313 struct line_alternator *alternator =
1314 (struct line_alternator *)skin_buffer_alloc(sizeof(struct line_alternator));
1315 alternator->current_line = 0;
1316#ifndef __PCTOOL__
1317 alternator->last_change_tick = current_tick;
1318#endif
1319 element->data = alternator;
1320 }
1321 break;
1322 case CONDITIONAL:
1323 {
1324 struct conditional *conditional =
1325 (struct conditional *)skin_buffer_alloc(sizeof(struct conditional));
1326 conditional->last_value = -1;
1327 conditional->token = element->data;
1328 element->data = conditional;
1329 if (!check_feature_tag(element->tag->type))
1330 {
1331 return FEATURE_NOT_AVAILABLE;
1332 }
1333 return CALLBACK_OK;
1334 }
1335 case TEXT:
1336 curr_line->update_mode |= SKIN_REFRESH_STATIC;
1337 break;
1338 default:
1339 break;
1340 }
1341 return CALLBACK_OK;
1342}
2265 1343
2266/* to setup up the wps-data from a format-buffer (isfile = false) 1344/* to setup up the wps-data from a format-buffer (isfile = false)
2267 from a (wps-)file (isfile = true)*/ 1345 from a (wps-)file (isfile = true)*/
@@ -2298,37 +1376,13 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2298 } 1376 }
2299#endif 1377#endif
2300 1378
1379
2301 skin_data_reset(wps_data); 1380 skin_data_reset(wps_data);
2302 wps_data->wps_loaded = false; 1381 wps_data->wps_loaded = false;
2303 curr_screen = screen; 1382 curr_screen = screen;
2304
2305 /* alloc default viewport, will be fixed up later */
2306 curr_vp = skin_buffer_alloc(sizeof(struct skin_viewport));
2307 if (!curr_vp)
2308 return false;
2309 struct skin_token_list *list = new_skin_token_list_item(NULL, curr_vp);
2310 if (!list)
2311 return false;
2312 add_to_ll_chain(&wps_data->viewports, list);
2313
2314
2315 /* Initialise the first (default) viewport */
2316 curr_vp->label = VP_DEFAULT_LABEL;
2317 curr_vp->hidden_flags = 0;
2318 curr_vp->lines = NULL;
2319
2320 viewport_set_defaults(&curr_vp->vp, screen);
2321#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2322 curr_vp->start_fgcolour = curr_vp->vp.fg_pattern;
2323 curr_vp->start_bgcolour = curr_vp->vp.bg_pattern;
2324#endif
2325#ifdef HAVE_LCD_BITMAP
2326 curr_vp->vp.font = FONT_UI;
2327#endif
2328
2329 curr_line = NULL; 1383 curr_line = NULL;
2330 if (!skin_start_new_line(curr_vp, 0)) 1384 curr_vp = NULL;
2331 return false; 1385 curr_viewport_element = NULL;
2332 1386
2333 if (isfile) 1387 if (isfile)
2334 { 1388 {
@@ -2364,9 +1418,15 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2364 { 1418 {
2365 wps_buffer = (char*)buf; 1419 wps_buffer = (char*)buf;
2366 } 1420 }
2367 /* parse the WPS source */ 1421#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
2368 if (!wps_parse(wps_data, wps_buffer, isfile)) { 1422 wps_data->backdrop = "-";
1423#endif
1424 /* parse the skin source */
1425 skin_buffer_save_position();
1426 wps_data->tree = skin_parse(wps_buffer, skin_element_callback, wps_data);
1427 if (!wps_data->tree) {
2369 skin_data_reset(wps_data); 1428 skin_data_reset(wps_data);
1429 skin_buffer_restore_position();
2370 return false; 1430 return false;
2371 } 1431 }
2372 1432
@@ -2387,6 +1447,7 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2387 !skin_load_fonts(wps_data)) 1447 !skin_load_fonts(wps_data))
2388 { 1448 {
2389 skin_data_reset(wps_data); 1449 skin_data_reset(wps_data);
1450 skin_buffer_restore_position();
2390 return false; 1451 return false;
2391 } 1452 }
2392#endif 1453#endif
@@ -2410,8 +1471,8 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2410#endif 1471#endif
2411 wps_data->wps_loaded = true; 1472 wps_data->wps_loaded = true;
2412#ifdef DEBUG_SKIN_ENGINE 1473#ifdef DEBUG_SKIN_ENGINE
2413 if (isfile && debug_wps) 1474 // if (isfile && debug_wps)
2414 debug_skin_usage(); 1475 // debug_skin_usage();
2415#endif 1476#endif
2416 return true; 1477 return true;
2417} 1478}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: skin_parser.c 26752 2010-06-10 21:22:16Z bieber $
9 *
10 * Copyright (C) 2010 Jonathan Gordon
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <stdbool.h>
26#include <ctype.h>
27#include "strlcat.h"
28
29#include "config.h"
30#include "kernel.h"
31#ifdef HAVE_ALBUMART
32#include "albumart.h"
33#endif
34#include "skin_display.h"
35#include "skin_engine.h"
36#include "skin_parser.h"
37#include "tag_table.h"
38#include "skin_scan.h"
39#if CONFIG_TUNER
40#include "radio.h"
41#endif
42#include "language.h"
43#include "playback.h"
44
45
46#define MAX_LINE 1024
47
48struct skin_draw_info {
49 struct gui_wps *gwps;
50 struct skin_viewport *skin_vp;
51 int line_number;
52 unsigned long refresh_type;
53
54 char* cur_align_start;
55 struct align_pos align;
56 bool no_line_break;
57 bool line_scrolls;
58 bool force_redraw;
59
60 char *buf;
61 size_t buf_size;
62};
63
64typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info);
65bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info);
66
67
68static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
69 struct skin_element *element, struct viewport* vp)
70{
71#ifndef HAVE_LCD_BITMAP
72 (void)vp; /* silence warnings */
73#endif
74 struct wps_token *token = (struct wps_token *)element->data;
75 struct wps_data *data = gwps->data;
76 bool do_refresh = (element->tag->flags & info->refresh_type) > 0;
77 switch (token->type)
78 {
79#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
80 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
81 {
82 struct viewport_colour *col = token->value.data;
83 col->vp->fg_pattern = col->colour;
84 }
85 break;
86 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
87 {
88 struct viewport_colour *col = token->value.data;
89 col->vp->bg_pattern = col->colour;
90 }
91 break;
92#endif
93 case SKIN_TOKEN_VIEWPORT_ENABLE:
94 {
95 char label = token->value.i;
96 char temp = VP_DRAW_HIDEABLE;
97 struct skin_element *viewport = gwps->data->tree;
98 while (viewport)
99 {
100 struct skin_viewport *skinvp = (struct skin_viewport*)viewport->data;
101 if (skinvp->label == label)
102 {
103 if (skinvp->hidden_flags&VP_DRAW_HIDDEN)
104 {
105 temp |= VP_DRAW_WASHIDDEN;
106 }
107 skinvp->hidden_flags = temp;
108 }
109 viewport = viewport->next;
110 }
111 }
112 break;
113#ifdef HAVE_LCD_BITMAP
114 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
115 sb_set_info_vp(gwps->display->screen_type,
116 token->value.i|VP_INFO_LABEL);
117 break;
118 case SKIN_TOKEN_PEAKMETER:
119 data->peak_meter_enabled = true;
120 if (do_refresh)
121 draw_peakmeters(gwps, info->line_number, vp);
122 break;
123#endif
124 case SKIN_TOKEN_VOLUMEBAR:
125 case SKIN_TOKEN_BATTERY_PERCENTBAR:
126 case SKIN_TOKEN_PROGRESSBAR:
127 {
128#ifdef HAVE_LCD_BITMAP
129 struct progressbar *bar = (struct progressbar*)token->value.data;
130 if (do_refresh)
131 draw_progressbar(gwps, info->line_number, bar);
132#else /* HAVE_LCD_CHARCELL */
133 if (do_refresh)
134 {
135 if (data->full_line_progressbar)
136 draw_player_fullbar(gwps, info->buf, info->buf_size);
137 else
138 draw_player_progress(gwps);
139 }
140#endif
141 }
142 break;
143#ifdef HAVE_LCD_BITMAP
144 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
145 {
146 char n = token->value.i & 0xFF;
147 int subimage = token->value.i >> 8;
148 struct gui_img *img = find_image(n, data);
149 if (img && img->loaded)
150 img->display = subimage;
151 break;
152 }
153#ifdef HAVE_ALBUMART
154 case SKIN_TOKEN_ALBUMART_DISPLAY:
155 /* now draw the AA */
156 if (data->albumart)
157 {
158 int handle = playback_current_aa_hid(data->playback_aa_slot);
159#if CONFIG_TUNER
160 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
161 {
162 struct dim dim = {data->albumart->width, data->albumart->height};
163 handle = radio_get_art_hid(&dim);
164 }
165#endif
166 data->albumart->draw_handle = handle;
167 }
168 break;
169#endif
170 case SKIN_TOKEN_DRAW_INBUILTBAR:
171 gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]),
172 info->refresh_type == SKIN_REFRESH_ALL,
173 token->value.data);
174 break;
175 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
176 if (do_refresh)
177 draw_playlist_viewer_list(gwps, token->value.data);
178 break;
179
180#endif /* HAVE_LCD_BITMAP */
181 default:
182 return false;
183 }
184 return true;
185}
186
187
188
189static void do_tags_in_hidden_conditional(struct skin_element* branch,
190 struct skin_draw_info *info)
191{
192#ifdef HAVE_LCD_BITMAP
193 struct gui_wps *gwps = info->gwps;
194 struct wps_data *data = gwps->data;
195#endif
196 /* Tags here are ones which need to be "turned off" or cleared
197 * if they are in a conditional branch which isnt being used */
198 if (branch->type == LINE_ALTERNATOR)
199 {
200 int i;
201 for (i=0; i<branch->children_count; i++)
202 {
203 do_tags_in_hidden_conditional(branch->children[i], info);
204 }
205 }
206 else if (branch->type == LINE && branch->children_count)
207 {
208 struct skin_element *child = branch->children[0];
209 struct wps_token *token;
210 while (child)
211 {
212 if (child->type == CONDITIONAL)
213 {
214 int i;
215 for (i=0; i<child->children_count; i++)
216 {
217 do_tags_in_hidden_conditional(child->children[i], info);
218 }
219 child = child->next;
220 continue;
221 }
222 else if (child->type != TAG || !child->data)
223 {
224 child = child->next;
225 continue;
226 }
227 token = (struct wps_token *)child->data;
228#ifdef HAVE_LCD_BITMAP
229 /* clear all pictures in the conditional and nested ones */
230 if (token->type == SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY)
231 {
232 struct gui_img *img = find_image(token->value.i&0xFF, data);
233 clear_image_pos(gwps, img);
234 }
235 else if (token->type == SKIN_TOKEN_PEAKMETER)
236 {
237 data->peak_meter_enabled = false;
238 }
239 else if (token->type == SKIN_TOKEN_VIEWPORT_ENABLE)
240 {
241 char label = token->value.i&0x7f;
242 struct skin_element *viewport;
243 for (viewport = data->tree;
244 viewport;
245 viewport = viewport->next)
246 {
247 struct skin_viewport *skin_viewport = (struct skin_viewport*)viewport->data;
248 if ((skin_viewport->label&0x7f) != label)
249 continue;
250 if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
251 {
252 continue;
253 }
254 if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE)
255 {
256 if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN)
257 skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
258 else
259 {
260 gwps->display->set_viewport(&skin_viewport->vp);
261 gwps->display->clear_viewport();
262 gwps->display->scroll_stop(&skin_viewport->vp);
263 gwps->display->set_viewport(&info->skin_vp->vp);
264 skin_viewport->hidden_flags |= VP_DRAW_HIDDEN;
265 }
266 }
267 }
268 }
269#endif
270#ifdef HAVE_ALBUMART
271 else if (data->albumart && token->type == SKIN_TOKEN_ALBUMART_DISPLAY)
272 {
273 draw_album_art(gwps,
274 playback_current_aa_hid(data->playback_aa_slot), true);
275 }
276#endif
277 child = child->next;
278 }
279 }
280}
281
282static void fix_line_alignment(struct skin_draw_info *info, struct skin_element *element)
283{
284 struct align_pos *align = &info->align;
285 char *cur_pos = info->cur_align_start + strlen(info->cur_align_start);
286 switch (element->tag->type)
287 {
288 case SKIN_TOKEN_ALIGN_LEFT:
289 *cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
290 align->left = cur_pos;
291 info->cur_align_start = cur_pos;
292 break;
293 case SKIN_TOKEN_ALIGN_LEFT_RTL:
294 *cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
295 if (lang_is_rtl())
296 align->right = cur_pos;
297 else
298 align->left = cur_pos;
299 info->cur_align_start = cur_pos;
300 break;
301 case SKIN_TOKEN_ALIGN_CENTER:
302 *cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
303 align->center = cur_pos;
304 info->cur_align_start = cur_pos;
305 break;
306 case SKIN_TOKEN_ALIGN_RIGHT:
307 *cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
308 align->right = cur_pos;
309 info->cur_align_start = cur_pos;
310 break;
311 case SKIN_TOKEN_ALIGN_RIGHT_RTL:
312 *cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
313 if (lang_is_rtl())
314 align->left = cur_pos;
315 else
316 align->right = cur_pos;
317 info->cur_align_start = cur_pos;
318 break;
319 default:
320 break;
321 }
322}
323
324/* Draw a LINE element onto the display */
325bool skin_render_line(struct skin_element* line, struct skin_draw_info *info)
326{
327 bool needs_update = false;
328 int last_value, value;
329
330 if (line->children_count == 0)
331 return false; /* empty line, do nothing */
332
333 struct skin_element *child = line->children[0];
334 struct conditional *conditional;
335 skin_render_func func = skin_render_line;
336 char tempbuf[128];
337 int old_refresh_mode = info->refresh_type;
338 while (child)
339 {
340 tempbuf[0] = '\0';
341 switch (child->type)
342 {
343 case CONDITIONAL:
344 conditional = (struct conditional*)child->data;
345 last_value = conditional->last_value;
346 value = evaluate_conditional(info->gwps, conditional, child->children_count);
347
348 if (value != 1 && value >= child->children_count)
349 value = child->children_count-1;
350 if (child->children_count == 1)
351 {
352 /* special handling so
353 * %?aa<true> and %?<true|false> need special handlng here */
354
355 if (value == 1) /* tag is false */
356 {
357 /* we are in a false branch of a %?aa<true> conditional */
358 if (last_value == 0)
359 do_tags_in_hidden_conditional(child->children[0], info);
360 break;
361 }
362 value = 0;
363 }
364 else
365 {
366 if (last_value >= 0 && value != last_value && last_value < child->children_count)
367 do_tags_in_hidden_conditional(child->children[last_value], info);
368 }
369 if (child->children[value]->type == LINE_ALTERNATOR)
370 {
371 func = skin_render_alternator;
372 }
373 else if (child->children[value]->type == LINE)
374 func = skin_render_line;
375
376 if (value != last_value)
377 {
378 info->refresh_type = SKIN_REFRESH_ALL;
379 info->force_redraw = true;
380 }
381
382 if (func(child->children[value], info))
383 needs_update = true;
384 else
385 needs_update = needs_update || (last_value != value);
386
387 info->refresh_type = old_refresh_mode;
388 break;
389 case TAG:
390 if (child->tag->flags & NOBREAK)
391 info->no_line_break = true;
392 if (child->tag->type == SKIN_TOKEN_SUBLINE_SCROLL)
393 info->line_scrolls = true;
394
395 fix_line_alignment(info, child);
396
397 if (!child->data)
398 {
399 break;
400 }
401 if (!do_non_text_tags(info->gwps, info, child, &info->skin_vp->vp))
402 {
403 const char *value = get_token_value(info->gwps, child->data,
404 tempbuf, sizeof(tempbuf), NULL);
405 if (value)
406 {
407 needs_update = needs_update ||
408 ((child->tag->flags&info->refresh_type)!=0);
409 strlcat(info->cur_align_start, value,
410 info->buf_size - (info->cur_align_start-info->buf));
411 }
412 }
413 break;
414 case TEXT:
415 strlcat(info->cur_align_start, child->data,
416 info->buf_size - (info->cur_align_start-info->buf));
417 needs_update = needs_update ||
418 (info->refresh_type&SKIN_REFRESH_STATIC) != 0;
419 break;
420 case COMMENT:
421 default:
422 break;
423 }
424
425 child = child->next;
426 }
427 return needs_update;
428}
429
430bool skin_render_alternator(struct skin_element* element, struct skin_draw_info *info)
431{
432 bool changed_lines = false;
433 struct line_alternator *alternator = (struct line_alternator*)element->data;
434 unsigned old_refresh = info->refresh_type;
435 if (info->refresh_type == SKIN_REFRESH_ALL)
436 {
437 alternator->current_line = 0;
438 alternator->last_change_tick = current_tick;
439 changed_lines = true;
440 }
441 else
442 {
443 struct skin_element *current_line = element->children[alternator->current_line];
444 struct line *line = (struct line *)current_line->data;
445 int next_change = alternator->last_change_tick + line->timeout;
446 if (TIME_AFTER(current_tick, next_change))
447 {
448 alternator->current_line++;
449 if (alternator->current_line >= element->children_count)
450 alternator->current_line = 0;
451 alternator->last_change_tick = current_tick;
452 changed_lines = true;
453 }
454 }
455 if (element->children[alternator->current_line]->children_count == 0)
456 {
457 /* skip empty sublines */
458 alternator->current_line++;
459 if (alternator->current_line >= element->children_count)
460 alternator->current_line = 0;
461 changed_lines = true;
462 }
463
464 if (changed_lines)
465 {
466 info->refresh_type = SKIN_REFRESH_ALL;
467 info->force_redraw = true;
468 }
469 bool ret = skin_render_line(element->children[alternator->current_line], info);
470 info->refresh_type = old_refresh;
471 return changed_lines || ret;
472}
473
474void skin_render_viewport(struct skin_element* viewport, struct gui_wps *gwps,
475 struct skin_viewport* skin_viewport, unsigned long refresh_type)
476{
477 struct screen *display = gwps->display;
478 char linebuf[MAX_LINE];
479 skin_render_func func = skin_render_line;
480 struct skin_element* line = viewport;
481 struct skin_draw_info info = {
482 .gwps = gwps,
483 .buf = linebuf,
484 .buf_size = sizeof(linebuf),
485 .line_number = 0,
486 .no_line_break = false,
487 .line_scrolls = false,
488 .refresh_type = refresh_type,
489 .skin_vp = skin_viewport
490 };
491
492 struct align_pos * align = &info.align;
493 bool needs_update;
494#ifdef HAVE_LCD_BITMAP
495 /* Set images to not to be displayed */
496 struct skin_token_list *imglist = gwps->data->images;
497 while (imglist)
498 {
499 struct gui_img *img = (struct gui_img *)imglist->token->value.data;
500 img->display = -1;
501 imglist = imglist->next;
502 }
503#endif
504
505 while (line)
506 {
507 linebuf[0] = '\0';
508 info.no_line_break = false;
509 info.line_scrolls = false;
510 info.force_redraw = false;
511
512 info.cur_align_start = info.buf;
513 align->left = info.buf;
514 align->center = NULL;
515 align->right = NULL;
516
517
518 if (line->type == LINE_ALTERNATOR)
519 func = skin_render_alternator;
520 else if (line->type == LINE)
521 func = skin_render_line;
522
523 needs_update = func(line, &info);
524
525 /* only update if the line needs to be, and there is something to write */
526 if (refresh_type && needs_update)
527 {
528 if (info.line_scrolls)
529 {
530 /* if the line is a scrolling one we don't want to update
531 too often, so that it has the time to scroll */
532 if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw)
533 write_line(display, align, info.line_number, true);
534 }
535 else
536 write_line(display, align, info.line_number, false);
537 }
538 if (!info.no_line_break)
539 info.line_number++;
540 line = line->next;
541 }
542#ifdef HAVE_LCD_BITMAP
543 wps_display_images(gwps, &skin_viewport->vp);
544#endif
545}
546
547void skin_render(struct gui_wps *gwps, unsigned refresh_mode)
548{
549 struct wps_data *data = gwps->data;
550 struct screen *display = gwps->display;
551
552 struct skin_element* viewport = data->tree;
553 struct skin_viewport* skin_viewport;
554
555 int old_refresh_mode = refresh_mode;
556
557#ifdef HAVE_LCD_CHARCELLS
558 int i;
559 for (i = 0; i < 8; i++)
560 {
561 if (data->wps_progress_pat[i] == 0)
562 data->wps_progress_pat[i] = display->get_locked_pattern();
563 }
564#endif
565 viewport = data->tree;
566 skin_viewport = (struct skin_viewport *)viewport->data;
567 if (skin_viewport->label == VP_DEFAULT_LABEL && viewport->next)
568 refresh_mode = 0;
569
570 for (viewport = data->tree;
571 viewport;
572 viewport = viewport->next)
573 {
574 /* SETUP */
575 skin_viewport = (struct skin_viewport*)viewport->data;
576 unsigned vp_refresh_mode = refresh_mode;
577#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
578 skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour;
579 skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour;
580#endif
581
582 /* dont redraw the viewport if its disabled */
583 if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
584 { /* don't draw anything into this one */
585 vp_refresh_mode = 0;
586 }
587 else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN))
588 {
589 skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
590 continue;
591 }
592 else if (((skin_viewport->hidden_flags&
593 (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))
594 == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)))
595 {
596 vp_refresh_mode = SKIN_REFRESH_ALL;
597 skin_viewport->hidden_flags = VP_DRAW_HIDEABLE;
598 }
599
600 display->set_viewport(&skin_viewport->vp);
601 if ((vp_refresh_mode&SKIN_REFRESH_ALL) == SKIN_REFRESH_ALL)
602 {
603 display->clear_viewport();
604 }
605 /* render */
606 skin_render_viewport(viewport->children[0], gwps,
607 skin_viewport, vp_refresh_mode);
608 refresh_mode = old_refresh_mode;
609 }
610
611 /* Restore the default viewport */
612 display->set_viewport(NULL);
613 display->update();
614}
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,
167 unsigned long elapsed = id3->elapsed + state->ff_rewind_count; 167 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
168 switch (token->type) 168 switch (token->type)
169 { 169 {
170 case WPS_TOKEN_METADATA_ARTIST: 170 case SKIN_TOKEN_METADATA_ARTIST:
171 return id3->artist; 171 return id3->artist;
172 case WPS_TOKEN_METADATA_COMPOSER: 172 case SKIN_TOKEN_METADATA_COMPOSER:
173 return id3->composer; 173 return id3->composer;
174 case WPS_TOKEN_METADATA_ALBUM: 174 case SKIN_TOKEN_METADATA_ALBUM:
175 return id3->album; 175 return id3->album;
176 case WPS_TOKEN_METADATA_ALBUM_ARTIST: 176 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
177 return id3->albumartist; 177 return id3->albumartist;
178 case WPS_TOKEN_METADATA_GROUPING: 178 case SKIN_TOKEN_METADATA_GROUPING:
179 return id3->grouping; 179 return id3->grouping;
180 case WPS_TOKEN_METADATA_GENRE: 180 case SKIN_TOKEN_METADATA_GENRE:
181 return id3->genre_string; 181 return id3->genre_string;
182 case WPS_TOKEN_METADATA_DISC_NUMBER: 182 case SKIN_TOKEN_METADATA_DISC_NUMBER:
183 if (id3->disc_string) 183 if (id3->disc_string)
184 return id3->disc_string; 184 return id3->disc_string;
185 if (id3->discnum) { 185 if (id3->discnum) {
@@ -187,7 +187,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
187 return buf; 187 return buf;
188 } 188 }
189 return NULL; 189 return NULL;
190 case WPS_TOKEN_METADATA_TRACK_NUMBER: 190 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
191 if (id3->track_string) 191 if (id3->track_string)
192 return id3->track_string; 192 return id3->track_string;
193 if (id3->tracknum) { 193 if (id3->tracknum) {
@@ -195,9 +195,9 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
195 return buf; 195 return buf;
196 } 196 }
197 return NULL; 197 return NULL;
198 case WPS_TOKEN_METADATA_TRACK_TITLE: 198 case SKIN_TOKEN_METADATA_TRACK_TITLE:
199 return id3->title; 199 return id3->title;
200 case WPS_TOKEN_METADATA_VERSION: 200 case SKIN_TOKEN_METADATA_VERSION:
201 switch (id3->id3version) 201 switch (id3->id3version)
202 { 202 {
203 case ID3_VER_1_0: 203 case ID3_VER_1_0:
@@ -214,7 +214,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
214 break; 214 break;
215 } 215 }
216 return NULL; 216 return NULL;
217 case WPS_TOKEN_METADATA_YEAR: 217 case SKIN_TOKEN_METADATA_YEAR:
218 if( id3->year_string ) 218 if( id3->year_string )
219 return id3->year_string; 219 return id3->year_string;
220 if (id3->year) { 220 if (id3->year) {
@@ -222,29 +222,29 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
222 return buf; 222 return buf;
223 } 223 }
224 return NULL; 224 return NULL;
225 case WPS_TOKEN_METADATA_COMMENT: 225 case SKIN_TOKEN_METADATA_COMMENT:
226 return id3->comment; 226 return id3->comment;
227 case WPS_TOKEN_FILE_PATH: 227 case SKIN_TOKEN_FILE_PATH:
228 return id3->path; 228 return id3->path;
229 case WPS_TOKEN_FILE_BITRATE: 229 case SKIN_TOKEN_FILE_BITRATE:
230 if(id3->bitrate) 230 if(id3->bitrate)
231 snprintf(buf, buf_size, "%d", id3->bitrate); 231 snprintf(buf, buf_size, "%d", id3->bitrate);
232 else 232 else
233 return "?"; 233 return "?";
234 return buf; 234 return buf;
235 case WPS_TOKEN_TRACK_TIME_ELAPSED: 235 case SKIN_TOKEN_TRACK_TIME_ELAPSED:
236 format_time(buf, buf_size, elapsed); 236 format_time(buf, buf_size, elapsed);
237 return buf; 237 return buf;
238 238
239 case WPS_TOKEN_TRACK_TIME_REMAINING: 239 case SKIN_TOKEN_TRACK_TIME_REMAINING:
240 format_time(buf, buf_size, length - elapsed); 240 format_time(buf, buf_size, length - elapsed);
241 return buf; 241 return buf;
242 242
243 case WPS_TOKEN_TRACK_LENGTH: 243 case SKIN_TOKEN_TRACK_LENGTH:
244 format_time(buf, buf_size, length); 244 format_time(buf, buf_size, length);
245 return buf; 245 return buf;
246 246
247 case WPS_TOKEN_TRACK_ELAPSED_PERCENT: 247 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
248 if (length <= 0) 248 if (length <= 0)
249 return NULL; 249 return NULL;
250 250
@@ -255,14 +255,14 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
255 snprintf(buf, buf_size, "%lu", 100 * elapsed / length); 255 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
256 return buf; 256 return buf;
257 257
258 case WPS_TOKEN_TRACK_STARTING: 258 case SKIN_TOKEN_TRACK_STARTING:
259 { 259 {
260 unsigned long time = token->value.i * 1000; 260 unsigned long time = token->value.i * 1000;
261 if (elapsed < time) 261 if (elapsed < time)
262 return "starting"; 262 return "starting";
263 } 263 }
264 return NULL; 264 return NULL;
265 case WPS_TOKEN_TRACK_ENDING: 265 case SKIN_TOKEN_TRACK_ENDING:
266 { 266 {
267 unsigned long time = token->value.i * 1000; 267 unsigned long time = token->value.i * 1000;
268 if (length - elapsed < time) 268 if (length - elapsed < time)
@@ -270,7 +270,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
270 } 270 }
271 return NULL; 271 return NULL;
272 272
273 case WPS_TOKEN_FILE_CODEC: 273 case SKIN_TOKEN_FILE_CODEC:
274 if (intval) 274 if (intval)
275 { 275 {
276 if(id3->codectype == AFMT_UNKNOWN) 276 if(id3->codectype == AFMT_UNKNOWN)
@@ -280,10 +280,10 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
280 } 280 }
281 return get_codectype(id3); 281 return get_codectype(id3);
282 282
283 case WPS_TOKEN_FILE_FREQUENCY: 283 case SKIN_TOKEN_FILE_FREQUENCY:
284 snprintf(buf, buf_size, "%ld", id3->frequency); 284 snprintf(buf, buf_size, "%ld", id3->frequency);
285 return buf; 285 return buf;
286 case WPS_TOKEN_FILE_FREQUENCY_KHZ: 286 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
287 /* ignore remainders < 100, so 22050 Hz becomes just 22k */ 287 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
288 if ((id3->frequency % 1000) < 100) 288 if ((id3->frequency % 1000) < 100)
289 snprintf(buf, buf_size, "%ld", id3->frequency / 1000); 289 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
@@ -292,7 +292,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
292 id3->frequency / 1000, 292 id3->frequency / 1000,
293 (id3->frequency % 1000) / 100); 293 (id3->frequency % 1000) / 100);
294 return buf; 294 return buf;
295 case WPS_TOKEN_FILE_NAME: 295 case SKIN_TOKEN_FILE_NAME:
296 if (get_dir(buf, buf_size, id3->path, 0)) { 296 if (get_dir(buf, buf_size, id3->path, 0)) {
297 /* Remove extension */ 297 /* Remove extension */
298 char* sep = strrchr(buf, '.'); 298 char* sep = strrchr(buf, '.');
@@ -302,28 +302,28 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
302 return buf; 302 return buf;
303 } 303 }
304 return NULL; 304 return NULL;
305 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION: 305 case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION:
306 return get_dir(buf, buf_size, id3->path, 0); 306 return get_dir(buf, buf_size, id3->path, 0);
307 case WPS_TOKEN_FILE_SIZE: 307 case SKIN_TOKEN_FILE_SIZE:
308 snprintf(buf, buf_size, "%ld", id3->filesize / 1024); 308 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
309 return buf; 309 return buf;
310 case WPS_TOKEN_FILE_VBR: 310 case SKIN_TOKEN_FILE_VBR:
311 return (id3->vbr) ? "(avg)" : NULL; 311 return (id3->vbr) ? "(avg)" : NULL;
312 case WPS_TOKEN_FILE_DIRECTORY: 312 case SKIN_TOKEN_FILE_DIRECTORY:
313 return get_dir(buf, buf_size, id3->path, token->value.i); 313 return get_dir(buf, buf_size, id3->path, token->value.i);
314 314
315#ifdef HAVE_TAGCACHE 315#ifdef HAVE_TAGCACHE
316 case WPS_TOKEN_DATABASE_PLAYCOUNT: 316 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
317 if (intval) 317 if (intval)
318 *intval = id3->playcount + 1; 318 *intval = id3->playcount + 1;
319 snprintf(buf, buf_size, "%ld", id3->playcount); 319 snprintf(buf, buf_size, "%ld", id3->playcount);
320 return buf; 320 return buf;
321 case WPS_TOKEN_DATABASE_RATING: 321 case SKIN_TOKEN_DATABASE_RATING:
322 if (intval) 322 if (intval)
323 *intval = id3->rating + 1; 323 *intval = id3->rating + 1;
324 snprintf(buf, buf_size, "%d", id3->rating); 324 snprintf(buf, buf_size, "%d", id3->rating);
325 return buf; 325 return buf;
326 case WPS_TOKEN_DATABASE_AUTOSCORE: 326 case SKIN_TOKEN_DATABASE_AUTOSCORE:
327 if (intval) 327 if (intval)
328 *intval = id3->score + 1; 328 *intval = id3->score + 1;
329 snprintf(buf, buf_size, "%d", id3->score); 329 snprintf(buf, buf_size, "%d", id3->score);
@@ -340,13 +340,13 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
340 { 340 {
341 /* Most tokens expect NULL on error so leave that for the default case, 341 /* Most tokens expect NULL on error so leave that for the default case,
342 * The ones that expect "0" need to be handled */ 342 * The ones that expect "0" need to be handled */
343 case WPS_TOKEN_FILE_FREQUENCY: 343 case SKIN_TOKEN_FILE_FREQUENCY:
344 case WPS_TOKEN_FILE_FREQUENCY_KHZ: 344 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
345 case WPS_TOKEN_FILE_SIZE: 345 case SKIN_TOKEN_FILE_SIZE:
346#ifdef HAVE_TAGCACHE 346#ifdef HAVE_TAGCACHE
347 case WPS_TOKEN_DATABASE_PLAYCOUNT: 347 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
348 case WPS_TOKEN_DATABASE_RATING: 348 case SKIN_TOKEN_DATABASE_RATING:
349 case WPS_TOKEN_DATABASE_AUTOSCORE: 349 case SKIN_TOKEN_DATABASE_AUTOSCORE:
350#endif 350#endif
351 if (intval) 351 if (intval)
352 *intval = 0; 352 *intval = 0;
@@ -397,30 +397,30 @@ const char *get_radio_token(struct wps_token *token, int preset_offset,
397 switch (token->type) 397 switch (token->type)
398 { 398 {
399 /* Radio/tuner tokens */ 399 /* Radio/tuner tokens */
400 case WPS_TOKEN_TUNER_TUNED: 400 case SKIN_TOKEN_TUNER_TUNED:
401 if (tuner_get(RADIO_TUNED)) 401 if (tuner_get(RADIO_TUNED))
402 return "t"; 402 return "t";
403 return NULL; 403 return NULL;
404 case WPS_TOKEN_TUNER_SCANMODE: 404 case SKIN_TOKEN_TUNER_SCANMODE:
405 if (radio_scan_mode()) 405 if (radio_scan_mode())
406 return "s"; 406 return "s";
407 return NULL; 407 return NULL;
408 case WPS_TOKEN_TUNER_STEREO: 408 case SKIN_TOKEN_TUNER_STEREO:
409 if (radio_is_stereo()) 409 if (radio_is_stereo())
410 return "s"; 410 return "s";
411 return NULL; 411 return NULL;
412 case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */ 412 case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
413 return format_freq_MHz(region_data->freq_min, 413 return format_freq_MHz(region_data->freq_min,
414 region_data->freq_step, buf, buf_size); 414 region_data->freq_step, buf, buf_size);
415 case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */ 415 case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
416 return format_freq_MHz(region_data->freq_max, 416 return format_freq_MHz(region_data->freq_max,
417 region_data->freq_step, buf, buf_size); 417 region_data->freq_step, buf, buf_size);
418 case WPS_TOKEN_TUNER_CURFREQ: 418 case SKIN_TOKEN_TUNER_CURFREQ:
419 return format_freq_MHz(radio_current_frequency(), 419 return format_freq_MHz(radio_current_frequency(),
420 region_data->freq_step, buf, buf_size); 420 region_data->freq_step, buf, buf_size);
421 case WPS_TOKEN_PRESET_NAME: 421 case SKIN_TOKEN_PRESET_NAME:
422 case WPS_TOKEN_PRESET_FREQ: 422 case SKIN_TOKEN_PRESET_FREQ:
423 case WPS_TOKEN_PRESET_ID: 423 case SKIN_TOKEN_PRESET_ID:
424 { 424 {
425 int preset_count = radio_preset_count(); 425 int preset_count = radio_preset_count();
426 int cur_preset = radio_current_preset(); 426 int cur_preset = radio_current_preset();
@@ -431,30 +431,32 @@ const char *get_radio_token(struct wps_token *token, int preset_offset,
431 preset %= preset_count; 431 preset %= preset_count;
432 if (preset < 0) 432 if (preset < 0)
433 preset += preset_count; 433 preset += preset_count;
434 if (token->type == WPS_TOKEN_PRESET_NAME) 434 if (token->type == SKIN_TOKEN_PRESET_NAME)
435 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name); 435 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
436 else if (token->type == WPS_TOKEN_PRESET_FREQ) 436 else if (token->type == SKIN_TOKEN_PRESET_FREQ)
437 format_freq_MHz(radio_get_preset(preset)->frequency, 437 format_freq_MHz(radio_get_preset(preset)->frequency,
438 region_data->freq_step, buf, buf_size); 438 region_data->freq_step, buf, buf_size);
439 else 439 else
440 snprintf(buf, buf_size, "%d", preset + 1); 440 snprintf(buf, buf_size, "%d", preset + 1);
441 return buf; 441 return buf;
442 } 442 }
443 case WPS_TOKEN_PRESET_COUNT: 443 case SKIN_TOKEN_PRESET_COUNT:
444 snprintf(buf, buf_size, "%d", radio_preset_count()); 444 snprintf(buf, buf_size, "%d", radio_preset_count());
445 if (intval) 445 if (intval)
446 *intval = radio_preset_count(); 446 *intval = radio_preset_count();
447 return buf; 447 return buf;
448 case WPS_TOKEN_HAVE_RDS: 448 case SKIN_TOKEN_HAVE_RDS:
449#ifdef HAVE_RDS_CAP 449#ifdef HAVE_RDS_CAP
450 return "rds"; 450 return "rds";
451 case WPS_TOKEN_RDS_NAME: 451 case SKIN_TOKEN_RDS_NAME:
452 return tuner_get_rds_info(RADIO_RDS_NAME); 452 return tuner_get_rds_info(RADIO_RDS_NAME);
453 case WPS_TOKEN_RDS_TEXT: 453 case SKIN_TOKEN_RDS_TEXT:
454 return tuner_get_rds_info(RADIO_RDS_TEXT); 454 return tuner_get_rds_info(RADIO_RDS_TEXT);
455#else 455#else
456 return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */ 456 return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
457#endif /* HAVE_RDS_CAP */ 457#endif /* HAVE_RDS_CAP */
458 default:
459 return NULL;
458 } 460 }
459 return NULL; 461 return NULL;
460} 462}
@@ -497,8 +499,8 @@ const char *get_token_value(struct gui_wps *gwps,
497 499
498 /* if the token is an RTC one, update the time 500 /* if the token is an RTC one, update the time
499 and do the necessary checks */ 501 and do the necessary checks */
500 if (token->type >= WPS_TOKENS_RTC_BEGIN 502 if (token->type >= SKIN_TOKENS_RTC_BEGIN
501 && token->type <= WPS_TOKENS_RTC_END) 503 && token->type <= SKIN_TOKENS_RTC_END)
502 { 504 {
503 tm = get_time(); 505 tm = get_time();
504 506
@@ -531,44 +533,44 @@ const char *get_token_value(struct gui_wps *gwps,
531 533
532 switch (token->type) 534 switch (token->type)
533 { 535 {
534 case WPS_TOKEN_CHARACTER: 536 case SKIN_TOKEN_CHARACTER:
535 if (token->value.c == '\n') 537 if (token->value.c == '\n')
536 return NULL; 538 return NULL;
537 return &(token->value.c); 539 return &(token->value.c);
538 540
539 case WPS_TOKEN_STRING: 541 case SKIN_TOKEN_STRING:
540 return (char*)token->value.data; 542 return (char*)token->value.data;
541 543
542 case WPS_TOKEN_TRANSLATEDSTRING: 544 case SKIN_TOKEN_TRANSLATEDSTRING:
543 return (char*)P2STR(ID2P(token->value.i)); 545 return (char*)P2STR(ID2P(token->value.i));
544 546
545 case WPS_TOKEN_PLAYLIST_ENTRIES: 547 case SKIN_TOKEN_PLAYLIST_ENTRIES:
546 snprintf(buf, buf_size, "%d", playlist_amount()); 548 snprintf(buf, buf_size, "%d", playlist_amount());
547 return buf; 549 return buf;
548 550
549 case WPS_TOKEN_LIST_TITLE_TEXT: 551 case SKIN_TOKEN_LIST_TITLE_TEXT:
550 return (char*)token->value.data; 552 return (char*)token->value.data;
551 case WPS_TOKEN_LIST_TITLE_ICON: 553 case SKIN_TOKEN_LIST_TITLE_ICON:
552 if (intval) 554 if (intval)
553 *intval = token->value.i; 555 *intval = token->value.i;
554 snprintf(buf, buf_size, "%d", token->value.i); 556 snprintf(buf, buf_size, "%d", token->value.i);
555 return buf; 557 return buf;
556 558
557 case WPS_TOKEN_PLAYLIST_NAME: 559 case SKIN_TOKEN_PLAYLIST_NAME:
558 return playlist_name(NULL, buf, buf_size); 560 return playlist_name(NULL, buf, buf_size);
559 561
560 case WPS_TOKEN_PLAYLIST_POSITION: 562 case SKIN_TOKEN_PLAYLIST_POSITION:
561 snprintf(buf, buf_size, "%d", playlist_get_display_index()); 563 snprintf(buf, buf_size, "%d", playlist_get_display_index());
562 return buf; 564 return buf;
563 565
564 case WPS_TOKEN_PLAYLIST_SHUFFLE: 566 case SKIN_TOKEN_PLAYLIST_SHUFFLE:
565 if ( global_settings.playlist_shuffle ) 567 if ( global_settings.playlist_shuffle )
566 return "s"; 568 return "s";
567 else 569 else
568 return NULL; 570 return NULL;
569 break; 571 break;
570 572
571 case WPS_TOKEN_VOLUME: 573 case SKIN_TOKEN_VOLUME:
572 snprintf(buf, buf_size, "%d", global_settings.volume); 574 snprintf(buf, buf_size, "%d", global_settings.volume);
573 if (intval) 575 if (intval)
574 { 576 {
@@ -593,7 +595,7 @@ const char *get_token_value(struct gui_wps *gwps,
593 } 595 }
594 return buf; 596 return buf;
595#ifdef HAVE_ALBUMART 597#ifdef HAVE_ALBUMART
596 case WPS_TOKEN_ALBUMART_FOUND: 598 case SKIN_TOKEN_ALBUMART_FOUND:
597 if (data->albumart) 599 if (data->albumart)
598 { 600 {
599 int handle = -1; 601 int handle = -1;
@@ -609,16 +611,9 @@ const char *get_token_value(struct gui_wps *gwps,
609 return "C"; 611 return "C";
610 } 612 }
611 return NULL; 613 return NULL;
612
613 case WPS_TOKEN_ALBUMART_DISPLAY:
614 if (!data->albumart)
615 return NULL;
616 if (!data->albumart->draw)
617 data->albumart->draw = true;
618 return NULL;
619#endif 614#endif
620 615
621 case WPS_TOKEN_BATTERY_PERCENT: 616 case SKIN_TOKEN_BATTERY_PERCENT:
622 { 617 {
623 int l = battery_level(); 618 int l = battery_level();
624 619
@@ -641,14 +636,14 @@ const char *get_token_value(struct gui_wps *gwps,
641 } 636 }
642 } 637 }
643 638
644 case WPS_TOKEN_BATTERY_VOLTS: 639 case SKIN_TOKEN_BATTERY_VOLTS:
645 { 640 {
646 unsigned int v = battery_voltage(); 641 unsigned int v = battery_voltage();
647 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10); 642 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
648 return buf; 643 return buf;
649 } 644 }
650 645
651 case WPS_TOKEN_BATTERY_TIME: 646 case SKIN_TOKEN_BATTERY_TIME:
652 { 647 {
653 int t = battery_time(); 648 int t = battery_time();
654 if (t >= 0) 649 if (t >= 0)
@@ -659,7 +654,7 @@ const char *get_token_value(struct gui_wps *gwps,
659 } 654 }
660 655
661#if CONFIG_CHARGING 656#if CONFIG_CHARGING
662 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED: 657 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
663 { 658 {
664 if(charger_input_state==CHARGER) 659 if(charger_input_state==CHARGER)
665 return "p"; 660 return "p";
@@ -668,7 +663,7 @@ const char *get_token_value(struct gui_wps *gwps,
668 } 663 }
669#endif 664#endif
670#if CONFIG_CHARGING >= CHARGING_MONITOR 665#if CONFIG_CHARGING >= CHARGING_MONITOR
671 case WPS_TOKEN_BATTERY_CHARGING: 666 case SKIN_TOKEN_BATTERY_CHARGING:
672 { 667 {
673 if (charge_state == CHARGING || charge_state == TOPOFF) { 668 if (charge_state == CHARGING || charge_state == TOPOFF) {
674 return "c"; 669 return "c";
@@ -678,12 +673,12 @@ const char *get_token_value(struct gui_wps *gwps,
678 } 673 }
679#endif 674#endif
680#ifdef HAVE_USB_POWER 675#ifdef HAVE_USB_POWER
681 case WPS_TOKEN_USB_POWERED: 676 case SKIN_TOKEN_USB_POWERED:
682 if (usb_powered()) 677 if (usb_powered())
683 return "u"; 678 return "u";
684 return NULL; 679 return NULL;
685#endif 680#endif
686 case WPS_TOKEN_BATTERY_SLEEPTIME: 681 case SKIN_TOKEN_BATTERY_SLEEPTIME:
687 { 682 {
688 if (get_sleep_timer() == 0) 683 if (get_sleep_timer() == 0)
689 return NULL; 684 return NULL;
@@ -694,7 +689,7 @@ const char *get_token_value(struct gui_wps *gwps,
694 } 689 }
695 } 690 }
696 691
697 case WPS_TOKEN_PLAYBACK_STATUS: 692 case SKIN_TOKEN_PLAYBACK_STATUS:
698 { 693 {
699 int status = current_playmode(); 694 int status = current_playmode();
700 /* music */ 695 /* music */
@@ -734,13 +729,13 @@ const char *get_token_value(struct gui_wps *gwps,
734 return buf; 729 return buf;
735 } 730 }
736 731
737 case WPS_TOKEN_REPEAT_MODE: 732 case SKIN_TOKEN_REPEAT_MODE:
738 if (intval) 733 if (intval)
739 *intval = global_settings.repeat_mode + 1; 734 *intval = global_settings.repeat_mode + 1;
740 snprintf(buf, buf_size, "%d", global_settings.repeat_mode); 735 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
741 return buf; 736 return buf;
742 737
743 case WPS_TOKEN_RTC_PRESENT: 738 case SKIN_TOKEN_RTC_PRESENT:
744#if CONFIG_RTC 739#if CONFIG_RTC
745 return "c"; 740 return "c";
746#else 741#else
@@ -748,41 +743,41 @@ const char *get_token_value(struct gui_wps *gwps,
748#endif 743#endif
749 744
750#if CONFIG_RTC 745#if CONFIG_RTC
751 case WPS_TOKEN_RTC_12HOUR_CFG: 746 case SKIN_TOKEN_RTC_12HOUR_CFG:
752 if (intval) 747 if (intval)
753 *intval = global_settings.timeformat + 1; 748 *intval = global_settings.timeformat + 1;
754 snprintf(buf, buf_size, "%d", global_settings.timeformat); 749 snprintf(buf, buf_size, "%d", global_settings.timeformat);
755 return buf; 750 return buf;
756 751
757 case WPS_TOKEN_RTC_DAY_OF_MONTH: 752 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
758 /* d: day of month (01..31) */ 753 /* d: day of month (01..31) */
759 snprintf(buf, buf_size, "%02d", tm->tm_mday); 754 snprintf(buf, buf_size, "%02d", tm->tm_mday);
760 if (intval) 755 if (intval)
761 *intval = tm->tm_mday - 1; 756 *intval = tm->tm_mday - 1;
762 return buf; 757 return buf;
763 758
764 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: 759 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
765 /* e: day of month, blank padded ( 1..31) */ 760 /* e: day of month, blank padded ( 1..31) */
766 snprintf(buf, buf_size, "%2d", tm->tm_mday); 761 snprintf(buf, buf_size, "%2d", tm->tm_mday);
767 if (intval) 762 if (intval)
768 *intval = tm->tm_mday - 1; 763 *intval = tm->tm_mday - 1;
769 return buf; 764 return buf;
770 765
771 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED: 766 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
772 /* H: hour (00..23) */ 767 /* H: hour (00..23) */
773 snprintf(buf, buf_size, "%02d", tm->tm_hour); 768 snprintf(buf, buf_size, "%02d", tm->tm_hour);
774 if (intval) 769 if (intval)
775 *intval = tm->tm_hour; 770 *intval = tm->tm_hour;
776 return buf; 771 return buf;
777 772
778 case WPS_TOKEN_RTC_HOUR_24: 773 case SKIN_TOKEN_RTC_HOUR_24:
779 /* k: hour ( 0..23) */ 774 /* k: hour ( 0..23) */
780 snprintf(buf, buf_size, "%2d", tm->tm_hour); 775 snprintf(buf, buf_size, "%2d", tm->tm_hour);
781 if (intval) 776 if (intval)
782 *intval = tm->tm_hour; 777 *intval = tm->tm_hour;
783 return buf; 778 return buf;
784 779
785 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED: 780 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
786 /* I: hour (01..12) */ 781 /* I: hour (01..12) */
787 snprintf(buf, buf_size, "%02d", 782 snprintf(buf, buf_size, "%02d",
788 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12); 783 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
@@ -790,7 +785,7 @@ const char *get_token_value(struct gui_wps *gwps,
790 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12; 785 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
791 return buf; 786 return buf;
792 787
793 case WPS_TOKEN_RTC_HOUR_12: 788 case SKIN_TOKEN_RTC_HOUR_12:
794 /* l: hour ( 1..12) */ 789 /* l: hour ( 1..12) */
795 snprintf(buf, buf_size, "%2d", 790 snprintf(buf, buf_size, "%2d",
796 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12); 791 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
@@ -798,107 +793,107 @@ const char *get_token_value(struct gui_wps *gwps,
798 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12; 793 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
799 return buf; 794 return buf;
800 795
801 case WPS_TOKEN_RTC_MONTH: 796 case SKIN_TOKEN_RTC_MONTH:
802 /* m: month (01..12) */ 797 /* m: month (01..12) */
803 if (intval) 798 if (intval)
804 *intval = tm->tm_mon + 1; 799 *intval = tm->tm_mon + 1;
805 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1); 800 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
806 return buf; 801 return buf;
807 802
808 case WPS_TOKEN_RTC_MINUTE: 803 case SKIN_TOKEN_RTC_MINUTE:
809 /* M: minute (00..59) */ 804 /* M: minute (00..59) */
810 snprintf(buf, buf_size, "%02d", tm->tm_min); 805 snprintf(buf, buf_size, "%02d", tm->tm_min);
811 if (intval) 806 if (intval)
812 *intval = tm->tm_min; 807 *intval = tm->tm_min;
813 return buf; 808 return buf;
814 809
815 case WPS_TOKEN_RTC_SECOND: 810 case SKIN_TOKEN_RTC_SECOND:
816 /* S: second (00..59) */ 811 /* S: second (00..59) */
817 snprintf(buf, buf_size, "%02d", tm->tm_sec); 812 snprintf(buf, buf_size, "%02d", tm->tm_sec);
818 if (intval) 813 if (intval)
819 *intval = tm->tm_sec; 814 *intval = tm->tm_sec;
820 return buf; 815 return buf;
821 816
822 case WPS_TOKEN_RTC_YEAR_2_DIGITS: 817 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
823 /* y: last two digits of year (00..99) */ 818 /* y: last two digits of year (00..99) */
824 snprintf(buf, buf_size, "%02d", tm->tm_year % 100); 819 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
825 if (intval) 820 if (intval)
826 *intval = tm->tm_year % 100; 821 *intval = tm->tm_year % 100;
827 return buf; 822 return buf;
828 823
829 case WPS_TOKEN_RTC_YEAR_4_DIGITS: 824 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
830 /* Y: year (1970...) */ 825 /* Y: year (1970...) */
831 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900); 826 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
832 if (intval) 827 if (intval)
833 *intval = tm->tm_year + 1900; 828 *intval = tm->tm_year + 1900;
834 return buf; 829 return buf;
835 830
836 case WPS_TOKEN_RTC_AM_PM_UPPER: 831 case SKIN_TOKEN_RTC_AM_PM_UPPER:
837 /* p: upper case AM or PM indicator */ 832 /* p: upper case AM or PM indicator */
838 if (intval) 833 if (intval)
839 *intval = tm->tm_hour/12 == 0 ? 0 : 1; 834 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
840 return tm->tm_hour/12 == 0 ? "AM" : "PM"; 835 return tm->tm_hour/12 == 0 ? "AM" : "PM";
841 836
842 case WPS_TOKEN_RTC_AM_PM_LOWER: 837 case SKIN_TOKEN_RTC_AM_PM_LOWER:
843 /* P: lower case am or pm indicator */ 838 /* P: lower case am or pm indicator */
844 if (intval) 839 if (intval)
845 *intval = tm->tm_hour/12 == 0 ? 0 : 1; 840 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
846 return tm->tm_hour/12 == 0 ? "am" : "pm"; 841 return tm->tm_hour/12 == 0 ? "am" : "pm";
847 842
848 case WPS_TOKEN_RTC_WEEKDAY_NAME: 843 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
849 /* a: abbreviated weekday name (Sun..Sat) */ 844 /* a: abbreviated weekday name (Sun..Sat) */
850 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday); 845 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
851 846
852 case WPS_TOKEN_RTC_MONTH_NAME: 847 case SKIN_TOKEN_RTC_MONTH_NAME:
853 /* b: abbreviated month name (Jan..Dec) */ 848 /* b: abbreviated month name (Jan..Dec) */
854 return str(LANG_MONTH_JANUARY + tm->tm_mon); 849 return str(LANG_MONTH_JANUARY + tm->tm_mon);
855 850
856 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON: 851 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
857 /* u: day of week (1..7); 1 is Monday */ 852 /* u: day of week (1..7); 1 is Monday */
858 if (intval) 853 if (intval)
859 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday; 854 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
860 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1); 855 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
861 return buf; 856 return buf;
862 857
863 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN: 858 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
864 /* w: day of week (0..6); 0 is Sunday */ 859 /* w: day of week (0..6); 0 is Sunday */
865 if (intval) 860 if (intval)
866 *intval = tm->tm_wday + 1; 861 *intval = tm->tm_wday + 1;
867 snprintf(buf, buf_size, "%1d", tm->tm_wday); 862 snprintf(buf, buf_size, "%1d", tm->tm_wday);
868 return buf; 863 return buf;
869#else 864#else
870 case WPS_TOKEN_RTC_DAY_OF_MONTH: 865 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
871 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: 866 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
872 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED: 867 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
873 case WPS_TOKEN_RTC_HOUR_24: 868 case SKIN_TOKEN_RTC_HOUR_24:
874 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED: 869 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
875 case WPS_TOKEN_RTC_HOUR_12: 870 case SKIN_TOKEN_RTC_HOUR_12:
876 case WPS_TOKEN_RTC_MONTH: 871 case SKIN_TOKEN_RTC_MONTH:
877 case WPS_TOKEN_RTC_MINUTE: 872 case SKIN_TOKEN_RTC_MINUTE:
878 case WPS_TOKEN_RTC_SECOND: 873 case SKIN_TOKEN_RTC_SECOND:
879 case WPS_TOKEN_RTC_AM_PM_UPPER: 874 case SKIN_TOKEN_RTC_AM_PM_UPPER:
880 case WPS_TOKEN_RTC_AM_PM_LOWER: 875 case SKIN_TOKEN_RTC_AM_PM_LOWER:
881 case WPS_TOKEN_RTC_YEAR_2_DIGITS: 876 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
882 return "--"; 877 return "--";
883 case WPS_TOKEN_RTC_YEAR_4_DIGITS: 878 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
884 return "----"; 879 return "----";
885 case WPS_TOKEN_RTC_WEEKDAY_NAME: 880 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
886 case WPS_TOKEN_RTC_MONTH_NAME: 881 case SKIN_TOKEN_RTC_MONTH_NAME:
887 return "---"; 882 return "---";
888 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON: 883 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
889 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN: 884 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
890 return "-"; 885 return "-";
891#endif 886#endif
892 887
893#ifdef HAVE_LCD_CHARCELLS 888#ifdef HAVE_LCD_CHARCELLS
894 case WPS_TOKEN_PROGRESSBAR: 889 case SKIN_TOKEN_PROGRESSBAR:
895 { 890 {
896 char *end = utf8encode(data->wps_progress_pat[0], buf); 891 char *end = utf8encode(data->wps_progress_pat[0], buf);
897 *end = '\0'; 892 *end = '\0';
898 return buf; 893 return buf;
899 } 894 }
900 895
901 case WPS_TOKEN_PLAYER_PROGRESSBAR: 896 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
902 if(is_new_player()) 897 if(is_new_player())
903 { 898 {
904 /* we need 11 characters (full line) for 899 /* we need 11 characters (full line) for
@@ -916,7 +911,7 @@ const char *get_token_value(struct gui_wps *gwps,
916 911
917 912
918#if (CONFIG_CODEC == SWCODEC) 913#if (CONFIG_CODEC == SWCODEC)
919 case WPS_TOKEN_CROSSFADE: 914 case SKIN_TOKEN_CROSSFADE:
920#ifdef HAVE_CROSSFADE 915#ifdef HAVE_CROSSFADE
921 if (intval) 916 if (intval)
922 *intval = global_settings.crossfade + 1; 917 *intval = global_settings.crossfade + 1;
@@ -926,7 +921,7 @@ const char *get_token_value(struct gui_wps *gwps,
926#endif 921#endif
927 return buf; 922 return buf;
928 923
929 case WPS_TOKEN_REPLAYGAIN: 924 case SKIN_TOKEN_REPLAYGAIN:
930 { 925 {
931 int val; 926 int val;
932 927
@@ -974,7 +969,7 @@ const char *get_token_value(struct gui_wps *gwps,
974#endif /* (CONFIG_CODEC == SWCODEC) */ 969#endif /* (CONFIG_CODEC == SWCODEC) */
975 970
976#if (CONFIG_CODEC != MAS3507D) 971#if (CONFIG_CODEC != MAS3507D)
977 case WPS_TOKEN_SOUND_PITCH: 972 case SKIN_TOKEN_SOUND_PITCH:
978 { 973 {
979 int32_t pitch = sound_get_pitch(); 974 int32_t pitch = sound_get_pitch();
980 snprintf(buf, buf_size, "%ld.%ld", 975 snprintf(buf, buf_size, "%ld.%ld",
@@ -989,7 +984,7 @@ const char *get_token_value(struct gui_wps *gwps,
989#endif 984#endif
990 985
991#if CONFIG_CODEC == SWCODEC 986#if CONFIG_CODEC == SWCODEC
992 case WPS_TOKEN_SOUND_SPEED: 987 case SKIN_TOKEN_SOUND_SPEED:
993 { 988 {
994 int32_t pitch = sound_get_pitch(); 989 int32_t pitch = sound_get_pitch();
995 int32_t speed; 990 int32_t speed;
@@ -1007,7 +1002,7 @@ const char *get_token_value(struct gui_wps *gwps,
1007 } 1002 }
1008#endif 1003#endif
1009 1004
1010 case WPS_TOKEN_MAIN_HOLD: 1005 case SKIN_TOKEN_MAIN_HOLD:
1011#ifdef HAS_BUTTON_HOLD 1006#ifdef HAS_BUTTON_HOLD
1012 if (button_hold()) 1007 if (button_hold())
1013#else 1008#else
@@ -1018,7 +1013,7 @@ const char *get_token_value(struct gui_wps *gwps,
1018 return NULL; 1013 return NULL;
1019 1014
1020#ifdef HAS_REMOTE_BUTTON_HOLD 1015#ifdef HAS_REMOTE_BUTTON_HOLD
1021 case WPS_TOKEN_REMOTE_HOLD: 1016 case SKIN_TOKEN_REMOTE_HOLD:
1022 if (remote_button_hold()) 1017 if (remote_button_hold())
1023 return "r"; 1018 return "r";
1024 else 1019 else
@@ -1026,20 +1021,20 @@ const char *get_token_value(struct gui_wps *gwps,
1026#endif 1021#endif
1027 1022
1028#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) 1023#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1029 case WPS_TOKEN_VLED_HDD: 1024 case SKIN_TOKEN_VLED_HDD:
1030 if(led_read(HZ/2)) 1025 if(led_read(HZ/2))
1031 return "h"; 1026 return "h";
1032 else 1027 else
1033 return NULL; 1028 return NULL;
1034#endif 1029#endif
1035 case WPS_TOKEN_BUTTON_VOLUME: 1030 case SKIN_TOKEN_BUTTON_VOLUME:
1036 if (global_status.last_volume_change && 1031 if (global_status.last_volume_change &&
1037 TIME_BEFORE(current_tick, global_status.last_volume_change + 1032 TIME_BEFORE(current_tick, global_status.last_volume_change +
1038 token->value.i * TIMEOUT_UNIT)) 1033 token->value.i * TIMEOUT_UNIT))
1039 return "v"; 1034 return "v";
1040 return NULL; 1035 return NULL;
1041 1036
1042 case WPS_TOKEN_LASTTOUCH: 1037 case SKIN_TOKEN_LASTTOUCH:
1043 { 1038 {
1044#ifdef HAVE_TOUCHSCREEN 1039#ifdef HAVE_TOUCHSCREEN
1045 unsigned int last_touch = touchscreen_last_touch(); 1040 unsigned int last_touch = touchscreen_last_touch();
@@ -1051,7 +1046,7 @@ const char *get_token_value(struct gui_wps *gwps,
1051 } 1046 }
1052 return NULL; 1047 return NULL;
1053 1048
1054 case WPS_TOKEN_SETTING: 1049 case SKIN_TOKEN_SETTING:
1055 { 1050 {
1056 const struct settings_list *s = settings+token->value.i; 1051 const struct settings_list *s = settings+token->value.i;
1057 if (intval) 1052 if (intval)
@@ -1120,14 +1115,14 @@ const char *get_token_value(struct gui_wps *gwps,
1120 cfg_to_string(token->value.i,buf,buf_size); 1115 cfg_to_string(token->value.i,buf,buf_size);
1121 return buf; 1116 return buf;
1122 } 1117 }
1123 case WPS_TOKEN_HAVE_TUNER: 1118 case SKIN_TOKEN_HAVE_TUNER:
1124#if CONFIG_TUNER 1119#if CONFIG_TUNER
1125 if (radio_hardware_present()) 1120 if (radio_hardware_present())
1126 return "r"; 1121 return "r";
1127#endif 1122#endif
1128 return NULL; 1123 return NULL;
1129 /* Recording tokens */ 1124 /* Recording tokens */
1130 case WPS_TOKEN_HAVE_RECORDING: 1125 case SKIN_TOKEN_HAVE_RECORDING:
1131#ifdef HAVE_RECORDING 1126#ifdef HAVE_RECORDING
1132 return "r"; 1127 return "r";
1133#else 1128#else
@@ -1135,11 +1130,11 @@ const char *get_token_value(struct gui_wps *gwps,
1135#endif 1130#endif
1136 1131
1137#ifdef HAVE_RECORDING 1132#ifdef HAVE_RECORDING
1138 case WPS_TOKEN_IS_RECORDING: 1133 case SKIN_TOKEN_IS_RECORDING:
1139 if (audio_status() == AUDIO_STATUS_RECORD) 1134 if (audio_status() == AUDIO_STATUS_RECORD)
1140 return "r"; 1135 return "r";
1141 return NULL; 1136 return NULL;
1142 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */ 1137 case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1143 { 1138 {
1144#if CONFIG_CODEC == SWCODEC 1139#if CONFIG_CODEC == SWCODEC
1145 unsigned long samprk; 1140 unsigned long samprk;
@@ -1227,7 +1222,7 @@ const char *get_token_value(struct gui_wps *gwps,
1227 return buf; 1222 return buf;
1228 } 1223 }
1229#if CONFIG_CODEC == SWCODEC 1224#if CONFIG_CODEC == SWCODEC
1230 case WPS_TOKEN_REC_ENCODER: 1225 case SKIN_TOKEN_REC_ENCODER:
1231 { 1226 {
1232 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */ 1227 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1233 if (intval) 1228 if (intval)
@@ -1248,7 +1243,7 @@ const char *get_token_value(struct gui_wps *gwps,
1248 break; 1243 break;
1249 } 1244 }
1250#endif 1245#endif
1251 case WPS_TOKEN_REC_BITRATE: 1246 case SKIN_TOKEN_REC_BITRATE:
1252#if CONFIG_CODEC == SWCODEC 1247#if CONFIG_CODEC == SWCODEC
1253 if (global_settings.rec_format == REC_FORMAT_MPA_L3) 1248 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1254 { 1249 {
@@ -1317,12 +1312,12 @@ const char *get_token_value(struct gui_wps *gwps,
1317 snprintf(buf, buf_size, "%d", global_settings.rec_quality); 1312 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1318 return buf; 1313 return buf;
1319#endif 1314#endif
1320 case WPS_TOKEN_REC_MONO: 1315 case SKIN_TOKEN_REC_MONO:
1321 if (!global_settings.rec_channels) 1316 if (!global_settings.rec_channels)
1322 return "m"; 1317 return "m";
1323 return NULL; 1318 return NULL;
1324 1319
1325 case WPS_TOKEN_REC_SECONDS: 1320 case SKIN_TOKEN_REC_SECONDS:
1326 { 1321 {
1327 int time = (audio_recorded_time() / HZ) % 60; 1322 int time = (audio_recorded_time() / HZ) % 60;
1328 if (intval) 1323 if (intval)
@@ -1330,7 +1325,7 @@ const char *get_token_value(struct gui_wps *gwps,
1330 snprintf(buf, buf_size, "%02d", time); 1325 snprintf(buf, buf_size, "%02d", time);
1331 return buf; 1326 return buf;
1332 } 1327 }
1333 case WPS_TOKEN_REC_MINUTES: 1328 case SKIN_TOKEN_REC_MINUTES:
1334 { 1329 {
1335 int time = (audio_recorded_time() / HZ) / 60; 1330 int time = (audio_recorded_time() / HZ) / 60;
1336 if (intval) 1331 if (intval)
@@ -1338,7 +1333,7 @@ const char *get_token_value(struct gui_wps *gwps,
1338 snprintf(buf, buf_size, "%02d", time); 1333 snprintf(buf, buf_size, "%02d", time);
1339 return buf; 1334 return buf;
1340 } 1335 }
1341 case WPS_TOKEN_REC_HOURS: 1336 case SKIN_TOKEN_REC_HOURS:
1342 { 1337 {
1343 int time = (audio_recorded_time() / HZ) / 3600; 1338 int time = (audio_recorded_time() / HZ) / 3600;
1344 if (intval) 1339 if (intval)
@@ -1349,7 +1344,7 @@ const char *get_token_value(struct gui_wps *gwps,
1349 1344
1350#endif /* HAVE_RECORDING */ 1345#endif /* HAVE_RECORDING */
1351 1346
1352 case WPS_TOKEN_CURRENT_SCREEN: 1347 case SKIN_TOKEN_CURRENT_SCREEN:
1353 { 1348 {
1354 int curr_screen = current_screen(); 1349 int curr_screen = current_screen();
1355 1350
@@ -1390,7 +1385,7 @@ const char *get_token_value(struct gui_wps *gwps,
1390 return buf; 1385 return buf;
1391 } 1386 }
1392 1387
1393 case WPS_TOKEN_LANG_IS_RTL: 1388 case SKIN_TOKEN_LANG_IS_RTL:
1394 return lang_is_rtl() ? "r" : NULL; 1389 return lang_is_rtl() ? "r" : NULL;
1395 1390
1396 default: 1391 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 @@
23#define _SKIN_TOKENS_H_ 23#define _SKIN_TOKENS_H_
24 24
25#include <stdbool.h> 25#include <stdbool.h>
26 26#include "tag_table.h"
27
28enum wps_token_type {
29
30 TOKEN_MARKER_CONTROL_TOKENS = -1,
31 WPS_NO_TOKEN = 0, /* for WPS tags we don't want to save as tokens */
32 WPS_TOKEN_UNKNOWN,
33
34 /* Markers */
35 WPS_TOKEN_CHARACTER,
36 WPS_TOKEN_STRING,
37 WPS_TOKEN_TRANSLATEDSTRING,
38
39 /* Alignment */
40 WPS_TOKEN_ALIGN_LEFT,
41 WPS_TOKEN_ALIGN_LEFT_RTL,
42 WPS_TOKEN_ALIGN_CENTER,
43 WPS_TOKEN_ALIGN_RIGHT,
44 WPS_TOKEN_ALIGN_RIGHT_RTL,
45
46 /* Sublines */
47 WPS_TOKEN_SUBLINE_TIMEOUT,
48
49 /* Conditional */
50 WPS_TOKEN_CONDITIONAL,
51 WPS_TOKEN_CONDITIONAL_START,
52 WPS_TOKEN_CONDITIONAL_OPTION,
53 WPS_TOKEN_CONDITIONAL_END,
54
55 /* Viewport display */
56 WPS_VIEWPORT_ENABLE,
57 WPS_VIEWPORT_CUSTOMLIST,
58 WPS_TOKEN_UIVIEWPORT_ENABLE,
59 WPS_TOKEN_VIEWPORT_FGCOLOUR,
60 WPS_TOKEN_VIEWPORT_BGCOLOUR,
61
62 /* Battery */
63 TOKEN_MARKER_BATTERY,
64 WPS_TOKEN_BATTERY_PERCENT,
65 WPS_TOKEN_BATTERY_PERCENTBAR,
66 WPS_TOKEN_BATTERY_VOLTS,
67 WPS_TOKEN_BATTERY_TIME,
68 WPS_TOKEN_BATTERY_CHARGER_CONNECTED,
69 WPS_TOKEN_BATTERY_CHARGING,
70 WPS_TOKEN_BATTERY_SLEEPTIME,
71 WPS_TOKEN_USB_POWERED,
72
73 /* Sound */
74 TOKEN_MARKER_SOUND,
75#if (CONFIG_CODEC != MAS3507D)
76 WPS_TOKEN_SOUND_PITCH,
77#endif
78#if (CONFIG_CODEC == SWCODEC)
79 WPS_TOKEN_SOUND_SPEED,
80 WPS_TOKEN_REPLAYGAIN,
81 WPS_TOKEN_CROSSFADE,
82#endif
83
84 /* Time */
85 TOKEN_MARKER_RTC,
86 WPS_TOKEN_RTC_PRESENT,
87
88 /* The begin/end values allow us to know if a token is an RTC one.
89 New RTC tokens should be added between the markers. */
90
91 WPS_TOKENS_RTC_BEGIN, /* just the start marker, not an actual token */
92
93 WPS_TOKEN_RTC_DAY_OF_MONTH,
94 WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,
95 WPS_TOKEN_RTC_12HOUR_CFG,
96 WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED,
97 WPS_TOKEN_RTC_HOUR_24,
98 WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED,
99 WPS_TOKEN_RTC_HOUR_12,
100 WPS_TOKEN_RTC_MONTH,
101 WPS_TOKEN_RTC_MINUTE,
102 WPS_TOKEN_RTC_SECOND,
103 WPS_TOKEN_RTC_YEAR_2_DIGITS,
104 WPS_TOKEN_RTC_YEAR_4_DIGITS,
105 WPS_TOKEN_RTC_AM_PM_UPPER,
106 WPS_TOKEN_RTC_AM_PM_LOWER,
107 WPS_TOKEN_RTC_WEEKDAY_NAME,
108 WPS_TOKEN_RTC_MONTH_NAME,
109 WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON,
110 WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN,
111
112 WPS_TOKENS_RTC_END, /* just the end marker, not an actual token */
113
114 /* Database */
115 TOKEN_MARKER_DATABASE,
116#ifdef HAVE_TAGCACHE
117 WPS_TOKEN_DATABASE_PLAYCOUNT,
118 WPS_TOKEN_DATABASE_RATING,
119 WPS_TOKEN_DATABASE_AUTOSCORE,
120#endif
121
122 /* File */
123 TOKEN_MARKER_FILE,
124 WPS_TOKEN_FILE_BITRATE,
125 WPS_TOKEN_FILE_CODEC,
126 WPS_TOKEN_FILE_FREQUENCY,
127 WPS_TOKEN_FILE_FREQUENCY_KHZ,
128 WPS_TOKEN_FILE_NAME,
129 WPS_TOKEN_FILE_NAME_WITH_EXTENSION,
130 WPS_TOKEN_FILE_PATH,
131 WPS_TOKEN_FILE_SIZE,
132 WPS_TOKEN_FILE_VBR,
133 WPS_TOKEN_FILE_DIRECTORY,
134
135 /* Image */
136 TOKEN_MARKER_IMAGES,
137#ifdef HAVE_LCD_BITMAP
138 WPS_TOKEN_IMAGE_BACKDROP,
139 WPS_TOKEN_IMAGE_PROGRESS_BAR,
140 WPS_TOKEN_IMAGE_PRELOAD,
141 WPS_TOKEN_IMAGE_PRELOAD_DISPLAY,
142 WPS_TOKEN_IMAGE_DISPLAY,
143#endif
144
145#ifdef HAVE_ALBUMART
146 /* Albumart */
147 WPS_TOKEN_ALBUMART_DISPLAY,
148 WPS_TOKEN_ALBUMART_FOUND,
149#endif
150
151 /* Metadata */
152 TOKEN_MARKER_METADATA,
153 WPS_TOKEN_METADATA_ARTIST,
154 WPS_TOKEN_METADATA_COMPOSER,
155 WPS_TOKEN_METADATA_ALBUM_ARTIST,
156 WPS_TOKEN_METADATA_GROUPING,
157 WPS_TOKEN_METADATA_ALBUM,
158 WPS_TOKEN_METADATA_GENRE,
159 WPS_TOKEN_METADATA_DISC_NUMBER,
160 WPS_TOKEN_METADATA_TRACK_NUMBER,
161 WPS_TOKEN_METADATA_TRACK_TITLE,
162 WPS_TOKEN_METADATA_VERSION,
163 WPS_TOKEN_METADATA_YEAR,
164 WPS_TOKEN_METADATA_COMMENT,
165
166 TOKEN_MARKER_PLAYBACK_INFO,
167 /* Mode */
168 WPS_TOKEN_REPEAT_MODE,
169 WPS_TOKEN_PLAYBACK_STATUS,
170 /* Progressbar */
171 WPS_TOKEN_PROGRESSBAR,
172#ifdef HAVE_LCD_CHARCELLS
173 WPS_TOKEN_PLAYER_PROGRESSBAR,
174#endif
175#ifdef HAVE_LCD_BITMAP
176 /* Peakmeter */
177 WPS_TOKEN_PEAKMETER,
178#endif
179
180 /* Current track */
181 WPS_TOKEN_TRACK_ELAPSED_PERCENT,
182 WPS_TOKEN_TRACK_TIME_ELAPSED,
183 WPS_TOKEN_TRACK_TIME_REMAINING,
184 WPS_TOKEN_TRACK_LENGTH,
185 WPS_TOKEN_TRACK_STARTING,
186 WPS_TOKEN_TRACK_ENDING,
187
188 /* Playlist */
189 TOKEN_MARKER_PLAYLIST,
190 WPS_TOKEN_PLAYLIST_ENTRIES,
191 WPS_TOKEN_PLAYLIST_NAME,
192 WPS_TOKEN_PLAYLIST_POSITION,
193 WPS_TOKEN_PLAYLIST_SHUFFLE,
194
195
196 /* buttons */
197 TOKEN_MARKER_MISC,
198 WPS_TOKEN_DRAW_INBUILTBAR,
199 WPS_TOKEN_LIST_TITLE_TEXT,
200 WPS_TOKEN_LIST_TITLE_ICON,
201 WPS_TOKEN_BUTTON_VOLUME,
202 WPS_TOKEN_LASTTOUCH,
203#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
204 /* Virtual LED */
205 WPS_TOKEN_VLED_HDD,
206#endif
207 /* Volume level */
208 WPS_TOKEN_VOLUME,
209 WPS_TOKEN_VOLUMEBAR,
210 /* hold */
211 WPS_TOKEN_MAIN_HOLD,
212#ifdef HAS_REMOTE_BUTTON_HOLD
213 WPS_TOKEN_REMOTE_HOLD,
214#endif
215
216 /* Setting option */
217 WPS_TOKEN_SETTING,
218 WPS_TOKEN_CURRENT_SCREEN,
219 WPS_TOKEN_LANG_IS_RTL,
220
221 /* Recording Tokens */
222 TOKEN_MARKER_RECORDING,
223 WPS_TOKEN_HAVE_RECORDING,
224 WPS_TOKEN_IS_RECORDING,
225 WPS_TOKEN_REC_FREQ,
226 WPS_TOKEN_REC_ENCODER,
227 WPS_TOKEN_REC_BITRATE, /* SWCODEC: MP3 bitrate, HWCODEC: MP3 "quality" */
228 WPS_TOKEN_REC_MONO,
229 WPS_TOKEN_REC_SECONDS,
230 WPS_TOKEN_REC_MINUTES,
231 WPS_TOKEN_REC_HOURS,
232
233
234 /* Radio Tokens */
235 TOKEN_MARKER_TUNER,
236 WPS_TOKEN_HAVE_TUNER,
237#if CONFIG_TUNER
238 WPS_TOKEN_TUNER_TUNED,
239 WPS_TOKEN_TUNER_SCANMODE,
240 WPS_TOKEN_TUNER_STEREO,
241 WPS_TOKEN_TUNER_MINFREQ, /* changes based on "region" */
242 WPS_TOKEN_TUNER_MAXFREQ, /* changes based on "region" */
243 WPS_TOKEN_TUNER_CURFREQ,
244 WPS_TOKEN_PRESET_ID, /* "id" of this preset.. really the array element number */
245 WPS_TOKEN_PRESET_NAME,
246 WPS_TOKEN_PRESET_FREQ,
247 WPS_TOKEN_PRESET_COUNT,
248 /* RDS tokens */
249 WPS_TOKEN_HAVE_RDS,
250#ifdef HAVE_RDS_CAP
251 WPS_TOKEN_RDS_NAME,
252 WPS_TOKEN_RDS_TEXT,
253#endif
254#endif /* CONFIG_TUNER */
255
256
257 TOKEN_MARKER_END, /* this needs to be the last value in this enum */
258};
259 27
260struct wps_token { 28struct wps_token {
261 unsigned char type; /* enough to store the token type */ 29 enum skin_token_type type; /* enough to store the token type */
262 30
263 /* Whether the tag (e.g. track name or the album) refers the 31 /* Whether the tag (e.g. track name or the album) refers the
264 current or the next song (false=current, true=next) */ 32 current or the next song (false=current, true=next) */
265 bool next; 33 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 @@
26 26
27#include <stdio.h> 27#include <stdio.h>
28#include <string.h> 28#include <string.h>
29#include "skin_buffer.h"
30#include "settings_list.h" 29#include "settings_list.h"
31#ifdef __PCTOOL__ 30#ifdef __PCTOOL__
32#ifdef WPSEDITOR 31#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 @@
24 24
25#ifndef _WPS_ENGINE_INTERNALS_ 25#ifndef _WPS_ENGINE_INTERNALS_
26#define _WPS_ENGINE_INTERNALS_ 26#define _WPS_ENGINE_INTERNALS_
27
28
27/* Timeout unit expressed in HZ. In WPS, all timeouts are given in seconds 29/* Timeout unit expressed in HZ. In WPS, all timeouts are given in seconds
28 (possibly with a decimal fraction) but stored as integer values. 30 (possibly with a decimal fraction) but stored as integer values.
29 E.g. 2.5 is stored as 25. This means 25 tenth of a second, i.e. 25 units. 31 E.g. 2.5 is stored as 25. This means 25 tenth of a second, i.e. 25 units.
@@ -32,6 +34,8 @@
32#define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* In TIMEOUT_UNIT's */ 34#define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* In TIMEOUT_UNIT's */
33 35
34#include "skin_tokens.h" 36#include "skin_tokens.h"
37#include "tag_table.h"
38#include "skin_parser.h"
35 39
36 40
37/* TODO: sort this mess out */ 41/* TODO: sort this mess out */
@@ -40,19 +44,6 @@
40#include "statusbar.h" 44#include "statusbar.h"
41#include "metadata.h" 45#include "metadata.h"
42 46
43/* constants used in line_type and as refresh_mode for wps_refresh */
44#define WPS_REFRESH_STATIC (1u<<0) /* line doesn't change over time */
45#define WPS_REFRESH_DYNAMIC (1u<<1) /* line may change (e.g. time flag) */
46#define WPS_REFRESH_SCROLL (1u<<2) /* line scrolls */
47#define WPS_REFRESH_PLAYER_PROGRESS (1u<<3) /* line contains a progress bar */
48#define WPS_REFRESH_PEAK_METER (1u<<4) /* line contains a peak meter */
49#define WPS_REFRESH_STATUSBAR (1u<<5) /* refresh statusbar */
50#define WPS_REFRESH_ALL (0xffffffffu) /* to refresh all line types */
51
52/* to refresh only those lines that change over time */
53#define WPS_REFRESH_NON_STATIC (WPS_REFRESH_DYNAMIC| \
54 WPS_REFRESH_PLAYER_PROGRESS| \
55 WPS_REFRESH_PEAK_METER)
56/* alignments */ 47/* alignments */
57#define WPS_ALIGN_RIGHT 32 48#define WPS_ALIGN_RIGHT 32
58#define WPS_ALIGN_CENTER 64 49#define WPS_ALIGN_CENTER 64
@@ -82,16 +73,16 @@ struct gui_img {
82 short int y; /* y-pos */ 73 short int y; /* y-pos */
83 short int num_subimages; /* number of sub-images */ 74 short int num_subimages; /* number of sub-images */
84 short int subimage_height; /* height of each sub-image */ 75 short int subimage_height; /* height of each sub-image */
85 short int display; /* -1 for no display, 0..n to display a subimage */
86 struct bitmap bm; 76 struct bitmap bm;
87 char label; 77 char label;
88 bool loaded; /* load state */ 78 bool loaded; /* load state */
89 bool always_display; /* not using the preload/display mechanism */ 79 bool always_display; /* not using the preload/display mechanism */
80 int display;
90}; 81};
91 82
92 83
93struct progressbar { 84struct progressbar {
94 enum wps_token_type type; 85 enum skin_token_type type;
95 struct viewport *vp; 86 struct viewport *vp;
96 /* regular pb */ 87 /* regular pb */
97 short x; 88 short x;
@@ -105,8 +96,6 @@ struct progressbar {
105 /*progressbar image*/ 96 /*progressbar image*/
106 struct bitmap bm; 97 struct bitmap bm;
107 bool have_bitmap_pb; 98 bool have_bitmap_pb;
108
109 bool draw;
110}; 99};
111#endif 100#endif
112 101
@@ -157,45 +146,6 @@ enum wps_parse_error {
157 PARSE_FAIL_LIMITS_EXCEEDED, 146 PARSE_FAIL_LIMITS_EXCEEDED,
158}; 147};
159 148
160
161/* Description of a subline on the WPS */
162struct skin_subline {
163
164 /* Index of the first token for this subline in the token array.
165 Tokens of this subline end where tokens for the next subline
166 begin. */
167 unsigned short first_token_idx;
168 unsigned short last_token_idx;
169
170 /* Bit or'ed WPS_REFRESH_xxx */
171 unsigned char line_type;
172
173 /* How long the subline should be displayed, in 10ths of sec */
174 unsigned char time_mult;
175
176 /* pointer to the next subline in this line */
177 struct skin_subline *next;
178};
179
180/* Description of a line on the WPS. A line is a set of sublines.
181 A subline is displayed for a certain amount of time. After that,
182 the next subline of the line is displayed. And so on. */
183struct skin_line {
184
185 /* Linked list of all the sublines on this line,
186 * a line *must* have at least one subline so no need to add an extra pointer */
187 struct skin_subline sublines;
188 /* pointer to the current subline */
189 struct skin_subline *curr_subline;
190
191 /* When the next subline of this line should be displayed
192 (absolute time value in ticks) */
193 long subline_expire_time;
194
195 /* pointer to the next line */
196 struct skin_line *next;
197};
198
199#define VP_DRAW_HIDEABLE 0x1 149#define VP_DRAW_HIDEABLE 0x1
200#define VP_DRAW_HIDDEN 0x2 150#define VP_DRAW_HIDDEN 0x2
201#define VP_DRAW_WASHIDDEN 0x4 151#define VP_DRAW_WASHIDDEN 0x4
@@ -206,7 +156,6 @@ struct skin_line {
206#define VP_INFO_LABEL 0x80 156#define VP_INFO_LABEL 0x80
207struct skin_viewport { 157struct skin_viewport {
208 struct viewport vp; /* The LCD viewport struct */ 158 struct viewport vp; /* The LCD viewport struct */
209 struct skin_line *lines;
210 char hidden_flags; 159 char hidden_flags;
211 char label; 160 char label;
212 unsigned start_fgcolour; 161 unsigned start_fgcolour;
@@ -236,9 +185,6 @@ struct touchregion {
236}; 185};
237#endif 186#endif
238 187
239#define MAX_PLAYLISTLINE_TOKENS 16
240#define MAX_PLAYLISTLINE_STRINGS 8
241#define MAX_PLAYLISTLINE_STRLEN 8
242enum info_line_type { 188enum info_line_type {
243 TRACK_HAS_INFO = 0, 189 TRACK_HAS_INFO = 0,
244 TRACK_HAS_NO_INFO 190 TRACK_HAS_NO_INFO
@@ -250,36 +196,50 @@ struct playlistviewer {
250#ifdef HAVE_TC_RAMCACHE 196#ifdef HAVE_TC_RAMCACHE
251 struct mp3entry tempid3; 197 struct mp3entry tempid3;
252#endif 198#endif
253 struct { 199 struct skin_element *lines[2];
254 enum wps_token_type tokens[MAX_PLAYLISTLINE_TOKENS];
255 char strings[MAX_PLAYLISTLINE_STRINGS][MAX_PLAYLISTLINE_STRLEN];
256 int count;
257 bool scroll;
258 } lines[2];
259}; 200};
260 201
261 202
262#ifdef HAVE_ALBUMART 203#ifdef HAVE_ALBUMART
263struct skin_albumart { 204struct skin_albumart {
264 /* Album art support */ 205 /* Album art support */
265 struct viewport *vp;/* The viewport this is in */
266 int x; 206 int x;
267 int y; 207 int y;
268 int width; 208 int width;
269 int height; 209 int height;
270 210
271 bool draw;
272 unsigned char xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT */ 211 unsigned char xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT */
273 unsigned char yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */ 212 unsigned char yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */
274 unsigned char state; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */ 213 unsigned char state; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */
214
215 struct viewport *vp;
216 int draw_handle;
275}; 217};
276#endif 218#endif
277 219
220
221struct line {
222 int timeout; /* if inside a line alternator */
223 unsigned update_mode;
224};
225
226struct line_alternator {
227 int current_line;
228 unsigned long last_change_tick;
229};
230
231struct conditional {
232 int last_value;
233 struct wps_token *token;
234};
235
236
278/* wps_data 237/* wps_data
279 this struct holds all necessary data which describes the 238 this struct holds all necessary data which describes the
280 viewable content of a wps */ 239 viewable content of a wps */
281struct wps_data 240struct wps_data
282{ 241{
242 struct skin_element *tree;
283#ifdef HAVE_LCD_BITMAP 243#ifdef HAVE_LCD_BITMAP
284 struct skin_token_list *images; 244 struct skin_token_list *images;
285 struct skin_token_list *progressbars; 245 struct skin_token_list *progressbars;
@@ -291,16 +251,10 @@ struct wps_data
291#ifdef HAVE_TOUCHSCREEN 251#ifdef HAVE_TOUCHSCREEN
292 struct skin_token_list *touchregions; 252 struct skin_token_list *touchregions;
293#endif 253#endif
294 struct skin_token_list *viewports;
295 struct skin_token_list *strings;
296#ifdef HAVE_ALBUMART 254#ifdef HAVE_ALBUMART
297 struct skin_albumart *albumart; 255 struct skin_albumart *albumart;
298 int playback_aa_slot; 256 int playback_aa_slot;
299#endif 257#endif
300 struct wps_token *tokens;
301 /* Total number of tokens in the WPS. During WPS parsing, this is
302 the index of the token being parsed. */
303 int num_tokens;
304 258
305#ifdef HAVE_LCD_BITMAP 259#ifdef HAVE_LCD_BITMAP
306 bool peak_meter_enabled; 260 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 @@
27#include "appevents.h" 27#include "appevents.h"
28#include "screens.h" 28#include "screens.h"
29#include "screen_access.h" 29#include "screen_access.h"
30#include "strlcpy.h"
31#include "skin_parser.h"
32#include "skin_buffer.h"
30#include "skin_engine/skin_engine.h" 33#include "skin_engine/skin_engine.h"
31#include "skin_engine/wps_internals.h" 34#include "skin_engine/wps_internals.h"
32#include "viewport.h" 35#include "viewport.h"
@@ -45,26 +48,55 @@ static struct wps_sync_data sb_skin_sync_data = { .do_full_update = false
45 48
46/* initial setup of wps_data */ 49/* initial setup of wps_data */
47static int update_delay = DEFAULT_UPDATE_DELAY; 50static int update_delay = DEFAULT_UPDATE_DELAY;
48 51struct wps_token *found_token;
49bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen) 52static int set_title_worker(char* title, enum themable_icons icon,
53 struct wps_data *data, struct skin_element *root)
50{ 54{
51 int i; 55 int retval = 0;
52 bool retval = false; 56 struct skin_element *element = root;
53 for(i=0; i<sb_skin_data[screen].num_tokens; i++) 57 while (element)
54 { 58 {
55 if (sb_skin_data[screen].tokens[i].type == WPS_TOKEN_LIST_TITLE_TEXT) 59 struct wps_token *token = NULL;
60 if (element->type == CONDITIONAL)
61 {
62 struct conditional *cond = (struct conditional *)element->data;
63 token = cond->token;
64 }
65 else if (element->type == TAG)
66 {
67 token = (struct wps_token *)element->data;
68 }
69 if (token)
56 { 70 {
57 sb_skin_data[screen].tokens[i].value.data = title; 71 if (token->type == SKIN_TOKEN_LIST_TITLE_TEXT)
58 retval = true; 72 {
73 found_token = token;
74 token->value.data = title;
75 retval = 1;
76 }
77 else if (token->type == SKIN_TOKEN_LIST_TITLE_ICON)
78 {
79 /* Icon_NOICON == -1 which the skin engine wants at position 1, so + 2 */
80 token->value.i = icon+2;
81 }
59 } 82 }
60 else if (sb_skin_data[screen].tokens[i].type == WPS_TOKEN_LIST_TITLE_ICON) 83 if (element->children_count)
61 { 84 {
62 /* Icon_NOICON == -1 which the skin engine wants at position 1, so + 2 */ 85 int i;
63 sb_skin_data[screen].tokens[i].value.i = icon+2; 86 for (i=0; i<element->children_count; i++)
87 retval |= set_title_worker(title, icon, data, element->children[i]);
64 } 88 }
89 element = element->next;
65 } 90 }
66 return retval; 91 return retval;
67} 92}
93
94bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen)
95{
96 bool retval = set_title_worker(title, icon, &sb_skin_data[screen],
97 sb_skin_data[screen].tree) > 0;
98 return retval;
99}
68 100
69 101
70void sb_skin_data_load(enum screen_type screen, const char *buf, bool isfile) 102void 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)
75 success = buf && skin_data_load(screen, data, buf, isfile); 107 success = buf && skin_data_load(screen, data, buf, isfile);
76 108
77 if (success) 109 if (success)
78 { /* hide the sb's default viewport because it has nasty effect with stuff 110 {
111 /* hide the sb's default viewport because it has nasty effect with stuff
79 * not part of the statusbar, 112 * not part of the statusbar,
80 * hence .sbs's without any other vps are unsupported*/ 113 * hence .sbs's without any other vps are unsupported*/
81 struct skin_viewport *vp = find_viewport(VP_DEFAULT_LABEL, data); 114 struct skin_viewport *vp = find_viewport(VP_DEFAULT_LABEL, data);
82 struct skin_token_list *next_vp = data->viewports->next; 115 struct skin_element *next_vp = data->tree->next;
83 116
84 if (!next_vp) 117 if (vp)
85 { /* no second viewport, let parsing fail */ 118 {
86 success = false; 119 if (!next_vp)
120 { /* no second viewport, let parsing fail */
121 success = false;
122 }
123 /* hide this viewport, forever */
124 vp->hidden_flags = VP_NEVER_VISIBLE;
87 } 125 }
88 /* hide this viewport, forever */
89 vp->hidden_flags = VP_NEVER_VISIBLE;
90 sb_set_info_vp(screen, VP_INFO_LABEL|VP_DEFAULT_LABEL); 126 sb_set_info_vp(screen, VP_INFO_LABEL|VP_DEFAULT_LABEL);
91 } 127 }
92 128
@@ -135,7 +171,7 @@ bool sb_set_backdrop(enum screen_type screen, char* filename)
135 else 171 else
136#endif 172#endif
137 buf_size = LCD_BACKDROP_BYTES; 173 buf_size = LCD_BACKDROP_BYTES;
138 sb_skin[screen].data->backdrop = skin_buffer_alloc(buf_size); 174 sb_skin[screen].data->backdrop = (char*)skin_buffer_alloc(buf_size);
139 if (!sb_skin[screen].data->backdrop) 175 if (!sb_skin[screen].data->backdrop)
140 return false; 176 return false;
141 } 177 }
@@ -150,6 +186,8 @@ void sb_skin_update(enum screen_type screen, bool force)
150{ 186{
151 static long next_update[NB_SCREENS] = {0}; 187 static long next_update[NB_SCREENS] = {0};
152 int i = screen; 188 int i = screen;
189 if (!sb_skin_data[screen].wps_loaded)
190 return;
153 if (TIME_AFTER(current_tick, next_update[i]) || force) 191 if (TIME_AFTER(current_tick, next_update[i]) || force)
154 { 192 {
155#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) 193#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
@@ -158,7 +196,7 @@ void sb_skin_update(enum screen_type screen, bool force)
158 if (lcd_active() || (i != SCREEN_MAIN)) 196 if (lcd_active() || (i != SCREEN_MAIN))
159#endif 197#endif
160 skin_update(&sb_skin[i], force? 198 skin_update(&sb_skin[i], force?
161 WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); 199 SKIN_REFRESH_ALL : SKIN_REFRESH_NON_STATIC);
162 next_update[i] = current_tick + update_delay; /* don't update too often */ 200 next_update[i] = current_tick + update_delay; /* don't update too often */
163 sb_skin[SCREEN_MAIN].sync_data->do_full_update = false; 201 sb_skin[SCREEN_MAIN].sync_data->do_full_update = false;
164 } 202 }
@@ -216,7 +254,30 @@ void sb_create_from_settings(enum screen_type screen)
216 254
217 if (ptr2[0] && ptr2[0] != '-') /* from ui viewport setting */ 255 if (ptr2[0] && ptr2[0] != '-') /* from ui viewport setting */
218 { 256 {
257 char *comma = ptr;
258 int param_count = 0;
219 len = snprintf(ptr, remaining, "%%ax%%Vi(-,%s)\n", ptr2); 259 len = snprintf(ptr, remaining, "%%ax%%Vi(-,%s)\n", ptr2);
260 /* The config put the colours at the end of the viewport,
261 * they need to be stripped for the skin code though */
262 do {
263 param_count++;
264 comma = strchr(comma+1, ',');
265
266 } while (comma && param_count < 6);
267 if (comma)
268 {
269 char *end = comma;
270 char fg[8], bg[8];
271 int i = 0;
272 comma++;
273 while (*comma != ',')
274 fg[i++] = *comma++;
275 fg[i] = '\0'; comma++; i=0;
276 while (*comma != ')')
277 bg[i++] = *comma++;
278 bg[i] = '\0';
279 len += snprintf(end, remaining-len, ") %%Vf(%s) %%Vb(%s)\n", fg, bg);
280 }
220 } 281 }
221 else 282 else
222 { 283 {
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 @@
30#include "settings.h" 30#include "settings.h"
31#include "wps.h" 31#include "wps.h"
32#include "file.h" 32#include "file.h"
33#include "buffer.h"
33#if CONFIG_TUNER 34#if CONFIG_TUNER
34#include "radio.h" 35#include "radio.h"
35#endif 36#endif
36#include "skin_engine/skin_engine.h" 37#include "skin_engine/skin_engine.h"
37#include "skin_engine/skin_fonts.h" 38#include "skin_buffer.h"
38#include "statusbar-skinned.h" 39#include "statusbar-skinned.h"
39#include "bootchart.h" 40#include "bootchart.h"
40 41
42static char *skin_buffer = NULL;
43void theme_init_buffer(void)
44{
45 skin_buffer = buffer_alloc(SKIN_BUFFER_SIZE);
46}
47
41 48
42/* call this after loading a .wps/.rwps or other skin files, so that the 49/* call this after loading a .wps/.rwps or other skin files, so that the
43 * skin buffer is reset properly 50 * skin buffer is reset properly
@@ -71,9 +78,10 @@ void settings_apply_skins(void)
71{ 78{
72 char buf[MAX_PATH]; 79 char buf[MAX_PATH];
73 /* re-initialize the skin buffer before we start reloading skins */ 80 /* re-initialize the skin buffer before we start reloading skins */
74 skin_buffer_init();
75 enum screen_type screen = SCREEN_MAIN; 81 enum screen_type screen = SCREEN_MAIN;
76 unsigned int i; 82 unsigned int i;
83
84 skin_buffer_init(skin_buffer, SKIN_BUFFER_SIZE);
77#ifdef HAVE_LCD_BITMAP 85#ifdef HAVE_LCD_BITMAP
78 skin_backdrop_init(); 86 skin_backdrop_init();
79 skin_font_init(); 87 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)
310#endif /* HAVE_LCD_BITMAP */ 310#endif /* HAVE_LCD_BITMAP */
311#endif /* __PCTOOL__ */ 311#endif /* __PCTOOL__ */
312 312
313#ifdef HAVE_LCD_COLOR
314#define ARG_STRING(_depth) ((_depth) == 2 ? "dddddgg":"dddddcc")
315#else
316#define ARG_STRING(_depth) "dddddgg"
317#endif
318
319
320void viewport_set_fullscreen(struct viewport *vp, 313void viewport_set_fullscreen(struct viewport *vp,
321 const enum screen_type screen) 314 const enum screen_type screen)
322{ 315{
@@ -416,81 +409,4 @@ int get_viewport_default_colour(enum screen_type screen, bool fgcolour)
416#endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */ 409#endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */
417} 410}
418 411
419const char* viewport_parse_viewport(struct viewport *vp,
420 enum screen_type screen,
421 const char *bufptr,
422 const char separator)
423{
424 /* parse the list to the viewport struct */
425 const char *ptr = bufptr;
426 uint32_t set = 0;
427
428 enum {
429 PL_X = 0,
430 PL_Y,
431 PL_WIDTH,
432 PL_HEIGHT,
433 PL_FONT,
434 };
435
436 if (!(ptr = parse_list("ddddd", &set, separator, ptr,
437 &vp->x, &vp->y, &vp->width, &vp->height, &vp->font)))
438 return NULL;
439
440 /* X and Y *must* be set */
441 if (!LIST_VALUE_PARSED(set, PL_X) || !LIST_VALUE_PARSED(set, PL_Y))
442 return NULL;
443 /* check for negative values */
444 if (vp->x < 0)
445 vp->x += screens[screen].lcdwidth;
446 if (vp->y < 0)
447 vp->y += screens[screen].lcdheight;
448
449 /* fix defaults,
450 * and negative width/height which means "extend to edge minus value */
451 if (!LIST_VALUE_PARSED(set, PL_WIDTH))
452 vp->width = screens[screen].lcdwidth - vp->x;
453 else if (vp->width < 0)
454 vp->width = (vp->width + screens[screen].lcdwidth) - vp->x;
455 if (!LIST_VALUE_PARSED(set, PL_HEIGHT))
456 vp->height = screens[screen].lcdheight - vp->y;
457 else if (vp->height < 0)
458 vp->height = (vp->height + screens[screen].lcdheight) - vp->y;
459
460#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
461 vp->fg_pattern = get_viewport_default_colour(screen, true);
462 vp->bg_pattern = get_viewport_default_colour(screen, false);
463#endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */
464
465#ifdef HAVE_LCD_COLOR
466 vp->lss_pattern = global_settings.lss_color;
467 vp->lse_pattern = global_settings.lse_color;
468 vp->lst_pattern = global_settings.lst_color;
469#endif
470
471 /* Validate the viewport dimensions - we know that the numbers are
472 non-negative integers, ignore bars and assume the viewport takes them
473 * into account */
474 if ((vp->x >= screens[screen].lcdwidth) ||
475 ((vp->x + vp->width) > screens[screen].lcdwidth) ||
476 (vp->y >= screens[screen].lcdheight) ||
477 ((vp->y + vp->height) > screens[screen].lcdheight))
478 {
479 return NULL;
480 }
481
482 /* Default to using the user font if the font was an invalid number or '-'
483 * font 1 is *always* the UI font for the current screen
484 * 2 is always the first extra font */
485 if (!LIST_VALUE_PARSED(set, PL_FONT))
486 vp->font = FONT_UI;
487
488 /* Set the defaults for fields not user-specified */
489 vp->drawmode = DRMODE_SOLID;
490#ifndef __PCTOOL__
491 set_default_align_flags(vp);
492#endif
493
494 return ptr;
495}
496#endif 412#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,
74 74
75#endif /* __PCTOOL__ */ 75#endif /* __PCTOOL__ */
76 76
77#ifdef HAVE_LCD_BITMAP
78
79/*
80 * Parse a viewport definition (vp_def), which looks like:
81 *
82 * Screens with depth > 1:
83 * X|Y|width|height|font|foregorund color|background color
84 * Screens with depth = 1:
85 * X|Y|width|height|font
86 *
87 * | is a separator and can be specified via the parameter
88 *
89 * Returns the pointer to the char after the last character parsed
90 * if everything went OK or NULL if an error happened (some values
91 * not specified in the definition)
92 */
93const char* viewport_parse_viewport(struct viewport *vp,
94 enum screen_type screen,
95 const char *vp_def,
96 const char separator);
97#endif /* HAVE_LCD_BITMAP */
98#endif /* __VIEWPORT_H__ */ 77#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)
175 if (updatewps) 175 if (updatewps)
176 { 176 {
177 FOR_NB_SCREENS(i) 177 FOR_NB_SCREENS(i)
178 skin_update(&gui_wps[i], WPS_REFRESH_NON_STATIC); 178 skin_update(&gui_wps[i], SKIN_REFRESH_NON_STATIC);
179 } 179 }
180 sleep(1); 180 sleep(1);
181 } 181 }
@@ -191,7 +191,7 @@ void fade(bool fade_in, bool updatewps)
191 if (updatewps) 191 if (updatewps)
192 { 192 {
193 FOR_NB_SCREENS(i) 193 FOR_NB_SCREENS(i)
194 skin_update(&gui_wps[i], WPS_REFRESH_NON_STATIC); 194 skin_update(&gui_wps[i], SKIN_REFRESH_NON_STATIC);
195 } 195 }
196 sleep(1); 196 sleep(1);
197 } 197 }
@@ -212,7 +212,7 @@ void fade(bool fade_in, bool updatewps)
212 212
213static bool update_onvol_change(struct gui_wps * gwps) 213static bool update_onvol_change(struct gui_wps * gwps)
214{ 214{
215 skin_update(gwps, WPS_REFRESH_NON_STATIC); 215 skin_update(gwps, SKIN_REFRESH_NON_STATIC);
216 216
217#ifdef HAVE_LCD_CHARCELLS 217#ifdef HAVE_LCD_CHARCELLS
218 splashf(0, "Vol: %3d dB", 218 splashf(0, "Vol: %3d dB",
@@ -372,8 +372,8 @@ bool ffwd_rew(int button)
372 FOR_NB_SCREENS(i) 372 FOR_NB_SCREENS(i)
373 { 373 {
374 skin_update(&gui_wps[i], 374 skin_update(&gui_wps[i],
375 WPS_REFRESH_PLAYER_PROGRESS | 375 SKIN_REFRESH_PLAYER_PROGRESS |
376 WPS_REFRESH_DYNAMIC); 376 SKIN_REFRESH_DYNAMIC);
377 } 377 }
378 378
379 break; 379 break;
@@ -390,7 +390,7 @@ bool ffwd_rew(int button)
390#endif 390#endif
391#ifdef HAVE_LCD_CHARCELLS 391#ifdef HAVE_LCD_CHARCELLS
392 FOR_NB_SCREENS(i) 392 FOR_NB_SCREENS(i)
393 skin_update(&gui_wps[i], WPS_REFRESH_ALL); 393 skin_update(&gui_wps[i], SKIN_REFRESH_ALL);
394#endif 394#endif
395 exit = true; 395 exit = true;
396 break; 396 break;
@@ -662,7 +662,7 @@ static void gwps_enter_wps(void)
662 display->backdrop_show(gwps->data->backdrop); 662 display->backdrop_show(gwps->data->backdrop);
663#endif 663#endif
664 display->clear_display(); 664 display->clear_display();
665 skin_update(gwps, WPS_REFRESH_ALL); 665 skin_update(gwps, SKIN_REFRESH_ALL);
666 666
667#ifdef HAVE_TOUCHSCREEN 667#ifdef HAVE_TOUCHSCREEN
668 skin_disarm_touchregions(gui_wps[i].data); 668 skin_disarm_touchregions(gui_wps[i].data);
@@ -1116,7 +1116,7 @@ long gui_wps_show(void)
1116#endif 1116#endif
1117 { 1117 {
1118 skin_update(&gui_wps[i], wps_sync_data.do_full_update ? 1118 skin_update(&gui_wps[i], wps_sync_data.do_full_update ?
1119 WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); 1119 SKIN_REFRESH_ALL : SKIN_REFRESH_NON_STATIC);
1120 } 1120 }
1121 } 1121 }
1122 wps_sync_data.do_full_update = false; 1122 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)
357 tree_mem_init(); 357 tree_mem_init();
358 filetype_init(); 358 filetype_init();
359 playlist_init(); 359 playlist_init();
360 theme_init_buffer();
360 361
361#if CONFIG_CODEC != SWCODEC 362#if CONFIG_CODEC != SWCODEC
362 mp3_init( global_settings.volume, 363 mp3_init( global_settings.volume,
@@ -639,6 +640,7 @@ static void init(void)
639#if CONFIG_CODEC == SWCODEC 640#if CONFIG_CODEC == SWCODEC
640 tdspeed_init(); 641 tdspeed_init();
641#endif /* CONFIG_CODEC == SWCODEC */ 642#endif /* CONFIG_CODEC == SWCODEC */
643 theme_init_buffer();
642 644
643#if CONFIG_CODEC != SWCODEC 645#if CONFIG_CODEC != SWCODEC
644 /* No buffer allocation (see buffer.c) may take place after the call to 646 /* 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 @@
48#include "version.h" 48#include "version.h"
49#include "time.h" 49#include "time.h"
50#include "wps.h" 50#include "wps.h"
51#include "skin_engine/skin_buffer.h" 51#include "skin_buffer.h"
52 52
53static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG}; 53static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG};
54 54
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)
937#endif /* HAVE_LCD_COLOR */ 937#endif /* HAVE_LCD_COLOR */
938 938
939#ifdef HAVE_LCD_BITMAP 939#ifdef HAVE_LCD_BITMAP
940/* A simplified scanf - used (at time of writing) by wps parsing functions.
941
942 fmt - char array specifying the format of each list option. Valid values
943 are: d - int
944 s - string (sets pointer to string, without copying)
945 c - hex colour (RGB888 - e.g. ff00ff)
946 g - greyscale "colour" (0-3)
947 set_vals - if not NULL 1 is set in the bitplace if the item was read OK
948 0 if not read.
949 first item is LSB, (max 32 items! )
950 Stops parseing if an item is invalid unless the item == '-'
951 sep - list separator (e.g. ',' or '|')
952 str - string to parse, must be terminated by 0 or sep
953 ... - pointers to store the parsed values
954
955 return value - pointer to char after parsed data, 0 if there was an error.
956
957*/
958
959/* '0'-'3' are ASCII 0x30 to 0x33 */ 940/* '0'-'3' are ASCII 0x30 to 0x33 */
960#define is0123(x) (((x) & 0xfc) == 0x30) 941#define is0123(x) (((x) & 0xfc) == 0x30)
961 942
962const char* parse_list(const char *fmt, uint32_t *set_vals, 943bool parse_color(char *text, int *value)
963 const char sep, const char* str, ...)
964{ 944{
965 va_list ap; 945 (void)text; (void)value; /* silence warnings on mono bitmap */
966 const char* p = str, *f = fmt;
967 const char** s;
968 int* d;
969 bool set, is_negative;
970 int i=0;
971
972 va_start(ap, str);
973 if (set_vals)
974 *set_vals = 0;
975 while (*fmt)
976 {
977 /* Check for separator, if we're not at the start */
978 if (f != fmt)
979 {
980 if (*p != sep)
981 goto err;
982 p++;
983 }
984 set = false;
985 switch (*fmt++)
986 {
987 case 's': /* string - return a pointer to it (not a copy) */
988 s = va_arg(ap, const char **);
989
990 *s = p;
991 while (*p && *p != sep && *p != ')')
992 p++;
993 set = (s[0][0]!='-') && (s[0][1]!=sep && s[0][1]!=')') ;
994 break;
995
996 case 'd': /* int */
997 is_negative = false;
998 d = va_arg(ap, int*);
999
1000 if (*p == '-' && isdigit(*(p+1)))
1001 {
1002 is_negative = true;
1003 p++;
1004 }
1005 if (!isdigit(*p))
1006 {
1007 if (!set_vals || *p != '-')
1008 goto err;
1009 p++;
1010 }
1011 else
1012 {
1013 *d = *p++ - '0';
1014 while (isdigit(*p))
1015 *d = (*d * 10) + (*p++ - '0');
1016 set = true;
1017 if (is_negative)
1018 *d *= -1;
1019 }
1020
1021 break;
1022
1023#ifdef HAVE_LCD_COLOR 946#ifdef HAVE_LCD_COLOR
1024 case 'c': /* colour (rrggbb - e.g. f3c1a8) */ 947 if (hex_to_rgb(text, value) < 0)
1025 d = va_arg(ap, int*); 948 return false;
1026
1027 if (hex_to_rgb(p, d) < 0)
1028 {
1029 if (!set_vals || *p != '-')
1030 goto err;
1031 p++;
1032 }
1033 else
1034 {
1035 p += 6;
1036 set = true;
1037 }
1038
1039 break;
1040#endif 949#endif
1041 950
1042#if LCD_DEPTH == 2 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2) 951#if LCD_DEPTH == 2 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2)
1043 case 'g': /* greyscale colour (0-3) */ 952 if (!is0123(*text))
1044 d = va_arg(ap, int*); 953 return false;
1045 954 *value = *text - '0';
1046 if (!is0123(*p))
1047 {
1048 if (!set_vals || *p != '-')
1049 goto err;
1050 p++;
1051 }
1052 else
1053 {
1054 *d = *p++ - '0';
1055 set = true;
1056 }
1057
1058 break;
1059#endif 955#endif
1060 956 return true;
1061 default: /* Unknown format type */
1062 goto err;
1063 break;
1064 }
1065 if (set_vals && set)
1066 *set_vals |= BIT_N(i);
1067 i++;
1068 }
1069
1070 va_end(ap);
1071 return p;
1072
1073err:
1074 va_end(ap);
1075 return NULL;
1076} 957}
1077 958
1078/* only used in USB HID and set_time screen */ 959/* 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);
94char *strip_extension(char* buffer, int buffer_size, const char *filename); 94char *strip_extension(char* buffer, int buffer_size, const char *filename);
95 95
96#ifdef HAVE_LCD_BITMAP 96#ifdef HAVE_LCD_BITMAP
97/* A simplified scanf */ 97bool parse_color(char *text, int *value);
98/*
99 * Checks whether the value at position 'position' was really read
100 * during a call to 'parse_list'
101 * - position: 0-based number of the value
102 * - valid_vals: value after the call to 'parse_list'
103 */
104#define LIST_VALUE_PARSED(setvals, position) ((setvals) & BIT_N(position))
105const char* parse_list(const char *fmt, uint32_t *set_vals,
106 const char sep, const char* str, ...);
107 98
108/* only used in USB HID and set_time screen */ 99/* only used in USB HID and set_time screen */
109#if defined(USB_ENABLE_HID) || (CONFIG_RTC != 0) 100#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)
800 if (restore) 800 if (restore)
801 fms_fix_displays(FMS_ENTER); 801 fms_fix_displays(FMS_ENTER);
802 FOR_NB_SCREENS(i) 802 FOR_NB_SCREENS(i)
803 skin_update(fms_get(i), restore ? WPS_REFRESH_ALL : 803 skin_update(fms_get(i), restore ? SKIN_REFRESH_ALL :
804 WPS_REFRESH_NON_STATIC); 804 SKIN_REFRESH_NON_STATIC);
805 restore = false; 805 restore = false;
806 } 806 }
807 } 807 }
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 @@
35bool find_albumart(const struct mp3entry *id3, char *buf, int buflen, 35bool find_albumart(const struct mp3entry *id3, char *buf, int buflen,
36 struct dim *dim); 36 struct dim *dim);
37 37
38/* Draw the album art bitmap from the given handle ID onto the given WPS. 38#ifndef PLUGIN
39/* Draw the album art bitmap from the given handle ID onto the given Skin.
39 Call with clear = true to clear the bitmap instead of drawing it. */ 40 Call with clear = true to clear the bitmap instead of drawing it. */
40void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear); 41void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear);
42#endif
41 43
42bool search_albumart_files(const struct mp3entry *id3, const char *size_string, 44bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
43 char *buf, int buflen); 45 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);
260 * skin buffer is reset properly 260 * skin buffer is reset properly
261 */ 261 */
262void settings_apply_skins(void); 262void settings_apply_skins(void);
263void theme_init_buffer(void);
263 264
264void settings_apply(bool read_disk); 265void settings_apply(bool read_disk);
265void settings_apply_pm_range(void); 266void 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 @@
1skin_buffer.c 1skin_buffer.c
2skin_parser.c 2skin_parser.c
3#ifndef ROCKBOX 3#if !defined(ROCKBOX) || defined(__PCTOOL__)
4skin_debug.c 4skin_debug.c
5#endif 5#endif
6skin_scan.c 6skin_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 @@
24#include <string.h> 24#include <string.h>
25#include <stdlib.h> 25#include <stdlib.h>
26 26
27#include "skin_buffer.h"
28
27#ifdef ROCKBOX 29#ifdef ROCKBOX
28#define SKIN_BUFFER_SIZE (400*1024) /* Excessivly large for now */ 30static size_t buf_size;
29static unsigned char buffer[SKIN_BUFFER_SIZE]; 31static unsigned char *buffer_start = NULL;
30static unsigned char *buffer_front = NULL; /* start of the free space, 32static unsigned char *buffer_front = NULL;
31 increases with allocation*/
32#endif 33#endif
33 34
34void skin_buffer_init(void) 35void skin_buffer_init(char* buffer, size_t size)
35{ 36{
36#if defined(ROCKBOX) 37#if defined(ROCKBOX)
37 { 38 buffer_start = buffer_front = buffer;
38 /* reset the buffer.... */ 39 buf_size = size;
39 buffer_front = buffer;
40 //TODO: buf_size = size;
41 }
42#endif 40#endif
43} 41}
44 42
@@ -46,7 +44,9 @@ void skin_buffer_init(void)
46void* skin_buffer_alloc(size_t size) 44void* skin_buffer_alloc(size_t size)
47{ 45{
48 void *retval = NULL; 46 void *retval = NULL;
49#ifdef ROCKBOX 47#ifdef ROCKBOX
48 if (size > skin_buffer_freespace())
49 return NULL;
50 retval = buffer_front; 50 retval = buffer_front;
51 buffer_front += size; 51 buffer_front += size;
52 /* 32-bit aligned */ 52 /* 32-bit aligned */
@@ -62,10 +62,22 @@ void* skin_buffer_alloc(size_t size)
62/* get the number of bytes currently being used */ 62/* get the number of bytes currently being used */
63size_t skin_buffer_usage(void) 63size_t skin_buffer_usage(void)
64{ 64{
65 return buffer_front - buffer; 65 return buffer_front - buffer_start;
66} 66}
67size_t skin_buffer_freespace(void) 67size_t skin_buffer_freespace(void)
68{ 68{
69 return SKIN_BUFFER_SIZE - skin_buffer_usage(); 69 return buf_size - skin_buffer_usage();
70}
71
72static unsigned char *saved_buffer_pos = NULL;
73void skin_buffer_save_position(void)
74{
75 saved_buffer_pos = buffer_front;
76}
77
78void skin_buffer_restore_position(void)
79{
80 if (saved_buffer_pos)
81 buffer_front = saved_buffer_pos;
70} 82}
71#endif 83#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 @@
25#include <stdlib.h> 25#include <stdlib.h>
26#ifndef _SKIN_BUFFFER_H_ 26#ifndef _SKIN_BUFFFER_H_
27#define _SKIN_BUFFFER_H_ 27#define _SKIN_BUFFFER_H_
28void skin_buffer_init(size_t size); 28void skin_buffer_init(char* buffer, size_t size);
29/* Allocate size bytes from the buffer */ 29/* Allocate size bytes from the buffer */
30void* skin_buffer_alloc(size_t size); 30void* skin_buffer_alloc(size_t size);
31 31
32/* get the number of bytes currently being used */ 32/* get the number of bytes currently being used */
33size_t skin_buffer_usage(void); 33size_t skin_buffer_usage(void);
34size_t skin_buffer_freespace(void); 34size_t skin_buffer_freespace(void);
35
36/* save and restore a buffer position incase a skin fails to load */
37void skin_buffer_save_position(void);
38void skin_buffer_restore_position(void);
35#endif 39#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;
35/* Global error variables */ 35/* Global error variables */
36int error_line; 36int error_line;
37int error_col; 37int error_col;
38char *error_line_start;
38char* error_message; 39char* error_message;
39 40
40/* Debugging functions */ 41/* Debugging functions */
@@ -48,6 +49,7 @@ void skin_error(enum skin_errorcode error, char* cursor)
48 cursor--; 49 cursor--;
49 error_col++; 50 error_col++;
50 } 51 }
52 error_line_start = cursor+1;
51 53
52 error_line = skin_line; 54 error_line = skin_line;
53 55
@@ -285,4 +287,42 @@ void skin_debug_indent()
285 for(i = 0; i < debug_indent_level; i++) 287 for(i = 0; i < debug_indent_level; i++)
286 printf(" "); 288 printf(" ");
287} 289}
290
288#endif 291#endif
292
293#define MIN(a,b) ((a<b)?(a):(b))
294void skin_error_format_message()
295{
296 int i;
297 char text[128];
298 char* line_end = strchr(error_line_start, '\n');
299 int len = MIN(line_end - error_line_start, 80);
300 if (!line_end)
301 len = strlen(error_line_start);
302 printf("Error on line %d.\n", error_line);
303 error_col--;
304 if (error_col <= 10)
305 {
306 strncpy(text, error_line_start, len);
307 text[len] = '\0';
308 }
309 else
310 {
311 int j;
312 /* make it fit nicely.. "<start few chars>...<10 chars><error>" */
313 strncpy(text, error_line_start, 6);
314 i = 5;
315 text[i++] = '.';
316 text[i++] = '.';
317 text[i++] = '.';
318 for (j=error_col-10; error_line_start[j] && error_line_start[j] != '\n'; j++)
319 text[i++] = error_line_start[j];
320 text[i] = '\0';
321 error_col = 18;
322 }
323 printf("%s\n", text);
324 for (i=0; i<error_col; i++)
325 text[i] = ' ';
326 snprintf(&text[i],64, "^ \'%s\' Here", error_message);
327 printf("%s\n", text);
328}
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"
28{ 28{
29#endif 29#endif
30 30
31#if !defined(ROCKBOX) || defined(__PCTOOL__)
32#define SKINPARSER_DEBUG
33#endif
34
31#include "skin_parser.h" 35#include "skin_parser.h"
32#ifndef ROCKBOX 36#ifdef SKINPARSER_DEBUG
33/* Debugging functions */ 37/* Debugging functions */
34void skin_error(enum skin_errorcode error, char* cursor); 38void skin_error(enum skin_errorcode error, char* cursor);
35int skin_error_line(void); 39int skin_error_line(void);
@@ -37,6 +41,7 @@ int skin_error_col(void);
37char* skin_error_message(void); 41char* skin_error_message(void);
38void skin_clear_errors(void); 42void skin_clear_errors(void);
39void skin_debug_tree(struct skin_element* root); 43void skin_debug_tree(struct skin_element* root);
44void skin_error_format_message();
40 45
41/* Auxiliary debug functions */ 46/* Auxiliary debug functions */
42void skin_debug_params(int count, struct skin_tag_parameter params[]); 47void skin_debug_params(int count, struct skin_tag_parameter params[]);
@@ -46,7 +51,7 @@ void skin_debug_indent(void);
46#define skin_error(...) 51#define skin_error(...)
47#define skin_clear_errors() 52#define skin_clear_errors()
48 53
49#endif /* !ROCKBOX */ 54#endif /* SKINPARSER_DEBUG */
50 55
51 56
52#ifdef __cplusplus 57#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 @@
21 21
22#include <stdlib.h> 22#include <stdlib.h>
23#include <stdio.h> 23#include <stdio.h>
24#include <stdbool.h>
24#include <string.h> 25#include <string.h>
25#include <ctype.h> 26#include <ctype.h>
26#include <stdbool.h> 27#include <stdbool.h>
@@ -37,6 +38,11 @@ int skin_line = 0;
37char* skin_start = 0; 38char* skin_start = 0;
38int viewport_line = 0; 39int viewport_line = 0;
39 40
41#ifdef ROCKBOX
42static skin_callback callback = NULL;
43static void* callback_data;
44#endif
45
40/* Auxiliary parsing functions (not visible at global scope) */ 46/* Auxiliary parsing functions (not visible at global scope) */
41static struct skin_element* skin_parse_viewport(char** document); 47static struct skin_element* skin_parse_viewport(char** document);
42static struct skin_element* skin_parse_line(char** document); 48static struct skin_element* skin_parse_line(char** document);
@@ -55,10 +61,23 @@ static int skin_parse_comment(struct skin_element* element, char** document);
55static struct skin_element* skin_parse_code_as_arg(char** document); 61static struct skin_element* skin_parse_code_as_arg(char** document);
56 62
57 63
64static void skip_whitespace(char** document)
65{
66 while(**document == ' ' || **document == '\t')
67 (*document)++;
68}
58 69
70#ifdef ROCKBOX
71struct skin_element* skin_parse(const char* document,
72 skin_callback cb, void* cb_data)
73
74{
75 callback = cb;
76 callback_data = cb_data;
77#else
59struct skin_element* skin_parse(const char* document) 78struct skin_element* skin_parse(const char* document)
60{ 79{
61 80#endif
62 struct skin_element* root = NULL; 81 struct skin_element* root = NULL;
63 struct skin_element* last = NULL; 82 struct skin_element* last = NULL;
64 83
@@ -94,7 +113,6 @@ struct skin_element* skin_parse(const char* document)
94 last = last->next; 113 last = last->next;
95 114
96 } 115 }
97
98 return root; 116 return root;
99 117
100} 118}
@@ -107,6 +125,8 @@ static struct skin_element* skin_parse_viewport(char** document)
107 struct skin_element* retval = NULL; 125 struct skin_element* retval = NULL;
108 126
109 retval = skin_alloc_element(); 127 retval = skin_alloc_element();
128 if (!retval)
129 return NULL;
110 retval->type = VIEWPORT; 130 retval->type = VIEWPORT;
111 retval->children_count = 1; 131 retval->children_count = 1;
112 retval->line = skin_line; 132 retval->line = skin_line;
@@ -129,11 +149,18 @@ static struct skin_element* skin_parse_viewport(char** document)
129 skin_line++; 149 skin_line++;
130 } 150 }
131 } 151 }
152#ifdef ROCKBOX
153 else if (callback)
154 {
155 if (callback(retval, callback_data) == CALLBACK_ERROR)
156 return NULL;
157 }
158#endif
132 159
133 retval->children_count = 1; 160 retval->children_count = 1;
134 retval->children = skin_alloc_children(1); 161 retval->children = skin_alloc_children(1);
135 162 if (!retval->children)
136 163 return NULL;
137 do 164 do
138 { 165 {
139 166
@@ -199,7 +226,6 @@ static struct skin_element* skin_parse_viewport(char** document)
199 return NULL; 226 return NULL;
200 227
201 } 228 }
202
203 /* Making sure last is at the end */ 229 /* Making sure last is at the end */
204 while(last->next) 230 while(last->next)
205 last = last->next; 231 last = last->next;
@@ -245,6 +271,8 @@ static struct skin_element* skin_parse_line_optional(char** document,
245 271
246 /* A wrapper for the line */ 272 /* A wrapper for the line */
247 retval = skin_alloc_element(); 273 retval = skin_alloc_element();
274 if (!retval)
275 return NULL;
248 retval->type = LINE; 276 retval->type = LINE;
249 retval->line = skin_line; 277 retval->line = skin_line;
250 if(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM 278 if(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM
@@ -261,7 +289,24 @@ static struct skin_element* skin_parse_line_optional(char** document,
261 } 289 }
262 290
263 if(retval->children_count > 0) 291 if(retval->children_count > 0)
292 {
264 retval->children = skin_alloc_children(1); 293 retval->children = skin_alloc_children(1);
294 if (!retval->children)
295 return NULL;
296 }
297
298#ifdef ROCKBOX
299 if (callback)
300 {
301 switch (callback(retval, callback_data))
302 {
303 case CALLBACK_ERROR:
304 return NULL;
305 default:
306 break;
307 }
308 }
309#endif
265 310
266 while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM 311 while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM
267 && !((*cursor == ARGLISTSEPERATESYM 312 && !((*cursor == ARGLISTSEPERATESYM
@@ -275,11 +320,15 @@ static struct skin_element* skin_parse_line_optional(char** document,
275 if(root) 320 if(root)
276 { 321 {
277 current->next = skin_alloc_element(); 322 current->next = skin_alloc_element();
323 if (!current->next)
324 return NULL;
278 current = current->next; 325 current = current->next;
279 } 326 }
280 else 327 else
281 { 328 {
282 current = skin_alloc_element(); 329 current = skin_alloc_element();
330 if (!current)
331 return NULL;
283 root = current; 332 root = current;
284 } 333 }
285 334
@@ -306,9 +355,10 @@ static struct skin_element* skin_parse_line_optional(char** document,
306 } 355 }
307 } 356 }
308 357
358
309 /* Moving up the calling function's pointer */ 359 /* Moving up the calling function's pointer */
310 *document = cursor; 360 *document = cursor;
311 361
312 if(root) 362 if(root)
313 retval->children[0] = root; 363 retval->children[0] = root;
314 return retval; 364 return retval;
@@ -328,6 +378,8 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
328 int i; 378 int i;
329 379
330 retval = skin_alloc_element(); 380 retval = skin_alloc_element();
381 if (!retval)
382 return NULL;
331 retval->type = LINE_ALTERNATOR; 383 retval->type = LINE_ALTERNATOR;
332 retval->next = NULL; 384 retval->next = NULL;
333 retval->line = skin_line; 385 retval->line = skin_line;
@@ -374,6 +426,8 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
374 /* ...and then we parse them */ 426 /* ...and then we parse them */
375 retval->children_count = sublines; 427 retval->children_count = sublines;
376 retval->children = skin_alloc_children(sublines); 428 retval->children = skin_alloc_children(sublines);
429 if (!retval->children)
430 return NULL;
377 431
378 cursor = *document; 432 cursor = *document;
379 for(i = 0; i < sublines; i++) 433 for(i = 0; i < sublines; i++)
@@ -392,6 +446,13 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
392 } 446 }
393 } 447 }
394 448
449#ifdef ROCKBOX
450 if (callback)
451 {
452 if (callback(retval, callback_data) == CALLBACK_ERROR)
453 return NULL;
454 }
455#endif
395 *document = cursor; 456 *document = cursor;
396 457
397 return retval; 458 return retval;
@@ -458,6 +519,14 @@ static int skin_parse_tag(struct skin_element* element, char** document)
458 || (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM) 519 || (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM)
459 || (star && *cursor != ARGLISTOPENSYM)) 520 || (star && *cursor != ARGLISTOPENSYM))
460 { 521 {
522
523#ifdef ROCKBOX
524 if (callback)
525 {
526 if (callback(element, callback_data) == CALLBACK_ERROR)
527 return 0;
528 }
529#endif
461 *document = cursor; 530 *document = cursor;
462 return 1; 531 return 1;
463 } 532 }
@@ -507,6 +576,8 @@ static int skin_parse_tag(struct skin_element* element, char** document)
507 cursor = bookmark; /* Restoring the cursor */ 576 cursor = bookmark; /* Restoring the cursor */
508 element->params_count = num_args; 577 element->params_count = num_args;
509 element->params = skin_alloc_params(num_args); 578 element->params = skin_alloc_params(num_args);
579 if (!element->params)
580 return 0;
510 581
511 /* Now we have to actually parse each argument */ 582 /* Now we have to actually parse each argument */
512 for(i = 0; i < num_args; i++) 583 for(i = 0; i < num_args; i++)
@@ -587,7 +658,6 @@ static int skin_parse_tag(struct skin_element* element, char** document)
587 } 658 }
588 if (have_tenth == false) 659 if (have_tenth == false)
589 val *= 10; 660 val *= 10;
590
591 element->params[i].type = DECIMAL; 661 element->params[i].type = DECIMAL;
592 element->params[i].data.number = val; 662 element->params[i].data.number = val;
593 } 663 }
@@ -644,7 +714,13 @@ static int skin_parse_tag(struct skin_element* element, char** document)
644 skin_error(INSUFFICIENT_ARGS, cursor); 714 skin_error(INSUFFICIENT_ARGS, cursor);
645 return 0; 715 return 0;
646 } 716 }
647 717#ifdef ROCKBOX
718 if (callback)
719 {
720 if (callback(element, callback_data) == CALLBACK_ERROR)
721 return 0;
722 }
723#endif
648 *document = cursor; 724 *document = cursor;
649 725
650 return 1; 726 return 1;
@@ -691,6 +767,8 @@ static int skin_parse_text(struct skin_element* element, char** document,
691 element->line = skin_line; 767 element->line = skin_line;
692 element->next = NULL; 768 element->next = NULL;
693 element->data = text = skin_alloc_string(length); 769 element->data = text = skin_alloc_string(length);
770 if (!element->data)
771 return 0;
694 772
695 for(dest = 0; dest < length; dest++) 773 for(dest = 0; dest < length; dest++)
696 { 774 {
@@ -702,6 +780,14 @@ static int skin_parse_text(struct skin_element* element, char** document,
702 cursor++; 780 cursor++;
703 } 781 }
704 text[length] = '\0'; 782 text[length] = '\0';
783
784#ifdef ROCKBOX
785 if (callback)
786 {
787 if (callback(element, callback_data) == CALLBACK_ERROR)
788 return 0;
789 }
790#endif
705 791
706 *document = cursor; 792 *document = cursor;
707 793
@@ -715,14 +801,40 @@ static int skin_parse_conditional(struct skin_element* element, char** document)
715 char* bookmark; 801 char* bookmark;
716 int children = 1; 802 int children = 1;
717 int i; 803 int i;
804
805#ifdef ROCKBOX
806 bool feature_available = true;
807 char *false_branch = NULL;
808#endif
718 809
719 element->type = CONDITIONAL; 810 /* Some conditional tags allow for target feature checking,
811 * so to handle that call the callback as usual with type == TAG
812 * then call it a second time with type == CONDITIONAL and check the return
813 * value */
814 element->type = TAG;
720 element->line = skin_line; 815 element->line = skin_line;
721 816
722 /* Parsing the tag first */ 817 /* Parsing the tag first */
723 if(!skin_parse_tag(element, &cursor)) 818 if(!skin_parse_tag(element, &cursor))
724 return 0; 819 return 0;
725 820
821 element->type = CONDITIONAL;
822#ifdef ROCKBOX
823 if (callback)
824 {
825 switch (callback(element, callback_data))
826 {
827 case FEATURE_NOT_AVAILABLE:
828 feature_available = false;
829 break;
830 case CALLBACK_ERROR:
831 return 0;
832 default:
833 break;
834 }
835 }
836#endif
837
726 /* Counting the children */ 838 /* Counting the children */
727 if(*(cursor++) != ENUMLISTOPENSYM) 839 if(*(cursor++) != ENUMLISTOPENSYM)
728 { 840 {
@@ -751,16 +863,35 @@ static int skin_parse_conditional(struct skin_element* element, char** document)
751 { 863 {
752 children++; 864 children++;
753 cursor++; 865 cursor++;
866#ifdef ROCKBOX
867 if (false_branch == NULL && !feature_available)
868 {
869 false_branch = cursor;
870 children--;
871 }
872#endif
754 } 873 }
755 else 874 else
756 { 875 {
757 cursor++; 876 cursor++;
758 } 877 }
759 } 878 }
879#ifdef ROCKBOX
880 if (*cursor == ENUMLISTCLOSESYM &&
881 false_branch == NULL && !feature_available)
882 {
883 false_branch = cursor+1;
884 children--;
885 }
886 /* if we are skipping the true branch fix that up */
887 cursor = false_branch ? false_branch : bookmark;
888#else
760 cursor = bookmark; 889 cursor = bookmark;
761 890#endif
762 /* Parsing the children */ 891 /* Parsing the children */
763 element->children = skin_alloc_children(children); 892 element->children = skin_alloc_children(children);
893 if (!element->children)
894 return 0;
764 element->children_count = children; 895 element->children_count = children;
765 896
766 for(i = 0; i < children; i++) 897 for(i = 0; i < children; i++)
@@ -809,6 +940,8 @@ static int skin_parse_comment(struct skin_element* element, char** document)
809 element->data = NULL; 940 element->data = NULL;
810#else 941#else
811 element->data = text = skin_alloc_string(length); 942 element->data = text = skin_alloc_string(length);
943 if (!element->data)
944 return 0;
812 /* We copy from one char past cursor to leave out the # */ 945 /* We copy from one char past cursor to leave out the # */
813 memcpy((void*)text, (void*)(cursor + 1), 946 memcpy((void*)text, (void*)(cursor + 1),
814 sizeof(char) * (length-1)); 947 sizeof(char) * (length-1));
@@ -877,6 +1010,8 @@ struct skin_element* skin_alloc_element()
877{ 1010{
878 struct skin_element* retval = (struct skin_element*) 1011 struct skin_element* retval = (struct skin_element*)
879 skin_buffer_alloc(sizeof(struct skin_element)); 1012 skin_buffer_alloc(sizeof(struct skin_element));
1013 if (!retval)
1014 return NULL;
880 retval->type = UNKNOWN; 1015 retval->type = UNKNOWN;
881 retval->next = NULL; 1016 retval->next = NULL;
882 retval->tag = NULL; 1017 retval->tag = NULL;
@@ -886,9 +1021,21 @@ struct skin_element* skin_alloc_element()
886 return retval; 1021 return retval;
887 1022
888} 1023}
889 1024/* On a ROCKBOX build we try to save space as much as possible
1025 * so if we can, use a shared param pool which should be more then large
1026 * enough for any tag. params should be used straight away by the callback
1027 * so this is safe.
1028 */
890struct skin_tag_parameter* skin_alloc_params(int count) 1029struct skin_tag_parameter* skin_alloc_params(int count)
891{ 1030{
1031#ifdef ROCKBOX
1032 static struct skin_tag_parameter params[MAX_TAG_PARAMS];
1033 if (count <= MAX_TAG_PARAMS)
1034 {
1035 memset(params, 0, sizeof(params));
1036 return params;
1037 }
1038#endif
892 size_t size = sizeof(struct skin_tag_parameter) * count; 1039 size_t size = sizeof(struct skin_tag_parameter) * count;
893 return (struct skin_tag_parameter*)skin_buffer_alloc(size); 1040 return (struct skin_tag_parameter*)skin_buffer_alloc(size);
894 1041
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
115 struct skin_element* next; 115 struct skin_element* next;
116}; 116};
117 117
118enum skin_cb_returnvalue
119{
120 CALLBACK_ERROR = -666,
121 FEATURE_NOT_AVAILABLE,
122 CALLBACK_OK = 0,
123 /* > 0 reserved for future use */
124};
125typedef int (*skin_callback)(struct skin_element* element, void* data);
126
118/*********************************************************************** 127/***********************************************************************
119 ***** Functions ******************************************************* 128 ***** Functions *******************************************************
120 **********************************************************************/ 129 **********************************************************************/
121 130
122/* Parses a WPS document and returns a list of skin_element 131/* Parses a WPS document and returns a list of skin_element
123 structures. */ 132 structures. */
133#ifdef ROCKBOX
134struct skin_element* skin_parse(const char* document,
135 skin_callback callback, void* callback_data);
136#else
124struct skin_element* skin_parse(const char* document); 137struct skin_element* skin_parse(const char* document);
125 138#endif
126/* Memory management functions */ 139/* Memory management functions */
127struct skin_element* skin_alloc_element(void); 140struct skin_element* skin_alloc_element(void);
128struct skin_element** skin_alloc_children(int count); 141struct 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)
40 (*document)++; 40 (*document)++;
41} 41}
42 42
43void skip_whitespace(char** document)
44{
45 while(**document == ' ' || **document == '\t')
46 (*document)++;
47}
48
49void skip_arglist(char** document) 43void skip_arglist(char** document)
50{ 44{
51 if(**document == ARGLISTOPENSYM) 45 if(**document == ARGLISTOPENSYM)
@@ -132,6 +126,8 @@ char* scan_string(char** document)
132 /* Copying the string */ 126 /* Copying the string */
133 cursor = *document; 127 cursor = *document;
134 buffer = skin_alloc_string(length); 128 buffer = skin_alloc_string(length);
129 if (!buffer)
130 return NULL;
135 buffer[length] = '\0'; 131 buffer[length] = '\0';
136 for(i = 0; i < length; i++) 132 for(i = 0; i < length; i++)
137 { 133 {
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"
30 30
31/* Scanning functions */ 31/* Scanning functions */
32void skip_comment(char** document); 32void skip_comment(char** document);
33void skip_whitespace(char** document);
34void skip_arglist(char** document); 33void skip_arglist(char** document);
35void skip_enumlist(char** document); 34void skip_enumlist(char** document);
36char* scan_string(char** document); 35char* 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[] =
33 { SKIN_TOKEN_ALIGN_RIGHT_RTL, "aR", "", 0 }, 33 { SKIN_TOKEN_ALIGN_RIGHT_RTL, "aR", "", 0 },
34 { SKIN_TOKEN_ALIGN_LANGDIRECTION, "ax", "", 0 }, 34 { SKIN_TOKEN_ALIGN_LANGDIRECTION, "ax", "", 0 },
35 35
36 { SKIN_TOKEN_BATTERY_PERCENT, "bl" , BAR_PARAMS, 0 }, 36 { SKIN_TOKEN_BATTERY_PERCENT, "bl" , BAR_PARAMS, SKIN_REFRESH_DYNAMIC },
37 { SKIN_TOKEN_BATTERY_VOLTS, "bv", "", 0 }, 37 { SKIN_TOKEN_BATTERY_VOLTS, "bv", "", SKIN_REFRESH_DYNAMIC },
38 { SKIN_TOKEN_BATTERY_TIME, "bt", "", 0 }, 38 { SKIN_TOKEN_BATTERY_TIME, "bt", "", SKIN_REFRESH_DYNAMIC },
39 { SKIN_TOKEN_BATTERY_SLEEPTIME, "bs", "", 0 }, 39 { SKIN_TOKEN_BATTERY_SLEEPTIME, "bs", "", SKIN_REFRESH_DYNAMIC },
40 { SKIN_TOKEN_BATTERY_CHARGING, "bc", "", 0 }, 40 { SKIN_TOKEN_BATTERY_CHARGING, "bc", "", SKIN_REFRESH_DYNAMIC },
41 { SKIN_TOKEN_BATTERY_CHARGER_CONNECTED, "bp", "", 0 }, 41 { SKIN_TOKEN_BATTERY_CHARGER_CONNECTED, "bp", "", SKIN_REFRESH_DYNAMIC },
42 { SKIN_TOKEN_USB_POWERED, "bu", "", 0 }, 42 { SKIN_TOKEN_USB_POWERED, "bu", "", SKIN_REFRESH_DYNAMIC },
43 43
44 44
45 { SKIN_TOKEN_RTC_PRESENT, "cc", "", 0 }, 45 { SKIN_TOKEN_RTC_PRESENT, "cc", "", SKIN_REFRESH_STATIC },
46 { SKIN_TOKEN_RTC_DAY_OF_MONTH, "cd", "", 0 }, 46 { SKIN_TOKEN_RTC_DAY_OF_MONTH, "cd", "", SKIN_RTC_REFRESH },
47 { SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, "ce", "", 0 }, 47 { SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, "ce", "", SKIN_RTC_REFRESH },
48 { SKIN_TOKEN_RTC_12HOUR_CFG, "cf", "", 0 }, 48 { SKIN_TOKEN_RTC_12HOUR_CFG, "cf", "", SKIN_RTC_REFRESH },
49 { SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", "", 0 }, 49 { SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", "", SKIN_RTC_REFRESH },
50 { SKIN_TOKEN_RTC_HOUR_24, "ck", "", 0 }, 50 { SKIN_TOKEN_RTC_HOUR_24, "ck", "", SKIN_RTC_REFRESH },
51 { SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", "", 0 }, 51 { SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", "", SKIN_RTC_REFRESH },
52 { SKIN_TOKEN_RTC_HOUR_12, "cl", "", 0 }, 52 { SKIN_TOKEN_RTC_HOUR_12, "cl", "", SKIN_RTC_REFRESH },
53 { SKIN_TOKEN_RTC_MONTH, "cm", "", 0 }, 53 { SKIN_TOKEN_RTC_MONTH, "cm", "", SKIN_RTC_REFRESH },
54 { SKIN_TOKEN_RTC_MINUTE, "cM", "", 0 }, 54 { SKIN_TOKEN_RTC_MINUTE, "cM", "", SKIN_RTC_REFRESH },
55 { SKIN_TOKEN_RTC_SECOND, "cS", "", 0 }, 55 { SKIN_TOKEN_RTC_SECOND, "cS", "", SKIN_RTC_REFRESH },
56 { SKIN_TOKEN_RTC_YEAR_2_DIGITS, "cy", "", 0 }, 56 { SKIN_TOKEN_RTC_YEAR_2_DIGITS, "cy", "", SKIN_RTC_REFRESH },
57 { SKIN_TOKEN_RTC_YEAR_4_DIGITS, "cY", "", 0 }, 57 { SKIN_TOKEN_RTC_YEAR_4_DIGITS, "cY", "", SKIN_RTC_REFRESH },
58 { SKIN_TOKEN_RTC_AM_PM_UPPER, "cP", "", 0 }, 58 { SKIN_TOKEN_RTC_AM_PM_UPPER, "cP", "", SKIN_RTC_REFRESH },
59 { SKIN_TOKEN_RTC_AM_PM_LOWER, "cp", "", 0 }, 59 { SKIN_TOKEN_RTC_AM_PM_LOWER, "cp", "", SKIN_RTC_REFRESH },
60 { SKIN_TOKEN_RTC_WEEKDAY_NAME, "ca", "", 0 }, 60 { SKIN_TOKEN_RTC_WEEKDAY_NAME, "ca", "", SKIN_RTC_REFRESH },
61 { SKIN_TOKEN_RTC_MONTH_NAME, "cb", "", 0 }, 61 { SKIN_TOKEN_RTC_MONTH_NAME, "cb", "", SKIN_RTC_REFRESH },
62 { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", "", 0 }, 62 { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", "", SKIN_RTC_REFRESH },
63 { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", "", 0 }, 63 { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", "", SKIN_RTC_REFRESH },
64 64
65 { SKIN_TOKEN_FILE_BITRATE, "fb", "", 0 }, 65 { SKIN_TOKEN_FILE_BITRATE, "fb", "", SKIN_REFRESH_STATIC },
66 { SKIN_TOKEN_FILE_CODEC, "fc", "", 0 }, 66 { SKIN_TOKEN_FILE_CODEC, "fc", "", SKIN_REFRESH_STATIC },
67 { SKIN_TOKEN_FILE_FREQUENCY, "ff", "", 0 }, 67 { SKIN_TOKEN_FILE_FREQUENCY, "ff", "", SKIN_REFRESH_STATIC },
68 { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "fk", "", 0 }, 68 { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "fk", "", SKIN_REFRESH_STATIC },
69 { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", "", 0 }, 69 { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", "", SKIN_REFRESH_STATIC },
70 { SKIN_TOKEN_FILE_NAME, "fn", "", 0 }, 70 { SKIN_TOKEN_FILE_NAME, "fn", "", SKIN_REFRESH_STATIC },
71 { SKIN_TOKEN_FILE_PATH, "fp", "", 0 }, 71 { SKIN_TOKEN_FILE_PATH, "fp", "", SKIN_REFRESH_STATIC },
72 { SKIN_TOKEN_FILE_SIZE, "fs", "", 0 }, 72 { SKIN_TOKEN_FILE_SIZE, "fs", "", SKIN_REFRESH_STATIC },
73 { SKIN_TOKEN_FILE_VBR, "fv", "", 0 }, 73 { SKIN_TOKEN_FILE_VBR, "fv", "", SKIN_REFRESH_STATIC },
74 { SKIN_TOKEN_FILE_DIRECTORY, "d" , "I", 0 }, 74 { SKIN_TOKEN_FILE_DIRECTORY, "d" , "I", SKIN_REFRESH_STATIC },
75 75
76 { SKIN_TOKEN_FILE_BITRATE, "Fb", "", 0 }, 76 { SKIN_TOKEN_FILE_BITRATE, "Fb", "", SKIN_REFRESH_STATIC },
77 { SKIN_TOKEN_FILE_CODEC, "Fc", "", 0 }, 77 { SKIN_TOKEN_FILE_CODEC, "Fc", "", SKIN_REFRESH_STATIC },
78 { SKIN_TOKEN_FILE_FREQUENCY, "Ff", "", 0 }, 78 { SKIN_TOKEN_FILE_FREQUENCY, "Ff", "", SKIN_REFRESH_STATIC },
79 { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "Fk", "", 0 }, 79 { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "Fk", "", SKIN_REFRESH_STATIC },
80 { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", "", 0 }, 80 { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", "", SKIN_REFRESH_STATIC },
81 { SKIN_TOKEN_FILE_NAME, "Fn", "", 0 }, 81 { SKIN_TOKEN_FILE_NAME, "Fn", "", SKIN_REFRESH_STATIC },
82 { SKIN_TOKEN_FILE_PATH, "Fp", "", 0 }, 82 { SKIN_TOKEN_FILE_PATH, "Fp", "", SKIN_REFRESH_STATIC },
83 { SKIN_TOKEN_FILE_SIZE, "Fs", "", 0 }, 83 { SKIN_TOKEN_FILE_SIZE, "Fs", "", SKIN_REFRESH_STATIC },
84 { SKIN_TOKEN_FILE_VBR, "Fv", "", 0 }, 84 { SKIN_TOKEN_FILE_VBR, "Fv", "", SKIN_REFRESH_STATIC },
85 { SKIN_TOKEN_FILE_DIRECTORY, "D" , "I", 0 }, 85 { SKIN_TOKEN_FILE_DIRECTORY, "D" , "I", SKIN_REFRESH_STATIC },
86 86
87 87
88 { SKIN_TOKEN_METADATA_ARTIST, "ia", "", 0 }, 88 { SKIN_TOKEN_METADATA_ARTIST, "ia", "", SKIN_REFRESH_STATIC },
89 { SKIN_TOKEN_METADATA_COMPOSER, "ic", "", 0 }, 89 { SKIN_TOKEN_METADATA_COMPOSER, "ic", "", SKIN_REFRESH_STATIC },
90 { SKIN_TOKEN_METADATA_ALBUM, "id", "", 0 }, 90 { SKIN_TOKEN_METADATA_ALBUM, "id", "", SKIN_REFRESH_STATIC },
91 { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "iA", "", 0 }, 91 { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "iA", "", SKIN_REFRESH_STATIC },
92 { SKIN_TOKEN_METADATA_GROUPING, "iG", "", 0 }, 92 { SKIN_TOKEN_METADATA_GROUPING, "iG", "", SKIN_REFRESH_STATIC },
93 { SKIN_TOKEN_METADATA_GENRE, "ig", "", 0 }, 93 { SKIN_TOKEN_METADATA_GENRE, "ig", "", SKIN_REFRESH_STATIC },
94 { SKIN_TOKEN_METADATA_DISC_NUMBER, "ik", "", 0 }, 94 { SKIN_TOKEN_METADATA_DISC_NUMBER, "ik", "", SKIN_REFRESH_STATIC },
95 { SKIN_TOKEN_METADATA_TRACK_NUMBER, "in", "", 0 }, 95 { SKIN_TOKEN_METADATA_TRACK_NUMBER, "in", "", SKIN_REFRESH_STATIC },
96 { SKIN_TOKEN_METADATA_TRACK_TITLE, "it", "", 0 }, 96 { SKIN_TOKEN_METADATA_TRACK_TITLE, "it", "", SKIN_REFRESH_STATIC },
97 { SKIN_TOKEN_METADATA_VERSION, "iv", "", 0 }, 97 { SKIN_TOKEN_METADATA_VERSION, "iv", "", SKIN_REFRESH_STATIC },
98 { SKIN_TOKEN_METADATA_YEAR, "iy", "", 0 }, 98 { SKIN_TOKEN_METADATA_YEAR, "iy", "", SKIN_REFRESH_STATIC },
99 { SKIN_TOKEN_METADATA_COMMENT, "iC", "", 0 }, 99 { SKIN_TOKEN_METADATA_COMMENT, "iC", "", SKIN_REFRESH_STATIC },
100 100
101 { SKIN_TOKEN_METADATA_ARTIST, "Ia", "", 0 }, 101 { SKIN_TOKEN_METADATA_ARTIST, "Ia", "", SKIN_REFRESH_STATIC },
102 { SKIN_TOKEN_METADATA_COMPOSER, "Ic", "", 0 }, 102 { SKIN_TOKEN_METADATA_COMPOSER, "Ic", "", SKIN_REFRESH_STATIC },
103 { SKIN_TOKEN_METADATA_ALBUM, "Id", "", 0 }, 103 { SKIN_TOKEN_METADATA_ALBUM, "Id", "", SKIN_REFRESH_STATIC },
104 { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "IA", "", 0 }, 104 { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "IA", "", SKIN_REFRESH_STATIC },
105 { SKIN_TOKEN_METADATA_GROUPING, "IG", "", 0 }, 105 { SKIN_TOKEN_METADATA_GROUPING, "IG", "", SKIN_REFRESH_STATIC },
106 { SKIN_TOKEN_METADATA_GENRE, "Ig", "", 0 }, 106 { SKIN_TOKEN_METADATA_GENRE, "Ig", "", SKIN_REFRESH_STATIC },
107 { SKIN_TOKEN_METADATA_DISC_NUMBER, "Ik", "", 0 }, 107 { SKIN_TOKEN_METADATA_DISC_NUMBER, "Ik", "", SKIN_REFRESH_STATIC },
108 { SKIN_TOKEN_METADATA_TRACK_NUMBER, "In", "", 0 }, 108 { SKIN_TOKEN_METADATA_TRACK_NUMBER, "In", "", SKIN_REFRESH_STATIC },
109 { SKIN_TOKEN_METADATA_TRACK_TITLE, "It", "", 0 }, 109 { SKIN_TOKEN_METADATA_TRACK_TITLE, "It", "", SKIN_REFRESH_STATIC },
110 { SKIN_TOKEN_METADATA_VERSION, "Iv", "", 0 }, 110 { SKIN_TOKEN_METADATA_VERSION, "Iv", "", SKIN_REFRESH_STATIC },
111 { SKIN_TOKEN_METADATA_YEAR, "Iy", "", 0 }, 111 { SKIN_TOKEN_METADATA_YEAR, "Iy", "", SKIN_REFRESH_STATIC },
112 { SKIN_TOKEN_METADATA_COMMENT, "IC", "", 0 }, 112 { SKIN_TOKEN_METADATA_COMMENT, "IC", "", SKIN_REFRESH_STATIC },
113 113
114 { SKIN_TOKEN_SOUND_PITCH, "Sp", "", 0 }, 114 { SKIN_TOKEN_SOUND_PITCH, "Sp", "", SKIN_REFRESH_DYNAMIC },
115 { SKIN_TOKEN_SOUND_SPEED, "Ss", "", 0 }, 115 { SKIN_TOKEN_SOUND_SPEED, "Ss", "", SKIN_REFRESH_DYNAMIC },
116 116
117 { SKIN_TOKEN_VLED_HDD, "lh", "", 0 }, 117 { SKIN_TOKEN_VLED_HDD, "lh", "", SKIN_REFRESH_DYNAMIC },
118 118
119 { SKIN_TOKEN_MAIN_HOLD, "mh", "", 0 }, 119 { SKIN_TOKEN_MAIN_HOLD, "mh", "", SKIN_REFRESH_DYNAMIC },
120 { SKIN_TOKEN_REMOTE_HOLD, "mr", "", 0 }, 120 { SKIN_TOKEN_REMOTE_HOLD, "mr", "", SKIN_REFRESH_DYNAMIC },
121 { SKIN_TOKEN_REPEAT_MODE, "mm", "", 0 }, 121 { SKIN_TOKEN_REPEAT_MODE, "mm", "", SKIN_REFRESH_DYNAMIC },
122 { SKIN_TOKEN_PLAYBACK_STATUS, "mp", "", 0 }, 122 { SKIN_TOKEN_PLAYBACK_STATUS, "mp", "", SKIN_REFRESH_DYNAMIC },
123 { SKIN_TOKEN_BUTTON_VOLUME, "mv", "|D", 0 }, 123 { SKIN_TOKEN_BUTTON_VOLUME, "mv", "|D", SKIN_REFRESH_DYNAMIC },
124 124
125 { SKIN_TOKEN_PEAKMETER, "pm", "", 0 }, 125 { SKIN_TOKEN_PEAKMETER, "pm", "", SKIN_REFRESH_PEAK_METER },
126 { SKIN_TOKEN_PLAYER_PROGRESSBAR, "pf", "", 0 }, 126 { SKIN_TOKEN_PLAYER_PROGRESSBAR, "pf", "", SKIN_REFRESH_DYNAMIC|SKIN_REFRESH_PLAYER_PROGRESS },
127 { SKIN_TOKEN_PROGRESSBAR, "pb" , BAR_PARAMS, 0 }, 127 { SKIN_TOKEN_PROGRESSBAR, "pb" , BAR_PARAMS, SKIN_REFRESH_PLAYER_PROGRESS },
128 { SKIN_TOKEN_VOLUME, "pv" , BAR_PARAMS, 0 }, 128 { SKIN_TOKEN_VOLUME, "pv" , BAR_PARAMS, SKIN_REFRESH_DYNAMIC },
129 129 { SKIN_TOKEN_TRACK_ELAPSED_PERCENT, "px", "", SKIN_REFRESH_DYNAMIC },
130 { SKIN_TOKEN_TRACK_ELAPSED_PERCENT, "px", "", 0 }, 130 { SKIN_TOKEN_TRACK_TIME_ELAPSED, "pc", "", SKIN_REFRESH_DYNAMIC },
131 { SKIN_TOKEN_TRACK_TIME_ELAPSED, "pc", "", 0 }, 131 { SKIN_TOKEN_TRACK_TIME_REMAINING, "pr", "", SKIN_REFRESH_DYNAMIC },
132 { SKIN_TOKEN_TRACK_TIME_REMAINING, "pr", "", 0 }, 132 { SKIN_TOKEN_TRACK_LENGTH, "pt", "", SKIN_REFRESH_STATIC },
133 { SKIN_TOKEN_TRACK_LENGTH, "pt", "", 0 }, 133 { SKIN_TOKEN_TRACK_STARTING, "pS" , "|D", SKIN_REFRESH_DYNAMIC },
134 { SKIN_TOKEN_TRACK_STARTING, "pS" , "|D", 0 }, 134 { SKIN_TOKEN_TRACK_ENDING, "pE" , "|D", SKIN_REFRESH_DYNAMIC },
135 { SKIN_TOKEN_TRACK_ENDING, "pE" , "|D", 0 }, 135 { SKIN_TOKEN_PLAYLIST_POSITION, "pp", "", SKIN_REFRESH_STATIC },
136 { SKIN_TOKEN_PLAYLIST_POSITION, "pp", "", 0 }, 136 { SKIN_TOKEN_PLAYLIST_ENTRIES, "pe", "", SKIN_REFRESH_STATIC },
137 { SKIN_TOKEN_PLAYLIST_ENTRIES, "pe", "", 0 }, 137 { SKIN_TOKEN_PLAYLIST_NAME, "pn", "", SKIN_REFRESH_STATIC },
138 { SKIN_TOKEN_PLAYLIST_NAME, "pn", "", 0 }, 138 { SKIN_TOKEN_PLAYLIST_SHUFFLE, "ps", "", SKIN_REFRESH_DYNAMIC },
139 { SKIN_TOKEN_PLAYLIST_SHUFFLE, "ps", "", 0 }, 139
140 140 { SKIN_TOKEN_DATABASE_PLAYCOUNT, "rp", "", SKIN_REFRESH_DYNAMIC },
141 { SKIN_TOKEN_DATABASE_PLAYCOUNT, "rp", "", 0 }, 141 { SKIN_TOKEN_DATABASE_RATING, "rr", "", SKIN_REFRESH_DYNAMIC },
142 { SKIN_TOKEN_DATABASE_RATING, "rr", "", 0 }, 142 { SKIN_TOKEN_DATABASE_AUTOSCORE, "ra", "", SKIN_REFRESH_DYNAMIC },
143 { SKIN_TOKEN_DATABASE_AUTOSCORE, "ra", "", 0 }, 143
144 144 { SKIN_TOKEN_REPLAYGAIN, "rg", "", SKIN_REFRESH_STATIC },
145 { SKIN_TOKEN_REPLAYGAIN, "rg", "", 0 }, 145 { SKIN_TOKEN_CROSSFADE, "xf", "", SKIN_REFRESH_DYNAMIC },
146 { SKIN_TOKEN_CROSSFADE, "xf", "", 0 }, 146
147 147 { SKIN_TOKEN_HAVE_TUNER, "tp", "", SKIN_REFRESH_STATIC },
148 { SKIN_TOKEN_HAVE_TUNER, "tp", "", 0 }, 148 { SKIN_TOKEN_TUNER_TUNED, "tt", "", SKIN_REFRESH_DYNAMIC },
149 { SKIN_TOKEN_TUNER_TUNED, "tt", "", 0 }, 149 { SKIN_TOKEN_TUNER_SCANMODE, "tm", "", SKIN_REFRESH_DYNAMIC },
150 { SKIN_TOKEN_TUNER_SCANMODE, "tm", "", 0 }, 150 { SKIN_TOKEN_TUNER_STEREO, "ts", "", SKIN_REFRESH_DYNAMIC },
151 { SKIN_TOKEN_TUNER_STEREO, "ts", "", 0 }, 151 { SKIN_TOKEN_TUNER_MINFREQ, "ta", "", SKIN_REFRESH_STATIC },
152 { SKIN_TOKEN_TUNER_MINFREQ, "ta", "", 0 }, 152 { SKIN_TOKEN_TUNER_MAXFREQ, "tb", "", SKIN_REFRESH_STATIC },
153 { SKIN_TOKEN_TUNER_MAXFREQ, "tb", "", 0 }, 153 { SKIN_TOKEN_TUNER_CURFREQ, "tf", "", SKIN_REFRESH_DYNAMIC },
154 { SKIN_TOKEN_TUNER_CURFREQ, "tf", "", 0 }, 154 { SKIN_TOKEN_PRESET_ID, "Ti", "", SKIN_REFRESH_STATIC },
155 { SKIN_TOKEN_PRESET_ID, "Ti", "", 0 }, 155 { SKIN_TOKEN_PRESET_NAME, "Tn", "", SKIN_REFRESH_STATIC },
156 { SKIN_TOKEN_PRESET_NAME, "Tn", "", 0 }, 156 { SKIN_TOKEN_PRESET_FREQ, "Tf", "", SKIN_REFRESH_STATIC },
157 { SKIN_TOKEN_PRESET_FREQ, "Tf", "", 0 }, 157 { SKIN_TOKEN_PRESET_COUNT, "Tc", "", SKIN_REFRESH_STATIC },
158 { SKIN_TOKEN_PRESET_COUNT, "Tc", "", 0 }, 158 { SKIN_TOKEN_HAVE_RDS, "tx", "", SKIN_REFRESH_STATIC },
159 { SKIN_TOKEN_HAVE_RDS, "tx", "", 0 }, 159 { SKIN_TOKEN_RDS_NAME, "ty", "", SKIN_REFRESH_DYNAMIC },
160 { SKIN_TOKEN_RDS_NAME, "ty", "", 0 }, 160 { SKIN_TOKEN_RDS_TEXT, "tz", "", SKIN_REFRESH_DYNAMIC },
161 { SKIN_TOKEN_RDS_TEXT, "tz", "", 0 }, 161
162 162 { SKIN_TOKEN_SUBLINE_SCROLL, "s", "", SKIN_REFRESH_SCROLL },
163 { SKIN_TOKEN_SUBLINE_SCROLL, "s", "", 0 },
164 { SKIN_TOKEN_SUBLINE_TIMEOUT, "t" , "D", 0 }, 163 { SKIN_TOKEN_SUBLINE_TIMEOUT, "t" , "D", 0 },
164
165 { SKIN_TOKEN_ENABLE_THEME, "we", "", 0|NOBREAK },
166 { SKIN_TOKEN_DISABLE_THEME, "wd", "", 0|NOBREAK },
167 { SKIN_TOKEN_DRAW_INBUILTBAR, "wi", "", SKIN_REFRESH_STATIC|NOBREAK },
165 168
166 { SKIN_TOKEN_ENABLE_THEME, "we", "", NOBREAK }, 169 { SKIN_TOKEN_IMAGE_PRELOAD, "xl", "SFII|I", 0|NOBREAK },
167 { SKIN_TOKEN_DISABLE_THEME, "wd", "", NOBREAK },
168 { SKIN_TOKEN_DRAW_INBUILTBAR, "wi", "", NOBREAK },
169
170 { SKIN_TOKEN_IMAGE_PRELOAD, "xl", "SFII|I", NOBREAK },
171 { SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", "S", 0 }, 170 { SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", "S", 0 },
172 { SKIN_TOKEN_IMAGE_PRELOAD, "x", "SFII", NOBREAK }, 171 { SKIN_TOKEN_IMAGE_DISPLAY, "x", "SFII", 0|NOBREAK },
173 172
174 { SKIN_TOKEN_LOAD_FONT, "Fl" , "IF", NOBREAK }, 173 { SKIN_TOKEN_LOAD_FONT, "Fl" , "IF", 0|NOBREAK },
175 { SKIN_TOKEN_ALBUMART_LOAD, "Cl" , "IIII|ss", NOBREAK }, 174 { SKIN_TOKEN_ALBUMART_LOAD, "Cl" , "IIII|ss", 0|NOBREAK },
176 { SKIN_TOKEN_ALBUMART_DISPLAY, "Cd" , "", 0 }, 175 { SKIN_TOKEN_ALBUMART_DISPLAY, "Cd" , "", SKIN_REFRESH_STATIC },
177 { SKIN_TOKEN_ALBUMART_FOUND, "C" , "", 0 }, 176 { SKIN_TOKEN_ALBUMART_FOUND, "C" , "", SKIN_REFRESH_STATIC },
178 177
179 { SKIN_TOKEN_VIEWPORT_ENABLE, "Vd" , "S", 0 }, 178 { SKIN_TOKEN_VIEWPORT_ENABLE, "Vd" , "S", SKIN_REFRESH_STATIC },
180 { SKIN_TOKEN_UIVIEWPORT_ENABLE, "VI" , "S", 0 }, 179 { SKIN_TOKEN_UIVIEWPORT_ENABLE, "VI" , "S", SKIN_REFRESH_STATIC },
181 180
182 { SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "ICC", NOBREAK }, 181 { SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "ICC", SKIN_REFRESH_DYNAMIC|NOBREAK },
183 { SKIN_TOKEN_LIST_TITLE_TEXT, "Lt" , "", 0 }, 182 { SKIN_TOKEN_LIST_TITLE_TEXT, "Lt" , "", SKIN_REFRESH_DYNAMIC },
184 { SKIN_TOKEN_LIST_TITLE_ICON, "Li" , "", 0 }, 183 { SKIN_TOKEN_LIST_TITLE_ICON, "Li" , "", SKIN_REFRESH_DYNAMIC },
185 184
186 { SKIN_TOKEN_VIEWPORT_FGCOLOUR, "Vf" , "S", NOBREAK }, 185 { SKIN_TOKEN_VIEWPORT_FGCOLOUR, "Vf" , "s", SKIN_REFRESH_STATIC|NOBREAK },
187 { SKIN_TOKEN_VIEWPORT_BGCOLOUR, "Vb" , "S", NOBREAK }, 186 { SKIN_TOKEN_VIEWPORT_BGCOLOUR, "Vb" , "s", SKIN_REFRESH_STATIC|NOBREAK },
188 187
189 { SKIN_TOKEN_VIEWPORT_CONDITIONAL, "Vl" , "SIIiii", 0 }, 188 { SKIN_TOKEN_VIEWPORT_CONDITIONAL, "Vl" , "SIIiii", 0 },
190 { SKIN_TOKEN_UIVIEWPORT_LOAD, "Vi" , "sIIiii", 0 }, 189 { SKIN_TOKEN_UIVIEWPORT_LOAD, "Vi" , "sIIiii", 0 },
191 { SKIN_TOKEN_VIEWPORT_LOAD, "V" , "IIiii", 0 }, 190 { SKIN_TOKEN_VIEWPORT_LOAD, "V" , "IIiii", 0 },
192 191
193 { SKIN_TOKEN_IMAGE_BACKDROP, "X" , "f", NOBREAK }, 192 { SKIN_TOKEN_IMAGE_BACKDROP, "X" , "f", SKIN_REFRESH_STATIC|NOBREAK },
194 193
195 { SKIN_TOKEN_SETTING, "St" , "S", 0 }, 194 { SKIN_TOKEN_SETTING, "St" , "S", SKIN_REFRESH_DYNAMIC },
196 { SKIN_TOKEN_TRANSLATEDSTRING, "Sx" , "S", 0 }, 195 { SKIN_TOKEN_TRANSLATEDSTRING, "Sx" , "S", SKIN_REFRESH_STATIC },
197 { SKIN_TOKEN_LANG_IS_RTL, "Sr" , "", 0 }, 196 { SKIN_TOKEN_LANG_IS_RTL, "Sr" , "", SKIN_REFRESH_STATIC },
198 197
199 { SKIN_TOKEN_LASTTOUCH, "Tl" , "|D", 0 }, 198 { SKIN_TOKEN_LASTTOUCH, "Tl" , "|D", SKIN_REFRESH_DYNAMIC },
200 { SKIN_TOKEN_CURRENT_SCREEN, "cs", "", 0 }, 199 { SKIN_TOKEN_CURRENT_SCREEN, "cs", "", SKIN_REFRESH_DYNAMIC },
201 { SKIN_TOKEN_TOUCHREGION, "T" , "IIiiS", NOBREAK }, 200 { SKIN_TOKEN_TOUCHREGION, "T" , "IIiiS", 0|NOBREAK },
202 201
203 { SKIN_TOKEN_HAVE_RECORDING, "Rp" , "", 0 }, 202 { SKIN_TOKEN_HAVE_RECORDING, "Rp" , "", SKIN_REFRESH_STATIC },
204 { SKIN_TOKEN_IS_RECORDING, "Rr" , "", 0 }, 203 { SKIN_TOKEN_IS_RECORDING, "Rr" , "", SKIN_REFRESH_DYNAMIC },
205 { SKIN_TOKEN_REC_FREQ, "Rf" , "", 0 }, 204 { SKIN_TOKEN_REC_FREQ, "Rf" , "", SKIN_REFRESH_DYNAMIC },
206 { SKIN_TOKEN_REC_ENCODER, "Re" , "", 0 }, 205 { SKIN_TOKEN_REC_ENCODER, "Re" , "", SKIN_REFRESH_DYNAMIC },
207 { SKIN_TOKEN_REC_BITRATE, "Rb" , "", 0 }, 206 { SKIN_TOKEN_REC_BITRATE, "Rb" , "", SKIN_REFRESH_DYNAMIC },
208 { SKIN_TOKEN_REC_MONO, "Rm" , "", 0 }, 207 { SKIN_TOKEN_REC_MONO, "Rm" , "", SKIN_REFRESH_DYNAMIC },
209 { SKIN_TOKEN_REC_SECONDS, "Rs" , "", 0 }, 208 { SKIN_TOKEN_REC_SECONDS, "Rs" , "", SKIN_REFRESH_DYNAMIC },
210 { SKIN_TOKEN_REC_MINUTES, "Rn" , "", 0 }, 209 { SKIN_TOKEN_REC_MINUTES, "Rn" , "", SKIN_REFRESH_DYNAMIC },
211 { SKIN_TOKEN_REC_HOURS, "Rh" , "", 0 }, 210 { SKIN_TOKEN_REC_HOURS, "Rh" , "", SKIN_REFRESH_DYNAMIC },
212 211
213 { SKIN_TOKEN_UNKNOWN, "" , "", 0 } 212 { SKIN_TOKEN_UNKNOWN, "" , "", 0 }
214 /* Keep this here to mark the end of the table */ 213 /* 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"
27{ 27{
28#endif 28#endif
29 29
30#define MAX_TAG_PARAMS 12
31
32
30 /* Flag to tell the renderer not to insert a line break */ 33 /* Flag to tell the renderer not to insert a line break */
31#define NOBREAK 0x1 34#define NOBREAK 0x1
32 35
36/* constants used in line_type and as refresh_mode for wps_refresh */
37#define SKIN_REFRESH_SHIFT 16
38#define SKIN_REFRESH_STATIC (1u<<SKIN_REFRESH_SHIFT) /* line doesn't change over time */
39#define SKIN_REFRESH_DYNAMIC (1u<<(SKIN_REFRESH_SHIFT+1)) /* line may change (e.g. time flag) */
40#define SKIN_REFRESH_SCROLL (1u<<(SKIN_REFRESH_SHIFT+2)) /* line scrolls */
41#define SKIN_REFRESH_PLAYER_PROGRESS (1u<<(SKIN_REFRESH_SHIFT+3)) /* line contains a progress bar */
42#define SKIN_REFRESH_PEAK_METER (1u<<(SKIN_REFRESH_SHIFT+4)) /* line contains a peak meter */
43#define SKIN_REFRESH_STATUSBAR (1u<<(SKIN_REFRESH_SHIFT+5)) /* refresh statusbar */
44#define SKIN_RTC_REFRESH (1u<<(SKIN_REFRESH_SHIFT+6)) /* refresh rtc, convert at parse time */
45#define SKIN_REFRESH_ALL (0xffffu<<SKIN_REFRESH_SHIFT) /* to refresh all line types */
46
47/* to refresh only those lines that change over time */
48#define SKIN_REFRESH_NON_STATIC (SKIN_REFRESH_DYNAMIC| \
49 SKIN_REFRESH_PLAYER_PROGRESS| \
50 SKIN_REFRESH_PEAK_METER)
33 51
34enum skin_token_type { 52enum skin_token_type {
35 53
54 SKIN_TOKEN_NO_TOKEN,
36 SKIN_TOKEN_UNKNOWN, 55 SKIN_TOKEN_UNKNOWN,
37 56
38 /* Markers */ 57 /* Markers */
@@ -91,7 +110,7 @@ enum skin_token_type {
91 /* The begin/end values allow us to know if a token is an RTC one. 110 /* The begin/end values allow us to know if a token is an RTC one.
92 New RTC tokens should be added between the markers. */ 111 New RTC tokens should be added between the markers. */
93 112
94 SKIN_TOKENs_RTC_BEGIN, /* just the start marker, not an actual token */ 113 SKIN_TOKENS_RTC_BEGIN, /* just the start marker, not an actual token */
95 114
96 SKIN_TOKEN_RTC_DAY_OF_MONTH, 115 SKIN_TOKEN_RTC_DAY_OF_MONTH,
97 SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, 116 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 @@
1../../apps/gui/skin_engine/wps_debug.c 1../../apps/gui/skin_engine/wps_debug.c
2../../apps/gui/skin_engine/skin_parser.c 2../../apps/gui/skin_engine/skin_parser.c
3../../apps/gui/skin_engine/skin_backdrops.c 3../../apps/gui/skin_engine/skin_backdrops.c
4../../apps/gui/skin_engine/skin_buffer.c
5#ifdef HAVE_LCD_BITMAP 4#ifdef HAVE_LCD_BITMAP
6../../apps/gui/skin_engine/skin_fonts.c 5../../apps/gui/skin_engine/skin_fonts.c
7#endif 6#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 @@
26#include "checkwps.h" 26#include "checkwps.h"
27#include "resize.h" 27#include "resize.h"
28#include "wps.h" 28#include "wps.h"
29#include "skin_buffer.h"
30#include "skin_debug.h"
29#include "skin_engine.h" 31#include "skin_engine.h"
30#include "wps_internals.h" 32#include "wps_internals.h"
31#include "settings.h" 33#include "settings.h"
@@ -237,6 +239,8 @@ int main(int argc, char **argv)
237 struct wps_data wps; 239 struct wps_data wps;
238 enum screen_type screen = SCREEN_MAIN; 240 enum screen_type screen = SCREEN_MAIN;
239 struct screen* wps_screen; 241 struct screen* wps_screen;
242
243 char* buffer = NULL;
240 244
241 /* No arguments -> print the help text 245 /* No arguments -> print the help text
242 * Also print the help text upon -h or --help */ 246 * Also print the help text upon -h or --help */
@@ -261,13 +265,19 @@ int main(int argc, char **argv)
261 wps_verbose_level++; 265 wps_verbose_level++;
262 } 266 }
263 } 267 }
268 buffer = malloc(SKIN_BUFFER_SIZE);
269 if (!buffer)
270 {
271 printf("mallloc fail!\n");
272 return 1;
273 }
264 274
265 skin_buffer_init(); 275 skin_buffer_init(buffer, SKIN_BUFFER_SIZE);
266#ifdef HAVE_LCD_BITMAP 276#ifdef HAVE_LCD_BITMAP
267 skin_font_init(); 277 skin_font_init();
268#endif 278#endif
269 279
270 /* Go through every wps that was thrown at us, error out at the first 280 /* Go through every skin that was thrown at us, error out at the first
271 * flawed wps */ 281 * flawed wps */
272 while (argv[filearg]) { 282 while (argv[filearg]) {
273 printf("Checking %s...\n", argv[filearg]); 283 printf("Checking %s...\n", argv[filearg]);
@@ -285,6 +295,7 @@ int main(int argc, char **argv)
285 295
286 if (!res) { 296 if (!res) {
287 printf("WPS parsing failure\n"); 297 printf("WPS parsing failure\n");
298 skin_error_format_message();
288 return 3; 299 return 3;
289 } 300 }
290 301
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__
26 26
27.SECONDEXPANSION: # $$(OBJ) is not populated until after this 27.SECONDEXPANSION: # $$(OBJ) is not populated until after this
28 28
29$(BUILDDIR)/$(BINARY): $$(OBJ) 29$(BUILDDIR)/$(BINARY): $$(OBJ) $$(SKINLIB)
30 @echo LD $(BINARY) 30 @echo LD $(BINARY)
31 $(SILENT)$(HOSTCC) $(INCLUDE) $(FLAGS) -o $@ $+ 31 $(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)))
70 include $(APPSDIR)/bootbox.make 70 include $(APPSDIR)/bootbox.make
71else ifneq (,$(findstring checkwps,$(APPSDIR))) 71else ifneq (,$(findstring checkwps,$(APPSDIR)))
72 include $(APPSDIR)/checkwps.make 72 include $(APPSDIR)/checkwps.make
73 include $(ROOTDIR)/lib/skin_parser/skin_parser.make
73else ifneq (,$(findstring database,$(APPSDIR))) 74else ifneq (,$(findstring database,$(APPSDIR)))
74 include $(APPSDIR)/database.make 75 include $(APPSDIR)/database.make
75else 76else
@@ -170,7 +171,8 @@ $(BUILDDIR)/rockbox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) $$(L
170$(BUILDDIR)/rombox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) $$(LINKROM) 171$(BUILDDIR)/rombox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) $$(LINKROM)
171 $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \ 172 $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \
172 $(VOICESPEEXLIB) $(FIRMLIB) -lgcc $(GLOBAL_LDOPTS) \ 173 $(VOICESPEEXLIB) $(FIRMLIB) -lgcc $(GLOBAL_LDOPTS) \
173 -L$(BUILDDIR)/firmware -T$(LINKROM) -Wl,-Map,$(BUILDDIR)/rombox.map 174 -L$(BUILDDIR)/lib -lskin_parser \
175 -L$(BUILDDIR)/firmware -T$(LINKROM) -Wl,-Map,$(BUILDDIR)/rombox.map
174 176
175$(BUILDDIR)/rockbox.bin : $(BUILDDIR)/rockbox.elf 177$(BUILDDIR)/rockbox.bin : $(BUILDDIR)/rockbox.elf
176 $(call PRINTS,OC $(@F))$(OC) $(if $(filter yes, $(USE_ELF)), -S -x, -O binary) $< $@ 178 $(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)
43{ 43{
44 /* Tags here are ones which need to be "turned off" or cleared 44 /* Tags here are ones which need to be "turned off" or cleared
45 * if they are in a conditional branch which isnt being used */ 45 * if they are in a conditional branch which isnt being used */
46 if (branch->type == SUBLINES) 46 if (branch->type == LINE_ALTERNATOR)
47 { 47 {
48 int i; 48 int i;
49 for (i=0; i<branch->children_count; i++) 49 for (i=0; i<branch->children_count; i++)
@@ -71,7 +71,6 @@ static void do_tags_in_hidden_conditional(struct skin_element* branch)
71 break; 71 break;
72 case SKIN_TOKEN_IMAGE_DISPLAY: 72 case SKIN_TOKEN_IMAGE_DISPLAY:
73 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: 73 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
74 printf("disable image\n");
75 /* clear images */ 74 /* clear images */
76 break; 75 break;
77 default: 76 default:
@@ -109,7 +108,7 @@ void skin_render_line(struct skin_element* line,
109 do_tags_in_hidden_conditional(child->children[last_value]); 108 do_tags_in_hidden_conditional(child->children[last_value]);
110 last_value = value; 109 last_value = value;
111 110
112 if (child->children[value]->type == SUBLINES) 111 if (child->children[value]->type == LINE_ALTERNATOR)
113 func = skin_render_alternator; 112 func = skin_render_alternator;
114 else if (child->children[value]->type == LINE) 113 else if (child->children[value]->type == LINE)
115 func = skin_render_line; 114 func = skin_render_line;