Rearrange and cleanup settings code

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13851 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jonathan Gordon 2007-07-11 05:41:23 +00:00
parent 50dc0cabe3
commit a5278fa3db
12 changed files with 691 additions and 626 deletions

View file

@ -8,6 +8,7 @@
* $Id$ * $Id$
* *
* Copyright (C) 2005 by Kevin Ferrare * 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. * 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. * See the file COPYING in the source tree root for full license agreement.
@ -16,12 +17,496 @@
* KIND, either express or implied. * KIND, either express or implied.
* *
****************************************************************************/ ****************************************************************************/
#include <stdlib.h>
#include "config.h"
#include "option_select.h" #include "option_select.h"
#include "sprintf.h" #include "sprintf.h"
#include "kernel.h" #include "kernel.h"
#include "lang.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, void option_select_init_items(struct option_select * opt,
const char * title, const char * title,
int selected, int selected,

View file

@ -21,6 +21,8 @@
#define _GUI_OPTION_SELECT_H_ #define _GUI_OPTION_SELECT_H_
#include "settings.h" #include "settings.h"
bool option_screen(struct settings_list *setting, bool use_temp_var);
struct option_select struct option_select
{ {
const char * title; const char * title;

View file

@ -36,6 +36,7 @@
#include "panic.h" #include "panic.h"
#include "settings.h" #include "settings.h"
#include "settings_list.h" #include "settings_list.h"
#include "option_select.h"
#include "status.h" #include "status.h"
#include "screens.h" #include "screens.h"
#include "talk.h" #include "talk.h"
@ -259,120 +260,9 @@ bool do_setting_from_menu(const struct menu_item_ex *temp)
const struct settings_list *setting = find_setting( const struct settings_list *setting = find_setting(
temp->variable, temp->variable,
&setting_id); &setting_id);
bool ret_val = false; option_screen((struct settings_list *)setting,
unsigned char *title; setting->flags&F_TEMPVAR);
if (setting) return false;
{
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;
} }
int do_menu(const struct menu_item_ex *start_menu, int *start_selected) int do_menu(const struct menu_item_ex *start_menu, int *start_selected)

View file

@ -62,6 +62,7 @@
#include "general.h" #include "general.h"
#endif #endif
#include "action.h" #include "action.h"
#include "recording.h"
static bool no_source_in_menu = true; static bool no_source_in_menu = true;

View file

@ -32,6 +32,7 @@
#include "powermgmt.h" #include "powermgmt.h"
#include "splash.h" #include "splash.h"
#include "logf.h" #include "logf.h"
#include "option_select.h"
#if CONFIG_CHARGING #if CONFIG_CHARGING
#include "power.h" #include "power.h"
@ -318,7 +319,6 @@ static const struct plugin_api rockbox_api = {
sound_default, sound_default,
#endif #endif
sound_set, sound_set,
set_sound,
sound_min, sound_min,
sound_max, sound_max,
@ -405,6 +405,8 @@ static const struct plugin_api rockbox_api = {
&statusbars, &statusbars,
gui_syncstatusbar_draw, gui_syncstatusbar_draw,
/* options */ /* options */
find_setting,
option_screen,
set_option, set_option,
set_bool_options, set_bool_options,
set_int, set_int,

View file

@ -115,12 +115,12 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */ #define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 61 #define PLUGIN_API_VERSION 62
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */ new function which are "waiting" at the end of the function table) */
#define PLUGIN_MIN_API_VERSION 61 #define PLUGIN_MIN_API_VERSION 62
/* plugin return codes */ /* plugin return codes */
enum plugin_status { enum plugin_status {
@ -418,8 +418,6 @@ struct plugin_api {
int (*sound_default)(int setting); int (*sound_default)(int setting);
#endif #endif
void (*sound_set)(int setting, int value); 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_min)(int setting);
int (*sound_max)(int setting); int (*sound_max)(int setting);
#ifndef SIMULATOR #ifndef SIMULATOR
@ -509,6 +507,8 @@ struct plugin_api {
void (*gui_syncstatusbar_draw)(struct gui_syncstatusbar * bars, bool force_redraw); void (*gui_syncstatusbar_draw)(struct gui_syncstatusbar * bars, bool force_redraw);
/* options */ /* options */
const struct settings_list* (*find_setting)(void* variable, int *id);
bool (*option_screen)(struct settings_list *setting, bool use_temp_var);
bool (*set_option)(const char* string, void* variable, bool (*set_option)(const char* string, void* variable,
enum optiontype type, const struct opt_items* options, enum optiontype type, const struct opt_items* options,
int numoptions, void (*function)(int)); int numoptions, void (*function)(int));

View file

@ -59,46 +59,31 @@ bool nexttrack(void)
static bool volume(void) static bool volume(void)
{ {
return api->set_sound("Volume", &api->global_settings->volume, const struct settings_list* vol =
SOUND_VOLUME); api->find_setting(&api->global_settings->volume, NULL);
return api->option_screen((struct settings_list*)vol, false);
} }
static bool shuffle(void) static bool shuffle(void)
{ {
struct opt_items names[2]; const struct settings_list* shuffle =
names[0].string = "No"; api->find_setting(&api->global_settings->playlist_shuffle, NULL);
names[0].voice_id = -1; return api->option_screen((struct settings_list*)shuffle, false);
names[1].string = "Yes";
names[1].voice_id = -1;
return api->set_option("Shuffle", &api->global_settings->playlist_shuffle,
BOOL, names, 2,NULL);
} }
static bool repeat_mode(void) static bool repeat_mode(void)
{ {
bool result; const struct settings_list* repeat =
static const struct opt_items names[] = { api->find_setting(&api->global_settings->repeat_mode, NULL);
{ "Off", -1 },
{ "Repeat All", -1 },
{ "Repeat One", -1 },
{ "Repeat Shuffle", -1 },
#ifdef AB_REPEAT_ENABLE
{ "Repeat A-B", -1 }
#endif
};
int old_repeat = api->global_settings->repeat_mode; int old_repeat = api->global_settings->repeat_mode;
result = api->set_option( "Repeat Mode", api->option_screen((struct settings_list*)repeat, false);
&api->global_settings->repeat_mode,
INT, names, NUM_REPEAT_MODES, NULL );
if (old_repeat != api->global_settings->repeat_mode && if (old_repeat != api->global_settings->repeat_mode &&
(api->audio_status() & AUDIO_STATUS_PLAY)) (api->audio_status() & AUDIO_STATUS_PLAY))
api->audio_flush_and_reload_tracks(); api->audio_flush_and_reload_tracks();
return result; return false;
} }
MENUITEM_FUNCTION(prevtrack_item, 0, "Previous Track", MENUITEM_FUNCTION(prevtrack_item, 0, "Previous Track",
prevtrack, NULL, NULL, Icon_NOICON); prevtrack, NULL, NULL, Icon_NOICON);

View file

@ -69,7 +69,86 @@
#include "action.h" #include "action.h"
#include "radio.h" #include "radio.h"
#ifdef HAVE_RECORDING #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 */
};
static 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 */
};
static 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]
);
}
/* recording screen status flags */ /* recording screen status flags */
enum rec_status_flags enum rec_status_flags
{ {

View file

@ -24,6 +24,7 @@ bool in_recording_screen(void);
bool recording_screen(bool no_source); bool recording_screen(bool no_source);
char *rec_create_filename(char *buf); char *rec_create_filename(char *buf);
int rec_create_directory(void); int rec_create_directory(void);
void settings_apply_trigger(void);
/* If true, start recording automatically when recording_sreen() is entered */ /* If true, start recording automatically when recording_sreen() is entered */
extern bool recording_start_automatic; extern bool recording_start_automatic;

View file

@ -932,51 +932,6 @@ void talk_setting(void *global_settings_variable)
talk_id(setting->lang_id,false); 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 ) bool set_bool(const char* string, bool* variable )
{ {
return set_bool_options(string, variable, return set_bool_options(string, variable,
@ -985,15 +940,6 @@ bool set_bool(const char* string, bool* variable )
NULL); 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, bool set_bool_options(const char* string, bool* variable,
const char* yes_str, int yes_voice, const char* yes_str, int yes_voice,
@ -1006,237 +952,11 @@ bool set_bool_options(const char* string, bool* variable,
}; };
bool result; bool result;
boolfunction = function;
result = set_option(string, variable, BOOL, names, 2, result = set_option(string, variable, BOOL, names, 2,
function ? bool_funcwrapper : NULL); (void (*)(int))function);
return result; 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, bool set_int(const unsigned char* string,
const char* unit, const char* unit,
int voice_unit, int voice_unit,
@ -1250,25 +970,7 @@ bool set_int(const unsigned char* string,
return set_int_ex(string, unit, voice_unit, variable, function, return set_int_ex(string, unit, voice_unit, variable, function,
step, min, max, formatter, NULL); 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 **/ /** extra stuff which is probably misplaced **/
@ -1303,85 +1005,3 @@ void set_file(char* filename, char* setting, int maxlen)
settings_save(); settings_save();
} }
#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

View file

@ -282,9 +282,6 @@ bool set_int_ex(const unsigned char* string, const char* unit, int voice_unit,
bool set_time_screen(const char* string, struct tm *tm); bool set_time_screen(const char* string, struct tm *tm);
int read_line(int fd, char* buffer, int buffer_size); int read_line(int fd, char* buffer, int buffer_size);
void set_file(char* filename, char* setting, int maxlen); 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);
/** global_settings and global_status struct definitions **/ /** global_settings and global_status struct definitions **/

View file

@ -47,6 +47,103 @@
#include "radio.h" #include "radio.h"
#endif #endif
#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
and you may need to update it if you edit this file */
#define UNUSED {.RESERVED=NULL}
#define INT(a) {.int_ = a}
#define UINT(a) {.uint_ = a}
#define BOOL(a) {.bool_ = a}
#define CHARPTR(a) {.charptr = a}
#define UCHARPTR(a) {.ucharptr = a}
#define FUNCTYPE(a) {.func = a}
#define NODEFAULT INT(0)
/* in all the following macros the args are:
- flags: bitwise | or the F_ bits in settings_list.h
- var: pointer to the variable being changed (usually in global_settings)
- lang_ig: LANG_* id to display in menus and setting screens for the settings
- default: the default value for the variable, set if settings are reset
- name: the name of the setting in config files
- cfg_vals: comma seperated list of legal values in cfg files.
NULL if a number is written to the file instead.
- cb: the callback used by the setting screen.
*/
/* Use for int settings which use the set_sound() function to set them */
#define SOUND_SETTING(flags,var,lang_id,name,setting) \
{flags|F_T_INT|F_T_SOUND, &global_settings.var, \
lang_id, NODEFAULT,name,NULL, \
{.sound_setting=(struct sound_setting[]){{setting}}} }
/* Use for bool variables which don't use LANG_SET_BOOL_YES and LANG_SET_BOOL_NO,
or dont save as "off" or "on" in the cfg */
#define BOOL_SETTING(flags,var,lang_id,default,name,cfgvals,yes,no,cb) \
{flags|F_BOOL_SETTING, &global_settings.var, \
lang_id, BOOL(default),name,cfgvals, \
{.bool_setting=(struct bool_setting[]){{cb,yes,no}}} }
/* bool setting which does use LANG_YES and _NO and save as "off,on" */
#define OFFON_SETTING(flags,var,lang_id,default,name,cb) \
{flags|F_BOOL_SETTING, &global_settings.var, \
lang_id, BOOL(default),name,off_on, \
{.bool_setting=(struct bool_setting[]) \
{{cb,LANG_SET_BOOL_YES,LANG_SET_BOOL_NO}}} }
/* int variable which is NOT saved to .cfg files,
(Use NVRAM() in the flags to save to the nvram (or nvram.bin file) */
#define SYSTEM_SETTING(flags,var,default) \
{flags|F_T_INT, &global_status.var,-1, INT(default), \
NULL, NULL, UNUSED}
/* setting which stores as a filename in the .cfgvals
prefix: The absolute path to not save in the variable, e.g /.rockbox/wps_file
suffx: The file extention (usually...) e.g .wps_file */
#define FILENAME_SETTING(flags,var,name,default,prefix,suffix,len) \
{flags|F_T_UCHARPTR, &global_settings.var,-1, \
CHARPTR(default),name,NULL, \
{.filename_setting= \
(struct filename_setting[]){{prefix,suffix,len}}} }
/* Used for settings which use the set_option() setting screen.
the ... arg is a list of pointers to strings to display in the setting screen.
These can either be literal strings, or ID2P(LANG_*) */
#define CHOICE_SETTING(flags,var,lang_id,default,name,cfg_vals,cb,count,...) \
{flags|F_CHOICE_SETTING|F_T_INT, &global_settings.var, lang_id, \
INT(default), name, cfg_vals, \
{.choice_setting = (struct choice_setting[]){ \
{cb, count, {.desc = (unsigned char*[]){__VA_ARGS__}}}}}}
/* Similar to above, except the strings to display are taken from cfg_vals,
the ... arg is a list of ID's to talk for the strings... can use TALK_ID()'s */
#define STRINGCHOICE_SETTING(flags,var,lang_id,default,name,cfg_vals,cb,count,...) \
{flags|F_CHOICE_SETTING|F_T_INT|F_CHOICETALKS, \
&global_settings.var, lang_id, \
INT(default), name, cfg_vals, \
{.choice_setting = (struct choice_setting[]){ \
{cb, count, {.talks = (int[]){__VA_ARGS__}}}}}}
/* for settings which use the set_int() setting screen.
unit is the UNIT_ define to display/talk.
the first one saves a string to the config file,
the second one saves the variable value to the config file */
#define INT_SETTING_W_CFGVALS(flags, var, lang_id, default, name, cfg_vals, \
unit, min, max, step, formatter, get_talk_id, cb) \
{flags|F_INT_SETTING|F_T_INT, &global_settings.var, \
lang_id, INT(default), name, cfg_vals, \
{.int_setting = (struct int_setting[]){ \
{cb, unit, min, max, step, formatter, get_talk_id}}}}
#define INT_SETTING(flags, var, lang_id, default, name, \
unit, min, max, step, formatter, get_talk_id, cb) \
{flags|F_INT_SETTING|F_T_INT, &global_settings.var, \
lang_id, INT(default), name, NULL, \
{.int_setting = (struct int_setting[]){ \
{cb, unit, min, max, step, formatter, get_talk_id}}}}
/* some sets of values which are used more than once, to save memory */ /* 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[] = "off,on";
static const char off_on_ask[] = "off,on,ask"; static const char off_on_ask[] = "off,on,ask";
@ -193,100 +290,6 @@ static void listaccel_formatter(char *buffer, int buffer_size,
snprintf(buffer, buffer_size, "%d ms", 5*HZ*val); snprintf(buffer, buffer_size, "%d ms", 5*HZ*val);
} }
#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
and you may need to update it if you edit this file */
#define UNUSED {.RESERVED=NULL}
#define INT(a) {.int_ = a}
#define UINT(a) {.uint_ = a}
#define BOOL(a) {.bool_ = a}
#define CHARPTR(a) {.charptr = a}
#define UCHARPTR(a) {.ucharptr = a}
#define FUNCTYPE(a) {.func = a}
#define NODEFAULT INT(0)
/* in all the following macros the args are:
- flags: bitwise | or the F_ bits in settings_list.h
- var: pointer to the variable being changed (usually in global_settings)
- lang_ig: LANG_* id to display in menus and setting screens for the settings
- default: the default value for the variable, set if settings are reset
- name: the name of the setting in config files
- cfg_vals: comma seperated list of legal values in cfg files.
NULL if a number is written to the file instead.
- cb: the callback used by the setting screen.
*/
/* Use for int settings which use the set_sound() function to set them */
#define SOUND_SETTING(flags,var,lang_id,name,setting) \
{flags|F_T_INT|F_T_SOUND, &global_settings.var, \
lang_id, NODEFAULT,name,NULL, \
{.sound_setting=(struct sound_setting[]){{setting}}} }
/* Use for bool variables which don't use LANG_SET_BOOL_YES and LANG_SET_BOOL_NO,
or dont save as "off" or "on" in the cfg */
#define BOOL_SETTING(flags,var,lang_id,default,name,cfgvals,yes,no,cb) \
{flags|F_BOOL_SETTING, &global_settings.var, \
lang_id, BOOL(default),name,cfgvals, \
{.bool_setting=(struct bool_setting[]){{cb,yes,no}}} }
/* bool setting which does use LANG_YES and _NO and save as "off,on" */
#define OFFON_SETTING(flags,var,lang_id,default,name,cb) \
{flags|F_BOOL_SETTING, &global_settings.var, \
lang_id, BOOL(default),name,off_on, \
{.bool_setting=(struct bool_setting[]) \
{{cb,LANG_SET_BOOL_YES,LANG_SET_BOOL_NO}}} }
/* int variable which is NOT saved to .cfg files,
(Use NVRAM() in the flags to save to the nvram (or nvram.bin file) */
#define SYSTEM_SETTING(flags,var,default) \
{flags|F_T_INT, &global_status.var,-1, INT(default), \
NULL, NULL, UNUSED}
/* setting which stores as a filename in the .cfgvals
prefix: The absolute path to not save in the variable, e.g /.rockbox/wps_file
suffx: The file extention (usually...) e.g .wps_file */
#define FILENAME_SETTING(flags,var,name,default,prefix,suffix,len) \
{flags|F_T_UCHARPTR, &global_settings.var,-1, \
CHARPTR(default),name,NULL, \
{.filename_setting= \
(struct filename_setting[]){{prefix,suffix,len}}} }
/* Used for settings which use the set_option() setting screen.
the ... arg is a list of pointers to strings to display in the setting screen.
These can either be literal strings, or ID2P(LANG_*) */
#define CHOICE_SETTING(flags,var,lang_id,default,name,cfg_vals,cb,count,...) \
{flags|F_CHOICE_SETTING|F_T_INT, &global_settings.var, lang_id, \
INT(default), name, cfg_vals, \
{.choice_setting = (struct choice_setting[]){ \
{cb, count, {.desc = (unsigned char*[]){__VA_ARGS__}}}}}}
/* Similar to above, except the strings to display are taken from cfg_vals,
the ... arg is a list of ID's to talk for the strings... can use TALK_ID()'s */
#define STRINGCHOICE_SETTING(flags,var,lang_id,default,name,cfg_vals,cb,count,...) \
{flags|F_CHOICE_SETTING|F_T_INT|F_CHOICETALKS, \
&global_settings.var, lang_id, \
INT(default), name, cfg_vals, \
{.choice_setting = (struct choice_setting[]){ \
{cb, count, {.talks = (int[]){__VA_ARGS__}}}}}}
/* for settings which use the set_int() setting screen.
unit is the UNIT_ define to display/talk.
the first one saves a string to the config file,
the second one saves the variable value to the config file */
#define INT_SETTING_W_CFGVALS(flags, var, lang_id, default, name, cfg_vals, \
unit, min, max, step, formatter, get_talk_id, cb) \
{flags|F_INT_SETTING|F_T_INT, &global_settings.var, \
lang_id, INT(default), name, cfg_vals, \
{.int_setting = (struct int_setting[]){ \
{cb, unit, min, max, step, formatter, get_talk_id}}}}
#define INT_SETTING(flags, var, lang_id, default, name, \
unit, min, max, step, formatter, get_talk_id, cb) \
{flags|F_INT_SETTING|F_T_INT, &global_settings.var, \
lang_id, INT(default), name, NULL, \
{.int_setting = (struct int_setting[]){ \
{cb, unit, min, max, step, formatter, get_talk_id}}}}
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
static void crossfeed_format(char* buffer, int buffer_size, int value, static void crossfeed_format(char* buffer, int buffer_size, int value,
const char* unit) const char* unit)