Index: apps/settings.c
===================================================================
--- apps/settings.c	(revision 13624)
+++ apps/settings.c	(working copy)
@@ -961,51 +961,6 @@
         talk_id(setting->lang_id,false);
 }
 
-static int selected_setting; /* Used by the callback */
-
-static 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 = abs(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)
-        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 );
-    }
-}
-
 bool set_bool(const char* string, bool* variable )
 {
     return set_bool_options(string, variable,
@@ -1014,15 +969,6 @@
                             NULL);
 }
 
-/* wrapper to convert from int param to bool param in set_option */
-static void (*boolfunction)(bool);
-static 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,
@@ -1035,237 +981,11 @@
     };
     bool result;
 
-    boolfunction = function;
     result = set_option(string, variable, BOOL, names, 2,
-                        function ? bool_funcwrapper : NULL);
+                        (void (*)(int))function);
     return result;
 }
 
-static void talk_unit(int unit, int value, long (*get_talk_id)(int value))
-{
-    if (talk_menus_enabled())
-    {
-        if (get_talk_id)
-        {
-            talk_id(get_talk_id(value),false);
-        }
-        else 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 value, const char* unit);
-    long (*get_talk_id)(int value);
-    /* used for BOOL and "choice" settings */
-    struct opt_items* options;
-};
-
-static 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))
-static 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,Icon_Questionmark);
-    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 (talk_menus_enabled())
-    {
-        if (cb_data->type == INT && !cb_data->options)
-            talk_unit(cb_data->voice_unit, *(int*)variable, cb_data->get_talk_id);
-        else 
-            talk_id(cb_data->options[selected].voice_id, false);
-    }
-
-    gui_synclist_draw(&lists);
-    action_signalscreenchange();
-    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 (talk_menus_enabled())
-            {
-                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, cb_data->get_talk_id);
-                }
-                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)
-        {
-            if (cb_data->type == INT)
-            {
-                if (*(int*)variable != oldvalue)
-                {
-                    gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL));
-                    *(int*)variable = oldvalue;
-                }
-            }
-            else
-            {
-                if (*(bool*)variable != (bool)oldvalue)
-                {
-                    gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL));
-                    *(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));
-    }
-    if (cb_data->type == INT)
-    {
-        if (oldvalue != *(int*)variable)
-            settings_save();
-    }
-    else if (oldvalue != *(bool*)variable)
-         settings_save();
-
-    action_signalscreenchange();
-    return false;
-}
-static const char *unit_strings[] = 
-{   
-    [UNIT_INT]
-        = "",
-    [UNIT_MS]
-        = "ms",
-    [UNIT_SEC]
-        = "s", 
-    [UNIT_MIN]
-        = "min", 
-    [UNIT_HOUR]
-        = "hr", 
-    [UNIT_KHZ]
-        = "KHz", 
-    [UNIT_DB]
-        = "dB", 
-    [UNIT_PERCENT]
-        = "%",
-    [UNIT_MAH]
-        = "mAh",
-    [UNIT_PIXEL]
-        = "px",
-    [UNIT_PER_SEC]
-        = "per sec",
-    [UNIT_HERTZ]
-        = "Hz",
-    [UNIT_MB]
-        = "MB",
-    [UNIT_KBIT]
-        = "kb/s",
-};
-bool set_int_ex(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*),
-             long (*get_talk_id)(int))
-{
-    int count = (max-min)/step + 1;
-#if CONFIG_KEYPAD != PLAYER_PAD
-    struct value_setting_data data = {
-        INT,max, step, voice_unit,unit,formatter,get_talk_id,NULL };
-    if (voice_unit < UNIT_LAST)
-        data.unit = unit_strings[voice_unit];
-    else 
-        data.unit = str(voice_unit);
-    return do_set_setting(string,variable,count,
-                          (max-*variable)/step, &data,function);
-#else
-    struct value_setting_data data = {
-        INT,min, -step, voice_unit,unit,formatter,get_talk_id,NULL };
-    if (voice_unit < UNIT_LAST)
-        data.unit = unit_strings[voice_unit];
-    else 
-        data.unit = str(voice_unit);
-    return do_set_setting(string,variable,count,
-                          (*variable-min)/step, &data,function);
-#endif
-}
 bool set_int(const unsigned char* string,
              const char* unit,
              int voice_unit,
@@ -1279,25 +999,7 @@
     return set_int_ex(string, unit, voice_unit, variable, function,
                       step, min, max, formatter, NULL);
 }
-/* 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,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);
-}
 
 /** extra stuff which is probably misplaced **/
 
Index: apps/plugins/lib/playback_control.c
===================================================================
--- apps/plugins/lib/playback_control.c	(revision 13624)
+++ apps/plugins/lib/playback_control.c	(working copy)
@@ -59,44 +59,31 @@
 
 static bool volume(void)
 {
-    return api->set_sound("Volume", &api->global_settings->volume,
-                          SOUND_VOLUME);
+    const struct settings_list* vol = 
+            api->find_setting(&api->global_settings->volume, NULL);
+    return api->option_screen((struct settings_list*)vol, false);
 }
 
 static bool shuffle(void)
 {
-    struct opt_items names[] = {
-        { "No", -1 },
-        { "Yes", -1 }
-    };
-    return api->set_option("Shuffle", &api->global_settings->playlist_shuffle,
-                           BOOL, names, 2,NULL);
+    const struct settings_list* shuffle = 
+            api->find_setting(&api->global_settings->playlist_shuffle, NULL);
+    return api->option_screen((struct settings_list*)shuffle, false);
 }
 
 static bool repeat_mode(void)
 {
-    bool result;
-    static const struct opt_items names[] = {
-        { "Off", -1 },
-        { "Repeat All", -1 },
-        { "Repeat One", -1 },
-        { "Repeat Shuffle", -1 },
-#ifdef AB_REPEAT_ENABLE
-        { "Repeat A-B", -1 }
-#endif
-    };
-    
+    const struct settings_list* repeat = 
+            api->find_setting(&api->global_settings->repeat_mode, NULL);
     int old_repeat = api->global_settings->repeat_mode;
 
-    result = api->set_option( "Repeat Mode",
-                              &api->global_settings->repeat_mode,
-                              INT, names, NUM_REPEAT_MODES, NULL );
+    api->option_screen((struct settings_list*)repeat, false);
 
     if (old_repeat != api->global_settings->repeat_mode &&
         (api->audio_status() & AUDIO_STATUS_PLAY))
         api->audio_flush_and_reload_tracks();
 
-    return result;
+    return false;
 }
 MENUITEM_FUNCTION(prevtrack_item, 0, "Previous Track",
                   prevtrack, NULL, NULL, Icon_NOICON);
Index: apps/gui/option_select.c
===================================================================
--- apps/gui/option_select.c	(revision 13624)
+++ apps/gui/option_select.c	(working copy)
@@ -8,6 +8,7 @@
  * $Id$
  *
  * Copyright (C) 2005 by Kevin Ferrare
+ * Copyright (C) 2007 by 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.
@@ -16,12 +17,496 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-
+#include <stdlib.h>
+#include "config.h"
 #include "option_select.h"
 #include "sprintf.h"
 #include "kernel.h"
 #include "lang.h"
+#include "talk.h"
+#include "settings_list.h"
+#include "sound.h"
+#include "list.h"
+#include "action.h"
+#include "statusbar.h"
+#include "misc.h"
+#include "splash.h"
 
+static const char *unit_strings[] = 
+{   
+    [UNIT_INT] = "",    [UNIT_MS]  = "ms",
+    [UNIT_SEC] = "s",   [UNIT_MIN] = "min", 
+    [UNIT_HOUR]= "hr",  [UNIT_KHZ] = "KHz", 
+    [UNIT_DB]  = "dB",  [UNIT_PERCENT] = "%",
+    [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
+    [UNIT_PER_SEC] = "per sec",
+    [UNIT_HERTZ] = "Hz",
+    [UNIT_MB]  = "MB",  [UNIT_KBIT]  = "kb/s",
+};
+
+char *option_get_valuestring(struct settings_list *setting, 
+                             char *buffer, int buf_len,
+                             intptr_t temp_var)
+{
+    if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
+    {
+        bool val = (bool)temp_var;
+        snprintf(buffer, buf_len, "%s", 
+            str(val? setting->bool_setting->lang_yes :
+                     setting->bool_setting->lang_no));
+    }
+#if 0 /* probably dont need this one */
+    else if ((setting->flags & F_FILENAME) == F_FILENAME)
+    {
+        struct filename_setting *info = setting->filename_setting;
+        snprintf(buffer, buf_len, "%s%s%s", info->prefix,
+                 (char*)temp_var, info->suffix);
+    }
+#endif
+    else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
+    {
+        struct int_setting *info = setting->int_setting;
+        if (info->formatter)
+            info->formatter(buffer, buf_len, (int)temp_var,
+                            unit_strings[info->unit]);
+        else
+            snprintf(buffer, buf_len, "%d %s", (int)temp_var,
+                     unit_strings[info->unit]?
+                             unit_strings[info->unit]:"");
+    }
+    else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
+    {
+        char sign = ' ', *unit;
+        unit = (char*)sound_unit(setting->sound_setting->setting);
+        if (sound_numdecimals(setting->sound_setting->setting))
+        {
+            int integer, dec;
+            int val = sound_val2phys(setting->sound_setting->setting,
+                                 (int)temp_var);
+            if(val < 0)
+            {
+                sign = '-';
+                val = abs(val);
+            }
+            integer = val / 10; dec = val % 10;
+            snprintf(buffer, buf_len, "%c%d.%d %s", sign, integer, dec, unit);
+        }
+        else
+            snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit);
+    }
+    else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
+    {
+        if (setting->flags & F_CHOICETALKS)
+        {
+            int setting_id;
+            find_setting(setting->setting, &setting_id);
+            cfg_int_to_string(setting_id, (int)temp_var, buffer, buf_len);
+        }
+        else
+        {
+            int value= (int)temp_var;
+            char *val = P2STR(setting->choice_setting->desc[value]);
+            snprintf(buffer, buf_len, "%s", val);
+        }
+    }
+    return buffer;
+}
+
+void option_talk(struct settings_list *setting, int temp_var)
+{
+    if (!talk_menus_enabled())
+        return;
+    if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
+    {
+        bool val = temp_var==1?true:false;
+        talk_id(val? setting->bool_setting->lang_yes :
+                setting->bool_setting->lang_no, false);
+    }
+#if 0 /* probably dont need this one */
+    else if ((setting->flags & F_FILENAME) == F_FILENAME)
+    {
+    }
+#endif
+    else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
+    {
+        struct int_setting *info = setting->int_setting;
+        if (info->get_talk_id)
+            talk_id(info->get_talk_id((int)temp_var), false);
+        else 
+            talk_value((int)temp_var, info->unit, false);
+    }
+    else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
+    {
+        int talkunit = UNIT_DB;
+        const char *unit = sound_unit(setting->sound_setting->setting);
+        /* crude reconstruction */
+        if (*unit == '%')
+            talkunit = UNIT_PERCENT;
+        else if (*unit == 'H')
+            talkunit = UNIT_HERTZ;
+        talk_value((int)temp_var, talkunit, false);
+    }
+    else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
+    {
+        int value = (int)temp_var;
+        if (setting->flags & F_CHOICETALKS)
+        {
+            talk_id(setting->choice_setting->talks[value], false);
+        }
+        else
+        {
+            talk_id(P2ID(setting->choice_setting->desc[value]), false);
+        }
+    }
+}
+#if 0
+int option_select_next_val(struct settings_list *setting,
+                           intptr_t temp_var)
+{
+    int val = 0;
+    if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
+    {
+        val = (bool)temp_var ? 0 : 1;
+    }
+    else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
+    {
+        struct int_setting *info = setting->int_setting;
+        val = (int)temp_var + info->step;
+        if (val > info->max)
+            val = info->min;
+    }
+    else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
+    {
+        int setting_id = setting->sound_setting->setting;
+        int steps = sound_steps(setting_id);
+        int min = sound_min(setting_id);
+        int max = sound_max(setting_id);
+        val = (int)temp_var + steps;
+        if (val > max)
+            val = min;
+    }
+    else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
+    {
+        struct choice_setting *info = setting->choice_setting;
+        val = (int)temp_var;
+        if (val > info->count)
+            val = 0;
+    }
+    return val;
+}
+
+int option_select_prev_val(struct settings_list *setting,
+                           intptr_t temp_var)
+{
+    int val = 0;
+    if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
+    {
+        val = (bool)temp_var ? 0 : 1;
+    }
+    else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
+    {
+        struct int_setting *info = setting->int_setting;
+        val = (int)temp_var - info->step;
+        if (val < info->min)
+            val = info->max;
+    }
+    else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
+    {
+        int setting_id = setting->sound_setting->setting;
+        int steps = sound_steps(setting_id);
+        int min = sound_min(setting_id);
+        int max = sound_max(setting_id);
+        val = (int)temp_var -+ steps;
+        if (val < min)
+            val = max;
+    }
+    else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
+    {
+        struct choice_setting *info = setting->choice_setting;
+        val = (int)temp_var;
+        if (val < 0)
+            val = info->count - 1;
+    }
+    return val;
+}
+#endif
+
+static int selection_to_val(struct settings_list *setting, int selection)
+{
+    int min = 0, max = 0, step = 1;
+    if (((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) ||
+          ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING))
+        return selection;
+    else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
+    {
+        int setting_id = setting->sound_setting->setting;
+        step = sound_steps(setting_id);
+        max = sound_max(setting_id);
+        min = sound_min(setting_id);
+    }
+    else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
+    {
+        struct int_setting *info = setting->int_setting;
+        min = info->min;
+        max = info->max;
+        step = info->step;
+    }
+    if (setting->flags & F_FLIPLIST)
+    {
+        int a;
+        a = min; min = max; max = a;
+        step = -step;
+    }
+    return max- (selection * step);
+}
+static char * value_setting_get_name_cb(int selected_item, 
+                                        void * data, char *buffer)
+{
+    selected_item = selection_to_val(data, selected_item);
+    return option_get_valuestring(data, buffer, MAX_PATH, selected_item);
+}
+
+/* wrapper to convert from int param to bool param in option_screen */
+static void (*boolfunction)(bool);
+static void bool_funcwrapper(int value)
+{
+    if (value)
+        boolfunction(true);
+    else
+        boolfunction(false);
+}
+
+bool option_screen(struct settings_list *setting, bool use_temp_var)
+{
+    int action;
+    bool done = false;
+    struct gui_synclist lists;
+    int oldvalue, nb_items = 0, selected = 0, temp_var;
+    int *variable;
+    bool allow_wrap = ((int*)setting->setting != &global_settings.volume);
+    int var_type = setting->flags&F_T_MASK;
+    void (*function)(int) = NULL;
+    
+    if (var_type == F_T_INT || var_type == F_T_UINT)
+    {
+        variable = use_temp_var ? &temp_var: (int*)setting->setting;
+        temp_var = oldvalue = *(int*)setting->setting;
+    }
+    else if (var_type == F_T_BOOL)
+    {
+        /* bools always use the temp variable...
+        if use_temp_var is false it will be copied to setting->setting every change */
+        variable = &temp_var;
+        temp_var = oldvalue = *(bool*)setting->setting?1:0;
+    }
+    else return false; /* only int/bools can go here */
+    gui_synclist_init(&lists, value_setting_get_name_cb, 
+                      (void*)setting, false, 1);
+    if (setting->lang_id == -1)
+        gui_synclist_set_title(&lists, 
+                                (char*)setting->cfg_vals, Icon_Questionmark);
+    else
+        gui_synclist_set_title(&lists, 
+                                str(setting->lang_id), Icon_Questionmark);
+    gui_synclist_set_icon_callback(&lists, NULL);
+    
+    /* set the number of items and current selection */
+    if (var_type == F_T_INT || var_type == F_T_UINT)
+    {
+        if (setting->flags&F_CHOICE_SETTING)
+        {
+            nb_items = setting->choice_setting->count;
+            selected = oldvalue;
+            function = setting->choice_setting->option_callback;
+        }
+        else if (setting->flags&F_T_SOUND)
+        {
+            int setting_id = setting->sound_setting->setting;
+            int steps = sound_steps(setting_id);
+            int min = sound_min(setting_id);
+            int max = sound_max(setting_id);
+            nb_items = (max-min)/steps + 1;
+            selected = (max-oldvalue)/steps;
+            function = sound_get_fn(setting_id);
+        }
+        else
+        {
+            struct int_setting *info = setting->int_setting;
+            int min, max, step;
+            if (setting->flags&F_FLIPLIST)
+            {
+                min = info->max;
+                max = info->min;
+                step = -info->step;
+            }
+            else
+            {
+                max = info->max;
+                min = info->min;
+                step = info->step;
+            }
+            nb_items = (max-min)/step + 1;
+            selected = (max - oldvalue)/step;
+            function = info->option_callback;
+        }
+    }
+    else if (var_type == F_T_BOOL)
+    {
+        selected = oldvalue;
+        nb_items = 2;
+        boolfunction = setting->bool_setting->option_callback;
+        if (boolfunction)
+            function = bool_funcwrapper;
+    }
+    
+    gui_synclist_set_nb_items(&lists, nb_items);
+    gui_synclist_select_item(&lists, selected);
+    
+    gui_synclist_limit_scroll(&lists, true);
+    gui_synclist_draw(&lists);
+    action_signalscreenchange();
+    /* talk the item */
+    option_talk(setting, *variable);
+    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))
+        {
+            selected = gui_synclist_get_sel_pos(&lists);
+            *variable = selection_to_val(setting, selected);
+            if (var_type == F_T_BOOL)
+            {
+                if (!use_temp_var)
+                    *(bool*)setting->setting = selected==1?true:false;
+            }
+            /* talk */
+            option_talk(setting, *variable);
+        }
+        else if (action == ACTION_STD_CANCEL)
+        {
+            bool show_cancel = false;
+            if (use_temp_var)
+                show_cancel = true;
+            else if (var_type == F_T_INT || var_type == F_T_UINT)
+            {
+                if (*variable != oldvalue)
+                {
+                    show_cancel = true;
+                    *variable = oldvalue;
+                }
+            }
+            else
+            {
+                if (*variable != oldvalue)
+                {
+                    show_cancel = true;
+                    if (!use_temp_var)
+                        *(bool*)setting->setting = oldvalue==1?true:false;
+                    *variable = oldvalue;
+                }
+            }
+            if (show_cancel)
+                gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL));
+            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);
+        /* callback */
+        if ( function )
+            function(*variable);
+    }
+    
+    if (use_temp_var)
+    {
+        if (var_type == F_T_INT || var_type == F_T_UINT)
+        {
+            if (oldvalue != *variable)
+            {
+                *(int*)setting->setting = *variable;
+                settings_save();
+            }
+        }
+        else if (oldvalue != *variable)
+        {
+            *(bool*)setting->setting = *variable?true:false;
+            settings_save();
+        }
+    }
+
+    action_signalscreenchange();
+    return false;
+}
+
+/******************************************************
+    Compatability functions 
+*******************************************************/
+#define MAX_OPTIONS 32
+bool set_option(const char* string, void* variable, enum optiontype type,
+                const struct opt_items* options, 
+                int numoptions, void (*function)(int))
+{
+    int temp;
+    char *strings[MAX_OPTIONS];
+    struct choice_setting data;
+    struct settings_list item;
+    for (temp=0; temp<MAX_OPTIONS && temp<numoptions; temp++)
+        strings[temp] = (char*)options[temp].string;
+    if (type == BOOL)
+    {
+        temp = *(bool*)variable? 1: 0;
+        item.setting = &temp;
+    }
+    else 
+        item.setting = variable;
+    item.flags = F_CHOICE_SETTING|F_T_INT;
+    item.lang_id = -1;
+    item.cfg_vals = (char*)string;
+    data.count = numoptions<MAX_OPTIONS ? numoptions: MAX_OPTIONS;
+    data.desc = (void*)strings; /* shutup gcc... */
+    data.option_callback = function;
+    item.choice_setting = &data;
+    option_screen(&item, false);
+    if (type == BOOL)
+    {
+        *(bool*)variable = (temp == 1? true: false);
+    }
+    return false;
+}
+
+bool set_int_ex(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*),
+                long (*get_talk_id)(int))
+{
+    (void)unit;
+    struct settings_list item;
+    struct int_setting data = {
+        function, voice_unit, min, max, step, 
+        formatter, get_talk_id
+    };
+    item.int_setting = &data;
+    item.flags = F_INT_SETTING|F_T_INT;
+    item.lang_id = -1;
+    item.cfg_vals = (char*)string;
+    item.setting = variable;
+    return option_screen(&item, false);
+}
+
+/* to be replaced */
 void option_select_init_items(struct option_select * opt,
                               const char * title,
                               int selected,
Index: apps/gui/option_select.h
===================================================================
--- apps/gui/option_select.h	(revision 13624)
+++ apps/gui/option_select.h	(working copy)
@@ -21,6 +21,8 @@
 #define _GUI_OPTION_SELECT_H_
 #include "settings.h"
 
+bool option_screen(struct settings_list *setting, bool use_temp_var);
+
 struct option_select
 {
     const char * title;
Index: apps/menu.c
===================================================================
--- apps/menu.c	(revision 13624)
+++ apps/menu.c	(working copy)
@@ -36,6 +36,7 @@
 #include "panic.h"
 #include "settings.h"
 #include "settings_list.h"
+#include "option_select.h"
 #include "status.h"
 #include "screens.h"
 #include "talk.h"
@@ -259,120 +260,9 @@
     const struct settings_list *setting = find_setting(
                                                temp->variable,
                                                &setting_id);
-    bool ret_val = false;
-    unsigned char *title;
-    if (setting)
-    {
-        if ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT)
-            title = temp->callback_and_desc->desc;
-        else
-            title = ID2P(setting->lang_id);
-
-        if ((setting->flags&F_BOOL_SETTING) == F_BOOL_SETTING)
-        {
-            bool temp_var, *var;
-            bool show_icons = global_settings.show_icons;
-            if (setting->flags&F_TEMPVAR)
-            {
-                temp_var = *(bool*)setting->setting;
-                var = &temp_var;
-            }
-            else
-            {
-                var = (bool*)setting->setting;
-            }
-            set_bool_options(P2STR(title), var,
-                        STR(setting->bool_setting->lang_yes),
-                        STR(setting->bool_setting->lang_no),
-                        setting->bool_setting->option_callback);
-            if (setting->flags&F_TEMPVAR)
-                *(bool*)setting->setting = temp_var;
-            if (show_icons != global_settings.show_icons)
-                ret_val = true;
-        }
-        else if (setting->flags&F_T_SOUND)
-        {
-            set_sound(P2STR(title), setting->setting,
-                        setting->sound_setting->setting);
-        }
-        else /* other setting, must be an INT type */
-        {
-            int temp_var, *var;
-            if (setting->flags&F_TEMPVAR)
-            {
-                temp_var = *(int*)setting->setting;
-                var = &temp_var;
-            }
-            else
-            {
-                var = (int*)setting->setting;
-            }
-            if (setting->flags&F_INT_SETTING)
-            {
-                int min, max, step;
-                if (setting->flags&F_FLIPLIST)
-                {
-                    min = setting->int_setting->max;
-                    max = setting->int_setting->min;
-                    step = -setting->int_setting->step;
-                }
-                else
-                {
-                    max = setting->int_setting->max;
-                    min = setting->int_setting->min;
-                    step = setting->int_setting->step;
-                }
-                set_int_ex(P2STR(title), NULL,
-                        setting->int_setting->unit,var,
-                        setting->int_setting->option_callback,
-                        step, min, max,
-                        setting->int_setting->formatter,
-                        setting->int_setting->get_talk_id);
-            }
-            else if (setting->flags&F_CHOICE_SETTING)
-            {
-                static struct opt_items options[MAX_OPTIONS];
-                char buffer[256];
-                char *buf_start = buffer;
-                int buf_free = 256;
-                int i,j, count = setting->choice_setting->count;
-                for (i=0, j=0; i<count && i<MAX_OPTIONS; i++)
-                {
-                    if (setting->flags&F_CHOICETALKS)
-                    {
-                        if (cfg_int_to_string(setting_id, i,
-                                            buf_start, buf_free))
-                        {
-                            int len = strlen(buf_start) +1;
-                            options[j].string = buf_start;
-                            buf_start += len;
-                            buf_free -= len;
-                            options[j].voice_id = 
-                                setting->choice_setting->talks[i];
-                            j++;
-                        }
-                    }
-                    else
-                    {
-                        options[j].string =
-                            P2STR(setting->
-                                  choice_setting->desc[i]);
-                        options[j].voice_id = 
-                            P2ID(setting->
-                                  choice_setting->desc[i]);
-                        j++;
-                    }
-                }
-                set_option(P2STR(title), var, INT,
-                            options,j,
-                            setting->
-                               choice_setting->option_callback);
-            }
-            if (setting->flags&F_TEMPVAR)
-                *(int*)setting->setting = temp_var;
-        }
-    }
-    return ret_val;
+    option_screen((struct settings_list *)setting, 
+                   setting->flags&F_TEMPVAR);
+    return false;
 }
 
 int do_menu(const struct menu_item_ex *start_menu, int *start_selected)
Index: apps/plugin.c
===================================================================
--- apps/plugin.c	(revision 13624)
+++ apps/plugin.c	(working copy)
@@ -32,6 +32,7 @@
 #include "powermgmt.h"
 #include "splash.h"
 #include "logf.h"
+#include "option_select.h"
 
 #if CONFIG_CHARGING
 #include "power.h"
@@ -315,7 +316,6 @@
     sound_default,
 #endif
     sound_set,
-    set_sound,
 
     sound_min,
     sound_max,
@@ -405,7 +405,9 @@
     set_option,
     set_int,
     set_bool,
-
+    find_setting,
+    option_screen,
+    
     /* action handling */
     get_custom_action,
     get_action,
Index: apps/plugin.h
===================================================================
--- apps/plugin.h	(revision 13624)
+++ apps/plugin.h	(working copy)
@@ -114,12 +114,12 @@
 #define PLUGIN_MAGIC 0x526F634B /* RocK */
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 57
+#define PLUGIN_API_VERSION 58
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
    new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 56
+#define PLUGIN_MIN_API_VERSION 58
 
 /* plugin return codes */
 enum plugin_status {
@@ -412,8 +412,6 @@
     int (*sound_default)(int setting);
 #endif
     void (*sound_set)(int setting, int value);
-    bool (*set_sound)(const unsigned char * string,
-                      int* variable, int setting);
     int (*sound_min)(int setting);
     int (*sound_max)(int setting);
 #ifndef SIMULATOR
@@ -510,7 +508,9 @@
                     int* variable, void (*function)(int), int step, int min,
                     int max, void (*formatter)(char*, int, int, const char*) );
     bool (*set_bool)(const char* string, bool* variable );
-
+    const struct settings_list* (*find_setting)(void* variable, int *id);
+    bool (*option_screen)(struct settings_list *setting, bool use_temp_var);
+    
     /* action handling */
     int (*get_custom_action)(int context,int timeout,
                           const struct button_mapping* (*get_context_map)(int));
