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 
554 
lv_obj_get_width(const lv_obj_t * obj)555 lv_coord_t lv_obj_get_width(const lv_obj_t * obj)
556 {
557     LV_ASSERT_OBJ(obj, MY_CLASS);
558 
559     return lv_area_get_width(&obj->coords);
560 }
561 
lv_obj_get_height(const lv_obj_t * obj)562 lv_coord_t lv_obj_get_height(const lv_obj_t * obj)
563 {
564     LV_ASSERT_OBJ(obj, MY_CLASS);
565 
566     return lv_area_get_height(&obj->coords);
567 }
568 
lv_obj_get_content_width(const lv_obj_t * obj)569 lv_coord_t lv_obj_get_content_width(const lv_obj_t * obj)
570 {
571     LV_ASSERT_OBJ(obj, MY_CLASS);
572 
573     lv_coord_t left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
574     lv_coord_t right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN);
575     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
576 
577     return lv_obj_get_width(obj) - left - right - 2 * border_width;
578 }
579 
lv_obj_get_content_height(const lv_obj_t * obj)580 lv_coord_t lv_obj_get_content_height(const lv_obj_t * obj)
581 {
582     LV_ASSERT_OBJ(obj, MY_CLASS);
583 
584     lv_coord_t top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN);
585     lv_coord_t bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
586     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
587 
588     return lv_obj_get_height(obj) - top - bottom - 2 * border_width;
589 }
590 
lv_obj_get_content_coords(const lv_obj_t * obj,lv_area_t * area)591 void lv_obj_get_content_coords(const lv_obj_t * obj, lv_area_t * area)
592 {
593     LV_ASSERT_OBJ(obj, MY_CLASS);
594     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
595 
596     lv_obj_get_coords(obj, area);
597     lv_area_increase(area, -border_width, -border_width);
598     area->x1 += lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
599     area->x2 -= lv_obj_get_style_pad_right(obj, LV_PART_MAIN);
600     area->y1 += lv_obj_get_style_pad_top(obj, LV_PART_MAIN);
601     area->y2 -= lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
602 
603 }
604 
lv_obj_get_self_width(const lv_obj_t * obj)605 lv_coord_t lv_obj_get_self_width(const lv_obj_t * obj)
606 {
607     lv_point_t p = {0, LV_COORD_MIN};
608     lv_event_send((lv_obj_t *)obj, LV_EVENT_GET_SELF_SIZE, &p);
609     return p.x;
610 }
611 
lv_obj_get_self_height(const lv_obj_t * obj)612 lv_coord_t lv_obj_get_self_height(const lv_obj_t * obj)
613 {
614     lv_point_t p = {LV_COORD_MIN, 0};
615     lv_event_send((lv_obj_t *)obj, LV_EVENT_GET_SELF_SIZE, &p);
616     return p.y;
617 }
618 
lv_obj_refresh_self_size(lv_obj_t * obj)619 bool lv_obj_refresh_self_size(lv_obj_t * obj)
620 {
621     lv_coord_t w_set = lv_obj_get_style_width(obj, LV_PART_MAIN);
622     lv_coord_t h_set = lv_obj_get_style_height(obj, LV_PART_MAIN);
623     if(w_set != LV_SIZE_CONTENT && h_set != LV_SIZE_CONTENT) return false;
624 
625     lv_obj_mark_layout_as_dirty(obj);
626     return true;
627 }
628 
lv_obj_refr_pos(lv_obj_t * obj)629 void lv_obj_refr_pos(lv_obj_t * obj)
630 {
631     if(lv_obj_is_layout_positioned(obj)) return;
632 
633 
634     lv_obj_t * parent = lv_obj_get_parent(obj);
635     lv_coord_t x = lv_obj_get_style_x(obj, LV_PART_MAIN);
636     lv_coord_t y = lv_obj_get_style_y(obj, LV_PART_MAIN);
637 
638     if(parent == NULL) {
639         lv_obj_move_to(obj, x, y);
640         return;
641     }
642 
643     /*Handle percentage value*/
644     lv_coord_t pw = lv_obj_get_content_width(parent);
645     lv_coord_t ph = lv_obj_get_content_height(parent);
646     if(LV_COORD_IS_PCT(x)) x = (pw * LV_COORD_GET_PCT(x)) / 100;
647     if(LV_COORD_IS_PCT(y)) y = (ph * LV_COORD_GET_PCT(y)) / 100;
648 
649     /*Handle percentage value of translate*/
650     lv_coord_t tr_x = lv_obj_get_style_translate_x(obj, LV_PART_MAIN);
651     lv_coord_t tr_y = lv_obj_get_style_translate_y(obj, LV_PART_MAIN);
652     lv_coord_t w = lv_obj_get_width(obj);
653     lv_coord_t h = lv_obj_get_height(obj);
654     if(LV_COORD_IS_PCT(tr_x)) tr_x = (w * LV_COORD_GET_PCT(tr_x)) / 100;
655     if(LV_COORD_IS_PCT(tr_y)) tr_y = (h * LV_COORD_GET_PCT(tr_y)) / 100;
656 
657     /*Use the translation*/
658     x += tr_x;
659     y += tr_y;
660 
661     lv_align_t align = lv_obj_get_style_align(obj, LV_PART_MAIN);
662 
663     if(align == LV_ALIGN_DEFAULT) {
664         if(lv_obj_get_style_base_dir(parent, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_ALIGN_TOP_RIGHT;
665         else align = LV_ALIGN_TOP_LEFT;
666     }
667 
668     if(align == LV_ALIGN_TOP_LEFT) {
669         lv_obj_move_to(obj, x, y);
670     }
671     else {
672 
673         switch(align) {
674             case LV_ALIGN_TOP_MID:
675                 x += pw / 2 - w / 2;
676                 break;
677             case LV_ALIGN_TOP_RIGHT:
678                 x += pw - w;
679                 break;
680             case LV_ALIGN_LEFT_MID:
681                 y += ph / 2 - h / 2;
682                 break;
683             case LV_ALIGN_BOTTOM_LEFT:
684                 y += ph - h;
685                 break;
686             case LV_ALIGN_BOTTOM_MID:
687                 x += pw / 2 - w / 2;
688                 y += ph - h;
689                 break;
690             case LV_ALIGN_BOTTOM_RIGHT:
691                 x += pw - w;
692                 y += ph - h;
693                 break;
694             case LV_ALIGN_RIGHT_MID:
695                 x += pw - w;
696                 y += ph / 2 - h / 2;
697                 break;
698             case LV_ALIGN_CENTER:
699                 x += pw / 2 - w / 2;
700                 y += ph / 2 - h / 2;
701                 break;
702             default:
703                 break;
704         }
705         lv_obj_move_to(obj, x, y);
706     }
707 }
708 
lv_obj_move_to(lv_obj_t * obj,lv_coord_t x,lv_coord_t y)709 void lv_obj_move_to(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
710 {
711     /*Convert x and y to absolute coordinates*/
712     lv_obj_t * parent = obj->parent;
713 
714     if(parent) {
715         lv_coord_t pad_left = lv_obj_get_style_pad_left(parent, LV_PART_MAIN);
716         lv_coord_t pad_top = lv_obj_get_style_pad_top(parent, LV_PART_MAIN);
717 
718         if(lv_obj_has_flag(obj, LV_OBJ_FLAG_FLOATING)) {
719             x += pad_left + parent->coords.x1;
720             y += pad_top + parent->coords.y1;
721         }
722         else {
723             x += pad_left + parent->coords.x1 - lv_obj_get_scroll_x(parent);
724             y += pad_top + parent->coords.y1 - lv_obj_get_scroll_y(parent);
725         }
726 
727         lv_coord_t border_width = lv_obj_get_style_border_width(parent, LV_PART_MAIN);
728         x += border_width;
729         y += border_width;
730     }
731 
732     /*Calculate and set the movement*/
733     lv_point_t diff;
734     diff.x = x - obj->coords.x1;
735     diff.y = y - obj->coords.y1;
736 
737     /*Do nothing if the position is not changed*/
738     /*It is very important else recursive positioning can
739      *occur without position change*/
740     if(diff.x == 0 && diff.y == 0) return;
741 
742     /*Invalidate the original area*/
743     lv_obj_invalidate(obj);
744 
745     /*Save the original coordinates*/
746     lv_area_t ori;
747     lv_obj_get_coords(obj, &ori);
748 
749     /*Check if the object inside the parent or not*/
750     lv_area_t parent_fit_area;
751     bool on1 = false;
752     if(parent) {
753         lv_obj_get_content_coords(parent, &parent_fit_area);
754 
755         /*If the object is already out of the parent and its position is changes
756          *surely the scrollbars also changes so invalidate them*/
757         on1 = _lv_area_is_in(&ori, &parent_fit_area, 0);
758         if(!on1) lv_obj_scrollbar_invalidate(parent);
759     }
760 
761     obj->coords.x1 += diff.x;
762     obj->coords.y1 += diff.y;
763     obj->coords.x2 += diff.x;
764     obj->coords.y2 += diff.y;
765 
766     lv_obj_move_children_by(obj, diff.x, diff.y, false);
767 
768     /*Call the ancestor's event handler to the parent too*/
769     if(parent) lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj);
770 
771     /*Invalidate the new area*/
772     lv_obj_invalidate(obj);
773 
774     /*If the object was out of the parent invalidate the new scrollbar area too.
775      *If it wasn't out of the parent but out now, also invalidate the srollbars*/
776     if(parent) {
777         bool on2 = _lv_area_is_in(&obj->coords, &parent_fit_area, 0);
778         if(on1 || (!on1 && on2)) lv_obj_scrollbar_invalidate(parent);
779     }
780 }
781 
lv_obj_move_children_by(lv_obj_t * obj,lv_coord_t x_diff,lv_coord_t y_diff,bool ignore_floating)782 void lv_obj_move_children_by(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff, bool ignore_floating)
783 {
784     uint32_t i;
785     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
786     for(i = 0; i < child_cnt; i++) {
787         lv_obj_t * child = obj->spec_attr->children[i];
788         if(ignore_floating && lv_obj_has_flag(child, LV_OBJ_FLAG_FLOATING)) continue;
789         child->coords.x1 += x_diff;
790         child->coords.y1 += y_diff;
791         child->coords.x2 += x_diff;
792         child->coords.y2 += y_diff;
793 
794         lv_obj_move_children_by(child, x_diff, y_diff, false);
795     }
796 }
797 
lv_obj_transform_point(const lv_obj_t * obj,lv_point_t * p,bool recursive,bool inv)798 void lv_obj_transform_point(const lv_obj_t * obj, lv_point_t * p, bool recursive, bool inv)
799 {
800     if(obj) {
801         lv_layer_type_t layer_type = _lv_obj_get_layer_type(obj);
802         bool do_tranf = layer_type == LV_LAYER_TYPE_TRANSFORM;
803         if(inv) {
804             if(recursive) lv_obj_transform_point(lv_obj_get_parent(obj), p, recursive, inv);
805             if(do_tranf) transform_point(obj, p, inv);
806         }
807         else {
808             if(do_tranf) transform_point(obj, p, inv);
809             if(recursive) lv_obj_transform_point(lv_obj_get_parent(obj), p, recursive, inv);
810         }
811     }
812 }
813 
lv_obj_get_transformed_area(const lv_obj_t * obj,lv_area_t * area,bool recursive,bool inv)814 void lv_obj_get_transformed_area(const lv_obj_t * obj, lv_area_t * area, bool recursive,
815                                  bool inv)
816 {
817     lv_point_t p[4] = {
818         {area->x1, area->y1},
819         {area->x1, area->y2},
820         {area->x2, area->y1},
821         {area->x2, area->y2},
822     };
823 
824     lv_obj_transform_point(obj, &p[0], recursive, inv);
825     lv_obj_transform_point(obj, &p[1], recursive, inv);
826     lv_obj_transform_point(obj, &p[2], recursive, inv);
827     lv_obj_transform_point(obj, &p[3], recursive, inv);
828 
829     area->x1 = LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x);
830     area->x2 = LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x);
831     area->y1 = LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y);
832     area->y2 = LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y);
833     lv_area_increase(area, 5, 5);
834 }
835 
836 
lv_obj_invalidate_area(const lv_obj_t * obj,const lv_area_t * area)837 void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area)
838 {
839     LV_ASSERT_OBJ(obj, MY_CLASS);
840 
841     lv_disp_t * disp   = lv_obj_get_disp(obj);
842     if(!lv_disp_is_invalidation_enabled(disp)) return;
843 
844     lv_area_t area_tmp;
845     lv_area_copy(&area_tmp, area);
846     if(!lv_obj_area_is_visible(obj, &area_tmp)) return;
847 
848     _lv_inv_area(lv_obj_get_disp(obj),  &area_tmp);
849 }
850 
lv_obj_invalidate(const lv_obj_t * obj)851 void lv_obj_invalidate(const lv_obj_t * obj)
852 {
853     LV_ASSERT_OBJ(obj, MY_CLASS);
854 
855     /*Truncate the area to the object*/
856     lv_area_t obj_coords;
857     lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
858     lv_area_copy(&obj_coords, &obj->coords);
859     obj_coords.x1 -= ext_size;
860     obj_coords.y1 -= ext_size;
861     obj_coords.x2 += ext_size;
862     obj_coords.y2 += ext_size;
863 
864     lv_obj_invalidate_area(obj, &obj_coords);
865 
866 }
867 
lv_obj_area_is_visible(const lv_obj_t * obj,lv_area_t * area)868 bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area)
869 {
870     if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return false;
871 
872     /*Invalidate the object only if it belongs to the current or previous or one of the layers'*/
873     lv_obj_t * obj_scr = lv_obj_get_screen(obj);
874     lv_disp_t * disp   = lv_obj_get_disp(obj_scr);
875     if(obj_scr != lv_disp_get_scr_act(disp) &&
876        obj_scr != lv_disp_get_scr_prev(disp) &&
877        obj_scr != lv_disp_get_layer_top(disp) &&
878        obj_scr != lv_disp_get_layer_sys(disp)) {
879         return false;
880     }
881 
882     /*Truncate the area to the object*/
883     if(!lv_obj_has_flag_any(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
884         lv_area_t obj_coords;
885         lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
886         lv_area_copy(&obj_coords, &obj->coords);
887         obj_coords.x1 -= ext_size;
888         obj_coords.y1 -= ext_size;
889         obj_coords.x2 += ext_size;
890         obj_coords.y2 += ext_size;
891 
892         /*The area is not on the object*/
893         if(!_lv_area_intersect(area, area, &obj_coords)) return false;
894     }
895 
896     lv_obj_get_transformed_area(obj, area, true, false);
897 
898 
899     /*Truncate recursively to the parents*/
900     lv_obj_t * par = lv_obj_get_parent(obj);
901     while(par != NULL) {
902         /*If the parent is hidden then the child is hidden and won't be drawn*/
903         if(lv_obj_has_flag(par, LV_OBJ_FLAG_HIDDEN)) return false;
904 
905         /*Truncate to the parent and if no common parts break*/
906         if(!lv_obj_has_flag_any(par, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
907             lv_area_t par_area = par->coords;
908             lv_obj_get_transformed_area(par, &par_area, true, false);
909             if(!_lv_area_intersect(area, area, &par_area)) return false;
910         }
911 
912         par = lv_obj_get_parent(par);
913     }
914 
915     return true;
916 }
917 
lv_obj_is_visible(const lv_obj_t * obj)918 bool lv_obj_is_visible(const lv_obj_t * obj)
919 {
920     LV_ASSERT_OBJ(obj, MY_CLASS);
921 
922     lv_area_t obj_coords;
923     lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
924     lv_area_copy(&obj_coords, &obj->coords);
925     obj_coords.x1 -= ext_size;
926     obj_coords.y1 -= ext_size;
927     obj_coords.x2 += ext_size;
928     obj_coords.y2 += ext_size;
929 
930     return lv_obj_area_is_visible(obj, &obj_coords);
931 
932 }
933 
lv_obj_set_ext_click_area(lv_obj_t * obj,lv_coord_t size)934 void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t size)
935 {
936     LV_ASSERT_OBJ(obj, MY_CLASS);
937 
938     lv_obj_allocate_spec_attr(obj);
939     obj->spec_attr->ext_click_pad = size;
940 }
941 
lv_obj_get_click_area(const lv_obj_t * obj,lv_area_t * area)942 void lv_obj_get_click_area(const lv_obj_t * obj, lv_area_t * area)
943 {
944     lv_area_copy(area, &obj->coords);
945     if(obj->spec_attr) {
946         area->x1 -= obj->spec_attr->ext_click_pad;
947         area->x2 += obj->spec_attr->ext_click_pad;
948         area->y1 -= obj->spec_attr->ext_click_pad;
949         area->y2 += obj->spec_attr->ext_click_pad;
950     }
951 }
952 
lv_obj_hit_test(lv_obj_t * obj,const lv_point_t * point)953 bool lv_obj_hit_test(lv_obj_t * obj, const lv_point_t * point)
954 {
955     if(!lv_obj_has_flag(obj, LV_OBJ_FLAG_CLICKABLE)) return false;
956     if(lv_obj_has_state(obj, LV_STATE_DISABLED)) return false;
957 
958     lv_area_t a;
959     lv_obj_get_click_area(obj, &a);
960     bool res = _lv_area_is_point_on(&a, point, 0);
961     if(res == false) return false;
962 
963     if(lv_obj_has_flag(obj, LV_OBJ_FLAG_ADV_HITTEST)) {
964         lv_hit_test_info_t hit_info;
965         hit_info.point = point;
966         hit_info.res = true;
967         lv_event_send(obj, LV_EVENT_HIT_TEST, &hit_info);
968         return hit_info.res;
969     }
970 
971     return res;
972 }
973 
lv_clamp_width(lv_coord_t width,lv_coord_t min_width,lv_coord_t max_width,lv_coord_t ref_width)974 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)
975 {
976     if(LV_COORD_IS_PCT(min_width)) min_width = (ref_width * LV_COORD_GET_PCT(min_width)) / 100;
977     if(LV_COORD_IS_PCT(max_width)) max_width = (ref_width * LV_COORD_GET_PCT(max_width)) / 100;
978     return LV_CLAMP(min_width, width, max_width);
979 }
980 
lv_clamp_height(lv_coord_t height,lv_coord_t min_height,lv_coord_t max_height,lv_coord_t ref_height)981 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)
982 {
983     if(LV_COORD_IS_PCT(min_height)) min_height = (ref_height * LV_COORD_GET_PCT(min_height)) / 100;
984     if(LV_COORD_IS_PCT(max_height)) max_height = (ref_height * LV_COORD_GET_PCT(max_height)) / 100;
985     return LV_CLAMP(min_height, height, max_height);
986 }
987 
988 
989 
990 /**********************
991  *   STATIC FUNCTIONS
992  **********************/
993 
calc_content_width(lv_obj_t * obj)994 static lv_coord_t calc_content_width(lv_obj_t * obj)
995 {
996     lv_obj_scroll_to_x(obj, 0, LV_ANIM_OFF);
997 
998     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
999     lv_coord_t pad_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN) + border_width;
1000     lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width;
1001 
1002     lv_coord_t self_w;
1003     self_w = lv_obj_get_self_width(obj) +  pad_left + pad_right;
1004 
1005     lv_coord_t child_res = LV_COORD_MIN;
1006     uint32_t i;
1007     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
1008     /*With RTL find the left most coordinate*/
1009     if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) {
1010         for(i = 0; i < child_cnt; i++) {
1011             lv_obj_t * child = obj->spec_attr->children[i];
1012             if(lv_obj_has_flag_any(child,  LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
1013 
1014             if(!lv_obj_is_layout_positioned(child)) {
1015                 lv_align_t align = lv_obj_get_style_align(child, 0);
1016                 switch(align) {
1017                     case LV_ALIGN_DEFAULT:
1018                     case LV_ALIGN_TOP_RIGHT:
1019                     case LV_ALIGN_BOTTOM_RIGHT:
1020                     case LV_ALIGN_RIGHT_MID:
1021                         /*Normal right aligns. Other are ignored due to possible circular dependencies*/
1022                         child_res = LV_MAX(child_res, obj->coords.x2 - child->coords.x1 + 1);
1023                         break;
1024                     default:
1025                         /* Consider other cases only if x=0 and use the width of the object.
1026                          * With x!=0 circular dependency could occur. */
1027                         if(lv_obj_get_style_x(child, 0) == 0) {
1028                             child_res = LV_MAX(child_res, lv_area_get_width(&child->coords) + pad_right);
1029                         }
1030                 }
1031             }
1032             else {
1033                 child_res = LV_MAX(child_res, obj->coords.x2 - child->coords.x1 + 1);
1034             }
1035         }
1036         if(child_res != LV_COORD_MIN) {
1037             child_res += pad_left;
1038         }
1039     }
1040     /*Else find the right most coordinate*/
1041     else {
1042         for(i = 0; i < child_cnt; i++) {
1043             lv_obj_t * child = obj->spec_attr->children[i];
1044             if(lv_obj_has_flag_any(child,  LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
1045 
1046             if(!lv_obj_is_layout_positioned(child)) {
1047                 lv_align_t align = lv_obj_get_style_align(child, 0);
1048                 switch(align) {
1049                     case LV_ALIGN_DEFAULT:
1050                     case LV_ALIGN_TOP_LEFT:
1051                     case LV_ALIGN_BOTTOM_LEFT:
1052                     case LV_ALIGN_LEFT_MID:
1053                         /*Normal left aligns.*/
1054                         child_res = LV_MAX(child_res, child->coords.x2 - obj->coords.x1 + 1);
1055                         break;
1056                     default:
1057                         /* Consider other cases only if x=0 and use the width of the object.
1058                          * With x!=0 circular dependency could occur. */
1059                         if(lv_obj_get_style_y(child, 0) == 0) {
1060                             child_res = LV_MAX(child_res, lv_area_get_width(&child->coords) + pad_left);
1061                         }
1062                 }
1063             }
1064             else {
1065                 child_res = LV_MAX(child_res, child->coords.x2 - obj->coords.x1 + 1);
1066             }
1067         }
1068 
1069         if(child_res != LV_COORD_MIN) {
1070             child_res += pad_right;
1071         }
1072     }
1073 
1074     if(child_res == LV_COORD_MIN) return self_w;
1075     else return LV_MAX(child_res, self_w);
1076 }
1077 
calc_content_height(lv_obj_t * obj)1078 static lv_coord_t calc_content_height(lv_obj_t * obj)
1079 {
1080     lv_obj_scroll_to_y(obj, 0, LV_ANIM_OFF);
1081 
1082     lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
1083     lv_coord_t pad_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN) + border_width;
1084     lv_coord_t pad_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN) + border_width;
1085 
1086     lv_coord_t self_h;
1087     self_h = lv_obj_get_self_height(obj) + pad_top + pad_bottom;
1088 
1089     lv_coord_t child_res = LV_COORD_MIN;
1090     uint32_t i;
1091     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
1092     for(i = 0; i < child_cnt; i++) {
1093         lv_obj_t * child = obj->spec_attr->children[i];
1094         if(lv_obj_has_flag_any(child,  LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
1095 
1096 
1097         if(!lv_obj_is_layout_positioned(child)) {
1098             lv_align_t align = lv_obj_get_style_align(child, 0);
1099             switch(align) {
1100                 case LV_ALIGN_DEFAULT:
1101                 case LV_ALIGN_TOP_RIGHT:
1102                 case LV_ALIGN_TOP_MID:
1103                 case LV_ALIGN_TOP_LEFT:
1104                     /*Normal top aligns. */
1105                     child_res = LV_MAX(child_res, child->coords.y2 - obj->coords.y1 + 1);
1106                     break;
1107                 default:
1108                     /* Consider other cases only if y=0 and use the height of the object.
1109                      * With y!=0 circular dependency could occur. */
1110                     if(lv_obj_get_style_y(child, 0) == 0) {
1111                         child_res = LV_MAX(child_res, lv_area_get_height(&child->coords) + pad_top);
1112                     }
1113                     break;
1114             }
1115         }
1116         else {
1117             child_res = LV_MAX(child_res, child->coords.y2 - obj->coords.y1 + 1);
1118         }
1119     }
1120 
1121     if(child_res != LV_COORD_MIN) {
1122         child_res += pad_bottom;
1123         return LV_MAX(child_res, self_h);
1124     }
1125     else {
1126         return self_h;
1127     }
1128 
1129 }
1130 
layout_update_core(lv_obj_t * obj)1131 static void layout_update_core(lv_obj_t * obj)
1132 {
1133     uint32_t i;
1134     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
1135     for(i = 0; i < child_cnt; i++) {
1136         lv_obj_t * child = obj->spec_attr->children[i];
1137         layout_update_core(child);
1138     }
1139 
1140     if(obj->layout_inv) {
1141         obj->layout_inv = 0;
1142         lv_obj_refr_size(obj);
1143         lv_obj_refr_pos(obj);
1144 
1145         if(child_cnt > 0) {
1146             uint32_t layout_id = lv_obj_get_style_layout(obj, LV_PART_MAIN);
1147             if(layout_id > 0 && layout_id <= layout_cnt) {
1148                 void  * user_data = LV_GC_ROOT(_lv_layout_list)[layout_id - 1].user_data;
1149                 LV_GC_ROOT(_lv_layout_list)[layout_id - 1].cb(obj, user_data);
1150             }
1151         }
1152     }
1153 
1154     if(obj->readjust_scroll_after_layout) {
1155         obj->readjust_scroll_after_layout = 0;
1156         lv_obj_readjust_scroll(obj, LV_ANIM_OFF);
1157     }
1158 }
1159 
transform_point(const lv_obj_t * obj,lv_point_t * p,bool inv)1160 static void transform_point(const lv_obj_t * obj, lv_point_t * p, bool inv)
1161 {
1162     int16_t angle = lv_obj_get_style_transform_angle(obj, 0);
1163     int16_t zoom = lv_obj_get_style_transform_zoom(obj, 0);
1164 
1165     if(angle == 0 && zoom == LV_IMG_ZOOM_NONE) return;
1166 
1167     lv_point_t pivot = {
1168         .x = lv_obj_get_style_transform_pivot_x(obj, 0),
1169         .y = lv_obj_get_style_transform_pivot_y(obj, 0)
1170     };
1171 
1172     if(LV_COORD_IS_PCT(pivot.x)) {
1173         pivot.x = (LV_COORD_GET_PCT(pivot.x) * lv_area_get_width(&obj->coords)) / 100;
1174     }
1175     if(LV_COORD_IS_PCT(pivot.y)) {
1176         pivot.y = (LV_COORD_GET_PCT(pivot.y) * lv_area_get_height(&obj->coords)) / 100;
1177     }
1178 
1179     pivot.x = obj->coords.x1 + pivot.x;
1180     pivot.y = obj->coords.y1 + pivot.y;
1181 
1182     if(inv) {
1183         angle = -angle;
1184         zoom = (256 * 256) / zoom;
1185     }
1186 
1187     lv_point_transform(p, angle, zoom, &pivot);
1188 }
1189