diff options
Diffstat (limited to 'apps/gui/skin_engine/skin_display.c')
-rw-r--r-- | apps/gui/skin_engine/skin_display.c | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c new file mode 100644 index 0000000000..bf342116a6 --- /dev/null +++ b/apps/gui/skin_engine/skin_display.c | |||
@@ -0,0 +1,1127 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002-2007 Björn Stenberg | ||
11 | * Copyright (C) 2007-2008 Nicolas Pennequin | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "font.h" | ||
23 | #include <stdio.h> | ||
24 | #include <string.h> | ||
25 | #include <stdlib.h> | ||
26 | #include "system.h" | ||
27 | #include "settings.h" | ||
28 | #include "settings_list.h" | ||
29 | #include "rbunicode.h" | ||
30 | #include "rtc.h" | ||
31 | #include "audio.h" | ||
32 | #include "status.h" | ||
33 | #include "power.h" | ||
34 | #include "powermgmt.h" | ||
35 | #include "sound.h" | ||
36 | #include "debug.h" | ||
37 | #ifdef HAVE_LCD_CHARCELLS | ||
38 | #include "hwcompat.h" | ||
39 | #endif | ||
40 | #include "abrepeat.h" | ||
41 | #include "mp3_playback.h" | ||
42 | #include "lang.h" | ||
43 | #include "misc.h" | ||
44 | #include "splash.h" | ||
45 | #include "scrollbar.h" | ||
46 | #include "led.h" | ||
47 | #include "lcd.h" | ||
48 | #ifdef HAVE_LCD_BITMAP | ||
49 | #include "peakmeter.h" | ||
50 | /* Image stuff */ | ||
51 | #include "bmp.h" | ||
52 | #include "albumart.h" | ||
53 | #endif | ||
54 | #include "dsp.h" | ||
55 | #include "action.h" | ||
56 | #include "cuesheet.h" | ||
57 | #include "playlist.h" | ||
58 | #if CONFIG_CODEC == SWCODEC | ||
59 | #include "playback.h" | ||
60 | #endif | ||
61 | #include "backdrop.h" | ||
62 | #include "viewport.h" | ||
63 | |||
64 | |||
65 | #include "wps_internals.h" | ||
66 | #include "skin_engine.h" | ||
67 | |||
68 | static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode); | ||
69 | |||
70 | |||
71 | #ifdef HAVE_LCD_BITMAP | ||
72 | /* Clear the WPS image cache */ | ||
73 | static void wps_images_clear(struct wps_data *data) | ||
74 | { | ||
75 | int i; | ||
76 | /* set images to unloaded and not displayed */ | ||
77 | for (i = 0; i < MAX_IMAGES; i++) | ||
78 | { | ||
79 | data->img[i].loaded = false; | ||
80 | data->img[i].display = -1; | ||
81 | data->img[i].always_display = false; | ||
82 | data->img[i].num_subimages = 1; | ||
83 | } | ||
84 | } | ||
85 | #endif | ||
86 | |||
87 | /* initial setup of wps_data */ | ||
88 | void skin_data_init(struct wps_data *wps_data) | ||
89 | { | ||
90 | #ifdef HAVE_LCD_BITMAP | ||
91 | wps_images_clear(wps_data); | ||
92 | wps_data->wps_sb_tag = false; | ||
93 | wps_data->show_sb_on_wps = false; | ||
94 | wps_data->img_buf_ptr = wps_data->img_buf; /* where in image buffer */ | ||
95 | wps_data->img_buf_free = IMG_BUFSIZE; /* free space in image buffer */ | ||
96 | wps_data->peak_meter_enabled = false; | ||
97 | /* progress bars */ | ||
98 | wps_data->progressbar_count = 0; | ||
99 | #else /* HAVE_LCD_CHARCELLS */ | ||
100 | int i; | ||
101 | for (i = 0; i < 8; i++) | ||
102 | { | ||
103 | wps_data->wps_progress_pat[i] = 0; | ||
104 | } | ||
105 | wps_data->full_line_progressbar = false; | ||
106 | #endif | ||
107 | wps_data->button_time_volume = 0; | ||
108 | wps_data->wps_loaded = false; | ||
109 | } | ||
110 | |||
111 | /* TODO: maybe move this whole function into wps.c instead ? */ | ||
112 | bool gui_wps_display(struct gui_wps *gwps) | ||
113 | { | ||
114 | struct screen *display = gwps->display; | ||
115 | |||
116 | /* Update the values in the first (default) viewport - in case the user | ||
117 | has modified the statusbar or colour settings */ | ||
118 | #if LCD_DEPTH > 1 | ||
119 | if (display->depth > 1) | ||
120 | { | ||
121 | gwps->data->viewports[0].vp.fg_pattern = display->get_foreground(); | ||
122 | gwps->data->viewports[0].vp.bg_pattern = display->get_background(); | ||
123 | } | ||
124 | #endif | ||
125 | display->clear_display(); | ||
126 | display->backdrop_show(BACKDROP_SKIN_WPS); | ||
127 | return skin_redraw(gwps, WPS_REFRESH_ALL); | ||
128 | } | ||
129 | |||
130 | /* update a skinned screen, update_type is WPS_REFRESH_* values. | ||
131 | * Usually it should only be WPS_REFRESH_NON_STATIC | ||
132 | * A full update will be done if required (state.do_full_update == true) | ||
133 | */ | ||
134 | bool skin_update(struct gui_wps *gwps, unsigned int update_type) | ||
135 | { | ||
136 | bool retval; | ||
137 | /* This maybe shouldnt be here, but while the skin is only used to | ||
138 | * display the music screen this is better than whereever we are being | ||
139 | * called from. This is also safe for skined screen which dont use the id3 */ | ||
140 | struct mp3entry *id3 = gwps->state->id3; | ||
141 | bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false); | ||
142 | gwps->state->do_full_update = cuesheet_update || gwps->state->do_full_update; | ||
143 | |||
144 | retval = skin_redraw(gwps, gwps->state->do_full_update ? | ||
145 | WPS_REFRESH_ALL : update_type); | ||
146 | return retval; | ||
147 | } | ||
148 | |||
149 | |||
150 | #ifdef HAVE_LCD_BITMAP | ||
151 | |||
152 | static void draw_progressbar(struct gui_wps *gwps, | ||
153 | struct wps_viewport *wps_vp) | ||
154 | { | ||
155 | struct screen *display = gwps->display; | ||
156 | struct wps_state *state = gwps->state; | ||
157 | struct progressbar *pb = wps_vp->pb; | ||
158 | int y = pb->y; | ||
159 | |||
160 | if (y < 0) | ||
161 | { | ||
162 | int line_height = font_get(wps_vp->vp.font)->height; | ||
163 | /* center the pb in the line, but only if the line is higher than the pb */ | ||
164 | int center = (line_height-pb->height)/2; | ||
165 | /* if Y was not set calculate by font height,Y is -line_number-1 */ | ||
166 | y = (-y -1)*line_height + (0 > center ? 0 : center); | ||
167 | } | ||
168 | |||
169 | if (pb->have_bitmap_pb) | ||
170 | gui_bitmap_scrollbar_draw(display, pb->bm, | ||
171 | pb->x, y, pb->width, pb->bm.height, | ||
172 | state->id3->length ? state->id3->length : 1, 0, | ||
173 | state->id3->length ? state->id3->elapsed | ||
174 | + state->ff_rewind_count : 0, | ||
175 | HORIZONTAL); | ||
176 | else | ||
177 | gui_scrollbar_draw(display, pb->x, y, pb->width, pb->height, | ||
178 | state->id3->length ? state->id3->length : 1, 0, | ||
179 | state->id3->length ? state->id3->elapsed | ||
180 | + state->ff_rewind_count : 0, | ||
181 | HORIZONTAL); | ||
182 | #ifdef AB_REPEAT_ENABLE | ||
183 | if ( ab_repeat_mode_enabled() && state->id3->length != 0 ) | ||
184 | ab_draw_markers(display, state->id3->length, | ||
185 | pb->x, pb->x + pb->width, y, pb->height); | ||
186 | #endif | ||
187 | |||
188 | if (state->id3->cuesheet) | ||
189 | cue_draw_markers(display, state->id3->cuesheet, state->id3->length, | ||
190 | pb->x, pb->x + pb->width, y+1, pb->height-2); | ||
191 | } | ||
192 | |||
193 | /* clears the area where the image was shown */ | ||
194 | static void clear_image_pos(struct gui_wps *gwps, int n) | ||
195 | { | ||
196 | if(!gwps) | ||
197 | return; | ||
198 | struct wps_data *data = gwps->data; | ||
199 | gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | ||
200 | gwps->display->fillrect(data->img[n].x, data->img[n].y, | ||
201 | data->img[n].bm.width, data->img[n].subimage_height); | ||
202 | gwps->display->set_drawmode(DRMODE_SOLID); | ||
203 | } | ||
204 | |||
205 | static void wps_draw_image(struct gui_wps *gwps, int n, int subimage) | ||
206 | { | ||
207 | struct screen *display = gwps->display; | ||
208 | struct wps_data *data = gwps->data; | ||
209 | if(data->img[n].always_display) | ||
210 | display->set_drawmode(DRMODE_FG); | ||
211 | else | ||
212 | display->set_drawmode(DRMODE_SOLID); | ||
213 | |||
214 | #if LCD_DEPTH > 1 | ||
215 | if(data->img[n].bm.format == FORMAT_MONO) { | ||
216 | #endif | ||
217 | display->mono_bitmap_part(data->img[n].bm.data, | ||
218 | 0, data->img[n].subimage_height * subimage, | ||
219 | data->img[n].bm.width, data->img[n].x, | ||
220 | data->img[n].y, data->img[n].bm.width, | ||
221 | data->img[n].subimage_height); | ||
222 | #if LCD_DEPTH > 1 | ||
223 | } else { | ||
224 | display->transparent_bitmap_part((fb_data *)data->img[n].bm.data, | ||
225 | 0, data->img[n].subimage_height * subimage, | ||
226 | data->img[n].bm.width, data->img[n].x, | ||
227 | data->img[n].y, data->img[n].bm.width, | ||
228 | data->img[n].subimage_height); | ||
229 | } | ||
230 | #endif | ||
231 | } | ||
232 | |||
233 | static void wps_display_images(struct gui_wps *gwps, struct viewport* vp) | ||
234 | { | ||
235 | if(!gwps || !gwps->data || !gwps->display) | ||
236 | return; | ||
237 | |||
238 | int n; | ||
239 | struct wps_data *data = gwps->data; | ||
240 | struct screen *display = gwps->display; | ||
241 | |||
242 | for (n = 0; n < MAX_IMAGES; n++) | ||
243 | { | ||
244 | if (data->img[n].loaded) | ||
245 | { | ||
246 | if (data->img[n].display >= 0) | ||
247 | { | ||
248 | wps_draw_image(gwps, n, data->img[n].display); | ||
249 | } else if (data->img[n].always_display && data->img[n].vp == vp) | ||
250 | { | ||
251 | wps_draw_image(gwps, n, 0); | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | display->set_drawmode(DRMODE_SOLID); | ||
256 | } | ||
257 | |||
258 | #else /* HAVE_LCD_CHARCELL */ | ||
259 | |||
260 | static bool draw_player_progress(struct gui_wps *gwps) | ||
261 | { | ||
262 | struct wps_state *state = gwps->state; | ||
263 | struct screen *display = gwps->display; | ||
264 | unsigned char progress_pattern[7]; | ||
265 | int pos = 0; | ||
266 | int i; | ||
267 | |||
268 | if (!state->id3) | ||
269 | return false; | ||
270 | |||
271 | if (state->id3->length) | ||
272 | pos = 36 * (state->id3->elapsed + state->ff_rewind_count) | ||
273 | / state->id3->length; | ||
274 | |||
275 | for (i = 0; i < 7; i++, pos -= 5) | ||
276 | { | ||
277 | if (pos <= 0) | ||
278 | progress_pattern[i] = 0x1fu; | ||
279 | else if (pos >= 5) | ||
280 | progress_pattern[i] = 0x00u; | ||
281 | else | ||
282 | progress_pattern[i] = 0x1fu >> pos; | ||
283 | } | ||
284 | |||
285 | display->define_pattern(gwps->data->wps_progress_pat[0], progress_pattern); | ||
286 | return true; | ||
287 | } | ||
288 | |||
289 | static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size) | ||
290 | { | ||
291 | static const unsigned char numbers[10][4] = { | ||
292 | {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */ | ||
293 | {0x04, 0x0c, 0x04, 0x04}, /* 1 */ | ||
294 | {0x0e, 0x02, 0x04, 0x0e}, /* 2 */ | ||
295 | {0x0e, 0x02, 0x06, 0x0e}, /* 3 */ | ||
296 | {0x08, 0x0c, 0x0e, 0x04}, /* 4 */ | ||
297 | {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */ | ||
298 | {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */ | ||
299 | {0x0e, 0x02, 0x04, 0x08}, /* 7 */ | ||
300 | {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */ | ||
301 | {0x0e, 0x0e, 0x02, 0x0e}, /* 9 */ | ||
302 | }; | ||
303 | |||
304 | struct wps_state *state = gwps->state; | ||
305 | struct screen *display = gwps->display; | ||
306 | struct wps_data *data = gwps->data; | ||
307 | unsigned char progress_pattern[7]; | ||
308 | char timestr[10]; | ||
309 | int time; | ||
310 | int time_idx = 0; | ||
311 | int pos = 0; | ||
312 | int pat_idx = 1; | ||
313 | int digit, i, j; | ||
314 | bool softchar; | ||
315 | |||
316 | if (!state->id3 || buf_size < 34) /* worst case: 11x UTF-8 char + \0 */ | ||
317 | return; | ||
318 | |||
319 | time = state->id3->elapsed + state->ff_rewind_count; | ||
320 | if (state->id3->length) | ||
321 | pos = 55 * time / state->id3->length; | ||
322 | |||
323 | memset(timestr, 0, sizeof(timestr)); | ||
324 | format_time(timestr, sizeof(timestr)-2, time); | ||
325 | timestr[strlen(timestr)] = ':'; /* always safe */ | ||
326 | |||
327 | for (i = 0; i < 11; i++, pos -= 5) | ||
328 | { | ||
329 | softchar = false; | ||
330 | memset(progress_pattern, 0, sizeof(progress_pattern)); | ||
331 | |||
332 | if ((digit = timestr[time_idx])) | ||
333 | { | ||
334 | softchar = true; | ||
335 | digit -= '0'; | ||
336 | |||
337 | if (timestr[time_idx + 1] == ':') /* ones, left aligned */ | ||
338 | { | ||
339 | memcpy(progress_pattern, numbers[digit], 4); | ||
340 | time_idx += 2; | ||
341 | } | ||
342 | else /* tens, shifted right */ | ||
343 | { | ||
344 | for (j = 0; j < 4; j++) | ||
345 | progress_pattern[j] = numbers[digit][j] >> 1; | ||
346 | |||
347 | if (time_idx > 0) /* not the first group, add colon in front */ | ||
348 | { | ||
349 | progress_pattern[1] |= 0x10u; | ||
350 | progress_pattern[3] |= 0x10u; | ||
351 | } | ||
352 | time_idx++; | ||
353 | } | ||
354 | |||
355 | if (pos >= 5) | ||
356 | progress_pattern[5] = progress_pattern[6] = 0x1fu; | ||
357 | } | ||
358 | |||
359 | if (pos > 0 && pos < 5) | ||
360 | { | ||
361 | softchar = true; | ||
362 | progress_pattern[5] = progress_pattern[6] = (~0x1fu >> pos) & 0x1fu; | ||
363 | } | ||
364 | |||
365 | if (softchar && pat_idx < 8) | ||
366 | { | ||
367 | display->define_pattern(data->wps_progress_pat[pat_idx], | ||
368 | progress_pattern); | ||
369 | buf = utf8encode(data->wps_progress_pat[pat_idx], buf); | ||
370 | pat_idx++; | ||
371 | } | ||
372 | else if (pos <= 0) | ||
373 | buf = utf8encode(' ', buf); | ||
374 | else | ||
375 | buf = utf8encode(0xe115, buf); /* 2/7 _ */ | ||
376 | } | ||
377 | *buf = '\0'; | ||
378 | } | ||
379 | |||
380 | #endif /* HAVE_LCD_CHARCELL */ | ||
381 | |||
382 | /* Returns the index of the subline in the subline array | ||
383 | line - 0-based line number | ||
384 | subline - 0-based subline number within the line | ||
385 | */ | ||
386 | static int subline_index(struct wps_data *data, int line, int subline) | ||
387 | { | ||
388 | return data->lines[line].first_subline_idx + subline; | ||
389 | } | ||
390 | |||
391 | /* Returns the index of the first subline's token in the token array | ||
392 | line - 0-based line number | ||
393 | subline - 0-based subline number within the line | ||
394 | */ | ||
395 | static int first_token_index(struct wps_data *data, int line, int subline) | ||
396 | { | ||
397 | int first_subline_idx = data->lines[line].first_subline_idx; | ||
398 | return data->sublines[first_subline_idx + subline].first_token_idx; | ||
399 | } | ||
400 | |||
401 | int skin_last_token_index(struct wps_data *data, int line, int subline) | ||
402 | { | ||
403 | int first_subline_idx = data->lines[line].first_subline_idx; | ||
404 | int idx = first_subline_idx + subline; | ||
405 | if (idx < data->num_sublines - 1) | ||
406 | { | ||
407 | /* This subline ends where the next begins */ | ||
408 | return data->sublines[idx+1].first_token_idx - 1; | ||
409 | } | ||
410 | else | ||
411 | { | ||
412 | /* The last subline goes to the end */ | ||
413 | return data->num_tokens - 1; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | /* Return the index to the end token for the conditional token at index. | ||
418 | The conditional token can be either a start token or a separator | ||
419 | (i.e. option) token. | ||
420 | */ | ||
421 | static int find_conditional_end(struct wps_data *data, int index) | ||
422 | { | ||
423 | int ret = index; | ||
424 | while (data->tokens[ret].type != WPS_TOKEN_CONDITIONAL_END) | ||
425 | ret = data->tokens[ret].value.i; | ||
426 | |||
427 | /* ret now is the index to the end token for the conditional. */ | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | /* Evaluate the conditional that is at *token_index and return whether a skip | ||
432 | has ocurred. *token_index is updated with the new position. | ||
433 | */ | ||
434 | static bool evaluate_conditional(struct gui_wps *gwps, int *token_index) | ||
435 | { | ||
436 | if (!gwps) | ||
437 | return false; | ||
438 | |||
439 | struct wps_data *data = gwps->data; | ||
440 | |||
441 | int i, cond_end; | ||
442 | int cond_index = *token_index; | ||
443 | char result[128]; | ||
444 | const char *value; | ||
445 | unsigned char num_options = data->tokens[cond_index].value.i & 0xFF; | ||
446 | unsigned char prev_val = (data->tokens[cond_index].value.i & 0xFF00) >> 8; | ||
447 | |||
448 | /* treat ?xx<true> constructs as if they had 2 options. */ | ||
449 | if (num_options < 2) | ||
450 | num_options = 2; | ||
451 | |||
452 | int intval = num_options; | ||
453 | /* get_token_value needs to know the number of options in the enum */ | ||
454 | value = get_token_value(gwps, &data->tokens[cond_index + 1], | ||
455 | result, sizeof(result), &intval); | ||
456 | |||
457 | /* intval is now the number of the enum option we want to read, | ||
458 | starting from 1. If intval is -1, we check if value is empty. */ | ||
459 | if (intval == -1) | ||
460 | intval = (value && *value) ? 1 : num_options; | ||
461 | else if (intval > num_options || intval < 1) | ||
462 | intval = num_options; | ||
463 | |||
464 | data->tokens[cond_index].value.i = (intval << 8) + num_options; | ||
465 | |||
466 | /* skip to the appropriate enum case */ | ||
467 | int next = cond_index + 2; | ||
468 | for (i = 1; i < intval; i++) | ||
469 | { | ||
470 | next = data->tokens[next].value.i; | ||
471 | } | ||
472 | *token_index = next; | ||
473 | |||
474 | if (prev_val == intval) | ||
475 | { | ||
476 | /* Same conditional case as previously. Return without clearing the | ||
477 | pictures */ | ||
478 | return false; | ||
479 | } | ||
480 | |||
481 | cond_end = find_conditional_end(data, cond_index + 2); | ||
482 | for (i = cond_index + 3; i < cond_end; i++) | ||
483 | { | ||
484 | #ifdef HAVE_LCD_BITMAP | ||
485 | /* clear all pictures in the conditional and nested ones */ | ||
486 | if (data->tokens[i].type == WPS_TOKEN_IMAGE_PRELOAD_DISPLAY) | ||
487 | clear_image_pos(gwps, data->tokens[i].value.i & 0xFF); | ||
488 | #endif | ||
489 | #ifdef HAVE_ALBUMART | ||
490 | if (data->tokens[i].type == WPS_TOKEN_ALBUMART_DISPLAY) | ||
491 | draw_album_art(gwps, audio_current_aa_hid(), true); | ||
492 | #endif | ||
493 | } | ||
494 | |||
495 | return true; | ||
496 | } | ||
497 | |||
498 | /* Read a (sub)line to the given alignment format buffer. | ||
499 | linebuf is the buffer where the data is actually stored. | ||
500 | align is the alignment format that'll be used to display the text. | ||
501 | The return value indicates whether the line needs to be updated. | ||
502 | */ | ||
503 | static bool get_line(struct gui_wps *gwps, | ||
504 | int line, int subline, | ||
505 | struct align_pos *align, | ||
506 | char *linebuf, | ||
507 | int linebuf_size) | ||
508 | { | ||
509 | struct wps_data *data = gwps->data; | ||
510 | |||
511 | char temp_buf[128]; | ||
512 | char *buf = linebuf; /* will always point to the writing position */ | ||
513 | char *linebuf_end = linebuf + linebuf_size - 1; | ||
514 | int i, last_token_idx; | ||
515 | bool update = false; | ||
516 | |||
517 | /* alignment-related variables */ | ||
518 | int cur_align; | ||
519 | char* cur_align_start; | ||
520 | cur_align_start = buf; | ||
521 | cur_align = WPS_ALIGN_LEFT; | ||
522 | align->left = NULL; | ||
523 | align->center = NULL; | ||
524 | align->right = NULL; | ||
525 | |||
526 | /* Process all tokens of the desired subline */ | ||
527 | last_token_idx = skin_last_token_index(data, line, subline); | ||
528 | for (i = first_token_index(data, line, subline); | ||
529 | i <= last_token_idx; i++) | ||
530 | { | ||
531 | switch(data->tokens[i].type) | ||
532 | { | ||
533 | case WPS_TOKEN_CONDITIONAL: | ||
534 | /* place ourselves in the right conditional case */ | ||
535 | update |= evaluate_conditional(gwps, &i); | ||
536 | break; | ||
537 | |||
538 | case WPS_TOKEN_CONDITIONAL_OPTION: | ||
539 | /* we've finished in the curent conditional case, | ||
540 | skip to the end of the conditional structure */ | ||
541 | i = find_conditional_end(data, i); | ||
542 | break; | ||
543 | |||
544 | #ifdef HAVE_LCD_BITMAP | ||
545 | case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY: | ||
546 | { | ||
547 | struct gui_img *img = data->img; | ||
548 | int n = data->tokens[i].value.i & 0xFF; | ||
549 | int subimage = data->tokens[i].value.i >> 8; | ||
550 | |||
551 | if (n >= 0 && n < MAX_IMAGES && img[n].loaded) | ||
552 | img[n].display = subimage; | ||
553 | break; | ||
554 | } | ||
555 | #endif | ||
556 | |||
557 | case WPS_TOKEN_ALIGN_LEFT: | ||
558 | case WPS_TOKEN_ALIGN_CENTER: | ||
559 | case WPS_TOKEN_ALIGN_RIGHT: | ||
560 | /* remember where the current aligned text started */ | ||
561 | switch (cur_align) | ||
562 | { | ||
563 | case WPS_ALIGN_LEFT: | ||
564 | align->left = cur_align_start; | ||
565 | break; | ||
566 | |||
567 | case WPS_ALIGN_CENTER: | ||
568 | align->center = cur_align_start; | ||
569 | break; | ||
570 | |||
571 | case WPS_ALIGN_RIGHT: | ||
572 | align->right = cur_align_start; | ||
573 | break; | ||
574 | } | ||
575 | /* start a new alignment */ | ||
576 | switch (data->tokens[i].type) | ||
577 | { | ||
578 | case WPS_TOKEN_ALIGN_LEFT: | ||
579 | cur_align = WPS_ALIGN_LEFT; | ||
580 | break; | ||
581 | case WPS_TOKEN_ALIGN_CENTER: | ||
582 | cur_align = WPS_ALIGN_CENTER; | ||
583 | break; | ||
584 | case WPS_TOKEN_ALIGN_RIGHT: | ||
585 | cur_align = WPS_ALIGN_RIGHT; | ||
586 | break; | ||
587 | default: | ||
588 | break; | ||
589 | } | ||
590 | *buf++ = 0; | ||
591 | cur_align_start = buf; | ||
592 | break; | ||
593 | case WPS_VIEWPORT_ENABLE: | ||
594 | { | ||
595 | char label = data->tokens[i].value.i; | ||
596 | int j; | ||
597 | char temp = VP_DRAW_HIDEABLE; | ||
598 | for(j=0;j<data->num_viewports;j++) | ||
599 | { | ||
600 | temp = VP_DRAW_HIDEABLE; | ||
601 | if ((data->viewports[j].hidden_flags&VP_DRAW_HIDEABLE) && | ||
602 | (data->viewports[j].label == label)) | ||
603 | { | ||
604 | if (data->viewports[j].hidden_flags&VP_DRAW_WASHIDDEN) | ||
605 | temp |= VP_DRAW_WASHIDDEN; | ||
606 | data->viewports[j].hidden_flags = temp; | ||
607 | } | ||
608 | } | ||
609 | } | ||
610 | break; | ||
611 | default: | ||
612 | { | ||
613 | /* get the value of the tag and copy it to the buffer */ | ||
614 | const char *value = get_token_value(gwps, &data->tokens[i], | ||
615 | temp_buf, sizeof(temp_buf), NULL); | ||
616 | if (value) | ||
617 | { | ||
618 | update = true; | ||
619 | while (*value && (buf < linebuf_end)) | ||
620 | *buf++ = *value++; | ||
621 | } | ||
622 | break; | ||
623 | } | ||
624 | } | ||
625 | } | ||
626 | |||
627 | /* close the current alignment */ | ||
628 | switch (cur_align) | ||
629 | { | ||
630 | case WPS_ALIGN_LEFT: | ||
631 | align->left = cur_align_start; | ||
632 | break; | ||
633 | |||
634 | case WPS_ALIGN_CENTER: | ||
635 | align->center = cur_align_start; | ||
636 | break; | ||
637 | |||
638 | case WPS_ALIGN_RIGHT: | ||
639 | align->right = cur_align_start; | ||
640 | break; | ||
641 | } | ||
642 | |||
643 | return update; | ||
644 | } | ||
645 | |||
646 | static void get_subline_timeout(struct gui_wps *gwps, int line, int subline) | ||
647 | { | ||
648 | struct wps_data *data = gwps->data; | ||
649 | int i; | ||
650 | int subline_idx = subline_index(data, line, subline); | ||
651 | int last_token_idx = skin_last_token_index(data, line, subline); | ||
652 | |||
653 | data->sublines[subline_idx].time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER; | ||
654 | |||
655 | for (i = first_token_index(data, line, subline); | ||
656 | i <= last_token_idx; i++) | ||
657 | { | ||
658 | switch(data->tokens[i].type) | ||
659 | { | ||
660 | case WPS_TOKEN_CONDITIONAL: | ||
661 | /* place ourselves in the right conditional case */ | ||
662 | evaluate_conditional(gwps, &i); | ||
663 | break; | ||
664 | |||
665 | case WPS_TOKEN_CONDITIONAL_OPTION: | ||
666 | /* we've finished in the curent conditional case, | ||
667 | skip to the end of the conditional structure */ | ||
668 | i = find_conditional_end(data, i); | ||
669 | break; | ||
670 | |||
671 | case WPS_TOKEN_SUBLINE_TIMEOUT: | ||
672 | data->sublines[subline_idx].time_mult = data->tokens[i].value.i; | ||
673 | break; | ||
674 | |||
675 | default: | ||
676 | break; | ||
677 | } | ||
678 | } | ||
679 | } | ||
680 | |||
681 | /* Calculates which subline should be displayed for the specified line | ||
682 | Returns true iff the subline must be refreshed */ | ||
683 | static bool update_curr_subline(struct gui_wps *gwps, int line) | ||
684 | { | ||
685 | struct wps_data *data = gwps->data; | ||
686 | |||
687 | int search, search_start, num_sublines; | ||
688 | bool reset_subline; | ||
689 | bool new_subline_refresh; | ||
690 | bool only_one_subline; | ||
691 | |||
692 | num_sublines = data->lines[line].num_sublines; | ||
693 | reset_subline = (data->lines[line].curr_subline == SUBLINE_RESET); | ||
694 | new_subline_refresh = false; | ||
695 | only_one_subline = false; | ||
696 | |||
697 | /* if time to advance to next sub-line */ | ||
698 | if (TIME_AFTER(current_tick, data->lines[line].subline_expire_time - 1) || | ||
699 | reset_subline) | ||
700 | { | ||
701 | /* search all sublines until the next subline with time > 0 | ||
702 | is found or we get back to the subline we started with */ | ||
703 | if (reset_subline) | ||
704 | search_start = 0; | ||
705 | else | ||
706 | search_start = data->lines[line].curr_subline; | ||
707 | |||
708 | for (search = 0; search < num_sublines; search++) | ||
709 | { | ||
710 | data->lines[line].curr_subline++; | ||
711 | |||
712 | /* wrap around if beyond last defined subline or WPS_MAX_SUBLINES */ | ||
713 | if (data->lines[line].curr_subline == num_sublines) | ||
714 | { | ||
715 | if (data->lines[line].curr_subline == 1) | ||
716 | only_one_subline = true; | ||
717 | data->lines[line].curr_subline = 0; | ||
718 | } | ||
719 | |||
720 | /* if back where we started after search or | ||
721 | only one subline is defined on the line */ | ||
722 | if (((search > 0) && | ||
723 | (data->lines[line].curr_subline == search_start)) || | ||
724 | only_one_subline) | ||
725 | { | ||
726 | /* no other subline with a time > 0 exists */ | ||
727 | data->lines[line].subline_expire_time = (reset_subline ? | ||
728 | current_tick : | ||
729 | data->lines[line].subline_expire_time) + 100 * HZ; | ||
730 | break; | ||
731 | } | ||
732 | else | ||
733 | { | ||
734 | /* get initial time multiplier for this subline */ | ||
735 | get_subline_timeout(gwps, line, data->lines[line].curr_subline); | ||
736 | |||
737 | int subline_idx = subline_index(data, line, | ||
738 | data->lines[line].curr_subline); | ||
739 | |||
740 | /* only use this subline if subline time > 0 */ | ||
741 | if (data->sublines[subline_idx].time_mult > 0) | ||
742 | { | ||
743 | new_subline_refresh = true; | ||
744 | data->lines[line].subline_expire_time = (reset_subline ? | ||
745 | current_tick : data->lines[line].subline_expire_time) + | ||
746 | TIMEOUT_UNIT*data->sublines[subline_idx].time_mult; | ||
747 | break; | ||
748 | } | ||
749 | } | ||
750 | } | ||
751 | } | ||
752 | |||
753 | return new_subline_refresh; | ||
754 | } | ||
755 | |||
756 | /* Display a line appropriately according to its alignment format. | ||
757 | format_align contains the text, separated between left, center and right. | ||
758 | line is the index of the line on the screen. | ||
759 | scroll indicates whether the line is a scrolling one or not. | ||
760 | */ | ||
761 | static void write_line(struct screen *display, | ||
762 | struct align_pos *format_align, | ||
763 | int line, | ||
764 | bool scroll) | ||
765 | { | ||
766 | int left_width = 0, left_xpos; | ||
767 | int center_width = 0, center_xpos; | ||
768 | int right_width = 0, right_xpos; | ||
769 | int ypos; | ||
770 | int space_width; | ||
771 | int string_height; | ||
772 | int scroll_width; | ||
773 | |||
774 | /* calculate different string sizes and positions */ | ||
775 | display->getstringsize((unsigned char *)" ", &space_width, &string_height); | ||
776 | if (format_align->left != 0) { | ||
777 | display->getstringsize((unsigned char *)format_align->left, | ||
778 | &left_width, &string_height); | ||
779 | } | ||
780 | |||
781 | if (format_align->right != 0) { | ||
782 | display->getstringsize((unsigned char *)format_align->right, | ||
783 | &right_width, &string_height); | ||
784 | } | ||
785 | |||
786 | if (format_align->center != 0) { | ||
787 | display->getstringsize((unsigned char *)format_align->center, | ||
788 | ¢er_width, &string_height); | ||
789 | } | ||
790 | |||
791 | left_xpos = 0; | ||
792 | right_xpos = (display->getwidth() - right_width); | ||
793 | center_xpos = (display->getwidth() + left_xpos - center_width) / 2; | ||
794 | |||
795 | scroll_width = display->getwidth() - left_xpos; | ||
796 | |||
797 | /* Checks for overlapping strings. | ||
798 | If needed the overlapping strings will be merged, separated by a | ||
799 | space */ | ||
800 | |||
801 | /* CASE 1: left and centered string overlap */ | ||
802 | /* there is a left string, need to merge left and center */ | ||
803 | if ((left_width != 0 && center_width != 0) && | ||
804 | (left_xpos + left_width + space_width > center_xpos)) { | ||
805 | /* replace the former separator '\0' of left and | ||
806 | center string with a space */ | ||
807 | *(--format_align->center) = ' '; | ||
808 | /* calculate the new width and position of the merged string */ | ||
809 | left_width = left_width + space_width + center_width; | ||
810 | /* there is no centered string anymore */ | ||
811 | center_width = 0; | ||
812 | } | ||
813 | /* there is no left string, move center to left */ | ||
814 | if ((left_width == 0 && center_width != 0) && | ||
815 | (left_xpos + left_width > center_xpos)) { | ||
816 | /* move the center string to the left string */ | ||
817 | format_align->left = format_align->center; | ||
818 | /* calculate the new width and position of the string */ | ||
819 | left_width = center_width; | ||
820 | /* there is no centered string anymore */ | ||
821 | center_width = 0; | ||
822 | } | ||
823 | |||
824 | /* CASE 2: centered and right string overlap */ | ||
825 | /* there is a right string, need to merge center and right */ | ||
826 | if ((center_width != 0 && right_width != 0) && | ||
827 | (center_xpos + center_width + space_width > right_xpos)) { | ||
828 | /* replace the former separator '\0' of center and | ||
829 | right string with a space */ | ||
830 | *(--format_align->right) = ' '; | ||
831 | /* move the center string to the right after merge */ | ||
832 | format_align->right = format_align->center; | ||
833 | /* calculate the new width and position of the merged string */ | ||
834 | right_width = center_width + space_width + right_width; | ||
835 | right_xpos = (display->getwidth() - right_width); | ||
836 | /* there is no centered string anymore */ | ||
837 | center_width = 0; | ||
838 | } | ||
839 | /* there is no right string, move center to right */ | ||
840 | if ((center_width != 0 && right_width == 0) && | ||
841 | (center_xpos + center_width > right_xpos)) { | ||
842 | /* move the center string to the right string */ | ||
843 | format_align->right = format_align->center; | ||
844 | /* calculate the new width and position of the string */ | ||
845 | right_width = center_width; | ||
846 | right_xpos = (display->getwidth() - right_width); | ||
847 | /* there is no centered string anymore */ | ||
848 | center_width = 0; | ||
849 | } | ||
850 | |||
851 | /* CASE 3: left and right overlap | ||
852 | There is no center string anymore, either there never | ||
853 | was one or it has been merged in case 1 or 2 */ | ||
854 | /* there is a left string, need to merge left and right */ | ||
855 | if ((left_width != 0 && center_width == 0 && right_width != 0) && | ||
856 | (left_xpos + left_width + space_width > right_xpos)) { | ||
857 | /* replace the former separator '\0' of left and | ||
858 | right string with a space */ | ||
859 | *(--format_align->right) = ' '; | ||
860 | /* calculate the new width and position of the string */ | ||
861 | left_width = left_width + space_width + right_width; | ||
862 | /* there is no right string anymore */ | ||
863 | right_width = 0; | ||
864 | } | ||
865 | /* there is no left string, move right to left */ | ||
866 | if ((left_width == 0 && center_width == 0 && right_width != 0) && | ||
867 | (left_width > right_xpos)) { | ||
868 | /* move the right string to the left string */ | ||
869 | format_align->left = format_align->right; | ||
870 | /* calculate the new width and position of the string */ | ||
871 | left_width = right_width; | ||
872 | /* there is no right string anymore */ | ||
873 | right_width = 0; | ||
874 | } | ||
875 | |||
876 | ypos = (line * string_height); | ||
877 | |||
878 | |||
879 | if (scroll && ((left_width > scroll_width) || | ||
880 | (center_width > scroll_width) || | ||
881 | (right_width > scroll_width))) | ||
882 | { | ||
883 | display->puts_scroll(0, line, | ||
884 | (unsigned char *)format_align->left); | ||
885 | } | ||
886 | else | ||
887 | { | ||
888 | #ifdef HAVE_LCD_BITMAP | ||
889 | /* clear the line first */ | ||
890 | display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | ||
891 | display->fillrect(left_xpos, ypos, display->getwidth(), string_height); | ||
892 | display->set_drawmode(DRMODE_SOLID); | ||
893 | #endif | ||
894 | |||
895 | /* Nasty hack: we output an empty scrolling string, | ||
896 | which will reset the scroller for that line */ | ||
897 | display->puts_scroll(0, line, (unsigned char *)""); | ||
898 | |||
899 | /* print aligned strings */ | ||
900 | if (left_width != 0) | ||
901 | { | ||
902 | display->putsxy(left_xpos, ypos, | ||
903 | (unsigned char *)format_align->left); | ||
904 | } | ||
905 | if (center_width != 0) | ||
906 | { | ||
907 | display->putsxy(center_xpos, ypos, | ||
908 | (unsigned char *)format_align->center); | ||
909 | } | ||
910 | if (right_width != 0) | ||
911 | { | ||
912 | display->putsxy(right_xpos, ypos, | ||
913 | (unsigned char *)format_align->right); | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | |||
918 | static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode) | ||
919 | { | ||
920 | struct wps_data *data = gwps->data; | ||
921 | struct screen *display = gwps->display; | ||
922 | struct wps_state *state = gwps->state; | ||
923 | |||
924 | if (!data || !state || !display) | ||
925 | return false; | ||
926 | |||
927 | struct mp3entry *id3 = state->id3; | ||
928 | |||
929 | if (!id3) | ||
930 | return false; | ||
931 | |||
932 | int v, line, i, subline_idx; | ||
933 | unsigned flags; | ||
934 | char linebuf[MAX_PATH]; | ||
935 | |||
936 | struct align_pos align; | ||
937 | align.left = NULL; | ||
938 | align.center = NULL; | ||
939 | align.right = NULL; | ||
940 | |||
941 | bool update_line, new_subline_refresh; | ||
942 | |||
943 | #ifdef HAVE_LCD_BITMAP | ||
944 | |||
945 | /* to find out wether the peak meter is enabled we | ||
946 | assume it wasn't until we find a line that contains | ||
947 | the peak meter. We can't use peak_meter_enabled itself | ||
948 | because that would mean to turn off the meter thread | ||
949 | temporarily. (That shouldn't matter unless yield | ||
950 | or sleep is called but who knows...) | ||
951 | */ | ||
952 | bool enable_pm = false; | ||
953 | |||
954 | #endif | ||
955 | |||
956 | /* reset to first subline if refresh all flag is set */ | ||
957 | if (refresh_mode == WPS_REFRESH_ALL) | ||
958 | { | ||
959 | display->set_viewport(&data->viewports[0].vp); | ||
960 | display->clear_viewport(); | ||
961 | |||
962 | for (i = 0; i <= data->num_lines; i++) | ||
963 | { | ||
964 | data->lines[i].curr_subline = SUBLINE_RESET; | ||
965 | } | ||
966 | } | ||
967 | |||
968 | #ifdef HAVE_LCD_CHARCELLS | ||
969 | for (i = 0; i < 8; i++) | ||
970 | { | ||
971 | if (data->wps_progress_pat[i] == 0) | ||
972 | data->wps_progress_pat[i] = display->get_locked_pattern(); | ||
973 | } | ||
974 | #endif | ||
975 | |||
976 | /* disable any viewports which are conditionally displayed */ | ||
977 | for (v = 0; v < data->num_viewports; v++) | ||
978 | { | ||
979 | if (data->viewports[v].hidden_flags&VP_DRAW_HIDEABLE) | ||
980 | { | ||
981 | if (data->viewports[v].hidden_flags&VP_DRAW_HIDDEN) | ||
982 | data->viewports[v].hidden_flags |= VP_DRAW_WASHIDDEN; | ||
983 | else | ||
984 | data->viewports[v].hidden_flags |= VP_DRAW_HIDDEN; | ||
985 | } | ||
986 | } | ||
987 | for (v = 0; v < data->num_viewports; v++) | ||
988 | { | ||
989 | struct wps_viewport *wps_vp = &(data->viewports[v]); | ||
990 | unsigned vp_refresh_mode = refresh_mode; | ||
991 | display->set_viewport(&wps_vp->vp); | ||
992 | |||
993 | #ifdef HAVE_LCD_BITMAP | ||
994 | /* Set images to not to be displayed */ | ||
995 | for (i = 0; i < MAX_IMAGES; i++) | ||
996 | { | ||
997 | data->img[i].display = -1; | ||
998 | } | ||
999 | #endif | ||
1000 | /* dont redraw the viewport if its disabled */ | ||
1001 | if ((wps_vp->hidden_flags&VP_DRAW_HIDDEN)) | ||
1002 | { | ||
1003 | if (!(wps_vp->hidden_flags&VP_DRAW_WASHIDDEN)) | ||
1004 | display->scroll_stop(&wps_vp->vp); | ||
1005 | wps_vp->hidden_flags |= VP_DRAW_WASHIDDEN; | ||
1006 | continue; | ||
1007 | } | ||
1008 | else if (((wps_vp->hidden_flags& | ||
1009 | (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)) | ||
1010 | == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))) | ||
1011 | { | ||
1012 | vp_refresh_mode = WPS_REFRESH_ALL; | ||
1013 | wps_vp->hidden_flags = VP_DRAW_HIDEABLE; | ||
1014 | } | ||
1015 | if (vp_refresh_mode == WPS_REFRESH_ALL) | ||
1016 | { | ||
1017 | display->clear_viewport(); | ||
1018 | } | ||
1019 | |||
1020 | for (line = wps_vp->first_line; | ||
1021 | line <= wps_vp->last_line; line++) | ||
1022 | { | ||
1023 | memset(linebuf, 0, sizeof(linebuf)); | ||
1024 | update_line = false; | ||
1025 | |||
1026 | /* get current subline for the line */ | ||
1027 | new_subline_refresh = update_curr_subline(gwps, line); | ||
1028 | |||
1029 | subline_idx = subline_index(data, line, | ||
1030 | data->lines[line].curr_subline); | ||
1031 | flags = data->sublines[subline_idx].line_type; | ||
1032 | |||
1033 | if (vp_refresh_mode == WPS_REFRESH_ALL || (flags & vp_refresh_mode) | ||
1034 | || new_subline_refresh) | ||
1035 | { | ||
1036 | /* get_line tells us if we need to update the line */ | ||
1037 | update_line = get_line(gwps, line, data->lines[line].curr_subline, | ||
1038 | &align, linebuf, sizeof(linebuf)); | ||
1039 | } | ||
1040 | #ifdef HAVE_LCD_BITMAP | ||
1041 | /* peakmeter */ | ||
1042 | if (flags & vp_refresh_mode & WPS_REFRESH_PEAK_METER) | ||
1043 | { | ||
1044 | /* the peakmeter should be alone on its line */ | ||
1045 | update_line = false; | ||
1046 | |||
1047 | int h = font_get(wps_vp->vp.font)->height; | ||
1048 | int peak_meter_y = (line - wps_vp->first_line)* h; | ||
1049 | |||
1050 | /* The user might decide to have the peak meter in the last | ||
1051 | line so that it is only displayed if no status bar is | ||
1052 | visible. If so we neither want do draw nor enable the | ||
1053 | peak meter. */ | ||
1054 | if (peak_meter_y + h <= display->getheight()) { | ||
1055 | /* found a line with a peak meter -> remember that we must | ||
1056 | enable it later */ | ||
1057 | enable_pm = true; | ||
1058 | peak_meter_enabled = true; | ||
1059 | peak_meter_screen(gwps->display, 0, peak_meter_y, | ||
1060 | MIN(h, display->getheight() - peak_meter_y)); | ||
1061 | } | ||
1062 | else | ||
1063 | { | ||
1064 | peak_meter_enabled = false; | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | #else /* HAVE_LCD_CHARCELL */ | ||
1069 | |||
1070 | /* progressbar */ | ||
1071 | if (flags & vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) | ||
1072 | { | ||
1073 | if (data->full_line_progressbar) | ||
1074 | draw_player_fullbar(gwps, linebuf, sizeof(linebuf)); | ||
1075 | else | ||
1076 | draw_player_progress(gwps); | ||
1077 | } | ||
1078 | #endif | ||
1079 | |||
1080 | if (update_line && | ||
1081 | /* conditionals clear the line which means if the %Vd is put into the default | ||
1082 | viewport there will be a blank line. | ||
1083 | To get around this we dont allow any actual drawing to happen in the | ||
1084 | deault vp if other vp's are defined */ | ||
1085 | ((data->num_viewports>1 && v!=0) || data->num_viewports == 1)) | ||
1086 | { | ||
1087 | if (flags & WPS_REFRESH_SCROLL) | ||
1088 | { | ||
1089 | /* if the line is a scrolling one we don't want to update | ||
1090 | too often, so that it has the time to scroll */ | ||
1091 | if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh) | ||
1092 | write_line(display, &align, line - wps_vp->first_line, true); | ||
1093 | } | ||
1094 | else | ||
1095 | write_line(display, &align, line - wps_vp->first_line, false); | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | #ifdef HAVE_LCD_BITMAP | ||
1100 | /* progressbar */ | ||
1101 | if (vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) | ||
1102 | { | ||
1103 | if (wps_vp->pb) | ||
1104 | { | ||
1105 | draw_progressbar(gwps, wps_vp); | ||
1106 | } | ||
1107 | } | ||
1108 | /* Now display any images in this viewport */ | ||
1109 | wps_display_images(gwps, &wps_vp->vp); | ||
1110 | #endif | ||
1111 | } | ||
1112 | |||
1113 | #ifdef HAVE_LCD_BITMAP | ||
1114 | data->peak_meter_enabled = enable_pm; | ||
1115 | #endif | ||
1116 | |||
1117 | if (refresh_mode & WPS_REFRESH_STATUSBAR) | ||
1118 | { | ||
1119 | gwps_draw_statusbars(); | ||
1120 | } | ||
1121 | /* Restore the default viewport */ | ||
1122 | display->set_viewport(NULL); | ||
1123 | |||
1124 | display->update(); | ||
1125 | |||
1126 | return true; | ||
1127 | } | ||