Reorder a bit in viewport.c so that we don't need stubs for checkwps.
[kugel-rb.git] / apps / gui / viewport.c
blobb2fed557c0d681ab902dd5c206cd5840695fc708
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 <stdlib.h>
23 #include "config.h"
24 #include "lcd.h"
25 #include "lcd-remote.h"
26 #include "font.h"
27 #include "viewport.h"
28 #include "screen_access.h"
29 #include "settings.h"
30 #include "misc.h"
32 /*some short cuts for fg/bg/line selector handling */
33 #ifdef HAVE_LCD_COLOR
34 #define FG_FALLBACK global_settings.fg_color
35 #define BG_FALLBACK global_settings.bg_color
36 #else
37 #define FG_FALLBACK LCD_DEFAULT_FG
38 #define BG_FALLBACK LCD_DEFAULT_BG
39 #endif
41 static void set_default_align_flags(struct viewport *vp);
43 /* all below isn't needed for pc tools (i.e. checkwps/wps editor)
44 * only viewport_parse_viewport() is */
45 #ifndef __PCTOOL__
46 #include "sprintf.h"
47 #include "string.h"
48 #include "kernel.h"
49 #include "system.h"
50 #include "statusbar.h"
51 #include "appevents.h"
52 #ifdef HAVE_LCD_BITMAP
53 #include "language.h"
54 #endif
55 #include "statusbar-skinned.h"
56 #include "debug.h"
59 static int statusbar_enabled = 0;
61 #ifdef HAVE_LCD_BITMAP
62 static struct {
63 struct viewport* vp;
64 int active[NB_SCREENS];
65 } ui_vp_info;
67 static struct viewport custom_vp[NB_SCREENS];
69 /* callbacks for GUI_EVENT_* events */
70 static void viewportmanager_ui_vp_changed(void *param);
71 static void statusbar_toggled(void* param);
72 static unsigned viewport_init_ui_vp(void);
73 #endif
74 static void viewportmanager_redraw(void* data);
76 int viewport_get_nb_lines(const struct viewport *vp)
78 #ifdef HAVE_LCD_BITMAP
79 return vp->height/font_get(vp->font)->height;
80 #else
81 (void)vp;
82 return 2;
83 #endif
86 static bool showing_bars(enum screen_type screen)
88 if (statusbar_enabled & VP_SB_ONSCREEN(screen))
90 #ifdef HAVE_LCD_BITMAP
91 int ignore;
92 ignore = statusbar_enabled & VP_SB_IGNORE_SETTING(screen);
93 return ignore || (statusbar_position(screen) != STATUSBAR_OFF);
94 #else
95 return true;
96 #endif
98 return false;
102 void viewportmanager_init(void)
104 #ifdef HAVE_LCD_BITMAP
105 int retval, i;
106 add_event(GUI_EVENT_STATUSBAR_TOGGLE, false, statusbar_toggled);
107 retval = viewport_init_ui_vp();
108 FOR_NB_SCREENS(i)
109 ui_vp_info.active[i] = retval & BIT_N(i);
110 ui_vp_info.vp = custom_vp;
111 #endif
112 viewportmanager_set_statusbar(VP_SB_ALLSCREENS);
115 int viewportmanager_get_statusbar(void)
117 return statusbar_enabled;
120 int viewportmanager_set_statusbar(const int enabled)
122 int old = statusbar_enabled;
123 int i;
125 statusbar_enabled = enabled;
127 FOR_NB_SCREENS(i)
129 if (showing_bars(i)
130 && statusbar_position(i) != STATUSBAR_CUSTOM)
132 add_event(GUI_EVENT_ACTIONUPDATE, false, viewportmanager_redraw);
133 gui_statusbar_draw(&statusbars.statusbars[i], true);
135 else
136 remove_event(GUI_EVENT_ACTIONUPDATE, viewportmanager_redraw);
139 #ifdef HAVE_LCD_BITMAP
140 FOR_NB_SCREENS(i)
142 sb_skin_set_state(showing_bars(i)
143 && statusbar_position(i) == STATUSBAR_CUSTOM, i);
145 #endif
146 return old;
149 static void viewportmanager_redraw(void* data)
151 int i;
153 FOR_NB_SCREENS(i)
155 if (showing_bars(i)
156 && statusbar_position(i) != STATUSBAR_CUSTOM)
157 gui_statusbar_draw(&statusbars.statusbars[i], NULL != data);
160 #ifdef HAVE_LCD_BITMAP
162 static void statusbar_toggled(void* param)
164 (void)param;
165 /* update vp manager for the new setting and reposition vps
166 * if necessary */
167 viewportmanager_theme_changed(THEME_STATUSBAR);
170 void viewportmanager_theme_changed(const int which)
172 int i;
173 #ifdef HAVE_BUTTONBAR
174 if (which & THEME_BUTTONBAR)
175 { /* don't handle further, the custom ui viewport ignores the buttonbar,
176 * as does viewport_set_defaults(), since only lists use it*/
177 screens[SCREEN_MAIN].has_buttonbar = global_settings.buttonbar;
179 #endif
180 if (which & THEME_UI_VIEWPORT)
182 int retval = viewport_init_ui_vp();
183 /* reset the ui viewport */
184 FOR_NB_SCREENS(i)
185 ui_vp_info.active[i] = retval & BIT_N(i);
186 /* and point to it */
187 ui_vp_info.vp = custom_vp;
189 else if (which & THEME_LANGUAGE)
190 { /* THEME_UI_VIEWPORT handles rtl already */
191 FOR_NB_SCREENS(i)
192 set_default_align_flags(&custom_vp[i]);
194 if (which & THEME_STATUSBAR)
196 statusbar_enabled = 0;
197 FOR_NB_SCREENS(i)
199 if (statusbar_position(i) != STATUSBAR_OFF)
200 statusbar_enabled |= VP_SB_ONSCREEN(i);
203 viewportmanager_set_statusbar(statusbar_enabled);
205 /* reposition viewport to fit statusbar, only if not using the ui vp */
207 FOR_NB_SCREENS(i)
209 if (!ui_vp_info.active[i])
210 viewport_set_fullscreen(&custom_vp[i], i);
214 int event_add = 0;
215 FOR_NB_SCREENS(i)
217 event_add |= ui_vp_info.active[i];
218 event_add |= (statusbar_position(i) == STATUSBAR_CUSTOM);
221 if (event_add)
222 add_event(GUI_EVENT_REFRESH, false, viewportmanager_ui_vp_changed);
223 else
224 remove_event(GUI_EVENT_REFRESH, viewportmanager_ui_vp_changed);
226 send_event(GUI_EVENT_THEME_CHANGED, NULL);
229 static void viewportmanager_ui_vp_changed(void *param)
231 /* if the user changed the theme, we need to initiate a full redraw */
232 int i;
233 /* cast param to a function */
234 void (*draw_func)(void) = ((void(*)(void))param);
235 /* start with clearing the screen */
236 FOR_NB_SCREENS(i)
237 screens[i].clear_display();
238 /* redraw the statusbar if it was enabled */
239 send_event(GUI_EVENT_ACTIONUPDATE, (void*)true);
240 /* call the passed function which will redraw the content of
241 * the current screen */
242 if (draw_func != NULL)
243 draw_func();
244 FOR_NB_SCREENS(i)
245 screens[i].update();
248 void viewport_set_current_vp(struct viewport* vp)
250 if (vp != NULL)
251 ui_vp_info.vp = vp;
252 else
253 ui_vp_info.vp = custom_vp;
255 /* must be done after the assignment above or event handler get old vps */
256 send_event(GUI_EVENT_THEME_CHANGED, NULL);
259 struct viewport* viewport_get_current_vp(void)
261 return ui_vp_info.vp;
264 bool viewport_ui_vp_get_state(enum screen_type screen)
266 return ui_vp_info.active[screen];
270 * (re)parse the UI vp from the settings
271 * - Returns
272 * 0 if no UI vp is used at all
273 * else the bit for the screen (1<<screen) is set
275 static unsigned viewport_init_ui_vp(void)
277 int screen;
278 unsigned ret = 0;
279 char *setting;
280 FOR_NB_SCREENS(screen)
282 #ifdef HAVE_REMOTE_LCD
283 if ((screen == SCREEN_REMOTE))
284 setting = global_settings.remote_ui_vp_config;
285 else
286 #endif
287 setting = global_settings.ui_vp_config;
290 if (!(viewport_parse_viewport(&custom_vp[screen], screen,
291 setting, ',')))
292 viewport_set_fullscreen(&custom_vp[screen], screen);
293 else
294 ret |= BIT_N(screen);
296 return ret;
299 #ifdef HAVE_TOUCHSCREEN
300 /* check if a point (x and y coordinates) are within a viewport */
301 bool viewport_point_within_vp(const struct viewport *vp,
302 const int x, const int y)
304 bool is_x = (x >= vp->x && x < (vp->x + vp->width));
305 bool is_y = (y >= vp->y && y < (vp->y + vp->height));
306 return (is_x && is_y);
308 #endif /* HAVE_TOUCHSCREEN */
309 #endif /* HAVE_LCD_BITMAP */
310 #endif /* __PCTOOL__ */
312 #ifdef HAVE_LCD_COLOR
313 #define ARG_STRING(_depth) ((_depth) == 2 ? "dddddgg":"dddddcc")
314 #else
315 #define ARG_STRING(_depth) "dddddgg"
316 #endif
319 void viewport_set_fullscreen(struct viewport *vp,
320 const enum screen_type screen)
322 vp->x = 0;
323 vp->y = 0;
324 vp->width = screens[screen].lcdwidth;
325 vp->height = screens[screen].lcdheight;
327 #ifdef HAVE_LCD_BITMAP
328 set_default_align_flags(vp);
329 vp->font = FONT_UI; /* default to UI to discourage SYSFONT use */
330 vp->drawmode = DRMODE_SOLID;
331 #if LCD_DEPTH > 1
332 #ifdef HAVE_REMOTE_LCD
333 /* We only need this test if there is a remote LCD */
334 if (screen == SCREEN_MAIN)
335 #endif
337 vp->fg_pattern = FG_FALLBACK;
338 vp->bg_pattern = BG_FALLBACK;
339 #ifdef HAVE_LCD_COLOR
340 vp->lss_pattern = global_settings.lss_color;
341 vp->lse_pattern = global_settings.lse_color;
342 vp->lst_pattern = global_settings.lst_color;
343 #endif
345 #endif
347 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
348 if (screen == SCREEN_REMOTE)
350 vp->fg_pattern = LCD_REMOTE_DEFAULT_FG;
351 vp->bg_pattern = LCD_REMOTE_DEFAULT_BG;
353 #endif
354 #endif
357 void viewport_set_defaults(struct viewport *vp,
358 const enum screen_type screen)
360 /* Reposition:
361 1) If the "ui viewport" setting is set, and a sbs is loaded which specifies a %Vi
362 return the intersection of those two viewports
363 2) If only one of the "ui viewport" setting, or sbs %Vi is set
364 return it
365 3) No user viewports set
366 return the full display
368 #if defined(HAVE_LCD_BITMAP) && !defined(__PCTOOL__)
370 struct viewport *sbs_area = NULL, *user_setting = NULL;
371 /* get the two viewports */
372 if (ui_vp_info.active[screen])
373 user_setting = &ui_vp_info.vp[screen];
374 if (sb_skin_get_state(screen))
375 sbs_area = sb_skin_get_info_vp(screen);
376 /* have both? get their intersection */
377 if (sbs_area && user_setting)
379 struct viewport *a = sbs_area, *b = user_setting;
380 /* make sure they do actually overlap,
381 * if they dont its user error, so use the full display
382 * and live with redraw problems */
383 if (a->x < b->x + b->width &&
384 a->x + a->width > b->x &&
385 a->y < b->y + b->height &&
386 a->y + a->height > b->y)
388 vp->x = MAX(a->x, b->x);
389 vp->y = MAX(a->y, b->y);
390 vp->width = MIN(a->x + a->width, b->x + b->width) - vp->x;
391 vp->height = MIN(a->y + a->height, b->y + b->height) - vp->y;
394 /* only one so use it */
395 else if (sbs_area)
396 *vp = *sbs_area;
397 else if (user_setting)
398 *vp = *user_setting;
399 /* have neither so its fullscreen which was fixed at the beginning */
400 else
401 #endif /* HAVE_LCD_BITMAP */
402 viewport_set_fullscreen(vp, screen);
406 #ifdef HAVE_LCD_BITMAP
408 static void set_default_align_flags(struct viewport *vp)
410 vp->flags &= ~VP_FLAG_ALIGNMENT_MASK;
411 #ifndef __PCTOOL__
412 if (UNLIKELY(lang_is_rtl()))
413 vp->flags |= VP_FLAG_ALIGN_RIGHT;
414 #endif
417 const char* viewport_parse_viewport(struct viewport *vp,
418 enum screen_type screen,
419 const char *bufptr,
420 const char separator)
422 /* parse the list to the viewport struct */
423 const char *ptr = bufptr;
424 int depth;
425 uint32_t set = 0;
427 enum {
428 PL_X = 0,
429 PL_Y,
430 PL_WIDTH,
431 PL_HEIGHT,
432 PL_FONT,
433 PL_FG,
434 PL_BG,
437 /* Work out the depth of this display */
438 depth = screens[screen].depth;
439 #if (LCD_DEPTH == 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 1)
440 if (depth == 1)
442 if (!(ptr = parse_list("ddddd", &set, separator, ptr,
443 &vp->x, &vp->y, &vp->width, &vp->height, &vp->font)))
444 return NULL;
446 else
447 #endif
448 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
449 if (depth >= 2)
451 if (!(ptr = parse_list(ARG_STRING(depth), &set, separator, ptr,
452 &vp->x, &vp->y, &vp->width, &vp->height, &vp->font,
453 &vp->fg_pattern,&vp->bg_pattern)))
454 return NULL;
456 else
457 #endif
459 #undef ARG_STRING
461 /* X and Y *must* be set */
462 if (!LIST_VALUE_PARSED(set, PL_X) || !LIST_VALUE_PARSED(set, PL_Y))
463 return NULL;
464 /* check for negative values */
465 if (vp->x < 0)
466 vp->x += screens[screen].lcdwidth;
467 if (vp->y < 0)
468 vp->y += screens[screen].lcdheight;
470 /* fix defaults,
471 * and negative width/height which means "extend to edge minus value */
472 if (!LIST_VALUE_PARSED(set, PL_WIDTH))
473 vp->width = screens[screen].lcdwidth - vp->x;
474 else if (vp->width < 0)
475 vp->width = (vp->width + screens[screen].lcdwidth) - vp->x;
476 if (!LIST_VALUE_PARSED(set, PL_HEIGHT))
477 vp->height = screens[screen].lcdheight - vp->y;
478 else if (vp->height < 0)
479 vp->height = (vp->height + screens[screen].lcdheight) - vp->y;
481 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
482 if (!LIST_VALUE_PARSED(set, PL_FG))
483 vp->fg_pattern = FG_FALLBACK;
484 if (!LIST_VALUE_PARSED(set, PL_BG))
485 vp->bg_pattern = BG_FALLBACK;
486 #endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */
488 #ifdef HAVE_LCD_COLOR
489 vp->lss_pattern = global_settings.lss_color;
490 vp->lse_pattern = global_settings.lse_color;
491 vp->lst_pattern = global_settings.lst_color;
492 #endif
494 /* Validate the viewport dimensions - we know that the numbers are
495 non-negative integers, ignore bars and assume the viewport takes them
496 * into account */
497 if ((vp->x >= screens[screen].lcdwidth) ||
498 ((vp->x + vp->width) > screens[screen].lcdwidth) ||
499 (vp->y >= screens[screen].lcdheight) ||
500 ((vp->y + vp->height) > screens[screen].lcdheight))
502 return NULL;
505 /* Default to using the user font if the font was an invalid number or '-'*/
506 if (((vp->font != FONT_SYSFIXED) && (vp->font != FONT_UI))
507 || !LIST_VALUE_PARSED(set, PL_FONT)
509 vp->font = FONT_UI;
511 /* Set the defaults for fields not user-specified */
512 vp->drawmode = DRMODE_SOLID;
513 set_default_align_flags(vp);
515 return ptr;
517 #endif