1 /**
2  * @file lv_disp.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_disp.h"
10 #include "../lv_misc/lv_math.h"
11 #include "../lv_core/lv_refr.h"
12 
13 /*********************
14  *      DEFINES
15  *********************/
16 
17 /**********************
18  *      TYPEDEFS
19  **********************/
20 
21 /**********************
22  *  STATIC PROTOTYPES
23  **********************/
24 
25 #if LV_USE_ANIMATION
26     static void scr_load_anim_start(lv_anim_t * a);
27     static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v);
28     static void scr_anim_ready(lv_anim_t * a);
29 #endif
30 
31 /**********************
32  *  STATIC VARIABLES
33  **********************/
34 
35 /**********************
36  *      MACROS
37  **********************/
38 
39 /**********************
40  *   GLOBAL FUNCTIONS
41  **********************/
42 
43 /**
44  * Return with a pointer to the active screen
45  * @param disp pointer to display which active screen should be get. (NULL to use the default
46  * screen)
47  * @return pointer to the active screen object (loaded by 'lv_scr_load()')
48  */
lv_disp_get_scr_act(lv_disp_t * disp)49 lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp)
50 {
51     if(!disp) disp = lv_disp_get_default();
52     if(!disp) {
53         LV_LOG_WARN("no display registered to get its active screen");
54         return NULL;
55     }
56 
57     return disp->act_scr;
58 }
59 
60 /**
61  * Return with a pointer to the previous screen. Only used during screen transitions.
62  * @param disp pointer to display which previous screen should be get. (NULL to use the default
63  * screen)
64  * @return pointer to the previous screen object or NULL if not used now
65  */
lv_disp_get_scr_prev(lv_disp_t * disp)66 lv_obj_t * lv_disp_get_scr_prev(lv_disp_t * disp)
67 {
68     if(!disp) disp = lv_disp_get_default();
69     if(!disp) {
70         LV_LOG_WARN("no display registered to get its previous screen");
71         return NULL;
72     }
73 
74     return disp->prev_scr;
75 }
76 
77 /**
78  * Make a screen active
79  * @param scr pointer to a screen
80  */
lv_disp_load_scr(lv_obj_t * scr)81 void lv_disp_load_scr(lv_obj_t * scr)
82 {
83     lv_disp_t * d = lv_obj_get_disp(scr);
84     if(!d) return;  /*Shouldn't happen, just to be sure*/
85     d->act_scr = scr;
86 
87     lv_obj_invalidate(scr);
88 }
89 
90 /**
91  * Return with the top layer. (Same on every screen and it is above the normal screen layer)
92  * @param disp pointer to display which top layer should be get. (NULL to use the default screen)
93  * @return pointer to the top layer object  (transparent screen sized lv_obj)
94  */
lv_disp_get_layer_top(lv_disp_t * disp)95 lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp)
96 {
97     if(!disp) disp = lv_disp_get_default();
98     if(!disp) {
99         LV_LOG_WARN("lv_layer_top: no display registered to get its top layer");
100         return NULL;
101     }
102 
103     return disp->top_layer;
104 }
105 
106 /**
107  * Return with the sys. layer. (Same on every screen and it is above the normal screen and the top
108  * layer)
109  * @param disp pointer to display which sys. layer  should be get. (NULL to use the default screen)
110  * @return pointer to the sys layer object  (transparent screen sized lv_obj)
111  */
lv_disp_get_layer_sys(lv_disp_t * disp)112 lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp)
113 {
114     if(!disp) disp = lv_disp_get_default();
115     if(!disp) {
116         LV_LOG_WARN("lv_layer_sys: no display registered to get its sys. layer");
117         return NULL;
118     }
119 
120     return disp->sys_layer;
121 }
122 
123 /**
124  * Assign a screen to a display.
125  * @param disp pointer to a display where to assign the screen
126  * @param scr pointer to a screen object to assign
127  */
lv_disp_assign_screen(lv_disp_t * disp,lv_obj_t * scr)128 void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr)
129 {
130     if(lv_obj_get_parent(scr) != NULL) {
131         LV_LOG_WARN("lv_disp_assign_screen: try to assign a non-screen object");
132         return;
133     }
134 
135     lv_disp_t * old_disp = lv_obj_get_disp(scr);
136 
137     if(old_disp == disp) return;
138 
139     _lv_ll_chg_list(&old_disp->scr_ll, &disp->scr_ll, scr, true);
140 }
141 
142 /**
143  * Set the background color of a display
144  * @param disp pointer to a display
145  * @param color color of the background
146  */
lv_disp_set_bg_color(lv_disp_t * disp,lv_color_t color)147 void lv_disp_set_bg_color(lv_disp_t * disp, lv_color_t color)
148 {
149     if(!disp) disp = lv_disp_get_default();
150     if(!disp) {
151         LV_LOG_WARN("no display registered");
152         return;
153     }
154 
155     disp->bg_color = color;
156 
157     lv_area_t a;
158     lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
159     _lv_inv_area(disp, &a);
160 
161 }
162 
163 /**
164  * Set the background image of a display
165  * @param disp pointer to a display
166  * @param img_src path to file or pointer to an `lv_img_dsc_t` variable
167  */
lv_disp_set_bg_image(lv_disp_t * disp,const void * img_src)168 void lv_disp_set_bg_image(lv_disp_t * disp, const void  * img_src)
169 {
170     if(!disp) disp = lv_disp_get_default();
171     if(!disp) {
172         LV_LOG_WARN("no display registered");
173         return;
174     }
175 
176     disp->bg_img = img_src;
177 
178     lv_area_t a;
179     lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
180     _lv_inv_area(disp, &a);
181 }
182 
183 
184 /**
185  * Opacity of the background
186  * @param disp pointer to a display
187  * @param opa opacity (0..255)
188  */
lv_disp_set_bg_opa(lv_disp_t * disp,lv_opa_t opa)189 void lv_disp_set_bg_opa(lv_disp_t * disp, lv_opa_t opa)
190 {
191     if(!disp) disp = lv_disp_get_default();
192     if(!disp) {
193         LV_LOG_WARN("no display registered");
194         return;
195     }
196 
197     disp->bg_opa = opa;
198 
199     lv_area_t a;
200     lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
201     _lv_inv_area(disp, &a);
202 }
203 
204 #if LV_USE_ANIMATION
205 
206 /**
207  * Switch screen with animation
208  * @param scr pointer to the new screen to load
209  * @param anim_type type of the animation from `lv_scr_load_anim_t`. E.g.  `LV_SCR_LOAD_ANIM_MOVE_LEFT`
210  * @param time time of the animation
211  * @param delay delay before the transition
212  * @param auto_del true: automatically delete the old screen
213  */
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)214 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)
215 {
216     lv_disp_t * d = lv_obj_get_disp(new_scr);
217 
218     if(d->prev_scr && d->del_prev) {
219         lv_obj_del(d->prev_scr);
220         d->prev_scr = NULL;
221     }
222 
223     d->del_prev = auto_del;
224 
225     /*Be sure there is no other animation on the screens*/
226     lv_anim_del(new_scr, NULL);
227     lv_anim_del(lv_scr_act(), NULL);
228 
229     /*Be sure both screens are in a normal position*/
230     lv_obj_set_pos(new_scr, 0, 0);
231     lv_obj_set_pos(lv_scr_act(), 0, 0);
232     lv_style_remove_prop(lv_obj_get_local_style(new_scr, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
233     lv_style_remove_prop(lv_obj_get_local_style(lv_scr_act(), LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
234 
235     lv_anim_t a_new;
236     lv_anim_init(&a_new);
237     lv_anim_set_var(&a_new, new_scr);
238     lv_anim_set_start_cb(&a_new, scr_load_anim_start);
239     lv_anim_set_ready_cb(&a_new, scr_anim_ready);
240     lv_anim_set_time(&a_new, time);
241     lv_anim_set_delay(&a_new, delay);
242 
243     lv_anim_t a_old;
244     lv_anim_init(&a_old);
245     lv_anim_set_var(&a_old, d->act_scr);
246     lv_anim_set_time(&a_old, time);
247     lv_anim_set_delay(&a_old, delay);
248 
249     switch(anim_type) {
250         case LV_SCR_LOAD_ANIM_NONE:
251             /* Create a dummy animation to apply the delay*/
252             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
253             lv_anim_set_values(&a_new, 0, 0);
254             break;
255         case LV_SCR_LOAD_ANIM_OVER_LEFT:
256             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
257             lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0);
258             break;
259         case LV_SCR_LOAD_ANIM_OVER_RIGHT:
260             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
261             lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0);
262             break;
263         case LV_SCR_LOAD_ANIM_OVER_TOP:
264             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y);
265             lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0);
266             break;
267         case LV_SCR_LOAD_ANIM_OVER_BOTTOM:
268             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y);
269             lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0);
270             break;
271         case LV_SCR_LOAD_ANIM_MOVE_LEFT:
272             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
273             lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0);
274 
275             lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_x);
276             lv_anim_set_values(&a_old, 0, -lv_disp_get_hor_res(d));
277             break;
278         case LV_SCR_LOAD_ANIM_MOVE_RIGHT:
279             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
280             lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0);
281 
282             lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_x);
283             lv_anim_set_values(&a_old, 0, lv_disp_get_hor_res(d));
284             break;
285         case LV_SCR_LOAD_ANIM_MOVE_TOP:
286             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y);
287             lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0);
288 
289             lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_y);
290             lv_anim_set_values(&a_old, 0, -lv_disp_get_ver_res(d));
291             break;
292         case LV_SCR_LOAD_ANIM_MOVE_BOTTOM:
293             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y);
294             lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0);
295 
296             lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_y);
297             lv_anim_set_values(&a_old, 0, lv_disp_get_ver_res(d));
298             break;
299 
300         case LV_SCR_LOAD_ANIM_FADE_ON:
301             lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) opa_scale_anim);
302             lv_anim_set_values(&a_new, LV_OPA_TRANSP, LV_OPA_COVER);
303             break;
304     }
305 
306     lv_anim_start(&a_new);
307     lv_anim_start(&a_old);
308 }
309 
310 #endif
311 
312 /**
313  * Get elapsed time since last user activity on a display (e.g. click)
314  * @param disp pointer to an display (NULL to get the overall smallest inactivity)
315  * @return elapsed ticks (milliseconds) since the last activity
316  */
lv_disp_get_inactive_time(const lv_disp_t * disp)317 uint32_t lv_disp_get_inactive_time(const lv_disp_t * disp)
318 {
319     if(!disp) disp = lv_disp_get_default();
320     if(!disp) {
321         LV_LOG_WARN("lv_disp_get_inactive_time: no display registered");
322         return 0;
323     }
324 
325     if(disp) return lv_tick_elaps(disp->last_activity_time);
326 
327     lv_disp_t * d;
328     uint32_t t = UINT32_MAX;
329     d          = lv_disp_get_next(NULL);
330     while(d) {
331         uint32_t elaps = lv_tick_elaps(d->last_activity_time);
332         t = LV_MATH_MIN(t, elaps);
333         d = lv_disp_get_next(d);
334     }
335 
336     return t;
337 }
338 
339 /**
340  * Manually trigger an activity on a display
341  * @param disp pointer to an display (NULL to use the default display)
342  */
lv_disp_trig_activity(lv_disp_t * disp)343 void lv_disp_trig_activity(lv_disp_t * disp)
344 {
345     if(!disp) disp = lv_disp_get_default();
346     if(!disp) {
347         LV_LOG_WARN("lv_disp_trig_activity: no display registered");
348         return;
349     }
350 
351     disp->last_activity_time = lv_tick_get();
352 }
353 
354 /**
355  * Clean any CPU cache that is related to the display.
356  * @param disp pointer to an display (NULL to use the default display)
357  */
lv_disp_clean_dcache(lv_disp_t * disp)358 void lv_disp_clean_dcache(lv_disp_t * disp)
359 {
360     if(!disp) disp = lv_disp_get_default();
361     if(!disp) {
362         LV_LOG_WARN("lv_disp_clean_dcache: no display registered");
363         return;
364     }
365 
366     if(disp->driver.clean_dcache_cb)
367         disp->driver.clean_dcache_cb(&disp->driver);
368 }
369 
370 /**
371  * Get a pointer to the screen refresher task to
372  * modify its parameters with `lv_task_...` functions.
373  * @param disp pointer to a display
374  * @return pointer to the display refresher task. (NULL on error)
375  */
_lv_disp_get_refr_task(lv_disp_t * disp)376 lv_task_t * _lv_disp_get_refr_task(lv_disp_t * disp)
377 {
378     if(!disp) disp = lv_disp_get_default();
379     if(!disp) {
380         LV_LOG_WARN("lv_disp_get_refr_task: no display registered");
381         return NULL;
382     }
383 
384     return disp->refr_task;
385 }
386 
387 /**********************
388  *   STATIC FUNCTIONS
389  **********************/
390 
391 #if LV_USE_ANIMATION
scr_load_anim_start(lv_anim_t * a)392 static void scr_load_anim_start(lv_anim_t * a)
393 {
394     lv_disp_t * d = lv_obj_get_disp(a->var);
395     d->prev_scr = lv_scr_act();
396 
397     lv_disp_load_scr(a->var);
398 }
399 
opa_scale_anim(lv_obj_t * obj,lv_anim_value_t v)400 static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v)
401 {
402     lv_obj_set_style_local_opa_scale(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, v);
403 }
404 
405 
scr_anim_ready(lv_anim_t * a)406 static void scr_anim_ready(lv_anim_t * a)
407 {
408     lv_disp_t * d = lv_obj_get_disp(a->var);
409 
410     if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr);
411     d->prev_scr = NULL;
412     lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
413 }
414 #endif
415