rockbox/apps/screens.c

1180 lines
34 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 Bj<EFBFBD>n Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* 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"
#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 "gwps-common.h"
#include "splash.h"
#include "statusbar.h"
#include "screen_access.h"
#include "quickscreen.h"
#include "logo.h"
#include "pcmbuf.h"
#include "list.h"
#if defined(HAVE_LCD_BITMAP)
#include "widgets.h"
#endif
#ifdef HAVE_MMC
#include "ata_mmc.h"
#endif
#if CONFIG_CODEC == SWCODEC
#include "dsp.h"
#endif
#ifdef HAVE_LCD_COLOR
#include "backdrop.h"
#endif
#ifdef HAVE_LCD_BITMAP
#define SCROLLBAR_WIDTH 6
#endif
void usb_screen(void)
{
#ifdef USB_NONE
/* nothing here! */
#else
int i;
#ifdef HAVE_LCD_COLOR
show_main_backdrop();
#endif
FOR_NB_SCREENS(i) {
screens[i].backlight_on();
gui_logo_draw(&usb_logos[i], &screens[i]);
}
#ifdef HAVE_LCD_CHARCELLS
status_set_param(false);
status_set_audio(false);
status_set_usb(true);
#endif /* HAVE_LCD_BITMAP */
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();
#endif /* USB_NONE */
}
#ifdef HAVE_MMC
int mmc_remove_request(void)
{
struct event ev;
int i;
FOR_NB_SCREENS(i)
screens[i].clear_display();
gui_syncsplash(1, true, 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_MMC_EXTRACTED:
return SYS_MMC_EXTRACTED;
case SYS_USB_DISCONNECTED:
return SYS_USB_DISCONNECTED;
}
}
}
#endif
/* some simulator dummies */
#ifdef SIMULATOR
#define BATTERY_SCALE_FACTOR 7000
unsigned short adc_read(int channel)
{
(void)channel;
return 100;
}
#endif
#if defined(CONFIG_CHARGING) && !defined(HAVE_POWEROFF_WHILE_CHARGING)
#ifdef HAVE_LCD_BITMAP
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 battery_voltage;
int batt_int, batt_frac;
battery_voltage = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000;
batt_int = battery_voltage / 100;
batt_frac = battery_voltage % 100;
snprintf(buf, 32, " Batt: %d.%02dV %d%% ", batt_int, batt_frac,
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 char logo_chars[5];
static const unsigned char logo_pattern[] = {
0x07, 0x04, 0x1c, 0x14, 0x1c, 0x04, 0x07, /* char 1 */
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, /* char 2 */
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, /* char 3 */
0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1f, /* 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();
logo_chars[4] = '\0';
}
else
{
for (i = 0; i < 4; i++)
lcd_unlock_pattern(logo_chars[i]);
}
}
void charging_display_info(bool animate)
{
int battery_voltage;
unsigned i, ypos;
static unsigned phase = 3;
char buf[28];
battery_voltage = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR)
/ 10000;
snprintf(buf, sizeof(buf), "%s %d.%02dV", logo_chars,
battery_voltage / 100, battery_voltage % 100);
lcd_puts(0, 1, buf);
memcpy(buf, logo_pattern, 28); /* copy logo patterns */
if (!animate) /* build the screen */
{
lcd_double_height(false);
lcd_puts(0, 0, "[Charging]");
}
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 + 7 * (i/5)] |= 0x10 >> (i%5);
}
}
phase++;
}
for (i = 0; i < 4; i++)
lcd_define_pattern(logo_chars[i], buf + 7 * i);
}
#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
action_signalscreenchange();
return rc;
}
#endif /* CONFIG_CHARGING && !HAVE_POWEROFF_WHILE_CHARGING */
#ifdef HAVE_PITCHSCREEN
/* returns:
0 if no key was pressed
1 if USB was connected */
void pitch_screen_draw(int pitch)
{
unsigned char* ptr;
unsigned char buf[32];
int w, h;
lcd_clear_display();
/* UP: Pitch Up */
ptr = str(LANG_SYSFONT_PITCH_UP);
lcd_getstringsize(ptr,&w,&h);
lcd_putsxy((LCD_WIDTH-w)/2, 0, ptr);
lcd_mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
LCD_WIDTH/2 - 3, h, 7, 8);
/* DOWN: Pitch Down */
ptr = str(LANG_SYSFONT_PITCH_DOWN);
lcd_getstringsize(ptr,&w,&h);
lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
lcd_mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
LCD_WIDTH/2 - 3, LCD_HEIGHT - h*2, 7, 8);
/* RIGHT: +2% */
ptr = "+2%";
lcd_getstringsize(ptr,&w,&h);
lcd_putsxy(LCD_WIDTH-w, (LCD_HEIGHT-h)/2, ptr);
lcd_mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
LCD_WIDTH-w-8, (LCD_HEIGHT-h)/2, 7, 8);
/* LEFT: -2% */
ptr = "-2%";
lcd_getstringsize(ptr,&w,&h);
lcd_putsxy(0, (LCD_HEIGHT-h)/2, ptr);
lcd_mono_bitmap(bitmap_icons_7x8[Icon_FastBackward],
w+1, (LCD_HEIGHT-h)/2, 7, 8);
/* "Pitch" */
snprintf((char *)buf, sizeof(buf), str(LANG_SYSFONT_PITCH));
lcd_getstringsize(buf,&w,&h);
lcd_putsxy((LCD_WIDTH-w)/2, (LCD_HEIGHT/2)-h, buf);
/* "XX.X%" */
snprintf((char *)buf, sizeof(buf), "%d.%d%%",
pitch / 10, pitch % 10 );
lcd_getstringsize(buf,&w,&h);
lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT/2, buf);
lcd_update();
}
bool pitch_screen(void)
{
int button;
int pitch = sound_get_pitch();
bool exit = false;
lcd_setfont(FONT_SYSFIXED);
#if CONFIG_CODEC == SWCODEC
pcmbuf_set_low_latency(true);
#endif
action_signalscreenchange();
while (!exit)
{
pitch_screen_draw(pitch);
button = get_action(CONTEXT_PITCHSCREEN,TIMEOUT_BLOCK);
switch (button) {
case ACTION_PS_INC_SMALL:
if ( pitch < 2000 )
pitch++;
sound_set_pitch(pitch);
break;
case ACTION_PS_INC_BIG:
if ( pitch < 1990 )
pitch += 10;
else
pitch = 2000;
sound_set_pitch(pitch);
break;
case ACTION_PS_DEC_SMALL:
if ( pitch > 500 )
pitch--;
sound_set_pitch(pitch);
break;
case ACTION_PS_DEC_BIG:
if ( pitch > 510 )
pitch -= 10;
else
pitch = 500;
sound_set_pitch(pitch);
break;
case ACTION_PS_NUDGE_RIGHT:
if ( pitch < 1980 )
{
pitch += 20;
sound_set_pitch(pitch);
pitch_screen_draw(pitch);
}
break;
case ACTION_PS_NUDGE_RIGHTOFF:
pitch -= 20;
sound_set_pitch(pitch);
break;
case ACTION_PS_NUDGE_LEFT:
if ( pitch > 520 )
{
pitch -= 20;
sound_set_pitch(pitch);
pitch_screen_draw(pitch);
}
break;
case ACTION_PS_NUDGE_LEFTOFF:
pitch += 20;
sound_set_pitch(pitch);
break;
case ACTION_PS_RESET:
pitch = 1000;
sound_set_pitch( pitch );
break;
case ACTION_PS_EXIT:
exit = true;
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
return 1;
break;
}
}
#if CONFIG_CODEC == SWCODEC
pcmbuf_set_low_latency(false);
#endif
lcd_setfont(FONT_UI);
action_signalscreenchange();
return 0;
}
#endif /* HAVE_PITCHSCREEN */
#ifdef HAVE_QUICKSCREEN
#define bool_to_int(b)\
b?1:0
#define int_to_bool(i)\
i==0?false:true
void quick_screen_quick_apply(struct gui_quickscreen *qs)
{
global_settings.playlist_shuffle=int_to_bool(qs->left_option->option);
global_settings.dirfilter=qs->bottom_option->option;
global_settings.repeat_mode=qs->right_option->option;
}
bool quick_screen_quick(int button_enter)
{
bool res, oldshuffle;
struct option_select left_option;
struct option_select bottom_option;
struct option_select right_option;
int oldrepeat, old_x_margin, old_y_margin;
static const struct opt_items left_items[] = {
[0]={ STR(LANG_SYSFONT_OFF) },
[1]={ STR(LANG_SYSFONT_ON) }
};
static const struct opt_items bottom_items[] = {
[SHOW_ALL]={ STR(LANG_SYSFONT_FILTER_ALL) },
[SHOW_SUPPORTED]={ STR(LANG_SYSFONT_FILTER_SUPPORTED) },
[SHOW_MUSIC]={ STR(LANG_SYSFONT_FILTER_MUSIC) },
[SHOW_PLAYLIST]={ STR(LANG_SYSFONT_FILTER_PLAYLIST) },
[SHOW_ID3DB]={ STR(LANG_SYSFONT_FILTER_ID3DB) }
};
static const struct opt_items right_items[] = {
[REPEAT_OFF]={ STR(LANG_SYSFONT_OFF) },
[REPEAT_ALL]={ STR(LANG_SYSFONT_REPEAT_ALL) },
[REPEAT_ONE]={ STR(LANG_SYSFONT_REPEAT_ONE) },
[REPEAT_SHUFFLE]={ STR(LANG_SYSFONT_SHUFFLE) },
#if (AB_REPEAT_ENABLE == 1)
[REPEAT_AB]={ STR(LANG_SYSFONT_REPEAT_AB) }
#endif
};
struct gui_quickscreen qs;
old_x_margin = lcd_getxmargin();
old_y_margin = lcd_getymargin();
lcd_setmargins(0, 0);
option_select_init_items(&left_option,
(char *)str(LANG_SYSFONT_SHUFFLE),
bool_to_int(global_settings.playlist_shuffle),
left_items,
2);
option_select_init_items(&bottom_option,
(char *)str(LANG_SYSFONT_FILTER),
global_settings.dirfilter,
bottom_items,
sizeof(bottom_items)/sizeof(struct opt_items));
option_select_init_items(&right_option,
(char *)str(LANG_SYSFONT_REPEAT),
global_settings.repeat_mode,
right_items,
sizeof(right_items)/sizeof(struct opt_items));
gui_quickscreen_init(&qs, &left_option, &bottom_option, &right_option,
&quick_screen_quick_apply);
oldrepeat=global_settings.repeat_mode;
oldshuffle=global_settings.playlist_shuffle;
res=gui_syncquickscreen_run(&qs, button_enter);
if(!res)
{
if ( oldrepeat != global_settings.repeat_mode &&
(audio_status() & AUDIO_STATUS_PLAY) )
audio_flush_and_reload_tracks();
if(oldshuffle != global_settings.playlist_shuffle
&& audio_status() & AUDIO_STATUS_PLAY)
{
#if CONFIG_CODEC == SWCODEC
dsp_set_replaygain(true);
#endif
if (global_settings.playlist_shuffle)
playlist_randomise(NULL, current_tick, true);
else
playlist_sort(NULL, true);
}
settings_save();
}
lcd_setmargins(old_x_margin, old_y_margin);
return(res);
}
#ifdef BUTTON_F3
void quick_screen_f3_apply(struct gui_quickscreen *qs)
{
global_settings.scrollbar=int_to_bool(qs->left_option->option);
global_settings.flip_display=int_to_bool(qs->bottom_option->option);
button_set_flip(global_settings.flip_display);
lcd_set_flip(global_settings.flip_display);
global_settings.statusbar=int_to_bool(qs->right_option->option);
gui_syncstatusbar_draw(&statusbars, true);
}
bool quick_screen_f3(int button_enter)
{
bool res;
struct option_select left_option;
struct option_select bottom_option;
struct option_select right_option;
int old_x_margin, old_y_margin;
static const struct opt_items onoff_items[] = {
[0]={ STR(LANG_SYSFONT_OFF) },
[1]={ STR(LANG_SYSFONT_ON) }
};
static const struct opt_items yesno_items[] = {
[0]={ STR(LANG_SYSFONT_SET_BOOL_NO) },
[1]={ STR(LANG_SYSFONT_SET_BOOL_YES) }
};
struct gui_quickscreen qs;
old_x_margin = lcd_getxmargin();
old_y_margin = lcd_getymargin();
lcd_setmargins(0, 0);
option_select_init_items(&left_option,
str(LANG_SYSFONT_SCROLL_BAR),
bool_to_int(global_settings.scrollbar),
onoff_items,
2);
option_select_init_items(&bottom_option,
str(LANG_SYSFONT_FLIP_DISPLAY),
bool_to_int(global_settings.flip_display),
yesno_items,
2);
option_select_init_items(&right_option,
str(LANG_SYSFONT_STATUS_BAR),
bool_to_int(global_settings.statusbar),
onoff_items,
2);
gui_quickscreen_init(&qs, &left_option, &bottom_option, &right_option,
&quick_screen_f3_apply);
res=gui_syncquickscreen_run(&qs, button_enter);
if(!res)
settings_save();
lcd_setmargins(old_x_margin, old_y_margin);
return(res);
}
#endif /* BUTTON_F3 */
#endif /* CONFIG_KEYPAD in (RECORDER_PAD |IRIVER_H100_PAD | IRIVER_H300_PAD) */
#if defined(CONFIG_CHARGING) || defined(SIMULATOR)
void charging_splash(void)
{
gui_syncsplash(2*HZ, true, (unsigned char *)str(LANG_BATTERY_CHARGE));
button_clear_queue();
}
#endif
#if defined(HAVE_LCD_BITMAP) && defined (CONFIG_RTC)
const int dayname[] = {
LANG_WEEKDAY_SUNDAY,
LANG_WEEKDAY_MONDAY,
LANG_WEEKDAY_TUESDAY,
LANG_WEEKDAY_WEDNESDAY,
LANG_WEEKDAY_THURSDAY,
LANG_WEEKDAY_FRIDAY,
LANG_WEEKDAY_SATURDAY
};
const int monthname[] = {
LANG_MONTH_JANUARY,
LANG_MONTH_FEBRUARY,
LANG_MONTH_MARCH,
LANG_MONTH_APRIL,
LANG_MONTH_MAY,
LANG_MONTH_JUNE,
LANG_MONTH_JULY,
LANG_MONTH_AUGUST,
LANG_MONTH_SEPTEMBER,
LANG_MONTH_OCTOBER,
LANG_MONTH_NOVEMBER,
LANG_MONTH_DECEMBER
};
/* little helper function for voice output */
static void say_time(int cursorpos, const struct tm *tm)
{
static const int unit[] = { UNIT_HOUR, UNIT_MIN, UNIT_SEC, 0, 0, 0 };
int value = 0;
if (!global_settings.talk_menu)
return;
switch(cursorpos)
{
case 0:
value = tm->tm_hour;
break;
case 1:
value = tm->tm_min;
break;
case 2:
value = tm->tm_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[cursorpos], false);
}
#define INDEX_X 0
#define INDEX_Y 1
#define INDEX_WIDTH 2
bool set_time_screen(const char* string, struct tm *tm)
{
bool done = false;
int button;
int min = 0, steps = 0;
int cursorpos = 0;
int lastcursorpos = !cursorpos;
unsigned char buffer[19];
int realyear;
int julianday;
int i;
unsigned char reffub[5];
unsigned int width, height;
unsigned int separator_width, weekday_width;
unsigned int line_height, prev_line_height;
int lastmode = lcd_get_drawmode();
char cursor[][3] = {{ 0, 8, 12}, {18, 8, 12}, {36, 8, 12},
{24, 16, 24}, {54, 16, 18}, {78, 16, 12}};
char daysinmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int monthname_len = 0, dayname_len = 0;
int *valptr = NULL;
#ifdef HAVE_LCD_BITMAP
if(global_settings.statusbar)
lcd_setmargins(0, STATUSBAR_HEIGHT);
else
lcd_setmargins(0, 0);
#endif
lcd_clear_display();
lcd_puts_scroll(0, 0, string);
while ( !done ) {
/* 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 = 0;
for(i = 0; i < tm->tm_mon; i++) {
julianday += daysinmonth[i];
}
julianday += tm->tm_mday;
tm->tm_wday = (realyear + julianday + (realyear - 1) / 4 -
(realyear - 1) / 100 + (realyear - 1) / 400 + 7 - 1) % 7;
snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d ",
tm->tm_hour, tm->tm_min, tm->tm_sec);
lcd_puts(0, 1, buffer);
/* recalculate the positions and offsets */
lcd_getstringsize(string, &width, &prev_line_height);
lcd_getstringsize(buffer, &width, &line_height);
lcd_getstringsize(":", &separator_width, &height);
/* hour */
strncpy(reffub, buffer, 2);
reffub[2] = '\0';
lcd_getstringsize(reffub, &width, &height);
cursor[0][INDEX_X] = 0;
cursor[0][INDEX_Y] = prev_line_height;
cursor[0][INDEX_WIDTH] = width;
/* minute */
strncpy(reffub, buffer + 3, 2);
reffub[2] = '\0';
lcd_getstringsize(reffub, &width, &height);
cursor[1][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width;
cursor[1][INDEX_Y] = prev_line_height;
cursor[1][INDEX_WIDTH] = width;
/* second */
strncpy(reffub, buffer + 6, 2);
reffub[2] = '\0';
lcd_getstringsize(reffub, &width, &height);
cursor[2][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width +
cursor[1][INDEX_WIDTH] + separator_width;
cursor[2][INDEX_Y] = prev_line_height;
cursor[2][INDEX_WIDTH] = width;
lcd_getstringsize(buffer, &width, &prev_line_height);
snprintf(buffer, sizeof(buffer), "%s %04d %s %02d ",
str(dayname[tm->tm_wday]), tm->tm_year+1900,
str(monthname[tm->tm_mon]), tm->tm_mday);
lcd_puts(0, 2, buffer);
/* recalculate the positions and offsets */
lcd_getstringsize(buffer, &width, &line_height);
/* store these 2 to prevent _repeated_ strlen calls */
monthname_len = strlen(str(monthname[tm->tm_mon]));
dayname_len = strlen(str(dayname[tm->tm_wday]));
/* weekday */
strncpy(reffub, buffer, dayname_len);
reffub[dayname_len] = '\0';
lcd_getstringsize(reffub, &weekday_width, &height);
lcd_getstringsize(" ", &separator_width, &height);
/* year */
strncpy(reffub, buffer + dayname_len + 1, 4);
reffub[4] = '\0';
lcd_getstringsize(reffub, &width, &height);
cursor[3][INDEX_X] = weekday_width + separator_width;
cursor[3][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
cursor[3][INDEX_WIDTH] = width;
/* month */
strncpy(reffub, buffer + dayname_len + 6, monthname_len);
reffub[monthname_len] = '\0';
lcd_getstringsize(reffub, &width, &height);
cursor[4][INDEX_X] = weekday_width + separator_width +
cursor[3][INDEX_WIDTH] + separator_width;
cursor[4][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
cursor[4][INDEX_WIDTH] = width;
/* day */
strncpy(reffub, buffer + dayname_len + monthname_len + 7, 2);
reffub[2] = '\0';
lcd_getstringsize(reffub, &width, &height);
cursor[5][INDEX_X] = weekday_width + separator_width +
cursor[3][INDEX_WIDTH] + separator_width +
cursor[4][INDEX_WIDTH] + separator_width;
cursor[5][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
cursor[5][INDEX_WIDTH] = width;
lcd_set_drawmode(DRMODE_COMPLEMENT);
lcd_fillrect(cursor[cursorpos][INDEX_X],
cursor[cursorpos][INDEX_Y] + lcd_getymargin(),
cursor[cursorpos][INDEX_WIDTH],
line_height);
lcd_set_drawmode(DRMODE_SOLID);
lcd_puts(0, 4, str(LANG_TIME_SET));
lcd_puts(0, 5, str(LANG_TIME_REVERT));
#ifdef HAVE_LCD_BITMAP
gui_syncstatusbar_draw(&statusbars, true);
#endif
lcd_update();
/* calculate the minimum and maximum for the number under cursor */
if(cursorpos!=lastcursorpos) {
lastcursorpos=cursorpos;
switch(cursorpos) {
case 0: /* hour */
min = 0;
steps = 24;
valptr = &tm->tm_hour;
break;
case 1: /* minute */
min = 0;
steps = 60;
valptr = &tm->tm_min;
break;
case 2: /* second */
min = 0;
steps = 60;
valptr = &tm->tm_sec;
break;
case 3: /* year */
min = 1;
steps = 200;
valptr = &tm->tm_year;
break;
case 4: /* month */
min = 0;
steps = 12;
valptr = &tm->tm_mon;
break;
case 5: /* day */
min = 1;
steps = daysinmonth[tm->tm_mon];
valptr = &tm->tm_mday;
break;
}
say_time(cursorpos, tm);
}
button = get_action(CONTEXT_SETTINGS_TIME,HZ/2);
switch ( button ) {
case ACTION_STD_PREV:
cursorpos = (cursorpos + 6 - 1) % 6;
break;
case ACTION_STD_NEXT:
cursorpos = (cursorpos + 6 + 1) % 6;
break;
case ACTION_SETTINGS_INC:
case ACTION_SETTINGS_INCREPEAT:
*valptr = (*valptr + steps - min + 1) %
steps + min;
if(*valptr == 0)
*valptr = min;
say_time(cursorpos, tm);
break;
case ACTION_SETTINGS_DEC:
case ACTION_SETTINGS_DECREPEAT:
*valptr = (*valptr + steps - min - 1) %
steps + min;
if(*valptr == 0)
*valptr = 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;
}
}
action_signalscreenchange();
lcd_set_drawmode(lastmode);
return false;
}
#endif /* defined(HAVE_LCD_BITMAP) && defined (CONFIG_RTC) */
#if (CONFIG_KEYPAD == RECORDER_PAD) && !defined(HAVE_SW_POWEROFF)
bool shutdown_screen(void)
{
int button;
bool done = false;
lcd_stop_scroll();
gui_syncsplash(0, true, str(LANG_CONFIRM_SHUTDOWN));
while(!done)
{
button = get_action(CONTEXT_STD,HZ*2);
switch(button)
{
case ACTION_STD_CANCEL:
sys_poweroff();
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
return true;
/* Return if any other button was pushed, or if there
was a timeout. We ignore RELEASE events, since we may
have been called by a button down event, and the user might
not have released the button yet.
We also ignore REPEAT events, since we don't want to
remove the splash when the user holds OFF to shut down. */
/* Is this still needed? commenting out so it compiles..
CHECK ME!!
if(!(button & (BUTTON_REL | BUTTON_REPEAT)))
*/ done = true;
break;
}
}
action_signalscreenchange();
return false;
}
#endif
#if CONFIG_CODEC == SWCODEC
#define ID3_ITEMS 13
#else
#define ID3_ITEMS 11
#endif
char * id3_get_info(int selected_item, void* data, char *buffer)
{
struct mp3entry* id3 =(struct mp3entry*)data;
int info_no=selected_item/2;
if(!(selected_item%2))
{/* header */
static const int headers[]=
{
LANG_ID3_TITLE,
LANG_ID3_ARTIST,
LANG_ID3_ALBUM,
LANG_ID3_TRACKNUM,
LANG_ID3_GENRE,
LANG_ID3_YEAR,
LANG_ID3_LENGTH,
LANG_ID3_PLAYLIST,
LANG_ID3_BITRATE,
LANG_ID3_FRECUENCY,
#if CONFIG_CODEC == SWCODEC
LANG_ID3_TRACK_GAIN,
LANG_ID3_ALBUM_GAIN,
#endif
LANG_ID3_PATH,
};
return( str(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_TRACKNUM*/
if (id3->track_string)
info = id3->track_string;
else if (id3->tracknum)
{
snprintf(buffer, MAX_PATH, "%d", id3->tracknum);
info = buffer;
}
break;
case 4:/*LANG_ID3_GENRE*/
info = id3_get_genre(id3);
break;
case 5:/*LANG_ID3_YEAR*/
if (id3->year_string)
info = id3->year_string;
else if (id3->year)
{
snprintf(buffer, MAX_PATH, "%d", id3->year);
info = buffer;
}
break;
case 6:/*LANG_ID3_LENGTH*/
gui_wps_format_time(buffer, MAX_PATH, id3->length);
info=buffer;
break;
case 7:/*LANG_ID3_PLAYLIST*/
snprintf(buffer, MAX_PATH, "%d/%d", playlist_get_display_index(),
playlist_amount());
info=buffer;
break;
case 8:/*LANG_ID3_BITRATE*/
snprintf(buffer, MAX_PATH, "%d kbps%s", id3->bitrate,
id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) "");
info=buffer;
break;
case 9:/*LANG_ID3_FRECUENCY*/
snprintf(buffer, MAX_PATH, "%ld Hz", id3->frequency);
info=buffer;
break;
#if CONFIG_CODEC == SWCODEC
case 10:/*LANG_ID3_TRACK_GAIN*/
info=id3->track_gain_string;
break;
case 11:/*LANG_ID3_ALBUM_GAIN*/
info=id3->album_gain_string;
break;
case 12:/*LANG_ID3_PATH*/
#else
case 10:/*LANG_ID3_PATH*/
#endif
info=id3->path;
break;
}
if(info==NULL)
return(str(LANG_ID3_NO_INFO));
return(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);
gui_synclist_set_nb_items(&id3_lists, ID3_ITEMS*2);
gui_synclist_draw(&id3_lists);
action_signalscreenchange();
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))
{
action_signalscreenchange();
return(default_event_handler(key) == SYS_USB_CONNECTED);
}
}
}
bool set_rating(void)
{
struct mp3entry* id3 = audio_current_track();
int button;
bool exit = false;
char rating_text[20];
if (!(audio_status() & AUDIO_STATUS_PLAY)||id3==NULL)
return false;
while (!exit)
{
lcd_clear_display();
lcd_puts(0, 0, str(LANG_RATING));
snprintf(rating_text, sizeof(rating_text), "%d", id3->rating);
lcd_puts(0, 1, (unsigned char *)rating_text);
lcd_update();
button = get_action(CONTEXT_SETTINGS,TIMEOUT_BLOCK);
switch(button)
{
case ACTION_SETTINGS_DEC:
if (id3->rating > 0)
id3->rating--;
else
id3->rating = 10;
break;
case ACTION_SETTINGS_INC:
if (id3->rating < 10)
id3->rating++;
else
id3->rating = 0;
break;
case ACTION_STD_CANCEL:
exit = true;
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
return true;
break;
}
}
action_signalscreenchange();
return false;
}