A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) Robert E. Hak (2002), Linus Nielsen Feltzing (2002)
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include "config.h"
23#include "font.h"
24#include "kernel.h"
25#include "string.h" /* for memcmp oO*/
26#include "string-extra.h" /* for itoa */
27#include "sound.h"
28#include "settings.h"
29#include "viewport.h"
30#include "metadata.h"
31#include "icons.h"
32#include "powermgmt.h"
33#include "usb.h"
34#include "led.h"
35#include "screen_access.h"
36
37#include "status.h" /* needed for battery_state global var */
38#include "action.h" /* for keys_locked */
39#include "statusbar.h"
40#ifdef HAVE_RECORDING
41#include "audio.h"
42#include "recording.h"
43#include "pcm_record.h"
44#endif
45#include "appevents.h"
46#include "timefuncs.h"
47
48/* FIXME: should be removed from icon.h to avoid redefinition,
49 but still needed for compatibility with old system */
50#define ICONS_SPACING 2
51#define STATUSBAR_BATTERY_X_POS 0*ICONS_SPACING
52#define STATUSBAR_BATTERY_WIDTH (2+(2*SYSFONT_WIDTH))
53#define STATUSBAR_PLUG_X_POS STATUSBAR_X_POS + \
54 STATUSBAR_BATTERY_WIDTH + \
55 ICONS_SPACING
56#define STATUSBAR_BATTERY_HEIGHT SB_ICON_HEIGHT - 1
57#define STATUSBAR_PLUG_WIDTH 7
58#define STATUSBAR_VOLUME_X_POS STATUSBAR_X_POS + \
59 STATUSBAR_BATTERY_WIDTH + \
60 STATUSBAR_PLUG_WIDTH + \
61 2*ICONS_SPACING
62#define STATUSBAR_VOLUME_WIDTH (2+(2*SYSFONT_WIDTH))
63#define STATUSBAR_ENCODER_X_POS STATUSBAR_X_POS + \
64 STATUSBAR_BATTERY_WIDTH + \
65 STATUSBAR_PLUG_WIDTH + \
66 2*ICONS_SPACING - 1
67#define STATUSBAR_ENCODER_WIDTH 18
68#define STATUSBAR_PLAY_STATE_X_POS STATUSBAR_X_POS + \
69 STATUSBAR_BATTERY_WIDTH + \
70 STATUSBAR_PLUG_WIDTH + \
71 STATUSBAR_VOLUME_WIDTH + \
72 3*ICONS_SPACING
73#define STATUSBAR_PLAY_STATE_WIDTH 7
74#define STATUSBAR_PLAY_MODE_X_POS STATUSBAR_X_POS + \
75 STATUSBAR_BATTERY_WIDTH + \
76 STATUSBAR_PLUG_WIDTH + \
77 STATUSBAR_VOLUME_WIDTH + \
78 STATUSBAR_PLAY_STATE_WIDTH + \
79 4*ICONS_SPACING
80#define STATUSBAR_PLAY_MODE_WIDTH 7
81#define STATUSBAR_RECFREQ_X_POS STATUSBAR_X_POS + \
82 STATUSBAR_BATTERY_WIDTH + \
83 STATUSBAR_PLUG_WIDTH + \
84 STATUSBAR_VOLUME_WIDTH + \
85 STATUSBAR_PLAY_STATE_WIDTH + \
86 3*ICONS_SPACING
87#define STATUSBAR_RECFREQ_WIDTH 12
88#define STATUSBAR_RECCHANNELS_X_POS STATUSBAR_X_POS + \
89 STATUSBAR_BATTERY_WIDTH + \
90 STATUSBAR_PLUG_WIDTH + \
91 STATUSBAR_VOLUME_WIDTH + \
92 STATUSBAR_PLAY_STATE_WIDTH + \
93 STATUSBAR_RECFREQ_WIDTH + \
94 4*ICONS_SPACING
95#define STATUSBAR_RECCHANNELS_WIDTH 5
96#define STATUSBAR_SHUFFLE_X_POS STATUSBAR_X_POS + \
97 STATUSBAR_BATTERY_WIDTH + \
98 STATUSBAR_PLUG_WIDTH + \
99 STATUSBAR_VOLUME_WIDTH + \
100 STATUSBAR_PLAY_STATE_WIDTH + \
101 STATUSBAR_PLAY_MODE_WIDTH + \
102 5*ICONS_SPACING
103#define STATUSBAR_SHUFFLE_WIDTH 7
104#define STATUSBAR_LOCKM_X_POS STATUSBAR_X_POS + \
105 STATUSBAR_BATTERY_WIDTH + \
106 STATUSBAR_PLUG_WIDTH + \
107 STATUSBAR_VOLUME_WIDTH + \
108 STATUSBAR_PLAY_STATE_WIDTH + \
109 STATUSBAR_PLAY_MODE_WIDTH + \
110 STATUSBAR_SHUFFLE_WIDTH + \
111 6*ICONS_SPACING
112#define STATUSBAR_LOCKM_WIDTH 5
113#define STATUSBAR_LOCKR_X_POS STATUSBAR_X_POS + \
114 STATUSBAR_BATTERY_WIDTH + \
115 STATUSBAR_PLUG_WIDTH + \
116 STATUSBAR_VOLUME_WIDTH + \
117 STATUSBAR_PLAY_STATE_WIDTH + \
118 STATUSBAR_PLAY_MODE_WIDTH + \
119 STATUSBAR_SHUFFLE_WIDTH + \
120 STATUSBAR_LOCKM_WIDTH + \
121 7*ICONS_SPACING
122#define STATUSBAR_LOCKR_WIDTH 5
123
124#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
125#define STATUSBAR_DISK_WIDTH 12
126#define STATUSBAR_DISK_X_POS(statusbar_width) statusbar_width - \
127 STATUSBAR_DISK_WIDTH
128#else
129#define STATUSBAR_DISK_WIDTH 0
130#endif
131#define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \
132 STATUSBAR_DISK_WIDTH
133struct gui_syncstatusbar statusbars;
134
135/* Prototypes */
136static void gui_statusbar_icon_battery(struct screen * display, int percent,
137 int batt_charge_step);
138static bool gui_statusbar_icon_volume(struct gui_statusbar * bar, int volume);
139static void gui_statusbar_icon_play_state(struct screen * display, int state);
140static void gui_statusbar_icon_play_mode(struct screen * display, int mode);
141static void gui_statusbar_icon_shuffle(struct screen * display);
142static void gui_statusbar_icon_lock(struct screen * display);
143#ifdef HAS_REMOTE_BUTTON_HOLD
144static void gui_statusbar_icon_lock_remote(struct screen * display);
145#endif
146#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
147static void gui_statusbar_led(struct screen * display);
148#endif
149#ifdef HAVE_RECORDING
150static void gui_statusbar_icon_recording_info(struct screen * display);
151#endif
152#if CONFIG_RTC
153static void gui_statusbar_time(struct screen * display, struct tm *time);
154#endif
155
156/* End prototypes */
157
158
159/*
160 * Initializes a status bar
161 * - bar : the bar to initialize
162 */
163static void gui_statusbar_init(struct screen * display, struct gui_statusbar * bar)
164{
165 bar->display = display;
166 bar->redraw_volume = true;
167 bar->volume_icon_switch_tick = bar->battery_icon_switch_tick = current_tick;
168 memset((void*)&(bar->lastinfo), 0, sizeof(struct status_info));
169#if CONFIG_RTC
170 bar->last_tm_min = 0;
171#endif
172}
173
174static struct screen * sb_fill_bar_info(struct gui_statusbar * bar)
175{
176 struct screen *display = bar->display;
177
178 if (!display)
179 return display;
180
181 bar->info.battlevel = battery_level();
182#ifdef HAVE_USB_POWER
183 bar->info.usb_inserted = usb_inserted();
184#endif
185#if CONFIG_CHARGING
186 bar->info.inserted = (charger_input_state == CHARGER);
187 if (bar->info.inserted)
188 {
189 bar->info.battery_state = true;
190
191#if CONFIG_CHARGING >= CHARGING_MONITOR
192
193 /* zero battery run time if charging */
194 if (charge_state > DISCHARGING)
195 zero_runtime();
196
197 /* animate battery if charging */
198 if ((charge_state == DISCHARGING) || (charge_state == TRICKLE))
199 {
200 bar->info.batt_charge_step = -1;
201 }
202 else
203 {
204#else /* CONFIG_CHARGING < CHARGING_MONITOR */
205 zero_runtime();
206 {
207#endif /* CONFIG_CHARGING < CHARGING_MONITOR */
208 /* animate in (max.) 4 steps, starting near the current charge level */
209 if (TIME_AFTER(current_tick, bar->battery_icon_switch_tick))
210 {
211 if (++bar->info.batt_charge_step > 3)
212 bar->info.batt_charge_step = bar->info.battlevel / 34;
213 bar->battery_icon_switch_tick = current_tick + HZ;
214 }
215 }
216 }
217 else
218#endif /* CONFIG_CHARGING */
219 {
220 bar->info.batt_charge_step = -1;
221 if (battery_level_safe())
222 bar->info.battery_state = true;
223 else
224 /* blink battery if level is low */
225 if (TIME_AFTER(current_tick, bar->battery_icon_switch_tick) &&
226 (bar->info.battlevel > -1))
227 {
228 bar->info.battery_state = !bar->info.battery_state;
229 bar->battery_icon_switch_tick = current_tick + HZ;
230 }
231 }
232 bar->info.volume = global_status.volume;
233 bar->info.shuffle = global_settings.playlist_shuffle;
234#ifdef HAS_BUTTON_HOLD
235 bar->info.keylock = button_hold();
236#else
237 bar->info.keylock = is_keys_locked();
238#endif /* HAS_BUTTON_HOLD */
239#ifdef HAS_REMOTE_BUTTON_HOLD
240 bar->info.keylockremote = remote_button_hold();
241#endif
242 bar->info.repeat = global_settings.repeat_mode;
243 bar->info.playmode = current_playmode();
244#if CONFIG_RTC
245 bar->time = get_time();
246#endif /* CONFIG_RTC */
247#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
248 if(!display->has_disk_led)
249 bar->info.led = led_read(HZ/2); /* delay should match polling interval */
250#endif
251
252 return display;
253}
254
255void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw, struct viewport *vp)
256{
257 struct viewport *last_vp = NULL;
258 struct screen * display = sb_fill_bar_info(bar);
259 if (!display)
260 return;
261
262 /* only redraw if forced to, or info has changed */
263 if (force_redraw || bar->redraw_volume ||
264#if CONFIG_RTC
265 (bar->time->tm_min != bar->last_tm_min) ||
266#endif
267 memcmp(&(bar->info), &(bar->lastinfo), sizeof(struct status_info)))
268 {
269 last_vp = display->set_viewport(vp);
270 display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
271 display->fill_viewport();
272 display->set_drawmode(DRMODE_SOLID);
273 display->setfont(FONT_SYSFIXED);
274
275 if (bar->info.battery_state)
276 gui_statusbar_icon_battery(display, bar->info.battlevel,
277 bar->info.batt_charge_step);
278#ifdef HAVE_USB_POWER
279 if (bar->info.usb_inserted)
280 display->mono_bitmap(bitmap_icons_7x8[Icon_USBPlug],
281 STATUSBAR_PLUG_X_POS,
282 STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH,
283 SB_ICON_HEIGHT);
284#endif /* HAVE_USB_POWER */
285#if CONFIG_CHARGING
286#ifdef HAVE_USB_POWER
287 else
288#endif
289 /* draw power plug if charging */
290 if (bar->info.inserted)
291 display->mono_bitmap(bitmap_icons_7x8[Icon_Plug],
292 STATUSBAR_PLUG_X_POS,
293 STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH,
294 SB_ICON_HEIGHT);
295#endif /* CONFIG_CHARGING */
296#ifdef HAVE_RECORDING
297 /* turn off volume display in recording screen */
298 bool recscreen_on = in_recording_screen();
299 if (!recscreen_on)
300#endif
301 bar->redraw_volume = gui_statusbar_icon_volume(bar, bar->info.volume);
302 gui_statusbar_icon_play_state(display, current_playmode() + Icon_Play);
303
304#ifdef HAVE_RECORDING
305 /* If in recording screen, replace repeat mode, volume
306 and shuffle icons with recording info */
307 if (recscreen_on)
308 gui_statusbar_icon_recording_info(display);
309 else
310#endif
311 {
312 gui_statusbar_icon_play_mode(display, bar->info.repeat);
313
314 if (bar->info.shuffle)
315 gui_statusbar_icon_shuffle(display);
316 }
317 if (bar->info.keylock)
318 gui_statusbar_icon_lock(display);
319#ifdef HAS_REMOTE_BUTTON_HOLD
320 if (bar->info.keylockremote)
321 gui_statusbar_icon_lock_remote(display);
322#endif
323#if CONFIG_RTC
324 gui_statusbar_time(display, bar->time);
325 bar->last_tm_min = bar->time->tm_min;
326#endif /* CONFIG_RTC */
327#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
328 if(!display->has_disk_led && bar->info.led)
329 {
330 gui_statusbar_led(display);
331 }
332#endif
333 display->setfont(FONT_UI);
334 display->update_viewport();
335 display->set_viewport(last_vp);
336 bar->lastinfo = bar->info;
337 }
338}
339
340/* from icon.c */
341/*
342 * Print battery icon to status bar
343 */
344static void gui_statusbar_icon_battery(struct screen * display, int percent,
345 int batt_charge_step)
346{
347 int fill, endfill;
348 char buffer[5];
349 unsigned int width, height;
350#if LCD_DEPTH > 1
351 unsigned int prevfg = 0;
352#endif
353
354#if CONFIG_CHARGING
355 if (batt_charge_step >= 0)
356 {
357 fill = percent * (STATUSBAR_BATTERY_WIDTH-3) / 100;
358 endfill = 34 * batt_charge_step * (STATUSBAR_BATTERY_WIDTH-3) / 100;
359 }
360 else
361#else
362 (void)batt_charge_step;
363#endif
364 {
365 fill = endfill = (percent * (STATUSBAR_BATTERY_WIDTH-3) + 50) / 100;
366 }
367
368#if CONFIG_CHARGING == CHARGING_MONITOR && !defined(SIMULATOR)
369 /* Certain charge controlled targets */
370 /* show graphical animation when charging instead of numbers */
371 if ((global_settings.battery_display) &&
372 (charge_state != CHARGING) &&
373 (percent > -1) &&
374 (percent <= 100)) {
375#else /* all others */
376 if (global_settings.battery_display && (percent > -1) && (percent <= 100)) {
377#endif
378 /* Numeric display */
379 snprintf(buffer, sizeof(buffer), "%3d", percent);
380 font_getstringsize(buffer, &width, &height, FONT_SYSFIXED);
381 if (height <= STATUSBAR_HEIGHT) {
382 display->putsxy(STATUSBAR_BATTERY_X_POS
383 + STATUSBAR_BATTERY_WIDTH / 2
384 - width/2, STATUSBAR_Y_POS, buffer);
385 }
386
387 }
388 else {
389 /* draw battery */
390 display->drawrect(STATUSBAR_BATTERY_X_POS, STATUSBAR_Y_POS,
391 STATUSBAR_BATTERY_WIDTH - 1, STATUSBAR_BATTERY_HEIGHT);
392 display->vline(STATUSBAR_BATTERY_X_POS + STATUSBAR_BATTERY_WIDTH - 1,
393 STATUSBAR_Y_POS + 2, STATUSBAR_Y_POS + 4);
394
395 display->fillrect(STATUSBAR_BATTERY_X_POS + 1, STATUSBAR_Y_POS + 1,
396 fill, STATUSBAR_BATTERY_HEIGHT - 2);
397#if LCD_DEPTH > 1
398 if (display->depth > 1)
399 {
400 prevfg = display->get_foreground();
401 display->set_foreground(LCD_DARKGRAY);
402 }
403#endif
404 display->fillrect(STATUSBAR_BATTERY_X_POS + 1 + fill, STATUSBAR_Y_POS + 1,
405 endfill - fill, STATUSBAR_BATTERY_HEIGHT - 2);
406#if LCD_DEPTH > 1
407 if (display->depth > 1)
408 display->set_foreground(prevfg);
409#endif
410 }
411
412 if (percent == -1 || percent > 100) {
413 display->putsxy(STATUSBAR_BATTERY_X_POS + STATUSBAR_BATTERY_WIDTH / 2
414 - 4, STATUSBAR_Y_POS, "?");
415 }
416}
417
418/*
419 * Print volume gauge to status bar
420 */
421static bool gui_statusbar_icon_volume(struct gui_statusbar * bar, int volume)
422{
423 int i;
424 int vol;
425 char buffer[4];
426 unsigned int width, height;
427 bool needs_redraw = false;
428 int type = global_settings.volume_type;
429 struct screen * display=bar->display;
430 const int minvol = sound_min(SOUND_VOLUME);
431
432 if (volume < minvol)
433 volume = minvol;
434
435 if (volume == minvol) {
436 display->mono_bitmap(bitmap_icons_7x8[Icon_Mute],
437 STATUSBAR_VOLUME_X_POS + STATUSBAR_VOLUME_WIDTH / 2 - 4,
438 STATUSBAR_Y_POS, 7, SB_ICON_HEIGHT);
439 }
440 else {
441 const int maxvol = sound_max(SOUND_VOLUME);
442
443 if (volume > maxvol)
444 volume = maxvol;
445 /* We want to redraw the icon later on */
446 if (bar->last_volume != volume && bar->last_volume >= minvol) {
447 bar->volume_icon_switch_tick = current_tick + HZ;
448 }
449
450 /* If the timeout hasn't yet been reached, we show it numerically
451 and tell the caller that we want to be called again */
452 if (TIME_BEFORE(current_tick,bar->volume_icon_switch_tick)) {
453 type = 1;
454 needs_redraw = true;
455 }
456
457 /* display volume level numerical? */
458 if (type)
459 {
460 const int num_decimals = sound_numdecimals(SOUND_VOLUME);
461 if (num_decimals)
462 volume /= 10 * num_decimals;
463
464 snprintf(buffer, sizeof(buffer), "%2d", volume);
465 font_getstringsize(buffer, &width, &height, FONT_SYSFIXED);
466 if (height <= STATUSBAR_HEIGHT) {
467 display->putsxy(STATUSBAR_VOLUME_X_POS
468 + STATUSBAR_VOLUME_WIDTH / 2
469 - width/2, STATUSBAR_Y_POS, buffer);
470 }
471 } else {
472 /* display volume bar */
473 vol = (volume - minvol) * 14 / (maxvol - minvol);
474 for(i=0; i < vol; i++) {
475 display->vline(STATUSBAR_VOLUME_X_POS + i,
476 STATUSBAR_Y_POS + 6 - i / 2,
477 STATUSBAR_Y_POS + 6);
478 }
479 }
480 }
481 bar->last_volume = volume;
482
483 return needs_redraw;
484}
485
486/*
487 * Print play state to status bar
488 */
489static void gui_statusbar_icon_play_state(struct screen * display, int state)
490{
491 display->mono_bitmap(bitmap_icons_7x8[state], STATUSBAR_PLAY_STATE_X_POS,
492 STATUSBAR_Y_POS, STATUSBAR_PLAY_STATE_WIDTH,
493 SB_ICON_HEIGHT);
494}
495
496/*
497 * Print play mode to status bar
498 */
499static void gui_statusbar_icon_play_mode(struct screen * display, int mode)
500{
501 switch (mode) {
502#ifdef AB_REPEAT_ENABLE
503 case REPEAT_AB:
504 display->mono_bitmap(bitmap_icons_7x8[Icon_RepeatAB],
505 STATUSBAR_PLAY_MODE_X_POS,
506 STATUSBAR_Y_POS, STATUSBAR_PLAY_MODE_WIDTH,
507 SB_ICON_HEIGHT);
508 break;
509#endif /* AB_REPEAT_ENABLE */
510
511 case REPEAT_ONE:
512 display->mono_bitmap(bitmap_icons_7x8[Icon_RepeatOne],
513 STATUSBAR_PLAY_MODE_X_POS,
514 STATUSBAR_Y_POS, STATUSBAR_PLAY_MODE_WIDTH,
515 SB_ICON_HEIGHT);
516 break;
517
518 case REPEAT_ALL:
519 case REPEAT_SHUFFLE:
520 display->mono_bitmap(bitmap_icons_7x8[Icon_Repeat],
521 STATUSBAR_PLAY_MODE_X_POS,
522 STATUSBAR_Y_POS, STATUSBAR_PLAY_MODE_WIDTH,
523 SB_ICON_HEIGHT);
524 break;
525 }
526}
527/*
528 * Print shuffle mode to status bar
529 */
530static void gui_statusbar_icon_shuffle(struct screen * display)
531{
532 display->mono_bitmap(bitmap_icons_7x8[Icon_Shuffle],
533 STATUSBAR_SHUFFLE_X_POS, STATUSBAR_Y_POS,
534 STATUSBAR_SHUFFLE_WIDTH, SB_ICON_HEIGHT);
535}
536
537/*
538 * Print lock when keys are locked
539 */
540static void gui_statusbar_icon_lock(struct screen * display)
541{
542 display->mono_bitmap(bitmap_icons_5x8[Icon_Lock_Main],
543 STATUSBAR_LOCKM_X_POS, STATUSBAR_Y_POS,
544 STATUSBAR_LOCKM_WIDTH, SB_ICON_HEIGHT);
545}
546
547#ifdef HAS_REMOTE_BUTTON_HOLD
548/*
549 * Print remote lock when remote hold is enabled
550 */
551static void gui_statusbar_icon_lock_remote(struct screen * display)
552{
553 display->mono_bitmap(bitmap_icons_5x8[Icon_Lock_Remote],
554 STATUSBAR_LOCKR_X_POS, STATUSBAR_Y_POS,
555 STATUSBAR_LOCKR_WIDTH, SB_ICON_HEIGHT);
556}
557#endif
558
559#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
560/*
561 * no real LED: disk activity in status bar
562 */
563static void gui_statusbar_led(struct screen * display)
564{
565 display->mono_bitmap(bitmap_icon_disk,
566 STATUSBAR_DISK_X_POS(display->getwidth()),
567 STATUSBAR_Y_POS, STATUSBAR_DISK_WIDTH,
568 SB_ICON_HEIGHT);
569}
570#endif
571
572#if CONFIG_RTC
573/*
574 * Print time to status bar
575 */
576static void gui_statusbar_time(struct screen * display, struct tm *time)
577{
578 unsigned char buffer[6];
579 const unsigned char *p = buffer;
580 unsigned int width, height;
581 int hour, minute;
582 if ( valid_time(time) ) {
583 hour = time->tm_hour;
584 minute = time->tm_min;
585 if ( global_settings.timeformat ) { /* 12 hour clock */
586 hour %= 12;
587 if ( hour == 0 ) {
588 hour += 12;
589 }
590 }
591 snprintf(buffer, sizeof(buffer), "%02d:%02d", hour, minute);
592 }
593 else {
594 p = "--:--";
595 }
596
597 font_getstringsize(p, &width, &height, FONT_SYSFIXED);
598 if (height <= STATUSBAR_HEIGHT) {
599 display->putsxy(STATUSBAR_TIME_X_END(display->getwidth()) - width,
600 STATUSBAR_Y_POS, p);
601 }
602
603}
604#endif
605
606#ifdef HAVE_RECORDING
607/**
608 * Write a number to the display using bitmaps and return new position
609 */
610static int write_bitmap_number(struct screen * display, int value,
611 int x, int y)
612{
613 char buf[12], *ptr;
614 itoa_buf(buf, sizeof(buf), value);
615
616 for (ptr = buf; *ptr != '\0'; ptr++, x += BM_GLYPH_WIDTH)
617 display->mono_bitmap(bitmap_glyphs_4x8[*ptr - '0'], x, y,
618 BM_GLYPH_WIDTH, SB_ICON_HEIGHT);
619 return x;
620}
621
622/**
623 * Write format info bitmaps - right justified
624 */
625static void gui_statusbar_write_format_info(struct screen * display)
626{
627 /* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED
628 so must use icons */
629 int rec_format = global_settings.rec_format;
630 unsigned bitrk = 0; /* compiler warns about unitialized use !! */
631 int xpos = STATUSBAR_ENCODER_X_POS;
632 int width = STATUSBAR_ENCODER_WIDTH;
633 const unsigned char *bm = bitmap_formats_18x8[rec_format];
634
635 if (rec_format == REC_FORMAT_MPA_L3)
636 {
637 /* Special handling for mp3 */
638 bitrk = global_settings.mp3_enc_config.bitrate;
639 bitrk = mp3_enc_bitr[bitrk];
640
641 width = BM_MPA_L3_M_WIDTH;
642
643 /* Slide 'M' to right if fewer than three digits used */
644 if (bitrk > 999)
645 bitrk = 999; /* neurotic safety check if corrupted */
646 else
647 {
648 if (bitrk < 100)
649 xpos += BM_GLYPH_WIDTH;
650 if (bitrk < 10)
651 xpos += BM_GLYPH_WIDTH;
652 }
653 }
654
655 /* Show bitmap - clipping right edge if needed */
656 display->mono_bitmap_part(bm, 0, 0, STATUSBAR_ENCODER_WIDTH,
657 xpos, STATUSBAR_Y_POS, width, SB_ICON_HEIGHT);
658
659 if (rec_format == REC_FORMAT_MPA_L3)
660 {
661 xpos += BM_MPA_L3_M_WIDTH; /* to right of 'M' */
662 write_bitmap_number(display, bitrk, xpos, STATUSBAR_Y_POS);
663 }
664}
665
666/**
667 * Write sample rate using bitmaps - left justified
668 */
669static void gui_statusbar_write_samplerate_info(struct screen * display)
670{
671 unsigned long samprk;
672 int xpos;
673
674#ifdef SIMULATOR
675 samprk = 44100;
676#else
677#ifdef HAVE_SPDIF_REC
678 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
679 /* Use rate in use, not current measured rate if it changed */
680 samprk = pcm_rec_sample_rate();
681 else
682#endif
683 samprk = rec_freq_sampr[global_settings.rec_frequency];
684#endif /* SIMULATOR */
685
686 samprk /= 1000;
687 if (samprk > 99)
688 samprk = 99; /* Limit to 3 glyphs */
689
690 xpos = write_bitmap_number(display, (unsigned)samprk,
691 STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS);
692
693 /* write the 'k' */
694 display->mono_bitmap(bitmap_glyphs_4x8[Glyph_4x8_k], xpos,
695 STATUSBAR_Y_POS, BM_GLYPH_WIDTH,
696 SB_ICON_HEIGHT);
697}
698
699static void gui_statusbar_icon_recording_info(struct screen * display)
700{
701 /* Display Codec info in statusbar */
702 gui_statusbar_write_format_info(display);
703
704 /* Display Samplerate info in statusbar */
705 gui_statusbar_write_samplerate_info(display);
706
707 /* Display Channel status in status bar */
708 if(global_settings.rec_channels)
709 {
710 display->mono_bitmap(bitmap_icons_5x8[Icon_Mono],
711 STATUSBAR_RECCHANNELS_X_POS , STATUSBAR_Y_POS,
712 STATUSBAR_RECCHANNELS_WIDTH, SB_ICON_HEIGHT);
713 }
714 else
715 {
716 display->mono_bitmap(bitmap_icons_5x8[Icon_Stereo],
717 STATUSBAR_RECCHANNELS_X_POS, STATUSBAR_Y_POS,
718 STATUSBAR_RECCHANNELS_WIDTH, SB_ICON_HEIGHT);
719 }
720}
721#endif /* HAVE_RECORDING */
722
723void gui_syncstatusbar_init(struct gui_syncstatusbar * bars)
724{
725 FOR_NB_SCREENS(i) {
726 gui_statusbar_init(&(screens[i]), &(bars->statusbars[i]));
727 }
728}
729
730
731#ifdef HAVE_REMOTE_LCD
732enum statusbar_values statusbar_position(int screen)
733{
734 if (screen == SCREEN_REMOTE)
735 return global_settings.remote_statusbar;
736 return global_settings.statusbar;
737}
738#endif