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
+ readonly 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
+ foreach ( int deviceId in trackedAnnotation . activeDevices ) {
79
+ annotation . onExit ( PointerExitEvent . fromHoverEvent ( ( PointerHoverEvent ) this . _lastMouseEvent [ deviceId ] ) ) ;
80
+ }
81
+
82
+ this . _trackedAnnotations . Remove ( annotation ) ;
83
+ }
84
+
85
+ void _scheduleMousePositionCheck ( ) {
86
+ SchedulerBinding . instance . addPostFrameCallback ( _ => { this . collectMousePositions ( ) ; } ) ;
87
+ SchedulerBinding . instance . scheduleFrame ( ) ;
88
+ }
89
+
90
+ void _handleEvent ( PointerEvent evt ) {
91
+ if ( evt . kind != PointerDeviceKind . mouse ) {
92
+ return ;
93
+ }
94
+
95
+ int deviceId = evt . device ;
96
+ if ( this . _trackedAnnotations . isEmpty ( ) ) {
97
+ this . _lastMouseEvent . Remove ( deviceId ) ;
98
+ return ;
99
+ }
100
+
101
+ if ( evt is PointerRemovedEvent ) {
102
+ this . _lastMouseEvent . Remove ( deviceId ) ;
103
+ this . _scheduleMousePositionCheck ( ) ;
104
+ }
105
+ else {
106
+ if ( evt is PointerMoveEvent ||
107
+ evt is PointerHoverEvent ||
108
+ evt is PointerDownEvent ) {
109
+ if ( ! this . _lastMouseEvent . ContainsKey ( deviceId ) ||
110
+ this . _lastMouseEvent [ deviceId ] . position != evt . position ) {
111
+ this . _scheduleMousePositionCheck ( ) ;
112
+ }
113
+
114
+ this . _lastMouseEvent [ deviceId ] = evt ;
115
+ }
116
+ }
117
+ }
118
+
119
+ _TrackedAnnotation _findAnnotation ( MouseTrackerAnnotation annotation ) {
120
+ if ( ! this . _trackedAnnotations . TryGetValue ( annotation , out var trackedAnnotation ) ) {
121
+ D . assert ( false , ( ) => "Unable to find annotation $annotation in tracked annotations. " +
122
+ "Check that attachAnnotation has been called for all annotated layers." ) ;
123
+ }
124
+
125
+ return trackedAnnotation ;
126
+ }
127
+
128
+ bool isAnnotationAttached ( MouseTrackerAnnotation annotation ) {
129
+ return this . _trackedAnnotations . ContainsKey ( annotation ) ;
130
+ }
131
+
132
+ public void collectMousePositions ( ) {
133
+ void exitAnnotation ( _TrackedAnnotation trackedAnnotation , int deviceId ) {
134
+ if ( trackedAnnotation . annotation ? . onExit != null &&
135
+ trackedAnnotation . activeDevices . Contains ( deviceId ) ) {
136
+ trackedAnnotation . annotation . onExit ( PointerExitEvent . fromHoverEvent ( this . _lastMouseEvent [ deviceId ] ) ) ;
137
+ trackedAnnotation . activeDevices . Remove ( deviceId ) ;
138
+ }
139
+ }
140
+
141
+ void exitAllDevices ( _TrackedAnnotation trackedAnnotation ) {
142
+ if ( trackedAnnotation . activeDevices . isNotEmpty ( ) ) {
143
+ HashSet < int > deviceIds = new HashSet < int > ( trackedAnnotation . activeDevices ) ;
144
+ foreach ( int deviceId in deviceIds ) {
145
+ exitAnnotation ( trackedAnnotation , deviceId ) ;
146
+ }
147
+ }
148
+ }
149
+
150
+ if ( ! this . mouseIsConnected ) {
151
+ foreach ( var annotation in this . _trackedAnnotations . Values ) {
152
+ exitAllDevices ( annotation ) ;
153
+ }
154
+
155
+ return ;
156
+ }
157
+
158
+ foreach ( int deviceId in this . _lastMouseEvent . Keys ) {
159
+ PointerEvent lastEvent = this . _lastMouseEvent [ deviceId ] ;
160
+ MouseTrackerAnnotation hit = this . annotationFinder ( lastEvent . position ) ;
161
+
162
+ if ( hit == null ) {
163
+ foreach ( _TrackedAnnotation trackedAnnotation in this . _trackedAnnotations . Values ) {
164
+ exitAnnotation ( trackedAnnotation , deviceId ) ;
165
+ }
166
+
167
+ return ;
168
+ }
169
+
170
+ _TrackedAnnotation hitAnnotation = this . _findAnnotation ( hit ) ;
171
+ //enter
172
+ if ( ! hitAnnotation . activeDevices . Contains ( deviceId ) ) {
173
+ hitAnnotation . activeDevices . Add ( deviceId ) ;
174
+ if ( hitAnnotation . annotation ? . onEnter != null ) {
175
+ hitAnnotation . annotation . onEnter ( PointerEnterEvent . fromHoverEvent ( lastEvent ) ) ;
176
+ }
177
+ }
178
+
179
+ //hover
180
+ if ( hitAnnotation . annotation ? . onHover != null ) {
181
+ hitAnnotation . annotation . onHover ( PointerHoverEvent . fromHoverEvent ( lastEvent ) ) ;
182
+ }
183
+
184
+ //leave
185
+ foreach ( _TrackedAnnotation trackedAnnotation in this . _trackedAnnotations . Values ) {
186
+ if ( hitAnnotation == trackedAnnotation ) {
187
+ continue ;
188
+ }
189
+
190
+ if ( trackedAnnotation . activeDevices . Contains ( deviceId ) ) {
191
+ if ( trackedAnnotation . annotation ? . onExit != null ) {
192
+ trackedAnnotation . annotation . onExit ( PointerExitEvent . fromHoverEvent ( ( PointerHoverEvent ) lastEvent ) ) ;
193
+ }
194
+
195
+ trackedAnnotation . activeDevices . Remove ( deviceId ) ;
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ }
0 commit comments