From 6f5b1064eef47529f559e1db86c0338dd9a29933 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 11 Dec 2023 16:50:44 -0800 Subject: [PATCH] Fix detection of topmost region under the dragged item Co-authored-by: Mikayla --- crates/gpui2/src/elements/div.rs | 47 ++++++++++++++++++-------------- crates/gpui2/src/window.rs | 21 +++++++++++++- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 25566e7483d3d0c63d6bc8ed64148797c9a74319..7c365d8734f01d3339961debb84f12c37e1d53b7 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -763,6 +763,11 @@ impl InteractiveBounds { pub fn visibly_contains(&self, point: &Point, cx: &WindowContext) -> bool { self.bounds.contains(point) && cx.was_top_layer(&point, &self.stacking_order) } + + pub fn drag_target_contains(&self, point: &Point, cx: &WindowContext) -> bool { + self.bounds.contains(point) + && cx.was_top_layer_under_active_drag(&point, &self.stacking_order) + } } impl Interactivity { @@ -888,30 +893,32 @@ impl Interactivity { if cx.active_drag.is_some() { let drop_listeners = mem::take(&mut self.drop_listeners); let interactive_bounds = interactive_bounds.clone(); - cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| { - if phase == DispatchPhase::Bubble - && interactive_bounds.visibly_contains(&event.position, &cx) - { - if let Some(drag_state_type) = - cx.active_drag.as_ref().map(|drag| drag.view.entity_type()) + if !drop_listeners.is_empty() { + cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| { + if phase == DispatchPhase::Bubble + && interactive_bounds.drag_target_contains(&event.position, cx) { - for (drop_state_type, listener) in &drop_listeners { - if *drop_state_type == drag_state_type { - let drag = cx - .active_drag - .take() - .expect("checked for type drag state type above"); - - listener(drag.view.clone(), cx); - cx.notify(); - cx.stop_propagation(); + if let Some(drag_state_type) = + cx.active_drag.as_ref().map(|drag| drag.view.entity_type()) + { + for (drop_state_type, listener) in &drop_listeners { + if *drop_state_type == drag_state_type { + let drag = cx + .active_drag + .take() + .expect("checked for type drag state type above"); + + listener(drag.view.clone(), cx); + cx.notify(); + cx.stop_propagation(); + } } + } else { + cx.active_drag = None; } - } else { - cx.active_drag = None; } - } - }); + }); + } } let click_listeners = mem::take(&mut self.click_listeners); diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index b84137fa967be7201f7c0b33b95e18b248e258a5..16de7ef62a4bbd3af3f2fad1821d00a3aea506ee 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -38,6 +38,8 @@ use std::{ }; use util::ResultExt; +const ACTIVE_DRAG_Z_INDEX: u32 = 1; + /// A global stacking order, which is created by stacking successive z-index values. /// Each z-index will always be interpreted in the context of its parent z-index. #[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default, Debug)] @@ -907,6 +909,23 @@ impl<'a> WindowContext<'a> { false } + pub fn was_top_layer_under_active_drag( + &self, + point: &Point, + level: &StackingOrder, + ) -> bool { + for (stack, bounds) in self.window.rendered_frame.depth_map.iter() { + if stack.starts_with(&[ACTIVE_DRAG_Z_INDEX]) { + continue; + } + if bounds.contains(point) { + return level.starts_with(stack) || stack.starts_with(level); + } + } + + false + } + /// Called during painting to get the current stacking order. pub fn stacking_order(&self) -> &StackingOrder { &self.window.next_frame.z_index_stack @@ -1238,7 +1257,7 @@ impl<'a> WindowContext<'a> { }); if let Some(active_drag) = self.app.active_drag.take() { - self.with_z_index(1, |cx| { + self.with_z_index(ACTIVE_DRAG_Z_INDEX, |cx| { let offset = cx.mouse_position() - active_drag.cursor_offset; let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); active_drag.view.draw(offset, available_space, cx);