Prototype declaration strictness fixes.
[Rockbox.git] / apps / gui / quickscreen.c
blob5ebf1dc5ed04100c7d5fc0cedfbf274e26f52127
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 static void talk_qs_option(struct settings_list *opt, bool enqueue)
236 if (global_settings.talk_menu) {
237 if(!enqueue)
238 talk_shutup();
239 talk_id(opt->lang_id, true);
240 option_talk_value(opt, option_value(opt), true);
245 * Does the actions associated to the given button if any
246 * - qs : the quickscreen
247 * - button : the key we are going to analyse
248 * returns : true if the button corresponded to an action, false otherwise
250 static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
252 int item;
253 switch(button)
255 case ACTION_QS_LEFT:
256 item = QUICKSCREEN_LEFT;
257 break;
259 case ACTION_QS_DOWN:
260 case ACTION_QS_DOWNINV:
261 item = QUICKSCREEN_BOTTOM;
262 break;
264 case ACTION_QS_RIGHT:
265 item = QUICKSCREEN_RIGHT;
266 break;
268 default:
269 return false;
271 option_select_next_val((struct settings_list *)qs->items[item], false, true);
272 talk_qs_option((struct settings_list *)qs->items[item], false);
273 return true;
276 bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter)
278 int button, i;
279 struct viewport vp[NB_SCREENS];
280 bool changed = false;
281 /* To quit we need either :
282 * - a second press on the button that made us enter
283 * - an action taken while pressing the enter button,
284 * then release the enter button*/
285 bool can_quit=false;
286 gui_syncstatusbar_draw(&statusbars, true);
287 FOR_NB_SCREENS(i)
289 screens[i].set_viewport(NULL);
290 screens[i].stop_scroll();
291 viewport_set_defaults(&vp[i], i);
292 quickscreen_fix_viewports(qs, &screens[i], &vp[i]);
293 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
295 /* Announce current selection on entering this screen. This is all
296 queued up, but can be interrupted as soon as a setting is
297 changed. */
298 cond_talk_ids(VOICE_QUICKSCREEN);
299 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_LEFT], true);
300 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_BOTTOM], true);
301 talk_qs_option((struct settings_list *)qs->items[QUICKSCREEN_RIGHT], true);
302 while (true) {
303 button = get_action(CONTEXT_QUICKSCREEN,HZ/5);
304 if(default_event_handler(button) == SYS_USB_CONNECTED)
305 return(true);
306 if(gui_quickscreen_do_button(qs, button))
308 changed = true;
309 can_quit=true;
310 FOR_NB_SCREENS(i)
311 gui_quickscreen_draw(qs, &screens[i], &vp[i]);
312 if (qs->callback)
313 qs->callback(qs);
315 else if(button==button_enter)
316 can_quit=true;
318 if((button == button_enter) && can_quit)
319 break;
321 if(button==ACTION_STD_CANCEL)
322 break;
324 gui_syncstatusbar_draw(&statusbars, false);
326 /* Notify that we're exiting this screen */
327 cond_talk_ids_fq(VOICE_OK);
328 return changed;
331 bool quick_screen_quick(int button_enter)
333 struct gui_quickscreen qs;
334 bool oldshuffle = global_settings.playlist_shuffle;
335 int oldrepeat = global_settings.repeat_mode;
336 qs.items[QUICKSCREEN_LEFT] = find_setting(&global_settings.playlist_shuffle, NULL);
337 qs.items[QUICKSCREEN_RIGHT] = find_setting(&global_settings.repeat_mode, NULL);
338 qs.items[QUICKSCREEN_BOTTOM] = find_setting(&global_settings.dirfilter, NULL);
339 qs.callback = NULL;
340 if (gui_syncquickscreen_run(&qs, button_enter))
342 settings_save();
343 settings_apply(false);
344 /* make sure repeat/shuffle/any other nasty ones get updated */
345 if ( oldrepeat != global_settings.repeat_mode &&
346 (audio_status() & AUDIO_STATUS_PLAY) )
348 audio_flush_and_reload_tracks();
350 if (oldshuffle != global_settings.playlist_shuffle
351 && audio_status() & AUDIO_STATUS_PLAY)
353 #if CONFIG_CODEC == SWCODEC
354 dsp_set_replaygain();
355 #endif
356 if (global_settings.playlist_shuffle)
357 playlist_randomise(NULL, current_tick, true);
358 else
359 playlist_sort(NULL, true);
362 return(0);
365 #ifdef BUTTON_F3
366 bool quick_screen_f3(int button_enter)
368 struct gui_quickscreen qs;
369 qs.items[QUICKSCREEN_LEFT] = find_setting(&global_settings.scrollbar, NULL);
370 qs.items[QUICKSCREEN_RIGHT] = find_setting(&global_settings.statusbar, NULL);
371 qs.items[QUICKSCREEN_BOTTOM] = find_setting(&global_settings.flip_display, NULL);
372 qs.callback = NULL;
373 if (gui_syncquickscreen_run(&qs, button_enter))
375 settings_save();
376 settings_apply(false);
378 return(0);
380 #endif /* BUTTON_F3 */