1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-06 13:22:19 +01:00

LVGL stage 2 (#7129)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Clyde Stubbs
2024-07-30 09:41:34 +10:00
committed by GitHub
parent 12e840ee88
commit 7c1aa771aa
18 changed files with 503 additions and 183 deletions

View File

@@ -3,15 +3,9 @@ from esphome.const import CONF_ARGS, CONF_FORMAT, CONF_ID, CONF_STATE, CONF_TYPE
from esphome.schema_extractors import SCHEMA_EXTRACT
from . import defines as df, lv_validation as lvalid, types as ty
from .defines import WIDGET_PARTS
from .helpers import (
REQUIRED_COMPONENTS,
add_lv_use,
requires_component,
validate_printf,
)
from .helpers import add_lv_use, requires_component, validate_printf
from .lv_validation import lv_font
from .types import WIDGET_TYPES, get_widget_type
from .types import WIDGET_TYPES, WidgetType
# A schema for text properties
TEXT_SCHEMA = cv.Schema(
@@ -46,9 +40,9 @@ STYLE_PROPS = {
"bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of,
"bg_grad_dir": df.LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER").one_of,
"bg_grad_stop": lvalid.stop_value,
"bg_img_opa": lvalid.opacity,
"bg_img_recolor": lvalid.lv_color,
"bg_img_recolor_opa": lvalid.opacity,
"bg_image_opa": lvalid.opacity,
"bg_image_recolor": lvalid.lv_color,
"bg_image_recolor_opa": lvalid.opacity,
"bg_main_stop": lvalid.stop_value,
"bg_opa": lvalid.opacity,
"border_color": lvalid.lv_color,
@@ -60,8 +54,8 @@ STYLE_PROPS = {
"border_width": cv.positive_int,
"clip_corner": lvalid.lv_bool,
"height": lvalid.size,
"img_recolor": lvalid.lv_color,
"img_recolor_opa": lvalid.opacity,
"image_recolor": lvalid.lv_color,
"image_recolor_opa": lvalid.opacity,
"line_width": cv.positive_int,
"line_dash_width": cv.positive_int,
"line_dash_gap": cv.positive_int,
@@ -108,12 +102,21 @@ STYLE_PROPS = {
"max_width": lvalid.pixels_or_percent,
"min_height": lvalid.pixels_or_percent,
"min_width": lvalid.pixels_or_percent,
"radius": cv.Any(lvalid.size, df.LvConstant("LV_RADIUS_", "CIRCLE").one_of),
"radius": lvalid.radius,
"width": lvalid.size,
"x": lvalid.pixels_or_percent,
"y": lvalid.pixels_or_percent,
}
STYLE_REMAP = {
"bg_image_opa": "bg_img_opa",
"bg_image_recolor": "bg_img_recolor",
"bg_image_recolor_opa": "bg_img_recolor_opa",
"bg_image_src": "bg_img_src",
"image_recolor": "img_recolor",
"image_recolor_opa": "img_recolor_opa",
}
# Complete object style schema
STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend(
{
@@ -132,25 +135,23 @@ SET_STATE_SCHEMA = cv.Schema(
{cv.Optional(state): lvalid.lv_bool for state in df.STATES}
)
# Setting object flags
FLAG_SCHEMA = cv.Schema({cv.Optional(flag): cv.boolean for flag in df.OBJ_FLAGS})
FLAG_SCHEMA = cv.Schema({cv.Optional(flag): lvalid.lv_bool for flag in df.OBJ_FLAGS})
FLAG_LIST = cv.ensure_list(df.LvConstant("LV_OBJ_FLAG_", *df.OBJ_FLAGS).one_of)
def part_schema(widget_type):
def part_schema(widget_type: WidgetType):
"""
Generate a schema for the various parts (e.g. main:, indicator:) of a widget type
:param widget_type: The type of widget to generate for
:return:
"""
parts = WIDGET_PARTS.get(widget_type)
if parts is None:
parts = (df.CONF_MAIN,)
parts = widget_type.parts
return cv.Schema({cv.Optional(part): STATE_SCHEMA for part in parts}).extend(
STATE_SCHEMA
)
def obj_schema(widget_type: str):
def obj_schema(widget_type: WidgetType):
"""
Create a schema for a widget type itself i.e. no allowance for children
:param widget_type:
@@ -187,13 +188,12 @@ STYLED_TEXT_SCHEMA = cv.maybe_simple_value(
STYLE_SCHEMA.extend(TEXT_SCHEMA), key=df.CONF_TEXT
)
ALL_STYLES = {
**STYLE_PROPS,
}
def container_validator(schema, widget_type):
def container_validator(schema, widget_type: WidgetType):
"""
Create a validator for a container given the widget type
:param schema: Base schema to extend
@@ -203,13 +203,16 @@ def container_validator(schema, widget_type):
def validator(value):
result = schema
if w_sch := WIDGET_TYPES[widget_type].schema:
if w_sch := widget_type.schema:
result = result.extend(w_sch)
if value and (layout := value.get(df.CONF_LAYOUT)):
if not isinstance(layout, dict):
raise cv.Invalid("Layout value must be a dict")
ltype = layout.get(CONF_TYPE)
add_lv_use(ltype)
result = result.extend(
{cv.Optional(df.CONF_WIDGETS): cv.ensure_list(any_widget_schema())}
)
if value == SCHEMA_EXTRACT:
return result
return result(value)
@@ -217,7 +220,7 @@ def container_validator(schema, widget_type):
return validator
def container_schema(widget_type, extras=None):
def container_schema(widget_type: WidgetType, extras=None):
"""
Create a schema for a container widget of a given type. All obj properties are available, plus
the extras passed in, plus any defined for the specific widget being specified.
@@ -225,15 +228,16 @@ def container_schema(widget_type, extras=None):
:param extras: Additional options to be made available, e.g. layout properties for children
:return: The schema for this type of widget.
"""
lv_type = get_widget_type(widget_type)
schema = obj_schema(widget_type).extend({cv.GenerateID(): cv.declare_id(lv_type)})
schema = obj_schema(widget_type).extend(
{cv.GenerateID(): cv.declare_id(widget_type.w_type)}
)
if extras:
schema = schema.extend(extras)
# Delayed evaluation for recursion
return container_validator(schema, widget_type)
def widget_schema(widget_type, extras=None):
def widget_schema(widget_type: WidgetType, extras=None):
"""
Create a schema for a given widget type
:param widget_type: The name of the widget
@@ -241,9 +245,9 @@ def widget_schema(widget_type, extras=None):
:return:
"""
validator = container_schema(widget_type, extras=extras)
if required := REQUIRED_COMPONENTS.get(widget_type):
if required := widget_type.required_component:
validator = cv.All(validator, requires_component(required))
return cv.Exclusive(widget_type, df.CONF_WIDGETS), validator
return cv.Exclusive(widget_type.name, df.CONF_WIDGETS), validator
# All widget schemas must be defined before this is called.
@@ -257,4 +261,4 @@ def any_widget_schema(extras=None):
:param extras: Additional schema to be applied to each generated one
:return:
"""
return cv.Any(dict(widget_schema(wt, extras) for wt in WIDGET_PARTS))
return cv.Any(dict(widget_schema(wt, extras) for wt in WIDGET_TYPES.values()))