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/// Default maximum width (cells) for a [`DragPreview::SourceSnapshot`] float preview.
118pub const DEFAULT_PREVIEW_MAX_WIDTH: u16 = 60;
119/// Default maximum height (cells) for a [`DragPreview::SourceSnapshot`] float preview.
120pub const DEFAULT_PREVIEW_MAX_HEIGHT: u16 = 20;
121
122/// Which axis [`DragSlot`] main-axis sizes apply to when measuring a drag source outside a stack
123/// (e.g. inside `Frame`). In `VStack` / `HStack`, the stack's axis always wins.
124#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
125pub enum DragSlotAxis {
126 /// Vertical main axis (height) when measuring outside a stack.
127 #[default]
128 Vertical,
129 /// Horizontal main axis (width) when measuring outside a stack.
130 Horizontal,
131}
132
133/// Main-axis space reserved at the [`crate::widgets::DragSource`] while dragging (when using
134/// [`DragPreview::SourceSnapshot`]).
135///
136/// In `VStack` / `HStack`, [`DragSlot::Specified`] uses the same main-axis rules as stack children.
137/// [`DragSlot::Collapse`] is **0 cells** on the stack main axis.
138#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
139pub enum DragSlot {
140 /// Zero cells on the stack main axis while dragging.
141 #[default]
142 Collapse,
143 /// Fixed main-axis length using the same rules as stack children.
144 Specified(Length),
145}
146
147/// What the [`crate::widgets::DropTarget`] renders in place of its child while a compatible
148/// [`DragPreview::SourceSnapshot`] drag is hovering over it.
149#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
150pub enum DropSlot {
151 /// Render the child normally (default). [`crate::widgets::DropHighlight`] still applies on top.
152 #[default]
153 Child,
154 /// Replace the child with the dragged source's snapshot cells and suppress the floating
155 /// cursor preview. The snapshot is rendered top-left aligned and clipped to the target rect.
156 /// [`crate::widgets::DropHighlight`] is still composited on top when set.
157 SourcePreview,
158}