[lvgl] Fix align_to directives (#15311)

This commit is contained in:
Clyde Stubbs
2026-03-31 06:25:15 +10:00
committed by GitHub
parent 8561a8c495
commit f25fa71235
6 changed files with 54 additions and 10 deletions
+13 -2
View File
@@ -48,6 +48,7 @@ from esphome.yaml_util import load_yaml
from . import defines as df, helpers, lv_validation as lvalid, widgets
from .automation import focused_widgets, layers_to_code, lvgl_update, refreshed_widgets
from .defines import CONF_ALIGN_TO_LAMBDA_ID
from .encoders import (
ENCODERS_CONFIG,
encoders_to_code,
@@ -69,8 +70,16 @@ from .schemas import (
)
from .styles import styles_to_code, theme_to_code
from .touchscreens import touchscreen_schema, touchscreens_to_code
from .trigger import add_on_boot_triggers, generate_triggers
from .types import IdleTrigger, PlainTrigger, lv_font_t, lv_group_t, lv_style_t, lvgl_ns
from .trigger import add_on_boot_triggers, generate_align_tos, generate_triggers
from .types import (
IdleTrigger,
PlainTrigger,
lv_font_t,
lv_group_t,
lv_lambda_t,
lv_style_t,
lvgl_ns,
)
from .widgets import (
LvScrActType,
Widget,
@@ -345,6 +354,7 @@ async def to_code(configs):
Widget.widgets_completed = True
async with LvContext():
await generate_triggers()
await generate_align_tos(configs[0])
for config in configs:
lv_component = await cg.get_variable(config[CONF_ID])
await generate_page_triggers(config)
@@ -458,6 +468,7 @@ LVGL_SCHEMA = cv.All(
.extend(
{
cv.GenerateID(CONF_ID): cv.declare_id(LvglComponent),
cv.GenerateID(CONF_ALIGN_TO_LAMBDA_ID): cv.declare_id(lv_lambda_t),
cv.GenerateID(df.CONF_DISPLAYS): display_schema,
cv.Optional(CONF_COLOR_DEPTH, default=16): cv.one_of(16),
cv.Optional(
+1
View File
@@ -504,6 +504,7 @@ CONF_ACCEPTED_CHARS = "accepted_chars"
CONF_ADJUSTABLE = "adjustable"
CONF_ALIGN = "align"
CONF_ALIGN_TO = "align_to"
CONF_ALIGN_TO_LAMBDA_ID = "align_to_lambda_id"
CONF_ANGLE_RANGE = "angle_range"
CONF_ANIMATED = "animated"
CONF_ANIMATION = "animation"
+12 -3
View File
@@ -128,10 +128,19 @@ class LvPageType : public Parented<LvglComponent> {
bool skip;
};
using LvLambdaType = std::function<void(lv_obj_t *)>;
using set_value_lambda_t = std::function<void(float)>;
using event_callback_t = void(lv_event_t *);
using text_lambda_t = std::function<const char *()>;
class LvLambdaComponent : public Component {
public:
LvLambdaComponent(void (*callback)()) : callback_(callback) {}
void setup() override { this->callback_(); }
// execute after the LvglComponent is setup
float get_setup_priority() const override { return setup_priority::PROCESSOR - 5; }
protected:
void (*callback_)();
};
template<typename... Ts> class ObjUpdateAction : public Action<Ts...> {
public:
+23 -2
View File
@@ -8,10 +8,13 @@ from esphome.const import (
CONF_X,
CONF_Y,
)
from esphome.cpp_generator import new_Pvariable
from esphome.cpp_helpers import register_component
from .defines import (
CONF_ALIGN,
CONF_ALIGN_TO,
CONF_ALIGN_TO_LAMBDA_ID,
DIRECTIONS,
LV_EVENT_MAP,
LV_EVENT_TRIGGERS,
@@ -89,14 +92,32 @@ async def generate_triggers():
await add_on_boot_triggers(w.config.get(CONF_ON_BOOT, ()))
# Generate align to directives while we're here
if align_to := w.config.get(CONF_ALIGN_TO):
async def generate_align_tos(config: dict):
"""
Called once, with a full lvgl configuration to emit deferred align_to actions as a component
that executes after the LVGL setup. This is required since align_to actions are not recalculated on layout changes
and so must be applied after the display is properly laid out.
:param config:
:return:
"""
align_tos = tuple(
w for w in widget_map.values() if w.config and CONF_ALIGN_TO in w.config
)
if align_tos:
async with LambdaContext(where="align_to") as context:
for w in align_tos:
align_to = w.config[CONF_ALIGN_TO]
target = widget_map[align_to[CONF_ID]].obj
align = literal(align_to[CONF_ALIGN])
x = align_to[CONF_X]
y = align_to[CONF_Y]
lv.obj_align_to(w.obj, target, align, x, y)
action_id = config[CONF_ALIGN_TO_LAMBDA_ID]
var = new_Pvariable(action_id, await context.get_lambda())
await register_component(var, {})
async def add_trigger(conf, w, *events, is_selected=None):
is_selected = is_selected or w.is_selected()
+2 -2
View File
@@ -1,7 +1,7 @@
from esphome import automation, codegen as cg
from esphome.const import CONF_TEXT, CONF_VALUE
from esphome.cpp_generator import MockObj
from esphome.cpp_types import esphome_ns
from esphome.cpp_types import Component, esphome_ns
from .defines import lvgl_ns
@@ -51,7 +51,7 @@ IdleTrigger = lvgl_ns.class_("IdleTrigger", automation.Trigger.template())
ObjUpdateAction = lvgl_ns.class_("ObjUpdateAction", automation.Action)
LvglCondition = lvgl_ns.class_("LvglCondition", automation.Condition)
LvglAction = lvgl_ns.class_("LvglAction", automation.Action)
lv_lambda_t = lvgl_ns.class_("LvLambdaType")
lv_lambda_t = lvgl_ns.class_("LvLambdaComponent", Component)
LvCompound = lvgl_ns.class_("LvCompound")
lv_font_t = cg.global_ns.class_("lv_font_t")
lv_style_t = cg.global_ns.struct("lv_style_t")
+3 -1
View File
@@ -288,7 +288,9 @@ lvgl:
- label:
text: "Hello shiny day"
text_color: 0xFFFFFF
align: bottom_mid
align_to:
id: hello_label
align: OUT_LEFT_TOP
- label:
id: setup_lambda_label
# Test lambda in widget property during setup (LvContext)