Skip to main content

tui_lipan/widgets/drag_drop/
payload.rs

1use std::any::Any;
2use std::fmt::Debug;
3use std::sync::Arc;
4
5use crate::style::Length;
6
7/// Type-erased payload for generic drag-and-drop.
8pub trait DragPayload: Any + Debug + 'static {
9    /// Downcast helper for payload inspection.
10    fn as_any(&self) -> &dyn Any;
11
12    /// Convert boxed payload into shared payload storage without double boxing.
13    fn into_arc(self: Box<Self>) -> Arc<dyn DragPayload>;
14}
15
16impl<T> DragPayload for T
17where
18    T: Any + Debug + 'static,
19{
20    fn as_any(&self) -> &dyn Any {
21        self
22    }
23
24    fn into_arc(self: Box<Self>) -> Arc<dyn DragPayload> {
25        let payload: Arc<Self> = Arc::from(self);
26        payload
27    }
28}
29
30impl dyn DragPayload {
31    /// Downcast payload to a concrete type.
32    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
33        self.as_any().downcast_ref::<T>().or_else(|| {
34            self.as_any()
35                .downcast_ref::<Box<dyn DragPayload>>()
36                .and_then(|boxed| boxed.as_ref().as_any().downcast_ref::<T>())
37        })
38    }
39}
40
41#[derive(Clone, Debug, PartialEq, Eq)]
42/// Event emitted when drag activation threshold is exceeded.
43pub struct DragStartEvent {
44    /// Pointer x coordinate when drag starts.
45    pub x: u16,
46    /// Pointer y coordinate when drag starts.
47    pub y: u16,
48}
49
50#[derive(Clone)]
51/// Event emitted while a compatible payload hovers a drop target.
52pub struct DragOverEvent {
53    /// Current pointer x coordinate.
54    pub x: u16,
55    /// Current pointer y coordinate.
56    pub y: u16,
57    /// Pointer `y` minus the hovered drop target's top edge (content coordinates).
58    pub local_y: u16,
59    /// Height of the hovered drop target in cells.
60    pub local_height: u16,
61    /// Active drag payload.
62    pub payload: Arc<dyn DragPayload>,
63}
64
65#[derive(Clone)]
66/// Event emitted when payload leaves a drop target.
67pub struct DragLeaveEvent {
68    /// Active drag payload.
69    pub payload: Arc<dyn DragPayload>,
70}
71
72#[derive(Clone)]
73/// Event emitted when payload is dropped on a compatible target.
74pub struct DropEvent {
75    /// Pointer x coordinate at drop time.
76    pub x: u16,
77    /// Pointer y coordinate at drop time.
78    pub y: u16,
79    /// Pointer `y` minus the drop target's top edge (content coordinates).
80    pub local_y: u16,
81    /// Height of the drop target in cells.
82    pub local_height: u16,
83    /// Active drag payload.
84    pub payload: Arc<dyn DragPayload>,
85}
86
87#[derive(Clone)]
88/// Fired once when a generic drag becomes active (after the movement threshold).
89pub struct DragStartedEvent {
90    /// Pointer x coordinate when the drag activated.
91    pub x: u16,
92    /// Pointer y coordinate when the drag activated.
93    pub y: u16,
94    /// Active drag payload.
95    pub payload: Arc<dyn DragPayload>,
96}
97
98#[derive(Clone)]
99/// Event emitted when active drag is canceled.
100pub struct DragCancelEvent {
101    /// Active drag payload.
102    pub payload: Arc<dyn DragPayload>,
103}
104
105#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
106/// Visual preview style rendered near pointer during drag.
107pub enum DragPreview {
108    /// Show this label near the pointer while dragging.
109    Label(Arc<str>),
110    /// Render a snapshot of the drag source's cells near the pointer while dragging.
111    SourceSnapshot,
112    /// Do not render a drag preview.
113    #[default]
114    None,
115}
116
117/// Suggested maximum width (cells) when capping a [`DragPreview::SourceSnapshot`] float preview.
118///
119/// Not applied automatically — pass `Some(DEFAULT_PREVIEW_MAX_WIDTH)` to
120/// [`crate::widgets::DragSource::preview_max_width`] if you want this limit.
121pub const DEFAULT_PREVIEW_MAX_WIDTH: u16 = 60;
122/// Suggested maximum height (cells) when capping a [`DragPreview::SourceSnapshot`] float preview.
123///
124/// Not applied automatically — pass `Some(DEFAULT_PREVIEW_MAX_HEIGHT)` to
125/// [`crate::widgets::DragSource::preview_max_height`] if you want this limit.
126pub const DEFAULT_PREVIEW_MAX_HEIGHT: u16 = 20;
127
128/// Which axis [`DragSlot`] main-axis sizes apply to when measuring a drag source outside a stack
129/// (e.g. inside `Frame`). In `VStack` / `HStack`, the stack's axis always wins.
130#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
131pub enum DragSlotAxis {
132    /// Vertical main axis (height) when measuring outside a stack.
133    #[default]
134    Vertical,
135    /// Horizontal main axis (width) when measuring outside a stack.
136    Horizontal,
137}
138
139/// Main-axis space reserved at the [`crate::widgets::DragSource`] while dragging (when using
140/// [`DragPreview::SourceSnapshot`]).
141///
142/// In `VStack` / `HStack`, [`DragSlot::Specified`] uses the same main-axis rules as stack children.
143/// [`DragSlot::Collapse`] is **0 cells** on the stack main axis.
144#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
145pub enum DragSlot {
146    /// Zero cells on the stack main axis while dragging.
147    #[default]
148    Collapse,
149    /// Fixed main-axis length using the same rules as stack children.
150    Specified(Length),
151}
152
153/// What the [`crate::widgets::DropTarget`] renders in place of its child while a compatible
154/// [`DragPreview::SourceSnapshot`] drag is hovering over it.
155#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
156pub enum DropSlot {
157    /// Render the child normally (default). [`crate::widgets::DropHighlight`] still applies on top.
158    #[default]
159    Child,
160    /// Replace the child with the dragged source's snapshot cells and suppress the floating
161    /// cursor preview. The snapshot is rendered top-left aligned and clipped to the target rect.
162    /// [`crate::widgets::DropHighlight`] is still composited on top when set.
163    SourcePreview,
164}