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