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"
36 #include "skin_display.h"
37 #include "skin_engine.h"
38 #include "skin_parser.h"
39 #include "tag_table.h"
40 #include "skin_scan.h"
49 #include "root_menu.h"
56 struct skin_draw_info
{
58 struct skin_viewport
*skin_vp
;
60 unsigned long refresh_type
;
63 char* cur_align_start
;
64 struct align_pos align
;
72 int offset
; /* used by the playlist viewer */
75 typedef bool (*skin_render_func
)(struct skin_element
* alternator
, struct skin_draw_info
*info
);
76 bool skin_render_alternator(struct skin_element
* alternator
, struct skin_draw_info
*info
);
78 #ifdef HAVE_LCD_BITMAP
79 static void skin_render_playlistviewer(struct playlistviewer
* viewer
,
81 struct skin_viewport
* skin_viewport
,
82 unsigned long refresh_type
);
85 static char* skin_buffer
;
86 /* hack alert: fix skin_parser.c's skin_buffer pointer */
87 void skinparser_set_buffer(char* pointer
);
89 static inline struct skin_element
*
90 get_child(OFFSETTYPE(struct skin_element
**) children
, int child
)
92 OFFSETTYPE(struct skin_element
*) *kids
= SKINOFFSETTOPTR(skin_buffer
, children
);
93 return SKINOFFSETTOPTR(skin_buffer
, kids
[child
]);
97 static bool do_non_text_tags(struct gui_wps
*gwps
, struct skin_draw_info
*info
,
98 struct skin_element
*element
, struct viewport
* vp
)
100 #ifndef HAVE_LCD_BITMAP
101 (void)vp
; /* silence warnings */
104 struct wps_token
*token
= (struct wps_token
*)SKINOFFSETTOPTR(skin_buffer
, element
->data
);
106 #ifdef HAVE_LCD_BITMAP
107 struct wps_data
*data
= gwps
->data
;
108 bool do_refresh
= (element
->tag
->flags
& info
->refresh_type
) > 0;
112 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
113 case SKIN_TOKEN_VIEWPORT_FGCOLOUR
:
115 struct viewport_colour
*col
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
116 struct viewport
*vp
= SKINOFFSETTOPTR(skin_buffer
, col
->vp
);
117 vp
->fg_pattern
= col
->colour
;
120 case SKIN_TOKEN_VIEWPORT_BGCOLOUR
:
122 struct viewport_colour
*col
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
123 struct viewport
*vp
= SKINOFFSETTOPTR(skin_buffer
, col
->vp
);
124 vp
->bg_pattern
= col
->colour
;
127 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE
:
128 info
->text_style
= token
->value
.l
;
131 #ifdef HAVE_LCD_COLOR
132 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP
:
134 struct gradient_config
*cfg
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
135 vp
->lss_pattern
= cfg
->start
;
136 vp
->lse_pattern
= cfg
->end
;
137 vp
->lst_pattern
= cfg
->text
;
141 case SKIN_TOKEN_VIEWPORT_ENABLE
:
143 char *label
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
144 char temp
= VP_DRAW_HIDEABLE
;
145 struct skin_element
*viewport
= SKINOFFSETTOPTR(skin_buffer
, gwps
->data
->tree
);
148 struct skin_viewport
*skinvp
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
150 char *vplabel
= SKINOFFSETTOPTR(skin_buffer
, skinvp
->label
);
151 if (skinvp
->label
== VP_DEFAULT_LABEL
)
152 vplabel
= VP_DEFAULT_LABEL_STRING
;
153 if (vplabel
&& !skinvp
->is_infovp
&&
154 !strcmp(vplabel
, label
))
156 if (skinvp
->hidden_flags
&VP_DRAW_HIDDEN
)
158 temp
|= VP_DRAW_WASHIDDEN
;
160 skinvp
->hidden_flags
= temp
;
162 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
);
166 #ifdef HAVE_LCD_BITMAP
167 case SKIN_TOKEN_LIST_ITEM_CFG
:
168 skinlist_set_cfg(gwps
->display
->screen_type
,
169 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
));
171 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
172 sb_set_info_vp(gwps
->display
->screen_type
, token
->value
.data
);
174 case SKIN_TOKEN_PEAKMETER
:
175 data
->peak_meter_enabled
= true;
177 draw_peakmeters(gwps
, info
->line_number
, vp
);
179 case SKIN_TOKEN_DRAWRECTANGLE
:
182 struct draw_rectangle
*rect
=
183 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
184 #ifdef HAVE_LCD_COLOR
185 if (rect
->start_colour
!= rect
->end_colour
&&
186 gwps
->display
->screen_type
== SCREEN_MAIN
)
188 gwps
->display
->gradient_fillrect(rect
->x
, rect
->y
, rect
->width
,
189 rect
->height
, rect
->start_colour
, rect
->end_colour
);
194 unsigned backup
= vp
->fg_pattern
;
195 vp
->fg_pattern
= rect
->start_colour
;
196 gwps
->display
->fillrect(rect
->x
, rect
->y
, rect
->width
,
198 vp
->fg_pattern
= backup
;
202 case SKIN_TOKEN_PEAKMETER_LEFTBAR
:
203 case SKIN_TOKEN_PEAKMETER_RIGHTBAR
:
204 data
->peak_meter_enabled
= true;
205 /* fall through to the progressbar code */
207 case SKIN_TOKEN_VOLUMEBAR
:
208 case SKIN_TOKEN_BATTERY_PERCENTBAR
:
209 #ifdef HAVE_LCD_BITMAP
210 case SKIN_TOKEN_PROGRESSBAR
:
211 case SKIN_TOKEN_TUNER_RSSI_BAR
:
212 case SKIN_TOKEN_LIST_SCROLLBAR
:
214 struct progressbar
*bar
= (struct progressbar
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
216 draw_progressbar(gwps
, info
->line_number
, bar
);
220 #ifdef HAVE_LCD_BITMAP
221 case SKIN_TOKEN_IMAGE_DISPLAY
:
223 struct gui_img
*img
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
224 if (img
&& img
->loaded
&& do_refresh
)
228 case SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
:
229 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
231 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
232 const char* label
= SKINOFFSETTOPTR(skin_buffer
, id
->label
);
233 struct gui_img
*img
= skin_find_item(label
,SKIN_FIND_IMAGE
, data
);
234 if (img
&& img
->loaded
)
236 if (SKINOFFSETTOPTR(skin_buffer
, id
->token
) == NULL
)
238 img
->display
= id
->subimage
;
244 int a
= img
->num_subimages
;
245 out
= get_token_value(gwps
, SKINOFFSETTOPTR(skin_buffer
, id
->token
),
246 info
->offset
, buf
, sizeof(buf
), &a
);
248 /* NOTE: get_token_value() returns values starting at 1! */
250 a
= (out
&& *out
) ? 1 : 2;
251 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
)
252 a
-= 2; /* 2 is added in statusbar-skinned.c! */
257 /* Clear the image, as in conditionals */
258 clear_image_pos(gwps
, img
);
260 /* If the token returned a value which is higher than
261 * the amount of subimages, don't draw it. */
262 if (a
>= 0 && a
< img
->num_subimages
)
271 case SKIN_TOKEN_ALBUMART_DISPLAY
:
273 struct skin_albumart
*aa
= SKINOFFSETTOPTR(skin_buffer
, data
->albumart
);
274 /* now draw the AA */
275 if (do_refresh
&& aa
)
277 int handle
= playback_current_aa_hid(data
->playback_aa_slot
);
279 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
281 struct dim dim
= {aa
->width
, aa
->height
};
282 handle
= radio_get_art_hid(&dim
);
285 aa
->draw_handle
= handle
;
290 case SKIN_TOKEN_DRAW_INBUILTBAR
:
291 gui_statusbar_draw(&(statusbars
.statusbars
[gwps
->display
->screen_type
]),
292 info
->refresh_type
== SKIN_REFRESH_ALL
,
293 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
));
295 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
297 skin_render_playlistviewer(SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
), gwps
,
298 info
->skin_vp
, info
->refresh_type
);
301 #endif /* HAVE_LCD_BITMAP */
302 #ifdef HAVE_SKIN_VARIABLES
303 case SKIN_TOKEN_VAR_SET
:
305 struct skin_var_changer
*data
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
306 struct skin_var
*var
= SKINOFFSETTOPTR(skin_buffer
, data
->var
);
308 var
->value
= data
->newval
;
311 var
->value
+= data
->newval
;
314 if (var
->value
> data
->max
)
316 else if (var
->value
< 1)
317 var
->value
= data
->max
;
322 var
->last_changed
= current_tick
;
334 static void do_tags_in_hidden_conditional(struct skin_element
* branch
,
335 struct skin_draw_info
*info
)
337 #ifdef HAVE_LCD_BITMAP
338 struct gui_wps
*gwps
= info
->gwps
;
339 struct wps_data
*data
= gwps
->data
;
341 /* Tags here are ones which need to be "turned off" or cleared
342 * if they are in a conditional branch which isnt being used */
343 if (branch
->type
== LINE_ALTERNATOR
)
346 for (i
=0; i
<branch
->children_count
; i
++)
348 do_tags_in_hidden_conditional(get_child(branch
->children
, i
), info
);
351 else if (branch
->type
== LINE
&& branch
->children_count
)
353 struct skin_element
*child
= get_child(branch
->children
, 0);
354 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
355 struct wps_token
*token
;
359 if (child
->type
== CONDITIONAL
)
362 for (i
=0; i
<child
->children_count
; i
++)
364 do_tags_in_hidden_conditional(get_child(child
->children
, i
), info
);
366 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
369 else if (child
->type
!= TAG
|| !SKINOFFSETTOPTR(skin_buffer
, child
->data
))
371 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
374 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
375 token
= (struct wps_token
*)SKINOFFSETTOPTR(skin_buffer
, child
->data
);
377 #ifdef HAVE_LCD_BITMAP
378 /* clear all pictures in the conditional and nested ones */
379 if (token
->type
== SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
)
381 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
382 struct gui_img
*img
= skin_find_item(SKINOFFSETTOPTR(skin_buffer
, id
->label
),
383 SKIN_FIND_IMAGE
, data
);
384 clear_image_pos(gwps
, img
);
386 else if (token
->type
== SKIN_TOKEN_PEAKMETER
)
388 data
->peak_meter_enabled
= false;
390 else if (token
->type
== SKIN_TOKEN_VIEWPORT_ENABLE
)
392 char *label
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
393 struct skin_element
*viewport
;
394 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
396 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
398 struct skin_viewport
*skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
400 char *vplabel
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
401 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
402 vplabel
= VP_DEFAULT_LABEL_STRING
;
403 if (vplabel
&& strcmp(vplabel
, label
))
405 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
409 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
411 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
412 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
415 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
416 if (skin_viewport
->output_to_backdrop_buffer
)
418 void *backdrop
= skin_backdrop_get_buffer(data
->backdrop_id
);
419 gwps
->display
->set_framebuffer(backdrop
);
420 skin_backdrop_show(-1);
423 gwps
->display
->set_viewport(&skin_viewport
->vp
);
424 gwps
->display
->clear_viewport();
425 gwps
->display
->scroll_stop(&skin_viewport
->vp
);
426 gwps
->display
->set_viewport(&info
->skin_vp
->vp
);
427 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
429 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
430 if (skin_viewport
->output_to_backdrop_buffer
)
432 gwps
->display
->set_framebuffer(NULL
);
433 skin_backdrop_show(data
->backdrop_id
);
442 else if (data
->albumart
&& token
->type
== SKIN_TOKEN_ALBUMART_DISPLAY
)
445 playback_current_aa_hid(data
->playback_aa_slot
), true);
448 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
453 static void fix_line_alignment(struct skin_draw_info
*info
, struct skin_element
*element
)
455 struct align_pos
*align
= &info
->align
;
456 char *cur_pos
= info
->cur_align_start
+ strlen(info
->cur_align_start
);
457 switch (element
->tag
->type
)
459 case SKIN_TOKEN_ALIGN_LEFT
:
460 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
461 align
->left
= cur_pos
;
462 info
->cur_align_start
= cur_pos
;
464 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
465 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
467 align
->right
= cur_pos
;
469 align
->left
= cur_pos
;
470 info
->cur_align_start
= cur_pos
;
472 case SKIN_TOKEN_ALIGN_CENTER
:
473 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
474 align
->center
= cur_pos
;
475 info
->cur_align_start
= cur_pos
;
477 case SKIN_TOKEN_ALIGN_RIGHT
:
478 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
479 align
->right
= cur_pos
;
480 info
->cur_align_start
= cur_pos
;
482 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
483 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
485 align
->left
= cur_pos
;
487 align
->right
= cur_pos
;
488 info
->cur_align_start
= cur_pos
;
495 /* Draw a LINE element onto the display */
496 static bool skin_render_line(struct skin_element
* line
, struct skin_draw_info
*info
)
498 bool needs_update
= false;
499 int last_value
, value
;
501 if (line
->children_count
== 0)
502 return false; /* empty line, do nothing */
504 struct skin_element
*child
= get_child(line
->children
, 0);
505 struct conditional
*conditional
;
506 skin_render_func func
= skin_render_line
;
507 int old_refresh_mode
= info
->refresh_type
;
513 conditional
= SKINOFFSETTOPTR(skin_buffer
, child
->data
);
514 last_value
= conditional
->last_value
;
515 value
= evaluate_conditional(info
->gwps
, info
->offset
,
516 conditional
, child
->children_count
);
517 conditional
->last_value
= value
;
518 if (child
->children_count
== 1)
520 /* special handling so
521 * %?aa<true> and %?<true|false> need special handlng here */
523 if (value
== -1) /* tag is false */
525 /* we are in a false branch of a %?aa<true> conditional */
527 do_tags_in_hidden_conditional(get_child(child
->children
, 0), info
);
533 if (last_value
>= 0 && value
!= last_value
&& last_value
< child
->children_count
)
534 do_tags_in_hidden_conditional(get_child(child
->children
, last_value
), info
);
536 if (get_child(child
->children
, value
)->type
== LINE_ALTERNATOR
)
538 func
= skin_render_alternator
;
540 else if (get_child(child
->children
, value
)->type
== LINE
)
541 func
= skin_render_line
;
543 if (value
!= last_value
)
545 info
->refresh_type
= SKIN_REFRESH_ALL
;
546 info
->force_redraw
= true;
549 if (func(get_child(child
->children
, value
), info
))
552 needs_update
= needs_update
|| (last_value
!= value
);
554 info
->refresh_type
= old_refresh_mode
;
557 if (child
->tag
->flags
& NOBREAK
)
558 info
->no_line_break
= true;
559 if (child
->tag
->type
== SKIN_TOKEN_SUBLINE_SCROLL
)
560 info
->line_scrolls
= true;
562 fix_line_alignment(info
, child
);
564 if (!SKINOFFSETTOPTR(skin_buffer
, child
->data
))
568 if (!do_non_text_tags(info
->gwps
, info
, child
, &info
->skin_vp
->vp
))
570 static char tempbuf
[128];
571 const char *valuestr
= get_token_value(info
->gwps
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
572 info
->offset
, tempbuf
,
573 sizeof(tempbuf
), NULL
);
577 if (child
->tag
->flags
&SKIN_RTC_REFRESH
)
578 needs_update
= needs_update
|| info
->refresh_type
&SKIN_REFRESH_DYNAMIC
;
580 needs_update
= needs_update
||
581 ((child
->tag
->flags
&info
->refresh_type
)!=0);
582 strlcat(info
->cur_align_start
, valuestr
,
583 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
588 strlcat(info
->cur_align_start
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
589 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
590 needs_update
= needs_update
||
591 (info
->refresh_type
&SKIN_REFRESH_STATIC
) != 0;
598 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
603 static int get_subline_timeout(struct gui_wps
*gwps
, struct skin_element
* line
)
605 struct skin_element
*element
=line
;
606 struct wps_token
*token
;
607 int retval
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
608 if (element
->type
== LINE
)
610 if (element
->children_count
== 0)
611 return retval
; /* empty line, so force redraw */
612 element
= get_child(element
->children
, 0);
616 if (element
->type
== TAG
&&
617 element
->tag
->type
== SKIN_TOKEN_SUBLINE_TIMEOUT
)
619 token
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
620 return token
->value
.i
;
622 else if (element
->type
== CONDITIONAL
)
624 struct conditional
*conditional
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
625 int val
= evaluate_conditional(gwps
, 0, conditional
,
626 element
->children_count
);
629 retval
= get_subline_timeout(gwps
, get_child(element
->children
, val
));
634 element
= SKINOFFSETTOPTR(skin_buffer
, element
->next
);
639 bool skin_render_alternator(struct skin_element
* element
, struct skin_draw_info
*info
)
641 bool changed_lines
= false;
642 struct line_alternator
*alternator
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
643 unsigned old_refresh
= info
->refresh_type
;
644 if (info
->refresh_type
== SKIN_REFRESH_ALL
)
646 alternator
->current_line
= element
->children_count
-1;
647 changed_lines
= true;
649 else if (TIME_AFTER(current_tick
, alternator
->next_change_tick
))
651 changed_lines
= true;
656 struct skin_element
*current_line
;
657 int start
= alternator
->current_line
;
658 int try_line
= start
;
659 bool suitable
= false;
660 int rettimeout
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
662 /* find a subline which has at least one token in it,
663 * and that line doesnt have a timeout set to 0 through conditionals */
666 if (try_line
>= element
->children_count
)
668 if (get_child(element
->children
, try_line
)->children_count
!= 0)
670 current_line
= get_child(element
->children
, try_line
);
671 rettimeout
= get_subline_timeout(info
->gwps
,
672 get_child(current_line
->children
, 0));
679 while (try_line
!= start
&& !suitable
);
683 alternator
->current_line
= try_line
;
684 alternator
->next_change_tick
= current_tick
+ rettimeout
;
687 info
->refresh_type
= SKIN_REFRESH_ALL
;
688 info
->force_redraw
= true;
690 bool ret
= skin_render_line(get_child(element
->children
, alternator
->current_line
), info
);
691 info
->refresh_type
= old_refresh
;
692 return changed_lines
|| ret
;
695 void skin_render_viewport(struct skin_element
* viewport
, struct gui_wps
*gwps
,
696 struct skin_viewport
* skin_viewport
, unsigned long refresh_type
)
698 struct screen
*display
= gwps
->display
;
699 char linebuf
[MAX_LINE
];
700 skin_render_func func
= skin_render_line
;
701 struct skin_element
* line
= viewport
;
702 struct skin_draw_info info
= {
705 .buf_size
= sizeof(linebuf
),
707 .no_line_break
= false,
708 .line_scrolls
= false,
709 .refresh_type
= refresh_type
,
710 .skin_vp
= skin_viewport
,
712 .text_style
= STYLE_DEFAULT
715 struct align_pos
* align
= &info
.align
;
717 skin_buffer
= get_skin_buffer(gwps
->data
);
718 skinparser_set_buffer(skin_buffer
);
719 #ifdef HAVE_LCD_BITMAP
720 /* Set images to not to be displayed */
721 struct skin_token_list
*imglist
= SKINOFFSETTOPTR(skin_buffer
, gwps
->data
->images
);
724 struct wps_token
*token
= SKINOFFSETTOPTR(skin_buffer
, imglist
->token
);
725 struct gui_img
*img
= (struct gui_img
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
727 imglist
= SKINOFFSETTOPTR(skin_buffer
, imglist
->next
);
731 if (skin_viewport
->parsed_fontid
== 1)
732 skin_viewport
->vp
.font
= display
->getuifont();
738 info
.no_line_break
= false;
739 info
.line_scrolls
= false;
740 info
.force_redraw
= false;
741 #ifdef HAVE_LCD_COLOR
742 if (info
.text_style
&STYLE_GRADIENT
)
744 int cur
= CURLN_UNPACK(info
.text_style
);
745 int num
= NUMLN_UNPACK(info
.text_style
);
747 info
.text_style
= STYLE_DEFAULT
;
749 info
.text_style
= STYLE_GRADIENT
|CURLN_PACK(cur
+1)|NUMLN_PACK(num
);
752 info
.cur_align_start
= info
.buf
;
753 align
->left
= info
.buf
;
754 align
->center
= NULL
;
758 if (line
->type
== LINE_ALTERNATOR
)
759 func
= skin_render_alternator
;
760 else if (line
->type
== LINE
)
761 func
= skin_render_line
;
763 needs_update
= func(line
, &info
);
764 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
765 if (skin_viewport
->vp
.fg_pattern
!= skin_viewport
->start_fgcolour
||
766 skin_viewport
->vp
.bg_pattern
!= skin_viewport
->start_bgcolour
)
768 /* 2bit lcd drivers need lcd_set_viewport() to be called to change
769 * the colour, 16bit doesnt. But doing this makes static text
770 * get the new colour also */
772 display
->set_viewport(&skin_viewport
->vp
);
775 /* only update if the line needs to be, and there is something to write */
776 if (refresh_type
&& needs_update
)
778 if (!info
.force_redraw
)
779 display
->scroll_stop_line(&skin_viewport
->vp
, info
.line_number
);
780 write_line(display
, align
, info
.line_number
,
781 info
.line_scrolls
, info
.text_style
);
783 if (!info
.no_line_break
)
785 line
= SKINOFFSETTOPTR(skin_buffer
, line
->next
);
787 #ifdef HAVE_LCD_BITMAP
788 wps_display_images(gwps
, &skin_viewport
->vp
);
792 void skin_render(struct gui_wps
*gwps
, unsigned refresh_mode
)
794 struct wps_data
*data
= gwps
->data
;
795 struct screen
*display
= gwps
->display
;
797 struct skin_element
* viewport
;
798 struct skin_viewport
* skin_viewport
;
801 int old_refresh_mode
= refresh_mode
;
802 skin_buffer
= get_skin_buffer(gwps
->data
);
803 skinparser_set_buffer(skin_buffer
);
805 #ifdef HAVE_LCD_CHARCELLS
807 for (i
= 0; i
< 8; i
++)
809 if (data
->wps_progress_pat
[i
] == 0)
810 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
814 viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
815 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
816 label
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
817 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
818 label
= VP_DEFAULT_LABEL_STRING
;
819 if (label
&& SKINOFFSETTOPTR(skin_buffer
, viewport
->next
) &&
820 !strcmp(label
,VP_DEFAULT_LABEL_STRING
))
823 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
825 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
828 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
829 unsigned vp_refresh_mode
= refresh_mode
;
830 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
831 skin_viewport
->vp
.fg_pattern
= skin_viewport
->start_fgcolour
;
832 skin_viewport
->vp
.bg_pattern
= skin_viewport
->start_bgcolour
;
833 if (skin_viewport
->output_to_backdrop_buffer
)
835 display
->set_framebuffer(skin_backdrop_get_buffer(data
->backdrop_id
));
836 skin_backdrop_show(-1);
840 display
->set_framebuffer(NULL
);
841 skin_backdrop_show(data
->backdrop_id
);
844 #ifdef HAVE_LCD_COLOR
845 skin_viewport
->vp
.lss_pattern
= skin_viewport
->start_gradient
.start
;
846 skin_viewport
->vp
.lse_pattern
= skin_viewport
->start_gradient
.end
;
847 skin_viewport
->vp
.lst_pattern
= skin_viewport
->start_gradient
.text
;
850 /* dont redraw the viewport if its disabled */
851 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
852 { /* don't draw anything into this one */
855 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
857 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
860 else if (((skin_viewport
->hidden_flags
&
861 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
862 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
864 vp_refresh_mode
= SKIN_REFRESH_ALL
;
865 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
868 display
->set_viewport(&skin_viewport
->vp
);
869 if ((vp_refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
)
871 display
->clear_viewport();
874 if (viewport
->children_count
)
875 skin_render_viewport(get_child(viewport
->children
, 0), gwps
,
876 skin_viewport
, vp_refresh_mode
);
877 refresh_mode
= old_refresh_mode
;
879 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
880 display
->set_framebuffer(NULL
);
881 skin_backdrop_show(data
->backdrop_id
);
883 /* Restore the default viewport */
884 display
->set_viewport(NULL
);
888 #ifdef HAVE_LCD_BITMAP
889 static __attribute__((noinline
))
890 void skin_render_playlistviewer(struct playlistviewer
* viewer
,
891 struct gui_wps
*gwps
,
892 struct skin_viewport
* skin_viewport
,
893 unsigned long refresh_type
)
895 struct screen
*display
= gwps
->display
;
896 char linebuf
[MAX_LINE
];
897 skin_render_func func
= skin_render_line
;
898 struct skin_element
* line
;
899 struct skin_draw_info info
= {
902 .buf_size
= sizeof(linebuf
),
904 .no_line_break
= false,
905 .line_scrolls
= false,
906 .refresh_type
= refresh_type
,
907 .skin_vp
= skin_viewport
,
908 .offset
= viewer
->start_offset
,
909 .text_style
= STYLE_DEFAULT
912 struct align_pos
* align
= &info
.align
;
914 int cur_pos
, start_item
, max
;
915 int nb_lines
= viewport_get_nb_lines(SKINOFFSETTOPTR(skin_buffer
, viewer
->vp
));
917 if (get_current_activity() == ACTIVITY_FM
)
919 cur_pos
= radio_current_preset();
920 start_item
= cur_pos
+ viewer
->start_offset
;
921 max
= start_item
+radio_preset_count();
926 struct cuesheet
*cue
= skin_get_global_state()->id3
?
927 skin_get_global_state()->id3
->cuesheet
: NULL
;
928 cur_pos
= playlist_get_display_index();
929 max
= playlist_amount()+1;
931 max
+= cue
->track_count
;
932 start_item
= MAX(0, cur_pos
+ viewer
->start_offset
);
934 if (max
-start_item
> nb_lines
)
935 max
= start_item
+ nb_lines
;
937 line
= SKINOFFSETTOPTR(skin_buffer
, viewer
->line
);
938 while (start_item
< max
)
941 info
.no_line_break
= false;
942 info
.line_scrolls
= false;
943 info
.force_redraw
= false;
945 info
.cur_align_start
= info
.buf
;
946 align
->left
= info
.buf
;
947 align
->center
= NULL
;
951 if (line
->type
== LINE_ALTERNATOR
)
952 func
= skin_render_alternator
;
953 else if (line
->type
== LINE
)
954 func
= skin_render_line
;
956 needs_update
= func(line
, &info
);
958 /* only update if the line needs to be, and there is something to write */
959 if (refresh_type
&& needs_update
)
961 if (!info
.force_redraw
)
962 display
->scroll_stop_line(&skin_viewport
->vp
, info
.line_number
);
963 write_line(display
, align
, info
.line_number
,
964 info
.line_scrolls
, info
.text_style
);