feat(text): add text recolor back (#6966)
Co-authored-by: Benign X <1341398182@qq.com>
This commit is contained in:
4
Kconfig
4
Kconfig
@@ -972,6 +972,10 @@ menu "LVGL configuration"
|
||||
help
|
||||
Minimum number of characters in a long word to put on a line after a break
|
||||
|
||||
config LV_TXT_COLOR_CMD
|
||||
string "The control character to use for signalling text recoloring"
|
||||
default "#"
|
||||
|
||||
config LV_USE_BIDI
|
||||
bool "Support bidirectional texts"
|
||||
help
|
||||
|
||||
@@ -607,6 +607,9 @@
|
||||
* In these languages characters should be replaced with another form based on their position in the text */
|
||||
#define LV_USE_ARABIC_PERSIAN_CHARS 0
|
||||
|
||||
/*The control character to use for signaling text recoloring*/
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
|
||||
/*==================
|
||||
* WIDGETS
|
||||
*================*/
|
||||
|
||||
@@ -32,10 +32,17 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum {
|
||||
CMD_STATE_WAIT,
|
||||
CMD_STATE_PAR,
|
||||
CMD_STATE_IN,
|
||||
};
|
||||
typedef unsigned char cmd_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static uint8_t hex_char_to_num(char hex);
|
||||
static void draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos,
|
||||
const lv_font_t * font, uint32_t letter, lv_draw_glyph_cb_t cb);
|
||||
|
||||
@@ -228,14 +235,16 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
|
||||
|
||||
/*Align to middle*/
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width = lv_text_get_width(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space);
|
||||
line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space,
|
||||
dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width = lv_text_get_width(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space);
|
||||
line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space,
|
||||
dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
@@ -260,7 +269,10 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
|
||||
int32_t underline_width = font->underline_thickness ? font->underline_thickness : 1;
|
||||
int32_t line_start_x;
|
||||
uint32_t i;
|
||||
uint32_t par_start = 0;
|
||||
int32_t letter_w;
|
||||
cmd_state_t cmd_state = CMD_STATE_WAIT;
|
||||
lv_color_t recolor = lv_color_black(); /* Holds the selected color inside the recolor command */
|
||||
|
||||
/*Write out all lines*/
|
||||
while(dsc->text[line_start] != '\0') {
|
||||
@@ -268,6 +280,7 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
|
||||
line_start_x = pos.x;
|
||||
|
||||
/*Write all letter of a line*/
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
i = 0;
|
||||
#if LV_USE_BIDI
|
||||
char * bidi_txt = lv_malloc(line_end - line_start + 1);
|
||||
@@ -293,6 +306,49 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(bidi_txt, &letter, &letter_next, &i);
|
||||
|
||||
/* Handle the recolor command */
|
||||
if((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) {
|
||||
if(cmd_state == CMD_STATE_WAIT) { /*Start char*/
|
||||
par_start = i;
|
||||
cmd_state = CMD_STATE_PAR;
|
||||
continue;
|
||||
}
|
||||
else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char*/
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
}
|
||||
else if(cmd_state == CMD_STATE_IN) { /*Command end*/
|
||||
cmd_state = CMD_STATE_WAIT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*Skip the color parameter and wait the space after it*/
|
||||
if(cmd_state == CMD_STATE_PAR) {
|
||||
if(letter == ' ') {
|
||||
/*Get the parameter*/
|
||||
if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) {
|
||||
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
|
||||
lv_memcpy(buf, &bidi_txt[par_start], LABEL_RECOLOR_PAR_LENGTH);
|
||||
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
|
||||
int r, g, b;
|
||||
r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);
|
||||
g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]);
|
||||
b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]);
|
||||
|
||||
recolor = lv_color_make(r, g, b);
|
||||
}
|
||||
else {
|
||||
recolor.red = dsc->color.red;
|
||||
recolor.blue = dsc->color.blue;
|
||||
recolor.green = dsc->color.green;
|
||||
}
|
||||
cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
/*Always set the bg_coordinates for placeholder drawing*/
|
||||
@@ -329,6 +385,9 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
|
||||
fill_dsc.color = dsc->sel_bg_color;
|
||||
cb(draw_unit, NULL, &fill_dsc, &bg_coords);
|
||||
}
|
||||
else if(cmd_state == CMD_STATE_IN) {
|
||||
draw_letter_dsc.color = recolor;
|
||||
}
|
||||
else {
|
||||
draw_letter_dsc.color = dsc->color;
|
||||
}
|
||||
@@ -352,14 +411,14 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
|
||||
/*Align to middle*/
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width =
|
||||
lv_text_get_width(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space);
|
||||
lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width =
|
||||
lv_text_get_width(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space);
|
||||
lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
@@ -378,6 +437,17 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Convert a hexadecimal characters to a number (0..15)
|
||||
* @param hex Pointer to a hexadecimal character (0..9, A..F)
|
||||
* @return the numerical value of `hex` or 0 on error
|
||||
*/
|
||||
static uint8_t hex_char_to_num(char hex)
|
||||
{
|
||||
if(hex >= '0' && hex <= '9') return hex - '0';
|
||||
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
|
||||
return 'A' <= hex && hex <= 'F' ? hex - 'A' + 10 : 0;
|
||||
}
|
||||
static void draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos,
|
||||
const lv_font_t * font, uint32_t letter, lv_draw_glyph_cb_t cb)
|
||||
{
|
||||
|
||||
@@ -1790,6 +1790,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*The control character to use for signaling text recoloring*/
|
||||
#ifndef LV_TXT_COLOR_CMD
|
||||
#ifdef CONFIG_LV_TXT_COLOR_CMD
|
||||
#define LV_TXT_COLOR_CMD CONFIG_LV_TXT_COLOR_CMD
|
||||
#else
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* WIDGETS
|
||||
*================*/
|
||||
|
||||
@@ -136,6 +136,37 @@ void lv_text_get_size(lv_point_t * size_res, const char * text, const lv_font_t
|
||||
size_res->y -= line_space;
|
||||
}
|
||||
|
||||
bool lv_text_is_cmd(lv_text_cmd_state_t * state, uint32_t c)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if(c == (uint32_t)LV_TXT_COLOR_CMD[0]) {
|
||||
if(*state == LV_TEXT_CMD_STATE_WAIT) { /*Start char*/
|
||||
*state = LV_TEXT_CMD_STATE_PAR;
|
||||
ret = true;
|
||||
}
|
||||
/*Other start char in parameter is escaped cmd. char*/
|
||||
else if(*state == LV_TEXT_CMD_STATE_WAIT) {
|
||||
*state = LV_TEXT_CMD_STATE_WAIT;
|
||||
}
|
||||
/*Command end*/
|
||||
else if(*state == LV_TEXT_CMD_STATE_IN) {
|
||||
*state = LV_TEXT_CMD_STATE_WAIT;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*Skip the color parameter and wait the space after it*/
|
||||
if(*state == LV_TEXT_CMD_STATE_PAR) {
|
||||
if(c == ' ') {
|
||||
*state = LV_TEXT_CMD_STATE_IN; /*After the parameter the text is in the command*/
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next word of text. A word is delimited by break characters.
|
||||
*
|
||||
@@ -164,11 +195,13 @@ void lv_text_get_size(lv_point_t * size_res, const char * text, const lv_font_t
|
||||
* @param max_width max width of the text (break the lines to fit this size). Set COORD_MAX to avoid line breaks
|
||||
* @param flags settings for the text from 'txt_flag_type' enum
|
||||
* @param[out] word_w_ptr width (in pixels) of the parsed word. May be NULL.
|
||||
* @param cmd_state Pointer to a lv_text_cmd_state_t variable which stored the current state of command proocessing
|
||||
* @return the index of the first char of the next word (in byte index not letter index. With UTF-8 they are different)
|
||||
*/
|
||||
static uint32_t lv_text_get_next_word(const char * txt, const lv_font_t * font,
|
||||
int32_t letter_space, int32_t max_width,
|
||||
lv_text_flag_t flag, uint32_t * word_w_ptr)
|
||||
lv_text_flag_t flag, uint32_t * word_w_ptr,
|
||||
lv_text_cmd_state_t * cmd_state)
|
||||
{
|
||||
if(txt == NULL || txt[0] == '\0') return 0;
|
||||
if(font == NULL) return 0;
|
||||
@@ -192,6 +225,16 @@ static uint32_t lv_text_get_next_word(const char * txt, const lv_font_t * font,
|
||||
letter_next = lv_text_encoded_next(txt, &i_next_next);
|
||||
word_len++;
|
||||
|
||||
/*Handle the recolor command*/
|
||||
if((flag & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_text_is_cmd(cmd_state, letter)) {
|
||||
i = i_next;
|
||||
i_next = i_next_next;
|
||||
letter = letter_next;
|
||||
continue; /*Skip the letter if it is part of a command*/
|
||||
}
|
||||
}
|
||||
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
cur_w += letter_w;
|
||||
|
||||
@@ -297,6 +340,8 @@ uint32_t lv_text_get_next_line(const char * txt, const lv_font_t * font,
|
||||
}
|
||||
|
||||
if(flag & LV_TEXT_FLAG_EXPAND) max_width = LV_COORD_MAX;
|
||||
lv_text_cmd_state_t cmd_state = LV_TEXT_CMD_STATE_WAIT;
|
||||
|
||||
uint32_t i = 0; /*Iterating index into txt*/
|
||||
|
||||
while(txt[i] != '\0' && max_width > 0) {
|
||||
@@ -304,7 +349,7 @@ uint32_t lv_text_get_next_line(const char * txt, const lv_font_t * font,
|
||||
if(i == 0) word_flag |= LV_TEXT_FLAG_BREAK_ALL;
|
||||
|
||||
uint32_t word_w = 0;
|
||||
uint32_t advance = lv_text_get_next_word(&txt[i], font, letter_space, max_width, word_flag, &word_w);
|
||||
uint32_t advance = lv_text_get_next_word(&txt[i], font, letter_space, max_width, word_flag, &word_w, &cmd_state);
|
||||
max_width -= word_w;
|
||||
line_w += word_w;
|
||||
|
||||
@@ -369,6 +414,45 @@ int32_t lv_text_get_width(const char * txt, uint32_t length, const lv_font_t * f
|
||||
return width;
|
||||
}
|
||||
|
||||
int32_t lv_text_get_width_with_flags(const char * txt, uint32_t length, const lv_font_t * font, int32_t letter_space,
|
||||
lv_text_flag_t flags)
|
||||
{
|
||||
if(txt == NULL) return 0;
|
||||
if(font == NULL) return 0;
|
||||
if(txt[0] == '\0') return 0;
|
||||
|
||||
uint32_t i = 0;
|
||||
int32_t width = 0;
|
||||
lv_text_cmd_state_t cmd_state = LV_TEXT_CMD_STATE_WAIT;
|
||||
|
||||
if(length != 0) {
|
||||
while(i < length) {
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(txt, &letter, &letter_next, &i);
|
||||
|
||||
if((flags & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_text_is_cmd(&cmd_state, letter) != false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t char_width = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
if(char_width > 0) {
|
||||
width += char_width;
|
||||
width += letter_space;
|
||||
}
|
||||
}
|
||||
|
||||
if(width > 0) {
|
||||
width -= letter_space; /*Trim the last letter space. Important if the text is center
|
||||
aligned*/
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
void lv_text_ins(char * txt_buf, uint32_t pos, const char * ins_txt)
|
||||
{
|
||||
if(txt_buf == NULL || ins_txt == NULL) return;
|
||||
|
||||
@@ -23,6 +23,9 @@ extern "C" {
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#ifndef LV_TXT_COLOR_CMD
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
#endif
|
||||
|
||||
#define LV_TXT_ENC_UTF8 1
|
||||
#define LV_TXT_ENC_ASCII 2
|
||||
@@ -43,6 +46,7 @@ typedef enum {
|
||||
Otherwise breaks are inserted at word boundaries, as configured via LV_TXT_BREAK_CHARS
|
||||
or according to LV_TXT_LINE_BREAK_LONG_LEN, LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN,
|
||||
and LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN.*/
|
||||
LV_TEXT_FLAG_RECOLOR = 0x08, /**< Enable parsing of recolor command*/
|
||||
} lv_text_flag_t;
|
||||
|
||||
/** Label align policy*/
|
||||
@@ -53,6 +57,13 @@ typedef enum {
|
||||
LV_TEXT_ALIGN_RIGHT, /**< Align text to right*/
|
||||
} lv_text_align_t;
|
||||
|
||||
/** State machine for text renderer. */
|
||||
typedef enum {
|
||||
LV_TEXT_CMD_STATE_WAIT, /**< Waiting for command*/
|
||||
LV_TEXT_CMD_STATE_PAR, /**< Processing the parameter*/
|
||||
LV_TEXT_CMD_STATE_IN, /**< Processing the command*/
|
||||
} lv_text_cmd_state_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
@@ -83,6 +94,26 @@ void lv_text_get_size(lv_point_t * size_res, const char * text, const lv_font_t
|
||||
*/
|
||||
int32_t lv_text_get_width(const char * txt, uint32_t length, const lv_font_t * font, int32_t letter_space);
|
||||
|
||||
/**
|
||||
* Give the length of a text with a given font with text flags
|
||||
* @param txt a '\0' terminate string
|
||||
* @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in
|
||||
* UTF-8)
|
||||
* @param font pointer to a font
|
||||
* @param letter_space letter space
|
||||
* @param flags settings for the text from ::lv_text_flag_t
|
||||
* @return length of a char_num long text
|
||||
*/
|
||||
int32_t lv_text_get_width_with_flags(const char * txt, uint32_t length, const lv_font_t * font, int32_t letter_space,
|
||||
lv_text_flag_t flags);
|
||||
|
||||
/**
|
||||
* Check if c is command state
|
||||
* @param state
|
||||
* @param c
|
||||
* @return True if c is state
|
||||
*/
|
||||
bool lv_text_is_cmd(lv_text_cmd_state_t * state, uint32_t c);
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -55,6 +55,7 @@ static void allocate_button_areas_and_controls(const lv_obj_t * obj, const char
|
||||
static void invalidate_button_area(const lv_obj_t * obj, uint32_t btn_idx);
|
||||
static void make_one_button_checked(lv_obj_t * obj, uint32_t btn_idx);
|
||||
static bool has_popovers_in_top_row(lv_obj_t * obj);
|
||||
static bool button_is_recolor(lv_buttonmatrix_ctrl_t ctrl_bits);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -749,6 +750,10 @@ static void draw_main(lv_event_t * e)
|
||||
obj->skip_trans = 0;
|
||||
}
|
||||
|
||||
bool recolor = button_is_recolor(btnm->ctrl_bits[btn_i]);
|
||||
if(recolor) draw_label_dsc_act.flag |= LV_TEXT_FLAG_RECOLOR;
|
||||
else draw_label_dsc_act.flag &= ~LV_TEXT_FLAG_RECOLOR;
|
||||
|
||||
draw_rect_dsc_act.base.id1 = btn_i;
|
||||
|
||||
/*Remove borders on the edges if `LV_BORDER_SIDE_INTERNAL`*/
|
||||
@@ -1042,4 +1047,9 @@ static bool has_popovers_in_top_row(lv_obj_t * obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool button_is_recolor(lv_buttonmatrix_ctrl_t ctrl_bits)
|
||||
{
|
||||
return (ctrl_bits & LV_BUTTONMATRIX_CTRL_RECOLOR) ? true : false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,7 +39,7 @@ typedef enum {
|
||||
LV_BUTTONMATRIX_CTRL_CHECKED = 0x0100, /**< Button is currently toggled (e.g. checked).*/
|
||||
LV_BUTTONMATRIX_CTRL_CLICK_TRIG = 0x0200, /**< 1: Send LV_EVENT_VALUE_CHANGE on CLICK, 0: Send LV_EVENT_VALUE_CHANGE on PRESS*/
|
||||
LV_BUTTONMATRIX_CTRL_POPOVER = 0x0400, /**< Show a popover when pressing this key*/
|
||||
LV_BUTTONMATRIX_CTRL_RESERVED_1 = 0x0800, /**< Reserved for later use*/
|
||||
LV_BUTTONMATRIX_CTRL_RECOLOR = 0x0800, /**< Enable text recoloring with `#color`*/
|
||||
LV_BUTTONMATRIX_CTRL_RESERVED_2 = 0x1000, /**< Reserved for later use*/
|
||||
LV_BUTTONMATRIX_CTRL_RESERVED_3 = 0x2000, /**< Reserved for later use*/
|
||||
LV_BUTTONMATRIX_CTRL_CUSTOM_1 = 0x4000, /**< Custom free to use flag*/
|
||||
|
||||
@@ -59,7 +59,7 @@ static size_t get_text_length(const char * text);
|
||||
static void copy_text_to_label(lv_label_t * label, const char * text);
|
||||
static lv_text_flag_t get_label_flags(lv_label_t * label);
|
||||
static void calculate_x_coordinate(int32_t * x, const lv_text_align_t align, const char * txt,
|
||||
uint32_t length, const lv_font_t * font, int32_t letter_space, lv_area_t * txt_coords);
|
||||
uint32_t length, const lv_font_t * font, int32_t letter_space, lv_area_t * txt_coords, lv_text_flag_t flags);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -274,6 +274,19 @@ void lv_label_set_text_selection_end(lv_obj_t * obj, uint32_t index)
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_label_set_recolor(lv_obj_t * obj, bool en)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
if(label->recolor == en) return;
|
||||
|
||||
label->recolor = en == false ? 0 : 1;
|
||||
|
||||
/*Refresh the text because the potential color codes in text needs to be hidden or revealed*/
|
||||
lv_label_refr_text(obj);
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
@@ -386,11 +399,11 @@ void lv_label_get_letter_pos(const lv_obj_t * obj, uint32_t char_id, lv_point_t
|
||||
#endif
|
||||
|
||||
/*Calculate the x coordinate*/
|
||||
int32_t x = lv_text_get_width(bidi_txt, visual_byte_pos, font, letter_space);
|
||||
int32_t x = lv_text_get_width_with_flags(bidi_txt, visual_byte_pos, font, letter_space, flag);
|
||||
if(char_id != line_start) x += letter_space;
|
||||
|
||||
uint32_t length = new_line_start - line_start;
|
||||
calculate_x_coordinate(&x, align, bidi_txt, length, font, letter_space, &txt_coords);
|
||||
calculate_x_coordinate(&x, align, bidi_txt, length, font, letter_space, &txt_coords, flag);
|
||||
pos->x = x;
|
||||
pos->y = y;
|
||||
|
||||
@@ -468,7 +481,9 @@ uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in, bool
|
||||
int32_t x = 0;
|
||||
const lv_text_align_t align = lv_obj_calculate_style_text_align(obj, LV_PART_MAIN, label->text);
|
||||
uint32_t length = new_line_start - line_start;
|
||||
calculate_x_coordinate(&x, align, bidi_txt, length, font, letter_space, &txt_coords);
|
||||
calculate_x_coordinate(&x, align, bidi_txt, length, font, letter_space, &txt_coords, flag);
|
||||
|
||||
lv_text_cmd_state_t cmd_state = LV_TEXT_CMD_STATE_WAIT;
|
||||
|
||||
uint32_t i = 0;
|
||||
uint32_t i_act = i;
|
||||
@@ -481,6 +496,12 @@ uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in, bool
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(bidi_txt, &letter, &letter_next, &i);
|
||||
|
||||
if((flag & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_text_is_cmd(&cmd_state, bidi_txt[i]) != false) {
|
||||
continue; /*Skip the letter if it is part of a command*/
|
||||
}
|
||||
}
|
||||
|
||||
int32_t gw = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
/*Finish if the x position or the last char of the next line is reached*/
|
||||
@@ -558,14 +579,18 @@ bool lv_label_is_char_under_pos(const lv_obj_t * obj, lv_point_t * pos)
|
||||
|
||||
int32_t x = 0;
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
const int32_t line_w = lv_text_get_width(&txt[line_start], new_line_start - line_start, font, letter_space);
|
||||
const int32_t line_w = lv_text_get_width_with_flags(&txt[line_start], new_line_start - line_start, font, letter_space,
|
||||
flag);
|
||||
x += lv_area_get_width(&txt_coords) / 2 - line_w / 2;
|
||||
}
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
const int32_t line_w = lv_text_get_width(&txt[line_start], new_line_start - line_start, font, letter_space);
|
||||
const int32_t line_w = lv_text_get_width_with_flags(&txt[line_start], new_line_start - line_start, font, letter_space,
|
||||
flag);
|
||||
x += lv_area_get_width(&txt_coords) - line_w;
|
||||
}
|
||||
|
||||
lv_text_cmd_state_t cmd_state = LV_TEXT_CMD_STATE_WAIT;
|
||||
|
||||
int32_t last_x = 0;
|
||||
uint32_t i = line_start;
|
||||
uint32_t i_current = i;
|
||||
@@ -578,6 +603,12 @@ bool lv_label_is_char_under_pos(const lv_obj_t * obj, lv_point_t * pos)
|
||||
/*Be careful 'i' already points to the next character*/
|
||||
lv_text_encoded_letter_next_2(txt, &letter, &letter_next, &i);
|
||||
|
||||
if((flag & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
if(lv_text_is_cmd(&cmd_state, txt[i]) != false) {
|
||||
continue; /*Skip the letter if it is part of a command*/
|
||||
}
|
||||
}
|
||||
|
||||
last_x = x;
|
||||
x += lv_font_get_glyph_width(font, letter, letter_next);
|
||||
if(pos->x < x) {
|
||||
@@ -619,6 +650,14 @@ uint32_t lv_label_get_text_selection_end(const lv_obj_t * obj)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool lv_label_get_recolor(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
return label->recolor == 0 ? false : true;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
@@ -681,6 +720,7 @@ static void lv_label_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
lv_label_t * label = (lv_label_t *)obj;
|
||||
|
||||
label->text = NULL;
|
||||
label->recolor = 0;
|
||||
label->static_txt = 0;
|
||||
label->dot_end = LV_LABEL_DOT_END_INV;
|
||||
label->long_mode = LV_LABEL_LONG_WRAP;
|
||||
@@ -748,6 +788,7 @@ static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
|
||||
int32_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
|
||||
lv_text_flag_t flag = LV_TEXT_FLAG_NONE;
|
||||
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);
|
||||
@@ -1302,6 +1343,7 @@ static lv_text_flag_t get_label_flags(lv_label_t * label)
|
||||
{
|
||||
lv_text_flag_t flag = LV_TEXT_FLAG_NONE;
|
||||
|
||||
if(label->recolor) flag |= LV_TEXT_FLAG_RECOLOR;
|
||||
if(label->expand) flag |= LV_TEXT_FLAG_EXPAND;
|
||||
|
||||
lv_obj_t * obj = (lv_obj_t *) label;
|
||||
@@ -1316,14 +1358,14 @@ static lv_text_flag_t get_label_flags(lv_label_t * label)
|
||||
|
||||
/* Function created because of this pattern be used in multiple functions */
|
||||
static void calculate_x_coordinate(int32_t * x, const lv_text_align_t align, const char * txt, uint32_t length,
|
||||
const lv_font_t * font, int32_t letter_space, lv_area_t * txt_coords)
|
||||
const lv_font_t * font, int32_t letter_space, lv_area_t * txt_coords, lv_text_flag_t flags)
|
||||
{
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
const int32_t line_w = lv_text_get_width(txt, length, font, letter_space);
|
||||
const int32_t line_w = lv_text_get_width_with_flags(txt, length, font, letter_space, flags);
|
||||
*x += lv_area_get_width(txt_coords) / 2 - line_w / 2;
|
||||
}
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
const int32_t line_w = lv_text_get_width(txt, length, font, letter_space);
|
||||
const int32_t line_w = lv_text_get_width_with_flags(txt, length, font, letter_space, flags);
|
||||
*x += lv_area_get_width(txt_coords) - line_w;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -129,6 +129,14 @@ void lv_label_set_text_selection_start(lv_obj_t * obj, uint32_t index);
|
||||
*/
|
||||
void lv_label_set_text_selection_end(lv_obj_t * obj, uint32_t index);
|
||||
|
||||
/**
|
||||
* Enable the recoloring by in-line commands
|
||||
* @param obj pointer to a label object
|
||||
* @param en true: enable recoloring, false: disable
|
||||
* @example "This is a #ff0000 red# word"
|
||||
*/
|
||||
void lv_label_set_recolor(lv_obj_t * obj, bool en);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
@@ -188,6 +196,13 @@ uint32_t lv_label_get_text_selection_start(const lv_obj_t * obj);
|
||||
*/
|
||||
uint32_t lv_label_get_text_selection_end(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* @brief Get the recoloring attribute
|
||||
* @param obj pointer to a label object.
|
||||
* @return true: recoloring is enabled, false: recoloring is disabled
|
||||
*/
|
||||
bool lv_label_get_recolor(const lv_obj_t * obj);
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
@@ -50,6 +50,7 @@ struct _lv_label_t {
|
||||
lv_point_t offset; /**< Text draw position offset */
|
||||
lv_label_long_mode_t long_mode : 3; /**< Determine what to do with the long texts */
|
||||
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 */
|
||||
|
||||
@@ -511,6 +511,7 @@ static void draw_main(lv_event_t * e)
|
||||
area_ok = lv_area_intersect(&mask_sel, &layer->_clip_area, &sel_area);
|
||||
if(area_ok) {
|
||||
lv_obj_t * label = get_label(obj);
|
||||
if(lv_label_get_recolor(label)) label_dsc.flag |= LV_TEXT_FLAG_RECOLOR;
|
||||
|
||||
/*Get the size of the "selected text"*/
|
||||
lv_point_t label_sel_size;
|
||||
@@ -569,6 +570,8 @@ static void draw_label(lv_event_t * e)
|
||||
lv_draw_label_dsc_t label_draw_dsc;
|
||||
lv_draw_label_dsc_init(&label_draw_dsc);
|
||||
lv_obj_init_draw_label_dsc(roller, LV_PART_MAIN, &label_draw_dsc);
|
||||
if(lv_label_get_recolor(label_obj)) label_draw_dsc.flag |= LV_TEXT_FLAG_RECOLOR;
|
||||
|
||||
lv_layer_t * layer = lv_event_get_layer(e);
|
||||
|
||||
/*If the roller has shadow or outline it has some ext. draw size
|
||||
|
||||
@@ -1025,8 +1025,8 @@ static void lv_draw_span(lv_obj_t * obj, lv_layer_t * layer)
|
||||
if(txt_pos.y + max_line_h + next_line_h - line_space > coords.y2 + 1) { /* for overflow if is end line. */
|
||||
if(last_snippet->txt[last_snippet->bytes] != '\0') {
|
||||
last_snippet->bytes = lv_strlen(last_snippet->txt);
|
||||
last_snippet->txt_w = lv_text_get_width(last_snippet->txt, last_snippet->bytes, last_snippet->font,
|
||||
last_snippet->letter_space);
|
||||
last_snippet->txt_w = lv_text_get_width_with_flags(last_snippet->txt, last_snippet->bytes, last_snippet->font,
|
||||
last_snippet->letter_space, label_draw_dsc.flag);
|
||||
}
|
||||
ellipsis_valid = spans->overflow == LV_SPAN_OVERFLOW_ELLIPSIS;
|
||||
is_end_line = true;
|
||||
|
||||
BIN
tests/ref_imgs/widgets/label_recolor.png
Normal file
BIN
tests/ref_imgs/widgets/label_recolor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
@@ -615,4 +615,15 @@ void test_label_max_width(void)
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/label_max_width.png");
|
||||
}
|
||||
|
||||
void test_label_with_recolor_cmd(void)
|
||||
{
|
||||
lv_obj_clean(lv_screen_active());
|
||||
|
||||
lv_obj_t * label_recolor = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label_recolor, "Write a #ff0000 red# word");
|
||||
lv_label_set_recolor(label_recolor, true);
|
||||
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/label_recolor.png");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user