Make some global function/variables local (by making them static)
[maemo-rb.git] / apps / gui / skin_engine / skin_display.c
blob6b6db680230494aadc1c75eaae0b869bebe6d3a4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
22 #include "config.h"
23 #include <stdio.h>
24 #include "string-extra.h"
25 #include "misc.h"
26 #include "font.h"
27 #include "system.h"
28 #include "rbunicode.h"
29 #include "sound.h"
30 #include "powermgmt.h"
31 #ifdef DEBUG
32 #include "debug.h"
33 #endif
34 #include "action.h"
35 #include "abrepeat.h"
36 #include "lang.h"
37 #include "language.h"
38 #include "statusbar.h"
39 #include "settings.h"
40 #include "scrollbar.h"
41 #include "screen_access.h"
42 #include "playlist.h"
43 #include "audio.h"
44 #include "tagcache.h"
46 #ifdef HAVE_LCD_BITMAP
47 #include "peakmeter.h"
48 /* Image stuff */
49 #include "bmp.h"
50 #ifdef HAVE_ALBUMART
51 #include "albumart.h"
52 #endif
53 #endif
55 #include "cuesheet.h"
56 #if CONFIG_CODEC == SWCODEC
57 #include "playback.h"
58 #endif
59 #include "backdrop.h"
60 #include "viewport.h"
61 #if CONFIG_TUNER
62 #include "radio.h"
63 #include "tuner.h"
64 #endif
65 #include "root_menu.h"
68 #include "wps_internals.h"
69 #include "skin_engine.h"
70 #include "statusbar-skinned.h"
71 #include "skin_display.h"
73 void skin_render(struct gui_wps *gwps, unsigned refresh_mode);
75 /* update a skinned screen, update_type is WPS_REFRESH_* values.
76 * Usually it should only be WPS_REFRESH_NON_STATIC
77 * A full update will be done if required (state.do_full_update == true)
79 void skin_update(struct gui_wps *gwps, unsigned int update_type)
81 /* This maybe shouldnt be here,
82 * This is also safe for skined screen which dont use the id3 */
83 struct mp3entry *id3 = gwps->state->id3;
84 bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false);
85 gwps->sync_data->do_full_update |= cuesheet_update;
87 skin_render(gwps, gwps->sync_data->do_full_update ?
88 SKIN_REFRESH_ALL : update_type);
91 #ifdef HAVE_LCD_BITMAP
93 void skin_statusbar_changed(struct gui_wps *skin)
95 if (!skin)
96 return;
97 struct wps_data *data = skin->data;
98 const struct screen *display = skin->display;
99 const int screen = display->screen_type;
101 struct viewport *vp = &find_viewport(VP_DEFAULT_LABEL, data)->vp;
102 viewport_set_defaults(vp, screen);
104 if (data->wps_sb_tag)
105 { /* fix up the default viewport */
106 if (data->show_sb_on_wps)
108 if (statusbar_position(screen) != STATUSBAR_OFF)
109 return; /* vp is fixed already */
111 vp->y = STATUSBAR_HEIGHT;
112 vp->height = display->lcdheight - STATUSBAR_HEIGHT;
114 else
116 if (statusbar_position(screen) == STATUSBAR_OFF)
117 return; /* vp is fixed already */
118 vp->y = vp->x = 0;
119 vp->height = display->lcdheight;
120 vp->width = display->lcdwidth;
125 void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
127 struct screen *display = gwps->display;
128 struct viewport *vp = pb->vp;
129 struct wps_state *state = gwps->state;
130 struct mp3entry *id3 = state->id3;
131 int y = pb->y, height = pb->height;
132 unsigned long length, elapsed;
134 if (height < 0)
135 height = font_get(vp->font)->height;
137 if (y < 0)
139 int line_height = font_get(vp->font)->height;
140 /* center the pb in the line, but only if the line is higher than the pb */
141 int center = (line_height-height)/2;
142 /* if Y was not set calculate by font height,Y is -line_number-1 */
143 y = line*line_height + (0 > center ? 0 : center);
146 if (pb->type == SKIN_TOKEN_VOLUMEBAR)
148 int minvol = sound_min(SOUND_VOLUME);
149 int maxvol = sound_max(SOUND_VOLUME);
150 length = maxvol-minvol;
151 elapsed = global_settings.volume-minvol;
153 else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR)
155 length = 100;
156 elapsed = battery_level();
158 #if CONFIG_TUNER
159 else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
161 int min = fm_region_data[global_settings.fm_region].freq_min;
162 elapsed = radio_current_frequency() - min;
163 length = fm_region_data[global_settings.fm_region].freq_max - min;
165 #endif
166 else if (id3 && id3->length)
168 length = id3->length;
169 elapsed = id3->elapsed + state->ff_rewind_count;
171 else
173 length = 1;
174 elapsed = 0;
177 if (pb->have_bitmap_pb)
178 gui_bitmap_scrollbar_draw(display, &pb->bm,
179 pb->x, y, pb->width, pb->bm.height,
180 length, 0, elapsed, HORIZONTAL);
181 else
182 gui_scrollbar_draw(display, pb->x, y, pb->width, height,
183 length, 0, elapsed, HORIZONTAL);
185 if (pb->type == SKIN_TOKEN_PROGRESSBAR)
187 if (id3 && id3->length)
189 #ifdef AB_REPEAT_ENABLE
190 if (ab_repeat_mode_enabled())
191 ab_draw_markers(display, id3->length,
192 pb->x, y, pb->width, height);
193 #endif
195 if (id3->cuesheet)
196 cue_draw_markers(display, id3->cuesheet, id3->length,
197 pb->x, y+1, pb->width, height-2);
199 #if 0 /* disable for now CONFIG_TUNER */
200 else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
202 presets_draw_markers(display, pb->x, y, pb->width, height);
204 #endif
208 void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer)
210 struct wps_state *state = gwps->state;
211 int lines = viewport_get_nb_lines(viewer->vp);
212 int line_height = font_get(viewer->vp->font)->height;
213 int cur_pos, max;
214 int start_item;
215 int i;
216 bool scroll = false;
217 struct wps_token *token;
218 int x, length, alignment = SKIN_TOKEN_ALIGN_LEFT;
220 struct mp3entry *pid3;
221 char buf[MAX_PATH*2], tempbuf[MAX_PATH];
222 const char *filename;
223 #if CONFIG_TUNER
224 if (current_screen() == GO_TO_FM)
226 cur_pos = radio_current_preset();
227 start_item = cur_pos + viewer->start_offset;
228 max = start_item+radio_preset_count();
230 else
231 #endif
233 cur_pos = playlist_get_display_index();
234 max = playlist_amount()+1;
235 start_item = MAX(0, cur_pos + viewer->start_offset);
238 gwps->display->set_viewport(viewer->vp);
239 for(i=start_item; (i-start_item)<lines && i<max; i++)
241 int line;
242 #if CONFIG_TUNER
243 if (current_screen() == GO_TO_FM)
245 pid3 = NULL;
246 line = TRACK_HAS_INFO;
247 filename = "";
249 else
250 #endif
252 filename = playlist_peek(i-cur_pos);
253 if (i == cur_pos)
255 pid3 = state->id3;
257 else if (i == cur_pos+1)
259 pid3 = state->nid3;
261 #if CONFIG_CODEC == SWCODEC
262 else if (i>cur_pos)
264 #ifdef HAVE_TC_RAMCACHE
265 if (tagcache_fill_tags(&viewer->tempid3, filename))
267 pid3 = &viewer->tempid3;
269 else
270 #endif
271 if (!audio_peek_track(&pid3, i-cur_pos))
272 pid3 = NULL;
274 #endif
275 else
277 pid3 = NULL;
279 line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO;
281 unsigned int line_len = 0;
282 if (viewer->lines[line]->children_count == 0)
283 return;
284 struct skin_element *element = viewer->lines[line]->children[0];
285 buf[0] = '\0';
286 while (element && line_len < sizeof(buf))
288 const char *out = NULL;
289 if (element->type == TEXT)
291 line_len = strlcat(buf, (char*)element->data, sizeof(buf));
292 element = element->next;
293 continue;
295 if (element->type != TAG)
297 element = element->next;
298 continue;
300 if (element->tag->type == SKIN_TOKEN_SUBLINE_SCROLL)
301 scroll = true;
302 token = (struct wps_token*)element->data;
303 out = get_id3_token(token, pid3, tempbuf, sizeof(tempbuf), -1, NULL);
304 #if CONFIG_TUNER
305 if (!out)
306 out = get_radio_token(token, i-cur_pos,
307 tempbuf, sizeof(tempbuf), -1, NULL);
308 #endif
309 if (out)
311 line_len = strlcat(buf, out, sizeof(buf));
312 element = element->next;
313 continue;
316 switch (token->type)
318 case SKIN_TOKEN_ALIGN_CENTER:
319 case SKIN_TOKEN_ALIGN_LEFT:
320 case SKIN_TOKEN_ALIGN_LEFT_RTL:
321 case SKIN_TOKEN_ALIGN_RIGHT:
322 case SKIN_TOKEN_ALIGN_RIGHT_RTL:
323 alignment = token->type;
324 tempbuf[0] = '\0';
325 break;
326 case SKIN_TOKEN_PLAYLIST_POSITION:
327 snprintf(tempbuf, sizeof(tempbuf), "%d", i);
328 break;
329 case SKIN_TOKEN_FILE_NAME:
330 get_dir(tempbuf, sizeof(tempbuf), filename, 0);
331 break;
332 case SKIN_TOKEN_FILE_PATH:
333 snprintf(tempbuf, sizeof(tempbuf), "%s", filename);
334 break;
335 default:
336 tempbuf[0] = '\0';
337 break;
339 if (tempbuf[0])
341 line_len = strlcat(buf, tempbuf, sizeof(buf));
343 element = element->next;
346 int vpwidth = viewer->vp->width;
347 length = gwps->display->getstringsize(buf, NULL, NULL);
348 if (scroll && length >= vpwidth)
350 gwps->display->puts_scroll(0, (i-start_item), buf );
352 else
354 if (length >= vpwidth)
355 x = 0;
356 else
358 switch (alignment)
360 case SKIN_TOKEN_ALIGN_CENTER:
361 x = (vpwidth-length)/2;
362 break;
363 case SKIN_TOKEN_ALIGN_LEFT_RTL:
364 if (lang_is_rtl() && VP_IS_RTL(viewer->vp))
366 x = vpwidth - length;
367 break;
369 case SKIN_TOKEN_ALIGN_LEFT:
370 x = 0;
371 break;
372 case SKIN_TOKEN_ALIGN_RIGHT_RTL:
373 if (lang_is_rtl() && VP_IS_RTL(viewer->vp))
375 x = 0;
376 break;
378 case SKIN_TOKEN_ALIGN_RIGHT:
379 x = vpwidth - length;
380 break;
381 default:
382 x = 0;
383 break;
386 gwps->display->putsxy(x, (i-start_item)*line_height, buf );
392 /* clears the area where the image was shown */
393 void clear_image_pos(struct gui_wps *gwps, struct gui_img *img)
395 if(!gwps)
396 return;
397 gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
398 gwps->display->fillrect(img->x, img->y, img->bm.width, img->subimage_height);
399 gwps->display->set_drawmode(DRMODE_SOLID);
402 void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage)
404 struct screen *display = gwps->display;
405 if(img->always_display)
406 display->set_drawmode(DRMODE_FG);
407 else
408 display->set_drawmode(DRMODE_SOLID);
410 #if LCD_DEPTH > 1
411 if(img->bm.format == FORMAT_MONO) {
412 #endif
413 display->mono_bitmap_part(img->bm.data,
414 0, img->subimage_height * subimage,
415 img->bm.width, img->x,
416 img->y, img->bm.width,
417 img->subimage_height);
418 #if LCD_DEPTH > 1
419 } else {
420 display->transparent_bitmap_part((fb_data *)img->bm.data,
421 0, img->subimage_height * subimage,
422 STRIDE(display->screen_type,
423 img->bm.width, img->bm.height),
424 img->x, img->y, img->bm.width,
425 img->subimage_height);
427 #endif
431 void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
433 if(!gwps || !gwps->data || !gwps->display)
434 return;
436 struct wps_data *data = gwps->data;
437 struct screen *display = gwps->display;
438 struct skin_token_list *list = data->images;
440 while (list)
442 struct gui_img *img = (struct gui_img*)list->token->value.data;
443 if (img->loaded)
445 if (img->display >= 0)
447 wps_draw_image(gwps, img, img->display);
449 else if (img->always_display && img->vp == vp)
451 wps_draw_image(gwps, img, 0);
454 list = list->next;
456 #ifdef HAVE_ALBUMART
457 /* now draw the AA */
458 if (data->albumart && data->albumart->vp == vp
459 && data->albumart->draw_handle >= 0)
461 draw_album_art(gwps, data->albumart->draw_handle, false);
462 data->albumart->draw_handle = -1;
464 #endif
466 display->set_drawmode(DRMODE_SOLID);
469 #else /* HAVE_LCD_CHARCELL */
471 bool draw_player_progress(struct gui_wps *gwps)
473 struct wps_state *state = gwps->state;
474 struct screen *display = gwps->display;
475 unsigned char progress_pattern[7];
476 int pos = 0;
477 int i;
479 int elapsed, length;
480 if (LIKELY(state->id3))
482 elapsed = state->id3->elapsed;
483 length = state->id3->length;
485 else
487 elapsed = 0;
488 length = 0;
491 if (length)
492 pos = 36 * (elapsed + state->ff_rewind_count) / length;
494 for (i = 0; i < 7; i++, pos -= 5)
496 if (pos <= 0)
497 progress_pattern[i] = 0x1fu;
498 else if (pos >= 5)
499 progress_pattern[i] = 0x00u;
500 else
501 progress_pattern[i] = 0x1fu >> pos;
504 display->define_pattern(gwps->data->wps_progress_pat[0], progress_pattern);
505 return true;
508 void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
510 static const unsigned char numbers[10][4] = {
511 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
512 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
513 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
514 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
515 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
516 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
517 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
518 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
519 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
520 {0x0e, 0x0e, 0x02, 0x0e}, /* 9 */
523 struct wps_state *state = gwps->state;
524 struct screen *display = gwps->display;
525 struct wps_data *data = gwps->data;
526 unsigned char progress_pattern[7];
527 char timestr[10];
528 int time;
529 int time_idx = 0;
530 int pos = 0;
531 int pat_idx = 1;
532 int digit, i, j;
533 bool softchar;
535 int elapsed, length;
536 if (LIKELY(state->id3))
538 elapsed = state->id3->elapsed;
539 length = state->id3->length;
541 else
543 elapsed = 0;
544 length = 0;
547 if (buf_size < 34) /* worst case: 11x UTF-8 char + \0 */
548 return;
550 time = elapsed + state->ff_rewind_count;
551 if (length)
552 pos = 55 * time / length;
554 memset(timestr, 0, sizeof(timestr));
555 format_time(timestr, sizeof(timestr)-2, time);
556 timestr[strlen(timestr)] = ':'; /* always safe */
558 for (i = 0; i < 11; i++, pos -= 5)
560 softchar = false;
561 memset(progress_pattern, 0, sizeof(progress_pattern));
563 if ((digit = timestr[time_idx]))
565 softchar = true;
566 digit -= '0';
568 if (timestr[time_idx + 1] == ':') /* ones, left aligned */
570 memcpy(progress_pattern, numbers[digit], 4);
571 time_idx += 2;
573 else /* tens, shifted right */
575 for (j = 0; j < 4; j++)
576 progress_pattern[j] = numbers[digit][j] >> 1;
578 if (time_idx > 0) /* not the first group, add colon in front */
580 progress_pattern[1] |= 0x10u;
581 progress_pattern[3] |= 0x10u;
583 time_idx++;
586 if (pos >= 5)
587 progress_pattern[5] = progress_pattern[6] = 0x1fu;
590 if (pos > 0 && pos < 5)
592 softchar = true;
593 progress_pattern[5] = progress_pattern[6] = (~0x1fu >> pos) & 0x1fu;
596 if (softchar && pat_idx < 8)
598 display->define_pattern(data->wps_progress_pat[pat_idx],
599 progress_pattern);
600 buf = utf8encode(data->wps_progress_pat[pat_idx], buf);
601 pat_idx++;
603 else if (pos <= 0)
604 buf = utf8encode(' ', buf);
605 else
606 buf = utf8encode(0xe115, buf); /* 2/7 _ */
608 *buf = '\0';
611 #endif /* HAVE_LCD_CHARCELL */
613 /* Evaluate the conditional that is at *token_index and return whether a skip
614 has ocurred. *token_index is updated with the new position.
616 int evaluate_conditional(struct gui_wps *gwps, struct conditional *conditional, int num_options)
618 if (!gwps)
619 return false;
621 char result[128];
622 const char *value;
624 /* treat ?xx<true> constructs as if they had 2 options.
625 * (i.e ?xx<true|false>) */
626 if (num_options < 2)
627 num_options = 2;
629 int intval = num_options;
630 /* get_token_value needs to know the number of options in the enum */
631 value = get_token_value(gwps, conditional->token,
632 result, sizeof(result), &intval);
634 /* intval is now the number of the enum option we want to read,
635 starting from 1. If intval is -1, we check if value is empty. */
636 if (intval == -1)
637 intval = (value && *value) ? 1 : num_options;
638 else if (intval > num_options || intval < 1)
639 intval = num_options;
641 conditional->last_value = intval -1;
642 return intval -1;
646 /* Display a line appropriately according to its alignment format.
647 format_align contains the text, separated between left, center and right.
648 line is the index of the line on the screen.
649 scroll indicates whether the line is a scrolling one or not.
651 void write_line(struct screen *display,
652 struct align_pos *format_align,
653 int line,
654 bool scroll)
656 int left_width = 0, left_xpos;
657 int center_width = 0, center_xpos;
658 int right_width = 0, right_xpos;
659 int ypos;
660 int space_width;
661 int string_height;
662 int scroll_width;
664 /* calculate different string sizes and positions */
665 display->getstringsize((unsigned char *)" ", &space_width, &string_height);
666 if (format_align->left != 0) {
667 display->getstringsize((unsigned char *)format_align->left,
668 &left_width, &string_height);
671 if (format_align->right != 0) {
672 display->getstringsize((unsigned char *)format_align->right,
673 &right_width, &string_height);
676 if (format_align->center != 0) {
677 display->getstringsize((unsigned char *)format_align->center,
678 &center_width, &string_height);
681 left_xpos = 0;
682 right_xpos = (display->getwidth() - right_width);
683 center_xpos = (display->getwidth() + left_xpos - center_width) / 2;
685 scroll_width = display->getwidth() - left_xpos;
687 /* Checks for overlapping strings.
688 If needed the overlapping strings will be merged, separated by a
689 space */
691 /* CASE 1: left and centered string overlap */
692 /* there is a left string, need to merge left and center */
693 if ((left_width != 0 && center_width != 0) &&
694 (left_xpos + left_width + space_width > center_xpos)) {
695 /* replace the former separator '\0' of left and
696 center string with a space */
697 *(--format_align->center) = ' ';
698 /* calculate the new width and position of the merged string */
699 left_width = left_width + space_width + center_width;
700 /* there is no centered string anymore */
701 center_width = 0;
703 /* there is no left string, move center to left */
704 if ((left_width == 0 && center_width != 0) &&
705 (left_xpos + left_width > center_xpos)) {
706 /* move the center string to the left string */
707 format_align->left = format_align->center;
708 /* calculate the new width and position of the string */
709 left_width = center_width;
710 /* there is no centered string anymore */
711 center_width = 0;
714 /* CASE 2: centered and right string overlap */
715 /* there is a right string, need to merge center and right */
716 if ((center_width != 0 && right_width != 0) &&
717 (center_xpos + center_width + space_width > right_xpos)) {
718 /* replace the former separator '\0' of center and
719 right string with a space */
720 *(--format_align->right) = ' ';
721 /* move the center string to the right after merge */
722 format_align->right = format_align->center;
723 /* calculate the new width and position of the merged string */
724 right_width = center_width + space_width + right_width;
725 right_xpos = (display->getwidth() - right_width);
726 /* there is no centered string anymore */
727 center_width = 0;
729 /* there is no right string, move center to right */
730 if ((center_width != 0 && right_width == 0) &&
731 (center_xpos + center_width > right_xpos)) {
732 /* move the center string to the right string */
733 format_align->right = format_align->center;
734 /* calculate the new width and position of the string */
735 right_width = center_width;
736 right_xpos = (display->getwidth() - right_width);
737 /* there is no centered string anymore */
738 center_width = 0;
741 /* CASE 3: left and right overlap
742 There is no center string anymore, either there never
743 was one or it has been merged in case 1 or 2 */
744 /* there is a left string, need to merge left and right */
745 if ((left_width != 0 && center_width == 0 && right_width != 0) &&
746 (left_xpos + left_width + space_width > right_xpos)) {
747 /* replace the former separator '\0' of left and
748 right string with a space */
749 *(--format_align->right) = ' ';
750 /* calculate the new width and position of the string */
751 left_width = left_width + space_width + right_width;
752 /* there is no right string anymore */
753 right_width = 0;
755 /* there is no left string, move right to left */
756 if ((left_width == 0 && center_width == 0 && right_width != 0) &&
757 (left_width > right_xpos)) {
758 /* move the right string to the left string */
759 format_align->left = format_align->right;
760 /* calculate the new width and position of the string */
761 left_width = right_width;
762 /* there is no right string anymore */
763 right_width = 0;
766 ypos = (line * string_height);
769 if (scroll && ((left_width > scroll_width) ||
770 (center_width > scroll_width) ||
771 (right_width > scroll_width)))
773 display->puts_scroll(0, line,
774 (unsigned char *)format_align->left);
776 else
778 #ifdef HAVE_LCD_BITMAP
779 /* clear the line first */
780 display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
781 display->fillrect(left_xpos, ypos, display->getwidth(), string_height);
782 display->set_drawmode(DRMODE_SOLID);
783 #endif
785 /* Nasty hack: we output an empty scrolling string,
786 which will reset the scroller for that line */
787 display->puts_scroll(0, line, (unsigned char *)"");
789 /* print aligned strings */
790 if (left_width != 0)
792 display->putsxy(left_xpos, ypos,
793 (unsigned char *)format_align->left);
795 if (center_width != 0)
797 display->putsxy(center_xpos, ypos,
798 (unsigned char *)format_align->center);
800 if (right_width != 0)
802 display->putsxy(right_xpos, ypos,
803 (unsigned char *)format_align->right);
808 #ifdef HAVE_LCD_BITMAP
809 void draw_peakmeters(struct gui_wps *gwps, int line_number,
810 struct viewport *viewport)
812 struct wps_data *data = gwps->data;
813 if (!data->peak_meter_enabled)
815 peak_meter_enable(false);
817 else
819 int h = font_get(viewport->font)->height;
820 int peak_meter_y = line_number * h;
822 /* The user might decide to have the peak meter in the last
823 line so that it is only displayed if no status bar is
824 visible. If so we neither want do draw nor enable the
825 peak meter. */
826 if (peak_meter_y + h <= viewport->y+viewport->height) {
827 peak_meter_enable(true);
828 peak_meter_screen(gwps->display, 0, peak_meter_y,
829 MIN(h, viewport->y+viewport->height - peak_meter_y));
834 bool skin_has_sbs(enum screen_type screen, struct wps_data *data)
836 (void)screen;
837 (void)data;
838 bool draw = false;
839 #ifdef HAVE_LCD_BITMAP
840 if (data->wps_sb_tag)
841 draw = data->show_sb_on_wps;
842 else if (statusbar_position(screen) != STATUSBAR_OFF)
843 draw = true;
844 #endif
845 return draw;
847 #endif
849 /* do the button loop as often as required for the peak meters to update
850 * with a good refresh rate.
851 * gwps is really gwps[NB_SCREENS]! don't wrap this if FOR_NB_SCREENS()
853 int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout)
855 (void)gwps; /* silence charcell warning */
856 int button = ACTION_NONE;
857 #ifdef HAVE_LCD_BITMAP
858 int i;
859 /* when the peak meter is enabled we want to have a
860 few extra updates to make it look smooth. On the
861 other hand we don't want to waste energy if it
862 isn't displayed */
863 bool pm=false;
864 FOR_NB_SCREENS(i)
866 if(gwps[i].data->peak_meter_enabled)
867 pm = true;
870 if (pm) {
871 long next_refresh = current_tick;
872 long next_big_refresh = current_tick + timeout;
873 button = BUTTON_NONE;
874 while (TIME_BEFORE(current_tick, next_big_refresh)) {
875 button = get_action(context,TIMEOUT_NOBLOCK);
876 if (button != ACTION_NONE) {
877 break;
879 peak_meter_peek();
880 sleep(0); /* Sleep until end of current tick. */
882 if (TIME_AFTER(current_tick, next_refresh)) {
883 FOR_NB_SCREENS(i)
885 if(gwps[i].data->peak_meter_enabled)
886 skin_update(&gwps[i], SKIN_REFRESH_PEAK_METER);
887 next_refresh += HZ / PEAK_METER_FPS;
894 /* The peak meter is disabled
895 -> no additional screen updates needed */
896 else
897 #endif
899 button = get_action(context, timeout);
901 return button;