mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-24 08:16:29 +08:00
feat(arc_label): support recolor feature
This commit is contained in:
@@ -46,7 +46,10 @@ static void lv_arc_label_constructor(const lv_obj_class_t * class_p, lv_obj_t *
|
||||
static void arc_label_draw_main(lv_event_t * e);
|
||||
static void lv_arc_label_event(const lv_obj_class_t * class_p, lv_event_t * e);
|
||||
static lv_value_precise_t calc_arc_text_total_angle(const char * text, const lv_font_t * font, uint32_t radius,
|
||||
const lv_value_precise_t angle_size, int32_t letter_space);
|
||||
const lv_value_precise_t angle_size, int32_t letter_space, bool recolor);
|
||||
static const char * recolor_cmd_get_next(const char * text_in, uint32_t len_in,
|
||||
const char ** text_out, uint32_t * len_out,
|
||||
lv_color_t * color_out);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -367,6 +370,9 @@ static void arc_label_draw_main(lv_event_t * e)
|
||||
lv_obj_t * obj = lv_event_get_current_target(e);
|
||||
lv_arc_label_t * arc_label = (lv_arc_label_t *)obj;
|
||||
|
||||
const char * text = arc_label->text;
|
||||
const char * text_start = text;
|
||||
|
||||
lv_area_t coords;
|
||||
lv_obj_get_content_coords(obj, &coords);
|
||||
|
||||
@@ -407,126 +413,193 @@ static void arc_label_draw_main(lv_event_t * e)
|
||||
angle_start = angle_offset;
|
||||
break;
|
||||
case LV_ARC_LABEL_TEXT_ALIGN_CENTER:
|
||||
angle_start = (arc_label->angle_size + angle_offset - calc_arc_text_total_angle(arc_label->text, font, arc_r,
|
||||
arc_label->angle_size,
|
||||
letter_space)) / 2;
|
||||
angle_start = (arc_label->angle_size + angle_offset - calc_arc_text_total_angle(text_start, font, arc_r,
|
||||
arc_label->angle_size, letter_space, arc_label->recolor)) / 2;
|
||||
break;
|
||||
case LV_ARC_LABEL_TEXT_ALIGN_TRAILING:
|
||||
angle_start = arc_label->angle_size - calc_arc_text_total_angle(arc_label->text, font, arc_r, arc_label->angle_size,
|
||||
letter_space);
|
||||
angle_start = arc_label->angle_size - calc_arc_text_total_angle(text_start, font, arc_r, arc_label->angle_size,
|
||||
letter_space, arc_label->recolor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t word_i = 0;
|
||||
uint32_t processed_word_count = 0;
|
||||
lv_value_precise_t prev_letter_w = 0;
|
||||
lv_value_precise_t total_arc_length = arc_label->angle_size * M_PI / 180 * arc_r;
|
||||
lv_value_precise_t curr_total_arc_length = angle_start * M_PI / 180 * arc_r;
|
||||
while(curr_total_arc_length <= total_arc_length) {
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(arc_label->text, &letter, &letter_next, &word_i);
|
||||
const lv_value_precise_t letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
if(processed_word_count > 0) {
|
||||
const lv_value_precise_t arc_offset = (prev_letter_w + letter_w + letter_space) / (lv_value_precise_t)2;
|
||||
curr_total_arc_length += arc_offset;
|
||||
if(curr_total_arc_length > total_arc_length) {
|
||||
break;
|
||||
while(text) {
|
||||
uint32_t word_i = 0;
|
||||
uint32_t text_len = LV_TEXT_LEN_MAX;
|
||||
lv_color_t recolor_color = color;
|
||||
if(arc_label->recolor) text = recolor_cmd_get_next(text, LV_TEXT_LEN_MAX, &text_start, &text_len, &recolor_color);
|
||||
else text = NULL;
|
||||
|
||||
while(word_i < text_len && curr_total_arc_length <= total_arc_length) {
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(text_start, &letter, &letter_next, &word_i);
|
||||
const lv_value_precise_t letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
if(processed_word_count > 0) {
|
||||
const lv_value_precise_t arc_offset = (prev_letter_w + letter_w + letter_space) / (lv_value_precise_t)2;
|
||||
curr_total_arc_length += arc_offset;
|
||||
if(curr_total_arc_length > total_arc_length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const lv_value_precise_t curr_angle = arc_label->angle_start + (arc_label->dir == LV_ARC_LABEL_DIR_CLOCKWISE ?
|
||||
curr_total_arc_length : total_arc_length - curr_total_arc_length) * 180 / M_PI / arc_r;
|
||||
const lv_value_precise_t curr_angle = arc_label->angle_start + (arc_label->dir == LV_ARC_LABEL_DIR_CLOCKWISE ?
|
||||
curr_total_arc_length : total_arc_length - curr_total_arc_length) * 180 / M_PI / arc_r;
|
||||
|
||||
#if LV_USE_FLOAT
|
||||
const lv_value_precise_t x = cos(curr_angle * M_PI / 180) * arc_r;
|
||||
const lv_value_precise_t y = sin(curr_angle * M_PI / 180) * arc_r;
|
||||
const lv_value_precise_t x = cos(curr_angle * M_PI / 180) * arc_r;
|
||||
const lv_value_precise_t y = sin(curr_angle * M_PI / 180) * arc_r;
|
||||
#else
|
||||
const lv_value_precise_t x = lv_trigo_cos(curr_angle) * arc_r / 32767;
|
||||
const lv_value_precise_t y = lv_trigo_sin(curr_angle) * arc_r / 32767;
|
||||
const lv_value_precise_t x = lv_trigo_cos(curr_angle) * arc_r / 32767;
|
||||
const lv_value_precise_t y = lv_trigo_sin(curr_angle) * arc_r / 32767;
|
||||
#endif
|
||||
|
||||
lv_point_t point = {
|
||||
x + lv_area_get_width(&coords) / 2 + coords.x1 + arc_label->center_offset.x,
|
||||
y + lv_area_get_height(&coords) / 2 + coords.y1 + arc_label->center_offset.y,
|
||||
};
|
||||
lv_point_t point = {
|
||||
x + lv_area_get_width(&coords) / 2 + coords.x1 + arc_label->center_offset.x,
|
||||
y + lv_area_get_height(&coords) / 2 + coords.y1 + arc_label->center_offset.y,
|
||||
};
|
||||
|
||||
lv_draw_letter_dsc_t dsc;
|
||||
lv_draw_letter_dsc_init(&dsc);
|
||||
dsc.font = font;
|
||||
dsc.color = color;
|
||||
dsc.opa = opa;
|
||||
if(arc_label->dir == LV_ARC_LABEL_DIR_CLOCKWISE) dsc.rotation = (curr_angle + 90) * 10;
|
||||
else dsc.rotation = (curr_angle - 90) * 10;
|
||||
lv_draw_letter_dsc_t dsc;
|
||||
lv_draw_letter_dsc_init(&dsc);
|
||||
dsc.font = font;
|
||||
dsc.color = arc_label->recolor ? recolor_color : color;
|
||||
dsc.opa = opa;
|
||||
if(arc_label->dir == LV_ARC_LABEL_DIR_CLOCKWISE) dsc.rotation = (curr_angle + 90) * 10;
|
||||
else dsc.rotation = (curr_angle - 90) * 10;
|
||||
|
||||
dsc.unicode = letter;
|
||||
if(dsc.unicode == 0) {
|
||||
break;
|
||||
}
|
||||
dsc.unicode = letter;
|
||||
if(dsc.unicode == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
lv_draw_letter(layer, &dsc, &point);
|
||||
lv_draw_letter(layer, &dsc, &point);
|
||||
|
||||
prev_letter_w = letter_w;
|
||||
processed_word_count++;
|
||||
prev_letter_w = letter_w;
|
||||
processed_word_count++;
|
||||
|
||||
#if LV_ARC_LABEL_DEBUG
|
||||
lv_draw_line_dsc_t line_dsc;
|
||||
lv_draw_line_dsc_init(&line_dsc);
|
||||
line_dsc.color = lv_color_make(0x11, 0x45, 0x14);
|
||||
line_dsc.opa = LV_OPA_30;
|
||||
line_dsc.width = 2;
|
||||
line_dsc.p1 = (lv_point_precise_t) {
|
||||
.x = point.x,
|
||||
.y = point.y
|
||||
};
|
||||
line_dsc.p2 = (lv_point_precise_t) {
|
||||
.x = lv_area_get_width(&coords) / 2 + coords.x1,
|
||||
.y = lv_area_get_height(&coords) / 2 + coords.y1
|
||||
};
|
||||
lv_draw_line_dsc_t line_dsc;
|
||||
lv_draw_line_dsc_init(&line_dsc);
|
||||
line_dsc.color = lv_color_make(0x11, 0x45, 0x14);
|
||||
line_dsc.opa = LV_OPA_30;
|
||||
line_dsc.width = 2;
|
||||
line_dsc.p1 = (lv_point_precise_t) {
|
||||
.x = point.x,
|
||||
.y = point.y
|
||||
};
|
||||
line_dsc.p2 = (lv_point_precise_t) {
|
||||
.x = lv_area_get_width(&coords) / 2 + coords.x1,
|
||||
.y = lv_area_get_height(&coords) / 2 + coords.y1
|
||||
};
|
||||
|
||||
lv_draw_line(layer, &line_dsc);
|
||||
lv_draw_line(layer, &line_dsc);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static lv_value_precise_t calc_arc_text_total_angle(const char * text, const lv_font_t * font, const uint32_t radius,
|
||||
const lv_value_precise_t angle_size, const int32_t letter_space)
|
||||
const lv_value_precise_t angle_size, const int32_t letter_space, const bool recolor)
|
||||
{
|
||||
uint32_t word_i = 0;
|
||||
const char * text_start = text;
|
||||
uint32_t processed_letter_count = 0;
|
||||
lv_value_precise_t prev_letter_w = 0;
|
||||
const lv_value_precise_t angle_size_in_arc_length = angle_size * M_PI / 180 * radius;
|
||||
lv_value_precise_t total_arc_length = 0;
|
||||
while(total_arc_length < angle_size_in_arc_length) {
|
||||
if(total_arc_length > angle_size_in_arc_length) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(text, &letter, &letter_next, &word_i);
|
||||
const lv_value_precise_t letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
while(text) {
|
||||
uint32_t word_i = 0;
|
||||
uint32_t text_len = LV_TEXT_LEN_MAX;
|
||||
if(recolor) text = recolor_cmd_get_next(text, LV_TEXT_LEN_MAX, &text_start, &text_len, NULL);
|
||||
else text = NULL;
|
||||
|
||||
if(processed_letter_count == 0) {
|
||||
while(word_i <= text_len && total_arc_length < angle_size_in_arc_length) {
|
||||
if(total_arc_length > angle_size_in_arc_length) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(text_start, &letter, &letter_next, &word_i);
|
||||
const lv_value_precise_t letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
if(processed_letter_count == 0) {
|
||||
processed_letter_count++;
|
||||
continue;
|
||||
}
|
||||
const lv_value_precise_t arc_offset = (prev_letter_w + letter_w + letter_space) / (lv_value_precise_t)2;
|
||||
|
||||
total_arc_length += arc_offset;
|
||||
|
||||
if(letter == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev_letter_w = letter_w;
|
||||
processed_letter_count++;
|
||||
continue;
|
||||
}
|
||||
const lv_value_precise_t arc_offset = (prev_letter_w + letter_w + letter_space) / (lv_value_precise_t)2;
|
||||
|
||||
total_arc_length += arc_offset;
|
||||
|
||||
if(letter == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev_letter_w = letter_w;
|
||||
processed_letter_count++;
|
||||
}
|
||||
|
||||
return total_arc_length * 180 / M_PI / radius;
|
||||
}
|
||||
|
||||
static const char * recolor_cmd_get_next(const char * text_in, uint32_t len_in,
|
||||
const char ** text_out, uint32_t * len_out,
|
||||
lv_color_t * color_out)
|
||||
{
|
||||
if(!text_in || len_in == 0 || *text_in == '\0') return NULL;
|
||||
|
||||
const char * text = text_in;
|
||||
const char * text_end = text_in + len_in;
|
||||
bool has_cmd = false;
|
||||
|
||||
if(*text == LV_TXT_COLOR_CMD[0]) {
|
||||
if(len_in < 8) {
|
||||
if(text_out) *text_out = text_in;
|
||||
if(len_out) *len_out = len_in;
|
||||
return NULL;
|
||||
}
|
||||
has_cmd = true;
|
||||
text++;
|
||||
|
||||
int32_t index = 0;
|
||||
uint8_t color_buf[6];
|
||||
while(*text && index < 6) {
|
||||
uint8_t ch = text[index];
|
||||
if(!((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))) break;
|
||||
if(ch >= 'a' && ch <= 'f') ch -= 'a' - 10;
|
||||
else if(ch >= 'A' && ch <= 'F') ch -= 'A' - 10;
|
||||
else ch -= '0';
|
||||
color_buf[index] = ch;
|
||||
index++;
|
||||
}
|
||||
|
||||
const bool has_valid_param = index == 6 && text[index] == ' ';
|
||||
|
||||
text += index;
|
||||
if(has_valid_param && color_out)
|
||||
*color_out = lv_color_make(color_buf[0] << 4 | color_buf[1],
|
||||
color_buf[2] << 4 | color_buf[3],
|
||||
color_buf[4] << 4 | color_buf[5]);
|
||||
|
||||
while(text < text_end && *text && *text++ != ' ') { }
|
||||
}
|
||||
|
||||
const char * text_segment_start = text;
|
||||
while(text < text_end && *text && *text != LV_TXT_COLOR_CMD[0]) text++;
|
||||
if(text_out) *text_out = text_segment_start;
|
||||
if(len_out) *len_out = text - text_segment_start;
|
||||
if(*text == '\0') return NULL;
|
||||
if(has_cmd && *text == LV_TXT_COLOR_CMD[0]) text++;
|
||||
|
||||
return text < text_end && *text ? text : NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user