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