tui_lipan/widgets/drag_drop/
drop_target.rs1use std::hash::Hash;
2use std::rc::Rc;
3use std::sync::Arc;
4
5use crate::callback::Callback;
6use crate::core::element::{Element, ElementKind};
7use crate::layout::hash::LayoutHash;
8use crate::style::{LayoutConstraints, Length, Style, StyleSlot};
9
10use super::drop_target_layout::measure_drop_target;
11use super::payload::{DragLeaveEvent, DragOverEvent, DragPayload, DropEvent, DropSlot};
12
13pub type PayloadAcceptFn = Rc<dyn Fn(&dyn DragPayload) -> bool>;
15
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
18pub enum DropHighlight {
19 #[default]
21 None,
22 Fill,
24 Placeholder,
26 Overlay,
28}
29
30#[derive(Clone)]
31pub struct DropTarget {
33 pub(crate) child: Option<Box<Element>>,
34 pub(crate) on_drag_over: Option<Callback<DragOverEvent>>,
35 pub(crate) on_drag_leave: Option<Callback<DragLeaveEvent>>,
36 pub(crate) on_drop: Option<Callback<DropEvent>>,
37 pub(crate) accept_group: Option<Arc<str>>,
38 pub(crate) can_accept: Option<PayloadAcceptFn>,
39 pub(crate) highlight: DropHighlight,
40 pub(crate) highlight_style: StyleSlot,
41 pub(crate) drop_slot: DropSlot,
42 pub(crate) enabled: bool,
43}
44
45impl Default for DropTarget {
46 fn default() -> Self {
47 Self {
48 child: None,
49 on_drag_over: None,
50 on_drag_leave: None,
51 on_drop: None,
52 accept_group: None,
53 can_accept: None,
54 highlight: DropHighlight::None,
55 highlight_style: StyleSlot::Inherit,
56 drop_slot: DropSlot::Child,
57 enabled: true,
58 }
59 }
60}
61
62impl DropTarget {
63 pub fn new() -> Self {
65 Self::default()
66 }
67
68 pub fn child(mut self, child: impl Into<Element>) -> Self {
70 self.child = Some(Box::new(child.into()));
71 self
72 }
73
74 pub fn on_drag_over(mut self, cb: Callback<DragOverEvent>) -> Self {
76 self.on_drag_over = Some(cb);
77 self
78 }
79
80 pub fn on_drag_leave(mut self, cb: Callback<DragLeaveEvent>) -> Self {
82 self.on_drag_leave = Some(cb);
83 self
84 }
85
86 pub fn on_drop(mut self, cb: Callback<DropEvent>) -> Self {
88 self.on_drop = Some(cb);
89 self
90 }
91
92 pub fn accept_group(mut self, group: impl Into<Arc<str>>) -> Self {
94 self.accept_group = Some(group.into());
95 self
96 }
97
98 pub fn clear_accept_group(mut self) -> Self {
100 self.accept_group = None;
101 self
102 }
103
104 pub fn can_accept(mut self, accept: PayloadAcceptFn) -> Self {
106 self.can_accept = Some(accept);
107 self
108 }
109
110 pub fn can_accept_with(mut self, accept: impl Fn(&dyn DragPayload) -> bool + 'static) -> Self {
112 self.can_accept = Some(Rc::new(accept));
113 self
114 }
115
116 pub fn clear_can_accept(mut self) -> Self {
118 self.can_accept = None;
119 self
120 }
121
122 pub fn highlight(mut self, highlight: DropHighlight) -> Self {
124 self.highlight = highlight;
125 self
126 }
127
128 pub fn highlight_style(mut self, style: Style) -> Self {
130 self.highlight_style = StyleSlot::Replace(style);
131 self
132 }
133
134 pub fn extend_highlight_style(mut self, style: Style) -> Self {
136 self.highlight_style = StyleSlot::Extend(style);
137 self
138 }
139
140 pub fn inherit_highlight_style(mut self) -> Self {
142 self.highlight_style = StyleSlot::Inherit;
143 self
144 }
145
146 pub fn highlight_style_slot(mut self, slot: StyleSlot) -> Self {
148 self.highlight_style = slot;
149 self
150 }
151
152 pub fn highlight_fill(mut self, style: Style) -> Self {
154 self.highlight = DropHighlight::Fill;
155 self.highlight_style = StyleSlot::Replace(style);
156 self
157 }
158
159 pub fn highlight_placeholder(mut self, style: Style) -> Self {
161 self.highlight = DropHighlight::Placeholder;
162 self.highlight_style = StyleSlot::Replace(style);
163 self
164 }
165
166 pub fn highlight_overlay(mut self, style: Style) -> Self {
168 self.highlight = DropHighlight::Overlay;
169 self.highlight_style = StyleSlot::Replace(style);
170 self
171 }
172
173 pub fn drop_slot(mut self, slot: DropSlot) -> Self {
175 self.drop_slot = slot;
176 self
177 }
178
179 pub fn drop_slot_source_preview(mut self) -> Self {
182 self.drop_slot = DropSlot::SourcePreview;
183 self
184 }
185
186 pub fn enabled(mut self, enabled: bool) -> Self {
188 self.enabled = enabled;
189 self
190 }
191}
192
193impl From<DropTarget> for Element {
194 fn from(value: DropTarget) -> Self {
195 let (min_w, min_h) = measure_drop_target(&value, None, None);
196 Element::new(ElementKind::DropTarget(value)).with_layout(
197 LayoutConstraints::default()
198 .min_width(Length::Px(min_w))
199 .min_height(Length::Px(min_h)),
200 )
201 }
202}
203
204impl LayoutHash for DropTarget {
205 fn layout_hash(
206 &self,
207 hasher: &mut impl std::hash::Hasher,
208 recurse: &dyn Fn(&Element) -> Option<u64>,
209 ) -> Option<()> {
210 self.enabled.hash(hasher);
211 self.on_drag_over.is_some().hash(hasher);
212 self.on_drag_leave.is_some().hash(hasher);
213 self.on_drop.is_some().hash(hasher);
214 self.accept_group.hash(hasher);
215 self.can_accept.is_some().hash(hasher);
216 self.highlight.hash(hasher);
217 self.highlight_style.hash(hasher);
218 self.drop_slot.hash(hasher);
219 if let Some(child) = self.child.as_ref() {
220 recurse(child.as_ref())?.hash(hasher);
221 }
222 Some(())
223 }
224}