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