diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 89abf277d3..0228dca57b 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -11,9 +11,9 @@ use smallvec::SmallVec; use crate::{ current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId, KeyBinding, - Keymap, LayoutId, MainThread, MainThreadOnly, Platform, SharedString, SubscriberSet, - Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window, - WindowContext, WindowHandle, WindowId, + Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point, SharedString, + SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, + View, Window, WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; use collections::{HashMap, HashSet, VecDeque}; @@ -736,6 +736,7 @@ pub(crate) enum Effect { pub(crate) struct AnyDrag { pub drag_handle_view: AnyView, + pub cursor_offset: Point, pub state: AnyBox, pub state_type: TypeId, } diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 194e6824ef..acc97810f1 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -319,19 +319,21 @@ pub trait StatefulInteractive: StatelessInteractive { self.stateful_interaction().drag_listener.is_none(), "calling on_drag more than once on the same element is not supported" ); - self.stateful_interaction().drag_listener = Some(Arc::new(move |view_state, cx| { - let drag = listener(view_state, cx); - let view_handle = cx.handle().upgrade().unwrap(); - let drag_handle_view = view(view_handle, move |view_state, cx| { - (drag.render_drag_handle)(view_state, cx) - }) - .into_any(); - AnyDrag { - drag_handle_view, - state: Box::new(drag.state), - state_type: TypeId::of::(), - } - })); + self.stateful_interaction().drag_listener = + Some(Arc::new(move |view_state, cursor_offset, cx| { + let drag = listener(view_state, cx); + let view_handle = cx.handle().upgrade().unwrap(); + let drag_handle_view = view(view_handle, move |view_state, cx| { + (drag.render_drag_handle)(view_state, cx) + }) + .into_any(); + AnyDrag { + drag_handle_view, + cursor_offset, + state: Box::new(drag.state), + state_type: TypeId::of::(), + } + })); self } } @@ -472,7 +474,8 @@ pub trait ElementInteraction: 'static + Send + Sync { } else if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { - let any_drag = drag_listener(view_state, cx); + let cursor_offset = event.position - bounds.origin; + let any_drag = drag_listener(view_state, cursor_offset, cx); cx.start_drag(any_drag); cx.stop_propagation(); } @@ -1030,7 +1033,7 @@ pub type ClickListener = Arc) + Send + Sync + 'static>; pub(crate) type DragListener = - Arc) -> AnyDrag + Send + Sync + 'static>; + Arc, &mut ViewContext) -> AnyDrag + Send + Sync + 'static>; pub type KeyListener = Arc< dyn Fn( diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 33b6daeb22..c54103b2a0 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -812,8 +812,8 @@ impl<'a, 'w> WindowContext<'a, 'w> { if let Some(mut active_drag) = cx.active_drag.take() { cx.stack(1, |cx| { - let mouse_position = cx.mouse_position(); - cx.with_element_offset(Some(mouse_position), |cx| { + let offset = cx.mouse_position() - active_drag.cursor_offset; + cx.with_element_offset(Some(offset), |cx| { let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); draw_any_view(&mut active_drag.drag_handle_view, available_space, cx);