make the quickscreen talk
[Rockbox.git] / apps / gui / quickscreen.c
blob36f3d8221726c597bd3ed05d2d1e2b90d3ffb093
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Jonathan Gordon
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 #include <stdio.h>
22 #include "config.h"
23 #include "system.h"
24 #include "icons.h"
25 #include "textarea.h"
26 #include "font.h"
27 #include "kernel.h"
28 #include "misc.h"
29 #include "statusbar.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"
40 static struct viewport vps[NB_SCREENS][QUICKSCREEN_ITEM_COUNT];
41 static struct viewport vp_icons[NB_SCREENS];
42 /* vp_icons will be used like this:
43 the side icons will be aligned to the top of this vp and to their sides
44 the bottom icon wil be aligned center and at the bottom of this vp */
46 #define MIN_LINES 4
47 #define MAX_NEEDED_LINES 8
48 #define CENTER_MARGIN 10 /* pixels between the 2 center items minimum */
49 #define CENTER_ICONAREA_WIDTH (CENTER_MARGIN+8*2)
51 static void quickscreen_fix_viewports(struct gui_quickscreen *qs,
52 struct screen *display,
53 struct viewport *parent)
55 int char_height, i, screen = display->screen_type;
56 int left_width, right_width, bottom_lines = 3;
57 unsigned char *s;
58 int nb_lines = viewport_get_nb_lines(parent);
59 char_height = parent->height/nb_lines;
61 vp_icons[screen] = *parent;
63 vps[screen][QUICKSCREEN_BOTTOM] = *parent;
64 if (nb_lines <= MIN_LINES) /* make the bottom item use 1 line */
65 bottom_lines = 1;
66 else
67 bottom_lines = 2;
68 vps[screen][QUICKSCREEN_BOTTOM].height = bottom_lines*char_height;
69 vps[screen][QUICKSCREEN_BOTTOM].y = parent->y + parent->height - bottom_lines*char_height;
70 if (nb_lines >= MAX_NEEDED_LINES)
72 vps[screen][QUICKSCREEN_BOTTOM].y -= char_height;
75 /* adjust the left/right items widths to fit the screen nicely */
76 s = P2STR(ID2P(qs->items[QUICKSCREEN_LEFT]->lang_id));
77 left_width = display->getstringsize(s, NULL, NULL);
78 s = P2STR(ID2P(qs->items[QUICKSCREEN_RIGHT]->lang_id));
79 right_width = display->getstringsize(s, NULL, NULL);
80 nb_lines -= bottom_lines;
82 vps[screen][QUICKSCREEN_LEFT] = *parent;
83 vps[screen][QUICKSCREEN_RIGHT] = *parent;
84 vps[screen][QUICKSCREEN_LEFT].x = parent->x;
85 if (nb_lines <= MIN_LINES)
86 i = 0;
87 else
88 i = nb_lines/2;
89 vps[screen][QUICKSCREEN_LEFT].y = parent->y + (i*char_height);
90 vps[screen][QUICKSCREEN_RIGHT].y = parent->y + (i*char_height);
91 if (nb_lines >= 3)
92 i = 3*char_height;
93 else
94 i = nb_lines*char_height;
96 vps[screen][QUICKSCREEN_LEFT].height = i;
97 vps[screen][QUICKSCREEN_RIGHT].height = i;
98 vp_icons[screen].y = vps[screen][QUICKSCREEN_LEFT].y + (char_height/2);
99 vp_icons[screen].height = vps[screen][QUICKSCREEN_BOTTOM].y - vp_icons[screen].y;
101 if (left_width + right_width > display->width - CENTER_MARGIN) /* scrolling needed */
103 int width = (parent->width - CENTER_ICONAREA_WIDTH)/2;
104 vps[screen][QUICKSCREEN_LEFT].width = width;
105 vps[screen][QUICKSCREEN_RIGHT].width = width;
106 vps[screen][QUICKSCREEN_RIGHT].x = parent->x+parent->width - width;
107 vp_icons[screen].x = parent->x + width;
108 vp_icons[screen].width = CENTER_ICONAREA_WIDTH;
110 else
112 int width, pad = 0;
113 if (left_width > right_width)
114 width = left_width;
115 else
116 width = right_width;
117 width += CENTER_MARGIN;
118 if (width*2 < parent->width/2)
120 width += parent->width/6;
121 /* add some padding on the edges */
122 pad = CENTER_MARGIN;
124 vps[screen][QUICKSCREEN_LEFT].width = width;
125 vps[screen][QUICKSCREEN_RIGHT].width = width;
126 vps[screen][QUICKSCREEN_RIGHT].x = parent->x + parent->width - width;
127 vp_icons[screen].x = parent->x + width;
128 if (pad)
130 vp_icons[screen].x += pad;
131 vps[screen][QUICKSCREEN_LEFT].x += pad;
132 vps[screen][QUICKSCREEN_RIGHT].x -= pad;
133 /* need to add the pad to the bottom to make it all centered nicely */
134 vps[screen][QUICKSCREEN_BOTTOM].x += pad;
135 vps[screen][QUICKSCREEN_BOTTOM].width -= pad;
137 vp_icons[screen].width = vps[screen][QUICKSCREEN_RIGHT].x - width;
142 static void quickscreen_draw_text(char *s, int item, bool title,
143 struct screen *display, struct viewport *vp)
145 int nb_lines = viewport_get_nb_lines(vp);
146 int w, h, line = 0, x=0;
147 display->getstringsize(s, &w, &h);
149 if (nb_lines > 1 && !title)
150 line = 1;
151 switch (item)
153 case QUICKSCREEN_BOTTOM:
154 x = (vp->width - w)/2;
155 break;
156 case QUICKSCREEN_LEFT:
157 x = 0;
158 break;
159 case QUICKSCREEN_RIGHT:
160 x = vp->width - w;
161 break;
163 if (w>vp->width)
164 display->puts_scroll(0,line,s);
165 else
166 display->putsxy(x, line*h, s);
169 static void gui_quickscreen_draw(struct gui_quickscreen *qs,
170 struct screen *display,
171 struct viewport *parent)
173 int i;
174 char buf[MAX_PATH];
175 unsigned char *title, *value;
176 void *setting;
177 int temp;
178 display->set_viewport(parent);
179 display->clear_viewport();
180 for (i=0; i<QUICKSCREEN_ITEM_COUNT; i++)
183 if (!qs->items[i])
184 continue;
185 display->set_viewport(&vps[display->screen_type][i]);
186 display->scroll_stop(&vps[display->screen_type][i]);
188 title = P2STR(ID2P(qs->items[i]->lang_id));
189 setting = qs->items[i]->setting;
190 if ((qs->items[i]->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
191 temp = *(bool*)setting?1:0;
192 else
193 temp = *(int*)setting;
194 value = option_get_valuestring((struct settings_list*)qs->items[i], buf, MAX_PATH, temp);
196 if (vps[display->screen_type][i].height < display->char_height*2)
198 char text[MAX_PATH];
199 snprintf(text, MAX_PATH, "%s: %s", title, value);
200 quickscreen_draw_text(text, i, true, display, &vps[display->screen_type][i]);
202 else
204 quickscreen_draw_text(title, i, true, display, &vps[display->screen_type][i]);
205 quickscreen_draw_text(value, i, false, display, &vps[display->screen_type][i]);
207 display->update_viewport();
209 /* draw the icons */
210 display->set_viewport(&vp_icons[display->screen_type]);
211 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
212 vp_icons[display->screen_type].width - 8, 0, 7, 8);
213 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward], 0, 0, 7, 8);
214 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
215 (vp_icons[display->screen_type].width/2) - 4,
216 vp_icons[display->screen_type].height - 7, 7, 8);
217 display->update_viewport();
219 display->set_viewport(parent);
220 display->update_viewport();
221 display->set_viewport(NULL);
224 static int option_value(const struct settings_list *setting)
226 if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
228 return *(bool*)setting->setting==true?1:0;
230 else
231 return *(int*)setting->setting;
234 * Does the actions associated to the given button if any
235 * - qs : the quickscreen
236 * - button : the key we are going to analyse
237 * returns : true if the button corresponded to an action, false otherwise
239 static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
241 int item;
242 switch(button)
244 case ACTION_QS_LEFT:
245 item = QUICKSCREEN_LEFT;
246 break;
248 case ACTION_QS_DOWN:
249 case ACTION_QS_DOWNINV:
250 item = QUICKSCREEN_BOTTOM;
251 break;
253 case ACTION_QS_RIGHT:
254 item = QUICKSCREEN_RIGHT;
255 break;
257 default:
258 return false;
260 option_select_next_val((struct settings_list *)qs->items[item], false, true);
261 option_talk_value((struct settings_list *)qs->items[item],
262 option_value((struct settings_list *)qs->items[item]), false);
263 return true;
266 bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter)
268 int button, i;
269 struct viewport vp[NB_SCREENS];
270 bool changed = false;
271 /* To quit we need either :
272 * - a second press on the button that made us enter
273 * - an action taken while pressing the enter button,
274 * then release the enter button*/
275 bool can_quit=false;
276 gui_syncstatusbar_draw(&statusbars, true);
277 FOR_NB_SCREENS(i)
279 screens[i].set_viewport(NULL);
280 screens[i].stop_scroll();
281 viewport_set_defaults(&vp[i], i);
282 quickscreen_fix_viewports(qs, &screens[i], &vp[i]);
283 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
285 talk_id(qs->items[QUICKSCREEN_LEFT]->lang_id, false);
286 option_talk_value(qs->items[QUICKSCREEN_LEFT],
287 option_value(qs->items[QUICKSCREEN_LEFT]), true);
289 talk_id(qs->items[QUICKSCREEN_RIGHT]->lang_id, true);
290 option_talk_value(qs->items[QUICKSCREEN_RIGHT],
291 option_value(qs->items[QUICKSCREEN_RIGHT]), true);
293 talk_id(qs->items[QUICKSCREEN_BOTTOM]->lang_id, true);
294 option_talk_value(qs->items[QUICKSCREEN_BOTTOM],
295 option_value(qs->items[QUICKSCREEN_BOTTOM]), true);
296 while (true) {
297 button = get_action(CONTEXT_QUICKSCREEN,HZ/5);
298 if(default_event_handler(button) == SYS_USB_CONNECTED)
299 return(true);
300 if(gui_quickscreen_do_button(qs, button))
302 changed = true;
303 can_quit=true;
304 FOR_NB_SCREENS(i)
305 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
306 if (qs->callback)
307 qs->callback(qs);
309 else if(button==button_enter)
310 can_quit=true;
312 if((button == button_enter) && can_quit)
313 break;
315 if(button==ACTION_STD_CANCEL)
316 break;
318 gui_syncstatusbar_draw(&statusbars, false);
320 return changed;
323 bool quick_screen_quick(int button_enter)
325 struct gui_quickscreen qs;
326 bool oldshuffle = global_settings.playlist_shuffle;
327 int oldrepeat = global_settings.repeat_mode;
328 qs.items[QUICKSCREEN_LEFT] = find_setting(&global_settings.playlist_shuffle, NULL);
329 qs.items[QUICKSCREEN_RIGHT] = find_setting(&global_settings.repeat_mode, NULL);
330 qs.items[QUICKSCREEN_BOTTOM] = find_setting(&global_settings.dirfilter, NULL);
331 qs.callback = NULL;
332 if (gui_syncquickscreen_run(&qs, button_enter))
334 settings_save();
335 settings_apply(false);
336 /* make sure repeat/shuffle/any other nasty ones get updated */
337 if ( oldrepeat != global_settings.repeat_mode &&
338 (audio_status() & AUDIO_STATUS_PLAY) )
340 audio_flush_and_reload_tracks();
342 if (oldshuffle != global_settings.playlist_shuffle
343 && audio_status() & AUDIO_STATUS_PLAY)
345 #if CONFIG_CODEC == SWCODEC
346 dsp_set_replaygain();
347 #endif
348 if (global_settings.playlist_shuffle)
349 playlist_randomise(NULL, current_tick, true);
350 else
351 playlist_sort(NULL, true);
354 return(0);
357 #ifdef BUTTON_F3
358 bool quick_screen_f3(int button_enter)
360 struct gui_quickscreen qs;
361 qs.items[QUICKSCREEN_LEFT] = find_setting(&global_settings.scrollbar, NULL);
362 qs.items[QUICKSCREEN_RIGHT] = find_setting(&global_settings.statusbar, NULL);
363 qs.items[QUICKSCREEN_BOTTOM] = find_setting(&global_settings.flip_display, NULL);
364 qs.callback = NULL;
365 if (gui_syncquickscreen_run(&qs, button_enter))
367 settings_save();
368 settings_apply(false);
370 return(0);
372 #endif /* BUTTON_F3 */