1 /**
2  * @file lv_obj_pos.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_obj.h"
10 #include "lv_disp.h"
11 #include "lv_refr.h"
12 #include "../misc/lv_gc.h"
13 
14 /*********************
15  *      DEFINES
16  *********************/
17 #define MY_CLASS &lv_obj_class
18 
19 /**********************
20  *      TYPEDEFS
21  **********************/
22 
23 /**********************
24  *  STATIC PROTOTYPES
25  **********************/
26 static lv_coord_t calc_content_width(lv_obj_t * obj);
27 static lv_coord_t calc_content_height(lv_obj_t * obj);
28 static void layout_update_core(lv_obj_t * obj);
29 
30 /**********************
31  *  STATIC VARIABLES
32  **********************/
33 static uint32_t layout_cnt;
34 
35 /**********************
36  *      MACROS
37  **********************/
38 
39 /**********************
40  *   GLOBAL FUNCTIONS
41  **********************/
42 
lv_obj_set_pos(lv_obj_t * obj,lv_coord_t x,lv_coord_t y)43 void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
44 {
45     LV_ASSERT_OBJ(obj, MY_CLASS);
46 
47     lv_obj_set_x(obj, x);
48     lv_obj_set_y(obj, y);
49 }
50 
lv_obj_set_x(lv_obj_t * obj,lv_coord_t x)51 void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x)
52 {
53     LV_ASSERT_OBJ(obj, MY_CLASS);
54 
55     lv_res_t res_x;
56     lv_style_value_t v_x;
57 
58     res_x = lv_obj_get_local_style_prop(obj, LV_STYLE_X, &v_x, 0);
59 
60     if((res_x == LV_RES_OK && v_x.num != x) || res_x == LV_RES_INV) {
61         lv_obj_set_style_x(obj, x, 0);
62     }
63 }
64 
lv_obj_set_y(lv_obj_t * obj,lv_coord_t y)65 void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y)
66 {
67     LV_ASSERT_OBJ(obj, MY_CLASS);
68 
69     lv_res_t res_y;
70     lv_style_value_t v_y;
71 
72     res_y = lv_obj_get_local_style_prop(obj, LV_STYLE_Y, &v_y, 0);
73 
74     if((res_y == LV_RES_OK && v_y.num != y) || res_y == LV_RES_INV) {
75         lv_obj_set_style_y(obj, y, 0);
76     }
77 }
78 
lv_obj_refr_size(lv_obj_t * obj)79 bool lv_obj_refr_size(lv_obj_t * obj)
80 {
81     LV_ASSERT_OBJ(obj, MY_CLASS);
82 
83     /*If the width or height is set by a layout do not modify them*/
84     if(obj->w_layout && obj->h_layout) return false;
85 
86     lv_obj_t * parent = lv_obj_get_parent(obj);
87     if(parent == NULL) return false;
88 
89     lv_coord_t sl_ori = lv_obj_get_scroll_left(obj);
90     bool w_is_content = false;
91     bool w_is_pct = false;
92 
93     lv_coord_t w;
94     if(obj->w_layout) {
95         w = lv_obj_get_width(obj);
96     }
97     else {
98         w = lv_obj_get_style_width(obj, LV_PART_MAIN);
99         w_is_content = w == LV_SIZE_CONTENT ? true : false;
100         w_is_pct = LV_COORD_IS_PCT(w) ? true : false;
101         lv_coord_t parent_w = lv_obj_get_content_width(parent);
102 
103         if(w_is_content) {
104             w = calc_content_width(obj);
105         }
106         else if(w_is_pct) {
107             /*If parent has content size and the child has pct size
108              *a circular dependency will occur. To solve it keep child size at zero */
109             if(parent->w_layout == 0 && lv_obj_get_style_width(parent, 0) == LV_SIZE_CONTENT) {
110                 lv_coord_t border_w = lv_obj_get_style_border_width(obj, 0);
111                 w = lv_obj_get_style_pad_left(obj, 0) + border_w;
112                 w += lv_obj_get_style_pad_right(obj, 0) + border_w;
113             }
114             else {
115                 w = (LV_COORD_GET_PCT(w) * parent_w) / 100;
116             }
117         }
118 
119         lv_coord_t minw = lv_obj_get_style_min_width(obj, LV_PART_MAIN);
120         lv_coord_t maxw = lv_obj_get_style_max_width(obj, LV_PART_MAIN);
121         w = lv_clamp_width(w, minw, maxw, parent_w);
122     }
123 
124     lv_coord_t st_ori = lv_obj_get_scroll_top(obj);
125     lv_coord_t h;
126     bool h_is_content = false;
127     bool h_is_pct = false;
128     if(obj->h_layout) {
129         h = lv_obj_get_height(obj);
130     }
131     else {
132         h = lv_obj_get_style_height(obj, LV_PART_MAIN);
133         h_is_content = h == LV_SIZE_CONTENT ? true : false;
134         h_is_pct = LV_COORD_IS_PCT(h) ? true : false;
135         lv_coord_t parent_h = lv_obj_get_content_height(parent);
136 
137         if(h_is_content) {
138             h = calc_content_height(obj);
139         }
140         else if(h_is_pct) {
141             /*If parent has content size and the child has pct size
142              *a circular dependency will occur. To solve it keep child size at zero */
143             if(parent->h_layout == 0 && lv_obj_get_style_height(parent, 0) == LV_SIZE_CONTENT) {
144                 lv_coord_t border_w = lv_obj_get_style_border_width(obj, 0);
145                 h = lv_obj_get_style_pad_top(obj, 0) + border_w;
146                 h += lv_obj_get_style_pad_bottom(obj, 0) + border_w;
147             }
148             else {
149                 h = (LV_COORD_GET_PCT(h) * parent_h) / 100;
150             }
151         }
152 
153         lv_coord_t minh = lv_obj_get_style_min_height(obj, LV_PART_MAIN);
154         lv_coord_t maxh = lv_obj_get_style_max_height(obj, LV_PART_MAIN);
155         h = lv_clamp_height(h, minh, maxh, parent_h);
156     }
157 
158     /*calc_auto_size set the scroll x/y to 0 so revert the original value*/
159     if(w_is_content || h_is_content) {
160         lv_obj_scroll_to(obj, sl_ori, st_ori, LV_ANIM_OFF);
161     }
162 
163     /*Do nothing if the size is not changed*/
164     /*It is very important else recursive resizing can occur without size change*/
165     if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) return false;
166 
167     /*Invalidate the original area*/
168     lv_obj_invalidate(obj);
169 
170     /*Save the original coordinates*/
171     lv_area_t ori;
172     lv_obj_get_coords(obj, &ori);
173 
174     /*Check if the object inside the parent or not*/
175     lv_area_t parent_fit_area;
176     lv_obj_get_content_coords(parent, &parent_fit_area);
177 
178     /*If the object is already out of the parent and its position is changes
179      *surely the scrollbars also changes so invalidate them*/
180     bool on1 = _lv_area_is_in(&ori, &parent_fit_area, 0);
181     if(!on1) lv_obj_scrollbar_invalidate(parent);
182 
183     /*Set the length and height
184      *Be sure the content is not scrolled in an invalid position on the new size*/
185     obj->coords.y2 = obj->coords.y1 + h - 1;
186     if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) {
187         obj->coords.x1 = obj->coords.x2 - w + 1;
188     }
189     else {
190         obj->coords.x2 = obj->coords.x1 + w - 1;
191     }
192 
193     /*Call the ancestor's event handler to the object with its new coordinates*/
194     lv_event_send(obj, LV_EVENT_SIZE_CHANGED, &ori);
195 
196     /*Call the ancestor's event handler to the parent too*/
197     lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj);
198 
199     /*Invalidate the new area*/
200     lv_obj_invalidate(obj);
201 
202     lv_obj_readjust_scroll(obj, LV_ANIM_OFF);
203 
204     /*If the object was out of the parent invalidate the new scrollbar area too.
205      *If it wasn't out of the parent but out now, also invalidate the scrollbars*/
206     bool on2 = _lv_area_is_in(&obj->coords, &parent_fit_area, 0);
207     if(on1 || (!on1 && on2)) lv_obj_scrollbar_invalidate(parent);
208 
209     return true;
210 }
211 
lv_obj_set_size(lv_obj_t * obj,lv_coord_t w,lv_coord_t h)212 void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h)
213 {
214     LV_ASSERT_OBJ(obj, MY_CLASS);
215 
216     lv_obj_set_width(obj, w);
217     lv_obj_set_height(obj, h);
218 }
219 
lv_obj_set_width(lv_obj_t * obj,lv_coord_t w)220 void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w)
221 {
222     LV_ASSERT_OBJ(obj, MY_CLASS);
223     lv_res_t res_w;
224     lv_style_value_t v_w;
225 
226     res_w = lv_obj_get_local_style_prop(obj, LV_STYLE_WIDTH, &v_w, 0);
227 
228     if((res_w == LV_RES_OK && v_w.num != w) || res_w == LV_RES_INV) {
229         lv_obj_set_style_width(obj, w, 0);
230     }
231 }
232 
lv_obj_set_height(lv_obj_t * obj,lv_coord_t h)233 void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h)
234 {
235     LV_ASSERT_OBJ(obj, MY_CLASS);
236     lv_res_t res_h;
237     lv_style_value_t v_h;
238 
239     res_h = lv_obj_get_local_style_prop(obj, LV_STYLE_HEIGHT, &v_h, 0);
240 
241     if((res_h == LV_RES_OK && v_h.num != h) || res_h == LV_RES_INV) {
242         lv_obj_set_style_height(obj, h, 0);
243     }
244 }
245 
lv_obj_set_content_width(lv_obj_t * obj,lv_coord_t w)246 void lv_obj_set_content_width(lv_obj_t * obj, lv_coord_t w)
247 {
248     lv_coord_t pleft = lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
249     lv_coord_t pright = lv_obj_get_style_pad_right(obj, LV_PART_MAIN);
250     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
251 
252     lv_obj_set_width(obj, w + pleft + pright + 2 * border_width);
253 }
254 
lv_obj_set_content_height(lv_obj_t * obj,lv_coord_t h)255 void lv_obj_set_content_height(lv_obj_t * obj, lv_coord_t h)
256 {
257     lv_coord_t ptop = lv_obj_get_style_pad_top(obj, LV_PART_MAIN);
258     lv_coord_t pbottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
259     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
260 
261     lv_obj_set_height(obj, h + ptop + pbottom + 2 * border_width);
262 }
263 
lv_obj_set_layout(lv_obj_t * obj,uint32_t layout)264 void lv_obj_set_layout(lv_obj_t * obj, uint32_t layout)
265 {
266     LV_ASSERT_OBJ(obj, MY_CLASS);
267 
268     lv_obj_set_style_layout(obj, layout, 0);
269 
270     lv_obj_mark_layout_as_dirty(obj);
271 }
272 
lv_obj_is_layout_positioned(const lv_obj_t * obj)273 bool lv_obj_is_layout_positioned(const lv_obj_t * obj)
274 {
275     if(lv_obj_has_flag_any(obj, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_IGNORE_LAYOUT | LV_OBJ_FLAG_FLOATING)) return false;
276 
277     lv_obj_t * parent = lv_obj_get_parent(obj);
278     if(parent == NULL) return false;
279 
280     uint32_t layout = lv_obj_get_style_layout(parent, LV_PART_MAIN);
281     if(layout) return true;
282     else return false;
283 }
284 
lv_obj_mark_layout_as_dirty(lv_obj_t * obj)285 void lv_obj_mark_layout_as_dirty(lv_obj_t * obj)
286 {
287     obj->layout_inv = 1;
288 
289     /*Mark the screen as dirty too to mark that there is something to do on this screen*/
290     lv_obj_t * scr = lv_obj_get_screen(obj);
291     scr->scr_layout_inv = 1;
292 
293     /*Make the display refreshing*/
294     lv_disp_t * disp = lv_obj_get_disp(scr);
295     if(disp->refr_timer) lv_timer_resume(disp->refr_timer);
296 }
297 
lv_obj_update_layout(const lv_obj_t * obj)298 void lv_obj_update_layout(const lv_obj_t * obj)
299 {
300     static bool mutex = false;
301     if(mutex) {
302         LV_LOG_TRACE("Already running, returning");
303         return;
304     }
305     mutex = true;
306 
307     lv_obj_t * scr = lv_obj_get_screen(obj);
308 
309     /*Repeat until there where layout invalidations*/
310     while(scr->scr_layout_inv) {
311         LV_LOG_INFO("Layout update begin");
312         scr->scr_layout_inv = 0;
313         layout_update_core(scr);
314         LV_LOG_TRACE("Layout update end");
315     }
316 
317     mutex = false;
318 }
319 
lv_layout_register(lv_layout_update_cb_t cb,void * user_data)320 uint32_t lv_layout_register(lv_layout_update_cb_t cb, void * user_data)
321 {
322     layout_cnt++;
323     LV_GC_ROOT(_lv_layout_list) = lv_mem_realloc(LV_GC_ROOT(_lv_layout_list), layout_cnt * sizeof(lv_layout_dsc_t));
324     LV_ASSERT_MALLOC(LV_GC_ROOT(_lv_layout_list));
325 
326     LV_GC_ROOT(_lv_layout_list)[layout_cnt - 1].cb = cb;
327     LV_GC_ROOT(_lv_layout_list)[layout_cnt - 1].user_data = user_data;
328     return layout_cnt;  /*No -1 to skip 0th index*/
329 }
330 
lv_obj_set_align(lv_obj_t * obj,lv_align_t align)331 void lv_obj_set_align(lv_obj_t * obj, lv_align_t align)
332 {
333     lv_obj_set_style_align(obj, align, 0);
334 }
335 
lv_obj_align(lv_obj_t * obj,lv_align_t align,lv_coord_t x_ofs,lv_coord_t y_ofs)336 void lv_obj_align(lv_obj_t * obj, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs)
337 {
338     lv_obj_set_style_align(obj, align, 0);
339     lv_obj_set_pos(obj, x_ofs, y_ofs);
340 }
341 
lv_obj_align_to(lv_obj_t * obj,const lv_obj_t * base,lv_align_t align,lv_coord_t x_ofs,lv_coord_t y_ofs)342 void lv_obj_align_to(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs)
343 {
344     LV_ASSERT_OBJ(obj, MY_CLASS);
345 
346     lv_obj_update_layout(obj);
347     if(base == NULL) base = lv_obj_get_parent(obj);
348 
349     LV_ASSERT_OBJ(base, MY_CLASS);
350 
351     lv_coord_t x = 0;
352     lv_coord_t y = 0;
353 
354     lv_obj_t * parent = lv_obj_get_parent(obj);
355     lv_coord_t pborder = lv_obj_get_style_border_width(parent, LV_PART_MAIN);
356     lv_coord_t pleft = lv_obj_get_style_pad_left(parent, LV_PART_MAIN) + pborder;
357     lv_coord_t ptop = lv_obj_get_style_pad_top(parent, LV_PART_MAIN) + pborder;
358 
359     lv_coord_t bborder = lv_obj_get_style_border_width(base, LV_PART_MAIN);
360     lv_coord_t bleft = lv_obj_get_style_pad_left(base, LV_PART_MAIN) + bborder;
361     lv_coord_t btop = lv_obj_get_style_pad_top(base, LV_PART_MAIN) + bborder;
362 
363     if(align == LV_ALIGN_DEFAULT) {
364         if(lv_obj_get_style_base_dir(base, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_ALIGN_TOP_RIGHT;
365         else align = LV_ALIGN_TOP_LEFT;
366     }
367 
368     switch(align) {
369         case LV_ALIGN_CENTER:
370             x = lv_obj_get_content_width(base) / 2 - lv_obj_get_width(obj) / 2 + bleft;
371             y = lv_obj_get_content_height(base) / 2 - lv_obj_get_height(obj) / 2 + btop;
372             break;
373         case LV_ALIGN_TOP_LEFT:
374             x = bleft;
375             y = btop;
376             break;
377         case LV_ALIGN_TOP_MID:
378             x = lv_obj_get_content_width(base) / 2 - lv_obj_get_width(obj) / 2 + bleft;
379             y = btop;
380             break;
381 
382         case LV_ALIGN_TOP_RIGHT:
383             x = lv_obj_get_content_width(base) - lv_obj_get_width(obj) + bleft;
384             y = btop;
385             break;
386 
387         case LV_ALIGN_BOTTOM_LEFT:
388             x = bleft;
389             y = lv_obj_get_content_height(base) - lv_obj_get_height(obj) + btop;
390             break;
391         case LV_ALIGN_BOTTOM_MID:
392             x = lv_obj_get_content_width(base) / 2 - lv_obj_get_width(obj) / 2 + bleft;
393             y = lv_obj_get_content_height(base) - lv_obj_get_height(obj) + btop;
394             break;
395 
396         case LV_ALIGN_BOTTOM_RIGHT:
397             x = lv_obj_get_content_width(base) - lv_obj_get_width(obj) + bleft;
398             y = lv_obj_get_content_height(base) - lv_obj_get_height(obj) + btop;
399             break;
400 
401         case LV_ALIGN_LEFT_MID:
402             x = bleft;
403             y = lv_obj_get_content_height(base) / 2 - lv_obj_get_height(obj) / 2 + btop;
404             break;
405 
406         case LV_ALIGN_RIGHT_MID:
407             x = lv_obj_get_content_width(base) - lv_obj_get_width(obj) + bleft;
408             y = lv_obj_get_content_height(base) / 2 - lv_obj_get_height(obj) / 2 + btop;
409             break;
410 
411         case LV_ALIGN_OUT_TOP_LEFT:
412             x = 0;
413             y = -lv_obj_get_height(obj);
414             break;
415 
416         case LV_ALIGN_OUT_TOP_MID:
417             x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;
418             y = -lv_obj_get_height(obj);
419             break;
420 
421         case LV_ALIGN_OUT_TOP_RIGHT:
422             x = lv_obj_get_width(base) - lv_obj_get_width(obj);
423             y = -lv_obj_get_height(obj);
424             break;
425 
426         case LV_ALIGN_OUT_BOTTOM_LEFT:
427             x = 0;
428             y = lv_obj_get_height(base);
429             break;
430 
431         case LV_ALIGN_OUT_BOTTOM_MID:
432             x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;
433             y = lv_obj_get_height(base);
434             break;
435 
436         case LV_ALIGN_OUT_BOTTOM_RIGHT:
437             x = lv_obj_get_width(base) - lv_obj_get_width(obj);
438             y = lv_obj_get_height(base);
439             break;
440 
441         case LV_ALIGN_OUT_LEFT_TOP:
442             x = -lv_obj_get_width(obj);
443             y = 0;
444             break;
445 
446         case LV_ALIGN_OUT_LEFT_MID:
447             x = -lv_obj_get_width(obj);
448             y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;
449             break;
450 
451         case LV_ALIGN_OUT_LEFT_BOTTOM:
452             x = -lv_obj_get_width(obj);
453             y = lv_obj_get_height(base) - lv_obj_get_height(obj);
454             break;
455 
456         case LV_ALIGN_OUT_RIGHT_TOP:
457             x = lv_obj_get_width(base);
458             y = 0;
459             break;
460 
461         case LV_ALIGN_OUT_RIGHT_MID:
462             x = lv_obj_get_width(base);
463             y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;
464             break;
465 
466         case LV_ALIGN_OUT_RIGHT_BOTTOM:
467             x = lv_obj_get_width(base);
468             y = lv_obj_get_height(base) - lv_obj_get_height(obj);
469             break;
470     }
471 
472     if(lv_obj_get_style_base_dir(parent, LV_PART_MAIN) == LV_BASE_DIR_RTL) {
473         x += x_ofs + base->coords.x1 - parent->coords.x1 + lv_obj_get_scroll_right(parent) - pleft;
474     }
475     else {
476         x += x_ofs + base->coords.x1 - parent->coords.x1 + lv_obj_get_scroll_left(parent) - pleft;
477     }
478     y += y_ofs + base->coords.y1 - parent->coords.y1 + lv_obj_get_scroll_top(parent) - ptop;
479     lv_obj_set_style_align(obj, LV_ALIGN_TOP_LEFT, 0);
480     lv_obj_set_pos(obj, x, y);
481 
482 }
483 
lv_obj_get_coords(const lv_obj_t * obj,lv_area_t * coords)484 void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * coords)
485 {
486     LV_ASSERT_OBJ(obj, MY_CLASS);
487 
488     lv_area_copy(coords, &obj->coords);
489 }
490 
lv_obj_get_x(const lv_obj_t * obj)491 lv_coord_t lv_obj_get_x(const lv_obj_t * obj)
492 {
493     LV_ASSERT_OBJ(obj, MY_CLASS);
494 
495     lv_coord_t rel_x;
496     lv_obj_t * parent = lv_obj_get_parent(obj);
497     if(parent) {
498         rel_x  = obj->coords.x1 - parent->coords.x1;
499         rel_x += lv_obj_get_scroll_x(parent);
500         rel_x -= lv_obj_get_style_pad_left(parent, LV_PART_MAIN);
501         rel_x -= lv_obj_get_style_border_width(parent, LV_PART_MAIN);
502     }
503     else {
504         rel_x = obj->coords.x1;
505     }
506     return rel_x;
507 }
508 
lv_obj_get_x2(const lv_obj_t * obj)509 lv_coord_t lv_obj_get_x2(const lv_obj_t * obj)
510 {
511     LV_ASSERT_OBJ(obj, MY_CLASS);
512 
513     return lv_obj_get_x(obj) + lv_obj_get_width(obj);
514 }
515 
lv_obj_get_y(const lv_obj_t * obj)516 lv_coord_t lv_obj_get_y(const lv_obj_t * obj)
517 {
518     LV_ASSERT_OBJ(obj, MY_CLASS);
519 
520     lv_coord_t rel_y;
521     lv_obj_t * parent = lv_obj_get_parent(obj);
522     if(parent) {
523         rel_y = obj->coords.y1 - parent->coords.y1;
524         rel_y += lv_obj_get_scroll_y(parent);
525         rel_y -= lv_obj_get_style_pad_top(parent, LV_PART_MAIN);
526         rel_y -= lv_obj_get_style_border_width(parent, LV_PART_MAIN);
527     }
528     else {
529         rel_y = obj->coords.y1;
530     }
531     return rel_y;
532 }
533 
lv_obj_get_y2(const lv_obj_t * obj)534 lv_coord_t lv_obj_get_y2(const lv_obj_t * obj)
535 {
536     LV_ASSERT_OBJ(obj, MY_CLASS);
537 
538     return lv_obj_get_y(obj) + lv_obj_get_height(obj);
539 }
540 
lv_obj_get_x_aligned(const lv_obj_t * obj)541 lv_coord_t lv_obj_get_x_aligned(const lv_obj_t * obj)
542 {
543     return lv_obj_get_style_x(obj, LV_PART_MAIN);
544 }
545 
lv_obj_get_y_aligned(const lv_obj_t * obj)546 lv_coord_t lv_obj_get_y_aligned(const lv_obj_t * obj)
547 {
548     return lv_obj_get_style_y(obj, LV_PART_MAIN);
549 }
550 
551 
lv_obj_get_width(const lv_obj_t * obj)552 lv_coord_t lv_obj_get_width(const lv_obj_t * obj)
553 {
554     LV_ASSERT_OBJ(obj, MY_CLASS);
555 
556     return lv_area_get_width(&obj->coords);
557 }
558 
lv_obj_get_height(const lv_obj_t * obj)559 lv_coord_t lv_obj_get_height(const lv_obj_t * obj)
560 {
561     LV_ASSERT_OBJ(obj, MY_CLASS);
562 
563     return lv_area_get_height(&obj->coords);
564 }
565 
lv_obj_get_content_width(const lv_obj_t * obj)566 lv_coord_t lv_obj_get_content_width(const lv_obj_t * obj)
567 {
568     LV_ASSERT_OBJ(obj, MY_CLASS);
569 
570     lv_coord_t left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
571     lv_coord_t right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN);
572     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
573 
574     return lv_obj_get_width(obj) - left - right - 2 * border_width;
575 }
576 
lv_obj_get_content_height(const lv_obj_t * obj)577 lv_coord_t lv_obj_get_content_height(const lv_obj_t * obj)
578 {
579     LV_ASSERT_OBJ(obj, MY_CLASS);
580 
581     lv_coord_t top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN);
582     lv_coord_t bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
583     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
584 
585     return lv_obj_get_height(obj) - top - bottom - 2 * border_width;
586 }
587 
lv_obj_get_content_coords(const lv_obj_t * obj,lv_area_t * area)588 void lv_obj_get_content_coords(const lv_obj_t * obj, lv_area_t * area)
589 {
590     LV_ASSERT_OBJ(obj, MY_CLASS);
591     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
592 
593     lv_obj_get_coords(obj, area);
594     lv_area_increase(area, -border_width, -border_width);
595     area->x1 += lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
596     area->x2 -= lv_obj_get_style_pad_right(obj, LV_PART_MAIN);
597     area->y1 += lv_obj_get_style_pad_top(obj, LV_PART_MAIN);
598     area->y2 -= lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
599 
600 }
601 
lv_obj_get_self_width(const lv_obj_t * obj)602 lv_coord_t lv_obj_get_self_width(const lv_obj_t * obj)
603 {
604     lv_point_t p = {0, LV_COORD_MIN};
605     lv_event_send((lv_obj_t *)obj, LV_EVENT_GET_SELF_SIZE, &p);
606     return p.x;
607 }
608 
lv_obj_get_self_height(const lv_obj_t * obj)609 lv_coord_t lv_obj_get_self_height(const lv_obj_t * obj)
610 {
611     lv_point_t p = {LV_COORD_MIN, 0};
612     lv_event_send((lv_obj_t *)obj, LV_EVENT_GET_SELF_SIZE, &p);
613     return p.y;
614 }
615 
lv_obj_refresh_self_size(lv_obj_t * obj)616 bool lv_obj_refresh_self_size(lv_obj_t * obj)
617 {
618     lv_coord_t w_set = lv_obj_get_style_width(obj, LV_PART_MAIN);
619     lv_coord_t h_set = lv_obj_get_style_height(obj, LV_PART_MAIN);
620     if(w_set != LV_SIZE_CONTENT && h_set != LV_SIZE_CONTENT) return false;
621 
622     lv_obj_mark_layout_as_dirty(obj);
623     return true;
624 }
625 
lv_obj_refr_pos(lv_obj_t * obj)626 void lv_obj_refr_pos(lv_obj_t * obj)
627 {
628     if(lv_obj_is_layout_positioned(obj)) return;
629 
630     lv_obj_t * parent = lv_obj_get_parent(obj);
631     lv_coord_t x = lv_obj_get_style_x(obj, LV_PART_MAIN);
632     lv_coord_t y = lv_obj_get_style_y(obj, LV_PART_MAIN);
633 
634     if(parent == NULL) {
635         lv_obj_move_to(obj, x, y);
636         return;
637     }
638 
639     /*Handle percentage value*/
640     lv_coord_t pw = lv_obj_get_content_width(parent);
641     lv_coord_t ph = lv_obj_get_content_height(parent);
642     if(LV_COORD_IS_PCT(x)) x = (pw * LV_COORD_GET_PCT(x)) / 100;
643     if(LV_COORD_IS_PCT(y)) y = (ph * LV_COORD_GET_PCT(y)) / 100;
644 
645     /*Handle percentage value of translate*/
646     lv_coord_t tr_x = lv_obj_get_style_translate_x(obj, LV_PART_MAIN);
647     lv_coord_t tr_y = lv_obj_get_style_translate_y(obj, LV_PART_MAIN);
648     lv_coord_t w = lv_obj_get_width(obj);
649     lv_coord_t h = lv_obj_get_height(obj);
650     if(LV_COORD_IS_PCT(tr_x)) tr_x = (w * LV_COORD_GET_PCT(tr_x)) / 100;
651     if(LV_COORD_IS_PCT(tr_y)) tr_y = (h * LV_COORD_GET_PCT(tr_y)) / 100;
652 
653     /*Use the translation*/
654     x += tr_x;
655     y += tr_y;
656 
657     lv_align_t align = lv_obj_get_style_align(obj, LV_PART_MAIN);
658 
659     if(align == LV_ALIGN_DEFAULT) {
660         if(lv_obj_get_style_base_dir(parent, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_ALIGN_TOP_RIGHT;
661         else align = LV_ALIGN_TOP_LEFT;
662     }
663 
664     if(align == LV_ALIGN_TOP_LEFT) {
665         lv_obj_move_to(obj, x, y);
666     }
667     else {
668 
669         switch(align) {
670             case LV_ALIGN_TOP_MID:
671                 x += pw / 2 - w / 2;
672                 break;
673             case LV_ALIGN_TOP_RIGHT:
674                 x += pw - w;
675                 break;
676             case LV_ALIGN_LEFT_MID:
677                 y += ph / 2 - h / 2;
678                 break;
679             case LV_ALIGN_BOTTOM_LEFT:
680                 y += ph - h;
681                 break;
682             case LV_ALIGN_BOTTOM_MID:
683                 x += pw / 2 - w / 2;
684                 y += ph - h;
685                 break;
686             case LV_ALIGN_BOTTOM_RIGHT:
687                 x += pw - w;
688                 y += ph - h;
689                 break;
690             case LV_ALIGN_RIGHT_MID:
691                 x += pw - w;
692                 y += ph / 2 - h / 2;
693                 break;
694             case LV_ALIGN_CENTER:
695                 x += pw / 2 - w / 2;
696                 y += ph / 2 - h / 2;
697                 break;
698             default:
699                 break;
700         }
701         lv_obj_move_to(obj, x, y);
702     }
703 }
704 
lv_obj_move_to(lv_obj_t * obj,lv_coord_t x,lv_coord_t y)705 void lv_obj_move_to(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
706 {
707     /*Convert x and y to absolute coordinates*/
708     lv_obj_t * parent = obj->parent;
709 
710     if(parent) {
711         lv_coord_t pad_left = lv_obj_get_style_pad_left(parent, LV_PART_MAIN);
712         lv_coord_t pad_top = lv_obj_get_style_pad_top(parent, LV_PART_MAIN);
713 
714         if(lv_obj_has_flag(obj, LV_OBJ_FLAG_FLOATING)) {
715             x += pad_left + parent->coords.x1;
716             y += pad_top + parent->coords.y1;
717         }
718         else {
719             x += pad_left + parent->coords.x1 - lv_obj_get_scroll_x(parent);
720             y += pad_top + parent->coords.y1 - lv_obj_get_scroll_y(parent);
721         }
722 
723         lv_coord_t border_width = lv_obj_get_style_border_width(parent, LV_PART_MAIN);
724         x += border_width;
725         y += border_width;
726     }
727 
728     /*Calculate and set the movement*/
729     lv_point_t diff;
730     diff.x = x - obj->coords.x1;
731     diff.y = y - obj->coords.y1;
732 
733     /*Do nothing if the position is not changed*/
734     /*It is very important else recursive positioning can
735      *occur without position change*/
736     if(diff.x == 0 && diff.y == 0) return;
737 
738     /*Invalidate the original area*/
739     lv_obj_invalidate(obj);
740 
741     /*Save the original coordinates*/
742     lv_area_t ori;
743     lv_obj_get_coords(obj, &ori);
744 
745     /*Check if the object inside the parent or not*/
746     lv_area_t parent_fit_area;
747     bool on1 = false;
748     if(parent) {
749         lv_obj_get_content_coords(parent, &parent_fit_area);
750 
751         /*If the object is already out of the parent and its position is changes
752          *surely the scrollbars also changes so invalidate them*/
753         on1 = _lv_area_is_in(&ori, &parent_fit_area, 0);
754         if(!on1) lv_obj_scrollbar_invalidate(parent);
755     }
756 
757     obj->coords.x1 += diff.x;
758     obj->coords.y1 += diff.y;
759     obj->coords.x2 += diff.x;
760     obj->coords.y2 += diff.y;
761 
762     lv_obj_move_children_by(obj, diff.x, diff.y, false);
763 
764     /*Call the ancestor's event handler to the parent too*/
765     if(parent) lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj);
766 
767     /*Invalidate the new area*/
768     lv_obj_invalidate(obj);
769 
770     /*If the object was out of the parent invalidate the new scrollbar area too.
771      *If it wasn't out of the parent but out now, also invalidate the srollbars*/
772     if(parent) {
773         bool on2 = _lv_area_is_in(&obj->coords, &parent_fit_area, 0);
774         if(on1 || (!on1 && on2)) lv_obj_scrollbar_invalidate(parent);
775     }
776 }
777 
lv_obj_move_children_by(lv_obj_t * obj,lv_coord_t x_diff,lv_coord_t y_diff,bool ignore_floating)778 void lv_obj_move_children_by(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff, bool ignore_floating)
779 {
780     uint32_t i;
781     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
782     for(i = 0; i < child_cnt; i++) {
783         lv_obj_t * child = obj->spec_attr->children[i];
784         if(ignore_floating && lv_obj_has_flag(child, LV_OBJ_FLAG_FLOATING)) continue;
785         child->coords.x1 += x_diff;
786         child->coords.y1 += y_diff;
787         child->coords.x2 += x_diff;
788         child->coords.y2 += y_diff;
789 
790         lv_obj_move_children_by(child, x_diff, y_diff, false);
791     }
792 }
793 
794 
lv_obj_invalidate_area(const lv_obj_t * obj,const lv_area_t * area)795 void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area)
796 {
797     LV_ASSERT_OBJ(obj, MY_CLASS);
798 
799     lv_area_t area_tmp;
800     lv_area_copy(&area_tmp, area);
801     bool visible = lv_obj_area_is_visible(obj, &area_tmp);
802 
803     if(visible) _lv_inv_area(lv_obj_get_disp(obj), &area_tmp);
804 }
805 
lv_obj_invalidate(const lv_obj_t * obj)806 void lv_obj_invalidate(const lv_obj_t * obj)
807 {
808     LV_ASSERT_OBJ(obj, MY_CLASS);
809 
810     /*If the object has overflow visible it can be drawn anywhere on its parent
811      *It needs to be checked recursively*/
812     while(lv_obj_get_parent(obj) && lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
813         obj = lv_obj_get_parent(obj);
814     }
815 
816     /*Truncate the area to the object*/
817     lv_area_t obj_coords;
818     lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
819     lv_area_copy(&obj_coords, &obj->coords);
820     obj_coords.x1 -= ext_size;
821     obj_coords.y1 -= ext_size;
822     obj_coords.x2 += ext_size;
823     obj_coords.y2 += ext_size;
824 
825     lv_obj_invalidate_area(obj, &obj_coords);
826 
827 }
828 
lv_obj_area_is_visible(const lv_obj_t * obj,lv_area_t * area)829 bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area)
830 {
831     if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return false;
832 
833     /*Invalidate the object only if it belongs to the current or previous or one of the layers'*/
834     lv_obj_t * obj_scr = lv_obj_get_screen(obj);
835     lv_disp_t * disp   = lv_obj_get_disp(obj_scr);
836     if(obj_scr != lv_disp_get_scr_act(disp) &&
837        obj_scr != lv_disp_get_scr_prev(disp) &&
838        obj_scr != lv_disp_get_layer_top(disp) &&
839        obj_scr != lv_disp_get_layer_sys(disp)) {
840         return false;
841     }
842 
843     /*Truncate the area to the object*/
844     if(!lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
845         lv_area_t obj_coords;
846         lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
847         lv_area_copy(&obj_coords, &obj->coords);
848         obj_coords.x1 -= ext_size;
849         obj_coords.y1 -= ext_size;
850         obj_coords.x2 += ext_size;
851         obj_coords.y2 += ext_size;
852 
853         /*The area is not on the object*/
854         if(!_lv_area_intersect(area, area, &obj_coords)) return false;
855     }
856 
857     /*Truncate recursively to the parents*/
858     lv_obj_t * par = lv_obj_get_parent(obj);
859     while(par != NULL) {
860         /*If the parent is hidden then the child is hidden and won't be drawn*/
861         if(lv_obj_has_flag(par, LV_OBJ_FLAG_HIDDEN)) return false;
862 
863         /*Truncate to the parent and if no common parts break*/
864         if(!lv_obj_has_flag(par, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
865             if(!_lv_area_intersect(area, area, &par->coords)) return false;
866         }
867 
868         par = lv_obj_get_parent(par);
869     }
870 
871     return true;
872 }
873 
lv_obj_is_visible(const lv_obj_t * obj)874 bool lv_obj_is_visible(const lv_obj_t * obj)
875 {
876     LV_ASSERT_OBJ(obj, MY_CLASS);
877 
878     lv_area_t obj_coords;
879     lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
880     lv_area_copy(&obj_coords, &obj->coords);
881     obj_coords.x1 -= ext_size;
882     obj_coords.y1 -= ext_size;
883     obj_coords.x2 += ext_size;
884     obj_coords.y2 += ext_size;
885 
886     return lv_obj_area_is_visible(obj, &obj_coords);
887 
888 }
889 
lv_obj_set_ext_click_area(lv_obj_t * obj,lv_coord_t size)890 void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t size)
891 {
892     LV_ASSERT_OBJ(obj, MY_CLASS);
893 
894     lv_obj_allocate_spec_attr(obj);
895     obj->spec_attr->ext_click_pad = size;
896 }
897 
lv_obj_get_click_area(const lv_obj_t * obj,lv_area_t * area)898 void lv_obj_get_click_area(const lv_obj_t * obj, lv_area_t * area)
899 {
900     lv_area_copy(area, &obj->coords);
901     if(obj->spec_attr) {
902         area->x1 -= obj->spec_attr->ext_click_pad;
903         area->x2 += obj->spec_attr->ext_click_pad;
904         area->y1 -= obj->spec_attr->ext_click_pad;
905         area->y2 += obj->spec_attr->ext_click_pad;
906     }
907 }
908 
lv_obj_hit_test(lv_obj_t * obj,const lv_point_t * point)909 bool lv_obj_hit_test(lv_obj_t * obj, const lv_point_t * point)
910 {
911     if(!lv_obj_has_flag(obj, LV_OBJ_FLAG_CLICKABLE)) return false;
912     if(lv_obj_has_state(obj, LV_STATE_DISABLED)) return false;
913 
914     lv_area_t a;
915     lv_obj_get_click_area(obj, &a);
916     bool res = _lv_area_is_point_on(&a, point, 0);
917     if(res == false) return false;
918 
919     if(lv_obj_has_flag(obj, LV_OBJ_FLAG_ADV_HITTEST)) {
920         lv_hit_test_info_t hit_info;
921         hit_info.point = point;
922         hit_info.res = true;
923         lv_event_send(obj, LV_EVENT_HIT_TEST, &hit_info);
924         return hit_info.res;
925     }
926 
927     return res;
928 }
929 
lv_clamp_width(lv_coord_t width,lv_coord_t min_width,lv_coord_t max_width,lv_coord_t ref_width)930 lv_coord_t lv_clamp_width(lv_coord_t width, lv_coord_t min_width, lv_coord_t max_width, lv_coord_t ref_width)
931 {
932     if(LV_COORD_IS_PCT(min_width)) min_width = (ref_width * LV_COORD_GET_PCT(min_width)) / 100;
933     if(LV_COORD_IS_PCT(max_width)) max_width = (ref_width * LV_COORD_GET_PCT(max_width)) / 100;
934     return LV_CLAMP(min_width, width, max_width);
935 }
936 
lv_clamp_height(lv_coord_t height,lv_coord_t min_height,lv_coord_t max_height,lv_coord_t ref_height)937 lv_coord_t lv_clamp_height(lv_coord_t height, lv_coord_t min_height, lv_coord_t max_height, lv_coord_t ref_height)
938 {
939     if(LV_COORD_IS_PCT(min_height)) min_height = (ref_height * LV_COORD_GET_PCT(min_height)) / 100;
940     if(LV_COORD_IS_PCT(max_height)) max_height = (ref_height * LV_COORD_GET_PCT(max_height)) / 100;
941     return LV_CLAMP(min_height, height, max_height);
942 }
943 
944 
945 
946 /**********************
947  *   STATIC FUNCTIONS
948  **********************/
949 
calc_content_width(lv_obj_t * obj)950 static lv_coord_t calc_content_width(lv_obj_t * obj)
951 {
952     lv_obj_scroll_to_x(obj, 0, LV_ANIM_OFF);
953 
954     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
955     lv_coord_t pad_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN) + border_width;
956     lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width;
957 
958     lv_coord_t self_w;
959     self_w = lv_obj_get_self_width(obj) +  pad_left + pad_right;
960 
961     lv_coord_t child_res = LV_COORD_MIN;
962     uint32_t i;
963     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
964     /*With RTL find the left most coordinate*/
965     if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) {
966         for(i = 0; i < child_cnt; i++) {
967             lv_obj_t * child = obj->spec_attr->children[i];
968             if(lv_obj_has_flag_any(child,  LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
969 
970             if(!lv_obj_is_layout_positioned(child)) {
971                 lv_align_t align = lv_obj_get_style_align(child, 0);
972                 switch(align) {
973                     case LV_ALIGN_DEFAULT:
974                     case LV_ALIGN_TOP_RIGHT:
975                     case LV_ALIGN_BOTTOM_RIGHT:
976                     case LV_ALIGN_RIGHT_MID:
977                         /*Normal right aligns. Other are ignored due to possible circular dependencies*/
978                         child_res = LV_MAX(child_res, obj->coords.x2 - child->coords.x1 + 1);
979                         break;
980                     default:
981                         /* Consider other cases only if x=0 and use the width of the object.
982                          * With x!=0 circular dependency could occur. */
983                         if(lv_obj_get_style_x(child, 0) == 0) {
984                             child_res = LV_MAX(child_res, lv_area_get_width(&child->coords) + pad_right);
985                         }
986                 }
987             }
988             else {
989                 child_res = LV_MAX(child_res, obj->coords.x2 - child->coords.x1 + 1);
990             }
991         }
992         if(child_res != LV_COORD_MIN) {
993             child_res += pad_left;
994         }
995     }
996     /*Else find the right most coordinate*/
997     else {
998         for(i = 0; i < child_cnt; i++) {
999             lv_obj_t * child = obj->spec_attr->children[i];
1000             if(lv_obj_has_flag_any(child,  LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
1001 
1002             if(!lv_obj_is_layout_positioned(child)) {
1003                 lv_align_t align = lv_obj_get_style_align(child, 0);
1004                 switch(align) {
1005                     case LV_ALIGN_DEFAULT:
1006                     case LV_ALIGN_TOP_LEFT:
1007                     case LV_ALIGN_BOTTOM_LEFT:
1008                     case LV_ALIGN_LEFT_MID:
1009                         /*Normal left aligns.*/
1010                         child_res = LV_MAX(child_res, child->coords.x2 - obj->coords.x1 + 1);
1011                         break;
1012                     default:
1013                         /* Consider other cases only if x=0 and use the width of the object.
1014                          * With x!=0 circular dependency could occur. */
1015                         if(lv_obj_get_style_y(child, 0) == 0) {
1016                             child_res = LV_MAX(child_res, lv_area_get_width(&child->coords) + pad_left);
1017                         }
1018                 }
1019             }
1020             else {
1021                 child_res = LV_MAX(child_res, child->coords.x2 - obj->coords.x1 + 1);
1022             }
1023         }
1024 
1025         if(child_res != LV_COORD_MIN) {
1026             child_res += pad_right;
1027         }
1028     }
1029 
1030     if(child_res == LV_COORD_MIN) return self_w;
1031     else return LV_MAX(child_res, self_w);
1032 }
1033 
calc_content_height(lv_obj_t * obj)1034 static lv_coord_t calc_content_height(lv_obj_t * obj)
1035 {
1036     lv_obj_scroll_to_y(obj, 0, LV_ANIM_OFF);
1037 
1038     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
1039     lv_coord_t pad_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN) + border_width;
1040     lv_coord_t pad_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN) + border_width;
1041 
1042     lv_coord_t self_h;
1043     self_h = lv_obj_get_self_height(obj) + pad_top + pad_bottom;
1044 
1045     lv_coord_t child_res = LV_COORD_MIN;
1046     uint32_t i;
1047     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
1048     for(i = 0; i < child_cnt; i++) {
1049         lv_obj_t * child = obj->spec_attr->children[i];
1050         if(lv_obj_has_flag_any(child,  LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
1051 
1052 
1053         if(!lv_obj_is_layout_positioned(child)) {
1054             lv_align_t align = lv_obj_get_style_align(child, 0);
1055             switch(align) {
1056                 case LV_ALIGN_DEFAULT:
1057                 case LV_ALIGN_TOP_RIGHT:
1058                 case LV_ALIGN_TOP_MID:
1059                 case LV_ALIGN_TOP_LEFT:
1060                     /*Normal top aligns. */
1061                     child_res = LV_MAX(child_res, child->coords.y2 - obj->coords.y1 + 1);
1062                     break;
1063                 default:
1064                     /* Consider other cases only if y=0 and use the height of the object.
1065                      * With y!=0 circular dependency could occur. */
1066                     if(lv_obj_get_style_y(child, 0) == 0) {
1067                         child_res = LV_MAX(child_res, lv_area_get_height(&child->coords) + pad_top);
1068                     }
1069                     break;
1070             }
1071         }
1072         else {
1073             child_res = LV_MAX(child_res, child->coords.y2 - obj->coords.y1 + 1);
1074         }
1075     }
1076 
1077     if(child_res != LV_COORD_MIN) {
1078         child_res += pad_bottom;
1079         return LV_MAX(child_res, self_h);
1080     }
1081     else {
1082         return self_h;
1083     }
1084 
1085 }
1086 
layout_update_core(lv_obj_t * obj)1087 static void layout_update_core(lv_obj_t * obj)
1088 {
1089     uint32_t i;
1090     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
1091     for(i = 0; i < child_cnt; i++) {
1092         lv_obj_t * child = obj->spec_attr->children[i];
1093         layout_update_core(child);
1094     }
1095 
1096     if(obj->layout_inv == 0) return;
1097 
1098     obj->layout_inv = 0;
1099 
1100     lv_obj_refr_size(obj);
1101     lv_obj_refr_pos(obj);
1102 
1103     if(child_cnt > 0) {
1104         uint32_t layout_id = lv_obj_get_style_layout(obj, LV_PART_MAIN);
1105         if(layout_id > 0 && layout_id <= layout_cnt) {
1106             void  * user_data = LV_GC_ROOT(_lv_layout_list)[layout_id - 1].user_data;
1107             LV_GC_ROOT(_lv_layout_list)[layout_id - 1].cb(obj, user_data);
1108         }
1109     }
1110 }
1111