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"
68 static bool skin_redraw(struct gui_wps
*gwps
, unsigned refresh_mode
);
71 /* initial setup of wps_data */
72 void skin_data_init(struct wps_data
*wps_data
)
74 #ifdef HAVE_LCD_BITMAP
75 wps_data
->wps_sb_tag
= false;
76 wps_data
->show_sb_on_wps
= false;
77 wps_data
->peak_meter_enabled
= false;
78 wps_data
->images
= NULL
;
79 wps_data
->progressbars
= NULL
;
81 wps_data
->albumart
= NULL
;
84 #else /* HAVE_LCD_CHARCELLS */
86 for (i
= 0; i
< 8; i
++)
88 wps_data
->wps_progress_pat
[i
] = 0;
90 wps_data
->full_line_progressbar
= false;
92 wps_data
->button_time_volume
= 0;
93 wps_data
->wps_loaded
= false;
96 /* TODO: maybe move this whole function into wps.c instead ? */
97 bool gui_wps_display(struct gui_wps
*gwps
)
99 struct screen
*display
= gwps
->display
;
101 /* Update the values in the first (default) viewport - in case the user
102 has modified the statusbar or colour settings */
104 if (display
->depth
> 1)
106 struct viewport
*vp
= &find_viewport(VP_DEFAULT_LABEL
, gwps
->data
)->vp
;
107 vp
->fg_pattern
= display
->get_foreground();
108 vp
->bg_pattern
= display
->get_background();
111 display
->clear_display();
112 display
->backdrop_show(BACKDROP_SKIN_WPS
);
113 return skin_redraw(gwps
, WPS_REFRESH_ALL
);
116 /* update a skinned screen, update_type is WPS_REFRESH_* values.
117 * Usually it should only be WPS_REFRESH_NON_STATIC
118 * A full update will be done if required (state.do_full_update == true)
120 bool skin_update(struct gui_wps
*gwps
, unsigned int update_type
)
123 /* This maybe shouldnt be here, but while the skin is only used to
124 * display the music screen this is better than whereever we are being
125 * called from. This is also safe for skined screen which dont use the id3 */
126 struct mp3entry
*id3
= gwps
->state
->id3
;
127 bool cuesheet_update
= (id3
!= NULL
? cuesheet_subtrack_changed(id3
) : false);
128 gwps
->state
->do_full_update
= cuesheet_update
|| gwps
->state
->do_full_update
;
130 retval
= skin_redraw(gwps
, gwps
->state
->do_full_update
?
131 WPS_REFRESH_ALL
: update_type
);
135 #ifdef HAVE_LCD_BITMAP
137 void skin_statusbar_changed(struct gui_wps
*skin
)
141 struct wps_data
*data
= skin
->data
;
142 const struct screen
*display
= skin
->display
;
144 struct viewport
*vp
= &find_viewport(VP_DEFAULT_LABEL
, data
)->vp
;
145 viewport_set_fullscreen(vp
, display
->screen_type
);
147 if (data
->wps_sb_tag
)
148 { /* fix up the default viewport */
149 if (data
->show_sb_on_wps
)
152 statusbar_position(display
->screen_type
) != STATUSBAR_BOTTOM
;
154 vp
->y
= bar_at_top
?STATUSBAR_HEIGHT
:0;
155 vp
->height
= display
->lcdheight
- STATUSBAR_HEIGHT
;
160 vp
->height
= display
->lcdheight
;
167 static void draw_progressbar(struct gui_wps
*gwps
,
168 struct skin_viewport
*wps_vp
)
170 struct screen
*display
= gwps
->display
;
171 struct wps_state
*state
= gwps
->state
;
172 struct progressbar
*pb
= wps_vp
->pb
;
177 int line_height
= font_get(wps_vp
->vp
.font
)->height
;
178 /* center the pb in the line, but only if the line is higher than the pb */
179 int center
= (line_height
-pb
->height
)/2;
180 /* if Y was not set calculate by font height,Y is -line_number-1 */
181 y
= (-y
-1)*line_height
+ (0 > center
? 0 : center
);
184 if (pb
->have_bitmap_pb
)
185 gui_bitmap_scrollbar_draw(display
, pb
->bm
,
186 pb
->x
, y
, pb
->width
, pb
->bm
.height
,
187 state
->id3
->length
? state
->id3
->length
: 1, 0,
188 state
->id3
->length
? state
->id3
->elapsed
189 + state
->ff_rewind_count
: 0,
192 gui_scrollbar_draw(display
, pb
->x
, y
, pb
->width
, pb
->height
,
193 state
->id3
->length
? state
->id3
->length
: 1, 0,
194 state
->id3
->length
? state
->id3
->elapsed
195 + state
->ff_rewind_count
: 0,
197 #ifdef AB_REPEAT_ENABLE
198 if ( ab_repeat_mode_enabled() && state
->id3
->length
!= 0 )
199 ab_draw_markers(display
, state
->id3
->length
,
200 pb
->x
, pb
->x
+ pb
->width
, y
, pb
->height
);
203 if (state
->id3
->cuesheet
)
204 cue_draw_markers(display
, state
->id3
->cuesheet
, state
->id3
->length
,
205 pb
->x
, pb
->x
+ pb
->width
, y
+1, pb
->height
-2);
208 /* clears the area where the image was shown */
209 static void clear_image_pos(struct gui_wps
*gwps
, struct gui_img
*img
)
213 gwps
->display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
214 gwps
->display
->fillrect(img
->x
, img
->y
, img
->bm
.width
, img
->subimage_height
);
215 gwps
->display
->set_drawmode(DRMODE_SOLID
);
218 static void wps_draw_image(struct gui_wps
*gwps
, struct gui_img
*img
, int subimage
)
220 struct screen
*display
= gwps
->display
;
221 if(img
->always_display
)
222 display
->set_drawmode(DRMODE_FG
);
224 display
->set_drawmode(DRMODE_SOLID
);
227 if(img
->bm
.format
== FORMAT_MONO
) {
229 display
->mono_bitmap_part(img
->bm
.data
,
230 0, img
->subimage_height
* subimage
,
231 img
->bm
.width
, img
->x
,
232 img
->y
, img
->bm
.width
,
233 img
->subimage_height
);
236 display
->transparent_bitmap_part((fb_data
*)img
->bm
.data
,
237 0, img
->subimage_height
* subimage
,
238 STRIDE(display
->screen_type
,
239 img
->bm
.width
, img
->bm
.height
),
240 img
->x
, img
->y
, img
->bm
.width
,
241 img
->subimage_height
);
246 static void wps_display_images(struct gui_wps
*gwps
, struct viewport
* vp
)
248 if(!gwps
|| !gwps
->data
|| !gwps
->display
)
251 struct wps_data
*data
= gwps
->data
;
252 struct screen
*display
= gwps
->display
;
253 struct skin_token_list
*list
= data
->images
;
257 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
260 if (img
->display
>= 0)
262 wps_draw_image(gwps
, img
, img
->display
);
264 else if (img
->always_display
&& img
->vp
== vp
)
266 wps_draw_image(gwps
, img
, 0);
272 /* now draw the AA */
273 if (data
->albumart
&& data
->albumart
->vp
== vp
&& data
->albumart
->draw
)
275 draw_album_art(gwps
, audio_current_aa_hid(), false);
279 display
->set_drawmode(DRMODE_SOLID
);
282 #else /* HAVE_LCD_CHARCELL */
284 static bool draw_player_progress(struct gui_wps
*gwps
)
286 struct wps_state
*state
= gwps
->state
;
287 struct screen
*display
= gwps
->display
;
288 unsigned char progress_pattern
[7];
295 if (state
->id3
->length
)
296 pos
= 36 * (state
->id3
->elapsed
+ state
->ff_rewind_count
)
297 / state
->id3
->length
;
299 for (i
= 0; i
< 7; i
++, pos
-= 5)
302 progress_pattern
[i
] = 0x1fu
;
304 progress_pattern
[i
] = 0x00u
;
306 progress_pattern
[i
] = 0x1fu
>> pos
;
309 display
->define_pattern(gwps
->data
->wps_progress_pat
[0], progress_pattern
);
313 static void draw_player_fullbar(struct gui_wps
*gwps
, char* buf
, int buf_size
)
315 static const unsigned char numbers
[10][4] = {
316 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
317 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
318 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
319 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
320 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
321 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
322 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
323 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
324 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
325 {0x0e, 0x0e, 0x02, 0x0e}, /* 9 */
328 struct wps_state
*state
= gwps
->state
;
329 struct screen
*display
= gwps
->display
;
330 struct wps_data
*data
= gwps
->data
;
331 unsigned char progress_pattern
[7];
340 if (!state
->id3
|| buf_size
< 34) /* worst case: 11x UTF-8 char + \0 */
343 time
= state
->id3
->elapsed
+ state
->ff_rewind_count
;
344 if (state
->id3
->length
)
345 pos
= 55 * time
/ state
->id3
->length
;
347 memset(timestr
, 0, sizeof(timestr
));
348 format_time(timestr
, sizeof(timestr
)-2, time
);
349 timestr
[strlen(timestr
)] = ':'; /* always safe */
351 for (i
= 0; i
< 11; i
++, pos
-= 5)
354 memset(progress_pattern
, 0, sizeof(progress_pattern
));
356 if ((digit
= timestr
[time_idx
]))
361 if (timestr
[time_idx
+ 1] == ':') /* ones, left aligned */
363 memcpy(progress_pattern
, numbers
[digit
], 4);
366 else /* tens, shifted right */
368 for (j
= 0; j
< 4; j
++)
369 progress_pattern
[j
] = numbers
[digit
][j
] >> 1;
371 if (time_idx
> 0) /* not the first group, add colon in front */
373 progress_pattern
[1] |= 0x10u
;
374 progress_pattern
[3] |= 0x10u
;
380 progress_pattern
[5] = progress_pattern
[6] = 0x1fu
;
383 if (pos
> 0 && pos
< 5)
386 progress_pattern
[5] = progress_pattern
[6] = (~0x1fu
>> pos
) & 0x1fu
;
389 if (softchar
&& pat_idx
< 8)
391 display
->define_pattern(data
->wps_progress_pat
[pat_idx
],
393 buf
= utf8encode(data
->wps_progress_pat
[pat_idx
], buf
);
397 buf
= utf8encode(' ', buf
);
399 buf
= utf8encode(0xe115, buf
); /* 2/7 _ */
404 #endif /* HAVE_LCD_CHARCELL */
406 /* Return the index to the end token for the conditional token at index.
407 The conditional token can be either a start token or a separator
410 static int find_conditional_end(struct wps_data
*data
, int index
)
413 while (data
->tokens
[ret
].type
!= WPS_TOKEN_CONDITIONAL_END
)
414 ret
= data
->tokens
[ret
].value
.i
;
416 /* ret now is the index to the end token for the conditional. */
420 /* Evaluate the conditional that is at *token_index and return whether a skip
421 has ocurred. *token_index is updated with the new position.
423 static bool evaluate_conditional(struct gui_wps
*gwps
, int *token_index
)
428 struct wps_data
*data
= gwps
->data
;
431 int cond_index
= *token_index
;
434 unsigned char num_options
= data
->tokens
[cond_index
].value
.i
& 0xFF;
435 unsigned char prev_val
= (data
->tokens
[cond_index
].value
.i
& 0xFF00) >> 8;
437 /* treat ?xx<true> constructs as if they had 2 options. */
441 int intval
= num_options
;
442 /* get_token_value needs to know the number of options in the enum */
443 value
= get_token_value(gwps
, &data
->tokens
[cond_index
+ 1],
444 result
, sizeof(result
), &intval
);
446 /* intval is now the number of the enum option we want to read,
447 starting from 1. If intval is -1, we check if value is empty. */
449 intval
= (value
&& *value
) ? 1 : num_options
;
450 else if (intval
> num_options
|| intval
< 1)
451 intval
= num_options
;
453 data
->tokens
[cond_index
].value
.i
= (intval
<< 8) + num_options
;
455 /* skip to the appropriate enum case */
456 int next
= cond_index
+ 2;
457 for (i
= 1; i
< intval
; i
++)
459 next
= data
->tokens
[next
].value
.i
;
463 if (prev_val
== intval
)
465 /* Same conditional case as previously. Return without clearing the
470 cond_end
= find_conditional_end(data
, cond_index
+ 2);
471 for (i
= cond_index
+ 3; i
< cond_end
; i
++)
473 #ifdef HAVE_LCD_BITMAP
474 /* clear all pictures in the conditional and nested ones */
475 if (data
->tokens
[i
].type
== WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
)
476 clear_image_pos(gwps
, find_image(data
->tokens
[i
].value
.i
&0xFF, gwps
->data
));
482 #ifdef HAVE_LCD_BITMAP
483 struct gui_img
* find_image(char label
, struct wps_data
*data
)
485 struct skin_token_list
*list
= data
->images
;
488 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
489 if (img
->label
== label
)
497 struct skin_viewport
* find_viewport(char label
, struct wps_data
*data
)
499 struct skin_token_list
*list
= data
->viewports
;
502 struct skin_viewport
*vp
= (struct skin_viewport
*)list
->token
->value
.data
;
503 if (vp
->label
== label
)
511 /* Read a (sub)line to the given alignment format buffer.
512 linebuf is the buffer where the data is actually stored.
513 align is the alignment format that'll be used to display the text.
514 The return value indicates whether the line needs to be updated.
516 static bool get_line(struct gui_wps
*gwps
,
517 struct skin_subline
*subline
,
518 struct align_pos
*align
,
522 struct wps_data
*data
= gwps
->data
;
525 char *buf
= linebuf
; /* will always point to the writing position */
526 char *linebuf_end
= linebuf
+ linebuf_size
- 1;
530 /* alignment-related variables */
532 char* cur_align_start
;
533 cur_align_start
= buf
;
534 cur_align
= WPS_ALIGN_LEFT
;
536 align
->center
= NULL
;
538 /* Process all tokens of the desired subline */
539 for (i
= subline
->first_token_idx
;
540 i
<= subline
->last_token_idx
; i
++)
542 switch(data
->tokens
[i
].type
)
544 case WPS_TOKEN_CONDITIONAL
:
545 /* place ourselves in the right conditional case */
546 update
|= evaluate_conditional(gwps
, &i
);
549 case WPS_TOKEN_CONDITIONAL_OPTION
:
550 /* we've finished in the curent conditional case,
551 skip to the end of the conditional structure */
552 i
= find_conditional_end(data
, i
);
555 #ifdef HAVE_LCD_BITMAP
556 case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
:
558 char n
= data
->tokens
[i
].value
.i
& 0xFF;
559 int subimage
= data
->tokens
[i
].value
.i
>> 8;
560 struct gui_img
*img
= find_image(n
, data
);
562 if (img
&& img
->loaded
)
563 img
->display
= subimage
;
568 case WPS_TOKEN_ALIGN_LEFT
:
569 case WPS_TOKEN_ALIGN_CENTER
:
570 case WPS_TOKEN_ALIGN_RIGHT
:
571 /* remember where the current aligned text started */
575 align
->left
= cur_align_start
;
578 case WPS_ALIGN_CENTER
:
579 align
->center
= cur_align_start
;
582 case WPS_ALIGN_RIGHT
:
583 align
->right
= cur_align_start
;
586 /* start a new alignment */
587 switch (data
->tokens
[i
].type
)
589 case WPS_TOKEN_ALIGN_LEFT
:
590 cur_align
= WPS_ALIGN_LEFT
;
592 case WPS_TOKEN_ALIGN_CENTER
:
593 cur_align
= WPS_ALIGN_CENTER
;
595 case WPS_TOKEN_ALIGN_RIGHT
:
596 cur_align
= WPS_ALIGN_RIGHT
;
602 cur_align_start
= buf
;
604 case WPS_VIEWPORT_ENABLE
:
606 char label
= data
->tokens
[i
].value
.i
;
607 char temp
= VP_DRAW_HIDEABLE
;
608 /* viewports are allowed to share id's so find and enable
610 struct skin_token_list
*list
= data
->viewports
;
613 struct skin_viewport
*vp
=
614 (struct skin_viewport
*)list
->token
->value
.data
;
615 if (vp
->label
== label
)
617 if (vp
->hidden_flags
&VP_DRAW_WASHIDDEN
)
618 temp
|= VP_DRAW_WASHIDDEN
;
619 vp
->hidden_flags
= temp
;
626 case WPS_TOKEN_ALBUMART_DISPLAY
:
629 data
->albumart
->draw
= true;
635 /* get the value of the tag and copy it to the buffer */
636 const char *value
= get_token_value(gwps
, &data
->tokens
[i
],
637 temp_buf
, sizeof(temp_buf
), NULL
);
641 while (*value
&& (buf
< linebuf_end
))
649 /* close the current alignment */
653 align
->left
= cur_align_start
;
656 case WPS_ALIGN_CENTER
:
657 align
->center
= cur_align_start
;
660 case WPS_ALIGN_RIGHT
:
661 align
->right
= cur_align_start
;
667 static void get_subline_timeout(struct gui_wps
*gwps
, struct skin_subline
*subline
)
669 struct wps_data
*data
= gwps
->data
;
671 subline
->time_mult
= DEFAULT_SUBLINE_TIME_MULTIPLIER
;
673 for (i
= subline
->first_token_idx
;
674 i
<= subline
->last_token_idx
; i
++)
676 switch(data
->tokens
[i
].type
)
678 case WPS_TOKEN_CONDITIONAL
:
679 /* place ourselves in the right conditional case */
680 evaluate_conditional(gwps
, &i
);
683 case WPS_TOKEN_CONDITIONAL_OPTION
:
684 /* we've finished in the curent conditional case,
685 skip to the end of the conditional structure */
686 i
= find_conditional_end(data
, i
);
689 case WPS_TOKEN_SUBLINE_TIMEOUT
:
690 subline
->time_mult
= data
->tokens
[i
].value
.i
;
699 /* Calculates which subline should be displayed for the specified line
700 Returns true iff the subline must be refreshed */
701 static bool update_curr_subline(struct gui_wps
*gwps
, struct skin_line
*line
)
703 /* shortcut this whole thing if we need to reset the line completly */
704 if (line
->curr_subline
== NULL
)
706 line
->subline_expire_time
= current_tick
;
707 line
->curr_subline
= &line
->sublines
;
708 if (!line
->curr_subline
->next
)
710 line
->subline_expire_time
+= 100*HZ
;
714 get_subline_timeout(gwps
, line
->curr_subline
);
715 line
->subline_expire_time
+= TIMEOUT_UNIT
*line
->curr_subline
->time_mult
;
719 /* if time to advance to next sub-line */
720 if (TIME_AFTER(current_tick
, line
->subline_expire_time
- 1))
722 /* if there is only one subline, there is no need to search for a new one */
723 if (&line
->sublines
== line
->curr_subline
&&
724 line
->curr_subline
->next
== NULL
)
726 line
->subline_expire_time
+= 100 * HZ
;
729 if (line
->curr_subline
->next
)
730 line
->curr_subline
= line
->curr_subline
->next
;
732 line
->curr_subline
= &line
->sublines
;
733 get_subline_timeout(gwps
, line
->curr_subline
);
734 line
->subline_expire_time
+= TIMEOUT_UNIT
*line
->curr_subline
->time_mult
;
740 /* Display a line appropriately according to its alignment format.
741 format_align contains the text, separated between left, center and right.
742 line is the index of the line on the screen.
743 scroll indicates whether the line is a scrolling one or not.
745 static void write_line(struct screen
*display
,
746 struct align_pos
*format_align
,
750 int left_width
= 0, left_xpos
;
751 int center_width
= 0, center_xpos
;
752 int right_width
= 0, right_xpos
;
758 /* calculate different string sizes and positions */
759 display
->getstringsize((unsigned char *)" ", &space_width
, &string_height
);
760 if (format_align
->left
!= 0) {
761 display
->getstringsize((unsigned char *)format_align
->left
,
762 &left_width
, &string_height
);
765 if (format_align
->right
!= 0) {
766 display
->getstringsize((unsigned char *)format_align
->right
,
767 &right_width
, &string_height
);
770 if (format_align
->center
!= 0) {
771 display
->getstringsize((unsigned char *)format_align
->center
,
772 ¢er_width
, &string_height
);
776 right_xpos
= (display
->getwidth() - right_width
);
777 center_xpos
= (display
->getwidth() + left_xpos
- center_width
) / 2;
779 scroll_width
= display
->getwidth() - left_xpos
;
781 /* Checks for overlapping strings.
782 If needed the overlapping strings will be merged, separated by a
785 /* CASE 1: left and centered string overlap */
786 /* there is a left string, need to merge left and center */
787 if ((left_width
!= 0 && center_width
!= 0) &&
788 (left_xpos
+ left_width
+ space_width
> center_xpos
)) {
789 /* replace the former separator '\0' of left and
790 center string with a space */
791 *(--format_align
->center
) = ' ';
792 /* calculate the new width and position of the merged string */
793 left_width
= left_width
+ space_width
+ center_width
;
794 /* there is no centered string anymore */
797 /* there is no left string, move center to left */
798 if ((left_width
== 0 && center_width
!= 0) &&
799 (left_xpos
+ left_width
> center_xpos
)) {
800 /* move the center string to the left string */
801 format_align
->left
= format_align
->center
;
802 /* calculate the new width and position of the string */
803 left_width
= center_width
;
804 /* there is no centered string anymore */
808 /* CASE 2: centered and right string overlap */
809 /* there is a right string, need to merge center and right */
810 if ((center_width
!= 0 && right_width
!= 0) &&
811 (center_xpos
+ center_width
+ space_width
> right_xpos
)) {
812 /* replace the former separator '\0' of center and
813 right string with a space */
814 *(--format_align
->right
) = ' ';
815 /* move the center string to the right after merge */
816 format_align
->right
= format_align
->center
;
817 /* calculate the new width and position of the merged string */
818 right_width
= center_width
+ space_width
+ right_width
;
819 right_xpos
= (display
->getwidth() - right_width
);
820 /* there is no centered string anymore */
823 /* there is no right string, move center to right */
824 if ((center_width
!= 0 && right_width
== 0) &&
825 (center_xpos
+ center_width
> right_xpos
)) {
826 /* move the center string to the right string */
827 format_align
->right
= format_align
->center
;
828 /* calculate the new width and position of the string */
829 right_width
= center_width
;
830 right_xpos
= (display
->getwidth() - right_width
);
831 /* there is no centered string anymore */
835 /* CASE 3: left and right overlap
836 There is no center string anymore, either there never
837 was one or it has been merged in case 1 or 2 */
838 /* there is a left string, need to merge left and right */
839 if ((left_width
!= 0 && center_width
== 0 && right_width
!= 0) &&
840 (left_xpos
+ left_width
+ space_width
> right_xpos
)) {
841 /* replace the former separator '\0' of left and
842 right string with a space */
843 *(--format_align
->right
) = ' ';
844 /* calculate the new width and position of the string */
845 left_width
= left_width
+ space_width
+ right_width
;
846 /* there is no right string anymore */
849 /* there is no left string, move right to left */
850 if ((left_width
== 0 && center_width
== 0 && right_width
!= 0) &&
851 (left_width
> right_xpos
)) {
852 /* move the right string to the left string */
853 format_align
->left
= format_align
->right
;
854 /* calculate the new width and position of the string */
855 left_width
= right_width
;
856 /* there is no right string anymore */
860 ypos
= (line
* string_height
);
863 if (scroll
&& ((left_width
> scroll_width
) ||
864 (center_width
> scroll_width
) ||
865 (right_width
> scroll_width
)))
867 display
->puts_scroll(0, line
,
868 (unsigned char *)format_align
->left
);
872 #ifdef HAVE_LCD_BITMAP
873 /* clear the line first */
874 display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
875 display
->fillrect(left_xpos
, ypos
, display
->getwidth(), string_height
);
876 display
->set_drawmode(DRMODE_SOLID
);
879 /* Nasty hack: we output an empty scrolling string,
880 which will reset the scroller for that line */
881 display
->puts_scroll(0, line
, (unsigned char *)"");
883 /* print aligned strings */
886 display
->putsxy(left_xpos
, ypos
,
887 (unsigned char *)format_align
->left
);
889 if (center_width
!= 0)
891 display
->putsxy(center_xpos
, ypos
,
892 (unsigned char *)format_align
->center
);
894 if (right_width
!= 0)
896 display
->putsxy(right_xpos
, ypos
,
897 (unsigned char *)format_align
->right
);
902 static bool skin_redraw(struct gui_wps
*gwps
, unsigned refresh_mode
)
904 struct wps_data
*data
= gwps
->data
;
905 struct screen
*display
= gwps
->display
;
906 struct wps_state
*state
= gwps
->state
;
908 if (!data
|| !state
|| !display
)
911 struct mp3entry
*id3
= state
->id3
;
917 char linebuf
[MAX_PATH
];
919 struct align_pos align
;
925 struct skin_token_list
*viewport_list
;
927 bool update_line
, new_subline_refresh
;
929 #ifdef HAVE_LCD_BITMAP
931 /* to find out wether the peak meter is enabled we
932 assume it wasn't until we find a line that contains
933 the peak meter. We can't use peak_meter_enabled itself
934 because that would mean to turn off the meter thread
935 temporarily. (That shouldn't matter unless yield
936 or sleep is called but who knows...)
938 bool enable_pm
= false;
942 /* reset to first subline if refresh all flag is set */
943 if (refresh_mode
== WPS_REFRESH_ALL
)
945 struct skin_line
*line
;
947 display
->set_viewport(&find_viewport(VP_DEFAULT_LABEL
, data
)->vp
);
948 display
->clear_viewport();
950 for (viewport_list
= data
->viewports
;
951 viewport_list
; viewport_list
= viewport_list
->next
)
953 struct skin_viewport
*skin_viewport
=
954 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
955 for(line
= skin_viewport
->lines
; line
; line
= line
->next
)
957 line
->curr_subline
= NULL
;
962 #ifdef HAVE_LCD_CHARCELLS
964 for (i
= 0; i
< 8; i
++)
966 if (data
->wps_progress_pat
[i
] == 0)
967 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
971 /* disable any viewports which are conditionally displayed */
972 for (viewport_list
= data
->viewports
;
973 viewport_list
; viewport_list
= viewport_list
->next
)
975 struct skin_viewport
*skin_viewport
=
976 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
977 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDEABLE
)
979 if (skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
)
980 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
982 skin_viewport
->hidden_flags
|= VP_DRAW_HIDDEN
;
985 int viewport_count
= 0;
986 for (viewport_list
= data
->viewports
;
987 viewport_list
; viewport_list
= viewport_list
->next
, viewport_count
++)
989 struct skin_viewport
*skin_viewport
=
990 (struct skin_viewport
*)viewport_list
->token
->value
.data
;
991 unsigned vp_refresh_mode
= refresh_mode
;
992 display
->set_viewport(&skin_viewport
->vp
);
994 #ifdef HAVE_LCD_BITMAP
995 /* Set images to not to be displayed */
996 struct skin_token_list
*imglist
= data
->images
;
999 struct gui_img
*img
= (struct gui_img
*)imglist
->token
->value
.data
;
1001 imglist
= imglist
->next
;
1004 /* dont redraw the viewport if its disabled */
1005 if ((skin_viewport
->hidden_flags
&VP_DRAW_HIDDEN
))
1007 if (!(skin_viewport
->hidden_flags
&VP_DRAW_WASHIDDEN
))
1008 display
->scroll_stop(&skin_viewport
->vp
);
1009 skin_viewport
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
1012 else if (((skin_viewport
->hidden_flags
&
1013 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
1014 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
1016 vp_refresh_mode
= WPS_REFRESH_ALL
;
1017 skin_viewport
->hidden_flags
= VP_DRAW_HIDEABLE
;
1019 if (vp_refresh_mode
== WPS_REFRESH_ALL
)
1021 display
->clear_viewport();
1024 /* loop over the lines for this viewport */
1025 struct skin_line
*line
;
1028 for (line
= skin_viewport
->lines
; line
; line
= line
->next
, line_count
++)
1030 struct skin_subline
*subline
;
1031 memset(linebuf
, 0, sizeof(linebuf
));
1032 update_line
= false;
1034 /* get current subline for the line */
1035 new_subline_refresh
= update_curr_subline(gwps
, line
);
1036 subline
= line
->curr_subline
;
1037 flags
= line
->curr_subline
->line_type
;
1039 if (vp_refresh_mode
== WPS_REFRESH_ALL
|| (flags
& vp_refresh_mode
)
1040 || new_subline_refresh
)
1042 /* get_line tells us if we need to update the line */
1043 update_line
= get_line(gwps
, subline
,
1044 &align
, linebuf
, sizeof(linebuf
));
1046 #ifdef HAVE_LCD_BITMAP
1048 if (flags
& vp_refresh_mode
& WPS_REFRESH_PEAK_METER
)
1050 /* the peakmeter should be alone on its line */
1051 update_line
= false;
1053 int h
= font_get(skin_viewport
->vp
.font
)->height
;
1054 int peak_meter_y
= line_count
* h
;
1056 /* The user might decide to have the peak meter in the last
1057 line so that it is only displayed if no status bar is
1058 visible. If so we neither want do draw nor enable the
1060 if (peak_meter_y
+ h
<= skin_viewport
->vp
.y
+skin_viewport
->vp
.height
) {
1061 /* found a line with a peak meter -> remember that we must
1064 peak_meter_enabled
= true;
1065 peak_meter_screen(gwps
->display
, 0, peak_meter_y
,
1066 MIN(h
, skin_viewport
->vp
.y
+skin_viewport
->vp
.height
- peak_meter_y
));
1070 peak_meter_enabled
= false;
1074 #else /* HAVE_LCD_CHARCELL */
1077 if (flags
& vp_refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
)
1079 if (data
->full_line_progressbar
)
1080 draw_player_fullbar(gwps
, linebuf
, sizeof(linebuf
));
1082 draw_player_progress(gwps
);
1087 /* conditionals clear the line which means if the %Vd is put into the default
1088 viewport there will be a blank line.
1089 To get around this we dont allow any actual drawing to happen in the
1090 deault vp if other vp's are defined */
1091 ((skin_viewport
->label
!= VP_DEFAULT_LABEL
&& viewport_list
->next
) ||
1092 !viewport_list
->next
))
1094 if (flags
& WPS_REFRESH_SCROLL
)
1096 /* if the line is a scrolling one we don't want to update
1097 too often, so that it has the time to scroll */
1098 if ((vp_refresh_mode
& WPS_REFRESH_SCROLL
) || new_subline_refresh
)
1099 write_line(display
, &align
, line_count
, true);
1102 write_line(display
, &align
, line_count
, false);
1106 #ifdef HAVE_LCD_BITMAP
1108 if (vp_refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
)
1110 if (skin_viewport
->pb
)
1112 draw_progressbar(gwps
, skin_viewport
);
1115 /* Now display any images in this viewport */
1116 wps_display_images(gwps
, &skin_viewport
->vp
);
1120 #ifdef HAVE_LCD_BITMAP
1121 data
->peak_meter_enabled
= enable_pm
;
1124 if (refresh_mode
& WPS_REFRESH_STATUSBAR
)
1126 viewportmanager_set_statusbar(*gwps
->statusbars
);
1128 /* Restore the default viewport */
1129 display
->set_viewport(NULL
);