lcd/skin_engine: Add the ability to draw onto the backdrop layer
[maemo-rb.git] / apps / gui / skin_engine / skin_parser.c
blob0fe8789bcb5d885992e7ad1c0ec39f6ade0c9d6e
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_parser.h"
37 #include "tag_table.h"
39 #ifdef __PCTOOL__
40 #ifdef WPSEDITOR
41 #include "proxy.h"
42 #include "sysfont.h"
43 #else
44 #include "action.h"
45 #include "checkwps.h"
46 #include "audio.h"
47 #define lang_is_rtl() (false)
48 #define DEBUGF printf
49 #endif /*WPSEDITOR*/
50 #else
51 #include "debug.h"
52 #include "language.h"
53 #endif /*__PCTOOL__*/
55 #include <ctype.h>
56 #include <stdbool.h>
57 #include "font.h"
59 #include "wps_internals.h"
60 #include "skin_engine.h"
61 #include "settings.h"
62 #include "settings_list.h"
63 #if CONFIG_TUNER
64 #include "radio.h"
65 #include "tuner.h"
66 #endif
68 #ifdef HAVE_LCD_BITMAP
69 #include "bmp.h"
70 #endif
72 #ifdef HAVE_ALBUMART
73 #include "playback.h"
74 #endif
76 #include "backdrop.h"
77 #include "statusbar-skinned.h"
79 #define WPS_ERROR_INVALID_PARAM -1
81 static char* skin_buffer = NULL;
82 void skinparser_set_buffer(char* pointer)
84 skin_buffer = pointer;
87 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
88 static char *backdrop_filename;
89 #endif
91 static bool isdefault(struct skin_tag_parameter *param)
93 return param->type == DEFAULT;
96 static inline char*
97 get_param_text(struct skin_element *element, int param_number)
99 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
100 return SKINOFFSETTOPTR(skin_buffer, params[param_number].data.text);
103 static inline struct skin_element*
104 get_param_code(struct skin_element *element, int param_number)
106 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
107 return SKINOFFSETTOPTR(skin_buffer, params[param_number].data.code);
110 static inline struct skin_tag_parameter*
111 get_param(struct skin_element *element, int param_number)
113 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
114 return &params[param_number];
117 /* which screen are we parsing for? */
118 static enum screen_type curr_screen;
120 /* the current viewport */
121 static struct skin_element *curr_viewport_element;
122 static struct skin_viewport *curr_vp;
123 static struct skin_element *first_viewport;
125 static struct line *curr_line;
127 static int follow_lang_direction = 0;
129 typedef int (*parse_function)(struct skin_element *element,
130 struct wps_token *token,
131 struct wps_data *wps_data);
133 #ifdef HAVE_LCD_BITMAP
134 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
135 * chains require the order to be kept.
137 static void add_to_ll_chain(OFFSETTYPE(struct skin_token_list *) *listoffset,
138 struct skin_token_list *item)
140 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, *listoffset);
141 if (list == NULL)
143 *listoffset = PTRTOSKINOFFSET(skin_buffer, item);
145 else
147 while (SKINOFFSETTOPTR(skin_buffer, list->next))
148 list = SKINOFFSETTOPTR(skin_buffer, list->next);
149 list->next = PTRTOSKINOFFSET(skin_buffer, item);
153 #endif
156 void *skin_find_item(const char *label, enum skin_find_what what,
157 struct wps_data *data)
159 const char *itemlabel = NULL;
160 char *old_skin_buffer = skin_buffer;
161 char *databuf = get_skin_buffer(data);
162 union {
163 struct skin_token_list *linkedlist;
164 struct skin_element *vplist;
165 } list = {NULL};
166 bool isvplist = false;
167 void *ret = NULL;
168 if (databuf && databuf != skin_buffer)
169 skin_buffer = get_skin_buffer(data);
170 switch (what)
172 case SKIN_FIND_UIVP:
173 case SKIN_FIND_VP:
174 list.vplist = SKINOFFSETTOPTR(skin_buffer, data->tree);
175 isvplist = true;
176 break;
177 #ifdef HAVE_LCD_BITMAP
178 case SKIN_FIND_IMAGE:
179 list.linkedlist = SKINOFFSETTOPTR(skin_buffer, data->images);
180 break;
181 #endif
182 #ifdef HAVE_TOUCHSCREEN
183 case SKIN_FIND_TOUCHREGION:
184 list.linkedlist = SKINOFFSETTOPTR(skin_buffer, data->touchregions);
185 break;
186 #endif
187 #ifdef HAVE_SKIN_VARIABLES
188 case SKIN_VARIABLE:
189 list.linkedlist = SKINOFFSETTOPTR(skin_buffer, data->skinvars);
190 break;
191 #endif
194 while (list.linkedlist)
196 bool skip = false;
197 #ifdef HAVE_LCD_BITMAP
198 struct wps_token *token = NULL;
199 if (!isvplist)
200 token = SKINOFFSETTOPTR(skin_buffer, list.linkedlist->token);
201 #endif
202 switch (what)
204 case SKIN_FIND_UIVP:
205 case SKIN_FIND_VP:
206 ret = SKINOFFSETTOPTR(skin_buffer, list.vplist->data);
207 if (((struct skin_viewport *)ret)->label == VP_DEFAULT_LABEL)
208 itemlabel = VP_DEFAULT_LABEL_STRING;
209 else
210 itemlabel = SKINOFFSETTOPTR(skin_buffer, ((struct skin_viewport *)ret)->label);
211 skip = !(((struct skin_viewport *)ret)->is_infovp ==
212 (what==SKIN_FIND_UIVP));
213 break;
214 #ifdef HAVE_LCD_BITMAP
215 case SKIN_FIND_IMAGE:
216 ret = SKINOFFSETTOPTR(skin_buffer, token->value.data);
217 itemlabel = SKINOFFSETTOPTR(skin_buffer, ((struct gui_img *)ret)->label);
218 break;
219 #endif
220 #ifdef HAVE_TOUCHSCREEN
221 case SKIN_FIND_TOUCHREGION:
222 ret = SKINOFFSETTOPTR(skin_buffer, token->value.data);
223 itemlabel = SKINOFFSETTOPTR(skin_buffer, ((struct touchregion *)ret)->label);
224 break;
225 #endif
226 #ifdef HAVE_SKIN_VARIABLES
227 case SKIN_VARIABLE:
228 ret = SKINOFFSETTOPTR(skin_buffer, token->value.data);
229 itemlabel = SKINOFFSETTOPTR(skin_buffer, ((struct skin_var *)ret)->label);
230 break;
231 #endif
234 if (!skip && itemlabel && !strcmp(itemlabel, label))
236 if (old_skin_buffer != skin_buffer)
237 skin_buffer = old_skin_buffer;
238 return ret;
241 if (isvplist)
242 list.vplist = SKINOFFSETTOPTR(skin_buffer, list.vplist->next);
243 else
244 list.linkedlist = SKINOFFSETTOPTR(skin_buffer, list.linkedlist->next);
246 if (old_skin_buffer != skin_buffer)
247 skin_buffer = old_skin_buffer;
248 return NULL;
251 #ifdef HAVE_LCD_BITMAP
253 /* create and init a new wpsll item.
254 * passing NULL to token will alloc a new one.
255 * You should only pass NULL for the token when the token type (table above)
256 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
258 static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
259 void* token_data)
261 struct skin_token_list *llitem =
262 (struct skin_token_list *)skin_buffer_alloc(sizeof(struct skin_token_list));
263 if (!token)
264 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
265 if (!llitem || !token)
266 return NULL;
267 llitem->next = PTRTOSKINOFFSET(skin_buffer, NULL);
268 llitem->token = PTRTOSKINOFFSET(skin_buffer, token);
269 if (token_data)
270 token->value.data = PTRTOSKINOFFSET(skin_buffer, token_data);
271 return llitem;
274 static int parse_statusbar_tags(struct skin_element* element,
275 struct wps_token *token,
276 struct wps_data *wps_data)
278 (void)element;
279 if (token->type == SKIN_TOKEN_DRAW_INBUILTBAR)
281 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)&curr_vp->vp);
283 else
285 struct skin_viewport *default_vp = SKINOFFSETTOPTR(skin_buffer, first_viewport->data);
286 if (first_viewport->params_count == 0)
288 wps_data->wps_sb_tag = true;
289 wps_data->show_sb_on_wps = (token->type == SKIN_TOKEN_ENABLE_THEME);
291 if (wps_data->show_sb_on_wps)
293 viewport_set_defaults(&default_vp->vp, curr_screen);
295 else
297 viewport_set_fullscreen(&default_vp->vp, curr_screen);
299 #ifdef HAVE_REMOTE_LCD
300 /* This parser requires viewports which will use the settings font to
301 * have font == 1, but the above viewport_set() calls set font to
302 * the current real font id. So force 1 here it will be set correctly
303 * at the end
305 default_vp->vp.font = 1;
306 #endif
308 return 0;
311 static int get_image_id(int c)
313 if(c >= 'a' && c <= 'z')
314 return c - 'a';
315 else if(c >= 'A' && c <= 'Z')
316 return c - 'A' + 26;
317 else
318 return -1;
321 char *get_image_filename(const char *start, const char* bmpdir,
322 char *buf, int buf_size)
324 snprintf(buf, buf_size, "%s/%s", bmpdir, start);
326 return buf;
329 static int parse_image_display(struct skin_element *element,
330 struct wps_token *token,
331 struct wps_data *wps_data)
333 char *label = get_param_text(element, 0);
334 char sublabel = '\0';
335 int subimage;
336 struct gui_img *img;
337 struct image_display *id = skin_buffer_alloc(sizeof(struct image_display));
339 if (element->params_count == 1 && strlen(label) <= 2)
341 /* backwards compatability. Allow %xd(Aa) to still work */
342 sublabel = label[1];
343 label[1] = '\0';
345 /* sanity check */
346 img = skin_find_item(label, SKIN_FIND_IMAGE, wps_data);
347 if (!img || !id)
349 return WPS_ERROR_INVALID_PARAM;
351 id->label = img->label;
352 id->offset = 0;
353 id->token = PTRTOSKINOFFSET(skin_buffer, NULL);
354 if (img->using_preloaded_icons)
356 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
359 if (element->params_count > 1)
361 if (get_param(element, 1)->type == CODE)
362 id->token = get_param_code(element, 1)->data;
363 /* specify a number. 1 being the first subimage (i.e top) NOT 0 */
364 else if (get_param(element, 1)->type == INTEGER)
365 id->subimage = get_param(element, 1)->data.number - 1;
366 if (element->params_count > 2)
367 id->offset = get_param(element, 2)->data.number;
369 else
371 if ((subimage = get_image_id(sublabel)) != -1)
373 if (subimage >= img->num_subimages)
374 return WPS_ERROR_INVALID_PARAM;
375 id->subimage = subimage;
376 } else {
377 id->subimage = 0;
380 token->value.data = PTRTOSKINOFFSET(skin_buffer, id);
381 return 0;
384 static int parse_image_load(struct skin_element *element,
385 struct wps_token *token,
386 struct wps_data *wps_data)
388 const char* filename;
389 const char* id;
390 int x,y;
391 struct gui_img *img;
393 /* format: %x(n,filename.bmp,x,y)
394 or %xl(n,filename.bmp,x,y)
395 or %xl(n,filename.bmp,x,y,num_subimages)
398 id = get_param_text(element, 0);
399 filename = get_param_text(element, 1);
400 x = get_param(element, 2)->data.number;
401 y = get_param(element, 3)->data.number;
403 /* check the image number and load state */
404 if(skin_find_item(id, SKIN_FIND_IMAGE, wps_data))
406 /* Invalid image ID */
407 return WPS_ERROR_INVALID_PARAM;
409 img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img));
410 if (!img)
411 return WPS_ERROR_INVALID_PARAM;
412 /* save a pointer to the filename */
413 img->bm.data = (char*)filename;
414 img->label = PTRTOSKINOFFSET(skin_buffer, (void*)id);
415 img->x = x;
416 img->y = y;
417 img->num_subimages = 1;
418 img->always_display = false;
419 img->display = -1;
420 img->using_preloaded_icons = false;
421 img->buflib_handle = -1;
423 /* save current viewport */
424 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
426 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
428 img->always_display = true;
430 else if (element->params_count == 5)
432 img->num_subimages = get_param(element, 4)->data.number;
433 if (img->num_subimages <= 0)
434 return WPS_ERROR_INVALID_PARAM;
437 if (!strcmp(img->bm.data, "__list_icons__"))
439 img->num_subimages = Icon_Last_Themeable;
440 img->using_preloaded_icons = true;
443 struct skin_token_list *item =
444 (struct skin_token_list *)new_skin_token_list_item(NULL, img);
445 if (!item)
446 return WPS_ERROR_INVALID_PARAM;
447 add_to_ll_chain(&wps_data->images, item);
449 return 0;
451 struct skin_font {
452 int id; /* the id from font_load */
453 char *name; /* filename without path and extension */
454 int glyphs; /* how many glyphs to reserve room for */
456 static struct skin_font skinfonts[MAXUSERFONTS];
457 static int parse_font_load(struct skin_element *element,
458 struct wps_token *token,
459 struct wps_data *wps_data)
461 (void)wps_data; (void)token;
462 int id = get_param(element, 0)->data.number;
463 char *filename = get_param_text(element, 1);
464 int glyphs;
465 char *ptr;
467 if(element->params_count > 2)
468 glyphs = get_param(element, 2)->data.number;
469 else
470 glyphs = global_settings.glyphs_to_cache;
471 if (id < 2)
473 DEBUGF("font id must be >= 2\n");
474 return 1;
476 #if defined(DEBUG) || defined(SIMULATOR)
477 if (skinfonts[id-2].name != NULL)
479 DEBUGF("font id %d already being used\n", id);
481 #endif
482 /* make sure the filename contains .fnt,
483 * we dont actually use it, but require it anyway */
484 ptr = strchr(filename, '.');
485 if (!ptr || strncmp(ptr, ".fnt", 4))
486 return WPS_ERROR_INVALID_PARAM;
487 skinfonts[id-2].id = -1;
488 skinfonts[id-2].name = filename;
489 skinfonts[id-2].glyphs = glyphs;
491 return 0;
495 #ifdef HAVE_LCD_BITMAP
497 static int parse_playlistview(struct skin_element *element,
498 struct wps_token *token,
499 struct wps_data *wps_data)
501 (void)wps_data;
502 struct playlistviewer *viewer =
503 (struct playlistviewer *)skin_buffer_alloc(sizeof(struct playlistviewer));
504 if (!viewer)
505 return WPS_ERROR_INVALID_PARAM;
506 viewer->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
507 viewer->show_icons = true;
508 viewer->start_offset = get_param(element, 0)->data.number;
509 viewer->line = PTRTOSKINOFFSET(skin_buffer, get_param_code(element, 1));
511 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)viewer);
513 return 0;
515 #endif
516 #ifdef HAVE_LCD_COLOR
517 static int parse_viewport_gradient_setup(struct skin_element *element,
518 struct wps_token *token,
519 struct wps_data *wps_data)
521 (void)wps_data;
522 struct gradient_config *cfg;
523 if (element->params_count < 2) /* only start and end are required */
524 return 1;
525 cfg = (struct gradient_config *)skin_buffer_alloc(sizeof(struct gradient_config));
526 if (!cfg)
527 return 1;
528 if (!parse_color(curr_screen, get_param_text(element, 0), &cfg->start) ||
529 !parse_color(curr_screen, get_param_text(element, 1), &cfg->end))
530 return 1;
531 if (element->params_count > 2)
533 if (!parse_color(curr_screen, get_param_text(element, 2), &cfg->text))
534 return 1;
536 else
538 cfg->text = curr_vp->vp.fg_pattern;
541 token->value.data = PTRTOSKINOFFSET(skin_buffer, cfg);
542 return 0;
544 #endif
546 static int parse_listitem(struct skin_element *element,
547 struct wps_token *token,
548 struct wps_data *wps_data)
550 (void)wps_data;
551 struct listitem *li = (struct listitem *)skin_buffer_alloc(sizeof(struct listitem));
552 if (!li)
553 return 1;
554 token->value.data = PTRTOSKINOFFSET(skin_buffer, li);
555 if (element->params_count == 0)
556 li->offset = 0;
557 else
559 li->offset = get_param(element, 0)->data.number;
560 if (element->params_count > 1)
561 li->wrap = strcasecmp(get_param_text(element, 1), "nowrap") != 0;
562 else
563 li->wrap = true;
565 return 0;
568 static int parse_listitemviewport(struct skin_element *element,
569 struct wps_token *token,
570 struct wps_data *wps_data)
572 #ifndef __PCTOOL__
573 struct listitem_viewport_cfg *cfg =
574 (struct listitem_viewport_cfg *)skin_buffer_alloc(
575 sizeof(struct listitem_viewport_cfg));
576 if (!cfg)
577 return -1;
578 cfg->data = wps_data;
579 cfg->tile = false;
580 cfg->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
581 cfg->width = -1;
582 cfg->height = -1;
583 if (!isdefault(get_param(element, 1)))
584 cfg->width = get_param(element, 1)->data.number;
585 if (!isdefault(get_param(element, 2)))
586 cfg->height = get_param(element, 2)->data.number;
587 if (element->params_count > 3 &&
588 !strcmp(get_param_text(element, 3), "tile"))
589 cfg->tile = true;
590 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)cfg);
591 #endif
592 return 0;
595 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
596 static int parse_viewporttextstyle(struct skin_element *element,
597 struct wps_token *token,
598 struct wps_data *wps_data)
600 (void)wps_data;
601 int style;
602 char *mode = get_param_text(element, 0);
603 unsigned colour;
605 if (!strcmp(mode, "invert"))
607 style = STYLE_INVERT;
609 else if (!strcmp(mode, "colour") || !strcmp(mode, "color"))
611 if (element->params_count < 2 ||
612 !parse_color(curr_screen, get_param_text(element, 1), &colour))
613 return 1;
614 style = STYLE_COLORED|(STYLE_COLOR_MASK&colour);
616 #ifdef HAVE_LCD_COLOR
617 else if (!strcmp(mode, "gradient"))
619 int num_lines;
620 if (element->params_count < 2)
621 num_lines = 1;
622 else /* atoi() instead of using a number in the parser is because [si]
623 * will select the number for something which looks like a colour
624 * making the "colour" case (above) harder to parse */
625 num_lines = atoi(get_param_text(element, 1));
626 style = STYLE_GRADIENT|NUMLN_PACK(num_lines)|CURLN_PACK(0);
628 #endif
629 else if (!strcmp(mode, "clear"))
631 style = STYLE_DEFAULT;
633 else
634 return 1;
635 token->value.l = style;
636 return 0;
639 static int parse_viewportcolour(struct skin_element *element,
640 struct wps_token *token,
641 struct wps_data *wps_data)
643 (void)wps_data;
644 struct skin_tag_parameter *param = get_param(element, 0);
645 struct viewport_colour *colour =
646 (struct viewport_colour *)skin_buffer_alloc(sizeof(struct viewport_colour));
647 if (!colour)
648 return -1;
649 if (isdefault(param))
651 colour->colour = get_viewport_default_colour(curr_screen,
652 token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
654 else
656 if (!parse_color(curr_screen, SKINOFFSETTOPTR(skin_buffer, param->data.text),
657 &colour->colour))
658 return -1;
660 colour->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
661 token->value.data = PTRTOSKINOFFSET(skin_buffer, colour);
662 if (element->line == curr_viewport_element->line)
664 if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
666 curr_vp->start_fgcolour = colour->colour;
667 curr_vp->vp.fg_pattern = colour->colour;
669 else
671 curr_vp->start_bgcolour = colour->colour;
672 curr_vp->vp.bg_pattern = colour->colour;
675 return 0;
678 static int parse_image_special(struct skin_element *element,
679 struct wps_token *token,
680 struct wps_data *wps_data)
682 (void)wps_data; /* kill warning */
683 (void)token;
685 #if LCD_DEPTH > 1
686 char *filename;
687 if (token->type == SKIN_TOKEN_IMAGE_BACKDROP)
689 if (isdefault(get_param(element, 0)))
691 filename = "-";
693 else
695 filename = get_param_text(element, 0);
696 /* format: %X(filename.bmp) or %X(d) */
697 if (!strcmp(filename, "d"))
698 filename = NULL;
700 backdrop_filename = filename;
702 #endif
704 return 0;
706 #endif
708 #endif /* HAVE_LCD_BITMAP */
710 static int parse_setting_and_lang(struct skin_element *element,
711 struct wps_token *token,
712 struct wps_data *wps_data)
714 /* NOTE: both the string validations that happen in here will
715 * automatically PASS on checkwps because its too hard to get
716 * settings_list.c and english.lang built for it.
717 * If that ever changes remove the #ifndef __PCTOOL__'s here
719 (void)wps_data;
720 char *temp = get_param_text(element, 0);
721 int i;
723 if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
725 #ifndef __PCTOOL__
726 i = lang_english_to_id(temp);
727 if (i < 0)
728 return WPS_ERROR_INVALID_PARAM;
729 #endif
731 else
733 #ifndef __PCTOOL__
734 if (find_setting_by_cfgname(temp, &i) == NULL)
735 return WPS_ERROR_INVALID_PARAM;
736 #endif
738 /* Store the setting number */
739 token->value.i = i;
740 return 0;
743 static int parse_logical_andor(struct skin_element *element,
744 struct wps_token *token,
745 struct wps_data *wps_data)
747 (void)wps_data;
748 token->value.data = PTRTOSKINOFFSET(skin_buffer, element);
749 return 0;
752 static int parse_logical_if(struct skin_element *element,
753 struct wps_token *token,
754 struct wps_data *wps_data)
756 (void)wps_data;
757 char *op = get_param_text(element, 1);
758 struct logical_if *lif = skin_buffer_alloc(sizeof(struct logical_if));
759 if (!lif)
760 return -1;
761 token->value.data = PTRTOSKINOFFSET(skin_buffer, lif);
762 lif->token = get_param_code(element, 0)->data;
764 if (!strncmp(op, "=", 1))
765 lif->op = IF_EQUALS;
766 else if (!strncmp(op, "!=", 2))
767 lif->op = IF_NOTEQUALS;
768 else if (!strncmp(op, ">=", 2))
769 lif->op = IF_GREATERTHAN_EQ;
770 else if (!strncmp(op, "<=", 2))
771 lif->op = IF_LESSTHAN_EQ;
772 else if (!strncmp(op, ">", 2))
773 lif->op = IF_GREATERTHAN;
774 else if (!strncmp(op, "<", 1))
775 lif->op = IF_LESSTHAN;
777 memcpy(&lif->operand, get_param(element, 2), sizeof(lif->operand));
778 if (element->params_count > 3)
779 lif->num_options = get_param(element, 3)->data.number;
780 else
781 lif->num_options = TOKEN_VALUE_ONLY;
782 return 0;
786 static int parse_timeout_tag(struct skin_element *element,
787 struct wps_token *token,
788 struct wps_data *wps_data)
790 (void)wps_data;
791 int val = 0;
792 if (element->params_count == 0)
794 switch (token->type)
796 case SKIN_TOKEN_SUBLINE_TIMEOUT:
797 return -1;
798 case SKIN_TOKEN_BUTTON_VOLUME:
799 case SKIN_TOKEN_TRACK_STARTING:
800 case SKIN_TOKEN_TRACK_ENDING:
801 val = 10;
802 break;
803 default:
804 break;
807 else
808 val = get_param(element, 0)->data.number;
809 token->value.i = val * TIMEOUT_UNIT;
810 return 0;
813 static int parse_substring_tag(struct skin_element* element,
814 struct wps_token *token,
815 struct wps_data *wps_data)
817 (void)wps_data;
818 struct substring *ss = (struct substring*)skin_buffer_alloc(sizeof(struct substring));
819 if (!ss)
820 return 1;
821 ss->start = get_param(element, 0)->data.number;
822 if (get_param(element, 1)->type == DEFAULT)
823 ss->length = -1;
824 else
825 ss->length = get_param(element, 1)->data.number;
826 ss->token = get_param_code(element, 2)->data;
827 if (element->params_count > 3)
828 ss->expect_number = !strcmp(get_param_text(element, 3), "number");
829 else
830 ss->expect_number = false;
831 token->value.data = PTRTOSKINOFFSET(skin_buffer, ss);
832 return 0;
835 static int parse_progressbar_tag(struct skin_element* element,
836 struct wps_token *token,
837 struct wps_data *wps_data)
839 #ifdef HAVE_LCD_BITMAP
840 struct progressbar *pb;
841 struct viewport *vp = &curr_vp->vp;
842 struct skin_tag_parameter *param = get_param(element, 0);
843 int curr_param = 0;
844 char *image_filename = NULL;
846 if (element->params_count == 0 &&
847 element->tag->type != SKIN_TOKEN_PROGRESSBAR)
848 return 0; /* nothing to do */
849 pb = (struct progressbar*)skin_buffer_alloc(sizeof(struct progressbar));
851 token->value.data = PTRTOSKINOFFSET(skin_buffer, pb);
853 if (!pb)
854 return WPS_ERROR_INVALID_PARAM;
855 pb->vp = PTRTOSKINOFFSET(skin_buffer, vp);
856 pb->follow_lang_direction = follow_lang_direction > 0;
857 pb->nofill = false;
858 pb->nobar = false;
859 pb->image = PTRTOSKINOFFSET(skin_buffer, NULL);
860 pb->slider = PTRTOSKINOFFSET(skin_buffer, NULL);
861 pb->backdrop = PTRTOSKINOFFSET(skin_buffer, NULL);
862 pb->invert_fill_direction = false;
863 pb->horizontal = true;
865 if (element->params_count == 0)
867 pb->x = 0;
868 pb->width = vp->width;
869 pb->height = SYSFONT_HEIGHT-2;
870 pb->y = -1; /* Will be computed during the rendering */
871 pb->type = element->tag->type;
872 return 0;
875 /* (x, y, width, height, ...) */
876 if (!isdefault(param))
877 pb->x = param->data.number;
878 else
879 pb->x = 0;
880 param++;
882 if (!isdefault(param))
883 pb->y = param->data.number;
884 else
885 pb->y = -1; /* computed at rendering */
886 param++;
888 if (!isdefault(param))
889 pb->width = param->data.number;
890 else
891 pb->width = vp->width - pb->x;
892 param++;
894 if (!isdefault(param))
896 /* A zero height makes no sense - reject it */
897 if (param->data.number == 0)
898 return WPS_ERROR_INVALID_PARAM;
900 pb->height = param->data.number;
902 else
904 if (vp->font > FONT_UI)
905 pb->height = -1; /* calculate at display time */
906 else
908 #ifndef __PCTOOL__
909 pb->height = font_get(vp->font)->height;
910 #else
911 pb->height = 8;
912 #endif
915 /* optional params, first is the image filename if it isnt recognised as a keyword */
917 curr_param = 4;
918 if (isdefault(get_param(element, curr_param)))
920 param++;
921 curr_param++;
924 pb->horizontal = pb->width > pb->height;
925 while (curr_param < element->params_count)
927 char* text;
928 param++;
929 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
930 if (!strcmp(text, "invert"))
931 pb->invert_fill_direction = true;
932 else if (!strcmp(text, "nofill"))
933 pb->nofill = true;
934 else if (!strcmp(text, "nobar"))
935 pb->nobar = true;
936 else if (!strcmp(text, "slider"))
938 if (curr_param+1 < element->params_count)
940 curr_param++;
941 param++;
942 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
943 pb->slider = PTRTOSKINOFFSET(skin_buffer,
944 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
946 else /* option needs the next param */
947 return -1;
949 else if (!strcmp(text, "image"))
951 if (curr_param+1 < element->params_count)
953 curr_param++;
954 param++;
955 image_filename = SKINOFFSETTOPTR(skin_buffer, param->data.text);
957 else /* option needs the next param */
958 return -1;
960 else if (!strcmp(text, "backdrop"))
962 if (curr_param+1 < element->params_count)
964 curr_param++;
965 param++;
966 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
967 pb->backdrop = PTRTOSKINOFFSET(skin_buffer,
968 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
971 else /* option needs the next param */
972 return -1;
974 else if (!strcmp(text, "vertical"))
976 pb->horizontal = false;
977 if (isdefault(get_param(element, 3)))
978 pb->height = vp->height - pb->y;
980 else if (!strcmp(text, "horizontal"))
981 pb->horizontal = true;
982 else if (curr_param == 4)
983 image_filename = text;
985 curr_param++;
988 if (image_filename)
990 pb->image = PTRTOSKINOFFSET(skin_buffer,
991 skin_find_item(image_filename, SKIN_FIND_IMAGE, wps_data));
992 if (!SKINOFFSETTOPTR(skin_buffer, pb->image)) /* load later */
994 struct gui_img* img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img));
995 if (!img)
996 return WPS_ERROR_INVALID_PARAM;
997 /* save a pointer to the filename */
998 img->bm.data = (char*)image_filename;
999 img->label = PTRTOSKINOFFSET(skin_buffer, image_filename);
1000 img->x = 0;
1001 img->y = 0;
1002 img->num_subimages = 1;
1003 img->always_display = false;
1004 img->display = -1;
1005 img->using_preloaded_icons = false;
1006 img->buflib_handle = -1;
1007 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1008 struct skin_token_list *item =
1009 (struct skin_token_list *)new_skin_token_list_item(NULL, img);
1010 if (!item)
1011 return WPS_ERROR_INVALID_PARAM;
1012 add_to_ll_chain(&wps_data->images, item);
1013 pb->image = PTRTOSKINOFFSET(skin_buffer, img);
1017 if (token->type == SKIN_TOKEN_VOLUME)
1018 token->type = SKIN_TOKEN_VOLUMEBAR;
1019 else if (token->type == SKIN_TOKEN_BATTERY_PERCENT)
1020 token->type = SKIN_TOKEN_BATTERY_PERCENTBAR;
1021 else if (token->type == SKIN_TOKEN_TUNER_RSSI)
1022 token->type = SKIN_TOKEN_TUNER_RSSI_BAR;
1023 else if (token->type == SKIN_TOKEN_PEAKMETER_LEFT)
1024 token->type = SKIN_TOKEN_PEAKMETER_LEFTBAR;
1025 else if (token->type == SKIN_TOKEN_PEAKMETER_RIGHT)
1026 token->type = SKIN_TOKEN_PEAKMETER_RIGHTBAR;
1027 else if (token->type == SKIN_TOKEN_LIST_NEEDS_SCROLLBAR)
1028 token->type = SKIN_TOKEN_LIST_SCROLLBAR;
1029 pb->type = token->type;
1031 return 0;
1033 #else
1034 (void)element;
1035 if (token->type == SKIN_TOKEN_PROGRESSBAR ||
1036 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR)
1038 wps_data->full_line_progressbar =
1039 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR;
1041 return 0;
1043 #endif
1046 #ifdef HAVE_ALBUMART
1047 static int parse_albumart_load(struct skin_element* element,
1048 struct wps_token *token,
1049 struct wps_data *wps_data)
1051 struct dim dimensions;
1052 int albumart_slot;
1053 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction;
1054 struct skin_albumart *aa =
1055 (struct skin_albumart *)skin_buffer_alloc(sizeof(struct skin_albumart));
1056 (void)token; /* silence warning */
1057 if (!aa)
1058 return -1;
1060 /* reset albumart info in wps */
1061 aa->width = -1;
1062 aa->height = -1;
1063 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1064 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1066 aa->x = get_param(element, 0)->data.number;
1067 aa->y = get_param(element, 1)->data.number;
1068 aa->width = get_param(element, 2)->data.number;
1069 aa->height = get_param(element, 3)->data.number;
1071 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1072 aa->draw_handle = -1;
1074 /* if we got here, we parsed everything ok .. ! */
1075 if (aa->width < 0)
1076 aa->width = 0;
1077 else if (aa->width > LCD_WIDTH)
1078 aa->width = LCD_WIDTH;
1080 if (aa->height < 0)
1081 aa->height = 0;
1082 else if (aa->height > LCD_HEIGHT)
1083 aa->height = LCD_HEIGHT;
1085 if (swap_for_rtl)
1086 aa->x = LCD_WIDTH - (aa->x + aa->width);
1088 aa->state = WPS_ALBUMART_LOAD;
1089 wps_data->albumart = PTRTOSKINOFFSET(skin_buffer, aa);
1091 dimensions.width = aa->width;
1092 dimensions.height = aa->height;
1094 albumart_slot = playback_claim_aa_slot(&dimensions);
1096 if (0 <= albumart_slot)
1097 wps_data->playback_aa_slot = albumart_slot;
1099 if (element->params_count > 4 && !isdefault(get_param(element, 4)))
1101 switch (*get_param_text(element, 4))
1103 case 'l':
1104 case 'L':
1105 if (swap_for_rtl)
1106 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1107 else
1108 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1109 break;
1110 case 'c':
1111 case 'C':
1112 aa->xalign = WPS_ALBUMART_ALIGN_CENTER;
1113 break;
1114 case 'r':
1115 case 'R':
1116 if (swap_for_rtl)
1117 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1118 else
1119 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1120 break;
1123 if (element->params_count > 5 && !isdefault(get_param(element, 5)))
1125 switch (*get_param_text(element, 5))
1127 case 't':
1128 case 'T':
1129 aa->yalign = WPS_ALBUMART_ALIGN_TOP;
1130 break;
1131 case 'c':
1132 case 'C':
1133 aa->yalign = WPS_ALBUMART_ALIGN_CENTER;
1134 break;
1135 case 'b':
1136 case 'B':
1137 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM;
1138 break;
1141 return 0;
1144 #endif /* HAVE_ALBUMART */
1145 #ifdef HAVE_SKIN_VARIABLES
1146 static struct skin_var* find_or_add_var(const char* label,
1147 struct wps_data *data)
1149 struct skin_var* ret = skin_find_item(label, SKIN_VARIABLE, data);
1150 if (!ret)
1152 ret = (struct skin_var*)skin_buffer_alloc(sizeof(struct skin_var));
1153 if (!ret)
1154 return NULL;
1155 ret->label = PTRTOSKINOFFSET(skin_buffer, label);
1156 ret->value = 1;
1157 ret->last_changed = 0xffff;
1158 struct skin_token_list *item = new_skin_token_list_item(NULL, ret);
1159 if (!item)
1160 return NULL;
1161 add_to_ll_chain(&data->skinvars, item);
1163 return ret;
1165 static int parse_skinvar( struct skin_element *element,
1166 struct wps_token *token,
1167 struct wps_data *wps_data)
1169 const char* label = get_param_text(element, 0);
1170 struct skin_var* var = find_or_add_var(label, wps_data);
1171 if (!var)
1172 return WPS_ERROR_INVALID_PARAM;
1173 switch (token->type)
1175 case SKIN_TOKEN_VAR_GETVAL:
1176 token->value.data = PTRTOSKINOFFSET(skin_buffer, var);
1177 break;
1178 case SKIN_TOKEN_VAR_SET:
1180 struct skin_var_changer *data =
1181 (struct skin_var_changer*)skin_buffer_alloc(
1182 sizeof(struct skin_var_changer));
1183 if (!data)
1184 return WPS_ERROR_INVALID_PARAM;
1185 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1186 if (!isdefault(get_param(element, 2)))
1187 data->newval = get_param(element, 2)->data.number;
1188 else if (strcmp(get_param_text(element, 1), "touch"))
1189 return WPS_ERROR_INVALID_PARAM;
1190 data->max = 0;
1191 if (!strcmp(get_param_text(element, 1), "set"))
1192 data->direct = true;
1193 else if (!strcmp(get_param_text(element, 1), "inc"))
1195 data->direct = false;
1197 else if (!strcmp(get_param_text(element, 1), "dec"))
1199 data->direct = false;
1200 data->newval *= -1;
1202 else if (!strcmp(get_param_text(element, 1), "touch"))
1204 data->direct = false;
1205 data->newval = 0;
1207 if (element->params_count > 3)
1208 data->max = get_param(element, 3)->data.number;
1209 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1211 break;
1212 case SKIN_TOKEN_VAR_TIMEOUT:
1214 struct skin_var_lastchange *data =
1215 (struct skin_var_lastchange*)skin_buffer_alloc(
1216 sizeof(struct skin_var_lastchange));
1217 if (!data)
1218 return WPS_ERROR_INVALID_PARAM;
1219 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1220 data->timeout = 10;
1221 if (element->params_count > 1)
1222 data->timeout = get_param(element, 1)->data.number;
1223 data->timeout *= TIMEOUT_UNIT;
1224 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1226 break;
1227 default: /* kill the warning */
1228 break;
1230 return 0;
1232 #endif /* HAVE_SKIN_VARIABLES */
1233 #ifdef HAVE_TOUCHSCREEN
1234 static int parse_lasttouch(struct skin_element *element,
1235 struct wps_token *token,
1236 struct wps_data *wps_data)
1238 struct touchregion_lastpress *data =
1239 (struct touchregion_lastpress*)skin_buffer_alloc(
1240 sizeof(struct touchregion_lastpress));
1241 int i;
1242 struct touchregion *region = NULL;
1243 if (!data)
1244 return WPS_ERROR_INVALID_PARAM;
1246 data->timeout = 10;
1248 for (i=0; i<element->params_count; i++)
1250 if (get_param(element, i)->type == STRING)
1251 region = skin_find_item(get_param_text(element, i),
1252 SKIN_FIND_TOUCHREGION, wps_data);
1253 else if (get_param(element, i)->type == INTEGER ||
1254 get_param(element, i)->type == DECIMAL)
1255 data->timeout = get_param(element, i)->data.number;
1258 data->region = PTRTOSKINOFFSET(skin_buffer, region);
1259 data->timeout *= TIMEOUT_UNIT;
1260 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1261 return 0;
1264 struct touchaction {const char* s; int action;};
1265 static const struct touchaction touchactions[] = {
1266 /* generic actions, convert to screen actions on use */
1267 {"none", ACTION_TOUCHSCREEN_IGNORE},{"lock", ACTION_TOUCH_SOFTLOCK },
1268 {"prev", ACTION_STD_PREV }, {"next", ACTION_STD_NEXT },
1269 {"hotkey", ACTION_STD_HOTKEY}, {"select", ACTION_STD_OK },
1270 {"menu", ACTION_STD_MENU }, {"cancel", ACTION_STD_CANCEL },
1271 {"contextmenu", ACTION_STD_CONTEXT},{"quickscreen", ACTION_STD_QUICKSCREEN },
1273 /* list/tree actions */
1274 { "resumeplayback", ACTION_TREE_WPS}, /* returns to previous music, WPS/FM */
1275 /* not really WPS specific, but no equivilant ACTION_STD_* */
1276 {"voldown", ACTION_WPS_VOLDOWN}, {"volup", ACTION_WPS_VOLUP},
1277 {"mute", ACTION_TOUCH_MUTE },
1279 /* generic settings changers */
1280 {"setting_inc", ACTION_SETTINGS_INC}, {"setting_dec", ACTION_SETTINGS_DEC},
1281 {"setting_set", ACTION_SETTINGS_SET},
1283 /* WPS specific actions */
1284 {"rwd", ACTION_WPS_SEEKBACK }, {"ffwd", ACTION_WPS_SEEKFWD },
1285 {"wps_prev", ACTION_WPS_SKIPPREV }, {"wps_next", ACTION_WPS_SKIPNEXT },
1286 {"browse", ACTION_WPS_BROWSE },
1287 {"play", ACTION_WPS_PLAY }, {"stop", ACTION_WPS_STOP },
1288 {"shuffle", ACTION_TOUCH_SHUFFLE }, {"repmode", ACTION_TOUCH_REPMODE },
1289 {"pitch", ACTION_WPS_PITCHSCREEN}, {"playlist", ACTION_WPS_VIEW_PLAYLIST },
1291 #if CONFIG_TUNER
1292 /* FM screen actions */
1293 /* Also allow browse, play, stop from WPS codes */
1294 {"mode", ACTION_FM_MODE }, {"record", ACTION_FM_RECORD },
1295 {"presets", ACTION_FM_PRESET},
1296 #endif
1299 static int touchregion_setup_setting(struct skin_element *element, int param_no,
1300 struct touchregion *region)
1302 #ifndef __PCTOOL__
1303 int p = param_no;
1304 char *name = get_param_text(element, p++);
1305 int j;
1307 region->setting_data.setting = find_setting_by_cfgname(name, &j);
1308 if (region->setting_data.setting == NULL)
1309 return WPS_ERROR_INVALID_PARAM;
1311 if (region->action == ACTION_SETTINGS_SET)
1313 char* text;
1314 int temp;
1315 struct touchsetting *setting =
1316 &region->setting_data;
1317 if (element->params_count < p+1)
1318 return -1;
1320 text = get_param_text(element, p++);
1321 switch (settings[j].flags&F_T_MASK)
1323 case F_T_CUSTOM:
1324 setting->value.text = PTRTOSKINOFFSET(skin_buffer, text);
1325 break;
1326 case F_T_INT:
1327 case F_T_UINT:
1328 if (settings[j].cfg_vals == NULL)
1330 setting->value.number = atoi(text);
1332 else if (cfg_string_to_int(j, &temp, text))
1334 if (settings[j].flags&F_TABLE_SETTING)
1335 setting->value.number =
1336 settings[j].table_setting->values[temp];
1337 else
1338 setting->value.number = temp;
1340 else
1341 return -1;
1342 break;
1343 case F_T_BOOL:
1344 if (cfg_string_to_int(j, &temp, text))
1346 setting->value.number = temp;
1348 else
1349 return -1;
1350 break;
1351 default:
1352 return -1;
1355 return p-param_no;
1356 #endif /* __PCTOOL__ */
1357 return 0;
1360 static int parse_touchregion(struct skin_element *element,
1361 struct wps_token *token,
1362 struct wps_data *wps_data)
1364 (void)token;
1365 unsigned i, imax;
1366 int p;
1367 struct touchregion *region = NULL;
1368 const char *action;
1369 const char pb_string[] = "progressbar";
1370 const char vol_string[] = "volume";
1372 /* format: %T([label,], x,y,width,height,action[, ...])
1373 * if action starts with & the area must be held to happen
1377 region = (struct touchregion*)skin_buffer_alloc(sizeof(struct touchregion));
1378 if (!region)
1379 return WPS_ERROR_INVALID_PARAM;
1381 /* should probably do some bounds checking here with the viewport... but later */
1382 region->action = ACTION_NONE;
1384 if (get_param(element, 0)->type == STRING)
1386 region->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
1387 p = 1;
1388 /* "[SI]III[SI]|SS" is the param list. There MUST be 4 numbers
1389 * followed by at least one string. Verify that here */
1390 if (element->params_count < 6 ||
1391 get_param(element, 4)->type != INTEGER)
1392 return WPS_ERROR_INVALID_PARAM;
1394 else
1396 region->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1397 p = 0;
1400 region->x = get_param(element, p++)->data.number;
1401 region->y = get_param(element, p++)->data.number;
1402 region->width = get_param(element, p++)->data.number;
1403 region->height = get_param(element, p++)->data.number;
1404 region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp);
1405 region->armed = false;
1406 region->reverse_bar = false;
1407 region->value = 0;
1408 region->last_press = 0xffff;
1409 region->press_length = PRESS;
1410 region->allow_while_locked = false;
1411 action = get_param_text(element, p++);
1413 /* figure out the action */
1414 if(!strcmp(pb_string, action))
1415 region->action = ACTION_TOUCH_SCROLLBAR;
1416 else if(!strcmp(vol_string, action))
1417 region->action = ACTION_TOUCH_VOLUME;
1418 else
1420 imax = ARRAYLEN(touchactions);
1421 for (i = 0; i < imax; i++)
1423 /* try to match with one of our touchregion screens */
1424 if (!strcmp(touchactions[i].s, action))
1426 region->action = touchactions[i].action;
1427 if (region->action == ACTION_SETTINGS_INC ||
1428 region->action == ACTION_SETTINGS_DEC ||
1429 region->action == ACTION_SETTINGS_SET)
1431 int val;
1432 if (element->params_count < p+1)
1433 return WPS_ERROR_INVALID_PARAM;
1434 val = touchregion_setup_setting(element, p, region);
1435 if (val < 0)
1436 return WPS_ERROR_INVALID_PARAM;
1437 p += val;
1439 break;
1442 if (region->action == ACTION_NONE)
1443 return WPS_ERROR_INVALID_PARAM;
1445 while (p < element->params_count)
1447 char* param = get_param_text(element, p++);
1448 if (!strcmp(param, "allow_while_locked"))
1449 region->allow_while_locked = true;
1450 else if (!strcmp(param, "reverse_bar"))
1451 region->reverse_bar = true;
1452 else if (!strcmp(param, "repeat_press"))
1453 region->press_length = REPEAT;
1454 else if (!strcmp(param, "long_press"))
1455 region->press_length = LONG_PRESS;
1457 struct skin_token_list *item = new_skin_token_list_item(NULL, region);
1458 if (!item)
1459 return WPS_ERROR_INVALID_PARAM;
1460 add_to_ll_chain(&wps_data->touchregions, item);
1462 if (region->action == ACTION_TOUCH_MUTE)
1464 region->value = global_settings.volume;
1468 return 0;
1470 #endif
1472 static bool check_feature_tag(const int type)
1474 switch (type)
1476 case SKIN_TOKEN_RTC_PRESENT:
1477 #if CONFIG_RTC
1478 return true;
1479 #else
1480 return false;
1481 #endif
1482 case SKIN_TOKEN_HAVE_RECORDING:
1483 #ifdef HAVE_RECORDING
1484 return true;
1485 #else
1486 return false;
1487 #endif
1488 case SKIN_TOKEN_HAVE_TUNER:
1489 #if CONFIG_TUNER
1490 if (radio_hardware_present())
1491 return true;
1492 #endif
1493 return false;
1494 case SKIN_TOKEN_HAVE_TOUCH:
1495 #ifdef HAVE_TOUCHSCREEN
1496 return true;
1497 #else
1498 return false;
1499 #endif
1501 #if CONFIG_TUNER
1502 case SKIN_TOKEN_HAVE_RDS:
1503 #ifdef HAVE_RDS_CAP
1504 return true;
1505 #else
1506 return false;
1507 #endif /* HAVE_RDS_CAP */
1508 #endif /* CONFIG_TUNER */
1509 default: /* not a tag we care about, just don't skip */
1510 return true;
1514 /* This is used to free any buflib allocations before the rest of
1515 * wps_data is reset.
1516 * The call to this in settings_apply_skins() is the last chance to do
1517 * any core_free()'s before wps_data is trashed and those handles lost
1519 void skin_data_free_buflib_allocs(struct wps_data *wps_data)
1521 if (wps_data->wps_loaded)
1522 skin_buffer = get_skin_buffer(wps_data);
1523 #ifdef HAVE_LCD_BITMAP
1524 #ifndef __PCTOOL__
1525 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1526 int *font_ids = SKINOFFSETTOPTR(skin_buffer, wps_data->font_ids);
1527 while (list)
1529 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1530 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1531 if (img->buflib_handle > 0)
1532 core_free(img->buflib_handle);
1533 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1535 wps_data->images = PTRTOSKINOFFSET(skin_buffer, NULL);
1536 if (font_ids != NULL)
1538 while (wps_data->font_count > 0)
1539 font_unload(font_ids[--wps_data->font_count]);
1541 wps_data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1542 if (wps_data->buflib_handle > 0)
1543 core_free(wps_data->buflib_handle);
1544 wps_data->buflib_handle = -1;
1545 #endif
1546 #endif
1550 * initial setup of wps_data; does reset everything
1551 * except fields which need to survive, i.e.
1552 * Also called if the load fails
1554 static void skin_data_reset(struct wps_data *wps_data)
1556 skin_data_free_buflib_allocs(wps_data);
1557 #ifdef HAVE_LCD_BITMAP
1558 wps_data->images = INVALID_OFFSET;
1559 #endif
1560 wps_data->tree = INVALID_OFFSET;
1561 #ifdef HAVE_BACKDROP_IMAGE
1562 if (wps_data->backdrop_id >= 0)
1563 skin_backdrop_unload(wps_data->backdrop_id);
1564 backdrop_filename = NULL;
1565 #endif
1566 #ifdef HAVE_TOUCHSCREEN
1567 wps_data->touchregions = INVALID_OFFSET;
1568 #endif
1569 #ifdef HAVE_SKIN_VARIABLES
1570 wps_data->skinvars = INVALID_OFFSET;
1571 #endif
1572 #ifdef HAVE_ALBUMART
1573 wps_data->albumart = INVALID_OFFSET;
1574 if (wps_data->playback_aa_slot >= 0)
1576 playback_release_aa_slot(wps_data->playback_aa_slot);
1577 wps_data->playback_aa_slot = -1;
1579 #endif
1581 #ifdef HAVE_LCD_BITMAP
1582 wps_data->peak_meter_enabled = false;
1583 wps_data->wps_sb_tag = false;
1584 wps_data->show_sb_on_wps = false;
1585 #else /* HAVE_LCD_CHARCELLS */
1586 /* progress bars */
1587 int i;
1588 for (i = 0; i < 8; i++)
1590 wps_data->wps_progress_pat[i] = 0;
1592 wps_data->full_line_progressbar = false;
1593 #endif
1594 wps_data->wps_loaded = false;
1597 #ifdef HAVE_LCD_BITMAP
1598 #ifndef __PCTOOL__
1599 static int currently_loading_handle = -1;
1600 static int buflib_move_callback(int handle, void* current, void* new)
1602 (void)current;
1603 (void)new;
1604 if (handle == currently_loading_handle)
1605 return BUFLIB_CB_CANNOT_MOVE;
1606 return BUFLIB_CB_OK;
1608 static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL};
1609 static void lock_handle(int handle)
1611 currently_loading_handle = handle;
1613 static void unlock_handle(void)
1615 currently_loading_handle = -1;
1617 #endif
1619 static int load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir)
1621 (void)wps_data; /* only needed for remote targets */
1622 char img_path[MAX_PATH];
1623 int fd;
1624 int handle;
1625 get_image_filename(bitmap->data, bmpdir,
1626 img_path, sizeof(img_path));
1628 /* load the image */
1629 int format;
1630 #ifdef HAVE_REMOTE_LCD
1631 if (curr_screen == SCREEN_REMOTE)
1632 format = FORMAT_ANY|FORMAT_REMOTE;
1633 else
1634 #endif
1635 format = FORMAT_ANY|FORMAT_TRANSPARENT;
1637 fd = open(img_path, O_RDONLY);
1638 if (fd < 0)
1640 DEBUGF("Couldn't open %s\n", img_path);
1641 return fd;
1643 #ifndef __PCTOOL__
1644 size_t buf_size = read_bmp_fd(fd, bitmap, 0,
1645 format|FORMAT_RETURN_SIZE, NULL);
1646 handle = core_alloc_ex(bitmap->data, buf_size, &buflib_ops);
1647 if (handle < 0)
1649 DEBUGF("Not enough skin buffer: need %zd more.\n",
1650 buf_size - skin_buffer_freespace());
1651 close(fd);
1652 return handle;
1654 lseek(fd, 0, SEEK_SET);
1655 lock_handle(handle);
1656 bitmap->data = core_get_data(handle);
1657 int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
1658 bitmap->data = NULL; /* do this to force a crash later if the
1659 caller doesnt call core_get_data() */
1660 unlock_handle();
1661 close(fd);
1662 if (ret > 0)
1664 /* free unused alpha channel, if any */
1665 core_shrink(handle, core_get_data(handle), ret);
1666 return handle;
1668 else
1670 /* Abort if we can't load an image */
1671 DEBUGF("Couldn't load '%s'\n", img_path);
1672 core_free(handle);
1673 return -1;
1675 #else /* !__PCTOOL__ */
1676 close(fd);
1677 return 1;
1678 #endif
1681 static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
1683 struct skin_token_list *list;
1684 bool retval = true; /* return false if a single image failed to load */
1686 /* regular images */
1687 list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1688 while (list)
1690 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1691 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1692 if (img->bm.data)
1694 if (img->using_preloaded_icons)
1696 img->loaded = true;
1697 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
1699 else
1701 img->buflib_handle = load_skin_bmp(wps_data, &img->bm, bmpdir);
1702 img->loaded = img->buflib_handle >= 0;
1703 if (img->loaded)
1704 img->subimage_height = img->bm.height / img->num_subimages;
1705 else
1706 retval = false;
1709 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1712 #ifdef HAVE_BACKDROP_IMAGE
1713 wps_data->backdrop_id = skin_backdrop_assign(backdrop_filename, bmpdir, curr_screen);
1714 #endif /* has backdrop support */
1715 return retval;
1718 static bool skin_load_fonts(struct wps_data *data)
1720 /* don't spit out after the first failue to aid debugging */
1721 int id_array[MAXUSERFONTS];
1722 int font_count = 0;
1723 bool success = true;
1724 struct skin_element *vp_list;
1725 int font_id;
1726 /* walk though each viewport and assign its font */
1727 for(vp_list = SKINOFFSETTOPTR(skin_buffer, data->tree);
1728 vp_list; vp_list = SKINOFFSETTOPTR(skin_buffer, vp_list->next))
1730 /* first, find the viewports that have a non-sys/ui-font font */
1731 struct skin_viewport *skin_vp =
1732 SKINOFFSETTOPTR(skin_buffer, vp_list->data);
1733 struct viewport *vp = &skin_vp->vp;
1735 font_id = skin_vp->parsed_fontid;
1736 if (font_id == 1)
1737 { /* the usual case -> built-in fonts */
1738 vp->font = screens[curr_screen].getuifont();
1739 continue;
1741 else if (font_id <= 0)
1743 vp->font = FONT_SYSFIXED;
1744 continue;
1747 /* now find the corresponding skin_font */
1748 struct skin_font *font = &skinfonts[font_id-2];
1749 if (!font->name)
1751 if (success)
1753 DEBUGF("font %d not specified\n", font_id);
1755 success = false;
1756 continue;
1759 /* load the font - will handle loading the same font again if
1760 * multiple viewports use the same */
1761 if (font->id < 0)
1763 char path[MAX_PATH];
1764 snprintf(path, sizeof path, FONT_DIR "/%s", font->name);
1765 #ifndef __PCTOOL__
1766 font->id = font_load_ex(path, 0, skinfonts[font_id-2].glyphs);
1768 #else
1769 font->id = font_load(path);
1770 #endif
1771 //printf("[%d] %s -> %d\n",font_id, font->name, font->id);
1772 id_array[font_count++] = font->id;
1775 if (font->id < 0)
1777 DEBUGF("Unable to load font %d: '%s.fnt'\n",
1778 font_id, font->name);
1779 font->name = NULL; /* to stop trying to load it again if we fail */
1780 success = false;
1781 continue;
1784 /* finally, assign the font_id to the viewport */
1785 vp->font = font->id;
1787 if (font_count)
1789 int *font_ids = skin_buffer_alloc(font_count * sizeof(int));
1790 if (!success || font_ids == NULL)
1792 while (font_count > 0)
1794 if(id_array[--font_count] != -1)
1795 font_unload(id_array[font_count]);
1797 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1798 return false;
1800 memcpy(font_ids, id_array, sizeof(int)*font_count);
1801 data->font_count = font_count;
1802 data->font_ids = PTRTOSKINOFFSET(skin_buffer, font_ids);
1804 else
1806 data->font_count = 0;
1807 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1809 return success;
1812 #endif /* HAVE_LCD_BITMAP */
1813 static int convert_viewport(struct wps_data *data, struct skin_element* element)
1815 struct skin_viewport *skin_vp =
1816 (struct skin_viewport *)skin_buffer_alloc(sizeof(struct skin_viewport));
1817 struct screen *display = &screens[curr_screen];
1819 if (!skin_vp)
1820 return CALLBACK_ERROR;
1822 skin_vp->hidden_flags = 0;
1823 skin_vp->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1824 skin_vp->is_infovp = false;
1825 skin_vp->parsed_fontid = 1;
1826 element->data = PTRTOSKINOFFSET(skin_buffer, skin_vp);
1827 curr_vp = skin_vp;
1828 curr_viewport_element = element;
1829 if (!first_viewport)
1830 first_viewport = element;
1832 viewport_set_defaults(&skin_vp->vp, curr_screen);
1834 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1835 skin_vp->output_to_backdrop_buffer = false;
1836 skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
1837 skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
1838 #endif
1839 #ifdef HAVE_LCD_COLOR
1840 skin_vp->start_gradient.start = skin_vp->vp.lss_pattern;
1841 skin_vp->start_gradient.end = skin_vp->vp.lse_pattern;
1842 skin_vp->start_gradient.text = skin_vp->vp.lst_pattern;
1843 #endif
1846 struct skin_tag_parameter *param = get_param(element, 0);
1847 if (element->params_count == 0) /* default viewport */
1849 if (data->tree < 0) /* first viewport in the skin */
1850 data->tree = PTRTOSKINOFFSET(skin_buffer, element);
1851 skin_vp->label = VP_DEFAULT_LABEL;
1852 return CALLBACK_OK;
1855 if (element->params_count == 6)
1857 if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
1859 skin_vp->is_infovp = true;
1860 if (isdefault(param))
1862 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1863 skin_vp->label = VP_DEFAULT_LABEL;
1865 else
1867 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1868 skin_vp->label = param->data.text;
1871 else
1873 skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN;
1874 skin_vp->label = param->data.text;
1876 param++;
1878 /* x */
1879 if (!isdefault(param))
1881 skin_vp->vp.x = param->data.number;
1882 if (param->data.number < 0)
1883 skin_vp->vp.x += display->lcdwidth;
1885 param++;
1886 /* y */
1887 if (!isdefault(param))
1889 skin_vp->vp.y = param->data.number;
1890 if (param->data.number < 0)
1891 skin_vp->vp.y += display->lcdheight;
1893 param++;
1894 /* width */
1895 if (!isdefault(param))
1897 skin_vp->vp.width = param->data.number;
1898 if (param->data.number < 0)
1899 skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
1901 else
1903 skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x;
1905 param++;
1906 /* height */
1907 if (!isdefault(param))
1909 skin_vp->vp.height = param->data.number;
1910 if (param->data.number < 0)
1911 skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
1913 else
1915 skin_vp->vp.height = display->lcdheight - skin_vp->vp.y;
1917 param++;
1918 #ifdef HAVE_LCD_BITMAP
1919 /* font */
1920 if (!isdefault(param))
1921 skin_vp->parsed_fontid = param->data.number;
1922 #endif
1923 if ((unsigned) skin_vp->vp.x >= (unsigned) display->lcdwidth ||
1924 skin_vp->vp.width + skin_vp->vp.x > display->lcdwidth ||
1925 (unsigned) skin_vp->vp.y >= (unsigned) display->lcdheight ||
1926 skin_vp->vp.height + skin_vp->vp.y > display->lcdheight)
1927 return CALLBACK_ERROR;
1929 return CALLBACK_OK;
1932 static int skin_element_callback(struct skin_element* element, void* data)
1934 struct wps_data *wps_data = (struct wps_data *)data;
1935 struct wps_token *token;
1936 parse_function function = NULL;
1938 switch (element->type)
1940 /* IMPORTANT: element params are shared, so copy them if needed
1941 * or use then NOW, dont presume they have a long lifespan
1943 case TAG:
1945 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
1946 memset(token, 0, sizeof(*token));
1947 token->type = element->tag->type;
1948 token->value.data = INVALID_OFFSET;
1950 if (element->tag->flags&SKIN_RTC_REFRESH)
1952 #if CONFIG_RTC
1953 curr_line->update_mode |= SKIN_REFRESH_DYNAMIC;
1954 #else
1955 curr_line->update_mode |= SKIN_REFRESH_STATIC;
1956 #endif
1958 else
1959 curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL;
1961 element->data = PTRTOSKINOFFSET(skin_buffer, token);
1963 /* Some tags need special handling for the tag, so add them here */
1964 switch (token->type)
1966 case SKIN_TOKEN_ALIGN_LANGDIRECTION:
1967 follow_lang_direction = 2;
1968 break;
1969 case SKIN_TOKEN_LOGICAL_IF:
1970 function = parse_logical_if;
1971 break;
1972 case SKIN_TOKEN_LOGICAL_AND:
1973 case SKIN_TOKEN_LOGICAL_OR:
1974 function = parse_logical_andor;
1975 break;
1976 case SKIN_TOKEN_SUBSTRING:
1977 function = parse_substring_tag;
1978 break;
1979 case SKIN_TOKEN_PROGRESSBAR:
1980 case SKIN_TOKEN_VOLUME:
1981 case SKIN_TOKEN_BATTERY_PERCENT:
1982 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1983 case SKIN_TOKEN_PEAKMETER_LEFT:
1984 case SKIN_TOKEN_PEAKMETER_RIGHT:
1985 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
1986 #ifdef HAVE_RADIO_RSSI
1987 case SKIN_TOKEN_TUNER_RSSI:
1988 #endif
1989 function = parse_progressbar_tag;
1990 break;
1991 case SKIN_TOKEN_SUBLINE_TIMEOUT:
1992 case SKIN_TOKEN_BUTTON_VOLUME:
1993 case SKIN_TOKEN_TRACK_STARTING:
1994 case SKIN_TOKEN_TRACK_ENDING:
1995 function = parse_timeout_tag;
1996 break;
1997 #ifdef HAVE_LCD_BITMAP
1998 case SKIN_TOKEN_LIST_ITEM_TEXT:
1999 case SKIN_TOKEN_LIST_ITEM_ICON:
2000 function = parse_listitem;
2001 break;
2002 case SKIN_TOKEN_DISABLE_THEME:
2003 case SKIN_TOKEN_ENABLE_THEME:
2004 case SKIN_TOKEN_DRAW_INBUILTBAR:
2005 function = parse_statusbar_tags;
2006 break;
2007 case SKIN_TOKEN_LIST_TITLE_TEXT:
2008 #ifndef __PCTOOL__
2009 sb_skin_has_title(curr_screen);
2010 #endif
2011 break;
2012 #endif
2013 case SKIN_TOKEN_FILE_DIRECTORY:
2014 token->value.i = get_param(element, 0)->data.number;
2015 break;
2016 #ifdef HAVE_BACKDROP_IMAGE
2017 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
2018 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
2019 function = parse_viewportcolour;
2020 break;
2021 case SKIN_TOKEN_IMAGE_BACKDROP:
2022 function = parse_image_special;
2023 break;
2024 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE:
2025 function = parse_viewporttextstyle;
2026 break;
2027 case SKIN_TOKEN_VIEWPORT_DRAWONBG:
2028 curr_vp->output_to_backdrop_buffer = true;
2029 backdrop_filename = BACKDROP_BUFFERNAME;
2030 wps_data->use_extra_framebuffer = true;
2031 break;
2032 #endif
2033 #ifdef HAVE_LCD_COLOR
2034 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP:
2035 function = parse_viewport_gradient_setup;
2036 break;
2037 #endif
2038 case SKIN_TOKEN_TRANSLATEDSTRING:
2039 case SKIN_TOKEN_SETTING:
2040 function = parse_setting_and_lang;
2041 break;
2042 #ifdef HAVE_LCD_BITMAP
2043 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
2044 function = parse_playlistview;
2045 break;
2046 case SKIN_TOKEN_LOAD_FONT:
2047 function = parse_font_load;
2048 break;
2049 case SKIN_TOKEN_VIEWPORT_ENABLE:
2050 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
2051 token->value.data = get_param(element, 0)->data.text;
2052 break;
2053 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
2054 function = parse_image_display;
2055 break;
2056 case SKIN_TOKEN_IMAGE_PRELOAD:
2057 case SKIN_TOKEN_IMAGE_DISPLAY:
2058 function = parse_image_load;
2059 break;
2060 case SKIN_TOKEN_LIST_ITEM_CFG:
2061 function = parse_listitemviewport;
2062 break;
2063 #endif
2064 #ifdef HAVE_TOUCHSCREEN
2065 case SKIN_TOKEN_TOUCHREGION:
2066 function = parse_touchregion;
2067 break;
2068 case SKIN_TOKEN_LASTTOUCH:
2069 function = parse_lasttouch;
2070 break;
2071 #endif
2072 #ifdef HAVE_ALBUMART
2073 case SKIN_TOKEN_ALBUMART_DISPLAY:
2074 if (SKINOFFSETTOPTR(skin_buffer, wps_data->albumart))
2076 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2077 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
2079 break;
2080 case SKIN_TOKEN_ALBUMART_LOAD:
2081 function = parse_albumart_load;
2082 break;
2083 #endif
2084 #ifdef HAVE_SKIN_VARIABLES
2085 case SKIN_TOKEN_VAR_SET:
2086 case SKIN_TOKEN_VAR_GETVAL:
2087 case SKIN_TOKEN_VAR_TIMEOUT:
2088 function = parse_skinvar;
2089 break;
2090 #endif
2091 default:
2092 break;
2094 if (function)
2096 if (function(element, token, wps_data) < 0)
2097 return CALLBACK_ERROR;
2099 /* tags that start with 'F', 'I' or 'D' are for the next file */
2100 if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' ||
2101 *(element->tag->name) == 'D')
2102 token->next = true;
2103 if (follow_lang_direction > 0 )
2104 follow_lang_direction--;
2105 break;
2107 case VIEWPORT:
2108 return convert_viewport(wps_data, element);
2109 case LINE:
2111 struct line *line =
2112 (struct line *)skin_buffer_alloc(sizeof(struct line));
2113 line->update_mode = SKIN_REFRESH_STATIC;
2114 curr_line = line;
2115 element->data = PTRTOSKINOFFSET(skin_buffer, line);
2117 break;
2118 case LINE_ALTERNATOR:
2120 struct line_alternator *alternator =
2121 (struct line_alternator *)skin_buffer_alloc(sizeof(struct line_alternator));
2122 alternator->current_line = 0;
2123 #ifndef __PCTOOL__
2124 alternator->next_change_tick = current_tick;
2125 #endif
2126 element->data = PTRTOSKINOFFSET(skin_buffer, alternator);
2128 break;
2129 case CONDITIONAL:
2131 struct conditional *conditional =
2132 (struct conditional *)skin_buffer_alloc(sizeof(struct conditional));
2133 conditional->last_value = -1;
2134 conditional->token = element->data;
2135 element->data = PTRTOSKINOFFSET(skin_buffer, conditional);
2136 if (!check_feature_tag(element->tag->type))
2138 return FEATURE_NOT_AVAILABLE;
2140 return CALLBACK_OK;
2142 case TEXT:
2143 curr_line->update_mode |= SKIN_REFRESH_STATIC;
2144 break;
2145 default:
2146 break;
2148 return CALLBACK_OK;
2151 /* to setup up the wps-data from a format-buffer (isfile = false)
2152 from a (wps-)file (isfile = true)*/
2153 bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2154 const char *buf, bool isfile)
2156 char *wps_buffer = NULL;
2157 if (!wps_data || !buf)
2158 return false;
2159 #ifdef HAVE_ALBUMART
2160 int status;
2161 struct mp3entry *curtrack;
2162 long offset;
2163 struct skin_albumart old_aa = {.state = WPS_ALBUMART_NONE};
2164 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2165 if (aa)
2167 old_aa.state = aa->state;
2168 old_aa.height = aa->height;
2169 old_aa.width = aa->width;
2171 #endif
2172 #ifdef HAVE_LCD_BITMAP
2173 int i;
2174 for (i=0;i<MAXUSERFONTS;i++)
2176 skinfonts[i].id = -1;
2177 skinfonts[i].name = NULL;
2179 #endif
2180 #ifdef DEBUG_SKIN_ENGINE
2181 if (isfile && debug_wps)
2183 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf);
2185 #endif
2188 /* get buffer space from the plugin buffer */
2189 size_t buffersize = 0;
2190 wps_buffer = (char *)plugin_get_buffer(&buffersize);
2192 if (!wps_buffer)
2193 return false;
2195 skin_data_reset(wps_data);
2196 wps_data->wps_loaded = false;
2197 curr_screen = screen;
2198 curr_line = NULL;
2199 curr_vp = NULL;
2200 curr_viewport_element = NULL;
2201 first_viewport = NULL;
2203 if (isfile)
2205 int fd = open_utf8(buf, O_RDONLY);
2207 if (fd < 0)
2208 return false;
2209 /* copy the file's content to the buffer for parsing,
2210 ensuring that every line ends with a newline char. */
2211 unsigned int start = 0;
2212 while(read_line(fd, wps_buffer + start, buffersize - start) > 0)
2214 start += strlen(wps_buffer + start);
2215 if (start < buffersize - 1)
2217 wps_buffer[start++] = '\n';
2218 wps_buffer[start] = 0;
2221 close(fd);
2222 if (start <= 0)
2223 return false;
2224 start++;
2225 skin_buffer = &wps_buffer[start];
2226 buffersize -= start;
2228 else
2230 skin_buffer = wps_buffer;
2231 wps_buffer = (char*)buf;
2233 skin_buffer = (void *)(((unsigned long)skin_buffer + 3) & ~3);
2234 buffersize -= 3;
2235 #ifdef HAVE_BACKDROP_IMAGE
2236 backdrop_filename = "-";
2237 wps_data->backdrop_id = -1;
2238 #endif
2239 /* parse the skin source */
2240 skin_buffer_init(skin_buffer, buffersize);
2241 struct skin_element *tree = skin_parse(wps_buffer, skin_element_callback, wps_data);
2242 wps_data->tree = PTRTOSKINOFFSET(skin_buffer, tree);
2243 if (!SKINOFFSETTOPTR(skin_buffer, wps_data->tree)) {
2244 skin_data_reset(wps_data);
2245 return false;
2248 #ifdef HAVE_LCD_BITMAP
2249 char bmpdir[MAX_PATH];
2250 if (isfile)
2252 /* get the bitmap dir */
2253 char *dot = strrchr(buf, '.');
2254 strlcpy(bmpdir, buf, dot - buf + 1);
2256 else
2258 snprintf(bmpdir, MAX_PATH, "%s", BACKDROP_DIR);
2260 /* load the bitmaps that were found by the parsing */
2261 if (!load_skin_bitmaps(wps_data, bmpdir) ||
2262 !skin_load_fonts(wps_data))
2264 skin_data_reset(wps_data);
2265 return false;
2267 #endif
2268 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2269 status = audio_status();
2270 if (status & AUDIO_STATUS_PLAY)
2272 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2273 if (aa && ((aa->state && !old_aa.state) ||
2274 (aa->state &&
2275 (((old_aa.height != aa->height) ||
2276 (old_aa.width != aa->width))))))
2278 curtrack = audio_current_track();
2279 offset = curtrack->offset;
2280 audio_stop();
2281 if (!(status & AUDIO_STATUS_PAUSE))
2282 audio_play(offset);
2285 #endif
2286 #ifndef __PCTOOL__
2287 wps_data->buflib_handle = core_alloc(isfile ? buf : "failsafe skin",
2288 skin_buffer_usage());
2289 if (wps_data->buflib_handle >= 0)
2291 wps_data->wps_loaded = true;
2292 memcpy(core_get_data(wps_data->buflib_handle), skin_buffer,
2293 skin_buffer_usage());
2295 #else
2296 wps_data->wps_loaded = wps_data->tree >= 0;
2297 #endif
2298 #ifdef DEBUG_SKIN_ENGINE
2299 // if (isfile && debug_wps)
2300 // debug_skin_usage();
2301 #endif
2302 return true;