1 /**
2 * @file lv_grid.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_grid.h"
10
11 #if LV_USE_GRID
12
13 #include "../../stdlib/lv_string.h"
14 #include "../lv_layout.h"
15 #include "../../core/lv_obj_private.h"
16 #include "../../core/lv_global.h"
17 /*********************
18 * DEFINES
19 *********************/
20 #define layout_list_def LV_GLOBAL_DEFAULT()->layout_list
21
22 /**
23 * Some helper defines
24 */
25 #define IS_FR(x) (x >= LV_COORD_MAX - 100)
26 #define IS_CONTENT(x) (x == LV_COORD_MAX - 101)
27 #define GET_FR(x) (x - (LV_COORD_MAX - 100))
28
29 /**********************
30 * TYPEDEFS
31 **********************/
32 typedef struct {
33 uint32_t col;
34 uint32_t row;
35 lv_point_t grid_abs;
36 } item_repos_hint_t;
37
38 typedef struct {
39 int32_t * x;
40 int32_t * y;
41 int32_t * w;
42 int32_t * h;
43 uint32_t col_num;
44 uint32_t row_num;
45 int32_t grid_w;
46 int32_t grid_h;
47 } lv_grid_calc_t;
48
49 /**********************
50 * GLOBAL PROTOTYPES
51 **********************/
52
53 /**********************
54 * STATIC PROTOTYPES
55 **********************/
56 static void grid_update(lv_obj_t * cont, void * user_data);
57 static void calc(lv_obj_t * obj, lv_grid_calc_t * calc);
58 static void calc_free(lv_grid_calc_t * calc);
59 static void calc_cols(lv_obj_t * cont, lv_grid_calc_t * c);
60 static void calc_rows(lv_obj_t * cont, lv_grid_calc_t * c);
61 static void item_repos(lv_obj_t * item, lv_grid_calc_t * c, item_repos_hint_t * hint);
62 static int32_t grid_align(int32_t cont_size, bool auto_size, lv_grid_align_t align, int32_t gap,
63 uint32_t track_num,
64 int32_t * size_array, int32_t * pos_array, bool reverse);
65 static uint32_t count_tracks(const int32_t * templ);
66
get_col_dsc(lv_obj_t * obj)67 static inline const int32_t * get_col_dsc(lv_obj_t * obj)
68 {
69 return lv_obj_get_style_grid_column_dsc_array(obj, 0);
70 }
get_row_dsc(lv_obj_t * obj)71 static inline const int32_t * get_row_dsc(lv_obj_t * obj)
72 {
73 return lv_obj_get_style_grid_row_dsc_array(obj, 0);
74 }
get_col_pos(lv_obj_t * obj)75 static inline int32_t get_col_pos(lv_obj_t * obj)
76 {
77 return lv_obj_get_style_grid_cell_column_pos(obj, 0);
78 }
get_row_pos(lv_obj_t * obj)79 static inline int32_t get_row_pos(lv_obj_t * obj)
80 {
81 return lv_obj_get_style_grid_cell_row_pos(obj, 0);
82 }
get_col_span(lv_obj_t * obj)83 static inline int32_t get_col_span(lv_obj_t * obj)
84 {
85 return lv_obj_get_style_grid_cell_column_span(obj, 0);
86 }
get_row_span(lv_obj_t * obj)87 static inline int32_t get_row_span(lv_obj_t * obj)
88 {
89 return lv_obj_get_style_grid_cell_row_span(obj, 0);
90 }
get_cell_col_align(lv_obj_t * obj)91 static inline lv_grid_align_t get_cell_col_align(lv_obj_t * obj)
92 {
93 return lv_obj_get_style_grid_cell_x_align(obj, 0);
94 }
get_cell_row_align(lv_obj_t * obj)95 static inline lv_grid_align_t get_cell_row_align(lv_obj_t * obj)
96 {
97 return lv_obj_get_style_grid_cell_y_align(obj, 0);
98 }
get_grid_col_align(lv_obj_t * obj)99 static inline lv_grid_align_t get_grid_col_align(lv_obj_t * obj)
100 {
101 return lv_obj_get_style_grid_column_align(obj, 0);
102 }
get_grid_row_align(lv_obj_t * obj)103 static inline lv_grid_align_t get_grid_row_align(lv_obj_t * obj)
104 {
105 return lv_obj_get_style_grid_row_align(obj, 0);
106 }
get_margin_hor(lv_obj_t * obj)107 static inline int32_t get_margin_hor(lv_obj_t * obj)
108 {
109 return lv_obj_get_style_margin_left(obj, LV_PART_MAIN)
110 + lv_obj_get_style_margin_right(obj, LV_PART_MAIN);
111 }
get_margin_ver(lv_obj_t * obj)112 static inline int32_t get_margin_ver(lv_obj_t * obj)
113 {
114 return lv_obj_get_style_margin_top(obj, LV_PART_MAIN)
115 + lv_obj_get_style_margin_bottom(obj, LV_PART_MAIN);
116 }
117
lv_div_round_closest(int32_t dividend,int32_t divisor)118 static inline int32_t lv_div_round_closest(int32_t dividend, int32_t divisor)
119 {
120 return (dividend + divisor / 2) / divisor;
121 }
122
123 /**********************
124 * GLOBAL VARIABLES
125 **********************/
126
127 /**********************
128 * STATIC VARIABLES
129 **********************/
130
131 /**********************
132 * MACROS
133 **********************/
134 #if LV_USE_LOG && LV_LOG_TRACE_LAYOUT
135 #define LV_TRACE_LAYOUT(...) LV_LOG_TRACE(__VA_ARGS__)
136 #else
137 #define LV_TRACE_LAYOUT(...)
138 #endif
139
140 /**********************
141 * GLOBAL FUNCTIONS
142 **********************/
143
lv_grid_init(void)144 void lv_grid_init(void)
145 {
146 layout_list_def[LV_LAYOUT_GRID].cb = grid_update;
147 layout_list_def[LV_LAYOUT_GRID].user_data = NULL;
148 }
149
lv_obj_set_grid_dsc_array(lv_obj_t * obj,const int32_t col_dsc[],const int32_t row_dsc[])150 void lv_obj_set_grid_dsc_array(lv_obj_t * obj, const int32_t col_dsc[], const int32_t row_dsc[])
151 {
152 lv_obj_set_style_grid_column_dsc_array(obj, col_dsc, 0);
153 lv_obj_set_style_grid_row_dsc_array(obj, row_dsc, 0);
154 lv_obj_set_style_layout(obj, LV_LAYOUT_GRID, 0);
155 }
156
lv_obj_set_grid_align(lv_obj_t * obj,lv_grid_align_t column_align,lv_grid_align_t row_align)157 void lv_obj_set_grid_align(lv_obj_t * obj, lv_grid_align_t column_align, lv_grid_align_t row_align)
158 {
159 lv_obj_set_style_grid_column_align(obj, column_align, 0);
160 lv_obj_set_style_grid_row_align(obj, row_align, 0);
161
162 }
163
lv_obj_set_grid_cell(lv_obj_t * obj,lv_grid_align_t x_align,int32_t col_pos,int32_t col_span,lv_grid_align_t y_align,int32_t row_pos,int32_t row_span)164 void lv_obj_set_grid_cell(lv_obj_t * obj, lv_grid_align_t x_align, int32_t col_pos, int32_t col_span,
165 lv_grid_align_t y_align, int32_t row_pos, int32_t row_span)
166
167 {
168 lv_obj_set_style_grid_cell_column_pos(obj, col_pos, 0);
169 lv_obj_set_style_grid_cell_row_pos(obj, row_pos, 0);
170 lv_obj_set_style_grid_cell_x_align(obj, x_align, 0);
171 lv_obj_set_style_grid_cell_column_span(obj, col_span, 0);
172 lv_obj_set_style_grid_cell_row_span(obj, row_span, 0);
173 lv_obj_set_style_grid_cell_y_align(obj, y_align, 0);
174
175 lv_obj_mark_layout_as_dirty(lv_obj_get_parent(obj));
176 }
177
lv_grid_fr(uint8_t x)178 int32_t lv_grid_fr(uint8_t x)
179 {
180 return LV_GRID_FR(x);
181 }
182
183 /**********************
184 * STATIC FUNCTIONS
185 **********************/
186
grid_update(lv_obj_t * cont,void * user_data)187 static void grid_update(lv_obj_t * cont, void * user_data)
188 {
189 LV_LOG_INFO("update %p container", (void *)cont);
190 LV_UNUSED(user_data);
191
192 // const int32_t * col_templ = get_col_dsc(cont);
193 // const int32_t * row_templ = get_row_dsc(cont);
194 // if(col_templ == NULL || row_templ == NULL) return;
195
196 lv_grid_calc_t c;
197 calc(cont, &c);
198
199 item_repos_hint_t hint;
200 lv_memzero(&hint, sizeof(hint));
201
202 /*Calculate the grids absolute x and y coordinates.
203 *It will be used as helper during item repositioning to avoid calculating this value for every children*/
204 int32_t pad_left = lv_obj_get_style_space_left(cont, LV_PART_MAIN);
205 int32_t pad_top = lv_obj_get_style_space_top(cont, LV_PART_MAIN);
206 hint.grid_abs.x = pad_left + cont->coords.x1 - lv_obj_get_scroll_x(cont);
207 hint.grid_abs.y = pad_top + cont->coords.y1 - lv_obj_get_scroll_y(cont);
208
209 uint32_t i;
210 for(i = 0; i < cont->spec_attr->child_cnt; i++) {
211 lv_obj_t * item = cont->spec_attr->children[i];
212 item_repos(item, &c, &hint);
213 }
214 calc_free(&c);
215
216 int32_t w_set = lv_obj_get_style_width(cont, LV_PART_MAIN);
217 int32_t h_set = lv_obj_get_style_height(cont, LV_PART_MAIN);
218 if(w_set == LV_SIZE_CONTENT || h_set == LV_SIZE_CONTENT) {
219 lv_obj_refr_size(cont);
220 }
221
222 lv_obj_send_event(cont, LV_EVENT_LAYOUT_CHANGED, NULL);
223
224 LV_TRACE_LAYOUT("finished");
225 }
226
227 /**
228 * Calculate the grid cells coordinates
229 * @param cont an object that has a grid
230 * @param calc store the calculated cells sizes here
231 * @note `lv_grid_calc_free(calc_out)` needs to be called when `calc_out` is not needed anymore
232 */
calc(lv_obj_t * cont,lv_grid_calc_t * calc_out)233 static void calc(lv_obj_t * cont, lv_grid_calc_t * calc_out)
234 {
235 if(lv_obj_get_child(cont, 0) == NULL) {
236 lv_memzero(calc_out, sizeof(lv_grid_calc_t));
237 return;
238 }
239
240 calc_rows(cont, calc_out);
241 calc_cols(cont, calc_out);
242
243 int32_t col_gap = lv_obj_get_style_pad_column(cont, LV_PART_MAIN);
244 int32_t row_gap = lv_obj_get_style_pad_row(cont, LV_PART_MAIN);
245
246 bool rev = lv_obj_get_style_base_dir(cont, LV_PART_MAIN) == LV_BASE_DIR_RTL;
247
248 int32_t w_set = lv_obj_get_style_width(cont, LV_PART_MAIN);
249 int32_t h_set = lv_obj_get_style_height(cont, LV_PART_MAIN);
250 bool auto_w = w_set == LV_SIZE_CONTENT && !cont->w_layout;
251 int32_t cont_w = lv_obj_get_content_width(cont);
252 calc_out->grid_w = grid_align(cont_w, auto_w, get_grid_col_align(cont), col_gap, calc_out->col_num, calc_out->w,
253 calc_out->x, rev);
254
255 bool auto_h = h_set == LV_SIZE_CONTENT && !cont->h_layout;
256 int32_t cont_h = lv_obj_get_content_height(cont);
257 calc_out->grid_h = grid_align(cont_h, auto_h, get_grid_row_align(cont), row_gap, calc_out->row_num, calc_out->h,
258 calc_out->y, false);
259
260 LV_ASSERT_MEM_INTEGRITY();
261 }
262
263 /**
264 * Free the a grid calculation's data
265 * @param calc pointer to the calculated grid cell coordinates
266 */
calc_free(lv_grid_calc_t * calc)267 static void calc_free(lv_grid_calc_t * calc)
268 {
269 lv_free(calc->x);
270 lv_free(calc->y);
271 lv_free(calc->w);
272 lv_free(calc->h);
273 }
274
calc_cols(lv_obj_t * cont,lv_grid_calc_t * c)275 static void calc_cols(lv_obj_t * cont, lv_grid_calc_t * c)
276 {
277
278 const int32_t * col_templ;
279 col_templ = get_col_dsc(cont);
280 bool subgrid = false;
281 if(col_templ == NULL) {
282 lv_obj_t * parent = lv_obj_get_parent(cont);
283 col_templ = get_col_dsc(parent);
284 if(col_templ == NULL) {
285 LV_LOG_WARN("No col descriptor found even on the parent");
286 return;
287 }
288
289 int32_t pos = get_col_pos(cont);
290 int32_t span = get_col_span(cont);
291
292 int32_t * col_templ_sub = lv_malloc(sizeof(int32_t) * (span + 1));
293 lv_memcpy(col_templ_sub, &col_templ[pos], sizeof(int32_t) * span);
294 col_templ_sub[span] = LV_GRID_TEMPLATE_LAST;
295 col_templ = col_templ_sub;
296 subgrid = true;
297 }
298
299 int32_t cont_w = lv_obj_get_content_width(cont);
300
301 c->col_num = count_tracks(col_templ);
302 c->x = lv_malloc(sizeof(int32_t) * c->col_num);
303 c->w = lv_malloc(sizeof(int32_t) * c->col_num);
304
305 /*Set sizes for CONTENT cells*/
306 uint32_t i;
307 for(i = 0; i < c->col_num; i++) {
308 int32_t size = LV_COORD_MIN;
309 if(IS_CONTENT(col_templ[i])) {
310 /*Check the size of children of this cell*/
311 uint32_t ci;
312 for(ci = 0; ci < lv_obj_get_child_count(cont); ci++) {
313 lv_obj_t * item = lv_obj_get_child(cont, ci);
314 if(lv_obj_has_flag_any(item, LV_OBJ_FLAG_IGNORE_LAYOUT | LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
315 uint32_t col_span = get_col_span(item);
316 if(col_span != 1) continue;
317
318 uint32_t col_pos = get_col_pos(item);
319 if(col_pos != i) continue;
320
321 size = LV_MAX(size, lv_obj_get_width(item));
322 }
323 if(size >= 0) c->w[i] = size;
324 else c->w[i] = 0;
325 }
326 }
327
328 uint32_t col_fr_cnt = 0;
329 int32_t grid_w = 0;
330
331 for(i = 0; i < c->col_num; i++) {
332 int32_t x = col_templ[i];
333 if(IS_FR(x)) {
334 col_fr_cnt += GET_FR(x);
335 }
336 else if(IS_CONTENT(x)) {
337 grid_w += c->w[i];
338 }
339 else {
340 c->w[i] = x;
341 grid_w += x;
342 }
343 }
344
345 int32_t col_gap = lv_obj_get_style_pad_column(cont, LV_PART_MAIN);
346 cont_w -= col_gap * (c->col_num - 1);
347 int32_t free_w = cont_w - grid_w;
348 if(free_w < 0) free_w = 0;
349
350 for(i = 0; i < c->col_num && col_fr_cnt; i++) {
351 int32_t x = col_templ[i];
352 if(IS_FR(x)) {
353 int32_t f = GET_FR(x);
354 c->w[i] = lv_div_round_closest(free_w * f, col_fr_cnt);
355 /*By updating remaining fr and width, we ensure f == col_fr_cnt
356 *in the last loop iteration. That means the last iteration will
357 *not have rounding errors and use all remaining space.*/
358 col_fr_cnt -= f;
359 free_w -= c->w[i];
360 }
361 }
362
363 if(subgrid) {
364 lv_free((void *)col_templ);
365 }
366 }
367
calc_rows(lv_obj_t * cont,lv_grid_calc_t * c)368 static void calc_rows(lv_obj_t * cont, lv_grid_calc_t * c)
369 {
370 const int32_t * row_templ;
371 row_templ = get_row_dsc(cont);
372 bool subgrid = false;
373 if(row_templ == NULL) {
374 lv_obj_t * parent = lv_obj_get_parent(cont);
375 row_templ = get_row_dsc(parent);
376 if(row_templ == NULL) {
377 LV_LOG_WARN("No row descriptor found even on the parent");
378 return;
379 }
380
381 int32_t pos = get_row_pos(cont);
382 int32_t span = get_row_span(cont);
383
384 int32_t * row_templ_sub = lv_malloc(sizeof(int32_t) * (span + 1));
385 lv_memcpy(row_templ_sub, &row_templ[pos], sizeof(int32_t) * span);
386 row_templ_sub[span] = LV_GRID_TEMPLATE_LAST;
387 row_templ = row_templ_sub;
388 subgrid = true;
389 }
390
391 c->row_num = count_tracks(row_templ);
392 c->y = lv_malloc(sizeof(int32_t) * c->row_num);
393 c->h = lv_malloc(sizeof(int32_t) * c->row_num);
394 /*Set sizes for CONTENT cells*/
395 uint32_t i;
396 for(i = 0; i < c->row_num; i++) {
397 int32_t size = LV_COORD_MIN;
398 if(IS_CONTENT(row_templ[i])) {
399 /*Check the size of children of this cell*/
400 uint32_t ci;
401 for(ci = 0; ci < lv_obj_get_child_count(cont); ci++) {
402 lv_obj_t * item = lv_obj_get_child(cont, ci);
403 if(lv_obj_has_flag_any(item, LV_OBJ_FLAG_IGNORE_LAYOUT | LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
404 uint32_t row_span = get_row_span(item);
405 if(row_span != 1) continue;
406
407 uint32_t row_pos = get_row_pos(item);
408 if(row_pos != i) continue;
409
410 size = LV_MAX(size, lv_obj_get_height(item));
411 }
412 if(size >= 0) c->h[i] = size;
413 else c->h[i] = 0;
414 }
415 }
416
417 uint32_t row_fr_cnt = 0;
418 int32_t grid_h = 0;
419
420 for(i = 0; i < c->row_num; i++) {
421 int32_t x = row_templ[i];
422 if(IS_FR(x)) {
423 row_fr_cnt += GET_FR(x);
424 }
425 else if(IS_CONTENT(x)) {
426 grid_h += c->h[i];
427 }
428 else {
429 c->h[i] = x;
430 grid_h += x;
431 }
432 }
433
434 int32_t row_gap = lv_obj_get_style_pad_row(cont, LV_PART_MAIN);
435 int32_t cont_h = lv_obj_get_content_height(cont) - row_gap * (c->row_num - 1);
436 int32_t free_h = cont_h - grid_h;
437 if(free_h < 0) free_h = 0;
438
439 for(i = 0; i < c->row_num && row_fr_cnt; i++) {
440 int32_t x = row_templ[i];
441 if(IS_FR(x)) {
442 int32_t f = GET_FR(x);
443 c->h[i] = lv_div_round_closest(free_h * f, row_fr_cnt);
444 /*By updating remaining fr and height, we ensure f == row_fr_cnt
445 *in the last loop iteration. That means the last iteration will
446 *not have rounding errors and use all remaining space.*/
447 row_fr_cnt -= f;
448 free_h -= c->h[i];
449 }
450 }
451
452 if(subgrid) {
453 lv_free((void *)row_templ);
454 }
455 }
456
457 /**
458 * Reposition a grid item in its cell
459 * @param item a grid item to reposition
460 * @param calc the calculated grid of `cont`
461 * @param child_id_ext helper value if the ID of the child is know (order from the oldest) else -1
462 * @param grid_abs helper value, the absolute position of the grid, NULL if unknown
463 */
item_repos(lv_obj_t * item,lv_grid_calc_t * c,item_repos_hint_t * hint)464 static void item_repos(lv_obj_t * item, lv_grid_calc_t * c, item_repos_hint_t * hint)
465 {
466 if(lv_obj_has_flag_any(item, LV_OBJ_FLAG_IGNORE_LAYOUT | LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) return;
467 uint32_t col_span = get_col_span(item);
468 uint32_t row_span = get_row_span(item);
469 if(row_span == 0 || col_span == 0) return;
470
471 uint32_t col_pos = get_col_pos(item);
472 uint32_t row_pos = get_row_pos(item);
473 lv_grid_align_t col_align = get_cell_col_align(item);
474 lv_grid_align_t row_align = get_cell_row_align(item);
475
476 int32_t col_x1 = c->x[col_pos];
477 int32_t col_x2 = c->x[col_pos + col_span - 1] + c->w[col_pos + col_span - 1];
478 int32_t col_w = col_x2 - col_x1;
479
480 int32_t row_y1 = c->y[row_pos];
481 int32_t row_y2 = c->y[row_pos + row_span - 1] + c->h[row_pos + row_span - 1];
482 int32_t row_h = row_y2 - row_y1;
483
484 /*If the item has RTL base dir switch start and end*/
485 if(lv_obj_get_style_base_dir(item, LV_PART_MAIN) == LV_BASE_DIR_RTL) {
486 if(col_align == LV_GRID_ALIGN_START) col_align = LV_GRID_ALIGN_END;
487 else if(col_align == LV_GRID_ALIGN_END) col_align = LV_GRID_ALIGN_START;
488 }
489
490 int32_t x;
491 int32_t y;
492 int32_t item_w = lv_area_get_width(&item->coords);
493 int32_t item_h = lv_area_get_height(&item->coords);
494
495 switch(col_align) {
496 default:
497 case LV_GRID_ALIGN_START:
498 x = c->x[col_pos] + lv_obj_get_style_margin_left(item, LV_PART_MAIN);
499 item->w_layout = 0;
500 break;
501 case LV_GRID_ALIGN_STRETCH:
502 x = c->x[col_pos] + lv_obj_get_style_margin_left(item, LV_PART_MAIN);
503 item_w = col_w - get_margin_hor(item);
504 item->w_layout = 1;
505 break;
506 case LV_GRID_ALIGN_CENTER:
507 x = c->x[col_pos] + (col_w - item_w) / 2 + (lv_obj_get_style_margin_left(item, LV_PART_MAIN) -
508 lv_obj_get_style_margin_right(item, LV_PART_MAIN)) / 2;
509 item->w_layout = 0;
510 break;
511 case LV_GRID_ALIGN_END:
512 x = c->x[col_pos] + col_w - lv_obj_get_width(item) - lv_obj_get_style_margin_right(item, LV_PART_MAIN);
513 item->w_layout = 0;
514 break;
515 }
516
517 switch(row_align) {
518 default:
519 case LV_GRID_ALIGN_START:
520 y = c->y[row_pos] + lv_obj_get_style_margin_top(item, LV_PART_MAIN);
521 item->h_layout = 0;
522 break;
523 case LV_GRID_ALIGN_STRETCH:
524 y = c->y[row_pos] + lv_obj_get_style_margin_top(item, LV_PART_MAIN);
525 item_h = row_h - get_margin_ver(item);
526 item->h_layout = 1;
527 break;
528 case LV_GRID_ALIGN_CENTER:
529 y = c->y[row_pos] + (row_h - item_h) / 2 + (lv_obj_get_style_margin_top(item, LV_PART_MAIN) -
530 lv_obj_get_style_margin_bottom(item, LV_PART_MAIN)) / 2;
531 item->h_layout = 0;
532 break;
533 case LV_GRID_ALIGN_END:
534 y = c->y[row_pos] + row_h - lv_obj_get_height(item) - lv_obj_get_style_margin_bottom(item, LV_PART_MAIN);
535 item->h_layout = 0;
536 break;
537 }
538
539 /*Set a new size if required*/
540 if(lv_obj_get_width(item) != item_w || lv_obj_get_height(item) != item_h) {
541 lv_area_t old_coords;
542 lv_area_copy(&old_coords, &item->coords);
543 lv_obj_invalidate(item);
544 lv_area_set_width(&item->coords, item_w);
545 lv_area_set_height(&item->coords, item_h);
546 lv_obj_invalidate(item);
547 lv_obj_send_event(item, LV_EVENT_SIZE_CHANGED, &old_coords);
548 lv_obj_send_event(lv_obj_get_parent(item), LV_EVENT_CHILD_CHANGED, item);
549
550 }
551
552 /*Handle percentage value of translate*/
553 int32_t tr_x = lv_obj_get_style_translate_x(item, LV_PART_MAIN);
554 int32_t tr_y = lv_obj_get_style_translate_y(item, LV_PART_MAIN);
555 int32_t w = lv_obj_get_width(item);
556 int32_t h = lv_obj_get_height(item);
557 if(LV_COORD_IS_PCT(tr_x)) tr_x = (w * LV_COORD_GET_PCT(tr_x)) / 100;
558 if(LV_COORD_IS_PCT(tr_y)) tr_y = (h * LV_COORD_GET_PCT(tr_y)) / 100;
559
560 x += tr_x;
561 y += tr_y;
562
563 int32_t diff_x = hint->grid_abs.x + x - item->coords.x1;
564 int32_t diff_y = hint->grid_abs.y + y - item->coords.y1;
565 if(diff_x || diff_y) {
566 lv_obj_invalidate(item);
567 item->coords.x1 += diff_x;
568 item->coords.x2 += diff_x;
569 item->coords.y1 += diff_y;
570 item->coords.y2 += diff_y;
571 lv_obj_invalidate(item);
572 lv_obj_move_children_by(item, diff_x, diff_y, false);
573 }
574 }
575
576 /**
577 * Place the grid track according to align methods. It keeps the track sizes but sets their position.
578 * It can process both columns or rows according to the passed parameters.
579 * @param cont_size size of the containers content area (width/height)
580 * @param auto_size true: the container has auto size in the current direction
581 * @param align align method
582 * @param gap grid gap
583 * @param track_num number of tracks
584 * @param size_array array with the track sizes
585 * @param pos_array write the positions of the tracks here
586 * @return the total size of the grid
587 */
grid_align(int32_t cont_size,bool auto_size,lv_grid_align_t align,int32_t gap,uint32_t track_num,int32_t * size_array,int32_t * pos_array,bool reverse)588 static int32_t grid_align(int32_t cont_size, bool auto_size, lv_grid_align_t align, int32_t gap,
589 uint32_t track_num,
590 int32_t * size_array, int32_t * pos_array, bool reverse)
591 {
592 int32_t grid_size = 0;
593 uint32_t i;
594
595 if(auto_size) {
596 pos_array[0] = 0;
597 }
598 else {
599 /*With spaced alignment gap will be calculated from the remaining space*/
600 if(align == LV_GRID_ALIGN_SPACE_AROUND || align == LV_GRID_ALIGN_SPACE_BETWEEN || align == LV_GRID_ALIGN_SPACE_EVENLY) {
601 gap = 0;
602 if(track_num == 1) align = LV_GRID_ALIGN_CENTER;
603 }
604
605 /*Get the full grid size with gap*/
606 for(i = 0; i < track_num; i++) {
607 grid_size += size_array[i] + gap;
608 }
609 grid_size -= gap;
610
611 /*Calculate the position of the first item and set gap is necessary*/
612 switch(align) {
613 case LV_GRID_ALIGN_START:
614 pos_array[0] = 0;
615 break;
616 case LV_GRID_ALIGN_CENTER:
617 pos_array[0] = (cont_size - grid_size) / 2;
618 break;
619 case LV_GRID_ALIGN_END:
620 pos_array[0] = cont_size - grid_size;
621 break;
622 case LV_GRID_ALIGN_SPACE_BETWEEN:
623 pos_array[0] = 0;
624 gap = (int32_t)(cont_size - grid_size) / (int32_t)(track_num - 1);
625 break;
626 case LV_GRID_ALIGN_SPACE_AROUND:
627 gap = (int32_t)(cont_size - grid_size) / (int32_t)(track_num);
628 pos_array[0] = gap / 2;
629 break;
630 case LV_GRID_ALIGN_SPACE_EVENLY:
631 gap = (int32_t)(cont_size - grid_size) / (int32_t)(track_num + 1);
632 pos_array[0] = gap;
633 break;
634 default:
635 break;
636 }
637 }
638
639 /*Set the position of all tracks from the start position, gaps and track sizes*/
640 for(i = 0; i < track_num - 1; i++) {
641 pos_array[i + 1] = pos_array[i] + size_array[i] + gap;
642 }
643
644 int32_t total_gird_size = pos_array[track_num - 1] + size_array[track_num - 1] - pos_array[0];
645
646 if(reverse) {
647 for(i = 0; i < track_num; i++) {
648 pos_array[i] = cont_size - pos_array[i] - size_array[i];
649 }
650
651 }
652
653 /*Return the full size of the grid*/
654 return total_gird_size;
655 }
656
count_tracks(const int32_t * templ)657 static uint32_t count_tracks(const int32_t * templ)
658 {
659 uint32_t i;
660 for(i = 0; templ[i] != LV_GRID_TEMPLATE_LAST; i++);
661
662 return i;
663 }
664
665 #endif /*LV_USE_GRID*/
666