1
+ using System . Collections . Generic ;
2
+ using Unity . UIWidgets . foundation ;
3
+ using Unity . UIWidgets . scheduler ;
4
+ using Unity . UIWidgets . ui ;
5
+
6
+ namespace Unity . UIWidgets . gestures {
7
+
8
+ public delegate void PointerHoverEventListener ( PointerHoverEvent evt ) ;
9
+
10
+ public delegate void PointerEnterEventListener ( PointerEnterEvent evt ) ;
11
+
12
+ public delegate void PointerExitEventListener ( PointerExitEvent evt ) ;
13
+
14
+
15
+ public class MouseTrackerAnnotation {
16
+ public MouseTrackerAnnotation (
17
+ PointerEnterEventListener onEnter = null ,
18
+ PointerHoverEventListener onHover = null ,
19
+ PointerExitEventListener onExit = null
20
+ ) {
21
+ this . onEnter = onEnter ;
22
+ this . onHover = onHover ;
23
+ this . onExit = onExit ;
24
+ }
25
+
26
+ public readonly PointerEnterEventListener onEnter ;
27
+
28
+ public readonly PointerHoverEventListener onHover ;
29
+
30
+ public readonly PointerExitEventListener onExit ;
31
+
32
+ public override string ToString ( ) {
33
+ return $ "{ this . GetType ( ) } #{ this . GetHashCode ( ) } { ( this . onEnter == null ? "" : " onEnter" ) } { ( this . onHover == null ? "" : " onHover" ) } { ( this . onExit == null ? "" : " onExit" ) } ";
34
+ }
35
+ }
36
+
37
+ public class _TrackedAnnotation {
38
+ public _TrackedAnnotation (
39
+ MouseTrackerAnnotation annotation ) {
40
+ this . annotation = annotation ;
41
+ }
42
+
43
+ public readonly MouseTrackerAnnotation annotation ;
44
+
45
+ public HashSet < int > activeDevices = new HashSet < int > ( ) ;
46
+ }
47
+
48
+ public delegate MouseTrackerAnnotation MouseDetectorAnnotationFinder ( Offset offset ) ;
49
+
50
+
51
+ public class MouseTracker {
52
+ public MouseTracker (
53
+ PointerRouter router ,
54
+ MouseDetectorAnnotationFinder annotationFinder ) {
55
+ router . addGlobalRoute ( this . _handleEvent ) ;
56
+ this . annotationFinder = annotationFinder ;
57
+ }
58
+
59
+ Dictionary < int , PointerEvent > _lastMouseEvent = new Dictionary < int , PointerEvent > ( ) ;
60
+
61
+ public bool mouseIsConnected {
62
+ get { return this . _lastMouseEvent . isNotEmpty ( ) ; }
63
+ }
64
+
65
+ public readonly MouseDetectorAnnotationFinder annotationFinder ;
66
+
67
+ public readonly Dictionary < MouseTrackerAnnotation , _TrackedAnnotation > _trackedAnnotations =
68
+ new Dictionary < MouseTrackerAnnotation , _TrackedAnnotation > ( ) ;
69
+
70
+
71
+ public void attachAnnotation ( MouseTrackerAnnotation annotation ) {
72
+ this . _trackedAnnotations [ annotation ] = new _TrackedAnnotation ( annotation ) ;
73
+ this . _scheduleMousePositionCheck ( ) ;
74
+ }
75
+
76
+ public void detachAnnotation ( MouseTrackerAnnotation annotation ) {
77
+ _TrackedAnnotation trackedAnnotation = this . _findAnnotation ( annotation ) ;
78
+ D . assert ( trackedAnnotation != null , $ "Tried to detach an annotation that wasn't attached: { annotation } ") ;
79
+ foreach ( int deviceId in trackedAnnotation . activeDevices ) {
80
+ annotation . onExit ( PointerExitEvent . fromHoverEvent ( ( PointerHoverEvent ) this . _lastMouseEvent [ deviceId ] ) ) ;
81
+ }
82
+
83
+ this . _trackedAnnotations . Remove ( annotation ) ;
84
+ }
85
+
86
+ void _scheduleMousePositionCheck ( ) {
87
+ SchedulerBinding . instance . addPostFrameCallback ( _ => { this . collectMousePositions ( ) ; } ) ;
88
+ SchedulerBinding . instance . scheduleFrame ( ) ;
89
+ }
90
+
91
+ void _handleEvent ( PointerEvent evt ) {
92
+ if ( evt . kind != PointerDeviceKind . mouse ) {
93
+ return ;
94
+ }
95
+
96
+ int deviceId = evt . device ;
97
+ if ( this . _trackedAnnotations . isEmpty ( ) ) {
98
+ this . _lastMouseEvent . Remove ( deviceId ) ;
99
+ return ;
100
+ }
101
+
102
+ if ( evt is PointerRemovedEvent ) {
103
+ this . _lastMouseEvent . Remove ( deviceId ) ;
104
+ this . _scheduleMousePositionCheck ( ) ;
105
+ }
106
+ else {
107
+ if ( evt is PointerMoveEvent ||
108
+ evt is PointerHoverEvent ||
109
+ evt is PointerDownEvent ) {
110
+ if ( ! this . _lastMouseEvent . ContainsKey ( deviceId ) ||
111
+ this . _lastMouseEvent [ deviceId ] . position != evt . position ) {
112
+ this . _scheduleMousePositionCheck ( ) ;
113
+ }
114
+
115
+ this . _lastMouseEvent [ deviceId ] = evt ;
116
+ }
117
+ }
118
+ }
119
+
120
+ _TrackedAnnotation _findAnnotation ( MouseTrackerAnnotation annotation ) {
121
+ if ( ! this . _trackedAnnotations . TryGetValue ( annotation , out var trackedAnnotation ) ) {
122
+ D . assert ( false , "Unable to find annotation $annotation in tracked annotations. " +
123
+ "Check that attachAnnotation has been called for all annotated layers." ) ;
124
+ }
125
+
126
+ return trackedAnnotation ;
127
+ }
128
+
129
+ public void collectMousePositions ( ) {
130
+ void exitAnnotation ( _TrackedAnnotation trackedAnnotation , int deviceId ) {
131
+ if ( trackedAnnotation . annotation ? . onExit != null &&
132
+ trackedAnnotation . activeDevices . Contains ( deviceId ) ) {
133
+ trackedAnnotation . annotation . onExit ( PointerExitEvent . fromHoverEvent ( ( PointerHoverEvent ) this . _lastMouseEvent [ deviceId ] ) ) ;
134
+ }
135
+ }
136
+
137
+ void exitAllDevices ( _TrackedAnnotation trackedAnnotation ) {
138
+ if ( trackedAnnotation . activeDevices . isNotEmpty ( ) ) {
139
+ HashSet < int > deviceIds = new HashSet < int > ( trackedAnnotation . activeDevices ) ;
140
+ foreach ( int deviceId in deviceIds ) {
141
+ exitAnnotation ( trackedAnnotation , deviceId ) ;
142
+ }
143
+ }
144
+ }
145
+
146
+ if ( ! this . mouseIsConnected ) {
147
+ foreach ( var annotation in this . _trackedAnnotations . Values ) {
148
+ exitAllDevices ( annotation ) ;
149
+ }
150
+
151
+ return ;
152
+ }
153
+
154
+ foreach ( int deviceId in this . _lastMouseEvent . Keys ) {
155
+ PointerEvent lastEvent = this . _lastMouseEvent [ deviceId ] ;
156
+ MouseTrackerAnnotation hit = this . annotationFinder ( lastEvent . position ) ;
157
+
158
+ if ( hit == null ) {
159
+ foreach ( _TrackedAnnotation trackedAnnotation in this . _trackedAnnotations . Values ) {
160
+ exitAnnotation ( trackedAnnotation , deviceId ) ;
161
+ }
162
+
163
+ return ;
164
+ }
165
+
166
+ _TrackedAnnotation hitAnnotation = this . _findAnnotation ( hit ) ;
167
+ if ( ! hitAnnotation . activeDevices . Contains ( deviceId ) ) {
168
+ hitAnnotation . activeDevices . Add ( deviceId ) ;
169
+ if ( hitAnnotation . annotation ? . onEnter != null ) {
170
+ hitAnnotation . annotation . onEnter ( PointerEnterEvent . fromHoverEvent ( ( PointerHoverEvent ) lastEvent ) ) ;
171
+ }
172
+ }
173
+
174
+ if ( hitAnnotation . annotation ? . onHover != null ) {
175
+ hitAnnotation . annotation . onHover ( ( PointerHoverEvent ) lastEvent ) ;
176
+ }
177
+
178
+ foreach ( _TrackedAnnotation trackedAnnotation in this . _trackedAnnotations . Values ) {
179
+ if ( hitAnnotation == trackedAnnotation ) {
180
+ continue ;
181
+ }
182
+
183
+ if ( trackedAnnotation . activeDevices . Contains ( deviceId ) ) {
184
+ if ( trackedAnnotation . annotation ? . onExit != null ) {
185
+ trackedAnnotation . annotation . onExit ( PointerExitEvent . fromHoverEvent ( ( PointerHoverEvent ) lastEvent ) ) ;
186
+ }
187
+
188
+ trackedAnnotation . activeDevices . Remove ( deviceId ) ;
189
+ }
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
0 commit comments