mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-30 07:06:19 +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 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 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,
|
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
|
* 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_obj_t * obj = lv_event_get_current_target(e);
|
||||||
lv_arc_label_t * arc_label = (lv_arc_label_t *)obj;
|
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_area_t coords;
|
||||||
lv_obj_get_content_coords(obj, &coords);
|
lv_obj_get_content_coords(obj, &coords);
|
||||||
|
|
||||||
@@ -407,27 +413,33 @@ static void arc_label_draw_main(lv_event_t * e)
|
|||||||
angle_start = angle_offset;
|
angle_start = angle_offset;
|
||||||
break;
|
break;
|
||||||
case LV_ARC_LABEL_TEXT_ALIGN_CENTER:
|
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,
|
angle_start = (arc_label->angle_size + angle_offset - calc_arc_text_total_angle(text_start, font, arc_r,
|
||||||
arc_label->angle_size,
|
arc_label->angle_size, letter_space, arc_label->recolor)) / 2;
|
||||||
letter_space)) / 2;
|
|
||||||
break;
|
break;
|
||||||
case LV_ARC_LABEL_TEXT_ALIGN_TRAILING:
|
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,
|
angle_start = arc_label->angle_size - calc_arc_text_total_angle(text_start, font, arc_r, arc_label->angle_size,
|
||||||
letter_space);
|
letter_space, arc_label->recolor);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t word_i = 0;
|
|
||||||
uint32_t processed_word_count = 0;
|
uint32_t processed_word_count = 0;
|
||||||
lv_value_precise_t prev_letter_w = 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 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;
|
lv_value_precise_t curr_total_arc_length = angle_start * M_PI / 180 * arc_r;
|
||||||
while(curr_total_arc_length <= total_arc_length) {
|
|
||||||
|
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;
|
||||||
uint32_t letter_next;
|
uint32_t letter_next;
|
||||||
lv_text_encoded_letter_next_2(arc_label->text, &letter, &letter_next, &word_i);
|
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);
|
const lv_value_precise_t letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||||
|
|
||||||
if(processed_word_count > 0) {
|
if(processed_word_count > 0) {
|
||||||
@@ -457,7 +469,7 @@ static void arc_label_draw_main(lv_event_t * e)
|
|||||||
lv_draw_letter_dsc_t dsc;
|
lv_draw_letter_dsc_t dsc;
|
||||||
lv_draw_letter_dsc_init(&dsc);
|
lv_draw_letter_dsc_init(&dsc);
|
||||||
dsc.font = font;
|
dsc.font = font;
|
||||||
dsc.color = color;
|
dsc.color = arc_label->recolor ? recolor_color : color;
|
||||||
dsc.opa = opa;
|
dsc.opa = opa;
|
||||||
if(arc_label->dir == LV_ARC_LABEL_DIR_CLOCKWISE) dsc.rotation = (curr_angle + 90) * 10;
|
if(arc_label->dir == LV_ARC_LABEL_DIR_CLOCKWISE) dsc.rotation = (curr_angle + 90) * 10;
|
||||||
else dsc.rotation = (curr_angle - 90) * 10;
|
else dsc.rotation = (curr_angle - 90) * 10;
|
||||||
@@ -490,24 +502,32 @@ static void arc_label_draw_main(lv_event_t * e)
|
|||||||
lv_draw_line(layer, &line_dsc);
|
lv_draw_line(layer, &line_dsc);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static lv_value_precise_t calc_arc_text_total_angle(const char * text, const lv_font_t * font, const uint32_t radius,
|
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;
|
uint32_t processed_letter_count = 0;
|
||||||
lv_value_precise_t prev_letter_w = 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;
|
const lv_value_precise_t angle_size_in_arc_length = angle_size * M_PI / 180 * radius;
|
||||||
lv_value_precise_t total_arc_length = 0;
|
lv_value_precise_t total_arc_length = 0;
|
||||||
while(total_arc_length < angle_size_in_arc_length) {
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
while(word_i <= text_len && total_arc_length < angle_size_in_arc_length) {
|
||||||
if(total_arc_length > angle_size_in_arc_length) {
|
if(total_arc_length > angle_size_in_arc_length) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t letter;
|
uint32_t letter;
|
||||||
uint32_t letter_next;
|
uint32_t letter_next;
|
||||||
lv_text_encoded_letter_next_2(text, &letter, &letter_next, &word_i);
|
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);
|
const lv_value_precise_t letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||||
|
|
||||||
if(processed_letter_count == 0) {
|
if(processed_letter_count == 0) {
|
||||||
@@ -525,8 +545,61 @@ static lv_value_precise_t calc_arc_text_total_angle(const char * text, const lv_
|
|||||||
prev_letter_w = letter_w;
|
prev_letter_w = letter_w;
|
||||||
processed_letter_count++;
|
processed_letter_count++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return total_arc_length * 180 / M_PI / radius;
|
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
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user