Make local functions static
[kugel-rb.git] / apps / gui / quickscreen.c
blob4c0cddf7ac31eb9baee60ae8eb6bd509707df2c6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Jonathan Gordon
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include <stdio.h>
24 #include "config.h"
25 #include "system.h"
26 #include "icons.h"
27 #include "font.h"
28 #include "kernel.h"
29 #include "misc.h"
30 #include "statusbar.h"
31 #include "action.h"
32 #include "settings_list.h"
33 #include "lang.h"
34 #include "playlist.h"
35 #include "dsp.h"
36 #include "viewport.h"
37 #include "audio.h"
38 #include "quickscreen.h"
39 #include "talk.h"
40 #include "list.h"
41 #include "splash.h"
43 static struct viewport vps[NB_SCREENS][QUICKSCREEN_ITEM_COUNT];
44 static struct viewport vp_icons[NB_SCREENS];
45 /* vp_icons will be used like this:
46 the side icons will be aligned to the top of this vp and to their sides
47 the bottom icon wil be aligned center and at the bottom of this vp */
49 #define MIN_LINES 4
50 #define MAX_NEEDED_LINES 8
51 #define CENTER_MARGIN 10 /* pixels between the 2 center items minimum */
52 #define CENTER_ICONAREA_WIDTH (CENTER_MARGIN+8*2)
54 static void quickscreen_fix_viewports(struct gui_quickscreen *qs,
55 struct screen *display,
56 struct viewport *parent)
58 #ifdef HAVE_REMOTE_LCD
59 int screen = display->screen_type;
60 #else
61 const int screen = 0;
62 #endif
64 int char_height, i, width, pad = 0;
65 int left_width, right_width, bottom_lines = 2;
66 unsigned char *s;
67 int nb_lines = viewport_get_nb_lines(parent);
68 char_height = parent->height/nb_lines;
70 /* center the icons VP first */
71 vp_icons[screen] = *parent;
72 vp_icons[screen].width = CENTER_ICONAREA_WIDTH; /* abosulte smallest allowed */
73 vp_icons[screen].x = (parent->width-parent->x-CENTER_ICONAREA_WIDTH)/2;
75 vps[screen][QUICKSCREEN_BOTTOM] = *parent;
76 if (nb_lines <= MIN_LINES) /* make the bottom item use 1 line */
77 bottom_lines = 1;
78 else
79 bottom_lines = 2;
80 vps[screen][QUICKSCREEN_BOTTOM].height = bottom_lines*char_height;
81 vps[screen][QUICKSCREEN_BOTTOM].y =
82 parent->y + parent->height - bottom_lines*char_height;
83 if (nb_lines >= MAX_NEEDED_LINES)
85 vps[screen][QUICKSCREEN_BOTTOM].y -= char_height;
88 /* adjust the left/right items widths to fit the screen nicely */
89 s = P2STR(ID2P(qs->items[QUICKSCREEN_LEFT]->lang_id));
90 left_width = display->getstringsize(s, NULL, NULL);
91 s = P2STR(ID2P(qs->items[QUICKSCREEN_RIGHT]->lang_id));
92 right_width = display->getstringsize(s, NULL, NULL);
93 nb_lines -= bottom_lines;
95 width = MAX(left_width, right_width);
96 if (width*2 + vp_icons[screen].width > display->lcdwidth)
97 width = (display->lcdwidth - vp_icons[screen].width)/2;
98 else /* add more gap in icons vp */
100 int excess = display->lcdwidth - vp_icons[screen].width - width*2;
101 if (excess > CENTER_MARGIN*4)
103 pad = CENTER_MARGIN;
104 excess -= CENTER_MARGIN*2;
106 vp_icons[screen].x -= excess/2;
107 vp_icons[screen].width += excess;
109 vps[screen][QUICKSCREEN_LEFT] = *parent;
110 vps[screen][QUICKSCREEN_LEFT].x = parent->x + pad;
111 vps[screen][QUICKSCREEN_LEFT].width = width;
113 vps[screen][QUICKSCREEN_RIGHT] = *parent;
114 vps[screen][QUICKSCREEN_RIGHT].x = parent->x + parent->width - width - pad;
115 vps[screen][QUICKSCREEN_RIGHT].width = width;
117 /* shrink the icons vp by a few pixels if there is room so the arrows
118 aren't drawn right next to the text */
119 if (vp_icons[screen].width > CENTER_ICONAREA_WIDTH+8)
121 vp_icons[screen].width -= 8;
122 vp_icons[screen].x += 4;
126 if (nb_lines <= MIN_LINES)
127 i = 0;
128 else
129 i = nb_lines/2;
130 vps[screen][QUICKSCREEN_LEFT].y = parent->y + (i*char_height);
131 vps[screen][QUICKSCREEN_RIGHT].y = parent->y + (i*char_height);
132 if (nb_lines >= 3)
133 i = 3*char_height;
134 else
135 i = nb_lines*char_height;
137 vps[screen][QUICKSCREEN_LEFT].height = i;
138 vps[screen][QUICKSCREEN_RIGHT].height = i;
139 vp_icons[screen].y = vps[screen][QUICKSCREEN_LEFT].y + (char_height/2);
140 vp_icons[screen].height =
141 vps[screen][QUICKSCREEN_BOTTOM].y - vp_icons[screen].y;
144 static void quickscreen_draw_text(char *s, int item, bool title,
145 struct screen *display, struct viewport *vp)
147 int nb_lines = viewport_get_nb_lines(vp);
148 int w, h, line = 0, x = 0;
149 display->getstringsize(s, &w, &h);
151 if (nb_lines > 1 && !title)
152 line = 1;
153 switch (item)
155 case QUICKSCREEN_BOTTOM:
156 x = (vp->width - w)/2;
157 break;
158 case QUICKSCREEN_LEFT:
159 x = 0;
160 break;
161 case QUICKSCREEN_RIGHT:
162 x = vp->width - w;
163 break;
165 if (w>vp->width)
166 display->puts_scroll(0, line, s);
167 else
168 display->putsxy(x, line*h, s);
171 static void gui_quickscreen_draw(struct gui_quickscreen *qs,
172 struct screen *display,
173 struct viewport *parent)
175 #ifdef HAVE_REMOTE_LCD
176 int screen = display->screen_type;
177 #else
178 const int screen = 0;
179 #endif
181 int i;
182 char buf[MAX_PATH];
183 unsigned char *title, *value;
184 void *setting;
185 int temp;
186 display->set_viewport(parent);
187 display->clear_viewport();
188 for (i=0; i<QUICKSCREEN_ITEM_COUNT; i++)
190 if (!qs->items[i])
191 continue;
192 display->set_viewport(&vps[screen][i]);
193 display->scroll_stop(&vps[screen][i]);
195 title = P2STR(ID2P(qs->items[i]->lang_id));
196 setting = qs->items[i]->setting;
197 temp = option_value_as_int(qs->items[i]);
198 value = option_get_valuestring((struct settings_list*)qs->items[i],
199 buf, MAX_PATH, temp);
201 if (vps[screen][i].height < display->getcharheight()*2)
203 char text[MAX_PATH];
204 snprintf(text, MAX_PATH, "%s: %s", title, value);
205 quickscreen_draw_text(text, i, true, display, &vps[screen][i]);
207 else
209 quickscreen_draw_text(title, i, true, display, &vps[screen][i]);
210 quickscreen_draw_text(value, i, false, display, &vps[screen][i]);
212 display->update_viewport();
214 /* draw the icons */
215 display->set_viewport(&vp_icons[screen]);
216 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
217 vp_icons[screen].width - 8, 0, 7, 8);
218 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward], 0, 0, 7, 8);
219 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
220 (vp_icons[screen].width/2) - 4,
221 vp_icons[screen].height - 7, 7, 8);
222 display->update_viewport();
224 display->set_viewport(parent);
225 display->update_viewport();
226 display->set_viewport(NULL);
229 static void talk_qs_option(struct settings_list *opt, bool enqueue)
231 if (global_settings.talk_menu) {
232 if(!enqueue)
233 talk_shutup();
234 talk_id(opt->lang_id, true);
235 option_talk_value(opt, option_value_as_int(opt), true);
240 * Does the actions associated to the given button if any
241 * - qs : the quickscreen
242 * - button : the key we are going to analyse
243 * returns : true if the button corresponded to an action, false otherwise
245 static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
247 int item;
248 switch(button)
250 case ACTION_QS_LEFT:
251 item = QUICKSCREEN_LEFT;
252 break;
254 case ACTION_QS_DOWN:
255 case ACTION_QS_DOWNINV:
256 item = QUICKSCREEN_BOTTOM;
257 break;
259 case ACTION_QS_RIGHT:
260 item = QUICKSCREEN_RIGHT;
261 break;
263 default:
264 return false;
266 option_select_next_val((struct settings_list *)qs->items[item], false, true);
267 talk_qs_option((struct settings_list *)qs->items[item], false);
268 return true;
271 bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter)
273 int button, i;
274 struct viewport vp[NB_SCREENS];
275 bool changed = false;
276 /* To quit we need either :
277 * - a second press on the button that made us enter
278 * - an action taken while pressing the enter button,
279 * then release the enter button*/
280 bool can_quit = false;
281 gui_syncstatusbar_draw(&statusbars, true);
282 FOR_NB_SCREENS(i)
284 screens[i].set_viewport(NULL);
285 screens[i].stop_scroll();
286 viewport_set_defaults(&vp[i], i);
287 quickscreen_fix_viewports(qs, &screens[i], &vp[i]);
288 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
290 /* Announce current selection on entering this screen. This is all
291 queued up, but can be interrupted as soon as a setting is
292 changed. */
293 cond_talk_ids(VOICE_QUICKSCREEN);
294 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_LEFT], true);
295 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_BOTTOM], true);
296 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_RIGHT], true);
297 while (true) {
298 button = get_action(CONTEXT_QUICKSCREEN,HZ/5);
299 if(default_event_handler(button) == SYS_USB_CONNECTED)
300 return(true);
301 if(gui_quickscreen_do_button(qs, button))
303 changed = true;
304 can_quit=true;
305 FOR_NB_SCREENS(i)
306 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
307 if (qs->callback)
308 qs->callback(qs);
310 else if(button==button_enter)
311 can_quit=true;
313 if((button == button_enter) && can_quit)
314 break;
316 if(button==ACTION_STD_CANCEL)
317 break;
319 gui_syncstatusbar_draw(&statusbars, false);
321 /* Notify that we're exiting this screen */
322 cond_talk_ids_fq(VOICE_OK);
323 return changed;
325 static bool is_setting_quickscreenable(const struct settings_list *setting);
326 static inline const struct settings_list *get_setting(int gs_value,
327 const struct settings_list *defaultval)
329 if (gs_value != -1 && gs_value < nb_settings &&
330 is_setting_quickscreenable(&settings[gs_value]))
331 return &settings[gs_value];
332 return defaultval;
334 bool quick_screen_quick(int button_enter)
336 struct gui_quickscreen qs;
337 bool oldshuffle = global_settings.playlist_shuffle;
338 int oldrepeat = global_settings.repeat_mode;
340 qs.items[QUICKSCREEN_LEFT] =
341 get_setting(global_settings.qs_item_left,
342 find_setting(&global_settings.playlist_shuffle, NULL));
343 qs.items[QUICKSCREEN_RIGHT] =
344 get_setting(global_settings.qs_item_right,
345 find_setting(&global_settings.repeat_mode, NULL));
346 qs.items[QUICKSCREEN_BOTTOM] =
347 get_setting(global_settings.qs_item_bottom,
348 find_setting(&global_settings.dirfilter, NULL));
350 qs.callback = NULL;
351 if (gui_syncquickscreen_run(&qs, button_enter))
353 settings_save();
354 settings_apply(false);
355 /* make sure repeat/shuffle/any other nasty ones get updated */
356 if ( oldrepeat != global_settings.repeat_mode &&
357 (audio_status() & AUDIO_STATUS_PLAY) )
359 audio_flush_and_reload_tracks();
361 if (oldshuffle != global_settings.playlist_shuffle
362 && audio_status() & AUDIO_STATUS_PLAY)
364 #if CONFIG_CODEC == SWCODEC
365 dsp_set_replaygain();
366 #endif
367 if (global_settings.playlist_shuffle)
368 playlist_randomise(NULL, current_tick, true);
369 else
370 playlist_sort(NULL, true);
373 return(0);
376 #ifdef BUTTON_F3
377 bool quick_screen_f3(int button_enter)
379 struct gui_quickscreen qs;
380 qs.items[QUICKSCREEN_LEFT] =
381 find_setting(&global_settings.scrollbar, NULL);
382 qs.items[QUICKSCREEN_RIGHT] =
383 find_setting(&global_settings.statusbar, NULL);
384 qs.items[QUICKSCREEN_BOTTOM] =
385 find_setting(&global_settings.flip_display, NULL);
386 qs.callback = NULL;
387 if (gui_syncquickscreen_run(&qs, button_enter))
389 settings_save();
390 settings_apply(false);
392 return(0);
394 #endif /* BUTTON_F3 */
396 /* stuff to make the quickscreen configurable */
397 static bool is_setting_quickscreenable(const struct settings_list *setting)
399 /* to keep things simple, only settings which have a lang_id set are ok */
400 if (setting->lang_id < 0 || (setting->flags&F_BANFROMQS))
401 return false;
402 switch (setting->flags&F_T_MASK)
404 case F_T_BOOL:
405 return true;
406 case F_T_INT:
407 case F_T_UINT:
408 return (setting->RESERVED != NULL);
409 default:
410 return false;
414 static const struct settings_list *find_setting_from_index(int index)
416 int count = -1, i;
417 const struct settings_list *setting = &settings[0];
418 for(i=0;i<nb_settings;i++)
420 setting = &settings[i];
421 if (is_setting_quickscreenable(setting))
422 count++;
423 if (count == index)
424 return setting;
426 return NULL;
428 static char* quickscreen_setter_getname(int selected_item, void *data,
429 char *buffer, size_t buffer_len)
431 (void)data;
432 const struct settings_list *setting = find_setting_from_index(selected_item);
433 snprintf(buffer, buffer_len, "%s (%s)",
434 str(setting->lang_id), setting->cfg_name);
435 return buffer;
437 static int quickscreen_setter_speak_item(int selected_item, void * data)
439 (void)data;
440 talk_id(find_setting_from_index(selected_item)->lang_id, true);
441 return 0;
443 static int quickscreen_setter_action_callback(int action,
444 struct gui_synclist *lists)
446 const struct settings_list *temp = lists->data;
447 switch (action)
449 case ACTION_STD_OK:
450 /* ok, quit */
451 return ACTION_STD_CANCEL;
452 case ACTION_STD_CONTEXT: /* real settings use this to reset to default */
454 int i=0, count=0;
455 reset_setting(temp, temp->setting);
456 for(i=0;i<nb_settings;i++)
458 if (is_setting_quickscreenable(&settings[i]))
459 count++;
460 if (*(int*)temp->setting == i)
462 gui_synclist_select_item(lists, count-1);
463 break;
466 return ACTION_REDRAW;
469 return action;
471 int quickscreen_set_option(void *data)
473 int valid_settings_count = 0;
474 int i, newval = 0, oldval, *setting = NULL;
475 struct simplelist_info info;
476 switch ((intptr_t)data)
478 case QUICKSCREEN_LEFT:
479 setting = &global_settings.qs_item_left;
480 break;
481 case QUICKSCREEN_RIGHT:
482 setting = &global_settings.qs_item_right;
483 break;
484 case QUICKSCREEN_BOTTOM:
485 setting = &global_settings.qs_item_bottom;
486 break;
488 oldval = *setting;
489 for(i=0;i<nb_settings;i++)
491 if (is_setting_quickscreenable(&settings[i]))
492 valid_settings_count++;
493 if (oldval == i)
494 newval = valid_settings_count - 1;
497 simplelist_info_init(&info, str(LANG_QS_ITEMS),
498 valid_settings_count,
499 (void*)find_setting(setting, NULL)); /* find the qs item being changed */
500 info.get_name = quickscreen_setter_getname;
501 if(global_settings.talk_menu)
502 info.get_talk = quickscreen_setter_speak_item;
503 info.action_callback = quickscreen_setter_action_callback;
504 info.selection = newval;
505 simplelist_show_list(&info);
506 if (info.selection != oldval)
508 if (info.selection != -1)
510 const struct settings_list *temp = find_setting_from_index(info.selection);
511 int i = 0;
512 for(i=0;i<nb_settings;i++)
514 if (&settings[i] == temp)
515 break;
517 *setting = i;
518 settings_save();
520 /* probably should splash LANG_CANCEL here but right now
521 we cant find out the selection when the cancel button was
522 pressed, (without hacks)so we cant know if the
523 selection was changed, or just viewed */
525 return 0;