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 ****************************************************************************/
27 #include "core_alloc.h"
33 #include "skin_buffer.h"
34 #include "skin_parser.h"
35 #include "tag_table.h"
45 #define lang_is_rtl() (false)
57 #include "wps_internals.h"
58 #include "skin_engine.h"
60 #include "settings_list.h"
66 #ifdef HAVE_LCD_BITMAP
75 #include "statusbar-skinned.h"
77 #define WPS_ERROR_INVALID_PARAM -1
80 #define SKIN_FONT_SIZE (1024*10)
82 #define SKIN_FONT_SIZE (1024*3)
84 #define GLYPHS_TO_CACHE 256
86 static bool isdefault(struct skin_tag_parameter
*param
)
88 return param
->type
== DEFAULT
;
92 /* which screen are we parsing for? */
93 static enum screen_type curr_screen
;
95 /* the current viewport */
96 static struct skin_element
*curr_viewport_element
;
97 static struct skin_viewport
*curr_vp
;
99 static struct line
*curr_line
;
101 static int follow_lang_direction
= 0;
103 typedef int (*parse_function
)(struct skin_element
*element
,
104 struct wps_token
*token
,
105 struct wps_data
*wps_data
);
107 #ifdef HAVE_LCD_BITMAP
108 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
109 * chains require the order to be kept.
111 static void add_to_ll_chain(struct skin_token_list
**list
, struct skin_token_list
*item
)
117 struct skin_token_list
*t
= *list
;
127 void *skin_find_item(const char *label
, enum skin_find_what what
,
128 struct wps_data
*data
)
130 const char *itemlabel
= NULL
;
132 struct skin_token_list
*linkedlist
;
133 struct skin_element
*vplist
;
135 bool isvplist
= false;
141 list
.vplist
= data
->tree
;
144 #ifdef HAVE_LCD_BITMAP
145 case SKIN_FIND_IMAGE
:
146 list
.linkedlist
= data
->images
;
149 #ifdef HAVE_TOUCHSCREEN
150 case SKIN_FIND_TOUCHREGION
:
151 list
.linkedlist
= data
->touchregions
;
154 #ifdef HAVE_SKIN_VARIABLES
156 list
.linkedlist
= data
->skinvars
;
161 while (list
.linkedlist
)
168 ret
= list
.vplist
->data
;
169 itemlabel
= ((struct skin_viewport
*)ret
)->label
;
170 skip
= !(((struct skin_viewport
*)ret
)->is_infovp
==
171 (what
==SKIN_FIND_UIVP
));
173 #ifdef HAVE_LCD_BITMAP
174 case SKIN_FIND_IMAGE
:
175 ret
= list
.linkedlist
->token
->value
.data
;
176 itemlabel
= ((struct gui_img
*)ret
)->label
;
179 #ifdef HAVE_TOUCHSCREEN
180 case SKIN_FIND_TOUCHREGION
:
181 ret
= list
.linkedlist
->token
->value
.data
;
182 itemlabel
= ((struct touchregion
*)ret
)->label
;
185 #ifdef HAVE_SKIN_VARIABLES
187 ret
= list
.linkedlist
->token
->value
.data
;
188 itemlabel
= ((struct skin_var
*)ret
)->label
;
193 if (!skip
&& itemlabel
&& !strcmp(itemlabel
, label
))
197 list
.vplist
= list
.vplist
->next
;
199 list
.linkedlist
= list
.linkedlist
->next
;
204 #ifdef HAVE_LCD_BITMAP
206 /* create and init a new wpsll item.
207 * passing NULL to token will alloc a new one.
208 * You should only pass NULL for the token when the token type (table above)
209 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
211 static struct skin_token_list
*new_skin_token_list_item(struct wps_token
*token
,
214 struct skin_token_list
*llitem
=
215 (struct skin_token_list
*)skin_buffer_alloc(sizeof(struct skin_token_list
));
217 token
= (struct wps_token
*)skin_buffer_alloc(sizeof(struct wps_token
));
218 if (!llitem
|| !token
)
221 llitem
->token
= token
;
223 llitem
->token
->value
.data
= token_data
;
227 static int parse_statusbar_tags(struct skin_element
* element
,
228 struct wps_token
*token
,
229 struct wps_data
*wps_data
)
232 if (token
->type
== SKIN_TOKEN_DRAW_INBUILTBAR
)
234 token
->value
.data
= (void*)&curr_vp
->vp
;
238 struct skin_element
*def_vp
= wps_data
->tree
;
239 struct skin_viewport
*default_vp
= def_vp
->data
;
240 if (def_vp
->params_count
== 0)
242 wps_data
->wps_sb_tag
= true;
243 wps_data
->show_sb_on_wps
= (token
->type
== SKIN_TOKEN_ENABLE_THEME
);
245 if (wps_data
->show_sb_on_wps
)
247 viewport_set_defaults(&default_vp
->vp
, curr_screen
);
251 viewport_set_fullscreen(&default_vp
->vp
, curr_screen
);
253 #ifdef HAVE_REMOTE_LCD
254 /* viewport_set_defaults() sets the font to FONT_UI+curr_screen.
255 * This parser requires font 1 to always be the UI font,
256 * so force it back to FONT_UI and handle the screen number at the end */
257 default_vp
->vp
.font
= FONT_UI
;
263 static int get_image_id(int c
)
265 if(c
>= 'a' && c
<= 'z')
267 else if(c
>= 'A' && c
<= 'Z')
273 char *get_image_filename(const char *start
, const char* bmpdir
,
274 char *buf
, int buf_size
)
276 snprintf(buf
, buf_size
, "%s/%s", bmpdir
, start
);
281 static int parse_image_display(struct skin_element
*element
,
282 struct wps_token
*token
,
283 struct wps_data
*wps_data
)
285 char *label
= element
->params
[0].data
.text
;
286 char sublabel
= '\0';
289 struct image_display
*id
= skin_buffer_alloc(sizeof(struct image_display
));
291 if (element
->params_count
== 1 && strlen(label
) <= 2)
293 /* backwards compatability. Allow %xd(Aa) to still work */
298 img
= skin_find_item(label
, SKIN_FIND_IMAGE
, wps_data
);
301 return WPS_ERROR_INVALID_PARAM
;
306 if (img
->using_preloaded_icons
)
308 token
->type
= SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
;
311 if (element
->params_count
> 1)
313 if (element
->params
[1].type
== CODE
)
314 id
->token
= element
->params
[1].data
.code
->data
;
315 /* specify a number. 1 being the first subimage (i.e top) NOT 0 */
316 else if (element
->params
[1].type
== INTEGER
)
317 id
->subimage
= element
->params
[1].data
.number
- 1;
318 if (element
->params_count
> 2)
319 id
->offset
= element
->params
[2].data
.number
;
323 if ((subimage
= get_image_id(sublabel
)) != -1)
325 if (subimage
>= img
->num_subimages
)
326 return WPS_ERROR_INVALID_PARAM
;
327 id
->subimage
= subimage
;
332 token
->value
.data
= id
;
336 static int parse_image_load(struct skin_element
*element
,
337 struct wps_token
*token
,
338 struct wps_data
*wps_data
)
340 const char* filename
;
345 /* format: %x(n,filename.bmp,x,y)
346 or %xl(n,filename.bmp,x,y)
347 or %xl(n,filename.bmp,x,y,num_subimages)
350 id
= element
->params
[0].data
.text
;
351 filename
= element
->params
[1].data
.text
;
352 x
= element
->params
[2].data
.number
;
353 y
= element
->params
[3].data
.number
;
355 /* check the image number and load state */
356 if(skin_find_item(id
, SKIN_FIND_IMAGE
, wps_data
))
358 /* Invalid image ID */
359 return WPS_ERROR_INVALID_PARAM
;
361 img
= (struct gui_img
*)skin_buffer_alloc(sizeof(struct gui_img
));
363 return WPS_ERROR_INVALID_PARAM
;
364 /* save a pointer to the filename */
365 img
->bm
.data
= (char*)filename
;
369 img
->num_subimages
= 1;
370 img
->always_display
= false;
372 img
->using_preloaded_icons
= false;
373 img
->buflib_handle
= -1;
375 /* save current viewport */
376 img
->vp
= &curr_vp
->vp
;
378 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY
)
380 img
->always_display
= true;
382 else if (element
->params_count
== 5)
384 img
->num_subimages
= element
->params
[4].data
.number
;
385 if (img
->num_subimages
<= 0)
386 return WPS_ERROR_INVALID_PARAM
;
389 if (!strcmp(img
->bm
.data
, "__list_icons__"))
391 img
->num_subimages
= Icon_Last_Themeable
;
392 img
->using_preloaded_icons
= true;
395 struct skin_token_list
*item
=
396 (struct skin_token_list
*)new_skin_token_list_item(NULL
, img
);
398 return WPS_ERROR_INVALID_PARAM
;
399 add_to_ll_chain(&wps_data
->images
, item
);
404 int id
; /* the id from font_load */
405 char *name
; /* filename without path and extension */
406 int glyphs
; /* how many glyphs to reserve room for */
408 static struct skin_font skinfonts
[MAXUSERFONTS
];
409 static int parse_font_load(struct skin_element
*element
,
410 struct wps_token
*token
,
411 struct wps_data
*wps_data
)
413 (void)wps_data
; (void)token
;
414 int id
= element
->params
[0].data
.number
;
415 char *filename
= element
->params
[1].data
.text
;
419 if(element
->params_count
> 2)
420 glyphs
= element
->params
[2].data
.number
;
425 DEBUGF("font id must be >= 2\n");
428 #if defined(DEBUG) || defined(SIMULATOR)
429 if (skinfonts
[id
-2].name
!= NULL
)
431 DEBUGF("font id %d already being used\n", id
);
434 /* make sure the filename contains .fnt,
435 * we dont actually use it, but require it anyway */
436 ptr
= strchr(filename
, '.');
437 if (!ptr
|| strncmp(ptr
, ".fnt", 4))
438 return WPS_ERROR_INVALID_PARAM
;
439 skinfonts
[id
-2].id
= -1;
440 skinfonts
[id
-2].name
= filename
;
441 skinfonts
[id
-2].glyphs
= glyphs
;
447 #ifdef HAVE_LCD_BITMAP
449 static int parse_playlistview(struct skin_element
*element
,
450 struct wps_token
*token
,
451 struct wps_data
*wps_data
)
454 struct playlistviewer
*viewer
=
455 (struct playlistviewer
*)skin_buffer_alloc(sizeof(struct playlistviewer
));
457 return WPS_ERROR_INVALID_PARAM
;
458 viewer
->vp
= &curr_vp
->vp
;
459 viewer
->show_icons
= true;
460 viewer
->start_offset
= element
->params
[0].data
.number
;
461 viewer
->line
= element
->params
[1].data
.code
;
463 token
->value
.data
= (void*)viewer
;
468 #ifdef HAVE_LCD_COLOR
469 static int parse_viewport_gradient_setup(struct skin_element
*element
,
470 struct wps_token
*token
,
471 struct wps_data
*wps_data
)
474 struct gradient_config
*cfg
;
475 if (element
->params_count
< 2) /* only start and end are required */
477 cfg
= (struct gradient_config
*)skin_buffer_alloc(sizeof(struct gradient_config
));
480 if (!parse_color(curr_screen
, element
->params
[0].data
.text
, &cfg
->start
) ||
481 !parse_color(curr_screen
, element
->params
[1].data
.text
, &cfg
->end
))
483 if (element
->params_count
> 2)
485 if (!parse_color(curr_screen
, element
->params
[2].data
.text
, &cfg
->text
))
490 cfg
->text
= curr_vp
->vp
.fg_pattern
;
493 token
->value
.data
= cfg
;
498 static int parse_listitem(struct skin_element
*element
,
499 struct wps_token
*token
,
500 struct wps_data
*wps_data
)
503 struct listitem
*li
= (struct listitem
*)skin_buffer_alloc(sizeof(struct listitem
));
506 token
->value
.data
= li
;
507 if (element
->params_count
== 0)
511 li
->offset
= element
->params
[0].data
.number
;
512 if (element
->params_count
> 1)
513 li
->wrap
= strcasecmp(element
->params
[1].data
.text
, "nowrap") != 0;
520 static int parse_listitemviewport(struct skin_element
*element
,
521 struct wps_token
*token
,
522 struct wps_data
*wps_data
)
525 struct listitem_viewport_cfg
*cfg
=
526 (struct listitem_viewport_cfg
*)skin_buffer_alloc(
527 sizeof(struct listitem_viewport_cfg
));
530 cfg
->data
= wps_data
;
532 cfg
->label
= element
->params
[0].data
.text
;
535 if (!isdefault(&element
->params
[1]))
536 cfg
->width
= element
->params
[1].data
.number
;
537 if (!isdefault(&element
->params
[2]))
538 cfg
->height
= element
->params
[2].data
.number
;
539 if (element
->params_count
> 3 &&
540 !strcmp(element
->params
[3].data
.text
, "tile"))
542 token
->value
.data
= (void*)cfg
;
547 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
548 static int parse_viewporttextstyle(struct skin_element
*element
,
549 struct wps_token
*token
,
550 struct wps_data
*wps_data
)
554 char *mode
= element
->params
[0].data
.text
;
557 if (!strcmp(mode
, "invert"))
559 style
= STYLE_INVERT
;
561 else if (!strcmp(mode
, "colour") || !strcmp(mode
, "color"))
563 if (element
->params_count
< 2 ||
564 !parse_color(curr_screen
, element
->params
[1].data
.text
, &colour
))
566 style
= STYLE_COLORED
|(STYLE_COLOR_MASK
&colour
);
568 #ifdef HAVE_LCD_COLOR
569 else if (!strcmp(mode
, "gradient"))
572 if (element
->params_count
< 2)
574 else /* atoi() instead of using a number in the parser is because [si]
575 * will select the number for something which looks like a colour
576 * making the "colour" case (above) harder to parse */
577 num_lines
= atoi(element
->params
[1].data
.text
);
578 style
= STYLE_GRADIENT
|NUMLN_PACK(num_lines
)|CURLN_PACK(0);
581 else if (!strcmp(mode
, "clear"))
583 style
= STYLE_DEFAULT
;
587 token
->value
.l
= style
;
591 static int parse_viewportcolour(struct skin_element
*element
,
592 struct wps_token
*token
,
593 struct wps_data
*wps_data
)
596 struct skin_tag_parameter
*param
= element
->params
;
597 struct viewport_colour
*colour
=
598 (struct viewport_colour
*)skin_buffer_alloc(sizeof(struct viewport_colour
));
601 if (isdefault(param
))
603 colour
->colour
= get_viewport_default_colour(curr_screen
,
604 token
->type
== SKIN_TOKEN_VIEWPORT_FGCOLOUR
);
608 if (!parse_color(curr_screen
, param
->data
.text
, &colour
->colour
))
611 colour
->vp
= &curr_vp
->vp
;
612 token
->value
.data
= colour
;
613 if (element
->line
== curr_viewport_element
->line
)
615 if (token
->type
== SKIN_TOKEN_VIEWPORT_FGCOLOUR
)
617 curr_vp
->start_fgcolour
= colour
->colour
;
618 curr_vp
->vp
.fg_pattern
= colour
->colour
;
622 curr_vp
->start_bgcolour
= colour
->colour
;
623 curr_vp
->vp
.bg_pattern
= colour
->colour
;
629 static int parse_image_special(struct skin_element
*element
,
630 struct wps_token
*token
,
631 struct wps_data
*wps_data
)
633 (void)wps_data
; /* kill warning */
638 if (token
->type
== SKIN_TOKEN_IMAGE_BACKDROP
)
640 if (isdefault(&element
->params
[0]))
646 filename
= element
->params
[0].data
.text
;
647 /* format: %X(filename.bmp) or %X(d) */
648 if (!strcmp(filename
, "d"))
651 wps_data
->backdrop
= filename
;
659 #endif /* HAVE_LCD_BITMAP */
661 static int parse_setting_and_lang(struct skin_element
*element
,
662 struct wps_token
*token
,
663 struct wps_data
*wps_data
)
665 /* NOTE: both the string validations that happen in here will
666 * automatically PASS on checkwps because its too hard to get
667 * settings_list.c and english.lang built for it.
668 * If that ever changes remove the #ifndef __PCTOOL__'s here
671 char *temp
= element
->params
[0].data
.text
;
674 if (token
->type
== SKIN_TOKEN_TRANSLATEDSTRING
)
677 i
= lang_english_to_id(temp
);
679 return WPS_ERROR_INVALID_PARAM
;
685 if (find_setting_by_cfgname(temp
, &i
) == NULL
)
686 return WPS_ERROR_INVALID_PARAM
;
689 /* Store the setting number */
693 static int parse_logical_if(struct skin_element
*element
,
694 struct wps_token
*token
,
695 struct wps_data
*wps_data
)
698 char *op
= element
->params
[1].data
.text
;
699 struct logical_if
*lif
= skin_buffer_alloc(sizeof(struct logical_if
));
702 token
->value
.data
= lif
;
703 lif
->token
= element
->params
[0].data
.code
->data
;
705 if (!strncmp(op
, "=", 1))
707 else if (!strncmp(op
, "!=", 2))
708 lif
->op
= IF_NOTEQUALS
;
709 else if (!strncmp(op
, ">=", 2))
710 lif
->op
= IF_GREATERTHAN_EQ
;
711 else if (!strncmp(op
, "<=", 2))
712 lif
->op
= IF_LESSTHAN_EQ
;
713 else if (!strncmp(op
, ">", 2))
714 lif
->op
= IF_GREATERTHAN
;
715 else if (!strncmp(op
, "<", 1))
716 lif
->op
= IF_LESSTHAN
;
718 memcpy(&lif
->operand
, &element
->params
[2], sizeof(lif
->operand
));
719 if (element
->params_count
> 3)
720 lif
->num_options
= element
->params
[3].data
.number
;
722 lif
->num_options
= TOKEN_VALUE_ONLY
;
727 static int parse_timeout_tag(struct skin_element
*element
,
728 struct wps_token
*token
,
729 struct wps_data
*wps_data
)
733 if (element
->params_count
== 0)
737 case SKIN_TOKEN_SUBLINE_TIMEOUT
:
739 case SKIN_TOKEN_BUTTON_VOLUME
:
740 case SKIN_TOKEN_TRACK_STARTING
:
741 case SKIN_TOKEN_TRACK_ENDING
:
749 val
= element
->params
[0].data
.number
;
750 token
->value
.i
= val
* TIMEOUT_UNIT
;
754 static int parse_substring_tag(struct skin_element
* element
,
755 struct wps_token
*token
,
756 struct wps_data
*wps_data
)
759 struct substring
*ss
= (struct substring
*)skin_buffer_alloc(sizeof(struct substring
));
762 ss
->start
= element
->params
[0].data
.number
;
763 if (element
->params
[1].type
== DEFAULT
)
766 ss
->length
= element
->params
[1].data
.number
;
767 ss
->token
= element
->params
[2].data
.code
->data
;
768 token
->value
.data
= ss
;
772 static int parse_progressbar_tag(struct skin_element
* element
,
773 struct wps_token
*token
,
774 struct wps_data
*wps_data
)
776 #ifdef HAVE_LCD_BITMAP
777 struct progressbar
*pb
;
778 struct viewport
*vp
= &curr_vp
->vp
;
779 struct skin_tag_parameter
*param
= element
->params
;
781 char *image_filename
= NULL
;
783 if (element
->params_count
== 0 &&
784 element
->tag
->type
!= SKIN_TOKEN_PROGRESSBAR
)
785 return 0; /* nothing to do */
786 pb
= (struct progressbar
*)skin_buffer_alloc(sizeof(struct progressbar
));
788 token
->value
.data
= pb
;
791 return WPS_ERROR_INVALID_PARAM
;
793 pb
->follow_lang_direction
= follow_lang_direction
> 0;
799 pb
->invert_fill_direction
= false;
800 pb
->horizontal
= true;
802 if (element
->params_count
== 0)
805 pb
->width
= vp
->width
;
806 pb
->height
= SYSFONT_HEIGHT
-2;
807 pb
->y
= -1; /* Will be computed during the rendering */
808 pb
->type
= element
->tag
->type
;
812 /* (x, y, width, height, ...) */
813 if (!isdefault(param
))
814 pb
->x
= param
->data
.number
;
819 if (!isdefault(param
))
820 pb
->y
= param
->data
.number
;
822 pb
->y
= -1; /* computed at rendering */
825 if (!isdefault(param
))
826 pb
->width
= param
->data
.number
;
828 pb
->width
= vp
->width
- pb
->x
;
831 if (!isdefault(param
))
833 /* A zero height makes no sense - reject it */
834 if (param
->data
.number
== 0)
835 return WPS_ERROR_INVALID_PARAM
;
837 pb
->height
= param
->data
.number
;
841 if (vp
->font
> FONT_UI
)
842 pb
->height
= -1; /* calculate at display time */
846 pb
->height
= font_get(vp
->font
)->height
;
852 /* optional params, first is the image filename if it isnt recognised as a keyword */
855 if (isdefault(&element
->params
[curr_param
]))
861 pb
->horizontal
= pb
->width
> pb
->height
;
862 while (curr_param
< element
->params_count
)
865 if (!strcmp(param
->data
.text
, "invert"))
866 pb
->invert_fill_direction
= true;
867 else if (!strcmp(param
->data
.text
, "nofill"))
869 else if (!strcmp(param
->data
.text
, "nobar"))
871 else if (!strcmp(param
->data
.text
, "slider"))
873 if (curr_param
+1 < element
->params_count
)
877 pb
->slider
= skin_find_item(param
->data
.text
,
878 SKIN_FIND_IMAGE
, wps_data
);
880 else /* option needs the next param */
883 else if (!strcmp(param
->data
.text
, "image"))
885 if (curr_param
+1 < element
->params_count
)
889 image_filename
= param
->data
.text
;
892 else /* option needs the next param */
895 else if (!strcmp(param
->data
.text
, "backdrop"))
897 if (curr_param
+1 < element
->params_count
)
901 pb
->backdrop
= skin_find_item(param
->data
.text
,
902 SKIN_FIND_IMAGE
, wps_data
);
905 else /* option needs the next param */
908 else if (!strcmp(param
->data
.text
, "vertical"))
910 pb
->horizontal
= false;
911 if (isdefault(&element
->params
[3]))
912 pb
->height
= vp
->height
- pb
->y
;
914 else if (!strcmp(param
->data
.text
, "horizontal"))
915 pb
->horizontal
= true;
916 else if (curr_param
== 4)
917 image_filename
= param
->data
.text
;
924 pb
->image
= skin_find_item(image_filename
, SKIN_FIND_IMAGE
, wps_data
);
925 if (!pb
->image
) /* load later */
927 struct gui_img
* img
= (struct gui_img
*)skin_buffer_alloc(sizeof(struct gui_img
));
929 return WPS_ERROR_INVALID_PARAM
;
930 /* save a pointer to the filename */
931 img
->bm
.data
= (char*)image_filename
;
932 img
->label
= image_filename
;
935 img
->num_subimages
= 1;
936 img
->always_display
= false;
938 img
->using_preloaded_icons
= false;
939 img
->buflib_handle
= -1;
940 img
->vp
= &curr_vp
->vp
;
941 struct skin_token_list
*item
=
942 (struct skin_token_list
*)new_skin_token_list_item(NULL
, img
);
944 return WPS_ERROR_INVALID_PARAM
;
945 add_to_ll_chain(&wps_data
->images
, item
);
950 if (token
->type
== SKIN_TOKEN_VOLUME
)
951 token
->type
= SKIN_TOKEN_VOLUMEBAR
;
952 else if (token
->type
== SKIN_TOKEN_BATTERY_PERCENT
)
953 token
->type
= SKIN_TOKEN_BATTERY_PERCENTBAR
;
954 else if (token
->type
== SKIN_TOKEN_TUNER_RSSI
)
955 token
->type
= SKIN_TOKEN_TUNER_RSSI_BAR
;
956 else if (token
->type
== SKIN_TOKEN_PEAKMETER_LEFT
)
957 token
->type
= SKIN_TOKEN_PEAKMETER_LEFTBAR
;
958 else if (token
->type
== SKIN_TOKEN_PEAKMETER_RIGHT
)
959 token
->type
= SKIN_TOKEN_PEAKMETER_RIGHTBAR
;
960 else if (token
->type
== SKIN_TOKEN_LIST_NEEDS_SCROLLBAR
)
961 token
->type
= SKIN_TOKEN_LIST_SCROLLBAR
;
962 pb
->type
= token
->type
;
968 if (token
->type
== SKIN_TOKEN_PROGRESSBAR
||
969 token
->type
== SKIN_TOKEN_PLAYER_PROGRESSBAR
)
971 wps_data
->full_line_progressbar
=
972 token
->type
== SKIN_TOKEN_PLAYER_PROGRESSBAR
;
980 static int parse_albumart_load(struct skin_element
* element
,
981 struct wps_token
*token
,
982 struct wps_data
*wps_data
)
984 struct dim dimensions
;
986 bool swap_for_rtl
= lang_is_rtl() && follow_lang_direction
;
987 struct skin_albumart
*aa
=
988 (struct skin_albumart
*)skin_buffer_alloc(sizeof(struct skin_albumart
));
989 (void)token
; /* silence warning */
993 /* reset albumart info in wps */
996 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
997 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
999 aa
->x
= element
->params
[0].data
.number
;
1000 aa
->y
= element
->params
[1].data
.number
;
1001 aa
->width
= element
->params
[2].data
.number
;
1002 aa
->height
= element
->params
[3].data
.number
;
1004 aa
->vp
= &curr_vp
->vp
;
1005 aa
->draw_handle
= -1;
1007 /* if we got here, we parsed everything ok .. ! */
1010 else if (aa
->width
> LCD_WIDTH
)
1011 aa
->width
= LCD_WIDTH
;
1015 else if (aa
->height
> LCD_HEIGHT
)
1016 aa
->height
= LCD_HEIGHT
;
1019 aa
->x
= LCD_WIDTH
- (aa
->x
+ aa
->width
);
1021 aa
->state
= WPS_ALBUMART_LOAD
;
1022 wps_data
->albumart
= aa
;
1024 dimensions
.width
= aa
->width
;
1025 dimensions
.height
= aa
->height
;
1027 albumart_slot
= playback_claim_aa_slot(&dimensions
);
1029 if (0 <= albumart_slot
)
1030 wps_data
->playback_aa_slot
= albumart_slot
;
1032 if (element
->params_count
> 4 && !isdefault(&element
->params
[4]))
1034 switch (*element
->params
[4].data
.text
)
1039 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1041 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1045 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
;
1050 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1052 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1056 if (element
->params_count
> 5 && !isdefault(&element
->params
[5]))
1058 switch (*element
->params
[5].data
.text
)
1062 aa
->yalign
= WPS_ALBUMART_ALIGN_TOP
;
1066 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
;
1070 aa
->yalign
= WPS_ALBUMART_ALIGN_BOTTOM
;
1077 #endif /* HAVE_ALBUMART */
1078 #ifdef HAVE_SKIN_VARIABLES
1079 static struct skin_var
* find_or_add_var(const char* label
,
1080 struct wps_data
*data
)
1082 struct skin_var
* ret
= skin_find_item(label
, SKIN_VARIABLE
, data
);
1085 ret
= (struct skin_var
*)skin_buffer_alloc(sizeof(struct skin_var
));
1090 ret
->last_changed
= 0xffff;
1091 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, ret
);
1094 add_to_ll_chain(&data
->skinvars
, item
);
1098 static int parse_skinvar( struct skin_element
*element
,
1099 struct wps_token
*token
,
1100 struct wps_data
*wps_data
)
1102 const char* label
= element
->params
[0].data
.text
;
1103 struct skin_var
* var
= find_or_add_var(label
, wps_data
);
1105 return WPS_ERROR_INVALID_PARAM
;
1106 switch (token
->type
)
1108 case SKIN_TOKEN_VAR_GETVAL
:
1109 token
->value
.data
= var
;
1111 case SKIN_TOKEN_VAR_SET
:
1113 struct skin_var_changer
*data
=
1114 (struct skin_var_changer
*)skin_buffer_alloc(
1115 sizeof(struct skin_var_changer
));
1117 return WPS_ERROR_INVALID_PARAM
;
1119 data
->newval
= element
->params
[2].data
.number
;
1121 if (!strcmp(element
->params
[1].data
.text
, "set"))
1122 data
->direct
= true;
1123 else if (!strcmp(element
->params
[1].data
.text
, "inc"))
1125 data
->direct
= false;
1127 else if (!strcmp(element
->params
[1].data
.text
, "dec"))
1129 data
->direct
= false;
1132 if (element
->params_count
> 3)
1133 data
->max
= element
->params
[3].data
.number
;
1134 token
->value
.data
= data
;
1137 case SKIN_TOKEN_VAR_TIMEOUT
:
1139 struct skin_var_lastchange
*data
=
1140 (struct skin_var_lastchange
*)skin_buffer_alloc(
1141 sizeof(struct skin_var_lastchange
));
1143 return WPS_ERROR_INVALID_PARAM
;
1146 if (element
->params_count
> 1)
1147 data
->timeout
= element
->params
[1].data
.number
;
1148 data
->timeout
*= TIMEOUT_UNIT
;
1149 token
->value
.data
= data
;
1152 default: /* kill the warning */
1157 #endif /* HAVE_SKIN_VARIABLES */
1158 #ifdef HAVE_TOUCHSCREEN
1159 static int parse_lasttouch(struct skin_element
*element
,
1160 struct wps_token
*token
,
1161 struct wps_data
*wps_data
)
1163 struct touchregion_lastpress
*data
=
1164 (struct touchregion_lastpress
*)skin_buffer_alloc(
1165 sizeof(struct touchregion_lastpress
));
1168 return WPS_ERROR_INVALID_PARAM
;
1169 data
->region
= NULL
;
1172 for (i
=0; i
<element
->params_count
; i
++)
1174 if (element
->params
[i
].type
== STRING
)
1175 data
->region
= skin_find_item(element
->params
[i
].data
.text
,
1176 SKIN_FIND_TOUCHREGION
, wps_data
);
1177 else if (element
->params
[i
].type
== INTEGER
||
1178 element
->params
[i
].type
== DECIMAL
)
1179 data
->timeout
= element
->params
[i
].data
.number
;
1182 data
->timeout
*= TIMEOUT_UNIT
;
1183 token
->value
.data
= data
;
1187 struct touchaction
{const char* s
; int action
;};
1188 static const struct touchaction touchactions
[] = {
1189 /* generic actions, convert to screen actions on use */
1190 {"none", ACTION_TOUCHSCREEN
}, {"lock", ACTION_TOUCH_SOFTLOCK
},
1191 {"prev", ACTION_STD_PREV
}, {"next", ACTION_STD_NEXT
},
1192 {"rwd", ACTION_STD_PREVREPEAT
}, {"ffwd", ACTION_STD_NEXTREPEAT
},
1193 {"hotkey", ACTION_STD_HOTKEY
}, {"select", ACTION_STD_OK
},
1194 {"menu", ACTION_STD_MENU
}, {"cancel", ACTION_STD_CANCEL
},
1195 {"contextmenu", ACTION_STD_CONTEXT
},{"quickscreen", ACTION_STD_QUICKSCREEN
},
1197 /* list/tree actions */
1198 { "resumeplayback", ACTION_TREE_WPS
}, /* returns to previous music, WPS/FM */
1199 /* not really WPS specific, but no equivilant ACTION_STD_* */
1200 {"voldown", ACTION_WPS_VOLDOWN
}, {"volup", ACTION_WPS_VOLUP
},
1201 {"mute", ACTION_TOUCH_MUTE
},
1203 /* generic settings changers */
1204 {"setting_inc", ACTION_SETTINGS_INC
}, {"setting_dec", ACTION_SETTINGS_DEC
},
1205 {"setting_set", ACTION_SETTINGS_SET
},
1207 /* WPS specific actions */
1208 {"wps_prev", ACTION_WPS_SKIPPREV
}, {"wps_next", ACTION_WPS_SKIPNEXT
},
1209 {"browse", ACTION_WPS_BROWSE
},
1210 {"play", ACTION_WPS_PLAY
}, {"stop", ACTION_WPS_STOP
},
1211 {"shuffle", ACTION_TOUCH_SHUFFLE
}, {"repmode", ACTION_TOUCH_REPMODE
},
1212 {"pitch", ACTION_WPS_PITCHSCREEN
}, {"playlist", ACTION_WPS_VIEW_PLAYLIST
},
1215 /* FM screen actions */
1216 /* Also allow browse, play, stop from WPS codes */
1217 {"mode", ACTION_FM_MODE
}, {"record", ACTION_FM_RECORD
},
1218 {"presets", ACTION_FM_PRESET
},
1222 static int touchregion_setup_setting(struct skin_element
*element
, int param_no
,
1223 struct touchregion
*region
)
1227 char *name
= element
->params
[p
++].data
.text
;
1230 region
->setting_data
.setting
= find_setting_by_cfgname(name
, &j
);
1231 if (region
->setting_data
.setting
== NULL
)
1232 return WPS_ERROR_INVALID_PARAM
;
1234 if (region
->action
== ACTION_SETTINGS_SET
)
1238 struct touchsetting
*setting
=
1239 ®ion
->setting_data
;
1240 if (element
->params_count
< p
+1)
1243 text
= element
->params
[p
++].data
.text
;
1244 switch (settings
[j
].flags
&F_T_MASK
)
1247 setting
->value
.text
= text
;
1251 if (settings
[j
].cfg_vals
== NULL
)
1253 setting
->value
.number
= atoi(text
);
1255 else if (cfg_string_to_int(j
, &temp
, text
))
1257 if (settings
[j
].flags
&F_TABLE_SETTING
)
1258 setting
->value
.number
=
1259 settings
[j
].table_setting
->values
[temp
];
1261 setting
->value
.number
= temp
;
1267 if (cfg_string_to_int(j
, &temp
, text
))
1269 setting
->value
.number
= temp
;
1279 #endif /* __PCTOOL__ */
1283 static int parse_touchregion(struct skin_element
*element
,
1284 struct wps_token
*token
,
1285 struct wps_data
*wps_data
)
1290 struct touchregion
*region
= NULL
;
1292 const char pb_string
[] = "progressbar";
1293 const char vol_string
[] = "volume";
1295 /* format: %T([label,], x,y,width,height,action[, ...])
1296 * if action starts with & the area must be held to happen
1300 region
= (struct touchregion
*)skin_buffer_alloc(sizeof(struct touchregion
));
1302 return WPS_ERROR_INVALID_PARAM
;
1304 /* should probably do some bounds checking here with the viewport... but later */
1305 region
->action
= ACTION_NONE
;
1307 if (element
->params
[0].type
== STRING
)
1309 region
->label
= element
->params
[0].data
.text
;
1311 /* "[SI]III[SI]|SS" is the param list. There MUST be 4 numbers
1312 * followed by at least one string. Verify that here */
1313 if (element
->params_count
< 6 ||
1314 element
->params
[4].type
!= INTEGER
)
1315 return WPS_ERROR_INVALID_PARAM
;
1319 region
->label
= NULL
;
1323 region
->x
= element
->params
[p
++].data
.number
;
1324 region
->y
= element
->params
[p
++].data
.number
;
1325 region
->width
= element
->params
[p
++].data
.number
;
1326 region
->height
= element
->params
[p
++].data
.number
;
1327 region
->wvp
= curr_vp
;
1328 region
->armed
= false;
1329 region
->reverse_bar
= false;
1331 region
->last_press
= 0xffff;
1332 region
->press_length
= PRESS
;
1333 region
->allow_while_locked
= false;
1334 action
= element
->params
[p
++].data
.text
;
1336 /* figure out the action */
1337 if(!strcmp(pb_string
, action
))
1338 region
->action
= ACTION_TOUCH_SCROLLBAR
;
1339 else if(!strcmp(vol_string
, action
))
1340 region
->action
= ACTION_TOUCH_VOLUME
;
1343 imax
= ARRAYLEN(touchactions
);
1344 for (i
= 0; i
< imax
; i
++)
1346 /* try to match with one of our touchregion screens */
1347 if (!strcmp(touchactions
[i
].s
, action
))
1349 region
->action
= touchactions
[i
].action
;
1350 if (region
->action
== ACTION_SETTINGS_INC
||
1351 region
->action
== ACTION_SETTINGS_DEC
||
1352 region
->action
== ACTION_SETTINGS_SET
)
1355 if (element
->params_count
< p
+1)
1356 return WPS_ERROR_INVALID_PARAM
;
1357 val
= touchregion_setup_setting(element
, p
, region
);
1359 return WPS_ERROR_INVALID_PARAM
;
1365 if (region
->action
== ACTION_NONE
)
1366 return WPS_ERROR_INVALID_PARAM
;
1368 while (p
< element
->params_count
)
1370 char* param
= element
->params
[p
++].data
.text
;
1371 if (!strcmp(param
, "allow_while_locked"))
1372 region
->allow_while_locked
= true;
1373 else if (!strcmp(param
, "reverse_bar"))
1374 region
->reverse_bar
= true;
1375 else if (!strcmp(param
, "repeat_press"))
1376 region
->press_length
= REPEAT
;
1377 else if (!strcmp(param
, "long_press"))
1378 region
->press_length
= LONG_PRESS
;
1380 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, region
);
1382 return WPS_ERROR_INVALID_PARAM
;
1383 add_to_ll_chain(&wps_data
->touchregions
, item
);
1385 if (region
->action
== ACTION_TOUCH_MUTE
)
1387 region
->value
= global_settings
.volume
;
1395 static bool check_feature_tag(const int type
)
1399 case SKIN_TOKEN_RTC_PRESENT
:
1405 case SKIN_TOKEN_HAVE_RECORDING
:
1406 #ifdef HAVE_RECORDING
1411 case SKIN_TOKEN_HAVE_TUNER
:
1413 if (radio_hardware_present())
1417 case SKIN_TOKEN_HAVE_TOUCH
:
1418 #ifdef HAVE_TOUCHSCREEN
1425 case SKIN_TOKEN_HAVE_RDS
:
1430 #endif /* HAVE_RDS_CAP */
1431 #endif /* CONFIG_TUNER */
1432 default: /* not a tag we care about, just don't skip */
1437 /* This is used to free any buflib allocations before the rest of
1438 * wps_data is reset.
1439 * The call to this in settings_apply_skins() is the last chance to do
1440 * any core_free()'s before wps_data is trashed and those handles lost
1442 void skin_data_free_buflib_allocs(struct wps_data
*wps_data
)
1445 #ifdef HAVE_LCD_BITMAP
1447 struct skin_token_list
*list
= wps_data
->images
;
1450 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
1451 if (img
->buflib_handle
> 0)
1452 core_free(img
->buflib_handle
);
1455 if (wps_data
->font_ids
!= NULL
)
1457 while (wps_data
->font_count
> 0)
1458 font_unload(wps_data
->font_ids
[--wps_data
->font_count
]);
1465 * initial setup of wps_data; does reset everything
1466 * except fields which need to survive, i.e.
1467 * Also called if the load fails
1469 static void skin_data_reset(struct wps_data
*wps_data
)
1471 skin_data_free_buflib_allocs(wps_data
);
1472 #ifdef HAVE_LCD_BITMAP
1473 wps_data
->images
= NULL
;
1475 wps_data
->tree
= NULL
;
1476 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1477 if (wps_data
->backdrop_id
>= 0)
1478 skin_backdrop_unload(wps_data
->backdrop_id
);
1479 wps_data
->backdrop
= NULL
;
1481 #ifdef HAVE_TOUCHSCREEN
1482 wps_data
->touchregions
= NULL
;
1484 #ifdef HAVE_SKIN_VARIABLES
1485 wps_data
->skinvars
= NULL
;
1487 #ifdef HAVE_ALBUMART
1488 wps_data
->albumart
= NULL
;
1489 if (wps_data
->playback_aa_slot
>= 0)
1491 playback_release_aa_slot(wps_data
->playback_aa_slot
);
1492 wps_data
->playback_aa_slot
= -1;
1496 #ifdef HAVE_LCD_BITMAP
1497 wps_data
->peak_meter_enabled
= false;
1498 wps_data
->wps_sb_tag
= false;
1499 wps_data
->show_sb_on_wps
= false;
1500 #else /* HAVE_LCD_CHARCELLS */
1503 for (i
= 0; i
< 8; i
++)
1505 wps_data
->wps_progress_pat
[i
] = 0;
1507 wps_data
->full_line_progressbar
= false;
1509 wps_data
->wps_loaded
= false;
1512 #ifdef HAVE_LCD_BITMAP
1514 static int currently_loading_handle
= -1;
1515 static int buflib_move_callback(int handle
, void* current
, void* new)
1519 if (handle
== currently_loading_handle
)
1520 return BUFLIB_CB_CANNOT_MOVE
;
1521 return BUFLIB_CB_OK
;
1523 static struct buflib_callbacks buflib_ops
= {buflib_move_callback
, NULL
};
1524 static void lock_handle(int handle
)
1526 currently_loading_handle
= handle
;
1528 static void unlock_handle(void)
1530 currently_loading_handle
= -1;
1534 static int load_skin_bmp(struct wps_data
*wps_data
, struct bitmap
*bitmap
, char* bmpdir
)
1536 (void)wps_data
; /* only needed for remote targets */
1537 char img_path
[MAX_PATH
];
1540 get_image_filename(bitmap
->data
, bmpdir
,
1541 img_path
, sizeof(img_path
));
1543 /* load the image */
1545 #ifdef HAVE_REMOTE_LCD
1546 if (curr_screen
== SCREEN_REMOTE
)
1547 format
= FORMAT_ANY
|FORMAT_REMOTE
;
1550 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
1552 fd
= open(img_path
, O_RDONLY
);
1555 DEBUGF("Couldn't open %s\n", img_path
);
1559 size_t buf_size
= read_bmp_fd(fd
, bitmap
, 0,
1560 format
|FORMAT_RETURN_SIZE
, NULL
);
1561 handle
= core_alloc_ex(bitmap
->data
, buf_size
, &buflib_ops
);
1565 DEBUGF("Not enough skin buffer: need %zd more.\n",
1566 buf_size
- skin_buffer_freespace());
1571 lseek(fd
, 0, SEEK_SET
);
1572 lock_handle(handle
);
1573 bitmap
->data
= core_get_data(handle
);
1574 int ret
= read_bmp_fd(fd
, bitmap
, buf_size
, format
, NULL
);
1575 bitmap
->data
= NULL
; /* do this to force a crash later if the
1576 caller doesnt call core_get_data() */
1585 /* Abort if we can't load an image */
1586 DEBUGF("Couldn't load '%s'\n", img_path
);
1590 #else /* !__PCTOOL__ */
1596 static bool load_skin_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
1598 struct skin_token_list
*list
;
1599 bool retval
= true; /* return false if a single image failed to load */
1601 /* regular images */
1602 list
= wps_data
->images
;
1605 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
1608 if (img
->using_preloaded_icons
)
1611 list
->token
->type
= SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
;
1615 img
->buflib_handle
= load_skin_bmp(wps_data
, &img
->bm
, bmpdir
);
1616 img
->loaded
= img
->buflib_handle
>= 0;
1618 img
->subimage_height
= img
->bm
.height
/ img
->num_subimages
;
1626 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1627 wps_data
->backdrop_id
= skin_backdrop_assign(wps_data
->backdrop
, bmpdir
, curr_screen
);
1628 #endif /* has backdrop support */
1632 static bool skin_load_fonts(struct wps_data
*data
)
1634 /* don't spit out after the first failue to aid debugging */
1635 int id_array
[MAXUSERFONTS
];
1637 bool success
= true;
1638 struct skin_element
*vp_list
;
1640 /* walk though each viewport and assign its font */
1641 for(vp_list
= data
->tree
; vp_list
; vp_list
= vp_list
->next
)
1643 /* first, find the viewports that have a non-sys/ui-font font */
1644 struct skin_viewport
*skin_vp
=
1645 (struct skin_viewport
*)vp_list
->data
;
1646 struct viewport
*vp
= &skin_vp
->vp
;
1648 font_id
= skin_vp
->parsed_fontid
;
1650 { /* the usual case -> built-in fonts */
1651 vp
->font
= global_status
.font_id
[curr_screen
];
1654 else if (font_id
<= 0)
1656 vp
->font
= FONT_SYSFIXED
;
1660 /* now find the corresponding skin_font */
1661 struct skin_font
*font
= &skinfonts
[font_id
-2];
1666 DEBUGF("font %d not specified\n", font_id
);
1672 /* load the font - will handle loading the same font again if
1673 * multiple viewports use the same */
1676 char path
[MAX_PATH
];
1677 snprintf(path
, sizeof path
, FONT_DIR
"/%s", font
->name
);
1678 if (skinfonts
[font_id
-2].glyphs
> 0)
1680 font
->id
= font_load_ex(path
,
1681 font_glyphs_to_bufsize(path
, skinfonts
[font_id
-2].glyphs
));
1684 font
->id
= font_load(path
);
1685 //printf("[%d] %s -> %d\n",font_id, font->name, font->id);
1686 id_array
[font_count
++] = font
->id
;
1691 DEBUGF("Unable to load font %d: '%s.fnt'\n",
1692 font_id
, font
->name
);
1693 font
->name
= NULL
; /* to stop trying to load it again if we fail */
1698 /* finally, assign the font_id to the viewport */
1699 vp
->font
= font
->id
;
1701 data
->font_ids
= skin_buffer_alloc(font_count
* sizeof(int));
1702 if (!success
|| data
->font_ids
== NULL
)
1704 while (font_count
> 0)
1705 font_unload(id_array
[--font_count
]);
1706 data
->font_ids
= NULL
;
1709 memcpy(data
->font_ids
, id_array
, sizeof(int)*font_count
);
1710 data
->font_count
= font_count
;
1714 #endif /* HAVE_LCD_BITMAP */
1715 static int convert_viewport(struct wps_data
*data
, struct skin_element
* element
)
1717 struct skin_viewport
*skin_vp
=
1718 (struct skin_viewport
*)skin_buffer_alloc(sizeof(struct skin_viewport
));
1719 struct screen
*display
= &screens
[curr_screen
];
1722 return CALLBACK_ERROR
;
1724 skin_vp
->hidden_flags
= 0;
1725 skin_vp
->label
= NULL
;
1726 skin_vp
->is_infovp
= false;
1727 skin_vp
->parsed_fontid
= 1;
1728 element
->data
= skin_vp
;
1730 curr_viewport_element
= element
;
1732 viewport_set_defaults(&skin_vp
->vp
, curr_screen
);
1734 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1735 skin_vp
->start_fgcolour
= skin_vp
->vp
.fg_pattern
;
1736 skin_vp
->start_bgcolour
= skin_vp
->vp
.bg_pattern
;
1738 #ifdef HAVE_LCD_COLOR
1739 skin_vp
->start_gradient
.start
= skin_vp
->vp
.lss_pattern
;
1740 skin_vp
->start_gradient
.end
= skin_vp
->vp
.lse_pattern
;
1741 skin_vp
->start_gradient
.text
= skin_vp
->vp
.lst_pattern
;
1745 struct skin_tag_parameter
*param
= element
->params
;
1746 if (element
->params_count
== 0) /* default viewport */
1748 if (!data
->tree
) /* first viewport in the skin */
1749 data
->tree
= element
;
1750 skin_vp
->label
= VP_DEFAULT_LABEL
;
1754 if (element
->params_count
== 6)
1756 if (element
->tag
->type
== SKIN_TOKEN_UIVIEWPORT_LOAD
)
1758 skin_vp
->is_infovp
= true;
1759 if (isdefault(param
))
1761 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
1762 skin_vp
->label
= VP_DEFAULT_LABEL
;
1766 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
1767 skin_vp
->label
= param
->data
.text
;
1772 skin_vp
->hidden_flags
= VP_DRAW_HIDEABLE
|VP_DRAW_HIDDEN
;
1773 skin_vp
->label
= param
->data
.text
;
1778 if (!isdefault(param
))
1780 skin_vp
->vp
.x
= param
->data
.number
;
1781 if (param
->data
.number
< 0)
1782 skin_vp
->vp
.x
+= display
->lcdwidth
;
1786 if (!isdefault(param
))
1788 skin_vp
->vp
.y
= param
->data
.number
;
1789 if (param
->data
.number
< 0)
1790 skin_vp
->vp
.y
+= display
->lcdheight
;
1794 if (!isdefault(param
))
1796 skin_vp
->vp
.width
= param
->data
.number
;
1797 if (param
->data
.number
< 0)
1798 skin_vp
->vp
.width
= (skin_vp
->vp
.width
+ display
->lcdwidth
) - skin_vp
->vp
.x
;
1802 skin_vp
->vp
.width
= display
->lcdwidth
- skin_vp
->vp
.x
;
1806 if (!isdefault(param
))
1808 skin_vp
->vp
.height
= param
->data
.number
;
1809 if (param
->data
.number
< 0)
1810 skin_vp
->vp
.height
= (skin_vp
->vp
.height
+ display
->lcdheight
) - skin_vp
->vp
.y
;
1814 skin_vp
->vp
.height
= display
->lcdheight
- skin_vp
->vp
.y
;
1817 #ifdef HAVE_LCD_BITMAP
1819 if (!isdefault(param
))
1820 skin_vp
->parsed_fontid
= param
->data
.number
;
1822 if ((unsigned) skin_vp
->vp
.x
>= (unsigned) display
->lcdwidth
||
1823 skin_vp
->vp
.width
+ skin_vp
->vp
.x
> display
->lcdwidth
||
1824 (unsigned) skin_vp
->vp
.y
>= (unsigned) display
->lcdheight
||
1825 skin_vp
->vp
.height
+ skin_vp
->vp
.y
> display
->lcdheight
)
1826 return CALLBACK_ERROR
;
1831 static int skin_element_callback(struct skin_element
* element
, void* data
)
1833 struct wps_data
*wps_data
= (struct wps_data
*)data
;
1834 struct wps_token
*token
;
1835 parse_function function
= NULL
;
1837 switch (element
->type
)
1839 /* IMPORTANT: element params are shared, so copy them if needed
1840 * or use then NOW, dont presume they have a long lifespan
1844 token
= (struct wps_token
*)skin_buffer_alloc(sizeof(struct wps_token
));
1845 memset(token
, 0, sizeof(*token
));
1846 token
->type
= element
->tag
->type
;
1848 if (element
->tag
->flags
&SKIN_RTC_REFRESH
)
1851 curr_line
->update_mode
|= SKIN_REFRESH_DYNAMIC
;
1853 curr_line
->update_mode
|= SKIN_REFRESH_STATIC
;
1857 curr_line
->update_mode
|= element
->tag
->flags
&SKIN_REFRESH_ALL
;
1859 element
->data
= token
;
1861 /* Some tags need special handling for the tag, so add them here */
1862 switch (token
->type
)
1864 case SKIN_TOKEN_ALIGN_LANGDIRECTION
:
1865 follow_lang_direction
= 2;
1867 case SKIN_TOKEN_LOGICAL_IF
:
1868 function
= parse_logical_if
;
1870 case SKIN_TOKEN_SUBSTRING
:
1871 function
= parse_substring_tag
;
1873 case SKIN_TOKEN_PROGRESSBAR
:
1874 case SKIN_TOKEN_VOLUME
:
1875 case SKIN_TOKEN_BATTERY_PERCENT
:
1876 case SKIN_TOKEN_PLAYER_PROGRESSBAR
:
1877 case SKIN_TOKEN_PEAKMETER_LEFT
:
1878 case SKIN_TOKEN_PEAKMETER_RIGHT
:
1879 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR
:
1880 #ifdef HAVE_RADIO_RSSI
1881 case SKIN_TOKEN_TUNER_RSSI
:
1883 function
= parse_progressbar_tag
;
1885 case SKIN_TOKEN_SUBLINE_TIMEOUT
:
1886 case SKIN_TOKEN_BUTTON_VOLUME
:
1887 case SKIN_TOKEN_TRACK_STARTING
:
1888 case SKIN_TOKEN_TRACK_ENDING
:
1889 function
= parse_timeout_tag
;
1891 #ifdef HAVE_LCD_BITMAP
1892 case SKIN_TOKEN_LIST_ITEM_TEXT
:
1893 case SKIN_TOKEN_LIST_ITEM_ICON
:
1894 function
= parse_listitem
;
1896 case SKIN_TOKEN_DISABLE_THEME
:
1897 case SKIN_TOKEN_ENABLE_THEME
:
1898 case SKIN_TOKEN_DRAW_INBUILTBAR
:
1899 function
= parse_statusbar_tags
;
1901 case SKIN_TOKEN_LIST_TITLE_TEXT
:
1903 sb_skin_has_title(curr_screen
);
1907 case SKIN_TOKEN_FILE_DIRECTORY
:
1908 token
->value
.i
= element
->params
[0].data
.number
;
1910 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1911 case SKIN_TOKEN_VIEWPORT_FGCOLOUR
:
1912 case SKIN_TOKEN_VIEWPORT_BGCOLOUR
:
1913 function
= parse_viewportcolour
;
1915 case SKIN_TOKEN_IMAGE_BACKDROP
:
1916 function
= parse_image_special
;
1918 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE
:
1919 function
= parse_viewporttextstyle
;
1922 #ifdef HAVE_LCD_COLOR
1923 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP
:
1924 function
= parse_viewport_gradient_setup
;
1927 case SKIN_TOKEN_TRANSLATEDSTRING
:
1928 case SKIN_TOKEN_SETTING
:
1929 function
= parse_setting_and_lang
;
1931 #ifdef HAVE_LCD_BITMAP
1932 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
1933 function
= parse_playlistview
;
1935 case SKIN_TOKEN_LOAD_FONT
:
1936 function
= parse_font_load
;
1938 case SKIN_TOKEN_VIEWPORT_ENABLE
:
1939 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
1940 token
->value
.data
= element
->params
[0].data
.text
;
1942 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
1943 function
= parse_image_display
;
1945 case SKIN_TOKEN_IMAGE_PRELOAD
:
1946 case SKIN_TOKEN_IMAGE_DISPLAY
:
1947 function
= parse_image_load
;
1949 case SKIN_TOKEN_LIST_ITEM_CFG
:
1950 function
= parse_listitemviewport
;
1953 #ifdef HAVE_TOUCHSCREEN
1954 case SKIN_TOKEN_TOUCHREGION
:
1955 function
= parse_touchregion
;
1957 case SKIN_TOKEN_LASTTOUCH
:
1958 function
= parse_lasttouch
;
1961 #ifdef HAVE_ALBUMART
1962 case SKIN_TOKEN_ALBUMART_DISPLAY
:
1963 if (wps_data
->albumart
)
1964 wps_data
->albumart
->vp
= &curr_vp
->vp
;
1966 case SKIN_TOKEN_ALBUMART_LOAD
:
1967 function
= parse_albumart_load
;
1970 #ifdef HAVE_SKIN_VARIABLES
1971 case SKIN_TOKEN_VAR_SET
:
1972 case SKIN_TOKEN_VAR_GETVAL
:
1973 case SKIN_TOKEN_VAR_TIMEOUT
:
1974 function
= parse_skinvar
;
1982 if (function(element
, token
, wps_data
) < 0)
1983 return CALLBACK_ERROR
;
1985 /* tags that start with 'F', 'I' or 'D' are for the next file */
1986 if ( *(element
->tag
->name
) == 'I' || *(element
->tag
->name
) == 'F' ||
1987 *(element
->tag
->name
) == 'D')
1989 if (follow_lang_direction
> 0 )
1990 follow_lang_direction
--;
1994 return convert_viewport(wps_data
, element
);
1998 (struct line
*)skin_buffer_alloc(sizeof(struct line
));
1999 line
->update_mode
= SKIN_REFRESH_STATIC
;
2001 element
->data
= line
;
2004 case LINE_ALTERNATOR
:
2006 struct line_alternator
*alternator
=
2007 (struct line_alternator
*)skin_buffer_alloc(sizeof(struct line_alternator
));
2008 alternator
->current_line
= 0;
2010 alternator
->next_change_tick
= current_tick
;
2012 element
->data
= alternator
;
2017 struct conditional
*conditional
=
2018 (struct conditional
*)skin_buffer_alloc(sizeof(struct conditional
));
2019 conditional
->last_value
= -1;
2020 conditional
->token
= element
->data
;
2021 element
->data
= conditional
;
2022 if (!check_feature_tag(element
->tag
->type
))
2024 return FEATURE_NOT_AVAILABLE
;
2029 curr_line
->update_mode
|= SKIN_REFRESH_STATIC
;
2037 /* to setup up the wps-data from a format-buffer (isfile = false)
2038 from a (wps-)file (isfile = true)*/
2039 bool skin_data_load(enum screen_type screen
, struct wps_data
*wps_data
,
2040 const char *buf
, bool isfile
)
2042 char *wps_buffer
= NULL
;
2043 if (!wps_data
|| !buf
)
2045 #ifdef HAVE_ALBUMART
2047 struct mp3entry
*curtrack
;
2049 struct skin_albumart old_aa
= {.state
= WPS_ALBUMART_NONE
};
2050 if (wps_data
->albumart
)
2052 old_aa
.state
= wps_data
->albumart
->state
;
2053 old_aa
.height
= wps_data
->albumart
->height
;
2054 old_aa
.width
= wps_data
->albumart
->width
;
2057 #ifdef HAVE_LCD_BITMAP
2059 for (i
=0;i
<MAXUSERFONTS
;i
++)
2061 skinfonts
[i
].id
= -1;
2062 skinfonts
[i
].name
= NULL
;
2065 #ifdef DEBUG_SKIN_ENGINE
2066 if (isfile
&& debug_wps
)
2068 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf
);
2073 skin_data_reset(wps_data
);
2074 wps_data
->wps_loaded
= false;
2075 curr_screen
= screen
;
2078 curr_viewport_element
= NULL
;
2082 int fd
= open_utf8(buf
, O_RDONLY
);
2087 /* get buffer space from the plugin buffer */
2088 size_t buffersize
= 0;
2089 wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
2094 /* copy the file's content to the buffer for parsing,
2095 ensuring that every line ends with a newline char. */
2096 unsigned int start
= 0;
2097 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
2099 start
+= strlen(wps_buffer
+ start
);
2100 if (start
< buffersize
- 1)
2102 wps_buffer
[start
++] = '\n';
2103 wps_buffer
[start
] = 0;
2112 wps_buffer
= (char*)buf
;
2114 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
2115 wps_data
->backdrop
= "-";
2116 wps_data
->backdrop_id
= -1;
2118 /* parse the skin source */
2120 skin_buffer_save_position();
2122 wps_data
->tree
= skin_parse(wps_buffer
, skin_element_callback
, wps_data
);
2123 if (!wps_data
->tree
) {
2124 skin_data_reset(wps_data
);
2126 skin_buffer_restore_position();
2131 #ifdef HAVE_LCD_BITMAP
2132 char bmpdir
[MAX_PATH
];
2135 /* get the bitmap dir */
2136 char *dot
= strrchr(buf
, '.');
2137 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
2141 snprintf(bmpdir
, MAX_PATH
, "%s", BACKDROP_DIR
);
2143 /* load the bitmaps that were found by the parsing */
2144 if (!load_skin_bitmaps(wps_data
, bmpdir
) ||
2145 !skin_load_fonts(wps_data
))
2147 skin_data_reset(wps_data
);
2149 skin_buffer_restore_position();
2154 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2155 status
= audio_status();
2156 if (status
& AUDIO_STATUS_PLAY
)
2158 struct skin_albumart
*aa
= wps_data
->albumart
;
2159 if (aa
&& ((aa
->state
&& !old_aa
.state
) ||
2161 (((old_aa
.height
!= aa
->height
) ||
2162 (old_aa
.width
!= aa
->width
))))))
2164 curtrack
= audio_current_track();
2165 offset
= curtrack
->offset
;
2167 if (!(status
& AUDIO_STATUS_PAUSE
))
2172 wps_data
->wps_loaded
= true;
2173 #ifdef DEBUG_SKIN_ENGINE
2174 // if (isfile && debug_wps)
2175 // debug_skin_usage();