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