FS#11470 - new skin code, finally svn uses the new parser from the theme editor. This means that a skin that passes the editor WILL pass svn and checkwps (unless the target runs out of skin buffer or something.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27613 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jonathan Gordon 2010-07-29 12:37:48 +00:00
parent e436483b66
commit 2d31d77a8b
44 changed files with 2105 additions and 3326 deletions

View file

@ -94,13 +94,12 @@ gui/yesno.c
gui/viewport.c gui/viewport.c
gui/skin_engine/skin_backdrops.c gui/skin_engine/skin_backdrops.c
gui/skin_engine/skin_buffer.c
gui/skin_engine/wps_debug.c
gui/skin_engine/skin_display.c gui/skin_engine/skin_display.c
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
gui/skin_engine/skin_fonts.c gui/skin_engine/skin_fonts.c
#endif #endif
gui/skin_engine/skin_parser.c gui/skin_engine/skin_parser.c
gui/skin_engine/skin_render.c
gui/skin_engine/skin_tokens.c gui/skin_engine/skin_tokens.c
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
gui/skin_engine/skin_touchsupport.c gui/skin_engine/skin_touchsupport.c

View file

@ -363,20 +363,22 @@ const char *get_cuesheetid3_token(struct wps_token *token, struct mp3entry *id3,
} }
switch (token->type) switch (token->type)
{ {
case WPS_TOKEN_METADATA_ARTIST: case SKIN_TOKEN_METADATA_ARTIST:
return *track->performer ? track->performer : NULL; return *track->performer ? track->performer : NULL;
case WPS_TOKEN_METADATA_COMPOSER: case SKIN_TOKEN_METADATA_COMPOSER:
return *track->songwriter ? track->songwriter : NULL; return *track->songwriter ? track->songwriter : NULL;
case WPS_TOKEN_METADATA_ALBUM: case SKIN_TOKEN_METADATA_ALBUM:
return *cue->title ? cue->title : NULL; return *cue->title ? cue->title : NULL;
case WPS_TOKEN_METADATA_ALBUM_ARTIST: case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
return *cue->performer ? cue->performer : NULL; return *cue->performer ? cue->performer : NULL;
case WPS_TOKEN_METADATA_TRACK_TITLE: case SKIN_TOKEN_METADATA_TRACK_TITLE:
return *track->title ? track->title : NULL; return *track->title ? track->title : NULL;
case WPS_TOKEN_METADATA_TRACK_NUMBER: case SKIN_TOKEN_METADATA_TRACK_NUMBER:
snprintf(buf, buf_size, "%d/%d", snprintf(buf, buf_size, "%d/%d",
cue->curr_track_idx+offset_tracks+1, cue->track_count); cue->curr_track_idx+offset_tracks+1, cue->track_count);
return buf; return buf;
default:
return NULL;
} }
return NULL; return NULL;
} }

View file

@ -24,9 +24,9 @@
#include <stdlib.h> #include <stdlib.h>
#include "string-extra.h" #include "string-extra.h"
#include "settings.h" #include "settings.h"
#include "skin_buffer.h"
#include "wps_internals.h" #include "wps_internals.h"
#include "skin_engine.h" #include "skin_engine.h"
#include "skin_buffer.h"
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
@ -100,7 +100,7 @@ char* skin_backdrop_load(char* backdrop, char *bmpdir, enum screen_type screen)
if (!bdrop) if (!bdrop)
return NULL; /* too many backdrops loaded */ return NULL; /* too many backdrops loaded */
bdrop->buffer = skin_buffer_alloc(buf_size); bdrop->buffer = (char*)skin_buffer_alloc(buf_size);
if (!bdrop->buffer) if (!bdrop->buffer)
return NULL; return NULL;
loaded = screens[screen].backdrop_load(filename, bdrop->buffer); loaded = screens[screen].backdrop_load(filename, bdrop->buffer);

View file

@ -1,170 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Linus Nielsen Feltzing
* Copyright (C) 2009 Jonathan Gordon
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "config.h"
#include "buffer.h"
#include "settings.h"
#include "screen_access.h"
#include "skin_engine.h"
#include "wps_internals.h"
#include "skin_tokens.h"
#include "skin_buffer.h"
#include "skin_fonts.h"
/* skin buffer management.
* This module is used to allocate space in a single global skin buffer for
* tokens for both/all screens.
*
* This is mostly just copy/paste from firmware/buffer.c
*
*
* MAIN_ and REMOTE_BUFFER are just for reasonable size calibration,
* both screens can use the whole buffer as they need; it's not split
* between screens
*
* Buffer can be allocated from either "end" of the global buffer.
* items with unknown sizes get allocated from the start (0->) (data)
* items with known sizes get allocated from the end (<-buf_size) (tokens)
* After loading 2 skins the buffer will look like this:
* |tokens skin1|images skin1|tokens s2|images s2|---SPACE---|data skin2|data skin1|
* Make sure to never start allocating from the beginning before letting us know
* how much was used. and RESPECT THE buf_free RETURN VALUES!
*
*/
#ifdef HAVE_LCD_BITMAP
#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
+ (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES))
#if (NB_SCREENS > 1)
#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
+ (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES))
#else
#define REMOTE_BUFFER 0
#endif
#define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER + SKIN_FONT_SIZE) + \
(WPS_MAX_TOKENS * sizeof(struct wps_token))
#endif
#ifdef HAVE_LCD_CHARCELLS
#define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \
(WPS_MAX_TOKENS * sizeof(struct wps_token))
#endif
static unsigned char buffer[SKIN_BUFFER_SIZE];
static unsigned char *buffer_front = NULL; /* start of the free space,
increases with allocation*/
static unsigned char *buffer_back = NULL; /* end of the free space
decreases with allocation */
static size_t buf_size = SKIN_BUFFER_SIZE;
void skin_buffer_init(void)
{
#if 0 /* this will go in again later probably */
if (buffer == NULL)
{
buf_size = SKIN_BUFFER_SIZE;/* global_settings.skin_buf_size */
buffer = buffer_alloc(buf_size);
buffer_front = buffer;
buffer_back = bufer + buf_size;
}
else
#endif
{
/* reset the buffer.... */
buffer_front = buffer;
buffer_back = buffer + buf_size;
}
}
/* get the number of bytes currently being used */
size_t skin_buffer_usage(void)
{
return buf_size - (buffer_back-buffer_front);
}
size_t skin_buffer_freespace(void)
{
return buffer_back-buffer_front;
}
/* Allocate size bytes from the buffer
* allocates from the back end (data end)
*/
void* skin_buffer_alloc(size_t size)
{
if (skin_buffer_freespace() <= size)
{
return NULL;
}
buffer_back -= size;
/* 32-bit aligned */
buffer_back = (void *)(((unsigned long)buffer_back) & ~3);
memset(buffer_back, 0, size);
return buffer_back;
}
/* Get a pointer to the skin buffer and the count of how much is free
* used to do your own buffer management.
* Any memory used will be overwritten next time wps_buffer_alloc()
* is called unless skin_buffer_increment() is called first
*
* This is from the start of the buffer, it is YOUR responsility to make
* sure you dont ever use more then *freespace, and bear in mind this will only
* be valid untill skin_buffer_alloc() is next called...
* so call skin_buffer_increment() and skin_buffer_freespace() regularly
*/
void* skin_buffer_grab(size_t *freespace)
{
*freespace = buf_size - skin_buffer_usage();
return buffer_front;
}
/* Use after skin_buffer_grab() to specify how much buffer was used */
void skin_buffer_increment(size_t used, bool align)
{
buffer_front += used;
if (align)
{
/* 32-bit aligned */
buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3);
}
}
/* free previously skin_buffer_increment()'ed space. This just moves the pointer
* back 'used' bytes so make sure you actually want to do this */
void skin_buffer_free_from_front(size_t used)
{
buffer_front -= used;
/* 32-bit aligned */
buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3);
}

View file

@ -1,64 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Linus Nielsen Feltzing
* Copyright (C) 2009 Jonathan Gordon
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _SKIN_BUFFER_H_
#define _SKIN_BUFFER_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* int the global buffer */
void skin_buffer_init(void);
/* get the number of bytes currently being used */
size_t skin_buffer_usage(void);
size_t skin_buffer_freespace(void);
/* Allocate size bytes from the buffer */
void* skin_buffer_alloc(size_t size);
/* Get a pointer to the skin buffer and the count of how much is free
* used to do your own buffer management.
* Any memory used will be overwritten next time wps_buffer_alloc()
* is called unless skin_buffer_increment() is called first
*
* This is from the start of the buffer, it is YOUR responsility to make
* sure you dont ever use more then *freespace, and bear in mind this will only
* be valid untill skin_buffer_alloc() is next called...
* so call skin_buffer_increment() and skin_buffer_freespace() regularly
*/
void* skin_buffer_grab(size_t *freespace);
/* Use after skin_buffer_grab() to specify how much buffer was used.
* align should always be true unless there is a possibility that you will need
* more space *immediatly* after the previous allocation. (i.e in an array).
* NEVER leave the buffer unaligned */
void skin_buffer_increment(size_t used, bool align);
/* free previously skin_buffer_increment()'ed space. This just moves the pointer
* back 'used' bytes so make sure you actually want to do this */
void skin_buffer_free_from_front(size_t used);
#endif /* _SKIN_BUFFER_H_ */

View file

@ -69,25 +69,22 @@
#include "skin_engine.h" #include "skin_engine.h"
#include "statusbar-skinned.h" #include "statusbar-skinned.h"
static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode); void skin_render(struct gui_wps *gwps, unsigned refresh_mode);
/* update a skinned screen, update_type is WPS_REFRESH_* values. /* update a skinned screen, update_type is WPS_REFRESH_* values.
* Usually it should only be WPS_REFRESH_NON_STATIC * Usually it should only be WPS_REFRESH_NON_STATIC
* A full update will be done if required (state.do_full_update == true) * A full update will be done if required (state.do_full_update == true)
*/ */
bool skin_update(struct gui_wps *gwps, unsigned int update_type) void skin_update(struct gui_wps *gwps, unsigned int update_type)
{ {
bool retval; /* This maybe shouldnt be here,
/* This maybe shouldnt be here, but while the skin is only used to * This is also safe for skined screen which dont use the id3 */
* display the music screen this is better than whereever we are being
* called from. This is also safe for skined screen which dont use the id3 */
struct mp3entry *id3 = gwps->state->id3; struct mp3entry *id3 = gwps->state->id3;
bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false); bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false);
gwps->sync_data->do_full_update |= cuesheet_update; gwps->sync_data->do_full_update |= cuesheet_update;
retval = skin_redraw(gwps, gwps->sync_data->do_full_update ? skin_render(gwps, gwps->sync_data->do_full_update ?
WPS_REFRESH_ALL : update_type); SKIN_REFRESH_ALL : update_type);
return retval;
} }
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
@ -124,8 +121,7 @@ void skin_statusbar_changed(struct gui_wps *skin)
} }
} }
static void draw_progressbar(struct gui_wps *gwps, void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
struct progressbar *pb)
{ {
struct screen *display = gwps->display; struct screen *display = gwps->display;
struct viewport *vp = pb->vp; struct viewport *vp = pb->vp;
@ -143,17 +139,17 @@ static void draw_progressbar(struct gui_wps *gwps,
/* center the pb in the line, but only if the line is higher than the pb */ /* center the pb in the line, but only if the line is higher than the pb */
int center = (line_height-height)/2; int center = (line_height-height)/2;
/* if Y was not set calculate by font height,Y is -line_number-1 */ /* if Y was not set calculate by font height,Y is -line_number-1 */
y = (-y -1)*line_height + (0 > center ? 0 : center); y = line*line_height + (0 > center ? 0 : center);
} }
if (pb->type == WPS_TOKEN_VOLUMEBAR) if (pb->type == SKIN_TOKEN_VOLUMEBAR)
{ {
int minvol = sound_min(SOUND_VOLUME); int minvol = sound_min(SOUND_VOLUME);
int maxvol = sound_max(SOUND_VOLUME); int maxvol = sound_max(SOUND_VOLUME);
length = maxvol-minvol; length = maxvol-minvol;
elapsed = global_settings.volume-minvol; elapsed = global_settings.volume-minvol;
} }
else if (pb->type == WPS_TOKEN_BATTERY_PERCENTBAR) else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR)
{ {
length = 100; length = 100;
elapsed = battery_level(); elapsed = battery_level();
@ -185,7 +181,7 @@ static void draw_progressbar(struct gui_wps *gwps,
gui_scrollbar_draw(display, pb->x, y, pb->width, height, gui_scrollbar_draw(display, pb->x, y, pb->width, height,
length, 0, elapsed, HORIZONTAL); length, 0, elapsed, HORIZONTAL);
if (pb->type == WPS_TOKEN_PROGRESSBAR) if (pb->type == SKIN_TOKEN_PROGRESSBAR)
{ {
if (id3 && id3->length) if (id3 && id3->length)
{ {
@ -208,8 +204,7 @@ static void draw_progressbar(struct gui_wps *gwps,
} }
} }
static void draw_playlist_viewer_list(struct gui_wps *gwps, void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer)
struct playlistviewer *viewer)
{ {
struct wps_state *state = gwps->state; struct wps_state *state = gwps->state;
int lines = viewport_get_nb_lines(viewer->vp); int lines = viewport_get_nb_lines(viewer->vp);
@ -217,8 +212,9 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
int cur_pos, max; int cur_pos, max;
int start_item; int start_item;
int i; int i;
struct wps_token token; bool scroll = false;
int x, length, alignment = WPS_TOKEN_ALIGN_LEFT; struct wps_token *token;
int x, length, alignment = SKIN_TOKEN_ALIGN_LEFT;
struct mp3entry *pid3; struct mp3entry *pid3;
char buf[MAX_PATH*2], tempbuf[MAX_PATH]; char buf[MAX_PATH*2], tempbuf[MAX_PATH];
@ -281,51 +277,58 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
} }
line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO; line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO;
} }
int j = 0, cur_string = 0;
unsigned int line_len = 0; unsigned int line_len = 0;
if (viewer->lines[line]->children_count == 0)
return;
struct skin_element *element = viewer->lines[line]->children[0];
buf[0] = '\0'; buf[0] = '\0';
while (j < viewer->lines[line].count && line_len < sizeof(buf)) while (element && line_len < sizeof(buf))
{ {
const char *out = NULL; const char *out = NULL;
token.type = viewer->lines[line].tokens[j]; if (element->type == TEXT)
token.value.i = 0; {
token.next = false; line_len = strlcat(buf, (char*)element->data, sizeof(buf));
out = get_id3_token(&token, pid3, tempbuf, sizeof(tempbuf), -1, NULL); element = element->next;
continue;
}
if (element->type != TAG)
{
element = element->next;
continue;
}
if (element->tag->type == SKIN_TOKEN_SUBLINE_SCROLL)
scroll = true;
token = (struct wps_token*)element->data;
out = get_id3_token(token, pid3, tempbuf, sizeof(tempbuf), -1, NULL);
#if CONFIG_TUNER #if CONFIG_TUNER
if (!out) if (!out)
out = get_radio_token(&token, i-cur_pos, out = get_radio_token(token, i-cur_pos,
tempbuf, sizeof(tempbuf), -1, NULL); tempbuf, sizeof(tempbuf), -1, NULL);
#endif #endif
if (out) if (out)
{ {
line_len = strlcat(buf, out, sizeof(buf)); line_len = strlcat(buf, out, sizeof(buf));
j++; element = element->next;
continue; continue;
} }
switch (viewer->lines[line].tokens[j]) switch (token->type)
{ {
case WPS_TOKEN_ALIGN_CENTER: case SKIN_TOKEN_ALIGN_CENTER:
case WPS_TOKEN_ALIGN_LEFT: case SKIN_TOKEN_ALIGN_LEFT:
case WPS_TOKEN_ALIGN_LEFT_RTL: case SKIN_TOKEN_ALIGN_LEFT_RTL:
case WPS_TOKEN_ALIGN_RIGHT: case SKIN_TOKEN_ALIGN_RIGHT:
case WPS_TOKEN_ALIGN_RIGHT_RTL: case SKIN_TOKEN_ALIGN_RIGHT_RTL:
alignment = viewer->lines[line].tokens[j]; alignment = token->type;
tempbuf[0] = '\0'; tempbuf[0] = '\0';
break; break;
case WPS_TOKEN_STRING: case SKIN_TOKEN_PLAYLIST_POSITION:
case WPS_TOKEN_CHARACTER:
snprintf(tempbuf, sizeof(tempbuf), "%s",
viewer->lines[line].strings[cur_string]);
cur_string++;
break;
case WPS_TOKEN_PLAYLIST_POSITION:
snprintf(tempbuf, sizeof(tempbuf), "%d", i); snprintf(tempbuf, sizeof(tempbuf), "%d", i);
break; break;
case WPS_TOKEN_FILE_NAME: case SKIN_TOKEN_FILE_NAME:
get_dir(tempbuf, sizeof(tempbuf), filename, 0); get_dir(tempbuf, sizeof(tempbuf), filename, 0);
break; break;
case WPS_TOKEN_FILE_PATH: case SKIN_TOKEN_FILE_PATH:
snprintf(tempbuf, sizeof(tempbuf), "%s", filename); snprintf(tempbuf, sizeof(tempbuf), "%s", filename);
break; break;
default: default:
@ -336,12 +339,12 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
{ {
line_len = strlcat(buf, tempbuf, sizeof(buf)); line_len = strlcat(buf, tempbuf, sizeof(buf));
} }
j++; element = element->next;
} }
int vpwidth = viewer->vp->width; int vpwidth = viewer->vp->width;
length = gwps->display->getstringsize(buf, NULL, NULL); length = gwps->display->getstringsize(buf, NULL, NULL);
if (viewer->lines[line].scroll && length >= vpwidth) if (scroll && length >= vpwidth)
{ {
gwps->display->puts_scroll(0, (i-start_item), buf ); gwps->display->puts_scroll(0, (i-start_item), buf );
} }
@ -353,25 +356,25 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
{ {
switch (alignment) switch (alignment)
{ {
case WPS_TOKEN_ALIGN_CENTER: case SKIN_TOKEN_ALIGN_CENTER:
x = (vpwidth-length)/2; x = (vpwidth-length)/2;
break; break;
case WPS_TOKEN_ALIGN_LEFT_RTL: case SKIN_TOKEN_ALIGN_LEFT_RTL:
if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) if (lang_is_rtl() && VP_IS_RTL(viewer->vp))
{ {
x = vpwidth - length; x = vpwidth - length;
break; break;
} }
case WPS_TOKEN_ALIGN_LEFT: case SKIN_TOKEN_ALIGN_LEFT:
x = 0; x = 0;
break; break;
case WPS_TOKEN_ALIGN_RIGHT_RTL: case SKIN_TOKEN_ALIGN_RIGHT_RTL:
if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) if (lang_is_rtl() && VP_IS_RTL(viewer->vp))
{ {
x = 0; x = 0;
break; break;
} }
case WPS_TOKEN_ALIGN_RIGHT: case SKIN_TOKEN_ALIGN_RIGHT:
x = vpwidth - length; x = vpwidth - length;
break; break;
default: default:
@ -386,7 +389,7 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
/* clears the area where the image was shown */ /* clears the area where the image was shown */
static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) void clear_image_pos(struct gui_wps *gwps, struct gui_img *img)
{ {
if(!gwps) if(!gwps)
return; return;
@ -395,7 +398,7 @@ static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img)
gwps->display->set_drawmode(DRMODE_SOLID); gwps->display->set_drawmode(DRMODE_SOLID);
} }
static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage) void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage)
{ {
struct screen *display = gwps->display; struct screen *display = gwps->display;
if(img->always_display) if(img->always_display)
@ -423,7 +426,8 @@ static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subima
#endif #endif
} }
static void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
{ {
if(!gwps || !gwps->data || !gwps->display) if(!gwps || !gwps->data || !gwps->display)
return; return;
@ -451,18 +455,10 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
#ifdef HAVE_ALBUMART #ifdef HAVE_ALBUMART
/* now draw the AA */ /* now draw the AA */
if (data->albumart && data->albumart->vp == vp if (data->albumart && data->albumart->vp == vp
&& data->albumart->draw) && data->albumart->draw_handle >= 0)
{ {
int handle = playback_current_aa_hid(data->playback_aa_slot); draw_album_art(gwps, data->albumart->draw_handle, false);
#if CONFIG_TUNER data->albumart->draw_handle = -1;
if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
{
struct dim dim = {data->albumart->width, data->albumart->height};
handle = radio_get_art_hid(&dim);
}
#endif
draw_album_art(gwps, handle, false);
data->albumart->draw = false;
} }
#endif #endif
@ -471,7 +467,7 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
#else /* HAVE_LCD_CHARCELL */ #else /* HAVE_LCD_CHARCELL */
static bool draw_player_progress(struct gui_wps *gwps) bool draw_player_progress(struct gui_wps *gwps)
{ {
struct wps_state *state = gwps->state; struct wps_state *state = gwps->state;
struct screen *display = gwps->display; struct screen *display = gwps->display;
@ -508,7 +504,7 @@ static bool draw_player_progress(struct gui_wps *gwps)
return true; return true;
} }
static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size) void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
{ {
static const unsigned char numbers[10][4] = { static const unsigned char numbers[10][4] = {
{0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */ {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
@ -613,44 +609,25 @@ static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
#endif /* HAVE_LCD_CHARCELL */ #endif /* HAVE_LCD_CHARCELL */
/* Return the index to the end token for the conditional token at index.
The conditional token can be either a start token or a separator
(i.e. option) token.
*/
static int find_conditional_end(struct wps_data *data, int index)
{
int ret = index;
while (data->tokens[ret].type != WPS_TOKEN_CONDITIONAL_END)
ret = data->tokens[ret].value.i;
/* ret now is the index to the end token for the conditional. */
return ret;
}
/* Evaluate the conditional that is at *token_index and return whether a skip /* Evaluate the conditional that is at *token_index and return whether a skip
has ocurred. *token_index is updated with the new position. has ocurred. *token_index is updated with the new position.
*/ */
static bool evaluate_conditional(struct gui_wps *gwps, int *token_index) int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options)
{ {
if (!gwps) if (!gwps)
return false; return false;
struct wps_data *data = gwps->data;
int i, cond_end;
int cond_index = *token_index;
char result[128]; char result[128];
const char *value; const char *value;
unsigned char num_options = data->tokens[cond_index].value.i & 0xFF;
unsigned char prev_val = (data->tokens[cond_index].value.i & 0xFF00) >> 8;
/* treat ?xx<true> constructs as if they had 2 options. */ /* treat ?xx<true> constructs as if they had 2 options.
* (i.e ?xx<true|false>) */
if (num_options < 2) if (num_options < 2)
num_options = 2; num_options = 2;
int intval = num_options; int intval = num_options;
/* get_token_value needs to know the number of options in the enum */ /* get_token_value needs to know the number of options in the enum */
value = get_token_value(gwps, &data->tokens[cond_index + 1], value = get_token_value(gwps, conditional->token,
result, sizeof(result), &intval); result, sizeof(result), &intval);
/* intval is now the number of the enum option we want to read, /* intval is now the number of the enum option we want to read,
@ -660,333 +637,17 @@ static bool evaluate_conditional(struct gui_wps *gwps, int *token_index)
else if (intval > num_options || intval < 1) else if (intval > num_options || intval < 1)
intval = num_options; intval = num_options;
data->tokens[cond_index].value.i = (intval << 8) + num_options; conditional->last_value = intval -1;
return intval -1;
/* skip to the appropriate enum case */
int next = cond_index + 2;
for (i = 1; i < intval; i++)
{
next = data->tokens[next].value.i;
}
*token_index = next;
if (prev_val == intval)
{
/* Same conditional case as previously. Return without clearing the
pictures */
return false;
}
cond_end = find_conditional_end(data, cond_index + 2);
for (i = cond_index + 3; i < cond_end; i++)
{
#ifdef HAVE_LCD_BITMAP
/* clear all pictures in the conditional and nested ones */
if (data->tokens[i].type == WPS_TOKEN_IMAGE_PRELOAD_DISPLAY)
clear_image_pos(gwps, find_image(data->tokens[i].value.i&0xFF, data));
else if (data->tokens[i].type == WPS_TOKEN_VOLUMEBAR ||
data->tokens[i].type == WPS_TOKEN_PROGRESSBAR ||
data->tokens[i].type == WPS_TOKEN_BATTERY_PERCENTBAR )
{
struct progressbar *bar = (struct progressbar*)data->tokens[i].value.data;
bar->draw = false;
}
else if (data->tokens[i].type == WPS_TOKEN_PEAKMETER)
{
data->peak_meter_enabled = false;
}
#endif
#ifdef HAVE_ALBUMART
if (data->albumart && data->tokens[i].type == WPS_TOKEN_ALBUMART_DISPLAY)
{
draw_album_art(gwps,
playback_current_aa_hid(data->playback_aa_slot), true);
data->albumart->draw = false;
}
#endif
}
return true;
} }
/* Read a (sub)line to the given alignment format buffer.
linebuf is the buffer where the data is actually stored.
align is the alignment format that'll be used to display the text.
The return value indicates whether the line needs to be updated.
*/
static bool get_line(struct gui_wps *gwps,
struct skin_subline *subline,
struct align_pos *align,
char *linebuf,
int linebuf_size,
unsigned refresh_mode)
{
struct wps_data *data = gwps->data;
char temp_buf[128];
char *buf = linebuf; /* will always point to the writing position */
char *linebuf_end = linebuf + linebuf_size - 1;
bool update = false;
int i;
(void)refresh_mode; /* silence warning on charcell */
/* alignment-related variables */
int cur_align;
char* cur_align_start;
cur_align_start = buf;
cur_align = WPS_ALIGN_LEFT;
align->left = NULL;
align->center = NULL;
align->right = NULL;
/* Process all tokens of the desired subline */
for (i = subline->first_token_idx;
i <= subline->last_token_idx; i++)
{
switch(data->tokens[i].type)
{
case WPS_TOKEN_CONDITIONAL:
/* place ourselves in the right conditional case */
update |= evaluate_conditional(gwps, &i);
break;
case WPS_TOKEN_CONDITIONAL_OPTION:
/* we've finished in the curent conditional case,
skip to the end of the conditional structure */
i = find_conditional_end(data, i);
break;
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
case WPS_TOKEN_VIEWPORT_FGCOLOUR:
{
struct viewport_colour *col = data->tokens[i].value.data;
col->vp->fg_pattern = col->colour;
}
break;
case WPS_TOKEN_VIEWPORT_BGCOLOUR:
{
struct viewport_colour *col = data->tokens[i].value.data;
col->vp->bg_pattern = col->colour;
}
break;
#endif
#ifdef HAVE_LCD_BITMAP
case WPS_TOKEN_PEAKMETER:
data->peak_meter_enabled = true;
break;
case WPS_TOKEN_VOLUMEBAR:
case WPS_TOKEN_BATTERY_PERCENTBAR:
case WPS_TOKEN_PROGRESSBAR:
{
struct progressbar *bar = (struct progressbar*)data->tokens[i].value.data;
bar->draw = true;
}
break;
case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY:
{
char n = data->tokens[i].value.i & 0xFF;
int subimage = data->tokens[i].value.i >> 8;
struct gui_img *img = find_image(n, data);
if (img && img->loaded)
img->display = subimage;
break;
}
case WPS_TOKEN_DRAW_INBUILTBAR:
gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]),
refresh_mode == WPS_REFRESH_ALL,
data->tokens[i].value.data);
break;
#endif
case WPS_TOKEN_ALIGN_LEFT:
case WPS_TOKEN_ALIGN_LEFT_RTL:
case WPS_TOKEN_ALIGN_CENTER:
case WPS_TOKEN_ALIGN_RIGHT:
case WPS_TOKEN_ALIGN_RIGHT_RTL:
/* remember where the current aligned text started */
switch (cur_align)
{
case WPS_ALIGN_LEFT:
align->left = cur_align_start;
break;
case WPS_ALIGN_CENTER:
align->center = cur_align_start;
break;
case WPS_ALIGN_RIGHT:
align->right = cur_align_start;
break;
}
/* start a new alignment */
switch (data->tokens[i].type)
{
case WPS_TOKEN_ALIGN_LEFT:
cur_align = WPS_ALIGN_LEFT;
break;
case WPS_TOKEN_ALIGN_LEFT_RTL:
cur_align = lang_is_rtl() ? WPS_ALIGN_RIGHT :
WPS_ALIGN_LEFT;
break;
case WPS_TOKEN_ALIGN_CENTER:
cur_align = WPS_ALIGN_CENTER;
break;
case WPS_TOKEN_ALIGN_RIGHT:
cur_align = WPS_ALIGN_RIGHT;
break;
case WPS_TOKEN_ALIGN_RIGHT_RTL:
cur_align = lang_is_rtl() ? WPS_ALIGN_LEFT :
WPS_ALIGN_RIGHT;
break;
default:
break;
}
*buf++ = 0;
cur_align_start = buf;
break;
case WPS_VIEWPORT_ENABLE:
{
char label = data->tokens[i].value.i;
char temp = VP_DRAW_HIDEABLE;
/* viewports are allowed to share id's so find and enable
* all of them */
struct skin_token_list *list = data->viewports;
while (list)
{
struct skin_viewport *vp =
(struct skin_viewport *)list->token->value.data;
if (vp->label == label)
{
if (vp->hidden_flags&VP_DRAW_WASHIDDEN)
temp |= VP_DRAW_WASHIDDEN;
vp->hidden_flags = temp;
}
list = list->next;
}
}
break;
#ifdef HAVE_LCD_BITMAP
case WPS_TOKEN_UIVIEWPORT_ENABLE:
sb_set_info_vp(gwps->display->screen_type,
data->tokens[i].value.i|VP_INFO_LABEL);
break;
case WPS_VIEWPORT_CUSTOMLIST:
draw_playlist_viewer_list(gwps, data->tokens[i].value.data);
break;
#endif
default:
{
/* get the value of the tag and copy it to the buffer */
const char *value = get_token_value(gwps, &data->tokens[i],
temp_buf, sizeof(temp_buf), NULL);
if (value)
{
update = true;
while (*value && (buf < linebuf_end))
*buf++ = *value++;
}
break;
}
}
}
/* close the current alignment */
switch (cur_align)
{
case WPS_ALIGN_LEFT:
align->left = cur_align_start;
break;
case WPS_ALIGN_CENTER:
align->center = cur_align_start;
break;
case WPS_ALIGN_RIGHT:
align->right = cur_align_start;
break;
}
return update;
}
static void get_subline_timeout(struct gui_wps *gwps, struct skin_subline *subline)
{
struct wps_data *data = gwps->data;
int i;
subline->time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER;
for (i = subline->first_token_idx;
i <= subline->last_token_idx; i++)
{
switch(data->tokens[i].type)
{
case WPS_TOKEN_CONDITIONAL:
/* place ourselves in the right conditional case */
evaluate_conditional(gwps, &i);
break;
case WPS_TOKEN_CONDITIONAL_OPTION:
/* we've finished in the curent conditional case,
skip to the end of the conditional structure */
i = find_conditional_end(data, i);
break;
case WPS_TOKEN_SUBLINE_TIMEOUT:
subline->time_mult = data->tokens[i].value.i;
break;
default:
break;
}
}
}
/* Calculates which subline should be displayed for the specified line
Returns true iff the subline must be refreshed */
static bool update_curr_subline(struct gui_wps *gwps, struct skin_line *line)
{
/* shortcut this whole thing if we need to reset the line completly */
if (line->curr_subline == NULL)
{
line->subline_expire_time = current_tick;
line->curr_subline = &line->sublines;
if (!line->curr_subline->next)
{
line->subline_expire_time += 100*HZ;
}
else
{
get_subline_timeout(gwps, line->curr_subline);
line->subline_expire_time += TIMEOUT_UNIT*line->curr_subline->time_mult;
}
return true;
}
/* if time to advance to next sub-line */
if (TIME_AFTER(current_tick, line->subline_expire_time - 1))
{
/* if there is only one subline, there is no need to search for a new one */
if (&line->sublines == line->curr_subline &&
line->curr_subline->next == NULL)
{
line->subline_expire_time += 100 * HZ;
return false;
}
if (line->curr_subline->next)
line->curr_subline = line->curr_subline->next;
else
line->curr_subline = &line->sublines;
get_subline_timeout(gwps, line->curr_subline);
line->subline_expire_time = current_tick + TIMEOUT_UNIT*line->curr_subline->time_mult;
return true;
}
return false;
}
/* Display a line appropriately according to its alignment format. /* Display a line appropriately according to its alignment format.
format_align contains the text, separated between left, center and right. format_align contains the text, separated between left, center and right.
line is the index of the line on the screen. line is the index of the line on the screen.
scroll indicates whether the line is a scrolling one or not. scroll indicates whether the line is a scrolling one or not.
*/ */
static void write_line(struct screen *display, void write_line(struct screen *display,
struct align_pos *format_align, struct align_pos *format_align,
int line, int line,
bool scroll) bool scroll)
@ -1143,244 +804,30 @@ static void write_line(struct screen *display,
} }
} }
static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode) #ifdef HAVE_LCD_BITMAP
void draw_peakmeters(struct gui_wps *gwps, int line_number,
struct viewport *viewport)
{ {
struct wps_data *data = gwps->data; struct wps_data *data = gwps->data;
struct screen *display = gwps->display; if (!data->peak_meter_enabled)
if (!data || !display || !gwps->state)
return false;
unsigned flags;
char linebuf[MAX_PATH];
struct align_pos align;
align.left = NULL;
align.center = NULL;
align.right = NULL;
struct skin_token_list *viewport_list;
bool update_line, new_subline_refresh;
/* reset to first subline if refresh all flag is set */
if (refresh_mode == WPS_REFRESH_ALL)
{ {
struct skin_line *line; peak_meter_enable(false);
struct skin_viewport *skin_viewport = find_viewport(VP_DEFAULT_LABEL, data); }
else
{
int h = font_get(viewport->font)->height;
int peak_meter_y = line_number * h;
if (!(skin_viewport->hidden_flags & VP_NEVER_VISIBLE)) /* The user might decide to have the peak meter in the last
{ line so that it is only displayed if no status bar is
display->set_viewport(&skin_viewport->vp); visible. If so we neither want do draw nor enable the
display->clear_viewport(); peak meter. */
} if (peak_meter_y + h <= viewport->y+viewport->height) {
peak_meter_enable(true);
for (viewport_list = data->viewports; peak_meter_screen(gwps->display, 0, peak_meter_y,
viewport_list; viewport_list = viewport_list->next) MIN(h, viewport->y+viewport->height - peak_meter_y));
{
skin_viewport =
(struct skin_viewport *)viewport_list->token->value.data;
for(line = skin_viewport->lines; line; line = line->next)
{
line->curr_subline = NULL;
}
} }
} }
#ifdef HAVE_LCD_CHARCELLS
int i;
for (i = 0; i < 8; i++)
{
if (data->wps_progress_pat[i] == 0)
data->wps_progress_pat[i] = display->get_locked_pattern();
}
#endif
/* disable any viewports which are conditionally displayed.
* If we are only refreshing the peak meter then don't change the viewport
* enabled flags as this will stop scrolling. viewports cant be
* toggled in this refresh mode anyway (FS#10215)*/
if (refresh_mode != WPS_REFRESH_PEAK_METER)
{
for (viewport_list = data->viewports;
viewport_list; viewport_list = viewport_list->next)
{
struct skin_viewport *skin_viewport =
(struct skin_viewport *)viewport_list->token->value.data;
if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
{
continue;
}
if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE)
{
if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN)
skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
else
skin_viewport->hidden_flags |= VP_DRAW_HIDDEN;
}
}
}
for (viewport_list = data->viewports;
viewport_list; viewport_list = viewport_list->next)
{
struct skin_viewport *skin_viewport =
(struct skin_viewport *)viewport_list->token->value.data;
unsigned vp_refresh_mode = refresh_mode;
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour;
skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour;
#endif
display->set_viewport(&skin_viewport->vp);
int hidden_vp = 0;
#ifdef HAVE_LCD_BITMAP
/* Set images to not to be displayed */
struct skin_token_list *imglist = data->images;
while (imglist)
{
struct gui_img *img = (struct gui_img *)imglist->token->value.data;
img->display = -1;
imglist = imglist->next;
}
#endif
/* dont redraw the viewport if its disabled */
if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
{ /* don't draw anything into this one */
vp_refresh_mode = 0; hidden_vp = true;
}
else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN))
{
if (!(skin_viewport->hidden_flags&VP_DRAW_WASHIDDEN))
display->scroll_stop(&skin_viewport->vp);
skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
continue;
}
else if (((skin_viewport->hidden_flags&
(VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))
== (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)))
{
vp_refresh_mode = WPS_REFRESH_ALL;
skin_viewport->hidden_flags = VP_DRAW_HIDEABLE;
}
if (vp_refresh_mode == WPS_REFRESH_ALL)
{
display->clear_viewport();
}
/* loop over the lines for this viewport */
struct skin_line *line;
/* %V() doesnt eat the \n which means the first line of text
* is actually going to be one line down. so set line_count to -1
* unless we are using the default viewport which doesnt have this problem */
int line_count = skin_viewport->label==VP_DEFAULT_LABEL?0:-1;
for (line = skin_viewport->lines; line; line = line->next, line_count++)
{
struct skin_subline *subline;
memset(linebuf, 0, sizeof(linebuf));
update_line = false;
/* get current subline for the line */
new_subline_refresh = update_curr_subline(gwps, line);
subline = line->curr_subline;
flags = line->curr_subline->line_type;
if (vp_refresh_mode == WPS_REFRESH_ALL || (flags & vp_refresh_mode)
|| new_subline_refresh || hidden_vp)
{
/* get_line tells us if we need to update the line */
update_line = get_line(gwps, subline, &align,
linebuf, sizeof(linebuf), vp_refresh_mode);
}
#ifdef HAVE_LCD_BITMAP
/* peakmeter */
if (flags & vp_refresh_mode & WPS_REFRESH_PEAK_METER)
{
if (!data->peak_meter_enabled)
{
peak_meter_enable(false);
}
else
{
/* the peakmeter should be alone on its line */
update_line = false;
int h = font_get(skin_viewport->vp.font)->height;
int peak_meter_y = line_count* h;
/* The user might decide to have the peak meter in the last
line so that it is only displayed if no status bar is
visible. If so we neither want do draw nor enable the
peak meter. */
if (peak_meter_y + h <= skin_viewport->vp.y+skin_viewport->vp.height) {
peak_meter_enable(true);
peak_meter_screen(gwps->display, 0, peak_meter_y,
MIN(h, skin_viewport->vp.y+skin_viewport->vp.height - peak_meter_y));
}
}
}
#else /* HAVE_LCD_CHARCELL */
/* progressbar */
if (flags & vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
{
if (data->full_line_progressbar)
draw_player_fullbar(gwps, linebuf, sizeof(linebuf));
else
draw_player_progress(gwps);
}
#endif
if (line_count>= 0 && update_line && !hidden_vp &&
/* conditionals clear the line which means if the %Vd is put into the default
viewport there will be a blank line.
To get around this we dont allow any actual drawing to happen in the
deault vp if other vp's are defined */
((skin_viewport->label != VP_DEFAULT_LABEL && viewport_list->next) ||
!viewport_list->next))
{
if (flags & WPS_REFRESH_SCROLL)
{
/* if the line is a scrolling one we don't want to update
too often, so that it has the time to scroll */
if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh)
write_line(display, &align, line_count, true);
}
else
write_line(display, &align, line_count, false);
}
}
#ifdef HAVE_LCD_BITMAP
/* progressbar */
if (vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
{
struct skin_token_list *bar = gwps->data->progressbars;
while (bar)
{
struct progressbar *thisbar = (struct progressbar*)bar->token->value.data;
if (thisbar->vp == &skin_viewport->vp && thisbar->draw)
{
draw_progressbar(gwps, thisbar);
}
bar = bar->next;
}
}
/* Now display any images in this viewport */
if (!hidden_vp)
wps_display_images(gwps, &skin_viewport->vp);
#endif
}
/* Restore the default viewport */
display->set_viewport(NULL);
display->update();
return true;
} }
bool skin_has_sbs(enum screen_type screen, struct wps_data *data) bool skin_has_sbs(enum screen_type screen, struct wps_data *data)
@ -1396,6 +843,7 @@ bool skin_has_sbs(enum screen_type screen, struct wps_data *data)
#endif #endif
return draw; return draw;
} }
#endif
/* do the button loop as often as required for the peak meters to update /* do the button loop as often as required for the peak meters to update
* with a good refresh rate. * with a good refresh rate.
@ -1434,7 +882,7 @@ int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout)
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
{ {
if(gwps[i].data->peak_meter_enabled) if(gwps[i].data->peak_meter_enabled)
skin_update(&gwps[i], WPS_REFRESH_PEAK_METER); skin_update(&gwps[i], SKIN_REFRESH_PEAK_METER);
next_refresh += HZ / PEAK_METER_FPS; next_refresh += HZ / PEAK_METER_FPS;
} }
} }

View file

@ -0,0 +1,59 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002-2007 Björn Stenberg
* Copyright (C) 2007-2008 Nicolas Pennequin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include <stdio.h>
#include "wps_internals.h"
#include "skin_engine.h"
#include "statusbar-skinned.h"
#ifndef _SKIN_DISPLAY_H_
#define _SKIN_DISPLAY_H_
#ifdef HAVE_LCD_BITMAP
void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb);
void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer);
/* clears the area where the image was shown */
void clear_image_pos(struct gui_wps *gwps, struct gui_img *img);
void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage);
void wps_display_images(struct gui_wps *gwps, struct viewport* vp);
#else
bool draw_player_progress(struct gui_wps *gwps);
void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size);
#endif
/* Evaluate the conditional that is at *token_index and return whether a skip
has ocurred. *token_index is updated with the new position.
*/
int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options);
/* Display a line appropriately according to its alignment format.
format_align contains the text, separated between left, center and right.
line is the index of the line on the screen.
scroll indicates whether the line is a scrolling one or not.
*/
void write_line(struct screen *display,
struct align_pos *format_align,
int line,
bool scroll);
void draw_peakmeters(struct gui_wps *gwps, int line_number,
struct viewport *viewport);
#endif

View file

@ -23,7 +23,10 @@
#ifndef _SKIN_ENGINE_H #ifndef _SKIN_ENGINE_H
#define _SKIN_ENGINE_H #define _SKIN_ENGINE_H
#include "skin_buffer.h" #ifndef PLUGIN
#include "skin_fonts.h"
#include "tag_table.h"
#include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */ #include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */
@ -39,13 +42,37 @@ enum skinnable_screens {
}; };
#ifdef HAVE_LCD_BITMAP
#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
+ (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES))
#if (NB_SCREENS > 1)
#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
+ (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES))
#else
#define REMOTE_BUFFER 0
#endif
#define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER + SKIN_FONT_SIZE) + \
(WPS_MAX_TOKENS * \
(sizeof(struct wps_token) + (sizeof(struct skin_element))))
#endif
#ifdef HAVE_LCD_CHARCELLS
#define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \
(WPS_MAX_TOKENS * \
(sizeof(struct wps_token) + (sizeof(struct skin_element))))
#endif
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
int skin_get_touchaction(struct wps_data *data, int* edge_offset); int skin_get_touchaction(struct wps_data *data, int* edge_offset);
void skin_disarm_touchregions(struct wps_data *data); void skin_disarm_touchregions(struct wps_data *data);
#endif #endif
/* Do a update_type update of the skinned screen */ /* Do a update_type update of the skinned screen */
bool skin_update(struct gui_wps *gwps, unsigned int update_type); void skin_update(struct gui_wps *gwps, unsigned int update_type);
/* /*
* setup up the skin-data from a format-buffer (isfile = false) * setup up the skin-data from a format-buffer (isfile = false)
@ -72,3 +99,5 @@ void skin_backdrop_init(void);
*/ */
int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout); int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout);
#endif #endif
#endif

View file

@ -88,7 +88,7 @@ int skin_font_load(char* font_name)
pf = &font->font; pf = &font->font;
if (!font->buffer) if (!font->buffer)
{ {
pf->buffer_start = skin_buffer_alloc(SKIN_FONT_SIZE); pf->buffer_start = (char*)skin_buffer_alloc(SKIN_FONT_SIZE);
if (!pf->buffer_start) if (!pf->buffer_start)
return -1; return -1;
font->buffer = pf->buffer_start; font->buffer = pf->buffer_start;

View file

@ -27,7 +27,6 @@
#include "file.h" #include "file.h"
#include "settings.h" #include "settings.h"
#include "font.h" #include "font.h"
#include "skin_buffer.h"
#ifndef _SKINFONTS_H_ #ifndef _SKINFONTS_H_
#define _SKINFONTS_H_ #define _SKINFONTS_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,614 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id: skin_parser.c 26752 2010-06-10 21:22:16Z bieber $
*
* Copyright (C) 2010 Jonathan Gordon
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include "strlcat.h"
#include "config.h"
#include "kernel.h"
#ifdef HAVE_ALBUMART
#include "albumart.h"
#endif
#include "skin_display.h"
#include "skin_engine.h"
#include "skin_parser.h"
#include "tag_table.h"
#include "skin_scan.h"
#if CONFIG_TUNER
#include "radio.h"
#endif
#include "language.h"
#include "playback.h"
#define MAX_LINE 1024
struct skin_draw_info {
struct gui_wps *gwps;
struct skin_viewport *skin_vp;
int line_number;
unsigned long refresh_type;
char* cur_align_start;
struct align_pos align;
bool no_line_break;
bool line_scrolls;
bool force_redraw;
char *buf;
size_t buf_size;
};
typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info);
bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info);
static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
struct skin_element *element, struct viewport* vp)
{
#ifndef HAVE_LCD_BITMAP
(void)vp; /* silence warnings */
#endif
struct wps_token *token = (struct wps_token *)element->data;
struct wps_data *data = gwps->data;
bool do_refresh = (element->tag->flags & info->refresh_type) > 0;
switch (token->type)
{
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
{
struct viewport_colour *col = token->value.data;
col->vp->fg_pattern = col->colour;
}
break;
case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
{
struct viewport_colour *col = token->value.data;
col->vp->bg_pattern = col->colour;
}
break;
#endif
case SKIN_TOKEN_VIEWPORT_ENABLE:
{
char label = token->value.i;
char temp = VP_DRAW_HIDEABLE;
struct skin_element *viewport = gwps->data->tree;
while (viewport)
{
struct skin_viewport *skinvp = (struct skin_viewport*)viewport->data;
if (skinvp->label == label)
{
if (skinvp->hidden_flags&VP_DRAW_HIDDEN)
{
temp |= VP_DRAW_WASHIDDEN;
}
skinvp->hidden_flags = temp;
}
viewport = viewport->next;
}
}
break;
#ifdef HAVE_LCD_BITMAP
case SKIN_TOKEN_UIVIEWPORT_ENABLE:
sb_set_info_vp(gwps->display->screen_type,
token->value.i|VP_INFO_LABEL);
break;
case SKIN_TOKEN_PEAKMETER:
data->peak_meter_enabled = true;
if (do_refresh)
draw_peakmeters(gwps, info->line_number, vp);
break;
#endif
case SKIN_TOKEN_VOLUMEBAR:
case SKIN_TOKEN_BATTERY_PERCENTBAR:
case SKIN_TOKEN_PROGRESSBAR:
{
#ifdef HAVE_LCD_BITMAP
struct progressbar *bar = (struct progressbar*)token->value.data;
if (do_refresh)
draw_progressbar(gwps, info->line_number, bar);
#else /* HAVE_LCD_CHARCELL */
if (do_refresh)
{
if (data->full_line_progressbar)
draw_player_fullbar(gwps, info->buf, info->buf_size);
else
draw_player_progress(gwps);
}
#endif
}
break;
#ifdef HAVE_LCD_BITMAP
case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
{
char n = token->value.i & 0xFF;
int subimage = token->value.i >> 8;
struct gui_img *img = find_image(n, data);
if (img && img->loaded)
img->display = subimage;
break;
}
#ifdef HAVE_ALBUMART
case SKIN_TOKEN_ALBUMART_DISPLAY:
/* now draw the AA */
if (data->albumart)
{
int handle = playback_current_aa_hid(data->playback_aa_slot);
#if CONFIG_TUNER
if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
{
struct dim dim = {data->albumart->width, data->albumart->height};
handle = radio_get_art_hid(&dim);
}
#endif
data->albumart->draw_handle = handle;
}
break;
#endif
case SKIN_TOKEN_DRAW_INBUILTBAR:
gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]),
info->refresh_type == SKIN_REFRESH_ALL,
token->value.data);
break;
case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
if (do_refresh)
draw_playlist_viewer_list(gwps, token->value.data);
break;
#endif /* HAVE_LCD_BITMAP */
default:
return false;
}
return true;
}
static void do_tags_in_hidden_conditional(struct skin_element* branch,
struct skin_draw_info *info)
{
#ifdef HAVE_LCD_BITMAP
struct gui_wps *gwps = info->gwps;
struct wps_data *data = gwps->data;
#endif
/* Tags here are ones which need to be "turned off" or cleared
* if they are in a conditional branch which isnt being used */
if (branch->type == LINE_ALTERNATOR)
{
int i;
for (i=0; i<branch->children_count; i++)
{
do_tags_in_hidden_conditional(branch->children[i], info);
}
}
else if (branch->type == LINE && branch->children_count)
{
struct skin_element *child = branch->children[0];
struct wps_token *token;
while (child)
{
if (child->type == CONDITIONAL)
{
int i;
for (i=0; i<child->children_count; i++)
{
do_tags_in_hidden_conditional(child->children[i], info);
}
child = child->next;
continue;
}
else if (child->type != TAG || !child->data)
{
child = child->next;
continue;
}
token = (struct wps_token *)child->data;
#ifdef HAVE_LCD_BITMAP
/* clear all pictures in the conditional and nested ones */
if (token->type == SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY)
{
struct gui_img *img = find_image(token->value.i&0xFF, data);
clear_image_pos(gwps, img);
}
else if (token->type == SKIN_TOKEN_PEAKMETER)
{
data->peak_meter_enabled = false;
}
else if (token->type == SKIN_TOKEN_VIEWPORT_ENABLE)
{
char label = token->value.i&0x7f;
struct skin_element *viewport;
for (viewport = data->tree;
viewport;
viewport = viewport->next)
{
struct skin_viewport *skin_viewport = (struct skin_viewport*)viewport->data;
if ((skin_viewport->label&0x7f) != label)
continue;
if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
{
continue;
}
if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE)
{
if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN)
skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
else
{
gwps->display->set_viewport(&skin_viewport->vp);
gwps->display->clear_viewport();
gwps->display->scroll_stop(&skin_viewport->vp);
gwps->display->set_viewport(&info->skin_vp->vp);
skin_viewport->hidden_flags |= VP_DRAW_HIDDEN;
}
}
}
}
#endif
#ifdef HAVE_ALBUMART
else if (data->albumart && token->type == SKIN_TOKEN_ALBUMART_DISPLAY)
{
draw_album_art(gwps,
playback_current_aa_hid(data->playback_aa_slot), true);
}
#endif
child = child->next;
}
}
}
static void fix_line_alignment(struct skin_draw_info *info, struct skin_element *element)
{
struct align_pos *align = &info->align;
char *cur_pos = info->cur_align_start + strlen(info->cur_align_start);
switch (element->tag->type)
{
case SKIN_TOKEN_ALIGN_LEFT:
*cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
align->left = cur_pos;
info->cur_align_start = cur_pos;
break;
case SKIN_TOKEN_ALIGN_LEFT_RTL:
*cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
if (lang_is_rtl())
align->right = cur_pos;
else
align->left = cur_pos;
info->cur_align_start = cur_pos;
break;
case SKIN_TOKEN_ALIGN_CENTER:
*cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
align->center = cur_pos;
info->cur_align_start = cur_pos;
break;
case SKIN_TOKEN_ALIGN_RIGHT:
*cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
align->right = cur_pos;
info->cur_align_start = cur_pos;
break;
case SKIN_TOKEN_ALIGN_RIGHT_RTL:
*cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
if (lang_is_rtl())
align->left = cur_pos;
else
align->right = cur_pos;
info->cur_align_start = cur_pos;
break;
default:
break;
}
}
/* Draw a LINE element onto the display */
bool skin_render_line(struct skin_element* line, struct skin_draw_info *info)
{
bool needs_update = false;
int last_value, value;
if (line->children_count == 0)
return false; /* empty line, do nothing */
struct skin_element *child = line->children[0];
struct conditional *conditional;
skin_render_func func = skin_render_line;
char tempbuf[128];
int old_refresh_mode = info->refresh_type;
while (child)
{
tempbuf[0] = '\0';
switch (child->type)
{
case CONDITIONAL:
conditional = (struct conditional*)child->data;
last_value = conditional->last_value;
value = evaluate_conditional(info->gwps, conditional, child->children_count);
if (value != 1 && value >= child->children_count)
value = child->children_count-1;
if (child->children_count == 1)
{
/* special handling so
* %?aa<true> and %?<true|false> need special handlng here */
if (value == 1) /* tag is false */
{
/* we are in a false branch of a %?aa<true> conditional */
if (last_value == 0)
do_tags_in_hidden_conditional(child->children[0], info);
break;
}
value = 0;
}
else
{
if (last_value >= 0 && value != last_value && last_value < child->children_count)
do_tags_in_hidden_conditional(child->children[last_value], info);
}
if (child->children[value]->type == LINE_ALTERNATOR)
{
func = skin_render_alternator;
}
else if (child->children[value]->type == LINE)
func = skin_render_line;
if (value != last_value)
{
info->refresh_type = SKIN_REFRESH_ALL;
info->force_redraw = true;
}
if (func(child->children[value], info))
needs_update = true;
else
needs_update = needs_update || (last_value != value);
info->refresh_type = old_refresh_mode;
break;
case TAG:
if (child->tag->flags & NOBREAK)
info->no_line_break = true;
if (child->tag->type == SKIN_TOKEN_SUBLINE_SCROLL)
info->line_scrolls = true;
fix_line_alignment(info, child);
if (!child->data)
{
break;
}
if (!do_non_text_tags(info->gwps, info, child, &info->skin_vp->vp))
{
const char *value = get_token_value(info->gwps, child->data,
tempbuf, sizeof(tempbuf), NULL);
if (value)
{
needs_update = needs_update ||
((child->tag->flags&info->refresh_type)!=0);
strlcat(info->cur_align_start, value,
info->buf_size - (info->cur_align_start-info->buf));
}
}
break;
case TEXT:
strlcat(info->cur_align_start, child->data,
info->buf_size - (info->cur_align_start-info->buf));
needs_update = needs_update ||
(info->refresh_type&SKIN_REFRESH_STATIC) != 0;
break;
case COMMENT:
default:
break;
}
child = child->next;
}
return needs_update;
}
bool skin_render_alternator(struct skin_element* element, struct skin_draw_info *info)
{
bool changed_lines = false;
struct line_alternator *alternator = (struct line_alternator*)element->data;
unsigned old_refresh = info->refresh_type;
if (info->refresh_type == SKIN_REFRESH_ALL)
{
alternator->current_line = 0;
alternator->last_change_tick = current_tick;
changed_lines = true;
}
else
{
struct skin_element *current_line = element->children[alternator->current_line];
struct line *line = (struct line *)current_line->data;
int next_change = alternator->last_change_tick + line->timeout;
if (TIME_AFTER(current_tick, next_change))
{
alternator->current_line++;
if (alternator->current_line >= element->children_count)
alternator->current_line = 0;
alternator->last_change_tick = current_tick;
changed_lines = true;
}
}
if (element->children[alternator->current_line]->children_count == 0)
{
/* skip empty sublines */
alternator->current_line++;
if (alternator->current_line >= element->children_count)
alternator->current_line = 0;
changed_lines = true;
}
if (changed_lines)
{
info->refresh_type = SKIN_REFRESH_ALL;
info->force_redraw = true;
}
bool ret = skin_render_line(element->children[alternator->current_line], info);
info->refresh_type = old_refresh;
return changed_lines || ret;
}
void skin_render_viewport(struct skin_element* viewport, struct gui_wps *gwps,
struct skin_viewport* skin_viewport, unsigned long refresh_type)
{
struct screen *display = gwps->display;
char linebuf[MAX_LINE];
skin_render_func func = skin_render_line;
struct skin_element* line = viewport;
struct skin_draw_info info = {
.gwps = gwps,
.buf = linebuf,
.buf_size = sizeof(linebuf),
.line_number = 0,
.no_line_break = false,
.line_scrolls = false,
.refresh_type = refresh_type,
.skin_vp = skin_viewport
};
struct align_pos * align = &info.align;
bool needs_update;
#ifdef HAVE_LCD_BITMAP
/* Set images to not to be displayed */
struct skin_token_list *imglist = gwps->data->images;
while (imglist)
{
struct gui_img *img = (struct gui_img *)imglist->token->value.data;
img->display = -1;
imglist = imglist->next;
}
#endif
while (line)
{
linebuf[0] = '\0';
info.no_line_break = false;
info.line_scrolls = false;
info.force_redraw = false;
info.cur_align_start = info.buf;
align->left = info.buf;
align->center = NULL;
align->right = NULL;
if (line->type == LINE_ALTERNATOR)
func = skin_render_alternator;
else if (line->type == LINE)
func = skin_render_line;
needs_update = func(line, &info);
/* only update if the line needs to be, and there is something to write */
if (refresh_type && needs_update)
{
if (info.line_scrolls)
{
/* if the line is a scrolling one we don't want to update
too often, so that it has the time to scroll */
if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw)
write_line(display, align, info.line_number, true);
}
else
write_line(display, align, info.line_number, false);
}
if (!info.no_line_break)
info.line_number++;
line = line->next;
}
#ifdef HAVE_LCD_BITMAP
wps_display_images(gwps, &skin_viewport->vp);
#endif
}
void skin_render(struct gui_wps *gwps, unsigned refresh_mode)
{
struct wps_data *data = gwps->data;
struct screen *display = gwps->display;
struct skin_element* viewport = data->tree;
struct skin_viewport* skin_viewport;
int old_refresh_mode = refresh_mode;
#ifdef HAVE_LCD_CHARCELLS
int i;
for (i = 0; i < 8; i++)
{
if (data->wps_progress_pat[i] == 0)
data->wps_progress_pat[i] = display->get_locked_pattern();
}
#endif
viewport = data->tree;
skin_viewport = (struct skin_viewport *)viewport->data;
if (skin_viewport->label == VP_DEFAULT_LABEL && viewport->next)
refresh_mode = 0;
for (viewport = data->tree;
viewport;
viewport = viewport->next)
{
/* SETUP */
skin_viewport = (struct skin_viewport*)viewport->data;
unsigned vp_refresh_mode = refresh_mode;
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour;
skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour;
#endif
/* dont redraw the viewport if its disabled */
if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
{ /* don't draw anything into this one */
vp_refresh_mode = 0;
}
else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN))
{
skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
continue;
}
else if (((skin_viewport->hidden_flags&
(VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))
== (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)))
{
vp_refresh_mode = SKIN_REFRESH_ALL;
skin_viewport->hidden_flags = VP_DRAW_HIDEABLE;
}
display->set_viewport(&skin_viewport->vp);
if ((vp_refresh_mode&SKIN_REFRESH_ALL) == SKIN_REFRESH_ALL)
{
display->clear_viewport();
}
/* render */
skin_render_viewport(viewport->children[0], gwps,
skin_viewport, vp_refresh_mode);
refresh_mode = old_refresh_mode;
}
/* Restore the default viewport */
display->set_viewport(NULL);
display->update();
}

View file

@ -167,19 +167,19 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
unsigned long elapsed = id3->elapsed + state->ff_rewind_count; unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
switch (token->type) switch (token->type)
{ {
case WPS_TOKEN_METADATA_ARTIST: case SKIN_TOKEN_METADATA_ARTIST:
return id3->artist; return id3->artist;
case WPS_TOKEN_METADATA_COMPOSER: case SKIN_TOKEN_METADATA_COMPOSER:
return id3->composer; return id3->composer;
case WPS_TOKEN_METADATA_ALBUM: case SKIN_TOKEN_METADATA_ALBUM:
return id3->album; return id3->album;
case WPS_TOKEN_METADATA_ALBUM_ARTIST: case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
return id3->albumartist; return id3->albumartist;
case WPS_TOKEN_METADATA_GROUPING: case SKIN_TOKEN_METADATA_GROUPING:
return id3->grouping; return id3->grouping;
case WPS_TOKEN_METADATA_GENRE: case SKIN_TOKEN_METADATA_GENRE:
return id3->genre_string; return id3->genre_string;
case WPS_TOKEN_METADATA_DISC_NUMBER: case SKIN_TOKEN_METADATA_DISC_NUMBER:
if (id3->disc_string) if (id3->disc_string)
return id3->disc_string; return id3->disc_string;
if (id3->discnum) { if (id3->discnum) {
@ -187,7 +187,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
return buf; return buf;
} }
return NULL; return NULL;
case WPS_TOKEN_METADATA_TRACK_NUMBER: case SKIN_TOKEN_METADATA_TRACK_NUMBER:
if (id3->track_string) if (id3->track_string)
return id3->track_string; return id3->track_string;
if (id3->tracknum) { if (id3->tracknum) {
@ -195,9 +195,9 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
return buf; return buf;
} }
return NULL; return NULL;
case WPS_TOKEN_METADATA_TRACK_TITLE: case SKIN_TOKEN_METADATA_TRACK_TITLE:
return id3->title; return id3->title;
case WPS_TOKEN_METADATA_VERSION: case SKIN_TOKEN_METADATA_VERSION:
switch (id3->id3version) switch (id3->id3version)
{ {
case ID3_VER_1_0: case ID3_VER_1_0:
@ -214,7 +214,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
break; break;
} }
return NULL; return NULL;
case WPS_TOKEN_METADATA_YEAR: case SKIN_TOKEN_METADATA_YEAR:
if( id3->year_string ) if( id3->year_string )
return id3->year_string; return id3->year_string;
if (id3->year) { if (id3->year) {
@ -222,29 +222,29 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
return buf; return buf;
} }
return NULL; return NULL;
case WPS_TOKEN_METADATA_COMMENT: case SKIN_TOKEN_METADATA_COMMENT:
return id3->comment; return id3->comment;
case WPS_TOKEN_FILE_PATH: case SKIN_TOKEN_FILE_PATH:
return id3->path; return id3->path;
case WPS_TOKEN_FILE_BITRATE: case SKIN_TOKEN_FILE_BITRATE:
if(id3->bitrate) if(id3->bitrate)
snprintf(buf, buf_size, "%d", id3->bitrate); snprintf(buf, buf_size, "%d", id3->bitrate);
else else
return "?"; return "?";
return buf; return buf;
case WPS_TOKEN_TRACK_TIME_ELAPSED: case SKIN_TOKEN_TRACK_TIME_ELAPSED:
format_time(buf, buf_size, elapsed); format_time(buf, buf_size, elapsed);
return buf; return buf;
case WPS_TOKEN_TRACK_TIME_REMAINING: case SKIN_TOKEN_TRACK_TIME_REMAINING:
format_time(buf, buf_size, length - elapsed); format_time(buf, buf_size, length - elapsed);
return buf; return buf;
case WPS_TOKEN_TRACK_LENGTH: case SKIN_TOKEN_TRACK_LENGTH:
format_time(buf, buf_size, length); format_time(buf, buf_size, length);
return buf; return buf;
case WPS_TOKEN_TRACK_ELAPSED_PERCENT: case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
if (length <= 0) if (length <= 0)
return NULL; return NULL;
@ -255,14 +255,14 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
snprintf(buf, buf_size, "%lu", 100 * elapsed / length); snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
return buf; return buf;
case WPS_TOKEN_TRACK_STARTING: case SKIN_TOKEN_TRACK_STARTING:
{ {
unsigned long time = token->value.i * 1000; unsigned long time = token->value.i * 1000;
if (elapsed < time) if (elapsed < time)
return "starting"; return "starting";
} }
return NULL; return NULL;
case WPS_TOKEN_TRACK_ENDING: case SKIN_TOKEN_TRACK_ENDING:
{ {
unsigned long time = token->value.i * 1000; unsigned long time = token->value.i * 1000;
if (length - elapsed < time) if (length - elapsed < time)
@ -270,7 +270,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
} }
return NULL; return NULL;
case WPS_TOKEN_FILE_CODEC: case SKIN_TOKEN_FILE_CODEC:
if (intval) if (intval)
{ {
if(id3->codectype == AFMT_UNKNOWN) if(id3->codectype == AFMT_UNKNOWN)
@ -280,10 +280,10 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
} }
return get_codectype(id3); return get_codectype(id3);
case WPS_TOKEN_FILE_FREQUENCY: case SKIN_TOKEN_FILE_FREQUENCY:
snprintf(buf, buf_size, "%ld", id3->frequency); snprintf(buf, buf_size, "%ld", id3->frequency);
return buf; return buf;
case WPS_TOKEN_FILE_FREQUENCY_KHZ: case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
/* ignore remainders < 100, so 22050 Hz becomes just 22k */ /* ignore remainders < 100, so 22050 Hz becomes just 22k */
if ((id3->frequency % 1000) < 100) if ((id3->frequency % 1000) < 100)
snprintf(buf, buf_size, "%ld", id3->frequency / 1000); snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
@ -292,7 +292,7 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
id3->frequency / 1000, id3->frequency / 1000,
(id3->frequency % 1000) / 100); (id3->frequency % 1000) / 100);
return buf; return buf;
case WPS_TOKEN_FILE_NAME: case SKIN_TOKEN_FILE_NAME:
if (get_dir(buf, buf_size, id3->path, 0)) { if (get_dir(buf, buf_size, id3->path, 0)) {
/* Remove extension */ /* Remove extension */
char* sep = strrchr(buf, '.'); char* sep = strrchr(buf, '.');
@ -302,28 +302,28 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
return buf; return buf;
} }
return NULL; return NULL;
case WPS_TOKEN_FILE_NAME_WITH_EXTENSION: case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION:
return get_dir(buf, buf_size, id3->path, 0); return get_dir(buf, buf_size, id3->path, 0);
case WPS_TOKEN_FILE_SIZE: case SKIN_TOKEN_FILE_SIZE:
snprintf(buf, buf_size, "%ld", id3->filesize / 1024); snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
return buf; return buf;
case WPS_TOKEN_FILE_VBR: case SKIN_TOKEN_FILE_VBR:
return (id3->vbr) ? "(avg)" : NULL; return (id3->vbr) ? "(avg)" : NULL;
case WPS_TOKEN_FILE_DIRECTORY: case SKIN_TOKEN_FILE_DIRECTORY:
return get_dir(buf, buf_size, id3->path, token->value.i); return get_dir(buf, buf_size, id3->path, token->value.i);
#ifdef HAVE_TAGCACHE #ifdef HAVE_TAGCACHE
case WPS_TOKEN_DATABASE_PLAYCOUNT: case SKIN_TOKEN_DATABASE_PLAYCOUNT:
if (intval) if (intval)
*intval = id3->playcount + 1; *intval = id3->playcount + 1;
snprintf(buf, buf_size, "%ld", id3->playcount); snprintf(buf, buf_size, "%ld", id3->playcount);
return buf; return buf;
case WPS_TOKEN_DATABASE_RATING: case SKIN_TOKEN_DATABASE_RATING:
if (intval) if (intval)
*intval = id3->rating + 1; *intval = id3->rating + 1;
snprintf(buf, buf_size, "%d", id3->rating); snprintf(buf, buf_size, "%d", id3->rating);
return buf; return buf;
case WPS_TOKEN_DATABASE_AUTOSCORE: case SKIN_TOKEN_DATABASE_AUTOSCORE:
if (intval) if (intval)
*intval = id3->score + 1; *intval = id3->score + 1;
snprintf(buf, buf_size, "%d", id3->score); snprintf(buf, buf_size, "%d", id3->score);
@ -340,13 +340,13 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
{ {
/* Most tokens expect NULL on error so leave that for the default case, /* Most tokens expect NULL on error so leave that for the default case,
* The ones that expect "0" need to be handled */ * The ones that expect "0" need to be handled */
case WPS_TOKEN_FILE_FREQUENCY: case SKIN_TOKEN_FILE_FREQUENCY:
case WPS_TOKEN_FILE_FREQUENCY_KHZ: case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
case WPS_TOKEN_FILE_SIZE: case SKIN_TOKEN_FILE_SIZE:
#ifdef HAVE_TAGCACHE #ifdef HAVE_TAGCACHE
case WPS_TOKEN_DATABASE_PLAYCOUNT: case SKIN_TOKEN_DATABASE_PLAYCOUNT:
case WPS_TOKEN_DATABASE_RATING: case SKIN_TOKEN_DATABASE_RATING:
case WPS_TOKEN_DATABASE_AUTOSCORE: case SKIN_TOKEN_DATABASE_AUTOSCORE:
#endif #endif
if (intval) if (intval)
*intval = 0; *intval = 0;
@ -397,30 +397,30 @@ const char *get_radio_token(struct wps_token *token, int preset_offset,
switch (token->type) switch (token->type)
{ {
/* Radio/tuner tokens */ /* Radio/tuner tokens */
case WPS_TOKEN_TUNER_TUNED: case SKIN_TOKEN_TUNER_TUNED:
if (tuner_get(RADIO_TUNED)) if (tuner_get(RADIO_TUNED))
return "t"; return "t";
return NULL; return NULL;
case WPS_TOKEN_TUNER_SCANMODE: case SKIN_TOKEN_TUNER_SCANMODE:
if (radio_scan_mode()) if (radio_scan_mode())
return "s"; return "s";
return NULL; return NULL;
case WPS_TOKEN_TUNER_STEREO: case SKIN_TOKEN_TUNER_STEREO:
if (radio_is_stereo()) if (radio_is_stereo())
return "s"; return "s";
return NULL; return NULL;
case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */ case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
return format_freq_MHz(region_data->freq_min, return format_freq_MHz(region_data->freq_min,
region_data->freq_step, buf, buf_size); region_data->freq_step, buf, buf_size);
case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */ case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
return format_freq_MHz(region_data->freq_max, return format_freq_MHz(region_data->freq_max,
region_data->freq_step, buf, buf_size); region_data->freq_step, buf, buf_size);
case WPS_TOKEN_TUNER_CURFREQ: case SKIN_TOKEN_TUNER_CURFREQ:
return format_freq_MHz(radio_current_frequency(), return format_freq_MHz(radio_current_frequency(),
region_data->freq_step, buf, buf_size); region_data->freq_step, buf, buf_size);
case WPS_TOKEN_PRESET_NAME: case SKIN_TOKEN_PRESET_NAME:
case WPS_TOKEN_PRESET_FREQ: case SKIN_TOKEN_PRESET_FREQ:
case WPS_TOKEN_PRESET_ID: case SKIN_TOKEN_PRESET_ID:
{ {
int preset_count = radio_preset_count(); int preset_count = radio_preset_count();
int cur_preset = radio_current_preset(); int cur_preset = radio_current_preset();
@ -431,30 +431,32 @@ const char *get_radio_token(struct wps_token *token, int preset_offset,
preset %= preset_count; preset %= preset_count;
if (preset < 0) if (preset < 0)
preset += preset_count; preset += preset_count;
if (token->type == WPS_TOKEN_PRESET_NAME) if (token->type == SKIN_TOKEN_PRESET_NAME)
snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name); snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
else if (token->type == WPS_TOKEN_PRESET_FREQ) else if (token->type == SKIN_TOKEN_PRESET_FREQ)
format_freq_MHz(radio_get_preset(preset)->frequency, format_freq_MHz(radio_get_preset(preset)->frequency,
region_data->freq_step, buf, buf_size); region_data->freq_step, buf, buf_size);
else else
snprintf(buf, buf_size, "%d", preset + 1); snprintf(buf, buf_size, "%d", preset + 1);
return buf; return buf;
} }
case WPS_TOKEN_PRESET_COUNT: case SKIN_TOKEN_PRESET_COUNT:
snprintf(buf, buf_size, "%d", radio_preset_count()); snprintf(buf, buf_size, "%d", radio_preset_count());
if (intval) if (intval)
*intval = radio_preset_count(); *intval = radio_preset_count();
return buf; return buf;
case WPS_TOKEN_HAVE_RDS: case SKIN_TOKEN_HAVE_RDS:
#ifdef HAVE_RDS_CAP #ifdef HAVE_RDS_CAP
return "rds"; return "rds";
case WPS_TOKEN_RDS_NAME: case SKIN_TOKEN_RDS_NAME:
return tuner_get_rds_info(RADIO_RDS_NAME); return tuner_get_rds_info(RADIO_RDS_NAME);
case WPS_TOKEN_RDS_TEXT: case SKIN_TOKEN_RDS_TEXT:
return tuner_get_rds_info(RADIO_RDS_TEXT); return tuner_get_rds_info(RADIO_RDS_TEXT);
#else #else
return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */ return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
#endif /* HAVE_RDS_CAP */ #endif /* HAVE_RDS_CAP */
default:
return NULL;
} }
return NULL; return NULL;
} }
@ -497,8 +499,8 @@ const char *get_token_value(struct gui_wps *gwps,
/* if the token is an RTC one, update the time /* if the token is an RTC one, update the time
and do the necessary checks */ and do the necessary checks */
if (token->type >= WPS_TOKENS_RTC_BEGIN if (token->type >= SKIN_TOKENS_RTC_BEGIN
&& token->type <= WPS_TOKENS_RTC_END) && token->type <= SKIN_TOKENS_RTC_END)
{ {
tm = get_time(); tm = get_time();
@ -531,44 +533,44 @@ const char *get_token_value(struct gui_wps *gwps,
switch (token->type) switch (token->type)
{ {
case WPS_TOKEN_CHARACTER: case SKIN_TOKEN_CHARACTER:
if (token->value.c == '\n') if (token->value.c == '\n')
return NULL; return NULL;
return &(token->value.c); return &(token->value.c);
case WPS_TOKEN_STRING: case SKIN_TOKEN_STRING:
return (char*)token->value.data; return (char*)token->value.data;
case WPS_TOKEN_TRANSLATEDSTRING: case SKIN_TOKEN_TRANSLATEDSTRING:
return (char*)P2STR(ID2P(token->value.i)); return (char*)P2STR(ID2P(token->value.i));
case WPS_TOKEN_PLAYLIST_ENTRIES: case SKIN_TOKEN_PLAYLIST_ENTRIES:
snprintf(buf, buf_size, "%d", playlist_amount()); snprintf(buf, buf_size, "%d", playlist_amount());
return buf; return buf;
case WPS_TOKEN_LIST_TITLE_TEXT: case SKIN_TOKEN_LIST_TITLE_TEXT:
return (char*)token->value.data; return (char*)token->value.data;
case WPS_TOKEN_LIST_TITLE_ICON: case SKIN_TOKEN_LIST_TITLE_ICON:
if (intval) if (intval)
*intval = token->value.i; *intval = token->value.i;
snprintf(buf, buf_size, "%d", token->value.i); snprintf(buf, buf_size, "%d", token->value.i);
return buf; return buf;
case WPS_TOKEN_PLAYLIST_NAME: case SKIN_TOKEN_PLAYLIST_NAME:
return playlist_name(NULL, buf, buf_size); return playlist_name(NULL, buf, buf_size);
case WPS_TOKEN_PLAYLIST_POSITION: case SKIN_TOKEN_PLAYLIST_POSITION:
snprintf(buf, buf_size, "%d", playlist_get_display_index()); snprintf(buf, buf_size, "%d", playlist_get_display_index());
return buf; return buf;
case WPS_TOKEN_PLAYLIST_SHUFFLE: case SKIN_TOKEN_PLAYLIST_SHUFFLE:
if ( global_settings.playlist_shuffle ) if ( global_settings.playlist_shuffle )
return "s"; return "s";
else else
return NULL; return NULL;
break; break;
case WPS_TOKEN_VOLUME: case SKIN_TOKEN_VOLUME:
snprintf(buf, buf_size, "%d", global_settings.volume); snprintf(buf, buf_size, "%d", global_settings.volume);
if (intval) if (intval)
{ {
@ -593,7 +595,7 @@ const char *get_token_value(struct gui_wps *gwps,
} }
return buf; return buf;
#ifdef HAVE_ALBUMART #ifdef HAVE_ALBUMART
case WPS_TOKEN_ALBUMART_FOUND: case SKIN_TOKEN_ALBUMART_FOUND:
if (data->albumart) if (data->albumart)
{ {
int handle = -1; int handle = -1;
@ -609,16 +611,9 @@ const char *get_token_value(struct gui_wps *gwps,
return "C"; return "C";
} }
return NULL; return NULL;
case WPS_TOKEN_ALBUMART_DISPLAY:
if (!data->albumart)
return NULL;
if (!data->albumart->draw)
data->albumart->draw = true;
return NULL;
#endif #endif
case WPS_TOKEN_BATTERY_PERCENT: case SKIN_TOKEN_BATTERY_PERCENT:
{ {
int l = battery_level(); int l = battery_level();
@ -641,14 +636,14 @@ const char *get_token_value(struct gui_wps *gwps,
} }
} }
case WPS_TOKEN_BATTERY_VOLTS: case SKIN_TOKEN_BATTERY_VOLTS:
{ {
unsigned int v = battery_voltage(); unsigned int v = battery_voltage();
snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10); snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
return buf; return buf;
} }
case WPS_TOKEN_BATTERY_TIME: case SKIN_TOKEN_BATTERY_TIME:
{ {
int t = battery_time(); int t = battery_time();
if (t >= 0) if (t >= 0)
@ -659,7 +654,7 @@ const char *get_token_value(struct gui_wps *gwps,
} }
#if CONFIG_CHARGING #if CONFIG_CHARGING
case WPS_TOKEN_BATTERY_CHARGER_CONNECTED: case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
{ {
if(charger_input_state==CHARGER) if(charger_input_state==CHARGER)
return "p"; return "p";
@ -668,7 +663,7 @@ const char *get_token_value(struct gui_wps *gwps,
} }
#endif #endif
#if CONFIG_CHARGING >= CHARGING_MONITOR #if CONFIG_CHARGING >= CHARGING_MONITOR
case WPS_TOKEN_BATTERY_CHARGING: case SKIN_TOKEN_BATTERY_CHARGING:
{ {
if (charge_state == CHARGING || charge_state == TOPOFF) { if (charge_state == CHARGING || charge_state == TOPOFF) {
return "c"; return "c";
@ -678,12 +673,12 @@ const char *get_token_value(struct gui_wps *gwps,
} }
#endif #endif
#ifdef HAVE_USB_POWER #ifdef HAVE_USB_POWER
case WPS_TOKEN_USB_POWERED: case SKIN_TOKEN_USB_POWERED:
if (usb_powered()) if (usb_powered())
return "u"; return "u";
return NULL; return NULL;
#endif #endif
case WPS_TOKEN_BATTERY_SLEEPTIME: case SKIN_TOKEN_BATTERY_SLEEPTIME:
{ {
if (get_sleep_timer() == 0) if (get_sleep_timer() == 0)
return NULL; return NULL;
@ -694,7 +689,7 @@ const char *get_token_value(struct gui_wps *gwps,
} }
} }
case WPS_TOKEN_PLAYBACK_STATUS: case SKIN_TOKEN_PLAYBACK_STATUS:
{ {
int status = current_playmode(); int status = current_playmode();
/* music */ /* music */
@ -734,13 +729,13 @@ const char *get_token_value(struct gui_wps *gwps,
return buf; return buf;
} }
case WPS_TOKEN_REPEAT_MODE: case SKIN_TOKEN_REPEAT_MODE:
if (intval) if (intval)
*intval = global_settings.repeat_mode + 1; *intval = global_settings.repeat_mode + 1;
snprintf(buf, buf_size, "%d", global_settings.repeat_mode); snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
return buf; return buf;
case WPS_TOKEN_RTC_PRESENT: case SKIN_TOKEN_RTC_PRESENT:
#if CONFIG_RTC #if CONFIG_RTC
return "c"; return "c";
#else #else
@ -748,41 +743,41 @@ const char *get_token_value(struct gui_wps *gwps,
#endif #endif
#if CONFIG_RTC #if CONFIG_RTC
case WPS_TOKEN_RTC_12HOUR_CFG: case SKIN_TOKEN_RTC_12HOUR_CFG:
if (intval) if (intval)
*intval = global_settings.timeformat + 1; *intval = global_settings.timeformat + 1;
snprintf(buf, buf_size, "%d", global_settings.timeformat); snprintf(buf, buf_size, "%d", global_settings.timeformat);
return buf; return buf;
case WPS_TOKEN_RTC_DAY_OF_MONTH: case SKIN_TOKEN_RTC_DAY_OF_MONTH:
/* d: day of month (01..31) */ /* d: day of month (01..31) */
snprintf(buf, buf_size, "%02d", tm->tm_mday); snprintf(buf, buf_size, "%02d", tm->tm_mday);
if (intval) if (intval)
*intval = tm->tm_mday - 1; *intval = tm->tm_mday - 1;
return buf; return buf;
case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
/* e: day of month, blank padded ( 1..31) */ /* e: day of month, blank padded ( 1..31) */
snprintf(buf, buf_size, "%2d", tm->tm_mday); snprintf(buf, buf_size, "%2d", tm->tm_mday);
if (intval) if (intval)
*intval = tm->tm_mday - 1; *intval = tm->tm_mday - 1;
return buf; return buf;
case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED: case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
/* H: hour (00..23) */ /* H: hour (00..23) */
snprintf(buf, buf_size, "%02d", tm->tm_hour); snprintf(buf, buf_size, "%02d", tm->tm_hour);
if (intval) if (intval)
*intval = tm->tm_hour; *intval = tm->tm_hour;
return buf; return buf;
case WPS_TOKEN_RTC_HOUR_24: case SKIN_TOKEN_RTC_HOUR_24:
/* k: hour ( 0..23) */ /* k: hour ( 0..23) */
snprintf(buf, buf_size, "%2d", tm->tm_hour); snprintf(buf, buf_size, "%2d", tm->tm_hour);
if (intval) if (intval)
*intval = tm->tm_hour; *intval = tm->tm_hour;
return buf; return buf;
case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED: case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
/* I: hour (01..12) */ /* I: hour (01..12) */
snprintf(buf, buf_size, "%02d", snprintf(buf, buf_size, "%02d",
(tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12); (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
@ -790,7 +785,7 @@ const char *get_token_value(struct gui_wps *gwps,
*intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12; *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
return buf; return buf;
case WPS_TOKEN_RTC_HOUR_12: case SKIN_TOKEN_RTC_HOUR_12:
/* l: hour ( 1..12) */ /* l: hour ( 1..12) */
snprintf(buf, buf_size, "%2d", snprintf(buf, buf_size, "%2d",
(tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12); (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
@ -798,107 +793,107 @@ const char *get_token_value(struct gui_wps *gwps,
*intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12; *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
return buf; return buf;
case WPS_TOKEN_RTC_MONTH: case SKIN_TOKEN_RTC_MONTH:
/* m: month (01..12) */ /* m: month (01..12) */
if (intval) if (intval)
*intval = tm->tm_mon + 1; *intval = tm->tm_mon + 1;
snprintf(buf, buf_size, "%02d", tm->tm_mon + 1); snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
return buf; return buf;
case WPS_TOKEN_RTC_MINUTE: case SKIN_TOKEN_RTC_MINUTE:
/* M: minute (00..59) */ /* M: minute (00..59) */
snprintf(buf, buf_size, "%02d", tm->tm_min); snprintf(buf, buf_size, "%02d", tm->tm_min);
if (intval) if (intval)
*intval = tm->tm_min; *intval = tm->tm_min;
return buf; return buf;
case WPS_TOKEN_RTC_SECOND: case SKIN_TOKEN_RTC_SECOND:
/* S: second (00..59) */ /* S: second (00..59) */
snprintf(buf, buf_size, "%02d", tm->tm_sec); snprintf(buf, buf_size, "%02d", tm->tm_sec);
if (intval) if (intval)
*intval = tm->tm_sec; *intval = tm->tm_sec;
return buf; return buf;
case WPS_TOKEN_RTC_YEAR_2_DIGITS: case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
/* y: last two digits of year (00..99) */ /* y: last two digits of year (00..99) */
snprintf(buf, buf_size, "%02d", tm->tm_year % 100); snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
if (intval) if (intval)
*intval = tm->tm_year % 100; *intval = tm->tm_year % 100;
return buf; return buf;
case WPS_TOKEN_RTC_YEAR_4_DIGITS: case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
/* Y: year (1970...) */ /* Y: year (1970...) */
snprintf(buf, buf_size, "%04d", tm->tm_year + 1900); snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
if (intval) if (intval)
*intval = tm->tm_year + 1900; *intval = tm->tm_year + 1900;
return buf; return buf;
case WPS_TOKEN_RTC_AM_PM_UPPER: case SKIN_TOKEN_RTC_AM_PM_UPPER:
/* p: upper case AM or PM indicator */ /* p: upper case AM or PM indicator */
if (intval) if (intval)
*intval = tm->tm_hour/12 == 0 ? 0 : 1; *intval = tm->tm_hour/12 == 0 ? 0 : 1;
return tm->tm_hour/12 == 0 ? "AM" : "PM"; return tm->tm_hour/12 == 0 ? "AM" : "PM";
case WPS_TOKEN_RTC_AM_PM_LOWER: case SKIN_TOKEN_RTC_AM_PM_LOWER:
/* P: lower case am or pm indicator */ /* P: lower case am or pm indicator */
if (intval) if (intval)
*intval = tm->tm_hour/12 == 0 ? 0 : 1; *intval = tm->tm_hour/12 == 0 ? 0 : 1;
return tm->tm_hour/12 == 0 ? "am" : "pm"; return tm->tm_hour/12 == 0 ? "am" : "pm";
case WPS_TOKEN_RTC_WEEKDAY_NAME: case SKIN_TOKEN_RTC_WEEKDAY_NAME:
/* a: abbreviated weekday name (Sun..Sat) */ /* a: abbreviated weekday name (Sun..Sat) */
return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday); return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
case WPS_TOKEN_RTC_MONTH_NAME: case SKIN_TOKEN_RTC_MONTH_NAME:
/* b: abbreviated month name (Jan..Dec) */ /* b: abbreviated month name (Jan..Dec) */
return str(LANG_MONTH_JANUARY + tm->tm_mon); return str(LANG_MONTH_JANUARY + tm->tm_mon);
case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON: case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
/* u: day of week (1..7); 1 is Monday */ /* u: day of week (1..7); 1 is Monday */
if (intval) if (intval)
*intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday; *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
snprintf(buf, buf_size, "%1d", tm->tm_wday + 1); snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
return buf; return buf;
case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN: case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
/* w: day of week (0..6); 0 is Sunday */ /* w: day of week (0..6); 0 is Sunday */
if (intval) if (intval)
*intval = tm->tm_wday + 1; *intval = tm->tm_wday + 1;
snprintf(buf, buf_size, "%1d", tm->tm_wday); snprintf(buf, buf_size, "%1d", tm->tm_wday);
return buf; return buf;
#else #else
case WPS_TOKEN_RTC_DAY_OF_MONTH: case SKIN_TOKEN_RTC_DAY_OF_MONTH:
case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED: case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
case WPS_TOKEN_RTC_HOUR_24: case SKIN_TOKEN_RTC_HOUR_24:
case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED: case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
case WPS_TOKEN_RTC_HOUR_12: case SKIN_TOKEN_RTC_HOUR_12:
case WPS_TOKEN_RTC_MONTH: case SKIN_TOKEN_RTC_MONTH:
case WPS_TOKEN_RTC_MINUTE: case SKIN_TOKEN_RTC_MINUTE:
case WPS_TOKEN_RTC_SECOND: case SKIN_TOKEN_RTC_SECOND:
case WPS_TOKEN_RTC_AM_PM_UPPER: case SKIN_TOKEN_RTC_AM_PM_UPPER:
case WPS_TOKEN_RTC_AM_PM_LOWER: case SKIN_TOKEN_RTC_AM_PM_LOWER:
case WPS_TOKEN_RTC_YEAR_2_DIGITS: case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
return "--"; return "--";
case WPS_TOKEN_RTC_YEAR_4_DIGITS: case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
return "----"; return "----";
case WPS_TOKEN_RTC_WEEKDAY_NAME: case SKIN_TOKEN_RTC_WEEKDAY_NAME:
case WPS_TOKEN_RTC_MONTH_NAME: case SKIN_TOKEN_RTC_MONTH_NAME:
return "---"; return "---";
case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON: case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN: case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
return "-"; return "-";
#endif #endif
#ifdef HAVE_LCD_CHARCELLS #ifdef HAVE_LCD_CHARCELLS
case WPS_TOKEN_PROGRESSBAR: case SKIN_TOKEN_PROGRESSBAR:
{ {
char *end = utf8encode(data->wps_progress_pat[0], buf); char *end = utf8encode(data->wps_progress_pat[0], buf);
*end = '\0'; *end = '\0';
return buf; return buf;
} }
case WPS_TOKEN_PLAYER_PROGRESSBAR: case SKIN_TOKEN_PLAYER_PROGRESSBAR:
if(is_new_player()) if(is_new_player())
{ {
/* we need 11 characters (full line) for /* we need 11 characters (full line) for
@ -916,7 +911,7 @@ const char *get_token_value(struct gui_wps *gwps,
#if (CONFIG_CODEC == SWCODEC) #if (CONFIG_CODEC == SWCODEC)
case WPS_TOKEN_CROSSFADE: case SKIN_TOKEN_CROSSFADE:
#ifdef HAVE_CROSSFADE #ifdef HAVE_CROSSFADE
if (intval) if (intval)
*intval = global_settings.crossfade + 1; *intval = global_settings.crossfade + 1;
@ -926,7 +921,7 @@ const char *get_token_value(struct gui_wps *gwps,
#endif #endif
return buf; return buf;
case WPS_TOKEN_REPLAYGAIN: case SKIN_TOKEN_REPLAYGAIN:
{ {
int val; int val;
@ -974,7 +969,7 @@ const char *get_token_value(struct gui_wps *gwps,
#endif /* (CONFIG_CODEC == SWCODEC) */ #endif /* (CONFIG_CODEC == SWCODEC) */
#if (CONFIG_CODEC != MAS3507D) #if (CONFIG_CODEC != MAS3507D)
case WPS_TOKEN_SOUND_PITCH: case SKIN_TOKEN_SOUND_PITCH:
{ {
int32_t pitch = sound_get_pitch(); int32_t pitch = sound_get_pitch();
snprintf(buf, buf_size, "%ld.%ld", snprintf(buf, buf_size, "%ld.%ld",
@ -989,7 +984,7 @@ const char *get_token_value(struct gui_wps *gwps,
#endif #endif
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
case WPS_TOKEN_SOUND_SPEED: case SKIN_TOKEN_SOUND_SPEED:
{ {
int32_t pitch = sound_get_pitch(); int32_t pitch = sound_get_pitch();
int32_t speed; int32_t speed;
@ -1007,7 +1002,7 @@ const char *get_token_value(struct gui_wps *gwps,
} }
#endif #endif
case WPS_TOKEN_MAIN_HOLD: case SKIN_TOKEN_MAIN_HOLD:
#ifdef HAS_BUTTON_HOLD #ifdef HAS_BUTTON_HOLD
if (button_hold()) if (button_hold())
#else #else
@ -1018,7 +1013,7 @@ const char *get_token_value(struct gui_wps *gwps,
return NULL; return NULL;
#ifdef HAS_REMOTE_BUTTON_HOLD #ifdef HAS_REMOTE_BUTTON_HOLD
case WPS_TOKEN_REMOTE_HOLD: case SKIN_TOKEN_REMOTE_HOLD:
if (remote_button_hold()) if (remote_button_hold())
return "r"; return "r";
else else
@ -1026,20 +1021,20 @@ const char *get_token_value(struct gui_wps *gwps,
#endif #endif
#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
case WPS_TOKEN_VLED_HDD: case SKIN_TOKEN_VLED_HDD:
if(led_read(HZ/2)) if(led_read(HZ/2))
return "h"; return "h";
else else
return NULL; return NULL;
#endif #endif
case WPS_TOKEN_BUTTON_VOLUME: case SKIN_TOKEN_BUTTON_VOLUME:
if (global_status.last_volume_change && if (global_status.last_volume_change &&
TIME_BEFORE(current_tick, global_status.last_volume_change + TIME_BEFORE(current_tick, global_status.last_volume_change +
token->value.i * TIMEOUT_UNIT)) token->value.i * TIMEOUT_UNIT))
return "v"; return "v";
return NULL; return NULL;
case WPS_TOKEN_LASTTOUCH: case SKIN_TOKEN_LASTTOUCH:
{ {
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
unsigned int last_touch = touchscreen_last_touch(); unsigned int last_touch = touchscreen_last_touch();
@ -1051,7 +1046,7 @@ const char *get_token_value(struct gui_wps *gwps,
} }
return NULL; return NULL;
case WPS_TOKEN_SETTING: case SKIN_TOKEN_SETTING:
{ {
const struct settings_list *s = settings+token->value.i; const struct settings_list *s = settings+token->value.i;
if (intval) if (intval)
@ -1120,14 +1115,14 @@ const char *get_token_value(struct gui_wps *gwps,
cfg_to_string(token->value.i,buf,buf_size); cfg_to_string(token->value.i,buf,buf_size);
return buf; return buf;
} }
case WPS_TOKEN_HAVE_TUNER: case SKIN_TOKEN_HAVE_TUNER:
#if CONFIG_TUNER #if CONFIG_TUNER
if (radio_hardware_present()) if (radio_hardware_present())
return "r"; return "r";
#endif #endif
return NULL; return NULL;
/* Recording tokens */ /* Recording tokens */
case WPS_TOKEN_HAVE_RECORDING: case SKIN_TOKEN_HAVE_RECORDING:
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
return "r"; return "r";
#else #else
@ -1135,11 +1130,11 @@ const char *get_token_value(struct gui_wps *gwps,
#endif #endif
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
case WPS_TOKEN_IS_RECORDING: case SKIN_TOKEN_IS_RECORDING:
if (audio_status() == AUDIO_STATUS_RECORD) if (audio_status() == AUDIO_STATUS_RECORD)
return "r"; return "r";
return NULL; return NULL;
case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */ case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
{ {
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
unsigned long samprk; unsigned long samprk;
@ -1227,7 +1222,7 @@ const char *get_token_value(struct gui_wps *gwps,
return buf; return buf;
} }
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
case WPS_TOKEN_REC_ENCODER: case SKIN_TOKEN_REC_ENCODER:
{ {
int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */ int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
if (intval) if (intval)
@ -1248,7 +1243,7 @@ const char *get_token_value(struct gui_wps *gwps,
break; break;
} }
#endif #endif
case WPS_TOKEN_REC_BITRATE: case SKIN_TOKEN_REC_BITRATE:
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
if (global_settings.rec_format == REC_FORMAT_MPA_L3) if (global_settings.rec_format == REC_FORMAT_MPA_L3)
{ {
@ -1317,12 +1312,12 @@ const char *get_token_value(struct gui_wps *gwps,
snprintf(buf, buf_size, "%d", global_settings.rec_quality); snprintf(buf, buf_size, "%d", global_settings.rec_quality);
return buf; return buf;
#endif #endif
case WPS_TOKEN_REC_MONO: case SKIN_TOKEN_REC_MONO:
if (!global_settings.rec_channels) if (!global_settings.rec_channels)
return "m"; return "m";
return NULL; return NULL;
case WPS_TOKEN_REC_SECONDS: case SKIN_TOKEN_REC_SECONDS:
{ {
int time = (audio_recorded_time() / HZ) % 60; int time = (audio_recorded_time() / HZ) % 60;
if (intval) if (intval)
@ -1330,7 +1325,7 @@ const char *get_token_value(struct gui_wps *gwps,
snprintf(buf, buf_size, "%02d", time); snprintf(buf, buf_size, "%02d", time);
return buf; return buf;
} }
case WPS_TOKEN_REC_MINUTES: case SKIN_TOKEN_REC_MINUTES:
{ {
int time = (audio_recorded_time() / HZ) / 60; int time = (audio_recorded_time() / HZ) / 60;
if (intval) if (intval)
@ -1338,7 +1333,7 @@ const char *get_token_value(struct gui_wps *gwps,
snprintf(buf, buf_size, "%02d", time); snprintf(buf, buf_size, "%02d", time);
return buf; return buf;
} }
case WPS_TOKEN_REC_HOURS: case SKIN_TOKEN_REC_HOURS:
{ {
int time = (audio_recorded_time() / HZ) / 3600; int time = (audio_recorded_time() / HZ) / 3600;
if (intval) if (intval)
@ -1349,7 +1344,7 @@ const char *get_token_value(struct gui_wps *gwps,
#endif /* HAVE_RECORDING */ #endif /* HAVE_RECORDING */
case WPS_TOKEN_CURRENT_SCREEN: case SKIN_TOKEN_CURRENT_SCREEN:
{ {
int curr_screen = current_screen(); int curr_screen = current_screen();
@ -1390,7 +1385,7 @@ const char *get_token_value(struct gui_wps *gwps,
return buf; return buf;
} }
case WPS_TOKEN_LANG_IS_RTL: case SKIN_TOKEN_LANG_IS_RTL:
return lang_is_rtl() ? "r" : NULL; return lang_is_rtl() ? "r" : NULL;
default: default:

View file

@ -23,242 +23,10 @@
#define _SKIN_TOKENS_H_ #define _SKIN_TOKENS_H_
#include <stdbool.h> #include <stdbool.h>
#include "tag_table.h"
enum wps_token_type {
TOKEN_MARKER_CONTROL_TOKENS = -1,
WPS_NO_TOKEN = 0, /* for WPS tags we don't want to save as tokens */
WPS_TOKEN_UNKNOWN,
/* Markers */
WPS_TOKEN_CHARACTER,
WPS_TOKEN_STRING,
WPS_TOKEN_TRANSLATEDSTRING,
/* Alignment */
WPS_TOKEN_ALIGN_LEFT,
WPS_TOKEN_ALIGN_LEFT_RTL,
WPS_TOKEN_ALIGN_CENTER,
WPS_TOKEN_ALIGN_RIGHT,
WPS_TOKEN_ALIGN_RIGHT_RTL,
/* Sublines */
WPS_TOKEN_SUBLINE_TIMEOUT,
/* Conditional */
WPS_TOKEN_CONDITIONAL,
WPS_TOKEN_CONDITIONAL_START,
WPS_TOKEN_CONDITIONAL_OPTION,
WPS_TOKEN_CONDITIONAL_END,
/* Viewport display */
WPS_VIEWPORT_ENABLE,
WPS_VIEWPORT_CUSTOMLIST,
WPS_TOKEN_UIVIEWPORT_ENABLE,
WPS_TOKEN_VIEWPORT_FGCOLOUR,
WPS_TOKEN_VIEWPORT_BGCOLOUR,
/* Battery */
TOKEN_MARKER_BATTERY,
WPS_TOKEN_BATTERY_PERCENT,
WPS_TOKEN_BATTERY_PERCENTBAR,
WPS_TOKEN_BATTERY_VOLTS,
WPS_TOKEN_BATTERY_TIME,
WPS_TOKEN_BATTERY_CHARGER_CONNECTED,
WPS_TOKEN_BATTERY_CHARGING,
WPS_TOKEN_BATTERY_SLEEPTIME,
WPS_TOKEN_USB_POWERED,
/* Sound */
TOKEN_MARKER_SOUND,
#if (CONFIG_CODEC != MAS3507D)
WPS_TOKEN_SOUND_PITCH,
#endif
#if (CONFIG_CODEC == SWCODEC)
WPS_TOKEN_SOUND_SPEED,
WPS_TOKEN_REPLAYGAIN,
WPS_TOKEN_CROSSFADE,
#endif
/* Time */
TOKEN_MARKER_RTC,
WPS_TOKEN_RTC_PRESENT,
/* The begin/end values allow us to know if a token is an RTC one.
New RTC tokens should be added between the markers. */
WPS_TOKENS_RTC_BEGIN, /* just the start marker, not an actual token */
WPS_TOKEN_RTC_DAY_OF_MONTH,
WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,
WPS_TOKEN_RTC_12HOUR_CFG,
WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED,
WPS_TOKEN_RTC_HOUR_24,
WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED,
WPS_TOKEN_RTC_HOUR_12,
WPS_TOKEN_RTC_MONTH,
WPS_TOKEN_RTC_MINUTE,
WPS_TOKEN_RTC_SECOND,
WPS_TOKEN_RTC_YEAR_2_DIGITS,
WPS_TOKEN_RTC_YEAR_4_DIGITS,
WPS_TOKEN_RTC_AM_PM_UPPER,
WPS_TOKEN_RTC_AM_PM_LOWER,
WPS_TOKEN_RTC_WEEKDAY_NAME,
WPS_TOKEN_RTC_MONTH_NAME,
WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON,
WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN,
WPS_TOKENS_RTC_END, /* just the end marker, not an actual token */
/* Database */
TOKEN_MARKER_DATABASE,
#ifdef HAVE_TAGCACHE
WPS_TOKEN_DATABASE_PLAYCOUNT,
WPS_TOKEN_DATABASE_RATING,
WPS_TOKEN_DATABASE_AUTOSCORE,
#endif
/* File */
TOKEN_MARKER_FILE,
WPS_TOKEN_FILE_BITRATE,
WPS_TOKEN_FILE_CODEC,
WPS_TOKEN_FILE_FREQUENCY,
WPS_TOKEN_FILE_FREQUENCY_KHZ,
WPS_TOKEN_FILE_NAME,
WPS_TOKEN_FILE_NAME_WITH_EXTENSION,
WPS_TOKEN_FILE_PATH,
WPS_TOKEN_FILE_SIZE,
WPS_TOKEN_FILE_VBR,
WPS_TOKEN_FILE_DIRECTORY,
/* Image */
TOKEN_MARKER_IMAGES,
#ifdef HAVE_LCD_BITMAP
WPS_TOKEN_IMAGE_BACKDROP,
WPS_TOKEN_IMAGE_PROGRESS_BAR,
WPS_TOKEN_IMAGE_PRELOAD,
WPS_TOKEN_IMAGE_PRELOAD_DISPLAY,
WPS_TOKEN_IMAGE_DISPLAY,
#endif
#ifdef HAVE_ALBUMART
/* Albumart */
WPS_TOKEN_ALBUMART_DISPLAY,
WPS_TOKEN_ALBUMART_FOUND,
#endif
/* Metadata */
TOKEN_MARKER_METADATA,
WPS_TOKEN_METADATA_ARTIST,
WPS_TOKEN_METADATA_COMPOSER,
WPS_TOKEN_METADATA_ALBUM_ARTIST,
WPS_TOKEN_METADATA_GROUPING,
WPS_TOKEN_METADATA_ALBUM,
WPS_TOKEN_METADATA_GENRE,
WPS_TOKEN_METADATA_DISC_NUMBER,
WPS_TOKEN_METADATA_TRACK_NUMBER,
WPS_TOKEN_METADATA_TRACK_TITLE,
WPS_TOKEN_METADATA_VERSION,
WPS_TOKEN_METADATA_YEAR,
WPS_TOKEN_METADATA_COMMENT,
TOKEN_MARKER_PLAYBACK_INFO,
/* Mode */
WPS_TOKEN_REPEAT_MODE,
WPS_TOKEN_PLAYBACK_STATUS,
/* Progressbar */
WPS_TOKEN_PROGRESSBAR,
#ifdef HAVE_LCD_CHARCELLS
WPS_TOKEN_PLAYER_PROGRESSBAR,
#endif
#ifdef HAVE_LCD_BITMAP
/* Peakmeter */
WPS_TOKEN_PEAKMETER,
#endif
/* Current track */
WPS_TOKEN_TRACK_ELAPSED_PERCENT,
WPS_TOKEN_TRACK_TIME_ELAPSED,
WPS_TOKEN_TRACK_TIME_REMAINING,
WPS_TOKEN_TRACK_LENGTH,
WPS_TOKEN_TRACK_STARTING,
WPS_TOKEN_TRACK_ENDING,
/* Playlist */
TOKEN_MARKER_PLAYLIST,
WPS_TOKEN_PLAYLIST_ENTRIES,
WPS_TOKEN_PLAYLIST_NAME,
WPS_TOKEN_PLAYLIST_POSITION,
WPS_TOKEN_PLAYLIST_SHUFFLE,
/* buttons */
TOKEN_MARKER_MISC,
WPS_TOKEN_DRAW_INBUILTBAR,
WPS_TOKEN_LIST_TITLE_TEXT,
WPS_TOKEN_LIST_TITLE_ICON,
WPS_TOKEN_BUTTON_VOLUME,
WPS_TOKEN_LASTTOUCH,
#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
/* Virtual LED */
WPS_TOKEN_VLED_HDD,
#endif
/* Volume level */
WPS_TOKEN_VOLUME,
WPS_TOKEN_VOLUMEBAR,
/* hold */
WPS_TOKEN_MAIN_HOLD,
#ifdef HAS_REMOTE_BUTTON_HOLD
WPS_TOKEN_REMOTE_HOLD,
#endif
/* Setting option */
WPS_TOKEN_SETTING,
WPS_TOKEN_CURRENT_SCREEN,
WPS_TOKEN_LANG_IS_RTL,
/* Recording Tokens */
TOKEN_MARKER_RECORDING,
WPS_TOKEN_HAVE_RECORDING,
WPS_TOKEN_IS_RECORDING,
WPS_TOKEN_REC_FREQ,
WPS_TOKEN_REC_ENCODER,
WPS_TOKEN_REC_BITRATE, /* SWCODEC: MP3 bitrate, HWCODEC: MP3 "quality" */
WPS_TOKEN_REC_MONO,
WPS_TOKEN_REC_SECONDS,
WPS_TOKEN_REC_MINUTES,
WPS_TOKEN_REC_HOURS,
/* Radio Tokens */
TOKEN_MARKER_TUNER,
WPS_TOKEN_HAVE_TUNER,
#if CONFIG_TUNER
WPS_TOKEN_TUNER_TUNED,
WPS_TOKEN_TUNER_SCANMODE,
WPS_TOKEN_TUNER_STEREO,
WPS_TOKEN_TUNER_MINFREQ, /* changes based on "region" */
WPS_TOKEN_TUNER_MAXFREQ, /* changes based on "region" */
WPS_TOKEN_TUNER_CURFREQ,
WPS_TOKEN_PRESET_ID, /* "id" of this preset.. really the array element number */
WPS_TOKEN_PRESET_NAME,
WPS_TOKEN_PRESET_FREQ,
WPS_TOKEN_PRESET_COUNT,
/* RDS tokens */
WPS_TOKEN_HAVE_RDS,
#ifdef HAVE_RDS_CAP
WPS_TOKEN_RDS_NAME,
WPS_TOKEN_RDS_TEXT,
#endif
#endif /* CONFIG_TUNER */
TOKEN_MARKER_END, /* this needs to be the last value in this enum */
};
struct wps_token { struct wps_token {
unsigned char type; /* enough to store the token type */ enum skin_token_type type; /* enough to store the token type */
/* Whether the tag (e.g. track name or the album) refers the /* Whether the tag (e.g. track name or the album) refers the
current or the next song (false=current, true=next) */ current or the next song (false=current, true=next) */

View file

@ -26,7 +26,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "skin_buffer.h"
#include "settings_list.h" #include "settings_list.h"
#ifdef __PCTOOL__ #ifdef __PCTOOL__
#ifdef WPSEDITOR #ifdef WPSEDITOR

View file

@ -24,6 +24,8 @@
#ifndef _WPS_ENGINE_INTERNALS_ #ifndef _WPS_ENGINE_INTERNALS_
#define _WPS_ENGINE_INTERNALS_ #define _WPS_ENGINE_INTERNALS_
/* Timeout unit expressed in HZ. In WPS, all timeouts are given in seconds /* Timeout unit expressed in HZ. In WPS, all timeouts are given in seconds
(possibly with a decimal fraction) but stored as integer values. (possibly with a decimal fraction) but stored as integer values.
E.g. 2.5 is stored as 25. This means 25 tenth of a second, i.e. 25 units. E.g. 2.5 is stored as 25. This means 25 tenth of a second, i.e. 25 units.
@ -32,6 +34,8 @@
#define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* In TIMEOUT_UNIT's */ #define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* In TIMEOUT_UNIT's */
#include "skin_tokens.h" #include "skin_tokens.h"
#include "tag_table.h"
#include "skin_parser.h"
/* TODO: sort this mess out */ /* TODO: sort this mess out */
@ -40,19 +44,6 @@
#include "statusbar.h" #include "statusbar.h"
#include "metadata.h" #include "metadata.h"
/* constants used in line_type and as refresh_mode for wps_refresh */
#define WPS_REFRESH_STATIC (1u<<0) /* line doesn't change over time */
#define WPS_REFRESH_DYNAMIC (1u<<1) /* line may change (e.g. time flag) */
#define WPS_REFRESH_SCROLL (1u<<2) /* line scrolls */
#define WPS_REFRESH_PLAYER_PROGRESS (1u<<3) /* line contains a progress bar */
#define WPS_REFRESH_PEAK_METER (1u<<4) /* line contains a peak meter */
#define WPS_REFRESH_STATUSBAR (1u<<5) /* refresh statusbar */
#define WPS_REFRESH_ALL (0xffffffffu) /* to refresh all line types */
/* to refresh only those lines that change over time */
#define WPS_REFRESH_NON_STATIC (WPS_REFRESH_DYNAMIC| \
WPS_REFRESH_PLAYER_PROGRESS| \
WPS_REFRESH_PEAK_METER)
/* alignments */ /* alignments */
#define WPS_ALIGN_RIGHT 32 #define WPS_ALIGN_RIGHT 32
#define WPS_ALIGN_CENTER 64 #define WPS_ALIGN_CENTER 64
@ -82,16 +73,16 @@ struct gui_img {
short int y; /* y-pos */ short int y; /* y-pos */
short int num_subimages; /* number of sub-images */ short int num_subimages; /* number of sub-images */
short int subimage_height; /* height of each sub-image */ short int subimage_height; /* height of each sub-image */
short int display; /* -1 for no display, 0..n to display a subimage */
struct bitmap bm; struct bitmap bm;
char label; char label;
bool loaded; /* load state */ bool loaded; /* load state */
bool always_display; /* not using the preload/display mechanism */ bool always_display; /* not using the preload/display mechanism */
int display;
}; };
struct progressbar { struct progressbar {
enum wps_token_type type; enum skin_token_type type;
struct viewport *vp; struct viewport *vp;
/* regular pb */ /* regular pb */
short x; short x;
@ -105,8 +96,6 @@ struct progressbar {
/*progressbar image*/ /*progressbar image*/
struct bitmap bm; struct bitmap bm;
bool have_bitmap_pb; bool have_bitmap_pb;
bool draw;
}; };
#endif #endif
@ -157,45 +146,6 @@ enum wps_parse_error {
PARSE_FAIL_LIMITS_EXCEEDED, PARSE_FAIL_LIMITS_EXCEEDED,
}; };
/* Description of a subline on the WPS */
struct skin_subline {
/* Index of the first token for this subline in the token array.
Tokens of this subline end where tokens for the next subline
begin. */
unsigned short first_token_idx;
unsigned short last_token_idx;
/* Bit or'ed WPS_REFRESH_xxx */
unsigned char line_type;
/* How long the subline should be displayed, in 10ths of sec */
unsigned char time_mult;
/* pointer to the next subline in this line */
struct skin_subline *next;
};
/* Description of a line on the WPS. A line is a set of sublines.
A subline is displayed for a certain amount of time. After that,
the next subline of the line is displayed. And so on. */
struct skin_line {
/* Linked list of all the sublines on this line,
* a line *must* have at least one subline so no need to add an extra pointer */
struct skin_subline sublines;
/* pointer to the current subline */
struct skin_subline *curr_subline;
/* When the next subline of this line should be displayed
(absolute time value in ticks) */
long subline_expire_time;
/* pointer to the next line */
struct skin_line *next;
};
#define VP_DRAW_HIDEABLE 0x1 #define VP_DRAW_HIDEABLE 0x1
#define VP_DRAW_HIDDEN 0x2 #define VP_DRAW_HIDDEN 0x2
#define VP_DRAW_WASHIDDEN 0x4 #define VP_DRAW_WASHIDDEN 0x4
@ -206,7 +156,6 @@ struct skin_line {
#define VP_INFO_LABEL 0x80 #define VP_INFO_LABEL 0x80
struct skin_viewport { struct skin_viewport {
struct viewport vp; /* The LCD viewport struct */ struct viewport vp; /* The LCD viewport struct */
struct skin_line *lines;
char hidden_flags; char hidden_flags;
char label; char label;
unsigned start_fgcolour; unsigned start_fgcolour;
@ -236,9 +185,6 @@ struct touchregion {
}; };
#endif #endif
#define MAX_PLAYLISTLINE_TOKENS 16
#define MAX_PLAYLISTLINE_STRINGS 8
#define MAX_PLAYLISTLINE_STRLEN 8
enum info_line_type { enum info_line_type {
TRACK_HAS_INFO = 0, TRACK_HAS_INFO = 0,
TRACK_HAS_NO_INFO TRACK_HAS_NO_INFO
@ -250,36 +196,50 @@ struct playlistviewer {
#ifdef HAVE_TC_RAMCACHE #ifdef HAVE_TC_RAMCACHE
struct mp3entry tempid3; struct mp3entry tempid3;
#endif #endif
struct { struct skin_element *lines[2];
enum wps_token_type tokens[MAX_PLAYLISTLINE_TOKENS];
char strings[MAX_PLAYLISTLINE_STRINGS][MAX_PLAYLISTLINE_STRLEN];
int count;
bool scroll;
} lines[2];
}; };
#ifdef HAVE_ALBUMART #ifdef HAVE_ALBUMART
struct skin_albumart { struct skin_albumart {
/* Album art support */ /* Album art support */
struct viewport *vp;/* The viewport this is in */
int x; int x;
int y; int y;
int width; int width;
int height; int height;
bool draw;
unsigned char xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT */ unsigned char xalign; /* WPS_ALBUMART_ALIGN_LEFT, _CENTER, _RIGHT */
unsigned char yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */ unsigned char yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */
unsigned char state; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */ unsigned char state; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */
struct viewport *vp;
int draw_handle;
}; };
#endif #endif
struct line {
int timeout; /* if inside a line alternator */
unsigned update_mode;
};
struct line_alternator {
int current_line;
unsigned long last_change_tick;
};
struct conditional {
int last_value;
struct wps_token *token;
};
/* wps_data /* wps_data
this struct holds all necessary data which describes the this struct holds all necessary data which describes the
viewable content of a wps */ viewable content of a wps */
struct wps_data struct wps_data
{ {
struct skin_element *tree;
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
struct skin_token_list *images; struct skin_token_list *images;
struct skin_token_list *progressbars; struct skin_token_list *progressbars;
@ -291,16 +251,10 @@ struct wps_data
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
struct skin_token_list *touchregions; struct skin_token_list *touchregions;
#endif #endif
struct skin_token_list *viewports;
struct skin_token_list *strings;
#ifdef HAVE_ALBUMART #ifdef HAVE_ALBUMART
struct skin_albumart *albumart; struct skin_albumart *albumart;
int playback_aa_slot; int playback_aa_slot;
#endif #endif
struct wps_token *tokens;
/* Total number of tokens in the WPS. During WPS parsing, this is
the index of the token being parsed. */
int num_tokens;
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
bool peak_meter_enabled; bool peak_meter_enabled;

View file

@ -27,6 +27,9 @@
#include "appevents.h" #include "appevents.h"
#include "screens.h" #include "screens.h"
#include "screen_access.h" #include "screen_access.h"
#include "strlcpy.h"
#include "skin_parser.h"
#include "skin_buffer.h"
#include "skin_engine/skin_engine.h" #include "skin_engine/skin_engine.h"
#include "skin_engine/wps_internals.h" #include "skin_engine/wps_internals.h"
#include "viewport.h" #include "viewport.h"
@ -45,24 +48,53 @@ static struct wps_sync_data sb_skin_sync_data = { .do_full_update = false
/* initial setup of wps_data */ /* initial setup of wps_data */
static int update_delay = DEFAULT_UPDATE_DELAY; static int update_delay = DEFAULT_UPDATE_DELAY;
struct wps_token *found_token;
static int set_title_worker(char* title, enum themable_icons icon,
struct wps_data *data, struct skin_element *root)
{
int retval = 0;
struct skin_element *element = root;
while (element)
{
struct wps_token *token = NULL;
if (element->type == CONDITIONAL)
{
struct conditional *cond = (struct conditional *)element->data;
token = cond->token;
}
else if (element->type == TAG)
{
token = (struct wps_token *)element->data;
}
if (token)
{
if (token->type == SKIN_TOKEN_LIST_TITLE_TEXT)
{
found_token = token;
token->value.data = title;
retval = 1;
}
else if (token->type == SKIN_TOKEN_LIST_TITLE_ICON)
{
/* Icon_NOICON == -1 which the skin engine wants at position 1, so + 2 */
token->value.i = icon+2;
}
}
if (element->children_count)
{
int i;
for (i=0; i<element->children_count; i++)
retval |= set_title_worker(title, icon, data, element->children[i]);
}
element = element->next;
}
return retval;
}
bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen) bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen)
{ {
int i; bool retval = set_title_worker(title, icon, &sb_skin_data[screen],
bool retval = false; sb_skin_data[screen].tree) > 0;
for(i=0; i<sb_skin_data[screen].num_tokens; i++)
{
if (sb_skin_data[screen].tokens[i].type == WPS_TOKEN_LIST_TITLE_TEXT)
{
sb_skin_data[screen].tokens[i].value.data = title;
retval = true;
}
else if (sb_skin_data[screen].tokens[i].type == WPS_TOKEN_LIST_TITLE_ICON)
{
/* Icon_NOICON == -1 which the skin engine wants at position 1, so + 2 */
sb_skin_data[screen].tokens[i].value.i = icon+2;
}
}
return retval; return retval;
} }
@ -75,18 +107,22 @@ void sb_skin_data_load(enum screen_type screen, const char *buf, bool isfile)
success = buf && skin_data_load(screen, data, buf, isfile); success = buf && skin_data_load(screen, data, buf, isfile);
if (success) if (success)
{ /* hide the sb's default viewport because it has nasty effect with stuff {
/* hide the sb's default viewport because it has nasty effect with stuff
* not part of the statusbar, * not part of the statusbar,
* hence .sbs's without any other vps are unsupported*/ * hence .sbs's without any other vps are unsupported*/
struct skin_viewport *vp = find_viewport(VP_DEFAULT_LABEL, data); struct skin_viewport *vp = find_viewport(VP_DEFAULT_LABEL, data);
struct skin_token_list *next_vp = data->viewports->next; struct skin_element *next_vp = data->tree->next;
if (!next_vp) if (vp)
{ /* no second viewport, let parsing fail */ {
success = false; if (!next_vp)
{ /* no second viewport, let parsing fail */
success = false;
}
/* hide this viewport, forever */
vp->hidden_flags = VP_NEVER_VISIBLE;
} }
/* hide this viewport, forever */
vp->hidden_flags = VP_NEVER_VISIBLE;
sb_set_info_vp(screen, VP_INFO_LABEL|VP_DEFAULT_LABEL); sb_set_info_vp(screen, VP_INFO_LABEL|VP_DEFAULT_LABEL);
} }
@ -135,7 +171,7 @@ bool sb_set_backdrop(enum screen_type screen, char* filename)
else else
#endif #endif
buf_size = LCD_BACKDROP_BYTES; buf_size = LCD_BACKDROP_BYTES;
sb_skin[screen].data->backdrop = skin_buffer_alloc(buf_size); sb_skin[screen].data->backdrop = (char*)skin_buffer_alloc(buf_size);
if (!sb_skin[screen].data->backdrop) if (!sb_skin[screen].data->backdrop)
return false; return false;
} }
@ -150,6 +186,8 @@ void sb_skin_update(enum screen_type screen, bool force)
{ {
static long next_update[NB_SCREENS] = {0}; static long next_update[NB_SCREENS] = {0};
int i = screen; int i = screen;
if (!sb_skin_data[screen].wps_loaded)
return;
if (TIME_AFTER(current_tick, next_update[i]) || force) if (TIME_AFTER(current_tick, next_update[i]) || force)
{ {
#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
@ -158,7 +196,7 @@ void sb_skin_update(enum screen_type screen, bool force)
if (lcd_active() || (i != SCREEN_MAIN)) if (lcd_active() || (i != SCREEN_MAIN))
#endif #endif
skin_update(&sb_skin[i], force? skin_update(&sb_skin[i], force?
WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); SKIN_REFRESH_ALL : SKIN_REFRESH_NON_STATIC);
next_update[i] = current_tick + update_delay; /* don't update too often */ next_update[i] = current_tick + update_delay; /* don't update too often */
sb_skin[SCREEN_MAIN].sync_data->do_full_update = false; sb_skin[SCREEN_MAIN].sync_data->do_full_update = false;
} }
@ -216,7 +254,30 @@ void sb_create_from_settings(enum screen_type screen)
if (ptr2[0] && ptr2[0] != '-') /* from ui viewport setting */ if (ptr2[0] && ptr2[0] != '-') /* from ui viewport setting */
{ {
char *comma = ptr;
int param_count = 0;
len = snprintf(ptr, remaining, "%%ax%%Vi(-,%s)\n", ptr2); len = snprintf(ptr, remaining, "%%ax%%Vi(-,%s)\n", ptr2);
/* The config put the colours at the end of the viewport,
* they need to be stripped for the skin code though */
do {
param_count++;
comma = strchr(comma+1, ',');
} while (comma && param_count < 6);
if (comma)
{
char *end = comma;
char fg[8], bg[8];
int i = 0;
comma++;
while (*comma != ',')
fg[i++] = *comma++;
fg[i] = '\0'; comma++; i=0;
while (*comma != ')')
bg[i++] = *comma++;
bg[i] = '\0';
len += snprintf(end, remaining-len, ") %%Vf(%s) %%Vb(%s)\n", fg, bg);
}
} }
else else
{ {

View file

@ -30,14 +30,21 @@
#include "settings.h" #include "settings.h"
#include "wps.h" #include "wps.h"
#include "file.h" #include "file.h"
#include "buffer.h"
#if CONFIG_TUNER #if CONFIG_TUNER
#include "radio.h" #include "radio.h"
#endif #endif
#include "skin_engine/skin_engine.h" #include "skin_engine/skin_engine.h"
#include "skin_engine/skin_fonts.h" #include "skin_buffer.h"
#include "statusbar-skinned.h" #include "statusbar-skinned.h"
#include "bootchart.h" #include "bootchart.h"
static char *skin_buffer = NULL;
void theme_init_buffer(void)
{
skin_buffer = buffer_alloc(SKIN_BUFFER_SIZE);
}
/* call this after loading a .wps/.rwps or other skin files, so that the /* call this after loading a .wps/.rwps or other skin files, so that the
* skin buffer is reset properly * skin buffer is reset properly
@ -71,9 +78,10 @@ void settings_apply_skins(void)
{ {
char buf[MAX_PATH]; char buf[MAX_PATH];
/* re-initialize the skin buffer before we start reloading skins */ /* re-initialize the skin buffer before we start reloading skins */
skin_buffer_init();
enum screen_type screen = SCREEN_MAIN; enum screen_type screen = SCREEN_MAIN;
unsigned int i; unsigned int i;
skin_buffer_init(skin_buffer, SKIN_BUFFER_SIZE);
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
skin_backdrop_init(); skin_backdrop_init();
skin_font_init(); skin_font_init();

View file

@ -310,13 +310,6 @@ static void set_default_align_flags(struct viewport *vp)
#endif /* HAVE_LCD_BITMAP */ #endif /* HAVE_LCD_BITMAP */
#endif /* __PCTOOL__ */ #endif /* __PCTOOL__ */
#ifdef HAVE_LCD_COLOR
#define ARG_STRING(_depth) ((_depth) == 2 ? "dddddgg":"dddddcc")
#else
#define ARG_STRING(_depth) "dddddgg"
#endif
void viewport_set_fullscreen(struct viewport *vp, void viewport_set_fullscreen(struct viewport *vp,
const enum screen_type screen) const enum screen_type screen)
{ {
@ -416,81 +409,4 @@ int get_viewport_default_colour(enum screen_type screen, bool fgcolour)
#endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */ #endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */
} }
const char* viewport_parse_viewport(struct viewport *vp,
enum screen_type screen,
const char *bufptr,
const char separator)
{
/* parse the list to the viewport struct */
const char *ptr = bufptr;
uint32_t set = 0;
enum {
PL_X = 0,
PL_Y,
PL_WIDTH,
PL_HEIGHT,
PL_FONT,
};
if (!(ptr = parse_list("ddddd", &set, separator, ptr,
&vp->x, &vp->y, &vp->width, &vp->height, &vp->font)))
return NULL;
/* X and Y *must* be set */
if (!LIST_VALUE_PARSED(set, PL_X) || !LIST_VALUE_PARSED(set, PL_Y))
return NULL;
/* check for negative values */
if (vp->x < 0)
vp->x += screens[screen].lcdwidth;
if (vp->y < 0)
vp->y += screens[screen].lcdheight;
/* fix defaults,
* and negative width/height which means "extend to edge minus value */
if (!LIST_VALUE_PARSED(set, PL_WIDTH))
vp->width = screens[screen].lcdwidth - vp->x;
else if (vp->width < 0)
vp->width = (vp->width + screens[screen].lcdwidth) - vp->x;
if (!LIST_VALUE_PARSED(set, PL_HEIGHT))
vp->height = screens[screen].lcdheight - vp->y;
else if (vp->height < 0)
vp->height = (vp->height + screens[screen].lcdheight) - vp->y;
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
vp->fg_pattern = get_viewport_default_colour(screen, true);
vp->bg_pattern = get_viewport_default_colour(screen, false);
#endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */
#ifdef HAVE_LCD_COLOR
vp->lss_pattern = global_settings.lss_color;
vp->lse_pattern = global_settings.lse_color;
vp->lst_pattern = global_settings.lst_color;
#endif
/* Validate the viewport dimensions - we know that the numbers are
non-negative integers, ignore bars and assume the viewport takes them
* into account */
if ((vp->x >= screens[screen].lcdwidth) ||
((vp->x + vp->width) > screens[screen].lcdwidth) ||
(vp->y >= screens[screen].lcdheight) ||
((vp->y + vp->height) > screens[screen].lcdheight))
{
return NULL;
}
/* Default to using the user font if the font was an invalid number or '-'
* font 1 is *always* the UI font for the current screen
* 2 is always the first extra font */
if (!LIST_VALUE_PARSED(set, PL_FONT))
vp->font = FONT_UI;
/* Set the defaults for fields not user-specified */
vp->drawmode = DRMODE_SOLID;
#ifndef __PCTOOL__
set_default_align_flags(vp);
#endif
return ptr;
}
#endif #endif

View file

@ -74,25 +74,4 @@ bool viewport_point_within_vp(const struct viewport *vp,
#endif /* __PCTOOL__ */ #endif /* __PCTOOL__ */
#ifdef HAVE_LCD_BITMAP
/*
* Parse a viewport definition (vp_def), which looks like:
*
* Screens with depth > 1:
* X|Y|width|height|font|foregorund color|background color
* Screens with depth = 1:
* X|Y|width|height|font
*
* | is a separator and can be specified via the parameter
*
* Returns the pointer to the char after the last character parsed
* if everything went OK or NULL if an error happened (some values
* not specified in the definition)
*/
const char* viewport_parse_viewport(struct viewport *vp,
enum screen_type screen,
const char *vp_def,
const char separator);
#endif /* HAVE_LCD_BITMAP */
#endif /* __VIEWPORT_H__ */ #endif /* __VIEWPORT_H__ */

View file

@ -175,7 +175,7 @@ void fade(bool fade_in, bool updatewps)
if (updatewps) if (updatewps)
{ {
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
skin_update(&gui_wps[i], WPS_REFRESH_NON_STATIC); skin_update(&gui_wps[i], SKIN_REFRESH_NON_STATIC);
} }
sleep(1); sleep(1);
} }
@ -191,7 +191,7 @@ void fade(bool fade_in, bool updatewps)
if (updatewps) if (updatewps)
{ {
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
skin_update(&gui_wps[i], WPS_REFRESH_NON_STATIC); skin_update(&gui_wps[i], SKIN_REFRESH_NON_STATIC);
} }
sleep(1); sleep(1);
} }
@ -212,7 +212,7 @@ void fade(bool fade_in, bool updatewps)
static bool update_onvol_change(struct gui_wps * gwps) static bool update_onvol_change(struct gui_wps * gwps)
{ {
skin_update(gwps, WPS_REFRESH_NON_STATIC); skin_update(gwps, SKIN_REFRESH_NON_STATIC);
#ifdef HAVE_LCD_CHARCELLS #ifdef HAVE_LCD_CHARCELLS
splashf(0, "Vol: %3d dB", splashf(0, "Vol: %3d dB",
@ -372,8 +372,8 @@ bool ffwd_rew(int button)
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
{ {
skin_update(&gui_wps[i], skin_update(&gui_wps[i],
WPS_REFRESH_PLAYER_PROGRESS | SKIN_REFRESH_PLAYER_PROGRESS |
WPS_REFRESH_DYNAMIC); SKIN_REFRESH_DYNAMIC);
} }
break; break;
@ -390,7 +390,7 @@ bool ffwd_rew(int button)
#endif #endif
#ifdef HAVE_LCD_CHARCELLS #ifdef HAVE_LCD_CHARCELLS
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
skin_update(&gui_wps[i], WPS_REFRESH_ALL); skin_update(&gui_wps[i], SKIN_REFRESH_ALL);
#endif #endif
exit = true; exit = true;
break; break;
@ -662,7 +662,7 @@ static void gwps_enter_wps(void)
display->backdrop_show(gwps->data->backdrop); display->backdrop_show(gwps->data->backdrop);
#endif #endif
display->clear_display(); display->clear_display();
skin_update(gwps, WPS_REFRESH_ALL); skin_update(gwps, SKIN_REFRESH_ALL);
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
skin_disarm_touchregions(gui_wps[i].data); skin_disarm_touchregions(gui_wps[i].data);
@ -1116,7 +1116,7 @@ long gui_wps_show(void)
#endif #endif
{ {
skin_update(&gui_wps[i], wps_sync_data.do_full_update ? skin_update(&gui_wps[i], wps_sync_data.do_full_update ?
WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC); SKIN_REFRESH_ALL : SKIN_REFRESH_NON_STATIC);
} }
} }
wps_sync_data.do_full_update = false; wps_sync_data.do_full_update = false;

View file

@ -357,6 +357,7 @@ static void init(void)
tree_mem_init(); tree_mem_init();
filetype_init(); filetype_init();
playlist_init(); playlist_init();
theme_init_buffer();
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
mp3_init( global_settings.volume, mp3_init( global_settings.volume,
@ -639,6 +640,7 @@ static void init(void)
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
tdspeed_init(); tdspeed_init();
#endif /* CONFIG_CODEC == SWCODEC */ #endif /* CONFIG_CODEC == SWCODEC */
theme_init_buffer();
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
/* No buffer allocation (see buffer.c) may take place after the call to /* No buffer allocation (see buffer.c) may take place after the call to

View file

@ -48,7 +48,7 @@
#include "version.h" #include "version.h"
#include "time.h" #include "time.h"
#include "wps.h" #include "wps.h"
#include "skin_engine/skin_buffer.h" #include "skin_buffer.h"
static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG}; static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG};

View file

@ -937,142 +937,23 @@ int hex_to_rgb(const char* hex, int* color)
#endif /* HAVE_LCD_COLOR */ #endif /* HAVE_LCD_COLOR */
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
/* A simplified scanf - used (at time of writing) by wps parsing functions.
fmt - char array specifying the format of each list option. Valid values
are: d - int
s - string (sets pointer to string, without copying)
c - hex colour (RGB888 - e.g. ff00ff)
g - greyscale "colour" (0-3)
set_vals - if not NULL 1 is set in the bitplace if the item was read OK
0 if not read.
first item is LSB, (max 32 items! )
Stops parseing if an item is invalid unless the item == '-'
sep - list separator (e.g. ',' or '|')
str - string to parse, must be terminated by 0 or sep
... - pointers to store the parsed values
return value - pointer to char after parsed data, 0 if there was an error.
*/
/* '0'-'3' are ASCII 0x30 to 0x33 */ /* '0'-'3' are ASCII 0x30 to 0x33 */
#define is0123(x) (((x) & 0xfc) == 0x30) #define is0123(x) (((x) & 0xfc) == 0x30)
const char* parse_list(const char *fmt, uint32_t *set_vals, bool parse_color(char *text, int *value)
const char sep, const char* str, ...)
{ {
va_list ap; (void)text; (void)value; /* silence warnings on mono bitmap */
const char* p = str, *f = fmt;
const char** s;
int* d;
bool set, is_negative;
int i=0;
va_start(ap, str);
if (set_vals)
*set_vals = 0;
while (*fmt)
{
/* Check for separator, if we're not at the start */
if (f != fmt)
{
if (*p != sep)
goto err;
p++;
}
set = false;
switch (*fmt++)
{
case 's': /* string - return a pointer to it (not a copy) */
s = va_arg(ap, const char **);
*s = p;
while (*p && *p != sep && *p != ')')
p++;
set = (s[0][0]!='-') && (s[0][1]!=sep && s[0][1]!=')') ;
break;
case 'd': /* int */
is_negative = false;
d = va_arg(ap, int*);
if (*p == '-' && isdigit(*(p+1)))
{
is_negative = true;
p++;
}
if (!isdigit(*p))
{
if (!set_vals || *p != '-')
goto err;
p++;
}
else
{
*d = *p++ - '0';
while (isdigit(*p))
*d = (*d * 10) + (*p++ - '0');
set = true;
if (is_negative)
*d *= -1;
}
break;
#ifdef HAVE_LCD_COLOR #ifdef HAVE_LCD_COLOR
case 'c': /* colour (rrggbb - e.g. f3c1a8) */ if (hex_to_rgb(text, value) < 0)
d = va_arg(ap, int*); return false;
if (hex_to_rgb(p, d) < 0)
{
if (!set_vals || *p != '-')
goto err;
p++;
}
else
{
p += 6;
set = true;
}
break;
#endif #endif
#if LCD_DEPTH == 2 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2) #if LCD_DEPTH == 2 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2)
case 'g': /* greyscale colour (0-3) */ if (!is0123(*text))
d = va_arg(ap, int*); return false;
*value = *text - '0';
if (!is0123(*p))
{
if (!set_vals || *p != '-')
goto err;
p++;
}
else
{
*d = *p++ - '0';
set = true;
}
break;
#endif #endif
return true;
default: /* Unknown format type */
goto err;
break;
}
if (set_vals && set)
*set_vals |= BIT_N(i);
i++;
}
va_end(ap);
return p;
err:
va_end(ap);
return NULL;
} }
/* only used in USB HID and set_time screen */ /* only used in USB HID and set_time screen */

View file

@ -94,16 +94,7 @@ bool dir_exists(const char *path);
char *strip_extension(char* buffer, int buffer_size, const char *filename); char *strip_extension(char* buffer, int buffer_size, const char *filename);
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
/* A simplified scanf */ bool parse_color(char *text, int *value);
/*
* Checks whether the value at position 'position' was really read
* during a call to 'parse_list'
* - position: 0-based number of the value
* - valid_vals: value after the call to 'parse_list'
*/
#define LIST_VALUE_PARSED(setvals, position) ((setvals) & BIT_N(position))
const char* parse_list(const char *fmt, uint32_t *set_vals,
const char sep, const char* str, ...);
/* only used in USB HID and set_time screen */ /* only used in USB HID and set_time screen */
#if defined(USB_ENABLE_HID) || (CONFIG_RTC != 0) #if defined(USB_ENABLE_HID) || (CONFIG_RTC != 0)

View file

@ -800,8 +800,8 @@ int radio_screen(void)
if (restore) if (restore)
fms_fix_displays(FMS_ENTER); fms_fix_displays(FMS_ENTER);
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
skin_update(fms_get(i), restore ? WPS_REFRESH_ALL : skin_update(fms_get(i), restore ? SKIN_REFRESH_ALL :
WPS_REFRESH_NON_STATIC); SKIN_REFRESH_NON_STATIC);
restore = false; restore = false;
} }
} }

View file

@ -35,9 +35,11 @@
bool find_albumart(const struct mp3entry *id3, char *buf, int buflen, bool find_albumart(const struct mp3entry *id3, char *buf, int buflen,
struct dim *dim); struct dim *dim);
/* Draw the album art bitmap from the given handle ID onto the given WPS. #ifndef PLUGIN
/* Draw the album art bitmap from the given handle ID onto the given Skin.
Call with clear = true to clear the bitmap instead of drawing it. */ Call with clear = true to clear the bitmap instead of drawing it. */
void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear); void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear);
#endif
bool search_albumart_files(const struct mp3entry *id3, const char *size_string, bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
char *buf, int buflen); char *buf, int buflen);

View file

@ -260,6 +260,7 @@ void sound_settings_apply(void);
* skin buffer is reset properly * skin buffer is reset properly
*/ */
void settings_apply_skins(void); void settings_apply_skins(void);
void theme_init_buffer(void);
void settings_apply(bool read_disk); void settings_apply(bool read_disk);
void settings_apply_pm_range(void); void settings_apply_pm_range(void);

View file

@ -1,6 +1,6 @@
skin_buffer.c skin_buffer.c
skin_parser.c skin_parser.c
#ifndef ROCKBOX #if !defined(ROCKBOX) || defined(__PCTOOL__)
skin_debug.c skin_debug.c
#endif #endif
skin_scan.c skin_scan.c

View file

@ -24,21 +24,19 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "skin_buffer.h"
#ifdef ROCKBOX #ifdef ROCKBOX
#define SKIN_BUFFER_SIZE (400*1024) /* Excessivly large for now */ static size_t buf_size;
static unsigned char buffer[SKIN_BUFFER_SIZE]; static unsigned char *buffer_start = NULL;
static unsigned char *buffer_front = NULL; /* start of the free space, static unsigned char *buffer_front = NULL;
increases with allocation*/
#endif #endif
void skin_buffer_init(void) void skin_buffer_init(char* buffer, size_t size)
{ {
#if defined(ROCKBOX) #if defined(ROCKBOX)
{ buffer_start = buffer_front = buffer;
/* reset the buffer.... */ buf_size = size;
buffer_front = buffer;
//TODO: buf_size = size;
}
#endif #endif
} }
@ -47,6 +45,8 @@ void* skin_buffer_alloc(size_t size)
{ {
void *retval = NULL; void *retval = NULL;
#ifdef ROCKBOX #ifdef ROCKBOX
if (size > skin_buffer_freespace())
return NULL;
retval = buffer_front; retval = buffer_front;
buffer_front += size; buffer_front += size;
/* 32-bit aligned */ /* 32-bit aligned */
@ -62,10 +62,22 @@ void* skin_buffer_alloc(size_t size)
/* get the number of bytes currently being used */ /* get the number of bytes currently being used */
size_t skin_buffer_usage(void) size_t skin_buffer_usage(void)
{ {
return buffer_front - buffer; return buffer_front - buffer_start;
} }
size_t skin_buffer_freespace(void) size_t skin_buffer_freespace(void)
{ {
return SKIN_BUFFER_SIZE - skin_buffer_usage(); return buf_size - skin_buffer_usage();
}
static unsigned char *saved_buffer_pos = NULL;
void skin_buffer_save_position(void)
{
saved_buffer_pos = buffer_front;
}
void skin_buffer_restore_position(void)
{
if (saved_buffer_pos)
buffer_front = saved_buffer_pos;
} }
#endif #endif

View file

@ -25,11 +25,15 @@
#include <stdlib.h> #include <stdlib.h>
#ifndef _SKIN_BUFFFER_H_ #ifndef _SKIN_BUFFFER_H_
#define _SKIN_BUFFFER_H_ #define _SKIN_BUFFFER_H_
void skin_buffer_init(size_t size); void skin_buffer_init(char* buffer, size_t size);
/* Allocate size bytes from the buffer */ /* Allocate size bytes from the buffer */
void* skin_buffer_alloc(size_t size); void* skin_buffer_alloc(size_t size);
/* get the number of bytes currently being used */ /* get the number of bytes currently being used */
size_t skin_buffer_usage(void); size_t skin_buffer_usage(void);
size_t skin_buffer_freespace(void); size_t skin_buffer_freespace(void);
/* save and restore a buffer position incase a skin fails to load */
void skin_buffer_save_position(void);
void skin_buffer_restore_position(void);
#endif #endif

View file

@ -35,6 +35,7 @@ extern char* skin_start;
/* Global error variables */ /* Global error variables */
int error_line; int error_line;
int error_col; int error_col;
char *error_line_start;
char* error_message; char* error_message;
/* Debugging functions */ /* Debugging functions */
@ -48,6 +49,7 @@ void skin_error(enum skin_errorcode error, char* cursor)
cursor--; cursor--;
error_col++; error_col++;
} }
error_line_start = cursor+1;
error_line = skin_line; error_line = skin_line;
@ -285,4 +287,42 @@ void skin_debug_indent()
for(i = 0; i < debug_indent_level; i++) for(i = 0; i < debug_indent_level; i++)
printf(" "); printf(" ");
} }
#endif #endif
#define MIN(a,b) ((a<b)?(a):(b))
void skin_error_format_message()
{
int i;
char text[128];
char* line_end = strchr(error_line_start, '\n');
int len = MIN(line_end - error_line_start, 80);
if (!line_end)
len = strlen(error_line_start);
printf("Error on line %d.\n", error_line);
error_col--;
if (error_col <= 10)
{
strncpy(text, error_line_start, len);
text[len] = '\0';
}
else
{
int j;
/* make it fit nicely.. "<start few chars>...<10 chars><error>" */
strncpy(text, error_line_start, 6);
i = 5;
text[i++] = '.';
text[i++] = '.';
text[i++] = '.';
for (j=error_col-10; error_line_start[j] && error_line_start[j] != '\n'; j++)
text[i++] = error_line_start[j];
text[i] = '\0';
error_col = 18;
}
printf("%s\n", text);
for (i=0; i<error_col; i++)
text[i] = ' ';
snprintf(&text[i],64, "^ \'%s\' Here", error_message);
printf("%s\n", text);
}

View file

@ -28,8 +28,12 @@ extern "C"
{ {
#endif #endif
#if !defined(ROCKBOX) || defined(__PCTOOL__)
#define SKINPARSER_DEBUG
#endif
#include "skin_parser.h" #include "skin_parser.h"
#ifndef ROCKBOX #ifdef SKINPARSER_DEBUG
/* Debugging functions */ /* Debugging functions */
void skin_error(enum skin_errorcode error, char* cursor); void skin_error(enum skin_errorcode error, char* cursor);
int skin_error_line(void); int skin_error_line(void);
@ -37,6 +41,7 @@ int skin_error_col(void);
char* skin_error_message(void); char* skin_error_message(void);
void skin_clear_errors(void); void skin_clear_errors(void);
void skin_debug_tree(struct skin_element* root); void skin_debug_tree(struct skin_element* root);
void skin_error_format_message();
/* Auxiliary debug functions */ /* Auxiliary debug functions */
void skin_debug_params(int count, struct skin_tag_parameter params[]); void skin_debug_params(int count, struct skin_tag_parameter params[]);
@ -46,7 +51,7 @@ void skin_debug_indent(void);
#define skin_error(...) #define skin_error(...)
#define skin_clear_errors() #define skin_clear_errors()
#endif /* !ROCKBOX */ #endif /* SKINPARSER_DEBUG */
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -21,6 +21,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <stdbool.h> #include <stdbool.h>
@ -37,6 +38,11 @@ int skin_line = 0;
char* skin_start = 0; char* skin_start = 0;
int viewport_line = 0; int viewport_line = 0;
#ifdef ROCKBOX
static skin_callback callback = NULL;
static void* callback_data;
#endif
/* Auxiliary parsing functions (not visible at global scope) */ /* Auxiliary parsing functions (not visible at global scope) */
static struct skin_element* skin_parse_viewport(char** document); static struct skin_element* skin_parse_viewport(char** document);
static struct skin_element* skin_parse_line(char** document); static struct skin_element* skin_parse_line(char** document);
@ -55,10 +61,23 @@ static int skin_parse_comment(struct skin_element* element, char** document);
static struct skin_element* skin_parse_code_as_arg(char** document); static struct skin_element* skin_parse_code_as_arg(char** document);
static void skip_whitespace(char** document)
{
while(**document == ' ' || **document == '\t')
(*document)++;
}
#ifdef ROCKBOX
struct skin_element* skin_parse(const char* document,
skin_callback cb, void* cb_data)
{
callback = cb;
callback_data = cb_data;
#else
struct skin_element* skin_parse(const char* document) struct skin_element* skin_parse(const char* document)
{ {
#endif
struct skin_element* root = NULL; struct skin_element* root = NULL;
struct skin_element* last = NULL; struct skin_element* last = NULL;
@ -94,7 +113,6 @@ struct skin_element* skin_parse(const char* document)
last = last->next; last = last->next;
} }
return root; return root;
} }
@ -107,6 +125,8 @@ static struct skin_element* skin_parse_viewport(char** document)
struct skin_element* retval = NULL; struct skin_element* retval = NULL;
retval = skin_alloc_element(); retval = skin_alloc_element();
if (!retval)
return NULL;
retval->type = VIEWPORT; retval->type = VIEWPORT;
retval->children_count = 1; retval->children_count = 1;
retval->line = skin_line; retval->line = skin_line;
@ -129,11 +149,18 @@ static struct skin_element* skin_parse_viewport(char** document)
skin_line++; skin_line++;
} }
} }
#ifdef ROCKBOX
else if (callback)
{
if (callback(retval, callback_data) == CALLBACK_ERROR)
return NULL;
}
#endif
retval->children_count = 1; retval->children_count = 1;
retval->children = skin_alloc_children(1); retval->children = skin_alloc_children(1);
if (!retval->children)
return NULL;
do do
{ {
@ -199,7 +226,6 @@ static struct skin_element* skin_parse_viewport(char** document)
return NULL; return NULL;
} }
/* Making sure last is at the end */ /* Making sure last is at the end */
while(last->next) while(last->next)
last = last->next; last = last->next;
@ -245,6 +271,8 @@ static struct skin_element* skin_parse_line_optional(char** document,
/* A wrapper for the line */ /* A wrapper for the line */
retval = skin_alloc_element(); retval = skin_alloc_element();
if (!retval)
return NULL;
retval->type = LINE; retval->type = LINE;
retval->line = skin_line; retval->line = skin_line;
if(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM if(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM
@ -261,7 +289,24 @@ static struct skin_element* skin_parse_line_optional(char** document,
} }
if(retval->children_count > 0) if(retval->children_count > 0)
{
retval->children = skin_alloc_children(1); retval->children = skin_alloc_children(1);
if (!retval->children)
return NULL;
}
#ifdef ROCKBOX
if (callback)
{
switch (callback(retval, callback_data))
{
case CALLBACK_ERROR:
return NULL;
default:
break;
}
}
#endif
while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM
&& !((*cursor == ARGLISTSEPERATESYM && !((*cursor == ARGLISTSEPERATESYM
@ -275,11 +320,15 @@ static struct skin_element* skin_parse_line_optional(char** document,
if(root) if(root)
{ {
current->next = skin_alloc_element(); current->next = skin_alloc_element();
if (!current->next)
return NULL;
current = current->next; current = current->next;
} }
else else
{ {
current = skin_alloc_element(); current = skin_alloc_element();
if (!current)
return NULL;
root = current; root = current;
} }
@ -306,6 +355,7 @@ static struct skin_element* skin_parse_line_optional(char** document,
} }
} }
/* Moving up the calling function's pointer */ /* Moving up the calling function's pointer */
*document = cursor; *document = cursor;
@ -328,6 +378,8 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
int i; int i;
retval = skin_alloc_element(); retval = skin_alloc_element();
if (!retval)
return NULL;
retval->type = LINE_ALTERNATOR; retval->type = LINE_ALTERNATOR;
retval->next = NULL; retval->next = NULL;
retval->line = skin_line; retval->line = skin_line;
@ -374,6 +426,8 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
/* ...and then we parse them */ /* ...and then we parse them */
retval->children_count = sublines; retval->children_count = sublines;
retval->children = skin_alloc_children(sublines); retval->children = skin_alloc_children(sublines);
if (!retval->children)
return NULL;
cursor = *document; cursor = *document;
for(i = 0; i < sublines; i++) for(i = 0; i < sublines; i++)
@ -392,6 +446,13 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
} }
} }
#ifdef ROCKBOX
if (callback)
{
if (callback(retval, callback_data) == CALLBACK_ERROR)
return NULL;
}
#endif
*document = cursor; *document = cursor;
return retval; return retval;
@ -458,6 +519,14 @@ static int skin_parse_tag(struct skin_element* element, char** document)
|| (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM) || (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM)
|| (star && *cursor != ARGLISTOPENSYM)) || (star && *cursor != ARGLISTOPENSYM))
{ {
#ifdef ROCKBOX
if (callback)
{
if (callback(element, callback_data) == CALLBACK_ERROR)
return 0;
}
#endif
*document = cursor; *document = cursor;
return 1; return 1;
} }
@ -507,6 +576,8 @@ static int skin_parse_tag(struct skin_element* element, char** document)
cursor = bookmark; /* Restoring the cursor */ cursor = bookmark; /* Restoring the cursor */
element->params_count = num_args; element->params_count = num_args;
element->params = skin_alloc_params(num_args); element->params = skin_alloc_params(num_args);
if (!element->params)
return 0;
/* Now we have to actually parse each argument */ /* Now we have to actually parse each argument */
for(i = 0; i < num_args; i++) for(i = 0; i < num_args; i++)
@ -587,7 +658,6 @@ static int skin_parse_tag(struct skin_element* element, char** document)
} }
if (have_tenth == false) if (have_tenth == false)
val *= 10; val *= 10;
element->params[i].type = DECIMAL; element->params[i].type = DECIMAL;
element->params[i].data.number = val; element->params[i].data.number = val;
} }
@ -644,7 +714,13 @@ static int skin_parse_tag(struct skin_element* element, char** document)
skin_error(INSUFFICIENT_ARGS, cursor); skin_error(INSUFFICIENT_ARGS, cursor);
return 0; return 0;
} }
#ifdef ROCKBOX
if (callback)
{
if (callback(element, callback_data) == CALLBACK_ERROR)
return 0;
}
#endif
*document = cursor; *document = cursor;
return 1; return 1;
@ -691,6 +767,8 @@ static int skin_parse_text(struct skin_element* element, char** document,
element->line = skin_line; element->line = skin_line;
element->next = NULL; element->next = NULL;
element->data = text = skin_alloc_string(length); element->data = text = skin_alloc_string(length);
if (!element->data)
return 0;
for(dest = 0; dest < length; dest++) for(dest = 0; dest < length; dest++)
{ {
@ -703,6 +781,14 @@ static int skin_parse_text(struct skin_element* element, char** document,
} }
text[length] = '\0'; text[length] = '\0';
#ifdef ROCKBOX
if (callback)
{
if (callback(element, callback_data) == CALLBACK_ERROR)
return 0;
}
#endif
*document = cursor; *document = cursor;
return 1; return 1;
@ -716,13 +802,39 @@ static int skin_parse_conditional(struct skin_element* element, char** document)
int children = 1; int children = 1;
int i; int i;
element->type = CONDITIONAL; #ifdef ROCKBOX
bool feature_available = true;
char *false_branch = NULL;
#endif
/* Some conditional tags allow for target feature checking,
* so to handle that call the callback as usual with type == TAG
* then call it a second time with type == CONDITIONAL and check the return
* value */
element->type = TAG;
element->line = skin_line; element->line = skin_line;
/* Parsing the tag first */ /* Parsing the tag first */
if(!skin_parse_tag(element, &cursor)) if(!skin_parse_tag(element, &cursor))
return 0; return 0;
element->type = CONDITIONAL;
#ifdef ROCKBOX
if (callback)
{
switch (callback(element, callback_data))
{
case FEATURE_NOT_AVAILABLE:
feature_available = false;
break;
case CALLBACK_ERROR:
return 0;
default:
break;
}
}
#endif
/* Counting the children */ /* Counting the children */
if(*(cursor++) != ENUMLISTOPENSYM) if(*(cursor++) != ENUMLISTOPENSYM)
{ {
@ -751,16 +863,35 @@ static int skin_parse_conditional(struct skin_element* element, char** document)
{ {
children++; children++;
cursor++; cursor++;
#ifdef ROCKBOX
if (false_branch == NULL && !feature_available)
{
false_branch = cursor;
children--;
}
#endif
} }
else else
{ {
cursor++; cursor++;
} }
} }
#ifdef ROCKBOX
if (*cursor == ENUMLISTCLOSESYM &&
false_branch == NULL && !feature_available)
{
false_branch = cursor+1;
children--;
}
/* if we are skipping the true branch fix that up */
cursor = false_branch ? false_branch : bookmark;
#else
cursor = bookmark; cursor = bookmark;
#endif
/* Parsing the children */ /* Parsing the children */
element->children = skin_alloc_children(children); element->children = skin_alloc_children(children);
if (!element->children)
return 0;
element->children_count = children; element->children_count = children;
for(i = 0; i < children; i++) for(i = 0; i < children; i++)
@ -809,6 +940,8 @@ static int skin_parse_comment(struct skin_element* element, char** document)
element->data = NULL; element->data = NULL;
#else #else
element->data = text = skin_alloc_string(length); element->data = text = skin_alloc_string(length);
if (!element->data)
return 0;
/* We copy from one char past cursor to leave out the # */ /* We copy from one char past cursor to leave out the # */
memcpy((void*)text, (void*)(cursor + 1), memcpy((void*)text, (void*)(cursor + 1),
sizeof(char) * (length-1)); sizeof(char) * (length-1));
@ -877,6 +1010,8 @@ struct skin_element* skin_alloc_element()
{ {
struct skin_element* retval = (struct skin_element*) struct skin_element* retval = (struct skin_element*)
skin_buffer_alloc(sizeof(struct skin_element)); skin_buffer_alloc(sizeof(struct skin_element));
if (!retval)
return NULL;
retval->type = UNKNOWN; retval->type = UNKNOWN;
retval->next = NULL; retval->next = NULL;
retval->tag = NULL; retval->tag = NULL;
@ -886,9 +1021,21 @@ struct skin_element* skin_alloc_element()
return retval; return retval;
} }
/* On a ROCKBOX build we try to save space as much as possible
* so if we can, use a shared param pool which should be more then large
* enough for any tag. params should be used straight away by the callback
* so this is safe.
*/
struct skin_tag_parameter* skin_alloc_params(int count) struct skin_tag_parameter* skin_alloc_params(int count)
{ {
#ifdef ROCKBOX
static struct skin_tag_parameter params[MAX_TAG_PARAMS];
if (count <= MAX_TAG_PARAMS)
{
memset(params, 0, sizeof(params));
return params;
}
#endif
size_t size = sizeof(struct skin_tag_parameter) * count; size_t size = sizeof(struct skin_tag_parameter) * count;
return (struct skin_tag_parameter*)skin_buffer_alloc(size); return (struct skin_tag_parameter*)skin_buffer_alloc(size);

View file

@ -115,14 +115,27 @@ struct skin_element
struct skin_element* next; struct skin_element* next;
}; };
enum skin_cb_returnvalue
{
CALLBACK_ERROR = -666,
FEATURE_NOT_AVAILABLE,
CALLBACK_OK = 0,
/* > 0 reserved for future use */
};
typedef int (*skin_callback)(struct skin_element* element, void* data);
/*********************************************************************** /***********************************************************************
***** Functions ******************************************************* ***** Functions *******************************************************
**********************************************************************/ **********************************************************************/
/* Parses a WPS document and returns a list of skin_element /* Parses a WPS document and returns a list of skin_element
structures. */ structures. */
#ifdef ROCKBOX
struct skin_element* skin_parse(const char* document,
skin_callback callback, void* callback_data);
#else
struct skin_element* skin_parse(const char* document); struct skin_element* skin_parse(const char* document);
#endif
/* Memory management functions */ /* Memory management functions */
struct skin_element* skin_alloc_element(void); struct skin_element* skin_alloc_element(void);
struct skin_element** skin_alloc_children(int count); struct skin_element** skin_alloc_children(int count);

View file

@ -40,12 +40,6 @@ void skip_comment(char** document)
(*document)++; (*document)++;
} }
void skip_whitespace(char** document)
{
while(**document == ' ' || **document == '\t')
(*document)++;
}
void skip_arglist(char** document) void skip_arglist(char** document)
{ {
if(**document == ARGLISTOPENSYM) if(**document == ARGLISTOPENSYM)
@ -132,6 +126,8 @@ char* scan_string(char** document)
/* Copying the string */ /* Copying the string */
cursor = *document; cursor = *document;
buffer = skin_alloc_string(length); buffer = skin_alloc_string(length);
if (!buffer)
return NULL;
buffer[length] = '\0'; buffer[length] = '\0';
for(i = 0; i < length; i++) for(i = 0; i < length; i++)
{ {

View file

@ -30,7 +30,6 @@ extern "C"
/* Scanning functions */ /* Scanning functions */
void skip_comment(char** document); void skip_comment(char** document);
void skip_whitespace(char** document);
void skip_arglist(char** document); void skip_arglist(char** document);
void skip_enumlist(char** document); void skip_enumlist(char** document);
char* scan_string(char** document); char* scan_string(char** document);

View file

@ -33,182 +33,181 @@ struct tag_info legal_tags[] =
{ SKIN_TOKEN_ALIGN_RIGHT_RTL, "aR", "", 0 }, { SKIN_TOKEN_ALIGN_RIGHT_RTL, "aR", "", 0 },
{ SKIN_TOKEN_ALIGN_LANGDIRECTION, "ax", "", 0 }, { SKIN_TOKEN_ALIGN_LANGDIRECTION, "ax", "", 0 },
{ SKIN_TOKEN_BATTERY_PERCENT, "bl" , BAR_PARAMS, 0 }, { SKIN_TOKEN_BATTERY_PERCENT, "bl" , BAR_PARAMS, SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BATTERY_VOLTS, "bv", "", 0 }, { SKIN_TOKEN_BATTERY_VOLTS, "bv", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BATTERY_TIME, "bt", "", 0 }, { SKIN_TOKEN_BATTERY_TIME, "bt", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BATTERY_SLEEPTIME, "bs", "", 0 }, { SKIN_TOKEN_BATTERY_SLEEPTIME, "bs", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BATTERY_CHARGING, "bc", "", 0 }, { SKIN_TOKEN_BATTERY_CHARGING, "bc", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BATTERY_CHARGER_CONNECTED, "bp", "", 0 }, { SKIN_TOKEN_BATTERY_CHARGER_CONNECTED, "bp", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_USB_POWERED, "bu", "", 0 }, { SKIN_TOKEN_USB_POWERED, "bu", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_RTC_PRESENT, "cc", "", 0 }, { SKIN_TOKEN_RTC_PRESENT, "cc", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_RTC_DAY_OF_MONTH, "cd", "", 0 }, { SKIN_TOKEN_RTC_DAY_OF_MONTH, "cd", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, "ce", "", 0 }, { SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, "ce", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_12HOUR_CFG, "cf", "", 0 }, { SKIN_TOKEN_RTC_12HOUR_CFG, "cf", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", "", 0 }, { SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_HOUR_24, "ck", "", 0 }, { SKIN_TOKEN_RTC_HOUR_24, "ck", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", "", 0 }, { SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_HOUR_12, "cl", "", 0 }, { SKIN_TOKEN_RTC_HOUR_12, "cl", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_MONTH, "cm", "", 0 }, { SKIN_TOKEN_RTC_MONTH, "cm", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_MINUTE, "cM", "", 0 }, { SKIN_TOKEN_RTC_MINUTE, "cM", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_SECOND, "cS", "", 0 }, { SKIN_TOKEN_RTC_SECOND, "cS", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_YEAR_2_DIGITS, "cy", "", 0 }, { SKIN_TOKEN_RTC_YEAR_2_DIGITS, "cy", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_YEAR_4_DIGITS, "cY", "", 0 }, { SKIN_TOKEN_RTC_YEAR_4_DIGITS, "cY", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_AM_PM_UPPER, "cP", "", 0 }, { SKIN_TOKEN_RTC_AM_PM_UPPER, "cP", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_AM_PM_LOWER, "cp", "", 0 }, { SKIN_TOKEN_RTC_AM_PM_LOWER, "cp", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_WEEKDAY_NAME, "ca", "", 0 }, { SKIN_TOKEN_RTC_WEEKDAY_NAME, "ca", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_MONTH_NAME, "cb", "", 0 }, { SKIN_TOKEN_RTC_MONTH_NAME, "cb", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", "", 0 }, { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", "", 0 }, { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", "", SKIN_RTC_REFRESH },
{ SKIN_TOKEN_FILE_BITRATE, "fb", "", 0 }, { SKIN_TOKEN_FILE_BITRATE, "fb", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_CODEC, "fc", "", 0 }, { SKIN_TOKEN_FILE_CODEC, "fc", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_FREQUENCY, "ff", "", 0 }, { SKIN_TOKEN_FILE_FREQUENCY, "ff", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_FREQUENCY_KHZ, "fk", "", 0 }, { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "fk", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", "", 0 }, { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_NAME, "fn", "", 0 }, { SKIN_TOKEN_FILE_NAME, "fn", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_PATH, "fp", "", 0 }, { SKIN_TOKEN_FILE_PATH, "fp", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_SIZE, "fs", "", 0 }, { SKIN_TOKEN_FILE_SIZE, "fs", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_VBR, "fv", "", 0 }, { SKIN_TOKEN_FILE_VBR, "fv", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_DIRECTORY, "d" , "I", 0 }, { SKIN_TOKEN_FILE_DIRECTORY, "d" , "I", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_BITRATE, "Fb", "", 0 }, { SKIN_TOKEN_FILE_BITRATE, "Fb", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_CODEC, "Fc", "", 0 }, { SKIN_TOKEN_FILE_CODEC, "Fc", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_FREQUENCY, "Ff", "", 0 }, { SKIN_TOKEN_FILE_FREQUENCY, "Ff", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_FREQUENCY_KHZ, "Fk", "", 0 }, { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "Fk", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", "", 0 }, { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_NAME, "Fn", "", 0 }, { SKIN_TOKEN_FILE_NAME, "Fn", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_PATH, "Fp", "", 0 }, { SKIN_TOKEN_FILE_PATH, "Fp", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_SIZE, "Fs", "", 0 }, { SKIN_TOKEN_FILE_SIZE, "Fs", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_VBR, "Fv", "", 0 }, { SKIN_TOKEN_FILE_VBR, "Fv", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_FILE_DIRECTORY, "D" , "I", 0 }, { SKIN_TOKEN_FILE_DIRECTORY, "D" , "I", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_ARTIST, "ia", "", 0 }, { SKIN_TOKEN_METADATA_ARTIST, "ia", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_COMPOSER, "ic", "", 0 }, { SKIN_TOKEN_METADATA_COMPOSER, "ic", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_ALBUM, "id", "", 0 }, { SKIN_TOKEN_METADATA_ALBUM, "id", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_ALBUM_ARTIST, "iA", "", 0 }, { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "iA", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_GROUPING, "iG", "", 0 }, { SKIN_TOKEN_METADATA_GROUPING, "iG", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_GENRE, "ig", "", 0 }, { SKIN_TOKEN_METADATA_GENRE, "ig", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_DISC_NUMBER, "ik", "", 0 }, { SKIN_TOKEN_METADATA_DISC_NUMBER, "ik", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_TRACK_NUMBER, "in", "", 0 }, { SKIN_TOKEN_METADATA_TRACK_NUMBER, "in", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_TRACK_TITLE, "it", "", 0 }, { SKIN_TOKEN_METADATA_TRACK_TITLE, "it", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_VERSION, "iv", "", 0 }, { SKIN_TOKEN_METADATA_VERSION, "iv", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_YEAR, "iy", "", 0 }, { SKIN_TOKEN_METADATA_YEAR, "iy", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_COMMENT, "iC", "", 0 }, { SKIN_TOKEN_METADATA_COMMENT, "iC", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_ARTIST, "Ia", "", 0 }, { SKIN_TOKEN_METADATA_ARTIST, "Ia", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_COMPOSER, "Ic", "", 0 }, { SKIN_TOKEN_METADATA_COMPOSER, "Ic", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_ALBUM, "Id", "", 0 }, { SKIN_TOKEN_METADATA_ALBUM, "Id", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_ALBUM_ARTIST, "IA", "", 0 }, { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "IA", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_GROUPING, "IG", "", 0 }, { SKIN_TOKEN_METADATA_GROUPING, "IG", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_GENRE, "Ig", "", 0 }, { SKIN_TOKEN_METADATA_GENRE, "Ig", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_DISC_NUMBER, "Ik", "", 0 }, { SKIN_TOKEN_METADATA_DISC_NUMBER, "Ik", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_TRACK_NUMBER, "In", "", 0 }, { SKIN_TOKEN_METADATA_TRACK_NUMBER, "In", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_TRACK_TITLE, "It", "", 0 }, { SKIN_TOKEN_METADATA_TRACK_TITLE, "It", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_VERSION, "Iv", "", 0 }, { SKIN_TOKEN_METADATA_VERSION, "Iv", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_YEAR, "Iy", "", 0 }, { SKIN_TOKEN_METADATA_YEAR, "Iy", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_METADATA_COMMENT, "IC", "", 0 }, { SKIN_TOKEN_METADATA_COMMENT, "IC", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_SOUND_PITCH, "Sp", "", 0 }, { SKIN_TOKEN_SOUND_PITCH, "Sp", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_SOUND_SPEED, "Ss", "", 0 }, { SKIN_TOKEN_SOUND_SPEED, "Ss", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_VLED_HDD, "lh", "", 0 }, { SKIN_TOKEN_VLED_HDD, "lh", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_MAIN_HOLD, "mh", "", 0 }, { SKIN_TOKEN_MAIN_HOLD, "mh", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REMOTE_HOLD, "mr", "", 0 }, { SKIN_TOKEN_REMOTE_HOLD, "mr", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REPEAT_MODE, "mm", "", 0 }, { SKIN_TOKEN_REPEAT_MODE, "mm", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_PLAYBACK_STATUS, "mp", "", 0 }, { SKIN_TOKEN_PLAYBACK_STATUS, "mp", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BUTTON_VOLUME, "mv", "|D", 0 }, { SKIN_TOKEN_BUTTON_VOLUME, "mv", "|D", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_PEAKMETER, "pm", "", 0 }, { SKIN_TOKEN_PEAKMETER, "pm", "", SKIN_REFRESH_PEAK_METER },
{ SKIN_TOKEN_PLAYER_PROGRESSBAR, "pf", "", 0 }, { SKIN_TOKEN_PLAYER_PROGRESSBAR, "pf", "", SKIN_REFRESH_DYNAMIC|SKIN_REFRESH_PLAYER_PROGRESS },
{ SKIN_TOKEN_PROGRESSBAR, "pb" , BAR_PARAMS, 0 }, { SKIN_TOKEN_PROGRESSBAR, "pb" , BAR_PARAMS, SKIN_REFRESH_PLAYER_PROGRESS },
{ SKIN_TOKEN_VOLUME, "pv" , BAR_PARAMS, 0 }, { SKIN_TOKEN_VOLUME, "pv" , BAR_PARAMS, SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_ELAPSED_PERCENT, "px", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_TIME_ELAPSED, "pc", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_TIME_REMAINING, "pr", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_LENGTH, "pt", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_TRACK_STARTING, "pS" , "|D", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_ENDING, "pE" , "|D", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_PLAYLIST_POSITION, "pp", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_PLAYLIST_ENTRIES, "pe", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_PLAYLIST_NAME, "pn", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_PLAYLIST_SHUFFLE, "ps", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_ELAPSED_PERCENT, "px", "", 0 }, { SKIN_TOKEN_DATABASE_PLAYCOUNT, "rp", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_TIME_ELAPSED, "pc", "", 0 }, { SKIN_TOKEN_DATABASE_RATING, "rr", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_TIME_REMAINING, "pr", "", 0 }, { SKIN_TOKEN_DATABASE_AUTOSCORE, "ra", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRACK_LENGTH, "pt", "", 0 },
{ SKIN_TOKEN_TRACK_STARTING, "pS" , "|D", 0 },
{ SKIN_TOKEN_TRACK_ENDING, "pE" , "|D", 0 },
{ SKIN_TOKEN_PLAYLIST_POSITION, "pp", "", 0 },
{ SKIN_TOKEN_PLAYLIST_ENTRIES, "pe", "", 0 },
{ SKIN_TOKEN_PLAYLIST_NAME, "pn", "", 0 },
{ SKIN_TOKEN_PLAYLIST_SHUFFLE, "ps", "", 0 },
{ SKIN_TOKEN_DATABASE_PLAYCOUNT, "rp", "", 0 }, { SKIN_TOKEN_REPLAYGAIN, "rg", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_DATABASE_RATING, "rr", "", 0 }, { SKIN_TOKEN_CROSSFADE, "xf", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_DATABASE_AUTOSCORE, "ra", "", 0 },
{ SKIN_TOKEN_REPLAYGAIN, "rg", "", 0 }, { SKIN_TOKEN_HAVE_TUNER, "tp", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_CROSSFADE, "xf", "", 0 }, { SKIN_TOKEN_TUNER_TUNED, "tt", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TUNER_SCANMODE, "tm", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TUNER_STEREO, "ts", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TUNER_MINFREQ, "ta", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_TUNER_MAXFREQ, "tb", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_TUNER_CURFREQ, "tf", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_PRESET_ID, "Ti", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_PRESET_NAME, "Tn", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_PRESET_FREQ, "Tf", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_PRESET_COUNT, "Tc", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_HAVE_RDS, "tx", "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_RDS_NAME, "ty", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_RDS_TEXT, "tz", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_HAVE_TUNER, "tp", "", 0 }, { SKIN_TOKEN_SUBLINE_SCROLL, "s", "", SKIN_REFRESH_SCROLL },
{ SKIN_TOKEN_TUNER_TUNED, "tt", "", 0 },
{ SKIN_TOKEN_TUNER_SCANMODE, "tm", "", 0 },
{ SKIN_TOKEN_TUNER_STEREO, "ts", "", 0 },
{ SKIN_TOKEN_TUNER_MINFREQ, "ta", "", 0 },
{ SKIN_TOKEN_TUNER_MAXFREQ, "tb", "", 0 },
{ SKIN_TOKEN_TUNER_CURFREQ, "tf", "", 0 },
{ SKIN_TOKEN_PRESET_ID, "Ti", "", 0 },
{ SKIN_TOKEN_PRESET_NAME, "Tn", "", 0 },
{ SKIN_TOKEN_PRESET_FREQ, "Tf", "", 0 },
{ SKIN_TOKEN_PRESET_COUNT, "Tc", "", 0 },
{ SKIN_TOKEN_HAVE_RDS, "tx", "", 0 },
{ SKIN_TOKEN_RDS_NAME, "ty", "", 0 },
{ SKIN_TOKEN_RDS_TEXT, "tz", "", 0 },
{ SKIN_TOKEN_SUBLINE_SCROLL, "s", "", 0 },
{ SKIN_TOKEN_SUBLINE_TIMEOUT, "t" , "D", 0 }, { SKIN_TOKEN_SUBLINE_TIMEOUT, "t" , "D", 0 },
{ SKIN_TOKEN_ENABLE_THEME, "we", "", NOBREAK }, { SKIN_TOKEN_ENABLE_THEME, "we", "", 0|NOBREAK },
{ SKIN_TOKEN_DISABLE_THEME, "wd", "", NOBREAK }, { SKIN_TOKEN_DISABLE_THEME, "wd", "", 0|NOBREAK },
{ SKIN_TOKEN_DRAW_INBUILTBAR, "wi", "", NOBREAK }, { SKIN_TOKEN_DRAW_INBUILTBAR, "wi", "", SKIN_REFRESH_STATIC|NOBREAK },
{ SKIN_TOKEN_IMAGE_PRELOAD, "xl", "SFII|I", NOBREAK }, { SKIN_TOKEN_IMAGE_PRELOAD, "xl", "SFII|I", 0|NOBREAK },
{ SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", "S", 0 }, { SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", "S", 0 },
{ SKIN_TOKEN_IMAGE_PRELOAD, "x", "SFII", NOBREAK }, { SKIN_TOKEN_IMAGE_DISPLAY, "x", "SFII", 0|NOBREAK },
{ SKIN_TOKEN_LOAD_FONT, "Fl" , "IF", NOBREAK }, { SKIN_TOKEN_LOAD_FONT, "Fl" , "IF", 0|NOBREAK },
{ SKIN_TOKEN_ALBUMART_LOAD, "Cl" , "IIII|ss", NOBREAK }, { SKIN_TOKEN_ALBUMART_LOAD, "Cl" , "IIII|ss", 0|NOBREAK },
{ SKIN_TOKEN_ALBUMART_DISPLAY, "Cd" , "", 0 }, { SKIN_TOKEN_ALBUMART_DISPLAY, "Cd" , "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_ALBUMART_FOUND, "C" , "", 0 }, { SKIN_TOKEN_ALBUMART_FOUND, "C" , "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_VIEWPORT_ENABLE, "Vd" , "S", 0 }, { SKIN_TOKEN_VIEWPORT_ENABLE, "Vd" , "S", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_UIVIEWPORT_ENABLE, "VI" , "S", 0 }, { SKIN_TOKEN_UIVIEWPORT_ENABLE, "VI" , "S", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "ICC", NOBREAK }, { SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "ICC", SKIN_REFRESH_DYNAMIC|NOBREAK },
{ SKIN_TOKEN_LIST_TITLE_TEXT, "Lt" , "", 0 }, { SKIN_TOKEN_LIST_TITLE_TEXT, "Lt" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_LIST_TITLE_ICON, "Li" , "", 0 }, { SKIN_TOKEN_LIST_TITLE_ICON, "Li" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_VIEWPORT_FGCOLOUR, "Vf" , "S", NOBREAK }, { SKIN_TOKEN_VIEWPORT_FGCOLOUR, "Vf" , "s", SKIN_REFRESH_STATIC|NOBREAK },
{ SKIN_TOKEN_VIEWPORT_BGCOLOUR, "Vb" , "S", NOBREAK }, { SKIN_TOKEN_VIEWPORT_BGCOLOUR, "Vb" , "s", SKIN_REFRESH_STATIC|NOBREAK },
{ SKIN_TOKEN_VIEWPORT_CONDITIONAL, "Vl" , "SIIiii", 0 }, { SKIN_TOKEN_VIEWPORT_CONDITIONAL, "Vl" , "SIIiii", 0 },
{ SKIN_TOKEN_UIVIEWPORT_LOAD, "Vi" , "sIIiii", 0 }, { SKIN_TOKEN_UIVIEWPORT_LOAD, "Vi" , "sIIiii", 0 },
{ SKIN_TOKEN_VIEWPORT_LOAD, "V" , "IIiii", 0 }, { SKIN_TOKEN_VIEWPORT_LOAD, "V" , "IIiii", 0 },
{ SKIN_TOKEN_IMAGE_BACKDROP, "X" , "f", NOBREAK }, { SKIN_TOKEN_IMAGE_BACKDROP, "X" , "f", SKIN_REFRESH_STATIC|NOBREAK },
{ SKIN_TOKEN_SETTING, "St" , "S", 0 }, { SKIN_TOKEN_SETTING, "St" , "S", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TRANSLATEDSTRING, "Sx" , "S", 0 }, { SKIN_TOKEN_TRANSLATEDSTRING, "Sx" , "S", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_LANG_IS_RTL, "Sr" , "", 0 }, { SKIN_TOKEN_LANG_IS_RTL, "Sr" , "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_LASTTOUCH, "Tl" , "|D", 0 }, { SKIN_TOKEN_LASTTOUCH, "Tl" , "|D", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_CURRENT_SCREEN, "cs", "", 0 }, { SKIN_TOKEN_CURRENT_SCREEN, "cs", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_TOUCHREGION, "T" , "IIiiS", NOBREAK }, { SKIN_TOKEN_TOUCHREGION, "T" , "IIiiS", 0|NOBREAK },
{ SKIN_TOKEN_HAVE_RECORDING, "Rp" , "", 0 }, { SKIN_TOKEN_HAVE_RECORDING, "Rp" , "", SKIN_REFRESH_STATIC },
{ SKIN_TOKEN_IS_RECORDING, "Rr" , "", 0 }, { SKIN_TOKEN_IS_RECORDING, "Rr" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REC_FREQ, "Rf" , "", 0 }, { SKIN_TOKEN_REC_FREQ, "Rf" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REC_ENCODER, "Re" , "", 0 }, { SKIN_TOKEN_REC_ENCODER, "Re" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REC_BITRATE, "Rb" , "", 0 }, { SKIN_TOKEN_REC_BITRATE, "Rb" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REC_MONO, "Rm" , "", 0 }, { SKIN_TOKEN_REC_MONO, "Rm" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REC_SECONDS, "Rs" , "", 0 }, { SKIN_TOKEN_REC_SECONDS, "Rs" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REC_MINUTES, "Rn" , "", 0 }, { SKIN_TOKEN_REC_MINUTES, "Rn" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_REC_HOURS, "Rh" , "", 0 }, { SKIN_TOKEN_REC_HOURS, "Rh" , "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_UNKNOWN, "" , "", 0 } { SKIN_TOKEN_UNKNOWN, "" , "", 0 }
/* Keep this here to mark the end of the table */ /* Keep this here to mark the end of the table */

View file

@ -27,12 +27,31 @@ extern "C"
{ {
#endif #endif
#define MAX_TAG_PARAMS 12
/* Flag to tell the renderer not to insert a line break */ /* Flag to tell the renderer not to insert a line break */
#define NOBREAK 0x1 #define NOBREAK 0x1
/* constants used in line_type and as refresh_mode for wps_refresh */
#define SKIN_REFRESH_SHIFT 16
#define SKIN_REFRESH_STATIC (1u<<SKIN_REFRESH_SHIFT) /* line doesn't change over time */
#define SKIN_REFRESH_DYNAMIC (1u<<(SKIN_REFRESH_SHIFT+1)) /* line may change (e.g. time flag) */
#define SKIN_REFRESH_SCROLL (1u<<(SKIN_REFRESH_SHIFT+2)) /* line scrolls */
#define SKIN_REFRESH_PLAYER_PROGRESS (1u<<(SKIN_REFRESH_SHIFT+3)) /* line contains a progress bar */
#define SKIN_REFRESH_PEAK_METER (1u<<(SKIN_REFRESH_SHIFT+4)) /* line contains a peak meter */
#define SKIN_REFRESH_STATUSBAR (1u<<(SKIN_REFRESH_SHIFT+5)) /* refresh statusbar */
#define SKIN_RTC_REFRESH (1u<<(SKIN_REFRESH_SHIFT+6)) /* refresh rtc, convert at parse time */
#define SKIN_REFRESH_ALL (0xffffu<<SKIN_REFRESH_SHIFT) /* to refresh all line types */
/* to refresh only those lines that change over time */
#define SKIN_REFRESH_NON_STATIC (SKIN_REFRESH_DYNAMIC| \
SKIN_REFRESH_PLAYER_PROGRESS| \
SKIN_REFRESH_PEAK_METER)
enum skin_token_type { enum skin_token_type {
SKIN_TOKEN_NO_TOKEN,
SKIN_TOKEN_UNKNOWN, SKIN_TOKEN_UNKNOWN,
/* Markers */ /* Markers */
@ -91,7 +110,7 @@ enum skin_token_type {
/* The begin/end values allow us to know if a token is an RTC one. /* The begin/end values allow us to know if a token is an RTC one.
New RTC tokens should be added between the markers. */ New RTC tokens should be added between the markers. */
SKIN_TOKENs_RTC_BEGIN, /* just the start marker, not an actual token */ SKIN_TOKENS_RTC_BEGIN, /* just the start marker, not an actual token */
SKIN_TOKEN_RTC_DAY_OF_MONTH, SKIN_TOKEN_RTC_DAY_OF_MONTH,
SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,

View file

@ -1,7 +1,6 @@
../../apps/gui/skin_engine/wps_debug.c ../../apps/gui/skin_engine/wps_debug.c
../../apps/gui/skin_engine/skin_parser.c ../../apps/gui/skin_engine/skin_parser.c
../../apps/gui/skin_engine/skin_backdrops.c ../../apps/gui/skin_engine/skin_backdrops.c
../../apps/gui/skin_engine/skin_buffer.c
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
../../apps/gui/skin_engine/skin_fonts.c ../../apps/gui/skin_engine/skin_fonts.c
#endif #endif

View file

@ -26,6 +26,8 @@
#include "checkwps.h" #include "checkwps.h"
#include "resize.h" #include "resize.h"
#include "wps.h" #include "wps.h"
#include "skin_buffer.h"
#include "skin_debug.h"
#include "skin_engine.h" #include "skin_engine.h"
#include "wps_internals.h" #include "wps_internals.h"
#include "settings.h" #include "settings.h"
@ -238,6 +240,8 @@ int main(int argc, char **argv)
enum screen_type screen = SCREEN_MAIN; enum screen_type screen = SCREEN_MAIN;
struct screen* wps_screen; struct screen* wps_screen;
char* buffer = NULL;
/* No arguments -> print the help text /* No arguments -> print the help text
* Also print the help text upon -h or --help */ * Also print the help text upon -h or --help */
if( (argc < 2) || if( (argc < 2) ||
@ -261,13 +265,19 @@ int main(int argc, char **argv)
wps_verbose_level++; wps_verbose_level++;
} }
} }
buffer = malloc(SKIN_BUFFER_SIZE);
if (!buffer)
{
printf("mallloc fail!\n");
return 1;
}
skin_buffer_init(); skin_buffer_init(buffer, SKIN_BUFFER_SIZE);
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
skin_font_init(); skin_font_init();
#endif #endif
/* Go through every wps that was thrown at us, error out at the first /* Go through every skin that was thrown at us, error out at the first
* flawed wps */ * flawed wps */
while (argv[filearg]) { while (argv[filearg]) {
printf("Checking %s...\n", argv[filearg]); printf("Checking %s...\n", argv[filearg]);
@ -285,6 +295,7 @@ int main(int argc, char **argv)
if (!res) { if (!res) {
printf("WPS parsing failure\n"); printf("WPS parsing failure\n");
skin_error_format_message();
return 3; return 3;
} }

View file

@ -26,6 +26,6 @@ GCCOPTS+=-D__PCTOOL__
.SECONDEXPANSION: # $$(OBJ) is not populated until after this .SECONDEXPANSION: # $$(OBJ) is not populated until after this
$(BUILDDIR)/$(BINARY): $$(OBJ) $(BUILDDIR)/$(BINARY): $$(OBJ) $$(SKINLIB)
@echo LD $(BINARY) @echo LD $(BINARY)
$(SILENT)$(HOSTCC) $(INCLUDE) $(FLAGS) -o $@ $+ $(SILENT)$(HOSTCC) $(INCLUDE) $(FLAGS) -L$(BUILDDIR)/lib -lskin_parser -o $@ $+

View file

@ -70,6 +70,7 @@ else ifneq (,$(findstring bootbox,$(APPSDIR)))
include $(APPSDIR)/bootbox.make include $(APPSDIR)/bootbox.make
else ifneq (,$(findstring checkwps,$(APPSDIR))) else ifneq (,$(findstring checkwps,$(APPSDIR)))
include $(APPSDIR)/checkwps.make include $(APPSDIR)/checkwps.make
include $(ROOTDIR)/lib/skin_parser/skin_parser.make
else ifneq (,$(findstring database,$(APPSDIR))) else ifneq (,$(findstring database,$(APPSDIR)))
include $(APPSDIR)/database.make include $(APPSDIR)/database.make
else else
@ -170,7 +171,8 @@ $(BUILDDIR)/rockbox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) $$(L
$(BUILDDIR)/rombox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) $$(LINKROM) $(BUILDDIR)/rombox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) $$(LINKROM)
$(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \ $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \
$(VOICESPEEXLIB) $(FIRMLIB) -lgcc $(GLOBAL_LDOPTS) \ $(VOICESPEEXLIB) $(FIRMLIB) -lgcc $(GLOBAL_LDOPTS) \
-L$(BUILDDIR)/firmware -T$(LINKROM) -Wl,-Map,$(BUILDDIR)/rombox.map -L$(BUILDDIR)/lib -lskin_parser \
-L$(BUILDDIR)/firmware -T$(LINKROM) -Wl,-Map,$(BUILDDIR)/rombox.map
$(BUILDDIR)/rockbox.bin : $(BUILDDIR)/rockbox.elf $(BUILDDIR)/rockbox.bin : $(BUILDDIR)/rockbox.elf
$(call PRINTS,OC $(@F))$(OC) $(if $(filter yes, $(USE_ELF)), -S -x, -O binary) $< $@ $(call PRINTS,OC $(@F))$(OC) $(if $(filter yes, $(USE_ELF)), -S -x, -O binary) $< $@

View file

@ -43,7 +43,7 @@ static void do_tags_in_hidden_conditional(struct skin_element* branch)
{ {
/* Tags here are ones which need to be "turned off" or cleared /* Tags here are ones which need to be "turned off" or cleared
* if they are in a conditional branch which isnt being used */ * if they are in a conditional branch which isnt being used */
if (branch->type == SUBLINES) if (branch->type == LINE_ALTERNATOR)
{ {
int i; int i;
for (i=0; i<branch->children_count; i++) for (i=0; i<branch->children_count; i++)
@ -71,7 +71,6 @@ static void do_tags_in_hidden_conditional(struct skin_element* branch)
break; break;
case SKIN_TOKEN_IMAGE_DISPLAY: case SKIN_TOKEN_IMAGE_DISPLAY:
case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
printf("disable image\n");
/* clear images */ /* clear images */
break; break;
default: default:
@ -109,7 +108,7 @@ void skin_render_line(struct skin_element* line,
do_tags_in_hidden_conditional(child->children[last_value]); do_tags_in_hidden_conditional(child->children[last_value]);
last_value = value; last_value = value;
if (child->children[value]->type == SUBLINES) if (child->children[value]->type == LINE_ALTERNATOR)
func = skin_render_alternator; func = skin_render_alternator;
else if (child->children[value]->type == LINE) else if (child->children[value]->type == LINE)
func = skin_render_line; func = skin_render_line;