1use super::{
5 DropEvent, Item, ItemConsts, ItemRc, MouseCursor, PointerEventButton, RenderingResult,
6};
7use crate::input::{
8 FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEvent,
9 KeyEventResult, MouseEvent,
10};
11use crate::item_rendering::{CachedRenderingData, ItemRenderer};
12use crate::layout::{LayoutInfo, Orientation};
13use crate::lengths::{LogicalPoint, LogicalRect, LogicalSize};
14#[cfg(feature = "rtti")]
15use crate::rtti::*;
16use crate::window::WindowAdapter;
17use crate::{Callback, Property, SharedString};
18use alloc::rc::Rc;
19use const_field_offset::FieldOffsets;
20use core::cell::Cell;
21use core::pin::Pin;
22use i_slint_core_macros::*;
23
24pub type DropEventArg = (DropEvent,);
25
26#[repr(C)]
27#[derive(FieldOffsets, Default, SlintElement)]
28#[pin]
29pub struct DragArea {
31 pub enabled: Property<bool>,
32 pub mime_type: Property<SharedString>,
33 pub data: Property<SharedString>,
34 pressed: Cell<bool>,
35 pressed_position: Cell<LogicalPoint>,
36 pub cached_rendering_data: CachedRenderingData,
37}
38
39impl Item for DragArea {
40 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
41
42 fn layout_info(
43 self: Pin<&Self>,
44 _: Orientation,
45 _window_adapter: &Rc<dyn WindowAdapter>,
46 _self_rc: &ItemRc,
47 ) -> LayoutInfo {
48 LayoutInfo { stretch: 1., ..LayoutInfo::default() }
49 }
50
51 fn input_event_filter_before_children(
52 self: Pin<&Self>,
53 event: &MouseEvent,
54 _window_adapter: &Rc<dyn WindowAdapter>,
55 _self_rc: &ItemRc,
56 ) -> InputEventFilterResult {
57 if !self.enabled() {
58 self.cancel();
59 return InputEventFilterResult::ForwardAndIgnore;
60 }
61
62 match event {
63 MouseEvent::Pressed { position, button: PointerEventButton::Left, .. } => {
64 self.pressed_position.set(*position);
65 self.pressed.set(true);
66 InputEventFilterResult::ForwardAndInterceptGrab
67 }
68 MouseEvent::Exit => {
69 self.cancel();
70 InputEventFilterResult::ForwardAndIgnore
71 }
72 MouseEvent::Released { button: PointerEventButton::Left, .. } => {
73 self.pressed.set(false);
74 InputEventFilterResult::ForwardAndIgnore
75 }
76
77 MouseEvent::Moved { position } => {
78 if !self.pressed.get() {
79 InputEventFilterResult::ForwardEvent
80 } else {
81 let pressed_pos = self.pressed_position.get();
82 let dx = (position.x - pressed_pos.x).abs();
83 let dy = (position.y - pressed_pos.y).abs();
84 let threshold = super::flickable::DISTANCE_THRESHOLD.get();
85 if dy > threshold || dx > threshold {
86 InputEventFilterResult::Intercept
87 } else {
88 InputEventFilterResult::ForwardAndInterceptGrab
89 }
90 }
91 }
92 MouseEvent::Wheel { .. } => InputEventFilterResult::ForwardAndIgnore,
93 MouseEvent::Pressed { .. } | MouseEvent::Released { .. } => {
95 InputEventFilterResult::ForwardAndIgnore
96 }
97 MouseEvent::DragMove(..) | MouseEvent::Drop(..) => {
98 InputEventFilterResult::ForwardAndIgnore
99 }
100 }
101 }
102
103 fn input_event(
104 self: Pin<&Self>,
105 event: &MouseEvent,
106 _window_adapter: &Rc<dyn WindowAdapter>,
107 _self_rc: &ItemRc,
108 ) -> InputEventResult {
109 match event {
110 MouseEvent::Pressed { .. } => InputEventResult::EventAccepted,
111 MouseEvent::Exit => {
112 self.cancel();
113 InputEventResult::EventIgnored
114 }
115 MouseEvent::Released { .. } => {
116 self.cancel();
117 InputEventResult::EventIgnored
118 }
119 MouseEvent::Moved { position } => {
120 if !self.pressed.get() || !self.enabled() {
121 return InputEventResult::EventIgnored;
122 }
123 let pressed_pos = self.pressed_position.get();
124 let dx = (position.x - pressed_pos.x).abs();
125 let dy = (position.y - pressed_pos.y).abs();
126 let threshold = super::flickable::DISTANCE_THRESHOLD.get();
127 let start_drag = dx > threshold || dy > threshold;
128 if start_drag {
129 self.pressed.set(false);
130 InputEventResult::StartDrag
131 } else {
132 InputEventResult::EventAccepted
133 }
134 }
135 MouseEvent::Wheel { .. } => InputEventResult::EventIgnored,
136 MouseEvent::DragMove(..) | MouseEvent::Drop(..) => InputEventResult::EventIgnored,
137 }
138 }
139
140 fn capture_key_event(
141 self: Pin<&Self>,
142 _: &KeyEvent,
143 _window_adapter: &Rc<dyn WindowAdapter>,
144 _self_rc: &ItemRc,
145 ) -> KeyEventResult {
146 KeyEventResult::EventIgnored
147 }
148
149 fn key_event(
150 self: Pin<&Self>,
151 _: &KeyEvent,
152 _window_adapter: &Rc<dyn WindowAdapter>,
153 _self_rc: &ItemRc,
154 ) -> KeyEventResult {
155 KeyEventResult::EventIgnored
156 }
157
158 fn focus_event(
159 self: Pin<&Self>,
160 _: &FocusEvent,
161 _window_adapter: &Rc<dyn WindowAdapter>,
162 _self_rc: &ItemRc,
163 ) -> FocusEventResult {
164 FocusEventResult::FocusIgnored
165 }
166
167 fn render(
168 self: Pin<&Self>,
169 _: &mut &mut dyn ItemRenderer,
170 _self_rc: &ItemRc,
171 _size: LogicalSize,
172 ) -> RenderingResult {
173 RenderingResult::ContinueRenderingChildren
174 }
175
176 fn bounding_rect(
177 self: core::pin::Pin<&Self>,
178 _window_adapter: &Rc<dyn WindowAdapter>,
179 _self_rc: &ItemRc,
180 mut geometry: LogicalRect,
181 ) -> LogicalRect {
182 geometry.size = LogicalSize::zero();
183 geometry
184 }
185
186 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
187 false
188 }
189}
190
191impl ItemConsts for DragArea {
192 const cached_rendering_data_offset: const_field_offset::FieldOffset<
193 DragArea,
194 CachedRenderingData,
195 > = DragArea::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
196}
197
198impl DragArea {
199 fn cancel(self: Pin<&Self>) {
200 self.pressed.set(false)
201 }
202}
203
204#[repr(C)]
205#[derive(FieldOffsets, Default, SlintElement)]
206#[pin]
207pub struct DropArea {
209 pub enabled: Property<bool>,
210 pub contains_drag: Property<bool>,
211 pub can_drop: Callback<DropEventArg, bool>,
212 pub dropped: Callback<DropEventArg>,
213
214 pub cached_rendering_data: CachedRenderingData,
215}
216
217impl Item for DropArea {
218 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
219
220 fn layout_info(
221 self: Pin<&Self>,
222 _: Orientation,
223 _window_adapter: &Rc<dyn WindowAdapter>,
224 _self_rc: &ItemRc,
225 ) -> LayoutInfo {
226 LayoutInfo { stretch: 1., ..LayoutInfo::default() }
227 }
228
229 fn input_event_filter_before_children(
230 self: Pin<&Self>,
231 _: &MouseEvent,
232 _window_adapter: &Rc<dyn WindowAdapter>,
233 _self_rc: &ItemRc,
234 ) -> InputEventFilterResult {
235 InputEventFilterResult::ForwardEvent
236 }
237
238 fn input_event(
239 self: Pin<&Self>,
240 event: &MouseEvent,
241 window_adapter: &Rc<dyn WindowAdapter>,
242 _self_rc: &ItemRc,
243 ) -> InputEventResult {
244 if !self.enabled() {
245 return InputEventResult::EventIgnored;
246 }
247 match event {
248 MouseEvent::DragMove(event) => {
249 let r = Self::FIELD_OFFSETS.can_drop.apply_pin(self).call(&(event.clone(),));
250 if r {
251 self.contains_drag.set(true);
252 if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
253 window_adapter.set_mouse_cursor(MouseCursor::Copy);
254 }
255 InputEventResult::EventAccepted
256 } else {
257 self.contains_drag.set(false);
258 InputEventResult::EventIgnored
259 }
260 }
261 MouseEvent::Drop(event) => {
262 self.contains_drag.set(false);
263 Self::FIELD_OFFSETS.dropped.apply_pin(self).call(&(event.clone(),));
264 InputEventResult::EventAccepted
265 }
266 MouseEvent::Exit => {
267 self.contains_drag.set(false);
268 InputEventResult::EventIgnored
269 }
270 _ => InputEventResult::EventIgnored,
271 }
272 }
273
274 fn capture_key_event(
275 self: Pin<&Self>,
276 _: &KeyEvent,
277 _window_adapter: &Rc<dyn WindowAdapter>,
278 _self_rc: &ItemRc,
279 ) -> KeyEventResult {
280 KeyEventResult::EventIgnored
281 }
282
283 fn key_event(
284 self: Pin<&Self>,
285 _: &KeyEvent,
286 _window_adapter: &Rc<dyn WindowAdapter>,
287 _self_rc: &ItemRc,
288 ) -> KeyEventResult {
289 KeyEventResult::EventIgnored
290 }
291
292 fn focus_event(
293 self: Pin<&Self>,
294 _: &FocusEvent,
295 _window_adapter: &Rc<dyn WindowAdapter>,
296 _self_rc: &ItemRc,
297 ) -> FocusEventResult {
298 FocusEventResult::FocusIgnored
299 }
300
301 fn render(
302 self: Pin<&Self>,
303 _: &mut &mut dyn ItemRenderer,
304 _self_rc: &ItemRc,
305 _size: LogicalSize,
306 ) -> RenderingResult {
307 RenderingResult::ContinueRenderingChildren
308 }
309
310 fn bounding_rect(
311 self: core::pin::Pin<&Self>,
312 _window_adapter: &Rc<dyn WindowAdapter>,
313 _self_rc: &ItemRc,
314 mut geometry: LogicalRect,
315 ) -> LogicalRect {
316 geometry.size = LogicalSize::zero();
317 geometry
318 }
319
320 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
321 false
322 }
323}
324
325impl ItemConsts for DropArea {
326 const cached_rendering_data_offset: const_field_offset::FieldOffset<
327 DropArea,
328 CachedRenderingData,
329 > = DropArea::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
330}