invert the quickscreen setting direction on wheel targets for settings which are...
[maemo-rb.git] / apps / gui / option_select.c
blob5d1e3d778e388cf0d6f70c0d44a368ed79f30ded
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-extra.h"
24 #include "config.h"
25 #include "option_select.h"
26 #include "kernel.h"
27 #include "lang.h"
28 #include "talk.h"
29 #include "settings_list.h"
30 #include "sound.h"
31 #include "list.h"
32 #include "action.h"
33 #include "misc.h"
34 #include "splash.h"
35 #include "menu.h"
36 #include "quickscreen.h"
39 static int selection_to_val(const struct settings_list *setting, int selection);
40 int option_value_as_int(const struct settings_list *setting)
42 int type = (setting->flags & F_T_MASK);
43 int temp = 0;
44 if (type == F_T_BOOL)
45 temp = *(bool*)setting->setting?1:0;
46 else if (type == F_T_UINT || type == F_T_INT)
47 temp = *(int*)setting->setting;
48 return temp;
50 static const char *unit_strings[] =
52 [UNIT_INT] = "", [UNIT_MS] = "ms",
53 [UNIT_SEC] = "s", [UNIT_MIN] = "min",
54 [UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz",
55 [UNIT_DB] = "dB", [UNIT_PERCENT] = "%",
56 [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
57 [UNIT_PER_SEC] = "per sec",
58 [UNIT_HERTZ] = "Hz",
59 [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s",
60 [UNIT_PM_TICK] = "units/10ms",
62 /* these two vars are needed so arbitrary values can be added to the
63 TABLE_SETTING settings if the F_ALLOW_ARBITRARY_VALS flag is set */
64 static int table_setting_oldval = 0, table_setting_array_position = 0;
65 const char *option_get_valuestring(const struct settings_list *setting,
66 char *buffer, int buf_len,
67 intptr_t temp_var)
69 const char* str = buffer;
70 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
72 bool val = (bool)temp_var;
73 strlcpy(buffer, str(val? setting->bool_setting->lang_yes :
74 setting->bool_setting->lang_no), buf_len);
76 #if 0 /* probably dont need this one */
77 else if ((setting->flags & F_FILENAME) == F_FILENAME)
79 struct filename_setting *info = setting->filename_setting;
80 snprintf(buffer, buf_len, "%s%s%s", info->prefix,
81 (char*)temp_var, info->suffix);
83 #endif
84 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
85 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
87 const struct int_setting *int_info = setting->int_setting;
88 const struct table_setting *tbl_info = setting->table_setting;
89 const char *unit;
90 const char* (*formatter)(char*, size_t, int, const char*);
91 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
93 formatter = int_info->formatter;
94 unit = unit_strings[int_info->unit];
96 else
98 formatter = tbl_info->formatter;
99 unit = unit_strings[tbl_info->unit];
101 if (formatter)
102 str = formatter(buffer, buf_len, (int)temp_var, unit);
103 else
104 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit?unit:"");
106 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
108 char sign = ' ';
109 const char *unit = sound_unit(setting->sound_setting->setting);
110 int val = sound_val2phys(setting->sound_setting->setting, (int)temp_var);
111 if (sound_numdecimals(setting->sound_setting->setting))
113 int integer, dec;
114 if(val < 0)
116 sign = '-';
117 val = abs(val);
119 integer = val / 10;
120 dec = val % 10;
121 snprintf(buffer, buf_len, "%c%d.%d %s", sign, integer, dec, unit);
123 else
124 snprintf(buffer, buf_len, "%d %s", val, unit);
126 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
128 if (setting->flags & F_CHOICETALKS)
130 int setting_id;
131 const struct choice_setting *info = setting->choice_setting;
132 if (info->talks[(int)temp_var] < LANG_LAST_INDEX_IN_ARRAY)
134 strlcpy(buffer, str(info->talks[(int)temp_var]), buf_len);
136 else
138 find_setting(setting->setting, &setting_id);
139 cfg_int_to_string(setting_id, (int)temp_var, buffer, buf_len);
142 else
144 int value = (int)temp_var;
145 char *val = P2STR(setting->choice_setting->desc[value]);
146 strlcpy(buffer, val, buf_len);
149 return str;
151 void option_talk_value(const struct settings_list *setting, int value, bool enqueue)
153 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
155 bool val = (value==1);
156 talk_id(val? setting->bool_setting->lang_yes :
157 setting->bool_setting->lang_no, enqueue);
159 #if 0 /* probably dont need this one */
160 else if ((setting->flags & F_FILENAME) == F_FILENAME)
163 #endif
164 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
165 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
167 const struct int_setting *int_info = setting->int_setting;
168 const struct table_setting *tbl_info = setting->table_setting;
169 int unit;
170 int32_t (*get_talk_id)(int, int);
171 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
173 unit = int_info->unit;
174 get_talk_id = int_info->get_talk_id;
176 else
178 unit = tbl_info->unit;
179 get_talk_id = tbl_info->get_talk_id;
181 if (get_talk_id)
182 talk_id(get_talk_id(value, unit), enqueue);
183 else
184 talk_value(value, unit, enqueue);
186 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
188 int talkunit = UNIT_INT;
189 int sound_setting = setting->sound_setting->setting;
190 const char *unit = sound_unit(sound_setting);
191 int decimals = sound_numdecimals(sound_setting);
192 int phys = sound_val2phys(sound_setting, value);
193 if (!strcmp(unit, "dB"))
194 talkunit = UNIT_DB;
195 else if (!strcmp(unit, "%"))
196 talkunit = UNIT_PERCENT;
197 else if (!strcmp(unit, "Hz"))
198 talkunit = UNIT_HERTZ;
199 talk_value_decimal(phys, talkunit, decimals, false);
201 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
203 if (setting->flags & F_CHOICETALKS)
205 talk_id(setting->choice_setting->talks[value], enqueue);
207 else
209 talk_id(P2ID(setting->choice_setting->desc[value]), enqueue);
214 static int option_talk(int selected_item, void * data)
216 struct settings_list *setting = (struct settings_list *)data;
217 int temp_var = selection_to_val(setting, selected_item);
218 option_talk_value(setting, temp_var, false);
219 return 0;
222 #if defined(HAVE_QUICKSCREEN) || defined(HAVE_RECORDING) || defined(HAVE_TOUCHSCREEN)
223 /* only the quickscreen and recording trigger needs this */
224 void option_select_next_val(const struct settings_list *setting,
225 bool previous, bool apply)
227 int val = 0;
228 int *value = setting->setting;
229 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
231 *(bool*)value = !*(bool*)value;
232 if (apply && setting->bool_setting->option_callback)
233 setting->bool_setting->option_callback(*(bool*)value);
234 return;
236 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
238 struct int_setting *info = (struct int_setting *)setting->int_setting;
239 bool neg_step = (info->step < 0);
240 if (!previous)
242 val = *value + info->step;
243 if (neg_step ? (val < info->max) : (val > info->max))
244 val = info->min;
246 else
248 val = *value - info->step;
249 if (neg_step ? (val > info->min) : (val < info->min))
250 val = info->max;
252 *value = val;
253 if (apply && info->option_callback)
254 info->option_callback(val);
256 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
258 int setting_id = setting->sound_setting->setting;
259 int steps = sound_steps(setting_id);
260 int min = sound_min(setting_id);
261 int max = sound_max(setting_id);
262 if (!previous)
264 val = *value + steps;
265 if (val >= max)
266 val = min;
268 else
270 val = *value - steps;
271 if (val < min)
272 val = max;
274 *value = val;
276 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
278 struct choice_setting *info = (struct choice_setting *)setting->choice_setting;
279 val = *value + 1;
280 if (!previous)
282 val = *value + 1;
283 if (val >= info->count)
284 val = 0;
286 else
288 val = *value - 1;
289 if (val < 0)
290 val = info->count-1;
292 *value = val;
293 if (apply && info->option_callback)
294 info->option_callback(val);
296 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
298 const struct table_setting *tbl_info = setting->table_setting;
299 int i, add;
300 add = previous?tbl_info->count-1:1;
301 for (i=0; i<tbl_info->count;i++)
303 if ((*value == tbl_info->values[i]) ||
304 (settings->flags&F_ALLOW_ARBITRARY_VALS &&
305 *value < tbl_info->values[i]))
307 val = tbl_info->values[(i+add)%tbl_info->count];
308 break;
311 *value = val;
314 #endif
316 static int selection_to_val(const struct settings_list *setting, int selection)
318 int min = 0, max = 0, step = 1;
319 if (((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) ||
320 ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING))
321 return selection;
322 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
324 const struct table_setting *info = setting->table_setting;
325 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
326 table_setting_array_position != -1 &&
327 (selection >= table_setting_array_position))
329 if (selection == table_setting_array_position)
330 return table_setting_oldval;
331 return info->values[selection-1];
333 else
334 return info->values[selection];
336 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
338 int setting_id = setting->sound_setting->setting;
339 #ifndef ASCENDING_INT_SETTINGS
340 step = sound_steps(setting_id);
341 max = sound_max(setting_id);
342 min = sound_min(setting_id);
343 #else
344 step = -sound_steps(setting_id);
345 min = sound_max(setting_id);
346 max = sound_min(setting_id);
347 #endif
349 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
351 const struct int_setting *info = setting->int_setting;
352 #ifndef ASCENDING_INT_SETTINGS
353 min = info->min;
354 max = info->max;
355 step = info->step;
356 #else
357 max = info->min;
358 min = info->max;
359 step = -info->step;
360 #endif
362 return max- (selection * step);
365 static const char * value_setting_get_name_cb(int selected_item,
366 void * data,
367 char *buffer,
368 size_t buffer_len)
370 selected_item = selection_to_val(data, selected_item);
371 return option_get_valuestring(data, buffer, buffer_len, selected_item);
374 /* wrapper to convert from int param to bool param in option_screen */
375 static void (*boolfunction)(bool);
376 static void bool_funcwrapper(int value)
378 if (value)
379 boolfunction(true);
380 else
381 boolfunction(false);
384 static void val_to_selection(const struct settings_list *setting, int oldvalue,
385 int *nb_items, int *selected,
386 void (**function)(int))
388 int var_type = setting->flags&F_T_MASK;
389 /* set the number of items and current selection */
390 if (var_type == F_T_INT || var_type == F_T_UINT)
392 if (setting->flags&F_CHOICE_SETTING)
394 *nb_items = setting->choice_setting->count;
395 *selected = oldvalue;
396 *function = setting->choice_setting->option_callback;
398 else if (setting->flags&F_TABLE_SETTING)
400 const struct table_setting *info = setting->table_setting;
401 int i;
402 *nb_items = info->count;
403 *selected = -1;
404 table_setting_array_position = -1;
405 for (i=0;*selected==-1 && i<*nb_items;i++)
407 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
408 (oldvalue < info->values[i]))
410 table_setting_oldval = oldvalue;
411 table_setting_array_position = i;
412 *selected = i;
413 (*nb_items)++;
415 else if (oldvalue == info->values[i])
416 *selected = i;
418 *function = info->option_callback;
420 else if (setting->flags&F_T_SOUND)
422 int setting_id = setting->sound_setting->setting;
423 int steps = sound_steps(setting_id);
424 int min = sound_min(setting_id);
425 int max = sound_max(setting_id);
426 *nb_items = (max-min)/steps + 1;
427 #ifndef ASCENDING_INT_SETTINGS
428 *selected = (max - oldvalue) / steps;
429 #else
430 *selected = (oldvalue - min) / steps;
431 #endif
432 *function = sound_get_fn(setting_id);
434 else
436 const struct int_setting *info = setting->int_setting;
437 int min, max, step;
438 max = info->max;
439 min = info->min;
440 step = info->step;
441 *nb_items = (max-min)/step + 1;
442 #ifndef ASCENDING_INT_SETTINGS
443 *selected = (max - oldvalue) / step;
444 #else
445 *selected = (oldvalue - min) / step;
446 #endif
447 *function = info->option_callback;
450 else if (var_type == F_T_BOOL)
452 *selected = oldvalue;
453 *nb_items = 2;
454 boolfunction = setting->bool_setting->option_callback;
455 if (boolfunction)
456 *function = bool_funcwrapper;
460 bool option_screen(const struct settings_list *setting,
461 struct viewport parent[NB_SCREENS],
462 bool use_temp_var, unsigned char* option_title)
464 int action;
465 bool done = false;
466 struct gui_synclist lists;
467 int oldvalue, nb_items = 0, selected = 0, temp_var;
468 int *variable;
469 bool allow_wrap = setting->flags & F_NO_WRAP ? false : true;
470 int var_type = setting->flags&F_T_MASK;
471 void (*function)(int) = NULL;
472 char *title;
473 if (var_type == F_T_INT || var_type == F_T_UINT)
475 variable = use_temp_var ? &temp_var: (int*)setting->setting;
476 temp_var = oldvalue = *(int*)setting->setting;
478 else if (var_type == F_T_BOOL)
480 /* bools always use the temp variable...
481 if use_temp_var is false it will be copied to setting->setting every change */
482 variable = &temp_var;
483 temp_var = oldvalue = *(bool*)setting->setting?1:0;
485 else return false; /* only int/bools can go here */
486 gui_synclist_init(&lists, value_setting_get_name_cb,
487 (void*)setting, false, 1, parent);
488 if (setting->lang_id == -1)
489 title = (char*)setting->cfg_vals;
490 else
491 title = P2STR(option_title);
493 gui_synclist_set_title(&lists, title, Icon_Questionmark);
494 gui_synclist_set_icon_callback(&lists, NULL);
495 if(global_settings.talk_menu)
496 gui_synclist_set_voice_callback(&lists, option_talk);
498 val_to_selection(setting, oldvalue, &nb_items, &selected, &function);
499 gui_synclist_set_nb_items(&lists, nb_items);
500 gui_synclist_select_item(&lists, selected);
502 gui_synclist_limit_scroll(&lists, true);
503 gui_synclist_draw(&lists);
504 /* talk the item */
505 gui_synclist_speak_item(&lists);
506 while (!done)
508 if (list_do_action(CONTEXT_LIST, HZ, /* HZ so the status bar redraws */
509 &lists, &action,
510 allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
512 /* setting changed */
513 selected = gui_synclist_get_sel_pos(&lists);
514 *variable = selection_to_val(setting, selected);
515 if (var_type == F_T_BOOL && !use_temp_var)
516 *(bool*)setting->setting = (*variable==1);
518 else if (action == ACTION_NONE)
519 continue;
520 else if (action == ACTION_STD_CANCEL)
522 /* setting canceled, restore old value if changed */
523 if (*variable != oldvalue)
525 *variable = oldvalue;
526 if (var_type == F_T_BOOL && !use_temp_var)
527 *(bool*)setting->setting = (oldvalue==1);
528 splash(HZ/2, ID2P(LANG_CANCEL));
530 done = true;
532 else if (action == ACTION_STD_CONTEXT)
534 /* reset setting to default */
535 reset_setting(setting, variable);
536 if (var_type == F_T_BOOL && !use_temp_var)
537 *(bool*)setting->setting = (*variable==1);
538 val_to_selection(setting, *variable, &nb_items,
539 &selected, &function);
540 gui_synclist_select_item(&lists, selected);
541 gui_synclist_draw(&lists);
542 gui_synclist_speak_item(&lists);
544 else if (action == ACTION_STD_OK)
546 /* setting accepted, store now if it used a temp var */
547 if (use_temp_var)
549 if (var_type == F_T_INT || var_type == F_T_UINT)
550 *(int*)setting->setting = *variable;
551 else
552 *(bool*)setting->setting = (*variable==1);
554 settings_save();
555 done = true;
557 else if(default_event_handler(action) == SYS_USB_CONNECTED)
558 return true;
559 /* callback */
560 if ( function )
561 function(*variable);
562 /* if the volume is changing we need to let the skins know */
563 if (function == sound_get_fn(SOUND_VOLUME))
564 global_status.last_volume_change = current_tick;
566 return false;