Remove WPS related variable which is read but not set or changed. Closes FS#11396.
[kugel-rb.git] / apps / gui / skin_engine / skin_parser.c
blob31dd89d0bbbdf73aab1cca03ec07a2264614ca59
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 #include "file.h"
28 #include "misc.h"
29 #include "plugin.h"
30 #include "viewport.h"
32 #include "skin_buffer.h"
33 #include "skin_parser.h"
34 #include "tag_table.h"
36 #ifdef __PCTOOL__
37 #ifdef WPSEDITOR
38 #include "proxy.h"
39 #include "sysfont.h"
40 #else
41 #include "action.h"
42 #include "checkwps.h"
43 #include "audio.h"
44 #define lang_is_rtl() (false)
45 #define DEBUGF printf
46 #endif /*WPSEDITOR*/
47 #else
48 #include "debug.h"
49 #include "language.h"
50 #endif /*__PCTOOL__*/
52 #include <ctype.h>
53 #include <stdbool.h>
54 #include "font.h"
56 #include "wps_internals.h"
57 #include "skin_engine.h"
58 #include "settings.h"
59 #include "settings_list.h"
60 #if CONFIG_TUNER
61 #include "radio.h"
62 #include "tuner.h"
63 #endif
64 #include "skin_fonts.h"
66 #ifdef HAVE_LCD_BITMAP
67 #include "bmp.h"
68 #endif
70 #ifdef HAVE_ALBUMART
71 #include "playback.h"
72 #endif
74 #include "backdrop.h"
75 #include "statusbar-skinned.h"
77 #define WPS_ERROR_INVALID_PARAM -1
80 static bool isdefault(struct skin_tag_parameter *param)
82 return param->type == DEFAULT;
86 /* which screen are we parsing for? */
87 static enum screen_type curr_screen;
89 /* the current viewport */
90 static struct skin_element *curr_viewport_element;
91 static struct skin_viewport *curr_vp;
93 static struct line *curr_line;
95 static int follow_lang_direction = 0;
97 typedef int (*parse_function)(struct skin_element *element,
98 struct wps_token *token,
99 struct wps_data *wps_data);
101 #ifdef HAVE_LCD_BITMAP
102 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
103 * chains require the order to be kept.
105 static void add_to_ll_chain(struct skin_token_list **list, struct skin_token_list *item)
107 if (*list == NULL)
108 *list = item;
109 else
111 struct skin_token_list *t = *list;
112 while (t->next)
113 t = t->next;
114 t->next = item;
118 /* traverse the image linked-list for an image */
119 struct gui_img* find_image(const char *label, struct wps_data *data)
121 struct skin_token_list *list = data->images;
122 while (list)
124 struct gui_img *img = (struct gui_img *)list->token->value.data;
125 if (!strcmp(img->label,label))
126 return img;
127 list = list->next;
129 return NULL;
132 #endif
134 /* traverse the viewport linked list for a viewport */
135 struct skin_viewport* find_viewport(const char *label, bool uivp, struct wps_data *data)
137 struct skin_element *list = data->tree;
138 while (list)
140 struct skin_viewport *vp = (struct skin_viewport *)list->data;
141 if (vp->label && (vp->is_infovp == uivp) &&
142 !strcmp(vp->label, label))
143 return vp;
144 list = list->next;
146 return NULL;
149 #ifdef HAVE_LCD_BITMAP
151 /* create and init a new wpsll item.
152 * passing NULL to token will alloc a new one.
153 * You should only pass NULL for the token when the token type (table above)
154 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
156 static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
157 void* token_data)
159 struct skin_token_list *llitem =
160 (struct skin_token_list *)skin_buffer_alloc(sizeof(struct skin_token_list));
161 if (!token)
162 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
163 if (!llitem || !token)
164 return NULL;
165 llitem->next = NULL;
166 llitem->token = token;
167 if (token_data)
168 llitem->token->value.data = token_data;
169 return llitem;
172 static int parse_statusbar_tags(struct skin_element* element,
173 struct wps_token *token,
174 struct wps_data *wps_data)
176 (void)element;
177 if (token->type == SKIN_TOKEN_DRAW_INBUILTBAR)
179 token->value.data = (void*)&curr_vp->vp;
181 else
183 struct skin_element *def_vp = wps_data->tree;
184 struct skin_viewport *default_vp = def_vp->data;
185 if (def_vp->params_count == 0)
187 wps_data->wps_sb_tag = true;
188 wps_data->show_sb_on_wps = (token->type == SKIN_TOKEN_ENABLE_THEME);
190 if (wps_data->show_sb_on_wps)
192 viewport_set_defaults(&default_vp->vp, curr_screen);
194 else
196 viewport_set_fullscreen(&default_vp->vp, curr_screen);
198 #ifdef HAVE_REMOTE_LCD
199 /* viewport_set_defaults() sets the font to FONT_UI+curr_screen.
200 * This parser requires font 1 to always be the UI font,
201 * so force it back to FONT_UI and handle the screen number at the end */
202 default_vp->vp.font = FONT_UI;
203 #endif
205 return 0;
208 static int get_image_id(int c)
210 if(c >= 'a' && c <= 'z')
211 return c - 'a';
212 else if(c >= 'A' && c <= 'Z')
213 return c - 'A' + 26;
214 else
215 return -1;
218 char *get_image_filename(const char *start, const char* bmpdir,
219 char *buf, int buf_size)
221 snprintf(buf, buf_size, "%s/%s", bmpdir, start);
223 return buf;
226 static int parse_image_display(struct skin_element *element,
227 struct wps_token *token,
228 struct wps_data *wps_data)
230 char *label = element->params[0].data.text;
231 char sublabel = '\0';
232 int subimage;
233 struct gui_img *img;
234 struct image_display *id = skin_buffer_alloc(sizeof(struct image_display));
236 if (element->params_count == 1 && strlen(label) <= 2)
238 /* backwards compatability. Allow %xd(Aa) to still work */
239 sublabel = label[1];
240 label[1] = '\0';
242 /* sanity check */
243 img = find_image(label, wps_data);
244 if (!img || !id)
246 return WPS_ERROR_INVALID_PARAM;
248 id->label = label;
249 id->offset = 0;
250 id->token = NULL;
251 if (img->using_preloaded_icons)
253 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
256 if (element->params_count > 1)
258 if (element->params[1].type == CODE)
259 id->token = element->params[1].data.code->data;
260 /* specify a number. 1 being the first subimage (i.e top) NOT 0 */
261 else if (element->params[1].type == INTEGER)
262 id->subimage = element->params[1].data.number - 1;
263 if (element->params_count > 2)
264 id->offset = element->params[2].data.number;
266 else
268 if ((subimage = get_image_id(sublabel)) != -1)
270 if (subimage >= img->num_subimages)
271 return WPS_ERROR_INVALID_PARAM;
272 id->subimage = subimage;
273 } else {
274 id->subimage = 0;
277 token->value.data = id;
278 return 0;
281 static int parse_image_load(struct skin_element *element,
282 struct wps_token *token,
283 struct wps_data *wps_data)
285 const char* filename;
286 const char* id;
287 int x,y;
288 struct gui_img *img;
290 /* format: %x(n,filename.bmp,x,y)
291 or %xl(n,filename.bmp,x,y)
292 or %xl(n,filename.bmp,x,y,num_subimages)
295 id = element->params[0].data.text;
296 filename = element->params[1].data.text;
297 x = element->params[2].data.number;
298 y = element->params[3].data.number;
300 /* check the image number and load state */
301 if(find_image(id, wps_data))
303 /* Invalid image ID */
304 return WPS_ERROR_INVALID_PARAM;
306 img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img));
307 if (!img)
308 return WPS_ERROR_INVALID_PARAM;
309 /* save a pointer to the filename */
310 img->bm.data = (char*)filename;
311 img->label = id;
312 img->x = x;
313 img->y = y;
314 img->num_subimages = 1;
315 img->always_display = false;
316 img->display = -1;
317 img->using_preloaded_icons = false;
319 /* save current viewport */
320 img->vp = &curr_vp->vp;
322 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
324 img->always_display = true;
326 else if (element->params_count == 5)
328 img->num_subimages = element->params[4].data.number;
329 if (img->num_subimages <= 0)
330 return WPS_ERROR_INVALID_PARAM;
333 if (!strcmp(img->bm.data, "__list_icons__"))
335 img->num_subimages = Icon_Last_Themeable;
336 img->using_preloaded_icons = true;
339 struct skin_token_list *item =
340 (struct skin_token_list *)new_skin_token_list_item(NULL, img);
341 if (!item)
342 return WPS_ERROR_INVALID_PARAM;
343 add_to_ll_chain(&wps_data->images, item);
345 return 0;
347 struct skin_font {
348 int id; /* the id from font_load */
349 char *name; /* filename without path and extension */
350 int glyphs; /* how many glyphs to reserve room for */
352 static struct skin_font skinfonts[MAXUSERFONTS];
353 static int parse_font_load(struct skin_element *element,
354 struct wps_token *token,
355 struct wps_data *wps_data)
357 (void)wps_data; (void)token;
358 int id = element->params[0].data.number;
359 char *filename = element->params[1].data.text;
360 int glyphs;
361 char *ptr;
363 if(element->params_count > 2)
364 glyphs = element->params[2].data.number;
365 else
366 glyphs = GLYPHS_TO_CACHE;
367 #if defined(DEBUG) || defined(SIMULATOR)
368 if (skinfonts[id-FONT_FIRSTUSERFONT].name != NULL)
370 DEBUGF("font id %d already being used\n", id);
372 #endif
373 /* make sure the filename contains .fnt,
374 * we dont actually use it, but require it anyway */
375 ptr = strchr(filename, '.');
376 if (!ptr || strncmp(ptr, ".fnt", 4))
377 return WPS_ERROR_INVALID_PARAM;
378 skinfonts[id-FONT_FIRSTUSERFONT].id = -1;
379 skinfonts[id-FONT_FIRSTUSERFONT].name = filename;
380 skinfonts[id-FONT_FIRSTUSERFONT].glyphs = glyphs;
382 return 0;
386 #ifdef HAVE_LCD_BITMAP
388 static int parse_playlistview(struct skin_element *element,
389 struct wps_token *token,
390 struct wps_data *wps_data)
392 (void)wps_data;
393 struct playlistviewer *viewer =
394 (struct playlistviewer *)skin_buffer_alloc(sizeof(struct playlistviewer));
395 if (!viewer)
396 return WPS_ERROR_INVALID_PARAM;
397 viewer->vp = &curr_vp->vp;
398 viewer->show_icons = true;
399 viewer->start_offset = element->params[0].data.number;
400 viewer->line = element->params[1].data.code;
402 token->value.data = (void*)viewer;
404 return 0;
406 #endif
408 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
410 static int parse_viewportcolour(struct skin_element *element,
411 struct wps_token *token,
412 struct wps_data *wps_data)
414 (void)wps_data;
415 struct skin_tag_parameter *param = element->params;
416 struct viewport_colour *colour =
417 (struct viewport_colour *)skin_buffer_alloc(sizeof(struct viewport_colour));
418 if (!colour)
419 return -1;
420 if (isdefault(param))
422 colour->colour = get_viewport_default_colour(curr_screen,
423 token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
425 else
427 if (!parse_color(curr_screen, param->data.text, &colour->colour))
428 return -1;
430 colour->vp = &curr_vp->vp;
431 token->value.data = colour;
432 if (element->line == curr_viewport_element->line)
434 if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
436 curr_vp->start_fgcolour = colour->colour;
437 curr_vp->vp.fg_pattern = colour->colour;
439 else
441 curr_vp->start_bgcolour = colour->colour;
442 curr_vp->vp.bg_pattern = colour->colour;
445 return 0;
448 static int parse_image_special(struct skin_element *element,
449 struct wps_token *token,
450 struct wps_data *wps_data)
452 (void)wps_data; /* kill warning */
453 (void)token;
455 #if LCD_DEPTH > 1
456 char *filename;
457 if (token->type == SKIN_TOKEN_IMAGE_BACKDROP)
459 if (isdefault(&element->params[0]))
461 filename = "-";
463 else
465 filename = element->params[0].data.text;
466 /* format: %X(filename.bmp) or %X(d) */
467 if (!strcmp(filename, "d"))
468 filename = NULL;
470 wps_data->backdrop = filename;
472 #endif
474 return 0;
476 #endif
478 #endif /* HAVE_LCD_BITMAP */
480 static int parse_setting_and_lang(struct skin_element *element,
481 struct wps_token *token,
482 struct wps_data *wps_data)
484 /* NOTE: both the string validations that happen in here will
485 * automatically PASS on checkwps because its too hard to get
486 * settings_list.c and english.lang built for it.
487 * If that ever changes remove the #ifndef __PCTOOL__'s here
489 (void)wps_data;
490 char *temp = element->params[0].data.text;
491 int i;
493 if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
495 #ifndef __PCTOOL__
496 i = lang_english_to_id(temp);
497 if (i < 0)
498 return WPS_ERROR_INVALID_PARAM;
499 #endif
501 else
503 /* Find the setting */
504 for (i=0; i<nb_settings; i++)
505 if (settings[i].cfg_name &&
506 !strcmp(settings[i].cfg_name, temp))
507 break;
508 #ifndef __PCTOOL__
509 if (i == nb_settings)
510 return WPS_ERROR_INVALID_PARAM;
511 #endif
513 /* Store the setting number */
514 token->value.i = i;
515 return 0;
517 static int parse_logical_if(struct skin_element *element,
518 struct wps_token *token,
519 struct wps_data *wps_data)
521 (void)wps_data;
522 char *op = element->params[1].data.text;
523 struct logical_if *lif = skin_buffer_alloc(sizeof(struct logical_if));
524 if (!lif)
525 return -1;
526 token->value.data = lif;
527 lif->token = element->params[0].data.code->data;
529 if (!strncmp(op, "=", 1))
530 lif->op = IF_EQUALS;
531 else if (!strncmp(op, "!=", 2))
532 lif->op = IF_NOTEQUALS;
533 else if (!strncmp(op, ">=", 2))
534 lif->op = IF_GREATERTHAN_EQ;
535 else if (!strncmp(op, "<=", 2))
536 lif->op = IF_LESSTHAN_EQ;
537 else if (!strncmp(op, ">", 2))
538 lif->op = IF_GREATERTHAN;
539 else if (!strncmp(op, "<", 1))
540 lif->op = IF_LESSTHAN;
542 memcpy(&lif->operand, &element->params[2], sizeof(lif->operand));
543 if (element->params_count > 3)
544 lif->num_options = element->params[3].data.number;
545 else
546 lif->num_options = TOKEN_VALUE_ONLY;
547 return 0;
550 static int parse_timeout_tag(struct skin_element *element,
551 struct wps_token *token,
552 struct wps_data *wps_data)
554 (void)wps_data;
555 int val = 0;
556 if (element->params_count == 0)
558 switch (token->type)
560 case SKIN_TOKEN_SUBLINE_TIMEOUT:
561 return -1;
562 case SKIN_TOKEN_BUTTON_VOLUME:
563 case SKIN_TOKEN_TRACK_STARTING:
564 case SKIN_TOKEN_TRACK_ENDING:
565 case SKIN_TOKEN_LASTTOUCH:
566 val = 10;
567 break;
568 default:
569 break;
572 else
573 val = element->params[0].data.number;
574 token->value.i = val * TIMEOUT_UNIT;
575 return 0;
578 static int parse_progressbar_tag(struct skin_element* element,
579 struct wps_token *token,
580 struct wps_data *wps_data)
582 #ifdef HAVE_LCD_BITMAP
583 struct progressbar *pb;
584 struct viewport *vp = &curr_vp->vp;
585 struct skin_tag_parameter *param = element->params;
586 int curr_param = 0;
587 char *image_filename = NULL;
589 if (element->params_count == 0 &&
590 element->tag->type != SKIN_TOKEN_PROGRESSBAR)
591 return 0; /* nothing to do */
592 pb = (struct progressbar*)skin_buffer_alloc(sizeof(struct progressbar));
594 token->value.data = pb;
596 if (!pb)
597 return WPS_ERROR_INVALID_PARAM;
598 pb->vp = vp;
599 pb->follow_lang_direction = follow_lang_direction > 0;
600 pb->nofill = false;
601 pb->nobar = false;
602 pb->image = NULL;
603 pb->slider = NULL;
604 pb->backdrop = NULL;
605 pb->invert_fill_direction = false;
606 pb->horizontal = true;
608 if (element->params_count == 0)
610 pb->x = 0;
611 pb->width = vp->width;
612 pb->height = SYSFONT_HEIGHT-2;
613 pb->y = -1; /* Will be computed during the rendering */
614 pb->type = element->tag->type;
615 return 0;
618 /* (x, y, width, height, ...) */
619 if (!isdefault(param))
620 pb->x = param->data.number;
621 else
622 pb->x = 0;
623 param++;
625 if (!isdefault(param))
626 pb->y = param->data.number;
627 else
628 pb->y = -1; /* computed at rendering */
629 param++;
631 if (!isdefault(param))
632 pb->width = param->data.number;
633 else
634 pb->width = vp->width - pb->x;
635 param++;
637 if (!isdefault(param))
639 /* A zero height makes no sense - reject it */
640 if (param->data.number == 0)
641 return WPS_ERROR_INVALID_PARAM;
643 pb->height = param->data.number;
645 else
647 if (vp->font > FONT_UI)
648 pb->height = -1; /* calculate at display time */
649 else
651 #ifndef __PCTOOL__
652 pb->height = font_get(vp->font)->height;
653 #else
654 pb->height = 8;
655 #endif
658 /* optional params, first is the image filename if it isnt recognised as a keyword */
660 curr_param = 4;
661 if (isdefault(&element->params[curr_param]))
663 param++;
664 curr_param++;
667 pb->horizontal = pb->width > pb->height;
668 while (curr_param < element->params_count)
670 param++;
671 if (!strcmp(param->data.text, "invert"))
672 pb->invert_fill_direction = true;
673 else if (!strcmp(param->data.text, "nofill"))
674 pb->nofill = true;
675 else if (!strcmp(param->data.text, "nobar"))
676 pb->nobar = true;
677 else if (!strcmp(param->data.text, "slider"))
679 if (curr_param+1 < element->params_count)
681 curr_param++;
682 param++;
683 pb->slider = find_image(param->data.text, wps_data);
685 else /* option needs the next param */
686 return -1;
688 else if (!strcmp(param->data.text, "image"))
690 if (curr_param+1 < element->params_count)
692 curr_param++;
693 param++;
694 image_filename = param->data.text;
697 else /* option needs the next param */
698 return -1;
700 else if (!strcmp(param->data.text, "backdrop"))
702 if (curr_param+1 < element->params_count)
704 curr_param++;
705 param++;
706 pb->backdrop = find_image(param->data.text, wps_data);
709 else /* option needs the next param */
710 return -1;
712 else if (!strcmp(param->data.text, "vertical"))
714 pb->horizontal = false;
715 if (isdefault(&element->params[3]))
716 pb->height = vp->height - pb->y;
718 else if (!strcmp(param->data.text, "horizontal"))
719 pb->horizontal = true;
720 else if (curr_param == 4)
721 image_filename = param->data.text;
723 curr_param++;
726 if (image_filename)
728 pb->image = find_image(image_filename, wps_data);
729 if (!pb->image) /* load later */
731 struct gui_img* img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img));
732 if (!img)
733 return WPS_ERROR_INVALID_PARAM;
734 /* save a pointer to the filename */
735 img->bm.data = (char*)image_filename;
736 img->label = image_filename;
737 img->x = 0;
738 img->y = 0;
739 img->num_subimages = 1;
740 img->always_display = false;
741 img->display = -1;
742 img->using_preloaded_icons = false;
743 img->vp = &curr_vp->vp;
744 struct skin_token_list *item =
745 (struct skin_token_list *)new_skin_token_list_item(NULL, img);
746 if (!item)
747 return WPS_ERROR_INVALID_PARAM;
748 add_to_ll_chain(&wps_data->images, item);
749 pb->image = img;
753 if (token->type == SKIN_TOKEN_VOLUME)
754 token->type = SKIN_TOKEN_VOLUMEBAR;
755 else if (token->type == SKIN_TOKEN_BATTERY_PERCENT)
756 token->type = SKIN_TOKEN_BATTERY_PERCENTBAR;
757 else if (token->type == SKIN_TOKEN_TUNER_RSSI)
758 token->type = SKIN_TOKEN_TUNER_RSSI_BAR;
759 else if (token->type == SKIN_TOKEN_PEAKMETER_LEFT)
760 token->type = SKIN_TOKEN_PEAKMETER_LEFTBAR;
761 else if (token->type == SKIN_TOKEN_PEAKMETER_RIGHT)
762 token->type = SKIN_TOKEN_PEAKMETER_RIGHTBAR;
763 pb->type = token->type;
765 return 0;
767 #else
768 (void)element;
769 if (token->type == SKIN_TOKEN_PROGRESSBAR ||
770 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR)
772 wps_data->full_line_progressbar =
773 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR;
775 return 0;
777 #endif
780 #ifdef HAVE_ALBUMART
781 static int parse_albumart_load(struct skin_element* element,
782 struct wps_token *token,
783 struct wps_data *wps_data)
785 struct dim dimensions;
786 int albumart_slot;
787 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction;
788 struct skin_albumart *aa =
789 (struct skin_albumart *)skin_buffer_alloc(sizeof(struct skin_albumart));
790 (void)token; /* silence warning */
791 if (!aa)
792 return -1;
794 /* reset albumart info in wps */
795 aa->width = -1;
796 aa->height = -1;
797 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
798 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
800 aa->x = element->params[0].data.number;
801 aa->y = element->params[1].data.number;
802 aa->width = element->params[2].data.number;
803 aa->height = element->params[3].data.number;
805 aa->vp = &curr_vp->vp;
806 aa->draw_handle = -1;
808 /* if we got here, we parsed everything ok .. ! */
809 if (aa->width < 0)
810 aa->width = 0;
811 else if (aa->width > LCD_WIDTH)
812 aa->width = LCD_WIDTH;
814 if (aa->height < 0)
815 aa->height = 0;
816 else if (aa->height > LCD_HEIGHT)
817 aa->height = LCD_HEIGHT;
819 if (swap_for_rtl)
820 aa->x = LCD_WIDTH - (aa->x + aa->width);
822 aa->state = WPS_ALBUMART_LOAD;
823 wps_data->albumart = aa;
825 dimensions.width = aa->width;
826 dimensions.height = aa->height;
828 albumart_slot = playback_claim_aa_slot(&dimensions);
830 if (0 <= albumart_slot)
831 wps_data->playback_aa_slot = albumart_slot;
833 if (element->params_count > 4 && !isdefault(&element->params[4]))
835 switch (*element->params[4].data.text)
837 case 'l':
838 case 'L':
839 if (swap_for_rtl)
840 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
841 else
842 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
843 break;
844 case 'c':
845 case 'C':
846 aa->xalign = WPS_ALBUMART_ALIGN_CENTER;
847 break;
848 case 'r':
849 case 'R':
850 if (swap_for_rtl)
851 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
852 else
853 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
854 break;
857 if (element->params_count > 5 && !isdefault(&element->params[5]))
859 switch (*element->params[5].data.text)
861 case 't':
862 case 'T':
863 aa->yalign = WPS_ALBUMART_ALIGN_TOP;
864 break;
865 case 'c':
866 case 'C':
867 aa->yalign = WPS_ALBUMART_ALIGN_CENTER;
868 break;
869 case 'b':
870 case 'B':
871 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM;
872 break;
875 return 0;
878 #endif /* HAVE_ALBUMART */
880 #ifdef HAVE_TOUCHSCREEN
882 struct touchaction {const char* s; int action;};
883 static const struct touchaction touchactions[] = {
884 /* generic actions, convert to screen actions on use */
885 {"prev", ACTION_STD_PREV }, {"next", ACTION_STD_NEXT },
886 {"rwd", ACTION_STD_PREVREPEAT }, {"ffwd", ACTION_STD_NEXTREPEAT },
887 {"hotkey", ACTION_STD_HOTKEY}, {"select", ACTION_STD_OK },
888 {"menu", ACTION_STD_MENU }, {"cancel", ACTION_STD_CANCEL },
889 {"contextmenu", ACTION_STD_CONTEXT},{"quickscreen", ACTION_STD_QUICKSCREEN },
891 /* list/tree actions */
892 { "resumeplayback", ACTION_TREE_WPS}, /* returns to previous music, WPS/FM */
893 /* not really WPS specific, but no equivilant ACTION_STD_* */
894 {"voldown", ACTION_WPS_VOLDOWN}, {"volup", ACTION_WPS_VOLUP},
895 {"mute", ACTION_TOUCH_MUTE },
897 /* generic settings changers */
898 {"setting_inc", ACTION_SETTINGS_INC}, {"setting_dec", ACTION_SETTINGS_DEC},
900 /* WPS specific actions */
901 {"browse", ACTION_WPS_BROWSE },
902 {"play", ACTION_WPS_PLAY }, {"stop", ACTION_WPS_STOP },
903 {"shuffle", ACTION_TOUCH_SHUFFLE }, {"repmode", ACTION_TOUCH_REPMODE },
904 {"pitch", ACTION_WPS_PITCHSCREEN}, {"playlist", ACTION_WPS_VIEW_PLAYLIST },
906 #if CONFIG_TUNER
907 /* FM screen actions */
908 /* Also allow browse, play, stop from WPS codes */
909 {"mode", ACTION_FM_MODE }, {"record", ACTION_FM_RECORD },
910 {"presets", ACTION_FM_PRESET},
911 #endif
914 static int parse_touchregion(struct skin_element *element,
915 struct wps_token *token,
916 struct wps_data *wps_data)
918 (void)token;
919 unsigned i, imax;
920 struct touchregion *region = NULL;
921 const char *action;
922 const char pb_string[] = "progressbar";
923 const char vol_string[] = "volume";
924 char temp[20];
926 /* format: %T(x,y,width,height,action)
927 * if action starts with & the area must be held to happen
928 * action is one of:
929 * play - play/pause playback
930 * stop - stop playback, exit the wps
931 * prev - prev track
932 * next - next track
933 * ffwd - seek forward
934 * rwd - seek backwards
935 * menu - go back to the main menu
936 * browse - go back to the file/db browser
937 * shuffle - toggle shuffle mode
938 * repmode - cycle the repeat mode
939 * quickscreen - go into the quickscreen
940 * contextmenu - open the context menu
941 * playlist - go into the playlist
942 * pitch - go into the pitchscreen
943 * volup - increase volume by one step
944 * voldown - decrease volume by one step
948 region = (struct touchregion*)skin_buffer_alloc(sizeof(struct touchregion));
949 if (!region)
950 return WPS_ERROR_INVALID_PARAM;
952 /* should probably do some bounds checking here with the viewport... but later */
953 region->action = ACTION_NONE;
954 region->x = element->params[0].data.number;
955 region->y = element->params[1].data.number;
956 region->width = element->params[2].data.number;
957 region->height = element->params[3].data.number;
958 region->wvp = curr_vp;
959 region->armed = false;
960 region->reverse_bar = false;
961 region->data = NULL;
962 action = element->params[4].data.text;
964 strcpy(temp, action);
965 action = temp;
967 if (*action == '!')
969 region->reverse_bar = true;
970 action++;
973 if(!strcmp(pb_string, action))
974 region->type = WPS_TOUCHREGION_SCROLLBAR;
975 else if(!strcmp(vol_string, action))
976 region->type = WPS_TOUCHREGION_VOLUME;
977 else
979 region->type = WPS_TOUCHREGION_ACTION;
981 if (*action == '&')
983 action++;
984 region->repeat = true;
986 else
987 region->repeat = false;
989 imax = ARRAYLEN(touchactions);
990 for (i = 0; i < imax; i++)
992 /* try to match with one of our touchregion screens */
993 if (!strcmp(touchactions[i].s, action))
995 region->action = touchactions[i].action;
996 if (region->action == ACTION_SETTINGS_INC ||
997 region->action == ACTION_SETTINGS_DEC)
999 if (element->params_count < 6)
1001 return WPS_ERROR_INVALID_PARAM;
1003 else
1005 char *name = element->params[5].data.text;
1006 int j;
1007 /* Find the setting */
1008 for (j=0; j<nb_settings; j++)
1009 if (settings[j].cfg_name &&
1010 !strcmp(settings[j].cfg_name, name))
1011 break;
1012 if (j==nb_settings)
1013 return WPS_ERROR_INVALID_PARAM;
1014 region->data = (void*)&settings[j];
1017 break;
1020 if (region->action == ACTION_NONE)
1021 return WPS_ERROR_INVALID_PARAM;
1023 struct skin_token_list *item = new_skin_token_list_item(NULL, region);
1024 if (!item)
1025 return WPS_ERROR_INVALID_PARAM;
1026 add_to_ll_chain(&wps_data->touchregions, item);
1028 if (region->action == ACTION_TOUCH_MUTE)
1030 region->value = global_settings.volume;
1034 return 0;
1036 #endif
1038 static bool check_feature_tag(const int type)
1040 switch (type)
1042 case SKIN_TOKEN_RTC_PRESENT:
1043 #if CONFIG_RTC
1044 return true;
1045 #else
1046 return false;
1047 #endif
1048 case SKIN_TOKEN_HAVE_RECORDING:
1049 #ifdef HAVE_RECORDING
1050 return true;
1051 #else
1052 return false;
1053 #endif
1054 case SKIN_TOKEN_HAVE_TUNER:
1055 #if CONFIG_TUNER
1056 if (radio_hardware_present())
1057 return true;
1058 #endif
1059 return false;
1060 case SKIN_TOKEN_HAVE_TOUCH:
1061 #ifdef HAVE_TOUCHSCREEN
1062 return true;
1063 #else
1064 return false;
1065 #endif
1067 #if CONFIG_TUNER
1068 case SKIN_TOKEN_HAVE_RDS:
1069 #ifdef HAVE_RDS_CAP
1070 return true;
1071 #else
1072 return false;
1073 #endif /* HAVE_RDS_CAP */
1074 #endif /* CONFIG_TUNER */
1075 default: /* not a tag we care about, just don't skip */
1076 return true;
1081 * initial setup of wps_data; does reset everything
1082 * except fields which need to survive, i.e.
1085 static void skin_data_reset(struct wps_data *wps_data)
1087 wps_data->tree = NULL;
1088 #ifdef HAVE_LCD_BITMAP
1089 wps_data->images = NULL;
1090 #endif
1091 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1092 if (wps_data->backdrop_id >= 0)
1093 skin_backdrop_unload(wps_data->backdrop_id);
1094 wps_data->backdrop = NULL;
1095 #endif
1096 #ifdef HAVE_TOUCHSCREEN
1097 wps_data->touchregions = NULL;
1098 #endif
1099 #ifdef HAVE_ALBUMART
1100 wps_data->albumart = NULL;
1101 if (wps_data->playback_aa_slot >= 0)
1103 playback_release_aa_slot(wps_data->playback_aa_slot);
1104 wps_data->playback_aa_slot = -1;
1106 #endif
1108 #ifdef HAVE_LCD_BITMAP
1109 wps_data->peak_meter_enabled = false;
1110 wps_data->wps_sb_tag = false;
1111 wps_data->show_sb_on_wps = false;
1112 #else /* HAVE_LCD_CHARCELLS */
1113 /* progress bars */
1114 int i;
1115 for (i = 0; i < 8; i++)
1117 wps_data->wps_progress_pat[i] = 0;
1119 wps_data->full_line_progressbar = false;
1120 #endif
1121 wps_data->wps_loaded = false;
1124 #ifdef HAVE_LCD_BITMAP
1125 static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir)
1127 (void)wps_data; /* only needed for remote targets */
1128 char img_path[MAX_PATH];
1129 int fd;
1130 get_image_filename(bitmap->data, bmpdir,
1131 img_path, sizeof(img_path));
1133 /* load the image */
1134 int format;
1135 #ifdef HAVE_REMOTE_LCD
1136 if (curr_screen == SCREEN_REMOTE)
1137 format = FORMAT_ANY|FORMAT_REMOTE;
1138 else
1139 #endif
1140 format = FORMAT_ANY|FORMAT_TRANSPARENT;
1142 fd = open(img_path, O_RDONLY);
1143 if (fd < 0)
1145 DEBUGF("Couldn't open %s\n", img_path);
1146 return false;
1148 size_t buf_size = read_bmp_fd(fd, bitmap, 0,
1149 format|FORMAT_RETURN_SIZE, NULL);
1150 char* imgbuf = (char*)skin_buffer_alloc(buf_size);
1151 if (!imgbuf)
1153 #ifndef APPLICATION
1154 DEBUGF("Not enough skin buffer: need %zd more.\n",
1155 buf_size - skin_buffer_freespace());
1156 #endif
1157 close(fd);
1158 return NULL;
1160 lseek(fd, 0, SEEK_SET);
1161 bitmap->data = imgbuf;
1162 int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
1164 close(fd);
1165 if (ret > 0)
1167 return true;
1169 else
1171 /* Abort if we can't load an image */
1172 DEBUGF("Couldn't load '%s'\n", img_path);
1173 return false;
1177 static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
1179 struct skin_token_list *list;
1180 bool retval = true; /* return false if a single image failed to load */
1182 /* regular images */
1183 list = wps_data->images;
1184 while (list)
1186 struct gui_img *img = (struct gui_img*)list->token->value.data;
1187 if (img->bm.data)
1189 if (img->using_preloaded_icons)
1191 img->loaded = true;
1192 list->token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
1194 else
1196 img->loaded = load_skin_bmp(wps_data, &img->bm, bmpdir);
1197 if (img->loaded)
1198 img->subimage_height = img->bm.height / img->num_subimages;
1199 else
1200 retval = false;
1203 list = list->next;
1206 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1207 wps_data->backdrop_id = skin_backdrop_assign(wps_data->backdrop, bmpdir, curr_screen);
1208 #endif /* has backdrop support */
1209 return retval;
1212 static bool skin_load_fonts(struct wps_data *data)
1214 /* don't spit out after the first failue to aid debugging */
1215 bool success = true;
1216 struct skin_element *vp_list;
1217 int font_id;
1218 /* walk though each viewport and assign its font */
1219 for(vp_list = data->tree; vp_list; vp_list = vp_list->next)
1221 /* first, find the viewports that have a non-sys/ui-font font */
1222 struct skin_viewport *skin_vp =
1223 (struct skin_viewport*)vp_list->data;
1224 struct viewport *vp = &skin_vp->vp;
1227 if (vp->font <= FONT_UI)
1228 { /* the usual case -> built-in fonts */
1229 #ifdef HAVE_REMOTE_LCD
1230 if (vp->font == FONT_UI)
1231 vp->font += curr_screen;
1232 #endif
1233 continue;
1235 font_id = vp->font;
1237 /* now find the corresponding skin_font */
1238 struct skin_font *font = &skinfonts[font_id-FONT_FIRSTUSERFONT];
1239 if (!font->name)
1241 if (success)
1243 DEBUGF("font %d not specified\n", font_id);
1245 success = false;
1246 continue;
1249 /* load the font - will handle loading the same font again if
1250 * multiple viewports use the same */
1251 if (font->id < 0)
1253 char *dot = strchr(font->name, '.');
1254 *dot = '\0';
1255 font->id = skin_font_load(font->name,
1256 skinfonts[font_id-FONT_FIRSTUSERFONT].glyphs);
1259 if (font->id < 0)
1261 DEBUGF("Unable to load font %d: '%s.fnt'\n",
1262 font_id, font->name);
1263 font->name = NULL; /* to stop trying to load it again if we fail */
1264 success = false;
1265 font->name = NULL;
1266 continue;
1269 /* finally, assign the font_id to the viewport */
1270 vp->font = font->id;
1272 return success;
1275 #endif /* HAVE_LCD_BITMAP */
1276 static int convert_viewport(struct wps_data *data, struct skin_element* element)
1278 struct skin_viewport *skin_vp =
1279 (struct skin_viewport *)skin_buffer_alloc(sizeof(struct skin_viewport));
1280 struct screen *display = &screens[curr_screen];
1282 if (!skin_vp)
1283 return CALLBACK_ERROR;
1285 skin_vp->hidden_flags = 0;
1286 skin_vp->label = NULL;
1287 skin_vp->is_infovp = false;
1288 element->data = skin_vp;
1289 curr_vp = skin_vp;
1290 curr_viewport_element = element;
1292 viewport_set_defaults(&skin_vp->vp, curr_screen);
1293 #ifdef HAVE_REMOTE_LCD
1294 /* viewport_set_defaults() sets the font to FONT_UI+curr_screen.
1295 * This parser requires font 1 to always be the UI font,
1296 * so force it back to FONT_UI and handle the screen number at the end */
1297 skin_vp->vp.font = FONT_UI;
1298 #endif
1300 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1301 skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
1302 skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
1303 #endif
1306 struct skin_tag_parameter *param = element->params;
1307 if (element->params_count == 0) /* default viewport */
1309 if (!data->tree) /* first viewport in the skin */
1310 data->tree = element;
1311 skin_vp->label = VP_DEFAULT_LABEL;
1312 return CALLBACK_OK;
1315 if (element->params_count == 6)
1317 if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
1319 skin_vp->is_infovp = true;
1320 if (isdefault(param))
1322 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1323 skin_vp->label = VP_DEFAULT_LABEL;
1325 else
1327 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1328 skin_vp->label = param->data.text;
1331 else
1333 skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN;
1334 skin_vp->label = param->data.text;
1336 param++;
1338 /* x */
1339 if (!isdefault(param))
1341 skin_vp->vp.x = param->data.number;
1342 if (param->data.number < 0)
1343 skin_vp->vp.x += display->lcdwidth;
1345 param++;
1346 /* y */
1347 if (!isdefault(param))
1349 skin_vp->vp.y = param->data.number;
1350 if (param->data.number < 0)
1351 skin_vp->vp.y += display->lcdheight;
1353 param++;
1354 /* width */
1355 if (!isdefault(param))
1357 skin_vp->vp.width = param->data.number;
1358 if (param->data.number < 0)
1359 skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
1361 else
1363 skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x;
1365 param++;
1366 /* height */
1367 if (!isdefault(param))
1369 skin_vp->vp.height = param->data.number;
1370 if (param->data.number < 0)
1371 skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
1373 else
1375 skin_vp->vp.height = display->lcdheight - skin_vp->vp.y;
1377 param++;
1378 #ifdef HAVE_LCD_BITMAP
1379 /* font */
1380 if (!isdefault(param))
1382 skin_vp->vp.font = param->data.number;
1384 #endif
1385 if ((unsigned) skin_vp->vp.x >= (unsigned) display->lcdwidth ||
1386 skin_vp->vp.width + skin_vp->vp.x > display->lcdwidth ||
1387 (unsigned) skin_vp->vp.y >= (unsigned) display->lcdheight ||
1388 skin_vp->vp.height + skin_vp->vp.y > display->lcdheight)
1389 return CALLBACK_ERROR;
1391 return CALLBACK_OK;
1394 static int skin_element_callback(struct skin_element* element, void* data)
1396 struct wps_data *wps_data = (struct wps_data *)data;
1397 struct wps_token *token;
1398 parse_function function = NULL;
1400 switch (element->type)
1402 /* IMPORTANT: element params are shared, so copy them if needed
1403 * or use then NOW, dont presume they have a long lifespan
1405 case TAG:
1407 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
1408 memset(token, 0, sizeof(*token));
1409 token->type = element->tag->type;
1411 if (element->tag->flags&SKIN_RTC_REFRESH)
1413 #if CONFIG_RTC
1414 curr_line->update_mode |= SKIN_REFRESH_DYNAMIC;
1415 #else
1416 curr_line->update_mode |= SKIN_REFRESH_STATIC;
1417 #endif
1419 else
1420 curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL;
1422 element->data = token;
1424 /* Some tags need special handling for the tag, so add them here */
1425 switch (token->type)
1427 case SKIN_TOKEN_ALIGN_LANGDIRECTION:
1428 follow_lang_direction = 2;
1429 break;
1430 case SKIN_TOKEN_LOGICAL_IF:
1431 function = parse_logical_if;
1432 break;
1433 case SKIN_TOKEN_PROGRESSBAR:
1434 case SKIN_TOKEN_VOLUME:
1435 case SKIN_TOKEN_BATTERY_PERCENT:
1436 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1437 case SKIN_TOKEN_PEAKMETER_LEFT:
1438 case SKIN_TOKEN_PEAKMETER_RIGHT:
1439 #ifdef HAVE_RADIO_RSSI
1440 case SKIN_TOKEN_TUNER_RSSI:
1441 #endif
1442 function = parse_progressbar_tag;
1443 break;
1444 case SKIN_TOKEN_SUBLINE_TIMEOUT:
1445 case SKIN_TOKEN_BUTTON_VOLUME:
1446 case SKIN_TOKEN_TRACK_STARTING:
1447 case SKIN_TOKEN_TRACK_ENDING:
1448 case SKIN_TOKEN_LASTTOUCH:
1449 function = parse_timeout_tag;
1450 break;
1451 #ifdef HAVE_LCD_BITMAP
1452 case SKIN_TOKEN_DISABLE_THEME:
1453 case SKIN_TOKEN_ENABLE_THEME:
1454 case SKIN_TOKEN_DRAW_INBUILTBAR:
1455 function = parse_statusbar_tags;
1456 break;
1457 case SKIN_TOKEN_LIST_TITLE_TEXT:
1458 #ifndef __PCTOOL__
1459 sb_skin_has_title(curr_screen);
1460 #endif
1461 break;
1462 #endif
1463 case SKIN_TOKEN_FILE_DIRECTORY:
1464 token->value.i = element->params[0].data.number;
1465 break;
1466 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1467 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
1468 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
1469 function = parse_viewportcolour;
1470 break;
1471 case SKIN_TOKEN_IMAGE_BACKDROP:
1472 function = parse_image_special;
1473 break;
1474 #endif
1475 case SKIN_TOKEN_TRANSLATEDSTRING:
1476 case SKIN_TOKEN_SETTING:
1477 function = parse_setting_and_lang;
1478 break;
1479 #ifdef HAVE_LCD_BITMAP
1480 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
1481 function = parse_playlistview;
1482 break;
1483 case SKIN_TOKEN_LOAD_FONT:
1484 function = parse_font_load;
1485 break;
1486 case SKIN_TOKEN_VIEWPORT_ENABLE:
1487 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
1488 token->value.data = element->params[0].data.text;
1489 break;
1490 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
1491 function = parse_image_display;
1492 break;
1493 case SKIN_TOKEN_IMAGE_PRELOAD:
1494 case SKIN_TOKEN_IMAGE_DISPLAY:
1495 function = parse_image_load;
1496 break;
1497 #endif
1498 #ifdef HAVE_TOUCHSCREEN
1499 case SKIN_TOKEN_TOUCHREGION:
1500 function = parse_touchregion;
1501 break;
1502 #endif
1503 #ifdef HAVE_ALBUMART
1504 case SKIN_TOKEN_ALBUMART_DISPLAY:
1505 if (wps_data->albumart)
1506 wps_data->albumart->vp = &curr_vp->vp;
1507 break;
1508 case SKIN_TOKEN_ALBUMART_LOAD:
1509 function = parse_albumart_load;
1510 break;
1511 #endif
1512 default:
1513 break;
1515 if (function)
1517 if (function(element, token, wps_data) < 0)
1518 return CALLBACK_ERROR;
1520 /* tags that start with 'F', 'I' or 'D' are for the next file */
1521 if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' ||
1522 *(element->tag->name) == 'D')
1523 token->next = true;
1524 if (follow_lang_direction > 0 )
1525 follow_lang_direction--;
1526 break;
1528 case VIEWPORT:
1529 return convert_viewport(wps_data, element);
1530 case LINE:
1532 struct line *line =
1533 (struct line *)skin_buffer_alloc(sizeof(struct line));
1534 line->update_mode = SKIN_REFRESH_STATIC;
1535 curr_line = line;
1536 element->data = line;
1538 break;
1539 case LINE_ALTERNATOR:
1541 struct line_alternator *alternator =
1542 (struct line_alternator *)skin_buffer_alloc(sizeof(struct line_alternator));
1543 alternator->current_line = 0;
1544 #ifndef __PCTOOL__
1545 alternator->next_change_tick = current_tick;
1546 #endif
1547 element->data = alternator;
1549 break;
1550 case CONDITIONAL:
1552 struct conditional *conditional =
1553 (struct conditional *)skin_buffer_alloc(sizeof(struct conditional));
1554 conditional->last_value = -1;
1555 conditional->token = element->data;
1556 element->data = conditional;
1557 if (!check_feature_tag(element->tag->type))
1559 return FEATURE_NOT_AVAILABLE;
1561 return CALLBACK_OK;
1563 case TEXT:
1564 curr_line->update_mode |= SKIN_REFRESH_STATIC;
1565 break;
1566 default:
1567 break;
1569 return CALLBACK_OK;
1572 /* to setup up the wps-data from a format-buffer (isfile = false)
1573 from a (wps-)file (isfile = true)*/
1574 bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
1575 const char *buf, bool isfile)
1577 char *wps_buffer = NULL;
1578 if (!wps_data || !buf)
1579 return false;
1580 #ifdef HAVE_ALBUMART
1581 int status;
1582 struct mp3entry *curtrack;
1583 long offset;
1584 struct skin_albumart old_aa = {.state = WPS_ALBUMART_NONE};
1585 if (wps_data->albumart)
1587 old_aa.state = wps_data->albumart->state;
1588 old_aa.height = wps_data->albumart->height;
1589 old_aa.width = wps_data->albumart->width;
1591 #endif
1592 #ifdef HAVE_LCD_BITMAP
1593 int i;
1594 for (i=0;i<MAXUSERFONTS;i++)
1596 skinfonts[i].id = -1;
1597 skinfonts[i].name = NULL;
1599 #endif
1600 #ifdef DEBUG_SKIN_ENGINE
1601 if (isfile && debug_wps)
1603 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf);
1605 #endif
1608 skin_data_reset(wps_data);
1609 wps_data->wps_loaded = false;
1610 curr_screen = screen;
1611 curr_line = NULL;
1612 curr_vp = NULL;
1613 curr_viewport_element = NULL;
1615 if (isfile)
1617 int fd = open_utf8(buf, O_RDONLY);
1619 if (fd < 0)
1620 return false;
1622 /* get buffer space from the plugin buffer */
1623 size_t buffersize = 0;
1624 wps_buffer = (char *)plugin_get_buffer(&buffersize);
1626 if (!wps_buffer)
1627 return false;
1629 /* copy the file's content to the buffer for parsing,
1630 ensuring that every line ends with a newline char. */
1631 unsigned int start = 0;
1632 while(read_line(fd, wps_buffer + start, buffersize - start) > 0)
1634 start += strlen(wps_buffer + start);
1635 if (start < buffersize - 1)
1637 wps_buffer[start++] = '\n';
1638 wps_buffer[start] = 0;
1641 close(fd);
1642 if (start <= 0)
1643 return false;
1645 else
1647 wps_buffer = (char*)buf;
1649 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1650 wps_data->backdrop = "-";
1651 wps_data->backdrop_id = -1;
1652 #endif
1653 /* parse the skin source */
1654 #ifndef APPLICATION
1655 skin_buffer_save_position();
1656 #endif
1657 wps_data->tree = skin_parse(wps_buffer, skin_element_callback, wps_data);
1658 if (!wps_data->tree) {
1659 skin_data_reset(wps_data);
1660 #ifndef APPLICATION
1661 skin_buffer_restore_position();
1662 #endif
1663 return false;
1666 #ifdef HAVE_LCD_BITMAP
1667 char bmpdir[MAX_PATH];
1668 if (isfile)
1670 /* get the bitmap dir */
1671 char *dot = strrchr(buf, '.');
1672 strlcpy(bmpdir, buf, dot - buf + 1);
1674 else
1676 snprintf(bmpdir, MAX_PATH, "%s", BACKDROP_DIR);
1678 /* load the bitmaps that were found by the parsing */
1679 if (!load_skin_bitmaps(wps_data, bmpdir) ||
1680 !skin_load_fonts(wps_data))
1682 skin_data_reset(wps_data);
1683 #ifndef APPLICATION
1684 skin_buffer_restore_position();
1685 #endif
1686 return false;
1688 #endif
1689 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
1690 status = audio_status();
1691 if (status & AUDIO_STATUS_PLAY)
1693 struct skin_albumart *aa = wps_data->albumart;
1694 if (aa && ((aa->state && !old_aa.state) ||
1695 (aa->state &&
1696 (((old_aa.height != aa->height) ||
1697 (old_aa.width != aa->width))))))
1699 curtrack = audio_current_track();
1700 offset = curtrack->offset;
1701 audio_stop();
1702 if (!(status & AUDIO_STATUS_PAUSE))
1703 audio_play(offset);
1706 #endif
1707 wps_data->wps_loaded = true;
1708 #ifdef DEBUG_SKIN_ENGINE
1709 // if (isfile && debug_wps)
1710 // debug_skin_usage();
1711 #endif
1712 return true;