mirror of
https://github.com/esphome/esphome.git
synced 2025-07-24 12:16:35 +00:00
[lvgl] Make line points templatable (#8502)
This commit is contained in:
parent
1c72fd4674
commit
6240bfff97
@ -375,6 +375,7 @@ async def to_code(configs):
|
||||
add_define("LV_COLOR_SCREEN_TRANSP", "1")
|
||||
for use in helpers.lv_uses:
|
||||
add_define(f"LV_USE_{use.upper()}")
|
||||
cg.add_define(f"USE_LVGL_{use.upper()}")
|
||||
lv_conf_h_file = CORE.relative_src_path(LV_CONF_FILENAME)
|
||||
write_file_if_changed(lv_conf_h_file, generate_lv_conf_h())
|
||||
cg.add_build_flag("-DLV_CONF_H=1")
|
||||
|
@ -17,6 +17,7 @@ from .defines import (
|
||||
CONF_SHOW_SNOW,
|
||||
PARTS,
|
||||
literal,
|
||||
static_cast,
|
||||
)
|
||||
from .lv_validation import lv_bool, lv_color, lv_image, opacity
|
||||
from .lvcode import (
|
||||
@ -32,7 +33,6 @@ from .lvcode import (
|
||||
lv_expr,
|
||||
lv_obj,
|
||||
lvgl_comp,
|
||||
static_cast,
|
||||
)
|
||||
from .schemas import DISP_BG_SCHEMA, LIST_ACTION_SCHEMA, LVGL_SCHEMA, base_update_schema
|
||||
from .types import (
|
||||
|
@ -35,6 +35,10 @@ def literal(arg):
|
||||
return arg
|
||||
|
||||
|
||||
def static_cast(type, value):
|
||||
return literal(f"static_cast<{type}>({value})")
|
||||
|
||||
|
||||
def call_lambda(lamb: LambdaExpression):
|
||||
expr = lamb.content.strip()
|
||||
if expr.startswith("return") and expr.endswith(";"):
|
||||
|
@ -285,10 +285,6 @@ class LvExpr(MockLv):
|
||||
pass
|
||||
|
||||
|
||||
def static_cast(type, value):
|
||||
return literal(f"static_cast<{type}>({value})")
|
||||
|
||||
|
||||
# Top level mock for generic lv_ calls to be recorded
|
||||
lv = MockLv("lv_")
|
||||
# Just generate an expression
|
||||
|
@ -90,6 +90,7 @@ inline void lv_animimg_set_src(lv_obj_t *img, std::vector<image::Image *> images
|
||||
// Parent class for things that wrap an LVGL object
|
||||
class LvCompound {
|
||||
public:
|
||||
virtual ~LvCompound() = default;
|
||||
virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; }
|
||||
lv_obj_t *obj{};
|
||||
};
|
||||
@ -330,6 +331,19 @@ class LVEncoderListener : public Parented<LvglComponent> {
|
||||
};
|
||||
#endif // USE_LVGL_KEY_LISTENER
|
||||
|
||||
#ifdef USE_LVGL_LINE
|
||||
class LvLineType : public LvCompound {
|
||||
public:
|
||||
std::vector<lv_point_t> get_points() { return this->points_; }
|
||||
void set_points(std::vector<lv_point_t> points) {
|
||||
this->points_ = std::move(points);
|
||||
lv_line_set_points(this->obj, this->points_.data(), this->points_.size());
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<lv_point_t> points_{};
|
||||
};
|
||||
#endif
|
||||
#if defined(USE_LVGL_DROPDOWN) || defined(LV_USE_ROLLER)
|
||||
class LvSelectable : public LvCompound {
|
||||
public:
|
||||
|
@ -19,7 +19,7 @@ from esphome.core.config import StartupTrigger
|
||||
from esphome.schema_extractors import SCHEMA_EXTRACT
|
||||
|
||||
from . import defines as df, lv_validation as lvalid
|
||||
from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR
|
||||
from .defines import CONF_TIME_FORMAT, CONF_X, CONF_Y, LV_GRAD_DIR
|
||||
from .helpers import add_lv_use, requires_component, validate_printf
|
||||
from .lv_validation import lv_color, lv_font, lv_gradient, lv_image, opacity
|
||||
from .lvcode import LvglComponent, lv_event_t_ptr
|
||||
@ -87,6 +87,33 @@ ENCODER_SCHEMA = cv.Schema(
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def point_shorthand(value):
|
||||
"""
|
||||
A shorthand for a point in the form of x,y
|
||||
:param value: The value to check
|
||||
:return: The value as a tuple of x,y
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
try:
|
||||
x, y = map(int, value.split(","))
|
||||
return {CONF_X: x, CONF_Y: y}
|
||||
except ValueError:
|
||||
pass
|
||||
raise cv.Invalid("Invalid point format, should be <x_value>, <y_value>")
|
||||
|
||||
|
||||
POINT_SCHEMA = cv.Any(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_X): cv.templatable(cv.int_),
|
||||
cv.Required(CONF_Y): cv.templatable(cv.int_),
|
||||
}
|
||||
),
|
||||
point_shorthand,
|
||||
)
|
||||
|
||||
|
||||
# All LVGL styles and their validators
|
||||
STYLE_PROPS = {
|
||||
"align": df.CHILD_ALIGNMENTS.one_of,
|
||||
|
@ -1,11 +1,11 @@
|
||||
import functools
|
||||
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.core import Lambda
|
||||
|
||||
from ..defines import CONF_MAIN
|
||||
from ..lvcode import lv
|
||||
from ..types import LvType
|
||||
from ..defines import CONF_MAIN, CONF_X, CONF_Y, call_lambda
|
||||
from ..lvcode import lv_add
|
||||
from ..schemas import POINT_SCHEMA
|
||||
from ..types import LvCompound, LvType
|
||||
from . import Widget, WidgetType
|
||||
|
||||
CONF_LINE = "line"
|
||||
@ -15,47 +15,37 @@ CONF_POINT_LIST_ID = "point_list_id"
|
||||
lv_point_t = cg.global_ns.struct("lv_point_t")
|
||||
|
||||
|
||||
def point_list(il):
|
||||
il = cv.string(il)
|
||||
nl = il.replace(" ", "").split(",")
|
||||
return [int(n) for n in nl]
|
||||
|
||||
|
||||
def cv_point_list(value):
|
||||
if not isinstance(value, list):
|
||||
raise cv.Invalid("List of points required")
|
||||
values = [point_list(v) for v in value]
|
||||
if not functools.reduce(lambda f, v: f and len(v) == 2, values, True):
|
||||
raise cv.Invalid("Points must be a list of x,y integer pairs")
|
||||
return values
|
||||
|
||||
|
||||
LINE_SCHEMA = {
|
||||
cv.Required(CONF_POINTS): cv_point_list,
|
||||
cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t),
|
||||
cv.Required(CONF_POINTS): cv.ensure_list(POINT_SCHEMA),
|
||||
}
|
||||
|
||||
LINE_MODIFY_SCHEMA = {
|
||||
cv.Optional(CONF_POINTS): cv_point_list,
|
||||
cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t),
|
||||
}
|
||||
|
||||
async def process_coord(coord):
|
||||
if isinstance(coord, Lambda):
|
||||
coord = call_lambda(
|
||||
await cg.process_lambda(coord, (), return_type="lv_coord_t")
|
||||
)
|
||||
if not coord.endswith("()"):
|
||||
coord = f"static_cast<lv_coord_t>({coord})"
|
||||
return cg.RawExpression(coord)
|
||||
return cg.safe_exp(coord)
|
||||
|
||||
|
||||
class LineType(WidgetType):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
CONF_LINE,
|
||||
LvType("lv_line_t"),
|
||||
LvType("LvLineType", parents=(LvCompound,)),
|
||||
(CONF_MAIN,),
|
||||
LINE_SCHEMA,
|
||||
modify_schema=LINE_MODIFY_SCHEMA,
|
||||
)
|
||||
|
||||
async def to_code(self, w: Widget, config):
|
||||
"""For a line object, create and add the points"""
|
||||
if data := config.get(CONF_POINTS):
|
||||
points = cg.static_const_array(config[CONF_POINT_LIST_ID], data)
|
||||
lv.line_set_points(w.obj, points, len(data))
|
||||
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()
|
||||
|
@ -614,6 +614,8 @@ lvgl:
|
||||
align: center
|
||||
points:
|
||||
- 5, 5
|
||||
- x: !lambda return random_uint32() % 100;
|
||||
y: !lambda return random_uint32() % 100;
|
||||
- 70, 70
|
||||
- 120, 10
|
||||
- 180, 60
|
||||
@ -622,6 +624,14 @@ lvgl:
|
||||
- lvgl.line.update:
|
||||
id: lv_line_id
|
||||
line_color: 0xFFFF
|
||||
points:
|
||||
- 5, 5
|
||||
- x: !lambda return random_uint32() % 100;
|
||||
y: !lambda return random_uint32() % 100;
|
||||
- 70, 70
|
||||
- 120, 10
|
||||
- 180, 60
|
||||
- 240, 10
|
||||
- lvgl.page.next:
|
||||
- switch:
|
||||
align: right_mid
|
||||
|
Loading…
x
Reference in New Issue
Block a user