From 374657c1be69d439728eff6ccdef93af403f11f3 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 19 Dec 2019 22:44:18 +0100 Subject: [PATCH] new_style: integrate label --- src/lv_core/lv_obj.c | 123 ++- src/lv_core/lv_obj.h | 5 + src/lv_core/lv_style.c | 47 ++ src/lv_core/lv_style.h | 14 +- src/lv_draw/lv_draw_label.c | 1463 ++++++++++++++++++----------------- src/lv_draw/lv_draw_label.h | 27 +- src/lv_objx/lv_btn.c | 3 +- src/lv_objx/lv_label.c | 187 +++-- src/lv_objx/lv_label.h | 31 +- 9 files changed, 1039 insertions(+), 861 deletions(-) diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index ce5fc8b8d..68f1f99d9 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -1229,6 +1229,11 @@ void lv_obj_set_style_opa(lv_obj_t * obj, lv_style_property_t prop, lv_opa_t opa lv_style_set_opa(&obj->style_dsc.local, prop, opa); } +void lv_obj_set_style_ptr(lv_obj_t * obj, lv_style_property_t prop, void * p) +{ + lv_style_set_ptr(&obj->style_dsc.local, prop, p); +} + void lv_obj_add_style_class(lv_obj_t * obj, uint8_t type, lv_style_t * style) { lv_style_classes_t * class = lv_mem_alloc(sizeof(lv_style_classes_t)); @@ -1258,6 +1263,8 @@ void lv_obj_refresh_style(lv_obj_t * obj, uint8_t type) lv_obj_invalidate(obj); obj->signal_cb(obj, LV_SIGNAL_STYLE_CHG, &type); lv_obj_invalidate(obj); + + refresh_children_style(obj, type) } /** @@ -2072,7 +2079,7 @@ lv_style_value_t lv_obj_get_style_value(const lv_obj_t * obj, uint8_t type, lv_s const lv_obj_t * parent = obj; while(parent) { - lv_style_dsc_t * dsc = lv_obj_get_style(obj, type); + lv_style_dsc_t * dsc = lv_obj_get_style(parent, type); if(dsc == NULL) continue; int16_t weight_act; @@ -2131,7 +2138,7 @@ lv_color_t lv_obj_get_style_color(const lv_obj_t * obj, uint8_t type, lv_style_p const lv_obj_t * parent = obj; while(parent) { - lv_style_dsc_t * dsc = lv_obj_get_style(obj, type); + lv_style_dsc_t * dsc = lv_obj_get_style(parent, type); if(dsc == NULL) continue; int16_t weight_act; lv_color_t value_act; @@ -2169,6 +2176,12 @@ lv_color_t lv_obj_get_style_color(const lv_obj_t * obj, uint8_t type, lv_style_p if(weight >= 0) return value; + prop = prop & (~LV_STYLE_STATE_MASK); + switch(prop) { + case LV_STYLE_TEXT_COLOR: + return LV_COLOR_BLACK; + } + return LV_COLOR_WHITE; } @@ -2183,7 +2196,7 @@ lv_opa_t lv_obj_get_style_opa(const lv_obj_t * obj, uint8_t type, lv_style_prope const lv_obj_t * parent = obj; while(parent) { - lv_style_dsc_t * dsc = lv_obj_get_style(obj, type); + lv_style_dsc_t * dsc = lv_obj_get_style(parent, type); if(dsc == NULL) continue; int16_t weight_act; @@ -2205,7 +2218,7 @@ lv_opa_t lv_obj_get_style_opa(const lv_obj_t * obj, uint8_t type, lv_style_prope weight_act = lv_style_get_opa(classes->style, prop, &value_act); /*On perfect match return the value immediately*/ if(weight_act == weight_goal) { - return weight_act; + return value_act; } /*If the found ID is better the current candidate then use it*/ else if(weight_act >= weight) { @@ -2225,6 +2238,67 @@ lv_opa_t lv_obj_get_style_opa(const lv_obj_t * obj, uint8_t type, lv_style_prope return LV_OPA_COVER; } + +void * lv_obj_get_style_ptr(const lv_obj_t * obj, uint8_t type, lv_style_property_t prop) +{ + lv_style_attr_t attr; + attr.full = prop >> 8; + + int16_t weight_goal = attr.bits.state; + int16_t weight = -1; + void * value; + + const lv_obj_t * parent = obj; + while(parent) { + lv_style_dsc_t * dsc = lv_obj_get_style(parent, type); + if(dsc == NULL) continue; + + int16_t weight_act; + void * value_act; + weight_act = lv_style_get_ptr(&dsc->local, prop, &value_act); + + /*On perfect match return the value immediately*/ + if(weight_act == weight_goal) { + return value_act; + } + /*If the found ID is better the current candidate then use it*/ + else if(weight_act >= weight) { + weight = weight_act; + value = value_act; + } + + const lv_style_classes_t * classes = obj->style_dsc.classes; + while(classes) { + weight_act = lv_style_get_ptr(classes->style, prop, &value_act); + /*On perfect match return the value immediately*/ + if(weight_act == weight_goal) { + return value_act; + } + /*If the found ID is better the current candidate then use it*/ + else if(weight_act >= weight) { + weight = weight_act; + value = value_act; + } + + classes = classes->next; + } + + if(attr.bits.inherit == 0) break; + parent = lv_obj_get_parent(parent); + } + + if(weight >= 0) return value; + + + prop = prop & (~LV_STYLE_STATE_MASK); + switch(prop) { + case LV_STYLE_FONT: + return LV_FONT_DEFAULT; + } + + return NULL; +} + /*----------------- * Attribute get *----------------*/ @@ -2402,7 +2476,14 @@ bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot) lv_obj_state_t lv_obj_get_state(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - return obj->state; + uint8_t state = 0; + const lv_obj_t * parent = obj; + while(parent) { + state |= parent->state; + parent = lv_obj_get_parent(parent); + } + + return state; } /** @@ -2601,10 +2682,8 @@ static void lv_obj_del_async_cb(void * obj) */ void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, uint8_t type, lv_obj_state_t state, lv_draw_rect_dsc_t * draw_dsc) { - lv_style_state_t style_state = state << LV_STYLE_STATE_POS; - lv_draw_rect_dsc_init(draw_dsc); draw_dsc->radius = lv_obj_get_style_value(obj, type, LV_STYLE_RADIUS | style_state); draw_dsc->bg_color = lv_obj_get_style_color(obj, type, LV_STYLE_BG_COLOR | style_state); @@ -2619,6 +2698,16 @@ void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, uint8_t type, lv_obj_state_t stat } } +void lv_obj_init_draw_label_dsc(lv_obj_t * obj, uint8_t type, lv_obj_state_t state, lv_draw_label_dsc_t * draw_dsc) +{ + + lv_style_state_t style_state = state << LV_STYLE_STATE_POS; + + draw_dsc->color = lv_obj_get_style_color(obj, type, LV_STYLE_TEXT_COLOR| style_state); + + draw_dsc->font = lv_obj_get_style_ptr(obj, type, LV_STYLE_FONT | style_state); +} + /** * Handle the drawing related tasks of the base objects. * @param obj pointer to an object @@ -2667,6 +2756,7 @@ static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area } else if(mode == LV_DESIGN_DRAW_MAIN) { lv_draw_rect_dsc_t draw_dsc; + lv_draw_rect_dsc_init(&draw_dsc); lv_obj_init_draw_rect_dsc(obj, LV_OBJ_STYLE_MAIN, lv_obj_get_state(obj), &draw_dsc); lv_draw_rect(&obj->coords, clip_area, &draw_dsc, lv_obj_get_opa_scale(obj)); @@ -2780,19 +2870,14 @@ static void report_style_mod_core(void * style_p, lv_obj_t * obj) * because the NULL styles are inherited from the parent * @param obj pointer to an object */ -static void refresh_children_style(lv_obj_t * obj) +static void refresh_children_style(lv_obj_t * obj, uint8_t type) { -// lv_obj_t * child = lv_obj_get_child(obj, NULL); -// while(child != NULL) { -// if(child->style_p == NULL) { -// refresh_children_style(child); /*Check children too*/ -// lv_obj_refresh_style(child); /*Notify the child about the style change*/ -// } else if(child->style_p->glass) { -// /*Children with 'glass' parent might be effected if their class == NULL*/ -// refresh_children_style(child); -// } -// child = lv_obj_get_child(obj, child); -// } + lv_obj_t * child = lv_obj_get_child(obj, NULL); + while(child != NULL) { + refresh_children_style(child); /*Check children too*/ + lv_obj_refresh_style(child); /*Notify the child about the style change*/ + child = lv_obj_get_child(obj, child); + } } /** diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index 8d85b7a7d..a6c3084af 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -470,6 +470,8 @@ void lv_obj_set_style_value(lv_obj_t * obj, lv_style_property_t prop, lv_style_v void lv_obj_set_style_opa(lv_obj_t * obj, lv_style_property_t prop, lv_opa_t opa); +void lv_obj_set_style_ptr(lv_obj_t * obj, lv_style_property_t prop, void * p); + void lv_obj_add_style_class(lv_obj_t * obj, uint8_t type, lv_style_t * style); /** * Notify an object about its style is modified @@ -829,6 +831,7 @@ lv_color_t lv_obj_get_style_color(const lv_obj_t * obj, uint8_t type, lv_style_p lv_opa_t lv_obj_get_style_opa(const lv_obj_t * obj, uint8_t type, lv_style_property_t prop); +void * lv_obj_get_style_ptr(const lv_obj_t * obj, uint8_t type, lv_style_property_t prop); ///** // * Get the style pointer of an object (if NULL get style of the parent) // * @param obj pointer to an object @@ -1036,6 +1039,8 @@ lv_res_t lv_obj_handle_get_type_signal(lv_obj_type_t * buf, const char * name); */ void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, uint8_t type, lv_obj_state_t state, lv_draw_rect_dsc_t * draw_dsc); +void lv_obj_init_draw_label_dsc(lv_obj_t * obj, uint8_t type, lv_obj_state_t state, lv_draw_label_dsc_t * draw_dsc); + /********************** * MACROS **********************/ diff --git a/src/lv_core/lv_style.c b/src/lv_core/lv_style.c index 063bee37e..4f64db1e5 100644 --- a/src/lv_core/lv_style.c +++ b/src/lv_core/lv_style.c @@ -165,6 +165,34 @@ void lv_style_set_opa(lv_style_t * style, lv_style_property_t prop, lv_opa_t opa memcpy(style->map + style->size - sizeof(lv_opa_t), &opa, sizeof(lv_opa_t)); } +void lv_style_set_ptr(lv_style_t * style, lv_style_property_t prop, void * p) +{ + int32_t id = get_property_index(style, prop); + /*The property already exists but not sure it's state is the same*/ + if(id >= 0) { + lv_style_attr_t attr_found; + lv_style_attr_t attr_goal; + + attr_found.full = *(style->map + id + 1); + attr_goal.full = (prop >> 8) & 0xFFU; + + if(attr_found.bits.state == attr_goal.bits.state) { + memcpy(style->map + id + sizeof(lv_style_property_t), &p, sizeof(void *)); + return; + } + } + + /*Add new property if not exists yet*/ + style->size += sizeof(lv_style_property_t) + sizeof(void *); + style->map = lv_mem_realloc(style->map, style->size); + LV_ASSERT_MEM(style->map); + if(style == NULL) return; + + memcpy(style->map + style->size - (sizeof(lv_style_property_t) + sizeof(void *)), &prop, sizeof(lv_style_property_t)); + memcpy(style->map + style->size - sizeof(void *), &p, sizeof(void *)); +} + + /** * Get the a property from a style. * Take into account the style state and return the property which matches the best. @@ -227,6 +255,25 @@ int16_t lv_style_get_color(const lv_style_t * style, lv_style_property_t prop, l } } + + +int16_t lv_style_get_ptr(const lv_style_t * style, lv_style_property_t prop, void ** res) +{ + int32_t id = get_property_index(style, prop); + if(id < 0) { + return -1; + } else { + memcpy(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(void*)); + lv_style_attr_t attr_act; + attr_act.full = style->map[id + 1]; + + lv_style_attr_t attr_goal; + attr_goal.full = (prop >> 8) & 0xFF; + + return attr_act.bits.state & attr_goal.bits.state; + } +} + /** * Mix two styles according to a given ratio * @param start start style diff --git a/src/lv_core/lv_style.h b/src/lv_core/lv_style.h index 41bdf6234..c78b7b637 100644 --- a/src/lv_core/lv_style.h +++ b/src/lv_core/lv_style.h @@ -58,7 +58,7 @@ typedef uint8_t lv_grad_dir_t; #define LV_STYLE_ID_MASK 0x00FF #define LV_STYLE_ATTR_NONE 0 -#define LV_STYLE_ATTR_INHERIT (1 << 8) +#define LV_STYLE_ATTR_INHERIT (1 << 7) typedef union { struct { @@ -104,8 +104,14 @@ enum { LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_COLOR, 0x4, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_OPA, 0x4, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), -// LV_STYLE_PROP_INIT(LV_STYLE_TEXT_COLOR, 0x40, LV_STYLE_ATTR_TYPE_COLOR), -// LV_STYLE_PROP_INIT(LV_STYLE_LINE_COLOR, 0x50, LV_STYLE_ATTR_TYPE_COLOR), + LV_STYLE_PROP_INIT(LV_STYLE_LETTER_SPACE, 0x5, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_LINE_SPACE, 0x5, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_BLEND_MODE, 0x5, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_COLOR, 0x5, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_OPA, 0x5, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_FONT, 0x5, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_INHERIT), + + // LV_STYLE_PROP_INIT(LV_STYLE_LINE_COLOR, 0x50, LV_STYLE_ATTR_TYPE_COLOR), // LV_STYLE_PROP_INIT(LV_STYLE_IMG_COLOR, 0x60, LV_STYLE_ATTR_TYPE_COLOR), }; @@ -191,11 +197,13 @@ void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * void lv_style_set_value(lv_style_t * style, lv_style_property_t prop, lv_style_value_t value); void lv_style_set_color(lv_style_t * style, lv_style_property_t prop, lv_color_t color); void lv_style_set_opa(lv_style_t * style, lv_style_property_t prop, lv_opa_t opa); +void lv_style_set_ptr(lv_style_t * style, lv_style_property_t prop, void * p); int16_t lv_style_get_value(const lv_style_t * style, lv_style_property_t prop, lv_style_value_t * res); int16_t lv_style_get_opa(const lv_style_t * style, lv_style_property_t prop, lv_opa_t * res); int16_t lv_style_get_color(const lv_style_t * style, lv_style_property_t prop, lv_color_t * res); +int16_t lv_style_get_ptr(const lv_style_t * style, lv_style_property_t prop, void ** res); #if LV_USE_ANIMATION diff --git a/src/lv_draw/lv_draw_label.c b/src/lv_draw/lv_draw_label.c index 69ef7a327..b68caaa07 100644 --- a/src/lv_draw/lv_draw_label.c +++ b/src/lv_draw/lv_draw_label.c @@ -1,757 +1,764 @@ -///** -// * @file lv_draw_label.c -// * -// */ -// -///********************* -// * INCLUDES -// *********************/ -//#include "lv_draw_label.h" -//#include "../lv_misc/lv_math.h" -//#include "../lv_hal/lv_hal_disp.h" -//#include "../lv_core/lv_refr.h" -//#include "../lv_misc/lv_bidi.h" -// -///********************* -// * DEFINES -// *********************/ -//#define LABEL_RECOLOR_PAR_LENGTH 6 -//#define LV_LABEL_HINT_UPDATE_TH 1024 /*Update the "hint" if the label's y coordinates have changed more then this*/ -// -///********************** -// * TYPEDEFS -// **********************/ -//enum { -// CMD_STATE_WAIT, -// CMD_STATE_PAR, -// CMD_STATE_IN, -//}; -//typedef uint8_t cmd_state_t; -// -///********************** -// * STATIC PROTOTYPES -// **********************/ -//static void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, const lv_font_t * font_p, uint32_t letter, -// lv_color_t color, lv_opa_t opa); -//static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, const uint8_t * map_p, lv_color_t color, lv_opa_t opa); -//static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, const uint8_t * map_p, lv_color_t color, lv_opa_t opa); -// -// -//static uint8_t hex_char_to_num(char hex); -// -///********************** -// * STATIC VARIABLES -// **********************/ -///*clang-format off*/ -//static const uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ -//static const uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ -//static const uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ -// 68, 85, 102, 119, -// 136, 153, 170, 187, -// 204, 221, 238, 255}; -// /*clang-format on*/ -// -///********************** -// * MACROS -// **********************/ -// -///********************** -// * GLOBAL FUNCTIONS -// **********************/ -// -///** -// * Write a text -// * @param coords coordinates of the label -// * @param mask the label will be drawn only in this area -// * @param style pointer to a style -// * @param opa_scale scale down all opacities by the factor -// * @param txt 0 terminated text to write -// * @param flag settings for the text from 'txt_flag_t' enum -// * @param offset text offset in x and y direction (NULL if unused) -// * @param sel make the text selected in the range by drawing a background there -// */ -//void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, -// const char * txt, lv_txt_flag_t flag, lv_point_t * offset, lv_draw_label_txt_sel_t * sel, -// lv_draw_label_hint_t * hint, lv_bidi_dir_t bidi_dir) -//{ -// const lv_font_t * font = style->text.font; -// lv_coord_t w; -// -// /*No need to waste processor time if string is empty*/ -// if (txt[0] == '\0') return; -// -// if((flag & LV_TXT_FLAG_EXPAND) == 0) { -// /*Normally use the label's width as width*/ -// w = lv_area_get_width(coords); -// } else { -// /*If EXAPND is enabled then not limit the text's width to the object's width*/ -// lv_point_t p; -// lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, -// flag); -// w = p.x; -// } -// -// lv_coord_t line_height = lv_font_get_line_height(font) + style->text.line_space; -// -// /*Init variables for the first line*/ -// lv_coord_t line_width = 0; -// lv_point_t pos; -// pos.x = coords->x1; -// pos.y = coords->y1; -// -// lv_coord_t x_ofs = 0; -// lv_coord_t y_ofs = 0; -// if(offset != NULL) { -// x_ofs = offset->x; -// y_ofs = offset->y; -// pos.y += y_ofs; -// } -// -// uint32_t line_start = 0; -// int32_t last_line_start = -1; -// -// /*Check the hint to use the cached info*/ -// if(hint && y_ofs == 0 && coords->y1 < 0) { -// /*If the label changed too much recalculate the hint.*/ -// if(LV_MATH_ABS(hint->coord_y - coords->y1) > LV_LABEL_HINT_UPDATE_TH - 2 * line_height) { -// hint->line_start = -1; -// } -// last_line_start = hint->line_start; -// } -// -// /*Use the hint if it's valid*/ -// if(hint && last_line_start >= 0) { -// line_start = last_line_start; -// pos.y += hint->y; -// } -// -// -// uint32_t line_end = line_start + lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); -// -// /*Go the first visible line*/ -// while(pos.y + line_height < mask->y1) { -// /*Go to next line*/ -// line_start = line_end; -// line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); -// pos.y += line_height; -// -// /*Save at the threshold coordinate*/ -// if(hint && pos.y >= -LV_LABEL_HINT_UPDATE_TH && hint->line_start < 0) { -// hint->line_start = line_start; -// hint->y = pos.y - coords->y1; -// hint->coord_y = coords->y1; -// } -// -// if(txt[line_start] == '\0') return; -// } -// -// /*Align to middle*/ -// if(flag & LV_TXT_FLAG_CENTER) { -// line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, style->text.letter_space, flag); -// -// pos.x += (lv_area_get_width(coords) - line_width) / 2; -// -// } -// /*Align to the right*/ -// else if(flag & LV_TXT_FLAG_RIGHT) { -// line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, style->text.letter_space, flag); -// pos.x += lv_area_get_width(coords) - line_width; -// } -// -// lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->text.opa : (uint16_t)((uint16_t)style->text.opa * opa_scale) >> 8; -// -// uint16_t sel_start = 0xFFFF; -// uint16_t sel_end = 0xFFFF; -// if(sel) { -// sel_start = sel->start; -// sel_end = sel->end; -// if(sel_start > sel_end) { -// uint16_t tmp = sel_start; -// sel_start = sel_end; -// sel_end = tmp; -// } -// } -// +/** + * @file lv_draw_label.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_label.h" +#include "../lv_misc/lv_math.h" +#include "../lv_hal/lv_hal_disp.h" +#include "../lv_core/lv_refr.h" +#include "../lv_misc/lv_bidi.h" + +/********************* + * DEFINES + *********************/ +#define LABEL_RECOLOR_PAR_LENGTH 6 +#define LV_LABEL_HINT_UPDATE_TH 1024 /*Update the "hint" if the label's y coordinates have changed more then this*/ + +/********************** + * TYPEDEFS + **********************/ +enum { + CMD_STATE_WAIT, + CMD_STATE_PAR, + CMD_STATE_IN, +}; +typedef uint8_t cmd_state_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); +static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, const uint8_t * map_p, lv_color_t color, lv_opa_t opa); +static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, const uint8_t * map_p, lv_color_t color, lv_opa_t opa); + + +static uint8_t hex_char_to_num(char hex); + +/********************** + * STATIC VARIABLES + **********************/ +/*clang-format off*/ +static const uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ +static const uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ +static const uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, + 136, 153, 170, 187, + 204, 221, 238, 255}; + /*clang-format on*/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc) +{ + memset(dsc, 0x00, sizeof(lv_draw_label_dsc_t)); + dsc->opa = LV_OPA_COVER; + dsc->color = LV_COLOR_RED; + dsc->font = LV_FONT_DEFAULT; + dsc->sel_start = LV_DRAW_LABEL_NO_TXT_SEL; + dsc->sel_end = LV_DRAW_LABEL_NO_TXT_SEL; + dsc->sel_color = LV_COLOR_BLUE; + dsc->bidi_dir = LV_BIDI_DIR_LTR; +} + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + * @param txt 0 terminated text to write + * @paramdsc->flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * @param sel make the text selected in the range by drawing a background there + */ +void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, lv_draw_label_dsc_t * dsc, + const char * txt, lv_opa_t opa_scale, lv_draw_label_hint_t * hint) +{ + const lv_font_t * font = dsc->font; + lv_coord_t w; + + /*No need to waste processor time if string is empty*/ + if (txt[0] == '\0') return; + + if((dsc->flag & LV_TXT_FLAG_EXPAND) == 0) { + /*Normally use the label's width as width*/ + w = lv_area_get_width(coords); + } else { + /*If EXAPND is enabled then not limit the text's width to the object's width*/ + lv_point_t p; + lv_txt_get_size(&p, txt, dsc->font, dsc->letter_space, dsc->line_space, LV_COORD_MAX, + dsc->flag); + w = p.x; + } + + lv_coord_t line_height = lv_font_get_line_height(font) + dsc->line_space; + + /*Init variables for the first line*/ + lv_coord_t line_width = 0; + lv_point_t pos; + pos.x = coords->x1; + pos.y = coords->y1; + + lv_coord_t x_ofs = 0; + lv_coord_t y_ofs = 0; + x_ofs = dsc->ofs_x; + y_ofs = dsc->ofs_y; + pos.y += y_ofs; + + uint32_t line_start = 0; + int32_t last_line_start = -1; + + /*Check the hint to use the cached info*/ + if(hint && y_ofs == 0 && coords->y1 < 0) { + /*If the label changed too much recalculate the hint.*/ + if(LV_MATH_ABS(hint->coord_y - coords->y1) > LV_LABEL_HINT_UPDATE_TH - 2 * line_height) { + hint->line_start = -1; + } + last_line_start = hint->line_start; + } + + /*Use the hint if it's valid*/ + if(hint && last_line_start >= 0) { + line_start = last_line_start; + pos.y += hint->y; + } + + + uint32_t line_end = line_start + lv_txt_get_next_line(&txt[line_start], font, dsc->letter_space, w, dsc->flag); + + /*Go the first visible line*/ + while(pos.y + line_height < mask->y1) { + /*Go to next line*/ + line_start = line_end; + line_end += lv_txt_get_next_line(&txt[line_start], font, dsc->letter_space, w, dsc->flag); + pos.y += line_height; + + /*Save at the threshold coordinate*/ + if(hint && pos.y >= -LV_LABEL_HINT_UPDATE_TH && hint->line_start < 0) { + hint->line_start = line_start; + hint->y = pos.y - coords->y1; + hint->coord_y = coords->y1; + } + + if(txt[line_start] == '\0') return; + } + + /*Align to middle*/ + if(dsc->flag & LV_TXT_FLAG_CENTER) { + line_width = lv_txt_get_width(&txt[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(dsc->flag & LV_TXT_FLAG_RIGHT) { + line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); + pos.x += lv_area_get_width(coords) - line_width; + } + + lv_opa_t opa = opa_scale == LV_OPA_COVER ? dsc->opa : (uint16_t)((uint16_t)dsc->opa * opa_scale) >> 8; + + uint16_t sel_start = dsc->sel_start; + uint16_t sel_end = dsc->sel_end; + if(sel_start > sel_end) { + uint16_t tmp = sel_start; + sel_start = sel_end; + sel_end = tmp; + } + // lv_style_t line_style; -// if(style->text.underline || style->text.strikethrough) { +// if(dsc->underline || dsc->strikethrough) { // lv_style_copy(&line_style, style); -// line_style.line.color = style->text.color; -// line_style.line.width = (style->text.font->line_height + 5) / 10; /*+5 for rounding*/ -// line_style.line.opa = style->text.opa; -// line_style.line.blend_mode = style->text.blend_mode; +// line_style.line.color = dsc->color; +// line_style.line.width = (dsc->font->line_height + 5) / 10; /*+5 for rounding*/ +// line_style.line.opa = dsc->opa; +// line_style.line.blend_mode = dsc->blend_mode; // } -// -// cmd_state_t cmd_state = CMD_STATE_WAIT; -// uint32_t i; -// uint16_t par_start = 0; -// lv_color_t recolor; -// lv_coord_t letter_w; + + cmd_state_t cmd_state = CMD_STATE_WAIT; + uint32_t i; + uint16_t par_start = 0; + lv_color_t recolor; + lv_coord_t letter_w; + // lv_style_t sel_style; // lv_style_copy(&sel_style, &lv_style_plain_color); -// sel_style.body.main_color = sel_style.body.grad_color = style->text.sel_color; -// lv_coord_t pos_x_start = pos.x; -// /*Write out all lines*/ -// while(txt[line_start] != '\0') { -// if(offset != NULL) pos.x += x_ofs; -// -// /*Write all letter of a line*/ -// cmd_state = CMD_STATE_WAIT; -// i = 0; -// uint32_t letter; -// uint32_t letter_next; -//#if LV_USE_BIDI -// char *bidi_txt = lv_mem_buf_get(line_end - line_start + 1); -// lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, bidi_dir, NULL, 0); -//#else -// const char *bidi_txt = txt + line_start; -//#endif -// -// while(i < line_end - line_start) { -// uint16_t logical_char_pos = 0; -// if(sel_start != 0xFFFF && sel_end != 0xFFFF) { -//#if LV_USE_BIDI -// logical_char_pos = lv_txt_encoded_get_char_id(txt, line_start); -// uint16_t t = lv_txt_encoded_get_char_id(bidi_txt, i); -// logical_char_pos += lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, bidi_dir, t, NULL); -//#else -// logical_char_pos = lv_txt_encoded_get_char_id(txt, line_start + i); -//#endif -// } -// -// letter = lv_txt_encoded_next(bidi_txt, &i); -// letter_next = lv_txt_encoded_next(&bidi_txt[i], NULL); -// -// -// /*Handle the re-color command*/ -// if((flag & LV_TXT_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]; -// 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.full = style->text.color.full; -// } -// cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/ -// } -// continue; -// } -// } -// -// lv_color_t color = style->text.color; -// -// if(cmd_state == CMD_STATE_IN) color = recolor; -// -// letter_w = lv_font_get_glyph_width(font, letter, letter_next); -// +// sel_style.body.main_color = sel_style.body.grad_color = dsc->sel_color; + + lv_coord_t pos_x_start = pos.x; + /*Write out all lines*/ + while(txt[line_start] != '\0') { + pos.x += x_ofs; + + /*Write all letter of a line*/ + cmd_state = CMD_STATE_WAIT; + i = 0; + uint32_t letter; + uint32_t letter_next; +#if LV_USE_BIDI + char *bidi_txt = lv_mem_buf_get(line_end - line_start + 1); + lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, dsc->bidi_dir, NULL, 0); +#else + const char *bidi_txt = txt + line_start; +#endif + + while(i < line_end - line_start) { + uint16_t logical_char_pos = 0; + if(sel_start != 0xFFFF && sel_end != 0xFFFF) { +#if LV_USE_BIDI + logical_char_pos = lv_txt_encoded_get_char_id(txt, line_start); + uint16_t t = lv_txt_encoded_get_char_id(bidi_txt, i); + logical_char_pos += lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, dsc->bidi_dir, t, NULL); +#else + logical_char_pos = lv_txt_encoded_get_char_id(txt, line_start + i); +#endif + } + + letter = lv_txt_encoded_next(bidi_txt, &i); + letter_next = lv_txt_encoded_next(&bidi_txt[i], NULL); + + + /*Handle the re-color command*/ + if((dsc->flag & LV_TXT_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]; + 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.full = dsc->color.full; + } + cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/ + } + continue; + } + } + + lv_color_t color = dsc->color; + + if(cmd_state == CMD_STATE_IN) color = recolor; + + letter_w = lv_font_get_glyph_width(font, letter, letter_next); + // if(sel_start != 0xFFFF && sel_end != 0xFFFF) { // if(logical_char_pos >= sel_start && logical_char_pos < sel_end) { // lv_area_t sel_coords; // sel_coords.x1 = pos.x; // sel_coords.y1 = pos.y; -// sel_coords.x2 = pos.x + letter_w + style->text.letter_space - 1; +// sel_coords.x2 = pos.x + letter_w + dsc->letter_space - 1; // sel_coords.y2 = pos.y + line_height - 1; // lv_draw_rect(&sel_coords, mask, &sel_style, opa); // } // } -// -// lv_draw_letter(&pos, mask, font, letter, color, opa); -// -// if(letter_w > 0) { -// pos.x += letter_w + style->text.letter_space; -// } -// } -// -// if(style->text.strikethrough) { + + lv_draw_letter(&pos, mask, font, letter, color, opa); + + if(letter_w > 0) { + pos.x += letter_w + dsc->letter_space; + } + } + +// if(dsc->strikethrough) { // lv_point_t p1; // lv_point_t p2; // p1.x = pos_x_start; -// p1.y = pos.y + (style->text.font->line_height / 2) + style->line.width / 2; +// p1.y = pos.y + (dsc->font->line_height / 2) + style->line.width / 2; // p2.x = pos.x; // p2.y = p1.y; // lv_draw_line(&p1, &p2, mask, &line_style, opa_scale); // } // -// if(style->text.underline) { +// if(dsc->underline) { // lv_point_t p1; // lv_point_t p2; // p1.x = pos_x_start; -// p1.y = pos.y + style->text.font->line_height - style->text.font->base_line + style->line.width / 2 + 1; +// p1.y = pos.y + dsc->font->line_height - dsc->font->base_line + style->line.width / 2 + 1; // p2.x = pos.x; // p2.y = p1.y; // lv_draw_line(&p1, &p2, mask, &line_style, opa_scale); // } -// -//#if LV_USE_BIDI -// lv_mem_buf_release(bidi_txt); -// bidi_txt = NULL; -//#endif -// /*Go to next line*/ -// line_start = line_end; -// line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); -// -// pos.x = coords->x1; -// /*Align to middle*/ -// if(flag & LV_TXT_FLAG_CENTER) { -// line_width = -// lv_txt_get_width(&txt[line_start], line_end - line_start, font, style->text.letter_space, flag); -// -// pos.x += (lv_area_get_width(coords) - line_width) / 2; -// -// } -// /*Align to the right*/ -// else if(flag & LV_TXT_FLAG_RIGHT) { -// line_width = -// lv_txt_get_width(&txt[line_start], line_end - line_start, font, style->text.letter_space, flag); -// pos.x += lv_area_get_width(coords) - line_width; -// } -// -// /*Go the next line position*/ -// pos.y += line_height; -// -// if(pos.y > mask->y2) return; -// } -//} -// -///********************** -// * STATIC FUNCTIONS -// **********************/ -// -// -///** -// * Draw a letter in the Virtual Display Buffer -// * @param pos_p left-top coordinate of the latter -// * @param mask_p the letter will be drawn only on this area (truncated to VDB area) -// * @param font_p pointer to font -// * @param letter a letter to draw -// * @param color color of letter -// * @param opa opacity of letter (0..255) -// */ -//static void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, const lv_font_t * font_p, uint32_t letter, -// lv_color_t color, lv_opa_t opa) -//{ -// if(opa < LV_OPA_MIN) return; -// if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; -// -// if(font_p == NULL) { -// LV_LOG_WARN("lv_draw_letter: font is NULL"); -// return; -// } -// -// lv_font_glyph_dsc_t g; -// bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter, '\0'); -// if(g_ret == false) { -// /* Add waring if the dsc is not found -// * but do not print warning for non printable ASCII chars (e.g. '\n')*/ -// if(letter >= 0x20) { -// LV_LOG_WARN("lv_draw_letter: glyph dsc. not found"); -// } -// return; -// } -// -// lv_coord_t pos_x = pos_p->x + g.ofs_x; -// lv_coord_t pos_y = pos_p->y + (font_p->line_height - font_p->base_line) - g.box_h - g.ofs_y; -// -// /*If the letter is completely out of mask don't draw it */ -// if(pos_x + g.box_w < clip_area->x1 || -// pos_x > clip_area->x2 || -// pos_y + g.box_h < clip_area->y1 || -// pos_y > clip_area->y2) return; -// -// -// const uint8_t * map_p = lv_font_get_glyph_bitmap(font_p, letter); -// if(map_p == NULL) { -// LV_LOG_WARN("lv_draw_letter: character's bitmap not found"); -// return; -// } -// -// if(font_p->subpx) { -// draw_letter_subpx(pos_x, pos_y, &g, clip_area, map_p, color, opa); -// } else { -// draw_letter_normal(pos_x, pos_y, &g, clip_area, map_p, color, opa); -// } -//} -// -// -//static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, const uint8_t * map_p, lv_color_t color, lv_opa_t opa) -//{ -// -// const uint8_t * bpp_opa_table; -// uint8_t bitmask_init; -// uint8_t bitmask; -// -// if(g->bpp == 3) g->bpp = 4; -// -// switch(g->bpp) { -// case 1: -// bpp_opa_table = bpp1_opa_table; -// bitmask_init = 0x80; -// break; -// case 2: -// bpp_opa_table = bpp2_opa_table; -// bitmask_init = 0xC0; -// break; -// case 4: -// bpp_opa_table = bpp4_opa_table; -// bitmask_init = 0xF0; -// break; -// case 8: -// bpp_opa_table = NULL; -// bitmask_init = 0xFF; -// break; /*No opa table, pixel value will be used directly*/ -// default: -// LV_LOG_WARN("lv_draw_letter: invalid bpp not found"); -// return; /*Invalid bpp. Can't render the letter*/ -// } -// -// -// -// lv_coord_t col, row; -// -// uint8_t width_byte_scr = g->box_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ -// if(g->box_w & 0x7) width_byte_scr++; -// uint16_t width_bit = g->box_w * g->bpp; /*Letter width in bits*/ -// -// -// /* Calculate the col/row start/end on the map*/ -// lv_coord_t col_start = pos_x >= clip_area->x1 ? 0 : clip_area->x1 - pos_x; -// lv_coord_t col_end = pos_x + g->box_w <= clip_area->x2 ? g->box_w : clip_area->x2 - pos_x + 1; -// lv_coord_t row_start = pos_y >= clip_area->y1 ? 0 : clip_area->y1 - pos_y; -// lv_coord_t row_end = pos_y + g->box_h <= clip_area->y2 ? g->box_h : clip_area->y2 - pos_y + 1; -// -// /*Move on the map too*/ -// uint32_t bit_ofs = (row_start * width_bit) + (col_start * g->bpp); -// map_p += bit_ofs >> 3; -// -// uint8_t letter_px; -// lv_opa_t px_opa; -// uint16_t col_bit; -// col_bit = bit_ofs & 0x7; /* "& 0x7" equals to "% 8" just faster */ -// -// uint32_t mask_buf_size = g->box_w * g->box_h > LV_HOR_RES_MAX ? g->box_w * g->box_h : LV_HOR_RES_MAX; -// lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); -// lv_coord_t mask_p = 0; -// lv_coord_t mask_p_start; -// -// lv_area_t fill_area; -// fill_area.x1 = col_start + pos_x; -// fill_area.x2 = col_end + pos_x - 1; -// fill_area.y1 = row_start + pos_y; -// fill_area.y2 = fill_area.y1; -// -// uint8_t other_mask_cnt = lv_draw_mask_get_cnt(); -// -// for(row = row_start ; row < row_end; row++) { -// bitmask = bitmask_init >> col_bit; -// mask_p_start = mask_p; -// for(col = col_start; col < col_end; col++) { -// -// /*Load the pixel's opacity into the mask*/ -// letter_px = (*map_p & bitmask) >> (8 - col_bit - g->bpp); -// if(letter_px != 0) { -// if(opa == LV_OPA_COVER) { -// px_opa = g->bpp == 8 ? letter_px : bpp_opa_table[letter_px]; -// } else { -// px_opa = g->bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8 -// : (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8; -// } -// -// mask_buf[mask_p] = px_opa; -// -// } else { -// mask_buf[mask_p] = 0; -// } -// -// /*Go to the next column*/ -// if(col_bit < 8 - g->bpp) { -// col_bit += g->bpp; -// bitmask = bitmask >> g->bpp; -// } else { -// col_bit = 0; -// bitmask = bitmask_init; -// map_p++; -// } -// -// /*Next mask byte*/ -// mask_p++; -// } -// -// /*Apply masks if any*/ -// if(other_mask_cnt) { -// lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, fill_area.x1, fill_area.y2, lv_area_get_width(&fill_area)); -// if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) { -// memset(mask_buf + mask_p_start, 0x00, lv_area_get_width(&fill_area)); -// } -// } -// -// if((uint32_t) mask_p + (row_end - row_start) < mask_buf_size) { -// fill_area.y2 ++; -// } else { -// lv_blend_fill(clip_area, &fill_area, -// color, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, -// LV_BLEND_MODE_NORMAL); -// -// fill_area.y1 = fill_area.y2 + 1; -// fill_area.y2 = fill_area.y1; -// mask_p = 0; -// } -// -// col_bit += ((g->box_w - col_end) + col_start) * g->bpp; -// -// map_p += (col_bit >> 3); -// col_bit = col_bit & 0x7; -// } -// -// /*Flush the last part*/ -// if(fill_area.y1 != fill_area.y2) { -// fill_area.y2--; -// lv_blend_fill(clip_area, &fill_area, -// color, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, -// LV_BLEND_MODE_NORMAL); -// mask_p = 0; -// } -// -// lv_mem_buf_release(mask_buf); -//} -// -//static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, const uint8_t * map_p, lv_color_t color, lv_opa_t opa) -//{ -// const uint8_t * bpp_opa_table; -// uint8_t bitmask_init; -// uint8_t bitmask; -// -// if(g->bpp == 3) g->bpp = 4; -// -// switch(g->bpp) { -// case 1: -// bpp_opa_table = bpp1_opa_table; -// bitmask_init = 0x80; -// break; -// case 2: -// bpp_opa_table = bpp2_opa_table; -// bitmask_init = 0xC0; -// break; -// case 4: -// bpp_opa_table = bpp4_opa_table; -// bitmask_init = 0xF0; -// break; -// case 8: -// bpp_opa_table = NULL; -// bitmask_init = 0xFF; -// break; /*No opa table, pixel value will be used directly*/ -// default: -// LV_LOG_WARN("lv_draw_letter: invalid bpp not found"); -// return; /*Invalid bpp. Can't render the letter*/ -// } -// -// lv_coord_t col, row; -// -// uint8_t width_byte_scr = g->box_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ -// if(g->box_w & 0x7) width_byte_scr++; -// uint16_t width_bit = g->box_w * g->bpp; /*Letter width in bits*/ -// -// -// /* Calculate the col/row start/end on the map*/ -// lv_coord_t col_start = pos_x >= clip_area->x1 ? 0 : (clip_area->x1 - pos_x) * 3; -// lv_coord_t col_end = pos_x + g->box_w / 3 <= clip_area->x2 ? g->box_w : (clip_area->x2 - pos_x + 1) * 3; -// lv_coord_t row_start = pos_y >= clip_area->y1 ? 0 : clip_area->y1 - pos_y; -// lv_coord_t row_end = pos_y + g->box_h <= clip_area->y2 ? g->box_h : clip_area->y2 - pos_y + 1; -// -// /*Move on the map too*/ -// uint32_t bit_ofs = (row_start * width_bit) + (col_start * g->bpp); -// map_p += bit_ofs >> 3; -// -// uint8_t letter_px; -// lv_opa_t px_opa; -// uint16_t col_bit; -// col_bit = bit_ofs & 0x7; /* "& 0x7" equals to "% 8" just faster */ -// -// uint32_t mask_buf_size = g->box_w * g->box_h > LV_HOR_RES_MAX ? g->box_w * g->box_h : LV_HOR_RES_MAX; -// lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); -// lv_coord_t mask_p = 0; -// lv_coord_t mask_p_start; -// lv_color_t * color_buf = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t)); -// -// lv_disp_t * disp = lv_refr_get_disp_refreshing(); -// lv_disp_buf_t * vdb = lv_disp_get_buf(disp); -// -// lv_coord_t vdb_width = lv_area_get_width(&vdb->area); -// lv_color_t * vdb_buf_tmp = vdb->buf_act; -// -// /*Set a pointer on VDB to the first pixel of the letter*/ -// vdb_buf_tmp += ((pos_y - vdb->area.y1) * vdb_width) + pos_x - vdb->area.x1; -// -// /*If the letter is partially out of mask the move there on VDB*/ -// vdb_buf_tmp += (row_start * vdb_width) + col_start / 3; -// -// lv_area_t map_area; -// map_area.x1 = col_start / 3 + pos_x; -// map_area.x2 = col_end / 3 + pos_x - 1; -// map_area.y1 = row_start + pos_y; -// map_area.y2 = map_area.y1; -// -// uint8_t other_mask_cnt = lv_draw_mask_get_cnt(); -// -// uint8_t font_rgb[3]; -// -//#if LV_COLOR_16_SWAP == 0 -// uint8_t txt_rgb[3] = {color.ch.red, color.ch.green, color.ch.blue}; -//#else -// uint8_t txt_rgb[3] = {color.ch.red, (color.ch.green_h << 3) + color.ch.green_l, color.ch.blue}; -//#endif -// -// for(row = row_start ; row < row_end; row++) { -// uint8_t subpx_cnt = 0; -// bitmask = bitmask_init >> col_bit; -// mask_p_start = mask_p; -// for(col = col_start; col < col_end; col++) { -// /*Load the pixel's opacity into the mask*/ -// letter_px = (*map_p & bitmask) >> (8 - col_bit - g->bpp); -// if(letter_px != 0) { -// if(opa == LV_OPA_COVER) { -// px_opa = g->bpp == 8 ? letter_px : bpp_opa_table[letter_px]; -// } else { -// px_opa = g->bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8 -// : (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8; -// } -// } else { -// px_opa = 0; -// } -// -// font_rgb[subpx_cnt] = px_opa; -// -// subpx_cnt ++; -// if(subpx_cnt == 3) { -// subpx_cnt = 0; -// -// lv_color_t res_color; -//#if LV_COLOR_16_SWAP == 0 -// uint8_t bg_rgb[3] = {vdb_buf_tmp->ch.red, vdb_buf_tmp->ch.green, vdb_buf_tmp->ch.blue}; -//#else -// uint8_t bg_rgb[3] = {vdb_buf_tmp->ch.red, -// (vdb_buf_tmp->ch.green_h << 3) + vdb_buf_tmp->ch.green_l, -// vdb_buf_tmp->ch.blue}; -//#endif -// -//#if LV_SUBPX_BGR -// res_color.ch.blue = (uint16_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8; -// res_color.ch.red = (uint16_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8; -//#else -// res_color.ch.red = (uint16_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8; -// res_color.ch.blue = (uint16_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8; -//#endif -// -//#if LV_COLOR_16_SWAP == 0 -// res_color.ch.green = (uint16_t)((uint16_t)txt_rgb[1] * font_rgb[1] + (bg_rgb[1] * (255 - font_rgb[1]))) >> 8; -//#else -// uint8_t green = (uint16_t)((uint16_t)txt_rgb[1] * font_rgb[1] + (bg_rgb[1] * (255 - font_rgb[1]))) >> 8; -// res_color.ch.green_h = green >> 3; -// res_color.ch.green_l = green & 0x7; -//#endif -// -// if(font_rgb[0] == 0 && font_rgb[1] == 0 && font_rgb[2] == 0) mask_buf[mask_p] = LV_OPA_TRANSP; -// else mask_buf[mask_p] = LV_OPA_COVER; -// color_buf[mask_p] = res_color; -// -// /*Next mask byte*/ -// mask_p++; -// vdb_buf_tmp++; -// } -// -// /*Go to the next column*/ -// if(col_bit < 8 - g->bpp) { -// col_bit += g->bpp; -// bitmask = bitmask >> g->bpp; -// } else { -// col_bit = 0; -// bitmask = bitmask_init; -// map_p++; -// } -// } -// -// /*Apply masks if any*/ -// if(other_mask_cnt) { -// lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, map_area.x1, map_area.y2, lv_area_get_width(&map_area)); -// if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) { -// memset(mask_buf + mask_p_start, 0x00, lv_area_get_width(&map_area)); -// } -// } -// -// if((uint32_t) mask_p + (row_end - row_start) < mask_buf_size) { -// map_area.y2 ++; -// } else { -// lv_blend_map(clip_area, &map_area, color_buf, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, LV_BLEND_MODE_NORMAL); -// -// map_area.y1 = map_area.y2 + 1; -// map_area.y2 = map_area.y1; -// mask_p = 0; -// } -// -// col_bit += ((g->box_w - col_end) + col_start) * g->bpp; -// -// map_p += (col_bit >> 3); -// col_bit = col_bit & 0x7; -// -// /*Next row in VDB*/ -// vdb_buf_tmp += vdb_width - (col_end - col_start) / 3; -// } -// -// /*Flush the last part*/ -// if(map_area.y1 != map_area.y2) { -// map_area.y2--; -// lv_blend_map(clip_area, &map_area, color_buf, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, LV_BLEND_MODE_NORMAL); -// } -// -// lv_mem_buf_release(mask_buf); -// lv_mem_buf_release(color_buf); -//} -// -// -///** -// * 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) -//{ -// uint8_t result = 0; -// -// if(hex >= '0' && hex <= '9') { -// result = hex - '0'; -// } else { -// if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/ -// -// switch(hex) { -// case 'A': result = 10; break; -// case 'B': result = 11; break; -// case 'C': result = 12; break; -// case 'D': result = 13; break; -// case 'E': result = 14; break; -// case 'F': result = 15; break; -// default: result = 0; break; -// } -// } -// -// return result; -//} + +#if LV_USE_BIDI + lv_mem_buf_release(bidi_txt); + bidi_txt = NULL; +#endif + /*Go to next line*/ + line_start = line_end; + line_end += lv_txt_get_next_line(&txt[line_start], font, dsc->letter_space, w, dsc->flag); + + pos.x = coords->x1; + /*Align to middle*/ + if(dsc->flag & LV_TXT_FLAG_CENTER) { + line_width = + lv_txt_get_width(&txt[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(dsc->flag & LV_TXT_FLAG_RIGHT) { + line_width = + lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); + pos.x += lv_area_get_width(coords) - line_width; + } + + /*Go the next line position*/ + pos.y += line_height; + + if(pos.y > mask->y2) return; + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + +/** + * Draw a letter in the Virtual Display Buffer + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area (truncated to VDB area) + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (0..255) + */ +static void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa) +{ + if(opa < LV_OPA_MIN) return; + if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; + + if(font_p == NULL) { + LV_LOG_WARN("lv_draw_letter: font is NULL"); + return; + } + + lv_font_glyph_dsc_t g; + bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter, '\0'); + if(g_ret == false) { + /* Add waring if the dsc is not found + * but do not print warning for non printable ASCII chars (e.g. '\n')*/ + if(letter >= 0x20) { + LV_LOG_WARN("lv_draw_letter: glyph dsc. not found"); + } + return; + } + + lv_coord_t pos_x = pos_p->x + g.ofs_x; + lv_coord_t pos_y = pos_p->y + (font_p->line_height - font_p->base_line) - g.box_h - g.ofs_y; + + /*If the letter is completely out of mask don't draw it */ + if(pos_x + g.box_w < clip_area->x1 || + pos_x > clip_area->x2 || + pos_y + g.box_h < clip_area->y1 || + pos_y > clip_area->y2) return; + + + const uint8_t * map_p = lv_font_get_glyph_bitmap(font_p, letter); + if(map_p == NULL) { + LV_LOG_WARN("lv_draw_letter: character's bitmap not found"); + return; + } + + if(font_p->subpx) { + draw_letter_subpx(pos_x, pos_y, &g, clip_area, map_p, color, opa); + } else { + draw_letter_normal(pos_x, pos_y, &g, clip_area, map_p, color, opa); + } +} + + +static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, const uint8_t * map_p, lv_color_t color, lv_opa_t opa) +{ + + const uint8_t * bpp_opa_table; + uint8_t bitmask_init; + uint8_t bitmask; + + if(g->bpp == 3) g->bpp = 4; + + switch(g->bpp) { + case 1: + bpp_opa_table = bpp1_opa_table; + bitmask_init = 0x80; + break; + case 2: + bpp_opa_table = bpp2_opa_table; + bitmask_init = 0xC0; + break; + case 4: + bpp_opa_table = bpp4_opa_table; + bitmask_init = 0xF0; + break; + case 8: + bpp_opa_table = NULL; + bitmask_init = 0xFF; + break; /*No opa table, pixel value will be used directly*/ + default: + LV_LOG_WARN("lv_draw_letter: invalid bpp not found"); + return; /*Invalid bpp. Can't render the letter*/ + } + + + + lv_coord_t col, row; + + uint8_t width_byte_scr = g->box_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ + if(g->box_w & 0x7) width_byte_scr++; + uint16_t width_bit = g->box_w * g->bpp; /*Letter width in bits*/ + + + /* Calculate the col/row start/end on the map*/ + lv_coord_t col_start = pos_x >= clip_area->x1 ? 0 : clip_area->x1 - pos_x; + lv_coord_t col_end = pos_x + g->box_w <= clip_area->x2 ? g->box_w : clip_area->x2 - pos_x + 1; + lv_coord_t row_start = pos_y >= clip_area->y1 ? 0 : clip_area->y1 - pos_y; + lv_coord_t row_end = pos_y + g->box_h <= clip_area->y2 ? g->box_h : clip_area->y2 - pos_y + 1; + + /*Move on the map too*/ + uint32_t bit_ofs = (row_start * width_bit) + (col_start * g->bpp); + map_p += bit_ofs >> 3; + + uint8_t letter_px; + lv_opa_t px_opa; + uint16_t col_bit; + col_bit = bit_ofs & 0x7; /* "& 0x7" equals to "% 8" just faster */ + + uint32_t mask_buf_size = g->box_w * g->box_h > LV_HOR_RES_MAX ? g->box_w * g->box_h : LV_HOR_RES_MAX; + lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); + lv_coord_t mask_p = 0; + lv_coord_t mask_p_start; + + lv_area_t fill_area; + fill_area.x1 = col_start + pos_x; + fill_area.x2 = col_end + pos_x - 1; + fill_area.y1 = row_start + pos_y; + fill_area.y2 = fill_area.y1; + + uint8_t other_mask_cnt = lv_draw_mask_get_cnt(); + + for(row = row_start ; row < row_end; row++) { + bitmask = bitmask_init >> col_bit; + mask_p_start = mask_p; + for(col = col_start; col < col_end; col++) { + + /*Load the pixel's opacity into the mask*/ + letter_px = (*map_p & bitmask) >> (8 - col_bit - g->bpp); + if(letter_px != 0) { + if(opa == LV_OPA_COVER) { + px_opa = g->bpp == 8 ? letter_px : bpp_opa_table[letter_px]; + } else { + px_opa = g->bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8 + : (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8; + } + + mask_buf[mask_p] = px_opa; + + } else { + mask_buf[mask_p] = 0; + } + + /*Go to the next column*/ + if(col_bit < 8 - g->bpp) { + col_bit += g->bpp; + bitmask = bitmask >> g->bpp; + } else { + col_bit = 0; + bitmask = bitmask_init; + map_p++; + } + + /*Next mask byte*/ + mask_p++; + } + + /*Apply masks if any*/ + if(other_mask_cnt) { + lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, fill_area.x1, fill_area.y2, lv_area_get_width(&fill_area)); + if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) { + memset(mask_buf + mask_p_start, 0x00, lv_area_get_width(&fill_area)); + } + } + + if((uint32_t) mask_p + (row_end - row_start) < mask_buf_size) { + fill_area.y2 ++; + } else { + lv_blend_fill(clip_area, &fill_area, + color, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, + LV_BLEND_MODE_NORMAL); + + fill_area.y1 = fill_area.y2 + 1; + fill_area.y2 = fill_area.y1; + mask_p = 0; + } + + col_bit += ((g->box_w - col_end) + col_start) * g->bpp; + + map_p += (col_bit >> 3); + col_bit = col_bit & 0x7; + } + + /*Flush the last part*/ + if(fill_area.y1 != fill_area.y2) { + fill_area.y2--; + lv_blend_fill(clip_area, &fill_area, + color, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, + LV_BLEND_MODE_NORMAL); + mask_p = 0; + } + + lv_mem_buf_release(mask_buf); +} + +static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, const uint8_t * map_p, lv_color_t color, lv_opa_t opa) +{ + const uint8_t * bpp_opa_table; + uint8_t bitmask_init; + uint8_t bitmask; + + if(g->bpp == 3) g->bpp = 4; + + switch(g->bpp) { + case 1: + bpp_opa_table = bpp1_opa_table; + bitmask_init = 0x80; + break; + case 2: + bpp_opa_table = bpp2_opa_table; + bitmask_init = 0xC0; + break; + case 4: + bpp_opa_table = bpp4_opa_table; + bitmask_init = 0xF0; + break; + case 8: + bpp_opa_table = NULL; + bitmask_init = 0xFF; + break; /*No opa table, pixel value will be used directly*/ + default: + LV_LOG_WARN("lv_draw_letter: invalid bpp not found"); + return; /*Invalid bpp. Can't render the letter*/ + } + + lv_coord_t col, row; + + uint8_t width_byte_scr = g->box_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ + if(g->box_w & 0x7) width_byte_scr++; + uint16_t width_bit = g->box_w * g->bpp; /*Letter width in bits*/ + + + /* Calculate the col/row start/end on the map*/ + lv_coord_t col_start = pos_x >= clip_area->x1 ? 0 : (clip_area->x1 - pos_x) * 3; + lv_coord_t col_end = pos_x + g->box_w / 3 <= clip_area->x2 ? g->box_w : (clip_area->x2 - pos_x + 1) * 3; + lv_coord_t row_start = pos_y >= clip_area->y1 ? 0 : clip_area->y1 - pos_y; + lv_coord_t row_end = pos_y + g->box_h <= clip_area->y2 ? g->box_h : clip_area->y2 - pos_y + 1; + + /*Move on the map too*/ + uint32_t bit_ofs = (row_start * width_bit) + (col_start * g->bpp); + map_p += bit_ofs >> 3; + + uint8_t letter_px; + lv_opa_t px_opa; + uint16_t col_bit; + col_bit = bit_ofs & 0x7; /* "& 0x7" equals to "% 8" just faster */ + + uint32_t mask_buf_size = g->box_w * g->box_h > LV_HOR_RES_MAX ? g->box_w * g->box_h : LV_HOR_RES_MAX; + lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); + lv_coord_t mask_p = 0; + lv_coord_t mask_p_start; + lv_color_t * color_buf = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t)); + + lv_disp_t * disp = lv_refr_get_disp_refreshing(); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp); + + lv_coord_t vdb_width = lv_area_get_width(&vdb->area); + lv_color_t * vdb_buf_tmp = vdb->buf_act; + + /*Set a pointer on VDB to the first pixel of the letter*/ + vdb_buf_tmp += ((pos_y - vdb->area.y1) * vdb_width) + pos_x - vdb->area.x1; + + /*If the letter is partially out of mask the move there on VDB*/ + vdb_buf_tmp += (row_start * vdb_width) + col_start / 3; + + lv_area_t map_area; + map_area.x1 = col_start / 3 + pos_x; + map_area.x2 = col_end / 3 + pos_x - 1; + map_area.y1 = row_start + pos_y; + map_area.y2 = map_area.y1; + + uint8_t other_mask_cnt = lv_draw_mask_get_cnt(); + + uint8_t font_rgb[3]; + +#if LV_COLOR_16_SWAP == 0 + uint8_t txt_rgb[3] = {color.ch.red, color.ch.green, color.ch.blue}; +#else + uint8_t txt_rgb[3] = {color.ch.red, (color.ch.green_h << 3) + color.ch.green_l, color.ch.blue}; +#endif + + for(row = row_start ; row < row_end; row++) { + uint8_t subpx_cnt = 0; + bitmask = bitmask_init >> col_bit; + mask_p_start = mask_p; + for(col = col_start; col < col_end; col++) { + /*Load the pixel's opacity into the mask*/ + letter_px = (*map_p & bitmask) >> (8 - col_bit - g->bpp); + if(letter_px != 0) { + if(opa == LV_OPA_COVER) { + px_opa = g->bpp == 8 ? letter_px : bpp_opa_table[letter_px]; + } else { + px_opa = g->bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8 + : (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8; + } + } else { + px_opa = 0; + } + + font_rgb[subpx_cnt] = px_opa; + + subpx_cnt ++; + if(subpx_cnt == 3) { + subpx_cnt = 0; + + lv_color_t res_color; +#if LV_COLOR_16_SWAP == 0 + uint8_t bg_rgb[3] = {vdb_buf_tmp->ch.red, vdb_buf_tmp->ch.green, vdb_buf_tmp->ch.blue}; +#else + uint8_t bg_rgb[3] = {vdb_buf_tmp->ch.red, + (vdb_buf_tmp->ch.green_h << 3) + vdb_buf_tmp->ch.green_l, + vdb_buf_tmp->ch.blue}; +#endif + +#if LV_SUBPX_BGR + res_color.ch.blue = (uint16_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8; + res_color.ch.red = (uint16_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8; +#else + res_color.ch.red = (uint16_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8; + res_color.ch.blue = (uint16_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8; +#endif + +#if LV_COLOR_16_SWAP == 0 + res_color.ch.green = (uint16_t)((uint16_t)txt_rgb[1] * font_rgb[1] + (bg_rgb[1] * (255 - font_rgb[1]))) >> 8; +#else + uint8_t green = (uint16_t)((uint16_t)txt_rgb[1] * font_rgb[1] + (bg_rgb[1] * (255 - font_rgb[1]))) >> 8; + res_color.ch.green_h = green >> 3; + res_color.ch.green_l = green & 0x7; +#endif + + if(font_rgb[0] == 0 && font_rgb[1] == 0 && font_rgb[2] == 0) mask_buf[mask_p] = LV_OPA_TRANSP; + else mask_buf[mask_p] = LV_OPA_COVER; + color_buf[mask_p] = res_color; + + /*Next mask byte*/ + mask_p++; + vdb_buf_tmp++; + } + + /*Go to the next column*/ + if(col_bit < 8 - g->bpp) { + col_bit += g->bpp; + bitmask = bitmask >> g->bpp; + } else { + col_bit = 0; + bitmask = bitmask_init; + map_p++; + } + } + + /*Apply masks if any*/ + if(other_mask_cnt) { + lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, map_area.x1, map_area.y2, lv_area_get_width(&map_area)); + if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) { + memset(mask_buf + mask_p_start, 0x00, lv_area_get_width(&map_area)); + } + } + + if((uint32_t) mask_p + (row_end - row_start) < mask_buf_size) { + map_area.y2 ++; + } else { + lv_blend_map(clip_area, &map_area, color_buf, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, LV_BLEND_MODE_NORMAL); + + map_area.y1 = map_area.y2 + 1; + map_area.y2 = map_area.y1; + mask_p = 0; + } + + col_bit += ((g->box_w - col_end) + col_start) * g->bpp; + + map_p += (col_bit >> 3); + col_bit = col_bit & 0x7; + + /*Next row in VDB*/ + vdb_buf_tmp += vdb_width - (col_end - col_start) / 3; + } + + /*Flush the last part*/ + if(map_area.y1 != map_area.y2) { + map_area.y2--; + lv_blend_map(clip_area, &map_area, color_buf, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, LV_BLEND_MODE_NORMAL); + } + + lv_mem_buf_release(mask_buf); + lv_mem_buf_release(color_buf); +} + + +/** + * 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) +{ + uint8_t result = 0; + + if(hex >= '0' && hex <= '9') { + result = hex - '0'; + } else { + if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/ + + switch(hex) { + case 'A': result = 10; break; + case 'B': result = 11; break; + case 'C': result = 12; break; + case 'D': result = 13; break; + case 'E': result = 14; break; + case 'F': result = 15; break; + default: result = 0; break; + } + } + + return result; +} diff --git a/src/lv_draw/lv_draw_label.h b/src/lv_draw/lv_draw_label.h index 6dc4d6464..d0215179a 100644 --- a/src/lv_draw/lv_draw_label.h +++ b/src/lv_draw/lv_draw_label.h @@ -25,12 +25,20 @@ extern "C" { * TYPEDEFS **********************/ -typedef struct -{ - uint16_t start; - uint16_t end; -}lv_draw_label_txt_sel_t; - +typedef struct { + lv_color_t color; + lv_color_t sel_color; + const lv_font_t * font; + lv_opa_t opa; + lv_style_value_t line_space; + lv_style_value_t letter_space; + uint16_t sel_start; + uint16_t sel_end; + lv_coord_t ofs_x; + lv_coord_t ofs_y; + lv_bidi_dir_t bidi_dir; + lv_txt_flag_t flag; +}lv_draw_label_dsc_t; /** Store some info to speed up drawing of very large texts * It takes a lot of time to get the first visible character because @@ -53,6 +61,8 @@ typedef struct { * GLOBAL PROTOTYPES **********************/ +void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc); + /** * Write a text * @param coords coordinates of the label @@ -65,9 +75,8 @@ typedef struct { * @param sel_start start index of selected area (`LV_LABEL_TXT_SEL_OFF` if none) * @param bidi_dir base direction of the text */ -void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, - const char * txt, lv_txt_flag_t flag, lv_point_t * offset, lv_draw_label_txt_sel_t * sel, - lv_draw_label_hint_t * hint, lv_bidi_dir_t bidi_dir); +void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, lv_draw_label_dsc_t * dsc, + const char * txt, lv_opa_t opa_scale, lv_draw_label_hint_t * hint); /********************** * MACROS diff --git a/src/lv_objx/lv_btn.c b/src/lv_objx/lv_btn.c index 72e39c3db..780a27e4a 100644 --- a/src/lv_objx/lv_btn.c +++ b/src/lv_objx/lv_btn.c @@ -452,9 +452,10 @@ static lv_design_res_t lv_btn_design(lv_obj_t * btn, const lv_area_t * clip_area } #else lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn); - lv_draw_rect_dsc_t draw_dsc; lv_obj_state_t state = lv_obj_get_state(btn); + lv_draw_rect_dsc_t draw_dsc; + lv_draw_rect_dsc_init(&draw_dsc); lv_obj_init_draw_rect_dsc(btn, LV_OBJ_STYLE_MAIN, state, &draw_dsc); lv_draw_rect(&btn->coords, clip_area, &draw_dsc, lv_obj_get_opa_scale(btn)); diff --git a/src/lv_objx/lv_label.c b/src/lv_objx/lv_label.c index a581fead7..c8292581b 100644 --- a/src/lv_objx/lv_label.c +++ b/src/lv_objx/lv_label.c @@ -113,8 +113,8 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy) #endif #if LV_LABEL_TEXT_SEL - ext->txt_sel.start = LV_DRAW_LABEL_NO_TXT_SEL; - ext->txt_sel.end = LV_DRAW_LABEL_NO_TXT_SEL; + ext->sel_start = LV_DRAW_LABEL_NO_TXT_SEL; + ext->sel_end = LV_DRAW_LABEL_NO_TXT_SEL; #endif ext->dot.tmp_ptr = NULL; ext->dot_tmp_alloc = 0; @@ -127,7 +127,6 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy) lv_obj_set_click(new_label, false); lv_label_set_long_mode(new_label, LV_LABEL_LONG_EXPAND); lv_label_set_text(new_label, "Text"); - lv_label_set_style(new_label, LV_LABEL_STYLE_MAIN, NULL); /*Inherit parent's style*/ } /*Copy 'copy' if not NULL*/ else { @@ -159,7 +158,7 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy) ext->dot_end = copy_ext->dot_end; /*Refresh the style with new signal function*/ - lv_obj_refresh_style(new_label); +// lv_obj_refresh_style(new_label); } LV_LOG_INFO("label created"); @@ -450,7 +449,7 @@ void lv_label_set_text_sel_start(lv_obj_t * label, uint16_t index) #if LV_LABEL_TEXT_SEL lv_label_ext_t * ext = lv_obj_get_ext_attr(label); - ext->txt_sel.start = index; + ext->sel_start = index; lv_obj_invalidate(label); #else (void)label; /*Unused*/ @@ -464,7 +463,7 @@ void lv_label_set_text_sel_end(lv_obj_t * label, uint16_t index) #if LV_LABEL_TEXT_SEL lv_label_ext_t * ext = lv_obj_get_ext_attr(label); - ext->txt_sel.end = index; + ext->sel_end = index; lv_obj_invalidate(label); #else (void)label; /*Unused*/ @@ -592,8 +591,9 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t char_id, lv_point_ uint32_t line_start = 0; uint32_t new_line_start = 0; lv_coord_t max_w = lv_obj_get_width(label); - const lv_style_t * style = lv_obj_get_style(label); - const lv_font_t * font = style->text.font; + const lv_font_t * font = lv_obj_get_style_ptr(label, LV_LABEL_STYLE_MAIN, LV_STYLE_FONT); + lv_style_value_t line_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LINE_SPACE); + lv_style_value_t letter_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LETTER_SPACE); lv_coord_t letter_height = lv_font_get_line_height(font); lv_coord_t y = 0; lv_txt_flag_t flag = LV_TXT_FLAG_NONE; @@ -614,18 +614,18 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t char_id, lv_point_ /*Search the line of the index letter */; while(txt[new_line_start] != '\0') { - new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag); + new_line_start += lv_txt_get_next_line(&txt[line_start], font, letter_space, max_w, flag); if(byte_id < new_line_start || txt[new_line_start] == '\0') break; /*The line of 'index' letter begins at 'line_start'*/ - y += letter_height + style->text.line_space; + y += letter_height + line_space; line_start = new_line_start; } /*If the last character is line break then go to the next line*/ if(byte_id > 0) { if((txt[byte_id - 1] == '\n' || txt[byte_id - 1] == '\r') && txt[byte_id] == '\0') { - y += letter_height + style->text.line_space; + y += letter_height + line_space; line_start = byte_id; } } @@ -655,18 +655,18 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t char_id, lv_point_ /*Calculate the x coordinate*/ - lv_coord_t x = lv_txt_get_width(bidi_txt, visual_byte_pos, font, style->text.letter_space, flag); + lv_coord_t x = lv_txt_get_width(bidi_txt, visual_byte_pos, font, letter_space, flag); - if(char_id != line_start) x += style->text.letter_space; + if(char_id != line_start) x += letter_space; if(align == LV_LABEL_ALIGN_CENTER) { lv_coord_t line_w; - line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, letter_space, flag); x += lv_obj_get_width(label) / 2 - line_w / 2; } else if(align == LV_LABEL_ALIGN_RIGHT) { lv_coord_t line_w; - line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, letter_space, flag); x += lv_obj_get_width(label) - line_w; } @@ -695,8 +695,9 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) uint32_t line_start = 0; uint32_t new_line_start = 0; lv_coord_t max_w = lv_obj_get_width(label); - const lv_style_t * style = lv_obj_get_style(label); - const lv_font_t * font = style->text.font; + const lv_font_t * font = lv_obj_get_style_ptr(label, LV_LABEL_STYLE_MAIN, LV_STYLE_FONT); + lv_style_value_t line_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LINE_SPACE); + lv_style_value_t letter_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LETTER_SPACE); lv_coord_t letter_height = lv_font_get_line_height(font); lv_coord_t y = 0; lv_txt_flag_t flag = LV_TXT_FLAG_NONE; @@ -717,7 +718,7 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) /*Search the line of the index letter */; while(txt[line_start] != '\0') { - new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag); + new_line_start += lv_txt_get_next_line(&txt[line_start], font, letter_space, max_w, flag); if(pos->y <= y + letter_height) { /*The line is found (stored in 'line_start')*/ @@ -728,7 +729,7 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) if(letter != '\n' && txt[new_line_start] == '\0' ) new_line_start++; break; } - y += letter_height + style->text.line_space; + y += letter_height + line_space; line_start = new_line_start; } @@ -746,12 +747,12 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) lv_coord_t x = 0; if(align == LV_LABEL_ALIGN_CENTER) { lv_coord_t line_w; - line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, letter_space, flag); x += lv_obj_get_width(label) / 2 - line_w / 2; } else if(align == LV_LABEL_ALIGN_RIGHT) { lv_coord_t line_w; - line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, letter_space, flag); x += lv_obj_get_width(label) - line_w; } @@ -784,7 +785,7 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) i = i_act; break; } - x += style->text.letter_space; + x += letter_space; i_act = i; } } @@ -813,7 +814,7 @@ uint16_t lv_label_get_text_sel_start(const lv_obj_t * label) #if LV_LABEL_TEXT_SEL lv_label_ext_t * ext = lv_obj_get_ext_attr(label); - return ext->txt_sel.start; + return ext->sel_start; #else (void)label; /*Unused*/ @@ -832,7 +833,7 @@ uint16_t lv_label_get_text_sel_end(const lv_obj_t * label) #if LV_LABEL_TEXT_SEL lv_label_ext_t * ext = lv_obj_get_ext_attr(label); - return ext->txt_sel.end; + return ext->sel_end; #else (void)label; /*Unused*/ return LV_LABEL_TEXT_SEL_OFF; @@ -855,8 +856,9 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos) uint32_t line_start = 0; uint32_t new_line_start = 0; lv_coord_t max_w = lv_obj_get_width(label); - const lv_style_t * style = lv_obj_get_style(label); - const lv_font_t * font = style->text.font; + const lv_font_t * font = lv_obj_get_style_ptr(label, LV_LABEL_STYLE_MAIN, LV_STYLE_FONT); + lv_style_value_t line_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LINE_SPACE); + lv_style_value_t letter_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LETTER_SPACE); lv_coord_t letter_height = lv_font_get_line_height(font); lv_coord_t y = 0; lv_txt_flag_t flag = LV_TXT_FLAG_NONE; @@ -873,10 +875,10 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos) /*Search the line of the index letter */; while(txt[line_start] != '\0') { - new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag); + new_line_start += lv_txt_get_next_line(&txt[line_start], font, letter_space, max_w, flag); if(pos->y <= y + letter_height) break; /*The line is found (stored in 'line_start')*/ - y += letter_height + style->text.line_space; + y += letter_height + line_space; line_start = new_line_start; } @@ -886,12 +888,12 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos) lv_coord_t last_x = 0; if(align == LV_LABEL_ALIGN_CENTER) { lv_coord_t line_w; - line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, letter_space, flag); x += lv_obj_get_width(label) / 2 - line_w / 2; } else if(align == LV_LABEL_ALIGN_RIGHT) { lv_coord_t line_w; - line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, letter_space, flag); x += lv_obj_get_width(label) - line_w; } @@ -923,15 +925,28 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos) i = i_current; break; } - x += style->text.letter_space; + x += letter_space; i_current = i; } } - int32_t max_diff = lv_font_get_glyph_width(font, letter, letter_next) + style->text.letter_space + 1; - return (pos->x >= (last_x - style->text.letter_space) && pos->x <= (last_x + max_diff)); + int32_t max_diff = lv_font_get_glyph_width(font, letter, letter_next) + letter_space + 1; + return (pos->x >= (last_x - letter_space) && pos->x <= (last_x + max_diff)); } +lv_style_dsc_t * lv_label_get_style(lv_obj_t * label, uint8_t type) +{ + lv_style_dsc_t * style_dsc_p; + switch(type) { + case LV_LABEL_STYLE_MAIN: + style_dsc_p = &label->style_dsc; + break; + default: + style_dsc_p = NULL; + } + + return style_dsc_p; +} /*===================== * Other functions *====================*/ @@ -1029,28 +1044,32 @@ static lv_design_res_t lv_label_design(lv_obj_t * label, const lv_area_t * clip_ return LV_DESIGN_RES_NOT_COVER; else if(mode == LV_DESIGN_DRAW_MAIN) { lv_area_t coords; - const lv_style_t * style = lv_obj_get_style(label); + const lv_font_t * font = lv_obj_get_style_ptr(label, LV_LABEL_STYLE_MAIN, LV_STYLE_FONT); + lv_style_value_t line_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LINE_SPACE); + lv_style_value_t letter_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LETTER_SPACE); lv_opa_t opa_scale = lv_obj_get_opa_scale(label); lv_obj_get_coords(label, &coords); -#if LV_USE_GROUP - lv_group_t * g = lv_obj_get_group(label); - if(lv_group_get_focused(g) == label) { - lv_draw_rect(&coords, clip_area, style, opa_scale); - } -#endif - lv_label_ext_t * ext = lv_obj_get_ext_attr(label); - + lv_obj_state_t state = lv_obj_get_state(label); if(ext->body_draw) { lv_area_t bg; lv_obj_get_coords(label, &bg); - bg.x1 -= style->body.padding.left; - bg.x2 += style->body.padding.right; - bg.y1 -= style->body.padding.top; - bg.y2 += style->body.padding.bottom; - lv_draw_rect(&bg, clip_area, style, lv_obj_get_opa_scale(label)); + lv_coord_t left = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_PAD_LEFT); + lv_coord_t right = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_PAD_RIGHT); + lv_coord_t top = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_PAD_TOP); + lv_coord_t bottom = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_PAD_BOTTOM); + bg.x1 -= left; + bg.x2 += right; + bg.y1 -= top; + bg.y2 += bottom; + + lv_draw_rect_dsc_t draw_rect_dsc; + lv_draw_rect_dsc_init(&draw_rect_dsc); + lv_obj_init_draw_rect_dsc(label, LV_LABEL_STYLE_MAIN, state, &draw_rect_dsc); + + lv_draw_rect(&bg, clip_area, &draw_rect_dsc, lv_obj_get_opa_scale(label)); } lv_label_align_t align = lv_label_get_align(label); @@ -1066,7 +1085,7 @@ static lv_design_res_t lv_label_design(lv_obj_t * label, const lv_area_t * clip_ if((ext->long_mode == LV_LABEL_LONG_SROLL || ext->long_mode == LV_LABEL_LONG_SROLL_CIRC) && (ext->align == LV_LABEL_ALIGN_CENTER || ext->align == LV_LABEL_ALIGN_RIGHT)) { lv_point_t size; - lv_txt_get_size(&size, ext->text, style->text.font, style->text.letter_space, style->text.line_space, + lv_txt_get_size(&size, ext->text, font, letter_space, line_space, LV_COORD_MAX, flag); if(size.x > lv_obj_get_width(label)) { flag &= ~LV_TXT_FLAG_RIGHT; @@ -1082,33 +1101,39 @@ static lv_design_res_t lv_label_design(lv_obj_t * label, const lv_area_t * clip_ /*Just for compatibility*/ lv_draw_label_hint_t * hint = NULL; #endif - lv_draw_label_txt_sel_t sel; - sel.start = lv_label_get_text_sel_start(label); - sel.end = lv_label_get_text_sel_end(label); - lv_draw_label(&coords, clip_area, style, opa_scale, ext->text, flag, &ext->offset, &sel, hint, lv_obj_get_base_dir(label)); + lv_draw_label_dsc_t label_draw_dsc; + lv_draw_label_dsc_init(&label_draw_dsc); + + label_draw_dsc.sel_start = lv_label_get_text_sel_start(label); + label_draw_dsc.sel_end = lv_label_get_text_sel_end(label); + label_draw_dsc.ofs_x = ext->offset.x; + label_draw_dsc.ofs_y = ext->offset.y; + label_draw_dsc.flag = flag; + lv_obj_init_draw_label_dsc(label, LV_LABEL_STYLE_MAIN, state, &label_draw_dsc); + + lv_draw_label(&coords, clip_area, &label_draw_dsc, ext->text, opa_scale, hint); if(ext->long_mode == LV_LABEL_LONG_SROLL_CIRC) { lv_point_t size; - lv_txt_get_size(&size, ext->text, style->text.font, style->text.letter_space, style->text.line_space, + lv_txt_get_size(&size, ext->text, font, letter_space, line_space, LV_COORD_MAX, flag); - lv_point_t ofs; - /*Draw the text again next to the original to make an circular effect */ if(size.x > lv_obj_get_width(label)) { - ofs.x = ext->offset.x + size.x + - lv_font_get_glyph_width(style->text.font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; - ofs.y = ext->offset.y; + label_draw_dsc.ofs_x = ext->offset.x + size.x + + lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; + label_draw_dsc.ofs_y = ext->offset.y; - lv_draw_label(&coords, clip_area, style, opa_scale, ext->text, flag, &ofs, &sel, NULL, lv_obj_get_base_dir(label)); + lv_draw_label(&coords, clip_area, &label_draw_dsc, ext->text, opa_scale, hint); } /*Draw the text again below the original to make an circular effect */ if(size.y > lv_obj_get_height(label)) { - ofs.x = ext->offset.x; - ofs.y = ext->offset.y + size.y + lv_font_get_line_height(style->text.font); - lv_draw_label(&coords, clip_area, style, opa_scale, ext->text, flag, &ofs, &sel, NULL, lv_obj_get_base_dir(label)); + label_draw_dsc.ofs_x = ext->offset.x; + label_draw_dsc.ofs_y = ext->offset.y + size.y + lv_font_get_line_height(font); + + lv_draw_label(&coords, clip_area, &label_draw_dsc, ext->text, opa_scale, hint); } } } @@ -1127,6 +1152,13 @@ static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param { lv_res_t res; + if(sign == LV_SIGNAL_GET_STYLE) { + uint8_t ** type_p = param; + lv_style_dsc_t ** style_dsc_p = param; + *style_dsc_p = lv_label_get_style(label, **type_p); + return LV_RES_OK; + } + /* Include the ancient signal function */ res = ancestor_signal(label, sign, param); if(res != LV_RES_OK) return res; @@ -1152,12 +1184,14 @@ static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param } } else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) { if(ext->body_draw) { - const lv_style_t * style = lv_label_get_style(label, LV_LABEL_STYLE_MAIN); - - label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, style->body.padding.left); - label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, style->body.padding.right); - label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, style->body.padding.top); - label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, style->body.padding.bottom); + lv_coord_t left = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_PAD_LEFT); + lv_coord_t right = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_PAD_RIGHT); + lv_coord_t top = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_PAD_TOP); + lv_coord_t bottom = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_PAD_BOTTOM); + label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, left); + label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, right); + label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, top); + label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, bottom); } } else if(sign == LV_SIGNAL_BASE_DIR_CHG) { @@ -1190,8 +1224,9 @@ static void lv_label_refr_text(lv_obj_t * label) #endif lv_coord_t max_w = lv_obj_get_width(label); - const lv_style_t * style = lv_obj_get_style(label); - const lv_font_t * font = style->text.font; + const lv_font_t * font = lv_obj_get_style_ptr(label, LV_LABEL_STYLE_MAIN, LV_STYLE_FONT); + lv_style_value_t line_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LINE_SPACE); + lv_style_value_t letter_space = lv_obj_get_style_value(label, LV_LABEL_STYLE_MAIN, LV_STYLE_LETTER_SPACE); /*If the width will be expanded set the max length to very big */ if(ext->long_mode == LV_LABEL_LONG_EXPAND) { @@ -1203,7 +1238,7 @@ static void lv_label_refr_text(lv_obj_t * label) lv_txt_flag_t flag = LV_TXT_FLAG_NONE; if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; - lv_txt_get_size(&size, ext->text, font, style->text.letter_space, style->text.line_space, max_w, flag); + lv_txt_get_size(&size, ext->text, font, letter_space, line_space, max_w, flag); /*Set the full size in expand mode*/ if(ext->long_mode == LV_LABEL_LONG_EXPAND) { @@ -1220,7 +1255,7 @@ static void lv_label_refr_text(lv_obj_t * label) anim.ready_cb = NULL; anim.path_cb = lv_anim_path_linear; anim.playback_pause = - (((lv_font_get_glyph_width(style->text.font, ' ', ' ') + style->text.letter_space) * 1000) / + (((lv_font_get_glyph_width(font, ' ', ' ') + letter_space) * 1000) / ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT; anim.repeat_pause = anim.playback_pause; @@ -1261,7 +1296,7 @@ static void lv_label_refr_text(lv_obj_t * label) anim.var = label; anim.repeat = 1; anim.playback = 0; - anim.act_time = -(((lv_font_get_glyph_width(style->text.font, ' ', ' ') + style->text.letter_space) * 1000) / + anim.act_time = -(((lv_font_get_glyph_width(font, ' ', ' ') + letter_space) * 1000) / ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT; anim.ready_cb = NULL; @@ -1315,12 +1350,12 @@ static void lv_label_refr_text(lv_obj_t * label) } else { lv_point_t p; p.x = lv_obj_get_width(label) - - (lv_font_get_glyph_width(style->text.font, '.', '.') + style->text.letter_space) * + (lv_font_get_glyph_width(font, '.', '.') + letter_space) * LV_LABEL_DOT_NUM; /*Shrink with dots*/ p.y = lv_obj_get_height(label); p.y -= p.y % - (lv_font_get_line_height(style->text.font) + style->text.line_space); /*Round down to the last line*/ - p.y -= style->text.line_space; /*Trim the last line space*/ + (lv_font_get_line_height(font) + line_space); /*Round down to the last line*/ + p.y -= line_space; /*Trim the last line space*/ uint32_t letter_id = lv_label_get_letter_on(label, &p); /*Save letters under the dots and replace them with dots*/ diff --git a/src/lv_objx/lv_label.h b/src/lv_objx/lv_label.h index 976854235..9daedc64e 100644 --- a/src/lv_objx/lv_label.h +++ b/src/lv_objx/lv_label.h @@ -91,7 +91,8 @@ typedef struct #endif #if LV_LABEL_TEXT_SEL - lv_draw_label_txt_sel_t txt_sel; + uint16_t sel_start; + uint16_t sel_end; #endif lv_label_long_mode_t long_mode : 3; /*Determinate what to do with the long texts*/ @@ -108,6 +109,7 @@ typedef struct enum { LV_LABEL_STYLE_MAIN, }; + typedef uint8_t lv_label_style_t; /********************** @@ -194,18 +196,6 @@ void lv_label_set_body_draw(lv_obj_t * label, bool en); */ void lv_label_set_anim_speed(lv_obj_t * label, uint16_t anim_speed); -/** - * Set the style of an label - * @param label pointer to an label object - * @param type which style should be get (can be only `LV_LABEL_STYLE_MAIN`) - * @param style pointer to a style - */ -static inline void lv_label_set_style(lv_obj_t * label, lv_label_style_t type, const lv_style_t * style) -{ - (void)type; /*Unused*/ - lv_obj_set_style(label, style); -} - /** * @brief Set the selection start index. * @param label pointer to a label object. @@ -292,18 +282,6 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos); */ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos); -/** - * Get the style of an label object - * @param label pointer to an label object - * @param type which style should be get (can be only `LV_LABEL_STYLE_MAIN`) - * @return pointer to the label's style - */ -static inline const lv_style_t * lv_label_get_style(const lv_obj_t * label, lv_label_style_t type) -{ - (void)type; /*Unused*/ - return lv_obj_get_style(label); -} - /** * @brief Get the selection start index. * @param label pointer to a label object. @@ -318,6 +296,9 @@ uint16_t lv_label_get_text_sel_start(const lv_obj_t * label); */ uint16_t lv_label_get_text_sel_end(const lv_obj_t * label); + +lv_style_dsc_t * lv_label_get_style(lv_obj_t * label, uint8_t type); + /*===================== * Other functions *====================*/