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
:
169 skinlist_set_cfg(gwps
->display
->screen_type
,
170 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
));
172 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
173 sb_set_info_vp(gwps
->display
->screen_type
, token
->value
.data
);
175 case SKIN_TOKEN_PEAKMETER
:
176 data
->peak_meter_enabled
= true;
178 draw_peakmeters(gwps
, info
->line_number
, vp
);
181 #ifdef HAVE_LCD_BITMAP
182 case SKIN_TOKEN_PEAKMETER_LEFTBAR
:
183 case SKIN_TOKEN_PEAKMETER_RIGHTBAR
:
184 data
->peak_meter_enabled
= true;
185 /* fall through to the progressbar code */
187 case SKIN_TOKEN_VOLUMEBAR
:
188 case SKIN_TOKEN_BATTERY_PERCENTBAR
:
189 #ifdef HAVE_LCD_BITMAP
190 case SKIN_TOKEN_PROGRESSBAR
:
191 case SKIN_TOKEN_TUNER_RSSI_BAR
:
192 case SKIN_TOKEN_LIST_SCROLLBAR
:
194 struct progressbar
*bar
= (struct progressbar
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
196 draw_progressbar(gwps
, info
->line_number
, bar
);
200 #ifdef HAVE_LCD_BITMAP
201 case SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
:
202 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
204 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
205 const char* label
= SKINOFFSETTOPTR(skin_buffer
, id
->label
);
206 struct gui_img
*img
= skin_find_item(label
,SKIN_FIND_IMAGE
, data
);
207 if (img
&& img
->loaded
)
209 if (SKINOFFSETTOPTR(skin_buffer
, id
->token
) == NULL
)
211 img
->display
= id
->subimage
;
217 int a
= img
->num_subimages
;
218 out
= get_token_value(gwps
, SKINOFFSETTOPTR(skin_buffer
, id
->token
),
219 info
->offset
, buf
, sizeof(buf
), &a
);
221 /* NOTE: get_token_value() returns values starting at 1! */
223 a
= (out
&& *out
) ? 1 : 2;
224 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
)
225 a
-= 2; /* 2 is added in statusbar-skinned.c! */
230 /* Clear the image, as in conditionals */
231 clear_image_pos(gwps
, img
);
233 /* If the token returned a value which is higher than
234 * the amount of subimages, don't draw it. */
235 if (a
>= 0 && a
< img
->num_subimages
)
244 case SKIN_TOKEN_ALBUMART_DISPLAY
:
246 struct skin_albumart
*aa
= SKINOFFSETTOPTR(skin_buffer
, data
->albumart
);
247 /* now draw the AA */
248 if (do_refresh
&& aa
)
250 int handle
= playback_current_aa_hid(data
->playback_aa_slot
);
252 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
254 struct dim dim
= {aa
->width
, aa
->height
};
255 handle
= radio_get_art_hid(&dim
);
258 aa
->draw_handle
= handle
;
263 case SKIN_TOKEN_DRAW_INBUILTBAR
:
264 gui_statusbar_draw(&(statusbars
.statusbars
[gwps
->display
->screen_type
]),
265 info
->refresh_type
== SKIN_REFRESH_ALL
,
266 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
));
268 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
270 skin_render_playlistviewer(SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
), gwps
,
271 info
->skin_vp
, info
->refresh_type
);
274 #endif /* HAVE_LCD_BITMAP */
275 #ifdef HAVE_SKIN_VARIABLES
276 case SKIN_TOKEN_VAR_SET
:
279 struct skin_var_changer
*data
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
280 struct skin_var
*var
= SKINOFFSETTOPTR(skin_buffer
, data
->var
);
282 var
->value
= data
->newval
;
285 var
->value
+= data
->newval
;
288 if (var
->value
> data
->max
)
290 else if (var
->value
< 1)
291 var
->value
= data
->max
;
296 var
->last_changed
= current_tick
;
308 static void do_tags_in_hidden_conditional(struct skin_element
* branch
,
309 struct skin_draw_info
*info
)
311 #ifdef HAVE_LCD_BITMAP
312 struct gui_wps
*gwps
= info
->gwps
;
313 struct wps_data
*data
= gwps
->data
;
315 /* Tags here are ones which need to be "turned off" or cleared
316 * if they are in a conditional branch which isnt being used */
317 if (branch
->type
== LINE_ALTERNATOR
)
320 for (i
=0; i
<branch
->children_count
; i
++)
322 do_tags_in_hidden_conditional(get_child(branch
->children
, i
), info
);
325 else if (branch
->type
== LINE
&& branch
->children_count
)
327 struct skin_element
*child
= get_child(branch
->children
, 0);
328 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
329 struct wps_token
*token
;
333 if (child
->type
== CONDITIONAL
)
336 for (i
=0; i
<child
->children_count
; i
++)
338 do_tags_in_hidden_conditional(get_child(child
->children
, i
), info
);
340 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
343 else if (child
->type
!= TAG
|| !SKINOFFSETTOPTR(skin_buffer
, child
->data
))
345 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
348 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
349 token
= (struct wps_token
*)SKINOFFSETTOPTR(skin_buffer
, child
->data
);
351 #ifdef HAVE_LCD_BITMAP
352 /* clear all pictures in the conditional and nested ones */
353 if (token
->type
== SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
)
355 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
356 struct gui_img
*img
= skin_find_item(SKINOFFSETTOPTR(skin_buffer
, id
->label
),
357 SKIN_FIND_IMAGE
, data
);
358 clear_image_pos(gwps
, img
);
360 else if (token
->type
== SKIN_TOKEN_PEAKMETER
)
362 data
->peak_meter_enabled
= false;
364 else if (token
->type
== SKIN_TOKEN_VIEWPORT_ENABLE
)
366 char *label
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
367 struct skin_element
*viewport
;
368 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
370 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
372 struct skin_viewport
*skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
374 char *vplabel
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
375 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
376 vplabel
= VP_DEFAULT_LABEL_STRING
;
377 if (vplabel
&& strcmp(vplabel
, label
))
379 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
383 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
385 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
386 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
389 gwps
->display
->set_viewport(&skin_viewport
->vp
);
390 gwps
->display
->clear_viewport();
391 gwps
->display
->scroll_stop(&skin_viewport
->vp
);
392 gwps
->display
->set_viewport(&info
->skin_vp
->vp
);
393 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
400 else if (data
->albumart
&& token
->type
== SKIN_TOKEN_ALBUMART_DISPLAY
)
403 playback_current_aa_hid(data
->playback_aa_slot
), true);
406 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
411 static void fix_line_alignment(struct skin_draw_info
*info
, struct skin_element
*element
)
413 struct align_pos
*align
= &info
->align
;
414 char *cur_pos
= info
->cur_align_start
+ strlen(info
->cur_align_start
);
415 switch (element
->tag
->type
)
417 case SKIN_TOKEN_ALIGN_LEFT
:
418 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
419 align
->left
= cur_pos
;
420 info
->cur_align_start
= cur_pos
;
422 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
423 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
425 align
->right
= cur_pos
;
427 align
->left
= cur_pos
;
428 info
->cur_align_start
= cur_pos
;
430 case SKIN_TOKEN_ALIGN_CENTER
:
431 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
432 align
->center
= cur_pos
;
433 info
->cur_align_start
= cur_pos
;
435 case SKIN_TOKEN_ALIGN_RIGHT
:
436 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
437 align
->right
= cur_pos
;
438 info
->cur_align_start
= cur_pos
;
440 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
441 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
443 align
->left
= cur_pos
;
445 align
->right
= cur_pos
;
446 info
->cur_align_start
= cur_pos
;
453 /* Draw a LINE element onto the display */
454 static bool skin_render_line(struct skin_element
* line
, struct skin_draw_info
*info
)
456 bool needs_update
= false;
457 int last_value
, value
;
459 if (line
->children_count
== 0)
460 return false; /* empty line, do nothing */
462 struct skin_element
*child
= get_child(line
->children
, 0);
463 struct conditional
*conditional
;
464 skin_render_func func
= skin_render_line
;
465 int old_refresh_mode
= info
->refresh_type
;
471 conditional
= SKINOFFSETTOPTR(skin_buffer
, child
->data
);
472 last_value
= conditional
->last_value
;
473 value
= evaluate_conditional(info
->gwps
, info
->offset
,
474 conditional
, child
->children_count
);
475 conditional
->last_value
= value
;
476 if (child
->children_count
== 1)
478 /* special handling so
479 * %?aa<true> and %?<true|false> need special handlng here */
481 if (value
== -1) /* tag is false */
483 /* we are in a false branch of a %?aa<true> conditional */
485 do_tags_in_hidden_conditional(get_child(child
->children
, 0), info
);
491 if (last_value
>= 0 && value
!= last_value
&& last_value
< child
->children_count
)
492 do_tags_in_hidden_conditional(get_child(child
->children
, last_value
), info
);
494 if (get_child(child
->children
, value
)->type
== LINE_ALTERNATOR
)
496 func
= skin_render_alternator
;
498 else if (get_child(child
->children
, value
)->type
== LINE
)
499 func
= skin_render_line
;
501 if (value
!= last_value
)
503 info
->refresh_type
= SKIN_REFRESH_ALL
;
504 info
->force_redraw
= true;
507 if (func(get_child(child
->children
, value
), info
))
510 needs_update
= needs_update
|| (last_value
!= value
);
512 info
->refresh_type
= old_refresh_mode
;
515 if (child
->tag
->flags
& NOBREAK
)
516 info
->no_line_break
= true;
517 if (child
->tag
->type
== SKIN_TOKEN_SUBLINE_SCROLL
)
518 info
->line_scrolls
= true;
520 fix_line_alignment(info
, child
);
522 if (!SKINOFFSETTOPTR(skin_buffer
, child
->data
))
526 if (!do_non_text_tags(info
->gwps
, info
, child
, &info
->skin_vp
->vp
))
528 static char tempbuf
[128];
529 const char *valuestr
= get_token_value(info
->gwps
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
530 info
->offset
, tempbuf
,
531 sizeof(tempbuf
), NULL
);
535 if (child
->tag
->flags
&SKIN_RTC_REFRESH
)
536 needs_update
= needs_update
|| info
->refresh_type
&SKIN_REFRESH_DYNAMIC
;
538 needs_update
= needs_update
||
539 ((child
->tag
->flags
&info
->refresh_type
)!=0);
540 strlcat(info
->cur_align_start
, valuestr
,
541 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
546 strlcat(info
->cur_align_start
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
547 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
548 needs_update
= needs_update
||
549 (info
->refresh_type
&SKIN_REFRESH_STATIC
) != 0;
556 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
561 static int get_subline_timeout(struct gui_wps
*gwps
, struct skin_element
* line
)
563 struct skin_element
*element
=line
;
564 struct wps_token
*token
;
565 int retval
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
566 if (element
->type
== LINE
)
568 if (element
->children_count
== 0)
569 return retval
; /* empty line, so force redraw */
570 element
= get_child(element
->children
, 0);
574 if (element
->type
== TAG
&&
575 element
->tag
->type
== SKIN_TOKEN_SUBLINE_TIMEOUT
)
577 token
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
578 return token
->value
.i
;
580 else if (element
->type
== CONDITIONAL
)
582 struct conditional
*conditional
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
583 int val
= evaluate_conditional(gwps
, 0, conditional
,
584 element
->children_count
);
587 retval
= get_subline_timeout(gwps
, get_child(element
->children
, val
));
592 element
= SKINOFFSETTOPTR(skin_buffer
, element
->next
);
597 bool skin_render_alternator(struct skin_element
* element
, struct skin_draw_info
*info
)
599 bool changed_lines
= false;
600 struct line_alternator
*alternator
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
601 unsigned old_refresh
= info
->refresh_type
;
602 if (info
->refresh_type
== SKIN_REFRESH_ALL
)
604 alternator
->current_line
= element
->children_count
-1;
605 changed_lines
= true;
607 else if (TIME_AFTER(current_tick
, alternator
->next_change_tick
))
609 changed_lines
= true;
614 struct skin_element
*current_line
;
615 int start
= alternator
->current_line
;
616 int try_line
= start
;
617 bool suitable
= false;
618 int rettimeout
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
620 /* find a subline which has at least one token in it,
621 * and that line doesnt have a timeout set to 0 through conditionals */
624 if (try_line
>= element
->children_count
)
626 if (get_child(element
->children
, try_line
)->children_count
!= 0)
628 current_line
= get_child(element
->children
, try_line
);
629 rettimeout
= get_subline_timeout(info
->gwps
,
630 get_child(current_line
->children
, 0));
637 while (try_line
!= start
&& !suitable
);
641 alternator
->current_line
= try_line
;
642 alternator
->next_change_tick
= current_tick
+ rettimeout
;
645 info
->refresh_type
= SKIN_REFRESH_ALL
;
646 info
->force_redraw
= true;
648 bool ret
= skin_render_line(get_child(element
->children
, alternator
->current_line
), info
);
649 info
->refresh_type
= old_refresh
;
650 return changed_lines
|| ret
;
653 void skin_render_viewport(struct skin_element
* viewport
, struct gui_wps
*gwps
,
654 struct skin_viewport
* skin_viewport
, unsigned long refresh_type
)
656 struct screen
*display
= gwps
->display
;
657 char linebuf
[MAX_LINE
];
658 skin_render_func func
= skin_render_line
;
659 struct skin_element
* line
= viewport
;
660 struct skin_draw_info info
= {
663 .buf_size
= sizeof(linebuf
),
665 .no_line_break
= false,
666 .line_scrolls
= false,
667 .refresh_type
= refresh_type
,
668 .skin_vp
= skin_viewport
,
670 .text_style
= STYLE_DEFAULT
673 struct align_pos
* align
= &info
.align
;
675 skin_buffer
= get_skin_buffer(gwps
->data
);
676 skinparser_set_buffer(skin_buffer
);
677 #ifdef HAVE_LCD_BITMAP
678 /* Set images to not to be displayed */
679 struct skin_token_list
*imglist
= SKINOFFSETTOPTR(skin_buffer
, gwps
->data
->images
);
682 struct wps_token
*token
= SKINOFFSETTOPTR(skin_buffer
, imglist
->token
);
683 struct gui_img
*img
= (struct gui_img
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
685 imglist
= SKINOFFSETTOPTR(skin_buffer
, imglist
->next
);
689 if (skin_viewport
->parsed_fontid
== 1)
690 skin_viewport
->vp
.font
= display
->getuifont();
696 info
.no_line_break
= false;
697 info
.line_scrolls
= false;
698 info
.force_redraw
= false;
699 #ifdef HAVE_LCD_COLOR
700 if (info
.text_style
&STYLE_GRADIENT
)
702 int cur
= CURLN_UNPACK(info
.text_style
);
703 int num
= NUMLN_UNPACK(info
.text_style
);
705 info
.text_style
= STYLE_DEFAULT
;
707 info
.text_style
= STYLE_GRADIENT
|CURLN_PACK(cur
+1)|NUMLN_PACK(num
);
710 info
.cur_align_start
= info
.buf
;
711 align
->left
= info
.buf
;
712 align
->center
= NULL
;
716 if (line
->type
== LINE_ALTERNATOR
)
717 func
= skin_render_alternator
;
718 else if (line
->type
== LINE
)
719 func
= skin_render_line
;
721 needs_update
= func(line
, &info
);
722 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
723 if (skin_viewport
->vp
.fg_pattern
!= skin_viewport
->start_fgcolour
||
724 skin_viewport
->vp
.bg_pattern
!= skin_viewport
->start_bgcolour
)
726 /* 2bit lcd drivers need lcd_set_viewport() to be called to change
727 * the colour, 16bit doesnt. But doing this makes static text
728 * get the new colour also */
730 display
->set_viewport(&skin_viewport
->vp
);
733 /* only update if the line needs to be, and there is something to write */
734 if (refresh_type
&& needs_update
)
736 if (info
.line_scrolls
)
738 /* if the line is a scrolling one we don't want to update
739 too often, so that it has the time to scroll */
740 if ((refresh_type
& SKIN_REFRESH_SCROLL
) || info
.force_redraw
)
741 write_line(display
, align
, info
.line_number
, true, info
.text_style
);
744 write_line(display
, align
, info
.line_number
, false, info
.text_style
);
746 if (!info
.no_line_break
)
748 line
= SKINOFFSETTOPTR(skin_buffer
, line
->next
);
750 #ifdef HAVE_LCD_BITMAP
751 wps_display_images(gwps
, &skin_viewport
->vp
);
755 void skin_render(struct gui_wps
*gwps
, unsigned refresh_mode
)
757 struct wps_data
*data
= gwps
->data
;
758 struct screen
*display
= gwps
->display
;
760 struct skin_element
* viewport
;
761 struct skin_viewport
* skin_viewport
;
764 int old_refresh_mode
= refresh_mode
;
765 skin_buffer
= get_skin_buffer(gwps
->data
);
766 skinparser_set_buffer(skin_buffer
);
768 #ifdef HAVE_LCD_CHARCELLS
770 for (i
= 0; i
< 8; i
++)
772 if (data
->wps_progress_pat
[i
] == 0)
773 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
776 viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
777 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
778 label
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
779 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
780 label
= VP_DEFAULT_LABEL_STRING
;
781 if (label
&& SKINOFFSETTOPTR(skin_buffer
, viewport
->next
) &&
782 !strcmp(label
,VP_DEFAULT_LABEL_STRING
))
785 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
787 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
790 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
791 unsigned vp_refresh_mode
= refresh_mode
;
792 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
793 skin_viewport
->vp
.fg_pattern
= skin_viewport
->start_fgcolour
;
794 skin_viewport
->vp
.bg_pattern
= skin_viewport
->start_bgcolour
;
796 #ifdef HAVE_LCD_COLOR
797 skin_viewport
->vp
.lss_pattern
= skin_viewport
->start_gradient
.start
;
798 skin_viewport
->vp
.lse_pattern
= skin_viewport
->start_gradient
.end
;
799 skin_viewport
->vp
.lst_pattern
= skin_viewport
->start_gradient
.text
;
802 /* dont redraw the viewport if its disabled */
803 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
804 { /* don't draw anything into this one */
807 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
809 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
812 else if (((skin_viewport
->hidden_flags
&
813 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
814 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
816 vp_refresh_mode
= SKIN_REFRESH_ALL
;
817 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
820 display
->set_viewport(&skin_viewport
->vp
);
821 if ((vp_refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
)
823 display
->clear_viewport();
826 if (viewport
->children_count
)
827 skin_render_viewport(get_child(viewport
->children
, 0), gwps
,
828 skin_viewport
, vp_refresh_mode
);
829 refresh_mode
= old_refresh_mode
;
832 /* Restore the default viewport */
833 display
->set_viewport(NULL
);
837 #ifdef HAVE_LCD_BITMAP
838 static __attribute__((noinline
))
839 void skin_render_playlistviewer(struct playlistviewer
* viewer
,
840 struct gui_wps
*gwps
,
841 struct skin_viewport
* skin_viewport
,
842 unsigned long refresh_type
)
844 struct screen
*display
= gwps
->display
;
845 char linebuf
[MAX_LINE
];
846 skin_render_func func
= skin_render_line
;
847 struct skin_element
* line
;
848 struct skin_draw_info info
= {
851 .buf_size
= sizeof(linebuf
),
853 .no_line_break
= false,
854 .line_scrolls
= false,
855 .refresh_type
= refresh_type
,
856 .skin_vp
= skin_viewport
,
857 .offset
= viewer
->start_offset
,
858 .text_style
= STYLE_DEFAULT
861 struct align_pos
* align
= &info
.align
;
863 int cur_pos
, start_item
, max
;
864 int nb_lines
= viewport_get_nb_lines(SKINOFFSETTOPTR(skin_buffer
, viewer
->vp
));
866 if (get_current_activity() == ACTIVITY_FM
)
868 cur_pos
= radio_current_preset();
869 start_item
= cur_pos
+ viewer
->start_offset
;
870 max
= start_item
+radio_preset_count();
875 struct cuesheet
*cue
= skin_get_global_state()->id3
?
876 skin_get_global_state()->id3
->cuesheet
: NULL
;
877 cur_pos
= playlist_get_display_index();
878 max
= playlist_amount()+1;
880 max
+= cue
->track_count
;
881 start_item
= MAX(0, cur_pos
+ viewer
->start_offset
);
883 if (max
-start_item
> nb_lines
)
884 max
= start_item
+ nb_lines
;
886 line
= SKINOFFSETTOPTR(skin_buffer
, viewer
->line
);
887 while (start_item
< max
)
890 info
.no_line_break
= false;
891 info
.line_scrolls
= false;
892 info
.force_redraw
= false;
894 info
.cur_align_start
= info
.buf
;
895 align
->left
= info
.buf
;
896 align
->center
= NULL
;
900 if (line
->type
== LINE_ALTERNATOR
)
901 func
= skin_render_alternator
;
902 else if (line
->type
== LINE
)
903 func
= skin_render_line
;
905 needs_update
= func(line
, &info
);
907 /* only update if the line needs to be, and there is something to write */
908 if (refresh_type
&& needs_update
)
910 if (info
.line_scrolls
)
912 /* if the line is a scrolling one we don't want to update
913 too often, so that it has the time to scroll */
914 if ((refresh_type
& SKIN_REFRESH_SCROLL
) || info
.force_redraw
)
915 write_line(display
, align
, info
.line_number
, true, info
.text_style
);
918 write_line(display
, align
, info
.line_number
, false, info
.text_style
);