1use super::{
5 EventResult, FocusReasonArg, Item, ItemConsts, ItemRc, ItemRendererRef, KeyEventArg,
6 PointerEvent, PointerEventArg, PointerEventButton, PointerEventKind, PointerScrollEvent,
7 PointerScrollEventArg, RenderingResult, VoidArg,
8};
9use crate::api::LogicalPosition;
10use crate::input::{
11 FocusEvent, FocusEventResult, FocusReason, InputEventFilterResult, InputEventResult,
12 InternalKeyEvent, KeyEventResult, KeyEventType, Keys, MouseEvent,
13};
14use crate::item_rendering::CachedRenderingData;
15use crate::items::{ItemTreeVTable, MouseCursorInner};
16use crate::layout::{LayoutInfo, Orientation};
17use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PointLengths};
18use crate::properties::PropertyTracker;
19#[cfg(feature = "rtti")]
20use crate::rtti::*;
21use crate::window::{WindowAdapter, WindowInner};
22use crate::{Callback, Coord, Property};
23use alloc::{boxed::Box, rc::Rc, vec::Vec};
24use const_field_offset::FieldOffsets;
25use core::cell::Cell;
26use core::pin::Pin;
27use i_slint_core_macros::*;
28use vtable::{VRcMapped, VWeakMapped};
29
30#[repr(C)]
32#[derive(FieldOffsets, SlintElement, Default)]
33#[pin]
34pub struct TouchArea {
35 pub enabled: Property<bool>,
36 pub pressed: Property<bool>,
38 pub has_hover: Property<bool>,
39 pub pressed_x: Property<LogicalLength>,
43 pub pressed_y: Property<LogicalLength>,
44 pub mouse_x: Property<LogicalLength>,
46 pub mouse_y: Property<LogicalLength>,
47 pub mouse_cursor: Property<MouseCursorInner>,
48 pub clicked: Callback<VoidArg>,
49 pub double_clicked: Callback<VoidArg>,
50 pub moved: Callback<VoidArg>,
51 pub pointer_event: Callback<PointerEventArg>,
52 pub scroll_event: Callback<PointerScrollEventArg, EventResult>,
53 pub cached_rendering_data: CachedRenderingData,
55 grabbed: Cell<bool>,
57}
58
59impl Item for TouchArea {
60 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
61
62 fn deinit(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
63
64 fn layout_info(
65 self: Pin<&Self>,
66 _orientation: Orientation,
67 _cross_axis_constraint: Coord,
68 _window_adapter: &Rc<dyn WindowAdapter>,
69 _self_rc: &ItemRc,
70 ) -> LayoutInfo {
71 LayoutInfo { stretch: 1., ..LayoutInfo::default() }
72 }
73
74 fn input_event_filter_before_children(
75 self: Pin<&Self>,
76 event: &MouseEvent,
77 window_adapter: &Rc<dyn WindowAdapter>,
78 _self_rc: &ItemRc,
79 cursor: &mut MouseCursorInner,
80 ) -> InputEventFilterResult {
81 if !self.enabled() {
82 self.has_hover.set(false);
83 if self.grabbed.replace(false) {
84 self.pressed.set(false);
85 Self::FIELD_OFFSETS.pointer_event().apply_pin(self).call(&(PointerEvent {
86 button: PointerEventButton::Other,
87 kind: PointerEventKind::Cancel,
88 modifiers: window_adapter.window().0.context().0.modifiers.get().into(),
89 touch_finger_id: 0,
90 },));
91 }
92 return InputEventFilterResult::ForwardAndIgnore;
93 }
94 if matches!(event, MouseEvent::DragMove { .. } | MouseEvent::Drop { .. }) {
95 return InputEventFilterResult::ForwardAndIgnore;
97 }
98 if let Some(pos) = event.position() {
99 Self::FIELD_OFFSETS.mouse_x().apply_pin(self).set(pos.x_length());
100 Self::FIELD_OFFSETS.mouse_y().apply_pin(self).set(pos.y_length());
101 }
102 let hovering = !matches!(event, MouseEvent::Exit);
103 Self::FIELD_OFFSETS.has_hover().apply_pin(self).set(hovering);
104 if hovering {
105 *cursor = self.mouse_cursor();
106 }
107 InputEventFilterResult::ForwardAndInterceptGrab
108 }
109
110 fn input_event(
111 self: Pin<&Self>,
112 event: &MouseEvent,
113 window_adapter: &Rc<dyn WindowAdapter>,
114 self_rc: &ItemRc,
115 _: &mut MouseCursorInner,
116 ) -> InputEventResult {
117 if matches!(event, MouseEvent::Exit) {
118 Self::FIELD_OFFSETS.has_hover().apply_pin(self).set(false);
119 }
120 if !self.enabled() {
121 return InputEventResult::EventIgnored;
122 }
123 match event {
124 MouseEvent::Pressed { position, button, touch_finger_id, .. } => {
125 self.grabbed.set(true);
126 if *button == PointerEventButton::Left {
127 Self::FIELD_OFFSETS.pressed_x().apply_pin(self).set(position.x_length());
128 Self::FIELD_OFFSETS.pressed_y().apply_pin(self).set(position.y_length());
129 Self::FIELD_OFFSETS.pressed().apply_pin(self).set(true);
130 }
131 Self::FIELD_OFFSETS.pointer_event().apply_pin(self).call(&(PointerEvent {
132 button: *button,
133 kind: PointerEventKind::Down,
134 modifiers: window_adapter.window().0.context().0.modifiers.get().into(),
135 touch_finger_id: *touch_finger_id,
136 },));
137
138 InputEventResult::GrabMouse
139 }
140 MouseEvent::Exit => {
141 Self::FIELD_OFFSETS.pressed().apply_pin(self).set(false);
142 if self.grabbed.replace(false) {
143 Self::FIELD_OFFSETS.pointer_event().apply_pin(self).call(&(PointerEvent {
144 button: PointerEventButton::Other,
145 kind: PointerEventKind::Cancel,
146 modifiers: window_adapter.window().0.context().0.modifiers.get().into(),
147 touch_finger_id: 0,
148 },));
149 }
150
151 InputEventResult::EventAccepted
152 }
153
154 MouseEvent::Released { button, position, click_count, touch_finger_id } => {
155 let geometry = self_rc.geometry();
156 if *button == PointerEventButton::Left
157 && LogicalRect::new(LogicalPoint::default(), geometry.size).contains(*position)
158 && self.pressed()
159 {
160 Self::FIELD_OFFSETS.clicked().apply_pin(self).call(&());
161 if (click_count % 2) == 1 {
162 Self::FIELD_OFFSETS.double_clicked().apply_pin(self).call(&())
163 }
164 }
165
166 self.grabbed.set(false);
167 if *button == PointerEventButton::Left {
168 Self::FIELD_OFFSETS.pressed().apply_pin(self).set(false);
169 }
170 Self::FIELD_OFFSETS.pointer_event().apply_pin(self).call(&(PointerEvent {
171 button: *button,
172 kind: PointerEventKind::Up,
173 modifiers: window_adapter.window().0.context().0.modifiers.get().into(),
174 touch_finger_id: *touch_finger_id,
175 },));
176
177 InputEventResult::EventAccepted
178 }
179 MouseEvent::Moved { touch_finger_id, .. } => {
180 Self::FIELD_OFFSETS.pointer_event().apply_pin(self).call(&(PointerEvent {
181 button: PointerEventButton::Other,
182 kind: PointerEventKind::Move,
183 modifiers: window_adapter.window().0.context().0.modifiers.get().into(),
184 touch_finger_id: *touch_finger_id,
185 },));
186 if self.grabbed.get() {
187 Self::FIELD_OFFSETS.moved().apply_pin(self).call(&());
188 InputEventResult::GrabMouse
189 } else {
190 InputEventResult::EventAccepted
191 }
192 }
193 MouseEvent::Wheel { delta_x, delta_y, .. } => {
194 let modifiers = window_adapter.window().0.context().0.modifiers.get().into();
195 let r = Self::FIELD_OFFSETS.scroll_event().apply_pin(self).call(&(
196 PointerScrollEvent { delta_x: *delta_x, delta_y: *delta_y, modifiers },
197 ));
198 if self.grabbed.get() {
199 InputEventResult::GrabMouse
200 } else {
201 match r {
202 EventResult::Reject => {
203 Self::FIELD_OFFSETS.has_hover().apply_pin(self).set(false);
207 InputEventResult::EventIgnored
208 }
209 EventResult::Accept => InputEventResult::EventAccepted,
210 }
211 }
212 }
213 MouseEvent::PinchGesture { .. } | MouseEvent::RotationGesture { .. } => {
214 InputEventResult::EventIgnored
215 }
216 MouseEvent::DragMove { .. } | MouseEvent::Drop { .. } => InputEventResult::EventIgnored,
217 }
218 }
219
220 fn capture_key_event(
221 self: Pin<&Self>,
222 _: &InternalKeyEvent,
223 _window_adapter: &Rc<dyn WindowAdapter>,
224 _self_rc: &ItemRc,
225 ) -> KeyEventResult {
226 KeyEventResult::EventIgnored
227 }
228
229 fn key_event(
230 self: Pin<&Self>,
231 _: &InternalKeyEvent,
232 _window_adapter: &Rc<dyn WindowAdapter>,
233 _self_rc: &ItemRc,
234 ) -> KeyEventResult {
235 KeyEventResult::EventIgnored
236 }
237
238 fn focus_event(
239 self: Pin<&Self>,
240 _: &FocusEvent,
241 _window_adapter: &Rc<dyn WindowAdapter>,
242 _self_rc: &ItemRc,
243 ) -> FocusEventResult {
244 FocusEventResult::FocusIgnored
245 }
246
247 fn render(
248 self: Pin<&Self>,
249 _backend: &mut ItemRendererRef,
250 _self_rc: &ItemRc,
251 _size: LogicalSize,
252 ) -> RenderingResult {
253 RenderingResult::ContinueRenderingChildren
254 }
255
256 fn bounding_rect(
257 self: core::pin::Pin<&Self>,
258 _window_adapter: &Rc<dyn WindowAdapter>,
259 _self_rc: &ItemRc,
260 mut geometry: LogicalRect,
261 ) -> LogicalRect {
262 geometry.size = LogicalSize::zero();
263 geometry
264 }
265
266 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
267 false
268 }
269}
270
271impl ItemConsts for TouchArea {
272 const cached_rendering_data_offset: const_field_offset::FieldOffset<
273 TouchArea,
274 CachedRenderingData,
275 > = TouchArea::FIELD_OFFSETS.cached_rendering_data().as_unpinned_projection();
276}
277
278impl ItemConsts for KeyBinding {
279 const cached_rendering_data_offset: const_field_offset::FieldOffset<
280 KeyBinding,
281 CachedRenderingData,
282 > = KeyBinding::FIELD_OFFSETS.cached_rendering_data().as_unpinned_projection();
283}
284
285#[repr(C)]
287#[derive(FieldOffsets, Default, SlintElement)]
288#[pin]
289pub struct WindowMoveArea {
290 pub enabled: Property<bool>,
291 pressed: Cell<bool>,
292 pressed_position: Cell<LogicalPoint>,
293 pub cached_rendering_data: CachedRenderingData,
294}
295
296impl Item for WindowMoveArea {
297 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
298
299 fn deinit(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
300
301 fn layout_info(
302 self: Pin<&Self>,
303 _: Orientation,
304 _cross_axis_constraint: Coord,
305 _window_adapter: &Rc<dyn WindowAdapter>,
306 _self_rc: &ItemRc,
307 ) -> LayoutInfo {
308 LayoutInfo { stretch: 1., ..LayoutInfo::default() }
309 }
310
311 fn input_event_filter_before_children(
312 self: Pin<&Self>,
313 event: &MouseEvent,
314 _window_adapter: &Rc<dyn WindowAdapter>,
315 _self_rc: &ItemRc,
316 _: &mut MouseCursorInner,
317 ) -> InputEventFilterResult {
318 if !self.enabled() {
319 self.pressed.set(false);
320 return InputEventFilterResult::ForwardAndIgnore;
321 }
322 super::drag_n_drop::press_drag_filter(&self.pressed, &self.pressed_position, event)
323 }
324
325 fn input_event(
326 self: Pin<&Self>,
327 event: &MouseEvent,
328 window_adapter: &Rc<dyn WindowAdapter>,
329 _self_rc: &ItemRc,
330 _: &mut MouseCursorInner,
331 ) -> InputEventResult {
332 match event {
333 MouseEvent::Pressed { .. } => InputEventResult::EventAccepted,
334 MouseEvent::Exit | MouseEvent::Released { .. } => {
335 self.pressed.set(false);
336 InputEventResult::EventIgnored
337 }
338 MouseEvent::Moved { position, .. } => {
339 if !self.pressed.get() || !self.enabled() {
340 return InputEventResult::EventIgnored;
341 }
342 if super::drag_n_drop::exceeds_drag_threshold(
343 self.pressed_position.get(),
344 *position,
345 ) {
346 self.pressed.set(false);
347 if let Some(internal) = window_adapter.internal(crate::InternalToken) {
348 internal.start_window_move();
349 }
350 }
351 InputEventResult::EventAccepted
352 }
353 MouseEvent::Wheel { .. } => InputEventResult::EventIgnored,
354 MouseEvent::PinchGesture { .. } | MouseEvent::RotationGesture { .. } => {
355 InputEventResult::EventIgnored
356 }
357 MouseEvent::DragMove { .. } | MouseEvent::Drop { .. } => InputEventResult::EventIgnored,
358 }
359 }
360
361 fn capture_key_event(
362 self: Pin<&Self>,
363 _: &InternalKeyEvent,
364 _window_adapter: &Rc<dyn WindowAdapter>,
365 _self_rc: &ItemRc,
366 ) -> KeyEventResult {
367 KeyEventResult::EventIgnored
368 }
369
370 fn key_event(
371 self: Pin<&Self>,
372 _: &InternalKeyEvent,
373 _window_adapter: &Rc<dyn WindowAdapter>,
374 _self_rc: &ItemRc,
375 ) -> KeyEventResult {
376 KeyEventResult::EventIgnored
377 }
378
379 fn focus_event(
380 self: Pin<&Self>,
381 _: &FocusEvent,
382 _window_adapter: &Rc<dyn WindowAdapter>,
383 _self_rc: &ItemRc,
384 ) -> FocusEventResult {
385 FocusEventResult::FocusIgnored
386 }
387
388 fn render(
389 self: Pin<&Self>,
390 _: &mut ItemRendererRef,
391 _self_rc: &ItemRc,
392 _size: LogicalSize,
393 ) -> RenderingResult {
394 RenderingResult::ContinueRenderingChildren
395 }
396
397 fn bounding_rect(
398 self: core::pin::Pin<&Self>,
399 _window_adapter: &Rc<dyn WindowAdapter>,
400 _self_rc: &ItemRc,
401 mut geometry: LogicalRect,
402 ) -> LogicalRect {
403 geometry.size = LogicalSize::zero();
404 geometry
405 }
406
407 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
408 false
409 }
410}
411
412impl ItemConsts for WindowMoveArea {
413 const cached_rendering_data_offset: const_field_offset::FieldOffset<
414 WindowMoveArea,
415 CachedRenderingData,
416 > = WindowMoveArea::FIELD_OFFSETS.cached_rendering_data().as_unpinned_projection();
417}
418
419#[repr(C)]
420#[derive(FieldOffsets, Default, SlintElement)]
421#[pin]
422pub struct KeyBinding {
423 pub keys: Property<Keys>,
424 pub enabled: Property<bool>,
425 pub activated: Callback<VoidArg>,
426 pub cached_rendering_data: CachedRenderingData,
427}
428
429impl Item for KeyBinding {
430 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
431
432 fn deinit(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
433
434 fn layout_info(
435 self: Pin<&Self>,
436 _orientation: crate::items::Orientation,
437 _cross_axis_constraint: Coord,
438 _window_adapter: &Rc<dyn WindowAdapter>,
439 _self_rc: &ItemRc,
440 ) -> crate::layout::LayoutInfo {
441 Default::default()
442 }
443
444 fn input_event_filter_before_children(
445 self: Pin<&Self>,
446 _: &crate::input::MouseEvent,
447 _window_adapter: &Rc<dyn WindowAdapter>,
448 _self_rc: &ItemRc,
449 _: &mut crate::cursor::MouseCursorInner,
450 ) -> crate::input::InputEventFilterResult {
451 Default::default()
452 }
453
454 fn input_event(
455 self: Pin<&Self>,
456 _: &crate::input::MouseEvent,
457 _window_adapter: &Rc<dyn WindowAdapter>,
458 _self_rc: &ItemRc,
459 _: &mut crate::cursor::MouseCursorInner,
460 ) -> crate::input::InputEventResult {
461 Default::default()
462 }
463
464 fn capture_key_event(
465 self: Pin<&Self>,
466 _: &InternalKeyEvent,
467 _window_adapter: &Rc<dyn WindowAdapter>,
468 _self_rc: &ItemRc,
469 ) -> crate::input::KeyEventResult {
470 crate::input::KeyEventResult::EventIgnored
471 }
472
473 fn key_event(
474 self: Pin<&Self>,
475 _: &InternalKeyEvent,
476 _window_adapter: &Rc<dyn WindowAdapter>,
477 _self_rc: &ItemRc,
478 ) -> crate::input::KeyEventResult {
479 Default::default()
480 }
481
482 fn focus_event(
483 self: Pin<&Self>,
484 _: &crate::input::FocusEvent,
485 _window_adapter: &Rc<dyn WindowAdapter>,
486 _self_rc: &ItemRc,
487 ) -> crate::input::FocusEventResult {
488 Default::default()
489 }
490
491 fn render(
492 self: Pin<&Self>,
493 _backend: &mut &mut dyn crate::item_rendering::ItemRenderer,
494 _self_rc: &ItemRc,
495 _size: crate::lengths::LogicalSize,
496 ) -> crate::items::RenderingResult {
497 Default::default()
498 }
499
500 fn bounding_rect(
501 self: Pin<&Self>,
502 _window_adapter: &Rc<dyn WindowAdapter>,
503 _self_rc: &ItemRc,
504 geometry: crate::lengths::LogicalRect,
505 ) -> crate::lengths::LogicalRect {
506 geometry
507 }
508
509 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
510 false
511 }
512}
513
514#[repr(C)]
517#[derive(Default)] pub struct MaybeKeyBindingList(Cell<*const KeyBindingList>);
519
520impl MaybeKeyBindingList {
521 fn ensure_init(&self) {
522 if self.0.get().is_null() {
525 self.0.set(Box::leak(Box::default()));
526 }
527 }
528}
529
530impl Drop for MaybeKeyBindingList {
531 fn drop(&mut self) {
532 let ptr = self.0.replace(core::ptr::null());
533 if !ptr.is_null() {
534 drop(unsafe { Box::from_raw(ptr as *mut KeyBindingList) });
536 }
537 }
538}
539
540impl MaybeKeyBindingList {
541 fn deref_pin(self: Pin<&Self>) -> Pin<&KeyBindingList> {
542 self.ensure_init();
543 unsafe { Pin::new_unchecked(&*self.get_ref().0.get()) }
545 }
546}
547
548#[derive(Default)]
549#[pin_project::pin_project]
550pub struct KeyBindingList {
551 found: core::cell::RefCell<Vec<VWeakMapped<ItemTreeVTable, KeyBinding>>>,
552 #[pin]
553 property_tracker: PropertyTracker,
554}
555
556#[repr(C)]
558#[derive(FieldOffsets, Default, SlintElement)]
559#[pin]
560pub struct FocusScope {
561 pub enabled: Property<bool>,
562 pub has_focus: Property<bool>,
563 pub focus_on_click: Property<bool>,
564 pub focus_on_tab_navigation: Property<bool>,
565 pub key_pressed: Callback<KeyEventArg, EventResult>,
566 pub key_released: Callback<KeyEventArg, EventResult>,
567 pub capture_key_pressed: Callback<KeyEventArg, EventResult>,
568 pub capture_key_released: Callback<KeyEventArg, EventResult>,
569 pub focus_changed_event: Callback<FocusReasonArg>,
570 pub focus_gained: Callback<FocusReasonArg>,
571 pub focus_lost: Callback<FocusReasonArg>,
572 pub key_bindings: MaybeKeyBindingList,
573 pub cached_rendering_data: CachedRenderingData,
575}
576
577impl FocusScope {
578 fn visit_enabled_key_bindings<R>(
579 self: Pin<&Self>,
580 self_rc: &ItemRc,
581 mut fun: impl FnMut(&VRcMapped<ItemTreeVTable, KeyBinding>) -> Option<R>,
582 ) -> Option<R> {
583 let list = Self::FIELD_OFFSETS.key_bindings().apply_pin(self);
584 let list = list.deref_pin();
585
586 list.project_ref().property_tracker.evaluate_if_dirty(|| {
587 let mut found = list.found.borrow_mut();
588 found.clear();
589
590 let mut next = self_rc.first_child();
591 while let Some(child) = next {
592 if let Some(key_binding) = ItemRc::downcast::<KeyBinding>(&child)
593 && key_binding.as_pin_ref().enabled()
594 {
595 found.push(VRcMapped::downgrade(&key_binding));
596 }
597 next = child.next_sibling();
598 }
599 });
600
601 let list = list.found.borrow();
602 for key_binding in &*list {
603 let Some(shortcut) = key_binding.upgrade() else {
604 crate::debug_log!("Warning: Found a dropped KeyBinding!");
605 continue;
606 };
607 if let Some(result) = fun(&shortcut) {
608 return Some(result);
609 }
610 }
611
612 None
613 }
614
615 fn key_binding_for_event(
617 self: Pin<&Self>,
618 self_rc: &ItemRc,
619 inter_key_event: &InternalKeyEvent,
620 ) -> Option<(VRcMapped<ItemTreeVTable, KeyBinding>, bool)> {
621 let mut first_match = None;
622
623 let ambiguous = self.visit_enabled_key_bindings(self_rc, |key_binding| {
624 let keys = key_binding.as_pin_ref().keys();
625 if keys.matches(&inter_key_event.key_event) {
626 match &first_match {
627 Some(key_binding) => {
628 return Some(VRcMapped::clone(key_binding));
629 }
630 None => {
631 first_match = Some(VRcMapped::clone(key_binding));
632 }
633 };
634 }
635 None
636 });
637
638 first_match.map(|binding| (VRcMapped::clone(&binding), ambiguous.is_some()))
639 }
640}
641
642impl Item for FocusScope {
643 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
644
645 fn deinit(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
646
647 fn layout_info(
648 self: Pin<&Self>,
649 _orientation: Orientation,
650 _cross_axis_constraint: Coord,
651 _window_adapter: &Rc<dyn WindowAdapter>,
652 _self_rc: &ItemRc,
653 ) -> LayoutInfo {
654 LayoutInfo { stretch: 1., ..LayoutInfo::default() }
655 }
656
657 fn input_event_filter_before_children(
658 self: Pin<&Self>,
659 _: &MouseEvent,
660 _window_adapter: &Rc<dyn WindowAdapter>,
661 _self_rc: &ItemRc,
662 _: &mut MouseCursorInner,
663 ) -> InputEventFilterResult {
664 InputEventFilterResult::ForwardEvent
665 }
666
667 fn input_event(
668 self: Pin<&Self>,
669 event: &MouseEvent,
670 window_adapter: &Rc<dyn WindowAdapter>,
671 self_rc: &ItemRc,
672 _: &mut MouseCursorInner,
673 ) -> InputEventResult {
674 if self.enabled()
675 && self.focus_on_click()
676 && matches!(event, MouseEvent::Pressed { .. })
677 && !self.has_focus()
678 {
679 WindowInner::from_pub(window_adapter.window()).set_focus_item(
680 self_rc,
681 true,
682 FocusReason::PointerClick,
683 );
684 InputEventResult::EventAccepted
685 } else {
686 InputEventResult::EventIgnored
687 }
688 }
689
690 fn capture_key_event(
691 self: Pin<&Self>,
692 event: &InternalKeyEvent,
693 _window_adapter: &Rc<dyn WindowAdapter>,
694 _self_rc: &ItemRc,
695 ) -> KeyEventResult {
696 let r = match event.event_type {
697 KeyEventType::KeyPressed => Self::FIELD_OFFSETS
698 .capture_key_pressed()
699 .apply_pin(self)
700 .call(&(event.key_event.clone(),)),
701 KeyEventType::KeyReleased => Self::FIELD_OFFSETS
702 .capture_key_released()
703 .apply_pin(self)
704 .call(&(event.key_event.clone(),)),
705 KeyEventType::UpdateComposition | KeyEventType::CommitComposition => {
706 EventResult::Reject
707 }
708 };
709 match r {
710 EventResult::Accept => KeyEventResult::EventAccepted,
711 EventResult::Reject => KeyEventResult::EventIgnored,
712 }
713 }
714
715 fn key_event(
716 self: Pin<&Self>,
717 event: &InternalKeyEvent,
718 _window_adapter: &Rc<dyn WindowAdapter>,
719 self_rc: &ItemRc,
720 ) -> KeyEventResult {
721 let r = match event.event_type {
722 KeyEventType::KeyPressed => {
723 if let Some((key_binding, ambiguous)) = self.key_binding_for_event(self_rc, event) {
724 if ambiguous {
725 let keys = KeyBinding::FIELD_OFFSETS
726 .keys()
727 .apply_pin(key_binding.as_pin_ref())
728 .get();
729 crate::debug_log!(
730 "Warning: Multiple matching KeyBinding elements for keys {:?}!",
731 keys
732 );
733 }
734 KeyBinding::FIELD_OFFSETS
735 .activated()
736 .apply_pin(key_binding.as_pin_ref())
737 .call(&());
738 EventResult::Accept
739 } else {
740 Self::FIELD_OFFSETS
741 .key_pressed()
742 .apply_pin(self)
743 .call(&(event.key_event.clone(),))
744 }
745 }
746 KeyEventType::KeyReleased => {
747 let binding = self.key_binding_for_event(self_rc, event);
748 if binding.is_some() {
749 EventResult::Accept
754 } else {
755 Self::FIELD_OFFSETS
756 .key_released()
757 .apply_pin(self)
758 .call(&(event.key_event.clone(),))
759 }
760 }
761 KeyEventType::UpdateComposition | KeyEventType::CommitComposition => {
762 EventResult::Reject
763 }
764 };
765 match r {
766 EventResult::Accept => KeyEventResult::EventAccepted,
767 EventResult::Reject => KeyEventResult::EventIgnored,
768 }
769 }
770
771 fn focus_event(
772 self: Pin<&Self>,
773 event: &FocusEvent,
774 _window_adapter: &Rc<dyn WindowAdapter>,
775 _self_rc: &ItemRc,
776 ) -> FocusEventResult {
777 if !self.enabled() {
778 return FocusEventResult::FocusIgnored;
779 }
780
781 match event {
782 FocusEvent::FocusIn(reason) => {
783 match reason {
784 FocusReason::TabNavigation if !self.focus_on_tab_navigation() => {
785 return FocusEventResult::FocusIgnored;
786 }
787 FocusReason::PointerClick if !self.focus_on_click() => {
788 return FocusEventResult::FocusIgnored;
789 }
790 _ => (),
791 };
792
793 self.has_focus.set(true);
794 Self::FIELD_OFFSETS.focus_changed_event().apply_pin(self).call(&(*reason,));
795 Self::FIELD_OFFSETS.focus_gained().apply_pin(self).call(&(*reason,));
796 }
797 FocusEvent::FocusOut(reason) => {
798 self.has_focus.set(false);
799 Self::FIELD_OFFSETS.focus_changed_event().apply_pin(self).call(&(*reason,));
800 Self::FIELD_OFFSETS.focus_lost().apply_pin(self).call(&(*reason,));
801 }
802 }
803 FocusEventResult::FocusAccepted
804 }
805
806 fn render(
807 self: Pin<&Self>,
808 _backend: &mut ItemRendererRef,
809 _self_rc: &ItemRc,
810 _size: LogicalSize,
811 ) -> RenderingResult {
812 RenderingResult::ContinueRenderingChildren
813 }
814
815 fn bounding_rect(
816 self: core::pin::Pin<&Self>,
817 _window_adapter: &Rc<dyn WindowAdapter>,
818 _self_rc: &ItemRc,
819 mut geometry: LogicalRect,
820 ) -> LogicalRect {
821 geometry.size = LogicalSize::zero();
822 geometry
823 }
824
825 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
826 false
827 }
828}
829
830impl ItemConsts for FocusScope {
831 const cached_rendering_data_offset: const_field_offset::FieldOffset<
832 FocusScope,
833 CachedRenderingData,
834 > = FocusScope::FIELD_OFFSETS.cached_rendering_data().as_unpinned_projection();
835}
836
837#[repr(C)]
838#[derive(FieldOffsets, Default, SlintElement)]
839#[pin]
840pub struct SwipeGestureHandler {
841 pub enabled: Property<bool>,
842 pub handle_swipe_left: Property<bool>,
843 pub handle_swipe_right: Property<bool>,
844 pub handle_swipe_up: Property<bool>,
845 pub handle_swipe_down: Property<bool>,
846
847 pub moved: Callback<VoidArg>,
848 pub swiped: Callback<VoidArg>,
849 pub cancelled: Callback<VoidArg>,
850
851 pub pressed_position: Property<LogicalPosition>,
852 pub current_position: Property<LogicalPosition>,
853 pub swiping: Property<bool>,
854
855 pressed: Cell<bool>,
857 pub cached_rendering_data: CachedRenderingData,
860}
861
862impl Item for SwipeGestureHandler {
863 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
864
865 fn deinit(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
866
867 fn layout_info(
868 self: Pin<&Self>,
869 _orientation: Orientation,
870 _cross_axis_constraint: Coord,
871 _window_adapter: &Rc<dyn WindowAdapter>,
872 _self_rc: &ItemRc,
873 ) -> LayoutInfo {
874 LayoutInfo { stretch: 1., ..LayoutInfo::default() }
875 }
876
877 fn input_event_filter_before_children(
878 self: Pin<&Self>,
879 event: &MouseEvent,
880 _window_adapter: &Rc<dyn WindowAdapter>,
881 _self_rc: &ItemRc,
882 _: &mut MouseCursorInner,
883 ) -> InputEventFilterResult {
884 if !self.enabled() {
885 if self.pressed.get() {
886 self.cancel_impl();
887 }
888 return InputEventFilterResult::ForwardAndIgnore;
889 }
890
891 match event {
892 MouseEvent::Pressed { position, button: PointerEventButton::Left, .. } => {
893 Self::FIELD_OFFSETS
894 .pressed_position()
895 .apply_pin(self)
896 .set(crate::lengths::logical_position_to_api(*position));
897 self.pressed.set(true);
898 InputEventFilterResult::DelayForwarding(
899 super::flickable::FORWARD_DELAY.as_millis() as _
900 )
901 }
902 MouseEvent::Exit => {
903 self.cancel_impl();
904 InputEventFilterResult::ForwardAndIgnore
905 }
906 MouseEvent::Released { button: PointerEventButton::Left, .. } => {
907 if self.swiping() {
908 InputEventFilterResult::Intercept
909 } else {
910 self.pressed.set(false);
911 InputEventFilterResult::ForwardEvent
912 }
913 }
914 MouseEvent::Moved { position, .. } => {
915 if self.swiping() {
916 InputEventFilterResult::Intercept
917 } else if !self.pressed.get() {
918 InputEventFilterResult::ForwardEvent
919 } else if self.is_over_threshold(position) {
920 InputEventFilterResult::Intercept
921 } else {
922 InputEventFilterResult::ForwardAndInterceptGrab
923 }
924 }
925 MouseEvent::Wheel { .. } => InputEventFilterResult::ForwardAndIgnore,
926 MouseEvent::Pressed { .. } | MouseEvent::Released { .. } => {
928 InputEventFilterResult::ForwardAndIgnore
929 }
930 MouseEvent::PinchGesture { .. } | MouseEvent::RotationGesture { .. } => {
931 InputEventFilterResult::ForwardAndIgnore
932 }
933 MouseEvent::DragMove { .. } | MouseEvent::Drop { .. } => {
934 InputEventFilterResult::ForwardAndIgnore
935 }
936 }
937 }
938
939 fn input_event(
940 self: Pin<&Self>,
941 event: &MouseEvent,
942 _window_adapter: &Rc<dyn WindowAdapter>,
943 _self_rc: &ItemRc,
944 _: &mut MouseCursorInner,
945 ) -> InputEventResult {
946 match event {
947 MouseEvent::Pressed { .. } => InputEventResult::GrabMouse,
948 MouseEvent::Exit => {
949 self.cancel_impl();
950 InputEventResult::EventIgnored
951 }
952 MouseEvent::Released { position, .. } => {
953 if !self.pressed.get() && !self.swiping() {
954 return InputEventResult::EventIgnored;
955 }
956 self.current_position.set(crate::lengths::logical_position_to_api(*position));
957 self.pressed.set(false);
958 if self.swiping() {
959 Self::FIELD_OFFSETS.swiping().apply_pin(self).set(false);
960 Self::FIELD_OFFSETS.swiped().apply_pin(self).call(&());
961 InputEventResult::EventAccepted
962 } else {
963 InputEventResult::EventIgnored
964 }
965 }
966 MouseEvent::Moved { position, .. } => {
967 if !self.pressed.get() {
968 return InputEventResult::EventAccepted;
969 }
970 self.current_position.set(crate::lengths::logical_position_to_api(*position));
971 let mut swiping = self.swiping();
972 if !swiping && self.is_over_threshold(position) {
973 Self::FIELD_OFFSETS.swiping().apply_pin(self).set(true);
974 swiping = true;
975 }
976 Self::FIELD_OFFSETS.moved().apply_pin(self).call(&());
977 if swiping { InputEventResult::GrabMouse } else { InputEventResult::EventAccepted }
978 }
979 MouseEvent::Wheel { .. } => InputEventResult::EventIgnored,
980 MouseEvent::PinchGesture { .. } | MouseEvent::RotationGesture { .. } => {
981 InputEventResult::EventIgnored
982 }
983 MouseEvent::DragMove { .. } | MouseEvent::Drop { .. } => InputEventResult::EventIgnored,
984 }
985 }
986
987 fn capture_key_event(
988 self: Pin<&Self>,
989 _: &InternalKeyEvent,
990 _window_adapter: &Rc<dyn WindowAdapter>,
991 _self_rc: &ItemRc,
992 ) -> KeyEventResult {
993 KeyEventResult::EventIgnored
994 }
995
996 fn key_event(
997 self: Pin<&Self>,
998 _event: &InternalKeyEvent,
999 _window_adapter: &Rc<dyn WindowAdapter>,
1000 _self_rc: &ItemRc,
1001 ) -> KeyEventResult {
1002 KeyEventResult::EventIgnored
1003 }
1004
1005 fn focus_event(
1006 self: Pin<&Self>,
1007 _: &FocusEvent,
1008 _window_adapter: &Rc<dyn WindowAdapter>,
1009 _self_rc: &ItemRc,
1010 ) -> FocusEventResult {
1011 FocusEventResult::FocusIgnored
1012 }
1013
1014 fn render(
1015 self: Pin<&Self>,
1016 _backend: &mut ItemRendererRef,
1017 _self_rc: &ItemRc,
1018 _size: LogicalSize,
1019 ) -> RenderingResult {
1020 RenderingResult::ContinueRenderingChildren
1021 }
1022
1023 fn bounding_rect(
1024 self: core::pin::Pin<&Self>,
1025 _window_adapter: &Rc<dyn WindowAdapter>,
1026 _self_rc: &ItemRc,
1027 mut geometry: LogicalRect,
1028 ) -> LogicalRect {
1029 geometry.size = LogicalSize::zero();
1030 geometry
1031 }
1032
1033 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
1034 false
1035 }
1036}
1037
1038impl ItemConsts for SwipeGestureHandler {
1039 const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
1040 Self::FIELD_OFFSETS.cached_rendering_data().as_unpinned_projection();
1041}
1042
1043impl SwipeGestureHandler {
1044 pub fn cancel(self: Pin<&Self>, _: &Rc<dyn WindowAdapter>, _: &ItemRc) {
1045 self.cancel_impl();
1046 }
1047
1048 fn cancel_impl(self: Pin<&Self>) {
1049 if !self.pressed.replace(false) {
1050 debug_assert!(!self.swiping());
1051 return;
1052 }
1053 if self.swiping() {
1054 Self::FIELD_OFFSETS.swiping().apply_pin(self).set(false);
1055 Self::FIELD_OFFSETS.cancelled().apply_pin(self).call(&());
1056 }
1057 }
1058
1059 fn is_over_threshold(self: Pin<&Self>, position: &LogicalPoint) -> bool {
1060 let pressed_pos = self.pressed_position();
1061 let dx = position.x - pressed_pos.x as Coord;
1062 let dy = position.y - pressed_pos.y as Coord;
1063 let threshold = super::flickable::DISTANCE_THRESHOLD.get();
1064 (self.handle_swipe_down() && dy > threshold && dy > dx.abs() / 2 as Coord)
1065 || (self.handle_swipe_up() && dy < -threshold && dy < -dx.abs() / 2 as Coord)
1066 || (self.handle_swipe_left() && dx < -threshold && dx < -dy.abs() / 2 as Coord)
1067 || (self.handle_swipe_right() && dx > threshold && dx > dy.abs() / 2 as Coord)
1068 }
1069}
1070
1071#[cfg(feature = "ffi")]
1072mod ffi {
1073 use super::*;
1074
1075 #[unsafe(no_mangle)]
1076 pub unsafe extern "C" fn slint_swipegesturehandler_cancel(
1077 s: Pin<&SwipeGestureHandler>,
1078 window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,
1079 self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,
1080 self_index: u32,
1081 ) {
1082 unsafe {
1083 let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);
1084 let self_rc = ItemRc::new(self_component.clone(), self_index);
1085 s.cancel(window_adapter, &self_rc);
1086 }
1087 }
1088
1089 #[unsafe(no_mangle)]
1093 pub unsafe extern "C" fn slint_maybe_key_binding_list_init(list: *mut MaybeKeyBindingList) {
1094 unsafe {
1095 core::ptr::write(list, MaybeKeyBindingList::default());
1096 }
1097 }
1098
1099 #[unsafe(no_mangle)]
1102 pub unsafe extern "C" fn slint_maybe_key_binding_list_free(list: *mut MaybeKeyBindingList) {
1103 unsafe { core::ptr::drop_in_place(list) };
1104 }
1105}
1106
1107#[repr(C)]
1113#[derive(FieldOffsets, Default, SlintElement)]
1114#[pin]
1115pub struct ScaleRotateGestureHandler {
1116 pub enabled: Property<bool>,
1117
1118 pub active: Property<bool>,
1120 pub scale: Property<f32>,
1124 pub rotation: Property<f32>,
1127 pub center: Property<LogicalPosition>,
1128
1129 pub started: Callback<VoidArg>,
1131 pub updated: Callback<VoidArg>,
1132 pub ended: Callback<VoidArg>,
1133 pub cancelled: Callback<VoidArg>,
1134
1135 pub cached_rendering_data: CachedRenderingData,
1137}
1138
1139impl Item for ScaleRotateGestureHandler {
1140 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {
1141 self.scale.set(1.0);
1142 }
1143
1144 fn deinit(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
1145
1146 fn layout_info(
1147 self: Pin<&Self>,
1148 _orientation: Orientation,
1149 _cross_axis_constraint: Coord,
1150 _window_adapter: &Rc<dyn WindowAdapter>,
1151 _self_rc: &ItemRc,
1152 ) -> LayoutInfo {
1153 LayoutInfo { stretch: 1., ..LayoutInfo::default() }
1154 }
1155
1156 fn input_event_filter_before_children(
1157 self: Pin<&Self>,
1158 event: &MouseEvent,
1159 _window_adapter: &Rc<dyn WindowAdapter>,
1160 _self_rc: &ItemRc,
1161 _: &mut MouseCursorInner,
1162 ) -> InputEventFilterResult {
1163 match event {
1164 MouseEvent::PinchGesture { .. } | MouseEvent::RotationGesture { .. }
1166 if self.enabled() =>
1167 {
1168 InputEventFilterResult::ForwardEvent
1169 }
1170 _ if self.active() => InputEventFilterResult::Intercept,
1173 _ => InputEventFilterResult::ForwardAndIgnore,
1174 }
1175 }
1176
1177 fn input_event(
1178 self: Pin<&Self>,
1179 event: &MouseEvent,
1180 _window_adapter: &Rc<dyn WindowAdapter>,
1181 _self_rc: &ItemRc,
1182 _: &mut MouseCursorInner,
1183 ) -> InputEventResult {
1184 use crate::input::TouchPhase;
1185 match event {
1186 MouseEvent::PinchGesture { delta, phase, position } => {
1187 if !self.enabled() {
1188 if self.active() {
1189 self.cancel_impl();
1190 }
1191 return InputEventResult::EventIgnored;
1192 }
1193 let new_scale = self.scale() * (1.0 + delta);
1194 Self::FIELD_OFFSETS.scale().apply_pin(self).set(new_scale);
1195 let center = crate::lengths::logical_position_to_api(*position);
1196 Self::FIELD_OFFSETS.center().apply_pin(self).set(center);
1197 match phase {
1198 TouchPhase::Started => {
1199 if !self.active() {
1200 Self::FIELD_OFFSETS.active().apply_pin(self).set(true);
1201 Self::FIELD_OFFSETS.started().apply_pin(self).call(&());
1202 }
1203 InputEventResult::GrabMouse
1204 }
1205 TouchPhase::Moved => {
1206 if !self.active() {
1207 return InputEventResult::EventIgnored;
1208 }
1209 Self::FIELD_OFFSETS.updated().apply_pin(self).call(&());
1210 InputEventResult::GrabMouse
1211 }
1212 TouchPhase::Ended => self.end_impl(),
1213 TouchPhase::Cancelled => {
1214 self.cancel_impl();
1215 InputEventResult::EventAccepted
1216 }
1217 }
1218 }
1219 MouseEvent::RotationGesture { delta, phase, position } => {
1220 if !self.enabled() {
1221 return InputEventResult::EventIgnored;
1222 }
1223 let center = crate::lengths::logical_position_to_api(*position);
1224 Self::FIELD_OFFSETS.center().apply_pin(self).set(center);
1225 let new_rotation = self.rotation() + delta;
1226 Self::FIELD_OFFSETS.rotation().apply_pin(self).set(new_rotation);
1227 match phase {
1228 TouchPhase::Started => {
1229 if !self.active() {
1230 Self::FIELD_OFFSETS.active().apply_pin(self).set(true);
1231 Self::FIELD_OFFSETS.started().apply_pin(self).call(&());
1232 }
1233 InputEventResult::GrabMouse
1234 }
1235 TouchPhase::Moved => {
1236 if !self.active() {
1237 return InputEventResult::EventIgnored;
1238 }
1239 Self::FIELD_OFFSETS.updated().apply_pin(self).call(&());
1240 InputEventResult::GrabMouse
1241 }
1242 TouchPhase::Ended => self.end_impl(),
1243 TouchPhase::Cancelled => {
1244 self.cancel_impl();
1245 InputEventResult::EventAccepted
1246 }
1247 }
1248 }
1249 _ if self.active() => InputEventResult::GrabMouse,
1251 _ => InputEventResult::EventIgnored,
1252 }
1253 }
1254
1255 fn capture_key_event(
1256 self: Pin<&Self>,
1257 _: &InternalKeyEvent,
1258 _window_adapter: &Rc<dyn WindowAdapter>,
1259 _self_rc: &ItemRc,
1260 ) -> KeyEventResult {
1261 KeyEventResult::EventIgnored
1262 }
1263
1264 fn key_event(
1265 self: Pin<&Self>,
1266 _event: &InternalKeyEvent,
1267 _window_adapter: &Rc<dyn WindowAdapter>,
1268 _self_rc: &ItemRc,
1269 ) -> KeyEventResult {
1270 KeyEventResult::EventIgnored
1271 }
1272
1273 fn focus_event(
1274 self: Pin<&Self>,
1275 _: &FocusEvent,
1276 _window_adapter: &Rc<dyn WindowAdapter>,
1277 _self_rc: &ItemRc,
1278 ) -> FocusEventResult {
1279 FocusEventResult::FocusIgnored
1280 }
1281
1282 fn render(
1283 self: Pin<&Self>,
1284 _backend: &mut ItemRendererRef,
1285 _self_rc: &ItemRc,
1286 _size: LogicalSize,
1287 ) -> RenderingResult {
1288 RenderingResult::ContinueRenderingChildren
1289 }
1290
1291 fn bounding_rect(
1292 self: core::pin::Pin<&Self>,
1293 _window_adapter: &Rc<dyn WindowAdapter>,
1294 _self_rc: &ItemRc,
1295 mut geometry: LogicalRect,
1296 ) -> LogicalRect {
1297 geometry.size = LogicalSize::zero();
1298 geometry
1299 }
1300
1301 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
1302 false
1303 }
1304}
1305
1306impl ItemConsts for ScaleRotateGestureHandler {
1307 const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
1308 Self::FIELD_OFFSETS.cached_rendering_data().as_unpinned_projection();
1309}
1310
1311impl ScaleRotateGestureHandler {
1312 fn cancel_impl(self: Pin<&Self>) {
1313 if !self.active() {
1314 return;
1315 }
1316 Self::FIELD_OFFSETS.active().apply_pin(self).set(false);
1317 Self::FIELD_OFFSETS.cancelled().apply_pin(self).call(&());
1318 Self::FIELD_OFFSETS.scale().apply_pin(self).set(1.0);
1322 Self::FIELD_OFFSETS.rotation().apply_pin(self).set(0.0);
1323 }
1324
1325 fn end_impl(self: Pin<&Self>) -> InputEventResult {
1326 if !self.active() {
1327 return InputEventResult::EventIgnored;
1328 }
1329 Self::FIELD_OFFSETS.ended().apply_pin(self).call(&());
1330 Self::FIELD_OFFSETS.active().apply_pin(self).set(false);
1331 Self::FIELD_OFFSETS.scale().apply_pin(self).set(1.0);
1332 Self::FIELD_OFFSETS.rotation().apply_pin(self).set(0.0);
1333 InputEventResult::EventAccepted
1334 }
1335}