Do some #ifdef'ing to make the Player happy.
[kugel-rb.git] / apps / gui / quickscreen.c
blobd6d662b1f1dbb15ebd3eb409e1fa45c663955481
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 "action.h"
31 #include "settings_list.h"
32 #include "lang.h"
33 #include "playlist.h"
34 #include "dsp.h"
35 #include "viewport.h"
36 #include "audio.h"
37 #include "quickscreen.h"
38 #include "talk.h"
39 #include "list.h"
40 #include "option_select.h"
42 static struct viewport vps[NB_SCREENS][QUICKSCREEN_ITEM_COUNT];
43 static struct viewport vp_icons[NB_SCREENS];
44 /* vp_icons will be used like this:
45 the side icons will be aligned to the top of this vp and to their sides
46 the bottom icon will be aligned center and at the bottom of this vp */
48 #define MIN_LINES 4
49 #define MAX_NEEDED_LINES 8
50 #define CENTER_MARGIN 10 /* pixels between the 2 center items minimum */
51 #define CENTER_ICONAREA_WIDTH (CENTER_MARGIN+8*2)
53 static void quickscreen_fix_viewports(struct gui_quickscreen *qs,
54 struct screen *display,
55 struct viewport *parent)
57 #ifdef HAVE_REMOTE_LCD
58 int screen = display->screen_type;
59 #else
60 const int screen = 0;
61 #endif
63 int char_height, i, width, pad = 0;
64 int left_width, right_width, bottom_lines = 2;
65 unsigned char *s;
66 int nb_lines = viewport_get_nb_lines(parent);
68 /* nb_lines only returns the number of fully visible lines, small screens
69 or really large fonts could cause problems with the calculation below.
71 if(nb_lines==0)
72 nb_lines++;
74 char_height = parent->height/nb_lines;
76 /* center the icons VP first */
77 vp_icons[screen] = *parent;
78 vp_icons[screen].width = CENTER_ICONAREA_WIDTH; /* absolute smallest allowed */
79 vp_icons[screen].x = parent->x + (parent->width / 2 - CENTER_ICONAREA_WIDTH / 2);
81 vps[screen][QUICKSCREEN_BOTTOM] = *parent;
82 if (nb_lines <= MIN_LINES) /* make the bottom item use 1 line */
83 bottom_lines = 1;
84 else
85 bottom_lines = 2;
86 vps[screen][QUICKSCREEN_BOTTOM].height = bottom_lines*char_height;
87 vps[screen][QUICKSCREEN_BOTTOM].y =
88 parent->y + parent->height - bottom_lines*char_height;
89 if (nb_lines >= MAX_NEEDED_LINES)
91 vps[screen][QUICKSCREEN_BOTTOM].y -= char_height;
94 /* adjust the left/right items widths to fit the screen nicely */
95 s = P2STR(ID2P(qs->items[QUICKSCREEN_LEFT]->lang_id));
96 left_width = display->getstringsize(s, NULL, NULL);
97 s = P2STR(ID2P(qs->items[QUICKSCREEN_RIGHT]->lang_id));
98 right_width = display->getstringsize(s, NULL, NULL);
99 nb_lines -= bottom_lines;
101 width = MAX(left_width, right_width);
102 if (width*2 + vp_icons[screen].width > display->lcdwidth)
103 width = (display->lcdwidth - vp_icons[screen].width)/2;
104 else /* add more gap in icons vp */
106 int excess = display->lcdwidth - vp_icons[screen].width - width*2;
107 if (excess > CENTER_MARGIN*4)
109 pad = CENTER_MARGIN;
110 excess -= CENTER_MARGIN*2;
112 vp_icons[screen].x -= excess/2;
113 vp_icons[screen].width += excess;
115 vps[screen][QUICKSCREEN_LEFT] = *parent;
116 vps[screen][QUICKSCREEN_LEFT].x = parent->x + pad;
117 vps[screen][QUICKSCREEN_LEFT].width = width;
119 vps[screen][QUICKSCREEN_RIGHT] = *parent;
120 vps[screen][QUICKSCREEN_RIGHT].x = parent->x + parent->width - width - pad;
121 vps[screen][QUICKSCREEN_RIGHT].width = width;
123 /* shrink the icons vp by a few pixels if there is room so the arrows
124 aren't drawn right next to the text */
125 if (vp_icons[screen].width > CENTER_ICONAREA_WIDTH+8)
127 vp_icons[screen].width -= 8;
128 vp_icons[screen].x += 4;
132 if (nb_lines <= MIN_LINES)
133 i = 0;
134 else
135 i = nb_lines/2;
136 vps[screen][QUICKSCREEN_LEFT].y = parent->y + (i*char_height);
137 vps[screen][QUICKSCREEN_RIGHT].y = parent->y + (i*char_height);
138 if (nb_lines >= 3)
139 i = 3*char_height;
140 else
141 i = nb_lines*char_height;
143 vps[screen][QUICKSCREEN_LEFT].height = i;
144 vps[screen][QUICKSCREEN_RIGHT].height = i;
145 vp_icons[screen].y = vps[screen][QUICKSCREEN_LEFT].y + (char_height/2);
146 vp_icons[screen].height =
147 vps[screen][QUICKSCREEN_BOTTOM].y - vp_icons[screen].y;
150 static void quickscreen_draw_text(const char *s, int item, bool title,
151 struct screen *display, struct viewport *vp)
153 int nb_lines = viewport_get_nb_lines(vp);
154 int w, h, line = 0, x = 0;
155 display->getstringsize(s, &w, &h);
157 if (nb_lines > 1 && !title)
158 line = 1;
159 switch (item)
161 case QUICKSCREEN_BOTTOM:
162 x = (vp->width - w)/2;
163 break;
164 case QUICKSCREEN_LEFT:
165 x = 0;
166 break;
167 case QUICKSCREEN_RIGHT:
168 x = vp->width - w;
169 break;
171 if (w>vp->width)
172 display->puts_scroll(0, line, s);
173 else
174 display->putsxy(x, line*h, s);
177 static void gui_quickscreen_draw(struct gui_quickscreen *qs,
178 struct screen *display,
179 struct viewport *parent)
181 #ifdef HAVE_REMOTE_LCD
182 int screen = display->screen_type;
183 #else
184 const int screen = 0;
185 #endif
187 int i;
188 char buf[MAX_PATH];
189 unsigned const char *title, *value;
190 void *setting;
191 int temp;
192 display->set_viewport(parent);
193 display->clear_viewport();
194 for (i=0; i<QUICKSCREEN_ITEM_COUNT; i++)
196 if (!qs->items[i])
197 continue;
198 display->set_viewport(&vps[screen][i]);
199 display->scroll_stop(&vps[screen][i]);
201 title = P2STR(ID2P(qs->items[i]->lang_id));
202 setting = qs->items[i]->setting;
203 temp = option_value_as_int(qs->items[i]);
204 value = option_get_valuestring((struct settings_list*)qs->items[i],
205 buf, MAX_PATH, temp);
207 if (vps[screen][i].height < display->getcharheight()*2)
209 char text[MAX_PATH];
210 snprintf(text, MAX_PATH, "%s: %s", title, value);
211 quickscreen_draw_text(text, i, true, display, &vps[screen][i]);
213 else
215 quickscreen_draw_text(title, i, true, display, &vps[screen][i]);
216 quickscreen_draw_text(value, i, false, display, &vps[screen][i]);
218 display->update_viewport();
220 /* draw the icons */
221 display->set_viewport(&vp_icons[screen]);
222 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
223 vp_icons[screen].width - 8, 0, 7, 8);
224 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward], 0, 0, 7, 8);
225 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
226 (vp_icons[screen].width/2) - 4,
227 vp_icons[screen].height - 7, 7, 8);
228 display->update_viewport();
230 display->set_viewport(parent);
231 display->update_viewport();
232 display->set_viewport(NULL);
235 static void talk_qs_option(struct settings_list *opt, bool enqueue)
237 if (global_settings.talk_menu) {
238 if(!enqueue)
239 talk_shutup();
240 talk_id(opt->lang_id, true);
241 option_talk_value(opt, option_value_as_int(opt), true);
246 * Does the actions associated to the given button if any
247 * - qs : the quickscreen
248 * - button : the key we are going to analyse
249 * returns : true if the button corresponded to an action, false otherwise
251 static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
253 int item;
254 bool invert = false;
255 switch(button)
257 case ACTION_QS_LEFT:
258 item = QUICKSCREEN_LEFT;
259 break;
261 case ACTION_QS_DOWNINV:
262 invert = true; /* fallthrough */
263 case ACTION_QS_DOWN:
264 item = QUICKSCREEN_BOTTOM;
265 break;
267 case ACTION_QS_RIGHT:
268 item = QUICKSCREEN_RIGHT;
269 break;
271 default:
272 return false;
274 option_select_next_val((struct settings_list *)qs->items[item], invert, true);
275 talk_qs_option((struct settings_list *)qs->items[item], false);
276 return true;
278 #ifdef HAVE_TOUCHSCREEN
279 /* figure out which button was pressed...
280 * top is exit, left/right/botton are the respective actions
282 static int quickscreen_touchscreen_button(void)
284 short x,y;
285 if (action_get_touchscreen_press(&x, &y) != BUTTON_REL)
286 return ACTION_NONE;
287 if (y < vps[SCREEN_MAIN][QUICKSCREEN_LEFT].y)
288 return ACTION_STD_CANCEL;
289 else if (y > vps[SCREEN_MAIN][QUICKSCREEN_LEFT].y +
290 vps[SCREEN_MAIN][QUICKSCREEN_LEFT].height)
291 return ACTION_QS_DOWN;
292 else if (x < vps[SCREEN_MAIN][QUICKSCREEN_LEFT].x +
293 vps[SCREEN_MAIN][QUICKSCREEN_LEFT].width)
294 return ACTION_QS_LEFT;
295 else if (x >= vps[SCREEN_MAIN][QUICKSCREEN_RIGHT].x)
296 return ACTION_QS_RIGHT;
297 return ACTION_STD_CANCEL;
299 #endif
300 static bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter)
302 int button, i;
303 struct viewport vp[NB_SCREENS];
304 bool changed = false;
305 /* To quit we need either :
306 * - a second press on the button that made us enter
307 * - an action taken while pressing the enter button,
308 * then release the enter button*/
309 bool can_quit = false;
310 FOR_NB_SCREENS(i)
312 screens[i].set_viewport(NULL);
313 screens[i].stop_scroll();
314 viewport_set_defaults(&vp[i], i);
315 quickscreen_fix_viewports(qs, &screens[i], &vp[i]);
316 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
318 /* Announce current selection on entering this screen. This is all
319 queued up, but can be interrupted as soon as a setting is
320 changed. */
321 cond_talk_ids(VOICE_QUICKSCREEN);
322 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_LEFT], true);
323 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_BOTTOM], true);
324 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_RIGHT], true);
325 while (true) {
326 button = get_action(CONTEXT_QUICKSCREEN,HZ/5);
327 #ifdef HAVE_TOUCHSCREEN
328 if (button == ACTION_TOUCHSCREEN)
329 button = quickscreen_touchscreen_button();
330 #endif
331 if(default_event_handler(button) == SYS_USB_CONNECTED)
332 return(true);
333 if(gui_quickscreen_do_button(qs, button))
335 changed = true;
336 can_quit=true;
337 FOR_NB_SCREENS(i)
338 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
339 if (qs->callback)
340 qs->callback(qs);
342 else if(button==button_enter)
343 can_quit=true;
345 if((button == button_enter) && can_quit)
346 break;
348 if(button==ACTION_STD_CANCEL)
349 break;
351 /* Notify that we're exiting this screen */
352 cond_talk_ids_fq(VOICE_OK);
353 return changed;
356 static inline const struct settings_list *get_setting(int gs_value,
357 const struct settings_list *defaultval)
359 if (gs_value != -1 && gs_value < nb_settings &&
360 is_setting_quickscreenable(&settings[gs_value]))
361 return &settings[gs_value];
362 return defaultval;
364 bool quick_screen_quick(int button_enter)
366 struct gui_quickscreen qs;
367 bool oldshuffle = global_settings.playlist_shuffle;
368 int oldrepeat = global_settings.repeat_mode;
370 qs.items[QUICKSCREEN_LEFT] =
371 get_setting(global_settings.qs_item_left,
372 find_setting(&global_settings.playlist_shuffle, NULL));
373 qs.items[QUICKSCREEN_RIGHT] =
374 get_setting(global_settings.qs_item_right,
375 find_setting(&global_settings.repeat_mode, NULL));
376 qs.items[QUICKSCREEN_BOTTOM] =
377 get_setting(global_settings.qs_item_bottom,
378 find_setting(&global_settings.dirfilter, NULL));
380 qs.callback = NULL;
381 if (gui_syncquickscreen_run(&qs, button_enter))
383 settings_save();
384 settings_apply(false);
385 /* make sure repeat/shuffle/any other nasty ones get updated */
386 if ( oldrepeat != global_settings.repeat_mode &&
387 (audio_status() & AUDIO_STATUS_PLAY) )
389 audio_flush_and_reload_tracks();
391 if (oldshuffle != global_settings.playlist_shuffle
392 && audio_status() & AUDIO_STATUS_PLAY)
394 #if CONFIG_CODEC == SWCODEC
395 dsp_set_replaygain();
396 #endif
397 if (global_settings.playlist_shuffle)
398 playlist_randomise(NULL, current_tick, true);
399 else
400 playlist_sort(NULL, true);
403 return(0);
406 #ifdef BUTTON_F3
407 bool quick_screen_f3(int button_enter)
409 struct gui_quickscreen qs;
410 qs.items[QUICKSCREEN_LEFT] =
411 find_setting(&global_settings.scrollbar, NULL);
412 qs.items[QUICKSCREEN_RIGHT] =
413 find_setting(&global_settings.statusbar, NULL);
414 qs.items[QUICKSCREEN_BOTTOM] =
415 find_setting(&global_settings.flip_display, NULL);
416 qs.callback = NULL;
417 if (gui_syncquickscreen_run(&qs, button_enter))
419 settings_save();
420 settings_apply(false);
422 return(0);
424 #endif /* BUTTON_F3 */
426 /* stuff to make the quickscreen configurable */
427 bool is_setting_quickscreenable(const struct settings_list *setting)
429 /* to keep things simple, only settings which have a lang_id set are ok */
430 if (setting->lang_id < 0 || (setting->flags&F_BANFROMQS))
431 return false;
432 switch (setting->flags&F_T_MASK)
434 case F_T_BOOL:
435 return true;
436 case F_T_INT:
437 case F_T_UINT:
438 return (setting->RESERVED != NULL);
439 default:
440 return false;
444 void set_as_qs_item(const struct settings_list *setting,
445 enum quickscreen_item item)
447 int i;
448 for(i=0;i<nb_settings;i++)
450 if (&settings[i] == setting)
451 break;
453 switch (item)
455 case QUICKSCREEN_LEFT:
456 global_settings.qs_item_left = i;
457 break;
458 case QUICKSCREEN_RIGHT:
459 global_settings.qs_item_right = i;
460 break;
461 case QUICKSCREEN_BOTTOM:
462 global_settings.qs_item_bottom = i;
463 break;
464 default: /* shut the copiler up */
465 break;