From d92b2046914b5fe431725f3a3f075ac5ddb48a89 Mon Sep 17 00:00:00 2001 From: lucasmerlin Date: Sun, 12 Oct 2025 19:45:14 +0200 Subject: [PATCH 1/2] Add Sense::LONG_CLICK --- crates/eframe/src/web/events.rs | 12 ++++++------ crates/egui/src/interaction.rs | 1 + crates/egui/src/sense.rs | 19 ++++++++++++++++--- crates/egui_demo_app/src/wrap_app.rs | 1 + 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index eb0d848e0..0dbc67ecd 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -682,6 +682,7 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<() |event: web_sys::TouchEvent, runner| { let mut should_stop_propagation = true; let mut should_prevent_default = true; + push_touches(runner, egui::TouchPhase::Start, &event); if let Some((pos, _)) = primary_touch_pos(runner, &event) { let egui_event = egui::Event::PointerButton { pos, @@ -691,10 +692,9 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<() }; should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event); should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event); - runner.input.raw.events.push(egui_event); + // runner.input.raw.events.push(egui_event); } - push_touches(runner, egui::TouchPhase::Start, &event); runner.needs_repaint.repaint_asap(); // Use web options to tell if the web event should be propagated to parent elements based on the egui event. @@ -721,7 +721,7 @@ fn install_touchmove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), (runner.web_options.should_stop_propagation)(&egui_event); let should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event); - runner.input.raw.events.push(egui_event); + // runner.input.raw.events.push(egui_event); push_touches(runner, egui::TouchPhase::Move, &event); runner.needs_repaint.repaint(); @@ -746,6 +746,7 @@ fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), runner, egui::pos2(touch.client_x() as f32, touch.client_y() as f32), ) { + push_touches(runner, egui::TouchPhase::End, &event); // First release mouse to click: let mut should_stop_propagation = true; let mut should_prevent_default = true; @@ -758,15 +759,14 @@ fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), should_stop_propagation &= (runner.web_options.should_stop_propagation)(&egui_event); should_prevent_default &= (runner.web_options.should_prevent_default)(&egui_event); - runner.input.raw.events.push(egui_event); + // runner.input.raw.events.push(egui_event); // Then remove hover effect: should_stop_propagation &= (runner.web_options.should_stop_propagation)(&egui::Event::PointerGone); should_prevent_default &= (runner.web_options.should_prevent_default)(&egui::Event::PointerGone); - runner.input.raw.events.push(egui::Event::PointerGone); + // runner.input.raw.events.push(egui::Event::PointerGone); - push_touches(runner, egui::TouchPhase::End, &event); runner.needs_repaint.repaint_asap(); diff --git a/crates/egui/src/interaction.rs b/crates/egui/src/interaction.rs index bfac38da7..11c4079a3 100644 --- a/crates/egui/src/interaction.rs +++ b/crates/egui/src/interaction.rs @@ -145,6 +145,7 @@ pub(crate) fn interact( if let Some(widget) = interaction .potential_click_id .and_then(|id| widgets.get(id)) + && widget.sense.senses_long_click() { dragged = None; clicked = Some(widget.id); diff --git a/crates/egui/src/sense.rs b/crates/egui/src/sense.rs index 464db311f..55cfa0a21 100644 --- a/crates/egui/src/sense.rs +++ b/crates/egui/src/sense.rs @@ -19,6 +19,14 @@ bitflags::bitflags! { /// Anything interactive + labels that can be focused /// for the benefit of screen readers. const FOCUSABLE = 1<<2; + + /// Sense long clicks + /// + /// By default, anything that senses clicks also senses long clicks. + /// You can remove this flag if you want to sense clicks but not long clicks. + /// + /// Sensing for long clicks might cause problems when you need to sense precise drags + const LONG_CLICK = 1<<3; } } @@ -53,10 +61,10 @@ impl Sense { Self::FOCUSABLE } - /// Sense clicks and hover, but not drags. + /// Sense clicks, long clicks and hover, but not drags. #[inline] pub fn click() -> Self { - Self::CLICK | Self::FOCUSABLE + Self::CLICK | Self::FOCUSABLE | Self::LONG_CLICK } /// Sense drags and hover, but not clicks. @@ -75,7 +83,7 @@ impl Sense { /// See [`crate::PointerState::is_decidedly_dragging`] for details. #[inline] pub fn click_and_drag() -> Self { - Self::CLICK | Self::FOCUSABLE | Self::DRAG + Self::CLICK | Self::LONG_CLICK | Self::FOCUSABLE | Self::DRAG } /// Returns true if we sense either clicks or drags. @@ -89,6 +97,11 @@ impl Sense { self.contains(Self::CLICK) } + #[inline] + pub fn senses_long_click(&self) -> bool { + self.contains(Self::LONG_CLICK) + } + #[inline] pub fn senses_drag(&self) -> bool { self.contains(Self::DRAG) diff --git a/crates/egui_demo_app/src/wrap_app.rs b/crates/egui_demo_app/src/wrap_app.rs index bec0aacf3..968a10605 100644 --- a/crates/egui_demo_app/src/wrap_app.rs +++ b/crates/egui_demo_app/src/wrap_app.rs @@ -5,6 +5,7 @@ use eframe::glow; #[cfg(target_arch = "wasm32")] use core::any::Any; +use log::info; #[derive(Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] From 73a8b316deb407caa24283c769beaa0f5744e66d Mon Sep 17 00:00:00 2001 From: lucasmerlin Date: Sun, 12 Oct 2025 19:46:32 +0200 Subject: [PATCH 2/2] Revert unrelated changes --- crates/eframe/src/web/events.rs | 12 ++++++------ crates/egui_demo_app/src/wrap_app.rs | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index 0dbc67ecd..eb0d848e0 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -682,7 +682,6 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<() |event: web_sys::TouchEvent, runner| { let mut should_stop_propagation = true; let mut should_prevent_default = true; - push_touches(runner, egui::TouchPhase::Start, &event); if let Some((pos, _)) = primary_touch_pos(runner, &event) { let egui_event = egui::Event::PointerButton { pos, @@ -692,9 +691,10 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<() }; should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event); should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event); - // runner.input.raw.events.push(egui_event); + runner.input.raw.events.push(egui_event); } + push_touches(runner, egui::TouchPhase::Start, &event); runner.needs_repaint.repaint_asap(); // Use web options to tell if the web event should be propagated to parent elements based on the egui event. @@ -721,7 +721,7 @@ fn install_touchmove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), (runner.web_options.should_stop_propagation)(&egui_event); let should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event); - // runner.input.raw.events.push(egui_event); + runner.input.raw.events.push(egui_event); push_touches(runner, egui::TouchPhase::Move, &event); runner.needs_repaint.repaint(); @@ -746,7 +746,6 @@ fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), runner, egui::pos2(touch.client_x() as f32, touch.client_y() as f32), ) { - push_touches(runner, egui::TouchPhase::End, &event); // First release mouse to click: let mut should_stop_propagation = true; let mut should_prevent_default = true; @@ -759,14 +758,15 @@ fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), should_stop_propagation &= (runner.web_options.should_stop_propagation)(&egui_event); should_prevent_default &= (runner.web_options.should_prevent_default)(&egui_event); - // runner.input.raw.events.push(egui_event); + runner.input.raw.events.push(egui_event); // Then remove hover effect: should_stop_propagation &= (runner.web_options.should_stop_propagation)(&egui::Event::PointerGone); should_prevent_default &= (runner.web_options.should_prevent_default)(&egui::Event::PointerGone); - // runner.input.raw.events.push(egui::Event::PointerGone); + runner.input.raw.events.push(egui::Event::PointerGone); + push_touches(runner, egui::TouchPhase::End, &event); runner.needs_repaint.repaint_asap(); diff --git a/crates/egui_demo_app/src/wrap_app.rs b/crates/egui_demo_app/src/wrap_app.rs index 968a10605..bec0aacf3 100644 --- a/crates/egui_demo_app/src/wrap_app.rs +++ b/crates/egui_demo_app/src/wrap_app.rs @@ -5,7 +5,6 @@ use eframe::glow; #[cfg(target_arch = "wasm32")] use core::any::Any; -use log::info; #[derive(Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]