Make set_option correctly return USB connect status.
[Rockbox.git] / apps / gui / option_select.c
blobcb5b6eee361fa4c80a749f06cab3323168bbc4ad
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 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
20 #include <stdlib.h>
21 #include <string.h>
22 #include "config.h"
23 #include "option_select.h"
24 #include "sprintf.h"
25 #include "kernel.h"
26 #include "lang.h"
27 #include "talk.h"
28 #include "settings_list.h"
29 #include "sound.h"
30 #include "list.h"
31 #include "action.h"
32 #include "statusbar.h"
33 #include "misc.h"
34 #include "splash.h"
36 #if defined (HAVE_SCROLLWHEEL) || \
37 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
38 (CONFIG_KEYPAD == IPOD_4G_PAD) || \
39 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
40 (CONFIG_KEYPAD == PLAYER_PAD)
41 /* Define this if your target makes sense to have
42 smaller values at the top of the list increasing down the list */
43 #define ASCENDING_INT_SETTINGS
44 #endif
46 static int selection_to_val(struct settings_list *setting, int selection);
48 static const char *unit_strings[] =
50 [UNIT_INT] = "", [UNIT_MS] = "ms",
51 [UNIT_SEC] = "s", [UNIT_MIN] = "min",
52 [UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz",
53 [UNIT_DB] = "dB", [UNIT_PERCENT] = "%",
54 [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
55 [UNIT_PER_SEC] = "per sec",
56 [UNIT_HERTZ] = "Hz",
57 [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s",
58 [UNIT_PM_TICK] = "units/10ms",
60 /* these two vars are needed so arbitrary values can be added to the
61 TABLE_SETTING settings if the F_ALLOW_ARBITRARY_VALS flag is set */
62 static int table_setting_oldval = 0, table_setting_array_position = 0;
63 static char *option_get_valuestring(struct settings_list *setting,
64 char *buffer, int buf_len,
65 intptr_t temp_var)
67 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
69 bool val = (bool)temp_var;
70 snprintf(buffer, buf_len, "%s",
71 str(val? setting->bool_setting->lang_yes :
72 setting->bool_setting->lang_no));
74 #if 0 /* probably dont need this one */
75 else if ((setting->flags & F_FILENAME) == F_FILENAME)
77 struct filename_setting *info = setting->filename_setting;
78 snprintf(buffer, buf_len, "%s%s%s", info->prefix,
79 (char*)temp_var, info->suffix);
81 #endif
82 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
83 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
85 const struct int_setting *int_info = setting->int_setting;
86 const struct table_setting *tbl_info = setting->table_setting;
87 const char *unit;
88 void (*formatter)(char*, size_t, int, const char*);
89 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
91 formatter = int_info->formatter;
92 unit = unit_strings[int_info->unit];
94 else
96 formatter = tbl_info->formatter;
97 unit = unit_strings[tbl_info->unit];
99 if (formatter)
100 formatter(buffer, buf_len, (int)temp_var, unit);
101 else
102 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit?unit:"");
104 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
106 char sign = ' ', *unit;
107 unit = (char*)sound_unit(setting->sound_setting->setting);
108 if (sound_numdecimals(setting->sound_setting->setting))
110 int integer, dec;
111 int val = sound_val2phys(setting->sound_setting->setting,
112 (int)temp_var);
113 if(val < 0)
115 sign = '-';
116 val = abs(val);
118 integer = val / 10; dec = val % 10;
119 snprintf(buffer, buf_len, "%c%d.%d %s", sign, integer, dec, unit);
121 else
122 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit);
124 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
126 if (setting->flags & F_CHOICETALKS)
128 int setting_id;
129 const struct choice_setting *info = setting->choice_setting;
130 if (info->talks[(int)temp_var] < LANG_LAST_INDEX_IN_ARRAY)
132 snprintf(buffer, buf_len, "%s", str(info->talks[(int)temp_var]));
134 else
136 find_setting(setting->setting, &setting_id);
137 cfg_int_to_string(setting_id, (int)temp_var, buffer, buf_len);
140 else
142 int value= (int)temp_var;
143 char *val = P2STR(setting->choice_setting->desc[value]);
144 snprintf(buffer, buf_len, "%s", val);
147 return buffer;
150 static int option_talk(int selected_item, void * data)
152 struct settings_list *setting = (struct settings_list *)data;
153 int temp_var = selection_to_val(setting, selected_item);
154 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
156 bool val = temp_var==1?true:false;
157 talk_id(val? setting->bool_setting->lang_yes :
158 setting->bool_setting->lang_no, false);
160 #if 0 /* probably dont need this one */
161 else if ((setting->flags & F_FILENAME) == F_FILENAME)
164 #endif
165 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
166 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
168 const struct int_setting *int_info = setting->int_setting;
169 const struct table_setting *tbl_info = setting->table_setting;
170 int unit;
171 int32_t (*get_talk_id)(int, int);
172 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
174 unit = int_info->unit;
175 get_talk_id = int_info->get_talk_id;
177 else
179 unit = tbl_info->unit;
180 get_talk_id = tbl_info->get_talk_id;
182 if (get_talk_id)
183 talk_id(get_talk_id((int)temp_var, unit), false);
184 else
185 talk_value((int)temp_var, unit, false);
187 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
189 int talkunit = UNIT_INT;
190 const char *unit = sound_unit(setting->sound_setting->setting);
191 if (!strcmp(unit, "dB"))
192 talkunit = UNIT_DB;
193 else if (!strcmp(unit, "%"))
194 talkunit = UNIT_PERCENT;
195 else if (!strcmp(unit, "Hz"))
196 talkunit = UNIT_HERTZ;
197 talk_value((int)temp_var, talkunit, false);
199 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
201 int value = (int)temp_var;
202 if (setting->flags & F_CHOICETALKS)
204 talk_id(setting->choice_setting->talks[value], false);
206 else
208 talk_id(P2ID(setting->choice_setting->desc[value]), false);
211 return 0;
213 #if 0
214 int option_select_next_val(struct settings_list *setting,
215 intptr_t temp_var)
217 int val = 0;
218 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
220 val = (bool)temp_var ? 0 : 1;
222 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
224 struct int_setting *info = setting->int_setting;
225 val = (int)temp_var + info->step;
226 if (val > info->max)
227 val = info->min;
229 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
231 int setting_id = setting->sound_setting->setting;
232 int steps = sound_steps(setting_id);
233 int min = sound_min(setting_id);
234 int max = sound_max(setting_id);
235 val = (int)temp_var + steps;
236 if (val > max)
237 val = min;
239 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
241 struct choice_setting *info = setting->choice_setting;
242 val = (int)temp_var;
243 if (val > info->count)
244 val = 0;
246 return val;
249 int option_select_prev_val(struct settings_list *setting,
250 intptr_t temp_var)
252 int val = 0;
253 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
255 val = (bool)temp_var ? 0 : 1;
257 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
259 struct int_setting *info = setting->int_setting;
260 val = (int)temp_var - info->step;
261 if (val < info->min)
262 val = info->max;
264 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
266 int setting_id = setting->sound_setting->setting;
267 int steps = sound_steps(setting_id);
268 int min = sound_min(setting_id);
269 int max = sound_max(setting_id);
270 val = (int)temp_var -+ steps;
271 if (val < min)
272 val = max;
274 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
276 struct choice_setting *info = setting->choice_setting;
277 val = (int)temp_var;
278 if (val < 0)
279 val = info->count - 1;
281 return val;
283 #endif
285 static int selection_to_val(struct settings_list *setting, int selection)
287 int min = 0, max = 0, step = 1;
288 if (((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) ||
289 ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING))
290 return selection;
291 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
293 const struct table_setting *info = setting->table_setting;
294 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
295 table_setting_array_position != -1 &&
296 (selection >= table_setting_array_position))
298 if (selection == table_setting_array_position)
299 return table_setting_oldval;
300 return info->values[selection-1];
302 else
303 return info->values[selection];
305 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
307 int setting_id = setting->sound_setting->setting;
308 #ifndef ASCENDING_INT_SETTINGS
309 step = sound_steps(setting_id);
310 max = sound_max(setting_id);
311 min = sound_min(setting_id);
312 #else
313 step = -sound_steps(setting_id);
314 min = sound_max(setting_id);
315 max = sound_min(setting_id);
316 #endif
318 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
320 const struct int_setting *info = setting->int_setting;
321 #ifndef ASCENDING_INT_SETTINGS
322 min = info->min;
323 max = info->max;
324 step = info->step;
325 #else
326 max = info->min;
327 min = info->max;
328 step = -info->step;
329 #endif
331 return max- (selection * step);
333 static char * value_setting_get_name_cb(int selected_item,
334 void * data, char *buffer)
336 selected_item = selection_to_val(data, selected_item);
337 return option_get_valuestring(data, buffer, MAX_PATH, selected_item);
340 /* wrapper to convert from int param to bool param in option_screen */
341 static void (*boolfunction)(bool);
342 static void bool_funcwrapper(int value)
344 if (value)
345 boolfunction(true);
346 else
347 boolfunction(false);
350 bool option_screen(struct settings_list *setting,
351 bool use_temp_var, unsigned char* option_title)
353 int action;
354 bool done = false;
355 struct gui_synclist lists;
356 int oldvalue, nb_items = 0, selected = 0, temp_var;
357 int *variable;
358 bool allow_wrap = setting->flags & F_NO_WRAP ? false : true;
359 int var_type = setting->flags&F_T_MASK;
360 void (*function)(int) = NULL;
361 char *title;
362 if (var_type == F_T_INT || var_type == F_T_UINT)
364 variable = use_temp_var ? &temp_var: (int*)setting->setting;
365 temp_var = oldvalue = *(int*)setting->setting;
367 else if (var_type == F_T_BOOL)
369 /* bools always use the temp variable...
370 if use_temp_var is false it will be copied to setting->setting every change */
371 variable = &temp_var;
372 temp_var = oldvalue = *(bool*)setting->setting?1:0;
374 else return false; /* only int/bools can go here */
375 gui_synclist_init(&lists, value_setting_get_name_cb,
376 (void*)setting, false, 1);
377 if (setting->lang_id == -1)
378 title = (char*)setting->cfg_vals;
379 else
380 title = P2STR(option_title);
382 gui_synclist_set_title(&lists, title, Icon_Questionmark);
383 gui_synclist_set_icon_callback(&lists, NULL);
384 if(global_settings.talk_menu)
385 gui_synclist_set_voice_callback(&lists, option_talk);
387 /* set the number of items and current selection */
388 if (var_type == F_T_INT || var_type == F_T_UINT)
390 if (setting->flags&F_CHOICE_SETTING)
392 nb_items = setting->choice_setting->count;
393 selected = oldvalue;
394 function = setting->choice_setting->option_callback;
396 else if (setting->flags&F_TABLE_SETTING)
398 const struct table_setting *info = setting->table_setting;
399 int i;
400 nb_items = info->count;
401 selected = -1;
402 table_setting_array_position = -1;
403 for (i=0;selected==-1 && i<nb_items;i++)
405 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
406 (oldvalue < info->values[i]))
408 table_setting_oldval = oldvalue;
409 table_setting_array_position = i;
410 selected = i;
411 nb_items++;
413 else if (oldvalue == info->values[i])
414 selected = i;
416 function = info->option_callback;
418 else if (setting->flags&F_T_SOUND)
420 int setting_id = setting->sound_setting->setting;
421 int steps = sound_steps(setting_id);
422 int min = sound_min(setting_id);
423 int max = sound_max(setting_id);
424 nb_items = (max-min)/steps + 1;
425 #ifndef ASCENDING_INT_SETTINGS
426 selected = (max - oldvalue) / steps;
427 #else
428 selected = (oldvalue - min) / steps;
429 #endif
430 function = sound_get_fn(setting_id);
432 else
434 const struct int_setting *info = setting->int_setting;
435 int min, max, step;
436 max = info->max;
437 min = info->min;
438 step = info->step;
439 nb_items = (max-min)/step + 1;
440 #ifndef ASCENDING_INT_SETTINGS
441 selected = (max - oldvalue) / step;
442 #else
443 selected = (oldvalue - min) / step;
444 #endif
445 function = info->option_callback;
448 else if (var_type == F_T_BOOL)
450 selected = oldvalue;
451 nb_items = 2;
452 boolfunction = setting->bool_setting->option_callback;
453 if (boolfunction)
454 function = bool_funcwrapper;
456 gui_synclist_set_nb_items(&lists, nb_items);
457 gui_synclist_select_item(&lists, selected);
459 gui_synclist_limit_scroll(&lists, true);
460 gui_synclist_draw(&lists);
461 /* talk the item */
462 gui_synclist_speak_item(&lists);
463 while (!done)
465 if (list_do_action(CONTEXT_LIST, TIMEOUT_BLOCK,
466 &lists, &action,
467 allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
469 selected = gui_synclist_get_sel_pos(&lists);
470 *variable = selection_to_val(setting, selected);
471 if (var_type == F_T_BOOL)
473 if (!use_temp_var)
474 *(bool*)setting->setting = selected==1?true:false;
477 else if (action == ACTION_NONE)
478 continue;
479 else if (action == ACTION_STD_CANCEL)
481 bool show_cancel = false;
482 if (use_temp_var)
483 show_cancel = true;
484 else if (var_type == F_T_INT || var_type == F_T_UINT)
486 if (*variable != oldvalue)
488 show_cancel = true;
489 *variable = oldvalue;
492 else
494 if (*variable != oldvalue)
496 show_cancel = true;
497 if (!use_temp_var)
498 *(bool*)setting->setting = oldvalue==1?true:false;
499 *variable = oldvalue;
502 if (show_cancel)
503 gui_syncsplash(HZ/2, ID2P(LANG_CANCEL));
504 done = true;
506 else if (action == ACTION_STD_OK)
508 done = true;
510 else if(default_event_handler(action) == SYS_USB_CONNECTED)
511 return true;
512 gui_syncstatusbar_draw(&statusbars, false);
513 /* callback */
514 if ( function )
515 function(*variable);
518 if (oldvalue != *variable && (action != ACTION_STD_CANCEL))
520 if (use_temp_var)
522 if (var_type == F_T_INT || var_type == F_T_UINT)
523 *(int*)setting->setting = *variable;
524 else
525 *(bool*)setting->setting = *variable?true:false;
527 settings_save();
530 return false;
533 /******************************************************
534 Compatability functions
535 *******************************************************/
536 #define MAX_OPTIONS 32
537 const struct opt_items *set_option_options;
538 void set_option_formatter(char* buf, size_t size, int item, const char* unit)
540 (void)unit;
541 const unsigned char *text = set_option_options[item].string;
542 snprintf(buf, size, "%s", P2STR(text));
544 int32_t set_option_get_talk_id(int value, int unit)
546 (void)unit;
547 return set_option_options[value].voice_id;
549 bool set_option(const char* string, void* variable, enum optiontype type,
550 const struct opt_items* options,
551 int numoptions, void (*function)(int))
553 int temp;
554 struct settings_list item;
555 struct int_setting data = {
556 function, UNIT_INT, 0, numoptions-1, 1,
557 set_option_formatter, set_option_get_talk_id
559 set_option_options = options;
560 item.int_setting = &data;
561 item.flags = F_INT_SETTING|F_T_INT;
562 item.lang_id = -1;
563 item.cfg_vals = (char*)string;
564 item.setting = &temp;
565 if (type == BOOL)
566 temp = *(bool*)variable? 1: 0;
567 else
568 temp = *(int*)variable;
569 if (!option_screen(&item, false, NULL))
571 if (type == BOOL)
572 *(bool*)variable = (temp == 1? true: false);
573 else
574 *(int*)variable = temp;
575 return false;
577 return true;
580 bool set_int_ex(const unsigned char* string,
581 const char* unit,
582 int voice_unit,
583 int* variable,
584 void (*function)(int),
585 int step,
586 int min,
587 int max,
588 void (*formatter)(char*, size_t, int, const char*),
589 int32_t (*get_talk_id)(int, int))
591 (void)unit;
592 struct settings_list item;
593 struct int_setting data = {
594 function, voice_unit, min, max, step,
595 formatter, get_talk_id
597 item.int_setting = &data;
598 item.flags = F_INT_SETTING|F_T_INT;
599 item.lang_id = -1;
600 item.cfg_vals = (char*)string;
601 item.setting = variable;
602 return option_screen(&item, false, NULL);
605 /* to be replaced */
606 void option_select_init_items(struct option_select * opt,
607 const char * title,
608 int selected,
609 const struct opt_items * items,
610 int nb_items)
612 opt->title=title;
613 opt->min_value=0;
614 opt->max_value=nb_items;
615 opt->option=selected;
616 opt->items=items;
619 void option_select_next(struct option_select * opt)
621 if(opt->option + 1 >= opt->max_value)
623 if(opt->option==opt->max_value-1)
624 opt->option=opt->min_value;
625 else
626 opt->option=opt->max_value-1;
628 else
629 opt->option+=1;
632 void option_select_prev(struct option_select * opt)
634 if(opt->option - 1 < opt->min_value)
636 /* the dissimilarity to option_select_next() arises from the
637 * sleep timer problem (bug #5000 and #5001):
638 * there we have min=0, step = 5 but the value itself might
639 * not be a multiple of 5 -- as time elapsed;
640 * We need to be able to set timer to 0 (= Off) nevertheless. */
641 if(opt->option!=opt->min_value)
642 opt->option=opt->min_value;
643 else
644 opt->option=opt->max_value-1;
646 else
647 opt->option-=1;
650 const char * option_select_get_text(struct option_select * opt)
652 return(P2STR(opt->items[opt->option].string));