rockbox/apps/screens.c
Daniel Stenberg 2acc0ac542 Updated our source code header to explicitly mention that we are GPL v2 or
later. We still need to hunt down snippets used that are not. 1324 modified
files...
http://www.rockbox.org/mail/archive/rockbox-dev-archive-2008-06/0060.shtml


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17847 a1c6a512-1295-4272-9138-f99709370657
2008-06-28 18:10:04 +00:00

930 lines
27 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 Björn Stenberg
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include "backlight.h"
#include "action.h"
#include "lcd.h"
#ifdef HAVE_REMOTE_LCD
#include "lcd-remote.h"
#endif
#include "lang.h"
#include "icons.h"
#include "font.h"
#include "audio.h"
#include "mp3_playback.h"
#include "usb.h"
#include "settings.h"
#include "status.h"
#include "playlist.h"
#include "sprintf.h"
#include "kernel.h"
#include "power.h"
#include "system.h"
#include "powermgmt.h"
#include "adc.h"
#include "action.h"
#include "talk.h"
#include "misc.h"
#include "id3.h"
#include "screens.h"
#include "debug.h"
#include "led.h"
#include "sound.h"
#include "splash.h"
#include "statusbar.h"
#include "screen_access.h"
#include "pcmbuf.h"
#include "list.h"
#include "yesno.h"
#include "backdrop.h"
#include "viewport.h"
#ifdef HAVE_LCD_BITMAP
#include <bitmaps/usblogo.h>
#endif
#ifdef HAVE_REMOTE_LCD
#include <bitmaps/remote_usblogo.h>
#endif
#ifdef HAVE_MMC
#include "ata_mmc.h"
#endif
#if CONFIG_CODEC == SWCODEC
#include "dsp.h"
#endif
#ifdef HAVE_LCD_BITMAP
#define SCROLLBAR_WIDTH 6
#endif
/* only used in set_time screen */
#if defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0)
static int clamp_value_wrap(int value, int max, int min)
{
if (value > max)
return min;
if (value < min)
return max;
return value;
}
#endif
void usb_screen(void)
{
#ifdef USB_NONE
/* nothing here! */
#else
int i;
bool statusbar = global_settings.statusbar; /* force the statusbar */
global_settings.statusbar = true;
#if LCD_DEPTH > 1
show_main_backdrop();
#endif
#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
show_remote_main_backdrop();
#endif
FOR_NB_SCREENS(i)
{
screens[i].backlight_on();
screens[i].clear_display();
#if NB_SCREENS > 1
if (i == SCREEN_REMOTE)
{
screens[i].bitmap(remote_usblogo,
(LCD_REMOTE_WIDTH-BMPWIDTH_remote_usblogo),
(LCD_REMOTE_HEIGHT-BMPHEIGHT_remote_usblogo)/2,
BMPWIDTH_remote_usblogo, BMPHEIGHT_remote_usblogo);
}
else
{
#endif
#ifdef HAVE_LCD_BITMAP
screens[i].transparent_bitmap(usblogo,
(LCD_WIDTH-BMPWIDTH_usblogo),
(LCD_HEIGHT-BMPHEIGHT_usblogo)/2,
BMPWIDTH_usblogo, BMPHEIGHT_usblogo);
#else
screens[i].double_height(false);
screens[i].puts_scroll(0, 0, "[USB Mode]");
status_set_param(false);
status_set_audio(false);
status_set_usb(true);
#endif /* HAVE_LCD_BITMAP */
#if NB_SCREENS > 1
}
#endif
screens[i].update();
}
gui_syncstatusbar_draw(&statusbars, true);
#ifdef SIMULATOR
while (button_get(true) & BUTTON_REL);
#else
usb_acknowledge(SYS_USB_CONNECTED_ACK);
while(usb_wait_for_disconnect_w_tmo(&button_queue, HZ)) {
if(usb_inserted()) {
#ifdef HAVE_MMC /* USB-MMC bridge can report activity */
led(mmc_usb_active(HZ));
#endif /* HAVE_MMC */
gui_syncstatusbar_draw(&statusbars, false);
}
}
#endif /* SIMULATOR */
#ifdef HAVE_LCD_CHARCELLS
status_set_usb(false);
#endif /* HAVE_LCD_CHARCELLS */
FOR_NB_SCREENS(i)
screens[i].backlight_on();
global_settings.statusbar = statusbar;
#endif /* USB_NONE */
}
#ifdef HAVE_MMC
int mmc_remove_request(void)
{
struct queue_event ev;
int i;
FOR_NB_SCREENS(i)
screens[i].clear_display();
gui_syncsplash(1, str(LANG_REMOVE_MMC));
if (global_settings.talk_menu)
talk_id(LANG_REMOVE_MMC, false);
while (1)
{
queue_wait_w_tmo(&button_queue, &ev, HZ/2);
switch (ev.id)
{
case SYS_HOTSWAP_EXTRACTED:
return SYS_HOTSWAP_EXTRACTED;
case SYS_USB_DISCONNECTED:
return SYS_USB_DISCONNECTED;
}
}
}
#endif
/* the charging screen is only used for archos targets */
#if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) && defined(CPU_SH)
#ifdef HAVE_LCD_BITMAP
static void charging_display_info(bool animate)
{
unsigned char charging_logo[36];
const int pox_x = (LCD_WIDTH - sizeof(charging_logo)) / 2;
const int pox_y = 32;
static unsigned phase = 3;
unsigned i;
char buf[32];
(void)buf;
#ifdef NEED_ATA_POWER_BATT_MEASURE
if (ide_powered()) /* FM and V2 can only measure when ATA power is on */
#endif
{
int battv = battery_voltage();
snprintf(buf, 32, " Batt: %d.%02dV %d%% ", battv / 1000,
(battv % 1000) / 10, battery_level());
lcd_puts(0, 7, buf);
}
#if CONFIG_CHARGING == CHARGING_CONTROL
snprintf(buf, 32, "Charge mode:");
lcd_puts(0, 2, buf);
if (charge_state == CHARGING)
snprintf(buf, 32, str(LANG_BATTERY_CHARGE));
else if (charge_state == TOPOFF)
snprintf(buf, 32, str(LANG_BATTERY_TOPOFF_CHARGE));
else if (charge_state == TRICKLE)
snprintf(buf, 32, str(LANG_BATTERY_TRICKLE_CHARGE));
else
snprintf(buf, 32, "not charging");
lcd_puts(0, 3, buf);
if (!charger_enabled)
animate = false;
#endif /* CONFIG_CHARGING == CHARGING_CONTROL */
/* middle part */
memset(charging_logo+3, 0x00, 32);
charging_logo[0] = 0x3C;
charging_logo[1] = 0x24;
charging_logo[2] = charging_logo[35] = 0xFF;
if (!animate)
{ /* draw the outline */
/* middle part */
lcd_mono_bitmap(charging_logo, pox_x, pox_y + 8,
sizeof(charging_logo), 8);
lcd_set_drawmode(DRMODE_FG);
/* upper line */
charging_logo[0] = charging_logo[1] = 0x00;
memset(charging_logo+2, 0x80, 34);
lcd_mono_bitmap(charging_logo, pox_x, pox_y, sizeof(charging_logo), 8);
/* lower line */
memset(charging_logo+2, 0x01, 34);
lcd_mono_bitmap(charging_logo, pox_x, pox_y + 16,
sizeof(charging_logo), 8);
lcd_set_drawmode(DRMODE_SOLID);
}
else
{ /* animate the middle part */
for (i = 3; i<MIN(sizeof(charging_logo)-1, phase); i++)
{
if ((i-phase) % 8 == 0)
{ /* draw a "bubble" here */
unsigned bitpos;
bitpos = (phase + i/8) % 15; /* "bounce" effect */
if (bitpos > 7)
bitpos = 14 - bitpos;
charging_logo[i] = 0x01 << bitpos;
}
}
lcd_mono_bitmap(charging_logo, pox_x, pox_y + 8,
sizeof(charging_logo), 8);
phase++;
}
lcd_update();
}
#else /* not HAVE_LCD_BITMAP */
static unsigned long logo_chars[4];
static const unsigned char logo_pattern[] = {
0x07, 0x04, 0x1c, 0x14, 0x1c, 0x04, 0x07, 0, /* char 1 */
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0, /* char 2 */
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0, /* char 3 */
0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1f, 0, /* char 4 */
};
static void logo_lock_patterns(bool on)
{
int i;
if (on)
{
for (i = 0; i < 4; i++)
logo_chars[i] = lcd_get_locked_pattern();
}
else
{
for (i = 0; i < 4; i++)
lcd_unlock_pattern(logo_chars[i]);
}
}
static void charging_display_info(bool animate)
{
int battv;
unsigned i, ypos;
static unsigned phase = 3;
char buf[32];
battv = battery_voltage();
snprintf(buf, sizeof(buf), " %d.%02dV", battv / 1000, (battv % 1000) / 10);
lcd_puts(4, 1, buf);
memcpy(buf, logo_pattern, 32); /* copy logo patterns */
if (!animate) /* build the screen */
{
lcd_double_height(false);
lcd_puts(0, 0, "[Charging]");
for (i = 0; i < 4; i++)
lcd_putc(i, 1, logo_chars[i]);
}
else /* animate the logo */
{
for (i = 3; i < MIN(19, phase); i++)
{
if ((i - phase) % 5 == 0)
{ /* draw a "bubble" here */
ypos = (phase + i/5) % 9; /* "bounce" effect */
if (ypos > 4)
ypos = 8 - ypos;
buf[5 - ypos + 8 * (i/5)] |= 0x10 >> (i%5);
}
}
phase++;
}
for (i = 0; i < 4; i++)
lcd_define_pattern(logo_chars[i], buf + 8 * i);
lcd_update();
}
#endif /* (not) HAVE_LCD_BITMAP */
/* blocks while charging, returns on event:
1 if charger cable was removed
2 if Off/Stop key was pressed
3 if On key was pressed
4 if USB was connected */
int charging_screen(void)
{
unsigned int button;
int rc = 0;
ide_power_enable(false); /* power down the disk, else would be spinning */
lcd_clear_display();
backlight_set_timeout(global_settings.backlight_timeout);
#ifdef HAVE_REMOTE_LCD
remote_backlight_set_timeout(global_settings.remote_backlight_timeout);
#endif
backlight_set_timeout_plugged(global_settings.backlight_timeout_plugged);
gui_syncstatusbar_draw(&statusbars, true);
#ifdef HAVE_LCD_CHARCELLS
logo_lock_patterns(true);
#endif
charging_display_info(false);
do
{
gui_syncstatusbar_draw(&statusbars, false);
charging_display_info(true);
button = get_action(CONTEXT_STD,HZ/3);
if (button == ACTION_STD_OK)
rc = 2;
else if (usb_detect())
rc = 3;
else if (!charger_inserted())
rc = 1;
} while (!rc);
#ifdef HAVE_LCD_CHARCELLS
logo_lock_patterns(false);
#endif
return rc;
}
#endif /* CONFIG_CHARGING && !HAVE_POWEROFF_WHILE_CHARGING && defined(CPU_SH) */
#if CONFIG_CHARGING
void charging_splash(void)
{
gui_syncsplash(2*HZ, (unsigned char *)str(LANG_BATTERY_CHARGE));
button_clear_queue();
}
#endif
#if defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0)
/* little helper function for voice output */
static void say_time(int cursorpos, const struct tm *tm)
{
int value = 0;
int unit = 0;
if (!global_settings.talk_menu)
return;
switch(cursorpos)
{
case 0:
value = tm->tm_hour;
unit = UNIT_HOUR;
break;
case 1:
value = tm->tm_min;
unit = UNIT_MIN;
break;
case 2:
value = tm->tm_sec;
unit = UNIT_SEC;
break;
case 3:
value = tm->tm_year + 1900;
break;
case 5:
value = tm->tm_mday;
break;
}
if (cursorpos == 4) /* month */
talk_id(LANG_MONTH_JANUARY + tm->tm_mon, false);
else
talk_value(value, unit, false);
}
#define INDEX_X 0
#define INDEX_Y 1
#define SEPARATOR ":"
bool set_time_screen(const char* title, struct tm *tm)
{
bool done = false;
int button;
unsigned int i, j, s;
int cursorpos = 0;
unsigned int julianday;
unsigned int realyear;
unsigned int width;
unsigned int min, max;
unsigned int statusbar_height = 0;
unsigned int separator_width, weekday_width;
unsigned int prev_line_height;
int daysinmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
unsigned char buffer[20];
struct viewport vp[NB_SCREENS];
int nb_lines;
/* 6 possible cursor possitions, 2 values stored for each: x, y */
unsigned int cursor[6][2];
int *valptr = NULL;
unsigned char *ptr[6];
if(global_settings.statusbar)
statusbar_height = STATUSBAR_HEIGHT;
/* speak selection when screen is entered */
say_time(cursorpos, tm);
while (!done) {
/* for easy acess in the drawing loop */
ptr[0] = buffer; /* hours */
ptr[1] = buffer + 3; /* minutes */
ptr[2] = buffer + 6; /* seconds */
ptr[3] = buffer + 9; /* year */
ptr[4] = str(LANG_MONTH_JANUARY + tm->tm_mon); /* monthname */
ptr[5] = buffer + 14; /* day of month */
/* calculate the number of days in febuary */
realyear = tm->tm_year + 1900;
if((realyear % 4 == 0 && !(realyear % 100 == 0)) || realyear % 400 == 0)
daysinmonth[1] = 29;
else
daysinmonth[1] = 28;
/* fix day if month or year changed */
if (tm->tm_mday > daysinmonth[tm->tm_mon])
tm->tm_mday = daysinmonth[tm->tm_mon];
/* calculate day of week */
julianday = tm->tm_mday;
for(i = 0; (int)i < tm->tm_mon; i++) {
julianday += daysinmonth[i];
}
tm->tm_wday = (realyear + julianday + (realyear - 1) / 4 -
(realyear - 1) / 100 + (realyear - 1) / 400 + 7 - 1) % 7;
/* put all the numbers we want from the tm struct into
an easily printable buffer */
snprintf(buffer, sizeof(buffer),
"%02d " "%02d " "%02d " "%04d " "%02d",
tm->tm_hour, tm->tm_min, tm->tm_sec,
tm->tm_year+1900, tm->tm_mday);
/* convert spaces in the buffer to '\0' to make it possible to work
directly on the buffer */
for(i=0; i < sizeof(buffer); i++)
{
if(buffer[i] == ' ')
buffer[i] = '\0';
}
FOR_NB_SCREENS(s)
{
viewport_set_defaults(&vp[s], s);
nb_lines = viewport_get_nb_lines(&vp[s]);
/* minimum lines needed is 2 + title line */
if (nb_lines < 4)
{
vp[s].font = FONT_SYSFIXED;
nb_lines = viewport_get_nb_lines(&vp[s]);
}
/* recalculate the positions and offsets */
if (nb_lines >= 3)
screens[s].getstringsize(title, NULL, &prev_line_height);
else
prev_line_height = 0;
screens[s].getstringsize(SEPARATOR, &separator_width, NULL);
/* weekday */
screens[s].getstringsize(str(LANG_WEEKDAY_SUNDAY + tm->tm_wday),
&weekday_width, NULL);
screens[s].getstringsize(" ", &separator_width, NULL);
for(i=0, j=0; i < 6; i++)
{
if(i==3) /* second row */
{
j = weekday_width + separator_width;;
prev_line_height *= 2;
}
screens[s].getstringsize(ptr[i], &width, NULL);
cursor[i][INDEX_Y] = prev_line_height + statusbar_height;
cursor[i][INDEX_X] = j;
j += width + separator_width;
}
/* draw the screen */
screens[s].set_viewport(&vp[s]);
screens[s].clear_viewport();
/* display the screen title */
screens[s].puts_scroll(0, 0, title);
/* these are not selectable, so we draw them outside the loop */
/* name of the week day */
screens[s].putsxy(0, cursor[3][INDEX_Y],
str(LANG_WEEKDAY_SUNDAY + tm->tm_wday));
/* draw the selected item with drawmode set to
DRMODE_SOLID|DRMODE_INVERSEVID, all other selectable
items with drawmode DRMODE_SOLID */
for(i=0; i<6; i++)
{
if (cursorpos == (int)i)
vp[s].drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
screens[s].putsxy(cursor[i][INDEX_X],
cursor[i][INDEX_Y], ptr[i]);
vp[s].drawmode = DRMODE_SOLID;
screens[s].putsxy(cursor[i/4 +1][INDEX_X] - separator_width,
cursor[0][INDEX_Y], SEPARATOR);
}
/* print help text */
if (nb_lines > 4)
screens[s].puts(0, 4, str(LANG_TIME_SET_BUTTON));
if (nb_lines > 5)
screens[s].puts(0, 5, str(LANG_TIME_REVERT));
screens[s].update_viewport();
screens[s].set_viewport(NULL);
}
gui_syncstatusbar_draw(&statusbars, true);
/* set the most common numbers */
min = 0;
max = 59;
/* calculate the minimum and maximum for the number under cursor */
switch(cursorpos) {
case 0: /* hour */
max = 23;
valptr = &tm->tm_hour;
break;
case 1: /* minute */
valptr = &tm->tm_min;
break;
case 2: /* second */
valptr = &tm->tm_sec;
break;
case 3: /* year */
min = 1;
max = 200;
valptr = &tm->tm_year;
break;
case 4: /* month */
max = 11;
valptr = &tm->tm_mon;
break;
case 5: /* day */
min = 1;
max = daysinmonth[tm->tm_mon];
valptr = &tm->tm_mday;
break;
}
button = get_action(CONTEXT_SETTINGS_TIME, TIMEOUT_BLOCK);
switch ( button ) {
case ACTION_STD_PREV:
cursorpos = clamp_value_wrap(--cursorpos, 5, 0);
say_time(cursorpos, tm);
break;
case ACTION_STD_NEXT:
cursorpos = clamp_value_wrap(++cursorpos, 5, 0);
say_time(cursorpos, tm);
break;
case ACTION_SETTINGS_INC:
case ACTION_SETTINGS_INCREPEAT:
*valptr = clamp_value_wrap(++(*valptr), max, min);
say_time(cursorpos, tm);
break;
case ACTION_SETTINGS_DEC:
case ACTION_SETTINGS_DECREPEAT:
*valptr = clamp_value_wrap(--(*valptr), max, min);
say_time(cursorpos, tm);
break;
case ACTION_STD_OK:
done = true;
break;
case ACTION_STD_CANCEL:
done = true;
tm->tm_year = -1;
break;
default:
if (default_event_handler(button) == SYS_USB_CONNECTED)
return true;
break;
}
}
return false;
}
#endif /* defined(HAVE_LCD_BITMAP) && (CONFIG_RTC != 0) */
#if (CONFIG_KEYPAD == RECORDER_PAD) && !defined(HAVE_SW_POWEROFF)
bool shutdown_screen(void)
{
int button;
bool done = false;
long time_entered = current_tick;
lcd_stop_scroll();
gui_syncsplash(0, str(LANG_CONFIRM_SHUTDOWN));
while(!done && TIME_BEFORE(current_tick,time_entered+HZ*2))
{
button = get_action(CONTEXT_STD,HZ);
switch(button)
{
case ACTION_STD_CANCEL:
sys_poweroff();
break;
/* do nothing here, because ACTION_NONE might be caused
* by timeout or button release. In case of timeout the loop
* is terminated by TIME_BEFORE */
case ACTION_NONE:
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
return true;
done = true;
break;
}
}
return false;
}
#endif
static const int id3_headers[]=
{
LANG_ID3_TITLE,
LANG_ID3_ARTIST,
LANG_ID3_ALBUM,
LANG_ID3_ALBUMARTIST,
LANG_ID3_GROUPING,
LANG_ID3_DISCNUM,
LANG_ID3_TRACKNUM,
LANG_ID3_COMMENT,
LANG_ID3_GENRE,
LANG_ID3_YEAR,
LANG_ID3_LENGTH,
LANG_ID3_PLAYLIST,
LANG_ID3_BITRATE,
LANG_ID3_FREQUENCY,
#if CONFIG_CODEC == SWCODEC
LANG_ID3_TRACK_GAIN,
LANG_ID3_ALBUM_GAIN,
#endif
LANG_ID3_PATH,
};
static char * id3_get_info(int selected_item, void* data,
char *buffer, size_t buffer_len)
{
struct mp3entry* id3 =(struct mp3entry*)data;
int info_no=selected_item/2;
if(!(selected_item%2))
{/* header */
return( str(id3_headers[info_no]));
}
else
{/* data */
char * info=NULL;
switch(info_no)
{
case 0:/*LANG_ID3_TITLE*/
info=id3->title;
break;
case 1:/*LANG_ID3_ARTIST*/
info=id3->artist;
break;
case 2:/*LANG_ID3_ALBUM*/
info=id3->album;
break;
case 3:/*LANG_ID3_ALBUMARTIST*/
info=id3->albumartist;
break;
case 4:/*LANG_ID3_GROUPING*/
info=id3->grouping;
break;
case 5:/*LANG_ID3_DISCNUM*/
if (id3->disc_string)
info = id3->disc_string;
else if (id3->discnum)
{
snprintf(buffer, buffer_len, "%d", id3->discnum);
info = buffer;
}
break;
case 6:/*LANG_ID3_TRACKNUM*/
if (id3->track_string)
info = id3->track_string;
else if (id3->tracknum)
{
snprintf(buffer, buffer_len, "%d", id3->tracknum);
info = buffer;
}
break;
case 7:/*LANG_ID3_COMMENT*/
info=id3->comment;
break;
case 8:/*LANG_ID3_GENRE*/
info = id3->genre_string;
break;
case 9:/*LANG_ID3_YEAR*/
if (id3->year_string)
info = id3->year_string;
else if (id3->year)
{
snprintf(buffer, buffer_len, "%d", id3->year);
info = buffer;
}
break;
case 10:/*LANG_ID3_LENGTH*/
format_time(buffer, buffer_len, id3->length);
info=buffer;
break;
case 11:/*LANG_ID3_PLAYLIST*/
snprintf(buffer, buffer_len, "%d/%d",
playlist_get_display_index(), playlist_amount());
info=buffer;
break;
case 12:/*LANG_ID3_BITRATE*/
snprintf(buffer, buffer_len, "%d kbps%s", id3->bitrate,
id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) "");
info=buffer;
break;
case 13:/*LANG_ID3_FREQUENCY*/
snprintf(buffer, buffer_len, "%ld Hz", id3->frequency);
info=buffer;
break;
#if CONFIG_CODEC == SWCODEC
case 14:/*LANG_ID3_TRACK_GAIN*/
info=id3->track_gain_string;
break;
case 15:/*LANG_ID3_ALBUM_GAIN*/
info=id3->album_gain_string;
break;
case 16:/*LANG_ID3_PATH*/
#else
case 14:/*LANG_ID3_PATH*/
#endif
info=id3->path;
break;
}
return info && *info ? info : (char*) str(LANG_ID3_NO_INFO);
}
}
bool browse_id3(void)
{
struct gui_synclist id3_lists;
struct mp3entry* id3 = audio_current_track();
int key;
gui_synclist_init(&id3_lists, &id3_get_info, id3, true, 2, NULL);
gui_synclist_set_nb_items(&id3_lists,
sizeof(id3_headers)/sizeof(id3_headers[0])*2);
gui_synclist_draw(&id3_lists);
gui_syncstatusbar_draw(&statusbars, true);
while (true) {
gui_syncstatusbar_draw(&statusbars, false);
key = get_action(CONTEXT_LIST,HZ/2);
if(key!=ACTION_NONE && key!=ACTION_UNKNOWN
&& !gui_synclist_do_button(&id3_lists, &key,LIST_WRAP_UNLESS_HELD))
{
return(default_event_handler(key) == SYS_USB_CONNECTED);
}
}
}
static char* runtime_get_data(int selected_item, void* data,
char* buffer, size_t buffer_len)
{
(void)data;
unsigned char *headers[] = {str(LANG_RUNNING_TIME), str(LANG_TOP_TIME) };
int t;
if(!(selected_item%2))
return headers[selected_item/2];
if(selected_item/2)
t = global_status.topruntime;
else t = global_status.runtime;
snprintf(buffer, buffer_len, "%dh %dm %ds",
t / 3600, (t % 3600) / 60, t % 60);
return buffer;
}
static int runtime_speak_data(int selected_item, void* data)
{
(void) data;
long title_ids[] = {LANG_RUNNING_TIME, LANG_TOP_TIME};
talk_ids(false,
title_ids[selected_item/2],
TALK_ID((selected_item == 0) ? global_status.runtime
: global_status.topruntime, UNIT_TIME));
return 0;
}
bool view_runtime(void)
{
static const char *lines[]={ID2P(LANG_CLEAR_TIME)};
static const struct text_message message={lines, 1};
struct gui_synclist lists;
int action;
gui_synclist_init(&lists, runtime_get_data, NULL, false, 2, NULL);
#if !defined(HAVE_LCD_CHARCELLS)
gui_synclist_set_title(&lists, str(LANG_RUNNING_TIME), NOICON);
#else
gui_synclist_set_title(&lists, NULL, NOICON);
#endif
if(global_settings.talk_menu)
gui_synclist_set_voice_callback(&lists, runtime_speak_data);
gui_synclist_set_icon_callback(&lists, NULL);
gui_synclist_set_nb_items(&lists, 4);
gui_synclist_speak_item(&lists);
while(1)
{
#if CONFIG_CHARGING
if (charger_inserted()
#ifdef HAVE_USB_POWER
|| usb_powered()
#endif
)
{
global_status.runtime = 0;
}
else
#endif
{
global_status.runtime += ((current_tick - lasttime) / HZ);
}
lasttime = current_tick;
gui_synclist_draw(&lists);
gui_syncstatusbar_draw(&statusbars, true);
list_do_action(CONTEXT_STD, HZ,
&lists, &action, LIST_WRAP_UNLESS_HELD);
if(action == ACTION_STD_CANCEL)
break;
if(action == ACTION_STD_OK) {
if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
{
if (!(gui_synclist_get_sel_pos(&lists)/2))
global_status.runtime = 0;
else
global_status.topruntime = 0;
gui_synclist_speak_item(&lists);
}
}
if(default_event_handler(action) == SYS_USB_CONNECTED)
return true;
}
return false;
}