1 /**
2  * @file lv_base_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_themes/lv_theme.h"
15 #include "../lv_draw/lv_draw.h"
16 #include "../lv_misc/lv_anim.h"
17 #include "../lv_misc/lv_task.h"
18 #include "../lv_misc/lv_async.h"
19 #include "../lv_misc/lv_fs.h"
20 #include "../lv_hal/lv_hal.h"
21 #include <stdint.h>
22 #include <string.h>
23 #include "../lv_misc/lv_gc.h"
24 
25 #if defined(LV_GC_INCLUDE)
26 #include LV_GC_INCLUDE
27 #endif /* LV_ENABLE_GC */
28 
29 /*********************
30  *      DEFINES
31  *********************/
32 #define LV_OBJ_DEF_WIDTH (LV_DPI)
33 #define LV_OBJ_DEF_HEIGHT (2 * LV_DPI / 3)
34 
35 /**********************
36  *      TYPEDEFS
37  **********************/
38 typedef struct _lv_event_temp_data
39 {
40     lv_obj_t * obj;
41     bool deleted;
42     struct _lv_event_temp_data * prev;
43 } lv_event_temp_data_t;
44 
45 /**********************
46  *  STATIC PROTOTYPES
47  **********************/
48 static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff);
49 static void report_style_mod_core(void * style_p, lv_obj_t * obj);
50 static void refresh_children_style(lv_obj_t * obj);
51 static void delete_children(lv_obj_t * obj);
52 static void lv_event_mark_deleted(lv_obj_t * obj);
53 static void lv_obj_del_async_cb(void * obj);
54 static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode);
55 static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param);
56 
57 /**********************
58  *  STATIC VARIABLES
59  **********************/
60 static bool lv_initialized = false;
61 static lv_event_temp_data_t * event_temp_data_head;
62 static const void * event_act_data;
63 
64 /**********************
65  *      MACROS
66  **********************/
67 
68 /**********************
69  *   GLOBAL FUNCTIONS
70  **********************/
71 
72 /**
73  * Init. the 'lv' library.
74  */
lv_init(void)75 void lv_init(void)
76 {
77     /* Do nothing if already initialized */
78     if(lv_initialized) {
79         LV_LOG_WARN("lv_init: already inited");
80         return;
81     }
82 
83     LV_LOG_TRACE("lv_init started");
84 
85     /*Initialize the lv_misc modules*/
86     lv_mem_init();
87     lv_task_core_init();
88 
89 #if LV_USE_FILESYSTEM
90     lv_fs_init();
91 #endif
92 
93 #if LV_USE_ANIMATION
94     lv_anim_core_init();
95 #endif
96 
97 #if LV_USE_GROUP
98     lv_group_init();
99 #endif
100 
101     /*Init. the sstyles*/
102     lv_style_init();
103 
104     /*Initialize the screen refresh system*/
105     lv_refr_init();
106 
107     lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t));
108     lv_ll_init(&LV_GC_ROOT(_lv_indev_ll), sizeof(lv_indev_t));
109 
110     /*Init the input device handling*/
111     lv_indev_init();
112 
113     lv_img_decoder_init();
114     lv_img_cache_set_size(LV_IMG_CACHE_DEF_SIZE);
115 
116     lv_initialized = true;
117     LV_LOG_INFO("lv_init ready");
118 }
119 
120 /*--------------------
121  * Create and delete
122  *-------------------*/
123 
124 /**
125  * Create a basic object
126  * @param parent pointer to a parent object.
127  *                  If NULL then a screen will be created
128  * @param copy pointer to a base object, if not NULL then the new object will be copied from it
129  * @return pointer to the new object
130  */
lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy)131 lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
132 {
133 
134     lv_obj_t * new_obj = NULL;
135     /*Create a screen if the parent is NULL*/
136     if(parent == NULL) {
137         LV_LOG_TRACE("Screen create started");
138         lv_disp_t * disp = lv_disp_get_default();
139         if(!disp) {
140             LV_LOG_WARN("lv_obj_create: not display created to so far. No place to assign the new screen");
141             return NULL;
142         }
143 
144         new_obj = lv_ll_ins_head(&disp->scr_ll);
145         lv_mem_assert(new_obj);
146         if(new_obj == NULL) return NULL;
147 
148         new_obj->par = NULL; /*Screens has no a parent*/
149         lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t));
150 
151         /*Set coordinates to full screen size*/
152         new_obj->coords.x1    = 0;
153         new_obj->coords.y1    = 0;
154         new_obj->coords.x2    = lv_disp_get_hor_res(NULL) - 1;
155         new_obj->coords.y2    = lv_disp_get_ver_res(NULL) - 1;
156         new_obj->ext_draw_pad = 0;
157 
158 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
159         memset(&new_obj->ext_click_pad, 0, sizeof(new_obj->ext_click_pad));
160 #endif
161 
162 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
163         new_obj->ext_click_pad_hor = 0;
164         new_obj->ext_click_pad_ver = 0;
165 #endif
166 
167         /*Init realign*/
168 #if LV_USE_OBJ_REALIGN
169         new_obj->realign.align        = LV_ALIGN_CENTER;
170         new_obj->realign.xofs         = 0;
171         new_obj->realign.yofs         = 0;
172         new_obj->realign.base         = NULL;
173         new_obj->realign.auto_realign = 0;
174 #endif
175 
176         /*Set the default styles*/
177         lv_theme_t * th = lv_theme_get_current();
178         if(th) {
179             new_obj->style_p = th->style.scr;
180         } else {
181             new_obj->style_p = &lv_style_scr;
182         }
183         /*Set the callbacks*/
184         lv_obj_set_signal_cb(new_obj, lv_obj_signal);
185         lv_obj_set_design_cb(new_obj, lv_obj_design);
186         new_obj->event_cb = NULL;
187 
188         /*Init. user date*/
189 #if LV_USE_USER_DATA
190         memset(&new_obj->user_data, 0, sizeof(lv_obj_user_data_t));
191 #endif
192 
193 #if LV_USE_GROUP
194         new_obj->group_p = NULL;
195 #endif
196         /*Set attributes*/
197         new_obj->click        = 0;
198         new_obj->drag         = 0;
199         new_obj->drag_throw   = 0;
200         new_obj->drag_parent  = 0;
201         new_obj->hidden       = 0;
202         new_obj->top          = 0;
203         new_obj->protect      = LV_PROTECT_NONE;
204         new_obj->opa_scale_en = 0;
205         new_obj->opa_scale    = LV_OPA_COVER;
206         new_obj->parent_event = 0;
207         new_obj->reserved     = 0;
208 
209         new_obj->ext_attr = NULL;
210 
211         LV_LOG_INFO("Screen create ready");
212     }
213     /*parent != NULL create normal obj. on a parent*/
214     else {
215         LV_LOG_TRACE("Object create started");
216 
217         new_obj = lv_ll_ins_head(&parent->child_ll);
218         lv_mem_assert(new_obj);
219         if(new_obj == NULL) return NULL;
220 
221         new_obj->par = parent; /*Set the parent*/
222         lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t));
223 
224         /*Set coordinates left top corner of parent*/
225         new_obj->coords.x1    = parent->coords.x1;
226         new_obj->coords.y1    = parent->coords.y1;
227         new_obj->coords.x2    = parent->coords.x1 + LV_OBJ_DEF_WIDTH;
228         new_obj->coords.y2    = parent->coords.y1 + LV_OBJ_DEF_HEIGHT;
229         new_obj->ext_draw_pad = 0;
230 
231 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
232         memset(&new_obj->ext_click_pad, 0, sizeof(new_obj->ext_click_pad));
233 #endif
234 
235 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
236         new_obj->ext_click_pad_hor = 0;
237         new_obj->ext_click_pad_ver = 0;
238 #endif
239 
240         /*Init realign*/
241 #if LV_USE_OBJ_REALIGN
242         new_obj->realign.align        = LV_ALIGN_CENTER;
243         new_obj->realign.xofs         = 0;
244         new_obj->realign.yofs         = 0;
245         new_obj->realign.base         = NULL;
246         new_obj->realign.auto_realign = 0;
247 #endif
248         /*Set appearance*/
249         lv_theme_t * th = lv_theme_get_current();
250         if(th) {
251             new_obj->style_p = th->style.panel;
252         } else {
253             new_obj->style_p = &lv_style_plain_color;
254         }
255 
256         /*Set the callbacks*/
257         lv_obj_set_signal_cb(new_obj, lv_obj_signal);
258         lv_obj_set_design_cb(new_obj, lv_obj_design);
259         new_obj->event_cb = NULL;
260 
261 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
262         memset(&new_obj->ext_click_pad, 0, sizeof(new_obj->ext_click_pad));
263 #endif
264 
265 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
266         new_obj->ext_click_pad_hor = 0;
267         new_obj->ext_click_pad_ver = 0;
268 #endif
269 
270         /*Init. user date*/
271 #if LV_USE_USER_DATA
272         memset(&new_obj->user_data, 0, sizeof(lv_obj_user_data_t));
273 #endif
274 
275 #if LV_USE_GROUP
276         new_obj->group_p = NULL;
277 #endif
278 
279         /*Set attributes*/
280         new_obj->click        = 1;
281         new_obj->drag         = 0;
282         new_obj->drag_dir     = LV_DRAG_DIR_ALL;
283         new_obj->drag_throw   = 0;
284         new_obj->drag_parent  = 0;
285         new_obj->hidden       = 0;
286         new_obj->top          = 0;
287         new_obj->protect      = LV_PROTECT_NONE;
288         new_obj->opa_scale    = LV_OPA_COVER;
289         new_obj->opa_scale_en = 0;
290         new_obj->parent_event = 0;
291 
292         new_obj->ext_attr = NULL;
293     }
294 
295     /*Copy the attributes if required*/
296     if(copy != NULL) {
297         lv_area_copy(&new_obj->coords, &copy->coords);
298         new_obj->ext_draw_pad = copy->ext_draw_pad;
299 
300 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
301         lv_area_copy(&new_obj->ext_click_pad, &copy->ext_click_pad);
302 #endif
303 
304 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
305         new_obj->ext_click_pad_hor = copy->ext_click_pad_hor;
306         new_obj->ext_click_pad_ver = copy->ext_click_pad_ver;
307 #endif
308 
309         /*Set free data*/
310 #if LV_USE_USER_DATA
311         memcpy(&new_obj->user_data, &copy->user_data, sizeof(lv_obj_user_data_t));
312 #endif
313         /*Copy realign*/
314 #if LV_USE_OBJ_REALIGN
315         new_obj->realign.align        = copy->realign.align;
316         new_obj->realign.xofs         = copy->realign.xofs;
317         new_obj->realign.yofs         = copy->realign.yofs;
318         new_obj->realign.base         = copy->realign.base;
319         new_obj->realign.auto_realign = copy->realign.auto_realign;
320 #endif
321 
322         /*Only copy the `event_cb`. `signal_cb` and `design_cb` will be copied the the derived
323          * object type (e.g. `lv_btn`)*/
324         new_obj->event_cb = copy->event_cb;
325 
326         /*Copy attributes*/
327         new_obj->click        = copy->click;
328         new_obj->drag         = copy->drag;
329         new_obj->drag_dir     = copy->drag_dir;
330         new_obj->drag_throw   = copy->drag_throw;
331         new_obj->drag_parent  = copy->drag_parent;
332         new_obj->hidden       = copy->hidden;
333         new_obj->top          = copy->top;
334         new_obj->parent_event = copy->parent_event;
335 
336         new_obj->opa_scale_en = copy->opa_scale_en;
337         new_obj->protect      = copy->protect;
338         new_obj->opa_scale    = copy->opa_scale;
339 
340         new_obj->style_p = copy->style_p;
341 
342 #if LV_USE_GROUP
343         /*Add to the same group*/
344         if(copy->group_p != NULL) {
345             lv_group_add_obj(copy->group_p, new_obj);
346         }
347 #endif
348 
349         /*Set the same coordinates for non screen objects*/
350         if(lv_obj_get_parent(copy) != NULL && parent != NULL) {
351             lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy));
352         } else {
353             lv_obj_set_pos(new_obj, 0, 0);
354         }
355 
356         LV_LOG_INFO("Object create ready");
357     }
358 
359     /*Send a signal to the parent to notify it about the new child*/
360     if(parent != NULL) {
361         parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, new_obj);
362 
363         /*Invalidate the area if not screen created*/
364         lv_obj_invalidate(new_obj);
365     }
366 
367     return new_obj;
368 }
369 
370 /**
371  * Delete 'obj' and all of its children
372  * @param obj pointer to an object to delete
373  * @return LV_RES_INV because the object is deleted
374  */
lv_obj_del(lv_obj_t * obj)375 lv_res_t lv_obj_del(lv_obj_t * obj)
376 {
377     lv_obj_invalidate(obj);
378 
379     /*Delete from the group*/
380 #if LV_USE_GROUP
381     lv_group_t * group = lv_obj_get_group(obj);
382     if(group) lv_group_remove_obj(obj);
383 #endif
384 
385         /*Remove the animations from this object*/
386 #if LV_USE_ANIMATION
387     lv_anim_del(obj, NULL);
388 #endif
389 
390     /*Recursively delete the children*/
391     lv_obj_t * i;
392     lv_obj_t * i_next;
393     i = lv_ll_get_head(&(obj->child_ll));
394     while(i != NULL) {
395         /*Get the next object before delete this*/
396         i_next = lv_ll_get_next(&(obj->child_ll), i);
397 
398         /*Call the recursive del to the child too*/
399         delete_children(i);
400 
401         /*Set i to the next node*/
402         i = i_next;
403     }
404 
405     /*Let the user free the resources used in `LV_EVENT_DELETE`*/
406     lv_event_send(obj, LV_EVENT_DELETE, NULL);
407 
408     lv_event_mark_deleted(obj);
409 
410     /*Remove the object from parent's children list*/
411     lv_obj_t * par = lv_obj_get_parent(obj);
412     if(par == NULL) { /*It is a screen*/
413         lv_disp_t * d = lv_obj_get_disp(obj);
414         lv_ll_rem(&d->scr_ll, obj);
415     } else {
416         lv_ll_rem(&(par->child_ll), obj);
417     }
418 
419     /* Reset all input devices if the object to delete is used*/
420     lv_indev_t * indev = lv_indev_get_next(NULL);
421     while(indev) {
422         if(indev->proc.types.pointer.act_obj == obj || indev->proc.types.pointer.last_obj == obj) {
423             lv_indev_reset(indev);
424         }
425         if(indev->proc.types.pointer.last_pressed == obj) {
426             indev->proc.types.pointer.last_pressed = NULL;
427         }
428 
429 #if LV_USE_GROUP
430         if(indev->group == group && obj == lv_indev_get_obj_act()) {
431             lv_indev_reset(indev);
432         }
433 #endif
434         indev = lv_indev_get_next(indev);
435     }
436 
437     /* All children deleted.
438      * Now clean up the object specific data*/
439     obj->signal_cb(obj, LV_SIGNAL_CLEANUP, NULL);
440 
441     /*Delete the base objects*/
442     if(obj->ext_attr != NULL) lv_mem_free(obj->ext_attr);
443     lv_mem_free(obj); /*Free the object itself*/
444 
445     /*Send a signal to the parent to notify it about the child delete*/
446     if(par != NULL) {
447         par->signal_cb(par, LV_SIGNAL_CHILD_CHG, NULL);
448     }
449 
450     return LV_RES_INV;
451 }
452 
453 /**
454  * Helper function for asynchronously deleting objects.
455  * Useful for cases where you can't delete an object directly in an `LV_EVENT_DELETE` handler (i.e. parent).
456  * @param obj object to delete
457  * @see lv_async_call
458  */
lv_obj_del_async(lv_obj_t * obj)459 void lv_obj_del_async(lv_obj_t * obj)
460 {
461     lv_async_call(lv_obj_del_async_cb, obj);
462 }
463 
464 /**
465  * Delete all children of an object
466  * @param obj pointer to an object
467  */
lv_obj_clean(lv_obj_t * obj)468 void lv_obj_clean(lv_obj_t * obj)
469 {
470     lv_obj_t * child = lv_obj_get_child(obj, NULL);
471     lv_obj_t * child_next;
472     while(child) {
473         /* Read the next child before deleting the current
474          * because the next couldn't be read from a deleted (invalid) node*/
475         child_next = lv_obj_get_child(obj, child);
476         lv_obj_del(child);
477         child = child_next;
478     }
479 }
480 
481 /**
482  * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task'
483  * @param obj pointer to an object
484  */
lv_obj_invalidate(const lv_obj_t * obj)485 void lv_obj_invalidate(const lv_obj_t * obj)
486 {
487     if(lv_obj_get_hidden(obj)) return;
488 
489     /*Invalidate the object only if it belongs to the 'LV_GC_ROOT(_lv_act_scr)'*/
490     lv_obj_t * obj_scr = lv_obj_get_screen(obj);
491     lv_disp_t * disp   = lv_obj_get_disp(obj_scr);
492     if(obj_scr == lv_disp_get_scr_act(disp) || obj_scr == lv_disp_get_layer_top(disp) ||
493        obj_scr == lv_disp_get_layer_sys(disp)) {
494         /*Truncate recursively to the parents*/
495         lv_area_t area_trunc;
496         lv_obj_t * par = lv_obj_get_parent(obj);
497         bool union_ok  = true;
498         /*Start with the original coordinates*/
499         lv_coord_t ext_size = obj->ext_draw_pad;
500         lv_area_copy(&area_trunc, &obj->coords);
501         area_trunc.x1 -= ext_size;
502         area_trunc.y1 -= ext_size;
503         area_trunc.x2 += ext_size;
504         area_trunc.y2 += ext_size;
505 
506         /*Check through all parents*/
507         while(par != NULL) {
508             union_ok = lv_area_intersect(&area_trunc, &area_trunc, &par->coords);
509             if(union_ok == false) break;       /*If no common parts with parent break;*/
510             if(lv_obj_get_hidden(par)) return; /*If the parent is hidden then the child is hidden and won't be drawn*/
511 
512             par = lv_obj_get_parent(par);
513         }
514 
515         if(union_ok) lv_inv_area(disp, &area_trunc);
516     }
517 }
518 
519 /*=====================
520  * Setter functions
521  *====================*/
522 
523 /*--------------------
524  * Parent/children set
525  *--------------------*/
526 
527 /**
528  * Set a new parent for an object. Its relative position will be the same.
529  * @param obj pointer to an object. Can't be a screen.
530  * @param parent pointer to the new parent object. (Can't be NULL)
531  */
lv_obj_set_parent(lv_obj_t * obj,lv_obj_t * parent)532 void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent)
533 {
534     if(obj->par == NULL) {
535         LV_LOG_WARN("Can't set the parent of a screen");
536         return;
537     }
538 
539     if(parent == NULL) {
540         LV_LOG_WARN("Can't set parent == NULL to an object");
541         return;
542     }
543 
544     lv_obj_invalidate(obj);
545 
546     lv_point_t old_pos;
547     old_pos.x = lv_obj_get_x(obj);
548     old_pos.y = lv_obj_get_y(obj);
549 
550     lv_obj_t * old_par = obj->par;
551 
552     lv_ll_chg_list(&obj->par->child_ll, &parent->child_ll, obj, true);
553     obj->par = parent;
554     lv_obj_set_pos(obj, old_pos.x, old_pos.y);
555 
556     /*Notify the original parent because one of its children is lost*/
557     old_par->signal_cb(old_par, LV_SIGNAL_CHILD_CHG, NULL);
558 
559     /*Notify the new parent about the child*/
560     parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj);
561 
562     lv_obj_invalidate(obj);
563 }
564 
565 /**
566  * Move and object to the foreground
567  * @param obj pointer to an object
568  */
lv_obj_move_foreground(lv_obj_t * obj)569 void lv_obj_move_foreground(lv_obj_t * obj)
570 {
571     lv_obj_t * parent = lv_obj_get_parent(obj);
572 
573     /*Do nothing of already in the foreground*/
574     if(lv_ll_get_head(&parent->child_ll) == obj) return;
575 
576     lv_obj_invalidate(parent);
577 
578     lv_ll_chg_list(&parent->child_ll, &parent->child_ll, obj, true);
579 
580     /*Notify the new parent about the child*/
581     parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj);
582 
583     lv_obj_invalidate(parent);
584 }
585 
586 /**
587  * Move and object to the background
588  * @param obj pointer to an object
589  */
lv_obj_move_background(lv_obj_t * obj)590 void lv_obj_move_background(lv_obj_t * obj)
591 {
592     lv_obj_t * parent = lv_obj_get_parent(obj);
593 
594     /*Do nothing of already in the background*/
595     if(lv_ll_get_tail(&parent->child_ll) == obj) return;
596 
597     lv_obj_invalidate(parent);
598 
599     lv_ll_chg_list(&parent->child_ll, &parent->child_ll, obj, false);
600 
601     /*Notify the new parent about the child*/
602     parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj);
603 
604     lv_obj_invalidate(parent);
605 }
606 
607 /*--------------------
608  * Coordinate set
609  * ------------------*/
610 
611 /**
612  * Set relative the position of an object (relative to the parent)
613  * @param obj pointer to an object
614  * @param x new distance from the left side of the parent
615  * @param y new distance from the top of the parent
616  */
lv_obj_set_pos(lv_obj_t * obj,lv_coord_t x,lv_coord_t y)617 void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
618 {
619     /*Convert x and y to absolute coordinates*/
620     lv_obj_t * par = obj->par;
621 
622     x = x + par->coords.x1;
623     y = y + par->coords.y1;
624 
625     /*Calculate and set the movement*/
626     lv_point_t diff;
627     diff.x = x - obj->coords.x1;
628     diff.y = y - obj->coords.y1;
629 
630     /* Do nothing if the position is not changed */
631     /* It is very important else recursive positioning can
632      * occur without position change*/
633     if(diff.x == 0 && diff.y == 0) return;
634 
635     /*Invalidate the original area*/
636     lv_obj_invalidate(obj);
637 
638     /*Save the original coordinates*/
639     lv_area_t ori;
640     lv_obj_get_coords(obj, &ori);
641 
642     obj->coords.x1 += diff.x;
643     obj->coords.y1 += diff.y;
644     obj->coords.x2 += diff.x;
645     obj->coords.y2 += diff.y;
646 
647     refresh_children_position(obj, diff.x, diff.y);
648 
649     /*Inform the object about its new coordinates*/
650     obj->signal_cb(obj, LV_SIGNAL_CORD_CHG, &ori);
651 
652     /*Send a signal to the parent too*/
653     par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj);
654 
655     /*Invalidate the new area*/
656     lv_obj_invalidate(obj);
657 }
658 
659 /**
660  * Set the x coordinate of a object
661  * @param obj pointer to an object
662  * @param x new distance from the left side from the parent
663  */
lv_obj_set_x(lv_obj_t * obj,lv_coord_t x)664 void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x)
665 {
666     lv_obj_set_pos(obj, x, lv_obj_get_y(obj));
667 }
668 
669 /**
670  * Set the y coordinate of a object
671  * @param obj pointer to an object
672  * @param y new distance from the top of the parent
673  */
lv_obj_set_y(lv_obj_t * obj,lv_coord_t y)674 void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y)
675 {
676     lv_obj_set_pos(obj, lv_obj_get_x(obj), y);
677 }
678 
679 /**
680  * Set the size of an object
681  * @param obj pointer to an object
682  * @param w new width
683  * @param h new height
684  */
lv_obj_set_size(lv_obj_t * obj,lv_coord_t w,lv_coord_t h)685 void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h)
686 {
687 
688     /* Do nothing if the size is not changed */
689     /* It is very important else recursive resizing can
690      * occur without size change*/
691     if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) {
692         return;
693     }
694 
695     /*Invalidate the original area*/
696     lv_obj_invalidate(obj);
697 
698     /*Save the original coordinates*/
699     lv_area_t ori;
700     lv_obj_get_coords(obj, &ori);
701 
702     /*Set the length and height*/
703     obj->coords.x2 = obj->coords.x1 + w - 1;
704     obj->coords.y2 = obj->coords.y1 + h - 1;
705 
706     /*Send a signal to the object with its new coordinates*/
707     obj->signal_cb(obj, LV_SIGNAL_CORD_CHG, &ori);
708 
709     /*Send a signal to the parent too*/
710     lv_obj_t * par = lv_obj_get_parent(obj);
711     if(par != NULL) par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj);
712 
713     /*Tell the children the parent's size has changed*/
714     lv_obj_t * i;
715     LV_LL_READ(obj->child_ll, i)
716     {
717         i->signal_cb(i, LV_SIGNAL_PARENT_SIZE_CHG, NULL);
718     }
719 
720     /*Invalidate the new area*/
721     lv_obj_invalidate(obj);
722 
723     /*Automatically realign the object if required*/
724 #if LV_USE_OBJ_REALIGN
725     if(obj->realign.auto_realign) lv_obj_realign(obj);
726 #endif
727 }
728 
729 /**
730  * Set the width of an object
731  * @param obj pointer to an object
732  * @param w new width
733  */
lv_obj_set_width(lv_obj_t * obj,lv_coord_t w)734 void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w)
735 {
736     lv_obj_set_size(obj, w, lv_obj_get_height(obj));
737 }
738 
739 /**
740  * Set the height of an object
741  * @param obj pointer to an object
742  * @param h new height
743  */
lv_obj_set_height(lv_obj_t * obj,lv_coord_t h)744 void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h)
745 {
746     lv_obj_set_size(obj, lv_obj_get_width(obj), h);
747 }
748 
749 /**
750  * Align an object to an other object.
751  * @param obj pointer to an object to align
752  * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
753  * @param align type of alignment (see 'lv_align_t' enum)
754  * @param x_mod x coordinate shift after alignment
755  * @param y_mod y coordinate shift after alignment
756  */
lv_obj_align(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t x_mod,lv_coord_t y_mod)757 void lv_obj_align(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod)
758 {
759     lv_coord_t new_x = lv_obj_get_x(obj);
760     lv_coord_t new_y = lv_obj_get_y(obj);
761 
762     if(base == NULL) {
763         base = lv_obj_get_parent(obj);
764     }
765 
766     switch(align) {
767         case LV_ALIGN_CENTER:
768             new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;
769             new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;
770             break;
771 
772         case LV_ALIGN_IN_TOP_LEFT:
773             new_x = 0;
774             new_y = 0;
775             break;
776         case LV_ALIGN_IN_TOP_MID:
777             new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;
778             new_y = 0;
779             break;
780 
781         case LV_ALIGN_IN_TOP_RIGHT:
782             new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);
783             new_y = 0;
784             break;
785 
786         case LV_ALIGN_IN_BOTTOM_LEFT:
787             new_x = 0;
788             new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);
789             break;
790         case LV_ALIGN_IN_BOTTOM_MID:
791             new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;
792             new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);
793             break;
794 
795         case LV_ALIGN_IN_BOTTOM_RIGHT:
796             new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);
797             new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);
798             break;
799 
800         case LV_ALIGN_IN_LEFT_MID:
801             new_x = 0;
802             new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;
803             break;
804 
805         case LV_ALIGN_IN_RIGHT_MID:
806             new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);
807             new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;
808             break;
809 
810         case LV_ALIGN_OUT_TOP_LEFT:
811             new_x = 0;
812             new_y = -lv_obj_get_height(obj);
813             break;
814 
815         case LV_ALIGN_OUT_TOP_MID:
816             new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;
817             new_y = -lv_obj_get_height(obj);
818             break;
819 
820         case LV_ALIGN_OUT_TOP_RIGHT:
821             new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);
822             new_y = -lv_obj_get_height(obj);
823             break;
824 
825         case LV_ALIGN_OUT_BOTTOM_LEFT:
826             new_x = 0;
827             new_y = lv_obj_get_height(base);
828             break;
829 
830         case LV_ALIGN_OUT_BOTTOM_MID:
831             new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;
832             new_y = lv_obj_get_height(base);
833             break;
834 
835         case LV_ALIGN_OUT_BOTTOM_RIGHT:
836             new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);
837             new_y = lv_obj_get_height(base);
838             break;
839 
840         case LV_ALIGN_OUT_LEFT_TOP:
841             new_x = -lv_obj_get_width(obj);
842             new_y = 0;
843             break;
844 
845         case LV_ALIGN_OUT_LEFT_MID:
846             new_x = -lv_obj_get_width(obj);
847             new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;
848             break;
849 
850         case LV_ALIGN_OUT_LEFT_BOTTOM:
851             new_x = -lv_obj_get_width(obj);
852             new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);
853             break;
854 
855         case LV_ALIGN_OUT_RIGHT_TOP:
856             new_x = lv_obj_get_width(base);
857             new_y = 0;
858             break;
859 
860         case LV_ALIGN_OUT_RIGHT_MID:
861             new_x = lv_obj_get_width(base);
862             new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;
863             break;
864 
865         case LV_ALIGN_OUT_RIGHT_BOTTOM:
866             new_x = lv_obj_get_width(base);
867             new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);
868             break;
869     }
870 
871     /*Bring together the coordination system of base and obj*/
872     lv_obj_t * par        = lv_obj_get_parent(obj);
873     lv_coord_t base_abs_x = base->coords.x1;
874     lv_coord_t base_abs_y = base->coords.y1;
875     lv_coord_t par_abs_x  = par->coords.x1;
876     lv_coord_t par_abs_y  = par->coords.y1;
877     new_x += x_mod + base_abs_x;
878     new_y += y_mod + base_abs_y;
879     new_x -= par_abs_x;
880     new_y -= par_abs_y;
881 
882     lv_obj_set_pos(obj, new_x, new_y);
883 
884 #if LV_USE_OBJ_REALIGN
885     /*Save the last align parameters to use them in `lv_obj_realign`*/
886     obj->realign.align       = align;
887     obj->realign.xofs        = x_mod;
888     obj->realign.yofs        = y_mod;
889     obj->realign.base        = base;
890     obj->realign.origo_align = 0;
891 #endif
892 }
893 
894 /**
895  * Align an object's middle point to an other object.
896  * @param obj pointer to an object to align
897  * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.
898  * @param align type of alignment (see 'lv_align_t' enum)
899  * @param x_mod x coordinate shift after alignment
900  * @param y_mod y coordinate shift after alignment
901  */
lv_obj_align_origo(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t x_mod,lv_coord_t y_mod)902 void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod)
903 {
904     lv_coord_t new_x = lv_obj_get_x(obj);
905     lv_coord_t new_y = lv_obj_get_y(obj);
906 
907     lv_coord_t obj_w_half = lv_obj_get_width(obj) / 2;
908     lv_coord_t obj_h_half = lv_obj_get_height(obj) / 2;
909 
910     if(base == NULL) {
911         base = lv_obj_get_parent(obj);
912     }
913 
914     switch(align) {
915         case LV_ALIGN_CENTER:
916             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
917             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
918             break;
919 
920         case LV_ALIGN_IN_TOP_LEFT:
921             new_x = -obj_w_half;
922             new_y = -obj_h_half;
923             break;
924         case LV_ALIGN_IN_TOP_MID:
925             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
926             new_y = -obj_h_half;
927             break;
928 
929         case LV_ALIGN_IN_TOP_RIGHT:
930             new_x = lv_obj_get_width(base) - obj_w_half;
931             new_y = -obj_h_half;
932             break;
933 
934         case LV_ALIGN_IN_BOTTOM_LEFT:
935             new_x = -obj_w_half;
936             new_y = lv_obj_get_height(base) - obj_h_half;
937             break;
938         case LV_ALIGN_IN_BOTTOM_MID:
939             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
940             new_y = lv_obj_get_height(base) - obj_h_half;
941             break;
942 
943         case LV_ALIGN_IN_BOTTOM_RIGHT:
944             new_x = lv_obj_get_width(base) - obj_w_half;
945             new_y = lv_obj_get_height(base) - obj_h_half;
946             break;
947 
948         case LV_ALIGN_IN_LEFT_MID:
949             new_x = -obj_w_half;
950             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
951             break;
952 
953         case LV_ALIGN_IN_RIGHT_MID:
954             new_x = lv_obj_get_width(base) - obj_w_half;
955             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
956             break;
957 
958         case LV_ALIGN_OUT_TOP_LEFT:
959             new_x = -obj_w_half;
960             new_y = -obj_h_half;
961             break;
962 
963         case LV_ALIGN_OUT_TOP_MID:
964             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
965             new_y = -obj_h_half;
966             break;
967 
968         case LV_ALIGN_OUT_TOP_RIGHT:
969             new_x = lv_obj_get_width(base) - obj_w_half;
970             new_y = -obj_h_half;
971             break;
972 
973         case LV_ALIGN_OUT_BOTTOM_LEFT:
974             new_x = -obj_w_half;
975             new_y = lv_obj_get_height(base) - obj_h_half;
976             break;
977 
978         case LV_ALIGN_OUT_BOTTOM_MID:
979             new_x = lv_obj_get_width(base) / 2 - obj_w_half;
980             new_y = lv_obj_get_height(base) - obj_h_half;
981             break;
982 
983         case LV_ALIGN_OUT_BOTTOM_RIGHT:
984             new_x = lv_obj_get_width(base) - obj_w_half;
985             new_y = lv_obj_get_height(base) - obj_h_half;
986             break;
987 
988         case LV_ALIGN_OUT_LEFT_TOP:
989             new_x = -obj_w_half;
990             new_y = -obj_h_half;
991             break;
992 
993         case LV_ALIGN_OUT_LEFT_MID:
994             new_x = -obj_w_half;
995             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
996             break;
997 
998         case LV_ALIGN_OUT_LEFT_BOTTOM:
999             new_x = -obj_w_half;
1000             new_y = lv_obj_get_height(base) - obj_h_half;
1001             break;
1002 
1003         case LV_ALIGN_OUT_RIGHT_TOP:
1004             new_x = lv_obj_get_width(base) - obj_w_half;
1005             new_y = -obj_h_half;
1006             break;
1007 
1008         case LV_ALIGN_OUT_RIGHT_MID:
1009             new_x = lv_obj_get_width(base) - obj_w_half;
1010             new_y = lv_obj_get_height(base) / 2 - obj_h_half;
1011             break;
1012 
1013         case LV_ALIGN_OUT_RIGHT_BOTTOM:
1014             new_x = lv_obj_get_width(base) - obj_w_half;
1015             new_y = lv_obj_get_height(base) - obj_h_half;
1016             break;
1017     }
1018 
1019     /*Bring together the coordination system of base and obj*/
1020     lv_obj_t * par        = lv_obj_get_parent(obj);
1021     lv_coord_t base_abs_x = base->coords.x1;
1022     lv_coord_t base_abs_y = base->coords.y1;
1023     lv_coord_t par_abs_x  = par->coords.x1;
1024     lv_coord_t par_abs_y  = par->coords.y1;
1025     new_x += x_mod + base_abs_x;
1026     new_y += y_mod + base_abs_y;
1027     new_x -= par_abs_x;
1028     new_y -= par_abs_y;
1029 
1030     lv_obj_set_pos(obj, new_x, new_y);
1031 
1032 #if LV_USE_OBJ_REALIGN
1033     /*Save the last align parameters to use them in `lv_obj_realign`*/
1034     obj->realign.align       = align;
1035     obj->realign.xofs        = x_mod;
1036     obj->realign.yofs        = y_mod;
1037     obj->realign.base        = base;
1038     obj->realign.origo_align = 1;
1039 #endif
1040 }
1041 
1042 /**
1043  * Realign the object based on the last `lv_obj_align` parameters.
1044  * @param obj pointer to an object
1045  */
lv_obj_realign(lv_obj_t * obj)1046 void lv_obj_realign(lv_obj_t * obj)
1047 {
1048 #if LV_USE_OBJ_REALIGN
1049     if(obj->realign.origo_align)
1050         lv_obj_align_origo(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs);
1051     else
1052         lv_obj_align(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs);
1053 #else
1054     (void)obj;
1055     LV_LOG_WARN("lv_obj_realaign: no effect because LV_USE_OBJ_REALIGN = 0");
1056 #endif
1057 }
1058 
1059 /**
1060  * Enable the automatic realign of the object when its size has changed based on the last
1061  * `lv_obj_align` parameters.
1062  * @param obj pointer to an object
1063  * @param en true: enable auto realign; false: disable auto realign
1064  */
lv_obj_set_auto_realign(lv_obj_t * obj,bool en)1065 void lv_obj_set_auto_realign(lv_obj_t * obj, bool en)
1066 {
1067 #if LV_USE_OBJ_REALIGN
1068     obj->realign.auto_realign = en ? 1 : 0;
1069 #else
1070     (void)obj;
1071     (void)en;
1072     LV_LOG_WARN("lv_obj_set_auto_realign: no effect because LV_USE_OBJ_REALIGN = 0");
1073 #endif
1074 }
1075 
1076 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
1077 /**
1078  * Set the size of an extended clickable area
1079  * @param obj pointer to an object
1080  * @param w extended width to both sides
1081  * @param h extended height to both sides
1082  */
lv_obj_set_ext_click_area(lv_obj_t * obj,uint8_t w,uint8_t h)1083 void lv_obj_set_ext_click_area(lv_obj_t * obj, uint8_t w, uint8_t h)
1084 {
1085     obj->ext_click_pad_hor = w;
1086     obj->ext_click_pad_ver = h;
1087 }
1088 #endif
1089 
1090 /**
1091  * Set the size of an extended clickable area
1092  * If TINY mode is used, only the largest of the horizontal and vertical padding
1093  * values are considered.
1094  * @param obj pointer to an object
1095  * @param left extended clickable are on the left [px]
1096  * @param right extended clickable are on the right [px]
1097  * @param top extended clickable are on the top [px]
1098  * @param bottom extended clickable are on the bottom [px]
1099  */
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)1100 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)
1101 {
1102 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
1103     obj->ext_click_pad.x1 = left;
1104     obj->ext_click_pad.x2 = right;
1105     obj->ext_click_pad.y1 = top;
1106     obj->ext_click_pad.y2 = bottom;
1107 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
1108     obj->ext_click_pad_hor = LV_MATH_MAX(left, right);
1109     obj->ext_click_pad_ver = LV_MATH_MAX(top, bottom);
1110 #else
1111     (void)obj;    /*Unused*/
1112     (void)left;   /*Unused*/
1113     (void)right;  /*Unused*/
1114     (void)top;    /*Unused*/
1115     (void)bottom; /*Unused*/
1116 #endif
1117 }
1118 
1119 /*---------------------
1120  * Appearance set
1121  *--------------------*/
1122 
1123 /**
1124  * Set a new style for an object
1125  * @param obj pointer to an object
1126  * @param style_p pointer to the new style
1127  */
lv_obj_set_style(lv_obj_t * obj,const lv_style_t * style)1128 void lv_obj_set_style(lv_obj_t * obj, const lv_style_t * style)
1129 {
1130     obj->style_p = style;
1131 
1132     /*Send a signal about style change to every children with NULL style*/
1133     refresh_children_style(obj);
1134 
1135     /*Notify the object about the style change too*/
1136     lv_obj_refresh_style(obj);
1137 }
1138 
1139 /**
1140  * Notify an object about its style is modified
1141  * @param obj pointer to an object
1142  */
lv_obj_refresh_style(lv_obj_t * obj)1143 void lv_obj_refresh_style(lv_obj_t * obj)
1144 {
1145     lv_obj_invalidate(obj);
1146     obj->signal_cb(obj, LV_SIGNAL_STYLE_CHG, NULL);
1147     lv_obj_invalidate(obj);
1148 }
1149 
1150 /**
1151  * Notify all object if a style is modified
1152  * @param style pointer to a style. Only the objects with this style will be notified
1153  *               (NULL to notify all objects)
1154  */
lv_obj_report_style_mod(lv_style_t * style)1155 void lv_obj_report_style_mod(lv_style_t * style)
1156 {
1157     lv_disp_t * d = lv_disp_get_next(NULL);
1158 
1159     while(d) {
1160         lv_obj_t * i;
1161         LV_LL_READ(d->scr_ll, i)
1162         {
1163             if(i->style_p == style || style == NULL) {
1164                 lv_obj_refresh_style(i);
1165             }
1166 
1167             report_style_mod_core(style, i);
1168         }
1169         d = lv_disp_get_next(d);
1170     }
1171 }
1172 
1173 /*-----------------
1174  * Attribute set
1175  *----------------*/
1176 
1177 /**
1178  * Hide an object. It won't be visible and clickable.
1179  * @param obj pointer to an object
1180  * @param en true: hide the object
1181  */
lv_obj_set_hidden(lv_obj_t * obj,bool en)1182 void lv_obj_set_hidden(lv_obj_t * obj, bool en)
1183 {
1184     if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */
1185 
1186     obj->hidden = en == false ? 0 : 1;
1187 
1188     if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */
1189 
1190     lv_obj_t * par = lv_obj_get_parent(obj);
1191     par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj);
1192 }
1193 
1194 /**
1195  * Enable or disable the clicking of an object
1196  * @param obj pointer to an object
1197  * @param en true: make the object clickable
1198  */
lv_obj_set_click(lv_obj_t * obj,bool en)1199 void lv_obj_set_click(lv_obj_t * obj, bool en)
1200 {
1201     obj->click = (en == true ? 1 : 0);
1202 }
1203 
1204 /**
1205  * Enable to bring this object to the foreground if it
1206  * or any of its children is clicked
1207  * @param obj pointer to an object
1208  * @param en true: enable the auto top feature
1209  */
lv_obj_set_top(lv_obj_t * obj,bool en)1210 void lv_obj_set_top(lv_obj_t * obj, bool en)
1211 {
1212     obj->top = (en == true ? 1 : 0);
1213 }
1214 
1215 /**
1216  * Enable the dragging of an object
1217  * @param obj pointer to an object
1218  * @param en true: make the object dragable
1219  */
lv_obj_set_drag(lv_obj_t * obj,bool en)1220 void lv_obj_set_drag(lv_obj_t * obj, bool en)
1221 {
1222     if(en == true) lv_obj_set_click(obj, true); /*Drag is useless without enabled clicking*/
1223     obj->drag = (en == true ? 1 : 0);
1224 }
1225 
1226 /**
1227  * Set the directions an object can be dragged in
1228  * @param obj pointer to an object
1229  * @param drag_dir bitwise OR of allowed directions an object can be dragged in
1230  */
lv_obj_set_drag_dir(lv_obj_t * obj,lv_drag_dir_t drag_dir)1231 void lv_obj_set_drag_dir(lv_obj_t * obj, lv_drag_dir_t drag_dir)
1232 {
1233     obj->drag_dir = drag_dir;
1234 
1235     if(obj->drag_dir != 0) lv_obj_set_drag(obj, true); /*Drag direction requires drag*/
1236 }
1237 
1238 /**
1239  * Enable the throwing of an object after is is dragged
1240  * @param obj pointer to an object
1241  * @param en true: enable the drag throw
1242  */
lv_obj_set_drag_throw(lv_obj_t * obj,bool en)1243 void lv_obj_set_drag_throw(lv_obj_t * obj, bool en)
1244 {
1245     obj->drag_throw = (en == true ? 1 : 0);
1246 }
1247 
1248 /**
1249  * Enable to use parent for drag related operations.
1250  * If trying to drag the object the parent will be moved instead
1251  * @param obj pointer to an object
1252  * @param en true: enable the 'drag parent' for the object
1253  */
lv_obj_set_drag_parent(lv_obj_t * obj,bool en)1254 void lv_obj_set_drag_parent(lv_obj_t * obj, bool en)
1255 {
1256     obj->drag_parent = (en == true ? 1 : 0);
1257 }
1258 
1259 /**
1260  * Propagate the events to the parent too
1261  * @param obj pointer to an object
1262  * @param en true: enable the event propagation
1263  */
lv_obj_set_parent_event(lv_obj_t * obj,bool en)1264 void lv_obj_set_parent_event(lv_obj_t * obj, bool en)
1265 {
1266     obj->parent_event = (en == true ? 1 : 0);
1267 }
1268 
1269 /**
1270  * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)
1271  * @param obj pointer to an object
1272  * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling
1273  */
lv_obj_set_opa_scale_enable(lv_obj_t * obj,bool en)1274 void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en)
1275 {
1276     obj->opa_scale_en = en ? 1 : 0;
1277 }
1278 
1279 /**
1280  * Set the opa scale of an object.
1281  * The opacity of this object and all it's children will be scaled down with this factor.
1282  * `lv_obj_set_opa_scale_enable(obj, true)` needs to be called to enable it.
1283  * (not for all children just for the parent where to start the opa scaling)
1284  * @param obj pointer to an object
1285  * @param opa_scale a factor to scale down opacity [0..255]
1286  */
lv_obj_set_opa_scale(lv_obj_t * obj,lv_opa_t opa_scale)1287 void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale)
1288 {
1289     obj->opa_scale = opa_scale;
1290     lv_obj_invalidate(obj);
1291 }
1292 
1293 /**
1294  * Set a bit or bits in the protect filed
1295  * @param obj pointer to an object
1296  * @param prot 'OR'-ed values from `lv_protect_t`
1297  */
lv_obj_set_protect(lv_obj_t * obj,uint8_t prot)1298 void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot)
1299 {
1300     obj->protect |= prot;
1301 }
1302 
1303 /**
1304  * Clear a bit or bits in the protect filed
1305  * @param obj pointer to an object
1306  * @param prot 'OR'-ed values from `lv_protect_t`
1307  */
lv_obj_clear_protect(lv_obj_t * obj,uint8_t prot)1308 void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot)
1309 {
1310     prot = (~prot) & 0xFF;
1311     obj->protect &= prot;
1312 }
1313 
1314 /**
1315  * Set a an event handler function for an object.
1316  * Used by the user to react on event which happens with the object.
1317  * @param obj pointer to an object
1318  * @param event_cb the new event function
1319  */
lv_obj_set_event_cb(lv_obj_t * obj,lv_event_cb_t event_cb)1320 void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb)
1321 {
1322     obj->event_cb = event_cb;
1323 }
1324 
1325 /**
1326  * Send an event to the object
1327  * @param obj pointer to an object
1328  * @param event the type of the event from `lv_event_t`
1329  * @param data arbitrary data depending on the object type and the event. (Usually `NULL`)
1330  * @return LV_RES_OK: `obj` was not deleted in the event; LV_RES_INV: `obj` was deleted in the event
1331  */
lv_event_send(lv_obj_t * obj,lv_event_t event,const void * data)1332 lv_res_t lv_event_send(lv_obj_t * obj, lv_event_t event, const void * data)
1333 {
1334     if(obj == NULL) return LV_RES_OK;
1335 
1336     lv_res_t res;
1337     res = lv_event_send_func(obj->event_cb, obj, event, data);
1338     return res;
1339 }
1340 
1341 /**
1342  * Call an event function with an object, event, and data.
1343  * @param event_xcb an event callback function. If `NULL` `LV_RES_OK` will return without any actions.
1344  *        (the 'x' in the argument name indicates that its not a fully generic function because it not follows
1345  *         the `func_name(object, callback, ...)` convention)
1346  * @param obj pointer to an object to associate with the event (can be `NULL` to simply call the `event_cb`)
1347  * @param event an event
1348  * @param data pointer to a custom data
1349  * @return LV_RES_OK: `obj` was not deleted in the event; LV_RES_INV: `obj` was deleted in the event
1350  */
lv_event_send_func(lv_event_cb_t event_xcb,lv_obj_t * obj,lv_event_t event,const void * data)1351 lv_res_t lv_event_send_func(lv_event_cb_t event_xcb, lv_obj_t * obj, lv_event_t event, const void * data)
1352 {
1353     /* Build a simple linked list from the objects used in the events
1354      * It's important to know if an this object was deleted by a nested event
1355      * called from this `even_cb`. */
1356     lv_event_temp_data_t event_temp_data;
1357     event_temp_data.obj     = obj;
1358     event_temp_data.deleted = false;
1359     event_temp_data.prev    = NULL;
1360 
1361     if(event_temp_data_head) {
1362         event_temp_data.prev = event_temp_data_head;
1363     }
1364     event_temp_data_head = &event_temp_data;
1365 
1366     const void * event_act_data_save = event_act_data;
1367     event_act_data                   = data;
1368 
1369     /*Call the input device's feedback callback if set*/
1370     lv_indev_t * indev_act = lv_indev_get_act();
1371     if(indev_act) {
1372         if(indev_act->driver.feedback_cb) indev_act->driver.feedback_cb(&indev_act->driver, event);
1373     }
1374 
1375     /*Call the event callback itself*/
1376     if(event_xcb) event_xcb(obj, event);
1377 
1378     /*Restore the event data*/
1379     event_act_data = event_act_data_save;
1380 
1381     /*Remove this element from the list*/
1382     event_temp_data_head = event_temp_data_head->prev;
1383 
1384     if(event_temp_data.deleted) {
1385         return LV_RES_INV;
1386     }
1387 
1388     if(obj) {
1389         if(obj->parent_event && obj->par) {
1390             lv_res_t res = lv_event_send(obj->par, event, data);
1391             if(res != LV_RES_OK) {
1392                 return LV_RES_INV;
1393             }
1394         }
1395     }
1396 
1397     return LV_RES_OK;
1398 }
1399 
1400 /**
1401  * Get the `data` parameter of the current event
1402  * @return the `data` parameter
1403  */
lv_event_get_data(void)1404 const void * lv_event_get_data(void)
1405 {
1406     return event_act_data;
1407 }
1408 
1409 /**
1410  * Set the a signal function of an object. Used internally by the library.
1411  * Always call the previous signal function in the new.
1412  * @param obj pointer to an object
1413  * @param cb the new signal function
1414  */
lv_obj_set_signal_cb(lv_obj_t * obj,lv_signal_cb_t signal_cb)1415 void lv_obj_set_signal_cb(lv_obj_t * obj, lv_signal_cb_t signal_cb)
1416 {
1417     obj->signal_cb = signal_cb;
1418 }
1419 
1420 /**
1421  * Send an event to the object
1422  * @param obj pointer to an object
1423  * @param event the type of the event from `lv_event_t`.
1424  */
lv_signal_send(lv_obj_t * obj,lv_signal_t signal,void * param)1425 void lv_signal_send(lv_obj_t * obj, lv_signal_t signal, void * param)
1426 {
1427     if(obj->signal_cb) obj->signal_cb(obj, signal, param);
1428 }
1429 
1430 /**
1431  * Set a new design function for an object
1432  * @param obj pointer to an object
1433  * @param design_cb the new design function
1434  */
lv_obj_set_design_cb(lv_obj_t * obj,lv_design_cb_t design_cb)1435 void lv_obj_set_design_cb(lv_obj_t * obj, lv_design_cb_t design_cb)
1436 {
1437     obj->design_cb = design_cb;
1438 }
1439 
1440 /*----------------
1441  * Other set
1442  *--------------*/
1443 
1444 /**
1445  * Allocate a new ext. data for an object
1446  * @param obj pointer to an object
1447  * @param ext_size the size of the new ext. data
1448  * @return Normal pointer to the allocated ext
1449  */
lv_obj_allocate_ext_attr(lv_obj_t * obj,uint16_t ext_size)1450 void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size)
1451 {
1452     obj->ext_attr = lv_mem_realloc(obj->ext_attr, ext_size);
1453 
1454     return (void *)obj->ext_attr;
1455 }
1456 
1457 /**
1458  * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object
1459  * @param obj pointer to an object
1460  */
lv_obj_refresh_ext_draw_pad(lv_obj_t * obj)1461 void lv_obj_refresh_ext_draw_pad(lv_obj_t * obj)
1462 {
1463     obj->ext_draw_pad = 0;
1464     obj->signal_cb(obj, LV_SIGNAL_REFR_EXT_DRAW_PAD, NULL);
1465 
1466     lv_obj_invalidate(obj);
1467 }
1468 
1469 /*=======================
1470  * Getter functions
1471  *======================*/
1472 
1473 /**
1474  * Return with the screen of an object
1475  * @param obj pointer to an object
1476  * @return pointer to a screen
1477  */
lv_obj_get_screen(const lv_obj_t * obj)1478 lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj)
1479 {
1480     const lv_obj_t * par = obj;
1481     const lv_obj_t * act_p;
1482 
1483     do {
1484         act_p = par;
1485         par   = lv_obj_get_parent(act_p);
1486     } while(par != NULL);
1487 
1488     return (lv_obj_t *)act_p;
1489 }
1490 
1491 /**
1492  * Get the display of an object
1493  * @param scr pointer to an object
1494  * @return pointer the object's display
1495  */
lv_obj_get_disp(const lv_obj_t * obj)1496 lv_disp_t * lv_obj_get_disp(const lv_obj_t * obj)
1497 {
1498     const lv_obj_t * scr;
1499 
1500     if(obj->par == NULL)
1501         scr = obj; /*`obj` is a screen*/
1502     else
1503         scr = lv_obj_get_screen(obj); /*get the screen of `obj`*/
1504 
1505     lv_disp_t * d;
1506     LV_LL_READ(LV_GC_ROOT(_lv_disp_ll), d)
1507     {
1508         lv_obj_t * s;
1509         LV_LL_READ(d->scr_ll, s)
1510         {
1511             if(s == scr) return d;
1512         }
1513     }
1514 
1515     LV_LOG_WARN("lv_scr_get_disp: screen not found")
1516     return NULL;
1517 }
1518 
1519 /*---------------------
1520  * Parent/children get
1521  *--------------------*/
1522 
1523 /**
1524  * Returns with the parent of an object
1525  * @param obj pointer to an object
1526  * @return pointer to the parent of  'obj'
1527  */
lv_obj_get_parent(const lv_obj_t * obj)1528 lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj)
1529 {
1530     return obj->par;
1531 }
1532 
1533 /**
1534  * Iterate through the children of an object (start from the "youngest")
1535  * @param obj pointer to an object
1536  * @param child NULL at first call to get the next children
1537  *                  and the previous return value later
1538  * @return the child after 'act_child' or NULL if no more child
1539  */
lv_obj_get_child(const lv_obj_t * obj,const lv_obj_t * child)1540 lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child)
1541 {
1542     lv_obj_t * result = NULL;
1543 
1544     if(child == NULL) {
1545         result = lv_ll_get_head(&obj->child_ll);
1546     } else {
1547         result = lv_ll_get_next(&obj->child_ll, child);
1548     }
1549 
1550     return result;
1551 }
1552 
1553 /**
1554  * Iterate through the children of an object (start from the "oldest")
1555  * @param obj pointer to an object
1556  * @param child NULL at first call to get the next children
1557  *                  and the previous return value later
1558  * @return the child after 'act_child' or NULL if no more child
1559  */
lv_obj_get_child_back(const lv_obj_t * obj,const lv_obj_t * child)1560 lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child)
1561 {
1562     lv_obj_t * result = NULL;
1563 
1564     if(child == NULL) {
1565         result = lv_ll_get_tail(&obj->child_ll);
1566     } else {
1567         result = lv_ll_get_prev(&obj->child_ll, child);
1568     }
1569 
1570     return result;
1571 }
1572 
1573 /**
1574  * Count the children of an object (only children directly on 'obj')
1575  * @param obj pointer to an object
1576  * @return children number of 'obj'
1577  */
lv_obj_count_children(const lv_obj_t * obj)1578 uint16_t lv_obj_count_children(const lv_obj_t * obj)
1579 {
1580     lv_obj_t * i;
1581     uint16_t cnt = 0;
1582 
1583     LV_LL_READ(obj->child_ll, i) cnt++;
1584 
1585     return cnt;
1586 }
1587 
1588 /** Recursively count the children of an object
1589  * @param obj pointer to an object
1590  * @return children number of 'obj'
1591  */
lv_obj_count_children_recursive(const lv_obj_t * obj)1592 uint16_t lv_obj_count_children_recursive(const lv_obj_t * obj)
1593 {
1594     lv_obj_t * i;
1595     uint16_t cnt = 0;
1596 
1597     LV_LL_READ(obj->child_ll, i)
1598     {
1599         cnt++;                                     /*Count the child*/
1600         cnt += lv_obj_count_children_recursive(i); /*recursively count children's children*/
1601     }
1602 
1603     return cnt;
1604 }
1605 
1606 /*---------------------
1607  * Coordinate get
1608  *--------------------*/
1609 
1610 /**
1611  * Copy the coordinates of an object to an area
1612  * @param obj pointer to an object
1613  * @param cords_p pointer to an area to store the coordinates
1614  */
lv_obj_get_coords(const lv_obj_t * obj,lv_area_t * cords_p)1615 void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p)
1616 {
1617     lv_area_copy(cords_p, &obj->coords);
1618 }
1619 
1620 /**
1621  * Reduce area retried by `lv_obj_get_coords()` the get graphically usable area of an object.
1622  * (Without the size of the border or other extra graphical elements)
1623  * @param coords_p store the result area here
1624  */
lv_obj_get_inner_coords(const lv_obj_t * obj,lv_area_t * coords_p)1625 void lv_obj_get_inner_coords(const lv_obj_t * obj, lv_area_t * coords_p)
1626 {
1627     const lv_style_t * style = lv_obj_get_style(obj);
1628     if(style->body.border.part & LV_BORDER_LEFT) coords_p->x1 += style->body.border.width;
1629 
1630     if(style->body.border.part & LV_BORDER_RIGHT) coords_p->x2 -= style->body.border.width;
1631 
1632     if(style->body.border.part & LV_BORDER_TOP) coords_p->y1 += style->body.border.width;
1633 
1634     if(style->body.border.part & LV_BORDER_BOTTOM) coords_p->y2 -= style->body.border.width;
1635 }
1636 
1637 /**
1638  * Get the x coordinate of object
1639  * @param obj pointer to an object
1640  * @return distance of 'obj' from the left side of its parent
1641  */
lv_obj_get_x(const lv_obj_t * obj)1642 lv_coord_t lv_obj_get_x(const lv_obj_t * obj)
1643 {
1644     lv_coord_t rel_x;
1645     lv_obj_t * parent = lv_obj_get_parent(obj);
1646     rel_x             = obj->coords.x1 - parent->coords.x1;
1647 
1648     return rel_x;
1649 }
1650 
1651 /**
1652  * Get the y coordinate of object
1653  * @param obj pointer to an object
1654  * @return distance of 'obj' from the top of its parent
1655  */
lv_obj_get_y(const lv_obj_t * obj)1656 lv_coord_t lv_obj_get_y(const lv_obj_t * obj)
1657 {
1658     lv_coord_t rel_y;
1659     lv_obj_t * parent = lv_obj_get_parent(obj);
1660     rel_y             = obj->coords.y1 - parent->coords.y1;
1661 
1662     return rel_y;
1663 }
1664 
1665 /**
1666  * Get the width of an object
1667  * @param obj pointer to an object
1668  * @return the width
1669  */
lv_obj_get_width(const lv_obj_t * obj)1670 lv_coord_t lv_obj_get_width(const lv_obj_t * obj)
1671 {
1672     return lv_area_get_width(&obj->coords);
1673 }
1674 
1675 /**
1676  * Get the height of an object
1677  * @param obj pointer to an object
1678  * @return the height
1679  */
lv_obj_get_height(const lv_obj_t * obj)1680 lv_coord_t lv_obj_get_height(const lv_obj_t * obj)
1681 {
1682     return lv_area_get_height(&obj->coords);
1683 }
1684 
1685 /**
1686  * Get that width reduced by the left and right padding.
1687  * @param obj pointer to an object
1688  * @return the width which still fits into the container
1689  */
lv_obj_get_width_fit(lv_obj_t * obj)1690 lv_coord_t lv_obj_get_width_fit(lv_obj_t * obj)
1691 {
1692     const lv_style_t * style = lv_obj_get_style(obj);
1693 
1694     return lv_obj_get_width(obj) - style->body.padding.left - style->body.padding.right;
1695 }
1696 
1697 /**
1698  * Get that height reduced by the top an bottom padding.
1699  * @param obj pointer to an object
1700  * @return the height which still fits into the container
1701  */
lv_obj_get_height_fit(lv_obj_t * obj)1702 lv_coord_t lv_obj_get_height_fit(lv_obj_t * obj)
1703 {
1704     const lv_style_t * style = lv_obj_get_style(obj);
1705 
1706     return lv_obj_get_height(obj) - style->body.padding.top - style->body.padding.bottom;
1707 }
1708 
1709 /**
1710  * Get the automatic realign property of the object.
1711  * @param obj pointer to an object
1712  * @return  true: auto realign is enabled; false: auto realign is disabled
1713  */
lv_obj_get_auto_realign(lv_obj_t * obj)1714 bool lv_obj_get_auto_realign(lv_obj_t * obj)
1715 {
1716 #if LV_USE_OBJ_REALIGN
1717     return obj->realign.auto_realign ? true : false;
1718 #else
1719     (void)obj;
1720     return false;
1721 #endif
1722 }
1723 
1724 /**
1725  * Get the left padding of extended clickable area
1726  * @param obj pointer to an object
1727  * @return the extended left padding
1728  */
lv_obj_get_ext_click_pad_left(const lv_obj_t * obj)1729 lv_coord_t lv_obj_get_ext_click_pad_left(const lv_obj_t * obj)
1730 {
1731 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
1732     return obj->ext_click_pad_hor;
1733 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
1734     return obj->ext_click_pad.x1;
1735 #else
1736     (void)obj;    /*Unused*/
1737     return 0;
1738 #endif
1739 }
1740 
1741 /**
1742  * Get the right padding of extended clickable area
1743  * @param obj pointer to an object
1744  * @return the extended right padding
1745  */
lv_obj_get_ext_click_pad_right(const lv_obj_t * obj)1746 lv_coord_t lv_obj_get_ext_click_pad_right(const lv_obj_t * obj)
1747 {
1748 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
1749     return obj->ext_click_pad_hor;
1750 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
1751     return obj->ext_click_pad.x2;
1752 #else
1753     (void)obj; /*Unused*/
1754     return 0;
1755 #endif
1756 }
1757 
1758 /**
1759  * Get the top padding of extended clickable area
1760  * @param obj pointer to an object
1761  * @return the extended top padding
1762  */
lv_obj_get_ext_click_pad_top(const lv_obj_t * obj)1763 lv_coord_t lv_obj_get_ext_click_pad_top(const lv_obj_t * obj)
1764 {
1765 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
1766     return obj->ext_click_pad_ver;
1767 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
1768     return obj->ext_click_pad.y1;
1769 #else
1770     (void)obj; /*Unused*/
1771     return 0;
1772 #endif
1773 }
1774 
1775 /**
1776  * Get the bottom padding of extended clickable area
1777  * @param obj pointer to an object
1778  * @return the extended bottom padding
1779  */
lv_obj_get_ext_click_pad_bottom(const lv_obj_t * obj)1780 lv_coord_t lv_obj_get_ext_click_pad_bottom(const lv_obj_t * obj)
1781 {
1782 #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
1783     return obj->ext_click_pad_ver
1784 #elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
1785     return obj->ext_click_pad.y2;
1786 #else
1787     (void)obj; /*Unused*/
1788     return 0;
1789 #endif
1790 }
1791 
1792 /**
1793  * Get the extended size attribute of an object
1794  * @param obj pointer to an object
1795  * @return the extended size attribute
1796  */
1797 lv_coord_t lv_obj_get_ext_draw_pad(const lv_obj_t * obj)
1798 {
1799     return obj->ext_draw_pad;
1800 }
1801 
1802 /*-----------------
1803  * Appearance get
1804  *---------------*/
1805 
1806 /**
1807  * Get the style pointer of an object (if NULL get style of the parent)
1808  * @param obj pointer to an object
1809  * @return pointer to a style
1810  */
1811 const lv_style_t * lv_obj_get_style(const lv_obj_t * obj)
1812 {
1813     const lv_style_t * style_act = obj->style_p;
1814     if(style_act == NULL) {
1815         lv_obj_t * par = obj->par;
1816 
1817         while(par) {
1818             if(par->style_p) {
1819                 if(par->style_p->glass == 0) {
1820 #if LV_USE_GROUP == 0
1821                     style_act = par->style_p;
1822 #else
1823                     /*If a parent is focused then use then focused style*/
1824                     lv_group_t * g = lv_obj_get_group(par);
1825                     if(lv_group_get_focused(g) == par) {
1826                         style_act = lv_group_mod_style(g, par->style_p);
1827                     } else {
1828                         style_act = par->style_p;
1829                     }
1830 #endif
1831                     break;
1832                 }
1833             }
1834             par = par->par;
1835         }
1836     }
1837 #if LV_USE_GROUP
1838     if(obj->group_p) {
1839         if(lv_group_get_focused(obj->group_p) == obj) {
1840             style_act = lv_group_mod_style(obj->group_p, style_act);
1841         }
1842     }
1843 #endif
1844 
1845     if(style_act == NULL) style_act = &lv_style_plain;
1846 
1847     return style_act;
1848 }
1849 
1850 /*-----------------
1851  * Attribute get
1852  *----------------*/
1853 
1854 /**
1855  * Get the hidden attribute of an object
1856  * @param obj pointer to an object
1857  * @return true: the object is hidden
1858  */
1859 bool lv_obj_get_hidden(const lv_obj_t * obj)
1860 {
1861     return obj->hidden == 0 ? false : true;
1862 }
1863 
1864 /**
1865  * Get the click enable attribute of an object
1866  * @param obj pointer to an object
1867  * @return true: the object is clickable
1868  */
1869 bool lv_obj_get_click(const lv_obj_t * obj)
1870 {
1871     return obj->click == 0 ? false : true;
1872 }
1873 
1874 /**
1875  * Get the top enable attribute of an object
1876  * @param obj pointer to an object
1877  * @return true: the auto top feture is enabled
1878  */
1879 bool lv_obj_get_top(const lv_obj_t * obj)
1880 {
1881     return obj->top == 0 ? false : true;
1882 }
1883 
1884 /**
1885  * Get the drag enable attribute of an object
1886  * @param obj pointer to an object
1887  * @return true: the object is dragable
1888  */
1889 bool lv_obj_get_drag(const lv_obj_t * obj)
1890 {
1891     return obj->drag == 0 ? false : true;
1892 }
1893 
1894 /**
1895  * Get the directions an object can be dragged
1896  * @param obj pointer to an object
1897  * @return bitwise OR of allowed directions an object can be dragged in
1898  */
1899 lv_drag_dir_t lv_obj_get_drag_dir(const lv_obj_t * obj)
1900 {
1901     return obj->drag_dir;
1902 }
1903 
1904 /**
1905  * Get the drag throw enable attribute of an object
1906  * @param obj pointer to an object
1907  * @return true: drag throw is enabled
1908  */
1909 bool lv_obj_get_drag_throw(const lv_obj_t * obj)
1910 {
1911     return obj->drag_throw == 0 ? false : true;
1912 }
1913 
1914 /**
1915  * Get the drag parent attribute of an object
1916  * @param obj pointer to an object
1917  * @return true: drag parent is enabled
1918  */
1919 bool lv_obj_get_drag_parent(const lv_obj_t * obj)
1920 {
1921     return obj->drag_parent == 0 ? false : true;
1922 }
1923 
1924 /**
1925  * Get the drag parent attribute of an object
1926  * @param obj pointer to an object
1927  * @return true: drag parent is enabled
1928  */
1929 bool lv_obj_get_parent_event(const lv_obj_t * obj)
1930 {
1931     return obj->parent_event == 0 ? false : true;
1932 }
1933 
1934 /**
1935  * Get the opa scale enable parameter
1936  * @param obj pointer to an object
1937  * @return true: opa scaling is enabled for this object and all children; false: no opa scaling
1938  */
1939 lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj)
1940 {
1941     return obj->opa_scale_en == 0 ? false : true;
1942 }
1943 
1944 /**
1945  * Get the opa scale parameter of an object
1946  * @param obj pointer to an object
1947  * @return opa scale [0..255]
1948  */
1949 lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj)
1950 {
1951     const lv_obj_t * parent = obj;
1952 
1953     while(parent) {
1954         if(parent->opa_scale_en) return parent->opa_scale;
1955         parent = lv_obj_get_parent(parent);
1956     }
1957 
1958     return LV_OPA_COVER;
1959 }
1960 
1961 /**
1962  * Get the protect field of an object
1963  * @param obj pointer to an object
1964  * @return protect field ('OR'ed values of `lv_protect_t`)
1965  */
1966 uint8_t lv_obj_get_protect(const lv_obj_t * obj)
1967 {
1968     return obj->protect;
1969 }
1970 
1971 /**
1972  * Check at least one bit of a given protect bitfield is set
1973  * @param obj pointer to an object
1974  * @param prot protect bits to test ('OR'ed values of `lv_protect_t`)
1975  * @return false: none of the given bits are set, true: at least one bit is set
1976  */
1977 bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot)
1978 {
1979     return (obj->protect & prot) == 0 ? false : true;
1980 }
1981 
1982 /**
1983  * Get the signal function of an object
1984  * @param obj pointer to an object
1985  * @return the signal function
1986  */
1987 lv_signal_cb_t lv_obj_get_signal_cb(const lv_obj_t * obj)
1988 {
1989     return obj->signal_cb;
1990 }
1991 
1992 /**
1993  * Get the design function of an object
1994  * @param obj pointer to an object
1995  * @return the design function
1996  */
1997 lv_design_cb_t lv_obj_get_design_cb(const lv_obj_t * obj)
1998 {
1999     return obj->design_cb;
2000 }
2001 
2002 /**
2003  * Get the event function of an object
2004  * @param obj pointer to an object
2005  * @return the event function
2006  */
2007 lv_event_cb_t lv_obj_get_event_cb(const lv_obj_t * obj)
2008 {
2009     return obj->event_cb;
2010 }
2011 
2012 /*------------------
2013  * Other get
2014  *-----------------*/
2015 
2016 /**
2017  * Get the ext pointer
2018  * @param obj pointer to an object
2019  * @return the ext pointer but not the dynamic version
2020  *         Use it as ext->data1, and NOT da(ext)->data1
2021  */
2022 void * lv_obj_get_ext_attr(const lv_obj_t * obj)
2023 {
2024     return obj->ext_attr;
2025 }
2026 
2027 /**
2028  * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type.
2029  * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj"
2030  * @param obj pointer to an object which type should be get
2031  * @param buf pointer to an `lv_obj_type_t` buffer to store the types
2032  */
2033 void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf)
2034 {
2035     lv_obj_type_t tmp;
2036 
2037     memset(buf, 0, sizeof(lv_obj_type_t));
2038     memset(&tmp, 0, sizeof(lv_obj_type_t));
2039 
2040     obj->signal_cb(obj, LV_SIGNAL_GET_TYPE, &tmp);
2041 
2042     uint8_t cnt;
2043     for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) {
2044         if(tmp.type[cnt] == NULL) break;
2045     }
2046 
2047     /*Swap the order. The real type comes first*/
2048     uint8_t i;
2049     for(i = 0; i < cnt; i++) {
2050         buf->type[i] = tmp.type[cnt - 1 - i];
2051     }
2052 }
2053 
2054 #if LV_USE_USER_DATA
2055 
2056 /**
2057  * Get the object's user data
2058  * @param obj pointer to an object
2059  * @return user data
2060  */
2061 lv_obj_user_data_t lv_obj_get_user_data(lv_obj_t * obj)
2062 {
2063     return obj->user_data;
2064 }
2065 
2066 /**
2067  * Get a pointer to the object's user data
2068  * @param obj pointer to an object
2069  * @return pointer to the user data
2070  */
2071 lv_obj_user_data_t * lv_obj_get_user_data_ptr(lv_obj_t * obj)
2072 {
2073     return &obj->user_data;
2074 }
2075 
2076 /**
2077  * Set the object's user data. The data will be copied.
2078  * @param obj pointer to an object
2079  * @param data user data
2080  */
2081 void lv_obj_set_user_data(lv_obj_t * obj, lv_obj_user_data_t data)
2082 {
2083     memcpy(&obj->user_data, &data, sizeof(lv_obj_user_data_t));
2084 }
2085 #endif
2086 
2087 #if LV_USE_GROUP
2088 /**
2089  * Get the group of the object
2090  * @param obj pointer to an object
2091  * @return the pointer to group of the object
2092  */
2093 void * lv_obj_get_group(const lv_obj_t * obj)
2094 {
2095     return obj->group_p;
2096 }
2097 
2098 /**
2099  * Tell whether the object is the focused object of a group or not.
2100  * @param obj pointer to an object
2101  * @return true: the object is focused, false: the object is not focused or not in a group
2102  */
2103 bool lv_obj_is_focused(const lv_obj_t * obj)
2104 {
2105     if(obj->group_p) {
2106         if(lv_group_get_focused(obj->group_p) == obj) return true;
2107     }
2108 
2109     return false;
2110 }
2111 #endif
2112 
2113 /**********************
2114  *   STATIC FUNCTIONS
2115  **********************/
2116 
2117 static void lv_obj_del_async_cb(void * obj)
2118 {
2119     lv_obj_del(obj);
2120 }
2121 
2122 /**
2123  * Handle the drawing related tasks of the base objects.
2124  * @param obj pointer to an object
2125  * @param mask the object will be drawn only in this area
2126  * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
2127  *                                  (return 'true' if yes)
2128  *             LV_DESIGN_DRAW: draw the object (always return 'true')
2129  * @param return true/false, depends on 'mode'
2130  */
2131 static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode)
2132 {
2133     if(mode == LV_DESIGN_COVER_CHK) {
2134 
2135         /*Most trivial test. Is the mask fully IN the object? If no it surely doesn't cover it*/
2136         if(lv_area_is_in(mask_p, &obj->coords) == false) return false;
2137 
2138         /*Can cover the area only if fully solid (no opacity)*/
2139         const lv_style_t * style = lv_obj_get_style(obj);
2140         if(style->body.opa < LV_OPA_MAX) return false;
2141 
2142         /* Because of the radius it is not sure the area is covered
2143          * Check the areas where there is no radius*/
2144         lv_coord_t r = style->body.radius;
2145 
2146         if(r == LV_RADIUS_CIRCLE) return false;
2147 
2148         lv_area_t area_tmp;
2149 
2150         /*Check horizontally without radius*/
2151         lv_obj_get_coords(obj, &area_tmp);
2152         area_tmp.x1 += r;
2153         area_tmp.x2 -= r;
2154         if(lv_area_is_in(mask_p, &area_tmp) == false) return false;
2155 
2156         /*Check vertically without radius*/
2157         lv_obj_get_coords(obj, &area_tmp);
2158         area_tmp.y1 += r;
2159         area_tmp.y2 -= r;
2160         if(lv_area_is_in(mask_p, &area_tmp) == false) return false;
2161 
2162     } else if(mode == LV_DESIGN_DRAW_MAIN) {
2163         const lv_style_t * style = lv_obj_get_style(obj);
2164         lv_draw_rect(&obj->coords, mask_p, style, lv_obj_get_opa_scale(obj));
2165     }
2166 
2167     return true;
2168 }
2169 
2170 /**
2171  * Signal function of the basic object
2172  * @param obj pointer to an object
2173  * @param sign signal type
2174  * @param param parameter for the signal (depends on signal type)
2175  * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
2176  */
2177 static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param)
2178 {
2179     (void)param;
2180 
2181     lv_res_t res = LV_RES_OK;
2182 
2183     const lv_style_t * style = lv_obj_get_style(obj);
2184 
2185     if(sign == LV_SIGNAL_CHILD_CHG) {
2186         /*Return 'invalid' if the child change signal is not enabled*/
2187         if(lv_obj_is_protected(obj, LV_PROTECT_CHILD_CHG) != false) res = LV_RES_INV;
2188     } else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
2189         if(style->body.shadow.width > obj->ext_draw_pad) obj->ext_draw_pad = style->body.shadow.width;
2190     } else if(sign == LV_SIGNAL_STYLE_CHG) {
2191         lv_obj_refresh_ext_draw_pad(obj);
2192     } else if(sign == LV_SIGNAL_GET_TYPE) {
2193         lv_obj_type_t * buf = param;
2194         buf->type[0]        = "lv_obj";
2195     }
2196 
2197     return res;
2198 }
2199 
2200 /**
2201  * Reposition the children of an object. (Called recursively)
2202  * @param obj pointer to an object which children will be repositioned
2203  * @param x_diff x coordinate shift
2204  * @param y_diff y coordinate shift
2205  */
2206 static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff)
2207 {
2208     lv_obj_t * i;
2209     LV_LL_READ(obj->child_ll, i)
2210     {
2211         i->coords.x1 += x_diff;
2212         i->coords.y1 += y_diff;
2213         i->coords.x2 += x_diff;
2214         i->coords.y2 += y_diff;
2215 
2216         refresh_children_position(i, x_diff, y_diff);
2217     }
2218 }
2219 
2220 /**
2221  * Refresh the style of all children of an object. (Called recursively)
2222  * @param style_p refresh objects only with this style.
2223  * @param obj pointer to an object
2224  */
2225 static void report_style_mod_core(void * style_p, lv_obj_t * obj)
2226 {
2227     lv_obj_t * i;
2228     LV_LL_READ(obj->child_ll, i)
2229     {
2230         if(i->style_p == style_p || style_p == NULL) {
2231             refresh_children_style(i);
2232             lv_obj_refresh_style(i);
2233         }
2234 
2235         report_style_mod_core(style_p, i);
2236     }
2237 }
2238 
2239 /**
2240  * Recursively refresh the style of the children. Go deeper until a not NULL style is found
2241  * because the NULL styles are inherited from the parent
2242  * @param obj pointer to an object
2243  */
2244 static void refresh_children_style(lv_obj_t * obj)
2245 {
2246     lv_obj_t * child = lv_obj_get_child(obj, NULL);
2247     while(child != NULL) {
2248         if(child->style_p == NULL) {
2249             refresh_children_style(child); /*Check children too*/
2250             lv_obj_refresh_style(child);   /*Notify the child about the style change*/
2251         } else if(child->style_p->glass) {
2252             /*Children with 'glass' parent might be effected if their style == NULL*/
2253             refresh_children_style(child);
2254         }
2255         child = lv_obj_get_child(obj, child);
2256     }
2257 }
2258 
2259 /**
2260  * Called by 'lv_obj_del' to delete the children objects
2261  * @param obj pointer to an object (all of its children will be deleted)
2262  */
2263 static void delete_children(lv_obj_t * obj)
2264 {
2265     lv_obj_t * i;
2266     lv_obj_t * i_next;
2267     i = lv_ll_get_head(&(obj->child_ll));
2268 
2269     /*Remove from the group; remove before transversing children so that
2270      * the object still has access to all children during the
2271      * LV_SIGNAL_DEFOCUS call*/
2272 #if LV_USE_GROUP
2273     lv_group_t * group = lv_obj_get_group(obj);
2274     if(group) lv_group_remove_obj(obj);
2275 #endif
2276 
2277     while(i != NULL) {
2278         /*Get the next object before delete this*/
2279         i_next = lv_ll_get_next(&(obj->child_ll), i);
2280 
2281         /*Call the recursive del to the child too*/
2282         delete_children(i);
2283 
2284         /*Set i to the next node*/
2285         i = i_next;
2286     }
2287 
2288     /*Let the suer free the resources used in `LV_EVENT_DELETE`*/
2289     lv_event_send(obj, LV_EVENT_DELETE, NULL);
2290 
2291     lv_event_mark_deleted(obj);
2292 
2293     /*Remove the animations from this object*/
2294 #if LV_USE_ANIMATION
2295     lv_anim_del(obj, NULL);
2296 #endif
2297 
2298     /* Reset the input devices if
2299      * the object to delete is used*/
2300     lv_indev_t * indev = lv_indev_get_next(NULL);
2301     while(indev) {
2302         if(indev->proc.types.pointer.act_obj == obj || indev->proc.types.pointer.last_obj == obj) {
2303             lv_indev_reset(indev);
2304         }
2305 
2306         if(indev->proc.types.pointer.last_pressed == obj) {
2307             indev->proc.types.pointer.last_pressed = NULL;
2308         }
2309 #if LV_USE_GROUP
2310         if(indev->group == group && obj == lv_indev_get_obj_act()) {
2311             lv_indev_reset(indev);
2312         }
2313 #endif
2314         indev = lv_indev_get_next(indev);
2315     }
2316 
2317     /*Remove the object from parent's children list*/
2318     lv_obj_t * par = lv_obj_get_parent(obj);
2319     lv_ll_rem(&(par->child_ll), obj);
2320 
2321     /* Clean up the object specific data*/
2322     obj->signal_cb(obj, LV_SIGNAL_CLEANUP, NULL);
2323 
2324     /*Delete the base objects*/
2325     if(obj->ext_attr != NULL) lv_mem_free(obj->ext_attr);
2326     lv_mem_free(obj); /*Free the object itself*/
2327 }
2328 
2329 static void lv_event_mark_deleted(lv_obj_t * obj)
2330 {
2331     lv_event_temp_data_t * t = event_temp_data_head;
2332 
2333     while(t) {
2334         if(t->obj == obj) t->deleted = true;
2335         t = t->prev;
2336     }
2337 }
2338