mirror of
https://github.com/esphome/esphome.git
synced 2026-05-22 18:56:40 +08:00
[lvgl] Pass touch point to touch event lambdas (#16272)
This commit is contained in:
@@ -309,6 +309,14 @@ LV_EVENT_MAP = {
|
||||
"STYLE_CHANGE": "STYLE_CHANGED",
|
||||
"TRIPLE_CLICK": "TRIPLE_CLICKED",
|
||||
}
|
||||
|
||||
LV_PRESS_EVENTS = ("PRESS", "PRESSING", "RELEASE")
|
||||
|
||||
|
||||
def is_press_event(event: str) -> bool:
|
||||
return event.removeprefix("on_").upper() in LV_PRESS_EVENTS
|
||||
|
||||
|
||||
LV_SCREEN_EVENT_MAP = {
|
||||
"SCREEN_LOAD": "SCREEN_LOADED",
|
||||
"SCREEN_LOAD_START": "SCREEN_LOAD_START",
|
||||
|
||||
@@ -890,7 +890,21 @@ lv_color_t lv_grad_calculate_color(const lv_grad_dsc_t *dsc, int32_t pos) {
|
||||
int32_t offset = pos - stop1->frac;
|
||||
return lv_color_mix(stop2->color, stop1->color, range == 0 ? 0 : (offset * 255) / range);
|
||||
}
|
||||
#endif
|
||||
#endif // USE_LVGL_GRADIENT
|
||||
|
||||
lv_point_t LvglComponent::get_touch_relative_to_obj(lv_obj_t *obj) {
|
||||
auto *indev = lv_indev_get_act();
|
||||
if (indev == nullptr) {
|
||||
return {INT32_MAX, INT32_MAX};
|
||||
}
|
||||
lv_point_t point;
|
||||
lv_indev_get_point(indev, &point);
|
||||
lv_area_t coords;
|
||||
lv_obj_get_coords(obj, &coords);
|
||||
point.x -= coords.x1;
|
||||
point.y -= coords.y1;
|
||||
return point;
|
||||
}
|
||||
|
||||
static void lv_container_constructor(const lv_obj_class_t *class_p, lv_obj_t *obj) {
|
||||
LV_TRACE_OBJ_CREATE("begin");
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#endif // USE_BINARY_SENSOR
|
||||
#ifdef USE_IMAGE
|
||||
#include "esphome/components/image/image.h"
|
||||
#endif // USE_LVGL_IMAGE
|
||||
#endif // USE_IMAGE
|
||||
#ifdef USE_LVGL_ROTARY_ENCODER
|
||||
#include "esphome/components/rotary_encoder/rotary_encoder.h"
|
||||
#endif // USE_LVGL_ROTARY_ENCODER
|
||||
@@ -32,10 +32,10 @@
|
||||
|
||||
#ifdef USE_FONT
|
||||
#include "esphome/components/font/font.h"
|
||||
#endif // USE_LVGL_FONT
|
||||
#endif // USE_FONT
|
||||
#ifdef USE_TOUCHSCREEN
|
||||
#include "esphome/components/touchscreen/touchscreen.h"
|
||||
#endif // USE_LVGL_TOUCHSCREEN
|
||||
#endif // USE_TOUCHSCREEN
|
||||
|
||||
#if defined(USE_LVGL_BUTTONMATRIX) || defined(USE_LVGL_KEYBOARD)
|
||||
#include "esphome/components/key_provider/key_provider.h"
|
||||
@@ -124,7 +124,8 @@ int16_t lv_get_needle_angle_for_value(lv_obj_t *obj, int32_t value);
|
||||
*/
|
||||
|
||||
lv_color_t lv_grad_calculate_color(const lv_grad_dsc_t *dsc, int32_t pos);
|
||||
#endif
|
||||
#endif // USE_LVGL_GRADIENT
|
||||
|
||||
// Parent class for things that wrap an LVGL object
|
||||
class LvCompound {
|
||||
public:
|
||||
@@ -169,9 +170,9 @@ template<typename... Ts> class ObjUpdateAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit ObjUpdateAction(std::function<void(Ts...)> &&lamb) : lamb_(std::move(lamb)) {}
|
||||
|
||||
protected:
|
||||
void play(const Ts &...x) override { this->lamb_(x...); }
|
||||
|
||||
protected:
|
||||
std::function<void(Ts...)> lamb_;
|
||||
};
|
||||
#ifdef USE_LVGL_ANIMIMG
|
||||
@@ -190,6 +191,12 @@ class LvglComponent : public PollingComponent {
|
||||
LvglComponent(std::vector<display::Display *> displays, float buffer_frac, bool full_refresh, int draw_rounding,
|
||||
bool resume_on_input, bool update_when_display_idle, RotationType rotation_type);
|
||||
static void static_flush_cb(lv_display_t *disp_drv, const lv_area_t *area, uint8_t *color_p);
|
||||
/**
|
||||
*
|
||||
* @param obj A widget
|
||||
* @return The position of the last indev point relative to the widget's origin.
|
||||
*/
|
||||
static lv_point_t get_touch_relative_to_obj(lv_obj_t *obj);
|
||||
|
||||
float get_setup_priority() const override { return setup_priority::PROCESSOR; }
|
||||
void setup() override;
|
||||
@@ -311,9 +318,9 @@ class IdleTrigger : public Trigger<> {
|
||||
template<typename... Ts> class LvglAction : public Action<Ts...>, public Parented<LvglComponent> {
|
||||
public:
|
||||
explicit LvglAction(std::function<void(LvglComponent *)> &&lamb) : action_(std::move(lamb)) {}
|
||||
void play(const Ts &...x) override { this->action_(this->parent_); }
|
||||
|
||||
protected:
|
||||
void play(const Ts &...x) override { this->action_(this->parent_); }
|
||||
std::function<void(LvglComponent *)> action_{};
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ from .defines import (
|
||||
CONF_TIME_FORMAT,
|
||||
LV_GRAD_DIR,
|
||||
get_remapped_uses,
|
||||
is_press_event,
|
||||
)
|
||||
from .helpers import CONF_IF_NAN, requires_component, validate_printf
|
||||
from .layout import (
|
||||
@@ -46,6 +47,7 @@ from .types import (
|
||||
LvType,
|
||||
lv_group_t,
|
||||
lv_obj_t,
|
||||
lv_point_t,
|
||||
lv_pseudo_button_t,
|
||||
lv_style_t,
|
||||
)
|
||||
@@ -370,13 +372,20 @@ def automation_schema(typ: LvType):
|
||||
if typ.has_on_value:
|
||||
events = events + (CONF_ON_VALUE,)
|
||||
args = typ.get_arg_type()
|
||||
args.append(lv_event_t_ptr)
|
||||
|
||||
def get_trigger_args(event):
|
||||
result = args.copy()
|
||||
if is_press_event(event):
|
||||
result.append(lv_point_t)
|
||||
result.append(lv_event_t_ptr)
|
||||
return result
|
||||
|
||||
return {
|
||||
**{
|
||||
cv.Optional(event): validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
Trigger.template(*args)
|
||||
Trigger.template(*get_trigger_args(event))
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -24,6 +24,7 @@ from .defines import (
|
||||
LV_SCREEN_EVENT_MAP,
|
||||
LV_SCREEN_EVENT_TRIGGERS,
|
||||
SWIPE_TRIGGERS,
|
||||
is_press_event,
|
||||
literal,
|
||||
)
|
||||
from .lvcode import (
|
||||
@@ -34,11 +35,10 @@ from .lvcode import (
|
||||
LvConditional,
|
||||
lv,
|
||||
lv_add,
|
||||
lv_event_t_ptr,
|
||||
lv_expr,
|
||||
lvgl_static,
|
||||
)
|
||||
from .types import LV_EVENT
|
||||
from .types import LV_EVENT, lv_point_t
|
||||
from .widgets import LvScrActType, get_screen_active, widget_map
|
||||
|
||||
|
||||
@@ -133,19 +133,24 @@ def _get_event_literal(trigger: str | MockObj) -> MockObj:
|
||||
return literal("LV_EVENT_" + TRIGGER_MAP[trigger.upper()])
|
||||
|
||||
|
||||
async def add_trigger(conf, w, *events, is_selected=None):
|
||||
async def add_trigger(conf, w, *events: str | MockObj, is_selected=None):
|
||||
is_selected = is_selected or w.is_selected()
|
||||
tid = conf[CONF_TRIGGER_ID]
|
||||
trigger = cg.new_Pvariable(tid)
|
||||
args = w.get_args() + [(lv_event_t_ptr, "event")]
|
||||
value = w.get_values()
|
||||
args = w.get_args()
|
||||
value: list = w.get_values()
|
||||
if len(events) == 1 and is_press_event(str(events[0])):
|
||||
# Make the touch point available for selected events
|
||||
args.append((lv_point_t, "point"))
|
||||
value.append(lvgl_static.get_touch_relative_to_obj(w.obj))
|
||||
args.extend(EVENT_ARG)
|
||||
await automation.build_automation(trigger, args, conf)
|
||||
async with LambdaContext(EVENT_ARG, where=tid) as context:
|
||||
with LvConditional(is_selected):
|
||||
lv_add(trigger.trigger(*value, literal("event")))
|
||||
callback = await context.get_lambda()
|
||||
event_literals = [_get_event_literal(event) for event in events]
|
||||
if isinstance(events[0], str) and events[0] in DISPLAY_TRIGGERS:
|
||||
if str(events[0]) in DISPLAY_TRIGGERS:
|
||||
assert len(events) == 1
|
||||
lv.display_add_event_cb(
|
||||
lv_expr.obj_get_display(w.obj), callback, event_literals[0], nullptr
|
||||
|
||||
@@ -70,6 +70,8 @@ lv_image_t = LvType("lv_image_t")
|
||||
lv_gradient_t = LvType("lv_grad_dsc_t")
|
||||
lv_event_t = LvType("lv_event_t")
|
||||
RotationType = lvgl_ns.enum("RotationType")
|
||||
lv_point_t = cg.global_ns.struct("lv_point_t")
|
||||
lv_point_precise_t = cg.global_ns.struct("lv_point_precise_t")
|
||||
|
||||
LV_EVENT = MockObj(base="LV_EVENT_", op="")
|
||||
LV_STATE = MockObj(base="LV_STATE_", op="")
|
||||
|
||||
@@ -366,7 +366,7 @@ class Widget:
|
||||
|
||||
def get_args(self):
|
||||
if isinstance(self.type.w_type, LvType):
|
||||
return self.type.w_type.args
|
||||
return self.type.w_type.args.copy()
|
||||
return [(lv_obj_t_ptr, "obj")]
|
||||
|
||||
def get_value(self):
|
||||
|
||||
@@ -57,10 +57,9 @@ from ..lv_validation import (
|
||||
)
|
||||
from ..lvcode import LocalVariable, lv, lv_assign, lv_expr
|
||||
from ..schemas import STYLE_PROPS, TEXT_SCHEMA, point_schema, remap_property
|
||||
from ..types import LvType, ObjUpdateAction
|
||||
from ..types import LvType, ObjUpdateAction, lv_point_precise_t
|
||||
from . import Widget, WidgetType, get_widgets
|
||||
from .img import CONF_IMAGE
|
||||
from .line import lv_point_precise_t
|
||||
|
||||
CONF_CANVAS = "canvas"
|
||||
CONF_BUFFER_ID = "buffer_id"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_X, CONF_Y
|
||||
|
||||
@@ -13,9 +12,6 @@ CONF_LINE = "line"
|
||||
CONF_POINTS = "points"
|
||||
CONF_POINT_LIST_ID = "point_list_id"
|
||||
|
||||
lv_point_t = cg.global_ns.struct("lv_point_t")
|
||||
lv_point_precise_t = cg.global_ns.struct("lv_point_precise_t")
|
||||
|
||||
|
||||
class LineType(WidgetType):
|
||||
def __init__(self):
|
||||
|
||||
@@ -649,11 +649,15 @@ lvgl:
|
||||
on_scroll_begin:
|
||||
logger.log: Button clicked
|
||||
on_release:
|
||||
logger.log: Button clicked
|
||||
logger.log:
|
||||
format: Button released at %d/%d
|
||||
args: [point.x, point.y]
|
||||
on_long_press_repeat:
|
||||
logger.log: Button clicked
|
||||
on_pressing:
|
||||
logger.log: Button pressing
|
||||
logger.log:
|
||||
format: Button pressing at %d/%d
|
||||
args: [point.x, point.y]
|
||||
on_press_lost:
|
||||
logger.log: Button press lost
|
||||
on_single_click:
|
||||
@@ -925,6 +929,10 @@ lvgl:
|
||||
value: !lambda |-
|
||||
static float yyy = 83.0;
|
||||
return yyy + .8;
|
||||
on_release:
|
||||
logger.log:
|
||||
format: Slider released at %d/%d with value %.0f
|
||||
args: [point.x, point.y, x]
|
||||
- button:
|
||||
styles: spin_button
|
||||
id: spin_up
|
||||
|
||||
Reference in New Issue
Block a user