Hey all.
For ages i've wanted to move the setting screen code out of settings.c
and make it use the structs from setting_list.c instead of copying
data around before openin the setting screen.
So, the attached diff does this.

I need help testing it though. If everything went well there should be
no noticable difference to the user.

So if you try it out and notice voices not working or setting lists
being backwards or something funny please let me know..

Also, does the code look nicer at all than the svn code?

Jonathan
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));

Reply via email to