Introduce names for header and row color in the tables so that they are the same...
[kugel-rb.git] / apps / gui / option_select.c
blobd806a0aa0824d0e94cfe09b0559805335065d013
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 "misc.h"
35 #include "splash.h"
36 #include "menu.h"
37 #include "quickscreen.h"
39 #if defined (HAVE_SCROLLWHEEL) || \
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);
47 int option_value_as_int(const struct settings_list *setting)
49 int type = (setting->flags & F_T_MASK);
50 int temp = 0;
51 if (type == F_T_BOOL)
52 temp = *(bool*)setting->setting?1:0;
53 else if (type == F_T_UINT || type == F_T_INT)
54 temp = *(int*)setting->setting;
55 return temp;
57 static const char *unit_strings[] =
59 [UNIT_INT] = "", [UNIT_MS] = "ms",
60 [UNIT_SEC] = "s", [UNIT_MIN] = "min",
61 [UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz",
62 [UNIT_DB] = "dB", [UNIT_PERCENT] = "%",
63 [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
64 [UNIT_PER_SEC] = "per sec",
65 [UNIT_HERTZ] = "Hz",
66 [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s",
67 [UNIT_PM_TICK] = "units/10ms",
69 /* these two vars are needed so arbitrary values can be added to the
70 TABLE_SETTING settings if the F_ALLOW_ARBITRARY_VALS flag is set */
71 static int table_setting_oldval = 0, table_setting_array_position = 0;
72 const char *option_get_valuestring(const struct settings_list *setting,
73 char *buffer, int buf_len,
74 intptr_t temp_var)
76 const char* str = buffer;
77 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
79 bool val = (bool)temp_var;
80 strlcpy(buffer, str(val? setting->bool_setting->lang_yes :
81 setting->bool_setting->lang_no), buf_len);
83 #if 0 /* probably dont need this one */
84 else if ((setting->flags & F_FILENAME) == F_FILENAME)
86 struct filename_setting *info = setting->filename_setting;
87 snprintf(buffer, buf_len, "%s%s%s", info->prefix,
88 (char*)temp_var, info->suffix);
90 #endif
91 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
92 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
94 const struct int_setting *int_info = setting->int_setting;
95 const struct table_setting *tbl_info = setting->table_setting;
96 const char *unit;
97 const char* (*formatter)(char*, size_t, int, const char*);
98 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
100 formatter = int_info->formatter;
101 unit = unit_strings[int_info->unit];
103 else
105 formatter = tbl_info->formatter;
106 unit = unit_strings[tbl_info->unit];
108 if (formatter)
109 str = formatter(buffer, buf_len, (int)temp_var, unit);
110 else
111 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit?unit:"");
113 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
115 char sign = ' ', *unit;
116 unit = (char*)sound_unit(setting->sound_setting->setting);
117 if (sound_numdecimals(setting->sound_setting->setting))
119 int integer, dec;
120 int val = sound_val2phys(setting->sound_setting->setting,
121 (int)temp_var);
122 if(val < 0)
124 sign = '-';
125 val = abs(val);
127 integer = val / 10; dec = val % 10;
128 snprintf(buffer, buf_len, "%c%d.%d %s", sign, integer, dec, unit);
130 else
131 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit);
133 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
135 if (setting->flags & F_CHOICETALKS)
137 int setting_id;
138 const struct choice_setting *info = setting->choice_setting;
139 if (info->talks[(int)temp_var] < LANG_LAST_INDEX_IN_ARRAY)
141 strlcpy(buffer, str(info->talks[(int)temp_var]), buf_len);
143 else
145 find_setting(setting->setting, &setting_id);
146 cfg_int_to_string(setting_id, (int)temp_var, buffer, buf_len);
149 else
151 int value= (int)temp_var;
152 char *val = P2STR(setting->choice_setting->desc[value]);
153 strlcpy(buffer, val, buf_len);
156 return str;
158 void option_talk_value(const struct settings_list *setting, int value, bool enqueue)
160 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
162 bool val = (value==1);
163 talk_id(val? setting->bool_setting->lang_yes :
164 setting->bool_setting->lang_no, enqueue);
166 #if 0 /* probably dont need this one */
167 else if ((setting->flags & F_FILENAME) == F_FILENAME)
170 #endif
171 else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) ||
172 ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING))
174 const struct int_setting *int_info = setting->int_setting;
175 const struct table_setting *tbl_info = setting->table_setting;
176 int unit;
177 int32_t (*get_talk_id)(int, int);
178 if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
180 unit = int_info->unit;
181 get_talk_id = int_info->get_talk_id;
183 else
185 unit = tbl_info->unit;
186 get_talk_id = tbl_info->get_talk_id;
188 if (get_talk_id)
189 talk_id(get_talk_id(value, unit), enqueue);
190 else
191 talk_value(value, unit, enqueue);
193 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
195 int talkunit = UNIT_INT;
196 const char *unit = sound_unit(setting->sound_setting->setting);
197 if (!strcmp(unit, "dB"))
198 talkunit = UNIT_DB;
199 else if (!strcmp(unit, "%"))
200 talkunit = UNIT_PERCENT;
201 else if (!strcmp(unit, "Hz"))
202 talkunit = UNIT_HERTZ;
203 talk_value(value, talkunit, false);
205 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
207 if (setting->flags & F_CHOICETALKS)
209 talk_id(setting->choice_setting->talks[value], enqueue);
211 else
213 talk_id(P2ID(setting->choice_setting->desc[value]), enqueue);
218 static int option_talk(int selected_item, void * data)
220 struct settings_list *setting = (struct settings_list *)data;
221 int temp_var = selection_to_val(setting, selected_item);
222 option_talk_value(setting, temp_var, false);
223 return 0;
226 #if defined(HAVE_QUICKSCREEN) || defined(HAVE_RECORDING)
227 /* only the quickscreen and recording trigger needs this */
228 void option_select_next_val(const struct settings_list *setting,
229 bool previous, bool apply)
231 int val = 0;
232 int *value = setting->setting;
233 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
235 *(bool*)value = !*(bool*)value;
236 if (apply && setting->bool_setting->option_callback)
237 setting->bool_setting->option_callback(*(bool*)value);
238 return;
240 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
242 struct int_setting *info = (struct int_setting *)setting->int_setting;
243 int step = info->step;
244 if (step < 0)
245 step = -step;
246 if (!previous)
248 val = *value + step;
249 if (val > info->max)
250 val = info->min;
252 else
254 val = *value - step;
255 if (val < info->min)
256 val = info->max;
258 if (apply && info->option_callback)
259 info->option_callback(val);
261 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
263 int setting_id = setting->sound_setting->setting;
264 int steps = sound_steps(setting_id);
265 int min = sound_min(setting_id);
266 int max = sound_max(setting_id);
267 if (!previous)
269 val = *value + steps;
270 if (val >= max)
271 val = min;
273 else
275 val = *value - steps;
276 if (val < min)
277 val = max;
280 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
282 struct choice_setting *info = (struct choice_setting *)setting->choice_setting;
283 val = *value + 1;
284 if (!previous)
286 val = *value + 1;
287 if (val >= info->count)
288 val = 0;
290 else
292 val = *value - 1;
293 if (val < 0)
294 val = info->count-1;
296 if (apply && info->option_callback)
297 info->option_callback(val);
299 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
301 const struct table_setting *tbl_info = setting->table_setting;
302 int i, add;
303 add = previous?tbl_info->count-1:1;
304 for (i=0; i<tbl_info->count;i++)
306 if ((*value == tbl_info->values[i]) ||
307 (settings->flags&F_ALLOW_ARBITRARY_VALS &&
308 *value < tbl_info->values[i]))
310 val = tbl_info->values[(i+add)%tbl_info->count];
311 break;
315 *value = val;
317 #endif
319 static int selection_to_val(const struct settings_list *setting, int selection)
321 int min = 0, max = 0, step = 1;
322 if (((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) ||
323 ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING))
324 return selection;
325 else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
327 const struct table_setting *info = setting->table_setting;
328 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
329 table_setting_array_position != -1 &&
330 (selection >= table_setting_array_position))
332 if (selection == table_setting_array_position)
333 return table_setting_oldval;
334 return info->values[selection-1];
336 else
337 return info->values[selection];
339 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
341 int setting_id = setting->sound_setting->setting;
342 #ifndef ASCENDING_INT_SETTINGS
343 step = sound_steps(setting_id);
344 max = sound_max(setting_id);
345 min = sound_min(setting_id);
346 #else
347 step = -sound_steps(setting_id);
348 min = sound_max(setting_id);
349 max = sound_min(setting_id);
350 #endif
352 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
354 const struct int_setting *info = setting->int_setting;
355 #ifndef ASCENDING_INT_SETTINGS
356 min = info->min;
357 max = info->max;
358 step = info->step;
359 #else
360 max = info->min;
361 min = info->max;
362 step = -info->step;
363 #endif
365 return max- (selection * step);
368 static const char * value_setting_get_name_cb(int selected_item,
369 void * data,
370 char *buffer,
371 size_t buffer_len)
373 selected_item = selection_to_val(data, selected_item);
374 return option_get_valuestring(data, buffer, buffer_len, selected_item);
377 /* wrapper to convert from int param to bool param in option_screen */
378 static void (*boolfunction)(bool);
379 static void bool_funcwrapper(int value)
381 if (value)
382 boolfunction(true);
383 else
384 boolfunction(false);
387 static void val_to_selection(const struct settings_list *setting, int oldvalue,
388 int *nb_items, int *selected,
389 void (**function)(int))
391 int var_type = setting->flags&F_T_MASK;
392 /* set the number of items and current selection */
393 if (var_type == F_T_INT || var_type == F_T_UINT)
395 if (setting->flags&F_CHOICE_SETTING)
397 *nb_items = setting->choice_setting->count;
398 *selected = oldvalue;
399 *function = setting->choice_setting->option_callback;
401 else if (setting->flags&F_TABLE_SETTING)
403 const struct table_setting *info = setting->table_setting;
404 int i;
405 *nb_items = info->count;
406 *selected = -1;
407 table_setting_array_position = -1;
408 for (i=0;*selected==-1 && i<*nb_items;i++)
410 if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
411 (oldvalue < info->values[i]))
413 table_setting_oldval = oldvalue;
414 table_setting_array_position = i;
415 *selected = i;
416 (*nb_items)++;
418 else if (oldvalue == info->values[i])
419 *selected = i;
421 *function = info->option_callback;
423 else if (setting->flags&F_T_SOUND)
425 int setting_id = setting->sound_setting->setting;
426 int steps = sound_steps(setting_id);
427 int min = sound_min(setting_id);
428 int max = sound_max(setting_id);
429 *nb_items = (max-min)/steps + 1;
430 #ifndef ASCENDING_INT_SETTINGS
431 *selected = (max - oldvalue) / steps;
432 #else
433 *selected = (oldvalue - min) / steps;
434 #endif
435 *function = sound_get_fn(setting_id);
437 else
439 const struct int_setting *info = setting->int_setting;
440 int min, max, step;
441 max = info->max;
442 min = info->min;
443 step = info->step;
444 *nb_items = (max-min)/step + 1;
445 #ifndef ASCENDING_INT_SETTINGS
446 *selected = (max - oldvalue) / step;
447 #else
448 *selected = (oldvalue - min) / step;
449 #endif
450 *function = info->option_callback;
453 else if (var_type == F_T_BOOL)
455 *selected = oldvalue;
456 *nb_items = 2;
457 boolfunction = setting->bool_setting->option_callback;
458 if (boolfunction)
459 *function = bool_funcwrapper;
463 bool option_screen(const struct settings_list *setting,
464 struct viewport parent[NB_SCREENS],
465 bool use_temp_var, unsigned char* option_title)
467 int action;
468 bool done = false;
469 struct gui_synclist lists;
470 int oldvalue, nb_items = 0, selected = 0, temp_var;
471 int *variable;
472 bool allow_wrap = setting->flags & F_NO_WRAP ? false : true;
473 int var_type = setting->flags&F_T_MASK;
474 void (*function)(int) = NULL;
475 char *title;
476 if (var_type == F_T_INT || var_type == F_T_UINT)
478 variable = use_temp_var ? &temp_var: (int*)setting->setting;
479 temp_var = oldvalue = *(int*)setting->setting;
481 else if (var_type == F_T_BOOL)
483 /* bools always use the temp variable...
484 if use_temp_var is false it will be copied to setting->setting every change */
485 variable = &temp_var;
486 temp_var = oldvalue = *(bool*)setting->setting?1:0;
488 else return false; /* only int/bools can go here */
489 gui_synclist_init(&lists, value_setting_get_name_cb,
490 (void*)setting, false, 1, parent);
491 if (setting->lang_id == -1)
492 title = (char*)setting->cfg_vals;
493 else
494 title = P2STR(option_title);
496 gui_synclist_set_title(&lists, title, Icon_Questionmark);
497 gui_synclist_set_icon_callback(&lists, NULL);
498 if(global_settings.talk_menu)
499 gui_synclist_set_voice_callback(&lists, option_talk);
501 val_to_selection(setting, oldvalue, &nb_items, &selected, &function);
502 gui_synclist_set_nb_items(&lists, nb_items);
503 gui_synclist_select_item(&lists, selected);
505 gui_synclist_limit_scroll(&lists, true);
506 gui_synclist_draw(&lists);
507 /* talk the item */
508 gui_synclist_speak_item(&lists);
509 while (!done)
511 if (list_do_action(CONTEXT_LIST, TIMEOUT_BLOCK,
512 &lists, &action,
513 allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
515 /* setting changed */
516 selected = gui_synclist_get_sel_pos(&lists);
517 *variable = selection_to_val(setting, selected);
518 if (var_type == F_T_BOOL && !use_temp_var)
519 *(bool*)setting->setting = (*variable==1);
521 else if (action == ACTION_NONE)
522 continue;
523 else if (action == ACTION_STD_CANCEL)
525 /* setting canceled, restore old value if changed */
526 if (*variable != oldvalue)
528 *variable = oldvalue;
529 if (var_type == F_T_BOOL && !use_temp_var)
530 *(bool*)setting->setting = (oldvalue==1);
531 splash(HZ/2, ID2P(LANG_CANCEL));
533 done = true;
535 else if (action == ACTION_STD_CONTEXT)
537 /* reset setting to default */
538 reset_setting(setting, variable);
539 if (var_type == F_T_BOOL && !use_temp_var)
540 *(bool*)setting->setting = (*variable==1);
541 val_to_selection(setting, *variable, &nb_items,
542 &selected, &function);
543 gui_synclist_select_item(&lists, selected);
544 gui_synclist_draw(&lists);
545 gui_synclist_speak_item(&lists);
547 else if (action == ACTION_STD_OK)
549 /* setting accepted, store now if it used a temp var */
550 if (use_temp_var)
552 if (var_type == F_T_INT || var_type == F_T_UINT)
553 *(int*)setting->setting = *variable;
554 else
555 *(bool*)setting->setting = (*variable==1);
557 settings_save();
558 done = true;
560 else if(default_event_handler(action) == SYS_USB_CONNECTED)
561 return true;
562 /* callback */
563 if ( function )
564 function(*variable);
566 return false;