Struct DragController
pub struct DragController<Id = ()> { /* private fields */ }Expand description
A single-axis drag-to-reorder controller. Construct one per reorderable
list (DragController::vertical / DragController::horizontal) and
drive it from the owner’s event handler:
let grab = cursor.y - metrics.slot_lead(i); // press on item i
ctrl.begin(item_id, i, grab, cursor);
if ctrl.pointer_moved(cursor, &metrics) { /* mark dirty */ }
for (i, item) in items { let dy = ctrl.item_shift(i, &metrics); }
if let Some(g) = ctrl.ghost_rect(list_x0, list_x1) { /* paint ghost */ }
if let Some((from, to)) = ctrl.commit() { model.move_item(from, to); }
ctrl.cancel(); // Escape / drop outsideImplementations§
§impl<Id> DragController<Id>where
Id: Clone,
impl<Id> DragController<Id>where
Id: Clone,
pub fn vertical() -> DragController<Id>
pub fn vertical() -> DragController<Id>
A vertical reorderable list (items stack top-to-bottom, ghost slides along Y).
pub fn horizontal() -> DragController<Id>
pub fn horizontal() -> DragController<Id>
A horizontal reorderable list (items run left-to-right, ghost slides along X).
pub fn axis(&self) -> Axis
pub fn begin(&mut self, id: Id, from: usize, grab_offset: f64, start: Point)
pub fn begin(&mut self, id: Id, from: usize, grab_offset: f64, start: Point)
Begin a (pending) drag of the item at index from, carrying id.
grab_offset is the pointer’s offset within the grabbed item
(cursor_axis - item_leading_edge). Not yet “active” — promotes to a
live reorder only once the pointer clears the threshold.
pub fn pointer_moved(&mut self, cursor: Point, metrics: &ListMetrics) -> bool
pub fn pointer_moved(&mut self, cursor: Point, metrics: &ListMetrics) -> bool
Feed the latest pointer position. Promotes the drag to active once it
clears the threshold. Returns true when the visible state changed
(activation or a moved gap) so the owner can redraw only on an edge.
pub fn sync_insertion(&mut self, metrics: &ListMetrics)
pub fn sync_insertion(&mut self, metrics: &ListMetrics)
Recompute the live target index from the freshest metrics without a
pointer move — call once per frame in draw so the gap stays pinned
to the ghost while the list scrolls under a held drag.
pub fn commit(&mut self) -> Option<(usize, usize)>
pub fn commit(&mut self) -> Option<(usize, usize)>
End the drag, yielding (from, to) to apply to the model, or None
when the drag never became active or the item didn’t move. Clears
the session either way. to is the final index after
removal-and-reinsertion (Vec::remove(from) + insert(to, _)).
pub fn cancel(&mut self) -> bool
pub fn cancel(&mut self) -> bool
Abort the drag (Escape, or a drop outside the list). The model is
only mutated on commit, so this simply
forgets the session. Returns true if a drag was in progress.
pub fn is_pending(&self) -> bool
pub fn is_pending(&self) -> bool
Whether a press has latched (active or not). Wire this to
Widget::wants_pointer_capture
so the drag keeps receiving events after the cursor leaves the item.
pub fn is_active(&self) -> bool
pub fn is_active(&self) -> bool
Whether the drag has crossed the threshold and is live (ghost + gap showing).
pub fn from_index(&self) -> Option<usize>
pub fn from_index(&self) -> Option<usize>
The original index of the item being dragged, once the drag is active.
pub fn insertion(&self) -> Option<usize>
pub fn insertion(&self) -> Option<usize>
The live target index the dragged item would land at, once active —
the to a drop would commit. Paint the insertion caret at this slot
so the caret and the reflowed gap coincide.
pub fn dragged_id(&self) -> Option<&Id>
pub fn dragged_id(&self) -> Option<&Id>
The identity payload attached to the dragged item, once active.
pub fn item_shift(&self, index: usize, metrics: &ListMetrics) -> f64
pub fn item_shift(&self, index: usize, metrics: &ListMetrics) -> f64
How far the non-dragged item at original index index must slide
(signed) to open a one-slot gap at the live target index. 0 for the
dragged item, and 0 for every item during the dead-zone. Models
“remove the dragged item, then open a gap where it will land”: an
item collapses into the vacated slot, then shifts past the gap if
the drop lands before it.
pub fn ghost_lead(&self) -> Option<f64>
pub fn ghost_lead(&self) -> Option<f64>
The leading-edge coordinate of the floating ghost along the axis
(cursor_axis - grab_offset), once active. Combine with the list’s
cross-axis bounds via ghost_rect.
pub fn ghost_rect(
&self,
cross_lo: f64,
cross_hi: f64,
metrics: &ListMetrics,
) -> Option<Rect>
pub fn ghost_rect( &self, cross_lo: f64, cross_hi: f64, metrics: &ListMetrics, ) -> Option<Rect>
The floating ghost rect: one item-extent long along the axis, pinned
to the list’s cross-axis span [cross_lo, cross_hi], positioned so the
grab point stays under the cursor. None unless the drag is active.
pub fn ghost_rect_sized(&self, cross_lo: f64, size: Size) -> Option<Rect>
pub fn ghost_rect_sized(&self, cross_lo: f64, size: Size) -> Option<Rect>
Convenience ghost rect from an explicit item size (for callers whose
item cross-extent differs from the list metrics), anchored so the grab
point tracks the cursor. None unless active.
Auto Trait Implementations§
impl<Id> Freeze for DragController<Id>where
Id: Freeze,
impl<Id> RefUnwindSafe for DragController<Id>where
Id: RefUnwindSafe,
impl<Id> Send for DragController<Id>where
Id: Send,
impl<Id> Sync for DragController<Id>where
Id: Sync,
impl<Id> Unpin for DragController<Id>where
Id: Unpin,
impl<Id> UnsafeUnpin for DragController<Id>where
Id: UnsafeUnpin,
impl<Id> UnwindSafe for DragController<Id>where
Id: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more