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 ****************************************************************************/
32 #include "skin_buffer.h"
33 #include "skin_parser.h"
34 #include "tag_table.h"
44 #define lang_is_rtl() (false)
56 #include "wps_internals.h"
57 #include "skin_engine.h"
59 #include "settings_list.h"
64 #include "skin_fonts.h"
66 #ifdef HAVE_LCD_BITMAP
75 #include "statusbar-skinned.h"
77 #define WPS_ERROR_INVALID_PARAM -1
80 static bool isdefault(struct skin_tag_parameter
*param
)
82 return param
->type
== DEFAULT
;
86 /* which screen are we parsing for? */
87 static enum screen_type curr_screen
;
89 /* the current viewport */
90 static struct skin_element
*curr_viewport_element
;
91 static struct skin_viewport
*curr_vp
;
93 static struct line
*curr_line
;
95 static int follow_lang_direction
= 0;
97 typedef int (*parse_function
)(struct skin_element
*element
,
98 struct wps_token
*token
,
99 struct wps_data
*wps_data
);
101 #ifdef HAVE_LCD_BITMAP
102 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
103 * chains require the order to be kept.
105 static void add_to_ll_chain(struct skin_token_list
**list
, struct skin_token_list
*item
)
111 struct skin_token_list
*t
= *list
;
121 void *skin_find_item(const char *label
, enum skin_find_what what
,
122 struct wps_data
*data
)
124 const char *itemlabel
= NULL
;
126 struct skin_token_list
*linkedlist
;
127 struct skin_element
*vplist
;
129 bool isvplist
= false;
135 list
.vplist
= data
->tree
;
138 #ifdef HAVE_LCD_BITMAP
139 case SKIN_FIND_IMAGE
:
140 list
.linkedlist
= data
->images
;
143 #ifdef HAVE_TOUCHSCREEN
144 case SKIN_FIND_TOUCHREGION
:
145 list
.linkedlist
= data
->touchregions
;
148 #ifdef HAVE_SKIN_VARIABLES
150 list
.linkedlist
= data
->skinvars
;
155 while (list
.linkedlist
)
162 ret
= list
.vplist
->data
;
163 itemlabel
= ((struct skin_viewport
*)ret
)->label
;
164 skip
= !(((struct skin_viewport
*)ret
)->is_infovp
==
165 (what
==SKIN_FIND_UIVP
));
167 #ifdef HAVE_LCD_BITMAP
168 case SKIN_FIND_IMAGE
:
169 ret
= list
.linkedlist
->token
->value
.data
;
170 itemlabel
= ((struct gui_img
*)ret
)->label
;
173 #ifdef HAVE_TOUCHSCREEN
174 case SKIN_FIND_TOUCHREGION
:
175 ret
= list
.linkedlist
->token
->value
.data
;
176 itemlabel
= ((struct touchregion
*)ret
)->label
;
179 #ifdef HAVE_SKIN_VARIABLES
181 ret
= list
.linkedlist
->token
->value
.data
;
182 itemlabel
= ((struct skin_var
*)ret
)->label
;
187 if (!skip
&& itemlabel
&& !strcmp(itemlabel
, label
))
191 list
.vplist
= list
.vplist
->next
;
193 list
.linkedlist
= list
.linkedlist
->next
;
198 #ifdef HAVE_LCD_BITMAP
200 /* create and init a new wpsll item.
201 * passing NULL to token will alloc a new one.
202 * You should only pass NULL for the token when the token type (table above)
203 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
205 static struct skin_token_list
*new_skin_token_list_item(struct wps_token
*token
,
208 struct skin_token_list
*llitem
=
209 (struct skin_token_list
*)skin_buffer_alloc(sizeof(struct skin_token_list
));
211 token
= (struct wps_token
*)skin_buffer_alloc(sizeof(struct wps_token
));
212 if (!llitem
|| !token
)
215 llitem
->token
= token
;
217 llitem
->token
->value
.data
= token_data
;
221 static int parse_statusbar_tags(struct skin_element
* element
,
222 struct wps_token
*token
,
223 struct wps_data
*wps_data
)
226 if (token
->type
== SKIN_TOKEN_DRAW_INBUILTBAR
)
228 token
->value
.data
= (void*)&curr_vp
->vp
;
232 struct skin_element
*def_vp
= wps_data
->tree
;
233 struct skin_viewport
*default_vp
= def_vp
->data
;
234 if (def_vp
->params_count
== 0)
236 wps_data
->wps_sb_tag
= true;
237 wps_data
->show_sb_on_wps
= (token
->type
== SKIN_TOKEN_ENABLE_THEME
);
239 if (wps_data
->show_sb_on_wps
)
241 viewport_set_defaults(&default_vp
->vp
, curr_screen
);
245 viewport_set_fullscreen(&default_vp
->vp
, curr_screen
);
247 #ifdef HAVE_REMOTE_LCD
248 /* viewport_set_defaults() sets the font to FONT_UI+curr_screen.
249 * This parser requires font 1 to always be the UI font,
250 * so force it back to FONT_UI and handle the screen number at the end */
251 default_vp
->vp
.font
= FONT_UI
;
257 static int get_image_id(int c
)
259 if(c
>= 'a' && c
<= 'z')
261 else if(c
>= 'A' && c
<= 'Z')
267 char *get_image_filename(const char *start
, const char* bmpdir
,
268 char *buf
, int buf_size
)
270 snprintf(buf
, buf_size
, "%s/%s", bmpdir
, start
);
275 static int parse_image_display(struct skin_element
*element
,
276 struct wps_token
*token
,
277 struct wps_data
*wps_data
)
279 char *label
= element
->params
[0].data
.text
;
280 char sublabel
= '\0';
283 struct image_display
*id
= skin_buffer_alloc(sizeof(struct image_display
));
285 if (element
->params_count
== 1 && strlen(label
) <= 2)
287 /* backwards compatability. Allow %xd(Aa) to still work */
292 img
= skin_find_item(label
, SKIN_FIND_IMAGE
, wps_data
);
295 return WPS_ERROR_INVALID_PARAM
;
300 if (img
->using_preloaded_icons
)
302 token
->type
= SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
;
305 if (element
->params_count
> 1)
307 if (element
->params
[1].type
== CODE
)
308 id
->token
= element
->params
[1].data
.code
->data
;
309 /* specify a number. 1 being the first subimage (i.e top) NOT 0 */
310 else if (element
->params
[1].type
== INTEGER
)
311 id
->subimage
= element
->params
[1].data
.number
- 1;
312 if (element
->params_count
> 2)
313 id
->offset
= element
->params
[2].data
.number
;
317 if ((subimage
= get_image_id(sublabel
)) != -1)
319 if (subimage
>= img
->num_subimages
)
320 return WPS_ERROR_INVALID_PARAM
;
321 id
->subimage
= subimage
;
326 token
->value
.data
= id
;
330 static int parse_image_load(struct skin_element
*element
,
331 struct wps_token
*token
,
332 struct wps_data
*wps_data
)
334 const char* filename
;
339 /* format: %x(n,filename.bmp,x,y)
340 or %xl(n,filename.bmp,x,y)
341 or %xl(n,filename.bmp,x,y,num_subimages)
344 id
= element
->params
[0].data
.text
;
345 filename
= element
->params
[1].data
.text
;
346 x
= element
->params
[2].data
.number
;
347 y
= element
->params
[3].data
.number
;
349 /* check the image number and load state */
350 if(skin_find_item(id
, SKIN_FIND_IMAGE
, wps_data
))
352 /* Invalid image ID */
353 return WPS_ERROR_INVALID_PARAM
;
355 img
= (struct gui_img
*)skin_buffer_alloc(sizeof(struct gui_img
));
357 return WPS_ERROR_INVALID_PARAM
;
358 /* save a pointer to the filename */
359 img
->bm
.data
= (char*)filename
;
363 img
->num_subimages
= 1;
364 img
->always_display
= false;
366 img
->using_preloaded_icons
= false;
368 /* save current viewport */
369 img
->vp
= &curr_vp
->vp
;
371 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY
)
373 img
->always_display
= true;
375 else if (element
->params_count
== 5)
377 img
->num_subimages
= element
->params
[4].data
.number
;
378 if (img
->num_subimages
<= 0)
379 return WPS_ERROR_INVALID_PARAM
;
382 if (!strcmp(img
->bm
.data
, "__list_icons__"))
384 img
->num_subimages
= Icon_Last_Themeable
;
385 img
->using_preloaded_icons
= true;
388 struct skin_token_list
*item
=
389 (struct skin_token_list
*)new_skin_token_list_item(NULL
, img
);
391 return WPS_ERROR_INVALID_PARAM
;
392 add_to_ll_chain(&wps_data
->images
, item
);
397 int id
; /* the id from font_load */
398 char *name
; /* filename without path and extension */
399 int glyphs
; /* how many glyphs to reserve room for */
401 static struct skin_font skinfonts
[MAXUSERFONTS
];
402 static int parse_font_load(struct skin_element
*element
,
403 struct wps_token
*token
,
404 struct wps_data
*wps_data
)
406 (void)wps_data
; (void)token
;
407 int id
= element
->params
[0].data
.number
;
408 char *filename
= element
->params
[1].data
.text
;
412 if(element
->params_count
> 2)
413 glyphs
= element
->params
[2].data
.number
;
415 glyphs
= GLYPHS_TO_CACHE
;
416 #if defined(DEBUG) || defined(SIMULATOR)
417 if (skinfonts
[id
-FONT_FIRSTUSERFONT
].name
!= NULL
)
419 DEBUGF("font id %d already being used\n", id
);
422 /* make sure the filename contains .fnt,
423 * we dont actually use it, but require it anyway */
424 ptr
= strchr(filename
, '.');
425 if (!ptr
|| strncmp(ptr
, ".fnt", 4))
426 return WPS_ERROR_INVALID_PARAM
;
427 skinfonts
[id
-FONT_FIRSTUSERFONT
].id
= -1;
428 skinfonts
[id
-FONT_FIRSTUSERFONT
].name
= filename
;
429 skinfonts
[id
-FONT_FIRSTUSERFONT
].glyphs
= glyphs
;
435 #ifdef HAVE_LCD_BITMAP
437 static int parse_playlistview(struct skin_element
*element
,
438 struct wps_token
*token
,
439 struct wps_data
*wps_data
)
442 struct playlistviewer
*viewer
=
443 (struct playlistviewer
*)skin_buffer_alloc(sizeof(struct playlistviewer
));
445 return WPS_ERROR_INVALID_PARAM
;
446 viewer
->vp
= &curr_vp
->vp
;
447 viewer
->show_icons
= true;
448 viewer
->start_offset
= element
->params
[0].data
.number
;
449 viewer
->line
= element
->params
[1].data
.code
;
451 token
->value
.data
= (void*)viewer
;
456 #ifdef HAVE_LCD_COLOR
457 static int parse_viewport_gradient_setup(struct skin_element
*element
,
458 struct wps_token
*token
,
459 struct wps_data
*wps_data
)
462 struct gradient_config
*cfg
;
463 if (element
->params_count
< 2) /* only start and end are required */
465 cfg
= (struct gradient_config
*)skin_buffer_alloc(sizeof(struct gradient_config
));
468 if (!parse_color(curr_screen
, element
->params
[0].data
.text
, &cfg
->start
) ||
469 !parse_color(curr_screen
, element
->params
[1].data
.text
, &cfg
->end
))
471 if (element
->params_count
> 2)
473 if (!parse_color(curr_screen
, element
->params
[2].data
.text
, &cfg
->text
))
478 cfg
->text
= curr_vp
->vp
.fg_pattern
;
481 token
->value
.data
= cfg
;
485 static int parse_viewporttextstyle(struct skin_element
*element
,
486 struct wps_token
*token
,
487 struct wps_data
*wps_data
)
491 char *mode
= element
->params
[0].data
.text
;
494 if (!strcmp(mode
, "invert"))
496 style
= STYLE_INVERT
;
498 else if (!strcmp(mode
, "colour") || !strcmp(mode
, "color"))
500 if (element
->params_count
< 2 ||
501 !parse_color(curr_screen
, element
->params
[1].data
.text
, &colour
))
503 style
= STYLE_COLORED
|(STYLE_COLOR_MASK
&colour
);
505 #ifdef HAVE_LCD_COLOR
506 else if (!strcmp(mode
, "gradient"))
509 if (element
->params_count
< 2)
511 else /* atoi() instead of using a number in the parser is because [si]
512 * will select the number for something which looks like a colour
513 * making the "colour" case (above) harder to parse */
514 num_lines
= atoi(element
->params
[1].data
.text
);
515 style
= STYLE_GRADIENT
|NUMLN_PACK(num_lines
)|CURLN_PACK(0);
518 else if (!strcmp(mode
, "clear"))
520 style
= STYLE_DEFAULT
;
524 token
->value
.l
= style
;
528 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
530 static int parse_viewportcolour(struct skin_element
*element
,
531 struct wps_token
*token
,
532 struct wps_data
*wps_data
)
535 struct skin_tag_parameter
*param
= element
->params
;
536 struct viewport_colour
*colour
=
537 (struct viewport_colour
*)skin_buffer_alloc(sizeof(struct viewport_colour
));
540 if (isdefault(param
))
542 colour
->colour
= get_viewport_default_colour(curr_screen
,
543 token
->type
== SKIN_TOKEN_VIEWPORT_FGCOLOUR
);
547 if (!parse_color(curr_screen
, param
->data
.text
, &colour
->colour
))
550 colour
->vp
= &curr_vp
->vp
;
551 token
->value
.data
= colour
;
552 if (element
->line
== curr_viewport_element
->line
)
554 if (token
->type
== SKIN_TOKEN_VIEWPORT_FGCOLOUR
)
556 curr_vp
->start_fgcolour
= colour
->colour
;
557 curr_vp
->vp
.fg_pattern
= colour
->colour
;
561 curr_vp
->start_bgcolour
= colour
->colour
;
562 curr_vp
->vp
.bg_pattern
= colour
->colour
;
568 static int parse_image_special(struct skin_element
*element
,
569 struct wps_token
*token
,
570 struct wps_data
*wps_data
)
572 (void)wps_data
; /* kill warning */
577 if (token
->type
== SKIN_TOKEN_IMAGE_BACKDROP
)
579 if (isdefault(&element
->params
[0]))
585 filename
= element
->params
[0].data
.text
;
586 /* format: %X(filename.bmp) or %X(d) */
587 if (!strcmp(filename
, "d"))
590 wps_data
->backdrop
= filename
;
598 #endif /* HAVE_LCD_BITMAP */
600 static int parse_setting_and_lang(struct skin_element
*element
,
601 struct wps_token
*token
,
602 struct wps_data
*wps_data
)
604 /* NOTE: both the string validations that happen in here will
605 * automatically PASS on checkwps because its too hard to get
606 * settings_list.c and english.lang built for it.
607 * If that ever changes remove the #ifndef __PCTOOL__'s here
610 char *temp
= element
->params
[0].data
.text
;
613 if (token
->type
== SKIN_TOKEN_TRANSLATEDSTRING
)
616 i
= lang_english_to_id(temp
);
618 return WPS_ERROR_INVALID_PARAM
;
623 /* Find the setting */
624 for (i
=0; i
<nb_settings
; i
++)
625 if (settings
[i
].cfg_name
&&
626 !strcmp(settings
[i
].cfg_name
, temp
))
629 if (i
== nb_settings
)
630 return WPS_ERROR_INVALID_PARAM
;
633 /* Store the setting number */
637 static int parse_logical_if(struct skin_element
*element
,
638 struct wps_token
*token
,
639 struct wps_data
*wps_data
)
642 char *op
= element
->params
[1].data
.text
;
643 struct logical_if
*lif
= skin_buffer_alloc(sizeof(struct logical_if
));
646 token
->value
.data
= lif
;
647 lif
->token
= element
->params
[0].data
.code
->data
;
649 if (!strncmp(op
, "=", 1))
651 else if (!strncmp(op
, "!=", 2))
652 lif
->op
= IF_NOTEQUALS
;
653 else if (!strncmp(op
, ">=", 2))
654 lif
->op
= IF_GREATERTHAN_EQ
;
655 else if (!strncmp(op
, "<=", 2))
656 lif
->op
= IF_LESSTHAN_EQ
;
657 else if (!strncmp(op
, ">", 2))
658 lif
->op
= IF_GREATERTHAN
;
659 else if (!strncmp(op
, "<", 1))
660 lif
->op
= IF_LESSTHAN
;
662 memcpy(&lif
->operand
, &element
->params
[2], sizeof(lif
->operand
));
663 if (element
->params_count
> 3)
664 lif
->num_options
= element
->params
[3].data
.number
;
666 lif
->num_options
= TOKEN_VALUE_ONLY
;
671 static int parse_timeout_tag(struct skin_element
*element
,
672 struct wps_token
*token
,
673 struct wps_data
*wps_data
)
677 if (element
->params_count
== 0)
681 case SKIN_TOKEN_SUBLINE_TIMEOUT
:
683 case SKIN_TOKEN_BUTTON_VOLUME
:
684 case SKIN_TOKEN_TRACK_STARTING
:
685 case SKIN_TOKEN_TRACK_ENDING
:
693 val
= element
->params
[0].data
.number
;
694 token
->value
.i
= val
* TIMEOUT_UNIT
;
698 static int parse_progressbar_tag(struct skin_element
* element
,
699 struct wps_token
*token
,
700 struct wps_data
*wps_data
)
702 #ifdef HAVE_LCD_BITMAP
703 struct progressbar
*pb
;
704 struct viewport
*vp
= &curr_vp
->vp
;
705 struct skin_tag_parameter
*param
= element
->params
;
707 char *image_filename
= NULL
;
709 if (element
->params_count
== 0 &&
710 element
->tag
->type
!= SKIN_TOKEN_PROGRESSBAR
)
711 return 0; /* nothing to do */
712 pb
= (struct progressbar
*)skin_buffer_alloc(sizeof(struct progressbar
));
714 token
->value
.data
= pb
;
717 return WPS_ERROR_INVALID_PARAM
;
719 pb
->follow_lang_direction
= follow_lang_direction
> 0;
725 pb
->invert_fill_direction
= false;
726 pb
->horizontal
= true;
728 if (element
->params_count
== 0)
731 pb
->width
= vp
->width
;
732 pb
->height
= SYSFONT_HEIGHT
-2;
733 pb
->y
= -1; /* Will be computed during the rendering */
734 pb
->type
= element
->tag
->type
;
738 /* (x, y, width, height, ...) */
739 if (!isdefault(param
))
740 pb
->x
= param
->data
.number
;
745 if (!isdefault(param
))
746 pb
->y
= param
->data
.number
;
748 pb
->y
= -1; /* computed at rendering */
751 if (!isdefault(param
))
752 pb
->width
= param
->data
.number
;
754 pb
->width
= vp
->width
- pb
->x
;
757 if (!isdefault(param
))
759 /* A zero height makes no sense - reject it */
760 if (param
->data
.number
== 0)
761 return WPS_ERROR_INVALID_PARAM
;
763 pb
->height
= param
->data
.number
;
767 if (vp
->font
> FONT_UI
)
768 pb
->height
= -1; /* calculate at display time */
772 pb
->height
= font_get(vp
->font
)->height
;
778 /* optional params, first is the image filename if it isnt recognised as a keyword */
781 if (isdefault(&element
->params
[curr_param
]))
787 pb
->horizontal
= pb
->width
> pb
->height
;
788 while (curr_param
< element
->params_count
)
791 if (!strcmp(param
->data
.text
, "invert"))
792 pb
->invert_fill_direction
= true;
793 else if (!strcmp(param
->data
.text
, "nofill"))
795 else if (!strcmp(param
->data
.text
, "nobar"))
797 else if (!strcmp(param
->data
.text
, "slider"))
799 if (curr_param
+1 < element
->params_count
)
803 pb
->slider
= skin_find_item(param
->data
.text
,
804 SKIN_FIND_IMAGE
, wps_data
);
806 else /* option needs the next param */
809 else if (!strcmp(param
->data
.text
, "image"))
811 if (curr_param
+1 < element
->params_count
)
815 image_filename
= param
->data
.text
;
818 else /* option needs the next param */
821 else if (!strcmp(param
->data
.text
, "backdrop"))
823 if (curr_param
+1 < element
->params_count
)
827 pb
->backdrop
= skin_find_item(param
->data
.text
,
828 SKIN_FIND_IMAGE
, wps_data
);
831 else /* option needs the next param */
834 else if (!strcmp(param
->data
.text
, "vertical"))
836 pb
->horizontal
= false;
837 if (isdefault(&element
->params
[3]))
838 pb
->height
= vp
->height
- pb
->y
;
840 else if (!strcmp(param
->data
.text
, "horizontal"))
841 pb
->horizontal
= true;
842 else if (curr_param
== 4)
843 image_filename
= param
->data
.text
;
850 pb
->image
= skin_find_item(image_filename
, SKIN_FIND_IMAGE
, wps_data
);
851 if (!pb
->image
) /* load later */
853 struct gui_img
* img
= (struct gui_img
*)skin_buffer_alloc(sizeof(struct gui_img
));
855 return WPS_ERROR_INVALID_PARAM
;
856 /* save a pointer to the filename */
857 img
->bm
.data
= (char*)image_filename
;
858 img
->label
= image_filename
;
861 img
->num_subimages
= 1;
862 img
->always_display
= false;
864 img
->using_preloaded_icons
= false;
865 img
->vp
= &curr_vp
->vp
;
866 struct skin_token_list
*item
=
867 (struct skin_token_list
*)new_skin_token_list_item(NULL
, img
);
869 return WPS_ERROR_INVALID_PARAM
;
870 add_to_ll_chain(&wps_data
->images
, item
);
875 if (token
->type
== SKIN_TOKEN_VOLUME
)
876 token
->type
= SKIN_TOKEN_VOLUMEBAR
;
877 else if (token
->type
== SKIN_TOKEN_BATTERY_PERCENT
)
878 token
->type
= SKIN_TOKEN_BATTERY_PERCENTBAR
;
879 else if (token
->type
== SKIN_TOKEN_TUNER_RSSI
)
880 token
->type
= SKIN_TOKEN_TUNER_RSSI_BAR
;
881 else if (token
->type
== SKIN_TOKEN_PEAKMETER_LEFT
)
882 token
->type
= SKIN_TOKEN_PEAKMETER_LEFTBAR
;
883 else if (token
->type
== SKIN_TOKEN_PEAKMETER_RIGHT
)
884 token
->type
= SKIN_TOKEN_PEAKMETER_RIGHTBAR
;
885 pb
->type
= token
->type
;
891 if (token
->type
== SKIN_TOKEN_PROGRESSBAR
||
892 token
->type
== SKIN_TOKEN_PLAYER_PROGRESSBAR
)
894 wps_data
->full_line_progressbar
=
895 token
->type
== SKIN_TOKEN_PLAYER_PROGRESSBAR
;
903 static int parse_albumart_load(struct skin_element
* element
,
904 struct wps_token
*token
,
905 struct wps_data
*wps_data
)
907 struct dim dimensions
;
909 bool swap_for_rtl
= lang_is_rtl() && follow_lang_direction
;
910 struct skin_albumart
*aa
=
911 (struct skin_albumart
*)skin_buffer_alloc(sizeof(struct skin_albumart
));
912 (void)token
; /* silence warning */
916 /* reset albumart info in wps */
919 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
920 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
922 aa
->x
= element
->params
[0].data
.number
;
923 aa
->y
= element
->params
[1].data
.number
;
924 aa
->width
= element
->params
[2].data
.number
;
925 aa
->height
= element
->params
[3].data
.number
;
927 aa
->vp
= &curr_vp
->vp
;
928 aa
->draw_handle
= -1;
930 /* if we got here, we parsed everything ok .. ! */
933 else if (aa
->width
> LCD_WIDTH
)
934 aa
->width
= LCD_WIDTH
;
938 else if (aa
->height
> LCD_HEIGHT
)
939 aa
->height
= LCD_HEIGHT
;
942 aa
->x
= LCD_WIDTH
- (aa
->x
+ aa
->width
);
944 aa
->state
= WPS_ALBUMART_LOAD
;
945 wps_data
->albumart
= aa
;
947 dimensions
.width
= aa
->width
;
948 dimensions
.height
= aa
->height
;
950 albumart_slot
= playback_claim_aa_slot(&dimensions
);
952 if (0 <= albumart_slot
)
953 wps_data
->playback_aa_slot
= albumart_slot
;
955 if (element
->params_count
> 4 && !isdefault(&element
->params
[4]))
957 switch (*element
->params
[4].data
.text
)
962 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
964 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
968 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
;
973 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
975 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
979 if (element
->params_count
> 5 && !isdefault(&element
->params
[5]))
981 switch (*element
->params
[5].data
.text
)
985 aa
->yalign
= WPS_ALBUMART_ALIGN_TOP
;
989 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
;
993 aa
->yalign
= WPS_ALBUMART_ALIGN_BOTTOM
;
1000 #endif /* HAVE_ALBUMART */
1001 #ifdef HAVE_SKIN_VARIABLES
1002 static struct skin_var
* find_or_add_var(const char* label
,
1003 struct wps_data
*data
)
1005 struct skin_var
* ret
= skin_find_item(label
, SKIN_VARIABLE
, data
);
1008 ret
= (struct skin_var
*)skin_buffer_alloc(sizeof(struct skin_var
));
1013 ret
->last_changed
= 0xffff;
1014 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, ret
);
1017 add_to_ll_chain(&data
->skinvars
, item
);
1021 static int parse_skinvar( struct skin_element
*element
,
1022 struct wps_token
*token
,
1023 struct wps_data
*wps_data
)
1025 const char* label
= element
->params
[0].data
.text
;
1026 struct skin_var
* var
= find_or_add_var(label
, wps_data
);
1028 return WPS_ERROR_INVALID_PARAM
;
1029 switch (token
->type
)
1031 case SKIN_TOKEN_VAR_GETVAL
:
1032 token
->value
.data
= var
;
1034 case SKIN_TOKEN_VAR_SET
:
1036 struct skin_var_changer
*data
=
1037 (struct skin_var_changer
*)skin_buffer_alloc(
1038 sizeof(struct skin_var_changer
));
1040 return WPS_ERROR_INVALID_PARAM
;
1042 data
->newval
= element
->params
[2].data
.number
;
1044 if (!strcmp(element
->params
[1].data
.text
, "set"))
1045 data
->direct
= true;
1046 else if (!strcmp(element
->params
[1].data
.text
, "inc"))
1048 data
->direct
= false;
1050 else if (!strcmp(element
->params
[1].data
.text
, "dec"))
1052 data
->direct
= false;
1055 if (element
->params_count
> 3)
1056 data
->max
= element
->params
[3].data
.number
;
1057 token
->value
.data
= data
;
1060 case SKIN_TOKEN_VAR_TIMEOUT
:
1062 struct skin_var_lastchange
*data
=
1063 (struct skin_var_lastchange
*)skin_buffer_alloc(
1064 sizeof(struct skin_var_lastchange
));
1066 return WPS_ERROR_INVALID_PARAM
;
1069 if (element
->params_count
> 1)
1070 data
->timeout
= element
->params
[1].data
.number
;
1071 data
->timeout
*= TIMEOUT_UNIT
;
1072 token
->value
.data
= data
;
1075 default: /* kill the warning */
1080 #endif /* HAVE_SKIN_VARIABLES */
1081 #ifdef HAVE_TOUCHSCREEN
1082 static int parse_lasttouch(struct skin_element
*element
,
1083 struct wps_token
*token
,
1084 struct wps_data
*wps_data
)
1086 struct touchregion_lastpress
*data
=
1087 (struct touchregion_lastpress
*)skin_buffer_alloc(
1088 sizeof(struct touchregion_lastpress
));
1091 return WPS_ERROR_INVALID_PARAM
;
1092 data
->region
= NULL
;
1095 for (i
=0; i
<element
->params_count
; i
++)
1097 if (element
->params
[i
].type
== STRING
)
1098 data
->region
= skin_find_item(element
->params
[i
].data
.text
,
1099 SKIN_FIND_TOUCHREGION
, wps_data
);
1100 else if (element
->params
[i
].type
== INTEGER
||
1101 element
->params
[i
].type
== DECIMAL
)
1102 data
->timeout
= element
->params
[i
].data
.number
;
1105 data
->timeout
*= TIMEOUT_UNIT
;
1106 token
->value
.data
= data
;
1110 struct touchaction
{const char* s
; int action
;};
1111 static const struct touchaction touchactions
[] = {
1112 /* generic actions, convert to screen actions on use */
1113 {"none", ACTION_TOUCHSCREEN
}, {"lock", ACTION_TOUCH_SOFTLOCK
},
1114 {"prev", ACTION_STD_PREV
}, {"next", ACTION_STD_NEXT
},
1115 {"rwd", ACTION_STD_PREVREPEAT
}, {"ffwd", ACTION_STD_NEXTREPEAT
},
1116 {"hotkey", ACTION_STD_HOTKEY
}, {"select", ACTION_STD_OK
},
1117 {"menu", ACTION_STD_MENU
}, {"cancel", ACTION_STD_CANCEL
},
1118 {"contextmenu", ACTION_STD_CONTEXT
},{"quickscreen", ACTION_STD_QUICKSCREEN
},
1120 /* list/tree actions */
1121 { "resumeplayback", ACTION_TREE_WPS
}, /* returns to previous music, WPS/FM */
1122 /* not really WPS specific, but no equivilant ACTION_STD_* */
1123 {"voldown", ACTION_WPS_VOLDOWN
}, {"volup", ACTION_WPS_VOLUP
},
1124 {"mute", ACTION_TOUCH_MUTE
},
1126 /* generic settings changers */
1127 {"setting_inc", ACTION_SETTINGS_INC
}, {"setting_dec", ACTION_SETTINGS_DEC
},
1128 {"setting_set", ACTION_SETTINGS_SET
},
1130 /* WPS specific actions */
1131 {"wps_prev", ACTION_WPS_SKIPPREV
}, {"wps_next", ACTION_WPS_SKIPNEXT
},
1132 {"browse", ACTION_WPS_BROWSE
},
1133 {"play", ACTION_WPS_PLAY
}, {"stop", ACTION_WPS_STOP
},
1134 {"shuffle", ACTION_TOUCH_SHUFFLE
}, {"repmode", ACTION_TOUCH_REPMODE
},
1135 {"pitch", ACTION_WPS_PITCHSCREEN
}, {"playlist", ACTION_WPS_VIEW_PLAYLIST
},
1138 /* FM screen actions */
1139 /* Also allow browse, play, stop from WPS codes */
1140 {"mode", ACTION_FM_MODE
}, {"record", ACTION_FM_RECORD
},
1141 {"presets", ACTION_FM_PRESET
},
1145 static int touchregion_setup_setting(struct skin_element
*element
, int param_no
,
1146 struct touchregion
*region
)
1149 char *name
= element
->params
[p
++].data
.text
;
1151 /* Find the setting */
1152 for (j
=0; j
<nb_settings
; j
++)
1153 if (settings
[j
].cfg_name
&&
1154 !strcmp(settings
[j
].cfg_name
, name
))
1157 return WPS_ERROR_INVALID_PARAM
;
1158 region
->setting_data
.setting
= (void*)&settings
[j
];
1159 if (region
->action
== ACTION_SETTINGS_SET
)
1163 struct touchsetting
*setting
=
1164 ®ion
->setting_data
;
1165 if (element
->params_count
< p
+1)
1168 text
= element
->params
[p
++].data
.text
;
1169 switch (settings
[j
].flags
&F_T_MASK
)
1172 setting
->value
.text
= text
;
1176 if (settings
[j
].cfg_vals
== NULL
)
1178 setting
->value
.number
= atoi(text
);
1180 else if (cfg_string_to_int(j
, &temp
, text
))
1182 if (settings
[j
].flags
&F_TABLE_SETTING
)
1183 setting
->value
.number
=
1184 settings
[j
].table_setting
->values
[temp
];
1186 setting
->value
.number
= temp
;
1192 if (cfg_string_to_int(j
, &temp
, text
))
1194 setting
->value
.number
= temp
;
1202 #endif /* __PCTOOL__ */
1207 static int parse_touchregion(struct skin_element
*element
,
1208 struct wps_token
*token
,
1209 struct wps_data
*wps_data
)
1214 struct touchregion
*region
= NULL
;
1216 const char pb_string
[] = "progressbar";
1217 const char vol_string
[] = "volume";
1219 /* format: %T([label,], x,y,width,height,action[, ...])
1220 * if action starts with & the area must be held to happen
1224 region
= (struct touchregion
*)skin_buffer_alloc(sizeof(struct touchregion
));
1226 return WPS_ERROR_INVALID_PARAM
;
1228 /* should probably do some bounds checking here with the viewport... but later */
1229 region
->action
= ACTION_NONE
;
1231 if (element
->params
[0].type
== STRING
)
1233 region
->label
= element
->params
[0].data
.text
;
1235 /* "[SI]III[SI]|SS" is the param list. There MUST be 4 numbers
1236 * followed by at least one string. Verify that here */
1237 if (element
->params_count
< 6 ||
1238 element
->params
[4].type
!= INTEGER
)
1239 return WPS_ERROR_INVALID_PARAM
;
1243 region
->label
= NULL
;
1247 region
->x
= element
->params
[p
++].data
.number
;
1248 region
->y
= element
->params
[p
++].data
.number
;
1249 region
->width
= element
->params
[p
++].data
.number
;
1250 region
->height
= element
->params
[p
++].data
.number
;
1251 region
->wvp
= curr_vp
;
1252 region
->armed
= false;
1253 region
->reverse_bar
= false;
1255 region
->last_press
= 0xffff;
1256 region
->press_length
= PRESS
;
1257 region
->allow_while_locked
= false;
1258 action
= element
->params
[p
++].data
.text
;
1260 /* figure out the action */
1261 if(!strcmp(pb_string
, action
))
1262 region
->action
= ACTION_TOUCH_SCROLLBAR
;
1263 else if(!strcmp(vol_string
, action
))
1264 region
->action
= ACTION_TOUCH_VOLUME
;
1267 imax
= ARRAYLEN(touchactions
);
1268 for (i
= 0; i
< imax
; i
++)
1270 /* try to match with one of our touchregion screens */
1271 if (!strcmp(touchactions
[i
].s
, action
))
1273 region
->action
= touchactions
[i
].action
;
1274 if (region
->action
== ACTION_SETTINGS_INC
||
1275 region
->action
== ACTION_SETTINGS_DEC
||
1276 region
->action
== ACTION_SETTINGS_SET
)
1279 if (element
->params_count
< p
+1)
1280 return WPS_ERROR_INVALID_PARAM
;
1281 val
= touchregion_setup_setting(element
, p
, region
);
1283 return WPS_ERROR_INVALID_PARAM
;
1289 if (region
->action
== ACTION_NONE
)
1290 return WPS_ERROR_INVALID_PARAM
;
1292 while (p
< element
->params_count
)
1294 char* param
= element
->params
[p
++].data
.text
;
1295 if (!strcmp(param
, "allow_while_locked"))
1296 region
->allow_while_locked
= true;
1297 else if (!strcmp(param
, "reverse_bar"))
1298 region
->reverse_bar
= true;
1299 else if (!strcmp(param
, "repeat_press"))
1300 region
->press_length
= REPEAT
;
1301 else if (!strcmp(param
, "long_press"))
1302 region
->press_length
= LONG_PRESS
;
1304 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, region
);
1306 return WPS_ERROR_INVALID_PARAM
;
1307 add_to_ll_chain(&wps_data
->touchregions
, item
);
1309 if (region
->action
== ACTION_TOUCH_MUTE
)
1311 region
->value
= global_settings
.volume
;
1319 static bool check_feature_tag(const int type
)
1323 case SKIN_TOKEN_RTC_PRESENT
:
1329 case SKIN_TOKEN_HAVE_RECORDING
:
1330 #ifdef HAVE_RECORDING
1335 case SKIN_TOKEN_HAVE_TUNER
:
1337 if (radio_hardware_present())
1341 case SKIN_TOKEN_HAVE_TOUCH
:
1342 #ifdef HAVE_TOUCHSCREEN
1349 case SKIN_TOKEN_HAVE_RDS
:
1354 #endif /* HAVE_RDS_CAP */
1355 #endif /* CONFIG_TUNER */
1356 default: /* not a tag we care about, just don't skip */
1362 * initial setup of wps_data; does reset everything
1363 * except fields which need to survive, i.e.
1366 static void skin_data_reset(struct wps_data
*wps_data
)
1368 wps_data
->tree
= NULL
;
1369 #ifdef HAVE_LCD_BITMAP
1370 wps_data
->images
= NULL
;
1372 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1373 if (wps_data
->backdrop_id
>= 0)
1374 skin_backdrop_unload(wps_data
->backdrop_id
);
1375 wps_data
->backdrop
= NULL
;
1377 #ifdef HAVE_TOUCHSCREEN
1378 wps_data
->touchregions
= NULL
;
1380 #ifdef HAVE_SKIN_VARIABLES
1381 wps_data
->skinvars
= NULL
;
1383 #ifdef HAVE_ALBUMART
1384 wps_data
->albumart
= NULL
;
1385 if (wps_data
->playback_aa_slot
>= 0)
1387 playback_release_aa_slot(wps_data
->playback_aa_slot
);
1388 wps_data
->playback_aa_slot
= -1;
1392 #ifdef HAVE_LCD_BITMAP
1393 wps_data
->peak_meter_enabled
= false;
1394 wps_data
->wps_sb_tag
= false;
1395 wps_data
->show_sb_on_wps
= false;
1396 #else /* HAVE_LCD_CHARCELLS */
1399 for (i
= 0; i
< 8; i
++)
1401 wps_data
->wps_progress_pat
[i
] = 0;
1403 wps_data
->full_line_progressbar
= false;
1405 wps_data
->wps_loaded
= false;
1408 #ifdef HAVE_LCD_BITMAP
1409 static bool load_skin_bmp(struct wps_data
*wps_data
, struct bitmap
*bitmap
, char* bmpdir
)
1411 (void)wps_data
; /* only needed for remote targets */
1412 char img_path
[MAX_PATH
];
1414 get_image_filename(bitmap
->data
, bmpdir
,
1415 img_path
, sizeof(img_path
));
1417 /* load the image */
1419 #ifdef HAVE_REMOTE_LCD
1420 if (curr_screen
== SCREEN_REMOTE
)
1421 format
= FORMAT_ANY
|FORMAT_REMOTE
;
1424 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
1426 fd
= open(img_path
, O_RDONLY
);
1429 DEBUGF("Couldn't open %s\n", img_path
);
1432 size_t buf_size
= read_bmp_fd(fd
, bitmap
, 0,
1433 format
|FORMAT_RETURN_SIZE
, NULL
);
1434 char* imgbuf
= (char*)skin_buffer_alloc(buf_size
);
1438 DEBUGF("Not enough skin buffer: need %zd more.\n",
1439 buf_size
- skin_buffer_freespace());
1444 lseek(fd
, 0, SEEK_SET
);
1445 bitmap
->data
= imgbuf
;
1446 int ret
= read_bmp_fd(fd
, bitmap
, buf_size
, format
, NULL
);
1455 /* Abort if we can't load an image */
1456 DEBUGF("Couldn't load '%s'\n", img_path
);
1461 static bool load_skin_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
1463 struct skin_token_list
*list
;
1464 bool retval
= true; /* return false if a single image failed to load */
1466 /* regular images */
1467 list
= wps_data
->images
;
1470 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
1473 if (img
->using_preloaded_icons
)
1476 list
->token
->type
= SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
;
1480 img
->loaded
= load_skin_bmp(wps_data
, &img
->bm
, bmpdir
);
1482 img
->subimage_height
= img
->bm
.height
/ img
->num_subimages
;
1490 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1491 wps_data
->backdrop_id
= skin_backdrop_assign(wps_data
->backdrop
, bmpdir
, curr_screen
);
1492 #endif /* has backdrop support */
1496 static bool skin_load_fonts(struct wps_data
*data
)
1498 /* don't spit out after the first failue to aid debugging */
1499 bool success
= true;
1500 struct skin_element
*vp_list
;
1502 /* walk though each viewport and assign its font */
1503 for(vp_list
= data
->tree
; vp_list
; vp_list
= vp_list
->next
)
1505 /* first, find the viewports that have a non-sys/ui-font font */
1506 struct skin_viewport
*skin_vp
=
1507 (struct skin_viewport
*)vp_list
->data
;
1508 struct viewport
*vp
= &skin_vp
->vp
;
1511 if (vp
->font
<= FONT_UI
)
1512 { /* the usual case -> built-in fonts */
1513 #ifdef HAVE_REMOTE_LCD
1514 if (vp
->font
== FONT_UI
)
1515 vp
->font
+= curr_screen
;
1521 /* now find the corresponding skin_font */
1522 struct skin_font
*font
= &skinfonts
[font_id
-FONT_FIRSTUSERFONT
];
1527 DEBUGF("font %d not specified\n", font_id
);
1533 /* load the font - will handle loading the same font again if
1534 * multiple viewports use the same */
1537 char *dot
= strchr(font
->name
, '.');
1539 font
->id
= skin_font_load(font
->name
,
1540 skinfonts
[font_id
-FONT_FIRSTUSERFONT
].glyphs
);
1545 DEBUGF("Unable to load font %d: '%s.fnt'\n",
1546 font_id
, font
->name
);
1547 font
->name
= NULL
; /* to stop trying to load it again if we fail */
1553 /* finally, assign the font_id to the viewport */
1554 vp
->font
= font
->id
;
1559 #endif /* HAVE_LCD_BITMAP */
1560 static int convert_viewport(struct wps_data
*data
, struct skin_element
* element
)
1562 struct skin_viewport
*skin_vp
=
1563 (struct skin_viewport
*)skin_buffer_alloc(sizeof(struct skin_viewport
));
1564 struct screen
*display
= &screens
[curr_screen
];
1567 return CALLBACK_ERROR
;
1569 skin_vp
->hidden_flags
= 0;
1570 skin_vp
->label
= NULL
;
1571 skin_vp
->is_infovp
= false;
1572 element
->data
= skin_vp
;
1574 curr_viewport_element
= element
;
1576 viewport_set_defaults(&skin_vp
->vp
, curr_screen
);
1577 #ifdef HAVE_REMOTE_LCD
1578 /* viewport_set_defaults() sets the font to FONT_UI+curr_screen.
1579 * This parser requires font 1 to always be the UI font,
1580 * so force it back to FONT_UI and handle the screen number at the end */
1581 skin_vp
->vp
.font
= FONT_UI
;
1584 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1585 skin_vp
->start_fgcolour
= skin_vp
->vp
.fg_pattern
;
1586 skin_vp
->start_bgcolour
= skin_vp
->vp
.bg_pattern
;
1588 #ifdef HAVE_LCD_COLOR
1589 skin_vp
->start_gradient
.start
= skin_vp
->vp
.lss_pattern
;
1590 skin_vp
->start_gradient
.end
= skin_vp
->vp
.lse_pattern
;
1591 skin_vp
->start_gradient
.text
= skin_vp
->vp
.lst_pattern
;
1595 struct skin_tag_parameter
*param
= element
->params
;
1596 if (element
->params_count
== 0) /* default viewport */
1598 if (!data
->tree
) /* first viewport in the skin */
1599 data
->tree
= element
;
1600 skin_vp
->label
= VP_DEFAULT_LABEL
;
1604 if (element
->params_count
== 6)
1606 if (element
->tag
->type
== SKIN_TOKEN_UIVIEWPORT_LOAD
)
1608 skin_vp
->is_infovp
= true;
1609 if (isdefault(param
))
1611 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
1612 skin_vp
->label
= VP_DEFAULT_LABEL
;
1616 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
1617 skin_vp
->label
= param
->data
.text
;
1622 skin_vp
->hidden_flags
= VP_DRAW_HIDEABLE
|VP_DRAW_HIDDEN
;
1623 skin_vp
->label
= param
->data
.text
;
1628 if (!isdefault(param
))
1630 skin_vp
->vp
.x
= param
->data
.number
;
1631 if (param
->data
.number
< 0)
1632 skin_vp
->vp
.x
+= display
->lcdwidth
;
1636 if (!isdefault(param
))
1638 skin_vp
->vp
.y
= param
->data
.number
;
1639 if (param
->data
.number
< 0)
1640 skin_vp
->vp
.y
+= display
->lcdheight
;
1644 if (!isdefault(param
))
1646 skin_vp
->vp
.width
= param
->data
.number
;
1647 if (param
->data
.number
< 0)
1648 skin_vp
->vp
.width
= (skin_vp
->vp
.width
+ display
->lcdwidth
) - skin_vp
->vp
.x
;
1652 skin_vp
->vp
.width
= display
->lcdwidth
- skin_vp
->vp
.x
;
1656 if (!isdefault(param
))
1658 skin_vp
->vp
.height
= param
->data
.number
;
1659 if (param
->data
.number
< 0)
1660 skin_vp
->vp
.height
= (skin_vp
->vp
.height
+ display
->lcdheight
) - skin_vp
->vp
.y
;
1664 skin_vp
->vp
.height
= display
->lcdheight
- skin_vp
->vp
.y
;
1667 #ifdef HAVE_LCD_BITMAP
1669 if (!isdefault(param
))
1671 skin_vp
->vp
.font
= param
->data
.number
;
1674 if ((unsigned) skin_vp
->vp
.x
>= (unsigned) display
->lcdwidth
||
1675 skin_vp
->vp
.width
+ skin_vp
->vp
.x
> display
->lcdwidth
||
1676 (unsigned) skin_vp
->vp
.y
>= (unsigned) display
->lcdheight
||
1677 skin_vp
->vp
.height
+ skin_vp
->vp
.y
> display
->lcdheight
)
1678 return CALLBACK_ERROR
;
1683 static int skin_element_callback(struct skin_element
* element
, void* data
)
1685 struct wps_data
*wps_data
= (struct wps_data
*)data
;
1686 struct wps_token
*token
;
1687 parse_function function
= NULL
;
1689 switch (element
->type
)
1691 /* IMPORTANT: element params are shared, so copy them if needed
1692 * or use then NOW, dont presume they have a long lifespan
1696 token
= (struct wps_token
*)skin_buffer_alloc(sizeof(struct wps_token
));
1697 memset(token
, 0, sizeof(*token
));
1698 token
->type
= element
->tag
->type
;
1700 if (element
->tag
->flags
&SKIN_RTC_REFRESH
)
1703 curr_line
->update_mode
|= SKIN_REFRESH_DYNAMIC
;
1705 curr_line
->update_mode
|= SKIN_REFRESH_STATIC
;
1709 curr_line
->update_mode
|= element
->tag
->flags
&SKIN_REFRESH_ALL
;
1711 element
->data
= token
;
1713 /* Some tags need special handling for the tag, so add them here */
1714 switch (token
->type
)
1716 case SKIN_TOKEN_ALIGN_LANGDIRECTION
:
1717 follow_lang_direction
= 2;
1719 case SKIN_TOKEN_LOGICAL_IF
:
1720 function
= parse_logical_if
;
1722 case SKIN_TOKEN_PROGRESSBAR
:
1723 case SKIN_TOKEN_VOLUME
:
1724 case SKIN_TOKEN_BATTERY_PERCENT
:
1725 case SKIN_TOKEN_PLAYER_PROGRESSBAR
:
1726 case SKIN_TOKEN_PEAKMETER_LEFT
:
1727 case SKIN_TOKEN_PEAKMETER_RIGHT
:
1728 #ifdef HAVE_RADIO_RSSI
1729 case SKIN_TOKEN_TUNER_RSSI
:
1731 function
= parse_progressbar_tag
;
1733 case SKIN_TOKEN_SUBLINE_TIMEOUT
:
1734 case SKIN_TOKEN_BUTTON_VOLUME
:
1735 case SKIN_TOKEN_TRACK_STARTING
:
1736 case SKIN_TOKEN_TRACK_ENDING
:
1737 function
= parse_timeout_tag
;
1739 #ifdef HAVE_LCD_BITMAP
1740 case SKIN_TOKEN_DISABLE_THEME
:
1741 case SKIN_TOKEN_ENABLE_THEME
:
1742 case SKIN_TOKEN_DRAW_INBUILTBAR
:
1743 function
= parse_statusbar_tags
;
1745 case SKIN_TOKEN_LIST_TITLE_TEXT
:
1747 sb_skin_has_title(curr_screen
);
1751 case SKIN_TOKEN_FILE_DIRECTORY
:
1752 token
->value
.i
= element
->params
[0].data
.number
;
1754 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1755 case SKIN_TOKEN_VIEWPORT_FGCOLOUR
:
1756 case SKIN_TOKEN_VIEWPORT_BGCOLOUR
:
1757 function
= parse_viewportcolour
;
1759 case SKIN_TOKEN_IMAGE_BACKDROP
:
1760 function
= parse_image_special
;
1763 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE
:
1764 function
= parse_viewporttextstyle
;
1766 #ifdef HAVE_LCD_COLOR
1767 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP
:
1768 function
= parse_viewport_gradient_setup
;
1771 case SKIN_TOKEN_TRANSLATEDSTRING
:
1772 case SKIN_TOKEN_SETTING
:
1773 function
= parse_setting_and_lang
;
1775 #ifdef HAVE_LCD_BITMAP
1776 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
1777 function
= parse_playlistview
;
1779 case SKIN_TOKEN_LOAD_FONT
:
1780 function
= parse_font_load
;
1782 case SKIN_TOKEN_VIEWPORT_ENABLE
:
1783 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
1784 token
->value
.data
= element
->params
[0].data
.text
;
1786 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
1787 function
= parse_image_display
;
1789 case SKIN_TOKEN_IMAGE_PRELOAD
:
1790 case SKIN_TOKEN_IMAGE_DISPLAY
:
1791 function
= parse_image_load
;
1794 #ifdef HAVE_TOUCHSCREEN
1795 case SKIN_TOKEN_TOUCHREGION
:
1796 function
= parse_touchregion
;
1798 case SKIN_TOKEN_LASTTOUCH
:
1799 function
= parse_lasttouch
;
1802 #ifdef HAVE_ALBUMART
1803 case SKIN_TOKEN_ALBUMART_DISPLAY
:
1804 if (wps_data
->albumart
)
1805 wps_data
->albumart
->vp
= &curr_vp
->vp
;
1807 case SKIN_TOKEN_ALBUMART_LOAD
:
1808 function
= parse_albumart_load
;
1811 #ifdef HAVE_SKIN_VARIABLES
1812 case SKIN_TOKEN_VAR_SET
:
1813 case SKIN_TOKEN_VAR_GETVAL
:
1814 case SKIN_TOKEN_VAR_TIMEOUT
:
1815 function
= parse_skinvar
;
1823 if (function(element
, token
, wps_data
) < 0)
1824 return CALLBACK_ERROR
;
1826 /* tags that start with 'F', 'I' or 'D' are for the next file */
1827 if ( *(element
->tag
->name
) == 'I' || *(element
->tag
->name
) == 'F' ||
1828 *(element
->tag
->name
) == 'D')
1830 if (follow_lang_direction
> 0 )
1831 follow_lang_direction
--;
1835 return convert_viewport(wps_data
, element
);
1839 (struct line
*)skin_buffer_alloc(sizeof(struct line
));
1840 line
->update_mode
= SKIN_REFRESH_STATIC
;
1842 element
->data
= line
;
1845 case LINE_ALTERNATOR
:
1847 struct line_alternator
*alternator
=
1848 (struct line_alternator
*)skin_buffer_alloc(sizeof(struct line_alternator
));
1849 alternator
->current_line
= 0;
1851 alternator
->next_change_tick
= current_tick
;
1853 element
->data
= alternator
;
1858 struct conditional
*conditional
=
1859 (struct conditional
*)skin_buffer_alloc(sizeof(struct conditional
));
1860 conditional
->last_value
= -1;
1861 conditional
->token
= element
->data
;
1862 element
->data
= conditional
;
1863 if (!check_feature_tag(element
->tag
->type
))
1865 return FEATURE_NOT_AVAILABLE
;
1870 curr_line
->update_mode
|= SKIN_REFRESH_STATIC
;
1878 /* to setup up the wps-data from a format-buffer (isfile = false)
1879 from a (wps-)file (isfile = true)*/
1880 bool skin_data_load(enum screen_type screen
, struct wps_data
*wps_data
,
1881 const char *buf
, bool isfile
)
1883 char *wps_buffer
= NULL
;
1884 if (!wps_data
|| !buf
)
1886 #ifdef HAVE_ALBUMART
1888 struct mp3entry
*curtrack
;
1890 struct skin_albumart old_aa
= {.state
= WPS_ALBUMART_NONE
};
1891 if (wps_data
->albumart
)
1893 old_aa
.state
= wps_data
->albumart
->state
;
1894 old_aa
.height
= wps_data
->albumart
->height
;
1895 old_aa
.width
= wps_data
->albumart
->width
;
1898 #ifdef HAVE_LCD_BITMAP
1900 for (i
=0;i
<MAXUSERFONTS
;i
++)
1902 skinfonts
[i
].id
= -1;
1903 skinfonts
[i
].name
= NULL
;
1906 #ifdef DEBUG_SKIN_ENGINE
1907 if (isfile
&& debug_wps
)
1909 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf
);
1914 skin_data_reset(wps_data
);
1915 wps_data
->wps_loaded
= false;
1916 curr_screen
= screen
;
1919 curr_viewport_element
= NULL
;
1923 int fd
= open_utf8(buf
, O_RDONLY
);
1928 /* get buffer space from the plugin buffer */
1929 size_t buffersize
= 0;
1930 wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
1935 /* copy the file's content to the buffer for parsing,
1936 ensuring that every line ends with a newline char. */
1937 unsigned int start
= 0;
1938 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
1940 start
+= strlen(wps_buffer
+ start
);
1941 if (start
< buffersize
- 1)
1943 wps_buffer
[start
++] = '\n';
1944 wps_buffer
[start
] = 0;
1953 wps_buffer
= (char*)buf
;
1955 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1956 wps_data
->backdrop
= "-";
1957 wps_data
->backdrop_id
= -1;
1959 /* parse the skin source */
1961 skin_buffer_save_position();
1963 wps_data
->tree
= skin_parse(wps_buffer
, skin_element_callback
, wps_data
);
1964 if (!wps_data
->tree
) {
1965 skin_data_reset(wps_data
);
1967 skin_buffer_restore_position();
1972 #ifdef HAVE_LCD_BITMAP
1973 char bmpdir
[MAX_PATH
];
1976 /* get the bitmap dir */
1977 char *dot
= strrchr(buf
, '.');
1978 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
1982 snprintf(bmpdir
, MAX_PATH
, "%s", BACKDROP_DIR
);
1984 /* load the bitmaps that were found by the parsing */
1985 if (!load_skin_bitmaps(wps_data
, bmpdir
) ||
1986 !skin_load_fonts(wps_data
))
1988 skin_data_reset(wps_data
);
1990 skin_buffer_restore_position();
1995 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
1996 status
= audio_status();
1997 if (status
& AUDIO_STATUS_PLAY
)
1999 struct skin_albumart
*aa
= wps_data
->albumart
;
2000 if (aa
&& ((aa
->state
&& !old_aa
.state
) ||
2002 (((old_aa
.height
!= aa
->height
) ||
2003 (old_aa
.width
!= aa
->width
))))))
2005 curtrack
= audio_current_track();
2006 offset
= curtrack
->offset
;
2008 if (!(status
& AUDIO_STATUS_PAUSE
))
2013 wps_data
->wps_loaded
= true;
2014 #ifdef DEBUG_SKIN_ENGINE
2015 // if (isfile && debug_wps)
2016 // debug_skin_usage();