[lvgl] Use styles instead of object properties for themes (#9116)

This commit is contained in:
Clyde Stubbs 2025-06-23 12:25:26 +10:00 committed by GitHub
parent 78ec9856fb
commit 41c7852128
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 18 deletions

View File

@ -3,7 +3,6 @@ import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.core import ID from esphome.core import ID
from esphome.cpp_generator import MockObj
from .defines import ( from .defines import (
CONF_STYLE_DEFINITIONS, CONF_STYLE_DEFINITIONS,
@ -13,12 +12,13 @@ from .defines import (
literal, literal,
) )
from .helpers import add_lv_use from .helpers import add_lv_use
from .lvcode import LambdaContext, LocalVariable, lv, lv_assign, lv_variable from .lvcode import LambdaContext, LocalVariable, lv
from .schemas import ALL_STYLES, FULL_STYLE_SCHEMA, STYLE_REMAP from .schemas import ALL_STYLES, FULL_STYLE_SCHEMA, STYLE_REMAP
from .types import ObjUpdateAction, lv_lambda_t, lv_obj_t, lv_obj_t_ptr, lv_style_t from .types import ObjUpdateAction, lv_obj_t, lv_style_t
from .widgets import ( from .widgets import (
Widget, Widget,
add_widgets, add_widgets,
collect_parts,
set_obj_properties, set_obj_properties,
theme_widget_map, theme_widget_map,
wait_for_widgets, wait_for_widgets,
@ -37,12 +37,18 @@ async def style_set(svar, style):
lv.call(f"style_set_{remapped_prop}", svar, literal(value)) lv.call(f"style_set_{remapped_prop}", svar, literal(value))
async def create_style(style, id_name):
style_id = ID(id_name, True, lv_style_t)
svar = cg.new_Pvariable(style_id)
lv.style_init(svar)
await style_set(svar, style)
return svar
async def styles_to_code(config): async def styles_to_code(config):
"""Convert styles to C__ code.""" """Convert styles to C__ code."""
for style in config.get(CONF_STYLE_DEFINITIONS, ()): for style in config.get(CONF_STYLE_DEFINITIONS, ()):
svar = cg.new_Pvariable(style[CONF_ID]) await create_style(style, style[CONF_ID].id)
lv.style_init(svar)
await style_set(svar, style)
@automation.register_action( @automation.register_action(
@ -68,16 +74,18 @@ async def theme_to_code(config):
if theme := config.get(CONF_THEME): if theme := config.get(CONF_THEME):
add_lv_use(CONF_THEME) add_lv_use(CONF_THEME)
for w_name, style in theme.items(): for w_name, style in theme.items():
if not isinstance(style, dict): # Work around Python 3.10 bug with nested async comprehensions
continue # With Python 3.11 this could be simplified
styles = {}
lname = "lv_theme_apply_" + w_name for part, states in collect_parts(style).items():
apply = lv_variable(lv_lambda_t, lname) styles[part] = {
theme_widget_map[w_name] = apply state: await create_style(
ow = Widget.create("obj", MockObj(ID("obj")), obj_spec) props,
async with LambdaContext([(lv_obj_t_ptr, "obj")], where=w_name) as context: "_lv_theme_style_" + w_name + "_" + part + "_" + state,
await set_obj_properties(ow, style) )
lv_assign(apply, await context.get_lambda()) for state, props in states.items()
}
theme_widget_map[w_name] = styles
async def add_top_layer(lv_component, config): async def add_top_layer(lv_component, config):

View File

@ -6,7 +6,7 @@ from esphome.config_validation import Invalid
from esphome.const import CONF_DEFAULT, CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE from esphome.const import CONF_DEFAULT, CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE
from esphome.core import ID, TimePeriod from esphome.core import ID, TimePeriod
from esphome.coroutine import FakeAwaitable from esphome.coroutine import FakeAwaitable
from esphome.cpp_generator import CallExpression, MockObj from esphome.cpp_generator import MockObj
from ..defines import ( from ..defines import (
CONF_FLEX_ALIGN_CROSS, CONF_FLEX_ALIGN_CROSS,
@ -453,7 +453,17 @@ async def widget_to_code(w_cnfig, w_type: WidgetType, parent):
w = Widget.create(wid, var, spec, w_cnfig) w = Widget.create(wid, var, spec, w_cnfig)
if theme := theme_widget_map.get(w_type): if theme := theme_widget_map.get(w_type):
lv_add(CallExpression(theme, w.obj)) for part, states in theme.items():
part = "LV_PART_" + part.upper()
for state, style in states.items():
state = "LV_STATE_" + state.upper()
if state == "LV_STATE_DEFAULT":
lv_state = literal(part)
elif part == "LV_PART_MAIN":
lv_state = literal(state)
else:
lv_state = join_enums((state, part))
lv.obj_add_style(w.obj, style, lv_state)
await set_obj_properties(w, w_cnfig) await set_obj_properties(w, w_cnfig)
await add_widgets(w, w_cnfig) await add_widgets(w, w_cnfig)
await spec.to_code(w, w_cnfig) await spec.to_code(w, w_cnfig)