1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr
11 * 2010 Jonathan Gordon
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
28 #include "core_alloc.h"
35 #include "skin_buffer.h"
36 #include "skin_debug.h"
37 #include "skin_parser.h"
38 #include "tag_table.h"
48 #define lang_is_rtl() (false)
60 #include "wps_internals.h"
61 #include "skin_engine.h"
63 #include "settings_list.h"
69 #ifdef HAVE_LCD_BITMAP
78 #include "statusbar-skinned.h"
80 #define WPS_ERROR_INVALID_PARAM -1
82 static char* skin_buffer
= NULL
;
83 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
84 static char *backdrop_filename
;
86 static struct skin_stats
*_stats
= NULL
;
88 static bool isdefault(struct skin_tag_parameter
*param
)
90 return param
->type
== DEFAULT
;
94 get_param_text(struct skin_element
*element
, int param_number
)
96 struct skin_tag_parameter
* params
= SKINOFFSETTOPTR(skin_buffer
, element
->params
);
97 return SKINOFFSETTOPTR(skin_buffer
, params
[param_number
].data
.text
);
100 static inline struct skin_element
*
101 get_param_code(struct skin_element
*element
, int param_number
)
103 struct skin_tag_parameter
* params
= SKINOFFSETTOPTR(skin_buffer
, element
->params
);
104 return SKINOFFSETTOPTR(skin_buffer
, params
[param_number
].data
.code
);
107 static inline struct skin_tag_parameter
*
108 get_param(struct skin_element
*element
, int param_number
)
110 struct skin_tag_parameter
* params
= SKINOFFSETTOPTR(skin_buffer
, element
->params
);
111 return ¶ms
[param_number
];
114 /* which screen are we parsing for? */
115 static enum screen_type curr_screen
;
117 /* the current viewport */
118 static struct skin_element
*curr_viewport_element
;
119 static struct skin_viewport
*curr_vp
;
120 static struct skin_element
*first_viewport
;
122 static struct line
*curr_line
;
124 static int follow_lang_direction
= 0;
126 typedef int (*parse_function
)(struct skin_element
*element
,
127 struct wps_token
*token
,
128 struct wps_data
*wps_data
);
130 #ifdef HAVE_LCD_BITMAP
131 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
132 * chains require the order to be kept.
134 static void add_to_ll_chain(OFFSETTYPE(struct skin_token_list
*) *listoffset
,
135 struct skin_token_list
*item
)
137 struct skin_token_list
*list
= SKINOFFSETTOPTR(skin_buffer
, *listoffset
);
140 *listoffset
= PTRTOSKINOFFSET(skin_buffer
, item
);
144 while (SKINOFFSETTOPTR(skin_buffer
, list
->next
))
145 list
= SKINOFFSETTOPTR(skin_buffer
, list
->next
);
146 list
->next
= PTRTOSKINOFFSET(skin_buffer
, item
);
153 void *skin_find_item(const char *label
, enum skin_find_what what
,
154 struct wps_data
*data
)
156 const char *itemlabel
= NULL
;
157 char *databuf
= get_skin_buffer(data
);
159 struct skin_token_list
*linkedlist
;
160 struct skin_element
*vplist
;
162 bool isvplist
= false;
165 databuf
= skin_buffer
;
170 list
.vplist
= SKINOFFSETTOPTR(databuf
, data
->tree
);
173 #ifdef HAVE_LCD_BITMAP
174 case SKIN_FIND_IMAGE
:
175 list
.linkedlist
= SKINOFFSETTOPTR(databuf
, data
->images
);
178 #ifdef HAVE_TOUCHSCREEN
179 case SKIN_FIND_TOUCHREGION
:
180 list
.linkedlist
= SKINOFFSETTOPTR(databuf
, data
->touchregions
);
183 #ifdef HAVE_SKIN_VARIABLES
185 list
.linkedlist
= SKINOFFSETTOPTR(databuf
, data
->skinvars
);
190 while (list
.linkedlist
)
193 #ifdef HAVE_LCD_BITMAP
194 struct wps_token
*token
= NULL
;
196 token
= SKINOFFSETTOPTR(databuf
, list
.linkedlist
->token
);
202 ret
= SKINOFFSETTOPTR(databuf
, list
.vplist
->data
);
203 if (((struct skin_viewport
*)ret
)->label
== VP_DEFAULT_LABEL
)
204 itemlabel
= VP_DEFAULT_LABEL_STRING
;
206 itemlabel
= SKINOFFSETTOPTR(databuf
, ((struct skin_viewport
*)ret
)->label
);
207 skip
= !(((struct skin_viewport
*)ret
)->is_infovp
==
208 (what
==SKIN_FIND_UIVP
));
210 #ifdef HAVE_LCD_BITMAP
211 case SKIN_FIND_IMAGE
:
212 ret
= SKINOFFSETTOPTR(databuf
, token
->value
.data
);
213 itemlabel
= SKINOFFSETTOPTR(databuf
, ((struct gui_img
*)ret
)->label
);
216 #ifdef HAVE_TOUCHSCREEN
217 case SKIN_FIND_TOUCHREGION
:
218 ret
= SKINOFFSETTOPTR(databuf
, token
->value
.data
);
219 itemlabel
= SKINOFFSETTOPTR(databuf
, ((struct touchregion
*)ret
)->label
);
222 #ifdef HAVE_SKIN_VARIABLES
224 ret
= SKINOFFSETTOPTR(databuf
, token
->value
.data
);
225 itemlabel
= SKINOFFSETTOPTR(databuf
, ((struct skin_var
*)ret
)->label
);
230 if (!skip
&& itemlabel
&& !strcmp(itemlabel
, label
))
236 list
.vplist
= SKINOFFSETTOPTR(databuf
, list
.vplist
->next
);
238 list
.linkedlist
= SKINOFFSETTOPTR(databuf
, list
.linkedlist
->next
);
243 #ifdef HAVE_LCD_BITMAP
245 /* create and init a new wpsll item.
246 * passing NULL to token will alloc a new one.
247 * You should only pass NULL for the token when the token type (table above)
248 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
250 static struct skin_token_list
*new_skin_token_list_item(struct wps_token
*token
,
253 struct skin_token_list
*llitem
= skin_buffer_alloc(sizeof(*llitem
));
255 token
= skin_buffer_alloc(sizeof(*token
));
256 if (!llitem
|| !token
)
258 llitem
->next
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
259 llitem
->token
= PTRTOSKINOFFSET(skin_buffer
, token
);
261 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, token_data
);
265 static int parse_statusbar_tags(struct skin_element
* element
,
266 struct wps_token
*token
,
267 struct wps_data
*wps_data
)
270 if (token
->type
== SKIN_TOKEN_DRAW_INBUILTBAR
)
272 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, (void*)&curr_vp
->vp
);
276 struct skin_viewport
*default_vp
= SKINOFFSETTOPTR(skin_buffer
, first_viewport
->data
);
277 if (first_viewport
->params_count
== 0)
279 wps_data
->wps_sb_tag
= true;
280 wps_data
->show_sb_on_wps
= (token
->type
== SKIN_TOKEN_ENABLE_THEME
);
282 if (wps_data
->show_sb_on_wps
)
284 viewport_set_defaults(&default_vp
->vp
, curr_screen
);
288 viewport_set_fullscreen(&default_vp
->vp
, curr_screen
);
290 #ifdef HAVE_REMOTE_LCD
291 /* This parser requires viewports which will use the settings font to
292 * have font == 1, but the above viewport_set() calls set font to
293 * the current real font id. So force 1 here it will be set correctly
296 default_vp
->vp
.font
= 1;
302 static int get_image_id(int c
)
304 if(c
>= 'a' && c
<= 'z')
306 else if(c
>= 'A' && c
<= 'Z')
312 void get_image_filename(const char *start
, const char* bmpdir
,
313 char *buf
, int buf_size
)
315 snprintf(buf
, buf_size
, "%s/%s", bmpdir
, start
);
318 static int parse_image_display(struct skin_element
*element
,
319 struct wps_token
*token
,
320 struct wps_data
*wps_data
)
322 char *label
= get_param_text(element
, 0);
323 char sublabel
= '\0';
326 struct image_display
*id
= skin_buffer_alloc(sizeof(*id
));
328 if (element
->params_count
== 1 && strlen(label
) <= 2)
330 /* backwards compatability. Allow %xd(Aa) to still work */
335 img
= skin_find_item(label
, SKIN_FIND_IMAGE
, wps_data
);
338 return WPS_ERROR_INVALID_PARAM
;
340 id
->label
= img
->label
;
342 id
->token
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
343 if (img
->using_preloaded_icons
)
345 token
->type
= SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
;
348 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT
)
349 img
->is_9_segment
= true;
351 if (element
->params_count
> 1)
353 if (get_param(element
, 1)->type
== CODE
)
354 id
->token
= get_param_code(element
, 1)->data
;
355 /* specify a number. 1 being the first subimage (i.e top) NOT 0 */
356 else if (get_param(element
, 1)->type
== INTEGER
)
357 id
->subimage
= get_param(element
, 1)->data
.number
- 1;
358 if (element
->params_count
> 2)
359 id
->offset
= get_param(element
, 2)->data
.number
;
363 if ((subimage
= get_image_id(sublabel
)) != -1)
365 if (subimage
>= img
->num_subimages
)
366 return WPS_ERROR_INVALID_PARAM
;
367 id
->subimage
= subimage
;
372 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, id
);
376 static int parse_image_load(struct skin_element
*element
,
377 struct wps_token
*token
,
378 struct wps_data
*wps_data
)
380 const char* filename
;
382 int x
= 0,y
= 0, subimages
= 1;
385 /* format: %x(n,filename.bmp[,x,y])
386 or %xl(n,filename.bmp[,x,y])
387 or %xl(n,filename.bmp[,x,y,num_subimages])
390 id
= get_param_text(element
, 0);
391 filename
= get_param_text(element
, 1);
392 /* x,y,num_subimages handling:
393 * If all 3 are left out use sane defaults.
394 * If there are 2 params it must be x,y
395 * if there is only 1 param it must be the num_subimages
397 if (element
->params_count
== 3)
398 subimages
= get_param(element
, 2)->data
.number
;
399 else if (element
->params_count
> 3)
401 x
= get_param(element
, 2)->data
.number
;
402 y
= get_param(element
, 3)->data
.number
;
403 if (element
->params_count
== 5)
404 subimages
= get_param(element
, 4)->data
.number
;
406 /* check the image number and load state */
407 if(skin_find_item(id
, SKIN_FIND_IMAGE
, wps_data
))
409 /* Invalid image ID */
410 return WPS_ERROR_INVALID_PARAM
;
412 img
= skin_buffer_alloc(sizeof(*img
));
414 return WPS_ERROR_INVALID_PARAM
;
415 /* save a pointer to the filename */
416 img
->bm
.data
= (char*)filename
;
417 img
->label
= PTRTOSKINOFFSET(skin_buffer
, (void*)id
);
420 img
->num_subimages
= subimages
;
422 img
->using_preloaded_icons
= false;
423 img
->buflib_handle
= -1;
424 img
->is_9_segment
= false;
426 /* save current viewport */
427 img
->vp
= PTRTOSKINOFFSET(skin_buffer
, &curr_vp
->vp
);
429 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY
)
430 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, img
);
432 if (!strcmp(img
->bm
.data
, "__list_icons__"))
434 img
->num_subimages
= Icon_Last_Themeable
;
435 img
->using_preloaded_icons
= true;
438 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, img
);
440 return WPS_ERROR_INVALID_PARAM
;
441 add_to_ll_chain(&wps_data
->images
, item
);
446 int id
; /* the id from font_load */
447 char *name
; /* filename without path and extension */
448 int glyphs
; /* how many glyphs to reserve room for */
450 static struct skin_font skinfonts
[MAXUSERFONTS
];
451 static int parse_font_load(struct skin_element
*element
,
452 struct wps_token
*token
,
453 struct wps_data
*wps_data
)
455 (void)wps_data
; (void)token
;
456 int id
= get_param(element
, 0)->data
.number
;
457 char *filename
= get_param_text(element
, 1);
461 if(element
->params_count
> 2)
462 glyphs
= get_param(element
, 2)->data
.number
;
464 glyphs
= global_settings
.glyphs_to_cache
;
467 DEBUGF("font id must be >= 2 (%d)\n", id
);
470 #if defined(DEBUG) || defined(SIMULATOR)
471 if (skinfonts
[id
-2].name
!= NULL
)
473 DEBUGF("font id %d already being used\n", id
);
476 /* make sure the filename contains .fnt,
477 * we dont actually use it, but require it anyway */
478 ptr
= strchr(filename
, '.');
479 if (!ptr
|| strncmp(ptr
, ".fnt", 4))
480 return WPS_ERROR_INVALID_PARAM
;
481 skinfonts
[id
-2].id
= -1;
482 skinfonts
[id
-2].name
= filename
;
483 skinfonts
[id
-2].glyphs
= glyphs
;
489 #ifdef HAVE_LCD_BITMAP
491 static int parse_playlistview(struct skin_element
*element
,
492 struct wps_token
*token
,
493 struct wps_data
*wps_data
)
496 struct playlistviewer
*viewer
= skin_buffer_alloc(sizeof(*viewer
));
498 return WPS_ERROR_INVALID_PARAM
;
499 viewer
->vp
= PTRTOSKINOFFSET(skin_buffer
, &curr_vp
->vp
);
500 viewer
->show_icons
= true;
501 viewer
->start_offset
= get_param(element
, 0)->data
.number
;
502 viewer
->line
= PTRTOSKINOFFSET(skin_buffer
, get_param_code(element
, 1));
504 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, (void*)viewer
);
509 #ifdef HAVE_LCD_COLOR
510 static int parse_viewport_gradient_setup(struct skin_element
*element
,
511 struct wps_token
*token
,
512 struct wps_data
*wps_data
)
515 struct gradient_config
*cfg
;
516 if (element
->params_count
< 2) /* only start and end are required */
518 cfg
= skin_buffer_alloc(sizeof(*cfg
));
521 if (!parse_color(curr_screen
, get_param_text(element
, 0), &cfg
->start
) ||
522 !parse_color(curr_screen
, get_param_text(element
, 1), &cfg
->end
))
524 if (element
->params_count
> 2)
526 if (!parse_color(curr_screen
, get_param_text(element
, 2), &cfg
->text
))
531 cfg
->text
= curr_vp
->vp
.fg_pattern
;
534 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, cfg
);
539 static int parse_listitem(struct skin_element
*element
,
540 struct wps_token
*token
,
541 struct wps_data
*wps_data
)
544 struct listitem
*li
= skin_buffer_alloc(sizeof(*li
));
547 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, li
);
548 if (element
->params_count
== 0)
552 li
->offset
= get_param(element
, 0)->data
.number
;
553 if (element
->params_count
> 1)
554 li
->wrap
= strcasecmp(get_param_text(element
, 1), "nowrap") != 0;
561 static int parse_listitemviewport(struct skin_element
*element
,
562 struct wps_token
*token
,
563 struct wps_data
*wps_data
)
566 struct listitem_viewport_cfg
*cfg
= skin_buffer_alloc(sizeof(*cfg
));
569 cfg
->data
= wps_data
;
571 cfg
->label
= PTRTOSKINOFFSET(skin_buffer
, get_param_text(element
, 0));
574 if (!isdefault(get_param(element
, 1)))
575 cfg
->width
= get_param(element
, 1)->data
.number
;
576 if (!isdefault(get_param(element
, 2)))
577 cfg
->height
= get_param(element
, 2)->data
.number
;
578 if (element
->params_count
> 3 &&
579 !strcmp(get_param_text(element
, 3), "tile"))
581 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, (void*)cfg
);
586 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
587 static int parse_viewporttextstyle(struct skin_element
*element
,
588 struct wps_token
*token
,
589 struct wps_data
*wps_data
)
593 char *mode
= get_param_text(element
, 0);
596 if (!strcmp(mode
, "invert"))
598 style
= STYLE_INVERT
;
600 else if (!strcmp(mode
, "colour") || !strcmp(mode
, "color"))
602 if (element
->params_count
< 2 ||
603 !parse_color(curr_screen
, get_param_text(element
, 1), &colour
))
605 style
= STYLE_COLORED
|(STYLE_COLOR_MASK
&colour
);
607 #ifdef HAVE_LCD_COLOR
608 else if (!strcmp(mode
, "gradient"))
611 if (element
->params_count
< 2)
613 else /* atoi() instead of using a number in the parser is because [si]
614 * will select the number for something which looks like a colour
615 * making the "colour" case (above) harder to parse */
616 num_lines
= atoi(get_param_text(element
, 1));
617 style
= STYLE_GRADIENT
|NUMLN_PACK(num_lines
)|CURLN_PACK(0);
620 else if (!strcmp(mode
, "clear"))
622 style
= STYLE_DEFAULT
;
626 token
->value
.l
= style
;
630 static int parse_drawrectangle( struct skin_element
*element
,
631 struct wps_token
*token
,
632 struct wps_data
*wps_data
)
635 struct draw_rectangle
*rect
= skin_buffer_alloc(sizeof(*rect
));
640 rect
->x
= get_param(element
, 0)->data
.number
;
641 rect
->y
= get_param(element
, 1)->data
.number
;
643 if (isdefault(get_param(element
, 2)))
644 rect
->width
= curr_vp
->vp
.width
- rect
->x
;
646 rect
->width
= get_param(element
, 2)->data
.number
;
648 if (isdefault(get_param(element
, 3)))
649 rect
->height
= curr_vp
->vp
.height
- rect
->y
;
651 rect
->height
= get_param(element
, 3)->data
.number
;
653 rect
->start_colour
= curr_vp
->vp
.fg_pattern
;
654 rect
->end_colour
= curr_vp
->vp
.fg_pattern
;
656 if (element
->params_count
> 4)
658 if (!parse_color(curr_screen
, get_param_text(element
, 4),
659 &rect
->start_colour
))
661 rect
->end_colour
= rect
->start_colour
;
663 if (element
->params_count
> 5)
665 if (!parse_color(curr_screen
, get_param_text(element
, 5),
669 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, rect
);
674 static int parse_viewportcolour(struct skin_element
*element
,
675 struct wps_token
*token
,
676 struct wps_data
*wps_data
)
679 struct skin_tag_parameter
*param
= get_param(element
, 0);
680 struct viewport_colour
*colour
= skin_buffer_alloc(sizeof(*colour
));
683 if (isdefault(param
))
685 colour
->colour
= get_viewport_default_colour(curr_screen
,
686 token
->type
== SKIN_TOKEN_VIEWPORT_FGCOLOUR
);
690 if (!parse_color(curr_screen
, SKINOFFSETTOPTR(skin_buffer
, param
->data
.text
),
694 colour
->vp
= PTRTOSKINOFFSET(skin_buffer
, &curr_vp
->vp
);
695 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, colour
);
696 if (element
->line
== curr_viewport_element
->line
)
698 if (token
->type
== SKIN_TOKEN_VIEWPORT_FGCOLOUR
)
700 curr_vp
->start_fgcolour
= colour
->colour
;
701 curr_vp
->vp
.fg_pattern
= colour
->colour
;
705 curr_vp
->start_bgcolour
= colour
->colour
;
706 curr_vp
->vp
.bg_pattern
= colour
->colour
;
712 static int parse_image_special(struct skin_element
*element
,
713 struct wps_token
*token
,
714 struct wps_data
*wps_data
)
716 (void)wps_data
; /* kill warning */
721 if (token
->type
== SKIN_TOKEN_IMAGE_BACKDROP
)
723 if (isdefault(get_param(element
, 0)))
729 filename
= get_param_text(element
, 0);
730 /* format: %X(filename.bmp) or %X(d) */
731 if (!strcmp(filename
, "d"))
734 backdrop_filename
= filename
;
742 #endif /* HAVE_LCD_BITMAP */
744 static int parse_progressbar_tag(struct skin_element
* element
,
745 struct wps_token
*token
,
746 struct wps_data
*wps_data
);
748 static int parse_setting_and_lang(struct skin_element
*element
,
749 struct wps_token
*token
,
750 struct wps_data
*wps_data
)
752 /* NOTE: both the string validations that happen in here will
753 * automatically PASS on checkwps because its too hard to get
754 * settings_list.c and english.lang built for it.
755 * If that ever changes remove the #ifndef __PCTOOL__'s here
758 char *temp
= get_param_text(element
, 0);
761 if (token
->type
== SKIN_TOKEN_TRANSLATEDSTRING
)
764 i
= lang_english_to_id(temp
);
766 return WPS_ERROR_INVALID_PARAM
;
769 else if (element
->params_count
> 1)
771 if (element
->params_count
> 4)
772 return parse_progressbar_tag(element
, token
, wps_data
);
774 return WPS_ERROR_INVALID_PARAM
;
779 if (find_setting_by_cfgname(temp
, &i
) == NULL
)
780 return WPS_ERROR_INVALID_PARAM
;
783 /* Store the setting number */
788 static int parse_logical_andor(struct skin_element
*element
,
789 struct wps_token
*token
,
790 struct wps_data
*wps_data
)
793 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, element
);
797 static int parse_logical_if(struct skin_element
*element
,
798 struct wps_token
*token
,
799 struct wps_data
*wps_data
)
802 char *op
= get_param_text(element
, 1);
803 struct logical_if
*lif
= skin_buffer_alloc(sizeof(*lif
));
806 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, lif
);
807 lif
->token
= get_param_code(element
, 0)->data
;
809 if (!strncmp(op
, "=", 1))
811 else if (!strncmp(op
, "!=", 2))
812 lif
->op
= IF_NOTEQUALS
;
813 else if (!strncmp(op
, ">=", 2))
814 lif
->op
= IF_GREATERTHAN_EQ
;
815 else if (!strncmp(op
, "<=", 2))
816 lif
->op
= IF_LESSTHAN_EQ
;
817 else if (!strncmp(op
, ">", 2))
818 lif
->op
= IF_GREATERTHAN
;
819 else if (!strncmp(op
, "<", 1))
820 lif
->op
= IF_LESSTHAN
;
822 memcpy(&lif
->operand
, get_param(element
, 2), sizeof(lif
->operand
));
823 if (element
->params_count
> 3)
824 lif
->num_options
= get_param(element
, 3)->data
.number
;
826 lif
->num_options
= TOKEN_VALUE_ONLY
;
831 static int parse_timeout_tag(struct skin_element
*element
,
832 struct wps_token
*token
,
833 struct wps_data
*wps_data
)
837 if (element
->params_count
== 0)
841 case SKIN_TOKEN_SUBLINE_TIMEOUT
:
843 case SKIN_TOKEN_BUTTON_VOLUME
:
844 case SKIN_TOKEN_TRACK_STARTING
:
845 case SKIN_TOKEN_TRACK_ENDING
:
853 val
= get_param(element
, 0)->data
.number
;
854 token
->value
.i
= val
* TIMEOUT_UNIT
;
858 static int parse_substring_tag(struct skin_element
* element
,
859 struct wps_token
*token
,
860 struct wps_data
*wps_data
)
863 struct substring
*ss
= skin_buffer_alloc(sizeof(*ss
));
866 ss
->start
= get_param(element
, 0)->data
.number
;
867 if (get_param(element
, 1)->type
== DEFAULT
)
870 ss
->length
= get_param(element
, 1)->data
.number
;
871 ss
->token
= get_param_code(element
, 2)->data
;
872 if (element
->params_count
> 3)
873 ss
->expect_number
= !strcmp(get_param_text(element
, 3), "number");
875 ss
->expect_number
= false;
876 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, ss
);
880 static int parse_progressbar_tag(struct skin_element
* element
,
881 struct wps_token
*token
,
882 struct wps_data
*wps_data
)
884 #ifdef HAVE_LCD_BITMAP
885 struct progressbar
*pb
;
886 struct viewport
*vp
= &curr_vp
->vp
;
887 struct skin_tag_parameter
*param
= get_param(element
, 0);
889 char *image_filename
= NULL
;
890 #ifdef HAVE_TOUCHSCREEN
891 bool suppress_touchregion
= false;
894 if (element
->params_count
== 0 &&
895 element
->tag
->type
!= SKIN_TOKEN_PROGRESSBAR
)
896 return 0; /* nothing to do */
897 pb
= skin_buffer_alloc(sizeof(*pb
));
899 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, pb
);
902 return WPS_ERROR_INVALID_PARAM
;
903 pb
->vp
= PTRTOSKINOFFSET(skin_buffer
, vp
);
904 pb
->follow_lang_direction
= follow_lang_direction
> 0;
907 pb
->image
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
908 pb
->slider
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
909 pb
->backdrop
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
911 pb
->invert_fill_direction
= false;
912 pb
->horizontal
= true;
914 if (element
->params_count
== 0)
917 pb
->width
= vp
->width
;
918 pb
->height
= SYSFONT_HEIGHT
-2;
919 pb
->y
= -1; /* Will be computed during the rendering */
920 pb
->type
= element
->tag
->type
;
924 /* (x, y, width, height, ...) */
925 if (!isdefault(param
))
926 pb
->x
= param
->data
.number
;
931 if (!isdefault(param
))
932 pb
->y
= param
->data
.number
;
934 pb
->y
= -1; /* computed at rendering */
937 if (!isdefault(param
))
938 pb
->width
= param
->data
.number
;
940 pb
->width
= vp
->width
- pb
->x
;
943 if (!isdefault(param
))
945 /* A zero height makes no sense - reject it */
946 if (param
->data
.number
== 0)
947 return WPS_ERROR_INVALID_PARAM
;
949 pb
->height
= param
->data
.number
;
953 if (vp
->font
> FONT_UI
)
954 pb
->height
= -1; /* calculate at display time */
958 pb
->height
= font_get(vp
->font
)->height
;
964 /* optional params, first is the image filename if it isnt recognised as a keyword */
967 if (isdefault(get_param(element
, curr_param
)))
973 pb
->horizontal
= pb
->width
> pb
->height
;
974 while (curr_param
< element
->params_count
)
978 text
= SKINOFFSETTOPTR(skin_buffer
, param
->data
.text
);
979 if (!strcmp(text
, "invert"))
980 pb
->invert_fill_direction
= true;
981 else if (!strcmp(text
, "nofill"))
983 else if (!strcmp(text
, "nobar"))
985 else if (!strcmp(text
, "slider"))
987 if (curr_param
+1 < element
->params_count
)
991 text
= SKINOFFSETTOPTR(skin_buffer
, param
->data
.text
);
992 pb
->slider
= PTRTOSKINOFFSET(skin_buffer
,
993 skin_find_item(text
, SKIN_FIND_IMAGE
, wps_data
));
995 else /* option needs the next param */
998 else if (!strcmp(text
, "image"))
1000 if (curr_param
+1 < element
->params_count
)
1004 image_filename
= SKINOFFSETTOPTR(skin_buffer
, param
->data
.text
);
1006 else /* option needs the next param */
1009 else if (!strcmp(text
, "backdrop"))
1011 if (curr_param
+1 < element
->params_count
)
1015 text
= SKINOFFSETTOPTR(skin_buffer
, param
->data
.text
);
1016 pb
->backdrop
= PTRTOSKINOFFSET(skin_buffer
,
1017 skin_find_item(text
, SKIN_FIND_IMAGE
, wps_data
));
1020 else /* option needs the next param */
1023 else if (!strcmp(text
, "vertical"))
1025 pb
->horizontal
= false;
1026 if (isdefault(get_param(element
, 3)))
1027 pb
->height
= vp
->height
- pb
->y
;
1029 else if (!strcmp(text
, "horizontal"))
1030 pb
->horizontal
= true;
1031 #ifdef HAVE_TOUCHSCREEN
1032 else if (!strcmp(text
, "notouch"))
1033 suppress_touchregion
= true;
1035 else if (token
->type
== SKIN_TOKEN_SETTING
&& !strcmp(text
, "setting"))
1037 if (curr_param
+1 < element
->params_count
)
1041 text
= SKINOFFSETTOPTR(skin_buffer
, param
->data
.text
);
1043 if (find_setting_by_cfgname(text
, &pb
->setting_id
) == NULL
)
1044 return WPS_ERROR_INVALID_PARAM
;
1048 else if (curr_param
== 4)
1049 image_filename
= text
;
1056 pb
->image
= PTRTOSKINOFFSET(skin_buffer
,
1057 skin_find_item(image_filename
, SKIN_FIND_IMAGE
, wps_data
));
1058 if (!SKINOFFSETTOPTR(skin_buffer
, pb
->image
)) /* load later */
1060 struct gui_img
*img
= skin_buffer_alloc(sizeof(*img
));
1062 return WPS_ERROR_INVALID_PARAM
;
1063 /* save a pointer to the filename */
1064 img
->bm
.data
= (char*)image_filename
;
1065 img
->label
= PTRTOSKINOFFSET(skin_buffer
, image_filename
);
1068 img
->num_subimages
= 1;
1070 img
->using_preloaded_icons
= false;
1071 img
->buflib_handle
= -1;
1072 img
->vp
= PTRTOSKINOFFSET(skin_buffer
, &curr_vp
->vp
);
1073 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, img
);
1075 return WPS_ERROR_INVALID_PARAM
;
1076 add_to_ll_chain(&wps_data
->images
, item
);
1077 pb
->image
= PTRTOSKINOFFSET(skin_buffer
, img
);
1081 if (token
->type
== SKIN_TOKEN_VOLUME
)
1082 token
->type
= SKIN_TOKEN_VOLUMEBAR
;
1083 else if (token
->type
== SKIN_TOKEN_BATTERY_PERCENT
)
1084 token
->type
= SKIN_TOKEN_BATTERY_PERCENTBAR
;
1085 else if (token
->type
== SKIN_TOKEN_TUNER_RSSI
)
1086 token
->type
= SKIN_TOKEN_TUNER_RSSI_BAR
;
1087 else if (token
->type
== SKIN_TOKEN_PEAKMETER_LEFT
)
1088 token
->type
= SKIN_TOKEN_PEAKMETER_LEFTBAR
;
1089 else if (token
->type
== SKIN_TOKEN_PEAKMETER_RIGHT
)
1090 token
->type
= SKIN_TOKEN_PEAKMETER_RIGHTBAR
;
1091 else if (token
->type
== SKIN_TOKEN_LIST_NEEDS_SCROLLBAR
)
1092 token
->type
= SKIN_TOKEN_LIST_SCROLLBAR
;
1093 else if (token
->type
== SKIN_TOKEN_SETTING
)
1094 token
->type
= SKIN_TOKEN_SETTINGBAR
;
1095 pb
->type
= token
->type
;
1097 #ifdef HAVE_TOUCHSCREEN
1098 if (!suppress_touchregion
&&
1099 (token
->type
== SKIN_TOKEN_VOLUMEBAR
||
1100 token
->type
== SKIN_TOKEN_PROGRESSBAR
||
1101 token
->type
== SKIN_TOKEN_SETTINGBAR
))
1103 struct touchregion
*region
= skin_buffer_alloc(sizeof(*region
));
1104 struct skin_token_list
*item
;
1110 if (token
->type
== SKIN_TOKEN_VOLUMEBAR
)
1111 region
->action
= ACTION_TOUCH_VOLUME
;
1112 else if (token
->type
== SKIN_TOKEN_SETTINGBAR
)
1113 region
->action
= ACTION_TOUCH_SETTING
;
1115 region
->action
= ACTION_TOUCH_SCROLLBAR
;
1117 /* try to add some extra space on either end to make pressing the
1118 * full bar easier. ~5% on either side
1120 wpad
= pb
->width
* 5 / 100;
1123 hpad
= pb
->height
* 5 / 100;
1127 region
->x
= pb
->x
- wpad
;
1130 region
->width
= pb
->width
+ 2 * wpad
;
1131 if (region
->x
+ region
->width
> curr_vp
->vp
.x
+ curr_vp
->vp
.width
)
1132 region
->width
= curr_vp
->vp
.x
+ curr_vp
->vp
.width
- region
->x
;
1134 region
->y
= pb
->y
- hpad
;
1137 region
->height
= pb
->height
+ 2 * hpad
;
1138 if (region
->y
+ region
->height
> curr_vp
->vp
.y
+ curr_vp
->vp
.height
)
1139 region
->height
= curr_vp
->vp
.y
+ curr_vp
->vp
.height
- region
->y
;
1141 region
->wvp
= PTRTOSKINOFFSET(skin_buffer
, curr_vp
);
1142 region
->reverse_bar
= false;
1143 region
->allow_while_locked
= false;
1144 region
->press_length
= PRESS
;
1145 region
->last_press
= 0xffff;
1146 region
->armed
= false;
1147 region
->bar
= PTRTOSKINOFFSET(skin_buffer
, pb
);
1149 item
= new_skin_token_list_item(NULL
, region
);
1151 return WPS_ERROR_INVALID_PARAM
;
1152 add_to_ll_chain(&wps_data
->touchregions
, item
);
1160 if (token
->type
== SKIN_TOKEN_PROGRESSBAR
||
1161 token
->type
== SKIN_TOKEN_PLAYER_PROGRESSBAR
)
1163 wps_data
->full_line_progressbar
=
1164 token
->type
== SKIN_TOKEN_PLAYER_PROGRESSBAR
;
1171 #ifdef HAVE_ALBUMART
1172 static int parse_albumart_load(struct skin_element
* element
,
1173 struct wps_token
*token
,
1174 struct wps_data
*wps_data
)
1176 struct dim dimensions
;
1178 bool swap_for_rtl
= lang_is_rtl() && follow_lang_direction
;
1179 struct skin_albumart
*aa
= skin_buffer_alloc(sizeof(*aa
));
1180 (void)token
; /* silence warning */
1184 /* reset albumart info in wps */
1187 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1188 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1190 aa
->x
= get_param(element
, 0)->data
.number
;
1191 aa
->y
= get_param(element
, 1)->data
.number
;
1192 aa
->width
= get_param(element
, 2)->data
.number
;
1193 aa
->height
= get_param(element
, 3)->data
.number
;
1195 aa
->vp
= PTRTOSKINOFFSET(skin_buffer
, &curr_vp
->vp
);
1196 aa
->draw_handle
= -1;
1198 /* if we got here, we parsed everything ok .. ! */
1206 aa
->x
= (curr_vp
->vp
.width
- aa
->width
- aa
->x
);
1208 aa
->state
= WPS_ALBUMART_LOAD
;
1209 wps_data
->albumart
= PTRTOSKINOFFSET(skin_buffer
, aa
);
1211 dimensions
.width
= aa
->width
;
1212 dimensions
.height
= aa
->height
;
1214 albumart_slot
= playback_claim_aa_slot(&dimensions
);
1216 if (0 <= albumart_slot
)
1217 wps_data
->playback_aa_slot
= albumart_slot
;
1219 if (element
->params_count
> 4 && !isdefault(get_param(element
, 4)))
1221 switch (*get_param_text(element
, 4))
1226 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1228 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1232 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
;
1237 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1239 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1243 if (element
->params_count
> 5 && !isdefault(get_param(element
, 5)))
1245 switch (*get_param_text(element
, 5))
1249 aa
->yalign
= WPS_ALBUMART_ALIGN_TOP
;
1253 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
;
1257 aa
->yalign
= WPS_ALBUMART_ALIGN_BOTTOM
;
1264 #endif /* HAVE_ALBUMART */
1265 #ifdef HAVE_SKIN_VARIABLES
1266 static struct skin_var
* find_or_add_var(const char* label
,
1267 struct wps_data
*data
)
1269 struct skin_var
* ret
= skin_find_item(label
, SKIN_VARIABLE
, data
);
1273 ret
= skin_buffer_alloc(sizeof(*ret
));
1276 ret
->label
= PTRTOSKINOFFSET(skin_buffer
, label
);
1278 ret
->last_changed
= 0xffff;
1279 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, ret
);
1282 add_to_ll_chain(&data
->skinvars
, item
);
1285 static int parse_skinvar( struct skin_element
*element
,
1286 struct wps_token
*token
,
1287 struct wps_data
*wps_data
)
1289 const char* label
= get_param_text(element
, 0);
1290 struct skin_var
* var
= find_or_add_var(label
, wps_data
);
1292 return WPS_ERROR_INVALID_PARAM
;
1293 switch (token
->type
)
1295 case SKIN_TOKEN_VAR_GETVAL
:
1296 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, var
);
1298 case SKIN_TOKEN_VAR_SET
:
1300 struct skin_var_changer
*data
= skin_buffer_alloc(sizeof(*data
));
1302 return WPS_ERROR_INVALID_PARAM
;
1303 data
->var
= PTRTOSKINOFFSET(skin_buffer
, var
);
1304 if (!isdefault(get_param(element
, 2)))
1305 data
->newval
= get_param(element
, 2)->data
.number
;
1306 else if (strcmp(get_param_text(element
, 1), "touch"))
1307 return WPS_ERROR_INVALID_PARAM
;
1309 if (!strcmp(get_param_text(element
, 1), "set"))
1310 data
->direct
= true;
1311 else if (!strcmp(get_param_text(element
, 1), "inc"))
1313 data
->direct
= false;
1315 else if (!strcmp(get_param_text(element
, 1), "dec"))
1317 data
->direct
= false;
1320 else if (!strcmp(get_param_text(element
, 1), "touch"))
1322 data
->direct
= false;
1325 if (element
->params_count
> 3)
1326 data
->max
= get_param(element
, 3)->data
.number
;
1327 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, data
);
1330 case SKIN_TOKEN_VAR_TIMEOUT
:
1332 struct skin_var_lastchange
*data
= skin_buffer_alloc(sizeof(*data
));
1334 return WPS_ERROR_INVALID_PARAM
;
1335 data
->var
= PTRTOSKINOFFSET(skin_buffer
, var
);
1337 if (element
->params_count
> 1)
1338 data
->timeout
= get_param(element
, 1)->data
.number
;
1339 data
->timeout
*= TIMEOUT_UNIT
;
1340 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, data
);
1346 #endif /* HAVE_SKIN_VARIABLES */
1347 #ifdef HAVE_TOUCHSCREEN
1348 static int parse_lasttouch(struct skin_element
*element
,
1349 struct wps_token
*token
,
1350 struct wps_data
*wps_data
)
1352 struct touchregion_lastpress
*data
= skin_buffer_alloc(sizeof(*data
));
1354 struct touchregion
*region
= NULL
;
1356 return WPS_ERROR_INVALID_PARAM
;
1360 for (i
=0; i
<element
->params_count
; i
++)
1362 if (get_param(element
, i
)->type
== STRING
)
1363 region
= skin_find_item(get_param_text(element
, i
),
1364 SKIN_FIND_TOUCHREGION
, wps_data
);
1365 else if (get_param(element
, i
)->type
== INTEGER
||
1366 get_param(element
, i
)->type
== DECIMAL
)
1367 data
->timeout
= get_param(element
, i
)->data
.number
;
1370 data
->region
= PTRTOSKINOFFSET(skin_buffer
, region
);
1371 data
->timeout
*= TIMEOUT_UNIT
;
1372 token
->value
.data
= PTRTOSKINOFFSET(skin_buffer
, data
);
1376 struct touchaction
{const char* s
; int action
;};
1377 static const struct touchaction touchactions
[] = {
1378 /* generic actions, convert to screen actions on use */
1379 {"none", ACTION_TOUCHSCREEN_IGNORE
},{"lock", ACTION_TOUCH_SOFTLOCK
},
1380 {"prev", ACTION_STD_PREV
}, {"next", ACTION_STD_NEXT
},
1381 {"hotkey", ACTION_STD_HOTKEY
}, {"select", ACTION_STD_OK
},
1382 {"menu", ACTION_STD_MENU
}, {"cancel", ACTION_STD_CANCEL
},
1383 {"contextmenu", ACTION_STD_CONTEXT
},{"quickscreen", ACTION_STD_QUICKSCREEN
},
1385 /* list/tree actions */
1386 { "resumeplayback", ACTION_TREE_WPS
}, /* returns to previous music, WPS/FM */
1387 /* not really WPS specific, but no equivilant ACTION_STD_* */
1388 {"voldown", ACTION_WPS_VOLDOWN
}, {"volup", ACTION_WPS_VOLUP
},
1389 {"mute", ACTION_TOUCH_MUTE
},
1391 /* generic settings changers */
1392 {"setting_inc", ACTION_SETTINGS_INC
}, {"setting_dec", ACTION_SETTINGS_DEC
},
1393 {"setting_set", ACTION_SETTINGS_SET
},
1395 /* WPS specific actions */
1396 {"rwd", ACTION_WPS_SEEKBACK
}, {"ffwd", ACTION_WPS_SEEKFWD
},
1397 {"wps_prev", ACTION_WPS_SKIPPREV
}, {"wps_next", ACTION_WPS_SKIPNEXT
},
1398 {"browse", ACTION_WPS_BROWSE
},
1399 {"play", ACTION_WPS_PLAY
}, {"stop", ACTION_WPS_STOP
},
1400 {"shuffle", ACTION_TOUCH_SHUFFLE
}, {"repmode", ACTION_TOUCH_REPMODE
},
1401 {"pitch", ACTION_WPS_PITCHSCREEN
}, {"trackinfo", ACTION_WPS_ID3SCREEN
},
1402 {"playlist", ACTION_WPS_VIEW_PLAYLIST
},
1403 {"listbookmarks", ACTION_WPS_LIST_BOOKMARKS
},
1404 {"createbookmark", ACTION_WPS_CREATE_BOOKMARK
},
1407 /* FM screen actions */
1408 /* Also allow browse, play, stop from WPS codes */
1409 {"mode", ACTION_FM_MODE
}, {"record", ACTION_FM_RECORD
},
1410 {"presets", ACTION_FM_PRESET
},
1414 static int touchregion_setup_setting(struct skin_element
*element
, int param_no
,
1415 struct touchregion
*region
)
1419 char *name
= get_param_text(element
, p
++);
1422 region
->setting_data
.setting
= find_setting_by_cfgname(name
, &j
);
1423 if (region
->setting_data
.setting
== NULL
)
1424 return WPS_ERROR_INVALID_PARAM
;
1426 if (region
->action
== ACTION_SETTINGS_SET
)
1430 struct touchsetting
*setting
=
1431 ®ion
->setting_data
;
1432 if (element
->params_count
< p
+1)
1435 text
= get_param_text(element
, p
++);
1436 switch (settings
[j
].flags
&F_T_MASK
)
1439 setting
->value
.text
= PTRTOSKINOFFSET(skin_buffer
, text
);
1443 if (settings
[j
].cfg_vals
== NULL
)
1445 setting
->value
.number
= atoi(text
);
1447 else if (cfg_string_to_int(j
, &temp
, text
))
1449 if (settings
[j
].flags
&F_TABLE_SETTING
)
1450 setting
->value
.number
=
1451 settings
[j
].table_setting
->values
[temp
];
1453 setting
->value
.number
= temp
;
1459 if (cfg_string_to_int(j
, &temp
, text
))
1461 setting
->value
.number
= temp
;
1471 #endif /* __PCTOOL__ */
1475 static int parse_touchregion(struct skin_element
*element
,
1476 struct wps_token
*token
,
1477 struct wps_data
*wps_data
)
1482 struct touchregion
*region
= NULL
;
1484 const char pb_string
[] = "progressbar";
1485 const char vol_string
[] = "volume";
1487 /* format: %T([label,], x,y,width,height,action[, ...])
1488 * if action starts with & the area must be held to happen
1492 region
= skin_buffer_alloc(sizeof(*region
));
1494 return WPS_ERROR_INVALID_PARAM
;
1496 /* should probably do some bounds checking here with the viewport... but later */
1497 region
->action
= ACTION_NONE
;
1499 if (get_param(element
, 0)->type
== STRING
)
1501 region
->label
= PTRTOSKINOFFSET(skin_buffer
, get_param_text(element
, 0));
1503 /* "[SI]III[SI]|SS" is the param list. There MUST be 4 numbers
1504 * followed by at least one string. Verify that here */
1505 if (element
->params_count
< 6 ||
1506 get_param(element
, 4)->type
!= INTEGER
)
1507 return WPS_ERROR_INVALID_PARAM
;
1511 region
->label
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
1515 region
->x
= get_param(element
, p
++)->data
.number
;
1516 region
->y
= get_param(element
, p
++)->data
.number
;
1517 region
->width
= get_param(element
, p
++)->data
.number
;
1518 region
->height
= get_param(element
, p
++)->data
.number
;
1519 region
->wvp
= PTRTOSKINOFFSET(skin_buffer
, curr_vp
);
1520 region
->armed
= false;
1521 region
->reverse_bar
= false;
1523 region
->last_press
= 0xffff;
1524 region
->press_length
= PRESS
;
1525 region
->allow_while_locked
= false;
1526 region
->bar
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
1527 action
= get_param_text(element
, p
++);
1529 /* figure out the action */
1530 if(!strcmp(pb_string
, action
))
1531 region
->action
= ACTION_TOUCH_SCROLLBAR
;
1532 else if(!strcmp(vol_string
, action
))
1533 region
->action
= ACTION_TOUCH_VOLUME
;
1536 imax
= ARRAYLEN(touchactions
);
1537 for (i
= 0; i
< imax
; i
++)
1539 /* try to match with one of our touchregion screens */
1540 if (!strcmp(touchactions
[i
].s
, action
))
1542 region
->action
= touchactions
[i
].action
;
1543 if (region
->action
== ACTION_SETTINGS_INC
||
1544 region
->action
== ACTION_SETTINGS_DEC
||
1545 region
->action
== ACTION_SETTINGS_SET
)
1548 if (element
->params_count
< p
+1)
1549 return WPS_ERROR_INVALID_PARAM
;
1550 val
= touchregion_setup_setting(element
, p
, region
);
1552 return WPS_ERROR_INVALID_PARAM
;
1558 if (region
->action
== ACTION_NONE
)
1559 return WPS_ERROR_INVALID_PARAM
;
1561 while (p
< element
->params_count
)
1563 char* param
= get_param_text(element
, p
++);
1564 if (!strcmp(param
, "allow_while_locked"))
1565 region
->allow_while_locked
= true;
1566 else if (!strcmp(param
, "reverse_bar"))
1567 region
->reverse_bar
= true;
1568 else if (!strcmp(param
, "repeat_press"))
1569 region
->press_length
= REPEAT
;
1570 else if (!strcmp(param
, "long_press"))
1571 region
->press_length
= LONG_PRESS
;
1573 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, region
);
1575 return WPS_ERROR_INVALID_PARAM
;
1576 add_to_ll_chain(&wps_data
->touchregions
, item
);
1578 if (region
->action
== ACTION_TOUCH_MUTE
)
1580 region
->value
= global_settings
.volume
;
1588 static bool check_feature_tag(const int type
)
1592 case SKIN_TOKEN_RTC_PRESENT
:
1598 case SKIN_TOKEN_HAVE_RECORDING
:
1599 #ifdef HAVE_RECORDING
1604 case SKIN_TOKEN_HAVE_TUNER
:
1606 if (radio_hardware_present())
1610 case SKIN_TOKEN_HAVE_TOUCH
:
1611 #ifdef HAVE_TOUCHSCREEN
1618 case SKIN_TOKEN_HAVE_RDS
:
1623 #endif /* HAVE_RDS_CAP */
1624 #endif /* CONFIG_TUNER */
1625 default: /* not a tag we care about, just don't skip */
1630 /* This is used to free any buflib allocations before the rest of
1631 * wps_data is reset.
1632 * The call to this in settings_apply_skins() is the last chance to do
1633 * any core_free()'s before wps_data is trashed and those handles lost
1635 void skin_data_free_buflib_allocs(struct wps_data
*wps_data
)
1637 if (wps_data
->wps_loaded
)
1638 skin_buffer
= get_skin_buffer(wps_data
);
1639 #ifdef HAVE_LCD_BITMAP
1641 struct skin_token_list
*list
= SKINOFFSETTOPTR(skin_buffer
, wps_data
->images
);
1642 int *font_ids
= SKINOFFSETTOPTR(skin_buffer
, wps_data
->font_ids
);
1645 struct wps_token
*token
= SKINOFFSETTOPTR(skin_buffer
, list
->token
);
1646 struct gui_img
*img
= (struct gui_img
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
1647 if (img
->buflib_handle
> 0)
1648 core_free(img
->buflib_handle
);
1649 list
= SKINOFFSETTOPTR(skin_buffer
, list
->next
);
1651 wps_data
->images
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
1652 if (font_ids
!= NULL
)
1654 while (wps_data
->font_count
> 0)
1655 font_unload(font_ids
[--wps_data
->font_count
]);
1657 wps_data
->font_ids
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
1658 if (wps_data
->buflib_handle
> 0)
1659 core_free(wps_data
->buflib_handle
);
1660 wps_data
->buflib_handle
= -1;
1666 * initial setup of wps_data; does reset everything
1667 * except fields which need to survive, i.e.
1668 * Also called if the load fails
1670 static void skin_data_reset(struct wps_data
*wps_data
)
1672 skin_data_free_buflib_allocs(wps_data
);
1673 #ifdef HAVE_LCD_BITMAP
1674 wps_data
->images
= INVALID_OFFSET
;
1676 wps_data
->tree
= INVALID_OFFSET
;
1677 #ifdef HAVE_BACKDROP_IMAGE
1678 if (wps_data
->backdrop_id
>= 0)
1679 skin_backdrop_unload(wps_data
->backdrop_id
);
1680 backdrop_filename
= NULL
;
1682 #ifdef HAVE_TOUCHSCREEN
1683 wps_data
->touchregions
= INVALID_OFFSET
;
1685 #ifdef HAVE_SKIN_VARIABLES
1686 wps_data
->skinvars
= INVALID_OFFSET
;
1688 #ifdef HAVE_ALBUMART
1689 wps_data
->albumart
= INVALID_OFFSET
;
1690 if (wps_data
->playback_aa_slot
>= 0)
1692 playback_release_aa_slot(wps_data
->playback_aa_slot
);
1693 wps_data
->playback_aa_slot
= -1;
1697 #ifdef HAVE_LCD_BITMAP
1698 wps_data
->peak_meter_enabled
= false;
1699 wps_data
->wps_sb_tag
= false;
1700 wps_data
->show_sb_on_wps
= false;
1701 #else /* HAVE_LCD_CHARCELLS */
1704 for (i
= 0; i
< 8; i
++)
1706 wps_data
->wps_progress_pat
[i
] = 0;
1708 wps_data
->full_line_progressbar
= false;
1710 wps_data
->wps_loaded
= false;
1713 #ifdef HAVE_LCD_BITMAP
1715 static int currently_loading_handle
= -1;
1716 static int buflib_move_callback(int handle
, void* current
, void* new)
1720 if (handle
== currently_loading_handle
)
1721 return BUFLIB_CB_CANNOT_MOVE
;
1722 return BUFLIB_CB_OK
;
1724 static struct buflib_callbacks buflib_ops
= {buflib_move_callback
, NULL
, NULL
};
1725 static void lock_handle(int handle
)
1727 currently_loading_handle
= handle
;
1729 static void unlock_handle(void)
1731 currently_loading_handle
= -1;
1735 static int load_skin_bmp(struct wps_data
*wps_data
, struct bitmap
*bitmap
, char* bmpdir
)
1737 (void)wps_data
; /* only needed for remote targets */
1738 char img_path
[MAX_PATH
];
1741 get_image_filename(bitmap
->data
, bmpdir
,
1742 img_path
, sizeof(img_path
));
1744 /* load the image */
1746 #ifdef HAVE_REMOTE_LCD
1747 if (curr_screen
== SCREEN_REMOTE
)
1748 format
= FORMAT_ANY
|FORMAT_REMOTE
;
1751 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
1753 fd
= open(img_path
, O_RDONLY
);
1756 DEBUGF("Couldn't open %s\n", img_path
);
1760 size_t buf_size
= read_bmp_fd(fd
, bitmap
, 0,
1761 format
|FORMAT_RETURN_SIZE
, NULL
);
1762 handle
= core_alloc_ex(bitmap
->data
, buf_size
, &buflib_ops
);
1765 DEBUGF("Not enough skin buffer: need %zd more.\n",
1766 buf_size
- skin_buffer_freespace());
1770 _stats
->buflib_handles
++;
1771 _stats
->images_size
+= buf_size
;
1772 lseek(fd
, 0, SEEK_SET
);
1773 lock_handle(handle
);
1774 bitmap
->data
= core_get_data(handle
);
1775 int ret
= read_bmp_fd(fd
, bitmap
, buf_size
, format
, NULL
);
1776 bitmap
->data
= NULL
; /* do this to force a crash later if the
1777 caller doesnt call core_get_data() */
1782 /* free unused alpha channel, if any */
1783 core_shrink(handle
, core_get_data(handle
), ret
);
1788 /* Abort if we can't load an image */
1789 DEBUGF("Couldn't load '%s'\n", img_path
);
1793 #else /* !__PCTOOL__ */
1799 static bool load_skin_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
1801 struct skin_token_list
*list
;
1802 bool retval
= true; /* return false if a single image failed to load */
1804 /* regular images */
1805 list
= SKINOFFSETTOPTR(skin_buffer
, wps_data
->images
);
1808 struct wps_token
*token
= SKINOFFSETTOPTR(skin_buffer
, list
->token
);
1809 struct gui_img
*img
= (struct gui_img
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
1812 if (img
->using_preloaded_icons
)
1815 token
->type
= SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
;
1819 img
->buflib_handle
= load_skin_bmp(wps_data
, &img
->bm
, bmpdir
);
1820 img
->loaded
= img
->buflib_handle
>= 0;
1822 img
->subimage_height
= img
->bm
.height
/ img
->num_subimages
;
1827 list
= SKINOFFSETTOPTR(skin_buffer
, list
->next
);
1830 #ifdef HAVE_BACKDROP_IMAGE
1831 wps_data
->backdrop_id
= skin_backdrop_assign(backdrop_filename
, bmpdir
, curr_screen
);
1832 #endif /* has backdrop support */
1836 static bool skin_load_fonts(struct wps_data
*data
)
1838 /* don't spit out after the first failue to aid debugging */
1839 int id_array
[MAXUSERFONTS
];
1841 bool success
= true;
1842 struct skin_element
*vp_list
;
1844 /* walk though each viewport and assign its font */
1845 for(vp_list
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
1846 vp_list
; vp_list
= SKINOFFSETTOPTR(skin_buffer
, vp_list
->next
))
1848 /* first, find the viewports that have a non-sys/ui-font font */
1849 struct skin_viewport
*skin_vp
=
1850 SKINOFFSETTOPTR(skin_buffer
, vp_list
->data
);
1851 struct viewport
*vp
= &skin_vp
->vp
;
1853 font_id
= skin_vp
->parsed_fontid
;
1855 { /* the usual case -> built-in fonts */
1856 vp
->font
= screens
[curr_screen
].getuifont();
1859 else if (font_id
<= 0)
1861 vp
->font
= FONT_SYSFIXED
;
1865 /* now find the corresponding skin_font */
1866 struct skin_font
*font
= &skinfonts
[font_id
-2];
1871 DEBUGF("font %d not specified\n", font_id
);
1877 /* load the font - will handle loading the same font again if
1878 * multiple viewports use the same */
1881 char path
[MAX_PATH
];
1882 snprintf(path
, sizeof path
, FONT_DIR
"/%s", font
->name
);
1884 font
->id
= font_load_ex(path
, 0, skinfonts
[font_id
-2].glyphs
);
1887 font
->id
= font_load(path
);
1889 //printf("[%d] %s -> %d\n",font_id, font->name, font->id);
1890 id_array
[font_count
++] = font
->id
;
1895 DEBUGF("Unable to load font %d: '%s'\n", font_id
, font
->name
);
1896 font
->name
= NULL
; /* to stop trying to load it again if we fail */
1901 /* finally, assign the font_id to the viewport */
1902 vp
->font
= font
->id
;
1906 int *font_ids
= skin_buffer_alloc(font_count
* sizeof(int));
1907 if (!success
|| font_ids
== NULL
)
1909 while (font_count
> 0)
1911 if(id_array
[--font_count
] != -1)
1912 font_unload(id_array
[font_count
]);
1914 data
->font_ids
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
1917 memcpy(font_ids
, id_array
, sizeof(int)*font_count
);
1918 data
->font_count
= font_count
;
1919 data
->font_ids
= PTRTOSKINOFFSET(skin_buffer
, font_ids
);
1923 data
->font_count
= 0;
1924 data
->font_ids
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
1929 #endif /* HAVE_LCD_BITMAP */
1930 static int convert_viewport(struct wps_data
*data
, struct skin_element
* element
)
1932 struct skin_viewport
*skin_vp
= skin_buffer_alloc(sizeof(*skin_vp
));
1933 struct screen
*display
= &screens
[curr_screen
];
1936 return CALLBACK_ERROR
;
1938 skin_vp
->hidden_flags
= 0;
1939 skin_vp
->label
= PTRTOSKINOFFSET(skin_buffer
, NULL
);
1940 skin_vp
->is_infovp
= false;
1941 skin_vp
->parsed_fontid
= 1;
1942 element
->data
= PTRTOSKINOFFSET(skin_buffer
, skin_vp
);
1944 curr_viewport_element
= element
;
1945 if (!first_viewport
)
1946 first_viewport
= element
;
1948 viewport_set_defaults(&skin_vp
->vp
, curr_screen
);
1950 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1951 skin_vp
->output_to_backdrop_buffer
= false;
1952 skin_vp
->start_fgcolour
= skin_vp
->vp
.fg_pattern
;
1953 skin_vp
->start_bgcolour
= skin_vp
->vp
.bg_pattern
;
1955 #ifdef HAVE_LCD_COLOR
1956 skin_vp
->start_gradient
.start
= skin_vp
->vp
.lss_pattern
;
1957 skin_vp
->start_gradient
.end
= skin_vp
->vp
.lse_pattern
;
1958 skin_vp
->start_gradient
.text
= skin_vp
->vp
.lst_pattern
;
1962 struct skin_tag_parameter
*param
= get_param(element
, 0);
1963 if (element
->params_count
== 0) /* default viewport */
1965 if (data
->tree
< 0) /* first viewport in the skin */
1966 data
->tree
= PTRTOSKINOFFSET(skin_buffer
, element
);
1967 skin_vp
->label
= VP_DEFAULT_LABEL
;
1971 if (element
->params_count
== 6)
1973 if (element
->tag
->type
== SKIN_TOKEN_UIVIEWPORT_LOAD
)
1975 skin_vp
->is_infovp
= true;
1976 if (isdefault(param
))
1978 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
1979 skin_vp
->label
= VP_DEFAULT_LABEL
;
1983 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
1984 skin_vp
->label
= param
->data
.text
;
1989 skin_vp
->hidden_flags
= VP_DRAW_HIDEABLE
|VP_DRAW_HIDDEN
;
1990 skin_vp
->label
= param
->data
.text
;
1995 if (!isdefault(param
))
1997 skin_vp
->vp
.x
= param
->data
.number
;
1998 if (param
->data
.number
< 0)
1999 skin_vp
->vp
.x
+= display
->lcdwidth
;
2000 else if (param
->type
== PERCENT
)
2001 skin_vp
->vp
.x
= param
->data
.number
* display
->lcdwidth
/ 1000;
2005 if (!isdefault(param
))
2007 skin_vp
->vp
.y
= param
->data
.number
;
2008 if (param
->data
.number
< 0)
2009 skin_vp
->vp
.y
+= display
->lcdheight
;
2010 else if (param
->type
== PERCENT
)
2011 skin_vp
->vp
.y
= param
->data
.number
* display
->lcdheight
/ 1000;
2015 if (!isdefault(param
))
2017 skin_vp
->vp
.width
= param
->data
.number
;
2018 if (param
->data
.number
< 0)
2019 skin_vp
->vp
.width
= (skin_vp
->vp
.width
+ display
->lcdwidth
) - skin_vp
->vp
.x
;
2020 else if (param
->type
== PERCENT
)
2021 skin_vp
->vp
.width
= param
->data
.number
* display
->lcdwidth
/ 1000;
2025 skin_vp
->vp
.width
= display
->lcdwidth
- skin_vp
->vp
.x
;
2029 if (!isdefault(param
))
2031 skin_vp
->vp
.height
= param
->data
.number
;
2032 if (param
->data
.number
< 0)
2033 skin_vp
->vp
.height
= (skin_vp
->vp
.height
+ display
->lcdheight
) - skin_vp
->vp
.y
;
2034 else if (param
->type
== PERCENT
)
2035 skin_vp
->vp
.height
= param
->data
.number
* display
->lcdheight
/ 1000;
2039 skin_vp
->vp
.height
= display
->lcdheight
- skin_vp
->vp
.y
;
2042 #ifdef HAVE_LCD_BITMAP
2044 if (!isdefault(param
))
2045 skin_vp
->parsed_fontid
= param
->data
.number
;
2047 if ((unsigned) skin_vp
->vp
.x
>= (unsigned) display
->lcdwidth
||
2048 skin_vp
->vp
.width
+ skin_vp
->vp
.x
> display
->lcdwidth
||
2049 (unsigned) skin_vp
->vp
.y
>= (unsigned) display
->lcdheight
||
2050 skin_vp
->vp
.height
+ skin_vp
->vp
.y
> display
->lcdheight
)
2051 return CALLBACK_ERROR
;
2053 /* Fix x position for RTL languages */
2054 if (follow_lang_direction
&& lang_is_rtl())
2055 skin_vp
->vp
.x
= display
->lcdwidth
- skin_vp
->vp
.x
- skin_vp
->vp
.width
;
2060 static int skin_element_callback(struct skin_element
* element
, void* data
)
2062 struct wps_data
*wps_data
= (struct wps_data
*)data
;
2063 struct wps_token
*token
;
2064 parse_function function
= NULL
;
2066 switch (element
->type
)
2068 /* IMPORTANT: element params are shared, so copy them if needed
2069 * or use then NOW, dont presume they have a long lifespan
2073 token
= skin_buffer_alloc(sizeof(*token
));
2074 memset(token
, 0, sizeof(*token
));
2075 token
->type
= element
->tag
->type
;
2076 token
->value
.data
= INVALID_OFFSET
;
2078 if (element
->tag
->flags
&SKIN_RTC_REFRESH
)
2081 curr_line
->update_mode
|= SKIN_REFRESH_DYNAMIC
;
2083 curr_line
->update_mode
|= SKIN_REFRESH_STATIC
;
2087 curr_line
->update_mode
|= element
->tag
->flags
&SKIN_REFRESH_ALL
;
2089 element
->data
= PTRTOSKINOFFSET(skin_buffer
, token
);
2091 /* Some tags need special handling for the tag, so add them here */
2092 switch (token
->type
)
2094 case SKIN_TOKEN_ALIGN_LANGDIRECTION
:
2095 follow_lang_direction
= 2;
2097 case SKIN_TOKEN_LOGICAL_IF
:
2098 function
= parse_logical_if
;
2100 case SKIN_TOKEN_LOGICAL_AND
:
2101 case SKIN_TOKEN_LOGICAL_OR
:
2102 function
= parse_logical_andor
;
2104 case SKIN_TOKEN_SUBSTRING
:
2105 function
= parse_substring_tag
;
2107 case SKIN_TOKEN_PROGRESSBAR
:
2108 case SKIN_TOKEN_VOLUME
:
2109 case SKIN_TOKEN_BATTERY_PERCENT
:
2110 case SKIN_TOKEN_PLAYER_PROGRESSBAR
:
2111 case SKIN_TOKEN_PEAKMETER_LEFT
:
2112 case SKIN_TOKEN_PEAKMETER_RIGHT
:
2113 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR
:
2114 #ifdef HAVE_RADIO_RSSI
2115 case SKIN_TOKEN_TUNER_RSSI
:
2117 function
= parse_progressbar_tag
;
2119 case SKIN_TOKEN_SUBLINE_TIMEOUT
:
2120 case SKIN_TOKEN_BUTTON_VOLUME
:
2121 case SKIN_TOKEN_TRACK_STARTING
:
2122 case SKIN_TOKEN_TRACK_ENDING
:
2123 function
= parse_timeout_tag
;
2125 #ifdef HAVE_LCD_BITMAP
2126 case SKIN_TOKEN_LIST_ITEM_TEXT
:
2127 case SKIN_TOKEN_LIST_ITEM_ICON
:
2128 function
= parse_listitem
;
2130 case SKIN_TOKEN_DISABLE_THEME
:
2131 case SKIN_TOKEN_ENABLE_THEME
:
2132 case SKIN_TOKEN_DRAW_INBUILTBAR
:
2133 function
= parse_statusbar_tags
;
2135 case SKIN_TOKEN_LIST_TITLE_TEXT
:
2137 sb_skin_has_title(curr_screen
);
2141 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2142 case SKIN_TOKEN_DRAWRECTANGLE
:
2143 function
= parse_drawrectangle
;
2146 case SKIN_TOKEN_FILE_DIRECTORY
:
2147 token
->value
.i
= get_param(element
, 0)->data
.number
;
2149 #ifdef HAVE_BACKDROP_IMAGE
2150 case SKIN_TOKEN_VIEWPORT_FGCOLOUR
:
2151 case SKIN_TOKEN_VIEWPORT_BGCOLOUR
:
2152 function
= parse_viewportcolour
;
2154 case SKIN_TOKEN_IMAGE_BACKDROP
:
2155 function
= parse_image_special
;
2157 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE
:
2158 function
= parse_viewporttextstyle
;
2160 case SKIN_TOKEN_VIEWPORT_DRAWONBG
:
2161 curr_vp
->output_to_backdrop_buffer
= true;
2162 backdrop_filename
= BACKDROP_BUFFERNAME
;
2163 wps_data
->use_extra_framebuffer
= true;
2166 #ifdef HAVE_LCD_COLOR
2167 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP
:
2168 function
= parse_viewport_gradient_setup
;
2171 case SKIN_TOKEN_TRANSLATEDSTRING
:
2172 case SKIN_TOKEN_SETTING
:
2173 function
= parse_setting_and_lang
;
2175 #ifdef HAVE_LCD_BITMAP
2176 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
2177 function
= parse_playlistview
;
2179 case SKIN_TOKEN_LOAD_FONT
:
2180 function
= parse_font_load
;
2182 case SKIN_TOKEN_VIEWPORT_ENABLE
:
2183 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
2184 token
->value
.data
= get_param(element
, 0)->data
.text
;
2186 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
2187 case SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT
:
2188 function
= parse_image_display
;
2190 case SKIN_TOKEN_IMAGE_PRELOAD
:
2191 case SKIN_TOKEN_IMAGE_DISPLAY
:
2192 function
= parse_image_load
;
2194 case SKIN_TOKEN_LIST_ITEM_CFG
:
2195 function
= parse_listitemviewport
;
2198 #ifdef HAVE_TOUCHSCREEN
2199 case SKIN_TOKEN_TOUCHREGION
:
2200 function
= parse_touchregion
;
2202 case SKIN_TOKEN_LASTTOUCH
:
2203 function
= parse_lasttouch
;
2206 #ifdef HAVE_ALBUMART
2207 case SKIN_TOKEN_ALBUMART_DISPLAY
:
2208 if (SKINOFFSETTOPTR(skin_buffer
, wps_data
->albumart
))
2210 struct skin_albumart
*aa
= SKINOFFSETTOPTR(skin_buffer
, wps_data
->albumart
);
2211 aa
->vp
= PTRTOSKINOFFSET(skin_buffer
, &curr_vp
->vp
);
2214 case SKIN_TOKEN_ALBUMART_LOAD
:
2215 function
= parse_albumart_load
;
2218 #ifdef HAVE_SKIN_VARIABLES
2219 case SKIN_TOKEN_VAR_SET
:
2220 case SKIN_TOKEN_VAR_GETVAL
:
2221 case SKIN_TOKEN_VAR_TIMEOUT
:
2222 function
= parse_skinvar
;
2230 if (function(element
, token
, wps_data
) < 0)
2231 return CALLBACK_ERROR
;
2233 /* tags that start with 'F', 'I' or 'D' are for the next file */
2234 if ( *(element
->tag
->name
) == 'I' || *(element
->tag
->name
) == 'F' ||
2235 *(element
->tag
->name
) == 'D')
2237 if (follow_lang_direction
> 0 )
2238 follow_lang_direction
--;
2242 return convert_viewport(wps_data
, element
);
2245 curr_line
= skin_buffer_alloc(sizeof(*curr_line
));
2246 curr_line
->update_mode
= SKIN_REFRESH_STATIC
;
2247 element
->data
= PTRTOSKINOFFSET(skin_buffer
, curr_line
);
2250 case LINE_ALTERNATOR
:
2252 struct line_alternator
*alternator
= skin_buffer_alloc(sizeof(*alternator
));
2253 alternator
->current_line
= 0;
2255 alternator
->next_change_tick
= current_tick
;
2257 element
->data
= PTRTOSKINOFFSET(skin_buffer
, alternator
);
2262 struct conditional
*conditional
= skin_buffer_alloc(sizeof(*conditional
));
2263 conditional
->last_value
= -1;
2264 conditional
->token
= element
->data
;
2265 element
->data
= PTRTOSKINOFFSET(skin_buffer
, conditional
);
2266 if (!check_feature_tag(element
->tag
->type
))
2268 return FEATURE_NOT_AVAILABLE
;
2273 curr_line
->update_mode
|= SKIN_REFRESH_STATIC
;
2281 /* to setup up the wps-data from a format-buffer (isfile = false)
2282 from a (wps-)file (isfile = true)*/
2283 bool skin_data_load(enum screen_type screen
, struct wps_data
*wps_data
,
2284 const char *buf
, bool isfile
, struct skin_stats
*stats
)
2286 char *wps_buffer
= NULL
;
2287 if (!wps_data
|| !buf
)
2289 #ifdef HAVE_ALBUMART
2291 struct mp3entry
*curtrack
;
2293 struct skin_albumart old_aa
= {.state
= WPS_ALBUMART_NONE
};
2294 struct skin_albumart
*aa
= SKINOFFSETTOPTR(skin_buffer
, wps_data
->albumart
);
2297 old_aa
.state
= aa
->state
;
2298 old_aa
.height
= aa
->height
;
2299 old_aa
.width
= aa
->width
;
2302 #ifdef HAVE_LCD_BITMAP
2304 for (i
=0;i
<MAXUSERFONTS
;i
++)
2306 skinfonts
[i
].id
= -1;
2307 skinfonts
[i
].name
= NULL
;
2310 #ifdef DEBUG_SKIN_ENGINE
2311 if (isfile
&& debug_wps
)
2313 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf
);
2318 skin_clear_stats(stats
);
2319 /* get buffer space from the plugin buffer */
2320 size_t buffersize
= 0;
2321 wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
2326 skin_data_reset(wps_data
);
2327 wps_data
->wps_loaded
= false;
2328 curr_screen
= screen
;
2331 curr_viewport_element
= NULL
;
2332 first_viewport
= NULL
;
2336 int fd
= open_utf8(buf
, O_RDONLY
);
2340 /* copy the file's content to the buffer for parsing,
2341 ensuring that every line ends with a newline char. */
2342 unsigned int start
= 0;
2343 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
2345 start
+= strlen(wps_buffer
+ start
);
2346 if (start
< buffersize
- 1)
2348 wps_buffer
[start
++] = '\n';
2349 wps_buffer
[start
] = 0;
2356 skin_buffer
= &wps_buffer
[start
];
2357 buffersize
-= start
;
2361 skin_buffer
= wps_buffer
;
2362 wps_buffer
= (char*)buf
;
2364 skin_buffer
= (void *)(((unsigned long)skin_buffer
+ 3) & ~3);
2366 #ifdef HAVE_BACKDROP_IMAGE
2367 backdrop_filename
= "-";
2368 wps_data
->backdrop_id
= -1;
2370 /* parse the skin source */
2371 skin_buffer_init(skin_buffer
, buffersize
);
2372 struct skin_element
*tree
= skin_parse(wps_buffer
, skin_element_callback
, wps_data
);
2373 wps_data
->tree
= PTRTOSKINOFFSET(skin_buffer
, tree
);
2374 if (!SKINOFFSETTOPTR(skin_buffer
, wps_data
->tree
)) {
2375 #ifdef DEBUG_SKIN_ENGINE
2376 if (isfile
&& debug_wps
)
2377 skin_error_format_message();
2379 skin_data_reset(wps_data
);
2383 #ifdef HAVE_LCD_BITMAP
2384 char bmpdir
[MAX_PATH
];
2387 /* get the bitmap dir */
2388 char *dot
= strrchr(buf
, '.');
2389 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
2393 snprintf(bmpdir
, MAX_PATH
, "%s", BACKDROP_DIR
);
2395 /* load the bitmaps that were found by the parsing */
2396 if (!load_skin_bitmaps(wps_data
, bmpdir
) ||
2397 !skin_load_fonts(wps_data
))
2399 skin_data_reset(wps_data
);
2403 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2404 status
= audio_status();
2405 if (status
& AUDIO_STATUS_PLAY
)
2407 struct skin_albumart
*aa
= SKINOFFSETTOPTR(skin_buffer
, wps_data
->albumart
);
2408 if (aa
&& ((aa
->state
&& !old_aa
.state
) ||
2410 (((old_aa
.height
!= aa
->height
) ||
2411 (old_aa
.width
!= aa
->width
))))))
2413 curtrack
= audio_current_track();
2414 offset
= curtrack
->offset
;
2416 if (!(status
& AUDIO_STATUS_PAUSE
))
2422 wps_data
->buflib_handle
= core_alloc(isfile
? buf
: "failsafe skin",
2423 skin_buffer_usage());
2424 if (wps_data
->buflib_handle
> 0)
2426 wps_data
->wps_loaded
= true;
2427 memcpy(core_get_data(wps_data
->buflib_handle
), skin_buffer
,
2428 skin_buffer_usage());
2429 stats
->buflib_handles
++;
2430 stats
->tree_size
= skin_buffer_usage();
2433 wps_data
->wps_loaded
= wps_data
->tree
>= 0;
2436 #ifdef HAVE_TOUCHSCREEN
2437 /* Check if there are any touch regions from the skin and not just
2438 * auto-created ones for bars */
2439 struct skin_token_list
*regions
= SKINOFFSETTOPTR(skin_buffer
,
2440 wps_data
->touchregions
);
2441 bool user_touch_region_found
= false;
2444 struct wps_token
*token
= SKINOFFSETTOPTR(skin_buffer
, regions
->token
);
2445 struct touchregion
*r
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
2447 if (r
->action
!= ACTION_TOUCH_SCROLLBAR
&&
2448 r
->action
!= ACTION_TOUCH_VOLUME
)
2450 user_touch_region_found
= true;
2453 regions
= SKINOFFSETTOPTR(skin_buffer
, regions
->next
);
2455 regions
= SKINOFFSETTOPTR(skin_buffer
, wps_data
->touchregions
);
2456 if (regions
&& !user_touch_region_found
)
2457 wps_data
->touchregions
= PTRTOSKINOFFSET(skin_buffer
, NULL
);