mirror of
https://github.com/lvgl/lvgl.git
synced 2024-11-23 09:43:41 +08:00
perf(label): simplify handling of bytes overwritten with dots (#7001)
This commit is contained in:
parent
e332a0db52
commit
59c72243cc
@ -32,7 +32,7 @@
|
||||
|
||||
#define LV_LABEL_DEF_SCROLL_SPEED lv_anim_speed_clamped(40, 300, 10000)
|
||||
#define LV_LABEL_SCROLL_DELAY 300
|
||||
#define LV_LABEL_DOT_END_INV 0xFFFFFFFF
|
||||
#define LV_LABEL_DOT_BEGIN_INV 0xFFFFFFFF
|
||||
#define LV_LABEL_HINT_HEIGHT_LIMIT 1024 /*Enable "hint" to buffer info about labels larger than this. (Speed up drawing)*/
|
||||
|
||||
/**********************
|
||||
@ -49,10 +49,8 @@ static void draw_main(lv_event_t * e);
|
||||
|
||||
static void lv_label_refr_text(lv_obj_t * obj);
|
||||
static void lv_label_revert_dots(lv_obj_t * label);
|
||||
static void lv_label_set_dots(lv_obj_t * label, uint32_t dot_begin);
|
||||
|
||||
static bool lv_label_set_dot_tmp(lv_obj_t * label, char * data, uint32_t len);
|
||||
static char * lv_label_get_dot_tmp(lv_obj_t * label);
|
||||
static void lv_label_dot_tmp_free(lv_obj_t * label);
|
||||
static void set_ofs_x_anim(void * obj, int32_t v);
|
||||
static void set_ofs_y_anim(void * obj, int32_t v);
|
||||
static size_t get_text_length(const char * text);
|
||||
@ -137,11 +135,10 @@ void lv_label_set_text(lv_obj_t * obj, const char * text)
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
|
||||
lv_obj_invalidate(obj);
|
||||
|
||||
/*If text is NULL then just refresh with the current text*/
|
||||
if(text == NULL) text = label->text;
|
||||
|
||||
lv_label_revert_dots(obj); /*In case text == label->text*/
|
||||
const size_t text_len = get_text_length(text);
|
||||
|
||||
/*If set its own text then reallocate it (maybe its size changed)*/
|
||||
@ -237,11 +234,6 @@ void lv_label_set_long_mode(lv_obj_t * obj, lv_label_long_mode_t long_mode)
|
||||
else
|
||||
label->expand = 0;
|
||||
|
||||
/*Restore the character under the dots*/
|
||||
if(label->long_mode == LV_LABEL_LONG_DOT && label->dot_end != LV_LABEL_DOT_END_INV) {
|
||||
lv_label_revert_dots(obj);
|
||||
}
|
||||
|
||||
label->long_mode = long_mode;
|
||||
lv_label_refr_text(obj);
|
||||
}
|
||||
@ -722,7 +714,7 @@ static void lv_label_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
label->text = NULL;
|
||||
label->recolor = 0;
|
||||
label->static_txt = 0;
|
||||
label->dot_end = LV_LABEL_DOT_END_INV;
|
||||
label->dot_begin = LV_LABEL_DOT_BEGIN_INV;
|
||||
label->long_mode = LV_LABEL_LONG_WRAP;
|
||||
lv_point_set(&label->offset, 0, 0);
|
||||
|
||||
@ -736,8 +728,6 @@ static void lv_label_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
label->sel_start = LV_DRAW_LABEL_NO_TXT_SEL;
|
||||
label->sel_end = LV_DRAW_LABEL_NO_TXT_SEL;
|
||||
#endif
|
||||
label->dot.tmp_ptr = NULL;
|
||||
label->dot_tmp_alloc = 0;
|
||||
|
||||
lv_obj_remove_flag(obj, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_label_set_long_mode(obj, LV_LABEL_LONG_WRAP);
|
||||
@ -751,7 +741,6 @@ static void lv_label_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
LV_UNUSED(class_p);
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
|
||||
lv_label_dot_tmp_free(obj);
|
||||
if(!label->static_txt) lv_free(label->text);
|
||||
label->text = NULL;
|
||||
}
|
||||
@ -768,8 +757,6 @@ 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)) {
|
||||
/*Revert dots for proper refresh*/
|
||||
lv_label_revert_dots(obj);
|
||||
lv_label_refr_text(obj);
|
||||
}
|
||||
else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
|
||||
@ -791,13 +778,16 @@ static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
if(label->recolor != 0) flag |= LV_TEXT_FLAG_RECOLOR;
|
||||
if(label->expand != 0) flag |= LV_TEXT_FLAG_EXPAND;
|
||||
|
||||
int32_t w = lv_obj_get_content_width(obj);
|
||||
int32_t w;
|
||||
if(lv_obj_get_style_width(obj, LV_PART_MAIN) == LV_SIZE_CONTENT && !obj->w_layout) w = LV_COORD_MAX;
|
||||
else w = lv_obj_get_content_width(obj);
|
||||
|
||||
w = LV_MIN(w, lv_obj_get_style_max_width(obj, 0));
|
||||
|
||||
uint32_t dot_begin = label->dot_begin;
|
||||
lv_label_revert_dots(obj);
|
||||
lv_text_get_size(&label->size_cache, label->text, font, letter_space, line_space, w, flag);
|
||||
lv_label_set_dots(obj, dot_begin);
|
||||
|
||||
label->invalid_size_cache = false;
|
||||
}
|
||||
|
||||
@ -955,6 +945,7 @@ static void lv_label_refr_text(lv_obj_t * obj)
|
||||
lv_point_t size;
|
||||
lv_text_flag_t flag = get_label_flags(label);
|
||||
|
||||
lv_label_revert_dots(obj);
|
||||
lv_text_get_size(&size, label->text, font, letter_space, line_space, max_w, flag);
|
||||
|
||||
lv_obj_refresh_self_size(obj);
|
||||
@ -1152,16 +1143,9 @@ static void lv_label_refr_text(lv_obj_t * obj)
|
||||
}
|
||||
}
|
||||
else if(label->long_mode == LV_LABEL_LONG_DOT) {
|
||||
if(size.y <= lv_area_get_height(&txt_coords)) { /*No dots are required, the text is short enough*/
|
||||
label->dot_end = LV_LABEL_DOT_END_INV;
|
||||
}
|
||||
else if(size.y <= lv_font_get_line_height(font)) { /*No dots are required for one-line texts*/
|
||||
label->dot_end = LV_LABEL_DOT_END_INV;
|
||||
}
|
||||
else if(lv_text_get_encoded_length(label->text) <= LV_LABEL_DOT_NUM) { /*Don't turn to dots all the characters*/
|
||||
label->dot_end = LV_LABEL_DOT_END_INV;
|
||||
}
|
||||
else {
|
||||
if(size.y > lv_area_get_height(&txt_coords) && /*Text overflows available area*/
|
||||
size.y > lv_font_get_line_height(font) && /*No break requested, so no dots required*/
|
||||
lv_text_get_encoded_length(label->text) > LV_LABEL_DOT_NUM) { /*Do not turn all characters into dots*/
|
||||
lv_point_t p;
|
||||
int32_t y_overed;
|
||||
p.x = lv_area_get_width(&txt_coords) -
|
||||
@ -1190,27 +1174,10 @@ static void lv_label_refr_text(lv_obj_t * obj)
|
||||
}
|
||||
|
||||
/*Save letters under the dots and replace them with dots*/
|
||||
uint32_t byte_id_ori = byte_id;
|
||||
uint32_t i;
|
||||
uint8_t len = 0;
|
||||
for(i = 0; i <= LV_LABEL_DOT_NUM; i++) {
|
||||
len += lv_text_encoded_size(&label->text[byte_id]);
|
||||
lv_text_encoded_next(label->text, &byte_id);
|
||||
if(len > LV_LABEL_DOT_NUM || byte_id > txt_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lv_label_set_dot_tmp(obj, &label->text[byte_id_ori], len)) {
|
||||
for(i = 0; i < LV_LABEL_DOT_NUM; i++) {
|
||||
label->text[byte_id_ori + i] = '.';
|
||||
}
|
||||
label->text[byte_id_ori + LV_LABEL_DOT_NUM] = '\0';
|
||||
label->dot_end = letter_id + LV_LABEL_DOT_NUM;
|
||||
}
|
||||
lv_label_set_dots(obj, byte_id);
|
||||
}
|
||||
}
|
||||
else if(label->long_mode == LV_LABEL_LONG_CLIP) {
|
||||
else if(label->long_mode == LV_LABEL_LONG_CLIP || label->long_mode == LV_LABEL_LONG_WRAP) {
|
||||
/*Do nothing*/
|
||||
}
|
||||
|
||||
@ -1220,88 +1187,30 @@ static void lv_label_refr_text(lv_obj_t * obj)
|
||||
static void lv_label_revert_dots(lv_obj_t * obj)
|
||||
{
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
|
||||
if(label->long_mode != LV_LABEL_LONG_DOT) return;
|
||||
if(label->dot_end == LV_LABEL_DOT_END_INV) return;
|
||||
|
||||
const uint32_t letter_i = label->dot_end - LV_LABEL_DOT_NUM;
|
||||
const uint32_t byte_i = lv_text_encoded_get_byte_id(label->text, letter_i);
|
||||
|
||||
/*Restore the characters*/
|
||||
uint8_t i = 0;
|
||||
char * dot_tmp = lv_label_get_dot_tmp(obj);
|
||||
while(label->text[byte_i + i] != '\0') {
|
||||
label->text[byte_i + i] = dot_tmp[i];
|
||||
i++;
|
||||
}
|
||||
label->text[byte_i + i] = dot_tmp[i];
|
||||
|
||||
lv_label_dot_tmp_free(obj);
|
||||
|
||||
label->dot_end = LV_LABEL_DOT_END_INV;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store `len` characters from `data`. Allocates space if necessary.
|
||||
*
|
||||
* @param label pointer to label object
|
||||
* @param len Number of characters to store.
|
||||
* @return true on success.
|
||||
*/
|
||||
static bool lv_label_set_dot_tmp(lv_obj_t * obj, char * data, uint32_t len)
|
||||
{
|
||||
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
lv_label_dot_tmp_free(obj); /*Deallocate any existing space*/
|
||||
if(len > sizeof(char *)) {
|
||||
/*Memory needs to be allocated. Allocates an additional byte
|
||||
*for a NULL-terminator so it can be copied.*/
|
||||
label->dot.tmp_ptr = lv_malloc(len + 1);
|
||||
if(label->dot.tmp_ptr == NULL) {
|
||||
LV_LOG_ERROR("Failed to allocate memory for dot_tmp_ptr");
|
||||
return false;
|
||||
if(label->dot_begin != LV_LABEL_DOT_BEGIN_INV) {
|
||||
for(int i = 0; i < LV_LABEL_DOT_NUM + 1 && label->dot[i]; i++) {
|
||||
label->text[label->dot_begin + i] = label->dot[i];
|
||||
}
|
||||
lv_memcpy(label->dot.tmp_ptr, data, len);
|
||||
label->dot.tmp_ptr[len] = '\0';
|
||||
label->dot_tmp_alloc = true;
|
||||
}
|
||||
else {
|
||||
/*Characters can be directly stored in object*/
|
||||
label->dot_tmp_alloc = false;
|
||||
lv_memcpy(label->dot.tmp, data, len);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored dot_tmp characters
|
||||
* @param label pointer to label object
|
||||
* @return char pointer to a stored characters. Is *not* necessarily NULL-terminated.
|
||||
*/
|
||||
static char * lv_label_get_dot_tmp(lv_obj_t * obj)
|
||||
{
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
if(label->dot_tmp_alloc) {
|
||||
return label->dot.tmp_ptr;
|
||||
}
|
||||
else {
|
||||
return label->dot.tmp;
|
||||
label->dot_begin = LV_LABEL_DOT_BEGIN_INV;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the dot_tmp_ptr field if it was previously allocated.
|
||||
* Always clears the field
|
||||
* @param label pointer to label object.
|
||||
*/
|
||||
static void lv_label_dot_tmp_free(lv_obj_t * obj)
|
||||
static void lv_label_set_dots(lv_obj_t * obj, uint32_t dot_begin)
|
||||
{
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
if(label->dot_tmp_alloc && label->dot.tmp_ptr) {
|
||||
lv_free(label->dot.tmp_ptr);
|
||||
LV_ASSERT_MSG(label->dot_begin == LV_LABEL_DOT_BEGIN_INV, "Label dots already set");
|
||||
if(dot_begin != LV_LABEL_DOT_BEGIN_INV) {
|
||||
/*Save characters*/
|
||||
lv_strncpy(label->dot, &label->text[dot_begin], LV_LABEL_DOT_NUM + 1);
|
||||
label->dot_begin = dot_begin;
|
||||
|
||||
/*Overwrite up to LV_LABEL_DOT_NUM + 1 characters with dots and null terminator*/
|
||||
int i = 0;
|
||||
for(; i < LV_LABEL_DOT_NUM && label->text[dot_begin + i]; i++) {
|
||||
label->text[dot_begin + i] = '.';
|
||||
}
|
||||
label->text[dot_begin + i] = '\0';
|
||||
}
|
||||
label->dot_tmp_alloc = false;
|
||||
label->dot.tmp_ptr = NULL;
|
||||
}
|
||||
|
||||
static void set_ofs_x_anim(void * obj, int32_t v)
|
||||
|
@ -31,11 +31,8 @@ extern "C" {
|
||||
struct _lv_label_t {
|
||||
lv_obj_t obj;
|
||||
char * text;
|
||||
union {
|
||||
char * tmp_ptr; /**< Pointer to the allocated memory containing the character replaced by dots */
|
||||
char tmp[LV_LABEL_DOT_NUM + 1]; /**< Directly store the characters if <=4 characters */
|
||||
} dot;
|
||||
uint32_t dot_end; /**< The real text length, used in dot mode */
|
||||
char dot[LV_LABEL_DOT_NUM + 1]; /**< Bytes that have been replaced with dots */
|
||||
uint32_t dot_begin; /**< Offset where bytes have been replaced with dots */
|
||||
|
||||
#if LV_LABEL_LONG_TXT_HINT
|
||||
lv_draw_label_hint_t hint;
|
||||
@ -52,7 +49,6 @@ struct _lv_label_t {
|
||||
uint8_t static_txt : 1; /**< Flag to indicate the text is static */
|
||||
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_SCROLL) */
|
||||
uint8_t dot_tmp_alloc : 1; /**< 1: dot is allocated, 0: dot directly holds up to 4 chars */
|
||||
uint8_t invalid_size_cache : 1; /**< 1: Recalculate size and update cache */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user