? h120
? h300
? h300-sim
? rec
? uisimulator
? apps/settings_list.c
? apps/settings_list.h
? apps/menus/display_menu.c
? apps/menus/exported_menus.h
? apps/menus/main_menu.c
? apps/menus/playback_menu.c
? apps/menus/playlist_menu.c
? apps/menus/recording_menu.c
? apps/menus/sound_menu.c
? tools/codepages
? tools/mkboot
? tools/rdf2binary
? tools/uclpack
Index: apps/FILES
===================================================================
RCS file: /cvsroot/rockbox/apps/FILES,v
retrieving revision 1.51
diff -u -r1.51 FILES
--- apps/FILES	3 Nov 2006 18:22:28 -0000	1.51
+++ apps/FILES	30 Nov 2006 07:20:52 -0000
@@ -5,6 +5,7 @@
 gui/*.[ch]
 recorder/*.[ch]
 player/*.[ch]
+menus/*.[ch]
 lang/*.lang
 eqs/*.cfg
 bitmaps/mono/*
Index: apps/SOURCES
===================================================================
RCS file: /cvsroot/rockbox/apps/SOURCES,v
retrieving revision 1.58
diff -u -r1.58 SOURCES
--- apps/SOURCES	19 Nov 2006 14:11:40 -0000	1.58
+++ apps/SOURCES	30 Nov 2006 07:20:52 -0000
@@ -9,19 +9,24 @@
 filetypes.c
 language.c
 main.c
-main_menu.c
 menu.c
+
+menus/main_menu.c
+menus/playlist_menu.c
+menus/sound_menu.c
+menus/recording_menu.c
+menus/playback_menu.c
+menus/display_menu.c
+
 misc.c
 onplay.c
 playlist.c
 playlist_catalog.c
-playlist_menu.c
 playlist_viewer.c
 plugin.c
 screens.c
 settings.c
-settings_menu.c
-sound_menu.c
+settings_list.c
 status.c
 #if !defined(SIMULATOR) || CONFIG_CODEC == SWCODEC
 talk.c
Index: apps/action.h
===================================================================
RCS file: /cvsroot/rockbox/apps/action.h,v
retrieving revision 1.16
diff -u -r1.16 action.h
--- apps/action.h	16 Nov 2006 02:53:40 -0000	1.16
+++ apps/action.h	30 Nov 2006 07:20:53 -0000
@@ -150,6 +150,10 @@
     ACTION_REC_F3,
     
     /* main menu */
+    ACTION_MENU_WPS, /* return to the wps */
+    ACTION_REQUEST_MENUITEM, /* set to callback before displaying items, returning ACTION_EXIT_MENUITEM will not show the menu item */
+    ACTION_ENTER_MENUITEM, /* sent to the menu callback the firs time an item is being enetred */
+    ACTION_EXIT_MENUITEM,  /* menu callback returns this when it is called to back out of the menu item */
     
     /* id3db */
     
Index: apps/database.c
===================================================================
RCS file: /cvsroot/rockbox/apps/database.c,v
retrieving revision 1.25
diff -u -r1.25 database.c
--- apps/database.c	5 Dec 2005 23:37:14 -0000	1.25
+++ apps/database.c	30 Nov 2006 07:20:54 -0000
@@ -31,7 +31,6 @@
 #include "debug.h"
 #include "button.h"
 #include "menu.h"
-#include "main_menu.h"
 #include "mpeg.h"
 #include "misc.h"
 #include "ata.h"
Index: apps/dbtree.c
===================================================================
RCS file: /cvsroot/rockbox/apps/dbtree.c,v
retrieving revision 1.29
diff -u -r1.29 dbtree.c
--- apps/dbtree.c	1 Apr 2006 13:36:33 -0000	1.29
+++ apps/dbtree.c	30 Nov 2006 07:20:57 -0000
@@ -31,7 +31,6 @@
 #include "debug.h"
 #include "button.h"
 #include "menu.h"
-#include "main_menu.h"
 #include "mpeg.h"
 #include "misc.h"
 #include "ata.h"
Index: apps/enc_config.c
===================================================================
RCS file: /cvsroot/rockbox/apps/enc_config.c,v
retrieving revision 1.2
diff -u -r1.2 enc_config.c
--- apps/enc_config.c	24 Nov 2006 19:49:02 -0000	1.2
+++ apps/enc_config.c	30 Nov 2006 07:20:57 -0000
@@ -94,26 +94,9 @@
 /* mp3_enc: return the default configuration */
 static void mp3_enc_default_config(struct encoder_config *cfg)
 {
-    cfg->mp3_enc.bitrate = 128; /* default that works for all types */
+    cfg->mp3_enc.bitrate = MP3_ENC_BITRATE_DEFAULT;
 } /* mp3_enc_default_config */
 
-static void mp3_enc_convert_config(struct encoder_config *cfg,
-                                   bool to_encoder)
-{
-    if (to_encoder)
-    {
-        if ((unsigned)global_settings.mp3_enc_config.bitrate > MP3_ENC_NUM_BITR)
-            global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT;
-        cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate];
-    }
-    else
-    {
-        global_settings.mp3_enc_config.bitrate =
-            round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
-                                  MP3_ENC_NUM_BITR, false);
-    }
-} /* mp3_enc_convert_config */
-
 /* mp3_enc: show the bitrate setting options */
 static bool mp3_enc_bitrate(struct encoder_config *cfg)
 {
@@ -167,9 +150,7 @@
                                       n_rates, false);
     bool res = set_option(str(LANG_BITRATE), &index, INT,
                           items, n_rates, NULL);
-    index = round_value_to_list32(rate_list[index], mp3_enc_bitr,
-                                  MP3_ENC_NUM_BITR, false);
-    cfg->mp3_enc.bitrate = mp3_enc_bitr[index];
+    cfg->mp3_enc.bitrate = rate_list[index];
 
     return res;
 } /* mp3_enc_bitrate */
@@ -202,43 +183,31 @@
 #endif
 
 /** config function pointers and/or data for each codec **/
+#define ENCODER_DATA_ENTRY(rec_format, enc) \
+    [rec_format] = { enc##_get_caps, enc##_default_config, \
+                     &global_settings.enc##_config, sizeof (struct enc##_config), \
+                     enc##_menu }
+#define ENCODER_DATA_ENTRY_NO_CONFIG(rec_format) \
+    [rec_format] = { NULL, NULL, NULL, 0, enc_no_config_menu }
+
 static const struct encoder_data
 {
     void   (*get_caps)(const struct encoder_config *, struct encoder_caps *,
                        bool);
     void   (*default_cfg)(struct encoder_config *);
-    void   (*convert_cfg)(struct encoder_config *, bool to_encoder);
+    void    *global_cfg;
+    size_t   cfg_size;
     bool   (*menu)(struct encoder_config *);
 } enc_data[REC_NUM_FORMATS] =
 {
-    /* aiff_enc.codec */
-    [REC_FORMAT_AIFF] = {
-        NULL,
-        NULL,
-        NULL,
-        enc_no_config_menu,
-    },
     /* mp3_enc.codec */
-    [REC_FORMAT_MPA_L3] = {
-        mp3_enc_get_caps,
-        mp3_enc_default_config,
-        mp3_enc_convert_config,
-        mp3_enc_menu,
-    },
+    ENCODER_DATA_ENTRY(REC_FORMAT_MPA_L3, mp3_enc),
     /* wav_enc.codec */
-    [REC_FORMAT_PCM_WAV] = {
-        NULL,
-        NULL,
-        NULL,
-        enc_no_config_menu,
-    },
+    ENCODER_DATA_ENTRY_NO_CONFIG(REC_FORMAT_PCM_WAV),
     /* wavpack_enc.codec */
-    [REC_FORMAT_WAVPACK] = {
-        NULL,
-        NULL,
-        NULL,
-        enc_no_config_menu,
-    },
+    ENCODER_DATA_ENTRY_NO_CONFIG(REC_FORMAT_WAVPACK),
+    /* aiff_enc.codec */
+    ENCODER_DATA_ENTRY_NO_CONFIG(REC_FORMAT_AIFF),
 };
 
 static inline bool rec_format_ok(int rec_format)
@@ -317,29 +286,30 @@
                               table, n, true);
     global_settings.rec_channels = table[n];
 
-    /* rec_frequency */
+    /* rec_sampr */
     n = make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
                               caps.samplerate_caps, table);
 
-    n = round_value_to_list32(
-                rec_freq_sampr[global_settings.rec_frequency],
-                table, n, false);
+    n = round_value_to_list32(global_settings.rec_sampr, table, n, false);
+
+    n = round_value_to_list32(table[n], rec_freq_sampr, REC_NUM_FREQ, false);
 
-    global_settings.rec_frequency = round_value_to_list32(
-            table[n], rec_freq_sampr, REC_NUM_FREQ, false);
+    global_settings.rec_sampr = rec_freq_sampr[n];
 } /* enc_rec_settings_changed */
 
 /** public stuff **/
 void global_to_encoder_config(struct encoder_config *cfg)
 {
     const struct encoder_data *data = &enc_data[cfg->rec_format];
-    CALL_FN_(data->convert_cfg, cfg, true);
+    if (data->cfg_size)
+        memcpy(cfg->data, data->global_cfg, data->cfg_size);
 } /* global_to_encoder_config */
 
 void encoder_config_to_global(const struct encoder_config *cfg)
 {
     const struct encoder_data *data = &enc_data[cfg->rec_format];
-    CALL_FN_(data->convert_cfg, (struct encoder_config *)cfg, false);
+    if (data->cfg_size)
+        memcpy(data->global_cfg, cfg->data, data->cfg_size);
 } /* encoder_config_to_global */
 
 bool enc_get_caps(const struct encoder_config *cfg,
@@ -389,7 +359,7 @@
 void enc_global_settings_reset(void)
 {
     struct encoder_config cfg;
-    cfg.rec_format = 0;
+    cfg.rec_format = REC_FORMAT_FIRST;
 
     do
     {
@@ -399,7 +369,7 @@
         if (cfg.rec_format == global_settings.rec_format)
             enc_rec_settings_changed(&cfg);
     }
-    while (++cfg.rec_format < REC_NUM_FORMATS);
+    while (++cfg.rec_format <= REC_FORMAT_LAST);
 } /* enc_global_settings_reset */
 
 /* Apply new settings */
@@ -417,7 +387,7 @@
 
 /* Show an encoder's config menu based on the global_settings.
    Modified settings are placed in global_settings.enc_config. */
-bool enc_global_config_menu(void)
+int enc_global_config_menu(void)
 {
     struct encoder_config cfg;
 
Index: apps/enc_config.h
===================================================================
RCS file: /cvsroot/rockbox/apps/enc_config.h,v
retrieving revision 1.1
diff -u -r1.1 enc_config.h
--- apps/enc_config.h	6 Nov 2006 18:18:05 -0000	1.1
+++ apps/enc_config.h	30 Nov 2006 07:20:57 -0000
@@ -54,9 +54,7 @@
 /** Encoder Menus **/
 
 /* Shows an encoder's config menu given an encoder config returned by one
-   of the enc_api functions. Modified settings are not saved to disk but
-   instead are placed in the structure. Call enc_save_config to commit
-   the data. */
+   of the enc_ functions. Modified settings are returned in cfg. */
 bool enc_config_menu(struct encoder_config *cfg);
 
 /** Global Settings **/
@@ -68,6 +66,6 @@
 void enc_global_settings_apply(void);
 
 /* Show an encoder's config menu based on the global_settings.
-   Modified settings are placed in global_settings.enc_config. */
-bool enc_global_config_menu(void);
+   Modified settings are placed in global_settings.*_enc_config. */
+int enc_global_config_menu(void);
 #endif /* ENC_CONFIG_H */
Index: apps/eq_menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/eq_menu.c,v
retrieving revision 1.28
diff -u -r1.28 eq_menu.c
--- apps/eq_menu.c	6 Nov 2006 18:07:21 -0000	1.28
+++ apps/eq_menu.c	30 Nov 2006 07:21:00 -0000
@@ -49,21 +49,7 @@
 #include "wm8758.h"
 #endif
 
-/* Various user interface limits and sizes */
-#define EQ_CUTOFF_MIN        20
-#define EQ_CUTOFF_MAX     22040
-#define EQ_CUTOFF_STEP       10
-#define EQ_CUTOFF_FAST_STEP 100
-#define EQ_GAIN_MIN       (-240)
-#define EQ_GAIN_MAX         240
-#define EQ_GAIN_STEP          5
-#define EQ_GAIN_FAST_STEP    10
-#define EQ_Q_MIN              5
-#define EQ_Q_MAX             64
-#define EQ_Q_STEP             1
-#define EQ_Q_FAST_STEP       10
 
-#define EQ_USER_DIVISOR      10
 
 /*
  * Utility functions
@@ -1158,7 +1144,7 @@
 #endif
 
 /* Full equalizer menu */
-bool eq_menu(void)
+int eq_menu(void)
 {
     int m;
     bool result;
@@ -1177,6 +1163,6 @@
     result = menu_run(m);
     menu_exit(m);
 
-    return result;
+    return (int)result;
 }
 
Index: apps/eq_menu.h
===================================================================
RCS file: /cvsroot/rockbox/apps/eq_menu.h,v
retrieving revision 1.3
diff -u -r1.3 eq_menu.h
--- apps/eq_menu.h	5 Sep 2006 11:48:17 -0000	1.3
+++ apps/eq_menu.h	30 Nov 2006 07:21:00 -0000
@@ -24,10 +24,26 @@
 
 bool eq_browse_presets(void);
 bool eq_menu_graphical(void);
-bool eq_menu(void);
+int eq_menu(void);
 #ifdef HAVE_WM8758
 bool eq_hw_menu(void);
 void eq_hw_enable(bool enable);
 #endif
 
+/* Various user interface limits and sizes */
+#define EQ_CUTOFF_MIN        20
+#define EQ_CUTOFF_MAX     22040
+#define EQ_CUTOFF_STEP       10
+#define EQ_CUTOFF_FAST_STEP 100
+#define EQ_GAIN_MIN       (-240)
+#define EQ_GAIN_MAX         240
+#define EQ_GAIN_STEP          5
+#define EQ_GAIN_FAST_STEP    10
+#define EQ_Q_MIN              5
+#define EQ_Q_MAX             64
+#define EQ_Q_STEP             1
+#define EQ_Q_FAST_STEP       10
+
+#define EQ_USER_DIVISOR      10
+
 #endif
Index: apps/main.c
===================================================================
RCS file: /cvsroot/rockbox/apps/main.c,v
retrieving revision 1.196
diff -u -r1.196 main.c
--- apps/main.c	27 Nov 2006 02:15:14 -0000	1.196
+++ apps/main.c	30 Nov 2006 07:21:02 -0000
@@ -232,10 +232,9 @@
     screen_access_init();
     gui_syncstatusbar_init(&statusbars);
     settings_reset();
-    settings_calc_config_sector();
     settings_load(SETTINGS_ALL);
     gui_sync_wps_init();
-    settings_apply();
+    settings_apply(true);
     init_dircache(true);
     init_dircache(false);
 #ifdef HAVE_TAGCACHE
@@ -427,7 +426,6 @@
         }
     }
 
-    settings_calc_config_sector();
     
 #if defined(SETTINGS_RESET) || (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IRIVER_H10_PAD)
 #ifdef SETTINGS_RESET
@@ -453,7 +451,7 @@
     }
     
     gui_sync_wps_init();
-    settings_apply();
+    settings_apply(false);
     init_dircache(false);
 #ifdef HAVE_TAGCACHE
     init_tagcache();
Index: apps/main_menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/main_menu.c,v
retrieving revision 1.159
diff -u -r1.159 main_menu.c
--- apps/main_menu.c	25 Oct 2006 10:17:53 -0000	1.159
+++ apps/main_menu.c	30 Nov 2006 07:21:02 -0000
@@ -291,55 +291,6 @@
     return rockbox_browse(THEME_DIR, SHOW_CFG);
 }
 
-#ifdef HAVE_RECORDING
-
-static bool rec_menu_recording_screen(void)
-{
-    return recording_screen(false);
-}
-
-static bool recording_settings(void)
-{
-    bool ret;
-#ifdef HAVE_FMRADIO_IN
-    int rec_source = global_settings.rec_source;
-#endif
-
-    ret = recording_menu(false);
-
-#ifdef HAVE_FMRADIO_IN
-    if (rec_source != global_settings.rec_source)
-    {
-        if (rec_source == AUDIO_SRC_FMRADIO)
-            radio_stop();
-        /* If AUDIO_SRC_FMRADIO was selected from something else,
-           the recording screen will start the radio */       
-    }
-#endif
-
-    return ret;
-}
-
-bool rec_menu(void)
-{
-    int m;
-    bool result;
-
-    /* recording menu */
-    static const struct menu_item items[] = {
-        { ID2P(LANG_RECORDING_MENU),     rec_menu_recording_screen  },
-        { ID2P(LANG_RECORDING_SETTINGS), recording_settings},
-    };
-
-    m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
-                 NULL, NULL, NULL);
-    result = menu_run(m);
-    menu_exit(m);
-
-    return result;
-}
-#endif
-
 bool info_menu(void)
 {
     int m;
Index: apps/main_menu.h
===================================================================
RCS file: /cvsroot/rockbox/apps/main_menu.h,v
retrieving revision 1.6
diff -u -r1.6 main_menu.h
--- apps/main_menu.h	2 Sep 2005 05:39:09 -0000	1.6
+++ apps/main_menu.h	30 Nov 2006 07:21:02 -0000
@@ -21,7 +21,7 @@
 
 #include "menu.h"
 
-extern bool main_menu(void);
+extern int  main_memu(void);
 extern bool rec_menu(void);
 
 #endif
Index: apps/menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/menu.c,v
retrieving revision 1.106
diff -u -r1.106 menu.c
--- apps/menu.c	6 Nov 2006 10:11:50 -0000	1.106
+++ apps/menu.c	30 Nov 2006 07:21:03 -0000
@@ -35,12 +35,15 @@
 #include "usb.h"
 #include "panic.h"
 #include "settings.h"
+#include "settings_list.h"
 #include "status.h"
 #include "screens.h"
 #include "talk.h"
 #include "lang.h"
 #include "misc.h"
 #include "action.h"
+#include "string.h"
+#include "atoi.h"
 
 #ifdef HAVE_LCD_BITMAP
 #include "icons.h"
@@ -356,3 +359,330 @@
 #endif
     }
 }
+/******************************************************************/
+/*              New menu stuff here!!
+ ******************************************************************/
+
+/* doing this stops compile warnings... */
+#undef P2STR
+#undef P2ID
+#define P2ID(p) (((char *)p>=(char *)VIRT_PTR && \
+    (char *)p<=(char *)(VIRT_PTR+VIRT_SIZE)) ? (char *)p-(char *)VIRT_PTR : -1)
+inline char* P2STR(char* p) {
+    if (p>=(char*)VIRT_PTR && (char*)p<=(char*)(VIRT_PTR+VIRT_SIZE))
+        return str((char*)p-(char*)VIRT_PTR);
+    else return p;
+}
+
+const struct settings_list* find_setting(void* variable)
+{
+    int i;
+    for(i=0;i<nb_settings;i++)
+    {
+        if (settings[i].setting == variable)
+            return &settings[i];
+    }
+    return NULL;
+}
+#define MAX_MENU_SUBITEMS 64
+int current_subitems[MAX_MENU_SUBITEMS];
+int current_subitems_count = 0;
+
+int get_menu_selection(int selected_item, const struct menu_item_ex *menu)
+{
+    if (menu->type == MT_MENU && (selected_item<current_subitems_count))
+        return current_subitems[selected_item];
+    return selected_item;
+}
+
+char * get_menu_item_name(int selected_item,void * data, char *buffer)
+{
+    const struct menu_item_ex *menu = (const struct menu_item_ex *)data;
+    selected_item = get_menu_selection(selected_item, menu);
+    
+    (void)buffer;
+    /* only MT_MENU or MT_RETURN_ID is allowed in here */
+    if (menu->type == MT_RETURN_ID)
+    {
+        return (char*)menu->strings[selected_item];
+    }
+    
+    menu = menu->submenus[selected_item];
+    if (menu->type == MT_SETTING)
+    {
+        const struct settings_list *v
+                = find_setting(menu->global_settings_variable);
+        if (v)
+            return str(v->cfg_lang_id);
+        else return "Not Done yet!";
+    }
+    return P2STR(menu->desc);
+}
+
+void init_menu_lists(const struct menu_item_ex *menu,
+                     struct gui_synclist *lists, int selected, bool callback)
+{
+    int i;
+    current_subitems_count = 0;
+    for (i=0; i<menu->item_count; i++)
+    {
+        if (menu->submenus[i]->menu_callback)
+        {
+            if (menu->submenus[i]->menu_callback(
+                            ACTION_REQUEST_MENUITEM,menu->submenus[i])
+                != ACTION_EXIT_MENUITEM)
+            {
+                current_subitems[current_subitems_count] = i;
+                current_subitems_count++;
+            }
+        }
+        else 
+        {
+            current_subitems[current_subitems_count] = i;
+            current_subitems_count++;
+        }
+    }
+    
+    gui_synclist_init(lists,get_menu_item_name,(void*)menu,false,1);
+    gui_synclist_set_title(lists, P2STR(menu->desc), NOICON);
+    gui_synclist_set_icon_callback(lists,NULL);
+    gui_synclist_set_nb_items(lists,current_subitems_count);
+    gui_synclist_limit_scroll(lists,true);
+    gui_synclist_select_item(lists, selected);
+    
+    if (callback && menu->menu_callback)
+        menu->menu_callback(ACTION_ENTER_MENUITEM,menu);
+}
+
+void talk_menu_item(const struct menu_item_ex *menu,
+                    struct gui_synclist *lists)
+{
+    int id = -1;
+    if (global_settings.talk_menu)
+    {
+        int sel = get_menu_selection(gui_synclist_get_sel_pos(lists),menu);
+        if (menu->type == MT_MENU)
+        {
+           if (menu->submenus[sel]->type == MT_SETTING)
+               talk_setting(menu->submenus[sel]->global_settings_variable);
+           else 
+           {
+               id = P2ID(menu->submenus[sel]->desc);
+               if (id != -1)
+                   talk_id(id,false);
+           }
+        }
+    }
+}
+
+int do_menu(const struct menu_item_ex *menu)
+{
+    int action;
+    int selected = 0;
+    struct gui_synclist lists;
+    const struct menu_item_ex *temp;
+    int ret = 0;
+    
+    const struct menu_item_ex *menu_stack[MAX_MENUS];
+    int menu_stack_selected_item[MAX_MENUS];
+    int stack_top = 0;
+    bool in_stringlist;
+    bool apply_settings = false;
+    if (menu == NULL)
+        menu = &main_menu_;
+
+    init_menu_lists(menu,&lists,selected,true);
+    in_stringlist = (menu->type == MT_RETURN_ID);
+    
+    talk_menu_item(menu, &lists);
+    
+    gui_synclist_draw(&lists);
+    gui_syncstatusbar_draw(&statusbars, true);
+    action_signalscreenchange();
+    
+    while (ret == 0)
+    {
+        action = get_action(CONTEXT_MAINMENU,TIMEOUT_BLOCK); 
+        if (action == ACTION_NONE)
+            continue;
+
+        if (menu->menu_callback)
+        {
+            action = menu->menu_callback(action,menu);
+        }
+
+        if (gui_synclist_do_button(&lists,action,LIST_WRAP_UNLESS_HELD))
+        {
+            talk_menu_item(menu, &lists);
+        }
+        else if (action == ACTION_MENU_WPS)
+        {
+            ret = MENU_RETURN_TO_WPS;
+        }
+        else if ((action == ACTION_STD_CANCEL) ||
+                 (action == ACTION_STD_MENU))
+        {
+            if (in_stringlist)
+                in_stringlist = false;
+            if (stack_top > 0)
+            {
+                if (menu->menu_callback)
+                {
+                    if (menu->menu_callback(action,menu) ==
+                            ACTION_EXIT_MENUITEM)
+                        break;
+                }
+                stack_top--;
+                menu = menu_stack[stack_top];
+                init_menu_lists(menu,&lists,menu_stack_selected_item[stack_top],false);
+                talk_menu_item(menu, &lists);
+            }
+            else 
+            {
+                break;
+            }
+        }
+        else if (action == ACTION_STD_OK)
+        {
+            int type;
+            selected = get_menu_selection(gui_synclist_get_sel_pos(&lists),menu);
+            temp = menu->submenus[selected];
+            if (in_stringlist)
+                type = menu->type;
+            else type = temp->type;
+            if (temp->menu_callback)
+            {
+                action = temp->menu_callback(ACTION_ENTER_MENUITEM,temp);
+                if (action == ACTION_EXIT_MENUITEM)
+                    break;
+            }
+            switch (type)
+            {
+                case MT_MENU:
+                    if (stack_top < MAX_MENUS)
+                    {
+                        menu_stack[stack_top] = menu;
+                        menu_stack_selected_item[stack_top]
+                                = gui_synclist_get_sel_pos(&lists);
+                        stack_top++;
+                        init_menu_lists(temp,&lists,0,true);
+                        menu = temp;
+                        talk_menu_item(menu, &lists);
+                    }
+                    break;
+                case MT_FUNCTION_CALL:
+                    action_signalscreenchange();
+                    temp->function();
+                    break;
+                case MT_SETTING:
+                    load_setting_screen(
+                            (struct settings_list *)find_setting(
+                                temp->global_settings_variable));
+                    apply_settings = true;
+                    break;
+                case MT_RETURN_ID:
+                    if (in_stringlist)
+                    {
+                        action_signalscreenchange();
+                        return selected;
+                    }
+                    else if (stack_top < MAX_MENUS)
+                    {
+                        menu_stack[stack_top] = menu;
+                        menu_stack_selected_item[stack_top] = selected;
+                        stack_top++;
+                        menu = temp;
+                        init_menu_lists(menu,&lists,0,false);
+                        in_stringlist = true;
+                    }
+                    break;
+            }
+            if (type != MT_MENU && temp->menu_callback)
+                temp->menu_callback(ACTION_EXIT_MENUITEM,temp);
+        }
+        else if(default_event_handler(action) == SYS_USB_CONNECTED)
+            ret = MENU_ATTACHED_USB;
+        gui_syncstatusbar_draw(&statusbars, true);
+        gui_synclist_draw(&lists);
+    }
+    if (apply_settings)
+        settings_apply(true);
+    action_signalscreenchange();
+    return ret;
+}
+
+int main_menu(void)
+{
+    return do_menu(NULL);
+}
+
+#if 0
+/* user menus, this doesnt work properly, so comment out untill after commit */
+#define MAX_USER_MENUS 32
+int user_menu_count;
+struct menu_item_ex user_menus;
+const struct menu_item_ex *user_menus_items[MAX_USER_MENUS];
+/* user menu stuff */
+int user_menu_callback(int action, const struct menu_item_ex *this_item)
+{
+    (void)this_item;
+    if ((action == ACTION_ENTERING_MENUITEM) &&
+         (user_menu_count == 0)
+       )
+        return ACTION_BACKOUT_MENUITEM;
+    return action;
+}
+int split_line(char* buffer, int* out_array, int out_len)
+{
+    char *s = buffer, *e;
+    int i=0;
+    while (i<out_len)
+    {
+        e = strchr(s,',');
+        if (e) *e = '\0';
+        out_array[i++] = atoi(s);
+        s = e;
+        if (s == NULL)
+            break;
+        s++;
+    }
+    return i;
+}
+
+void user_menu_init(void)
+{
+    int fd;
+    int i =0,j, count;
+    char buffer[MAX_PATH];
+    int menu_order[MAX_USER_MENUS];
+    const struct menu_item_ex *temp;
+    user_menu_count = 0;
+    user_menus.type = MT_MENU;
+    user_menus.item_count = 0;
+    user_menus.menu_callback = user_menu_callback;
+    user_menus.desc = ID2P(LANG_USER_MENU);
+    user_menus.submenus = user_menus_items;
+    
+    fd = open(ROCKBOX_DIR "/user_menu.config",O_RDONLY);
+    if (fd < 0)
+        return;
+    while (read_line(fd,buffer,MAX_PATH))
+    {
+        if (buffer[0] == '#') /* comment */
+            continue;
+        count = split_line(buffer,menu_order,MAX_USER_MENUS);
+        temp = &main_menu_;
+        for (j=0;j<count;j++)
+        {
+            if ((menu_order[j] >= 0) &&
+                 (menu_order[j] < temp->item_count))
+                temp = temp->submenus[menu_order[j]];
+            else break;
+        }
+        user_menus_items[i++] = temp;
+        user_menu_count++;
+    }
+    close(fd);
+    user_menus.item_count = user_menu_count;
+}
+#endif
Index: apps/menu.h
===================================================================
RCS file: /cvsroot/rockbox/apps/menu.h,v
retrieving revision 1.45
diff -u -r1.45 menu.h
--- apps/menu.h	10 Nov 2006 20:25:59 -0000	1.45
+++ apps/menu.h	30 Nov 2006 07:21:07 -0000
@@ -21,6 +21,9 @@
 #define __MENU_H__
 
 #include <stdbool.h>
+#include "config.h"
+#include "sound.h"
+#include "menus/exported_menus.h"
 
 /* button definitions */
 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
@@ -126,6 +129,7 @@
 #define MENU_ATTACHED_USB -1
 #define MENU_SELECTED_EXIT -2
 
+
 bool menu_run(int menu);
 int menu_cursor(int menu);
 char* menu_description(int menu, int position);
@@ -138,4 +142,49 @@
 void menu_set_cursor(int menu, int position);
 void menu_talk_selected(int m);
 
+#define MENU_EXIT_ALL -3
+#define MENU_RETURN_TO_WPS -4
+enum menu_item_type {
+    MT_MENU = 0,
+    MT_SETTING,
+    MT_FUNCTION_CALL, /* used when the standard code wont work */
+    MT_RETURN_ID, /* returns the position of the selected item on selection (starting at 0)*/
+};
+typedef int (*menu_function)(void);
+struct menu_item_ex {
+    enum menu_item_type type;
+    union {
+        const struct menu_item_ex **submenus; /* used with MT_MENU */
+        void *global_settings_variable; /* used with MT_SETTING */
+        int (*function)(void); /* used with MT_FUNCTION_CALL */
+        const char **strings; /* used with MT_RETURN_ID */
+    };
+    int item_count; /* # of submenu, options, or strings */
+    int (*menu_callback)(int action, const struct menu_item_ex *this_item);
+    
+    char *desc;
+};
+typedef int (*menu_callback_type)(int action, const struct menu_item_ex *this_item);
+int do_menu(const struct menu_item_ex *menu);
+
+#define MAKE_SETTING_OPT(var,callback) const struct menu_item_ex var = \
+{MT_SETTING, {.global_settings_variable = (void*)&global_settings.var},1,callback,0};
+
+#define MAKE_MENU( name, str, cb, ... )                                 \
+    const struct menu_item_ex *name##_[]  = {__VA_ARGS__};     \
+    const struct menu_item_ex name =                           \
+        {MT_MENU, { (void*)name##_}, sizeof( name##_)/sizeof(*name##_),cb,str};
+        
+#define MAKE_STRINGLIST(name, str, callback, ... )                            \
+    const char *name##_[] = {__VA_ARGS__};                     \
+    const struct menu_item_ex name =                           \
+{MT_RETURN_ID, { .submenus = name##_}, sizeof( name##_)/sizeof(*name##_),callback, str};
+
+#define MAKE_FUNCTION_CALL(name, str, func, callback)               \
+    const struct menu_item_ex name   =                         \
+{ MT_FUNCTION_CALL, { .function = func},0,callback,str};
+        
+void user_menu_init(void);
+extern struct menu_item_ex user_menus;
 #endif /* End __MENU_H__ */
+
Index: apps/misc.c
===================================================================
RCS file: /cvsroot/rockbox/apps/misc.c,v
retrieving revision 1.76
diff -u -r1.76 misc.c
--- apps/misc.c	26 Nov 2006 09:53:42 -0000	1.76
+++ apps/misc.c	30 Nov 2006 07:21:07 -0000
@@ -555,6 +555,7 @@
 
 static void system_flush(void)
 {
+    settings_save_config(ROCKBOX_CONFIGFILE,false); /* unfortunatly nessacery */
     call_ata_idle_notifys(true); /*doesnt work on usb and shutdown from ata thread */
     tree_flush();
 }
@@ -713,7 +714,7 @@
     }
 }
 #endif
-
+void write_settings_to_disk(void); /* from settings.c */
 long default_event_handler_ex(long event, void (*callback)(void *), void *parameter)
 {
     switch(event)
@@ -753,6 +754,9 @@
             unplug_change(false);
             return SYS_PHONE_UNPLUGGED;
 #endif
+        case SYS_DUMPSETTINGS:
+            write_settings_to_disk();
+            return SYS_DUMPSETTINGS;
     }
     return 0;
 }
Index: apps/onplay.c
===================================================================
RCS file: /cvsroot/rockbox/apps/onplay.c,v
retrieving revision 1.91
diff -u -r1.91 onplay.c
--- apps/onplay.c	13 Nov 2006 00:45:19 -0000	1.91
+++ apps/onplay.c	30 Nov 2006 07:21:09 -0000
@@ -56,13 +56,11 @@
 #ifdef HAVE_LCD_BITMAP
 #include "icons.h"
 #endif
-#include "main_menu.h"
-#include "sound_menu.h"
+#include "menu.h"
 #include "database.h"
 #if CONFIG_CODEC == SWCODEC
 #include "eq_menu.h"
 #endif
-#include "playlist_menu.h"
 #include "playlist_catalog.h"
 #ifdef HAVE_TAGCACHE
 #include "tagtree.h"
Index: apps/playback.c
===================================================================
RCS file: /cvsroot/rockbox/apps/playback.c,v
retrieving revision 1.401
diff -u -r1.401 playback.c
--- apps/playback.c	28 Nov 2006 15:00:54 -0000	1.401
+++ apps/playback.c	30 Nov 2006 07:21:17 -0000
@@ -48,7 +48,6 @@
 #include "mp3_playback.h"
 #include "usb.h"
 #include "status.h"
-#include "main_menu.h"
 #include "ata.h"
 #include "screens.h"
 #include "playlist.h"
Index: apps/playback.h
===================================================================
RCS file: /cvsroot/rockbox/apps/playback.h,v
retrieving revision 1.39
diff -u -r1.39 playback.h
--- apps/playback.h	25 Oct 2006 08:54:25 -0000	1.39
+++ apps/playback.h	30 Nov 2006 07:21:18 -0000
@@ -76,6 +76,7 @@
 #endif
 void audio_preinit(void);
 
+void mpeg_id3_options(bool _v1first);
 #endif
 
 
Index: apps/playlist_viewer.c
===================================================================
RCS file: /cvsroot/rockbox/apps/playlist_viewer.c,v
retrieving revision 1.55
diff -u -r1.55 playlist_viewer.c
--- apps/playlist_viewer.c	18 Nov 2006 02:18:23 -0000	1.55
+++ apps/playlist_viewer.c	30 Nov 2006 07:21:21 -0000
@@ -47,7 +47,6 @@
 #include "list.h"
 #include "statusbar.h"
 #include "splash.h"
-#include "playlist_menu.h"
 #include "action.h"
 
 /* Maximum number of tracks we can have loaded at one time */
Index: apps/settings.c
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.c,v
retrieving revision 1.438
diff -u -r1.438 settings.c
--- apps/settings.c	24 Nov 2006 19:49:02 -0000	1.438
+++ apps/settings.c	30 Nov 2006 07:21:26 -0000
@@ -26,6 +26,7 @@
 #include "thread.h"
 #include "action.h"
 #include "settings.h"
+#include "settings_list.h"
 #include "disk.h"
 #include "panic.h"
 #include "debug.h"
@@ -50,6 +51,7 @@
 #include "errno.h"
 #include "system.h"
 #include "misc.h"
+#include "general.h"
 #include "timefuncs.h"
 #ifdef HAVE_LCD_BITMAP
 #include "icons.h"
@@ -100,9 +102,7 @@
 #include "eq_menu.h"
 #endif
 
-#define CONFIG_BLOCK_VERSION 56
-#define CONFIG_BLOCK_SIZE 512
-#define RTC_BLOCK_SIZE 44
+#define RTC_RAM_CONFIG_VERSION 1
 
 #ifdef HAVE_LCD_BITMAP
 #define MAX_LINES 10
@@ -115,631 +115,26 @@
 #endif
 
 long lasttime = 0;
-static long config_sector = 0;  /* mark uninitialized */
-static unsigned char config_block[CONFIG_BLOCK_SIZE];
 
-
-/* descriptor for a configuration value */
-/* (watch the struct packing and member sizes to keep this small) */
-struct bit_entry
-{
-    /* how many bits within the bitfield (1-32), MSB set if value is signed */
-    unsigned char bit_size; /* min 6+1 bit */
-    /* how many bytes in the global_settings struct (1,2,4) */
-    unsigned char byte_size; /* min 3 bits */
-    /* store position in global_settings struct */
-    short settings_offset; /* min 9 bit, better 10 */
-    /* default value */
-    int default_val; /* min 15 bit */
-    /* variable name in a .cfg file, NULL if not to be saved */
-    const char* cfg_name;
-    /* set of values, "rgb" for a color, or NULL for a numerical value */
-    const char* cfg_val;
-};
-
-/********************************************
-
-Config block as saved on the battery-packed RTC user RAM memory block
-of 44 bytes, starting at offset 0x14 of the RTC memory space.
-
-offset  abs
-0x00    0x14    "Roc"   header signature: 0x52 0x6f 0x63
-0x03    0x17    <version byte: 0x0>
-0x04    0x18    start of bit-table
-...
-0x28,0x29 unused, not reachable by set_bits() without disturbing the next 2
-0x2A,0x2B <checksum 2 bytes: xor of 0x00-0x29>
-
-Config memory is reset to 0xff and initialized with 'factory defaults' if
-a valid header & checksum is not found. Config version number is only
-increased when information is _relocated_ or space is _reused_ so that old
-versions can read and modify configuration changed by new versions.
-Memory locations not used by a given version should not be
-modified unless the header & checksum test fails.
-
-Rest of config block, only saved to disk:
-0x2C  start of 2nd bit-table
-...
-0xA4  (char[20]) FMR Preset file
-0xB8  (char[20]) WPS file
-0xCC  (char[20]) Lang file
-0xE0  (char[20]) Font file
-...   (char[20]) RWPS file (on targets supporting a Remote WPS)
-...   (char[20]) Main backdrop file (on color LCD targets)
-
-... to 0x200  <unused>
-
-*************************************/
-
-/* The persistence of the global_settings members is now controlled by
-   the two tables below, rtc_bits and hd_bits.
-   New values can just be added to the end, it will be backwards
-   compatible. If you however change order, bitsize, etc. of existing
-   entries, you need to bump CONFIG_BLOCK_VERSION to break compatibility.
-*/
-
-
-/* convenience macro for both size and offset of global_settings member */
-#define S_O(val) sizeof(global_settings.val), offsetof(struct user_settings, val)
-#define SIGNED 0x80 /* for bitsize value with signed attribute */
-
-/* some sets of values which are used more than once, to save memory */
-static const char off_on[] = "off,on";
-static const char off_on_ask[] = "off,on,ask";
-static const char off_number_spell_hover[] = "off,number,spell,hover";
-#ifdef HAVE_LCD_BITMAP
-static const char graphic_numeric[] = "graphic,numeric";
-#endif
-
-#ifdef HAVE_RECORDING
-/* keep synchronous to trig_durations and
-   trigger_times in settings_apply_trigger */
-static const char trig_durations_conf [] =
-                  "0s,1s,2s,5s,10s,15s,20s,25s,30s,1min,2min,5min,10min";
-#endif
-
-#if defined(CONFIG_BACKLIGHT)
-static const char backlight_times_conf [] =
-                  "off,on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90";
-#endif
-
-/* the part of the settings which ends up in the RTC RAM, where available
-   (those we either need early, save frequently, or without spinup) */
-static const struct bit_entry rtc_bits[] =
-{
-    /* placeholder, containing the size information */
-    {9, 0, 0, 0, NULL, NULL }, /* 9 bit to tell how far this is populated */
-
-    /* # of bits, offset+size, default, .cfg name, .cfg values */
-    /* sound */
-#if CONFIG_CODEC == MAS3507D
-    {8 | SIGNED, S_O(volume), -18, "volume", NULL }, /* -78...+18 */
-#else
-    {8 | SIGNED, S_O(volume), -25, "volume", NULL }, /* -100...+12 / -84...0 */
-#endif
-    {8 | SIGNED, S_O(balance), 0, "balance", NULL }, /* -100...100 */
-#if CONFIG_CODEC != SWCODEC /* any MAS */
-    {5 | SIGNED, S_O(bass), 0, "bass", NULL }, /* -15..+15 / -12..+12 */
-    {5 | SIGNED, S_O(treble), 0, "treble", NULL }, /* -15..+15 / -12..+12 */
-#elif defined HAVE_UDA1380
-    {5, S_O(bass), 0, "bass", NULL }, /* 0..+24 */
-    {3, S_O(treble), 0, "treble", NULL }, /* 0..+6 */
-#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
-   || defined(HAVE_WM8731) || defined(HAVE_WM8721)
-    {5 | SIGNED, S_O(bass), 0, "bass", NULL }, /* -6..+9 */
-    {5 | SIGNED, S_O(treble), 0, "treble", NULL }, /* -6..+9 */
-#endif
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    {5, S_O(loudness), 0, "loudness", NULL }, /* 0...17 */
-    {3, S_O(avc), 0, "auto volume", "off,20ms,2,4,8" },
-    {1, S_O(superbass), false, "superbass", off_on },
-#endif
-    {3, S_O(channel_config), 0, "channels",
-        "stereo,mono,custom,mono left,mono right,karaoke" },
-    {8, S_O(stereo_width), 100, "stereo width", NULL},
-    /* playback */
-    {1, S_O(resume), false, "resume", off_on },
-    {1, S_O(playlist_shuffle), false, "shuffle", off_on },
-    {16 | SIGNED, S_O(resume_index), -1, NULL, NULL },
-    {16 | SIGNED, S_O(resume_first_index), 0, NULL, NULL },
-    {32 | SIGNED, S_O(resume_offset), -1, NULL, NULL },
-    {32 | SIGNED, S_O(resume_seed), -1, NULL, NULL },
-    {3, S_O(repeat_mode), REPEAT_ALL, "repeat", "off,all,one,shuffle,ab" },
-    /* LCD */
-#ifdef HAVE_LCD_CONTRAST
-    {6, S_O(contrast), DEFAULT_CONTRAST_SETTING, "contrast", NULL },
-#endif
-#ifdef CONFIG_BACKLIGHT
-    {5, S_O(backlight_timeout), 6, "backlight timeout", backlight_times_conf },
-#ifdef CONFIG_CHARGING
-    {5, S_O(backlight_timeout_plugged), 11, "backlight timeout plugged",
-        backlight_times_conf },
-#endif
-#endif /* CONFIG_BACKLIGHT */
-#ifdef HAVE_LCD_BITMAP
-    {1, S_O(invert), false, "invert", off_on },
-    {1, S_O(flip_display), false, "flip display", off_on },
-    /* display */
-    {1, S_O(invert_cursor), true, "invert cursor", off_on },
-    {1, S_O(statusbar), true, "statusbar", off_on },
-    {1, S_O(scrollbar), true, "scrollbar", off_on },
-#if CONFIG_KEYPAD == RECORDER_PAD
-    {1, S_O(buttonbar), true, "buttonbar", off_on },
-#endif
-    {1, S_O(volume_type), 0, "volume display", graphic_numeric },
-    {1, S_O(battery_display), 0, "battery display", graphic_numeric },
-    {1, S_O(timeformat), 0, "time format", "24hour,12hour" },
-#endif /* HAVE_LCD_BITMAP */
-    {1, S_O(show_icons), true, "show icons", off_on },
-    /* system */
-    {4, S_O(poweroff), 10,
-        "idle poweroff", "off,1,2,3,4,5,6,7,8,9,10,15,30,45,60" },
-    {18, S_O(runtime), 0, NULL, NULL },
-    {18, S_O(topruntime), 0, NULL, NULL },
-#if MEM > 1
-    {15, S_O(max_files_in_playlist), 10000,
-        "max files in playlist", NULL }, /* 1000...20000 */
-    {14, S_O(max_files_in_dir), 400,
-        "max files in dir", NULL }, /* 50...10000 */
-#else
-    {15, S_O(max_files_in_playlist), 1000,
-        "max files in playlist", NULL }, /* 1000...20000 */
-    {14, S_O(max_files_in_dir), 200,
-        "max files in dir", NULL }, /* 50...10000 */
-#endif
-    /* battery */
-    {12, S_O(battery_capacity), BATTERY_CAPACITY_DEFAULT, "battery capacity",
-         NULL }, /* 1500...3200 for NiMH, 2200...3200 for LiIon,
-                     500...1500 for Alkaline */
-#ifdef CONFIG_CHARGING
-    {1, S_O(car_adapter_mode), false, "car adapter mode", off_on },
-#endif
-    /* tuner */
-#ifdef CONFIG_TUNER
-    {1, S_O(fm_force_mono), false, "force fm mono", off_on },
-    {9, S_O(last_frequency), 0, NULL, NULL }, /* Default: MIN_FREQ */
-#endif
-
-#if BATTERY_TYPES_COUNT > 1
-    {1, S_O(battery_type), 0, "battery type", "alkaline,nimh" },
-#endif
-
-#ifdef HAVE_REMOTE_LCD
-    /* remote lcd */
-    {6, S_O(remote_contrast), DEFAULT_REMOTE_CONTRAST_SETTING,
-        "remote contrast", NULL },
-    {1, S_O(remote_invert), false, "remote invert", off_on },
-    {1, S_O(remote_flip_display), false, "remote flip display", off_on },
-    {5, S_O(remote_backlight_timeout), 6, "remote backlight timeout",
-        backlight_times_conf },
-#ifdef CONFIG_CHARGING
-    {5, S_O(remote_backlight_timeout_plugged), 11,
-        "remote backlight timeout plugged", backlight_times_conf },
-#endif
-#ifdef HAVE_REMOTE_LCD_TICKING
-    {1, S_O(remote_reduce_ticking), false, "remote reduce ticking", off_on },
-#endif
-#endif
-
-#ifdef CONFIG_BACKLIGHT
-    {1, S_O(bl_filter_first_keypress), false,
-            "backlight filters first keypress", off_on },
-#ifdef HAVE_REMOTE_LCD
-    {1, S_O(remote_bl_filter_first_keypress), false,
-            "backlight filters first remote keypress", off_on },
-#endif
-#endif /* CONFIG_BACKLIGHT */
-
-    /* new stuff to be added here */
-    /* If values are just added to the end, no need to bump the version. */
-
-    /* Current sum of bits: 277 (worst case, but w/o remote lcd) */
-    /* Sum of all bit sizes must not grow beyond 288! */
-};
-
-
-/* the part of the settings which ends up in HD sector only */
-static const struct bit_entry hd_bits[] =
-{
-    /* This table starts after the 44 RTC bytes = 352 bits. */
-    /* Here we need 11 bits to tell how far this is populated. */
-
-    /* placeholder, containing the size information */
-    {11, 0, 0, 0, NULL, NULL }, /* 11 bit to tell how far this is populated */
-
-    /* # of bits, offset+size, default, .cfg name, .cfg values */
-    /* more display */
-#ifdef CONFIG_BACKLIGHT
-    {1, S_O(caption_backlight), false, "caption backlight", off_on },
-#endif
-#ifdef HAVE_REMOTE_LCD
-    {1, S_O(remote_caption_backlight), false,
-        "remote caption backlight", off_on },
-#endif
-#ifdef HAVE_BACKLIGHT_BRIGHTNESS
-    {4, S_O(brightness), DEFAULT_BRIGHTNESS_SETTING, "brightness", NULL },
-#endif
-#ifdef HAVE_BACKLIGHT_PWM_FADING
-    /* backlight fading */
-    {2, S_O(backlight_fade_in), 1, "backlight fade in", "off,500ms,1s,2s"},
-    {3, S_O(backlight_fade_out), 3, "backlight fade out",
-        "off,500ms,1s,2s,3s,4s,5s,10s"},
-#endif
-
-    {4, S_O(scroll_speed), 9, "scroll speed", NULL }, /* 0...15 */
-    {8, S_O(scroll_delay), 100, "scroll delay", NULL }, /* 0...250 */
-    {8, S_O(bidir_limit), 50, "bidir limit", NULL }, /* 0...200 */
-    
-#ifdef HAVE_REMOTE_LCD
-    {4, S_O(remote_scroll_speed), 9, "remote scroll speed", NULL }, /* 0...15 */
-    {8, S_O(remote_scroll_step), 6, "remote scroll step", NULL }, /* 1...160 */
-    {8, S_O(remote_scroll_delay), 100, "remote scroll delay", NULL }, /* 0...250 */
-    {8, S_O(remote_bidir_limit), 50, "remote bidir limit", NULL }, /* 0...200 */
-#endif
-
-#ifdef HAVE_LCD_BITMAP
-    {1, S_O(offset_out_of_view), false, "Screen Scrolls Out Of View", off_on },
-#if LCD_WIDTH > 255
-    {9, S_O(scroll_step), 6, "scroll step", NULL },
-    {9, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
-#elif LCD_WIDTH > 127
-    {8, S_O(scroll_step), 6, "scroll step", NULL },
-    {8, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
-#else
-    {7, S_O(scroll_step), 6, "scroll step", NULL },
-    {7, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
-#endif
-#endif /* HAVE_LCD_BITMAP */
-#ifdef HAVE_LCD_CHARCELLS
-    {3, S_O(jump_scroll), 0, "jump scroll", NULL }, /* 0...5 */
-    {8, S_O(jump_scroll_delay), 50, "jump scroll delay", NULL }, /* 0...250 */
-#endif
-    {1, S_O(scroll_paginated), false, "scroll paginated", off_on },
-
-#ifdef HAVE_LCD_COLOR
-    {LCD_DEPTH,S_O(fg_color),LCD_DEFAULT_FG,"foreground color","rgb"},
-    {LCD_DEPTH,S_O(bg_color),LCD_DEFAULT_BG,"background color","rgb"},
-#endif
-
-    /* more playback */
-    {1, S_O(play_selected), true, "play selected", off_on },
-    {1, S_O(fade_on_stop), true, "volume fade", off_on },
-    {4, S_O(ff_rewind_min_step), FF_REWIND_1000,
-        "scan min step", "1,2,3,4,5,6,8,10,15,20,25,30,45,60" },
-    {4, S_O(ff_rewind_accel), 3, "scan accel", NULL },
-#if CONFIG_CODEC == SWCODEC
-    {3, S_O(buffer_margin), 0, "antiskip",
-        "5s,15s,30s,1min,2min,3min,5min,10min" },
-#else
-    {3, S_O(buffer_margin), 0, "antiskip", NULL },
-#endif
-    /* disk */
-#ifndef HAVE_MMC
-#ifdef HAVE_ATA_POWER_OFF
-    {1, S_O(disk_poweroff), false, "disk poweroff", off_on },
-#endif
-    {8, S_O(disk_spindown), 5, "disk spindown", NULL },
-#endif /* HAVE_MMC */
-
-    /* browser */
-    {3, S_O(dirfilter), SHOW_SUPPORTED,
-        "show files", "all,supported,music,playlists"
-#ifdef HAVE_TAGCACHE
-        ",id3 database" 
-#endif
-        },
-    {1, S_O(sort_case), false, "sort case", off_on },
-    {1, S_O(browse_current), false, "follow playlist", off_on },
-    /* playlist */
-    {1, S_O(playlist_viewer_icons), true, "playlist viewer icons", off_on },
-    {1, S_O(playlist_viewer_indices), true,
-        "playlist viewer indices", off_on },
-    {1, S_O(playlist_viewer_track_display), 0,
-        "playlist viewer track display", "track name,full path" },
-    {2, S_O(recursive_dir_insert), RECURSE_OFF,
-        "recursive directory insert", off_on_ask },
-    /* bookmarks */
-    {3, S_O(autocreatebookmark), BOOKMARK_NO, "autocreate bookmarks",
-        "off,on,ask,recent only - on,recent only - ask" },
-    {2, S_O(autoloadbookmark), BOOKMARK_NO,
-        "autoload bookmarks", off_on_ask },
-    {2, S_O(usemrb), BOOKMARK_NO,
-        "use most-recent-bookmarks", "off,on,unique only" },
-#ifdef HAVE_LCD_BITMAP
-    /* peak meter */
-    {5, S_O(peak_meter_clip_hold), 16, "peak meter clip hold", /* 0...25 */
-        "on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90,2min,3min,5min,10min,20min,45min,90min" },
-    {5, S_O(peak_meter_hold), 3, "peak meter hold",
-        "off,200ms,300ms,500ms,1,2,3,4,5,6,7,8,9,10,15,20,30,1min" },
-    {7, S_O(peak_meter_release), 8, "peak meter release", NULL }, /* 0...126 */
-    {1, S_O(peak_meter_dbfs), true, "peak meter dbfs", off_on },
-    {7, S_O(peak_meter_min), 60, "peak meter min", NULL }, /* 0...100 */
-    {7, S_O(peak_meter_max), 0, "peak meter max", NULL }, /* 0...100 */
-#endif
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    {7, S_O(mdb_strength), 0, "mdb strength", NULL},
-    {7, S_O(mdb_harmonics), 0, "mdb harmonics", NULL},
-    {9, S_O(mdb_center), 0, "mdb center", NULL},
-    {9, S_O(mdb_shape), 0, "mdb shape", NULL},
-    {1, S_O(mdb_enable), 0, "mdb enable", off_on},
-#endif
-#if CONFIG_CODEC == MAS3507D
-    {1, S_O(line_in), false, "line in", off_on },
-#endif
-    /* voice */
-    {2, S_O(talk_dir), 0, "talk dir", off_number_spell_hover },
-    {2, S_O(talk_file), 0, "talk file", off_number_spell_hover },
-    {1, S_O(talk_menu), true, "talk menu", off_on },
-
-    {2, S_O(sort_file), 0, "sort files", "alpha,oldest,newest,type" },
-    {2, S_O(sort_dir), 0, "sort dirs", "alpha,oldest,newest" },
-    {1, S_O(id3_v1_first), 0, "id3 tag priority", "v2-v1,v1-v2"},
-
-#ifdef HAVE_RECORDING
-    /* recording */
-    {1, S_O(recscreen_on), false, "recscreen on", off_on },
-    {1, S_O(rec_startup), false, "rec screen on startup", off_on },
-    {4, S_O(rec_timesplit), 0, "rec timesplit", /* 0...15 */
-        "off,00:05,00:10,00:15,00:30,01:00,01:14,01:20,02:00,04:00,06:00,08:00,10:00,12:00,18:00,24:00" },
-    {4, S_O(rec_sizesplit), 0, "rec sizesplit", /* 0...15 */
-        "off,5MB,10MB,15MB,32MB,64MB,75MB,100MB,128MB,256MB,512MB,650MB,700MB,1GB,1.5GB,1.75GB" },
-    {1, S_O(rec_channels), 0, "rec channels", "stereo,mono" },
-    {1, S_O(rec_split_type), 0, "rec split type", "Split, Stop" },
-    {1, S_O(rec_split_method), 0, "rec split method", "Time,Filesize" },
-
-    {
-#if defined(HAVE_SPDIF_IN) || defined(HAVE_FMRADIO_IN)
-        2,
-#else
-        1,
-#endif
-        S_O(rec_source), 0 /* 0=mic */, "rec source",
-        "mic,line"
-#ifdef HAVE_SPDIF_IN
-        ",spdif"
-#endif
-#ifdef HAVE_FMRADIO_IN
-        ",fmradio"
-#endif
-    },
-    {5, S_O(rec_prerecord_time), 0, "prerecording time", NULL }, /* 0...30 */
-    {1, S_O(rec_directory), 0, /* rec_base_directory */
-        "rec directory", REC_BASE_DIR ",current" },
-#ifdef CONFIG_BACKLIGHT
-    {2, S_O(cliplight), 0, "cliplight", "off,main,both,remote" },
-#endif 
-#if CONFIG_CODEC == MAS3587F
-    {4, S_O(rec_mic_gain), 8, "rec mic gain", NULL },
-    {4, S_O(rec_left_gain), 2 /* 0dB */, "rec left gain", NULL }, /* 0...15 */
-    {4, S_O(rec_right_gain), 2 /* 0dB */, "rec right gain", NULL }, /* 0...15 */
-    {3, S_O(rec_frequency), 0, /* 0=44.1kHz */
-        "rec frequency", "44,48,32,22,24,16" },
-    {3, S_O(rec_quality), 5 /* 192 kBit/s max */, "rec quality", NULL },
-    {1, S_O(rec_editable), false, "editable recordings", off_on },
-#endif /* CONFIG_CODEC == MAS3587F */
-
-#if CONFIG_CODEC == SWCODEC
-#ifdef HAVE_UDA1380
-    {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
-#endif
-#ifdef HAVE_TLV320
-    /* TLV320 only has no mic boost or 20db mic boost */
-    {1, S_O(rec_mic_gain), 0 /* 0 dB */, "rec mic gain", NULL }, /* 0db or 20db */
-#endif
-    {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
-    {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
-    {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT,
-        "rec frequency", REC_FREQ_CFG_VAL_LIST },
-    {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT,
-        "rec format", REC_FORMAT_CFG_VAL_LIST },
-    /** Encoder settings start - keep these together **/
-    /* aiff_enc */
-    /* (no settings yet) */
-    /* mp3_enc */
-    {5,S_O(mp3_enc_config.bitrate), MP3_ENC_BITRATE_CFG_DEFAULT,
-        "mp3_enc bitrate", MP3_ENC_BITRATE_CFG_VALUE_LIST },
-    /* wav_enc */
-    /* (no settings yet) */
-    /* wavpack_enc */
-    /* (no settings yet) */
-    /** Encoder settings end **/
-#endif /* CONFIG_CODEC == SWCODEC */
-
-    /* values for the trigger */
-    {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL},
-    {8 | SIGNED, S_O(rec_stop_thres), -45, "trigger stop threshold", NULL},
-    {4, S_O(rec_start_duration), 0, "trigger start duration", trig_durations_conf},
-    {4, S_O(rec_stop_postrec), 2, "trigger stop postrec", trig_durations_conf},
-    {4, S_O(rec_stop_gap), 1, "trigger min gap", trig_durations_conf},
-    {4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"},
-#endif /* HAVE_RECORDING */
-
-#ifdef HAVE_SPDIF_POWER
-    {1, S_O(spdif_enable), false, "spdif enable", off_on},
-#endif
-
-    {2, S_O(next_folder), false, "folder navigation", "off,on,random" },
-    {1, S_O(runtimedb), false, "gather runtime data", off_on },
-
-#if CONFIG_CODEC == SWCODEC
-    {1, S_O(replaygain), false, "replaygain", off_on },
-    {2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type",
-        "track,album,track shuffle" },
-    {1, S_O(replaygain_noclip), false, "replaygain noclip", off_on },
-    {8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL },
-    {2, S_O(beep), 0, "beep", "off,weak,moderate,strong" },
-    {2, S_O(crossfade), 0, "crossfade", "off,shuffle,track skip,always"},
-    {3, S_O(crossfade_fade_in_delay), 0, "crossfade fade in delay", NULL},
-    {3, S_O(crossfade_fade_out_delay), 0, "crossfade fade out delay", NULL},
-    {4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL},
-    {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL},
-    {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"},
-    {1, S_O(crossfeed), false, "crossfeed", off_on },
-    {6, S_O(crossfeed_direct_gain), 15, "crossfeed direct gain", NULL },
-    {7, S_O(crossfeed_cross_gain), 60, "crossfeed cross gain", NULL },
-    {8, S_O(crossfeed_hf_attenuation), 160, "crossfeed hf attenuation", NULL },
-    {11, S_O(crossfeed_hf_cutoff), 700, "crossfeed hf cutoff", NULL },
-
-    /* equalizer */
-    {1, S_O(eq_enabled), false, "eq enabled", off_on },
-    {8, S_O(eq_precut), 0, "eq precut", NULL },
-    /* 0..32768 Hz */
-    {15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL },
-    {15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL },
-    {15, S_O(eq_band2_cutoff), 800, "eq band 2 cutoff", NULL },
-    {15, S_O(eq_band3_cutoff), 4000, "eq band 3 cutoff", NULL },
-    {15, S_O(eq_band4_cutoff), 12000, "eq band 4 cutoff", NULL },
-    /* 0..64 (or 0.0 to 6.4) */
-    {6, S_O(eq_band0_q), 7, "eq band 0 q", NULL },
-    {6, S_O(eq_band1_q), 10, "eq band 1 q", NULL },
-    {6, S_O(eq_band2_q), 10, "eq band 2 q", NULL },
-    {6, S_O(eq_band3_q), 10, "eq band 3 q", NULL },
-    {6, S_O(eq_band4_q), 7, "eq band 4 q", NULL },
-    /* -240..240 (or -24db to +24db) */
-    {9|SIGNED, S_O(eq_band0_gain), 0, "eq band 0 gain", NULL },
-    {9|SIGNED, S_O(eq_band1_gain), 0, "eq band 1 gain", NULL },
-    {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL },
-    {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL },
-    {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL },
-
-    /* dithering */
-    {1, S_O(dithering_enabled), false, "dithering enabled", off_on },
-#endif
-
-#ifdef HAVE_DIRCACHE
-    {1, S_O(dircache), false, "dircache", off_on },
-    {22, S_O(dircache_size), 0, NULL, NULL },
-#endif
-
-#ifdef HAVE_TAGCACHE
-#ifdef HAVE_TC_RAMCACHE
-    {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on },
-#endif
-    {1, S_O(tagcache_autoupdate), 0, "tagcache_autoupdate", off_on },
-#endif
-
-    {4, S_O(default_codepage), 0, "default codepage",
-        "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256" },
-
-    {1, S_O(warnon_erase_dynplaylist), false,
-        "warn when erasing dynamic playlist", off_on },
-
-#ifdef CONFIG_BACKLIGHT
-#ifdef HAS_BUTTON_HOLD
-    {2, S_O(backlight_on_button_hold), 0, "backlight on button hold",
-        "normal,off,on" },
-#endif
-
-#ifdef HAVE_LCD_SLEEP
-    {4, S_O(lcd_sleep_after_backlight_off), 3,
-        "lcd sleep after backlight off",
-        "always,never,5,10,15,20,30,45,60,90" },
-#endif
-#endif /* CONFIG_BACKLIGHT */
-
-#ifdef HAVE_WM8758
-    {1, S_O(eq_hw_enabled), false, "eq hardware enabled", off_on },
-    
-    {2, S_O(eq_hw_band0_cutoff), 1, "eq hardware band 0 cutoff", "80Hz,105Hz,135Hz,175Hz" },
-    {5|SIGNED, S_O(eq_hw_band0_gain), 0, "eq hardware band 0 gain", NULL },
-
-    {2, S_O(eq_hw_band1_center), 1, "eq hardware band 1 center", "230Hz,300Hz,385Hz,500Hz" },
-    {1, S_O(eq_hw_band1_bandwidth), 0, "eq hardware band 1 bandwidth", "narrow,wide" },
-    {5|SIGNED, S_O(eq_hw_band1_gain), 0, "eq hardware band 1 gain", NULL },
-
-    {2, S_O(eq_hw_band2_center), 1, "eq hardware band 2 center", "650Hz,850Hz,1.1kHz,1.4kHz" },
-    {1, S_O(eq_hw_band2_bandwidth), 0, "eq hardware band 2 bandwidth", "narrow,wide" },
-    {5|SIGNED, S_O(eq_hw_band2_gain), 0, "eq hardware band 2 gain", NULL },
-
-    {2, S_O(eq_hw_band3_center), 1, "eq hardware band 3 center", "1.8kHz,2.4kHz,3.2kHz,4.1kHz" },
-    {1, S_O(eq_hw_band3_bandwidth), 0, "eq hardware band 3 bandwidth", "narrow,wide" },
-    {5|SIGNED, S_O(eq_hw_band3_gain), 0, "eq hardware band 3 gain", NULL },
-
-    {2, S_O(eq_hw_band4_cutoff), 1, "eq hardware band 4 cutoff", "5.3kHz,6.9kHz,9kHz,11.7kHz" },
-    {5|SIGNED, S_O(eq_hw_band4_gain), 0, "eq hardware band 4 gain", NULL },
-#endif
-    {1, S_O(hold_lr_for_scroll_in_list), true, "hold_lr_for_scroll_in_list", off_on },
-
-    {2, S_O(show_path_in_browser), 0, "show path in browser", "off,current directory,full path" },
-#ifdef HAVE_AGC
-    {4, S_O(rec_agc_preset_mic), 1, "agc mic preset", NULL}, /* 0...5 */
-    {4, S_O(rec_agc_preset_line), 1, "agc line preset", NULL}, /* 0...5 */
-    {8|SIGNED, S_O(rec_agc_maxgain_mic), 104, "agc maximum mic gain", NULL},
-    {8|SIGNED, S_O(rec_agc_maxgain_line), 96, "agc maximum line gain", NULL},
-    {3, S_O(rec_agc_cliptime), 1, "agc cliptime", "0.2s,0.4s,0.6s,0.8,1s"},
-#endif
-
-#ifdef HAVE_REMOTE_LCD
-#ifdef HAS_REMOTE_BUTTON_HOLD
-    {2, S_O(remote_backlight_on_button_hold), 0, "remote backlight on button hold",
-        "normal,off,on" },
-#endif
-#endif
-
-#ifdef HAVE_HEADPHONE_DETECTION
-    {2, S_O(unplug_mode), 0, "pause on headphone unplug", NULL},
-    {4, S_O(unplug_rw), 0, "rewind duration on pause", NULL},
-    {1, S_O(unplug_autoresume), 0, "disable autoresume if phones not present", off_on },
-#endif
-#ifdef CONFIG_TUNER
-    {2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" },
-#endif
-
-    {1, S_O(audioscrobbler), false, "Last.fm Logging", off_on},
-
-    /* If values are just added to the end, no need to bump the version. */
-    /* new stuff to be added at the end */
-#ifdef HAVE_RECORDING
-    {2, S_O(rec_trigger_type), 0, "trigger type", "stop,pause,nf stp"},
-#endif
-
-    /* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
+struct persistant_vars {
+    void *setting;
+    char value[MAX_FILENAME];
 };
 
-/* helper function to extract n (<=32) bits from an arbitrary position
- * counting from LSB to MSB */
-static uint32_t get_bits(
-    const uint32_t *p, /* the start of the bitfield array */
-    unsigned int from, /* bit no. to start reading from */
-    unsigned int size) /* how many bits to read */
-{
-    unsigned int long_index = from / 32;
-    unsigned int bit_index = from % 32;
-    uint32_t result;
-
-    result = p[long_index] >> bit_index;
-
-    if (bit_index + size > 32)     /* crossing longword boundary */
-        result |= p[long_index+1] << (32 - bit_index);
-
-    result &= 0xFFFFFFFF >> (32 - size);
+#define MAX_PERSISTANT_VARS 16
+struct persistant_vars persistant_variables[MAX_PERSISTANT_VARS];
+int persistant_vars_count = 0;
+void add_to_persistant(const struct settings_list *item, char* value)
+{
+    if (persistant_vars_count<MAX_PERSISTANT_VARS)
+    {
+        strcpy(persistant_variables[persistant_vars_count].value,value);
+        persistant_variables[persistant_vars_count].setting = item->setting;
+        persistant_vars_count++;
+    }
 
-    return result;
 }
 
-/* helper function to set n (<=32) bits to an arbitrary position,
- * counting from LSB to MSB */
-static void set_bits(
-    uint32_t *p,       /* the start of the bitfield array */
-    unsigned int from, /* bit no. to start writing into */
-    unsigned int size, /* how many bits to change */
-    uint32_t value)    /* content (LSBs will be taken) */
-{
-    unsigned int long_index = from / 32;
-    unsigned int bit_index = from % 32;
-    uint32_t mask;
-
-    mask = 0xFFFFFFFF >> (32 - size);
-    value &= mask;
-    mask <<= bit_index;
-
-    if (bit_index + size > 32)
-        p[long_index+1] =
-            (p[long_index+1] & (0xFFFFFFFF << (bit_index + size - 32)))
-            | (value >> (32 - bit_index));
-
-    p[long_index] = (p[long_index] & ~mask) | (value << bit_index);
-}
 
 #ifdef HAVE_LCD_COLOR
 /*
@@ -774,390 +169,1002 @@
 }
 #endif
 
-/*
- * Calculates the checksum for the config block and returns it
- */
-
-static unsigned short calculate_config_checksum(const unsigned char* buf)
+void write_settings_to_disk(void)
 {
-    unsigned int i;
-    unsigned char cksum[2];
-    cksum[0] = cksum[1] = 0;
-
-    for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
-        cksum[0] ^= buf[i];
-        cksum[1] ^= buf[i+1];
-    }
-
-    return (cksum[0] << 8) | cksum[1];
+#ifndef SIMULATOR
+    if (ata_disk_is_active())
+        settings_save_config(ROCKBOX_CONFIGFILE,false);
+    else 
+#endif
+        settings_save();
 }
 
-/*
- * initialize the config block buffer
- */
-static void init_config_buffer( void )
+bool settings_save_ata_cb( void )
 {
-    DEBUGF( "init_config_buffer()\n" );
-
-    /* reset to 0 - all unused */
-    memset(config_block, 0, CONFIG_BLOCK_SIZE);
-    /* insert header */
-    config_block[0] = 'R';
-    config_block[1] = 'o';
-    config_block[2] = 'c';
-    config_block[3] = CONFIG_BLOCK_VERSION;
+#ifndef SIMULATOR
+    queue_broadcast(SYS_DUMPSETTINGS,0); /*hopefully only the main thread 
+                                           will accept use this, so it 
+                                           shouldnt stkOv! */
+#else
+    write_settings_to_disk();
+#endif
+    return 0;
 }
 
-bool flush_config_block_callback(void)
-{
-    ata_write_sectors(IF_MV2(0,) config_sector, 1, config_block);
-    return true;
-}
-/*
- * save the config block buffer to disk or RTC RAM
- */
-static int save_config_buffer( void )
+int settings_save( void )
 {
-    unsigned short chksum;
-#ifdef HAVE_RTC_RAM
-    unsigned int i;
-#endif
-
-    /* update the checksum in the end of the block before saving */
-    chksum = calculate_config_checksum(config_block);
-    config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
-    config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
-
-#ifdef HAVE_RTC_RAM
-    /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
-       that it would write a number of bytes at a time since the RTC chip
-       supports that, but this will have to do for now 8-) */
-    for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
-        int r = rtc_write(0x14+i, config_block[i]);
-        if (r) {
-            DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
-                    14+i, r );
-            return r;
-        }
-    }
-
-#endif
-
-    if (config_sector != 0)
-        register_ata_idle_func(flush_config_block_callback);
-    else
-        return -1;
-
+    register_ata_idle_func(settings_save_ata_cb);
     return 0;
 }
 
-/*
- * load the config block buffer from disk or RTC RAM
- */
-static int load_config_buffer(int which)
+void save_item_to_gs(const struct settings_list *item, char* new_val)
 {
-    unsigned short chksum;
-    bool correct = false;
-
-
-    DEBUGF( "load_config_buffer()\n" );
-
-    if (which & SETTINGS_HD)
+    switch (item->flags&F_T_MASK)
     {
-        if (config_sector != 0) {
-            ata_read_sectors(IF_MV2(0,) config_sector, 1,  config_block);
-            /* calculate the checksum, check it and the header */
-            chksum = calculate_config_checksum(config_block);
+        case F_T_INT:
+#ifdef HAVE_LCD_COLOR
+            if (item->flags&F_STORERGB)
+            {
+                *(int*)item->setting = hex_to_rgb(new_val);
+            }
+            else 
+#endif
+            if (item->flags&F_STOREREALVALUE)
+            {
+                *(int*)item->setting = atoi(new_val);
 
-            if (config_block[0] == 'R' &&
-                config_block[1] == 'o' &&
-                config_block[2] == 'c' &&
-                config_block[3] == CONFIG_BLOCK_VERSION &&
-                (chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
-                (chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
+                if ((item->flags&F_T_CHOICE) && (item->flags&F_RV_ROUNDTOLIST))
+                {
+                    int index = round_value_to_list32(
+                        *(int*)item->setting, (long *)item->values,
+                        item->nb_values,
+                        (item->flags & F_T_MASK) == F_T_INT);
+                    *(int*)item->setting = item->values[index];
+                }                   
+            }
+            else if (item->flags&F_T_CHOICE)
+            {
+                int i;
+                if (item->flags&F_LANG_STRING)
+                {
+                    for (i=0;i<item->nb_values;i++)
+                    {
+                        if (!strcmp(new_val, item->strings[i]))
+                        {
+                            *(int*)item->setting = i;
+                            break;
+                        }
+                    }
+                }
+                else
+                {
+                    char *start, *end;
+                    int len = strlen(new_val);
+                    start = strchr(item->conf_file_info,',');
+                    if (!start)
+                        break;
+                    end = strchr(++start,',');
+                    i = 0;
+                    while (start)
+                    {
+                        if (!strncmp(start,new_val, MAX(((end?end:0)-start),len)))
+                        {
+                            *(int*)item->setting = i;
+                            break;
+                        }
+                        i++;
+                        start = end+1;
+                        if (end)
+                            end = strchr(++end,',');
+                    }
+                }
+            }
+            else *(int*)item->setting = atoi(new_val);
+            break;
+        case F_T_UINT:
+            *(unsigned int*)item->setting = 
+                    (unsigned int)atoi(new_val);
+            break;
+        case F_T_BOOL:
+            if (!strcmp(new_val,"on"))
+                *(bool*)item->setting = true;
+            else *(bool*)item->setting = false;
+            break;
+        case F_T_CHARPTR:
+        case F_T_UCHARPTR:
+            if (item->flags&F_FILENAMEONLY && 
+                strrchr(new_val,'/'))
             {
-                DEBUGF( "load_config_buffer: header & checksum test ok\n" );
-                correct = true;
+                set_file(new_val,
+                         (char*)item->setting,MAX_FILENAME);
             }
-        }
+            else strcpy((char*)item->setting,new_val);
+            break;
     }
+}
+bool check_setting_name(char* from_file, char* in_settings)
+{
+    int len = strlen(from_file);
+    return !strncmp(from_file,in_settings,len) &&
+            ( ( in_settings[len] == ',') ||
+                    ( in_settings[len] == '\0'));
+}
 
-#ifdef HAVE_RTC_RAM
-    if(!correct)
-    {
-        /* If the disk sector was incorrect, reinit the buffer */
-        memset(config_block, 0, CONFIG_BLOCK_SIZE);
-    }
+bool settings_load_config(const char* file)
+{
+    int fd;
+    char line[256];
+    char* name;
+    char* value;
+    int pos; /* currently returned position */
+    const struct settings_list *item;
+    bool persistant = false;
+    
+    fd = open(file, O_RDONLY);
+    if (fd < 0)
+        return false;
 
-    if (which & SETTINGS_RTC)
+    while (read_line(fd, line, sizeof line) > 0)
     {
-        unsigned int i;
-        unsigned char rtc_block[RTC_BLOCK_SIZE];
-
-        /* read rtc block */
-        for (i=0; i < RTC_BLOCK_SIZE; i++ )
-            rtc_block[i] = rtc_read(0x14+i);
-
-        chksum = calculate_config_checksum(rtc_block);
+        if (!settings_parseline(line, &name, &value))
+            continue;
 
-        /* if rtc block is ok, use that */
-        if (rtc_block[0] == 'R' &&
-            rtc_block[1] == 'o' &&
-            rtc_block[2] == 'c' &&
-            rtc_block[3] == CONFIG_BLOCK_VERSION &&
-            (chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
-            (chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
+        if (name[0] == '~') /* load the value, and dont save the new value to disk */
         {
-            memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
-            correct = true;
+            persistant = true;
+            name++;
         }
-    }
-#endif
+        else persistant = false;
 
-    if ( !correct ) {
-        /* if checksum is not valid, clear the config buffer */
-        DEBUGF( "load_config_buffer: header & checksum test failed\n" );
-        init_config_buffer();
-        return -1;
+        for (pos = 0; pos < nb_settings ; pos++)
+        {
+            item = &settings[pos];
+            
+            if (item->flags&(F_SYSTEMSETTING|F_T_CHARPTR|F_LANG_IS_STRING))
+            {
+                if (!strcmp(name,item->cfg_string))
+                {
+                    if (persistant)
+                        add_to_persistant(item,value);
+                    save_item_to_gs(item,value);
+                    break;
+                }
+            }
+            else if (check_setting_name(name,item->conf_file_info))
+            {
+                if (persistant)
+                    add_to_persistant(item,value);
+                save_item_to_gs(item,value);
+                break;
+            }
+        } /* for (...) */
     }
 
-    return 0;
+    close(fd);
+    settings_apply(false);
+    return true;
 }
-
-
-/* helper to save content of global_settings into a bitfield,
-   as described per table */
-static void save_bit_table(const struct bit_entry* p_table, int count, int bitstart)
+#ifdef HAVE_RTC_RAM
+bool load_from_rtc(int rtc_item, int *value)
 {
-    uint32_t *p_bitfield = (uint32_t *)config_block; /* 32 bit addr. */
-    uint32_t value; /* 32 bit content */
-    int i;
-    const struct bit_entry* p_run = p_table; /* start after the size info */
-    int curr_bit = bitstart + p_table->bit_size;
-    count--; /* first is excluded from loop */
-
-    for (i=0; i<count; i++)
-    {
-        p_run++;
-        /* could do a memcpy, but that would be endian-dependent */
-        switch(p_run->byte_size)
-        {
-        case 1:
-            value = ((uint8_t *)&global_settings)[p_run->settings_offset];
-            break;
-        case 2:
-            value = ((uint16_t *)&global_settings)[p_run->settings_offset/2];
-            break;
-        case 4:
-            value = ((uint32_t *)&global_settings)[p_run->settings_offset/4];
-            break;
-        default:
-            DEBUGF( "save_bit_table: illegal size!\n" );
-            continue;
-        }
-        set_bits(p_bitfield, curr_bit, p_run->bit_size & 0x3F, value);
-        curr_bit += p_run->bit_size & 0x3F;
+    if (!rtc_read_multiple(0x14+(rtc_item*4),(char*)value,4))
+        return true;
+    return false;
+}
+    
+bool save_to_rtc(int rtc_item, int value)
+{
+    union { int i; char c[4]; } storage;
+    int j = 0;
+    int ret=0, address = 0x14+(rtc_item*4);
+    storage.i = value;
+    for(j=0; j<4 && ret==0;j++)
+    {
+        ret = rtc_write(address+j, storage.c[j]);
     }
-    set_bits(p_bitfield, bitstart, p_table->bit_size, /* write size */
-        curr_bit); /* = position after last element */
+    return (ret==0) ? true : false;
 }
-
+#endif
 /*
- * figure out the config sector from the partition table and the
- * mounted file system
+ * load settings from disk or RTC RAM
  */
-void settings_calc_config_sector(void)
+void settings_load(int which)
 {
-#ifdef SIMULATOR
-    config_sector = 61;
-#else
-    int i;
-    long partition_start;
-    long sector = 0;
-
-    if (fat_startsector(IF_MV(0)) != 0)    /* There is a partition table */
+    DEBUGF( "reload_all_settings()\n" );
+#ifdef HAVE_RTC_RAM
+    if (which&SETTINGS_RTC)
     {
-        sector = 61;
-        for (i = 0; i < 4; i++)
+        int i, value, rtc_item = 0;
+        bool config_ok = false;
+        if (load_from_rtc(rtc_item,&value) == true)
         {
-            partition_start = disk_partinfo(i)->start;
-            if (partition_start != 0 && (partition_start - 2) < sector)
-                sector = partition_start - 2;
+            if (value == RTC_RAM_CONFIG_VERSION)
+                config_ok = true;
         }
-        if (sector < 0)
-            sector = 0;
-    }
-
-    config_sector = sector;
+        rtc_item++;
+        for (i=0; i<nb_settings; i++)
+        {
+            if (settings[i].flags&F_SAVETORTC)
+            {
+                if (config_ok == true)
+                {
+                    if (load_from_rtc(rtc_item++,
+                        (int*)settings[i].setting) == false)
+                    {
+                        *(int*)settings[i].setting
+                                = settings[i].default_val.int_;
+                    }
+                }
+                else *(int*)settings[i].setting
+                            = settings[i].default_val.int_;
+            }
+        }
+    }
 #endif
+    if (which&SETTINGS_HD)
+    {
+        settings_load_config(ROCKBOX_CONFIGFILE);
+    }
+}
+
+void set_file(char* filename, char* setting, int maxlen)
+{
+    char* fptr = strrchr(filename,'/');
+    int len;
+    int extlen = 0;
+    char* ptr;
+
+    if (!fptr)
+        return;
+
+    *fptr = 0;
+    fptr++;
+
+    len = strlen(fptr);
+    ptr = fptr + len;
+    while ((*ptr != '.') && (ptr != fptr)) {
+        extlen++;
+        ptr--;
+    }
+    if(ptr == fptr) extlen = 0;
+
+    if (strncasecmp(ROCKBOX_DIR, filename ,strlen(ROCKBOX_DIR)) ||
+        (len-extlen > maxlen))
+        return;
+
+    strncpy(setting, fptr, len-extlen);
+    setting[len-extlen]=0;
+    settings_save();
 }
 
 /*
- * persist all runtime user settings to disk or RTC RAM
+ * reset all settings to their default value
  */
-int settings_save( void )
+void settings_reset(void) 
 {
-    int i;
+    int i; 
+    const struct settings_list *item;
+    DEBUGF( "settings_reset()\n" );
 
+    for (i = 0; i < nb_settings ; i++)
     {
-        int elapsed_secs;
+        item = &settings[i];         
+        if (item->flags&F_T_SOUND)
+        {
+            *(int*)item->setting
+                    = sound_default(item->values[0]);
+            continue;
+        }
+        switch (item->flags&F_T_MASK)
+        {
+            case F_T_INT:
+                *(int*)item->setting
+                        = item->default_val.int_;
+                break;
+            case F_T_UINT:
+                *(unsigned int*)item->setting
+                        = item->default_val.uint_;
+                break;
+            case F_T_BOOL:
+                *(bool*)item->setting
+                        = item->default_val.bool_;
+                break;
+            case F_T_CHARPTR:
+            case F_T_UCHARPTR:
+                strcpy((char*)item->setting,
+                        item->default_val.charptr);
+                break;
+        }
+    } /* for (...) */
+}
 
-        elapsed_secs = (current_tick - lasttime) / HZ;
-        global_settings.runtime += elapsed_secs;
-        lasttime += (elapsed_secs * HZ);
-
-        if ( global_settings.runtime > global_settings.topruntime )
-            global_settings.topruntime = global_settings.runtime;
-    }
-
-    /* serialize scalar values into RTC and HD sector, specified via table */
-    save_bit_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), 4*8);
-    save_bit_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), RTC_BLOCK_SIZE*8);
-
-    i = 0xb8;
-    strncpy((char *)&config_block[i], (char *)global_settings.wps_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-    strncpy((char *)&config_block[i], (char *)global_settings.lang_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-    strncpy((char *)&config_block[i], (char *)global_settings.font_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#ifdef HAVE_REMOTE_LCD
-    strncpy((char *)&config_block[i], (char *)global_settings.rwps_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
+bool settings_save_config(const char* filename, bool theme)
+{
+    int fd;
+    int i, value = 0, type;
+    int j;
+    bool persistant = false;
+    char name[256], *char_value;
+    const struct settings_list *item;
+    
+#ifdef HAVE_RTC_RAM
+    j = 0;
+    save_to_rtc(j++, RTC_RAM_CONFIG_VERSION);
+    for (i=0; i<nb_settings; i++)
+    {
+        if (settings[i].flags&F_SAVETORTC)
+        {
+            value = *(int*)settings[i].setting;
+            save_to_rtc(j++, value);
+        }
+    }
 #endif
 
-#ifdef CONFIG_TUNER
-    strncpy((char *)&config_block[i], (char *)global_settings.fmr_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#endif
+    fd = creat(filename, O_WRONLY);
+    if (fd < 0)
+        return false;
+    
+    fdprintf(fd, "#\r\n# .cfg file created by rockbox %s - "
+            "http://www.rockbox.org\r\n#\r\n\r\n", appsversion);
+    
+    for (i=0; i < nb_settings; i++)
+    {
+        persistant = false;
+        item = &settings[i];
+        if (theme && ((item->flags&F_THEMESETTING) == 0))
+            continue;
+        type = item->flags&F_T_MASK;
+        if (item->flags&F_LANG_IS_STRING)
+            strcpy(name,item->cfg_string);
+        else 
+        {
+            char *p = strchr(item->conf_file_info,',');
+            if (p)
+            {
+                strncpy(name,item->conf_file_info,p-item->conf_file_info);
+                name[p-item->conf_file_info] = '\0';
+            }
+            else strcpy(name,item->conf_file_info);
+        }
+        
+        char_value = NULL;
 
-#if LCD_DEPTH > 1
-    strncpy((char *)&config_block[i], (char *)global_settings.backdrop_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#endif
-#ifdef HAVE_LCD_BITMAP
-    strncpy((char *)&config_block[i], (char *)global_settings.kbd_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#endif
+        for (j=0; j<persistant_vars_count; j++)
+        {
+            if (persistant_variables[j].setting == item->setting)
+            {
+                persistant = true;
+                char_value = persistant_variables[j].value;
+                break;
+            }
+        }
 
-    if(save_config_buffer())
-    {
-        lcd_clear_display();
-#ifdef HAVE_REMOTE_LCD
-        lcd_remote_clear_display();
-#endif
-#ifdef HAVE_LCD_CHARCELLS
-        lcd_puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER));
-        lcd_puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER));
-#else
-        lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
-        lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
-        lcd_update();
-#ifdef HAVE_REMOTE_LCD
-        lcd_remote_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
-        lcd_remote_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
-        lcd_remote_update();
-#endif
+        if (persistant == false)
+        {
+            switch (type)
+            {
+                case F_T_INT:
+                    value = *(int*)item->setting;
+                    if ((item->flags&(F_T_CHOICE|F_SYSTEMSETTING|
+                            F_STORERGB|F_T_SOUND|F_STOREREALVALUE)) == 0)
+                        fdprintf(fd,"# %s - min=%d, max=%d, step=%d\r\n",
+                            name,item->values[0],item->values[1],
+                            item->values[2]);
+                    break;
+                case F_T_UINT:
+                    value = *(unsigned int*)item->setting;
+                    if ((item->flags&(F_T_CHOICE|F_SYSTEMSETTING|
+                            F_STORERGB|F_T_SOUND|F_STOREREALVALUE)) == 0)
+                        fdprintf(fd,"# %s - min=%d, max=%d, step=%d\r\n",
+                            name,
+                                item->values[0],item->values[1],item->values[2]);
+                    break;
+                case F_T_BOOL:
+                    char_value = 
+                            (*(bool*)item->setting==true)?
+                                    "on":"off";
+                    fdprintf(fd,"# %s - on, off\r\n",name);
+                    break;
+                case F_T_CHARPTR:
+                case F_T_UCHARPTR:
+                    char_value = (char*)item->setting;
+                    break;
+            }
+            if ((item->flags&F_T_CHOICE) && ((item->flags&F_STOREREALVALUE) == 0))
+            {
+                fdprintf(fd,"# %s - ", name);
+                if (item->flags&F_LANG_STRING)
+                {
+                    for(j=0;j<item->nb_values;j++)
+                        fdprintf(fd,"%s,", item->strings[j]);
+                    fdprintf(fd,"\r\n");
+                    char_value = item->strings[value];
+                }
+                else 
+                {
+                    char *p;
+                    p = strchr(item->conf_file_info,',');
+                    if (p)
+                    {
+                        p++;
+                        fdprintf(fd,"%s\r\n", p);
+                        for(j=0;j<value && *p;j++)
+                        {
+                            while (*p != ',' && *p)
+                                p++;
+                            if (*p) p++; /* skip over the comma */
+                        }
+                        char_value = p;
+                    }
+                    else char_value = item->conf_file_info;
+                }
+            }
+        } /* if (!persistant) */
+        
+#ifdef HAVE_LCD_COLOR
+        if (item->flags&F_STORERGB && char_value==NULL)
+        {
+            fdprintf(fd, "# %s - RRGGBB (hex values)\r\n%s: %02x%02x%02x\r\n",
+                    name,name,
+                    (int)RGB_UNPACK_RED(value),
+                    (int)RGB_UNPACK_GREEN(value),
+                    (int)RGB_UNPACK_BLUE(value));
+        }
+        else 
 #endif
-        sleep(HZ*2);
-        return -1;
-    }
-    return 0;
+        if (char_value == NULL)
+        {
+            fdprintf(fd,"%c%s: %d\r\n",(persistant == true)?'~':'\0',
+                     name, value);
+        }
+        else
+        {
+            char *p = strchr(char_value,',');
+            char text[128];
+            if (p)
+            {
+                strncpy(text,char_value,p-char_value);
+                text[p-char_value] = '\0';
+            }
+            else strcpy(text,char_value);
+            fdprintf(fd,"%c%s: %s\r\n",(persistant == true)?'~':'\0',
+                    name, text);
+        }
+    } /* for(...) */
+    close(fd);
+    return true;
+}
+bool set_bool(const char* string, bool* variable )
+{
+    return set_bool_options(string, variable,
+                            (char *)STR(LANG_SET_BOOL_YES),
+                            (char *)STR(LANG_SET_BOOL_NO),
+                            NULL);
 }
 
-#ifdef HAVE_LCD_BITMAP
-/**
- * Applies the range infos stored in global_settings to
- * the peak meter.
- */
-void settings_apply_pm_range(void)
+/* wrapper to convert from int param to bool param in set_option */
+static void (*boolfunction)(bool);
+void bool_funcwrapper(int value)
 {
-    int pm_min, pm_max;
+    if (value)
+        boolfunction(true);
+    else
+        boolfunction(false);
+}
 
-    /* depending on the scale mode (dBfs or percent) the values
-       of global_settings.peak_meter_dbfs have different meanings */
-    if (global_settings.peak_meter_dbfs)
+bool set_bool_options(const char* string, bool* variable,
+                      const char* yes_str, int yes_voice,
+                      const char* no_str, int no_voice,
+                      void (*function)(bool))
+{
+    struct opt_items names[] = {
+        {(unsigned char *)no_str, no_voice},
+        {(unsigned char *)yes_str, yes_voice}
+    };
+    bool result;
+
+    boolfunction = function;
+    result = set_option(string, variable, BOOL, names, 2,
+                        function ? bool_funcwrapper : NULL);
+    return result;
+}
+
+void talk_unit(int unit, int value)
+{
+    if (global_settings.talk_menu)
     {
-        /* convert to dBfs * 100          */
-        pm_min = -(((int)global_settings.peak_meter_min) * 100);
-        pm_max = -(((int)global_settings.peak_meter_max) * 100);
+        if (unit < UNIT_LAST)
+        {   /* use the available unit definition */
+            talk_value(value, unit, false);
+        }
+        else
+        {   /* say the number, followed by an arbitrary voice ID */
+            talk_number(value, false);
+            talk_id(unit, true);
+        }
     }
+}
+ 
+int selected_setting; /* Used by the callback */
+void dec_sound_formatter(char *buffer, int buffer_size, int val, const char * unit)
+{
+    val = sound_val2phys(selected_setting, val);
+    char sign = ' ';
+    if(val < 0)
+    {
+        sign = '-';
+        val = (val<0) ? -val : val;
+    }
+    int integer = val / 10;
+    int dec = val % 10;
+    snprintf(buffer, buffer_size, "%c%d.%d %s", sign, integer, dec, unit);
+}
+
+bool set_sound(const unsigned char * string,
+               int* variable,
+               int setting)
+{
+    int talkunit = UNIT_INT;
+    const char* unit = sound_unit(setting);
+    int numdec = sound_numdecimals(setting);
+    int steps = sound_steps(setting);
+    int min = sound_min(setting);
+    int max = sound_max(setting);
+    sound_set_type* sound_callback = sound_get_fn(setting);
+    if (*unit == 'd') /* crude reconstruction */
+        talkunit = UNIT_DB;
+    else if (*unit == '%')
+        talkunit = UNIT_PERCENT;
+    else if (*unit == 'H')
+        talkunit = UNIT_HERTZ;
+    if(!numdec)
+#if CONFIG_CODEC == SWCODEC
+        /* We need to hijack this one and send it off to apps/dsp.c instead of
+                firmware/sound.c */
+                if (setting == SOUND_STEREO_WIDTH)
+                return set_int(string, unit, talkunit,  variable, &stereo_width_set,
+                               steps, min, max, NULL );
     else
-    {
-        /* percent is stored directly -> no conversion */
-        pm_min = global_settings.peak_meter_min;
-        pm_max = global_settings.peak_meter_max;
+#endif   
+                return set_int(string, unit, talkunit,  variable, sound_callback,
+                               steps, min, max, NULL );
+    else
+    {/* Decimal number */
+        selected_setting=setting;
+        return set_int(string, unit, talkunit,  variable, sound_callback,
+                       steps, min, max, &dec_sound_formatter );
     }
-
-    /* apply the range */
-    peak_meter_init_range(global_settings.peak_meter_dbfs, pm_min, pm_max);
 }
-#endif /* HAVE_LCD_BITMAP */
 
-void sound_settings_apply(void)
+ struct value_setting_data {
+     enum optiontype type;
+    int cur_setting; /* current setting as an index in settings list*/
+     /* used for "value" settings.. */
+     int max;
+     int step;
+     int voice_unit;
+     const char * unit;
+     void (*formatter)(char* dest, int dest_length,
+     int variable, const char* unit);
+     /* used for BOOL and "choice" settings */
+     struct opt_items* options;
+ };
+    
+char * value_setting_get_name_cb(int selected_item,void * data, char *buffer)
 {
-    sound_set(SOUND_BASS, global_settings.bass);
-    sound_set(SOUND_TREBLE, global_settings.treble);
-    sound_set(SOUND_BALANCE, global_settings.balance);
-    sound_set(SOUND_VOLUME, global_settings.volume);
-#if CONFIG_CODEC == SWCODEC
-    channels_set(global_settings.channel_config);
-    stereo_width_set(global_settings.stereo_width);
+    struct value_setting_data* cb_data = 
+            (struct value_setting_data*)data;
+    if (cb_data->type == INT && !cb_data->options)
+    {
+        int item = cb_data->max -(selected_item*cb_data->step);
+        if (cb_data->formatter)
+            cb_data->formatter(buffer, MAX_PATH,item,cb_data->unit);
+        else
+            snprintf(buffer, MAX_PATH,"%d %s",item,cb_data->unit);
+    }
+    else strcpy(buffer,P2STR(cb_data->options[selected_item].string));
+    return buffer;
+} 
+void value_setting_icon_cb(int selected_item, void * data, ICON * icon)
+{
+    struct value_setting_data* cb_data = 
+            (struct value_setting_data*)data;
+
+    if (selected_item == cb_data->cur_setting)
+#ifdef HAVE_LCD_BITMAP
+        *icon=bitmap_icons_6x8[Icon_Checkmark];
 #else
-    sound_set(SOUND_CHANNELS, global_settings.channel_config);
-    sound_set(SOUND_STEREO_WIDTH, global_settings.stereo_width);
+        *icon=Icon_Checkmark;
 #endif
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    sound_set(SOUND_LOUDNESS, global_settings.loudness);
-    sound_set(SOUND_AVC, global_settings.avc);
-    sound_set(SOUND_MDB_STRENGTH, global_settings.mdb_strength);
-    sound_set(SOUND_MDB_HARMONICS, global_settings.mdb_harmonics);
-    sound_set(SOUND_MDB_CENTER, global_settings.mdb_center);
-    sound_set(SOUND_MDB_SHAPE, global_settings.mdb_shape);
-    sound_set(SOUND_MDB_ENABLE, global_settings.mdb_enable);
-    sound_set(SOUND_SUPERBASS, global_settings.superbass);
+    else
+#ifdef HAVE_LCD_BITMAP
+        *icon=0;
+#else
+        *icon=-1;
 #endif
 }
-
-void settings_apply(void)
+void talk_setting(void *global_settings_variable)
 {
-    char buf[64];
-#if CONFIG_CODEC == SWCODEC
-    int i;
-#endif
-
-    sound_settings_apply();
-
-    audio_set_buffer_margin(global_settings.buffer_margin);
-
-#ifdef HAVE_LCD_CONTRAST
-    lcd_set_contrast(global_settings.contrast);
-#endif
-    lcd_scroll_speed(global_settings.scroll_speed);
-#ifdef HAVE_REMOTE_LCD
-    lcd_remote_set_contrast(global_settings.remote_contrast);
-    lcd_remote_set_invert_display(global_settings.remote_invert);
-    lcd_remote_set_flip(global_settings.remote_flip_display);
-    lcd_remote_scroll_speed(global_settings.remote_scroll_speed);
-    lcd_remote_scroll_step(global_settings.remote_scroll_step);
-    lcd_remote_scroll_delay(global_settings.remote_scroll_delay * (HZ/10));
-    lcd_remote_bidir_scroll(global_settings.remote_bidir_limit);
-#ifdef HAVE_REMOTE_LCD_TICKING
-    lcd_remote_emireduce(global_settings.remote_reduce_ticking);
-#endif
-    remote_backlight_set_timeout(global_settings.remote_backlight_timeout);
-#ifdef CONFIG_CHARGING
-    remote_backlight_set_timeout_plugged(global_settings.remote_backlight_timeout_plugged);
-#endif
-#ifdef HAS_REMOTE_BUTTON_HOLD
-    remote_backlight_set_on_button_hold(global_settings.remote_backlight_on_button_hold);
+    const struct settings_list *setting;
+    int id = -1;
+    if (global_settings.talk_menu == 0)
+        return;
+    setting = find_setting(global_settings_variable);
+    if (setting == NULL)
+        return;
+    if ((setting->flags&F_LANG_IS_STRING) == 0)
+    {
+        id = setting->cfg_lang_id;
+    }
+    if (id != -1)
+        talk_id(id,false);
+}
+    
+ #define type_fromvoidptr(type, value) \
+     (type == INT)? \
+         (int)(*(int*)(value)) \
+     : \
+         (bool)(*(bool*)(value))
+ bool do_set_setting(const unsigned char* string, void *variable,
+                     int nb_items,
+                     struct value_setting_data *cb_data,
+                     void (*function)(int))
+ {
+    int action;
+    bool done = false;
+    struct gui_synclist lists;
+    int oldvalue;
+    bool allow_wrap = true;
+    
+    if (cb_data->type == INT)
+    {
+         oldvalue = *(int*)variable;
+         if (variable == &global_settings.volume)
+             allow_wrap = false;
+    }
+    else oldvalue = *(bool*)variable;
+    
+    gui_synclist_init(&lists,value_setting_get_name_cb,(void*)cb_data,false,1);
+    gui_synclist_set_title(&lists, (char*)string, NOICON);
+    gui_synclist_set_icon_callback(&lists,value_setting_icon_cb);
+    gui_synclist_set_nb_items(&lists,nb_items);
+    gui_synclist_limit_scroll(&lists,true);
+    gui_synclist_select_item(&lists, cb_data->cur_setting);
+    
+    if (global_settings.talk_menu)
+    {
+        if (cb_data->type == INT && !cb_data->options)
+            talk_unit(cb_data->voice_unit, *(int*)variable);
+        else talk_id(cb_data->options[cb_data->cur_setting].voice_id, false);
+    }
+    
+    gui_synclist_draw(&lists);
+    while (!done)
+    {
+        
+        action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK); 
+        if (action == ACTION_NONE)
+            continue;
+        if (gui_synclist_do_button(&lists,action,
+                                   allow_wrap?LIST_WRAP_UNLESS_HELD:LIST_WRAP_OFF))
+        {
+            if (global_settings.talk_menu)
+            {
+                int value;
+                if (cb_data->type == INT && !cb_data->options)
+                {
+                    value = cb_data->max - 
+                            gui_synclist_get_sel_pos(&lists)*cb_data->step;
+                    talk_unit(cb_data->voice_unit, value);
+                }
+                else 
+                {
+                    value = gui_synclist_get_sel_pos(&lists);
+                    talk_id(cb_data->options[value].voice_id, false);
+                }
+            }
+            if (cb_data->type == INT && !cb_data->options)
+                *(int*)variable = cb_data->max - 
+                        gui_synclist_get_sel_pos(&lists)*cb_data->step;
+            else if (cb_data->type == BOOL)
+                *(bool*)variable = gui_synclist_get_sel_pos(&lists) ? true : false;
+            else *(int*)variable = gui_synclist_get_sel_pos(&lists);
+        }  
+        else if (action == ACTION_STD_CANCEL)
+        {
+            gui_syncsplash(HZ/2,true,str(LANG_MENU_SETTING_CANCEL));
+            if (cb_data->type == INT)
+                *(int*)variable = oldvalue;
+            else *(bool*)variable = (bool)oldvalue;
+            done = true;
+        }
+        else if (action == ACTION_STD_OK)
+        {
+            done = true;
+        }
+        else if(default_event_handler(action) == SYS_USB_CONNECTED)
+            return true;
+        gui_syncstatusbar_draw(&statusbars, false);
+        if ( function )
+            function(type_fromvoidptr(cb_data->type,variable));
+    }
+    return false;
+}
+bool set_int(const unsigned char* string,
+             const char* unit,
+             int voice_unit,
+             int* variable,
+             void (*function)(int),
+             int step,
+             int min,
+             int max,
+             void (*formatter)(char*, int, int, const char*) )
+{
+#if CONFIG_KEYPAD != PLAYER_PAD
+    struct value_setting_data data = {
+        INT,(max-*variable)/step, max, step, voice_unit,unit,formatter,NULL };
+#else
+     int count = (max-min)/step + 1;
+     struct value_setting_data data = {
+        INT,count - ((max-*variable)/step), min, -step, voice_unit,unit,formatter,NULL };
+#endif
+    /* untill a better way is found */
+    switch (voice_unit)
+    {
+        case UNIT_MS:
+            data.unit = "ms";
+            break;
+        case UNIT_SEC:
+            data.unit = "s";
+            break;
+        case UNIT_KHZ:
+            data.unit = "kHz";
+            break;
+        case UNIT_DB:
+            data.unit = "dB";
+            break;
+        case UNIT_PERCENT:
+            data.unit = "%";
+            break;
+        case UNIT_MAH:
+            data.unit = "mAh";
+            break;
+        case UNIT_PIXEL:
+            data.unit = "px";
+            break;
+        case UNIT_PER_SEC:
+            data.unit = "per sec";
+            break;
+        case UNIT_HERTZ:
+            data.unit = "Hz";
+            break;
+        case UNIT_MB:
+            data.unit = "MB";
+            break;
+        case UNIT_KBIT: /* kilobits per sec */
+            data.unit = "kb/s";
+            break;
+        default:
+            data.unit = "";
+            break;
+    }
+    return do_set_setting(string,variable,(max-min)/step + 1,
+                          &data,function);
+}
+
+/* NOTE: the 'type' parameter specifies the actual type of the variable
+   that 'variable' points to. not the value within. Only variables with
+   type 'bool' should use parameter BOOL.
+
+   The type separation is necessary since int and bool are fundamentally
+   different and bit-incompatible types and can not share the same access
+   code. */ 
+bool set_option(const char* string, void* variable, enum optiontype type,
+                const struct opt_items* options, int numoptions, void (*function)(int))
+{
+    struct value_setting_data data = {
+        type,0,0, 0, 0,NULL,NULL,(struct opt_items*)options };
+    if (type == BOOL)
+        data.cur_setting = *(bool*)variable ? 1 : 0;
+    else data.cur_setting = *(int*)variable;
+    return do_set_setting(string,variable,numoptions,
+                          &data,function);
+}
+
+#define MAX_OPTIONS 64
+bool load_setting_screen(struct settings_list *setting)
+{
+    void* variable;
+    int   temp_var = 0;
+    bool ret = false;
+    if(!setting)
+        return false;
+    variable = setting->setting;
+        
+    switch (setting->flags&F_T_MASK)
+    {
+        case F_T_BOOL:
+            if (setting->flags&F_TEMPVARIABLE)
+            {
+                bool temp_v = *(bool*)setting->setting;
+                ret = set_bool(str(setting->cfg_lang_id),&temp_v);
+                if (temp_v != *(bool*)setting->setting)
+                    *(bool*)setting->setting = temp_v;
+            }
+            else ret = set_bool(str(setting->cfg_lang_id),(bool*)variable);
+            break;
+        case F_T_INT:
+        case F_T_UINT:
+            if (setting->flags&F_T_CHOICE)
+            {
+                static struct opt_items options[MAX_OPTIONS];
+                int i, count = setting->nb_values, j=0;
+                bool store_real = setting->flags&F_STOREREALVALUE;
+                for (i=0; i<count && i<MAX_OPTIONS; i++)
+                {
+                    if (setting->flags&F_LANG_STRING)
+                    {
+                        options[j].string = setting->strings[i];
+                        if (settings->talk_id != NULL)
+                            options[j].voice_id = settings->talk_id[i];
+                    }
+                    else 
+                    {
+                        options[j].string = ID2P(setting->values[i]);
+                        options[j].voice_id = setting->values[i];
+                    }
+                    if (store_real)
+                        i++; /* skip the real val for now */
+                    j++;
+                }
+                if (setting->flags&(F_TEMPVARIABLE|F_STOREREALVALUE))
+                {
+                    variable = (void*)&temp_var;
+                    temp_var = *(int*)setting->setting;
+                    if (store_real) /* find the fake value */
+                    {
+                        for (i=1; i<count; i+=2)
+                        {
+                            if (setting->values[i] == temp_var)
+                            {
+                                temp_var = (i/2);
+                                break;
+                            }
+                        }
+                    }
+                    
+                    ret = set_option(ID2P(setting->cfg_lang_id),variable,INT,
+                                     options, j, (void*)setting->function);
+                    if (store_real) /* convert it back to the real value*/
+                    {
+                        temp_var = setting->values[1+(temp_var*2)];
+                    }
+                    if (*(int*)variable != 
+                          *(int*)setting->setting)
+                        *(int*)setting->setting
+                                = *(int*)variable;
+                }
+                else ret = set_option(str(setting->cfg_lang_id),variable,INT,
+                                      options, i, (void*)setting->function);
+            }
+            else if (setting->flags&F_T_SOUND)
+            {
+                ret = set_sound(str(setting->cfg_lang_id),
+                          (int*)variable,setting->values[0]);
+            }
+            else
+            {
+                if (setting->flags&F_TEMPVARIABLE)
+                {
+                    variable = (void*)temp_var;
+                    *(int*)variable = *(int*)setting->setting;
+                }
+                ret = set_int(str(setting->cfg_lang_id),
+                              str(setting->talk_id[0]),setting->talk_id[0],
+                              (int*)variable,(void*)setting->function,
+                              setting->values[2],
+                              setting->values[0],setting->values[1],
+                              (void*)setting->values[3]);
+                if (setting->flags&F_TEMPVARIABLE)
+                {
+                    if (*(int*)variable != 
+                          *(int*)setting->setting)
+                        *(int*)setting->setting
+                                = *(int*)variable;
+                }
+            }
+            break;
+    }
+    
+    return ret;
+}
+
+#ifdef HAVE_LCD_BITMAP
+/**
+ * Applies the range infos stored in global_settings to
+ * the peak meter.
+ */
+void settings_apply_pm_range(void)
+{
+    int pm_min, pm_max;
+
+    /* depending on the scale mode (dBfs or percent) the values
+       of global_settings.peak_meter_dbfs have different meanings */
+    if (global_settings.peak_meter_dbfs)
+    {
+        /* convert to dBfs * 100          */
+        pm_min = -(((int)global_settings.peak_meter_min) * 100);
+        pm_max = -(((int)global_settings.peak_meter_max) * 100);
+    }
+    else
+    {
+        /* percent is stored directly -> no conversion */
+        pm_min = global_settings.peak_meter_min;
+        pm_max = global_settings.peak_meter_max;
+    }
+
+    /* apply the range */
+    peak_meter_init_range(global_settings.peak_meter_dbfs, pm_min, pm_max);
+}
+#endif /* HAVE_LCD_BITMAP */
+
+void sound_settings_apply(void)
+{
+    sound_set(SOUND_BASS, global_settings.bass);
+    sound_set(SOUND_TREBLE, global_settings.treble);
+    sound_set(SOUND_BALANCE, global_settings.balance);
+    sound_set(SOUND_VOLUME, global_settings.volume);
+#if CONFIG_CODEC == SWCODEC
+    channels_set(global_settings.channel_config);
+    stereo_width_set(global_settings.stereo_width);
+#else
+    sound_set(SOUND_CHANNELS, global_settings.channel_config);
+    sound_set(SOUND_STEREO_WIDTH, global_settings.stereo_width);
+#endif
+#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
+    sound_set(SOUND_LOUDNESS, global_settings.loudness);
+    sound_set(SOUND_AVC, global_settings.avc);
+    sound_set(SOUND_MDB_STRENGTH, global_settings.mdb_strength);
+    sound_set(SOUND_MDB_HARMONICS, global_settings.mdb_harmonics);
+    sound_set(SOUND_MDB_CENTER, global_settings.mdb_center);
+    sound_set(SOUND_MDB_SHAPE, global_settings.mdb_shape);
+    sound_set(SOUND_MDB_ENABLE, global_settings.mdb_enable);
+    sound_set(SOUND_SUPERBASS, global_settings.superbass);
+#endif
+}
+
+void settings_apply(bool partial)
+{
+    char buf[MAX_PATH];
+#if CONFIG_CODEC == SWCODEC
+    int i;
+#endif
+
+    sound_settings_apply();
+
+    audio_set_buffer_margin(global_settings.buffer_margin);
+
+#ifdef HAVE_LCD_CONTRAST
+    lcd_set_contrast(global_settings.contrast);
+#endif
+    lcd_scroll_speed(global_settings.scroll_speed);
+#ifdef HAVE_REMOTE_LCD
+    lcd_remote_set_contrast(global_settings.remote_contrast);
+    lcd_remote_set_invert_display(global_settings.remote_invert);
+    lcd_remote_set_flip(global_settings.remote_flip_display);
+    lcd_remote_scroll_speed(global_settings.remote_scroll_speed);
+    lcd_remote_scroll_step(global_settings.remote_scroll_step);
+    lcd_remote_scroll_delay(global_settings.remote_scroll_delay * (HZ/10));
+    lcd_remote_bidir_scroll(global_settings.remote_bidir_limit);
+#ifdef HAVE_REMOTE_LCD_TICKING
+    lcd_remote_emireduce(global_settings.remote_reduce_ticking);
+#endif
+    remote_backlight_set_timeout(global_settings.remote_backlight_timeout);
+#ifdef CONFIG_CHARGING
+    remote_backlight_set_timeout_plugged(global_settings.remote_backlight_timeout_plugged);
+#endif
+#ifdef HAS_REMOTE_BUTTON_HOLD
+    remote_backlight_set_on_button_hold(global_settings.remote_backlight_on_button_hold);
 #endif
 #endif /* HAVE_REMOTE_LCD */
 #ifdef CONFIG_BACKLIGHT
@@ -1199,68 +1206,74 @@
         global_settings.peak_meter_release, global_settings.peak_meter_hold,
         global_settings.peak_meter_clip_hold);
 #endif
-
+    if (!partial)
+    {
 #if LCD_DEPTH > 1
-    unload_wps_backdrop();
+        unload_wps_backdrop();
 #endif
-    if ( global_settings.wps_file[0] &&
-         global_settings.wps_file[0] != 0xff ) {
-        snprintf(buf, sizeof buf, WPS_DIR "/%s.wps",
-                 global_settings.wps_file);
-        wps_data_load(gui_wps[0].data, buf, true);
-    }
-    else
-    {
-        wps_data_init(gui_wps[0].data);
-    }
+        if ( global_settings.wps_file[0] &&
+            global_settings.wps_file[0] != 0xff ) {
+            snprintf(buf, sizeof buf, WPS_DIR "/%s.wps",
+                    global_settings.wps_file);
+            wps_data_load(gui_wps[0].data, buf, true);
+        }
+        else
+        {
+            wps_data_init(gui_wps[0].data);
+        }
 
 #if LCD_DEPTH > 1
-    if ( global_settings.backdrop_file[0] &&
-         global_settings.backdrop_file[0] != 0xff ) {
-        snprintf(buf, sizeof buf, BACKDROP_DIR "/%s.bmp",
-                 global_settings.backdrop_file);
-        load_main_backdrop(buf);
-    } else {
-        unload_main_backdrop();
-    }
-    show_main_backdrop();
+        if ( global_settings.backdrop_file[0] &&
+            global_settings.backdrop_file[0] != 0xff ) {
+            snprintf(buf, sizeof buf, BACKDROP_DIR "/%s.bmp",
+                    global_settings.backdrop_file);
+            load_main_backdrop(buf);
+        } else {
+            unload_main_backdrop();
+        }
+        show_main_backdrop();
 #endif
-
+    }
 #ifdef HAVE_LCD_COLOR
     screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
     screens[SCREEN_MAIN].set_background(global_settings.bg_color);
 #endif
-
+    
 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
-    if ( global_settings.rwps_file[0] &&
-         global_settings.rwps_file[0] != 0xff ) {
-        snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps",
-                 global_settings.rwps_file);
-        wps_data_load(gui_wps[1].data, buf, true);
+    if (!partial)
+    {
+        if ( global_settings.rwps_file[0] &&
+            global_settings.rwps_file[0] != 0xff ) {
+            snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps",
+                    global_settings.rwps_file);
+            wps_data_load(gui_wps[1].data, buf, true);
+        }
+        else
+            wps_data_init(gui_wps[1].data);
     }
-    else
-        wps_data_init(gui_wps[1].data);
 #endif
 
 #ifdef HAVE_LCD_BITMAP
-    if ( global_settings.font_file[0] &&
-         global_settings.font_file[0] != 0xff ) {
-        snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
-                 global_settings.font_file);
-        font_load(buf);
-    }
-    else
-        font_reset();
-
-    if ( global_settings.kbd_file[0] &&
-         global_settings.kbd_file[0] != 0xff ) {
-        snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd",
-                 global_settings.kbd_file);
-        load_kbd(buf);
+    if (!partial)
+    {
+        if ( global_settings.font_file[0] &&
+            global_settings.font_file[0] != 0xff ) {
+            snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                    global_settings.font_file);
+            font_load(buf);
+        }
+        else
+            font_reset();
+    
+        if ( global_settings.kbd_file[0] &&
+            global_settings.kbd_file[0] != 0xff ) {
+            snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd",
+                    global_settings.kbd_file);
+            load_kbd(buf);
+        }
+        else
+            load_kbd(NULL);
     }
-    else
-        load_kbd(NULL);
-
     lcd_scroll_step(global_settings.scroll_step);
     gui_list_screen_scroll_step(global_settings.screen_scroll_step);
     gui_list_screen_scroll_out_of_view(global_settings.offset_out_of_view);
@@ -1270,15 +1283,16 @@
 #endif
     lcd_bidir_scroll(global_settings.bidir_limit);
     lcd_scroll_delay(global_settings.scroll_delay * (HZ/10));
-
-    if ( global_settings.lang_file[0] &&
-         global_settings.lang_file[0] != 0xff ) {
-        snprintf(buf, sizeof buf, LANG_DIR "/%s.lng",
-                 global_settings.lang_file);
-        lang_load(buf);
-        talk_init(); /* use voice of same language */
+    if (!partial)
+    {
+        if ( global_settings.lang_file[0] &&
+            global_settings.lang_file[0] != 0xff ) {
+            snprintf(buf, sizeof buf, LANG_DIR "/%s.lng",
+                    global_settings.lang_file);
+            lang_load(buf);
+            talk_init(); /* use voice of same language */
+        }
     }
-
     set_codepage(global_settings.default_codepage);
 
 #if CONFIG_CODEC == SWCODEC
@@ -1326,891 +1340,5 @@
 #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
     enc_global_settings_apply();
 #endif
+    write_settings_to_disk();
 }
-
-
-/* helper to load global_settings from a bitfield, as described per table */
-static void load_bit_table(const struct bit_entry* p_table, int count, int bitstart)
-{
-    uint32_t *p_bitfield = (uint32_t *)config_block; /* 32 bit addr. */
-    uint32_t value; /* 32 bit content */
-    int i;
-    int maxbit; /* how many bits are valid in the saved part */
-    const struct bit_entry* p_run = p_table; /* start after the size info */
-    count--; /* first is excluded from loop */
-    maxbit = get_bits(p_bitfield, bitstart, p_table->bit_size);
-    bitstart += p_table->bit_size;
-
-    for (i=0; i<count; i++)
-    {
-        int size;
-        p_run++;
-
-        size = p_run->bit_size & 0x3F; /* mask off abused bits */
-        if (bitstart + size > maxbit)
-            break; /* exit if this is not valid any more in bitfield */
-
-        value = get_bits(p_bitfield, bitstart, size);
-        bitstart += size;
-        if (p_run->bit_size & SIGNED)
-        {   // sign extend the read value
-            unsigned long mask = 0xFFFFFFFF << (size - 1);
-            if (value & mask) /* true if MSB of value is set */
-                value |= mask;
-        }
-
-        /* could do a memcpy, but that would be endian-dependent */
-        switch(p_run->byte_size)
-        {
-        case 1:
-            ((uint8_t *)&global_settings)[p_run->settings_offset] =
-                (unsigned char)value;
-            break;
-        case 2:
-            ((uint16_t *)&global_settings)[p_run->settings_offset/2] =
-                (unsigned short)value;
-            break;
-        case 4:
-            ((uint32_t *)&global_settings)[p_run->settings_offset/4] =
-                (unsigned int)value;
-            break;
-        default:
-            DEBUGF( "load_bit_table: illegal size!\n" );
-            continue;
-        }
-    }
-}
-
-
-/*
- * load settings from disk or RTC RAM
- */
-void settings_load(int which)
-{
-    int i;
-    DEBUGF( "reload_all_settings()\n" );
-
-    /* load the buffer from the RTC (resets it to all-unused if the block
-       is invalid) and decode the settings which are set in the block */
-    if (!load_config_buffer(which))
-    {
-        /* load scalar values from RTC and HD sector, specified via table */
-        if (which & SETTINGS_RTC)
-        {
-            load_bit_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), 4*8);
-        }
-        if (which & SETTINGS_HD)
-        {
-            load_bit_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]),
-                RTC_BLOCK_SIZE*8);
-        }
-
-#ifdef HAVE_RECORDING
-    global_settings.recscreen_on = false;
-#endif
-
-#ifdef HAVE_LCD_CONTRAST
-        if ( global_settings.contrast < MIN_CONTRAST_SETTING ||
-             global_settings.contrast > MAX_CONTRAST_SETTING )
-            global_settings.contrast = lcd_default_contrast();
-#endif
-
-#ifdef HAVE_LCD_REMOTE
-        if (global_settings.remote_contrast < MIN_REMOTE_CONTRAST_SETTING ||
-            global_settings.remote_contrast > MAX_REMOTE_CONTRAST_SETTING )
-            global_settings.remote_contrast = lcd_remote_default_contrast();
-#endif
-        i = 0xb8;
-        strncpy((char *)global_settings.wps_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-        strncpy((char *)global_settings.lang_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-        strncpy((char *)global_settings.font_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#ifdef HAVE_REMOTE_LCD
-        strncpy((char *)global_settings.rwps_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#endif
-
-#ifdef CONFIG_TUNER
-        strncpy((char *)global_settings.fmr_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#endif
-
-#if LCD_DEPTH > 1
-        strncpy((char *)global_settings.backdrop_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#endif
-#ifdef HAVE_LCD_BITMAP
-        strncpy((char *)global_settings.kbd_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#endif
-    }
-}
-
-void set_file(char* filename, char* setting, int maxlen)
-{
-    char* fptr = strrchr(filename,'/');
-    int len;
-    int extlen = 0;
-    char* ptr;
-
-    if (!fptr)
-        return;
-
-    *fptr = 0;
-    fptr++;
-
-    len = strlen(fptr);
-    ptr = fptr + len;
-    while ((*ptr != '.') && (ptr != fptr)) {
-        extlen++;
-        ptr--;
-    }
-    if(ptr == fptr) extlen = 0;
-
-    if (strncasecmp(ROCKBOX_DIR, filename ,strlen(ROCKBOX_DIR)) ||
-        (len-extlen > maxlen))
-        return;
-
-    strncpy(setting, fptr, len-extlen);
-    setting[len-extlen]=0;
-
-    settings_save();
-}
-
-/* helper to sort a .cfg file entry into a global_settings member,
-   as described per table. Returns the position if found, else 0. */
-static int load_cfg_table(
-    const struct bit_entry* p_table, /* the table which describes the entries */
-    int count, /* number of entries in the table, including the first */
-    const char* name, /* the item to be searched */
-    const char* value, /* the value which got loaded for that item */
-    int hint) /* position to start looking */
-{
-    int i = hint;
-
-    do
-    {
-        if (p_table[i].cfg_name != NULL && !strcasecmp(name, p_table[i].cfg_name))
-        { /* found */
-            int val = 0;
-            if (p_table[i].cfg_val == NULL)
-            {   /* numerical value, just convert the string */
-                val = atoi(value);
-            }
-#if HAVE_LCD_COLOR
-            else if (!strncasecmp(p_table[i].cfg_val,"rgb",4))
-            {
-                val = hex_to_rgb(value);
-            }
-#endif
-            else
-            {   /* set of string values, find the index */
-                const char* item;
-                const char* run;
-                int len = strlen(value);
-
-                item = run = p_table[i].cfg_val;
-
-                while(1)
-                {
-                    /* count the length of the field */
-                    while (*run != ',' && *run != '\0')
-                        run++;
-
-                    if (!strncasecmp(value, item, MAX(run-item, len)))
-                        break; /* match, exit the search */
-
-                    if (*run == '\0') /* reached the end of the choices */
-                        return i; /* return the position, but don't update */
-
-                    val++; /* count the item up */
-                    run++; /* behind the ',' */
-                    item = run;
-                }
-            }
-
-            /* could do a memcpy, but that would be endian-dependent */
-            switch(p_table[i].byte_size)
-            {
-            case 1:
-                ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
-                    (unsigned char)val;
-                break;
-            case 2:
-                ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
-                    (unsigned short)val;
-                break;
-            case 4:
-                ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
-                    (unsigned int)val;
-                break;
-            default:
-                DEBUGF( "illegal size!" );
-                continue;
-            }
-
-            return i; /* return the position */
-        }
-
-        i++;
-        if (i==count)
-            i=1; /* wraparound */
-    } while (i != hint); /* back where we started, all searched */
-
-    return 0; /* indicate not found */
-}
-
-
-bool settings_load_config(const char* file)
-{
-    int fd;
-    char line[128];
-
-    fd = open(file, O_RDONLY);
-    if (fd < 0)
-        return false;
-
-    while (read_line(fd, line, sizeof line) > 0)
-    {
-        char* name;
-        char* value;
-        const struct bit_entry* table[2] = { rtc_bits, hd_bits };
-        const int ta_size[2] = {
-            sizeof(rtc_bits)/sizeof(rtc_bits[0]),
-            sizeof(hd_bits)/sizeof(hd_bits[0])
-        };
-        int last_table = 0; /* which table was used last round */
-        int last_pos = 1; /* at which position did we succeed */
-        int pos; /* currently returned position */
-
-        if (!settings_parseline(line, &name, &value))
-            continue;
-
-        /* check for the string values */
-        if (!strcasecmp(name, "wps")) {
-#if LCD_DEPTH > 1
-            unload_wps_backdrop();
-#endif
-            int fd2;
-            if ((fd2 = open(value, O_RDONLY)) >= 0) {
-                close(fd2);
-                set_file(value, (char *)global_settings.wps_file, MAX_FILENAME);
-            }
-        }
-#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
-        else if (!strcasecmp(name, "rwps")) {
-            int fd2;
-            if ((fd2 = open(value, O_RDONLY)) >= 0) {
-                close(fd2);
-                set_file(value, (char *)global_settings.rwps_file, MAX_FILENAME);
-            }
-        }
-#endif
-        else if (!strcasecmp(name, "lang")) {
-            if (!lang_load(value))
-            {
-                set_file(value, (char *)global_settings.lang_file, MAX_FILENAME);
-                talk_init(); /* use voice of same language */
-            }
-        }
-#ifdef CONFIG_TUNER
-        else if (!strcasecmp(name, "fmr")) {
-            set_file(value, global_settings.fmr_file, MAX_FILENAME);
-        }
-#endif
-#ifdef HAVE_LCD_BITMAP
-        else if (!strcasecmp(name, "font")) {
-            if (font_load(value))
-                set_file(value, (char *)global_settings.font_file, MAX_FILENAME);
-        }
-#endif
-#if LCD_DEPTH > 1
-        else if (!strcasecmp(name, "backdrop")) {
-            if (load_main_backdrop(value)) {
-                set_file(value, (char *)global_settings.backdrop_file, MAX_FILENAME);
-                show_main_backdrop();
-            }
-        }
-#endif
-#ifdef HAVE_LCD_BITMAP
-        else if (!strcasecmp(name, "keyboard")) {
-            if (!load_kbd(value))
-                set_file(value, (char *)global_settings.kbd_file, MAX_FILENAME);
-        }
-#endif
-
-
-        /* check for scalar values, using the two tables */
-        pos = load_cfg_table(table[last_table], ta_size[last_table],
-            name, value, last_pos);
-        if (pos) /* success */
-        {
-            last_pos = pos; /* remember as a position hint for next round */
-            continue;
-        }
-
-        last_table = 1-last_table; /* try other table */
-        last_pos = 1; /* search from start */
-        pos = load_cfg_table(table[last_table], ta_size[last_table],
-            name, value, last_pos);
-        if (pos) /* success */
-        {
-            last_pos = pos; /* remember as a position hint for next round */
-            continue;
-        }
-    }
-
-    close(fd);
-    settings_apply();
-    settings_save();
-    return true;
-}
-
-
-/* helper to save content of global_settings into a file,
-   as described per table */
-static void save_cfg_table(const struct bit_entry* p_table, int count, int fd)
-{
-    long value; /* 32 bit content */
-    int i;
-    const struct bit_entry* p_run = p_table; /* start after the size info */
-    count--; /* first is excluded from loop */
-
-    for (i=0; i<count; i++)
-    {
-        p_run++;
-
-        if (p_run->cfg_name == NULL)
-            continue; /* this value is not to be saved */
-
-        /* could do a memcpy, but that would be endian-dependent */
-        switch(p_run->byte_size)
-        {
-        case 1:
-            if (p_run->bit_size & SIGNED) /* signed? */
-                value = ((char*)&global_settings)[p_run->settings_offset];
-            else
-                value = ((unsigned char*)&global_settings)[p_run->settings_offset];
-            break;
-        case 2:
-            if (p_run->bit_size & SIGNED) /* signed? */
-                value = ((short*)&global_settings)[p_run->settings_offset/2];
-            else
-                value = ((unsigned short*)&global_settings)[p_run->settings_offset/2];
-            break;
-        case 4:
-            value = ((unsigned int*)&global_settings)[p_run->settings_offset/4];
-            break;
-        default:
-            DEBUGF( "illegal size!" );
-            continue;
-        }
-
-        if (p_run->cfg_val == NULL) /* write as number */
-        {
-            fdprintf(fd, "%s: %ld\r\n", p_run->cfg_name, value);
-        }
-#ifdef HAVE_LCD_COLOR
-        else if (!strcasecmp(p_run->cfg_val, "rgb"))
-        {
-            fdprintf(fd, "%s: %02x%02x%02x\r\n", p_run->cfg_name,
-                                                 (int)RGB_UNPACK_RED(value),
-                                                 (int)RGB_UNPACK_GREEN(value),
-                                                 (int)RGB_UNPACK_BLUE(value));
-        }
-#endif
-        else /* write as item */
-        {
-            const char* p = p_run->cfg_val;
-
-            fdprintf(fd, "%s: ", p_run->cfg_name);
-
-            while(value >= 0)
-            {
-                char c = *p++; /* currently processed char */
-                if (c == ',') /* separator */
-                    value--;
-                else if (c == '\0') /* end of string */
-                    break; /* not found */
-                else if (value == 0) /* the right place */
-                    write(fd, &c, 1); /* char by char, this is lame, OK */
-            }
-
-            fdprintf(fd, "\r\n");
-            if (p_run->cfg_val != off_on) /* explaination for non-bool */
-                fdprintf(fd, "# (possible values: %s)\r\n", p_run->cfg_val);
-        }
-    }
-}
-
-bool settings_save_config(void)
-{
-    int fd;
-    char filename[MAX_PATH];
-
-    create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2
-                             IF_CNFN_NUM_(, NULL));
-
-    /* allow user to modify filename */
-    while (true) {
-        if (!kbd_input(filename, sizeof filename)) {
-            fd = creat(filename, O_WRONLY);
-            if (fd < 0)
-                gui_syncsplash(HZ, true, str(LANG_FAILED));
-            else
-                break;
-        }
-        else {
-            gui_syncsplash(HZ, true, str(LANG_MENU_SETTING_CANCEL));
-            return false;
-        }
-    }
-
-    fdprintf(fd, "# .cfg file created by rockbox %s - "
-                 "http://www.rockbox.org\r\n#\r\n#\r\n# wps / rwps / language"
-                 " / font / fmpreset / backdrop \r\n#\r\n", appsversion);
-
-    if (global_settings.wps_file[0] != 0)
-        fdprintf(fd, "wps: %s/%s.wps\r\n", WPS_DIR,
-                 global_settings.wps_file);
-
-#ifdef HAVE_REMOTE_LCD
-    if (global_settings.rwps_file[0] != 0)
-        fdprintf(fd, "rwps: %s/%s.rwps\r\n", WPS_DIR,
-                 global_settings.rwps_file);
-#endif
-
-    if (global_settings.lang_file[0] != 0)
-        fdprintf(fd, "lang: %s/%s.lng\r\n", LANG_DIR,
-                 global_settings.lang_file);
-
-#ifdef HAVE_LCD_BITMAP
-    if (global_settings.font_file[0] != 0)
-        fdprintf(fd, "font: %s/%s.fnt\r\n", FONT_DIR,
-                 global_settings.font_file);
-#endif
-
-#if LCD_DEPTH > 1
-    if (global_settings.backdrop_file[0] != 0)
-        fdprintf(fd, "backdrop: %s/%s.bmp\r\n", BACKDROP_DIR,
-                 global_settings.backdrop_file);
-#endif
-
-#ifdef CONFIG_TUNER
-    if (global_settings.fmr_file[0] != 0)
-        fdprintf(fd, "fmr: %s/%s.fmr\r\n", FMPRESET_PATH,
-                 global_settings.fmr_file);
-#endif
-
-#ifdef HAVE_LCD_BITMAP
-    if (global_settings.kbd_file[0] != 0)
-        fdprintf(fd, "keyboard: %s/%s.kbd\r\n", ROCKBOX_DIR,
-                 global_settings.kbd_file);
-#endif
-
-    /* here's the action: write values to file, specified via table */
-    save_cfg_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), fd);
-    save_cfg_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), fd);
-
-    close(fd);
-
-    gui_syncsplash(HZ, true, str(LANG_SETTINGS_SAVED));
-    return true;
-}
-
-
-/* helper to load defaults from table into global_settings members */
-static void default_table(const struct bit_entry* p_table, int count)
-{
-    int i;
-
-    for (i=1; i<count; i++) /* exclude the first, the size placeholder */
-    {
-        /* could do a memcpy, but that would be endian-dependent */
-        switch(p_table[i].byte_size)
-        {
-        case 1:
-            ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
-                (unsigned char)p_table[i].default_val;
-            break;
-        case 2:
-            ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
-                (unsigned short)p_table[i].default_val;
-            break;
-        case 4:
-            ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
-                (unsigned int)p_table[i].default_val;
-            break;
-        default:
-            DEBUGF( "illegal size!" );
-            continue;
-        }
-    }
-}
-
-
-/*
- * reset all settings to their default value
- */
-void settings_reset(void) {
-
-    DEBUGF( "settings_reset()\n" );
-
-    /* read defaults from table(s) into global_settings */
-    default_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]));
-    default_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]));
-
-    /* do some special cases not covered by table */
-    global_settings.volume      = sound_default(SOUND_VOLUME);
-    global_settings.balance     = sound_default(SOUND_BALANCE);
-    global_settings.bass        = sound_default(SOUND_BASS);
-    global_settings.treble      = sound_default(SOUND_TREBLE);
-    global_settings.channel_config = sound_default(SOUND_CHANNELS);
-    global_settings.stereo_width = sound_default(SOUND_STEREO_WIDTH);
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    global_settings.loudness    = sound_default(SOUND_LOUDNESS);
-    global_settings.avc         = sound_default(SOUND_AVC);
-    global_settings.mdb_strength = sound_default(SOUND_MDB_STRENGTH);
-    global_settings.mdb_harmonics = sound_default(SOUND_MDB_HARMONICS);
-    global_settings.mdb_center = sound_default(SOUND_MDB_CENTER);
-    global_settings.mdb_shape = sound_default(SOUND_MDB_SHAPE);
-    global_settings.mdb_enable = sound_default(SOUND_MDB_ENABLE);
-    global_settings.superbass = sound_default(SOUND_SUPERBASS);
-#endif
-#ifdef HAVE_LCD_CONTRAST 
-    global_settings.contrast = lcd_default_contrast();
-#endif
-#ifdef HAVE_LCD_REMOTE
-    global_settings.remote_contrast = lcd_remote_default_contrast();
-#endif
-
-#ifdef CONFIG_TUNER
-    global_settings.fmr_file[0] = '\0';
-#endif
-    global_settings.wps_file[0] = '\0';
-#ifdef HAVE_REMOTE_LCD
-    global_settings.rwps_file[0] = '\0';
-#endif
-    global_settings.font_file[0] = '\0';
-    global_settings.lang_file[0] = '\0';
-#if LCD_DEPTH > 1
-    global_settings.backdrop_file[0] = '\0';
-#endif
-#ifdef HAVE_LCD_COLOR
-    global_settings.fg_color = LCD_DEFAULT_FG;
-    global_settings.bg_color = LCD_DEFAULT_BG;
-#endif
-#ifdef HAVE_LCD_BITMAP
-    global_settings.kbd_file[0] = '\0';
-#endif
-    global_settings.hold_lr_for_scroll_in_list = true;
-
-#if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
-    enc_global_settings_reset();
-#endif
-}
-
-bool set_bool(const char* string, bool* variable )
-{
-    return set_bool_options(string, variable,
-                            (char *)STR(LANG_SET_BOOL_YES),
-                            (char *)STR(LANG_SET_BOOL_NO),
-                            NULL);
-}
-
-/* wrapper to convert from int param to bool param in set_option */
-static void (*boolfunction)(bool);
-void bool_funcwrapper(int value)
-{
-    if (value)
-        boolfunction(true);
-    else
-        boolfunction(false);
-}
-
-bool set_bool_options(const char* string, bool* variable,
-                      const char* yes_str, int yes_voice,
-                      const char* no_str, int no_voice,
-                      void (*function)(bool))
-{
-    struct opt_items names[] = {
-        {(unsigned char *)no_str, no_voice},
-        {(unsigned char *)yes_str, yes_voice}
-    };
-    bool result;
-
-    boolfunction = function;
-    result = set_option(string, variable, BOOL, names, 2,
-                        function ? bool_funcwrapper : NULL);
-    return result;
-}
-
-void talk_unit(int unit, int value)
-{
-    if (global_settings.talk_menu)
-    {
-        if (unit < UNIT_LAST)
-        {   /* use the available unit definition */
-            talk_value(value, unit, false);
-        }
-        else
-        {   /* say the number, followed by an arbitrary voice ID */
-            talk_number(value, false);
-            talk_id(unit, true);
-        }
-    }
-}
-
-struct value_setting_data {
-    enum optiontype type;
-    /* used for "value" settings.. */
-    int max;
-    int step;
-    int voice_unit;
-    const char * unit;
-    void (*formatter)(char* dest, int dest_length,
-                          int variable, const char* unit);
-    /* used for BOOL and "choice" settings */
-    struct opt_items* options;    
-};
-    
-char * value_setting_get_name_cb(int selected_item,void * data, char *buffer)
-{
-    struct value_setting_data* cb_data = 
-            (struct value_setting_data*)data;
-    if (cb_data->type == INT && !cb_data->options)
-    {
-        int item = cb_data->max -(selected_item*cb_data->step);
-        if (cb_data->formatter)
-            cb_data->formatter(buffer, MAX_PATH,item,cb_data->unit);
-        else
-            snprintf(buffer, MAX_PATH,"%d %s",item,cb_data->unit);
-    }
-    else strcpy(buffer,P2STR(cb_data->options[selected_item].string));
-    return buffer;
-} 
-#define type_fromvoidptr(type, value) \
-    (type == INT)? \
-        (int)(*(int*)(value)) \
-    : \
-        (bool)(*(bool*)(value))
-bool do_set_setting(const unsigned char* string, void *variable,
-                    int nb_items,int selected, 
-                    struct value_setting_data *cb_data,
-                    void (*function)(int))
-{
-    int action;
-    bool done = false;
-    struct gui_synclist lists;
-    int oldvalue;
-    bool allow_wrap = true;
-    
-    if (cb_data->type == INT)
-    {
-         oldvalue = *(int*)variable;
-         if (variable == &global_settings.volume)
-             allow_wrap = false;
-    }
-    else oldvalue = *(bool*)variable;
-    
-    gui_synclist_init(&lists,value_setting_get_name_cb,(void*)cb_data,false,1);
-    gui_synclist_set_title(&lists, (char*)string, NOICON);
-    gui_synclist_set_icon_callback(&lists,NULL);
-    gui_synclist_set_nb_items(&lists,nb_items);
-    gui_synclist_limit_scroll(&lists,true);
-    gui_synclist_select_item(&lists, selected);
-    
-    if (global_settings.talk_menu)
-    {
-        if (cb_data->type == INT && !cb_data->options)
-            talk_unit(cb_data->voice_unit, *(int*)variable);
-        else talk_id(cb_data->options[selected].voice_id, false);
-    }
-    
-    gui_synclist_draw(&lists);
-    while (!done)
-    {
-        
-        action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK); 
-        if (action == ACTION_NONE)
-            continue;
-        if (gui_synclist_do_button(&lists,action,
-                                   allow_wrap?LIST_WRAP_UNLESS_HELD:LIST_WRAP_OFF))
-        {
-            if (global_settings.talk_menu)
-            {
-                int value;
-                if (cb_data->type == INT && !cb_data->options)
-                {
-                    value = cb_data->max - 
-                            gui_synclist_get_sel_pos(&lists)*cb_data->step;
-                    talk_unit(cb_data->voice_unit, value);
-                }
-                else 
-                {
-                    value = gui_synclist_get_sel_pos(&lists);
-                    talk_id(cb_data->options[value].voice_id, false);
-                }
-            }
-            if (cb_data->type == INT && !cb_data->options)
-                *(int*)variable = cb_data->max - 
-                        gui_synclist_get_sel_pos(&lists)*cb_data->step;
-            else if (cb_data->type == BOOL)
-                *(bool*)variable = gui_synclist_get_sel_pos(&lists) ? true : false;
-            else *(int*)variable = gui_synclist_get_sel_pos(&lists);
-        }  
-        else if (action == ACTION_STD_CANCEL)
-        {
-            gui_syncsplash(HZ/2,true,str(LANG_MENU_SETTING_CANCEL));
-            if (cb_data->type == INT)
-                *(int*)variable = oldvalue;
-            else *(bool*)variable = (bool)oldvalue;
-            done = true;
-        }
-        else if (action == ACTION_STD_OK)
-        {
-            done = true;
-        }
-        else if(default_event_handler(action) == SYS_USB_CONNECTED)
-            return true;
-        gui_syncstatusbar_draw(&statusbars, false);
-        if ( function )
-            function(type_fromvoidptr(cb_data->type,variable));
-    }
-    return false;
-}
-bool set_int(const unsigned char* string,
-             const char* unit,
-             int voice_unit,
-             int* variable,
-             void (*function)(int),
-             int step,
-             int min,
-             int max,
-             void (*formatter)(char*, int, int, const char*) )
-{
-#if CONFIG_KEYPAD != PLAYER_PAD
-    struct value_setting_data data = {
-        INT,max, step, voice_unit,unit,formatter,NULL };
-    return do_set_setting(string,variable,(max-min)/step + 1,
-                          (max-*variable)/step, &data,function);
-#else
-    int count = (max-min)/step + 1;
-    struct value_setting_data data = {
-        INT,min, -step, voice_unit,unit,formatter,NULL };
-    return do_set_setting(string,variable,count,
-                          count - ((max-*variable)/step), &data,function);
-#endif
-}
-
-/* NOTE: the 'type' parameter specifies the actual type of the variable
-   that 'variable' points to. not the value within. Only variables with
-   type 'bool' should use parameter BOOL.
-
-   The type separation is necessary since int and bool are fundamentally
-   different and bit-incompatible types and can not share the same access
-   code. */ 
-bool set_option(const char* string, void* variable, enum optiontype type,
-                const struct opt_items* options, int numoptions, void (*function)(int))
-{
-    struct value_setting_data data = {
-        type,0, 0, 0,NULL,NULL,(struct opt_items*)options };
-    int selected;
-    if (type == BOOL)
-        selected = *(bool*)variable ? 1 : 0;
-    else selected = *(int*)variable;
-    return do_set_setting(string,variable,numoptions,
-                          selected, &data,function);
-}
-
-#ifdef HAVE_RECORDING
-/* This array holds the record timer interval lengths, in seconds */
-static const unsigned long rec_timer_seconds[] =
-{
-    0,        /* 0 means OFF */
-    5*60,     /* 00:05 */
-    10*60,    /* 00:10 */
-    15*60,    /* 00:15 */
-    30*60,    /* 00:30 */
-    60*60,    /* 01:00 */
-    74*60,    /* 74:00 */
-    80*60,    /* 80:00 */
-    2*60*60,  /* 02:00 */
-    4*60*60,  /* 04:00 */
-    6*60*60,  /* 06:00 */
-    8*60*60,  /* 08:00 */
-    10L*60*60, /* 10:00 */
-    12L*60*60, /* 12:00 */
-    18L*60*60, /* 18:00 */
-    24L*60*60  /* 24:00 */
-};
-
-unsigned int rec_timesplit_seconds(void)
-{
-    return rec_timer_seconds[global_settings.rec_timesplit];
-}
-
-/* This array holds the record size interval lengths, in bytes */
-static const unsigned long rec_size_bytes[] =
-{
-    0,               /* 0 means OFF */
-    5*1024*1024,     /* 5MB */
-    10*1024*1024,    /* 10MB */
-    15*1024*1024,    /* 15MB */
-    32*1024*1024,    /* 32MB */
-    64*1024*1024,    /* 64MB */
-    75*1024*1024,    /* 75MB */
-    100*1024*1024,   /* 100MB */
-    128*1024*1024,   /* 128MB */
-    256*1024*1024,   /* 256MB */
-    512*1024*1024,   /* 512MB */
-    650*1024*1024,   /* 650MB */
-    700*1024*1024,   /* 700MB */
-    1024*1024*1024,  /* 1GB */
-    1536*1024*1024,  /* 1.5GB */
-    1792*1024*1024,  /* 1.75GB  */
-};
-
-unsigned long rec_sizesplit_bytes(void)
-{
-    return rec_size_bytes[global_settings.rec_sizesplit];
-}
-/*
- * Time strings used for the trigger durations.
- * Keep synchronous to trigger_times in settings_apply_trigger
- */
-const char * const trig_durations[TRIG_DURATION_COUNT] =
-{
-    "0s", "1s", "2s", "5s",
-    "10s", "15s", "20s", "25s", "30s",
-    "1min", "2min", "5min", "10min"
-};
-
-void settings_apply_trigger(void)
-{
-    /* Keep synchronous to trig_durations and trig_durations_conf*/
-    static const long trigger_times[TRIG_DURATION_COUNT] = {
-        0, HZ, 2*HZ, 5*HZ,
-        10*HZ, 15*HZ, 20*HZ, 25*HZ, 30*HZ,
-        60*HZ, 2*60*HZ, 5*60*HZ, 10*60*HZ
-    };
-
-    peak_meter_define_trigger(
-        global_settings.rec_start_thres,
-        trigger_times[global_settings.rec_start_duration],
-        MIN(trigger_times[global_settings.rec_start_duration] / 2, 2*HZ),
-        global_settings.rec_stop_thres,
-        trigger_times[global_settings.rec_stop_postrec],
-        trigger_times[global_settings.rec_stop_gap]
-    );
-}
-#endif
Index: apps/settings.h
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.h,v
retrieving revision 1.255
diff -u -r1.255 settings.h
--- apps/settings.h	24 Nov 2006 19:49:02 -0000	1.255
+++ apps/settings.h	30 Nov 2006 07:21:28 -0000
@@ -28,6 +28,7 @@
 #include "timefuncs.h"
 #include "tagcache.h"
 #include "button.h"
+#include "settings_list.h"
 
 #if CONFIG_CODEC == SWCODEC
 #include "audio.h"
@@ -54,9 +55,11 @@
 #define REC_BASE_DIR "/recordings"
 #define EQS_DIR     ROCKBOX_DIR "/eqs"
 #define CODECS_DIR  ROCKBOX_DIR"/codecs"
+#define ROCKBOX_CONFIGFILE ROCKBOX_DIR "/config.cfg"
 
 #define MAX_FILENAME 20
 
+
 /* data structures */
 
 #define BOOKMARK_NO  0
@@ -154,22 +157,23 @@
 
 #if CONFIG_CODEC == SWCODEC
     int rec_format;    /* record format index */
+    int rec_sampr;     /* recording sample rate */
 #else
     int rec_quality;   /* 0-7 */
-#endif  /* CONFIG_CODEC == SWCODEC */
-    int rec_source;    /* 0=mic, 1=line, 2=S/PDIF, 2 or 3=FM Radio */
     int rec_frequency; /* 0 = 44.1kHz (depends on target)
                           1 = 48kHz
                           2 = 32kHz
                           3 = 22.05kHz
                           4 = 24kHz
                           5 = 16kHz */
+    bool rec_editable; /* true means that the bit reservoir is off */
+#endif  /* CONFIG_CODEC == SWCODEC */
+
+    int rec_source;    /* 0=mic, 1=line, 2=S/PDIF, 2 or 3=FM Radio */
     int rec_channels;  /* 0=Stereo, 1=Mono */
     int rec_mic_gain;   /* depends on target */
     int rec_left_gain;  /* depends on target */
     int rec_right_gain; /* depands on target */
-    bool rec_editable; /* true means that the bit reservoir is off */
-    bool recscreen_on; /* true if using the recording screen */
 
     /* note: timesplit setting is not saved */
     int rec_timesplit; /* 0 = off,
@@ -346,7 +350,7 @@
 
     bool   line_in;       /* false=off, true=active */
 
-    bool id3_v1_first;    /* true = ID3V1 has prio over ID3V2 tag */
+    int id3_v1_first;    /* 0 = ID3V1 has prio over ID3V2 tag */
 
     /* playlist viewer settings */
     bool playlist_viewer_icons; /* display icons on viewer */
@@ -550,12 +554,12 @@
 void settings_load(int which);
 void settings_reset(void);
 void sound_settings_apply(void);
-void settings_apply(void);
+void settings_apply(bool partial);
 void settings_apply_pm_range(void);
 void settings_display(void);
 
 bool settings_load_config(const char* file);
-bool settings_save_config(void);
+bool settings_save_config(const char* filename,bool theme);
 bool set_bool_options(const char* string, bool* variable,
                       const char* yes_str, int yes_voice,
                       const char* no_str, int no_voice,
@@ -572,9 +576,9 @@
 int read_line(int fd, char* buffer, int buffer_size);
 void set_file(char* filename, char* setting, int maxlen);
 
-unsigned int rec_timesplit_seconds(void);
-unsigned long rec_sizesplit_bytes(void);
-void settings_apply_trigger(void);
+bool load_setting_screen(struct settings_list *setting);
+const struct settings_list *find_setting(void* variable);
+void talk_setting(void *global_settings_variable);
 
 /* global settings */
 extern struct user_settings global_settings;
Index: apps/sound_menu.h
===================================================================
RCS file: /cvsroot/rockbox/apps/sound_menu.h,v
retrieving revision 1.7
diff -u -r1.7 sound_menu.h
--- apps/sound_menu.h	26 Mar 2006 22:33:25 -0000	1.7
+++ apps/sound_menu.h	30 Nov 2006 07:21:29 -0000
@@ -22,8 +22,6 @@
 #include "menu.h"
 
 bool sound_menu(void);
-bool recording_menu(bool no_source);
-bool rectrigger(void);
 bool set_sound(const unsigned char * string, int* variable, int setting);
 
 #endif
Index: apps/tagcache.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tagcache.c,v
retrieving revision 1.78
diff -u -r1.78 tagcache.c
--- apps/tagcache.c	19 Nov 2006 19:11:30 -0000	1.78
+++ apps/tagcache.c	30 Nov 2006 07:21:39 -0000
@@ -3808,23 +3808,23 @@
     queue_post(&tagcache_queue, Q_START_SCAN, 0);
 }
 
-bool tagcache_update(void)
+int tagcache_update(void)
 {
     if (!tc_stat.ready)
-        return false;
+        return 0;
     
     queue_post(&tagcache_queue, Q_UPDATE, 0);
     gui_syncsplash(HZ*2, true, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH));
     
-    return false;
+    return 0;
 }
 
-bool tagcache_rebuild(void)
+int tagcache_rebuild(void)
 {
     queue_post(&tagcache_queue, Q_REBUILD, 0);
     gui_syncsplash(HZ*2, true, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH));
     
-    return false;
+    return 0;
 }
 
 void tagcache_stop_scan(void)
Index: apps/tagcache.h
===================================================================
RCS file: /cvsroot/rockbox/apps/tagcache.h,v
retrieving revision 1.32
diff -u -r1.32 tagcache.h
--- apps/tagcache.h	25 Nov 2006 09:42:05 -0000	1.32
+++ apps/tagcache.h	30 Nov 2006 07:21:40 -0000
@@ -183,8 +183,8 @@
 bool tagcache_is_initialized(void);
 void tagcache_start_scan(void);
 void tagcache_stop_scan(void);
-bool tagcache_update(void);
-bool tagcache_rebuild(void);
+int tagcache_update(void);
+int tagcache_rebuild(void);
 
 #endif
 #endif
Index: apps/tagtree.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tagtree.c,v
retrieving revision 1.56
diff -u -r1.56 tagtree.c
--- apps/tagtree.c	11 Nov 2006 17:39:37 -0000	1.56
+++ apps/tagtree.c	30 Nov 2006 07:21:46 -0000
@@ -666,7 +666,7 @@
     tagcache_search_finish(&tcs);
 }
 
-bool tagtree_export(void)
+int tagtree_export(void)
 {
     gui_syncsplash(0, true, str(LANG_CREATING));
     if (!tagcache_create_changelog(&tcs))
@@ -674,10 +674,10 @@
         gui_syncsplash(HZ*2, true, str(LANG_FAILED));
     }
     
-    return false;
+    return 0;
 }
 
-bool tagtree_import(void)
+int tagtree_import(void)
 {
     gui_syncsplash(0, true, str(LANG_WAIT));
     if (!tagcache_import_changelog())
@@ -685,7 +685,7 @@
         gui_syncsplash(HZ*2, true, str(LANG_FAILED));
     }
     
-    return false;
+    return 0;
 }
 
 static bool parse_menu(const char *filename);
Index: apps/tagtree.h
===================================================================
RCS file: /cvsroot/rockbox/apps/tagtree.h,v
retrieving revision 1.14
diff -u -r1.14 tagtree.h
--- apps/tagtree.h	25 Oct 2006 10:17:56 -0000	1.14
+++ apps/tagtree.h	30 Nov 2006 07:21:46 -0000
@@ -36,8 +36,8 @@
     int extraseek;
 };
 
-bool tagtree_export(void);
-bool tagtree_import(void);
+int tagtree_export(void);
+int tagtree_import(void);
 void tagtree_init(void);
 int tagtree_enter(struct tree_context* c);
 void tagtree_exit(struct tree_context* c);
Index: apps/tree.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tree.c,v
retrieving revision 1.456
diff -u -r1.456 tree.c
--- apps/tree.c	19 Nov 2006 14:11:40 -0000	1.456
+++ apps/tree.c	30 Nov 2006 07:21:53 -0000
@@ -31,7 +31,6 @@
 #include "kernel.h"
 #include "usb.h"
 #include "tree.h"
-#include "main_menu.h"
 #include "sprintf.h"
 #include "audio.h"
 #include "playlist.h"
@@ -215,7 +214,7 @@
     }
     else
 #endif
-		{
+        {
         struct entry* dc = local_tc->dircache;
         struct entry* e = &dc[selected_item];
         *icon = (ICON)filetype_get_icon(e->attr);
@@ -331,7 +330,7 @@
     }
     else 
 #endif
-		{
+        {
         /* if the tc.currdir has been changed, reload it ...*/
         if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir) {
 
@@ -356,9 +355,9 @@
     {
         if(
 #ifdef HAVE_TAGCACHE
-		!id3db && 
+        !id3db && 
 #endif
-		(tc.dirfull ||
+        (tc.dirfull ||
                       tc.filesindir == global_settings.max_files_in_dir) )
         {
             gui_syncsplash(HZ, true, str(LANG_SHOWDIR_BUFFER_FULL));
@@ -636,8 +635,8 @@
                won't initialize */
             sleep(HZ);
 #endif
-            recording_screen(false);
-            rec_menu();
+            recording_screen();
+            recording_menu();
             main_menu();
         }
         else
@@ -765,7 +764,10 @@
                     FOR_NB_SCREENS(i)
                         screens[i].stop_scroll();
                     action_signalscreenchange();
-                    if (main_menu())
+                    i = main_menu();
+                    if (i == MENU_RETURN_TO_WPS)
+                        start_wps=true;
+                    else if (i)
                         reload_dir = true;
                     restore = true;
 
Index: apps/gui/gwps.c
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/gwps.c,v
retrieving revision 1.55
diff -u -r1.55 gwps.c
--- apps/gui/gwps.c	26 Nov 2006 09:53:42 -0000	1.55
+++ apps/gui/gwps.c	30 Nov 2006 07:21:58 -0000
@@ -37,7 +37,7 @@
 #include "audio.h"
 #include "usb.h"
 #include "status.h"
-#include "main_menu.h"
+#include "menu.h"
 #include "ata.h"
 #include "screens.h"
 #include "playlist.h"
Index: apps/gui/statusbar.c
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/statusbar.c,v
retrieving revision 1.33
diff -u -r1.33 statusbar.c
--- apps/gui/statusbar.c	6 Nov 2006 18:07:26 -0000	1.33
+++ apps/gui/statusbar.c	30 Nov 2006 07:22:01 -0000
@@ -38,6 +38,7 @@
 #include "statusbar.h"
 #ifdef HAVE_RECORDING
 #include "audio.h"
+#include "recording.h"
 #endif
 
 /* FIXME: should be removed from icon.h to avoid redefinition,
@@ -135,6 +136,9 @@
 void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw)
 {
     struct screen * display = bar->display;
+#ifdef HAVE_RECORDING
+    bool recscreen_on;
+#endif
 
 #ifdef HAVE_LCD_CHARCELLS
     int val;
@@ -256,8 +260,9 @@
                                     STATUSBAR_HEIGHT);
 #endif
 #ifdef HAVE_RECORDING
+        recscreen_on = in_recording_screen();
         /* turn off volume display in recording screen */
-        if (!global_settings.recscreen_on)
+        if (!recscreen_on)
 #endif
             bar->redraw_volume = gui_statusbar_icon_volume(bar, bar->info.volume);
         gui_statusbar_icon_play_state(display, current_playmode() + Icon_Play);
@@ -265,7 +270,7 @@
 #ifdef HAVE_RECORDING
         /* If in recording screen, replace repeat mode, volume
            and shuffle icons with recording info */
-        if (global_settings.recscreen_on)
+        if (recscreen_on)
             gui_statusbar_icon_recording_info(display);
         else
 #endif
@@ -620,8 +625,6 @@
     {
         /* Special handling for mp3 */
         bitrk = global_settings.mp3_enc_config.bitrate;
-        bitrk = mp3_enc_bitr[bitrk];
-
         width = BM_MPA_L3_M_WIDTH;
 
         /* Slide 'M' to right if fewer than three digits used */
@@ -665,7 +668,7 @@
         samprk = pcm_rec_sample_rate();
     else
 #endif
-        samprk = rec_freq_sampr[global_settings.rec_frequency];
+        samprk = global_settings.rec_sampr;
 #endif /* SIMULATOR */
 
     samprk /= 1000;
Index: apps/keymaps/keymap-h1x0_h3x0.c
===================================================================
RCS file: /cvsroot/rockbox/apps/keymaps/keymap-h1x0_h3x0.c,v
retrieving revision 1.37
diff -u -r1.37 keymap-h1x0_h3x0.c
--- apps/keymaps/keymap-h1x0_h3x0.c	10 Nov 2006 16:46:33 -0000	1.37
+++ apps/keymaps/keymap-h1x0_h3x0.c	30 Nov 2006 07:22:08 -0000
@@ -65,6 +65,10 @@
     LAST_ITEM_IN_LIST
 }; /* button_context_standard */
 
+const struct button_mapping button_context_main_menu[]  = {
+    { ACTION_MENU_WPS,          BUTTON_ON,           BUTTON_NONE },
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
+};
 
 const struct button_mapping button_context_wps[]  = {
     { ACTION_WPS_PLAY,          BUTTON_ON|BUTTON_REL,           BUTTON_ON },
@@ -910,8 +914,9 @@
     switch (context)
     {
         case CONTEXT_STD:
-        case CONTEXT_MAINMENU:
             return button_context_standard;
+        case CONTEXT_MAINMENU:
+            return button_context_main_menu;
         case CONTEXT_WPS:
             return button_context_wps;
             
Index: apps/lang/english.lang
===================================================================
RCS file: /cvsroot/rockbox/apps/lang/english.lang,v
retrieving revision 1.302
diff -u -r1.302 english.lang
--- apps/lang/english.lang	25 Nov 2006 20:11:56 -0000	1.302
+++ apps/lang/english.lang	30 Nov 2006 07:22:24 -0000
@@ -10358,3 +10358,73 @@
     *: "AGC maximum gain"
   </voice>
 </phrase>
+<phrase>
+  id: LANG_HOLD_DIRECTION_FOR_SCROLL
+  desc: hold direction arrows to scroll filename
+  user:
+  <source>
+    *: "Hold left/right to scroll filename"
+  </source>
+  <dest>
+    *: "Hold left/right to scroll filename"
+  </dest>
+  <voice>
+    *: ""
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_ONCE
+  desc: once
+  user:
+  <source>
+    *: "Once"
+  </source>
+  <dest>
+    *: "Once"
+  </dest>
+  <voice>
+    *: "Once"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_MAIN_MENU
+  desc: main menu text
+  user:
+  <source>
+    *: "Main Menu"
+  </source>
+  <dest>
+    *: "Main Menu"
+  </dest>
+  <voice>
+    *: "Main Menu"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_USER_MENU
+  desc: user menu text
+  user:
+  <source>
+    *: "User Menu"
+  </source>
+  <dest>
+    *: "User Menu"
+  </dest>
+  <voice>
+    *: "User Menu"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_WRITE_THEME
+  desc: write theme to disk
+  user:
+  <source>
+    *: "Write Theme"
+  </source>
+  <dest>
+    *: "Write Theme"
+  </dest>
+  <voice>
+    *: "Write Theme"
+  </voice>
+</phrase>
Index: apps/player/icons.h
===================================================================
RCS file: /cvsroot/rockbox/apps/player/icons.h,v
retrieving revision 1.9
diff -u -r1.9 icons.h
--- apps/player/icons.h	16 Nov 2005 02:12:25 -0000	1.9
+++ apps/player/icons.h	30 Nov 2006 07:22:24 -0000
@@ -31,7 +31,8 @@
     Icon_Queued = 'Q',
     Icon_Moving = 'M',
     Icon_Unknown = 0x90,
-    Icon_Bookmark = 0x16,
+    Icon_Checkmark = 0x15,
+    Icon_Bookmark,
     Icon_Plugin,
     Icon_Folder,
     Icon_Firmware,
@@ -40,7 +41,7 @@
     Icon_Wps,
     Icon_Playlist,
     Icon_Text,
-    Icon_Config,
+    Icon_Config
 };
 
 #endif
Index: apps/recorder/icons.c
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/icons.c,v
retrieving revision 1.88
diff -u -r1.88 icons.c
--- apps/recorder/icons.c	24 Nov 2006 19:49:04 -0000	1.88
+++ apps/recorder/icons.c	30 Nov 2006 07:22:28 -0000
@@ -62,6 +62,7 @@
     { 0x3e, 0x41, 0x3e, 0x1c, 0x1c, 0x08 }, /* Moving Item */
     { 0x7f, 0x7f, 0x1c, 0x3e, 0x77, 0x63 }, /* Keyboard file */
     { 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e }, /* Reverse Cursor / Marker */
+    { 0x38, 0x70, 0x38, 0x1c, 0x0e, 0x07 }, /* Checkmark */
 };
 
 const unsigned char bitmap_icons_7x8[][7] =
Index: apps/recorder/icons.h
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/icons.h,v
retrieving revision 1.68
diff -u -r1.68 icons.h
--- apps/recorder/icons.h	24 Nov 2006 19:49:04 -0000	1.68
+++ apps/recorder/icons.h	30 Nov 2006 07:22:29 -0000
@@ -64,6 +64,7 @@
     Icon_Moving,
     Icon_Keyboard,
     Icon_Reverse_Cursor,
+    Icon_Checkmark,
     Icon6x8Last,
 };
 
Index: apps/recorder/radio.c
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/radio.c,v
retrieving revision 1.114
diff -u -r1.114 radio.c
--- apps/recorder/radio.c	6 Nov 2006 18:07:27 -0000	1.114
+++ apps/recorder/radio.c	30 Nov 2006 07:22:33 -0000
@@ -43,7 +43,6 @@
 #include "peakmeter.h"
 #include "lang.h"
 #include "font.h"
-#include "sound_menu.h"
 #include "recording.h"
 #include "talk.h"
 #include "tuner.h"
@@ -1515,7 +1514,7 @@
     /* clearing queue seems to cure a spontaneous abort during record */
     while (button_get(false) != BUTTON_NONE);
 
-    ret = recording_screen(true);
+    ret = recording_screen();
 
     /* safe to reset as changing sources is prohibited here */
     global_settings.rec_source = rec_source;
@@ -1528,7 +1527,7 @@
 #define FM_RECORDING_SETTINGS
 static bool fm_recording_settings(void)
 {
-    bool ret = recording_menu(true);
+    bool ret = recording_menu();
 
 #if CONFIG_CODEC != SWCODEC
     if (!ret)
Index: apps/recorder/recording.c
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/recording.c,v
retrieving revision 1.149
diff -u -r1.149 recording.c
--- apps/recorder/recording.c	25 Nov 2006 20:11:59 -0000	1.149
+++ apps/recorder/recording.c	30 Nov 2006 07:22:39 -0000
@@ -52,7 +52,6 @@
 #include "peakmeter.h"
 #include "statusbar.h"
 #include "menu.h"
-#include "sound_menu.h"
 #include "timefuncs.h"
 #include "debug.h"
 #include "misc.h"
@@ -70,6 +69,11 @@
 #include "radio.h"
 #ifdef HAVE_RECORDING
 
+/* these are at the bottom of the file */
+unsigned int rec_timesplit_seconds(void);
+unsigned long rec_sizesplit_bytes(void);
+void settings_apply_trigger(void);
+
 #define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1)
 
 #if CONFIG_KEYPAD == RECORDER_PAD
@@ -79,8 +83,14 @@
 
 #define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */
 
-int screen_update = NB_SCREENS;
-bool remote_display_on = true;
+static int screen_update = NB_SCREENS;
+static bool remote_display_on = true;
+static bool recscreen_on = false;
+
+bool in_recording_screen(void)
+{
+    return recscreen_on;
+}
 
 /** File name creation **/
 #if CONFIG_CODEC == SWCODEC
@@ -622,7 +632,11 @@
 void rec_init_recording_options(struct audio_recording_options *options)
 {
     options->rec_source            = global_settings.rec_source;
+#if CONFIG_CODEC == SWCODEC
+    options->rec_sampr             = global_settings.rec_sampr;
+#else
     options->rec_frequency         = global_settings.rec_frequency;
+#endif
     options->rec_channels          = global_settings.rec_channels;
     options->rec_prerecord_time    = global_settings.rec_prerecord_time;
 #if CONFIG_CODEC == SWCODEC
@@ -736,7 +750,7 @@
     }
 }
 
-bool recording_screen(bool no_source)
+int recording_screen(void)
 {
     long button;
     bool done = false;
@@ -788,7 +802,7 @@
 
     struct audio_recording_options rec_options;
 
-    global_settings.recscreen_on = true;
+    recscreen_on = true;
     cursor = 0;
 #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR)
     ata_set_led_enabled(false);
@@ -1177,7 +1191,7 @@
                     /* led is restored at begin of loop / end of function */
                     led(false);
 #endif
-                    if (recording_menu(no_source))
+                    if (recording_menu())
                     {
                         done = true;
                         been_in_usb_mode = true;
@@ -1743,7 +1757,7 @@
     peak_meter_trigger(false);
     peak_meter_set_trigger_listener(NULL);
 
-    global_settings.recscreen_on = false;
+    recscreen_on = false;
     sound_settings_apply();
 
     FOR_NB_SCREENS(i)
@@ -1755,7 +1769,7 @@
 #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR)
     ata_set_led_enabled(true);
 #endif
-    return been_in_usb_mode;
+    return (int)been_in_usb_mode;
 } /* recording_screen */
 
 #if CONFIG_KEYPAD == RECORDER_PAD
@@ -2097,5 +2111,55 @@
 #endif /* #ifdef SIMULATOR */
 #endif /* #ifdef CONFIG_CODEC == SWCODEC */
 
+/* This array holds the record timer interval lengths, in seconds */
+static const unsigned long rec_timer_seconds[] =
+{
+    0,        /* 0 means OFF */
+    5*60,     /* 00:05 */
+    10*60,    /* 00:10 */
+    15*60,    /* 00:15 */
+    30*60,    /* 00:30 */
+    60*60,    /* 01:00 */
+    74*60,    /* 74:00 */
+    80*60,    /* 80:00 */
+    2*60*60,  /* 02:00 */
+    4*60*60,  /* 04:00 */
+    6*60*60,  /* 06:00 */
+    8*60*60,  /* 08:00 */
+    10L*60*60, /* 10:00 */
+    12L*60*60, /* 12:00 */
+    18L*60*60, /* 18:00 */
+    24L*60*60  /* 24:00 */
+};
 
+unsigned int rec_timesplit_seconds(void)
+{
+    return rec_timer_seconds[global_settings.rec_timesplit];
+}
+
+/* This array holds the record size interval lengths, in bytes */
+static const unsigned long rec_size_bytes[] =
+{
+    0,               /* 0 means OFF */
+    5*1024*1024,     /* 5MB */
+    10*1024*1024,    /* 10MB */
+    15*1024*1024,    /* 15MB */
+    32*1024*1024,    /* 32MB */
+    64*1024*1024,    /* 64MB */
+    75*1024*1024,    /* 75MB */
+    100*1024*1024,   /* 100MB */
+    128*1024*1024,   /* 128MB */
+    256*1024*1024,   /* 256MB */
+    512*1024*1024,   /* 512MB */
+    650*1024*1024,   /* 650MB */
+    700*1024*1024,   /* 700MB */
+    1024*1024*1024,  /* 1GB */
+    1536*1024*1024,  /* 1.5GB */
+    1792*1024*1024,  /* 1.75GB  */
+};
+
+unsigned long rec_sizesplit_bytes(void)
+{
+    return rec_size_bytes[global_settings.rec_sizesplit];
+}
 #endif /* HAVE_RECORDING */
Index: apps/recorder/recording.h
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/recording.h,v
retrieving revision 1.7
diff -u -r1.7 recording.h
--- apps/recorder/recording.h	23 Nov 2006 19:21:12 -0000	1.7
+++ apps/recorder/recording.h	30 Nov 2006 07:22:39 -0000
@@ -19,7 +19,8 @@
 #ifndef RECORDING_H
 #define RECORDING_H
 
-bool recording_screen(bool no_source);
+bool in_recording_screen(void);
+int recording_screen(void);
 char *rec_create_filename(char *buf);
 int rec_create_directory(void);
 
@@ -41,5 +42,4 @@
 
 /* creates unique filename and starts recording */
 void rec_new_file(void);
-
 #endif
Index: firmware/SOURCES
===================================================================
RCS file: /cvsroot/rockbox/firmware/SOURCES,v
retrieving revision 1.144
diff -u -r1.144 SOURCES
--- firmware/SOURCES	27 Nov 2006 09:44:55 -0000	1.144
+++ firmware/SOURCES	30 Nov 2006 07:22:41 -0000
@@ -101,6 +101,9 @@
 drivers/dac.c
 drivers/serial.c
 #endif /* SIMULATOR */
+#ifndef BOOTLADER
+general.c
+#endif
 
 /* Storage */
 #ifndef SIMULATOR
@@ -161,7 +164,6 @@
 #if CONFIG_CODEC == SWCODEC
 
 #ifndef BOOTLOADER
-general.c
 pcm_sampr.c
 replaygain.c
 #ifndef SIMULATOR
Index: firmware/pcm_record.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/pcm_record.c,v
retrieving revision 1.39
diff -u -r1.39 pcm_record.c
--- firmware/pcm_record.c	29 Nov 2006 14:23:24 -0000	1.39
+++ firmware/pcm_record.c	30 Nov 2006 07:22:45 -0000
@@ -24,9 +24,9 @@
 #include <string.h>
 #include "ata.h"
 #include "usb.h"
+#include "general.h"
 #if defined(HAVE_UDA1380)
 #include "uda1380.h"
-#include "general.h"
 #elif defined(HAVE_TLV320)
 #include "tlv320.h"
 #endif
@@ -91,8 +91,8 @@
 
 /** These apply to current settings **/
 static int           rec_source;         /* current rec_source setting     */
-static int           rec_frequency;      /* current frequency setting      */
-static unsigned long sample_rate;        /* Sample rate in HZ              */
+static unsigned long rec_sampr;          /* current frequency setting      */
+static unsigned long sample_rate;        /* hardware rate recording is using */
 static int           num_channels;       /* Current number of channels     */
 static struct encoder_config enc_config; /* Current encoder configuration  */
   
@@ -301,10 +301,6 @@
 #ifdef HAVE_SPDIF_IN
 unsigned long pcm_rec_sample_rate(void)
 {
-    /* Which is better ?? */
-#if 0
-    return enc_sample_rate;
-#endif
     return sample_rate;
 } /* audio_get_sample_rate */
 #endif
@@ -378,13 +374,14 @@
  */
 void audio_set_recording_options(struct audio_recording_options *options)
 {
+    int index;
+
     pcm_thread_wait_for_stop();
 
     /* stop DMA transfer */
     dma_lock = true;
     pcm_stop_recording();
 
-    rec_frequency      = options->rec_frequency;
     rec_source         = options->rec_source;
     num_channels       = options->rec_channels == 1 ? 1 : 2;
     pre_record_ticks   = options->rec_prerecord_time * HZ;
@@ -395,13 +392,13 @@
     if (rec_source == AUDIO_SRC_SPDIF)
     {
         /* must measure SPDIF sample rate before configuring codecs */
-        unsigned long sr = spdif_measure_frequency();
+        rec_sampr = spdif_measure_frequency();
         /* round to master list for SPDIF rate */
-        int index = round_value_to_list32(sr, audio_master_sampr_list,
-                                          SAMPR_NUM_FREQ, false);
+        index = round_value_to_list32(rec_sampr, audio_master_sampr_list,
+                                      SAMPR_NUM_FREQ, false);
         sample_rate = audio_master_sampr_list[index];
         /* round to HW playback rates for monitoring */
-        index = round_value_to_list32(sr, hw_freq_sampr,
+        index = round_value_to_list32(rec_sampr, hw_freq_sampr,
                                       HW_NUM_FREQ, false);
         pcm_set_frequency(hw_freq_sampr[index]);
         /* encoders with a limited number of rates do their own rounding */
@@ -409,8 +406,11 @@
     else
 #endif
     {
-        /* set sample rate from frequency selection */
-        sample_rate = rec_freq_sampr[rec_frequency];
+        /* Round requested rate to closest hardware recording rate */
+        rec_sampr = options->rec_sampr;
+        index = round_value_to_list32(rec_sampr, rec_freq_sampr,
+                                      REC_NUM_FREQ, false);
+        sample_rate = rec_freq_sampr[index];
         pcm_set_frequency(sample_rate);
     }
 
Index: firmware/drivers/lcd-player-charset.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/lcd-player-charset.c,v
retrieving revision 1.9
diff -u -r1.9 lcd-player-charset.c
--- firmware/drivers/lcd-player-charset.c	23 May 2005 12:04:30 -0000	1.9
+++ firmware/drivers/lcd-player-charset.c	30 Nov 2006 07:22:49 -0000
@@ -49,7 +49,7 @@
    RESERVED_CHAR, /* reserved */
    RESERVED_CHAR, /* reserved */
    RESERVED_CHAR, /* reserved */
-   RESERVED_CHAR, /* reserved */
+   0x215, /* 0x15 .. "checkmark" icon */
    0x216, /* 0x16 .. "bookmark" icon */
    0x217, /* 0x17 .. "plugin" icon */
    0x218, /* 0x18 .. "folder" icon */
@@ -311,7 +311,7 @@
    RESERVED_CHAR, /* reserved */
    RESERVED_CHAR, /* reserved */
    RESERVED_CHAR, /* reserved */
-   RESERVED_CHAR, /* reserved */
+   0x215, /* 0x15 .. "checkmark" icon */
    0x216, /* 0x16 .. "bookmark" icon */
    0x217, /* 0x17 .. "plugin" icon */
    0x218, /* 0x18 .. "folder" icon */
@@ -671,7 +671,7 @@
   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 12 */
   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 13 */
   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 14 */
-  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 15 */
+  { 0x00, 0x01, 0x03, 0x16, 0x1c, 0x08, 0x00, 0x00}, /* 15 Checkmark */
   { 0x00, 0x03, 0x07, 0x0e, 0x1c, 0x08, 0x00, 0x00}, /* 16 Bookmark icon */
   { 0x04, 0x1e, 0x07, 0x1f, 0x05, 0x01, 0x06, 0x00}, /* 17 Plugin file icon */
   { 0x0c, 0x13, 0x11, 0x11, 0x11, 0x11, 0x1f, 0x00}, /* 18 Folder icon */
Index: firmware/export/audio.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/audio.h,v
retrieving revision 1.25
diff -u -r1.25 audio.h
--- firmware/export/audio.h	23 Nov 2006 19:21:14 -0000	1.25
+++ firmware/export/audio.h	30 Nov 2006 07:22:50 -0000
@@ -147,9 +147,22 @@
 #else
     AUDIO_NUM_SOURCES = AUDIO_SOURCE_LIST_END-1,
 #endif
-    AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1
+    AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1,
+    AUDIO_SRC_DEFAULT = AUDIO_SRC_MIC
 };
 
+#ifdef HAVE_SPDIF_IN
+#define HAVE_SPDIF_IN_(...) __VA_ARGS__
+#else
+#define HAVE_SPDIF_IN_(...)
+#endif
+
+#ifdef HAVE_FMRADIO_IN
+#define HAVE_FMRADIO_IN_(...) __VA_ARGS__
+#else
+#define HAVE_FMRADIO_IN_(...)
+#endif
+
 #if CONFIG_CODEC == SWCODEC
 /* selects an audio source for recording or playback */
 #define SRCF_PLAYBACK         0x0000    /* default */
@@ -166,7 +179,11 @@
 struct audio_recording_options
 {
     int  rec_source;
+#if CONFIG_CODEC == SWCODEC
+    int  rec_sampr;
+#else
     int  rec_frequency;
+#endif
     int  rec_channels;
     int  rec_prerecord_time;
 #if CONFIG_CODEC == SWCODEC
Index: firmware/export/enc_base.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/enc_base.h,v
retrieving revision 1.2
diff -u -r1.2 enc_base.h
--- firmware/export/enc_base.h	24 Nov 2006 19:49:04 -0000	1.2
+++ firmware/export/enc_base.h	30 Nov 2006 07:22:51 -0000
@@ -101,9 +101,8 @@
     unsigned long bitrate;
 };
 
-#define MP3_ENC_BITRATE_CFG_DEFAULT     11 /* 128 */
-#define MP3_ENC_BITRATE_CFG_VALUE_LIST  "8,16,24,32,40,48,56,64,80,96," \
-                                        "112,128,144,160,192,224,256,320"
+/* default that works for all types */
+#define MP3_ENC_BITRATE_DEFAULT 128
 
 /** wav_enc.codec **/
 #define WAV_ENC_SAMPR_CAPS      SAMPR_CAP_ALL
@@ -136,6 +135,7 @@
 
     union
     {
+        unsigned char data[1]; /* generic union access */
         struct mp3_enc_config     mp3_enc;
         struct wavpack_enc_config wavpack_enc;
         struct wav_enc_config     wav_enc;
Index: firmware/export/id3.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/id3.h,v
retrieving revision 1.36
diff -u -r1.36 id3.h
--- firmware/export/id3.h	24 Nov 2006 20:10:32 -0000	1.36
+++ firmware/export/id3.h	30 Nov 2006 07:22:52 -0000
@@ -84,17 +84,18 @@
 
     /* add new formats at any index above this line to have a sensible order -
        specified array index inits are used
-       REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range
        REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes
     */
 
     REC_NUM_FORMATS,
-
-    REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV,
-    REC_FORMAT_CFG_NUM_BITS = 2
+    REC_FORMAT_FIRST = 0,
+    REC_FORMAT_LAST  = REC_NUM_FORMATS-1,
+    REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV
 };
 
-#define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3" 
+
+#define REC_FORMAT_CFG_VAL_LIST "wave,wvpk,mpa3"
+#define REC_FORMAT_LANG_ID_LIST LANG_AFMT_PCM_WAV, LANG_AFMT_WAVPACK, LANG_AFMT_MPA_L3
 
 /* get REC_FORMAT_* corresponding AFMT_* */
 extern const int rec_format_afmt[REC_NUM_FORMATS];
Index: firmware/export/kernel.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/kernel.h,v
retrieving revision 1.29
diff -u -r1.29 kernel.h
--- firmware/export/kernel.h	22 Nov 2006 00:41:30 -0000	1.29
+++ firmware/export/kernel.h	30 Nov 2006 07:22:52 -0000
@@ -48,6 +48,7 @@
 #define SYS_CHARGER_DISCONNECTED  ((SYS_EVENT | ((long)11 << 27)))
 #define SYS_PHONE_PLUGGED         ((SYS_EVENT | ((long)12 << 27)))
 #define SYS_PHONE_UNPLUGGED       ((SYS_EVENT | ((long)13 << 27)))
+#define SYS_DUMPSETTINGS          ((SYS_EVENT | ((long)14 << 27)))
 
 struct event
 {
Index: firmware/export/pcm_sampr.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/pcm_sampr.h,v
retrieving revision 1.1
diff -u -r1.1 pcm_sampr.h
--- firmware/export/pcm_sampr.h	6 Nov 2006 18:18:05 -0000	1.1
+++ firmware/export/pcm_sampr.h	30 Nov 2006 07:22:53 -0000
@@ -286,23 +286,9 @@
     REC_NUM_FREQ,
     /* This should always come out I reckon */
     REC_FREQ_DEFAULT      = REC_FREQ_44,
-    /* Get the minimum bitcount needed to save the range of values */
-    REC_FREQ_CFG_NUM_BITS = (REC_NUM_FREQ > 8 ?
-                             4 : (REC_NUM_FREQ > 4 ?
-                                  3 : (REC_NUM_FREQ > 2 ?
-                                       2 : 1
-                                      )
-                                 )
-                            ),
+    REC_SAMPR_DEFAULT     = SAMPR_44,
 }; /* enum rec_freq_indexes */
 
-#define REC_FREQ_CFG_VAL_LIST  &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \
-                                REC_HAVE_64_(",64") REC_HAVE_48_(",48") \
-                                REC_HAVE_44_(",44") REC_HAVE_32_(",32") \
-                                REC_HAVE_24_(",24") REC_HAVE_22_(",22") \
-                                REC_HAVE_16_(",16") REC_HAVE_12_(",12") \
-                                REC_HAVE_11_(",11") REC_HAVE_8_(",8")[1]
-
 /* List of recording supported sample rates (set or subset of master list) */
 extern const unsigned long rec_freq_sampr[REC_NUM_FREQ];
 #endif /* HAVE_RECORDING */
--- /dev/null	2006-10-26 00:03:47.000000000 +1000
+++ apps/menus/display_menu.c	2006-11-23 18:53:06.000000000 +1100
@@ -0,0 +1,374 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:  $
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <timefuncs.h>
+#include "config.h"
+#include "options.h"
+
+#include "menu.h"
+#include "tree.h"
+#include "lcd.h"
+#include "font.h"
+#include "action.h"
+#include "kernel.h"
+#include "debug_menu.h"
+#include "sprintf.h"
+#include <string.h>
+#include "settings.h"
+#include "power.h"
+#include "powermgmt.h"
+#include "status.h"
+#include "fat.h"
+#include "bookmark.h"
+#include "buffer.h"
+#include "screens.h"
+#include "keyboard.h"
+#include "playlist_catalog.h"
+#include "playlist_viewer.h"
+#include "playlist.h"
+#include "talk.h"
+#ifdef CONFIG_TUNER
+#include "radio.h"
+#endif
+#include "misc.h"
+#include "lang.h"
+#include "logfdisp.h"
+#include "plugin.h"
+#include "filetypes.h"
+#include "splash.h"
+#include "yesno.h"
+#ifdef HAVE_LCD_COLOR
+#include "color_picker.h"
+#include "backdrop.h"
+#endif
+
+#ifdef HAVE_RECORDING
+#include "recording.h"
+#endif
+#if CONFIG_CODEC == SWCODEC
+#include "dsp.h"
+#include "eq_menu.h"
+#include "pcmbuf.h"
+#endif
+
+#include "tagcache.h"
+#include "tagtree.h"
+#include "tagcache.h"
+#ifdef HAVE_ALARM_MOD
+#include "alarm_menu.h"
+#endif
+
+
+/***********************************/
+/*    LCD MENU                     */
+#ifdef CONFIG_BACKLIGHT
+MAKE_SETTING_OPT(backlight_timeout,NULL);
+#ifdef CONFIG_CHARGING
+MAKE_SETTING_OPT(backlight_timeout_plugged,NULL);
+#endif
+#ifdef HAS_BUTTON_HOLD
+MAKE_SETTING_OPT(backlight_on_button_hold,NULL);
+#endif
+MAKE_SETTING_OPT(caption_backlight,NULL);
+#if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
+MAKE_SETTING_OPT(backlight_fade_in,NULL);
+MAKE_SETTING_OPT(backlight_fade_out,NULL);
+#endif
+MAKE_SETTING_OPT(bl_filter_first_keypress,NULL);
+#ifdef HAVE_LCD_SLEEP
+MAKE_SETTING_OPT(lcd_sleep_after_backlight_off,NULL);
+#endif
+#ifdef HAVE_BACKLIGHT_BRIGHTNESS
+const struct menu_item_ex brightness_item =
+{MT_SETTING, {.global_settings_variable = 
+    (void*)&global_settings.brightness},1,NULL,0};
+#endif
+#endif /* CONFIG_BACKLIGHT */
+#ifdef HAVE_LCD_CONTRAST
+MAKE_SETTING_OPT(contrast,NULL);
+#endif
+#ifdef HAVE_LCD_BITMAP
+#ifndef HAVE_LCD_COLOR
+MAKE_SETTING_OPT(invert,NULL);
+#endif
+#ifdef HAVE_LCD_FLIP
+MAKE_SETTING_OPT(flip_display,NULL);
+#endif
+MAKE_SETTING_OPT(invert_cursor,NULL);
+#endif /* HAVE_LCD_BITMAP */
+#ifdef HAVE_LCD_COLOR
+/**
+ * Menu to clear the backdrop image
+ */
+static int clear_main_backdrop(void)
+{
+    global_settings.backdrop_file[0]=0;
+    unload_main_backdrop();
+    show_main_backdrop();
+    return 0;
+}
+
+/**
+ * Menu for fore/back colors
+ */
+static int set_fg_color(void)
+{
+    int res;
+
+    res = (int)set_color(&screens[SCREEN_MAIN],str(LANG_FOREGROUND_COLOR),
+                     &global_settings.fg_color,global_settings.bg_color);
+
+    screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
+
+    return res;
+}
+
+static int set_bg_color(void)
+{
+    int res;
+
+    res = (int)set_color(&screens[SCREEN_MAIN],str(LANG_BACKGROUND_COLOR),
+                     &global_settings.bg_color,global_settings.fg_color);
+
+    screens[SCREEN_MAIN].set_background(global_settings.bg_color);
+
+    return res;
+}
+
+static int reset_color(void)
+{
+    global_settings.fg_color = LCD_DEFAULT_FG;
+    global_settings.bg_color = LCD_DEFAULT_BG;
+
+    screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
+    screens[SCREEN_MAIN].set_background(global_settings.bg_color);
+    return 0;
+}
+MAKE_FUNCTION_CALL(clear_main_bd, ID2P(LANG_CLEAR_BACKDROP),clear_main_backdrop, NULL);
+MAKE_FUNCTION_CALL(set_bg_col, ID2P(LANG_BACKGROUND_COLOR),set_bg_color, NULL);
+MAKE_FUNCTION_CALL(set_fg_col, ID2P(LANG_FOREGROUND_COLOR),set_fg_color, NULL);
+MAKE_FUNCTION_CALL(reset_colors, ID2P(LANG_RESET_COLORS),reset_color, NULL);
+#endif
+
+/* now the actual menu */
+MAKE_MENU(lcd_settings_menu,ID2P(LANG_LCD_MENU),0
+#ifdef CONFIG_BACKLIGHT
+,&backlight_timeout
+#ifdef CONFIG_CHARGING
+,&backlight_timeout_plugged
+#endif
+#ifdef HAS_BUTTON_HOLD
+,&backlight_on_button_hold
+#endif
+,&caption_backlight
+#if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
+,&backlight_fade_in,&backlight_fade_out
+#endif
+,&bl_filter_first_keypress
+#ifdef HAVE_LCD_SLEEP
+,&lcd_sleep_after_backlight_off
+#endif
+#ifdef HAVE_BACKLIGHT_BRIGHTNESS
+,&brightness_item
+#endif
+#endif /* CONFIG_BACKLIGHT */
+#ifdef HAVE_LCD_CONTRAST
+,&contrast
+#endif
+#ifdef HAVE_LCD_BITMAP
+#ifndef HAVE_LCD_COLOR
+,&invert
+#endif
+#ifdef HAVE_LCD_FLIP
+,&flip_display
+#endif
+,&invert_cursor
+#endif /* HAVE_LCD_BITMAP */
+#ifdef HAVE_LCD_COLOR
+,&clear_main_bd,&set_bg_col,&set_fg_col,&reset_colors
+#endif
+         );
+/*    LCD MENU                    */
+/***********************************/
+
+/***********************************/
+/*    REMOTE LCD MENU              */
+#ifdef HAVE_REMOTE_LCD
+MAKE_SETTING_OPT(remote_backlight_timeout,NULL);
+#ifdef CONFIG_CHARGING
+MAKE_SETTING_OPT(remote_backlight_timeout_plugged,NULL);
+#endif
+#ifdef HAS_REMOTE_BUTTON_HOLD
+MAKE_SETTING_OPT(remote_backlight_on_button_hold,NULL);
+#endif
+MAKE_SETTING_OPT(remote_caption_backlight,NULL);
+MAKE_SETTING_OPT(remote_bl_filter_first_keypress,NULL);
+MAKE_SETTING_OPT(remote_contrast,NULL);
+MAKE_SETTING_OPT(remote_invert,NULL);
+MAKE_SETTING_OPT(remote_flip_display,NULL);
+#ifdef HAVE_REMOTE_LCD_TICKING
+MAKE_SETTING_OPT(remote_reduce_ticking,NULL);
+#endif
+
+MAKE_MENU(remote_lcd_menu,ID2P(LANG_LCD_REMOTE_MENU),0,
+          &remote_backlight_timeout
+#ifdef CONFIG_CHARGING
+                  ,&remote_backlight_timeout_plugged
+#endif
+#ifdef HAS_REMOTE_BUTTON_HOLD
+,&remote_backlight_on_button_hold
+#endif
+,&remote_caption_backlight,&remote_bl_filter_first_keypress,&remote_contrast,
+&remote_invert,&remote_flip_display
+#ifdef HAVE_REMOTE_LCD_TICKING
+,&remote_reduce_ticking
+#endif
+         );
+#endif /* HAVE_REMOTE_LCD */
+/*    REMOTE LCD MENU              */
+/***********************************/
+
+/***********************************/
+/*    SCROLL MENU                  */
+MAKE_SETTING_OPT(scroll_speed,NULL);
+MAKE_SETTING_OPT(scroll_delay,NULL);
+#ifdef HAVE_LCD_BITMAP
+MAKE_SETTING_OPT(scroll_step,NULL);
+#endif
+MAKE_SETTING_OPT(bidir_limit,NULL);
+#ifdef HAVE_REMOTE_LCD
+MAKE_SETTING_OPT(remote_scroll_speed,NULL);
+MAKE_SETTING_OPT(remote_scroll_delay,NULL);
+MAKE_SETTING_OPT(remote_scroll_step,NULL);
+MAKE_SETTING_OPT(remote_bidir_limit,NULL);
+MAKE_MENU(remote_scroll_sets,ID2P(LANG_REMOTE_SCROLL_SETS),0,
+          &remote_scroll_speed,&remote_scroll_delay,
+          &remote_scroll_step,&remote_bidir_limit);
+#endif /* HAVE_REMOTE_LCD */
+#ifdef HAVE_LCD_CHARCELLS
+MAKE_SETTING_OPT(jump_scroll,NULL);
+MAKE_SETTING_OPT(jump_scroll_delay,NULL);
+#endif
+#ifdef HAVE_LCD_BITMAP
+MAKE_SETTING_OPT(offset_out_of_view,NULL);
+MAKE_SETTING_OPT(screen_scroll_step,NULL);
+#endif
+MAKE_SETTING_OPT(scroll_paginated,NULL);
+
+MAKE_MENU(scroll_settings_menu,ID2P(LANG_SCROLL_MENU),0,
+          &scroll_speed,&scroll_delay,
+#ifdef HAVE_LCD_BITMAP
+&scroll_step,
+#endif
+&bidir_limit,
+#ifdef HAVE_REMOTE_LCD
+&remote_scroll_sets,
+#endif
+#ifdef HAVE_LCD_CHARCELLS
+&jump_scroll,&jump_scroll_delay,
+#endif
+#ifdef HAVE_LCD_BITMAP
+&offset_out_of_view,&screen_scroll_step,
+#endif
+&scroll_paginated);
+/*    SCROLL MENU                  */
+/***********************************/
+
+/***********************************/
+/*    BARS MENU                    */
+#ifdef HAVE_LCD_BITMAP
+const struct menu_item_ex scrollbar_item =
+    {MT_SETTING, {.global_settings_variable = 
+        (void*)&global_settings.scrollbar},1,NULL,0};
+MAKE_SETTING_OPT(statusbar,NULL);
+#if CONFIG_KEYPAD == RECORDER_PAD
+MAKE_SETTING_OPT(buttonbar,NULL);
+#endif
+MAKE_SETTING_OPT(volume_type,NULL);
+MAKE_SETTING_OPT(battery_display,NULL);
+MAKE_MENU(bars_menu,ID2P(LANG_BARS_MENU),0,
+          &scrollbar_item,&statusbar,
+#if CONFIG_KEYPAD == RECORDER_PAD
+          &buttonbar,
+#endif
+          &volume_type,&battery_display);
+#endif /* HAVE_LCD_BITMAP */
+/*    BARS MENU                    */
+/***********************************/
+
+/***********************************/
+/*    PEAK-METERS MENU             */
+#ifdef HAVE_LCD_BITMAP
+MAKE_SETTING_OPT(peak_meter_release,NULL);
+MAKE_SETTING_OPT(peak_meter_hold,NULL);
+MAKE_SETTING_OPT(peak_meter_clip_hold,NULL);
+MAKE_SETTING_OPT(peak_meter_dbfs,NULL);
+MAKE_SETTING_OPT(peak_meter_min,NULL);
+MAKE_SETTING_OPT(peak_meter_max,NULL);
+
+MAKE_MENU(peak_meter_menu,ID2P(LANG_PM_MENU),0,
+          &peak_meter_release,&peak_meter_hold,&peak_meter_clip_hold,
+          &peak_meter_dbfs,&peak_meter_min,&peak_meter_max);
+#endif /* HAVE_LCD_BITMAP */
+/*    PEAK-METERS MENU             */
+/***********************************/
+
+/***********************************/
+/*    DISPLAY MENU                 */
+#ifdef HAVE_LCD_BITMAP
+static int font_browse(void)
+{
+    return (int)rockbox_browse(ROCKBOX_DIR FONT_DIR, SHOW_FONT);
+}
+MAKE_FUNCTION_CALL(browse_fonts, ID2P(LANG_CUSTOM_FONT),font_browse, NULL);
+#endif
+static int wps_browse(void)
+{
+    return (int)rockbox_browse(WPS_DIR, SHOW_WPS);
+}
+MAKE_FUNCTION_CALL(browse_wps, ID2P(LANG_WHILE_PLAYING),wps_browse, NULL);
+#ifdef HAVE_REMOTE_LCD
+static int rwps_browse(void)
+{
+    return (int)rockbox_browse(WPS_DIR, SHOW_RWPS);
+}
+MAKE_FUNCTION_CALL(browse_rwps, ID2P(LANG_REMOTE_WHILE_PLAYING),rwps_browse, NULL);
+#endif
+MAKE_SETTING_OPT(default_codepage,NULL);
+
+MAKE_MENU(display_menu,ID2P(LANG_DISPLAY),0,
+#ifdef HAVE_LCD_BITMAP
+            &browse_fonts,
+#endif
+            &browse_wps,
+#ifdef HAVE_REMOTE_LCD
+            &browse_rwps,
+#endif
+            &lcd_settings_menu,
+
+#ifdef HAVE_REMOTE_LCD
+            &remote_lcd_menu,
+#endif
+            &scroll_settings_menu,
+#ifdef HAVE_LCD_BITMAP
+            &bars_menu,&peak_meter_menu,
+#endif
+            &default_codepage
+         );
+/*    DISPLAY MENU                 */
+/***********************************/
--- /dev/null	2006-10-26 00:03:47.000000000 +1000
+++ apps/menus/main_menu.c	2006-11-23 20:19:02.000000000 +1100
@@ -0,0 +1,721 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:  $
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <timefuncs.h>
+#include "config.h"
+#include "options.h"
+
+#include "menu.h"
+#include "tree.h"
+#include "lcd.h"
+#include "font.h"
+#include "action.h"
+#include "kernel.h"
+#include "debug_menu.h"
+#include "sprintf.h"
+#include <string.h>
+#include "settings.h"
+#include "power.h"
+#include "powermgmt.h"
+#include "status.h"
+#include "fat.h"
+#include "bookmark.h"
+#include "buffer.h"
+#include "screens.h"
+#include "keyboard.h"
+#include "playlist_catalog.h"
+#include "playlist_viewer.h"
+#include "playlist.h"
+#include "talk.h"
+#ifdef CONFIG_TUNER
+#include "radio.h"
+#endif
+#include "misc.h"
+#include "lang.h"
+#include "logfdisp.h"
+#include "plugin.h"
+#include "filetypes.h"
+#include "splash.h"
+#include "yesno.h"
+#ifdef HAVE_LCD_COLOR
+#include "color_picker.h"
+#include "backdrop.h"
+#endif
+
+#ifdef HAVE_RECORDING
+#include "recording.h"
+#endif
+#if CONFIG_CODEC == SWCODEC
+#include "dsp.h"
+#include "eq_menu.h"
+#include "pcmbuf.h"
+#endif
+
+#include "tagcache.h"
+#include "tagtree.h"
+#include "tagcache.h"
+#ifdef HAVE_ALARM_MOD
+#include "alarm_menu.h"
+#endif
+
+
+
+
+
+bool show_credits(void)
+{
+    plugin_load("/.rockbox/rocks/credits.rock",NULL);
+    return false;
+}
+
+#ifdef SIMULATOR
+extern bool simulate_usb(void);
+#endif
+
+#ifdef HAVE_LCD_CHARCELLS
+#define SIZE_FMT "%s%s"
+#else
+#define SIZE_FMT "%s %s"
+#endif
+
+bool show_info(void)
+{
+    char s[64], s1[32];
+    unsigned long size, free;
+    long buflen = ((audiobufend - audiobuf) * 2) / 2097;  /* avoid overflow */
+    int key;
+    int i;
+    bool done = false;
+    bool new_info = true;
+#ifdef HAVE_MULTIVOLUME
+    char s2[32];
+    unsigned long size2, free2;
+#endif
+#ifdef HAVE_LCD_CHARCELLS
+    int page = 0;
+#endif
+
+    const unsigned char *kbyte_units[] = {
+        ID2P(LANG_KILOBYTE),
+        ID2P(LANG_MEGABYTE),
+        ID2P(LANG_GIGABYTE)
+    };
+    
+    while (!done)
+    {
+        int y=0;
+
+        if (new_info)
+        {
+            fat_size( IF_MV2(0,) &size, &free );
+#ifdef HAVE_MULTIVOLUME
+            if (fat_ismounted(1))
+                fat_size( 1, &size2, &free2 );
+            else
+                size2 = 0;
+#endif
+
+            if (global_settings.talk_menu)
+            {   /* say whatever is reasonable, no real connection to the screen */
+                bool enqueue = false; /* enqueue all but the first */
+                if (battery_level() >= 0)
+                {
+                    talk_id(LANG_BATTERY_TIME, enqueue);
+                    enqueue = true;
+                    talk_value(battery_level(), UNIT_PERCENT, true);
+#if CONFIG_CHARGING >= CHARGING_MONITOR
+                    if (charge_state == CHARGING)
+                        talk_id(LANG_BATTERY_CHARGE, true);               
+                    else if (charge_state == TOPOFF)
+                        talk_id(LANG_BATTERY_TOPOFF_CHARGE, true);
+                    else if (charge_state == TRICKLE)
+                        talk_id(LANG_BATTERY_TRICKLE_CHARGE, true);
+#endif
+                }
+
+                talk_id(LANG_DISK_FREE_INFO, enqueue);
+#ifdef HAVE_MULTIVOLUME
+                talk_id(LANG_DISK_NAME_INTERNAL, true);
+                output_dyn_value(NULL, 0, free, kbyte_units, true);
+                if (size2)
+                {
+                    talk_id(LANG_DISK_NAME_MMC, true);
+                    output_dyn_value(NULL, 0, free2, kbyte_units, true);
+                }
+#else
+                output_dyn_value(NULL, 0, free, kbyte_units, true);
+#endif
+
+#ifdef CONFIG_RTC
+                {
+                    struct tm* tm = get_time();
+                    talk_id(VOICE_CURRENT_TIME, true);
+                    talk_value(tm->tm_hour, UNIT_HOUR, true);
+                    talk_value(tm->tm_min, UNIT_MIN, true);
+                    talk_value(tm->tm_sec, UNIT_SEC, true);
+                    talk_id(LANG_MONTH_JANUARY + tm->tm_mon, true);
+                    talk_number(tm->tm_mday, true);
+                    talk_number(1900 + tm->tm_year, true);
+                }
+#endif
+            }
+            new_info = false;
+        }
+
+        FOR_NB_SCREENS(i)
+        {
+            screens[i].clear_display();
+#ifdef HAVE_LCD_BITMAP
+            screens[i].puts(0, y, str(LANG_ROCKBOX_INFO));
+#endif
+        }
+#ifdef HAVE_LCD_BITMAP
+        y += 2;
+#endif
+
+#ifdef HAVE_LCD_CHARCELLS
+        if (page == 0)
+#endif
+        {
+            int integer = buflen / 1000;
+            int decimal = buflen % 1000;
+
+#ifdef HAVE_LCD_CHARCELLS
+            snprintf(s, sizeof(s), (char *)str(LANG_BUFFER_STAT_PLAYER),
+                     integer, decimal);
+#else
+            snprintf(s, sizeof(s), (char *)str(LANG_BUFFER_STAT_RECORDER),
+                     integer, decimal);
+#endif
+            FOR_NB_SCREENS(i)
+                screens[i].puts_scroll(0, y, (unsigned char *)s);
+            y++;
+#if CONFIG_CHARGING == CHARGING_CONTROL
+            if (charge_state == CHARGING)
+                snprintf(s, sizeof(s), (char *)str(LANG_BATTERY_CHARGE));
+            else if (charge_state == TOPOFF)
+                snprintf(s, sizeof(s), (char *)str(LANG_BATTERY_TOPOFF_CHARGE));
+            else if (charge_state == TRICKLE)
+                snprintf(s, sizeof(s), (char *)str(LANG_BATTERY_TRICKLE_CHARGE));
+            else
+#endif
+            if (battery_level() >= 0)
+                snprintf(s, sizeof(s), (char *)str(LANG_BATTERY_TIME), battery_level(),
+                         battery_time() / 60, battery_time() % 60);
+            else
+                strncpy(s, "(n/a)", sizeof(s));
+            FOR_NB_SCREENS(i)
+                screens[i].puts_scroll(0, y, (unsigned char *)s); 
+            y++;
+        }
+
+#ifdef HAVE_LCD_CHARCELLS
+        if (page == 1)
+#endif
+        {
+#ifdef HAVE_MULTIVOLUME
+            output_dyn_value(s1, sizeof s1, free, kbyte_units, true);
+            output_dyn_value(s2, sizeof s2, size, kbyte_units, true);
+            snprintf(s, sizeof s, "%s %s/%s", str(LANG_DISK_NAME_INTERNAL),
+                     s1, s2);
+            FOR_NB_SCREENS(i)
+                screens[i].puts_scroll(0, y, (unsigned char *)s);
+            y++;
+
+            if (size2) {
+                output_dyn_value(s1, sizeof s1, free2, kbyte_units, true);
+                output_dyn_value(s2, sizeof s2, size2, kbyte_units, true);
+                snprintf(s, sizeof s, "%s %s/%s", str(LANG_DISK_NAME_MMC),
+                         s1, s2);
+                FOR_NB_SCREENS(i)
+                    screens[i].puts_scroll(0, y, (unsigned char *)s);
+                y++;
+            }
+#else
+            output_dyn_value(s1, sizeof s1, size, kbyte_units, true);
+            snprintf(s, sizeof s, SIZE_FMT, str(LANG_DISK_SIZE_INFO), s1);
+            FOR_NB_SCREENS(i)
+                screens[i].puts_scroll(0, y, (unsigned char *)s);
+            y++;
+            output_dyn_value(s1, sizeof s1, free, kbyte_units, true);
+            snprintf(s, sizeof s, SIZE_FMT, str(LANG_DISK_FREE_INFO), s1);
+            FOR_NB_SCREENS(i)
+                screens[i].puts_scroll(0, y, (unsigned char *)s);
+            y++;
+#endif
+        }
+
+#if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
+        FOR_NB_SCREENS(i)
+                screens[i].update();
+#endif
+
+        /* Wait for a key to be pushed */
+        key = get_action(CONTEXT_MAINMENU,HZ*5);
+        switch(key) {
+
+            case ACTION_STD_CANCEL:
+                done = true;
+                break;
+
+#ifdef HAVE_LCD_CHARCELLS
+            case ACTION_STD_NEXT:
+            case ACTION_STD_PREV:
+                page = (page == 0) ? 1 : 0;
+                break;
+#endif
+
+#ifndef SIMULATOR
+            case ACTION_STD_OK:
+                gui_syncsplash(0, true, str(LANG_DIRCACHE_BUILDING));
+                fat_recalc_free(IF_MV(0));
+#ifdef HAVE_MULTIVOLUME
+                if (fat_ismounted(1))
+                    fat_recalc_free(1);
+#endif
+                new_info = true;
+                break;
+#endif
+
+            default:
+                if (default_event_handler(key) == SYS_USB_CONNECTED)
+                    return true;
+                break;
+        }
+    }
+    action_signalscreenchange();
+    return false;
+}
+
+/* lazy coders can use this function if the needed callback is 
+    just to say if the item is shown or not */
+/* at the bottom of this file */
+int dynamicitem_callback(int action,const struct menu_item_ex *this_item); 
+    
+
+/***********************************/
+/*    MANAGE SETTINGS MENU        */
+static int config_browse(void)
+{
+    return (int)rockbox_browse(ROCKBOX_DIR, SHOW_CFG);
+}
+static int firmware_browse(void)
+{
+    return (int)rockbox_browse(ROCKBOX_DIR, SHOW_MOD);
+}
+static int reset_settings(void)
+{
+    unsigned char *lines[]={str(LANG_RESET_ASK_RECORDER)};
+    unsigned char *yes_lines[]={
+        str(LANG_RESET_DONE_SETTING),
+        str(LANG_RESET_DONE_CLEAR)
+    };
+    unsigned char *no_lines[]={yes_lines[0], str(LANG_RESET_DONE_CANCEL)};
+    struct text_message message={(char **)lines, 1};
+    struct text_message yes_message={(char **)yes_lines, 2};
+    struct text_message no_message={(char **)no_lines, 2};
+
+    switch(gui_syncyesno_run(&message, &yes_message, &no_message))
+    {
+        case YESNO_YES:
+            settings_reset();
+            settings_apply(false);
+            break;
+        case YESNO_NO:
+            break;
+        case YESNO_USB:
+            return 1;
+    }
+    return 0;
+}
+static int write_settings(bool theme)
+{
+    char buffer[MAX_PATH];
+    strcpy(buffer, ROCKBOX_CONFIGFILE);
+    if (!kbd_input(buffer,MAX_PATH))
+    {
+        if (settings_save_config(buffer,theme))
+        {
+            gui_syncsplash(HZ, true, str(LANG_SETTINGS_SAVED));
+            return 0;
+        }
+    }
+    gui_syncsplash(HZ, true, str(LANG_MENU_SETTING_CANCEL));
+    return 1;
+}
+static int write_settings_(void)
+{
+    return write_settings(false);
+}
+static int write_settings_theme(void)
+{
+    return write_settings(true);
+}
+MAKE_FUNCTION_CALL(browse_configs,ID2P(LANG_CUSTOM_CFG),config_browse, NULL);
+MAKE_FUNCTION_CALL(browse_firmwares,ID2P(LANG_FIRMWARE),firmware_browse, NULL);
+MAKE_FUNCTION_CALL(reset_settings_item,ID2P(LANG_RESET),reset_settings, NULL);
+MAKE_FUNCTION_CALL(save_settings_item,ID2P(LANG_SAVE_SETTINGS),write_settings_, NULL);
+MAKE_FUNCTION_CALL(save_theme_item,ID2P(LANG_WRITE_THEME),write_settings_theme, NULL);
+MAKE_MENU(manage_settings,ID2P(LANG_MANAGE_MENU),NULL,
+          &browse_configs,&browse_firmwares,&reset_settings_item,
+          &save_settings_item,&save_theme_item);
+/*    MANAGE SETTINGS MENU        */
+/**********************************/
+
+
+
+/***********************************/
+/*    TAGCACHE MENU                */
+#ifdef HAVE_TC_RAMCACHE
+MAKE_SETTING_OPT(tagcache_ram, NULL);
+#endif
+MAKE_SETTING_OPT(tagcache_autoupdate, NULL);
+MAKE_FUNCTION_CALL(tc_init, ID2P(LANG_TAGCACHE_FORCE_UPDATE),tagcache_rebuild, NULL);
+MAKE_FUNCTION_CALL(tc_update, ID2P(LANG_TAGCACHE_UPDATE),tagcache_update, NULL);
+MAKE_SETTING_OPT(runtimedb, NULL);
+MAKE_FUNCTION_CALL(tc_export, ID2P(LANG_TAGCACHE_EXPORT),tagtree_export, NULL);
+MAKE_FUNCTION_CALL(tc_import, ID2P(LANG_TAGCACHE_IMPORT),tagtree_import, NULL);
+MAKE_MENU(tagcache_menu, ID2P(LANG_TAGCACHE), 0, 
+#ifdef HAVE_TC_RAMCACHE
+                &tagcache_ram,
+#endif
+                &tagcache_autoupdate, &tc_init, &tc_update, &runtimedb,
+                &tc_export, &tc_import);
+/*    TAGCACHE MENU                */
+/***********************************/
+  
+/***********************************/
+/*    FILE VIEW MENU               */
+MAKE_SETTING_OPT(sort_case, NULL);
+MAKE_SETTING_OPT(sort_dir, NULL);
+MAKE_SETTING_OPT(sort_file, NULL);
+MAKE_SETTING_OPT(dirfilter, NULL);
+MAKE_SETTING_OPT(browse_current, NULL);
+MAKE_SETTING_OPT(show_icons, NULL);
+MAKE_SETTING_OPT(show_path_in_browser, NULL);
+MAKE_MENU(file_menu, ID2P(LANG_FILE),0,&sort_case,&sort_dir,&sort_file,
+                &dirfilter,&browse_current,&show_icons,&show_path_in_browser,
+                &tagcache_menu);
+/*    FILE VIEW MENU               */
+/***********************************/
+
+/***********************************/
+/*    BOOKMARK MENU                */
+MAKE_SETTING_OPT(autocreatebookmark, NULL);
+MAKE_SETTING_OPT(autoloadbookmark, NULL);
+MAKE_SETTING_OPT(usemrb, NULL);
+MAKE_MENU(bookmark_settings_menu,ID2P(LANG_BOOKMARK_SETTINGS),0,
+          &autocreatebookmark,&autoloadbookmark,&usemrb);
+/*    BOOKMARK MENU                */
+/***********************************/
+
+/***********************************/
+/*    VOICE MENU                   */
+int talkfile_callback(int action,const struct menu_item_ex *this_item)
+{
+    (void)this_item;
+    static int oldval = 0;
+    switch (action)
+    {
+        case ACTION_ENTER_MENUITEM:
+            oldval = global_settings.talk_file;
+            break;
+        case ACTION_EXIT_MENUITEM:
+#if CONFIG_CODEC == SWCODEC
+            audio_set_crossfade(global_settings.crossfade);
+#endif
+            if (oldval != 3 && global_settings.talk_file == 3)
+            {   /* force reload if newly talking thumbnails,
+                because the clip presence is cached only if enabled */
+                reload_directory();
+            }
+            break;
+    }
+    return action;
+}
+MAKE_SETTING_OPT(talk_menu, NULL);
+MAKE_SETTING_OPT(talk_dir, NULL);
+const struct menu_item_ex talk_file_item =
+{MT_SETTING, {.global_settings_variable = 
+    (void*)&global_settings.talk_file},1,talkfile_callback,0};
+MAKE_MENU(voice_settings_menu,ID2P(LANG_VOICE),0,
+          &talk_menu,&talk_dir,&talk_file_item);
+/*    VOICE MENU                   */
+/***********************************/
+
+/***********************************/
+/*    SYSTEM MENU                  */
+
+/* Battery */
+
+#ifndef SIMULATOR
+MAKE_SETTING_OPT(battery_capacity, NULL);
+MAKE_SETTING_OPT(battery_type, NULL);
+MAKE_MENU(battery_menu, ID2P(LANG_BATTERY_MENU), 0,
+          &battery_capacity,
+#if BATTERY_TYPES_COUNT > 1
+            &battery_type,
+#endif
+         );
+#endif
+
+/* Disk */
+#ifndef HAVE_MMC
+MAKE_SETTING_OPT(disk_spindown, NULL);
+#ifdef HAVE_ATA_POWER_OFF
+MAKE_SETTING_OPT(disk_poweroff, NULL);
+#endif
+#ifdef HAVE_DIRCACHE
+MAKE_SETTING_OPT(dircache, NULL);
+#endif
+MAKE_MENU(disk_menu, ID2P(LANG_DISK_MENU), 0,
+          &disk_spindown,
+#ifdef HAVE_ATA_POWER_OFF
+            &disk_poweroff,
+#endif
+#ifdef HAVE_DIRCACHE
+            &dircache,
+#endif
+         );
+#endif
+
+/* Time & Date */
+#ifdef CONFIG_RTC
+static int timedate_set(void)
+{
+    struct tm tm;
+    int result;
+
+    /* Make a local copy of the time struct */
+    memcpy(&tm, get_time(), sizeof(struct tm));
+
+    /* do some range checks */
+    /* This prevents problems with time/date setting after a power loss */
+    if (!valid_time(&tm))
+    {
+        /* hour   */
+        tm.tm_hour = 0;
+        tm.tm_min = 0;
+        tm.tm_sec = 0;
+        tm.tm_mday = 1;
+        tm.tm_mon = 0;
+        tm.tm_wday = 1;
+        tm.tm_year = 100;
+    }
+
+    result = (int)set_time_screen(str(LANG_TIME), &tm);
+
+    if(tm.tm_year != -1) {
+        set_time(&tm);
+    }
+    return result;
+}
+
+MAKE_FUNCTION_CALL(time_set, ID2P(LANG_TIME), timedate_set, NULL);
+MAKE_SETTING_OPT(timeformat,NULL);
+MAKE_MENU(time_menu, ID2P(LANG_TIME_MENU), 0, &time_set, &timeformat);
+#endif
+
+/* Limits menu */
+MAKE_SETTING_OPT(max_files_in_dir, NULL);
+MAKE_SETTING_OPT(max_files_in_playlist, NULL);
+MAKE_MENU(limits_menu, ID2P(LANG_LIMITS_MENU), 0,
+           &max_files_in_dir, &max_files_in_playlist);
+
+/* System Menu */
+static void sleep_timer_formatter(char* buffer, int buffer_size, int value,
+                                  const char* unit)
+{
+    int minutes, hours;
+
+    (void) unit;
+
+    if (value) {
+        hours = value / 60;
+        minutes = value - (hours * 60);
+        snprintf(buffer, buffer_size, "%d:%02d", hours, minutes);
+    } else {
+        snprintf(buffer, buffer_size, "%s", str(LANG_OFF));
+    }
+}
+
+static void sleep_timer_set(int minutes)
+{
+    set_sleep_timer(minutes * 60);
+}
+
+static int sleep_timer(void)
+{
+    int minutes = (get_sleep_timer() + 59) / 60; /* round up */
+    return (int)set_int(str(LANG_SLEEP_TIMER), "", UNIT_MIN, &minutes,
+                   &sleep_timer_set, 5, 0, 300, sleep_timer_formatter);
+}
+
+/* System menu */
+MAKE_SETTING_OPT(poweroff, NULL);
+MAKE_FUNCTION_CALL(sleep_timer_call, ID2P(LANG_SLEEP_TIMER), sleep_timer, NULL);
+#ifdef HAVE_ALARM_MOD
+MAKE_FUNCTION_CALL(alarm_screen_call, ID2P(LANG_ALARM_MOD_ALARM_MENU),
+                   (menu_function)alarm_screen, NULL);
+#endif
+#if CONFIG_CODEC == MAS3507D
+MAKE_SETTING_OPT(line_in, NULL);
+#endif
+#ifdef CONFIG_CHARGING
+MAKE_SETTING_OPT(car_adapter_mode, NULL);
+#endif
+MAKE_MENU(system_menu, ID2P(LANG_SYSTEM), 0,
+#ifndef SIMULATOR
+            &battery_menu,
+#endif
+#ifndef HAVE_MMC
+            &disk_menu,
+#endif
+#ifdef CONFIG_RTC
+            &time_menu,
+#endif
+            &poweroff,
+            &sleep_timer_call,
+#ifdef HAVE_ALARM_MOD
+            &alarm_screen_call,
+#endif
+            &limits_menu,
+#if CONFIG_CODEC == MAS3507D
+            &line_in,
+#endif
+#ifdef CONFIG_CHARGING
+            &car_adapter_mode,
+#endif
+         );
+
+/*    SYSTEM MENU                  */
+/***********************************/
+
+/***********************************/
+/*    SETTINGS MENU                */
+static int language_browse(void)
+{
+    return (int)rockbox_browse(LANG_DIR, SHOW_LNG);
+}
+MAKE_FUNCTION_CALL(browse_langs, ID2P(LANG_LANGUAGE),language_browse, NULL);
+MAKE_MENU(general_settings_menu,ID2P(LANG_GENERAL_SETTINGS),0,
+          &playback_settings,&file_menu,&display_menu, &system_menu,
+          &bookmark_settings_menu,&browse_langs ,&voice_settings_menu );
+/*    SETTINGS MENU                */
+/***********************************/
+
+
+/***********************************/
+/*      INFO MENU                  */
+MAKE_FUNCTION_CALL(show_info_item, ID2P(LANG_INFO_MENU),
+                   (menu_function)show_info, NULL);
+MAKE_FUNCTION_CALL(show_credits_item, ID2P(LANG_VERSION),
+                   (menu_function)show_credits, NULL);
+
+#ifndef SIMULATOR
+MAKE_FUNCTION_CALL(debug_menu_item, ID2P(LANG_DEBUG),
+                   (menu_function)debug_menu, NULL);
+#else
+MAKE_FUNCTION_CALL(simulate_usb_item, ID2P(LANG_USB),
+                   (menu_function)simulate_usb, NULL);
+#ifdef ROCKBOX_HAS_LOGF
+MAKE_FUNCTION_CALL(logfdisplay_item, "logf",logfdisplay, NULL);
+MAKE_FUNCTION_CALL(logfdump_item, "logfdump",logfdump, NULL);
+#endif
+#endif
+
+MAKE_MENU(info_menu,ID2P(LANG_INFO),0,&show_info_item,&show_credits_item,
+#ifndef SIMULATOR
+         &debug_menu_item
+#else
+         &simulate_usb_item
+#ifdef ROCKBOX_HAS_LOGF
+        ,&logfdisplay_item,&logfdump_item
+#endif
+#endif
+        );
+/*      INFO MENU                  */
+/***********************************/
+
+/***********************************/
+/*    MAIN MENU                    */
+
+static int themes_browse(void)
+{
+    return rockbox_browse(THEME_DIR, SHOW_CFG);
+}
+MAKE_FUNCTION_CALL(browse_themes, ID2P(LANG_CUSTOM_THEME),themes_browse, NULL);
+static int plugin_browse(void)
+{
+    return rockbox_browse(PLUGIN_DIR, SHOW_PLUGINS);
+}
+MAKE_FUNCTION_CALL(browse_plugins, ID2P(LANG_PLUGINS),plugin_browse, NULL);
+#ifdef CONFIG_TUNER
+MAKE_FUNCTION_CALL(load_radio_screen, ID2P(LANG_FM_RADIO),
+                   (menu_function)radio_screen, dynamicitem_callback);
+#endif
+#ifdef HAVE_RECORDING
+MAKE_FUNCTION_CALL(rec_menu_recording_screen_item, 
+                   ID2P(LANG_RECORDING_MENU),recording_screen, NULL);
+MAKE_MENU(rec_menu,ID2P(LANG_RECORDING),0,
+          &rec_menu_recording_screen_item,&recording_settings_menu);
+#endif
+MAKE_FUNCTION_CALL(mrb_bookmarks, ID2P(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS),
+                   (menu_function)bookmark_mrb_load, NULL);
+
+#ifdef HAVE_LCD_CHARCELLS
+static bool do_shutdown(void)
+{
+    sys_poweroff();
+    return false;
+}
+MAKE_FUNCTION_CALL(do_shutdown_item, ID2P(LANG_SHUTDOWN),do_shutdown_item, NULL);
+#endif
+
+MAKE_MENU(main_menu_,ID2P(LANG_MAIN_MENU),0,/*&user_menus,*/&mrb_bookmarks,&sound_settings,
+          &general_settings_menu, &manage_settings, &browse_themes,
+#ifdef CONFIG_TUNER
+          &load_radio_screen,
+#endif
+#ifdef HAVE_RECORDING
+          &rec_menu,
+#endif
+          &playlist_menu,&browse_plugins,&info_menu
+#ifdef HAVE_LCD_CHARCELLS
+         ,&do_shutdown_item
+#endif
+         );
+/*    MAIN MENU                    */
+/***********************************/
+
+/* lazy coders can use this function if the needed callback is just to say if the item is shown or not */
+int dynamicitem_callback(int action,const struct menu_item_ex *this_item)
+{
+    if (action != ACTION_ENTER_MENUITEM)
+        return action;
+#ifdef CONFIG_TUNER
+    if (this_item == &load_radio_screen)
+    {
+        if (radio_hardware_present() == 0)
+            return ACTION_EXIT_MENUITEM;
+    }
+#else
+    (void)this_item;
+#endif
+    return action;
+}
--- /dev/null	2006-10-26 00:03:47.000000000 +1000
+++ apps/menus/playback_menu.c	2006-11-23 18:53:06.000000000 +1100
@@ -0,0 +1,130 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:  $
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "system.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "menu.h"
+#include "action.h"
+#include "mp3_playback.h"
+#include "settings.h"
+#include "statusbar.h"
+#include "screens.h"
+#ifdef HAVE_LCD_BITMAP
+#include "icons.h"
+#include "font.h"
+#endif
+#include "lang.h"
+#include "sprintf.h"
+#include "talk.h"
+#include "misc.h"
+#include "sound.h"
+#ifdef HAVE_RECORDING
+#include "audio.h"
+#include "recording.h"
+#ifdef CONFIG_TUNER
+#include "radio.h"
+#endif
+#endif
+#if CONFIG_CODEC == MAS3587F
+#include "peakmeter.h"
+#include "mas.h"
+#endif
+#include "splash.h"
+#if CONFIG_CODEC == SWCODEC
+#include "dsp.h"
+#include "eq_menu.h"
+#include "pcmbuf.h"
+#endif
+#include "action.h"
+
+/***********************************/
+/*    PLAYBACK MENU                */
+const struct menu_item_ex shuffle_item =
+{MT_SETTING, {.global_settings_variable = 
+    (void*)&global_settings.playlist_shuffle},1,NULL,0};
+MAKE_SETTING_OPT(repeat_mode,NULL);
+MAKE_SETTING_OPT(play_selected,NULL);
+MAKE_SETTING_OPT(resume,NULL);
+
+MAKE_SETTING_OPT(ff_rewind_min_step,NULL);
+MAKE_SETTING_OPT(ff_rewind_accel,NULL);
+MAKE_MENU(ff_rewind_settings_menu,ID2P(LANG_WIND_MENU),0,
+          &ff_rewind_min_step,&ff_rewind_accel);
+
+MAKE_SETTING_OPT(buffer_margin,NULL);
+MAKE_SETTING_OPT(fade_on_stop,NULL);
+MAKE_SETTING_OPT(party_mode,NULL);
+#if CONFIG_CODEC == SWCODEC
+/* crossfade submenu */
+MAKE_SETTING_OPT(crossfade,NULL);
+MAKE_SETTING_OPT(crossfade_fade_in_delay,NULL);
+MAKE_SETTING_OPT(crossfade_fade_in_duration,NULL);
+MAKE_SETTING_OPT(crossfade_fade_out_delay,NULL);
+MAKE_SETTING_OPT(crossfade_fade_out_duration,NULL);
+MAKE_SETTING_OPT(crossfade_fade_out_mixmode,NULL);
+MAKE_MENU(crossfade_settings_menu,ID2P(LANG_CROSSFADE),0,
+          &crossfade,&crossfade_fade_in_delay,&crossfade_fade_in_duration,
+          &crossfade_fade_out_delay,&crossfade_fade_out_duration,
+          &crossfade_fade_out_mixmode);
+
+/* replay gain submenu */
+MAKE_SETTING_OPT(replaygain,NULL);
+MAKE_SETTING_OPT(replaygain_noclip,NULL);
+MAKE_SETTING_OPT(replaygain_type,NULL);
+MAKE_SETTING_OPT(replaygain_preamp,NULL);
+MAKE_MENU(replaygain_settings_menu,ID2P(LANG_REPLAYGAIN),0,
+          &replaygain,&replaygain_noclip,
+          &replaygain_type,&replaygain_preamp);
+          
+MAKE_SETTING_OPT(beep,NULL);
+#endif
+#ifdef HAVE_SPDIF_POWER
+MAKE_SETTING_OPT(spdif_enable,NULL);
+#endif
+MAKE_SETTING_OPT(id3_v1_first,NULL);
+MAKE_SETTING_OPT(next_folder,NULL);
+MAKE_SETTING_OPT(audioscrobbler,NULL);
+#ifdef HAVE_HEADPHONE_DETECTION
+MAKE_SETTING_OPT(unplug_mode,NULL);
+MAKE_SETTING_OPT(unplug_rw,NULL);
+MAKE_SETTING_OPT(unplug_autoresume,NULL);
+MAKE_MENU(unplug_menu, ID2P(LANG_UNPLUG),0,
+          &unplug_mode,&unplug_rw,&unplug_autoresume);
+#endif
+MAKE_MENU(playback_settings,ID2P(LANG_PLAYBACK),0,
+          &shuffle_item,&repeat_mode,&play_selected,&resume,
+          &ff_rewind_settings_menu,
+          &buffer_margin,&fade_on_stop,&party_mode,
+#if CONFIG_CODEC == SWCODEC
+          &crossfade_settings_menu,&replaygain_settings_menu,&beep,
+#endif
+#ifdef HAVE_SPDIF_POWER
+          &spdif_enable,
+#endif
+          &id3_v1_first,&next_folder,&audioscrobbler
+#ifdef HAVE_HEADPHONE_DETECTION
+         ,&unplug_menu
+#endif
+         );
+/*    PLAYBACK MENU                */
+/***********************************/
--- /dev/null	2006-10-26 00:03:47.000000000 +1000
+++ apps/menus/playlist_menu.c	2006-11-23 18:53:06.000000000 +1100
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: playlist_menu.c,v 1.17 2006-07-18 13:54:12 linus Exp $
+ *
+ * Copyright (C) 2002 Bj�n Stenberg
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <string.h>
+
+#include "menu.h"
+#include "file.h"
+#include "keyboard.h"
+#include "playlist.h"
+#include "tree.h"
+#include "settings.h"
+#include "playlist_viewer.h"
+#include "talk.h"
+#include "lang.h"
+#include "playlist_catalog.h"
+
+int save_playlist_screen(struct playlist_info* playlist)
+{
+    char* filename;
+    char temp[MAX_PATH+1];
+    int len;
+
+    filename = playlist_get_name(playlist, temp, sizeof(temp));
+
+    if (!filename || (len=strlen(filename)) <= 4 ||
+        strcasecmp(&filename[len-4], ".m3u"))
+        strcpy(filename, DEFAULT_DYNAMIC_PLAYLIST_NAME);
+
+    if (!kbd_input(filename, sizeof(temp)))
+    {
+        playlist_save(playlist, filename);
+
+        /* reload in case playlist was saved to cwd */
+        reload_directory();
+    }
+
+    return 0;
+}
+
+/***********************************/
+/*    PLAYLIST MENU                */
+static int save_playlist(void)
+{
+    save_playlist_screen(NULL);
+    return 0;
+}
+MAKE_FUNCTION_CALL(create_playlist_item, ID2P(LANG_CREATE_PLAYLIST),
+                   (menu_function)create_playlist, NULL);
+MAKE_FUNCTION_CALL(playlist_viewer_item, ID2P(LANG_VIEW_DYNAMIC_PLAYLIST),
+                   (menu_function)playlist_viewer, NULL);
+MAKE_FUNCTION_CALL(save_playlist_item, ID2P(LANG_SAVE_DYNAMIC_PLAYLIST),
+                   (menu_function)save_playlist, NULL);
+MAKE_FUNCTION_CALL(catalog_view_playlists_item, ID2P(LANG_CATALOG),
+                   (menu_function)catalog_view_playlists, NULL);
+MAKE_SETTING_OPT(recursive_dir_insert, NULL);
+MAKE_SETTING_OPT(warnon_erase_dynplaylist, NULL);
+MAKE_MENU(playlist_menu,ID2P(LANG_PLAYLIST_MENU),0,
+          &create_playlist_item,&playlist_viewer_item,
+          &save_playlist_item,&catalog_view_playlists_item,
+          &recursive_dir_insert,&warnon_erase_dynplaylist);
+
+/*    PLAYLIST MENU                */
+/***********************************/
--- /dev/null	2006-10-26 00:03:47.000000000 +1000
+++ apps/menus/recording_menu.c	2006-11-23 20:19:38.000000000 +1100
@@ -0,0 +1,805 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: sound_menu.c,v 1.117 2006-09-27 21:36:49 mmmm Exp $
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "system.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "menu.h"
+#include "action.h"
+#include "mp3_playback.h"
+#include "settings.h"
+#include "statusbar.h"
+#include "screens.h"
+#ifdef HAVE_LCD_BITMAP
+#include "icons.h"
+#include "font.h"
+/* for trigger menu */
+#include "scrollbar.h"
+#include "peakmeter.h"
+#endif
+#include "lang.h"
+#include "sprintf.h"
+#include "talk.h"
+#include "misc.h"
+#include "sound.h"
+#ifdef HAVE_RECORDING
+#include "audio.h"
+#include "recording.h"
+#ifdef CONFIG_TUNER
+#include "radio.h"
+#endif
+#endif
+#if CONFIG_CODEC == MAS3587F
+#include "mas.h"
+#endif
+#include "splash.h"
+#if CONFIG_CODEC == SWCODEC
+#include "general.h"
+#include "dsp.h"
+#include "eq_menu.h"
+#include "pcmbuf.h"
+#include "enc_config.h"
+#endif
+#include "action.h"
+
+#ifndef MAX_PEAK
+#define MAX_PEAK 0x8000
+#endif
+
+/***********************************/
+/*    RECORDING MENU               */
+int recording_callback(int action,const struct menu_item_ex *this_item);
+
+MAKE_SETTING_OPT(rec_source, recording_callback);
+#if CONFIG_CODEC == MAS3587F
+MAKE_SETTING_OPT(rec_quality, NULL);
+MAKE_SETTING_OPT(rec_frequency, NULL);
+MAKE_SETTING_OPT(rec_channels, NULL);
+MAKE_SETTING_OPT(rec_editable, NULL);
+#elif CONFIG_CODEC == SWCODEC
+static int recformat(void);
+static int recsampr(void);
+static int recchannels(void);
+MAKE_FUNCTION_CALL(recformat_item, ID2P(LANG_RECORDING_FORMAT),
+                   recformat, NULL);
+MAKE_FUNCTION_CALL(enc_config_item, ID2P(LANG_ENCODER_SETTINGS),
+                   enc_global_config_menu, NULL);
+MAKE_FUNCTION_CALL(recsampr_item, ID2P(LANG_RECORDING_FREQUENCY),
+                   recsampr, NULL);
+MAKE_FUNCTION_CALL(recchannels_item, ID2P(LANG_RECORDING_CHANNELS),
+                   recchannels, NULL);
+#endif /* CONFIG_CODEC == */
+
+/* file split options sub menu */
+MAKE_SETTING_OPT(rec_split_method, NULL);
+MAKE_SETTING_OPT(rec_split_type, NULL);
+MAKE_SETTING_OPT(rec_timesplit, NULL);
+MAKE_SETTING_OPT(rec_sizesplit, NULL);
+MAKE_MENU(filesplit_menu,ID2P(LANG_RECORD_TIMESPLIT),0,
+          &rec_split_method,&rec_split_type,
+          &rec_timesplit,&rec_sizesplit);
+          
+MAKE_SETTING_OPT(rec_prerecord_time, NULL);
+MAKE_SETTING_OPT(rec_directory, NULL);
+MAKE_SETTING_OPT(rec_startup, NULL);
+#ifdef CONFIG_BACKLIGHT
+MAKE_SETTING_OPT(cliplight, NULL);
+#endif
+int rectrigger(void);
+MAKE_FUNCTION_CALL(rectrigger_item, ID2P(LANG_RECORD_TRIGGER),rectrigger, NULL);
+#ifdef HAVE_AGC
+MAKE_SETTING_OPT(rec_agc_preset_line, recording_callback);
+MAKE_SETTING_OPT(rec_agc_preset_mic, recording_callback);
+MAKE_SETTING_OPT(rec_agc_cliptime, NULL);
+#endif
+MAKE_MENU(recording_settings_menu,ID2P(LANG_RECORDING_SETTINGS), recording_callback,
+#if CONFIG_CODEC == MAS3587F
+            &rec_quality, &rec_frequency, &rec_source,
+            &rec_channels, &rec_editable,
+#elif CONFIG_CODEC == SWCODEC
+            &recformat_item, &enc_config_item, &recsampr_item,
+            &rec_source, &recchannels_item,
+#endif /* CONFIG_CODEC == */
+            &filesplit_menu,&rec_prerecord_time,&rec_directory,&rec_startup
+#ifdef CONFIG_BACKLIGHT
+            ,&cliplight
+#endif
+#if !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F
+            ,&rectrigger_item
+#endif
+#ifdef HAVE_AGC
+            ,&rec_agc_preset_line,&rec_agc_preset_mic,&rec_agc_cliptime
+#endif
+         );
+
+int recording_callback(int action,const struct menu_item_ex *this_item)
+{
+#ifdef HAVE_FMRADIO_IN
+    static int src;
+#endif
+
+    switch (action)
+    {
+        case ACTION_ENTER_MENUITEM:
+#ifdef HAVE_AGC
+            if (this_item == &rec_agc_preset_line)
+            {
+                if (global_settings.rec_source == AUDIO_SRC_MIC)
+                    return ACTION_EXIT_MENUITEM;
+            }
+            else if (this_item == &rec_agc_preset_mic)
+            {
+                if (global_settings.rec_source != AUDIO_SRC_MIC)
+                    return ACTION_EXIT_MENUITEM;
+            }
+#endif /* HAVE_AGC */
+#ifdef HAVE_FMRADIO_IN
+            if (this_item == &rec_source)
+            {
+                src = global_settings.rec_source;
+                if (in_radio_screen() || !radio_hardware_present())
+                    return ACTION_EXIT_MENUITEM;
+            }
+#endif
+            break;
+        case ACTION_STD_CANCEL: /* exiting the menu */
+#ifdef HAVE_FMRADIO_IN
+            if (this_item == &recording_settings_menu)
+            {
+                if (src != global_settings.rec_source)
+                {
+                    if (src == AUDIO_SRC_FMRADIO)
+                        radio_stop();
+                    /* If AUDIO_SRC_FMRADIO was selected from something else,
+                       the recording screen will start the radio */       
+                }
+            }
+#endif
+            break;
+    }
+
+    return action;
+    (void)this_item;
+}
+
+#if CONFIG_CODEC == SWCODEC
+/* Makes an options list from a source list of options and indexes */
+void make_options_from_indexes(const struct opt_items *src_names,
+                               const long *src_indexes,
+                               int n_indexes,
+                               struct opt_items *dst_names)
+{
+    while (--n_indexes >= 0)
+        dst_names[n_indexes] = src_names[src_indexes[n_indexes]];
+} /* make_options_from_indexes */
+
+static int recformat(void)
+{
+    static const struct opt_items names[REC_NUM_FORMATS] = {
+        [REC_FORMAT_MPA_L3]  = { STR(LANG_AFMT_MPA_L3)  },
+        [REC_FORMAT_WAVPACK] = { STR(LANG_AFMT_WAVPACK) },
+        [REC_FORMAT_PCM_WAV] = { STR(LANG_AFMT_PCM_WAV) },
+    };
+
+    int rec_format = global_settings.rec_format;
+    bool ret = set_option(str(LANG_RECORDING_FORMAT), &rec_format, INT,
+                          names, REC_NUM_FORMATS, NULL );
+
+    if (rec_format != global_settings.rec_format)
+    {
+        global_settings.rec_format = rec_format;
+        enc_global_settings_apply();
+    }
+
+    return (int)ret;
+} /* recformat */
+
+static int recsampr(void)
+{
+    static const struct opt_items names[REC_NUM_FREQ] = {
+        REC_HAVE_96_([REC_FREQ_96] = { "96kHz",     TALK_ID(96, UNIT_KHZ) },)
+        REC_HAVE_88_([REC_FREQ_88] = { "88.2kHz",   TALK_ID(88, UNIT_KHZ) },)
+        REC_HAVE_64_([REC_FREQ_64] = { "64kHz",     TALK_ID(64, UNIT_KHZ) },)
+        REC_HAVE_48_([REC_FREQ_48] = { "48kHz",     TALK_ID(48, UNIT_KHZ) },)
+        REC_HAVE_44_([REC_FREQ_44] = { "44.1kHz",   TALK_ID(44, UNIT_KHZ) },)
+        REC_HAVE_32_([REC_FREQ_32] = { "32kHz",     TALK_ID(32, UNIT_KHZ) },)
+        REC_HAVE_24_([REC_FREQ_24] = { "24kHz",     TALK_ID(24, UNIT_KHZ) },)
+        REC_HAVE_22_([REC_FREQ_22] = { "22.05kHz",  TALK_ID(22, UNIT_KHZ) },)
+        REC_HAVE_16_([REC_FREQ_16] = { "16kHz",     TALK_ID(16, UNIT_KHZ) },)
+        REC_HAVE_12_([REC_FREQ_12] = { "12kHz",     TALK_ID(12, UNIT_KHZ) },)
+        REC_HAVE_11_([REC_FREQ_11] = { "11.025kHz", TALK_ID(11, UNIT_KHZ) },)
+        REC_HAVE_8_( [REC_FREQ_8 ] = { "8kHz",      TALK_ID( 8, UNIT_KHZ) },)
+    };
+
+    struct opt_items opts[REC_NUM_FREQ];
+    unsigned long    table[REC_NUM_FREQ];
+    int              n_opts;
+    int              rec_frequency;
+    bool             ret;
+
+#ifdef HAVE_SPDIF_IN
+    if (global_settings.rec_source == AUDIO_SRC_SPDIF)
+    {
+        /* Inform user that frequency follows the source's frequency */
+        opts[0].string    = ID2P(LANG_SOURCE_FREQUENCY);
+        opts[0].voice_id  = LANG_SOURCE_FREQUENCY;
+        n_opts            = 1;
+        rec_frequency     = 0;
+    }
+    else
+#endif
+    {
+        struct encoder_caps caps;
+        struct encoder_config cfg;
+
+        cfg.rec_format = global_settings.rec_format;
+        global_to_encoder_config(&cfg);
+
+        if (!enc_get_caps(&cfg, &caps, true))
+            return false;
+
+        /* Construct samplerate menu based upon encoder settings */
+        n_opts = make_list_from_caps32(REC_SAMPR_CAPS, NULL,
+                                       caps.samplerate_caps, table);
+
+        if (n_opts == 0)
+            return false; /* No common flags...?? */
+
+        make_options_from_indexes(names, table, n_opts, opts);
+
+        /* Find closest rate that the potentially restricted list
+           comes to */
+        make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
+                              caps.samplerate_caps, table);
+
+        rec_frequency = round_value_to_list32(
+                global_settings.rec_sampr,
+                table, n_opts, false);
+    }
+
+    ret = set_option(str(LANG_RECORDING_FREQUENCY),
+                     &rec_frequency, INT, opts, n_opts, NULL );
+
+    if (!ret HAVE_SPDIF_IN_(&& global_settings.rec_source != AUDIO_SRC_SPDIF))
+    {
+        /* Translate back to real value */
+        global_settings.rec_sampr = table[rec_frequency];
+    }
+
+    return (int)ret;
+} /* recfrequency */
+
+static int recchannels(void)
+{
+    static const struct opt_items names[CHN_NUM_MODES] = {
+        [CHN_MODE_STEREO] = { STR(LANG_CHANNEL_STEREO) },
+        [CHN_MODE_MONO]   = { STR(LANG_CHANNEL_MONO)   }
+    };
+
+    struct opt_items    opts[CHN_NUM_MODES];
+    long                table[CHN_NUM_MODES];
+    struct encoder_caps caps;
+    struct encoder_config cfg;
+    int                 n_opts;
+    int                 rec_channels;
+    bool                 ret;
+
+    cfg.rec_format = global_settings.rec_format;
+    global_to_encoder_config(&cfg);
+
+    if (!enc_get_caps(&cfg, &caps, true))
+        return false;
+
+    n_opts = make_list_from_caps32(CHN_CAP_ALL, NULL,
+                                   caps.channel_caps, table);
+
+    rec_channels = round_value_to_list32(global_settings.rec_channels,
+                                         table, n_opts, false);
+
+    make_options_from_indexes(names, table, n_opts, opts);
+
+    ret = set_option(str(LANG_RECORDING_CHANNELS), &rec_channels,
+                     INT, opts, n_opts, NULL );
+
+    if (!ret)
+        global_settings.rec_channels = table[rec_channels];
+
+    return (int)ret;
+}
+#endif /* CONFIG_CODEC == SWCODEC */
+
+/**
+ * Displays a menu for editing the trigger settings.
+ */
+
+/*
+ * Time strings used for the trigger durations.
+ * Keep synchronous to trigger_times in settings_apply_trigger
+ */
+const char * const trig_durations[TRIG_DURATION_COUNT] =
+{
+    "0s", "1s", "2s", "5s",
+    "10s", "15s", "20s", "25s", "30s",
+    "1min", "2min", "5min", "10min"
+};
+
+void settings_apply_trigger(void)
+{
+    /* Keep synchronous to trig_durations and trig_durations_conf*/
+    static const long trigger_times[TRIG_DURATION_COUNT] = {
+        0, HZ, 2*HZ, 5*HZ,
+        10*HZ, 15*HZ, 20*HZ, 25*HZ, 30*HZ,
+        60*HZ, 2*60*HZ, 5*60*HZ, 10*60*HZ
+    };
+
+    peak_meter_define_trigger(
+        global_settings.rec_start_thres,
+        trigger_times[global_settings.rec_start_duration],
+        MIN(trigger_times[global_settings.rec_start_duration] / 2, 2*HZ),
+        global_settings.rec_stop_thres,
+        trigger_times[global_settings.rec_stop_postrec],
+        trigger_times[global_settings.rec_stop_gap]);
+}
+
+enum trigger_menu_option
+{
+    TRIGGER_MODE,
+    TRIGGER_TYPE,
+    PRERECORD_TIME,
+    START_THRESHOLD,
+    START_DURATION,
+    STOP_THRESHOLD,
+    STOP_POSTREC,
+    STOP_GAP,
+    TRIG_OPTION_COUNT,
+};
+
+static char* create_thres_str(int threshold)
+{
+    static char retval[6];
+    if (threshold < 0) {
+        if (threshold < -88) {
+            snprintf (retval, sizeof retval, "%s", str(LANG_DB_INF));
+        } else {
+            snprintf (retval, sizeof retval, "%ddb", threshold + 1);
+        }
+    } else {
+        snprintf (retval, sizeof retval, "%d%%", threshold);
+    }
+    return retval;
+}
+
+#define INF_DB (-89)
+static void change_threshold(int *threshold, int change)
+{
+    if (global_settings.peak_meter_dbfs) {
+        if (*threshold >= 0) {
+            int db = (calc_db(*threshold * MAX_PEAK / 100) - 9000) / 100;
+            *threshold = db;
+        }
+        *threshold += change;
+        if (*threshold > -1) {
+            *threshold = INF_DB;
+        } else if (*threshold < INF_DB) {
+            *threshold = -1;
+        }
+    } else {
+        if (*threshold < 0) {
+            *threshold = peak_meter_db2sample(*threshold * 100) * 100 / MAX_PEAK;
+        }
+        *threshold += change;
+        if (*threshold > 100) {
+            *threshold = 0;
+        } else if (*threshold < 0) {
+            *threshold = 100;
+        }
+    }
+}
+
+/* Variable button definitions */
+#if CONFIG_KEYPAD == RECORDER_PAD
+#define TRIG_CANCEL BUTTON_OFF
+#define TRIG_ACCEPT BUTTON_PLAY
+#define TRIG_RESET_SIM BUTTON_F2
+
+#elif CONFIG_KEYPAD == ONDIO_PAD
+#define TRIG_CANCEL BUTTON_OFF
+#define TRIG_ACCEPT BUTTON_MENU
+#endif
+
+int rectrigger(void)
+{
+    int exit_request = false;
+    enum trigger_menu_option selected = TRIGGER_MODE;
+    bool retval = false;
+    int old_x_margin[NB_SCREENS];
+    int old_y_margin[NB_SCREENS];
+
+#define TRIGGER_MODE_COUNT 3
+    static const unsigned char *trigger_modes[] = {
+        ID2P(LANG_OFF),
+        ID2P(LANG_RECORD_TRIG_NOREARM),
+        ID2P(LANG_RECORD_TRIG_REARM)
+    };
+
+#define PRERECORD_TIMES_COUNT 31
+    static const unsigned char *prerecord_times[] = {
+        ID2P(LANG_OFF),"1s","2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s",
+        "10s", "11s", "12s", "13s", "14s", "15s", "16s", "17s", "18s", "19s",
+        "20s", "21s", "22s", "23s", "24s", "25s", "26s", "27s", "28s", "29s",
+        "30s"
+    };
+
+#define TRIGGER_TYPE_COUNT 3
+    static const unsigned char *trigger_types[] = {
+        ID2P(LANG_RECORD_TRIGGER_STOP),
+        ID2P(LANG_RECORD_TRIGGER_PAUSE),
+        ID2P(LANG_RECORD_TRIGGER_NEWFILESTP),
+    };
+
+    static const unsigned char *option_name[] = {
+        [TRIGGER_MODE] =    ID2P(LANG_RECORD_TRIGGER_MODE),
+        [TRIGGER_TYPE] =    ID2P(LANG_RECORD_TRIGGER_TYPE),
+        [PRERECORD_TIME] =  ID2P(LANG_RECORD_PRERECORD_TIME),
+        [START_THRESHOLD] = ID2P(LANG_RECORD_START_THRESHOLD),
+        [START_DURATION] =  ID2P(LANG_RECORD_MIN_DURATION),
+        [STOP_THRESHOLD] =  ID2P(LANG_RECORD_STOP_THRESHOLD),
+        [STOP_POSTREC] =    ID2P(LANG_RECORD_STOP_POSTREC),
+        [STOP_GAP] =        ID2P(LANG_RECORD_STOP_GAP)
+    };
+
+    int old_start_thres = global_settings.rec_start_thres;
+    int old_start_duration = global_settings.rec_start_duration;
+    int old_prerecord_time = global_settings.rec_prerecord_time;
+    int old_stop_thres = global_settings.rec_stop_thres;
+    int old_stop_postrec = global_settings.rec_stop_postrec;
+    int old_stop_gap = global_settings.rec_stop_gap;
+    int old_trigger_mode = global_settings.rec_trigger_mode;
+    int old_trigger_type = global_settings.rec_trigger_type;
+
+    int offset[NB_SCREENS];
+    int option_lines[NB_SCREENS];
+    int w, h, i;
+    int stat_height = global_settings.statusbar ? STATUSBAR_HEIGHT : 0;
+    int pm_y[NB_SCREENS];
+
+    int trig_xpos[NB_SCREENS];
+    int trig_ypos[NB_SCREENS];
+    int trig_width[NB_SCREENS];
+
+    FOR_NB_SCREENS(i)
+    {
+        offset[i] = 0;
+        trig_xpos[i] = 0;
+        trig_ypos[i] =  screens[i].height - stat_height - TRIG_HEIGHT;
+        pm_y[i] = screens[i].height - stat_height;
+        trig_width[i] = screens[i].width;
+    }
+
+    /* restart trigger with new values */
+    settings_apply_trigger();
+    peak_meter_trigger (global_settings.rec_trigger_mode != TRIG_MODE_OFF);
+
+    FOR_NB_SCREENS(i)
+    {
+        screens[i].clear_display();
+
+        old_x_margin[i] = screens[i].getxmargin();
+        old_y_margin[i] = screens[i].getymargin();
+        if(global_settings.statusbar)
+           screens[i].setmargins(0, STATUSBAR_HEIGHT);
+      else
+          screens[i].setmargins(0, 0);
+
+      screens[i].getstringsize("M", &w, &h);
+
+      // 16 pixels are reserved for peak meter and trigger status
+      option_lines[i] = MIN(((screens[i].height) -
+                          stat_height - 16)/h,
+                           TRIG_OPTION_COUNT);
+    }
+
+    while (!exit_request) {
+        int button, k;
+        const char *str;
+        char option_value[TRIG_OPTION_COUNT][9];
+
+        snprintf(
+            option_value[TRIGGER_MODE],
+            sizeof option_value[TRIGGER_MODE],
+            "%s",
+            P2STR(trigger_modes[global_settings.rec_trigger_mode]));
+
+        snprintf(
+            option_value[TRIGGER_TYPE],
+            sizeof option_value[TRIGGER_TYPE],
+            "%s",
+            P2STR(trigger_types[global_settings.rec_trigger_type]));
+
+        snprintf(
+            option_value[TRIGGER_TYPE],
+            sizeof option_value[TRIGGER_TYPE],
+            "%s",
+            P2STR(trigger_types[global_settings.rec_trigger_type]));
+
+        snprintf (
+            option_value[PRERECORD_TIME],
+            sizeof option_value[PRERECORD_TIME],
+            "%s",
+            P2STR(prerecord_times[global_settings.rec_prerecord_time]));
+
+        /* due to value range shift (peak_meter_define_trigger) -1 is 0db */
+        if (global_settings.rec_start_thres == -1) {
+            str = str(LANG_OFF);
+        } else {
+            str = create_thres_str(global_settings.rec_start_thres);
+        }
+        snprintf(
+            option_value[START_THRESHOLD],
+            sizeof option_value[START_THRESHOLD],
+            "%s",
+            str);
+
+        snprintf(
+            option_value[START_DURATION],
+            sizeof option_value[START_DURATION],
+            "%s",
+            trig_durations[global_settings.rec_start_duration]);
+
+
+        if (global_settings.rec_stop_thres <= INF_DB) {
+            str = str(LANG_OFF);
+        } else {
+            str = create_thres_str(global_settings.rec_stop_thres);
+        }
+        snprintf(
+            option_value[STOP_THRESHOLD],
+            sizeof option_value[STOP_THRESHOLD],
+            "%s",
+            str);
+
+        snprintf(
+            option_value[STOP_POSTREC],
+            sizeof option_value[STOP_POSTREC],
+            "%s",
+            trig_durations[global_settings.rec_stop_postrec]);
+
+        snprintf(
+            option_value[STOP_GAP],
+            sizeof option_value[STOP_GAP],
+            "%s",
+            trig_durations[global_settings.rec_stop_gap]);
+
+        FOR_NB_SCREENS(i)
+        {
+            screens[i].set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+            screens[i].fillrect(0, stat_height, screens[i].width,
+                                   screens[i].height - stat_height);
+            screens[i].set_drawmode(DRMODE_SOLID);
+        }
+
+        gui_syncstatusbar_draw(&statusbars, true);
+
+        /* reselect FONT_SYSFONT as status_draw has changed the font */
+        /*lcd_setfont(FONT_SYSFIXED);*/
+
+        FOR_NB_SCREENS(i)
+        {
+            for (k = 0; k < option_lines[i]; k++) {
+                int x, y;
+
+                str = P2STR(option_name[k + offset[i]]);
+                screens[i].putsxy((option_lines[i] < TRIG_OPTION_COUNT) ? 5 : 0,
+                                       stat_height + k * h, str);
+
+                str = option_value[k + offset[i]];
+                screens[i].getstringsize(str, &w, &h);
+                y = stat_height + k * h;
+                x = screens[i].width - w;
+                screens[i].putsxy(x, y, str);
+                if ((int)selected == (k + offset[i])) {
+                    screens[i].set_drawmode(DRMODE_COMPLEMENT);
+                    screens[i].fillrect(x, y, w, h);
+                    screens[i].set_drawmode(DRMODE_SOLID);
+                }
+            }
+            if (option_lines[i] < TRIG_OPTION_COUNT)
+                gui_scrollbar_draw(&screens[i], 0, stat_height,
+                    4, screens[i].height - 16 - stat_height,
+                    TRIG_OPTION_COUNT, offset[i], offset[i] + option_lines[i],
+                    VERTICAL);
+        }
+
+        peak_meter_draw_trig(trig_xpos, trig_ypos, trig_width, NB_SCREENS);
+        button = peak_meter_draw_get_btn(0, pm_y, 8, NB_SCREENS);
+
+        FOR_NB_SCREENS(i)
+            screens[i].update();
+
+        switch (button) {
+            case ACTION_STD_CANCEL:
+                gui_syncsplash(50, true, str(LANG_MENU_SETTING_CANCEL));
+                global_settings.rec_start_thres = old_start_thres;
+                global_settings.rec_start_duration = old_start_duration;
+                global_settings.rec_prerecord_time = old_prerecord_time;
+                global_settings.rec_stop_thres = old_stop_thres;
+                global_settings.rec_stop_postrec = old_stop_postrec;
+                global_settings.rec_stop_gap = old_stop_gap;
+                global_settings.rec_trigger_mode = old_trigger_mode;
+                global_settings.rec_trigger_type = old_trigger_type;
+                exit_request = true;
+                break;
+
+            case ACTION_REC_PAUSE:
+                exit_request = true;
+                break;
+
+            case ACTION_STD_PREV:
+                selected += TRIG_OPTION_COUNT - 1;
+                selected %= TRIG_OPTION_COUNT;
+                FOR_NB_SCREENS(i)
+                {
+                    offset[i] = MIN(offset[i], (int)selected);
+                    offset[i] = MAX(offset[i], (int)selected - option_lines[i] + 1);
+                }
+                break;
+
+            case ACTION_STD_NEXT:
+                selected ++;
+                selected %= TRIG_OPTION_COUNT;
+                FOR_NB_SCREENS(i)
+                {
+                    offset[i] = MIN(offset[i], (int)selected);
+                    offset[i] = MAX(offset[i], (int)selected - option_lines[i] + 1);
+                }
+                break;
+
+            case ACTION_SETTINGS_INC:
+                switch (selected) {
+                    case TRIGGER_MODE:
+                        global_settings.rec_trigger_mode ++;
+                        global_settings.rec_trigger_mode %= TRIGGER_MODE_COUNT;
+                        break;
+
+                    case TRIGGER_TYPE:
+                        global_settings.rec_trigger_type ++;
+                        global_settings.rec_trigger_type %= TRIGGER_TYPE_COUNT;
+                        break;
+
+                    case PRERECORD_TIME:
+                        global_settings.rec_prerecord_time ++;
+                        global_settings.rec_prerecord_time %= PRERECORD_TIMES_COUNT;
+                        break;
+
+                    case START_THRESHOLD:
+                        change_threshold(&global_settings.rec_start_thres, 1);
+                        break;
+
+                    case START_DURATION:
+                        global_settings.rec_start_duration ++;
+                        global_settings.rec_start_duration %= TRIG_DURATION_COUNT;
+                        break;
+
+                    case STOP_THRESHOLD:
+                        change_threshold(&global_settings.rec_stop_thres, 1);
+                        break;
+
+                    case STOP_POSTREC:
+                        global_settings.rec_stop_postrec ++;
+                        global_settings.rec_stop_postrec %= TRIG_DURATION_COUNT;
+                        break;
+
+                    case STOP_GAP:
+                        global_settings.rec_stop_gap ++;
+                        global_settings.rec_stop_gap %= TRIG_DURATION_COUNT;
+                        break;
+
+                    case TRIG_OPTION_COUNT:
+                        // avoid compiler warnings
+                        break;
+                }
+                peak_meter_trigger(global_settings.rec_trigger_mode!=TRIG_OFF);
+                settings_apply_trigger();
+                break;
+
+            case ACTION_SETTINGS_DEC:
+                switch (selected) {
+                    case TRIGGER_MODE:
+                        global_settings.rec_trigger_mode+=TRIGGER_MODE_COUNT-1;
+                        global_settings.rec_trigger_mode %= TRIGGER_MODE_COUNT;
+                        break;
+
+                    case TRIGGER_TYPE:
+                        global_settings.rec_trigger_type+=TRIGGER_TYPE_COUNT-1;
+                        global_settings.rec_trigger_type %= TRIGGER_TYPE_COUNT;
+                        break;
+
+                    case PRERECORD_TIME:
+                        global_settings.rec_prerecord_time += PRERECORD_TIMES_COUNT - 1;
+                        global_settings.rec_prerecord_time %= PRERECORD_TIMES_COUNT;
+                        break;
+
+                    case START_THRESHOLD:
+                        change_threshold(&global_settings.rec_start_thres, -1);
+                        break;
+
+                    case START_DURATION:
+                        global_settings.rec_start_duration += TRIG_DURATION_COUNT-1;
+                        global_settings.rec_start_duration %= TRIG_DURATION_COUNT;
+                        break;
+
+                    case STOP_THRESHOLD:
+                        change_threshold(&global_settings.rec_stop_thres, -1);
+                        break;
+
+                    case STOP_POSTREC:
+                        global_settings.rec_stop_postrec +=
+                            TRIG_DURATION_COUNT - 1;
+                        global_settings.rec_stop_postrec %=
+                            TRIG_DURATION_COUNT;
+                        break;
+
+                    case STOP_GAP:
+                        global_settings.rec_stop_gap +=
+                            TRIG_DURATION_COUNT - 1;
+                        global_settings.rec_stop_gap %= TRIG_DURATION_COUNT;
+                        break;
+
+                    case TRIG_OPTION_COUNT:
+                        // avoid compiler warnings
+                        break;
+                }
+                peak_meter_trigger(global_settings.rec_trigger_mode!=TRIG_OFF);
+                settings_apply_trigger();
+                break;
+
+            case ACTION_REC_F2:
+                peak_meter_trigger(true);
+                break;
+
+            case SYS_USB_CONNECTED:
+                if(default_event_handler(button) == SYS_USB_CONNECTED) {
+                    retval = true;
+                    exit_request = true;
+                }
+                break;
+        }
+    }
+
+    peak_meter_trigger(false);
+    FOR_NB_SCREENS(i)
+    {
+        screens[i].setfont(FONT_UI);
+        screens[i].setmargins(old_x_margin[i], old_y_margin[i]);
+    }
+    action_signalscreenchange();
+    return (int)retval;
+}
+
+/*    RECORDING MENU               */
+/***********************************/
+
+bool recording_menu(void)
+{
+    return do_menu(&recording_settings_menu);
+}
+
--- /dev/null	2006-10-26 00:03:47.000000000 +1000
+++ apps/menus/sound_menu.c	2006-11-23 20:20:52.000000000 +1100
@@ -0,0 +1,122 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:  $
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "system.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "menu.h"
+#include "action.h"
+#include "mp3_playback.h"
+#include "settings.h"
+#include "statusbar.h"
+#include "screens.h"
+#ifdef HAVE_LCD_BITMAP
+#include "icons.h"
+#include "font.h"
+#endif
+#include "lang.h"
+#include "sprintf.h"
+#include "talk.h"
+#include "misc.h"
+#include "sound.h"
+#ifdef HAVE_RECORDING
+#include "audio.h"
+#include "recording.h"
+#ifdef CONFIG_TUNER
+#include "radio.h"
+#endif
+#endif
+#if CONFIG_CODEC == MAS3587F
+#include "peakmeter.h"
+#include "mas.h"
+#endif
+#include "splash.h"
+#if CONFIG_CODEC == SWCODEC
+#include "dsp.h"
+#include "eq_menu.h"
+#include "pcmbuf.h"
+#endif
+#include "action.h"
+#include "debug.h"
+/***********************************/
+/*    SOUND MENU                   */
+#if CONFIG_CODEC == SWCODEC
+int soundmenu_callback(int action,const struct menu_item_ex *this_item)
+{
+    (void)this_item;
+    switch (action)
+    {
+        case ACTION_ENTER_MENUITEM: /* on entering */
+            pcmbuf_set_low_latency(true);
+            break;
+        case ACTION_STD_CANCEL: /* on exit */
+            pcmbuf_set_low_latency(false);
+            break;
+    }
+    return action;
+}
+#else
+#define soundmenu_callback NULL
+#endif
+
+MAKE_SETTING_OPT(volume,NULL);
+#ifndef HAVE_TLV320
+MAKE_SETTING_OPT(bass,NULL);
+MAKE_SETTING_OPT(treble,NULL);
+#endif
+MAKE_SETTING_OPT(balance,NULL);
+MAKE_SETTING_OPT(channel_config,NULL);
+static MAKE_SETTING_OPT(stereo_width,NULL);
+#if CONFIG_CODEC == SWCODEC
+MAKE_SETTING_OPT(crossfeed,NULL);
+MAKE_SETTING_OPT(crossfeed_direct_gain,NULL);
+MAKE_SETTING_OPT(crossfeed_cross_gain,NULL);
+MAKE_SETTING_OPT(crossfeed_hf_attenuation,NULL);
+MAKE_SETTING_OPT(crossfeed_hf_cutoff,NULL);
+MAKE_MENU(crossfeed_menu,ID2P(LANG_CROSSFEED),NULL,
+          &crossfeed, &crossfeed_direct_gain, &crossfeed_cross_gain,
+          &crossfeed_hf_attenuation, &crossfeed_hf_cutoff);
+MAKE_FUNCTION_CALL(equalizer_menu,ID2P(LANG_EQUALIZER),eq_menu, NULL);
+MAKE_SETTING_OPT(dithering_enabled,NULL);
+#ifdef HAVE_WM8758
+MAKE_FUNCTION_CALL(hw_equalizer_menu,ID2P(LANG_EQUALIZER_HARDWARE),eq_hw_menu, NULL);
+#endif
+#endif
+MAKE_MENU(sound_settings,ID2P(LANG_SOUND_SETTINGS),soundmenu_callback,&volume,
+#ifndef HAVE_TLV320
+&bass,&treble,
+#endif
+&balance,&channel_config,&stereo_width
+#if CONFIG_CODEC == SWCODEC
+         ,&crossfeed_menu, &equalizer_menu,&dithering_enabled
+#endif
+#ifdef HAVE_WM8758
+,&hw_equalizer_menu
+#endif
+         );
+/*    SOUND MENU                   */
+/***********************************/
+
+bool sound_menu(void)
+{
+    return do_menu(&sound_settings);
+}
--- /dev/null	2006-10-26 00:03:47.000000000 +1000
+++ apps/menus/exported_menus.h	2006-11-23 18:53:06.000000000 +1100
@@ -0,0 +1,45 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _EXPORTED_MENUS_H
+#define _EXPORTED_MENUS_H
+
+#include "menu.h"
+/* not needed for plugins and just causes compile error, possibly fix proberly later */
+#ifndef PLUGIN 
+#include "playlist.h"
+
+int main_menu(void);        /* apps/menu.c      */
+bool recording_menu(void);  /* recording_menu.c */
+bool sound_menu(void);      /* sound_menu.c     */
+bool set_sound(const unsigned char * string, 
+               int* variable, int setting);               /* sound_menu.c */
+int save_playlist_screen(struct playlist_info* playlist); /* playlist_menu.c */
+
+extern const struct menu_item_ex 
+        main_menu_,                 /* main_menu.c      */
+        display_menu,               /* display_menu.c   */
+        playback_settings,          /* playback_menu.c  */
+        recording_settings_menu,    /* recording_menu.c */
+        sound_settings,             /* sound_menu.c     */
+        playlist_menu;              /* playlist_menu.c  */
+
+
+
+#endif
+#endif /*_EXPORTED_MENUS_H */
