Make the recorder build with HAVE_LCD_FLIP disabled.
[maemo-rb.git] / apps / gui / quickscreen.c
blob5c8a7705aec7a5de1c1c3f4757fa7f1838fe1bbe
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 ****************************************************************************/
22 #include <stdio.h>
23 #include "config.h"
24 #include "system.h"
25 #include "icons.h"
26 #include "font.h"
27 #include "kernel.h"
28 #include "misc.h"
29 #include "action.h"
30 #include "settings_list.h"
31 #include "lang.h"
32 #include "playlist.h"
33 #include "viewport.h"
34 #include "audio.h"
35 #include "quickscreen.h"
36 #include "talk.h"
37 #include "list.h"
38 #include "option_select.h"
39 #include "debug.h"
40 #include "shortcuts.h"
42 /* 1 top, 1 bottom, 2 on either side, 1 for the icons
43 * if enough space, top and bottom have 2 lines */
44 #define MIN_LINES 5
45 #define MAX_NEEDED_LINES 10
46 /* pixels between the 2 center items minimum or between text and icons,
47 * and between text and parent boundaries */
48 #define MARGIN 10
49 #define CENTER_ICONAREA_SIZE (MARGIN+8*2)
51 static void quickscreen_fix_viewports(struct gui_quickscreen *qs,
52 struct screen *display,
53 struct viewport *parent,
54 struct viewport
55 vps[QUICKSCREEN_ITEM_COUNT],
56 struct viewport *vp_icons)
58 int char_height, width, pad = 0;
59 int left_width = 0, right_width = 0, vert_lines;
60 unsigned char *s;
61 int nb_lines = viewport_get_nb_lines(parent);
63 /* nb_lines only returns the number of fully visible lines, small screens
64 or really large fonts could cause problems with the calculation below.
66 if (nb_lines == 0)
67 nb_lines++;
69 char_height = parent->height/nb_lines;
71 /* center the icons VP first */
72 *vp_icons = *parent;
73 vp_icons->width = CENTER_ICONAREA_SIZE; /* abosulte smallest allowed */
74 vp_icons->x = parent->x;
75 vp_icons->x += (parent->width-CENTER_ICONAREA_SIZE)/2;
77 vps[QUICKSCREEN_BOTTOM] = *parent;
78 vps[QUICKSCREEN_TOP] = *parent;
79 /* depending on the space the top/buttom items use 1 or 2 lines */
80 if (nb_lines < MIN_LINES)
81 vert_lines = 1;
82 else
83 vert_lines = 2;
84 vps[QUICKSCREEN_TOP].y = parent->y;
85 vps[QUICKSCREEN_TOP].height = vps[QUICKSCREEN_BOTTOM].height
86 = vert_lines*char_height;
87 vps[QUICKSCREEN_BOTTOM].y
88 = parent->y + parent->height - vps[QUICKSCREEN_BOTTOM].height;
90 /* enough space vertically, so put a nice margin */
91 if (nb_lines >= MAX_NEEDED_LINES)
93 vps[QUICKSCREEN_TOP].y += MARGIN;
94 vps[QUICKSCREEN_BOTTOM].y -= MARGIN;
97 vp_icons->y = vps[QUICKSCREEN_TOP].y
98 + vps[QUICKSCREEN_TOP].height;
99 vp_icons->height = vps[QUICKSCREEN_BOTTOM].y - vp_icons->y;
101 /* adjust the left/right items widths to fit the screen nicely */
102 if (qs->items[QUICKSCREEN_LEFT])
104 s = P2STR(ID2P(qs->items[QUICKSCREEN_LEFT]->lang_id));
105 left_width = display->getstringsize(s, NULL, NULL);
107 if (qs->items[QUICKSCREEN_RIGHT])
109 s = P2STR(ID2P(qs->items[QUICKSCREEN_RIGHT]->lang_id));
110 right_width = display->getstringsize(s, NULL, NULL);
113 width = MAX(left_width, right_width);
114 if (width*2 + vp_icons->width > parent->width)
115 { /* crop text viewports */
116 width = (parent->width - vp_icons->width)/2;
118 else
119 { /* add more gap in icons vp */
120 int excess = parent->width - vp_icons->width - width*2;
121 if (excess > MARGIN*4)
123 pad = MARGIN;
124 excess -= MARGIN*2;
126 vp_icons->x -= excess/2;
127 vp_icons->width += excess;
130 vps[QUICKSCREEN_LEFT] = *parent;
131 vps[QUICKSCREEN_LEFT].x = parent->x + pad;
132 vps[QUICKSCREEN_LEFT].width = width;
134 vps[QUICKSCREEN_RIGHT] = *parent;
135 vps[QUICKSCREEN_RIGHT].x = parent->x + parent->width - width - pad;
136 vps[QUICKSCREEN_RIGHT].width = width;
138 vps[QUICKSCREEN_LEFT].height = vps[QUICKSCREEN_RIGHT].height
139 = 2*char_height;
141 vps[QUICKSCREEN_LEFT].y = vps[QUICKSCREEN_RIGHT].y
142 = parent->y + (parent->height/2) - char_height;
144 /* shrink the icons vp by a few pixels if there is room so the arrows
145 aren't drawn right next to the text */
146 if (vp_icons->width > CENTER_ICONAREA_SIZE*2)
148 vp_icons->width -= CENTER_ICONAREA_SIZE*2/3;
149 vp_icons->x += CENTER_ICONAREA_SIZE*2/6;
151 if (vp_icons->height > CENTER_ICONAREA_SIZE*2)
153 vp_icons->height -= CENTER_ICONAREA_SIZE*2/3;
154 vp_icons->y += CENTER_ICONAREA_SIZE*2/6;
157 /* text alignment */
158 vps[QUICKSCREEN_LEFT].flags &= ~VP_FLAG_ALIGNMENT_MASK; /* left-aligned */
159 vps[QUICKSCREEN_TOP].flags |= VP_FLAG_ALIGN_CENTER; /* centered */
160 vps[QUICKSCREEN_BOTTOM].flags |= VP_FLAG_ALIGN_CENTER; /* centered */
161 vps[QUICKSCREEN_RIGHT].flags &= ~VP_FLAG_ALIGNMENT_MASK;/* right aligned*/
162 vps[QUICKSCREEN_RIGHT].flags |= VP_FLAG_ALIGN_RIGHT;
165 static void gui_quickscreen_draw(const struct gui_quickscreen *qs,
166 struct screen *display,
167 struct viewport *parent,
168 struct viewport vps[QUICKSCREEN_ITEM_COUNT],
169 struct viewport *vp_icons)
171 int i;
172 char buf[MAX_PATH];
173 unsigned const char *title, *value;
174 int temp;
175 display->set_viewport(parent);
176 display->clear_viewport();
178 for (i = 0; i < QUICKSCREEN_ITEM_COUNT; i++)
180 struct viewport *vp = &vps[i];
181 if (!qs->items[i])
182 continue;
183 display->set_viewport(vp);
185 title = P2STR(ID2P(qs->items[i]->lang_id));
186 temp = option_value_as_int(qs->items[i]);
187 value = option_get_valuestring(qs->items[i],
188 buf, MAX_PATH, temp);
190 if (viewport_get_nb_lines(vp) < 2)
192 char text[MAX_PATH];
193 snprintf(text, MAX_PATH, "%s: %s", title, value);
194 display->puts_scroll(0, 0, text);
196 else
198 display->puts_scroll(0, 0, title);
199 display->puts_scroll(0, 1, value);
202 /* draw the icons */
203 display->set_viewport(vp_icons);
205 if (qs->items[QUICKSCREEN_TOP] != NULL)
207 display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
208 (vp_icons->width/2) - 4, 0, 7, 8);
210 if (qs->items[QUICKSCREEN_RIGHT] != NULL)
212 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
213 vp_icons->width - 8, (vp_icons->height/2) - 4, 7, 8);
215 if (qs->items[QUICKSCREEN_LEFT] != NULL)
217 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward],
218 0, (vp_icons->height/2) - 4, 7, 8);
220 if (qs->items[QUICKSCREEN_BOTTOM] != NULL)
222 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
223 (vp_icons->width/2) - 4, vp_icons->height - 8, 7, 8);
226 display->set_viewport(parent);
227 display->update_viewport();
228 display->set_viewport(NULL);
231 static void talk_qs_option(const struct settings_list *opt, bool enqueue)
233 if (!global_settings.talk_menu || !opt)
234 return;
236 if (!enqueue)
237 talk_shutup();
238 talk_id(opt->lang_id, true);
239 option_talk_value(opt, option_value_as_int(opt), true);
243 * Does the actions associated to the given button if any
244 * - qs : the quickscreen
245 * - button : the key we are going to analyse
246 * returns : true if the button corresponded to an action, false otherwise
248 static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
250 int item;
251 bool invert = false;
252 switch(button)
254 case ACTION_QS_TOP:
255 invert = true;
256 item = QUICKSCREEN_TOP;
257 break;
258 case ACTION_QS_LEFT:
259 invert = true;
260 item = QUICKSCREEN_LEFT;
261 break;
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 if (qs->items[item] == NULL)
275 return false;
276 #ifdef ASCENDING_INT_SETTINGS
277 if (((qs->items[item]->flags & F_INT_SETTING) == F_INT_SETTING) &&
278 ( button == ACTION_QS_DOWN || button == ACTION_QS_TOP))
280 invert = !invert;
282 #endif
283 option_select_next_val(qs->items[item], invert, true);
284 talk_qs_option(qs->items[item], false);
285 return true;
288 #ifdef HAVE_TOUCHSCREEN
289 static int quickscreen_touchscreen_button(const struct viewport
290 vps[QUICKSCREEN_ITEM_COUNT])
292 short x,y;
293 /* only hitting the text counts, everything else is exit */
294 if (action_get_touchscreen_press(&x, &y) != BUTTON_REL)
295 return ACTION_NONE;
296 else if (viewport_point_within_vp(&vps[QUICKSCREEN_TOP], x, y))
297 return ACTION_QS_TOP;
298 else if (viewport_point_within_vp(&vps[QUICKSCREEN_BOTTOM], x, y))
299 return ACTION_QS_DOWN;
300 else if (viewport_point_within_vp(&vps[QUICKSCREEN_LEFT], x, y))
301 return ACTION_QS_LEFT;
302 else if (viewport_point_within_vp(&vps[QUICKSCREEN_RIGHT], x, y))
303 return ACTION_QS_RIGHT;
304 return ACTION_STD_CANCEL;
306 #endif
308 static bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter)
310 int button;
311 struct viewport parent[NB_SCREENS];
312 struct viewport vps[NB_SCREENS][QUICKSCREEN_ITEM_COUNT];
313 struct viewport vp_icons[NB_SCREENS];
314 bool changed = false;
315 /* To quit we need either :
316 * - a second press on the button that made us enter
317 * - an action taken while pressing the enter button,
318 * then release the enter button*/
319 bool can_quit = false;
321 push_current_activity(ACTIVITY_QUICKSCREEN);
323 FOR_NB_SCREENS(i)
325 screens[i].set_viewport(NULL);
326 screens[i].stop_scroll();
327 viewportmanager_theme_enable(i, true, &parent[i]);
328 quickscreen_fix_viewports(qs, &screens[i], &parent[i], vps[i], &vp_icons[i]);
329 gui_quickscreen_draw(qs, &screens[i], &parent[i], vps[i], &vp_icons[i]);
331 /* Announce current selection on entering this screen. This is all
332 queued up, but can be interrupted as soon as a setting is
333 changed. */
334 cond_talk_ids(VOICE_QUICKSCREEN);
335 talk_qs_option(qs->items[QUICKSCREEN_TOP], true);
336 talk_qs_option(qs->items[QUICKSCREEN_LEFT], true);
337 talk_qs_option(qs->items[QUICKSCREEN_BOTTOM], true);
338 talk_qs_option(qs->items[QUICKSCREEN_RIGHT], true);
339 while (true) {
340 button = get_action(CONTEXT_QUICKSCREEN, HZ/5);
341 #ifdef HAVE_TOUCHSCREEN
342 if (button == ACTION_TOUCHSCREEN)
343 button = quickscreen_touchscreen_button(vps[SCREEN_MAIN]);
344 #endif
345 if (default_event_handler(button) == SYS_USB_CONNECTED)
346 return(true);
347 if (gui_quickscreen_do_button(qs, button))
349 changed = true;
350 can_quit = true;
351 FOR_NB_SCREENS(i)
352 gui_quickscreen_draw(qs, &screens[i], &parent[i],
353 vps[i], &vp_icons[i]);
354 if (qs->callback)
355 qs->callback(qs);
357 else if (button == button_enter)
358 can_quit = true;
360 if ((button == button_enter) && can_quit)
361 break;
363 if (button == ACTION_STD_CANCEL)
364 break;
366 /* Notify that we're exiting this screen */
367 cond_talk_ids_fq(VOICE_OK);
368 FOR_NB_SCREENS(i)
369 { /* stop scrolling before exiting */
370 for (int j = 0; j < QUICKSCREEN_ITEM_COUNT; j++)
371 screens[i].scroll_stop(&vps[i][j]);
372 viewportmanager_theme_undo(i, true);
375 pop_current_activity();
376 return changed;
379 static const struct settings_list *get_setting(int gs_value,
380 const struct settings_list *defaultval)
382 if (gs_value != -1 && gs_value < nb_settings &&
383 is_setting_quickscreenable(&settings[gs_value]))
384 return &settings[gs_value];
385 return defaultval;
388 bool quick_screen_quick(int button_enter)
390 struct gui_quickscreen qs;
391 bool oldshuffle = global_settings.playlist_shuffle;
392 int oldrepeat = global_settings.repeat_mode;
394 if (global_settings.shortcuts_replaces_qs)
395 return do_shortcut_menu(NULL);
397 qs.items[QUICKSCREEN_TOP] =
398 get_setting(global_settings.qs_items[QUICKSCREEN_TOP], NULL);
399 qs.items[QUICKSCREEN_LEFT] =
400 get_setting(global_settings.qs_items[QUICKSCREEN_LEFT],
401 find_setting(&global_settings.playlist_shuffle, NULL));
402 qs.items[QUICKSCREEN_RIGHT] =
403 get_setting(global_settings.qs_items[QUICKSCREEN_RIGHT],
404 find_setting(&global_settings.repeat_mode, NULL));
405 qs.items[QUICKSCREEN_BOTTOM] =
406 get_setting(global_settings.qs_items[QUICKSCREEN_BOTTOM], NULL);
408 qs.callback = NULL;
409 if (gui_syncquickscreen_run(&qs, button_enter))
411 settings_save();
412 settings_apply(false);
413 /* make sure repeat/shuffle/any other nasty ones get updated */
414 if ( oldrepeat != global_settings.repeat_mode &&
415 (audio_status() & AUDIO_STATUS_PLAY) )
417 audio_flush_and_reload_tracks();
419 if (oldshuffle != global_settings.playlist_shuffle
420 && audio_status() & AUDIO_STATUS_PLAY)
422 replaygain_update();
423 if (global_settings.playlist_shuffle)
424 playlist_randomise(NULL, current_tick, true);
425 else
426 playlist_sort(NULL, true);
429 return(0);
432 #ifdef BUTTON_F3
433 bool quick_screen_f3(int button_enter)
435 struct gui_quickscreen qs;
436 qs.items[QUICKSCREEN_TOP] = NULL;
437 qs.items[QUICKSCREEN_LEFT] =
438 find_setting(&global_settings.scrollbar, NULL);
439 qs.items[QUICKSCREEN_RIGHT] =
440 find_setting(&global_settings.statusbar, NULL);
441 qs.items[QUICKSCREEN_BOTTOM] =
442 #ifdef HAVE_LCD_FLIP
443 find_setting(&global_settings.flip_display, NULL);
444 #else
445 NULL;
446 #endif
447 qs.callback = NULL;
448 if (gui_syncquickscreen_run(&qs, button_enter))
450 settings_save();
451 settings_apply(false);
453 return(0);
455 #endif /* BUTTON_F3 */
457 /* stuff to make the quickscreen configurable */
458 bool is_setting_quickscreenable(const struct settings_list *setting)
460 /* to keep things simple, only settings which have a lang_id set are ok */
461 if (setting->lang_id < 0 || (setting->flags&F_BANFROMQS))
462 return false;
463 switch (setting->flags&F_T_MASK)
465 case F_T_BOOL:
466 return true;
467 case F_T_INT:
468 case F_T_UINT:
469 return (setting->RESERVED != NULL);
470 default:
471 return false;
475 void set_as_qs_item(const struct settings_list *setting,
476 enum quickscreen_item item)
478 int i;
479 for (i = 0; i < nb_settings; i++)
481 if (&settings[i] == setting)
482 break;
485 global_settings.qs_items[item] = i;