Remove a viewport ambiguity by changing the screens width/heigth members into lcdwidt...
[kugel-rb.git] / apps / gui / quickscreen.c
blobef1111fe3e8bd8195b317d6794c27203c3172369
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"
41 static struct viewport vps[NB_SCREENS][QUICKSCREEN_ITEM_COUNT];
42 static struct viewport vp_icons[NB_SCREENS];
43 /* vp_icons will be used like this:
44 the side icons will be aligned to the top of this vp and to their sides
45 the bottom icon wil be aligned center and at the bottom of this vp */
47 #define MIN_LINES 4
48 #define MAX_NEEDED_LINES 8
49 #define CENTER_MARGIN 10 /* pixels between the 2 center items minimum */
50 #define CENTER_ICONAREA_WIDTH (CENTER_MARGIN+8*2)
52 static void quickscreen_fix_viewports(struct gui_quickscreen *qs,
53 struct screen *display,
54 struct viewport *parent)
56 #ifdef HAVE_REMOTE_LCD
57 int screen = display->screen_type;
58 #else
59 const int screen = 0;
60 #endif
62 int char_height, i;
63 int left_width, right_width, bottom_lines = 3;
64 unsigned char *s;
65 int nb_lines = viewport_get_nb_lines(parent);
66 char_height = parent->height/nb_lines;
68 vp_icons[screen] = *parent;
70 vps[screen][QUICKSCREEN_BOTTOM] = *parent;
71 if (nb_lines <= MIN_LINES) /* make the bottom item use 1 line */
72 bottom_lines = 1;
73 else
74 bottom_lines = 2;
75 vps[screen][QUICKSCREEN_BOTTOM].height = bottom_lines*char_height;
76 vps[screen][QUICKSCREEN_BOTTOM].y =
77 parent->y + parent->height - bottom_lines*char_height;
78 if (nb_lines >= MAX_NEEDED_LINES)
80 vps[screen][QUICKSCREEN_BOTTOM].y -= char_height;
83 /* adjust the left/right items widths to fit the screen nicely */
84 s = P2STR(ID2P(qs->items[QUICKSCREEN_LEFT]->lang_id));
85 left_width = display->getstringsize(s, NULL, NULL);
86 s = P2STR(ID2P(qs->items[QUICKSCREEN_RIGHT]->lang_id));
87 right_width = display->getstringsize(s, NULL, NULL);
88 nb_lines -= bottom_lines;
90 vps[screen][QUICKSCREEN_LEFT] = *parent;
91 vps[screen][QUICKSCREEN_RIGHT] = *parent;
92 vps[screen][QUICKSCREEN_LEFT].x = parent->x;
93 if (nb_lines <= MIN_LINES)
94 i = 0;
95 else
96 i = nb_lines/2;
97 vps[screen][QUICKSCREEN_LEFT].y = parent->y + (i*char_height);
98 vps[screen][QUICKSCREEN_RIGHT].y = parent->y + (i*char_height);
99 if (nb_lines >= 3)
100 i = 3*char_height;
101 else
102 i = nb_lines*char_height;
104 vps[screen][QUICKSCREEN_LEFT].height = i;
105 vps[screen][QUICKSCREEN_RIGHT].height = i;
106 vp_icons[screen].y = vps[screen][QUICKSCREEN_LEFT].y + (char_height/2);
107 vp_icons[screen].height =
108 vps[screen][QUICKSCREEN_BOTTOM].y - vp_icons[screen].y;
110 if (left_width + right_width > display->lcdwidth - CENTER_ICONAREA_WIDTH)
112 /* scrolling needed */
113 int width = (parent->width - CENTER_ICONAREA_WIDTH)/2;
114 vps[screen][QUICKSCREEN_LEFT].width = width;
115 vps[screen][QUICKSCREEN_RIGHT].width = width;
116 vps[screen][QUICKSCREEN_RIGHT].x = parent->x+parent->width - width;
117 vp_icons[screen].x = parent->x + width;
118 vp_icons[screen].width = CENTER_ICONAREA_WIDTH;
120 else
122 int width, pad = 0;
123 if (left_width > right_width)
124 width = left_width;
125 else
126 width = right_width;
127 width += CENTER_MARGIN;
128 if (width*2 < parent->width/2)
130 width += parent->width/6;
131 /* add some padding on the edges */
132 pad = CENTER_MARGIN;
134 vps[screen][QUICKSCREEN_LEFT].width = width;
135 vps[screen][QUICKSCREEN_RIGHT].width = width;
136 vps[screen][QUICKSCREEN_RIGHT].x = parent->x + parent->width - width;
137 vp_icons[screen].x = parent->x + width;
138 if (pad)
140 vp_icons[screen].x += pad;
141 vps[screen][QUICKSCREEN_LEFT].x += pad;
142 vps[screen][QUICKSCREEN_RIGHT].x -= pad;
143 /* need to add the pad to the bottom to make it all centered nicely */
144 vps[screen][QUICKSCREEN_BOTTOM].x += pad;
145 vps[screen][QUICKSCREEN_BOTTOM].width -= pad;
147 vp_icons[screen].width = vps[screen][QUICKSCREEN_RIGHT].x - width;
152 static void quickscreen_draw_text(char *s, int item, bool title,
153 struct screen *display, struct viewport *vp)
155 int nb_lines = viewport_get_nb_lines(vp);
156 int w, h, line = 0, x = 0;
157 display->getstringsize(s, &w, &h);
159 if (nb_lines > 1 && !title)
160 line = 1;
161 switch (item)
163 case QUICKSCREEN_BOTTOM:
164 x = (vp->width - w)/2;
165 break;
166 case QUICKSCREEN_LEFT:
167 x = 0;
168 break;
169 case QUICKSCREEN_RIGHT:
170 x = vp->width - w;
171 break;
173 if (w>vp->width)
174 display->puts_scroll(0, line, s);
175 else
176 display->putsxy(x, line*h, s);
179 static void gui_quickscreen_draw(struct gui_quickscreen *qs,
180 struct screen *display,
181 struct viewport *parent)
183 #ifdef HAVE_REMOTE_LCD
184 int screen = display->screen_type;
185 #else
186 const int screen = 0;
187 #endif
189 int i;
190 char buf[MAX_PATH];
191 unsigned char *title, *value;
192 void *setting;
193 int temp;
194 display->set_viewport(parent);
195 display->clear_viewport();
196 for (i=0; i<QUICKSCREEN_ITEM_COUNT; i++)
198 if (!qs->items[i])
199 continue;
200 display->set_viewport(&vps[screen][i]);
201 display->scroll_stop(&vps[screen][i]);
203 title = P2STR(ID2P(qs->items[i]->lang_id));
204 setting = qs->items[i]->setting;
205 temp = option_value_as_int(qs->items[i]);
206 value = option_get_valuestring((struct settings_list*)qs->items[i],
207 buf, MAX_PATH, temp);
209 if (vps[screen][i].height < display->char_height*2)
211 char text[MAX_PATH];
212 snprintf(text, MAX_PATH, "%s: %s", title, value);
213 quickscreen_draw_text(text, i, true, display, &vps[screen][i]);
215 else
217 quickscreen_draw_text(title, i, true, display, &vps[screen][i]);
218 quickscreen_draw_text(value, i, false, display, &vps[screen][i]);
220 display->update_viewport();
222 /* draw the icons */
223 display->set_viewport(&vp_icons[screen]);
224 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
225 vp_icons[screen].width - 8, 0, 7, 8);
226 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward], 0, 0, 7, 8);
227 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
228 (vp_icons[screen].width/2) - 4,
229 vp_icons[screen].height - 7, 7, 8);
230 display->update_viewport();
232 display->set_viewport(parent);
233 display->update_viewport();
234 display->set_viewport(NULL);
237 static void talk_qs_option(struct settings_list *opt, bool enqueue)
239 if (global_settings.talk_menu) {
240 if(!enqueue)
241 talk_shutup();
242 talk_id(opt->lang_id, true);
243 option_talk_value(opt, option_value_as_int(opt), true);
248 * Does the actions associated to the given button if any
249 * - qs : the quickscreen
250 * - button : the key we are going to analyse
251 * returns : true if the button corresponded to an action, false otherwise
253 static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
255 int item;
256 switch(button)
258 case ACTION_QS_LEFT:
259 item = QUICKSCREEN_LEFT;
260 break;
262 case ACTION_QS_DOWN:
263 case ACTION_QS_DOWNINV:
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], false, true);
275 talk_qs_option((struct settings_list *)qs->items[item], false);
276 return true;
279 bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter)
281 int button, i;
282 struct viewport vp[NB_SCREENS];
283 bool changed = false;
284 /* To quit we need either :
285 * - a second press on the button that made us enter
286 * - an action taken while pressing the enter button,
287 * then release the enter button*/
288 bool can_quit = false;
289 gui_syncstatusbar_draw(&statusbars, true);
290 FOR_NB_SCREENS(i)
292 screens[i].set_viewport(NULL);
293 screens[i].stop_scroll();
294 viewport_set_defaults(&vp[i], i);
295 quickscreen_fix_viewports(qs, &screens[i], &vp[i]);
296 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
298 /* Announce current selection on entering this screen. This is all
299 queued up, but can be interrupted as soon as a setting is
300 changed. */
301 cond_talk_ids(VOICE_QUICKSCREEN);
302 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_LEFT], true);
303 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_BOTTOM], true);
304 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_RIGHT], true);
305 while (true) {
306 button = get_action(CONTEXT_QUICKSCREEN,HZ/5);
307 if(default_event_handler(button) == SYS_USB_CONNECTED)
308 return(true);
309 if(gui_quickscreen_do_button(qs, button))
311 changed = true;
312 can_quit=true;
313 FOR_NB_SCREENS(i)
314 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
315 if (qs->callback)
316 qs->callback(qs);
318 else if(button==button_enter)
319 can_quit=true;
321 if((button == button_enter) && can_quit)
322 break;
324 if(button==ACTION_STD_CANCEL)
325 break;
327 gui_syncstatusbar_draw(&statusbars, false);
329 /* Notify that we're exiting this screen */
330 cond_talk_ids_fq(VOICE_OK);
331 return changed;
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;
339 qs.items[QUICKSCREEN_LEFT] =
340 find_setting(&global_settings.playlist_shuffle, NULL);
341 qs.items[QUICKSCREEN_RIGHT] =
342 find_setting(&global_settings.repeat_mode, NULL);
343 qs.items[QUICKSCREEN_BOTTOM] =
344 find_setting(&global_settings.dirfilter, NULL);
345 qs.callback = NULL;
346 if (gui_syncquickscreen_run(&qs, button_enter))
348 settings_save();
349 settings_apply(false);
350 /* make sure repeat/shuffle/any other nasty ones get updated */
351 if ( oldrepeat != global_settings.repeat_mode &&
352 (audio_status() & AUDIO_STATUS_PLAY) )
354 audio_flush_and_reload_tracks();
356 if (oldshuffle != global_settings.playlist_shuffle
357 && audio_status() & AUDIO_STATUS_PLAY)
359 #if CONFIG_CODEC == SWCODEC
360 dsp_set_replaygain();
361 #endif
362 if (global_settings.playlist_shuffle)
363 playlist_randomise(NULL, current_tick, true);
364 else
365 playlist_sort(NULL, true);
368 return(0);
371 #ifdef BUTTON_F3
372 bool quick_screen_f3(int button_enter)
374 struct gui_quickscreen qs;
375 qs.items[QUICKSCREEN_LEFT] =
376 find_setting(&global_settings.scrollbar, NULL);
377 qs.items[QUICKSCREEN_RIGHT] =
378 find_setting(&global_settings.statusbar, NULL);
379 qs.items[QUICKSCREEN_BOTTOM] =
380 find_setting(&global_settings.flip_display, NULL);
381 qs.callback = NULL;
382 if (gui_syncquickscreen_run(&qs, button_enter))
384 settings_save();
385 settings_apply(false);
387 return(0);
389 #endif /* BUTTON_F3 */