autodetection: convert path to native separators before displaying it.
[Rockbox.git] / apps / gui / option_select.c
blobc3c2cb3c63d776d0886b4e30067432aeb363e5e1
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(const 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 char *option_get_valuestring(const 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;
149 void option_talk_value(const struct settings_list *setting, int value, bool enqueue)
151 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
153 bool val = value==1?true:false;
154 talk_id(val? setting->bool_setting->lang_yes :
155 setting->bool_setting->lang_no, enqueue);
157 #if 0 /* probably dont need this one */
158 else if ((setting->flags & F_FILENAME) == F_FILENAME)
161 #endif
162 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
163 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
165 const struct int_setting *int_info = setting->int_setting;
166 const struct table_setting *tbl_info = setting->table_setting;
167 int unit;
168 int32_t (*get_talk_id)(int, int);
169 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
171 unit = int_info->unit;
172 get_talk_id = int_info->get_talk_id;
174 else
176 unit = tbl_info->unit;
177 get_talk_id = tbl_info->get_talk_id;
179 if (get_talk_id)
180 talk_id(get_talk_id(value, unit), enqueue);
181 else
182 talk_value(value, unit, enqueue);
184 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
186 int talkunit = UNIT_INT;
187 const char *unit = sound_unit(setting->sound_setting->setting);
188 if (!strcmp(unit, "dB"))
189 talkunit = UNIT_DB;
190 else if (!strcmp(unit, "%"))
191 talkunit = UNIT_PERCENT;
192 else if (!strcmp(unit, "Hz"))
193 talkunit = UNIT_HERTZ;
194 talk_value(value, talkunit, false);
196 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
198 if (setting->flags & F_CHOICETALKS)
200 talk_id(setting->choice_setting->talks[value], enqueue);
202 else
204 talk_id(P2ID(setting->choice_setting->desc[value]), enqueue);
209 static int option_talk(int selected_item, void * data)
211 struct settings_list *setting = (struct settings_list *)data;
212 int temp_var = selection_to_val(setting, selected_item);
213 option_talk_value(setting, temp_var, false);
214 return 0;
217 #ifdef HAVE_QUICKSCREEN /* only the quickscreen uses this so far */
218 void option_select_next_val(const struct settings_list *setting,
219 bool previous, bool apply)
221 int val = 0;
222 int *value = setting->setting;
223 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
225 *(bool*)value = !*(bool*)value;
226 if (apply && setting->bool_setting->option_callback)
227 setting->bool_setting->option_callback(*(bool*)value);
228 return;
230 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
232 struct int_setting *info = (struct int_setting *)setting->int_setting;
233 int step = info->step;
234 if (step < 0)
235 step = -step;
236 if (!previous)
238 val = *value + step;
239 if (val > info->max)
240 val = info->min;
242 else
244 val = *value - step;
245 if (val < info->min)
246 val = info->max;
248 if (apply && info->option_callback)
249 info->option_callback(*(int*)value);
251 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
253 int setting_id = setting->sound_setting->setting;
254 int steps = sound_steps(setting_id);
255 int min = sound_min(setting_id);
256 int max = sound_max(setting_id);
257 if (!previous)
259 val = *value + steps;
260 if (val >= max)
261 val = min;
263 else
265 val = *value - steps;
266 if (val < min)
267 val = max;
270 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
272 struct choice_setting *info = (struct choice_setting *)setting->choice_setting;
273 val = *value + 1;
274 if (!previous)
276 val = *value + 1;
277 if (val >= info->count)
278 val = 0;
280 else
282 val = *value - 1;
283 if (val < 0)
284 val = info->count-1;
286 if (apply && info->option_callback)
287 info->option_callback(*(int*)value);
289 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
291 const struct table_setting *tbl_info = setting->table_setting;
292 int i, add;
293 add = previous?tbl_info->count-1:1;
294 for (i=0; i<tbl_info->count;i++)
296 if ((*value == tbl_info->values[i]) ||
297 (settings->flags&F_ALLOW_ARBITRARY_VALS &&
298 *value < tbl_info->values[i]))
300 val = tbl_info->values[(i+add)%tbl_info->count];
301 break;
305 *value = val;
307 #endif
309 static int selection_to_val(const struct settings_list *setting, int selection)
311 int min = 0, max = 0, step = 1;
312 if (((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) ||
313 ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING))
314 return selection;
315 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
317 const struct table_setting *info = setting->table_setting;
318 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
319 table_setting_array_position != -1 &&
320 (selection >= table_setting_array_position))
322 if (selection == table_setting_array_position)
323 return table_setting_oldval;
324 return info->values[selection-1];
326 else
327 return info->values[selection];
329 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
331 int setting_id = setting->sound_setting->setting;
332 #ifndef ASCENDING_INT_SETTINGS
333 step = sound_steps(setting_id);
334 max = sound_max(setting_id);
335 min = sound_min(setting_id);
336 #else
337 step = -sound_steps(setting_id);
338 min = sound_max(setting_id);
339 max = sound_min(setting_id);
340 #endif
342 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
344 const struct int_setting *info = setting->int_setting;
345 #ifndef ASCENDING_INT_SETTINGS
346 min = info->min;
347 max = info->max;
348 step = info->step;
349 #else
350 max = info->min;
351 min = info->max;
352 step = -info->step;
353 #endif
355 return max- (selection * step);
357 static char * value_setting_get_name_cb(int selected_item,
358 void * data,
359 char *buffer,
360 size_t buffer_len)
362 selected_item = selection_to_val(data, selected_item);
363 return option_get_valuestring(data, buffer, buffer_len, selected_item);
366 /* wrapper to convert from int param to bool param in option_screen */
367 static void (*boolfunction)(bool);
368 static void bool_funcwrapper(int value)
370 if (value)
371 boolfunction(true);
372 else
373 boolfunction(false);
376 static void val_to_selection(const struct settings_list *setting, int oldvalue,
377 int *nb_items, int *selected,
378 void (**function)(int))
380 int var_type = setting->flags&F_T_MASK;
381 /* set the number of items and current selection */
382 if (var_type == F_T_INT || var_type == F_T_UINT)
384 if (setting->flags&F_CHOICE_SETTING)
386 *nb_items = setting->choice_setting->count;
387 *selected = oldvalue;
388 *function = setting->choice_setting->option_callback;
390 else if (setting->flags&F_TABLE_SETTING)
392 const struct table_setting *info = setting->table_setting;
393 int i;
394 *nb_items = info->count;
395 *selected = -1;
396 table_setting_array_position = -1;
397 for (i=0;*selected==-1 && i<*nb_items;i++)
399 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
400 (oldvalue < info->values[i]))
402 table_setting_oldval = oldvalue;
403 table_setting_array_position = i;
404 *selected = i;
405 (*nb_items)++;
407 else if (oldvalue == info->values[i])
408 *selected = i;
410 *function = info->option_callback;
412 else if (setting->flags&F_T_SOUND)
414 int setting_id = setting->sound_setting->setting;
415 int steps = sound_steps(setting_id);
416 int min = sound_min(setting_id);
417 int max = sound_max(setting_id);
418 *nb_items = (max-min)/steps + 1;
419 #ifndef ASCENDING_INT_SETTINGS
420 *selected = (max - oldvalue) / steps;
421 #else
422 *selected = (oldvalue - min) / steps;
423 #endif
424 *function = sound_get_fn(setting_id);
426 else
428 const struct int_setting *info = setting->int_setting;
429 int min, max, step;
430 max = info->max;
431 min = info->min;
432 step = info->step;
433 *nb_items = (max-min)/step + 1;
434 #ifndef ASCENDING_INT_SETTINGS
435 *selected = (max - oldvalue) / step;
436 #else
437 *selected = (oldvalue - min) / step;
438 #endif
439 *function = info->option_callback;
442 else if (var_type == F_T_BOOL)
444 *selected = oldvalue;
445 *nb_items = 2;
446 boolfunction = setting->bool_setting->option_callback;
447 if (boolfunction)
448 *function = bool_funcwrapper;
452 bool option_screen(const struct settings_list *setting,
453 struct viewport parent[NB_SCREENS],
454 bool use_temp_var, unsigned char* option_title)
456 int action;
457 bool done = false;
458 struct gui_synclist lists;
459 int oldvalue, nb_items = 0, selected = 0, temp_var;
460 int *variable;
461 bool allow_wrap = setting->flags & F_NO_WRAP ? false : true;
462 int var_type = setting->flags&F_T_MASK;
463 void (*function)(int) = NULL;
464 char *title;
465 if (var_type == F_T_INT || var_type == F_T_UINT)
467 variable = use_temp_var ? &temp_var: (int*)setting->setting;
468 temp_var = oldvalue = *(int*)setting->setting;
470 else if (var_type == F_T_BOOL)
472 /* bools always use the temp variable...
473 if use_temp_var is false it will be copied to setting->setting every change */
474 variable = &temp_var;
475 temp_var = oldvalue = *(bool*)setting->setting?1:0;
477 else return false; /* only int/bools can go here */
478 gui_synclist_init(&lists, value_setting_get_name_cb,
479 (void*)setting, false, 1, parent);
480 if (setting->lang_id == -1)
481 title = (char*)setting->cfg_vals;
482 else
483 title = P2STR(option_title);
485 gui_synclist_set_title(&lists, title, Icon_Questionmark);
486 gui_synclist_set_icon_callback(&lists, NULL);
487 if(global_settings.talk_menu)
488 gui_synclist_set_voice_callback(&lists, option_talk);
490 val_to_selection(setting, oldvalue, &nb_items, &selected, &function);
491 gui_synclist_set_nb_items(&lists, nb_items);
492 gui_synclist_select_item(&lists, selected);
494 gui_synclist_limit_scroll(&lists, true);
495 gui_synclist_draw(&lists);
496 /* talk the item */
497 gui_synclist_speak_item(&lists);
498 gui_syncstatusbar_draw(&statusbars, false);
499 while (!done)
501 if (list_do_action(CONTEXT_LIST, TIMEOUT_BLOCK,
502 &lists, &action,
503 allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
505 selected = gui_synclist_get_sel_pos(&lists);
506 *variable = selection_to_val(setting, selected);
507 if (var_type == F_T_BOOL)
509 if (!use_temp_var)
510 *(bool*)setting->setting = selected==1?true:false;
513 else if (action == ACTION_NONE)
514 continue;
515 else if (action == ACTION_STD_CANCEL)
517 bool show_cancel = false;
518 if (use_temp_var)
519 show_cancel = true;
520 else if (var_type == F_T_INT || var_type == F_T_UINT)
522 if (*variable != oldvalue)
524 show_cancel = true;
525 *variable = oldvalue;
528 else
530 if (*variable != oldvalue)
532 show_cancel = true;
533 if (!use_temp_var)
534 *(bool*)setting->setting = oldvalue==1?true:false;
535 *variable = oldvalue;
538 if (show_cancel)
539 gui_syncsplash(HZ/2, ID2P(LANG_CANCEL));
540 done = true;
542 else if (action == ACTION_STD_CONTEXT)
544 reset_setting(setting, variable);
545 if (var_type == F_T_BOOL && !use_temp_var)
546 *(bool*)setting->setting = temp_var==1?true:false;
547 val_to_selection(setting, *variable, &nb_items,
548 &selected, &function);
549 gui_synclist_select_item(&lists, selected);
550 gui_synclist_draw(&lists);
551 gui_synclist_speak_item(&lists);
553 else if (action == ACTION_STD_OK)
555 done = true;
557 else if(default_event_handler(action) == SYS_USB_CONNECTED)
558 return true;
559 gui_syncstatusbar_draw(&statusbars, false);
560 /* callback */
561 if ( function )
562 function(*variable);
565 if (oldvalue != *variable && (action != ACTION_STD_CANCEL))
567 if (use_temp_var)
569 if (var_type == F_T_INT || var_type == F_T_UINT)
570 *(int*)setting->setting = *variable;
571 else
572 *(bool*)setting->setting = *variable?true:false;
574 settings_save();
577 return false;