mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[lvgl] Make line points templatable (#8502)
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user