[lvgl] Make image update via lambda work (#7886)

This commit is contained in:
Clyde Stubbs 2024-11-28 14:48:48 +11:00 committed by GitHub
parent d305870284
commit c9b0490305
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 52 additions and 28 deletions

View File

@ -8,7 +8,7 @@ import logging
from esphome import codegen as cg, config_validation as cv
from esphome.const import CONF_ITEMS
from esphome.core import Lambda
from esphome.core import ID, Lambda
from esphome.cpp_generator import LambdaExpression, MockObj
from esphome.cpp_types import uint32
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
@ -72,6 +72,12 @@ class LValidator:
)
if self.retmapper is not None:
return self.retmapper(value)
if isinstance(value, ID):
return await cg.get_variable(value)
if isinstance(value, list):
value = [
await cg.get_variable(x) if isinstance(x, ID) else x for x in value
]
return cg.safe_exp(value)

View File

@ -1,6 +1,7 @@
from typing import Union
import esphome.codegen as cg
from esphome.components import image
from esphome.components.color import CONF_HEX, ColorStruct, from_rgbw
from esphome.components.font import Font
from esphome.components.image import Image_
@ -31,7 +32,7 @@ from .defines import (
literal,
)
from .helpers import add_lv_use, esphome_fonts_used, lv_fonts_used, requires_component
from .types import lv_font_t, lv_gradient_t, lv_img_t
from .types import lv_font_t, lv_gradient_t
opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER")
@ -332,8 +333,12 @@ def image_validator(value):
lv_image = LValidator(
image_validator,
lv_img_t,
retmapper=lambda x: MockObj(x, "->").get_lv_img_dsc(),
image.Image_.operator("ptr"),
requires="image",
)
lv_image_list = LValidator(
cv.ensure_list(image_validator),
cg.std_vector.template(image.Image_.operator("ptr")),
requires="image",
)
lv_bool = LValidator(cv.boolean, cg.bool_, retmapper=literal)

View File

@ -57,6 +57,22 @@ inline void lv_img_set_src(lv_obj_t *obj, esphome::image::Image *image) {
lv_img_set_src(obj, image->get_lv_img_dsc());
}
#endif // USE_LVGL_IMAGE
#ifdef USE_LVGL_ANIMIMG
inline void lv_animimg_set_src(lv_obj_t *img, std::vector<image::Image *> images) {
auto *dsc = static_cast<std::vector<lv_img_dsc_t *> *>(lv_obj_get_user_data(img));
if (dsc == nullptr) {
// object will be lazily allocated but never freed.
dsc = new std::vector<lv_img_dsc_t *>(images.size()); // NOLINT
lv_obj_set_user_data(img, dsc);
}
dsc->clear();
for (auto &image : images) {
dsc->push_back(image->get_lv_img_dsc());
}
lv_animimg_set_src(img, (const void **) dsc->data(), dsc->size());
}
#endif // USE_LVGL_ANIMIMG
// Parent class for things that wrap an LVGL object
class LvCompound {

View File

@ -1,20 +1,18 @@
from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_DURATION, CONF_ID
from ..automation import action_to_code
from ..defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC
from ..helpers import lvgl_components_required
from ..lv_validation import lv_image, lv_milliseconds
from ..lv_validation import lv_image_list, lv_milliseconds
from ..lvcode import lv
from ..types import LvType, ObjUpdateAction, void_ptr
from ..types import LvType, ObjUpdateAction
from . import Widget, WidgetType, get_widgets
from .img import CONF_IMAGE
from .label import CONF_LABEL
CONF_ANIMIMG = "animimg"
CONF_SRC_LIST_ID = "src_list_id"
def lv_repeat_count(value):
@ -32,14 +30,14 @@ ANIMIMG_BASE_SCHEMA = cv.Schema(
ANIMIMG_SCHEMA = ANIMIMG_BASE_SCHEMA.extend(
{
cv.Required(CONF_DURATION): lv_milliseconds,
cv.Required(CONF_SRC): cv.ensure_list(lv_image),
cv.GenerateID(CONF_SRC_LIST_ID): cv.declare_id(void_ptr),
cv.Required(CONF_SRC): lv_image_list,
}
)
ANIMIMG_MODIFY_SCHEMA = ANIMIMG_BASE_SCHEMA.extend(
{
cv.Optional(CONF_DURATION): lv_milliseconds,
cv.Optional(CONF_SRC): lv_image_list,
}
)
@ -59,17 +57,14 @@ class AnimimgType(WidgetType):
async def to_code(self, w: Widget, config):
lvgl_components_required.add(CONF_IMAGE)
lvgl_components_required.add(CONF_ANIMIMG)
if CONF_SRC in config:
srcs = [
await lv_image.process(await cg.get_variable(x))
for x in config[CONF_SRC]
]
src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs)
count = len(config[CONF_SRC])
lv.animimg_set_src(w.obj, src_id, count)
lv.animimg_set_repeat_count(w.obj, config[CONF_REPEAT_COUNT])
lv.animimg_set_duration(w.obj, config[CONF_DURATION])
if config.get(CONF_AUTO_START):
if srcs := config.get(CONF_SRC):
srcs = await lv_image_list.process(srcs)
lv.animimg_set_src(w.obj, srcs)
if repeat_count := config.get(CONF_REPEAT_COUNT):
lv.animimg_set_repeat_count(w.obj, repeat_count)
if duration := config.get(CONF_DURATION):
lv.animimg_set_duration(w.obj, duration)
if config[CONF_AUTO_START]:
lv.animimg_start(w.obj)
def get_uses(self):

View File

@ -1,4 +1,3 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_ANGLE, CONF_MODE
@ -65,7 +64,6 @@ class ImgType(WidgetType):
async def to_code(self, w: Widget, config):
if src := config.get(CONF_SRC):
src = await cg.get_variable(src)
lv.img_set_src(w.obj, await lv_image.process(src))
if (cf_angle := config.get(CONF_ANGLE)) is not None:
pivot_x = config[CONF_PIVOT_X]

View File

@ -171,9 +171,13 @@ lvgl:
duration: 1s
auto_start: true
on_all_events:
logger.log:
format: "Event %s"
args: ['lv_event_code_name_for(event->code).c_str()']
- logger.log:
format: "Event %s"
args: ['lv_event_code_name_for(event->code).c_str()']
- lvgl.animimg.update:
id: anim_img
src: !lambda "return {dog_image, cat_image};"
duration: 2s
- label:
id: hello_label
text: Hello world
@ -635,7 +639,7 @@ lvgl:
- image:
grid_cell_row_pos: 0
grid_cell_column_pos: 0
src: dog_image
src: !lambda return dog_image;
on_click:
then:
- lvgl.tabview.select:

View File

@ -55,5 +55,5 @@ lvgl:
packages:
lvgl: !include lvgl-package.yaml
xvgl: !include common.yaml
<<: !include common.yaml