diff options
Diffstat (limited to 'apps/gui/viewport.c')
-rw-r--r-- | apps/gui/viewport.c | 347 |
1 files changed, 178 insertions, 169 deletions
diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c index 9a7cfbd3cb..fbf5ea82ad 100644 --- a/apps/gui/viewport.c +++ b/apps/gui/viewport.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include "screen_access.h" | 28 | #include "screen_access.h" |
29 | #include "settings.h" | 29 | #include "settings.h" |
30 | #include "misc.h" | 30 | #include "misc.h" |
31 | #include "panic.h" | ||
32 | #include "viewport.h" | ||
31 | 33 | ||
32 | /*some short cuts for fg/bg/line selector handling */ | 34 | /*some short cuts for fg/bg/line selector handling */ |
33 | #ifdef HAVE_LCD_COLOR | 35 | #ifdef HAVE_LCD_COLOR |
@@ -38,10 +40,6 @@ | |||
38 | #define BG_FALLBACK LCD_DEFAULT_BG | 40 | #define BG_FALLBACK LCD_DEFAULT_BG |
39 | #endif | 41 | #endif |
40 | 42 | ||
41 | #ifdef HAVE_LCD_BITMAP | ||
42 | static void set_default_align_flags(struct viewport *vp); | ||
43 | #endif | ||
44 | |||
45 | /* all below isn't needed for pc tools (i.e. checkwps/wps editor) | 43 | /* all below isn't needed for pc tools (i.e. checkwps/wps editor) |
46 | * only viewport_parse_viewport() is */ | 44 | * only viewport_parse_viewport() is */ |
47 | #ifndef __PCTOOL__ | 45 | #ifndef __PCTOOL__ |
@@ -56,115 +54,187 @@ static void set_default_align_flags(struct viewport *vp); | |||
56 | #endif | 54 | #endif |
57 | #include "statusbar-skinned.h" | 55 | #include "statusbar-skinned.h" |
58 | #include "debug.h" | 56 | #include "debug.h" |
57 | #include "viewport.h" | ||
59 | 58 | ||
60 | 59 | #define VPSTACK_DEPTH 16 | |
61 | static int statusbar_enabled = 0; | 60 | struct viewport_stack_item |
62 | 61 | { | |
63 | #ifdef HAVE_LCD_BITMAP | ||
64 | static struct { | ||
65 | struct viewport* vp; | 62 | struct viewport* vp; |
66 | int active[NB_SCREENS]; | 63 | bool enabled; |
67 | } ui_vp_info; | 64 | }; |
68 | 65 | ||
69 | static struct viewport custom_vp[NB_SCREENS]; | 66 | #ifdef HAVE_LCD_BITMAP |
70 | |||
71 | /* callbacks for GUI_EVENT_* events */ | ||
72 | static void viewportmanager_ui_vp_changed(void *param); | ||
73 | static void viewportmanager_call_draw_func(void *param); | ||
74 | static void statusbar_toggled(void* param); | ||
75 | static unsigned viewport_init_ui_vp(void); | ||
76 | #endif | ||
77 | static void viewportmanager_redraw(void* data); | 67 | static void viewportmanager_redraw(void* data); |
68 | |||
69 | static int theme_stack_top[NB_SCREENS]; /* the last item added */ | ||
70 | static struct viewport_stack_item theme_stack[NB_SCREENS][VPSTACK_DEPTH]; | ||
71 | static bool is_theme_enabled(enum screen_type screen); | ||
78 | 72 | ||
79 | int viewport_get_nb_lines(const struct viewport *vp) | 73 | static void toggle_theme(void) |
80 | { | 74 | { |
81 | #ifdef HAVE_LCD_BITMAP | 75 | bool enable_event = false; |
82 | return vp->height/font_get(vp->font)->height; | 76 | static bool was_enabled[NB_SCREENS] = {false}; |
83 | #else | 77 | int i; |
84 | (void)vp; | 78 | FOR_NB_SCREENS(i) |
85 | return 2; | 79 | { |
80 | enable_event = enable_event || is_theme_enabled(i); | ||
81 | } | ||
82 | if (enable_event) | ||
83 | { | ||
84 | add_event(GUI_EVENT_ACTIONUPDATE, false, viewportmanager_redraw); | ||
85 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
86 | add_event(LCD_EVENT_ACTIVATION, false, do_sbs_update_callback); | ||
86 | #endif | 87 | #endif |
87 | } | 88 | add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, |
88 | 89 | do_sbs_update_callback); | |
89 | static bool showing_bars(enum screen_type screen) | 90 | add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, |
90 | { | 91 | do_sbs_update_callback); |
91 | if (statusbar_enabled & VP_SB_ONSCREEN(screen)) | 92 | |
93 | /* remove the left overs from the previous screen. | ||
94 | * could cause a tiny flicker. Redo your screen code if that happens */ | ||
95 | FOR_NB_SCREENS(i) | ||
96 | { | ||
97 | if (!was_enabled[i]) | ||
98 | { | ||
99 | struct viewport deadspace, user; | ||
100 | viewport_set_defaults(&user, i); | ||
101 | deadspace = user; /* get colours and everything */ | ||
102 | /* above */ | ||
103 | deadspace.x = 0; | ||
104 | deadspace.y = 0; | ||
105 | deadspace.width = screens[i].lcdwidth; | ||
106 | deadspace.height = user.y; | ||
107 | if (deadspace.width && deadspace.height) | ||
108 | { | ||
109 | screens[i].set_viewport(&deadspace); | ||
110 | screens[i].clear_viewport(); | ||
111 | screens[i].update_viewport(); | ||
112 | } | ||
113 | /* below */ | ||
114 | deadspace.y = user.y + user.height; | ||
115 | deadspace.height = screens[i].lcdheight - deadspace.y; | ||
116 | if (deadspace.width && deadspace.height) | ||
117 | { | ||
118 | screens[i].set_viewport(&deadspace); | ||
119 | screens[i].clear_viewport(); | ||
120 | screens[i].update_viewport(); | ||
121 | } | ||
122 | /* left */ | ||
123 | deadspace.x = 0; | ||
124 | deadspace.y = 0; | ||
125 | deadspace.width = user.x; | ||
126 | deadspace.height = screens[i].lcdheight; | ||
127 | if (deadspace.width && deadspace.height) | ||
128 | { | ||
129 | screens[i].set_viewport(&deadspace); | ||
130 | screens[i].clear_viewport(); | ||
131 | screens[i].update_viewport(); | ||
132 | } | ||
133 | /* below */ | ||
134 | deadspace.x = user.x + user.width; | ||
135 | deadspace.width = screens[i].lcdwidth - deadspace.x; | ||
136 | if (deadspace.width && deadspace.height) | ||
137 | { | ||
138 | screens[i].set_viewport(&deadspace); | ||
139 | screens[i].clear_viewport(); | ||
140 | screens[i].update_viewport(); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | send_event(GUI_EVENT_ACTIONUPDATE, (void*)1); /* force a redraw */ | ||
145 | } | ||
146 | else | ||
92 | { | 147 | { |
93 | #ifdef HAVE_LCD_BITMAP | 148 | FOR_NB_SCREENS(i) |
94 | int ignore; | 149 | screens[i].stop_scroll(); |
95 | ignore = statusbar_enabled & VP_SB_IGNORE_SETTING(screen); | 150 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) |
96 | return ignore || (statusbar_position(screen) != STATUSBAR_OFF); | 151 | remove_event(LCD_EVENT_ACTIVATION, do_sbs_update_callback); |
97 | #else | ||
98 | return true; | ||
99 | #endif | 152 | #endif |
153 | remove_event(PLAYBACK_EVENT_TRACK_CHANGE, do_sbs_update_callback); | ||
154 | remove_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, do_sbs_update_callback); | ||
155 | remove_event(GUI_EVENT_ACTIONUPDATE, viewportmanager_redraw); | ||
100 | } | 156 | } |
101 | return false; | 157 | |
158 | FOR_NB_SCREENS(i) | ||
159 | was_enabled[i] = is_theme_enabled(i); | ||
102 | } | 160 | } |
103 | 161 | ||
104 | 162 | void viewportmanager_theme_enable(enum screen_type screen, bool enable, | |
105 | void viewportmanager_init(void) | 163 | struct viewport *viewport) |
106 | { | 164 | { |
107 | #ifdef HAVE_LCD_BITMAP | 165 | int top = ++theme_stack_top[screen]; |
108 | add_event(GUI_EVENT_STATUSBAR_TOGGLE, false, statusbar_toggled); | 166 | if (top >= VPSTACK_DEPTH-1) |
109 | #endif | 167 | panicf("Stack overflow... viewportmanager"); |
110 | viewportmanager_set_statusbar(VP_SB_ALLSCREENS); | 168 | theme_stack[screen][top].enabled = enable; |
169 | theme_stack[screen][top].vp = viewport; | ||
170 | toggle_theme(); | ||
171 | /* then be nice and set the viewport up */ | ||
172 | if (viewport) | ||
173 | viewport_set_defaults(viewport, screen); | ||
111 | } | 174 | } |
112 | 175 | ||
113 | int viewportmanager_get_statusbar(void) | 176 | void viewportmanager_theme_undo(enum screen_type screen) |
114 | { | 177 | { |
115 | return statusbar_enabled; | 178 | int top = --theme_stack_top[screen]; |
179 | if (top < 0) | ||
180 | panicf("Stack underflow... viewportmanager"); | ||
181 | |||
182 | toggle_theme(); | ||
116 | } | 183 | } |
117 | 184 | ||
118 | int viewportmanager_set_statusbar(const int enabled) | 185 | |
186 | static bool is_theme_enabled(enum screen_type screen) | ||
119 | { | 187 | { |
120 | int old = statusbar_enabled; | 188 | int top = theme_stack_top[screen]; |
121 | int i; | 189 | return theme_stack[screen][top].enabled; |
122 | 190 | } | |
123 | statusbar_enabled = enabled; | ||
124 | 191 | ||
125 | FOR_NB_SCREENS(i) | 192 | static bool custom_vp_loaded_ok[NB_SCREENS]; |
126 | { | 193 | static struct viewport custom_vp[NB_SCREENS]; |
127 | if (showing_bars(i) | ||
128 | && statusbar_position(i) != STATUSBAR_CUSTOM) | ||
129 | { | ||
130 | add_event(GUI_EVENT_ACTIONUPDATE, false, viewportmanager_redraw); | ||
131 | gui_statusbar_draw(&statusbars.statusbars[i], true); | ||
132 | } | ||
133 | else | ||
134 | remove_event(GUI_EVENT_ACTIONUPDATE, viewportmanager_redraw); | ||
135 | } | ||
136 | 194 | ||
195 | static unsigned viewport_init_ui_vp(void); | ||
196 | #endif /* HAVE_LCD_BITMAP */ | ||
197 | |||
198 | int viewport_get_nb_lines(const struct viewport *vp) | ||
199 | { | ||
137 | #ifdef HAVE_LCD_BITMAP | 200 | #ifdef HAVE_LCD_BITMAP |
138 | FOR_NB_SCREENS(i) | 201 | return vp->height/font_get(vp->font)->height; |
139 | { | 202 | #else |
140 | sb_skin_set_state(showing_bars(i) | 203 | (void)vp; |
141 | && statusbar_position(i) == STATUSBAR_CUSTOM, i); | 204 | return 2; |
142 | } | ||
143 | #endif | 205 | #endif |
144 | return old; | ||
145 | } | 206 | } |
146 | 207 | ||
147 | static void viewportmanager_redraw(void* data) | 208 | static void viewportmanager_redraw(void* data) |
148 | { | 209 | { |
149 | int i; | 210 | int i; |
150 | |||
151 | FOR_NB_SCREENS(i) | 211 | FOR_NB_SCREENS(i) |
152 | { | 212 | { |
153 | if (showing_bars(i) | 213 | #ifdef HAVE_LCD_BITMAP |
154 | && statusbar_position(i) != STATUSBAR_CUSTOM) | 214 | if (statusbar_position(i) == STATUSBAR_CUSTOM) |
215 | sb_skin_update(i, NULL != data); | ||
216 | else if (statusbar_position(i) != STATUSBAR_OFF) | ||
217 | #endif | ||
155 | gui_statusbar_draw(&statusbars.statusbars[i], NULL != data); | 218 | gui_statusbar_draw(&statusbars.statusbars[i], NULL != data); |
156 | } | 219 | } |
157 | } | 220 | } |
158 | #ifdef HAVE_LCD_BITMAP | ||
159 | 221 | ||
160 | static void statusbar_toggled(void* param) | 222 | void viewportmanager_init() |
161 | { | 223 | { |
162 | (void)param; | 224 | #ifdef HAVE_LCD_BITMAP |
163 | /* update vp manager for the new setting and reposition vps | 225 | int i; |
164 | * if necessary */ | 226 | FOR_NB_SCREENS(i) |
165 | viewportmanager_theme_changed(THEME_STATUSBAR); | 227 | { |
228 | theme_stack_top[i] = -1; /* the next call fixes this to 0 */ | ||
229 | /* We always want the theme enabled by default... */ | ||
230 | viewportmanager_theme_enable(i, true, NULL); | ||
231 | } | ||
232 | #else | ||
233 | add_event(GUI_EVENT_ACTIONUPDATE, false, viewportmanager_redraw); | ||
234 | #endif | ||
166 | } | 235 | } |
167 | 236 | ||
237 | #ifdef HAVE_LCD_BITMAP | ||
168 | void viewportmanager_theme_changed(const int which) | 238 | void viewportmanager_theme_changed(const int which) |
169 | { | 239 | { |
170 | int i; | 240 | int i; |
@@ -177,91 +247,25 @@ void viewportmanager_theme_changed(const int which) | |||
177 | #endif | 247 | #endif |
178 | if (which & THEME_UI_VIEWPORT) | 248 | if (which & THEME_UI_VIEWPORT) |
179 | { | 249 | { |
180 | int retval = viewport_init_ui_vp(); | 250 | viewport_init_ui_vp(); |
181 | /* reset the ui viewport */ | ||
182 | FOR_NB_SCREENS(i) | ||
183 | ui_vp_info.active[i] = retval & BIT_N(i); | ||
184 | /* and point to it */ | ||
185 | ui_vp_info.vp = custom_vp; | ||
186 | } | 251 | } |
187 | else if (which & THEME_LANGUAGE) | 252 | if (which & THEME_LANGUAGE) |
188 | { /* THEME_UI_VIEWPORT handles rtl already */ | 253 | { |
189 | FOR_NB_SCREENS(i) | ||
190 | set_default_align_flags(&custom_vp[i]); | ||
191 | } | 254 | } |
192 | if (which & THEME_STATUSBAR) | 255 | if (which & THEME_STATUSBAR) |
193 | { | 256 | { |
194 | statusbar_enabled = 0; | ||
195 | FOR_NB_SCREENS(i) | 257 | FOR_NB_SCREENS(i) |
196 | { | 258 | { |
197 | if (statusbar_position(i) != STATUSBAR_OFF) | 259 | /* This can probably be done better... |
198 | statusbar_enabled |= VP_SB_ONSCREEN(i); | 260 | * disable the theme so it's forced to do a full redraw */ |
261 | viewportmanager_theme_enable(i, false, NULL); | ||
262 | viewportmanager_theme_undo(i); | ||
199 | } | 263 | } |
200 | |||
201 | viewportmanager_set_statusbar(statusbar_enabled); | ||
202 | |||
203 | /* reposition viewport to fit statusbar, only if not using the ui vp */ | ||
204 | |||
205 | FOR_NB_SCREENS(i) | ||
206 | { | ||
207 | if (!ui_vp_info.active[i]) | ||
208 | viewport_set_fullscreen(&custom_vp[i], i); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | int event_add = 0; | ||
213 | FOR_NB_SCREENS(i) | ||
214 | { | ||
215 | event_add |= ui_vp_info.active[i]; | ||
216 | event_add |= (statusbar_position(i) == STATUSBAR_CUSTOM); | ||
217 | } | ||
218 | |||
219 | /* add one of those to ensure the draw function is called always */ | ||
220 | if (event_add) | ||
221 | { | ||
222 | add_event(GUI_EVENT_REFRESH, false, viewportmanager_ui_vp_changed); | ||
223 | remove_event(GUI_EVENT_REFRESH, viewportmanager_call_draw_func); | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | add_event(GUI_EVENT_REFRESH, false, viewportmanager_call_draw_func); | ||
228 | remove_event(GUI_EVENT_REFRESH, viewportmanager_ui_vp_changed); | ||
229 | } | 264 | } |
230 | |||
231 | send_event(GUI_EVENT_THEME_CHANGED, NULL); | 265 | send_event(GUI_EVENT_THEME_CHANGED, NULL); |
232 | } | 266 | } |
233 | 267 | ||
234 | /* | 268 | /* |
235 | * simply calls a function that draws stuff, this exists to ensure the | ||
236 | * drawing function call in the GUI_EVENT_REFRESH event | ||
237 | * | ||
238 | * param should be 'void func(void)' */ | ||
239 | static void viewportmanager_call_draw_func(void *param) | ||
240 | { | ||
241 | /* cast param to a function */ | ||
242 | void (*draw_func)(void) = ((void(*)(void))param); | ||
243 | /* call the passed function which will redraw the content of | ||
244 | * the current screen */ | ||
245 | if (draw_func != NULL) | ||
246 | draw_func(); | ||
247 | } | ||
248 | |||
249 | static void viewportmanager_ui_vp_changed(void *param) | ||
250 | { | ||
251 | /* if the user changed the theme, we need to initiate a full redraw */ | ||
252 | int i; | ||
253 | /* start with clearing the screen */ | ||
254 | FOR_NB_SCREENS(i) | ||
255 | screens[i].clear_display(); | ||
256 | /* redraw the statusbar if it was enabled */ | ||
257 | send_event(GUI_EVENT_ACTIONUPDATE, (void*)true); | ||
258 | /* call redraw function */ | ||
259 | viewportmanager_call_draw_func(param); | ||
260 | FOR_NB_SCREENS(i) | ||
261 | screens[i].update(); | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * (re)parse the UI vp from the settings | 269 | * (re)parse the UI vp from the settings |
266 | * - Returns | 270 | * - Returns |
267 | * 0 if no UI vp is used at all | 271 | * 0 if no UI vp is used at all |
@@ -270,7 +274,7 @@ static void viewportmanager_ui_vp_changed(void *param) | |||
270 | static unsigned viewport_init_ui_vp(void) | 274 | static unsigned viewport_init_ui_vp(void) |
271 | { | 275 | { |
272 | int screen; | 276 | int screen; |
273 | unsigned ret = 0; | 277 | const char *ret = NULL; |
274 | char *setting; | 278 | char *setting; |
275 | FOR_NB_SCREENS(screen) | 279 | FOR_NB_SCREENS(screen) |
276 | { | 280 | { |
@@ -280,15 +284,13 @@ static unsigned viewport_init_ui_vp(void) | |||
280 | else | 284 | else |
281 | #endif | 285 | #endif |
282 | setting = global_settings.ui_vp_config; | 286 | setting = global_settings.ui_vp_config; |
283 | |||
284 | 287 | ||
285 | if (!(viewport_parse_viewport(&custom_vp[screen], screen, | 288 | ret = viewport_parse_viewport(&custom_vp[screen], screen, |
286 | setting, ','))) | 289 | setting, ','); |
287 | viewport_set_fullscreen(&custom_vp[screen], screen); | 290 | |
288 | else | 291 | custom_vp_loaded_ok[screen] = ret?true:false; |
289 | ret |= BIT_N(screen); | ||
290 | } | 292 | } |
291 | return ret; | 293 | return true; /* meh fixme */ |
292 | } | 294 | } |
293 | 295 | ||
294 | #ifdef HAVE_TOUCHSCREEN | 296 | #ifdef HAVE_TOUCHSCREEN |
@@ -301,6 +303,16 @@ bool viewport_point_within_vp(const struct viewport *vp, | |||
301 | return (is_x && is_y); | 303 | return (is_x && is_y); |
302 | } | 304 | } |
303 | #endif /* HAVE_TOUCHSCREEN */ | 305 | #endif /* HAVE_TOUCHSCREEN */ |
306 | |||
307 | static void set_default_align_flags(struct viewport *vp) | ||
308 | { | ||
309 | vp->flags &= ~VP_FLAG_ALIGNMENT_MASK; | ||
310 | #ifndef __PCTOOL__ | ||
311 | if (UNLIKELY(lang_is_rtl())) | ||
312 | vp->flags |= VP_FLAG_ALIGN_RIGHT; | ||
313 | #endif | ||
314 | } | ||
315 | |||
304 | #endif /* HAVE_LCD_BITMAP */ | 316 | #endif /* HAVE_LCD_BITMAP */ |
305 | #endif /* __PCTOOL__ */ | 317 | #endif /* __PCTOOL__ */ |
306 | 318 | ||
@@ -363,11 +375,17 @@ void viewport_set_defaults(struct viewport *vp, | |||
363 | #if defined(HAVE_LCD_BITMAP) && !defined(__PCTOOL__) | 375 | #if defined(HAVE_LCD_BITMAP) && !defined(__PCTOOL__) |
364 | 376 | ||
365 | struct viewport *sbs_area = NULL, *user_setting = NULL; | 377 | struct viewport *sbs_area = NULL, *user_setting = NULL; |
378 | if (!is_theme_enabled(screen)) | ||
379 | { | ||
380 | viewport_set_fullscreen(vp, screen); | ||
381 | return; | ||
382 | } | ||
366 | /* get the two viewports */ | 383 | /* get the two viewports */ |
367 | if (ui_vp_info.active[screen]) | 384 | if (custom_vp_loaded_ok[screen]) |
368 | user_setting = &ui_vp_info.vp[screen]; | 385 | user_setting = &custom_vp[screen]; |
369 | if (sb_skin_get_state(screen)) | 386 | if (sb_skin_get_state(screen)) |
370 | sbs_area = sb_skin_get_info_vp(screen); | 387 | sbs_area = sb_skin_get_info_vp(screen); |
388 | |||
371 | /* have both? get their intersection */ | 389 | /* have both? get their intersection */ |
372 | if (sbs_area && user_setting) | 390 | if (sbs_area && user_setting) |
373 | { | 391 | { |
@@ -380,6 +398,7 @@ void viewport_set_defaults(struct viewport *vp, | |||
380 | { | 398 | { |
381 | /* copy from ui vp first (for other field),fix coordinates after */ | 399 | /* copy from ui vp first (for other field),fix coordinates after */ |
382 | *vp = *user_setting; | 400 | *vp = *user_setting; |
401 | set_default_align_flags(vp); | ||
383 | vp->x = MAX(a->x, b->x); | 402 | vp->x = MAX(a->x, b->x); |
384 | vp->y = MAX(a->y, b->y); | 403 | vp->y = MAX(a->y, b->y); |
385 | vp->width = MIN(a->x + a->width, b->x + b->width) - vp->x; | 404 | vp->width = MIN(a->x + a->width, b->x + b->width) - vp->x; |
@@ -405,16 +424,6 @@ void viewport_set_defaults(struct viewport *vp, | |||
405 | 424 | ||
406 | 425 | ||
407 | #ifdef HAVE_LCD_BITMAP | 426 | #ifdef HAVE_LCD_BITMAP |
408 | |||
409 | static void set_default_align_flags(struct viewport *vp) | ||
410 | { | ||
411 | vp->flags &= ~VP_FLAG_ALIGNMENT_MASK; | ||
412 | #ifndef __PCTOOL__ | ||
413 | if (UNLIKELY(lang_is_rtl())) | ||
414 | vp->flags |= VP_FLAG_ALIGN_RIGHT; | ||
415 | #endif | ||
416 | } | ||
417 | |||
418 | const char* viewport_parse_viewport(struct viewport *vp, | 427 | const char* viewport_parse_viewport(struct viewport *vp, |
419 | enum screen_type screen, | 428 | enum screen_type screen, |
420 | const char *bufptr, | 429 | const char *bufptr, |