skin_engine: New tag to draw a rectangle (optionally with a gradient)
[maemo-rb.git] / apps / gui / skin_engine / skin_parser.c
blob49373eca3297ca9f2de6a85c21bb27b0a7bd32af
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 = 0,y = 0, subimages = 1;
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,y,num_subimages handling:
401 * If all 3 are left out use sane defaults.
402 * If there are 2 params it must be x,y
403 * if there is only 1 param it must be the num_subimages
405 if (element->params_count == 3)
406 subimages = get_param(element, 2)->data.number;
407 else if (element->params_count > 3)
409 x = get_param(element, 2)->data.number;
410 y = get_param(element, 3)->data.number;
411 if (element->params_count == 5)
412 subimages = get_param(element, 4)->data.number;
414 /* check the image number and load state */
415 if(skin_find_item(id, SKIN_FIND_IMAGE, wps_data))
417 /* Invalid image ID */
418 return WPS_ERROR_INVALID_PARAM;
420 img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img));
421 if (!img)
422 return WPS_ERROR_INVALID_PARAM;
423 /* save a pointer to the filename */
424 img->bm.data = (char*)filename;
425 img->label = PTRTOSKINOFFSET(skin_buffer, (void*)id);
426 img->x = x;
427 img->y = y;
428 img->num_subimages = subimages;
429 img->display = -1;
430 img->using_preloaded_icons = false;
431 img->buflib_handle = -1;
433 /* save current viewport */
434 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
436 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
437 token->value.data = PTRTOSKINOFFSET(skin_buffer, img);
439 if (!strcmp(img->bm.data, "__list_icons__"))
441 img->num_subimages = Icon_Last_Themeable;
442 img->using_preloaded_icons = true;
445 struct skin_token_list *item =
446 (struct skin_token_list *)new_skin_token_list_item(NULL, img);
447 if (!item)
448 return WPS_ERROR_INVALID_PARAM;
449 add_to_ll_chain(&wps_data->images, item);
451 return 0;
453 struct skin_font {
454 int id; /* the id from font_load */
455 char *name; /* filename without path and extension */
456 int glyphs; /* how many glyphs to reserve room for */
458 static struct skin_font skinfonts[MAXUSERFONTS];
459 static int parse_font_load(struct skin_element *element,
460 struct wps_token *token,
461 struct wps_data *wps_data)
463 (void)wps_data; (void)token;
464 int id = get_param(element, 0)->data.number;
465 char *filename = get_param_text(element, 1);
466 int glyphs;
467 char *ptr;
469 if(element->params_count > 2)
470 glyphs = get_param(element, 2)->data.number;
471 else
472 glyphs = global_settings.glyphs_to_cache;
473 if (id < 2)
475 DEBUGF("font id must be >= 2\n");
476 return 1;
478 #if defined(DEBUG) || defined(SIMULATOR)
479 if (skinfonts[id-2].name != NULL)
481 DEBUGF("font id %d already being used\n", id);
483 #endif
484 /* make sure the filename contains .fnt,
485 * we dont actually use it, but require it anyway */
486 ptr = strchr(filename, '.');
487 if (!ptr || strncmp(ptr, ".fnt", 4))
488 return WPS_ERROR_INVALID_PARAM;
489 skinfonts[id-2].id = -1;
490 skinfonts[id-2].name = filename;
491 skinfonts[id-2].glyphs = glyphs;
493 return 0;
497 #ifdef HAVE_LCD_BITMAP
499 static int parse_playlistview(struct skin_element *element,
500 struct wps_token *token,
501 struct wps_data *wps_data)
503 (void)wps_data;
504 struct playlistviewer *viewer =
505 (struct playlistviewer *)skin_buffer_alloc(sizeof(struct playlistviewer));
506 if (!viewer)
507 return WPS_ERROR_INVALID_PARAM;
508 viewer->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
509 viewer->show_icons = true;
510 viewer->start_offset = get_param(element, 0)->data.number;
511 viewer->line = PTRTOSKINOFFSET(skin_buffer, get_param_code(element, 1));
513 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)viewer);
515 return 0;
517 #endif
518 #ifdef HAVE_LCD_COLOR
519 static int parse_viewport_gradient_setup(struct skin_element *element,
520 struct wps_token *token,
521 struct wps_data *wps_data)
523 (void)wps_data;
524 struct gradient_config *cfg;
525 if (element->params_count < 2) /* only start and end are required */
526 return 1;
527 cfg = (struct gradient_config *)skin_buffer_alloc(sizeof(struct gradient_config));
528 if (!cfg)
529 return 1;
530 if (!parse_color(curr_screen, get_param_text(element, 0), &cfg->start) ||
531 !parse_color(curr_screen, get_param_text(element, 1), &cfg->end))
532 return 1;
533 if (element->params_count > 2)
535 if (!parse_color(curr_screen, get_param_text(element, 2), &cfg->text))
536 return 1;
538 else
540 cfg->text = curr_vp->vp.fg_pattern;
543 token->value.data = PTRTOSKINOFFSET(skin_buffer, cfg);
544 return 0;
546 #endif
548 static int parse_listitem(struct skin_element *element,
549 struct wps_token *token,
550 struct wps_data *wps_data)
552 (void)wps_data;
553 struct listitem *li = (struct listitem *)skin_buffer_alloc(sizeof(struct listitem));
554 if (!li)
555 return 1;
556 token->value.data = PTRTOSKINOFFSET(skin_buffer, li);
557 if (element->params_count == 0)
558 li->offset = 0;
559 else
561 li->offset = get_param(element, 0)->data.number;
562 if (element->params_count > 1)
563 li->wrap = strcasecmp(get_param_text(element, 1), "nowrap") != 0;
564 else
565 li->wrap = true;
567 return 0;
570 static int parse_listitemviewport(struct skin_element *element,
571 struct wps_token *token,
572 struct wps_data *wps_data)
574 #ifndef __PCTOOL__
575 struct listitem_viewport_cfg *cfg =
576 (struct listitem_viewport_cfg *)skin_buffer_alloc(
577 sizeof(struct listitem_viewport_cfg));
578 if (!cfg)
579 return -1;
580 cfg->data = wps_data;
581 cfg->tile = false;
582 cfg->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
583 cfg->width = -1;
584 cfg->height = -1;
585 if (!isdefault(get_param(element, 1)))
586 cfg->width = get_param(element, 1)->data.number;
587 if (!isdefault(get_param(element, 2)))
588 cfg->height = get_param(element, 2)->data.number;
589 if (element->params_count > 3 &&
590 !strcmp(get_param_text(element, 3), "tile"))
591 cfg->tile = true;
592 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)cfg);
593 #endif
594 return 0;
597 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
598 static int parse_viewporttextstyle(struct skin_element *element,
599 struct wps_token *token,
600 struct wps_data *wps_data)
602 (void)wps_data;
603 int style;
604 char *mode = get_param_text(element, 0);
605 unsigned colour;
607 if (!strcmp(mode, "invert"))
609 style = STYLE_INVERT;
611 else if (!strcmp(mode, "colour") || !strcmp(mode, "color"))
613 if (element->params_count < 2 ||
614 !parse_color(curr_screen, get_param_text(element, 1), &colour))
615 return 1;
616 style = STYLE_COLORED|(STYLE_COLOR_MASK&colour);
618 #ifdef HAVE_LCD_COLOR
619 else if (!strcmp(mode, "gradient"))
621 int num_lines;
622 if (element->params_count < 2)
623 num_lines = 1;
624 else /* atoi() instead of using a number in the parser is because [si]
625 * will select the number for something which looks like a colour
626 * making the "colour" case (above) harder to parse */
627 num_lines = atoi(get_param_text(element, 1));
628 style = STYLE_GRADIENT|NUMLN_PACK(num_lines)|CURLN_PACK(0);
630 #endif
631 else if (!strcmp(mode, "clear"))
633 style = STYLE_DEFAULT;
635 else
636 return 1;
637 token->value.l = style;
638 return 0;
641 static int parse_drawrectangle( struct skin_element *element,
642 struct wps_token *token,
643 struct wps_data *wps_data)
645 (void)wps_data;
646 struct draw_rectangle *rect =
647 (struct draw_rectangle *)skin_buffer_alloc(sizeof(struct draw_rectangle));
649 if (!rect)
650 return -1;
652 rect->x = get_param(element, 0)->data.number;
653 rect->y = get_param(element, 1)->data.number;
655 if (isdefault(get_param(element, 2)))
656 rect->width = curr_vp->vp.width - rect->x;
657 else
658 rect->width = get_param(element, 2)->data.number;
660 if (isdefault(get_param(element, 3)))
661 rect->height = curr_vp->vp.height - rect->y;
662 else
663 rect->height = get_param(element, 3)->data.number;
665 rect->start_colour = curr_vp->vp.fg_pattern;
666 rect->end_colour = curr_vp->vp.fg_pattern;
668 if (element->params_count > 4)
670 if (!parse_color(curr_screen, get_param_text(element, 4),
671 &rect->start_colour))
672 return -1;
673 rect->end_colour = rect->start_colour;
675 if (element->params_count > 5)
677 if (!parse_color(curr_screen, get_param_text(element, 5),
678 &rect->end_colour))
679 return -1;
681 token->value.data = PTRTOSKINOFFSET(skin_buffer, rect);
683 return 0;
686 static int parse_viewportcolour(struct skin_element *element,
687 struct wps_token *token,
688 struct wps_data *wps_data)
690 (void)wps_data;
691 struct skin_tag_parameter *param = get_param(element, 0);
692 struct viewport_colour *colour =
693 (struct viewport_colour *)skin_buffer_alloc(sizeof(struct viewport_colour));
694 if (!colour)
695 return -1;
696 if (isdefault(param))
698 colour->colour = get_viewport_default_colour(curr_screen,
699 token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
701 else
703 if (!parse_color(curr_screen, SKINOFFSETTOPTR(skin_buffer, param->data.text),
704 &colour->colour))
705 return -1;
707 colour->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
708 token->value.data = PTRTOSKINOFFSET(skin_buffer, colour);
709 if (element->line == curr_viewport_element->line)
711 if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
713 curr_vp->start_fgcolour = colour->colour;
714 curr_vp->vp.fg_pattern = colour->colour;
716 else
718 curr_vp->start_bgcolour = colour->colour;
719 curr_vp->vp.bg_pattern = colour->colour;
722 return 0;
725 static int parse_image_special(struct skin_element *element,
726 struct wps_token *token,
727 struct wps_data *wps_data)
729 (void)wps_data; /* kill warning */
730 (void)token;
732 #if LCD_DEPTH > 1
733 char *filename;
734 if (token->type == SKIN_TOKEN_IMAGE_BACKDROP)
736 if (isdefault(get_param(element, 0)))
738 filename = "-";
740 else
742 filename = get_param_text(element, 0);
743 /* format: %X(filename.bmp) or %X(d) */
744 if (!strcmp(filename, "d"))
745 filename = NULL;
747 backdrop_filename = filename;
749 #endif
751 return 0;
753 #endif
755 #endif /* HAVE_LCD_BITMAP */
757 static int parse_setting_and_lang(struct skin_element *element,
758 struct wps_token *token,
759 struct wps_data *wps_data)
761 /* NOTE: both the string validations that happen in here will
762 * automatically PASS on checkwps because its too hard to get
763 * settings_list.c and english.lang built for it.
764 * If that ever changes remove the #ifndef __PCTOOL__'s here
766 (void)wps_data;
767 char *temp = get_param_text(element, 0);
768 int i;
770 if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
772 #ifndef __PCTOOL__
773 i = lang_english_to_id(temp);
774 if (i < 0)
775 return WPS_ERROR_INVALID_PARAM;
776 #endif
778 else
780 #ifndef __PCTOOL__
781 if (find_setting_by_cfgname(temp, &i) == NULL)
782 return WPS_ERROR_INVALID_PARAM;
783 #endif
785 /* Store the setting number */
786 token->value.i = i;
787 return 0;
790 static int parse_logical_andor(struct skin_element *element,
791 struct wps_token *token,
792 struct wps_data *wps_data)
794 (void)wps_data;
795 token->value.data = PTRTOSKINOFFSET(skin_buffer, element);
796 return 0;
799 static int parse_logical_if(struct skin_element *element,
800 struct wps_token *token,
801 struct wps_data *wps_data)
803 (void)wps_data;
804 char *op = get_param_text(element, 1);
805 struct logical_if *lif = skin_buffer_alloc(sizeof(struct logical_if));
806 if (!lif)
807 return -1;
808 token->value.data = PTRTOSKINOFFSET(skin_buffer, lif);
809 lif->token = get_param_code(element, 0)->data;
811 if (!strncmp(op, "=", 1))
812 lif->op = IF_EQUALS;
813 else if (!strncmp(op, "!=", 2))
814 lif->op = IF_NOTEQUALS;
815 else if (!strncmp(op, ">=", 2))
816 lif->op = IF_GREATERTHAN_EQ;
817 else if (!strncmp(op, "<=", 2))
818 lif->op = IF_LESSTHAN_EQ;
819 else if (!strncmp(op, ">", 2))
820 lif->op = IF_GREATERTHAN;
821 else if (!strncmp(op, "<", 1))
822 lif->op = IF_LESSTHAN;
824 memcpy(&lif->operand, get_param(element, 2), sizeof(lif->operand));
825 if (element->params_count > 3)
826 lif->num_options = get_param(element, 3)->data.number;
827 else
828 lif->num_options = TOKEN_VALUE_ONLY;
829 return 0;
833 static int parse_timeout_tag(struct skin_element *element,
834 struct wps_token *token,
835 struct wps_data *wps_data)
837 (void)wps_data;
838 int val = 0;
839 if (element->params_count == 0)
841 switch (token->type)
843 case SKIN_TOKEN_SUBLINE_TIMEOUT:
844 return -1;
845 case SKIN_TOKEN_BUTTON_VOLUME:
846 case SKIN_TOKEN_TRACK_STARTING:
847 case SKIN_TOKEN_TRACK_ENDING:
848 val = 10;
849 break;
850 default:
851 break;
854 else
855 val = get_param(element, 0)->data.number;
856 token->value.i = val * TIMEOUT_UNIT;
857 return 0;
860 static int parse_substring_tag(struct skin_element* element,
861 struct wps_token *token,
862 struct wps_data *wps_data)
864 (void)wps_data;
865 struct substring *ss = (struct substring*)skin_buffer_alloc(sizeof(struct substring));
866 if (!ss)
867 return 1;
868 ss->start = get_param(element, 0)->data.number;
869 if (get_param(element, 1)->type == DEFAULT)
870 ss->length = -1;
871 else
872 ss->length = get_param(element, 1)->data.number;
873 ss->token = get_param_code(element, 2)->data;
874 if (element->params_count > 3)
875 ss->expect_number = !strcmp(get_param_text(element, 3), "number");
876 else
877 ss->expect_number = false;
878 token->value.data = PTRTOSKINOFFSET(skin_buffer, ss);
879 return 0;
882 static int parse_progressbar_tag(struct skin_element* element,
883 struct wps_token *token,
884 struct wps_data *wps_data)
886 #ifdef HAVE_LCD_BITMAP
887 struct progressbar *pb;
888 struct viewport *vp = &curr_vp->vp;
889 struct skin_tag_parameter *param = get_param(element, 0);
890 int curr_param = 0;
891 char *image_filename = NULL;
893 if (element->params_count == 0 &&
894 element->tag->type != SKIN_TOKEN_PROGRESSBAR)
895 return 0; /* nothing to do */
896 pb = (struct progressbar*)skin_buffer_alloc(sizeof(struct progressbar));
898 token->value.data = PTRTOSKINOFFSET(skin_buffer, pb);
900 if (!pb)
901 return WPS_ERROR_INVALID_PARAM;
902 pb->vp = PTRTOSKINOFFSET(skin_buffer, vp);
903 pb->follow_lang_direction = follow_lang_direction > 0;
904 pb->nofill = false;
905 pb->nobar = false;
906 pb->image = PTRTOSKINOFFSET(skin_buffer, NULL);
907 pb->slider = PTRTOSKINOFFSET(skin_buffer, NULL);
908 pb->backdrop = PTRTOSKINOFFSET(skin_buffer, NULL);
909 pb->invert_fill_direction = false;
910 pb->horizontal = true;
912 if (element->params_count == 0)
914 pb->x = 0;
915 pb->width = vp->width;
916 pb->height = SYSFONT_HEIGHT-2;
917 pb->y = -1; /* Will be computed during the rendering */
918 pb->type = element->tag->type;
919 return 0;
922 /* (x, y, width, height, ...) */
923 if (!isdefault(param))
924 pb->x = param->data.number;
925 else
926 pb->x = 0;
927 param++;
929 if (!isdefault(param))
930 pb->y = param->data.number;
931 else
932 pb->y = -1; /* computed at rendering */
933 param++;
935 if (!isdefault(param))
936 pb->width = param->data.number;
937 else
938 pb->width = vp->width - pb->x;
939 param++;
941 if (!isdefault(param))
943 /* A zero height makes no sense - reject it */
944 if (param->data.number == 0)
945 return WPS_ERROR_INVALID_PARAM;
947 pb->height = param->data.number;
949 else
951 if (vp->font > FONT_UI)
952 pb->height = -1; /* calculate at display time */
953 else
955 #ifndef __PCTOOL__
956 pb->height = font_get(vp->font)->height;
957 #else
958 pb->height = 8;
959 #endif
962 /* optional params, first is the image filename if it isnt recognised as a keyword */
964 curr_param = 4;
965 if (isdefault(get_param(element, curr_param)))
967 param++;
968 curr_param++;
971 pb->horizontal = pb->width > pb->height;
972 while (curr_param < element->params_count)
974 char* text;
975 param++;
976 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
977 if (!strcmp(text, "invert"))
978 pb->invert_fill_direction = true;
979 else if (!strcmp(text, "nofill"))
980 pb->nofill = true;
981 else if (!strcmp(text, "nobar"))
982 pb->nobar = true;
983 else if (!strcmp(text, "slider"))
985 if (curr_param+1 < element->params_count)
987 curr_param++;
988 param++;
989 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
990 pb->slider = PTRTOSKINOFFSET(skin_buffer,
991 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
993 else /* option needs the next param */
994 return -1;
996 else if (!strcmp(text, "image"))
998 if (curr_param+1 < element->params_count)
1000 curr_param++;
1001 param++;
1002 image_filename = SKINOFFSETTOPTR(skin_buffer, param->data.text);
1004 else /* option needs the next param */
1005 return -1;
1007 else if (!strcmp(text, "backdrop"))
1009 if (curr_param+1 < element->params_count)
1011 curr_param++;
1012 param++;
1013 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
1014 pb->backdrop = PTRTOSKINOFFSET(skin_buffer,
1015 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
1018 else /* option needs the next param */
1019 return -1;
1021 else if (!strcmp(text, "vertical"))
1023 pb->horizontal = false;
1024 if (isdefault(get_param(element, 3)))
1025 pb->height = vp->height - pb->y;
1027 else if (!strcmp(text, "horizontal"))
1028 pb->horizontal = true;
1029 else if (curr_param == 4)
1030 image_filename = text;
1032 curr_param++;
1035 if (image_filename)
1037 pb->image = PTRTOSKINOFFSET(skin_buffer,
1038 skin_find_item(image_filename, SKIN_FIND_IMAGE, wps_data));
1039 if (!SKINOFFSETTOPTR(skin_buffer, pb->image)) /* load later */
1041 struct gui_img* img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img));
1042 if (!img)
1043 return WPS_ERROR_INVALID_PARAM;
1044 /* save a pointer to the filename */
1045 img->bm.data = (char*)image_filename;
1046 img->label = PTRTOSKINOFFSET(skin_buffer, image_filename);
1047 img->x = 0;
1048 img->y = 0;
1049 img->num_subimages = 1;
1050 img->display = -1;
1051 img->using_preloaded_icons = false;
1052 img->buflib_handle = -1;
1053 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1054 struct skin_token_list *item =
1055 (struct skin_token_list *)new_skin_token_list_item(NULL, img);
1056 if (!item)
1057 return WPS_ERROR_INVALID_PARAM;
1058 add_to_ll_chain(&wps_data->images, item);
1059 pb->image = PTRTOSKINOFFSET(skin_buffer, img);
1063 if (token->type == SKIN_TOKEN_VOLUME)
1064 token->type = SKIN_TOKEN_VOLUMEBAR;
1065 else if (token->type == SKIN_TOKEN_BATTERY_PERCENT)
1066 token->type = SKIN_TOKEN_BATTERY_PERCENTBAR;
1067 else if (token->type == SKIN_TOKEN_TUNER_RSSI)
1068 token->type = SKIN_TOKEN_TUNER_RSSI_BAR;
1069 else if (token->type == SKIN_TOKEN_PEAKMETER_LEFT)
1070 token->type = SKIN_TOKEN_PEAKMETER_LEFTBAR;
1071 else if (token->type == SKIN_TOKEN_PEAKMETER_RIGHT)
1072 token->type = SKIN_TOKEN_PEAKMETER_RIGHTBAR;
1073 else if (token->type == SKIN_TOKEN_LIST_NEEDS_SCROLLBAR)
1074 token->type = SKIN_TOKEN_LIST_SCROLLBAR;
1075 pb->type = token->type;
1077 return 0;
1079 #else
1080 (void)element;
1081 if (token->type == SKIN_TOKEN_PROGRESSBAR ||
1082 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR)
1084 wps_data->full_line_progressbar =
1085 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR;
1087 return 0;
1089 #endif
1092 #ifdef HAVE_ALBUMART
1093 static int parse_albumart_load(struct skin_element* element,
1094 struct wps_token *token,
1095 struct wps_data *wps_data)
1097 struct dim dimensions;
1098 int albumart_slot;
1099 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction;
1100 struct skin_albumart *aa =
1101 (struct skin_albumart *)skin_buffer_alloc(sizeof(struct skin_albumart));
1102 (void)token; /* silence warning */
1103 if (!aa)
1104 return -1;
1106 /* reset albumart info in wps */
1107 aa->width = -1;
1108 aa->height = -1;
1109 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1110 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1112 aa->x = get_param(element, 0)->data.number;
1113 aa->y = get_param(element, 1)->data.number;
1114 aa->width = get_param(element, 2)->data.number;
1115 aa->height = get_param(element, 3)->data.number;
1117 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1118 aa->draw_handle = -1;
1120 /* if we got here, we parsed everything ok .. ! */
1121 if (aa->width < 0)
1122 aa->width = 0;
1123 else if (aa->width > LCD_WIDTH)
1124 aa->width = LCD_WIDTH;
1126 if (aa->height < 0)
1127 aa->height = 0;
1128 else if (aa->height > LCD_HEIGHT)
1129 aa->height = LCD_HEIGHT;
1131 if (swap_for_rtl)
1132 aa->x = LCD_WIDTH - (aa->x + aa->width);
1134 aa->state = WPS_ALBUMART_LOAD;
1135 wps_data->albumart = PTRTOSKINOFFSET(skin_buffer, aa);
1137 dimensions.width = aa->width;
1138 dimensions.height = aa->height;
1140 albumart_slot = playback_claim_aa_slot(&dimensions);
1142 if (0 <= albumart_slot)
1143 wps_data->playback_aa_slot = albumart_slot;
1145 if (element->params_count > 4 && !isdefault(get_param(element, 4)))
1147 switch (*get_param_text(element, 4))
1149 case 'l':
1150 case 'L':
1151 if (swap_for_rtl)
1152 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1153 else
1154 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1155 break;
1156 case 'c':
1157 case 'C':
1158 aa->xalign = WPS_ALBUMART_ALIGN_CENTER;
1159 break;
1160 case 'r':
1161 case 'R':
1162 if (swap_for_rtl)
1163 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1164 else
1165 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1166 break;
1169 if (element->params_count > 5 && !isdefault(get_param(element, 5)))
1171 switch (*get_param_text(element, 5))
1173 case 't':
1174 case 'T':
1175 aa->yalign = WPS_ALBUMART_ALIGN_TOP;
1176 break;
1177 case 'c':
1178 case 'C':
1179 aa->yalign = WPS_ALBUMART_ALIGN_CENTER;
1180 break;
1181 case 'b':
1182 case 'B':
1183 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM;
1184 break;
1187 return 0;
1190 #endif /* HAVE_ALBUMART */
1191 #ifdef HAVE_SKIN_VARIABLES
1192 static struct skin_var* find_or_add_var(const char* label,
1193 struct wps_data *data)
1195 struct skin_var* ret = skin_find_item(label, SKIN_VARIABLE, data);
1196 if (!ret)
1198 ret = (struct skin_var*)skin_buffer_alloc(sizeof(struct skin_var));
1199 if (!ret)
1200 return NULL;
1201 ret->label = PTRTOSKINOFFSET(skin_buffer, label);
1202 ret->value = 1;
1203 ret->last_changed = 0xffff;
1204 struct skin_token_list *item = new_skin_token_list_item(NULL, ret);
1205 if (!item)
1206 return NULL;
1207 add_to_ll_chain(&data->skinvars, item);
1209 return ret;
1211 static int parse_skinvar( struct skin_element *element,
1212 struct wps_token *token,
1213 struct wps_data *wps_data)
1215 const char* label = get_param_text(element, 0);
1216 struct skin_var* var = find_or_add_var(label, wps_data);
1217 if (!var)
1218 return WPS_ERROR_INVALID_PARAM;
1219 switch (token->type)
1221 case SKIN_TOKEN_VAR_GETVAL:
1222 token->value.data = PTRTOSKINOFFSET(skin_buffer, var);
1223 break;
1224 case SKIN_TOKEN_VAR_SET:
1226 struct skin_var_changer *data =
1227 (struct skin_var_changer*)skin_buffer_alloc(
1228 sizeof(struct skin_var_changer));
1229 if (!data)
1230 return WPS_ERROR_INVALID_PARAM;
1231 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1232 if (!isdefault(get_param(element, 2)))
1233 data->newval = get_param(element, 2)->data.number;
1234 else if (strcmp(get_param_text(element, 1), "touch"))
1235 return WPS_ERROR_INVALID_PARAM;
1236 data->max = 0;
1237 if (!strcmp(get_param_text(element, 1), "set"))
1238 data->direct = true;
1239 else if (!strcmp(get_param_text(element, 1), "inc"))
1241 data->direct = false;
1243 else if (!strcmp(get_param_text(element, 1), "dec"))
1245 data->direct = false;
1246 data->newval *= -1;
1248 else if (!strcmp(get_param_text(element, 1), "touch"))
1250 data->direct = false;
1251 data->newval = 0;
1253 if (element->params_count > 3)
1254 data->max = get_param(element, 3)->data.number;
1255 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1257 break;
1258 case SKIN_TOKEN_VAR_TIMEOUT:
1260 struct skin_var_lastchange *data =
1261 (struct skin_var_lastchange*)skin_buffer_alloc(
1262 sizeof(struct skin_var_lastchange));
1263 if (!data)
1264 return WPS_ERROR_INVALID_PARAM;
1265 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1266 data->timeout = 10;
1267 if (element->params_count > 1)
1268 data->timeout = get_param(element, 1)->data.number;
1269 data->timeout *= TIMEOUT_UNIT;
1270 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1272 break;
1273 default: /* kill the warning */
1274 break;
1276 return 0;
1278 #endif /* HAVE_SKIN_VARIABLES */
1279 #ifdef HAVE_TOUCHSCREEN
1280 static int parse_lasttouch(struct skin_element *element,
1281 struct wps_token *token,
1282 struct wps_data *wps_data)
1284 struct touchregion_lastpress *data =
1285 (struct touchregion_lastpress*)skin_buffer_alloc(
1286 sizeof(struct touchregion_lastpress));
1287 int i;
1288 struct touchregion *region = NULL;
1289 if (!data)
1290 return WPS_ERROR_INVALID_PARAM;
1292 data->timeout = 10;
1294 for (i=0; i<element->params_count; i++)
1296 if (get_param(element, i)->type == STRING)
1297 region = skin_find_item(get_param_text(element, i),
1298 SKIN_FIND_TOUCHREGION, wps_data);
1299 else if (get_param(element, i)->type == INTEGER ||
1300 get_param(element, i)->type == DECIMAL)
1301 data->timeout = get_param(element, i)->data.number;
1304 data->region = PTRTOSKINOFFSET(skin_buffer, region);
1305 data->timeout *= TIMEOUT_UNIT;
1306 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1307 return 0;
1310 struct touchaction {const char* s; int action;};
1311 static const struct touchaction touchactions[] = {
1312 /* generic actions, convert to screen actions on use */
1313 {"none", ACTION_TOUCHSCREEN_IGNORE},{"lock", ACTION_TOUCH_SOFTLOCK },
1314 {"prev", ACTION_STD_PREV }, {"next", ACTION_STD_NEXT },
1315 {"hotkey", ACTION_STD_HOTKEY}, {"select", ACTION_STD_OK },
1316 {"menu", ACTION_STD_MENU }, {"cancel", ACTION_STD_CANCEL },
1317 {"contextmenu", ACTION_STD_CONTEXT},{"quickscreen", ACTION_STD_QUICKSCREEN },
1319 /* list/tree actions */
1320 { "resumeplayback", ACTION_TREE_WPS}, /* returns to previous music, WPS/FM */
1321 /* not really WPS specific, but no equivilant ACTION_STD_* */
1322 {"voldown", ACTION_WPS_VOLDOWN}, {"volup", ACTION_WPS_VOLUP},
1323 {"mute", ACTION_TOUCH_MUTE },
1325 /* generic settings changers */
1326 {"setting_inc", ACTION_SETTINGS_INC}, {"setting_dec", ACTION_SETTINGS_DEC},
1327 {"setting_set", ACTION_SETTINGS_SET},
1329 /* WPS specific actions */
1330 {"rwd", ACTION_WPS_SEEKBACK }, {"ffwd", ACTION_WPS_SEEKFWD },
1331 {"wps_prev", ACTION_WPS_SKIPPREV }, {"wps_next", ACTION_WPS_SKIPNEXT },
1332 {"browse", ACTION_WPS_BROWSE },
1333 {"play", ACTION_WPS_PLAY }, {"stop", ACTION_WPS_STOP },
1334 {"shuffle", ACTION_TOUCH_SHUFFLE }, {"repmode", ACTION_TOUCH_REPMODE },
1335 {"pitch", ACTION_WPS_PITCHSCREEN}, {"trackinfo", ACTION_WPS_ID3SCREEN },
1336 {"playlist", ACTION_WPS_VIEW_PLAYLIST },
1337 {"listbookmarks", ACTION_WPS_LIST_BOOKMARKS },
1338 {"createbookmark", ACTION_WPS_CREATE_BOOKMARK },
1340 #if CONFIG_TUNER
1341 /* FM screen actions */
1342 /* Also allow browse, play, stop from WPS codes */
1343 {"mode", ACTION_FM_MODE }, {"record", ACTION_FM_RECORD },
1344 {"presets", ACTION_FM_PRESET},
1345 #endif
1348 static int touchregion_setup_setting(struct skin_element *element, int param_no,
1349 struct touchregion *region)
1351 #ifndef __PCTOOL__
1352 int p = param_no;
1353 char *name = get_param_text(element, p++);
1354 int j;
1356 region->setting_data.setting = find_setting_by_cfgname(name, &j);
1357 if (region->setting_data.setting == NULL)
1358 return WPS_ERROR_INVALID_PARAM;
1360 if (region->action == ACTION_SETTINGS_SET)
1362 char* text;
1363 int temp;
1364 struct touchsetting *setting =
1365 &region->setting_data;
1366 if (element->params_count < p+1)
1367 return -1;
1369 text = get_param_text(element, p++);
1370 switch (settings[j].flags&F_T_MASK)
1372 case F_T_CUSTOM:
1373 setting->value.text = PTRTOSKINOFFSET(skin_buffer, text);
1374 break;
1375 case F_T_INT:
1376 case F_T_UINT:
1377 if (settings[j].cfg_vals == NULL)
1379 setting->value.number = atoi(text);
1381 else if (cfg_string_to_int(j, &temp, text))
1383 if (settings[j].flags&F_TABLE_SETTING)
1384 setting->value.number =
1385 settings[j].table_setting->values[temp];
1386 else
1387 setting->value.number = temp;
1389 else
1390 return -1;
1391 break;
1392 case F_T_BOOL:
1393 if (cfg_string_to_int(j, &temp, text))
1395 setting->value.number = temp;
1397 else
1398 return -1;
1399 break;
1400 default:
1401 return -1;
1404 return p-param_no;
1405 #endif /* __PCTOOL__ */
1406 return 0;
1409 static int parse_touchregion(struct skin_element *element,
1410 struct wps_token *token,
1411 struct wps_data *wps_data)
1413 (void)token;
1414 unsigned i, imax;
1415 int p;
1416 struct touchregion *region = NULL;
1417 const char *action;
1418 const char pb_string[] = "progressbar";
1419 const char vol_string[] = "volume";
1421 /* format: %T([label,], x,y,width,height,action[, ...])
1422 * if action starts with & the area must be held to happen
1426 region = (struct touchregion*)skin_buffer_alloc(sizeof(struct touchregion));
1427 if (!region)
1428 return WPS_ERROR_INVALID_PARAM;
1430 /* should probably do some bounds checking here with the viewport... but later */
1431 region->action = ACTION_NONE;
1433 if (get_param(element, 0)->type == STRING)
1435 region->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
1436 p = 1;
1437 /* "[SI]III[SI]|SS" is the param list. There MUST be 4 numbers
1438 * followed by at least one string. Verify that here */
1439 if (element->params_count < 6 ||
1440 get_param(element, 4)->type != INTEGER)
1441 return WPS_ERROR_INVALID_PARAM;
1443 else
1445 region->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1446 p = 0;
1449 region->x = get_param(element, p++)->data.number;
1450 region->y = get_param(element, p++)->data.number;
1451 region->width = get_param(element, p++)->data.number;
1452 region->height = get_param(element, p++)->data.number;
1453 region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp);
1454 region->armed = false;
1455 region->reverse_bar = false;
1456 region->value = 0;
1457 region->last_press = 0xffff;
1458 region->press_length = PRESS;
1459 region->allow_while_locked = false;
1460 action = get_param_text(element, p++);
1462 /* figure out the action */
1463 if(!strcmp(pb_string, action))
1464 region->action = ACTION_TOUCH_SCROLLBAR;
1465 else if(!strcmp(vol_string, action))
1466 region->action = ACTION_TOUCH_VOLUME;
1467 else
1469 imax = ARRAYLEN(touchactions);
1470 for (i = 0; i < imax; i++)
1472 /* try to match with one of our touchregion screens */
1473 if (!strcmp(touchactions[i].s, action))
1475 region->action = touchactions[i].action;
1476 if (region->action == ACTION_SETTINGS_INC ||
1477 region->action == ACTION_SETTINGS_DEC ||
1478 region->action == ACTION_SETTINGS_SET)
1480 int val;
1481 if (element->params_count < p+1)
1482 return WPS_ERROR_INVALID_PARAM;
1483 val = touchregion_setup_setting(element, p, region);
1484 if (val < 0)
1485 return WPS_ERROR_INVALID_PARAM;
1486 p += val;
1488 break;
1491 if (region->action == ACTION_NONE)
1492 return WPS_ERROR_INVALID_PARAM;
1494 while (p < element->params_count)
1496 char* param = get_param_text(element, p++);
1497 if (!strcmp(param, "allow_while_locked"))
1498 region->allow_while_locked = true;
1499 else if (!strcmp(param, "reverse_bar"))
1500 region->reverse_bar = true;
1501 else if (!strcmp(param, "repeat_press"))
1502 region->press_length = REPEAT;
1503 else if (!strcmp(param, "long_press"))
1504 region->press_length = LONG_PRESS;
1506 struct skin_token_list *item = new_skin_token_list_item(NULL, region);
1507 if (!item)
1508 return WPS_ERROR_INVALID_PARAM;
1509 add_to_ll_chain(&wps_data->touchregions, item);
1511 if (region->action == ACTION_TOUCH_MUTE)
1513 region->value = global_settings.volume;
1517 return 0;
1519 #endif
1521 static bool check_feature_tag(const int type)
1523 switch (type)
1525 case SKIN_TOKEN_RTC_PRESENT:
1526 #if CONFIG_RTC
1527 return true;
1528 #else
1529 return false;
1530 #endif
1531 case SKIN_TOKEN_HAVE_RECORDING:
1532 #ifdef HAVE_RECORDING
1533 return true;
1534 #else
1535 return false;
1536 #endif
1537 case SKIN_TOKEN_HAVE_TUNER:
1538 #if CONFIG_TUNER
1539 if (radio_hardware_present())
1540 return true;
1541 #endif
1542 return false;
1543 case SKIN_TOKEN_HAVE_TOUCH:
1544 #ifdef HAVE_TOUCHSCREEN
1545 return true;
1546 #else
1547 return false;
1548 #endif
1550 #if CONFIG_TUNER
1551 case SKIN_TOKEN_HAVE_RDS:
1552 #ifdef HAVE_RDS_CAP
1553 return true;
1554 #else
1555 return false;
1556 #endif /* HAVE_RDS_CAP */
1557 #endif /* CONFIG_TUNER */
1558 default: /* not a tag we care about, just don't skip */
1559 return true;
1563 /* This is used to free any buflib allocations before the rest of
1564 * wps_data is reset.
1565 * The call to this in settings_apply_skins() is the last chance to do
1566 * any core_free()'s before wps_data is trashed and those handles lost
1568 void skin_data_free_buflib_allocs(struct wps_data *wps_data)
1570 if (wps_data->wps_loaded)
1571 skin_buffer = get_skin_buffer(wps_data);
1572 #ifdef HAVE_LCD_BITMAP
1573 #ifndef __PCTOOL__
1574 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1575 int *font_ids = SKINOFFSETTOPTR(skin_buffer, wps_data->font_ids);
1576 while (list)
1578 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1579 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1580 if (img->buflib_handle > 0)
1581 core_free(img->buflib_handle);
1582 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1584 wps_data->images = PTRTOSKINOFFSET(skin_buffer, NULL);
1585 if (font_ids != NULL)
1587 while (wps_data->font_count > 0)
1588 font_unload(font_ids[--wps_data->font_count]);
1590 wps_data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1591 if (wps_data->buflib_handle > 0)
1592 core_free(wps_data->buflib_handle);
1593 wps_data->buflib_handle = -1;
1594 #endif
1595 #endif
1599 * initial setup of wps_data; does reset everything
1600 * except fields which need to survive, i.e.
1601 * Also called if the load fails
1603 static void skin_data_reset(struct wps_data *wps_data)
1605 skin_data_free_buflib_allocs(wps_data);
1606 #ifdef HAVE_LCD_BITMAP
1607 wps_data->images = INVALID_OFFSET;
1608 #endif
1609 wps_data->tree = INVALID_OFFSET;
1610 #ifdef HAVE_BACKDROP_IMAGE
1611 if (wps_data->backdrop_id >= 0)
1612 skin_backdrop_unload(wps_data->backdrop_id);
1613 backdrop_filename = NULL;
1614 #endif
1615 #ifdef HAVE_TOUCHSCREEN
1616 wps_data->touchregions = INVALID_OFFSET;
1617 #endif
1618 #ifdef HAVE_SKIN_VARIABLES
1619 wps_data->skinvars = INVALID_OFFSET;
1620 #endif
1621 #ifdef HAVE_ALBUMART
1622 wps_data->albumart = INVALID_OFFSET;
1623 if (wps_data->playback_aa_slot >= 0)
1625 playback_release_aa_slot(wps_data->playback_aa_slot);
1626 wps_data->playback_aa_slot = -1;
1628 #endif
1630 #ifdef HAVE_LCD_BITMAP
1631 wps_data->peak_meter_enabled = false;
1632 wps_data->wps_sb_tag = false;
1633 wps_data->show_sb_on_wps = false;
1634 #else /* HAVE_LCD_CHARCELLS */
1635 /* progress bars */
1636 int i;
1637 for (i = 0; i < 8; i++)
1639 wps_data->wps_progress_pat[i] = 0;
1641 wps_data->full_line_progressbar = false;
1642 #endif
1643 wps_data->wps_loaded = false;
1646 #ifdef HAVE_LCD_BITMAP
1647 #ifndef __PCTOOL__
1648 static int currently_loading_handle = -1;
1649 static int buflib_move_callback(int handle, void* current, void* new)
1651 (void)current;
1652 (void)new;
1653 if (handle == currently_loading_handle)
1654 return BUFLIB_CB_CANNOT_MOVE;
1655 return BUFLIB_CB_OK;
1657 static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL};
1658 static void lock_handle(int handle)
1660 currently_loading_handle = handle;
1662 static void unlock_handle(void)
1664 currently_loading_handle = -1;
1666 #endif
1668 static int load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir)
1670 (void)wps_data; /* only needed for remote targets */
1671 char img_path[MAX_PATH];
1672 int fd;
1673 int handle;
1674 get_image_filename(bitmap->data, bmpdir,
1675 img_path, sizeof(img_path));
1677 /* load the image */
1678 int format;
1679 #ifdef HAVE_REMOTE_LCD
1680 if (curr_screen == SCREEN_REMOTE)
1681 format = FORMAT_ANY|FORMAT_REMOTE;
1682 else
1683 #endif
1684 format = FORMAT_ANY|FORMAT_TRANSPARENT;
1686 fd = open(img_path, O_RDONLY);
1687 if (fd < 0)
1689 DEBUGF("Couldn't open %s\n", img_path);
1690 return fd;
1692 #ifndef __PCTOOL__
1693 size_t buf_size = read_bmp_fd(fd, bitmap, 0,
1694 format|FORMAT_RETURN_SIZE, NULL);
1695 handle = core_alloc_ex(bitmap->data, buf_size, &buflib_ops);
1696 if (handle < 0)
1698 DEBUGF("Not enough skin buffer: need %zd more.\n",
1699 buf_size - skin_buffer_freespace());
1700 close(fd);
1701 return handle;
1703 lseek(fd, 0, SEEK_SET);
1704 lock_handle(handle);
1705 bitmap->data = core_get_data(handle);
1706 int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
1707 bitmap->data = NULL; /* do this to force a crash later if the
1708 caller doesnt call core_get_data() */
1709 unlock_handle();
1710 close(fd);
1711 if (ret > 0)
1713 /* free unused alpha channel, if any */
1714 core_shrink(handle, core_get_data(handle), ret);
1715 return handle;
1717 else
1719 /* Abort if we can't load an image */
1720 DEBUGF("Couldn't load '%s'\n", img_path);
1721 core_free(handle);
1722 return -1;
1724 #else /* !__PCTOOL__ */
1725 close(fd);
1726 return 1;
1727 #endif
1730 static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
1732 struct skin_token_list *list;
1733 bool retval = true; /* return false if a single image failed to load */
1735 /* regular images */
1736 list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1737 while (list)
1739 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1740 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1741 if (img->bm.data)
1743 if (img->using_preloaded_icons)
1745 img->loaded = true;
1746 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
1748 else
1750 img->buflib_handle = load_skin_bmp(wps_data, &img->bm, bmpdir);
1751 img->loaded = img->buflib_handle >= 0;
1752 if (img->loaded)
1753 img->subimage_height = img->bm.height / img->num_subimages;
1754 else
1755 retval = false;
1758 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1761 #ifdef HAVE_BACKDROP_IMAGE
1762 wps_data->backdrop_id = skin_backdrop_assign(backdrop_filename, bmpdir, curr_screen);
1763 #endif /* has backdrop support */
1764 return retval;
1767 static bool skin_load_fonts(struct wps_data *data)
1769 /* don't spit out after the first failue to aid debugging */
1770 int id_array[MAXUSERFONTS];
1771 int font_count = 0;
1772 bool success = true;
1773 struct skin_element *vp_list;
1774 int font_id;
1775 /* walk though each viewport and assign its font */
1776 for(vp_list = SKINOFFSETTOPTR(skin_buffer, data->tree);
1777 vp_list; vp_list = SKINOFFSETTOPTR(skin_buffer, vp_list->next))
1779 /* first, find the viewports that have a non-sys/ui-font font */
1780 struct skin_viewport *skin_vp =
1781 SKINOFFSETTOPTR(skin_buffer, vp_list->data);
1782 struct viewport *vp = &skin_vp->vp;
1784 font_id = skin_vp->parsed_fontid;
1785 if (font_id == 1)
1786 { /* the usual case -> built-in fonts */
1787 vp->font = screens[curr_screen].getuifont();
1788 continue;
1790 else if (font_id <= 0)
1792 vp->font = FONT_SYSFIXED;
1793 continue;
1796 /* now find the corresponding skin_font */
1797 struct skin_font *font = &skinfonts[font_id-2];
1798 if (!font->name)
1800 if (success)
1802 DEBUGF("font %d not specified\n", font_id);
1804 success = false;
1805 continue;
1808 /* load the font - will handle loading the same font again if
1809 * multiple viewports use the same */
1810 if (font->id < 0)
1812 char path[MAX_PATH];
1813 snprintf(path, sizeof path, FONT_DIR "/%s", font->name);
1814 #ifndef __PCTOOL__
1815 font->id = font_load_ex(path, 0, skinfonts[font_id-2].glyphs);
1817 #else
1818 font->id = font_load(path);
1819 #endif
1820 //printf("[%d] %s -> %d\n",font_id, font->name, font->id);
1821 id_array[font_count++] = font->id;
1824 if (font->id < 0)
1826 DEBUGF("Unable to load font %d: '%s.fnt'\n",
1827 font_id, font->name);
1828 font->name = NULL; /* to stop trying to load it again if we fail */
1829 success = false;
1830 continue;
1833 /* finally, assign the font_id to the viewport */
1834 vp->font = font->id;
1836 if (font_count)
1838 int *font_ids = skin_buffer_alloc(font_count * sizeof(int));
1839 if (!success || font_ids == NULL)
1841 while (font_count > 0)
1843 if(id_array[--font_count] != -1)
1844 font_unload(id_array[font_count]);
1846 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1847 return false;
1849 memcpy(font_ids, id_array, sizeof(int)*font_count);
1850 data->font_count = font_count;
1851 data->font_ids = PTRTOSKINOFFSET(skin_buffer, font_ids);
1853 else
1855 data->font_count = 0;
1856 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1858 return success;
1861 #endif /* HAVE_LCD_BITMAP */
1862 static int convert_viewport(struct wps_data *data, struct skin_element* element)
1864 struct skin_viewport *skin_vp =
1865 (struct skin_viewport *)skin_buffer_alloc(sizeof(struct skin_viewport));
1866 struct screen *display = &screens[curr_screen];
1868 if (!skin_vp)
1869 return CALLBACK_ERROR;
1871 skin_vp->hidden_flags = 0;
1872 skin_vp->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1873 skin_vp->is_infovp = false;
1874 skin_vp->parsed_fontid = 1;
1875 element->data = PTRTOSKINOFFSET(skin_buffer, skin_vp);
1876 curr_vp = skin_vp;
1877 curr_viewport_element = element;
1878 if (!first_viewport)
1879 first_viewport = element;
1881 viewport_set_defaults(&skin_vp->vp, curr_screen);
1883 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1884 skin_vp->output_to_backdrop_buffer = false;
1885 skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
1886 skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
1887 #endif
1888 #ifdef HAVE_LCD_COLOR
1889 skin_vp->start_gradient.start = skin_vp->vp.lss_pattern;
1890 skin_vp->start_gradient.end = skin_vp->vp.lse_pattern;
1891 skin_vp->start_gradient.text = skin_vp->vp.lst_pattern;
1892 #endif
1895 struct skin_tag_parameter *param = get_param(element, 0);
1896 if (element->params_count == 0) /* default viewport */
1898 if (data->tree < 0) /* first viewport in the skin */
1899 data->tree = PTRTOSKINOFFSET(skin_buffer, element);
1900 skin_vp->label = VP_DEFAULT_LABEL;
1901 return CALLBACK_OK;
1904 if (element->params_count == 6)
1906 if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
1908 skin_vp->is_infovp = true;
1909 if (isdefault(param))
1911 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1912 skin_vp->label = VP_DEFAULT_LABEL;
1914 else
1916 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1917 skin_vp->label = param->data.text;
1920 else
1922 skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN;
1923 skin_vp->label = param->data.text;
1925 param++;
1927 /* x */
1928 if (!isdefault(param))
1930 skin_vp->vp.x = param->data.number;
1931 if (param->data.number < 0)
1932 skin_vp->vp.x += display->lcdwidth;
1934 param++;
1935 /* y */
1936 if (!isdefault(param))
1938 skin_vp->vp.y = param->data.number;
1939 if (param->data.number < 0)
1940 skin_vp->vp.y += display->lcdheight;
1942 param++;
1943 /* width */
1944 if (!isdefault(param))
1946 skin_vp->vp.width = param->data.number;
1947 if (param->data.number < 0)
1948 skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
1950 else
1952 skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x;
1954 param++;
1955 /* height */
1956 if (!isdefault(param))
1958 skin_vp->vp.height = param->data.number;
1959 if (param->data.number < 0)
1960 skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
1962 else
1964 skin_vp->vp.height = display->lcdheight - skin_vp->vp.y;
1966 param++;
1967 #ifdef HAVE_LCD_BITMAP
1968 /* font */
1969 if (!isdefault(param))
1970 skin_vp->parsed_fontid = param->data.number;
1971 #endif
1972 if ((unsigned) skin_vp->vp.x >= (unsigned) display->lcdwidth ||
1973 skin_vp->vp.width + skin_vp->vp.x > display->lcdwidth ||
1974 (unsigned) skin_vp->vp.y >= (unsigned) display->lcdheight ||
1975 skin_vp->vp.height + skin_vp->vp.y > display->lcdheight)
1976 return CALLBACK_ERROR;
1978 return CALLBACK_OK;
1981 static int skin_element_callback(struct skin_element* element, void* data)
1983 struct wps_data *wps_data = (struct wps_data *)data;
1984 struct wps_token *token;
1985 parse_function function = NULL;
1987 switch (element->type)
1989 /* IMPORTANT: element params are shared, so copy them if needed
1990 * or use then NOW, dont presume they have a long lifespan
1992 case TAG:
1994 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
1995 memset(token, 0, sizeof(*token));
1996 token->type = element->tag->type;
1997 token->value.data = INVALID_OFFSET;
1999 if (element->tag->flags&SKIN_RTC_REFRESH)
2001 #if CONFIG_RTC
2002 curr_line->update_mode |= SKIN_REFRESH_DYNAMIC;
2003 #else
2004 curr_line->update_mode |= SKIN_REFRESH_STATIC;
2005 #endif
2007 else
2008 curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL;
2010 element->data = PTRTOSKINOFFSET(skin_buffer, token);
2012 /* Some tags need special handling for the tag, so add them here */
2013 switch (token->type)
2015 case SKIN_TOKEN_ALIGN_LANGDIRECTION:
2016 follow_lang_direction = 2;
2017 break;
2018 case SKIN_TOKEN_LOGICAL_IF:
2019 function = parse_logical_if;
2020 break;
2021 case SKIN_TOKEN_LOGICAL_AND:
2022 case SKIN_TOKEN_LOGICAL_OR:
2023 function = parse_logical_andor;
2024 break;
2025 case SKIN_TOKEN_SUBSTRING:
2026 function = parse_substring_tag;
2027 break;
2028 case SKIN_TOKEN_PROGRESSBAR:
2029 case SKIN_TOKEN_VOLUME:
2030 case SKIN_TOKEN_BATTERY_PERCENT:
2031 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
2032 case SKIN_TOKEN_PEAKMETER_LEFT:
2033 case SKIN_TOKEN_PEAKMETER_RIGHT:
2034 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
2035 #ifdef HAVE_RADIO_RSSI
2036 case SKIN_TOKEN_TUNER_RSSI:
2037 #endif
2038 function = parse_progressbar_tag;
2039 break;
2040 case SKIN_TOKEN_SUBLINE_TIMEOUT:
2041 case SKIN_TOKEN_BUTTON_VOLUME:
2042 case SKIN_TOKEN_TRACK_STARTING:
2043 case SKIN_TOKEN_TRACK_ENDING:
2044 function = parse_timeout_tag;
2045 break;
2046 #ifdef HAVE_LCD_BITMAP
2047 case SKIN_TOKEN_LIST_ITEM_TEXT:
2048 case SKIN_TOKEN_LIST_ITEM_ICON:
2049 function = parse_listitem;
2050 break;
2051 case SKIN_TOKEN_DISABLE_THEME:
2052 case SKIN_TOKEN_ENABLE_THEME:
2053 case SKIN_TOKEN_DRAW_INBUILTBAR:
2054 function = parse_statusbar_tags;
2055 break;
2056 case SKIN_TOKEN_LIST_TITLE_TEXT:
2057 #ifndef __PCTOOL__
2058 sb_skin_has_title(curr_screen);
2059 #endif
2060 break;
2061 case SKIN_TOKEN_DRAWRECTANGLE:
2062 function = parse_drawrectangle;
2063 break;
2064 #endif
2065 case SKIN_TOKEN_FILE_DIRECTORY:
2066 token->value.i = get_param(element, 0)->data.number;
2067 break;
2068 #ifdef HAVE_BACKDROP_IMAGE
2069 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
2070 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
2071 function = parse_viewportcolour;
2072 break;
2073 case SKIN_TOKEN_IMAGE_BACKDROP:
2074 function = parse_image_special;
2075 break;
2076 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE:
2077 function = parse_viewporttextstyle;
2078 break;
2079 case SKIN_TOKEN_VIEWPORT_DRAWONBG:
2080 curr_vp->output_to_backdrop_buffer = true;
2081 backdrop_filename = BACKDROP_BUFFERNAME;
2082 wps_data->use_extra_framebuffer = true;
2083 break;
2084 #endif
2085 #ifdef HAVE_LCD_COLOR
2086 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP:
2087 function = parse_viewport_gradient_setup;
2088 break;
2089 #endif
2090 case SKIN_TOKEN_TRANSLATEDSTRING:
2091 case SKIN_TOKEN_SETTING:
2092 function = parse_setting_and_lang;
2093 break;
2094 #ifdef HAVE_LCD_BITMAP
2095 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
2096 function = parse_playlistview;
2097 break;
2098 case SKIN_TOKEN_LOAD_FONT:
2099 function = parse_font_load;
2100 break;
2101 case SKIN_TOKEN_VIEWPORT_ENABLE:
2102 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
2103 token->value.data = get_param(element, 0)->data.text;
2104 break;
2105 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
2106 function = parse_image_display;
2107 break;
2108 case SKIN_TOKEN_IMAGE_PRELOAD:
2109 case SKIN_TOKEN_IMAGE_DISPLAY:
2110 function = parse_image_load;
2111 break;
2112 case SKIN_TOKEN_LIST_ITEM_CFG:
2113 function = parse_listitemviewport;
2114 break;
2115 #endif
2116 #ifdef HAVE_TOUCHSCREEN
2117 case SKIN_TOKEN_TOUCHREGION:
2118 function = parse_touchregion;
2119 break;
2120 case SKIN_TOKEN_LASTTOUCH:
2121 function = parse_lasttouch;
2122 break;
2123 #endif
2124 #ifdef HAVE_ALBUMART
2125 case SKIN_TOKEN_ALBUMART_DISPLAY:
2126 if (SKINOFFSETTOPTR(skin_buffer, wps_data->albumart))
2128 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2129 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
2131 break;
2132 case SKIN_TOKEN_ALBUMART_LOAD:
2133 function = parse_albumart_load;
2134 break;
2135 #endif
2136 #ifdef HAVE_SKIN_VARIABLES
2137 case SKIN_TOKEN_VAR_SET:
2138 case SKIN_TOKEN_VAR_GETVAL:
2139 case SKIN_TOKEN_VAR_TIMEOUT:
2140 function = parse_skinvar;
2141 break;
2142 #endif
2143 default:
2144 break;
2146 if (function)
2148 if (function(element, token, wps_data) < 0)
2149 return CALLBACK_ERROR;
2151 /* tags that start with 'F', 'I' or 'D' are for the next file */
2152 if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' ||
2153 *(element->tag->name) == 'D')
2154 token->next = true;
2155 if (follow_lang_direction > 0 )
2156 follow_lang_direction--;
2157 break;
2159 case VIEWPORT:
2160 return convert_viewport(wps_data, element);
2161 case LINE:
2163 struct line *line =
2164 (struct line *)skin_buffer_alloc(sizeof(struct line));
2165 line->update_mode = SKIN_REFRESH_STATIC;
2166 curr_line = line;
2167 element->data = PTRTOSKINOFFSET(skin_buffer, line);
2169 break;
2170 case LINE_ALTERNATOR:
2172 struct line_alternator *alternator =
2173 (struct line_alternator *)skin_buffer_alloc(sizeof(struct line_alternator));
2174 alternator->current_line = 0;
2175 #ifndef __PCTOOL__
2176 alternator->next_change_tick = current_tick;
2177 #endif
2178 element->data = PTRTOSKINOFFSET(skin_buffer, alternator);
2180 break;
2181 case CONDITIONAL:
2183 struct conditional *conditional =
2184 (struct conditional *)skin_buffer_alloc(sizeof(struct conditional));
2185 conditional->last_value = -1;
2186 conditional->token = element->data;
2187 element->data = PTRTOSKINOFFSET(skin_buffer, conditional);
2188 if (!check_feature_tag(element->tag->type))
2190 return FEATURE_NOT_AVAILABLE;
2192 return CALLBACK_OK;
2194 case TEXT:
2195 curr_line->update_mode |= SKIN_REFRESH_STATIC;
2196 break;
2197 default:
2198 break;
2200 return CALLBACK_OK;
2203 /* to setup up the wps-data from a format-buffer (isfile = false)
2204 from a (wps-)file (isfile = true)*/
2205 bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2206 const char *buf, bool isfile)
2208 char *wps_buffer = NULL;
2209 if (!wps_data || !buf)
2210 return false;
2211 #ifdef HAVE_ALBUMART
2212 int status;
2213 struct mp3entry *curtrack;
2214 long offset;
2215 struct skin_albumart old_aa = {.state = WPS_ALBUMART_NONE};
2216 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2217 if (aa)
2219 old_aa.state = aa->state;
2220 old_aa.height = aa->height;
2221 old_aa.width = aa->width;
2223 #endif
2224 #ifdef HAVE_LCD_BITMAP
2225 int i;
2226 for (i=0;i<MAXUSERFONTS;i++)
2228 skinfonts[i].id = -1;
2229 skinfonts[i].name = NULL;
2231 #endif
2232 #ifdef DEBUG_SKIN_ENGINE
2233 if (isfile && debug_wps)
2235 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf);
2237 #endif
2240 /* get buffer space from the plugin buffer */
2241 size_t buffersize = 0;
2242 wps_buffer = (char *)plugin_get_buffer(&buffersize);
2244 if (!wps_buffer)
2245 return false;
2247 skin_data_reset(wps_data);
2248 wps_data->wps_loaded = false;
2249 curr_screen = screen;
2250 curr_line = NULL;
2251 curr_vp = NULL;
2252 curr_viewport_element = NULL;
2253 first_viewport = NULL;
2255 if (isfile)
2257 int fd = open_utf8(buf, O_RDONLY);
2259 if (fd < 0)
2260 return false;
2261 /* copy the file's content to the buffer for parsing,
2262 ensuring that every line ends with a newline char. */
2263 unsigned int start = 0;
2264 while(read_line(fd, wps_buffer + start, buffersize - start) > 0)
2266 start += strlen(wps_buffer + start);
2267 if (start < buffersize - 1)
2269 wps_buffer[start++] = '\n';
2270 wps_buffer[start] = 0;
2273 close(fd);
2274 if (start <= 0)
2275 return false;
2276 start++;
2277 skin_buffer = &wps_buffer[start];
2278 buffersize -= start;
2280 else
2282 skin_buffer = wps_buffer;
2283 wps_buffer = (char*)buf;
2285 skin_buffer = (void *)(((unsigned long)skin_buffer + 3) & ~3);
2286 buffersize -= 3;
2287 #ifdef HAVE_BACKDROP_IMAGE
2288 backdrop_filename = "-";
2289 wps_data->backdrop_id = -1;
2290 #endif
2291 /* parse the skin source */
2292 skin_buffer_init(skin_buffer, buffersize);
2293 struct skin_element *tree = skin_parse(wps_buffer, skin_element_callback, wps_data);
2294 wps_data->tree = PTRTOSKINOFFSET(skin_buffer, tree);
2295 if (!SKINOFFSETTOPTR(skin_buffer, wps_data->tree)) {
2296 skin_data_reset(wps_data);
2297 return false;
2300 #ifdef HAVE_LCD_BITMAP
2301 char bmpdir[MAX_PATH];
2302 if (isfile)
2304 /* get the bitmap dir */
2305 char *dot = strrchr(buf, '.');
2306 strlcpy(bmpdir, buf, dot - buf + 1);
2308 else
2310 snprintf(bmpdir, MAX_PATH, "%s", BACKDROP_DIR);
2312 /* load the bitmaps that were found by the parsing */
2313 if (!load_skin_bitmaps(wps_data, bmpdir) ||
2314 !skin_load_fonts(wps_data))
2316 skin_data_reset(wps_data);
2317 return false;
2319 #endif
2320 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2321 status = audio_status();
2322 if (status & AUDIO_STATUS_PLAY)
2324 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2325 if (aa && ((aa->state && !old_aa.state) ||
2326 (aa->state &&
2327 (((old_aa.height != aa->height) ||
2328 (old_aa.width != aa->width))))))
2330 curtrack = audio_current_track();
2331 offset = curtrack->offset;
2332 audio_stop();
2333 if (!(status & AUDIO_STATUS_PAUSE))
2334 audio_play(offset);
2337 #endif
2338 #ifndef __PCTOOL__
2339 wps_data->buflib_handle = core_alloc(isfile ? buf : "failsafe skin",
2340 skin_buffer_usage());
2341 if (wps_data->buflib_handle >= 0)
2343 wps_data->wps_loaded = true;
2344 memcpy(core_get_data(wps_data->buflib_handle), skin_buffer,
2345 skin_buffer_usage());
2347 #else
2348 wps_data->wps_loaded = wps_data->tree >= 0;
2349 #endif
2350 #ifdef DEBUG_SKIN_ENGINE
2351 // if (isfile && debug_wps)
2352 // debug_skin_usage();
2353 #endif
2354 return true;