1use std::{collections::HashMap, mem, num::NonZeroU32, time::*};
19
20use zng_app::{
21 DInstant, INSTANT,
22 event::{EventPropagationHandle, event, event_args},
23 hn,
24 shortcut::ModifiersState,
25 timer::{DeadlineVar, TIMERS},
26 view_process::{
27 VIEW_PROCESS_INITED_EVENT,
28 raw_device_events::InputDeviceId,
29 raw_events::{
30 RAW_MOUSE_INPUT_EVENT, RAW_MOUSE_LEFT_EVENT, RAW_MOUSE_MOVED_EVENT, RAW_MOUSE_WHEEL_EVENT,
31 RAW_MULTI_CLICK_CONFIG_CHANGED_EVENT, RAW_WINDOW_FOCUS_EVENT,
32 },
33 },
34 widget::{
35 WidgetId,
36 info::{HitTestInfo, InteractionPath, WIDGET_TREE_CHANGED_EVENT, WidgetInfo, WidgetInfoBuilder},
37 },
38 window::WindowId,
39};
40use zng_app_context::app_local;
41use zng_ext_window::{NestedWindowWidgetInfoExt, WINDOWS};
42use zng_layout::unit::{Dip, DipPoint, DipToPx, Factor, PxPoint, PxToDip};
43use zng_state_map::{StateId, state_map, static_id};
44use zng_var::{IntoVar, Var, context_var, impl_from_and_into_var, var};
45use zng_view_api::touch::TouchPhase;
46pub use zng_view_api::{
47 config::MultiClickConfig,
48 mouse::{ButtonState, MouseButton, MouseScrollDelta},
49};
50
51use crate::{
52 keyboard::{KEYBOARD, MODIFIERS_CHANGED_EVENT},
53 pointer_capture::{CaptureInfo, CaptureMode, POINTER_CAPTURE, POINTER_CAPTURE_EVENT},
54};
55
56event_args! {
57 pub struct MouseMoveArgs {
59 pub window_id: WindowId,
61
62 pub device_id: InputDeviceId,
64
65 pub modifiers: ModifiersState,
67
68 pub coalesced_pos: Vec<DipPoint>,
72
73 pub position: DipPoint,
75
76 pub hits: HitTestInfo,
78
79 pub target: InteractionPath,
81
82 pub capture: Option<CaptureInfo>,
84
85 ..
86
87 fn is_in_target(&self, id: WidgetId) -> bool {
92 if self.target.contains(id) {
93 return true;
94 }
95
96 if let Some(c) = &self.capture {
97 return c.target.contains(id);
98 }
99
100 false
101 }
102 }
103
104 pub struct MouseInputArgs {
106 pub window_id: WindowId,
108
109 pub device_id: Option<InputDeviceId>,
111
112 pub button: MouseButton,
114
115 pub position: DipPoint,
117
118 pub modifiers: ModifiersState,
120
121 pub state: ButtonState,
125
126 pub hits: HitTestInfo,
128
129 pub target: InteractionPath,
133
134 pub capture: Option<CaptureInfo>,
136
137 pub is_click: bool,
141
142 ..
143
144 fn is_in_target(&self, id: WidgetId) -> bool {
149 if self.target.contains(id) {
150 return true;
151 }
152
153 if let Some(c) = &self.capture {
154 return c.target.contains(id);
155 }
156
157 false
158 }
159 }
160
161 pub struct MouseClickArgs {
163 pub window_id: WindowId,
165
166 pub device_id: InputDeviceId,
168
169 pub button: MouseButton,
171
172 pub position: DipPoint,
174
175 pub modifiers: ModifiersState,
177
178 pub click_count: NonZeroU32,
182
183 pub is_repeat: bool,
185
186 pub hits: HitTestInfo,
189
190 pub target: InteractionPath,
206
207 ..
208
209 fn is_in_target(&self, id: WidgetId) -> bool {
213 self.target.contains(id)
214 }
215 }
216
217 pub struct MouseHoverArgs {
219 pub window_id: WindowId,
221
222 pub device_id: Option<InputDeviceId>,
224
225 pub position: DipPoint,
227
228 pub hits: HitTestInfo,
230
231 pub prev_target: Option<InteractionPath>,
233
234 pub target: Option<InteractionPath>,
241
242 pub prev_capture: Option<CaptureInfo>,
244
245 pub capture: Option<CaptureInfo>,
247
248 ..
249
250 fn is_in_target(&self, id: WidgetId) -> bool {
256 if let Some(t) = &self.target
257 && t.contains(id)
258 {
259 return true;
260 }
261 if let Some(t) = &self.prev_target
262 && t.contains(id)
263 {
264 return true;
265 }
266
267 if let Some(c) = &self.capture {
268 return c.target.contains(id);
269 }
270
271 false
272 }
273 }
274
275 pub struct MouseWheelArgs {
277 pub window_id: WindowId,
279 pub device_id: InputDeviceId,
281
282 pub position: DipPoint,
284 pub modifiers: ModifiersState,
286
287 pub delta: MouseScrollDelta,
289
290 pub phase: TouchPhase,
292
293 pub hits: HitTestInfo,
296
297 pub target: InteractionPath,
299
300 ..
301
302 fn is_in_target(&self, id: WidgetId) -> bool {
306 self.target.contains(id)
307 }
308 }
309}
310
311impl MouseHoverArgs {
312 pub fn capture_allows(&self, wgt: (WindowId, WidgetId)) -> bool {
317 self.capture.as_ref().map(|c| c.allows(wgt)).unwrap_or(true)
318 }
319
320 pub fn is_mouse_move(&self) -> bool {
322 self.device_id.is_some()
323 }
324
325 pub fn is_widget_move(&self) -> bool {
327 self.device_id.is_none()
328 }
329
330 pub fn is_capture_change(&self) -> bool {
332 self.prev_capture != self.capture
333 }
334
335 pub fn is_mouse_enter(&self, wgt: (WindowId, WidgetId)) -> bool {
337 !self.was_over(wgt) && self.is_over(wgt)
338 }
339
340 pub fn is_mouse_leave(&self, wgt: (WindowId, WidgetId)) -> bool {
342 self.was_over(wgt) && !self.is_over(wgt)
343 }
344
345 pub fn is_mouse_enter_enabled(&self, wgt: (WindowId, WidgetId)) -> bool {
347 (!self.was_over(wgt) || self.was_disabled(wgt.1)) && self.is_over(wgt) && self.is_enabled(wgt.1)
348 }
349
350 pub fn is_mouse_leave_enabled(&self, wgt: (WindowId, WidgetId)) -> bool {
352 self.was_over(wgt) && self.was_enabled(wgt.1) && (!self.is_over(wgt) || self.is_disabled(wgt.1))
353 }
354
355 pub fn is_mouse_enter_disabled(&self, wgt: (WindowId, WidgetId)) -> bool {
357 (!self.was_over(wgt) || self.was_enabled(wgt.1)) && self.is_over(wgt) && self.is_disabled(wgt.1)
358 }
359
360 pub fn is_mouse_leave_disabled(&self, wgt: (WindowId, WidgetId)) -> bool {
362 self.was_over(wgt) && self.was_disabled(wgt.1) && (!self.is_over(wgt) || self.is_enabled(wgt.1))
363 }
364
365 pub fn was_over(&self, wgt: (WindowId, WidgetId)) -> bool {
370 if let Some(cap) = &self.prev_capture
371 && !cap.allows(wgt)
372 {
373 return false;
374 }
375
376 if let Some(t) = &self.prev_target {
377 return t.contains(wgt.1);
378 }
379
380 false
381 }
382
383 pub fn is_over(&self, wgt: (WindowId, WidgetId)) -> bool {
388 if let Some(cap) = &self.capture
389 && !cap.allows(wgt)
390 {
391 return false;
392 }
393
394 if let Some(t) = &self.target {
395 return t.contains(wgt.1);
396 }
397
398 false
399 }
400
401 pub fn was_enabled(&self, widget_id: WidgetId) -> bool {
405 match &self.prev_target {
406 Some(t) => t.contains_enabled(widget_id),
407 None => false,
408 }
409 }
410
411 pub fn was_disabled(&self, widget_id: WidgetId) -> bool {
415 match &self.prev_target {
416 Some(t) => t.contains_disabled(widget_id),
417 None => false,
418 }
419 }
420
421 pub fn is_enabled(&self, widget_id: WidgetId) -> bool {
425 match &self.target {
426 Some(t) => t.contains_enabled(widget_id),
427 None => false,
428 }
429 }
430
431 pub fn is_disabled(&self, widget_id: WidgetId) -> bool {
435 match &self.target {
436 Some(t) => t.contains_disabled(widget_id),
437 None => false,
438 }
439 }
440
441 pub fn position_wgt(&self, wgt: (WindowId, WidgetId)) -> Option<PxPoint> {
443 let tree = WINDOWS.widget_tree(wgt.0)?;
444 tree.get(wgt.1)?
445 .inner_transform()
446 .inverse()?
447 .transform_point(self.position.to_px(tree.scale_factor()))
448 }
449}
450
451impl MouseMoveArgs {
452 pub fn capture_allows(&self, wgt: (WindowId, WidgetId)) -> bool {
457 self.capture.as_ref().map(|c| c.allows(wgt)).unwrap_or(true)
458 }
459
460 pub fn position_wgt(&self, wgt: (WindowId, WidgetId)) -> Option<PxPoint> {
462 let tree = WINDOWS.widget_tree(wgt.0)?;
463 tree.get(wgt.1)?
464 .inner_transform()
465 .inverse()?
466 .transform_point(self.position.to_px(tree.scale_factor()))
467 }
468}
469
470impl MouseInputArgs {
471 pub fn capture_allows(&self, wgt: (WindowId, WidgetId)) -> bool {
476 self.capture.as_ref().map(|c| c.allows(wgt)).unwrap_or(true)
477 }
478
479 pub fn is_over(&self, widget_id: WidgetId) -> bool {
483 self.target.contains(widget_id)
484 }
485
486 pub fn is_primary(&self) -> bool {
490 self.button == MouseButton::Left
491 }
492
493 pub fn is_context(&self) -> bool {
495 self.button == MouseButton::Right
496 }
497
498 pub fn is_mouse_down(&self) -> bool {
502 self.state == ButtonState::Pressed
503 }
504
505 pub fn is_mouse_up(&self) -> bool {
509 self.state == ButtonState::Released
510 }
511
512 pub fn position_wgt(&self, wgt: (WindowId, WidgetId)) -> Option<PxPoint> {
514 let tree = WINDOWS.widget_tree(wgt.0)?;
515 tree.get(wgt.1)?
516 .inner_transform()
517 .inverse()?
518 .transform_point(self.position.to_px(tree.scale_factor()))
519 }
520}
521
522impl MouseClickArgs {
523 pub fn is_primary(&self) -> bool {
525 self.button == MouseButton::Left
526 }
527
528 pub fn is_context(&self) -> bool {
530 self.button == MouseButton::Right
531 }
532
533 pub fn is_single(&self) -> bool {
535 self.click_count.get() == 1
536 }
537
538 pub fn is_double(&self) -> bool {
540 self.click_count.get() == 2
541 }
542
543 pub fn is_triple(&self) -> bool {
545 self.click_count.get() == 3
546 }
547
548 pub fn position_wgt(&self, wgt: (WindowId, WidgetId)) -> Option<PxPoint> {
550 let tree = WINDOWS.widget_tree(wgt.0)?;
551 tree.get(wgt.1)?
552 .inner_transform()
553 .inverse()?
554 .transform_point(self.position.to_px(tree.scale_factor()))
555 }
556}
557
558impl MouseWheelArgs {
559 pub fn shifted_delta(&self) -> MouseScrollDelta {
563 if self.modifiers.has_shift() {
564 match self.delta {
565 MouseScrollDelta::LineDelta(x, y) => MouseScrollDelta::LineDelta(y, x),
566 MouseScrollDelta::PixelDelta(x, y) => MouseScrollDelta::PixelDelta(y, x),
567 _ => unimplemented!(),
568 }
569 } else {
570 self.delta
571 }
572 }
573
574 pub fn is_scroll(&self) -> bool {
583 if CTRL_SCROLL_VAR.get() {
584 self.modifiers
585 .is_only(ModifiersState::CTRL | ModifiersState::SHIFT | ModifiersState::ALT)
586 } else {
587 self.modifiers.is_empty() || self.modifiers.is_only(ModifiersState::SHIFT | ModifiersState::ALT)
588 }
589 }
590
591 pub fn scroll_delta(&self, alt_factor: impl Into<Factor>) -> Option<MouseScrollDelta> {
599 let mut modifiers = self.modifiers;
600 if CTRL_SCROLL_VAR.get() && !modifiers.take_ctrl() {
601 return None;
602 }
603 let mut delta = self.delta;
604 if modifiers.take_alt() {
605 let alt_factor = alt_factor.into();
606 delta = match delta {
607 MouseScrollDelta::LineDelta(x, y) => MouseScrollDelta::LineDelta(x * alt_factor.0, y * alt_factor.0),
608 MouseScrollDelta::PixelDelta(x, y) => MouseScrollDelta::PixelDelta(x * alt_factor.0, y * alt_factor.0),
609 _ => return None,
610 };
611 }
612
613 if modifiers.is_empty() {
614 Some(delta)
615 } else if modifiers.is_only_shift() {
616 Some(match delta {
617 MouseScrollDelta::LineDelta(x, y) => MouseScrollDelta::LineDelta(y, x),
618 MouseScrollDelta::PixelDelta(x, y) => MouseScrollDelta::PixelDelta(y, x),
619 _ => return None,
620 })
621 } else {
622 None
623 }
624 }
625
626 pub fn is_zoom(&self) -> bool {
634 if CTRL_SCROLL_VAR.get() {
635 self.modifiers.is_empty()
636 } else {
637 self.modifiers.is_only_ctrl()
638 }
639 }
640
641 pub fn zoom_delta(&self) -> Option<MouseScrollDelta> {
648 if self.is_zoom() { Some(self.delta) } else { None }
649 }
650
651 pub fn position_wgt(&self, wgt: (WindowId, WidgetId)) -> Option<PxPoint> {
653 let tree = WINDOWS.widget_tree(wgt.0)?;
654 tree.get(wgt.1)?
655 .inner_transform()
656 .inverse()?
657 .transform_point(self.position.to_px(tree.scale_factor()))
658 }
659}
660
661context_var! {
662 pub static CTRL_SCROLL_VAR: bool = false;
669}
670
671event! {
672 pub static MOUSE_MOVE_EVENT: MouseMoveArgs {
674 let _ = MOUSE_SV.read();
675 };
676
677 pub static MOUSE_INPUT_EVENT: MouseInputArgs {
679 let _ = MOUSE_SV.read();
680 };
681
682 pub static MOUSE_CLICK_EVENT: MouseClickArgs {
684 let _ = MOUSE_SV.read();
685 };
686
687 pub static MOUSE_HOVERED_EVENT: MouseHoverArgs {
689 let _ = MOUSE_SV.read();
690 };
691
692 pub static MOUSE_WHEEL_EVENT: MouseWheelArgs {
694 let _ = MOUSE_SV.read();
695 };
696}
697
698#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
700pub enum ClickTrigger {
701 PressRelease,
703 Press,
705 Release,
707}
708
709#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
711pub struct ClickMode {
712 pub single: ClickTrigger,
714
715 pub double: ClickTrigger,
717
718 pub repeat: bool,
720}
721impl Default for ClickMode {
722 fn default() -> Self {
724 Self {
725 single: ClickTrigger::PressRelease,
726 double: ClickTrigger::Press,
727 repeat: false,
728 }
729 }
730}
731impl IntoVar<Option<ClickMode>> for ClickTrigger {
732 fn into_var(self) -> Var<Option<ClickMode>> {
733 Some(ClickMode::from(self)).into_var()
734 }
735}
736impl_from_and_into_var! {
737 fn from(gesture: ClickTrigger) -> ClickMode {
738 ClickMode {
739 single: gesture,
740 double: gesture,
741 repeat: false,
742 }
743 }
744
745 fn from(some: ClickMode) -> Option<ClickMode>;
746}
747impl ClickMode {
748 pub fn press() -> Self {
750 Self {
751 single: ClickTrigger::Press,
752 double: ClickTrigger::Press,
753 repeat: false,
754 }
755 }
756
757 pub fn release() -> Self {
759 Self {
760 single: ClickTrigger::Release,
761 double: ClickTrigger::Release,
762 repeat: false,
763 }
764 }
765
766 pub fn repeat() -> Self {
768 Self {
769 single: ClickTrigger::Press,
770 double: ClickTrigger::Press,
771 repeat: true,
772 }
773 }
774
775 pub fn mixed_repeat() -> Self {
777 Self {
778 single: ClickTrigger::PressRelease,
779 double: ClickTrigger::Press,
780 repeat: true,
781 }
782 }
783}
784
785pub trait WidgetInfoMouseExt {
787 fn click_mode(&self) -> ClickMode;
789}
790impl WidgetInfoMouseExt for WidgetInfo {
791 fn click_mode(&self) -> ClickMode {
792 for w in self.self_and_ancestors() {
793 if let Some(m) = w.meta().get_clone(*CLICK_MODE_ID).flatten() {
794 return m;
795 }
796 }
797 ClickMode::default()
798 }
799}
800
801pub trait WidgetInfoBuilderMouseExt {
803 fn set_click_mode(&mut self, mode: Option<ClickMode>);
807}
808impl WidgetInfoBuilderMouseExt for WidgetInfoBuilder {
809 fn set_click_mode(&mut self, mode: Option<ClickMode>) {
810 self.with_meta(|mut m| match m.entry(*CLICK_MODE_ID) {
811 state_map::StateMapEntry::Occupied(mut e) => *e.get_mut() = mode,
812 state_map::StateMapEntry::Vacant(e) => {
813 if mode.is_some() {
814 e.insert(mode);
815 }
816 }
817 })
818 }
819}
820
821static_id! {
822 static ref CLICK_MODE_ID: StateId<Option<ClickMode>>;
823}
824
825#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
827pub struct ButtonRepeatConfig {
828 pub start_delay: Duration,
830 pub interval: Duration,
832}
833impl Default for ButtonRepeatConfig {
834 fn default() -> Self {
836 Self {
837 start_delay: Duration::from_millis(600),
838 interval: Duration::from_millis(100),
839 }
840 }
841}
842
843pub struct MOUSE;
851impl MOUSE {
852 pub fn buttons(&self) -> Var<Vec<MouseButton>> {
856 MOUSE_SV.read().buttons.read_only()
857 }
858
859 pub fn multi_click_config(&self) -> Var<MultiClickConfig> {
867 MOUSE_SV.read().multi_click_config.clone()
868 }
869
870 pub fn sys_multi_click_config(&self) -> Var<MultiClickConfig> {
879 MOUSE_SV.read().sys_multi_click_config.read_only()
880 }
881
882 pub fn repeat_config(&self) -> Var<ButtonRepeatConfig> {
889 MOUSE_SV.read().repeat_config.clone()
890 }
891
892 pub fn position(&self) -> Var<Option<MousePosition>> {
894 MOUSE_SV.read().position.read_only()
895 }
896
897 pub fn hovered(&self) -> Var<Option<InteractionPath>> {
899 MOUSE_SV.read().hovered.read_only()
900 }
901}
902
903#[derive(Debug, Clone, Copy, PartialEq, Eq)]
909pub struct MousePosition {
910 pub window_id: WindowId,
912 pub position: DipPoint,
914 pub timestamp: DInstant,
916}
917
918app_local! {
919 static MOUSE_SV: MouseService = {
920 hooks();
921 let sys_multi_click_config = var(MultiClickConfig::default());
922 MouseService {
923 multi_click_config: sys_multi_click_config.cow(),
924 sys_multi_click_config,
925 repeat_config: KEYBOARD
926 .repeat_config()
927 .map(|c| ButtonRepeatConfig {
928 start_delay: c.start_delay,
929 interval: c.interval,
930 })
931 .cow(),
932 buttons: var(vec![]),
933 hovered: var(None),
934 position: var(None),
935
936 pos: DipPoint::zero(),
937 pos_window: None,
938 pos_device: None,
939 hits: None,
940
941 modifiers: ModifiersState::default(),
942
943 hovered_value: None,
944 clicking: HashMap::default(),
945 }
946 };
947}
948struct MouseService {
949 multi_click_config: Var<MultiClickConfig>,
950 sys_multi_click_config: Var<MultiClickConfig>,
951 repeat_config: Var<ButtonRepeatConfig>,
952 buttons: Var<Vec<MouseButton>>,
953 hovered: Var<Option<InteractionPath>>,
954 position: Var<Option<MousePosition>>,
955
956 pos: DipPoint,
958 pos_window: Option<WindowId>,
960 pos_device: Option<InputDeviceId>,
961 hits: Option<HitTestInfo>,
963
964 modifiers: ModifiersState,
966
967 hovered_value: Option<InteractionPath>,
968 clicking: HashMap<MouseButton, ClickingInfo>,
969}
970
971struct ClickingInfo {
972 path: InteractionPath,
973 press_stop_handle: EventPropagationHandle,
974
975 pressed: bool,
976 last_pos: DipPoint,
977 last_click: DInstant,
978 click_count: u32,
979
980 repeat_timer: Option<DeadlineVar>,
981 repeat_count: u32,
982}
983
984fn hooks() {
985 WIDGET_TREE_CHANGED_EVENT
986 .hook(|args| {
987 MOUSE_SV.write().continue_hovered(args.tree.window_id());
988 true
989 })
990 .perm();
991
992 RAW_MOUSE_MOVED_EVENT
993 .hook(|args| {
994 MOUSE_SV
995 .write()
996 .on_cursor_moved(args.window_id, args.device_id, args.coalesced_pos.clone(), args.position);
997 true
998 })
999 .perm();
1000
1001 RAW_MOUSE_WHEEL_EVENT
1002 .hook(|args| {
1003 MOUSE_SV.read().on_scroll(args.window_id, args.device_id, args.delta, args.phase);
1004 true
1005 })
1006 .perm();
1007
1008 RAW_MOUSE_INPUT_EVENT
1009 .hook(|args| {
1010 MOUSE_SV
1011 .write()
1012 .on_mouse_input(args.window_id, args.device_id, args.state, args.button);
1013 true
1014 })
1015 .perm();
1016
1017 MODIFIERS_CHANGED_EVENT
1018 .hook(|args| {
1019 MOUSE_SV.write().modifiers = args.modifiers;
1020 true
1021 })
1022 .perm();
1023
1024 RAW_MOUSE_LEFT_EVENT
1025 .hook(|args| {
1026 MOUSE_SV.write().on_cursor_left_window(args.window_id, args.device_id);
1027 true
1028 })
1029 .perm();
1030
1031 RAW_WINDOW_FOCUS_EVENT
1032 .hook(|args| {
1033 if let Some(window_id) = args.prev_focus {
1034 MOUSE_SV.write().on_window_blur(window_id, args.new_focus);
1035 }
1036 true
1037 })
1038 .perm();
1039
1040 RAW_MULTI_CLICK_CONFIG_CHANGED_EVENT
1041 .hook(|args| {
1042 let mut s = MOUSE_SV.write();
1043 s.multi_click_config.set(args.config);
1044 s.clicking.clear();
1045 true
1046 })
1047 .perm();
1048
1049 VIEW_PROCESS_INITED_EVENT
1050 .hook(|args| {
1051 if args.is_respawn {
1052 MOUSE_SV.write().clean_all_state();
1053 }
1054 true
1055 })
1056 .perm();
1057
1058 POINTER_CAPTURE_EVENT
1059 .on_event(
1060 true,
1061 hn!(|a| {
1062 MOUSE_SV.write().on_pointer_capture(&a.prev_capture, &a.new_capture);
1063 }),
1064 )
1065 .perm();
1066}
1067impl MouseService {
1068 fn on_mouse_input(&mut self, mut window_id: WindowId, device_id: InputDeviceId, state: ButtonState, button: MouseButton) {
1069 let mut position = if self.pos_window == Some(window_id) {
1070 self.pos
1071 } else {
1072 DipPoint::default()
1073 };
1074
1075 let hits = self.hits.clone().unwrap_or_else(|| HitTestInfo::no_hits(window_id));
1076
1077 let wgt_tree = match WINDOWS.widget_tree(hits.window_id()) {
1078 Some(t) => t,
1079 None => {
1080 tracing::error!("cannot find clicked window, {}", hits.window_id());
1081 return;
1082 }
1083 };
1084
1085 if hits.window_id() != window_id {
1086 window_id = hits.window_id();
1088 position = hits.point().to_dip(wgt_tree.scale_factor());
1089 }
1090
1091 let (wgt_path, click_mode) = hits
1092 .target()
1093 .and_then(|t| wgt_tree.get(t.widget_id).map(|w| (w.interaction_path(), w.click_mode())))
1094 .unwrap_or_else(|| (wgt_tree.root().interaction_path(), wgt_tree.root().click_mode()));
1095
1096 let wgt_path = match wgt_path.unblocked() {
1097 Some(p) => p,
1098 None => return, };
1100
1101 match state {
1102 ButtonState::Pressed => {
1103 self.buttons.modify(move |btns| {
1104 if !btns.contains(&button) {
1105 btns.push(button);
1106 }
1107 });
1108 }
1109 ButtonState::Released => {
1110 self.buttons.modify(move |btns| {
1111 if let Some(i) = btns.iter().position(|k| *k == button) {
1112 btns.swap_remove(i);
1113 }
1114 });
1115 }
1116 }
1117
1118 let stop_handle = EventPropagationHandle::new();
1119
1120 let entry = self.clicking.entry(button).or_insert_with(|| ClickingInfo {
1121 path: wgt_path.clone(),
1122 press_stop_handle: stop_handle.clone(),
1123 last_click: DInstant::EPOCH,
1124 last_pos: position,
1125 pressed: false,
1126 click_count: 0,
1127 repeat_timer: None,
1128 repeat_count: 0,
1129 });
1130
1131 if entry.path != wgt_path {
1132 let actual_change = entry.path.as_path() != wgt_path.as_path();
1133 entry.path = wgt_path.clone();
1136 if actual_change {
1137 entry.press_stop_handle = stop_handle.clone();
1138 entry.pressed = false;
1139 entry.click_count = 0;
1140 entry.repeat_timer = None;
1141 entry.repeat_count = 0;
1142 }
1143 }
1144
1145 let multi_click_cfg = self.multi_click_config.get();
1146
1147 let double_allowed = entry.last_click.elapsed() <= multi_click_cfg.time && {
1148 let dist = (entry.last_pos.to_vector() - position.to_vector()).abs();
1149 let area = multi_click_cfg.area;
1150 dist.x <= area.width && dist.y <= area.height
1151 };
1152
1153 let click_trigger = if entry.click_count == 0 || !double_allowed {
1154 entry.click_count = 0;
1155 click_mode.single
1156 } else {
1157 click_mode.double
1158 };
1159
1160 let click = match state {
1161 ButtonState::Pressed => {
1162 entry.pressed = true;
1163 entry.press_stop_handle = stop_handle.clone();
1164 matches!(click_trigger, ClickTrigger::Press)
1165 }
1166 ButtonState::Released => {
1167 entry.repeat_count = 0;
1168 entry.repeat_timer = None;
1169 if mem::take(&mut entry.pressed) && !entry.press_stop_handle.is_stopped() {
1170 matches!(click_trigger, ClickTrigger::PressRelease | ClickTrigger::Release)
1171 } else {
1172 matches!(click_trigger, ClickTrigger::Release)
1173 }
1174 }
1175 };
1176
1177 if click_mode.repeat {
1178 if click {
1179 let t = self.repeat_config.get().start_delay;
1180 let t = TIMERS.deadline(t);
1181 t.hook(|t| {
1182 let elapsed = t.value().has_elapsed();
1183 if elapsed {
1184 MOUSE_SV.write().on_repeat_timer_elapsed();
1185 }
1186 !elapsed
1187 })
1188 .perm();
1189 entry.repeat_timer = Some(t);
1190 entry.repeat_count = 0;
1191 }
1192 } else {
1193 entry.repeat_timer = None;
1194 entry.repeat_count = 0;
1195 }
1196
1197 let capture_info = POINTER_CAPTURE.current_capture().get();
1198
1199 let now = INSTANT.now();
1200 let args = MouseInputArgs::new(
1201 now,
1202 stop_handle.clone(),
1203 window_id,
1204 device_id,
1205 button,
1206 position,
1207 self.modifiers,
1208 state,
1209 hits.clone(),
1210 wgt_path.clone(),
1211 capture_info,
1212 click,
1213 );
1214
1215 MOUSE_INPUT_EVENT.notify(args);
1217
1218 if click {
1219 if double_allowed {
1220 entry.click_count += 1;
1221 } else {
1222 entry.click_count = 1;
1223 }
1224
1225 entry.last_click = now;
1226 entry.last_pos = position;
1227
1228 let args = MouseClickArgs::new(
1229 now,
1230 stop_handle,
1231 window_id,
1232 device_id,
1233 button,
1234 position,
1235 self.modifiers,
1236 NonZeroU32::new(entry.click_count).unwrap(),
1237 false,
1238 hits,
1239 wgt_path,
1240 );
1241
1242 MOUSE_CLICK_EVENT.notify(args);
1244 }
1245 }
1246
1247 fn on_cursor_moved(&mut self, window_id: WindowId, device_id: InputDeviceId, coalesced_pos: Vec<DipPoint>, mut position: DipPoint) {
1248 let mut moved = Some(window_id) != self.pos_window || Some(device_id) != self.pos_device;
1249
1250 if moved {
1251 self.pos_window = Some(window_id);
1253 self.pos_device = Some(device_id);
1254 }
1255
1256 moved |= position != self.pos;
1257
1258 if moved {
1259 self.pos = position;
1262
1263 let mut frame_info = match WINDOWS.widget_tree(window_id) {
1265 Some(f) => f,
1266 None => {
1267 if let Some(hovered) = self.hovered_value.take() {
1269 let capture = POINTER_CAPTURE.current_capture().get();
1270 let args = MouseHoverArgs::now(
1271 window_id,
1272 device_id,
1273 position,
1274 HitTestInfo::no_hits(window_id),
1275 Some(hovered),
1276 None,
1277 capture.clone(),
1278 capture,
1279 );
1280 MOUSE_HOVERED_EVENT.notify(args);
1281 }
1282 return;
1283 }
1284 };
1285
1286 let mut pos_hits = frame_info.root().hit_test(position.to_px(frame_info.scale_factor()));
1287
1288 let target = if let Some(t) = pos_hits.target() {
1289 if let Some(w) = frame_info.get(t.widget_id) {
1290 if let Some(f) = w.nested_window_tree() {
1291 frame_info = f;
1293 let factor = frame_info.scale_factor();
1294 let pos = position.to_px(factor);
1295 let pos = w.inner_transform().inverse().and_then(|t| t.transform_point(pos)).unwrap_or(pos);
1296 pos_hits = frame_info.root().hit_test(pos);
1297 position = pos.to_dip(factor);
1298 pos_hits
1299 .target()
1300 .and_then(|h| frame_info.get(h.widget_id))
1301 .map(|w| w.interaction_path())
1302 .unwrap_or_else(|| frame_info.root().interaction_path())
1303 } else {
1304 w.interaction_path()
1305 }
1306 } else {
1307 tracing::error!("hits target `{}` not found", t.widget_id);
1308 frame_info.root().interaction_path()
1309 }
1310 } else {
1311 frame_info.root().interaction_path()
1312 }
1313 .unblocked();
1314
1315 self.position.set(Some(MousePosition {
1316 window_id: frame_info.window_id(),
1317 position,
1318 timestamp: INSTANT.now(),
1319 }));
1320
1321 self.hits = Some(pos_hits.clone());
1322
1323 let capture = POINTER_CAPTURE.current_capture().get();
1324
1325 let hovered_args = if self.hovered_value != target {
1327 self.hovered.set(target.clone());
1328 let prev_target = mem::replace(&mut self.hovered_value, target.clone());
1329 let args = MouseHoverArgs::now(
1330 frame_info.window_id(),
1331 device_id,
1332 position,
1333 pos_hits.clone(),
1334 prev_target,
1335 target.clone(),
1336 capture.clone(),
1337 capture.clone(),
1338 );
1339 Some(args)
1340 } else {
1341 None
1342 };
1343
1344 if let Some(target) = target {
1346 let args = MouseMoveArgs::now(
1347 frame_info.window_id(),
1348 device_id,
1349 self.modifiers,
1350 coalesced_pos,
1351 position,
1352 pos_hits,
1353 target,
1354 capture,
1355 );
1356 MOUSE_MOVE_EVENT.notify(args);
1357 }
1358
1359 if let Some(args) = hovered_args {
1360 MOUSE_HOVERED_EVENT.notify(args);
1361 }
1362 } else if coalesced_pos.is_empty() {
1363 tracing::debug!("RawCursorMoved did not actually move")
1364 }
1365 }
1366
1367 fn on_scroll(&self, window_id: WindowId, device_id: InputDeviceId, delta: MouseScrollDelta, phase: TouchPhase) {
1368 let position = if self.pos_window == Some(window_id) {
1369 self.pos
1370 } else {
1371 DipPoint::default()
1372 };
1373
1374 let hits = self.hits.clone().unwrap_or_else(|| HitTestInfo::no_hits(window_id));
1375
1376 let frame_info = WINDOWS.widget_tree(hits.window_id()).unwrap();
1377
1378 let target = hits
1379 .target()
1380 .and_then(|t| frame_info.get(t.widget_id).map(|w| w.interaction_path()))
1381 .unwrap_or_else(|| frame_info.root().interaction_path());
1382
1383 if let Some(target) = target.unblocked() {
1384 let args = MouseWheelArgs::now(hits.window_id(), device_id, position, self.modifiers, delta, phase, hits, target);
1385 MOUSE_WHEEL_EVENT.notify(args);
1386 }
1387 }
1388
1389 fn on_cursor_left_window(&mut self, window_id: WindowId, device_id: InputDeviceId) {
1390 if Some(window_id) == self.pos_window.take() {
1391 self.position.set(None);
1392 if let Some(path) = self.hovered_value.take() {
1393 self.hovered.set(None);
1394 let capture = POINTER_CAPTURE.current_capture().get();
1395 let args = MouseHoverArgs::now(
1396 window_id,
1397 device_id,
1398 self.pos,
1399 HitTestInfo::no_hits(window_id),
1400 Some(path),
1401 None,
1402 capture.clone(),
1403 capture,
1404 );
1405 MOUSE_HOVERED_EVENT.notify(args);
1406 }
1407 }
1408 }
1409
1410 fn on_window_blur(&mut self, prev_window: WindowId, new_window: Option<WindowId>) {
1411 if new_window.is_some() {
1412 if let Some(p) = self.pos_window {
1413 if p == prev_window && (new_window.is_none() || new_window != self.hits.as_ref().map(|h| h.window_id())) {
1415 self.clean_all_state();
1416 }
1417 }
1418 } else {
1419 self.clean_all_state();
1420 }
1421 }
1422
1423 fn continue_hovered(&mut self, mut window_id: WindowId) {
1425 if self.pos_window == Some(window_id) {
1426 let mut frame_info = match WINDOWS.widget_tree(window_id) {
1428 Some(f) => f,
1429 None => {
1430 self.clean_all_state();
1431 return;
1432 }
1433 };
1434 let mut pos_hits = frame_info.root().hit_test(self.pos.to_px(frame_info.scale_factor()));
1435 let mut position = self.pos;
1436 let target = if let Some(t) = pos_hits.target() {
1437 if let Some(w) = frame_info.get(t.widget_id) {
1438 if let Some(f) = w.nested_window_tree() {
1439 frame_info = f;
1440 let factor = frame_info.scale_factor();
1441 let pos = self.pos.to_px(factor);
1442 let pos = w.inner_transform().inverse().and_then(|t| t.transform_point(pos)).unwrap_or(pos);
1443 pos_hits = frame_info.root().hit_test(pos);
1444 window_id = frame_info.window_id();
1445 position = pos.to_dip(factor);
1446 pos_hits
1447 .target()
1448 .and_then(|h| frame_info.get(h.widget_id))
1449 .map(|w| w.interaction_path())
1450 .unwrap_or_else(|| frame_info.root().interaction_path())
1451 } else {
1452 w.interaction_path()
1453 }
1454 } else {
1455 tracing::error!("hits target `{}` not found", t.widget_id);
1456 frame_info.root().interaction_path()
1457 }
1458 } else {
1459 frame_info.root().interaction_path()
1460 }
1461 .unblocked();
1462 self.hits = Some(pos_hits.clone());
1463
1464 if self.hovered_value != target {
1465 let capture = POINTER_CAPTURE.current_capture().get();
1466 let prev = mem::replace(&mut self.hovered_value, target.clone());
1467 let args = MouseHoverArgs::now(window_id, None, position, pos_hits, prev, target, capture.clone(), capture);
1468 MOUSE_HOVERED_EVENT.notify(args);
1469 }
1470 }
1471 }
1472
1473 fn clean_all_state(&mut self) {
1474 if self.pos_window.take().is_some()
1475 && let Some(path) = self.hovered_value.take()
1476 {
1477 let window_id = path.window_id();
1478 self.buttons.with(|b| {
1479 for btn in b {
1480 let args = MouseInputArgs::now(
1481 window_id,
1482 None,
1483 *btn,
1484 DipPoint::new(Dip::new(-1), Dip::new(-1)),
1485 ModifiersState::empty(),
1486 ButtonState::Released,
1487 HitTestInfo::no_hits(window_id),
1488 path.clone(),
1489 None,
1490 false,
1491 );
1492 MOUSE_INPUT_EVENT.notify(args);
1493 }
1494 });
1495
1496 let args = MouseHoverArgs::now(
1497 window_id,
1498 None,
1499 DipPoint::new(Dip::new(-1), Dip::new(-1)),
1500 HitTestInfo::no_hits(window_id),
1501 Some(path),
1502 None,
1503 None,
1504 None,
1505 );
1506 MOUSE_HOVERED_EVENT.notify(args);
1507 }
1508 self.buttons.set(vec![]);
1509 self.clicking.clear();
1510 self.pos_device = None;
1511 self.pos_window = None;
1512 self.hits = None;
1513 self.position.set(None);
1514 self.hovered.set(None);
1515 }
1516
1517 fn on_pointer_capture(&mut self, prev_capture: &Option<CaptureInfo>, new_capture: &Option<CaptureInfo>) {
1518 if let Some(path) = &self.hovered_value
1519 && self.pos_window.is_some()
1520 {
1521 let window_id = path.window_id();
1522 let hover_args = MouseHoverArgs::now(
1523 window_id,
1524 self.pos_device.unwrap(),
1525 self.pos,
1526 self.hits.clone().unwrap_or_else(|| HitTestInfo::no_hits(window_id)),
1527 Some(path.clone()),
1528 Some(path.clone()),
1529 prev_capture.clone(),
1530 new_capture.clone(),
1531 );
1532 MOUSE_HOVERED_EVENT.notify(hover_args);
1533 }
1534 }
1535}
1536impl MouseService {
1537 fn on_repeat_timer_elapsed(&mut self) {
1538 for (btn, info) in self.clicking.iter_mut() {
1540 if let Some(timer) = info.repeat_timer.take() {
1541 if timer.with_new(|t| t.has_elapsed()).unwrap_or(false) {
1543 info.repeat_count = info.repeat_count.saturating_add(1);
1545
1546 if let Some(dv) = self.pos_device
1547 && let Some(tree) = WINDOWS.widget_tree(info.path.window_id())
1548 {
1549 let hit_test = tree.root().hit_test(self.pos.to_px(tree.scale_factor()));
1552
1553 let mut target = None;
1555 if let Some(hit) = hit_test.target().map(|t| tree.get(t.widget_id).unwrap()) {
1556 target = hit.path().shared_ancestor(info.path.as_path()).map(|c| c.into_owned());
1557 }
1558 if let Some(c) = POINTER_CAPTURE.current_capture().get() {
1559 match c.mode {
1560 CaptureMode::Window => {
1561 if let Some(t) = &target {
1562 if t.window_id() != c.target.window_id() {
1563 target = None; }
1565 } else {
1566 target = Some(tree.root().path());
1568 }
1569 }
1570 CaptureMode::Subtree => {
1571 if let Some(t) = &target {
1572 target = c.target.shared_ancestor(t).map(|c| c.into_owned());
1573 } else {
1574 target = Some(c.target);
1575 }
1576 }
1577 CaptureMode::Widget => {
1578 target = Some(c.target);
1579 }
1580 }
1581 }
1582
1583 if let Some(target) = target {
1584 if let Some(target) = tree.get(target.widget_id()).and_then(|w| w.interaction_path().unblocked()) {
1586 let args = MouseClickArgs::now(
1590 target.window_id(),
1591 dv,
1592 *btn,
1593 self.pos,
1594 self.modifiers,
1595 NonZeroU32::new(info.repeat_count).unwrap(),
1596 true,
1597 hit_test,
1598 target,
1599 );
1600 MOUSE_CLICK_EVENT.notify(args);
1601
1602 let t = MOUSE.repeat_config().get().interval;
1604 let t = TIMERS.deadline(t);
1605 t.hook(|t| {
1606 let elapsed = t.value().has_elapsed();
1607 if elapsed {
1608 MOUSE_SV.write().on_repeat_timer_elapsed();
1609 }
1610 !elapsed
1611 })
1612 .perm();
1613 info.repeat_timer = Some(t);
1614 }
1615 }
1616 }
1617 } else {
1618 info.repeat_timer = Some(timer);
1620 }
1621 }
1622 }
1623 }
1624}