diff --git a/examples/scroll/lv_example_scroll_3.c b/examples/scroll/lv_example_scroll_3.c index 245c809e0..c0869507d 100644 --- a/examples/scroll/lv_example_scroll_3.c +++ b/examples/scroll/lv_example_scroll_3.c @@ -11,8 +11,13 @@ static void float_btn_event_cb(lv_obj_t * float_btn, lv_event_t e) lv_snprintf(buf, sizeof(buf), "Track %d", btn_cnt); lv_obj_t * list_btn = lv_list_add_btn(list, LV_SYMBOL_AUDIO, buf, NULL); btn_cnt++; - lv_obj_scroll_to_view(list_btn, LV_ANIM_ON); + lv_obj_move_foreground(float_btn); + + /* Layouts are only recalculated later but we need to know the updated position of the new button + * to scroll to it. */ + lv_obj_update_layout(list); + lv_obj_scroll_to_view(list_btn, LV_ANIM_ON); } } diff --git a/src/extra/layouts/flex/lv_flex.c b/src/extra/layouts/flex/lv_flex.c index ec29bc395..826cf82ce 100644 --- a/src/extra/layouts/flex/lv_flex.c +++ b/src/extra/layouts/flex/lv_flex.c @@ -32,7 +32,7 @@ typedef struct { /********************** * STATIC PROTOTYPES **********************/ -static void flex_update(lv_obj_t * cont, lv_obj_t * item); +static void flex_update(lv_obj_t * cont); static int32_t find_track_end(lv_obj_t * cont, int32_t item_start_id, lv_coord_t item_gap, 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, lv_coord_t item_gap, 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); @@ -145,17 +145,15 @@ void lv_obj_set_flex_grow(struct _lv_obj_t * obj, uint8_t grow) if(f->dir == LV_FLEX_FLOW_ROW) lv_obj_set_width(obj, (LV_COORD_SET_LAYOUT(grow))); else lv_obj_set_height(obj, (LV_COORD_SET_LAYOUT(grow))); - lv_obj_update_layout(parent, obj); + lv_obj_mark_layout_as_dirty(parent); } /********************** * STATIC FUNCTIONS **********************/ -static void flex_update(lv_obj_t * cont, lv_obj_t * item) +static void flex_update(lv_obj_t * cont) { - LV_UNUSED(item); - if(cont->spec_attr == NULL) return; const lv_flex_t * f = (const lv_flex_t *)cont->spec_attr->layout_dsc; diff --git a/src/extra/layouts/grid/lv_grid.c b/src/extra/layouts/grid/lv_grid.c index d915578fe..731cf721f 100644 --- a/src/extra/layouts/grid/lv_grid.c +++ b/src/extra/layouts/grid/lv_grid.c @@ -43,9 +43,8 @@ void lv_obj_move_to(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, bool notify_pare /********************** * STATIC PROTOTYPES **********************/ -static void grid_update(lv_obj_t * cont, lv_obj_t * item); +static void grid_update(lv_obj_t * cont); 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); @@ -109,7 +108,7 @@ void lv_obj_set_grid_cell(lv_obj_t * obj, lv_grid_place_t hor_place, uint8_t col obj->x_set = LV_COORD_SET_LAYOUT(col_pos | (col_span << CELL_SHIFT) | (hor_place << (CELL_SHIFT * 2))); obj->y_set = LV_COORD_SET_LAYOUT(row_pos | (row_span << CELL_SHIFT) | (ver_place << (CELL_SHIFT * 2))); - lv_obj_update_layout(parent, obj); + lv_obj_mark_layout_as_dirty(parent); } @@ -118,15 +117,14 @@ void lv_obj_set_grid_cell(lv_obj_t * obj, lv_grid_place_t hor_place, uint8_t col * STATIC FUNCTIONS **********************/ -static void grid_update(lv_obj_t * cont, lv_obj_t * item) +static void grid_update(lv_obj_t * cont) { if(cont->spec_attr == NULL) return; if(cont->spec_attr->layout_dsc == NULL) return; LV_LOG_INFO("update 0x%p container, triggered by 0x%p", cont, item); - if(item) item_refr(item); - else full_refresh(cont); + full_refresh(cont); LV_TRACE_LAYOUT("finished"); } @@ -168,27 +166,6 @@ static void full_refresh(lv_obj_t * cont) } } -/** - * 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); - - if(cont->w_set == LV_SIZE_CONTENT || cont->h_set == LV_SIZE_CONTENT) { - lv_obj_set_size(cont, cont->w_set, cont->h_set); - } -} - /** * Calculate the grid cells coordinates * @param cont an object that has a grid diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index 6399e47ab..fdfcbb8f0 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -336,7 +336,7 @@ void lv_obj_add_flag(lv_obj_t * obj, lv_obj_flag_t f) } if((was_on_layout != lv_obj_is_layout_positioned(obj)) || (f & (LV_OBJ_FLAG_LAYOUT_1 | LV_OBJ_FLAG_LAYOUT_2))) { - lv_obj_update_layout(lv_obj_get_parent(obj), obj); + lv_obj_mark_layout_as_dirty(lv_obj_get_parent(obj)); } } @@ -351,12 +351,12 @@ void lv_obj_clear_flag(lv_obj_t * obj, lv_obj_flag_t f) if(f & LV_OBJ_FLAG_HIDDEN) { lv_obj_invalidate(obj); if(lv_obj_is_layout_positioned(obj)) { - lv_obj_update_layout(lv_obj_get_parent(obj), obj); + lv_obj_mark_layout_as_dirty(lv_obj_get_parent(obj)); } } if((was_on_layout != lv_obj_is_layout_positioned(obj)) || (f & (LV_OBJ_FLAG_LAYOUT_1 | LV_OBJ_FLAG_LAYOUT_2))) { - lv_obj_update_layout(lv_obj_get_parent(obj), obj); + lv_obj_mark_layout_as_dirty(lv_obj_get_parent(obj)); } } @@ -933,7 +933,7 @@ 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); } } - lv_obj_update_layout(obj, NULL); + lv_obj_mark_layout_as_dirty(obj); } @@ -966,7 +966,7 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) } } else if(sign == LV_SIGNAL_CHILD_CHG) { - lv_obj_update_layout(obj, param); + lv_obj_mark_layout_as_dirty(obj); if(obj->w_set == LV_SIZE_CONTENT || obj->h_set == LV_SIZE_CONTENT) { lv_obj_set_size(obj, obj->w_set, obj->h_set); @@ -975,7 +975,7 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) else if(sign == LV_SIGNAL_BASE_DIR_CHG) { /* The layout might depend on the base dir. * E.g. the first is element is on the left or right*/ - lv_obj_update_layout(obj, NULL); + lv_obj_mark_layout_as_dirty(obj); } else if(sign == LV_SIGNAL_SCROLL) { res = lv_event_send(obj, LV_EVENT_SCROLL, NULL); @@ -993,7 +993,7 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) } else if(sign == LV_SIGNAL_STYLE_CHG) { /* Padding might have changed so the layout should be recalculated*/ - lv_obj_update_layout(obj, NULL); + lv_obj_mark_layout_as_dirty(obj); /*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 b572719c1..b954fa681 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -268,6 +268,7 @@ typedef struct _lv_obj_t{ lv_coord_t h_set; lv_obj_flag_t flags; lv_state_t state; + uint8_t layout_inv:1; }lv_obj_t; diff --git a/src/lv_core/lv_obj_pos.c b/src/lv_core/lv_obj_pos.c index 3a5ddd992..23a2264be 100644 --- a/src/lv_core/lv_obj_pos.c +++ b/src/lv_core/lv_obj_pos.c @@ -24,6 +24,7 @@ **********************/ static bool refr_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h); static void calc_auto_size(lv_obj_t * obj, lv_coord_t * w_out, lv_coord_t * h_out); +static void layout_update_core(lv_obj_t * obj); void lv_obj_move_to(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, bool notify); @@ -148,7 +149,7 @@ void lv_obj_set_layout(lv_obj_t * obj, const void * layout) lv_obj_allocate_spec_attr(obj); obj->spec_attr->layout_dsc = layout; - lv_obj_update_layout(obj, NULL); + lv_obj_mark_layout_as_dirty(obj); } bool lv_obj_is_layout_positioned(const lv_obj_t * obj) @@ -161,15 +162,35 @@ bool lv_obj_is_layout_positioned(const lv_obj_t * obj) else return false; } -void lv_obj_update_layout(lv_obj_t * obj, lv_obj_t * item) +void lv_obj_mark_layout_as_dirty(lv_obj_t * obj) { - if(obj->spec_attr == NULL) return; - if(obj->spec_attr->layout_dsc == NULL) return; - if(obj->spec_attr->child_cnt == 0) return; + obj->layout_inv = 1; + + /*Mark the screen as dirty too to mark that there is an something to do on this screen*/ + lv_obj_t * scr = lv_obj_get_screen(obj); + scr->layout_inv = 1; + + /*Make the display refreshing*/ + lv_disp_t * disp = lv_obj_get_disp(scr); + lv_timer_pause(disp->refr_timer, false); +} + +void lv_obj_update_layout(lv_obj_t * obj) +{ + lv_obj_t * scr = lv_obj_get_screen(obj); + + /*There are no dirty layouts on this screen*/ + if(scr->layout_inv == 0) return; + + do { + scr->layout_inv = 0; + layout_update_core(obj); + }while(scr->layout_inv); /*Repeat until there where layout invalidations*/ + + /* Restore the global state because other calls of this function needs this info too. + * Other calls might use different start object, but they need to know if there is dirty layout somewhere.*/ + scr->layout_inv = 1; - const lv_layout_dsc_t * layout = obj->spec_attr->layout_dsc; - if(layout->update_cb == NULL) return; - layout->update_cb(obj, item); } void lv_obj_align(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs) @@ -696,3 +717,21 @@ static void calc_auto_size(lv_obj_t * obj, lv_coord_t * w_out, lv_coord_t * h_ou *h_out = lv_obj_get_height(obj) + scroll_bottom + scroll_top; } } + +static void layout_update_core(lv_obj_t * obj) +{ + uint32_t i; + for(i = 0; i < lv_obj_get_child_cnt(obj); i++) { + lv_obj_t * child = lv_obj_get_child(obj, i); + layout_update_core(child); + } + + if(!obj->layout_inv) return; + + const lv_layout_dsc_t * layout = obj->spec_attr ? obj->spec_attr->layout_dsc : NULL; + const lv_layout_update_cb_t update_cp = layout ? layout->update_cb : NULL; + if(update_cp != NULL && lv_obj_get_child_cnt(obj) > 0) { + obj->layout_inv = 0; + update_cp(obj); + } +} diff --git a/src/lv_core/lv_obj_pos.h b/src/lv_core/lv_obj_pos.h index e16c381a4..999007919 100644 --- a/src/lv_core/lv_obj_pos.h +++ b/src/lv_core/lv_obj_pos.h @@ -24,7 +24,7 @@ extern "C" { **********************/ struct _lv_obj_t; -typedef void (*lv_layout_update_cb_t)(struct _lv_obj_t * cont, struct _lv_obj_t * item); +typedef void (*lv_layout_update_cb_t)(struct _lv_obj_t * cont); /** * The base of all layouts descriptor. @@ -126,14 +126,17 @@ void lv_obj_set_layout(struct _lv_obj_t * obj, const void * layout); */ bool lv_obj_is_layout_positioned(const struct _lv_obj_t * obj); +/** + * Mark the object for layout update. + * @param obj pointer to an object whose children needs to be updated + */ +void lv_obj_mark_layout_as_dirty(struct _lv_obj_t * obj); + /** * Update the layout of an object. * @param obj pointer to an object whose children needs to be updated - * @param item pointer to a child object that triggered the update. Set to `NULL` is not known. - * If not `NULL` the update process can make some optimization - * to update only the required parts of the layout */ -void lv_obj_update_layout(struct _lv_obj_t * obj, struct _lv_obj_t * item); +void lv_obj_update_layout(struct _lv_obj_t * obj); /** diff --git a/src/lv_core/lv_refr.c b/src/lv_core/lv_refr.c index f0707f35d..5fbafe688 100644 --- a/src/lv_core/lv_refr.c +++ b/src/lv_core/lv_refr.c @@ -199,10 +199,25 @@ void _lv_disp_refr_timer(lv_timer_t * tmr) lv_timer_pause(tmr, true); #endif + /*Refresh the screen's layout if required*/ + uint32_t i; + for(i = 0; i < disp_refr->screen_cnt; i++) { + lv_obj_update_layout(disp_refr->screens[i]); + disp_refr->screens[i]->layout_inv = 0; + } + + lv_obj_update_layout(disp_refr->top_layer); + disp_refr->top_layer->layout_inv = 0; + + lv_obj_update_layout(disp_refr->sys_layer); + disp_refr->sys_layer->layout_inv = 0; + + /*Do nothing if there is no active screen*/ if(disp_refr->act_scr == NULL) { disp_refr->inv_p = 0; - TRACE_REFR("finished (there were no invalid areas to redraw)"); + LV_LOG_WARN("there is no active screen"); + TRACE_REFR("finished"); return; } diff --git a/src/lv_hal/lv_hal_disp.h b/src/lv_hal/lv_hal_disp.h index 66b226f6f..027b2f40e 100644 --- a/src/lv_hal/lv_hal_disp.h +++ b/src/lv_hal/lv_hal_disp.h @@ -175,7 +175,7 @@ typedef struct _lv_disp_t { uint32_t inv_p : 10; /*Miscellaneous data*/ - uint32_t last_activity_time; /**< Last time there was activity on this display */ + uint32_t last_activity_time; /**< Last time when there was activity on this display */ } lv_disp_t; typedef enum {