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 gui_wps_redraw(struct gui_wps
*gwps
, unsigned refresh_mode
);
71 bool gui_wps_display(struct gui_wps
*gwps
)
73 struct screen
*display
= gwps
->display
;
75 /* Update the values in the first (default) viewport - in case the user
76 has modified the statusbar or colour settings */
78 if (display
->depth
> 1)
80 gwps
->data
->viewports
[0].vp
.fg_pattern
= display
->get_foreground();
81 gwps
->data
->viewports
[0].vp
.bg_pattern
= display
->get_background();
84 display
->clear_display();
85 display
->backdrop_show(BACKDROP_SKIN_WPS
);
86 return gui_wps_redraw(gwps
, WPS_REFRESH_ALL
);
89 /* update a skinned screen, update_type is WPS_REFRESH_* values.
90 * Usually it should only be WPS_REFRESH_NON_STATIC
91 * A full update will be done if required (state.do_full_update == true)
93 bool skin_update(struct gui_wps
*gwps
, unsigned int update_type
)
96 /* This maybe shouldnt be here, but while the skin is only used to
97 * display the music screen this is better than whereever we are being
98 * called from. This is also safe for skined screen which dont use the id3 */
99 struct mp3entry
*id3
= gwps
->state
->id3
;
100 bool cuesheet_update
= (id3
!= NULL
? cuesheet_subtrack_changed(id3
) : false);
101 gwps
->state
->do_full_update
= cuesheet_update
|| gwps
->state
->do_full_update
;
103 retval
= gui_wps_redraw(gwps
, gwps
->state
->do_full_update
?
104 WPS_REFRESH_ALL
: update_type
);
109 #ifdef HAVE_LCD_BITMAP
111 static void draw_progressbar(struct gui_wps
*gwps
,
112 struct wps_viewport
*wps_vp
)
114 struct screen
*display
= gwps
->display
;
115 struct wps_state
*state
= gwps
->state
;
116 struct progressbar
*pb
= wps_vp
->pb
;
121 int line_height
= font_get(wps_vp
->vp
.font
)->height
;
122 /* center the pb in the line, but only if the line is higher than the pb */
123 int center
= (line_height
-pb
->height
)/2;
124 /* if Y was not set calculate by font height,Y is -line_number-1 */
125 y
= (-y
-1)*line_height
+ (0 > center
? 0 : center
);
128 if (pb
->have_bitmap_pb
)
129 gui_bitmap_scrollbar_draw(display
, pb
->bm
,
130 pb
->x
, y
, pb
->width
, pb
->bm
.height
,
131 state
->id3
->length
? state
->id3
->length
: 1, 0,
132 state
->id3
->length
? state
->id3
->elapsed
133 + state
->ff_rewind_count
: 0,
136 gui_scrollbar_draw(display
, pb
->x
, y
, pb
->width
, pb
->height
,
137 state
->id3
->length
? state
->id3
->length
: 1, 0,
138 state
->id3
->length
? state
->id3
->elapsed
139 + state
->ff_rewind_count
: 0,
141 #ifdef AB_REPEAT_ENABLE
142 if ( ab_repeat_mode_enabled() && state
->id3
->length
!= 0 )
143 ab_draw_markers(display
, state
->id3
->length
,
144 pb
->x
, pb
->x
+ pb
->width
, y
, pb
->height
);
147 if (state
->id3
->cuesheet
)
148 cue_draw_markers(display
, state
->id3
->cuesheet
, state
->id3
->length
,
149 pb
->x
, pb
->x
+ pb
->width
, y
+1, pb
->height
-2);
152 /* clears the area where the image was shown */
153 static void clear_image_pos(struct gui_wps
*gwps
, int n
)
157 struct wps_data
*data
= gwps
->data
;
158 gwps
->display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
159 gwps
->display
->fillrect(data
->img
[n
].x
, data
->img
[n
].y
,
160 data
->img
[n
].bm
.width
, data
->img
[n
].subimage_height
);
161 gwps
->display
->set_drawmode(DRMODE_SOLID
);
164 static void wps_draw_image(struct gui_wps
*gwps
, int n
, int subimage
)
166 struct screen
*display
= gwps
->display
;
167 struct wps_data
*data
= gwps
->data
;
168 if(data
->img
[n
].always_display
)
169 display
->set_drawmode(DRMODE_FG
);
171 display
->set_drawmode(DRMODE_SOLID
);
174 if(data
->img
[n
].bm
.format
== FORMAT_MONO
) {
176 display
->mono_bitmap_part(data
->img
[n
].bm
.data
,
177 0, data
->img
[n
].subimage_height
* subimage
,
178 data
->img
[n
].bm
.width
, data
->img
[n
].x
,
179 data
->img
[n
].y
, data
->img
[n
].bm
.width
,
180 data
->img
[n
].subimage_height
);
183 display
->transparent_bitmap_part((fb_data
*)data
->img
[n
].bm
.data
,
184 0, data
->img
[n
].subimage_height
* subimage
,
185 data
->img
[n
].bm
.width
, data
->img
[n
].x
,
186 data
->img
[n
].y
, data
->img
[n
].bm
.width
,
187 data
->img
[n
].subimage_height
);
192 static void wps_display_images(struct gui_wps
*gwps
, struct viewport
* vp
)
194 if(!gwps
|| !gwps
->data
|| !gwps
->display
)
198 struct wps_data
*data
= gwps
->data
;
199 struct screen
*display
= gwps
->display
;
201 for (n
= 0; n
< MAX_IMAGES
; n
++)
203 if (data
->img
[n
].loaded
)
205 if (data
->img
[n
].display
>= 0)
207 wps_draw_image(gwps
, n
, data
->img
[n
].display
);
208 } else if (data
->img
[n
].always_display
&& data
->img
[n
].vp
== vp
)
210 wps_draw_image(gwps
, n
, 0);
214 display
->set_drawmode(DRMODE_SOLID
);
217 #else /* HAVE_LCD_CHARCELL */
219 static bool draw_player_progress(struct gui_wps
*gwps
)
221 struct wps_state
*state
= gwps
->state
;
222 struct screen
*display
= gwps
->display
;
223 unsigned char progress_pattern
[7];
230 if (state
->id3
->length
)
231 pos
= 36 * (state
->id3
->elapsed
+ state
->ff_rewind_count
)
232 / state
->id3
->length
;
234 for (i
= 0; i
< 7; i
++, pos
-= 5)
237 progress_pattern
[i
] = 0x1fu
;
239 progress_pattern
[i
] = 0x00u
;
241 progress_pattern
[i
] = 0x1fu
>> pos
;
244 display
->define_pattern(gwps
->data
->wps_progress_pat
[0], progress_pattern
);
248 static void draw_player_fullbar(struct gui_wps
*gwps
, char* buf
, int buf_size
)
250 static const unsigned char numbers
[10][4] = {
251 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
252 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
253 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
254 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
255 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
256 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
257 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
258 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
259 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
260 {0x0e, 0x0e, 0x02, 0x0e}, /* 9 */
263 struct wps_state
*state
= gwps
->state
;
264 struct screen
*display
= gwps
->display
;
265 struct wps_data
*data
= gwps
->data
;
266 unsigned char progress_pattern
[7];
275 if (!state
->id3
|| buf_size
< 34) /* worst case: 11x UTF-8 char + \0 */
278 time
= state
->id3
->elapsed
+ state
->ff_rewind_count
;
279 if (state
->id3
->length
)
280 pos
= 55 * time
/ state
->id3
->length
;
282 memset(timestr
, 0, sizeof(timestr
));
283 format_time(timestr
, sizeof(timestr
)-2, time
);
284 timestr
[strlen(timestr
)] = ':'; /* always safe */
286 for (i
= 0; i
< 11; i
++, pos
-= 5)
289 memset(progress_pattern
, 0, sizeof(progress_pattern
));
291 if ((digit
= timestr
[time_idx
]))
296 if (timestr
[time_idx
+ 1] == ':') /* ones, left aligned */
298 memcpy(progress_pattern
, numbers
[digit
], 4);
301 else /* tens, shifted right */
303 for (j
= 0; j
< 4; j
++)
304 progress_pattern
[j
] = numbers
[digit
][j
] >> 1;
306 if (time_idx
> 0) /* not the first group, add colon in front */
308 progress_pattern
[1] |= 0x10u
;
309 progress_pattern
[3] |= 0x10u
;
315 progress_pattern
[5] = progress_pattern
[6] = 0x1fu
;
318 if (pos
> 0 && pos
< 5)
321 progress_pattern
[5] = progress_pattern
[6] = (~0x1fu
>> pos
) & 0x1fu
;
324 if (softchar
&& pat_idx
< 8)
326 display
->define_pattern(data
->wps_progress_pat
[pat_idx
],
328 buf
= utf8encode(data
->wps_progress_pat
[pat_idx
], buf
);
332 buf
= utf8encode(' ', buf
);
334 buf
= utf8encode(0xe115, buf
); /* 2/7 _ */
339 #endif /* HAVE_LCD_CHARCELL */
341 /* Return the index to the end token for the conditional token at index.
342 The conditional token can be either a start token or a separator
345 static int find_conditional_end(struct wps_data
*data
, int index
)
348 while (data
->tokens
[ret
].type
!= WPS_TOKEN_CONDITIONAL_END
)
349 ret
= data
->tokens
[ret
].value
.i
;
351 /* ret now is the index to the end token for the conditional. */
355 /* Evaluate the conditional that is at *token_index and return whether a skip
356 has ocurred. *token_index is updated with the new position.
358 static bool evaluate_conditional(struct gui_wps
*gwps
, int *token_index
)
363 struct wps_data
*data
= gwps
->data
;
366 int cond_index
= *token_index
;
369 unsigned char num_options
= data
->tokens
[cond_index
].value
.i
& 0xFF;
370 unsigned char prev_val
= (data
->tokens
[cond_index
].value
.i
& 0xFF00) >> 8;
372 /* treat ?xx<true> constructs as if they had 2 options. */
376 int intval
= num_options
;
377 /* get_token_value needs to know the number of options in the enum */
378 value
= get_token_value(gwps
, &data
->tokens
[cond_index
+ 1],
379 result
, sizeof(result
), &intval
);
381 /* intval is now the number of the enum option we want to read,
382 starting from 1. If intval is -1, we check if value is empty. */
384 intval
= (value
&& *value
) ? 1 : num_options
;
385 else if (intval
> num_options
|| intval
< 1)
386 intval
= num_options
;
388 data
->tokens
[cond_index
].value
.i
= (intval
<< 8) + num_options
;
390 /* skip to the appropriate enum case */
391 int next
= cond_index
+ 2;
392 for (i
= 1; i
< intval
; i
++)
394 next
= data
->tokens
[next
].value
.i
;
398 if (prev_val
== intval
)
400 /* Same conditional case as previously. Return without clearing the
405 cond_end
= find_conditional_end(data
, cond_index
+ 2);
406 for (i
= cond_index
+ 3; i
< cond_end
; i
++)
408 #ifdef HAVE_LCD_BITMAP
409 /* clear all pictures in the conditional and nested ones */
410 if (data
->tokens
[i
].type
== WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
)
411 clear_image_pos(gwps
, data
->tokens
[i
].value
.i
& 0xFF);
414 if (data
->tokens
[i
].type
== WPS_TOKEN_ALBUMART_DISPLAY
)
415 draw_album_art(gwps
, audio_current_aa_hid(), true);
422 /* Read a (sub)line to the given alignment format buffer.
423 linebuf is the buffer where the data is actually stored.
424 align is the alignment format that'll be used to display the text.
425 The return value indicates whether the line needs to be updated.
427 static bool get_line(struct gui_wps
*gwps
,
428 int line
, int subline
,
429 struct align_pos
*align
,
433 struct wps_data
*data
= gwps
->data
;
436 char *buf
= linebuf
; /* will always point to the writing position */
437 char *linebuf_end
= linebuf
+ linebuf_size
- 1;
438 int i
, last_token_idx
;
441 /* alignment-related variables */
443 char* cur_align_start
;
444 cur_align_start
= buf
;
445 cur_align
= WPS_ALIGN_LEFT
;
447 align
->center
= NULL
;
450 /* Process all tokens of the desired subline */
451 last_token_idx
= wps_last_token_index(data
, line
, subline
);
452 for (i
= wps_first_token_index(data
, line
, subline
);
453 i
<= last_token_idx
; i
++)
455 switch(data
->tokens
[i
].type
)
457 case WPS_TOKEN_CONDITIONAL
:
458 /* place ourselves in the right conditional case */
459 update
|= evaluate_conditional(gwps
, &i
);
462 case WPS_TOKEN_CONDITIONAL_OPTION
:
463 /* we've finished in the curent conditional case,
464 skip to the end of the conditional structure */
465 i
= find_conditional_end(data
, i
);
468 #ifdef HAVE_LCD_BITMAP
469 case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
:
471 struct gui_img
*img
= data
->img
;
472 int n
= data
->tokens
[i
].value
.i
& 0xFF;
473 int subimage
= data
->tokens
[i
].value
.i
>> 8;
475 if (n
>= 0 && n
< MAX_IMAGES
&& img
[n
].loaded
)
476 img
[n
].display
= subimage
;
481 case WPS_TOKEN_ALIGN_LEFT
:
482 case WPS_TOKEN_ALIGN_CENTER
:
483 case WPS_TOKEN_ALIGN_RIGHT
:
484 /* remember where the current aligned text started */
488 align
->left
= cur_align_start
;
491 case WPS_ALIGN_CENTER
:
492 align
->center
= cur_align_start
;
495 case WPS_ALIGN_RIGHT
:
496 align
->right
= cur_align_start
;
499 /* start a new alignment */
500 switch (data
->tokens
[i
].type
)
502 case WPS_TOKEN_ALIGN_LEFT
:
503 cur_align
= WPS_ALIGN_LEFT
;
505 case WPS_TOKEN_ALIGN_CENTER
:
506 cur_align
= WPS_ALIGN_CENTER
;
508 case WPS_TOKEN_ALIGN_RIGHT
:
509 cur_align
= WPS_ALIGN_RIGHT
;
515 cur_align_start
= buf
;
517 case WPS_VIEWPORT_ENABLE
:
519 char label
= data
->tokens
[i
].value
.i
;
521 char temp
= VP_DRAW_HIDEABLE
;
522 for(j
=0;j
<data
->num_viewports
;j
++)
524 temp
= VP_DRAW_HIDEABLE
;
525 if ((data
->viewports
[j
].hidden_flags
&VP_DRAW_HIDEABLE
) &&
526 (data
->viewports
[j
].label
== label
))
528 if (data
->viewports
[j
].hidden_flags
&VP_DRAW_WASHIDDEN
)
529 temp
|= VP_DRAW_WASHIDDEN
;
530 data
->viewports
[j
].hidden_flags
= temp
;
537 /* get the value of the tag and copy it to the buffer */
538 const char *value
= get_token_value(gwps
, &data
->tokens
[i
],
539 temp_buf
, sizeof(temp_buf
), NULL
);
543 while (*value
&& (buf
< linebuf_end
))
551 /* close the current alignment */
555 align
->left
= cur_align_start
;
558 case WPS_ALIGN_CENTER
:
559 align
->center
= cur_align_start
;
562 case WPS_ALIGN_RIGHT
:
563 align
->right
= cur_align_start
;
570 static void get_subline_timeout(struct gui_wps
*gwps
, int line
, int subline
)
572 struct wps_data
*data
= gwps
->data
;
574 int subline_idx
= wps_subline_index(data
, line
, subline
);
575 int last_token_idx
= wps_last_token_index(data
, line
, subline
);
577 data
->sublines
[subline_idx
].time_mult
= DEFAULT_SUBLINE_TIME_MULTIPLIER
;
579 for (i
= wps_first_token_index(data
, line
, subline
);
580 i
<= last_token_idx
; i
++)
582 switch(data
->tokens
[i
].type
)
584 case WPS_TOKEN_CONDITIONAL
:
585 /* place ourselves in the right conditional case */
586 evaluate_conditional(gwps
, &i
);
589 case WPS_TOKEN_CONDITIONAL_OPTION
:
590 /* we've finished in the curent conditional case,
591 skip to the end of the conditional structure */
592 i
= find_conditional_end(data
, i
);
595 case WPS_TOKEN_SUBLINE_TIMEOUT
:
596 data
->sublines
[subline_idx
].time_mult
= data
->tokens
[i
].value
.i
;
605 /* Calculates which subline should be displayed for the specified line
606 Returns true iff the subline must be refreshed */
607 static bool update_curr_subline(struct gui_wps
*gwps
, int line
)
609 struct wps_data
*data
= gwps
->data
;
611 int search
, search_start
, num_sublines
;
613 bool new_subline_refresh
;
614 bool only_one_subline
;
616 num_sublines
= data
->lines
[line
].num_sublines
;
617 reset_subline
= (data
->lines
[line
].curr_subline
== SUBLINE_RESET
);
618 new_subline_refresh
= false;
619 only_one_subline
= false;
621 /* if time to advance to next sub-line */
622 if (TIME_AFTER(current_tick
, data
->lines
[line
].subline_expire_time
- 1) ||
625 /* search all sublines until the next subline with time > 0
626 is found or we get back to the subline we started with */
630 search_start
= data
->lines
[line
].curr_subline
;
632 for (search
= 0; search
< num_sublines
; search
++)
634 data
->lines
[line
].curr_subline
++;
636 /* wrap around if beyond last defined subline or WPS_MAX_SUBLINES */
637 if (data
->lines
[line
].curr_subline
== num_sublines
)
639 if (data
->lines
[line
].curr_subline
== 1)
640 only_one_subline
= true;
641 data
->lines
[line
].curr_subline
= 0;
644 /* if back where we started after search or
645 only one subline is defined on the line */
647 (data
->lines
[line
].curr_subline
== search_start
)) ||
650 /* no other subline with a time > 0 exists */
651 data
->lines
[line
].subline_expire_time
= (reset_subline
?
653 data
->lines
[line
].subline_expire_time
) + 100 * HZ
;
658 /* get initial time multiplier for this subline */
659 get_subline_timeout(gwps
, line
, data
->lines
[line
].curr_subline
);
661 int subline_idx
= wps_subline_index(data
, line
,
662 data
->lines
[line
].curr_subline
);
664 /* only use this subline if subline time > 0 */
665 if (data
->sublines
[subline_idx
].time_mult
> 0)
667 new_subline_refresh
= true;
668 data
->lines
[line
].subline_expire_time
= (reset_subline
?
669 current_tick
: data
->lines
[line
].subline_expire_time
) +
670 TIMEOUT_UNIT
*data
->sublines
[subline_idx
].time_mult
;
677 return new_subline_refresh
;
680 /* Display a line appropriately according to its alignment format.
681 format_align contains the text, separated between left, center and right.
682 line is the index of the line on the screen.
683 scroll indicates whether the line is a scrolling one or not.
685 static void write_line(struct screen
*display
,
686 struct align_pos
*format_align
,
690 int left_width
= 0, left_xpos
;
691 int center_width
= 0, center_xpos
;
692 int right_width
= 0, right_xpos
;
698 /* calculate different string sizes and positions */
699 display
->getstringsize((unsigned char *)" ", &space_width
, &string_height
);
700 if (format_align
->left
!= 0) {
701 display
->getstringsize((unsigned char *)format_align
->left
,
702 &left_width
, &string_height
);
705 if (format_align
->right
!= 0) {
706 display
->getstringsize((unsigned char *)format_align
->right
,
707 &right_width
, &string_height
);
710 if (format_align
->center
!= 0) {
711 display
->getstringsize((unsigned char *)format_align
->center
,
712 ¢er_width
, &string_height
);
716 right_xpos
= (display
->getwidth() - right_width
);
717 center_xpos
= (display
->getwidth() + left_xpos
- center_width
) / 2;
719 scroll_width
= display
->getwidth() - left_xpos
;
721 /* Checks for overlapping strings.
722 If needed the overlapping strings will be merged, separated by a
725 /* CASE 1: left and centered string overlap */
726 /* there is a left string, need to merge left and center */
727 if ((left_width
!= 0 && center_width
!= 0) &&
728 (left_xpos
+ left_width
+ space_width
> center_xpos
)) {
729 /* replace the former separator '\0' of left and
730 center string with a space */
731 *(--format_align
->center
) = ' ';
732 /* calculate the new width and position of the merged string */
733 left_width
= left_width
+ space_width
+ center_width
;
734 /* there is no centered string anymore */
737 /* there is no left string, move center to left */
738 if ((left_width
== 0 && center_width
!= 0) &&
739 (left_xpos
+ left_width
> center_xpos
)) {
740 /* move the center string to the left string */
741 format_align
->left
= format_align
->center
;
742 /* calculate the new width and position of the string */
743 left_width
= center_width
;
744 /* there is no centered string anymore */
748 /* CASE 2: centered and right string overlap */
749 /* there is a right string, need to merge center and right */
750 if ((center_width
!= 0 && right_width
!= 0) &&
751 (center_xpos
+ center_width
+ space_width
> right_xpos
)) {
752 /* replace the former separator '\0' of center and
753 right string with a space */
754 *(--format_align
->right
) = ' ';
755 /* move the center string to the right after merge */
756 format_align
->right
= format_align
->center
;
757 /* calculate the new width and position of the merged string */
758 right_width
= center_width
+ space_width
+ right_width
;
759 right_xpos
= (display
->getwidth() - right_width
);
760 /* there is no centered string anymore */
763 /* there is no right string, move center to right */
764 if ((center_width
!= 0 && right_width
== 0) &&
765 (center_xpos
+ center_width
> right_xpos
)) {
766 /* move the center string to the right string */
767 format_align
->right
= format_align
->center
;
768 /* calculate the new width and position of the string */
769 right_width
= center_width
;
770 right_xpos
= (display
->getwidth() - right_width
);
771 /* there is no centered string anymore */
775 /* CASE 3: left and right overlap
776 There is no center string anymore, either there never
777 was one or it has been merged in case 1 or 2 */
778 /* there is a left string, need to merge left and right */
779 if ((left_width
!= 0 && center_width
== 0 && right_width
!= 0) &&
780 (left_xpos
+ left_width
+ space_width
> right_xpos
)) {
781 /* replace the former separator '\0' of left and
782 right string with a space */
783 *(--format_align
->right
) = ' ';
784 /* calculate the new width and position of the string */
785 left_width
= left_width
+ space_width
+ right_width
;
786 /* there is no right string anymore */
789 /* there is no left string, move right to left */
790 if ((left_width
== 0 && center_width
== 0 && right_width
!= 0) &&
791 (left_width
> right_xpos
)) {
792 /* move the right string to the left string */
793 format_align
->left
= format_align
->right
;
794 /* calculate the new width and position of the string */
795 left_width
= right_width
;
796 /* there is no right string anymore */
800 ypos
= (line
* string_height
);
803 if (scroll
&& ((left_width
> scroll_width
) ||
804 (center_width
> scroll_width
) ||
805 (right_width
> scroll_width
)))
807 display
->puts_scroll(0, line
,
808 (unsigned char *)format_align
->left
);
812 #ifdef HAVE_LCD_BITMAP
813 /* clear the line first */
814 display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
815 display
->fillrect(left_xpos
, ypos
, display
->getwidth(), string_height
);
816 display
->set_drawmode(DRMODE_SOLID
);
819 /* Nasty hack: we output an empty scrolling string,
820 which will reset the scroller for that line */
821 display
->puts_scroll(0, line
, (unsigned char *)"");
823 /* print aligned strings */
826 display
->putsxy(left_xpos
, ypos
,
827 (unsigned char *)format_align
->left
);
829 if (center_width
!= 0)
831 display
->putsxy(center_xpos
, ypos
,
832 (unsigned char *)format_align
->center
);
834 if (right_width
!= 0)
836 display
->putsxy(right_xpos
, ypos
,
837 (unsigned char *)format_align
->right
);
842 static bool gui_wps_redraw(struct gui_wps
*gwps
, unsigned refresh_mode
)
844 struct wps_data
*data
= gwps
->data
;
845 struct screen
*display
= gwps
->display
;
846 struct wps_state
*state
= gwps
->state
;
848 if (!data
|| !state
|| !display
)
851 struct mp3entry
*id3
= state
->id3
;
856 int v
, line
, i
, subline_idx
;
858 char linebuf
[MAX_PATH
];
860 struct align_pos align
;
865 bool update_line
, new_subline_refresh
;
867 #ifdef HAVE_LCD_BITMAP
869 /* to find out wether the peak meter is enabled we
870 assume it wasn't until we find a line that contains
871 the peak meter. We can't use peak_meter_enabled itself
872 because that would mean to turn off the meter thread
873 temporarily. (That shouldn't matter unless yield
874 or sleep is called but who knows...)
876 bool enable_pm
= false;
880 /* reset to first subline if refresh all flag is set */
881 if (refresh_mode
== WPS_REFRESH_ALL
)
883 display
->set_viewport(&data
->viewports
[0].vp
);
884 display
->clear_viewport();
886 for (i
= 0; i
<= data
->num_lines
; i
++)
888 data
->lines
[i
].curr_subline
= SUBLINE_RESET
;
892 #ifdef HAVE_LCD_CHARCELLS
893 for (i
= 0; i
< 8; i
++)
895 if (data
->wps_progress_pat
[i
] == 0)
896 data
->wps_progress_pat
[i
] = display
->get_locked_pattern();
900 /* disable any viewports which are conditionally displayed */
901 for (v
= 0; v
< data
->num_viewports
; v
++)
903 if (data
->viewports
[v
].hidden_flags
&VP_DRAW_HIDEABLE
)
905 if (data
->viewports
[v
].hidden_flags
&VP_DRAW_HIDDEN
)
906 data
->viewports
[v
].hidden_flags
|= VP_DRAW_WASHIDDEN
;
908 data
->viewports
[v
].hidden_flags
|= VP_DRAW_HIDDEN
;
911 for (v
= 0; v
< data
->num_viewports
; v
++)
913 struct wps_viewport
*wps_vp
= &(data
->viewports
[v
]);
914 unsigned vp_refresh_mode
= refresh_mode
;
915 display
->set_viewport(&wps_vp
->vp
);
917 #ifdef HAVE_LCD_BITMAP
918 /* Set images to not to be displayed */
919 for (i
= 0; i
< MAX_IMAGES
; i
++)
921 data
->img
[i
].display
= -1;
924 /* dont redraw the viewport if its disabled */
925 if ((wps_vp
->hidden_flags
&VP_DRAW_HIDDEN
))
927 if (!(wps_vp
->hidden_flags
&VP_DRAW_WASHIDDEN
))
928 display
->scroll_stop(&wps_vp
->vp
);
929 wps_vp
->hidden_flags
|= VP_DRAW_WASHIDDEN
;
932 else if (((wps_vp
->hidden_flags
&
933 (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
))
934 == (VP_DRAW_WASHIDDEN
|VP_DRAW_HIDEABLE
)))
936 vp_refresh_mode
= WPS_REFRESH_ALL
;
937 wps_vp
->hidden_flags
= VP_DRAW_HIDEABLE
;
939 if (vp_refresh_mode
== WPS_REFRESH_ALL
)
941 display
->clear_viewport();
944 for (line
= wps_vp
->first_line
;
945 line
<= wps_vp
->last_line
; line
++)
947 memset(linebuf
, 0, sizeof(linebuf
));
950 /* get current subline for the line */
951 new_subline_refresh
= update_curr_subline(gwps
, line
);
953 subline_idx
= wps_subline_index(data
, line
,
954 data
->lines
[line
].curr_subline
);
955 flags
= data
->sublines
[subline_idx
].line_type
;
957 if (vp_refresh_mode
== WPS_REFRESH_ALL
|| (flags
& vp_refresh_mode
)
958 || new_subline_refresh
)
960 /* get_line tells us if we need to update the line */
961 update_line
= get_line(gwps
, line
, data
->lines
[line
].curr_subline
,
962 &align
, linebuf
, sizeof(linebuf
));
964 #ifdef HAVE_LCD_BITMAP
966 if (flags
& vp_refresh_mode
& WPS_REFRESH_PEAK_METER
)
968 /* the peakmeter should be alone on its line */
971 int h
= font_get(wps_vp
->vp
.font
)->height
;
972 int peak_meter_y
= (line
- wps_vp
->first_line
)* h
;
974 /* The user might decide to have the peak meter in the last
975 line so that it is only displayed if no status bar is
976 visible. If so we neither want do draw nor enable the
978 if (peak_meter_y
+ h
<= display
->getheight()) {
979 /* found a line with a peak meter -> remember that we must
982 peak_meter_enabled
= true;
983 peak_meter_screen(gwps
->display
, 0, peak_meter_y
,
984 MIN(h
, display
->getheight() - peak_meter_y
));
988 peak_meter_enabled
= false;
992 #else /* HAVE_LCD_CHARCELL */
995 if (flags
& vp_refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
)
997 if (data
->full_line_progressbar
)
998 draw_player_fullbar(gwps
, linebuf
, sizeof(linebuf
));
1000 draw_player_progress(gwps
);
1005 /* conditionals clear the line which means if the %Vd is put into the default
1006 viewport there will be a blank line.
1007 To get around this we dont allow any actual drawing to happen in the
1008 deault vp if other vp's are defined */
1009 ((data
->num_viewports
>1 && v
!=0) || data
->num_viewports
== 1))
1011 if (flags
& WPS_REFRESH_SCROLL
)
1013 /* if the line is a scrolling one we don't want to update
1014 too often, so that it has the time to scroll */
1015 if ((vp_refresh_mode
& WPS_REFRESH_SCROLL
) || new_subline_refresh
)
1016 write_line(display
, &align
, line
- wps_vp
->first_line
, true);
1019 write_line(display
, &align
, line
- wps_vp
->first_line
, false);
1023 #ifdef HAVE_LCD_BITMAP
1025 if (vp_refresh_mode
& WPS_REFRESH_PLAYER_PROGRESS
)
1029 draw_progressbar(gwps
, wps_vp
);
1032 /* Now display any images in this viewport */
1033 wps_display_images(gwps
, &wps_vp
->vp
);
1037 #ifdef HAVE_LCD_BITMAP
1038 data
->peak_meter_enabled
= enable_pm
;
1041 if (refresh_mode
& WPS_REFRESH_STATUSBAR
)
1043 gwps_draw_statusbars();
1045 /* Restore the default viewport */
1046 display
->set_viewport(NULL
);