Index: tools/checkwps/checkwps.c =================================================================== --- tools/checkwps/checkwps.c (revision 24716) +++ tools/checkwps/checkwps.c (working copy) @@ -237,6 +237,13 @@ } #endif +#if CONFIG_TUNER +bool radio_hardware_present(void) +{ + return true; +} +#endif + #ifdef HAVE_LCD_BITMAP static int loaded_fonts = 0; int font_load(struct font* pf, const char *path) Index: apps/recorder/radio.c =================================================================== --- apps/recorder/radio.c (revision 24742) +++ apps/recorder/radio.c (working copy) @@ -52,6 +52,7 @@ #ifdef IPOD_ACCESSORY_PROTOCOL #include "iap.h" #endif +#include "appevents.h" #include "talk.h" #include "tuner.h" #include "power.h" @@ -67,6 +68,8 @@ #include "menus/exported_menus.h" #include "root_menu.h" #include "viewport.h" +#include "skin_engine/skin_engine.h" +#include "statusbar-skinned.h" #if CONFIG_TUNER @@ -157,6 +160,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,17 +493,90 @@ } } +/* 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. %?Tn<%Tn|%Tf>>\n" + "%pb\n" +#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) + "%?Rr<%Sx|Time:| %Rh:%Rn:%Rs|" + "%?St|prerecording time|<%Sx|Prerecord Time| %Rs|%pm>>\n" +#endif + ; + skin_data_load(screen, data, default_fms, false); + } +} +enum fms_exiting { + FMS_EXIT, + FMS_ENTER +}; +void fms_fix_displays(enum fms_exiting toggle_state) +{ + int i; + FOR_NB_SCREENS(i) + { + if (toggle_state == FMS_ENTER) + { + viewportmanager_theme_enable(i, skin_has_sbs(i, fms_skin[i].data), NULL); +#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + screens[i].backdrop_show(fms_skin[i].data->backdrop); +#endif + screens[i].clear_display(); + /* force statusbar/skin update since we just cleared the whole screen */ + send_event(GUI_EVENT_ACTIONUPDATE, (void*)1); + } + else + { + screens[i].stop_scroll(); +#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + screens[i].backdrop_show(sb_get_backdrop(i)); +#endif + viewportmanager_theme_undo(i, skin_has_sbs(i, fms_skin[i].data)); + } + } +} + + +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]; bool done = false; int ret_val = GO_TO_ROOT; int button; int i; 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 +595,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,17 +641,12 @@ #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 @@ -602,15 +673,8 @@ cancel_cpu_boost(); } -#if CONFIG_CODEC != SWCODEC - /* TODO: Can we timeout at HZ when recording since peaks aren't - displayed? This should quiet recordings too. */ - button = get_action(CONTEXT_FM, - update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS); -#else - button = get_action(CONTEXT_FM, - update_screen ? TIMEOUT_NOBLOCK : HZ); -#endif + button = skin_wait_for_action(fms_skin, CONTEXT_FM, + update_screen ? TIMEOUT_NOBLOCK : HZ); #ifndef HAVE_NOISY_IDLE_MODE if (button != ACTION_NONE) @@ -757,25 +821,11 @@ break; case ACTION_FM_MENU: - FOR_NB_SCREENS(i) - { - screens[i].scroll_stop(&vp[i]); - } + fms_fix_displays(FMS_EXIT); 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; + restore = true; break; #ifdef FM_PRESET @@ -784,32 +834,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; } + fms_fix_displays(FMS_EXIT); 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; + restore = true; break; #endif /* FM_PRESET */ @@ -921,18 +951,6 @@ { /* Only display the peak meter when not recording */ #if CONFIG_CODEC != SWCODEC - if(!audio_status()) - { - FOR_NB_SCREENS(i) - { - screens[i].set_viewport(&vp[i]); - peak_meter_screen(&screens[i],0, fh*(top_of_screen + 4),fh); - screens[i].update_rect(0, fh*(top_of_screen + 4), - screens[i].getwidth(), fh); - screens[i].set_viewport(NULL); - } - } - if(TIME_AFTER(current_tick, timeout)) { timeout = current_tick + HZ; @@ -956,89 +974,20 @@ #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) seconds = audio_recorded_time() / HZ; - if (update_screen || seconds > last_seconds) + if (update_screen || seconds > last_seconds || restore) { last_seconds = seconds; #else - if (update_screen) + if (update_screen || restore) { #endif - int freq; - + if (restore) + fms_fix_displays(FMS_ENTER); 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); -#ifndef SIMULATOR -#ifdef HAVE_RDS_CAP - snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME)); - FOR_NB_SCREENS(i) - screens[i].puts_scroll(0, top_of_screen + 4, buf); - - snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT)); - FOR_NB_SCREENS(i) - screens[i].puts_scroll(0, top_of_screen + 5, buf); -#endif -#endif /* SIMULATOR */ - -#if CONFIG_CODEC != SWCODEC - if(audio_status() == AUDIO_STATUS_RECORD) - { - hours = seconds / 3600; - minutes = (seconds - (hours * 3600)) / 60; - snprintf(buf, 32, "%s %02d:%02d:%02d", - str(LANG_RECORDING_TIME), - hours, minutes, seconds%60); - FOR_NB_SCREENS(i) - screens[i].puts_scroll(0, top_of_screen + 4, buf); - } - else - { - if(rec_options.rec_prerecord_time) - { - snprintf(buf, 32, "%s %02d", - str(LANG_RECORD_PRERECORD), seconds%60); - FOR_NB_SCREENS(i) - screens[i].puts_scroll(0, top_of_screen + 4, buf); - } - } -#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 + skin_update(&fms_skin[i], WPS_REFRESH_ALL); + restore = false; } } - update_screen = false; if (global_settings.talk_file && talk @@ -1076,12 +1025,6 @@ if(audio_status() & AUDIO_STATUS_ERROR) { splash(0, str(LANG_DISK_FULL)); - FOR_NB_SCREENS(i) - { - screens[i].set_viewport(&vp[i]); - screens[i].update_viewport(); - screens[i].set_viewport(NULL); - } audio_error_clear(); while(1) @@ -1124,10 +1067,7 @@ #ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(false); #endif - FOR_NB_SCREENS(i) - { - screens[i].scroll_stop(&vp[i]); - } + fms_fix_displays(FMS_EXIT); in_screen = false; #if CONFIG_CODEC != SWCODEC return have_recorded; Index: apps/recorder/radio.h =================================================================== --- apps/recorder/radio.h (revision 24742) +++ apps/recorder/radio.h (working copy) @@ -24,6 +24,7 @@ #ifndef FMRADIO_H #include "fmradio.h" #endif +#include "screen_access.h" #if CONFIG_TUNER void radio_load_presets(char *filename); @@ -34,6 +35,18 @@ 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); + +/* skin functions */ +void fms_data_load(enum screen_type screen, const char *buf, bool isfile); +void fms_skin_init(void); + /* 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 24742) +++ 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 @@ -13349,3 +13349,54 @@ remote: "Remote Screen" + + id: LANG_REMOTE_FMRADIO + desc: in the main menu + user: core + + *:none + radio_remote: "Remote FM Radio" + + + *:none + radio_remote: "Remote FM Radio" + + + *:none + radio_remote: "Remote FM Radio" + + + + id: VOICE_EXT_FMS + desc: spoken only, for file extension + user: core + + *: none + radio: "" + + + *: none + radio: "" + + + *: none + radio: "radio screen skin" + + + + id: VOICE_EXT_RFMS + desc: spoken only, for file extension + user: core + + *: none + radio_remote: "" + + + *: none + radio_remote: "" + + + *: none + radio_remote: "remote radio screen skin" + + Index: apps/settings.c =================================================================== --- apps/settings.c (revision 24742) +++ apps/settings.c (working copy) @@ -766,6 +766,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 ) { @@ -787,7 +801,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); #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 int i; Index: apps/gui/skin_engine/skin_engine.h =================================================================== --- apps/gui/skin_engine/skin_engine.h (revision 24742) +++ apps/gui/skin_engine/skin_engine.h (working copy) @@ -30,6 +30,9 @@ enum skinnable_screens { CUSTOM_STATUSBAR, WPS, +#if CONFIG_TUNER + FM_SCREEN, +#endif SKINNABLE_SCREENS_COUNT @@ -53,9 +56,18 @@ /* call this in statusbar toggle handlers if needed */ void skin_statusbar_changed(struct gui_wps*); +bool skin_has_sbs(enum screen_type screen, struct wps_data *data); + /* load a backdrop into the skin buffer. * reuse buffers if the file is already loaded */ char* skin_backdrop_load(char* backdrop, char *bmpdir, enum screen_type screen); void skin_backdrop_init(void); + + +/* do the button loop as often as required for the peak meters to update + * with a good refresh rate. + * gwps is really gwps[NB_SCREENS]! don't wrap this if FOR_NB_SCREENS() + */ +int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout); #endif Index: apps/gui/skin_engine/wps_debug.c =================================================================== --- apps/gui/skin_engine/wps_debug.c (revision 24742) +++ 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 24742) +++ apps/gui/skin_engine/skin_parser.c (working copy) @@ -52,6 +52,7 @@ #include "skin_engine.h" #include "settings.h" #include "settings_list.h" +#include "radio.h" #include "skin_fonts.h" #ifdef HAVE_LCD_BITMAP @@ -343,6 +344,27 @@ { 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_STATIC, NULL }, + { WPS_TOKEN_PRESET_NAME, "Tn", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_PRESET_FREQ, "Tf", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_PRESET_COUNT, "Tc", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_HAVE_RDS, "tx", WPS_REFRESH_STATIC, NULL }, +#ifdef HAVE_RDS_CAPS + { WPS_TOKEN_RDS_NAME, "ty", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_RDS_TEXT, "tz", WPS_REFRESH_DYNAMIC, NULL }, +#endif +#endif /* CONFIG_TUNER */ + { WPS_NO_TOKEN, "s", WPS_REFRESH_SCROLL, NULL }, { WPS_TOKEN_SUBLINE_TIMEOUT, "t", 0, parse_timeout }, @@ -388,10 +410,14 @@ /* Recording Tokens */ { WPS_TOKEN_HAVE_RECORDING, "Rp", WPS_REFRESH_STATIC, NULL }, #ifdef HAVE_RECORDING + { WPS_TOKEN_IS_RECORDING, "Rr", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_REC_FREQ, "Rf", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_REC_ENCODER, "Re", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_REC_BITRATE, "Rb", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_REC_MONO, "Rm", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_REC_SECONDS, "Rs", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_REC_MINUTES, "Rn", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_REC_HOURS, "Rh", WPS_REFRESH_DYNAMIC, NULL }, #endif { WPS_TOKEN_UNKNOWN, "", 0, NULL } /* the array MUST end with an empty string (first char is \0) */ @@ -1660,6 +1686,13 @@ #else return find_false_branch(wps_bufptr); #endif + case WPS_TOKEN_HAVE_TUNER: +#if CONFIG_TUNER + if (radio_hardware_present()) + return 0; +#endif + return find_false_branch(wps_bufptr); + default: /* not a tag we care about, just don't skip */ return 0; } Index: apps/gui/skin_engine/skin_tokens.c =================================================================== --- apps/gui/skin_engine/skin_tokens.c (revision 24742) +++ 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" extern struct wps_state wps_state; @@ -342,6 +344,87 @@ return buf; } +#if CONFIG_TUNER +/* Tokens which are really only used by the radio screen go in here */ +const char *get_radio_token(struct wps_token *token, int preset_offset, + char *buf, int buf_size, int limit, int *intval) +{ + (void)limit; + switch (token->type) + { + /* Radio/tuner tokens */ + 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.%02d", 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.%02d", freq/100, freq%100); + return buf; + } + case WPS_TOKEN_TUNER_CURFREQ: + { + int freq = radio_current_frequency() / 10000; + snprintf(buf, buf_size, "%d.%02d", freq/100, freq%100); + return buf; + } + case WPS_TOKEN_PRESET_ID: + snprintf(buf, buf_size, "%d", radio_current_preset() + 1 + preset_offset); + return buf; + case WPS_TOKEN_PRESET_NAME: + case WPS_TOKEN_PRESET_FREQ: + { + int preset = radio_current_preset() + preset_offset; + /* 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.%02d", 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; + case WPS_TOKEN_HAVE_RDS: +#ifdef HAVE_RDS_CAP + return "rds"; + case WPS_TOKEN_RDS_NAME: + return tuner_get_rds_info(RADIO_RDS_NAME); + case WPS_TOKEN_RDS_TEXT: + return tuner_get_rds_info(RADIO_RDS_TEXT); +#else + return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */ +#endif /* HAVE_RDS_CAP */ + } + return NULL; +} +#endif + /* Return the tags value as text. buf should be used as temp storage if needed. intval is used with conditionals/enums: when this function is called, @@ -399,6 +482,11 @@ out_text = get_id3_token(token, id3, buf, buf_size, limit, intval); if (out_text) return out_text; +#if CONFIG_TUNER + out_text = get_radio_token(token, 0, buf, buf_size, limit, intval); + if (out_text) + return out_text; +#endif switch (token->type) { @@ -935,6 +1023,9 @@ * The string's emptyness discards the setting's * prefix and suffix */ *intval = ((char*)s->setting)[0]?1:2; + /* if there is a prefix we should ignore it here */ + if (s->filename_setting->prefix) + return (char*)s->setting; break; default: /* This shouldn't happen ... but you never know */ @@ -952,6 +1043,12 @@ cfg_to_string(token->value.i,buf,buf_size); return buf; } + case WPS_TOKEN_HAVE_TUNER: +#if CONFIG_TUNER + if (radio_hardware_present()) + return "r"; +#endif + return NULL; /* Recording tokens */ case WPS_TOKEN_HAVE_RECORDING: #ifdef HAVE_RECORDING @@ -961,6 +1058,10 @@ #endif #ifdef HAVE_RECORDING + case WPS_TOKEN_IS_RECORDING: + if (audio_status() == AUDIO_STATUS_RECORD) + return "r"; + return NULL; case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */ { #if CONFIG_CODEC == SWCODEC @@ -1143,8 +1244,25 @@ if (!global_settings.rec_channels) return "m"; return NULL; + + case WPS_TOKEN_REC_SECONDS: + if (intval) + *intval = (audio_recorded_time() / HZ) % 60; + snprintf(buf, buf_size, "%02d", (audio_recorded_time() / HZ) % 60); + return buf; + case WPS_TOKEN_REC_MINUTES: + if (intval) + *intval = (audio_recorded_time() / HZ) / 60; + snprintf(buf, buf_size, "%02d", (audio_recorded_time() / HZ) / 60); + return buf; + case WPS_TOKEN_REC_HOURS: + if (intval) + *intval = (audio_recorded_time() / HZ) / 3600; + snprintf(buf, buf_size, "%02d", (audio_recorded_time() / HZ) / 3600); + return buf; #endif /* HAVE_RECORDING */ + 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 24742) +++ apps/gui/skin_engine/skin_display.c (working copy) @@ -29,6 +29,7 @@ #ifdef DEBUG #include "debug.h" #endif +#include "action.h" #include "abrepeat.h" #include "lang.h" #include "language.h" @@ -53,6 +54,9 @@ #endif #include "backdrop.h" #include "viewport.h" +#include "radio.h" +#include "tuner.h" +#include "root_menu.h" #include "wps_internals.h" @@ -74,7 +78,7 @@ struct mp3entry *id3 = gwps->state->id3; bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false); gwps->sync_data->do_full_update |= cuesheet_update; - + retval = skin_redraw(gwps, gwps->sync_data->do_full_update ? WPS_REFRESH_ALL : update_type); return retval; @@ -121,6 +125,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) @@ -133,9 +138,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 @@ -148,12 +162,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 ) @@ -172,8 +186,8 @@ struct wps_state *state = gwps->state; int lines = viewport_get_nb_lines(viewer->vp); int line_height = font_get(viewer->vp->font)->height; - int cur_playlist_pos = playlist_get_display_index(); - int start_item = MAX(0, cur_playlist_pos + viewer->start_offset); + int cur_pos, count; + int start_item; int i; struct wps_token token; int x, length, alignment = WPS_TOKEN_ALIGN_LEFT; @@ -186,19 +200,33 @@ unsigned int buf_used = 0; +#if CONFIG_TUNER + if (current_screen() == GO_TO_FM) + { + cur_pos = radio_current_preset(); + count = radio_preset_count(); + } + else +#endif + { + cur_pos = playlist_get_display_index(); + count = playlist_amount(); + } + start_item = MAX(0, cur_pos + viewer->start_offset); + gwps->display->set_viewport(viewer->vp); - for(i=start_item; (i-start_item)id3; } - else if (i == cur_playlist_pos+1) + else if (i == cur_pos+1) { pid3 = state->nid3; } #if CONFIG_CODEC == SWCODEC - else if ((i>cur_playlist_pos) && audio_peek_track(&id3, i-cur_playlist_pos)) + else if ((i>cur_pos) && audio_peek_track(&id3, i-cur_pos)) { pid3 = &id3; } @@ -208,9 +236,21 @@ pid3 = NULL; } - int line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO; + int line; int j = 0, cur_string = 0; - char *filename = playlist_peek(i-cur_playlist_pos); + char *filename; +#if CONFIG_TUNER + if (current_screen() == GO_TO_FM) + { + line = TRACK_HAS_INFO; + filename = ""; + } + else +#endif + { + line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO; + filename = playlist_peek(i-cur_pos); + } buf[0] = '\0'; buf_used = 0; while (j < viewer->lines[line].count && (buf_usedlines[line].tokens[j]) { case WPS_TOKEN_ALIGN_CENTER: @@ -1259,3 +1310,70 @@ return true; } + +bool skin_has_sbs(enum screen_type screen, struct wps_data *data) +{ + (void)screen; + bool draw = false; +#ifdef HAVE_LCD_BITMAP + if (data->wps_sb_tag) + draw = data->show_sb_on_wps; + else if (statusbar_position(screen) != STATUSBAR_OFF) + draw = true; +#endif + return draw; +} + +/* do the button loop as often as required for the peak meters to update + * with a good refresh rate. + * gwps is really gwps[NB_SCREENS]! don't wrap this if FOR_NB_SCREENS() + */ +int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout) +{ +#ifdef HAVE_LCD_BITMAP + int i; + int button = ACTION_NONE; + /* when the peak meter is enabled we want to have a + few extra updates to make it look smooth. On the + other hand we don't want to waste energy if it + isn't displayed */ + bool pm=false; + FOR_NB_SCREENS(i) + { + if(gwps[i].data->peak_meter_enabled) + pm = true; + } + + if (pm) { + long next_refresh = current_tick; + long next_big_refresh = current_tick + timeout; + button = BUTTON_NONE; + while (TIME_BEFORE(current_tick, next_big_refresh)) { + button = get_action(context,TIMEOUT_NOBLOCK); + if (button != ACTION_NONE) { + break; + } + peak_meter_peek(); + sleep(0); /* Sleep until end of current tick. */ + + if (TIME_AFTER(current_tick, next_refresh)) { + FOR_NB_SCREENS(i) + { + if(gwps[i].data->peak_meter_enabled) + skin_update(&gwps[i], WPS_REFRESH_PEAK_METER); + next_refresh += HZ / PEAK_METER_FPS; + } + } + } + + } + + /* The peak meter is disabled + -> no additional screen updates needed */ + else +#endif + { + button = get_action(context, timeout); + } + return button; +} Index: apps/gui/skin_engine/skin_tokens.h =================================================================== --- apps/gui/skin_engine/skin_tokens.h (revision 24742) +++ apps/gui/skin_engine/skin_tokens.h (working copy) @@ -211,11 +211,39 @@ /* Recording Tokens */ TOKEN_MARKER_RECORDING, WPS_TOKEN_HAVE_RECORDING, + WPS_TOKEN_IS_RECORDING, WPS_TOKEN_REC_FREQ, WPS_TOKEN_REC_ENCODER, WPS_TOKEN_REC_BITRATE, /* SWCODEC: MP3 bitrate, HWCODEC: MP3 "quality" */ WPS_TOKEN_REC_MONO, + WPS_TOKEN_REC_SECONDS, + WPS_TOKEN_REC_MINUTES, + WPS_TOKEN_REC_HOURS, + + /* 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 element 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/gui/skin_engine/wps_internals.h =================================================================== --- apps/gui/skin_engine/wps_internals.h (revision 24742) +++ apps/gui/skin_engine/wps_internals.h (working copy) @@ -364,8 +364,11 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3, char *buf, int buf_size, int limit, int *intval); +#if CONFIG_TUNER +const char *get_radio_token(struct wps_token *token, int preset_offset, + char *buf, int buf_size, int limit, int *intval); +#endif - struct gui_img* find_image(char label, struct wps_data *data); struct skin_viewport* find_viewport(char label, struct wps_data *data); Index: apps/gui/wps.c =================================================================== --- apps/gui/wps.c (revision 24742) +++ apps/gui/wps.c (working copy) @@ -568,16 +568,8 @@ #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 gui_wps[i].display->backdrop_show(sb_get_backdrop(i)); #endif + viewportmanager_theme_undo(i, skin_has_sbs(i, gui_wps[i].data)); -#ifdef HAVE_LCD_BITMAP - bool draw = false; - if (gui_wps[i].data->wps_sb_tag) - draw = gui_wps[i].data->show_sb_on_wps; - else if (statusbar_position(i) != STATUSBAR_OFF) - draw = true; -#endif - viewportmanager_theme_undo(i, draw); - } #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) @@ -597,15 +589,8 @@ { struct gui_wps *gwps = &gui_wps[i]; struct screen *display = gwps->display; -#ifdef HAVE_LCD_BITMAP - bool draw = false; - if (gui_wps[i].data->wps_sb_tag) - draw = gui_wps[i].data->show_sb_on_wps; - else if (statusbar_position(i) != STATUSBAR_OFF) - draw = true; -#endif display->stop_scroll(); - viewportmanager_theme_enable(i, draw, NULL); + viewportmanager_theme_enable(i, skin_has_sbs(i, gui_wps[i].data), NULL); /* Update the values in the first (default) viewport - in case the user has modified the statusbar or colour settings */ @@ -771,57 +756,9 @@ #endif } } -#ifdef HAVE_LCD_BITMAP - /* when the peak meter is enabled we want to have a - few extra updates to make it look smooth. On the - other hand we don't want to waste energy if it - isn't displayed */ - bool pm=false; - FOR_NB_SCREENS(i) - { - if(gui_wps[i].data->peak_meter_enabled) - pm = true; - } + button = skin_wait_for_action(gui_wps, CONTEXT_WPS|ALLOW_SOFTLOCK, + restore ? 1 : HZ/5); - if (pm) { - long next_refresh = current_tick; - long next_big_refresh = current_tick + HZ / 5; - button = BUTTON_NONE; - while (TIME_BEFORE(current_tick, next_big_refresh)) { - button = get_action(CONTEXT_WPS|ALLOW_SOFTLOCK,TIMEOUT_NOBLOCK); - /* check for restore to not let the peakmeter delay the - * initial draw of the wps, don't delay handling of button - * presses either */ - if (button != ACTION_NONE || restore) { - break; - } - peak_meter_peek(); - sleep(0); /* Sleep until end of current tick. */ - - if (TIME_AFTER(current_tick, next_refresh)) { - FOR_NB_SCREENS(i) - { - if(gui_wps[i].data->peak_meter_enabled) - skin_update(&gui_wps[i], WPS_REFRESH_PEAK_METER); - next_refresh += HZ / PEAK_METER_FPS; - } - } - } - - } - - /* The peak meter is disabled - -> no additional screen updates needed */ - else -#endif - { /* 1 is the minimum timeout which lets other threads run. - * audio thread (apprently) needs to run before displaying the wps - * or bad things happen with regards to cuesheet - * (probably a race condition, on sh at least) */ - button = get_action(CONTEXT_WPS|ALLOW_SOFTLOCK, - restore ? 1 : HZ/5); - } - /* Exit if audio has stopped playing. This happens e.g. at end of playlist or if using the sleep timer. */ if (!(audio_status() & AUDIO_STATUS_PLAY)) Index: apps/settings.h =================================================================== --- apps/settings.h (revision 24742) +++ apps/settings.h (working copy) @@ -146,7 +146,7 @@ * must be added after NUM_FILTER_MODES. */ enum { SHOW_ALL, SHOW_SUPPORTED, SHOW_MUSIC, SHOW_PLAYLIST, SHOW_ID3DB, NUM_FILTER_MODES, - SHOW_WPS, SHOW_RWPS, SHOW_SBS, SHOW_RSBS, SHOW_FMR, SHOW_CFG, + SHOW_WPS, SHOW_RWPS, SHOW_FMS, SHOW_RFMS, SHOW_SBS, SHOW_RSBS, SHOW_FMR, SHOW_CFG, SHOW_LNG, SHOW_MOD, SHOW_FONT, SHOW_PLUGINS}; /* file and dir sort options */ @@ -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/menus/theme_menu.c =================================================================== --- apps/menus/theme_menu.c (revision 24742) +++ apps/menus/theme_menu.c (working copy) @@ -222,12 +222,18 @@ #ifdef HAVE_LCD_BITMAP static struct browse_folder_info fonts = {FONT_DIR, SHOW_FONT}; static struct browse_folder_info sbs = {SBS_DIR, SHOW_SBS}; +#if CONFIG_TUNER +static struct browse_folder_info fms = {WPS_DIR, SHOW_FMS}; #endif +#endif static struct browse_folder_info wps = {WPS_DIR, SHOW_WPS}; #ifdef HAVE_REMOTE_LCD static struct browse_folder_info rwps = {WPS_DIR, SHOW_RWPS}; static struct browse_folder_info rsbs = {SBS_DIR, SHOW_RSBS}; +#if CONFIG_TUNER +static struct browse_folder_info rfms = {WPS_DIR, SHOW_RFMS}; #endif +#endif static struct browse_folder_info themes = {THEME_DIR, SHOW_CFG}; int browse_folder(void *param) @@ -245,7 +251,12 @@ MENUITEM_FUNCTION(browse_sbs, MENU_FUNC_USEPARAM, ID2P(LANG_BASE_SKIN), browse_folder, (void*)&sbs, NULL, Icon_Wps); +#if CONFIG_TUNER +MENUITEM_FUNCTION(browse_fms, MENU_FUNC_USEPARAM, + ID2P(LANG_FM_RADIO), + browse_folder, (void*)&fms, NULL, Icon_Wps); #endif +#endif MENUITEM_FUNCTION(browse_wps, MENU_FUNC_USEPARAM, ID2P(LANG_WHILE_PLAYING), browse_folder, (void*)&wps, NULL, Icon_Wps); @@ -256,7 +267,12 @@ MENUITEM_FUNCTION(browse_rsbs, MENU_FUNC_USEPARAM, ID2P(LANG_REMOTE_BASE_SKIN), browse_folder, (void*)&rsbs, NULL, Icon_Wps); +#if CONFIG_TUNER +MENUITEM_FUNCTION(browse_rfms, MENU_FUNC_USEPARAM, + ID2P(LANG_REMOTE_FMRADIO), + browse_folder, (void*)&rfms, NULL, Icon_Wps); #endif +#endif MENUITEM_SETTING(show_icons, &global_settings.show_icons, NULL); MENUITEM_FUNCTION(browse_themes, MENU_FUNC_USEPARAM, @@ -276,6 +292,12 @@ #ifdef HAVE_REMOTE_LCD &browse_rwps, #endif +#if CONFIG_TUNER + &browse_fms, +#ifdef HAVE_REMOTE_LCD + &browse_rfms, +#endif +#endif #ifdef HAVE_LCD_BITMAP &browse_sbs, #endif Index: apps/settings_list.c =================================================================== --- apps/settings_list.c (revision 24742) +++ 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 @@ -1427,7 +1428,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"), Index: apps/filetree.c =================================================================== --- apps/filetree.c (revision 24742) +++ apps/filetree.c (working copy) @@ -332,11 +332,17 @@ #ifdef HAVE_LCD_BITMAP (*c->dirfilter == SHOW_FONT && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FONT) || (*c->dirfilter == SHOW_SBS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_SBS) || +#if CONFIG_TUNER + (*c->dirfilter == SHOW_FMS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FMS) || #endif +#endif #ifdef HAVE_REMOTE_LCD (*c->dirfilter == SHOW_RWPS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RWPS) || (*c->dirfilter == SHOW_RSBS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RSBS) || +#if CONFIG_TUNER + (*c->dirfilter == SHOW_RFMS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RFMS) || #endif +#endif #if CONFIG_TUNER (*c->dirfilter == SHOW_FMR && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FMR) || #endif @@ -505,7 +511,19 @@ } break; + case FILE_ATTR_FMS: + splash(0, ID2P(LANG_WAIT)); + set_file(buf, (char *)global_settings.fms_file, MAX_FILENAME); + settings_apply_skins(); + break; +#ifdef HAVE_REMOTE_LCD + case FILE_ATTR_FMS: + splash(0, ID2P(LANG_WAIT)); + set_file(buf, (char *)global_settings.rfms_file, MAX_FILENAME); + settings_apply_skins(); + break; #endif +#endif #ifdef HAVE_LCD_BITMAP case FILE_ATTR_SBS: Index: apps/features.txt =================================================================== --- apps/features.txt (revision 24742) +++ apps/features.txt (working copy) @@ -124,7 +124,10 @@ #if CONFIG_TUNER != 0 radio +#ifdef HAVE_REMOTE_LCD +radio_remote #endif +#endif #if (CONFIG_KEYPAD == RECORDER_PAD) recorder_pad Index: apps/playback.c =================================================================== --- apps/playback.c (revision 24742) +++ apps/playback.c (working copy) @@ -138,7 +138,7 @@ static struct cuesheet *curr_cue = NULL; -#define MAX_MULTIPLE_AA 2 +#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT #ifdef HAVE_ALBUMART static struct albumart_slot { Index: apps/filetypes.c =================================================================== --- apps/filetypes.c (revision 24742) +++ apps/filetypes.c (working copy) @@ -114,6 +114,7 @@ #endif #if CONFIG_TUNER { "fmr", FILE_ATTR_FMR, Icon_Preset, LANG_FMR }, + { "fms", FILE_ATTR_FMS, Icon_Wps, VOICE_EXT_FMS }, #endif { "lng", FILE_ATTR_LNG, Icon_Language, LANG_LANGUAGE }, { "rock",FILE_ATTR_ROCK,Icon_Plugin, VOICE_EXT_ROCK }, @@ -129,6 +130,9 @@ #endif #ifdef HAVE_REMOTE_LCD { "rsbs", FILE_ATTR_RSBS, Icon_Wps, VOICE_EXT_RSBS }, +#if CONFIG_TUNER + { "rfms", FILE_ATTR_RFMS, Icon_Wps, VOICE_EXT_RFMS }, +#endif #endif #ifdef BOOTFILE_EXT { BOOTFILE_EXT, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ }, Index: apps/filetypes.h =================================================================== --- apps/filetypes.h (revision 24742) +++ apps/filetypes.h (working copy) @@ -44,6 +44,8 @@ #define FILE_ATTR_SBS 0x0F00 /* statusbar file */ #define FILE_ATTR_RSBS 0x1000 /* remote statusbar file */ #define FILE_ATTR_LUA 0x1100 /* Lua rockbox plugin */ +#define FILE_ATTR_FMS 0x1200 /* FM screen skin file */ +#define FILE_ATTR_RFMS 0x1300 /* FM screen skin file */ #define FILE_ATTR_MASK 0xFF00 /* which bits tree.c uses for file types */ struct filetype {