diff --git a/packages/tui/src/hooks.rs b/packages/tui/src/hooks.rs index 04d320fcb..658229fae 100644 --- a/packages/tui/src/hooks.rs +++ b/packages/tui/src/hooks.rs @@ -188,16 +188,6 @@ impl InnerInputState { layout: &Stretch, dom: &mut Dom, ) { - struct Data<'b> { - new_pos: (i32, i32), - old_pos: Option<(i32, i32)>, - clicked: bool, - released: bool, - wheel_delta: f64, - mouse_data: &'b MouseData, - wheel_data: &'b Option, - } - fn layout_contains_point(layout: &Layout, point: (i32, i32)) -> bool { layout.location.x as i32 <= point.0 && layout.location.x as i32 + layout.size.width as i32 >= point.0 @@ -230,6 +220,13 @@ impl InnerInputState { } } + fn prepare_mouse_data(mouse_data: &MouseData, layout: &Layout) -> MouseData { + let mut data = mouse_data.clone(); + data.offset_x = data.client_x - layout.location.x as i32; + data.offset_y = data.client_y - layout.location.y as i32; + data + } + if let Some(mouse) = &self.mouse { let new_pos = (mouse.0.screen_x, mouse.0.screen_y); let old_pos = previous_mouse @@ -242,31 +239,21 @@ impl InnerInputState { let wheel_delta = self.wheel.as_ref().map_or(0.0, |w| w.delta_y); let mouse_data = &mouse.0; let wheel_data = &self.wheel; - let data = Data { - new_pos, - old_pos, - clicked, - released, - wheel_delta, - mouse_data, - wheel_data, - }; { // mousemove let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mousemove") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let previously_contained = data - .old_pos + let previously_contained = old_pos .filter(|pos| layout_contains_point(node_layout, *pos)) .is_some(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); if currently_contains && previously_contained { try_create_event( "mousemove", - Arc::new(data.mouse_data.clone()), + Arc::new(prepare_mouse_data(mouse_data, node_layout)), &mut will_bubble, resolved_events, node, @@ -281,16 +268,15 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseenter") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let previously_contained = data - .old_pos + let previously_contained = old_pos .filter(|pos| layout_contains_point(node_layout, *pos)) .is_some(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); if currently_contains && !previously_contained { try_create_event( "mouseenter", - Arc::new(data.mouse_data.clone()), + Arc::new(mouse_data.clone()), &mut will_bubble, resolved_events, node, @@ -305,16 +291,15 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseover") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let previously_contained = data - .old_pos + let previously_contained = old_pos .filter(|pos| layout_contains_point(node_layout, *pos)) .is_some(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); if currently_contains && !previously_contained { try_create_event( "mouseover", - Arc::new(data.mouse_data.clone()), + Arc::new(prepare_mouse_data(mouse_data, node_layout)), &mut will_bubble, resolved_events, node, @@ -329,12 +314,12 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mousedown") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); - if currently_contains && data.clicked { + if currently_contains && clicked { try_create_event( "mousedown", - Arc::new(data.mouse_data.clone()), + Arc::new(prepare_mouse_data(mouse_data, node_layout)), &mut will_bubble, resolved_events, node, @@ -349,12 +334,12 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseup") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); - if currently_contains && data.released { + if currently_contains && released { try_create_event( "mouseup", - Arc::new(data.mouse_data.clone()), + Arc::new(prepare_mouse_data(mouse_data, node_layout)), &mut will_bubble, resolved_events, node, @@ -369,12 +354,12 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("click") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); - if currently_contains && data.released && data.mouse_data.button == 0 { + if currently_contains && released && mouse_data.button == 0 { try_create_event( "click", - Arc::new(data.mouse_data.clone()), + Arc::new(prepare_mouse_data(mouse_data, node_layout)), &mut will_bubble, resolved_events, node, @@ -389,12 +374,12 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("contextmenu") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); - if currently_contains && data.released && data.mouse_data.button == 2 { + if currently_contains && released && mouse_data.button == 2 { try_create_event( "contextmenu", - Arc::new(data.mouse_data.clone()), + Arc::new(prepare_mouse_data(mouse_data, node_layout)), &mut will_bubble, resolved_events, node, @@ -409,10 +394,10 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("wheel") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); - if let Some(w) = data.wheel_data { - if currently_contains && data.wheel_delta != 0.0 { + if let Some(w) = wheel_data { + if currently_contains && wheel_delta != 0.0 { try_create_event( "wheel", Arc::new(w.clone()), @@ -431,16 +416,15 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseleave") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let previously_contained = data - .old_pos + let previously_contained = old_pos .filter(|pos| layout_contains_point(node_layout, *pos)) .is_some(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); if !currently_contains && previously_contained { try_create_event( "mouseleave", - Arc::new(data.mouse_data.clone()), + Arc::new(prepare_mouse_data(mouse_data, node_layout)), &mut will_bubble, resolved_events, node, @@ -455,16 +439,15 @@ impl InnerInputState { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseout") { let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap(); - let previously_contained = data - .old_pos + let previously_contained = old_pos .filter(|pos| layout_contains_point(node_layout, *pos)) .is_some(); - let currently_contains = layout_contains_point(node_layout, data.new_pos); + let currently_contains = layout_contains_point(node_layout, new_pos); if !currently_contains && previously_contained { try_create_event( "mouseout", - Arc::new(data.mouse_data.clone()), + Arc::new(prepare_mouse_data(mouse_data, node_layout)), &mut will_bubble, resolved_events, node, @@ -603,7 +586,7 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> { }; // from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent - // The `offset`, `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively. + // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively. // todo? // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway. EventData::Mouse(MouseData { @@ -614,8 +597,9 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> { client_y: y, ctrl_key: ctrl, meta_key: meta, - offset_x: x, - offset_y: y, + // offset x/y are set when the origin of the event is assigned to an element + offset_x: 0, + offset_y: 0, page_x: x, page_y: y, screen_x: x,