1use std::{collections::HashMap, mem, num::NonZeroU32, ops, time::Duration};
6use zng_app::{
7 APP, AppExtension, DInstant,
8 event::{AnyEventArgs, EventPropagationHandle, event, event_args},
9 shortcut::ModifiersState,
10 timer::{DeadlineVar, TIMERS},
11 update::EventUpdate,
12 view_process::{
13 VIEW_PROCESS_INITED_EVENT,
14 raw_device_events::InputDeviceId,
15 raw_events::{RAW_FRAME_RENDERED_EVENT, RAW_MOUSE_LEFT_EVENT, RAW_TOUCH_CONFIG_CHANGED_EVENT, RAW_TOUCH_EVENT, RawTouchArgs},
16 },
17 widget::{
18 WIDGET, WidgetId,
19 info::{HitTestInfo, InteractionPath, WIDGET_INFO_CHANGED_EVENT},
20 },
21 window::WindowId,
22};
23
24use zng_app_context::app_local;
25use zng_ext_window::{NestedWindowWidgetInfoExt as _, WINDOWS};
26use zng_layout::unit::{
27 AngleRadian, Dip, DipPoint, DipToPx, DipVector, Factor, Px, PxPoint, PxToDip, PxTransform, PxVector, TimeUnits, euclid,
28};
29use zng_var::{Var, impl_from_and_into_var, var};
30pub use zng_view_api::{
31 config::TouchConfig,
32 touch::{TouchForce, TouchId, TouchPhase, TouchUpdate},
33};
34
35use crate::{
36 keyboard::MODIFIERS_CHANGED_EVENT,
37 pointer_capture::{CaptureInfo, POINTER_CAPTURE, POINTER_CAPTURE_EVENT},
38};
39
40#[derive(Default)]
59pub struct TouchManager {
60 modifiers: ModifiersState,
61 pressed: HashMap<TouchId, PressedInfo>,
62 tap_gesture: TapGesture,
63 transform_gesture: TransformGesture,
64 long_press_gesture: LongPressGesture,
65 mouse_touch: Option<TouchId>,
66}
67struct PressedInfo {
68 touch_propagation: EventPropagationHandle,
69 target: InteractionPath,
70 device_id: InputDeviceId,
71 position: DipPoint,
72 force: Option<TouchForce>,
73 hits: HitTestInfo,
74 velocity_samples: Vec<(DInstant, DipPoint)>,
75}
76impl PressedInfo {
77 fn push_velocity_sample(&mut self, timestamp: DInstant, position: DipPoint) {
78 if let Some(last) = self.velocity_samples.last_mut()
79 && timestamp.duration_since(last.0) < 1.ms()
80 {
81 last.1 = position;
82 return;
83 }
84
85 if self.velocity_samples.len() == 4 {
86 self.velocity_samples.remove(0);
87 }
88 self.velocity_samples.push((timestamp, position));
89 }
90
91 fn velocity(&self) -> DipVector {
92 if self.velocity_samples.len() < 4 {
93 DipVector::zero()
94 } else {
95 let samples = [
96 self.velocity_samples[0].1.cast::<f64>(),
97 self.velocity_samples[1].1.cast(),
98 self.velocity_samples[2].1.cast(),
99 self.velocity_samples[3].1.cast(),
100 ];
101 let velocity_at = |end_i: usize| {
102 let start_i = end_i - 1;
103
104 let start_t = self.velocity_samples[start_i].0;
105 let end_t = self.velocity_samples[end_i].0;
106
107 let start_s = samples[start_i];
108 let end_s = samples[end_i];
109
110 let delta = (end_t - start_t).as_secs_f64();
111
112 if delta > 0.0 {
113 (end_s - start_s) / delta
114 } else {
115 euclid::vec2(0.0, 0.0)
116 }
117 };
118
119 let v23 = velocity_at(3) * 0.6;
120 let v12 = velocity_at(2) * 0.35;
121 let v01 = velocity_at(1) * 0.05;
122 let v = v23 + v12 + v01;
123
124 v.cast::<f32>().cast()
125 }
126 }
127}
128
129pub struct TOUCH;
141
142impl TOUCH {
143 pub fn touch_config(&self) -> Var<TouchConfig> {
149 TOUCH_SV.read().touch_config.clone()
150 }
151
152 pub fn sys_touch_config(&self) -> Var<TouchConfig> {
164 TOUCH_SV.read().sys_touch_config.read_only()
165 }
166
167 pub fn positions(&self) -> Var<Vec<TouchPosition>> {
169 TOUCH_SV.read().positions.read_only()
170 }
171
172 pub fn touch_from_mouse_events(&self) -> Var<bool> {
176 TOUCH_SV.read().touch_from_mouse_events.clone()
177 }
178}
179
180#[derive(Debug, Clone, PartialEq)]
186pub struct TouchPosition {
187 pub window_id: WindowId,
189 pub touch: TouchId,
191 pub position: DipPoint,
193
194 pub start_time: DInstant,
196 pub update_time: DInstant,
198}
199
200app_local! {
201 static TOUCH_SV: TouchService = {
202 APP.extensions().require::<TouchManager>();
203 let sys_touch_config = var(TouchConfig::default());
204 TouchService {
205 touch_config: sys_touch_config.cow(),
206 sys_touch_config,
207 positions: var(vec![]),
208 touch_from_mouse_events: var(false),
209 }
210 };
211}
212struct TouchService {
213 touch_config: Var<TouchConfig>,
214 sys_touch_config: Var<TouchConfig>,
215 positions: Var<Vec<TouchPosition>>,
216 touch_from_mouse_events: Var<bool>,
217}
218
219#[derive(Debug, Clone)]
221pub struct TouchMove {
222 pub touch: TouchId,
228
229 pub touch_propagation: EventPropagationHandle,
233
234 pub moves: Vec<(DipPoint, Option<TouchForce>)>,
238
239 pub velocity: DipVector,
243
244 pub hits: HitTestInfo,
246
247 pub target: InteractionPath,
249}
250impl TouchMove {
251 pub fn position(&self) -> DipPoint {
253 self.moves.last().map(|(p, _)| *p).unwrap_or_else(DipPoint::zero)
254 }
255}
256
257event_args! {
258 pub struct TouchMoveArgs {
260 pub window_id: WindowId,
262
263 pub device_id: InputDeviceId,
265
266 pub touches: Vec<TouchMove>,
271
272 pub capture: Option<CaptureInfo>,
274
275 pub modifiers: ModifiersState,
277
278 ..
279
280 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
284 for t in &self.touches {
285 list.insert_wgt(&t.target);
286 }
287 if let Some(c) = &self.capture {
288 list.insert_wgt(&c.target);
289 }
290 }
291 }
292
293 pub struct TouchInputArgs {
295 pub window_id: WindowId,
297
298 pub device_id: InputDeviceId,
300
301 pub touch: TouchId,
307
308 pub touch_propagation: EventPropagationHandle,
325
326 pub position: DipPoint,
328
329 pub force: Option<TouchForce>,
331
332 pub velocity: DipVector,
339
340 pub phase: TouchPhase,
344
345 pub hits: HitTestInfo,
347
348 pub target: InteractionPath,
350
351 pub capture: Option<CaptureInfo>,
353
354 pub modifiers: ModifiersState,
356
357 ..
358
359 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
364 list.insert_wgt(&self.target);
365 if let Some(c) = &self.capture {
366 list.insert_wgt(&c.target);
367 }
368 }
369 }
370
371 pub struct TouchedArgs {
373 pub window_id: WindowId,
375
376 pub device_id: Option<InputDeviceId>,
378
379 pub touch: TouchId,
385
386 pub touch_propagation: EventPropagationHandle,
390
391 pub position: DipPoint,
393
394 pub force: Option<TouchForce>,
396
397 pub phase: TouchPhase,
399
400 pub hits: HitTestInfo,
402
403 pub prev_target: Option<InteractionPath>,
405
406 pub target: Option<InteractionPath>,
408
409 pub prev_capture: Option<CaptureInfo>,
411
412 pub capture: Option<CaptureInfo>,
414
415 ..
416
417 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
423 if let Some(p) = &self.prev_target {
424 list.insert_wgt(p);
425 }
426 if let Some(p) = &self.target {
427 list.insert_wgt(p);
428 }
429 if let Some(c) = &self.capture {
430 list.insert_wgt(&c.target);
431 }
432 }
433 }
434
435 pub struct TouchTapArgs {
437 pub window_id: WindowId,
439
440 pub device_id: InputDeviceId,
442
443 pub touch: TouchId,
449
450 pub position: DipPoint,
452
453 pub hits: HitTestInfo,
455
456 pub target: InteractionPath,
458
459 pub modifiers: ModifiersState,
461
462 pub tap_count: NonZeroU32,
464
465 ..
466
467 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
471 list.insert_wgt(&self.target);
472 }
473 }
474
475 pub struct TouchLongPressArgs {
477 pub window_id: WindowId,
479
480 pub device_id: InputDeviceId,
482
483 pub touch: TouchId,
489
490 pub position: DipPoint,
492
493 pub hits: HitTestInfo,
495
496 pub target: InteractionPath,
498
499 pub modifiers: ModifiersState,
501
502 pub start_time: DInstant,
504
505 ..
506
507 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
511 list.insert_wgt(&self.target);
512 }
513 }
514
515 pub struct TouchTransformArgs {
517 pub window_id: WindowId,
519
520 pub device_id: InputDeviceId,
522
523 pub first_info: TouchTransformInfo,
525
526 pub latest_info: TouchTransformInfo,
528
529 pub velocity: [PxVector; 2],
531
532 pub scale_factor: Factor,
536
537 pub phase: TouchPhase,
539
540 pub hits: HitTestInfo,
543
544 pub target: InteractionPath,
546
547 pub capture: Option<CaptureInfo>,
549
550 pub modifiers: ModifiersState,
552
553 ..
554
555 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
560 list.insert_wgt(&self.target);
561 if let Some(c) = &self.capture {
562 list.insert_wgt(&c.target);
563 }
564 }
565 }
566}
567
568impl TouchMoveArgs {
569 pub fn capture_allows(&self) -> bool {
575 self.capture.as_ref().map(|c| c.allows()).unwrap_or(true)
576 }
577}
578
579impl TouchInputArgs {
580 pub fn capture_allows(&self) -> bool {
586 self.capture.as_ref().map(|c| c.allows()).unwrap_or(true)
587 }
588
589 pub fn is_touch_start(&self) -> bool {
593 matches!(self.phase, TouchPhase::Start)
594 }
595
596 pub fn is_touch_end(&self) -> bool {
600 matches!(self.phase, TouchPhase::End)
601 }
602
603 pub fn is_touch_cancel(&self) -> bool {
607 matches!(self.phase, TouchPhase::Cancel)
608 }
609
610 pub fn inertia_x(&self, friction: Dip) -> (Dip, Duration) {
623 Self::inertia(self.velocity.x, friction)
624 }
625
626 pub fn inertia_y(&self, friction: Dip) -> (Dip, Duration) {
634 Self::inertia(self.velocity.y, friction)
635 }
636
637 fn inertia(velocity: Dip, friction: Dip) -> (Dip, Duration) {
638 let cfg = TOUCH.touch_config().get();
639 let signal = if velocity >= 0 { 1.0 } else { -1.0 };
640 let velocity = velocity.abs();
641
642 if velocity < cfg.min_fling_velocity {
643 (Dip::new(0), Duration::ZERO)
644 } else {
645 let velocity = velocity.min(cfg.max_fling_velocity).to_f32();
646 let friction = friction.to_f32();
647
648 let time = velocity / friction;
649 let offset = (velocity * time) - (friction * time);
650
651 (Dip::from(offset) * signal, time.secs())
652 }
653 }
654
655 pub fn position_wgt(&self) -> Option<PxPoint> {
657 WIDGET.win_point_to_wgt(self.position)
658 }
659}
660
661impl TouchedArgs {
662 pub fn capture_allows(&self) -> bool {
668 self.capture.as_ref().map(|c| c.allows()).unwrap_or(true)
669 }
670
671 pub fn is_touch_move(&self) -> bool {
673 self.device_id.is_some()
674 }
675
676 pub fn is_widget_move(&self) -> bool {
678 self.device_id.is_none()
679 }
680
681 pub fn is_capture_change(&self) -> bool {
683 self.prev_capture != self.capture
684 }
685
686 pub fn is_touch_enter(&self) -> bool {
690 !self.was_touched() && self.is_touched()
691 }
692
693 pub fn is_touch_leave(&self) -> bool {
697 self.was_touched() && !self.is_touched()
698 }
699
700 pub fn is_touch_enter_enabled(&self) -> bool {
704 (!self.was_touched() || self.was_disabled(WIDGET.id())) && self.is_touched() && self.is_enabled(WIDGET.id())
705 }
706
707 pub fn is_touch_leave_enabled(&self) -> bool {
711 self.was_touched() && self.was_enabled(WIDGET.id()) && (!self.is_touched() || self.is_disabled(WIDGET.id()))
712 }
713
714 pub fn is_touch_enter_disabled(&self) -> bool {
718 (!self.was_touched() || self.was_enabled(WIDGET.id())) && self.is_touched() && self.is_disabled(WIDGET.id())
719 }
720
721 pub fn is_touch_leave_disabled(&self) -> bool {
725 self.was_touched() && self.was_disabled(WIDGET.id()) && (!self.is_touched() || self.is_enabled(WIDGET.id()))
726 }
727
728 pub fn was_touched(&self) -> bool {
734 if let Some(cap) = &self.prev_capture
735 && !cap.allows()
736 {
737 return false;
738 }
739
740 if let Some(t) = &self.prev_target {
741 return t.contains(WIDGET.id());
742 }
743
744 false
745 }
746
747 pub fn is_touched(&self) -> bool {
753 if let Some(cap) = &self.capture
754 && !cap.allows()
755 {
756 return false;
757 }
758
759 if let Some(t) = &self.target {
760 return t.contains(WIDGET.id());
761 }
762
763 false
764 }
765 pub fn was_enabled(&self, widget_id: WidgetId) -> bool {
769 match &self.prev_target {
770 Some(t) => t.contains_enabled(widget_id),
771 None => false,
772 }
773 }
774
775 pub fn was_disabled(&self, widget_id: WidgetId) -> bool {
779 match &self.prev_target {
780 Some(t) => t.contains_disabled(widget_id),
781 None => false,
782 }
783 }
784
785 pub fn is_enabled(&self, widget_id: WidgetId) -> bool {
789 match &self.target {
790 Some(t) => t.contains_enabled(widget_id),
791 None => false,
792 }
793 }
794
795 pub fn is_disabled(&self, widget_id: WidgetId) -> bool {
799 match &self.target {
800 Some(t) => t.contains_disabled(widget_id),
801 None => false,
802 }
803 }
804}
805
806impl TouchTransformArgs {
807 pub fn capture_allows(&self) -> bool {
813 self.capture.as_ref().map(|c| c.allows()).unwrap_or(true)
814 }
815
816 pub fn local_info(&self) -> [TouchTransformInfo; 2] {
822 let mut first = self.first_info.clone();
823 let mut latest = self.latest_info.clone();
824
825 let offset = WIDGET.bounds().inner_offset();
826
827 first -= offset;
828 latest -= offset;
829
830 [first, latest]
831 }
832
833 pub fn translation(&self) -> euclid::Vector2D<f32, Px> {
838 self.first_info.translation(&self.latest_info)
839 }
840
841 pub fn translation_x(&self) -> f32 {
846 self.first_info.translation_x(&self.latest_info)
847 }
848
849 pub fn translation_y(&self) -> f32 {
854 self.first_info.translation_y(&self.latest_info)
855 }
856
857 pub fn rotation(&self) -> AngleRadian {
862 self.first_info.rotation(&self.latest_info)
863 }
864
865 pub fn scale(&self) -> Factor {
870 self.first_info.scale(&self.latest_info)
871 }
872
873 pub fn scale_x(&self) -> Factor {
878 self.first_info.scale_x(&self.latest_info)
879 }
880
881 pub fn scale_y(&self) -> Factor {
886 self.first_info.scale_y(&self.latest_info)
887 }
888
889 pub fn transform(&self, mode: TouchTransformMode) -> PxTransform {
894 self.first_info.transform(&self.latest_info, mode)
895 }
896
897 pub fn local_transform(&self, mode: TouchTransformMode) -> PxTransform {
901 let [first, latest] = self.local_info();
902
903 let mut r = first.transform(&latest, mode);
904
905 if mode.contains(TouchTransformMode::ROTATE)
906 || mode.contains(TouchTransformMode::SCALE_X)
907 || mode.contains(TouchTransformMode::SCALE_Y)
908 {
909 let c = latest.center.to_vector();
910 r = PxTransform::Offset(-c).then(&r).then_translate(c);
911 }
912
913 r
914 }
915
916 pub fn translation_velocity(&self) -> PxVector {
918 (self.velocity[0] + self.velocity[1]) / Px(2)
919 }
920
921 pub fn translation_inertia_x(&self, deceleration: Dip) -> (Px, Duration) {
930 self.inertia((self.velocity[0].x + self.velocity[1].x) / Px(2), deceleration)
931 }
932
933 pub fn translation_inertia_y(&self, deceleration: Dip) -> (Px, Duration) {
942 self.inertia((self.velocity[0].y + self.velocity[1].y) / Px(2), deceleration)
943 }
944
945 pub fn is_start(&self) -> bool {
954 matches!(self.phase, TouchPhase::Start)
955 }
956
957 pub fn is_end(&self) -> bool {
963 matches!(self.phase, TouchPhase::End)
964 }
965
966 pub fn is_cancel(&self) -> bool {
972 matches!(self.phase, TouchPhase::Cancel)
973 }
974
975 fn inertia(&self, velocity: Px, deceleration: Dip) -> (Px, Duration) {
976 let friction = deceleration.to_px(self.scale_factor);
977 let cfg = TOUCH.touch_config().get();
978 let min_fling_velocity = cfg.min_fling_velocity.to_px(self.scale_factor);
979
980 let signal = if velocity >= 0 { 1.0 } else { -1.0 };
981 let velocity = velocity.abs();
982
983 if velocity < min_fling_velocity {
984 (Px(0), Duration::ZERO)
985 } else {
986 let max_fling_velocity = cfg.max_fling_velocity.to_px(self.scale_factor);
987 let velocity = velocity.min(max_fling_velocity).0 as f32;
988 let friction = friction.0 as f32;
989
990 let time = velocity / friction;
991 let offset = 0.5 * friction * time * time;
992 (Px(offset.round() as _) * signal, time.secs())
993 }
994 }
995}
996
997event! {
998 pub static TOUCH_MOVE_EVENT: TouchMoveArgs;
1000
1001 pub static TOUCH_INPUT_EVENT: TouchInputArgs;
1003
1004 pub static TOUCHED_EVENT: TouchedArgs;
1006
1007 pub static TOUCH_TAP_EVENT: TouchTapArgs;
1012
1013 pub static TOUCH_TRANSFORM_EVENT: TouchTransformArgs;
1018
1019 pub static TOUCH_LONG_PRESS_EVENT: TouchLongPressArgs;
1026}
1027
1028impl AppExtension for TouchManager {
1029 fn event_preview(&mut self, update: &mut EventUpdate) {
1030 if let Some(args) = RAW_FRAME_RENDERED_EVENT.on(update) {
1031 self.continue_pressed(args.window_id);
1032 } else if let Some(args) = RAW_TOUCH_EVENT.on(update) {
1033 let mut pending_move: Vec<TouchMove> = vec![];
1034
1035 for u in &args.touches {
1036 if let TouchPhase::Move = u.phase {
1037 if let Some(e) = pending_move.iter_mut().find(|e| e.touch == u.touch) {
1038 e.moves.push((u.position, u.force));
1039 } else {
1040 pending_move.push(TouchMove {
1041 touch: u.touch,
1042 touch_propagation: if let Some(i) = self.pressed.get(&u.touch) {
1043 i.touch_propagation.clone()
1044 } else {
1045 let weird = EventPropagationHandle::new();
1046 weird.stop();
1047 weird
1048 },
1049 moves: vec![(u.position, u.force)],
1050 velocity: DipVector::zero(),
1051 hits: HitTestInfo::no_hits(args.window_id), target: InteractionPath::new(args.window_id, []),
1053 });
1054 }
1055 } else {
1056 self.on_move(args, mem::take(&mut pending_move));
1057 self.on_input(args, u);
1058 }
1059 }
1060
1061 self.on_move(args, pending_move);
1062 } else if let Some(args) = WIDGET_INFO_CHANGED_EVENT.on(update) {
1063 self.continue_pressed(args.window_id);
1064 } else if let Some(args) = MODIFIERS_CHANGED_EVENT.on(update) {
1065 self.modifiers = args.modifiers;
1066 } else if let Some(args) = RAW_TOUCH_CONFIG_CHANGED_EVENT.on(update) {
1067 TOUCH_SV.read().touch_config.set(args.config);
1068 } else if let Some(args) = VIEW_PROCESS_INITED_EVENT.on(update) {
1069 if args.is_respawn {
1070 self.tap_gesture.clear();
1071 self.transform_gesture.clear();
1072 self.long_press_gesture.clear();
1073 TOUCH_SV.read().positions.set(vec![]);
1074
1075 for (touch, info) in self.pressed.drain() {
1076 let args = TouchInputArgs::now(
1077 info.target.window_id(),
1078 info.device_id,
1079 touch,
1080 info.touch_propagation.clone(),
1081 DipPoint::splat(Dip::new(-1)),
1082 None,
1083 DipVector::zero(),
1084 TouchPhase::Cancel,
1085 HitTestInfo::no_hits(info.target.window_id()),
1086 info.target.clone(),
1087 None,
1088 ModifiersState::empty(),
1089 );
1090 TOUCH_INPUT_EVENT.notify(args);
1091
1092 let args = TouchedArgs::now(
1093 info.target.window_id(),
1094 info.device_id,
1095 touch,
1096 info.touch_propagation,
1097 DipPoint::splat(Dip::new(-1)),
1098 None,
1099 TouchPhase::Cancel,
1100 HitTestInfo::no_hits(info.target.window_id()),
1101 info.target,
1102 None,
1103 None,
1104 None,
1105 );
1106 TOUCHED_EVENT.notify(args);
1107 }
1108 }
1109 } else if TOUCH_SV.read().touch_from_mouse_events.get() {
1110 use super::mouse::*;
1111
1112 if let Some(args) = MOUSE_MOVE_EVENT.on(update) {
1113 if let Some(id) = self.mouse_touch {
1114 args.propagation().stop();
1115
1116 RAW_TOUCH_EVENT.notify(RawTouchArgs::now(
1117 args.window_id,
1118 args.device_id,
1119 vec![TouchUpdate::new(id, TouchPhase::Move, args.position, None)],
1120 ));
1121 }
1122 } else if let Some(args) = MOUSE_INPUT_EVENT.on(update) {
1123 if args.button == super::mouse::MouseButton::Left {
1124 args.propagation().stop();
1125
1126 let phase = match args.state {
1127 ButtonState::Pressed => {
1128 if self.mouse_touch.is_some() {
1129 return;
1130 }
1131 self.mouse_touch = Some(TouchId(u64::MAX));
1132 TouchPhase::Start
1133 }
1134 ButtonState::Released => {
1135 if self.mouse_touch.is_none() {
1136 return;
1137 }
1138 self.mouse_touch = None;
1139 TouchPhase::End
1140 }
1141 };
1142
1143 RAW_TOUCH_EVENT.notify(RawTouchArgs::now(
1144 args.window_id,
1145 args.device_id.unwrap_or(InputDeviceId::new_unique()),
1146 vec![TouchUpdate::new(TouchId(u64::MAX), phase, args.position, None)],
1147 ));
1148 }
1149 } else if let Some(args) = RAW_MOUSE_LEFT_EVENT.on(update)
1150 && let Some(id) = self.mouse_touch.take()
1151 {
1152 RAW_TOUCH_EVENT.notify(RawTouchArgs::now(
1153 args.window_id,
1154 args.device_id,
1155 vec![TouchUpdate::new(id, TouchPhase::Cancel, DipPoint::zero(), None)],
1156 ))
1157 }
1158 }
1159 }
1160
1161 fn event(&mut self, update: &mut EventUpdate) {
1162 if let Some(args) = TOUCH_INPUT_EVENT.on(update) {
1163 self.tap_gesture.on_input(args);
1164 self.transform_gesture.on_input(args);
1165 self.long_press_gesture.on_input(args);
1166 } else if let Some(args) = TOUCH_MOVE_EVENT.on(update) {
1167 self.tap_gesture.on_move(args);
1168 self.transform_gesture.on_move(args);
1169 self.long_press_gesture.on_move(args);
1170 } else if let Some(args) = POINTER_CAPTURE_EVENT.on(update) {
1171 for (touch, info) in &self.pressed {
1172 let args = TouchedArgs::now(
1173 info.target.window_id(),
1174 info.device_id,
1175 *touch,
1176 info.touch_propagation.clone(),
1177 info.position,
1178 info.force,
1179 TouchPhase::Move,
1180 info.hits.clone(),
1181 info.target.clone(),
1182 info.target.clone(),
1183 args.prev_capture.clone(),
1184 args.new_capture.clone(),
1185 );
1186 TOUCHED_EVENT.notify(args);
1187 }
1188 }
1189 }
1190
1191 fn update_preview(&mut self) {
1192 self.long_press_gesture.on_update();
1193 }
1194}
1195impl TouchManager {
1196 fn on_input(&mut self, args: &RawTouchArgs, update: &TouchUpdate) {
1197 if let Ok(w) = WINDOWS.widget_tree(args.window_id) {
1198 let mut hits = w.root().hit_test(update.position.to_px(w.scale_factor()));
1199 let mut target = hits
1200 .target()
1201 .and_then(|t| w.get(t.widget_id))
1202 .map(|t| t.interaction_path())
1203 .unwrap_or_else(|| w.root().interaction_path());
1204 let mut position = update.position;
1205
1206 if let Some(wgt) = w.get(target.widget_id())
1208 && let Some(w) = wgt.nested_window_tree()
1209 {
1210 let f = w.scale_factor();
1211 let p = update.position.to_px(f);
1212 let p = wgt.inner_transform().inverse().and_then(|t| t.transform_point(p)).unwrap_or(p);
1213 position = p.to_dip(f);
1214 hits = w.root().hit_test(p);
1215 target = hits
1216 .target()
1217 .and_then(|t| w.get(t.widget_id))
1218 .map(|t| t.interaction_path())
1219 .unwrap_or_else(|| w.root().interaction_path());
1220 }
1221
1222 let target = match target.unblocked() {
1223 Some(t) => t,
1224 None => return, };
1226
1227 let capture_info = POINTER_CAPTURE.current_capture_value();
1228
1229 let (gesture_handle, velocity) = match update.phase {
1230 TouchPhase::Start => {
1231 let handle = EventPropagationHandle::new();
1232 if let Some(weird) = self.pressed.insert(
1233 update.touch,
1234 PressedInfo {
1235 touch_propagation: handle.clone(),
1236 target: target.clone(),
1237 device_id: args.device_id,
1238 position,
1239 force: update.force,
1240 hits: hits.clone(),
1241 velocity_samples: vec![], },
1243 ) {
1244 weird.touch_propagation.stop();
1245 }
1246 (handle, DipVector::zero())
1247 }
1248 TouchPhase::End => {
1249 if let Some(handle) = self.pressed.remove(&update.touch) {
1250 let vel = handle.velocity();
1251 (handle.touch_propagation, vel)
1252 } else {
1253 let weird = EventPropagationHandle::new();
1254 weird.stop();
1255 (weird, DipVector::zero())
1256 }
1257 }
1258 TouchPhase::Cancel => {
1259 let handle = self.pressed.remove(&update.touch).map(|i| i.touch_propagation).unwrap_or_default();
1260 handle.stop();
1261 (handle, DipVector::zero())
1262 }
1263 TouchPhase::Move => unreachable!(),
1264 };
1265
1266 match update.phase {
1267 TouchPhase::Start => {
1268 let pos_info = TouchPosition {
1269 window_id: hits.window_id(),
1270 touch: update.touch,
1271 position,
1272 start_time: args.timestamp,
1273 update_time: args.timestamp,
1274 };
1275 TOUCH_SV.read().positions.modify(move |p| {
1276 let p = &mut **p;
1277 if let Some(weird) = p.iter().position(|p| p.touch == pos_info.touch) {
1278 p.remove(weird);
1279 }
1280 p.push(pos_info);
1281 });
1282 }
1283 _ => {
1284 let touch = update.touch;
1285 TOUCH_SV.read().positions.modify(move |p| {
1286 if let Some(i) = p.iter().position(|p| p.touch == touch) {
1287 p.remove(i);
1288 }
1289 });
1290 }
1291 }
1292
1293 let args = TouchInputArgs::now(
1294 hits.window_id(),
1295 args.device_id,
1296 update.touch,
1297 gesture_handle,
1298 position,
1299 update.force,
1300 velocity,
1301 update.phase,
1302 hits,
1303 target,
1304 capture_info,
1305 self.modifiers,
1306 );
1307
1308 let touched_args = {
1309 let (prev_target, target) = match args.phase {
1312 TouchPhase::Start => (None, Some(args.target.clone())),
1313 TouchPhase::End | TouchPhase::Cancel => (Some(args.target.clone()), None),
1314 TouchPhase::Move => unreachable!(),
1315 };
1316
1317 TouchedArgs::now(
1318 args.window_id,
1319 args.device_id,
1320 args.touch,
1321 args.touch_propagation.clone(),
1322 args.position,
1323 args.force,
1324 args.phase,
1325 args.hits.clone(),
1326 prev_target,
1327 target,
1328 args.capture.clone(),
1329 args.capture.clone(),
1330 )
1331 };
1332
1333 TOUCH_INPUT_EVENT.notify(args);
1334 TOUCHED_EVENT.notify(touched_args);
1335 } else {
1336 for u in &args.touches {
1338 if let Some(i) = self.pressed.remove(&u.touch) {
1339 let capture = POINTER_CAPTURE.current_capture_value();
1340 let args = TouchedArgs::now(
1341 args.window_id,
1342 args.device_id,
1343 u.touch,
1344 i.touch_propagation,
1345 u.position,
1346 u.force,
1347 u.phase,
1348 HitTestInfo::no_hits(args.window_id),
1349 Some(i.target),
1350 None,
1351 capture.clone(),
1352 capture,
1353 );
1354 TOUCHED_EVENT.notify(args);
1355 }
1356 }
1357 }
1358 }
1359
1360 fn on_move(&mut self, args: &RawTouchArgs, mut moves: Vec<TouchMove>) {
1361 if !moves.is_empty()
1362 && let Ok(w) = WINDOWS.widget_tree(args.window_id)
1363 {
1364 let mut window_blocked_remove = vec![];
1365 for m in &mut moves {
1366 m.hits = w.root().hit_test(m.position().to_px(w.scale_factor()));
1367 let target = m
1368 .hits
1369 .target()
1370 .and_then(|t| w.get(t.widget_id))
1371 .map(|t| t.interaction_path())
1372 .unwrap_or_else(|| w.root().interaction_path());
1373
1374 match target.unblocked() {
1375 Some(t) => {
1376 m.target = t;
1377 if let Some(wgt) = w.get(m.target.widget_id())
1379 && let Some(w) = wgt.nested_window_tree()
1380 {
1381 let transform = wgt.inner_transform().inverse();
1382 let factor = w.scale_factor();
1383 let mut position = PxPoint::zero(); for (mv, _) in &mut m.moves {
1385 let p = mv.to_px(factor);
1386 let p = transform.and_then(|t| t.transform_point(p)).unwrap_or(p);
1387 *mv = p.to_dip(factor);
1388 position = p;
1389 }
1390 m.hits = w.root().hit_test(position);
1391 let target = m
1392 .hits
1393 .target()
1394 .and_then(|t| w.get(t.widget_id))
1395 .map(|t| t.interaction_path())
1396 .unwrap_or_else(|| w.root().interaction_path());
1397
1398 match target.unblocked() {
1399 Some(t) => m.target = t,
1400 None => window_blocked_remove.push(m.touch),
1401 }
1402 }
1403 }
1404 None => {
1405 window_blocked_remove.push(m.touch);
1406 }
1407 }
1408 }
1409
1410 let position_updates: Vec<_> = moves
1411 .iter()
1412 .map(|m| TouchPosition {
1413 window_id: args.window_id,
1414 touch: m.touch,
1415 position: m.position(),
1416 start_time: args.timestamp, update_time: args.timestamp,
1418 })
1419 .collect();
1420 TOUCH_SV.read().positions.modify(move |p| {
1421 for mut update in position_updates {
1422 if let Some(i) = p.iter().position(|p| p.touch == update.touch) {
1423 update.start_time = p[i].start_time;
1424 p[i] = update;
1425 }
1426 }
1427 });
1428
1429 let capture_info = POINTER_CAPTURE.current_capture_value();
1430
1431 let mut touched_events = vec![];
1432
1433 for touch in window_blocked_remove {
1434 let touch_move = moves.iter().position(|t| t.touch == touch).unwrap();
1435 moves.swap_remove(touch_move);
1436
1437 if let Some(i) = self.pressed.remove(&touch) {
1438 i.touch_propagation.stop();
1439 let args = TouchedArgs::now(
1440 args.window_id,
1441 args.device_id,
1442 touch,
1443 i.touch_propagation,
1444 DipPoint::splat(Dip::new(-1)),
1445 None,
1446 TouchPhase::Cancel,
1447 HitTestInfo::no_hits(args.window_id),
1448 i.target,
1449 None,
1450 None,
1451 None,
1452 );
1453 touched_events.push(args);
1454 }
1455 }
1456 for m in &mut moves {
1457 if let Some(i) = self.pressed.get_mut(&m.touch) {
1458 let (position, force) = *m.moves.last().unwrap();
1459 i.push_velocity_sample(args.timestamp, position);
1460 m.velocity = i.velocity();
1461 i.position = position;
1462 i.force = force;
1463 i.hits = m.hits.clone();
1464 if i.target != m.target {
1465 let args = TouchedArgs::now(
1466 args.window_id,
1467 args.device_id,
1468 m.touch,
1469 m.touch_propagation.clone(),
1470 position,
1471 force,
1472 TouchPhase::Move,
1473 m.hits.clone(),
1474 i.target.clone(),
1475 m.target.clone(),
1476 capture_info.clone(),
1477 capture_info.clone(),
1478 );
1479 i.target = m.target.clone();
1480 touched_events.push(args);
1481 }
1482 }
1483 }
1484
1485 if !moves.is_empty() {
1486 let args = TouchMoveArgs::now(args.window_id, args.device_id, moves, capture_info, self.modifiers);
1487 TOUCH_MOVE_EVENT.notify(args);
1488 }
1489
1490 for args in touched_events {
1491 TOUCHED_EVENT.notify(args);
1492 }
1493 }
1494 }
1495
1496 fn continue_pressed(&mut self, window_id: WindowId) {
1497 let mut tree = None;
1498
1499 let mut window_blocked_remove = vec![];
1500
1501 for (touch, info) in &mut self.pressed {
1502 if info.target.window_id() != window_id {
1503 continue;
1504 }
1505
1506 let tree = tree.get_or_insert_with(|| WINDOWS.widget_tree(window_id).unwrap());
1507 info.hits = tree.root().hit_test(info.position.to_px(tree.scale_factor()));
1508
1509 let target = if let Some(t) = info.hits.target() {
1510 tree.get(t.widget_id).map(|w| w.interaction_path()).unwrap_or_else(|| {
1511 tracing::error!("hits target `{}` not found", t.widget_id);
1512 tree.root().interaction_path()
1513 })
1514 } else {
1515 tree.root().interaction_path()
1516 }
1517 .unblocked();
1518
1519 if let Some(target) = target {
1520 if info.target != target {
1521 let capture = POINTER_CAPTURE.current_capture_value();
1522 let prev = mem::replace(&mut info.target, target.clone());
1523
1524 let args = TouchedArgs::now(
1525 info.target.window_id(),
1526 None,
1527 *touch,
1528 info.touch_propagation.clone(),
1529 info.position,
1530 info.force,
1531 TouchPhase::Move,
1532 info.hits.clone(),
1533 prev,
1534 target,
1535 capture.clone(),
1536 capture,
1537 );
1538 TOUCHED_EVENT.notify(args);
1539 }
1540 } else {
1541 window_blocked_remove.push(*touch);
1542 }
1543 }
1544
1545 for touch in window_blocked_remove {
1546 if let Some(i) = self.pressed.remove(&touch) {
1547 i.touch_propagation.stop();
1548 let args = TouchedArgs::now(
1549 i.target.window_id(),
1550 None,
1551 touch,
1552 i.touch_propagation,
1553 DipPoint::splat(Dip::new(-1)),
1554 None,
1555 TouchPhase::Cancel,
1556 HitTestInfo::no_hits(i.target.window_id()),
1557 i.target,
1558 None,
1559 None,
1560 None,
1561 );
1562 TOUCHED_EVENT.notify(args);
1563 }
1564 }
1565 }
1566}
1567
1568struct PendingDoubleTap {
1569 window_id: WindowId,
1570 device_id: InputDeviceId,
1571 target: WidgetId,
1572 count: NonZeroU32,
1573 timestamp: DInstant,
1574}
1575struct PendingTap {
1576 window_id: WindowId,
1577 device_id: InputDeviceId,
1578 touch: TouchId,
1579 target: WidgetId,
1580
1581 propagation: EventPropagationHandle,
1582}
1583impl PendingTap {
1584 fn retain(&self, window_id: WindowId, device_id: InputDeviceId, touch: TouchId) -> bool {
1588 if self.propagation.is_stopped() {
1589 return false;
1591 }
1592
1593 if window_id != self.window_id || device_id != self.device_id {
1594 return false;
1596 }
1597
1598 if touch != self.touch {
1599 return false;
1601 }
1602
1603 true
1605 }
1606}
1607
1608struct PendingLongPress {
1609 window_id: WindowId,
1610 device_id: InputDeviceId,
1611 touch: TouchId,
1612 target: WidgetId,
1613 position: DipPoint,
1614 start_time: DInstant,
1615 modifiers: ModifiersState,
1616
1617 propagation: EventPropagationHandle,
1618
1619 delay: DeadlineVar,
1620 canceled: bool,
1621}
1622
1623#[derive(Default)]
1624struct LongPressGesture {
1625 pending: Option<PendingLongPress>,
1626}
1627impl LongPressGesture {
1628 fn on_input(&mut self, args: &TouchInputArgs) {
1629 match args.phase {
1630 TouchPhase::Start => {
1631 if let Some(p) = &mut self.pending {
1632 p.canceled = true;
1634 } else if TOUCH_LONG_PRESS_EVENT.has_hooks()
1635 || args.target.widgets_path().iter().any(|w| TOUCH_LONG_PRESS_EVENT.is_subscriber(*w))
1636 {
1637 self.pending = Some(PendingLongPress {
1638 window_id: args.window_id,
1639 device_id: args.device_id,
1640 touch: args.touch,
1641 position: args.position,
1642 start_time: args.timestamp,
1643 modifiers: args.modifiers,
1644 target: args.target.widget_id(),
1645 propagation: args.touch_propagation.clone(),
1646 delay: TIMERS.deadline(TOUCH.touch_config().get().tap_max_time),
1647 canceled: false,
1648 });
1649 }
1650 }
1651 TouchPhase::End | TouchPhase::Cancel => {
1652 if let Some(p) = &self.pending
1653 && args.touch_propagation == p.propagation
1654 {
1655 self.pending = None;
1656 }
1657 }
1658 TouchPhase::Move => unreachable!(),
1659 }
1660 }
1661
1662 fn on_move(&mut self, args: &TouchMoveArgs) {
1663 if let Some(p) = &mut self.pending
1664 && !p.canceled
1665 && !p.propagation.is_stopped()
1666 {
1667 for m in &args.touches {
1668 if p.propagation == m.touch_propagation {
1669 let dist = p.position - m.position().to_vector();
1670 let max = TOUCH.touch_config().get().tap_area;
1671 if dist.x.abs() > max.width || dist.y.abs() > max.height {
1672 p.canceled = true;
1673 break;
1674 }
1675 } else {
1676 p.canceled = true;
1677 break;
1678 }
1679 }
1680 }
1681 }
1682
1683 fn on_update(&mut self) {
1684 if let Some(p) = &mut self.pending
1685 && !p.canceled
1686 && !p.propagation.is_stopped()
1687 && p.delay.get().has_elapsed()
1688 {
1689 if let Ok(w) = WINDOWS.widget_tree(p.window_id)
1690 && let Some(w) = w.get(p.target)
1691 {
1692 let hits = w.hit_test(p.position.to_px(w.tree().scale_factor()));
1693 if hits.contains(p.target) {
1694 p.propagation.stop();
1695
1696 let args = TouchLongPressArgs::now(
1697 p.window_id,
1698 p.device_id,
1699 p.touch,
1700 p.position,
1701 hits,
1702 w.interaction_path(),
1703 p.modifiers,
1704 p.start_time,
1705 );
1706 TOUCH_LONG_PRESS_EVENT.notify(args);
1707 return;
1708 }
1709 }
1710 p.canceled = true;
1711 }
1712 }
1713
1714 fn clear(&mut self) {
1715 self.pending = None;
1716 }
1717}
1718
1719#[derive(Default)]
1720struct TapGesture {
1721 pending_double: Option<PendingDoubleTap>,
1722 pending: Option<PendingTap>,
1723}
1724impl TapGesture {
1725 fn on_input(&mut self, args: &TouchInputArgs) {
1726 match args.phase {
1727 TouchPhase::Start => {
1728 if self.pending.is_some() {
1729 self.pending = None;
1730 self.pending_double = None;
1731 } else if TOUCH_TAP_EVENT.has_hooks() || args.target.widgets_path().iter().any(|w| TOUCH_TAP_EVENT.is_subscriber(*w)) {
1732 self.pending = Some(PendingTap {
1733 window_id: args.window_id,
1734 device_id: args.device_id,
1735 touch: args.touch,
1736 target: args.target.widget_id(),
1737 propagation: args.touch_propagation.clone(),
1738 });
1739 }
1740 }
1741 TouchPhase::End => {
1742 let pending_double = self.pending_double.take();
1743
1744 if let Some(p) = self.pending.take() {
1745 if !p.retain(args.window_id, args.device_id, args.touch) {
1746 return;
1747 }
1748
1749 p.propagation.stop(); let tree = if let Ok(w) = WINDOWS.widget_tree(args.window_id) {
1752 w
1753 } else {
1754 return;
1755 };
1756
1757 match tree.get(p.target) {
1758 Some(t) => {
1759 if !t.hit_test(args.position.to_px(tree.scale_factor())).contains(p.target) {
1760 return;
1762 }
1763 }
1764 None => return,
1765 }
1766
1767 if let Some(target) = args.target.sub_path(p.target) {
1768 let tap_count = if let Some(double) = pending_double {
1769 let cfg = TOUCH.touch_config().get();
1770 if double.window_id == p.window_id
1771 && double.device_id == p.device_id
1772 && double.target == p.target
1773 && double.timestamp.elapsed() <= cfg.double_tap_max_time
1774 {
1775 NonZeroU32::new(double.count.get() + 1).unwrap()
1776 } else {
1777 NonZeroU32::new(1).unwrap()
1778 }
1779 } else {
1780 NonZeroU32::new(1).unwrap()
1781 };
1782
1783 self.pending_double = Some(PendingDoubleTap {
1784 window_id: args.window_id,
1785 device_id: args.device_id,
1786 target: p.target,
1787 count: tap_count,
1788 timestamp: args.timestamp,
1789 });
1790
1791 TOUCH_TAP_EVENT.notify(TouchTapArgs::new(
1792 args.timestamp,
1793 args.propagation().clone(),
1794 p.window_id,
1795 p.device_id,
1796 p.touch,
1797 args.position,
1798 args.hits.clone(),
1799 target.into_owned(),
1800 args.modifiers,
1801 tap_count,
1802 ));
1803 }
1804 }
1805 }
1806 TouchPhase::Cancel => {
1807 if let Some(p) = self.pending.take() {
1808 p.propagation.stop();
1809 }
1810 self.pending = None;
1811 self.pending_double = None;
1812 }
1813 TouchPhase::Move => unreachable!(),
1814 }
1815 }
1816
1817 fn on_move(&mut self, args: &TouchMoveArgs) {
1818 if let Some(p) = &self.pending {
1819 for t in &args.touches {
1820 if !p.retain(args.window_id, args.device_id, t.touch) {
1821 self.pending = None;
1822 self.pending_double = None;
1823 break;
1824 }
1825 }
1826 }
1827 }
1828
1829 fn clear(&mut self) {
1830 self.pending = None;
1831 self.pending_double = None;
1832 }
1833}
1834
1835#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
1837pub struct TouchTransformInfo {
1838 pub touches: [euclid::Point2D<f32, Px>; 2],
1840
1841 pub center: euclid::Point2D<f32, Px>,
1843
1844 pub deviation: f32,
1848
1849 pub deviation_x: f32,
1853
1854 pub deviation_y: f32,
1858
1859 pub angle: AngleRadian,
1861}
1862impl TouchTransformInfo {
1863 pub fn new_f32(touches: [euclid::Point2D<f32, Px>; 2]) -> Self {
1865 let a = touches[0].to_vector();
1866 let b = touches[1].to_vector();
1867
1868 let center = (a + b) / 2.0;
1869 let deviation = (a - center).length();
1870 let deviation_x = (a.x - center.x).abs();
1871 let deviation_y = (a.y - center.y).abs();
1872
1873 Self {
1874 touches,
1875 center: center.to_point(),
1876 deviation: deviation.max(1.0),
1877 deviation_x: deviation_x.max(1.0),
1878 deviation_y: deviation_y.max(1.0),
1879 angle: AngleRadian((a.y - b.y).atan2(a.x - b.x)),
1880 }
1881 }
1882
1883 pub fn new(touches: [PxPoint; 2]) -> Self {
1885 Self::new_f32([touches[0].to_f32(), touches[1].to_f32()])
1886 }
1887
1888 pub fn new_dip(touches: [DipPoint; 2], scale_factor: Factor) -> Self {
1890 Self::new_f32([touches[0].to_f32().to_px(scale_factor), touches[1].to_f32().to_px(scale_factor)])
1891 }
1892}
1893impl TouchTransformInfo {
1894 pub fn translation(&self, other: &Self) -> euclid::Vector2D<f32, Px> {
1896 other.center.to_vector() - self.center.to_vector()
1897 }
1898
1899 pub fn translation_x(&self, other: &Self) -> f32 {
1901 other.center.x - self.center.x
1902 }
1903
1904 pub fn translation_y(&self, other: &Self) -> f32 {
1906 other.center.y - self.center.y
1907 }
1908
1909 pub fn rotation(&self, other: &Self) -> AngleRadian {
1911 other.angle - self.angle
1912 }
1913
1914 pub fn scale(&self, other: &Self) -> Factor {
1916 Factor(other.deviation / self.deviation)
1917 }
1918
1919 pub fn scale_x(&self, other: &Self) -> Factor {
1921 Factor(other.deviation_x / self.deviation_x)
1922 }
1923
1924 pub fn scale_y(&self, other: &Self) -> Factor {
1926 Factor(other.deviation_y / self.deviation_y)
1927 }
1928
1929 pub fn transform(&self, other: &Self, mode: TouchTransformMode) -> PxTransform {
1931 let mut m = PxTransform::identity();
1932
1933 if mode.contains(TouchTransformMode::TRANSLATE) {
1934 m = m.then_translate(self.translation(other));
1935 } else if mode.contains(TouchTransformMode::TRANSLATE_X) {
1936 let t = euclid::vec2(self.translation_x(other), 0.0);
1937 m = m.then_translate(t);
1938 } else if mode.contains(TouchTransformMode::TRANSLATE_Y) {
1939 let t = euclid::vec2(0.0, self.translation_y(other));
1940 m = m.then_translate(t);
1941 }
1942
1943 if mode.contains(TouchTransformMode::SCALE) {
1944 let s = self.scale(other).0;
1945 m = m.then(&PxTransform::scale(s, s));
1946 } else if mode.contains(TouchTransformMode::SCALE_X) {
1947 let s = self.scale_x(other);
1948 m = m.then(&PxTransform::scale(s.0, 1.0))
1949 } else if mode.contains(TouchTransformMode::SCALE_Y) {
1950 let s = self.scale_y(other);
1951 m = m.then(&PxTransform::scale(1.0, s.0))
1952 }
1953
1954 if mode.contains(TouchTransformMode::ROTATE) {
1955 let a = self.rotation(other);
1956 m = m.then(&PxTransform::rotation(0.0, 0.0, a.into()));
1957 }
1958
1959 m
1960 }
1961
1962 pub fn is_single(&self) -> bool {
1964 self.touches[0] == self.touches[1]
1965 }
1966}
1967impl ops::AddAssign<euclid::Vector2D<f32, Px>> for TouchTransformInfo {
1968 fn add_assign(&mut self, rhs: euclid::Vector2D<f32, Px>) {
1969 self.touches[0] += rhs;
1970 self.touches[1] += rhs;
1971 self.center += rhs;
1972 }
1973}
1974impl ops::Add<euclid::Vector2D<f32, Px>> for TouchTransformInfo {
1975 type Output = Self;
1976
1977 fn add(mut self, rhs: euclid::Vector2D<f32, Px>) -> Self::Output {
1978 self += rhs;
1979 self
1980 }
1981}
1982impl ops::AddAssign<PxVector> for TouchTransformInfo {
1983 fn add_assign(&mut self, rhs: PxVector) {
1984 *self += rhs.cast::<f32>();
1985 }
1986}
1987impl ops::Add<PxVector> for TouchTransformInfo {
1988 type Output = Self;
1989
1990 fn add(mut self, rhs: PxVector) -> Self::Output {
1991 self += rhs;
1992 self
1993 }
1994}
1995impl ops::SubAssign<euclid::Vector2D<f32, Px>> for TouchTransformInfo {
1996 fn sub_assign(&mut self, rhs: euclid::Vector2D<f32, Px>) {
1997 self.touches[0] -= rhs;
1998 self.touches[1] -= rhs;
1999 self.center -= rhs;
2000 }
2001}
2002impl ops::Sub<euclid::Vector2D<f32, Px>> for TouchTransformInfo {
2003 type Output = Self;
2004
2005 fn sub(mut self, rhs: euclid::Vector2D<f32, Px>) -> Self::Output {
2006 self -= rhs;
2007 self
2008 }
2009}
2010impl ops::SubAssign<PxVector> for TouchTransformInfo {
2011 fn sub_assign(&mut self, rhs: PxVector) {
2012 *self -= rhs.cast::<f32>();
2013 }
2014}
2015impl ops::Sub<PxVector> for TouchTransformInfo {
2016 type Output = Self;
2017
2018 fn sub(mut self, rhs: PxVector) -> Self::Output {
2019 self -= rhs;
2020 self
2021 }
2022}
2023
2024bitflags! {
2025 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
2028 #[serde(transparent)]
2029 pub struct TouchTransformMode: u8 {
2030 const TRANSLATE_X = 0b0000_0001;
2032 const TRANSLATE_Y = 0b0000_0010;
2034 const TRANSLATE = Self::TRANSLATE_X.bits() | Self::TRANSLATE_Y.bits();
2036
2037 const SCALE_X = 0b0000_0100;
2039 const SCALE_Y = 0b0000_1000;
2041 const SCALE = 0b0001_1100;
2043
2044 const ROTATE = 0b0010_0000;
2046
2047 const ALL = Self::TRANSLATE.bits() | Self::SCALE.bits() | Self::ROTATE.bits();
2049 }
2050}
2051impl_from_and_into_var! {
2052 fn from(all_or_empty: bool) -> TouchTransformMode {
2053 if all_or_empty {
2054 TouchTransformMode::ALL
2055 } else {
2056 TouchTransformMode::empty()
2057 }
2058 }
2059}
2060
2061#[derive(Default)]
2062enum TransformGesture {
2063 #[default]
2064 NoStartedZero,
2065
2066 NotStartedOne {
2067 window_id: WindowId,
2068 device_id: InputDeviceId,
2069 start_position: DipPoint,
2070 position: DipPoint,
2071 handle: EventPropagationHandle,
2072 },
2073 NotStartedTwo {
2074 window_id: WindowId,
2075 device_id: InputDeviceId,
2076 start_position: [DipPoint; 2],
2077 position: [DipPoint; 2],
2078 handle: [EventPropagationHandle; 2],
2079 scale_factor: Factor,
2080 },
2081
2082 StartedOne {
2083 window_id: WindowId,
2084 device_id: InputDeviceId,
2085 position: DipPoint,
2086 velocity: DipVector,
2087 scale_factor: Factor,
2088 handle: EventPropagationHandle,
2089 first_info: TouchTransformInfo,
2090 hits: HitTestInfo,
2091 target: InteractionPath,
2092 },
2093 StartedTwo {
2094 window_id: WindowId,
2095 device_id: InputDeviceId,
2096 position: [DipPoint; 2],
2097 velocity: [DipVector; 2],
2098 scale_factor: Factor,
2099 handle: [EventPropagationHandle; 2],
2100 first_info: TouchTransformInfo,
2101 hits: HitTestInfo,
2102 target: InteractionPath,
2103 },
2104}
2105impl TransformGesture {
2106 fn on_input(&mut self, args: &TouchInputArgs) {
2107 match mem::take(self) {
2108 Self::NoStartedZero => {
2109 if TouchPhase::Start == args.phase
2110 && !args.touch_propagation.is_stopped()
2111 && (TOUCH_TRANSFORM_EVENT.has_hooks()
2112 || args.target.widgets_path().iter().any(|w| TOUCH_TRANSFORM_EVENT.is_subscriber(*w)))
2113 {
2114 *self = Self::NotStartedOne {
2115 window_id: args.window_id,
2116 device_id: args.device_id,
2117 start_position: args.position,
2118 position: args.position,
2119 handle: args.touch_propagation.clone(),
2120 }
2121 }
2122 }
2123 Self::NotStartedOne {
2124 window_id,
2125 device_id,
2126 position,
2127 handle,
2128 ..
2129 } => {
2130 if TouchPhase::Start == args.phase
2131 && window_id == args.window_id
2132 && device_id == args.device_id
2133 && !args.touch_propagation.is_stopped()
2134 && !handle.is_stopped()
2135 && handle != args.touch_propagation
2136 && let Ok(w) = WINDOWS.widget_tree(args.window_id)
2137 {
2138 *self = Self::NotStartedTwo {
2139 window_id: args.window_id,
2140 device_id: args.device_id,
2141 start_position: [position, args.position],
2142 position: [position, args.position],
2143 handle: [handle, args.touch_propagation.clone()],
2144 scale_factor: w.scale_factor(),
2145 }
2146 }
2147 }
2148 Self::NotStartedTwo { .. } => {
2149 }
2151 Self::StartedOne {
2152 window_id,
2153 device_id,
2154 position,
2155 velocity,
2156 scale_factor,
2157 handle,
2158 first_info,
2159 hits,
2160 target,
2161 } => match args.phase {
2162 TouchPhase::Start
2163 if window_id == args.window_id
2164 && device_id == args.device_id
2165 && !args.touch_propagation.is_stopped()
2166 && !handle.is_stopped()
2167 && handle != args.touch_propagation =>
2168 {
2169 *self = Self::StartedTwo {
2170 window_id,
2171 device_id,
2172 position: [position, args.position],
2173 velocity: [velocity, args.velocity],
2174 scale_factor,
2175 handle: [handle, args.touch_propagation.clone()],
2176 first_info,
2177 hits,
2178 target,
2179 };
2180 }
2181 TouchPhase::Move => unreachable!(),
2182 TouchPhase::End if handle == args.touch_propagation => {
2183 let position = args.position;
2184
2185 let latest_info = TouchTransformInfo::new_dip([position, position], scale_factor);
2186 let capture = POINTER_CAPTURE.current_capture_value();
2187
2188 let velocity = velocity.to_px(scale_factor);
2189
2190 let args = TouchTransformArgs::now(
2191 window_id,
2192 device_id,
2193 first_info,
2194 latest_info,
2195 [velocity, velocity],
2196 scale_factor,
2197 TouchPhase::End,
2198 hits,
2199 target,
2200 capture,
2201 args.modifiers,
2202 );
2203 TOUCH_TRANSFORM_EVENT.notify(args);
2204 }
2205 _ => {
2206 *self = Self::StartedOne {
2208 window_id,
2209 device_id,
2210 position,
2211 velocity,
2212 scale_factor,
2213 handle,
2214 first_info,
2215 hits,
2216 target,
2217 };
2218 self.clear();
2219 }
2220 },
2221 Self::StartedTwo {
2222 window_id,
2223 device_id,
2224 mut position,
2225 velocity,
2226 scale_factor,
2227 handle,
2228 first_info,
2229 hits,
2230 target,
2231 } => {
2232 if TouchPhase::End == args.phase && handle.iter().any(|h| h == &args.touch_propagation) {
2233 let i = handle.iter().position(|h| h == &args.touch_propagation).unwrap();
2234 position[i] = args.position;
2235
2236 let latest_info = TouchTransformInfo::new_dip(position, scale_factor);
2237 let capture = POINTER_CAPTURE.current_capture_value();
2238
2239 let velocity = [velocity[0].to_px(scale_factor), velocity[1].to_px(scale_factor)];
2240
2241 let args = TouchTransformArgs::now(
2242 window_id,
2243 device_id,
2244 first_info,
2245 latest_info,
2246 velocity,
2247 scale_factor,
2248 TouchPhase::End,
2249 hits,
2250 target,
2251 capture,
2252 args.modifiers,
2253 );
2254 TOUCH_TRANSFORM_EVENT.notify(args);
2255 } else {
2256 *self = Self::StartedTwo {
2257 window_id,
2258 device_id,
2259 position,
2260 velocity,
2261 scale_factor,
2262 handle,
2263 first_info,
2264 hits,
2265 target,
2266 };
2267 self.clear();
2268 }
2269 }
2270 }
2271 }
2272
2273 fn on_move(&mut self, args: &TouchMoveArgs) {
2274 match self {
2275 Self::NoStartedZero => {}
2276 Self::NotStartedOne {
2277 start_position,
2278 position,
2279 handle,
2280 window_id,
2281 device_id,
2282 } => {
2283 if handle.is_stopped() {
2284 *self = Self::NoStartedZero;
2285 } else {
2286 let mut moved = false;
2287 for t in &args.touches {
2288 if handle == &t.touch_propagation {
2289 *position = t.position();
2290 moved = true;
2291 } else {
2292 *self = Self::NoStartedZero;
2293 return;
2294 }
2295 }
2296 if moved {
2297 let cfg = TOUCH.touch_config().get();
2298 if (position.x - start_position.x).abs() > cfg.double_tap_area.width
2299 || (position.y - start_position.y).abs() > cfg.double_tap_area.height
2300 {
2301 if let Ok(w) = WINDOWS.widget_tree(*window_id) {
2302 let scale_factor = w.scale_factor();
2303 let first_info = TouchTransformInfo::new_dip([*start_position, *start_position], scale_factor);
2304 let latest_info = TouchTransformInfo::new_dip([*position, *position], scale_factor);
2305
2306 let hits = w.root().hit_test(first_info.center.cast());
2307 let target = hits
2308 .target()
2309 .and_then(|t| w.get(t.widget_id))
2310 .map(|t| t.interaction_path())
2311 .unwrap_or_else(|| w.root().interaction_path());
2312
2313 let target = match target.unblocked() {
2314 Some(t) => t,
2315 None => {
2316 *self = Self::NoStartedZero;
2317 return; }
2319 };
2320 let capture = POINTER_CAPTURE.current_capture_value();
2321
2322 handle.stop();
2324
2325 let args = TouchTransformArgs::now(
2326 *window_id,
2327 *device_id,
2328 first_info.clone(),
2329 latest_info,
2330 [PxVector::zero(); 2],
2331 scale_factor,
2332 TouchPhase::Start,
2333 hits.clone(),
2334 target.clone(),
2335 capture,
2336 args.modifiers,
2337 );
2338 TOUCH_TRANSFORM_EVENT.notify(args);
2339
2340 *self = Self::StartedOne {
2341 window_id: *window_id,
2342 device_id: *device_id,
2343 position: *position,
2344 velocity: DipVector::zero(),
2345 scale_factor,
2346 handle: handle.clone(),
2347 first_info,
2348 hits,
2349 target,
2350 };
2351 } else {
2352 *self = Self::NoStartedZero;
2353 }
2354 }
2355 }
2356 }
2357 }
2358 Self::NotStartedTwo {
2359 start_position,
2360 position,
2361 handle,
2362 scale_factor,
2363 window_id,
2364 device_id,
2365 } => {
2366 if handle[0].is_stopped() || handle[1].is_stopped() {
2367 *self = Self::NoStartedZero;
2368 } else {
2369 let mut any_moved = false;
2370 for t in &args.touches {
2371 if let Some(i) = handle.iter().position(|h| h == &t.touch_propagation) {
2372 position[i] = t.position();
2373 any_moved = true;
2374 } else {
2375 *self = Self::NoStartedZero;
2376 return;
2377 }
2378 }
2379
2380 if any_moved {
2381 let first_info = TouchTransformInfo::new_dip(*start_position, *scale_factor);
2382 let latest_info = TouchTransformInfo::new_dip(*position, *scale_factor);
2383
2384 let start = {
2385 let translation = first_info.translation(&latest_info);
2386 translation.x > 0.0 && translation.y > 0.0
2387 } || {
2388 let scale = first_info.scale(&latest_info);
2389 scale.0 != 1.0
2390 } || {
2391 let rotate = first_info.rotation(&latest_info);
2392 rotate.0 != 0.0
2393 };
2394
2395 if start {
2396 if let Ok(w) = WINDOWS.widget_tree(*window_id) {
2397 let hits = w.root().hit_test(first_info.center.cast());
2398 let target = hits
2399 .target()
2400 .and_then(|t| w.get(t.widget_id))
2401 .map(|t| t.interaction_path())
2402 .unwrap_or_else(|| w.root().interaction_path());
2403
2404 let target = match target.unblocked() {
2405 Some(t) => t,
2406 None => {
2407 *self = Self::NoStartedZero;
2408 return; }
2410 };
2411 let capture = POINTER_CAPTURE.current_capture_value();
2412
2413 for h in handle.iter() {
2414 h.stop();
2416 }
2417
2418 let args = TouchTransformArgs::now(
2419 *window_id,
2420 *device_id,
2421 first_info.clone(),
2422 latest_info,
2423 [PxVector::zero(); 2],
2424 *scale_factor,
2425 TouchPhase::Start,
2426 hits.clone(),
2427 target.clone(),
2428 capture,
2429 args.modifiers,
2430 );
2431 TOUCH_TRANSFORM_EVENT.notify(args);
2432
2433 *self = Self::StartedTwo {
2434 window_id: *window_id,
2435 device_id: *device_id,
2436 position: *position,
2437 velocity: [DipVector::zero(); 2],
2438 scale_factor: *scale_factor,
2439 handle: handle.clone(),
2440 first_info,
2441 hits,
2442 target,
2443 };
2444 } else {
2445 *self = Self::NoStartedZero;
2446 }
2447 }
2448 }
2449 }
2450 }
2451 Self::StartedOne {
2452 window_id,
2453 device_id,
2454 position,
2455 velocity,
2456 scale_factor,
2457 handle,
2458 first_info,
2459 hits,
2460 target,
2461 } => {
2462 let mut any_moved = false;
2463 for t in &args.touches {
2464 if handle == &t.touch_propagation {
2465 *position = t.position();
2466 *velocity = t.velocity;
2467 any_moved = true;
2468 } else {
2469 self.clear();
2470 return;
2471 }
2472 }
2473
2474 if any_moved {
2475 let latest_info = TouchTransformInfo::new_dip([*position, *position], *scale_factor);
2476 let capture = POINTER_CAPTURE.current_capture_value();
2477
2478 let velocity = velocity.to_px(*scale_factor);
2479
2480 let args = TouchTransformArgs::now(
2481 *window_id,
2482 *device_id,
2483 first_info.clone(),
2484 latest_info,
2485 [velocity, velocity],
2486 *scale_factor,
2487 TouchPhase::Move,
2488 hits.clone(),
2489 target.clone(),
2490 capture,
2491 args.modifiers,
2492 );
2493 TOUCH_TRANSFORM_EVENT.notify(args);
2494 }
2495 }
2496 Self::StartedTwo {
2497 window_id,
2498 device_id,
2499 position,
2500 scale_factor,
2501 velocity,
2502 handle,
2503 first_info,
2504 hits,
2505 target,
2506 } => {
2507 let mut any_moved = false;
2508 for t in &args.touches {
2509 if let Some(i) = handle.iter().position(|h| h == &t.touch_propagation) {
2510 position[i] = t.position();
2511 velocity[i] = t.velocity;
2512 any_moved = true;
2513 } else {
2514 self.clear();
2515 return;
2516 }
2517 }
2518
2519 if any_moved {
2520 let latest_info = TouchTransformInfo::new_dip(*position, *scale_factor);
2521 let capture = POINTER_CAPTURE.current_capture_value();
2522
2523 let velocity = [velocity[0].to_px(*scale_factor), velocity[1].to_px(*scale_factor)];
2524
2525 let args = TouchTransformArgs::now(
2526 *window_id,
2527 *device_id,
2528 first_info.clone(),
2529 latest_info,
2530 velocity,
2531 *scale_factor,
2532 TouchPhase::Move,
2533 hits.clone(),
2534 target.clone(),
2535 capture,
2536 args.modifiers,
2537 );
2538 TOUCH_TRANSFORM_EVENT.notify(args);
2539 }
2540 }
2541 }
2542 }
2543
2544 fn clear(&mut self) {
2545 match mem::take(self) {
2546 TransformGesture::StartedOne {
2547 window_id,
2548 device_id,
2549 scale_factor,
2550 first_info,
2551 hits,
2552 target,
2553 ..
2554 }
2555 | TransformGesture::StartedTwo {
2556 window_id,
2557 device_id,
2558 scale_factor,
2559 first_info,
2560 hits,
2561 target,
2562 ..
2563 } => {
2564 let args = TouchTransformArgs::now(
2565 window_id,
2566 device_id,
2567 first_info.clone(),
2568 first_info,
2569 [PxVector::zero(); 2],
2570 scale_factor,
2571 TouchPhase::Cancel,
2572 hits,
2573 target,
2574 None,
2575 ModifiersState::empty(),
2576 );
2577 TOUCH_TRANSFORM_EVENT.notify(args);
2578 }
2579 _ => {}
2580 }
2581 }
2582}