diff --git a/src/core/lv_obj_pos.c b/src/core/lv_obj_pos.c index a88ace3979..de99ee9dfc 100644 --- a/src/core/lv_obj_pos.c +++ b/src/core/lv_obj_pos.c @@ -35,7 +35,7 @@ static int32_t calc_content_height(lv_obj_t * obj); static void layout_update_core(lv_obj_t * obj); static void transform_point_array(const lv_obj_t * obj, lv_point_t * p, size_t p_count, bool inv); static bool is_transformed(const lv_obj_t * obj); - +static lv_obj_tree_walk_res_t update_layout_completed_cb(lv_obj_t * obj, void * user_data); /********************** * STATIC VARIABLES **********************/ @@ -304,6 +304,12 @@ void lv_obj_mark_layout_as_dirty(lv_obj_t * obj) lv_display_send_event(disp, LV_EVENT_REFR_REQUEST, NULL); } +void lv_obj_request_layout_complete_event(lv_obj_t * obj) +{ + lv_obj_t * scr = lv_obj_get_screen(obj); + scr->scr_layout_complete_pending = 1; +} + void lv_obj_update_layout(const lv_obj_t * obj) { if(update_layout_mutex) { @@ -322,6 +328,11 @@ void lv_obj_update_layout(const lv_obj_t * obj) LV_LOG_TRACE("Layout update end"); } + if(scr->scr_layout_complete_pending) { + scr->scr_layout_complete_pending = 0; + lv_obj_tree_walk(scr, update_layout_completed_cb, NULL); + } + update_layout_mutex = false; LV_PROFILER_LAYOUT_END; } @@ -1316,3 +1327,10 @@ static void transform_point_array(const lv_obj_t * obj, lv_point_t * p, size_t p lv_point_array_transform(p, p_count, angle, scale_x, scale_y, &pivot, !inv); } + +static lv_obj_tree_walk_res_t update_layout_completed_cb(lv_obj_t * obj, void * user_data) +{ + LV_UNUSED(user_data); + lv_obj_send_event(obj, LV_EVENT_UPDATE_LAYOUT_COMPLETED, NULL); + return LV_OBJ_TREE_WALK_NEXT; +} \ No newline at end of file diff --git a/src/core/lv_obj_pos.h b/src/core/lv_obj_pos.h index eab91b2a22..b3bedca933 100644 --- a/src/core/lv_obj_pos.h +++ b/src/core/lv_obj_pos.h @@ -153,6 +153,12 @@ bool lv_obj_is_layout_positioned(const lv_obj_t * obj); */ void lv_obj_mark_layout_as_dirty(lv_obj_t * obj); +/** + * Mark screen to send layout completed event after update. + * @param obj Any object on the target screen + */ +void lv_obj_request_layout_complete_event(lv_obj_t * obj); + /** * Update the layout of an object. * @param obj pointer to an object whose position and size needs to be updated diff --git a/src/core/lv_obj_private.h b/src/core/lv_obj_private.h index 1a6540bf28..76a6a542bb 100644 --- a/src/core/lv_obj_private.h +++ b/src/core/lv_obj_private.h @@ -71,6 +71,7 @@ struct _lv_obj_t { uint16_t layout_inv : 1; uint16_t readjust_scroll_after_layout : 1; uint16_t scr_layout_inv : 1; + uint16_t scr_layout_complete_pending : 1; uint16_t skip_trans : 1; uint16_t style_cnt : 6; uint16_t h_layout : 1; diff --git a/src/misc/lv_event.c b/src/misc/lv_event.c index 70e092ab7a..761218a8e3 100644 --- a/src/misc/lv_event.c +++ b/src/misc/lv_event.c @@ -353,6 +353,7 @@ const char * lv_event_code_get_name(lv_event_code_t code) ENUM_CASE(EVENT_STYLE_CHANGED); ENUM_CASE(EVENT_LAYOUT_CHANGED); ENUM_CASE(EVENT_GET_SELF_SIZE); + ENUM_CASE(EVENT_UPDATE_LAYOUT_COMPLETED); /** Events of optional LVGL components*/ ENUM_CASE(EVENT_INVALIDATE_AREA); diff --git a/src/misc/lv_event.h b/src/misc/lv_event.h index 202dc84a92..8709443265 100644 --- a/src/misc/lv_event.h +++ b/src/misc/lv_event.h @@ -93,6 +93,7 @@ typedef enum { LV_EVENT_STYLE_CHANGED, /**< Object's style has changed */ LV_EVENT_LAYOUT_CHANGED, /**< A child's position position has changed due to a layout recalculation */ LV_EVENT_GET_SELF_SIZE, /**< Get internal size of a widget */ + LV_EVENT_UPDATE_LAYOUT_COMPLETED, /**< Sent after layout update completes*/ /** Events of optional LVGL components */ LV_EVENT_INVALIDATE_AREA, /**< An area is invalidated (marked for redraw). `lv_event_get_param(e)` diff --git a/src/widgets/label/lv_label.c b/src/widgets/label/lv_label.c index dd83228000..bcb2670967 100644 --- a/src/widgets/label/lv_label.c +++ b/src/widgets/label/lv_label.c @@ -62,7 +62,7 @@ static void copy_text_to_label(lv_label_t * label, const char * text); static lv_text_flag_t get_label_flags(lv_label_t * label); static void calculate_x_coordinate(int32_t * x, const lv_text_align_t align, const char * txt, uint32_t length, const lv_font_t * font, lv_area_t * txt_coords, lv_text_attributes_t * attributes); - +static void lv_label_mark_need_refr_text(lv_obj_t * obj); #if LV_USE_OBSERVER static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject); #endif @@ -166,7 +166,7 @@ void lv_label_set_text_vfmt(lv_obj_t * obj, const char * fmt, va_list args) /*If text is NULL then refresh*/ if(fmt == NULL) { - lv_label_refr_text(obj); + lv_label_mark_need_refr_text(obj); return; } @@ -178,7 +178,7 @@ void lv_label_set_text_vfmt(lv_obj_t * obj, const char * fmt, va_list args) label->text = lv_text_set_text_vfmt(fmt, args); label->static_txt = 0; /*Now the text is dynamically allocated*/ - lv_label_refr_text(obj); + lv_label_mark_need_refr_text(obj); } void lv_label_set_text_static(lv_obj_t * obj, const char * text) @@ -197,7 +197,7 @@ void lv_label_set_text_static(lv_obj_t * obj, const char * text) label->text = (char *)text; } - lv_label_refr_text(obj); + lv_label_mark_need_refr_text(obj); } #if LV_USE_TRANSLATION @@ -240,7 +240,7 @@ void lv_label_set_long_mode(lv_obj_t * obj, lv_label_long_mode_t long_mode) label->expand = 0; label->long_mode = long_mode; - lv_label_refr_text(obj); + lv_label_mark_need_refr_text(obj); } void lv_label_set_text_selection_start(lv_obj_t * obj, uint32_t index) @@ -281,7 +281,7 @@ void lv_label_set_recolor(lv_obj_t * obj, bool en) label->recolor = en == false ? 0 : 1; /*Refresh the text because the potential color codes in text needs to be hidden or revealed*/ - lv_label_refr_text(obj); + lv_label_mark_need_refr_text(obj); } /*===================== @@ -740,7 +740,7 @@ void lv_label_cut_text(lv_obj_t * obj, uint32_t pos, uint32_t cnt) lv_text_cut(label_txt, pos, cnt); /*Refresh the label*/ - lv_label_refr_text(obj); + lv_label_mark_need_refr_text(obj); } @@ -806,7 +806,7 @@ static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e) lv_obj_t * obj = lv_event_get_current_target(e); if((code == LV_EVENT_STYLE_CHANGED) || (code == LV_EVENT_SIZE_CHANGED)) { - lv_label_refr_text(obj); + lv_label_mark_need_refr_text(obj); } else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) { /* Italic or other non-typical letters can be drawn of out of the object. @@ -859,6 +859,9 @@ static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e) draw_main(e); } + else if(code == LV_EVENT_UPDATE_LAYOUT_COMPLETED) { + lv_label_refr_text(obj); + } #if LV_USE_TRANSLATION else if(code == LV_EVENT_TRANSLATION_LANGUAGE_CHANGED) { lv_label_t * label = (lv_label_t *)obj; @@ -1022,7 +1025,7 @@ static void set_text_internal(lv_obj_t * obj, const char * text) label->static_txt = 0; } - lv_label_refr_text(obj); + lv_label_mark_need_refr_text(obj); } static void remove_translation_tag(lv_obj_t * obj) @@ -1062,6 +1065,18 @@ static void overwrite_anim_property(lv_anim_t * dest, const lv_anim_t * src, lv_ } } +static void lv_label_mark_need_refr_text(lv_obj_t * obj) +{ + lv_label_t * label = (lv_label_t *)obj; + if(label->text == NULL) return; + label->invalid_size_cache = true; + label->need_refr_text = true; + + lv_obj_refresh_self_size(obj); + + lv_obj_request_layout_complete_event(obj); +} + /** * Refresh the label with its text stored in its extended data * @param label pointer to a label object @@ -1070,10 +1085,11 @@ static void lv_label_refr_text(lv_obj_t * obj) { lv_label_t * label = (lv_label_t *)obj; if(label->text == NULL) return; + if(!label->need_refr_text) return; + label->need_refr_text = false; #if LV_LABEL_LONG_TXT_HINT label->hint.line_start = -1; /*The hint is invalid if the text changes*/ #endif - label->invalid_size_cache = true; lv_area_t txt_coords; lv_text_attributes_t attributes = {0}; @@ -1091,8 +1107,6 @@ static void lv_label_refr_text(lv_obj_t * obj) lv_text_get_size_attributes(&size, label->text, font, &attributes); label->text_size = size; - lv_obj_refresh_self_size(obj); - /*In scroll mode start an offset animation*/ if(label->long_mode == LV_LABEL_LONG_MODE_SCROLL) { const lv_anim_t * anim_template = lv_obj_get_style_anim(obj, LV_PART_MAIN); diff --git a/src/widgets/label/lv_label_private.h b/src/widgets/label/lv_label_private.h index 063e8314b6..8681a22dba 100644 --- a/src/widgets/label/lv_label_private.h +++ b/src/widgets/label/lv_label_private.h @@ -53,6 +53,7 @@ struct _lv_label_t { uint8_t recolor : 1; /**< Enable in-line letter re-coloring*/ uint8_t expand : 1; /**< Ignore real width (used by the library with LV_LABEL_LONG_MODE_SCROLL) */ uint8_t invalid_size_cache : 1; /**< 1: Recalculate size and update cache */ + uint8_t need_refr_text : 1; /**< 1: Refresh text after layout update completion */ lv_point_t text_size; }; diff --git a/tests/ref_imgs/widgets/label_scroll_12.png b/tests/ref_imgs/widgets/label_scroll_12.png index 97d76a7103..e344d1a13a 100644 Binary files a/tests/ref_imgs/widgets/label_scroll_12.png and b/tests/ref_imgs/widgets/label_scroll_12.png differ diff --git a/tests/ref_imgs/widgets/label_scroll_15.png b/tests/ref_imgs/widgets/label_scroll_15.png index 118797221f..799118e802 100644 Binary files a/tests/ref_imgs/widgets/label_scroll_15.png and b/tests/ref_imgs/widgets/label_scroll_15.png differ diff --git a/tests/ref_imgs_vg_lite/widgets/label_scroll_12.png b/tests/ref_imgs_vg_lite/widgets/label_scroll_12.png index d1333592ca..a933062442 100644 Binary files a/tests/ref_imgs_vg_lite/widgets/label_scroll_12.png and b/tests/ref_imgs_vg_lite/widgets/label_scroll_12.png differ diff --git a/tests/ref_imgs_vg_lite/widgets/label_scroll_15.png b/tests/ref_imgs_vg_lite/widgets/label_scroll_15.png index 37ae6e158e..d69b41ee15 100644 Binary files a/tests/ref_imgs_vg_lite/widgets/label_scroll_15.png and b/tests/ref_imgs_vg_lite/widgets/label_scroll_15.png differ