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 "settings_list.h"
29 #include "rbunicode.h"
34 #include "powermgmt.h"
37 #ifdef HAVE_LCD_CHARCELLS
41 #include "mp3_playback.h"
45 #include "scrollbar.h"
48 #ifdef HAVE_LCD_BITMAP
49 #include "peakmeter.h"
58 #if CONFIG_CODEC == SWCODEC
65 #include "wps_internals.h"
66 #include "skin_engine.h"
67 #include "statusbar-skinned.h"
69 static bool skin_redraw(struct gui_wps
*gwps
, unsigned refresh_mode
);
72 /* TODO: maybe move this whole function into wps.c instead ? */
73 bool gui_wps_display(struct gui_wps
*gwps
)
75 struct screen
*display
= gwps
->display
;
77 /* Update the values in the first (default) viewport - in case the user
78 has modified the statusbar or colour settings */
80 if (display
->depth
> 1)
82 struct viewport
*vp
= &find_viewport(VP_DEFAULT_LABEL
, gwps
->data
)->vp
;
83 vp
->fg_pattern
= display
->get_foreground();
84 vp
->bg_pattern
= display
->get_background();
87 display
->backdrop_show(BACKDROP_SKIN_WPS
);
88 return skin_redraw(gwps
, WPS_REFRESH_ALL
);
91 /* update a skinned screen, update_type is WPS_REFRESH_* values.
92 * Usually it should only be WPS_REFRESH_NON_STATIC
93 * A full update will be done if required (state.do_full_update == true)
95 bool skin_update(struct gui_wps
*gwps
, unsigned int update_type
)
98 /* This maybe shouldnt be here, but while the skin is only used to
99 * display the music screen this is better than whereever we are being
100 * called from. This is also safe for skined screen which dont use the id3 */
101 struct mp3entry
*id3
= gwps
->state
->id3
;
102 bool cuesheet_update
= (id3
!= NULL
? cuesheet_subtrack_changed(id3
) : false);
103 gwps
->sync_data
->do_full_update
|= cuesheet_update
;
105 retval
= skin_redraw(gwps
, gwps
->sync_data
->do_full_update
?
106 WPS_REFRESH_ALL
: update_type
);
110 #ifdef HAVE_LCD_BITMAP
112 void skin_statusbar_changed(struct gui_wps
*skin
)
116 struct wps_data
*data
= skin
->data
;
117 const struct screen
*display
= skin
->display
;
118 const int screen
= display
->screen_type
;
120 struct viewport
*vp
= &find_viewport(VP_DEFAULT_LABEL
, data
)->vp
;
121 viewport_set_fullscreen(vp
, screen
);
123 if (data
->wps_sb_tag
)
124 { /* fix up the default viewport */
125 if (data
->show_sb_on_wps
)
127 if (statusbar_position(screen
) != STATUSBAR_OFF
)
128 return; /* vp is fixed already */
130 vp
->y
= STATUSBAR_HEIGHT
;
131 vp
->height
= display
->lcdheight
- STATUSBAR_HEIGHT
;
135 if (statusbar_position(screen
) == STATUSBAR_OFF
)
136 return; /* vp is fixed already */
138 vp
->height
= display
->lcdheight
;
139 vp
->width
= display
->lcdwidth
;
144 static void draw_progressbar(struct gui_wps
*gwps
,
145 struct skin_viewport
*wps_vp
)
147 struct screen
*display
= gwps
->display
;
148 struct wps_state
*state
= gwps
->state
;
149 struct progressbar
*pb
= wps_vp
->pb
;
150 struct mp3entry
*id3
= state
->id3
;
155 int line_height
= font_get(wps_vp
->vp
.font
)->height
;
156 /* center the pb in the line, but only if the line is higher than the pb */
157 int center
= (line_height
-pb
->height
)/2;
158 /* if Y was not set calculate by font height,Y is -line_number-1 */
159 y
= (-y
-1)*line_height
+ (0 > center
? 0 : center
);
165 elapsed
= id3
->elapsed
;
166 length
= id3
->length
;
174 if (pb
->have_bitmap_pb
)
175 gui_bitmap_scrollbar_draw(display
, pb
->bm
,
176 pb
->x
, y
, pb
->width
, pb
->bm
.height
,
177 length
? length
: 1, 0,
178 length
? elapsed
+ state
->ff_rewind_count
: 0,
181 gui_scrollbar_draw(display
, pb
->x
, y
, pb
->width
, pb
->height
,
182 length
? length
: 1, 0,
183 length
? elapsed
+ state
->ff_rewind_count
: 0,
185 #ifdef AB_REPEAT_ENABLE
186 if ( ab_repeat_mode_enabled() && length
!= 0 )
187 ab_draw_markers(display
, length
,
188 pb
->x
, pb
->x
+ pb
->width
, y
, pb
->height
);
191 if (id3
&& id3
->cuesheet
)
192 cue_draw_markers(display
, state
->id3
->cuesheet
, length
,
193 pb
->x
, pb
->x
+ pb
->width
, y
+1, pb
->height
-2);
196 /* clears the area where the image was shown */
197 static void clear_image_pos(struct gui_wps
*gwps
, struct gui_img
*img
)
201 gwps
->display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
202 gwps
->display
->fillrect(img
->x
, img
->y
, img
->bm
.width
, img
->subimage_height
);
203 gwps
->display
->set_drawmode(DRMODE_SOLID
);
206 static void wps_draw_image(struct gui_wps
*gwps
, struct gui_img
*img
, int subimage
)
208 struct screen
*display
= gwps
->display
;
209 if(img
->always_display
)
210 display
->set_drawmode(DRMODE_FG
);
212 display
->set_drawmode(DRMODE_SOLID
);
215 if(img
->bm
.format
== FORMAT_MONO
) {
217 display
->mono_bitmap_part(img
->bm
.data
,
218 0, img
->subimage_height
* subimage
,
219 img
->bm
.width
, img
->x
,
220 img
->y
, img
->bm
.width
,
221 img
->subimage_height
);
224 display
->transparent_bitmap_part((fb_data
*)img
->bm
.data
,
225 0, img
->subimage_height
* subimage
,
226 STRIDE(display
->screen_type
,
227 img
->bm
.width
, img
->bm
.height
),
228 img
->x
, img
->y
, img
->bm
.width
,
229 img
->subimage_height
);
234 static void wps_display_images(struct gui_wps
*gwps
, struct viewport
* vp
)
236 if(!gwps
|| !gwps
->data
|| !gwps
->display
)
239 struct wps_data
*data
= gwps
->data
;
240 struct screen
*display
= gwps
->display
;
241 struct skin_token_list
*list
= data
->images
;
245 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
248 if (img
->display
>= 0)
250 wps_draw_image(gwps
, img
, img
->display
);
252 else if (img
->always_display
&& img
->vp
== vp
)
254 wps_draw_image(gwps
, img
, 0);
260 /* now draw the AA */
261 if (data
->albumart
&& data
->albumart
->vp
== vp
262 && data
->albumart
->draw
)
264 draw_album_art(gwps
, playback_current_aa_hid(data
->playback_aa_slot
),
266 data
->albumart
->draw
= false;
270 display
->set_drawmode(DRMODE_SOLID
);
273 #else /* HAVE_LCD_CHARCELL */
275 static bool draw_player_progress(struct gui_wps
*gwps
)
277 struct wps_state
*state
= gwps
->state
;
278 struct screen
*display
= gwps
->display
;
279 unsigned char progress_pattern
[7];
284 if (LIKELY(state
->id3
))
286 elapsed
= state
->id3
->elapsed
;
287 length
= state
->id3
->length
;
296 pos
= 36 * (elapsed
+ state
->ff_rewind_count
) / length
;
298 for (i
= 0; i
< 7; i
++, pos
-= 5)
301 progress_pattern
[i
] = 0x1fu
;
303 progress_pattern
[i
] = 0x00u
;
305 progress_pattern
[i
] = 0x1fu
>> pos
;
308 display
->define_pattern(gwps
->data
->wps_progress_pat
[0], progress_pattern
);
312 static void draw_player_fullbar(struct gui_wps
*gwps
, char* buf
, int buf_size
)
314 static const unsigned char numbers
[10][4] = {
315 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
316 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
317 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
318 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
319 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
320 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
321 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
322 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
323 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
324 {0x0e, 0x0e, 0x02, 0x0e}, /* 9 */
327 struct wps_state
*state
= gwps
->state
;
328 struct screen
*display
= gwps
->display
;
329 struct wps_data
*data
= gwps
->data
;
330 unsigned char progress_pattern
[7];
340 if (LIKELY(state
->id3
))
342 elapsed
= state
->id3
->elapsed
;
343 length
= state
->id3
->length
;
351 if (buf_size
< 34) /* worst case: 11x UTF-8 char + \0 */
354 time
= elapsed
+ state
->ff_rewind_count
;
356 pos
= 55 * time
/ length
;
358 memset(timestr
, 0, sizeof(timestr
));
359 format_time(timestr
, sizeof(timestr
)-2, time
);
360 timestr
[strlen(timestr
)] = ':'; /* always safe */
362 for (i
= 0; i
< 11; i
++, pos
-= 5)
365 memset(progress_pattern
, 0, sizeof(progress_pattern
));
367 if ((digit
= timestr
[time_idx
]))
372 if (timestr
[time_idx
+ 1] == ':') /* ones, left aligned */
374 memcpy(progress_pattern
, numbers
[digit
], 4);
377 else /* tens, shifted right */
379 for (j
= 0; j
< 4; j
++)
380 progress_pattern
[j
] = numbers
[digit
][j
] >> 1;
382 if (time_idx
> 0) /* not the first group, add colon in front */
384 progress_pattern
[1] |= 0x10u
;
385 progress_pattern
[3] |= 0x10u
;
391 progress_pattern
[5] = progress_pattern
[6] = 0x1fu
;
394 if (pos
> 0 && pos
< 5)
397 progress_pattern
[5] = progress_pattern
[6] = (~0x1fu
>> pos
) & 0x1fu
;
400 if (softchar
&& pat_idx
< 8)
402 display
->define_pattern(data
->wps_progress_pat
[pat_idx
],
404 buf
= utf8encode(data
->wps_progress_pat
[pat_idx
], buf
);
408 buf
= utf8encode(' ', buf
);
410 buf
= utf8encode(0xe115, buf
); /* 2/7 _ */
415 #endif /* HAVE_LCD_CHARCELL */
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
421 static int find_conditional_end(struct wps_data
*data
, int index
)
424 while (data
->tokens
[ret
].type
!= WPS_TOKEN_CONDITIONAL_END
)
425 ret
= data
->tokens
[ret
].value
.i
;
427 /* ret now is the index to the end token for the conditional. */
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.
434 static bool evaluate_conditional(struct gui_wps
*gwps
, int *token_index
)
439 struct wps_data
*data
= gwps
->data
;
442 int cond_index
= *token_index
;
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;
448 /* treat ?xx<true> constructs as if they had 2 options. */
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
);
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. */
460 intval
= (value
&& *value
) ? 1 : num_options
;
461 else if (intval
> num_options
|| intval
< 1)
462 intval
= num_options
;
464 data
->tokens
[cond_index
].value
.i
= (intval
<< 8) + num_options
;
466 /* skip to the appropriate enum case */
467 int next
= cond_index
+ 2;
468 for (i
= 1; i
< intval
; i
++)
470 next
= data
->tokens
[next
].value
.i
;
474 if (prev_val
== intval
)
476 /* Same conditional case as previously. Return without clearing the
481 cond_end
= find_conditional_end(data
, cond_index
+ 2);
482 for (i
= cond_index
+ 3; i
< cond_end
; i
++)
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
, find_image(data
->tokens
[i
].value
.i
&0xFF, gwps
->data
));
490 if (data
->albumart
&& data
->tokens
[i
].type
== WPS_TOKEN_ALBUMART_DISPLAY
)
493 playback_current_aa_hid(data
->playback_aa_slot
), true);
494 data
->albumart
->draw
= false;
502 #ifdef HAVE_LCD_BITMAP
503 struct gui_img
* find_image(char label
, struct wps_data
*data
)
505 struct skin_token_list
*list
= data
->images
;
508 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
509 if (img
->label
== label
)
517 struct skin_viewport
* find_viewport(char label
, struct wps_data
*data
)
519 struct skin_token_list
*list
= data
->viewports
;
522 struct skin_viewport
*vp
= (struct skin_viewport
*)list
->token
->value
.data
;
523 if (vp
->label
== label
)
531 /* Read a (sub)line to the given alignment format buffer.
532 linebuf is the buffer where the data is actually stored.
533 align is the alignment format that'll be used to display the text.
534 The return value indicates whether the line needs to be updated.
536 static bool get_line(struct gui_wps
*gwps
,
537 struct skin_subline
*subline
,
538 struct align_pos
*align
,
542 struct wps_data
*data
= gwps
->data
;
545 char *buf
= linebuf
; /* will always point to the writing position */
546 char *linebuf_end
= linebuf
+ linebuf_size
- 1;
550 /* alignment-related variables */
552 char* cur_align_start
;
553 cur_align_start
= buf
;
554 cur_align
= WPS_ALIGN_LEFT
;
556 align
->center
= NULL
;
558 /* Process all tokens of the desired subline */
559 for (i
= subline
->first_token_idx
;
560 i
<= subline
->last_token_idx
; i
++)
562 switch(data
->tokens
[i
].type
)
564 case WPS_TOKEN_CONDITIONAL
:
565 /* place ourselves in the right conditional case */
566 update
|= evaluate_conditional(gwps
, &i
);
569 case WPS_TOKEN_CONDITIONAL_OPTION
:
570 /* we've finished in the curent conditional case,
571 skip to the end of the conditional structure */
572 i
= find_conditional_end(data
, i
);
575 #ifdef HAVE_LCD_BITMAP
576 case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
:
578 char n
= data
->tokens
[i
].value
.i
& 0xFF;
579 int subimage
= data
->tokens
[i
].value
.i
>> 8;
580 struct gui_img
*img
= find_image(n
, data
);
582 if (img
&& img
->loaded
)
583 img
->display
= subimage
;
588 case WPS_TOKEN_ALIGN_LEFT
:
589 case WPS_TOKEN_ALIGN_CENTER
:
590 case WPS_TOKEN_ALIGN_RIGHT
:
591 /* remember where the current aligned text started */
595 align
->left
= cur_align_start
;
598 case WPS_ALIGN_CENTER
:
599 align
->center
= cur_align_start
;
602 case WPS_ALIGN_RIGHT
:
603 align
->right
= cur_align_start
;
606 /* start a new alignment */
607 switch (data
->tokens
[i
].type
)
609 case WPS_TOKEN_ALIGN_LEFT
:
610 cur_align
= WPS_ALIGN_LEFT
;
612 case WPS_TOKEN_ALIGN_CENTER
:
613 cur_align
= WPS_ALIGN_CENTER
;
615 case WPS_TOKEN_ALIGN_RIGHT
:
616 cur_align
= WPS_ALIGN_RIGHT
;
622 cur_align_start
= buf
;
624 case WPS_VIEWPORT_ENABLE
:
626 char label
= data
->tokens
[i
].value
.i
;
627 char temp
= VP_DRAW_HIDEABLE
;
628 /* viewports are allowed to share id's so find and enable
630 struct skin_token_list
*list
= data
->viewports
;
633 struct skin_viewport
*vp
=
634 (struct skin_viewport
*)list
->token
->value
.data
;
635 if (vp
->label
== label
)
637 if (vp
->hidden_flags
&VP_DRAW_WASHIDDEN
)
638 temp
|= VP_DRAW_WASHIDDEN
;
639 vp
->hidden_flags
= temp
;
647 /* get the value of the tag and copy it to the buffer */
648 const char *value
= get_token_value(gwps
, &data
->tokens
[i
],
649 temp_buf
, sizeof(temp_buf
), NULL
);
653 while (*value
&& (buf
< linebuf_end
))
661 /* close the current alignment */
665 align
->left
= cur_align_start
;
668 case WPS_ALIGN_CENTER
:
669 align
->center
= cur_align_start
;
672 case WPS_ALIGN_RIGHT
:
673 align
->right
= cur_align_start
;
679 static void get_subline_timeout(struct gui_wps
*gwps
, struct skin_subline
*subline
)
681 struct wps_data
*data
= gwps
->data
;
683 subline
->time_mult
= DEFAULT_SUBLINE_TIME_MULTIPLIER
;
685 for (i
= subline
->first_token_idx
;
686 i
<= subline
->last_token_idx
; i
++)
688 switch(data
->tokens
[i
].type
)
690 case WPS_TOKEN_CONDITIONAL
:
691 /* place ourselves in the right conditional case */
692 evaluate_conditional(gwps
, &i
);
695 case WPS_TOKEN_CONDITIONAL_OPTION
:
696 /* we've finished in the curent conditional case,
697 skip to the end of the conditional structure */
698 i
= find_conditional_end(data
, i
);
701 case WPS_TOKEN_SUBLINE_TIMEOUT
:
702 subline
->time_mult
= data
->tokens
[i
].value
.i
;
711 /* Calculates which subline should be displayed for the specified line
712 Returns true iff the subline must be refreshed */
713 static bool update_curr_subline(struct gui_wps
*gwps
, struct skin_line
*line
)
715 /* shortcut this whole thing if we need to reset the line completly */
716 if (line
->curr_subline
== NULL
)
718 line
->subline_expire_time
= current_tick
;
719 line
->curr_subline
= &line
->sublines
;
720 if (!line
->curr_subline
->next
)
722 line
->subline_expire_time
+= 100*HZ
;
726 get_subline_timeout(gwps
, line
->curr_subline
);
727 line
->subline_expire_time
+= TIMEOUT_UNIT
*line
->curr_subline
->time_mult
;
731 /* if time to advance to next sub-line */
732 if (TIME_AFTER(current_tick
, line
->subline_expire_time
- 1))
734 /* if there is only one subline, there is no need to search for a new one */
735 if (&line
->sublines
== line
->curr_subline
&&
736 line
->curr_subline
->next
== NULL
)
738 line
->subline_expire_time
+= 100 * HZ
;
741 if (line
->curr_subline
->next
)
742 line
->curr_subline
= line
->curr_subline
->next
;
744 line
->curr_subline
= &line
->sublines
;
745 get_subline_timeout(gwps
, line
->curr_subline
);
746 line
->subline_expire_time
+= TIMEOUT_UNIT
*line
->curr_subline
->time_mult
;
752 /* Display a line appropriately according to its alignment format.
753 format_align contains the text, separated between left, center and right.
754 line is the index of the line on the screen.
755 scroll indicates whether the line is a scrolling one or not.
757 static void write_line(struct screen
*display
,
758 struct align_pos
*format_align
,
762 int left_width
= 0, left_xpos
;
763 int center_width
= 0, center_xpos
;
764 int right_width
= 0, right_xpos
;
770 /* calculate different string sizes and positions */
771 display
->getstringsize((unsigned char *)" ", &space_width
, &string_height
);
772 if (format_align
->left
!= 0) {
773 display
->getstringsize((unsigned char *)format_align
->left
,
774 &left_width
, &string_height
);
777 if (format_align
->right
!= 0) {
778 display
->getstringsize((unsigned char *)format_align
->right
,
779 &right_width
, &string_height
);
782 if (format_align
->center
!= 0) {
783 display
->getstringsize((unsigned char *)format_align
->center
,
784 ¢er_width
, &string_height
);
788 right_xpos
= (display
->getwidth() - right_width
);
789 center_xpos
= (display
->getwidth() + left_xpos
- center_width
) / 2;
791 scroll_width
= display
->getwidth() - left_xpos
;
793 /* Checks for overlapping strings.
794 If needed the overlapping strings will be merged, separated by a
797 /* CASE 1: left and centered string overlap */
798 /* there is a left string, need to merge left and center */
799 if ((left_width
!= 0 && center_width
!= 0) &&
800 (left_xpos
+ left_width
+ space_width
> center_xpos
)) {
801 /* replace the former separator '\0' of left and
802 center string with a space */
803 *(--format_align
->center
) = ' ';
804 /* calculate the new width and position of the merged string */
805 left_width
= left_width
+ space_width
+ center_width
;
806 /* there is no centered string anymore */
809 /* there is no left string, move center to left */
810 if ((left_width
== 0 && center_width
!= 0) &&
811 (left_xpos
+ left_width
> center_xpos
)) {
812 /* move the center string to the left string */
813 format_align
->left
= format_align
->center
;
814 /* calculate the new width and position of the string */
815 left_width
= center_width
;
816 /* there is no centered string anymore */
820 /* CASE 2: centered and right string overlap */
821 /* there is a right string, need to merge center and right */
822 if ((center_width
!= 0 && right_width
!= 0) &&
823 (center_xpos
+ center_width
+ space_width
> right_xpos
)) {
824 /* replace the former separator '\0' of center and
825 right string with a space */
826 *(--format_align
->right
) = ' ';
827 /* move the center string to the right after merge */
828 format_align
->right
= format_align
->center
;
829 /* calculate the new width and position of the merged string */
830 right_width
= center_width
+ space_width
+ right_width
;
831 right_xpos
= (display
->getwidth() - right_width
);
832 /* there is no centered string anymore */
835 /* there is no right string, move center to right */
836 if ((center_width
!= 0 && right_width
== 0) &&
837 (center_xpos
+ center_width
> right_xpos
)) {
838 /* move the center string to the right string */
839 format_align
->right
= format_align
->center
;
840 /* calculate the new width and position of the string */
841 right_width
= center_width
;
842 right_xpos
= (display
->getwidth() - right_width
);
843 /* there is no centered string anymore */
847 /* CASE 3: left and right overlap
848 There is no center string anymore, either there never
849 was one or it has been merged in case 1 or 2 */
850 /* there is a left string, need to merge left and right */
851 if ((left_width
!= 0 && center_width
== 0 && right_width
!= 0) &&
852 (left_xpos
+ left_width
+ space_width
> right_xpos
)) {
853 /* replace the former separator '\0' of left and
854 right string with a space */
855 *(--format_align
->right
) = ' ';
856 /* calculate the new width and position of the string */
857 left_width
= left_width
+ space_width
+ right_width
;
858 /* there is no right string anymore */
861 /* there is no left string, move right to left */
862 if ((left_width
== 0 && center_width
== 0 && right_width
!= 0) &&
863 (left_width
> right_xpos
)) {
864 /* move the right string to the left string */
865 format_align
->left
= format_align
->right
;
866 /* calculate the new width and position of the string */
867 left_width
= right_width
;
868 /* there is no right string anymore */
872 ypos
= (line
* string_height
);
875 if (scroll
&& ((left_width
> scroll_width
) ||
876 (center_width
> scroll_width
) ||
877 (right_width
> scroll_width
)))
879 display
->puts_scroll(0, line
,
880 (unsigned char *)format_align
->left
);
884 #ifdef HAVE_LCD_BITMAP
885 /* clear the line first */
886 display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
887 display
->fillrect(left_xpos
, ypos
, display
->getwidth(), string_height
);
888 display
->set_drawmode(DRMODE_SOLID
);
891 /* Nasty hack: we output an empty scrolling string,
892 which will reset the scroller for that line */
893 display
->puts_scroll(0, line
, (unsigned char *)"");
895 /* print aligned strings */
898 display
->putsxy(left_xpos
, ypos
,
899 (unsigned char *)format_align
->left
);
901 if (center_width
!= 0)
903 display
->putsxy(center_xpos
, ypos
,
904 (unsigned char *)format_align
->center
);
906 if (right_width
!= 0)
908 display
->putsxy(right_xpos
, ypos
,
909 (unsigned char *)format_align
->right
);
914 static bool skin_redraw(struct gui_wps
*gwps
, unsigned refresh_mode
)
916 struct wps_data
*data
= gwps
->data
;
917 struct screen
*display
= gwps
->display
;
919 if (!data
|| !display
|| !gwps
->state
)
923 char linebuf
[MAX_PATH
];
925 struct align_pos align
;
931 struct skin_token_list
*viewport_list
;
933 bool update_line
, new_subline_refresh
;
935 #ifdef HAVE_LCD_BITMAP
937 /* to find out wether the peak meter is enabled we
938 assume it wasn't until we find a line that contains
939 the peak meter. We can't use peak_meter_enabled itself
940 because that would mean to turn off the meter thread
941 temporarily. (That shouldn't matter unless yield
942 or sleep is called but who knows...)
944 bool enable_pm
= false;
948 /* reset to first subline if refresh all flag is set */
949 if (refresh_mode
== WPS_REFRESH_ALL
)
951 struct skin_line
*line
;
952 struct skin_viewport
*skin_viewport
= find_viewport(VP_DEFAULT_LABEL
, data
);
954 if (!(skin_viewport
->hidden_flags
& VP_NEVER_VISIBLE
))
956 display
->set_viewport(&skin_viewport
->vp
);
957 display
->clear_viewport();
960 for (viewport_list
= data
->viewports
;
961 viewport_list
; viewport_list
= viewport_list
->next
)
964 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
965 for(line
= skin_viewport
->lines
; line
; line
= line
->next
)
967 line
->curr_subline
= NULL
;
972 #ifdef HAVE_LCD_CHARCELLS
974 for (i
= 0; i
< 8; i
++)
976 if (data
->wps_progress_pat
[i
] == 0)
977 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
981 /* disable any viewports which are conditionally displayed */
982 for (viewport_list
= data
->viewports
;
983 viewport_list
; viewport_list
= viewport_list
->next
)
985 struct skin_viewport
*skin_viewport
=
986 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
987 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
991 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
993 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
994 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
996 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
999 int viewport_count
= 0;
1000 for (viewport_list
= data
->viewports
;
1001 viewport_list
; viewport_list
= viewport_list
->next
, viewport_count
++)
1003 struct skin_viewport
*skin_viewport
=
1004 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
1005 unsigned vp_refresh_mode
= refresh_mode
;
1007 display
->set_viewport(&skin_viewport
->vp
);
1011 #ifdef HAVE_LCD_BITMAP
1012 /* Set images to not to be displayed */
1013 struct skin_token_list
*imglist
= data
->images
;
1016 struct gui_img
*img
= (struct gui_img
*)imglist
->token
->value
.data
;
1018 imglist
= imglist
->next
;
1021 /* dont redraw the viewport if its disabled */
1022 if (skin_viewport
->hidden_flags
&VP_NEVER_VISIBLE
)
1023 { /* don't draw anything into this one */
1024 vp_refresh_mode
= 0; hidden_vp
= true;
1026 else if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
1028 if (!(skin_viewport
->hidden_flags
&VP_DRAW_WASHIDDEN
))
1029 display
->scroll_stop(&skin_viewport
->vp
);
1030 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
1033 else if (((skin_viewport
->hidden_flags
&
1034 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
1035 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
1037 vp_refresh_mode
= WPS_REFRESH_ALL
;
1038 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
1041 if (vp_refresh_mode
== WPS_REFRESH_ALL
)
1043 display
->clear_viewport();
1046 /* loop over the lines for this viewport */
1047 struct skin_line
*line
;
1050 for (line
= skin_viewport
->lines
; line
; line
= line
->next
, line_count
++)
1052 struct skin_subline
*subline
;
1053 memset(linebuf
, 0, sizeof(linebuf
));
1054 update_line
= false;
1056 /* get current subline for the line */
1057 new_subline_refresh
= update_curr_subline(gwps
, line
);
1058 subline
= line
->curr_subline
;
1059 flags
= line
->curr_subline
->line_type
;
1061 if (vp_refresh_mode
== WPS_REFRESH_ALL
|| (flags
& vp_refresh_mode
)
1062 || new_subline_refresh
|| hidden_vp
)
1064 /* get_line tells us if we need to update the line */
1065 update_line
= get_line(gwps
, subline
,
1066 &align
, linebuf
, sizeof(linebuf
));
1068 #ifdef HAVE_LCD_BITMAP
1070 if (flags
& vp_refresh_mode
& WPS_REFRESH_PEAK_METER
)
1072 /* the peakmeter should be alone on its line */
1073 update_line
= false;
1075 int h
= font_get(skin_viewport
->vp
.font
)->height
;
1076 int peak_meter_y
= line_count
* h
;
1078 /* The user might decide to have the peak meter in the last
1079 line so that it is only displayed if no status bar is
1080 visible. If so we neither want do draw nor enable the
1082 if (peak_meter_y
+ h
<= skin_viewport
->vp
.y
+skin_viewport
->vp
.height
) {
1083 /* found a line with a peak meter -> remember that we must
1086 peak_meter_enabled
= true;
1087 peak_meter_screen(gwps
->display
, 0, peak_meter_y
,
1088 MIN(h
, skin_viewport
->vp
.y
+skin_viewport
->vp
.height
- peak_meter_y
));
1092 peak_meter_enabled
= false;
1096 #else /* HAVE_LCD_CHARCELL */
1099 if (flags
& vp_refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
)
1101 if (data
->full_line_progressbar
)
1102 draw_player_fullbar(gwps
, linebuf
, sizeof(linebuf
));
1104 draw_player_progress(gwps
);
1108 if (update_line
&& !hidden_vp
&&
1109 /* conditionals clear the line which means if the %Vd is put into the default
1110 viewport there will be a blank line.
1111 To get around this we dont allow any actual drawing to happen in the
1112 deault vp if other vp's are defined */
1113 ((skin_viewport
->label
!= VP_DEFAULT_LABEL
&& viewport_list
->next
) ||
1114 !viewport_list
->next
))
1116 if (flags
& WPS_REFRESH_SCROLL
)
1118 /* if the line is a scrolling one we don't want to update
1119 too often, so that it has the time to scroll */
1120 if ((vp_refresh_mode
& WPS_REFRESH_SCROLL
) || new_subline_refresh
)
1121 write_line(display
, &align
, line_count
, true);
1124 write_line(display
, &align
, line_count
, false);
1127 #ifdef HAVE_LCD_BITMAP
1129 if (vp_refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
)
1131 if (skin_viewport
->pb
)
1133 draw_progressbar(gwps
, skin_viewport
);
1136 /* Now display any images in this viewport */
1138 wps_display_images(gwps
, &skin_viewport
->vp
);
1142 #ifdef HAVE_LCD_BITMAP
1143 data
->peak_meter_enabled
= enable_pm
;
1146 if (refresh_mode
& WPS_REFRESH_STATUSBAR
)
1148 viewportmanager_set_statusbar(gwps
->sync_data
->statusbars
);
1150 /* Restore the default viewport */
1151 display
->set_viewport(NULL
);