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(act_scr == new_scr || d->scr_to_load == new_scr) {
228 return;
229 }
230
231 /*If an other screen load animation is in progress
232 *make target screen loaded immediately. */
233 if(d->scr_to_load) {
234 lv_anim_del(d->scr_to_load, NULL);
235 lv_obj_set_pos(d->scr_to_load, 0, 0);
236 lv_obj_remove_local_style_prop(d->scr_to_load, LV_STYLE_OPA, 0);
237
238 if(d->del_prev) {
239 lv_obj_del(act_scr);
240 }
241 act_scr = d->scr_to_load;
242
243 scr_load_internal(d->scr_to_load);
244 }
245
246 d->scr_to_load = new_scr;
247
248 if(d->prev_scr && d->del_prev) {
249 lv_obj_del(d->prev_scr);
250 d->prev_scr = NULL;
251 }
252
253 d->draw_prev_over_act = is_out_anim(anim_type);
254 d->del_prev = auto_del;
255
256 /*Be sure there is no other animation on the screens*/
257 lv_anim_del(new_scr, NULL);
258 lv_anim_del(lv_scr_act(), NULL);
259
260 /*Be sure both screens are in a normal position*/
261 lv_obj_set_pos(new_scr, 0, 0);
262 lv_obj_set_pos(lv_scr_act(), 0, 0);
263 lv_obj_remove_local_style_prop(new_scr, LV_STYLE_OPA, 0);
264 lv_obj_remove_local_style_prop(lv_scr_act(), LV_STYLE_OPA, 0);
265
266 /*Shortcut for immediate load*/
267 if(time == 0 && delay == 0) {
268 scr_load_internal(new_scr);
269 if(auto_del) lv_obj_del(act_scr);
270 return;
271 }
272
273 lv_anim_t a_new;
274 lv_anim_init(&a_new);
275 lv_anim_set_var(&a_new, new_scr);
276 lv_anim_set_start_cb(&a_new, scr_load_anim_start);
277 lv_anim_set_ready_cb(&a_new, scr_anim_ready);
278 lv_anim_set_time(&a_new, time);
279 lv_anim_set_delay(&a_new, delay);
280
281 lv_anim_t a_old;
282 lv_anim_init(&a_old);
283 lv_anim_set_var(&a_old, d->act_scr);
284 lv_anim_set_time(&a_old, time);
285 lv_anim_set_delay(&a_old, delay);
286
287 switch(anim_type) {
288 case LV_SCR_LOAD_ANIM_NONE:
289 /*Create a dummy animation to apply the delay*/
290 lv_anim_set_exec_cb(&a_new, set_x_anim);
291 lv_anim_set_values(&a_new, 0, 0);
292 break;
293 case LV_SCR_LOAD_ANIM_OVER_LEFT:
294 lv_anim_set_exec_cb(&a_new, set_x_anim);
295 lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0);
296 break;
297 case LV_SCR_LOAD_ANIM_OVER_RIGHT:
298 lv_anim_set_exec_cb(&a_new, set_x_anim);
299 lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0);
300 break;
301 case LV_SCR_LOAD_ANIM_OVER_TOP:
302 lv_anim_set_exec_cb(&a_new, set_y_anim);
303 lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0);
304 break;
305 case LV_SCR_LOAD_ANIM_OVER_BOTTOM:
306 lv_anim_set_exec_cb(&a_new, set_y_anim);
307 lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0);
308 break;
309 case LV_SCR_LOAD_ANIM_MOVE_LEFT:
310 lv_anim_set_exec_cb(&a_new, set_x_anim);
311 lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0);
312
313 lv_anim_set_exec_cb(&a_old, set_x_anim);
314 lv_anim_set_values(&a_old, 0, -lv_disp_get_hor_res(d));
315 break;
316 case LV_SCR_LOAD_ANIM_MOVE_RIGHT:
317 lv_anim_set_exec_cb(&a_new, set_x_anim);
318 lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0);
319
320 lv_anim_set_exec_cb(&a_old, set_x_anim);
321 lv_anim_set_values(&a_old, 0, lv_disp_get_hor_res(d));
322 break;
323 case LV_SCR_LOAD_ANIM_MOVE_TOP:
324 lv_anim_set_exec_cb(&a_new, set_y_anim);
325 lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0);
326
327 lv_anim_set_exec_cb(&a_old, set_y_anim);
328 lv_anim_set_values(&a_old, 0, -lv_disp_get_ver_res(d));
329 break;
330 case LV_SCR_LOAD_ANIM_MOVE_BOTTOM:
331 lv_anim_set_exec_cb(&a_new, set_y_anim);
332 lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0);
333
334 lv_anim_set_exec_cb(&a_old, set_y_anim);
335 lv_anim_set_values(&a_old, 0, lv_disp_get_ver_res(d));
336 break;
337 case LV_SCR_LOAD_ANIM_FADE_IN:
338 lv_anim_set_exec_cb(&a_new, opa_scale_anim);
339 lv_anim_set_values(&a_new, LV_OPA_TRANSP, LV_OPA_COVER);
340 break;
341 case LV_SCR_LOAD_ANIM_FADE_OUT:
342 lv_anim_set_exec_cb(&a_old, opa_scale_anim);
343 lv_anim_set_values(&a_old, LV_OPA_COVER, LV_OPA_TRANSP);
344 break;
345 case LV_SCR_LOAD_ANIM_OUT_LEFT:
346 lv_anim_set_exec_cb(&a_old, set_x_anim);
347 lv_anim_set_values(&a_old, 0, -lv_disp_get_hor_res(d));
348 break;
349 case LV_SCR_LOAD_ANIM_OUT_RIGHT:
350 lv_anim_set_exec_cb(&a_old, set_x_anim);
351 lv_anim_set_values(&a_old, 0, lv_disp_get_hor_res(d));
352 break;
353 case LV_SCR_LOAD_ANIM_OUT_TOP:
354 lv_anim_set_exec_cb(&a_old, set_y_anim);
355 lv_anim_set_values(&a_old, 0, -lv_disp_get_ver_res(d));
356 break;
357 case LV_SCR_LOAD_ANIM_OUT_BOTTOM:
358 lv_anim_set_exec_cb(&a_old, set_y_anim);
359 lv_anim_set_values(&a_old, 0, lv_disp_get_ver_res(d));
360 break;
361 }
362
363 lv_event_send(act_scr, LV_EVENT_SCREEN_UNLOAD_START, NULL);
364
365 lv_anim_start(&a_new);
366 lv_anim_start(&a_old);
367 }
368
369 /**
370 * Get elapsed time since last user activity on a display (e.g. click)
371 * @param disp pointer to a display (NULL to get the overall smallest inactivity)
372 * @return elapsed ticks (milliseconds) since the last activity
373 */
lv_disp_get_inactive_time(const lv_disp_t * disp)374 uint32_t lv_disp_get_inactive_time(const lv_disp_t * disp)
375 {
376 if(disp) return lv_tick_elaps(disp->last_activity_time);
377
378 lv_disp_t * d;
379 uint32_t t = UINT32_MAX;
380 d = lv_disp_get_next(NULL);
381 while(d) {
382 uint32_t elaps = lv_tick_elaps(d->last_activity_time);
383 t = LV_MIN(t, elaps);
384 d = lv_disp_get_next(d);
385 }
386
387 return t;
388 }
389
390 /**
391 * Manually trigger an activity on a display
392 * @param disp pointer to a display (NULL to use the default display)
393 */
lv_disp_trig_activity(lv_disp_t * disp)394 void lv_disp_trig_activity(lv_disp_t * disp)
395 {
396 if(!disp) disp = lv_disp_get_default();
397 if(!disp) {
398 LV_LOG_WARN("lv_disp_trig_activity: no display registered");
399 return;
400 }
401
402 disp->last_activity_time = lv_tick_get();
403 }
404
405 /**
406 * Clean any CPU cache that is related to the display.
407 * @param disp pointer to a display (NULL to use the default display)
408 */
lv_disp_clean_dcache(lv_disp_t * disp)409 void lv_disp_clean_dcache(lv_disp_t * disp)
410 {
411 if(!disp) disp = lv_disp_get_default();
412 if(!disp) {
413 LV_LOG_WARN("lv_disp_clean_dcache: no display registered");
414 return;
415 }
416
417 if(disp->driver->clean_dcache_cb)
418 disp->driver->clean_dcache_cb(disp->driver);
419 }
420
421 /**
422 * Temporarily enable and disable the invalidation of the display.
423 * @param disp pointer to a display (NULL to use the default display)
424 * @param en true: enable invalidation; false: invalidation
425 */
lv_disp_enable_invalidation(lv_disp_t * disp,bool en)426 void lv_disp_enable_invalidation(lv_disp_t * disp, bool en)
427 {
428 if(!disp) disp = lv_disp_get_default();
429 if(!disp) {
430 LV_LOG_WARN("no display registered");
431 return;
432 }
433
434 disp->inv_en_cnt += en ? 1 : -1;
435 }
436
437 /**
438 * Get display invalidation is enabled.
439 * @param disp pointer to a display (NULL to use the default display)
440 * @return return true if invalidation is enabled
441 */
lv_disp_is_invalidation_enabled(lv_disp_t * disp)442 bool lv_disp_is_invalidation_enabled(lv_disp_t * disp)
443 {
444 if(!disp) disp = lv_disp_get_default();
445 if(!disp) {
446 LV_LOG_WARN("no display registered");
447 return false;
448 }
449
450 return (disp->inv_en_cnt > 0);
451 }
452
453 /**
454 * Get a pointer to the screen refresher timer to
455 * modify its parameters with `lv_timer_...` functions.
456 * @param disp pointer to a display
457 * @return pointer to the display refresher timer. (NULL on error)
458 */
_lv_disp_get_refr_timer(lv_disp_t * disp)459 lv_timer_t * _lv_disp_get_refr_timer(lv_disp_t * disp)
460 {
461 if(!disp) disp = lv_disp_get_default();
462 if(!disp) {
463 LV_LOG_WARN("lv_disp_get_refr_timer: no display registered");
464 return NULL;
465 }
466
467 return disp->refr_timer;
468 }
469
470 /**********************
471 * STATIC FUNCTIONS
472 **********************/
473
scr_load_internal(lv_obj_t * scr)474 static void scr_load_internal(lv_obj_t * scr)
475 {
476 lv_disp_t * d = lv_obj_get_disp(scr);
477 if(!d) return; /*Shouldn't happen, just to be sure*/
478
479 lv_obj_t * old_scr = d->act_scr;
480
481 if(d->act_scr) lv_event_send(old_scr, LV_EVENT_SCREEN_UNLOAD_START, NULL);
482 if(d->act_scr) lv_event_send(scr, LV_EVENT_SCREEN_LOAD_START, NULL);
483
484 d->act_scr = scr;
485 d->scr_to_load = NULL;
486
487 if(d->act_scr) lv_event_send(scr, LV_EVENT_SCREEN_LOADED, NULL);
488 if(d->act_scr) lv_event_send(old_scr, LV_EVENT_SCREEN_UNLOADED, NULL);
489
490 lv_obj_invalidate(scr);
491 }
492
scr_load_anim_start(lv_anim_t * a)493 static void scr_load_anim_start(lv_anim_t * a)
494 {
495 lv_disp_t * d = lv_obj_get_disp(a->var);
496
497 d->prev_scr = lv_scr_act();
498 d->act_scr = a->var;
499
500 lv_event_send(d->act_scr, LV_EVENT_SCREEN_LOAD_START, NULL);
501 }
502
opa_scale_anim(void * obj,int32_t v)503 static void opa_scale_anim(void * obj, int32_t v)
504 {
505 lv_obj_set_style_opa(obj, v, 0);
506 }
507
set_x_anim(void * obj,int32_t v)508 static void set_x_anim(void * obj, int32_t v)
509 {
510 lv_obj_set_x(obj, v);
511 }
512
set_y_anim(void * obj,int32_t v)513 static void set_y_anim(void * obj, int32_t v)
514 {
515 lv_obj_set_y(obj, v);
516 }
517
scr_anim_ready(lv_anim_t * a)518 static void scr_anim_ready(lv_anim_t * a)
519 {
520 lv_disp_t * d = lv_obj_get_disp(a->var);
521
522 lv_event_send(d->act_scr, LV_EVENT_SCREEN_LOADED, NULL);
523 lv_event_send(d->prev_scr, LV_EVENT_SCREEN_UNLOADED, NULL);
524
525 if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr);
526 d->prev_scr = NULL;
527 d->draw_prev_over_act = false;
528 d->scr_to_load = NULL;
529 lv_obj_remove_local_style_prop(a->var, LV_STYLE_OPA, 0);
530 lv_obj_invalidate(d->act_scr);
531 }
532
is_out_anim(lv_scr_load_anim_t anim_type)533 static bool is_out_anim(lv_scr_load_anim_t anim_type)
534 {
535 return anim_type == LV_SCR_LOAD_ANIM_FADE_OUT ||
536 anim_type == LV_SCR_LOAD_ANIM_OUT_LEFT ||
537 anim_type == LV_SCR_LOAD_ANIM_OUT_RIGHT ||
538 anim_type == LV_SCR_LOAD_ANIM_OUT_TOP ||
539 anim_type == LV_SCR_LOAD_ANIM_OUT_BOTTOM;
540 }
541