* combine i2c_ack and i2c_outb
[kugel-rb.git] / apps / gui / option_select.c
blob570a41a78d8f9a9a0b207b5bef58f1ab82e0d547
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"
37 #include "menu.h"
38 #include "quickscreen.h"
40 #if defined (HAVE_SCROLLWHEEL) || \
41 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
42 (CONFIG_KEYPAD == IPOD_4G_PAD) || \
43 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
44 (CONFIG_KEYPAD == PLAYER_PAD)
45 /* Define this if your target makes sense to have
46 smaller values at the top of the list increasing down the list */
47 #define ASCENDING_INT_SETTINGS
48 #endif
50 static int selection_to_val(const struct settings_list *setting, int selection);
51 int option_value_as_int(const struct settings_list *setting)
53 int type = (setting->flags & F_T_MASK);
54 int temp = 0;
55 if (type == F_T_BOOL)
56 temp = *(bool*)setting->setting?1:0;
57 else if (type == F_T_UINT || type == F_T_INT)
58 temp = *(int*)setting->setting;
59 return temp;
61 static const char *unit_strings[] =
63 [UNIT_INT] = "", [UNIT_MS] = "ms",
64 [UNIT_SEC] = "s", [UNIT_MIN] = "min",
65 [UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz",
66 [UNIT_DB] = "dB", [UNIT_PERCENT] = "%",
67 [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
68 [UNIT_PER_SEC] = "per sec",
69 [UNIT_HERTZ] = "Hz",
70 [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s",
71 [UNIT_PM_TICK] = "units/10ms",
73 /* these two vars are needed so arbitrary values can be added to the
74 TABLE_SETTING settings if the F_ALLOW_ARBITRARY_VALS flag is set */
75 static int table_setting_oldval = 0, table_setting_array_position = 0;
76 char *option_get_valuestring(const struct settings_list *setting,
77 char *buffer, int buf_len,
78 intptr_t temp_var)
80 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
82 bool val = (bool)temp_var;
83 strncpy(buffer, str(val? setting->bool_setting->lang_yes :
84 setting->bool_setting->lang_no), buf_len);
86 #if 0 /* probably dont need this one */
87 else if ((setting->flags & F_FILENAME) == F_FILENAME)
89 struct filename_setting *info = setting->filename_setting;
90 snprintf(buffer, buf_len, "%s%s%s", info->prefix,
91 (char*)temp_var, info->suffix);
93 #endif
94 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
95 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
97 const struct int_setting *int_info = setting->int_setting;
98 const struct table_setting *tbl_info = setting->table_setting;
99 const char *unit;
100 void (*formatter)(char*, size_t, int, const char*);
101 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
103 formatter = int_info->formatter;
104 unit = unit_strings[int_info->unit];
106 else
108 formatter = tbl_info->formatter;
109 unit = unit_strings[tbl_info->unit];
111 if (formatter)
112 formatter(buffer, buf_len, (int)temp_var, unit);
113 else
114 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit?unit:"");
116 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
118 char sign = ' ', *unit;
119 unit = (char*)sound_unit(setting->sound_setting->setting);
120 if (sound_numdecimals(setting->sound_setting->setting))
122 int integer, dec;
123 int val = sound_val2phys(setting->sound_setting->setting,
124 (int)temp_var);
125 if(val < 0)
127 sign = '-';
128 val = abs(val);
130 integer = val / 10; dec = val % 10;
131 snprintf(buffer, buf_len, "%c%d.%d %s", sign, integer, dec, unit);
133 else
134 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit);
136 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
138 if (setting->flags & F_CHOICETALKS)
140 int setting_id;
141 const struct choice_setting *info = setting->choice_setting;
142 if (info->talks[(int)temp_var] < LANG_LAST_INDEX_IN_ARRAY)
144 strncpy(buffer, str(info->talks[(int)temp_var]), buf_len);
146 else
148 find_setting(setting->setting, &setting_id);
149 cfg_int_to_string(setting_id, (int)temp_var, buffer, buf_len);
152 else
154 int value= (int)temp_var;
155 char *val = P2STR(setting->choice_setting->desc[value]);
156 strncpy(buffer, val, buf_len);
159 return buffer;
161 void option_talk_value(const struct settings_list *setting, int value, bool enqueue)
163 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
165 bool val = value==1?true:false;
166 talk_id(val? setting->bool_setting->lang_yes :
167 setting->bool_setting->lang_no, enqueue);
169 #if 0 /* probably dont need this one */
170 else if ((setting->flags & F_FILENAME) == F_FILENAME)
173 #endif
174 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
175 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
177 const struct int_setting *int_info = setting->int_setting;
178 const struct table_setting *tbl_info = setting->table_setting;
179 int unit;
180 int32_t (*get_talk_id)(int, int);
181 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
183 unit = int_info->unit;
184 get_talk_id = int_info->get_talk_id;
186 else
188 unit = tbl_info->unit;
189 get_talk_id = tbl_info->get_talk_id;
191 if (get_talk_id)
192 talk_id(get_talk_id(value, unit), enqueue);
193 else
194 talk_value(value, unit, enqueue);
196 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
198 int talkunit = UNIT_INT;
199 const char *unit = sound_unit(setting->sound_setting->setting);
200 if (!strcmp(unit, "dB"))
201 talkunit = UNIT_DB;
202 else if (!strcmp(unit, "%"))
203 talkunit = UNIT_PERCENT;
204 else if (!strcmp(unit, "Hz"))
205 talkunit = UNIT_HERTZ;
206 talk_value(value, talkunit, false);
208 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
210 if (setting->flags & F_CHOICETALKS)
212 talk_id(setting->choice_setting->talks[value], enqueue);
214 else
216 talk_id(P2ID(setting->choice_setting->desc[value]), enqueue);
221 static int option_talk(int selected_item, void * data)
223 struct settings_list *setting = (struct settings_list *)data;
224 int temp_var = selection_to_val(setting, selected_item);
225 option_talk_value(setting, temp_var, false);
226 return 0;
229 #if defined(HAVE_QUICKSCREEN) || defined(HAVE_RECORDING)
230 /* only the quickscreen and recording trigger needs this */
231 void option_select_next_val(const struct settings_list *setting,
232 bool previous, bool apply)
234 int val = 0;
235 int *value = setting->setting;
236 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
238 *(bool*)value = !*(bool*)value;
239 if (apply && setting->bool_setting->option_callback)
240 setting->bool_setting->option_callback(*(bool*)value);
241 return;
243 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
245 struct int_setting *info = (struct int_setting *)setting->int_setting;
246 int step = info->step;
247 if (step < 0)
248 step = -step;
249 if (!previous)
251 val = *value + step;
252 if (val > info->max)
253 val = info->min;
255 else
257 val = *value - step;
258 if (val < info->min)
259 val = info->max;
261 if (apply && info->option_callback)
262 info->option_callback(val);
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 if (!previous)
272 val = *value + steps;
273 if (val >= max)
274 val = min;
276 else
278 val = *value - steps;
279 if (val < min)
280 val = max;
283 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
285 struct choice_setting *info = (struct choice_setting *)setting->choice_setting;
286 val = *value + 1;
287 if (!previous)
289 val = *value + 1;
290 if (val >= info->count)
291 val = 0;
293 else
295 val = *value - 1;
296 if (val < 0)
297 val = info->count-1;
299 if (apply && info->option_callback)
300 info->option_callback(val);
302 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
304 const struct table_setting *tbl_info = setting->table_setting;
305 int i, add;
306 add = previous?tbl_info->count-1:1;
307 for (i=0; i<tbl_info->count;i++)
309 if ((*value == tbl_info->values[i]) ||
310 (settings->flags&F_ALLOW_ARBITRARY_VALS &&
311 *value < tbl_info->values[i]))
313 val = tbl_info->values[(i+add)%tbl_info->count];
314 break;
318 *value = val;
320 #endif
322 static int selection_to_val(const struct settings_list *setting, int selection)
324 int min = 0, max = 0, step = 1;
325 if (((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) ||
326 ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING))
327 return selection;
328 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
330 const struct table_setting *info = setting->table_setting;
331 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
332 table_setting_array_position != -1 &&
333 (selection >= table_setting_array_position))
335 if (selection == table_setting_array_position)
336 return table_setting_oldval;
337 return info->values[selection-1];
339 else
340 return info->values[selection];
342 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
344 int setting_id = setting->sound_setting->setting;
345 #ifndef ASCENDING_INT_SETTINGS
346 step = sound_steps(setting_id);
347 max = sound_max(setting_id);
348 min = sound_min(setting_id);
349 #else
350 step = -sound_steps(setting_id);
351 min = sound_max(setting_id);
352 max = sound_min(setting_id);
353 #endif
355 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
357 const struct int_setting *info = setting->int_setting;
358 #ifndef ASCENDING_INT_SETTINGS
359 min = info->min;
360 max = info->max;
361 step = info->step;
362 #else
363 max = info->min;
364 min = info->max;
365 step = -info->step;
366 #endif
368 return max- (selection * step);
370 static char * value_setting_get_name_cb(int selected_item,
371 void * data,
372 char *buffer,
373 size_t buffer_len)
375 selected_item = selection_to_val(data, selected_item);
376 return option_get_valuestring(data, buffer, buffer_len, selected_item);
379 /* wrapper to convert from int param to bool param in option_screen */
380 static void (*boolfunction)(bool);
381 static void bool_funcwrapper(int value)
383 if (value)
384 boolfunction(true);
385 else
386 boolfunction(false);
389 static void val_to_selection(const struct settings_list *setting, int oldvalue,
390 int *nb_items, int *selected,
391 void (**function)(int))
393 int var_type = setting->flags&F_T_MASK;
394 /* set the number of items and current selection */
395 if (var_type == F_T_INT || var_type == F_T_UINT)
397 if (setting->flags&F_CHOICE_SETTING)
399 *nb_items = setting->choice_setting->count;
400 *selected = oldvalue;
401 *function = setting->choice_setting->option_callback;
403 else if (setting->flags&F_TABLE_SETTING)
405 const struct table_setting *info = setting->table_setting;
406 int i;
407 *nb_items = info->count;
408 *selected = -1;
409 table_setting_array_position = -1;
410 for (i=0;*selected==-1 && i<*nb_items;i++)
412 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
413 (oldvalue < info->values[i]))
415 table_setting_oldval = oldvalue;
416 table_setting_array_position = i;
417 *selected = i;
418 (*nb_items)++;
420 else if (oldvalue == info->values[i])
421 *selected = i;
423 *function = info->option_callback;
425 else if (setting->flags&F_T_SOUND)
427 int setting_id = setting->sound_setting->setting;
428 int steps = sound_steps(setting_id);
429 int min = sound_min(setting_id);
430 int max = sound_max(setting_id);
431 *nb_items = (max-min)/steps + 1;
432 #ifndef ASCENDING_INT_SETTINGS
433 *selected = (max - oldvalue) / steps;
434 #else
435 *selected = (oldvalue - min) / steps;
436 #endif
437 *function = sound_get_fn(setting_id);
439 else
441 const struct int_setting *info = setting->int_setting;
442 int min, max, step;
443 max = info->max;
444 min = info->min;
445 step = info->step;
446 *nb_items = (max-min)/step + 1;
447 #ifndef ASCENDING_INT_SETTINGS
448 *selected = (max - oldvalue) / step;
449 #else
450 *selected = (oldvalue - min) / step;
451 #endif
452 *function = info->option_callback;
455 else if (var_type == F_T_BOOL)
457 *selected = oldvalue;
458 *nb_items = 2;
459 boolfunction = setting->bool_setting->option_callback;
460 if (boolfunction)
461 *function = bool_funcwrapper;
465 bool option_screen(const struct settings_list *setting,
466 struct viewport parent[NB_SCREENS],
467 bool use_temp_var, unsigned char* option_title)
469 int action;
470 bool done = false;
471 struct gui_synclist lists;
472 int oldvalue, nb_items = 0, selected = 0, temp_var;
473 int *variable;
474 bool allow_wrap = setting->flags & F_NO_WRAP ? false : true;
475 int var_type = setting->flags&F_T_MASK;
476 void (*function)(int) = NULL;
477 char *title;
478 if (var_type == F_T_INT || var_type == F_T_UINT)
480 variable = use_temp_var ? &temp_var: (int*)setting->setting;
481 temp_var = oldvalue = *(int*)setting->setting;
483 else if (var_type == F_T_BOOL)
485 /* bools always use the temp variable...
486 if use_temp_var is false it will be copied to setting->setting every change */
487 variable = &temp_var;
488 temp_var = oldvalue = *(bool*)setting->setting?1:0;
490 else return false; /* only int/bools can go here */
491 gui_synclist_init(&lists, value_setting_get_name_cb,
492 (void*)setting, false, 1, parent);
493 if (setting->lang_id == -1)
494 title = (char*)setting->cfg_vals;
495 else
496 title = P2STR(option_title);
498 gui_synclist_set_title(&lists, title, Icon_Questionmark);
499 gui_synclist_set_icon_callback(&lists, NULL);
500 if(global_settings.talk_menu)
501 gui_synclist_set_voice_callback(&lists, option_talk);
503 val_to_selection(setting, oldvalue, &nb_items, &selected, &function);
504 gui_synclist_set_nb_items(&lists, nb_items);
505 gui_synclist_select_item(&lists, selected);
507 gui_synclist_limit_scroll(&lists, true);
508 gui_synclist_draw(&lists);
509 /* talk the item */
510 gui_synclist_speak_item(&lists);
511 gui_syncstatusbar_draw(&statusbars, false);
512 while (!done)
514 if (list_do_action(CONTEXT_LIST, TIMEOUT_BLOCK,
515 &lists, &action,
516 allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
518 /* setting changed */
519 selected = gui_synclist_get_sel_pos(&lists);
520 *variable = selection_to_val(setting, selected);
521 if (var_type == F_T_BOOL && !use_temp_var)
522 *(bool*)setting->setting = (*variable==1);
524 else if (action == ACTION_NONE)
525 continue;
526 else if (action == ACTION_STD_CANCEL)
528 /* setting canceled, restore old value if changed */
529 if (*variable != oldvalue)
531 *variable = oldvalue;
532 if (var_type == F_T_BOOL && !use_temp_var)
533 *(bool*)setting->setting = (oldvalue==1);
534 splash(HZ/2, ID2P(LANG_CANCEL));
536 done = true;
538 else if (action == ACTION_STD_CONTEXT)
540 /* reset setting to default */
541 reset_setting(setting, variable);
542 if (var_type == F_T_BOOL && !use_temp_var)
543 *(bool*)setting->setting = (*variable==1);
544 val_to_selection(setting, *variable, &nb_items,
545 &selected, &function);
546 gui_synclist_select_item(&lists, selected);
547 gui_synclist_draw(&lists);
548 gui_synclist_speak_item(&lists);
550 else if (action == ACTION_STD_OK)
552 /* setting accepted, store now if it used a temp var */
553 if (use_temp_var)
555 if (var_type == F_T_INT || var_type == F_T_UINT)
556 *(int*)setting->setting = *variable;
557 else
558 *(bool*)setting->setting = (*variable==1);
560 settings_save();
561 done = true;
563 else if(default_event_handler(action) == SYS_USB_CONNECTED)
564 return true;
565 gui_syncstatusbar_draw(&statusbars, false);
566 /* callback */
567 if ( function )
568 function(*variable);
570 return false;