Colour targets: Revert an optimisation from almost 18 months ago that actually turned...
[Rockbox.git] / apps / screens.c
blob02c61a4f4076a6a453abd7a5daf56e8d601af2b4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Björn Stenberg
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdbool.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include "backlight.h"
26 #include "action.h"
27 #include "lcd.h"
28 #ifdef HAVE_REMOTE_LCD
29 #include "lcd-remote.h"
30 #endif
31 #include "lang.h"
32 #include "icons.h"
33 #include "font.h"
34 #include "audio.h"
35 #include "mp3_playback.h"
36 #include "usb.h"
37 #include "settings.h"
38 #include "status.h"
39 #include "playlist.h"
40 #include "sprintf.h"
41 #include "kernel.h"
42 #include "power.h"
43 #include "system.h"
44 #include "powermgmt.h"
45 #include "adc.h"
46 #include "action.h"
47 #include "talk.h"
48 #include "misc.h"
49 #include "id3.h"
50 #include "screens.h"
51 #include "debug.h"
52 #include "led.h"
53 #include "sound.h"
54 #include "splash.h"
55 #include "statusbar.h"
56 #include "screen_access.h"
57 #include "pcmbuf.h"
58 #include "list.h"
59 #include "yesno.h"
60 #include "backdrop.h"
61 #include "viewport.h"
63 #ifdef HAVE_LCD_BITMAP
64 #include <bitmaps/usblogo.h>
65 #endif
67 #ifdef HAVE_REMOTE_LCD
68 #include <bitmaps/remote_usblogo.h>
69 #endif
71 #ifdef HAVE_MMC
72 #include "ata_mmc.h"
73 #endif
74 #if CONFIG_CODEC == SWCODEC
75 #include "dsp.h"
76 #endif
78 #ifdef HAVE_LCD_BITMAP
79 #define SCROLLBAR_WIDTH 6
80 #endif
82 /* only used in set_time screen */
83 #if defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0)
84 static int clamp_value_wrap(int value, int max, int min)
86 if (value > max)
87 return min;
88 if (value < min)
89 return max;
90 return value;
92 #endif
94 void usb_screen(void)
96 #ifdef USB_NONE
97 /* nothing here! */
98 #else
99 int i;
100 bool statusbar = global_settings.statusbar; /* force the statusbar */
101 global_settings.statusbar = true;
102 #if LCD_DEPTH > 1
103 show_main_backdrop();
104 #endif
105 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
106 show_remote_main_backdrop();
107 #endif
108 FOR_NB_SCREENS(i)
110 screens[i].backlight_on();
111 screens[i].clear_display();
112 #if NB_SCREENS > 1
113 if (i == SCREEN_REMOTE)
115 screens[i].bitmap(remote_usblogo,
116 (LCD_REMOTE_WIDTH-BMPWIDTH_remote_usblogo),
117 (LCD_REMOTE_HEIGHT-BMPHEIGHT_remote_usblogo)/2,
118 BMPWIDTH_remote_usblogo, BMPHEIGHT_remote_usblogo);
120 else
122 #endif
123 #ifdef HAVE_LCD_BITMAP
124 screens[i].transparent_bitmap(usblogo,
125 (LCD_WIDTH-BMPWIDTH_usblogo),
126 (LCD_HEIGHT-BMPHEIGHT_usblogo)/2,
127 BMPWIDTH_usblogo, BMPHEIGHT_usblogo);
128 #else
129 screens[i].double_height(false);
130 screens[i].puts_scroll(0, 0, "[USB Mode]");
131 status_set_param(false);
132 status_set_audio(false);
133 status_set_usb(true);
134 #endif /* HAVE_LCD_BITMAP */
135 #if NB_SCREENS > 1
137 #endif
138 screens[i].update();
141 gui_syncstatusbar_draw(&statusbars, true);
142 #ifdef SIMULATOR
143 while (button_get(true) & BUTTON_REL);
144 #else
145 usb_acknowledge(SYS_USB_CONNECTED_ACK);
146 while(usb_wait_for_disconnect_w_tmo(&button_queue, HZ)) {
147 if(usb_inserted()) {
148 #ifdef HAVE_MMC /* USB-MMC bridge can report activity */
149 led(mmc_usb_active(HZ));
150 #endif /* HAVE_MMC */
151 gui_syncstatusbar_draw(&statusbars, false);
154 #endif /* SIMULATOR */
155 #ifdef HAVE_LCD_CHARCELLS
156 status_set_usb(false);
157 #endif /* HAVE_LCD_CHARCELLS */
158 FOR_NB_SCREENS(i)
159 screens[i].backlight_on();
160 global_settings.statusbar = statusbar;
161 #endif /* USB_NONE */
164 #ifdef HAVE_MMC
165 int mmc_remove_request(void)
167 struct queue_event ev;
168 int i;
169 FOR_NB_SCREENS(i)
170 screens[i].clear_display();
171 gui_syncsplash(1, str(LANG_REMOVE_MMC));
172 if (global_settings.talk_menu)
173 talk_id(LANG_REMOVE_MMC, false);
175 while (1)
177 queue_wait_w_tmo(&button_queue, &ev, HZ/2);
178 switch (ev.id)
180 case SYS_HOTSWAP_EXTRACTED:
181 return SYS_HOTSWAP_EXTRACTED;
183 case SYS_USB_DISCONNECTED:
184 return SYS_USB_DISCONNECTED;
188 #endif
190 /* the charging screen is only used for archos targets */
191 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) && defined(CPU_SH)
193 #ifdef HAVE_LCD_BITMAP
194 static void charging_display_info(bool animate)
196 unsigned char charging_logo[36];
197 const int pox_x = (LCD_WIDTH - sizeof(charging_logo)) / 2;
198 const int pox_y = 32;
199 static unsigned phase = 3;
200 unsigned i;
201 char buf[32];
202 (void)buf;
204 #ifdef NEED_ATA_POWER_BATT_MEASURE
205 if (ide_powered()) /* FM and V2 can only measure when ATA power is on */
206 #endif
208 int battv = battery_voltage();
209 snprintf(buf, 32, " Batt: %d.%02dV %d%% ", battv / 1000,
210 (battv % 1000) / 10, battery_level());
211 lcd_puts(0, 7, buf);
214 #if CONFIG_CHARGING == CHARGING_CONTROL
216 snprintf(buf, 32, "Charge mode:");
217 lcd_puts(0, 2, buf);
219 if (charge_state == CHARGING)
220 snprintf(buf, 32, str(LANG_BATTERY_CHARGE));
221 else if (charge_state == TOPOFF)
222 snprintf(buf, 32, str(LANG_BATTERY_TOPOFF_CHARGE));
223 else if (charge_state == TRICKLE)
224 snprintf(buf, 32, str(LANG_BATTERY_TRICKLE_CHARGE));
225 else
226 snprintf(buf, 32, "not charging");
228 lcd_puts(0, 3, buf);
229 if (!charger_enabled)
230 animate = false;
231 #endif /* CONFIG_CHARGING == CHARGING_CONTROL */
234 /* middle part */
235 memset(charging_logo+3, 0x00, 32);
236 charging_logo[0] = 0x3C;
237 charging_logo[1] = 0x24;
238 charging_logo[2] = charging_logo[35] = 0xFF;
240 if (!animate)
241 { /* draw the outline */
242 /* middle part */
243 lcd_mono_bitmap(charging_logo, pox_x, pox_y + 8,
244 sizeof(charging_logo), 8);
245 lcd_set_drawmode(DRMODE_FG);
246 /* upper line */
247 charging_logo[0] = charging_logo[1] = 0x00;
248 memset(charging_logo+2, 0x80, 34);
249 lcd_mono_bitmap(charging_logo, pox_x, pox_y, sizeof(charging_logo), 8);
250 /* lower line */
251 memset(charging_logo+2, 0x01, 34);
252 lcd_mono_bitmap(charging_logo, pox_x, pox_y + 16,
253 sizeof(charging_logo), 8);
254 lcd_set_drawmode(DRMODE_SOLID);
256 else
257 { /* animate the middle part */
258 for (i = 3; i<MIN(sizeof(charging_logo)-1, phase); i++)
260 if ((i-phase) % 8 == 0)
261 { /* draw a "bubble" here */
262 unsigned bitpos;
263 bitpos = (phase + i/8) % 15; /* "bounce" effect */
264 if (bitpos > 7)
265 bitpos = 14 - bitpos;
266 charging_logo[i] = 0x01 << bitpos;
269 lcd_mono_bitmap(charging_logo, pox_x, pox_y + 8,
270 sizeof(charging_logo), 8);
271 phase++;
273 lcd_update();
275 #else /* not HAVE_LCD_BITMAP */
277 static unsigned long logo_chars[4];
278 static const unsigned char logo_pattern[] = {
279 0x07, 0x04, 0x1c, 0x14, 0x1c, 0x04, 0x07, 0, /* char 1 */
280 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0, /* char 2 */
281 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0, /* char 3 */
282 0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1f, 0, /* char 4 */
285 static void logo_lock_patterns(bool on)
287 int i;
289 if (on)
291 for (i = 0; i < 4; i++)
292 logo_chars[i] = lcd_get_locked_pattern();
294 else
296 for (i = 0; i < 4; i++)
297 lcd_unlock_pattern(logo_chars[i]);
301 static void charging_display_info(bool animate)
303 int battv;
304 unsigned i, ypos;
305 static unsigned phase = 3;
306 char buf[32];
308 battv = battery_voltage();
309 snprintf(buf, sizeof(buf), " %d.%02dV", battv / 1000, (battv % 1000) / 10);
310 lcd_puts(4, 1, buf);
312 memcpy(buf, logo_pattern, 32); /* copy logo patterns */
314 if (!animate) /* build the screen */
316 lcd_double_height(false);
317 lcd_puts(0, 0, "[Charging]");
318 for (i = 0; i < 4; i++)
319 lcd_putc(i, 1, logo_chars[i]);
321 else /* animate the logo */
323 for (i = 3; i < MIN(19, phase); i++)
325 if ((i - phase) % 5 == 0)
326 { /* draw a "bubble" here */
327 ypos = (phase + i/5) % 9; /* "bounce" effect */
328 if (ypos > 4)
329 ypos = 8 - ypos;
330 buf[5 - ypos + 8 * (i/5)] |= 0x10 >> (i%5);
333 phase++;
336 for (i = 0; i < 4; i++)
337 lcd_define_pattern(logo_chars[i], buf + 8 * i);
339 lcd_update();
341 #endif /* (not) HAVE_LCD_BITMAP */
343 /* blocks while charging, returns on event:
344 1 if charger cable was removed
345 2 if Off/Stop key was pressed
346 3 if On key was pressed
347 4 if USB was connected */
349 int charging_screen(void)
351 unsigned int button;
352 int rc = 0;
354 ide_power_enable(false); /* power down the disk, else would be spinning */
356 lcd_clear_display();
357 backlight_set_timeout(global_settings.backlight_timeout);
358 #ifdef HAVE_REMOTE_LCD
359 remote_backlight_set_timeout(global_settings.remote_backlight_timeout);
360 #endif
361 backlight_set_timeout_plugged(global_settings.backlight_timeout_plugged);
362 gui_syncstatusbar_draw(&statusbars, true);
364 #ifdef HAVE_LCD_CHARCELLS
365 logo_lock_patterns(true);
366 #endif
367 charging_display_info(false);
371 gui_syncstatusbar_draw(&statusbars, false);
372 charging_display_info(true);
373 button = get_action(CONTEXT_STD,HZ/3);
374 if (button == ACTION_STD_OK)
375 rc = 2;
376 else if (usb_detect())
377 rc = 3;
378 else if (!charger_inserted())
379 rc = 1;
380 } while (!rc);
382 #ifdef HAVE_LCD_CHARCELLS
383 logo_lock_patterns(false);
384 #endif
385 return rc;
387 #endif /* CONFIG_CHARGING && !HAVE_POWEROFF_WHILE_CHARGING && defined(CPU_SH) */
389 #if CONFIG_CHARGING
390 void charging_splash(void)
392 gui_syncsplash(2*HZ, (unsigned char *)str(LANG_BATTERY_CHARGE));
393 button_clear_queue();
395 #endif
398 #if defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0)
400 /* little helper function for voice output */
401 static void say_time(int cursorpos, const struct tm *tm)
403 int value = 0;
404 int unit = 0;
406 if (!global_settings.talk_menu)
407 return;
409 switch(cursorpos)
411 case 0:
412 value = tm->tm_hour;
413 unit = UNIT_HOUR;
414 break;
415 case 1:
416 value = tm->tm_min;
417 unit = UNIT_MIN;
418 break;
419 case 2:
420 value = tm->tm_sec;
421 unit = UNIT_SEC;
422 break;
423 case 3:
424 value = tm->tm_year + 1900;
425 break;
426 case 5:
427 value = tm->tm_mday;
428 break;
431 if (cursorpos == 4) /* month */
432 talk_id(LANG_MONTH_JANUARY + tm->tm_mon, false);
433 else
434 talk_value(value, unit, false);
438 #define INDEX_X 0
439 #define INDEX_Y 1
441 #define SEPARATOR ":"
442 bool set_time_screen(const char* title, struct tm *tm)
444 bool done = false;
445 int button;
446 unsigned int i, j, s;
447 int cursorpos = 0;
448 unsigned int julianday;
449 unsigned int realyear;
450 unsigned int width;
451 unsigned int min, max;
452 unsigned int statusbar_height = 0;
453 unsigned int separator_width, weekday_width;
454 unsigned int prev_line_height;
455 int daysinmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
456 unsigned char buffer[20];
457 struct viewport vp[NB_SCREENS];
458 int nb_lines;
460 /* 6 possible cursor possitions, 2 values stored for each: x, y */
461 unsigned int cursor[6][2];
463 int *valptr = NULL;
464 unsigned char *ptr[6];
466 if(global_settings.statusbar)
467 statusbar_height = STATUSBAR_HEIGHT;
469 /* speak selection when screen is entered */
470 say_time(cursorpos, tm);
472 while (!done) {
473 /* for easy acess in the drawing loop */
474 ptr[0] = buffer; /* hours */
475 ptr[1] = buffer + 3; /* minutes */
476 ptr[2] = buffer + 6; /* seconds */
477 ptr[3] = buffer + 9; /* year */
478 ptr[4] = str(LANG_MONTH_JANUARY + tm->tm_mon); /* monthname */
479 ptr[5] = buffer + 14; /* day of month */
481 /* calculate the number of days in febuary */
482 realyear = tm->tm_year + 1900;
483 if((realyear % 4 == 0 && !(realyear % 100 == 0)) || realyear % 400 == 0)
484 daysinmonth[1] = 29;
485 else
486 daysinmonth[1] = 28;
488 /* fix day if month or year changed */
489 if (tm->tm_mday > daysinmonth[tm->tm_mon])
490 tm->tm_mday = daysinmonth[tm->tm_mon];
492 /* calculate day of week */
493 julianday = tm->tm_mday;
494 for(i = 0; (int)i < tm->tm_mon; i++) {
495 julianday += daysinmonth[i];
498 tm->tm_wday = (realyear + julianday + (realyear - 1) / 4 -
499 (realyear - 1) / 100 + (realyear - 1) / 400 + 7 - 1) % 7;
501 /* put all the numbers we want from the tm struct into
502 an easily printable buffer */
503 snprintf(buffer, sizeof(buffer),
504 "%02d " "%02d " "%02d " "%04d " "%02d",
505 tm->tm_hour, tm->tm_min, tm->tm_sec,
506 tm->tm_year+1900, tm->tm_mday);
508 /* convert spaces in the buffer to '\0' to make it possible to work
509 directly on the buffer */
510 for(i=0; i < sizeof(buffer); i++)
512 if(buffer[i] == ' ')
513 buffer[i] = '\0';
516 FOR_NB_SCREENS(s)
518 viewport_set_defaults(&vp[s], s);
519 nb_lines = viewport_get_nb_lines(&vp[s]);
521 /* minimum lines needed is 2 + title line */
522 if (nb_lines < 4)
524 vp[s].font = FONT_SYSFIXED;
525 nb_lines = viewport_get_nb_lines(&vp[s]);
528 /* recalculate the positions and offsets */
529 if (nb_lines >= 3)
530 screens[s].getstringsize(title, NULL, &prev_line_height);
531 else
532 prev_line_height = 0;
534 screens[s].getstringsize(SEPARATOR, &separator_width, NULL);
536 /* weekday */
537 screens[s].getstringsize(str(LANG_WEEKDAY_SUNDAY + tm->tm_wday),
538 &weekday_width, NULL);
539 screens[s].getstringsize(" ", &separator_width, NULL);
541 for(i=0, j=0; i < 6; i++)
543 if(i==3) /* second row */
545 j = weekday_width + separator_width;;
546 prev_line_height *= 2;
548 screens[s].getstringsize(ptr[i], &width, NULL);
549 cursor[i][INDEX_Y] = prev_line_height + statusbar_height;
550 cursor[i][INDEX_X] = j;
551 j += width + separator_width;
554 /* draw the screen */
555 screens[s].set_viewport(&vp[s]);
556 screens[s].clear_viewport();
557 /* display the screen title */
558 screens[s].puts_scroll(0, 0, title);
560 /* these are not selectable, so we draw them outside the loop */
561 /* name of the week day */
562 screens[s].putsxy(0, cursor[3][INDEX_Y],
563 str(LANG_WEEKDAY_SUNDAY + tm->tm_wday));
565 /* draw the selected item with drawmode set to
566 DRMODE_SOLID|DRMODE_INVERSEVID, all other selectable
567 items with drawmode DRMODE_SOLID */
568 for(i=0; i<6; i++)
570 if (cursorpos == (int)i)
571 vp[s].drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
573 screens[s].putsxy(cursor[i][INDEX_X],
574 cursor[i][INDEX_Y], ptr[i]);
576 vp[s].drawmode = DRMODE_SOLID;
578 screens[s].putsxy(cursor[i/4 +1][INDEX_X] - separator_width,
579 cursor[0][INDEX_Y], SEPARATOR);
582 /* print help text */
583 if (nb_lines > 4)
584 screens[s].puts(0, 4, str(LANG_TIME_SET_BUTTON));
585 if (nb_lines > 5)
586 screens[s].puts(0, 5, str(LANG_TIME_REVERT));
587 screens[s].update_viewport();
588 screens[s].set_viewport(NULL);
590 gui_syncstatusbar_draw(&statusbars, true);
592 /* set the most common numbers */
593 min = 0;
594 max = 59;
595 /* calculate the minimum and maximum for the number under cursor */
596 switch(cursorpos) {
597 case 0: /* hour */
598 max = 23;
599 valptr = &tm->tm_hour;
600 break;
601 case 1: /* minute */
602 valptr = &tm->tm_min;
603 break;
604 case 2: /* second */
605 valptr = &tm->tm_sec;
606 break;
607 case 3: /* year */
608 min = 1;
609 max = 200;
610 valptr = &tm->tm_year;
611 break;
612 case 4: /* month */
613 max = 11;
614 valptr = &tm->tm_mon;
615 break;
616 case 5: /* day */
617 min = 1;
618 max = daysinmonth[tm->tm_mon];
619 valptr = &tm->tm_mday;
620 break;
623 button = get_action(CONTEXT_SETTINGS_TIME, TIMEOUT_BLOCK);
624 switch ( button ) {
625 case ACTION_STD_PREV:
626 cursorpos = clamp_value_wrap(--cursorpos, 5, 0);
627 say_time(cursorpos, tm);
628 break;
629 case ACTION_STD_NEXT:
630 cursorpos = clamp_value_wrap(++cursorpos, 5, 0);
631 say_time(cursorpos, tm);
632 break;
633 case ACTION_SETTINGS_INC:
634 case ACTION_SETTINGS_INCREPEAT:
635 *valptr = clamp_value_wrap(++(*valptr), max, min);
636 say_time(cursorpos, tm);
637 break;
638 case ACTION_SETTINGS_DEC:
639 case ACTION_SETTINGS_DECREPEAT:
640 *valptr = clamp_value_wrap(--(*valptr), max, min);
641 say_time(cursorpos, tm);
642 break;
644 case ACTION_STD_OK:
645 done = true;
646 break;
648 case ACTION_STD_CANCEL:
649 done = true;
650 tm->tm_year = -1;
651 break;
653 default:
654 if (default_event_handler(button) == SYS_USB_CONNECTED)
655 return true;
656 break;
659 return false;
661 #endif /* defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0) */
663 #if (CONFIG_KEYPAD == RECORDER_PAD) && !defined(HAVE_SW_POWEROFF)
664 bool shutdown_screen(void)
666 int button;
667 bool done = false;
668 long time_entered = current_tick;
670 lcd_stop_scroll();
672 gui_syncsplash(0, str(LANG_CONFIRM_SHUTDOWN));
674 while(!done && TIME_BEFORE(current_tick,time_entered+HZ*2))
676 button = get_action(CONTEXT_STD,HZ);
677 switch(button)
679 case ACTION_STD_CANCEL:
680 sys_poweroff();
681 break;
683 /* do nothing here, because ACTION_NONE might be caused
684 * by timeout or button release. In case of timeout the loop
685 * is terminated by TIME_BEFORE */
686 case ACTION_NONE:
687 break;
689 default:
690 if(default_event_handler(button) == SYS_USB_CONNECTED)
691 return true;
692 done = true;
693 break;
696 return false;
698 #endif
700 static const int id3_headers[]=
702 LANG_ID3_TITLE,
703 LANG_ID3_ARTIST,
704 LANG_ID3_ALBUM,
705 LANG_ID3_ALBUMARTIST,
706 LANG_ID3_GROUPING,
707 LANG_ID3_DISCNUM,
708 LANG_ID3_TRACKNUM,
709 LANG_ID3_COMMENT,
710 LANG_ID3_GENRE,
711 LANG_ID3_YEAR,
712 LANG_ID3_LENGTH,
713 LANG_ID3_PLAYLIST,
714 LANG_ID3_BITRATE,
715 LANG_ID3_FREQUENCY,
716 #if CONFIG_CODEC == SWCODEC
717 LANG_ID3_TRACK_GAIN,
718 LANG_ID3_ALBUM_GAIN,
719 #endif
720 LANG_ID3_PATH,
723 static char * id3_get_info(int selected_item, void* data,
724 char *buffer, size_t buffer_len)
726 struct mp3entry* id3 =(struct mp3entry*)data;
727 int info_no=selected_item/2;
728 if(!(selected_item%2))
729 {/* header */
730 return( str(id3_headers[info_no]));
732 else
733 {/* data */
735 char * info=NULL;
736 switch(info_no)
738 case 0:/*LANG_ID3_TITLE*/
739 info=id3->title;
740 break;
741 case 1:/*LANG_ID3_ARTIST*/
742 info=id3->artist;
743 break;
744 case 2:/*LANG_ID3_ALBUM*/
745 info=id3->album;
746 break;
747 case 3:/*LANG_ID3_ALBUMARTIST*/
748 info=id3->albumartist;
749 break;
750 case 4:/*LANG_ID3_GROUPING*/
751 info=id3->grouping;
752 break;
753 case 5:/*LANG_ID3_DISCNUM*/
754 if (id3->disc_string)
755 info = id3->disc_string;
756 else if (id3->discnum)
758 snprintf(buffer, buffer_len, "%d", id3->discnum);
759 info = buffer;
761 break;
762 case 6:/*LANG_ID3_TRACKNUM*/
763 if (id3->track_string)
764 info = id3->track_string;
765 else if (id3->tracknum)
767 snprintf(buffer, buffer_len, "%d", id3->tracknum);
768 info = buffer;
770 break;
771 case 7:/*LANG_ID3_COMMENT*/
772 info=id3->comment;
773 break;
774 case 8:/*LANG_ID3_GENRE*/
775 info = id3->genre_string;
776 break;
777 case 9:/*LANG_ID3_YEAR*/
778 if (id3->year_string)
779 info = id3->year_string;
780 else if (id3->year)
782 snprintf(buffer, buffer_len, "%d", id3->year);
783 info = buffer;
785 break;
786 case 10:/*LANG_ID3_LENGTH*/
787 format_time(buffer, buffer_len, id3->length);
788 info=buffer;
789 break;
790 case 11:/*LANG_ID3_PLAYLIST*/
791 snprintf(buffer, buffer_len, "%d/%d",
792 playlist_get_display_index(), playlist_amount());
793 info=buffer;
794 break;
795 case 12:/*LANG_ID3_BITRATE*/
796 snprintf(buffer, buffer_len, "%d kbps%s", id3->bitrate,
797 id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) "");
798 info=buffer;
799 break;
800 case 13:/*LANG_ID3_FREQUENCY*/
801 snprintf(buffer, buffer_len, "%ld Hz", id3->frequency);
802 info=buffer;
803 break;
804 #if CONFIG_CODEC == SWCODEC
805 case 14:/*LANG_ID3_TRACK_GAIN*/
806 info=id3->track_gain_string;
807 break;
808 case 15:/*LANG_ID3_ALBUM_GAIN*/
809 info=id3->album_gain_string;
810 break;
811 case 16:/*LANG_ID3_PATH*/
812 #else
813 case 14:/*LANG_ID3_PATH*/
814 #endif
815 info=id3->path;
816 break;
818 return info && *info ? info : (char*) str(LANG_ID3_NO_INFO);
822 bool browse_id3(void)
824 struct gui_synclist id3_lists;
825 struct mp3entry* id3 = audio_current_track();
826 int key;
828 gui_synclist_init(&id3_lists, &id3_get_info, id3, true, 2, NULL);
829 gui_synclist_set_nb_items(&id3_lists,
830 sizeof(id3_headers)/sizeof(id3_headers[0])*2);
831 gui_synclist_draw(&id3_lists);
832 gui_syncstatusbar_draw(&statusbars, true);
833 while (true) {
834 gui_syncstatusbar_draw(&statusbars, false);
835 key = get_action(CONTEXT_LIST,HZ/2);
836 if(key!=ACTION_NONE && key!=ACTION_UNKNOWN
837 && !gui_synclist_do_button(&id3_lists, &key,LIST_WRAP_UNLESS_HELD))
839 return(default_event_handler(key) == SYS_USB_CONNECTED);
844 static char* runtime_get_data(int selected_item, void* data,
845 char* buffer, size_t buffer_len)
847 (void)data;
848 unsigned char *headers[] = {str(LANG_RUNNING_TIME), str(LANG_TOP_TIME) };
849 int t;
850 if(!(selected_item%2))
851 return headers[selected_item/2];
853 if(selected_item/2)
854 t = global_status.topruntime;
856 else t = global_status.runtime;
858 snprintf(buffer, buffer_len, "%dh %dm %ds",
859 t / 3600, (t % 3600) / 60, t % 60);
860 return buffer;
863 static int runtime_speak_data(int selected_item, void* data)
865 (void) data;
866 long title_ids[] = {LANG_RUNNING_TIME, LANG_TOP_TIME};
867 talk_ids(false,
868 title_ids[selected_item/2],
869 TALK_ID((selected_item == 0) ? global_status.runtime
870 : global_status.topruntime, UNIT_TIME));
871 return 0;
875 bool view_runtime(void)
877 static const char *lines[]={ID2P(LANG_CLEAR_TIME)};
878 static const struct text_message message={lines, 1};
880 struct gui_synclist lists;
881 int action;
882 gui_synclist_init(&lists, runtime_get_data, NULL, false, 2, NULL);
883 #if !defined(HAVE_LCD_CHARCELLS)
884 gui_synclist_set_title(&lists, str(LANG_RUNNING_TIME), NOICON);
885 #else
886 gui_synclist_set_title(&lists, NULL, NOICON);
887 #endif
888 if(global_settings.talk_menu)
889 gui_synclist_set_voice_callback(&lists, runtime_speak_data);
890 gui_synclist_set_icon_callback(&lists, NULL);
891 gui_synclist_set_nb_items(&lists, 4);
892 gui_synclist_speak_item(&lists);
893 while(1)
895 #if CONFIG_CHARGING
896 if (charger_inserted()
897 #ifdef HAVE_USB_POWER
898 || usb_powered()
899 #endif
902 global_status.runtime = 0;
904 else
905 #endif
907 global_status.runtime += ((current_tick - lasttime) / HZ);
909 lasttime = current_tick;
910 gui_synclist_draw(&lists);
911 gui_syncstatusbar_draw(&statusbars, true);
912 list_do_action(CONTEXT_STD, HZ,
913 &lists, &action, LIST_WRAP_UNLESS_HELD);
914 if(action == ACTION_STD_CANCEL)
915 break;
916 if(action == ACTION_STD_OK) {
917 if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
919 if (!(gui_synclist_get_sel_pos(&lists)/2))
920 global_status.runtime = 0;
921 else
922 global_status.topruntime = 0;
923 gui_synclist_speak_item(&lists);
926 if(default_event_handler(action) == SYS_USB_CONNECTED)
927 return true;
929 return false;