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 ****************************************************************************/
34 #include "skin_display.h"
35 #include "skin_engine.h"
36 #include "skin_parser.h"
37 #include "tag_table.h"
38 #include "skin_scan.h"
47 #include "root_menu.h"
54 struct skin_draw_info
{
56 struct skin_viewport
*skin_vp
;
58 unsigned long refresh_type
;
61 char* cur_align_start
;
62 struct align_pos align
;
70 int offset
; /* used by the playlist viewer */
73 typedef bool (*skin_render_func
)(struct skin_element
* alternator
, struct skin_draw_info
*info
);
74 bool skin_render_alternator(struct skin_element
* alternator
, struct skin_draw_info
*info
);
76 #ifdef HAVE_LCD_BITMAP
77 static void skin_render_playlistviewer(struct playlistviewer
* viewer
,
79 struct skin_viewport
* skin_viewport
,
80 unsigned long refresh_type
);
83 static bool do_non_text_tags(struct gui_wps
*gwps
, struct skin_draw_info
*info
,
84 struct skin_element
*element
, struct viewport
* vp
)
86 #ifndef HAVE_LCD_BITMAP
87 (void)vp
; /* silence warnings */
90 struct wps_token
*token
= (struct wps_token
*)element
->data
;
92 #ifdef HAVE_LCD_BITMAP
93 struct wps_data
*data
= gwps
->data
;
94 bool do_refresh
= (element
->tag
->flags
& info
->refresh_type
) > 0;
98 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
99 case SKIN_TOKEN_VIEWPORT_FGCOLOUR
:
101 struct viewport_colour
*col
= token
->value
.data
;
102 col
->vp
->fg_pattern
= col
->colour
;
105 case SKIN_TOKEN_VIEWPORT_BGCOLOUR
:
107 struct viewport_colour
*col
= token
->value
.data
;
108 col
->vp
->bg_pattern
= col
->colour
;
111 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE
:
112 info
->text_style
= token
->value
.l
;
115 #ifdef HAVE_LCD_COLOR
116 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP
:
118 struct gradient_config
*cfg
= token
->value
.data
;
119 vp
->lss_pattern
= cfg
->start
;
120 vp
->lse_pattern
= cfg
->end
;
121 vp
->lst_pattern
= cfg
->text
;
125 case SKIN_TOKEN_VIEWPORT_ENABLE
:
127 char *label
= token
->value
.data
;
128 char temp
= VP_DRAW_HIDEABLE
;
129 struct skin_element
*viewport
= gwps
->data
->tree
;
132 struct skin_viewport
*skinvp
= (struct skin_viewport
*)viewport
->data
;
133 if (skinvp
->label
&& !skinvp
->is_infovp
&&
134 !strcmp(skinvp
->label
, label
))
136 if (skinvp
->hidden_flags
&VP_DRAW_HIDDEN
)
138 temp
|= VP_DRAW_WASHIDDEN
;
140 skinvp
->hidden_flags
= temp
;
142 viewport
= viewport
->next
;
146 #ifdef HAVE_LCD_BITMAP
147 case SKIN_TOKEN_LIST_ITEM_CFG
:
149 skinlist_set_cfg(gwps
->display
->screen_type
,
152 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
153 sb_set_info_vp(gwps
->display
->screen_type
,
156 case SKIN_TOKEN_PEAKMETER
:
157 data
->peak_meter_enabled
= true;
159 draw_peakmeters(gwps
, info
->line_number
, vp
);
162 #ifdef HAVE_LCD_BITMAP
163 case SKIN_TOKEN_PEAKMETER_LEFTBAR
:
164 case SKIN_TOKEN_PEAKMETER_RIGHTBAR
:
165 data
->peak_meter_enabled
= true;
166 /* fall through to the progressbar code */
168 case SKIN_TOKEN_VOLUMEBAR
:
169 case SKIN_TOKEN_BATTERY_PERCENTBAR
:
170 #ifdef HAVE_LCD_BITMAP
171 case SKIN_TOKEN_PROGRESSBAR
:
172 case SKIN_TOKEN_TUNER_RSSI_BAR
:
173 case SKIN_TOKEN_LIST_SCROLLBAR
:
175 struct progressbar
*bar
= (struct progressbar
*)token
->value
.data
;
177 draw_progressbar(gwps
, info
->line_number
, bar
);
181 #ifdef HAVE_LCD_BITMAP
182 case SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
:
183 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
185 struct image_display
*id
= token
->value
.data
;
186 const char* label
= id
->label
;
187 struct gui_img
*img
= skin_find_item(label
,SKIN_FIND_IMAGE
, data
);
188 if (img
&& img
->loaded
)
190 if (id
->token
== NULL
)
192 img
->display
= id
->subimage
;
198 int a
= img
->num_subimages
;
199 out
= get_token_value(gwps
, id
->token
, info
->offset
,
200 buf
, sizeof(buf
), &a
);
202 /* NOTE: get_token_value() returns values starting at 1! */
204 a
= (out
&& *out
) ? 1 : 2;
205 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
)
206 a
-= 2; /* 2 is added in statusbar-skinned.c! */
211 /* Clear the image, as in conditionals */
212 clear_image_pos(gwps
, img
);
214 /* If the token returned a value which is higher than
215 * the amount of subimages, don't draw it. */
216 if (a
>= 0 && a
< img
->num_subimages
)
225 case SKIN_TOKEN_ALBUMART_DISPLAY
:
226 /* now draw the AA */
227 if (do_refresh
&& data
->albumart
)
229 int handle
= playback_current_aa_hid(data
->playback_aa_slot
);
231 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
233 struct dim dim
= {data
->albumart
->width
, data
->albumart
->height
};
234 handle
= radio_get_art_hid(&dim
);
237 data
->albumart
->draw_handle
= handle
;
241 case SKIN_TOKEN_DRAW_INBUILTBAR
:
242 gui_statusbar_draw(&(statusbars
.statusbars
[gwps
->display
->screen_type
]),
243 info
->refresh_type
== SKIN_REFRESH_ALL
,
246 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
248 skin_render_playlistviewer(token
->value
.data
, gwps
,
249 info
->skin_vp
, info
->refresh_type
);
252 #endif /* HAVE_LCD_BITMAP */
253 #ifdef HAVE_SKIN_VARIABLES
254 case SKIN_TOKEN_VAR_SET
:
257 struct skin_var_changer
*data
= token
->value
.data
;
259 data
->var
->value
= data
->newval
;
262 data
->var
->value
+= data
->newval
;
265 if (data
->var
->value
> data
->max
)
266 data
->var
->value
= 1;
267 else if (data
->var
->value
< 1)
268 data
->var
->value
= data
->max
;
271 if (data
->var
->value
< 1)
272 data
->var
->value
= 1;
273 data
->var
->last_changed
= current_tick
;
285 static void do_tags_in_hidden_conditional(struct skin_element
* branch
,
286 struct skin_draw_info
*info
)
288 #ifdef HAVE_LCD_BITMAP
289 struct gui_wps
*gwps
= info
->gwps
;
290 struct wps_data
*data
= gwps
->data
;
292 /* Tags here are ones which need to be "turned off" or cleared
293 * if they are in a conditional branch which isnt being used */
294 if (branch
->type
== LINE_ALTERNATOR
)
297 for (i
=0; i
<branch
->children_count
; i
++)
299 do_tags_in_hidden_conditional(branch
->children
[i
], info
);
302 else if (branch
->type
== LINE
&& branch
->children_count
)
304 struct skin_element
*child
= branch
->children
[0];
305 struct wps_token
*token
;
308 if (child
->type
== CONDITIONAL
)
311 for (i
=0; i
<child
->children_count
; i
++)
313 do_tags_in_hidden_conditional(child
->children
[i
], info
);
318 else if (child
->type
!= TAG
|| !child
->data
)
323 token
= (struct wps_token
*)child
->data
;
324 #ifdef HAVE_LCD_BITMAP
325 /* clear all pictures in the conditional and nested ones */
326 if (token
->type
== SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
)
328 struct image_display
*id
= token
->value
.data
;
329 struct gui_img
*img
= skin_find_item(id
->label
,
330 SKIN_FIND_IMAGE
, data
);
331 clear_image_pos(gwps
, img
);
333 else if (token
->type
== SKIN_TOKEN_PEAKMETER
)
335 data
->peak_meter_enabled
= false;
337 else if (token
->type
== SKIN_TOKEN_VIEWPORT_ENABLE
)
339 char *label
= token
->value
.data
;
340 struct skin_element
*viewport
;
341 for (viewport
= data
->tree
;
343 viewport
= viewport
->next
)
345 struct skin_viewport
*skin_viewport
= (struct skin_viewport
*)viewport
->data
;
346 if (skin_viewport
->label
&& strcmp(skin_viewport
->label
, label
))
348 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
352 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
354 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
355 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
358 gwps
->display
->set_viewport(&skin_viewport
->vp
);
359 gwps
->display
->clear_viewport();
360 gwps
->display
->scroll_stop(&skin_viewport
->vp
);
361 gwps
->display
->set_viewport(&info
->skin_vp
->vp
);
362 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
369 else if (data
->albumart
&& token
->type
== SKIN_TOKEN_ALBUMART_DISPLAY
)
372 playback_current_aa_hid(data
->playback_aa_slot
), true);
380 static void fix_line_alignment(struct skin_draw_info
*info
, struct skin_element
*element
)
382 struct align_pos
*align
= &info
->align
;
383 char *cur_pos
= info
->cur_align_start
+ strlen(info
->cur_align_start
);
384 switch (element
->tag
->type
)
386 case SKIN_TOKEN_ALIGN_LEFT
:
387 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
388 align
->left
= cur_pos
;
389 info
->cur_align_start
= cur_pos
;
391 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
392 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
394 align
->right
= cur_pos
;
396 align
->left
= cur_pos
;
397 info
->cur_align_start
= cur_pos
;
399 case SKIN_TOKEN_ALIGN_CENTER
:
400 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
401 align
->center
= cur_pos
;
402 info
->cur_align_start
= cur_pos
;
404 case SKIN_TOKEN_ALIGN_RIGHT
:
405 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
406 align
->right
= cur_pos
;
407 info
->cur_align_start
= cur_pos
;
409 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
410 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
412 align
->left
= cur_pos
;
414 align
->right
= cur_pos
;
415 info
->cur_align_start
= cur_pos
;
422 /* Draw a LINE element onto the display */
423 static bool skin_render_line(struct skin_element
* line
, struct skin_draw_info
*info
)
425 bool needs_update
= false;
426 int last_value
, value
;
428 if (line
->children_count
== 0)
429 return false; /* empty line, do nothing */
431 struct skin_element
*child
= line
->children
[0];
432 struct conditional
*conditional
;
433 skin_render_func func
= skin_render_line
;
434 int old_refresh_mode
= info
->refresh_type
;
440 conditional
= (struct conditional
*)child
->data
;
441 last_value
= conditional
->last_value
;
442 value
= evaluate_conditional(info
->gwps
, info
->offset
,
443 conditional
, child
->children_count
);
444 conditional
->last_value
= value
;
445 if (child
->children_count
== 1)
447 /* special handling so
448 * %?aa<true> and %?<true|false> need special handlng here */
450 if (value
== -1) /* tag is false */
452 /* we are in a false branch of a %?aa<true> conditional */
454 do_tags_in_hidden_conditional(child
->children
[0], info
);
460 if (last_value
>= 0 && value
!= last_value
&& last_value
< child
->children_count
)
461 do_tags_in_hidden_conditional(child
->children
[last_value
], info
);
463 if (child
->children
[value
]->type
== LINE_ALTERNATOR
)
465 func
= skin_render_alternator
;
467 else if (child
->children
[value
]->type
== LINE
)
468 func
= skin_render_line
;
470 if (value
!= last_value
)
472 info
->refresh_type
= SKIN_REFRESH_ALL
;
473 info
->force_redraw
= true;
476 if (func(child
->children
[value
], info
))
479 needs_update
= needs_update
|| (last_value
!= value
);
481 info
->refresh_type
= old_refresh_mode
;
484 if (child
->tag
->flags
& NOBREAK
)
485 info
->no_line_break
= true;
486 if (child
->tag
->type
== SKIN_TOKEN_SUBLINE_SCROLL
)
487 info
->line_scrolls
= true;
489 fix_line_alignment(info
, child
);
495 if (!do_non_text_tags(info
->gwps
, info
, child
, &info
->skin_vp
->vp
))
497 static char tempbuf
[128];
498 const char *valuestr
= get_token_value(info
->gwps
, child
->data
,
499 info
->offset
, tempbuf
,
500 sizeof(tempbuf
), NULL
);
504 if (child
->tag
->flags
&SKIN_RTC_REFRESH
)
505 needs_update
= needs_update
|| info
->refresh_type
&SKIN_REFRESH_DYNAMIC
;
507 needs_update
= needs_update
||
508 ((child
->tag
->flags
&info
->refresh_type
)!=0);
509 strlcat(info
->cur_align_start
, valuestr
,
510 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
515 strlcat(info
->cur_align_start
, child
->data
,
516 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
517 needs_update
= needs_update
||
518 (info
->refresh_type
&SKIN_REFRESH_STATIC
) != 0;
530 static int get_subline_timeout(struct gui_wps
*gwps
, struct skin_element
* line
)
532 struct skin_element
*element
=line
;
533 struct wps_token
*token
;
534 int retval
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
535 if (element
->type
== LINE
)
537 if (element
->children_count
== 0)
538 return retval
; /* empty line, so force redraw */
539 element
= element
->children
[0];
543 if (element
->type
== TAG
&&
544 element
->tag
->type
== SKIN_TOKEN_SUBLINE_TIMEOUT
)
546 token
= element
->data
;
547 return token
->value
.i
;
549 else if (element
->type
== CONDITIONAL
)
551 struct conditional
*conditional
= element
->data
;
552 int val
= evaluate_conditional(gwps
, 0, conditional
,
553 element
->children_count
);
556 retval
= get_subline_timeout(gwps
, element
->children
[val
]);
561 element
= element
->next
;
566 bool skin_render_alternator(struct skin_element
* element
, struct skin_draw_info
*info
)
568 bool changed_lines
= false;
569 struct line_alternator
*alternator
= (struct line_alternator
*)element
->data
;
570 unsigned old_refresh
= info
->refresh_type
;
571 if (info
->refresh_type
== SKIN_REFRESH_ALL
)
573 alternator
->current_line
= element
->children_count
-1;
574 changed_lines
= true;
576 else if (TIME_AFTER(current_tick
, alternator
->next_change_tick
))
578 changed_lines
= true;
583 struct skin_element
*current_line
;
584 int start
= alternator
->current_line
;
585 int try_line
= start
;
586 bool suitable
= false;
587 int rettimeout
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
589 /* find a subline which has at least one token in it,
590 * and that line doesnt have a timeout set to 0 through conditionals */
593 if (try_line
>= element
->children_count
)
595 if (element
->children
[try_line
]->children_count
!= 0)
597 current_line
= element
->children
[try_line
];
598 rettimeout
= get_subline_timeout(info
->gwps
,
599 current_line
->children
[0]);
606 while (try_line
!= start
&& !suitable
);
610 alternator
->current_line
= try_line
;
611 alternator
->next_change_tick
= current_tick
+ rettimeout
;
614 info
->refresh_type
= SKIN_REFRESH_ALL
;
615 info
->force_redraw
= true;
617 bool ret
= skin_render_line(element
->children
[alternator
->current_line
], info
);
618 info
->refresh_type
= old_refresh
;
619 return changed_lines
|| ret
;
622 void skin_render_viewport(struct skin_element
* viewport
, struct gui_wps
*gwps
,
623 struct skin_viewport
* skin_viewport
, unsigned long refresh_type
)
625 struct screen
*display
= gwps
->display
;
626 char linebuf
[MAX_LINE
];
627 skin_render_func func
= skin_render_line
;
628 struct skin_element
* line
= viewport
;
629 struct skin_draw_info info
= {
632 .buf_size
= sizeof(linebuf
),
634 .no_line_break
= false,
635 .line_scrolls
= false,
636 .refresh_type
= refresh_type
,
637 .skin_vp
= skin_viewport
,
639 .text_style
= STYLE_DEFAULT
642 struct align_pos
* align
= &info
.align
;
644 #ifdef HAVE_LCD_BITMAP
645 /* Set images to not to be displayed */
646 struct skin_token_list
*imglist
= gwps
->data
->images
;
649 struct gui_img
*img
= (struct gui_img
*)imglist
->token
->value
.data
;
651 imglist
= imglist
->next
;
658 info
.no_line_break
= false;
659 info
.line_scrolls
= false;
660 info
.force_redraw
= false;
661 #ifdef HAVE_LCD_COLOR
662 if (info
.text_style
&STYLE_GRADIENT
)
664 int cur
= CURLN_UNPACK(info
.text_style
);
665 int num
= NUMLN_UNPACK(info
.text_style
);
667 info
.text_style
= STYLE_DEFAULT
;
669 info
.text_style
= STYLE_GRADIENT
|CURLN_PACK(cur
+1)|NUMLN_PACK(num
);
672 info
.cur_align_start
= info
.buf
;
673 align
->left
= info
.buf
;
674 align
->center
= NULL
;
678 if (line
->type
== LINE_ALTERNATOR
)
679 func
= skin_render_alternator
;
680 else if (line
->type
== LINE
)
681 func
= skin_render_line
;
683 needs_update
= func(line
, &info
);
684 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
685 if (skin_viewport
->vp
.fg_pattern
!= skin_viewport
->start_fgcolour
||
686 skin_viewport
->vp
.bg_pattern
!= skin_viewport
->start_bgcolour
)
688 /* 2bit lcd drivers need lcd_set_viewport() to be called to change
689 * the colour, 16bit doesnt. But doing this makes static text
690 * get the new colour also */
692 display
->set_viewport(&skin_viewport
->vp
);
695 /* only update if the line needs to be, and there is something to write */
696 if (refresh_type
&& needs_update
)
698 if (info
.line_scrolls
)
700 /* if the line is a scrolling one we don't want to update
701 too often, so that it has the time to scroll */
702 if ((refresh_type
& SKIN_REFRESH_SCROLL
) || info
.force_redraw
)
703 write_line(display
, align
, info
.line_number
, true, info
.text_style
);
706 write_line(display
, align
, info
.line_number
, false, info
.text_style
);
708 if (!info
.no_line_break
)
712 #ifdef HAVE_LCD_BITMAP
713 wps_display_images(gwps
, &skin_viewport
->vp
);
717 void skin_render(struct gui_wps
*gwps
, unsigned refresh_mode
)
719 struct wps_data
*data
= gwps
->data
;
720 struct screen
*display
= gwps
->display
;
722 struct skin_element
* viewport
;
723 struct skin_viewport
* skin_viewport
;
725 int old_refresh_mode
= refresh_mode
;
727 #ifdef HAVE_LCD_CHARCELLS
729 for (i
= 0; i
< 8; i
++)
731 if (data
->wps_progress_pat
[i
] == 0)
732 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
735 viewport
= data
->tree
;
736 skin_viewport
= (struct skin_viewport
*)viewport
->data
;
737 if (skin_viewport
->label
&& viewport
->next
&&
738 !strcmp(skin_viewport
->label
,VP_DEFAULT_LABEL
))
741 for (viewport
= data
->tree
;
743 viewport
= viewport
->next
)
746 skin_viewport
= (struct skin_viewport
*)viewport
->data
;
747 unsigned vp_refresh_mode
= refresh_mode
;
748 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
749 skin_viewport
->vp
.fg_pattern
= skin_viewport
->start_fgcolour
;
750 skin_viewport
->vp
.bg_pattern
= skin_viewport
->start_bgcolour
;
752 #ifdef HAVE_LCD_COLOR
753 skin_viewport
->vp
.lss_pattern
= skin_viewport
->start_gradient
.start
;
754 skin_viewport
->vp
.lse_pattern
= skin_viewport
->start_gradient
.end
;
755 skin_viewport
->vp
.lst_pattern
= skin_viewport
->start_gradient
.text
;
758 /* dont redraw the viewport if its disabled */
759 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
760 { /* don't draw anything into this one */
763 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
765 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
768 else if (((skin_viewport
->hidden_flags
&
769 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
770 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
772 vp_refresh_mode
= SKIN_REFRESH_ALL
;
773 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
776 display
->set_viewport(&skin_viewport
->vp
);
777 if ((vp_refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
)
779 display
->clear_viewport();
782 if (viewport
->children_count
)
783 skin_render_viewport(viewport
->children
[0], gwps
,
784 skin_viewport
, vp_refresh_mode
);
785 refresh_mode
= old_refresh_mode
;
788 /* Restore the default viewport */
789 display
->set_viewport(NULL
);
793 #ifdef HAVE_LCD_BITMAP
794 static __attribute__((noinline
))
795 void skin_render_playlistviewer(struct playlistviewer
* viewer
,
796 struct gui_wps
*gwps
,
797 struct skin_viewport
* skin_viewport
,
798 unsigned long refresh_type
)
800 struct screen
*display
= gwps
->display
;
801 char linebuf
[MAX_LINE
];
802 skin_render_func func
= skin_render_line
;
803 struct skin_element
* line
;
804 struct skin_draw_info info
= {
807 .buf_size
= sizeof(linebuf
),
809 .no_line_break
= false,
810 .line_scrolls
= false,
811 .refresh_type
= refresh_type
,
812 .skin_vp
= skin_viewport
,
813 .offset
= viewer
->start_offset
,
814 .text_style
= STYLE_DEFAULT
817 struct align_pos
* align
= &info
.align
;
819 int cur_pos
, start_item
, max
;
820 int nb_lines
= viewport_get_nb_lines(viewer
->vp
);
822 if (get_current_activity() == ACTIVITY_FM
)
824 cur_pos
= radio_current_preset();
825 start_item
= cur_pos
+ viewer
->start_offset
;
826 max
= start_item
+radio_preset_count();
831 struct cuesheet
*cue
= skin_get_global_state()->id3
?
832 skin_get_global_state()->id3
->cuesheet
: NULL
;
833 cur_pos
= playlist_get_display_index();
834 max
= playlist_amount()+1;
836 max
+= cue
->track_count
;
837 start_item
= MAX(0, cur_pos
+ viewer
->start_offset
);
839 if (max
-start_item
> nb_lines
)
840 max
= start_item
+ nb_lines
;
843 while (start_item
< max
)
846 info
.no_line_break
= false;
847 info
.line_scrolls
= false;
848 info
.force_redraw
= false;
850 info
.cur_align_start
= info
.buf
;
851 align
->left
= info
.buf
;
852 align
->center
= NULL
;
856 if (line
->type
== LINE_ALTERNATOR
)
857 func
= skin_render_alternator
;
858 else if (line
->type
== LINE
)
859 func
= skin_render_line
;
861 needs_update
= func(line
, &info
);
863 /* only update if the line needs to be, and there is something to write */
864 if (refresh_type
&& needs_update
)
866 if (info
.line_scrolls
)
868 /* if the line is a scrolling one we don't want to update
869 too often, so that it has the time to scroll */
870 if ((refresh_type
& SKIN_REFRESH_SCROLL
) || info
.force_redraw
)
871 write_line(display
, align
, info
.line_number
, true, info
.text_style
);
874 write_line(display
, align
, info
.line_number
, false, info
.text_style
);