mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-27 11:57:48 +08:00
feat(arclabel): support lv_arclabel_get_text_angle to get real rendered text size in degree (#9546)
This commit is contained in:
@@ -51,6 +51,8 @@ static void lv_arclabel_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, bool recolor,
|
const lv_value_precise_t angle_size, int32_t letter_space, bool recolor,
|
||||||
const lv_arclabel_overflow_t overflow, bool end_overlap, bool * need_ellipsis, uint32_t * letter_count);
|
const lv_arclabel_overflow_t overflow, bool end_overlap, bool * need_ellipsis, uint32_t * letter_count);
|
||||||
|
static lv_value_precise_t arclabel_calc_arc_text_total_angle(lv_obj_t * obj, int32_t * arc_radius, bool * need_ellipsis,
|
||||||
|
uint32_t * letter_count);
|
||||||
static const char * recolor_cmd_get_next(const char * text_in, uint32_t len_in,
|
static const char * recolor_cmd_get_next(const char * text_in, uint32_t len_in,
|
||||||
const char ** text_out, uint32_t * len_out,
|
const char ** text_out, uint32_t * len_out,
|
||||||
lv_color_t * color_out);
|
lv_color_t * color_out);
|
||||||
@@ -356,6 +358,13 @@ bool lv_arclabel_get_end_overlap(lv_obj_t * obj)
|
|||||||
return ((lv_arclabel_t *) obj)->end_overlap;
|
return ((lv_arclabel_t *) obj)->end_overlap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lv_value_precise_t lv_arclabel_get_text_angle(lv_obj_t * obj)
|
||||||
|
{
|
||||||
|
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||||
|
|
||||||
|
return arclabel_calc_arc_text_total_angle(obj, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*=====================
|
/*=====================
|
||||||
* Other functions
|
* Other functions
|
||||||
*====================*/
|
*====================*/
|
||||||
@@ -418,42 +427,14 @@ static void arclabel_draw_main(lv_event_t * e)
|
|||||||
const lv_opa_t opa = LV_OPA_MIX2(layer->opa, lv_obj_get_style_text_opa(obj, LV_PART_MAIN));
|
const lv_opa_t opa = LV_OPA_MIX2(layer->opa, lv_obj_get_style_text_opa(obj, LV_PART_MAIN));
|
||||||
const int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
|
const int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
|
||||||
|
|
||||||
const int32_t line_height = font->line_height;
|
int32_t arc_r = 0;
|
||||||
const int32_t base_line = font->base_line;
|
|
||||||
int32_t arc_r_delta = 0;
|
|
||||||
int32_t arc_r = arclabel->radius;
|
|
||||||
|
|
||||||
if(arc_r == LV_SIZE_CONTENT) arc_r = LV_PCT(100);
|
|
||||||
if(LV_COORD_IS_PCT(arc_r)) {
|
|
||||||
const int32_t width = lv_area_get_width(&coords);
|
|
||||||
const int32_t height = lv_area_get_height(&coords);
|
|
||||||
arc_r = lv_pct_to_px(arc_r, LV_MIN(width, height)) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(arclabel->text_align_v) {
|
|
||||||
case LV_ARCLABEL_TEXT_ALIGN_LEADING:
|
|
||||||
arc_r_delta = line_height - base_line;
|
|
||||||
break;
|
|
||||||
case LV_ARCLABEL_TEXT_ALIGN_CENTER:
|
|
||||||
arc_r_delta = line_height / 2 - base_line;
|
|
||||||
break;
|
|
||||||
case LV_ARCLABEL_TEXT_ALIGN_TRAILING:
|
|
||||||
arc_r_delta = -base_line;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
arc_r += arclabel->dir == LV_ARCLABEL_DIR_CLOCKWISE ? -arc_r_delta : arc_r_delta;
|
|
||||||
|
|
||||||
bool need_ellipsis = false;
|
bool need_ellipsis = false;
|
||||||
|
uint32_t processed_total_word_count = 0;
|
||||||
|
const lv_value_precise_t total_visible_angle = arclabel_calc_arc_text_total_angle(obj, &arc_r, &need_ellipsis,
|
||||||
|
&processed_total_word_count);
|
||||||
|
|
||||||
const int32_t offset = arclabel->offset;
|
const int32_t offset = arclabel->offset;
|
||||||
const lv_value_precise_t angle_offset = rad_to_deg(offset, arc_r);
|
const lv_value_precise_t angle_offset = rad_to_deg(offset, arc_r);
|
||||||
uint32_t processed_total_word_count = 0;
|
|
||||||
|
|
||||||
lv_value_precise_t total_visible_angle = calc_arc_text_total_angle(text_start, font, arc_r,
|
|
||||||
arclabel->angle_size, letter_space, arclabel->recolor,
|
|
||||||
arclabel->overflow, arclabel->end_overlap, &need_ellipsis, &processed_total_word_count);
|
|
||||||
|
|
||||||
lv_value_precise_t angle_start = 0;
|
lv_value_precise_t angle_start = 0;
|
||||||
switch(arclabel->text_align_h) {
|
switch(arclabel->text_align_h) {
|
||||||
@@ -568,6 +549,54 @@ static void arclabel_draw_main(lv_event_t * e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static lv_value_precise_t arclabel_calc_arc_text_total_angle(lv_obj_t * obj, int32_t * arc_radius, bool * need_ellipsis,
|
||||||
|
uint32_t * letter_count)
|
||||||
|
{
|
||||||
|
lv_arclabel_t * arclabel = (lv_arclabel_t *)obj;
|
||||||
|
|
||||||
|
const char * text = arclabel->text;
|
||||||
|
const char * text_start = text;
|
||||||
|
|
||||||
|
lv_area_t coords;
|
||||||
|
lv_obj_get_content_coords(obj, &coords);
|
||||||
|
|
||||||
|
const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
|
||||||
|
const int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
|
||||||
|
|
||||||
|
const int32_t line_height = font->line_height;
|
||||||
|
const int32_t base_line = font->base_line;
|
||||||
|
int32_t arc_r_delta = 0;
|
||||||
|
int32_t arc_r = arclabel->radius;
|
||||||
|
|
||||||
|
if(arc_r == LV_SIZE_CONTENT) arc_r = LV_PCT(100);
|
||||||
|
if(LV_COORD_IS_PCT(arc_r)) {
|
||||||
|
const int32_t width = lv_area_get_width(&coords);
|
||||||
|
const int32_t height = lv_area_get_height(&coords);
|
||||||
|
arc_r = lv_pct_to_px(arc_r, LV_MIN(width, height)) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(arclabel->text_align_v) {
|
||||||
|
case LV_ARCLABEL_TEXT_ALIGN_LEADING:
|
||||||
|
arc_r_delta = line_height - base_line;
|
||||||
|
break;
|
||||||
|
case LV_ARCLABEL_TEXT_ALIGN_CENTER:
|
||||||
|
arc_r_delta = line_height / 2 - base_line;
|
||||||
|
break;
|
||||||
|
case LV_ARCLABEL_TEXT_ALIGN_TRAILING:
|
||||||
|
arc_r_delta = -base_line;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
arc_r += arclabel->dir == LV_ARCLABEL_DIR_CLOCKWISE ? -arc_r_delta : arc_r_delta;
|
||||||
|
if(arc_radius != NULL) *arc_radius = arc_r;
|
||||||
|
lv_value_precise_t total_visible_angle = calc_arc_text_total_angle(text_start, font, arc_r,
|
||||||
|
arclabel->angle_size, letter_space, arclabel->recolor,
|
||||||
|
arclabel->overflow, arclabel->end_overlap, need_ellipsis, letter_count);
|
||||||
|
return total_visible_angle;
|
||||||
|
}
|
||||||
|
|
||||||
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 bool recolor,
|
const lv_value_precise_t angle_size, const int32_t letter_space, const bool recolor,
|
||||||
const lv_arclabel_overflow_t overflow, bool end_overlap, bool * need_ellipsis, uint32_t * letter_count)
|
const lv_arclabel_overflow_t overflow, bool end_overlap, bool * need_ellipsis, uint32_t * letter_count)
|
||||||
@@ -580,6 +609,7 @@ static lv_value_precise_t calc_arc_text_total_angle(const char * text, const lv_
|
|||||||
lv_value_precise_t total_arc_length = 0;
|
lv_value_precise_t total_arc_length = 0;
|
||||||
lv_value_precise_t pre_total_arc_length = 0;
|
lv_value_precise_t pre_total_arc_length = 0;
|
||||||
uint32_t pre_processed_letter_count = 0;
|
uint32_t pre_processed_letter_count = 0;
|
||||||
|
lv_value_precise_t ellipsis_arc_length = 0;
|
||||||
bool full = false;
|
bool full = false;
|
||||||
uint32_t letter = 0;
|
uint32_t letter = 0;
|
||||||
uint32_t letter_next = 0;
|
uint32_t letter_next = 0;
|
||||||
@@ -587,7 +617,7 @@ static lv_value_precise_t calc_arc_text_total_angle(const char * text, const lv_
|
|||||||
lv_value_precise_t available_arc_length = angle_size_in_arc_length;
|
lv_value_precise_t available_arc_length = angle_size_in_arc_length;
|
||||||
if(overflow == LV_ARCLABEL_OVERFLOW_ELLIPSIS) {
|
if(overflow == LV_ARCLABEL_OVERFLOW_ELLIPSIS) {
|
||||||
lv_value_precise_t dot_width = lv_font_get_glyph_width(font, '.', '.');
|
lv_value_precise_t dot_width = lv_font_get_glyph_width(font, '.', '.');
|
||||||
lv_value_precise_t ellipsis_arc_length = 3 * dot_width + 2 * letter_space;
|
ellipsis_arc_length = 3 * dot_width + 2 * letter_space;
|
||||||
if(available_arc_length > ellipsis_arc_length) available_arc_length -= ellipsis_arc_length;
|
if(available_arc_length > ellipsis_arc_length) available_arc_length -= ellipsis_arc_length;
|
||||||
else available_arc_length = 0;
|
else available_arc_length = 0;
|
||||||
}
|
}
|
||||||
@@ -628,7 +658,9 @@ static lv_value_precise_t calc_arc_text_total_angle(const char * text, const lv_
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(full && (overflow == LV_ARCLABEL_OVERFLOW_ELLIPSIS || overflow == LV_ARCLABEL_OVERFLOW_CLIP)) {
|
if(full && (overflow == LV_ARCLABEL_OVERFLOW_ELLIPSIS || overflow == LV_ARCLABEL_OVERFLOW_CLIP)) {
|
||||||
total_arc_length = pre_total_arc_length;
|
total_arc_length = pre_total_arc_length + (overflow == LV_ARCLABEL_OVERFLOW_ELLIPSIS
|
||||||
|
? ellipsis_arc_length
|
||||||
|
: 0);
|
||||||
processed_letter_count = pre_processed_letter_count;
|
processed_letter_count = pre_processed_letter_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -273,6 +273,17 @@ lv_arclabel_overflow_t lv_arclabel_get_overflow(lv_obj_t * obj);
|
|||||||
*/
|
*/
|
||||||
bool lv_arclabel_get_end_overlap(lv_obj_t * obj);
|
bool lv_arclabel_get_end_overlap(lv_obj_t * obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text angle for an arc label object.
|
||||||
|
* @note The text angle is calculated at runtime. You can get the updated value
|
||||||
|
* after the arclabel's size has been updated.
|
||||||
|
* Returns the real rendered text angle in degrees except in
|
||||||
|
* `LV_ARCLABEL_OVERFLOW_VISIBLE` mode.
|
||||||
|
* @param obj pointer to an arc label object
|
||||||
|
* @return the text angle (if `LV_USE_FLOAT` is enabled it can be fractional too.)
|
||||||
|
*/
|
||||||
|
lv_value_precise_t lv_arclabel_get_text_angle(lv_obj_t * obj);
|
||||||
|
|
||||||
/*=====================
|
/*=====================
|
||||||
* Other functions
|
* Other functions
|
||||||
*====================*/
|
*====================*/
|
||||||
|
|||||||
@@ -165,10 +165,13 @@ void test_arclabel_overflow(void)
|
|||||||
lv_arclabel_set_dir(arclabel, LV_ARCLABEL_DIR_CLOCKWISE);
|
lv_arclabel_set_dir(arclabel, LV_ARCLABEL_DIR_CLOCKWISE);
|
||||||
lv_arclabel_set_overflow(arclabel, overflows[i]);
|
lv_arclabel_set_overflow(arclabel, overflows[i]);
|
||||||
lv_obj_center(arclabel);
|
lv_obj_center(arclabel);
|
||||||
}
|
|
||||||
|
|
||||||
|
lv_obj_refr_size(arclabel);
|
||||||
|
TEST_ASSERT_GREATER_THAN_FLOAT(178, lv_arclabel_get_text_angle(arclabel));
|
||||||
|
}
|
||||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/arclabel_overflow" EXT_NAME);
|
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/arclabel_overflow" EXT_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_arclabel_opacity(void)
|
void test_arclabel_opacity(void)
|
||||||
{
|
{
|
||||||
if(!font) {
|
if(!font) {
|
||||||
@@ -220,4 +223,5 @@ void test_arclabel_opacity(void)
|
|||||||
}
|
}
|
||||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/arclabel_opacity" EXT_NAME);
|
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/arclabel_opacity" EXT_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user