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, ©->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, ©->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, ©->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