1 /**
2  * @file lv_obj.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_obj.h"
10 #include "lv_indev.h"
11 #include "lv_refr.h"
12 #include "lv_group.h"
13 #include "lv_disp.h"
14 #include "../lv_misc/lv_debug.h"
15 #include "../lv_themes/lv_theme.h"
16 #include "../lv_draw/lv_draw.h"
17 #include "../lv_misc/lv_anim.h"
18 #include "../lv_misc/lv_task.h"
19 #include "../lv_misc/lv_async.h"
20 #include "../lv_misc/lv_fs.h"
21 #include "../lv_misc/lv_gc.h"
22 #include "../lv_misc/lv_math.h"
23 #include "../lv_misc/lv_gc.h"
24 #include "../lv_misc/lv_math.h"
25 #include "../lv_misc/lv_log.h"
26 #include "../lv_hal/lv_hal.h"
27 #include <stdint.h>
28 #include <string.h>
29 
30 #if defined(LV_GC_INCLUDE)
31     #include LV_GC_INCLUDE
32 #endif /* LV_ENABLE_GC */
33 
34 
35 #if defined(LV_USER_DATA_FREE_INCLUDE)
36     #include LV_USER_DATA_FREE_INCLUDE
37 #endif /* LV_USE_USER_DATA_FREE */
38 
39 #include LV_THEME_DEFAULT_INCLUDE
40 
41 #if LV_USE_GPU_STM32_DMA2D
42     #include "../lv_gpu/lv_gpu_stm32_dma2d.h"
43 #endif
44 
45 /*********************
46  *      DEFINES
47  *********************/
48 #define LV_OBJX_NAME "lv_obj"
49 #define LV_OBJ_DEF_WIDTH    (LV_DPX(100))
50 #define LV_OBJ_DEF_HEIGHT   (LV_DPX(50))
51 
52 /**********************
53  *      TYPEDEFS
54  **********************/
55 typedef struct _lv_event_temp_data {
56     lv_obj_t * obj;
57     bool deleted;
58     struct _lv_event_temp_data * prev;
59 } lv_event_temp_data_t;
60 
61 typedef struct {
62     lv_obj_t * obj;
63     lv_style_property_t prop;
64     uint8_t part;
65     union {
66         lv_color_t _color;
67         lv_style_int_t _int;
68         lv_opa_t _opa;
69         const void * _ptr;
70     } start_value;
71     union {
72         lv_color_t _color;
73         lv_style_int_t _int;
74         lv_opa_t _opa;
75         const void * _ptr;
76     } end_value;
77 } lv_style_trans_t;
78 
79 typedef struct {
80     lv_draw_rect_dsc_t rect;
81     lv_draw_label_dsc_t label;
82     lv_draw_line_dsc_t line;
83     lv_draw_img_dsc_t img;
84     lv_style_int_t pad_top;
85     lv_style_int_t pad_bottom;
86     lv_style_int_t pad_right;
87     lv_style_int_t pad_left;
88     lv_style_int_t pad_inner;
89     lv_style_int_t margin_top;
90     lv_style_int_t margin_bottom;
91     lv_style_int_t margin_left;
92     lv_style_int_t margin_right;
93     lv_style_int_t size;
94     lv_style_int_t transform_width;
95     lv_style_int_t transform_height;
96     lv_style_int_t transform_angle;
97     lv_style_int_t transform_zoom;
98     lv_style_int_t scale_width;
99     lv_style_int_t scale_border_width;
100     lv_style_int_t scale_end_border_width;
101     lv_style_int_t scale_end_line_width;
102     lv_color_t scale_grad_color;
103     lv_color_t scale_end_color;
104     lv_opa_t opa_scale;
105     uint32_t clip_corder : 1;
106     uint32_t border_post : 1;
107 } style_snapshot_t;
108 
109 typedef enum {
110     STYLE_COMPARE_SAME,
111     STYLE_COMPARE_VISUAL_DIFF,
112     STYLE_COMPARE_DIFF,
113 } style_snapshot_res_t;
114 
115 /**********************
116  *  STATIC PROTOTYPES
117  **********************/
118 static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area, lv_design_mode_t mode);
119 static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param);
120 static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff);
121 static void report_style_mod_core(void * style_p, lv_obj_t * obj);
122 static void refresh_children_style(lv_obj_t * obj);
123 static void base_dir_refr_children(lv_obj_t * obj);
124 static void obj_align_core(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, bool x_set, bool y_set,
125                            lv_coord_t x_ofs, lv_coord_t y_ofs);
126 static void obj_align_mid_core(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align,  bool x_set, bool y_set,
127                                lv_coord_t x_ofs, lv_coord_t y_ofs);
128 #if LV_USE_ANIMATION
129 static lv_style_trans_t * trans_create(lv_obj_t * obj, lv_style_property_t prop, uint8_t part, lv_state_t prev_state,
130                                        lv_state_t new_state);
131 static void trans_del(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_style_trans_t * tr_limit);
132 static void trans_anim_cb(lv_style_trans_t * tr, lv_anim_value_t v);
133 static void trans_anim_start_cb(lv_anim_t * a);
134 static void trans_anim_ready_cb(lv_anim_t * a);
135 static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v);
136 static void fade_in_anim_ready(lv_anim_t * a);
137 #endif
138 static void lv_event_mark_deleted(lv_obj_t * obj);
139 static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find);
140 static void lv_obj_del_async_cb(void * obj);
141 static void obj_del_core(lv_obj_t * obj);
142 static void update_style_cache(lv_obj_t * obj, uint8_t part, uint16_t prop);
143 static void update_style_cache_children(lv_obj_t * obj);
144 static void invalidate_style_cache(lv_obj_t * obj, uint8_t part, lv_style_property_t prop);
145 static void style_snapshot(lv_obj_t * obj, uint8_t part, style_snapshot_t * shot);
146 static style_snapshot_res_t style_snapshot_compare(style_snapshot_t * shot1, style_snapshot_t * shot2);
147 
148 /**********************
149  *  STATIC VARIABLES
150  **********************/
151 static bool lv_initialized = false;
152 static lv_event_temp_data_t * event_temp_data_head;
153 static const void * event_act_data;
154 
155 /**********************
156  *      MACROS
157  **********************/
158 
159 /**********************
160  *   GLOBAL FUNCTIONS
161  **********************/
162 
163 /**
164  * Init. the 'lv' library.
165  */
lv_init(void)166 void lv_init(void)
167 {
168     /* Do nothing if already initialized */
169     if(lv_initialized) {
170         LV_LOG_WARN("lv_init: already inited");
171         return;
172     }
173 
174     LV_LOG_TRACE("lv_init started");
175 
176     /*Initialize the lv_misc modules*/
177     _lv_mem_init();
178     _lv_task_core_init();
179 
180 #if LV_USE_FILESYSTEM
181     _lv_fs_init();
182 #endif
183 
184 #if LV_USE_ANIMATION
185     _lv_anim_core_init();
186 #endif
187 
188 #if LV_USE_GROUP
189     _lv_group_init();
190 #endif
191 
192 #if LV_USE_GPU_STM32_DMA2D
193     /*Initialize DMA2D GPU*/
194     lv_gpu_stm32_dma2d_init();
195 #endif
196 
197     _lv_ll_init(&LV_GC_ROOT(_lv_obj_style_trans_ll), sizeof(lv_style_trans_t));
198 
199     _lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t));
200     _lv_ll_init(&LV_GC_ROOT(_lv_indev_ll), sizeof(lv_indev_t));
201 
202     lv_theme_t * th = LV_THEME_DEFAULT_INIT(LV_THEME_DEFAULT_COLOR_PRIMARY, LV_THEME_DEFAULT_COLOR_SECONDARY,
203                                             LV_THEME_DEFAULT_FLAG,
204                                             LV_THEME_DEFAULT_FONT_SMALL, LV_THEME_DEFAULT_FONT_NORMAL, LV_THEME_DEFAULT_FONT_SUBTITLE, LV_THEME_DEFAULT_FONT_TITLE);
205     lv_theme_set_act(th);
206 
207     /*Initialize the screen refresh system*/
208     _lv_refr_init();
209 
210     /*Init the input device handling*/
211     _lv_indev_init();
212 
213     _lv_img_decoder_init();
214     lv_img_cache_set_size(LV_IMG_CACHE_DEF_SIZE);
215 
216     /*Test if the IDE has UTF-8 encoding*/
217     char * txt = "Á";
218 
219     uint8_t * txt_u8 = (uint8_t *) txt;
220     if(txt_u8[0] != 0xc3 || txt_u8[1] != 0x81 || txt_u8[2] != 0x00) {
221         LV_LOG_WARN("The strings has no UTF-8 encoding. Some characters won't be displayed.")
222     }
223 
224     lv_initialized = true;
225     LV_LOG_INFO("lv_init ready");
226 }
227 
228 #if LV_ENABLE_GC || !LV_MEM_CUSTOM
229 
230 /**
231  * Deinit the 'lv' library
232  * Currently only implemented when not using custom allocators, or GC is enabled.
233  */
lv_deinit(void)234 void lv_deinit(void)
235 {
236     _lv_gc_clear_roots();
237 
238     lv_disp_set_default(NULL);
239     _lv_mem_deinit();
240     lv_initialized = false;
241 
242     LV_LOG_INFO("lv_deinit done");
243 
244 #if LV_USE_LOG
245     lv_log_register_print_cb(NULL);
246 #endif
247 }
248 #endif
249 
250 /*--------------------
251  * Create and delete
252  *-------------------*/
253 
254 /**
255  * Create a basic object
256  * @param parent pointer to a parent object.
257  *                  If NULL then a screen will be created
258  * @param copy pointer to a base object, if not NULL then the new object will be copied from it
259  * @return pointer to the new object
260  */
lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy)261 lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
262 {
263     lv_obj_t * new_obj = NULL;
264 
265     /*Create a screen*/
266     if(parent == NULL) {
267         LV_LOG_TRACE("Screen create started");
268         lv_disp_t * disp = lv_disp_get_default();
269         if(!disp) {
270             LV_LOG_WARN("lv_obj_create: not display created to so far. No place to assign the new screen");
271             return NULL;
272         }
273 
274         new_obj = _lv_ll_ins_head(&disp->scr_ll);
275         LV_ASSERT_MEM(new_obj);
276         if(new_obj == NULL) return NULL;
277 
278         _lv_memset_00(new_obj, sizeof(lv_obj_t));
279 
280 #if LV_USE_BIDI
281         new_obj->base_dir     = LV_BIDI_BASE_DIR_DEF;
282 #else
283         new_obj->base_dir     = LV_BIDI_DIR_LTR;
284 #endif
285 
286         /*Set the callbacks*/
287         new_obj->signal_cb = lv_obj_signal;
288         new_obj->design_cb = lv_obj_design;
289         new_obj->event_cb = NULL;
290 
291         /*Set coordinates to full screen size*/
292         new_obj->coords.x1    = 0;
293         new_obj->coords.y1    = 0;
294         new_obj->coords.x2    = lv_disp_get_hor_res(NULL) - 1;
295         new_obj->coords.y2    = lv_disp_get_ver_res(NULL) - 1;
296     }
297     /*Create a normal object*/
298     else {
299         LV_LOG_TRACE("Object create started");
300         LV_ASSERT_OBJ(parent, LV_OBJX_NAME);
301 
302         new_obj = _lv_ll_ins_head(&parent->child_ll);
303         LV_ASSERT_MEM(new_obj);
304         if(new_obj == NULL) return NULL;
305 
306         _lv_memset_00(new_obj, sizeof(lv_obj_t));
307 
308         new_obj->parent = parent;
309 
310 #if LV_USE_BIDI
311         new_obj->base_dir     = LV_BIDI_DIR_INHERIT;
312 #else
313         new_obj->base_dir     = LV_BIDI_DIR_LTR;
314 #endif
315 
316         /*Set the callbacks (signal:cb is required in `lv_obj_get_base_dir` if `LV_USE_ASSERT_OBJ` is enabled)*/
317         new_obj->signal_cb = lv_obj_signal;
318         new_obj->design_cb = lv_obj_design;
319         new_obj->event_cb = NULL;
320 
321         new_obj->coords.y1    = parent->coords.y1;
322         new_obj->coords.y2    = parent->coords.y1 + LV_OBJ_DEF_HEIGHT;
323         if(lv_obj_get_base_dir(new_obj) == LV_BIDI_DIR_RTL) {
324             new_obj->coords.x2    = parent->coords.x2;
325             new_obj->coords.x1    = parent->coords.x2 - LV_OBJ_DEF_WIDTH;
326         }
327         else {
328             new_obj->coords.x1    = parent->coords.x1;
329             new_obj->coords.x2    = parent->coords.x1 + LV_OBJ_DEF_WIDTH;
330         }
331     }
332 
333 
334     _lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t));
335 
336 
337     new_obj->ext_draw_pad = 0;
338 
339 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
340     _lv_memset_00(&new_obj->ext_click_pad, sizeof(new_obj->ext_click_pad));
341 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
342     new_obj->ext_click_pad_hor = 0;
343     new_obj->ext_click_pad_ver = 0;
344 #endif
345 
346     /*Init realign*/
347 #if LV_USE_OBJ_REALIGN
348     new_obj->realign.align        = LV_ALIGN_CENTER;
349     new_obj->realign.xofs         = 0;
350     new_obj->realign.yofs         = 0;
351     new_obj->realign.base         = NULL;
352     new_obj->realign.auto_realign = 0;
353 #endif
354 
355     /*Init. user date*/
356 #if LV_USE_USER_DATA
357     _lv_memset_00(&new_obj->user_data, sizeof(lv_obj_user_data_t));
358 #endif
359 
360 
361 #if LV_USE_GROUP
362     new_obj->group_p = NULL;
363 #endif
364 
365     /*Set attributes*/
366     new_obj->adv_hittest  = 0;
367     new_obj->click        = 1;
368     new_obj->drag         = 0;
369     new_obj->drag_throw   = 0;
370     new_obj->drag_parent  = 0;
371     new_obj->drag_dir     = LV_DRAG_DIR_BOTH;
372     new_obj->hidden       = 0;
373     new_obj->top          = 0;
374     new_obj->protect      = LV_PROTECT_NONE;
375     new_obj->parent_event = 0;
376     new_obj->gesture_parent = parent ? 1 : 0;
377     new_obj->focus_parent  = 0;
378     new_obj->state = LV_STATE_DEFAULT;
379 
380     new_obj->ext_attr = NULL;
381 
382     lv_style_list_init(&new_obj->style_list);
383     if(copy == NULL) {
384         if(parent != NULL) lv_theme_apply(new_obj, LV_THEME_OBJ);
385         else  lv_theme_apply(new_obj, LV_THEME_SCR);
386     }
387     else {
388         lv_style_list_copy(&new_obj->style_list, &copy->style_list);
389     }
390     /*Copy the attributes if required*/
391     if(copy != NULL) {
392         lv_area_copy(&new_obj->coords, &copy->coords);
393         new_obj->ext_draw_pad = copy->ext_draw_pad;
394 
395 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
396         lv_area_copy(&new_obj->ext_click_pad, &copy->ext_click_pad);
397 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
398         new_obj->ext_click_pad_hor = copy->ext_click_pad_hor;
399         new_obj->ext_click_pad_ver = copy->ext_click_pad_ver;
400 #endif
401 
402         /*Set user data*/
403 #if LV_USE_USER_DATA
404         _lv_memcpy(&new_obj->user_data, &copy->user_data, sizeof(lv_obj_user_data_t));
405 #endif
406 
407         new_obj->base_dir = copy->base_dir;
408 
409         /*Copy realign*/
410 #if LV_USE_OBJ_REALIGN
411         new_obj->realign.align        = copy->realign.align;
412         new_obj->realign.xofs         = copy->realign.xofs;
413         new_obj->realign.yofs         = copy->realign.yofs;
414         new_obj->realign.base         = copy->realign.base;
415         new_obj->realign.auto_realign = copy->realign.auto_realign;
416 #endif
417 
418         /*Only copy the `event_cb`. `signal_cb` and `design_cb` will be copied in the derived
419          * object type (e.g. `lv_btn`)*/
420         new_obj->event_cb = copy->event_cb;
421 
422         /*Copy attributes*/
423         new_obj->adv_hittest  = copy->adv_hittest;
424         new_obj->click        = copy->click;
425         new_obj->drag         = copy->drag;
426         new_obj->drag_dir     = copy->drag_dir;
427         new_obj->drag_throw   = copy->drag_throw;
428         new_obj->drag_parent  = copy->drag_parent;
429         new_obj->hidden       = copy->hidden;
430         new_obj->top          = copy->top;
431         new_obj->parent_event = copy->parent_event;
432 
433         new_obj->protect      = copy->protect;
434         new_obj->gesture_parent = copy->gesture_parent;
435         new_obj->focus_parent = copy->focus_parent;
436 
437 #if LV_USE_GROUP
438         /*Add to the same group*/
439         if(copy->group_p != NULL) {
440             lv_group_add_obj(copy->group_p, new_obj);
441         }
442 #endif
443 
444         /*Set the same coordinates for non screen objects*/
445         if(lv_obj_get_parent(copy) != NULL && parent != NULL) {
446             lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy));
447         }
448     }
449 
450     /*Send a signal to the parent to notify it about the new child*/
451     if(parent != NULL) {
452         parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, new_obj);
453 
454         /*Invalidate the area if not screen created*/
455         lv_obj_invalidate(new_obj);
456     }
457 
458     LV_LOG_INFO("Object create ready");
459 
460     return new_obj;
461 }
462 
463 /**
464  * Delete 'obj' and all of its children
465  * @param obj pointer to an object to delete
466  * @return LV_RES_INV because the object is deleted
467  */
lv_obj_del(lv_obj_t * obj)468 lv_res_t lv_obj_del(lv_obj_t * obj)
469 {
470     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
471     lv_obj_invalidate(obj);
472 
473     lv_disp_t * disp = NULL;
474     bool act_scr_del = false;
475     lv_obj_t * par = lv_obj_get_parent(obj);
476     if(par == NULL) {
477         disp = lv_obj_get_disp(obj);
478         if(!disp) return LV_RES_INV;   /*Shouldn't happen*/
479         if(disp->act_scr == obj) act_scr_del = true;
480     }
481 
482 
483     obj_del_core(obj);
484 
485     /*Send a signal to the parent to notify it about the child delete*/
486     if(par) {
487         par->signal_cb(par, LV_SIGNAL_CHILD_CHG, NULL);
488     }
489 
490     /*Handle if the active screen was deleted*/
491     if(act_scr_del)  {
492         disp->act_scr = NULL;
493     }
494 
495     return LV_RES_INV;
496 }
497 
498 #if LV_USE_ANIMATION
499 /**
500  * A function to be easily used in animation ready callback to delete an object when the animation is ready
501  * @param a pointer to the animation
502  */
lv_obj_del_anim_ready_cb(lv_anim_t * a)503 void lv_obj_del_anim_ready_cb(lv_anim_t * a)
504 {
505     lv_obj_del(a->var);
506 }
507 #endif
508 
509 /**
510  * Helper function for asynchronously deleting objects.
511  * Useful for cases where you can't delete an object directly in an `LV_EVENT_DELETE` handler (i.e. parent).
512  * @param obj object to delete
513  * @see lv_async_call
514  */
lv_obj_del_async(lv_obj_t * obj)515 void lv_obj_del_async(lv_obj_t * obj)
516 {
517     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
518     lv_async_call(lv_obj_del_async_cb, obj);
519 }
520 
521 /**
522  * Delete all children of an object
523  * @param obj pointer to an object
524  */
lv_obj_clean(lv_obj_t * obj)525 void lv_obj_clean(lv_obj_t * obj)
526 {
527     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
528     lv_obj_t * child = lv_obj_get_child(obj, NULL);
529     while(child) {
530         lv_obj_del(child);
531         child = lv_obj_get_child(obj, NULL);    /*Get the new first child*/
532     }
533 }
534 
535 /**
536  * Mark an area of an object as invalid.
537  * This area will be redrawn by 'lv_refr_task'
538  * @param obj pointer to an object
539  * @param area the area to redraw
540  */
lv_obj_invalidate_area(const lv_obj_t * obj,const lv_area_t * area)541 void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area)
542 {
543     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
544 
545     lv_area_t area_tmp;
546     lv_area_copy(&area_tmp, area);
547     bool visible = lv_obj_area_is_visible(obj, &area_tmp);
548 
549     if(visible) _lv_inv_area(lv_obj_get_disp(obj), &area_tmp);
550 }
551 
552 /**
553  * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task'
554  * @param obj pointer to an object
555  */
lv_obj_invalidate(const lv_obj_t * obj)556 void lv_obj_invalidate(const lv_obj_t * obj)
557 {
558     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
559 
560     /*Truncate the area to the object*/
561     lv_area_t obj_coords;
562     lv_coord_t ext_size = obj->ext_draw_pad;
563     lv_area_copy(&obj_coords, &obj->coords);
564     obj_coords.x1 -= ext_size;
565     obj_coords.y1 -= ext_size;
566     obj_coords.x2 += ext_size;
567     obj_coords.y2 += ext_size;
568 
569     lv_obj_invalidate_area(obj, &obj_coords);
570 
571 }
572 
573 /**
574  * Tell whether an area of an object is visible (even partially) now or not
575  * @param obj pointer to an object
576  * @param area the are to check. The visible part of the area will be written back here.
577  * @return true: visible; false: not visible (hidden, out of parent, on other screen, etc)
578  */
lv_obj_area_is_visible(const lv_obj_t * obj,lv_area_t * area)579 bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area)
580 {
581     if(lv_obj_get_hidden(obj)) return false;
582 
583     /*Invalidate the object only if it belongs to the curent or previous'*/
584     lv_obj_t * obj_scr = lv_obj_get_screen(obj);
585     lv_disp_t * disp   = lv_obj_get_disp(obj_scr);
586     if(obj_scr == lv_disp_get_scr_act(disp) ||
587        obj_scr == lv_disp_get_scr_prev(disp) ||
588        obj_scr == lv_disp_get_layer_top(disp) ||
589        obj_scr == lv_disp_get_layer_sys(disp)) {
590 
591         /*Truncate the area to the object*/
592         lv_area_t obj_coords;
593         lv_coord_t ext_size = obj->ext_draw_pad;
594         lv_area_copy(&obj_coords, &obj->coords);
595         obj_coords.x1 -= ext_size;
596         obj_coords.y1 -= ext_size;
597         obj_coords.x2 += ext_size;
598         obj_coords.y2 += ext_size;
599 
600         bool is_common;
601 
602         is_common = _lv_area_intersect(area, area, &obj_coords);
603         if(is_common == false) return false;  /*The area is not on the object*/
604 
605         /*Truncate recursively to the parents*/
606         lv_obj_t * par = lv_obj_get_parent(obj);
607         while(par != NULL) {
608             is_common = _lv_area_intersect(area, area, &par->coords);
609             if(is_common == false) return false;       /*If no common parts with parent break;*/
610             if(lv_obj_get_hidden(par)) return false; /*If the parent is hidden then the child is hidden and won't be drawn*/
611 
612             par = lv_obj_get_parent(par);
613         }
614     }
615 
616     return true;
617 }
618 
619 /**
620  * Tell whether an object is visible (even partially) now or not
621  * @param obj pointer to an object
622  * @return true: visible; false: not visible (hidden, out of parent, on other screen, etc)
623  */
lv_obj_is_visible(const lv_obj_t * obj)624 bool lv_obj_is_visible(const lv_obj_t * obj)
625 {
626     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
627 
628     lv_area_t obj_coords;
629     lv_coord_t ext_size = obj->ext_draw_pad;
630     lv_area_copy(&obj_coords, &obj->coords);
631     obj_coords.x1 -= ext_size;
632     obj_coords.y1 -= ext_size;
633     obj_coords.x2 += ext_size;
634     obj_coords.y2 += ext_size;
635 
636     return lv_obj_area_is_visible(obj, &obj_coords);
637 
638 }
639 
640 /*=====================
641  * Setter functions
642  *====================*/
643 
644 /*--------------------
645  * Parent/children set
646  *--------------------*/
647 
648 /**
649  * Set a new parent for an object. Its relative position will be the same.
650  * @param obj pointer to an object. Can't be a screen.
651  * @param parent pointer to the new parent object. (Can't be NULL)
652  */
lv_obj_set_parent(lv_obj_t * obj,lv_obj_t * parent)653 void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent)
654 {
655     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
656     LV_ASSERT_OBJ(parent, LV_OBJX_NAME);
657 
658     if(obj->parent == NULL) {
659         LV_LOG_WARN("Can't set the parent of a screen");
660         return;
661     }
662 
663     if(parent == NULL) {
664         LV_LOG_WARN("Can't set parent == NULL to an object");
665         return;
666     }
667 
668     lv_obj_invalidate(obj);
669 
670     lv_obj_t * old_par = obj->parent;
671     lv_point_t old_pos;
672     old_pos.y = lv_obj_get_y(obj);
673 
674     lv_bidi_dir_t new_base_dir = lv_obj_get_base_dir(parent);
675 
676     if(new_base_dir != LV_BIDI_DIR_RTL) {
677         old_pos.x = lv_obj_get_x(obj);
678     }
679     else {
680         old_pos.x = old_par->coords.x2 - obj->coords.x2;
681     }
682 
683     _lv_ll_chg_list(&obj->parent->child_ll, &parent->child_ll, obj, true);
684     obj->parent = parent;
685 
686 
687     if(new_base_dir != LV_BIDI_DIR_RTL) {
688         lv_obj_set_pos(obj, old_pos.x, old_pos.y);
689     }
690     else {
691         /*Align to the right in case of RTL base dir*/
692         lv_coord_t new_x = lv_obj_get_width(parent) - old_pos.x - lv_obj_get_width(obj);
693         lv_obj_set_pos(obj, new_x, old_pos.y);
694     }
695 
696     /*Notify the original parent because one of its children is lost*/
697     old_par->signal_cb(old_par, LV_SIGNAL_CHILD_CHG, NULL);
698 
699     /*Notify the new parent about the child*/
700     parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj);
701 
702     lv_obj_invalidate(obj);
703 }
704 
705 /**
706  * Move and object to the foreground
707  * @param obj pointer to an object
708  */
lv_obj_move_foreground(lv_obj_t * obj)709 void lv_obj_move_foreground(lv_obj_t * obj)
710 {
711     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
712 
713     lv_obj_t * parent = lv_obj_get_parent(obj);
714 
715     /*Do nothing of already in the foreground*/
716     if(_lv_ll_get_head(&parent->child_ll) == obj) return;
717 
718     lv_obj_invalidate(parent);
719 
720     _lv_ll_chg_list(&parent->child_ll, &parent->child_ll, obj, true);
721 
722     /*Notify the new parent about the child*/
723     parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj);
724 
725     lv_obj_invalidate(parent);
726 }
727 
728 /**
729  * Move and object to the background
730  * @param obj pointer to an object
731  */
lv_obj_move_background(lv_obj_t * obj)732 void lv_obj_move_background(lv_obj_t * obj)
733 {
734     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
735 
736     lv_obj_t * parent = lv_obj_get_parent(obj);
737 
738     /*Do nothing of already in the background*/
739     if(_lv_ll_get_tail(&parent->child_ll) == obj) return;
740 
741     lv_obj_invalidate(parent);
742 
743     _lv_ll_chg_list(&parent->child_ll, &parent->child_ll, obj, false);
744 
745     /*Notify the new parent about the child*/
746     parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj);
747 
748     lv_obj_invalidate(parent);
749 }
750 
751 /*--------------------
752  * Coordinate set
753  * ------------------*/
754 
755 /**
756  * Set relative the position of an object (relative to the parent)
757  * @param obj pointer to an object
758  * @param x new distance from the left side of the parent
759  * @param y new distance from the top of the parent
760  */
lv_obj_set_pos(lv_obj_t * obj,lv_coord_t x,lv_coord_t y)761 void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
762 {
763     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
764 
765     /*Convert x and y to absolute coordinates*/
766     lv_obj_t * par = obj->parent;
767 
768     if(par) {
769         x = x + par->coords.x1;
770         y = y + par->coords.y1;
771     }
772 
773 
774     /*Calculate and set the movement*/
775     lv_point_t diff;
776     diff.x = x - obj->coords.x1;
777     diff.y = y - obj->coords.y1;
778 
779     /* Do nothing if the position is not changed */
780     /* It is very important else recursive positioning can
781      * occur without position change*/
782     if(diff.x == 0 && diff.y == 0) return;
783 
784     /*Invalidate the original area*/
785     lv_obj_invalidate(obj);
786 
787     /*Save the original coordinates*/
788     lv_area_t ori;
789     lv_obj_get_coords(obj, &ori);
790 
791     obj->coords.x1 += diff.x;
792     obj->coords.y1 += diff.y;
793     obj->coords.x2 += diff.x;
794     obj->coords.y2 += diff.y;
795 
796     refresh_children_position(obj, diff.x, diff.y);
797 
798     /*Inform the object about its new coordinates*/
799     obj->signal_cb(obj, LV_SIGNAL_COORD_CHG, &ori);
800 
801     /*Send a signal to the parent too*/
802     if(par) par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj);
803 
804     /*Invalidate the new area*/
805     lv_obj_invalidate(obj);
806 }
807 
808 /**
809  * Set the x coordinate of a object
810  * @param obj pointer to an object
811  * @param x new distance from the left side from the parent
812  */
lv_obj_set_x(lv_obj_t * obj,lv_coord_t x)813 void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x)
814 {
815     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
816 
817     lv_obj_set_pos(obj, x, lv_obj_get_y(obj));
818 }
819 
820 /**
821  * Set the y coordinate of a object
822  * @param obj pointer to an object
823  * @param y new distance from the top of the parent
824  */
lv_obj_set_y(lv_obj_t * obj,lv_coord_t y)825 void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y)
826 {
827     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
828 
829     lv_obj_set_pos(obj, lv_obj_get_x(obj), y);
830 }
831 
832 /**
833  * Set the size of an object
834  * @param obj pointer to an object
835  * @param w new width
836  * @param h new height
837  */
lv_obj_set_size(lv_obj_t * obj,lv_coord_t w,lv_coord_t h)838 void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h)
839 {
840     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
841 
842     /* Do nothing if the size is not changed */
843     /* It is very important else recursive resizing can
844      * occur without size change*/
845     if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) {
846         return;
847     }
848 
849     /*Invalidate the original area*/
850     lv_obj_invalidate(obj);
851 
852     /*Save the original coordinates*/
853     lv_area_t ori;
854     lv_obj_get_coords(obj, &ori);
855 
856     /*Set the length and height*/
857     obj->coords.y2 = obj->coords.y1 + h - 1;
858     if(lv_obj_get_base_dir(obj) == LV_BIDI_DIR_RTL) {
859         obj->coords.x1 = obj->coords.x2 - w + 1;
860     }
861     else {
862         obj->coords.x2 = obj->coords.x1 + w - 1;
863     }
864 
865     /*Send a signal to the object with its new coordinates*/
866     obj->signal_cb(obj, LV_SIGNAL_COORD_CHG, &ori);
867 
868     /*Send a signal to the parent too*/
869     lv_obj_t * par = lv_obj_get_parent(obj);
870     if(par != NULL) par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj);
871 
872     /*Tell the children the parent's size has changed*/
873     lv_obj_t * i;
874     _LV_LL_READ(obj->child_ll, i) {
875         i->signal_cb(i, LV_SIGNAL_PARENT_SIZE_CHG,  &ori);
876     }
877 
878     /*Invalidate the new area*/
879     lv_obj_invalidate(obj);
880 
881     /*Automatically realign the object if required*/
882 #if LV_USE_OBJ_REALIGN
883     if(obj->realign.auto_realign) lv_obj_realign(obj);
884 #endif
885 }
886 
887 /**
888  * Set the width of an object
889  * @param obj pointer to an object
890  * @param w new width
891  */
lv_obj_set_width(lv_obj_t * obj,lv_coord_t w)892 void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w)
893 {
894     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
895 
896     lv_obj_set_size(obj, w, lv_obj_get_height(obj));
897 }
898 
899 /**
900  * Set the height of an object
901  * @param obj pointer to an object
902  * @param h new height
903  */
lv_obj_set_height(lv_obj_t * obj,lv_coord_t h)904 void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h)
905 {
906     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
907 
908     lv_obj_set_size(obj, lv_obj_get_width(obj), h);
909 }
910 
911 /**
912  * Set the width reduced by the left and right padding.
913  * @param obj pointer to an object
914  * @param w the width without paddings
915  */
lv_obj_set_width_fit(lv_obj_t * obj,lv_coord_t w)916 void lv_obj_set_width_fit(lv_obj_t * obj, lv_coord_t w)
917 {
918     lv_style_int_t pleft = lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN);
919     lv_style_int_t pright = lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN);
920 
921     lv_obj_set_width(obj, w - pleft - pright);
922 }
923 
924 /**
925  * Set the height reduced by the top and bottom padding.
926  * @param obj pointer to an object
927  * @param h the height without paddings
928  */
lv_obj_set_height_fit(lv_obj_t * obj,lv_coord_t h)929 void lv_obj_set_height_fit(lv_obj_t * obj, lv_coord_t h)
930 {
931     lv_style_int_t ptop = lv_obj_get_style_pad_top(obj, LV_OBJ_PART_MAIN);
932     lv_style_int_t pbottom = lv_obj_get_style_pad_bottom(obj, LV_OBJ_PART_MAIN);
933 
934     lv_obj_set_height(obj, h - ptop - pbottom);
935 }
936 
937 /**
938  * Set the width of an object by taking the left and right margin into account.
939  * The object width will be `obj_w = w - margin_left - margin_right`
940  * @param obj pointer to an object
941  * @param w new height including margins
942  */
lv_obj_set_width_margin(lv_obj_t * obj,lv_coord_t w)943 void lv_obj_set_width_margin(lv_obj_t * obj, lv_coord_t w)
944 {
945     lv_style_int_t mleft = lv_obj_get_style_margin_left(obj, LV_OBJ_PART_MAIN);
946     lv_style_int_t mright = lv_obj_get_style_margin_right(obj, LV_OBJ_PART_MAIN);
947 
948     lv_obj_set_width(obj, w - mleft - mright);
949 }
950 
951 /**
952  * Set the height of an object by taking the top and bottom margin into account.
953  * The object height will be `obj_h = h - margin_top - margin_bottom`
954  * @param obj pointer to an object
955  * @param h new height including margins
956  */
lv_obj_set_height_margin(lv_obj_t * obj,lv_coord_t h)957 void lv_obj_set_height_margin(lv_obj_t * obj, lv_coord_t h)
958 {
959     lv_style_int_t mtop = lv_obj_get_style_margin_top(obj, LV_OBJ_PART_MAIN);
960     lv_style_int_t mbottom = lv_obj_get_style_margin_bottom(obj, LV_OBJ_PART_MAIN);
961 
962     lv_obj_set_height(obj, h - mtop - mbottom);
963 }
964 
965 /**
966  * Align an object to an other object.
967  * @param obj pointer to an object to align
968  * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
969  * @param align type of alignment (see 'lv_align_t' enum)
970  * @param x_ofs x coordinate offset after alignment
971  * @param y_ofs y coordinate offset after alignment
972  */
lv_obj_align(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t x_ofs,lv_coord_t y_ofs)973 void lv_obj_align(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs)
974 {
975     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
976 
977     if(base == NULL) base = lv_obj_get_parent(obj);
978 
979     LV_ASSERT_OBJ(base, LV_OBJX_NAME);
980 
981     obj_align_core(obj, base, align, true, true, x_ofs, y_ofs);
982 
983 #if LV_USE_OBJ_REALIGN
984     /*Save the last align parameters to use them in `lv_obj_realign`*/
985     obj->realign.align       = align;
986     obj->realign.xofs        = x_ofs;
987     obj->realign.yofs        = y_ofs;
988     obj->realign.base        = base;
989     obj->realign.mid_align = 0;
990 #endif
991 }
992 
993 /**
994  * Align an object to an other object horizontally.
995  * @param obj pointer to an object to align
996  * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
997  * @param align type of alignment (see 'lv_align_t' enum)
998  * @param x_ofs x coordinate offset after alignment
999  */
lv_obj_align_x(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t x_ofs)1000 void lv_obj_align_x(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs)
1001 {
1002     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1003 
1004     if(base == NULL) base = lv_obj_get_parent(obj);
1005 
1006     LV_ASSERT_OBJ(base, LV_OBJX_NAME);
1007 
1008     obj_align_core(obj, base, align, true, false, x_ofs, 0);
1009 }
1010 
1011 /**
1012  * Align an object to an other object vertically.
1013  * @param obj pointer to an object to align
1014  * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
1015  * @param align type of alignment (see 'lv_align_t' enum)
1016  * @param y_ofs y coordinate offset after alignment
1017  */
lv_obj_align_y(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t y_ofs)1018 void lv_obj_align_y(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t y_ofs)
1019 {
1020     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1021 
1022     if(base == NULL) base = lv_obj_get_parent(obj);
1023 
1024     LV_ASSERT_OBJ(base, LV_OBJX_NAME);
1025 
1026     obj_align_core(obj, base, align, false, true, 0, y_ofs);
1027 }
1028 
1029 /**
1030  * Align an object's middle point to an other object.
1031  * @param obj pointer to an object to align
1032  * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
1033  * @param align type of alignment (see 'lv_align_t' enum)
1034  * @param x_ofs x coordinate offset after alignment
1035  * @param y_ofs y coordinate offset after alignment
1036  */
lv_obj_align_mid(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t x_ofs,lv_coord_t y_ofs)1037 void lv_obj_align_mid(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs)
1038 {
1039     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1040 
1041     if(base == NULL) {
1042         base = lv_obj_get_parent(obj);
1043     }
1044 
1045     LV_ASSERT_OBJ(base, LV_OBJX_NAME);
1046 
1047 
1048     obj_align_mid_core(obj, base, align, true, true, x_ofs, y_ofs);
1049 
1050 #if LV_USE_OBJ_REALIGN
1051     /*Save the last align parameters to use them in `lv_obj_realign`*/
1052     obj->realign.align       = align;
1053     obj->realign.xofs        = x_ofs;
1054     obj->realign.yofs        = y_ofs;
1055     obj->realign.base        = base;
1056     obj->realign.mid_align = 1;
1057 #endif
1058 }
1059 
1060 /**
1061  * Align an object's middle point to an other object horizontally.
1062  * @param obj pointer to an object to align
1063  * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
1064  * @param align type of alignment (see 'lv_align_t' enum)
1065  * @param x_ofs x coordinate offset after alignment
1066  */
lv_obj_align_mid_x(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t x_ofs)1067 void lv_obj_align_mid_x(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs)
1068 {
1069     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1070 
1071     if(base == NULL) {
1072         base = lv_obj_get_parent(obj);
1073     }
1074 
1075     LV_ASSERT_OBJ(base, LV_OBJX_NAME);
1076 
1077 
1078     obj_align_mid_core(obj, base, align, true, false, x_ofs, 0);
1079 }
1080 
1081 
1082 /**
1083  * Align an object's middle point to an other object vertically.
1084  * @param obj pointer to an object to align
1085  * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
1086  * @param align type of alignment (see 'lv_align_t' enum)
1087  * @param y_ofs y coordinate offset after alignment
1088  */
lv_obj_align_mid_y(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t y_ofs)1089 void lv_obj_align_mid_y(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t y_ofs)
1090 {
1091     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1092 
1093     if(base == NULL) {
1094         base = lv_obj_get_parent(obj);
1095     }
1096 
1097     LV_ASSERT_OBJ(base, LV_OBJX_NAME);
1098 
1099 
1100     obj_align_mid_core(obj, base, align, false, true, 0, y_ofs);
1101 }
1102 
1103 /**
1104  * Realign the object based on the last `lv_obj_align` parameters.
1105  * @param obj pointer to an object
1106  */
lv_obj_realign(lv_obj_t * obj)1107 void lv_obj_realign(lv_obj_t * obj)
1108 {
1109     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1110 
1111 #if LV_USE_OBJ_REALIGN
1112     if(obj->realign.mid_align)
1113         lv_obj_align_mid(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs);
1114     else
1115         lv_obj_align(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs);
1116 #else
1117     (void)obj;
1118     LV_LOG_WARN("lv_obj_realign: no effect because LV_USE_OBJ_REALIGN = 0");
1119 #endif
1120 }
1121 
1122 /**
1123  * Enable the automatic realign of the object when its size has changed based on the last
1124  * `lv_obj_align` parameters.
1125  * @param obj pointer to an object
1126  * @param en true: enable auto realign; false: disable auto realign
1127  */
lv_obj_set_auto_realign(lv_obj_t * obj,bool en)1128 void lv_obj_set_auto_realign(lv_obj_t * obj, bool en)
1129 {
1130     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1131 
1132 #if LV_USE_OBJ_REALIGN
1133     obj->realign.auto_realign = en ? 1 : 0;
1134 #else
1135     (void)obj;
1136     (void)en;
1137     LV_LOG_WARN("lv_obj_set_auto_realign: no effect because LV_USE_OBJ_REALIGN = 0");
1138 #endif
1139 }
1140 
1141 
1142 /**
1143  * Set the size of an extended clickable area
1144  * If TINY mode is used, only the largest of the horizontal and vertical padding
1145  * values are considered.
1146  * @param obj pointer to an object
1147  * @param left extended clickable are on the left [px]
1148  * @param right extended clickable are on the right [px]
1149  * @param top extended clickable are on the top [px]
1150  * @param bottom extended clickable are on the bottom [px]
1151  */
lv_obj_set_ext_click_area(lv_obj_t * obj,lv_coord_t left,lv_coord_t right,lv_coord_t top,lv_coord_t bottom)1152 void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t left, lv_coord_t right, lv_coord_t top, lv_coord_t bottom)
1153 {
1154     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1155 
1156 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
1157     obj->ext_click_pad.x1 = left;
1158     obj->ext_click_pad.x2 = right;
1159     obj->ext_click_pad.y1 = top;
1160     obj->ext_click_pad.y2 = bottom;
1161 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
1162     obj->ext_click_pad_hor = LV_MATH_MAX(left, right);
1163     obj->ext_click_pad_ver = LV_MATH_MAX(top, bottom);
1164 #else
1165     (void)obj;    /*Unused*/
1166     (void)left;   /*Unused*/
1167     (void)right;  /*Unused*/
1168     (void)top;    /*Unused*/
1169     (void)bottom; /*Unused*/
1170 #endif
1171 }
1172 
1173 /*---------------------
1174  * Appearance set
1175  *--------------------*/
1176 
1177 /**
1178  * Add a new style to the style list of an object.
1179  * @param obj pointer to an object
1180  * @param part the part of the object which style property should be set.
1181  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1182  * @param style pointer to a style to add (Only its pointer will be saved)
1183  */
lv_obj_add_style(lv_obj_t * obj,uint8_t part,lv_style_t * style)1184 void lv_obj_add_style(lv_obj_t * obj, uint8_t part, lv_style_t * style)
1185 {
1186     if(style == NULL) return;
1187 
1188     lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part);
1189     if(style_dsc == NULL) {
1190         LV_LOG_WARN("Can't find style with part: %d", part);
1191         return;
1192     }
1193 
1194     _lv_style_list_add_style(style_dsc, style);
1195 #if LV_USE_ANIMATION
1196     trans_del(obj, part, 0xFF, NULL);
1197 #endif
1198     lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL);
1199 }
1200 
1201 /**
1202  * Remove a style from the style list of an object.
1203  * @param obj pointer to an object
1204  * @param part the part of the object which style property should be set.
1205  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1206  * @param style pointer to a style to remove
1207  */
lv_obj_remove_style(lv_obj_t * obj,uint8_t part,lv_style_t * style)1208 void lv_obj_remove_style(lv_obj_t * obj, uint8_t part, lv_style_t * style)
1209 {
1210     if(style == NULL) return;
1211 
1212     lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part);
1213     if(style_dsc == NULL) {
1214         LV_LOG_WARN("Can't find style with part: %d", part);
1215         return;
1216     }
1217 
1218     _lv_style_list_remove_style(style_dsc, style);
1219 #if LV_USE_ANIMATION
1220     trans_del(obj, part, 0xFF, NULL);
1221 #endif
1222     lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL);
1223 }
1224 
1225 /**
1226  * Reset a style to the default (empty) state.
1227  * Release all used memories and cancel pending related transitions.
1228  * Typically used in `LV_SIGN_CLEAN_UP.
1229  * @param obj pointer to an object
1230  * @param part the part of the object which style list should be reseted.
1231  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1232  */
lv_obj_clean_style_list(lv_obj_t * obj,uint8_t part)1233 void lv_obj_clean_style_list(lv_obj_t * obj, uint8_t part)
1234 {
1235     lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part);
1236     if(style_dsc == NULL) {
1237         LV_LOG_WARN("lv_obj_clean_style_list: can't find style with `part`");
1238         return;
1239     }
1240 
1241     _lv_style_list_reset(style_dsc);
1242 #if LV_USE_ANIMATION
1243     trans_del(obj, part, 0xFF, NULL);
1244 #endif
1245 }
1246 
1247 /**
1248  * Reset a style to the default (empty) state.
1249  * Release all used memories and cancel pending related transitions.
1250  * Also notifies the object about the style change.
1251  * @param obj pointer to an object
1252  * @param part the part of the object which style list should be reseted.
1253  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1254  */
lv_obj_reset_style_list(lv_obj_t * obj,uint8_t part)1255 void lv_obj_reset_style_list(lv_obj_t * obj, uint8_t part)
1256 {
1257     lv_obj_clean_style_list(obj, part);
1258 
1259     lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL);
1260 }
1261 
1262 /**
1263  * Set a local style property of a part of an object in a given state.
1264  * @param obj pointer to an object
1265  * @param part the part of the object which style property should be set.
1266  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1267  * @param prop a style property ORed with a state.
1268  * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
1269  * @param the value to set
1270  * @note shouldn't be used directly. Use the specific property get functions instead.
1271  *       For example: `lv_obj_style_get_border_opa()`
1272  * @note for performance reasons it's not checked if the property really has integer type
1273  */
_lv_obj_set_style_local_int(lv_obj_t * obj,uint8_t part,lv_style_property_t prop,lv_style_int_t value)1274 void _lv_obj_set_style_local_int(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_style_int_t value)
1275 {
1276     lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part);
1277     _lv_style_list_set_local_int(style_dsc, prop, value);
1278 #if LV_USE_ANIMATION
1279     trans_del(obj, part, prop, NULL);
1280 #endif
1281     lv_obj_refresh_style(obj, part, prop & (~LV_STYLE_STATE_MASK));
1282 }
1283 
1284 /**
1285  * Set a local style property of a part of an object in a given state.
1286  * @param obj pointer to an object
1287  * @param part the part of the object which style property should be set.
1288  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1289  * @param prop a style property ORed with a state.
1290  * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
1291  * @param the value to set
1292  * @note shouldn't be used directly. Use the specific property get functions instead.
1293  *       For example: `lv_obj_style_get_border_opa()`
1294  * @note for performance reasons it's not checked if the property really has color type
1295  */
_lv_obj_set_style_local_color(lv_obj_t * obj,uint8_t part,lv_style_property_t prop,lv_color_t color)1296 void _lv_obj_set_style_local_color(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_color_t color)
1297 {
1298     lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part);
1299     _lv_style_list_set_local_color(style_dsc, prop, color);
1300 #if LV_USE_ANIMATION
1301     trans_del(obj, part, prop, NULL);
1302 #endif
1303     lv_obj_refresh_style(obj, part, prop & (~LV_STYLE_STATE_MASK));
1304 }
1305 
1306 /**
1307  * Set a local style property of a part of an object in a given state.
1308  * @param obj pointer to an object
1309  * @param part the part of the object which style property should be set.
1310  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1311  * @param prop a style property ORed with a state.
1312  * E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
1313  * @param the value to set
1314  * @note shouldn't be used directly. Use the specific property get functions instead.
1315  *       For example: `lv_obj_style_get_border_opa()`
1316  * @note for performance reasons it's not checked if the property really has opacity type
1317  */
_lv_obj_set_style_local_opa(lv_obj_t * obj,uint8_t part,lv_style_property_t prop,lv_opa_t opa)1318 void _lv_obj_set_style_local_opa(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_opa_t opa)
1319 {
1320     lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part);
1321     _lv_style_list_set_local_opa(style_dsc, prop, opa);
1322 #if LV_USE_ANIMATION
1323     trans_del(obj, part, prop, NULL);
1324 #endif
1325     lv_obj_refresh_style(obj, part, prop & (~LV_STYLE_STATE_MASK));
1326 }
1327 
1328 /**
1329  * Set a local style property of a part of an object in a given state.
1330  * @param obj pointer to an object
1331  * @param part the part of the object which style property should be set.
1332  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1333  * @param prop a style property ORed with a state.
1334  * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
1335  * @param value the value to set
1336  * @note shouldn't be used directly. Use the specific property get functions instead.
1337  *       For example: `lv_obj_style_get_border_opa()`
1338  * @note for performance reasons it's not checked if the property really has pointer type
1339  */
_lv_obj_set_style_local_ptr(lv_obj_t * obj,uint8_t part,lv_style_property_t prop,const void * value)1340 void _lv_obj_set_style_local_ptr(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, const void * value)
1341 {
1342     lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part);
1343     _lv_style_list_set_local_ptr(style_dsc, prop, value);
1344 #if LV_USE_ANIMATION
1345     trans_del(obj, part, prop, NULL);
1346 #endif
1347     lv_obj_refresh_style(obj, part, prop & (~LV_STYLE_STATE_MASK));
1348 }
1349 
1350 /**
1351  * Remove a local style property from a part of an object with a given state.
1352  * @param obj pointer to an object
1353  * @param part the part of the object which style property should be removed.
1354  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
1355  * @param prop a style property ORed with a state.
1356  * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
1357  * @note shouldn't be used directly. Use the specific property remove functions instead.
1358  *       For example: `lv_obj_style_remove_border_opa()`
1359  * @return true: the property was found and removed; false: the property was not found
1360  */
lv_obj_remove_style_local_prop(lv_obj_t * obj,uint8_t part,lv_style_property_t prop)1361 bool lv_obj_remove_style_local_prop(lv_obj_t * obj, uint8_t part, lv_style_property_t prop)
1362 {
1363     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1364     lv_style_t * style = lv_obj_get_local_style(obj, part);
1365     if(style) return lv_style_remove_prop(style, prop);
1366     else return false;
1367 }
1368 
1369 /**
1370  * Notify an object (and its children) about its style is modified
1371  * @param obj pointer to an object
1372  * @param part the part of the object which style property should be refreshed.
1373  * @param prop `LV_STYLE_PROP_ALL` or an `LV_STYLE_...` property. It is used to optimize what needs to be refreshed.
1374  */
lv_obj_refresh_style(lv_obj_t * obj,uint8_t part,lv_style_property_t prop)1375 void lv_obj_refresh_style(lv_obj_t * obj, uint8_t part, lv_style_property_t prop)
1376 {
1377     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1378 
1379     invalidate_style_cache(obj, part, prop);
1380 
1381     /*If a real style refresh is required*/
1382     bool real_refr = false;
1383     switch(prop) {
1384         case LV_STYLE_PROP_ALL:
1385         case LV_STYLE_CLIP_CORNER:
1386         case LV_STYLE_SIZE:
1387         case LV_STYLE_TRANSFORM_WIDTH:
1388         case LV_STYLE_TRANSFORM_HEIGHT:
1389         case LV_STYLE_TRANSFORM_ANGLE:
1390         case LV_STYLE_TRANSFORM_ZOOM:
1391         case LV_STYLE_PAD_TOP:
1392         case LV_STYLE_PAD_BOTTOM:
1393         case LV_STYLE_PAD_LEFT:
1394         case LV_STYLE_PAD_RIGHT:
1395         case LV_STYLE_PAD_INNER:
1396         case LV_STYLE_MARGIN_TOP:
1397         case LV_STYLE_MARGIN_BOTTOM:
1398         case LV_STYLE_MARGIN_LEFT:
1399         case LV_STYLE_MARGIN_RIGHT:
1400         case LV_STYLE_OUTLINE_WIDTH:
1401         case LV_STYLE_OUTLINE_PAD:
1402         case LV_STYLE_OUTLINE_OPA:
1403         case LV_STYLE_SHADOW_WIDTH:
1404         case LV_STYLE_SHADOW_OPA:
1405         case LV_STYLE_SHADOW_OFS_X:
1406         case LV_STYLE_SHADOW_OFS_Y:
1407         case LV_STYLE_SHADOW_SPREAD:
1408         case LV_STYLE_VALUE_LETTER_SPACE:
1409         case LV_STYLE_VALUE_LINE_SPACE:
1410         case LV_STYLE_VALUE_OFS_X:
1411         case LV_STYLE_VALUE_OFS_Y:
1412         case LV_STYLE_VALUE_ALIGN:
1413         case LV_STYLE_VALUE_STR:
1414         case LV_STYLE_VALUE_FONT:
1415         case LV_STYLE_VALUE_OPA:
1416         case LV_STYLE_TEXT_LETTER_SPACE:
1417         case LV_STYLE_TEXT_LINE_SPACE:
1418         case LV_STYLE_TEXT_FONT:
1419         case LV_STYLE_LINE_WIDTH:
1420             real_refr = true;
1421             break;
1422         default:
1423             real_refr = false;
1424     }
1425 
1426     if(real_refr) {
1427         lv_obj_invalidate(obj);
1428         obj->signal_cb(obj, LV_SIGNAL_STYLE_CHG, NULL);
1429 
1430         switch(prop) {
1431             case LV_STYLE_PROP_ALL:
1432             case LV_STYLE_MARGIN_TOP:
1433             case LV_STYLE_MARGIN_BOTTOM:
1434             case LV_STYLE_MARGIN_LEFT:
1435             case LV_STYLE_MARGIN_RIGHT:
1436                 if(obj->parent) obj->parent->signal_cb(obj->parent, LV_SIGNAL_CHILD_CHG, NULL);
1437                 break;
1438         }
1439 
1440         lv_obj_invalidate(obj);
1441 
1442         /*Send style change signals*/
1443         if(prop == LV_STYLE_PROP_ALL || (prop & LV_STYLE_INHERIT_MASK)) refresh_children_style(obj);
1444     }
1445     else {
1446         lv_obj_invalidate(obj);
1447     }
1448 }
1449 
1450 /**
1451  * Notify all object if a style is modified
1452  * @param style pointer to a style. Only the objects with this style will be notified
1453  *               (NULL to notify all objects)
1454  */
lv_obj_report_style_mod(lv_style_t * style)1455 void lv_obj_report_style_mod(lv_style_t * style)
1456 {
1457     lv_disp_t * d = lv_disp_get_next(NULL);
1458 
1459     while(d) {
1460         lv_obj_t * i;
1461         _LV_LL_READ(d->scr_ll, i) {
1462             report_style_mod_core(style, i);
1463         }
1464         d = lv_disp_get_next(d);
1465     }
1466 }
1467 
1468 /**
1469  * Enable/disable the use of style cahche for an object
1470  * @param obj pointer to an object
1471  * @param dis true: disable; false: enable (re-enable)
1472  */
_lv_obj_disable_style_caching(lv_obj_t * obj,bool dis)1473 void _lv_obj_disable_style_caching(lv_obj_t * obj, bool dis)
1474 {
1475     uint8_t part;
1476     for(part = 0; part < _LV_OBJ_PART_REAL_FIRST; part++) {
1477         lv_style_list_t * list = lv_obj_get_style_list(obj, part);
1478         if(list == NULL) break;
1479         list->ignore_cache = dis;
1480     }
1481     for(part = _LV_OBJ_PART_REAL_FIRST; part < 0xFF; part++) {
1482         lv_style_list_t * list = lv_obj_get_style_list(obj, part);
1483         if(list == NULL) break;
1484         list->ignore_cache = dis;
1485     }
1486 }
1487 
1488 /*-----------------
1489  * Attribute set
1490  *----------------*/
1491 
1492 /**
1493  * Hide an object. It won't be visible and clickable.
1494  * @param obj pointer to an object
1495  * @param en true: hide the object
1496  */
lv_obj_set_hidden(lv_obj_t * obj,bool en)1497 void lv_obj_set_hidden(lv_obj_t * obj, bool en)
1498 {
1499     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1500 
1501     if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */
1502 
1503     obj->hidden = en == false ? 0 : 1;
1504 
1505     if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */
1506 
1507     lv_obj_t * par = lv_obj_get_parent(obj);
1508     if(par) par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj);
1509 }
1510 
1511 /**
1512  * Set whether advanced hit-testing is enabled on an object
1513  * @param obj pointer to an object
1514  * @param en true: advanced hit-testing is enabled
1515  */
lv_obj_set_adv_hittest(lv_obj_t * obj,bool en)1516 void lv_obj_set_adv_hittest(lv_obj_t * obj, bool en)
1517 {
1518     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1519 
1520     obj->adv_hittest = en == false ? 0 : 1;
1521 }
1522 
1523 /**
1524  * Enable or disable the clicking of an object
1525  * @param obj pointer to an object
1526  * @param en true: make the object clickable
1527  */
lv_obj_set_click(lv_obj_t * obj,bool en)1528 void lv_obj_set_click(lv_obj_t * obj, bool en)
1529 {
1530     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1531 
1532     obj->click = (en == true ? 1 : 0);
1533 }
1534 
1535 /**
1536  * Enable to bring this object to the foreground if it
1537  * or any of its children is clicked
1538  * @param obj pointer to an object
1539  * @param en true: enable the auto top feature
1540  */
lv_obj_set_top(lv_obj_t * obj,bool en)1541 void lv_obj_set_top(lv_obj_t * obj, bool en)
1542 {
1543     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1544 
1545     obj->top = (en == true ? 1 : 0);
1546 }
1547 
1548 /**
1549  * Enable the dragging of an object
1550  * @param obj pointer to an object
1551  * @param en true: make the object draggable
1552  */
lv_obj_set_drag(lv_obj_t * obj,bool en)1553 void lv_obj_set_drag(lv_obj_t * obj, bool en)
1554 {
1555     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1556 
1557     if(en == true) lv_obj_set_click(obj, true); /*Drag is useless without enabled clicking*/
1558     obj->drag = (en == true ? 1 : 0);
1559 }
1560 
1561 /**
1562  * Set the directions an object can be dragged in
1563  * @param obj pointer to an object
1564  * @param drag_dir bitwise OR of allowed directions an object can be dragged in
1565  */
lv_obj_set_drag_dir(lv_obj_t * obj,lv_drag_dir_t drag_dir)1566 void lv_obj_set_drag_dir(lv_obj_t * obj, lv_drag_dir_t drag_dir)
1567 {
1568     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1569 
1570     obj->drag_dir = drag_dir;
1571 
1572     if(obj->drag_dir != 0) lv_obj_set_drag(obj, true); /*Drag direction requires drag*/
1573 }
1574 
1575 /**
1576  * Enable the throwing of an object after is is dragged
1577  * @param obj pointer to an object
1578  * @param en true: enable the drag throw
1579  */
lv_obj_set_drag_throw(lv_obj_t * obj,bool en)1580 void lv_obj_set_drag_throw(lv_obj_t * obj, bool en)
1581 {
1582     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1583 
1584     obj->drag_throw = (en == true ? 1 : 0);
1585 }
1586 
1587 /**
1588  * Enable to use parent for drag related operations.
1589  * If trying to drag the object the parent will be moved instead
1590  * @param obj pointer to an object
1591  * @param en true: enable the 'drag parent' for the object
1592  */
lv_obj_set_drag_parent(lv_obj_t * obj,bool en)1593 void lv_obj_set_drag_parent(lv_obj_t * obj, bool en)
1594 {
1595     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1596 
1597     obj->drag_parent = (en == true ? 1 : 0);
1598 }
1599 
1600 /**
1601 * Enable to use parent for gesture related operations.
1602 * If trying to gesture the object the parent will be moved instead
1603 * @param obj pointer to an object
1604 * @param en true: enable the 'gesture parent' for the object
1605 */
lv_obj_set_gesture_parent(lv_obj_t * obj,bool en)1606 void lv_obj_set_gesture_parent(lv_obj_t * obj, bool en)
1607 {
1608     obj->gesture_parent = (en == true ? 1 : 0);
1609 }
1610 
1611 /**
1612 * Enable to use parent for focus state.
1613 * When object is focused the parent will get the state instead (visual only)
1614 * @param obj pointer to an object
1615 * @param en true: enable the 'focus parent' for the object
1616 */
lv_obj_set_focus_parent(lv_obj_t * obj,bool en)1617 void lv_obj_set_focus_parent(lv_obj_t * obj, bool en)
1618 {
1619     if(lv_obj_is_focused(obj)) {
1620         if(en) {
1621             obj->focus_parent = 1;
1622             lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED);
1623             lv_obj_set_state(lv_obj_get_focused_obj(obj), LV_STATE_FOCUSED);
1624         }
1625         else {
1626             lv_obj_clear_state(lv_obj_get_focused_obj(obj), LV_STATE_FOCUSED | LV_STATE_EDITED);
1627             lv_obj_set_state(obj, LV_STATE_FOCUSED);
1628             obj->focus_parent = 0;
1629         }
1630     }
1631     else {
1632         obj->focus_parent = (en == true ? 1 : 0);
1633     }
1634 }
1635 
1636 /**
1637  * Propagate the events to the parent too
1638  * @param obj pointer to an object
1639  * @param en true: enable the event propagation
1640  */
lv_obj_set_parent_event(lv_obj_t * obj,bool en)1641 void lv_obj_set_parent_event(lv_obj_t * obj, bool en)
1642 {
1643     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1644 
1645     obj->parent_event = (en == true ? 1 : 0);
1646 }
1647 
1648 /**
1649  * Set the base direction of the object
1650  * @param obj pointer to an object
1651  * @param dir the new base direction. `LV_BIDI_DIR_LTR/RTL/AUTO/INHERIT`
1652  */
lv_obj_set_base_dir(lv_obj_t * obj,lv_bidi_dir_t dir)1653 void lv_obj_set_base_dir(lv_obj_t * obj, lv_bidi_dir_t dir)
1654 {
1655     if(dir != LV_BIDI_DIR_LTR && dir != LV_BIDI_DIR_RTL &&
1656        dir != LV_BIDI_DIR_AUTO && dir != LV_BIDI_DIR_INHERIT) {
1657 
1658         LV_LOG_WARN("lv_obj_set_base_dir: invalid base dir");
1659         return;
1660     }
1661 
1662     obj->base_dir = dir;
1663     lv_signal_send(obj, LV_SIGNAL_BASE_DIR_CHG, NULL);
1664 
1665     /* Notify the children about the parent base dir has changed.
1666      * (The children might have `LV_BIDI_DIR_INHERIT`)*/
1667     base_dir_refr_children(obj);
1668 }
1669 
1670 /**
1671  * Set a bit or bits in the protect filed
1672  * @param obj pointer to an object
1673  * @param prot 'OR'-ed values from `lv_protect_t`
1674  */
lv_obj_add_protect(lv_obj_t * obj,uint8_t prot)1675 void lv_obj_add_protect(lv_obj_t * obj, uint8_t prot)
1676 {
1677     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1678 
1679     obj->protect |= prot;
1680 }
1681 
1682 /**
1683  * Clear a bit or bits in the protect filed
1684  * @param obj pointer to an object
1685  * @param prot 'OR'-ed values from `lv_protect_t`
1686  */
lv_obj_clear_protect(lv_obj_t * obj,uint8_t prot)1687 void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot)
1688 {
1689     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1690 
1691     prot = (~prot) & 0xFF;
1692     obj->protect &= prot;
1693 }
1694 
1695 /**
1696  * Set the state (fully overwrite) of an object.
1697  * If specified in the styles a transition animation will be started
1698  * from the previous state to the current
1699  * @param obj pointer to an object
1700  * @param state the new state
1701  */
lv_obj_set_state(lv_obj_t * obj,lv_state_t new_state)1702 void lv_obj_set_state(lv_obj_t * obj, lv_state_t new_state)
1703 {
1704     if(obj->state == new_state) return;
1705 
1706     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1707 
1708     lv_state_t prev_state = obj->state;
1709     style_snapshot_res_t cmp_res = STYLE_COMPARE_SAME;
1710     uint8_t part;
1711     for(part = 0; part < _LV_OBJ_PART_REAL_FIRST; part++) {
1712         lv_style_list_t * style_list = lv_obj_get_style_list(obj, part);
1713         if(style_list == NULL) break;   /*No more style lists*/
1714         obj->state = prev_state;
1715         style_snapshot_t shot_pre;
1716         style_snapshot(obj, part, &shot_pre);
1717         obj->state = new_state;
1718         style_snapshot_t shot_post;
1719         style_snapshot(obj, part, &shot_post);
1720 
1721         style_snapshot_res_t r = style_snapshot_compare(&shot_pre, &shot_post);
1722         if(r == STYLE_COMPARE_DIFF) {
1723             cmp_res = STYLE_COMPARE_DIFF;
1724             break;
1725         }
1726         if(r == STYLE_COMPARE_VISUAL_DIFF) {
1727             cmp_res = STYLE_COMPARE_VISUAL_DIFF;
1728         }
1729     }
1730 
1731     obj->state = new_state;
1732 
1733     if(cmp_res == STYLE_COMPARE_SAME) {
1734         return;
1735     }
1736 
1737 #if LV_USE_ANIMATION == 0
1738     if(cmp_res == STYLE_COMPARE_DIFF) lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL);
1739     else if(cmp_res == STYLE_COMPARE_VISUAL_DIFF) lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
1740 #else
1741 
1742 
1743     for(part = 0; part < _LV_OBJ_PART_REAL_LAST; part++) {
1744         lv_style_list_t * style_list = lv_obj_get_style_list(obj, part);
1745         if(style_list == NULL) break;   /*No more style lists*/
1746         if(style_list->ignore_trans) continue;
1747 
1748         lv_style_int_t time = lv_obj_get_style_transition_time(obj, part);
1749         lv_style_property_t props[LV_STYLE_TRANS_NUM_MAX];
1750         lv_style_int_t delay = lv_obj_get_style_transition_delay(obj, part);
1751         lv_anim_path_t * path = lv_obj_get_style_transition_path(obj, part);
1752         props[0] = lv_obj_get_style_transition_prop_1(obj, part);
1753         props[1] = lv_obj_get_style_transition_prop_2(obj, part);
1754         props[2] = lv_obj_get_style_transition_prop_3(obj, part);
1755         props[3] = lv_obj_get_style_transition_prop_4(obj, part);
1756         props[4] = lv_obj_get_style_transition_prop_5(obj, part);
1757         props[5] = lv_obj_get_style_transition_prop_6(obj, part);
1758 
1759         uint8_t i;
1760         for(i = 0; i < LV_STYLE_TRANS_NUM_MAX; i++) {
1761             if(props[i] != 0) {
1762                 _lv_style_list_add_trans_style(style_list);
1763 
1764                 lv_style_trans_t * tr = trans_create(obj, props[i], part, prev_state, new_state);
1765 
1766                 /*If there is a pending anim for this property remove it*/
1767                 if(tr) {
1768                     tr->obj = obj;
1769                     tr->prop = props[i];
1770                     tr->part = part;
1771 
1772                     lv_anim_t a;
1773                     lv_anim_init(&a);
1774                     lv_anim_set_var(&a, tr);
1775                     lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)trans_anim_cb);
1776                     lv_anim_set_start_cb(&a, trans_anim_start_cb);
1777                     lv_anim_set_ready_cb(&a, trans_anim_ready_cb);
1778                     lv_anim_set_values(&a, 0x00, 0xFF);
1779                     lv_anim_set_time(&a, time);
1780                     lv_anim_set_delay(&a, delay);
1781                     lv_anim_set_path(&a, path);
1782                     a.early_apply = 0;
1783                     lv_anim_start(&a);
1784                 }
1785 
1786             }
1787         }
1788         if(cmp_res == STYLE_COMPARE_DIFF) lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL);
1789 
1790         if(cmp_res == STYLE_COMPARE_VISUAL_DIFF) {
1791             invalidate_style_cache(obj, part, LV_STYLE_PROP_ALL);
1792         }
1793     }
1794 
1795     if(cmp_res == STYLE_COMPARE_VISUAL_DIFF) {
1796         lv_obj_invalidate(obj);
1797     }
1798 
1799 #endif
1800 
1801 }
1802 
1803 /**
1804  * Add a given state or states to the object. The other state bits will remain unchanged.
1805  * If specified in the styles a transition animation will be started
1806  * from the previous state to the current
1807  * @param obj pointer to an object
1808  * @param state the state bits to add. E.g `LV_STATE_PRESSED | LV_STATE_FOCUSED`
1809  */
lv_obj_add_state(lv_obj_t * obj,lv_state_t state)1810 void lv_obj_add_state(lv_obj_t * obj, lv_state_t state)
1811 {
1812     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1813 
1814     lv_state_t new_state = obj->state | state;
1815     if(obj->state != new_state) {
1816         lv_obj_set_state(obj, new_state);
1817     }
1818 }
1819 
1820 /**
1821  * Remove a given state or states to the object. The other state bits will remain unchanged.
1822  * If specified in the styles a transition animation will be started
1823  * from the previous state to the current
1824  * @param obj pointer to an object
1825  * @param state the state bits to remove. E.g `LV_STATE_PRESSED | LV_STATE_FOCUSED`
1826  */
lv_obj_clear_state(lv_obj_t * obj,lv_state_t state)1827 void lv_obj_clear_state(lv_obj_t * obj, lv_state_t state)
1828 {
1829     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1830 
1831     lv_state_t new_state = obj->state & (~state);
1832     if(obj->state != new_state) {
1833         lv_obj_set_state(obj, new_state);
1834     }
1835 }
1836 
1837 #if LV_USE_ANIMATION
1838 /**
1839  * Finish all pending transitions on a part of an object
1840  * @param obj pointer to an object
1841  * @param part part of the object, e.g `LV_BRN_PART_MAIN` or `LV_OBJ_PART_ALL` for all parts
1842  */
lv_obj_finish_transitions(lv_obj_t * obj,uint8_t part)1843 void lv_obj_finish_transitions(lv_obj_t * obj, uint8_t part)
1844 {
1845     /*Animate all related transition to the end value*/
1846     lv_style_trans_t * tr;
1847     _LV_LL_READ_BACK(LV_GC_ROOT(_lv_obj_style_trans_ll), tr) {
1848         if(tr->obj == obj && (part == tr->part || part == LV_OBJ_PART_ALL)) {
1849             trans_anim_cb(tr, 255);
1850         }
1851     }
1852 
1853     /*Free all related transition data*/
1854     trans_del(obj, part, 0xFF, NULL);
1855 }
1856 #endif
1857 
1858 /**
1859  * Set a an event handler function for an object.
1860  * Used by the user to react on event which happens with the object.
1861  * @param obj pointer to an object
1862  * @param event_cb the new event function
1863  */
lv_obj_set_event_cb(lv_obj_t * obj,lv_event_cb_t event_cb)1864 void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb)
1865 {
1866     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1867 
1868     obj->event_cb = event_cb;
1869 }
1870 
1871 /**
1872  * Send an event to the object
1873  * @param obj pointer to an object
1874  * @param event the type of the event from `lv_event_t`
1875  * @param data arbitrary data depending on the object type and the event. (Usually `NULL`)
1876  * @return LV_RES_OK: `obj` was not deleted in the event; LV_RES_INV: `obj` was deleted in the event
1877  */
lv_event_send(lv_obj_t * obj,lv_event_t event,const void * data)1878 lv_res_t lv_event_send(lv_obj_t * obj, lv_event_t event, const void * data)
1879 {
1880     if(obj == NULL) return LV_RES_OK;
1881 
1882     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1883 
1884     lv_res_t res;
1885     res = lv_event_send_func(obj->event_cb, obj, event, data);
1886     return res;
1887 }
1888 
1889 /**
1890  * Send LV_EVENT_REFRESH event to an object
1891  * @param obj point to an obejct. (Can NOT be NULL)
1892  * @return LV_RES_OK: success, LV_RES_INV: to object become invalid (e.g. deleted) due to this event.
1893  */
lv_event_send_refresh(lv_obj_t * obj)1894 lv_res_t lv_event_send_refresh(lv_obj_t * obj)
1895 {
1896     return lv_event_send(obj, LV_EVENT_REFRESH, NULL);
1897 }
1898 
1899 /**
1900  * Send LV_EVENT_REFRESH event to an object and all of its children.
1901  * @param obj pointer to an object or NULL to refresh all objects of all displays
1902  */
lv_event_send_refresh_recursive(lv_obj_t * obj)1903 void lv_event_send_refresh_recursive(lv_obj_t * obj)
1904 {
1905     if(obj == NULL) {
1906         /*If no obj specified refresh all screen of all displays */
1907         lv_disp_t * d = lv_disp_get_next(NULL);
1908         while(d) {
1909             lv_obj_t * scr = _lv_ll_get_head(&d->scr_ll);
1910             while(scr) {
1911                 lv_event_send_refresh_recursive(scr);
1912                 scr = _lv_ll_get_next(&d->scr_ll, scr);
1913             }
1914             lv_event_send_refresh_recursive(d->top_layer);
1915             lv_event_send_refresh_recursive(d->sys_layer);
1916 
1917             d = lv_disp_get_next(d);
1918         }
1919     }
1920     else {
1921 
1922         lv_res_t res = lv_event_send_refresh(obj);
1923         if(res != LV_RES_OK) return; /*If invalid returned do not check the children*/
1924 
1925         lv_obj_t * child = lv_obj_get_child(obj, NULL);
1926         while(child) {
1927             lv_event_send_refresh_recursive(child);
1928 
1929             child = lv_obj_get_child(obj, child);
1930         }
1931     }
1932 }
1933 
1934 
1935 /**
1936  * Call an event function with an object, event, and data.
1937  * @param event_xcb an event callback function. If `NULL` `LV_RES_OK` will return without any actions.
1938  *        (the 'x' in the argument name indicates that its not a fully generic function because it not follows
1939  *         the `func_name(object, callback, ...)` convention)
1940  * @param obj pointer to an object to associate with the event (can be `NULL` to simply call the `event_cb`)
1941  * @param event an event
1942  * @param data pointer to a custom data
1943  * @return LV_RES_OK: `obj` was not deleted in the event; LV_RES_INV: `obj` was deleted in the event
1944  */
lv_event_send_func(lv_event_cb_t event_xcb,lv_obj_t * obj,lv_event_t event,const void * data)1945 lv_res_t lv_event_send_func(lv_event_cb_t event_xcb, lv_obj_t * obj, lv_event_t event, const void * data)
1946 {
1947     if(obj != NULL) {
1948         LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
1949     }
1950 
1951     /* Build a simple linked list from the objects used in the events
1952      * It's important to know if an this object was deleted by a nested event
1953      * called from this `even_cb`. */
1954     lv_event_temp_data_t event_temp_data;
1955     event_temp_data.obj     = obj;
1956     event_temp_data.deleted = false;
1957     event_temp_data.prev    = NULL;
1958 
1959     if(event_temp_data_head) {
1960         event_temp_data.prev = event_temp_data_head;
1961     }
1962     event_temp_data_head = &event_temp_data;
1963 
1964     const void * event_act_data_save = event_act_data;
1965     event_act_data                   = data;
1966 
1967     /*Call the input device's feedback callback if set*/
1968     lv_indev_t * indev_act = lv_indev_get_act();
1969     if(indev_act) {
1970         if(indev_act->driver.feedback_cb) indev_act->driver.feedback_cb(&indev_act->driver, event);
1971     }
1972 
1973     /*Call the event callback itself*/
1974     if(event_xcb) event_xcb(obj, event);
1975 
1976     /*Restore the event data*/
1977     event_act_data = event_act_data_save;
1978 
1979     /*Remove this element from the list*/
1980     event_temp_data_head = event_temp_data_head->prev;
1981 
1982     if(event_temp_data.deleted) {
1983         return LV_RES_INV;
1984     }
1985 
1986     if(obj) {
1987         if(obj->parent_event && obj->parent) {
1988             lv_res_t res = lv_event_send(obj->parent, event, data);
1989             if(res != LV_RES_OK) {
1990                 return LV_RES_INV;
1991             }
1992         }
1993     }
1994 
1995     return LV_RES_OK;
1996 }
1997 
1998 /**
1999  * Get the `data` parameter of the current event
2000  * @return the `data` parameter
2001  */
lv_event_get_data(void)2002 const void * lv_event_get_data(void)
2003 {
2004     return event_act_data;
2005 }
2006 
2007 /**
2008  * Set the a signal function of an object. Used internally by the library.
2009  * Always call the previous signal function in the new.
2010  * @param obj pointer to an object
2011  * @param cb the new signal function
2012  */
lv_obj_set_signal_cb(lv_obj_t * obj,lv_signal_cb_t signal_cb)2013 void lv_obj_set_signal_cb(lv_obj_t * obj, lv_signal_cb_t signal_cb)
2014 {
2015     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2016 
2017     obj->signal_cb = signal_cb;
2018 }
2019 
2020 /**
2021  * Send an event to the object
2022  * @param obj pointer to an object
2023  * @param event the type of the event from `lv_event_t`.
2024  * @return LV_RES_OK or LV_RES_INV
2025  */
lv_signal_send(lv_obj_t * obj,lv_signal_t signal,void * param)2026 lv_res_t lv_signal_send(lv_obj_t * obj, lv_signal_t signal, void * param)
2027 {
2028     if(obj == NULL) return LV_RES_OK;
2029 
2030     lv_res_t res = LV_RES_OK;
2031     if(obj->signal_cb) res = obj->signal_cb(obj, signal, param);
2032 
2033     return res;
2034 }
2035 
2036 /**
2037  * Set a new design function for an object
2038  * @param obj pointer to an object
2039  * @param design_cb the new design function
2040  */
lv_obj_set_design_cb(lv_obj_t * obj,lv_design_cb_t design_cb)2041 void lv_obj_set_design_cb(lv_obj_t * obj, lv_design_cb_t design_cb)
2042 {
2043     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2044 
2045     obj->design_cb = design_cb;
2046 }
2047 
2048 /*----------------
2049  * Other set
2050  *--------------*/
2051 
2052 /**
2053  * Allocate a new ext. data for an object
2054  * @param obj pointer to an object
2055  * @param ext_size the size of the new ext. data
2056  * @return pointer to the allocated ext.
2057  * If out of memory NULL is returned and the original ext is preserved
2058  */
lv_obj_allocate_ext_attr(lv_obj_t * obj,uint16_t ext_size)2059 void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size)
2060 {
2061     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2062 
2063     void * new_ext = lv_mem_realloc(obj->ext_attr, ext_size);
2064     if(new_ext == NULL) return NULL;
2065 
2066     obj->ext_attr = new_ext;
2067     return (void *)obj->ext_attr;
2068 }
2069 
2070 /**
2071  * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object to refresh the extended draw area.
2072  * he object needs to be invalidated by `lv_obj_invalidate(obj)` manually after this function.
2073  * @param obj pointer to an object
2074  */
lv_obj_refresh_ext_draw_pad(lv_obj_t * obj)2075 void lv_obj_refresh_ext_draw_pad(lv_obj_t * obj)
2076 {
2077     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2078 
2079     obj->ext_draw_pad = 0;
2080     obj->signal_cb(obj, LV_SIGNAL_REFR_EXT_DRAW_PAD, NULL);
2081 
2082 }
2083 
2084 /*=======================
2085  * Getter functions
2086  *======================*/
2087 
2088 /**
2089  * Return with the screen of an object
2090  * @param obj pointer to an object
2091  * @return pointer to a screen
2092  */
lv_obj_get_screen(const lv_obj_t * obj)2093 lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj)
2094 {
2095     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2096 
2097     const lv_obj_t * par = obj;
2098     const lv_obj_t * act_p;
2099 
2100     do {
2101         act_p = par;
2102         par   = lv_obj_get_parent(act_p);
2103     } while(par != NULL);
2104 
2105     return (lv_obj_t *)act_p;
2106 }
2107 
2108 /**
2109  * Get the display of an object
2110  * @param scr pointer to an object
2111  * @return pointer the object's display
2112  */
lv_obj_get_disp(const lv_obj_t * obj)2113 lv_disp_t * lv_obj_get_disp(const lv_obj_t * obj)
2114 {
2115     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2116 
2117     const lv_obj_t * scr;
2118 
2119     if(obj->parent == NULL)
2120         scr = obj; /*`obj` is a screen*/
2121     else
2122         scr = lv_obj_get_screen(obj); /*get the screen of `obj`*/
2123 
2124     lv_disp_t * d;
2125     _LV_LL_READ(LV_GC_ROOT(_lv_disp_ll), d) {
2126         lv_obj_t * s;
2127         _LV_LL_READ(d->scr_ll, s) {
2128             if(s == scr) return d;
2129         }
2130     }
2131 
2132     LV_LOG_WARN("lv_scr_get_disp: screen not found")
2133     return NULL;
2134 }
2135 
2136 /*---------------------
2137  * Parent/children get
2138  *--------------------*/
2139 
2140 /**
2141  * Returns with the parent of an object
2142  * @param obj pointer to an object
2143  * @return pointer to the parent of  'obj'
2144  */
lv_obj_get_parent(const lv_obj_t * obj)2145 lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj)
2146 {
2147     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2148 
2149     return obj->parent;
2150 }
2151 
2152 /**
2153  * Iterate through the children of an object (start from the "youngest")
2154  * @param obj pointer to an object
2155  * @param child NULL at first call to get the next children
2156  *                  and the previous return value later
2157  * @return the child after 'act_child' or NULL if no more child
2158  */
lv_obj_get_child(const lv_obj_t * obj,const lv_obj_t * child)2159 lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child)
2160 {
2161     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2162 
2163     lv_obj_t * result = NULL;
2164 
2165     if(child == NULL) {
2166         result = _lv_ll_get_head(&obj->child_ll);
2167     }
2168     else {
2169         result = _lv_ll_get_next(&obj->child_ll, child);
2170     }
2171 
2172     return result;
2173 }
2174 
2175 /**
2176  * Iterate through the children of an object (start from the "oldest")
2177  * @param obj pointer to an object
2178  * @param child NULL at first call to get the next children
2179  *                  and the previous return value later
2180  * @return the child after 'act_child' or NULL if no more child
2181  */
lv_obj_get_child_back(const lv_obj_t * obj,const lv_obj_t * child)2182 lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child)
2183 {
2184     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2185 
2186     lv_obj_t * result = NULL;
2187 
2188     if(child == NULL) {
2189         result = _lv_ll_get_tail(&obj->child_ll);
2190     }
2191     else {
2192         result = _lv_ll_get_prev(&obj->child_ll, child);
2193     }
2194 
2195     return result;
2196 }
2197 
2198 /**
2199  * Count the children of an object (only children directly on 'obj')
2200  * @param obj pointer to an object
2201  * @return children number of 'obj'
2202  */
lv_obj_count_children(const lv_obj_t * obj)2203 uint16_t lv_obj_count_children(const lv_obj_t * obj)
2204 {
2205     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2206 
2207     lv_obj_t * i;
2208     uint16_t cnt = 0;
2209 
2210     _LV_LL_READ(obj->child_ll, i) cnt++;
2211 
2212     return cnt;
2213 }
2214 
2215 /** Recursively count the children of an object
2216  * @param obj pointer to an object
2217  * @return children number of 'obj'
2218  */
lv_obj_count_children_recursive(const lv_obj_t * obj)2219 uint16_t lv_obj_count_children_recursive(const lv_obj_t * obj)
2220 {
2221     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2222 
2223     lv_obj_t * i;
2224     uint16_t cnt = 0;
2225 
2226     _LV_LL_READ(obj->child_ll, i) {
2227         cnt++;                                     /*Count the child*/
2228         cnt += lv_obj_count_children_recursive(i); /*recursively count children's children*/
2229     }
2230 
2231     return cnt;
2232 }
2233 
2234 /*---------------------
2235  * Coordinate get
2236  *--------------------*/
2237 
2238 /**
2239  * Copy the coordinates of an object to an area
2240  * @param obj pointer to an object
2241  * @param cords_p pointer to an area to store the coordinates
2242  */
lv_obj_get_coords(const lv_obj_t * obj,lv_area_t * cords_p)2243 void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p)
2244 {
2245     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2246 
2247     lv_area_copy(cords_p, &obj->coords);
2248 }
2249 
2250 /**
2251  * Reduce area retried by `lv_obj_get_coords()` the get graphically usable area of an object.
2252  * (Without the size of the border or other extra graphical elements)
2253  * @param coords_p store the result area here
2254  */
lv_obj_get_inner_coords(const lv_obj_t * obj,lv_area_t * coords_p)2255 void lv_obj_get_inner_coords(const lv_obj_t * obj, lv_area_t * coords_p)
2256 {
2257     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2258 
2259     lv_border_side_t part = lv_obj_get_style_border_side(obj, LV_OBJ_PART_MAIN);
2260     lv_coord_t w = lv_obj_get_style_border_width(obj, LV_OBJ_PART_MAIN);
2261 
2262     if(part & LV_BORDER_SIDE_LEFT) coords_p->x1 += w;
2263 
2264     if(part & LV_BORDER_SIDE_RIGHT) coords_p->x2 -= w;
2265 
2266     if(part & LV_BORDER_SIDE_TOP) coords_p->y1 += w;
2267 
2268     if(part & LV_BORDER_SIDE_BOTTOM) coords_p->y2 -= w;
2269 }
2270 
2271 /**
2272  * Get the x coordinate of object
2273  * @param obj pointer to an object
2274  * @return distance of 'obj' from the left side of its parent
2275  */
lv_obj_get_x(const lv_obj_t * obj)2276 lv_coord_t lv_obj_get_x(const lv_obj_t * obj)
2277 {
2278     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2279 
2280     lv_coord_t rel_x;
2281     lv_obj_t * parent = lv_obj_get_parent(obj);
2282     if(parent) {
2283         rel_x             = obj->coords.x1 - parent->coords.x1;
2284     }
2285     else {
2286         rel_x = obj->coords.x1;
2287     }
2288     return rel_x;
2289 }
2290 
2291 /**
2292  * Get the y coordinate of object
2293  * @param obj pointer to an object
2294  * @return distance of 'obj' from the top of its parent
2295  */
lv_obj_get_y(const lv_obj_t * obj)2296 lv_coord_t lv_obj_get_y(const lv_obj_t * obj)
2297 {
2298     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2299 
2300     lv_coord_t rel_y;
2301     lv_obj_t * parent = lv_obj_get_parent(obj);
2302     if(parent) {
2303         rel_y             = obj->coords.y1 - parent->coords.y1;
2304     }
2305     else {
2306         rel_y = obj->coords.y1;
2307     }
2308     return rel_y;
2309 }
2310 
2311 /**
2312  * Get the width of an object
2313  * @param obj pointer to an object
2314  * @return the width
2315  */
lv_obj_get_width(const lv_obj_t * obj)2316 lv_coord_t lv_obj_get_width(const lv_obj_t * obj)
2317 {
2318     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2319 
2320     return lv_area_get_width(&obj->coords);
2321 }
2322 
2323 /**
2324  * Get the height of an object
2325  * @param obj pointer to an object
2326  * @return the height
2327  */
lv_obj_get_height(const lv_obj_t * obj)2328 lv_coord_t lv_obj_get_height(const lv_obj_t * obj)
2329 {
2330     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2331 
2332     return lv_area_get_height(&obj->coords);
2333 }
2334 
2335 /**
2336  * Get that width reduced by the left and right padding.
2337  * @param obj pointer to an object
2338  * @return the width which still fits into the container
2339  */
lv_obj_get_width_fit(const lv_obj_t * obj)2340 lv_coord_t lv_obj_get_width_fit(const lv_obj_t * obj)
2341 {
2342     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2343 
2344     lv_style_int_t left = lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN);
2345     lv_style_int_t right = lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN);
2346 
2347     return lv_obj_get_width(obj) - left - right;
2348 }
2349 
2350 /**
2351  * Get that height reduced by the top an bottom padding.
2352  * @param obj pointer to an object
2353  * @return the height which still fits into the container
2354  */
lv_obj_get_height_fit(const lv_obj_t * obj)2355 lv_coord_t lv_obj_get_height_fit(const lv_obj_t * obj)
2356 {
2357     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2358 
2359     lv_style_int_t top = lv_obj_get_style_pad_top((lv_obj_t *)obj, LV_OBJ_PART_MAIN);
2360     lv_style_int_t bottom =  lv_obj_get_style_pad_bottom((lv_obj_t *)obj, LV_OBJ_PART_MAIN);
2361 
2362     return lv_obj_get_height(obj) - top - bottom;
2363 }
2364 
2365 /**
2366  * Get the height of an object by taking the top and bottom margin into account.
2367  * The returned height will be `obj_h + margin_top + margin_bottom`
2368  * @param obj pointer to an object
2369  * @return the height including thee margins
2370  */
lv_obj_get_height_margin(lv_obj_t * obj)2371 lv_coord_t lv_obj_get_height_margin(lv_obj_t * obj)
2372 {
2373     lv_style_int_t mtop = lv_obj_get_style_margin_top(obj, LV_OBJ_PART_MAIN);
2374     lv_style_int_t mbottom = lv_obj_get_style_margin_bottom(obj, LV_OBJ_PART_MAIN);
2375 
2376     return lv_obj_get_height(obj) + mtop + mbottom;
2377 }
2378 
2379 /**
2380  * Get the width of an object by taking the left and right margin into account.
2381  * The returned width will be `obj_w + margin_left + margin_right`
2382  * @param obj pointer to an object
2383  * @return the height including thee margins
2384  */
lv_obj_get_width_margin(lv_obj_t * obj)2385 lv_coord_t lv_obj_get_width_margin(lv_obj_t * obj)
2386 {
2387     lv_style_int_t mleft = lv_obj_get_style_margin_left(obj, LV_OBJ_PART_MAIN);
2388     lv_style_int_t mright = lv_obj_get_style_margin_right(obj, LV_OBJ_PART_MAIN);
2389 
2390     return lv_obj_get_width(obj) + mleft + mright;
2391 }
2392 
2393 /**
2394  * Set that width reduced by the left and right padding of the parent.
2395  * @param obj pointer to an object
2396  * @param div indicates how many columns are assumed.
2397  * If 1 the width will be set the the parent's width
2398  * If 2 only half parent width - inner padding of the parent
2399  * If 3 only third parent width - 2 * inner padding of the parent
2400  * @param span how many columns are combined
2401  * @return the width according to the given parameters
2402  */
lv_obj_get_width_grid(lv_obj_t * obj,uint8_t div,uint8_t span)2403 lv_coord_t lv_obj_get_width_grid(lv_obj_t * obj, uint8_t div, uint8_t span)
2404 {
2405     lv_coord_t obj_w = lv_obj_get_width_fit(obj);
2406     lv_style_int_t pinner = lv_obj_get_style_pad_inner(obj, LV_OBJ_PART_MAIN);
2407 
2408     lv_coord_t r = (obj_w - (div - 1) * pinner) / div;
2409 
2410     r = r * span + (span - 1) * pinner;
2411     return r;
2412 }
2413 
2414 /**
2415  * Get that height reduced by the top and bottom padding of the parent.
2416  * @param obj pointer to an object
2417  * @param div indicates how many rows are assumed.
2418  * If 1 the height will be set the the parent's height
2419  * If 2 only half parent height - inner padding of the parent
2420  * If 3 only third parent height - 2 * inner padding of the parent
2421  * @param span how many rows are combined
2422  * @return the height according to the given parameters
2423  */
lv_obj_get_height_grid(lv_obj_t * obj,uint8_t div,uint8_t span)2424 lv_coord_t lv_obj_get_height_grid(lv_obj_t * obj, uint8_t div, uint8_t span)
2425 {
2426     lv_coord_t obj_h = lv_obj_get_height_fit(obj);
2427     lv_style_int_t pinner = lv_obj_get_style_pad_inner(obj, LV_OBJ_PART_MAIN);
2428 
2429     lv_coord_t r = (obj_h - (div - 1) * pinner) / div;
2430 
2431     r = r * span + (span - 1) * pinner;
2432     return r;
2433 }
2434 
2435 /**
2436  * Get the automatic realign property of the object.
2437  * @param obj pointer to an object
2438  * @return  true: auto realign is enabled; false: auto realign is disabled
2439  */
lv_obj_get_auto_realign(const lv_obj_t * obj)2440 bool lv_obj_get_auto_realign(const lv_obj_t * obj)
2441 {
2442     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2443 
2444 #if LV_USE_OBJ_REALIGN
2445     return obj->realign.auto_realign ? true : false;
2446 #else
2447     (void)obj;
2448     return false;
2449 #endif
2450 }
2451 
2452 /**
2453  * Get the left padding of extended clickable area
2454  * @param obj pointer to an object
2455  * @return the extended left padding
2456  */
lv_obj_get_ext_click_pad_left(const lv_obj_t * obj)2457 lv_coord_t lv_obj_get_ext_click_pad_left(const lv_obj_t * obj)
2458 {
2459     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2460 
2461 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
2462     return obj->ext_click_pad_hor;
2463 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
2464     return obj->ext_click_pad.x1;
2465 #else
2466     (void)obj;    /*Unused*/
2467     return 0;
2468 #endif
2469 }
2470 
2471 /**
2472  * Get the right padding of extended clickable area
2473  * @param obj pointer to an object
2474  * @return the extended right padding
2475  */
lv_obj_get_ext_click_pad_right(const lv_obj_t * obj)2476 lv_coord_t lv_obj_get_ext_click_pad_right(const lv_obj_t * obj)
2477 {
2478     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2479 
2480 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
2481     return obj->ext_click_pad_hor;
2482 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
2483     return obj->ext_click_pad.x2;
2484 #else
2485     (void)obj; /*Unused*/
2486     return 0;
2487 #endif
2488 }
2489 
2490 /**
2491  * Get the top padding of extended clickable area
2492  * @param obj pointer to an object
2493  * @return the extended top padding
2494  */
lv_obj_get_ext_click_pad_top(const lv_obj_t * obj)2495 lv_coord_t lv_obj_get_ext_click_pad_top(const lv_obj_t * obj)
2496 {
2497     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2498 
2499 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
2500     return obj->ext_click_pad_ver;
2501 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
2502     return obj->ext_click_pad.y1;
2503 #else
2504     (void)obj; /*Unused*/
2505     return 0;
2506 #endif
2507 }
2508 
2509 /**
2510  * Get the bottom padding of extended clickable area
2511  * @param obj pointer to an object
2512  * @return the extended bottom padding
2513  */
lv_obj_get_ext_click_pad_bottom(const lv_obj_t * obj)2514 lv_coord_t lv_obj_get_ext_click_pad_bottom(const lv_obj_t * obj)
2515 {
2516     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2517 
2518 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
2519     return obj->ext_click_pad_ver;
2520 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
2521     return obj->ext_click_pad.y2;
2522 #else
2523     (void)obj; /*Unused*/
2524     return 0;
2525 #endif
2526 }
2527 
2528 /**
2529  * Get the extended size attribute of an object
2530  * @param obj pointer to an object
2531  * @return the extended size attribute
2532  */
lv_obj_get_ext_draw_pad(const lv_obj_t * obj)2533 lv_coord_t lv_obj_get_ext_draw_pad(const lv_obj_t * obj)
2534 {
2535     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2536 
2537     return obj->ext_draw_pad;
2538 }
2539 
2540 /*-----------------
2541  * Appearance get
2542  *---------------*/
2543 
lv_obj_get_style_list(const lv_obj_t * obj,uint8_t part)2544 lv_style_list_t * lv_obj_get_style_list(const lv_obj_t * obj, uint8_t part)
2545 {
2546     if(part == LV_OBJ_PART_MAIN) return &((lv_obj_t *)obj)->style_list;
2547 
2548     lv_get_style_info_t info;
2549     info.part = part;
2550     info.result = NULL;
2551 
2552     lv_res_t res;
2553     res = lv_signal_send((lv_obj_t *)obj, LV_SIGNAL_GET_STYLE, &info);
2554 
2555     if(res != LV_RES_OK) return NULL;
2556 
2557     return info.result;
2558 }
2559 
2560 /**
2561  * Get a style property of a part of an object in the object's current state.
2562  * If there is a running transitions it is taken into account
2563  * @param obj pointer to an object
2564  * @param part the part of the object which style property should be get.
2565  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
2566  * @param prop the property to get. E.g. `LV_STYLE_BORDER_WIDTH`.
2567  *  The state of the object will be added internally
2568  * @return the value of the property of the given part in the current state.
2569  * If the property is not found a default value will be returned.
2570  * @note shouldn't be used directly. Use the specific property get functions instead.
2571  *       For example: `lv_obj_style_get_border_width()`
2572  * @note for performance reasons it's not checked if the property really has integer type
2573  */
_lv_obj_get_style_int(const lv_obj_t * obj,uint8_t part,lv_style_property_t prop)2574 lv_style_int_t _lv_obj_get_style_int(const lv_obj_t * obj, uint8_t part, lv_style_property_t prop)
2575 {
2576     lv_style_property_t prop_ori = prop;
2577 
2578     lv_style_attr_t attr;
2579     attr = prop_ori >> 8;
2580 
2581     lv_style_int_t value_act;
2582     lv_res_t res = LV_RES_INV;
2583     const lv_obj_t * parent = obj;
2584     while(parent) {
2585         lv_style_list_t * list = lv_obj_get_style_list(parent, part);
2586         if(!list->ignore_cache && list->style_cnt > 0) {
2587             if(!list->valid_cache) update_style_cache((lv_obj_t *)parent, part, prop  & (~LV_STYLE_STATE_MASK));
2588 
2589             bool def = false;
2590             switch(prop  & (~LV_STYLE_STATE_MASK)) {
2591                 case LV_STYLE_CLIP_CORNER:
2592                     if(list->clip_corner_off) def = true;
2593                     break;
2594                 case LV_STYLE_TEXT_LETTER_SPACE:
2595                 case LV_STYLE_TEXT_LINE_SPACE:
2596                     if(list->text_space_zero) def = true;
2597                     break;
2598                 case LV_STYLE_TRANSFORM_ANGLE:
2599                 case LV_STYLE_TRANSFORM_WIDTH:
2600                 case LV_STYLE_TRANSFORM_HEIGHT:
2601                 case LV_STYLE_TRANSFORM_ZOOM:
2602                     if(list->transform_all_zero) def = true;
2603                     break;
2604                 case LV_STYLE_BORDER_WIDTH:
2605                     if(list->border_width_zero) def = true;
2606                     break;
2607                 case LV_STYLE_BORDER_SIDE:
2608                     if(list->border_side_full) def = true;
2609                     break;
2610                 case LV_STYLE_BORDER_POST:
2611                     if(list->border_post_off) def = true;
2612                     break;
2613                 case LV_STYLE_OUTLINE_WIDTH:
2614                     if(list->outline_width_zero) def = true;
2615                     break;
2616                 case LV_STYLE_RADIUS:
2617                     if(list->radius_zero) def = true;
2618                     break;
2619                 case LV_STYLE_SHADOW_WIDTH:
2620                     if(list->shadow_width_zero) def = true;
2621                     break;
2622                 case LV_STYLE_PAD_TOP:
2623                 case LV_STYLE_PAD_BOTTOM:
2624                 case LV_STYLE_PAD_LEFT:
2625                 case LV_STYLE_PAD_RIGHT:
2626                     if(list->pad_all_zero) def = true;
2627                     break;
2628                 case LV_STYLE_MARGIN_TOP:
2629                 case LV_STYLE_MARGIN_BOTTOM:
2630                 case LV_STYLE_MARGIN_LEFT:
2631                 case LV_STYLE_MARGIN_RIGHT:
2632                     if(list->margin_all_zero) def = true;
2633                     break;
2634                 case LV_STYLE_BG_BLEND_MODE:
2635                 case LV_STYLE_BORDER_BLEND_MODE:
2636                 case LV_STYLE_IMAGE_BLEND_MODE:
2637                 case LV_STYLE_LINE_BLEND_MODE:
2638                 case LV_STYLE_OUTLINE_BLEND_MODE:
2639                 case LV_STYLE_PATTERN_BLEND_MODE:
2640                 case LV_STYLE_SHADOW_BLEND_MODE:
2641                 case LV_STYLE_TEXT_BLEND_MODE:
2642                 case LV_STYLE_VALUE_BLEND_MODE:
2643                     if(list->blend_mode_all_normal) def = true;
2644                     break;
2645                 case LV_STYLE_TEXT_DECOR:
2646                     if(list->text_decor_none) def = true;
2647                     break;
2648             }
2649 
2650             if(def) {
2651                 break;
2652             }
2653         }
2654 
2655         lv_state_t state = lv_obj_get_state(parent, part);
2656         prop = (uint16_t)prop_ori + ((uint16_t)state << LV_STYLE_STATE_POS);
2657 
2658         res = _lv_style_list_get_int(list, prop, &value_act);
2659         if(res == LV_RES_OK) return value_act;
2660 
2661         if(LV_STYLE_ATTR_GET_INHERIT(attr) == 0) break;
2662 
2663         /*If not found, check the `MAIN` style first*/
2664         if(part != LV_OBJ_PART_MAIN) {
2665             part = LV_OBJ_PART_MAIN;
2666             continue;
2667         }
2668 
2669         /*Check the parent too.*/
2670         parent = lv_obj_get_parent(parent);
2671     }
2672 
2673     /*Handle unset values*/
2674     prop = prop & (~LV_STYLE_STATE_MASK);
2675     switch(prop) {
2676         case LV_STYLE_BORDER_SIDE:
2677             return LV_BORDER_SIDE_FULL;
2678         case LV_STYLE_SIZE:
2679             return LV_DPI / 20;
2680         case LV_STYLE_SCALE_WIDTH:
2681             return LV_DPI / 8;
2682         case LV_STYLE_BG_GRAD_STOP:
2683             return 255;
2684         case LV_STYLE_TRANSFORM_ZOOM:
2685             return LV_IMG_ZOOM_NONE;
2686     }
2687 
2688     return 0;
2689 }
2690 
2691 /**
2692  * Get a style property of a part of an object in the object's current state.
2693  * If there is a running transitions it is taken into account
2694  * @param obj pointer to an object
2695  * @param part the part of the object which style property should be get.
2696  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
2697  * @param prop the property to get. E.g. `LV_STYLE_BORDER_COLOR`.
2698  *  The state of the object will be added internally
2699  * @return the value of the property of the given part in the current state.
2700  * If the property is not found a default value will be returned.
2701  * @note shouldn't be used directly. Use the specific property get functions instead.
2702  *       For example: `lv_obj_style_get_border_color()`
2703  * @note for performance reasons it's not checked if the property really has color type
2704  */
_lv_obj_get_style_color(const lv_obj_t * obj,uint8_t part,lv_style_property_t prop)2705 lv_color_t _lv_obj_get_style_color(const lv_obj_t * obj, uint8_t part, lv_style_property_t prop)
2706 {
2707     lv_style_property_t prop_ori = prop;
2708 
2709     lv_style_attr_t attr;
2710     attr = prop_ori >> 8;
2711 
2712     lv_color_t value_act;
2713     lv_res_t res = LV_RES_INV;
2714     const lv_obj_t * parent = obj;
2715     while(parent) {
2716         lv_style_list_t * list = lv_obj_get_style_list(parent, part);
2717 
2718         lv_state_t state = lv_obj_get_state(parent, part);
2719         prop = (uint16_t)prop_ori + ((uint16_t)state << LV_STYLE_STATE_POS);
2720 
2721         res = _lv_style_list_get_color(list, prop, &value_act);
2722         if(res == LV_RES_OK) return value_act;
2723 
2724         if(LV_STYLE_ATTR_GET_INHERIT(attr) == 0) break;
2725 
2726         /*If not found, check the `MAIN` style first*/
2727         if(part != LV_OBJ_PART_MAIN) {
2728             part = LV_OBJ_PART_MAIN;
2729             continue;
2730         }
2731 
2732         /*Check the parent too.*/
2733         parent = lv_obj_get_parent(parent);
2734     }
2735 
2736     /*Handle unset values*/
2737     prop = prop & (~LV_STYLE_STATE_MASK);
2738     switch(prop) {
2739         case LV_STYLE_BG_COLOR:
2740         case LV_STYLE_BG_GRAD_COLOR:
2741             return LV_COLOR_WHITE;
2742     }
2743 
2744     return LV_COLOR_BLACK;
2745 }
2746 
2747 /**
2748  * Get a style property of a part of an object in the object's current state.
2749  * If there is a running transitions it is taken into account
2750  * @param obj pointer to an object
2751  * @param part the part of the object which style property should be get.
2752  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
2753  * @param prop the property to get. E.g. `LV_STYLE_BORDER_OPA`.
2754  *  The state of the object will be added internally
2755  * @return the value of the property of the given part in the current state.
2756  * If the property is not found a default value will be returned.
2757  * @note shouldn't be used directly. Use the specific property get functions instead.
2758  *       For example: `lv_obj_style_get_border_opa()`
2759  * @note for performance reasons it's not checked if the property really has opacity type
2760  */
_lv_obj_get_style_opa(const lv_obj_t * obj,uint8_t part,lv_style_property_t prop)2761 lv_opa_t _lv_obj_get_style_opa(const lv_obj_t * obj, uint8_t part, lv_style_property_t prop)
2762 {
2763     lv_style_property_t prop_ori = prop;
2764 
2765     lv_style_attr_t attr;
2766     attr = prop_ori >> 8;
2767 
2768     lv_opa_t value_act;
2769     lv_res_t res = LV_RES_INV;
2770     const lv_obj_t * parent = obj;
2771     while(parent) {
2772         lv_style_list_t * list = lv_obj_get_style_list(parent, part);
2773 
2774         if(!list->ignore_cache && list->style_cnt > 0) {
2775             if(!list->valid_cache) update_style_cache((lv_obj_t *)parent, part, prop  & (~LV_STYLE_STATE_MASK));
2776             bool def = false;
2777             switch(prop & (~LV_STYLE_STATE_MASK)) {
2778                 case LV_STYLE_OPA_SCALE:
2779                     if(list->opa_scale_cover) def = true;
2780                     break;
2781                 case LV_STYLE_BG_OPA:
2782                     if(list->bg_opa_cover) return LV_OPA_COVER;     /*Special case, not the default value is used*/
2783                     if(list->bg_opa_transp) def = true;
2784                     break;
2785                 case LV_STYLE_IMAGE_RECOLOR_OPA:
2786                     if(list->img_recolor_opa_transp) def = true;
2787                     break;
2788             }
2789 
2790             if(def) {
2791                 break;
2792             }
2793         }
2794 
2795 
2796         lv_state_t state = lv_obj_get_state(parent, part);
2797         prop = (uint16_t)prop_ori + ((uint16_t)state << LV_STYLE_STATE_POS);
2798 
2799         res = _lv_style_list_get_opa(list, prop, &value_act);
2800         if(res == LV_RES_OK) return value_act;
2801 
2802         if(LV_STYLE_ATTR_GET_INHERIT(attr) == 0) break;
2803 
2804         /*If not found, check the `MAIN` style first*/
2805         if(part != LV_OBJ_PART_MAIN) {
2806             part = LV_OBJ_PART_MAIN;
2807             continue;
2808         }
2809 
2810         /*Check the parent too.*/
2811         parent = lv_obj_get_parent(parent);
2812     }
2813 
2814     /*Handle unset values*/
2815     prop = prop & (~LV_STYLE_STATE_MASK);
2816     switch(prop) {
2817         case LV_STYLE_BG_OPA:
2818         case LV_STYLE_IMAGE_RECOLOR_OPA:
2819         case LV_STYLE_PATTERN_RECOLOR_OPA:
2820             return LV_OPA_TRANSP;
2821     }
2822 
2823     return LV_OPA_COVER;
2824 }
2825 
2826 /**
2827  * Get a style property of a part of an object in the object's current state.
2828  * If there is a running transitions it is taken into account
2829  * @param obj pointer to an object
2830  * @param part the part of the object which style property should be get.
2831  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
2832  * @param prop the property to get. E.g. `LV_STYLE_TEXT_FONT`.
2833  *  The state of the object will be added internally
2834  * @return the value of the property of the given part in the current state.
2835  * If the property is not found a default value will be returned.
2836  * @note shouldn't be used directly. Use the specific property get functions instead.
2837  *       For example: `lv_obj_style_get_border_opa()`
2838  * @note for performance reasons it's not checked if the property really has pointer type
2839  */
_lv_obj_get_style_ptr(const lv_obj_t * obj,uint8_t part,lv_style_property_t prop)2840 const void * _lv_obj_get_style_ptr(const lv_obj_t * obj, uint8_t part, lv_style_property_t prop)
2841 {
2842     lv_style_property_t prop_ori = prop;
2843 
2844     lv_style_attr_t attr;
2845     attr = prop_ori >> 8;
2846 
2847     const void * value_act;
2848     lv_res_t res = LV_RES_INV;
2849     const lv_obj_t * parent = obj;
2850     while(parent) {
2851         lv_style_list_t * list = lv_obj_get_style_list(parent, part);
2852 
2853         if(!list->ignore_cache && list->style_cnt > 0) {
2854             if(!list->valid_cache) update_style_cache((lv_obj_t *)parent, part, prop  & (~LV_STYLE_STATE_MASK));
2855             bool def = false;
2856             switch(prop  & (~LV_STYLE_STATE_MASK)) {
2857                 case LV_STYLE_VALUE_STR:
2858                     if(list->value_txt_str) def = true;
2859                     break;
2860                 case LV_STYLE_PATTERN_IMAGE:
2861                     if(list->pattern_img_null) def = true;
2862                     break;
2863                 case LV_STYLE_TEXT_FONT:
2864                     if(list->text_font_normal) def = true;
2865                     break;
2866             }
2867 
2868             if(def) {
2869                 break;
2870             }
2871         }
2872 
2873         lv_state_t state = lv_obj_get_state(parent, part);
2874         prop = (uint16_t)prop_ori + ((uint16_t)state << LV_STYLE_STATE_POS);
2875 
2876         res = _lv_style_list_get_ptr(list, prop, &value_act);
2877         if(res == LV_RES_OK)  return value_act;
2878 
2879         if(LV_STYLE_ATTR_GET_INHERIT(attr) == 0) break;
2880 
2881         /*If not found, check the `MAIN` style first*/
2882         if(part != LV_OBJ_PART_MAIN) {
2883             part = LV_OBJ_PART_MAIN;
2884             continue;
2885         }
2886 
2887         /*Check the parent too.*/
2888         parent = lv_obj_get_parent(parent);
2889     }
2890 
2891     /*Handle unset values*/
2892     prop = prop & (~LV_STYLE_STATE_MASK);
2893     switch(prop) {
2894         case LV_STYLE_TEXT_FONT:
2895         case LV_STYLE_VALUE_FONT:
2896             return lv_theme_get_font_normal();
2897 #if LV_USE_ANIMATION
2898         case LV_STYLE_TRANSITION_PATH:
2899             return &lv_anim_path_def;
2900 #endif
2901     }
2902 
2903     return NULL;
2904 }
2905 
2906 /**
2907  * Get the local style of a part of an object.
2908  * @param obj pointer to an object
2909  * @param part the part of the object which style property should be set.
2910  * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB`
2911  * @return pointer to the local style if exists else `NULL`.
2912  */
lv_obj_get_local_style(lv_obj_t * obj,uint8_t part)2913 lv_style_t * lv_obj_get_local_style(lv_obj_t * obj, uint8_t part)
2914 {
2915     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2916     lv_style_list_t * style_list = lv_obj_get_style_list(obj, part);
2917     return lv_style_list_get_local_style(style_list);
2918 }
2919 
2920 /*-----------------
2921  * Attribute get
2922  *----------------*/
2923 
2924 /**
2925  * Get the hidden attribute of an object
2926  * @param obj pointer to an object
2927  * @return true: the object is hidden
2928  */
lv_obj_get_hidden(const lv_obj_t * obj)2929 bool lv_obj_get_hidden(const lv_obj_t * obj)
2930 {
2931     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2932 
2933     return obj->hidden == 0 ? false : true;
2934 }
2935 
2936 /**
2937  * Get whether advanced hit-testing is enabled on an object
2938  * @param obj pointer to an object
2939  * @return true: advanced hit-testing is enabled
2940  */
lv_obj_get_adv_hittest(const lv_obj_t * obj)2941 bool lv_obj_get_adv_hittest(const lv_obj_t * obj)
2942 {
2943     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2944 
2945     return obj->adv_hittest == 0 ? false : true;
2946 }
2947 
2948 /**
2949  * Get the click enable attribute of an object
2950  * @param obj pointer to an object
2951  * @return true: the object is clickable
2952  */
lv_obj_get_click(const lv_obj_t * obj)2953 bool lv_obj_get_click(const lv_obj_t * obj)
2954 {
2955     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2956 
2957     return obj->click == 0 ? false : true;
2958 }
2959 
2960 /**
2961  * Get the top enable attribute of an object
2962  * @param obj pointer to an object
2963  * @return true: the auto top feature is enabled
2964  */
lv_obj_get_top(const lv_obj_t * obj)2965 bool lv_obj_get_top(const lv_obj_t * obj)
2966 {
2967     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2968 
2969     return obj->top == 0 ? false : true;
2970 }
2971 
2972 /**
2973  * Get the drag enable attribute of an object
2974  * @param obj pointer to an object
2975  * @return true: the object is draggable
2976  */
lv_obj_get_drag(const lv_obj_t * obj)2977 bool lv_obj_get_drag(const lv_obj_t * obj)
2978 {
2979     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2980 
2981     return obj->drag == 0 ? false : true;
2982 }
2983 
2984 /**
2985  * Get the directions an object can be dragged
2986  * @param obj pointer to an object
2987  * @return bitwise OR of allowed directions an object can be dragged in
2988  */
lv_obj_get_drag_dir(const lv_obj_t * obj)2989 lv_drag_dir_t lv_obj_get_drag_dir(const lv_obj_t * obj)
2990 {
2991     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
2992 
2993     return obj->drag_dir;
2994 }
2995 
2996 /**
2997  * Get the drag throw enable attribute of an object
2998  * @param obj pointer to an object
2999  * @return true: drag throw is enabled
3000  */
lv_obj_get_drag_throw(const lv_obj_t * obj)3001 bool lv_obj_get_drag_throw(const lv_obj_t * obj)
3002 {
3003     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3004 
3005     return obj->drag_throw == 0 ? false : true;
3006 }
3007 
3008 /**
3009  * Get the drag parent attribute of an object
3010  * @param obj pointer to an object
3011  * @return true: drag parent is enabled
3012  */
lv_obj_get_drag_parent(const lv_obj_t * obj)3013 bool lv_obj_get_drag_parent(const lv_obj_t * obj)
3014 {
3015     return obj->drag_parent == 0 ? false : true;
3016 }
3017 
3018 /**
3019 * Get the gesture parent attribute of an object
3020 * @param obj pointer to an object
3021 * @return true: gesture parent is enabled
3022 */
lv_obj_get_gesture_parent(const lv_obj_t * obj)3023 bool lv_obj_get_gesture_parent(const lv_obj_t * obj)
3024 {
3025     return obj->gesture_parent == 0 ? false : true;
3026 }
3027 
3028 /**
3029 * Get the focus parent attribute of an object
3030 * @param obj pointer to an object
3031 * @return true: focus parent is enabled
3032 */
lv_obj_get_focus_parent(const lv_obj_t * obj)3033 bool lv_obj_get_focus_parent(const lv_obj_t * obj)
3034 {
3035     return obj->focus_parent == 0 ? false : true;
3036 }
3037 
3038 /**
3039  * Get the drag parent attribute of an object
3040  * @param obj pointer to an object
3041  * @return true: drag parent is enabled
3042  */
lv_obj_get_parent_event(const lv_obj_t * obj)3043 bool lv_obj_get_parent_event(const lv_obj_t * obj)
3044 {
3045     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3046 
3047     return obj->parent_event == 0 ? false : true;
3048 }
3049 
3050 
lv_obj_get_base_dir(const lv_obj_t * obj)3051 lv_bidi_dir_t lv_obj_get_base_dir(const lv_obj_t * obj)
3052 {
3053     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3054 
3055 #if LV_USE_BIDI
3056     const lv_obj_t * parent = obj;
3057 
3058     while(parent) {
3059         if(parent->base_dir != LV_BIDI_DIR_INHERIT) return parent->base_dir;
3060 
3061         parent = lv_obj_get_parent(parent);
3062     }
3063 
3064     return LV_BIDI_BASE_DIR_DEF;
3065 #else
3066     (void) obj;  /*Unused*/
3067     return LV_BIDI_DIR_LTR;
3068 #endif
3069 }
3070 
3071 /**
3072  * Get the protect field of an object
3073  * @param obj pointer to an object
3074  * @return protect field ('OR'ed values of `lv_protect_t`)
3075  */
lv_obj_get_protect(const lv_obj_t * obj)3076 uint8_t lv_obj_get_protect(const lv_obj_t * obj)
3077 {
3078     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3079 
3080     return obj->protect;
3081 }
3082 
3083 /**
3084  * Check at least one bit of a given protect bitfield is set
3085  * @param obj pointer to an object
3086  * @param prot protect bits to test ('OR'ed values of `lv_protect_t`)
3087  * @return false: none of the given bits are set, true: at least one bit is set
3088  */
lv_obj_is_protected(const lv_obj_t * obj,uint8_t prot)3089 bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot)
3090 {
3091     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3092 
3093     return (obj->protect & prot) == 0 ? false : true;
3094 }
3095 
lv_obj_get_state(const lv_obj_t * obj,uint8_t part)3096 lv_state_t lv_obj_get_state(const lv_obj_t * obj, uint8_t part)
3097 {
3098     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3099 
3100     if(part < _LV_OBJ_PART_REAL_LAST) return ((lv_obj_t *)obj)->state;
3101 
3102     /*If a real part is asked, then use the object's signal to get its state.
3103      * A real object can be in different state then the main part
3104      * and only the object itself knows who to get it's state. */
3105     lv_get_state_info_t info;
3106     info.part = part;
3107     info.result = LV_STATE_DEFAULT;
3108     lv_signal_send((lv_obj_t *)obj, LV_SIGNAL_GET_STATE_DSC, &info);
3109 
3110     return info.result;
3111 
3112 }
3113 
3114 /**
3115  * Get the signal function of an object
3116  * @param obj pointer to an object
3117  * @return the signal function
3118  */
lv_obj_get_signal_cb(const lv_obj_t * obj)3119 lv_signal_cb_t lv_obj_get_signal_cb(const lv_obj_t * obj)
3120 {
3121     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3122 
3123     return obj->signal_cb;
3124 }
3125 
3126 /**
3127  * Get the design function of an object
3128  * @param obj pointer to an object
3129  * @return the design function
3130  */
lv_obj_get_design_cb(const lv_obj_t * obj)3131 lv_design_cb_t lv_obj_get_design_cb(const lv_obj_t * obj)
3132 {
3133     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3134 
3135     return obj->design_cb;
3136 }
3137 
3138 /**
3139  * Get the event function of an object
3140  * @param obj pointer to an object
3141  * @return the event function
3142  */
lv_obj_get_event_cb(const lv_obj_t * obj)3143 lv_event_cb_t lv_obj_get_event_cb(const lv_obj_t * obj)
3144 {
3145     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3146 
3147     return obj->event_cb;
3148 }
3149 
3150 /*------------------
3151  * Other get
3152  *-----------------*/
3153 
3154 /**
3155  * Get the ext pointer
3156  * @param obj pointer to an object
3157  * @return the ext pointer but not the dynamic version
3158  *         Use it as ext->data1, and NOT da(ext)->data1
3159  */
lv_obj_get_ext_attr(const lv_obj_t * obj)3160 void * lv_obj_get_ext_attr(const lv_obj_t * obj)
3161 {
3162     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3163 
3164     return obj->ext_attr;
3165 }
3166 
3167 /**
3168  * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type.
3169  * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj"
3170  * @param obj pointer to an object which type should be get
3171  * @param buf pointer to an `lv_obj_type_t` buffer to store the types
3172  */
lv_obj_get_type(const lv_obj_t * obj,lv_obj_type_t * buf)3173 void lv_obj_get_type(const lv_obj_t * obj, lv_obj_type_t * buf)
3174 {
3175     LV_ASSERT_NULL(buf);
3176     LV_ASSERT_NULL(obj);
3177 
3178     lv_obj_type_t tmp;
3179 
3180     _lv_memset_00(buf, sizeof(lv_obj_type_t));
3181     _lv_memset_00(&tmp, sizeof(lv_obj_type_t));
3182 
3183     obj->signal_cb((lv_obj_t *)obj, LV_SIGNAL_GET_TYPE, &tmp);
3184 
3185     uint8_t cnt;
3186     for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) {
3187         if(tmp.type[cnt] == NULL) break;
3188     }
3189 
3190     /*Swap the order. The real type comes first*/
3191     uint8_t i;
3192     for(i = 0; i < cnt; i++) {
3193         buf->type[i] = tmp.type[cnt - 1 - i];
3194     }
3195 }
3196 
3197 #if LV_USE_USER_DATA
3198 
3199 /**
3200  * Get the object's user data
3201  * @param obj pointer to an object
3202  * @return user data
3203  */
lv_obj_get_user_data(const lv_obj_t * obj)3204 lv_obj_user_data_t lv_obj_get_user_data(const lv_obj_t * obj)
3205 {
3206     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3207 
3208     return obj->user_data;
3209 }
3210 
3211 /**
3212  * Get a pointer to the object's user data
3213  * @param obj pointer to an object
3214  * @return pointer to the user data
3215  */
lv_obj_get_user_data_ptr(const lv_obj_t * obj)3216 lv_obj_user_data_t * lv_obj_get_user_data_ptr(const lv_obj_t * obj)
3217 {
3218     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3219 
3220     return (lv_obj_user_data_t *)&obj->user_data;
3221 }
3222 
3223 /**
3224  * Set the object's user data. The data will be copied.
3225  * @param obj pointer to an object
3226  * @param data user data
3227  */
lv_obj_set_user_data(lv_obj_t * obj,lv_obj_user_data_t data)3228 void lv_obj_set_user_data(lv_obj_t * obj, lv_obj_user_data_t data)
3229 {
3230     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3231 
3232     _lv_memcpy(&obj->user_data, &data, sizeof(lv_obj_user_data_t));
3233 }
3234 #endif
3235 
3236 /**
3237  * Get the group of the object
3238  * @param obj pointer to an object
3239  * @return the pointer to group of the object
3240  */
lv_obj_get_group(const lv_obj_t * obj)3241 void * lv_obj_get_group(const lv_obj_t * obj)
3242 {
3243     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3244 
3245 #if LV_USE_GROUP
3246     return obj->group_p;
3247 #else
3248     LV_UNUSED(obj);
3249     return NULL;
3250 #endif
3251 }
3252 
3253 /**
3254  * Tell whether the object is the focused object of a group or not.
3255  * @param obj pointer to an object
3256  * @return true: the object is focused, false: the object is not focused or not in a group
3257  */
lv_obj_is_focused(const lv_obj_t * obj)3258 bool lv_obj_is_focused(const lv_obj_t * obj)
3259 {
3260     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3261 
3262 #if LV_USE_GROUP
3263     if(obj->group_p) {
3264         if(lv_group_get_focused(obj->group_p) == obj) return true;
3265     }
3266     return false;
3267 #else
3268     LV_UNUSED(obj);
3269     return false;
3270 #endif
3271 }
3272 
3273 
3274 /*-------------------
3275  * OTHER FUNCTIONS
3276  *------------------*/
3277 
3278 /**
3279  * Check if a given screen-space point is on an object's coordinates.
3280  *
3281  * This method is intended to be used mainly by advanced hit testing algorithms to check
3282  * whether the point is even within the object (as an optimization).
3283  * @param obj object to check
3284  * @param point screen-space point
3285  */
lv_obj_is_point_on_coords(lv_obj_t * obj,const lv_point_t * point)3286 bool lv_obj_is_point_on_coords(lv_obj_t * obj, const lv_point_t * point)
3287 {
3288 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
3289     lv_area_t ext_area;
3290     ext_area.x1 = obj->coords.x1 - obj->ext_click_pad_hor;
3291     ext_area.x2 = obj->coords.x2 + obj->ext_click_pad_hor;
3292     ext_area.y1 = obj->coords.y1 - obj->ext_click_pad_ver;
3293     ext_area.y2 = obj->coords.y2 + obj->ext_click_pad_ver;
3294 
3295     if(!_lv_area_is_point_on(&ext_area, point, 0)) {
3296 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
3297     lv_area_t ext_area;
3298     ext_area.x1 = obj->coords.x1 - obj->ext_click_pad.x1;
3299     ext_area.x2 = obj->coords.x2 + obj->ext_click_pad.x2;
3300     ext_area.y1 = obj->coords.y1 - obj->ext_click_pad.y1;
3301     ext_area.y2 = obj->coords.y2 + obj->ext_click_pad.y2;
3302 
3303     if(!_lv_area_is_point_on(&ext_area, point, 0)) {
3304 #else
3305     if(!_lv_area_is_point_on(&obj->coords, point, 0)) {
3306 #endif
3307         return false;
3308     }
3309     return true;
3310 }
3311 
3312 /**
3313  * Hit-test an object given a particular point in screen space.
3314  * @param obj object to hit-test
3315  * @param point screen-space point
3316  * @return true if the object is considered under the point
3317  */
3318 bool lv_obj_hittest(lv_obj_t * obj, lv_point_t * point)
3319 {
3320     if(obj->adv_hittest) {
3321         lv_hit_test_info_t hit_info;
3322         hit_info.point = point;
3323         hit_info.result = true;
3324         obj->signal_cb(obj, LV_SIGNAL_HIT_TEST, &hit_info);
3325         return hit_info.result;
3326     }
3327     else
3328         return lv_obj_is_point_on_coords(obj, point);
3329 }
3330 
3331 /**
3332  * Used in the signal callback to handle `LV_SIGNAL_GET_TYPE` signal
3333  * @param obj pointer to an object
3334  * @param buf pointer to `lv_obj_type_t`. (`param` in the signal callback)
3335  * @param name name of the object. E.g. "lv_btn". (Only the pointer is saved)
3336  * @return LV_RES_OK
3337  */
3338 lv_res_t lv_obj_handle_get_type_signal(lv_obj_type_t * buf, const char * name)
3339 {
3340     uint8_t i;
3341     for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
3342         if(buf->type[i] == NULL) break;
3343     }
3344     buf->type[i] = name;
3345 
3346     return LV_RES_OK;
3347 }
3348 
3349 /**
3350  * Initialize a rectangle descriptor from an object's styles
3351  * @param obj pointer to an object
3352  * @param type type of style. E.g.  `LV_OBJ_PART_MAIN`, `LV_BTN_STYLE_REL` or `LV_PAGE_STYLE_SCRL`
3353  * @param draw_dsc the descriptor the initialize
3354  * @note Only the relevant fields will be set.
3355  * E.g. if `border width == 0` the other border properties won't be evaluated.
3356  */
3357 void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, uint8_t part, lv_draw_rect_dsc_t * draw_dsc)
3358 {
3359     draw_dsc->radius = lv_obj_get_style_radius(obj, part);
3360 
3361 #if LV_USE_OPA_SCALE
3362     lv_opa_t opa_scale = lv_obj_get_style_opa_scale(obj, part);
3363     if(opa_scale <= LV_OPA_MIN) {
3364         draw_dsc->bg_opa = LV_OPA_TRANSP;
3365         draw_dsc->border_opa = LV_OPA_TRANSP;
3366         draw_dsc->shadow_opa = LV_OPA_TRANSP;
3367         draw_dsc->pattern_opa = LV_OPA_TRANSP;
3368         draw_dsc->value_opa = LV_OPA_TRANSP;
3369         return;
3370     }
3371 #endif
3372 
3373     if(draw_dsc->bg_opa != LV_OPA_TRANSP) {
3374         draw_dsc->bg_opa = lv_obj_get_style_bg_opa(obj, part);
3375         if(draw_dsc->bg_opa > LV_OPA_MIN) {
3376             draw_dsc->bg_color = lv_obj_get_style_bg_color(obj, part);
3377             draw_dsc->bg_grad_dir =  lv_obj_get_style_bg_grad_dir(obj, part);
3378             if(draw_dsc->bg_grad_dir != LV_GRAD_DIR_NONE) {
3379                 draw_dsc->bg_grad_color = lv_obj_get_style_bg_grad_color(obj, part);
3380                 draw_dsc->bg_main_color_stop =  lv_obj_get_style_bg_main_stop(obj, part);
3381                 draw_dsc->bg_grad_color_stop =  lv_obj_get_style_bg_grad_stop(obj, part);
3382             }
3383 
3384 #if LV_USE_BLEND_MODES
3385             draw_dsc->bg_blend_mode = lv_obj_get_style_bg_blend_mode(obj, part);
3386 #endif
3387         }
3388     }
3389 
3390     draw_dsc->border_width = lv_obj_get_style_border_width(obj, part);
3391     if(draw_dsc->border_width) {
3392         if(draw_dsc->border_opa != LV_OPA_TRANSP) {
3393             draw_dsc->border_opa = lv_obj_get_style_border_opa(obj, part);
3394             if(draw_dsc->border_opa > LV_OPA_MIN) {
3395                 draw_dsc->border_side = lv_obj_get_style_border_side(obj, part);
3396                 draw_dsc->border_color = lv_obj_get_style_border_color(obj, part);
3397             }
3398 #if LV_USE_BLEND_MODES
3399             draw_dsc->border_blend_mode = lv_obj_get_style_border_blend_mode(obj, part);
3400 #endif
3401         }
3402     }
3403 
3404 #if LV_USE_OUTLINE
3405     draw_dsc->outline_width = lv_obj_get_style_outline_width(obj, part);
3406     if(draw_dsc->outline_width) {
3407         if(draw_dsc->outline_opa != LV_OPA_TRANSP) {
3408             draw_dsc->outline_opa = lv_obj_get_style_outline_opa(obj, part);
3409             if(draw_dsc->outline_opa > LV_OPA_MIN) {
3410                 draw_dsc->outline_pad = lv_obj_get_style_outline_pad(obj, part);
3411                 draw_dsc->outline_color = lv_obj_get_style_outline_color(obj, part);
3412             }
3413 #if LV_USE_BLEND_MODES
3414             draw_dsc->outline_blend_mode = lv_obj_get_style_outline_blend_mode(obj, part);
3415 #endif
3416         }
3417     }
3418 #endif
3419 
3420 #if LV_USE_PATTERN
3421     draw_dsc->pattern_image = lv_obj_get_style_pattern_image(obj, part);
3422     if(draw_dsc->pattern_image) {
3423         if(draw_dsc->pattern_opa != LV_OPA_TRANSP) {
3424             draw_dsc->pattern_opa = lv_obj_get_style_pattern_opa(obj, part);
3425             if(draw_dsc->pattern_opa > LV_OPA_MIN) {
3426                 draw_dsc->pattern_recolor_opa = lv_obj_get_style_pattern_recolor_opa(obj, part);
3427                 draw_dsc->pattern_repeat = lv_obj_get_style_pattern_repeat(obj, part);
3428                 if(lv_img_src_get_type(draw_dsc->pattern_image) == LV_IMG_SRC_SYMBOL) {
3429                     draw_dsc->pattern_recolor = lv_obj_get_style_pattern_recolor(obj, part);
3430                     draw_dsc->pattern_font = lv_obj_get_style_text_font(obj, part);
3431                 }
3432                 else if(draw_dsc->pattern_recolor_opa > LV_OPA_MIN) {
3433                     draw_dsc->pattern_recolor = lv_obj_get_style_pattern_recolor(obj, part);
3434                 }
3435 #if LV_USE_BLEND_MODES
3436                 draw_dsc->pattern_blend_mode = lv_obj_get_style_pattern_blend_mode(obj, part);
3437 #endif
3438             }
3439         }
3440     }
3441 #endif
3442 
3443 #if LV_USE_SHADOW
3444     draw_dsc->shadow_width = lv_obj_get_style_shadow_width(obj, part);
3445     if(draw_dsc->shadow_width) {
3446         if(draw_dsc->shadow_opa > LV_OPA_MIN) {
3447             draw_dsc->shadow_opa = lv_obj_get_style_shadow_opa(obj, part);
3448             if(draw_dsc->shadow_opa > LV_OPA_MIN) {
3449                 draw_dsc->shadow_ofs_x = lv_obj_get_style_shadow_ofs_x(obj, part);
3450                 draw_dsc->shadow_ofs_y = lv_obj_get_style_shadow_ofs_y(obj, part);
3451                 draw_dsc->shadow_spread = lv_obj_get_style_shadow_spread(obj, part);
3452                 draw_dsc->shadow_color = lv_obj_get_style_shadow_color(obj, part);
3453 #if LV_USE_BLEND_MODES
3454                 draw_dsc->shadow_blend_mode = lv_obj_get_style_shadow_blend_mode(obj, part);
3455 #endif
3456             }
3457         }
3458     }
3459 #endif
3460 
3461 #if LV_USE_VALUE_STR
3462     draw_dsc->value_str = lv_obj_get_style_value_str(obj, part);
3463     if(draw_dsc->value_str) {
3464         if(draw_dsc->value_opa > LV_OPA_MIN) {
3465             draw_dsc->value_opa = lv_obj_get_style_value_opa(obj, part);
3466             if(draw_dsc->value_opa > LV_OPA_MIN) {
3467                 draw_dsc->value_ofs_x = lv_obj_get_style_value_ofs_x(obj, part);
3468                 draw_dsc->value_ofs_y = lv_obj_get_style_value_ofs_y(obj, part);
3469                 draw_dsc->value_color = lv_obj_get_style_value_color(obj, part);
3470                 draw_dsc->value_font = lv_obj_get_style_value_font(obj, part);
3471                 draw_dsc->value_letter_space = lv_obj_get_style_value_letter_space(obj, part);
3472                 draw_dsc->value_line_space = lv_obj_get_style_value_line_space(obj, part);
3473                 draw_dsc->value_align = lv_obj_get_style_value_align(obj, part);
3474 #if LV_USE_BLEND_MODES
3475                 draw_dsc->value_blend_mode = lv_obj_get_style_value_blend_mode(obj, part);
3476 #endif
3477             }
3478         }
3479     }
3480 #endif
3481 
3482 #if LV_USE_OPA_SCALE
3483     if(opa_scale < LV_OPA_MAX) {
3484         draw_dsc->bg_opa = (uint16_t)((uint16_t)draw_dsc->bg_opa * opa_scale) >> 8;
3485         draw_dsc->border_opa = (uint16_t)((uint16_t)draw_dsc->border_opa * opa_scale) >> 8;
3486         draw_dsc->shadow_opa = (uint16_t)((uint16_t)draw_dsc->shadow_opa * opa_scale) >> 8;
3487         draw_dsc->pattern_opa = (uint16_t)((uint16_t)draw_dsc->pattern_opa * opa_scale) >> 8;
3488         draw_dsc->value_opa = (uint16_t)((uint16_t)draw_dsc->value_opa * opa_scale) >> 8;
3489     }
3490 #endif
3491 }
3492 
3493 void lv_obj_init_draw_label_dsc(lv_obj_t * obj, uint8_t part, lv_draw_label_dsc_t * draw_dsc)
3494 {
3495     draw_dsc->opa = lv_obj_get_style_text_opa(obj, part);
3496     if(draw_dsc->opa <= LV_OPA_MIN) return;
3497 
3498 #if LV_USE_OPA_SCALE
3499     lv_opa_t opa_scale = lv_obj_get_style_opa_scale(obj, part);
3500     if(opa_scale < LV_OPA_MAX) {
3501         draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa_scale) >> 8;
3502     }
3503     if(draw_dsc->opa <= LV_OPA_MIN) return;
3504 #endif
3505 
3506     draw_dsc->color = lv_obj_get_style_text_color(obj, part);
3507     draw_dsc->letter_space = lv_obj_get_style_text_letter_space(obj, part);
3508     draw_dsc->line_space = lv_obj_get_style_text_line_space(obj, part);
3509     draw_dsc->decor = lv_obj_get_style_text_decor(obj, part);
3510 #if LV_USE_BLEND_MODES
3511     draw_dsc->blend_mode = lv_obj_get_style_text_blend_mode(obj, part);
3512 #endif
3513 
3514     draw_dsc->font = lv_obj_get_style_text_font(obj, part);
3515 
3516     if(draw_dsc->sel_start != LV_DRAW_LABEL_NO_TXT_SEL && draw_dsc->sel_end != LV_DRAW_LABEL_NO_TXT_SEL) {
3517         draw_dsc->color = lv_obj_get_style_text_sel_color(obj, part);
3518     }
3519 
3520 #if LV_USE_BIDI
3521     draw_dsc->bidi_dir = lv_obj_get_base_dir(obj);
3522 #endif
3523 }
3524 
3525 void lv_obj_init_draw_img_dsc(lv_obj_t * obj, uint8_t part, lv_draw_img_dsc_t * draw_dsc)
3526 {
3527     draw_dsc->opa = lv_obj_get_style_image_opa(obj, part);
3528     if(draw_dsc->opa <= LV_OPA_MIN)  return;
3529 
3530 #if LV_USE_OPA_SCALE
3531     lv_opa_t opa_scale = lv_obj_get_style_opa_scale(obj, part);
3532     if(opa_scale < LV_OPA_MAX) {
3533         draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa_scale) >> 8;
3534     }
3535     if(draw_dsc->opa <= LV_OPA_MIN)  return;
3536 #endif
3537 
3538     draw_dsc->angle = 0;
3539     draw_dsc->zoom = LV_IMG_ZOOM_NONE;
3540     draw_dsc->pivot.x = lv_area_get_width(&obj->coords) / 2;
3541     draw_dsc->pivot.y = lv_area_get_height(&obj->coords) / 2;
3542 
3543     draw_dsc->recolor_opa = lv_obj_get_style_image_recolor_opa(obj, part);
3544     if(draw_dsc->recolor_opa > 0) {
3545         draw_dsc->recolor = lv_obj_get_style_image_recolor(obj, part);
3546     }
3547 #if LV_USE_BLEND_MODES
3548     draw_dsc->blend_mode = lv_obj_get_style_image_blend_mode(obj, part);
3549 #endif
3550 }
3551 
3552 void lv_obj_init_draw_line_dsc(lv_obj_t * obj, uint8_t part, lv_draw_line_dsc_t * draw_dsc)
3553 {
3554     draw_dsc->width = lv_obj_get_style_line_width(obj, part);
3555     if(draw_dsc->width == 0) return;
3556 
3557     draw_dsc->opa = lv_obj_get_style_line_opa(obj, part);
3558     if(draw_dsc->opa <= LV_OPA_MIN)  return;
3559 
3560 #if LV_USE_OPA_SCALE
3561     lv_opa_t opa_scale = lv_obj_get_style_opa_scale(obj, part);
3562     if(opa_scale < LV_OPA_MAX) {
3563         draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa_scale) >> 8;
3564     }
3565     if(draw_dsc->opa <= LV_OPA_MIN)  return;
3566 #endif
3567 
3568     draw_dsc->color = lv_obj_get_style_line_color(obj, part);
3569 
3570     draw_dsc->dash_width = lv_obj_get_style_line_dash_width(obj, part);
3571     if(draw_dsc->dash_width) {
3572         draw_dsc->dash_gap = lv_obj_get_style_line_dash_gap(obj, part);
3573     }
3574 
3575     draw_dsc->round_start = lv_obj_get_style_line_rounded(obj, part);
3576     draw_dsc->round_end = draw_dsc->round_start;
3577 
3578 #if LV_USE_BLEND_MODES
3579     draw_dsc->blend_mode = lv_obj_get_style_line_blend_mode(obj, part);
3580 #endif
3581 }
3582 
3583 /**
3584  * Get the required extra size (around the object's part) to draw shadow, outline, value etc.
3585  * @param obj pointer to an object
3586  * @param part part of the object
3587  */
3588 lv_coord_t lv_obj_get_draw_rect_ext_pad_size(lv_obj_t * obj, uint8_t part)
3589 {
3590     lv_coord_t s = 0;
3591 
3592     lv_coord_t sh_width = lv_obj_get_style_shadow_width(obj, part);
3593     if(sh_width) {
3594         lv_opa_t sh_opa = lv_obj_get_style_shadow_opa(obj, part);
3595         if(sh_opa > LV_OPA_MIN) {
3596             sh_width = sh_width / 2;    /*THe blur adds only half width*/
3597             sh_width++;
3598             sh_width += lv_obj_get_style_shadow_spread(obj, part);
3599             lv_style_int_t sh_ofs_x = lv_obj_get_style_shadow_ofs_x(obj, part);
3600             lv_style_int_t sh_ofs_y = lv_obj_get_style_shadow_ofs_y(obj, part);
3601             sh_width += LV_MATH_MAX(LV_MATH_ABS(sh_ofs_x), LV_MATH_ABS(sh_ofs_y));
3602             s = LV_MATH_MAX(s, sh_width);
3603         }
3604     }
3605 
3606     const char * value_str = lv_obj_get_style_value_str(obj, part);
3607     if(value_str) {
3608         lv_opa_t value_opa = lv_obj_get_style_value_opa(obj, part);
3609         if(value_opa > LV_OPA_MIN) {
3610             lv_style_int_t letter_space = lv_obj_get_style_value_letter_space(obj, part);
3611             lv_style_int_t line_space = lv_obj_get_style_value_letter_space(obj, part);
3612             const lv_font_t * font = lv_obj_get_style_value_font(obj, part);
3613 
3614             lv_point_t txt_size;
3615             _lv_txt_get_size(&txt_size, value_str, font, letter_space, line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE);
3616 
3617             lv_area_t value_area;
3618             value_area.x1 = 0;
3619             value_area.y1 = 0;
3620             value_area.x2 = txt_size.x - 1;
3621             value_area.y2 = txt_size.y - 1;
3622 
3623             lv_style_int_t align = lv_obj_get_style_value_align(obj, part);
3624             lv_style_int_t xofs = lv_obj_get_style_value_ofs_x(obj, part);
3625             lv_style_int_t yofs = lv_obj_get_style_value_ofs_y(obj, part);
3626             lv_point_t p_align;
3627             _lv_area_align(&obj->coords, &value_area, align, &p_align);
3628 
3629             value_area.x1 += p_align.x + xofs;
3630             value_area.y1 += p_align.y + yofs;
3631             value_area.x2 += p_align.x + xofs;
3632             value_area.y2 += p_align.y + yofs;
3633 
3634             s = LV_MATH_MAX(s, obj->coords.x1 - value_area.x1);
3635             s = LV_MATH_MAX(s, obj->coords.y1 - value_area.y1);
3636             s = LV_MATH_MAX(s, value_area.x2 - obj->coords.x2);
3637             s = LV_MATH_MAX(s, value_area.y2 - obj->coords.y2);
3638         }
3639     }
3640 
3641     lv_style_int_t outline_width = lv_obj_get_style_outline_width(obj, part);
3642     if(outline_width) {
3643         lv_opa_t outline_opa = lv_obj_get_style_outline_opa(obj, part);
3644         if(outline_opa > LV_OPA_MIN) {
3645             lv_style_int_t outline_pad = lv_obj_get_style_outline_pad(obj, part);
3646             s = LV_MATH_MAX(s, outline_pad + outline_width);
3647         }
3648     }
3649 
3650     lv_coord_t w = lv_obj_get_style_transform_width(obj, part);
3651     lv_coord_t h = lv_obj_get_style_transform_height(obj, part);
3652     lv_coord_t wh = LV_MATH_MAX(w, h);
3653     if(wh > 0) s += wh;
3654 
3655     return s;
3656 }
3657 
3658 /**
3659  * Fade in (from transparent to fully cover) an object and all its children using an `opa_scale` animation.
3660  * @param obj the object to fade in
3661  * @param time duration of the animation [ms]
3662  * @param delay wait before the animation starts [ms]
3663  */
3664 void lv_obj_fade_in(lv_obj_t * obj, uint32_t time, uint32_t delay)
3665 {
3666 #if LV_USE_ANIMATION
3667     lv_anim_t a;
3668     lv_anim_init(&a);
3669     lv_anim_set_var(&a, obj);
3670     lv_anim_set_values(&a, LV_OPA_TRANSP, LV_OPA_COVER);
3671     lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)opa_scale_anim);
3672     lv_anim_set_ready_cb(&a, fade_in_anim_ready);
3673     lv_anim_set_time(&a, time);
3674     lv_anim_set_delay(&a, delay);
3675     lv_anim_start(&a);
3676 #else
3677     (void) obj;     /*Unused*/
3678     (void) time;    /*Unused*/
3679     (void) delay;   /*Unused*/
3680 #endif
3681 }
3682 
3683 /**
3684  * Fade out (from fully cover to transparent) an object and all its children using an `opa_scale` animation.
3685  * @param obj the object to fade in
3686  * @param time duration of the animation [ms]
3687  * @param delay wait before the animation starts [ms]
3688  */
3689 void lv_obj_fade_out(lv_obj_t * obj, uint32_t time, uint32_t delay)
3690 {
3691 #if LV_USE_ANIMATION
3692     lv_anim_t a;
3693     lv_anim_init(&a);
3694     lv_anim_set_var(&a, obj);
3695     lv_anim_set_values(&a, LV_OPA_COVER, LV_OPA_TRANSP);
3696     lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)opa_scale_anim);
3697     lv_anim_set_time(&a, time);
3698     lv_anim_set_delay(&a, delay);
3699     lv_anim_start(&a);
3700 #else
3701     (void) obj;     /*Unused*/
3702     (void) time;    /*Unused*/
3703     (void) delay;   /*Unused*/
3704 #endif
3705 }
3706 
3707 /**
3708  * Check if any object has a given type
3709  * @param obj pointer to an object
3710  * @param obj_type type of the object. (e.g. "lv_btn")
3711  * @return true: valid
3712  */
3713 bool lv_debug_check_obj_type(const lv_obj_t * obj, const char * obj_type)
3714 {
3715     if(obj_type[0] == '\0') return true;
3716 
3717     lv_obj_type_t types;
3718     lv_obj_get_type((lv_obj_t *)obj, &types);
3719 
3720     uint8_t i;
3721     for(i = 0; i < LV_MAX_ANCESTOR_NUM; i++) {
3722         if(types.type[i] == NULL) break;
3723         if(strcmp(types.type[i], obj_type) == 0) return true;
3724     }
3725 
3726     return false;
3727 }
3728 
3729 /**
3730  * Check if any object is still "alive", and part of the hierarchy
3731  * @param obj pointer to an object
3732  * @param obj_type type of the object. (e.g. "lv_btn")
3733  * @return true: valid
3734  */
3735 bool lv_debug_check_obj_valid(const lv_obj_t * obj)
3736 {
3737     lv_disp_t * disp = lv_disp_get_next(NULL);
3738     while(disp) {
3739         lv_obj_t * scr;
3740         _LV_LL_READ(disp->scr_ll, scr) {
3741 
3742             if(scr == obj) return true;
3743             bool found = obj_valid_child(scr, obj);
3744             if(found) return true;
3745         }
3746 
3747         disp = lv_disp_get_next(disp);
3748     }
3749 
3750     return false;
3751 }
3752 
3753 /**********************
3754  *   STATIC FUNCTIONS
3755  **********************/
3756 
3757 static void lv_obj_del_async_cb(void * obj)
3758 {
3759     LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
3760 
3761     lv_obj_del(obj);
3762 }
3763 
3764 static void obj_del_core(lv_obj_t * obj)
3765 {
3766     /*Let the user free the resources used in `LV_EVENT_DELETE`*/
3767     lv_event_send(obj, LV_EVENT_DELETE, NULL);
3768 
3769     /*Delete from the group*/
3770 #if LV_USE_GROUP
3771     lv_group_t * group = lv_obj_get_group(obj);
3772     if(group) lv_group_remove_obj(obj);
3773 #endif
3774 
3775     /*Remove the animations from this object*/
3776 #if LV_USE_ANIMATION
3777     lv_anim_del(obj, NULL);
3778     trans_del(obj, 0xFF, 0xFF, NULL);
3779 #endif
3780 
3781     /*Delete the user data*/
3782 #if LV_USE_USER_DATA
3783 #if LV_USE_USER_DATA_FREE
3784     LV_USER_DATA_FREE(obj);
3785 #endif
3786 #endif
3787 
3788     /*Recursively delete the children*/
3789     lv_obj_t * i;
3790     i = _lv_ll_get_head(&(obj->child_ll));
3791     while(i != NULL) {
3792         /*Call the recursive delete to the child too*/
3793         obj_del_core(i);
3794 
3795         /*Set i to the new head node*/
3796         i = _lv_ll_get_head(&(obj->child_ll));
3797     }
3798 
3799     lv_event_mark_deleted(obj);
3800 
3801     /* Reset all input devices if the object to delete is used*/
3802     lv_indev_t * indev = lv_indev_get_next(NULL);
3803     while(indev) {
3804         if(indev->proc.types.pointer.act_obj == obj || indev->proc.types.pointer.last_obj == obj) {
3805             lv_indev_reset(indev, obj);
3806         }
3807         if(indev->proc.types.pointer.last_pressed == obj) {
3808             indev->proc.types.pointer.last_pressed = NULL;
3809         }
3810 
3811 #if LV_USE_GROUP
3812         if(indev->group == group && obj == lv_indev_get_obj_act()) {
3813             lv_indev_reset(indev, obj);
3814         }
3815 #endif
3816         indev = lv_indev_get_next(indev);
3817     }
3818 
3819     /* All children deleted.
3820      * Now clean up the object specific data*/
3821     obj->signal_cb(obj, LV_SIGNAL_CLEANUP, NULL);
3822 
3823     /*Remove the object from parent's children list*/
3824     lv_obj_t * par = lv_obj_get_parent(obj);
3825     if(par == NULL) { /*It is a screen*/
3826         lv_disp_t * d = lv_obj_get_disp(obj);
3827         _lv_ll_remove(&d->scr_ll, obj);
3828     }
3829     else {
3830         _lv_ll_remove(&(par->child_ll), obj);
3831     }
3832 
3833     /*Delete the base objects*/
3834     if(obj->ext_attr != NULL) lv_mem_free(obj->ext_attr);
3835     lv_mem_free(obj); /*Free the object itself*/
3836 }
3837 
3838 /**
3839  * Handle the drawing related tasks of the base objects.
3840  * @param obj pointer to an object
3841  * @param clip_area the object will be drawn only in this area
3842  * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
3843  *                                  (return 'true' if yes)
3844  *             LV_DESIGN_DRAW: draw the object (always return 'true')
3845  * @param return an element of `lv_design_res_t`
3846  */
3847 static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area, lv_design_mode_t mode)
3848 {
3849     if(mode == LV_DESIGN_COVER_CHK) {
3850         if(lv_obj_get_style_clip_corner(obj, LV_OBJ_PART_MAIN)) return LV_DESIGN_RES_MASKED;
3851 
3852         /*Most trivial test. Is the mask fully IN the object? If no it surely doesn't cover it*/
3853         lv_coord_t r = lv_obj_get_style_radius(obj, LV_OBJ_PART_MAIN);
3854         lv_coord_t w = lv_obj_get_style_transform_width(obj, LV_OBJ_PART_MAIN);
3855         lv_coord_t h = lv_obj_get_style_transform_height(obj, LV_OBJ_PART_MAIN);
3856         lv_area_t coords;
3857         lv_area_copy(&coords, &obj->coords);
3858         coords.x1 -= w;
3859         coords.x2 += w;
3860         coords.y1 -= h;
3861         coords.y2 += h;
3862 
3863         if(_lv_area_is_in(clip_area, &coords, r) == false) return LV_DESIGN_RES_NOT_COVER;
3864 
3865         if(lv_obj_get_style_bg_opa(obj, LV_OBJ_PART_MAIN) < LV_OPA_MAX) return LV_DESIGN_RES_NOT_COVER;
3866 
3867         if(lv_obj_get_style_bg_blend_mode(obj, LV_OBJ_PART_MAIN) != LV_BLEND_MODE_NORMAL) return LV_DESIGN_RES_NOT_COVER;
3868         if(lv_obj_get_style_border_blend_mode(obj, LV_OBJ_PART_MAIN) != LV_BLEND_MODE_NORMAL) return LV_DESIGN_RES_NOT_COVER;
3869         if(lv_obj_get_style_opa_scale(obj, LV_OBJ_PART_MAIN) < LV_OPA_MAX) return LV_DESIGN_RES_NOT_COVER;
3870 
3871         return  LV_DESIGN_RES_COVER;
3872 
3873     }
3874     else if(mode == LV_DESIGN_DRAW_MAIN) {
3875         lv_draw_rect_dsc_t draw_dsc;
3876         lv_draw_rect_dsc_init(&draw_dsc);
3877         /*If the border is drawn later disable loading its properties*/
3878         if(lv_obj_get_style_border_post(obj, LV_OBJ_PART_MAIN)) {
3879             draw_dsc.border_post = 1;
3880         }
3881 
3882         lv_obj_init_draw_rect_dsc(obj, LV_OBJ_PART_MAIN, &draw_dsc);
3883 
3884         lv_coord_t w = lv_obj_get_style_transform_width(obj, LV_OBJ_PART_MAIN);
3885         lv_coord_t h = lv_obj_get_style_transform_height(obj, LV_OBJ_PART_MAIN);
3886         lv_area_t coords;
3887         lv_area_copy(&coords, &obj->coords);
3888         coords.x1 -= w;
3889         coords.x2 += w;
3890         coords.y1 -= h;
3891         coords.y2 += h;
3892 
3893         lv_draw_rect(&coords, clip_area, &draw_dsc);
3894 
3895         if(lv_obj_get_style_clip_corner(obj, LV_OBJ_PART_MAIN)) {
3896             lv_draw_mask_radius_param_t * mp = _lv_mem_buf_get(sizeof(lv_draw_mask_radius_param_t));
3897 
3898             lv_coord_t r = lv_obj_get_style_radius(obj, LV_OBJ_PART_MAIN);
3899             /* If it has border make the clip area 1 px smaller to avoid color bleeding
3900              * The border will cover the minimal issue on the edges*/
3901             if(draw_dsc.border_post && draw_dsc.border_opa >= LV_OPA_MIN && draw_dsc.border_width > 0) {
3902                 lv_area_t cc_area;
3903                 cc_area.x1 = obj->coords.x1 + 1;
3904                 cc_area.y1 = obj->coords.y1 + 1;
3905                 cc_area.x2 = obj->coords.x2 - 1;
3906                 cc_area.y2 = obj->coords.y2 - 1;
3907                 lv_draw_mask_radius_init(mp, &cc_area, r, false);
3908             }
3909             /*If no border use the full size.*/
3910             else {
3911                 lv_draw_mask_radius_init(mp, &obj->coords, r, false);
3912             }
3913 
3914             /*Add the mask and use `obj+8` as custom id. Don't use `obj` directly because it might be used by the user*/
3915             lv_draw_mask_add(mp, obj + 8);
3916         }
3917     }
3918     else if(mode == LV_DESIGN_DRAW_POST) {
3919         if(lv_obj_get_style_clip_corner(obj, LV_OBJ_PART_MAIN)) {
3920             lv_draw_mask_radius_param_t * param = lv_draw_mask_remove_custom(obj + 8);
3921             _lv_mem_buf_release(param);
3922         }
3923 
3924         /*If the border is drawn later disable loading other properties*/
3925         if(lv_obj_get_style_border_post(obj, LV_OBJ_PART_MAIN)) {
3926             lv_draw_rect_dsc_t draw_dsc;
3927             lv_draw_rect_dsc_init(&draw_dsc);
3928             draw_dsc.bg_opa = LV_OPA_TRANSP;
3929             draw_dsc.pattern_opa = LV_OPA_TRANSP;
3930             draw_dsc.shadow_opa = LV_OPA_TRANSP;
3931             draw_dsc.value_opa = LV_OPA_TRANSP;
3932             lv_obj_init_draw_rect_dsc(obj, LV_OBJ_PART_MAIN, &draw_dsc);
3933 
3934             lv_coord_t w = lv_obj_get_style_transform_width(obj, LV_OBJ_PART_MAIN);
3935             lv_coord_t h = lv_obj_get_style_transform_height(obj, LV_OBJ_PART_MAIN);
3936             lv_area_t coords;
3937             lv_area_copy(&coords, &obj->coords);
3938             coords.x1 -= w;
3939             coords.x2 += w;
3940             coords.y1 -= h;
3941             coords.y2 += h;
3942             lv_draw_rect(&coords, clip_area, &draw_dsc);
3943         }
3944     }
3945 
3946     return LV_DESIGN_RES_OK;
3947 }
3948 
3949 
3950 /**
3951  * Get the really focused object by taking `focus_parent` into account.
3952  * @param obj the start object
3953  * @return the object to really focus
3954  */
3955 lv_obj_t * lv_obj_get_focused_obj(const lv_obj_t * obj)
3956 {
3957     if(obj == NULL) return NULL;
3958     const lv_obj_t * focus_obj = obj;
3959     while(lv_obj_get_focus_parent(focus_obj) != false && focus_obj != NULL) {
3960         focus_obj = lv_obj_get_parent(focus_obj);
3961     }
3962 
3963     return (lv_obj_t *)focus_obj;
3964 }
3965 
3966 /**
3967  * Signal function of the basic object
3968  * @param obj pointer to an object
3969  * @param sign signal type
3970  * @param param parameter for the signal (depends on signal type)
3971  * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
3972  */
3973 static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param)
3974 {
3975     if(sign == LV_SIGNAL_GET_STYLE) {
3976         lv_get_style_info_t * info = param;
3977         if(info->part == LV_OBJ_PART_MAIN) info->result = &obj->style_list;
3978         else info->result = NULL;
3979         return LV_RES_OK;
3980     }
3981     else if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
3982 
3983     lv_res_t res = LV_RES_OK;
3984 
3985     if(sign == LV_SIGNAL_CHILD_CHG) {
3986         /*Return 'invalid' if the child change signal is not enabled*/
3987         if(lv_obj_is_protected(obj, LV_PROTECT_CHILD_CHG) != false) res = LV_RES_INV;
3988     }
3989     else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
3990         lv_coord_t d = lv_obj_get_draw_rect_ext_pad_size(obj, LV_OBJ_PART_MAIN);
3991         obj->ext_draw_pad = LV_MATH_MAX(obj->ext_draw_pad, d);
3992     }
3993 #if LV_USE_OBJ_REALIGN
3994     else if(sign == LV_SIGNAL_PARENT_SIZE_CHG) {
3995         if(obj->realign.auto_realign) {
3996             lv_obj_realign(obj);
3997         }
3998     }
3999 #endif
4000     else if(sign == LV_SIGNAL_STYLE_CHG) {
4001         lv_obj_refresh_ext_draw_pad(obj);
4002     }
4003     else if(sign == LV_SIGNAL_PRESSED) {
4004         lv_obj_add_state(obj, LV_STATE_PRESSED);
4005     }
4006     else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) {
4007         lv_obj_clear_state(obj, LV_STATE_PRESSED);
4008     }
4009     else if(sign == LV_SIGNAL_FOCUS) {
4010         bool editing = false;
4011 #if LV_USE_GROUP
4012         editing = lv_group_get_editing(lv_obj_get_group(obj));
4013 #endif
4014         if(editing) {
4015             uint8_t state = LV_STATE_FOCUSED;
4016             state |= LV_STATE_EDITED;
4017 
4018             /*if using focus mode, change target to parent*/
4019             obj = lv_obj_get_focused_obj(obj);
4020 
4021             lv_obj_add_state(obj, state);
4022         }
4023         else {
4024 
4025             /*if using focus mode, change target to parent*/
4026             obj = lv_obj_get_focused_obj(obj);
4027 
4028             lv_obj_add_state(obj, LV_STATE_FOCUSED);
4029             lv_obj_clear_state(obj, LV_STATE_EDITED);
4030         }
4031     }
4032     else if(sign == LV_SIGNAL_DEFOCUS) {
4033 
4034         /*if using focus mode, change target to parent*/
4035         obj = lv_obj_get_focused_obj(obj);
4036 
4037         lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED);
4038     }
4039     else if(sign == LV_SIGNAL_CLEANUP) {
4040         lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
4041     }
4042 
4043     return res;
4044 }
4045 
4046 /**
4047  * Reposition the children of an object. (Called recursively)
4048  * @param obj pointer to an object which children will be repositioned
4049  * @param x_diff x coordinate shift
4050  * @param y_diff y coordinate shift
4051  */
4052 static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff)
4053 {
4054     lv_obj_t * i;
4055     _LV_LL_READ(obj->child_ll, i) {
4056         i->coords.x1 += x_diff;
4057         i->coords.y1 += y_diff;
4058         i->coords.x2 += x_diff;
4059         i->coords.y2 += y_diff;
4060 
4061         refresh_children_position(i, x_diff, y_diff);
4062     }
4063 }
4064 
4065 /**
4066  * Refresh the style of all children of an object. (Called recursively)
4067  * @param style refresh objects only with this style_list.
4068  * @param obj pointer to an object
4069  */
4070 static void report_style_mod_core(void * style, lv_obj_t * obj)
4071 {
4072     uint8_t part;
4073     for(part = 0; part != _LV_OBJ_PART_REAL_LAST; part++) {
4074         lv_style_list_t * list = lv_obj_get_style_list(obj, part);
4075         if(list == NULL) break;
4076 
4077         uint8_t ci;
4078         for(ci = 0; ci < list->style_cnt; ci++) {
4079             lv_style_t * class = lv_style_list_get_style(list, ci);
4080             if(class == style || style == NULL) {
4081                 lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL);
4082                 break;
4083             }
4084         }
4085     }
4086 
4087     lv_obj_t * child = lv_obj_get_child(obj, NULL);
4088     while(child) {
4089         report_style_mod_core(style, child);
4090         child = lv_obj_get_child(obj, child);
4091     }
4092 
4093 }
4094 
4095 /**
4096  * Recursively refresh the style of the children. Go deeper until a not NULL style is found
4097  * because the NULL styles are inherited from the parent
4098  * @param obj pointer to an object
4099  */
4100 static void refresh_children_style(lv_obj_t * obj)
4101 {
4102     lv_obj_t * child = lv_obj_get_child(obj, NULL);
4103     while(child != NULL) {
4104         lv_obj_invalidate(child);
4105         child->signal_cb(child, LV_SIGNAL_STYLE_CHG, NULL);
4106         lv_obj_invalidate(child);
4107 
4108         refresh_children_style(child); /*Check children too*/
4109         child = lv_obj_get_child(obj, child);
4110     }
4111 }
4112 
4113 static void base_dir_refr_children(lv_obj_t * obj)
4114 {
4115     lv_obj_t * child;
4116     child = lv_obj_get_child(obj, NULL);
4117 
4118     while(child) {
4119         if(child->base_dir == LV_BIDI_DIR_INHERIT) {
4120             lv_signal_send(child, LV_SIGNAL_BASE_DIR_CHG, NULL);
4121             base_dir_refr_children(child);
4122         }
4123 
4124         child = lv_obj_get_child(obj, child);
4125     }
4126 }
4127 
4128 static void obj_align_core(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, bool x_set, bool y_set,
4129                            lv_coord_t x_ofs, lv_coord_t y_ofs)
4130 {
4131     lv_point_t new_pos;
4132     _lv_area_align(&base->coords, &obj->coords, align, &new_pos);
4133 
4134     /*Bring together the coordination system of base and obj*/
4135     lv_obj_t * par        = lv_obj_get_parent(obj);
4136     lv_coord_t par_abs_x  = par->coords.x1;
4137     lv_coord_t par_abs_y  = par->coords.y1;
4138     new_pos.x += x_ofs;
4139     new_pos.y += y_ofs;
4140     new_pos.x -= par_abs_x;
4141     new_pos.y -= par_abs_y;
4142 
4143     if(x_set && y_set) lv_obj_set_pos(obj, new_pos.x, new_pos.y);
4144     else if(x_set) lv_obj_set_x(obj, new_pos.x);
4145     else if(y_set) lv_obj_set_y(obj, new_pos.y);
4146 }
4147 
4148 static void obj_align_mid_core(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align,  bool x_set, bool y_set,
4149                                lv_coord_t x_ofs, lv_coord_t y_ofs)
4150 {
4151     lv_coord_t new_x = lv_obj_get_x(obj);
4152     lv_coord_t new_y = lv_obj_get_y(obj);
4153 
4154     lv_coord_t obj_w_half = lv_obj_get_width(obj) / 2;
4155     lv_coord_t obj_h_half = lv_obj_get_height(obj) / 2;
4156 
4157 
4158     switch(align) {
4159         case LV_ALIGN_CENTER:
4160             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
4161             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
4162             break;
4163 
4164         case LV_ALIGN_IN_TOP_LEFT:
4165             new_x = -obj_w_half;
4166             new_y = -obj_h_half;
4167             break;
4168         case LV_ALIGN_IN_TOP_MID:
4169             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
4170             new_y = -obj_h_half;
4171             break;
4172 
4173         case LV_ALIGN_IN_TOP_RIGHT:
4174             new_x = lv_obj_get_width(base) - obj_w_half;
4175             new_y = -obj_h_half;
4176             break;
4177 
4178         case LV_ALIGN_IN_BOTTOM_LEFT:
4179             new_x = -obj_w_half;
4180             new_y = lv_obj_get_height(base) - obj_h_half;
4181             break;
4182         case LV_ALIGN_IN_BOTTOM_MID:
4183             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
4184             new_y = lv_obj_get_height(base) - obj_h_half;
4185             break;
4186 
4187         case LV_ALIGN_IN_BOTTOM_RIGHT:
4188             new_x = lv_obj_get_width(base) - obj_w_half;
4189             new_y = lv_obj_get_height(base) - obj_h_half;
4190             break;
4191 
4192         case LV_ALIGN_IN_LEFT_MID:
4193             new_x = -obj_w_half;
4194             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
4195             break;
4196 
4197         case LV_ALIGN_IN_RIGHT_MID:
4198             new_x = lv_obj_get_width(base) - obj_w_half;
4199             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
4200             break;
4201 
4202         case LV_ALIGN_OUT_TOP_LEFT:
4203             new_x = -obj_w_half;
4204             new_y = -obj_h_half;
4205             break;
4206 
4207         case LV_ALIGN_OUT_TOP_MID:
4208             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
4209             new_y = -obj_h_half;
4210             break;
4211 
4212         case LV_ALIGN_OUT_TOP_RIGHT:
4213             new_x = lv_obj_get_width(base) - obj_w_half;
4214             new_y = -obj_h_half;
4215             break;
4216 
4217         case LV_ALIGN_OUT_BOTTOM_LEFT:
4218             new_x = -obj_w_half;
4219             new_y = lv_obj_get_height(base) - obj_h_half;
4220             break;
4221 
4222         case LV_ALIGN_OUT_BOTTOM_MID:
4223             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
4224             new_y = lv_obj_get_height(base) - obj_h_half;
4225             break;
4226 
4227         case LV_ALIGN_OUT_BOTTOM_RIGHT:
4228             new_x = lv_obj_get_width(base) - obj_w_half;
4229             new_y = lv_obj_get_height(base) - obj_h_half;
4230             break;
4231 
4232         case LV_ALIGN_OUT_LEFT_TOP:
4233             new_x = -obj_w_half;
4234             new_y = -obj_h_half;
4235             break;
4236 
4237         case LV_ALIGN_OUT_LEFT_MID:
4238             new_x = -obj_w_half;
4239             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
4240             break;
4241 
4242         case LV_ALIGN_OUT_LEFT_BOTTOM:
4243             new_x = -obj_w_half;
4244             new_y = lv_obj_get_height(base) - obj_h_half;
4245             break;
4246 
4247         case LV_ALIGN_OUT_RIGHT_TOP:
4248             new_x = lv_obj_get_width(base) - obj_w_half;
4249             new_y = -obj_h_half;
4250             break;
4251 
4252         case LV_ALIGN_OUT_RIGHT_MID:
4253             new_x = lv_obj_get_width(base) - obj_w_half;
4254             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
4255             break;
4256 
4257         case LV_ALIGN_OUT_RIGHT_BOTTOM:
4258             new_x = lv_obj_get_width(base) - obj_w_half;
4259             new_y = lv_obj_get_height(base) - obj_h_half;
4260             break;
4261     }
4262 
4263     /*Bring together the coordination system of base and obj*/
4264     lv_obj_t * par        = lv_obj_get_parent(obj);
4265     lv_coord_t base_abs_x = base->coords.x1;
4266     lv_coord_t base_abs_y = base->coords.y1;
4267     lv_coord_t par_abs_x  = par->coords.x1;
4268     lv_coord_t par_abs_y  = par->coords.y1;
4269     new_x += x_ofs + base_abs_x;
4270     new_y += y_ofs + base_abs_y;
4271     new_x -= par_abs_x;
4272     new_y -= par_abs_y;
4273     if(x_set && y_set) lv_obj_set_pos(obj, new_x, new_y);
4274     else if(x_set) lv_obj_set_x(obj, new_x);
4275     else if(y_set) lv_obj_set_y(obj, new_y);
4276 
4277 }
4278 
4279 
4280 
4281 #if LV_USE_ANIMATION
4282 
4283 /**
4284  * Allocate and initialize a transition for a property of an object if the properties value is different in the new state.
4285  * It allocates `lv_style_trans_t` in `_lv_obj_style_trans_ll` and set only `start/end_values`. No animation will be created here.
4286  * @param obj and object to add the transition
4287  * @param prop the property to apply the transaction
4288  * @param part the part of the object to apply the transaction
4289  * @param prev_state the previous state of the objects
4290  * @param new_state the new state of the object
4291  * @return pointer to the allocated `the transaction` variable or `NULL` if no transition created
4292  */
4293 static lv_style_trans_t * trans_create(lv_obj_t * obj, lv_style_property_t prop, uint8_t part, lv_state_t prev_state,
4294                                        lv_state_t new_state)
4295 {
4296     lv_style_trans_t * tr;
4297     lv_style_list_t * style_list = lv_obj_get_style_list(obj, part);
4298     lv_style_t * style_trans = _lv_style_list_get_transition_style(style_list);
4299 
4300     bool cahche_ori = style_list->ignore_cache;
4301 
4302     /*Get the previous and current values*/
4303     if((prop & 0xF) < LV_STYLE_ID_COLOR) { /*Int*/
4304         style_list->skip_trans = 1;
4305         style_list->ignore_cache = 1;
4306         obj->state = prev_state;
4307         lv_style_int_t int1 = _lv_obj_get_style_int(obj, part, prop);
4308         obj->state = new_state;
4309         lv_style_int_t int2 =  _lv_obj_get_style_int(obj, part, prop);
4310         style_list->skip_trans = 0;
4311         style_list->ignore_cache = cahche_ori;
4312 
4313         if(int1 == int2)  return NULL;
4314         obj->state = prev_state;
4315         int1 = _lv_obj_get_style_int(obj, part, prop);
4316         obj->state = new_state;
4317         _lv_style_set_int(style_trans, prop, int1);   /*Be sure `trans_style` has a valid value */
4318 
4319         if(prop == LV_STYLE_RADIUS) {
4320             if(int1 == LV_RADIUS_CIRCLE || int2 == LV_RADIUS_CIRCLE) {
4321                 lv_coord_t whalf = lv_obj_get_width(obj) / 2;
4322                 lv_coord_t hhalf = lv_obj_get_width(obj) / 2;
4323                 if(int1 == LV_RADIUS_CIRCLE) int1 = LV_MATH_MIN(whalf + 1, hhalf + 1);
4324                 if(int2 == LV_RADIUS_CIRCLE) int2 = LV_MATH_MIN(whalf + 1, hhalf + 1);
4325             }
4326         }
4327 
4328         tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll));
4329         LV_ASSERT_MEM(tr);
4330         if(tr == NULL) return NULL;
4331         tr->start_value._int = int1;
4332         tr->end_value._int = int2;
4333     }
4334     else if((prop & 0xF) < LV_STYLE_ID_OPA) { /*Color*/
4335         style_list->skip_trans = 1;
4336         style_list->ignore_cache = 1;
4337         obj->state = prev_state;
4338         lv_color_t c1 = _lv_obj_get_style_color(obj, part, prop);
4339         obj->state = new_state;
4340         lv_color_t c2 =  _lv_obj_get_style_color(obj, part, prop);
4341         style_list->skip_trans = 0;
4342         style_list->ignore_cache = cahche_ori;
4343 
4344         if(c1.full == c2.full) return NULL;
4345         obj->state = prev_state;
4346         c1 = _lv_obj_get_style_color(obj, part, prop);
4347         obj->state = new_state;
4348         _lv_style_set_color(style_trans, prop, c1);    /*Be sure `trans_style` has a valid value */
4349 
4350         tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll));
4351         LV_ASSERT_MEM(tr);
4352         if(tr == NULL) return NULL;
4353         tr->start_value._color = c1;
4354         tr->end_value._color = c2;
4355     }
4356     else if((prop & 0xF) < LV_STYLE_ID_PTR) { /*Opa*/
4357         style_list->skip_trans = 1;
4358         style_list->ignore_cache = 1;
4359         obj->state = prev_state;
4360         lv_opa_t o1 = _lv_obj_get_style_opa(obj, part, prop);
4361         obj->state = new_state;
4362         lv_opa_t o2 =  _lv_obj_get_style_opa(obj, part, prop);
4363         style_list->skip_trans = 0;
4364         style_list->ignore_cache = cahche_ori;
4365 
4366         if(o1 == o2) return NULL;
4367 
4368         obj->state = prev_state;
4369         o1 = _lv_obj_get_style_opa(obj, part, prop);
4370         obj->state = new_state;
4371         _lv_style_set_opa(style_trans, prop, o1);   /*Be sure `trans_style` has a valid value */
4372 
4373         tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll));
4374         LV_ASSERT_MEM(tr);
4375         if(tr == NULL) return NULL;
4376         tr->start_value._opa = o1;
4377         tr->end_value._opa = o2;
4378     }
4379     else {      /*Ptr*/
4380         obj->state = prev_state;
4381         style_list->skip_trans = 1;
4382         style_list->ignore_cache = 1;
4383         const void * p1 = _lv_obj_get_style_ptr(obj, part, prop);
4384         obj->state = new_state;
4385         const void * p2 = _lv_obj_get_style_ptr(obj, part, prop);
4386         style_list->skip_trans = 0;
4387         style_list->ignore_cache = cahche_ori;
4388 
4389         if(memcmp(&p1, &p2, sizeof(const void *)) == 0)  return NULL;
4390         obj->state = prev_state;
4391         p1 = _lv_obj_get_style_ptr(obj, part, prop);
4392         obj->state = new_state;
4393         _lv_style_set_ptr(style_trans, prop, p1);   /*Be sure `trans_style` has a valid value */
4394 
4395         tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll));
4396         LV_ASSERT_MEM(tr);
4397         if(tr == NULL) return NULL;
4398         tr->start_value._ptr = p1;
4399         tr->end_value._ptr = p2;
4400     }
4401 
4402     return tr;
4403 }
4404 
4405 /**
4406  * Remove the transition from object's part's property.
4407  * - Remove the transition from `_lv_obj_style_trans_ll` and free it
4408  * - Delete pending transitions
4409  * @param obj pointer to an object which transition(s) should be removed
4410  * @param part a part of object or 0xFF to remove from all parts
4411  * @param prop a property or 0xFF to remove all properties
4412  * @param tr_limit delete transitions only "older" then this. `NULL` is not used
4413  */
4414 static void trans_del(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_style_trans_t * tr_limit)
4415 {
4416     lv_style_trans_t * tr;
4417     lv_style_trans_t * tr_prev;
4418     tr = _lv_ll_get_tail(&LV_GC_ROOT(_lv_obj_style_trans_ll));
4419     while(tr != NULL) {
4420         if(tr == tr_limit) break;
4421 
4422         /*'tr' might be deleted, so get the next object while 'tr' is valid*/
4423         tr_prev = _lv_ll_get_prev(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr);
4424 
4425         if(tr->obj == obj && (part == tr->part || part == 0xFF) && (prop == tr->prop || prop == 0xFF)) {
4426             /* Remove the transitioned property from trans. style
4427              * to allow changing it by normal styles*/
4428             lv_style_list_t * list = lv_obj_get_style_list(tr->obj, tr->part);
4429             lv_style_t * style_trans = _lv_style_list_get_transition_style(list);
4430             lv_style_remove_prop(style_trans, tr->prop);
4431 
4432             lv_anim_del(tr, NULL);
4433             _lv_ll_remove(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr);
4434             lv_mem_free(tr);
4435         }
4436         tr = tr_prev;
4437     }
4438 }
4439 
4440 static void trans_anim_cb(lv_style_trans_t * tr, lv_anim_value_t v)
4441 {
4442     lv_style_list_t * list = lv_obj_get_style_list(tr->obj, tr->part);
4443     lv_style_t * style = _lv_style_list_get_transition_style(list);
4444 
4445     if((tr->prop & 0xF) < LV_STYLE_ID_COLOR) { /*Value*/
4446         lv_style_int_t x;
4447         if(v == 0) x = tr->start_value._int;
4448         else if(v == 255) x = tr->end_value._int;
4449         else x = tr->start_value._int + ((int32_t)((int32_t)(tr->end_value._int - tr->start_value._int) * v) >> 8);
4450         _lv_style_set_int(style, tr->prop, x);
4451     }
4452     else if((tr->prop & 0xF) < LV_STYLE_ID_OPA) { /*Color*/
4453         lv_color_t x;
4454         if(v <= 0) x = tr->start_value._color;
4455         else if(v >= 255) x = tr->end_value._color;
4456         else x = lv_color_mix(tr->end_value._color, tr->start_value._color, v);
4457         _lv_style_set_color(style, tr->prop, x);
4458     }
4459     else if((tr->prop & 0xF) < LV_STYLE_ID_PTR) { /*Opa*/
4460         lv_opa_t x;
4461         if(v <= 0) x = tr->start_value._opa;
4462         else if(v >= 255) x = tr->end_value._opa;
4463         else x = tr->start_value._opa + (((tr->end_value._opa - tr->start_value._opa) * v) >> 8);
4464         _lv_style_set_opa(style, tr->prop, x);
4465     }
4466     else {
4467         const void * x;
4468         if(v < 128) x = tr->start_value._ptr;
4469         else x = tr->end_value._ptr;
4470         _lv_style_set_ptr(style, tr->prop, x);
4471     }
4472     lv_obj_refresh_style(tr->obj, tr->part, tr->prop);
4473 
4474 }
4475 
4476 static void trans_anim_start_cb(lv_anim_t * a)
4477 {
4478     lv_style_trans_t * tr = a->var;
4479 
4480     lv_style_property_t prop_tmp = tr->prop;
4481 
4482     /*Start the animation from the current value*/
4483     if((prop_tmp & 0xF) < LV_STYLE_ID_COLOR) { /*Int*/
4484         tr->start_value._int = _lv_obj_get_style_int(tr->obj, tr->part, prop_tmp);
4485     }
4486     else if((prop_tmp & 0xF) < LV_STYLE_ID_OPA) { /*Color*/
4487         tr->start_value._color = _lv_obj_get_style_color(tr->obj, tr->part, prop_tmp);
4488     }
4489     else if((prop_tmp & 0xF) < LV_STYLE_ID_PTR) { /*Opa*/
4490         tr->start_value._opa = _lv_obj_get_style_opa(tr->obj, tr->part, prop_tmp);
4491     }
4492     else {      /*Ptr*/
4493         tr->start_value._ptr = _lv_obj_get_style_ptr(tr->obj, tr->part, prop_tmp);
4494     }
4495 
4496     /*Init prop to an invalid values to be sure `trans_del` won't delete this added `tr`*/
4497     tr->prop = 0;
4498     /*Delete the relate transition if any*/
4499     trans_del(tr->obj, tr->part, prop_tmp, tr);
4500 
4501     tr->prop = prop_tmp;
4502 
4503 }
4504 
4505 static void trans_anim_ready_cb(lv_anim_t * a)
4506 {
4507     lv_style_trans_t * tr = a->var;
4508 
4509     /* Remove the transitioned property from trans. style
4510      * if there no more transitions for this property
4511      * It allows changing it by normal styles*/
4512 
4513     bool running = false;
4514     lv_style_trans_t * tr_i;
4515     _LV_LL_READ(LV_GC_ROOT(_lv_obj_style_trans_ll), tr_i) {
4516         if(tr_i != tr && tr_i->obj == tr->obj && tr_i->part == tr->part && tr_i->prop == tr->prop) {
4517             running = true;
4518         }
4519     }
4520 
4521     if(!running) {
4522         lv_style_list_t * list = lv_obj_get_style_list(tr->obj, tr->part);
4523         lv_style_t * style_trans = _lv_style_list_get_transition_style(list);
4524         lv_style_remove_prop(style_trans, tr->prop);
4525     }
4526 
4527     _lv_ll_remove(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr);
4528     lv_mem_free(tr);
4529 }
4530 
4531 static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v)
4532 {
4533     lv_obj_set_style_local_opa_scale(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, v);
4534 }
4535 
4536 static void fade_in_anim_ready(lv_anim_t * a)
4537 {
4538     lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
4539 }
4540 
4541 #endif
4542 
4543 static void lv_event_mark_deleted(lv_obj_t * obj)
4544 {
4545     lv_event_temp_data_t * t = event_temp_data_head;
4546 
4547     while(t) {
4548         if(t->obj == obj) t->deleted = true;
4549         t = t->prev;
4550     }
4551 }
4552 
4553 static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find)
4554 {
4555     /*Check all children of `parent`*/
4556     lv_obj_t * child;
4557     _LV_LL_READ(parent->child_ll, child) {
4558         if(child == obj_to_find) return true;
4559 
4560         /*Check the children*/
4561         bool found = obj_valid_child(child, obj_to_find);
4562         if(found) return true;
4563     }
4564 
4565     return false;
4566 }
4567 
4568 static bool style_prop_is_cacheble(lv_style_property_t prop)
4569 {
4570 
4571     switch(prop) {
4572         case LV_STYLE_PROP_ALL:
4573         case LV_STYLE_CLIP_CORNER:
4574         case LV_STYLE_TEXT_LETTER_SPACE:
4575         case LV_STYLE_TEXT_LINE_SPACE:
4576         case LV_STYLE_TEXT_FONT:
4577         case LV_STYLE_TRANSFORM_ANGLE:
4578         case LV_STYLE_TRANSFORM_WIDTH:
4579         case LV_STYLE_TRANSFORM_HEIGHT:
4580         case LV_STYLE_TRANSFORM_ZOOM:
4581         case LV_STYLE_BORDER_WIDTH:
4582         case LV_STYLE_OUTLINE_WIDTH:
4583         case LV_STYLE_RADIUS:
4584         case LV_STYLE_SHADOW_WIDTH:
4585         case LV_STYLE_OPA_SCALE:
4586         case LV_STYLE_BG_OPA:
4587         case LV_STYLE_BORDER_SIDE:
4588         case LV_STYLE_BORDER_POST:
4589         case LV_STYLE_IMAGE_RECOLOR_OPA:
4590         case LV_STYLE_VALUE_STR:
4591         case LV_STYLE_PATTERN_IMAGE:
4592         case LV_STYLE_PAD_TOP:
4593         case LV_STYLE_PAD_BOTTOM:
4594         case LV_STYLE_PAD_LEFT:
4595         case LV_STYLE_PAD_RIGHT:
4596         case LV_STYLE_MARGIN_TOP:
4597         case LV_STYLE_MARGIN_BOTTOM:
4598         case LV_STYLE_MARGIN_LEFT:
4599         case LV_STYLE_MARGIN_RIGHT:
4600         case LV_STYLE_BG_BLEND_MODE:
4601         case LV_STYLE_BORDER_BLEND_MODE:
4602         case LV_STYLE_IMAGE_BLEND_MODE:
4603         case LV_STYLE_LINE_BLEND_MODE:
4604         case LV_STYLE_OUTLINE_BLEND_MODE:
4605         case LV_STYLE_PATTERN_BLEND_MODE:
4606         case LV_STYLE_SHADOW_BLEND_MODE:
4607         case LV_STYLE_TEXT_BLEND_MODE:
4608         case LV_STYLE_VALUE_BLEND_MODE:
4609             return true;
4610             break;
4611         default:
4612             return false;
4613     }
4614 }
4615 
4616 /**
4617  * Update the cache of style list
4618  * @param obj pointer to an obejct
4619  * @param part the part of the object
4620  * @param prop the property which triggered the update
4621  */
4622 static void update_style_cache(lv_obj_t * obj, uint8_t part, uint16_t prop)
4623 {
4624     if(style_prop_is_cacheble(prop) == false) return;
4625 
4626     lv_style_list_t * list = lv_obj_get_style_list(obj, part);
4627 
4628     bool ignore_cache_ori = list->ignore_cache;
4629     list->ignore_cache = 1;
4630 
4631 #if LV_USE_OPA_SCALE
4632     list->opa_scale_cover    = lv_obj_get_style_opa_scale(obj, part) == LV_OPA_COVER ? 1 : 0;
4633 #else
4634     list->opa_scale_cover    = 1;
4635 #endif
4636     list->text_decor_none    = lv_obj_get_style_text_decor(obj, part) == LV_TEXT_DECOR_NONE ? 1 : 0;
4637     list->text_font_normal    = lv_obj_get_style_text_font(obj, part) == LV_THEME_DEFAULT_FONT_NORMAL ? 1 : 0;
4638 
4639     list->text_space_zero = 1;
4640     if(lv_obj_get_style_text_letter_space(obj, part) != 0 ||
4641        lv_obj_get_style_text_line_space(obj, part) != 0) {
4642         list->text_space_zero = 0;
4643     }
4644 
4645 
4646     lv_opa_t bg_opa = lv_obj_get_style_bg_opa(obj, part);
4647     list->bg_opa_transp    = bg_opa == LV_OPA_TRANSP ? 1 : 0;
4648     list->bg_opa_cover     = bg_opa == LV_OPA_COVER ? 1 : 0;
4649 
4650     list->border_width_zero = lv_obj_get_style_border_width(obj, part) == 0 ? 1 : 0;
4651     list->border_side_full = lv_obj_get_style_border_side(obj, part) == LV_BORDER_SIDE_FULL ? 1 : 0;
4652     list->border_post_off = lv_obj_get_style_border_post(obj, part) == 0 ? 1 : 0;
4653     list->clip_corner_off   = lv_obj_get_style_clip_corner(obj, part) == false ? 1 : 0;
4654     list->img_recolor_opa_transp    = lv_obj_get_style_image_recolor_opa(obj, part) == LV_OPA_TRANSP ? 1 : 0;
4655     list->outline_width_zero    = lv_obj_get_style_outline_width(obj, part) == 0 ? 1 : 0;
4656     list->pattern_img_null    = lv_obj_get_style_pattern_image(obj, part) == NULL ? 1 : 0;
4657     list->radius_zero    = lv_obj_get_style_radius(obj, part) == 0 ? 1 : 0;
4658     list->shadow_width_zero    = lv_obj_get_style_shadow_width(obj, part) == 0 ? 1 : 0;
4659     list->value_txt_str    = lv_obj_get_style_value_str(obj, part) == NULL ? 1 : 0;
4660 
4661 
4662     list->transform_all_zero  = 1;
4663     if(lv_obj_get_style_transform_angle(obj, part) != 0 ||
4664        lv_obj_get_style_transform_width(obj, part) != 0 ||
4665        lv_obj_get_style_transform_height(obj, part) != 0 ||
4666        lv_obj_get_style_transform_zoom(obj, part) != LV_IMG_ZOOM_NONE) {
4667         list->transform_all_zero  = 0;
4668     }
4669 
4670     list->pad_all_zero  = 1;
4671     if(lv_obj_get_style_pad_top(obj, part) != 0 ||
4672        lv_obj_get_style_pad_bottom(obj, part) != 0 ||
4673        lv_obj_get_style_pad_left(obj, part) != 0 ||
4674        lv_obj_get_style_pad_right(obj, part) != 0) {
4675         list->pad_all_zero  = 0;
4676     }
4677 
4678     list->margin_all_zero  = 1;
4679     if(lv_obj_get_style_margin_top(obj, part) != 0 ||
4680        lv_obj_get_style_margin_bottom(obj, part) != 0 ||
4681        lv_obj_get_style_margin_left(obj, part) != 0 ||
4682        lv_obj_get_style_margin_right(obj, part) != 0) {
4683         list->margin_all_zero  = 0;
4684     }
4685 
4686     list->blend_mode_all_normal = 1;
4687 #if LV_USE_BLEND_MODES
4688     if(lv_obj_get_style_bg_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL ||
4689        lv_obj_get_style_border_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL ||
4690        lv_obj_get_style_pattern_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL ||
4691        lv_obj_get_style_outline_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL ||
4692        lv_obj_get_style_value_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL ||
4693        lv_obj_get_style_text_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL ||
4694        lv_obj_get_style_line_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL ||
4695        lv_obj_get_style_image_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL ||
4696        lv_obj_get_style_shadow_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL) {
4697         list->blend_mode_all_normal = 0;
4698     }
4699 #endif
4700     list->ignore_cache = ignore_cache_ori;
4701     list->valid_cache = 1;
4702 }
4703 
4704 /**
4705  * Update the cache of style list
4706  * @param obj pointer to an object
4707  * @param part the part of the object
4708  */
4709 static void update_style_cache_children(lv_obj_t * obj)
4710 {
4711     uint8_t part;
4712     for(part = 0; part != _LV_OBJ_PART_REAL_LAST; part++) {
4713         lv_style_list_t * list = lv_obj_get_style_list(obj, part);
4714         if(list == NULL) break;
4715 
4716         bool ignore_cache_ori = list->ignore_cache;
4717         list->ignore_cache = 1;
4718 
4719         list->opa_scale_cover    = lv_obj_get_style_opa_scale(obj, part) == LV_OPA_COVER ? 1 : 0;
4720         list->text_decor_none    = lv_obj_get_style_text_decor(obj, part) == LV_TEXT_DECOR_NONE ? 1 : 0;
4721         list->text_font_normal    = lv_obj_get_style_text_font(obj, part) == lv_theme_get_font_normal() ? 1 : 0;
4722         list->img_recolor_opa_transp    = lv_obj_get_style_image_recolor_opa(obj, part) == LV_OPA_TRANSP ? 1 : 0;
4723 
4724         list->text_space_zero = 1;
4725         if(lv_obj_get_style_text_letter_space(obj, part) != 0 ||
4726            lv_obj_get_style_text_line_space(obj, part) != 0) {
4727             list->text_space_zero = 0;
4728         }
4729 
4730         list->ignore_cache = ignore_cache_ori;
4731     }
4732 
4733     lv_obj_t * child = lv_obj_get_child(obj, NULL);
4734     while(child) {
4735         update_style_cache_children(child);
4736         child = lv_obj_get_child(obj, child);
4737     }
4738 
4739 }
4740 
4741 /**
4742  * Mark the object and all of it's children's style lists as invalid.
4743  * The cache will be updated when a cached property asked nest time
4744  * @param obj pointer to an object
4745  */
4746 static void invalidate_style_cache(lv_obj_t * obj, uint8_t part, lv_style_property_t prop)
4747 {
4748     if(style_prop_is_cacheble(prop) == false) return;
4749 
4750     if(part != LV_OBJ_PART_ALL) {
4751         lv_style_list_t * list = lv_obj_get_style_list(obj, part);
4752         if(list == NULL) return;
4753         list->valid_cache = 0;
4754     }
4755     else {
4756 
4757         for(part = 0; part < _LV_OBJ_PART_REAL_FIRST; part++) {
4758             lv_style_list_t * list = lv_obj_get_style_list(obj, part);
4759             if(list == NULL) break;
4760             list->valid_cache = 0;
4761         }
4762         for(part = _LV_OBJ_PART_REAL_FIRST; part < 0xFF; part++) {
4763             lv_style_list_t * list = lv_obj_get_style_list(obj, part);
4764             if(list == NULL) break;
4765             list->valid_cache = 0;
4766         }
4767     }
4768 
4769     lv_obj_t * child = lv_obj_get_child(obj, NULL);
4770     while(child) {
4771         update_style_cache_children(child);
4772         child = lv_obj_get_child(obj, child);
4773     }
4774 }
4775 
4776 static void style_snapshot(lv_obj_t * obj, uint8_t part, style_snapshot_t * shot)
4777 {
4778     _lv_obj_disable_style_caching(obj, true);
4779     _lv_memset_00(shot, sizeof(style_snapshot_t));
4780     lv_draw_rect_dsc_init(&shot->rect);
4781     lv_draw_label_dsc_init(&shot->label);
4782     lv_draw_img_dsc_init(&shot->img);
4783     lv_draw_line_dsc_init(&shot->line);
4784 
4785     lv_style_list_t * list = lv_obj_get_style_list(obj, part);
4786     bool trans_ori = list->skip_trans;
4787     list->skip_trans = 1;
4788 
4789     lv_obj_init_draw_rect_dsc(obj, part, &shot->rect);
4790     lv_obj_init_draw_label_dsc(obj, part, &shot->label);
4791     lv_obj_init_draw_img_dsc(obj, part, &shot->img);
4792     lv_obj_init_draw_line_dsc(obj, part, &shot->line);
4793 
4794 
4795     shot->pad_top = lv_obj_get_style_pad_top(obj, part);
4796     shot->pad_bottom = lv_obj_get_style_pad_bottom(obj, part);
4797     shot->pad_right = lv_obj_get_style_pad_right(obj, part);
4798     shot->pad_left = lv_obj_get_style_pad_left(obj, part);
4799     shot->pad_inner = lv_obj_get_style_pad_inner(obj, part);
4800     shot->margin_top = lv_obj_get_style_margin_top(obj, part);
4801     shot->margin_bottom = lv_obj_get_style_margin_bottom(obj, part);
4802     shot->margin_left = lv_obj_get_style_margin_left(obj, part);
4803     shot->margin_right = lv_obj_get_style_margin_right(obj, part);
4804     shot->size = lv_obj_get_style_size(obj, part);
4805     shot->transform_width = lv_obj_get_style_transform_width(obj, part);
4806     shot->transform_height = lv_obj_get_style_transform_height(obj, part);
4807     shot->transform_angle = lv_obj_get_style_transform_angle(obj, part);
4808     shot->transform_zoom = lv_obj_get_style_transform_zoom(obj, part);
4809     shot->scale_width = lv_obj_get_style_scale_width(obj, part);
4810     shot->scale_border_width = lv_obj_get_style_scale_border_width(obj, part);
4811     shot->scale_end_border_width = lv_obj_get_style_scale_end_border_width(obj, part);
4812     shot->scale_end_line_width = lv_obj_get_style_scale_end_line_width(obj, part);
4813     shot->scale_grad_color = lv_obj_get_style_scale_grad_color(obj, part);
4814     shot->scale_end_color = lv_obj_get_style_scale_end_color(obj, part);
4815     shot->opa_scale = lv_obj_get_style_opa_scale(obj, part);
4816     shot->clip_corder = lv_obj_get_style_clip_corner(obj, part);
4817     shot->border_post  = lv_obj_get_style_border_post(obj, part);
4818 
4819     _lv_obj_disable_style_caching(obj, false);
4820     list->skip_trans = trans_ori;
4821 }
4822 
4823 static style_snapshot_res_t style_snapshot_compare(style_snapshot_t * shot1, style_snapshot_t * shot2)
4824 {
4825     if(memcmp(shot1, shot2, sizeof(style_snapshot_t)) == 0) return STYLE_COMPARE_SAME;
4826 
4827 
4828     if(shot1->pad_top != shot2->pad_top) return STYLE_COMPARE_DIFF;
4829     if(shot1->pad_bottom != shot2->pad_bottom) return STYLE_COMPARE_DIFF;
4830     if(shot1->pad_left != shot2->pad_right) return STYLE_COMPARE_DIFF;
4831     if(shot1->pad_right != shot2->pad_right) return STYLE_COMPARE_DIFF;
4832     if(shot1->pad_top != shot2->pad_top) return STYLE_COMPARE_DIFF;
4833     if(shot1->pad_inner != shot2->pad_inner) return STYLE_COMPARE_DIFF;
4834     if(shot1->margin_top != shot2->margin_top) return STYLE_COMPARE_DIFF;
4835     if(shot1->margin_bottom != shot2->margin_bottom) return STYLE_COMPARE_DIFF;
4836     if(shot1->margin_left != shot2->margin_right) return STYLE_COMPARE_DIFF;
4837     if(shot1->margin_right != shot2->margin_right) return STYLE_COMPARE_DIFF;
4838     if(shot1->margin_top != shot2->margin_top) return STYLE_COMPARE_DIFF;
4839     if(shot1->transform_width != shot2->transform_width) return STYLE_COMPARE_DIFF;
4840     if(shot1->transform_height != shot2->transform_height) return STYLE_COMPARE_DIFF;
4841     if(shot1->transform_angle != shot2->transform_angle) return STYLE_COMPARE_DIFF;
4842     if(shot1->transform_zoom != shot2->transform_zoom) return STYLE_COMPARE_DIFF;
4843     if(shot1->rect.outline_width != shot2->rect.outline_width) return STYLE_COMPARE_DIFF;
4844     if(shot1->rect.outline_pad != shot2->rect.outline_pad) return STYLE_COMPARE_DIFF;
4845     if(shot1->rect.value_font != shot2->rect.value_font) return STYLE_COMPARE_DIFF;
4846     if(shot1->rect.value_align != shot2->rect.value_align) return STYLE_COMPARE_DIFF;
4847     if(shot1->rect.value_font != shot2->rect.value_font) return STYLE_COMPARE_DIFF;
4848     if(shot1->rect.shadow_spread != shot2->rect.shadow_spread) return STYLE_COMPARE_DIFF;
4849     if(shot1->rect.shadow_width != shot2->rect.shadow_width) return STYLE_COMPARE_DIFF;
4850     if(shot1->rect.shadow_ofs_x != shot2->rect.shadow_ofs_x) return STYLE_COMPARE_DIFF;
4851     if(shot1->rect.shadow_ofs_y != shot2->rect.shadow_ofs_y) return STYLE_COMPARE_DIFF;
4852 
4853     /*If not returned earlier its just a visual difference, a simple redraw is enough*/
4854     return STYLE_COMPARE_VISUAL_DIFF;
4855 }
4856