skin engine: Relax the AA load width/height checks
[maemo-rb.git] / apps / gui / skin_engine / skin_parser.c
blob94396640f292fdb67fc9a29068f6951dee4aa65a
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
86 static struct skin_stats *_stats = NULL;
88 static bool isdefault(struct skin_tag_parameter *param)
90 return param->type == DEFAULT;
93 static inline char*
94 get_param_text(struct skin_element *element, int param_number)
96 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
97 return SKINOFFSETTOPTR(skin_buffer, params[param_number].data.text);
100 static inline struct skin_element*
101 get_param_code(struct skin_element *element, int param_number)
103 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
104 return SKINOFFSETTOPTR(skin_buffer, params[param_number].data.code);
107 static inline struct skin_tag_parameter*
108 get_param(struct skin_element *element, int param_number)
110 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
111 return &params[param_number];
114 /* which screen are we parsing for? */
115 static enum screen_type curr_screen;
117 /* the current viewport */
118 static struct skin_element *curr_viewport_element;
119 static struct skin_viewport *curr_vp;
120 static struct skin_element *first_viewport;
122 static struct line *curr_line;
124 static int follow_lang_direction = 0;
126 typedef int (*parse_function)(struct skin_element *element,
127 struct wps_token *token,
128 struct wps_data *wps_data);
130 #ifdef HAVE_LCD_BITMAP
131 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
132 * chains require the order to be kept.
134 static void add_to_ll_chain(OFFSETTYPE(struct skin_token_list *) *listoffset,
135 struct skin_token_list *item)
137 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, *listoffset);
138 if (list == NULL)
140 *listoffset = PTRTOSKINOFFSET(skin_buffer, item);
142 else
144 while (SKINOFFSETTOPTR(skin_buffer, list->next))
145 list = SKINOFFSETTOPTR(skin_buffer, list->next);
146 list->next = PTRTOSKINOFFSET(skin_buffer, item);
150 #endif
153 void *skin_find_item(const char *label, enum skin_find_what what,
154 struct wps_data *data)
156 const char *itemlabel = NULL;
157 char *databuf = get_skin_buffer(data);
158 union {
159 struct skin_token_list *linkedlist;
160 struct skin_element *vplist;
161 } list = {NULL};
162 bool isvplist = false;
163 void *ret = NULL;
164 if (!databuf)
165 databuf = skin_buffer;
166 switch (what)
168 case SKIN_FIND_UIVP:
169 case SKIN_FIND_VP:
170 list.vplist = SKINOFFSETTOPTR(databuf, data->tree);
171 isvplist = true;
172 break;
173 #ifdef HAVE_LCD_BITMAP
174 case SKIN_FIND_IMAGE:
175 list.linkedlist = SKINOFFSETTOPTR(databuf, data->images);
176 break;
177 #endif
178 #ifdef HAVE_TOUCHSCREEN
179 case SKIN_FIND_TOUCHREGION:
180 list.linkedlist = SKINOFFSETTOPTR(databuf, data->touchregions);
181 break;
182 #endif
183 #ifdef HAVE_SKIN_VARIABLES
184 case SKIN_VARIABLE:
185 list.linkedlist = SKINOFFSETTOPTR(databuf, data->skinvars);
186 break;
187 #endif
190 while (list.linkedlist)
192 bool skip = false;
193 #ifdef HAVE_LCD_BITMAP
194 struct wps_token *token = NULL;
195 if (!isvplist)
196 token = SKINOFFSETTOPTR(databuf, list.linkedlist->token);
197 #endif
198 switch (what)
200 case SKIN_FIND_UIVP:
201 case SKIN_FIND_VP:
202 ret = SKINOFFSETTOPTR(databuf, list.vplist->data);
203 if (((struct skin_viewport *)ret)->label == VP_DEFAULT_LABEL)
204 itemlabel = VP_DEFAULT_LABEL_STRING;
205 else
206 itemlabel = SKINOFFSETTOPTR(databuf, ((struct skin_viewport *)ret)->label);
207 skip = !(((struct skin_viewport *)ret)->is_infovp ==
208 (what==SKIN_FIND_UIVP));
209 break;
210 #ifdef HAVE_LCD_BITMAP
211 case SKIN_FIND_IMAGE:
212 ret = SKINOFFSETTOPTR(databuf, token->value.data);
213 itemlabel = SKINOFFSETTOPTR(databuf, ((struct gui_img *)ret)->label);
214 break;
215 #endif
216 #ifdef HAVE_TOUCHSCREEN
217 case SKIN_FIND_TOUCHREGION:
218 ret = SKINOFFSETTOPTR(databuf, token->value.data);
219 itemlabel = SKINOFFSETTOPTR(databuf, ((struct touchregion *)ret)->label);
220 break;
221 #endif
222 #ifdef HAVE_SKIN_VARIABLES
223 case SKIN_VARIABLE:
224 ret = SKINOFFSETTOPTR(databuf, token->value.data);
225 itemlabel = SKINOFFSETTOPTR(databuf, ((struct skin_var *)ret)->label);
226 break;
227 #endif
230 if (!skip && itemlabel && !strcmp(itemlabel, label))
232 return ret;
235 if (isvplist)
236 list.vplist = SKINOFFSETTOPTR(databuf, list.vplist->next);
237 else
238 list.linkedlist = SKINOFFSETTOPTR(databuf, list.linkedlist->next);
240 return NULL;
243 #ifdef HAVE_LCD_BITMAP
245 /* create and init a new wpsll item.
246 * passing NULL to token will alloc a new one.
247 * You should only pass NULL for the token when the token type (table above)
248 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
250 static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
251 void* token_data)
253 struct skin_token_list *llitem = skin_buffer_alloc(sizeof(*llitem));
254 if (!token)
255 token = skin_buffer_alloc(sizeof(*token));
256 if (!llitem || !token)
257 return NULL;
258 llitem->next = PTRTOSKINOFFSET(skin_buffer, NULL);
259 llitem->token = PTRTOSKINOFFSET(skin_buffer, token);
260 if (token_data)
261 token->value.data = PTRTOSKINOFFSET(skin_buffer, token_data);
262 return llitem;
265 static int parse_statusbar_tags(struct skin_element* element,
266 struct wps_token *token,
267 struct wps_data *wps_data)
269 (void)element;
270 if (token->type == SKIN_TOKEN_DRAW_INBUILTBAR)
272 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)&curr_vp->vp);
274 else
276 struct skin_viewport *default_vp = SKINOFFSETTOPTR(skin_buffer, first_viewport->data);
277 if (first_viewport->params_count == 0)
279 wps_data->wps_sb_tag = true;
280 wps_data->show_sb_on_wps = (token->type == SKIN_TOKEN_ENABLE_THEME);
282 if (wps_data->show_sb_on_wps)
284 viewport_set_defaults(&default_vp->vp, curr_screen);
286 else
288 viewport_set_fullscreen(&default_vp->vp, curr_screen);
290 #ifdef HAVE_REMOTE_LCD
291 /* This parser requires viewports which will use the settings font to
292 * have font == 1, but the above viewport_set() calls set font to
293 * the current real font id. So force 1 here it will be set correctly
294 * at the end
296 default_vp->vp.font = 1;
297 #endif
299 return 0;
302 static int get_image_id(int c)
304 if(c >= 'a' && c <= 'z')
305 return c - 'a';
306 else if(c >= 'A' && c <= 'Z')
307 return c - 'A' + 26;
308 else
309 return -1;
312 void get_image_filename(const char *start, const char* bmpdir,
313 char *buf, int buf_size)
315 snprintf(buf, buf_size, "%s/%s", bmpdir, start);
318 static int parse_image_display(struct skin_element *element,
319 struct wps_token *token,
320 struct wps_data *wps_data)
322 char *label = get_param_text(element, 0);
323 char sublabel = '\0';
324 int subimage;
325 struct gui_img *img;
326 struct image_display *id = skin_buffer_alloc(sizeof(*id));
328 if (element->params_count == 1 && strlen(label) <= 2)
330 /* backwards compatability. Allow %xd(Aa) to still work */
331 sublabel = label[1];
332 label[1] = '\0';
334 /* sanity check */
335 img = skin_find_item(label, SKIN_FIND_IMAGE, wps_data);
336 if (!img || !id)
338 return WPS_ERROR_INVALID_PARAM;
340 id->label = img->label;
341 id->offset = 0;
342 id->token = PTRTOSKINOFFSET(skin_buffer, NULL);
343 if (img->using_preloaded_icons)
345 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
348 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT)
349 img->is_9_segment = true;
351 if (element->params_count > 1)
353 if (get_param(element, 1)->type == CODE)
354 id->token = get_param_code(element, 1)->data;
355 /* specify a number. 1 being the first subimage (i.e top) NOT 0 */
356 else if (get_param(element, 1)->type == INTEGER)
357 id->subimage = get_param(element, 1)->data.number - 1;
358 if (element->params_count > 2)
359 id->offset = get_param(element, 2)->data.number;
361 else
363 if ((subimage = get_image_id(sublabel)) != -1)
365 if (subimage >= img->num_subimages)
366 return WPS_ERROR_INVALID_PARAM;
367 id->subimage = subimage;
368 } else {
369 id->subimage = 0;
372 token->value.data = PTRTOSKINOFFSET(skin_buffer, id);
373 return 0;
376 static int parse_image_load(struct skin_element *element,
377 struct wps_token *token,
378 struct wps_data *wps_data)
380 const char* filename;
381 const char* id;
382 int x = 0,y = 0, subimages = 1;
383 struct gui_img *img;
385 /* format: %x(n,filename.bmp[,x,y])
386 or %xl(n,filename.bmp[,x,y])
387 or %xl(n,filename.bmp[,x,y,num_subimages])
390 id = get_param_text(element, 0);
391 filename = get_param_text(element, 1);
392 /* x,y,num_subimages handling:
393 * If all 3 are left out use sane defaults.
394 * If there are 2 params it must be x,y
395 * if there is only 1 param it must be the num_subimages
397 if (element->params_count == 3)
398 subimages = get_param(element, 2)->data.number;
399 else if (element->params_count > 3)
401 x = get_param(element, 2)->data.number;
402 y = get_param(element, 3)->data.number;
403 if (element->params_count == 5)
404 subimages = get_param(element, 4)->data.number;
406 /* check the image number and load state */
407 if(skin_find_item(id, SKIN_FIND_IMAGE, wps_data))
409 /* Invalid image ID */
410 return WPS_ERROR_INVALID_PARAM;
412 img = skin_buffer_alloc(sizeof(*img));
413 if (!img)
414 return WPS_ERROR_INVALID_PARAM;
415 /* save a pointer to the filename */
416 img->bm.data = (char*)filename;
417 img->label = PTRTOSKINOFFSET(skin_buffer, (void*)id);
418 img->x = x;
419 img->y = y;
420 img->num_subimages = subimages;
421 img->display = -1;
422 img->using_preloaded_icons = false;
423 img->buflib_handle = -1;
424 img->is_9_segment = false;
426 /* save current viewport */
427 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
429 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
430 token->value.data = PTRTOSKINOFFSET(skin_buffer, img);
432 if (!strcmp(img->bm.data, "__list_icons__"))
434 img->num_subimages = Icon_Last_Themeable;
435 img->using_preloaded_icons = true;
438 struct skin_token_list *item = new_skin_token_list_item(NULL, img);
439 if (!item)
440 return WPS_ERROR_INVALID_PARAM;
441 add_to_ll_chain(&wps_data->images, item);
443 return 0;
445 struct skin_font {
446 int id; /* the id from font_load */
447 char *name; /* filename without path and extension */
448 int glyphs; /* how many glyphs to reserve room for */
450 static struct skin_font skinfonts[MAXUSERFONTS];
451 static int parse_font_load(struct skin_element *element,
452 struct wps_token *token,
453 struct wps_data *wps_data)
455 (void)wps_data; (void)token;
456 int id = get_param(element, 0)->data.number;
457 char *filename = get_param_text(element, 1);
458 int glyphs;
459 char *ptr;
461 if(element->params_count > 2)
462 glyphs = get_param(element, 2)->data.number;
463 else
464 glyphs = global_settings.glyphs_to_cache;
465 if (id < 2)
467 DEBUGF("font id must be >= 2 (%d)\n", id);
468 return 1;
470 #if defined(DEBUG) || defined(SIMULATOR)
471 if (skinfonts[id-2].name != NULL)
473 DEBUGF("font id %d already being used\n", id);
475 #endif
476 /* make sure the filename contains .fnt,
477 * we dont actually use it, but require it anyway */
478 ptr = strchr(filename, '.');
479 if (!ptr || strncmp(ptr, ".fnt", 4))
480 return WPS_ERROR_INVALID_PARAM;
481 skinfonts[id-2].id = -1;
482 skinfonts[id-2].name = filename;
483 skinfonts[id-2].glyphs = glyphs;
485 return 0;
489 #ifdef HAVE_LCD_BITMAP
491 static int parse_playlistview(struct skin_element *element,
492 struct wps_token *token,
493 struct wps_data *wps_data)
495 (void)wps_data;
496 struct playlistviewer *viewer = skin_buffer_alloc(sizeof(*viewer));
497 if (!viewer)
498 return WPS_ERROR_INVALID_PARAM;
499 viewer->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
500 viewer->show_icons = true;
501 viewer->start_offset = get_param(element, 0)->data.number;
502 viewer->line = PTRTOSKINOFFSET(skin_buffer, get_param_code(element, 1));
504 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)viewer);
506 return 0;
508 #endif
509 #ifdef HAVE_LCD_COLOR
510 static int parse_viewport_gradient_setup(struct skin_element *element,
511 struct wps_token *token,
512 struct wps_data *wps_data)
514 (void)wps_data;
515 struct gradient_config *cfg;
516 if (element->params_count < 2) /* only start and end are required */
517 return 1;
518 cfg = skin_buffer_alloc(sizeof(*cfg));
519 if (!cfg)
520 return 1;
521 if (!parse_color(curr_screen, get_param_text(element, 0), &cfg->start) ||
522 !parse_color(curr_screen, get_param_text(element, 1), &cfg->end))
523 return 1;
524 if (element->params_count > 2)
526 if (!parse_color(curr_screen, get_param_text(element, 2), &cfg->text))
527 return 1;
529 else
531 cfg->text = curr_vp->vp.fg_pattern;
534 token->value.data = PTRTOSKINOFFSET(skin_buffer, cfg);
535 return 0;
537 #endif
539 static int parse_listitem(struct skin_element *element,
540 struct wps_token *token,
541 struct wps_data *wps_data)
543 (void)wps_data;
544 struct listitem *li = skin_buffer_alloc(sizeof(*li));
545 if (!li)
546 return 1;
547 token->value.data = PTRTOSKINOFFSET(skin_buffer, li);
548 if (element->params_count == 0)
549 li->offset = 0;
550 else
552 li->offset = get_param(element, 0)->data.number;
553 if (element->params_count > 1)
554 li->wrap = strcasecmp(get_param_text(element, 1), "nowrap") != 0;
555 else
556 li->wrap = true;
558 return 0;
561 static int parse_listitemviewport(struct skin_element *element,
562 struct wps_token *token,
563 struct wps_data *wps_data)
565 #ifndef __PCTOOL__
566 struct listitem_viewport_cfg *cfg = skin_buffer_alloc(sizeof(*cfg));
567 if (!cfg)
568 return -1;
569 cfg->data = wps_data;
570 cfg->tile = false;
571 cfg->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
572 cfg->width = -1;
573 cfg->height = -1;
574 if (!isdefault(get_param(element, 1)))
575 cfg->width = get_param(element, 1)->data.number;
576 if (!isdefault(get_param(element, 2)))
577 cfg->height = get_param(element, 2)->data.number;
578 if (element->params_count > 3 &&
579 !strcmp(get_param_text(element, 3), "tile"))
580 cfg->tile = true;
581 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)cfg);
582 #endif
583 return 0;
586 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
587 static int parse_viewporttextstyle(struct skin_element *element,
588 struct wps_token *token,
589 struct wps_data *wps_data)
591 (void)wps_data;
592 int style;
593 char *mode = get_param_text(element, 0);
594 unsigned colour;
596 if (!strcmp(mode, "invert"))
598 style = STYLE_INVERT;
600 else if (!strcmp(mode, "colour") || !strcmp(mode, "color"))
602 if (element->params_count < 2 ||
603 !parse_color(curr_screen, get_param_text(element, 1), &colour))
604 return 1;
605 style = STYLE_COLORED|(STYLE_COLOR_MASK&colour);
607 #ifdef HAVE_LCD_COLOR
608 else if (!strcmp(mode, "gradient"))
610 int num_lines;
611 if (element->params_count < 2)
612 num_lines = 1;
613 else /* atoi() instead of using a number in the parser is because [si]
614 * will select the number for something which looks like a colour
615 * making the "colour" case (above) harder to parse */
616 num_lines = atoi(get_param_text(element, 1));
617 style = STYLE_GRADIENT|NUMLN_PACK(num_lines)|CURLN_PACK(0);
619 #endif
620 else if (!strcmp(mode, "clear"))
622 style = STYLE_DEFAULT;
624 else
625 return 1;
626 token->value.l = style;
627 return 0;
630 static int parse_drawrectangle( struct skin_element *element,
631 struct wps_token *token,
632 struct wps_data *wps_data)
634 (void)wps_data;
635 struct draw_rectangle *rect = skin_buffer_alloc(sizeof(*rect));
637 if (!rect)
638 return -1;
640 rect->x = get_param(element, 0)->data.number;
641 rect->y = get_param(element, 1)->data.number;
643 if (isdefault(get_param(element, 2)))
644 rect->width = curr_vp->vp.width - rect->x;
645 else
646 rect->width = get_param(element, 2)->data.number;
648 if (isdefault(get_param(element, 3)))
649 rect->height = curr_vp->vp.height - rect->y;
650 else
651 rect->height = get_param(element, 3)->data.number;
653 rect->start_colour = curr_vp->vp.fg_pattern;
654 rect->end_colour = curr_vp->vp.fg_pattern;
656 if (element->params_count > 4)
658 if (!parse_color(curr_screen, get_param_text(element, 4),
659 &rect->start_colour))
660 return -1;
661 rect->end_colour = rect->start_colour;
663 if (element->params_count > 5)
665 if (!parse_color(curr_screen, get_param_text(element, 5),
666 &rect->end_colour))
667 return -1;
669 token->value.data = PTRTOSKINOFFSET(skin_buffer, rect);
671 return 0;
674 static int parse_viewportcolour(struct skin_element *element,
675 struct wps_token *token,
676 struct wps_data *wps_data)
678 (void)wps_data;
679 struct skin_tag_parameter *param = get_param(element, 0);
680 struct viewport_colour *colour = skin_buffer_alloc(sizeof(*colour));
681 if (!colour)
682 return -1;
683 if (isdefault(param))
685 colour->colour = get_viewport_default_colour(curr_screen,
686 token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
688 else
690 if (!parse_color(curr_screen, SKINOFFSETTOPTR(skin_buffer, param->data.text),
691 &colour->colour))
692 return -1;
694 colour->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
695 token->value.data = PTRTOSKINOFFSET(skin_buffer, colour);
696 if (element->line == curr_viewport_element->line)
698 if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
700 curr_vp->start_fgcolour = colour->colour;
701 curr_vp->vp.fg_pattern = colour->colour;
703 else
705 curr_vp->start_bgcolour = colour->colour;
706 curr_vp->vp.bg_pattern = colour->colour;
709 return 0;
712 static int parse_image_special(struct skin_element *element,
713 struct wps_token *token,
714 struct wps_data *wps_data)
716 (void)wps_data; /* kill warning */
717 (void)token;
719 #if LCD_DEPTH > 1
720 char *filename;
721 if (token->type == SKIN_TOKEN_IMAGE_BACKDROP)
723 if (isdefault(get_param(element, 0)))
725 filename = "-";
727 else
729 filename = get_param_text(element, 0);
730 /* format: %X(filename.bmp) or %X(d) */
731 if (!strcmp(filename, "d"))
732 filename = NULL;
734 backdrop_filename = filename;
736 #endif
738 return 0;
740 #endif
742 #endif /* HAVE_LCD_BITMAP */
744 static int parse_progressbar_tag(struct skin_element* element,
745 struct wps_token *token,
746 struct wps_data *wps_data);
748 static int parse_setting_and_lang(struct skin_element *element,
749 struct wps_token *token,
750 struct wps_data *wps_data)
752 /* NOTE: both the string validations that happen in here will
753 * automatically PASS on checkwps because its too hard to get
754 * settings_list.c and english.lang built for it.
755 * If that ever changes remove the #ifndef __PCTOOL__'s here
757 (void)wps_data;
758 char *temp = get_param_text(element, 0);
759 int i;
761 if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
763 #ifndef __PCTOOL__
764 i = lang_english_to_id(temp);
765 if (i < 0)
766 return WPS_ERROR_INVALID_PARAM;
767 #endif
769 else if (element->params_count > 1)
771 if (element->params_count > 4)
772 return parse_progressbar_tag(element, token, wps_data);
773 else
774 return WPS_ERROR_INVALID_PARAM;
776 else
778 #ifndef __PCTOOL__
779 if (find_setting_by_cfgname(temp, &i) == NULL)
780 return WPS_ERROR_INVALID_PARAM;
781 #endif
783 /* Store the setting number */
784 token->value.i = i;
785 return 0;
788 static int parse_logical_andor(struct skin_element *element,
789 struct wps_token *token,
790 struct wps_data *wps_data)
792 (void)wps_data;
793 token->value.data = PTRTOSKINOFFSET(skin_buffer, element);
794 return 0;
797 static int parse_logical_if(struct skin_element *element,
798 struct wps_token *token,
799 struct wps_data *wps_data)
801 (void)wps_data;
802 char *op = get_param_text(element, 1);
803 struct logical_if *lif = skin_buffer_alloc(sizeof(*lif));
804 if (!lif)
805 return -1;
806 token->value.data = PTRTOSKINOFFSET(skin_buffer, lif);
807 lif->token = get_param_code(element, 0)->data;
809 if (!strncmp(op, "=", 1))
810 lif->op = IF_EQUALS;
811 else if (!strncmp(op, "!=", 2))
812 lif->op = IF_NOTEQUALS;
813 else if (!strncmp(op, ">=", 2))
814 lif->op = IF_GREATERTHAN_EQ;
815 else if (!strncmp(op, "<=", 2))
816 lif->op = IF_LESSTHAN_EQ;
817 else if (!strncmp(op, ">", 2))
818 lif->op = IF_GREATERTHAN;
819 else if (!strncmp(op, "<", 1))
820 lif->op = IF_LESSTHAN;
822 memcpy(&lif->operand, get_param(element, 2), sizeof(lif->operand));
823 if (element->params_count > 3)
824 lif->num_options = get_param(element, 3)->data.number;
825 else
826 lif->num_options = TOKEN_VALUE_ONLY;
827 return 0;
831 static int parse_timeout_tag(struct skin_element *element,
832 struct wps_token *token,
833 struct wps_data *wps_data)
835 (void)wps_data;
836 int val = 0;
837 if (element->params_count == 0)
839 switch (token->type)
841 case SKIN_TOKEN_SUBLINE_TIMEOUT:
842 return -1;
843 case SKIN_TOKEN_BUTTON_VOLUME:
844 case SKIN_TOKEN_TRACK_STARTING:
845 case SKIN_TOKEN_TRACK_ENDING:
846 val = 10;
847 break;
848 default:
849 break;
852 else
853 val = get_param(element, 0)->data.number;
854 token->value.i = val * TIMEOUT_UNIT;
855 return 0;
858 static int parse_substring_tag(struct skin_element* element,
859 struct wps_token *token,
860 struct wps_data *wps_data)
862 (void)wps_data;
863 struct substring *ss = skin_buffer_alloc(sizeof(*ss));
864 if (!ss)
865 return 1;
866 ss->start = get_param(element, 0)->data.number;
867 if (get_param(element, 1)->type == DEFAULT)
868 ss->length = -1;
869 else
870 ss->length = get_param(element, 1)->data.number;
871 ss->token = get_param_code(element, 2)->data;
872 if (element->params_count > 3)
873 ss->expect_number = !strcmp(get_param_text(element, 3), "number");
874 else
875 ss->expect_number = false;
876 token->value.data = PTRTOSKINOFFSET(skin_buffer, ss);
877 return 0;
880 static int parse_progressbar_tag(struct skin_element* element,
881 struct wps_token *token,
882 struct wps_data *wps_data)
884 #ifdef HAVE_LCD_BITMAP
885 struct progressbar *pb;
886 struct viewport *vp = &curr_vp->vp;
887 struct skin_tag_parameter *param = get_param(element, 0);
888 int curr_param = 0;
889 char *image_filename = NULL;
890 #ifdef HAVE_TOUCHSCREEN
891 bool suppress_touchregion = false;
892 #endif
894 if (element->params_count == 0 &&
895 element->tag->type != SKIN_TOKEN_PROGRESSBAR)
896 return 0; /* nothing to do */
897 pb = skin_buffer_alloc(sizeof(*pb));
899 token->value.data = PTRTOSKINOFFSET(skin_buffer, pb);
901 if (!pb)
902 return WPS_ERROR_INVALID_PARAM;
903 pb->vp = PTRTOSKINOFFSET(skin_buffer, vp);
904 pb->follow_lang_direction = follow_lang_direction > 0;
905 pb->nofill = false;
906 pb->nobar = false;
907 pb->image = PTRTOSKINOFFSET(skin_buffer, NULL);
908 pb->slider = PTRTOSKINOFFSET(skin_buffer, NULL);
909 pb->backdrop = PTRTOSKINOFFSET(skin_buffer, NULL);
910 pb->setting_id = -1;
911 pb->invert_fill_direction = false;
912 pb->horizontal = true;
914 if (element->params_count == 0)
916 pb->x = 0;
917 pb->width = vp->width;
918 pb->height = SYSFONT_HEIGHT-2;
919 pb->y = -1; /* Will be computed during the rendering */
920 pb->type = element->tag->type;
921 return 0;
924 /* (x, y, width, height, ...) */
925 if (!isdefault(param))
926 pb->x = param->data.number;
927 else
928 pb->x = 0;
929 param++;
931 if (!isdefault(param))
932 pb->y = param->data.number;
933 else
934 pb->y = -1; /* computed at rendering */
935 param++;
937 if (!isdefault(param))
938 pb->width = param->data.number;
939 else
940 pb->width = vp->width - pb->x;
941 param++;
943 if (!isdefault(param))
945 /* A zero height makes no sense - reject it */
946 if (param->data.number == 0)
947 return WPS_ERROR_INVALID_PARAM;
949 pb->height = param->data.number;
951 else
953 if (vp->font > FONT_UI)
954 pb->height = -1; /* calculate at display time */
955 else
957 #ifndef __PCTOOL__
958 pb->height = font_get(vp->font)->height;
959 #else
960 pb->height = 8;
961 #endif
964 /* optional params, first is the image filename if it isnt recognised as a keyword */
966 curr_param = 4;
967 if (isdefault(get_param(element, curr_param)))
969 param++;
970 curr_param++;
973 pb->horizontal = pb->width > pb->height;
974 while (curr_param < element->params_count)
976 char* text;
977 param++;
978 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
979 if (!strcmp(text, "invert"))
980 pb->invert_fill_direction = true;
981 else if (!strcmp(text, "nofill"))
982 pb->nofill = true;
983 else if (!strcmp(text, "nobar"))
984 pb->nobar = true;
985 else if (!strcmp(text, "slider"))
987 if (curr_param+1 < element->params_count)
989 curr_param++;
990 param++;
991 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
992 pb->slider = PTRTOSKINOFFSET(skin_buffer,
993 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
995 else /* option needs the next param */
996 return -1;
998 else if (!strcmp(text, "image"))
1000 if (curr_param+1 < element->params_count)
1002 curr_param++;
1003 param++;
1004 image_filename = SKINOFFSETTOPTR(skin_buffer, param->data.text);
1006 else /* option needs the next param */
1007 return -1;
1009 else if (!strcmp(text, "backdrop"))
1011 if (curr_param+1 < element->params_count)
1013 curr_param++;
1014 param++;
1015 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
1016 pb->backdrop = PTRTOSKINOFFSET(skin_buffer,
1017 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
1020 else /* option needs the next param */
1021 return -1;
1023 else if (!strcmp(text, "vertical"))
1025 pb->horizontal = false;
1026 if (isdefault(get_param(element, 3)))
1027 pb->height = vp->height - pb->y;
1029 else if (!strcmp(text, "horizontal"))
1030 pb->horizontal = true;
1031 #ifdef HAVE_TOUCHSCREEN
1032 else if (!strcmp(text, "notouch"))
1033 suppress_touchregion = true;
1034 #endif
1035 else if (token->type == SKIN_TOKEN_SETTING && !strcmp(text, "setting"))
1037 if (curr_param+1 < element->params_count)
1039 curr_param++;
1040 param++;
1041 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
1042 #ifndef __PCTOOL__
1043 if (find_setting_by_cfgname(text, &pb->setting_id) == NULL)
1044 return WPS_ERROR_INVALID_PARAM;
1045 #endif
1048 else if (curr_param == 4)
1049 image_filename = text;
1051 curr_param++;
1054 if (image_filename)
1056 pb->image = PTRTOSKINOFFSET(skin_buffer,
1057 skin_find_item(image_filename, SKIN_FIND_IMAGE, wps_data));
1058 if (!SKINOFFSETTOPTR(skin_buffer, pb->image)) /* load later */
1060 struct gui_img *img = skin_buffer_alloc(sizeof(*img));
1061 if (!img)
1062 return WPS_ERROR_INVALID_PARAM;
1063 /* save a pointer to the filename */
1064 img->bm.data = (char*)image_filename;
1065 img->label = PTRTOSKINOFFSET(skin_buffer, image_filename);
1066 img->x = 0;
1067 img->y = 0;
1068 img->num_subimages = 1;
1069 img->display = -1;
1070 img->using_preloaded_icons = false;
1071 img->buflib_handle = -1;
1072 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1073 struct skin_token_list *item = new_skin_token_list_item(NULL, img);
1074 if (!item)
1075 return WPS_ERROR_INVALID_PARAM;
1076 add_to_ll_chain(&wps_data->images, item);
1077 pb->image = PTRTOSKINOFFSET(skin_buffer, img);
1081 if (token->type == SKIN_TOKEN_VOLUME)
1082 token->type = SKIN_TOKEN_VOLUMEBAR;
1083 else if (token->type == SKIN_TOKEN_BATTERY_PERCENT)
1084 token->type = SKIN_TOKEN_BATTERY_PERCENTBAR;
1085 else if (token->type == SKIN_TOKEN_TUNER_RSSI)
1086 token->type = SKIN_TOKEN_TUNER_RSSI_BAR;
1087 else if (token->type == SKIN_TOKEN_PEAKMETER_LEFT)
1088 token->type = SKIN_TOKEN_PEAKMETER_LEFTBAR;
1089 else if (token->type == SKIN_TOKEN_PEAKMETER_RIGHT)
1090 token->type = SKIN_TOKEN_PEAKMETER_RIGHTBAR;
1091 else if (token->type == SKIN_TOKEN_LIST_NEEDS_SCROLLBAR)
1092 token->type = SKIN_TOKEN_LIST_SCROLLBAR;
1093 else if (token->type == SKIN_TOKEN_SETTING)
1094 token->type = SKIN_TOKEN_SETTINGBAR;
1095 pb->type = token->type;
1097 #ifdef HAVE_TOUCHSCREEN
1098 if (!suppress_touchregion &&
1099 (token->type == SKIN_TOKEN_VOLUMEBAR ||
1100 token->type == SKIN_TOKEN_PROGRESSBAR ||
1101 token->type == SKIN_TOKEN_SETTINGBAR))
1103 struct touchregion *region = skin_buffer_alloc(sizeof(*region));
1104 struct skin_token_list *item;
1105 int wpad, hpad;
1107 if (!region)
1108 return 0;
1110 if (token->type == SKIN_TOKEN_VOLUMEBAR)
1111 region->action = ACTION_TOUCH_VOLUME;
1112 else if (token->type == SKIN_TOKEN_SETTINGBAR)
1113 region->action = ACTION_TOUCH_SETTING;
1114 else
1115 region->action = ACTION_TOUCH_SCROLLBAR;
1117 /* try to add some extra space on either end to make pressing the
1118 * full bar easier. ~5% on either side
1120 wpad = pb->width * 5 / 100;
1121 if (wpad > 10)
1122 wpad = 10;
1123 hpad = pb->height * 5 / 100;
1124 if (hpad > 10)
1125 hpad = 10;
1127 region->x = pb->x - wpad;
1128 if (region->x < 0)
1129 region->x = 0;
1130 region->width = pb->width + 2 * wpad;
1131 if (region->x + region->width > curr_vp->vp.x + curr_vp->vp.width)
1132 region->width = curr_vp->vp.x + curr_vp->vp.width - region->x;
1134 region->y = pb->y - hpad;
1135 if (region->y < 0)
1136 region->y = 0;
1137 region->height = pb->height + 2 * hpad;
1138 if (region->y + region->height > curr_vp->vp.y + curr_vp->vp.height)
1139 region->height = curr_vp->vp.y + curr_vp->vp.height - region->y;
1141 region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp);
1142 region->reverse_bar = false;
1143 region->allow_while_locked = false;
1144 region->press_length = PRESS;
1145 region->last_press = 0xffff;
1146 region->armed = false;
1147 region->bar = PTRTOSKINOFFSET(skin_buffer, pb);
1149 item = new_skin_token_list_item(NULL, region);
1150 if (!item)
1151 return WPS_ERROR_INVALID_PARAM;
1152 add_to_ll_chain(&wps_data->touchregions, item);
1154 #endif
1156 return 0;
1158 #else
1159 (void)element;
1160 if (token->type == SKIN_TOKEN_PROGRESSBAR ||
1161 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR)
1163 wps_data->full_line_progressbar =
1164 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR;
1166 return 0;
1168 #endif
1171 #ifdef HAVE_ALBUMART
1172 static int parse_albumart_load(struct skin_element* element,
1173 struct wps_token *token,
1174 struct wps_data *wps_data)
1176 struct dim dimensions;
1177 int albumart_slot;
1178 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction;
1179 struct skin_albumart *aa = skin_buffer_alloc(sizeof(*aa));
1180 (void)token; /* silence warning */
1181 if (!aa)
1182 return -1;
1184 /* reset albumart info in wps */
1185 aa->width = -1;
1186 aa->height = -1;
1187 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1188 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1190 aa->x = get_param(element, 0)->data.number;
1191 aa->y = get_param(element, 1)->data.number;
1192 aa->width = get_param(element, 2)->data.number;
1193 aa->height = get_param(element, 3)->data.number;
1195 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1196 aa->draw_handle = -1;
1198 /* if we got here, we parsed everything ok .. ! */
1199 if (aa->width < 0)
1200 aa->width = 0;
1202 if (aa->height < 0)
1203 aa->height = 0;
1205 if (swap_for_rtl)
1206 aa->x = (curr_vp->vp.width - aa->width - aa->x);
1208 aa->state = WPS_ALBUMART_LOAD;
1209 wps_data->albumart = PTRTOSKINOFFSET(skin_buffer, aa);
1211 dimensions.width = aa->width;
1212 dimensions.height = aa->height;
1214 albumart_slot = playback_claim_aa_slot(&dimensions);
1216 if (0 <= albumart_slot)
1217 wps_data->playback_aa_slot = albumart_slot;
1219 if (element->params_count > 4 && !isdefault(get_param(element, 4)))
1221 switch (*get_param_text(element, 4))
1223 case 'l':
1224 case 'L':
1225 if (swap_for_rtl)
1226 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1227 else
1228 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1229 break;
1230 case 'c':
1231 case 'C':
1232 aa->xalign = WPS_ALBUMART_ALIGN_CENTER;
1233 break;
1234 case 'r':
1235 case 'R':
1236 if (swap_for_rtl)
1237 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1238 else
1239 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1240 break;
1243 if (element->params_count > 5 && !isdefault(get_param(element, 5)))
1245 switch (*get_param_text(element, 5))
1247 case 't':
1248 case 'T':
1249 aa->yalign = WPS_ALBUMART_ALIGN_TOP;
1250 break;
1251 case 'c':
1252 case 'C':
1253 aa->yalign = WPS_ALBUMART_ALIGN_CENTER;
1254 break;
1255 case 'b':
1256 case 'B':
1257 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM;
1258 break;
1261 return 0;
1264 #endif /* HAVE_ALBUMART */
1265 #ifdef HAVE_SKIN_VARIABLES
1266 static struct skin_var* find_or_add_var(const char* label,
1267 struct wps_data *data)
1269 struct skin_var* ret = skin_find_item(label, SKIN_VARIABLE, data);
1270 if (ret)
1271 return ret;
1273 ret = skin_buffer_alloc(sizeof(*ret));
1274 if (!ret)
1275 return ret;
1276 ret->label = PTRTOSKINOFFSET(skin_buffer, label);
1277 ret->value = 1;
1278 ret->last_changed = 0xffff;
1279 struct skin_token_list *item = new_skin_token_list_item(NULL, ret);
1280 if (!item)
1281 return NULL;
1282 add_to_ll_chain(&data->skinvars, item);
1283 return ret;
1285 static int parse_skinvar( struct skin_element *element,
1286 struct wps_token *token,
1287 struct wps_data *wps_data)
1289 const char* label = get_param_text(element, 0);
1290 struct skin_var* var = find_or_add_var(label, wps_data);
1291 if (!var)
1292 return WPS_ERROR_INVALID_PARAM;
1293 switch (token->type)
1295 case SKIN_TOKEN_VAR_GETVAL:
1296 token->value.data = PTRTOSKINOFFSET(skin_buffer, var);
1297 return 0;
1298 case SKIN_TOKEN_VAR_SET:
1300 struct skin_var_changer *data = skin_buffer_alloc(sizeof(*data));
1301 if (!data)
1302 return WPS_ERROR_INVALID_PARAM;
1303 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1304 if (!isdefault(get_param(element, 2)))
1305 data->newval = get_param(element, 2)->data.number;
1306 else if (strcmp(get_param_text(element, 1), "touch"))
1307 return WPS_ERROR_INVALID_PARAM;
1308 data->max = 0;
1309 if (!strcmp(get_param_text(element, 1), "set"))
1310 data->direct = true;
1311 else if (!strcmp(get_param_text(element, 1), "inc"))
1313 data->direct = false;
1315 else if (!strcmp(get_param_text(element, 1), "dec"))
1317 data->direct = false;
1318 data->newval *= -1;
1320 else if (!strcmp(get_param_text(element, 1), "touch"))
1322 data->direct = false;
1323 data->newval = 0;
1325 if (element->params_count > 3)
1326 data->max = get_param(element, 3)->data.number;
1327 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1329 return 0;
1330 case SKIN_TOKEN_VAR_TIMEOUT:
1332 struct skin_var_lastchange *data = skin_buffer_alloc(sizeof(*data));
1333 if (!data)
1334 return WPS_ERROR_INVALID_PARAM;
1335 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1336 data->timeout = 10;
1337 if (element->params_count > 1)
1338 data->timeout = get_param(element, 1)->data.number;
1339 data->timeout *= TIMEOUT_UNIT;
1340 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1342 default:
1343 return 0;
1346 #endif /* HAVE_SKIN_VARIABLES */
1347 #ifdef HAVE_TOUCHSCREEN
1348 static int parse_lasttouch(struct skin_element *element,
1349 struct wps_token *token,
1350 struct wps_data *wps_data)
1352 struct touchregion_lastpress *data = skin_buffer_alloc(sizeof(*data));
1353 int i;
1354 struct touchregion *region = NULL;
1355 if (!data)
1356 return WPS_ERROR_INVALID_PARAM;
1358 data->timeout = 10;
1360 for (i=0; i<element->params_count; i++)
1362 if (get_param(element, i)->type == STRING)
1363 region = skin_find_item(get_param_text(element, i),
1364 SKIN_FIND_TOUCHREGION, wps_data);
1365 else if (get_param(element, i)->type == INTEGER ||
1366 get_param(element, i)->type == DECIMAL)
1367 data->timeout = get_param(element, i)->data.number;
1370 data->region = PTRTOSKINOFFSET(skin_buffer, region);
1371 data->timeout *= TIMEOUT_UNIT;
1372 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1373 return 0;
1376 struct touchaction {const char* s; int action;};
1377 static const struct touchaction touchactions[] = {
1378 /* generic actions, convert to screen actions on use */
1379 {"none", ACTION_TOUCHSCREEN_IGNORE},{"lock", ACTION_TOUCH_SOFTLOCK },
1380 {"prev", ACTION_STD_PREV }, {"next", ACTION_STD_NEXT },
1381 {"hotkey", ACTION_STD_HOTKEY}, {"select", ACTION_STD_OK },
1382 {"menu", ACTION_STD_MENU }, {"cancel", ACTION_STD_CANCEL },
1383 {"contextmenu", ACTION_STD_CONTEXT},{"quickscreen", ACTION_STD_QUICKSCREEN },
1385 /* list/tree actions */
1386 { "resumeplayback", ACTION_TREE_WPS}, /* returns to previous music, WPS/FM */
1387 /* not really WPS specific, but no equivilant ACTION_STD_* */
1388 {"voldown", ACTION_WPS_VOLDOWN}, {"volup", ACTION_WPS_VOLUP},
1389 {"mute", ACTION_TOUCH_MUTE },
1391 /* generic settings changers */
1392 {"setting_inc", ACTION_SETTINGS_INC}, {"setting_dec", ACTION_SETTINGS_DEC},
1393 {"setting_set", ACTION_SETTINGS_SET},
1395 /* WPS specific actions */
1396 {"rwd", ACTION_WPS_SEEKBACK }, {"ffwd", ACTION_WPS_SEEKFWD },
1397 {"wps_prev", ACTION_WPS_SKIPPREV }, {"wps_next", ACTION_WPS_SKIPNEXT },
1398 {"browse", ACTION_WPS_BROWSE },
1399 {"play", ACTION_WPS_PLAY }, {"stop", ACTION_WPS_STOP },
1400 {"shuffle", ACTION_TOUCH_SHUFFLE }, {"repmode", ACTION_TOUCH_REPMODE },
1401 {"pitch", ACTION_WPS_PITCHSCREEN}, {"trackinfo", ACTION_WPS_ID3SCREEN },
1402 {"playlist", ACTION_WPS_VIEW_PLAYLIST },
1403 {"listbookmarks", ACTION_WPS_LIST_BOOKMARKS },
1404 {"createbookmark", ACTION_WPS_CREATE_BOOKMARK },
1406 #if CONFIG_TUNER
1407 /* FM screen actions */
1408 /* Also allow browse, play, stop from WPS codes */
1409 {"mode", ACTION_FM_MODE }, {"record", ACTION_FM_RECORD },
1410 {"presets", ACTION_FM_PRESET},
1411 #endif
1414 static int touchregion_setup_setting(struct skin_element *element, int param_no,
1415 struct touchregion *region)
1417 #ifndef __PCTOOL__
1418 int p = param_no;
1419 char *name = get_param_text(element, p++);
1420 int j;
1422 region->setting_data.setting = find_setting_by_cfgname(name, &j);
1423 if (region->setting_data.setting == NULL)
1424 return WPS_ERROR_INVALID_PARAM;
1426 if (region->action == ACTION_SETTINGS_SET)
1428 char* text;
1429 int temp;
1430 struct touchsetting *setting =
1431 &region->setting_data;
1432 if (element->params_count < p+1)
1433 return -1;
1435 text = get_param_text(element, p++);
1436 switch (settings[j].flags&F_T_MASK)
1438 case F_T_CUSTOM:
1439 setting->value.text = PTRTOSKINOFFSET(skin_buffer, text);
1440 break;
1441 case F_T_INT:
1442 case F_T_UINT:
1443 if (settings[j].cfg_vals == NULL)
1445 setting->value.number = atoi(text);
1447 else if (cfg_string_to_int(j, &temp, text))
1449 if (settings[j].flags&F_TABLE_SETTING)
1450 setting->value.number =
1451 settings[j].table_setting->values[temp];
1452 else
1453 setting->value.number = temp;
1455 else
1456 return -1;
1457 break;
1458 case F_T_BOOL:
1459 if (cfg_string_to_int(j, &temp, text))
1461 setting->value.number = temp;
1463 else
1464 return -1;
1465 break;
1466 default:
1467 return -1;
1470 return p-param_no;
1471 #endif /* __PCTOOL__ */
1472 return 0;
1475 static int parse_touchregion(struct skin_element *element,
1476 struct wps_token *token,
1477 struct wps_data *wps_data)
1479 (void)token;
1480 unsigned i, imax;
1481 int p;
1482 struct touchregion *region = NULL;
1483 const char *action;
1484 const char pb_string[] = "progressbar";
1485 const char vol_string[] = "volume";
1487 /* format: %T([label,], x,y,width,height,action[, ...])
1488 * if action starts with & the area must be held to happen
1492 region = skin_buffer_alloc(sizeof(*region));
1493 if (!region)
1494 return WPS_ERROR_INVALID_PARAM;
1496 /* should probably do some bounds checking here with the viewport... but later */
1497 region->action = ACTION_NONE;
1499 if (get_param(element, 0)->type == STRING)
1501 region->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
1502 p = 1;
1503 /* "[SI]III[SI]|SS" is the param list. There MUST be 4 numbers
1504 * followed by at least one string. Verify that here */
1505 if (element->params_count < 6 ||
1506 get_param(element, 4)->type != INTEGER)
1507 return WPS_ERROR_INVALID_PARAM;
1509 else
1511 region->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1512 p = 0;
1515 region->x = get_param(element, p++)->data.number;
1516 region->y = get_param(element, p++)->data.number;
1517 region->width = get_param(element, p++)->data.number;
1518 region->height = get_param(element, p++)->data.number;
1519 region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp);
1520 region->armed = false;
1521 region->reverse_bar = false;
1522 region->value = 0;
1523 region->last_press = 0xffff;
1524 region->press_length = PRESS;
1525 region->allow_while_locked = false;
1526 region->bar = PTRTOSKINOFFSET(skin_buffer, NULL);
1527 action = get_param_text(element, p++);
1529 /* figure out the action */
1530 if(!strcmp(pb_string, action))
1531 region->action = ACTION_TOUCH_SCROLLBAR;
1532 else if(!strcmp(vol_string, action))
1533 region->action = ACTION_TOUCH_VOLUME;
1534 else
1536 imax = ARRAYLEN(touchactions);
1537 for (i = 0; i < imax; i++)
1539 /* try to match with one of our touchregion screens */
1540 if (!strcmp(touchactions[i].s, action))
1542 region->action = touchactions[i].action;
1543 if (region->action == ACTION_SETTINGS_INC ||
1544 region->action == ACTION_SETTINGS_DEC ||
1545 region->action == ACTION_SETTINGS_SET)
1547 int val;
1548 if (element->params_count < p+1)
1549 return WPS_ERROR_INVALID_PARAM;
1550 val = touchregion_setup_setting(element, p, region);
1551 if (val < 0)
1552 return WPS_ERROR_INVALID_PARAM;
1553 p += val;
1555 break;
1558 if (region->action == ACTION_NONE)
1559 return WPS_ERROR_INVALID_PARAM;
1561 while (p < element->params_count)
1563 char* param = get_param_text(element, p++);
1564 if (!strcmp(param, "allow_while_locked"))
1565 region->allow_while_locked = true;
1566 else if (!strcmp(param, "reverse_bar"))
1567 region->reverse_bar = true;
1568 else if (!strcmp(param, "repeat_press"))
1569 region->press_length = REPEAT;
1570 else if (!strcmp(param, "long_press"))
1571 region->press_length = LONG_PRESS;
1573 struct skin_token_list *item = new_skin_token_list_item(NULL, region);
1574 if (!item)
1575 return WPS_ERROR_INVALID_PARAM;
1576 add_to_ll_chain(&wps_data->touchregions, item);
1578 if (region->action == ACTION_TOUCH_MUTE)
1580 region->value = global_settings.volume;
1584 return 0;
1586 #endif
1588 static bool check_feature_tag(const int type)
1590 switch (type)
1592 case SKIN_TOKEN_RTC_PRESENT:
1593 #if CONFIG_RTC
1594 return true;
1595 #else
1596 return false;
1597 #endif
1598 case SKIN_TOKEN_HAVE_RECORDING:
1599 #ifdef HAVE_RECORDING
1600 return true;
1601 #else
1602 return false;
1603 #endif
1604 case SKIN_TOKEN_HAVE_TUNER:
1605 #if CONFIG_TUNER
1606 if (radio_hardware_present())
1607 return true;
1608 #endif
1609 return false;
1610 case SKIN_TOKEN_HAVE_TOUCH:
1611 #ifdef HAVE_TOUCHSCREEN
1612 return true;
1613 #else
1614 return false;
1615 #endif
1617 #if CONFIG_TUNER
1618 case SKIN_TOKEN_HAVE_RDS:
1619 #ifdef HAVE_RDS_CAP
1620 return true;
1621 #else
1622 return false;
1623 #endif /* HAVE_RDS_CAP */
1624 #endif /* CONFIG_TUNER */
1625 default: /* not a tag we care about, just don't skip */
1626 return true;
1630 /* This is used to free any buflib allocations before the rest of
1631 * wps_data is reset.
1632 * The call to this in settings_apply_skins() is the last chance to do
1633 * any core_free()'s before wps_data is trashed and those handles lost
1635 void skin_data_free_buflib_allocs(struct wps_data *wps_data)
1637 if (wps_data->wps_loaded)
1638 skin_buffer = get_skin_buffer(wps_data);
1639 #ifdef HAVE_LCD_BITMAP
1640 #ifndef __PCTOOL__
1641 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1642 int *font_ids = SKINOFFSETTOPTR(skin_buffer, wps_data->font_ids);
1643 while (list)
1645 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1646 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1647 if (img->buflib_handle > 0)
1648 core_free(img->buflib_handle);
1649 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1651 wps_data->images = PTRTOSKINOFFSET(skin_buffer, NULL);
1652 if (font_ids != NULL)
1654 while (wps_data->font_count > 0)
1655 font_unload(font_ids[--wps_data->font_count]);
1657 wps_data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1658 if (wps_data->buflib_handle > 0)
1659 core_free(wps_data->buflib_handle);
1660 wps_data->buflib_handle = -1;
1661 #endif
1662 #endif
1666 * initial setup of wps_data; does reset everything
1667 * except fields which need to survive, i.e.
1668 * Also called if the load fails
1670 static void skin_data_reset(struct wps_data *wps_data)
1672 skin_data_free_buflib_allocs(wps_data);
1673 #ifdef HAVE_LCD_BITMAP
1674 wps_data->images = INVALID_OFFSET;
1675 #endif
1676 wps_data->tree = INVALID_OFFSET;
1677 #ifdef HAVE_BACKDROP_IMAGE
1678 if (wps_data->backdrop_id >= 0)
1679 skin_backdrop_unload(wps_data->backdrop_id);
1680 backdrop_filename = NULL;
1681 #endif
1682 #ifdef HAVE_TOUCHSCREEN
1683 wps_data->touchregions = INVALID_OFFSET;
1684 #endif
1685 #ifdef HAVE_SKIN_VARIABLES
1686 wps_data->skinvars = INVALID_OFFSET;
1687 #endif
1688 #ifdef HAVE_ALBUMART
1689 wps_data->albumart = INVALID_OFFSET;
1690 if (wps_data->playback_aa_slot >= 0)
1692 playback_release_aa_slot(wps_data->playback_aa_slot);
1693 wps_data->playback_aa_slot = -1;
1695 #endif
1697 #ifdef HAVE_LCD_BITMAP
1698 wps_data->peak_meter_enabled = false;
1699 wps_data->wps_sb_tag = false;
1700 wps_data->show_sb_on_wps = false;
1701 #else /* HAVE_LCD_CHARCELLS */
1702 /* progress bars */
1703 int i;
1704 for (i = 0; i < 8; i++)
1706 wps_data->wps_progress_pat[i] = 0;
1708 wps_data->full_line_progressbar = false;
1709 #endif
1710 wps_data->wps_loaded = false;
1713 #ifdef HAVE_LCD_BITMAP
1714 #ifndef __PCTOOL__
1715 static int currently_loading_handle = -1;
1716 static int buflib_move_callback(int handle, void* current, void* new)
1718 (void)current;
1719 (void)new;
1720 if (handle == currently_loading_handle)
1721 return BUFLIB_CB_CANNOT_MOVE;
1722 return BUFLIB_CB_OK;
1724 static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
1725 static void lock_handle(int handle)
1727 currently_loading_handle = handle;
1729 static void unlock_handle(void)
1731 currently_loading_handle = -1;
1733 #endif
1735 static int load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir)
1737 (void)wps_data; /* only needed for remote targets */
1738 char img_path[MAX_PATH];
1739 int fd;
1740 int handle;
1741 get_image_filename(bitmap->data, bmpdir,
1742 img_path, sizeof(img_path));
1744 /* load the image */
1745 int format;
1746 #ifdef HAVE_REMOTE_LCD
1747 if (curr_screen == SCREEN_REMOTE)
1748 format = FORMAT_ANY|FORMAT_REMOTE;
1749 else
1750 #endif
1751 format = FORMAT_ANY|FORMAT_TRANSPARENT;
1753 fd = open(img_path, O_RDONLY);
1754 if (fd < 0)
1756 DEBUGF("Couldn't open %s\n", img_path);
1757 return fd;
1759 #ifndef __PCTOOL__
1760 size_t buf_size = read_bmp_fd(fd, bitmap, 0,
1761 format|FORMAT_RETURN_SIZE, NULL);
1762 handle = core_alloc_ex(bitmap->data, buf_size, &buflib_ops);
1763 if (handle <= 0)
1765 DEBUGF("Not enough skin buffer: need %zd more.\n",
1766 buf_size - skin_buffer_freespace());
1767 close(fd);
1768 return handle;
1770 _stats->buflib_handles++;
1771 _stats->images_size += buf_size;
1772 lseek(fd, 0, SEEK_SET);
1773 lock_handle(handle);
1774 bitmap->data = core_get_data(handle);
1775 int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
1776 bitmap->data = NULL; /* do this to force a crash later if the
1777 caller doesnt call core_get_data() */
1778 unlock_handle();
1779 close(fd);
1780 if (ret > 0)
1782 /* free unused alpha channel, if any */
1783 core_shrink(handle, core_get_data(handle), ret);
1784 return handle;
1786 else
1788 /* Abort if we can't load an image */
1789 DEBUGF("Couldn't load '%s'\n", img_path);
1790 core_free(handle);
1791 return -1;
1793 #else /* !__PCTOOL__ */
1794 close(fd);
1795 return 1;
1796 #endif
1799 static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
1801 struct skin_token_list *list;
1802 bool retval = true; /* return false if a single image failed to load */
1804 /* regular images */
1805 list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1806 while (list)
1808 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1809 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1810 if (img->bm.data)
1812 if (img->using_preloaded_icons)
1814 img->loaded = true;
1815 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
1817 else
1819 img->buflib_handle = load_skin_bmp(wps_data, &img->bm, bmpdir);
1820 img->loaded = img->buflib_handle >= 0;
1821 if (img->loaded)
1822 img->subimage_height = img->bm.height / img->num_subimages;
1823 else
1824 retval = false;
1827 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1830 #ifdef HAVE_BACKDROP_IMAGE
1831 wps_data->backdrop_id = skin_backdrop_assign(backdrop_filename, bmpdir, curr_screen);
1832 #endif /* has backdrop support */
1833 return retval;
1836 static bool skin_load_fonts(struct wps_data *data)
1838 /* don't spit out after the first failue to aid debugging */
1839 int id_array[MAXUSERFONTS];
1840 int font_count = 0;
1841 bool success = true;
1842 struct skin_element *vp_list;
1843 int font_id;
1844 /* walk though each viewport and assign its font */
1845 for(vp_list = SKINOFFSETTOPTR(skin_buffer, data->tree);
1846 vp_list; vp_list = SKINOFFSETTOPTR(skin_buffer, vp_list->next))
1848 /* first, find the viewports that have a non-sys/ui-font font */
1849 struct skin_viewport *skin_vp =
1850 SKINOFFSETTOPTR(skin_buffer, vp_list->data);
1851 struct viewport *vp = &skin_vp->vp;
1853 font_id = skin_vp->parsed_fontid;
1854 if (font_id == 1)
1855 { /* the usual case -> built-in fonts */
1856 vp->font = screens[curr_screen].getuifont();
1857 continue;
1859 else if (font_id <= 0)
1861 vp->font = FONT_SYSFIXED;
1862 continue;
1865 /* now find the corresponding skin_font */
1866 struct skin_font *font = &skinfonts[font_id-2];
1867 if (!font->name)
1869 if (success)
1871 DEBUGF("font %d not specified\n", font_id);
1873 success = false;
1874 continue;
1877 /* load the font - will handle loading the same font again if
1878 * multiple viewports use the same */
1879 if (font->id < 0)
1881 char path[MAX_PATH];
1882 snprintf(path, sizeof path, FONT_DIR "/%s", font->name);
1883 #ifndef __PCTOOL__
1884 font->id = font_load_ex(path, 0, skinfonts[font_id-2].glyphs);
1886 #else
1887 font->id = font_load(path);
1888 #endif
1889 //printf("[%d] %s -> %d\n",font_id, font->name, font->id);
1890 id_array[font_count++] = font->id;
1893 if (font->id < 0)
1895 DEBUGF("Unable to load font %d: '%s'\n", font_id, font->name);
1896 font->name = NULL; /* to stop trying to load it again if we fail */
1897 success = false;
1898 continue;
1901 /* finally, assign the font_id to the viewport */
1902 vp->font = font->id;
1904 if (font_count)
1906 int *font_ids = skin_buffer_alloc(font_count * sizeof(int));
1907 if (!success || font_ids == NULL)
1909 while (font_count > 0)
1911 if(id_array[--font_count] != -1)
1912 font_unload(id_array[font_count]);
1914 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1915 return false;
1917 memcpy(font_ids, id_array, sizeof(int)*font_count);
1918 data->font_count = font_count;
1919 data->font_ids = PTRTOSKINOFFSET(skin_buffer, font_ids);
1921 else
1923 data->font_count = 0;
1924 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1926 return success;
1929 #endif /* HAVE_LCD_BITMAP */
1930 static int convert_viewport(struct wps_data *data, struct skin_element* element)
1932 struct skin_viewport *skin_vp = skin_buffer_alloc(sizeof(*skin_vp));
1933 struct screen *display = &screens[curr_screen];
1935 if (!skin_vp)
1936 return CALLBACK_ERROR;
1938 skin_vp->hidden_flags = 0;
1939 skin_vp->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1940 skin_vp->is_infovp = false;
1941 skin_vp->parsed_fontid = 1;
1942 element->data = PTRTOSKINOFFSET(skin_buffer, skin_vp);
1943 curr_vp = skin_vp;
1944 curr_viewport_element = element;
1945 if (!first_viewport)
1946 first_viewport = element;
1948 viewport_set_defaults(&skin_vp->vp, curr_screen);
1950 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1951 skin_vp->output_to_backdrop_buffer = false;
1952 skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
1953 skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
1954 #endif
1955 #ifdef HAVE_LCD_COLOR
1956 skin_vp->start_gradient.start = skin_vp->vp.lss_pattern;
1957 skin_vp->start_gradient.end = skin_vp->vp.lse_pattern;
1958 skin_vp->start_gradient.text = skin_vp->vp.lst_pattern;
1959 #endif
1962 struct skin_tag_parameter *param = get_param(element, 0);
1963 if (element->params_count == 0) /* default viewport */
1965 if (data->tree < 0) /* first viewport in the skin */
1966 data->tree = PTRTOSKINOFFSET(skin_buffer, element);
1967 skin_vp->label = VP_DEFAULT_LABEL;
1968 return CALLBACK_OK;
1971 if (element->params_count == 6)
1973 if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
1975 skin_vp->is_infovp = true;
1976 if (isdefault(param))
1978 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1979 skin_vp->label = VP_DEFAULT_LABEL;
1981 else
1983 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1984 skin_vp->label = param->data.text;
1987 else
1989 skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN;
1990 skin_vp->label = param->data.text;
1992 param++;
1994 /* x */
1995 if (!isdefault(param))
1997 skin_vp->vp.x = param->data.number;
1998 if (param->data.number < 0)
1999 skin_vp->vp.x += display->lcdwidth;
2000 else if (param->type == PERCENT)
2001 skin_vp->vp.x = param->data.number * display->lcdwidth / 1000;
2003 param++;
2004 /* y */
2005 if (!isdefault(param))
2007 skin_vp->vp.y = param->data.number;
2008 if (param->data.number < 0)
2009 skin_vp->vp.y += display->lcdheight;
2010 else if (param->type == PERCENT)
2011 skin_vp->vp.y = param->data.number * display->lcdheight / 1000;
2013 param++;
2014 /* width */
2015 if (!isdefault(param))
2017 skin_vp->vp.width = param->data.number;
2018 if (param->data.number < 0)
2019 skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
2020 else if (param->type == PERCENT)
2021 skin_vp->vp.width = param->data.number * display->lcdwidth / 1000;
2023 else
2025 skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x;
2027 param++;
2028 /* height */
2029 if (!isdefault(param))
2031 skin_vp->vp.height = param->data.number;
2032 if (param->data.number < 0)
2033 skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
2034 else if (param->type == PERCENT)
2035 skin_vp->vp.height = param->data.number * display->lcdheight / 1000;
2037 else
2039 skin_vp->vp.height = display->lcdheight - skin_vp->vp.y;
2041 param++;
2042 #ifdef HAVE_LCD_BITMAP
2043 /* font */
2044 if (!isdefault(param))
2045 skin_vp->parsed_fontid = param->data.number;
2046 #endif
2047 if ((unsigned) skin_vp->vp.x >= (unsigned) display->lcdwidth ||
2048 skin_vp->vp.width + skin_vp->vp.x > display->lcdwidth ||
2049 (unsigned) skin_vp->vp.y >= (unsigned) display->lcdheight ||
2050 skin_vp->vp.height + skin_vp->vp.y > display->lcdheight)
2051 return CALLBACK_ERROR;
2053 /* Fix x position for RTL languages */
2054 if (follow_lang_direction && lang_is_rtl())
2055 skin_vp->vp.x = display->lcdwidth - skin_vp->vp.x - skin_vp->vp.width;
2057 return CALLBACK_OK;
2060 static int skin_element_callback(struct skin_element* element, void* data)
2062 struct wps_data *wps_data = (struct wps_data *)data;
2063 struct wps_token *token;
2064 parse_function function = NULL;
2066 switch (element->type)
2068 /* IMPORTANT: element params are shared, so copy them if needed
2069 * or use then NOW, dont presume they have a long lifespan
2071 case TAG:
2073 token = skin_buffer_alloc(sizeof(*token));
2074 memset(token, 0, sizeof(*token));
2075 token->type = element->tag->type;
2076 token->value.data = INVALID_OFFSET;
2078 if (element->tag->flags&SKIN_RTC_REFRESH)
2080 #if CONFIG_RTC
2081 curr_line->update_mode |= SKIN_REFRESH_DYNAMIC;
2082 #else
2083 curr_line->update_mode |= SKIN_REFRESH_STATIC;
2084 #endif
2086 else
2087 curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL;
2089 element->data = PTRTOSKINOFFSET(skin_buffer, token);
2091 /* Some tags need special handling for the tag, so add them here */
2092 switch (token->type)
2094 case SKIN_TOKEN_ALIGN_LANGDIRECTION:
2095 follow_lang_direction = 2;
2096 break;
2097 case SKIN_TOKEN_LOGICAL_IF:
2098 function = parse_logical_if;
2099 break;
2100 case SKIN_TOKEN_LOGICAL_AND:
2101 case SKIN_TOKEN_LOGICAL_OR:
2102 function = parse_logical_andor;
2103 break;
2104 case SKIN_TOKEN_SUBSTRING:
2105 function = parse_substring_tag;
2106 break;
2107 case SKIN_TOKEN_PROGRESSBAR:
2108 case SKIN_TOKEN_VOLUME:
2109 case SKIN_TOKEN_BATTERY_PERCENT:
2110 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
2111 case SKIN_TOKEN_PEAKMETER_LEFT:
2112 case SKIN_TOKEN_PEAKMETER_RIGHT:
2113 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
2114 #ifdef HAVE_RADIO_RSSI
2115 case SKIN_TOKEN_TUNER_RSSI:
2116 #endif
2117 function = parse_progressbar_tag;
2118 break;
2119 case SKIN_TOKEN_SUBLINE_TIMEOUT:
2120 case SKIN_TOKEN_BUTTON_VOLUME:
2121 case SKIN_TOKEN_TRACK_STARTING:
2122 case SKIN_TOKEN_TRACK_ENDING:
2123 function = parse_timeout_tag;
2124 break;
2125 #ifdef HAVE_LCD_BITMAP
2126 case SKIN_TOKEN_LIST_ITEM_TEXT:
2127 case SKIN_TOKEN_LIST_ITEM_ICON:
2128 function = parse_listitem;
2129 break;
2130 case SKIN_TOKEN_DISABLE_THEME:
2131 case SKIN_TOKEN_ENABLE_THEME:
2132 case SKIN_TOKEN_DRAW_INBUILTBAR:
2133 function = parse_statusbar_tags;
2134 break;
2135 case SKIN_TOKEN_LIST_TITLE_TEXT:
2136 #ifndef __PCTOOL__
2137 sb_skin_has_title(curr_screen);
2138 #endif
2139 break;
2140 #endif
2141 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2142 case SKIN_TOKEN_DRAWRECTANGLE:
2143 function = parse_drawrectangle;
2144 break;
2145 #endif
2146 case SKIN_TOKEN_FILE_DIRECTORY:
2147 token->value.i = get_param(element, 0)->data.number;
2148 break;
2149 #ifdef HAVE_BACKDROP_IMAGE
2150 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
2151 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
2152 function = parse_viewportcolour;
2153 break;
2154 case SKIN_TOKEN_IMAGE_BACKDROP:
2155 function = parse_image_special;
2156 break;
2157 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE:
2158 function = parse_viewporttextstyle;
2159 break;
2160 case SKIN_TOKEN_VIEWPORT_DRAWONBG:
2161 curr_vp->output_to_backdrop_buffer = true;
2162 backdrop_filename = BACKDROP_BUFFERNAME;
2163 wps_data->use_extra_framebuffer = true;
2164 break;
2165 #endif
2166 #ifdef HAVE_LCD_COLOR
2167 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP:
2168 function = parse_viewport_gradient_setup;
2169 break;
2170 #endif
2171 case SKIN_TOKEN_TRANSLATEDSTRING:
2172 case SKIN_TOKEN_SETTING:
2173 function = parse_setting_and_lang;
2174 break;
2175 #ifdef HAVE_LCD_BITMAP
2176 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
2177 function = parse_playlistview;
2178 break;
2179 case SKIN_TOKEN_LOAD_FONT:
2180 function = parse_font_load;
2181 break;
2182 case SKIN_TOKEN_VIEWPORT_ENABLE:
2183 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
2184 token->value.data = get_param(element, 0)->data.text;
2185 break;
2186 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
2187 case SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT:
2188 function = parse_image_display;
2189 break;
2190 case SKIN_TOKEN_IMAGE_PRELOAD:
2191 case SKIN_TOKEN_IMAGE_DISPLAY:
2192 function = parse_image_load;
2193 break;
2194 case SKIN_TOKEN_LIST_ITEM_CFG:
2195 function = parse_listitemviewport;
2196 break;
2197 #endif
2198 #ifdef HAVE_TOUCHSCREEN
2199 case SKIN_TOKEN_TOUCHREGION:
2200 function = parse_touchregion;
2201 break;
2202 case SKIN_TOKEN_LASTTOUCH:
2203 function = parse_lasttouch;
2204 break;
2205 #endif
2206 #ifdef HAVE_ALBUMART
2207 case SKIN_TOKEN_ALBUMART_DISPLAY:
2208 if (SKINOFFSETTOPTR(skin_buffer, wps_data->albumart))
2210 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2211 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
2213 break;
2214 case SKIN_TOKEN_ALBUMART_LOAD:
2215 function = parse_albumart_load;
2216 break;
2217 #endif
2218 #ifdef HAVE_SKIN_VARIABLES
2219 case SKIN_TOKEN_VAR_SET:
2220 case SKIN_TOKEN_VAR_GETVAL:
2221 case SKIN_TOKEN_VAR_TIMEOUT:
2222 function = parse_skinvar;
2223 break;
2224 #endif
2225 default:
2226 break;
2228 if (function)
2230 if (function(element, token, wps_data) < 0)
2231 return CALLBACK_ERROR;
2233 /* tags that start with 'F', 'I' or 'D' are for the next file */
2234 if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' ||
2235 *(element->tag->name) == 'D')
2236 token->next = true;
2237 if (follow_lang_direction > 0 )
2238 follow_lang_direction--;
2239 break;
2241 case VIEWPORT:
2242 return convert_viewport(wps_data, element);
2243 case LINE:
2245 curr_line = skin_buffer_alloc(sizeof(*curr_line));
2246 curr_line->update_mode = SKIN_REFRESH_STATIC;
2247 element->data = PTRTOSKINOFFSET(skin_buffer, curr_line);
2249 break;
2250 case LINE_ALTERNATOR:
2252 struct line_alternator *alternator = skin_buffer_alloc(sizeof(*alternator));
2253 alternator->current_line = 0;
2254 #ifndef __PCTOOL__
2255 alternator->next_change_tick = current_tick;
2256 #endif
2257 element->data = PTRTOSKINOFFSET(skin_buffer, alternator);
2259 break;
2260 case CONDITIONAL:
2262 struct conditional *conditional = skin_buffer_alloc(sizeof(*conditional));
2263 conditional->last_value = -1;
2264 conditional->token = element->data;
2265 element->data = PTRTOSKINOFFSET(skin_buffer, conditional);
2266 if (!check_feature_tag(element->tag->type))
2268 return FEATURE_NOT_AVAILABLE;
2270 return CALLBACK_OK;
2272 case TEXT:
2273 curr_line->update_mode |= SKIN_REFRESH_STATIC;
2274 break;
2275 default:
2276 break;
2278 return CALLBACK_OK;
2281 /* to setup up the wps-data from a format-buffer (isfile = false)
2282 from a (wps-)file (isfile = true)*/
2283 bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2284 const char *buf, bool isfile, struct skin_stats *stats)
2286 char *wps_buffer = NULL;
2287 if (!wps_data || !buf)
2288 return false;
2289 #ifdef HAVE_ALBUMART
2290 int status;
2291 struct mp3entry *curtrack;
2292 long offset;
2293 struct skin_albumart old_aa = {.state = WPS_ALBUMART_NONE};
2294 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2295 if (aa)
2297 old_aa.state = aa->state;
2298 old_aa.height = aa->height;
2299 old_aa.width = aa->width;
2301 #endif
2302 #ifdef HAVE_LCD_BITMAP
2303 int i;
2304 for (i=0;i<MAXUSERFONTS;i++)
2306 skinfonts[i].id = -1;
2307 skinfonts[i].name = NULL;
2309 #endif
2310 #ifdef DEBUG_SKIN_ENGINE
2311 if (isfile && debug_wps)
2313 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf);
2315 #endif
2317 _stats = stats;
2318 skin_clear_stats(stats);
2319 /* get buffer space from the plugin buffer */
2320 size_t buffersize = 0;
2321 wps_buffer = (char *)plugin_get_buffer(&buffersize);
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());
2429 stats->buflib_handles++;
2430 stats->tree_size = skin_buffer_usage();
2432 #else
2433 wps_data->wps_loaded = wps_data->tree >= 0;
2434 #endif
2436 #ifdef HAVE_TOUCHSCREEN
2437 /* Check if there are any touch regions from the skin and not just
2438 * auto-created ones for bars */
2439 struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer,
2440 wps_data->touchregions);
2441 bool user_touch_region_found = false;
2442 while (regions)
2444 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, regions->token);
2445 struct touchregion *r = SKINOFFSETTOPTR(skin_buffer, token->value.data);
2447 if (r->action != ACTION_TOUCH_SCROLLBAR &&
2448 r->action != ACTION_TOUCH_VOLUME)
2450 user_touch_region_found = true;
2451 break;
2453 regions = SKINOFFSETTOPTR(skin_buffer, regions->next);
2455 regions = SKINOFFSETTOPTR(skin_buffer, wps_data->touchregions);
2456 if (regions && !user_touch_region_found)
2457 wps_data->touchregions = PTRTOSKINOFFSET(skin_buffer, NULL);
2458 #endif
2460 skin_buffer = NULL;
2461 return true;