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
);
195 unsigned backup
= vp
->fg_pattern
;
196 vp
->fg_pattern
= rect
->start_colour
;
198 gwps
->display
->fillrect(rect
->x
, rect
->y
, rect
->width
,
201 vp
->fg_pattern
= backup
;
206 case SKIN_TOKEN_PEAKMETER_LEFTBAR
:
207 case SKIN_TOKEN_PEAKMETER_RIGHTBAR
:
208 data
->peak_meter_enabled
= true;
209 /* fall through to the progressbar code */
211 case SKIN_TOKEN_VOLUMEBAR
:
212 case SKIN_TOKEN_BATTERY_PERCENTBAR
:
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
:
235 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
236 const char* label
= SKINOFFSETTOPTR(skin_buffer
, id
->label
);
237 struct gui_img
*img
= skin_find_item(label
,SKIN_FIND_IMAGE
, data
);
238 if (img
&& img
->loaded
)
240 if (SKINOFFSETTOPTR(skin_buffer
, id
->token
) == NULL
)
242 img
->display
= id
->subimage
;
248 int a
= img
->num_subimages
;
249 out
= get_token_value(gwps
, SKINOFFSETTOPTR(skin_buffer
, id
->token
),
250 info
->offset
, buf
, sizeof(buf
), &a
);
252 /* NOTE: get_token_value() returns values starting at 1! */
254 a
= (out
&& *out
) ? 1 : 2;
255 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
)
256 a
-= 2; /* 2 is added in statusbar-skinned.c! */
261 /* Clear the image, as in conditionals */
262 clear_image_pos(gwps
, img
);
264 /* If the token returned a value which is higher than
265 * the amount of subimages, don't draw it. */
266 if (a
>= 0 && a
< img
->num_subimages
)
275 case SKIN_TOKEN_ALBUMART_DISPLAY
:
277 struct skin_albumart
*aa
= SKINOFFSETTOPTR(skin_buffer
, data
->albumart
);
278 /* now draw the AA */
279 if (do_refresh
&& aa
)
281 int handle
= playback_current_aa_hid(data
->playback_aa_slot
);
283 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
285 struct dim dim
= {aa
->width
, aa
->height
};
286 handle
= radio_get_art_hid(&dim
);
289 aa
->draw_handle
= handle
;
294 case SKIN_TOKEN_DRAW_INBUILTBAR
:
295 gui_statusbar_draw(&(statusbars
.statusbars
[gwps
->display
->screen_type
]),
296 info
->refresh_type
== SKIN_REFRESH_ALL
,
297 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
));
299 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
301 skin_render_playlistviewer(SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
), gwps
,
302 info
->skin_vp
, info
->refresh_type
);
305 #endif /* HAVE_LCD_BITMAP */
306 #ifdef HAVE_SKIN_VARIABLES
307 case SKIN_TOKEN_VAR_SET
:
309 struct skin_var_changer
*data
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
310 struct skin_var
*var
= SKINOFFSETTOPTR(skin_buffer
, data
->var
);
312 var
->value
= data
->newval
;
315 var
->value
+= data
->newval
;
318 if (var
->value
> data
->max
)
320 else if (var
->value
< 1)
321 var
->value
= data
->max
;
326 var
->last_changed
= current_tick
;
338 static void do_tags_in_hidden_conditional(struct skin_element
* branch
,
339 struct skin_draw_info
*info
)
341 #ifdef HAVE_LCD_BITMAP
342 struct gui_wps
*gwps
= info
->gwps
;
343 struct wps_data
*data
= gwps
->data
;
345 /* Tags here are ones which need to be "turned off" or cleared
346 * if they are in a conditional branch which isnt being used */
347 if (branch
->type
== LINE_ALTERNATOR
)
350 for (i
=0; i
<branch
->children_count
; i
++)
352 do_tags_in_hidden_conditional(get_child(branch
->children
, i
), info
);
355 else if (branch
->type
== LINE
&& branch
->children_count
)
357 struct skin_element
*child
= get_child(branch
->children
, 0);
358 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
359 struct wps_token
*token
;
363 if (child
->type
== CONDITIONAL
)
366 for (i
=0; i
<child
->children_count
; i
++)
368 do_tags_in_hidden_conditional(get_child(child
->children
, i
), info
);
370 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
373 else if (child
->type
!= TAG
|| !SKINOFFSETTOPTR(skin_buffer
, child
->data
))
375 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
378 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
379 token
= (struct wps_token
*)SKINOFFSETTOPTR(skin_buffer
, child
->data
);
381 #ifdef HAVE_LCD_BITMAP
382 /* clear all pictures in the conditional and nested ones */
383 if (token
->type
== SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
)
385 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
386 struct gui_img
*img
= skin_find_item(SKINOFFSETTOPTR(skin_buffer
, id
->label
),
387 SKIN_FIND_IMAGE
, data
);
388 clear_image_pos(gwps
, img
);
390 else if (token
->type
== SKIN_TOKEN_PEAKMETER
)
392 data
->peak_meter_enabled
= false;
394 else if (token
->type
== SKIN_TOKEN_VIEWPORT_ENABLE
)
396 char *label
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
397 struct skin_element
*viewport
;
398 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
400 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
402 struct skin_viewport
*skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
404 char *vplabel
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
405 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
406 vplabel
= VP_DEFAULT_LABEL_STRING
;
407 if (vplabel
&& strcmp(vplabel
, label
))
409 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
413 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
415 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
416 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
419 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
420 if (skin_viewport
->output_to_backdrop_buffer
)
422 void *backdrop
= skin_backdrop_get_buffer(data
->backdrop_id
);
423 gwps
->display
->set_framebuffer(backdrop
);
424 skin_backdrop_show(-1);
427 gwps
->display
->set_viewport(&skin_viewport
->vp
);
428 gwps
->display
->clear_viewport();
429 gwps
->display
->scroll_stop(&skin_viewport
->vp
);
430 gwps
->display
->set_viewport(&info
->skin_vp
->vp
);
431 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
433 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
434 if (skin_viewport
->output_to_backdrop_buffer
)
436 gwps
->display
->set_framebuffer(NULL
);
437 skin_backdrop_show(data
->backdrop_id
);
446 else if (data
->albumart
&& token
->type
== SKIN_TOKEN_ALBUMART_DISPLAY
)
449 playback_current_aa_hid(data
->playback_aa_slot
), true);
452 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
457 static void fix_line_alignment(struct skin_draw_info
*info
, struct skin_element
*element
)
459 struct align_pos
*align
= &info
->align
;
460 char *cur_pos
= info
->cur_align_start
+ strlen(info
->cur_align_start
);
461 switch (element
->tag
->type
)
463 case SKIN_TOKEN_ALIGN_LEFT
:
464 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
465 align
->left
= cur_pos
;
466 info
->cur_align_start
= cur_pos
;
468 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
469 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
471 align
->right
= cur_pos
;
473 align
->left
= cur_pos
;
474 info
->cur_align_start
= cur_pos
;
476 case SKIN_TOKEN_ALIGN_CENTER
:
477 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
478 align
->center
= cur_pos
;
479 info
->cur_align_start
= cur_pos
;
481 case SKIN_TOKEN_ALIGN_RIGHT
:
482 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
483 align
->right
= cur_pos
;
484 info
->cur_align_start
= cur_pos
;
486 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
487 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
489 align
->left
= cur_pos
;
491 align
->right
= cur_pos
;
492 info
->cur_align_start
= cur_pos
;
499 /* Draw a LINE element onto the display */
500 static bool skin_render_line(struct skin_element
* line
, struct skin_draw_info
*info
)
502 bool needs_update
= false;
503 int last_value
, value
;
505 if (line
->children_count
== 0)
506 return false; /* empty line, do nothing */
508 struct skin_element
*child
= get_child(line
->children
, 0);
509 struct conditional
*conditional
;
510 skin_render_func func
= skin_render_line
;
511 int old_refresh_mode
= info
->refresh_type
;
517 conditional
= SKINOFFSETTOPTR(skin_buffer
, child
->data
);
518 last_value
= conditional
->last_value
;
519 value
= evaluate_conditional(info
->gwps
, info
->offset
,
520 conditional
, child
->children_count
);
521 conditional
->last_value
= value
;
522 if (child
->children_count
== 1)
524 /* special handling so
525 * %?aa<true> and %?<true|false> need special handlng here */
527 if (value
== -1) /* tag is false */
529 /* we are in a false branch of a %?aa<true> conditional */
531 do_tags_in_hidden_conditional(get_child(child
->children
, 0), info
);
537 if (last_value
>= 0 && value
!= last_value
&& last_value
< child
->children_count
)
538 do_tags_in_hidden_conditional(get_child(child
->children
, last_value
), info
);
540 if (get_child(child
->children
, value
)->type
== LINE_ALTERNATOR
)
542 func
= skin_render_alternator
;
544 else if (get_child(child
->children
, value
)->type
== LINE
)
545 func
= skin_render_line
;
547 if (value
!= last_value
)
549 info
->refresh_type
= SKIN_REFRESH_ALL
;
550 info
->force_redraw
= true;
553 if (func(get_child(child
->children
, value
), info
))
556 needs_update
= needs_update
|| (last_value
!= value
);
558 info
->refresh_type
= old_refresh_mode
;
561 if (child
->tag
->flags
& NOBREAK
)
562 info
->no_line_break
= true;
563 if (child
->tag
->type
== SKIN_TOKEN_SUBLINE_SCROLL
)
564 info
->line_scrolls
= true;
566 fix_line_alignment(info
, child
);
568 if (!SKINOFFSETTOPTR(skin_buffer
, child
->data
))
572 if (!do_non_text_tags(info
->gwps
, info
, child
, &info
->skin_vp
->vp
))
574 static char tempbuf
[128];
575 const char *valuestr
= get_token_value(info
->gwps
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
576 info
->offset
, tempbuf
,
577 sizeof(tempbuf
), NULL
);
581 if (child
->tag
->flags
&SKIN_RTC_REFRESH
)
582 needs_update
= needs_update
|| info
->refresh_type
&SKIN_REFRESH_DYNAMIC
;
584 needs_update
= needs_update
||
585 ((child
->tag
->flags
&info
->refresh_type
)!=0);
586 strlcat(info
->cur_align_start
, valuestr
,
587 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
592 strlcat(info
->cur_align_start
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
593 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
594 needs_update
= needs_update
||
595 (info
->refresh_type
&SKIN_REFRESH_STATIC
) != 0;
602 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
607 static int get_subline_timeout(struct gui_wps
*gwps
, struct skin_element
* line
)
609 struct skin_element
*element
=line
;
610 struct wps_token
*token
;
611 int retval
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
612 if (element
->type
== LINE
)
614 if (element
->children_count
== 0)
615 return retval
; /* empty line, so force redraw */
616 element
= get_child(element
->children
, 0);
620 if (element
->type
== TAG
&&
621 element
->tag
->type
== SKIN_TOKEN_SUBLINE_TIMEOUT
)
623 token
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
624 return token
->value
.i
;
626 else if (element
->type
== CONDITIONAL
)
628 struct conditional
*conditional
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
629 int val
= evaluate_conditional(gwps
, 0, conditional
,
630 element
->children_count
);
633 retval
= get_subline_timeout(gwps
, get_child(element
->children
, val
));
638 element
= SKINOFFSETTOPTR(skin_buffer
, element
->next
);
643 bool skin_render_alternator(struct skin_element
* element
, struct skin_draw_info
*info
)
645 bool changed_lines
= false;
646 struct line_alternator
*alternator
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
647 unsigned old_refresh
= info
->refresh_type
;
648 if (info
->refresh_type
== SKIN_REFRESH_ALL
)
650 alternator
->current_line
= element
->children_count
-1;
651 changed_lines
= true;
653 else if (TIME_AFTER(current_tick
, alternator
->next_change_tick
))
655 changed_lines
= true;
660 struct skin_element
*current_line
;
661 int start
= alternator
->current_line
;
662 int try_line
= start
;
663 bool suitable
= false;
664 int rettimeout
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
666 /* find a subline which has at least one token in it,
667 * and that line doesnt have a timeout set to 0 through conditionals */
670 if (try_line
>= element
->children_count
)
672 if (get_child(element
->children
, try_line
)->children_count
!= 0)
674 current_line
= get_child(element
->children
, try_line
);
675 rettimeout
= get_subline_timeout(info
->gwps
,
676 get_child(current_line
->children
, 0));
683 while (try_line
!= start
&& !suitable
);
687 alternator
->current_line
= try_line
;
688 alternator
->next_change_tick
= current_tick
+ rettimeout
;
691 info
->refresh_type
= SKIN_REFRESH_ALL
;
692 info
->force_redraw
= true;
694 bool ret
= skin_render_line(get_child(element
->children
, alternator
->current_line
), info
);
695 info
->refresh_type
= old_refresh
;
696 return changed_lines
|| ret
;
699 void skin_render_viewport(struct skin_element
* viewport
, struct gui_wps
*gwps
,
700 struct skin_viewport
* skin_viewport
, unsigned long refresh_type
)
702 struct screen
*display
= gwps
->display
;
703 char linebuf
[MAX_LINE
];
704 skin_render_func func
= skin_render_line
;
705 struct skin_element
* line
= viewport
;
706 struct skin_draw_info info
= {
709 .buf_size
= sizeof(linebuf
),
711 .no_line_break
= false,
712 .line_scrolls
= false,
713 .refresh_type
= refresh_type
,
714 .skin_vp
= skin_viewport
,
716 .text_style
= STYLE_DEFAULT
719 struct align_pos
* align
= &info
.align
;
721 skin_buffer
= get_skin_buffer(gwps
->data
);
722 skinparser_set_buffer(skin_buffer
);
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
);
807 skinparser_set_buffer(skin_buffer
);
809 #ifdef HAVE_LCD_CHARCELLS
811 for (i
= 0; i
< 8; i
++)
813 if (data
->wps_progress_pat
[i
] == 0)
814 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
818 viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
819 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
820 label
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
821 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
822 label
= VP_DEFAULT_LABEL_STRING
;
823 if (label
&& SKINOFFSETTOPTR(skin_buffer
, viewport
->next
) &&
824 !strcmp(label
,VP_DEFAULT_LABEL_STRING
))
827 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
829 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
832 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
833 unsigned vp_refresh_mode
= refresh_mode
;
834 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
835 skin_viewport
->vp
.fg_pattern
= skin_viewport
->start_fgcolour
;
836 skin_viewport
->vp
.bg_pattern
= skin_viewport
->start_bgcolour
;
837 if (skin_viewport
->output_to_backdrop_buffer
)
839 display
->set_framebuffer(skin_backdrop_get_buffer(data
->backdrop_id
));
840 skin_backdrop_show(-1);
844 display
->set_framebuffer(NULL
);
845 skin_backdrop_show(data
->backdrop_id
);
848 #ifdef HAVE_LCD_COLOR
849 skin_viewport
->vp
.lss_pattern
= skin_viewport
->start_gradient
.start
;
850 skin_viewport
->vp
.lse_pattern
= skin_viewport
->start_gradient
.end
;
851 skin_viewport
->vp
.lst_pattern
= skin_viewport
->start_gradient
.text
;
854 /* dont redraw the viewport if its disabled */
855 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
856 { /* don't draw anything into this one */
859 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
861 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
864 else if (((skin_viewport
->hidden_flags
&
865 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
866 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
868 vp_refresh_mode
= SKIN_REFRESH_ALL
;
869 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
872 display
->set_viewport(&skin_viewport
->vp
);
873 if ((vp_refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
)
875 display
->clear_viewport();
878 if (viewport
->children_count
)
879 skin_render_viewport(get_child(viewport
->children
, 0), gwps
,
880 skin_viewport
, vp_refresh_mode
);
881 refresh_mode
= old_refresh_mode
;
883 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
884 display
->set_framebuffer(NULL
);
885 skin_backdrop_show(data
->backdrop_id
);
887 /* Restore the default viewport */
888 display
->set_viewport(NULL
);
892 #ifdef HAVE_LCD_BITMAP
893 static __attribute__((noinline
))
894 void skin_render_playlistviewer(struct playlistviewer
* viewer
,
895 struct gui_wps
*gwps
,
896 struct skin_viewport
* skin_viewport
,
897 unsigned long refresh_type
)
899 struct screen
*display
= gwps
->display
;
900 char linebuf
[MAX_LINE
];
901 skin_render_func func
= skin_render_line
;
902 struct skin_element
* line
;
903 struct skin_draw_info info
= {
906 .buf_size
= sizeof(linebuf
),
908 .no_line_break
= false,
909 .line_scrolls
= false,
910 .refresh_type
= refresh_type
,
911 .skin_vp
= skin_viewport
,
912 .offset
= viewer
->start_offset
,
913 .text_style
= STYLE_DEFAULT
916 struct align_pos
* align
= &info
.align
;
918 int cur_pos
, start_item
, max
;
919 int nb_lines
= viewport_get_nb_lines(SKINOFFSETTOPTR(skin_buffer
, viewer
->vp
));
921 if (get_current_activity() == ACTIVITY_FM
)
923 cur_pos
= radio_current_preset();
924 start_item
= cur_pos
+ viewer
->start_offset
;
925 max
= start_item
+radio_preset_count();
930 struct cuesheet
*cue
= skin_get_global_state()->id3
?
931 skin_get_global_state()->id3
->cuesheet
: NULL
;
932 cur_pos
= playlist_get_display_index();
933 max
= playlist_amount()+1;
935 max
+= cue
->track_count
;
936 start_item
= MAX(0, cur_pos
+ viewer
->start_offset
);
938 if (max
-start_item
> nb_lines
)
939 max
= start_item
+ nb_lines
;
941 line
= SKINOFFSETTOPTR(skin_buffer
, viewer
->line
);
942 while (start_item
< max
)
945 info
.no_line_break
= false;
946 info
.line_scrolls
= false;
947 info
.force_redraw
= false;
949 info
.cur_align_start
= info
.buf
;
950 align
->left
= info
.buf
;
951 align
->center
= NULL
;
955 if (line
->type
== LINE_ALTERNATOR
)
956 func
= skin_render_alternator
;
957 else if (line
->type
== LINE
)
958 func
= skin_render_line
;
960 needs_update
= func(line
, &info
);
962 /* only update if the line needs to be, and there is something to write */
963 if (refresh_type
&& needs_update
)
965 if (!info
.force_redraw
)
966 display
->scroll_stop_line(&skin_viewport
->vp
, info
.line_number
);
967 write_line(display
, align
, info
.line_number
,
968 info
.line_scrolls
, info
.text_style
);