Check if the mouse / touch event is above the canvas via element_from_point (#4775)
* Closes #4752 To test, start the web demo and follow the repro steps from #4752
This commit is contained in:
parent
b31d02dd21
commit
9a4c46289e
|
|
@ -1,6 +1,5 @@
|
||||||
use web_sys::EventTarget;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use web_sys::EventTarget;
|
||||||
|
|
||||||
// TODO(emilk): there are more calls to `prevent_default` and `stop_propagaton`
|
// TODO(emilk): there are more calls to `prevent_default` and `stop_propagaton`
|
||||||
// than what is probably needed.
|
// than what is probably needed.
|
||||||
|
|
@ -422,8 +421,17 @@ fn install_mousedown(runner_ref: &WebRunner, target: &EventTarget) -> Result<(),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the cursor is above the canvas, or if we're dragging something.
|
/// Returns true if the cursor is above the canvas, or if we're dragging something.
|
||||||
fn is_interested_in_pointer_event(egui_ctx: &egui::Context, pos: egui::Pos2) -> bool {
|
/// Pass in the position in browser viewport coordinates (usually event.clientX/Y).
|
||||||
egui_ctx.input(|i| i.screen_rect().contains(pos) || i.pointer.any_down() || i.any_touches())
|
fn is_interested_in_pointer_event(runner: &AppRunner, pos: egui::Pos2) -> bool {
|
||||||
|
let document = web_sys::window().unwrap().document().unwrap();
|
||||||
|
let is_hovering_canvas = document
|
||||||
|
.element_from_point(pos.x, pos.y)
|
||||||
|
.is_some_and(|element| element.eq(runner.canvas()));
|
||||||
|
let is_pointer_down = runner
|
||||||
|
.egui_ctx()
|
||||||
|
.input(|i| i.pointer.any_down() || i.any_touches());
|
||||||
|
|
||||||
|
is_hovering_canvas || is_pointer_down
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_mousemove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsValue> {
|
fn install_mousemove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsValue> {
|
||||||
|
|
@ -433,7 +441,10 @@ fn install_mousemove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(),
|
||||||
|
|
||||||
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
|
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
|
||||||
|
|
||||||
if is_interested_in_pointer_event(runner.egui_ctx(), pos) {
|
if is_interested_in_pointer_event(
|
||||||
|
runner,
|
||||||
|
egui::pos2(event.client_x() as f32, event.client_y() as f32),
|
||||||
|
) {
|
||||||
runner.input.raw.events.push(egui::Event::PointerMoved(pos));
|
runner.input.raw.events.push(egui::Event::PointerMoved(pos));
|
||||||
runner.needs_repaint.repaint_asap();
|
runner.needs_repaint.repaint_asap();
|
||||||
event.stop_propagation();
|
event.stop_propagation();
|
||||||
|
|
@ -449,7 +460,10 @@ fn install_mouseup(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), J
|
||||||
|
|
||||||
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
|
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
|
||||||
|
|
||||||
if is_interested_in_pointer_event(runner.egui_ctx(), pos) {
|
if is_interested_in_pointer_event(
|
||||||
|
runner,
|
||||||
|
egui::pos2(event.client_x() as f32, event.client_y() as f32),
|
||||||
|
) {
|
||||||
if let Some(button) = button_from_mouse_event(&event) {
|
if let Some(button) = button_from_mouse_event(&event) {
|
||||||
let modifiers = runner.input.raw.modifiers;
|
let modifiers = runner.input.raw.modifiers;
|
||||||
runner.input.raw.events.push(egui::Event::PointerButton {
|
runner.input.raw.events.push(egui::Event::PointerButton {
|
||||||
|
|
@ -493,7 +507,7 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<()
|
||||||
target,
|
target,
|
||||||
"touchstart",
|
"touchstart",
|
||||||
|event: web_sys::TouchEvent, runner| {
|
|event: web_sys::TouchEvent, runner| {
|
||||||
if let Some(pos) = primary_touch_pos(runner, &event) {
|
if let Some((pos, _)) = primary_touch_pos(runner, &event) {
|
||||||
runner.input.raw.events.push(egui::Event::PointerButton {
|
runner.input.raw.events.push(egui::Event::PointerButton {
|
||||||
pos,
|
pos,
|
||||||
button: egui::PointerButton::Primary,
|
button: egui::PointerButton::Primary,
|
||||||
|
|
@ -512,8 +526,11 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<()
|
||||||
|
|
||||||
fn install_touchmove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsValue> {
|
fn install_touchmove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsValue> {
|
||||||
runner_ref.add_event_listener(target, "touchmove", |event: web_sys::TouchEvent, runner| {
|
runner_ref.add_event_listener(target, "touchmove", |event: web_sys::TouchEvent, runner| {
|
||||||
if let Some(pos) = primary_touch_pos(runner, &event) {
|
if let Some((pos, touch)) = primary_touch_pos(runner, &event) {
|
||||||
if is_interested_in_pointer_event(runner.egui_ctx(), pos) {
|
if is_interested_in_pointer_event(
|
||||||
|
runner,
|
||||||
|
egui::pos2(touch.client_x() as f32, touch.client_y() as f32),
|
||||||
|
) {
|
||||||
runner.input.raw.events.push(egui::Event::PointerMoved(pos));
|
runner.input.raw.events.push(egui::Event::PointerMoved(pos));
|
||||||
|
|
||||||
push_touches(runner, egui::TouchPhase::Move, &event);
|
push_touches(runner, egui::TouchPhase::Move, &event);
|
||||||
|
|
@ -527,8 +544,11 @@ fn install_touchmove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(),
|
||||||
|
|
||||||
fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsValue> {
|
fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsValue> {
|
||||||
runner_ref.add_event_listener(target, "touchend", |event: web_sys::TouchEvent, runner| {
|
runner_ref.add_event_listener(target, "touchend", |event: web_sys::TouchEvent, runner| {
|
||||||
if let Some(pos) = primary_touch_pos(runner, &event) {
|
if let Some((pos, touch)) = primary_touch_pos(runner, &event) {
|
||||||
if is_interested_in_pointer_event(runner.egui_ctx(), pos) {
|
if is_interested_in_pointer_event(
|
||||||
|
runner,
|
||||||
|
egui::pos2(touch.client_x() as f32, touch.client_y() as f32),
|
||||||
|
) {
|
||||||
// First release mouse to click:
|
// First release mouse to click:
|
||||||
runner.input.raw.events.push(egui::Event::PointerButton {
|
runner.input.raw.events.push(egui::Event::PointerButton {
|
||||||
pos,
|
pos,
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ pub fn button_from_mouse_event(event: &web_sys::MouseEvent) -> Option<egui::Poin
|
||||||
pub fn primary_touch_pos(
|
pub fn primary_touch_pos(
|
||||||
runner: &mut AppRunner,
|
runner: &mut AppRunner,
|
||||||
event: &web_sys::TouchEvent,
|
event: &web_sys::TouchEvent,
|
||||||
) -> Option<egui::Pos2> {
|
) -> Option<(egui::Pos2, web_sys::Touch)> {
|
||||||
let all_touches: Vec<_> = (0..event.touches().length())
|
let all_touches: Vec<_> = (0..event.touches().length())
|
||||||
.filter_map(|i| event.touches().get(i))
|
.filter_map(|i| event.touches().get(i))
|
||||||
// On touchend we don't get anything in `touches`, but we still get `changed_touches`, so include those:
|
// On touchend we don't get anything in `touches`, but we still get `changed_touches`, so include those:
|
||||||
|
|
@ -59,7 +59,10 @@ pub fn primary_touch_pos(
|
||||||
for touch in all_touches {
|
for touch in all_touches {
|
||||||
if primary_touch == egui::TouchId::from(touch.identifier()) {
|
if primary_touch == egui::TouchId::from(touch.identifier()) {
|
||||||
let canvas_rect = canvas_content_rect(runner.canvas());
|
let canvas_rect = canvas_content_rect(runner.canvas());
|
||||||
return Some(pos_from_touch(canvas_rect, &touch, runner.egui_ctx()));
|
return Some((
|
||||||
|
pos_from_touch(canvas_rect, &touch, runner.egui_ctx()),
|
||||||
|
touch,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue