1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002-2007 Björn Stenberg
11 * Copyright (C) 2007-2008 Nicolas Pennequin
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
28 #include "rbunicode.h"
34 #include "statusbar.h"
35 #include "scrollbar.h"
36 #include "screen_access.h"
38 #ifdef HAVE_LCD_BITMAP
39 #include "peakmeter.h"
48 #if CONFIG_CODEC == SWCODEC
55 #include "wps_internals.h"
56 #include "skin_engine.h"
57 #include "statusbar-skinned.h"
59 static bool skin_redraw(struct gui_wps
*gwps
, unsigned refresh_mode
);
62 /* TODO: maybe move this whole function into wps.c instead ? */
63 bool gui_wps_display(struct gui_wps
*gwps
)
65 struct screen
*display
= gwps
->display
;
67 /* Update the values in the first (default) viewport - in case the user
68 has modified the statusbar or colour settings */
70 if (display
->depth
> 1)
72 struct viewport
*vp
= &find_viewport(VP_DEFAULT_LABEL
, gwps
->data
)->vp
;
73 vp
->fg_pattern
= display
->get_foreground();
74 vp
->bg_pattern
= display
->get_background();
77 display
->backdrop_show(BACKDROP_SKIN_WPS
);
78 return skin_redraw(gwps
, WPS_REFRESH_ALL
);
81 /* update a skinned screen, update_type is WPS_REFRESH_* values.
82 * Usually it should only be WPS_REFRESH_NON_STATIC
83 * A full update will be done if required (state.do_full_update == true)
85 bool skin_update(struct gui_wps
*gwps
, unsigned int update_type
)
88 /* This maybe shouldnt be here, but while the skin is only used to
89 * display the music screen this is better than whereever we are being
90 * called from. This is also safe for skined screen which dont use the id3 */
91 struct mp3entry
*id3
= gwps
->state
->id3
;
92 bool cuesheet_update
= (id3
!= NULL
? cuesheet_subtrack_changed(id3
) : false);
93 gwps
->sync_data
->do_full_update
|= cuesheet_update
;
95 retval
= skin_redraw(gwps
, gwps
->sync_data
->do_full_update
?
96 WPS_REFRESH_ALL
: update_type
);
100 #ifdef HAVE_LCD_BITMAP
102 void skin_statusbar_changed(struct gui_wps
*skin
)
106 struct wps_data
*data
= skin
->data
;
107 const struct screen
*display
= skin
->display
;
108 const int screen
= display
->screen_type
;
110 struct viewport
*vp
= &find_viewport(VP_DEFAULT_LABEL
, data
)->vp
;
111 viewport_set_fullscreen(vp
, screen
);
113 if (data
->wps_sb_tag
)
114 { /* fix up the default viewport */
115 if (data
->show_sb_on_wps
)
117 if (statusbar_position(screen
) != STATUSBAR_OFF
)
118 return; /* vp is fixed already */
120 vp
->y
= STATUSBAR_HEIGHT
;
121 vp
->height
= display
->lcdheight
- STATUSBAR_HEIGHT
;
125 if (statusbar_position(screen
) == STATUSBAR_OFF
)
126 return; /* vp is fixed already */
128 vp
->height
= display
->lcdheight
;
129 vp
->width
= display
->lcdwidth
;
134 static void draw_progressbar(struct gui_wps
*gwps
,
135 struct skin_viewport
*wps_vp
)
137 struct screen
*display
= gwps
->display
;
138 struct wps_state
*state
= gwps
->state
;
139 struct progressbar
*pb
= wps_vp
->pb
;
140 struct mp3entry
*id3
= state
->id3
;
145 int line_height
= font_get(wps_vp
->vp
.font
)->height
;
146 /* center the pb in the line, but only if the line is higher than the pb */
147 int center
= (line_height
-pb
->height
)/2;
148 /* if Y was not set calculate by font height,Y is -line_number-1 */
149 y
= (-y
-1)*line_height
+ (0 > center
? 0 : center
);
155 elapsed
= id3
->elapsed
;
156 length
= id3
->length
;
164 if (pb
->have_bitmap_pb
)
165 gui_bitmap_scrollbar_draw(display
, pb
->bm
,
166 pb
->x
, y
, pb
->width
, pb
->bm
.height
,
167 length
? length
: 1, 0,
168 length
? elapsed
+ state
->ff_rewind_count
: 0,
171 gui_scrollbar_draw(display
, pb
->x
, y
, pb
->width
, pb
->height
,
172 length
? length
: 1, 0,
173 length
? elapsed
+ state
->ff_rewind_count
: 0,
175 #ifdef AB_REPEAT_ENABLE
176 if ( ab_repeat_mode_enabled() && length
!= 0 )
177 ab_draw_markers(display
, length
,
178 pb
->x
, pb
->x
+ pb
->width
, y
, pb
->height
);
181 if (id3
&& id3
->cuesheet
)
182 cue_draw_markers(display
, state
->id3
->cuesheet
, length
,
183 pb
->x
, pb
->x
+ pb
->width
, y
+1, pb
->height
-2);
186 /* clears the area where the image was shown */
187 static void clear_image_pos(struct gui_wps
*gwps
, struct gui_img
*img
)
191 gwps
->display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
192 gwps
->display
->fillrect(img
->x
, img
->y
, img
->bm
.width
, img
->subimage_height
);
193 gwps
->display
->set_drawmode(DRMODE_SOLID
);
196 static void wps_draw_image(struct gui_wps
*gwps
, struct gui_img
*img
, int subimage
)
198 struct screen
*display
= gwps
->display
;
199 if(img
->always_display
)
200 display
->set_drawmode(DRMODE_FG
);
202 display
->set_drawmode(DRMODE_SOLID
);
205 if(img
->bm
.format
== FORMAT_MONO
) {
207 display
->mono_bitmap_part(img
->bm
.data
,
208 0, img
->subimage_height
* subimage
,
209 img
->bm
.width
, img
->x
,
210 img
->y
, img
->bm
.width
,
211 img
->subimage_height
);
214 display
->transparent_bitmap_part((fb_data
*)img
->bm
.data
,
215 0, img
->subimage_height
* subimage
,
216 STRIDE(display
->screen_type
,
217 img
->bm
.width
, img
->bm
.height
),
218 img
->x
, img
->y
, img
->bm
.width
,
219 img
->subimage_height
);
224 static void wps_display_images(struct gui_wps
*gwps
, struct viewport
* vp
)
226 if(!gwps
|| !gwps
->data
|| !gwps
->display
)
229 struct wps_data
*data
= gwps
->data
;
230 struct screen
*display
= gwps
->display
;
231 struct skin_token_list
*list
= data
->images
;
235 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
238 if (img
->display
>= 0)
240 wps_draw_image(gwps
, img
, img
->display
);
242 else if (img
->always_display
&& img
->vp
== vp
)
244 wps_draw_image(gwps
, img
, 0);
250 /* now draw the AA */
251 if (data
->albumart
&& data
->albumart
->vp
== vp
252 && data
->albumart
->draw
)
254 draw_album_art(gwps
, playback_current_aa_hid(data
->playback_aa_slot
),
256 data
->albumart
->draw
= false;
260 display
->set_drawmode(DRMODE_SOLID
);
263 #else /* HAVE_LCD_CHARCELL */
265 static bool draw_player_progress(struct gui_wps
*gwps
)
267 struct wps_state
*state
= gwps
->state
;
268 struct screen
*display
= gwps
->display
;
269 unsigned char progress_pattern
[7];
274 if (LIKELY(state
->id3
))
276 elapsed
= state
->id3
->elapsed
;
277 length
= state
->id3
->length
;
286 pos
= 36 * (elapsed
+ state
->ff_rewind_count
) / length
;
288 for (i
= 0; i
< 7; i
++, pos
-= 5)
291 progress_pattern
[i
] = 0x1fu
;
293 progress_pattern
[i
] = 0x00u
;
295 progress_pattern
[i
] = 0x1fu
>> pos
;
298 display
->define_pattern(gwps
->data
->wps_progress_pat
[0], progress_pattern
);
302 static void draw_player_fullbar(struct gui_wps
*gwps
, char* buf
, int buf_size
)
304 static const unsigned char numbers
[10][4] = {
305 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
306 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
307 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
308 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
309 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
310 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
311 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
312 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
313 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
314 {0x0e, 0x0e, 0x02, 0x0e}, /* 9 */
317 struct wps_state
*state
= gwps
->state
;
318 struct screen
*display
= gwps
->display
;
319 struct wps_data
*data
= gwps
->data
;
320 unsigned char progress_pattern
[7];
330 if (LIKELY(state
->id3
))
332 elapsed
= state
->id3
->elapsed
;
333 length
= state
->id3
->length
;
341 if (buf_size
< 34) /* worst case: 11x UTF-8 char + \0 */
344 time
= elapsed
+ state
->ff_rewind_count
;
346 pos
= 55 * time
/ length
;
348 memset(timestr
, 0, sizeof(timestr
));
349 format_time(timestr
, sizeof(timestr
)-2, time
);
350 timestr
[strlen(timestr
)] = ':'; /* always safe */
352 for (i
= 0; i
< 11; i
++, pos
-= 5)
355 memset(progress_pattern
, 0, sizeof(progress_pattern
));
357 if ((digit
= timestr
[time_idx
]))
362 if (timestr
[time_idx
+ 1] == ':') /* ones, left aligned */
364 memcpy(progress_pattern
, numbers
[digit
], 4);
367 else /* tens, shifted right */
369 for (j
= 0; j
< 4; j
++)
370 progress_pattern
[j
] = numbers
[digit
][j
] >> 1;
372 if (time_idx
> 0) /* not the first group, add colon in front */
374 progress_pattern
[1] |= 0x10u
;
375 progress_pattern
[3] |= 0x10u
;
381 progress_pattern
[5] = progress_pattern
[6] = 0x1fu
;
384 if (pos
> 0 && pos
< 5)
387 progress_pattern
[5] = progress_pattern
[6] = (~0x1fu
>> pos
) & 0x1fu
;
390 if (softchar
&& pat_idx
< 8)
392 display
->define_pattern(data
->wps_progress_pat
[pat_idx
],
394 buf
= utf8encode(data
->wps_progress_pat
[pat_idx
], buf
);
398 buf
= utf8encode(' ', buf
);
400 buf
= utf8encode(0xe115, buf
); /* 2/7 _ */
405 #endif /* HAVE_LCD_CHARCELL */
407 /* Return the index to the end token for the conditional token at index.
408 The conditional token can be either a start token or a separator
411 static int find_conditional_end(struct wps_data
*data
, int index
)
414 while (data
->tokens
[ret
].type
!= WPS_TOKEN_CONDITIONAL_END
)
415 ret
= data
->tokens
[ret
].value
.i
;
417 /* ret now is the index to the end token for the conditional. */
421 /* Evaluate the conditional that is at *token_index and return whether a skip
422 has ocurred. *token_index is updated with the new position.
424 static bool evaluate_conditional(struct gui_wps
*gwps
, int *token_index
)
429 struct wps_data
*data
= gwps
->data
;
432 int cond_index
= *token_index
;
435 unsigned char num_options
= data
->tokens
[cond_index
].value
.i
& 0xFF;
436 unsigned char prev_val
= (data
->tokens
[cond_index
].value
.i
& 0xFF00) >> 8;
438 /* treat ?xx<true> constructs as if they had 2 options. */
442 int intval
= num_options
;
443 /* get_token_value needs to know the number of options in the enum */
444 value
= get_token_value(gwps
, &data
->tokens
[cond_index
+ 1],
445 result
, sizeof(result
), &intval
);
447 /* intval is now the number of the enum option we want to read,
448 starting from 1. If intval is -1, we check if value is empty. */
450 intval
= (value
&& *value
) ? 1 : num_options
;
451 else if (intval
> num_options
|| intval
< 1)
452 intval
= num_options
;
454 data
->tokens
[cond_index
].value
.i
= (intval
<< 8) + num_options
;
456 /* skip to the appropriate enum case */
457 int next
= cond_index
+ 2;
458 for (i
= 1; i
< intval
; i
++)
460 next
= data
->tokens
[next
].value
.i
;
464 if (prev_val
== intval
)
466 /* Same conditional case as previously. Return without clearing the
471 cond_end
= find_conditional_end(data
, cond_index
+ 2);
472 for (i
= cond_index
+ 3; i
< cond_end
; i
++)
474 #ifdef HAVE_LCD_BITMAP
475 /* clear all pictures in the conditional and nested ones */
476 if (data
->tokens
[i
].type
== WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
)
477 clear_image_pos(gwps
, find_image(data
->tokens
[i
].value
.i
&0xFF, gwps
->data
));
480 if (data
->albumart
&& data
->tokens
[i
].type
== WPS_TOKEN_ALBUMART_DISPLAY
)
483 playback_current_aa_hid(data
->playback_aa_slot
), true);
484 data
->albumart
->draw
= false;
493 /* Read a (sub)line to the given alignment format buffer.
494 linebuf is the buffer where the data is actually stored.
495 align is the alignment format that'll be used to display the text.
496 The return value indicates whether the line needs to be updated.
498 static bool get_line(struct gui_wps
*gwps
,
499 struct skin_subline
*subline
,
500 struct align_pos
*align
,
504 struct wps_data
*data
= gwps
->data
;
507 char *buf
= linebuf
; /* will always point to the writing position */
508 char *linebuf_end
= linebuf
+ linebuf_size
- 1;
512 /* alignment-related variables */
514 char* cur_align_start
;
515 cur_align_start
= buf
;
516 cur_align
= WPS_ALIGN_LEFT
;
518 align
->center
= NULL
;
520 /* Process all tokens of the desired subline */
521 for (i
= subline
->first_token_idx
;
522 i
<= subline
->last_token_idx
; i
++)
524 switch(data
->tokens
[i
].type
)
526 case WPS_TOKEN_CONDITIONAL
:
527 /* place ourselves in the right conditional case */
528 update
|= evaluate_conditional(gwps
, &i
);
531 case WPS_TOKEN_CONDITIONAL_OPTION
:
532 /* we've finished in the curent conditional case,
533 skip to the end of the conditional structure */
534 i
= find_conditional_end(data
, i
);
537 #ifdef HAVE_LCD_BITMAP
538 case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
:
540 char n
= data
->tokens
[i
].value
.i
& 0xFF;
541 int subimage
= data
->tokens
[i
].value
.i
>> 8;
542 struct gui_img
*img
= find_image(n
, data
);
544 if (img
&& img
->loaded
)
545 img
->display
= subimage
;
550 case WPS_TOKEN_ALIGN_LEFT
:
551 case WPS_TOKEN_ALIGN_CENTER
:
552 case WPS_TOKEN_ALIGN_RIGHT
:
553 /* remember where the current aligned text started */
557 align
->left
= cur_align_start
;
560 case WPS_ALIGN_CENTER
:
561 align
->center
= cur_align_start
;
564 case WPS_ALIGN_RIGHT
:
565 align
->right
= cur_align_start
;
568 /* start a new alignment */
569 switch (data
->tokens
[i
].type
)
571 case WPS_TOKEN_ALIGN_LEFT
:
572 cur_align
= WPS_ALIGN_LEFT
;
574 case WPS_TOKEN_ALIGN_CENTER
:
575 cur_align
= WPS_ALIGN_CENTER
;
577 case WPS_TOKEN_ALIGN_RIGHT
:
578 cur_align
= WPS_ALIGN_RIGHT
;
584 cur_align_start
= buf
;
586 case WPS_VIEWPORT_ENABLE
:
588 char label
= data
->tokens
[i
].value
.i
;
589 char temp
= VP_DRAW_HIDEABLE
;
590 /* viewports are allowed to share id's so find and enable
592 struct skin_token_list
*list
= data
->viewports
;
595 struct skin_viewport
*vp
=
596 (struct skin_viewport
*)list
->token
->value
.data
;
597 if (vp
->label
== label
)
599 if (vp
->hidden_flags
&VP_DRAW_WASHIDDEN
)
600 temp
|= VP_DRAW_WASHIDDEN
;
601 vp
->hidden_flags
= temp
;
609 /* get the value of the tag and copy it to the buffer */
610 const char *value
= get_token_value(gwps
, &data
->tokens
[i
],
611 temp_buf
, sizeof(temp_buf
), NULL
);
615 while (*value
&& (buf
< linebuf_end
))
623 /* close the current alignment */
627 align
->left
= cur_align_start
;
630 case WPS_ALIGN_CENTER
:
631 align
->center
= cur_align_start
;
634 case WPS_ALIGN_RIGHT
:
635 align
->right
= cur_align_start
;
641 static void get_subline_timeout(struct gui_wps
*gwps
, struct skin_subline
*subline
)
643 struct wps_data
*data
= gwps
->data
;
645 subline
->time_mult
= DEFAULT_SUBLINE_TIME_MULTIPLIER
;
647 for (i
= subline
->first_token_idx
;
648 i
<= subline
->last_token_idx
; i
++)
650 switch(data
->tokens
[i
].type
)
652 case WPS_TOKEN_CONDITIONAL
:
653 /* place ourselves in the right conditional case */
654 evaluate_conditional(gwps
, &i
);
657 case WPS_TOKEN_CONDITIONAL_OPTION
:
658 /* we've finished in the curent conditional case,
659 skip to the end of the conditional structure */
660 i
= find_conditional_end(data
, i
);
663 case WPS_TOKEN_SUBLINE_TIMEOUT
:
664 subline
->time_mult
= data
->tokens
[i
].value
.i
;
673 /* Calculates which subline should be displayed for the specified line
674 Returns true iff the subline must be refreshed */
675 static bool update_curr_subline(struct gui_wps
*gwps
, struct skin_line
*line
)
677 /* shortcut this whole thing if we need to reset the line completly */
678 if (line
->curr_subline
== NULL
)
680 line
->subline_expire_time
= current_tick
;
681 line
->curr_subline
= &line
->sublines
;
682 if (!line
->curr_subline
->next
)
684 line
->subline_expire_time
+= 100*HZ
;
688 get_subline_timeout(gwps
, line
->curr_subline
);
689 line
->subline_expire_time
+= TIMEOUT_UNIT
*line
->curr_subline
->time_mult
;
693 /* if time to advance to next sub-line */
694 if (TIME_AFTER(current_tick
, line
->subline_expire_time
- 1))
696 /* if there is only one subline, there is no need to search for a new one */
697 if (&line
->sublines
== line
->curr_subline
&&
698 line
->curr_subline
->next
== NULL
)
700 line
->subline_expire_time
+= 100 * HZ
;
703 if (line
->curr_subline
->next
)
704 line
->curr_subline
= line
->curr_subline
->next
;
706 line
->curr_subline
= &line
->sublines
;
707 get_subline_timeout(gwps
, line
->curr_subline
);
708 line
->subline_expire_time
+= TIMEOUT_UNIT
*line
->curr_subline
->time_mult
;
714 /* Display a line appropriately according to its alignment format.
715 format_align contains the text, separated between left, center and right.
716 line is the index of the line on the screen.
717 scroll indicates whether the line is a scrolling one or not.
719 static void write_line(struct screen
*display
,
720 struct align_pos
*format_align
,
724 int left_width
= 0, left_xpos
;
725 int center_width
= 0, center_xpos
;
726 int right_width
= 0, right_xpos
;
732 /* calculate different string sizes and positions */
733 display
->getstringsize((unsigned char *)" ", &space_width
, &string_height
);
734 if (format_align
->left
!= 0) {
735 display
->getstringsize((unsigned char *)format_align
->left
,
736 &left_width
, &string_height
);
739 if (format_align
->right
!= 0) {
740 display
->getstringsize((unsigned char *)format_align
->right
,
741 &right_width
, &string_height
);
744 if (format_align
->center
!= 0) {
745 display
->getstringsize((unsigned char *)format_align
->center
,
746 ¢er_width
, &string_height
);
750 right_xpos
= (display
->getwidth() - right_width
);
751 center_xpos
= (display
->getwidth() + left_xpos
- center_width
) / 2;
753 scroll_width
= display
->getwidth() - left_xpos
;
755 /* Checks for overlapping strings.
756 If needed the overlapping strings will be merged, separated by a
759 /* CASE 1: left and centered string overlap */
760 /* there is a left string, need to merge left and center */
761 if ((left_width
!= 0 && center_width
!= 0) &&
762 (left_xpos
+ left_width
+ space_width
> center_xpos
)) {
763 /* replace the former separator '\0' of left and
764 center string with a space */
765 *(--format_align
->center
) = ' ';
766 /* calculate the new width and position of the merged string */
767 left_width
= left_width
+ space_width
+ center_width
;
768 /* there is no centered string anymore */
771 /* there is no left string, move center to left */
772 if ((left_width
== 0 && center_width
!= 0) &&
773 (left_xpos
+ left_width
> center_xpos
)) {
774 /* move the center string to the left string */
775 format_align
->left
= format_align
->center
;
776 /* calculate the new width and position of the string */
777 left_width
= center_width
;
778 /* there is no centered string anymore */
782 /* CASE 2: centered and right string overlap */
783 /* there is a right string, need to merge center and right */
784 if ((center_width
!= 0 && right_width
!= 0) &&
785 (center_xpos
+ center_width
+ space_width
> right_xpos
)) {
786 /* replace the former separator '\0' of center and
787 right string with a space */
788 *(--format_align
->right
) = ' ';
789 /* move the center string to the right after merge */
790 format_align
->right
= format_align
->center
;
791 /* calculate the new width and position of the merged string */
792 right_width
= center_width
+ space_width
+ right_width
;
793 right_xpos
= (display
->getwidth() - right_width
);
794 /* there is no centered string anymore */
797 /* there is no right string, move center to right */
798 if ((center_width
!= 0 && right_width
== 0) &&
799 (center_xpos
+ center_width
> right_xpos
)) {
800 /* move the center string to the right string */
801 format_align
->right
= format_align
->center
;
802 /* calculate the new width and position of the string */
803 right_width
= center_width
;
804 right_xpos
= (display
->getwidth() - right_width
);
805 /* there is no centered string anymore */
809 /* CASE 3: left and right overlap
810 There is no center string anymore, either there never
811 was one or it has been merged in case 1 or 2 */
812 /* there is a left string, need to merge left and right */
813 if ((left_width
!= 0 && center_width
== 0 && right_width
!= 0) &&
814 (left_xpos
+ left_width
+ space_width
> right_xpos
)) {
815 /* replace the former separator '\0' of left and
816 right string with a space */
817 *(--format_align
->right
) = ' ';
818 /* calculate the new width and position of the string */
819 left_width
= left_width
+ space_width
+ right_width
;
820 /* there is no right string anymore */
823 /* there is no left string, move right to left */
824 if ((left_width
== 0 && center_width
== 0 && right_width
!= 0) &&
825 (left_width
> right_xpos
)) {
826 /* move the right string to the left string */
827 format_align
->left
= format_align
->right
;
828 /* calculate the new width and position of the string */
829 left_width
= right_width
;
830 /* there is no right string anymore */
834 ypos
= (line
* string_height
);
837 if (scroll
&& ((left_width
> scroll_width
) ||
838 (center_width
> scroll_width
) ||
839 (right_width
> scroll_width
)))
841 display
->puts_scroll(0, line
,
842 (unsigned char *)format_align
->left
);
846 #ifdef HAVE_LCD_BITMAP
847 /* clear the line first */
848 display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
849 display
->fillrect(left_xpos
, ypos
, display
->getwidth(), string_height
);
850 display
->set_drawmode(DRMODE_SOLID
);
853 /* Nasty hack: we output an empty scrolling string,
854 which will reset the scroller for that line */
855 display
->puts_scroll(0, line
, (unsigned char *)"");
857 /* print aligned strings */
860 display
->putsxy(left_xpos
, ypos
,
861 (unsigned char *)format_align
->left
);
863 if (center_width
!= 0)
865 display
->putsxy(center_xpos
, ypos
,
866 (unsigned char *)format_align
->center
);
868 if (right_width
!= 0)
870 display
->putsxy(right_xpos
, ypos
,
871 (unsigned char *)format_align
->right
);
876 static bool skin_redraw(struct gui_wps
*gwps
, unsigned refresh_mode
)
878 struct wps_data
*data
= gwps
->data
;
879 struct screen
*display
= gwps
->display
;
881 if (!data
|| !display
|| !gwps
->state
)
885 char linebuf
[MAX_PATH
];
887 struct align_pos align
;
893 struct skin_token_list
*viewport_list
;
895 bool update_line
, new_subline_refresh
;
897 #ifdef HAVE_LCD_BITMAP
899 /* to find out wether the peak meter is enabled we
900 assume it wasn't until we find a line that contains
901 the peak meter. We can't use peak_meter_enabled itself
902 because that would mean to turn off the meter thread
903 temporarily. (That shouldn't matter unless yield
904 or sleep is called but who knows...)
906 bool enable_pm
= false;
910 /* reset to first subline if refresh all flag is set */
911 if (refresh_mode
== WPS_REFRESH_ALL
)
913 struct skin_line
*line
;
914 struct skin_viewport
*skin_viewport
= find_viewport(VP_DEFAULT_LABEL
, data
);
916 if (!(skin_viewport
->hidden_flags
& VP_NEVER_VISIBLE
))
918 display
->set_viewport(&skin_viewport
->vp
);
919 display
->clear_viewport();
922 for (viewport_list
= data
->viewports
;
923 viewport_list
; viewport_list
= viewport_list
->next
)
926 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
927 for(line
= skin_viewport
->lines
; line
; line
= line
->next
)
929 line
->curr_subline
= NULL
;
934 #ifdef HAVE_LCD_CHARCELLS
936 for (i
= 0; i
< 8; i
++)
938 if (data
->wps_progress_pat
[i
] == 0)
939 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
943 /* disable any viewports which are conditionally displayed */
944 for (viewport_list
= data
->viewports
;
945 viewport_list
; viewport_list
= viewport_list
->next
)
947 struct skin_viewport
*skin_viewport
=
948 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
949 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
953 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
955 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
956 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
958 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
961 int viewport_count
= 0;
962 for (viewport_list
= data
->viewports
;
963 viewport_list
; viewport_list
= viewport_list
->next
, viewport_count
++)
965 struct skin_viewport
*skin_viewport
=
966 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
967 unsigned vp_refresh_mode
= refresh_mode
;
969 display
->set_viewport(&skin_viewport
->vp
);
973 #ifdef HAVE_LCD_BITMAP
974 /* Set images to not to be displayed */
975 struct skin_token_list
*imglist
= data
->images
;
978 struct gui_img
*img
= (struct gui_img
*)imglist
->token
->value
.data
;
980 imglist
= imglist
->next
;
983 /* dont redraw the viewport if its disabled */
984 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
985 { /* don't draw anything into this one */
986 vp_refresh_mode
= 0; hidden_vp
= true;
988 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
990 if (!(skin_viewport
->hidden_flags
&VP_DRAW_WASHIDDEN
))
991 display
->scroll_stop(&skin_viewport
->vp
);
992 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
995 else if (((skin_viewport
->hidden_flags
&
996 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
997 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
999 vp_refresh_mode
= WPS_REFRESH_ALL
;
1000 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
1003 if (vp_refresh_mode
== WPS_REFRESH_ALL
)
1005 display
->clear_viewport();
1008 /* loop over the lines for this viewport */
1009 struct skin_line
*line
;
1012 for (line
= skin_viewport
->lines
; line
; line
= line
->next
, line_count
++)
1014 struct skin_subline
*subline
;
1015 memset(linebuf
, 0, sizeof(linebuf
));
1016 update_line
= false;
1018 /* get current subline for the line */
1019 new_subline_refresh
= update_curr_subline(gwps
, line
);
1020 subline
= line
->curr_subline
;
1021 flags
= line
->curr_subline
->line_type
;
1023 if (vp_refresh_mode
== WPS_REFRESH_ALL
|| (flags
& vp_refresh_mode
)
1024 || new_subline_refresh
|| hidden_vp
)
1026 /* get_line tells us if we need to update the line */
1027 update_line
= get_line(gwps
, subline
,
1028 &align
, linebuf
, sizeof(linebuf
));
1030 #ifdef HAVE_LCD_BITMAP
1032 if (flags
& vp_refresh_mode
& WPS_REFRESH_PEAK_METER
)
1034 /* the peakmeter should be alone on its line */
1035 update_line
= false;
1037 int h
= font_get(skin_viewport
->vp
.font
)->height
;
1038 int peak_meter_y
= line_count
* h
;
1040 /* The user might decide to have the peak meter in the last
1041 line so that it is only displayed if no status bar is
1042 visible. If so we neither want do draw nor enable the
1044 if (peak_meter_y
+ h
<= skin_viewport
->vp
.y
+skin_viewport
->vp
.height
) {
1045 /* found a line with a peak meter -> remember that we must
1048 peak_meter_enabled
= true;
1049 peak_meter_screen(gwps
->display
, 0, peak_meter_y
,
1050 MIN(h
, skin_viewport
->vp
.y
+skin_viewport
->vp
.height
- peak_meter_y
));
1054 peak_meter_enabled
= false;
1058 #else /* HAVE_LCD_CHARCELL */
1061 if (flags
& vp_refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
)
1063 if (data
->full_line_progressbar
)
1064 draw_player_fullbar(gwps
, linebuf
, sizeof(linebuf
));
1066 draw_player_progress(gwps
);
1070 if (update_line
&& !hidden_vp
&&
1071 /* conditionals clear the line which means if the %Vd is put into the default
1072 viewport there will be a blank line.
1073 To get around this we dont allow any actual drawing to happen in the
1074 deault vp if other vp's are defined */
1075 ((skin_viewport
->label
!= VP_DEFAULT_LABEL
&& viewport_list
->next
) ||
1076 !viewport_list
->next
))
1078 if (flags
& WPS_REFRESH_SCROLL
)
1080 /* if the line is a scrolling one we don't want to update
1081 too often, so that it has the time to scroll */
1082 if ((vp_refresh_mode
& WPS_REFRESH_SCROLL
) || new_subline_refresh
)
1083 write_line(display
, &align
, line_count
, true);
1086 write_line(display
, &align
, line_count
, false);
1089 #ifdef HAVE_LCD_BITMAP
1091 if (vp_refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
)
1093 if (skin_viewport
->pb
)
1095 draw_progressbar(gwps
, skin_viewport
);
1098 /* Now display any images in this viewport */
1100 wps_display_images(gwps
, &skin_viewport
->vp
);
1104 #ifdef HAVE_LCD_BITMAP
1105 data
->peak_meter_enabled
= enable_pm
;
1108 if (refresh_mode
& WPS_REFRESH_STATUSBAR
)
1110 viewportmanager_set_statusbar(gwps
->sync_data
->statusbars
);
1112 /* Restore the default viewport */
1113 display
->set_viewport(NULL
);