Skip to content
This repository was archived by the owner on Apr 29, 2021. It is now read-only.

Commit 8dce5bf

Browse files
committed
1 parent ed60ea9 commit 8dce5bf

File tree

11 files changed

+491
-60
lines changed

11 files changed

+491
-60
lines changed

Runtime/gestures/binding.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ void _handlePointerHoverEvent(PointerEvent evt) {
130130

131131
//leave events
132132
foreach (var lastMoveTarget in this.lastMoveTargets) {
133-
lastMoveTarget.handleEvent(new PointerLeaveEvent(
133+
lastMoveTarget.handleEvent(new PointerExitEvent(
134134
timeStamp: evt.timeStamp,
135135
pointer: evt.pointer,
136136
device: evt.device,

Runtime/gestures/events.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,20 @@ public PointerEnterEvent(
120120
position: position,
121121
down: false) {
122122
}
123+
124+
public static PointerEnterEvent fromHoverEvent(PointerHoverEvent hover) {
125+
return new PointerEnterEvent(
126+
timeStamp: hover.timeStamp,
127+
pointer: hover.pointer,
128+
kind: hover.kind,
129+
device: hover.device,
130+
position: hover.position
131+
);
132+
}
123133
}
124134

125-
public class PointerLeaveEvent : PointerEvent {
126-
public PointerLeaveEvent(
135+
public class PointerExitEvent : PointerEvent {
136+
public PointerExitEvent(
127137
TimeSpan timeStamp,
128138
int pointer = 0,
129139
PointerDeviceKind kind = PointerDeviceKind.mouse,
@@ -137,6 +147,16 @@ public PointerLeaveEvent(
137147
position: position,
138148
down: false) {
139149
}
150+
151+
public static PointerExitEvent fromHoverEvent(PointerHoverEvent hover) {
152+
return new PointerExitEvent(
153+
timeStamp: hover.timeStamp,
154+
pointer: hover.pointer,
155+
kind: hover.kind,
156+
device: hover.device,
157+
position: hover.position
158+
);
159+
}
140160
}
141161

142162
public class PointerDownEvent : PointerEvent {

Runtime/gestures/mouse_tracking.cs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
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+
}

Runtime/rendering/binding.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public RendererBinding() {
2121
this.initRenderView();
2222
D.assert(this.renderView != null);
2323
this.addPersistentFrameCallback(this._handlePersistentFrameCallback);
24+
this._mouseTracker = this._createMouseTracker();
2425
}
2526

2627
public void initRenderView() {
@@ -29,6 +30,11 @@ public void initRenderView() {
2930
this.renderView.scheduleInitialFrame();
3031
}
3132

33+
public MouseTracker mouseTracker {
34+
get { return this._mouseTracker; }
35+
}
36+
MouseTracker _mouseTracker;
37+
3238
public PipelineOwner pipelineOwner {
3339
get { return this._pipelineOwner; }
3440
}
@@ -63,6 +69,14 @@ void _handlePersistentFrameCallback(TimeSpan timeStamp) {
6369
this.drawFrame();
6470
}
6571

72+
MouseTracker _createMouseTracker() {
73+
return new MouseTracker(this.pointerRouter, (Offset offset) => {
74+
return this.renderView.layer.find<MouseTrackerAnnotation>(
75+
offset * Window.instance.devicePixelRatio
76+
);
77+
});
78+
}
79+
6680
protected virtual void drawFrame() {
6781
this.pipelineOwner.flushLayout();
6882
this.pipelineOwner.flushCompositingBits();

0 commit comments

Comments
 (0)