Position drag handle relative to cursor

This commit is contained in:
Nathan Sobo 2023-10-23 15:20:33 +02:00
parent fc927f7406
commit 258fcaea94
3 changed files with 24 additions and 20 deletions

View file

@ -11,9 +11,9 @@ use smallvec::SmallVec;
use crate::{ use crate::{
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource, current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource,
Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId, KeyBinding, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId, KeyBinding,
Keymap, LayoutId, MainThread, MainThreadOnly, Platform, SharedString, SubscriberSet, Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point, SharedString,
Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem,
WindowContext, WindowHandle, WindowId, View, Window, WindowContext, WindowHandle, WindowId,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::{HashMap, HashSet, VecDeque}; use collections::{HashMap, HashSet, VecDeque};
@ -736,6 +736,7 @@ pub(crate) enum Effect {
pub(crate) struct AnyDrag { pub(crate) struct AnyDrag {
pub drag_handle_view: AnyView, pub drag_handle_view: AnyView,
pub cursor_offset: Point<Pixels>,
pub state: AnyBox, pub state: AnyBox,
pub state_type: TypeId, pub state_type: TypeId,
} }

View file

@ -319,19 +319,21 @@ pub trait StatefulInteractive: StatelessInteractive {
self.stateful_interaction().drag_listener.is_none(), self.stateful_interaction().drag_listener.is_none(),
"calling on_drag more than once on the same element is not supported" "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| { self.stateful_interaction().drag_listener =
let drag = listener(view_state, cx); Some(Arc::new(move |view_state, cursor_offset, cx| {
let view_handle = cx.handle().upgrade().unwrap(); let drag = listener(view_state, cx);
let drag_handle_view = view(view_handle, move |view_state, cx| { let view_handle = cx.handle().upgrade().unwrap();
(drag.render_drag_handle)(view_state, cx) let drag_handle_view = view(view_handle, move |view_state, cx| {
}) (drag.render_drag_handle)(view_state, cx)
.into_any(); })
AnyDrag { .into_any();
drag_handle_view, AnyDrag {
state: Box::new(drag.state), drag_handle_view,
state_type: TypeId::of::<S>(), cursor_offset,
} state: Box::new(drag.state),
})); state_type: TypeId::of::<S>(),
}
}));
self self
} }
} }
@ -472,7 +474,8 @@ pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
} else if phase == DispatchPhase::Bubble } else if phase == DispatchPhase::Bubble
&& bounds.contains_point(&event.position) && 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.start_drag(any_drag);
cx.stop_propagation(); cx.stop_propagation();
} }
@ -1030,7 +1033,7 @@ pub type ClickListener<V> =
Arc<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>; Arc<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
pub(crate) type DragListener<V> = pub(crate) type DragListener<V> =
Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyDrag + Send + Sync + 'static>; Arc<dyn Fn(&mut V, Point<Pixels>, &mut ViewContext<V>) -> AnyDrag + Send + Sync + 'static>;
pub type KeyListener<V> = Arc< pub type KeyListener<V> = Arc<
dyn Fn( dyn Fn(

View file

@ -812,8 +812,8 @@ impl<'a, 'w> WindowContext<'a, 'w> {
if let Some(mut active_drag) = cx.active_drag.take() { if let Some(mut active_drag) = cx.active_drag.take() {
cx.stack(1, |cx| { cx.stack(1, |cx| {
let mouse_position = cx.mouse_position(); let offset = cx.mouse_position() - active_drag.cursor_offset;
cx.with_element_offset(Some(mouse_position), |cx| { cx.with_element_offset(Some(offset), |cx| {
let available_space = let available_space =
size(AvailableSpace::MinContent, AvailableSpace::MinContent); size(AvailableSpace::MinContent, AvailableSpace::MinContent);
draw_any_view(&mut active_drag.drag_handle_view, available_space, cx); draw_any_view(&mut active_drag.drag_handle_view, available_space, cx);