summaryrefslogtreecommitdiff
path: root/apps/gui/skin_engine/skin_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/gui/skin_engine/skin_display.c')
-rw-r--r--apps/gui/skin_engine/skin_display.c728
1 files changed, 88 insertions, 640 deletions
diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c
index 3d3a654c30..559ae8519f 100644
--- a/apps/gui/skin_engine/skin_display.c
+++ b/apps/gui/skin_engine/skin_display.c
@@ -69,25 +69,22 @@
69#include "skin_engine.h" 69#include "skin_engine.h"
70#include "statusbar-skinned.h" 70#include "statusbar-skinned.h"
71 71
72static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode); 72void skin_render(struct gui_wps *gwps, unsigned refresh_mode);
73 73
74/* update a skinned screen, update_type is WPS_REFRESH_* values. 74/* update a skinned screen, update_type is WPS_REFRESH_* values.
75 * Usually it should only be WPS_REFRESH_NON_STATIC 75 * Usually it should only be WPS_REFRESH_NON_STATIC
76 * A full update will be done if required (state.do_full_update == true) 76 * A full update will be done if required (state.do_full_update == true)
77 */ 77 */
78bool skin_update(struct gui_wps *gwps, unsigned int update_type) 78void skin_update(struct gui_wps *gwps, unsigned int update_type)
79{ 79{
80 bool retval; 80 /* This maybe shouldnt be here,
81 /* This maybe shouldnt be here, but while the skin is only used to 81 * This is also safe for skined screen which dont use the id3 */
82 * display the music screen this is better than whereever we are being
83 * called from. This is also safe for skined screen which dont use the id3 */
84 struct mp3entry *id3 = gwps->state->id3; 82 struct mp3entry *id3 = gwps->state->id3;
85 bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false); 83 bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false);
86 gwps->sync_data->do_full_update |= cuesheet_update; 84 gwps->sync_data->do_full_update |= cuesheet_update;
87 85
88 retval = skin_redraw(gwps, gwps->sync_data->do_full_update ? 86 skin_render(gwps, gwps->sync_data->do_full_update ?
89 WPS_REFRESH_ALL : update_type); 87 SKIN_REFRESH_ALL : update_type);
90 return retval;
91} 88}
92 89
93#ifdef HAVE_LCD_BITMAP 90#ifdef HAVE_LCD_BITMAP
@@ -124,8 +121,7 @@ void skin_statusbar_changed(struct gui_wps *skin)
124 } 121 }
125} 122}
126 123
127static void draw_progressbar(struct gui_wps *gwps, 124void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
128 struct progressbar *pb)
129{ 125{
130 struct screen *display = gwps->display; 126 struct screen *display = gwps->display;
131 struct viewport *vp = pb->vp; 127 struct viewport *vp = pb->vp;
@@ -143,17 +139,17 @@ static void draw_progressbar(struct gui_wps *gwps,
143 /* center the pb in the line, but only if the line is higher than the pb */ 139 /* center the pb in the line, but only if the line is higher than the pb */
144 int center = (line_height-height)/2; 140 int center = (line_height-height)/2;
145 /* if Y was not set calculate by font height,Y is -line_number-1 */ 141 /* if Y was not set calculate by font height,Y is -line_number-1 */
146 y = (-y -1)*line_height + (0 > center ? 0 : center); 142 y = line*line_height + (0 > center ? 0 : center);
147 } 143 }
148 144
149 if (pb->type == WPS_TOKEN_VOLUMEBAR) 145 if (pb->type == SKIN_TOKEN_VOLUMEBAR)
150 { 146 {
151 int minvol = sound_min(SOUND_VOLUME); 147 int minvol = sound_min(SOUND_VOLUME);
152 int maxvol = sound_max(SOUND_VOLUME); 148 int maxvol = sound_max(SOUND_VOLUME);
153 length = maxvol-minvol; 149 length = maxvol-minvol;
154 elapsed = global_settings.volume-minvol; 150 elapsed = global_settings.volume-minvol;
155 } 151 }
156 else if (pb->type == WPS_TOKEN_BATTERY_PERCENTBAR) 152 else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR)
157 { 153 {
158 length = 100; 154 length = 100;
159 elapsed = battery_level(); 155 elapsed = battery_level();
@@ -185,7 +181,7 @@ static void draw_progressbar(struct gui_wps *gwps,
185 gui_scrollbar_draw(display, pb->x, y, pb->width, height, 181 gui_scrollbar_draw(display, pb->x, y, pb->width, height,
186 length, 0, elapsed, HORIZONTAL); 182 length, 0, elapsed, HORIZONTAL);
187 183
188 if (pb->type == WPS_TOKEN_PROGRESSBAR) 184 if (pb->type == SKIN_TOKEN_PROGRESSBAR)
189 { 185 {
190 if (id3 && id3->length) 186 if (id3 && id3->length)
191 { 187 {
@@ -208,8 +204,7 @@ static void draw_progressbar(struct gui_wps *gwps,
208 } 204 }
209} 205}
210 206
211static void draw_playlist_viewer_list(struct gui_wps *gwps, 207void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer)
212 struct playlistviewer *viewer)
213{ 208{
214 struct wps_state *state = gwps->state; 209 struct wps_state *state = gwps->state;
215 int lines = viewport_get_nb_lines(viewer->vp); 210 int lines = viewport_get_nb_lines(viewer->vp);
@@ -217,8 +212,9 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
217 int cur_pos, max; 212 int cur_pos, max;
218 int start_item; 213 int start_item;
219 int i; 214 int i;
220 struct wps_token token; 215 bool scroll = false;
221 int x, length, alignment = WPS_TOKEN_ALIGN_LEFT; 216 struct wps_token *token;
217 int x, length, alignment = SKIN_TOKEN_ALIGN_LEFT;
222 218
223 struct mp3entry *pid3; 219 struct mp3entry *pid3;
224 char buf[MAX_PATH*2], tempbuf[MAX_PATH]; 220 char buf[MAX_PATH*2], tempbuf[MAX_PATH];
@@ -281,51 +277,58 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
281 } 277 }
282 line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO; 278 line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO;
283 } 279 }
284 int j = 0, cur_string = 0;
285 unsigned int line_len = 0; 280 unsigned int line_len = 0;
281 if (viewer->lines[line]->children_count == 0)
282 return;
283 struct skin_element *element = viewer->lines[line]->children[0];
286 buf[0] = '\0'; 284 buf[0] = '\0';
287 while (j < viewer->lines[line].count && line_len < sizeof(buf)) 285 while (element && line_len < sizeof(buf))
288 { 286 {
289 const char *out = NULL; 287 const char *out = NULL;
290 token.type = viewer->lines[line].tokens[j]; 288 if (element->type == TEXT)
291 token.value.i = 0; 289 {
292 token.next = false; 290 line_len = strlcat(buf, (char*)element->data, sizeof(buf));
293 out = get_id3_token(&token, pid3, tempbuf, sizeof(tempbuf), -1, NULL); 291 element = element->next;
292 continue;
293 }
294 if (element->type != TAG)
295 {
296 element = element->next;
297 continue;
298 }
299 if (element->tag->type == SKIN_TOKEN_SUBLINE_SCROLL)
300 scroll = true;
301 token = (struct wps_token*)element->data;
302 out = get_id3_token(token, pid3, tempbuf, sizeof(tempbuf), -1, NULL);
294#if CONFIG_TUNER 303#if CONFIG_TUNER
295 if (!out) 304 if (!out)
296 out = get_radio_token(&token, i-cur_pos, 305 out = get_radio_token(token, i-cur_pos,
297 tempbuf, sizeof(tempbuf), -1, NULL); 306 tempbuf, sizeof(tempbuf), -1, NULL);
298#endif 307#endif
299 if (out) 308 if (out)
300 { 309 {
301 line_len = strlcat(buf, out, sizeof(buf)); 310 line_len = strlcat(buf, out, sizeof(buf));
302 j++; 311 element = element->next;
303 continue; 312 continue;
304 } 313 }
305 314
306 switch (viewer->lines[line].tokens[j]) 315 switch (token->type)
307 { 316 {
308 case WPS_TOKEN_ALIGN_CENTER: 317 case SKIN_TOKEN_ALIGN_CENTER:
309 case WPS_TOKEN_ALIGN_LEFT: 318 case SKIN_TOKEN_ALIGN_LEFT:
310 case WPS_TOKEN_ALIGN_LEFT_RTL: 319 case SKIN_TOKEN_ALIGN_LEFT_RTL:
311 case WPS_TOKEN_ALIGN_RIGHT: 320 case SKIN_TOKEN_ALIGN_RIGHT:
312 case WPS_TOKEN_ALIGN_RIGHT_RTL: 321 case SKIN_TOKEN_ALIGN_RIGHT_RTL:
313 alignment = viewer->lines[line].tokens[j]; 322 alignment = token->type;
314 tempbuf[0] = '\0'; 323 tempbuf[0] = '\0';
315 break; 324 break;
316 case WPS_TOKEN_STRING: 325 case SKIN_TOKEN_PLAYLIST_POSITION:
317 case WPS_TOKEN_CHARACTER:
318 snprintf(tempbuf, sizeof(tempbuf), "%s",
319 viewer->lines[line].strings[cur_string]);
320 cur_string++;
321 break;
322 case WPS_TOKEN_PLAYLIST_POSITION:
323 snprintf(tempbuf, sizeof(tempbuf), "%d", i); 326 snprintf(tempbuf, sizeof(tempbuf), "%d", i);
324 break; 327 break;
325 case WPS_TOKEN_FILE_NAME: 328 case SKIN_TOKEN_FILE_NAME:
326 get_dir(tempbuf, sizeof(tempbuf), filename, 0); 329 get_dir(tempbuf, sizeof(tempbuf), filename, 0);
327 break; 330 break;
328 case WPS_TOKEN_FILE_PATH: 331 case SKIN_TOKEN_FILE_PATH:
329 snprintf(tempbuf, sizeof(tempbuf), "%s", filename); 332 snprintf(tempbuf, sizeof(tempbuf), "%s", filename);
330 break; 333 break;
331 default: 334 default:
@@ -336,12 +339,12 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
336 { 339 {
337 line_len = strlcat(buf, tempbuf, sizeof(buf)); 340 line_len = strlcat(buf, tempbuf, sizeof(buf));
338 } 341 }
339 j++; 342 element = element->next;
340 } 343 }
341 344
342 int vpwidth = viewer->vp->width; 345 int vpwidth = viewer->vp->width;
343 length = gwps->display->getstringsize(buf, NULL, NULL); 346 length = gwps->display->getstringsize(buf, NULL, NULL);
344 if (viewer->lines[line].scroll && length >= vpwidth) 347 if (scroll && length >= vpwidth)
345 { 348 {
346 gwps->display->puts_scroll(0, (i-start_item), buf ); 349 gwps->display->puts_scroll(0, (i-start_item), buf );
347 } 350 }
@@ -353,25 +356,25 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
353 { 356 {
354 switch (alignment) 357 switch (alignment)
355 { 358 {
356 case WPS_TOKEN_ALIGN_CENTER: 359 case SKIN_TOKEN_ALIGN_CENTER:
357 x = (vpwidth-length)/2; 360 x = (vpwidth-length)/2;
358 break; 361 break;
359 case WPS_TOKEN_ALIGN_LEFT_RTL: 362 case SKIN_TOKEN_ALIGN_LEFT_RTL:
360 if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) 363 if (lang_is_rtl() && VP_IS_RTL(viewer->vp))
361 { 364 {
362 x = vpwidth - length; 365 x = vpwidth - length;
363 break; 366 break;
364 } 367 }
365 case WPS_TOKEN_ALIGN_LEFT: 368 case SKIN_TOKEN_ALIGN_LEFT:
366 x = 0; 369 x = 0;
367 break; 370 break;
368 case WPS_TOKEN_ALIGN_RIGHT_RTL: 371 case SKIN_TOKEN_ALIGN_RIGHT_RTL:
369 if (lang_is_rtl() && VP_IS_RTL(viewer->vp)) 372 if (lang_is_rtl() && VP_IS_RTL(viewer->vp))
370 { 373 {
371 x = 0; 374 x = 0;
372 break; 375 break;
373 } 376 }
374 case WPS_TOKEN_ALIGN_RIGHT: 377 case SKIN_TOKEN_ALIGN_RIGHT:
375 x = vpwidth - length; 378 x = vpwidth - length;
376 break; 379 break;
377 default: 380 default:
@@ -386,7 +389,7 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
386 389
387 390
388/* clears the area where the image was shown */ 391/* clears the area where the image was shown */
389static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) 392void clear_image_pos(struct gui_wps *gwps, struct gui_img *img)
390{ 393{
391 if(!gwps) 394 if(!gwps)
392 return; 395 return;
@@ -395,7 +398,7 @@ static void clear_image_pos(struct gui_wps *gwps, struct gui_img *img)
395 gwps->display->set_drawmode(DRMODE_SOLID); 398 gwps->display->set_drawmode(DRMODE_SOLID);
396} 399}
397 400
398static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage) 401void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage)
399{ 402{
400 struct screen *display = gwps->display; 403 struct screen *display = gwps->display;
401 if(img->always_display) 404 if(img->always_display)
@@ -423,7 +426,8 @@ static void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subima
423#endif 426#endif
424} 427}
425 428
426static void wps_display_images(struct gui_wps *gwps, struct viewport* vp) 429
430void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
427{ 431{
428 if(!gwps || !gwps->data || !gwps->display) 432 if(!gwps || !gwps->data || !gwps->display)
429 return; 433 return;
@@ -451,18 +455,10 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
451#ifdef HAVE_ALBUMART 455#ifdef HAVE_ALBUMART
452 /* now draw the AA */ 456 /* now draw the AA */
453 if (data->albumart && data->albumart->vp == vp 457 if (data->albumart && data->albumart->vp == vp
454 && data->albumart->draw) 458 && data->albumart->draw_handle >= 0)
455 { 459 {
456 int handle = playback_current_aa_hid(data->playback_aa_slot); 460 draw_album_art(gwps, data->albumart->draw_handle, false);
457#if CONFIG_TUNER 461 data->albumart->draw_handle = -1;
458 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
459 {
460 struct dim dim = {data->albumart->width, data->albumart->height};
461 handle = radio_get_art_hid(&dim);
462 }
463#endif
464 draw_album_art(gwps, handle, false);
465 data->albumart->draw = false;
466 } 462 }
467#endif 463#endif
468 464
@@ -471,7 +467,7 @@ static void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
471 467
472#else /* HAVE_LCD_CHARCELL */ 468#else /* HAVE_LCD_CHARCELL */
473 469
474static bool draw_player_progress(struct gui_wps *gwps) 470bool draw_player_progress(struct gui_wps *gwps)
475{ 471{
476 struct wps_state *state = gwps->state; 472 struct wps_state *state = gwps->state;
477 struct screen *display = gwps->display; 473 struct screen *display = gwps->display;
@@ -508,7 +504,7 @@ static bool draw_player_progress(struct gui_wps *gwps)
508 return true; 504 return true;
509} 505}
510 506
511static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size) 507void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
512{ 508{
513 static const unsigned char numbers[10][4] = { 509 static const unsigned char numbers[10][4] = {
514 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */ 510 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
@@ -613,44 +609,25 @@ static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
613 609
614#endif /* HAVE_LCD_CHARCELL */ 610#endif /* HAVE_LCD_CHARCELL */
615 611
616/* Return the index to the end token for the conditional token at index.
617 The conditional token can be either a start token or a separator
618 (i.e. option) token.
619*/
620static int find_conditional_end(struct wps_data *data, int index)
621{
622 int ret = index;
623 while (data->tokens[ret].type != WPS_TOKEN_CONDITIONAL_END)
624 ret = data->tokens[ret].value.i;
625
626 /* ret now is the index to the end token for the conditional. */
627 return ret;
628}
629
630/* Evaluate the conditional that is at *token_index and return whether a skip 612/* Evaluate the conditional that is at *token_index and return whether a skip
631 has ocurred. *token_index is updated with the new position. 613 has ocurred. *token_index is updated with the new position.
632*/ 614*/
633static bool evaluate_conditional(struct gui_wps *gwps, int *token_index) 615int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options)
634{ 616{
635 if (!gwps) 617 if (!gwps)
636 return false; 618 return false;
637 619
638 struct wps_data *data = gwps->data;
639
640 int i, cond_end;
641 int cond_index = *token_index;
642 char result[128]; 620 char result[128];
643 const char *value; 621 const char *value;
644 unsigned char num_options = data->tokens[cond_index].value.i & 0xFF;
645 unsigned char prev_val = (data->tokens[cond_index].value.i & 0xFF00) >> 8;
646 622
647 /* treat ?xx<true> constructs as if they had 2 options. */ 623 /* treat ?xx<true> constructs as if they had 2 options.
624 * (i.e ?xx<true|false>) */
648 if (num_options < 2) 625 if (num_options < 2)
649 num_options = 2; 626 num_options = 2;
650 627
651 int intval = num_options; 628 int intval = num_options;
652 /* get_token_value needs to know the number of options in the enum */ 629 /* get_token_value needs to know the number of options in the enum */
653 value = get_token_value(gwps, &data->tokens[cond_index + 1], 630 value = get_token_value(gwps, conditional->token,
654 result, sizeof(result), &intval); 631 result, sizeof(result), &intval);
655 632
656 /* intval is now the number of the enum option we want to read, 633 /* intval is now the number of the enum option we want to read,
@@ -659,334 +636,18 @@ static bool evaluate_conditional(struct gui_wps *gwps, int *token_index)
659 intval = (value && *value) ? 1 : num_options; 636 intval = (value && *value) ? 1 : num_options;
660 else if (intval > num_options || intval < 1) 637 else if (intval > num_options || intval < 1)
661 intval = num_options; 638 intval = num_options;
662 639
663 data->tokens[cond_index].value.i = (intval << 8) + num_options; 640 conditional->last_value = intval -1;
664 641 return intval -1;
665 /* skip to the appropriate enum case */
666 int next = cond_index + 2;
667 for (i = 1; i < intval; i++)
668 {
669 next = data->tokens[next].value.i;
670 }
671 *token_index = next;
672
673 if (prev_val == intval)
674 {
675 /* Same conditional case as previously. Return without clearing the
676 pictures */
677 return false;
678 }
679
680 cond_end = find_conditional_end(data, cond_index + 2);
681 for (i = cond_index + 3; i < cond_end; i++)
682 {
683#ifdef HAVE_LCD_BITMAP
684 /* clear all pictures in the conditional and nested ones */
685 if (data->tokens[i].type == WPS_TOKEN_IMAGE_PRELOAD_DISPLAY)
686 clear_image_pos(gwps, find_image(data->tokens[i].value.i&0xFF, data));
687 else if (data->tokens[i].type == WPS_TOKEN_VOLUMEBAR ||
688 data->tokens[i].type == WPS_TOKEN_PROGRESSBAR ||
689 data->tokens[i].type == WPS_TOKEN_BATTERY_PERCENTBAR )
690 {
691 struct progressbar *bar = (struct progressbar*)data->tokens[i].value.data;
692 bar->draw = false;
693 }
694 else if (data->tokens[i].type == WPS_TOKEN_PEAKMETER)
695 {
696 data->peak_meter_enabled = false;
697 }
698#endif
699#ifdef HAVE_ALBUMART
700 if (data->albumart && data->tokens[i].type == WPS_TOKEN_ALBUMART_DISPLAY)
701 {
702 draw_album_art(gwps,
703 playback_current_aa_hid(data->playback_aa_slot), true);
704 data->albumart->draw = false;
705 }
706#endif
707 }
708
709 return true;
710}
711
712
713/* Read a (sub)line to the given alignment format buffer.
714 linebuf is the buffer where the data is actually stored.
715 align is the alignment format that'll be used to display the text.
716 The return value indicates whether the line needs to be updated.
717*/
718static bool get_line(struct gui_wps *gwps,
719 struct skin_subline *subline,
720 struct align_pos *align,
721 char *linebuf,
722 int linebuf_size,
723 unsigned refresh_mode)
724{
725 struct wps_data *data = gwps->data;
726
727 char temp_buf[128];
728 char *buf = linebuf; /* will always point to the writing position */
729 char *linebuf_end = linebuf + linebuf_size - 1;
730 bool update = false;
731 int i;
732 (void)refresh_mode; /* silence warning on charcell */
733
734 /* alignment-related variables */
735 int cur_align;
736 char* cur_align_start;
737 cur_align_start = buf;
738 cur_align = WPS_ALIGN_LEFT;
739 align->left = NULL;
740 align->center = NULL;
741 align->right = NULL;
742 /* Process all tokens of the desired subline */
743 for (i = subline->first_token_idx;
744 i <= subline->last_token_idx; i++)
745 {
746 switch(data->tokens[i].type)
747 {
748 case WPS_TOKEN_CONDITIONAL:
749 /* place ourselves in the right conditional case */
750 update |= evaluate_conditional(gwps, &i);
751 break;
752
753 case WPS_TOKEN_CONDITIONAL_OPTION:
754 /* we've finished in the curent conditional case,
755 skip to the end of the conditional structure */
756 i = find_conditional_end(data, i);
757 break;
758#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
759 case WPS_TOKEN_VIEWPORT_FGCOLOUR:
760 {
761 struct viewport_colour *col = data->tokens[i].value.data;
762 col->vp->fg_pattern = col->colour;
763 }
764 break;
765 case WPS_TOKEN_VIEWPORT_BGCOLOUR:
766 {
767 struct viewport_colour *col = data->tokens[i].value.data;
768 col->vp->bg_pattern = col->colour;
769 }
770 break;
771#endif
772#ifdef HAVE_LCD_BITMAP
773 case WPS_TOKEN_PEAKMETER:
774 data->peak_meter_enabled = true;
775 break;
776 case WPS_TOKEN_VOLUMEBAR:
777 case WPS_TOKEN_BATTERY_PERCENTBAR:
778 case WPS_TOKEN_PROGRESSBAR:
779 {
780 struct progressbar *bar = (struct progressbar*)data->tokens[i].value.data;
781 bar->draw = true;
782 }
783 break;
784 case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY:
785 {
786 char n = data->tokens[i].value.i & 0xFF;
787 int subimage = data->tokens[i].value.i >> 8;
788 struct gui_img *img = find_image(n, data);
789
790 if (img && img->loaded)
791 img->display = subimage;
792 break;
793 }
794 case WPS_TOKEN_DRAW_INBUILTBAR:
795 gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]),
796 refresh_mode == WPS_REFRESH_ALL,
797 data->tokens[i].value.data);
798 break;
799#endif
800
801 case WPS_TOKEN_ALIGN_LEFT:
802 case WPS_TOKEN_ALIGN_LEFT_RTL:
803 case WPS_TOKEN_ALIGN_CENTER:
804 case WPS_TOKEN_ALIGN_RIGHT:
805 case WPS_TOKEN_ALIGN_RIGHT_RTL:
806 /* remember where the current aligned text started */
807 switch (cur_align)
808 {
809 case WPS_ALIGN_LEFT:
810 align->left = cur_align_start;
811 break;
812
813 case WPS_ALIGN_CENTER:
814 align->center = cur_align_start;
815 break;
816
817 case WPS_ALIGN_RIGHT:
818 align->right = cur_align_start;
819 break;
820 }
821 /* start a new alignment */
822 switch (data->tokens[i].type)
823 {
824 case WPS_TOKEN_ALIGN_LEFT:
825 cur_align = WPS_ALIGN_LEFT;
826 break;
827 case WPS_TOKEN_ALIGN_LEFT_RTL:
828 cur_align = lang_is_rtl() ? WPS_ALIGN_RIGHT :
829 WPS_ALIGN_LEFT;
830 break;
831 case WPS_TOKEN_ALIGN_CENTER:
832 cur_align = WPS_ALIGN_CENTER;
833 break;
834 case WPS_TOKEN_ALIGN_RIGHT:
835 cur_align = WPS_ALIGN_RIGHT;
836 break;
837 case WPS_TOKEN_ALIGN_RIGHT_RTL:
838 cur_align = lang_is_rtl() ? WPS_ALIGN_LEFT :
839 WPS_ALIGN_RIGHT;
840 break;
841 default:
842 break;
843 }
844 *buf++ = 0;
845 cur_align_start = buf;
846 break;
847 case WPS_VIEWPORT_ENABLE:
848 {
849 char label = data->tokens[i].value.i;
850 char temp = VP_DRAW_HIDEABLE;
851 /* viewports are allowed to share id's so find and enable
852 * all of them */
853 struct skin_token_list *list = data->viewports;
854 while (list)
855 {
856 struct skin_viewport *vp =
857 (struct skin_viewport *)list->token->value.data;
858 if (vp->label == label)
859 {
860 if (vp->hidden_flags&VP_DRAW_WASHIDDEN)
861 temp |= VP_DRAW_WASHIDDEN;
862 vp->hidden_flags = temp;
863 }
864 list = list->next;
865 }
866 }
867 break;
868#ifdef HAVE_LCD_BITMAP
869 case WPS_TOKEN_UIVIEWPORT_ENABLE:
870 sb_set_info_vp(gwps->display->screen_type,
871 data->tokens[i].value.i|VP_INFO_LABEL);
872 break;
873 case WPS_VIEWPORT_CUSTOMLIST:
874 draw_playlist_viewer_list(gwps, data->tokens[i].value.data);
875 break;
876#endif
877 default:
878 {
879 /* get the value of the tag and copy it to the buffer */
880 const char *value = get_token_value(gwps, &data->tokens[i],
881 temp_buf, sizeof(temp_buf), NULL);
882 if (value)
883 {
884 update = true;
885 while (*value && (buf < linebuf_end))
886 *buf++ = *value++;
887 }
888 break;
889 }
890 }
891 }
892
893 /* close the current alignment */
894 switch (cur_align)
895 {
896 case WPS_ALIGN_LEFT:
897 align->left = cur_align_start;
898 break;
899
900 case WPS_ALIGN_CENTER:
901 align->center = cur_align_start;
902 break;
903
904 case WPS_ALIGN_RIGHT:
905 align->right = cur_align_start;
906 break;
907 }
908
909 return update;
910}
911static void get_subline_timeout(struct gui_wps *gwps, struct skin_subline *subline)
912{
913 struct wps_data *data = gwps->data;
914 int i;
915 subline->time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER;
916
917 for (i = subline->first_token_idx;
918 i <= subline->last_token_idx; i++)
919 {
920 switch(data->tokens[i].type)
921 {
922 case WPS_TOKEN_CONDITIONAL:
923 /* place ourselves in the right conditional case */
924 evaluate_conditional(gwps, &i);
925 break;
926
927 case WPS_TOKEN_CONDITIONAL_OPTION:
928 /* we've finished in the curent conditional case,
929 skip to the end of the conditional structure */
930 i = find_conditional_end(data, i);
931 break;
932
933 case WPS_TOKEN_SUBLINE_TIMEOUT:
934 subline->time_mult = data->tokens[i].value.i;
935 break;
936
937 default:
938 break;
939 }
940 }
941} 642}
942 643
943/* Calculates which subline should be displayed for the specified line
944 Returns true iff the subline must be refreshed */
945static bool update_curr_subline(struct gui_wps *gwps, struct skin_line *line)
946{
947 /* shortcut this whole thing if we need to reset the line completly */
948 if (line->curr_subline == NULL)
949 {
950 line->subline_expire_time = current_tick;
951 line->curr_subline = &line->sublines;
952 if (!line->curr_subline->next)
953 {
954 line->subline_expire_time += 100*HZ;
955 }
956 else
957 {
958 get_subline_timeout(gwps, line->curr_subline);
959 line->subline_expire_time += TIMEOUT_UNIT*line->curr_subline->time_mult;
960 }
961 return true;
962 }
963 /* if time to advance to next sub-line */
964 if (TIME_AFTER(current_tick, line->subline_expire_time - 1))
965 {
966 /* if there is only one subline, there is no need to search for a new one */
967 if (&line->sublines == line->curr_subline &&
968 line->curr_subline->next == NULL)
969 {
970 line->subline_expire_time += 100 * HZ;
971 return false;
972 }
973 if (line->curr_subline->next)
974 line->curr_subline = line->curr_subline->next;
975 else
976 line->curr_subline = &line->sublines;
977 get_subline_timeout(gwps, line->curr_subline);
978 line->subline_expire_time = current_tick + TIMEOUT_UNIT*line->curr_subline->time_mult;
979 return true;
980 }
981 return false;
982}
983 644
984/* Display a line appropriately according to its alignment format. 645/* Display a line appropriately according to its alignment format.
985 format_align contains the text, separated between left, center and right. 646 format_align contains the text, separated between left, center and right.
986 line is the index of the line on the screen. 647 line is the index of the line on the screen.
987 scroll indicates whether the line is a scrolling one or not. 648 scroll indicates whether the line is a scrolling one or not.
988*/ 649*/
989static void write_line(struct screen *display, 650void write_line(struct screen *display,
990 struct align_pos *format_align, 651 struct align_pos *format_align,
991 int line, 652 int line,
992 bool scroll) 653 bool scroll)
@@ -1143,244 +804,30 @@ static void write_line(struct screen *display,
1143 } 804 }
1144} 805}
1145 806
1146static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode) 807#ifdef HAVE_LCD_BITMAP
808void draw_peakmeters(struct gui_wps *gwps, int line_number,
809 struct viewport *viewport)
1147{ 810{
1148 struct wps_data *data = gwps->data; 811 struct wps_data *data = gwps->data;
1149 struct screen *display = gwps->display; 812 if (!data->peak_meter_enabled)
1150
1151 if (!data || !display || !gwps->state)
1152 return false;
1153
1154 unsigned flags;
1155 char linebuf[MAX_PATH];
1156
1157 struct align_pos align;
1158 align.left = NULL;
1159 align.center = NULL;
1160 align.right = NULL;
1161
1162
1163 struct skin_token_list *viewport_list;
1164
1165 bool update_line, new_subline_refresh;
1166
1167 /* reset to first subline if refresh all flag is set */
1168 if (refresh_mode == WPS_REFRESH_ALL)
1169 { 813 {
1170 struct skin_line *line; 814 peak_meter_enable(false);
1171 struct skin_viewport *skin_viewport = find_viewport(VP_DEFAULT_LABEL, data);
1172
1173 if (!(skin_viewport->hidden_flags & VP_NEVER_VISIBLE))
1174 {
1175 display->set_viewport(&skin_viewport->vp);
1176 display->clear_viewport();
1177 }
1178
1179 for (viewport_list = data->viewports;
1180 viewport_list; viewport_list = viewport_list->next)
1181 {
1182 skin_viewport =
1183 (struct skin_viewport *)viewport_list->token->value.data;
1184 for(line = skin_viewport->lines; line; line = line->next)
1185 {
1186 line->curr_subline = NULL;
1187 }
1188 }
1189 } 815 }
1190 816 else
1191#ifdef HAVE_LCD_CHARCELLS
1192 int i;
1193 for (i = 0; i < 8; i++)
1194 {
1195 if (data->wps_progress_pat[i] == 0)
1196 data->wps_progress_pat[i] = display->get_locked_pattern();
1197 }
1198#endif
1199
1200 /* disable any viewports which are conditionally displayed.
1201 * If we are only refreshing the peak meter then don't change the viewport
1202 * enabled flags as this will stop scrolling. viewports cant be
1203 * toggled in this refresh mode anyway (FS#10215)*/
1204 if (refresh_mode != WPS_REFRESH_PEAK_METER)
1205 {
1206 for (viewport_list = data->viewports;
1207 viewport_list; viewport_list = viewport_list->next)
1208 {
1209 struct skin_viewport *skin_viewport =
1210 (struct skin_viewport *)viewport_list->token->value.data;
1211 if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
1212 {
1213 continue;
1214 }
1215 if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE)
1216 {
1217 if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN)
1218 skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
1219 else
1220 skin_viewport->hidden_flags |= VP_DRAW_HIDDEN;
1221 }
1222 }
1223 }
1224 for (viewport_list = data->viewports;
1225 viewport_list; viewport_list = viewport_list->next)
1226 { 817 {
1227 struct skin_viewport *skin_viewport = 818 int h = font_get(viewport->font)->height;
1228 (struct skin_viewport *)viewport_list->token->value.data; 819 int peak_meter_y = line_number * h;
1229 unsigned vp_refresh_mode = refresh_mode;
1230#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
1231 skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour;
1232 skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour;
1233#endif
1234 display->set_viewport(&skin_viewport->vp);
1235
1236 int hidden_vp = 0;
1237 820
1238#ifdef HAVE_LCD_BITMAP 821 /* The user might decide to have the peak meter in the last
1239 /* Set images to not to be displayed */ 822 line so that it is only displayed if no status bar is
1240 struct skin_token_list *imglist = data->images; 823 visible. If so we neither want do draw nor enable the
1241 while (imglist) 824 peak meter. */
1242 { 825 if (peak_meter_y + h <= viewport->y+viewport->height) {
1243 struct gui_img *img = (struct gui_img *)imglist->token->value.data; 826 peak_meter_enable(true);
1244 img->display = -1; 827 peak_meter_screen(gwps->display, 0, peak_meter_y,
1245 imglist = imglist->next; 828 MIN(h, viewport->y+viewport->height - peak_meter_y));
1246 }
1247#endif
1248 /* dont redraw the viewport if its disabled */
1249 if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE)
1250 { /* don't draw anything into this one */
1251 vp_refresh_mode = 0; hidden_vp = true;
1252 }
1253 else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN))
1254 {
1255 if (!(skin_viewport->hidden_flags&VP_DRAW_WASHIDDEN))
1256 display->scroll_stop(&skin_viewport->vp);
1257 skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN;
1258 continue;
1259 }
1260 else if (((skin_viewport->hidden_flags&
1261 (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))
1262 == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)))
1263 {
1264 vp_refresh_mode = WPS_REFRESH_ALL;
1265 skin_viewport->hidden_flags = VP_DRAW_HIDEABLE;
1266 }
1267
1268 if (vp_refresh_mode == WPS_REFRESH_ALL)
1269 {
1270 display->clear_viewport();
1271 } 829 }
1272
1273 /* loop over the lines for this viewport */
1274 struct skin_line *line;
1275 /* %V() doesnt eat the \n which means the first line of text
1276 * is actually going to be one line down. so set line_count to -1
1277 * unless we are using the default viewport which doesnt have this problem */
1278 int line_count = skin_viewport->label==VP_DEFAULT_LABEL?0:-1;
1279
1280 for (line = skin_viewport->lines; line; line = line->next, line_count++)
1281 {
1282 struct skin_subline *subline;
1283 memset(linebuf, 0, sizeof(linebuf));
1284 update_line = false;
1285
1286 /* get current subline for the line */
1287 new_subline_refresh = update_curr_subline(gwps, line);
1288 subline = line->curr_subline;
1289 flags = line->curr_subline->line_type;
1290
1291 if (vp_refresh_mode == WPS_REFRESH_ALL || (flags & vp_refresh_mode)
1292 || new_subline_refresh || hidden_vp)
1293 {
1294 /* get_line tells us if we need to update the line */
1295 update_line = get_line(gwps, subline, &align,
1296 linebuf, sizeof(linebuf), vp_refresh_mode);
1297 }
1298#ifdef HAVE_LCD_BITMAP
1299 /* peakmeter */
1300 if (flags & vp_refresh_mode & WPS_REFRESH_PEAK_METER)
1301 {
1302 if (!data->peak_meter_enabled)
1303 {
1304 peak_meter_enable(false);
1305 }
1306 else
1307 {
1308 /* the peakmeter should be alone on its line */
1309 update_line = false;
1310
1311 int h = font_get(skin_viewport->vp.font)->height;
1312 int peak_meter_y = line_count* h;
1313
1314 /* The user might decide to have the peak meter in the last
1315 line so that it is only displayed if no status bar is
1316 visible. If so we neither want do draw nor enable the
1317 peak meter. */
1318 if (peak_meter_y + h <= skin_viewport->vp.y+skin_viewport->vp.height) {
1319 peak_meter_enable(true);
1320 peak_meter_screen(gwps->display, 0, peak_meter_y,
1321 MIN(h, skin_viewport->vp.y+skin_viewport->vp.height - peak_meter_y));
1322 }
1323 }
1324 }
1325
1326#else /* HAVE_LCD_CHARCELL */
1327
1328 /* progressbar */
1329 if (flags & vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
1330 {
1331 if (data->full_line_progressbar)
1332 draw_player_fullbar(gwps, linebuf, sizeof(linebuf));
1333 else
1334 draw_player_progress(gwps);
1335 }
1336#endif
1337
1338 if (line_count>= 0 && update_line && !hidden_vp &&
1339 /* conditionals clear the line which means if the %Vd is put into the default
1340 viewport there will be a blank line.
1341 To get around this we dont allow any actual drawing to happen in the
1342 deault vp if other vp's are defined */
1343 ((skin_viewport->label != VP_DEFAULT_LABEL && viewport_list->next) ||
1344 !viewport_list->next))
1345 {
1346 if (flags & WPS_REFRESH_SCROLL)
1347 {
1348 /* if the line is a scrolling one we don't want to update
1349 too often, so that it has the time to scroll */
1350 if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh)
1351 write_line(display, &align, line_count, true);
1352 }
1353 else
1354 write_line(display, &align, line_count, false);
1355 }
1356 }
1357#ifdef HAVE_LCD_BITMAP
1358 /* progressbar */
1359 if (vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
1360 {
1361 struct skin_token_list *bar = gwps->data->progressbars;
1362 while (bar)
1363 {
1364 struct progressbar *thisbar = (struct progressbar*)bar->token->value.data;
1365 if (thisbar->vp == &skin_viewport->vp && thisbar->draw)
1366 {
1367 draw_progressbar(gwps, thisbar);
1368 }
1369 bar = bar->next;
1370 }
1371 }
1372 /* Now display any images in this viewport */
1373 if (!hidden_vp)
1374 wps_display_images(gwps, &skin_viewport->vp);
1375#endif
1376 } 830 }
1377
1378 /* Restore the default viewport */
1379 display->set_viewport(NULL);
1380
1381 display->update();
1382
1383 return true;
1384} 831}
1385 832
1386bool skin_has_sbs(enum screen_type screen, struct wps_data *data) 833bool skin_has_sbs(enum screen_type screen, struct wps_data *data)
@@ -1396,6 +843,7 @@ bool skin_has_sbs(enum screen_type screen, struct wps_data *data)
1396#endif 843#endif
1397 return draw; 844 return draw;
1398} 845}
846#endif
1399 847
1400/* do the button loop as often as required for the peak meters to update 848/* do the button loop as often as required for the peak meters to update
1401 * with a good refresh rate. 849 * with a good refresh rate.
@@ -1434,7 +882,7 @@ int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout)
1434 FOR_NB_SCREENS(i) 882 FOR_NB_SCREENS(i)
1435 { 883 {
1436 if(gwps[i].data->peak_meter_enabled) 884 if(gwps[i].data->peak_meter_enabled)
1437 skin_update(&gwps[i], WPS_REFRESH_PEAK_METER); 885 skin_update(&gwps[i], SKIN_REFRESH_PEAK_METER);
1438 next_refresh += HZ / PEAK_METER_FPS; 886 next_refresh += HZ / PEAK_METER_FPS;
1439 } 887 }
1440 } 888 }