From 288411a1d360117b6a6833811f7f0f0afc92c310 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Tue, 10 Nov 2020 16:09:28 +0100 Subject: [PATCH] feat(flex): add item placement in the main direction too --- src/lv_core/lv_flex.c | 131 ++++++++++++++++++++++++++---------------- src/lv_core/lv_flex.h | 37 +++++------- 2 files changed, 94 insertions(+), 74 deletions(-) diff --git a/src/lv_core/lv_flex.c b/src/lv_core/lv_flex.c index ef0526366..8d9a6fbdb 100644 --- a/src/lv_core/lv_flex.c +++ b/src/lv_core/lv_flex.c @@ -16,13 +16,20 @@ /********************** * TYPEDEFS **********************/ +typedef struct { + lv_coord_t grow_unit; + lv_coord_t track_cross_size; + lv_coord_t track_main_size; + uint32_t item_cnt; +}track_t; /********************** * STATIC PROTOTYPES **********************/ -static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coord_t max_size, lv_coord_t * grow_unit, lv_coord_t * track_cross_size); -static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * item_last, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t track_size, lv_coord_t grow_unit); -static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t track_size, lv_coord_t track_cnt, lv_coord_t * start_pos, lv_coord_t * gap); +//static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coord_t max_size, lv_coord_t * grow_unit, lv_coord_t * track_cross_size, lv_coord_t * track_main_size, uint32_t * item_cnt); +static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coord_t max_main_size, track_t * t); +static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * item_last, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t max_main_size, lv_flex_place_t main_place, track_t * t); +static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t track_size, lv_coord_t item_cnt, lv_coord_t * start_pos, lv_coord_t * gap); static lv_flex_dir_t get_dir(const lv_obj_t * obj); static bool get_rev(const lv_obj_t * obj); @@ -56,12 +63,16 @@ void lv_obj_set_flex_dir(lv_obj_t * obj, lv_flex_dir_t flex_dir) _lv_flex_refresh(obj); } -void lv_obj_set_flex_track_place(lv_obj_t * obj, lv_flex_place_t place) +void lv_obj_set_flex_place(lv_obj_t * obj, lv_flex_place_t item_place, lv_flex_place_t track_place) { lv_obj_allocate_rare_attr(obj); - if(obj->spec_attr->flex_cont.place == place) return; + if(obj->spec_attr->flex_cont.item_place == item_place && + obj->spec_attr->flex_cont.track_place == track_place) { + return; + } - obj->spec_attr->flex_cont.place = place; + obj->spec_attr->flex_cont.item_place = item_place; + obj->spec_attr->flex_cont.track_place = track_place; _lv_flex_refresh(obj); } @@ -107,9 +118,15 @@ lv_flex_dir_t lv_obj_get_flex_dir(const lv_obj_t * obj) else return LV_FLEX_DIR_NONE; } +lv_flex_place_t lv_obj_get_flex_item_place(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->flex_cont.item_place; + else return LV_FLEX_PLACE_START; +} + lv_flex_place_t lv_obj_get_flex_track_place(const lv_obj_t * obj) { - if(obj->spec_attr) return obj->spec_attr->flex_cont.place; + if(obj->spec_attr) return obj->spec_attr->flex_cont.track_place; else return LV_FLEX_PLACE_START; } @@ -119,7 +136,7 @@ lv_coord_t lv_obj_get_flex_gap(const lv_obj_t * obj) else return 0; } -lv_flex_place_t lv_obj_get_flex_item_place(lv_obj_t * obj) +lv_flex_place_t lv_obj_get_flex_self_place(lv_obj_t * obj) { lv_coord_t x = lv_obj_get_x(obj); if(LV_COORD_IS_FLEX(x)) return LV_COORD_GET_FLEX(x); @@ -139,65 +156,65 @@ void _lv_flex_refresh(lv_obj_t * cont) lv_coord_t abs_y = cont->coords.y1 + lv_obj_get_style_pad_top(cont, LV_OBJ_PART_MAIN) - lv_obj_get_scroll_y(cont); lv_coord_t abs_x = cont->coords.x1 + lv_obj_get_style_pad_left(cont, LV_OBJ_PART_MAIN) - lv_obj_get_scroll_x(cont); - lv_coord_t place = lv_obj_get_flex_track_place(cont); + lv_flex_place_t cross_place = lv_obj_get_flex_track_place(cont); + lv_flex_place_t main_place = cont->spec_attr->flex_cont.item_place; lv_ll_t * ll = _lv_obj_get_child_ll(cont); lv_coord_t * cross_pos = (row ? &abs_y : &abs_x); if((row && cont->h_set == LV_SIZE_AUTO) || (!row && cont->w_set == LV_SIZE_AUTO)) { - place = LV_FLEX_PLACE_START; + cross_place = LV_FLEX_PLACE_START; } if(rtl && !row) { - if(place == LV_FLEX_PLACE_START) place = LV_FLEX_PLACE_END; - else if(place == LV_FLEX_PLACE_END) place = LV_FLEX_PLACE_START; + if(cross_place == LV_FLEX_PLACE_START) cross_place = LV_FLEX_PLACE_END; + else if(cross_place == LV_FLEX_PLACE_END) cross_place = LV_FLEX_PLACE_START; } - lv_coord_t all_track_size = 0; + lv_coord_t total_track_cross_size = 0; lv_coord_t gap = 0; - uint32_t row_cnt = 0; - lv_coord_t grow_unit; - lv_coord_t track_size; + uint32_t track_cnt = 0; lv_obj_t * track_first_item; lv_obj_t * next_track_first_item; bool rev = get_rev(cont); - if(place != LV_FLEX_PLACE_START) { + if(cross_place != LV_FLEX_PLACE_START) { track_first_item = rev ? _lv_ll_get_head(ll) : _lv_ll_get_tail(ll); - + track_t t; while(track_first_item) { /*Search the first item of the next row */ - next_track_first_item = find_track_end(cont, track_first_item, max_main_size, &grow_unit, &track_size); - all_track_size += track_size; - row_cnt++; + next_track_first_item = find_track_end(cont, track_first_item, max_main_size, &t); + total_track_cross_size += t.track_cross_size; + track_cnt++; track_first_item = next_track_first_item; } lv_coord_t max_cross_size = (row ? lv_obj_get_height_fit(cont) : lv_obj_get_width_fit(cont)); - place_content(place, max_cross_size, all_track_size,row_cnt, cross_pos, &gap); + place_content(cross_place, max_cross_size, total_track_cross_size, track_cnt, cross_pos, &gap); } track_first_item = rev ? _lv_ll_get_head(ll) : _lv_ll_get_tail(ll); if(rtl && !row) { - *cross_pos += all_track_size; + *cross_pos += total_track_cross_size; } while(track_first_item) { + track_t t; /*Search the first item of the next row */ - next_track_first_item = find_track_end(cont, track_first_item, max_main_size, &grow_unit, &track_size); + next_track_first_item = find_track_end(cont, track_first_item, max_main_size, &t); if(rtl && !row) { - *cross_pos -= track_size; + *cross_pos -= t.track_cross_size; } - children_repos(cont, track_first_item, next_track_first_item, abs_x, abs_y, track_size, grow_unit); + children_repos(cont, track_first_item, next_track_first_item, abs_x, abs_y, max_main_size, main_place, &t); track_first_item = next_track_first_item; if(rtl && !row) { *cross_pos -= gap; } else { - *cross_pos += track_size + gap; + *cross_pos += t.track_cross_size + gap; } } LV_ASSERT_MEM_INTEGRITY(); @@ -207,7 +224,7 @@ void _lv_flex_refresh(lv_obj_t * cont) * STATIC FUNCTIONS **********************/ -static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coord_t max_size, lv_coord_t * grow_unit, lv_coord_t * track_cross_size) +static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coord_t max_main_size, track_t * t) { bool wrap = get_wrap(cont); bool rev = get_rev(cont); @@ -220,10 +237,11 @@ static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coor lv_ll_t * ll = _lv_obj_get_child_ll(cont); lv_coord_t grow_sum = 0; - lv_coord_t used_size = 0; + t->track_main_size = 0; uint32_t grow_item_cnt = 0; - *track_cross_size = 0; - *grow_unit = 0; + t->track_cross_size = 0; + t->grow_unit = 0; + t->item_cnt = 0; lv_obj_t * item = item_start; while(item) { @@ -240,35 +258,41 @@ static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coor grow_item_cnt++; } else { lv_coord_t item_size = get_main_size(item) + gap; - if(wrap && used_size + item_size > max_size) break; - used_size += item_size; + if(wrap && t->track_main_size + item_size > max_main_size) break; + t->track_main_size += item_size; } - *track_cross_size = LV_MATH_MAX(get_cross_size(item), *track_cross_size); + t->track_cross_size = LV_MATH_MAX(get_cross_size(item), t->track_cross_size); item = ll_iter(ll, item); + t->item_cnt++; } - if(used_size > 0) used_size -= gap; /*There is no gap after the last item*/ + if(t->track_main_size > 0) t->track_main_size -= gap; /*There is no gap after the last item*/ if(grow_item_cnt && grow_sum) { - lv_coord_t s = max_size - used_size; + lv_coord_t s = max_main_size - t->track_main_size; s -= grow_item_cnt * gap; - *grow_unit = s / grow_sum; + t->grow_unit = s / grow_sum; + t->track_main_size = max_main_size; /*If there is at least one "grow item" the track takes the full space*/ } else { - *grow_unit = 0; + t->grow_unit = 0; } /*Have at least one item in a row*/ if(item && item == item_start) { item = ll_iter(ll, item); - if(item) *track_cross_size = get_cross_size(item); + if(item) { + t->track_cross_size = get_cross_size(item); + t->track_main_size = get_main_size(item); + t->item_cnt = 1; + } } return item; } -static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * item_last, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t track_size, lv_coord_t grow_unit) +static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * item_last, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t max_main_size, lv_flex_place_t main_place, track_t * t) { bool rev = get_rev(cont); lv_coord_t gap = lv_obj_get_flex_gap(cont); @@ -289,6 +313,9 @@ static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * it lv_ll_t * ll = _lv_obj_get_child_ll(cont); lv_coord_t main_pos = 0; + + lv_coord_t place_gap; + place_content(main_place, max_main_size, t->track_main_size, t->item_cnt, &main_pos, &place_gap); /*Reposition the children*/ lv_obj_t * item = item_first; /*Just to use a shorter name*/ while(item != item_last) { @@ -306,12 +333,12 @@ static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * it lv_area_copy(&old_coords, &item->coords); if(_LV_FLEX_GET_GROW(main_size)) { - lv_coord_t s = _LV_FLEX_GET_GROW(main_size) * grow_unit; + lv_coord_t s = _LV_FLEX_GET_GROW(main_size) * t->grow_unit; s -= get_margin_start(item, LV_OBJ_PART_MAIN) + get_margin_end(item, LV_OBJ_PART_MAIN); area_set_main_size(&item->coords, s); } if(LV_COORD_GET_FLEX(main_set) == LV_FLEX_PLACE_STRETCH) { - area_set_cross_size(&item->coords, track_size); + area_set_cross_size(&item->coords, t->track_cross_size); } if(lv_area_get_height(&old_coords) != area_get_main_size(&item->coords)) { @@ -325,15 +352,15 @@ static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * it lv_coord_t cross_set = (row ? item->y_set : item->x_set); switch(LV_COORD_GET_FLEX(cross_set)) { case LV_FLEX_PLACE_CENTER: - cross_pos = (track_size - obj_get_cross_size(item)) / 2; + cross_pos = (t->track_cross_size - obj_get_cross_size(item)) / 2; break; case LV_FLEX_PLACE_END: - cross_pos = track_size - obj_get_cross_size(item); + cross_pos = t->track_cross_size - obj_get_cross_size(item); break; } if(row && rtl) { - main_pos -= obj_get_main_size(item) + gap; + main_pos -= obj_get_main_size(item) + gap + place_gap; } lv_coord_t diff_x = abs_x - item->coords.x1 + lv_obj_get_style_margin_left(item, LV_OBJ_PART_MAIN); @@ -350,15 +377,15 @@ static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * it } if(!(row && rtl)) { - main_pos += obj_get_main_size(item) + gap; + main_pos += obj_get_main_size(item) + gap + place_gap; } item = ll_iter(ll, item); } } -static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t track_size, lv_coord_t track_cnt, lv_coord_t * start_pos, lv_coord_t * gap) +static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t track_size, lv_coord_t item_cnt, lv_coord_t * start_pos, lv_coord_t * gap) { - if(track_cnt <= 1) { + if(item_cnt <= 1) { switch(place) { case LV_FLEX_PLACE_SPACE_BETWEEN: case LV_FLEX_PLACE_SPACE_AROUND: @@ -370,20 +397,22 @@ static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t trac switch(place) { case LV_FLEX_PLACE_CENTER: + *gap = 0; *start_pos += (max_size - track_size) / 2; break; case LV_FLEX_PLACE_END: + *gap = 0; *start_pos += max_size - track_size; break; case LV_FLEX_PLACE_SPACE_BETWEEN: - *gap = (lv_coord_t)(max_size - track_size) / (lv_coord_t)(track_cnt - 1); + *gap = (lv_coord_t)(max_size - track_size) / (lv_coord_t)(item_cnt - 1); break; case LV_FLEX_PLACE_SPACE_AROUND: - *gap += (lv_coord_t)(max_size - track_size) / (lv_coord_t)(track_cnt); + *gap += (lv_coord_t)(max_size - track_size) / (lv_coord_t)(item_cnt); *start_pos += *gap / 2; break; case LV_FLEX_PLACE_SPACE_EVENLY: - *gap = (lv_coord_t)(max_size - track_size) / (lv_coord_t)(track_cnt + 1); + *gap = (lv_coord_t)(max_size - track_size) / (lv_coord_t)(item_cnt + 1); *start_pos += *gap; break; default: diff --git a/src/lv_core/lv_flex.h b/src/lv_core/lv_flex.h index b7169f5f2..a8c31e02f 100644 --- a/src/lv_core/lv_flex.h +++ b/src/lv_core/lv_flex.h @@ -62,7 +62,8 @@ typedef struct { uint8_t dir :2; uint8_t wrap :1; uint8_t rev :1; - uint8_t place :3; + uint8_t item_place :3; + uint8_t track_place :3; }lv_flex_cont_t; /********************** @@ -83,24 +84,13 @@ typedef struct { void lv_obj_set_flex_dir(struct _lv_obj_t * obj, lv_flex_dir_t flex_dir); /** - * Set how to place the tracks below/next to each other. - * For ROW direction it means how to place the rows vertically. - * For COLUMN direction it means how to place the column horizontally. + * Set how to place the items and the tracks * @param obj point to a flex container - * @param place the placement type. Can be any element of `lv_flex_place_t`. + * @param item_place tells how to distribute the free space among the items in the same track + * @param track_place tells how to distribute the free space among the tracks * @note if the base direction is RTL and the direction is ROW, LV_FLEX_START means the right side */ -void lv_obj_set_flex_track_place(struct _lv_obj_t * obj, lv_flex_place_t place); - -/** - * Set a gap in the main direction. - * For ROW direction it means adding gap horizontally between the items. - * For COLUMN direction it means adding gap vertically between the items. - * @param obj pointer to an object (flex container) - * @param gap the gap in pixels - * @note By default the objects are packed tightly after each other - */ -void lv_obj_set_flex_gap(struct _lv_obj_t * obj, lv_coord_t gap); +void lv_obj_set_flex_place(struct _lv_obj_t * obj, lv_flex_place_t item_place, lv_flex_place_t track_place); /** * Make an object flex item, i.e. allow setting it's coordinate according to the parent's flex settings. @@ -132,18 +122,19 @@ void lv_obj_set_flex_item_place(struct _lv_obj_t * obj, lv_flex_place_t place); */ lv_flex_dir_t lv_obj_get_flex_dir(const struct _lv_obj_t * obj); +/** + * Get the item placement of a flex container + * @param obj pointer to an object + * @return the item placement + */ +lv_flex_place_t lv_obj_get_flex_item_place(const struct _lv_obj_t * obj); + /** * Get the track placement of a flex container * @param obj pointer to an object * @return the track placement */ lv_flex_place_t lv_obj_get_flex_track_place(const struct _lv_obj_t * obj); -/** - * Get flex gap - * @param obj pointer to an flex container - * @return the gap in pixels - */ -lv_coord_t lv_obj_get_flex_gap(const struct _lv_obj_t * obj); /** * Get how the flex item is placed in its track in the cross direction. @@ -152,7 +143,7 @@ lv_coord_t lv_obj_get_flex_gap(const struct _lv_obj_t * obj); * @param obj pointer to a flex item * @return `LV_FLEX_PLACE_NONE/START/CENTER/END` */ -lv_flex_place_t lv_obj_get_flex_item_place(struct _lv_obj_t * obj); +lv_flex_place_t lv_obj_get_flex_self_place(struct _lv_obj_t * obj); /** * Rearrange the flex items of a flex container * @param cont pointer to a flex container object