kg
6 年前
当前提交
4c8583f7
共有 42 个文件被更改,包括 1702 次插入 和 19 次删除
-
68Assets/UIWidgets/editor/editor_window.cs
-
249Assets/UIWidgets/gestures/arena.cs
-
12Assets/UIWidgets/rendering/object.mixin.gen.cs
-
6Assets/UIWidgets/rendering/object.mixin.njk
-
2Assets/UIWidgets/ui/geometry.cs
-
24Assets/UIWidgets/ui/window.cs
-
5Packages/manifest.json
-
2ProjectSettings/ProjectVersion.txt
-
8Assets/UIWidgets/async.meta
-
42Assets/UIWidgets/foundation/basic_types.cs
-
3Assets/UIWidgets/foundation/basic_types.cs.meta
-
22Assets/UIWidgets/foundation/debug.cs
-
3Assets/UIWidgets/foundation/debug.cs.meta
-
8Assets/UIWidgets/gestures.meta
-
11Assets/UIWidgets/gestures/arena.cs.meta
-
101Assets/UIWidgets/gestures/binding.cs
-
3Assets/UIWidgets/gestures/binding.cs.meta
-
9Assets/UIWidgets/gestures/constants.cs
-
3Assets/UIWidgets/gestures/constants.cs.meta
-
139Assets/UIWidgets/gestures/converter.cs
-
3Assets/UIWidgets/gestures/converter.cs.meta
-
130Assets/UIWidgets/gestures/events.cs
-
3Assets/UIWidgets/gestures/events.cs.meta
-
53Assets/UIWidgets/gestures/hit_test.cs
-
3Assets/UIWidgets/gestures/hit_test.cs.meta
-
66Assets/UIWidgets/gestures/pointer_router.cs
-
3Assets/UIWidgets/gestures/pointer_router.cs.meta
-
206Assets/UIWidgets/gestures/recognizer.cs
-
3Assets/UIWidgets/gestures/recognizer.cs.meta
-
138Assets/UIWidgets/gestures/tap.cs
-
3Assets/UIWidgets/gestures/tap.cs.meta
-
118Assets/UIWidgets/gestures/team.cs
-
3Assets/UIWidgets/gestures/team.cs.meta
-
51Assets/UIWidgets/ui/pointer.cs
-
3Assets/UIWidgets/ui/pointer.cs.meta
-
26Assets/UIWidgets/async/microtask_queue.cs
-
3Assets/UIWidgets/async/microtask_queue.cs.meta
-
105Assets/UIWidgets/async/priority_queue.cs
-
3Assets/UIWidgets/async/priority_queue.cs.meta
-
67Assets/UIWidgets/async/timer.cs
-
11Assets/UIWidgets/async/timer.cs.meta
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
public enum GestureDisposition { |
|||
accepted, |
|||
rejected, |
|||
} |
|||
|
|||
public interface GestureArenaMember { |
|||
void acceptGesture(int pointer); |
|||
void rejectGesture(int pointer); |
|||
} |
|||
|
|||
public class GestureArenaEntry { |
|||
public GestureArenaEntry( |
|||
GestureArenaManager arena = null, |
|||
int pointer = 0, |
|||
GestureArenaMember member = null) { |
|||
this._arena = arena; |
|||
this._pointer = pointer; |
|||
this._member = member; |
|||
} |
|||
|
|||
readonly GestureArenaManager _arena; |
|||
readonly int _pointer; |
|||
readonly GestureArenaMember _member; |
|||
|
|||
public virtual void resolve(GestureDisposition disposition) { |
|||
this._arena._resolve(this._pointer, this._member, disposition); |
|||
} |
|||
} |
|||
|
|||
class _GestureArena { |
|||
public List<GestureArenaMember> members = new List<GestureArenaMember>(); |
|||
public bool isOpen = true; |
|||
public bool isHeld = false; |
|||
public bool hasPendingSweep = false; |
|||
|
|||
public GestureArenaMember eagerWinner; |
|||
|
|||
public void add(GestureArenaMember member) { |
|||
D.assert(this.isOpen); |
|||
this.members.Add(member); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
StringBuilder buffer = new StringBuilder(); |
|||
if (this.members.isEmpty()) { |
|||
buffer.Append("<empty>"); |
|||
} else { |
|||
buffer.Append(string.Join(", ", this.members.Select( |
|||
member => member == this.eagerWinner |
|||
? string.Format("{0} (eager winner)", member) |
|||
: member.ToString()).ToArray())); |
|||
} |
|||
|
|||
if (this.isOpen) { |
|||
buffer.Append(" [open]"); |
|||
} |
|||
|
|||
if (this.isHeld) { |
|||
buffer.Append(" [held]"); |
|||
} |
|||
|
|||
if (this.hasPendingSweep) { |
|||
buffer.Append(" [hasPendingSweep]"); |
|||
} |
|||
|
|||
return buffer.ToString(); |
|||
} |
|||
} |
|||
|
|||
public class GestureArenaManager { |
|||
readonly Dictionary<int, _GestureArena> _arenas = new Dictionary<int, _GestureArena>(); |
|||
readonly Window _window; |
|||
|
|||
public GestureArenaManager(Window window) { |
|||
this._window = window; |
|||
} |
|||
|
|||
public GestureArenaEntry add(int pointer, GestureArenaMember member) { |
|||
_GestureArena state = this._arenas.putIfAbsent(pointer, () => { |
|||
D.assert(this._debugLogDiagnostic(pointer, "★ Opening new gesture arena.")); |
|||
return state = new _GestureArena(); |
|||
}); |
|||
|
|||
state.add(member); |
|||
|
|||
D.assert(this._debugLogDiagnostic(pointer, string.Format("Adding: {0}", member))); |
|||
return new GestureArenaEntry(this, pointer, member); |
|||
} |
|||
|
|||
public void close(int pointer) { |
|||
_GestureArena state; |
|||
if (!this._arenas.TryGetValue(pointer, out state)) { |
|||
return; |
|||
} |
|||
|
|||
state.isOpen = false; |
|||
D.assert(this._debugLogDiagnostic(pointer, "Closing", state)); |
|||
this._tryToResolveArena(pointer, state); |
|||
} |
|||
|
|||
public void sweep(int pointer) { |
|||
_GestureArena state; |
|||
if (!this._arenas.TryGetValue(pointer, out state)) { |
|||
return; |
|||
} |
|||
|
|||
D.assert(!state.isOpen); |
|||
if (state.isHeld) { |
|||
state.hasPendingSweep = true; |
|||
D.assert(this._debugLogDiagnostic(pointer, "Delaying sweep", state)); |
|||
return; |
|||
} |
|||
|
|||
D.assert(this._debugLogDiagnostic(pointer, "Sweeping", state)); |
|||
this._arenas.Remove(pointer); |
|||
if (state.members.isNotEmpty()) { |
|||
D.assert(this._debugLogDiagnostic( |
|||
pointer, string.Format("Winner: {0}", state.members.First()))); |
|||
|
|||
state.members.First().acceptGesture(pointer); |
|||
for (int i = 1; i < state.members.Count; i++) { |
|||
state.members[i].rejectGesture(pointer); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void hold(int pointer) { |
|||
_GestureArena state; |
|||
if (!this._arenas.TryGetValue(pointer, out state)) { |
|||
return; |
|||
} |
|||
|
|||
state.isHeld = true; |
|||
D.assert(this._debugLogDiagnostic(pointer, "Holding", state)); |
|||
} |
|||
|
|||
public void release(int pointer) { |
|||
_GestureArena state; |
|||
if (!this._arenas.TryGetValue(pointer, out state)) { |
|||
return; |
|||
} |
|||
|
|||
state.isHeld = false; |
|||
D.assert(this._debugLogDiagnostic(pointer, "Releasing", state)); |
|||
if (state.hasPendingSweep) { |
|||
this.sweep(pointer); |
|||
} |
|||
} |
|||
|
|||
internal void _resolve(int pointer, GestureArenaMember member, GestureDisposition disposition) { |
|||
_GestureArena state; |
|||
if (!this._arenas.TryGetValue(pointer, out state)) { |
|||
return; |
|||
} |
|||
|
|||
D.assert(this._debugLogDiagnostic(pointer, |
|||
string.Format("{0}: {1}", |
|||
disposition == GestureDisposition.accepted ? "Accepting" : "Rejecting", |
|||
member))); |
|||
|
|||
D.assert(state.members.Contains(member)); |
|||
if (disposition == GestureDisposition.rejected) { |
|||
state.members.Remove(member); |
|||
member.rejectGesture(pointer); |
|||
if (!state.isOpen) { |
|||
this._tryToResolveArena(pointer, state); |
|||
} |
|||
} else { |
|||
if (state.isOpen) { |
|||
state.eagerWinner = state.eagerWinner ?? member; |
|||
} else { |
|||
D.assert(this._debugLogDiagnostic(pointer, |
|||
string.Format("Self-declared winner: {0}", member))); |
|||
this._resolveInFavorOf(pointer, state, member); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void _tryToResolveArena(int pointer, _GestureArena state) { |
|||
D.assert(this._arenas[pointer] == state); |
|||
D.assert(!state.isOpen); |
|||
|
|||
if (state.members.Count == 1) { |
|||
this._window.scheduleMicrotask(() => this._resolveByDefault(pointer, state)); |
|||
} else if (state.members.isEmpty()) { |
|||
this._arenas.Remove(pointer); |
|||
D.assert(this._debugLogDiagnostic(pointer, "Arena empty.")); |
|||
} else if (state.eagerWinner != null) { |
|||
D.assert(this._debugLogDiagnostic(pointer, |
|||
string.Format("Eager winner: {0}", state.eagerWinner))); |
|||
this._resolveInFavorOf(pointer, state, state.eagerWinner); |
|||
} |
|||
} |
|||
|
|||
void _resolveByDefault(int pointer, _GestureArena state) { |
|||
if (!this._arenas.ContainsKey(pointer)) { |
|||
return; |
|||
} |
|||
|
|||
D.assert(this._arenas[pointer] == state); |
|||
D.assert(!state.isOpen); |
|||
List<GestureArenaMember> members = state.members; |
|||
D.assert(members.Count == 1); |
|||
this._arenas.Remove(pointer); |
|||
D.assert(this._debugLogDiagnostic(pointer, |
|||
string.Format("Default winner: {0}", state.members.First()))); |
|||
state.members.First().acceptGesture(pointer); |
|||
} |
|||
|
|||
void _resolveInFavorOf(int pointer, _GestureArena state, GestureArenaMember member) { |
|||
D.assert(state == this._arenas[pointer]); |
|||
D.assert(state != null); |
|||
D.assert(state.eagerWinner == null || state.eagerWinner == member); |
|||
D.assert(!state.isOpen); |
|||
|
|||
this._arenas.Remove(pointer); |
|||
foreach (GestureArenaMember rejectedMember in state.members) { |
|||
if (rejectedMember != member) { |
|||
rejectedMember.rejectGesture(pointer); |
|||
} |
|||
} |
|||
|
|||
member.acceptGesture(pointer); |
|||
} |
|||
|
|||
bool _debugLogDiagnostic(int pointer, string message, _GestureArena state = null) { |
|||
D.assert(() => { |
|||
if (D.debugPrintGestureArenaDiagnostics) { |
|||
int? count = state != null ? state.members.Count : (int?) null; |
|||
string s = count != 1 ? "s" : ""; |
|||
Debug.LogFormat("Gesture arena {0} ❙ {1}{2}", |
|||
pointer.ToString().PadRight(4), |
|||
message, |
|||
count != null ? string.Format(" with {0} member{1}.", count, s) : ""); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
} |
|
|||
m_EditorVersion: 2018.2.4f1 |
|||
m_EditorVersion: 2018.3.0a9 |
|
|||
fileFormatVersion: 2 |
|||
guid: d164f4ad25c6f4b51b5f3e6a945a7296 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace UIWidgets.foundation { |
|||
public static class CollectionUtils { |
|||
public static V putIfAbsent<K, V>(this IDictionary<K, V> it, K key, Func<V> ifAbsent) { |
|||
V value; |
|||
if (it.TryGetValue(key, out value)) { |
|||
return value; |
|||
} |
|||
|
|||
value = ifAbsent(); |
|||
it[key] = value; |
|||
return value; |
|||
} |
|||
|
|||
public static bool isEmpty<T>(this ICollection<T> it) { |
|||
return it.Count == 0; |
|||
} |
|||
|
|||
public static bool isNotEmpty<T>(this ICollection<T> it) { |
|||
return it.Count != 0; |
|||
} |
|||
|
|||
public static bool isEmpty(this ICollection it) { |
|||
return it.Count == 0; |
|||
} |
|||
|
|||
public static bool isNotEmpty(this ICollection it) { |
|||
return it.Count != 0; |
|||
} |
|||
|
|||
public static bool isEmpty<TKey, TValue>(this IDictionary<TKey, TValue> it) { |
|||
return it.Count == 0; |
|||
} |
|||
|
|||
public static bool isNotEmpty<TKey, TValue>(this IDictionary<TKey, TValue> it) { |
|||
return it.Count != 0; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5677c530963d4d59baef909ab962ab44 |
|||
timeCreated: 1535605561 |
|
|||
using System; |
|||
using System.Diagnostics; |
|||
|
|||
namespace UIWidgets.foundation { |
|||
public static class D { |
|||
[Conditional("UIWidgets_DEBUG")] |
|||
public static void assert(Func<bool> result) { |
|||
D.assert(result()); |
|||
} |
|||
|
|||
[Conditional("UIWidgets_DEBUG")] |
|||
public static void assert(bool result) { |
|||
if (!result) { |
|||
throw new Exception("assertion failed. check stacktrace."); |
|||
} |
|||
} |
|||
|
|||
public static bool debugPrintGestureArenaDiagnostics = true; |
|||
|
|||
public static bool debugPrintHitTestResults = true; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 89e39060aaba41798359de8d7e6a013e |
|||
timeCreated: 1536123374 |
|
|||
fileFormatVersion: 2 |
|||
guid: 8617cc0ea80d74e80a0579e70d4e2d2c |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 8f1294e5215474e2d9ff98330207760e |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
public class GestureBinding : HitTestable, HitTestDispatcher, HitTestTarget { |
|||
public GestureBinding(Window window) { |
|||
this.window = window; |
|||
this.window._onPointerEvent += this._handlePointerDataPacket; |
|||
|
|||
this.gestureArena = new GestureArenaManager(window); |
|||
} |
|||
|
|||
public readonly Window window; |
|||
|
|||
readonly Queue<PointerEvent> _pendingPointerEvents = new Queue<PointerEvent>(); |
|||
|
|||
void _handlePointerDataPacket(PointerDataPacket packet) { |
|||
foreach (var pointerEvent in PointerEventConverter.expand(packet.data)) { |
|||
this._pendingPointerEvents.Enqueue(pointerEvent); |
|||
} |
|||
|
|||
this._flushPointerEventQueue(); |
|||
} |
|||
|
|||
public void cancelPointer(int pointer) { |
|||
if (this._pendingPointerEvents.isEmpty()) { |
|||
this.window.scheduleMicrotask(this._flushPointerEventQueue); |
|||
} |
|||
|
|||
this._pendingPointerEvents.Enqueue( |
|||
new PointerCancelEvent(timeStamp: DateTime.Now, pointer: pointer)); |
|||
} |
|||
|
|||
void _flushPointerEventQueue() { |
|||
while (this._pendingPointerEvents.Count != 0) { |
|||
this._handlePointerEvent(this._pendingPointerEvents.Dequeue()); |
|||
} |
|||
} |
|||
|
|||
public readonly PointerRouter pointerRouter = new PointerRouter(); |
|||
|
|||
public readonly GestureArenaManager gestureArena; |
|||
|
|||
public readonly Dictionary<int, HitTestResult> _hitTests = new Dictionary<int, HitTestResult>(); |
|||
|
|||
void _handlePointerEvent(PointerEvent evt) { |
|||
HitTestResult result; |
|||
if (evt is PointerDownEvent) { |
|||
D.assert(!this._hitTests.ContainsKey(evt.pointer)); |
|||
result = new HitTestResult(); |
|||
this.hitTest(result, evt.position); |
|||
this._hitTests[evt.pointer] = result; |
|||
D.assert(() => { |
|||
if (D.debugPrintHitTestResults) { |
|||
Debug.LogFormat("{0}: {1}", evt, result); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
} else if (evt is PointerUpEvent || evt is PointerCancelEvent) { |
|||
result = this._hitTests[evt.pointer]; |
|||
this._hitTests.Remove(evt.pointer); |
|||
} else if (evt.down) { |
|||
result = this._hitTests[evt.pointer]; |
|||
} else { |
|||
return; |
|||
} |
|||
|
|||
if (result != null) { |
|||
this.dispatchEvent(evt, result); |
|||
} |
|||
} |
|||
|
|||
public void hitTest(HitTestResult result, Offset position) { |
|||
result.add(new HitTestEntry(this)); |
|||
} |
|||
|
|||
public void dispatchEvent(PointerEvent evt, HitTestResult result) { |
|||
foreach (HitTestEntry entry in result.path) { |
|||
try { |
|||
entry.target.handleEvent(evt, entry); |
|||
} |
|||
catch (Exception ex) { |
|||
Debug.LogError("Error while dispatching a pointer event: " + ex); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void handleEvent(PointerEvent evt, HitTestEntry entry) { |
|||
this.pointerRouter.route(evt); |
|||
if (evt is PointerDownEvent) { |
|||
this.gestureArena.close(evt.pointer); |
|||
} else if (evt is PointerUpEvent) { |
|||
this.gestureArena.sweep(evt.pointer); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 4cdb394be98c414fb19a438686b949c1 |
|||
timeCreated: 1535609218 |
|
|||
using System; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
public static class Constants { |
|||
public const double kTouchSlop = 18.0; |
|||
|
|||
public static readonly TimeSpan kPressTimeout = new TimeSpan(0, 0, 0, 100); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: fe1823eee58c44999e824c526724caa3 |
|||
timeCreated: 1535608065 |
|
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
class _PointerState { |
|||
public _PointerState(Offset lastPosition) { |
|||
this.lastPosition = lastPosition ?? Offset.zero; |
|||
} |
|||
|
|||
public int pointer { |
|||
get { return this._pointer; } |
|||
} |
|||
|
|||
int _pointer; |
|||
|
|||
static int _pointerCount = 0; |
|||
|
|||
public void startNewPointer() { |
|||
_PointerState._pointerCount += 1; |
|||
this._pointer = _PointerState._pointerCount; |
|||
} |
|||
|
|||
public bool down { |
|||
get { return this._down; } |
|||
} |
|||
|
|||
bool _down = false; |
|||
|
|||
public void setDown() { |
|||
D.assert(!this._down); |
|||
this._down = true; |
|||
} |
|||
|
|||
public void setUp() { |
|||
D.assert(this._down); |
|||
this._down = false; |
|||
} |
|||
|
|||
public Offset lastPosition; |
|||
|
|||
public override string ToString() { |
|||
return string.Format("_PointerState(pointer: {0}, down: {1}, lastPosition: {2})", |
|||
this.pointer, this.down, this.lastPosition); |
|||
} |
|||
} |
|||
|
|||
public static class PointerEventConverter { |
|||
static readonly Dictionary<int, _PointerState> _pointers = new Dictionary<int, _PointerState>(); |
|||
|
|||
static _PointerState _ensureStateForPointer(PointerData datum, Offset position) { |
|||
return _pointers.putIfAbsent( |
|||
datum.device, |
|||
() => new _PointerState(position)); |
|||
} |
|||
|
|||
public static IEnumerable<PointerEvent> expand(IEnumerable<PointerData> data) { |
|||
foreach (PointerData datum in data) { |
|||
var position = new Offset(datum.physicalX, datum.physicalY); |
|||
var timeStamp = datum.timeStamp; |
|||
var kind = datum.kind; |
|||
|
|||
switch (datum.change) { |
|||
case PointerChange.down: { |
|||
_PointerState state = _ensureStateForPointer(datum, position); |
|||
D.assert(!state.down); |
|||
|
|||
state.startNewPointer(); |
|||
state.setDown(); |
|||
yield return new PointerDownEvent( |
|||
timeStamp: timeStamp, |
|||
pointer: state.pointer, |
|||
kind: kind, |
|||
device: datum.device, |
|||
position: position |
|||
); |
|||
} |
|||
break; |
|||
case PointerChange.move: { |
|||
D.assert(_pointers.ContainsKey(datum.device)); |
|||
_PointerState state = _pointers[datum.device]; |
|||
D.assert(state.down); |
|||
Offset offset = position - state.lastPosition; |
|||
state.lastPosition = position; |
|||
yield return new PointerMoveEvent( |
|||
timeStamp: timeStamp, |
|||
pointer: state.pointer, |
|||
kind: kind, |
|||
device: datum.device, |
|||
position: position, |
|||
delta: offset |
|||
); |
|||
} |
|||
break; |
|||
case PointerChange.up: |
|||
case PointerChange.cancel: { |
|||
D.assert(_pointers.ContainsKey(datum.device)); |
|||
_PointerState state = _pointers[datum.device]; |
|||
D.assert(state.down); |
|||
if (position != state.lastPosition) { |
|||
Offset offset = position - state.lastPosition; |
|||
state.lastPosition = position; |
|||
yield return new PointerMoveEvent( |
|||
timeStamp: timeStamp, |
|||
pointer: state.pointer, |
|||
kind: kind, |
|||
device: datum.device, |
|||
position: position, |
|||
delta: offset, |
|||
synthesized: true |
|||
); |
|||
} |
|||
|
|||
D.assert(position == state.lastPosition); |
|||
state.setUp(); |
|||
if (datum.change == PointerChange.up) { |
|||
yield return new PointerUpEvent( |
|||
timeStamp: timeStamp, |
|||
pointer: state.pointer, |
|||
kind: kind, |
|||
device: datum.device, |
|||
position: position |
|||
); |
|||
} else { |
|||
yield return new PointerCancelEvent( |
|||
timeStamp: timeStamp, |
|||
pointer: state.pointer, |
|||
kind: kind, |
|||
device: datum.device, |
|||
position: position |
|||
); |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 929719430a6b48a4b9639a1bb8b37e88 |
|||
timeCreated: 1536051892 |
|
|||
using System; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
public abstract class PointerEvent { |
|||
public PointerEvent( |
|||
DateTime timeStamp, |
|||
int pointer = 0, |
|||
PointerDeviceKind kind = PointerDeviceKind.mouse, |
|||
int device = 0, |
|||
Offset position = null, |
|||
Offset delta = null, |
|||
bool down = false, |
|||
bool synthesized = false |
|||
) { |
|||
this.timeStamp = timeStamp; |
|||
this.pointer = pointer; |
|||
this.kind = kind; |
|||
this.device = device; |
|||
this.position = position ?? Offset.zero; |
|||
this.delta = delta ?? Offset.zero; |
|||
this.down = down; |
|||
this.synthesized = synthesized; |
|||
} |
|||
|
|||
public readonly DateTime timeStamp; |
|||
|
|||
public readonly int pointer; |
|||
|
|||
public PointerDeviceKind kind; |
|||
|
|||
public int device; |
|||
|
|||
public readonly Offset position; |
|||
|
|||
public readonly Offset delta; |
|||
|
|||
public readonly bool down; |
|||
|
|||
public readonly bool synthesized; |
|||
} |
|||
|
|||
public class PointerDownEvent : PointerEvent { |
|||
public PointerDownEvent( |
|||
DateTime timeStamp, |
|||
int pointer = 0, |
|||
PointerDeviceKind kind = PointerDeviceKind.mouse, |
|||
int device = 0, |
|||
Offset position = null, |
|||
Offset delta = null, |
|||
bool down = false, |
|||
bool synthesized = false) |
|||
: base( |
|||
timeStamp, |
|||
pointer, |
|||
kind, |
|||
device, |
|||
position, |
|||
delta, |
|||
down, |
|||
synthesized) { |
|||
} |
|||
} |
|||
|
|||
public class PointerUpEvent : PointerEvent { |
|||
public PointerUpEvent( |
|||
DateTime timeStamp, |
|||
int pointer = 0, |
|||
PointerDeviceKind kind = PointerDeviceKind.mouse, |
|||
int device = 0, |
|||
Offset position = null, |
|||
Offset delta = null, |
|||
bool down = false, |
|||
bool synthesized = false) |
|||
: base( |
|||
timeStamp, |
|||
pointer, |
|||
kind, |
|||
device, |
|||
position, |
|||
delta, |
|||
down, |
|||
synthesized) { |
|||
} |
|||
} |
|||
|
|||
public class PointerCancelEvent : PointerEvent { |
|||
public PointerCancelEvent( |
|||
DateTime timeStamp, |
|||
int pointer = 0, |
|||
PointerDeviceKind kind = PointerDeviceKind.mouse, |
|||
int device = 0, |
|||
Offset position = null, |
|||
Offset delta = null, |
|||
bool down = false, |
|||
bool synthesized = false) |
|||
: base( |
|||
timeStamp, |
|||
pointer, |
|||
kind, |
|||
device, |
|||
position, |
|||
delta, |
|||
down, |
|||
synthesized) { |
|||
} |
|||
} |
|||
|
|||
public class PointerMoveEvent : PointerEvent { |
|||
public PointerMoveEvent( |
|||
DateTime timeStamp, |
|||
int pointer = 0, |
|||
PointerDeviceKind kind = PointerDeviceKind.mouse, |
|||
int device = 0, |
|||
Offset position = null, |
|||
Offset delta = null, |
|||
bool down = false, |
|||
bool synthesized = false) |
|||
: base( |
|||
timeStamp, |
|||
pointer, |
|||
kind, |
|||
device, |
|||
position, |
|||
delta, |
|||
down, |
|||
synthesized) { |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 85b73f18462c41199d2bd67c8f012ba6 |
|||
timeCreated: 1535595953 |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
public interface HitTestable { |
|||
void hitTest(HitTestResult result, Offset position); |
|||
} |
|||
|
|||
public interface HitTestDispatcher { |
|||
void dispatchEvent(PointerEvent @event, HitTestResult result); |
|||
} |
|||
|
|||
public interface HitTestTarget { |
|||
void handleEvent(PointerEvent @event, HitTestEntry entry); |
|||
} |
|||
|
|||
public class HitTestEntry { |
|||
public HitTestEntry(HitTestTarget target) { |
|||
this.target = target; |
|||
} |
|||
|
|||
public readonly HitTestTarget target; |
|||
|
|||
public override string ToString() { |
|||
return this.target.ToString(); |
|||
} |
|||
} |
|||
|
|||
public class HitTestResult { |
|||
public HitTestResult(List<HitTestEntry> path = null) { |
|||
this._path = path ?? new List<HitTestEntry>(); |
|||
} |
|||
|
|||
public IList<HitTestEntry> path { |
|||
get { return this._path.AsReadOnly(); } |
|||
} |
|||
|
|||
readonly List<HitTestEntry> _path; |
|||
|
|||
public void add(HitTestEntry entry) { |
|||
this._path.Add(entry); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("HitTestResult({0})", |
|||
this._path.isEmpty() |
|||
? "<empty path>" |
|||
: string.Join(", ", this._path.Select(x => x.ToString()).ToArray())); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 8e54d41203874208ad368d1a42e611f8 |
|||
timeCreated: 1535595576 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
public delegate void PointerRoute(PointerEvent evt); |
|||
|
|||
public class PointerRouter { |
|||
readonly Dictionary<int, HashSet<PointerRoute>> _routeMap = new Dictionary<int, HashSet<PointerRoute>>(); |
|||
|
|||
readonly HashSet<PointerRoute> _globalRoutes = new HashSet<PointerRoute>(); |
|||
|
|||
public void addRoute(int pointer, PointerRoute route) { |
|||
var routes = this._routeMap.putIfAbsent(pointer, () => new HashSet<PointerRoute>()); |
|||
D.assert(!routes.Contains(route)); |
|||
routes.Add(route); |
|||
} |
|||
|
|||
public void removeRoute(int pointer, PointerRoute route) { |
|||
D.assert(this._routeMap.ContainsKey(pointer)); |
|||
var routes = this._routeMap[pointer]; |
|||
routes.Remove(route); |
|||
if (routes.isEmpty()) { |
|||
this._routeMap.Remove(pointer); |
|||
} |
|||
} |
|||
|
|||
public void addGlobalRoute(PointerRoute route) { |
|||
D.assert(!this._globalRoutes.Contains(route)); |
|||
this._globalRoutes.Add(route); |
|||
} |
|||
|
|||
public void removeGlobalRoute(PointerRoute route) { |
|||
D.assert(this._globalRoutes.Contains(route)); |
|||
this._globalRoutes.Remove(route); |
|||
} |
|||
|
|||
void _dispatch(PointerEvent evt, PointerRoute route) { |
|||
try { |
|||
route(evt); |
|||
} |
|||
catch (Exception ex) { |
|||
Debug.LogError("Error while routing a pointer event: " + ex); |
|||
} |
|||
} |
|||
|
|||
public void route(PointerEvent evt) { |
|||
HashSet<PointerRoute> routes; |
|||
this._routeMap.TryGetValue(evt.pointer, out routes); |
|||
if (routes != null) { |
|||
foreach (PointerRoute route in new List<PointerRoute>(routes)) { |
|||
if (routes.Contains(route)) { |
|||
this._dispatch(evt, route); |
|||
} |
|||
} |
|||
} |
|||
|
|||
foreach (PointerRoute route in new List<PointerRoute>(this._globalRoutes)) { |
|||
if (this._globalRoutes.Contains(route)) { |
|||
this._dispatch(evt, route); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 37ff4ce5ebb74851a0bf2e62f12d9c50 |
|||
timeCreated: 1535604768 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.async; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
public delegate T RecognizerCallback<T>(); |
|||
|
|||
public abstract class GestureRecognizer : GestureArenaMember { |
|||
protected GestureRecognizer(GestureBinding binding = null) { |
|||
this._binding = binding; |
|||
} |
|||
|
|||
protected readonly GestureBinding _binding; |
|||
|
|||
public abstract void addPointer(PointerDownEvent evt); |
|||
|
|||
public virtual void dispose() { |
|||
} |
|||
|
|||
protected T invokeCallback<T>(string name, RecognizerCallback<T> callback) { |
|||
T result = default(T); |
|||
try { |
|||
result = callback(); |
|||
} |
|||
catch (Exception ex) { |
|||
Debug.LogError("Error while handling a gesture [" + name + "]: " + ex); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
public abstract void acceptGesture(int pointer); |
|||
public abstract void rejectGesture(int pointer); |
|||
} |
|||
|
|||
public abstract class OneSequenceGestureRecognizer : GestureRecognizer { |
|||
protected OneSequenceGestureRecognizer(GestureBinding binding = null) : base(binding) { |
|||
} |
|||
|
|||
readonly Dictionary<int, GestureArenaEntry> _entries = new Dictionary<int, GestureArenaEntry>(); |
|||
|
|||
readonly HashSet<int> _trackedPointers = new HashSet<int>(); |
|||
|
|||
protected abstract void handleEvent(PointerEvent evt); |
|||
|
|||
public override void acceptGesture(int pointer) { |
|||
} |
|||
|
|||
public override void rejectGesture(int pointer) { |
|||
} |
|||
|
|||
protected abstract void didStopTrackingLastPointer(int pointer); |
|||
|
|||
protected virtual void resolve(GestureDisposition disposition) { |
|||
var localEntries = new List<GestureArenaEntry>(this._entries.Values); |
|||
this._entries.Clear(); |
|||
foreach (GestureArenaEntry entry in localEntries) { |
|||
entry.resolve(disposition); |
|||
} |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this.resolve(GestureDisposition.rejected); |
|||
foreach (int pointer in this._trackedPointers) { |
|||
this._binding.pointerRouter.removeRoute(pointer, this.handleEvent); |
|||
} |
|||
|
|||
this._trackedPointers.Clear(); |
|||
D.assert(this._entries.isEmpty()); |
|||
base.dispose(); |
|||
} |
|||
|
|||
public GestureArenaTeam team { |
|||
get { return this._team; } |
|||
set { |
|||
D.assert(value != null); |
|||
D.assert(this._entries.isEmpty()); |
|||
D.assert(this._trackedPointers.isEmpty()); |
|||
D.assert(this._team == null); |
|||
this._team = value; |
|||
} |
|||
} |
|||
|
|||
GestureArenaTeam _team; |
|||
|
|||
GestureArenaEntry _addPointerToArena(int pointer) { |
|||
if (this._team != null) { |
|||
return this._team.add(pointer, this); |
|||
} |
|||
|
|||
return this._binding.gestureArena.add(pointer, this); |
|||
} |
|||
|
|||
protected void startTrackingPointer(int pointer) { |
|||
this._binding.pointerRouter.addRoute(pointer, this.handleEvent); |
|||
this._trackedPointers.Add(pointer); |
|||
D.assert(!this._entries.ContainsKey(pointer)); |
|||
this._entries[pointer] = this._addPointerToArena(pointer); |
|||
} |
|||
|
|||
protected void stopTrackingPointer(int pointer) { |
|||
if (this._trackedPointers.Contains(pointer)) { |
|||
this._binding.pointerRouter.removeRoute(pointer, this.handleEvent); |
|||
this._trackedPointers.Remove(pointer); |
|||
if (this._trackedPointers.isEmpty()) { |
|||
this.didStopTrackingLastPointer(pointer); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected void stopTrackingIfPointerNoLongerDown(PointerEvent evt) { |
|||
if (evt is PointerUpEvent || evt is PointerCancelEvent) { |
|||
this.stopTrackingPointer(evt.pointer); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public enum GestureRecognizerState { |
|||
ready, |
|||
possible, |
|||
defunct, |
|||
} |
|||
|
|||
public abstract class PrimaryPointerGestureRecognizer : OneSequenceGestureRecognizer { |
|||
protected PrimaryPointerGestureRecognizer( |
|||
TimeSpan? deadline = null, |
|||
GestureBinding binding = null |
|||
) : base(binding: binding) { |
|||
this.deadline = deadline; |
|||
} |
|||
|
|||
public readonly TimeSpan? deadline; |
|||
|
|||
public GestureRecognizerState state = GestureRecognizerState.ready; |
|||
|
|||
public int primaryPointer; |
|||
|
|||
public Offset initialPosition; |
|||
|
|||
Timer _timer; |
|||
|
|||
public override void addPointer(PointerDownEvent evt) { |
|||
this.startTrackingPointer(evt.pointer); |
|||
if (this.state == GestureRecognizerState.ready) { |
|||
this.state = GestureRecognizerState.possible; |
|||
this.primaryPointer = evt.pointer; |
|||
this.initialPosition = evt.position; |
|||
if (this.deadline != null) { |
|||
this._timer = this._binding.window.run(this.deadline.Value, this.didExceedDeadline); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected override void handleEvent(PointerEvent evt) { |
|||
D.assert(this.state != GestureRecognizerState.ready); |
|||
if (this.state == GestureRecognizerState.possible && evt.pointer == this.primaryPointer) { |
|||
if (evt is PointerMoveEvent && this._getDistance(evt) > Constants.kTouchSlop) { |
|||
this.resolve(GestureDisposition.rejected); |
|||
this.stopTrackingPointer(this.primaryPointer); |
|||
} else { |
|||
this.handlePrimaryPointer(evt); |
|||
} |
|||
} |
|||
|
|||
this.stopTrackingIfPointerNoLongerDown(evt); |
|||
} |
|||
|
|||
protected abstract void handlePrimaryPointer(PointerEvent evt); |
|||
|
|||
protected virtual void didExceedDeadline() { |
|||
D.assert(this.deadline == null); |
|||
} |
|||
|
|||
public override void rejectGesture(int pointer) { |
|||
if (pointer == this.primaryPointer && this.state == GestureRecognizerState.possible) { |
|||
this._stopTimer(); |
|||
this.state = GestureRecognizerState.defunct; |
|||
} |
|||
} |
|||
|
|||
protected override void didStopTrackingLastPointer(int pointer) { |
|||
this._stopTimer(); |
|||
this.state = GestureRecognizerState.ready; |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._stopTimer(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
void _stopTimer() { |
|||
if (this._timer != null) { |
|||
this._timer.cancel(); |
|||
this._timer = null; |
|||
} |
|||
} |
|||
|
|||
double _getDistance(PointerEvent evt) { |
|||
Offset offset = evt.position - this.initialPosition; |
|||
return offset.distance; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: d4c72baa549e450abe95d694fbad1a7b |
|||
timeCreated: 1535606392 |
|
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
public class TapDownDetails { |
|||
public TapDownDetails(Offset globalPosition = null) { |
|||
this.globalPosition = globalPosition ?? Offset.zero; |
|||
} |
|||
|
|||
public readonly Offset globalPosition; |
|||
} |
|||
|
|||
public delegate void GestureTapDownCallback(TapDownDetails details); |
|||
|
|||
public class TapUpDetails { |
|||
public TapUpDetails(Offset globalPosition = null) { |
|||
this.globalPosition = globalPosition ?? Offset.zero; |
|||
} |
|||
|
|||
public readonly Offset globalPosition; |
|||
} |
|||
|
|||
public delegate void GestureTapUpCallback(TapUpDetails details); |
|||
|
|||
public delegate void GestureTapCallback(); |
|||
|
|||
public delegate void GestureTapCancelCallback(); |
|||
|
|||
public class TapGestureRecognizer : PrimaryPointerGestureRecognizer { |
|||
public TapGestureRecognizer(GestureBinding binding) |
|||
: base(deadline: Constants.kPressTimeout, binding: binding) { |
|||
} |
|||
|
|||
public GestureTapDownCallback onTapDown; |
|||
|
|||
public GestureTapUpCallback onTapUp; |
|||
|
|||
public GestureTapCallback onTap; |
|||
|
|||
public GestureTapCancelCallback onTapCancel; |
|||
|
|||
bool _sentTapDown = false; |
|||
|
|||
bool _wonArenaForPrimaryPointer = false; |
|||
|
|||
Offset _finalPosition; |
|||
|
|||
protected override void handlePrimaryPointer(PointerEvent evt) { |
|||
if (evt is PointerUpEvent) { |
|||
this._finalPosition = evt.position; |
|||
this._checkUp(); |
|||
} else if (evt is PointerCancelEvent) { |
|||
this._reset(); |
|||
} |
|||
} |
|||
|
|||
protected override void resolve(GestureDisposition disposition) { |
|||
if (this._wonArenaForPrimaryPointer && disposition == GestureDisposition.rejected) { |
|||
if (this.onTapCancel != null) { |
|||
this.invokeCallback<object>("spontaneous onTapCancel", () => { |
|||
this.onTapCancel(); |
|||
return null; |
|||
}); |
|||
} |
|||
|
|||
this._reset(); |
|||
} |
|||
|
|||
base.resolve(disposition); |
|||
} |
|||
|
|||
protected override void didExceedDeadline() { |
|||
this._checkDown(); |
|||
} |
|||
|
|||
public override void acceptGesture(int pointer) { |
|||
base.acceptGesture(pointer); |
|||
if (pointer == this.primaryPointer) { |
|||
this._checkDown(); |
|||
this._wonArenaForPrimaryPointer = true; |
|||
this._checkUp(); |
|||
} |
|||
} |
|||
|
|||
public override void rejectGesture(int pointer) { |
|||
base.rejectGesture(pointer); |
|||
if (pointer == this.primaryPointer) { |
|||
if (this.onTapCancel != null) { |
|||
this.invokeCallback<object>("forced onTapCancel", () => { |
|||
this.onTapCancel(); |
|||
return null; |
|||
}); |
|||
} |
|||
|
|||
this._reset(); |
|||
} |
|||
} |
|||
|
|||
void _checkDown() { |
|||
if (!this._sentTapDown) { |
|||
if (this.onTapDown != null) |
|||
this.invokeCallback<object>("onTapDown", () => { |
|||
this.onTapDown(new TapDownDetails(globalPosition: this.initialPosition)); |
|||
return null; |
|||
}); |
|||
this._sentTapDown = true; |
|||
} |
|||
} |
|||
|
|||
void _checkUp() { |
|||
if (this._wonArenaForPrimaryPointer && this._finalPosition != null) { |
|||
this.resolve(GestureDisposition.accepted); |
|||
if (!this._wonArenaForPrimaryPointer || this._finalPosition == null) { |
|||
return; |
|||
} |
|||
|
|||
if (this.onTapUp != null) |
|||
this.invokeCallback<object>("onTapUp", () => { |
|||
this.onTapUp(new TapUpDetails(globalPosition: this._finalPosition)); |
|||
return null; |
|||
}); |
|||
if (this.onTap != null) { |
|||
this.invokeCallback<object>("onTap", () => { |
|||
this.onTap(); |
|||
return null; |
|||
}); |
|||
} |
|||
|
|||
this._reset(); |
|||
} |
|||
} |
|||
|
|||
void _reset() { |
|||
this._sentTapDown = false; |
|||
this._wonArenaForPrimaryPointer = false; |
|||
this._finalPosition = null; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f6283d6471a24256ad84c37472dfe262 |
|||
timeCreated: 1535608354 |
|
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
|
|||
namespace UIWidgets.gestures { |
|||
class _CombiningGestureArenaEntry : GestureArenaEntry { |
|||
public _CombiningGestureArenaEntry(_CombiningGestureArenaMember _combiner, GestureArenaMember _member) { |
|||
this._combiner = _combiner; |
|||
this._member = _member; |
|||
} |
|||
|
|||
readonly _CombiningGestureArenaMember _combiner; |
|||
readonly GestureArenaMember _member; |
|||
|
|||
public override void resolve(GestureDisposition disposition) { |
|||
this._combiner._resolve(this._member, disposition); |
|||
} |
|||
} |
|||
|
|||
class _CombiningGestureArenaMember : GestureArenaMember { |
|||
public _CombiningGestureArenaMember(GestureArenaTeam _owner, int _pointer) { |
|||
this._owner = _owner; |
|||
this._pointer = _pointer; |
|||
} |
|||
|
|||
readonly GestureArenaTeam _owner; |
|||
readonly List<GestureArenaMember> _members = new List<GestureArenaMember>(); |
|||
readonly int _pointer; |
|||
|
|||
bool _resolved = false; |
|||
GestureArenaMember _winner; |
|||
GestureArenaEntry _entry; |
|||
|
|||
public void acceptGesture(int pointer) { |
|||
D.assert(this._pointer == pointer); |
|||
D.assert(this._winner != null || this._members.isNotEmpty()); |
|||
|
|||
this._close(); |
|||
this._winner = this._winner ?? this._owner.captain ?? this._members[0]; |
|||
|
|||
foreach (GestureArenaMember member in this._members) { |
|||
if (member != this._winner) { |
|||
member.rejectGesture(pointer); |
|||
} |
|||
} |
|||
|
|||
this._winner.acceptGesture(pointer); |
|||
} |
|||
|
|||
public void rejectGesture(int pointer) { |
|||
D.assert(this._pointer == pointer); |
|||
|
|||
this._close(); |
|||
foreach (GestureArenaMember member in this._members) { |
|||
member.rejectGesture(pointer); |
|||
} |
|||
} |
|||
|
|||
void _close() { |
|||
D.assert(!this._resolved); |
|||
this._resolved = true; |
|||
|
|||
var combiner = this._owner._combiners[this._pointer]; |
|||
D.assert(combiner == this); |
|||
|
|||
this._owner._combiners.Remove(this._pointer); |
|||
} |
|||
|
|||
internal GestureArenaEntry _add(int pointer, GestureArenaMember member) { |
|||
D.assert(!this._resolved); |
|||
D.assert(this._pointer == pointer); |
|||
|
|||
this._members.Add(member); |
|||
this._entry = this._entry ?? this._owner._gestureArena.add(pointer, this); |
|||
return new _CombiningGestureArenaEntry(this, member); |
|||
} |
|||
|
|||
internal void _resolve(GestureArenaMember member, GestureDisposition disposition) { |
|||
if (this._resolved) { |
|||
return; |
|||
} |
|||
|
|||
if (disposition == GestureDisposition.rejected) { |
|||
this._members.Remove(member); |
|||
member.rejectGesture(this._pointer); |
|||
if (this._members.isEmpty()) { |
|||
this._entry.resolve(disposition); |
|||
} |
|||
} else { |
|||
this._winner = this._winner ?? this._owner.captain ?? member; |
|||
this._entry.resolve(disposition); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class GestureArenaTeam { |
|||
public GestureArenaTeam(GestureArenaManager gestureArena) { |
|||
this._gestureArena = gestureArena; |
|||
} |
|||
|
|||
internal readonly GestureArenaManager _gestureArena; |
|||
|
|||
internal readonly Dictionary<int, _CombiningGestureArenaMember> _combiners = |
|||
new Dictionary<int, _CombiningGestureArenaMember>(); |
|||
|
|||
public GestureArenaMember captain; |
|||
|
|||
public GestureArenaEntry add(int pointer, GestureArenaMember member) { |
|||
_CombiningGestureArenaMember combiner; |
|||
|
|||
if (!this._combiners.TryGetValue(pointer, out combiner)) { |
|||
combiner = new _CombiningGestureArenaMember(this, pointer); |
|||
this._combiners[pointer] = combiner; |
|||
} |
|||
|
|||
return combiner._add(pointer, member); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 7f4c3bdaf7be471ea5c3eeb4d7656d27 |
|||
timeCreated: 1535593919 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace UIWidgets.ui { |
|||
public enum PointerChange { |
|||
cancel, |
|||
add, |
|||
remove, |
|||
hover, |
|||
down, |
|||
move, |
|||
up, |
|||
} |
|||
|
|||
public enum PointerDeviceKind { |
|||
touch, |
|||
mouse, |
|||
} |
|||
|
|||
public class PointerData { |
|||
public PointerData( |
|||
DateTime timeStamp, |
|||
PointerChange change, |
|||
PointerDeviceKind kind, |
|||
int device, |
|||
double physicalX, |
|||
double physicalY) { |
|||
this.timeStamp = timeStamp; |
|||
this.change = change; |
|||
this.kind = kind; |
|||
this.device = device; |
|||
this.physicalX = physicalX; |
|||
this.physicalY = physicalY; |
|||
} |
|||
|
|||
public readonly DateTime timeStamp; |
|||
public PointerChange change; |
|||
public PointerDeviceKind kind; |
|||
public int device; |
|||
public double physicalX; |
|||
public double physicalY; |
|||
} |
|||
|
|||
public class PointerDataPacket { |
|||
public PointerDataPacket(List<PointerData> data) { |
|||
this.data = data; |
|||
} |
|||
|
|||
public readonly List<PointerData> data; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b5409a8bf1ca47a187b9a230dbcdcd98 |
|||
timeCreated: 1536048980 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.async { |
|||
public class MicrotaskQueue { |
|||
private Queue<Action> _queue = new Queue<Action>(); |
|||
|
|||
public void scheduleMicrotask(Action action) { |
|||
this._queue.Enqueue(action); |
|||
} |
|||
|
|||
public void flushMicrotasks() { |
|||
while (this._queue.isNotEmpty()) { |
|||
var action = this._queue.Dequeue(); |
|||
try { |
|||
action(); |
|||
} |
|||
catch (Exception ex) { |
|||
Debug.LogError("Error to execute microtask: " + ex); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 6d95e65550134a478f8f77093fc6d6f1 |
|||
timeCreated: 1535723558 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace UIWidgets.async { |
|||
public class PriorityQueue<T> where T : IComparable<T> { |
|||
private readonly List<T> _data; |
|||
|
|||
public PriorityQueue() { |
|||
this._data = new List<T>(); |
|||
} |
|||
|
|||
public void enqueue(T item) { |
|||
this._data.Add(item); |
|||
int ci = this._data.Count - 1; // child index; start at end
|
|||
while (ci > 0) { |
|||
int pi = (ci - 1) / 2; // parent index
|
|||
if (this._data[ci].CompareTo(this._data[pi]) >= 0) { |
|||
break; // child item is larger than (or equal) parent so we're done
|
|||
} |
|||
|
|||
T tmp = this._data[ci]; |
|||
this._data[ci] = this._data[pi]; |
|||
this._data[pi] = tmp; |
|||
ci = pi; |
|||
} |
|||
} |
|||
|
|||
public T dequeue() { |
|||
// assumes pq is not empty; up to calling code
|
|||
int li = this._data.Count - 1; // last index (before removal)
|
|||
T frontItem = this._data[0]; // fetch the front
|
|||
this._data[0] = this._data[li]; |
|||
this._data.RemoveAt(li); |
|||
|
|||
--li; // last index (after removal)
|
|||
int pi = 0; // parent index. start at front of pq
|
|||
while (true) { |
|||
int ci = pi * 2 + 1; // left child index of parent
|
|||
if (ci > li) { |
|||
break; // no children so done
|
|||
} |
|||
|
|||
int rc = ci + 1; // right child
|
|||
if (rc <= li && this._data[rc].CompareTo(this._data[ci]) < 0) { |
|||
// if there is a rc (ci + 1), and it is smaller than left child, use the rc instead
|
|||
ci = rc; |
|||
} |
|||
|
|||
if (this._data[pi].CompareTo(this._data[ci]) <= 0) { |
|||
break; // parent is smaller than (or equal to) smallest child so done
|
|||
} |
|||
|
|||
T tmp = this._data[pi]; |
|||
this._data[pi] = this._data[ci]; |
|||
this._data[ci] = tmp; // swap parent and child
|
|||
pi = ci; |
|||
} |
|||
|
|||
return frontItem; |
|||
} |
|||
|
|||
public T peek() { |
|||
T frontItem = this._data[0]; |
|||
return frontItem; |
|||
} |
|||
|
|||
public int count { |
|||
get { return this._data.Count; } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
string s = ""; |
|||
for (int i = 0; i < this._data.Count; ++i) { |
|||
s += this._data[i] + " "; |
|||
} |
|||
|
|||
s += "count = " + this._data.Count; |
|||
return s; |
|||
} |
|||
|
|||
public bool isConsistent() { |
|||
// is the heap property true for all data?
|
|||
if (this._data.Count == 0) { |
|||
return true; |
|||
} |
|||
|
|||
int li = this._data.Count - 1; // last index
|
|||
for (int pi = 0; pi < this._data.Count; ++pi) { |
|||
// each parent index
|
|||
int lci = 2 * pi + 1; // left child index
|
|||
int rci = 2 * pi + 2; // right child index
|
|||
|
|||
if (lci <= li && this._data[pi].CompareTo(this._data[lci]) > 0) { |
|||
return false; // if lc exists and it's greater than parent then bad.
|
|||
} |
|||
|
|||
if (rci <= li && this._data[pi].CompareTo(this._data[rci]) > 0) { |
|||
return false; // check the right child too.
|
|||
} |
|||
} |
|||
|
|||
return true; // passed all checks
|
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2d77ab33460640ddb5e3abbb2a11da34 |
|||
timeCreated: 1536040675 |
|
|||
using System; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.async { |
|||
public abstract class Timer { |
|||
public abstract void cancel(); |
|||
} |
|||
|
|||
public class TimerProvider { |
|||
private readonly PriorityQueue<TimerImpl> _queue; |
|||
|
|||
public TimerProvider() { |
|||
this._queue = new PriorityQueue<TimerImpl>(); |
|||
} |
|||
|
|||
public Timer run(TimeSpan duration, Action callback) { |
|||
var timer = new TimerImpl(DateTime.Now + duration, callback); |
|||
this._queue.enqueue(timer); |
|||
|
|||
return timer; |
|||
} |
|||
|
|||
public void update() { |
|||
var now = DateTime.Now; |
|||
|
|||
while (this._queue.count > 0 && this._queue.peek().deadline <= now) { |
|||
var timer = this._queue.dequeue(); |
|||
timer.invoke(); |
|||
} |
|||
} |
|||
|
|||
private class TimerImpl : Timer, IComparable<TimerImpl> { |
|||
public readonly DateTime deadline; |
|||
private readonly Action _callback; |
|||
private bool _done; |
|||
|
|||
public TimerImpl(DateTime deadline, Action callback) { |
|||
this.deadline = deadline; |
|||
this._callback = callback; |
|||
this._done = false; |
|||
} |
|||
|
|||
public override void cancel() { |
|||
this._done = true; |
|||
} |
|||
|
|||
public void invoke() { |
|||
if (this._done) { |
|||
return; |
|||
} |
|||
|
|||
this._done = true; |
|||
|
|||
try { |
|||
this._callback(); |
|||
} |
|||
catch (Exception ex) { |
|||
Debug.LogError("Error to execute timer callback: " + ex); |
|||
} |
|||
} |
|||
|
|||
public int CompareTo(TimerImpl other) { |
|||
return this.deadline.CompareTo(other.deadline); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 22e7b4cca5d354a4e9aa008cafcfdfe8 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue