Fix detection of topmost region under the dragged item

Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
Max Brunsfeld 2023-12-11 16:50:44 -08:00
parent cbce49ff68
commit 6f5b1064ee
2 changed files with 46 additions and 20 deletions

View file

@ -763,6 +763,11 @@ impl InteractiveBounds {
pub fn visibly_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool {
self.bounds.contains(point) && cx.was_top_layer(&point, &self.stacking_order)
}
pub fn drag_target_contains(&self, point: &Point<Pixels>, 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");
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();
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);

View file

@ -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<Pixels>,
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);