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