1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

feat(flex): add item placement in the main direction too

This commit is contained in:
Gabor Kiss-Vamosi 2020-11-10 16:09:28 +01:00
parent 1ea0d7845a
commit 288411a1d3
2 changed files with 94 additions and 74 deletions

View File

@ -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:

View File

@ -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