1#![warn(missing_docs)]
7
8use crate::item_tree::ItemTreeRc;
9use crate::item_tree::{ItemRc, ItemWeak, VisitChildrenResult};
10pub use crate::items::PointerEventButton;
11use crate::items::{DropEvent, ItemRef, TextCursorDirection};
12pub use crate::items::{FocusReason, KeyEvent, KeyboardModifiers};
13use crate::lengths::{ItemTransform, LogicalPoint, LogicalVector};
14use crate::timers::Timer;
15use crate::window::{WindowAdapter, WindowInner};
16use crate::{Coord, Property, SharedString};
17use alloc::rc::Rc;
18use alloc::vec::Vec;
19use const_field_offset::FieldOffsets;
20use core::cell::Cell;
21use core::pin::Pin;
22use core::time::Duration;
23
24#[repr(C)]
29#[derive(Debug, Clone, PartialEq)]
30#[allow(missing_docs)]
31pub enum MouseEvent {
32 Pressed { position: LogicalPoint, button: PointerEventButton, click_count: u8 },
37 Released { position: LogicalPoint, button: PointerEventButton, click_count: u8 },
42 Moved { position: LogicalPoint },
44 Wheel { position: LogicalPoint, delta_x: Coord, delta_y: Coord },
49 DragMove(DropEvent),
53 Drop(DropEvent),
55 Exit,
57}
58
59impl MouseEvent {
60 pub fn position(&self) -> Option<LogicalPoint> {
62 match self {
63 MouseEvent::Pressed { position, .. } => Some(*position),
64 MouseEvent::Released { position, .. } => Some(*position),
65 MouseEvent::Moved { position } => Some(*position),
66 MouseEvent::Wheel { position, .. } => Some(*position),
67 MouseEvent::DragMove(e) | MouseEvent::Drop(e) => {
68 Some(crate::lengths::logical_point_from_api(e.position))
69 }
70 MouseEvent::Exit => None,
71 }
72 }
73
74 pub fn translate(&mut self, vec: LogicalVector) {
76 let pos = match self {
77 MouseEvent::Pressed { position, .. } => Some(position),
78 MouseEvent::Released { position, .. } => Some(position),
79 MouseEvent::Moved { position } => Some(position),
80 MouseEvent::Wheel { position, .. } => Some(position),
81 MouseEvent::DragMove(e) | MouseEvent::Drop(e) => {
82 e.position = crate::api::LogicalPosition::from_euclid(
83 crate::lengths::logical_point_from_api(e.position) + vec,
84 );
85 None
86 }
87 MouseEvent::Exit => None,
88 };
89 if let Some(pos) = pos {
90 *pos += vec;
91 }
92 }
93
94 pub fn transform(&mut self, transform: ItemTransform) {
96 let pos = match self {
97 MouseEvent::Pressed { position, .. } => Some(position),
98 MouseEvent::Released { position, .. } => Some(position),
99 MouseEvent::Moved { position } => Some(position),
100 MouseEvent::Wheel { position, .. } => Some(position),
101 MouseEvent::DragMove(e) | MouseEvent::Drop(e) => {
102 e.position = crate::api::LogicalPosition::from_euclid(
103 transform
104 .transform_point(crate::lengths::logical_point_from_api(e.position).cast())
105 .cast(),
106 );
107 None
108 }
109 MouseEvent::Exit => None,
110 };
111 if let Some(pos) = pos {
112 *pos = transform.transform_point(pos.cast()).cast();
113 }
114 }
115
116 fn set_click_count(&mut self, count: u8) {
118 match self {
119 MouseEvent::Pressed { click_count, .. } | MouseEvent::Released { click_count, .. } => {
120 *click_count = count
121 }
122 _ => (),
123 }
124 }
125}
126
127#[repr(u8)]
132#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
133pub enum InputEventResult {
134 EventAccepted,
137 #[default]
139 EventIgnored,
140 GrabMouse,
142 StartDrag,
144}
145
146#[repr(C)]
150#[derive(Debug, Copy, Clone, PartialEq, Default)]
151pub enum InputEventFilterResult {
152 #[default]
155 ForwardEvent,
156 ForwardAndIgnore,
159 ForwardAndInterceptGrab,
162 Intercept,
165 DelayForwarding(u64),
172}
173
174#[allow(missing_docs, non_upper_case_globals)]
176pub mod key_codes {
177 macro_rules! declare_consts_for_special_keys {
178 ($($char:literal # $name:ident # $($_qt:ident)|* # $($_winit:ident $(($_pos:ident))?)|* # $($_xkb:ident)|*;)*) => {
179 $(pub const $name : char = $char;)*
180
181 #[allow(missing_docs)]
182 #[derive(Debug, Copy, Clone, PartialEq)]
183 #[non_exhaustive]
184 pub enum Key {
199 $($name,)*
200 }
201
202 impl From<Key> for char {
203 fn from(k: Key) -> Self {
204 match k {
205 $(Key::$name => $name,)*
206 }
207 }
208 }
209
210 impl From<Key> for crate::SharedString {
211 fn from(k: Key) -> Self {
212 char::from(k).into()
213 }
214 }
215 };
216 }
217
218 i_slint_common::for_each_special_keys!(declare_consts_for_special_keys);
219}
220
221#[derive(Clone, Copy, Default, Debug)]
224pub(crate) struct InternalKeyboardModifierState {
225 left_alt: bool,
226 right_alt: bool,
227 altgr: bool,
228 left_control: bool,
229 right_control: bool,
230 left_meta: bool,
231 right_meta: bool,
232 left_shift: bool,
233 right_shift: bool,
234}
235
236impl InternalKeyboardModifierState {
237 pub(crate) fn state_update(mut self, pressed: bool, text: &SharedString) -> Option<Self> {
240 if let Some(key_code) = text.chars().next() {
241 match key_code {
242 key_codes::Alt => self.left_alt = pressed,
243 key_codes::AltGr => self.altgr = pressed,
244 key_codes::Control => self.left_control = pressed,
245 key_codes::ControlR => self.right_control = pressed,
246 key_codes::Shift => self.left_shift = pressed,
247 key_codes::ShiftR => self.right_shift = pressed,
248 key_codes::Meta => self.left_meta = pressed,
249 key_codes::MetaR => self.right_meta = pressed,
250 _ => return None,
251 };
252
253 debug_assert_eq!(key_code.len_utf8(), text.len());
257 }
258
259 #[cfg(target_os = "windows")]
261 {
262 if self.altgr {
263 self.left_control = false;
265 self.right_control = false;
266 } else if self.control() && self.alt() {
267 self.left_control = false;
269 self.right_control = false;
270 self.left_alt = false;
271 self.right_alt = false;
272 }
273 }
274
275 Some(self)
276 }
277
278 pub fn shift(&self) -> bool {
279 self.right_shift || self.left_shift
280 }
281 pub fn alt(&self) -> bool {
282 self.right_alt || self.left_alt
283 }
284 pub fn meta(&self) -> bool {
285 self.right_meta || self.left_meta
286 }
287 pub fn control(&self) -> bool {
288 self.right_control || self.left_control
289 }
290}
291
292impl From<InternalKeyboardModifierState> for KeyboardModifiers {
293 fn from(internal_state: InternalKeyboardModifierState) -> Self {
294 Self {
295 alt: internal_state.alt(),
296 control: internal_state.control(),
297 meta: internal_state.meta(),
298 shift: internal_state.shift(),
299 }
300 }
301}
302
303#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
305#[repr(u8)]
306pub enum KeyEventType {
307 #[default]
309 KeyPressed = 0,
310 KeyReleased = 1,
312 UpdateComposition = 2,
315 CommitComposition = 3,
317}
318
319impl KeyEvent {
320 pub fn shortcut(&self) -> Option<StandardShortcut> {
323 if self.modifiers.control && !self.modifiers.shift {
324 match self.text.as_str() {
325 #[cfg(not(target_arch = "wasm32"))]
326 "c" => Some(StandardShortcut::Copy),
327 #[cfg(not(target_arch = "wasm32"))]
328 "x" => Some(StandardShortcut::Cut),
329 #[cfg(not(target_arch = "wasm32"))]
330 "v" => Some(StandardShortcut::Paste),
331 "a" => Some(StandardShortcut::SelectAll),
332 "f" => Some(StandardShortcut::Find),
333 "s" => Some(StandardShortcut::Save),
334 "p" => Some(StandardShortcut::Print),
335 "z" => Some(StandardShortcut::Undo),
336 #[cfg(target_os = "windows")]
337 "y" => Some(StandardShortcut::Redo),
338 "r" => Some(StandardShortcut::Refresh),
339 _ => None,
340 }
341 } else if self.modifiers.control && self.modifiers.shift {
342 match self.text.as_str() {
343 #[cfg(not(target_os = "windows"))]
344 "z" => Some(StandardShortcut::Redo),
345 _ => None,
346 }
347 } else {
348 None
349 }
350 }
351
352 pub fn text_shortcut(&self) -> Option<TextShortcut> {
355 let keycode = self.text.chars().next()?;
356
357 let is_apple = crate::is_apple_platform();
358
359 let move_mod = if is_apple {
360 self.modifiers.alt && !self.modifiers.control && !self.modifiers.meta
361 } else {
362 self.modifiers.control && !self.modifiers.alt && !self.modifiers.meta
363 };
364
365 if move_mod {
366 match keycode {
367 key_codes::LeftArrow => {
368 return Some(TextShortcut::Move(TextCursorDirection::BackwardByWord))
369 }
370 key_codes::RightArrow => {
371 return Some(TextShortcut::Move(TextCursorDirection::ForwardByWord))
372 }
373 key_codes::UpArrow => {
374 return Some(TextShortcut::Move(TextCursorDirection::StartOfParagraph))
375 }
376 key_codes::DownArrow => {
377 return Some(TextShortcut::Move(TextCursorDirection::EndOfParagraph))
378 }
379 key_codes::Backspace => {
380 return Some(TextShortcut::DeleteWordBackward);
381 }
382 key_codes::Delete => {
383 return Some(TextShortcut::DeleteWordForward);
384 }
385 _ => (),
386 };
387 }
388
389 #[cfg(not(target_os = "macos"))]
390 {
391 if self.modifiers.control && !self.modifiers.alt && !self.modifiers.meta {
392 match keycode {
393 key_codes::Home => {
394 return Some(TextShortcut::Move(TextCursorDirection::StartOfText))
395 }
396 key_codes::End => {
397 return Some(TextShortcut::Move(TextCursorDirection::EndOfText))
398 }
399 _ => (),
400 };
401 }
402 }
403
404 if is_apple && self.modifiers.control {
405 match keycode {
406 key_codes::LeftArrow => {
407 return Some(TextShortcut::Move(TextCursorDirection::StartOfLine))
408 }
409 key_codes::RightArrow => {
410 return Some(TextShortcut::Move(TextCursorDirection::EndOfLine))
411 }
412 key_codes::UpArrow => {
413 return Some(TextShortcut::Move(TextCursorDirection::StartOfText))
414 }
415 key_codes::DownArrow => {
416 return Some(TextShortcut::Move(TextCursorDirection::EndOfText))
417 }
418 key_codes::Backspace => {
419 return Some(TextShortcut::DeleteToStartOfLine);
420 }
421 _ => (),
422 };
423 }
424
425 if let Ok(direction) = TextCursorDirection::try_from(keycode) {
426 Some(TextShortcut::Move(direction))
427 } else {
428 match keycode {
429 key_codes::Backspace => Some(TextShortcut::DeleteBackward),
430 key_codes::Delete => Some(TextShortcut::DeleteForward),
431 _ => None,
432 }
433 }
434 }
435}
436
437pub enum StandardShortcut {
439 Copy,
441 Cut,
443 Paste,
445 SelectAll,
447 Find,
449 Save,
451 Print,
453 Undo,
455 Redo,
457 Refresh,
459}
460
461pub enum TextShortcut {
463 Move(TextCursorDirection),
465 DeleteForward,
467 DeleteBackward,
469 DeleteWordForward,
471 DeleteWordBackward,
473 DeleteToStartOfLine,
475}
476
477#[repr(u8)]
480#[derive(Debug, Clone, Copy, PartialEq, Default)]
481pub enum KeyEventResult {
482 EventAccepted,
484 #[default]
486 EventIgnored,
487}
488
489#[repr(u8)]
492#[derive(Debug, Clone, Copy, PartialEq, Default)]
493pub enum FocusEventResult {
494 FocusAccepted,
496 #[default]
498 FocusIgnored,
499}
500
501#[derive(Debug, Clone, Copy, PartialEq)]
504#[repr(u8)]
505pub enum FocusEvent {
506 FocusIn(FocusReason),
508 FocusOut(FocusReason),
510}
511
512#[derive(Default)]
514pub struct ClickState {
515 click_count_time_stamp: Cell<Option<crate::animations::Instant>>,
516 click_count: Cell<u8>,
517 click_position: Cell<LogicalPoint>,
518 click_button: Cell<PointerEventButton>,
519}
520
521impl ClickState {
522 fn restart(&self, position: LogicalPoint, button: PointerEventButton) {
524 self.click_count.set(0);
525 self.click_count_time_stamp.set(Some(crate::animations::Instant::now()));
526 self.click_position.set(position);
527 self.click_button.set(button);
528 }
529
530 pub fn reset(&self) {
532 self.click_count.set(0);
533 self.click_count_time_stamp.replace(None);
534 }
535
536 pub fn check_repeat(&self, mouse_event: MouseEvent, click_interval: Duration) -> MouseEvent {
538 match mouse_event {
539 MouseEvent::Pressed { position, button, .. } => {
540 let instant_now = crate::animations::Instant::now();
541
542 if let Some(click_count_time_stamp) = self.click_count_time_stamp.get() {
543 if instant_now - click_count_time_stamp < click_interval
544 && button == self.click_button.get()
545 && (position - self.click_position.get()).square_length() < 100 as _
546 {
547 self.click_count.set(self.click_count.get().wrapping_add(1));
548 self.click_count_time_stamp.set(Some(instant_now));
549 } else {
550 self.restart(position, button);
551 }
552 } else {
553 self.restart(position, button);
554 }
555
556 return MouseEvent::Pressed {
557 position,
558 button,
559 click_count: self.click_count.get(),
560 };
561 }
562 MouseEvent::Released { position, button, .. } => {
563 return MouseEvent::Released {
564 position,
565 button,
566 click_count: self.click_count.get(),
567 }
568 }
569 _ => {}
570 };
571
572 mouse_event
573 }
574}
575
576#[derive(Default)]
578pub struct MouseInputState {
579 item_stack: Vec<(ItemWeak, InputEventFilterResult)>,
582 pub(crate) offset: LogicalPoint,
584 grabbed: bool,
586 pub(crate) drag_data: Option<DropEvent>,
589 delayed: Option<(crate::timers::Timer, MouseEvent)>,
590 delayed_exit_items: Vec<ItemWeak>,
591}
592
593impl MouseInputState {
594 fn top_item(&self) -> Option<ItemRc> {
596 self.item_stack.last().and_then(|x| x.0.upgrade())
597 }
598
599 pub fn top_item_including_delayed(&self) -> Option<ItemRc> {
601 self.delayed_exit_items.last().and_then(|x| x.upgrade()).or_else(|| self.top_item())
602 }
603}
604
605pub(crate) fn handle_mouse_grab(
608 mouse_event: &MouseEvent,
609 window_adapter: &Rc<dyn WindowAdapter>,
610 mouse_input_state: &mut MouseInputState,
611) -> Option<MouseEvent> {
612 if !mouse_input_state.grabbed || mouse_input_state.item_stack.is_empty() {
613 return Some(mouse_event.clone());
614 };
615
616 let mut event = mouse_event.clone();
617 let mut intercept = false;
618 let mut invalid = false;
619
620 event.translate(-mouse_input_state.offset.to_vector());
621
622 mouse_input_state.item_stack.retain(|it| {
623 if invalid {
624 return false;
625 }
626 let item = if let Some(item) = it.0.upgrade() {
627 item
628 } else {
629 invalid = true;
630 return false;
631 };
632 if intercept {
633 item.borrow().as_ref().input_event(&MouseEvent::Exit, window_adapter, &item);
634 return false;
635 }
636 let g = item.geometry();
637 event.translate(-g.origin.to_vector());
638 if window_adapter.renderer().supports_transformations() {
639 if let Some(inverse_transform) = item.inverse_children_transform() {
640 event.transform(inverse_transform);
641 }
642 }
643
644 let interested = matches!(
645 it.1,
646 InputEventFilterResult::ForwardAndInterceptGrab
647 | InputEventFilterResult::DelayForwarding(_)
648 );
649
650 if interested
651 && item.borrow().as_ref().input_event_filter_before_children(
652 &event,
653 window_adapter,
654 &item,
655 ) == InputEventFilterResult::Intercept
656 {
657 intercept = true;
658 }
659 true
660 });
661 if invalid {
662 return Some(mouse_event.clone());
663 }
664
665 let grabber = mouse_input_state.top_item().unwrap();
666 let input_result = grabber.borrow().as_ref().input_event(&event, window_adapter, &grabber);
667 match input_result {
668 InputEventResult::GrabMouse => None,
669 InputEventResult::StartDrag => {
670 mouse_input_state.grabbed = false;
671 let drag_area_item = grabber.downcast::<crate::items::DragArea>().unwrap();
672 mouse_input_state.drag_data = Some(DropEvent {
673 mime_type: drag_area_item.as_pin_ref().mime_type(),
674 data: drag_area_item.as_pin_ref().data(),
675 position: Default::default(),
676 });
677 None
678 }
679 _ => {
680 mouse_input_state.grabbed = false;
681 Some(
683 mouse_event
684 .position()
685 .map_or(MouseEvent::Exit, |position| MouseEvent::Moved { position }),
686 )
687 }
688 }
689}
690
691pub(crate) fn send_exit_events(
692 old_input_state: &MouseInputState,
693 new_input_state: &mut MouseInputState,
694 mut pos: Option<LogicalPoint>,
695 window_adapter: &Rc<dyn WindowAdapter>,
696) {
697 for it in core::mem::take(&mut new_input_state.delayed_exit_items) {
698 let Some(item) = it.upgrade() else { continue };
699 item.borrow().as_ref().input_event(&MouseEvent::Exit, window_adapter, &item);
700 }
701
702 let mut clipped = false;
703 for (idx, it) in old_input_state.item_stack.iter().enumerate() {
704 let Some(item) = it.0.upgrade() else { break };
705 let g = item.geometry();
706 let contains = pos.is_some_and(|p| g.contains(p));
707 if let Some(p) = pos.as_mut() {
708 *p -= g.origin.to_vector();
709 if window_adapter.renderer().supports_transformations() {
710 if let Some(inverse_transform) = item.inverse_children_transform() {
711 *p = inverse_transform.transform_point(p.cast()).cast();
712 }
713 }
714 }
715 if !contains || clipped {
716 if item.borrow().as_ref().clips_children() {
717 clipped = true;
718 }
719 item.borrow().as_ref().input_event(&MouseEvent::Exit, window_adapter, &item);
720 } else if new_input_state.item_stack.get(idx).is_none_or(|(x, _)| *x != it.0) {
721 if new_input_state.delayed.is_some() {
723 new_input_state.delayed_exit_items.push(it.0.clone());
724 } else {
725 item.borrow().as_ref().input_event(&MouseEvent::Exit, window_adapter, &item);
726 }
727 }
728 }
729}
730
731pub fn process_mouse_input(
735 root: ItemRc,
736 mouse_event: &MouseEvent,
737 window_adapter: &Rc<dyn WindowAdapter>,
738 mouse_input_state: MouseInputState,
739) -> MouseInputState {
740 let mut result =
741 MouseInputState { drag_data: mouse_input_state.drag_data.clone(), ..Default::default() };
742 let r = send_mouse_event_to_item(
743 mouse_event,
744 root.clone(),
745 window_adapter,
746 &mut result,
747 mouse_input_state.top_item().as_ref(),
748 false,
749 );
750 if mouse_input_state.delayed.is_some()
751 && (!r.has_aborted()
752 || Option::zip(result.item_stack.last(), mouse_input_state.item_stack.last())
753 .is_none_or(|(a, b)| a.0 != b.0))
754 {
755 return mouse_input_state;
757 }
758 send_exit_events(&mouse_input_state, &mut result, mouse_event.position(), window_adapter);
759
760 if let MouseEvent::Wheel { position, .. } = mouse_event {
761 if r.has_aborted() {
762 return process_mouse_input(
764 root,
765 &MouseEvent::Moved { position: *position },
766 window_adapter,
767 result,
768 );
769 }
770 }
771
772 result
773}
774
775pub(crate) fn process_delayed_event(
776 window_adapter: &Rc<dyn WindowAdapter>,
777 mut mouse_input_state: MouseInputState,
778) -> MouseInputState {
779 let event = match mouse_input_state.delayed.take() {
781 Some(e) => e.1,
782 None => return mouse_input_state,
783 };
784
785 let top_item = match mouse_input_state.top_item() {
786 Some(i) => i,
787 None => return MouseInputState::default(),
788 };
789
790 let mut actual_visitor =
791 |component: &ItemTreeRc, index: u32, _: Pin<ItemRef>| -> VisitChildrenResult {
792 send_mouse_event_to_item(
793 &event,
794 ItemRc::new(component.clone(), index),
795 window_adapter,
796 &mut mouse_input_state,
797 Some(&top_item),
798 true,
799 )
800 };
801 vtable::new_vref!(let mut actual_visitor : VRefMut<crate::item_tree::ItemVisitorVTable> for crate::item_tree::ItemVisitor = &mut actual_visitor);
802 vtable::VRc::borrow_pin(top_item.item_tree()).as_ref().visit_children_item(
803 top_item.index() as isize,
804 crate::item_tree::TraversalOrder::FrontToBack,
805 actual_visitor,
806 );
807 mouse_input_state
808}
809
810fn send_mouse_event_to_item(
811 mouse_event: &MouseEvent,
812 item_rc: ItemRc,
813 window_adapter: &Rc<dyn WindowAdapter>,
814 result: &mut MouseInputState,
815 last_top_item: Option<&ItemRc>,
816 ignore_delays: bool,
817) -> VisitChildrenResult {
818 let item = item_rc.borrow();
819 let geom = item_rc.geometry();
820 let mut event_for_children = mouse_event.clone();
822 event_for_children.translate(-geom.origin.to_vector());
824 if window_adapter.renderer().supports_transformations() {
825 if let Some(inverse_transform) = item_rc.inverse_children_transform() {
827 event_for_children.transform(inverse_transform);
828 }
829 }
830
831 let filter_result = if mouse_event.position().is_some_and(|p| geom.contains(p))
832 || item.as_ref().clips_children()
833 {
834 item.as_ref().input_event_filter_before_children(
835 &event_for_children,
836 window_adapter,
837 &item_rc,
838 )
839 } else {
840 InputEventFilterResult::ForwardAndIgnore
841 };
842
843 let (forward_to_children, ignore) = match filter_result {
844 InputEventFilterResult::ForwardEvent => (true, false),
845 InputEventFilterResult::ForwardAndIgnore => (true, true),
846 InputEventFilterResult::ForwardAndInterceptGrab => (true, false),
847 InputEventFilterResult::Intercept => (false, false),
848 InputEventFilterResult::DelayForwarding(_) if ignore_delays => (true, false),
849 InputEventFilterResult::DelayForwarding(duration) => {
850 let timer = Timer::default();
851 let w = Rc::downgrade(window_adapter);
852 timer.start(
853 crate::timers::TimerMode::SingleShot,
854 Duration::from_millis(duration),
855 move || {
856 if let Some(w) = w.upgrade() {
857 WindowInner::from_pub(w.window()).process_delayed_event();
858 }
859 },
860 );
861 result.delayed = Some((timer, event_for_children));
862 result
863 .item_stack
864 .push((item_rc.downgrade(), InputEventFilterResult::DelayForwarding(duration)));
865 return VisitChildrenResult::abort(item_rc.index(), 0);
866 }
867 };
868
869 result.item_stack.push((item_rc.downgrade(), filter_result));
870 if forward_to_children {
871 let mut actual_visitor =
872 |component: &ItemTreeRc, index: u32, _: Pin<ItemRef>| -> VisitChildrenResult {
873 send_mouse_event_to_item(
874 &event_for_children,
875 ItemRc::new(component.clone(), index),
876 window_adapter,
877 result,
878 last_top_item,
879 ignore_delays,
880 )
881 };
882 vtable::new_vref!(let mut actual_visitor : VRefMut<crate::item_tree::ItemVisitorVTable> for crate::item_tree::ItemVisitor = &mut actual_visitor);
883 let r = vtable::VRc::borrow_pin(item_rc.item_tree()).as_ref().visit_children_item(
884 item_rc.index() as isize,
885 crate::item_tree::TraversalOrder::FrontToBack,
886 actual_visitor,
887 );
888 if r.has_aborted() {
889 return r;
890 }
891 };
892
893 let r = if ignore {
894 InputEventResult::EventIgnored
895 } else {
896 let mut event = mouse_event.clone();
897 event.translate(-geom.origin.to_vector());
898 if last_top_item.is_none_or(|x| *x != item_rc) {
899 event.set_click_count(0);
900 }
901 item.as_ref().input_event(&event, window_adapter, &item_rc)
902 };
903 match r {
904 InputEventResult::EventAccepted => VisitChildrenResult::abort(item_rc.index(), 0),
905 InputEventResult::EventIgnored => {
906 let _pop = result.item_stack.pop();
907 debug_assert_eq!(
908 _pop.map(|x| (x.0.upgrade().unwrap().index(), x.1)).unwrap(),
909 (item_rc.index(), filter_result)
910 );
911 VisitChildrenResult::CONTINUE
912 }
913 InputEventResult::GrabMouse => {
914 result.item_stack.last_mut().unwrap().1 =
915 InputEventFilterResult::ForwardAndInterceptGrab;
916 result.grabbed = true;
917 VisitChildrenResult::abort(item_rc.index(), 0)
918 }
919 InputEventResult::StartDrag => {
920 result.item_stack.last_mut().unwrap().1 =
921 InputEventFilterResult::ForwardAndInterceptGrab;
922 result.grabbed = false;
923 let drag_area_item = item_rc.downcast::<crate::items::DragArea>().unwrap();
924 result.drag_data = Some(DropEvent {
925 mime_type: drag_area_item.as_pin_ref().mime_type(),
926 data: drag_area_item.as_pin_ref().data(),
927 position: Default::default(),
928 });
929 VisitChildrenResult::abort(item_rc.index(), 0)
930 }
931 }
932}
933
934#[derive(FieldOffsets)]
941#[repr(C)]
942#[pin]
943pub(crate) struct TextCursorBlinker {
944 cursor_visible: Property<bool>,
945 cursor_blink_timer: crate::timers::Timer,
946}
947
948impl TextCursorBlinker {
949 pub fn new() -> Pin<Rc<Self>> {
952 Rc::pin(Self {
953 cursor_visible: Property::new(true),
954 cursor_blink_timer: Default::default(),
955 })
956 }
957
958 pub fn set_binding(
961 instance: Pin<Rc<TextCursorBlinker>>,
962 prop: &Property<bool>,
963 cycle_duration: Duration,
964 ) {
965 instance.as_ref().cursor_visible.set(true);
966 Self::start(&instance, cycle_duration);
968 prop.set_binding(move || {
969 TextCursorBlinker::FIELD_OFFSETS.cursor_visible.apply_pin(instance.as_ref()).get()
970 });
971 }
972
973 pub fn start(self: &Pin<Rc<Self>>, cycle_duration: Duration) {
976 if self.cursor_blink_timer.running() {
977 self.cursor_blink_timer.restart();
978 } else {
979 let toggle_cursor = {
980 let weak_blinker = pin_weak::rc::PinWeak::downgrade(self.clone());
981 move || {
982 if let Some(blinker) = weak_blinker.upgrade() {
983 let visible = TextCursorBlinker::FIELD_OFFSETS
984 .cursor_visible
985 .apply_pin(blinker.as_ref())
986 .get();
987 blinker.cursor_visible.set(!visible);
988 }
989 }
990 };
991 if !cycle_duration.is_zero() {
992 self.cursor_blink_timer.start(
993 crate::timers::TimerMode::Repeated,
994 cycle_duration / 2,
995 toggle_cursor,
996 );
997 }
998 }
999 }
1000
1001 pub fn stop(&self) {
1004 self.cursor_blink_timer.stop()
1005 }
1006}