diff --git a/src/lv_core/lv_flex.c b/src/lv_core/lv_flex.c index 6fba889766..b43f337a63 100644 --- a/src/lv_core/lv_flex.c +++ b/src/lv_core/lv_flex.c @@ -23,17 +23,43 @@ typedef struct { uint32_t item_cnt; }track_t; + /********************** * STATIC PROTOTYPES **********************/ -static uint32_t find_track_end(lv_obj_t * cont, uint32_t item_start_id, lv_coord_t max_main_size, track_t * t); -static void children_repos(lv_obj_t * cont, uint32_t item_first_id, uint32_t item_last_id, 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 void flex_update(lv_obj_t * cont, lv_obj_t * item); +static int32_t find_track_end(lv_obj_t * cont, int32_t item_start_id, lv_coord_t max_main_size, track_t * t); +static void children_repos(lv_obj_t * cont, int32_t item_first_id, int32_t item_last_id, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t max_main_size, track_t * t); +static void place_content(lv_flex_place_t place, lv_coord_t max_size, lv_coord_t content_size, lv_coord_t item_cnt, lv_coord_t * start_pos, lv_coord_t * gap); +static lv_obj_t * get_next_item(lv_obj_t * cont, bool rev, int32_t * item_id); -static lv_flex_dir_t get_dir(const lv_obj_t * obj); -static bool get_rev(const lv_obj_t * obj); -static bool get_wrap(const lv_obj_t * obj); -static lv_obj_t * get_next_item(lv_obj_t * cont, bool rev, uint32_t * item_id); +/********************** + * GLOBAL VARIABLES + **********************/ +const lv_flex_t lv_flex_center = { + .update_cb = flex_update, + .item_main_place = LV_FLEX_PLACE_CENTER, + .item_cross_place = LV_FLEX_PLACE_CENTER, + .track_place = LV_FLEX_PLACE_CENTER, + .dir = LV_FLEX_FLOW_COLUMN +}; + +const lv_flex_t lv_flex_stacked = { + .update_cb = flex_update, + .item_main_place = LV_FLEX_PLACE_START, + .item_cross_place = LV_FLEX_PLACE_START, + .track_place = LV_FLEX_PLACE_START, + .dir = LV_FLEX_FLOW_COLUMN +}; + +const lv_flex_t lv_flex_even = { + .update_cb = flex_update, + .item_main_place = LV_FLEX_PLACE_SPACE_EVENLY, + .item_cross_place = LV_FLEX_PLACE_CENTER, + .track_place = LV_FLEX_PLACE_CENTER, + .dir = LV_FLEX_FLOW_ROW, + .wrap = 1 +}; /********************** * STATIC VARIABLES @@ -51,113 +77,53 @@ static lv_obj_t * get_next_item(lv_obj_t * cont, bool rev, uint32_t * item_id); * Setter functions *====================*/ -void lv_obj_set_flex_dir(lv_obj_t * obj, lv_flex_dir_t flex_dir) +void lv_flex_init(lv_flex_t * flex) { - lv_obj_allocate_spec_attr(obj); - - if(obj->spec_attr->flex_cont.dir == flex_dir) return; - - obj->spec_attr->flex_cont.dir = flex_dir & 0x3; - obj->spec_attr->flex_cont.wrap = flex_dir & _LV_FLEX_WRAP ? 1 : 0; - obj->spec_attr->flex_cont.rev = flex_dir & _LV_FLEX_REVERSE ? 1 : 0; - _lv_flex_refresh(obj); + _lv_memset_00(flex, sizeof(lv_flex_t)); + flex->update_cb = flex_update; + flex->dir = LV_FLEX_FLOW_ROW; + flex->item_main_place = LV_FLEX_PLACE_START; + flex->track_place = LV_FLEX_PLACE_START; + flex->item_cross_place = LV_FLEX_PLACE_START; } -void lv_obj_set_flex_place(lv_obj_t * obj, lv_flex_place_t main_place, lv_flex_place_t cross_place) +void lv_flex_set_flow(lv_flex_t * flex, lv_flex_flow_t flow) { - lv_obj_allocate_spec_attr(obj); - if(obj->spec_attr->flex_cont.main_place == main_place && - obj->spec_attr->flex_cont.cross_place == cross_place) { - return; - } - - obj->spec_attr->flex_cont.main_place = main_place; - obj->spec_attr->flex_cont.cross_place = cross_place; - - _lv_flex_refresh(obj); + flex->dir = flow & 0x3; + flex->wrap = flow & _LV_FLEX_WRAP ? 1 : 0; + flex->rev = flow & _LV_FLEX_REVERSE ? 1 : 0; } -void lv_obj_set_flex_gap(lv_obj_t * obj, lv_coord_t gap) +void lv_flex_set_place(lv_flex_t * flex, lv_flex_place_t item_main_place, lv_flex_place_t item_cross_place, lv_flex_place_t track_place) { - if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); - - if(obj->spec_attr->flex_cont.gap == gap) return; - - obj->spec_attr->flex_cont.gap = gap; - - _lv_flex_refresh(obj); + flex->item_main_place = item_main_place; + flex->track_place = track_place; + flex->item_cross_place = item_cross_place; } -void lv_obj_set_flex_item(lv_obj_t * obj, bool en) +void lv_flex_set_gap(lv_flex_t * flex, lv_coord_t main_gap, lv_coord_t cross_gap) { - if(en) { - lv_coord_t f = _LV_COORD_FELX(LV_FLEX_PLACE_START); - lv_obj_set_pos(obj, f, f); - } else { - lv_obj_set_pos(obj, lv_obj_get_x(obj), lv_obj_get_y(obj)); - } -} - -void lv_obj_set_flex_item_place(lv_obj_t * obj, lv_flex_place_t place) -{ - if(place == LV_FLEX_PLACE_NONE) { - lv_obj_set_pos(obj, lv_obj_get_x(obj), lv_obj_get_x(obj)); - } else { - lv_coord_t f = _LV_COORD_FELX(place); - lv_obj_set_pos(obj, f, f); - } + flex->item_gap = main_gap; + flex->track_gap = cross_gap; } /*===================== * Getter functions *====================*/ -lv_flex_dir_t lv_obj_get_flex_dir(const lv_obj_t * obj) +static void flex_update(lv_obj_t * cont, lv_obj_t * item) { - if(obj->spec_attr) return obj->spec_attr->flex_cont.dir; - 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.main_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.cross_place; - else return LV_FLEX_PLACE_START; -} - -lv_coord_t lv_obj_get_flex_gap(const lv_obj_t * obj) -{ - if(obj->spec_attr) return obj->spec_attr->flex_cont.gap; - else return 0; -} - -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); - else return LV_FLEX_PLACE_NONE; -} - -void _lv_flex_refresh(lv_obj_t * cont) -{ - lv_flex_dir_t dir = get_dir(cont); - - if(dir == LV_FLEX_DIR_NONE) return; + if(cont->spec_attr == NULL) return; + const lv_flex_t * f = cont->spec_attr->layout_dsc; bool rtl = lv_obj_get_base_dir(cont) == LV_BIDI_DIR_RTL ? true : false; - bool row = dir == LV_FLEX_DIR_ROW ? true : false; + bool row = f->dir == LV_FLEX_FLOW_ROW ? true : false; /*Count the grow units and free space*/ lv_coord_t max_main_size = (row ? lv_obj_get_width_fit(cont) : lv_obj_get_height_fit(cont)); lv_coord_t abs_y = cont->coords.y1 + lv_obj_get_style_pad_top(cont, LV_PART_MAIN) - lv_obj_get_scroll_y(cont); lv_coord_t abs_x = cont->coords.x1 + lv_obj_get_style_pad_left(cont, LV_PART_MAIN) - lv_obj_get_scroll_x(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.main_place; + lv_flex_place_t cross_place = f->track_place; lv_coord_t * cross_pos = (row ? &abs_y : &abs_x); if((row && cont->h_set == LV_SIZE_AUTO) || @@ -174,32 +140,38 @@ void _lv_flex_refresh(lv_obj_t * cont) lv_coord_t total_track_cross_size = 0; lv_coord_t gap = 0; uint32_t track_cnt = 0; - uint32_t track_first_item; - uint32_t next_track_first_item; - bool rev = get_rev(cont); + int32_t track_first_item; + int32_t next_track_first_item; if(cross_place != LV_FLEX_PLACE_START) { - track_first_item = rev ? cont->spec_attr->child_cnt - 1 : 0; + track_first_item = f->rev ? cont->spec_attr->child_cnt - 1 : 0; track_t t; - while(track_first_item ) { + while(track_first_item < cont->spec_attr->child_cnt && track_first_item >= 0) { /*Search the first item of the next row */ next_track_first_item = find_track_end(cont, track_first_item, max_main_size, &t); - total_track_cross_size += t.track_cross_size; + total_track_cross_size += t.track_cross_size + f->track_gap; track_cnt++; track_first_item = next_track_first_item; } + if(track_cnt) total_track_cross_size -= f->track_gap; /*No gap after the last track*/ + + /* Place the tracks to get the start position + * If the the height of the tracks is larger than the available space + * always use the gap = 0 and start position = 0 to avoid unintuitive scrolling*/ lv_coord_t max_cross_size = (row ? lv_obj_get_height_fit(cont) : lv_obj_get_width_fit(cont)); - place_content(cross_place, max_cross_size, total_track_cross_size, track_cnt, cross_pos, &gap); + if(total_track_cross_size < max_cross_size) { + place_content(cross_place, max_cross_size, total_track_cross_size, track_cnt, cross_pos, &gap); + } } - track_first_item = rev ? cont->spec_attr->child_cnt - 1 : 0; + track_first_item = f->rev ? cont->spec_attr->child_cnt - 1 : 0; if(rtl && !row) { *cross_pos += total_track_cross_size; } - while(track_first_item) { + while(track_first_item < cont->spec_attr->child_cnt && track_first_item >= 0) { 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, &t); @@ -207,13 +179,13 @@ void _lv_flex_refresh(lv_obj_t * cont) if(rtl && !row) { *cross_pos -= t.track_cross_size; } - children_repos(cont, track_first_item, next_track_first_item, abs_x, abs_y, max_main_size, main_place, &t); + children_repos(cont, track_first_item, next_track_first_item, abs_x, abs_y, max_main_size, &t); track_first_item = next_track_first_item; if(rtl && !row) { - *cross_pos -= gap; + *cross_pos -= gap + f->track_gap; } else { - *cross_pos += t.track_cross_size + gap; + *cross_pos += t.track_cross_size + gap + f->track_gap; } } LV_ASSERT_MEM_INTEGRITY(); @@ -223,12 +195,11 @@ void _lv_flex_refresh(lv_obj_t * cont) * STATIC FUNCTIONS **********************/ -static uint32_t find_track_end(lv_obj_t * cont, uint32_t item_start_id, lv_coord_t max_main_size, track_t * t) +static int32_t find_track_end(lv_obj_t * cont, int32_t item_start_id, lv_coord_t max_main_size, track_t * t) { - bool wrap = get_wrap(cont); - bool rev = get_rev(cont); - lv_coord_t gap = lv_obj_get_flex_gap(cont); - bool row = get_dir(cont) == LV_FLEX_DIR_ROW ? true : false; + const lv_flex_t * f = cont->spec_attr->layout_dsc; + + bool row = f->dir == LV_FLEX_FLOW_ROW ? true : false; lv_coord_t(*get_main_size)(const lv_obj_t *) = (row ? lv_obj_get_width_margin : lv_obj_get_height_margin); lv_coord_t(*get_cross_size)(const lv_obj_t *) = (!row ? lv_obj_get_width_margin : lv_obj_get_height_margin); @@ -239,38 +210,31 @@ static uint32_t find_track_end(lv_obj_t * cont, uint32_t item_start_id, lv_coord t->grow_unit = 0; t->item_cnt = 0; - uint32_t item_id = item_start_id; + int32_t item_id = item_start_id; - lv_obj_t * item = get_next_item(cont, rev, &item_id); + lv_obj_t * item = lv_obj_get_child(cont, item_id); while(item) { - /*Ignore non-flex items*/ - lv_coord_t main_set = (row ? item->x_set : item->y_set); - if(LV_COORD_IS_FLEX(main_set) == false) { - item = get_next_item(cont, rev, &item_id); - continue; - } - lv_coord_t main_size = (row ? item->w_set : item->h_set); if(_LV_FLEX_GET_GROW(main_size)) { grow_sum += _LV_FLEX_GET_GROW(main_size); grow_item_cnt++; } else { - lv_coord_t item_size = get_main_size(item) + gap; - if(wrap && t->track_main_size + item_size > max_main_size) break; + lv_coord_t item_size = get_main_size(item) + f->item_gap; + if(f->wrap && t->track_main_size + item_size > max_main_size) break; t->track_main_size += item_size; } t->track_cross_size = LV_MATH_MAX(get_cross_size(item), t->track_cross_size); - item_id += rev ? -1 : +1; + item_id += f->rev ? -1 : +1; item = lv_obj_get_child(cont, item_id); t->item_cnt++; } - if(t->track_main_size > 0) t->track_main_size -= gap; /*There is no gap after the last item*/ + if(t->track_main_size > 0) t->track_main_size -= f->item_gap; /*There is no gap after the last item*/ if(grow_item_cnt && grow_sum) { lv_coord_t s = max_main_size - t->track_main_size; - s -= grow_item_cnt * gap; + s -= grow_item_cnt * f->item_gap; 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 { @@ -279,7 +243,7 @@ static uint32_t find_track_end(lv_obj_t * cont, uint32_t item_start_id, lv_coord /*Have at least one item in a row*/ if(item && item_id == item_start_id) { - item = get_next_item(cont, rev, &item_id); + item = get_next_item(cont, f->rev, &item_id); if(item) { t->track_cross_size = get_cross_size(item); t->track_main_size = get_main_size(item); @@ -291,19 +255,18 @@ static uint32_t find_track_end(lv_obj_t * cont, uint32_t item_start_id, lv_coord } -static void children_repos(lv_obj_t * cont, uint32_t item_first_id, uint32_t item_last_id, 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 children_repos(lv_obj_t * cont, int32_t item_first_id, int32_t item_last_id, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t max_main_size, track_t * t) { - bool rev = get_rev(cont); - lv_coord_t gap = lv_obj_get_flex_gap(cont); - bool row = get_dir(cont) == LV_FLEX_DIR_ROW ? true : false; + + const lv_flex_t * f = cont->spec_attr->layout_dsc; + bool row = f->dir == LV_FLEX_FLOW_ROW ? true : false; lv_coord_t(*obj_get_main_size)(const lv_obj_t *) = (row ? lv_obj_get_width_margin : lv_obj_get_height_margin); lv_coord_t(*obj_get_cross_size)(const lv_obj_t *) = (!row ? lv_obj_get_width_margin : lv_obj_get_height_margin); void (*area_set_main_size)(lv_area_t *, lv_coord_t) = (row ? lv_area_set_width : lv_area_set_height); - void (*area_set_cross_size)(lv_area_t *, lv_coord_t) = (!row ? lv_area_set_width : lv_area_set_height); lv_coord_t (*area_get_main_size)(const lv_area_t *) = (!row ? lv_area_get_width : lv_area_get_height); - lv_coord_t (*get_margin_start)(const lv_obj_t *, uint8_t part) = (row ? lv_obj_get_style_margin_left : lv_obj_get_style_margin_top); - lv_coord_t (*get_margin_end)(const lv_obj_t *, uint8_t part) = (row ? lv_obj_get_style_margin_right : lv_obj_get_style_margin_bottom); + lv_coord_t (*get_margin_start)(const lv_obj_t *, uint32_t part) = (row ? lv_obj_get_style_margin_left : lv_obj_get_style_margin_top); + lv_coord_t (*get_margin_end)(const lv_obj_t *, uint32_t part) = (row ? lv_obj_get_style_margin_right : lv_obj_get_style_margin_bottom); bool rtl = lv_obj_get_base_dir(cont) == LV_BIDI_DIR_RTL ? true : false; @@ -312,52 +275,37 @@ static void children_repos(lv_obj_t * cont, uint32_t item_first_id, uint32_t ite lv_coord_t main_pos = 0; lv_coord_t place_gap = 0; - place_content(main_place, max_main_size, t->track_main_size, t->item_cnt, &main_pos, &place_gap); + place_content(f->item_main_place, max_main_size, t->track_main_size, t->item_cnt, &main_pos, &place_gap); - lv_obj_t * item = get_next_item(cont, rev, &item_first_id); + lv_obj_t * item = lv_obj_get_child(cont, item_first_id); /*Reposition the children*/ while(item && item_first_id != item_last_id) { - /*Ignore non-flex items*/ - lv_coord_t main_set = (row ? item->x_set : item->y_set); - if(LV_COORD_IS_FLEX(main_set) == false) { - item = get_next_item(cont, rev, &item_first_id); - continue; - } - lv_coord_t main_size = (row ? item->w_set : item->h_set); - if(_LV_FLEX_GET_GROW(main_size) || LV_COORD_GET_FLEX(main_set) == LV_FLEX_PLACE_STRETCH) { + if(_LV_FLEX_GET_GROW(main_size)) { lv_area_t old_coords; lv_area_copy(&old_coords, &item->coords); - if(_LV_FLEX_GET_GROW(main_size)) { - lv_coord_t s = _LV_FLEX_GET_GROW(main_size) * t->grow_unit; - s -= get_margin_start(item, LV_PART_MAIN) + get_margin_end(item, LV_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, t->track_cross_size); - } + lv_coord_t s = _LV_FLEX_GET_GROW(main_size) * t->grow_unit; + s -= get_margin_start(item, LV_PART_MAIN) + get_margin_end(item, LV_PART_MAIN); + area_set_main_size(&item->coords, s); if(lv_area_get_height(&old_coords) != area_get_main_size(&item->coords)) { lv_obj_invalidate(item); - lv_signal_send(item, LV_SIGNAL_COORD_CHG, &old_coords); + lv_signal_send(item, LV_SIGNAL_COORD_CHG, &old_coords); lv_obj_invalidate(item); } } lv_coord_t cross_pos = 0; - lv_coord_t cross_set = (row ? item->y_set : item->x_set); - switch(LV_COORD_GET_FLEX(cross_set)) { + switch(f->item_cross_place) { case LV_FLEX_PLACE_CENTER: cross_pos = (t->track_cross_size - obj_get_cross_size(item)) / 2; break; case LV_FLEX_PLACE_END: cross_pos = t->track_cross_size - obj_get_cross_size(item); break; - } - - if(row && rtl) { - main_pos -= obj_get_main_size(item) + gap + place_gap; + default: + break; } lv_coord_t diff_x = abs_x - item->coords.x1 + lv_obj_get_style_margin_left(item, LV_PART_MAIN); @@ -374,13 +322,13 @@ static void children_repos(lv_obj_t * cont, uint32_t item_first_id, uint32_t ite } if(!(row && rtl)) { - main_pos += obj_get_main_size(item) + gap + place_gap; + main_pos += obj_get_main_size(item) + f->item_gap + place_gap; } - item = get_next_item(cont, rev, &item_first_id); + item = get_next_item(cont, f->rev, &item_first_id); } } -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 void place_content(lv_flex_place_t place, lv_coord_t max_size, lv_coord_t content_size, lv_coord_t item_cnt, lv_coord_t * start_pos, lv_coord_t * gap) { if(item_cnt <= 1) { switch(place) { @@ -389,27 +337,29 @@ static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t trac case LV_FLEX_PLACE_SPACE_EVENLY: place = LV_FLEX_PLACE_CENTER; break; + default: + break; } } switch(place) { case LV_FLEX_PLACE_CENTER: *gap = 0; - *start_pos += (max_size - track_size) / 2; + *start_pos += (max_size - content_size) / 2; break; case LV_FLEX_PLACE_END: *gap = 0; - *start_pos += max_size - track_size; + *start_pos += max_size - content_size; break; case LV_FLEX_PLACE_SPACE_BETWEEN: - *gap = (lv_coord_t)(max_size - track_size) / (lv_coord_t)(item_cnt - 1); + *gap = (lv_coord_t)(max_size - content_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)(item_cnt); + *gap += (lv_coord_t)(max_size - content_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)(item_cnt + 1); + *gap = (lv_coord_t)(max_size - content_size) / (lv_coord_t)(item_cnt + 1); *start_pos += *gap; break; default: @@ -417,41 +367,15 @@ static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t trac } } -static lv_flex_dir_t get_dir(const lv_obj_t * obj) -{ - if(obj->spec_attr) return obj->spec_attr->flex_cont.dir; - else return false; -} - -static bool get_rev(const lv_obj_t * obj) -{ - if(obj->spec_attr) return obj->spec_attr->flex_cont.rev; - else return false; -} - -static bool get_wrap(const lv_obj_t * obj) -{ - if(obj->spec_attr) return obj->spec_attr->flex_cont.wrap; - else return false; -} - -static lv_obj_t * get_next_item(lv_obj_t * cont, bool rev, uint32_t * item_id) +static lv_obj_t * get_next_item(lv_obj_t * cont, bool rev, int32_t * item_id) { if(rev) { - if(*item_id > 0) { - (*item_id)--; - return cont->spec_attr->children[*item_id]; - } - else { - return NULL; - } + (*item_id)--; + if(*item_id >= 0) return cont->spec_attr->children[*item_id]; + else return NULL; } else { - if((*item_id) <= cont->spec_attr->child_cnt - 1) { - item_id++; - return cont->spec_attr->children[*item_id]; - } - else { - return NULL; - } + (*item_id)++; + if((*item_id) < cont->spec_attr->child_cnt) return cont->spec_attr->children[*item_id]; + else return NULL; } } diff --git a/src/lv_core/lv_flex.h b/src/lv_core/lv_flex.h index 5eb38af4a0..5ba84ea89e 100644 --- a/src/lv_core/lv_flex.h +++ b/src/lv_core/lv_flex.h @@ -13,16 +13,16 @@ extern "C" { /********************* * INCLUDES *********************/ -#include "../lv_misc/lv_area.h" +#include "lv_obj_pos.h" /********************* * DEFINES *********************/ /** Can be set as width or height (on main axis) to grow the object in order fill the free space*/ -#define LV_FLEX_GROW(grow) (_LV_COORD_FELX(grow)) +#define LV_FLEX_GROW(grow) (LV_COORD_SET_LAYOUT(grow)) -#define _LV_FLEX_GET_GROW(v) (LV_COORD_IS_FLEX(v) ? LV_COORD_GET_FLEX(v) : 0) +#define _LV_FLEX_GET_GROW(v) (LV_COORD_IS_LAYOUT(v) ? _LV_COORD_PLAIN(v) : 0) #define _LV_FLEX_WRAP (1 << 2) #define _LV_FLEX_REVERSE (1 << 3) @@ -39,32 +39,33 @@ typedef enum { LV_FLEX_PLACE_START, LV_FLEX_PLACE_END, LV_FLEX_PLACE_CENTER, - LV_FLEX_PLACE_STRETCH, LV_FLEX_PLACE_SPACE_EVENLY, LV_FLEX_PLACE_SPACE_AROUND, LV_FLEX_PLACE_SPACE_BETWEEN, }lv_flex_place_t; typedef enum { - LV_FLEX_DIR_NONE, - LV_FLEX_DIR_ROW = 0x01, - LV_FLEX_DIR_COLUMN = 0x02, - LV_FLEX_DIR_ROW_WRAP = LV_FLEX_DIR_ROW | _LV_FLEX_WRAP, - LV_FLEX_DIR_ROW_REVERSE = LV_FLEX_DIR_ROW | _LV_FLEX_REVERSE, - LV_FLEX_DIR_ROW_WRAP_REVERSE = LV_FLEX_DIR_ROW | _LV_FLEX_WRAP | _LV_FLEX_REVERSE, - LV_FLEX_DIR_COLUMN_WRAP = LV_FLEX_DIR_COLUMN | _LV_FLEX_WRAP, - LV_FLEX_DIR_COLUMN_REVERSE = LV_FLEX_DIR_COLUMN | _LV_FLEX_REVERSE, - LV_FLEX_DIR_COLUMN_WRAP_REVERSE = LV_FLEX_DIR_COLUMN | _LV_FLEX_WRAP | _LV_FLEX_REVERSE, -}lv_flex_dir_t; + LV_FLEX_FLOW_ROW = 0x01, + LV_FLEX_FLOW_COLUMN = 0x02, + LV_FLEX_FLOW_ROW_WRAP = LV_FLEX_FLOW_ROW | _LV_FLEX_WRAP, + LV_FLEX_FLOW_ROW_REVERSE = LV_FLEX_FLOW_ROW | _LV_FLEX_REVERSE, + LV_FLEX_FLOW_ROW_WRAP_REVERSE = LV_FLEX_FLOW_ROW | _LV_FLEX_WRAP | _LV_FLEX_REVERSE, + LV_FLEX_FLOW_COLUMN_WRAP = LV_FLEX_FLOW_COLUMN | _LV_FLEX_WRAP, + LV_FLEX_FLOW_COLUMN_REVERSE = LV_FLEX_FLOW_COLUMN | _LV_FLEX_REVERSE, + LV_FLEX_FLOW_COLUMN_WRAP_REVERSE = LV_FLEX_FLOW_COLUMN | _LV_FLEX_WRAP | _LV_FLEX_REVERSE, +}lv_flex_flow_t; typedef struct { - lv_coord_t gap; - uint8_t dir :2; - uint8_t wrap :1; - uint8_t rev :1; - uint8_t main_place :3; - uint8_t cross_place :3; -}lv_flex_cont_t; + lv_layout_update_cb_t update_cb; /*The first element must be the update callback*/ + lv_coord_t item_gap; + lv_coord_t track_gap; + uint32_t dir :2; + uint32_t wrap :1; + uint32_t rev :1; + uint32_t item_main_place :3; + uint32_t track_place :3; + uint32_t item_cross_place :3; +}lv_flex_t; /********************** * GLOBAL PROTOTYPES @@ -81,7 +82,7 @@ typedef struct { * @param obj pointer to an object * @param flex_dir the flex direction, an element of `lv_flex_dir_t` */ -void lv_obj_set_flex_dir(struct _lv_obj_t * obj, lv_flex_dir_t flex_dir); +void lv_obj_set_flex_dir(struct _lv_obj_t * obj, lv_flex_flow_t flex_dir); /** * Set how to place the items and the tracks @@ -127,7 +128,7 @@ void lv_obj_set_flex_item_place(struct _lv_obj_t * obj, lv_flex_place_t place); * @param obj pointer to an object * @return the flex direction of `obj` */ -lv_flex_dir_t lv_obj_get_flex_dir(const struct _lv_obj_t * obj); +lv_flex_flow_t lv_obj_get_flex_dir(const struct _lv_obj_t * obj); /** * Get the item placement of a flex container @@ -157,12 +158,13 @@ lv_coord_t lv_obj_get_flex_gap(const struct _lv_obj_t * obj); * @return `LV_FLEX_PLACE_NONE/START/CENTER/END` */ 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 - */ -void _lv_flex_refresh(struct _lv_obj_t * cont); +/********************** + * GLOBAL VARIABLES + **********************/ +extern const lv_flex_t lv_flex_center; +extern const lv_flex_t lv_flex_stacked; +extern const lv_flex_t lv_flex_even; /********************** * MACROS diff --git a/src/lv_core/lv_grid.c b/src/lv_core/lv_grid.c index 2454bf0aae..6f44d1b580 100644 --- a/src/lv_core/lv_grid.c +++ b/src/lv_core/lv_grid.c @@ -26,11 +26,15 @@ typedef struct { /********************** * STATIC PROTOTYPES **********************/ -static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * calc); -static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * calc); -static void item_repos(lv_obj_t * item, _lv_grid_calc_t * calc, item_repos_hint_t * hint); +void grid_update(lv_obj_t * cont, lv_obj_t * item); +static void full_refresh(lv_obj_t * cont); +static void item_refr(lv_obj_t * item); +static void calc(struct _lv_obj_t * obj, _lv_grid_calc_t * calc); +static void calc_free(_lv_grid_calc_t * calc); +static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * c); +static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * c); +static void item_repos(lv_obj_t * item, _lv_grid_calc_t * c, item_repos_hint_t * hint); static lv_coord_t grid_place(lv_coord_t cont_size, bool auto_size, uint8_t place, lv_coord_t gap, uint32_t track_num, lv_coord_t * size_array, lv_coord_t * pos_array, bool reverse); -static void report_grid_change_core(const lv_grid_t * grid, lv_obj_t * obj); /********************** * STATIC VARIABLES @@ -47,6 +51,7 @@ static void report_grid_change_core(const lv_grid_t * grid, lv_obj_t * obj); void lv_grid_init(lv_grid_t * grid) { _lv_memset_00(grid,sizeof(lv_grid_t)); + grid->update_cb = grid_update; grid->col_place = LV_GRID_START; grid->row_place = LV_GRID_START; } @@ -72,55 +77,79 @@ void lv_grid_set_gap(lv_grid_t * grid, lv_coord_t col_gap, uint8_t row_gap) grid->row_gap = row_gap; } -/** - * Set a grid for an object - * @param obj pointer to an object - * @param grid the grid to set - */ -void lv_obj_set_grid(lv_obj_t * obj, const lv_grid_t * grid) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); - obj->spec_attr->grid = grid; - - _lv_grid_full_refresh(obj); -} - -/** - * Get the grid of an object - * @param obj pointer to an object - * @return the grid, NULL if no grid - */ -const lv_grid_t * lv_obj_get_grid(lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(obj->spec_attr) return obj->spec_attr->grid; - return NULL; -} void lv_obj_set_grid_cell(lv_obj_t * obj, lv_coord_t col_pos, lv_coord_t row_pos) { lv_obj_set_pos(obj, col_pos, row_pos); } -/** - * Notify all object if a style is modified - * @param grid pointer to a grid. Only the objects with this grid will be notified - * (NULL to notify all objects with any grid) - */ -void lv_obj_report_grid_change(const lv_grid_t * grid) -{ - lv_disp_t * d = lv_disp_get_next(NULL); - while(d) { - uint32_t i; - for(i = 0; i < d->screen_cnt; i++) { - report_grid_change_core(grid, d->screens[i]); + +/********************** + * STATIC FUNCTIONS + **********************/ + +void grid_update(lv_obj_t * cont, lv_obj_t * item) +{ + if(cont->spec_attr == NULL) return; + if(cont->spec_attr->layout_dsc == NULL) return; + + if(item) item_refr(item); + else full_refresh(cont); +} + +/** + * Refresh the all grid item on a container + * @param cont pointer to a grid container object + */ +static void full_refresh(lv_obj_t * cont) +{ + const lv_grid_t * g = cont->spec_attr->layout_dsc; + /*Calculate the grid*/ + if(g == NULL) return; + _lv_grid_calc_t c; + calc(cont, &c); + + + item_repos_hint_t hint; + _lv_memset_00(&hint, sizeof(hint)); + + /* Calculate the grids absolute x and y coordinates. + * It will be used as helper during item repositioning to avoid calculating this value for every children*/ + lv_coord_t pad_left = lv_obj_get_style_pad_left(cont, LV_PART_MAIN); + lv_coord_t pad_top = lv_obj_get_style_pad_top(cont, LV_PART_MAIN); + hint.grid_abs.x = pad_left + cont->coords.x1 - lv_obj_get_scroll_x(cont); + hint.grid_abs.y = pad_top + cont->coords.y1 - lv_obj_get_scroll_y(cont); + + uint32_t i; + for(i = 0; i < cont->spec_attr->child_cnt; i++) { + lv_obj_t * item = cont->spec_attr->children[i]; + if(LV_COORD_IS_LAYOUT(item->x_set) && LV_COORD_IS_LAYOUT(item->y_set)) { + item_repos(item, &c, &hint); } - d = lv_disp_get_next(d); } + calc_free(&c); + + if(cont->w_set == LV_SIZE_AUTO || cont->h_set == LV_SIZE_AUTO) { + lv_obj_set_size(cont, cont->w_set, cont->h_set); + } +} + +/** + * Refresh the position of a grid item + * @param item pointer to a grid item + */ +static void item_refr(lv_obj_t * item) +{ + /*Calculate the grid*/ + lv_obj_t * cont = lv_obj_get_parent(item); + if(cont == NULL) return; + _lv_grid_calc_t c; + calc(cont, &c); + + item_repos(item, &c, NULL); + + calc_free(&c); } /** @@ -129,10 +158,9 @@ void lv_obj_report_grid_change(const lv_grid_t * grid) * @param calc store the calculated cells sizes here * @note `_lv_grid_calc_free(calc_out)` needs to be called when `calc_out` is not needed anymore */ -void _lv_grid_calc(struct _lv_obj_t * cont, _lv_grid_calc_t * calc_out) +static void calc(struct _lv_obj_t * cont, _lv_grid_calc_t * calc_out) { - const lv_grid_t * g = lv_obj_get_grid(cont); - if(g == NULL) return; + const lv_grid_t * g = cont->spec_attr->layout_dsc; if(g->col_dsc == NULL || g->row_dsc == NULL) return; if(g->col_dsc_len == 0 || g->row_dsc_len == 0) return; @@ -160,7 +188,7 @@ void _lv_grid_calc(struct _lv_obj_t * cont, _lv_grid_calc_t * calc_out) * Free the a grid calculation's data * @param calc pointer to the calculated gtrid cell coordinates */ -void _lv_grid_calc_free(_lv_grid_calc_t * calc) +static void calc_free(_lv_grid_calc_t * calc) { _lv_mem_buf_release(calc->x); _lv_mem_buf_release(calc->y); @@ -168,149 +196,53 @@ void _lv_grid_calc_free(_lv_grid_calc_t * calc) _lv_mem_buf_release(calc->h); } -/** - * Check if the object's grid columns has FR cells or not - * @param obj pointer to an object - * @return true: has FR; false: has no FR - */ -bool _lv_grid_has_fr_col(struct _lv_obj_t * obj) +static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * c) { - const lv_grid_t * g = lv_obj_get_grid(obj); - if(g->col_dsc == NULL) return false; - - uint32_t i; - for(i = 0; i < g->col_dsc_len; i++) { - if(LV_GRID_IS_FR(g->col_dsc[i])) return true; - } - - return false; -} - -/** - * Check if the object's grid rows has FR cells or not - * @param obj pointer to an object - * @return true: has FR; false: has no FR - */ -bool _lv_grid_has_fr_row(struct _lv_obj_t * obj) -{ - const lv_grid_t * g = lv_obj_get_grid(obj); - if(g == NULL) return false; - if(g->row_dsc == NULL) return false; - - uint32_t i; - for(i = 0; i < g->row_dsc_len; i++) { - if(LV_GRID_IS_FR(g->row_dsc[i])) return true; - } - - return false; -} - -/** - * Refresh the all grid item on a container - * @param cont pointer to a grid container object - */ -void _lv_grid_full_refresh(lv_obj_t * cont) -{ - /*Calculate the grid*/ - if(lv_obj_get_grid(cont) == NULL) return; - _lv_grid_calc_t calc; - _lv_grid_calc(cont, &calc); - - - item_repos_hint_t hint; - _lv_memset_00(&hint, sizeof(hint)); - - /* Calculate the grids absolute x and y coordinates. - * It will be used as helper during item repositioning to avoid calculating this value for every children*/ - lv_coord_t pad_left = lv_obj_get_style_pad_left(cont, LV_PART_MAIN); - lv_coord_t pad_top = lv_obj_get_style_pad_top(cont, LV_PART_MAIN); - hint.grid_abs.x = pad_left + cont->coords.x1 - lv_obj_get_scroll_x(cont); - hint.grid_abs.y = pad_top + cont->coords.y1 - lv_obj_get_scroll_y(cont); - - uint32_t i; - for(i = 0; i < cont->spec_attr->child_cnt; i++) { - lv_obj_t * item = cont->spec_attr->children[i]; - if(LV_COORD_IS_GRID(item->x_set) && LV_COORD_IS_GRID(item->y_set)) { - item_repos(item, &calc, &hint); - } - } - _lv_grid_calc_free(&calc); - - if(cont->w_set == LV_SIZE_AUTO || cont->h_set == LV_SIZE_AUTO) { - lv_obj_set_size(cont, cont->w_set, cont->h_set); - } -} - -/** - * Refresh the position of a grid item - * @param item pointer to a grid item - */ -void lv_grid_item_refr_pos(lv_obj_t * item) -{ - /*Calculate the grid*/ - lv_obj_t * cont = lv_obj_get_parent(item); - if(cont == NULL) return; - if(cont->spec_attr == NULL) return; - if(cont->spec_attr->grid == NULL) return; - _lv_grid_calc_t calc; - _lv_grid_calc(cont, &calc); - - item_repos(item, &calc, NULL); - - _lv_grid_calc_free(&calc); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * calc) -{ - const lv_grid_t * grid = cont->spec_attr->grid; + const lv_grid_t * grid = cont->spec_attr->layout_dsc; uint32_t i; lv_coord_t cont_w = lv_obj_get_width_fit(cont); - calc->col_num = grid->col_dsc_len; - calc->x = _lv_mem_buf_get(sizeof(lv_coord_t) * calc->col_num); - calc->w = _lv_mem_buf_get(sizeof(lv_coord_t) * calc->col_num); + c->col_num = grid->col_dsc_len; + c->x = _lv_mem_buf_get(sizeof(lv_coord_t) * c->col_num); + c->w = _lv_mem_buf_get(sizeof(lv_coord_t) * c->col_num); uint32_t col_fr_cnt = 0; lv_coord_t grid_w = 0; bool auto_w = cont->w_set == LV_SIZE_AUTO ? true : false; - for(i = 0; i < calc->col_num; i++) { + for(i = 0; i < c->col_num; i++) { lv_coord_t x = grid->col_dsc[i]; if(LV_GRID_IS_FR(x)) col_fr_cnt += LV_GRID_GET_FR(x); else { - calc->w[i] = x; + c->w[i] = x; grid_w += x; } } - cont_w -= grid->col_gap * (calc->col_num - 1); + cont_w -= grid->col_gap * (c->col_num - 1); lv_coord_t free_w = cont_w - grid_w; - for(i = 0; i < calc->col_num; i++) { + for(i = 0; i < c->col_num; i++) { lv_coord_t x = grid->col_dsc[i]; if(LV_GRID_IS_FR(x)) { - if(auto_w) calc->w[i] = 0; /*Fr is considered zero if the cont has auto width*/ + if(auto_w) c->w[i] = 0; /*Fr is considered zero if the cont has auto width*/ else { lv_coord_t f = LV_GRID_GET_FR(x); - calc->w[i] = (free_w * f) / col_fr_cnt; + c->w[i] = (free_w * f) / col_fr_cnt; } } } } -static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * calc) +static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * c) { - const lv_grid_t * grid = cont->spec_attr->grid; + const lv_grid_t * grid = cont->spec_attr->layout_dsc; uint32_t i; - calc->row_num = grid->row_dsc_len; - calc->y = _lv_mem_buf_get(sizeof(lv_coord_t) * calc->row_num); - calc->h = _lv_mem_buf_get(sizeof(lv_coord_t) * calc->row_num); + c->row_num = grid->row_dsc_len; + c->y = _lv_mem_buf_get(sizeof(lv_coord_t) * c->row_num); + c->h = _lv_mem_buf_get(sizeof(lv_coord_t) * c->row_num); uint32_t row_fr_cnt = 0; lv_coord_t grid_h = 0; @@ -322,7 +254,7 @@ static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * calc) lv_coord_t x = grid->row_dsc[i]; if(LV_GRID_IS_FR(x)) row_fr_cnt += LV_GRID_GET_FR(x); else { - calc->h[i] = x; + c->h[i] = x; grid_h += x; } } @@ -333,10 +265,10 @@ static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * calc) for(i = 0; i < grid->row_dsc_len; i++) { lv_coord_t x = grid->row_dsc[i]; if(LV_GRID_IS_FR(x)) { - if(auto_h) calc->h[i] = 0; /*Fr is considered zero if the obj has auto height*/ + if(auto_h) c->h[i] = 0; /*Fr is considered zero if the obj has auto height*/ else { lv_coord_t f = LV_GRID_GET_FR(x); - calc->h[i] = (free_h * f) / row_fr_cnt; + c->h[i] = (free_h * f) / row_fr_cnt; } } } @@ -349,21 +281,21 @@ static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * calc) * @param child_id_ext helper value if the ID of the child is know (order from the oldest) else -1 * @param grid_abs helper value, the absolute position of the grid, NULL if unknown */ -static void item_repos(lv_obj_t * item, _lv_grid_calc_t * calc, item_repos_hint_t * hint) +static void item_repos(lv_obj_t * item, _lv_grid_calc_t * c, item_repos_hint_t * hint) { - if(_lv_obj_is_grid_item(item) == false) return; + if(LV_COORD_IS_LAYOUT(item->x_set) && LV_COORD_IS_LAYOUT(item->y_set)) return; uint32_t col_pos = LV_GRID_GET_CELL_POS(item->x_set); uint32_t col_span = LV_GRID_GET_CELL_SPAN(item->x_set); uint32_t row_pos = LV_GRID_GET_CELL_POS(item->y_set); uint32_t row_span = LV_GRID_GET_CELL_SPAN(item->y_set); - lv_coord_t col_x1 = calc->x[col_pos]; - lv_coord_t col_x2 = calc->x[col_pos + col_span - 1] + calc->w[col_pos + col_span - 1]; + lv_coord_t col_x1 = c->x[col_pos]; + lv_coord_t col_x2 = c->x[col_pos + col_span - 1] + c->w[col_pos + col_span - 1]; lv_coord_t col_w = col_x2 - col_x1; - lv_coord_t row_y1 = calc->y[row_pos]; - lv_coord_t row_y2 = calc->y[row_pos + row_span - 1] + calc->h[row_pos + row_span - 1]; + lv_coord_t row_y1 = c->y[row_pos]; + lv_coord_t row_y2 = c->y[row_pos + row_span - 1] + c->h[row_pos + row_span - 1]; lv_coord_t row_h = row_y2 - row_y1; uint8_t x_flag = LV_GRID_GET_CELL_PLACE(item->x_set); @@ -377,47 +309,50 @@ static void item_repos(lv_obj_t * item, _lv_grid_calc_t * calc, item_repos_hint_ lv_coord_t x; lv_coord_t y; - lv_coord_t item_w = lv_obj_get_width(item); - lv_coord_t item_h = lv_obj_get_height(item); + lv_coord_t item_w = lv_area_get_width(&item->coords); + lv_coord_t item_h = lv_area_get_height(&item->coords); lv_coord_t margin_top = lv_obj_get_style_margin_top(item, LV_PART_MAIN); lv_coord_t margin_bottom = lv_obj_get_style_margin_bottom(item, LV_PART_MAIN); lv_coord_t margin_left = lv_obj_get_style_margin_left(item, LV_PART_MAIN); lv_coord_t margin_right = lv_obj_get_style_margin_right(item, LV_PART_MAIN); + if(item->w_set == LV_SIZE_LAYOUT) item->w_set = item_w; + if(item->h_set == LV_SIZE_LAYOUT) item->h_set = item_h; + switch(x_flag) { default: case LV_GRID_START: - x = calc->x[col_pos] + margin_left; + x = c->x[col_pos] + margin_left; break; case LV_GRID_STRETCH: - x = calc->x[col_pos] + margin_left; + x = c->x[col_pos] + margin_left; item_w = col_w - margin_left - margin_right; - item->w_set = LV_SIZE_STRETCH; + item->w_set = LV_SIZE_LAYOUT; break; case LV_GRID_CENTER: - x = calc->x[col_pos] + (col_w - (item_w + margin_left - margin_right)) / 2; + x = c->x[col_pos] + (col_w - (item_w + margin_left - margin_right)) / 2; break; case LV_GRID_END: - x = calc->x[col_pos] + col_w - lv_obj_get_width(item) - margin_right; + x = c->x[col_pos] + col_w - lv_obj_get_width(item) - margin_right; break; } switch(y_flag) { default: case LV_GRID_START: - y = calc->y[row_pos] + margin_top; + y = c->y[row_pos] + margin_top; break; case LV_GRID_STRETCH: - y = calc->y[row_pos] + margin_top; + y = c->y[row_pos] + margin_top; item_h = row_h - margin_top - margin_bottom; - item->h_set = LV_SIZE_STRETCH; + item->h_set = LV_SIZE_LAYOUT; break; case LV_GRID_CENTER: - y = calc->y[row_pos] + (row_h - (item_h + margin_top + margin_bottom)) / 2; + y = c->y[row_pos] + (row_h - (item_h + margin_top + margin_bottom)) / 2; break; case LV_GRID_END: - y = calc->y[row_pos] + row_h - lv_obj_get_height(item) - margin_bottom; + y = c->y[row_pos] + row_h - lv_obj_get_height(item) - margin_bottom; break; } @@ -516,22 +451,3 @@ static lv_coord_t grid_place(lv_coord_t cont_size, bool auto_size, uint8_t plac /*Return the full size of the grid*/ return total_gird_size; } - - -/** - * Refresh the grid of all children of an object. (Called recursively) - * @param grid refresh objects only with this grid. - * @param obj pointer to an object - */ -static void report_grid_change_core(const lv_grid_t * grid, lv_obj_t * obj) -{ - if(obj->spec_attr) { - if(obj->spec_attr->grid == grid || (obj->spec_attr->grid && grid == NULL)) _lv_grid_full_refresh(obj); - } - - uint32_t i; - for(i = 0; i < obj->spec_attr->child_cnt; i++) { - report_grid_change_core(grid, obj->spec_attr->children[i]); - } - -} diff --git a/src/lv_core/lv_grid.h b/src/lv_core/lv_grid.h index 56dc9efbee..791a0ca4c0 100644 --- a/src/lv_core/lv_grid.h +++ b/src/lv_core/lv_grid.h @@ -13,7 +13,7 @@ extern "C" { /********************* * INCLUDES *********************/ -#include "../lv_misc/lv_area.h" +#include "lv_obj_pos.h" /********************* * DEFINES @@ -45,9 +45,9 @@ extern "C" { #define LV_GRID_GET_CELL_SPAN(c) (((c) & _LV_GRID_CELL_SPAN_MASK) >> _LV_GRID_CELL_SHIFT) #define LV_GRID_GET_CELL_PLACE(c) ((c) >> (_LV_GRID_CELL_SHIFT * 2) & 0x7) -#define LV_GRID_FR(x) (_LV_COORD_GRID(x)) -#define LV_GRID_IS_FR(x) (LV_COORD_IS_GRID(x)) -#define LV_GRID_GET_FR(x) (LV_COORD_GET_GRID(x)) +#define LV_GRID_FR(x) (LV_COORD_SET_LAYOUT(x)) +#define LV_GRID_IS_FR(x) (LV_COORD_IS_LAYOUT(x)) +#define LV_GRID_GET_FR(x) (_LV_COORD_PLAIN(x)) /********************** * TYPEDEFS @@ -57,6 +57,7 @@ extern "C" { struct _lv_obj_t; typedef struct { + lv_layout_update_cb_t update_cb; /*The first element must be the update callback*/ const lv_coord_t * col_dsc; const lv_coord_t * row_dsc; uint8_t col_dsc_len; @@ -90,20 +91,6 @@ void lv_grid_set_place(lv_grid_t * grid, uint8_t col_place, uint8_t row_place); void lv_grid_set_gap(lv_grid_t * grid, lv_coord_t col_gap, uint8_t row_gap); -/** - * Set a grid for an object - * @param obj pointer to an object - * @param grid the grid to set - */ -void lv_obj_set_grid(struct _lv_obj_t * obj, const lv_grid_t * grid); - -/** - * Get the grid of an object - * @param obj pointer to an object - * @return the grid, NULL if no grid - */ -const lv_grid_t * lv_obj_get_grid(struct _lv_obj_t * obj); - void lv_obj_set_grid_cell(struct _lv_obj_t * obj, lv_coord_t col_pos, lv_coord_t row_pos); /** @@ -113,9 +100,6 @@ void lv_obj_set_grid_cell(struct _lv_obj_t * obj, lv_coord_t col_pos, lv_coord_t */ void lv_obj_report_grid_change(const lv_grid_t * grid); -void _lv_grid_calc(struct _lv_obj_t * obj, _lv_grid_calc_t * calc); - -void _lv_grid_calc_free(_lv_grid_calc_t * calc); bool _lv_grid_has_fr_col(struct _lv_obj_t * obj); diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index 82e6c690e2..765741f47b 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -1474,7 +1474,7 @@ static void lv_obj_constructor(lv_obj_t * obj, lv_obj_t * parent, const lv_obj_t obj->flags |= LV_OBJ_FLAG_SCROLLABLE; obj->flags |= LV_OBJ_FLAG_SCROLL_ELASTIC; obj->flags |= LV_OBJ_FLAG_SCROLL_MOMENTUM; - obj->flags |= LV_OBJ_FLAG_FOCUS_SCROLL; + obj->flags |= LV_OBJ_FLAG_SCROLL_ON_FOCUS; if(parent) obj->flags |= LV_OBJ_FLAG_GESTURE_BUBBLE; obj->style_list.cache_state = LV_OBJ_STYLE_CACHE_STATE_INVALID; @@ -1747,7 +1747,7 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) else if(sign == LV_SIGNAL_FOCUS) { lv_obj_t * parent = lv_obj_get_parent(obj); lv_obj_t * child = obj; - while(parent && lv_obj_has_flag(child, LV_OBJ_FLAG_FOCUS_SCROLL)) { + while(parent && lv_obj_has_flag(child, LV_OBJ_FLAG_SCROLL_ON_FOCUS)) { lv_obj_scroll_to_view(child, LV_ANIM_ON); child = parent; parent = lv_obj_get_parent(parent); @@ -1805,14 +1805,11 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) lv_obj_set_size(child, child->w_set, child->h_set); } } - if(lv_obj_get_grid(obj)) _lv_grid_full_refresh(obj); - if(lv_obj_get_flex_dir(obj) != LV_FLEX_DIR_NONE) _lv_flex_refresh(obj); + lv_obj_update_layout(obj, NULL); } } else if(sign == LV_SIGNAL_CHILD_CHG) { - if(param == NULL || _lv_obj_is_flex_item(param)) { - _lv_flex_refresh(obj); - } + lv_obj_update_layout(obj, param); if(obj->w_set == LV_SIZE_AUTO || obj->h_set == LV_SIZE_AUTO) { lv_obj_set_size(obj, obj->w_set, obj->h_set); @@ -1835,11 +1832,9 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) *s = LV_MATH_MAX(*s, d); } else if(sign == LV_SIGNAL_STYLE_CHG) { - if(_lv_obj_is_grid_item(obj)) lv_grid_item_refr_pos(obj); - if(lv_obj_get_grid(obj)) _lv_grid_full_refresh(obj); - - if(_lv_obj_is_flex_item(obj)) _lv_flex_refresh(lv_obj_get_parent(obj)); - if(lv_obj_get_flex_dir(obj)) _lv_flex_refresh(obj); + /* Padding might have changed so the layout should be recalculated + * If margin has also changed the parent's layout also needs to be updated but it's done in CHILD_CHG signal*/ + lv_obj_update_layout(obj, NULL); /*Reposition non grid objects on by one*/ uint32_t i; diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index 794aa15806..f8673697b2 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -181,7 +181,7 @@ enum { LV_OBJ_FLAG_EVENT_BUBBLE = (1 << 11), LV_OBJ_FLAG_GESTURE_BUBBLE = (1 << 12), LV_OBJ_FLAG_FOCUS_BUBBLE = (1 << 13), - LV_OBJ_FLAG_FOCUS_SCROLL = (1 << 14), /** Automatically scroll the focused object's ancestors to make the focused object visible*/ + LV_OBJ_FLAG_SCROLL_ON_FOCUS = (1 << 14), /** Automatically scroll the focused object's ancestors to make the focused object visible*/ LV_OBJ_FLAG_ADV_HITTEST = (1 << 15), }; typedef uint16_t lv_obj_flag_t; @@ -192,7 +192,6 @@ typedef uint16_t lv_obj_flag_t; #include "lv_obj_style.h" #include "lv_obj_draw.h" - typedef struct { struct _lv_obj_t ** children; /**< Store the pointer of the children.*/ uint32_t child_cnt; @@ -200,11 +199,10 @@ typedef struct { void * group_p; #endif - const lv_grid_t * grid; + const void * layout_dsc; lv_event_cb_t event_cb; /**< Event callback function */ - lv_flex_cont_t flex_cont; lv_point_t scroll; /**< The current X/Y scroll offset*/ lv_coord_t ext_draw_pad; /**< EXTend the size in every direction for drawing. */ diff --git a/src/lv_core/lv_obj_pos.c b/src/lv_core/lv_obj_pos.c index 3f6ebe27ca..489067c27a 100644 --- a/src/lv_core/lv_obj_pos.c +++ b/src/lv_core/lv_obj_pos.c @@ -16,6 +16,9 @@ /********************** * TYPEDEFS **********************/ +typedef struct { + lv_layout_update_cb_t update_cb; +}lv_layout_base_t; /********************** * STATIC PROTOTYPES @@ -34,6 +37,24 @@ static bool refr_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h); * GLOBAL FUNCTIONS **********************/ +bool lv_obj_is_layout_positioned(const lv_obj_t * obj) +{ + lv_obj_t * parent = lv_obj_get_parent(obj); + if(parent == NULL) return false; + if(parent->spec_attr && parent->spec_attr->layout_dsc) return true; + else return false; +} + +void lv_obj_update_layout(lv_obj_t * cont, lv_obj_t * item) +{ + if(cont->spec_attr == NULL) return; + if(cont->spec_attr->layout_dsc == NULL) return; + + const lv_layout_base_t * layout = cont->spec_attr->layout_dsc; + if(layout->update_cb == NULL) return; + layout->update_cb(cont, item); +} + /** * Set relative the position of an object (relative to the parent) * @param obj pointer to an object @@ -50,37 +71,15 @@ void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); + if(lv_obj_is_layout_positioned(obj)) { + LV_LOG_WARN("Can't set position because the position is set by a layout"); + return; + } + obj->x_set = x; obj->y_set = y; - bool gi = _lv_obj_is_grid_item(obj); - bool fi = _lv_obj_is_flex_item(obj); - - /*For consistency set the size to stretched if the objects is stretched on the grid*/ - if(gi) { - if(LV_GRID_GET_CELL_PLACE(obj->x_set) == LV_GRID_STRETCH) obj->w_set = LV_SIZE_STRETCH; - if(LV_GRID_GET_CELL_PLACE(obj->y_set) == LV_GRID_STRETCH) obj->h_set = LV_SIZE_STRETCH; - } - - /*If not grid or flex item but has grid or flex position set the position to 0*/ - if(!gi) { - if(LV_COORD_IS_GRID(x)) x = 0; - if(LV_COORD_IS_GRID(y)) y = 0; - } - - if(!fi) { - if(LV_COORD_IS_FLEX(x)) x = 0; - if(LV_COORD_IS_FLEX(y)) y = 0; - } - - /*If the object is on a grid item let the grid to position it. */ - if(gi) { - lv_grid_item_refr_pos(obj); - } else if(fi) { - _lv_flex_refresh(lv_obj_get_parent(obj)); - } else { - _lv_obj_move_to(obj, x, y, true); - } + _lv_obj_move_to(obj, x, y, true); } /** @@ -117,33 +116,12 @@ void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - bool gi = _lv_obj_is_grid_item(obj); - bool fi = _lv_obj_is_flex_item(obj); - bool x_stretch = false; - bool y_stretch = false; - /*Use `LV_SIZE_STRETCH` value if the layout changes the size of the object*/ - if(gi) { - if(LV_GRID_GET_CELL_PLACE(obj->x_set)) x_stretch = true; - if(LV_GRID_GET_CELL_PLACE(obj->y_set)) y_stretch = true; - } - if(fi) { - lv_obj_t * parent = lv_obj_get_parent(obj); - if(parent->spec_attr->flex_cont.dir == LV_FLEX_DIR_ROW && LV_COORD_GET_FLEX(obj->y_set) == LV_FLEX_PLACE_STRETCH) y_stretch = true; - if(parent->spec_attr->flex_cont.dir == LV_FLEX_DIR_COLUMN && LV_COORD_GET_FLEX(obj->x_set) == LV_FLEX_PLACE_STRETCH) x_stretch = true; - } + if(obj->w_set == LV_SIZE_LAYOUT && obj->h_set == LV_SIZE_LAYOUT) return; - if(x_stretch) w = LV_SIZE_STRETCH; - if(y_stretch) h = LV_SIZE_STRETCH; - obj->w_set = w; - obj->h_set = h; - - /*If both stretched the size is managed by the grid*/ - if(x_stretch && y_stretch) return; - - if(x_stretch) w = lv_obj_get_width(obj); - if(y_stretch) h = lv_obj_get_height(obj); + if(obj->w_set == LV_SIZE_LAYOUT) w = lv_obj_get_width(obj); + if(obj->h_set == LV_SIZE_LAYOUT) h = lv_obj_get_height(obj); /*Calculate the required auto sizes*/ bool x_auto = obj->w_set == LV_SIZE_AUTO ? true : false; @@ -163,10 +141,10 @@ void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) lv_obj_t * parent = lv_obj_get_parent(obj); if(parent) { - lv_coord_t cont_w = lv_obj_get_width_fit(parent); - lv_coord_t cont_h = lv_obj_get_height_fit(parent); - if(pct_w) w = (_LV_COORD_GET_PCT(obj->w_set) * cont_w) / 100; - if(pct_h) h = (_LV_COORD_GET_PCT(obj->h_set) * cont_h) / 100; + lv_coord_t parent_w = lv_obj_get_width_fit(parent); + lv_coord_t parent_h = lv_obj_get_height_fit(parent); + if(pct_w) w = (LV_COORD_GET_PCT(obj->w_set) * parent_w) / 100; + if(pct_h) h = (LV_COORD_GET_PCT(obj->h_set) * parent_h) / 100; } refr_size(obj, w, h); @@ -250,6 +228,21 @@ void lv_obj_set_height_margin(lv_obj_t * obj, lv_coord_t h) lv_obj_set_height(obj, h - mtop - mbottom); } +/** + * Set a layout for an object + * @param obj pointer to an object + * @param layout pointer to a layout descriptor to set + */ +void lv_obj_set_layout(lv_obj_t * obj, const void * layout) +{ + LV_ASSERT_OBJ(obj, LV_OBJX_NAME); + + lv_obj_allocate_spec_attr(obj); + obj->spec_attr->layout_dsc = layout; + + lv_obj_update_layout(obj, NULL); +} + /** * Align an object to an other object. * @param obj pointer to an object to align @@ -625,14 +618,6 @@ void _lv_obj_move_to(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, bool notify_par x += pad_left + parent->coords.x1 - lv_obj_get_scroll_x(parent); y += pad_top + parent->coords.y1 - lv_obj_get_scroll_y(parent); - } else { - /*If no parent then it's screen but screen can't be on a grid*/ - if(LV_COORD_IS_GRID(obj->x_set) || LV_COORD_IS_GRID(obj->x_set)) { - obj->x_set = 0; - obj->y_set = 0; - x = 0; - y = 0; - } } /*Calculate and set the movement*/ @@ -690,41 +675,6 @@ void _lv_obj_move_children_by(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_di } } -/** - * Check if an object is valid grid item or not. - * @param obj pointer to an object to check - * @return true: grid item; false: not grid item - */ -bool _lv_obj_is_grid_item(lv_obj_t * obj) -{ - lv_obj_t * cont = lv_obj_get_parent(obj); - if(cont == NULL) return false; - const lv_grid_t * g = lv_obj_get_grid(cont); - if(g == NULL) return false; - if(g->col_dsc == NULL) return false; - if(g->row_dsc == NULL) return false; - if(g->row_dsc_len == 0) return false; - if(g->col_dsc_len == 0) return false; - if(LV_COORD_IS_GRID(obj->x_set) == false || LV_COORD_IS_GRID(obj->y_set) == false) return false; - return true; -} - - -/** - * Check if an object is valid grid item or not. - * @param obj pointer to an object to check - * @return true: grid item; false: not grid item - */ -bool _lv_obj_is_flex_item(struct _lv_obj_t * obj) -{ - lv_obj_t * cont = lv_obj_get_parent(obj); - if(cont == NULL) return false; - if(lv_obj_get_flex_dir(cont) == LV_FLEX_DIR_NONE) return false; - if(LV_COORD_IS_FLEX(obj->x_set) == false || LV_COORD_IS_FLEX(obj->y_set) == false) return false; - return true; -} - - /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/lv_core/lv_obj_pos.h b/src/lv_core/lv_obj_pos.h index 4b77775e3c..236e72d898 100644 --- a/src/lv_core/lv_obj_pos.h +++ b/src/lv_core/lv_obj_pos.h @@ -24,10 +24,19 @@ extern "C" { **********************/ struct _lv_obj_t; +typedef void (*lv_layout_update_cb_t)(struct _lv_obj_t * cont, struct _lv_obj_t * item); + +typedef union { + uint32_t num; + const void * ptr; +}lv_layout_data_t; + /********************** * GLOBAL PROTOTYPES **********************/ +void lv_obj_update_layout(struct _lv_obj_t * cont, struct _lv_obj_t * item); + /** * Set relative the position of an object (relative to the parent) * @param obj pointer to an object @@ -245,15 +254,6 @@ void _lv_obj_move_to(struct _lv_obj_t * obj, lv_coord_t x, lv_coord_t y, bool no */ void _lv_obj_move_children_by(struct _lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff); -/** - * Check if an object is valid grid item or not. - * @param obj pointer to an object to check - * @return true: grid item; false: not grid item - */ -bool _lv_obj_is_grid_item(struct _lv_obj_t * obj); - -bool _lv_obj_is_flex_item(struct _lv_obj_t * obj); - /********************** * MACROS **********************/ diff --git a/src/lv_core/lv_obj_style.c b/src/lv_core/lv_obj_style.c index 0b092b0c21..782f3be03a 100644 --- a/src/lv_core/lv_obj_style.c +++ b/src/lv_core/lv_obj_style.c @@ -47,7 +47,7 @@ typedef enum { static void report_style_change_core(void * style, lv_obj_t * obj); static void refresh_children_style(lv_obj_t * obj); #if LV_USE_ANIMATION -static void trans_del(lv_obj_t * obj, uint8_t part, lv_style_prop_t prop, lv_style_trans_t * tr_limit); +static bool trans_del(lv_obj_t * obj, uint8_t part, lv_style_prop_t prop, lv_style_trans_t * tr_limit); static void trans_anim_cb(lv_style_trans_t * tr, lv_anim_value_t v); static void trans_anim_start_cb(lv_anim_t * a); static void trans_anim_ready_cb(lv_anim_t * a); @@ -78,14 +78,7 @@ void _lv_obj_style_init(void) _lv_ll_init(&LV_GC_ROOT(_lv_obj_style_trans_ll), sizeof(lv_style_trans_t)); } -/** - * Add a new style to the style list of an object. - * @param obj pointer to an object - * @param part the part of the object which style property should be set. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param style pointer to a style to add (Only its pointer will be saved) - */ -void lv_obj_add_style(struct _lv_obj_t * obj, uint32_t part, uint32_t state, lv_style_t * style) +void lv_obj_add_style_no_refresh(struct _lv_obj_t * obj, uint32_t part, uint32_t state, lv_style_t * style) { if(style == NULL) return; @@ -117,6 +110,18 @@ void lv_obj_add_style(struct _lv_obj_t * obj, uint32_t part, uint32_t state, lv_ obj->style_list.styles[i].part = part; obj->style_list.styles[i].state = state; +} + +/** + * Add a new style to the style list of an object. + * @param obj pointer to an object + * @param part the part of the object which style property should be set. + * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` + * @param style pointer to a style to add (Only its pointer will be saved) + */ +void lv_obj_add_style(struct _lv_obj_t * obj, uint32_t part, uint32_t state, lv_style_t * style) +{ + lv_obj_add_style_no_refresh(obj, part, state, style); _lv_obj_refresh_style(obj, LV_STYLE_PROP_ALL); } @@ -160,6 +165,17 @@ void lv_obj_remove_style(lv_obj_t * obj, uint32_t part, uint32_t state, lv_style _lv_obj_refresh_style(obj, LV_STYLE_PROP_ALL); } +void lv_obj_remove_all_styles_no_refresh(lv_obj_t * obj) +{ +#if LV_USE_ANIMATION + trans_del(obj, 0xFF, 0xFF, NULL); +#endif + + lv_mem_free(obj->style_list.styles); + obj->style_list.styles = NULL; + obj->style_list.style_cnt = 0; +} + /** * Reset a style to the default (empty) state. * Release all used memories and cancel pending related transitions. @@ -170,14 +186,7 @@ void lv_obj_remove_style(lv_obj_t * obj, uint32_t part, uint32_t state, lv_style */ void lv_obj_remove_all_styles(lv_obj_t * obj) { -#if LV_USE_ANIMATION - trans_del(obj, 0xFF, 0xFF, NULL); -#endif - - lv_mem_free(obj->style_list.styles); - obj->style_list.styles = NULL; - obj->style_list.style_cnt = 0; - + lv_obj_remove_all_styles_no_refresh(obj); _lv_obj_refresh_style(obj, LV_STYLE_PROP_ALL); } @@ -800,8 +809,8 @@ static void update_cache(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop) else list->cache_img_recolor_opa_zero = 0; } if(prop == LV_STYLE_PROP_ALL || prop == LV_STYLE_CONTENT_SRC) { - if(get_prop_core(obj, part, LV_STYLE_CONTENT_SRC, &v) == false) v.num = 0; - if(v.num == 0) list->cache_content_src_zero = 1; + if(get_prop_core(obj, part, LV_STYLE_CONTENT_SRC, &v) == false) v.ptr = NULL; + if(v.ptr == NULL) list->cache_content_src_zero = 1; else list->cache_content_src_zero = 0; } if(prop == LV_STYLE_PROP_ALL || prop == LV_STYLE_COLOR_FILTER_CB || prop == LV_STYLE_COLOR_FILTER_OPA) { @@ -847,7 +856,7 @@ static void update_cache(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop) static cache_t read_cache(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop) { - lv_obj_style_list_t * list = &obj->style_list; + const lv_obj_style_list_t * list = &obj->style_list; if(part != LV_PART_MAIN) return CACHE_NEED_CHECK; if(obj->state != list->cache_state) return CACHE_NEED_CHECK; if(obj->style_list.skip_trans) return CACHE_NEED_CHECK; @@ -941,7 +950,7 @@ static cache_t read_cache(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t else return CACHE_NEED_CHECK; break; case LV_STYLE_CONTENT_SRC: - if(list->cache_shadow_width_zero ) return CACHE_ZERO; + if(list->cache_content_src_zero ) return CACHE_ZERO; else return CACHE_NEED_CHECK; break; case LV_STYLE_COLOR_FILTER_CB: @@ -1028,10 +1037,11 @@ static void refresh_children_style(lv_obj_t * obj) * @param prop a property or 0xFF to remove all properties * @param tr_limit delete transitions only "older" then this. `NULL` is not used */ -static void trans_del(lv_obj_t * obj, uint8_t part, lv_style_prop_t prop, lv_style_trans_t * tr_limit) +static bool trans_del(lv_obj_t * obj, uint8_t part, lv_style_prop_t prop, lv_style_trans_t * tr_limit) { lv_style_trans_t * tr; lv_style_trans_t * tr_prev; + bool removed = false; tr = _lv_ll_get_tail(&LV_GC_ROOT(_lv_obj_style_trans_ll)); while(tr != NULL) { if(tr == tr_limit) break; @@ -1049,12 +1059,14 @@ static void trans_del(lv_obj_t * obj, uint8_t part, lv_style_prop_t prop, lv_sty lv_anim_del(tr, NULL); _lv_ll_remove(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr); lv_mem_free(tr); + removed = true; } } } tr = tr_prev; } + return removed; } static void trans_anim_cb(lv_style_trans_t * tr, lv_anim_value_t v) diff --git a/src/lv_misc/lv_area.h b/src/lv_misc/lv_area.h index 86926d2060..487cebec5f 100644 --- a/src/lv_misc/lv_area.h +++ b/src/lv_misc/lv_area.h @@ -224,31 +224,26 @@ void _lv_area_align(const lv_area_t * base, const lv_area_t * to_align, lv_align #define _LV_COORD_TYPE_SHIFT (13) #define _LV_COORD_TYPE_MASK (3 << _LV_COORD_TYPE_SHIFT) +#define _LV_COORD_PLAIN(x) ((x) & (~_LV_COORD_TYPE_MASK)) /*Remove type specifiers*/ + #define _LV_COORD_TYPE_PX (0 << _LV_COORD_TYPE_SHIFT) -#define _LV_COORD_TYPE_GRID (1 << _LV_COORD_TYPE_SHIFT) -#define _LV_COORD_TYPE_FLEX (2 << _LV_COORD_TYPE_SHIFT) -#define _LV_COORD_TYPE_SPEC (3 << _LV_COORD_TYPE_SHIFT) +#define _LV_COORD_TYPE_SPEC (1 << _LV_COORD_TYPE_SHIFT) +#define _LV_COORD_TYPE_LAYOUT (2 << _LV_COORD_TYPE_SHIFT) +#define _LV_COORD_TYPE_RESERVED (3 << _LV_COORD_TYPE_SHIFT) -#define LV_COORD_IS_PX(x) ((((x) & _LV_COORD_TYPE_MASK) == _LV_COORD_TYPE_PX) ? true : false) -#define LV_COORD_IS_GRID(x) ((((x) & _LV_COORD_TYPE_MASK) == _LV_COORD_TYPE_GRID) ? true : false) -#define LV_COORD_IS_FLEX(x) ((((x) & _LV_COORD_TYPE_MASK) == _LV_COORD_TYPE_FLEX) ? true : false) -#define LV_COORD_IS_SPEC(x) ((((x) & _LV_COORD_TYPE_MASK) == _LV_COORD_TYPE_SPEC) ? true : false) +#define LV_COORD_IS_PX(x) ((((x) & _LV_COORD_TYPE_MASK) == _LV_COORD_TYPE_PX) ? true : false) +#define LV_COORD_IS_SPEC(x) ((((x) & _LV_COORD_TYPE_MASK) == _LV_COORD_TYPE_SPEC) ? true : false) +#define LV_COORD_IS_LAYOUT(x) ((((x) & _LV_COORD_TYPE_MASK) == _LV_COORD_TYPE_LAYOUT) ? true : false) -#define LV_COORD_GET_PX(x) ((x) & ~(_LV_COORD_TYPE_MASK)) -#define LV_COORD_GET_GRID(x) ((x) & ~(_LV_COORD_TYPE_MASK)) -#define LV_COORD_GET_FLEX(x) ((x) & ~(_LV_COORD_TYPE_MASK)) -#define LV_COORD_GET_SPEC(x) ((x) & ~(_LV_COORD_TYPE_MASK)) - -#define _LV_COORD_GRID(x) (_LV_COORD_TYPE_GRID | (x)) -#define _LV_COORD_FELX(x) (_LV_COORD_TYPE_FLEX | (x)) -#define _LV_COORD_SPEC(x) (_LV_COORD_TYPE_SPEC | (x)) +#define LV_COORD_SET_SPEC(x) ((x) | _LV_COORD_TYPE_SPEC) +#define LV_COORD_SET_LAYOUT(x) ((x) | _LV_COORD_TYPE_LAYOUT) /*Special coordinates*/ -#define LV_COORD_PCT(x) _LV_COORD_SPEC((x)) -#define LV_COORD_IS_PCT(x) ((LV_COORD_IS_SPEC(x) && LV_COORD_GET_SPEC(x) <= 1000) ? true : false) -#define _LV_COORD_GET_PCT(x) LV_COORD_GET_SPEC(x) -#define LV_SIZE_AUTO _LV_COORD_SPEC(1001) -#define LV_SIZE_STRETCH _LV_COORD_SPEC(1002) +#define LV_COORD_PCT(x) _LV_COORD_SPEC(x) +#define LV_COORD_IS_PCT(x) ((LV_COORD_IS_SPEC(x) && _LV_COORD_PLAIN(x) <= 1000) ? true : false) +#define LV_COORD_GET_PCT(x) _LV_COORD_PLAIN(x) +#define LV_SIZE_AUTO LV_COORD_SET_SPEC(1001) +#define LV_SIZE_LAYOUT LV_COORD_SET_SPEC(1002) /*The size is managed by the layout therefore `lv_obj_set_width/height/size()` can't change is*/ #ifdef __cplusplus } /* extern "C" */ diff --git a/src/lv_misc/lv_class.h b/src/lv_misc/lv_class.h index c38b12345b..ec7c0cd6c8 100644 --- a/src/lv_misc/lv_class.h +++ b/src/lv_misc/lv_class.h @@ -5,7 +5,7 @@ * It's important because the virtual functions should be called from the level of the constructor. */ #define LV_CLASS_CONSTRUCTOR_BEGIN(inst, classname) \ - void * _original_class_p = inst->class_p; \ + const void * _original_class_p = inst->class_p; \ obj->class_p = (void*)&classname; /** diff --git a/src/lv_themes/lv_theme.c b/src/lv_themes/lv_theme.c index ca847b5022..e02d01b938 100644 --- a/src/lv_themes/lv_theme.c +++ b/src/lv_themes/lv_theme.c @@ -60,10 +60,12 @@ lv_theme_t * lv_theme_get_act(void) */ void lv_theme_apply(lv_obj_t * obj) { - lv_obj_remove_all_styles(obj); + lv_obj_remove_all_styles_no_refresh(obj); /*Apply the theme including the base theme(s)*/ apply_theme(act_theme, obj); + + _lv_obj_refresh_style(obj, LV_STYLE_PROP_ALL); } /** diff --git a/src/lv_themes/lv_theme_default.c b/src/lv_themes/lv_theme_default.c index 7e85025968..8324fb5254 100644 --- a/src/lv_themes/lv_theme_default.c +++ b/src/lv_themes/lv_theme_default.c @@ -595,106 +595,106 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj) LV_UNUSED(th); if(lv_obj_get_parent(obj) == NULL) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->scr); - lv_obj_add_style(obj, LV_PART_SCROLLBAR, LV_STATE_DEFAULT, &styles->scrollbar); - lv_obj_add_style(obj, LV_PART_SCROLLBAR, LV_STATE_SCROLLED, &styles->scrollbar_scrolled); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->scr); + lv_obj_add_style_no_refresh(obj, LV_PART_SCROLLBAR, LV_STATE_DEFAULT, &styles->scrollbar); + lv_obj_add_style_no_refresh(obj, LV_PART_SCROLLBAR, LV_STATE_SCROLLED, &styles->scrollbar_scrolled); return; } if(lv_obj_check_type(obj, &lv_obj)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); - lv_obj_add_style(obj, LV_PART_SCROLLBAR, LV_STATE_DEFAULT, &styles->scrollbar); - lv_obj_add_style(obj, LV_PART_SCROLLBAR, LV_STATE_SCROLLED, &styles->scrollbar_scrolled); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); + lv_obj_add_style_no_refresh(obj, LV_PART_SCROLLBAR, LV_STATE_DEFAULT, &styles->scrollbar); + lv_obj_add_style_no_refresh(obj, LV_PART_SCROLLBAR, LV_STATE_SCROLLED, &styles->scrollbar_scrolled); } #if LV_USE_BTN else if(lv_obj_check_type(obj, &lv_btn)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->btn); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->btn_color); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->transition_delayed); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_PRESSED, &styles->pressed); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_PRESSED, &styles->transition_normal); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_PRESSED, &styles->grow); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_CHECKED, &styles->btn_color_checked); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->btn); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->btn_color); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->transition_delayed); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_PRESSED, &styles->pressed); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_PRESSED, &styles->transition_normal); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_PRESSED, &styles->grow); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_CHECKED, &styles->btn_color_checked); } #endif #if LV_USE_BAR else if(lv_obj_check_type(obj, &lv_bar)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->bg_color_gray); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->circle); - lv_obj_add_style(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->bg_color_primary); - lv_obj_add_style(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->circle); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->bg_color_gray); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->circle); + lv_obj_add_style_no_refresh(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->bg_color_primary); + lv_obj_add_style_no_refresh(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->circle); } #endif #if LV_USE_SLIDER else if(lv_obj_check_type(obj, &lv_slider)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->bg_color_gray); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->circle); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->transition_delayed); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_PRESSED, &styles->transition_normal); - lv_obj_add_style(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->bg_color_primary); - lv_obj_add_style(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->circle); - lv_obj_add_style(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->knob); - lv_obj_add_style(obj, LV_PART_KNOB, LV_STATE_PRESSED, &styles->grow); - lv_obj_add_style(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->transition_delayed); - lv_obj_add_style(obj, LV_PART_KNOB, LV_STATE_PRESSED, &styles->transition_normal); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->bg_color_gray); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->circle); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->transition_delayed); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_PRESSED, &styles->transition_normal); + lv_obj_add_style_no_refresh(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->bg_color_primary); + lv_obj_add_style_no_refresh(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->circle); + lv_obj_add_style_no_refresh(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->knob); + lv_obj_add_style_no_refresh(obj, LV_PART_KNOB, LV_STATE_PRESSED, &styles->grow); + lv_obj_add_style_no_refresh(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->transition_delayed); + lv_obj_add_style_no_refresh(obj, LV_PART_KNOB, LV_STATE_PRESSED, &styles->transition_normal); } #endif #if LV_USE_CHECKBOX else if(lv_obj_check_type(obj, &lv_checkbox)) { - lv_obj_add_style(obj, LV_PART_MARKER, LV_STATE_DEFAULT, &styles->cb_marker); - lv_obj_add_style(obj, LV_PART_MARKER, LV_STATE_CHECKED, &styles->bg_color_primary); - lv_obj_add_style(obj, LV_PART_MARKER, LV_STATE_CHECKED, &styles->cb_marker_checked); - lv_obj_add_style(obj, LV_PART_MARKER, LV_STATE_PRESSED, &styles->pressed); - lv_obj_add_style(obj, LV_PART_MARKER, LV_STATE_PRESSED, &styles->grow); - lv_obj_add_style(obj, LV_PART_MARKER, LV_STATE_PRESSED, &styles->transition_normal); - lv_obj_add_style(obj, LV_PART_MARKER, LV_STATE_DEFAULT, &styles->transition_delayed); + lv_obj_add_style_no_refresh(obj, LV_PART_MARKER, LV_STATE_DEFAULT, &styles->cb_marker); + lv_obj_add_style_no_refresh(obj, LV_PART_MARKER, LV_STATE_CHECKED, &styles->bg_color_primary); + lv_obj_add_style_no_refresh(obj, LV_PART_MARKER, LV_STATE_CHECKED, &styles->cb_marker_checked); + lv_obj_add_style_no_refresh(obj, LV_PART_MARKER, LV_STATE_PRESSED, &styles->pressed); + lv_obj_add_style_no_refresh(obj, LV_PART_MARKER, LV_STATE_PRESSED, &styles->grow); + lv_obj_add_style_no_refresh(obj, LV_PART_MARKER, LV_STATE_PRESSED, &styles->transition_normal); + lv_obj_add_style_no_refresh(obj, LV_PART_MARKER, LV_STATE_DEFAULT, &styles->transition_delayed); } #endif #if LV_USE_SWITCH else if(lv_obj_check_type(obj, &lv_switch)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->bg_color_gray); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->circle); - lv_obj_add_style(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->bg_color_primary); - lv_obj_add_style(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->circle); - lv_obj_add_style(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->knob); - lv_obj_add_style(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->bg_color_white); - lv_obj_add_style(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->pad_small_negative); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->bg_color_gray); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->circle); + lv_obj_add_style_no_refresh(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->bg_color_primary); + lv_obj_add_style_no_refresh(obj, LV_PART_INDICATOR, LV_STATE_DEFAULT, &styles->circle); + lv_obj_add_style_no_refresh(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->knob); + lv_obj_add_style_no_refresh(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->bg_color_white); + lv_obj_add_style_no_refresh(obj, LV_PART_KNOB, LV_STATE_DEFAULT, &styles->pad_small_negative); } #endif #if LV_USE_SWITCH else if(lv_obj_check_type(obj, &lv_chart)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->chart_bg); - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->pad_zero); - lv_obj_add_style(obj, LV_PART_SCROLLBAR, LV_STATE_DEFAULT, &styles->scrollbar); - lv_obj_add_style(obj, LV_PART_SCROLLBAR, LV_STATE_SCROLLED, &styles->scrollbar_scrolled); - lv_obj_add_style(obj, LV_PART_SERIES, LV_STATE_DEFAULT, &styles->chart_series); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->chart_bg); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->pad_zero); + lv_obj_add_style_no_refresh(obj, LV_PART_SCROLLBAR, LV_STATE_DEFAULT, &styles->scrollbar); + lv_obj_add_style_no_refresh(obj, LV_PART_SCROLLBAR, LV_STATE_SCROLLED, &styles->scrollbar_scrolled); + lv_obj_add_style_no_refresh(obj, LV_PART_SERIES, LV_STATE_DEFAULT, &styles->chart_series); } #endif #if LV_USE_ROLLER else if(lv_obj_check_type(obj, &lv_roller)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); -// lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->pad_zero); - lv_obj_add_style(obj, LV_PART_HIGHLIGHT, LV_STATE_DEFAULT, &styles->bg_color_primary); -// lv_obj_add_style(obj, LV_PART_SCROLLBAR, LV_STATE_DEFAULT, &styles->scrollbar); -// lv_obj_add_style(obj, LV_PART_SCROLLBAR, LV_STATE_SCROLLED, &styles->scrollbar_scrolled); -// lv_obj_add_style(obj, LV_PART_SERIES, LV_STATE_DEFAULT, &styles->chart_series); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); +// lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->pad_zero); + lv_obj_add_style_no_refresh(obj, LV_PART_HIGHLIGHT, LV_STATE_DEFAULT, &styles->bg_color_primary); +// lv_obj_add_style_no_refresh(obj, LV_PART_SCROLLBAR, LV_STATE_DEFAULT, &styles->scrollbar); +// lv_obj_add_style_no_refresh(obj, LV_PART_SCROLLBAR, LV_STATE_SCROLLED, &styles->scrollbar_scrolled); +// lv_obj_add_style_no_refresh(obj, LV_PART_SERIES, LV_STATE_DEFAULT, &styles->chart_series); } #endif #if LV_USE_DROPDOWN else if(lv_obj_check_type(obj, &lv_dropdown)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); } else if(lv_obj_check_type(obj, &lv_dropdown_list)) { - lv_obj_add_style(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); - lv_obj_add_style(obj, LV_PART_HIGHLIGHT, LV_STATE_DEFAULT, &styles->bg_color_primary); - lv_obj_add_style(obj, LV_PART_HIGHLIGHT, LV_STATE_PRESSED, &styles->bg_color_gray); + lv_obj_add_style_no_refresh(obj, LV_PART_MAIN, LV_STATE_DEFAULT, &styles->card); + lv_obj_add_style_no_refresh(obj, LV_PART_HIGHLIGHT, LV_STATE_DEFAULT, &styles->bg_color_primary); + lv_obj_add_style_no_refresh(obj, LV_PART_HIGHLIGHT, LV_STATE_PRESSED, &styles->bg_color_gray); } #endif