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"
53 struct skin_draw_info
{
55 struct skin_viewport
*skin_vp
;
57 unsigned long refresh_type
;
60 char* cur_align_start
;
61 struct align_pos align
;
69 int offset
; /* used by the playlist viewer */
72 typedef bool (*skin_render_func
)(struct skin_element
* alternator
, struct skin_draw_info
*info
);
73 bool skin_render_alternator(struct skin_element
* alternator
, struct skin_draw_info
*info
);
75 #ifdef HAVE_LCD_BITMAP
76 static void skin_render_playlistviewer(struct playlistviewer
* viewer
,
78 struct skin_viewport
* skin_viewport
,
79 unsigned long refresh_type
);
82 static bool do_non_text_tags(struct gui_wps
*gwps
, struct skin_draw_info
*info
,
83 struct skin_element
*element
, struct viewport
* vp
)
85 #ifndef HAVE_LCD_BITMAP
86 (void)vp
; /* silence warnings */
89 struct wps_token
*token
= (struct wps_token
*)element
->data
;
91 #ifdef HAVE_LCD_BITMAP
92 struct wps_data
*data
= gwps
->data
;
93 bool do_refresh
= (element
->tag
->flags
& info
->refresh_type
) > 0;
97 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
98 case SKIN_TOKEN_VIEWPORT_FGCOLOUR
:
100 struct viewport_colour
*col
= token
->value
.data
;
101 col
->vp
->fg_pattern
= col
->colour
;
104 case SKIN_TOKEN_VIEWPORT_BGCOLOUR
:
106 struct viewport_colour
*col
= token
->value
.data
;
107 col
->vp
->bg_pattern
= col
->colour
;
110 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE
:
111 info
->text_style
= token
->value
.l
;
114 #ifdef HAVE_LCD_COLOR
115 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP
:
117 struct gradient_config
*cfg
= token
->value
.data
;
118 vp
->lss_pattern
= cfg
->start
;
119 vp
->lse_pattern
= cfg
->end
;
120 vp
->lst_pattern
= cfg
->text
;
124 case SKIN_TOKEN_VIEWPORT_ENABLE
:
126 char *label
= token
->value
.data
;
127 char temp
= VP_DRAW_HIDEABLE
;
128 struct skin_element
*viewport
= gwps
->data
->tree
;
131 struct skin_viewport
*skinvp
= (struct skin_viewport
*)viewport
->data
;
132 if (skinvp
->label
&& !skinvp
->is_infovp
&&
133 !strcmp(skinvp
->label
, label
))
135 if (skinvp
->hidden_flags
&VP_DRAW_HIDDEN
)
137 temp
|= VP_DRAW_WASHIDDEN
;
139 skinvp
->hidden_flags
= temp
;
141 viewport
= viewport
->next
;
145 #ifdef HAVE_LCD_BITMAP
146 case SKIN_TOKEN_UIVIEWPORT_ENABLE
:
147 sb_set_info_vp(gwps
->display
->screen_type
,
150 case SKIN_TOKEN_PEAKMETER
:
151 data
->peak_meter_enabled
= true;
153 draw_peakmeters(gwps
, info
->line_number
, vp
);
156 #ifdef HAVE_LCD_BITMAP
157 case SKIN_TOKEN_PEAKMETER_LEFTBAR
:
158 case SKIN_TOKEN_PEAKMETER_RIGHTBAR
:
159 data
->peak_meter_enabled
= true;
160 /* fall through to the progressbar code */
162 case SKIN_TOKEN_VOLUMEBAR
:
163 case SKIN_TOKEN_BATTERY_PERCENTBAR
:
164 #ifdef HAVE_LCD_BITMAP
165 case SKIN_TOKEN_PROGRESSBAR
:
166 case SKIN_TOKEN_TUNER_RSSI_BAR
:
168 struct progressbar
*bar
= (struct progressbar
*)token
->value
.data
;
170 draw_progressbar(gwps
, info
->line_number
, bar
);
174 #ifdef HAVE_LCD_BITMAP
175 case SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
:
176 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
:
178 struct image_display
*id
= token
->value
.data
;
179 const char* label
= id
->label
;
180 struct gui_img
*img
= skin_find_item(label
,SKIN_FIND_IMAGE
, data
);
181 if (img
&& img
->loaded
)
183 if (id
->token
== NULL
)
185 img
->display
= id
->subimage
;
191 int a
= img
->num_subimages
;
192 out
= get_token_value(gwps
, id
->token
, info
->offset
,
193 buf
, sizeof(buf
), &a
);
195 /* NOTE: get_token_value() returns values starting at 1! */
197 a
= (out
&& *out
) ? 1 : 2;
198 if (token
->type
== SKIN_TOKEN_IMAGE_DISPLAY_LISTICON
)
199 a
-= 2; /* 2 is added in statusbar-skinned.c! */
204 /* Clear the image, as in conditionals */
205 clear_image_pos(gwps
, img
);
207 /* If the token returned a value which is higher than
208 * the amount of subimages, don't draw it. */
209 if (a
>= 0 && a
< img
->num_subimages
)
218 case SKIN_TOKEN_ALBUMART_DISPLAY
:
219 /* now draw the AA */
220 if (do_refresh
&& data
->albumart
)
222 int handle
= playback_current_aa_hid(data
->playback_aa_slot
);
224 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF
))
226 struct dim dim
= {data
->albumart
->width
, data
->albumart
->height
};
227 handle
= radio_get_art_hid(&dim
);
230 data
->albumart
->draw_handle
= handle
;
234 case SKIN_TOKEN_DRAW_INBUILTBAR
:
235 gui_statusbar_draw(&(statusbars
.statusbars
[gwps
->display
->screen_type
]),
236 info
->refresh_type
== SKIN_REFRESH_ALL
,
239 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST
:
241 skin_render_playlistviewer(token
->value
.data
, gwps
,
242 info
->skin_vp
, info
->refresh_type
);
245 #endif /* HAVE_LCD_BITMAP */
246 #ifdef HAVE_SKIN_VARIABLES
247 case SKIN_TOKEN_VAR_SET
:
250 struct skin_var_changer
*data
= token
->value
.data
;
252 data
->var
->value
= data
->newval
;
255 data
->var
->value
+= data
->newval
;
258 if (data
->var
->value
> data
->max
)
259 data
->var
->value
= 1;
260 else if (data
->var
->value
< 1)
261 data
->var
->value
= data
->max
;
264 if (data
->var
->value
< 1)
265 data
->var
->value
= 1;
266 data
->var
->last_changed
= current_tick
;
278 static void do_tags_in_hidden_conditional(struct skin_element
* branch
,
279 struct skin_draw_info
*info
)
281 #ifdef HAVE_LCD_BITMAP
282 struct gui_wps
*gwps
= info
->gwps
;
283 struct wps_data
*data
= gwps
->data
;
285 /* Tags here are ones which need to be "turned off" or cleared
286 * if they are in a conditional branch which isnt being used */
287 if (branch
->type
== LINE_ALTERNATOR
)
290 for (i
=0; i
<branch
->children_count
; i
++)
292 do_tags_in_hidden_conditional(branch
->children
[i
], info
);
295 else if (branch
->type
== LINE
&& branch
->children_count
)
297 struct skin_element
*child
= branch
->children
[0];
298 struct wps_token
*token
;
301 if (child
->type
== CONDITIONAL
)
304 for (i
=0; i
<child
->children_count
; i
++)
306 do_tags_in_hidden_conditional(child
->children
[i
], info
);
311 else if (child
->type
!= TAG
|| !child
->data
)
316 token
= (struct wps_token
*)child
->data
;
317 #ifdef HAVE_LCD_BITMAP
318 /* clear all pictures in the conditional and nested ones */
319 if (token
->type
== SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY
)
321 struct image_display
*id
= token
->value
.data
;
322 struct gui_img
*img
= skin_find_item(id
->label
,
323 SKIN_FIND_IMAGE
, data
);
324 clear_image_pos(gwps
, img
);
326 else if (token
->type
== SKIN_TOKEN_PEAKMETER
)
328 data
->peak_meter_enabled
= false;
330 else if (token
->type
== SKIN_TOKEN_VIEWPORT_ENABLE
)
332 char *label
= token
->value
.data
;
333 struct skin_element
*viewport
;
334 for (viewport
= data
->tree
;
336 viewport
= viewport
->next
)
338 struct skin_viewport
*skin_viewport
= (struct skin_viewport
*)viewport
->data
;
339 if (skin_viewport
->label
&& strcmp(skin_viewport
->label
, label
))
341 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
345 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
347 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
348 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
351 gwps
->display
->set_viewport(&skin_viewport
->vp
);
352 gwps
->display
->clear_viewport();
353 gwps
->display
->scroll_stop(&skin_viewport
->vp
);
354 gwps
->display
->set_viewport(&info
->skin_vp
->vp
);
355 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
362 else if (data
->albumart
&& token
->type
== SKIN_TOKEN_ALBUMART_DISPLAY
)
365 playback_current_aa_hid(data
->playback_aa_slot
), true);
373 static void fix_line_alignment(struct skin_draw_info
*info
, struct skin_element
*element
)
375 struct align_pos
*align
= &info
->align
;
376 char *cur_pos
= info
->cur_align_start
+ strlen(info
->cur_align_start
);
377 switch (element
->tag
->type
)
379 case SKIN_TOKEN_ALIGN_LEFT
:
380 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
381 align
->left
= cur_pos
;
382 info
->cur_align_start
= cur_pos
;
384 case SKIN_TOKEN_ALIGN_LEFT_RTL
:
385 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
387 align
->right
= cur_pos
;
389 align
->left
= cur_pos
;
390 info
->cur_align_start
= cur_pos
;
392 case SKIN_TOKEN_ALIGN_CENTER
:
393 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
394 align
->center
= cur_pos
;
395 info
->cur_align_start
= cur_pos
;
397 case SKIN_TOKEN_ALIGN_RIGHT
:
398 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
399 align
->right
= cur_pos
;
400 info
->cur_align_start
= cur_pos
;
402 case SKIN_TOKEN_ALIGN_RIGHT_RTL
:
403 *cur_pos
= '\0'; cur_pos
++; *cur_pos
= '\0';
405 align
->left
= cur_pos
;
407 align
->right
= cur_pos
;
408 info
->cur_align_start
= cur_pos
;
415 /* Draw a LINE element onto the display */
416 static bool skin_render_line(struct skin_element
* line
, struct skin_draw_info
*info
)
418 bool needs_update
= false;
419 int last_value
, value
;
421 if (line
->children_count
== 0)
422 return false; /* empty line, do nothing */
424 struct skin_element
*child
= line
->children
[0];
425 struct conditional
*conditional
;
426 skin_render_func func
= skin_render_line
;
427 int old_refresh_mode
= info
->refresh_type
;
433 conditional
= (struct conditional
*)child
->data
;
434 last_value
= conditional
->last_value
;
435 value
= evaluate_conditional(info
->gwps
, info
->offset
,
436 conditional
, child
->children_count
);
437 conditional
->last_value
= value
;
438 if (child
->children_count
== 1)
440 /* special handling so
441 * %?aa<true> and %?<true|false> need special handlng here */
443 if (value
== -1) /* tag is false */
445 /* we are in a false branch of a %?aa<true> conditional */
447 do_tags_in_hidden_conditional(child
->children
[0], info
);
453 if (last_value
>= 0 && value
!= last_value
&& last_value
< child
->children_count
)
454 do_tags_in_hidden_conditional(child
->children
[last_value
], info
);
456 if (child
->children
[value
]->type
== LINE_ALTERNATOR
)
458 func
= skin_render_alternator
;
460 else if (child
->children
[value
]->type
== LINE
)
461 func
= skin_render_line
;
463 if (value
!= last_value
)
465 info
->refresh_type
= SKIN_REFRESH_ALL
;
466 info
->force_redraw
= true;
469 if (func(child
->children
[value
], info
))
472 needs_update
= needs_update
|| (last_value
!= value
);
474 info
->refresh_type
= old_refresh_mode
;
477 if (child
->tag
->flags
& NOBREAK
)
478 info
->no_line_break
= true;
479 if (child
->tag
->type
== SKIN_TOKEN_SUBLINE_SCROLL
)
480 info
->line_scrolls
= true;
482 fix_line_alignment(info
, child
);
488 if (!do_non_text_tags(info
->gwps
, info
, child
, &info
->skin_vp
->vp
))
490 static char tempbuf
[128];
491 const char *value
= get_token_value(info
->gwps
, child
->data
,
492 info
->offset
, tempbuf
,
493 sizeof(tempbuf
), NULL
);
497 if (child
->tag
->flags
&SKIN_RTC_REFRESH
)
498 needs_update
= needs_update
|| info
->refresh_type
&SKIN_REFRESH_DYNAMIC
;
500 needs_update
= needs_update
||
501 ((child
->tag
->flags
&info
->refresh_type
)!=0);
502 strlcat(info
->cur_align_start
, value
,
503 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
508 strlcat(info
->cur_align_start
, child
->data
,
509 info
->buf_size
- (info
->cur_align_start
-info
->buf
));
510 needs_update
= needs_update
||
511 (info
->refresh_type
&SKIN_REFRESH_STATIC
) != 0;
523 static int get_subline_timeout(struct gui_wps
*gwps
, struct skin_element
* line
)
525 struct skin_element
*element
=line
;
526 struct wps_token
*token
;
527 int retval
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
528 if (element
->type
== LINE
)
530 if (element
->children_count
== 0)
531 return retval
; /* empty line, so force redraw */
532 element
= element
->children
[0];
536 if (element
->type
== TAG
&&
537 element
->tag
->type
== SKIN_TOKEN_SUBLINE_TIMEOUT
)
539 token
= element
->data
;
540 return token
->value
.i
;
542 else if (element
->type
== CONDITIONAL
)
544 struct conditional
*conditional
= element
->data
;
545 int val
= evaluate_conditional(gwps
, 0, conditional
,
546 element
->children_count
);
549 retval
= get_subline_timeout(gwps
, element
->children
[val
]);
554 element
= element
->next
;
559 bool skin_render_alternator(struct skin_element
* element
, struct skin_draw_info
*info
)
561 bool changed_lines
= false;
562 struct line_alternator
*alternator
= (struct line_alternator
*)element
->data
;
563 unsigned old_refresh
= info
->refresh_type
;
564 if (info
->refresh_type
== SKIN_REFRESH_ALL
)
566 alternator
->current_line
= element
->children_count
-1;
567 changed_lines
= true;
569 else if (TIME_AFTER(current_tick
, alternator
->next_change_tick
))
571 changed_lines
= true;
576 struct skin_element
*current_line
;
577 int start
= alternator
->current_line
;
578 int try_line
= start
;
579 bool suitable
= false;
580 int rettimeout
= DEFAULT_SUBLINE_TIME_MULTIPLIER
*TIMEOUT_UNIT
;
582 /* find a subline which has at least one token in it,
583 * and that line doesnt have a timeout set to 0 through conditionals */
586 if (try_line
>= element
->children_count
)
588 if (element
->children
[try_line
]->children_count
!= 0)
590 current_line
= element
->children
[try_line
];
591 rettimeout
= get_subline_timeout(info
->gwps
,
592 current_line
->children
[0]);
599 while (try_line
!= start
&& !suitable
);
603 alternator
->current_line
= try_line
;
604 alternator
->next_change_tick
= current_tick
+ rettimeout
;
607 info
->refresh_type
= SKIN_REFRESH_ALL
;
608 info
->force_redraw
= true;
610 bool ret
= skin_render_line(element
->children
[alternator
->current_line
], info
);
611 info
->refresh_type
= old_refresh
;
612 return changed_lines
|| ret
;
615 static void skin_render_viewport(struct skin_element
* viewport
, struct gui_wps
*gwps
,
616 struct skin_viewport
* skin_viewport
, unsigned long refresh_type
)
618 struct screen
*display
= gwps
->display
;
619 char linebuf
[MAX_LINE
];
620 skin_render_func func
= skin_render_line
;
621 struct skin_element
* line
= viewport
;
622 struct skin_draw_info info
= {
625 .buf_size
= sizeof(linebuf
),
627 .no_line_break
= false,
628 .line_scrolls
= false,
629 .refresh_type
= refresh_type
,
630 .skin_vp
= skin_viewport
,
632 .text_style
= STYLE_DEFAULT
635 struct align_pos
* align
= &info
.align
;
637 #ifdef HAVE_LCD_BITMAP
638 /* Set images to not to be displayed */
639 struct skin_token_list
*imglist
= gwps
->data
->images
;
642 struct gui_img
*img
= (struct gui_img
*)imglist
->token
->value
.data
;
644 imglist
= imglist
->next
;
651 info
.no_line_break
= false;
652 info
.line_scrolls
= false;
653 info
.force_redraw
= false;
654 #ifdef HAVE_LCD_COLOR
655 if (info
.text_style
&STYLE_GRADIENT
)
657 int cur
= CURLN_UNPACK(info
.text_style
);
658 int num
= NUMLN_UNPACK(info
.text_style
);
660 info
.text_style
= STYLE_DEFAULT
;
662 info
.text_style
= STYLE_GRADIENT
|CURLN_PACK(cur
+1)|NUMLN_PACK(num
);
665 info
.cur_align_start
= info
.buf
;
666 align
->left
= info
.buf
;
667 align
->center
= NULL
;
671 if (line
->type
== LINE_ALTERNATOR
)
672 func
= skin_render_alternator
;
673 else if (line
->type
== LINE
)
674 func
= skin_render_line
;
676 needs_update
= func(line
, &info
);
677 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
678 if (skin_viewport
->vp
.fg_pattern
!= skin_viewport
->start_fgcolour
||
679 skin_viewport
->vp
.bg_pattern
!= skin_viewport
->start_bgcolour
)
681 /* 2bit lcd drivers need lcd_set_viewport() to be called to change
682 * the colour, 16bit doesnt. But doing this makes static text
683 * get the new colour also */
685 display
->set_viewport(&skin_viewport
->vp
);
688 /* only update if the line needs to be, and there is something to write */
689 if (refresh_type
&& needs_update
)
691 if (info
.line_scrolls
)
693 /* if the line is a scrolling one we don't want to update
694 too often, so that it has the time to scroll */
695 if ((refresh_type
& SKIN_REFRESH_SCROLL
) || info
.force_redraw
)
696 write_line(display
, align
, info
.line_number
, true, info
.text_style
);
699 write_line(display
, align
, info
.line_number
, false, info
.text_style
);
701 if (!info
.no_line_break
)
705 #ifdef HAVE_LCD_BITMAP
706 wps_display_images(gwps
, &skin_viewport
->vp
);
710 void skin_render(struct gui_wps
*gwps
, unsigned refresh_mode
)
712 struct wps_data
*data
= gwps
->data
;
713 struct screen
*display
= gwps
->display
;
715 struct skin_element
* viewport
;
716 struct skin_viewport
* skin_viewport
;
718 int old_refresh_mode
= refresh_mode
;
720 #ifdef HAVE_LCD_CHARCELLS
722 for (i
= 0; i
< 8; i
++)
724 if (data
->wps_progress_pat
[i
] == 0)
725 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
728 viewport
= data
->tree
;
729 skin_viewport
= (struct skin_viewport
*)viewport
->data
;
730 if (skin_viewport
->label
&& viewport
->next
&&
731 !strcmp(skin_viewport
->label
,VP_DEFAULT_LABEL
))
734 for (viewport
= data
->tree
;
736 viewport
= viewport
->next
)
739 skin_viewport
= (struct skin_viewport
*)viewport
->data
;
740 unsigned vp_refresh_mode
= refresh_mode
;
741 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
742 skin_viewport
->vp
.fg_pattern
= skin_viewport
->start_fgcolour
;
743 skin_viewport
->vp
.bg_pattern
= skin_viewport
->start_bgcolour
;
745 #ifdef HAVE_LCD_COLOR
746 skin_viewport
->vp
.lss_pattern
= skin_viewport
->start_gradient
.start
;
747 skin_viewport
->vp
.lse_pattern
= skin_viewport
->start_gradient
.end
;
748 skin_viewport
->vp
.lst_pattern
= skin_viewport
->start_gradient
.text
;
751 /* dont redraw the viewport if its disabled */
752 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
753 { /* don't draw anything into this one */
756 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
758 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
761 else if (((skin_viewport
->hidden_flags
&
762 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
763 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
765 vp_refresh_mode
= SKIN_REFRESH_ALL
;
766 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
769 display
->set_viewport(&skin_viewport
->vp
);
770 if ((vp_refresh_mode
&SKIN_REFRESH_ALL
) == SKIN_REFRESH_ALL
)
772 display
->clear_viewport();
775 if (viewport
->children_count
)
776 skin_render_viewport(viewport
->children
[0], gwps
,
777 skin_viewport
, vp_refresh_mode
);
778 refresh_mode
= old_refresh_mode
;
781 /* Restore the default viewport */
782 display
->set_viewport(NULL
);
786 #ifdef HAVE_LCD_BITMAP
787 static __attribute__((noinline
)) void skin_render_playlistviewer(struct playlistviewer
* viewer
,
788 struct gui_wps
*gwps
,
789 struct skin_viewport
* skin_viewport
,
790 unsigned long refresh_type
)
792 struct screen
*display
= gwps
->display
;
793 char linebuf
[MAX_LINE
];
794 skin_render_func func
= skin_render_line
;
795 struct skin_element
* line
;
796 struct skin_draw_info info
= {
799 .buf_size
= sizeof(linebuf
),
801 .no_line_break
= false,
802 .line_scrolls
= false,
803 .refresh_type
= refresh_type
,
804 .skin_vp
= skin_viewport
,
805 .offset
= viewer
->start_offset
,
806 .text_style
= STYLE_DEFAULT
809 struct align_pos
* align
= &info
.align
;
811 int cur_pos
, start_item
, max
;
812 int nb_lines
= viewport_get_nb_lines(viewer
->vp
);
814 if (get_current_activity() == ACTIVITY_FM
)
816 cur_pos
= radio_current_preset();
817 start_item
= cur_pos
+ viewer
->start_offset
;
818 max
= start_item
+radio_preset_count();
823 struct cuesheet
*cue
= skin_get_global_state()->id3
?
824 skin_get_global_state()->id3
->cuesheet
: NULL
;
825 cur_pos
= playlist_get_display_index();
826 max
= playlist_amount()+1;
828 max
+= cue
->track_count
;
829 start_item
= MAX(0, cur_pos
+ viewer
->start_offset
);
831 if (max
-start_item
> nb_lines
)
832 max
= start_item
+ nb_lines
;
835 while (start_item
< max
)
838 info
.no_line_break
= false;
839 info
.line_scrolls
= false;
840 info
.force_redraw
= false;
842 info
.cur_align_start
= info
.buf
;
843 align
->left
= info
.buf
;
844 align
->center
= NULL
;
848 if (line
->type
== LINE_ALTERNATOR
)
849 func
= skin_render_alternator
;
850 else if (line
->type
== LINE
)
851 func
= skin_render_line
;
853 needs_update
= func(line
, &info
);
855 /* only update if the line needs to be, and there is something to write */
856 if (refresh_type
&& needs_update
)
858 if (info
.line_scrolls
)
860 /* if the line is a scrolling one we don't want to update
861 too often, so that it has the time to scroll */
862 if ((refresh_type
& SKIN_REFRESH_SCROLL
) || info
.force_redraw
)
863 write_line(display
, align
, info
.line_number
, true, info
.text_style
);
866 write_line(display
, align
, info
.line_number
, false, info
.text_style
);