summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHristo Kovachev <bger@rockbox.org>2006-04-02 12:23:08 +0000
committerHristo Kovachev <bger@rockbox.org>2006-04-02 12:23:08 +0000
commit009853f40e8d3a7ca242e03b66083ccfbbf960f6 (patch)
treea54c878870d720412218fe316c233f10cbf1c3e8
parentb0b333f95ef8b86ac1392ecaad26a3453d7c8d65 (diff)
downloadrockbox-009853f40e8d3a7ca242e03b66083ccfbbf960f6.tar.gz
rockbox-009853f40e8d3a7ca242e03b66083ccfbbf960f6.zip
Patch #2711 by Alexander Spyridakis with some changes by me: adds load/save of presets to different files;
Also fix the preset menu context menu not working on the remote git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9425 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/filetree.c35
-rw-r--r--apps/lang/english.lang44
-rw-r--r--apps/recorder/icons.c1
-rw-r--r--apps/recorder/icons.h1
-rw-r--r--apps/recorder/radio.c369
-rw-r--r--apps/recorder/radio.h6
-rw-r--r--apps/settings.c40
-rw-r--r--apps/settings.h5
-rw-r--r--apps/tree.c3
-rw-r--r--apps/tree.h1
10 files changed, 419 insertions, 86 deletions
diff --git a/apps/filetree.c b/apps/filetree.c
index 08a33cd7b4..1a4d5ae432 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -45,6 +45,10 @@
45#include "keyboard.h" 45#include "keyboard.h"
46#endif 46#endif
47 47
48#ifdef CONFIG_TUNER
49#include "radio.h"
50#endif
51
48#ifndef SIMULATOR 52#ifndef SIMULATOR
49static int boot_size = 0; 53static int boot_size = 0;
50static int boot_cluster; 54static int boot_cluster;
@@ -278,6 +282,9 @@ int ft_load(struct tree_context* c, const char* tempdir)
278#ifdef HAVE_REMOTE_LCD 282#ifdef HAVE_REMOTE_LCD
279 (*c->dirfilter == SHOW_RWPS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_RWPS) || 283 (*c->dirfilter == SHOW_RWPS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_RWPS) ||
280#endif 284#endif
285#ifdef CONFIG_TUNER
286 (*c->dirfilter == SHOW_FMR && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_FMR) ||
287#endif
281 (*c->dirfilter == SHOW_CFG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_CFG) || 288 (*c->dirfilter == SHOW_CFG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_CFG) ||
282 (*c->dirfilter == SHOW_LNG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_LNG) || 289 (*c->dirfilter == SHOW_LNG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_LNG) ||
283 (*c->dirfilter == SHOW_MOD && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_MOD) || 290 (*c->dirfilter == SHOW_MOD && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_MOD) ||
@@ -418,6 +425,34 @@ int ft_enter(struct tree_context* c)
418 } 425 }
419 break; 426 break;
420 427
428#ifdef CONFIG_TUNER
429 /* fmr preset file */
430 case TREE_ATTR_FMR:
431
432 /* Preset inside the default folder. */
433 if(!strncasecmp(FMPRESET_PATH, buf, strlen(FMPRESET_PATH)))
434 {
435 set_file(buf, global_settings.fmr_file, MAX_FILENAME);
436 radio_load_presets(global_settings.fmr_file);
437 if(get_radio_status() != FMRADIO_PLAYING &&
438 get_radio_status() != FMRADIO_PAUSED)
439 radio_screen();
440 }
441 /*
442 * Preset outside default folder, we can choose such only
443 * if we are out of the radio screen, so the check for the
444 * radio status isn't neccessary
445 */
446 else
447 {
448 radio_load_presets(buf);
449 radio_screen();
450 }
451
452 break;
453#endif
454
455
421 /* wps config file */ 456 /* wps config file */
422 case TREE_ATTR_WPS: 457 case TREE_ATTR_WPS:
423 wps_data_load(gui_wps[0].data, buf, true); 458 wps_data_load(gui_wps[0].data, buf, true);
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 0a3a684146..58411fdba7 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3677,3 +3677,47 @@ desc: possible answers to resume question
3677eng: "(PLAY/STOP)" 3677eng: "(PLAY/STOP)"
3678voice: "" 3678voice: ""
3679new: 3679new:
3680
3681id: LANG_FM_NO_PRESETS
3682desc: error when preset list is empty
3683eng: "No presets"
3684voice: "No presets"
3685new:
3686
3687id: LANG_FM_PRESET_LOAD
3688desc: load preset list in fm radio
3689eng: "Load Preset List"
3690voice: "Load Preset List"
3691new:
3692
3693id: LANG_FM_PRESET_SAVE
3694desc: Save preset list in fm radio
3695eng: "Save Preset List"
3696voice: "Save Preset List"
3697new:
3698
3699id: LANG_FM_PRESET_CLEAR
3700desc: clear preset list in fm radio
3701eng: "Clear Preset List"
3702voice: "Clear Preset List"
3703new:
3704
3705id: LANG_FMR
3706desc: Used when you need to say Preset List, also voiced
3707eng: "Preset List"
3708voice: "Preset List"
3709new:
3710
3711id: LANG_FM_FIRST_AUTOSCAN
3712desc: When you run the radio without an fmr file in settings
3713eng: "No Settings found, AutoScan?"
3714voice: "No Settings found, AutoScan?"
3715new:
3716
3717id: LANG_FM_SAVE_CHANGES
3718desc: When you try to exit radio to confirm save
3719eng: "Save Changes?"
3720voice: "Save Changes?"
3721new:
3722
3723
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index 4b6df725f9..bbb117e568 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -47,6 +47,7 @@ const unsigned char bitmap_icons_6x8[][6] =
47 { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */ 47 { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */
48 { 0x0a, 0x0a, 0x5f, 0x4e, 0x24, 0x18 }, /* Plugin file */ 48 { 0x0a, 0x0a, 0x5f, 0x4e, 0x24, 0x18 }, /* Plugin file */
49 { 0xff, 0x81, 0xaf, 0xaa, 0x8c, 0xf8 }, /* Bookmark file */ 49 { 0xff, 0x81, 0xaf, 0xaa, 0x8c, 0xf8 }, /* Bookmark file */
50 { 0x5f, 0x45, 0x5b, 0x40, 0x55, 0x55 }, /* Preset file */
50 { 0x77, 0x55, 0x55, 0x55, 0x55, 0x77 }, /* Queued Item */ 51 { 0x77, 0x55, 0x55, 0x55, 0x55, 0x77 }, /* Queued Item */
51 { 0x3e, 0x41, 0x3e, 0x1c, 0x1c, 0x08 }, /* Moving Item */ 52 { 0x3e, 0x41, 0x3e, 0x1c, 0x1c, 0x08 }, /* Moving Item */
52 { 0x7f, 0x7f, 0x1c, 0x3e, 0x77, 0x63 }, /* Keyboard file */ 53 { 0x7f, 0x7f, 0x1c, 0x3e, 0x77, 0x63 }, /* Keyboard file */
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index 15747edeeb..d29b549245 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -54,6 +54,7 @@ enum icons_6x8 {
54 Icon_Config, 54 Icon_Config,
55 Icon_Plugin, 55 Icon_Plugin,
56 Icon_Bookmark, 56 Icon_Bookmark,
57 Icon_Preset,
57 Icon_Queued, 58 Icon_Queued,
58 Icon_Moving, 59 Icon_Moving,
59 Icon_Keyboard, 60 Icon_Keyboard,
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index 7cdfd51e6d..3fef9507c1 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -58,6 +58,8 @@
58#include "yesno.h" 58#include "yesno.h"
59#include "buttonbar.h" 59#include "buttonbar.h"
60#include "power.h" 60#include "power.h"
61#include "tree.h"
62#include "dir.h"
61 63
62#ifdef CONFIG_TUNER 64#ifdef CONFIG_TUNER
63 65
@@ -130,19 +132,24 @@ static int radio_mode = RADIO_SCAN_MODE;
130static int radio_status = FMRADIO_OFF; 132static int radio_status = FMRADIO_OFF;
131 133
132#define MAX_PRESETS 64 134#define MAX_PRESETS 64
133static bool presets_loaded = false; 135static bool presets_loaded = false, presets_changed = false;
134static struct fmstation presets[MAX_PRESETS]; 136static struct fmstation presets[MAX_PRESETS];
135 137
136static const char default_filename[] = "/.rockbox/fm-presets-default.fmr"; 138static char filepreset[MAX_PATH]; /* preset filename variable */
137 139
138static int preset_menu; /* The menu index of the preset list */ 140static int preset_menu; /* The menu index of the preset list */
139static struct menu_item preset_menu_items[MAX_PRESETS]; 141static struct menu_item preset_menu_items[MAX_PRESETS];
140static int num_presets; /* The number of presets in the preset list */ 142static int num_presets = 0; /* The number of presets in the preset list */
141 143
142void radio_load_presets(void); 144void radio_save_presets(void);
143bool handle_radio_presets(void); 145bool handle_radio_presets(void);
144bool radio_menu(void); 146bool radio_menu(void);
145bool radio_add_preset(void); 147bool radio_add_preset(void);
148bool save_preset_list(void);
149bool load_preset_list(void);
150bool clear_preset_list(void);
151
152static bool scan_presets(void);
146 153
147#ifdef SIMULATOR 154#ifdef SIMULATOR
148void radio_set(int setting, int value); 155void radio_set(int setting, int value);
@@ -160,6 +167,19 @@ int (*radio_get)(int setting);
160#endif 167#endif
161#endif 168#endif
162 169
170/* Function to manipulate all yesno dialogues.
171 This function needs the output text as an argument. */
172bool yesno_pop(char* text)
173{
174 int i;
175 char *lines[]={text};
176 struct text_message message={lines, 1};
177 bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
178 FOR_NB_SCREENS(i)
179 gui_textarea_clear(&screens[i]);
180 return ret;
181}
182
163void radio_init(void) 183void radio_init(void)
164{ 184{
165#ifndef SIMULATOR 185#ifndef SIMULATOR
@@ -185,7 +205,7 @@ int get_radio_status(void)
185} 205}
186 206
187void radio_stop(void) 207void radio_stop(void)
188{ 208{
189 radio_set(RADIO_MUTE, 1); 209 radio_set(RADIO_MUTE, 1);
190 radio_set(RADIO_SLEEP, 1); /* low power mode, if available */ 210 radio_set(RADIO_SLEEP, 1); /* low power mode, if available */
191 radio_status = FMRADIO_OFF; 211 radio_status = FMRADIO_OFF;
@@ -208,6 +228,8 @@ bool radio_hardware_present(void)
208static int find_preset(int freq) 228static int find_preset(int freq)
209{ 229{
210 int i; 230 int i;
231 if(num_presets < 1)
232 return -1;
211 for(i = 0;i < MAX_PRESETS;i++) 233 for(i = 0;i < MAX_PRESETS;i++)
212 { 234 {
213 if(freq == presets[i].frequency) 235 if(freq == presets[i].frequency)
@@ -253,31 +275,27 @@ void next_preset(int direction)
253{ 275{
254 if (num_presets < 1) 276 if (num_presets < 1)
255 return; 277 return;
256 curr_preset = find_preset(curr_freq); 278
257 if(curr_preset == -1) 279 if(curr_preset == -1)
258 curr_preset = find_closest_preset(curr_freq); 280 curr_preset = find_closest_preset(curr_freq);
259 else if ((curr_preset < (num_presets-1) && direction > 0) || 281
260 ((curr_preset > 0) && direction < 0)) 282 if(direction > 0)
261 { 283 if(curr_preset == num_presets - 1)
262 if (direction > 0) 284 curr_preset = 0;
263 curr_preset++;
264 else
265 curr_preset--;
266 }
267 else if (num_presets > 1)
268 {
269 if (direction > 0)
270 curr_preset = 0;
271 else 285 else
272 curr_preset = num_presets - 1; 286 curr_preset++;
273 }
274 else 287 else
275 return; 288 if(curr_preset == 0)
289 curr_preset = num_presets - 1;
290 else
291 curr_preset--;
292
276 curr_freq = presets[curr_preset].frequency; 293 curr_freq = presets[curr_preset].frequency;
277 radio_set(RADIO_FREQUENCY, curr_freq); 294 radio_set(RADIO_FREQUENCY, curr_freq);
278 remember_frequency(); 295 remember_frequency();
279} 296}
280 297
298
281bool radio_screen(void) 299bool radio_screen(void)
282{ 300{
283 char buf[MAX_PATH]; 301 char buf[MAX_PATH];
@@ -313,11 +331,12 @@ bool radio_screen(void)
313#endif 331#endif
314 /* always display status bar in radio screen for now */ 332 /* always display status bar in radio screen for now */
315 global_settings.statusbar = true; 333 global_settings.statusbar = true;
316 FOR_NB_SCREENS(i){ 334 FOR_NB_SCREENS(i)
335 {
317 gui_textarea_clear(&screens[i]); 336 gui_textarea_clear(&screens[i]);
318 screen_set_xmargin(&screens[i],0); 337 screen_set_xmargin(&screens[i],0);
319 } 338 }
320 339
321 gui_syncstatusbar_draw(&statusbars,true); 340 gui_syncstatusbar_draw(&statusbars,true);
322 341
323 fh = font_get(FONT_UI)->height; 342 fh = font_get(FONT_UI)->height;
@@ -326,21 +345,30 @@ bool radio_screen(void)
326 if(fh < 10) 345 if(fh < 10)
327 top_of_screen = 1; 346 top_of_screen = 1;
328 347
329 radio_load_presets(); 348 if(!num_presets)
330 349 {
350 memset(presets, 0, sizeof(presets));
351 radio_load_presets(global_settings.fmr_file);
352 }
353
331#ifndef SIMULATOR 354#ifndef SIMULATOR
332#if CONFIG_CODEC != SWCODEC 355#if CONFIG_CODEC != SWCODEC
333 if(rec_create_directory() > 0) 356 if(rec_create_directory() > 0)
334 have_recorded = true; 357 have_recorded = true;
335#endif 358#endif
336
337 audio_stop();
338 359
360 if(radio_status == FMRADIO_PLAYING_OUT)
361 radio_status = FMRADIO_PLAYING;
362 else if(radio_status == FMRADIO_PAUSED_OUT)
363 radio_status = FMRADIO_PAUSED;
364
365 if(radio_status == FMRADIO_OFF)
366 audio_stop();
367
339#if CONFIG_CODEC != SWCODEC 368#if CONFIG_CODEC != SWCODEC
340 audio_init_recording(); 369 audio_init_recording();
341 370
342 sound_settings_apply(); 371 sound_settings_apply();
343
344 /* Yes, we use the D/A for monitoring */ 372 /* Yes, we use the D/A for monitoring */
345 peak_meter_playback(true); 373 peak_meter_playback(true);
346 374
@@ -373,7 +401,8 @@ bool radio_screen(void)
373 401
374 curr_freq = global_settings.last_frequency * FREQ_STEP + MIN_FREQ; 402 curr_freq = global_settings.last_frequency * FREQ_STEP + MIN_FREQ;
375 403
376 if(radio_status != FMRADIO_PLAYING){ 404 if(radio_status == FMRADIO_OFF)
405 {
377 radio_power(true); 406 radio_power(true);
378 radio_set(RADIO_SLEEP, 0); /* wake up the tuner */ 407 radio_set(RADIO_SLEEP, 0); /* wake up the tuner */
379 radio_set(RADIO_FREQUENCY, curr_freq); 408 radio_set(RADIO_FREQUENCY, curr_freq);
@@ -391,6 +420,9 @@ bool radio_screen(void)
391 radio_set(RADIO_MUTE, 0); 420 radio_set(RADIO_MUTE, 0);
392 radio_status = FMRADIO_PLAYING; 421 radio_status = FMRADIO_PLAYING;
393 } 422 }
423
424 if(num_presets == 0 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN)))
425 scan_presets();
394 426
395 curr_preset = find_preset(curr_freq); 427 curr_preset = find_preset(curr_freq);
396 if(curr_preset != -1) 428 if(curr_preset != -1)
@@ -402,7 +434,7 @@ bool radio_screen(void)
402#endif 434#endif
403 435
404 cpu_idle_mode(true); 436 cpu_idle_mode(true);
405 437
406 while(!done) 438 while(!done)
407 { 439 {
408 if(search_dir) 440 if(search_dir)
@@ -463,6 +495,18 @@ bool radio_screen(void)
463#endif 495#endif
464 { 496 {
465 done = true; 497 done = true;
498 if(presets_changed)
499 {
500 if(yesno_pop(str(LANG_FM_SAVE_CHANGES)))
501 {
502 if(filepreset[0] == '\0')
503 save_preset_list();
504 else
505 radio_save_presets();
506 }
507 }
508 /* Clear the preset list on exit. */
509 clear_preset_list();
466 } 510 }
467 update_screen = true; 511 update_screen = true;
468 break; 512 break;
@@ -517,6 +561,21 @@ bool radio_screen(void)
517#endif 561#endif
518 keep_playing = true; 562 keep_playing = true;
519 done = true; 563 done = true;
564
565 if(presets_changed)
566 {
567 if(yesno_pop(str(LANG_FM_SAVE_CHANGES)))
568 {
569 if(filepreset[0] == '\0')
570 save_preset_list();
571 else
572 radio_save_presets();
573 }
574 }
575
576 /* Clear the preset list on exit. */
577 clear_preset_list();
578
520 break; 579 break;
521 580
522#ifdef BUTTON_RC_REW 581#ifdef BUTTON_RC_REW
@@ -563,6 +622,12 @@ bool radio_screen(void)
563 case BUTTON_LEFT | BUTTON_REPEAT: 622 case BUTTON_LEFT | BUTTON_REPEAT:
564 if(radio_mode == RADIO_SCAN_MODE) 623 if(radio_mode == RADIO_SCAN_MODE)
565 search_dir = -1; 624 search_dir = -1;
625 else
626 {
627 next_preset(-1);
628 update_screen = true;
629 }
630
566 break; 631 break;
567 632
568#ifdef BUTTON_RC_FF 633#ifdef BUTTON_RC_FF
@@ -571,6 +636,12 @@ bool radio_screen(void)
571 case BUTTON_RIGHT | BUTTON_REPEAT: 636 case BUTTON_RIGHT | BUTTON_REPEAT:
572 if(radio_mode == RADIO_SCAN_MODE) 637 if(radio_mode == RADIO_SCAN_MODE)
573 search_dir = 1; 638 search_dir = 1;
639 else
640 {
641 next_preset(1);
642 update_screen = true;
643 }
644
574 break; 645 break;
575 646
576#ifdef BUTTON_RC_VOL_UP 647#ifdef BUTTON_RC_VOL_UP
@@ -671,16 +742,25 @@ bool radio_screen(void)
671 ) 742 )
672 break; 743 break;
673#endif 744#endif
674 if(num_presets < 1){ 745 if(num_presets < 1)
746 {
675 gui_syncsplash(HZ, true, str(LANG_FM_NO_PRESETS)); 747 gui_syncsplash(HZ, true, str(LANG_FM_NO_PRESETS));
676 update_screen = true; 748 update_screen = true;
749 FOR_NB_SCREENS(i)
750 {
751 gui_textarea_clear(&screens[i]);
752 screen_set_xmargin(&screens[i],0);
753 gui_textarea_update(&screens[i]);
754 }
755
677 break; 756 break;
678 } 757 }
679 handle_radio_presets(); 758 handle_radio_presets();
680 curr_preset = find_preset(curr_freq); 759 FOR_NB_SCREENS(i)
681 FOR_NB_SCREENS(i){ 760 {
682 gui_textarea_clear(&screens[i]); 761 gui_textarea_clear(&screens[i]);
683 screen_set_xmargin(&screens[i],0); 762 screen_set_xmargin(&screens[i],0);
763 gui_textarea_update(&screens[i]);
684 } 764 }
685#ifdef HAS_BUTTONBAR 765#ifdef HAS_BUTTONBAR
686 gui_buttonbar_set(&buttonbar, 766 gui_buttonbar_set(&buttonbar,
@@ -729,10 +809,14 @@ bool radio_screen(void)
729 ) 809 )
730 { 810 {
731 if(radio_mode == RADIO_SCAN_MODE) 811 if(radio_mode == RADIO_SCAN_MODE)
732 radio_mode = RADIO_PRESET_MODE; 812 {
813 /* Force scan mode if there are no presets. */
814 if(num_presets > 0)
815 radio_mode = RADIO_PRESET_MODE;
816 }
733 else 817 else
734 radio_mode = RADIO_SCAN_MODE; 818 radio_mode = RADIO_SCAN_MODE;
735 update_screen = true; 819 update_screen = true;
736 } 820 }
737 break; 821 break;
738#endif 822#endif
@@ -899,26 +983,34 @@ bool radio_screen(void)
899#endif 983#endif
900 984
901 sound_settings_apply(); 985 sound_settings_apply();
902 986#endif /* SIMULATOR */
903 if(keep_playing) 987 if(keep_playing)
904 { 988 {
989/* Catch FMRADIO_PLAYING_OUT status for the sim. */
990#ifndef SIMULATOR
905#if CONFIG_CODEC != SWCODEC 991#if CONFIG_CODEC != SWCODEC
906 /* Enable the Left and right A/D Converter */ 992 /* Enable the Left and right A/D Converter */
907 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), 993 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
908 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); 994 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
909 mas_codec_writereg(6, 0x4000); 995 mas_codec_writereg(6, 0x4000);
910#endif 996#endif
997#endif
998 if(radio_status == FMRADIO_PAUSED)
999 radio_status = FMRADIO_PAUSED_OUT;
1000 else
1001 radio_status = FMRADIO_PLAYING_OUT;
1002
911 } 1003 }
912 else 1004 else
913 { 1005 {
914 radio_stop(); 1006 radio_stop();
1007#ifndef SIMULATOR /* SIMULATOR. Catch FMRADIO_OFF status for the sim. */
915#if CONFIG_CODEC == SWCODEC 1008#if CONFIG_CODEC == SWCODEC
916 pcm_rec_mux(0); /* Line In */ 1009 pcm_rec_mux(0); /* Line In */
917 peak_meter_enabled = true; 1010 peak_meter_enabled = true;
918#endif 1011#endif
1012#endif /* SIMULATOR */
919 } 1013 }
920
921#endif
922 1014
923 cpu_idle_mode(false); 1015 cpu_idle_mode(false);
924 1016
@@ -932,8 +1024,8 @@ void radio_save_presets(void)
932{ 1024{
933 int fd; 1025 int fd;
934 int i; 1026 int i;
935 1027
936 fd = creat(default_filename, O_WRONLY); 1028 fd = creat(filepreset, O_WRONLY);
937 if(fd >= 0) 1029 if(fd >= 0)
938 { 1030 {
939 for(i = 0;i < num_presets;i++) 1031 for(i = 0;i < num_presets;i++)
@@ -941,14 +1033,18 @@ void radio_save_presets(void)
941 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name); 1033 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
942 } 1034 }
943 close(fd); 1035 close(fd);
1036
1037 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1038 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1039 presets_changed = false;
944 } 1040 }
945 else 1041 else
946 { 1042 {
947 gui_syncsplash(HZ*2, true, str(LANG_FM_PRESET_SAVE_FAILED)); 1043 gui_syncsplash(HZ, true, str(LANG_FM_PRESET_SAVE_FAILED));
948 } 1044 }
949} 1045}
950 1046
951void radio_load_presets(void) 1047void radio_load_presets(char *filename)
952{ 1048{
953 int fd; 1049 int fd;
954 int rc; 1050 int rc;
@@ -958,38 +1054,58 @@ void radio_load_presets(void)
958 bool done = false; 1054 bool done = false;
959 int f; 1055 int f;
960 1056
961 if(!presets_loaded) 1057
962 { 1058 memset(presets, 0, sizeof(presets));
963 memset(presets, 0, sizeof(presets)); 1059 num_presets = 0;
964 num_presets = 0; 1060
1061/* No Preset in configuration. */
1062 if(filename[0] == '\0')
1063 {
1064 filepreset[0] = '\0';
1065 return;
1066 }
1067/* Temporary preset, loaded until player shuts down. */
1068 else if(filename[0] == '/')
1069 strncpy(filepreset, filename, sizeof(filepreset));
1070/* Preset from default directory. */
1071 else
1072 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1073 FMPRESET_PATH, filename);
965 1074
966 fd = open(default_filename, O_RDONLY); 1075 fd = open(filepreset, O_RDONLY);
967 if(fd >= 0) 1076 if(fd >= 0)
1077 {
1078 while(!done && num_presets < MAX_PRESETS)
968 { 1079 {
969 while(!done && num_presets < MAX_PRESETS) 1080 rc = read_line(fd, buf, 128);
1081 if(rc > 0)
970 { 1082 {
971 rc = read_line(fd, buf, 128); 1083 if(settings_parseline(buf, &freq, &name))
972 if(rc > 0)
973 { 1084 {
974 if(settings_parseline(buf, &freq, &name)) 1085 f = atoi(freq);
1086 if(f) /* For backwards compatibility */
975 { 1087 {
976 f = atoi(freq); 1088 presets[num_presets].frequency = f;
977 if(f) /* For backwards compatibility */ 1089 strncpy(presets[num_presets].name, name, 27);
978 { 1090 presets[num_presets].name[27] = 0;
979 presets[num_presets].frequency = f; 1091 num_presets++;
980 strncpy(presets[num_presets].name, name, 27);
981 presets[num_presets].name[27] = 0;
982 num_presets++;
983 }
984 } 1092 }
985 } 1093 }
986 else
987 done = true;
988 } 1094 }
989 close(fd); 1095 else
1096 done = true;
990 } 1097 }
1098 close(fd);
991 } 1099 }
992 presets_loaded = true; 1100 else /* invalid file name? */
1101 filepreset[0] = '\0';
1102
1103 if(num_presets > 0)
1104 presets_loaded = true;
1105 else
1106 presets_loaded = false;
1107
1108 presets_changed = false;
993} 1109}
994 1110
995static void rebuild_preset_menu(void) 1111static void rebuild_preset_menu(void)
@@ -1022,12 +1138,14 @@ bool radio_add_preset(void)
1022 rebuild_preset_menu(); 1138 rebuild_preset_menu();
1023#endif 1139#endif
1024 num_presets++; 1140 num_presets++;
1025 radio_save_presets(); 1141 presets_changed = true;
1142 if(num_presets > 0)
1143 presets_loaded = true;
1026 } 1144 }
1027 } 1145 }
1028 else 1146 else
1029 { 1147 {
1030 gui_syncsplash(HZ*2, true, str(LANG_FM_NO_FREE_PRESETS)); 1148 gui_syncsplash(HZ, true, str(LANG_FM_NO_FREE_PRESETS));
1031 } 1149 }
1032 return true; 1150 return true;
1033} 1151}
@@ -1063,7 +1181,7 @@ static bool radio_edit_preset(void)
1063 { 1181 {
1064 buf[27] = 0; 1182 buf[27] = 0;
1065 strcpy(presets[pos].name, buf); 1183 strcpy(presets[pos].name, buf);
1066 radio_save_presets(); 1184 presets_changed = true;
1067 } 1185 }
1068 return true; 1186 return true;
1069} 1187}
@@ -1081,11 +1199,64 @@ bool radio_delete_preset(void)
1081 /* We must still rebuild the menu table, since the 1199 /* We must still rebuild the menu table, since the
1082 item name pointers must be updated */ 1200 item name pointers must be updated */
1083 rebuild_preset_menu(); 1201 rebuild_preset_menu();
1084 radio_save_presets(); 1202
1085 1203 /* Don't ask to save when all presets are deleted. */
1204 if(num_presets > 0)
1205 presets_changed = true;
1206 else
1207 {
1208 presets_changed = false;
1209 /* The preset list will be cleared, switch to Scan Mode. */
1210 radio_mode = RADIO_SCAN_MODE;
1211 presets_loaded = false;
1212 }
1213
1086 return true; /* Make the menu return immediately */ 1214 return true; /* Make the menu return immediately */
1087} 1215}
1088 1216
1217bool load_preset_list(void)
1218{
1219 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1220}
1221
1222bool save_preset_list(void)
1223{
1224 if(num_presets != 0)
1225 {
1226 if(!opendir(FMPRESET_PATH)) /* Check if there is preset folder */
1227 mkdir(FMPRESET_PATH, 0);
1228
1229 create_numbered_filename(filepreset, FMPRESET_PATH, "preset", ".fmr", 2);
1230
1231 if (!kbd_input(filepreset, sizeof(filepreset)))
1232 radio_save_presets();
1233 }
1234 else
1235 gui_syncsplash(HZ,true,str(LANG_FM_NO_PRESETS));
1236
1237 return true;
1238}
1239
1240bool clear_preset_list(void)
1241{
1242 int i;
1243
1244 /* Clear all the preset entries */
1245 for(i = 0;i <= num_presets;i++){
1246 presets[i].name[0] = '\0';
1247 presets[i].frequency = 0;
1248 }
1249
1250 num_presets = 0;
1251 presets_loaded = false;
1252 /* The preset list will be cleared switch to Scan Mode. */
1253 radio_mode = RADIO_SCAN_MODE;
1254
1255 presets_changed = false; /* Don't ask to save when clearing the list. */
1256
1257 return true;
1258}
1259
1089/* little menu on what to do with a preset entry */ 1260/* little menu on what to do with a preset entry */
1090bool handle_radio_presets_menu(void) 1261bool handle_radio_presets_menu(void)
1091{ 1262{
@@ -1128,6 +1299,12 @@ int handle_radio_presets_cb(int key, int m)
1128#ifdef FM_PRESET_ACTION 1299#ifdef FM_PRESET_ACTION
1129 case FM_PRESET_ACTION: 1300 case FM_PRESET_ACTION:
1130#endif 1301#endif
1302#ifdef MENU_RC_ENTER
1303 case MENU_RC_ENTER | BUTTON_REPEAT:
1304#endif
1305#ifdef MENU_RC_ENTER2
1306 case MENU_RC_ENTER2 | BUTTON_REPEAT:
1307#endif
1131#ifdef MENU_ENTER2 1308#ifdef MENU_ENTER2
1132 case MENU_ENTER2 | BUTTON_REPEAT: 1309 case MENU_ENTER2 | BUTTON_REPEAT:
1133#endif 1310#endif
@@ -1142,17 +1319,31 @@ int handle_radio_presets_cb(int key, int m)
1142 key = BUTTON_NONE; 1319 key = BUTTON_NONE;
1143 break; 1320 break;
1144 } 1321 }
1322#ifdef MENU_RC_ENTER
1323 case MENU_RC_ENTER | BUTTON_REL:
1324#endif
1325#ifdef MENU_RC_ENTER2
1326 case MENU_RC_ENTER2 | BUTTON_REL:
1327#endif
1145#ifdef MENU_ENTER2 1328#ifdef MENU_ENTER2
1146 case MENU_ENTER2 | BUTTON_REL: 1329 case MENU_ENTER2 | BUTTON_REL:
1147#endif 1330#endif
1148 case MENU_ENTER | BUTTON_REL: 1331 case MENU_ENTER | BUTTON_REL:
1149 key = MENU_ENTER; /* fake enter for short press */ 1332 key = MENU_ENTER; /* fake enter for short press */
1150 break; 1333 break;
1334
1335/* ignore down events */
1336#ifdef MENU_RC_ENTER
1337 case MENU_RC_ENTER:
1338#endif
1339#ifdef MENU_RC_ENTER2
1340 case MENU_RC_ENTER2:
1341#endif
1151 1342
1152#ifdef MENU_ENTER2 1343#ifdef MENU_ENTER2
1153 case MENU_ENTER2: 1344 case MENU_ENTER2:
1154#endif 1345#endif
1155 case MENU_ENTER: /* ignore down event */ 1346 case MENU_ENTER:
1156 /* Ignore the release events */ 1347 /* Ignore the release events */
1157#ifdef FM_PRESET_ADD 1348#ifdef FM_PRESET_ADD
1158 case FM_PRESET_ADD | BUTTON_REL: 1349 case FM_PRESET_ADD | BUTTON_REL:
@@ -1267,18 +1458,19 @@ static bool toggle_radio_mode(void)
1267 1458
1268static bool scan_presets(void) 1459static bool scan_presets(void)
1269{ 1460{
1270 bool tuned = false; 1461 bool tuned = false, do_scan = true;
1271 char buf[27]; 1462 char buf[27];
1272 int freq, i; 1463 int freq, i;
1273 char *lines[]={str(LANG_FM_CLEAR_PRESETS)}; 1464
1274 struct text_message message={lines, 1}; 1465 if(num_presets > 0) /* Do that to avoid 2 questions. */
1275 1466 do_scan = yesno_pop(str(LANG_FM_CLEAR_PRESETS));
1276 if(gui_syncyesno_run(&message,NULL,NULL)==YESNO_YES){ 1467
1277 FOR_NB_SCREENS(i) 1468 if(do_scan)
1278 gui_textarea_clear(&screens[i]); 1469 {
1279 curr_freq = MIN_FREQ; 1470 curr_freq = MIN_FREQ;
1280 num_presets = 0; 1471 num_presets = 0;
1281 while(curr_freq <= MAX_FREQ){ 1472 while(curr_freq <= MAX_FREQ)
1473 {
1282 if (num_presets >= MAX_PRESETS) 1474 if (num_presets >= MAX_PRESETS)
1283 break; 1475 break;
1284 1476
@@ -1309,14 +1501,25 @@ static bool scan_presets(void)
1309 1501
1310 } 1502 }
1311 1503
1312 radio_save_presets(); 1504 presets_changed = true;
1505
1506 FOR_NB_SCREENS(i)
1507 {
1508 gui_textarea_clear(&screens[i]);
1509 screen_set_xmargin(&screens[i],0);
1510 gui_textarea_update(&screens[i]);
1511 }
1313 1512
1314 if(num_presets > 0 ){ 1513 if(num_presets > 0 )
1514 {
1315 curr_freq = presets[0].frequency; 1515 curr_freq = presets[0].frequency;
1316 radio_set(RADIO_FREQUENCY, curr_freq); 1516 radio_set(RADIO_FREQUENCY, curr_freq);
1317 remember_frequency(); 1517 remember_frequency();
1318 radio_mode = RADIO_PRESET_MODE; 1518 radio_mode = RADIO_PRESET_MODE;
1519 presets_loaded = true;
1319 } 1520 }
1521 else
1522 presets_loaded = false;
1320 } 1523 }
1321 return true; 1524 return true;
1322} 1525}
@@ -1363,6 +1566,10 @@ bool radio_menu(void)
1363#ifndef FM_PRESET_ADD 1566#ifndef FM_PRESET_ADD
1364 { ID2P(LANG_FM_ADD_PRESET) , radio_add_preset }, 1567 { ID2P(LANG_FM_ADD_PRESET) , radio_add_preset },
1365#endif 1568#endif
1569 { ID2P(LANG_FM_PRESET_LOAD) , load_preset_list },
1570 { ID2P(LANG_FM_PRESET_SAVE) , save_preset_list },
1571 { ID2P(LANG_FM_PRESET_CLEAR) , clear_preset_list },
1572
1366 { monomode_menu_string , toggle_mono_mode }, 1573 { monomode_menu_string , toggle_mono_mode },
1367#ifndef FM_MODE 1574#ifndef FM_MODE
1368 { radiomode_menu_string , toggle_radio_mode }, 1575 { radiomode_menu_string , toggle_radio_mode },
diff --git a/apps/recorder/radio.h b/apps/recorder/radio.h
index b4f4da2f4f..4763d117f8 100644
--- a/apps/recorder/radio.h
+++ b/apps/recorder/radio.h
@@ -18,12 +18,16 @@
18 ****************************************************************************/ 18 ****************************************************************************/
19#ifndef RADIO_H 19#ifndef RADIO_H
20#define RADIO_H 20#define RADIO_H
21#define FMPRESET_PATH ROCKBOX_DIR "/fmpresets"
21 22
22#define FMRADIO_OFF 0 23#define FMRADIO_OFF 0
23#define FMRADIO_PLAYING 1 24#define FMRADIO_PLAYING 1
24#define FMRADIO_PAUSED 2 25#define FMRADIO_PLAYING_OUT 2
26#define FMRADIO_PAUSED 3
27#define FMRADIO_PAUSED_OUT 4
25 28
26#ifdef CONFIG_TUNER 29#ifdef CONFIG_TUNER
30void radio_load_presets(char *filename);
27void radio_init(void); 31void radio_init(void);
28bool radio_screen(void); 32bool radio_screen(void);
29void radio_stop(void); 33void radio_stop(void);
diff --git a/apps/settings.c b/apps/settings.c
index 7d7b2295f5..cbd39335f1 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -77,6 +77,10 @@
77#include "backdrop.h" 77#include "backdrop.h"
78#endif 78#endif
79 79
80#ifdef CONFIG_TUNER
81#include "radio.h"
82#endif
83
80#if CONFIG_CODEC == MAS3507D 84#if CONFIG_CODEC == MAS3507D
81void dac_line_in(bool enable); 85void dac_line_in(bool enable);
82#endif 86#endif
@@ -150,6 +154,7 @@ modified unless the header & checksum test fails.
150Rest of config block, only saved to disk: 154Rest of config block, only saved to disk:
1510x2C start of 2nd bit-table 1550x2C start of 2nd bit-table
152... 156...
1570xA4 (char[20]) FMR Preset file
1530xB8 (char[20]) WPS file 1580xB8 (char[20]) WPS file
1540xCC (char[20]) Lang file 1590xCC (char[20]) Lang file
1550xE0 (char[20]) Font file 1600xE0 (char[20]) Font file
@@ -912,6 +917,13 @@ int settings_save( void )
912 MAX_FILENAME); 917 MAX_FILENAME);
913 i+= MAX_FILENAME; 918 i+= MAX_FILENAME;
914#endif 919#endif
920
921#ifdef CONFIG_TUNER
922 strncpy((char *)&config_block[i], (char *)global_settings.fmr_file,
923 MAX_FILENAME);
924 i+= MAX_FILENAME;
925#endif
926
915#ifdef HAVE_LCD_COLOR 927#ifdef HAVE_LCD_COLOR
916 strncpy((char *)&config_block[i], (char *)global_settings.backdrop_file, 928 strncpy((char *)&config_block[i], (char *)global_settings.backdrop_file,
917 MAX_FILENAME); 929 MAX_FILENAME);
@@ -1263,6 +1275,13 @@ void settings_load(int which)
1263 MAX_FILENAME); 1275 MAX_FILENAME);
1264 i+= MAX_FILENAME; 1276 i+= MAX_FILENAME;
1265#endif 1277#endif
1278
1279#ifdef CONFIG_TUNER
1280 strncpy((char *)global_settings.fmr_file, (char *)&config_block[i],
1281 MAX_FILENAME);
1282 i+= MAX_FILENAME;
1283#endif
1284
1266#ifdef HAVE_LCD_COLOR 1285#ifdef HAVE_LCD_COLOR
1267 strncpy((char *)global_settings.backdrop_file, (char *)&config_block[i], 1286 strncpy((char *)global_settings.backdrop_file, (char *)&config_block[i],
1268 MAX_FILENAME); 1287 MAX_FILENAME);
@@ -1433,6 +1452,11 @@ bool settings_load_config(const char* file)
1433 talk_init(); /* use voice of same language */ 1452 talk_init(); /* use voice of same language */
1434 } 1453 }
1435 } 1454 }
1455#ifdef CONFIG_TUNER
1456 else if (!strcasecmp(name, "fmr")) {
1457 set_file(value, global_settings.fmr_file, MAX_FILENAME);
1458 }
1459#endif
1436#ifdef HAVE_LCD_BITMAP 1460#ifdef HAVE_LCD_BITMAP
1437 else if (!strcasecmp(name, "font")) { 1461 else if (!strcasecmp(name, "font")) {
1438 if (font_load(value)) 1462 if (font_load(value))
@@ -1580,9 +1604,9 @@ bool settings_save_config(void)
1580 } 1604 }
1581 1605
1582 fdprintf(fd, "# .cfg file created by rockbox %s - " 1606 fdprintf(fd, "# .cfg file created by rockbox %s - "
1583 "http://www.rockbox.org\r\n#\r\n" 1607 "http://www.rockbox.org\r\n#\r\n#\r\n# wps / rwps / language"
1584 "#\r\n# wps / language / font \r\n#\r\n", appsversion); 1608 " / font / fmpreset / backdrop \r\n#\r\n", appsversion);
1585 1609
1586 if (global_settings.wps_file[0] != 0) 1610 if (global_settings.wps_file[0] != 0)
1587 fdprintf(fd, "wps: %s/%s.wps\r\n", WPS_DIR, 1611 fdprintf(fd, "wps: %s/%s.wps\r\n", WPS_DIR,
1588 global_settings.wps_file); 1612 global_settings.wps_file);
@@ -1609,6 +1633,12 @@ bool settings_save_config(void)
1609 global_settings.backdrop_file); 1633 global_settings.backdrop_file);
1610#endif 1634#endif
1611 1635
1636#ifdef CONFIG_TUNER
1637 if (global_settings.fmr_file[0] != 0)
1638 fdprintf(fd, "fmr: %s/%s.fmr\r\n", FMPRESET_PATH,
1639 global_settings.fmr_file);
1640#endif
1641
1612#ifdef HAVE_LCD_BITMAP 1642#ifdef HAVE_LCD_BITMAP
1613 if (global_settings.kbd_file[0] != 0) 1643 if (global_settings.kbd_file[0] != 0)
1614 fdprintf(fd, "keyboard: %s/%s.kbd\r\n", ROCKBOX_DIR, 1644 fdprintf(fd, "keyboard: %s/%s.kbd\r\n", ROCKBOX_DIR,
@@ -1685,6 +1715,10 @@ void settings_reset(void) {
1685 global_settings.superbass = sound_default(SOUND_SUPERBASS); 1715 global_settings.superbass = sound_default(SOUND_SUPERBASS);
1686#endif 1716#endif
1687 global_settings.contrast = lcd_default_contrast(); 1717 global_settings.contrast = lcd_default_contrast();
1718
1719#ifdef CONFIG_TUNER
1720 global_settings.fmr_file[0] = '\0';
1721#endif
1688 global_settings.wps_file[0] = '\0'; 1722 global_settings.wps_file[0] = '\0';
1689#ifdef HAVE_REMOTE_LCD 1723#ifdef HAVE_REMOTE_LCD
1690 global_settings.rwps_file[0] = '\0'; 1724 global_settings.rwps_file[0] = '\0';
diff --git a/apps/settings.h b/apps/settings.h
index 498c880319..1266fed1c4 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -291,6 +291,9 @@ struct user_settings
291 int resume_seed; /* shuffle seed (-1=no resume shuffle 0=sorted 291 int resume_seed; /* shuffle seed (-1=no resume shuffle 0=sorted
292 >0=shuffled) */ 292 >0=shuffled) */
293 293
294#ifdef CONFIG_TUNER
295 unsigned char fmr_file[MAX_FILENAME+1]; /* last fmr preset */
296#endif
294 unsigned char font_file[MAX_FILENAME+1]; /* last font */ 297 unsigned char font_file[MAX_FILENAME+1]; /* last font */
295 unsigned char wps_file[MAX_FILENAME+1]; /* last wps */ 298 unsigned char wps_file[MAX_FILENAME+1]; /* last wps */
296 unsigned char lang_file[MAX_FILENAME+1]; /* last language */ 299 unsigned char lang_file[MAX_FILENAME+1]; /* last language */
@@ -571,7 +574,7 @@ enum
571 * must be added after NUM_FILTER_MODES. */ 574 * must be added after NUM_FILTER_MODES. */
572enum { SHOW_ALL, SHOW_SUPPORTED, SHOW_MUSIC, SHOW_PLAYLIST, SHOW_ID3DB, 575enum { SHOW_ALL, SHOW_SUPPORTED, SHOW_MUSIC, SHOW_PLAYLIST, SHOW_ID3DB,
573 NUM_FILTER_MODES, 576 NUM_FILTER_MODES,
574 SHOW_WPS, SHOW_RWPS, SHOW_CFG, SHOW_LNG, SHOW_MOD, SHOW_FONT, SHOW_PLUGINS}; 577 SHOW_WPS, SHOW_RWPS, SHOW_FMR, SHOW_CFG, SHOW_LNG, SHOW_MOD, SHOW_FONT, SHOW_PLUGINS};
575 578
576/* recursive dir insert options */ 579/* recursive dir insert options */
577enum { RECURSE_OFF, RECURSE_ON, RECURSE_ASK }; 580enum { RECURSE_OFF, RECURSE_ON, RECURSE_ASK };
diff --git a/apps/tree.c b/apps/tree.c
index 5fe94cb290..f492f8c8bd 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -106,6 +106,9 @@ const struct filetype filetypes[] = {
106#ifdef HAVE_LCD_COLOR 106#ifdef HAVE_LCD_COLOR
107 { "bmp", TREE_ATTR_BMP, Icon_Wps, VOICE_EXT_WPS }, 107 { "bmp", TREE_ATTR_BMP, Icon_Wps, VOICE_EXT_WPS },
108#endif 108#endif
109#ifdef CONFIG_TUNER
110 { "fmr", TREE_ATTR_FMR, Icon_Preset, LANG_FMR },
111#endif
109 { "lng", TREE_ATTR_LNG, Icon_Language, LANG_LANGUAGE }, 112 { "lng", TREE_ATTR_LNG, Icon_Language, LANG_LANGUAGE },
110 { "rock",TREE_ATTR_ROCK,Icon_Plugin, VOICE_EXT_ROCK }, 113 { "rock",TREE_ATTR_ROCK,Icon_Plugin, VOICE_EXT_ROCK },
111#ifdef HAVE_LCD_BITMAP 114#ifdef HAVE_LCD_BITMAP
diff --git a/apps/tree.h b/apps/tree.h
index c632ccdb52..ae97351dbb 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -243,6 +243,7 @@ struct tree_context {
243#define TREE_ATTR_RWPS 0x1000 /* remote-wps config file */ 243#define TREE_ATTR_RWPS 0x1000 /* remote-wps config file */
244#define TREE_ATTR_BMP 0x1100 /* backdrop bmp file */ 244#define TREE_ATTR_BMP 0x1100 /* backdrop bmp file */
245#define TREE_ATTR_KBD 0x1200 /* keyboard file */ 245#define TREE_ATTR_KBD 0x1200 /* keyboard file */
246#define TREE_ATTR_FMR 0x1300 /* preset file */
246#define TREE_ATTR_MASK 0xFF00 /* which bits tree.c uses for file types */ 247#define TREE_ATTR_MASK 0xFF00 /* which bits tree.c uses for file types */
247 248
248void tree_get_filetypes(const struct filetype**, int*); 249void tree_get_filetypes(const struct filetype**, int*);