diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index 24579e5be8..50e6db74b8 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -136,7 +136,7 @@ async def update_to_code(config, action_id, template_arg, args): widget.type.w_type.value_property is not None and widget.type.w_type.value_property in config ): - lv.event_send(widget.obj, UPDATE_EVENT, nullptr) + lv_obj.send_event(widget.obj, UPDATE_EVENT, nullptr) widgets = await get_widgets(config[CONF_ID]) return await action_to_code( @@ -455,6 +455,6 @@ async def obj_refresh_to_code(config, action_id, template_arg, args): widget.type.w_type.value_property is not None and widget.type.w_type.value_property in config ): - lv.event_send(widget.obj, UPDATE_EVENT, nullptr) + lv_obj.send_event(widget.obj, UPDATE_EVENT, nullptr) return await action_to_code(widget, do_refresh, action_id, template_arg, args) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 72345ca98e..de5835d7a6 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -541,6 +541,7 @@ CONF_END_ANGLE = "end_angle" CONF_END_VALUE = "end_value" CONF_ENTER_BUTTON = "enter_button" CONF_ENTRIES = "entries" +CONF_EXT_CLICK_AREA = "ext_click_area" CONF_FLAGS = "flags" CONF_FLEX_FLOW = "flex_flow" CONF_FLEX_ALIGN_MAIN = "flex_align_main" diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index 146b261f26..eb8f7d4437 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -253,14 +253,10 @@ class MockLv: A mock object that can be used to generate LVGL calls. """ - # Mapping for LVGL 9 - ATTR_MAP = {"event_send": "obj_send_event", "dither": "bg_dither_mode"} - def __init__(self, base): self.base = base def __getattr__(self, attr: str) -> "MockLv": - attr = MockLv.ATTR_MAP.get(attr, attr) return MockLv(f"{self.base}{attr}") def append(self, expression): @@ -314,7 +310,6 @@ class ReturnStatement(ExpressionStatement): class LvExpr(MockLv): def __getattr__(self, attr: str) -> "MockLv": - attr = MockLv.ATTR_MAP.get(attr, attr) return LvExpr(f"{self.base}{attr}") def append(self, expression): diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index bf86a4e9ee..a5075cb614 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -343,26 +343,26 @@ void IndicatorLine::set_value(int value) { } void IndicatorLine::update_length_() { - uint32_t actual_needle_length; - auto radius = lv_obj_get_width(lv_obj_get_parent(this->obj)) / 2; + auto cx = lv_obj_get_width(lv_obj_get_parent(this->obj)) / 2; + auto cy = lv_obj_get_height(lv_obj_get_parent(this->obj)) / 2; + auto radius = clamp_at_most(cx, cy); auto length = lv_obj_get_style_length(this->obj, LV_PART_MAIN); auto radial_offset = lv_obj_get_style_radial_offset(this->obj, LV_PART_MAIN); if (LV_COORD_IS_PCT(radial_offset)) { radial_offset = radius * LV_COORD_GET_PCT(radial_offset) / 100; } if (LV_COORD_IS_PCT(length)) { - actual_needle_length = radius * LV_COORD_GET_PCT(length) / 100; + length = radius * LV_COORD_GET_PCT(length) / 100; } else if (length < 0) { - actual_needle_length = radius + length; - } else { - actual_needle_length = length; + length += radius; } auto x = lv_trigo_cos(this->angle_) / 32768.0f; auto y = lv_trigo_sin(this->angle_) / 32768.0f; + // radius here also represents the offset of the scale center from top left this->points_[0].x = radius + radial_offset * x; this->points_[0].y = radius + radial_offset * y; - this->points_[1].x = x * actual_needle_length + radius; - this->points_[1].y = y * actual_needle_length + radius; + this->points_[1].x = radius + x * (radial_offset + length); + this->points_[1].y = radius + y * (radial_offset + length); lv_obj_refresh_self_size(this->obj); lv_obj_invalidate(this->obj); } @@ -682,15 +682,15 @@ void lv_scale_draw_event_cb(lv_event_t *e, int16_t range_start, int16_t range_en auto *line_dsc = static_cast(lv_draw_task_get_draw_dsc(task)); int tick = line_dsc->base.id2; if (tick >= range_start && tick <= range_end) { - unsigned range = range_end - range_start; + int ratio; if (local) { + int range = range_end - range_start; tick -= range_start; + ratio = range == 0 ? 0 : (tick * 255) / range; } else { - range = lv_scale_get_total_tick_count(scale) - 1; + // total tick count is guaranteed to be at least 2. + ratio = (line_dsc->base.id1 * 255) / (lv_scale_get_total_tick_count(scale) - 1); } - if (range == 0) - range = 1; - auto ratio = (tick * 255) / range; line_dsc->color = lv_color_mix(color_end, color_start, ratio); line_dsc->width += width; } diff --git a/esphome/components/lvgl/number/__init__.py b/esphome/components/lvgl/number/__init__.py index c48e051eac..d80e93708b 100644 --- a/esphome/components/lvgl/number/__init__.py +++ b/esphome/components/lvgl/number/__init__.py @@ -12,7 +12,7 @@ from ..lvcode import ( UPDATE_EVENT, LambdaContext, ReturnStatement, - lv, + lv_obj, lvgl_static, ) from ..types import LV_EVENT, LvNumber, lvgl_ns @@ -40,7 +40,7 @@ async def to_code(config): await widget.set_property( "value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED] ) - lv.event_send(widget.obj, API_EVENT, cg.nullptr) + lv_obj.send_event(widget.obj, API_EVENT, cg.nullptr) event_code = ( LV_EVENT.VALUE_CHANGED if not config[CONF_UPDATE_ON_RELEASE] diff --git a/esphome/components/lvgl/schemas.py b/esphome/components/lvgl/schemas.py index bcbb193ce3..9c9504f05f 100644 --- a/esphome/components/lvgl/schemas.py +++ b/esphome/components/lvgl/schemas.py @@ -146,26 +146,41 @@ def point_schema(value): # All LVGL styles and their validators -STYLE_PROPS = { +BASE_PROPS = { "align": df.CHILD_ALIGNMENTS.one_of, - "arc_opa": lvalid.opacity, + "anim_duration": lvalid.lv_milliseconds, "arc_color": lvalid.lv_color, + "arc_opa": lvalid.opacity, "arc_rounded": lvalid.lv_bool, "arc_width": lvalid.pixels, - "anim_time": lvalid.lv_milliseconds, + "base_dir": df.LvConstant("LV_BASE_DIR_", "LTR", "RTL", "AUTO").one_of, "bg_color": lvalid.lv_color, "bg_grad": lv_gradient, "bg_grad_color": lvalid.lv_color, - "bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of, "bg_grad_dir": LV_GRAD_DIR.one_of, + "bg_grad_opa": lvalid.opacity, "bg_grad_stop": lvalid.stop_value, "bg_image_opa": lvalid.opacity, "bg_image_recolor": lvalid.lv_color, "bg_image_recolor_opa": lvalid.opacity, "bg_image_src": lvalid.lv_image, "bg_image_tiled": lvalid.lv_bool, + "bg_main_opa": lvalid.opacity, "bg_main_stop": lvalid.stop_value, "bg_opa": lvalid.opacity, + "blend_mode": df.LvConstant( + "LV_BLEND_MODE_", + "NORMAL", + "ADDITIVE", + "SUBTRACTIVE", + "MULTIPLY", + "DIFFERENCE", + ).one_of, + "blur_backdrop": lvalid.lv_bool, + "blur_quality": df.LvConstant( + "LV_BLUR_QUALITY_", "AUTO", "SPEED", "PRECISION" + ).one_of, + "blur_radius": lvalid.lv_positive_int, "border_color": lvalid.lv_color, "border_opa": lvalid.opacity, "border_post": lvalid.lv_bool, @@ -175,33 +190,53 @@ STYLE_PROPS = { "border_width": lvalid.lv_positive_int, "clip_corner": lvalid.lv_bool, "color_filter_opa": lvalid.opacity, + "drop_shadow_color": lvalid.lv_color, + "drop_shadow_offset_x": lvalid.lv_int, + "drop_shadow_offset_y": lvalid.lv_int, + "drop_shadow_opa": lvalid.opacity, + "drop_shadow_quality": df.LvConstant( + "LV_BLUR_QUALITY_", "AUTO", "SPEED", "PRECISION" + ).one_of, + "drop_shadow_radius": lvalid.lv_positive_int, "height": lvalid.size, + "image_opa": lvalid.opacity, "image_recolor": lvalid.lv_color, "image_recolor_opa": lvalid.opacity, + "length": lvalid.pixels_or_percent, "line_color": lvalid.lv_color, "line_dash_gap": lvalid.lv_positive_int, "line_dash_width": lvalid.lv_positive_int, "line_opa": lvalid.opacity, "line_rounded": lvalid.lv_bool, "line_width": lvalid.lv_positive_int, + "margin_bottom": lvalid.padding, + "margin_left": lvalid.padding, + "margin_right": lvalid.padding, + "margin_top": lvalid.padding, + "max_height": lvalid.pixels_or_percent, + "max_width": lvalid.pixels_or_percent, + "min_height": lvalid.pixels_or_percent, + "min_width": lvalid.pixels_or_percent, "opa": lvalid.opacity, "opa_layered": lvalid.opacity, "outline_color": lvalid.lv_color, "outline_opa": lvalid.opacity, "outline_pad": lvalid.padding, "outline_width": lvalid.pixels, - "length": lvalid.pixels_or_percent, "pad_all": lvalid.padding, "pad_bottom": lvalid.padding, "pad_left": lvalid.padding, + "pad_radial": lvalid.padding, "pad_right": lvalid.padding, "pad_top": lvalid.padding, "radial_offset": lvalid.size, + "radius": lvalid.lv_fraction, + "recolor": lvalid.lv_color, + "recolor_opa": lvalid.opacity, + "rotary_sensitivity": lvalid.lv_positive_int, "shadow_color": lvalid.lv_color, "shadow_offset_x": lvalid.lv_int, "shadow_offset_y": lvalid.lv_int, - "shadow_ofs_x": lvalid.lv_int, - "shadow_ofs_y": lvalid.lv_int, "shadow_opa": lvalid.opacity, "shadow_spread": lvalid.lv_int, "shadow_width": lvalid.lv_positive_int, @@ -216,7 +251,9 @@ STYLE_PROPS = { "text_letter_space": lvalid.lv_positive_int, "text_line_space": lvalid.lv_positive_int, "text_opa": lvalid.opacity, - "transform_angle": lvalid.lv_angle, + "text_outline_stroke_color": lvalid.lv_color, + "text_outline_stroke_opa": lvalid.opacity, + "text_outline_stroke_width": lvalid.lv_positive_int, "transform_height": lvalid.pixels_or_percent, "transform_pivot_x": lvalid.pixels_or_percent, "transform_pivot_y": lvalid.pixels_or_percent, @@ -226,20 +263,17 @@ STYLE_PROPS = { "transform_scale_y": lvalid.scale, "transform_skew_x": lvalid.lv_angle, "transform_skew_y": lvalid.lv_angle, - "transform_zoom": lvalid.scale, + "transform_width": lvalid.pixels_or_percent, + "translate_radial": lvalid.lv_int, "translate_x": lvalid.pixels_or_percent, "translate_y": lvalid.pixels_or_percent, - "max_height": lvalid.pixels_or_percent, - "max_width": lvalid.pixels_or_percent, - "min_height": lvalid.pixels_or_percent, - "min_width": lvalid.pixels_or_percent, - "radius": lvalid.lv_fraction, "width": lvalid.size, "x": lvalid.pixels_or_percent, "y": lvalid.pixels_or_percent, } STYLE_REMAP = { + "anim_time": "anim_duration", "transform_angle": "transform_rotation", "transform_zoom": "transform_scale", "zoom": "scale", @@ -249,6 +283,10 @@ STYLE_REMAP = { "r_mod": "length", } +STYLE_PROPS = BASE_PROPS | { + p: BASE_PROPS[v] for p, v in STYLE_REMAP.items() if v in BASE_PROPS +} + def remap_property(prop, record=True): """ @@ -394,6 +432,7 @@ def obj_schema(widget_type: WidgetType): return ( part_schema(widget_type.parts) .extend(ALIGN_TO_SCHEMA) + .extend({cv.Optional(df.CONF_EXT_CLICK_AREA): lvalid.pixels}) .extend(automation_schema(widget_type.w_type)) .extend( { diff --git a/esphome/components/lvgl/switch/__init__.py b/esphome/components/lvgl/switch/__init__.py index 6d10a70d85..a43851b4a3 100644 --- a/esphome/components/lvgl/switch/__init__.py +++ b/esphome/components/lvgl/switch/__init__.py @@ -13,8 +13,8 @@ from ..lvcode import ( LambdaContext, LvConditional, LvContext, - lv, lv_add, + lv_obj, lvgl_static, ) from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns @@ -39,7 +39,7 @@ async def to_code(config): widget.add_state(LV_STATE.CHECKED) cond.else_() widget.clear_state(LV_STATE.CHECKED) - lv.event_send(widget.obj, API_EVENT, cg.nullptr) + lv_obj.send_event(widget.obj, API_EVENT, cg.nullptr) control.add(switch_id.publish_state(v)) switch = cg.new_Pvariable(config[CONF_ID], await control.get_lambda()) await cg.register_component(switch, config) diff --git a/esphome/components/lvgl/text/__init__.py b/esphome/components/lvgl/text/__init__.py index eb56cdb7a7..190ecacda5 100644 --- a/esphome/components/lvgl/text/__init__.py +++ b/esphome/components/lvgl/text/__init__.py @@ -10,8 +10,8 @@ from ..lvcode import ( UPDATE_EVENT, LambdaContext, LvContext, - lv, lv_add, + lv_obj, lvgl_static, ) from ..types import LV_EVENT, LvText, lvgl_ns @@ -33,7 +33,7 @@ async def to_code(config): await wait_for_widgets() async with LambdaContext([(cg.std_string, "text_value")]) as control: await widget.set_property("text", "text_value.c_str()") - lv.event_send(widget.obj, API_EVENT, cg.nullptr) + lv_obj.send_event(widget.obj, API_EVENT, cg.nullptr) control.add(textvar.publish_state(widget.get_value())) async with LambdaContext(EVENT_ARG) as lamb: lv_add(textvar.publish_state(widget.get_value())) diff --git a/esphome/components/lvgl/trigger.py b/esphome/components/lvgl/trigger.py index 54309cdf89..c52d213e15 100644 --- a/esphome/components/lvgl/trigger.py +++ b/esphome/components/lvgl/trigger.py @@ -15,6 +15,7 @@ from .defines import ( CONF_ALIGN, CONF_ALIGN_TO, CONF_ALIGN_TO_LAMBDA_ID, + CONF_EXT_CLICK_AREA, DIRECTIONS, LV_EVENT_MAP, LV_EVENT_TRIGGERS, @@ -113,6 +114,8 @@ async def generate_align_tos(config: dict): x = align_to[CONF_X] y = align_to[CONF_Y] lv.obj_align_to(w.obj, target, align, x, y) + if ext_click_area := w.config.get(CONF_EXT_CLICK_AREA): + lv.obj_set_ext_click_area(w.obj, ext_click_area) action_id = config[CONF_ALIGN_TO_LAMBDA_ID] var = new_Pvariable(action_id, await context.get_lambda()) diff --git a/esphome/components/lvgl/widgets/meter.py b/esphome/components/lvgl/widgets/meter.py index 494f811a8e..ab65a7c47d 100644 --- a/esphome/components/lvgl/widgets/meter.py +++ b/esphome/components/lvgl/widgets/meter.py @@ -56,11 +56,11 @@ from ..lv_validation import ( lv_float, lv_image, lv_int, + lv_positive_int, opacity, padding, pixels, pixels_or_percent, - pixels_or_percent_validator, requires_component, size, ) @@ -88,7 +88,10 @@ CONF_COLOR_START = "color_start" CONF_DRAW_TICKS_ON_TOP = "draw_ticks_on_top" CONF_IMAGE_ID = "image_id" CONF_INDICATORS = "indicators" +CONF_DASH_GAP = "dash_gap" +CONF_DASH_WIDTH = "dash_width" CONF_LINE_ID = "line_id" +CONF_ROUNDED = "rounded" CONF_LABEL_GAP = "label_gap" CONF_MAJOR = "major" CONF_METER = "meter" @@ -135,9 +138,12 @@ INDICATOR_LINE_SCHEMA = cv.Schema( { cv.Optional(CONF_WIDTH, default=4): cv.int_, cv.Optional(CONF_COLOR, default=0): lv_color, + cv.Optional(CONF_ROUNDED, default=True): lv_bool, + cv.Optional(CONF_DASH_GAP): lv_positive_int, + cv.Optional(CONF_DASH_WIDTH): lv_positive_int, cv.Optional(CONF_R_MOD): padding, - cv.Optional(CONF_LENGTH): pixels_or_percent_validator, - cv.Optional(CONF_RADIAL_OFFSET, 0): pixels_or_percent_validator, + cv.Optional(CONF_LENGTH): pixels_or_percent, + cv.Optional(CONF_RADIAL_OFFSET): pixels_or_percent, cv.Optional(CONF_VALUE, default=0.0): lv_float, cv.Optional(CONF_OPA, default=1.0): opacity, } @@ -249,17 +255,17 @@ SCALE_SCHEMA = cv.Schema( { cv.Optional(CONF_COUNT, default=12): cv.int_range(min=2), cv.Optional(CONF_WIDTH, default=2): cv.positive_int, - cv.Optional(CONF_LENGTH, default=10): size, - cv.Optional(CONF_RADIAL_OFFSET, default=0): size, + cv.Optional(CONF_LENGTH, default=10): cv.positive_int, + cv.Optional(CONF_RADIAL_OFFSET): cv.positive_int, cv.Optional(CONF_COLOR, default=0x808080): lv_color, cv.Optional(CONF_MAJOR): cv.Schema( { cv.Optional(CONF_STRIDE, default=3): cv.positive_int, cv.Optional(CONF_WIDTH, default=5): size, - cv.Optional(CONF_LENGTH, default="15%"): size, - cv.Optional(CONF_RADIAL_OFFSET, default=0): size, + cv.Optional(CONF_LENGTH, default=12): cv.positive_int, + cv.Optional(CONF_RADIAL_OFFSET): cv.positive_int, cv.Optional(CONF_COLOR, default=0): lv_color, - cv.Optional(CONF_LABEL_GAP, default=4): size, + cv.Optional(CONF_LABEL_GAP, default=4): cv.int_, } ), } @@ -466,11 +472,15 @@ class MeterType(WidgetType): CONF_OPA: v[CONF_OPA], CONF_LINE_WIDTH: v[CONF_WIDTH], "line_color": v[CONF_COLOR], - "line_rounded": True, + "line_rounded": v[CONF_ROUNDED], CONF_ALIGN: CHILD_ALIGNMENTS.TOP_LEFT, CONF_LENGTH: length, - CONF_RADIAL_OFFSET: v[CONF_RADIAL_OFFSET], } + if radial_offset := v.get(CONF_RADIAL_OFFSET): + props[CONF_RADIAL_OFFSET] = radial_offset + for option in (CONF_DASH_WIDTH, CONF_DASH_GAP): + if option in v: + props["line_" + option] = v[option] lw = await widget_to_code(props, line_indicator_type, scale_var) await set_indicator_values(lw, v) @@ -478,10 +488,8 @@ class MeterType(WidgetType): add_lv_use(CONF_IMAGE) src = v[CONF_SRC] src_data = get_image_metadata(src.id) - pivot_x = await pixels.process(v[CONF_PIVOT_X]) - pivot_y = await pixels.process( - v.get(CONF_PIVOT_Y, src_data.height // 2) - ) + pivot_x = v[CONF_PIVOT_X] + pivot_y = v.get(CONF_PIVOT_Y, src_data.height // 2) props = { CONF_X: src_data.width // 2 - pivot_x, "transform_pivot_x": pivot_x, @@ -511,11 +519,12 @@ class MeterType(WidgetType): lv_obj.set_style_line_width( scale_var, await size.process(ticks[CONF_WIDTH]), LV_PART.ITEMS ) - lv_obj.set_style_radial_offset( - scale_var, - await size.process(ticks[CONF_RADIAL_OFFSET]), - LV_PART.ITEMS, - ) + if radial_offset := ticks.get(CONF_RADIAL_OFFSET): + lv_obj.set_style_radial_offset( + scale_var, + -radial_offset, + LV_PART.ITEMS, + ) lv_obj.set_style_line_color( scale_var, await lv_color.process(ticks[CONF_COLOR]), @@ -536,11 +545,12 @@ class MeterType(WidgetType): await size.process(major[CONF_LENGTH]), LV_PART.INDICATOR, ) - lv_obj.set_style_radial_offset( - scale_var, - await size.process(ticks[CONF_RADIAL_OFFSET]), - LV_PART.INDICATOR, - ) + if radial_offset := major.get(CONF_RADIAL_OFFSET): + lv_obj.set_style_radial_offset( + scale_var, + -radial_offset, + LV_PART.INDICATOR, + ) lv_obj.set_style_line_width( scale_var, await size.process(major[CONF_WIDTH]), @@ -553,12 +563,9 @@ class MeterType(WidgetType): ) # Set label gap (padding) - label_gap = await size.process(major[CONF_LABEL_GAP]) - if isinstance(label_gap, int): - label_gap -= DEFAULT_LABEL_GAP lv_obj.set_style_pad_radial( scale_var, - label_gap, + major[CONF_LABEL_GAP] - DEFAULT_LABEL_GAP, LV_PART.INDICATOR, ) else: diff --git a/esphome/components/lvgl/widgets/tileview.py b/esphome/components/lvgl/widgets/tileview.py index 8e9d95f349..4657d628de 100644 --- a/esphome/components/lvgl/widgets/tileview.py +++ b/esphome/components/lvgl/widgets/tileview.py @@ -129,6 +129,6 @@ async def tileview_select(config, action_id, template_arg, args): lv.tileview_set_tile_by_index( widgets[0].obj, column, row, literal(config[CONF_ANIMATED]) ) - lv.event_send(w.obj, LV_EVENT.VALUE_CHANGED, cg.nullptr) + lv_obj.send_event(w.obj, LV_EVENT.VALUE_CHANGED, cg.nullptr) return await action_to_code(widgets, do_select, action_id, template_arg, args) diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 821476a72b..b8c9a1809e 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -232,7 +232,7 @@ lvgl: - roller: id: lv_roller visible_row_count: 2 - anim_time: 500ms + anim_duration: 500ms options: - Nov - Dec @@ -317,20 +317,27 @@ lvgl: align: top_left - container: align: center + anim_duration: 1s arc_opa: COVER arc_color: 0xFF0000 arc_rounded: false arc_width: 3 - anim_time: 1s + base_dir: auto bg_color: light_blue bg_grad_color: light_blue bg_grad_dir: hor + bg_grad_opa: cover bg_grad_stop: 128 bg_image_opa: transp bg_image_recolor: light_blue bg_image_recolor_opa: 50% + bg_main_opa: cover bg_main_stop: 0 bg_opa: 20% + blend_mode: normal + blur_backdrop: false + blur_quality: auto + blur_radius: 0 border_color: 0x00FF00 border_opa: cover border_post: true @@ -338,7 +345,15 @@ lvgl: border_width: 4 clip_corner: false color_filter_opa: transp + drop_shadow_color: 0x000000 + drop_shadow_offset_x: 5 + drop_shadow_offset_y: 5 + drop_shadow_opa: cover + drop_shadow_quality: precision + drop_shadow_radius: 10 + ext_click_area: 100px height: 50% + image_opa: cover image_recolor: light_blue image_recolor_opa: cover line_width: 10 @@ -346,6 +361,10 @@ lvgl: line_dash_gap: 10 line_rounded: false line_color: light_blue + margin_bottom: 4 + margin_left: 4 + margin_right: 4 + margin_top: 4 opa: cover opa_layered: cover outline_color: light_blue @@ -355,8 +374,12 @@ lvgl: pad_all: 10px pad_bottom: 10px pad_left: 10px + pad_radial: 0 pad_right: 10px pad_top: 10px + recolor: 0xFF0000 + recolor_opa: transp + rotary_sensitivity: 256 shadow_color: light_blue shadow_opa: cover shadow_spread: 5 @@ -368,6 +391,9 @@ lvgl: text_letter_space: 4 text_line_space: 4 text_opa: cover + text_outline_stroke_color: 0x000000 + text_outline_stroke_opa: cover + text_outline_stroke_width: 2 transform_rotation: 90 transform_height: 100 transform_pivot_x: 50% @@ -377,8 +403,10 @@ lvgl: transform_scale_y: 0.8 transform_skew_x: 10 transform_skew_y: 20 + transform_width: 100 shadow_offset_x: 3 shadow_offset_y: 3 + translate_radial: 0 translate_x: 10 translate_y: 10 max_height: 100 @@ -1053,7 +1081,7 @@ lvgl: - ticks: width: 1 count: 61 - length: 20% + length: 20 radial_offset: 5 color: 0xFFFFFF major: