mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	[lvgl] Add lvgl.widget.focus action and related triggers. (#7315)
This commit is contained in:
		| @@ -21,8 +21,8 @@ from esphome.final_validate import full_config | ||||
| from esphome.helpers import write_file_if_changed | ||||
|  | ||||
| from . import defines as df, helpers, lv_validation as lvalid | ||||
| from .automation import disp_update, update_to_code | ||||
| from .defines import CONF_SKIP | ||||
| from .automation import disp_update, focused_widgets, update_to_code | ||||
| from .defines import CONF_ADJUSTABLE, CONF_SKIP | ||||
| from .encoders import ENCODERS_CONFIG, encoders_to_code, initial_focus_to_code | ||||
| from .lv_validation import lv_bool, lv_images_used | ||||
| from .lvcode import LvContext, LvglComponent | ||||
| @@ -67,7 +67,7 @@ from .widgets.lv_bar import bar_spec | ||||
| from .widgets.meter import meter_spec | ||||
| from .widgets.msgbox import MSGBOX_SCHEMA, msgboxes_to_code | ||||
| from .widgets.obj import obj_spec | ||||
| from .widgets.page import add_pages, page_spec | ||||
| from .widgets.page import add_pages, generate_page_triggers, page_spec | ||||
| from .widgets.roller import roller_spec | ||||
| from .widgets.slider import slider_spec | ||||
| from .widgets.spinbox import spinbox_spec | ||||
| @@ -182,6 +182,14 @@ def final_validation(config): | ||||
|             raise cv.Invalid( | ||||
|                 "Using RGBA or RGB24 in image config not compatible with LVGL", path | ||||
|             ) | ||||
|     for w in focused_widgets: | ||||
|         path = global_config.get_path_for_id(w) | ||||
|         widget_conf = global_config.get_config_for_path(path[:-1]) | ||||
|         if CONF_ADJUSTABLE in widget_conf and not widget_conf[CONF_ADJUSTABLE]: | ||||
|             raise cv.Invalid( | ||||
|                 "A non adjustable arc may not be focused", | ||||
|                 path, | ||||
|             ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
| @@ -271,6 +279,7 @@ async def to_code(config): | ||||
|     Widget.set_completed() | ||||
|     async with LvContext(lv_component): | ||||
|         await generate_triggers(lv_component) | ||||
|         await generate_page_triggers(lv_component, config) | ||||
|         for conf in config.get(CONF_ON_IDLE, ()): | ||||
|             templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32) | ||||
|             idle_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, templ) | ||||
|   | ||||
| @@ -4,13 +4,15 @@ from typing import Callable | ||||
| from esphome import automation | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID, CONF_TIMEOUT | ||||
| from esphome.cpp_generator import RawExpression | ||||
| from esphome.const import CONF_ACTION, CONF_GROUP, CONF_ID, CONF_TIMEOUT | ||||
| from esphome.cpp_generator import RawExpression, get_variable | ||||
| from esphome.cpp_types import nullptr | ||||
|  | ||||
| from .defines import ( | ||||
|     CONF_DISP_BG_COLOR, | ||||
|     CONF_DISP_BG_IMAGE, | ||||
|     CONF_EDITING, | ||||
|     CONF_FREEZE, | ||||
|     CONF_LVGL_ID, | ||||
|     CONF_SHOW_SNOW, | ||||
|     literal, | ||||
| @@ -30,6 +32,7 @@ from .lvcode import ( | ||||
|     lv_expr, | ||||
|     lv_obj, | ||||
|     lvgl_comp, | ||||
|     static_cast, | ||||
| ) | ||||
| from .schemas import DISP_BG_SCHEMA, LIST_ACTION_SCHEMA, LVGL_SCHEMA | ||||
| from .types import ( | ||||
| @@ -38,7 +41,9 @@ from .types import ( | ||||
|     LvglCondition, | ||||
|     ObjUpdateAction, | ||||
|     lv_disp_t, | ||||
|     lv_group_t, | ||||
|     lv_obj_t, | ||||
|     lv_pseudo_button_t, | ||||
| ) | ||||
| from .widgets import ( | ||||
|     Widget, | ||||
| @@ -48,6 +53,9 @@ from .widgets import ( | ||||
|     wait_for_widgets, | ||||
| ) | ||||
|  | ||||
| # Record widgets that are used in a focused action here | ||||
| focused_widgets = set() | ||||
|  | ||||
|  | ||||
| async def action_to_code( | ||||
|     widgets: list[Widget], | ||||
| @@ -234,3 +242,72 @@ async def obj_show_to_code(config, action_id, template_arg, args): | ||||
|     return await action_to_code( | ||||
|         await get_widgets(config), do_show, action_id, template_arg, args | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def focused_id(value): | ||||
|     value = cv.use_id(lv_pseudo_button_t)(value) | ||||
|     focused_widgets.add(value) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| @automation.register_action( | ||||
|     "lvgl.widget.focus", | ||||
|     ObjUpdateAction, | ||||
|     cv.Any( | ||||
|         cv.maybe_simple_value( | ||||
|             { | ||||
|                 cv.Optional(CONF_GROUP): cv.use_id(lv_group_t), | ||||
|                 cv.Required(CONF_ACTION): cv.one_of( | ||||
|                     "MARK", "RESTORE", "NEXT", "PREVIOUS", upper=True | ||||
|                 ), | ||||
|                 cv.GenerateID(CONF_LVGL_ID): cv.use_id(LvglComponent), | ||||
|                 cv.Optional(CONF_FREEZE, default=False): cv.boolean, | ||||
|             }, | ||||
|             key=CONF_ACTION, | ||||
|         ), | ||||
|         cv.maybe_simple_value( | ||||
|             { | ||||
|                 cv.Required(CONF_ID): focused_id, | ||||
|                 cv.Optional(CONF_FREEZE, default=False): cv.boolean, | ||||
|                 cv.Optional(CONF_EDITING, default=False): cv.boolean, | ||||
|             }, | ||||
|             key=CONF_ID, | ||||
|         ), | ||||
|     ), | ||||
| ) | ||||
| async def widget_focus(config, action_id, template_arg, args): | ||||
|     widget = await get_widgets(config) | ||||
|     if widget: | ||||
|         widget = widget[0] | ||||
|         group = static_cast( | ||||
|             lv_group_t.operator("ptr"), lv_expr.obj_get_group(widget.obj) | ||||
|         ) | ||||
|     elif group := config.get(CONF_GROUP): | ||||
|         group = await get_variable(group) | ||||
|     else: | ||||
|         group = lv_expr.group_get_default() | ||||
|  | ||||
|     async with LambdaContext(parameters=args, where=action_id) as context: | ||||
|         if widget: | ||||
|             lv.group_focus_freeze(group, False) | ||||
|             lv.group_focus_obj(widget.obj) | ||||
|             if config[CONF_EDITING]: | ||||
|                 lv.group_set_editing(group, True) | ||||
|         else: | ||||
|             action = config[CONF_ACTION] | ||||
|             lv_comp = await get_variable(config[CONF_LVGL_ID]) | ||||
|             if action == "MARK": | ||||
|                 context.add(lv_comp.set_focus_mark(group)) | ||||
|             else: | ||||
|                 lv.group_focus_freeze(group, False) | ||||
|                 if action == "RESTORE": | ||||
|                     context.add(lv_comp.restore_focus_mark(group)) | ||||
|                 elif action == "NEXT": | ||||
|                     lv.group_focus_next(group) | ||||
|                 else: | ||||
|                     lv.group_focus_prev(group) | ||||
|  | ||||
|         if config[CONF_FREEZE]: | ||||
|             lv.group_focus_freeze(group, True) | ||||
|         var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) | ||||
|         return var | ||||
|   | ||||
| @@ -148,6 +148,7 @@ LV_EVENT_MAP = { | ||||
|     "DEFOCUS": "DEFOCUSED", | ||||
|     "READY": "READY", | ||||
|     "CANCEL": "CANCEL", | ||||
|     "ALL_EVENTS": "ALL", | ||||
| } | ||||
|  | ||||
| LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT_MAP) | ||||
| @@ -390,6 +391,7 @@ CONF_DEFAULT_FONT = "default_font" | ||||
| CONF_DEFAULT_GROUP = "default_group" | ||||
| CONF_DIR = "dir" | ||||
| CONF_DISPLAYS = "displays" | ||||
| CONF_EDITING = "editing" | ||||
| CONF_ENCODERS = "encoders" | ||||
| CONF_END_ANGLE = "end_angle" | ||||
| CONF_END_VALUE = "end_value" | ||||
| @@ -401,6 +403,7 @@ CONF_FLEX_ALIGN_MAIN = "flex_align_main" | ||||
| CONF_FLEX_ALIGN_CROSS = "flex_align_cross" | ||||
| CONF_FLEX_ALIGN_TRACK = "flex_align_track" | ||||
| CONF_FLEX_GROW = "flex_grow" | ||||
| CONF_FREEZE = "freeze" | ||||
| CONF_FULL_REFRESH = "full_refresh" | ||||
| CONF_GRID_CELL_ROW_POS = "grid_cell_row_pos" | ||||
| CONF_GRID_CELL_COLUMN_POS = "grid_cell_column_pos" | ||||
| @@ -428,9 +431,9 @@ CONF_MSGBOXES = "msgboxes" | ||||
| CONF_OBJ = "obj" | ||||
| CONF_OFFSET_X = "offset_x" | ||||
| CONF_OFFSET_Y = "offset_y" | ||||
| CONF_ONE_CHECKED = "one_checked" | ||||
| CONF_ONE_LINE = "one_line" | ||||
| CONF_ON_SELECT = "on_select" | ||||
| CONF_ONE_CHECKED = "one_checked" | ||||
| CONF_NEXT = "next" | ||||
| CONF_PAD_ROW = "pad_row" | ||||
| CONF_PAD_COLUMN = "pad_column" | ||||
|   | ||||
| @@ -28,7 +28,7 @@ LVGL_COMP = "lv_component"  # used as a lambda argument in lvgl_comp() | ||||
| LvglComponent = lvgl_ns.class_("LvglComponent", cg.PollingComponent) | ||||
| LVGL_COMP_ARG = [(LvglComponent.operator("ptr"), LVGL_COMP)] | ||||
| lv_event_t_ptr = cg.global_ns.namespace("lv_event_t").operator("ptr") | ||||
| EVENT_ARG = [(lv_event_t_ptr, "ev")] | ||||
| EVENT_ARG = [(lv_event_t_ptr, "event")] | ||||
| # Two custom events; API_EVENT is fired when an entity is updated remotely by an API interaction; | ||||
| # UPDATE_EVENT is fired when an entity is programmatically updated locally. | ||||
| # VALUE_CHANGED is the event generated by LVGL when an entity's value changes through user interaction. | ||||
| @@ -291,6 +291,10 @@ 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 | ||||
|   | ||||
| @@ -15,6 +15,60 @@ static void log_cb(const char *buf) { | ||||
| } | ||||
| #endif  // LV_USE_LOG | ||||
|  | ||||
| static const char *const EVENT_NAMES[] = { | ||||
|     "NONE", | ||||
|     "PRESSED", | ||||
|     "PRESSING", | ||||
|     "PRESS_LOST", | ||||
|     "SHORT_CLICKED", | ||||
|     "LONG_PRESSED", | ||||
|     "LONG_PRESSED_REPEAT", | ||||
|     "CLICKED", | ||||
|     "RELEASED", | ||||
|     "SCROLL_BEGIN", | ||||
|     "SCROLL_END", | ||||
|     "SCROLL", | ||||
|     "GESTURE", | ||||
|     "KEY", | ||||
|     "FOCUSED", | ||||
|     "DEFOCUSED", | ||||
|     "LEAVE", | ||||
|     "HIT_TEST", | ||||
|     "COVER_CHECK", | ||||
|     "REFR_EXT_DRAW_SIZE", | ||||
|     "DRAW_MAIN_BEGIN", | ||||
|     "DRAW_MAIN", | ||||
|     "DRAW_MAIN_END", | ||||
|     "DRAW_POST_BEGIN", | ||||
|     "DRAW_POST", | ||||
|     "DRAW_POST_END", | ||||
|     "DRAW_PART_BEGIN", | ||||
|     "DRAW_PART_END", | ||||
|     "VALUE_CHANGED", | ||||
|     "INSERT", | ||||
|     "REFRESH", | ||||
|     "READY", | ||||
|     "CANCEL", | ||||
|     "DELETE", | ||||
|     "CHILD_CHANGED", | ||||
|     "CHILD_CREATED", | ||||
|     "CHILD_DELETED", | ||||
|     "SCREEN_UNLOAD_START", | ||||
|     "SCREEN_LOAD_START", | ||||
|     "SCREEN_LOADED", | ||||
|     "SCREEN_UNLOADED", | ||||
|     "SIZE_CHANGED", | ||||
|     "STYLE_CHANGED", | ||||
|     "LAYOUT_CHANGED", | ||||
|     "GET_SELF_SIZE", | ||||
| }; | ||||
|  | ||||
| std::string lv_event_code_name_for(uint8_t event_code) { | ||||
|   if (event_code < sizeof(EVENT_NAMES) / sizeof(EVENT_NAMES[0])) { | ||||
|     return EVENT_NAMES[event_code]; | ||||
|   } | ||||
|   return str_sprintf("%2d", event_code); | ||||
| } | ||||
| static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) { | ||||
|   // make sure all coordinates are even | ||||
|   if (area->x1 & 1) | ||||
|   | ||||
| @@ -40,6 +40,7 @@ namespace lvgl { | ||||
|  | ||||
| extern lv_event_code_t lv_api_event;     // NOLINT | ||||
| extern lv_event_code_t lv_update_event;  // NOLINT | ||||
| extern std::string lv_event_code_name_for(uint8_t event_code); | ||||
| extern bool lv_is_pre_initialise(); | ||||
| #ifdef USE_LVGL_COLOR | ||||
| inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); } | ||||
| @@ -143,6 +144,13 @@ class LvglComponent : public PollingComponent { | ||||
|   void show_next_page(lv_scr_load_anim_t anim, uint32_t time); | ||||
|   void show_prev_page(lv_scr_load_anim_t anim, uint32_t time); | ||||
|   void set_page_wrap(bool wrap) { this->page_wrap_ = wrap; } | ||||
|   void set_focus_mark(lv_group_t *group) { this->focus_marks_[group] = lv_group_get_focused(group); } | ||||
|   void restore_focus_mark(lv_group_t *group) { | ||||
|     auto *mark = this->focus_marks_[group]; | ||||
|     if (mark != nullptr) { | ||||
|       lv_group_focus_obj(mark); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   void write_random_(); | ||||
| @@ -158,6 +166,7 @@ class LvglComponent : public PollingComponent { | ||||
|   bool show_snow_{}; | ||||
|   lv_coord_t snow_line_{}; | ||||
|   bool page_wrap_{true}; | ||||
|   std::map<lv_group_t *, lv_obj_t *> focus_marks_{}; | ||||
|  | ||||
|   std::vector<std::function<void(LvglComponent *lv_component)>> init_lambdas_; | ||||
|   CallbackManager<void(uint32_t)> idle_callbacks_{}; | ||||
|   | ||||
| @@ -20,7 +20,7 @@ from . import defines as df, lv_validation as lvalid | ||||
| from .defines import CONF_TIME_FORMAT | ||||
| from .helpers import add_lv_use, requires_component, validate_printf | ||||
| from .lv_validation import lv_color, lv_font, lv_image | ||||
| from .lvcode import LvglComponent | ||||
| from .lvcode import LvglComponent, lv_event_t_ptr | ||||
| from .types import ( | ||||
|     LVEncoderListener, | ||||
|     LvType, | ||||
| @@ -215,14 +215,12 @@ def automation_schema(typ: LvType): | ||||
|         events = df.LV_EVENT_TRIGGERS + (CONF_ON_VALUE,) | ||||
|     else: | ||||
|         events = df.LV_EVENT_TRIGGERS | ||||
|     if isinstance(typ, LvType): | ||||
|         template = Trigger.template(typ.get_arg_type()) | ||||
|     else: | ||||
|         template = Trigger.template() | ||||
|     args = [typ.get_arg_type()] if isinstance(typ, LvType) else [] | ||||
|     args.append(lv_event_t_ptr) | ||||
|     return { | ||||
|         cv.Optional(event): validate_automation( | ||||
|             { | ||||
|                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(template), | ||||
|                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger.template(*args)), | ||||
|             } | ||||
|         ) | ||||
|         for event in events | ||||
|   | ||||
| @@ -19,6 +19,7 @@ from .lvcode import ( | ||||
|     LvConditional, | ||||
|     lv, | ||||
|     lv_add, | ||||
|     lv_event_t_ptr, | ||||
| ) | ||||
| from .types import LV_EVENT | ||||
| from .widgets import widget_map | ||||
| @@ -65,10 +66,10 @@ async def generate_triggers(lv_component): | ||||
| async def add_trigger(conf, lv_component, w, *events): | ||||
|     tid = conf[CONF_TRIGGER_ID] | ||||
|     trigger = cg.new_Pvariable(tid) | ||||
|     args = w.get_args() | ||||
|     args = w.get_args() + [(lv_event_t_ptr, "event")] | ||||
|     value = w.get_value() | ||||
|     await automation.build_automation(trigger, args, conf) | ||||
|     async with LambdaContext(EVENT_ARG, where=tid) as context: | ||||
|         with LvConditional(w.is_selected()): | ||||
|             lv_add(trigger.trigger(value)) | ||||
|             lv_add(trigger.trigger(value, literal("event"))) | ||||
|     lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), *events)) | ||||
|   | ||||
| @@ -57,7 +57,7 @@ lv_group_t = cg.global_ns.struct("lv_group_t") | ||||
| LVTouchListener = lvgl_ns.class_("LVTouchListener") | ||||
| LVEncoderListener = lvgl_ns.class_("LVEncoderListener") | ||||
| lv_obj_t = LvType("lv_obj_t") | ||||
| lv_page_t = cg.global_ns.class_("LvPageType", LvCompound) | ||||
| lv_page_t = LvType("LvPageType", parents=(LvCompound,)) | ||||
| lv_img_t = LvType("lv_img_t") | ||||
|  | ||||
| LV_EVENT = MockObj(base="LV_EVENT_", op="") | ||||
|   | ||||
| @@ -225,7 +225,7 @@ def get_widget_generator(wid): | ||||
|         yield | ||||
|  | ||||
|  | ||||
| async def get_widget_(wid: Widget): | ||||
| async def get_widget_(wid): | ||||
|     if obj := widget_map.get(wid): | ||||
|         return obj | ||||
|     return await FakeAwaitable(get_widget_generator(wid)) | ||||
| @@ -348,8 +348,6 @@ async def set_obj_properties(w: Widget, config): | ||||
|     if group := config.get(CONF_GROUP): | ||||
|         group = await cg.get_variable(group) | ||||
|         lv.group_add_obj(group, w.obj) | ||||
|     flag_clr = set() | ||||
|     flag_set = set() | ||||
|     props = parts[CONF_MAIN][CONF_DEFAULT] | ||||
|     lambs = {} | ||||
|     flag_set = set() | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_GROUP, | ||||
|     CONF_MAX_VALUE, | ||||
|     CONF_MIN_VALUE, | ||||
|     CONF_MODE, | ||||
| @@ -20,7 +21,7 @@ from ..defines import ( | ||||
|     literal, | ||||
| ) | ||||
| from ..lv_validation import angle, get_start_value, lv_float | ||||
| from ..lvcode import lv, lv_obj | ||||
| from ..lvcode import lv, lv_expr, lv_obj | ||||
| from ..types import LvNumber, NumberType | ||||
| from . import Widget | ||||
|  | ||||
| @@ -69,6 +70,9 @@ class ArcType(NumberType): | ||||
|         if config.get(CONF_ADJUSTABLE) is False: | ||||
|             lv_obj.remove_style(w.obj, nullptr, literal("LV_PART_KNOB")) | ||||
|             w.clear_flag("LV_OBJ_FLAG_CLICKABLE") | ||||
|         elif CONF_GROUP not in config: | ||||
|             # For some reason arc does not get automatically added to the default group | ||||
|             lv.group_add_obj(lv_expr.group_get_default(), w.obj) | ||||
|  | ||||
|         value = await get_start_value(config) | ||||
|         if value is not None: | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| from esphome import automation, codegen as cg | ||||
| from esphome.automation import Trigger | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID, CONF_PAGES, CONF_TIME | ||||
| from esphome.const import CONF_ID, CONF_PAGES, CONF_TIME, CONF_TRIGGER_ID | ||||
|  | ||||
| from ..defines import ( | ||||
|     CONF_ANIMATION, | ||||
| @@ -9,12 +10,39 @@ from ..defines import ( | ||||
|     CONF_PAGE_WRAP, | ||||
|     CONF_SKIP, | ||||
|     LV_ANIM, | ||||
|     literal, | ||||
| ) | ||||
| from ..lv_validation import lv_bool, lv_milliseconds | ||||
| from ..lvcode import LVGL_COMP_ARG, LambdaContext, add_line_marks, lv_add, lvgl_comp | ||||
| from ..lvcode import ( | ||||
|     EVENT_ARG, | ||||
|     LVGL_COMP_ARG, | ||||
|     LambdaContext, | ||||
|     add_line_marks, | ||||
|     lv_add, | ||||
|     lvgl_comp, | ||||
| ) | ||||
| from ..schemas import LVGL_SCHEMA | ||||
| from ..types import LvglAction, lv_page_t | ||||
| from . import Widget, WidgetType, add_widgets, set_obj_properties | ||||
| from . import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties | ||||
|  | ||||
| CONF_ON_LOAD = "on_load" | ||||
| CONF_ON_UNLOAD = "on_unload" | ||||
|  | ||||
| PAGE_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.Optional(CONF_SKIP, default=False): lv_bool, | ||||
|         cv.Optional(CONF_ON_LOAD): automation.validate_automation( | ||||
|             { | ||||
|                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger.template()), | ||||
|             } | ||||
|         ), | ||||
|         cv.Optional(CONF_ON_UNLOAD): automation.validate_automation( | ||||
|             { | ||||
|                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger.template()), | ||||
|             } | ||||
|         ), | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| class PageType(WidgetType): | ||||
| @@ -23,9 +51,8 @@ class PageType(WidgetType): | ||||
|             CONF_PAGE, | ||||
|             lv_page_t, | ||||
|             (), | ||||
|             { | ||||
|                 cv.Optional(CONF_SKIP, default=False): lv_bool, | ||||
|             }, | ||||
|             PAGE_SCHEMA, | ||||
|             modify_schema={}, | ||||
|         ) | ||||
|  | ||||
|     async def to_code(self, w: Widget, config: dict): | ||||
| @@ -39,7 +66,6 @@ SHOW_SCHEMA = LVGL_SCHEMA.extend( | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| page_spec = PageType() | ||||
|  | ||||
|  | ||||
| @@ -111,3 +137,21 @@ async def add_pages(lv_component, config): | ||||
|         await set_obj_properties(page, config) | ||||
|         await set_obj_properties(page, pconf) | ||||
|         await add_widgets(page, pconf) | ||||
|  | ||||
|  | ||||
| async def generate_page_triggers(lv_component, config): | ||||
|     for pconf in config.get(CONF_PAGES, ()): | ||||
|         page = (await get_widgets(pconf))[0] | ||||
|         for ev in (CONF_ON_LOAD, CONF_ON_UNLOAD): | ||||
|             for loaded in pconf.get(ev, ()): | ||||
|                 trigger = cg.new_Pvariable(loaded[CONF_TRIGGER_ID]) | ||||
|                 await automation.build_automation(trigger, [], loaded) | ||||
|                 async with LambdaContext(EVENT_ARG, where=id) as context: | ||||
|                     lv_add(trigger.trigger()) | ||||
|                 lv_add( | ||||
|                     lv_component.add_event_cb( | ||||
|                         page.obj, | ||||
|                         await context.get_lambda(), | ||||
|                         literal(f"LV_EVENT_SCREEN_{ev[3:].upper()}_START"), | ||||
|                     ) | ||||
|                 ) | ||||
|   | ||||
| @@ -54,6 +54,17 @@ lvgl: | ||||
|       long_press_time: 500ms | ||||
|   pages: | ||||
|     - id: page1 | ||||
|       on_load: | ||||
|         - logger.log: page loaded | ||||
|         - lvgl.widget.focus: | ||||
|             action: restore | ||||
|       on_unload: | ||||
|         - logger.log: page unloaded | ||||
|         - lvgl.widget.focus: mark | ||||
|       on_all_events: | ||||
|         logger.log: | ||||
|           format: "Event %s" | ||||
|           args: ['lv_event_code_name_for(event->code).c_str()'] | ||||
|       skip: true | ||||
|       layout: | ||||
|         type: flex | ||||
| @@ -70,6 +81,10 @@ lvgl: | ||||
|             repeat_count: 10 | ||||
|             duration: 1s | ||||
|             auto_start: true | ||||
|             on_all_events: | ||||
|               logger.log: | ||||
|                 format: "Event %s" | ||||
|                 args: ['lv_event_code_name_for(event->code).c_str()'] | ||||
|         - label: | ||||
|             id: hello_label | ||||
|             text: Hello world | ||||
| @@ -229,6 +244,16 @@ lvgl: | ||||
|               - label: | ||||
|                   text: Button | ||||
|             on_click: | ||||
|               - lvgl.widget.focus: spin_up | ||||
|               - lvgl.widget.focus: next | ||||
|               - lvgl.widget.focus: previous | ||||
|               - lvgl.widget.focus: | ||||
|                   action: previous | ||||
|                   freeze: true | ||||
|               - lvgl.widget.focus: | ||||
|                   id: spin_up | ||||
|                   freeze: true | ||||
|                   editing: true | ||||
|               - lvgl.label.update: | ||||
|                   id: hello_label | ||||
|                   bg_color: 0x123456 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user