diff options
Diffstat (limited to 'apps/gui/skin_engine/skin_render.c')
-rw-r--r-- | apps/gui/skin_engine/skin_render.c | 614 |
1 files changed, 614 insertions, 0 deletions
diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c new file mode 100644 index 0000000000..e05f97ff4e --- /dev/null +++ b/apps/gui/skin_engine/skin_render.c | |||
@@ -0,0 +1,614 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: skin_parser.c 26752 2010-06-10 21:22:16Z bieber $ | ||
9 | * | ||
10 | * Copyright (C) 2010 Jonathan Gordon | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <stdlib.h> | ||
23 | #include <stdio.h> | ||
24 | #include <string.h> | ||
25 | #include <stdbool.h> | ||
26 | #include <ctype.h> | ||
27 | #include "strlcat.h" | ||
28 | |||
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 "language.h" | ||
43 | #include "playback.h" | ||
44 | |||
45 | |||
46 | #define MAX_LINE 1024 | ||
47 | |||
48 | struct skin_draw_info { | ||
49 | struct gui_wps *gwps; | ||
50 | struct skin_viewport *skin_vp; | ||
51 | int line_number; | ||
52 | unsigned long refresh_type; | ||
53 | |||
54 | char* cur_align_start; | ||
55 | struct align_pos align; | ||
56 | bool no_line_break; | ||
57 | bool line_scrolls; | ||
58 | bool force_redraw; | ||
59 | |||
60 | char *buf; | ||
61 | size_t buf_size; | ||
62 | }; | ||
63 | |||
64 | typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info); | ||
65 | bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info); | ||
66 | |||
67 | |||
68 | static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info, | ||
69 | struct skin_element *element, struct viewport* vp) | ||
70 | { | ||
71 | #ifndef HAVE_LCD_BITMAP | ||
72 | (void)vp; /* silence warnings */ | ||
73 | #endif | ||
74 | struct wps_token *token = (struct wps_token *)element->data; | ||
75 | struct wps_data *data = gwps->data; | ||
76 | bool do_refresh = (element->tag->flags & info->refresh_type) > 0; | ||
77 | switch (token->type) | ||
78 | { | ||
79 | #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) | ||
80 | case SKIN_TOKEN_VIEWPORT_FGCOLOUR: | ||
81 | { | ||
82 | struct viewport_colour *col = token->value.data; | ||
83 | col->vp->fg_pattern = col->colour; | ||
84 | } | ||
85 | break; | ||
86 | case SKIN_TOKEN_VIEWPORT_BGCOLOUR: | ||
87 | { | ||
88 | struct viewport_colour *col = token->value.data; | ||
89 | col->vp->bg_pattern = col->colour; | ||
90 | } | ||
91 | break; | ||
92 | #endif | ||
93 | case SKIN_TOKEN_VIEWPORT_ENABLE: | ||
94 | { | ||
95 | char label = token->value.i; | ||
96 | char temp = VP_DRAW_HIDEABLE; | ||
97 | struct skin_element *viewport = gwps->data->tree; | ||
98 | while (viewport) | ||
99 | { | ||
100 | struct skin_viewport *skinvp = (struct skin_viewport*)viewport->data; | ||
101 | if (skinvp->label == label) | ||
102 | { | ||
103 | if (skinvp->hidden_flags&VP_DRAW_HIDDEN) | ||
104 | { | ||
105 | temp |= VP_DRAW_WASHIDDEN; | ||
106 | } | ||
107 | skinvp->hidden_flags = temp; | ||
108 | } | ||
109 | viewport = viewport->next; | ||
110 | } | ||
111 | } | ||
112 | break; | ||
113 | #ifdef HAVE_LCD_BITMAP | ||
114 | case SKIN_TOKEN_UIVIEWPORT_ENABLE: | ||
115 | sb_set_info_vp(gwps->display->screen_type, | ||
116 | token->value.i|VP_INFO_LABEL); | ||
117 | break; | ||
118 | case SKIN_TOKEN_PEAKMETER: | ||
119 | data->peak_meter_enabled = true; | ||
120 | if (do_refresh) | ||
121 | draw_peakmeters(gwps, info->line_number, vp); | ||
122 | break; | ||
123 | #endif | ||
124 | case SKIN_TOKEN_VOLUMEBAR: | ||
125 | case SKIN_TOKEN_BATTERY_PERCENTBAR: | ||
126 | case SKIN_TOKEN_PROGRESSBAR: | ||
127 | { | ||
128 | #ifdef HAVE_LCD_BITMAP | ||
129 | struct progressbar *bar = (struct progressbar*)token->value.data; | ||
130 | if (do_refresh) | ||
131 | draw_progressbar(gwps, info->line_number, bar); | ||
132 | #else /* HAVE_LCD_CHARCELL */ | ||
133 | if (do_refresh) | ||
134 | { | ||
135 | if (data->full_line_progressbar) | ||
136 | draw_player_fullbar(gwps, info->buf, info->buf_size); | ||
137 | else | ||
138 | draw_player_progress(gwps); | ||
139 | } | ||
140 | #endif | ||
141 | } | ||
142 | break; | ||
143 | #ifdef HAVE_LCD_BITMAP | ||
144 | case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: | ||
145 | { | ||
146 | char n = token->value.i & 0xFF; | ||
147 | int subimage = token->value.i >> 8; | ||
148 | struct gui_img *img = find_image(n, data); | ||
149 | if (img && img->loaded) | ||
150 | img->display = subimage; | ||
151 | break; | ||
152 | } | ||
153 | #ifdef HAVE_ALBUMART | ||
154 | case SKIN_TOKEN_ALBUMART_DISPLAY: | ||
155 | /* now draw the AA */ | ||
156 | if (data->albumart) | ||
157 | { | ||
158 | int handle = playback_current_aa_hid(data->playback_aa_slot); | ||
159 | #if CONFIG_TUNER | ||
160 | if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) | ||
161 | { | ||
162 | struct dim dim = {data->albumart->width, data->albumart->height}; | ||
163 | handle = radio_get_art_hid(&dim); | ||
164 | } | ||
165 | #endif | ||
166 | data->albumart->draw_handle = handle; | ||
167 | } | ||
168 | break; | ||
169 | #endif | ||
170 | case SKIN_TOKEN_DRAW_INBUILTBAR: | ||
171 | gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]), | ||
172 | info->refresh_type == SKIN_REFRESH_ALL, | ||
173 | token->value.data); | ||
174 | break; | ||
175 | case SKIN_TOKEN_VIEWPORT_CUSTOMLIST: | ||
176 | if (do_refresh) | ||
177 | draw_playlist_viewer_list(gwps, token->value.data); | ||
178 | break; | ||
179 | |||
180 | #endif /* HAVE_LCD_BITMAP */ | ||
181 | default: | ||
182 | return false; | ||
183 | } | ||
184 | return true; | ||
185 | } | ||
186 | |||
187 | |||
188 | |||
189 | static void do_tags_in_hidden_conditional(struct skin_element* branch, | ||
190 | struct skin_draw_info *info) | ||
191 | { | ||
192 | #ifdef HAVE_LCD_BITMAP | ||
193 | struct gui_wps *gwps = info->gwps; | ||
194 | struct wps_data *data = gwps->data; | ||
195 | #endif | ||
196 | /* Tags here are ones which need to be "turned off" or cleared | ||
197 | * if they are in a conditional branch which isnt being used */ | ||
198 | if (branch->type == LINE_ALTERNATOR) | ||
199 | { | ||
200 | int i; | ||
201 | for (i=0; i<branch->children_count; i++) | ||
202 | { | ||
203 | do_tags_in_hidden_conditional(branch->children[i], info); | ||
204 | } | ||
205 | } | ||
206 | else if (branch->type == LINE && branch->children_count) | ||
207 | { | ||
208 | struct skin_element *child = branch->children[0]; | ||
209 | struct wps_token *token; | ||
210 | while (child) | ||
211 | { | ||
212 | if (child->type == CONDITIONAL) | ||
213 | { | ||
214 | int i; | ||
215 | for (i=0; i<child->children_count; i++) | ||
216 | { | ||
217 | do_tags_in_hidden_conditional(child->children[i], info); | ||
218 | } | ||
219 | child = child->next; | ||
220 | continue; | ||
221 | } | ||
222 | else if (child->type != TAG || !child->data) | ||
223 | { | ||
224 | child = child->next; | ||
225 | continue; | ||
226 | } | ||
227 | token = (struct wps_token *)child->data; | ||
228 | #ifdef HAVE_LCD_BITMAP | ||
229 | /* clear all pictures in the conditional and nested ones */ | ||
230 | if (token->type == SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY) | ||
231 | { | ||
232 | struct gui_img *img = find_image(token->value.i&0xFF, data); | ||
233 | clear_image_pos(gwps, img); | ||
234 | } | ||
235 | else if (token->type == SKIN_TOKEN_PEAKMETER) | ||
236 | { | ||
237 | data->peak_meter_enabled = false; | ||
238 | } | ||
239 | else if (token->type == SKIN_TOKEN_VIEWPORT_ENABLE) | ||
240 | { | ||
241 | char label = token->value.i&0x7f; | ||
242 | struct skin_element *viewport; | ||
243 | for (viewport = data->tree; | ||
244 | viewport; | ||
245 | viewport = viewport->next) | ||
246 | { | ||
247 | struct skin_viewport *skin_viewport = (struct skin_viewport*)viewport->data; | ||
248 | if ((skin_viewport->label&0x7f) != label) | ||
249 | continue; | ||
250 | if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) | ||
251 | { | ||
252 | continue; | ||
253 | } | ||
254 | if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE) | ||
255 | { | ||
256 | if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN) | ||
257 | skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; | ||
258 | else | ||
259 | { | ||
260 | gwps->display->set_viewport(&skin_viewport->vp); | ||
261 | gwps->display->clear_viewport(); | ||
262 | gwps->display->scroll_stop(&skin_viewport->vp); | ||
263 | gwps->display->set_viewport(&info->skin_vp->vp); | ||
264 | skin_viewport->hidden_flags |= VP_DRAW_HIDDEN; | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | #endif | ||
270 | #ifdef HAVE_ALBUMART | ||
271 | else if (data->albumart && token->type == SKIN_TOKEN_ALBUMART_DISPLAY) | ||
272 | { | ||
273 | draw_album_art(gwps, | ||
274 | playback_current_aa_hid(data->playback_aa_slot), true); | ||
275 | } | ||
276 | #endif | ||
277 | child = child->next; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static void fix_line_alignment(struct skin_draw_info *info, struct skin_element *element) | ||
283 | { | ||
284 | struct align_pos *align = &info->align; | ||
285 | char *cur_pos = info->cur_align_start + strlen(info->cur_align_start); | ||
286 | switch (element->tag->type) | ||
287 | { | ||
288 | case SKIN_TOKEN_ALIGN_LEFT: | ||
289 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; | ||
290 | align->left = cur_pos; | ||
291 | info->cur_align_start = cur_pos; | ||
292 | break; | ||
293 | case SKIN_TOKEN_ALIGN_LEFT_RTL: | ||
294 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; | ||
295 | if (lang_is_rtl()) | ||
296 | align->right = cur_pos; | ||
297 | else | ||
298 | align->left = cur_pos; | ||
299 | info->cur_align_start = cur_pos; | ||
300 | break; | ||
301 | case SKIN_TOKEN_ALIGN_CENTER: | ||
302 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; | ||
303 | align->center = cur_pos; | ||
304 | info->cur_align_start = cur_pos; | ||
305 | break; | ||
306 | case SKIN_TOKEN_ALIGN_RIGHT: | ||
307 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; | ||
308 | align->right = cur_pos; | ||
309 | info->cur_align_start = cur_pos; | ||
310 | break; | ||
311 | case SKIN_TOKEN_ALIGN_RIGHT_RTL: | ||
312 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; | ||
313 | if (lang_is_rtl()) | ||
314 | align->left = cur_pos; | ||
315 | else | ||
316 | align->right = cur_pos; | ||
317 | info->cur_align_start = cur_pos; | ||
318 | break; | ||
319 | default: | ||
320 | break; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | /* Draw a LINE element onto the display */ | ||
325 | bool skin_render_line(struct skin_element* line, struct skin_draw_info *info) | ||
326 | { | ||
327 | bool needs_update = false; | ||
328 | int last_value, value; | ||
329 | |||
330 | if (line->children_count == 0) | ||
331 | return false; /* empty line, do nothing */ | ||
332 | |||
333 | struct skin_element *child = line->children[0]; | ||
334 | struct conditional *conditional; | ||
335 | skin_render_func func = skin_render_line; | ||
336 | char tempbuf[128]; | ||
337 | int old_refresh_mode = info->refresh_type; | ||
338 | while (child) | ||
339 | { | ||
340 | tempbuf[0] = '\0'; | ||
341 | switch (child->type) | ||
342 | { | ||
343 | case CONDITIONAL: | ||
344 | conditional = (struct conditional*)child->data; | ||
345 | last_value = conditional->last_value; | ||
346 | value = evaluate_conditional(info->gwps, conditional, child->children_count); | ||
347 | |||
348 | if (value != 1 && value >= child->children_count) | ||
349 | value = child->children_count-1; | ||
350 | if (child->children_count == 1) | ||
351 | { | ||
352 | /* special handling so | ||
353 | * %?aa<true> and %?<true|false> need special handlng here */ | ||
354 | |||
355 | if (value == 1) /* tag is false */ | ||
356 | { | ||
357 | /* we are in a false branch of a %?aa<true> conditional */ | ||
358 | if (last_value == 0) | ||
359 | do_tags_in_hidden_conditional(child->children[0], info); | ||
360 | break; | ||
361 | } | ||
362 | value = 0; | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | if (last_value >= 0 && value != last_value && last_value < child->children_count) | ||
367 | do_tags_in_hidden_conditional(child->children[last_value], info); | ||
368 | } | ||
369 | if (child->children[value]->type == LINE_ALTERNATOR) | ||
370 | { | ||
371 | func = skin_render_alternator; | ||
372 | } | ||
373 | else if (child->children[value]->type == LINE) | ||
374 | func = skin_render_line; | ||
375 | |||
376 | if (value != last_value) | ||
377 | { | ||
378 | info->refresh_type = SKIN_REFRESH_ALL; | ||
379 | info->force_redraw = true; | ||
380 | } | ||
381 | |||
382 | if (func(child->children[value], info)) | ||
383 | needs_update = true; | ||
384 | else | ||
385 | needs_update = needs_update || (last_value != value); | ||
386 | |||
387 | info->refresh_type = old_refresh_mode; | ||
388 | break; | ||
389 | case TAG: | ||
390 | if (child->tag->flags & NOBREAK) | ||
391 | info->no_line_break = true; | ||
392 | if (child->tag->type == SKIN_TOKEN_SUBLINE_SCROLL) | ||
393 | info->line_scrolls = true; | ||
394 | |||
395 | fix_line_alignment(info, child); | ||
396 | |||
397 | if (!child->data) | ||
398 | { | ||
399 | break; | ||
400 | } | ||
401 | if (!do_non_text_tags(info->gwps, info, child, &info->skin_vp->vp)) | ||
402 | { | ||
403 | const char *value = get_token_value(info->gwps, child->data, | ||
404 | tempbuf, sizeof(tempbuf), NULL); | ||
405 | if (value) | ||
406 | { | ||
407 | needs_update = needs_update || | ||
408 | ((child->tag->flags&info->refresh_type)!=0); | ||
409 | strlcat(info->cur_align_start, value, | ||
410 | info->buf_size - (info->cur_align_start-info->buf)); | ||
411 | } | ||
412 | } | ||
413 | break; | ||
414 | case TEXT: | ||
415 | strlcat(info->cur_align_start, child->data, | ||
416 | info->buf_size - (info->cur_align_start-info->buf)); | ||
417 | needs_update = needs_update || | ||
418 | (info->refresh_type&SKIN_REFRESH_STATIC) != 0; | ||
419 | break; | ||
420 | case COMMENT: | ||
421 | default: | ||
422 | break; | ||
423 | } | ||
424 | |||
425 | child = child->next; | ||
426 | } | ||
427 | return needs_update; | ||
428 | } | ||
429 | |||
430 | bool skin_render_alternator(struct skin_element* element, struct skin_draw_info *info) | ||
431 | { | ||
432 | bool changed_lines = false; | ||
433 | struct line_alternator *alternator = (struct line_alternator*)element->data; | ||
434 | unsigned old_refresh = info->refresh_type; | ||
435 | if (info->refresh_type == SKIN_REFRESH_ALL) | ||
436 | { | ||
437 | alternator->current_line = 0; | ||
438 | alternator->last_change_tick = current_tick; | ||
439 | changed_lines = true; | ||
440 | } | ||
441 | else | ||
442 | { | ||
443 | struct skin_element *current_line = element->children[alternator->current_line]; | ||
444 | struct line *line = (struct line *)current_line->data; | ||
445 | int next_change = alternator->last_change_tick + line->timeout; | ||
446 | if (TIME_AFTER(current_tick, next_change)) | ||
447 | { | ||
448 | alternator->current_line++; | ||
449 | if (alternator->current_line >= element->children_count) | ||
450 | alternator->current_line = 0; | ||
451 | alternator->last_change_tick = current_tick; | ||
452 | changed_lines = true; | ||
453 | } | ||
454 | } | ||
455 | if (element->children[alternator->current_line]->children_count == 0) | ||
456 | { | ||
457 | /* skip empty sublines */ | ||
458 | alternator->current_line++; | ||
459 | if (alternator->current_line >= element->children_count) | ||
460 | alternator->current_line = 0; | ||
461 | changed_lines = true; | ||
462 | } | ||
463 | |||
464 | if (changed_lines) | ||
465 | { | ||
466 | info->refresh_type = SKIN_REFRESH_ALL; | ||
467 | info->force_redraw = true; | ||
468 | } | ||
469 | bool ret = skin_render_line(element->children[alternator->current_line], info); | ||
470 | info->refresh_type = old_refresh; | ||
471 | return changed_lines || ret; | ||
472 | } | ||
473 | |||
474 | void skin_render_viewport(struct skin_element* viewport, struct gui_wps *gwps, | ||
475 | struct skin_viewport* skin_viewport, unsigned long refresh_type) | ||
476 | { | ||
477 | struct screen *display = gwps->display; | ||
478 | char linebuf[MAX_LINE]; | ||
479 | skin_render_func func = skin_render_line; | ||
480 | struct skin_element* line = viewport; | ||
481 | struct skin_draw_info info = { | ||
482 | .gwps = gwps, | ||
483 | .buf = linebuf, | ||
484 | .buf_size = sizeof(linebuf), | ||
485 | .line_number = 0, | ||
486 | .no_line_break = false, | ||
487 | .line_scrolls = false, | ||
488 | .refresh_type = refresh_type, | ||
489 | .skin_vp = skin_viewport | ||
490 | }; | ||
491 | |||
492 | struct align_pos * align = &info.align; | ||
493 | bool needs_update; | ||
494 | #ifdef HAVE_LCD_BITMAP | ||
495 | /* Set images to not to be displayed */ | ||
496 | struct skin_token_list *imglist = gwps->data->images; | ||
497 | while (imglist) | ||
498 | { | ||
499 | struct gui_img *img = (struct gui_img *)imglist->token->value.data; | ||
500 | img->display = -1; | ||
501 | imglist = imglist->next; | ||
502 | } | ||
503 | #endif | ||
504 | |||
505 | while (line) | ||
506 | { | ||
507 | linebuf[0] = '\0'; | ||
508 | info.no_line_break = false; | ||
509 | info.line_scrolls = false; | ||
510 | info.force_redraw = false; | ||
511 | |||
512 | info.cur_align_start = info.buf; | ||
513 | align->left = info.buf; | ||
514 | align->center = NULL; | ||
515 | align->right = NULL; | ||
516 | |||
517 | |||
518 | if (line->type == LINE_ALTERNATOR) | ||
519 | func = skin_render_alternator; | ||
520 | else if (line->type == LINE) | ||
521 | func = skin_render_line; | ||
522 | |||
523 | needs_update = func(line, &info); | ||
524 | |||
525 | /* only update if the line needs to be, and there is something to write */ | ||
526 | if (refresh_type && needs_update) | ||
527 | { | ||
528 | if (info.line_scrolls) | ||
529 | { | ||
530 | /* if the line is a scrolling one we don't want to update | ||
531 | too often, so that it has the time to scroll */ | ||
532 | if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw) | ||
533 | write_line(display, align, info.line_number, true); | ||
534 | } | ||
535 | else | ||
536 | write_line(display, align, info.line_number, false); | ||
537 | } | ||
538 | if (!info.no_line_break) | ||
539 | info.line_number++; | ||
540 | line = line->next; | ||
541 | } | ||
542 | #ifdef HAVE_LCD_BITMAP | ||
543 | wps_display_images(gwps, &skin_viewport->vp); | ||
544 | #endif | ||
545 | } | ||
546 | |||
547 | void skin_render(struct gui_wps *gwps, unsigned refresh_mode) | ||
548 | { | ||
549 | struct wps_data *data = gwps->data; | ||
550 | struct screen *display = gwps->display; | ||
551 | |||
552 | struct skin_element* viewport = data->tree; | ||
553 | struct skin_viewport* skin_viewport; | ||
554 | |||
555 | int old_refresh_mode = refresh_mode; | ||
556 | |||
557 | #ifdef HAVE_LCD_CHARCELLS | ||
558 | int i; | ||
559 | for (i = 0; i < 8; i++) | ||
560 | { | ||
561 | if (data->wps_progress_pat[i] == 0) | ||
562 | data->wps_progress_pat[i] = display->get_locked_pattern(); | ||
563 | } | ||
564 | #endif | ||
565 | viewport = data->tree; | ||
566 | skin_viewport = (struct skin_viewport *)viewport->data; | ||
567 | if (skin_viewport->label == VP_DEFAULT_LABEL && viewport->next) | ||
568 | refresh_mode = 0; | ||
569 | |||
570 | for (viewport = data->tree; | ||
571 | viewport; | ||
572 | viewport = viewport->next) | ||
573 | { | ||
574 | /* SETUP */ | ||
575 | skin_viewport = (struct skin_viewport*)viewport->data; | ||
576 | unsigned vp_refresh_mode = refresh_mode; | ||
577 | #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
578 | skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour; | ||
579 | skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour; | ||
580 | #endif | ||
581 | |||
582 | /* dont redraw the viewport if its disabled */ | ||
583 | if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) | ||
584 | { /* don't draw anything into this one */ | ||
585 | vp_refresh_mode = 0; | ||
586 | } | ||
587 | else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN)) | ||
588 | { | ||
589 | skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; | ||
590 | continue; | ||
591 | } | ||
592 | else if (((skin_viewport->hidden_flags& | ||
593 | (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)) | ||
594 | == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))) | ||
595 | { | ||
596 | vp_refresh_mode = SKIN_REFRESH_ALL; | ||
597 | skin_viewport->hidden_flags = VP_DRAW_HIDEABLE; | ||
598 | } | ||
599 | |||
600 | display->set_viewport(&skin_viewport->vp); | ||
601 | if ((vp_refresh_mode&SKIN_REFRESH_ALL) == SKIN_REFRESH_ALL) | ||
602 | { | ||
603 | display->clear_viewport(); | ||
604 | } | ||
605 | /* render */ | ||
606 | skin_render_viewport(viewport->children[0], gwps, | ||
607 | skin_viewport, vp_refresh_mode); | ||
608 | refresh_mode = old_refresh_mode; | ||
609 | } | ||
610 | |||
611 | /* Restore the default viewport */ | ||
612 | display->set_viewport(NULL); | ||
613 | display->update(); | ||
614 | } | ||