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