Try to translate items when using the STRINGCHOICE_SETTING() macro (fixes FS#7603)
[Rockbox.git] / apps / gui / option_select.c
blobddd0f7f9b792ea9c2c209dc2c970c601e1a27717
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 "config.h"
22 #include "option_select.h"
23 #include "sprintf.h"
24 #include "kernel.h"
25 #include "lang.h"
26 #include "talk.h"
27 #include "settings_list.h"
28 #include "sound.h"
29 #include "list.h"
30 #include "action.h"
31 #include "statusbar.h"
32 #include "misc.h"
33 #include "splash.h"
35 static const char *unit_strings[] =
37 [UNIT_INT] = "", [UNIT_MS] = "ms",
38 [UNIT_SEC] = "s", [UNIT_MIN] = "min",
39 [UNIT_HOUR]= "hr", [UNIT_KHZ] = "KHz",
40 [UNIT_DB] = "dB", [UNIT_PERCENT] = "%",
41 [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
42 [UNIT_PER_SEC] = "per sec",
43 [UNIT_HERTZ] = "Hz",
44 [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s",
47 char *option_get_valuestring(struct settings_list *setting,
48 char *buffer, int buf_len,
49 intptr_t temp_var)
51 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
53 bool val = (bool)temp_var;
54 snprintf(buffer, buf_len, "%s",
55 str(val? setting->bool_setting->lang_yes :
56 setting->bool_setting->lang_no));
58 #if 0 /* probably dont need this one */
59 else if ((setting->flags & F_FILENAME) == F_FILENAME)
61 struct filename_setting *info = setting->filename_setting;
62 snprintf(buffer, buf_len, "%s%s%s", info->prefix,
63 (char*)temp_var, info->suffix);
65 #endif
66 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
68 struct int_setting *info = setting->int_setting;
69 if (info->formatter)
70 info->formatter(buffer, buf_len, (int)temp_var,
71 unit_strings[info->unit]);
72 else
73 snprintf(buffer, buf_len, "%d %s", (int)temp_var,
74 unit_strings[info->unit]?
75 unit_strings[info->unit]:"");
77 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
79 char sign = ' ', *unit;
80 unit = (char*)sound_unit(setting->sound_setting->setting);
81 if (sound_numdecimals(setting->sound_setting->setting))
83 int integer, dec;
84 int val = sound_val2phys(setting->sound_setting->setting,
85 (int)temp_var);
86 if(val < 0)
88 sign = '-';
89 val = abs(val);
91 integer = val / 10; dec = val % 10;
92 snprintf(buffer, buf_len, "%c%d.%d %s", sign, integer, dec, unit);
94 else
95 snprintf(buffer, buf_len, "%d %s", (int)temp_var, unit);
97 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
99 if (setting->flags & F_CHOICETALKS)
101 int setting_id;
102 struct choice_setting *info = setting->choice_setting;
103 if (info->talks[(int)temp_var] < LANG_LAST_INDEX_IN_ARRAY)
105 snprintf(buffer, buf_len, "%s", str(info->talks[(int)temp_var]));
107 else
109 find_setting(setting->setting, &setting_id);
110 cfg_int_to_string(setting_id, (int)temp_var, buffer, buf_len);
113 else
115 int value= (int)temp_var;
116 char *val = P2STR(setting->choice_setting->desc[value]);
117 snprintf(buffer, buf_len, "%s", val);
120 return buffer;
123 void option_talk(struct settings_list *setting, int temp_var)
125 if (!talk_menus_enabled())
126 return;
127 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
129 bool val = temp_var==1?true:false;
130 talk_id(val? setting->bool_setting->lang_yes :
131 setting->bool_setting->lang_no, false);
133 #if 0 /* probably dont need this one */
134 else if ((setting->flags & F_FILENAME) == F_FILENAME)
137 #endif
138 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
140 struct int_setting *info = setting->int_setting;
141 if (info->get_talk_id)
142 talk_id(info->get_talk_id((int)temp_var), false);
143 else
144 talk_value((int)temp_var, info->unit, false);
146 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
148 int talkunit = UNIT_DB;
149 const char *unit = sound_unit(setting->sound_setting->setting);
150 /* crude reconstruction */
151 if (*unit == '%')
152 talkunit = UNIT_PERCENT;
153 else if (*unit == 'H')
154 talkunit = UNIT_HERTZ;
155 talk_value((int)temp_var, talkunit, false);
157 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
159 int value = (int)temp_var;
160 if (setting->flags & F_CHOICETALKS)
162 talk_id(setting->choice_setting->talks[value], false);
164 else
166 talk_id(P2ID(setting->choice_setting->desc[value]), false);
170 #if 0
171 int option_select_next_val(struct settings_list *setting,
172 intptr_t temp_var)
174 int val = 0;
175 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
177 val = (bool)temp_var ? 0 : 1;
179 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
181 struct int_setting *info = setting->int_setting;
182 val = (int)temp_var + info->step;
183 if (val > info->max)
184 val = info->min;
186 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
188 int setting_id = setting->sound_setting->setting;
189 int steps = sound_steps(setting_id);
190 int min = sound_min(setting_id);
191 int max = sound_max(setting_id);
192 val = (int)temp_var + steps;
193 if (val > max)
194 val = min;
196 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
198 struct choice_setting *info = setting->choice_setting;
199 val = (int)temp_var;
200 if (val > info->count)
201 val = 0;
203 return val;
206 int option_select_prev_val(struct settings_list *setting,
207 intptr_t temp_var)
209 int val = 0;
210 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
212 val = (bool)temp_var ? 0 : 1;
214 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
216 struct int_setting *info = setting->int_setting;
217 val = (int)temp_var - info->step;
218 if (val < info->min)
219 val = info->max;
221 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
223 int setting_id = setting->sound_setting->setting;
224 int steps = sound_steps(setting_id);
225 int min = sound_min(setting_id);
226 int max = sound_max(setting_id);
227 val = (int)temp_var -+ steps;
228 if (val < min)
229 val = max;
231 else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING)
233 struct choice_setting *info = setting->choice_setting;
234 val = (int)temp_var;
235 if (val < 0)
236 val = info->count - 1;
238 return val;
240 #endif
242 static int selection_to_val(struct settings_list *setting, int selection)
244 int min = 0, max = 0, step = 1;
245 if (((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) ||
246 ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING))
247 return selection;
248 else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
250 int setting_id = setting->sound_setting->setting;
251 step = sound_steps(setting_id);
252 max = sound_max(setting_id);
253 min = sound_min(setting_id);
255 else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
257 struct int_setting *info = setting->int_setting;
258 min = info->min;
259 max = info->max;
260 step = info->step;
262 if (setting->flags & F_FLIPLIST)
264 int a;
265 a = min; min = max; max = a;
266 step = -step;
268 return max- (selection * step);
270 static char * value_setting_get_name_cb(int selected_item,
271 void * data, char *buffer)
273 selected_item = selection_to_val(data, selected_item);
274 return option_get_valuestring(data, buffer, MAX_PATH, selected_item);
277 /* wrapper to convert from int param to bool param in option_screen */
278 static void (*boolfunction)(bool);
279 static void bool_funcwrapper(int value)
281 if (value)
282 boolfunction(true);
283 else
284 boolfunction(false);
287 bool option_screen(struct settings_list *setting,
288 bool use_temp_var, unsigned char* option_title)
290 int action;
291 bool done = false;
292 struct gui_synclist lists;
293 int oldvalue, nb_items = 0, selected = 0, temp_var;
294 int *variable;
295 bool allow_wrap = ((int*)setting->setting != &global_settings.volume);
296 int var_type = setting->flags&F_T_MASK;
297 void (*function)(int) = NULL;
298 char *title;
299 if (var_type == F_T_INT || var_type == F_T_UINT)
301 variable = use_temp_var ? &temp_var: (int*)setting->setting;
302 temp_var = oldvalue = *(int*)setting->setting;
304 else if (var_type == F_T_BOOL)
306 /* bools always use the temp variable...
307 if use_temp_var is false it will be copied to setting->setting every change */
308 variable = &temp_var;
309 temp_var = oldvalue = *(bool*)setting->setting?1:0;
311 else return false; /* only int/bools can go here */
312 gui_synclist_init(&lists, value_setting_get_name_cb,
313 (void*)setting, false, 1);
314 if (setting->lang_id == -1)
315 title = (char*)setting->cfg_vals;
316 else
317 title = P2STR(option_title);
319 gui_synclist_set_title(&lists, title, Icon_Questionmark);
320 gui_synclist_set_icon_callback(&lists, NULL);
322 /* set the number of items and current selection */
323 if (var_type == F_T_INT || var_type == F_T_UINT)
325 if (setting->flags&F_CHOICE_SETTING)
327 nb_items = setting->choice_setting->count;
328 selected = oldvalue;
329 function = setting->choice_setting->option_callback;
331 else if (setting->flags&F_T_SOUND)
333 int setting_id = setting->sound_setting->setting;
334 int steps = sound_steps(setting_id);
335 int min = sound_min(setting_id);
336 int max = sound_max(setting_id);
337 nb_items = (max-min)/steps + 1;
338 selected = (max-oldvalue)/steps;
339 function = sound_get_fn(setting_id);
341 else
343 struct int_setting *info = setting->int_setting;
344 int min, max, step;
345 if (setting->flags&F_FLIPLIST)
347 min = info->max;
348 max = info->min;
349 step = -info->step;
351 else
353 max = info->max;
354 min = info->min;
355 step = info->step;
357 nb_items = (max-min)/step + 1;
358 selected = (max - oldvalue)/step;
359 function = info->option_callback;
362 else if (var_type == F_T_BOOL)
364 selected = oldvalue;
365 nb_items = 2;
366 boolfunction = setting->bool_setting->option_callback;
367 if (boolfunction)
368 function = bool_funcwrapper;
371 gui_synclist_set_nb_items(&lists, nb_items);
372 gui_synclist_select_item(&lists, selected);
374 gui_synclist_limit_scroll(&lists, true);
375 gui_synclist_draw(&lists);
376 /* talk the item */
377 option_talk(setting, *variable);
378 while (!done)
380 action = get_action(CONTEXT_LIST, TIMEOUT_BLOCK);
381 if (action == ACTION_NONE)
382 continue;
383 if (gui_synclist_do_button(&lists,action,
384 allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
386 selected = gui_synclist_get_sel_pos(&lists);
387 *variable = selection_to_val(setting, selected);
388 if (var_type == F_T_BOOL)
390 if (!use_temp_var)
391 *(bool*)setting->setting = selected==1?true:false;
393 /* talk */
394 option_talk(setting, *variable);
396 else if (action == ACTION_STD_CANCEL)
398 bool show_cancel = false;
399 if (use_temp_var)
400 show_cancel = true;
401 else if (var_type == F_T_INT || var_type == F_T_UINT)
403 if (*variable != oldvalue)
405 show_cancel = true;
406 *variable = oldvalue;
409 else
411 if (*variable != oldvalue)
413 show_cancel = true;
414 if (!use_temp_var)
415 *(bool*)setting->setting = oldvalue==1?true:false;
416 *variable = oldvalue;
419 if (show_cancel)
420 gui_syncsplash(HZ/2, str(LANG_CANCEL));
421 done = true;
423 else if (action == ACTION_STD_OK)
425 done = true;
427 else if(default_event_handler(action) == SYS_USB_CONNECTED)
428 return true;
429 gui_syncstatusbar_draw(&statusbars, false);
430 /* callback */
431 if ( function )
432 function(*variable);
435 if (oldvalue != *variable)
437 if (use_temp_var)
439 if (var_type == F_T_INT || var_type == F_T_UINT)
440 *(int*)setting->setting = *variable;
441 else
442 *(bool*)setting->setting = *variable?true:false;
444 settings_save();
447 return false;
450 /******************************************************
451 Compatability functions
452 *******************************************************/
453 #define MAX_OPTIONS 32
454 bool set_option(const char* string, void* variable, enum optiontype type,
455 const struct opt_items* options,
456 int numoptions, void (*function)(int))
458 int temp;
459 char *strings[MAX_OPTIONS];
460 struct choice_setting data;
461 struct settings_list item;
462 for (temp=0; temp<MAX_OPTIONS && temp<numoptions; temp++)
463 strings[temp] = (char*)options[temp].string;
464 if (type == BOOL)
466 temp = *(bool*)variable? 1: 0;
467 item.setting = &temp;
469 else
470 item.setting = variable;
471 item.flags = F_CHOICE_SETTING|F_T_INT;
472 item.lang_id = -1;
473 item.cfg_vals = (char*)string;
474 data.count = numoptions<MAX_OPTIONS ? numoptions: MAX_OPTIONS;
475 data.desc = (void*)strings; /* shutup gcc... */
476 data.option_callback = function;
477 item.choice_setting = &data;
478 option_screen(&item, false, NULL);
479 if (type == BOOL)
481 *(bool*)variable = (temp == 1? true: false);
483 return false;
486 bool set_int_ex(const unsigned char* string,
487 const char* unit,
488 int voice_unit,
489 int* variable,
490 void (*function)(int),
491 int step,
492 int min,
493 int max,
494 void (*formatter)(char*, int, int, const char*),
495 long (*get_talk_id)(int))
497 (void)unit;
498 struct settings_list item;
499 struct int_setting data = {
500 function, voice_unit, min, max, step,
501 formatter, get_talk_id
503 item.int_setting = &data;
504 item.flags = F_INT_SETTING|F_T_INT;
505 item.lang_id = -1;
506 item.cfg_vals = (char*)string;
507 item.setting = variable;
508 return option_screen(&item, false, NULL);
511 /* to be replaced */
512 void option_select_init_items(struct option_select * opt,
513 const char * title,
514 int selected,
515 const struct opt_items * items,
516 int nb_items)
518 opt->title=title;
519 opt->min_value=0;
520 opt->max_value=nb_items;
521 opt->option=selected;
522 opt->items=items;
525 void option_select_next(struct option_select * opt)
527 if(opt->option + 1 >= opt->max_value)
529 if(opt->option==opt->max_value-1)
530 opt->option=opt->min_value;
531 else
532 opt->option=opt->max_value-1;
534 else
535 opt->option+=1;
538 void option_select_prev(struct option_select * opt)
540 if(opt->option - 1 < opt->min_value)
542 /* the dissimilarity to option_select_next() arises from the
543 * sleep timer problem (bug #5000 and #5001):
544 * there we have min=0, step = 5 but the value itself might
545 * not be a multiple of 5 -- as time elapsed;
546 * We need to be able to set timer to 0 (= Off) nevertheless. */
547 if(opt->option!=opt->min_value)
548 opt->option=opt->min_value;
549 else
550 opt->option=opt->max_value-1;
552 else
553 opt->option-=1;
556 const char * option_select_get_text(struct option_select * opt)
558 return(P2STR(opt->items[opt->option].string));