[lvgl] Fixes #3 (#15304)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Clyde Stubbs
2026-04-01 10:04:10 +13:00
committed by GitHub
co-authored by Jesse Hills
parent 2064eef273
commit 66b6d36a26
11 changed files with 48 additions and 68 deletions
+2 -8
View File
@@ -380,7 +380,8 @@ async def to_code(configs):
# This must be done after all widgets are created
for comp in helpers.lvgl_components_required:
cg.add_define(f"USE_LVGL_{comp.upper()}")
lv_image_formats = df.get_color_formats().copy()
# Currently always need RGB565 for the display buffer, and ARGB8888 is used for layer blending
lv_image_formats = {"RGB565", "ARGB8888"}
if {
"transform_rotation",
"transform_scale",
@@ -388,10 +389,6 @@ async def to_code(configs):
"transform_scale_y",
} & styles_used:
df.add_define("LV_COLOR_SCREEN_TRANSP", "1")
lv_image_formats.add("ARGB8888")
lv_image_formats.add(
"RGB565"
) # Currently always need RGB565 for the display buffer
for use in helpers.lv_uses:
df.add_define(f"LV_USE_{use.upper()}")
cg.add_define(f"USE_LVGL_{use.upper()}")
@@ -401,9 +398,6 @@ async def to_code(configs):
metadata = get_image_metadata(image_id.id)
image_type = IMAGE_TYPE[metadata.image_type]
transparent = metadata.transparency != CONF_OPAQUE
if transparent:
# Internal draw layer will use ARGB8888
lv_image_formats.add("ARGB8888")
if image_type == ImageBinary:
lv_image_formats.add("I1")
if image_type == ImageGrayscale:
-4
View File
@@ -52,10 +52,6 @@ def get_remapped_uses():
return get_data(KEY_REMAPPED_USES, set())
def get_color_formats():
return get_data(KEY_COLOR_FORMATS, set())
def add_warning(msg: str):
get_warnings().add(msg)
+4 -27
View File
@@ -4,26 +4,12 @@ import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import ID
from .defines import (
CONF_STYLE_DEFINITIONS,
CONF_THEME,
CONF_TOP_LAYER,
LValidator,
literal,
)
from .defines import CONF_STYLE_DEFINITIONS, CONF_THEME, LValidator, literal
from .helpers import add_lv_use
from .lvcode import LambdaContext, LocalVariable, lv
from .lvcode import LambdaContext, lv
from .schemas import ALL_STYLES, FULL_STYLE_SCHEMA, remap_property
from .types import ObjUpdateAction, lv_obj_t, lv_style_t
from .widgets import (
Widget,
add_widgets,
collect_parts,
set_obj_properties,
theme_widget_map,
wait_for_widgets,
)
from .widgets.obj import obj_spec
from .types import ObjUpdateAction, lv_style_t
from .widgets import collect_parts, theme_widget_map, wait_for_widgets
def has_style_props(config) -> bool:
@@ -112,12 +98,3 @@ async def theme_to_code(config):
for state, props in states.items()
}
theme_widget_map[w_name] = styles
async def add_top_layer(lv_component, config):
top_layer = lv.disp_get_layer_top(lv_component.var.get_disp())
if top_conf := config.get(CONF_TOP_LAYER):
with LocalVariable("top_layer", lv_obj_t, top_layer) as top_layer_obj:
top_w = Widget(top_layer_obj, obj_spec, top_conf)
await set_obj_properties(top_w, top_conf)
await add_widgets(top_w, top_conf)
+5 -2
View File
@@ -1,5 +1,4 @@
import sys
from typing import Any
from esphome import codegen as cg, config_validation as cv
from esphome.automation import register_action
@@ -405,7 +404,11 @@ class Widget:
# Map of widgets to their config, used for trigger generation
widget_map: dict[Any, Widget] = {}
widget_map: dict[ID, Widget] = {}
def is_widget_completed(name: ID) -> bool:
return name in widget_map
class LvScrActType(WidgetType):
@@ -42,7 +42,6 @@ from ..defines import (
CONF_SRC,
CONF_START_ANGLE,
addr,
get_color_formats,
literal,
)
from ..lv_validation import (
@@ -99,7 +98,6 @@ class CanvasType(WidgetType):
# RGB565 is 16-bit (2 bytes per pixel), ARGB8888 is 32-bit (4 bytes per pixel)
if config[CONF_TRANSPARENT]:
color_format = "LV_COLOR_FORMAT_ARGB8888"
get_color_formats().add("ARGB8888")
else:
color_format = "LV_COLOR_FORMAT_NATIVE"
+20 -6
View File
@@ -1,12 +1,15 @@
from esphome.components.key_provider import KeyProvider
import esphome.config_validation as cv
from esphome.const import CONF_ITEMS, CONF_MODE
from esphome.core import CORE
from esphome.cpp_types import std_string
from .. import LvContext
from ..defines import CONF_MAIN, KEYBOARD_MODES, literal
from ..helpers import add_lv_use, lvgl_components_required
from ..helpers import lvgl_components_required
from ..types import LvCompound, LvType
from . import Widget, WidgetType, get_widgets
from . import Widget, WidgetType, get_widgets, is_widget_completed
from .buttonmatrix import CONF_BUTTONMATRIX
from .textarea import CONF_TEXTAREA, lv_textarea_t
CONF_KEYBOARD = "keyboard"
@@ -41,16 +44,27 @@ class KeyboardType(WidgetType):
)
def get_uses(self):
return CONF_KEYBOARD, CONF_TEXTAREA
return CONF_KEYBOARD, CONF_TEXTAREA, CONF_BUTTONMATRIX
async def to_code(self, w: Widget, config: dict):
lvgl_components_required.add("KEY_LISTENER")
lvgl_components_required.add(CONF_KEYBOARD)
add_lv_use("btnmatrix")
if mode := config.get(CONF_MODE):
await w.set_property(CONF_MODE, await KEYBOARD_MODES.process(mode))
if ta := await get_widgets(config, CONF_TEXTAREA):
await w.set_property(CONF_TEXTAREA, ta[0].obj)
if textarea := config.get(CONF_TEXTAREA):
# If a textarea is configured, it must be generated before the keyboard can attach it.
# If not yet configured, defer the attachment code.
async def add_textarea():
async with LvContext():
await w.set_property(
CONF_TEXTAREA, (await get_widgets(config, CONF_TEXTAREA))[0].obj
)
if is_widget_completed(textarea):
await add_textarea()
else:
CORE.add_job(add_textarea)
keyboard_spec = KeyboardType()
+1 -1
View File
@@ -35,7 +35,7 @@ class LabelType(WidgetType):
if (value := config.get(CONF_TEXT)) is not None:
await w.set_property(CONF_TEXT, await lv_text.process(value))
await w.set_property(CONF_LONG_MODE, config)
await w.set_property(CONF_RECOLOR, config)
await w.set_property(CONF_RECOLOR, config, processor=lv_bool)
label_spec = LabelType()
+8 -11
View File
@@ -17,11 +17,6 @@ lv_point_t = cg.global_ns.struct("lv_point_t")
lv_point_precise_t = cg.global_ns.struct("lv_point_precise_t")
LINE_SCHEMA = {
cv.Required(CONF_POINTS): cv.ensure_list(point_schema),
}
async def process_coord(coord):
if isinstance(coord, Lambda):
return call_lambda(await cg.process_lambda(coord, [], return_type=lv_coord_t))
@@ -34,15 +29,17 @@ class LineType(WidgetType):
CONF_LINE,
LvType("LvLineType", parents=(LvCompound,)),
(CONF_MAIN,),
LINE_SCHEMA,
schema={cv.Required(CONF_POINTS): cv.ensure_list(point_schema)},
modify_schema={cv.Optional(CONF_POINTS): cv.ensure_list(point_schema)},
)
async def to_code(self, w: Widget, config):
points = [
[await process_coord(p[CONF_X]), await process_coord(p[CONF_Y])]
for p in config[CONF_POINTS]
]
lv_add(w.var.set_points(points))
if CONF_POINTS in config:
points = [
[await process_coord(p[CONF_X]), await process_coord(p[CONF_Y])]
for p in config[CONF_POINTS]
]
lv_add(w.var.set_points(points))
line_spec = LineType()
+5 -3
View File
@@ -33,6 +33,7 @@ from ..styles import LVStyle
from ..types import LV_EVENT, lv_obj_t
from . import Widget, WidgetType, add_widgets, set_obj_properties, widget_to_code
from .button import button_spec, lv_button_t
from .img import CONF_IMAGE
from .label import CONF_LABEL
from .obj import obj_spec
@@ -41,7 +42,7 @@ CONF_MSGBOX = "msgbox"
OUTER_STYLE = LVStyle(
"msgbox_outer",
{
"bg_opa": 128,
"bg_opa": 0.5,
"bg_color": "black",
"border_width": 0,
"pad_all": 0,
@@ -119,6 +120,7 @@ async def msgbox_to_code(top_layer, conf):
CONF_BUTTON,
CONF_LABEL,
CONF_MSGBOX,
CONF_IMAGE,
*button_spec.get_uses(),
)
if CONF_BUTTON_STYLE in conf:
@@ -156,7 +158,7 @@ async def msgbox_to_code(top_layer, conf):
with LocalVariable(
"close_btn_", lv_obj_t, lv_expr.msgbox_add_close_button(msgbox)
) as close_btn:
lv_obj.remove_event_cb(close_btn, nullptr)
lv_obj.remove_event(close_btn, 0)
lv_obj.add_event_cb(
close_btn,
await close_action.get_lambda(),
@@ -170,6 +172,6 @@ async def msgbox_to_code(top_layer, conf):
async def msgboxes_to_code(lv_component, config):
top_layer = lv.disp_get_layer_top(lv_component.get_disp())
top_layer = lv_expr.disp_get_layer_top(lv_component.get_disp())
for conf in config.get(CONF_MSGBOXES, ()):
await msgbox_to_code(top_layer, conf)
+1 -2
View File
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_SIZE, CONF_TEXT
from ..defines import CONF_MAIN, get_color_formats
from ..defines import CONF_MAIN
from ..lv_validation import color, lv_color, lv_int, lv_text
from ..lvcode import LocalVariable, lv
from ..schemas import TEXT_SCHEMA
@@ -44,7 +44,6 @@ class QrCodeType(WidgetType):
return CONF_CANVAS, CONF_IMAGE
async def to_code(self, w: Widget, config):
get_color_formats().add("ARGB8888")
await w.set_property(
CONF_LIGHT_COLOR, await lv_color.process(config.get(CONF_LIGHT_COLOR))
)
+2 -2
View File
@@ -26,7 +26,7 @@ from ..schemas import container_schema, part_schema
from ..types import LV_EVENT, LvType, ObjUpdateAction, lv_obj_t, lv_obj_t_ptr
from . import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties
from .button import button_spec
from .buttonmatrix import buttonmatrix_spec
from .buttonmatrix import CONF_BUTTONMATRIX, buttonmatrix_spec
from .obj import obj_spec
CONF_TABVIEW = "tabview"
@@ -73,7 +73,7 @@ class TabviewType(WidgetType):
)
def get_uses(self):
return "btnmatrix", TYPE_FLEX
return CONF_BUTTONMATRIX, TYPE_FLEX
async def to_code(self, w: Widget, config: dict):
await w.set_property(