diff --git a/src/extra/widgets/span/lv_span.c b/src/extra/widgets/span/lv_span.c index 412cddce58..d9e4a6426c 100644 --- a/src/extra/widgets/span/lv_span.c +++ b/src/extra/widgets/span/lv_span.c @@ -40,6 +40,7 @@ static void lv_spangroup_destructor(const lv_obj_class_t * class_p, lv_obj_t * o static void lv_spangroup_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_spangroup_event(const lv_obj_class_t * class_p, lv_event_t * e); static void draw_main(lv_event_t * e); +static void refresh_self_size(lv_obj_t * obj); static const lv_font_t * lv_span_get_style_text_font(lv_obj_t * par, lv_span_t * span); static lv_coord_t lv_span_get_style_text_letter_space(lv_obj_t * par, lv_span_t * span); @@ -50,7 +51,6 @@ static lv_opa_t lv_span_get_style_text_blend_mode(lv_obj_t * par, lv_span_t * sp static int32_t lv_span_get_style_text_decor(lv_obj_t * par, lv_span_t * span); static inline void span_text_check(const char ** text); -static void get_txt_coords(const lv_obj_t * span, lv_area_t * area); static void lv_draw_span(lv_obj_t * spans, const lv_area_t * coords, const lv_area_t * mask); static bool lv_txt_get_snippet(const char * txt, const lv_font_t * font, lv_coord_t letter_space, lv_coord_t max_width, lv_text_flag_t flag, lv_coord_t * use_width, @@ -72,6 +72,8 @@ const lv_obj_class_t lv_spangroup_class = { .destructor_cb = lv_spangroup_destructor, .event_cb = lv_spangroup_event, .instance_size = sizeof(lv_spangroup_t), + .width_def = LV_SIZE_CONTENT, + .height_def = LV_SIZE_CONTENT, }; /********************** @@ -112,8 +114,10 @@ lv_span_t * lv_spangroup_new_span(lv_obj_t * obj) lv_style_init(&span->style); span->txt = (char *)""; span->static_flag = 1; + span->spangroup = obj; + + refresh_self_size(obj); - lv_obj_invalidate(obj); return span; } @@ -124,7 +128,7 @@ lv_span_t * lv_spangroup_new_span(lv_obj_t * obj) */ void lv_spangroup_del_span(lv_obj_t * obj, lv_span_t * span) { - if(obj == NULL) { + if(obj == NULL || span == NULL) { return; } @@ -142,7 +146,7 @@ void lv_spangroup_del_span(lv_obj_t * obj, lv_span_t * span) } } - lv_spangroup_refr_mode(obj); + refresh_self_size(obj); } /*===================== @@ -168,6 +172,8 @@ void lv_span_set_text(lv_span_t * span, const char * text) } span->static_flag = 0; strcpy(span->txt, text); + + refresh_self_size(span->spangroup); } /** @@ -187,6 +193,8 @@ void lv_span_set_text_static(lv_span_t * span, const char * text) } span->static_flag = 1; span->txt = (char *)text; + + refresh_self_size(span->spangroup); } /** @@ -196,11 +204,7 @@ void lv_span_set_text_static(lv_span_t * span, const char * text) */ void lv_spangroup_set_align(lv_obj_t * obj, lv_text_align_t align) { - lv_spangroup_t * spans = (lv_spangroup_t *)obj; - if(spans->align == align) return; - - spans->align = align; - lv_obj_invalidate(obj); + lv_obj_set_style_text_align(obj, align, LV_PART_MAIN); } /** @@ -228,7 +232,8 @@ void lv_spangroup_set_indent(lv_obj_t * obj, lv_coord_t indent) if(spans->indent == indent) return; spans->indent = indent; - lv_obj_invalidate(obj); + + refresh_self_size(obj); } /** @@ -256,8 +261,7 @@ void lv_spangroup_set_mode(lv_obj_t * obj, lv_span_mode_t mode) */ lv_text_align_t lv_spangroup_get_align(lv_obj_t * obj) { - lv_spangroup_t * spans = (lv_spangroup_t *)obj; - return spans->align; + return lv_obj_get_style_text_align(obj, LV_PART_MAIN); } /** @@ -301,24 +305,33 @@ void lv_spangroup_refr_mode(lv_obj_t * obj) { lv_spangroup_t * spans = (lv_spangroup_t *)obj; - if(_lv_ll_get_head(&spans->child_ll) == NULL) { - return; - } - if(spans->mode == LV_SPAN_MODE_EXPAND) { - lv_coord_t width = lv_spangroup_get_expand_width(obj); - lv_coord_t height = lv_spangroup_get_max_line_h(obj); - lv_coord_t top_pad = lv_obj_get_style_pad_top(obj, LV_PART_MAIN); - lv_coord_t bottom_pad = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN); - lv_obj_set_width(obj, width + spans->indent); - lv_obj_set_height(obj, height + top_pad + bottom_pad); + lv_obj_set_width(obj, LV_SIZE_CONTENT); + lv_obj_set_height(obj, LV_SIZE_CONTENT); } else if(spans->mode == LV_SPAN_MODE_BREAK) { - lv_coord_t height = lv_spangroup_get_expand_height(obj, lv_obj_get_width(obj)); - lv_obj_set_height(obj, height); + if(lv_obj_get_style_width(obj, LV_PART_MAIN) == LV_SIZE_CONTENT) { + lv_obj_set_width(obj, 100); + } + lv_obj_set_height(obj, LV_SIZE_CONTENT); + } + else if(spans->mode == LV_SPAN_MODE_FIXED) { + /* use this mode, The user needs to set the size. */ + /* This is just to prevent an infinite loop. */ + if(lv_obj_get_style_width(obj, LV_PART_MAIN) == LV_SIZE_CONTENT) { + lv_obj_set_width(obj, 100); + } + if(lv_obj_get_style_height(obj, LV_PART_MAIN) == LV_SIZE_CONTENT) { + lv_coord_t width = lv_obj_get_style_width(obj, LV_PART_MAIN); + if(LV_COORD_IS_PCT(width)) { + width = 100; + } + lv_coord_t height = lv_spangroup_get_expand_height(obj, width); + lv_obj_set_content_height(obj, height); + } } - lv_obj_invalidate(obj); + refresh_self_size(obj); } /** @@ -343,7 +356,7 @@ lv_coord_t lv_spangroup_get_max_line_h(lv_obj_t * obj) } /** - * get the width when all span of spangroup on a line. include spangroup pad. + * get the width when all span of spangroup on a line. not included spangroup pad, border width. * @param obj pointer to a spangroup object. */ lv_coord_t lv_spangroup_get_expand_width(lv_obj_t * obj) @@ -370,30 +383,24 @@ lv_coord_t lv_spangroup_get_expand_width(lv_obj_t * obj) } } - lv_coord_t left_pad = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); - lv_coord_t right_pad = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); - width = width + left_pad + right_pad; - return width; } /** - * get the height with width fixed. the height include spangroup pad. + * get the height with width fixed. Height and width are not included spangroup pad, border width. * @param obj pointer to a spangroup object. */ lv_coord_t lv_spangroup_get_expand_height(lv_obj_t * obj, lv_coord_t width) { lv_spangroup_t * spans = (lv_spangroup_t *)obj; - if(_lv_ll_get_head(&spans->child_ll) == NULL) { + if(_lv_ll_get_head(&spans->child_ll) == NULL || width <= 0) { return 0; } /* init draw variable */ lv_text_flag_t txt_flag = LV_TEXT_FLAG_NONE; lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN); - lv_coord_t left_pad = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); - lv_coord_t right_pad = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); - lv_coord_t max_width = width - left_pad - right_pad; + lv_coord_t max_width = width; lv_coord_t max_w = max_width - spans->indent; /* first line need minus indent */ /* coords of draw span-txt */ @@ -469,10 +476,6 @@ lv_coord_t lv_spangroup_get_expand_height(lv_obj_t * obj, lv_coord_t width) max_w = max_width; } - lv_coord_t top_pad = lv_obj_get_style_pad_top(obj, LV_PART_MAIN); - lv_coord_t bottom_pad = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN); - txt_pos.y = txt_pos.y + top_pad + bottom_pad - line_space; - return txt_pos.y; } @@ -486,9 +489,11 @@ static void lv_spangroup_constructor(const lv_obj_class_t * class_p, lv_obj_t * lv_spangroup_t * spans = (lv_spangroup_t *)obj; _lv_ll_init(&spans->child_ll, sizeof(lv_span_t)); spans->indent = 0; - spans->align = LV_TEXT_ALIGN_LEFT; - spans->mode = LV_SPAN_MODE_FIXED; + spans->mode = LV_SPAN_MODE_EXPAND; spans->overflow = LV_SPAN_OVERFLOW_CLIP; + spans->cache_w = 0; + spans->cache_h = 0; + spans->refresh = 1; } static void lv_spangroup_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) @@ -516,15 +521,51 @@ static void lv_spangroup_event(const lv_obj_class_t * class_p, lv_event_t * e) lv_event_code_t code = lv_event_get_code(e); lv_obj_t * obj = lv_event_get_target(e); + lv_spangroup_t * spans = (lv_spangroup_t *)obj; if(code == LV_EVENT_DRAW_MAIN) { draw_main(e); } else if(code == LV_EVENT_STYLE_CHANGED) { - lv_spangroup_refr_mode(obj); + refresh_self_size(obj); } else if(code == LV_EVENT_SIZE_CHANGED) { - lv_spangroup_refr_mode(obj); + refresh_self_size(obj); + } + else if(code == LV_EVENT_GET_SELF_SIZE) { + lv_coord_t width = 0; + lv_coord_t height = 0; + lv_point_t * self_size = lv_event_get_param(e); + + if(spans->mode == LV_SPAN_MODE_EXPAND) { + if(spans->refresh) { + spans->cache_w = lv_spangroup_get_expand_width(obj); + spans->cache_h = lv_spangroup_get_max_line_h(obj); + spans->refresh = 0; + } + width = spans->cache_w; + height = spans->cache_h; + } + else if(spans->mode == LV_SPAN_MODE_BREAK) { + width = lv_obj_get_content_width(obj); + if(self_size->y >= 0) { + if(width != spans->cache_w || spans->refresh) { + height = lv_spangroup_get_expand_height(obj, width); + spans->cache_w = width; + spans->cache_h = height; + spans->refresh = 0; + } + else { + height = spans->cache_h; + } + } + } + else if(spans->mode == LV_SPAN_MODE_FIXED) { + width = self_size->x >= 0 ? lv_obj_get_content_width(obj) : 0; + height = self_size->y >= 0 ? lv_obj_get_content_height(obj) : 0; + } + self_size->x = LV_MAX(self_size->x, width); + self_size->y = LV_MAX(self_size->y, height); } } @@ -534,29 +575,11 @@ static void draw_main(lv_event_t * e) const lv_area_t * clip_area = lv_event_get_param(e); lv_area_t txt_coords; - get_txt_coords(obj, &txt_coords); - - lv_area_t txt_clip; - bool is_common = _lv_area_intersect(&txt_clip, clip_area, &txt_coords); - if(!is_common) return; + lv_obj_get_content_coords(obj, &txt_coords); lv_draw_span(obj, &txt_coords, clip_area); } -static void get_txt_coords(const lv_obj_t * obj, lv_area_t * area) -{ - lv_obj_get_coords(obj, area); - - lv_coord_t left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); - lv_coord_t right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); - lv_coord_t top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN); - lv_coord_t bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN); - area->x1 += left; - area->x2 -= right; - area->y1 += top; - area->y2 -= bottom; -} - /** * @return true for txt fill the max_width. */ @@ -730,7 +753,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area uint32_t cur_txt_ofs = 0; lv_snippet_t snippet; /* use to save cur_span info and push it to stack */ memset(&snippet, 0, sizeof(snippet)); - + /* the loop control how many lines need to draw */ while(cur_span) { lv_coord_t max_line_h = 0; /* the max height of span-font when a line have a lot of span */ @@ -825,17 +848,18 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area } /* align deal with */ - if(spans->align != LV_TEXT_ALIGN_LEFT) { + lv_text_align_t align = lv_obj_get_style_text_align(obj, LV_PART_MAIN); + if(align != LV_TEXT_ALIGN_LEFT) { lv_coord_t align_ofs = 0; lv_coord_t txts_w = 0; for(int i = 0; i < item_cnt; i++) { lv_snippet_t * pinfo = lv_get_snippet(i); txts_w += pinfo->txt_w; } - if(spans->align == LV_TEXT_ALIGN_CENTER) { + if(align == LV_TEXT_ALIGN_CENTER) { align_ofs = (max_width - txts_w) / 2; } - else if(spans->align == LV_TEXT_ALIGN_RIGHT) { + else if(align == LV_TEXT_ALIGN_RIGHT) { align_ofs = max_width - txts_w; } txt_pos.x += align_ofs; @@ -950,4 +974,12 @@ Next_line_init: } } +static void refresh_self_size(lv_obj_t * obj) +{ + lv_spangroup_t * spans = (lv_spangroup_t *)obj; + spans->refresh = 1; + lv_obj_refresh_self_size(obj); + lv_obj_invalidate(obj); +} + #endif diff --git a/src/extra/widgets/span/lv_span.h b/src/extra/widgets/span/lv_span.h index 1670b3b588..4f7613de3e 100644 --- a/src/extra/widgets/span/lv_span.h +++ b/src/extra/widgets/span/lv_span.h @@ -41,19 +41,22 @@ enum { typedef uint8_t lv_span_mode_t; typedef struct { - char * txt; - lv_style_t style; - uint8_t static_flag : 1; + char * txt; /* a pointer to display text */ + lv_obj_t * spangroup; /* a pointer to spangroup */ + lv_style_t style; /* display text style */ + uint8_t static_flag : 1;/* the text is static flag */ } lv_span_t; /** Data of label*/ typedef struct { lv_obj_t obj; - lv_coord_t indent; + lv_coord_t indent; /* first line indent */ + lv_coord_t cache_w; /* the cache automatically calculates the width */ + lv_coord_t cache_h; /* similar cache_w */ lv_ll_t child_ll; - uint8_t mode : 2; - uint8_t align : 2; - uint8_t overflow : 1; + uint8_t mode : 2; /* details see lv_span_mode_t */ + uint8_t overflow : 1; /* details see lv_span_overflow_t */ + uint8_t refresh : 1; /* the spangroup need refresh cache_w and cache_h */ } lv_spangroup_t; extern const lv_obj_class_t lv_spangroup_class;