fix the last of the error
[maemo-rb.git] / apps / gui / skin_engine / skin_render.c
blob994ca23553fe4d1fcb8bdcc5856e15d962f6f032
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
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 ****************************************************************************/
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdbool.h>
26 #include <ctype.h>
27 #include "strlcat.h"
29 #include "config.h"
30 #include "kernel.h"
31 #ifdef HAVE_ALBUMART
32 #include "albumart.h"
33 #endif
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"
39 #if CONFIG_TUNER
40 #include "radio.h"
41 #endif
42 #include "viewport.h"
43 #include "cuesheet.h"
44 #include "language.h"
45 #include "playback.h"
46 #include "playlist.h"
47 #include "root_menu.h"
48 #include "misc.h"
49 #include "list.h"
52 #define MAX_LINE 1024
54 struct skin_draw_info {
55 struct gui_wps *gwps;
56 struct skin_viewport *skin_vp;
57 int line_number;
58 unsigned long refresh_type;
59 unsigned text_style;
61 char* cur_align_start;
62 struct align_pos align;
63 bool no_line_break;
64 bool line_scrolls;
65 bool force_redraw;
67 char *buf;
68 size_t buf_size;
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,
78 struct gui_wps *gwps,
79 struct skin_viewport* skin_viewport,
80 unsigned long refresh_type);
81 #endif
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 */
88 (void)info;
89 #endif
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;
95 #endif
96 switch (token->type)
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;
104 break;
105 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
107 struct viewport_colour *col = token->value.data;
108 col->vp->bg_pattern = col->colour;
110 break;
111 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE:
112 info->text_style = token->value.l;
113 break;
114 #endif
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;
123 break;
124 #endif
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;
130 while (viewport)
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;
145 break;
146 #ifdef HAVE_LCD_BITMAP
147 case SKIN_TOKEN_LIST_ITEM_CFG:
148 if (do_refresh)
149 skinlist_set_cfg(gwps->display->screen_type,
150 token->value.data);
151 break;
152 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
153 sb_set_info_vp(gwps->display->screen_type,
154 token->value.data);
155 break;
156 case SKIN_TOKEN_PEAKMETER:
157 data->peak_meter_enabled = true;
158 if (do_refresh)
159 draw_peakmeters(gwps, info->line_number, vp);
160 break;
161 #endif
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 */
167 #endif
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;
176 if (do_refresh)
177 draw_progressbar(gwps, info->line_number, bar);
179 #endif
180 break;
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;
194 else
196 char buf[16];
197 const char *out;
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! */
203 if (a == -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! */
207 else
208 a--;
209 a += id->offset;
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)
218 img->display = a;
222 break;
224 #ifdef HAVE_ALBUMART
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);
230 #if CONFIG_TUNER
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);
236 #endif
237 data->albumart->draw_handle = handle;
239 break;
240 #endif
241 case SKIN_TOKEN_DRAW_INBUILTBAR:
242 gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]),
243 info->refresh_type == SKIN_REFRESH_ALL,
244 token->value.data);
245 break;
246 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
247 if (do_refresh)
248 skin_render_playlistviewer(token->value.data, gwps,
249 info->skin_vp, info->refresh_type);
250 break;
252 #endif /* HAVE_LCD_BITMAP */
253 #ifdef HAVE_SKIN_VARIABLES
254 case SKIN_TOKEN_VAR_SET:
255 if (do_refresh)
257 struct skin_var_changer *data = token->value.data;
258 if (data->direct)
259 data->var->value = data->newval;
260 else
262 data->var->value += data->newval;
263 if (data->max)
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;
275 break;
276 #endif
277 default:
278 return false;
280 return true;
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;
291 #endif
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)
296 int i;
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;
306 while (child)
308 if (child->type == CONDITIONAL)
310 int i;
311 for (i=0; i<child->children_count; i++)
313 do_tags_in_hidden_conditional(child->children[i], info);
315 child = child->next;
316 continue;
318 else if (child->type != TAG || !child->data)
320 child = child->next;
321 continue;
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;
342 viewport;
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))
347 continue;
348 if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
350 continue;
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;
356 else
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;
367 #endif
368 #ifdef HAVE_ALBUMART
369 else if (data->albumart && token->type == SKIN_TOKEN_ALBUMART_DISPLAY)
371 draw_album_art(gwps,
372 playback_current_aa_hid(data->playback_aa_slot), true);
374 #endif
375 child = child->next;
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;
390 break;
391 case SKIN_TOKEN_ALIGN_LEFT_RTL:
392 *cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
393 if (lang_is_rtl())
394 align->right = cur_pos;
395 else
396 align->left = cur_pos;
397 info->cur_align_start = cur_pos;
398 break;
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;
403 break;
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;
408 break;
409 case SKIN_TOKEN_ALIGN_RIGHT_RTL:
410 *cur_pos = '\0'; cur_pos++; *cur_pos = '\0';
411 if (lang_is_rtl())
412 align->left = cur_pos;
413 else
414 align->right = cur_pos;
415 info->cur_align_start = cur_pos;
416 break;
417 default:
418 break;
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;
435 while (child)
437 switch (child->type)
439 case CONDITIONAL:
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 */
453 if (last_value == 0)
454 do_tags_in_hidden_conditional(child->children[0], info);
455 break;
458 else
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))
477 needs_update = true;
478 else
479 needs_update = needs_update || (last_value != value);
481 info->refresh_type = old_refresh_mode;
482 break;
483 case TAG:
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);
491 if (!child->data)
493 break;
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);
501 if (valuestr)
503 #if CONFIG_RTC
504 if (child->tag->flags&SKIN_RTC_REFRESH)
505 needs_update = needs_update || info->refresh_type&SKIN_REFRESH_DYNAMIC;
506 #endif
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));
513 break;
514 case TEXT:
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;
519 break;
520 case COMMENT:
521 default:
522 break;
525 child = child->next;
527 return needs_update;
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];
541 while (element)
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);
554 if (val >= 0)
556 retval = get_subline_timeout(gwps, element->children[val]);
557 if (retval >= 0)
558 return retval;
561 element = element->next;
563 return retval;
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;
581 if (changed_lines)
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 */
591 do {
592 try_line++;
593 if (try_line >= element->children_count)
594 try_line = 0;
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]);
600 if (rettimeout > 0)
602 suitable = true;
606 while (try_line != start && !suitable);
608 if (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 = {
630 .gwps = gwps,
631 .buf = linebuf,
632 .buf_size = sizeof(linebuf),
633 .line_number = 0,
634 .no_line_break = false,
635 .line_scrolls = false,
636 .refresh_type = refresh_type,
637 .skin_vp = skin_viewport,
638 .offset = 0,
639 .text_style = STYLE_DEFAULT
642 struct align_pos * align = &info.align;
643 bool needs_update;
644 #ifdef HAVE_LCD_BITMAP
645 /* Set images to not to be displayed */
646 struct skin_token_list *imglist = gwps->data->images;
647 while (imglist)
649 struct gui_img *img = (struct gui_img *)imglist->token->value.data;
650 img->display = -1;
651 imglist = imglist->next;
653 #endif
655 while (line)
657 linebuf[0] = '\0';
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);
666 if (cur+1 == num)
667 info.text_style = STYLE_DEFAULT;
668 else
669 info.text_style = STYLE_GRADIENT|CURLN_PACK(cur+1)|NUMLN_PACK(num);
671 #endif
672 info.cur_align_start = info.buf;
673 align->left = info.buf;
674 align->center = NULL;
675 align->right = 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 */
691 needs_update = true;
692 display->set_viewport(&skin_viewport->vp);
694 #endif
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);
705 else
706 write_line(display, align, info.line_number, false, info.text_style);
708 if (!info.no_line_break)
709 info.line_number++;
710 line = line->next;
712 #ifdef HAVE_LCD_BITMAP
713 wps_display_images(gwps, &skin_viewport->vp);
714 #endif
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
728 int i;
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();
734 #endif
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))
739 refresh_mode = 0;
741 for (viewport = data->tree;
742 viewport;
743 viewport = viewport->next)
745 /* SETUP */
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;
751 #endif
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;
756 #endif
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 */
761 vp_refresh_mode = 0;
763 else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN))
765 skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
766 continue;
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();
781 /* render */
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);
790 display->update();
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 = {
805 .gwps = gwps,
806 .buf = linebuf,
807 .buf_size = sizeof(linebuf),
808 .line_number = 0,
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;
818 bool needs_update;
819 int cur_pos, start_item, max;
820 int nb_lines = viewport_get_nb_lines(viewer->vp);
821 #if CONFIG_TUNER
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();
828 else
829 #endif
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;
835 if (cue)
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;
842 line = viewer->line;
843 while (start_item < max)
845 linebuf[0] = '\0';
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;
853 align->right = 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);
873 else
874 write_line(display, align, info.line_number, false, info.text_style);
876 info.line_number++;
877 info.offset++;
878 start_item++;
881 #endif