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 #ifdef HAVE_LCD_BITMAP
213 case SKIN_TOKEN_PROGRESSBAR
:
214 case SKIN_TOKEN_TUNER_RSSI_BAR
:
215 case SKIN_TOKEN_LIST_SCROLLBAR
:
217 struct progressbar
*bar
= (struct progressbar
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
219 draw_progressbar(gwps
, info
->line_number
, bar
);
223 #ifdef HAVE_LCD_BITMAP
224 case SKIN_TOKEN_IMAGE_DISPLAY
:
226 struct gui_img
*img
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
227 if (img
&& img
->loaded
&& do_refresh
)
231 case SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
:
232 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
234 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
235 const char* label
= SKINOFFSETTOPTR(skin_buffer
, id
->label
);
236 struct gui_img
*img
= skin_find_item(label
,SKIN_FIND_IMAGE
, data
);
237 if (img
&& img
->loaded
)
239 if (SKINOFFSETTOPTR(skin_buffer
, id
->token
) == NULL
)
241 img
->display
= id
->subimage
;
247 int a
= img
->num_subimages
;
248 out
= get_token_value(gwps
, SKINOFFSETTOPTR(skin_buffer
, id
->token
),
249 info
->offset
, buf
, sizeof(buf
), &a
);
251 /* NOTE: get_token_value() returns values starting at 1! */
253 a
= (out
&& *out
) ? 1 : 2;
254 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
)
255 a
-= 2; /* 2 is added in statusbar-skinned.c! */
260 /* Clear the image, as in conditionals */
261 clear_image_pos(gwps
, img
);
263 /* If the token returned a value which is higher than
264 * the amount of subimages, don't draw it. */
265 if (a
>= 0 && a
< img
->num_subimages
)
274 case SKIN_TOKEN_ALBUMART_DISPLAY
:
276 struct skin_albumart
*aa
= SKINOFFSETTOPTR(skin_buffer
, data
->albumart
);
277 /* now draw the AA */
278 if (do_refresh
&& aa
)
280 int handle
= playback_current_aa_hid(data
->playback_aa_slot
);
282 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
284 struct dim dim
= {aa
->width
, aa
->height
};
285 handle
= radio_get_art_hid(&dim
);
288 aa
->draw_handle
= handle
;
293 case SKIN_TOKEN_DRAW_INBUILTBAR
:
294 gui_statusbar_draw(&(statusbars
.statusbars
[gwps
->display
->screen_type
]),
295 info
->refresh_type
== SKIN_REFRESH_ALL
,
296 SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
));
298 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
300 skin_render_playlistviewer(SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
), gwps
,
301 info
->skin_vp
, info
->refresh_type
);
304 #endif /* HAVE_LCD_BITMAP */
305 #ifdef HAVE_SKIN_VARIABLES
306 case SKIN_TOKEN_VAR_SET
:
308 struct skin_var_changer
*data
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
309 struct skin_var
*var
= SKINOFFSETTOPTR(skin_buffer
, data
->var
);
311 var
->value
= data
->newval
;
314 var
->value
+= data
->newval
;
317 if (var
->value
> data
->max
)
319 else if (var
->value
< 1)
320 var
->value
= data
->max
;
325 var
->last_changed
= current_tick
;
337 static void do_tags_in_hidden_conditional(struct skin_element
* branch
,
338 struct skin_draw_info
*info
)
340 #ifdef HAVE_LCD_BITMAP
341 struct gui_wps
*gwps
= info
->gwps
;
342 struct wps_data
*data
= gwps
->data
;
344 /* Tags here are ones which need to be "turned off" or cleared
345 * if they are in a conditional branch which isnt being used */
346 if (branch
->type
== LINE_ALTERNATOR
)
349 for (i
=0; i
<branch
->children_count
; i
++)
351 do_tags_in_hidden_conditional(get_child(branch
->children
, i
), info
);
354 else if (branch
->type
== LINE
&& branch
->children_count
)
356 struct skin_element
*child
= get_child(branch
->children
, 0);
357 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
358 struct wps_token
*token
;
362 if (child
->type
== CONDITIONAL
)
365 for (i
=0; i
<child
->children_count
; i
++)
367 do_tags_in_hidden_conditional(get_child(child
->children
, i
), info
);
369 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
372 else if (child
->type
!= TAG
|| !SKINOFFSETTOPTR(skin_buffer
, child
->data
))
374 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
377 #if defined(HAVE_LCD_BITMAP) || defined(HAVE_ALBUMART)
378 token
= (struct wps_token
*)SKINOFFSETTOPTR(skin_buffer
, child
->data
);
380 #ifdef HAVE_LCD_BITMAP
381 /* clear all pictures in the conditional and nested ones */
382 if (token
->type
== SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
)
384 struct image_display
*id
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
385 struct gui_img
*img
= skin_find_item(SKINOFFSETTOPTR(skin_buffer
, id
->label
),
386 SKIN_FIND_IMAGE
, data
);
387 clear_image_pos(gwps
, img
);
389 else if (token
->type
== SKIN_TOKEN_PEAKMETER
)
391 data
->peak_meter_enabled
= false;
393 else if (token
->type
== SKIN_TOKEN_VIEWPORT_ENABLE
)
395 char *label
= SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
396 struct skin_element
*viewport
;
397 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
399 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
401 struct skin_viewport
*skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
403 char *vplabel
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
404 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
405 vplabel
= VP_DEFAULT_LABEL_STRING
;
406 if (vplabel
&& strcmp(vplabel
, label
))
408 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
412 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
414 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
415 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
418 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
419 if (skin_viewport
->output_to_backdrop_buffer
)
421 void *backdrop
= skin_backdrop_get_buffer(data
->backdrop_id
);
422 gwps
->display
->set_framebuffer(backdrop
);
423 skin_backdrop_show(-1);
426 gwps
->display
->set_viewport(&skin_viewport
->vp
);
427 gwps
->display
->clear_viewport();
428 gwps
->display
->scroll_stop(&skin_viewport
->vp
);
429 gwps
->display
->set_viewport(&info
->skin_vp
->vp
);
430 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
432 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
433 if (skin_viewport
->output_to_backdrop_buffer
)
435 gwps
->display
->set_framebuffer(NULL
);
436 skin_backdrop_show(data
->backdrop_id
);
445 else if (data
->albumart
&& token
->type
== SKIN_TOKEN_ALBUMART_DISPLAY
)
448 playback_current_aa_hid(data
->playback_aa_slot
), true);
451 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
456 static void fix_line_alignment(struct skin_draw_info
*info
, struct skin_element
*element
)
458 struct align_pos
*align
= &info
->align
;
459 char *cur_pos
= info
->cur_align_start
+ strlen(info
->cur_align_start
);
460 switch (element
->tag
->type
)
462 case SKIN_TOKEN_ALIGN_LEFT
:
463 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
464 align
->left
= cur_pos
;
465 info
->cur_align_start
= cur_pos
;
467 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
468 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
470 align
->right
= cur_pos
;
472 align
->left
= cur_pos
;
473 info
->cur_align_start
= cur_pos
;
475 case SKIN_TOKEN_ALIGN_CENTER
:
476 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
477 align
->center
= cur_pos
;
478 info
->cur_align_start
= cur_pos
;
480 case SKIN_TOKEN_ALIGN_RIGHT
:
481 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
482 align
->right
= cur_pos
;
483 info
->cur_align_start
= cur_pos
;
485 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
486 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
488 align
->left
= cur_pos
;
490 align
->right
= cur_pos
;
491 info
->cur_align_start
= cur_pos
;
498 /* Draw a LINE element onto the display */
499 static bool skin_render_line(struct skin_element
* line
, struct skin_draw_info
*info
)
501 bool needs_update
= false;
502 int last_value
, value
;
504 if (line
->children_count
== 0)
505 return false; /* empty line, do nothing */
507 struct skin_element
*child
= get_child(line
->children
, 0);
508 struct conditional
*conditional
;
509 skin_render_func func
= skin_render_line
;
510 int old_refresh_mode
= info
->refresh_type
;
516 conditional
= SKINOFFSETTOPTR(skin_buffer
, child
->data
);
517 last_value
= conditional
->last_value
;
518 value
= evaluate_conditional(info
->gwps
, info
->offset
,
519 conditional
, child
->children_count
);
520 conditional
->last_value
= value
;
521 if (child
->children_count
== 1)
523 /* special handling so
524 * %?aa<true> and %?<true|false> need special handlng here */
526 if (value
== -1) /* tag is false */
528 /* we are in a false branch of a %?aa<true> conditional */
530 do_tags_in_hidden_conditional(get_child(child
->children
, 0), info
);
536 if (last_value
>= 0 && value
!= last_value
&& last_value
< child
->children_count
)
537 do_tags_in_hidden_conditional(get_child(child
->children
, last_value
), info
);
539 if (get_child(child
->children
, value
)->type
== LINE_ALTERNATOR
)
541 func
= skin_render_alternator
;
543 else if (get_child(child
->children
, value
)->type
== LINE
)
544 func
= skin_render_line
;
546 if (value
!= last_value
)
548 info
->refresh_type
= SKIN_REFRESH_ALL
;
549 info
->force_redraw
= true;
552 if (func(get_child(child
->children
, value
), info
))
555 needs_update
= needs_update
|| (last_value
!= value
);
557 info
->refresh_type
= old_refresh_mode
;
560 if (child
->tag
->flags
& NOBREAK
)
561 info
->no_line_break
= true;
562 if (child
->tag
->type
== SKIN_TOKEN_SUBLINE_SCROLL
)
563 info
->line_scrolls
= true;
565 fix_line_alignment(info
, child
);
567 if (!SKINOFFSETTOPTR(skin_buffer
, child
->data
))
571 if (!do_non_text_tags(info
->gwps
, info
, child
, &info
->skin_vp
->vp
))
573 static char tempbuf
[128];
574 const char *valuestr
= get_token_value(info
->gwps
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
575 info
->offset
, tempbuf
,
576 sizeof(tempbuf
), NULL
);
580 if (child
->tag
->flags
&SKIN_RTC_REFRESH
)
581 needs_update
= needs_update
|| info
->refresh_type
&SKIN_REFRESH_DYNAMIC
;
583 needs_update
= needs_update
||
584 ((child
->tag
->flags
&info
->refresh_type
)!=0);
585 strlcat(info
->cur_align_start
, valuestr
,
586 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
591 strlcat(info
->cur_align_start
, SKINOFFSETTOPTR(skin_buffer
, child
->data
),
592 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
593 needs_update
= needs_update
||
594 (info
->refresh_type
&SKIN_REFRESH_STATIC
) != 0;
601 child
= SKINOFFSETTOPTR(skin_buffer
, child
->next
);
606 static int get_subline_timeout(struct gui_wps
*gwps
, struct skin_element
* line
)
608 struct skin_element
*element
=line
;
609 struct wps_token
*token
;
610 int retval
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
611 if (element
->type
== LINE
)
613 if (element
->children_count
== 0)
614 return retval
; /* empty line, so force redraw */
615 element
= get_child(element
->children
, 0);
619 if (element
->type
== TAG
&&
620 element
->tag
->type
== SKIN_TOKEN_SUBLINE_TIMEOUT
)
622 token
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
623 return token
->value
.i
;
625 else if (element
->type
== CONDITIONAL
)
627 struct conditional
*conditional
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
628 int val
= evaluate_conditional(gwps
, 0, conditional
,
629 element
->children_count
);
632 retval
= get_subline_timeout(gwps
, get_child(element
->children
, val
));
637 element
= SKINOFFSETTOPTR(skin_buffer
, element
->next
);
642 bool skin_render_alternator(struct skin_element
* element
, struct skin_draw_info
*info
)
644 bool changed_lines
= false;
645 struct line_alternator
*alternator
= SKINOFFSETTOPTR(skin_buffer
, element
->data
);
646 unsigned old_refresh
= info
->refresh_type
;
647 if (info
->refresh_type
== SKIN_REFRESH_ALL
)
649 alternator
->current_line
= element
->children_count
-1;
650 changed_lines
= true;
652 else if (TIME_AFTER(current_tick
, alternator
->next_change_tick
))
654 changed_lines
= true;
659 struct skin_element
*current_line
;
660 int start
= alternator
->current_line
;
661 int try_line
= start
;
662 bool suitable
= false;
663 int rettimeout
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
665 /* find a subline which has at least one token in it,
666 * and that line doesnt have a timeout set to 0 through conditionals */
669 if (try_line
>= element
->children_count
)
671 if (get_child(element
->children
, try_line
)->children_count
!= 0)
673 current_line
= get_child(element
->children
, try_line
);
674 rettimeout
= get_subline_timeout(info
->gwps
,
675 get_child(current_line
->children
, 0));
682 while (try_line
!= start
&& !suitable
);
686 alternator
->current_line
= try_line
;
687 alternator
->next_change_tick
= current_tick
+ rettimeout
;
690 info
->refresh_type
= SKIN_REFRESH_ALL
;
691 info
->force_redraw
= true;
693 bool ret
= skin_render_line(get_child(element
->children
, alternator
->current_line
), info
);
694 info
->refresh_type
= old_refresh
;
695 return changed_lines
|| ret
;
698 void skin_render_viewport(struct skin_element
* viewport
, struct gui_wps
*gwps
,
699 struct skin_viewport
* skin_viewport
, unsigned long refresh_type
)
701 struct screen
*display
= gwps
->display
;
702 char linebuf
[MAX_LINE
];
703 skin_render_func func
= skin_render_line
;
704 struct skin_element
* line
= viewport
;
705 struct skin_draw_info info
= {
708 .buf_size
= sizeof(linebuf
),
710 .no_line_break
= false,
711 .line_scrolls
= false,
712 .refresh_type
= refresh_type
,
713 .skin_vp
= skin_viewport
,
715 .text_style
= STYLE_DEFAULT
718 struct align_pos
* align
= &info
.align
;
720 skin_buffer
= get_skin_buffer(gwps
->data
);
721 #ifdef HAVE_LCD_BITMAP
722 /* Set images to not to be displayed */
723 struct skin_token_list
*imglist
= SKINOFFSETTOPTR(skin_buffer
, gwps
->data
->images
);
726 struct wps_token
*token
= SKINOFFSETTOPTR(skin_buffer
, imglist
->token
);
727 struct gui_img
*img
= (struct gui_img
*)SKINOFFSETTOPTR(skin_buffer
, token
->value
.data
);
729 imglist
= SKINOFFSETTOPTR(skin_buffer
, imglist
->next
);
733 if (skin_viewport
->parsed_fontid
== 1)
734 skin_viewport
->vp
.font
= display
->getuifont();
740 info
.no_line_break
= false;
741 info
.line_scrolls
= false;
742 info
.force_redraw
= false;
743 #ifdef HAVE_LCD_COLOR
744 if (info
.text_style
&STYLE_GRADIENT
)
746 int cur
= CURLN_UNPACK(info
.text_style
);
747 int num
= NUMLN_UNPACK(info
.text_style
);
749 info
.text_style
= STYLE_DEFAULT
;
751 info
.text_style
= STYLE_GRADIENT
|CURLN_PACK(cur
+1)|NUMLN_PACK(num
);
754 info
.cur_align_start
= info
.buf
;
755 align
->left
= info
.buf
;
756 align
->center
= NULL
;
760 if (line
->type
== LINE_ALTERNATOR
)
761 func
= skin_render_alternator
;
762 else if (line
->type
== LINE
)
763 func
= skin_render_line
;
765 needs_update
= func(line
, &info
);
766 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
767 if (skin_viewport
->vp
.fg_pattern
!= skin_viewport
->start_fgcolour
||
768 skin_viewport
->vp
.bg_pattern
!= skin_viewport
->start_bgcolour
)
770 /* 2bit lcd drivers need lcd_set_viewport() to be called to change
771 * the colour, 16bit doesnt. But doing this makes static text
772 * get the new colour also */
774 display
->set_viewport(&skin_viewport
->vp
);
777 /* only update if the line needs to be, and there is something to write */
778 if (refresh_type
&& needs_update
)
780 if (info
.force_redraw
)
781 display
->scroll_stop_line(&skin_viewport
->vp
, info
.line_number
);
782 write_line(display
, align
, info
.line_number
,
783 info
.line_scrolls
, info
.text_style
);
785 if (!info
.no_line_break
)
787 line
= SKINOFFSETTOPTR(skin_buffer
, line
->next
);
789 #ifdef HAVE_LCD_BITMAP
790 wps_display_images(gwps
, &skin_viewport
->vp
);
794 void skin_render(struct gui_wps
*gwps
, unsigned refresh_mode
)
796 struct wps_data
*data
= gwps
->data
;
797 struct screen
*display
= gwps
->display
;
799 struct skin_element
* viewport
;
800 struct skin_viewport
* skin_viewport
;
803 int old_refresh_mode
= refresh_mode
;
804 skin_buffer
= get_skin_buffer(gwps
->data
);
806 #ifdef HAVE_LCD_CHARCELLS
808 for (i
= 0; i
< 8; i
++)
810 if (data
->wps_progress_pat
[i
] == 0)
811 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
815 viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
816 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
817 label
= SKINOFFSETTOPTR(skin_buffer
, skin_viewport
->label
);
818 if (skin_viewport
->label
== VP_DEFAULT_LABEL
)
819 label
= VP_DEFAULT_LABEL_STRING
;
820 if (label
&& SKINOFFSETTOPTR(skin_buffer
, viewport
->next
) &&
821 !strcmp(label
,VP_DEFAULT_LABEL_STRING
))
824 for (viewport
= SKINOFFSETTOPTR(skin_buffer
, data
->tree
);
826 viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->next
))
829 skin_viewport
= SKINOFFSETTOPTR(skin_buffer
, viewport
->data
);
830 unsigned vp_refresh_mode
= refresh_mode
;
831 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
832 skin_viewport
->vp
.fg_pattern
= skin_viewport
->start_fgcolour
;
833 skin_viewport
->vp
.bg_pattern
= skin_viewport
->start_bgcolour
;
834 if (skin_viewport
->output_to_backdrop_buffer
)
836 display
->set_framebuffer(skin_backdrop_get_buffer(data
->backdrop_id
));
837 skin_backdrop_show(-1);
841 display
->set_framebuffer(NULL
);
842 skin_backdrop_show(data
->backdrop_id
);
845 #ifdef HAVE_LCD_COLOR
846 skin_viewport
->vp
.lss_pattern
= skin_viewport
->start_gradient
.start
;
847 skin_viewport
->vp
.lse_pattern
= skin_viewport
->start_gradient
.end
;
848 skin_viewport
->vp
.lst_pattern
= skin_viewport
->start_gradient
.text
;
851 /* dont redraw the viewport if its disabled */
852 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
853 { /* don't draw anything into this one */
856 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
858 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
861 else if (((skin_viewport
->hidden_flags
&
862 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
863 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
865 vp_refresh_mode
= SKIN_REFRESH_ALL
;
866 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
869 display
->set_viewport(&skin_viewport
->vp
);
870 if ((vp_refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
)
872 display
->clear_viewport();
875 if (viewport
->children_count
)
876 skin_render_viewport(get_child(viewport
->children
, 0), gwps
,
877 skin_viewport
, vp_refresh_mode
);
878 refresh_mode
= old_refresh_mode
;
880 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
881 display
->set_framebuffer(NULL
);
882 skin_backdrop_show(data
->backdrop_id
);
885 if (((refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
))
887 /* If this is the UI viewport then let the UI know
888 * to redraw itself */
889 send_event(GUI_EVENT_NEED_UI_UPDATE
, NULL
);
891 /* Restore the default viewport */
892 display
->set_viewport(NULL
);
896 #ifdef HAVE_LCD_BITMAP
897 static __attribute__((noinline
))
898 void skin_render_playlistviewer(struct playlistviewer
* viewer
,
899 struct gui_wps
*gwps
,
900 struct skin_viewport
* skin_viewport
,
901 unsigned long refresh_type
)
903 struct screen
*display
= gwps
->display
;
904 char linebuf
[MAX_LINE
];
905 skin_render_func func
= skin_render_line
;
906 struct skin_element
* line
;
907 struct skin_draw_info info
= {
910 .buf_size
= sizeof(linebuf
),
912 .no_line_break
= false,
913 .line_scrolls
= false,
914 .refresh_type
= refresh_type
,
915 .skin_vp
= skin_viewport
,
916 .offset
= viewer
->start_offset
,
917 .text_style
= STYLE_DEFAULT
920 struct align_pos
* align
= &info
.align
;
922 int cur_pos
, start_item
, max
;
923 int nb_lines
= viewport_get_nb_lines(SKINOFFSETTOPTR(skin_buffer
, viewer
->vp
));
925 if (get_current_activity() == ACTIVITY_FM
)
927 cur_pos
= radio_current_preset();
928 start_item
= cur_pos
+ viewer
->start_offset
;
929 max
= start_item
+radio_preset_count();
934 struct cuesheet
*cue
= skin_get_global_state()->id3
?
935 skin_get_global_state()->id3
->cuesheet
: NULL
;
936 cur_pos
= playlist_get_display_index();
937 max
= playlist_amount()+1;
939 max
+= cue
->track_count
;
940 start_item
= MAX(0, cur_pos
+ viewer
->start_offset
);
942 if (max
-start_item
> nb_lines
)
943 max
= start_item
+ nb_lines
;
945 line
= SKINOFFSETTOPTR(skin_buffer
, viewer
->line
);
946 while (start_item
< max
)
949 info
.no_line_break
= false;
950 info
.line_scrolls
= false;
951 info
.force_redraw
= false;
953 info
.cur_align_start
= info
.buf
;
954 align
->left
= info
.buf
;
955 align
->center
= NULL
;
959 if (line
->type
== LINE_ALTERNATOR
)
960 func
= skin_render_alternator
;
961 else if (line
->type
== LINE
)
962 func
= skin_render_line
;
964 needs_update
= func(line
, &info
);
966 /* only update if the line needs to be, and there is something to write */
967 if (refresh_type
&& needs_update
)
969 if (!info
.force_redraw
)
970 display
->scroll_stop_line(&skin_viewport
->vp
, info
.line_number
);
971 write_line(display
, align
, info
.line_number
,
972 info
.line_scrolls
, info
.text_style
);