Index: apps/recorder/radio.c =================================================================== --- apps/recorder/radio.c (revision 23968) +++ apps/recorder/radio.c (working copy) @@ -67,6 +67,7 @@ #include "menus/exported_menus.h" #include "root_menu.h" #include "viewport.h" +#include "skin_engine/skin_engine.h" #if CONFIG_TUNER @@ -157,6 +158,32 @@ static int scan_presets(void *viewports); +bool radio_scan_mode(void) +{ + return radio_mode == RADIO_SCAN_MODE; +} + +bool radio_is_stereo(void) +{ + return tuner_get(RADIO_STEREO) && !global_settings.fm_force_mono; +} +int radio_current_frequency(void) +{ + return curr_freq; +} + +int radio_current_preset(void) +{ + return curr_preset; +} +int radio_preset_count(void) +{ + return num_presets; +} +const struct fmstation *radio_get_preset(int preset) +{ + return &presets[preset]; +} /* Function to manipulate all yesno dialogues. This function needs the output text as an argument. */ static bool yesno_pop(const char* text) @@ -464,6 +491,47 @@ } } +/* Skin stuff */ +extern struct wps_state wps_state; /* from wps.c */ +static struct gui_wps fms_skin[NB_SCREENS] = {{ .data = NULL }}; +static struct wps_data fms_skin_data[NB_SCREENS] = {{ .wps_loaded = 0 }}; +static struct wps_sync_data fms_skin_sync_data = { .do_full_update = false }; + + +void fms_data_load(enum screen_type screen, const char *buf, bool isfile) +{ + struct wps_data *data = fms_skin[screen].data; + int success; + success = buf && skin_data_load(screen, data, buf, isfile); + + if (!success ) /* load the default */ + { + const char default_fms[] = "%Sx|Station:| %tf\n" + "%?ts<%Sx|Stereo||%Sx|Mono|>\n" + "%?tm<%Sx|Mode:| %Sx|Scan||%Sx|Preset|: %Ti. %?Tn0<%Tn0|%Tf0>>\n" + "%pb\n"; + skin_data_load(screen, data, default_fms, false); + } +} + +void fms_skin_init(void) +{ + int i; + FOR_NB_SCREENS(i) + { +#ifdef HAVE_ALBUMART + fms_skin_data[i].albumart = NULL; + fms_skin_data[i].playback_aa_slot = -1; +#endif + fms_skin[i].data = &fms_skin_data[i]; + fms_skin[i].display = &screens[i]; + /* Currently no seperate wps_state needed/possible + so use the only available ( "global" ) one */ + fms_skin[i].state = &wps_state; + fms_skin[i].sync_data = &fms_skin_sync_data; + } +} + int radio_screen(void) { char buf[MAX_PATH]; @@ -474,7 +542,7 @@ bool stereo = false, last_stereo = false; int fh; int top_of_screen = 0; - bool update_screen = true; + bool update_screen = true, restore = true; bool screen_freeze = false; bool keep_playing = false; bool talk = false; @@ -493,36 +561,10 @@ #ifndef HAVE_NOISY_IDLE_MODE int button_timeout = current_tick + (2*HZ); #endif - struct viewport vp[NB_SCREENS]; -#ifdef HAVE_BUTTONBAR - struct gui_buttonbar buttonbar; - gui_buttonbar_init(&buttonbar); - gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) ); -#endif /* change status to "in screen" */ in_screen = true; - /* always display status bar in radio screen for now */ - FOR_NB_SCREENS(i) - { - viewport_set_defaults(&vp[i], i); -#ifdef HAVE_BUTTONBAR - if (global_settings.buttonbar) - vp[i].height -= BUTTONBAR_HEIGHT; -#endif - screens[i].set_viewport(&vp[i]); - screens[i].stop_scroll(); - screens[i].clear_viewport(); - screens[i].update_viewport(); - } - - fh = font_get(FONT_UI)->height; - - /* Adjust for font size, trying to center the information vertically */ - if(fh < 10) - top_of_screen = 1; - if(num_presets <= 0) { radio_load_presets(global_settings.fmr_file); @@ -565,20 +607,17 @@ #endif if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN))) - scan_presets(vp); + scan_presets(NULL); curr_preset = find_preset(curr_freq); if(curr_preset != -1) radio_mode = RADIO_PRESET_MODE; -#ifdef HAVE_BUTTONBAR - gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU), - str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD)); -#endif - #ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(true); #endif + FOR_NB_SCREENS(i) + skin_update(&fms_skin[i], WPS_REFRESH_ALL); while(!done) { @@ -757,25 +796,11 @@ break; case ACTION_FM_MENU: - FOR_NB_SCREENS(i) - { - screens[i].scroll_stop(&vp[i]); - } + /* FIXME: enter/exit screen */ radio_menu(); curr_preset = find_preset(curr_freq); - FOR_NB_SCREENS(i) - { - screens[i].set_viewport(&vp[i]); - screens[i].clear_viewport(); - screens[i].update_viewport(); - screens[i].set_viewport(NULL); - } -#ifdef HAVE_BUTTONBAR - gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU), - str(LANG_PRESET), - str(LANG_FM_BUTTONBAR_RECORD)); -#endif - update_screen = true; + /* FIXME: enter/exit screen */ + restore = true; break; #ifdef FM_PRESET @@ -784,32 +809,12 @@ { splash(HZ, ID2P(LANG_FM_NO_PRESETS)); update_screen = true; - FOR_NB_SCREENS(i) - { - screens[i].set_viewport(&vp[i]); - screens[i].clear_viewport(); - screens[i].update_viewport(); - screens[i].set_viewport(NULL); - } - break; } + /* FIXME: enter/exit screen */ handle_radio_presets(); - FOR_NB_SCREENS(i) - { - screens[i].set_viewport(&vp[i]); - screens[i].stop_scroll(); - screens[i].clear_viewport(); - screens[i].update_viewport(); - screens[i].set_viewport(NULL); - } -#ifdef HAVE_BUTTONBAR - gui_buttonbar_set(&buttonbar, - str(LANG_BUTTONBAR_MENU), - str(LANG_PRESET), - str(LANG_FM_BUTTONBAR_RECORD)); -#endif - update_screen = true; + /* FIXME: enter/exit screen */ + restore = true; break; #endif /* FM_PRESET */ @@ -862,7 +867,7 @@ case ACTION_FM_NEXT_PRESET: next_preset(1); end_search(); - update_screen = true; + restore = true; talk = true; break; #endif @@ -871,7 +876,7 @@ case ACTION_FM_PREV_PRESET: next_preset(-1); end_search(); - update_screen = true; + restore = true; talk = true; break; #endif @@ -960,39 +965,14 @@ { last_seconds = seconds; #else - if (update_screen) + if (update_screen || restore) { #endif - int freq; - FOR_NB_SCREENS(i) - { - screens[i].set_viewport(&vp[i]); - } - - snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ", - curr_preset + 1, presets[curr_preset].name); - - FOR_NB_SCREENS(i) - screens[i].puts_scroll(0, top_of_screen, buf); - - freq = curr_freq / 10000; - snprintf(buf, 128, str(LANG_FM_STATION), - freq / 100, freq % 100); - FOR_NB_SCREENS(i) - screens[i].puts_scroll(0, top_of_screen + 1, buf); - - FOR_NB_SCREENS(i) - screens[i].puts_scroll(0, top_of_screen + 2, - stereo ? str(LANG_CHANNEL_STEREO) : - str(LANG_CHANNEL_MONO)); - - snprintf(buf, 128, "%s %s", str(LANG_MODE), - radio_mode ? str(LANG_PRESET) : - str(LANG_RADIO_SCAN_MODE)); - FOR_NB_SCREENS(i) - screens[i].puts_scroll(0, top_of_screen + 3, buf); + skin_update(&fms_skin[i], restore?WPS_REFRESH_ALL:WPS_REFRESH_NON_STATIC); + restore = false; #ifndef SIMULATOR + /* FIXME: NOT DONE YET */ #ifdef HAVE_RDS_CAP snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME)); FOR_NB_SCREENS(i) @@ -1005,6 +985,7 @@ #endif /* SIMULATOR */ #if CONFIG_CODEC != SWCODEC + /* FIXME: NOT DONE YET */ if(audio_status() == AUDIO_STATUS_RECORD) { hours = seconds / 3600; @@ -1026,19 +1007,8 @@ } } #endif /* CONFIG_CODEC != SWCODEC */ - - FOR_NB_SCREENS(i) - { - screens[i].update_viewport(); - screens[i].set_viewport(NULL); - } - -#ifdef HAVE_BUTTONBAR - gui_buttonbar_draw(&buttonbar); -#endif } } - update_screen = false; if (global_settings.talk_file && talk @@ -1124,10 +1094,7 @@ #ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(false); #endif - FOR_NB_SCREENS(i) - { - screens[i].scroll_stop(&vp[i]); - } + /* FIXME: exit cleanup */ in_screen = false; #if CONFIG_CODEC != SWCODEC return have_recorded; Index: apps/recorder/radio.h =================================================================== --- apps/recorder/radio.h (revision 23968) +++ apps/recorder/radio.h (working copy) @@ -34,6 +34,14 @@ void radio_stop(void); bool radio_hardware_present(void); bool in_radio_screen(void); + +bool radio_scan_mode(void); /* true for scan mode, false for preset mode */ +bool radio_is_stereo(void); +int radio_current_frequency(void); +int radio_current_preset(void); +int radio_preset_count(void); +const struct fmstation *radio_get_preset(int preset); + /* callbacks for the radio settings */ void set_radio_region(int region); void toggle_mono_mode(bool mono); Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 23968) +++ apps/lang/english.lang (working copy) @@ -5244,11 +5244,11 @@ user: core *: none - radio: "Station: %d.%02d MHz" + radio: "Station:" *: none - radio: "Station: %d.%02d MHz" + radio: "Station:" *: none Index: apps/settings.c =================================================================== --- apps/settings.c (revision 23968) +++ apps/settings.c (working copy) @@ -764,6 +764,20 @@ { wps_data_load(SCREEN_MAIN, NULL, true); } +#if CONFIG_TUNER + fms_skin_init(); + if ( global_settings.fms_file[0] && + global_settings.fms_file[0] != 0xff ) + { + snprintf(buf, sizeof buf, WPS_DIR "/%s.fms", + global_settings.fms_file); + fms_data_load(SCREEN_MAIN, buf, true); + } + else + { + fms_data_load(SCREEN_MAIN, NULL, true); + } +#endif #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1) if ( global_settings.rsbs_file[0] && global_settings.rsbs_file[0] != 0xff ) { @@ -785,7 +799,20 @@ { wps_data_load(SCREEN_REMOTE, NULL, true); } +#if CONFIG_TUNER + if ( global_settings.rfms_file[0] && + global_settings.rfms_file[0] != 0xff ) + { + snprintf(buf, sizeof buf, WPS_DIR "/%s.rfms", + global_settings.rfms_file); + fms_data_load(SCREEN_REMOTE, buf, true); + } + else + { + fms_data_load(SCREEN_REMOTE, NULL, true); + } #endif +#endif viewportmanager_theme_changed(THEME_STATUSBAR); } Index: apps/gui/skin_engine/wps_debug.c =================================================================== --- apps/gui/skin_engine/wps_debug.c (revision 23968) +++ apps/gui/skin_engine/wps_debug.c (working copy) @@ -61,6 +61,7 @@ { X(TOKEN_MARKER_PLAYLIST) }, { X(TOKEN_MARKER_MISC) }, { X(TOKEN_MARKER_RECORDING) }, + { X(TOKEN_MARKER_TUNER) }, { X(TOKEN_MARKER_END) }, }; #undef X Index: apps/gui/skin_engine/skin_parser.c =================================================================== --- apps/gui/skin_engine/skin_parser.c (revision 23968) +++ apps/gui/skin_engine/skin_parser.c (working copy) @@ -182,6 +182,10 @@ #else #define WPS_RTC_REFRESH WPS_REFRESH_STATIC #endif +#if CONFIG_TUNER +static int parse_presettoken(const char *wps_bufptr, + struct wps_token *token, struct wps_data *wps_data); +#endif /* array of available tags - those with more characters have to go first (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */ @@ -334,6 +338,22 @@ { WPS_TOKEN_CROSSFADE, "xf", WPS_REFRESH_DYNAMIC, NULL }, #endif + { WPS_TOKEN_HAVE_TUNER, "tp", WPS_REFRESH_STATIC, NULL }, +#if CONFIG_TUNER /* Re-uses the 't' and 'T' prefixes, be careful about doubleups */ + /* TODO: alot of these can be made WPS_REFRESH_STATIC + * if the skin is fully redrawn when changing stuff(!) */ + { WPS_TOKEN_TUNER_TUNED, "tt", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_TUNER_SCANMODE, "tm", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_TUNER_STEREO, "ts", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_TUNER_MINFREQ, "ta", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_TUNER_MAXFREQ, "tb", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_TUNER_CURFREQ, "tf", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_PRESET_ID, "Ti", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_PRESET_NAME, "Tn", WPS_REFRESH_DYNAMIC, parse_presettoken }, + { WPS_TOKEN_PRESET_FREQ, "Tf", WPS_REFRESH_DYNAMIC, parse_presettoken }, + { WPS_TOKEN_PRESET_COUNT, "Tc", WPS_REFRESH_DYNAMIC, NULL }, +#endif /* CONFIG_TUNER */ + { WPS_NO_TOKEN, "s", WPS_REFRESH_SCROLL, NULL }, { WPS_TOKEN_SUBLINE_TIMEOUT, "t", 0, parse_timeout }, @@ -1198,6 +1218,21 @@ }; #endif /* HAVE_ALBUMART */ +#if CONFIG_TUNER +static int parse_presettoken(const char *wps_bufptr, + struct wps_token *token, struct wps_data *wps_data) +{ + /* tokens are in the form %xxN where N is a number + * stored as *signed* in the tokens data */ + int value = 0, vals; + const char *ptr; + if (!(ptr = parse_list("d", NULL, '|',wps_bufptr, &value))) + return WPS_ERROR_INVALID_PARAM; + token->value.i = (signed int)value; + return ptr-wps_bufptr; +} +#endif /* CONFIG_TUNER */ + #ifdef HAVE_TOUCHSCREEN struct touchaction {char* s; int action;}; Index: apps/gui/skin_engine/skin_tokens.c =================================================================== --- apps/gui/skin_engine/skin_tokens.c (revision 23968) +++ apps/gui/skin_engine/skin_tokens.c (working copy) @@ -61,6 +61,8 @@ #endif #include "language.h" #include "usb.h" +#include "radio.h" +#include "tuner.h" static char* get_codectype(const struct mp3entry* id3) { @@ -1141,6 +1143,81 @@ return NULL; #endif /* HAVE_RECORDING */ + + /* Radio/tuner tokens */ + case WPS_TOKEN_HAVE_TUNER: +#if CONFIG_TUNER + if (radio_hardware_present()) + return "r"; +#endif + return NULL; +#if CONFIG_TUNER + case WPS_TOKEN_TUNER_TUNED: + if (tuner_get(RADIO_TUNED)) + return "t"; + return NULL; + case WPS_TOKEN_TUNER_SCANMODE: + if (radio_scan_mode()) + return "s"; + return NULL; + case WPS_TOKEN_TUNER_STEREO: + if (radio_is_stereo()) + return "s"; + return NULL; + case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */ + { + int freq = fm_region_data[global_settings.fm_region].freq_min / 10000; + snprintf(buf, buf_size, "%d.%d", freq/100, freq%100); + return buf; + } + case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */ + { + int freq = fm_region_data[global_settings.fm_region].freq_max / 10000; + snprintf(buf, buf_size, "%d.%d", freq/100, freq%100); + return buf; + } + case WPS_TOKEN_TUNER_CURFREQ: + { + int freq = radio_current_frequency() / 10000; + snprintf(buf, buf_size, "%d.%d", freq/100, freq%100); + return buf; + } + case WPS_TOKEN_PRESET_ID: + snprintf(buf, buf_size, "%d", radio_current_preset()+1); + return buf; + case WPS_TOKEN_PRESET_NAME: + case WPS_TOKEN_PRESET_FREQ: + { + int preset = radio_current_preset() + (signed int)token->value.i; + /* make sure its in the valid range */ + while (preset < 0) + preset += radio_preset_count(); + preset %= radio_preset_count(); + if (token->type == WPS_TOKEN_PRESET_NAME) + { + snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name); + } + else + { + int freq = radio_get_preset(preset)->frequency / 10000; + snprintf(buf, buf_size, "%d.%d", freq/100, freq%100); + } + return buf; + } + case WPS_TOKEN_PRESET_COUNT: + snprintf(buf, buf_size, "%d", radio_preset_count()); + if (intval) + *intval = radio_preset_count(); + return buf; + /* FIXME: RDS tokens + case WPS_TOKEN_HAVE_RDS: +#ifdef HAVE_RDS_CAP + WPS_TOKEN_RDS_NAME, + WPS_TOKEN_RDS_TEXT, +#endif +*/ +#endif /* CONFIG_TUNER */ + case WPS_TOKEN_CURRENT_SCREEN: { int curr_screen = current_screen(); Index: apps/gui/skin_engine/skin_display.c =================================================================== --- apps/gui/skin_engine/skin_display.c (revision 23968) +++ apps/gui/skin_engine/skin_display.c (working copy) @@ -50,6 +50,8 @@ #endif #include "backdrop.h" #include "viewport.h" +#include "tuner.h" +#include "root_menu.h" #include "wps_internals.h" @@ -118,6 +120,7 @@ struct wps_state *state = gwps->state; struct progressbar *pb = wps_vp->pb; struct mp3entry *id3 = state->id3; + int y = pb->y; if (y < 0) @@ -130,9 +133,18 @@ } int elapsed, length; +#if CONFIG_TUNER + if (current_screen() == GO_TO_FM) + { + int min = fm_region_data[global_settings.fm_region].freq_min; + elapsed = radio_current_frequency() - min; + length = fm_region_data[global_settings.fm_region].freq_max - min; + } + else +#endif if (id3) { - elapsed = id3->elapsed; + elapsed = id3->elapsed + state->ff_rewind_count; length = id3->length; } else @@ -145,12 +157,12 @@ gui_bitmap_scrollbar_draw(display, pb->bm, pb->x, y, pb->width, pb->bm.height, length ? length : 1, 0, - length ? elapsed + state->ff_rewind_count : 0, + length ? elapsed : 0, HORIZONTAL); else gui_scrollbar_draw(display, pb->x, y, pb->width, pb->height, length ? length : 1, 0, - length ? elapsed + state->ff_rewind_count : 0, + length ? elapsed : 0, HORIZONTAL); #ifdef AB_REPEAT_ENABLE if ( ab_repeat_mode_enabled() && length != 0 ) Index: apps/gui/skin_engine/skin_tokens.h =================================================================== --- apps/gui/skin_engine/skin_tokens.h (revision 23968) +++ apps/gui/skin_engine/skin_tokens.h (working copy) @@ -213,6 +213,30 @@ WPS_TOKEN_REC_BITRATE, /* SWCODEC: MP3 bitrate, HWCODEC: MP3 "quality" */ WPS_TOKEN_REC_MONO, + + /* Radio Tokens */ + TOKEN_MARKER_TUNER, + WPS_TOKEN_HAVE_TUNER, +#if CONFIG_TUNER + WPS_TOKEN_TUNER_TUNED, + WPS_TOKEN_TUNER_SCANMODE, + WPS_TOKEN_TUNER_STEREO, + WPS_TOKEN_TUNER_MINFREQ, /* changes based on "region" */ + WPS_TOKEN_TUNER_MAXFREQ, /* changes based on "region" */ + WPS_TOKEN_TUNER_CURFREQ, + WPS_TOKEN_PRESET_ID, /* "id" of this preset.. really the array elemt number */ + WPS_TOKEN_PRESET_NAME, + WPS_TOKEN_PRESET_FREQ, + WPS_TOKEN_PRESET_COUNT, + /* RDS tokens */ + WPS_TOKEN_HAVE_RDS, +#ifdef HAVE_RDS_CAP + WPS_TOKEN_RDS_NAME, + WPS_TOKEN_RDS_TEXT, +#endif +#endif /* CONFIG_TUNER */ + + TOKEN_MARKER_END, /* this needs to be the last value in this enum */ }; Index: apps/settings.h =================================================================== --- apps/settings.h (revision 23968) +++ apps/settings.h (working copy) @@ -495,7 +495,11 @@ int fm_region; bool fm_force_mono; /* Forces Mono mode if true */ unsigned char fmr_file[MAX_FILENAME+1]; /* last fmr preset */ + unsigned char fms_file[MAX_FILENAME+1]; /* last fms */ +#ifdef HAVE_REMOTE_LCD + unsigned char rfms_file[MAX_FILENAME+1]; /* last remote-fms */ #endif +#endif /* CONFIG_TUNER */ /* misc options */ #ifndef HAVE_WHEEL_ACCELERATION Index: apps/settings_list.c =================================================================== --- apps/settings_list.c (revision 23968) +++ apps/settings_list.c (working copy) @@ -200,6 +200,7 @@ /* Default theme settings */ #define DEFAULT_WPSNAME "cabbiev2" #define DEFAULT_SBS_NAME DEFAULT_WPSNAME +#define DEFAULT_FMS_NAME DEFAULT_WPSNAME #ifdef HAVE_LCD_BITMAP @@ -1421,7 +1422,13 @@ #if CONFIG_TUNER TEXT_SETTING(0, fmr_file, "fmr", "", FMPRESET_PATH "/", ".fmr"), + TEXT_SETTING(F_THEMESETTING,fms_file, "fms", + DEFAULT_FMS_NAME, SBS_DIR "/", ".fms"), +#ifdef HAVE_REMOTE_LCD + TEXT_SETTING(F_THEMESETTING,rfms_file, "rfms", + DEFAULT_FMS_NAME, SBS_DIR "/", ".rfms"), #endif +#endif /* CONFIG_TUNER */ #ifdef HAVE_LCD_BITMAP TEXT_SETTING(F_THEMESETTING, font_file, "font", DEFAULT_FONTNAME, FONT_DIR "/", ".fnt"),