From: Dominik Csapak <d.csapak@proxmox.com>
To: yew-devel@lists.proxmox.com
Subject: [yew-devel] [PATCH yew-widget-toolkit 1/7] touch: gesture detector: introduce `InputEvent`
Date: Tue, 24 Jun 2025 14:19:19 +0200 [thread overview]
Message-ID: <20250624121925.57056-6-d.csapak@proxmox.com> (raw)
In-Reply-To: <20250624121925.57056-1-d.csapak@proxmox.com>
this is an abstracted event for either a PointerEvent or a Touch.
This prepares the interfaces to deal with touch only input.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
Cargo.toml | 1 +
src/touch/gesture_detector.rs | 87 ++++++++++++++++++++++-------------
src/touch/mod.rs | 4 +-
src/touch/side_dialog.rs | 14 +++---
src/touch/slidable/mod.rs | 8 ++--
5 files changed, 67 insertions(+), 47 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 0e919e0..2561436 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -50,6 +50,7 @@ web-sys = { version = "0.3", features = [
"IntersectionObserver",
"IntersectionObserverEntry",
"KeyboardEventInit",
+ "Touch",
] }
js-sys = "0.3"
log = "0.4.6"
diff --git a/src/touch/gesture_detector.rs b/src/touch/gesture_detector.rs
index 2e50e54..0929e01 100644
--- a/src/touch/gesture_detector.rs
+++ b/src/touch/gesture_detector.rs
@@ -3,6 +3,7 @@ use std::collections::HashMap;
use std::rc::Rc;
use gloo_timers::callback::Timeout;
+use web_sys::Touch;
use yew::html::IntoEventCallback;
use yew::prelude::*;
use yew::virtual_dom::{Key, VComp, VNode};
@@ -11,39 +12,64 @@ use crate::impl_to_html;
use crate::props::{ContainerBuilder, EventSubscriber, WidgetBuilder, WidgetStyleBuilder};
use crate::widget::Container;
-/// Like [PointerEvent](web_sys::PointerEvent) (currently no additional features)
-pub struct GestureDragEvent {
- event: PointerEvent,
+/// An event that can happen from a [`PointerEvent`] or a [`Touch`]
+///
+/// For convenience, expose the most important values from the underlying events
+pub enum InputEvent {
+ PointerEvent(PointerEvent),
+ Touch(Touch),
}
-impl GestureDragEvent {
- fn new(event: PointerEvent) -> Self {
- Self { event }
+impl InputEvent {
+ pub fn x(&self) -> i32 {
+ match self {
+ InputEvent::PointerEvent(pointer_event) => pointer_event.client_x(),
+ InputEvent::Touch(touch) => touch.client_x(),
+ }
+ }
+
+ pub fn y(&self) -> i32 {
+ match self {
+ InputEvent::PointerEvent(pointer_event) => pointer_event.client_y(),
+ InputEvent::Touch(touch) => touch.client_y(),
+ }
+ }
+
+ pub fn id(&self) -> i32 {
+ match self {
+ InputEvent::PointerEvent(pointer_event) => pointer_event.pointer_id(),
+ InputEvent::Touch(touch) => touch.identifier(),
+ }
}
}
-impl Deref for GestureDragEvent {
- type Target = PointerEvent;
- fn deref(&self) -> &Self::Target {
- &self.event
+impl From<PointerEvent> for InputEvent {
+ fn from(event: PointerEvent) -> Self {
+ Self::PointerEvent(event)
+ }
+}
+
+impl From<Touch> for InputEvent {
+ fn from(touch: Touch) -> Self {
+ Self::Touch(touch)
}
}
/// Like [PointerEvent](web_sys::PointerEvent), but includes the swipe direction
pub struct GestureSwipeEvent {
- event: PointerEvent,
+ event: InputEvent,
/// Direction angle (from -180 to +180 degree)
pub direction: f64,
}
impl GestureSwipeEvent {
- fn new(event: PointerEvent, direction: f64) -> Self {
+ fn new(event: InputEvent, direction: f64) -> Self {
Self { event, direction }
}
}
impl Deref for GestureSwipeEvent {
- type Target = PointerEvent;
+ type Target = InputEvent;
fn deref(&self) -> &Self::Target {
&self.event
}
@@ -98,20 +124,20 @@ pub struct GestureDetector {
/// Callback for tap events.
#[prop_or_default]
- pub on_tap: Option<Callback<PointerEvent>>,
+ pub on_tap: Option<Callback<InputEvent>>,
/// Callback for long-tap events.
#[prop_or_default]
pub on_long_press: Option<Callback<()>>,
/// Callback for drag-start events.
#[prop_or_default]
- pub on_drag_start: Option<Callback<GestureDragEvent>>,
+ pub on_drag_start: Option<Callback<InputEvent>>,
/// Callback for drag-start events.
#[prop_or_default]
- pub on_drag_update: Option<Callback<GestureDragEvent>>,
+ pub on_drag_update: Option<Callback<InputEvent>>,
/// Callback for drag-start events.
#[prop_or_default]
- pub on_drag_end: Option<Callback<GestureDragEvent>>,
+ pub on_drag_end: Option<Callback<InputEvent>>,
#[prop_or_default]
pub on_swipe: Option<Callback<GestureSwipeEvent>>,
@@ -132,7 +158,7 @@ impl GestureDetector {
}
/// Builder style method to set the on_tap callback
- pub fn on_tap(mut self, cb: impl IntoEventCallback<PointerEvent>) -> Self {
+ pub fn on_tap(mut self, cb: impl IntoEventCallback<InputEvent>) -> Self {
self.on_tap = cb.into_event_callback();
self
}
@@ -144,19 +170,19 @@ impl GestureDetector {
}
/// Builder style method to set the on_drag_start callback
- pub fn on_drag_start(mut self, cb: impl IntoEventCallback<GestureDragEvent>) -> Self {
+ pub fn on_drag_start(mut self, cb: impl IntoEventCallback<InputEvent>) -> Self {
self.on_drag_start = cb.into_event_callback();
self
}
/// Builder style method to set the on_drag_update callback
- pub fn on_drag_update(mut self, cb: impl IntoEventCallback<GestureDragEvent>) -> Self {
+ pub fn on_drag_update(mut self, cb: impl IntoEventCallback<InputEvent>) -> Self {
self.on_drag_update = cb.into_event_callback();
self
}
/// Builder style method to set the on_drag_end callback
- pub fn on_drag_end(mut self, cb: impl IntoEventCallback<GestureDragEvent>) -> Self {
+ pub fn on_drag_end(mut self, cb: impl IntoEventCallback<InputEvent>) -> Self {
self.on_drag_end = cb.into_event_callback();
self
}
@@ -365,7 +391,7 @@ impl PwtGestureDetector {
if !pointer_state.got_tap_timeout && distance < props.tap_tolerance {
if let Some(on_tap) = &props.on_tap {
//log::info!("tap {} {}", event.x(), event.y());
- on_tap.emit(event);
+ on_tap.emit(event.into());
}
}
}
@@ -387,8 +413,7 @@ impl PwtGestureDetector {
self.state = DetectionState::Drag;
self.capture_pointer(event.pointer_id());
if let Some(on_drag_start) = &props.on_drag_start {
- let event = GestureDragEvent::new(event);
- on_drag_start.emit(event);
+ on_drag_start.emit(event.into());
}
}
}
@@ -417,8 +442,7 @@ impl PwtGestureDetector {
self.state = DetectionState::Double;
//log::info!("DRAG END");
if let Some(on_drag_end) = &props.on_drag_end {
- let event = GestureDragEvent::new(event);
- on_drag_end.emit(event);
+ on_drag_end.emit(event.into());
}
}
Msg::PointerUp(event) => {
@@ -437,8 +461,7 @@ impl PwtGestureDetector {
let speed = distance / time_diff;
//log::info!("DRAG END {time_diff} {speed}");
if let Some(on_drag_end) = &props.on_drag_end {
- let event = GestureDragEvent::new(event.clone());
- on_drag_end.emit(event);
+ on_drag_end.emit(event.clone().into());
}
if let Some(on_swipe) = &props.on_swipe {
@@ -453,7 +476,7 @@ impl PwtGestureDetector {
event.y(),
);
- let event = GestureSwipeEvent::new(event, direction);
+ let event = GestureSwipeEvent::new(event.into(), direction);
on_swipe.emit(event)
}
}
@@ -473,8 +496,7 @@ impl PwtGestureDetector {
if distance >= props.tap_tolerance || pointer_state.got_tap_timeout {
//log::info!("DRAG TO {} {}", event.x(), event.y());
if let Some(on_drag_update) = &props.on_drag_update {
- let event = GestureDragEvent::new(event);
- on_drag_update.emit(event);
+ on_drag_update.emit(event.into());
}
}
}
@@ -486,8 +508,7 @@ impl PwtGestureDetector {
self.state = DetectionState::Initial;
//log::info!("DRAG END");
if let Some(on_drag_end) = &props.on_drag_end {
- let event = GestureDragEvent::new(event);
- on_drag_end.emit(event);
+ on_drag_end.emit(event.into());
}
}
}
diff --git a/src/touch/mod.rs b/src/touch/mod.rs
index c33f1f0..87fcc85 100644
--- a/src/touch/mod.rs
+++ b/src/touch/mod.rs
@@ -5,9 +5,7 @@ mod application_bar;
pub use application_bar::{ApplicationBar, PwtApplicationBar};
mod gesture_detector;
-pub use gesture_detector::{
- GestureDetector, GestureDragEvent, GestureSwipeEvent, PwtGestureDetector,
-};
+pub use gesture_detector::{GestureDetector, GestureSwipeEvent, InputEvent, PwtGestureDetector};
mod fab;
pub use fab::{Fab, PwtFab};
diff --git a/src/touch/side_dialog.rs b/src/touch/side_dialog.rs
index 2bd45f8..01abcd9 100644
--- a/src/touch/side_dialog.rs
+++ b/src/touch/side_dialog.rs
@@ -12,7 +12,7 @@ use crate::prelude::*;
use crate::state::{SharedState, SharedStateObserver};
use crate::widget::Container;
-use super::{GestureDetector, GestureDragEvent, GestureSwipeEvent};
+use super::{GestureDetector, GestureSwipeEvent, InputEvent};
// Messages sent from the [SideDialogController].
pub enum SideDialogControllerMsg {
@@ -125,9 +125,9 @@ pub enum Msg {
Close,
Dismiss, // Slide out, then close
SliderAnimationEnd,
- DragStart(GestureDragEvent),
- DragEnd(GestureDragEvent),
- Drag(GestureDragEvent),
+ DragStart(InputEvent),
+ DragEnd(InputEvent),
+ Drag(InputEvent),
Swipe(GestureSwipeEvent),
Controller,
}
@@ -390,11 +390,11 @@ impl Component for PwtSideDialog {
.on_tap({
let slider_ref = self.slider_ref.clone();
let link = ctx.link().clone();
- move |event: PointerEvent| {
+ move |event: InputEvent| {
if let Some(element) = slider_ref.clone().into_html_element() {
let rect = element.get_bounding_client_rect();
- let x = event.client_x() as f64;
- let y = event.client_y() as f64;
+ let x = event.x() as f64;
+ let y = event.y() as f64;
if (rect.left() < x)
&& (x < rect.right())
diff --git a/src/touch/slidable/mod.rs b/src/touch/slidable/mod.rs
index c81d2a9..ffcf8c8 100644
--- a/src/touch/slidable/mod.rs
+++ b/src/touch/slidable/mod.rs
@@ -15,7 +15,7 @@ use yew::virtual_dom::VNode;
use crate::dom::DomSizeObserver;
use crate::prelude::*;
use crate::props::CssLength;
-use crate::touch::{GestureDetector, GestureDragEvent, GestureSwipeEvent};
+use crate::touch::{GestureDetector, GestureSwipeEvent, InputEvent};
use crate::widget::{Container, Row};
use pwt_macros::widget;
@@ -116,9 +116,9 @@ pub struct PwtSlidable {
pub enum Msg {
StartDismissTransition,
- Drag(GestureDragEvent),
- DragStart(GestureDragEvent),
- DragEnd(GestureDragEvent),
+ Drag(InputEvent),
+ DragStart(InputEvent),
+ DragEnd(InputEvent),
Swipe(GestureSwipeEvent),
LeftResize(f64),
RightResize(f64),
--
2.39.5
_______________________________________________
yew-devel mailing list
yew-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/yew-devel
next prev parent reply other threads:[~2025-06-24 12:18 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-24 12:19 [yew-devel] [PATCH yew-widget-toolkit/yew-widget-toolkit-assets 00/11] various touch fixes Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit-assets 1/4] slidable: don't add padding on top and bottom to actions Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit-assets 2/4] slidable: set background-color to pwt-color-background for actions Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit-assets 3/4] color scheme: add `pwt-default-colors` helper Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit-assets 4/4] material: add rounded corners to bottom sheet Dominik Csapak
2025-06-24 12:19 ` Dominik Csapak [this message]
2025-06-24 16:27 ` [yew-devel] applied: [PATCH yew-widget-toolkit 1/7] touch: gesture detector: introduce `InputEvent` Dietmar Maurer
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit 2/7] touch: gesture detector: implement a touch only mode Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit 3/7] touch: fab: rename on_click to on_activate Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit 4/7] touch: slidable action: " Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit 5/7] touch: slidable action: add css classes property Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit 6/7] touch: slidable: add on_tap callback Dominik Csapak
2025-06-24 12:19 ` [yew-devel] [PATCH yew-widget-toolkit 7/7] touch: slidable: cleanup unnecessary macro use Dominik Csapak
2025-06-25 6:57 ` [yew-devel] applied: [PATCH yew-widget-toolkit/yew-widget-toolkit-assets 00/11] various touch fixes Dietmar Maurer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250624121925.57056-6-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=yew-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.