1 /**
2 * @file lv_disp.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_disp.h"
10 #include "../misc/lv_math.h"
11 #include "../core/lv_refr.h"
12
13 /*********************
14 * DEFINES
15 *********************/
16
17 /**********************
18 * TYPEDEFS
19 **********************/
20
21 /**********************
22 * STATIC PROTOTYPES
23 **********************/
24 static void scr_load_internal(lv_obj_t * scr);
25 static void scr_load_anim_start(lv_anim_t * a);
26 static void opa_scale_anim(void * obj, int32_t v);
27 static void set_x_anim(void * obj, int32_t v);
28 static void set_y_anim(void * obj, int32_t v);
29 static void scr_anim_ready(lv_anim_t * a);
30 static bool is_out_anim(lv_scr_load_anim_t a);
31
32 /**********************
33 * STATIC VARIABLES
34 **********************/
35
36 /**********************
37 * MACROS
38 **********************/
39
40 /**********************
41 * GLOBAL FUNCTIONS
42 **********************/
43
44 /**
45 * Return with a pointer to the active screen
46 * @param disp pointer to display which active screen should be get. (NULL to use the default
47 * screen)
48 * @return pointer to the active screen object (loaded by 'lv_scr_load()')
49 */
lv_disp_get_scr_act(lv_disp_t * disp)50 lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp)
51 {
52 if(!disp) disp = lv_disp_get_default();
53 if(!disp) {
54 LV_LOG_WARN("no display registered to get its active screen");
55 return NULL;
56 }
57
58 return disp->act_scr;
59 }
60
61 /**
62 * Return with a pointer to the previous screen. Only used during screen transitions.
63 * @param disp pointer to display which previous screen should be get. (NULL to use the default
64 * screen)
65 * @return pointer to the previous screen object or NULL if not used now
66 */
lv_disp_get_scr_prev(lv_disp_t * disp)67 lv_obj_t * lv_disp_get_scr_prev(lv_disp_t * disp)
68 {
69 if(!disp) disp = lv_disp_get_default();
70 if(!disp) {
71 LV_LOG_WARN("no display registered to get its previous screen");
72 return NULL;
73 }
74
75 return disp->prev_scr;
76 }
77
78 /**
79 * Make a screen active
80 * @param scr pointer to a screen
81 */
lv_disp_load_scr(lv_obj_t * scr)82 void lv_disp_load_scr(lv_obj_t * scr)
83 {
84 lv_scr_load_anim(scr, LV_SCR_LOAD_ANIM_NONE, 0, 0, false);
85 }
86
87 /**
88 * Return with the top layer. (Same on every screen and it is above the normal screen layer)
89 * @param disp pointer to display which top layer should be get. (NULL to use the default screen)
90 * @return pointer to the top layer object (transparent screen sized lv_obj)
91 */
lv_disp_get_layer_top(lv_disp_t * disp)92 lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp)
93 {
94 if(!disp) disp = lv_disp_get_default();
95 if(!disp) {
96 LV_LOG_WARN("lv_layer_top: no display registered to get its top layer");
97 return NULL;
98 }
99
100 return disp->top_layer;
101 }
102
103 /**
104 * Return with the sys. layer. (Same on every screen and it is above the normal screen and the top
105 * layer)
106 * @param disp pointer to display which sys. layer should be retrieved. (NULL to use the default screen)
107 * @return pointer to the sys layer object (transparent screen sized lv_obj)
108 */
lv_disp_get_layer_sys(lv_disp_t * disp)109 lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp)
110 {
111 if(!disp) disp = lv_disp_get_default();
112 if(!disp) {
113 LV_LOG_WARN("lv_layer_sys: no display registered to get its sys. layer");
114 return NULL;
115 }
116
117 return disp->sys_layer;
118 }
119
120 /**
121 * Set the theme of a display
122 * @param disp pointer to a display
123 */
lv_disp_set_theme(lv_disp_t * disp,lv_theme_t * th)124 void lv_disp_set_theme(lv_disp_t * disp, lv_theme_t * th)
125 {
126 if(!disp) disp = lv_disp_get_default();
127 if(!disp) {
128 LV_LOG_WARN("no display registered");
129 return;
130 }
131
132 disp->theme = th;
133
134 if(disp->screen_cnt == 3 &&
135 lv_obj_get_child_cnt(disp->screens[0]) == 0 &&
136 lv_obj_get_child_cnt(disp->screens[1]) == 0 &&
137 lv_obj_get_child_cnt(disp->screens[2]) == 0) {
138 lv_theme_apply(disp->screens[0]);
139 }
140 }
141 /**
142 * Get the theme of a display
143 * @param disp pointer to a display
144 * @return the display's theme (can be NULL)
145 */
lv_disp_get_theme(lv_disp_t * disp)146 lv_theme_t * lv_disp_get_theme(lv_disp_t * disp)
147 {
148 if(disp == NULL) disp = lv_disp_get_default();
149 return disp->theme;
150 }
151
152 /**
153 * Set the background color of a display
154 * @param disp pointer to a display
155 * @param color color of the background
156 */
lv_disp_set_bg_color(lv_disp_t * disp,lv_color_t color)157 void lv_disp_set_bg_color(lv_disp_t * disp, lv_color_t color)
158 {
159 if(!disp) disp = lv_disp_get_default();
160 if(!disp) {
161 LV_LOG_WARN("no display registered");
162 return;
163 }
164
165 disp->bg_color = color;
166
167 lv_area_t a;
168 lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
169 _lv_inv_area(disp, &a);
170
171 }
172
173 /**
174 * Set the background image of a display
175 * @param disp pointer to a display
176 * @param img_src path to file or pointer to an `lv_img_dsc_t` variable
177 */
lv_disp_set_bg_image(lv_disp_t * disp,const void * img_src)178 void lv_disp_set_bg_image(lv_disp_t * disp, const void * img_src)
179 {
180 if(!disp) disp = lv_disp_get_default();
181 if(!disp) {
182 LV_LOG_WARN("no display registered");
183 return;
184 }
185
186 disp->bg_img = img_src;
187
188 lv_area_t a;
189 lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
190 _lv_inv_area(disp, &a);
191 }
192
193 /**
194 * Set opacity of the background
195 * @param disp pointer to a display
196 * @param opa opacity (0..255)
197 */
lv_disp_set_bg_opa(lv_disp_t * disp,lv_opa_t opa)198 void lv_disp_set_bg_opa(lv_disp_t * disp, lv_opa_t opa)
199 {
200 if(!disp) disp = lv_disp_get_default();
201 if(!disp) {
202 LV_LOG_WARN("no display registered");
203 return;
204 }
205
206 disp->bg_opa = opa;
207
208 lv_area_t a;
209 lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
210 _lv_inv_area(disp, &a);
211 }
212
213 /**
214 * Switch screen with animation
215 * @param scr pointer to the new screen to load
216 * @param anim_type type of the animation from `lv_scr_load_anim_t`, e.g. `LV_SCR_LOAD_ANIM_MOVE_LEFT`
217 * @param time time of the animation
218 * @param delay delay before the transition
219 * @param auto_del true: automatically delete the old screen
220 */
lv_scr_load_anim(lv_obj_t * new_scr,lv_scr_load_anim_t anim_type,uint32_t time,uint32_t delay,bool auto_del)221 void lv_scr_load_anim(lv_obj_t * new_scr, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del)
222 {
223
224 lv_disp_t * d = lv_obj_get_disp(new_scr);
225 lv_obj_t * act_scr = lv_scr_act();
226
227 /*If an other screen load animation is in progress
228 *make target screen loaded immediately. */
229 if(d->scr_to_load && act_scr != d->scr_to_load) {
230 scr_load_internal(d->scr_to_load);
231 lv_anim_del(d->scr_to_load, NULL);
232 lv_obj_set_pos(d->scr_to_load, 0, 0);
233 lv_obj_remove_local_style_prop(d->scr_to_load, LV_STYLE_OPA, 0);
234
235 if(d->del_prev) {
236 lv_obj_del(act_scr);
237 }
238 act_scr = d->scr_to_load;
239 }
240
241 d->scr_to_load = new_scr;
242
243 if(d->prev_scr && d->del_prev) {
244 lv_obj_del(d->prev_scr);
245 d->prev_scr = NULL;
246 }
247
248 d->draw_prev_over_act = is_out_anim(anim_type);
249 d->del_prev = auto_del;
250
251 /*Be sure there is no other animation on the screens*/
252 lv_anim_del(new_scr, NULL);
253 lv_anim_del(lv_scr_act(), NULL);
254
255 /*Be sure both screens are in a normal position*/
256 lv_obj_set_pos(new_scr, 0, 0);
257 lv_obj_set_pos(lv_scr_act(), 0, 0);
258 lv_obj_remove_local_style_prop(new_scr, LV_STYLE_OPA, 0);
259 lv_obj_remove_local_style_prop(lv_scr_act(), LV_STYLE_OPA, 0);
260
261
262 /*Shortcut for immediate load*/
263 if(time == 0 && delay == 0) {
264 scr_load_internal(new_scr);
265 return;
266 }
267
268 lv_anim_t a_new;
269 lv_anim_init(&a_new);
270 lv_anim_set_var(&a_new, new_scr);
271 lv_anim_set_start_cb(&a_new, scr_load_anim_start);
272 lv_anim_set_ready_cb(&a_new, scr_anim_ready);
273 lv_anim_set_time(&a_new, time);
274 lv_anim_set_delay(&a_new, delay);
275
276 lv_anim_t a_old;
277 lv_anim_init(&a_old);
278 lv_anim_set_var(&a_old, d->act_scr);
279 lv_anim_set_time(&a_old, time);
280 lv_anim_set_delay(&a_old, delay);
281
282 switch(anim_type) {
283 case LV_SCR_LOAD_ANIM_NONE:
284 /*Create a dummy animation to apply the delay*/
285 lv_anim_set_exec_cb(&a_new, set_x_anim);
286 lv_anim_set_values(&a_new, 0, 0);
287 break;
288 case LV_SCR_LOAD_ANIM_OVER_LEFT:
289 lv_anim_set_exec_cb(&a_new, set_x_anim);
290 lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0);
291 break;
292 case LV_SCR_LOAD_ANIM_OVER_RIGHT:
293 lv_anim_set_exec_cb(&a_new, set_x_anim);
294 lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0);
295 break;
296 case LV_SCR_LOAD_ANIM_OVER_TOP:
297 lv_anim_set_exec_cb(&a_new, set_y_anim);
298 lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0);
299 break;
300 case LV_SCR_LOAD_ANIM_OVER_BOTTOM:
301 lv_anim_set_exec_cb(&a_new, set_y_anim);
302 lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0);
303 break;
304 case LV_SCR_LOAD_ANIM_MOVE_LEFT:
305 lv_anim_set_exec_cb(&a_new, set_x_anim);
306 lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0);
307
308 lv_anim_set_exec_cb(&a_old, set_x_anim);
309 lv_anim_set_values(&a_old, 0, -lv_disp_get_hor_res(d));
310 break;
311 case LV_SCR_LOAD_ANIM_MOVE_RIGHT:
312 lv_anim_set_exec_cb(&a_new, set_x_anim);
313 lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0);
314
315 lv_anim_set_exec_cb(&a_old, set_x_anim);
316 lv_anim_set_values(&a_old, 0, lv_disp_get_hor_res(d));
317 break;
318 case LV_SCR_LOAD_ANIM_MOVE_TOP:
319 lv_anim_set_exec_cb(&a_new, set_y_anim);
320 lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0);
321
322 lv_anim_set_exec_cb(&a_old, set_y_anim);
323 lv_anim_set_values(&a_old, 0, -lv_disp_get_ver_res(d));
324 break;
325 case LV_SCR_LOAD_ANIM_MOVE_BOTTOM:
326 lv_anim_set_exec_cb(&a_new, set_y_anim);
327 lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0);
328
329 lv_anim_set_exec_cb(&a_old, set_y_anim);
330 lv_anim_set_values(&a_old, 0, lv_disp_get_ver_res(d));
331 break;
332 case LV_SCR_LOAD_ANIM_FADE_IN:
333 lv_anim_set_exec_cb(&a_new, opa_scale_anim);
334 lv_anim_set_values(&a_new, LV_OPA_TRANSP, LV_OPA_COVER);
335 break;
336 case LV_SCR_LOAD_ANIM_FADE_OUT:
337 lv_anim_set_exec_cb(&a_old, opa_scale_anim);
338 lv_anim_set_values(&a_old, LV_OPA_COVER, LV_OPA_TRANSP);
339 break;
340 case LV_SCR_LOAD_ANIM_OUT_LEFT:
341 lv_anim_set_exec_cb(&a_old, set_x_anim);
342 lv_anim_set_values(&a_old, 0, -lv_disp_get_hor_res(d));
343 break;
344 case LV_SCR_LOAD_ANIM_OUT_RIGHT:
345 lv_anim_set_exec_cb(&a_old, set_x_anim);
346 lv_anim_set_values(&a_old, 0, lv_disp_get_hor_res(d));
347 break;
348 case LV_SCR_LOAD_ANIM_OUT_TOP:
349 lv_anim_set_exec_cb(&a_old, set_y_anim);
350 lv_anim_set_values(&a_old, 0, -lv_disp_get_ver_res(d));
351 break;
352 case LV_SCR_LOAD_ANIM_OUT_BOTTOM:
353 lv_anim_set_exec_cb(&a_old, set_y_anim);
354 lv_anim_set_values(&a_old, 0, lv_disp_get_ver_res(d));
355 break;
356 }
357
358 lv_event_send(act_scr, LV_EVENT_SCREEN_UNLOAD_START, NULL);
359
360 lv_anim_start(&a_new);
361 lv_anim_start(&a_old);
362 }
363
364 /**
365 * Get elapsed time since last user activity on a display (e.g. click)
366 * @param disp pointer to a display (NULL to get the overall smallest inactivity)
367 * @return elapsed ticks (milliseconds) since the last activity
368 */
lv_disp_get_inactive_time(const lv_disp_t * disp)369 uint32_t lv_disp_get_inactive_time(const lv_disp_t * disp)
370 {
371 if(disp) return lv_tick_elaps(disp->last_activity_time);
372
373 lv_disp_t * d;
374 uint32_t t = UINT32_MAX;
375 d = lv_disp_get_next(NULL);
376 while(d) {
377 uint32_t elaps = lv_tick_elaps(d->last_activity_time);
378 t = LV_MIN(t, elaps);
379 d = lv_disp_get_next(d);
380 }
381
382 return t;
383 }
384
385 /**
386 * Manually trigger an activity on a display
387 * @param disp pointer to a display (NULL to use the default display)
388 */
lv_disp_trig_activity(lv_disp_t * disp)389 void lv_disp_trig_activity(lv_disp_t * disp)
390 {
391 if(!disp) disp = lv_disp_get_default();
392 if(!disp) {
393 LV_LOG_WARN("lv_disp_trig_activity: no display registered");
394 return;
395 }
396
397 disp->last_activity_time = lv_tick_get();
398 }
399
400 /**
401 * Clean any CPU cache that is related to the display.
402 * @param disp pointer to a display (NULL to use the default display)
403 */
lv_disp_clean_dcache(lv_disp_t * disp)404 void lv_disp_clean_dcache(lv_disp_t * disp)
405 {
406 if(!disp) disp = lv_disp_get_default();
407 if(!disp) {
408 LV_LOG_WARN("lv_disp_clean_dcache: no display registered");
409 return;
410 }
411
412 if(disp->driver->clean_dcache_cb)
413 disp->driver->clean_dcache_cb(disp->driver);
414 }
415
416 /**
417 * Temporarily enable and disable the invalidation of the display.
418 * @param disp pointer to a display (NULL to use the default display)
419 * @param en true: enable invalidation; false: invalidation
420 */
lv_disp_enable_invalidation(lv_disp_t * disp,bool en)421 void lv_disp_enable_invalidation(lv_disp_t * disp, bool en)
422 {
423 if(!disp) disp = lv_disp_get_default();
424 if(!disp) {
425 LV_LOG_WARN("no display registered");
426 return;
427 }
428
429 disp->inv_en_cnt += en ? 1 : -1;
430 }
431
432 /**
433 * Get display invalidation is enabled.
434 * @param disp pointer to a display (NULL to use the default display)
435 * @return return true if invalidation is enabled
436 */
lv_disp_is_invalidation_enabled(lv_disp_t * disp)437 bool lv_disp_is_invalidation_enabled(lv_disp_t * disp)
438 {
439 if(!disp) disp = lv_disp_get_default();
440 if(!disp) {
441 LV_LOG_WARN("no display registered");
442 return false;
443 }
444
445 return (disp->inv_en_cnt > 0);
446 }
447
448 /**
449 * Get a pointer to the screen refresher timer to
450 * modify its parameters with `lv_timer_...` functions.
451 * @param disp pointer to a display
452 * @return pointer to the display refresher timer. (NULL on error)
453 */
_lv_disp_get_refr_timer(lv_disp_t * disp)454 lv_timer_t * _lv_disp_get_refr_timer(lv_disp_t * disp)
455 {
456 if(!disp) disp = lv_disp_get_default();
457 if(!disp) {
458 LV_LOG_WARN("lv_disp_get_refr_timer: no display registered");
459 return NULL;
460 }
461
462 return disp->refr_timer;
463 }
464
465 /**********************
466 * STATIC FUNCTIONS
467 **********************/
468
scr_load_internal(lv_obj_t * scr)469 static void scr_load_internal(lv_obj_t * scr)
470 {
471 lv_disp_t * d = lv_obj_get_disp(scr);
472 if(!d) return; /*Shouldn't happen, just to be sure*/
473
474 lv_obj_t * old_scr = d->act_scr;
475
476 if(d->act_scr) lv_event_send(old_scr, LV_EVENT_SCREEN_UNLOAD_START, NULL);
477 if(d->act_scr) lv_event_send(scr, LV_EVENT_SCREEN_LOAD_START, NULL);
478
479 d->act_scr = scr;
480
481 if(d->act_scr) lv_event_send(scr, LV_EVENT_SCREEN_LOADED, NULL);
482 if(d->act_scr) lv_event_send(old_scr, LV_EVENT_SCREEN_UNLOADED, NULL);
483
484 lv_obj_invalidate(scr);
485 }
486
scr_load_anim_start(lv_anim_t * a)487 static void scr_load_anim_start(lv_anim_t * a)
488 {
489 lv_disp_t * d = lv_obj_get_disp(a->var);
490
491 d->prev_scr = lv_scr_act();
492 d->act_scr = a->var;
493
494 lv_event_send(d->act_scr, LV_EVENT_SCREEN_LOAD_START, NULL);
495 }
496
opa_scale_anim(void * obj,int32_t v)497 static void opa_scale_anim(void * obj, int32_t v)
498 {
499 lv_obj_set_style_opa(obj, v, 0);
500 }
501
set_x_anim(void * obj,int32_t v)502 static void set_x_anim(void * obj, int32_t v)
503 {
504 lv_obj_set_x(obj, v);
505 }
506
set_y_anim(void * obj,int32_t v)507 static void set_y_anim(void * obj, int32_t v)
508 {
509 lv_obj_set_y(obj, v);
510 }
511
scr_anim_ready(lv_anim_t * a)512 static void scr_anim_ready(lv_anim_t * a)
513 {
514 lv_disp_t * d = lv_obj_get_disp(a->var);
515
516 lv_event_send(d->act_scr, LV_EVENT_SCREEN_LOADED, NULL);
517 lv_event_send(d->prev_scr, LV_EVENT_SCREEN_UNLOADED, NULL);
518
519 if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr);
520 d->prev_scr = NULL;
521 d->draw_prev_over_act = false;
522 d->scr_to_load = NULL;
523 lv_obj_remove_local_style_prop(a->var, LV_STYLE_OPA, 0);
524 lv_obj_invalidate(d->act_scr);
525 }
526
is_out_anim(lv_scr_load_anim_t anim_type)527 static bool is_out_anim(lv_scr_load_anim_t anim_type)
528 {
529 return anim_type == LV_SCR_LOAD_ANIM_FADE_OUT ||
530 anim_type == LV_SCR_LOAD_ANIM_OUT_LEFT ||
531 anim_type == LV_SCR_LOAD_ANIM_OUT_RIGHT ||
532 anim_type == LV_SCR_LOAD_ANIM_OUT_TOP ||
533 anim_type == LV_SCR_LOAD_ANIM_OUT_BOTTOM;
534 }
535