1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
32 #include "skin_buffer.h"
33 #include "skin_parser.h"
34 #include "tag_table.h"
44 #define lang_is_rtl() (false)
56 #include "wps_internals.h"
57 #include "skin_engine.h"
59 #include "settings_list.h"
64 #include "skin_fonts.h"
66 #ifdef HAVE_LCD_BITMAP
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 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
)
111 struct skin_token_list
*t
= *list
;
118 /* traverse the image linked-list for an image */
119 struct gui_img
* find_image(char label
, struct wps_data
*data
)
121 struct skin_token_list
*list
= data
->images
;
124 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
125 if (img
->label
== label
)
134 /* traverse the viewport linked list for a viewport */
135 struct skin_viewport
* find_viewport(char label
, struct wps_data
*data
)
137 struct skin_element
*list
= data
->tree
;
140 struct skin_viewport
*vp
= (struct skin_viewport
*)list
->data
;
141 if (vp
->label
== label
)
148 #ifdef HAVE_LCD_BITMAP
150 /* create and init a new wpsll item.
151 * passing NULL to token will alloc a new one.
152 * You should only pass NULL for the token when the token type (table above)
153 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
155 static struct skin_token_list
*new_skin_token_list_item(struct wps_token
*token
,
158 struct skin_token_list
*llitem
=
159 (struct skin_token_list
*)skin_buffer_alloc(sizeof(struct skin_token_list
));
161 token
= (struct wps_token
*)skin_buffer_alloc(sizeof(struct wps_token
));
162 if (!llitem
|| !token
)
165 llitem
->token
= token
;
167 llitem
->token
->value
.data
= token_data
;
171 static int parse_statusbar_tags(struct skin_element
* element
,
172 struct wps_token
*token
,
173 struct wps_data
*wps_data
)
176 if (token
->type
== SKIN_TOKEN_DRAW_INBUILTBAR
)
178 token
->value
.data
= (void*)&curr_vp
->vp
;
182 struct skin_element
*def_vp
= wps_data
->tree
;
183 struct skin_viewport
*default_vp
= def_vp
->data
;
184 if (def_vp
->params_count
== 0)
186 wps_data
->wps_sb_tag
= true;
187 wps_data
->show_sb_on_wps
= (token
->type
== SKIN_TOKEN_ENABLE_THEME
);
189 if (wps_data
->show_sb_on_wps
)
191 viewport_set_defaults(&default_vp
->vp
, curr_screen
);
195 viewport_set_fullscreen(&default_vp
->vp
, curr_screen
);
201 static int get_image_id(int c
)
203 if(c
>= 'a' && c
<= 'z')
205 else if(c
>= 'A' && c
<= 'Z')
211 char *get_image_filename(const char *start
, const char* bmpdir
,
212 char *buf
, int buf_size
)
214 snprintf(buf
, buf_size
, "%s/%s", bmpdir
, start
);
219 static int parse_image_display(struct skin_element
*element
,
220 struct wps_token
*token
,
221 struct wps_data
*wps_data
)
223 char *text
= element
->params
[0].data
.text
;
224 char label
= text
[0];
225 char sublabel
= text
[1];
230 img
= find_image(label
, wps_data
);
233 token
->value
.i
= label
; /* so debug works */
234 return WPS_ERROR_INVALID_PARAM
;
237 if ((subimage
= get_image_id(sublabel
)) != -1)
239 if (subimage
>= img
->num_subimages
)
240 return WPS_ERROR_INVALID_PARAM
;
242 /* Store sub-image number to display in high bits */
243 token
->value
.i
= label
| (subimage
<< 8);
244 return 4; /* We have consumed 2 bytes */
246 token
->value
.i
= label
;
247 return 3; /* We have consumed 1 byte */
251 static int parse_image_load(struct skin_element
*element
,
252 struct wps_token
*token
,
253 struct wps_data
*wps_data
)
255 const char* filename
;
260 /* format: %x(n,filename.bmp,x,y)
261 or %xl(n,filename.bmp,x,y)
262 or %xl(n,filename.bmp,x,y,num_subimages)
265 id
= element
->params
[0].data
.text
;
266 filename
= element
->params
[1].data
.text
;
267 x
= element
->params
[2].data
.number
;
268 y
= element
->params
[3].data
.number
;
270 /* check the image number and load state */
271 if(find_image(*id
, wps_data
))
273 /* Invalid image ID */
274 return WPS_ERROR_INVALID_PARAM
;
276 img
= (struct gui_img
*)skin_buffer_alloc(sizeof(struct gui_img
));
278 return WPS_ERROR_INVALID_PARAM
;
279 /* save a pointer to the filename */
280 img
->bm
.data
= (char*)filename
;
284 img
->num_subimages
= 1;
285 img
->always_display
= false;
286 // img->just_drawn = false;
289 /* save current viewport */
290 img
->vp
= &curr_vp
->vp
;
292 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY
)
294 img
->always_display
= true;
296 else if (element
->params_count
== 5)
298 img
->num_subimages
= element
->params
[4].data
.number
;
299 if (img
->num_subimages
<= 0)
300 return WPS_ERROR_INVALID_PARAM
;
302 struct skin_token_list
*item
=
303 (struct skin_token_list
*)new_skin_token_list_item(NULL
, img
);
305 return WPS_ERROR_INVALID_PARAM
;
306 add_to_ll_chain(&wps_data
->images
, item
);
311 int id
; /* the id from font_load */
312 char *name
; /* filename without path and extension */
314 static struct skin_font skinfonts
[MAXUSERFONTS
];
315 static int parse_font_load(struct skin_element
*element
,
316 struct wps_token
*token
,
317 struct wps_data
*wps_data
)
319 (void)wps_data
; (void)token
;
320 int id
= element
->params
[0].data
.number
;
321 char *filename
= element
->params
[1].data
.text
;
324 #if defined(DEBUG) || defined(SIMULATOR)
325 if (skinfonts
[id
-FONT_FIRSTUSERFONT
].name
!= NULL
)
327 DEBUGF("font id %d already being used\n", id
);
330 /* make sure the filename contains .fnt,
331 * we dont actually use it, but require it anyway */
332 ptr
= strchr(filename
, '.');
333 if (!ptr
|| strncmp(ptr
, ".fnt", 4))
334 return WPS_ERROR_INVALID_PARAM
;
335 skinfonts
[id
-FONT_FIRSTUSERFONT
].id
= -1;
336 skinfonts
[id
-FONT_FIRSTUSERFONT
].name
= filename
;
342 #ifdef HAVE_LCD_BITMAP
344 static int parse_playlistview(struct skin_element
*element
,
345 struct wps_token
*token
,
346 struct wps_data
*wps_data
)
349 struct playlistviewer
*viewer
=
350 (struct playlistviewer
*)skin_buffer_alloc(sizeof(struct playlistviewer
));
352 return WPS_ERROR_INVALID_PARAM
;
353 viewer
->vp
= &curr_vp
->vp
;
354 viewer
->show_icons
= true;
355 viewer
->start_offset
= element
->params
[0].data
.number
;
356 viewer
->lines
[0] = element
->params
[1].data
.code
;
357 viewer
->lines
[1] = element
->params
[2].data
.code
;
359 token
->value
.data
= (void*)viewer
;
365 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
367 static int parse_viewportcolour(struct skin_element
*element
,
368 struct wps_token
*token
,
369 struct wps_data
*wps_data
)
372 struct skin_tag_parameter
*param
= element
->params
;
373 struct viewport_colour
*colour
=
374 (struct viewport_colour
*)skin_buffer_alloc(sizeof(struct viewport_colour
));
377 if (isdefault(param
))
379 colour
->colour
= get_viewport_default_colour(curr_screen
,
380 token
->type
== SKIN_TOKEN_VIEWPORT_FGCOLOUR
);
384 if (!parse_color(param
->data
.text
, &colour
->colour
))
387 colour
->vp
= &curr_vp
->vp
;
388 token
->value
.data
= colour
;
389 if (element
->line
== curr_viewport_element
->line
)
391 if (token
->type
== SKIN_TOKEN_VIEWPORT_FGCOLOUR
)
393 curr_vp
->start_fgcolour
= colour
->colour
;
394 curr_vp
->vp
.fg_pattern
= colour
->colour
;
398 curr_vp
->start_bgcolour
= colour
->colour
;
399 curr_vp
->vp
.bg_pattern
= colour
->colour
;
405 static int parse_image_special(struct skin_element
*element
,
406 struct wps_token
*token
,
407 struct wps_data
*wps_data
)
409 (void)wps_data
; /* kill warning */
414 if (token
->type
== SKIN_TOKEN_IMAGE_BACKDROP
)
416 char *filename
= element
->params
[0].data
.text
;
417 /* format: %X|filename.bmp| or %Xd */
418 if (!strcmp(filename
, "d"))
420 wps_data
->backdrop
= NULL
;
425 wps_data
->backdrop
= filename
;
429 /* Skip the rest of the line */
430 return error
? WPS_ERROR_INVALID_PARAM
: 0;
434 #endif /* HAVE_LCD_BITMAP */
436 static int parse_setting_and_lang(struct skin_element
*element
,
437 struct wps_token
*token
,
438 struct wps_data
*wps_data
)
440 /* NOTE: both the string validations that happen in here will
441 * automatically PASS on checkwps because its too hard to get
442 * settings_list.c and english.lang built for it.
443 * If that ever changes remove the #ifndef __PCTOOL__'s here
446 char *temp
= element
->params
[0].data
.text
;
449 if (token
->type
== SKIN_TOKEN_TRANSLATEDSTRING
)
452 i
= lang_english_to_id(temp
);
454 return WPS_ERROR_INVALID_PARAM
;
459 /* Find the setting */
460 for (i
=0; i
<nb_settings
; i
++)
461 if (settings
[i
].cfg_name
&&
462 !strcmp(settings
[i
].cfg_name
, temp
))
465 if (i
== nb_settings
)
466 return WPS_ERROR_INVALID_PARAM
;
469 /* Store the setting number */
474 static int parse_timeout_tag(struct skin_element
*element
,
475 struct wps_token
*token
,
476 struct wps_data
*wps_data
)
480 if (element
->params_count
== 0)
484 case SKIN_TOKEN_SUBLINE_TIMEOUT
:
486 case SKIN_TOKEN_BUTTON_VOLUME
:
487 case SKIN_TOKEN_TRACK_STARTING
:
488 case SKIN_TOKEN_TRACK_ENDING
:
489 case SKIN_TOKEN_LASTTOUCH
:
497 val
= element
->params
[0].data
.number
;
498 token
->value
.i
= val
;
499 if (token
->type
== SKIN_TOKEN_SUBLINE_TIMEOUT
)
500 curr_line
->timeout
= val
* TIMEOUT_UNIT
;
504 static int parse_progressbar_tag(struct skin_element
* element
,
505 struct wps_token
*token
,
506 struct wps_data
*wps_data
)
508 #ifdef HAVE_LCD_BITMAP
509 struct progressbar
*pb
;
510 struct skin_token_list
*item
;
511 struct viewport
*vp
= &curr_vp
->vp
;
512 struct skin_tag_parameter
*param
= element
->params
;
514 if (element
->params_count
== 0 &&
515 element
->tag
->type
!= SKIN_TOKEN_PROGRESSBAR
)
516 return 0; /* nothing to do */
517 pb
= (struct progressbar
*)skin_buffer_alloc(sizeof(struct progressbar
));
519 token
->value
.data
= pb
;
522 return WPS_ERROR_INVALID_PARAM
;
524 pb
->have_bitmap_pb
= false;
525 pb
->bm
.data
= NULL
; /* no bitmap specified */
526 pb
->follow_lang_direction
= follow_lang_direction
> 0;
528 if (element
->params_count
== 0)
531 pb
->width
= vp
->width
;
532 pb
->height
= SYSFONT_HEIGHT
-2;
533 pb
->y
= -1; /* Will be computed during the rendering */
534 pb
->type
= element
->tag
->type
;
538 item
= new_skin_token_list_item(token
, pb
);
541 add_to_ll_chain(&wps_data
->progressbars
, item
);
543 /* (x,y,width,height,filename) */
544 if (!isdefault(param
))
545 pb
->x
= param
->data
.number
;
550 if (!isdefault(param
))
551 pb
->y
= param
->data
.number
;
553 pb
->y
= -1; /* computed at rendering */
556 if (!isdefault(param
))
557 pb
->width
= param
->data
.number
;
559 pb
->width
= vp
->width
- pb
->x
;
562 if (!isdefault(param
))
564 /* A zero height makes no sense - reject it */
565 if (param
->data
.number
== 0)
566 return WPS_ERROR_INVALID_PARAM
;
568 pb
->height
= param
->data
.number
;
572 if (vp
->font
> FONT_UI
)
573 pb
->height
= -1; /* calculate at display time */
577 pb
->height
= font_get(vp
->font
)->height
;
584 if (!isdefault(param
))
585 pb
->bm
.data
= param
->data
.text
;
588 if (token
->type
== SKIN_TOKEN_VOLUME
)
589 token
->type
= SKIN_TOKEN_VOLUMEBAR
;
590 else if (token
->type
== SKIN_TOKEN_BATTERY_PERCENT
)
591 token
->type
= SKIN_TOKEN_BATTERY_PERCENTBAR
;
592 pb
->type
= token
->type
;
598 if (token
->type
== SKIN_TOKEN_PROGRESSBAR
||
599 token
->type
== SKIN_TOKEN_PLAYER_PROGRESSBAR
)
601 wps_data
->full_line_progressbar
=
602 token
->type
== SKIN_TOKEN_PLAYER_PROGRESSBAR
;
610 static int parse_albumart_load(struct skin_element
* element
,
611 struct wps_token
*token
,
612 struct wps_data
*wps_data
)
614 struct dim dimensions
;
616 bool swap_for_rtl
= lang_is_rtl() && follow_lang_direction
;
617 struct skin_albumart
*aa
=
618 (struct skin_albumart
*)skin_buffer_alloc(sizeof(struct skin_albumart
));
619 (void)token
; /* silence warning */
623 /* reset albumart info in wps */
626 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
627 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
629 aa
->x
= element
->params
[0].data
.number
;
630 aa
->y
= element
->params
[1].data
.number
;
631 aa
->width
= element
->params
[2].data
.number
;
632 aa
->height
= element
->params
[3].data
.number
;
634 aa
->vp
= &curr_vp
->vp
;
635 aa
->draw_handle
= -1;
637 /* if we got here, we parsed everything ok .. ! */
640 else if (aa
->width
> LCD_WIDTH
)
641 aa
->width
= LCD_WIDTH
;
645 else if (aa
->height
> LCD_HEIGHT
)
646 aa
->height
= LCD_HEIGHT
;
649 aa
->x
= LCD_WIDTH
- (aa
->x
+ aa
->width
);
651 aa
->state
= WPS_ALBUMART_LOAD
;
652 wps_data
->albumart
= aa
;
654 dimensions
.width
= aa
->width
;
655 dimensions
.height
= aa
->height
;
657 albumart_slot
= playback_claim_aa_slot(&dimensions
);
659 if (0 <= albumart_slot
)
660 wps_data
->playback_aa_slot
= albumart_slot
;
662 if (element
->params_count
> 4 && !isdefault(&element
->params
[4]))
664 switch (*element
->params
[4].data
.text
)
669 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
671 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
675 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
;
680 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
682 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
686 if (element
->params_count
> 5 && !isdefault(&element
->params
[5]))
688 switch (*element
->params
[5].data
.text
)
692 aa
->yalign
= WPS_ALBUMART_ALIGN_TOP
;
696 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
;
700 aa
->yalign
= WPS_ALBUMART_ALIGN_BOTTOM
;
707 #endif /* HAVE_ALBUMART */
709 #ifdef HAVE_TOUCHSCREEN
711 struct touchaction
{const char* s
; int action
;};
712 static const struct touchaction touchactions
[] = {
713 /* generic actions, convert to screen actions on use */
714 {"prev", ACTION_STD_PREV
}, {"next", ACTION_STD_NEXT
},
715 {"rwd", ACTION_STD_PREVREPEAT
}, {"ffwd", ACTION_STD_NEXTREPEAT
},
716 {"hotkey", ACTION_STD_HOTKEY
}, {"select", ACTION_STD_OK
},
717 {"menu", ACTION_STD_MENU
}, {"cancel", ACTION_STD_CANCEL
},
718 {"contextmenu", ACTION_STD_CONTEXT
},{"quickscreen", ACTION_STD_QUICKSCREEN
},
719 /* not really WPS specific, but no equivilant ACTION_STD_* */
720 {"voldown", ACTION_WPS_VOLDOWN
}, {"volup", ACTION_WPS_VOLUP
},
722 /* WPS specific actions */
723 {"browse", ACTION_WPS_BROWSE
},
724 {"play", ACTION_WPS_PLAY
}, {"stop", ACTION_WPS_STOP
},
725 {"shuffle", ACTION_TOUCH_SHUFFLE
}, {"repmode", ACTION_TOUCH_REPMODE
},
726 {"pitch", ACTION_WPS_PITCHSCREEN
}, {"playlist", ACTION_WPS_VIEW_PLAYLIST
},
729 /* FM screen actions */
730 /* Also allow browse, play, stop from WPS codes */
731 {"mode", ACTION_FM_MODE
}, {"record", ACTION_FM_RECORD
},
732 {"presets", ACTION_FM_PRESET
},
736 static int parse_touchregion(struct skin_element
*element
,
737 struct wps_token
*token
,
738 struct wps_data
*wps_data
)
742 struct touchregion
*region
= NULL
;
744 const char pb_string
[] = "progressbar";
745 const char vol_string
[] = "volume";
748 /* format: %T(x,y,width,height,action)
749 * if action starts with & the area must be held to happen
751 * play - play/pause playback
752 * stop - stop playback, exit the wps
755 * ffwd - seek forward
756 * rwd - seek backwards
757 * menu - go back to the main menu
758 * browse - go back to the file/db browser
759 * shuffle - toggle shuffle mode
760 * repmode - cycle the repeat mode
761 * quickscreen - go into the quickscreen
762 * contextmenu - open the context menu
763 * playlist - go into the playlist
764 * pitch - go into the pitchscreen
765 * volup - increase volume by one step
766 * voldown - decrease volume by one step
770 region
= (struct touchregion
*)skin_buffer_alloc(sizeof(struct touchregion
));
772 return WPS_ERROR_INVALID_PARAM
;
774 /* should probably do some bounds checking here with the viewport... but later */
775 region
->action
= ACTION_NONE
;
776 region
->x
= element
->params
[0].data
.number
;
777 region
->y
= element
->params
[1].data
.number
;
778 region
->width
= element
->params
[2].data
.number
;
779 region
->height
= element
->params
[3].data
.number
;
780 region
->wvp
= curr_vp
;
781 region
->armed
= false;
782 region
->reverse_bar
= false;
783 action
= element
->params
[4].data
.text
;
785 strcpy(temp
, action
);
790 region
->reverse_bar
= true;
794 if(!strcmp(pb_string
, action
))
795 region
->type
= WPS_TOUCHREGION_SCROLLBAR
;
796 else if(!strcmp(vol_string
, action
))
797 region
->type
= WPS_TOUCHREGION_VOLUME
;
800 region
->type
= WPS_TOUCHREGION_ACTION
;
805 region
->repeat
= true;
808 region
->repeat
= false;
810 imax
= ARRAYLEN(touchactions
);
811 for (i
= 0; i
< imax
; i
++)
813 /* try to match with one of our touchregion screens */
814 if (!strcmp(touchactions
[i
].s
, action
))
816 region
->action
= touchactions
[i
].action
;
820 if (region
->action
== ACTION_NONE
)
821 return WPS_ERROR_INVALID_PARAM
;
823 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, region
);
825 return WPS_ERROR_INVALID_PARAM
;
826 add_to_ll_chain(&wps_data
->touchregions
, item
);
831 static bool check_feature_tag(const int type
)
835 case SKIN_TOKEN_RTC_PRESENT
:
841 case SKIN_TOKEN_HAVE_RECORDING
:
842 #ifdef HAVE_RECORDING
847 case SKIN_TOKEN_HAVE_TUNER
:
849 if (radio_hardware_present())
855 case SKIN_TOKEN_HAVE_RDS
:
860 #endif /* HAVE_RDS_CAP */
861 #endif /* CONFIG_TUNER */
862 default: /* not a tag we care about, just don't skip */
868 * initial setup of wps_data; does reset everything
869 * except fields which need to survive, i.e.
872 static void skin_data_reset(struct wps_data
*wps_data
)
874 wps_data
->tree
= NULL
;
875 #ifdef HAVE_LCD_BITMAP
876 wps_data
->images
= NULL
;
877 wps_data
->progressbars
= NULL
;
879 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
880 wps_data
->backdrop
= NULL
;
882 #ifdef HAVE_TOUCHSCREEN
883 wps_data
->touchregions
= NULL
;
886 wps_data
->albumart
= NULL
;
887 if (wps_data
->playback_aa_slot
>= 0)
889 playback_release_aa_slot(wps_data
->playback_aa_slot
);
890 wps_data
->playback_aa_slot
= -1;
894 #ifdef HAVE_LCD_BITMAP
895 wps_data
->peak_meter_enabled
= false;
896 wps_data
->wps_sb_tag
= false;
897 wps_data
->show_sb_on_wps
= false;
898 #else /* HAVE_LCD_CHARCELLS */
901 for (i
= 0; i
< 8; i
++)
903 wps_data
->wps_progress_pat
[i
] = 0;
905 wps_data
->full_line_progressbar
= false;
907 wps_data
->wps_loaded
= false;
910 #ifdef HAVE_LCD_BITMAP
911 static bool load_skin_bmp(struct wps_data
*wps_data
, struct bitmap
*bitmap
, char* bmpdir
)
913 (void)wps_data
; /* only needed for remote targets */
914 char img_path
[MAX_PATH
];
916 get_image_filename(bitmap
->data
, bmpdir
,
917 img_path
, sizeof(img_path
));
921 #ifdef HAVE_REMOTE_LCD
922 if (curr_screen
== SCREEN_REMOTE
)
923 format
= FORMAT_ANY
|FORMAT_REMOTE
;
926 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
928 fd
= open(img_path
, O_RDONLY
);
931 size_t buf_size
= read_bmp_file(img_path
, bitmap
, 0,
932 format
|FORMAT_RETURN_SIZE
, NULL
);
933 char* imgbuf
= (char*)skin_buffer_alloc(buf_size
);
939 lseek(fd
, 0, SEEK_SET
);
940 bitmap
->data
= imgbuf
;
941 int ret
= read_bmp_fd(fd
, bitmap
, buf_size
, format
, NULL
);
950 /* Abort if we can't load an image */
951 DEBUGF("Couldn't load '%s'\n", img_path
);
956 static bool load_skin_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
958 struct skin_token_list
*list
;
959 bool retval
= true; /* return false if a single image failed to load */
960 /* do the progressbars */
961 list
= wps_data
->progressbars
;
964 struct progressbar
*pb
= (struct progressbar
*)list
->token
->value
.data
;
967 pb
->have_bitmap_pb
= load_skin_bmp(wps_data
, &pb
->bm
, bmpdir
);
968 if (!pb
->have_bitmap_pb
) /* no success */
974 list
= wps_data
->images
;
977 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
980 img
->loaded
= load_skin_bmp(wps_data
, &img
->bm
, bmpdir
);
982 img
->subimage_height
= img
->bm
.height
/ img
->num_subimages
;
989 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
990 /* Backdrop load scheme:
992 * 2) load the backdrop from settings
994 if (wps_data
->backdrop
)
996 bool needed
= wps_data
->backdrop
[0] != '-';
997 wps_data
->backdrop
= skin_backdrop_load(wps_data
->backdrop
,
998 bmpdir
, curr_screen
);
999 if (!wps_data
->backdrop
&& needed
)
1002 #endif /* has backdrop support */
1007 static bool skin_load_fonts(struct wps_data
*data
)
1009 /* don't spit out after the first failue to aid debugging */
1010 bool success
= true;
1011 struct skin_element
*vp_list
;
1013 /* walk though each viewport and assign its font */
1014 for(vp_list
= data
->tree
; vp_list
; vp_list
= vp_list
->next
)
1016 /* first, find the viewports that have a non-sys/ui-font font */
1017 struct skin_viewport
*skin_vp
=
1018 (struct skin_viewport
*)vp_list
->data
;
1019 struct viewport
*vp
= &skin_vp
->vp
;
1022 if (vp
->font
<= FONT_UI
)
1023 { /* the usual case -> built-in fonts */
1024 #ifdef HAVE_REMOTE_LCD
1025 if (vp
->font
== FONT_UI
)
1026 vp
->font
+= curr_screen
;
1032 /* now find the corresponding skin_font */
1033 struct skin_font
*font
= &skinfonts
[font_id
-FONT_FIRSTUSERFONT
];
1038 DEBUGF("font %d not specified\n", font_id
);
1044 /* load the font - will handle loading the same font again if
1045 * multiple viewports use the same */
1048 char *dot
= strchr(font
->name
, '.');
1050 font
->id
= skin_font_load(font
->name
);
1055 DEBUGF("Unable to load font %d: '%s.fnt'\n",
1056 font_id
, font
->name
);
1057 font
->name
= NULL
; /* to stop trying to load it again if we fail */
1063 /* finally, assign the font_id to the viewport */
1064 vp
->font
= font
->id
;
1069 #endif /* HAVE_LCD_BITMAP */
1070 static int convert_viewport(struct wps_data
*data
, struct skin_element
* element
)
1072 struct skin_viewport
*skin_vp
=
1073 (struct skin_viewport
*)skin_buffer_alloc(sizeof(struct skin_viewport
));
1074 struct screen
*display
= &screens
[curr_screen
];
1077 return CALLBACK_ERROR
;
1079 skin_vp
->hidden_flags
= 0;
1080 skin_vp
->label
= VP_NO_LABEL
;
1081 element
->data
= skin_vp
;
1083 curr_viewport_element
= element
;
1085 viewport_set_defaults(&skin_vp
->vp
, curr_screen
);
1087 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1088 skin_vp
->start_fgcolour
= skin_vp
->vp
.fg_pattern
;
1089 skin_vp
->start_bgcolour
= skin_vp
->vp
.bg_pattern
;
1093 struct skin_tag_parameter
*param
= element
->params
;
1094 if (element
->params_count
== 0) /* default viewport */
1096 if (!data
->tree
) /* first viewport in the skin */
1097 data
->tree
= element
;
1098 skin_vp
->label
= VP_DEFAULT_LABEL
;
1102 if (element
->params_count
== 6)
1104 if (element
->tag
->type
== SKIN_TOKEN_UIVIEWPORT_LOAD
)
1106 if (isdefault(param
))
1108 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
1109 skin_vp
->label
= VP_INFO_LABEL
|VP_DEFAULT_LABEL
;
1113 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
1114 skin_vp
->label
= VP_INFO_LABEL
|param
->data
.text
[0];
1119 skin_vp
->hidden_flags
= VP_DRAW_HIDEABLE
|VP_DRAW_HIDDEN
;
1120 skin_vp
->label
= param
->data
.text
[0];
1125 if (!isdefault(param
))
1127 skin_vp
->vp
.x
= param
->data
.number
;
1128 if (param
->data
.number
< 0)
1129 skin_vp
->vp
.x
+= display
->lcdwidth
;
1133 if (!isdefault(param
))
1135 skin_vp
->vp
.y
= param
->data
.number
;
1136 if (param
->data
.number
< 0)
1137 skin_vp
->vp
.y
+= display
->lcdheight
;
1141 if (!isdefault(param
))
1143 skin_vp
->vp
.width
= param
->data
.number
;
1144 if (param
->data
.number
< 0)
1145 skin_vp
->vp
.width
= (skin_vp
->vp
.width
+ display
->lcdwidth
) - skin_vp
->vp
.x
;
1149 skin_vp
->vp
.width
= display
->lcdwidth
- skin_vp
->vp
.x
;
1153 if (!isdefault(param
))
1155 skin_vp
->vp
.height
= param
->data
.number
;
1156 if (param
->data
.number
< 0)
1157 skin_vp
->vp
.height
= (skin_vp
->vp
.height
+ display
->lcdheight
) - skin_vp
->vp
.y
;
1161 skin_vp
->vp
.height
= display
->lcdheight
- skin_vp
->vp
.y
;
1164 #ifdef HAVE_LCD_BITMAP
1166 if (!isdefault(param
))
1168 skin_vp
->vp
.font
= param
->data
.number
;
1176 int skin_element_callback(struct skin_element
* element
, void* data
)
1178 struct wps_data
*wps_data
= (struct wps_data
*)data
;
1179 struct wps_token
*token
;
1180 parse_function function
= NULL
;
1182 switch (element
->type
)
1184 /* IMPORTANT: element params are shared, so copy them if needed
1185 * or use then NOW, dont presume they have a long lifespan
1189 token
= (struct wps_token
*)skin_buffer_alloc(sizeof(struct wps_token
));
1190 memset(token
, 0, sizeof(*token
));
1191 token
->type
= element
->tag
->type
;
1193 if ((element
->tag
->flags
&SKIN_REFRESH_ALL
) == SKIN_RTC_REFRESH
)
1196 curr_line
->update_mode
|= SKIN_REFRESH_DYNAMIC
;
1198 curr_line
->update_mode
|= SKIN_REFRESH_STATIC
;
1202 curr_line
->update_mode
|= element
->tag
->flags
&SKIN_REFRESH_ALL
;
1204 element
->data
= token
;
1206 /* Some tags need special handling for the tag, so add them here */
1207 switch (token
->type
)
1209 case SKIN_TOKEN_ALIGN_LANGDIRECTION
:
1210 follow_lang_direction
= 2;
1212 case SKIN_TOKEN_PROGRESSBAR
:
1213 case SKIN_TOKEN_VOLUME
:
1214 case SKIN_TOKEN_BATTERY_PERCENT
:
1215 case SKIN_TOKEN_PLAYER_PROGRESSBAR
:
1216 function
= parse_progressbar_tag
;
1218 case SKIN_TOKEN_SUBLINE_TIMEOUT
:
1219 case SKIN_TOKEN_BUTTON_VOLUME
:
1220 case SKIN_TOKEN_TRACK_STARTING
:
1221 case SKIN_TOKEN_TRACK_ENDING
:
1222 case SKIN_TOKEN_LASTTOUCH
:
1223 function
= parse_timeout_tag
;
1225 #ifdef HAVE_LCD_BITMAP
1226 case SKIN_TOKEN_DISABLE_THEME
:
1227 case SKIN_TOKEN_ENABLE_THEME
:
1228 case SKIN_TOKEN_DRAW_INBUILTBAR
:
1229 function
= parse_statusbar_tags
;
1232 case SKIN_TOKEN_FILE_DIRECTORY
:
1233 token
->value
.i
= element
->params
[0].data
.number
;
1235 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1236 case SKIN_TOKEN_VIEWPORT_FGCOLOUR
:
1237 case SKIN_TOKEN_VIEWPORT_BGCOLOUR
:
1238 function
= parse_viewportcolour
;
1240 case SKIN_TOKEN_IMAGE_BACKDROP
:
1241 function
= parse_image_special
;
1244 case SKIN_TOKEN_TRANSLATEDSTRING
:
1245 case SKIN_TOKEN_SETTING
:
1246 function
= parse_setting_and_lang
;
1248 #ifdef HAVE_LCD_BITMAP
1249 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
1250 function
= parse_playlistview
;
1252 case SKIN_TOKEN_LOAD_FONT
:
1253 function
= parse_font_load
;
1255 case SKIN_TOKEN_VIEWPORT_ENABLE
:
1256 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
1257 token
->value
.i
= element
->params
[0].data
.text
[0];
1259 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
1260 function
= parse_image_display
;
1262 case SKIN_TOKEN_IMAGE_PRELOAD
:
1263 case SKIN_TOKEN_IMAGE_DISPLAY
:
1264 function
= parse_image_load
;
1267 #ifdef HAVE_TOUCHSCREEN
1268 case SKIN_TOKEN_TOUCHREGION
:
1269 function
= parse_touchregion
;
1272 #ifdef HAVE_ALBUMART
1273 case SKIN_TOKEN_ALBUMART_DISPLAY
:
1274 if (wps_data
->albumart
)
1275 wps_data
->albumart
->vp
= &curr_vp
->vp
;
1277 case SKIN_TOKEN_ALBUMART_LOAD
:
1278 function
= parse_albumart_load
;
1286 if (function(element
, token
, wps_data
) < 0)
1287 return CALLBACK_ERROR
;
1289 /* tags that start with 'F', 'I' or 'D' are for the next file */
1290 if ( *(element
->tag
->name
) == 'I' || *(element
->tag
->name
) == 'F' ||
1291 *(element
->tag
->name
) == 'D')
1293 if (follow_lang_direction
> 0 )
1294 follow_lang_direction
--;
1298 return convert_viewport(wps_data
, element
);
1302 (struct line
*)skin_buffer_alloc(sizeof(struct line
));
1303 line
->update_mode
= SKIN_REFRESH_STATIC
;
1304 line
->timeout
= DEFAULT_SUBLINE_TIME_MULTIPLIER
* TIMEOUT_UNIT
;
1306 element
->data
= line
;
1309 case LINE_ALTERNATOR
:
1311 struct line_alternator
*alternator
=
1312 (struct line_alternator
*)skin_buffer_alloc(sizeof(struct line_alternator
));
1313 alternator
->current_line
= 0;
1315 alternator
->last_change_tick
= current_tick
;
1317 element
->data
= alternator
;
1322 struct conditional
*conditional
=
1323 (struct conditional
*)skin_buffer_alloc(sizeof(struct conditional
));
1324 conditional
->last_value
= -1;
1325 conditional
->token
= element
->data
;
1326 element
->data
= conditional
;
1327 if (!check_feature_tag(element
->tag
->type
))
1329 return FEATURE_NOT_AVAILABLE
;
1334 curr_line
->update_mode
|= SKIN_REFRESH_STATIC
;
1342 /* to setup up the wps-data from a format-buffer (isfile = false)
1343 from a (wps-)file (isfile = true)*/
1344 bool skin_data_load(enum screen_type screen
, struct wps_data
*wps_data
,
1345 const char *buf
, bool isfile
)
1347 char *wps_buffer
= NULL
;
1348 if (!wps_data
|| !buf
)
1350 #ifdef HAVE_ALBUMART
1352 struct mp3entry
*curtrack
;
1354 struct skin_albumart old_aa
= {.state
= WPS_ALBUMART_NONE
};
1355 if (wps_data
->albumart
)
1357 old_aa
.state
= wps_data
->albumart
->state
;
1358 old_aa
.height
= wps_data
->albumart
->height
;
1359 old_aa
.width
= wps_data
->albumart
->width
;
1362 #ifdef HAVE_LCD_BITMAP
1364 for (i
=0;i
<MAXUSERFONTS
;i
++)
1366 skinfonts
[i
].id
= -1;
1367 skinfonts
[i
].name
= NULL
;
1370 #ifdef DEBUG_SKIN_ENGINE
1371 if (isfile
&& debug_wps
)
1373 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf
);
1378 skin_data_reset(wps_data
);
1379 wps_data
->wps_loaded
= false;
1380 curr_screen
= screen
;
1383 curr_viewport_element
= NULL
;
1387 int fd
= open_utf8(buf
, O_RDONLY
);
1392 /* get buffer space from the plugin buffer */
1393 size_t buffersize
= 0;
1394 wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
1399 /* copy the file's content to the buffer for parsing,
1400 ensuring that every line ends with a newline char. */
1401 unsigned int start
= 0;
1402 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
1404 start
+= strlen(wps_buffer
+ start
);
1405 if (start
< buffersize
- 1)
1407 wps_buffer
[start
++] = '\n';
1408 wps_buffer
[start
] = 0;
1417 wps_buffer
= (char*)buf
;
1419 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1420 wps_data
->backdrop
= "-";
1422 /* parse the skin source */
1423 skin_buffer_save_position();
1424 wps_data
->tree
= skin_parse(wps_buffer
, skin_element_callback
, wps_data
);
1425 if (!wps_data
->tree
) {
1426 skin_data_reset(wps_data
);
1427 skin_buffer_restore_position();
1431 #ifdef HAVE_LCD_BITMAP
1432 char bmpdir
[MAX_PATH
];
1435 /* get the bitmap dir */
1436 char *dot
= strrchr(buf
, '.');
1437 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
1441 snprintf(bmpdir
, MAX_PATH
, "%s", BACKDROP_DIR
);
1443 /* load the bitmaps that were found by the parsing */
1444 if (!load_skin_bitmaps(wps_data
, bmpdir
) ||
1445 !skin_load_fonts(wps_data
))
1447 skin_data_reset(wps_data
);
1448 skin_buffer_restore_position();
1452 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
1453 status
= audio_status();
1454 if (status
& AUDIO_STATUS_PLAY
)
1456 struct skin_albumart
*aa
= wps_data
->albumart
;
1457 if (aa
&& ((aa
->state
&& !old_aa
.state
) ||
1459 (((old_aa
.height
!= aa
->height
) ||
1460 (old_aa
.width
!= aa
->width
))))))
1462 curtrack
= audio_current_track();
1463 offset
= curtrack
->offset
;
1465 if (!(status
& AUDIO_STATUS_PAUSE
))
1470 wps_data
->wps_loaded
= true;
1471 #ifdef DEBUG_SKIN_ENGINE
1472 // if (isfile && debug_wps)
1473 // debug_skin_usage();