1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * $Id: skin_parser.c 26752 2010-06-10 21:22:16Z bieber $
10 * Copyright (C) 2010 Jonathan Gordon
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
30 #include "core_alloc.h"
32 #include "appevents.h"
37 #include "skin_display.h"
38 #include "skin_engine.h"
39 #include "skin_parser.h"
40 #include "tag_table.h"
41 #include "skin_scan.h"
50 #include "root_menu.h"
57 struct skin_draw_info
{
59 struct skin_viewport
*skin_vp
;
61 unsigned long refresh_type
;
64 char* cur_align_start
;
65 struct align_pos align
;
73 int offset
; /* used by the playlist viewer */
76 typedef bool (*skin_render_func
)(struct skin_element
* alternator
, struct skin_draw_info
*info
);
77 bool skin_render_alternator(struct skin_element
* alternator
, struct skin_draw_info
*info
);
79 #ifdef HAVE_LCD_BITMAP
80 static void skin_render_playlistviewer(struct playlistviewer
* viewer
,
82 struct skin_viewport
* skin_viewport
,
83 unsigned long refresh_type
);
86 static char* skin_buffer
;
88 static inline struct skin_element
*
89 get_child(OFFSETTYPE(struct skin_element
**) children
, int child
)
91 OFFSETTYPE(struct skin_element
*) *kids
= SKINOFFSETTOPTR(skin_buffer
, children
);
92 return SKINOFFSETTOPTR(skin_buffer
, kids
[child
]);
96 static bool do_non_text_tags(struct gui_wps
*gwps
, struct skin_draw_info
*info
,
97 struct skin_element
*element
, struct viewport
* vp
)
99 #ifndef HAVE_LCD_BITMAP
100 (void)vp
; /* silence warnings */
103 struct wps_token
*token
= (struct wps_token
*)SKINOFFSETTOPTR(skin_buffer
, element
->data
);
105 #ifdef HAVE_LCD_BITMAP
106 struct wps_data
*data
= gwps
->data
;
107 bool do_refresh
= (element
->tag
->flags
& info
->refresh_type
) > 0;
111 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
112 case SKIN_TOKEN_VIEWPORT_FGCOLOUR
:
114 struct viewport_colour
*col
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
115 struct viewport
*vp
= SKINOFFSETTOPTR(skin_buffer
, col
->vp
);
116 vp
->fg_pattern
= col
->colour
;
119 case SKIN_TOKEN_VIEWPORT_BGCOLOUR
:
121 struct viewport_colour
*col
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
122 struct viewport
*vp
= SKINOFFSETTOPTR(skin_buffer
, col
->vp
);
123 vp
->bg_pattern
= col
->colour
;
126 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE
:
127 info
->text_style
= token
->value
.l
;
130 #ifdef HAVE_LCD_COLOR
131 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP
:
133 struct gradient_config
*cfg
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
134 vp
->lss_pattern
= cfg
->start
;
135 vp
->lse_pattern
= cfg
->end
;
136 vp
->lst_pattern
= cfg
->text
;
140 case SKIN_TOKEN_VIEWPORT_ENABLE
:
142 char *label
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
143 char temp
= VP_DRAW_HIDEABLE
;
144 struct skin_element
*viewport
= SKINOFFSETTOPTR(skin_buffer
, gwps
->data
->tree
);
147 struct skin_viewport
*skinvp
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
149 char *vplabel
= SKINOFFSETTOPTR(skin_buffer
, skinvp
->label
);
150 if (skinvp
->label
== VP_DEFAULT_LABEL
)
151 vplabel
= VP_DEFAULT_LABEL_STRING
;
152 if (vplabel
&& !skinvp
->is_infovp
&&
153 !strcmp(vplabel
, label
))
155 if (skinvp
->hidden_flags
&VP_DRAW_HIDDEN
)
157 temp
|= VP_DRAW_WASHIDDEN
;
159 skinvp
->hidden_flags
= temp
;
161 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
);
165 #ifdef HAVE_LCD_BITMAP
166 case SKIN_TOKEN_LIST_ITEM_CFG
:
167 skinlist_set_cfg(gwps
->display
->screen_type
,
168 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
));
170 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
171 sb_set_info_vp(gwps
->display
->screen_type
, token
->value
.data
);
173 case SKIN_TOKEN_PEAKMETER
:
174 data
->peak_meter_enabled
= true;
176 draw_peakmeters(gwps
, info
->line_number
, vp
);
178 case SKIN_TOKEN_DRAWRECTANGLE
:
181 struct draw_rectangle
*rect
=
182 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
183 #ifdef HAVE_LCD_COLOR
184 if (rect
->start_colour
!= rect
->end_colour
&&
185 gwps
->display
->screen_type
== SCREEN_MAIN
)
187 gwps
->display
->gradient_fillrect(rect
->x
, rect
->y
, rect
->width
,
188 rect
->height
, rect
->start_colour
, rect
->end_colour
);
194 unsigned backup
= vp
->fg_pattern
;
195 vp
->fg_pattern
= rect
->start_colour
;
197 gwps
->display
->fillrect(rect
->x
, rect
->y
, rect
->width
,
200 vp
->fg_pattern
= backup
;
205 case SKIN_TOKEN_PEAKMETER_LEFTBAR
:
206 case SKIN_TOKEN_PEAKMETER_RIGHTBAR
:
207 data
->peak_meter_enabled
= true;
208 /* fall through to the progressbar code */
210 case SKIN_TOKEN_VOLUMEBAR
:
211 case SKIN_TOKEN_BATTERY_PERCENTBAR
:
212 case SKIN_TOKEN_SETTINGBAR
:
213 #ifdef HAVE_LCD_BITMAP
214 case SKIN_TOKEN_PROGRESSBAR
:
215 case SKIN_TOKEN_TUNER_RSSI_BAR
:
216 case SKIN_TOKEN_LIST_SCROLLBAR
:
218 struct progressbar
*bar
= (struct progressbar
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
220 draw_progressbar(gwps
, info
->line_number
, bar
);
224 #ifdef HAVE_LCD_BITMAP
225 case SKIN_TOKEN_IMAGE_DISPLAY
:
227 struct gui_img
*img
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
228 if (img
&& img
->loaded
&& do_refresh
)
232 case SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
:
233 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
234 case SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT
:
236 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
237 const char* label
= SKINOFFSETTOPTR(skin_buffer
, id
->label
);
238 struct gui_img
*img
= skin_find_item(label
,SKIN_FIND_IMAGE
, data
);
239 if (img
&& img
->loaded
)
241 if (SKINOFFSETTOPTR(skin_buffer
, id
->token
) == NULL
)
243 img
->display
= id
->subimage
;
249 int a
= img
->num_subimages
;
250 out
= get_token_value(gwps
, SKINOFFSETTOPTR(skin_buffer
, id
->token
),
251 info
->offset
, buf
, sizeof(buf
), &a
);
253 /* NOTE: get_token_value() returns values starting at 1! */
255 a
= (out
&& *out
) ? 1 : 2;
256 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
)
257 a
-= 2; /* 2 is added in statusbar-skinned.c! */
262 /* Clear the image, as in conditionals */
263 clear_image_pos(gwps
, img
);
265 /* If the token returned a value which is higher than
266 * the amount of subimages, don't draw it. */
267 if (a
>= 0 && a
< img
->num_subimages
)
276 case SKIN_TOKEN_ALBUMART_DISPLAY
:
278 struct skin_albumart
*aa
= SKINOFFSETTOPTR(skin_buffer
, data
->albumart
);
279 /* now draw the AA */
280 if (do_refresh
&& aa
)
282 int handle
= playback_current_aa_hid(data
->playback_aa_slot
);
283 #if 0 /* FIXME: FS#12797*/
284 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
286 struct dim dim
= {aa
->width
, aa
->height
};
287 handle
= radio_get_art_hid(&dim
);
290 aa
->draw_handle
= handle
;
295 case SKIN_TOKEN_DRAW_INBUILTBAR
:
296 gui_statusbar_draw(&(statusbars
.statusbars
[gwps
->display
->screen_type
]),
297 info
->refresh_type
== SKIN_REFRESH_ALL
,
298 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
));
300 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
302 skin_render_playlistviewer(SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
), gwps
,
303 info
->skin_vp
, info
->refresh_type
);
306 #endif /* HAVE_LCD_BITMAP */
307 #ifdef HAVE_SKIN_VARIABLES
308 case SKIN_TOKEN_VAR_SET
:
310 struct skin_var_changer
*data
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
311 struct skin_var
*var
= SKINOFFSETTOPTR(skin_buffer
, data
->var
);
313 var
->value
= data
->newval
;
316 var
->value
+= data
->newval
;
319 if (var
->value
> data
->max
)
321 else if (var
->value
< 1)
322 var
->value
= data
->max
;
327 var
->last_changed
= current_tick
;
339 static void do_tags_in_hidden_conditional(struct skin_element
* branch
,
340 struct skin_draw_info
*info
)
342 #ifdef HAVE_LCD_BITMAP
343 struct gui_wps
*gwps
= info
->gwps
;
344 struct wps_data
*data
= gwps
->data
;
346 /* Tags here are ones which need to be "turned off" or cleared
347 * if they are in a conditional branch which isnt being used */
348 if (branch
->type
== LINE_ALTERNATOR
)
351 for (i
=0; i
<branch
->children_count
; i
++)
353 do_tags_in_hidden_conditional(get_child(branch
->children
, i
), info
);
356 else if (branch
->type
== LINE
&& branch
->children_count
)
358 struct skin_element
*child
= get_child(branch
->children
, 0);
359 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
360 struct wps_token
*token
;
364 if (child
->type
== CONDITIONAL
)
367 for (i
=0; i
<child
->children_count
; i
++)
369 do_tags_in_hidden_conditional(get_child(child
->children
, i
), info
);
371 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
374 else if (child
->type
!= TAG
|| !SKINOFFSETTOPTR(skin_buffer
, child
->data
))
376 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
379 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
380 token
= (struct wps_token
*)SKINOFFSETTOPTR(skin_buffer
, child
->data
);
382 #ifdef HAVE_LCD_BITMAP
383 /* clear all pictures in the conditional and nested ones */
384 if (token
->type
== SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
)
386 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
387 struct gui_img
*img
= skin_find_item(SKINOFFSETTOPTR(skin_buffer
, id
->label
),
388 SKIN_FIND_IMAGE
, data
);
389 clear_image_pos(gwps
, img
);
391 else if (token
->type
== SKIN_TOKEN_PEAKMETER
)
393 data
->peak_meter_enabled
= false;
395 else if (token
->type
== SKIN_TOKEN_VIEWPORT_ENABLE
)
397 char *label
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
398 struct skin_element
*viewport
;
399 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
401 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
403 struct skin_viewport
*skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
405 char *vplabel
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
406 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
407 vplabel
= VP_DEFAULT_LABEL_STRING
;
408 if (vplabel
&& strcmp(vplabel
, label
))
410 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
414 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
416 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
417 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
420 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
421 if (skin_viewport
->output_to_backdrop_buffer
)
423 void *backdrop
= skin_backdrop_get_buffer(data
->backdrop_id
);
424 gwps
->display
->set_framebuffer(backdrop
);
425 skin_backdrop_show(-1);
428 gwps
->display
->set_viewport(&skin_viewport
->vp
);
429 gwps
->display
->clear_viewport();
430 gwps
->display
->scroll_stop(&skin_viewport
->vp
);
431 gwps
->display
->set_viewport(&info
->skin_vp
->vp
);
432 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
434 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
435 if (skin_viewport
->output_to_backdrop_buffer
)
437 gwps
->display
->set_framebuffer(NULL
);
438 skin_backdrop_show(data
->backdrop_id
);
447 else if (data
->albumart
&& token
->type
== SKIN_TOKEN_ALBUMART_DISPLAY
)
450 playback_current_aa_hid(data
->playback_aa_slot
), true);
453 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
458 static void fix_line_alignment(struct skin_draw_info
*info
, struct skin_element
*element
)
460 struct align_pos
*align
= &info
->align
;
461 char *cur_pos
= info
->cur_align_start
+ strlen(info
->cur_align_start
);
462 switch (element
->tag
->type
)
464 case SKIN_TOKEN_ALIGN_LEFT
:
465 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
466 align
->left
= cur_pos
;
467 info
->cur_align_start
= cur_pos
;
469 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
470 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
472 align
->right
= cur_pos
;
474 align
->left
= cur_pos
;
475 info
->cur_align_start
= cur_pos
;
477 case SKIN_TOKEN_ALIGN_CENTER
:
478 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
479 align
->center
= cur_pos
;
480 info
->cur_align_start
= cur_pos
;
482 case SKIN_TOKEN_ALIGN_RIGHT
:
483 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
484 align
->right
= cur_pos
;
485 info
->cur_align_start
= cur_pos
;
487 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
488 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
490 align
->left
= cur_pos
;
492 align
->right
= cur_pos
;
493 info
->cur_align_start
= cur_pos
;
500 /* Draw a LINE element onto the display */
501 static bool skin_render_line(struct skin_element
* line
, struct skin_draw_info
*info
)
503 bool needs_update
= false;
504 int last_value
, value
;
506 if (line
->children_count
== 0)
507 return false; /* empty line, do nothing */
509 struct skin_element
*child
= get_child(line
->children
, 0);
510 struct conditional
*conditional
;
511 skin_render_func func
= skin_render_line
;
512 int old_refresh_mode
= info
->refresh_type
;
518 conditional
= SKINOFFSETTOPTR(skin_buffer
, child
->data
);
519 last_value
= conditional
->last_value
;
520 value
= evaluate_conditional(info
->gwps
, info
->offset
,
521 conditional
, child
->children_count
);
522 conditional
->last_value
= value
;
523 if (child
->children_count
== 1)
525 /* special handling so
526 * %?aa<true> and %?<true|false> need special handlng here */
528 if (value
== -1) /* tag is false */
530 /* we are in a false branch of a %?aa<true> conditional */
532 do_tags_in_hidden_conditional(get_child(child
->children
, 0), info
);
538 if (last_value
>= 0 && value
!= last_value
&& last_value
< child
->children_count
)
539 do_tags_in_hidden_conditional(get_child(child
->children
, last_value
), info
);
541 if (get_child(child
->children
, value
)->type
== LINE_ALTERNATOR
)
543 func
= skin_render_alternator
;
545 else if (get_child(child
->children
, value
)->type
== LINE
)
546 func
= skin_render_line
;
548 if (value
!= last_value
)
550 info
->refresh_type
= SKIN_REFRESH_ALL
;
551 info
->force_redraw
= true;
554 if (func(get_child(child
->children
, value
), info
))
557 needs_update
= needs_update
|| (last_value
!= value
);
559 info
->refresh_type
= old_refresh_mode
;
562 if (child
->tag
->flags
& NOBREAK
)
563 info
->no_line_break
= true;
564 if (child
->tag
->type
== SKIN_TOKEN_SUBLINE_SCROLL
)
565 info
->line_scrolls
= true;
567 fix_line_alignment(info
, child
);
569 if (!SKINOFFSETTOPTR(skin_buffer
, child
->data
))
573 if (!do_non_text_tags(info
->gwps
, info
, child
, &info
->skin_vp
->vp
))
575 static char tempbuf
[128];
576 const char *valuestr
= get_token_value(info
->gwps
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
577 info
->offset
, tempbuf
,
578 sizeof(tempbuf
), NULL
);
582 if (child
->tag
->flags
&SKIN_RTC_REFRESH
)
583 needs_update
= needs_update
|| info
->refresh_type
&SKIN_REFRESH_DYNAMIC
;
585 needs_update
= needs_update
||
586 ((child
->tag
->flags
&info
->refresh_type
)!=0);
587 strlcat(info
->cur_align_start
, valuestr
,
588 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
593 strlcat(info
->cur_align_start
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
594 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
595 needs_update
= needs_update
||
596 (info
->refresh_type
&SKIN_REFRESH_STATIC
) != 0;
603 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
608 static int get_subline_timeout(struct gui_wps
*gwps
, struct skin_element
* line
)
610 struct skin_element
*element
=line
;
611 struct wps_token
*token
;
612 int retval
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
613 if (element
->type
== LINE
)
615 if (element
->children_count
== 0)
616 return retval
; /* empty line, so force redraw */
617 element
= get_child(element
->children
, 0);
621 if (element
->type
== TAG
&&
622 element
->tag
->type
== SKIN_TOKEN_SUBLINE_TIMEOUT
)
624 token
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
625 return token
->value
.i
;
627 else if (element
->type
== CONDITIONAL
)
629 struct conditional
*conditional
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
630 int val
= evaluate_conditional(gwps
, 0, conditional
,
631 element
->children_count
);
634 retval
= get_subline_timeout(gwps
, get_child(element
->children
, val
));
639 element
= SKINOFFSETTOPTR(skin_buffer
, element
->next
);
644 bool skin_render_alternator(struct skin_element
* element
, struct skin_draw_info
*info
)
646 bool changed_lines
= false;
647 struct line_alternator
*alternator
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
648 unsigned old_refresh
= info
->refresh_type
;
649 if (info
->refresh_type
== SKIN_REFRESH_ALL
)
651 alternator
->current_line
= element
->children_count
-1;
652 changed_lines
= true;
654 else if (TIME_AFTER(current_tick
, alternator
->next_change_tick
))
656 changed_lines
= true;
661 struct skin_element
*current_line
;
662 int start
= alternator
->current_line
;
663 int try_line
= start
;
664 bool suitable
= false;
665 int rettimeout
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
667 /* find a subline which has at least one token in it,
668 * and that line doesnt have a timeout set to 0 through conditionals */
671 if (try_line
>= element
->children_count
)
673 if (get_child(element
->children
, try_line
)->children_count
!= 0)
675 current_line
= get_child(element
->children
, try_line
);
676 rettimeout
= get_subline_timeout(info
->gwps
,
677 get_child(current_line
->children
, 0));
684 while (try_line
!= start
&& !suitable
);
688 alternator
->current_line
= try_line
;
689 alternator
->next_change_tick
= current_tick
+ rettimeout
;
692 info
->refresh_type
= SKIN_REFRESH_ALL
;
693 info
->force_redraw
= true;
695 bool ret
= skin_render_line(get_child(element
->children
, alternator
->current_line
), info
);
696 info
->refresh_type
= old_refresh
;
697 return changed_lines
|| ret
;
700 void skin_render_viewport(struct skin_element
* viewport
, struct gui_wps
*gwps
,
701 struct skin_viewport
* skin_viewport
, unsigned long refresh_type
)
703 struct screen
*display
= gwps
->display
;
704 char linebuf
[MAX_LINE
];
705 skin_render_func func
= skin_render_line
;
706 struct skin_element
* line
= viewport
;
707 struct skin_draw_info info
= {
710 .buf_size
= sizeof(linebuf
),
712 .no_line_break
= false,
713 .line_scrolls
= false,
714 .refresh_type
= refresh_type
,
715 .skin_vp
= skin_viewport
,
717 .text_style
= STYLE_DEFAULT
720 struct align_pos
* align
= &info
.align
;
722 skin_buffer
= get_skin_buffer(gwps
->data
);
723 #ifdef HAVE_LCD_BITMAP
724 /* Set images to not to be displayed */
725 struct skin_token_list
*imglist
= SKINOFFSETTOPTR(skin_buffer
, gwps
->data
->images
);
728 struct wps_token
*token
= SKINOFFSETTOPTR(skin_buffer
, imglist
->token
);
729 struct gui_img
*img
= (struct gui_img
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
731 imglist
= SKINOFFSETTOPTR(skin_buffer
, imglist
->next
);
735 if (skin_viewport
->parsed_fontid
== 1)
736 skin_viewport
->vp
.font
= display
->getuifont();
742 info
.no_line_break
= false;
743 info
.line_scrolls
= false;
744 info
.force_redraw
= false;
745 #ifdef HAVE_LCD_COLOR
746 if (info
.text_style
&STYLE_GRADIENT
)
748 int cur
= CURLN_UNPACK(info
.text_style
);
749 int num
= NUMLN_UNPACK(info
.text_style
);
751 info
.text_style
= STYLE_DEFAULT
;
753 info
.text_style
= STYLE_GRADIENT
|CURLN_PACK(cur
+1)|NUMLN_PACK(num
);
756 info
.cur_align_start
= info
.buf
;
757 align
->left
= info
.buf
;
758 align
->center
= NULL
;
762 if (line
->type
== LINE_ALTERNATOR
)
763 func
= skin_render_alternator
;
764 else if (line
->type
== LINE
)
765 func
= skin_render_line
;
767 needs_update
= func(line
, &info
);
768 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
769 if (skin_viewport
->vp
.fg_pattern
!= skin_viewport
->start_fgcolour
||
770 skin_viewport
->vp
.bg_pattern
!= skin_viewport
->start_bgcolour
)
772 /* 2bit lcd drivers need lcd_set_viewport() to be called to change
773 * the colour, 16bit doesnt. But doing this makes static text
774 * get the new colour also */
776 display
->set_viewport(&skin_viewport
->vp
);
779 /* only update if the line needs to be, and there is something to write */
780 if (refresh_type
&& needs_update
)
782 if (info
.force_redraw
)
783 display
->scroll_stop_line(&skin_viewport
->vp
, info
.line_number
);
784 write_line(display
, align
, info
.line_number
,
785 info
.line_scrolls
, info
.text_style
);
787 if (!info
.no_line_break
)
789 line
= SKINOFFSETTOPTR(skin_buffer
, line
->next
);
791 #ifdef HAVE_LCD_BITMAP
792 wps_display_images(gwps
, &skin_viewport
->vp
);
796 void skin_render(struct gui_wps
*gwps
, unsigned refresh_mode
)
798 struct wps_data
*data
= gwps
->data
;
799 struct screen
*display
= gwps
->display
;
801 struct skin_element
* viewport
;
802 struct skin_viewport
* skin_viewport
;
805 int old_refresh_mode
= refresh_mode
;
806 skin_buffer
= get_skin_buffer(gwps
->data
);
808 #ifdef HAVE_LCD_CHARCELLS
810 for (i
= 0; i
< 8; i
++)
812 if (data
->wps_progress_pat
[i
] == 0)
813 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
817 viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
818 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
819 label
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
820 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
821 label
= VP_DEFAULT_LABEL_STRING
;
822 if (label
&& SKINOFFSETTOPTR(skin_buffer
, viewport
->next
) &&
823 !strcmp(label
,VP_DEFAULT_LABEL_STRING
))
826 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
828 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
831 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
832 unsigned vp_refresh_mode
= refresh_mode
;
833 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
834 skin_viewport
->vp
.fg_pattern
= skin_viewport
->start_fgcolour
;
835 skin_viewport
->vp
.bg_pattern
= skin_viewport
->start_bgcolour
;
836 if (skin_viewport
->output_to_backdrop_buffer
)
838 display
->set_framebuffer(skin_backdrop_get_buffer(data
->backdrop_id
));
839 skin_backdrop_show(-1);
843 display
->set_framebuffer(NULL
);
844 skin_backdrop_show(data
->backdrop_id
);
847 #ifdef HAVE_LCD_COLOR
848 skin_viewport
->vp
.lss_pattern
= skin_viewport
->start_gradient
.start
;
849 skin_viewport
->vp
.lse_pattern
= skin_viewport
->start_gradient
.end
;
850 skin_viewport
->vp
.lst_pattern
= skin_viewport
->start_gradient
.text
;
853 /* dont redraw the viewport if its disabled */
854 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
855 { /* don't draw anything into this one */
858 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
860 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
863 else if (((skin_viewport
->hidden_flags
&
864 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
865 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
867 vp_refresh_mode
= SKIN_REFRESH_ALL
;
868 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
871 display
->set_viewport(&skin_viewport
->vp
);
872 if ((vp_refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
)
874 display
->clear_viewport();
877 if (viewport
->children_count
)
878 skin_render_viewport(get_child(viewport
->children
, 0), gwps
,
879 skin_viewport
, vp_refresh_mode
);
880 refresh_mode
= old_refresh_mode
;
882 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
883 display
->set_framebuffer(NULL
);
884 skin_backdrop_show(data
->backdrop_id
);
887 if (((refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
))
889 /* If this is the UI viewport then let the UI know
890 * to redraw itself */
891 send_event(GUI_EVENT_NEED_UI_UPDATE
, NULL
);
893 /* Restore the default viewport */
894 display
->set_viewport(NULL
);
898 #ifdef HAVE_LCD_BITMAP
899 static __attribute__((noinline
))
900 void skin_render_playlistviewer(struct playlistviewer
* viewer
,
901 struct gui_wps
*gwps
,
902 struct skin_viewport
* skin_viewport
,
903 unsigned long refresh_type
)
905 struct screen
*display
= gwps
->display
;
906 char linebuf
[MAX_LINE
];
907 skin_render_func func
= skin_render_line
;
908 struct skin_element
* line
;
909 struct skin_draw_info info
= {
912 .buf_size
= sizeof(linebuf
),
914 .no_line_break
= false,
915 .line_scrolls
= false,
916 .refresh_type
= refresh_type
,
917 .skin_vp
= skin_viewport
,
918 .offset
= viewer
->start_offset
,
919 .text_style
= STYLE_DEFAULT
922 struct align_pos
* align
= &info
.align
;
924 int cur_pos
, start_item
, max
;
925 int nb_lines
= viewport_get_nb_lines(SKINOFFSETTOPTR(skin_buffer
, viewer
->vp
));
927 if (get_current_activity() == ACTIVITY_FM
)
929 cur_pos
= radio_current_preset();
930 start_item
= cur_pos
+ viewer
->start_offset
;
931 max
= start_item
+radio_preset_count();
936 struct cuesheet
*cue
= skin_get_global_state()->id3
?
937 skin_get_global_state()->id3
->cuesheet
: NULL
;
938 cur_pos
= playlist_get_display_index();
939 max
= playlist_amount()+1;
941 max
+= cue
->track_count
;
942 start_item
= MAX(0, cur_pos
+ viewer
->start_offset
);
944 if (max
-start_item
> nb_lines
)
945 max
= start_item
+ nb_lines
;
947 line
= SKINOFFSETTOPTR(skin_buffer
, viewer
->line
);
948 while (start_item
< max
)
951 info
.no_line_break
= false;
952 info
.line_scrolls
= false;
953 info
.force_redraw
= false;
955 info
.cur_align_start
= info
.buf
;
956 align
->left
= info
.buf
;
957 align
->center
= NULL
;
961 if (line
->type
== LINE_ALTERNATOR
)
962 func
= skin_render_alternator
;
963 else if (line
->type
== LINE
)
964 func
= skin_render_line
;
966 needs_update
= func(line
, &info
);
968 /* only update if the line needs to be, and there is something to write */
969 if (refresh_type
&& needs_update
)
971 if (!info
.force_redraw
)
972 display
->scroll_stop_line(&skin_viewport
->vp
, info
.line_number
);
973 write_line(display
, align
, info
.line_number
,
974 info
.line_scrolls
, info
.text_style
);