acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_grid.c (25245B)

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