Updated our source code header to explicitly mention that we are GPL v2 or
[Rockbox.git] / apps / gui / option_select.c
blobf6b15467a6a704edcc952a482b4ac30087526677
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Kevin Ferrare
11 * Copyright (C) 2007 by Jonathan Gordon
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdlib.h>
23 #include <string.h>
24 #include "config.h"
25 #include "option_select.h"
26 #include "sprintf.h"
27 #include "kernel.h"
28 #include "lang.h"
29 #include "talk.h"
30 #include "settings_list.h"
31 #include "sound.h"
32 #include "list.h"
33 #include "action.h"
34 #include "statusbar.h"
35 #include "misc.h"
36 #include "splash.h"
38 #if defined (HAVE_SCROLLWHEEL) || \
39 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
40 (CONFIG_KEYPAD == IPOD_4G_PAD) || \
41 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
42 (CONFIG_KEYPAD == PLAYER_PAD)
43 /* Define this if your target makes sense to have
44 smaller values at the top of the list increasing down the list */
45 #define ASCENDING_INT_SETTINGS
46 #endif
48 static int selection_to_val(const struct settings_list *setting, int selection);
49 int option_value_as_int(const struct settings_list *setting)
51 int type = (setting->flags & F_T_MASK);
52 int temp = 0;
53 if (type == F_T_BOOL)
54 temp = *(bool*)setting->setting?1:0;
55 else if (type == F_T_UINT || type == F_T_INT)
56 temp = *(int*)setting->setting;
57 return temp;
59 static const char *unit_strings[] =
61 [UNIT_INT] = "", [UNIT_MS] = "ms",
62 [UNIT_SEC] = "s", [UNIT_MIN] = "min",
63 [UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz",
64 [UNIT_DB] = "dB", [UNIT_PERCENT] = "%",
65 [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
66 [UNIT_PER_SEC] = "per sec",
67 [UNIT_HERTZ] = "Hz",
68 [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s",
69 [UNIT_PM_TICK] = "units/10ms",
71 /* these two vars are needed so arbitrary values can be added to the
72 TABLE_SETTING settings if the F_ALLOW_ARBITRARY_VALS flag is set */
73 static int table_setting_oldval = 0, table_setting_array_position = 0;
74 char *option_get_valuestring(const struct settings_list *setting,
75 char *buffer, int buf_len,
76 intptr_t temp_var)
78 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
80 bool val = (bool)temp_var;
81 snprintf(buffer, buf_len, "%s",
82 str(val? setting->bool_setting->lang_yes :
83 setting->bool_setting->lang_no));
85 #if 0 /* probably dont need this one */
86 else if ((setting->flags & F_FILENAME) == F_FILENAME)
88 struct filename_setting *info = setting->filename_setting;
89 snprintf(buffer, buf_len, "%s%s%s", info->prefix,
90 (char*)temp_var, info->suffix);
92 #endif
93 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
94 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
96 const struct int_setting *int_info = setting->int_setting;
97 const struct table_setting *tbl_info = setting->table_setting;
98 const char *unit;
99 void (*formatter)(char*, size_t, int, const char*);
100 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
102 formatter = int_info->formatter;
103 unit = unit_strings[int_info->unit];
105 else
107 formatter = tbl_info->formatter;
108 unit = unit_strings[tbl_info->unit];
110 if (formatter)
111 formatter(buffer, buf_len, (int)temp_var, unit);
112 else
113 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit?unit:"");
115 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
117 char sign = ' ', *unit;
118 unit = (char*)sound_unit(setting->sound_setting->setting);
119 if (sound_numdecimals(setting->sound_setting->setting))
121 int integer, dec;
122 int val = sound_val2phys(setting->sound_setting->setting,
123 (int)temp_var);
124 if(val < 0)
126 sign = '-';
127 val = abs(val);
129 integer = val / 10; dec = val % 10;
130 snprintf(buffer, buf_len, "%c%d.%d %s", sign, integer, dec, unit);
132 else
133 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit);
135 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
137 if (setting->flags & F_CHOICETALKS)
139 int setting_id;
140 const struct choice_setting *info = setting->choice_setting;
141 if (info->talks[(int)temp_var] < LANG_LAST_INDEX_IN_ARRAY)
143 snprintf(buffer, buf_len, "%s", str(info->talks[(int)temp_var]));
145 else
147 find_setting(setting->setting, &setting_id);
148 cfg_int_to_string(setting_id, (int)temp_var, buffer, buf_len);
151 else
153 int value= (int)temp_var;
154 char *val = P2STR(setting->choice_setting->desc[value]);
155 snprintf(buffer, buf_len, "%s", val);
158 return buffer;
160 void option_talk_value(const struct settings_list *setting, int value, bool enqueue)
162 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
164 bool val = value==1?true:false;
165 talk_id(val? setting->bool_setting->lang_yes :
166 setting->bool_setting->lang_no, enqueue);
168 #if 0 /* probably dont need this one */
169 else if ((setting->flags & F_FILENAME) == F_FILENAME)
172 #endif
173 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
174 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
176 const struct int_setting *int_info = setting->int_setting;
177 const struct table_setting *tbl_info = setting->table_setting;
178 int unit;
179 int32_t (*get_talk_id)(int, int);
180 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
182 unit = int_info->unit;
183 get_talk_id = int_info->get_talk_id;
185 else
187 unit = tbl_info->unit;
188 get_talk_id = tbl_info->get_talk_id;
190 if (get_talk_id)
191 talk_id(get_talk_id(value, unit), enqueue);
192 else
193 talk_value(value, unit, enqueue);
195 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
197 int talkunit = UNIT_INT;
198 const char *unit = sound_unit(setting->sound_setting->setting);
199 if (!strcmp(unit, "dB"))
200 talkunit = UNIT_DB;
201 else if (!strcmp(unit, "%"))
202 talkunit = UNIT_PERCENT;
203 else if (!strcmp(unit, "Hz"))
204 talkunit = UNIT_HERTZ;
205 talk_value(value, talkunit, false);
207 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
209 if (setting->flags & F_CHOICETALKS)
211 talk_id(setting->choice_setting->talks[value], enqueue);
213 else
215 talk_id(P2ID(setting->choice_setting->desc[value]), enqueue);
220 static int option_talk(int selected_item, void * data)
222 struct settings_list *setting = (struct settings_list *)data;
223 int temp_var = selection_to_val(setting, selected_item);
224 option_talk_value(setting, temp_var, false);
225 return 0;
228 #if defined(HAVE_QUICKSCREEN) || defined(HAVE_RECORDING)
229 /* only the quickscreen and recording trigger needs this */
230 void option_select_next_val(const struct settings_list *setting,
231 bool previous, bool apply)
233 int val = 0;
234 int *value = setting->setting;
235 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
237 *(bool*)value = !*(bool*)value;
238 if (apply && setting->bool_setting->option_callback)
239 setting->bool_setting->option_callback(*(bool*)value);
240 return;
242 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
244 struct int_setting *info = (struct int_setting *)setting->int_setting;
245 int step = info->step;
246 if (step < 0)
247 step = -step;
248 if (!previous)
250 val = *value + step;
251 if (val > info->max)
252 val = info->min;
254 else
256 val = *value - step;
257 if (val < info->min)
258 val = info->max;
260 if (apply && info->option_callback)
261 info->option_callback(val);
263 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
265 int setting_id = setting->sound_setting->setting;
266 int steps = sound_steps(setting_id);
267 int min = sound_min(setting_id);
268 int max = sound_max(setting_id);
269 if (!previous)
271 val = *value + steps;
272 if (val >= max)
273 val = min;
275 else
277 val = *value - steps;
278 if (val < min)
279 val = max;
282 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
284 struct choice_setting *info = (struct choice_setting *)setting->choice_setting;
285 val = *value + 1;
286 if (!previous)
288 val = *value + 1;
289 if (val >= info->count)
290 val = 0;
292 else
294 val = *value - 1;
295 if (val < 0)
296 val = info->count-1;
298 if (apply && info->option_callback)
299 info->option_callback(val);
301 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
303 const struct table_setting *tbl_info = setting->table_setting;
304 int i, add;
305 add = previous?tbl_info->count-1:1;
306 for (i=0; i<tbl_info->count;i++)
308 if ((*value == tbl_info->values[i]) ||
309 (settings->flags&F_ALLOW_ARBITRARY_VALS &&
310 *value < tbl_info->values[i]))
312 val = tbl_info->values[(i+add)%tbl_info->count];
313 break;
317 *value = val;
319 #endif
321 static int selection_to_val(const struct settings_list *setting, int selection)
323 int min = 0, max = 0, step = 1;
324 if (((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) ||
325 ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING))
326 return selection;
327 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
329 const struct table_setting *info = setting->table_setting;
330 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
331 table_setting_array_position != -1 &&
332 (selection >= table_setting_array_position))
334 if (selection == table_setting_array_position)
335 return table_setting_oldval;
336 return info->values[selection-1];
338 else
339 return info->values[selection];
341 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
343 int setting_id = setting->sound_setting->setting;
344 #ifndef ASCENDING_INT_SETTINGS
345 step = sound_steps(setting_id);
346 max = sound_max(setting_id);
347 min = sound_min(setting_id);
348 #else
349 step = -sound_steps(setting_id);
350 min = sound_max(setting_id);
351 max = sound_min(setting_id);
352 #endif
354 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
356 const struct int_setting *info = setting->int_setting;
357 #ifndef ASCENDING_INT_SETTINGS
358 min = info->min;
359 max = info->max;
360 step = info->step;
361 #else
362 max = info->min;
363 min = info->max;
364 step = -info->step;
365 #endif
367 return max- (selection * step);
369 static char * value_setting_get_name_cb(int selected_item,
370 void * data,
371 char *buffer,
372 size_t buffer_len)
374 selected_item = selection_to_val(data, selected_item);
375 return option_get_valuestring(data, buffer, buffer_len, selected_item);
378 /* wrapper to convert from int param to bool param in option_screen */
379 static void (*boolfunction)(bool);
380 static void bool_funcwrapper(int value)
382 if (value)
383 boolfunction(true);
384 else
385 boolfunction(false);
388 static void val_to_selection(const struct settings_list *setting, int oldvalue,
389 int *nb_items, int *selected,
390 void (**function)(int))
392 int var_type = setting->flags&F_T_MASK;
393 /* set the number of items and current selection */
394 if (var_type == F_T_INT || var_type == F_T_UINT)
396 if (setting->flags&F_CHOICE_SETTING)
398 *nb_items = setting->choice_setting->count;
399 *selected = oldvalue;
400 *function = setting->choice_setting->option_callback;
402 else if (setting->flags&F_TABLE_SETTING)
404 const struct table_setting *info = setting->table_setting;
405 int i;
406 *nb_items = info->count;
407 *selected = -1;
408 table_setting_array_position = -1;
409 for (i=0;*selected==-1 && i<*nb_items;i++)
411 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
412 (oldvalue < info->values[i]))
414 table_setting_oldval = oldvalue;
415 table_setting_array_position = i;
416 *selected = i;
417 (*nb_items)++;
419 else if (oldvalue == info->values[i])
420 *selected = i;
422 *function = info->option_callback;
424 else if (setting->flags&F_T_SOUND)
426 int setting_id = setting->sound_setting->setting;
427 int steps = sound_steps(setting_id);
428 int min = sound_min(setting_id);
429 int max = sound_max(setting_id);
430 *nb_items = (max-min)/steps + 1;
431 #ifndef ASCENDING_INT_SETTINGS
432 *selected = (max - oldvalue) / steps;
433 #else
434 *selected = (oldvalue - min) / steps;
435 #endif
436 *function = sound_get_fn(setting_id);
438 else
440 const struct int_setting *info = setting->int_setting;
441 int min, max, step;
442 max = info->max;
443 min = info->min;
444 step = info->step;
445 *nb_items = (max-min)/step + 1;
446 #ifndef ASCENDING_INT_SETTINGS
447 *selected = (max - oldvalue) / step;
448 #else
449 *selected = (oldvalue - min) / step;
450 #endif
451 *function = info->option_callback;
454 else if (var_type == F_T_BOOL)
456 *selected = oldvalue;
457 *nb_items = 2;
458 boolfunction = setting->bool_setting->option_callback;
459 if (boolfunction)
460 *function = bool_funcwrapper;
464 bool option_screen(const struct settings_list *setting,
465 struct viewport parent[NB_SCREENS],
466 bool use_temp_var, unsigned char* option_title)
468 int action;
469 bool done = false;
470 struct gui_synclist lists;
471 int oldvalue, nb_items = 0, selected = 0, temp_var;
472 int *variable;
473 bool allow_wrap = setting->flags & F_NO_WRAP ? false : true;
474 int var_type = setting->flags&F_T_MASK;
475 void (*function)(int) = NULL;
476 char *title;
477 if (var_type == F_T_INT || var_type == F_T_UINT)
479 variable = use_temp_var ? &temp_var: (int*)setting->setting;
480 temp_var = oldvalue = *(int*)setting->setting;
482 else if (var_type == F_T_BOOL)
484 /* bools always use the temp variable...
485 if use_temp_var is false it will be copied to setting->setting every change */
486 variable = &temp_var;
487 temp_var = oldvalue = *(bool*)setting->setting?1:0;
489 else return false; /* only int/bools can go here */
490 gui_synclist_init(&lists, value_setting_get_name_cb,
491 (void*)setting, false, 1, parent);
492 if (setting->lang_id == -1)
493 title = (char*)setting->cfg_vals;
494 else
495 title = P2STR(option_title);
497 gui_synclist_set_title(&lists, title, Icon_Questionmark);
498 gui_synclist_set_icon_callback(&lists, NULL);
499 if(global_settings.talk_menu)
500 gui_synclist_set_voice_callback(&lists, option_talk);
502 val_to_selection(setting, oldvalue, &nb_items, &selected, &function);
503 gui_synclist_set_nb_items(&lists, nb_items);
504 gui_synclist_select_item(&lists, selected);
506 gui_synclist_limit_scroll(&lists, true);
507 gui_synclist_draw(&lists);
508 /* talk the item */
509 gui_synclist_speak_item(&lists);
510 gui_syncstatusbar_draw(&statusbars, false);
511 while (!done)
513 if (list_do_action(CONTEXT_LIST, TIMEOUT_BLOCK,
514 &lists, &action,
515 allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
517 selected = gui_synclist_get_sel_pos(&lists);
518 *variable = selection_to_val(setting, selected);
519 if (var_type == F_T_BOOL)
521 if (!use_temp_var)
522 *(bool*)setting->setting = selected==1?true:false;
525 else if (action == ACTION_NONE)
526 continue;
527 else if (action == ACTION_STD_CANCEL)
529 bool show_cancel = false;
530 if (use_temp_var)
531 show_cancel = true;
532 else if (var_type == F_T_INT || var_type == F_T_UINT)
534 if (*variable != oldvalue)
536 show_cancel = true;
537 *variable = oldvalue;
540 else
542 if (*variable != oldvalue)
544 show_cancel = true;
545 if (!use_temp_var)
546 *(bool*)setting->setting = oldvalue==1?true:false;
547 *variable = oldvalue;
550 if (show_cancel)
551 gui_syncsplash(HZ/2, ID2P(LANG_CANCEL));
552 done = true;
554 else if (action == ACTION_STD_CONTEXT)
556 reset_setting(setting, variable);
557 if (var_type == F_T_BOOL && !use_temp_var)
558 *(bool*)setting->setting = temp_var==1?true:false;
559 val_to_selection(setting, *variable, &nb_items,
560 &selected, &function);
561 gui_synclist_select_item(&lists, selected);
562 gui_synclist_draw(&lists);
563 gui_synclist_speak_item(&lists);
565 else if (action == ACTION_STD_OK)
567 done = true;
569 else if(default_event_handler(action) == SYS_USB_CONNECTED)
570 return true;
571 gui_syncstatusbar_draw(&statusbars, false);
572 /* callback */
573 if ( function )
574 function(*variable);
577 if (oldvalue != *variable && (action != ACTION_STD_CANCEL))
579 if (use_temp_var)
581 if (var_type == F_T_INT || var_type == F_T_UINT)
582 *(int*)setting->setting = *variable;
583 else
584 *(bool*)setting->setting = *variable?true:false;
586 settings_save();
589 return false;