9 segment bitmap drawing:
[maemo-rb.git] / apps / gui / skin_engine / skin_parser.c
blob94adaf31160aeb78dcc5534b550a8836b67cded6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include "config.h"
27 #ifndef __PCTOOL__
28 #include "core_alloc.h"
29 #endif
30 #include "file.h"
31 #include "misc.h"
32 #include "plugin.h"
33 #include "viewport.h"
35 #include "skin_buffer.h"
36 #include "skin_debug.h"
37 #include "skin_parser.h"
38 #include "tag_table.h"
40 #ifdef __PCTOOL__
41 #ifdef WPSEDITOR
42 #include "proxy.h"
43 #include "sysfont.h"
44 #else
45 #include "action.h"
46 #include "checkwps.h"
47 #include "audio.h"
48 #define lang_is_rtl() (false)
49 #define DEBUGF printf
50 #endif /*WPSEDITOR*/
51 #else
52 #include "debug.h"
53 #include "language.h"
54 #endif /*__PCTOOL__*/
56 #include <ctype.h>
57 #include <stdbool.h>
58 #include "font.h"
60 #include "wps_internals.h"
61 #include "skin_engine.h"
62 #include "settings.h"
63 #include "settings_list.h"
64 #if CONFIG_TUNER
65 #include "radio.h"
66 #include "tuner.h"
67 #endif
69 #ifdef HAVE_LCD_BITMAP
70 #include "bmp.h"
71 #endif
73 #ifdef HAVE_ALBUMART
74 #include "playback.h"
75 #endif
77 #include "backdrop.h"
78 #include "statusbar-skinned.h"
80 #define WPS_ERROR_INVALID_PARAM -1
82 static char* skin_buffer = NULL;
83 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
84 static char *backdrop_filename;
85 #endif
87 static bool isdefault(struct skin_tag_parameter *param)
89 return param->type == DEFAULT;
92 static inline char*
93 get_param_text(struct skin_element *element, int param_number)
95 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
96 return SKINOFFSETTOPTR(skin_buffer, params[param_number].data.text);
99 static inline struct skin_element*
100 get_param_code(struct skin_element *element, int param_number)
102 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
103 return SKINOFFSETTOPTR(skin_buffer, params[param_number].data.code);
106 static inline struct skin_tag_parameter*
107 get_param(struct skin_element *element, int param_number)
109 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
110 return &params[param_number];
113 /* which screen are we parsing for? */
114 static enum screen_type curr_screen;
116 /* the current viewport */
117 static struct skin_element *curr_viewport_element;
118 static struct skin_viewport *curr_vp;
119 static struct skin_element *first_viewport;
121 static struct line *curr_line;
123 static int follow_lang_direction = 0;
125 typedef int (*parse_function)(struct skin_element *element,
126 struct wps_token *token,
127 struct wps_data *wps_data);
129 #ifdef HAVE_LCD_BITMAP
130 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
131 * chains require the order to be kept.
133 static void add_to_ll_chain(OFFSETTYPE(struct skin_token_list *) *listoffset,
134 struct skin_token_list *item)
136 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, *listoffset);
137 if (list == NULL)
139 *listoffset = PTRTOSKINOFFSET(skin_buffer, item);
141 else
143 while (SKINOFFSETTOPTR(skin_buffer, list->next))
144 list = SKINOFFSETTOPTR(skin_buffer, list->next);
145 list->next = PTRTOSKINOFFSET(skin_buffer, item);
149 #endif
152 void *skin_find_item(const char *label, enum skin_find_what what,
153 struct wps_data *data)
155 const char *itemlabel = NULL;
156 char *databuf = get_skin_buffer(data);
157 union {
158 struct skin_token_list *linkedlist;
159 struct skin_element *vplist;
160 } list = {NULL};
161 bool isvplist = false;
162 void *ret = NULL;
163 if (!databuf)
164 databuf = skin_buffer;
165 switch (what)
167 case SKIN_FIND_UIVP:
168 case SKIN_FIND_VP:
169 list.vplist = SKINOFFSETTOPTR(databuf, data->tree);
170 isvplist = true;
171 break;
172 #ifdef HAVE_LCD_BITMAP
173 case SKIN_FIND_IMAGE:
174 list.linkedlist = SKINOFFSETTOPTR(databuf, data->images);
175 break;
176 #endif
177 #ifdef HAVE_TOUCHSCREEN
178 case SKIN_FIND_TOUCHREGION:
179 list.linkedlist = SKINOFFSETTOPTR(databuf, data->touchregions);
180 break;
181 #endif
182 #ifdef HAVE_SKIN_VARIABLES
183 case SKIN_VARIABLE:
184 list.linkedlist = SKINOFFSETTOPTR(databuf, data->skinvars);
185 break;
186 #endif
189 while (list.linkedlist)
191 bool skip = false;
192 #ifdef HAVE_LCD_BITMAP
193 struct wps_token *token = NULL;
194 if (!isvplist)
195 token = SKINOFFSETTOPTR(databuf, list.linkedlist->token);
196 #endif
197 switch (what)
199 case SKIN_FIND_UIVP:
200 case SKIN_FIND_VP:
201 ret = SKINOFFSETTOPTR(databuf, list.vplist->data);
202 if (((struct skin_viewport *)ret)->label == VP_DEFAULT_LABEL)
203 itemlabel = VP_DEFAULT_LABEL_STRING;
204 else
205 itemlabel = SKINOFFSETTOPTR(databuf, ((struct skin_viewport *)ret)->label);
206 skip = !(((struct skin_viewport *)ret)->is_infovp ==
207 (what==SKIN_FIND_UIVP));
208 break;
209 #ifdef HAVE_LCD_BITMAP
210 case SKIN_FIND_IMAGE:
211 ret = SKINOFFSETTOPTR(databuf, token->value.data);
212 itemlabel = SKINOFFSETTOPTR(databuf, ((struct gui_img *)ret)->label);
213 break;
214 #endif
215 #ifdef HAVE_TOUCHSCREEN
216 case SKIN_FIND_TOUCHREGION:
217 ret = SKINOFFSETTOPTR(databuf, token->value.data);
218 itemlabel = SKINOFFSETTOPTR(databuf, ((struct touchregion *)ret)->label);
219 break;
220 #endif
221 #ifdef HAVE_SKIN_VARIABLES
222 case SKIN_VARIABLE:
223 ret = SKINOFFSETTOPTR(databuf, token->value.data);
224 itemlabel = SKINOFFSETTOPTR(databuf, ((struct skin_var *)ret)->label);
225 break;
226 #endif
229 if (!skip && itemlabel && !strcmp(itemlabel, label))
231 return ret;
234 if (isvplist)
235 list.vplist = SKINOFFSETTOPTR(databuf, list.vplist->next);
236 else
237 list.linkedlist = SKINOFFSETTOPTR(databuf, list.linkedlist->next);
239 return NULL;
242 #ifdef HAVE_LCD_BITMAP
244 /* create and init a new wpsll item.
245 * passing NULL to token will alloc a new one.
246 * You should only pass NULL for the token when the token type (table above)
247 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
249 static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
250 void* token_data)
252 struct skin_token_list *llitem = skin_buffer_alloc(sizeof(*llitem));
253 if (!token)
254 token = skin_buffer_alloc(sizeof(*token));
255 if (!llitem || !token)
256 return NULL;
257 llitem->next = PTRTOSKINOFFSET(skin_buffer, NULL);
258 llitem->token = PTRTOSKINOFFSET(skin_buffer, token);
259 if (token_data)
260 token->value.data = PTRTOSKINOFFSET(skin_buffer, token_data);
261 return llitem;
264 static int parse_statusbar_tags(struct skin_element* element,
265 struct wps_token *token,
266 struct wps_data *wps_data)
268 (void)element;
269 if (token->type == SKIN_TOKEN_DRAW_INBUILTBAR)
271 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)&curr_vp->vp);
273 else
275 struct skin_viewport *default_vp = SKINOFFSETTOPTR(skin_buffer, first_viewport->data);
276 if (first_viewport->params_count == 0)
278 wps_data->wps_sb_tag = true;
279 wps_data->show_sb_on_wps = (token->type == SKIN_TOKEN_ENABLE_THEME);
281 if (wps_data->show_sb_on_wps)
283 viewport_set_defaults(&default_vp->vp, curr_screen);
285 else
287 viewport_set_fullscreen(&default_vp->vp, curr_screen);
289 #ifdef HAVE_REMOTE_LCD
290 /* This parser requires viewports which will use the settings font to
291 * have font == 1, but the above viewport_set() calls set font to
292 * the current real font id. So force 1 here it will be set correctly
293 * at the end
295 default_vp->vp.font = 1;
296 #endif
298 return 0;
301 static int get_image_id(int c)
303 if(c >= 'a' && c <= 'z')
304 return c - 'a';
305 else if(c >= 'A' && c <= 'Z')
306 return c - 'A' + 26;
307 else
308 return -1;
311 void get_image_filename(const char *start, const char* bmpdir,
312 char *buf, int buf_size)
314 snprintf(buf, buf_size, "%s/%s", bmpdir, start);
317 static int parse_image_display(struct skin_element *element,
318 struct wps_token *token,
319 struct wps_data *wps_data)
321 char *label = get_param_text(element, 0);
322 char sublabel = '\0';
323 int subimage;
324 struct gui_img *img;
325 struct image_display *id = skin_buffer_alloc(sizeof(*id));
327 if (element->params_count == 1 && strlen(label) <= 2)
329 /* backwards compatability. Allow %xd(Aa) to still work */
330 sublabel = label[1];
331 label[1] = '\0';
333 /* sanity check */
334 img = skin_find_item(label, SKIN_FIND_IMAGE, wps_data);
335 if (!img || !id)
337 return WPS_ERROR_INVALID_PARAM;
339 id->label = img->label;
340 id->offset = 0;
341 id->token = PTRTOSKINOFFSET(skin_buffer, NULL);
342 if (img->using_preloaded_icons)
344 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
347 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT)
348 img->is_9_segment = true;
350 if (element->params_count > 1)
352 if (get_param(element, 1)->type == CODE)
353 id->token = get_param_code(element, 1)->data;
354 /* specify a number. 1 being the first subimage (i.e top) NOT 0 */
355 else if (get_param(element, 1)->type == INTEGER)
356 id->subimage = get_param(element, 1)->data.number - 1;
357 if (element->params_count > 2)
358 id->offset = get_param(element, 2)->data.number;
360 else
362 if ((subimage = get_image_id(sublabel)) != -1)
364 if (subimage >= img->num_subimages)
365 return WPS_ERROR_INVALID_PARAM;
366 id->subimage = subimage;
367 } else {
368 id->subimage = 0;
371 token->value.data = PTRTOSKINOFFSET(skin_buffer, id);
372 return 0;
375 static int parse_image_load(struct skin_element *element,
376 struct wps_token *token,
377 struct wps_data *wps_data)
379 const char* filename;
380 const char* id;
381 int x = 0,y = 0, subimages = 1;
382 struct gui_img *img;
384 /* format: %x(n,filename.bmp[,x,y])
385 or %xl(n,filename.bmp[,x,y])
386 or %xl(n,filename.bmp[,x,y,num_subimages])
389 id = get_param_text(element, 0);
390 filename = get_param_text(element, 1);
391 /* x,y,num_subimages handling:
392 * If all 3 are left out use sane defaults.
393 * If there are 2 params it must be x,y
394 * if there is only 1 param it must be the num_subimages
396 if (element->params_count == 3)
397 subimages = get_param(element, 2)->data.number;
398 else if (element->params_count > 3)
400 x = get_param(element, 2)->data.number;
401 y = get_param(element, 3)->data.number;
402 if (element->params_count == 5)
403 subimages = get_param(element, 4)->data.number;
405 /* check the image number and load state */
406 if(skin_find_item(id, SKIN_FIND_IMAGE, wps_data))
408 /* Invalid image ID */
409 return WPS_ERROR_INVALID_PARAM;
411 img = skin_buffer_alloc(sizeof(*img));
412 if (!img)
413 return WPS_ERROR_INVALID_PARAM;
414 /* save a pointer to the filename */
415 img->bm.data = (char*)filename;
416 img->label = PTRTOSKINOFFSET(skin_buffer, (void*)id);
417 img->x = x;
418 img->y = y;
419 img->num_subimages = subimages;
420 img->display = -1;
421 img->using_preloaded_icons = false;
422 img->buflib_handle = -1;
423 img->is_9_segment = false;
425 /* save current viewport */
426 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
428 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
429 token->value.data = PTRTOSKINOFFSET(skin_buffer, img);
431 if (!strcmp(img->bm.data, "__list_icons__"))
433 img->num_subimages = Icon_Last_Themeable;
434 img->using_preloaded_icons = true;
437 struct skin_token_list *item = new_skin_token_list_item(NULL, img);
438 if (!item)
439 return WPS_ERROR_INVALID_PARAM;
440 add_to_ll_chain(&wps_data->images, item);
442 return 0;
444 struct skin_font {
445 int id; /* the id from font_load */
446 char *name; /* filename without path and extension */
447 int glyphs; /* how many glyphs to reserve room for */
449 static struct skin_font skinfonts[MAXUSERFONTS];
450 static int parse_font_load(struct skin_element *element,
451 struct wps_token *token,
452 struct wps_data *wps_data)
454 (void)wps_data; (void)token;
455 int id = get_param(element, 0)->data.number;
456 char *filename = get_param_text(element, 1);
457 int glyphs;
458 char *ptr;
460 if(element->params_count > 2)
461 glyphs = get_param(element, 2)->data.number;
462 else
463 glyphs = global_settings.glyphs_to_cache;
464 if (id < 2)
466 DEBUGF("font id must be >= 2 (%d)\n", id);
467 return 1;
469 #if defined(DEBUG) || defined(SIMULATOR)
470 if (skinfonts[id-2].name != NULL)
472 DEBUGF("font id %d already being used\n", id);
474 #endif
475 /* make sure the filename contains .fnt,
476 * we dont actually use it, but require it anyway */
477 ptr = strchr(filename, '.');
478 if (!ptr || strncmp(ptr, ".fnt", 4))
479 return WPS_ERROR_INVALID_PARAM;
480 skinfonts[id-2].id = -1;
481 skinfonts[id-2].name = filename;
482 skinfonts[id-2].glyphs = glyphs;
484 return 0;
488 #ifdef HAVE_LCD_BITMAP
490 static int parse_playlistview(struct skin_element *element,
491 struct wps_token *token,
492 struct wps_data *wps_data)
494 (void)wps_data;
495 struct playlistviewer *viewer = skin_buffer_alloc(sizeof(*viewer));
496 if (!viewer)
497 return WPS_ERROR_INVALID_PARAM;
498 viewer->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
499 viewer->show_icons = true;
500 viewer->start_offset = get_param(element, 0)->data.number;
501 viewer->line = PTRTOSKINOFFSET(skin_buffer, get_param_code(element, 1));
503 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)viewer);
505 return 0;
507 #endif
508 #ifdef HAVE_LCD_COLOR
509 static int parse_viewport_gradient_setup(struct skin_element *element,
510 struct wps_token *token,
511 struct wps_data *wps_data)
513 (void)wps_data;
514 struct gradient_config *cfg;
515 if (element->params_count < 2) /* only start and end are required */
516 return 1;
517 cfg = skin_buffer_alloc(sizeof(*cfg));
518 if (!cfg)
519 return 1;
520 if (!parse_color(curr_screen, get_param_text(element, 0), &cfg->start) ||
521 !parse_color(curr_screen, get_param_text(element, 1), &cfg->end))
522 return 1;
523 if (element->params_count > 2)
525 if (!parse_color(curr_screen, get_param_text(element, 2), &cfg->text))
526 return 1;
528 else
530 cfg->text = curr_vp->vp.fg_pattern;
533 token->value.data = PTRTOSKINOFFSET(skin_buffer, cfg);
534 return 0;
536 #endif
538 static int parse_listitem(struct skin_element *element,
539 struct wps_token *token,
540 struct wps_data *wps_data)
542 (void)wps_data;
543 struct listitem *li = skin_buffer_alloc(sizeof(*li));
544 if (!li)
545 return 1;
546 token->value.data = PTRTOSKINOFFSET(skin_buffer, li);
547 if (element->params_count == 0)
548 li->offset = 0;
549 else
551 li->offset = get_param(element, 0)->data.number;
552 if (element->params_count > 1)
553 li->wrap = strcasecmp(get_param_text(element, 1), "nowrap") != 0;
554 else
555 li->wrap = true;
557 return 0;
560 static int parse_listitemviewport(struct skin_element *element,
561 struct wps_token *token,
562 struct wps_data *wps_data)
564 #ifndef __PCTOOL__
565 struct listitem_viewport_cfg *cfg = skin_buffer_alloc(sizeof(*cfg));
566 if (!cfg)
567 return -1;
568 cfg->data = wps_data;
569 cfg->tile = false;
570 cfg->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
571 cfg->width = -1;
572 cfg->height = -1;
573 if (!isdefault(get_param(element, 1)))
574 cfg->width = get_param(element, 1)->data.number;
575 if (!isdefault(get_param(element, 2)))
576 cfg->height = get_param(element, 2)->data.number;
577 if (element->params_count > 3 &&
578 !strcmp(get_param_text(element, 3), "tile"))
579 cfg->tile = true;
580 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)cfg);
581 #endif
582 return 0;
585 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
586 static int parse_viewporttextstyle(struct skin_element *element,
587 struct wps_token *token,
588 struct wps_data *wps_data)
590 (void)wps_data;
591 int style;
592 char *mode = get_param_text(element, 0);
593 unsigned colour;
595 if (!strcmp(mode, "invert"))
597 style = STYLE_INVERT;
599 else if (!strcmp(mode, "colour") || !strcmp(mode, "color"))
601 if (element->params_count < 2 ||
602 !parse_color(curr_screen, get_param_text(element, 1), &colour))
603 return 1;
604 style = STYLE_COLORED|(STYLE_COLOR_MASK&colour);
606 #ifdef HAVE_LCD_COLOR
607 else if (!strcmp(mode, "gradient"))
609 int num_lines;
610 if (element->params_count < 2)
611 num_lines = 1;
612 else /* atoi() instead of using a number in the parser is because [si]
613 * will select the number for something which looks like a colour
614 * making the "colour" case (above) harder to parse */
615 num_lines = atoi(get_param_text(element, 1));
616 style = STYLE_GRADIENT|NUMLN_PACK(num_lines)|CURLN_PACK(0);
618 #endif
619 else if (!strcmp(mode, "clear"))
621 style = STYLE_DEFAULT;
623 else
624 return 1;
625 token->value.l = style;
626 return 0;
629 static int parse_drawrectangle( struct skin_element *element,
630 struct wps_token *token,
631 struct wps_data *wps_data)
633 (void)wps_data;
634 struct draw_rectangle *rect = skin_buffer_alloc(sizeof(*rect));
636 if (!rect)
637 return -1;
639 rect->x = get_param(element, 0)->data.number;
640 rect->y = get_param(element, 1)->data.number;
642 if (isdefault(get_param(element, 2)))
643 rect->width = curr_vp->vp.width - rect->x;
644 else
645 rect->width = get_param(element, 2)->data.number;
647 if (isdefault(get_param(element, 3)))
648 rect->height = curr_vp->vp.height - rect->y;
649 else
650 rect->height = get_param(element, 3)->data.number;
652 rect->start_colour = curr_vp->vp.fg_pattern;
653 rect->end_colour = curr_vp->vp.fg_pattern;
655 if (element->params_count > 4)
657 if (!parse_color(curr_screen, get_param_text(element, 4),
658 &rect->start_colour))
659 return -1;
660 rect->end_colour = rect->start_colour;
662 if (element->params_count > 5)
664 if (!parse_color(curr_screen, get_param_text(element, 5),
665 &rect->end_colour))
666 return -1;
668 token->value.data = PTRTOSKINOFFSET(skin_buffer, rect);
670 return 0;
673 static int parse_viewportcolour(struct skin_element *element,
674 struct wps_token *token,
675 struct wps_data *wps_data)
677 (void)wps_data;
678 struct skin_tag_parameter *param = get_param(element, 0);
679 struct viewport_colour *colour = skin_buffer_alloc(sizeof(*colour));
680 if (!colour)
681 return -1;
682 if (isdefault(param))
684 colour->colour = get_viewport_default_colour(curr_screen,
685 token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
687 else
689 if (!parse_color(curr_screen, SKINOFFSETTOPTR(skin_buffer, param->data.text),
690 &colour->colour))
691 return -1;
693 colour->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
694 token->value.data = PTRTOSKINOFFSET(skin_buffer, colour);
695 if (element->line == curr_viewport_element->line)
697 if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
699 curr_vp->start_fgcolour = colour->colour;
700 curr_vp->vp.fg_pattern = colour->colour;
702 else
704 curr_vp->start_bgcolour = colour->colour;
705 curr_vp->vp.bg_pattern = colour->colour;
708 return 0;
711 static int parse_image_special(struct skin_element *element,
712 struct wps_token *token,
713 struct wps_data *wps_data)
715 (void)wps_data; /* kill warning */
716 (void)token;
718 #if LCD_DEPTH > 1
719 char *filename;
720 if (token->type == SKIN_TOKEN_IMAGE_BACKDROP)
722 if (isdefault(get_param(element, 0)))
724 filename = "-";
726 else
728 filename = get_param_text(element, 0);
729 /* format: %X(filename.bmp) or %X(d) */
730 if (!strcmp(filename, "d"))
731 filename = NULL;
733 backdrop_filename = filename;
735 #endif
737 return 0;
739 #endif
741 #endif /* HAVE_LCD_BITMAP */
743 static int parse_progressbar_tag(struct skin_element* element,
744 struct wps_token *token,
745 struct wps_data *wps_data);
747 static int parse_setting_and_lang(struct skin_element *element,
748 struct wps_token *token,
749 struct wps_data *wps_data)
751 /* NOTE: both the string validations that happen in here will
752 * automatically PASS on checkwps because its too hard to get
753 * settings_list.c and english.lang built for it.
754 * If that ever changes remove the #ifndef __PCTOOL__'s here
756 (void)wps_data;
757 char *temp = get_param_text(element, 0);
758 int i;
760 if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
762 #ifndef __PCTOOL__
763 i = lang_english_to_id(temp);
764 if (i < 0)
765 return WPS_ERROR_INVALID_PARAM;
766 #endif
768 else if (element->params_count > 1)
770 if (element->params_count > 4)
771 return parse_progressbar_tag(element, token, wps_data);
772 else
773 return WPS_ERROR_INVALID_PARAM;
775 else
777 #ifndef __PCTOOL__
778 if (find_setting_by_cfgname(temp, &i) == NULL)
779 return WPS_ERROR_INVALID_PARAM;
780 #endif
782 /* Store the setting number */
783 token->value.i = i;
784 return 0;
787 static int parse_logical_andor(struct skin_element *element,
788 struct wps_token *token,
789 struct wps_data *wps_data)
791 (void)wps_data;
792 token->value.data = PTRTOSKINOFFSET(skin_buffer, element);
793 return 0;
796 static int parse_logical_if(struct skin_element *element,
797 struct wps_token *token,
798 struct wps_data *wps_data)
800 (void)wps_data;
801 char *op = get_param_text(element, 1);
802 struct logical_if *lif = skin_buffer_alloc(sizeof(*lif));
803 if (!lif)
804 return -1;
805 token->value.data = PTRTOSKINOFFSET(skin_buffer, lif);
806 lif->token = get_param_code(element, 0)->data;
808 if (!strncmp(op, "=", 1))
809 lif->op = IF_EQUALS;
810 else if (!strncmp(op, "!=", 2))
811 lif->op = IF_NOTEQUALS;
812 else if (!strncmp(op, ">=", 2))
813 lif->op = IF_GREATERTHAN_EQ;
814 else if (!strncmp(op, "<=", 2))
815 lif->op = IF_LESSTHAN_EQ;
816 else if (!strncmp(op, ">", 2))
817 lif->op = IF_GREATERTHAN;
818 else if (!strncmp(op, "<", 1))
819 lif->op = IF_LESSTHAN;
821 memcpy(&lif->operand, get_param(element, 2), sizeof(lif->operand));
822 if (element->params_count > 3)
823 lif->num_options = get_param(element, 3)->data.number;
824 else
825 lif->num_options = TOKEN_VALUE_ONLY;
826 return 0;
830 static int parse_timeout_tag(struct skin_element *element,
831 struct wps_token *token,
832 struct wps_data *wps_data)
834 (void)wps_data;
835 int val = 0;
836 if (element->params_count == 0)
838 switch (token->type)
840 case SKIN_TOKEN_SUBLINE_TIMEOUT:
841 return -1;
842 case SKIN_TOKEN_BUTTON_VOLUME:
843 case SKIN_TOKEN_TRACK_STARTING:
844 case SKIN_TOKEN_TRACK_ENDING:
845 val = 10;
846 break;
847 default:
848 break;
851 else
852 val = get_param(element, 0)->data.number;
853 token->value.i = val * TIMEOUT_UNIT;
854 return 0;
857 static int parse_substring_tag(struct skin_element* element,
858 struct wps_token *token,
859 struct wps_data *wps_data)
861 (void)wps_data;
862 struct substring *ss = skin_buffer_alloc(sizeof(*ss));
863 if (!ss)
864 return 1;
865 ss->start = get_param(element, 0)->data.number;
866 if (get_param(element, 1)->type == DEFAULT)
867 ss->length = -1;
868 else
869 ss->length = get_param(element, 1)->data.number;
870 ss->token = get_param_code(element, 2)->data;
871 if (element->params_count > 3)
872 ss->expect_number = !strcmp(get_param_text(element, 3), "number");
873 else
874 ss->expect_number = false;
875 token->value.data = PTRTOSKINOFFSET(skin_buffer, ss);
876 return 0;
879 static int parse_progressbar_tag(struct skin_element* element,
880 struct wps_token *token,
881 struct wps_data *wps_data)
883 #ifdef HAVE_LCD_BITMAP
884 struct progressbar *pb;
885 struct viewport *vp = &curr_vp->vp;
886 struct skin_tag_parameter *param = get_param(element, 0);
887 int curr_param = 0;
888 char *image_filename = NULL;
889 #ifdef HAVE_TOUCHSCREEN
890 bool suppress_touchregion = false;
891 #endif
893 if (element->params_count == 0 &&
894 element->tag->type != SKIN_TOKEN_PROGRESSBAR)
895 return 0; /* nothing to do */
896 pb = skin_buffer_alloc(sizeof(*pb));
898 token->value.data = PTRTOSKINOFFSET(skin_buffer, pb);
900 if (!pb)
901 return WPS_ERROR_INVALID_PARAM;
902 pb->vp = PTRTOSKINOFFSET(skin_buffer, vp);
903 pb->follow_lang_direction = follow_lang_direction > 0;
904 pb->nofill = false;
905 pb->nobar = false;
906 pb->image = PTRTOSKINOFFSET(skin_buffer, NULL);
907 pb->slider = PTRTOSKINOFFSET(skin_buffer, NULL);
908 pb->backdrop = PTRTOSKINOFFSET(skin_buffer, NULL);
909 pb->setting_id = -1;
910 pb->invert_fill_direction = false;
911 pb->horizontal = true;
913 if (element->params_count == 0)
915 pb->x = 0;
916 pb->width = vp->width;
917 pb->height = SYSFONT_HEIGHT-2;
918 pb->y = -1; /* Will be computed during the rendering */
919 pb->type = element->tag->type;
920 return 0;
923 /* (x, y, width, height, ...) */
924 if (!isdefault(param))
925 pb->x = param->data.number;
926 else
927 pb->x = 0;
928 param++;
930 if (!isdefault(param))
931 pb->y = param->data.number;
932 else
933 pb->y = -1; /* computed at rendering */
934 param++;
936 if (!isdefault(param))
937 pb->width = param->data.number;
938 else
939 pb->width = vp->width - pb->x;
940 param++;
942 if (!isdefault(param))
944 /* A zero height makes no sense - reject it */
945 if (param->data.number == 0)
946 return WPS_ERROR_INVALID_PARAM;
948 pb->height = param->data.number;
950 else
952 if (vp->font > FONT_UI)
953 pb->height = -1; /* calculate at display time */
954 else
956 #ifndef __PCTOOL__
957 pb->height = font_get(vp->font)->height;
958 #else
959 pb->height = 8;
960 #endif
963 /* optional params, first is the image filename if it isnt recognised as a keyword */
965 curr_param = 4;
966 if (isdefault(get_param(element, curr_param)))
968 param++;
969 curr_param++;
972 pb->horizontal = pb->width > pb->height;
973 while (curr_param < element->params_count)
975 char* text;
976 param++;
977 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
978 if (!strcmp(text, "invert"))
979 pb->invert_fill_direction = true;
980 else if (!strcmp(text, "nofill"))
981 pb->nofill = true;
982 else if (!strcmp(text, "nobar"))
983 pb->nobar = true;
984 else if (!strcmp(text, "slider"))
986 if (curr_param+1 < element->params_count)
988 curr_param++;
989 param++;
990 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
991 pb->slider = PTRTOSKINOFFSET(skin_buffer,
992 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
994 else /* option needs the next param */
995 return -1;
997 else if (!strcmp(text, "image"))
999 if (curr_param+1 < element->params_count)
1001 curr_param++;
1002 param++;
1003 image_filename = SKINOFFSETTOPTR(skin_buffer, param->data.text);
1005 else /* option needs the next param */
1006 return -1;
1008 else if (!strcmp(text, "backdrop"))
1010 if (curr_param+1 < element->params_count)
1012 curr_param++;
1013 param++;
1014 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
1015 pb->backdrop = PTRTOSKINOFFSET(skin_buffer,
1016 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
1019 else /* option needs the next param */
1020 return -1;
1022 else if (!strcmp(text, "vertical"))
1024 pb->horizontal = false;
1025 if (isdefault(get_param(element, 3)))
1026 pb->height = vp->height - pb->y;
1028 else if (!strcmp(text, "horizontal"))
1029 pb->horizontal = true;
1030 #ifdef HAVE_TOUCHSCREEN
1031 else if (!strcmp(text, "notouch"))
1032 suppress_touchregion = true;
1033 #endif
1034 else if (token->type == SKIN_TOKEN_SETTING && !strcmp(text, "setting"))
1036 if (curr_param+1 < element->params_count)
1038 curr_param++;
1039 param++;
1040 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
1041 #ifndef __PCTOOL__
1042 if (find_setting_by_cfgname(text, &pb->setting_id) == NULL)
1043 return WPS_ERROR_INVALID_PARAM;
1044 #endif
1047 else if (curr_param == 4)
1048 image_filename = text;
1050 curr_param++;
1053 if (image_filename)
1055 pb->image = PTRTOSKINOFFSET(skin_buffer,
1056 skin_find_item(image_filename, SKIN_FIND_IMAGE, wps_data));
1057 if (!SKINOFFSETTOPTR(skin_buffer, pb->image)) /* load later */
1059 struct gui_img *img = skin_buffer_alloc(sizeof(*img));
1060 if (!img)
1061 return WPS_ERROR_INVALID_PARAM;
1062 /* save a pointer to the filename */
1063 img->bm.data = (char*)image_filename;
1064 img->label = PTRTOSKINOFFSET(skin_buffer, image_filename);
1065 img->x = 0;
1066 img->y = 0;
1067 img->num_subimages = 1;
1068 img->display = -1;
1069 img->using_preloaded_icons = false;
1070 img->buflib_handle = -1;
1071 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1072 struct skin_token_list *item = new_skin_token_list_item(NULL, img);
1073 if (!item)
1074 return WPS_ERROR_INVALID_PARAM;
1075 add_to_ll_chain(&wps_data->images, item);
1076 pb->image = PTRTOSKINOFFSET(skin_buffer, img);
1080 if (token->type == SKIN_TOKEN_VOLUME)
1081 token->type = SKIN_TOKEN_VOLUMEBAR;
1082 else if (token->type == SKIN_TOKEN_BATTERY_PERCENT)
1083 token->type = SKIN_TOKEN_BATTERY_PERCENTBAR;
1084 else if (token->type == SKIN_TOKEN_TUNER_RSSI)
1085 token->type = SKIN_TOKEN_TUNER_RSSI_BAR;
1086 else if (token->type == SKIN_TOKEN_PEAKMETER_LEFT)
1087 token->type = SKIN_TOKEN_PEAKMETER_LEFTBAR;
1088 else if (token->type == SKIN_TOKEN_PEAKMETER_RIGHT)
1089 token->type = SKIN_TOKEN_PEAKMETER_RIGHTBAR;
1090 else if (token->type == SKIN_TOKEN_LIST_NEEDS_SCROLLBAR)
1091 token->type = SKIN_TOKEN_LIST_SCROLLBAR;
1092 else if (token->type == SKIN_TOKEN_SETTING)
1093 token->type = SKIN_TOKEN_SETTINGBAR;
1094 pb->type = token->type;
1096 #ifdef HAVE_TOUCHSCREEN
1097 if (!suppress_touchregion &&
1098 (token->type == SKIN_TOKEN_VOLUMEBAR ||
1099 token->type == SKIN_TOKEN_PROGRESSBAR ||
1100 token->type == SKIN_TOKEN_SETTINGBAR))
1102 struct touchregion *region = skin_buffer_alloc(sizeof(*region));
1103 struct skin_token_list *item;
1104 int wpad, hpad;
1106 if (!region)
1107 return 0;
1109 if (token->type == SKIN_TOKEN_VOLUMEBAR)
1110 region->action = ACTION_TOUCH_VOLUME;
1111 else if (token->type == SKIN_TOKEN_SETTINGBAR)
1112 region->action = ACTION_TOUCH_SETTING;
1113 else
1114 region->action = ACTION_TOUCH_SCROLLBAR;
1116 /* try to add some extra space on either end to make pressing the
1117 * full bar easier. ~5% on either side
1119 wpad = pb->width * 5 / 100;
1120 if (wpad > 10)
1121 wpad = 10;
1122 hpad = pb->height * 5 / 100;
1123 if (hpad > 10)
1124 hpad = 10;
1126 region->x = pb->x - wpad;
1127 if (region->x < 0)
1128 region->x = 0;
1129 region->width = pb->width + 2 * wpad;
1130 if (region->x + region->width > curr_vp->vp.x + curr_vp->vp.width)
1131 region->width = curr_vp->vp.x + curr_vp->vp.width - region->x;
1133 region->y = pb->y - hpad;
1134 if (region->y < 0)
1135 region->y = 0;
1136 region->height = pb->height + 2 * hpad;
1137 if (region->y + region->height > curr_vp->vp.y + curr_vp->vp.height)
1138 region->height = curr_vp->vp.y + curr_vp->vp.height - region->y;
1140 region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp);
1141 region->reverse_bar = false;
1142 region->allow_while_locked = false;
1143 region->press_length = PRESS;
1144 region->last_press = 0xffff;
1145 region->armed = false;
1146 region->bar = PTRTOSKINOFFSET(skin_buffer, pb);
1148 item = new_skin_token_list_item(NULL, region);
1149 if (!item)
1150 return WPS_ERROR_INVALID_PARAM;
1151 add_to_ll_chain(&wps_data->touchregions, item);
1153 #endif
1155 return 0;
1157 #else
1158 (void)element;
1159 if (token->type == SKIN_TOKEN_PROGRESSBAR ||
1160 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR)
1162 wps_data->full_line_progressbar =
1163 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR;
1165 return 0;
1167 #endif
1170 #ifdef HAVE_ALBUMART
1171 static int parse_albumart_load(struct skin_element* element,
1172 struct wps_token *token,
1173 struct wps_data *wps_data)
1175 struct dim dimensions;
1176 int albumart_slot;
1177 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction;
1178 struct skin_albumart *aa = skin_buffer_alloc(sizeof(*aa));
1179 (void)token; /* silence warning */
1180 if (!aa)
1181 return -1;
1183 /* reset albumart info in wps */
1184 aa->width = -1;
1185 aa->height = -1;
1186 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1187 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1189 aa->x = get_param(element, 0)->data.number;
1190 aa->y = get_param(element, 1)->data.number;
1191 aa->width = get_param(element, 2)->data.number;
1192 aa->height = get_param(element, 3)->data.number;
1194 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1195 aa->draw_handle = -1;
1197 /* if we got here, we parsed everything ok .. ! */
1198 if (aa->width < 0)
1199 aa->width = 0;
1200 else if (aa->width > LCD_WIDTH)
1201 aa->width = LCD_WIDTH;
1203 if (aa->height < 0)
1204 aa->height = 0;
1205 else if (aa->height > LCD_HEIGHT)
1206 aa->height = LCD_HEIGHT;
1208 if (swap_for_rtl)
1209 aa->x = LCD_WIDTH - (aa->x + aa->width);
1211 aa->state = WPS_ALBUMART_LOAD;
1212 wps_data->albumart = PTRTOSKINOFFSET(skin_buffer, aa);
1214 dimensions.width = aa->width;
1215 dimensions.height = aa->height;
1217 albumart_slot = playback_claim_aa_slot(&dimensions);
1219 if (0 <= albumart_slot)
1220 wps_data->playback_aa_slot = albumart_slot;
1222 if (element->params_count > 4 && !isdefault(get_param(element, 4)))
1224 switch (*get_param_text(element, 4))
1226 case 'l':
1227 case 'L':
1228 if (swap_for_rtl)
1229 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1230 else
1231 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1232 break;
1233 case 'c':
1234 case 'C':
1235 aa->xalign = WPS_ALBUMART_ALIGN_CENTER;
1236 break;
1237 case 'r':
1238 case 'R':
1239 if (swap_for_rtl)
1240 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1241 else
1242 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1243 break;
1246 if (element->params_count > 5 && !isdefault(get_param(element, 5)))
1248 switch (*get_param_text(element, 5))
1250 case 't':
1251 case 'T':
1252 aa->yalign = WPS_ALBUMART_ALIGN_TOP;
1253 break;
1254 case 'c':
1255 case 'C':
1256 aa->yalign = WPS_ALBUMART_ALIGN_CENTER;
1257 break;
1258 case 'b':
1259 case 'B':
1260 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM;
1261 break;
1264 return 0;
1267 #endif /* HAVE_ALBUMART */
1268 #ifdef HAVE_SKIN_VARIABLES
1269 static struct skin_var* find_or_add_var(const char* label,
1270 struct wps_data *data)
1272 struct skin_var* ret = skin_find_item(label, SKIN_VARIABLE, data);
1273 if (ret)
1274 return ret;
1276 ret = skin_buffer_alloc(sizeof(*ret));
1277 if (!ret)
1278 return ret;
1279 ret->label = PTRTOSKINOFFSET(skin_buffer, label);
1280 ret->value = 1;
1281 ret->last_changed = 0xffff;
1282 struct skin_token_list *item = new_skin_token_list_item(NULL, ret);
1283 if (!item)
1284 return NULL;
1285 add_to_ll_chain(&data->skinvars, item);
1286 return ret;
1288 static int parse_skinvar( struct skin_element *element,
1289 struct wps_token *token,
1290 struct wps_data *wps_data)
1292 const char* label = get_param_text(element, 0);
1293 struct skin_var* var = find_or_add_var(label, wps_data);
1294 if (!var)
1295 return WPS_ERROR_INVALID_PARAM;
1296 switch (token->type)
1298 case SKIN_TOKEN_VAR_GETVAL:
1299 token->value.data = PTRTOSKINOFFSET(skin_buffer, var);
1300 return 0;
1301 case SKIN_TOKEN_VAR_SET:
1303 struct skin_var_changer *data = skin_buffer_alloc(sizeof(*data));
1304 if (!data)
1305 return WPS_ERROR_INVALID_PARAM;
1306 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1307 if (!isdefault(get_param(element, 2)))
1308 data->newval = get_param(element, 2)->data.number;
1309 else if (strcmp(get_param_text(element, 1), "touch"))
1310 return WPS_ERROR_INVALID_PARAM;
1311 data->max = 0;
1312 if (!strcmp(get_param_text(element, 1), "set"))
1313 data->direct = true;
1314 else if (!strcmp(get_param_text(element, 1), "inc"))
1316 data->direct = false;
1318 else if (!strcmp(get_param_text(element, 1), "dec"))
1320 data->direct = false;
1321 data->newval *= -1;
1323 else if (!strcmp(get_param_text(element, 1), "touch"))
1325 data->direct = false;
1326 data->newval = 0;
1328 if (element->params_count > 3)
1329 data->max = get_param(element, 3)->data.number;
1330 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1332 return 0;
1333 case SKIN_TOKEN_VAR_TIMEOUT:
1335 struct skin_var_lastchange *data = skin_buffer_alloc(sizeof(*data));
1336 if (!data)
1337 return WPS_ERROR_INVALID_PARAM;
1338 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1339 data->timeout = 10;
1340 if (element->params_count > 1)
1341 data->timeout = get_param(element, 1)->data.number;
1342 data->timeout *= TIMEOUT_UNIT;
1343 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1345 default:
1346 return 0;
1349 #endif /* HAVE_SKIN_VARIABLES */
1350 #ifdef HAVE_TOUCHSCREEN
1351 static int parse_lasttouch(struct skin_element *element,
1352 struct wps_token *token,
1353 struct wps_data *wps_data)
1355 struct touchregion_lastpress *data = skin_buffer_alloc(sizeof(*data));
1356 int i;
1357 struct touchregion *region = NULL;
1358 if (!data)
1359 return WPS_ERROR_INVALID_PARAM;
1361 data->timeout = 10;
1363 for (i=0; i<element->params_count; i++)
1365 if (get_param(element, i)->type == STRING)
1366 region = skin_find_item(get_param_text(element, i),
1367 SKIN_FIND_TOUCHREGION, wps_data);
1368 else if (get_param(element, i)->type == INTEGER ||
1369 get_param(element, i)->type == DECIMAL)
1370 data->timeout = get_param(element, i)->data.number;
1373 data->region = PTRTOSKINOFFSET(skin_buffer, region);
1374 data->timeout *= TIMEOUT_UNIT;
1375 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1376 return 0;
1379 struct touchaction {const char* s; int action;};
1380 static const struct touchaction touchactions[] = {
1381 /* generic actions, convert to screen actions on use */
1382 {"none", ACTION_TOUCHSCREEN_IGNORE},{"lock", ACTION_TOUCH_SOFTLOCK },
1383 {"prev", ACTION_STD_PREV }, {"next", ACTION_STD_NEXT },
1384 {"hotkey", ACTION_STD_HOTKEY}, {"select", ACTION_STD_OK },
1385 {"menu", ACTION_STD_MENU }, {"cancel", ACTION_STD_CANCEL },
1386 {"contextmenu", ACTION_STD_CONTEXT},{"quickscreen", ACTION_STD_QUICKSCREEN },
1388 /* list/tree actions */
1389 { "resumeplayback", ACTION_TREE_WPS}, /* returns to previous music, WPS/FM */
1390 /* not really WPS specific, but no equivilant ACTION_STD_* */
1391 {"voldown", ACTION_WPS_VOLDOWN}, {"volup", ACTION_WPS_VOLUP},
1392 {"mute", ACTION_TOUCH_MUTE },
1394 /* generic settings changers */
1395 {"setting_inc", ACTION_SETTINGS_INC}, {"setting_dec", ACTION_SETTINGS_DEC},
1396 {"setting_set", ACTION_SETTINGS_SET},
1398 /* WPS specific actions */
1399 {"rwd", ACTION_WPS_SEEKBACK }, {"ffwd", ACTION_WPS_SEEKFWD },
1400 {"wps_prev", ACTION_WPS_SKIPPREV }, {"wps_next", ACTION_WPS_SKIPNEXT },
1401 {"browse", ACTION_WPS_BROWSE },
1402 {"play", ACTION_WPS_PLAY }, {"stop", ACTION_WPS_STOP },
1403 {"shuffle", ACTION_TOUCH_SHUFFLE }, {"repmode", ACTION_TOUCH_REPMODE },
1404 {"pitch", ACTION_WPS_PITCHSCREEN}, {"trackinfo", ACTION_WPS_ID3SCREEN },
1405 {"playlist", ACTION_WPS_VIEW_PLAYLIST },
1406 {"listbookmarks", ACTION_WPS_LIST_BOOKMARKS },
1407 {"createbookmark", ACTION_WPS_CREATE_BOOKMARK },
1409 #if CONFIG_TUNER
1410 /* FM screen actions */
1411 /* Also allow browse, play, stop from WPS codes */
1412 {"mode", ACTION_FM_MODE }, {"record", ACTION_FM_RECORD },
1413 {"presets", ACTION_FM_PRESET},
1414 #endif
1417 static int touchregion_setup_setting(struct skin_element *element, int param_no,
1418 struct touchregion *region)
1420 #ifndef __PCTOOL__
1421 int p = param_no;
1422 char *name = get_param_text(element, p++);
1423 int j;
1425 region->setting_data.setting = find_setting_by_cfgname(name, &j);
1426 if (region->setting_data.setting == NULL)
1427 return WPS_ERROR_INVALID_PARAM;
1429 if (region->action == ACTION_SETTINGS_SET)
1431 char* text;
1432 int temp;
1433 struct touchsetting *setting =
1434 &region->setting_data;
1435 if (element->params_count < p+1)
1436 return -1;
1438 text = get_param_text(element, p++);
1439 switch (settings[j].flags&F_T_MASK)
1441 case F_T_CUSTOM:
1442 setting->value.text = PTRTOSKINOFFSET(skin_buffer, text);
1443 break;
1444 case F_T_INT:
1445 case F_T_UINT:
1446 if (settings[j].cfg_vals == NULL)
1448 setting->value.number = atoi(text);
1450 else if (cfg_string_to_int(j, &temp, text))
1452 if (settings[j].flags&F_TABLE_SETTING)
1453 setting->value.number =
1454 settings[j].table_setting->values[temp];
1455 else
1456 setting->value.number = temp;
1458 else
1459 return -1;
1460 break;
1461 case F_T_BOOL:
1462 if (cfg_string_to_int(j, &temp, text))
1464 setting->value.number = temp;
1466 else
1467 return -1;
1468 break;
1469 default:
1470 return -1;
1473 return p-param_no;
1474 #endif /* __PCTOOL__ */
1475 return 0;
1478 static int parse_touchregion(struct skin_element *element,
1479 struct wps_token *token,
1480 struct wps_data *wps_data)
1482 (void)token;
1483 unsigned i, imax;
1484 int p;
1485 struct touchregion *region = NULL;
1486 const char *action;
1487 const char pb_string[] = "progressbar";
1488 const char vol_string[] = "volume";
1490 /* format: %T([label,], x,y,width,height,action[, ...])
1491 * if action starts with & the area must be held to happen
1495 region = skin_buffer_alloc(sizeof(*region));
1496 if (!region)
1497 return WPS_ERROR_INVALID_PARAM;
1499 /* should probably do some bounds checking here with the viewport... but later */
1500 region->action = ACTION_NONE;
1502 if (get_param(element, 0)->type == STRING)
1504 region->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
1505 p = 1;
1506 /* "[SI]III[SI]|SS" is the param list. There MUST be 4 numbers
1507 * followed by at least one string. Verify that here */
1508 if (element->params_count < 6 ||
1509 get_param(element, 4)->type != INTEGER)
1510 return WPS_ERROR_INVALID_PARAM;
1512 else
1514 region->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1515 p = 0;
1518 region->x = get_param(element, p++)->data.number;
1519 region->y = get_param(element, p++)->data.number;
1520 region->width = get_param(element, p++)->data.number;
1521 region->height = get_param(element, p++)->data.number;
1522 region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp);
1523 region->armed = false;
1524 region->reverse_bar = false;
1525 region->value = 0;
1526 region->last_press = 0xffff;
1527 region->press_length = PRESS;
1528 region->allow_while_locked = false;
1529 region->bar = PTRTOSKINOFFSET(skin_buffer, NULL);
1530 action = get_param_text(element, p++);
1532 /* figure out the action */
1533 if(!strcmp(pb_string, action))
1534 region->action = ACTION_TOUCH_SCROLLBAR;
1535 else if(!strcmp(vol_string, action))
1536 region->action = ACTION_TOUCH_VOLUME;
1537 else
1539 imax = ARRAYLEN(touchactions);
1540 for (i = 0; i < imax; i++)
1542 /* try to match with one of our touchregion screens */
1543 if (!strcmp(touchactions[i].s, action))
1545 region->action = touchactions[i].action;
1546 if (region->action == ACTION_SETTINGS_INC ||
1547 region->action == ACTION_SETTINGS_DEC ||
1548 region->action == ACTION_SETTINGS_SET)
1550 int val;
1551 if (element->params_count < p+1)
1552 return WPS_ERROR_INVALID_PARAM;
1553 val = touchregion_setup_setting(element, p, region);
1554 if (val < 0)
1555 return WPS_ERROR_INVALID_PARAM;
1556 p += val;
1558 break;
1561 if (region->action == ACTION_NONE)
1562 return WPS_ERROR_INVALID_PARAM;
1564 while (p < element->params_count)
1566 char* param = get_param_text(element, p++);
1567 if (!strcmp(param, "allow_while_locked"))
1568 region->allow_while_locked = true;
1569 else if (!strcmp(param, "reverse_bar"))
1570 region->reverse_bar = true;
1571 else if (!strcmp(param, "repeat_press"))
1572 region->press_length = REPEAT;
1573 else if (!strcmp(param, "long_press"))
1574 region->press_length = LONG_PRESS;
1576 struct skin_token_list *item = new_skin_token_list_item(NULL, region);
1577 if (!item)
1578 return WPS_ERROR_INVALID_PARAM;
1579 add_to_ll_chain(&wps_data->touchregions, item);
1581 if (region->action == ACTION_TOUCH_MUTE)
1583 region->value = global_settings.volume;
1587 return 0;
1589 #endif
1591 static bool check_feature_tag(const int type)
1593 switch (type)
1595 case SKIN_TOKEN_RTC_PRESENT:
1596 #if CONFIG_RTC
1597 return true;
1598 #else
1599 return false;
1600 #endif
1601 case SKIN_TOKEN_HAVE_RECORDING:
1602 #ifdef HAVE_RECORDING
1603 return true;
1604 #else
1605 return false;
1606 #endif
1607 case SKIN_TOKEN_HAVE_TUNER:
1608 #if CONFIG_TUNER
1609 if (radio_hardware_present())
1610 return true;
1611 #endif
1612 return false;
1613 case SKIN_TOKEN_HAVE_TOUCH:
1614 #ifdef HAVE_TOUCHSCREEN
1615 return true;
1616 #else
1617 return false;
1618 #endif
1620 #if CONFIG_TUNER
1621 case SKIN_TOKEN_HAVE_RDS:
1622 #ifdef HAVE_RDS_CAP
1623 return true;
1624 #else
1625 return false;
1626 #endif /* HAVE_RDS_CAP */
1627 #endif /* CONFIG_TUNER */
1628 default: /* not a tag we care about, just don't skip */
1629 return true;
1633 /* This is used to free any buflib allocations before the rest of
1634 * wps_data is reset.
1635 * The call to this in settings_apply_skins() is the last chance to do
1636 * any core_free()'s before wps_data is trashed and those handles lost
1638 void skin_data_free_buflib_allocs(struct wps_data *wps_data)
1640 if (wps_data->wps_loaded)
1641 skin_buffer = get_skin_buffer(wps_data);
1642 #ifdef HAVE_LCD_BITMAP
1643 #ifndef __PCTOOL__
1644 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1645 int *font_ids = SKINOFFSETTOPTR(skin_buffer, wps_data->font_ids);
1646 while (list)
1648 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1649 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1650 if (img->buflib_handle > 0)
1651 core_free(img->buflib_handle);
1652 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1654 wps_data->images = PTRTOSKINOFFSET(skin_buffer, NULL);
1655 if (font_ids != NULL)
1657 while (wps_data->font_count > 0)
1658 font_unload(font_ids[--wps_data->font_count]);
1660 wps_data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1661 if (wps_data->buflib_handle > 0)
1662 core_free(wps_data->buflib_handle);
1663 wps_data->buflib_handle = -1;
1664 #endif
1665 #endif
1669 * initial setup of wps_data; does reset everything
1670 * except fields which need to survive, i.e.
1671 * Also called if the load fails
1673 static void skin_data_reset(struct wps_data *wps_data)
1675 skin_data_free_buflib_allocs(wps_data);
1676 #ifdef HAVE_LCD_BITMAP
1677 wps_data->images = INVALID_OFFSET;
1678 #endif
1679 wps_data->tree = INVALID_OFFSET;
1680 #ifdef HAVE_BACKDROP_IMAGE
1681 if (wps_data->backdrop_id >= 0)
1682 skin_backdrop_unload(wps_data->backdrop_id);
1683 backdrop_filename = NULL;
1684 #endif
1685 #ifdef HAVE_TOUCHSCREEN
1686 wps_data->touchregions = INVALID_OFFSET;
1687 #endif
1688 #ifdef HAVE_SKIN_VARIABLES
1689 wps_data->skinvars = INVALID_OFFSET;
1690 #endif
1691 #ifdef HAVE_ALBUMART
1692 wps_data->albumart = INVALID_OFFSET;
1693 if (wps_data->playback_aa_slot >= 0)
1695 playback_release_aa_slot(wps_data->playback_aa_slot);
1696 wps_data->playback_aa_slot = -1;
1698 #endif
1700 #ifdef HAVE_LCD_BITMAP
1701 wps_data->peak_meter_enabled = false;
1702 wps_data->wps_sb_tag = false;
1703 wps_data->show_sb_on_wps = false;
1704 #else /* HAVE_LCD_CHARCELLS */
1705 /* progress bars */
1706 int i;
1707 for (i = 0; i < 8; i++)
1709 wps_data->wps_progress_pat[i] = 0;
1711 wps_data->full_line_progressbar = false;
1712 #endif
1713 wps_data->wps_loaded = false;
1716 #ifdef HAVE_LCD_BITMAP
1717 #ifndef __PCTOOL__
1718 static int currently_loading_handle = -1;
1719 static int buflib_move_callback(int handle, void* current, void* new)
1721 (void)current;
1722 (void)new;
1723 if (handle == currently_loading_handle)
1724 return BUFLIB_CB_CANNOT_MOVE;
1725 return BUFLIB_CB_OK;
1727 static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
1728 static void lock_handle(int handle)
1730 currently_loading_handle = handle;
1732 static void unlock_handle(void)
1734 currently_loading_handle = -1;
1736 #endif
1738 static int load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir)
1740 (void)wps_data; /* only needed for remote targets */
1741 char img_path[MAX_PATH];
1742 int fd;
1743 int handle;
1744 get_image_filename(bitmap->data, bmpdir,
1745 img_path, sizeof(img_path));
1747 /* load the image */
1748 int format;
1749 #ifdef HAVE_REMOTE_LCD
1750 if (curr_screen == SCREEN_REMOTE)
1751 format = FORMAT_ANY|FORMAT_REMOTE;
1752 else
1753 #endif
1754 format = FORMAT_ANY|FORMAT_TRANSPARENT;
1756 fd = open(img_path, O_RDONLY);
1757 if (fd < 0)
1759 DEBUGF("Couldn't open %s\n", img_path);
1760 return fd;
1762 #ifndef __PCTOOL__
1763 size_t buf_size = read_bmp_fd(fd, bitmap, 0,
1764 format|FORMAT_RETURN_SIZE, NULL);
1765 handle = core_alloc_ex(bitmap->data, buf_size, &buflib_ops);
1766 if (handle <= 0)
1768 DEBUGF("Not enough skin buffer: need %zd more.\n",
1769 buf_size - skin_buffer_freespace());
1770 close(fd);
1771 return handle;
1773 lseek(fd, 0, SEEK_SET);
1774 lock_handle(handle);
1775 bitmap->data = core_get_data(handle);
1776 int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
1777 bitmap->data = NULL; /* do this to force a crash later if the
1778 caller doesnt call core_get_data() */
1779 unlock_handle();
1780 close(fd);
1781 if (ret > 0)
1783 /* free unused alpha channel, if any */
1784 core_shrink(handle, core_get_data(handle), ret);
1785 return handle;
1787 else
1789 /* Abort if we can't load an image */
1790 DEBUGF("Couldn't load '%s'\n", img_path);
1791 core_free(handle);
1792 return -1;
1794 #else /* !__PCTOOL__ */
1795 close(fd);
1796 return 1;
1797 #endif
1800 static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
1802 struct skin_token_list *list;
1803 bool retval = true; /* return false if a single image failed to load */
1805 /* regular images */
1806 list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1807 while (list)
1809 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1810 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1811 if (img->bm.data)
1813 if (img->using_preloaded_icons)
1815 img->loaded = true;
1816 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
1818 else
1820 img->buflib_handle = load_skin_bmp(wps_data, &img->bm, bmpdir);
1821 img->loaded = img->buflib_handle >= 0;
1822 if (img->loaded)
1823 img->subimage_height = img->bm.height / img->num_subimages;
1824 else
1825 retval = false;
1828 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1831 #ifdef HAVE_BACKDROP_IMAGE
1832 wps_data->backdrop_id = skin_backdrop_assign(backdrop_filename, bmpdir, curr_screen);
1833 #endif /* has backdrop support */
1834 return retval;
1837 static bool skin_load_fonts(struct wps_data *data)
1839 /* don't spit out after the first failue to aid debugging */
1840 int id_array[MAXUSERFONTS];
1841 int font_count = 0;
1842 bool success = true;
1843 struct skin_element *vp_list;
1844 int font_id;
1845 /* walk though each viewport and assign its font */
1846 for(vp_list = SKINOFFSETTOPTR(skin_buffer, data->tree);
1847 vp_list; vp_list = SKINOFFSETTOPTR(skin_buffer, vp_list->next))
1849 /* first, find the viewports that have a non-sys/ui-font font */
1850 struct skin_viewport *skin_vp =
1851 SKINOFFSETTOPTR(skin_buffer, vp_list->data);
1852 struct viewport *vp = &skin_vp->vp;
1854 font_id = skin_vp->parsed_fontid;
1855 if (font_id == 1)
1856 { /* the usual case -> built-in fonts */
1857 vp->font = screens[curr_screen].getuifont();
1858 continue;
1860 else if (font_id <= 0)
1862 vp->font = FONT_SYSFIXED;
1863 continue;
1866 /* now find the corresponding skin_font */
1867 struct skin_font *font = &skinfonts[font_id-2];
1868 if (!font->name)
1870 if (success)
1872 DEBUGF("font %d not specified\n", font_id);
1874 success = false;
1875 continue;
1878 /* load the font - will handle loading the same font again if
1879 * multiple viewports use the same */
1880 if (font->id < 0)
1882 char path[MAX_PATH];
1883 snprintf(path, sizeof path, FONT_DIR "/%s", font->name);
1884 #ifndef __PCTOOL__
1885 font->id = font_load_ex(path, 0, skinfonts[font_id-2].glyphs);
1887 #else
1888 font->id = font_load(path);
1889 #endif
1890 //printf("[%d] %s -> %d\n",font_id, font->name, font->id);
1891 id_array[font_count++] = font->id;
1894 if (font->id < 0)
1896 DEBUGF("Unable to load font %d: '%s'\n", font_id, font->name);
1897 font->name = NULL; /* to stop trying to load it again if we fail */
1898 success = false;
1899 continue;
1902 /* finally, assign the font_id to the viewport */
1903 vp->font = font->id;
1905 if (font_count)
1907 int *font_ids = skin_buffer_alloc(font_count * sizeof(int));
1908 if (!success || font_ids == NULL)
1910 while (font_count > 0)
1912 if(id_array[--font_count] != -1)
1913 font_unload(id_array[font_count]);
1915 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1916 return false;
1918 memcpy(font_ids, id_array, sizeof(int)*font_count);
1919 data->font_count = font_count;
1920 data->font_ids = PTRTOSKINOFFSET(skin_buffer, font_ids);
1922 else
1924 data->font_count = 0;
1925 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1927 return success;
1930 #endif /* HAVE_LCD_BITMAP */
1931 static int convert_viewport(struct wps_data *data, struct skin_element* element)
1933 struct skin_viewport *skin_vp = skin_buffer_alloc(sizeof(*skin_vp));
1934 struct screen *display = &screens[curr_screen];
1936 if (!skin_vp)
1937 return CALLBACK_ERROR;
1939 skin_vp->hidden_flags = 0;
1940 skin_vp->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1941 skin_vp->is_infovp = false;
1942 skin_vp->parsed_fontid = 1;
1943 element->data = PTRTOSKINOFFSET(skin_buffer, skin_vp);
1944 curr_vp = skin_vp;
1945 curr_viewport_element = element;
1946 if (!first_viewport)
1947 first_viewport = element;
1949 viewport_set_defaults(&skin_vp->vp, curr_screen);
1951 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1952 skin_vp->output_to_backdrop_buffer = false;
1953 skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
1954 skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
1955 #endif
1956 #ifdef HAVE_LCD_COLOR
1957 skin_vp->start_gradient.start = skin_vp->vp.lss_pattern;
1958 skin_vp->start_gradient.end = skin_vp->vp.lse_pattern;
1959 skin_vp->start_gradient.text = skin_vp->vp.lst_pattern;
1960 #endif
1963 struct skin_tag_parameter *param = get_param(element, 0);
1964 if (element->params_count == 0) /* default viewport */
1966 if (data->tree < 0) /* first viewport in the skin */
1967 data->tree = PTRTOSKINOFFSET(skin_buffer, element);
1968 skin_vp->label = VP_DEFAULT_LABEL;
1969 return CALLBACK_OK;
1972 if (element->params_count == 6)
1974 if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
1976 skin_vp->is_infovp = true;
1977 if (isdefault(param))
1979 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1980 skin_vp->label = VP_DEFAULT_LABEL;
1982 else
1984 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1985 skin_vp->label = param->data.text;
1988 else
1990 skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN;
1991 skin_vp->label = param->data.text;
1993 param++;
1995 /* x */
1996 if (!isdefault(param))
1998 skin_vp->vp.x = param->data.number;
1999 if (param->data.number < 0)
2000 skin_vp->vp.x += display->lcdwidth;
2001 else if (param->type == PERCENT)
2002 skin_vp->vp.x = param->data.number * display->lcdwidth / 1000;
2004 param++;
2005 /* y */
2006 if (!isdefault(param))
2008 skin_vp->vp.y = param->data.number;
2009 if (param->data.number < 0)
2010 skin_vp->vp.y += display->lcdheight;
2011 else if (param->type == PERCENT)
2012 skin_vp->vp.y = param->data.number * display->lcdheight / 1000;
2014 param++;
2015 /* width */
2016 if (!isdefault(param))
2018 skin_vp->vp.width = param->data.number;
2019 if (param->data.number < 0)
2020 skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
2021 else if (param->type == PERCENT)
2022 skin_vp->vp.width = param->data.number * display->lcdwidth / 1000;
2024 else
2026 skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x;
2028 param++;
2029 /* height */
2030 if (!isdefault(param))
2032 skin_vp->vp.height = param->data.number;
2033 if (param->data.number < 0)
2034 skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
2035 else if (param->type == PERCENT)
2036 skin_vp->vp.height = param->data.number * display->lcdheight / 1000;
2038 else
2040 skin_vp->vp.height = display->lcdheight - skin_vp->vp.y;
2042 param++;
2043 #ifdef HAVE_LCD_BITMAP
2044 /* font */
2045 if (!isdefault(param))
2046 skin_vp->parsed_fontid = param->data.number;
2047 #endif
2048 if ((unsigned) skin_vp->vp.x >= (unsigned) display->lcdwidth ||
2049 skin_vp->vp.width + skin_vp->vp.x > display->lcdwidth ||
2050 (unsigned) skin_vp->vp.y >= (unsigned) display->lcdheight ||
2051 skin_vp->vp.height + skin_vp->vp.y > display->lcdheight)
2052 return CALLBACK_ERROR;
2054 /* Fix x position for RTL languages */
2055 if (follow_lang_direction && lang_is_rtl())
2056 skin_vp->vp.x = display->lcdwidth - skin_vp->vp.x - skin_vp->vp.width;
2058 return CALLBACK_OK;
2061 static int skin_element_callback(struct skin_element* element, void* data)
2063 struct wps_data *wps_data = (struct wps_data *)data;
2064 struct wps_token *token;
2065 parse_function function = NULL;
2067 switch (element->type)
2069 /* IMPORTANT: element params are shared, so copy them if needed
2070 * or use then NOW, dont presume they have a long lifespan
2072 case TAG:
2074 token = skin_buffer_alloc(sizeof(*token));
2075 memset(token, 0, sizeof(*token));
2076 token->type = element->tag->type;
2077 token->value.data = INVALID_OFFSET;
2079 if (element->tag->flags&SKIN_RTC_REFRESH)
2081 #if CONFIG_RTC
2082 curr_line->update_mode |= SKIN_REFRESH_DYNAMIC;
2083 #else
2084 curr_line->update_mode |= SKIN_REFRESH_STATIC;
2085 #endif
2087 else
2088 curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL;
2090 element->data = PTRTOSKINOFFSET(skin_buffer, token);
2092 /* Some tags need special handling for the tag, so add them here */
2093 switch (token->type)
2095 case SKIN_TOKEN_ALIGN_LANGDIRECTION:
2096 follow_lang_direction = 2;
2097 break;
2098 case SKIN_TOKEN_LOGICAL_IF:
2099 function = parse_logical_if;
2100 break;
2101 case SKIN_TOKEN_LOGICAL_AND:
2102 case SKIN_TOKEN_LOGICAL_OR:
2103 function = parse_logical_andor;
2104 break;
2105 case SKIN_TOKEN_SUBSTRING:
2106 function = parse_substring_tag;
2107 break;
2108 case SKIN_TOKEN_PROGRESSBAR:
2109 case SKIN_TOKEN_VOLUME:
2110 case SKIN_TOKEN_BATTERY_PERCENT:
2111 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
2112 case SKIN_TOKEN_PEAKMETER_LEFT:
2113 case SKIN_TOKEN_PEAKMETER_RIGHT:
2114 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
2115 #ifdef HAVE_RADIO_RSSI
2116 case SKIN_TOKEN_TUNER_RSSI:
2117 #endif
2118 function = parse_progressbar_tag;
2119 break;
2120 case SKIN_TOKEN_SUBLINE_TIMEOUT:
2121 case SKIN_TOKEN_BUTTON_VOLUME:
2122 case SKIN_TOKEN_TRACK_STARTING:
2123 case SKIN_TOKEN_TRACK_ENDING:
2124 function = parse_timeout_tag;
2125 break;
2126 #ifdef HAVE_LCD_BITMAP
2127 case SKIN_TOKEN_LIST_ITEM_TEXT:
2128 case SKIN_TOKEN_LIST_ITEM_ICON:
2129 function = parse_listitem;
2130 break;
2131 case SKIN_TOKEN_DISABLE_THEME:
2132 case SKIN_TOKEN_ENABLE_THEME:
2133 case SKIN_TOKEN_DRAW_INBUILTBAR:
2134 function = parse_statusbar_tags;
2135 break;
2136 case SKIN_TOKEN_LIST_TITLE_TEXT:
2137 #ifndef __PCTOOL__
2138 sb_skin_has_title(curr_screen);
2139 #endif
2140 break;
2141 #endif
2142 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2143 case SKIN_TOKEN_DRAWRECTANGLE:
2144 function = parse_drawrectangle;
2145 break;
2146 #endif
2147 case SKIN_TOKEN_FILE_DIRECTORY:
2148 token->value.i = get_param(element, 0)->data.number;
2149 break;
2150 #ifdef HAVE_BACKDROP_IMAGE
2151 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
2152 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
2153 function = parse_viewportcolour;
2154 break;
2155 case SKIN_TOKEN_IMAGE_BACKDROP:
2156 function = parse_image_special;
2157 break;
2158 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE:
2159 function = parse_viewporttextstyle;
2160 break;
2161 case SKIN_TOKEN_VIEWPORT_DRAWONBG:
2162 curr_vp->output_to_backdrop_buffer = true;
2163 backdrop_filename = BACKDROP_BUFFERNAME;
2164 wps_data->use_extra_framebuffer = true;
2165 break;
2166 #endif
2167 #ifdef HAVE_LCD_COLOR
2168 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP:
2169 function = parse_viewport_gradient_setup;
2170 break;
2171 #endif
2172 case SKIN_TOKEN_TRANSLATEDSTRING:
2173 case SKIN_TOKEN_SETTING:
2174 function = parse_setting_and_lang;
2175 break;
2176 #ifdef HAVE_LCD_BITMAP
2177 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
2178 function = parse_playlistview;
2179 break;
2180 case SKIN_TOKEN_LOAD_FONT:
2181 function = parse_font_load;
2182 break;
2183 case SKIN_TOKEN_VIEWPORT_ENABLE:
2184 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
2185 token->value.data = get_param(element, 0)->data.text;
2186 break;
2187 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
2188 case SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT:
2189 function = parse_image_display;
2190 break;
2191 case SKIN_TOKEN_IMAGE_PRELOAD:
2192 case SKIN_TOKEN_IMAGE_DISPLAY:
2193 function = parse_image_load;
2194 break;
2195 case SKIN_TOKEN_LIST_ITEM_CFG:
2196 function = parse_listitemviewport;
2197 break;
2198 #endif
2199 #ifdef HAVE_TOUCHSCREEN
2200 case SKIN_TOKEN_TOUCHREGION:
2201 function = parse_touchregion;
2202 break;
2203 case SKIN_TOKEN_LASTTOUCH:
2204 function = parse_lasttouch;
2205 break;
2206 #endif
2207 #ifdef HAVE_ALBUMART
2208 case SKIN_TOKEN_ALBUMART_DISPLAY:
2209 if (SKINOFFSETTOPTR(skin_buffer, wps_data->albumart))
2211 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2212 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
2214 break;
2215 case SKIN_TOKEN_ALBUMART_LOAD:
2216 function = parse_albumart_load;
2217 break;
2218 #endif
2219 #ifdef HAVE_SKIN_VARIABLES
2220 case SKIN_TOKEN_VAR_SET:
2221 case SKIN_TOKEN_VAR_GETVAL:
2222 case SKIN_TOKEN_VAR_TIMEOUT:
2223 function = parse_skinvar;
2224 break;
2225 #endif
2226 default:
2227 break;
2229 if (function)
2231 if (function(element, token, wps_data) < 0)
2232 return CALLBACK_ERROR;
2234 /* tags that start with 'F', 'I' or 'D' are for the next file */
2235 if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' ||
2236 *(element->tag->name) == 'D')
2237 token->next = true;
2238 if (follow_lang_direction > 0 )
2239 follow_lang_direction--;
2240 break;
2242 case VIEWPORT:
2243 return convert_viewport(wps_data, element);
2244 case LINE:
2246 curr_line = skin_buffer_alloc(sizeof(*curr_line));
2247 curr_line->update_mode = SKIN_REFRESH_STATIC;
2248 element->data = PTRTOSKINOFFSET(skin_buffer, curr_line);
2250 break;
2251 case LINE_ALTERNATOR:
2253 struct line_alternator *alternator = skin_buffer_alloc(sizeof(*alternator));
2254 alternator->current_line = 0;
2255 #ifndef __PCTOOL__
2256 alternator->next_change_tick = current_tick;
2257 #endif
2258 element->data = PTRTOSKINOFFSET(skin_buffer, alternator);
2260 break;
2261 case CONDITIONAL:
2263 struct conditional *conditional = skin_buffer_alloc(sizeof(*conditional));
2264 conditional->last_value = -1;
2265 conditional->token = element->data;
2266 element->data = PTRTOSKINOFFSET(skin_buffer, conditional);
2267 if (!check_feature_tag(element->tag->type))
2269 return FEATURE_NOT_AVAILABLE;
2271 return CALLBACK_OK;
2273 case TEXT:
2274 curr_line->update_mode |= SKIN_REFRESH_STATIC;
2275 break;
2276 default:
2277 break;
2279 return CALLBACK_OK;
2282 /* to setup up the wps-data from a format-buffer (isfile = false)
2283 from a (wps-)file (isfile = true)*/
2284 bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2285 const char *buf, bool isfile)
2287 char *wps_buffer = NULL;
2288 if (!wps_data || !buf)
2289 return false;
2290 #ifdef HAVE_ALBUMART
2291 int status;
2292 struct mp3entry *curtrack;
2293 long offset;
2294 struct skin_albumart old_aa = {.state = WPS_ALBUMART_NONE};
2295 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2296 if (aa)
2298 old_aa.state = aa->state;
2299 old_aa.height = aa->height;
2300 old_aa.width = aa->width;
2302 #endif
2303 #ifdef HAVE_LCD_BITMAP
2304 int i;
2305 for (i=0;i<MAXUSERFONTS;i++)
2307 skinfonts[i].id = -1;
2308 skinfonts[i].name = NULL;
2310 #endif
2311 #ifdef DEBUG_SKIN_ENGINE
2312 if (isfile && debug_wps)
2314 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf);
2316 #endif
2319 /* get buffer space from the plugin buffer */
2320 size_t buffersize = 0;
2321 wps_buffer = (char *)plugin_get_buffer(&buffersize);
2323 if (!wps_buffer)
2324 return false;
2326 skin_data_reset(wps_data);
2327 wps_data->wps_loaded = false;
2328 curr_screen = screen;
2329 curr_line = NULL;
2330 curr_vp = NULL;
2331 curr_viewport_element = NULL;
2332 first_viewport = NULL;
2334 if (isfile)
2336 int fd = open_utf8(buf, O_RDONLY);
2338 if (fd < 0)
2339 return false;
2340 /* copy the file's content to the buffer for parsing,
2341 ensuring that every line ends with a newline char. */
2342 unsigned int start = 0;
2343 while(read_line(fd, wps_buffer + start, buffersize - start) > 0)
2345 start += strlen(wps_buffer + start);
2346 if (start < buffersize - 1)
2348 wps_buffer[start++] = '\n';
2349 wps_buffer[start] = 0;
2352 close(fd);
2353 if (start <= 0)
2354 return false;
2355 start++;
2356 skin_buffer = &wps_buffer[start];
2357 buffersize -= start;
2359 else
2361 skin_buffer = wps_buffer;
2362 wps_buffer = (char*)buf;
2364 skin_buffer = (void *)(((unsigned long)skin_buffer + 3) & ~3);
2365 buffersize -= 3;
2366 #ifdef HAVE_BACKDROP_IMAGE
2367 backdrop_filename = "-";
2368 wps_data->backdrop_id = -1;
2369 #endif
2370 /* parse the skin source */
2371 skin_buffer_init(skin_buffer, buffersize);
2372 struct skin_element *tree = skin_parse(wps_buffer, skin_element_callback, wps_data);
2373 wps_data->tree = PTRTOSKINOFFSET(skin_buffer, tree);
2374 if (!SKINOFFSETTOPTR(skin_buffer, wps_data->tree)) {
2375 #ifdef DEBUG_SKIN_ENGINE
2376 if (isfile && debug_wps)
2377 skin_error_format_message();
2378 #endif
2379 skin_data_reset(wps_data);
2380 return false;
2383 #ifdef HAVE_LCD_BITMAP
2384 char bmpdir[MAX_PATH];
2385 if (isfile)
2387 /* get the bitmap dir */
2388 char *dot = strrchr(buf, '.');
2389 strlcpy(bmpdir, buf, dot - buf + 1);
2391 else
2393 snprintf(bmpdir, MAX_PATH, "%s", BACKDROP_DIR);
2395 /* load the bitmaps that were found by the parsing */
2396 if (!load_skin_bitmaps(wps_data, bmpdir) ||
2397 !skin_load_fonts(wps_data))
2399 skin_data_reset(wps_data);
2400 return false;
2402 #endif
2403 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2404 status = audio_status();
2405 if (status & AUDIO_STATUS_PLAY)
2407 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2408 if (aa && ((aa->state && !old_aa.state) ||
2409 (aa->state &&
2410 (((old_aa.height != aa->height) ||
2411 (old_aa.width != aa->width))))))
2413 curtrack = audio_current_track();
2414 offset = curtrack->offset;
2415 audio_stop();
2416 if (!(status & AUDIO_STATUS_PAUSE))
2417 audio_play(offset);
2420 #endif
2421 #ifndef __PCTOOL__
2422 wps_data->buflib_handle = core_alloc(isfile ? buf : "failsafe skin",
2423 skin_buffer_usage());
2424 if (wps_data->buflib_handle > 0)
2426 wps_data->wps_loaded = true;
2427 memcpy(core_get_data(wps_data->buflib_handle), skin_buffer,
2428 skin_buffer_usage());
2430 #else
2431 wps_data->wps_loaded = wps_data->tree >= 0;
2432 #endif
2434 #ifdef HAVE_TOUCHSCREEN
2435 /* Check if there are any touch regions from the skin and not just
2436 * auto-created ones for bars */
2437 struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer,
2438 wps_data->touchregions);
2439 bool user_touch_region_found = false;
2440 while (regions)
2442 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, regions->token);
2443 struct touchregion *r = SKINOFFSETTOPTR(skin_buffer, token->value.data);
2445 if (r->action != ACTION_TOUCH_SCROLLBAR &&
2446 r->action != ACTION_TOUCH_VOLUME)
2448 user_touch_region_found = true;
2449 break;
2451 regions = SKINOFFSETTOPTR(skin_buffer, regions->next);
2453 regions = SKINOFFSETTOPTR(skin_buffer, wps_data->touchregions);
2454 if (regions && !user_touch_region_found)
2455 wps_data->touchregions = PTRTOSKINOFFSET(skin_buffer, NULL);
2456 #endif
2458 skin_buffer = NULL;
2459 return true;