1use std::{collections::HashMap, mem, num::NonZeroU32, time::*};
6
7use zng_app::{
8 AppExtension, DInstant, INSTANT,
9 event::{EventPropagationHandle, event, event_args},
10 shortcut::ModifiersState,
11 timer::{DeadlineVar, TIMERS},
12 update::EventUpdate,
13 view_process::{
14 VIEW_PROCESS_INITED_EVENT,
15 raw_device_events::DeviceId,
16 raw_events::{
17 RAW_FRAME_RENDERED_EVENT, RAW_MOUSE_INPUT_EVENT, RAW_MOUSE_LEFT_EVENT, RAW_MOUSE_MOVED_EVENT, RAW_MOUSE_WHEEL_EVENT,
18 RAW_MULTI_CLICK_CONFIG_CHANGED_EVENT, RAW_WINDOW_FOCUS_EVENT,
19 },
20 },
21 widget::{
22 WIDGET, WidgetId,
23 info::{HitTestInfo, InteractionPath, WIDGET_INFO_CHANGED_EVENT, WidgetInfo, WidgetInfoBuilder},
24 },
25 window::WindowId,
26};
27use zng_app_context::app_local;
28use zng_ext_window::{NestedWindowWidgetInfoExt, WINDOWS};
29use zng_layout::unit::{Dip, DipPoint, DipToPx, Factor, PxPoint, PxToDip};
30use zng_state_map::{StateId, state_map, static_id};
31use zng_var::{ArcVar, BoxedVar, IntoVar, LocalVar, ReadOnlyArcVar, Var, impl_from_and_into_var, types::ArcCowVar, var};
32use zng_view_api::touch::TouchPhase;
33pub use zng_view_api::{
34 config::MultiClickConfig,
35 mouse::{ButtonState, MouseButton, MouseScrollDelta},
36};
37
38use crate::{
39 keyboard::{KEYBOARD, MODIFIERS_CHANGED_EVENT},
40 pointer_capture::{CaptureInfo, CaptureMode, POINTER_CAPTURE, POINTER_CAPTURE_EVENT},
41};
42
43event_args! {
44 pub struct MouseMoveArgs {
46 pub window_id: WindowId,
48
49 pub device_id: DeviceId,
51
52 pub modifiers: ModifiersState,
54
55 pub coalesced_pos: Vec<DipPoint>,
59
60 pub position: DipPoint,
62
63 pub hits: HitTestInfo,
65
66 pub target: InteractionPath,
68
69 pub capture: Option<CaptureInfo>,
71
72 ..
73
74 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
79 list.insert_wgt(&self.target);
80 if let Some(c) = &self.capture {
81 list.insert_wgt(&c.target);
82 }
83 }
84 }
85
86 pub struct MouseInputArgs {
88 pub window_id: WindowId,
90
91 pub device_id: Option<DeviceId>,
93
94 pub button: MouseButton,
96
97 pub position: DipPoint,
99
100 pub modifiers: ModifiersState,
102
103 pub state: ButtonState,
107
108 pub hits: HitTestInfo,
110
111 pub target: InteractionPath,
115
116 pub capture: Option<CaptureInfo>,
118
119 pub is_click: bool,
123
124 ..
125
126 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
131 list.insert_wgt(&self.target);
132 if let Some(c) = &self.capture {
133 list.insert_wgt(&c.target);
134 }
135 }
136 }
137
138 pub struct MouseClickArgs {
140 pub window_id: WindowId,
142
143 pub device_id: DeviceId,
145
146 pub button: MouseButton,
148
149 pub position: DipPoint,
151
152 pub modifiers: ModifiersState,
154
155 pub click_count: NonZeroU32,
159
160 pub is_repeat: bool,
162
163 pub hits: HitTestInfo,
166
167 pub target: InteractionPath,
183
184 ..
185
186 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
190 list.insert_wgt(&self.target)
191 }
192 }
193
194 pub struct MouseHoverArgs {
196 pub window_id: WindowId,
198
199 pub device_id: Option<DeviceId>,
201
202 pub position: DipPoint,
204
205 pub hits: HitTestInfo,
207
208 pub prev_target: Option<InteractionPath>,
210
211 pub target: Option<InteractionPath>,
218
219 pub prev_capture: Option<CaptureInfo>,
221
222 pub capture: Option<CaptureInfo>,
224
225 ..
226
227 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
233 if let Some(p) = &self.prev_target {
234 list.insert_wgt(p);
235 }
236 if let Some(p) = &self.target {
237 list.insert_wgt(p);
238 }
239 if let Some(c) = &self.capture {
240 list.insert_wgt(&c.target);
241 }
242 }
243 }
244
245 pub struct MouseWheelArgs {
247 pub window_id: WindowId,
249 pub device_id: DeviceId,
251
252 pub position: DipPoint,
254 pub modifiers: ModifiersState,
256
257 pub delta: MouseScrollDelta,
259
260 pub phase: TouchPhase,
262
263 pub hits: HitTestInfo,
266
267 pub target: InteractionPath,
269
270 ..
271
272 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
276 list.insert_wgt(&self.target)
277 }
278 }
279}
280
281impl MouseHoverArgs {
282 pub fn capture_allows(&self) -> bool {
288 self.capture.as_ref().map(|c| c.allows()).unwrap_or(true)
289 }
290
291 pub fn is_mouse_move(&self) -> bool {
293 self.device_id.is_some()
294 }
295
296 pub fn is_widget_move(&self) -> bool {
298 self.device_id.is_none()
299 }
300
301 pub fn is_capture_change(&self) -> bool {
303 self.prev_capture != self.capture
304 }
305
306 pub fn is_mouse_enter(&self) -> bool {
310 !self.was_over() && self.is_over()
311 }
312
313 pub fn is_mouse_leave(&self) -> bool {
317 self.was_over() && !self.is_over()
318 }
319
320 pub fn is_mouse_enter_enabled(&self) -> bool {
324 (!self.was_over() || self.was_disabled(WIDGET.id())) && self.is_over() && self.is_enabled(WIDGET.id())
325 }
326
327 pub fn is_mouse_leave_enabled(&self) -> bool {
331 self.was_over() && self.was_enabled(WIDGET.id()) && (!self.is_over() || self.is_disabled(WIDGET.id()))
332 }
333
334 pub fn is_mouse_enter_disabled(&self) -> bool {
338 (!self.was_over() || self.was_enabled(WIDGET.id())) && self.is_over() && self.is_disabled(WIDGET.id())
339 }
340
341 pub fn is_mouse_leave_disabled(&self) -> bool {
345 self.was_over() && self.was_disabled(WIDGET.id()) && (!self.is_over() || self.is_enabled(WIDGET.id()))
346 }
347
348 pub fn was_over(&self) -> bool {
354 if let Some(cap) = &self.prev_capture {
355 if !cap.allows() {
356 return false;
357 }
358 }
359
360 if let Some(t) = &self.prev_target {
361 return t.contains(WIDGET.id());
362 }
363
364 false
365 }
366
367 pub fn is_over(&self) -> bool {
373 if let Some(cap) = &self.capture {
374 if !cap.allows() {
375 return false;
376 }
377 }
378
379 if let Some(t) = &self.target {
380 return t.contains(WIDGET.id());
381 }
382
383 false
384 }
385
386 pub fn was_enabled(&self, widget_id: WidgetId) -> bool {
390 self.prev_target
391 .as_ref()
392 .and_then(|t| t.interactivity_of(widget_id))
393 .map(|itr| itr.is_enabled())
394 .unwrap_or(false)
395 }
396
397 pub fn was_disabled(&self, widget_id: WidgetId) -> bool {
401 self.prev_target
402 .as_ref()
403 .and_then(|t| t.interactivity_of(widget_id))
404 .map(|itr| itr.is_disabled())
405 .unwrap_or(false)
406 }
407
408 pub fn is_enabled(&self, widget_id: WidgetId) -> bool {
412 self.target
413 .as_ref()
414 .and_then(|t| t.interactivity_of(widget_id))
415 .map(|itr| itr.is_enabled())
416 .unwrap_or(false)
417 }
418
419 pub fn is_disabled(&self, widget_id: WidgetId) -> bool {
423 self.target
424 .as_ref()
425 .and_then(|t| t.interactivity_of(widget_id))
426 .map(|itr| itr.is_disabled())
427 .unwrap_or(false)
428 }
429
430 pub fn position_wgt(&self) -> Option<PxPoint> {
432 WIDGET.win_point_to_wgt(self.position)
433 }
434}
435
436impl MouseMoveArgs {
437 pub fn capture_allows(&self) -> bool {
443 self.capture.as_ref().map(|c| c.allows()).unwrap_or(true)
444 }
445
446 pub fn position_wgt(&self) -> Option<PxPoint> {
448 WIDGET.win_point_to_wgt(self.position)
449 }
450}
451
452impl MouseInputArgs {
453 pub fn capture_allows(&self) -> bool {
459 self.capture.as_ref().map(|c| c.allows()).unwrap_or(true)
460 }
461
462 pub fn is_over(&self, widget_id: WidgetId) -> bool {
466 self.target.contains(widget_id)
467 }
468
469 pub fn is_enabled(&self, widget_id: WidgetId) -> bool {
473 self.target.interactivity_of(widget_id).map(|i| i.is_enabled()).unwrap_or(false)
474 }
475
476 pub fn is_disabled(&self, widget_id: WidgetId) -> bool {
480 self.target.interactivity_of(widget_id).map(|i| i.is_disabled()).unwrap_or(false)
481 }
482
483 pub fn is_primary(&self) -> bool {
487 self.button == MouseButton::Left
488 }
489
490 pub fn is_context(&self) -> bool {
492 self.button == MouseButton::Right
493 }
494
495 pub fn is_mouse_down(&self) -> bool {
499 self.state == ButtonState::Pressed
500 }
501
502 pub fn is_mouse_up(&self) -> bool {
506 self.state == ButtonState::Released
507 }
508
509 pub fn position_wgt(&self) -> Option<PxPoint> {
511 WIDGET.win_point_to_wgt(self.position)
512 }
513}
514
515impl MouseClickArgs {
516 pub fn is_enabled(&self, widget_id: WidgetId) -> bool {
520 self.target.interactivity_of(widget_id).map(|i| i.is_enabled()).unwrap_or(false)
521 }
522
523 pub fn is_disabled(&self, widget_id: WidgetId) -> bool {
527 self.target.interactivity_of(widget_id).map(|i| i.is_disabled()).unwrap_or(false)
528 }
529
530 pub fn is_primary(&self) -> bool {
532 self.button == MouseButton::Left
533 }
534
535 pub fn is_context(&self) -> bool {
537 self.button == MouseButton::Right
538 }
539
540 pub fn is_single(&self) -> bool {
542 self.click_count.get() == 1
543 }
544
545 pub fn is_double(&self) -> bool {
547 self.click_count.get() == 2
548 }
549
550 pub fn is_triple(&self) -> bool {
552 self.click_count.get() == 3
553 }
554
555 pub fn position_wgt(&self) -> Option<PxPoint> {
557 WIDGET.win_point_to_wgt(self.position)
558 }
559}
560
561impl MouseWheelArgs {
562 pub fn shifted_delta(&self) -> MouseScrollDelta {
566 if self.modifiers.has_shift() {
567 match self.delta {
568 MouseScrollDelta::LineDelta(x, y) => MouseScrollDelta::LineDelta(y, x),
569 MouseScrollDelta::PixelDelta(x, y) => MouseScrollDelta::PixelDelta(y, x),
570 }
571 } else {
572 self.delta
573 }
574 }
575
576 pub fn is_scroll(&self) -> bool {
583 self.modifiers.is_empty() || self.modifiers.is_only(ModifiersState::SHIFT | ModifiersState::ALT)
584 }
585
586 pub fn scroll_delta(&self, alt_factor: impl Into<Factor>) -> Option<MouseScrollDelta> {
593 let mut modifiers = self.modifiers;
594 let mut delta = self.delta;
595 if modifiers.take_alt() {
596 let alt_factor = alt_factor.into();
597 delta = match delta {
598 MouseScrollDelta::LineDelta(x, y) => MouseScrollDelta::LineDelta(x * alt_factor.0, y * alt_factor.0),
599 MouseScrollDelta::PixelDelta(x, y) => MouseScrollDelta::PixelDelta(x * alt_factor.0, y * alt_factor.0),
600 };
601 }
602
603 if modifiers.is_empty() {
604 Some(delta)
605 } else if modifiers.is_only_shift() {
606 Some(match delta {
607 MouseScrollDelta::LineDelta(x, y) => MouseScrollDelta::LineDelta(y, x),
608 MouseScrollDelta::PixelDelta(x, y) => MouseScrollDelta::PixelDelta(y, x),
609 })
610 } else {
611 None
612 }
613 }
614
615 pub fn is_zoom(&self) -> bool {
621 self.modifiers.is_only_ctrl()
622 }
623
624 pub fn zoom_delta(&self) -> Option<MouseScrollDelta> {
630 if self.is_zoom() { Some(self.delta) } else { None }
631 }
632
633 pub fn is_enabled(&self, widget_id: WidgetId) -> bool {
637 self.target.interactivity_of(widget_id).map(|i| i.is_enabled()).unwrap_or(false)
638 }
639
640 pub fn is_disabled(&self, widget_id: WidgetId) -> bool {
644 self.target.interactivity_of(widget_id).map(|i| i.is_disabled()).unwrap_or(false)
645 }
646
647 pub fn position_wgt(&self) -> Option<PxPoint> {
649 WIDGET.win_point_to_wgt(self.position)
650 }
651}
652
653event! {
654 pub static MOUSE_MOVE_EVENT: MouseMoveArgs;
656
657 pub static MOUSE_INPUT_EVENT: MouseInputArgs;
659
660 pub static MOUSE_CLICK_EVENT: MouseClickArgs;
662
663 pub static MOUSE_HOVERED_EVENT: MouseHoverArgs;
665
666 pub static MOUSE_WHEEL_EVENT: MouseWheelArgs;
668}
669
670struct ClickingInfo {
671 path: InteractionPath,
672 press_stop_handle: EventPropagationHandle,
673
674 pressed: bool,
675 last_pos: DipPoint,
676 last_click: DInstant,
677 click_count: u32,
678
679 repeat_timer: Option<DeadlineVar>,
680 repeat_count: u32,
681}
682
683pub struct MouseManager {
700 pos: DipPoint,
702 pos_window: Option<WindowId>,
704 pos_device: Option<DeviceId>,
705 hits: Option<HitTestInfo>,
707
708 modifiers: ModifiersState,
710
711 hovered: Option<InteractionPath>,
712 clicking: HashMap<MouseButton, ClickingInfo>,
713}
714impl Default for MouseManager {
715 fn default() -> Self {
716 MouseManager {
717 pos: DipPoint::zero(),
718 pos_window: None,
719 pos_device: None,
720 hits: None,
721
722 modifiers: ModifiersState::default(),
723
724 hovered: None,
725 clicking: HashMap::default(),
726 }
727 }
728}
729impl MouseManager {
730 fn on_mouse_input(&mut self, mut window_id: WindowId, device_id: DeviceId, state: ButtonState, button: MouseButton) {
731 let mouse = MOUSE_SV.read();
732
733 let mut position = if self.pos_window == Some(window_id) {
734 self.pos
735 } else {
736 DipPoint::default()
737 };
738
739 let hits = self.hits.clone().unwrap_or_else(|| HitTestInfo::no_hits(window_id));
740
741 let wgt_tree = match WINDOWS.widget_tree(hits.window_id()) {
742 Ok(t) => t,
743 Err(e) => {
744 tracing::error!("cannot find clicked window, {e:?}");
745 return;
746 }
747 };
748
749 if hits.window_id() != window_id {
750 window_id = hits.window_id();
752 position = hits.point().to_dip(wgt_tree.scale_factor());
753 }
754
755 let (wgt_path, click_mode) = hits
756 .target()
757 .and_then(|t| wgt_tree.get(t.widget_id).map(|w| (w.interaction_path(), w.click_mode())))
758 .unwrap_or_else(|| (wgt_tree.root().interaction_path(), wgt_tree.root().click_mode()));
759
760 let wgt_path = match wgt_path.unblocked() {
761 Some(p) => p,
762 None => return, };
764
765 match state {
766 ButtonState::Pressed => {
767 if !mouse.buttons.with(|b| b.contains(&button)) {
768 mouse.buttons.modify(move |btns| btns.to_mut().push(button));
769 }
770 }
771 ButtonState::Released => {
772 if mouse.buttons.with(|b| b.contains(&button)) {
773 mouse.buttons.modify(move |btns| {
774 if let Some(i) = btns.as_ref().iter().position(|k| *k == button) {
775 btns.to_mut().swap_remove(i);
776 }
777 });
778 }
779 }
780 }
781
782 let stop_handle = EventPropagationHandle::new();
783
784 let entry = self.clicking.entry(button).or_insert_with(|| ClickingInfo {
785 path: wgt_path.clone(),
786 press_stop_handle: stop_handle.clone(),
787 last_click: DInstant::EPOCH,
788 last_pos: position,
789 pressed: false,
790 click_count: 0,
791 repeat_timer: None,
792 repeat_count: 0,
793 });
794
795 if entry.path != wgt_path {
796 let actual_change = entry.path.as_path() != wgt_path.as_path();
797 entry.path = wgt_path.clone();
800 if actual_change {
801 entry.press_stop_handle = stop_handle.clone();
802 entry.pressed = false;
803 entry.click_count = 0;
804 entry.repeat_timer = None;
805 entry.repeat_count = 0;
806 }
807 }
808
809 let multi_click_cfg = mouse.multi_click_config.get();
810
811 let double_allowed = entry.last_click.elapsed() <= multi_click_cfg.time && {
812 let dist = (entry.last_pos.to_vector() - position.to_vector()).abs();
813 let area = multi_click_cfg.area;
814 dist.x <= area.width && dist.y <= area.height
815 };
816
817 let click_gesture = if entry.click_count == 0 || !double_allowed {
818 entry.click_count = 0;
819 click_mode.single
820 } else {
821 click_mode.double
822 };
823
824 let click = match state {
825 ButtonState::Pressed => {
826 entry.pressed = true;
827 entry.press_stop_handle = stop_handle.clone();
828 matches!(click_gesture, ClickTrigger::Press)
829 }
830 ButtonState::Released => {
831 entry.repeat_count = 0;
832 entry.repeat_timer = None;
833 if mem::take(&mut entry.pressed) && !entry.press_stop_handle.is_stopped() {
834 matches!(click_gesture, ClickTrigger::PressRelease | ClickTrigger::Release)
835 } else {
836 matches!(click_gesture, ClickTrigger::Release)
837 }
838 }
839 };
840
841 if click_mode.repeat {
842 if click {
843 let t = mouse.repeat_config.get().start_delay;
844 entry.repeat_timer = Some(TIMERS.deadline(t));
845 entry.repeat_count = 0;
846 }
847 } else {
848 entry.repeat_timer = None;
849 entry.repeat_count = 0;
850 }
851
852 let capture_info = POINTER_CAPTURE.current_capture_value();
853
854 let now = INSTANT.now();
855 let args = MouseInputArgs::new(
856 now,
857 stop_handle.clone(),
858 window_id,
859 device_id,
860 button,
861 position,
862 self.modifiers,
863 state,
864 hits.clone(),
865 wgt_path.clone(),
866 capture_info,
867 click,
868 );
869
870 MOUSE_INPUT_EVENT.notify(args);
872
873 if click {
874 if double_allowed {
875 entry.click_count += 1;
876 } else {
877 entry.click_count = 1;
878 }
879
880 entry.last_click = now;
881 entry.last_pos = position;
882
883 let args = MouseClickArgs::new(
884 now,
885 stop_handle,
886 window_id,
887 device_id,
888 button,
889 position,
890 self.modifiers,
891 NonZeroU32::new(entry.click_count).unwrap(),
892 false,
893 hits,
894 wgt_path,
895 );
896
897 MOUSE_CLICK_EVENT.notify(args);
899 }
900 }
901
902 fn on_cursor_moved(&mut self, window_id: WindowId, device_id: DeviceId, coalesced_pos: Vec<DipPoint>, mut position: DipPoint) {
903 let mut moved = Some(window_id) != self.pos_window || Some(device_id) != self.pos_device;
904
905 if moved {
906 self.pos_window = Some(window_id);
908 self.pos_device = Some(device_id);
909 }
910
911 moved |= position != self.pos;
912
913 if moved {
914 self.pos = position;
917
918 let mut frame_info = match WINDOWS.widget_tree(window_id) {
920 Ok(f) => f,
921 Err(_) => {
922 if let Some(hovered) = self.hovered.take() {
924 let capture = POINTER_CAPTURE.current_capture_value();
925 let args = MouseHoverArgs::now(
926 window_id,
927 device_id,
928 position,
929 HitTestInfo::no_hits(window_id),
930 Some(hovered),
931 None,
932 capture.clone(),
933 capture,
934 );
935 MOUSE_HOVERED_EVENT.notify(args);
936 }
937 return;
938 }
939 };
940
941 let mut pos_hits = frame_info.root().hit_test(position.to_px(frame_info.scale_factor()));
942
943 let target = if let Some(t) = pos_hits.target() {
944 if let Some(w) = frame_info.get(t.widget_id) {
945 if let Some(f) = w.nested_window_tree() {
946 frame_info = f;
948 let factor = frame_info.scale_factor();
949 let pos = position.to_px(factor);
950 let pos = w.inner_transform().inverse().and_then(|t| t.transform_point(pos)).unwrap_or(pos);
951 pos_hits = frame_info.root().hit_test(pos);
952 position = pos.to_dip(factor);
953 pos_hits
954 .target()
955 .and_then(|h| frame_info.get(h.widget_id))
956 .map(|w| w.interaction_path())
957 .unwrap_or_else(|| frame_info.root().interaction_path())
958 } else {
959 w.interaction_path()
960 }
961 } else {
962 tracing::error!("hits target `{}` not found", t.widget_id);
963 frame_info.root().interaction_path()
964 }
965 } else {
966 frame_info.root().interaction_path()
967 }
968 .unblocked();
969
970 MOUSE_SV.read().position.set(Some(MousePosition {
971 window_id: frame_info.window_id(),
972 position,
973 timestamp: INSTANT.now(),
974 }));
975
976 self.hits = Some(pos_hits.clone());
977
978 let capture = POINTER_CAPTURE.current_capture_value();
979
980 let hovered_args = if self.hovered != target {
982 MOUSE_SV.read().hovered.set(target.clone());
983 let prev_target = mem::replace(&mut self.hovered, target.clone());
984 let args = MouseHoverArgs::now(
985 frame_info.window_id(),
986 device_id,
987 position,
988 pos_hits.clone(),
989 prev_target,
990 target.clone(),
991 capture.clone(),
992 capture.clone(),
993 );
994 Some(args)
995 } else {
996 None
997 };
998
999 if let Some(target) = target {
1001 let args = MouseMoveArgs::now(
1002 frame_info.window_id(),
1003 device_id,
1004 self.modifiers,
1005 coalesced_pos,
1006 position,
1007 pos_hits,
1008 target,
1009 capture,
1010 );
1011 MOUSE_MOVE_EVENT.notify(args);
1012 }
1013
1014 if let Some(args) = hovered_args {
1015 MOUSE_HOVERED_EVENT.notify(args);
1016 }
1017 } else if coalesced_pos.is_empty() {
1018 tracing::debug!("RawCursorMoved did not actually move")
1019 }
1020 }
1021
1022 fn on_scroll(&self, window_id: WindowId, device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase) {
1023 let position = if self.pos_window == Some(window_id) {
1024 self.pos
1025 } else {
1026 DipPoint::default()
1027 };
1028
1029 let hits = self.hits.clone().unwrap_or_else(|| HitTestInfo::no_hits(window_id));
1030
1031 let frame_info = WINDOWS.widget_tree(hits.window_id()).unwrap();
1032
1033 let target = hits
1034 .target()
1035 .and_then(|t| frame_info.get(t.widget_id).map(|w| w.interaction_path()))
1036 .unwrap_or_else(|| frame_info.root().interaction_path());
1037
1038 if let Some(target) = target.unblocked() {
1039 let args = MouseWheelArgs::now(hits.window_id(), device_id, position, self.modifiers, delta, phase, hits, target);
1040 MOUSE_WHEEL_EVENT.notify(args);
1041 }
1042 }
1043
1044 fn on_cursor_left_window(&mut self, window_id: WindowId, device_id: DeviceId) {
1045 if Some(window_id) == self.pos_window.take() {
1046 MOUSE_SV.read().position.set(None);
1047 if let Some(path) = self.hovered.take() {
1048 MOUSE_SV.read().hovered.set(None);
1049 let capture = POINTER_CAPTURE.current_capture_value();
1050 let args = MouseHoverArgs::now(
1051 window_id,
1052 device_id,
1053 self.pos,
1054 HitTestInfo::no_hits(window_id),
1055 Some(path),
1056 None,
1057 capture.clone(),
1058 capture,
1059 );
1060 MOUSE_HOVERED_EVENT.notify(args);
1061 }
1062 }
1063 }
1064
1065 fn on_window_blur(&mut self, prev_window: WindowId, new_window: Option<WindowId>) {
1066 if new_window.is_some() {
1067 if let Some(p) = self.pos_window {
1068 if p == prev_window && (new_window.is_none() || new_window != self.hits.as_ref().map(|h| h.window_id())) {
1070 self.clean_all_state();
1071 }
1072 }
1073 } else {
1074 self.clean_all_state();
1075 }
1076 }
1077
1078 fn continue_hovered(&mut self, mut window_id: WindowId) {
1080 if self.pos_window == Some(window_id) {
1081 let mut frame_info = match WINDOWS.widget_tree(window_id) {
1083 Ok(f) => f,
1084 Err(_) => {
1085 self.clean_all_state();
1086 return;
1087 }
1088 };
1089 let mut pos_hits = frame_info.root().hit_test(self.pos.to_px(frame_info.scale_factor()));
1090 let mut position = self.pos;
1091 let target = if let Some(t) = pos_hits.target() {
1092 if let Some(w) = frame_info.get(t.widget_id) {
1093 if let Some(f) = w.nested_window_tree() {
1094 frame_info = f;
1095 let factor = frame_info.scale_factor();
1096 let pos = self.pos.to_px(factor);
1097 let pos = w.inner_transform().inverse().and_then(|t| t.transform_point(pos)).unwrap_or(pos);
1098 pos_hits = frame_info.root().hit_test(pos);
1099 window_id = frame_info.window_id();
1100 position = pos.to_dip(factor);
1101 pos_hits
1102 .target()
1103 .and_then(|h| frame_info.get(h.widget_id))
1104 .map(|w| w.interaction_path())
1105 .unwrap_or_else(|| frame_info.root().interaction_path())
1106 } else {
1107 w.interaction_path()
1108 }
1109 } else {
1110 tracing::error!("hits target `{}` not found", t.widget_id);
1111 frame_info.root().interaction_path()
1112 }
1113 } else {
1114 frame_info.root().interaction_path()
1115 }
1116 .unblocked();
1117 self.hits = Some(pos_hits.clone());
1118
1119 if self.hovered != target {
1120 let capture = POINTER_CAPTURE.current_capture_value();
1121 let prev = mem::replace(&mut self.hovered, target.clone());
1122 let args = MouseHoverArgs::now(window_id, None, position, pos_hits, prev, target, capture.clone(), capture);
1123 MOUSE_HOVERED_EVENT.notify(args);
1124 }
1125 }
1126 }
1127
1128 fn clean_all_state(&mut self) {
1129 let mouse = MOUSE_SV.read();
1130 if self.pos_window.take().is_some() {
1131 if let Some(path) = self.hovered.take() {
1132 let window_id = path.window_id();
1133 mouse.buttons.with(|b| {
1134 for btn in b {
1135 let args = MouseInputArgs::now(
1136 window_id,
1137 None,
1138 *btn,
1139 DipPoint::new(Dip::new(-1), Dip::new(-1)),
1140 ModifiersState::empty(),
1141 ButtonState::Released,
1142 HitTestInfo::no_hits(window_id),
1143 path.clone(),
1144 None,
1145 false,
1146 );
1147 MOUSE_INPUT_EVENT.notify(args);
1148 }
1149 });
1150
1151 let args = MouseHoverArgs::now(
1152 window_id,
1153 None,
1154 DipPoint::new(Dip::new(-1), Dip::new(-1)),
1155 HitTestInfo::no_hits(window_id),
1156 Some(path),
1157 None,
1158 None,
1159 None,
1160 );
1161 MOUSE_HOVERED_EVENT.notify(args);
1162 }
1163 }
1164 mouse.buttons.set(vec![]);
1165 self.clicking.clear();
1166 self.pos_device = None;
1167 self.pos_window = None;
1168 self.hits = None;
1169 mouse.position.set(None);
1170 mouse.hovered.set(None);
1171 }
1172}
1173impl AppExtension for MouseManager {
1174 fn event_preview(&mut self, update: &mut EventUpdate) {
1175 if let Some(args) = RAW_FRAME_RENDERED_EVENT.on(update) {
1176 self.continue_hovered(args.window_id);
1177 } else if let Some(args) = RAW_MOUSE_MOVED_EVENT.on(update) {
1178 self.on_cursor_moved(args.window_id, args.device_id, args.coalesced_pos.clone(), args.position);
1179 } else if let Some(args) = RAW_MOUSE_WHEEL_EVENT.on(update) {
1180 self.on_scroll(args.window_id, args.device_id, args.delta, args.phase);
1181 } else if let Some(args) = RAW_MOUSE_INPUT_EVENT.on(update) {
1182 self.on_mouse_input(args.window_id, args.device_id, args.state, args.button);
1183 } else if let Some(args) = MODIFIERS_CHANGED_EVENT.on(update) {
1184 self.modifiers = args.modifiers;
1185 } else if let Some(args) = RAW_MOUSE_LEFT_EVENT.on(update) {
1186 self.on_cursor_left_window(args.window_id, args.device_id);
1187 } else if let Some(args) = RAW_WINDOW_FOCUS_EVENT.on(update) {
1188 if let Some(window_id) = args.prev_focus {
1189 self.on_window_blur(window_id, args.new_focus);
1190 }
1191 } else if let Some(args) = WIDGET_INFO_CHANGED_EVENT.on(update) {
1192 self.continue_hovered(args.window_id);
1193 } else if let Some(args) = RAW_MULTI_CLICK_CONFIG_CHANGED_EVENT.on(update) {
1194 MOUSE_SV.read().multi_click_config.set(args.config);
1195 self.clicking.clear();
1196 } else if let Some(args) = VIEW_PROCESS_INITED_EVENT.on(update) {
1197 MOUSE_SV.read().multi_click_config.set(args.multi_click_config);
1198
1199 if args.is_respawn {
1200 self.clean_all_state();
1201 }
1202 }
1203 }
1204
1205 fn event(&mut self, update: &mut EventUpdate) {
1206 if let Some(args) = POINTER_CAPTURE_EVENT.on(update) {
1207 if let Some(path) = &self.hovered {
1208 if self.pos_window.is_some() {
1209 let window_id = path.window_id();
1210 let hover_args = MouseHoverArgs::now(
1211 window_id,
1212 self.pos_device.unwrap(),
1213 self.pos,
1214 self.hits.clone().unwrap_or_else(|| HitTestInfo::no_hits(window_id)),
1215 Some(path.clone()),
1216 Some(path.clone()),
1217 args.prev_capture.clone(),
1218 args.new_capture.clone(),
1219 );
1220 MOUSE_HOVERED_EVENT.notify(hover_args);
1221 }
1222 }
1223 }
1224 }
1225
1226 fn update_preview(&mut self) {
1227 for (btn, info) in self.clicking.iter_mut() {
1229 if let Some(timer) = info.repeat_timer.take() {
1230 if timer.with_new(|t| t.has_elapsed()).unwrap_or(false) {
1232 info.repeat_count = info.repeat_count.saturating_add(1);
1234
1235 if let (Some(dv), Ok(tree)) = (self.pos_device, WINDOWS.widget_tree(info.path.window_id())) {
1236 let hit_test = tree.root().hit_test(self.pos.to_px(tree.scale_factor()));
1239
1240 let mut target = None;
1242 if let Some(hit) = hit_test.target().map(|t| tree.get(t.widget_id).unwrap()) {
1243 target = hit.path().shared_ancestor(info.path.as_path()).map(|c| c.into_owned());
1244 }
1245 if let Some(c) = POINTER_CAPTURE.current_capture_value() {
1246 match c.mode {
1247 CaptureMode::Window => {
1248 if let Some(t) = &target {
1249 if t.window_id() != c.target.window_id() {
1250 target = None; }
1252 } else {
1253 target = Some(tree.root().path());
1255 }
1256 }
1257 CaptureMode::Subtree => {
1258 if let Some(t) = &target {
1259 target = c.target.shared_ancestor(t).map(|c| c.into_owned());
1260 } else {
1261 target = Some(c.target);
1262 }
1263 }
1264 CaptureMode::Widget => {
1265 target = Some(c.target);
1266 }
1267 }
1268 }
1269
1270 if let Some(target) = target {
1271 if let Some(target) = tree.get(target.widget_id()).and_then(|w| w.interaction_path().unblocked()) {
1273 let args = MouseClickArgs::now(
1277 target.window_id(),
1278 dv,
1279 *btn,
1280 self.pos,
1281 self.modifiers,
1282 NonZeroU32::new(info.repeat_count).unwrap(),
1283 true,
1284 hit_test,
1285 target,
1286 );
1287 MOUSE_CLICK_EVENT.notify(args);
1288
1289 let t = MOUSE.repeat_config().get().interval;
1291 info.repeat_timer = Some(TIMERS.deadline(t));
1292 }
1293 }
1294 }
1295 } else {
1296 info.repeat_timer = Some(timer);
1298 }
1299 }
1300 }
1301 }
1302}
1303
1304#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1306pub enum ClickTrigger {
1307 PressRelease,
1309 Press,
1311 Release,
1313}
1314
1315#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1317pub struct ClickMode {
1318 pub single: ClickTrigger,
1320
1321 pub double: ClickTrigger,
1323
1324 pub repeat: bool,
1326}
1327impl Default for ClickMode {
1328 fn default() -> Self {
1330 Self {
1331 single: ClickTrigger::PressRelease,
1332 double: ClickTrigger::Press,
1333 repeat: false,
1334 }
1335 }
1336}
1337impl IntoVar<Option<ClickMode>> for ClickTrigger {
1338 type Var = LocalVar<Option<ClickMode>>;
1339
1340 fn into_var(self) -> Self::Var {
1341 Some(ClickMode::from(self)).into_var()
1342 }
1343}
1344impl_from_and_into_var! {
1345 fn from(gesture: ClickTrigger) -> ClickMode {
1346 ClickMode {
1347 single: gesture,
1348 double: gesture,
1349 repeat: false,
1350 }
1351 }
1352
1353 fn from(some: ClickMode) -> Option<ClickMode>;
1354}
1355impl ClickMode {
1356 pub fn press() -> Self {
1358 Self {
1359 single: ClickTrigger::Press,
1360 double: ClickTrigger::Press,
1361 repeat: false,
1362 }
1363 }
1364
1365 pub fn release() -> Self {
1367 Self {
1368 single: ClickTrigger::Release,
1369 double: ClickTrigger::Release,
1370 repeat: false,
1371 }
1372 }
1373
1374 pub fn repeat() -> Self {
1376 Self {
1377 single: ClickTrigger::Press,
1378 double: ClickTrigger::Press,
1379 repeat: true,
1380 }
1381 }
1382
1383 pub fn mixed_repeat() -> Self {
1385 Self {
1386 single: ClickTrigger::PressRelease,
1387 double: ClickTrigger::Press,
1388 repeat: true,
1389 }
1390 }
1391}
1392
1393pub trait WidgetInfoMouseExt {
1395 fn click_mode(&self) -> ClickMode;
1397}
1398impl WidgetInfoMouseExt for WidgetInfo {
1399 fn click_mode(&self) -> ClickMode {
1400 for w in self.self_and_ancestors() {
1401 if let Some(m) = w.meta().get_clone(*CLICK_MODE_ID).flatten() {
1402 return m;
1403 }
1404 }
1405 ClickMode::default()
1406 }
1407}
1408
1409pub trait WidgetInfoBuilderMouseExt {
1411 fn set_click_mode(&mut self, mode: Option<ClickMode>);
1415}
1416impl WidgetInfoBuilderMouseExt for WidgetInfoBuilder {
1417 fn set_click_mode(&mut self, mode: Option<ClickMode>) {
1418 self.with_meta(|mut m| match m.entry(*CLICK_MODE_ID) {
1419 state_map::StateMapEntry::Occupied(mut e) => *e.get_mut() = mode,
1420 state_map::StateMapEntry::Vacant(e) => {
1421 if mode.is_some() {
1422 e.insert(mode);
1423 }
1424 }
1425 })
1426 }
1427}
1428
1429static_id! {
1430 static ref CLICK_MODE_ID: StateId<Option<ClickMode>>;
1431}
1432
1433#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1435pub struct ButtonRepeatConfig {
1436 pub start_delay: Duration,
1438 pub interval: Duration,
1440}
1441impl Default for ButtonRepeatConfig {
1442 fn default() -> Self {
1444 Self {
1445 start_delay: Duration::from_millis(600),
1446 interval: Duration::from_millis(100),
1447 }
1448 }
1449}
1450
1451pub struct MOUSE;
1463impl MOUSE {
1464 pub fn buttons(&self) -> ReadOnlyArcVar<Vec<MouseButton>> {
1468 MOUSE_SV.read().buttons.read_only()
1469 }
1470
1471 pub fn multi_click_config(&self) -> ArcCowVar<MultiClickConfig, ArcVar<MultiClickConfig>> {
1479 MOUSE_SV.read().multi_click_config.clone()
1480 }
1481
1482 pub fn sys_multi_click_config(&self) -> ReadOnlyArcVar<MultiClickConfig> {
1491 MOUSE_SV.read().sys_multi_click_config.read_only()
1492 }
1493
1494 pub fn repeat_config(&self) -> BoxedVar<ButtonRepeatConfig> {
1501 MOUSE_SV.read().repeat_config.clone()
1502 }
1503
1504 pub fn position(&self) -> ReadOnlyArcVar<Option<MousePosition>> {
1506 MOUSE_SV.read().position.read_only()
1507 }
1508
1509 pub fn hovered(&self) -> ReadOnlyArcVar<Option<InteractionPath>> {
1511 MOUSE_SV.read().hovered.read_only()
1512 }
1513}
1514
1515#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1521pub struct MousePosition {
1522 pub window_id: WindowId,
1524 pub position: DipPoint,
1526 pub timestamp: DInstant,
1528}
1529
1530app_local! {
1531 static MOUSE_SV: MouseService = {
1532 let sys_multi_click_config = var(MultiClickConfig::default());
1533 MouseService {
1534 multi_click_config: sys_multi_click_config.cow(),
1535 sys_multi_click_config,
1536 repeat_config: KEYBOARD
1537 .repeat_config()
1538 .map(|c| ButtonRepeatConfig {
1539 start_delay: c.start_delay,
1540 interval: c.interval,
1541 })
1542 .cow()
1543 .boxed(),
1544 buttons: var(vec![]),
1545 hovered: var(None),
1546 position: var(None),
1547 }
1548 };
1549}
1550struct MouseService {
1551 multi_click_config: ArcCowVar<MultiClickConfig, ArcVar<MultiClickConfig>>,
1552 sys_multi_click_config: ArcVar<MultiClickConfig>,
1553 repeat_config: BoxedVar<ButtonRepeatConfig>,
1554 buttons: ArcVar<Vec<MouseButton>>,
1555 hovered: ArcVar<Option<InteractionPath>>,
1556 position: ArcVar<Option<MousePosition>>,
1557}