浏览代码

gestures

/main
kg 6 年前
当前提交
46387278
共有 21 个文件被更改,包括 998 次插入38 次删除
  1. 6
      Assets/UIWidgets/Tests/Gestures.cs
  2. 37
      Assets/UIWidgets/editor/editor_window.cs
  3. 2
      Assets/UIWidgets/foundation/debug.cs
  4. 83
      Assets/UIWidgets/foundation/diagnostics.cs
  5. 4
      Assets/UIWidgets/gestures/binding.cs
  6. 6
      Assets/UIWidgets/gestures/constants.cs
  7. 4
      Assets/UIWidgets/gestures/converter.cs
  8. 28
      Assets/UIWidgets/gestures/events.cs
  9. 45
      Assets/UIWidgets/gestures/recognizer.cs
  10. 20
      Assets/UIWidgets/gestures/tap.cs
  11. 2
      Assets/UIWidgets/rendering/binding.cs
  12. 4
      Assets/UIWidgets/scheduler/binding.cs
  13. 12
      Assets/UIWidgets/ui/window.cs
  14. 90
      Assets/UIWidgets/gestures/drag_details.cs
  15. 3
      Assets/UIWidgets/gestures/drag_details.cs.meta
  16. 186
      Assets/UIWidgets/gestures/lsq_resolver.cs
  17. 3
      Assets/UIWidgets/gestures/lsq_resolver.cs.meta
  18. 281
      Assets/UIWidgets/gestures/monodrag.cs
  19. 3
      Assets/UIWidgets/gestures/monodrag.cs.meta
  20. 214
      Assets/UIWidgets/gestures/velocity_tracker.cs
  21. 3
      Assets/UIWidgets/gestures/velocity_tracker.cs.meta

6
Assets/UIWidgets/Tests/Gestures.cs


this._tapRecognizer = new TapGestureRecognizer(this.rendererBindings.gestureBinding);
this._tapRecognizer.onTap = () => { Debug.Log("tap"); };
this._panRecognizer = new PanGestureRecognizer(this.rendererBindings.gestureBinding);
this._panRecognizer.onUpdate = (details) => { Debug.Log("onUpdate " + details); };
}
void OnDestroy() {

TapGestureRecognizer _tapRecognizer;
PanGestureRecognizer _panRecognizer;
this._panRecognizer.addPointer(evt);
}
RenderBox tap() {

37
Assets/UIWidgets/editor/editor_window.cs


public class WindowAdapter : Window {
public WindowAdapter(EditorWindow editorWindow) {
this.editorWindow = editorWindow;
this.editorWindow.wantsMouseMove = false;
this.editorWindow.wantsMouseEnterLeaveWindow = false;
this._physicalSize = new Size(this._lastPosition.width, this._lastPosition.height);
this._physicalSize = new Size(
this._lastPosition.width * EditorGUIUtility.pixelsPerPoint,
this._lastPosition.height * EditorGUIUtility.pixelsPerPoint);
public EditorWindow editorWindow;
public Rect _lastPosition;
public readonly DateTime _epoch = DateTime.Now;
public readonly MicrotaskQueue _microtaskQueue = new MicrotaskQueue();
public readonly TimerProvider _timerProvider = new TimerProvider();
public readonly EditorWindow editorWindow;
Rect _lastPosition;
readonly DateTime _epoch = DateTime.Now;
readonly MicrotaskQueue _microtaskQueue = new MicrotaskQueue();
readonly TimerProvider _timerProvider = new TimerProvider();
public void OnGUI() {
var evt = Event.current;

change: PointerChange.down,
kind: PointerDeviceKind.mouse,
device: evt.button,
physicalX: evt.mousePosition.x,
physicalY: evt.mousePosition.y
physicalX: evt.mousePosition.x * this._devicePixelRatio,
physicalY: evt.mousePosition.y * this._devicePixelRatio
} else if (evt.type == EventType.MouseUp) {
} else if (evt.type == EventType.MouseUp || evt.rawType == EventType.MouseUp) {
physicalX: evt.mousePosition.x,
physicalY: evt.mousePosition.y
physicalX: evt.mousePosition.x * this._devicePixelRatio,
physicalY: evt.mousePosition.y * this._devicePixelRatio
);
} else if (evt.type == EventType.MouseDrag) {
pointerData = new PointerData(

device: evt.button,
physicalX: evt.mousePosition.x,
physicalY: evt.mousePosition.y
physicalX: evt.mousePosition.x * this._devicePixelRatio,
physicalY: evt.mousePosition.y * this._devicePixelRatio
);
}

this._lastPosition.width * EditorGUIUtility.pixelsPerPoint,
this._lastPosition.height * EditorGUIUtility.pixelsPerPoint);
if (this._onMetricsChanged != null) {
this._onMetricsChanged();
if (this.onMetricsChanged != null) {
this.onMetricsChanged();
}
}
}

2
Assets/UIWidgets/foundation/debug.cs


public static bool debugPrintHitTestResults = true;
public static bool debugPaintPointersEnabled = false;
public static bool debugPrintRecognizerCallbacksTrace = true;
}
}

83
Assets/UIWidgets/foundation/diagnostics.cs


internal _NoDefaultValue() {
}
}
class _NullDefaultValue {
internal _NullDefaultValue() {
}

}
}
public class FlagProperty : DiagnosticsProperty<bool> {
public FlagProperty(String name,
bool value,
string ifTrue = null,
string ifFalse = null,
bool showName = false,
object defaultValue = null,
DiagnosticLevel level = DiagnosticLevel.info
) : base(name,
value,
showName: showName,
defaultValue: defaultValue,
level: level
) {
D.assert(ifTrue != null || ifFalse != null);
}
public override Dictionary<string, object> toJsonMap() {
var json = base.toJsonMap();
if (this.ifTrue != null) {
json["ifTrue"] = this.ifTrue;
}
if (this.ifFalse != null) {
json["ifFalse"] = this.ifFalse;
}
return json;
}
public readonly string ifTrue;
public readonly string ifFalse;
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) {
if (this.value) {
if (this.ifTrue != null) {
return this.ifTrue;
}
} else if (!this.value) {
if (this.ifFalse != null) {
return this.ifFalse;
}
}
return base.valueToString(parentConfiguration: parentConfiguration);
}
public override bool showName {
get {
if (this.value && this.ifTrue == null || !this.value == false && this.ifFalse == null) {
return true;
}
return base.showName;
}
}
public override DiagnosticLevel level {
get {
if (this.value) {
if (this.ifTrue == null) {
return DiagnosticLevel.hidden;
}
}
if (!this.value) {
if (this.ifFalse == null) {
return DiagnosticLevel.hidden;
}
}
return base.level;
}
}
}
public class EnumerableProperty<T> : DiagnosticsProperty<IEnumerable<T>> {
public EnumerableProperty(
string name,

if (defaultValue == Diagnostics.kNullDefaultValue) {
defaultValue = null;
}
D.assert(defaultValue == null || defaultValue == Diagnostics.kNoDefaultValue || defaultValue is T);
this._description = description;

if (defaultValue == Diagnostics.kNullDefaultValue) {
defaultValue = null;
}
D.assert(defaultValue == null || defaultValue == Diagnostics.kNoDefaultValue || defaultValue is T);
this._description = description;

public abstract class DiagnosticableTree : Diagnosticable {
protected DiagnosticableTree() {
}
public string toStringShallow(
String joiner = ", ",
DiagnosticLevel minLevel = DiagnosticLevel.debug

4
Assets/UIWidgets/gestures/binding.cs


public class GestureBinding : HitTestable, HitTestDispatcher, HitTestTarget {
public GestureBinding(Window window, HitTestable hitTestable = null) {
this.window = window;
this.window._onPointerEvent += this._handlePointerDataPacket;
this.window.onPointerEvent += this._handlePointerDataPacket;
this.gestureArena = new GestureArenaManager(window);
this._hitTestable = hitTestable;

readonly Queue<PointerEvent> _pendingPointerEvents = new Queue<PointerEvent>();
void _handlePointerDataPacket(PointerDataPacket packet) {
foreach (var pointerEvent in PointerEventConverter.expand(packet.data)) {
foreach (var pointerEvent in PointerEventConverter.expand(packet.data, this.window.devicePixelRatio)) {
this._pendingPointerEvents.Enqueue(pointerEvent);
}

6
Assets/UIWidgets/gestures/constants.cs


namespace UIWidgets.gestures {
public static class Constants {
public const double kTouchSlop = 18.0;
public const double kPanSlop = kTouchSlop * 2.0;
public const double kMinFlingVelocity = 50.0;
public const double kMaxFlingVelocity = 8000.0;
}
}

4
Assets/UIWidgets/gestures/converter.cs


() => new _PointerState(position));
}
public static IEnumerable<PointerEvent> expand(IEnumerable<PointerData> data) {
public static IEnumerable<PointerEvent> expand(IEnumerable<PointerData> data, double devicePixelRatio) {
var position = new Offset(datum.physicalX, datum.physicalY);
var position = new Offset(datum.physicalX, datum.physicalY) / devicePixelRatio;
var timeStamp = datum.timeStamp;
var kind = datum.kind;

28
Assets/UIWidgets/gestures/events.cs


public readonly bool synthesized;
}
public class PointerAddedEvent : PointerEvent {
public PointerAddedEvent(
DateTime timeStamp,
PointerDeviceKind kind = PointerDeviceKind.touch,
int device = 0,
Offset position = null
) : base(
timeStamp: timeStamp,
kind: kind,
device: device,
position: position
) {
}
}
public class PointerRemovedEvent : PointerEvent {
public PointerRemovedEvent(
DateTime timeStamp,
PointerDeviceKind kind = PointerDeviceKind.touch,
int device = 0
) : base(
timeStamp: timeStamp,
kind: kind,
device: device
) {
}
}
public class PointerDownEvent : PointerEvent {
public PointerDownEvent(
DateTime timeStamp,

45
Assets/UIWidgets/gestures/recognizer.cs


namespace UIWidgets.gestures {
public delegate T RecognizerCallback<T>();
public abstract class GestureRecognizer : GestureArenaMember {
protected GestureRecognizer(GestureBinding binding = null) {
public abstract class GestureRecognizer : DiagnosticableTree, GestureArenaMember {
protected GestureRecognizer(GestureBinding binding = null, object debugOwner = null) {
this.debugOwner = debugOwner;
public readonly object debugOwner;
protected T invokeCallback<T>(string name, RecognizerCallback<T> callback) {
public abstract string debugDescription { get; }
protected T invokeCallback<T>(string name, RecognizerCallback<T> callback, Func<string> debugReport = null) {
D.assert(callback != null);
D.assert(() => {
if (D.debugPrintRecognizerCallbacksTrace) {
var report = debugReport != null ? debugReport() : null;
// The 19 in the line below is the width of the prefix used by
// _debugLogDiagnostic in arena.dart.
var prefix = D.debugPrintGestureArenaDiagnostics ? new string(' ', 19) + "❙ " : "";
Debug.LogFormat("{0}this calling {1} callback.{2}",
prefix, name, report.isNotEmpty() ? " " + report : "");
}
return true;
});
result = callback();
}
catch (Exception ex) {

public abstract void acceptGesture(int pointer);
public abstract void rejectGesture(int pointer);
protected internal override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<object>("debugOwner", this.debugOwner,
defaultValue: Diagnostics.kNullDefaultValue));
}
protected OneSequenceGestureRecognizer(GestureBinding binding = null) : base(binding) {
protected OneSequenceGestureRecognizer(
GestureBinding binding = null, object debugOwner = null) : base(binding, debugOwner) {
}
readonly Dictionary<int, GestureArenaEntry> _entries = new Dictionary<int, GestureArenaEntry>();

public abstract class PrimaryPointerGestureRecognizer : OneSequenceGestureRecognizer {
protected PrimaryPointerGestureRecognizer(
TimeSpan? deadline = null,
GestureBinding binding = null
) : base(binding: binding) {
GestureBinding binding = null,
object debugOwner = null
) : base(binding: binding, debugOwner: debugOwner) {
this.deadline = deadline;
}

double _getDistance(PointerEvent evt) {
Offset offset = evt.position - this.initialPosition;
return offset.distance;
}
protected internal override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new EnumProperty<GestureRecognizerState>("state", this.state));
}
}
}

20
Assets/UIWidgets/gestures/tap.cs


using UIWidgets.foundation;
using UIWidgets.ui;
namespace UIWidgets.gestures {

public delegate void GestureTapCancelCallback();
public class TapGestureRecognizer : PrimaryPointerGestureRecognizer {
public TapGestureRecognizer(GestureBinding binding)
: base(deadline: Constants.kPressTimeout, binding: binding) {
public TapGestureRecognizer(GestureBinding binding, object debugOwner = null)
: base(deadline: Constants.kPressTimeout, binding: binding, debugOwner: debugOwner) {
}
public GestureTapDownCallback onTapDown;

this._sentTapDown = false;
this._wonArenaForPrimaryPointer = false;
this._finalPosition = null;
}
public override string debugDescription {
get { return "tap"; }
}
protected internal override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new FlagProperty("wonArenaForPrimaryPointer",
value: this._wonArenaForPrimaryPointer,
ifTrue: "won arena"));
properties.add(new DiagnosticsProperty<Offset>("finalPosition",
this._finalPosition, defaultValue: Diagnostics.kNullDefaultValue));
properties.add(new FlagProperty("sentTapDown",
value: this._sentTapDown, ifTrue: "sent tap down"));
}
}
}

2
Assets/UIWidgets/rendering/binding.cs


onNeedVisualUpdate: this._schedulerBinding.ensureVisualUpdate
);
window._onMetricsChanged = this.handleMetricsChanged;
window.onMetricsChanged += this.handleMetricsChanged;
this.initRenderView();
this._schedulerBinding.addPersistentFrameCallback(this._handlePersistentFrameCallback);
}

4
Assets/UIWidgets/scheduler/binding.cs


public SchedulerBinding(Window window) {
this._window = window;
window.onBeginFrame = this._handleBeginFrame;
window.onDrawFrame = this._handleDrawFrame;
window.onBeginFrame += this._handleBeginFrame;
window.onDrawFrame += this._handleDrawFrame;
}
public readonly Window _window;

12
Assets/UIWidgets/ui/window.cs


get { return this._devicePixelRatio; }
}
public double _devicePixelRatio = 1.0;
protected double _devicePixelRatio = 1.0;
public Size _physicalSize = Size.zero;
protected Size _physicalSize = Size.zero;
public VoidCallback onMetricsChanged {
get { return this._onMetricsChanged; }

public VoidCallback _onMetricsChanged;
VoidCallback _onMetricsChanged;
public FrameCallback onBeginFrame {
get { return this._onBeginFrame; }

public FrameCallback _onBeginFrame;
FrameCallback _onBeginFrame;
public VoidCallback onDrawFrame {
get { return this._onDrawFrame; }

public VoidCallback _onDrawFrame;
VoidCallback _onDrawFrame;
public PointerDataPacketCallback onPointerEvent {
get { return this._onPointerEvent; }

public PointerDataPacketCallback _onPointerEvent;
PointerDataPacketCallback _onPointerEvent;
public abstract void scheduleFrame();

90
Assets/UIWidgets/gestures/drag_details.cs


using System;
using UIWidgets.foundation;
using UIWidgets.ui;
namespace UIWidgets.gestures {
public class DragDownDetails {
public DragDownDetails(
Offset globalPosition = null
) {
this.globalPosition = globalPosition ?? Offset.zero;
}
public readonly Offset globalPosition;
public override string ToString() {
return this.GetType() + "(" + this.globalPosition + ")";
}
}
public delegate void GestureDragDownCallback(DragDownDetails details);
public class DragStartDetails {
public DragStartDetails(DateTime sourceTimeStamp, Offset globalPosition = null) {
this.sourceTimeStamp = sourceTimeStamp;
this.globalPosition = globalPosition ?? Offset.zero;
}
public readonly DateTime sourceTimeStamp;
public readonly Offset globalPosition;
public override string ToString() {
return this.GetType() + "(" + this.globalPosition + ")";
}
}
public delegate void GestureDragStartCallback(DragStartDetails details);
public class DragUpdateDetails {
public DragUpdateDetails(
DateTime sourceTimeStamp,
Offset delta = null,
double? primaryDelta = null,
Offset globalPosition = null) {
this.sourceTimeStamp = sourceTimeStamp;
this.delta = delta ?? Offset.zero;
this.primaryDelta = primaryDelta;
this.globalPosition = globalPosition ?? Offset.zero;
D.assert(primaryDelta == null
|| primaryDelta == this.delta.dx && this.delta.dy == 0.0
|| primaryDelta == this.delta.dy && this.delta.dx == 0.0);
}
public readonly DateTime sourceTimeStamp;
public readonly Offset delta;
public readonly double? primaryDelta;
public readonly Offset globalPosition;
public override string ToString() {
return this.GetType() + "(" + this.delta + ")";
}
}
public delegate void GestureDragUpdateCallback(DragUpdateDetails details);
public class DragEndDetails {
public DragEndDetails(
Velocity velocity = null,
double? primaryVelocity = null
) {
this.velocity = velocity ?? Velocity.zero;
this.primaryVelocity = primaryVelocity;
D.assert(primaryVelocity == null
|| primaryVelocity == this.velocity.pixelsPerSecond.dx
|| primaryVelocity == this.velocity.pixelsPerSecond.dy);
}
public readonly Velocity velocity;
public readonly double? primaryVelocity;
public override string ToString() {
return this.GetType() + "(" + this.velocity + ")";
}
}
}

3
Assets/UIWidgets/gestures/drag_details.cs.meta


fileFormatVersion: 2
guid: 4283bd1f6f7945578b47e7ad21999e7c
timeCreated: 1536330559

186
Assets/UIWidgets/gestures/lsq_resolver.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UIWidgets.foundation;
namespace UIWidgets.gestures {
class _Vector {
internal _Vector(int size) {
this._offset = 0;
this._length = size;
this._elements = Enumerable.Repeat(0.0, size).ToList();
}
private _Vector(List<double> values, int offset, int length) {
this._offset = offset;
this._length = length;
this._elements = values;
}
internal static _Vector fromVOL(List<double> values, int offset, int length) {
return new _Vector(values, offset, length);
}
readonly int _offset;
readonly int _length;
readonly List<double> _elements;
public double this[int i] {
get { return this._elements[i + this._offset]; }
set { this._elements[i + this._offset] = value; }
}
public static double operator *(_Vector a, _Vector b) {
double result = 0.0;
for (int i = 0; i < a._length; i += 1)
result += a[i] * b[i];
return result;
}
public double norm() {
return Math.Sqrt(this * this);
}
}
class _Matrix {
internal _Matrix(int rows, int cols) {
this._columns = cols;
this._elements = Enumerable.Repeat(0.0, rows * cols).ToList();
}
readonly int _columns;
readonly List<double> _elements;
public double this[int row, int col] {
get { return this._elements[row * this._columns + col]; }
set { this._elements[row * this._columns + col] = value; }
}
public _Vector getRow(int row) {
return _Vector.fromVOL(
this._elements,
row * this._columns,
this._columns
);
}
}
public class PolynomialFit {
public PolynomialFit(int degree) {
this.coefficients = Enumerable.Repeat(0.0, degree + 1).ToList();
}
public readonly List<double> coefficients;
public double confidence;
}
public class LeastSquaresSolver {
public LeastSquaresSolver(List<double> x, List<double> y, List<double> w) {
D.assert(x != null && y != null && w != null);
D.assert(x.Count == y.Count);
D.assert(y.Count == w.Count);
this.x = x;
this.y = y;
this.w = w;
}
public readonly List<double> x;
public readonly List<double> y;
public readonly List<double> w;
/// Fits a polynomial of the given degree to the data points.
public PolynomialFit solve(int degree) {
if (degree > this.x.Count) {
// Not enough data to fit a curve.
return null;
}
PolynomialFit result = new PolynomialFit(degree);
// Shorthands for the purpose of notation equivalence to original C++ code.
int m = x.Count;
int n = degree + 1;
// Expand the X vector to a matrix A, pre-multiplied by the weights.
_Matrix a = new _Matrix(n, m);
for (int h = 0; h < m; h += 1) {
a[0, h] = this.w[h];
for (int i = 1; i < n; i += 1)
a[i, h] = a[i - 1, h] * this.x[h];
}
// Apply the Gram-Schmidt process to A to obtain its QR decomposition.
// Orthonormal basis, column-major ordVectorer.
_Matrix q = new _Matrix(n, m);
// Upper triangular matrix, row-major order.
_Matrix r = new _Matrix(n, n);
for (int j = 0; j < n; j += 1) {
for (int h = 0; h < m; h += 1)
q[j, h] = a[j, h];
for (int i = 0; i < j; i += 1) {
double dot = q.getRow(j) * q.getRow(i);
for (int h = 0; h < m; h += 1)
q[j, h] = q[j, h] - dot * q[i, h];
}
double norm = q.getRow(j).norm();
if (norm < 0.000001) {
// Vectors are linearly dependent or zero so no solution.
return null;
}
double inverseNorm = 1.0 / norm;
for (int h = 0; h < m; h += 1)
q[j, h] = q[j, h] * inverseNorm;
for (int i = 0; i < n; i += 1)
r[j, i] = i < j ? 0.0 : q.getRow(j) * a.getRow(i);
}
// Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
// We just work from bottom-right to top-left calculating B's coefficients.
_Vector wy = new _Vector(m);
for (int h = 0; h < m; h += 1)
wy[h] = y[h] * w[h];
for (int i = n - 1; i >= 0; i -= 1) {
result.coefficients[i] = q.getRow(i) * wy;
for (int j = n - 1; j > i; j -= 1)
result.coefficients[i] -= r[i, j] * result.coefficients[j];
result.coefficients[i] /= r[i, i];
}
// Calculate the coefficient of determination (confidence) as:
// 1 - (sumSquaredError / sumSquaredTotal)
// ...where sumSquaredError is the residual sum of squares (variance of the
// error), and sumSquaredTotal is the total sum of squares (variance of the
// data) where each has been weighted.
double yMean = 0.0;
for (int h = 0; h < m; h += 1)
yMean += y[h];
yMean /= m;
double sumSquaredError = 0.0;
double sumSquaredTotal = 0.0;
for (int h = 0; h < m; h += 1) {
double term = 1.0;
double err = y[h] - result.coefficients[0];
for (int i = 1; i < n; i += 1) {
term *= x[h];
err -= term * result.coefficients[i];
}
sumSquaredError += w[h] * w[h] * err * err;
double v = y[h] - yMean;
sumSquaredTotal += w[h] * w[h] * v * v;
}
result.confidence = sumSquaredTotal <= 0.000001 ? 1.0 : 1.0 - (sumSquaredError / sumSquaredTotal);
return result;
}
}
}

3
Assets/UIWidgets/gestures/lsq_resolver.cs.meta


fileFormatVersion: 2
guid: 575547b88e714c13b02cc94a7fac6bb2
timeCreated: 1536333643

281
Assets/UIWidgets/gestures/monodrag.cs


using System;
using System.Collections.Generic;
using UIWidgets.foundation;
using UIWidgets.ui;
namespace UIWidgets.gestures {
enum _DragState {
ready,
possible,
accepted,
}
public delegate void GestureDragEndCallback(DragEndDetails details);
public delegate void GestureDragCancelCallback();
public abstract class DragGestureRecognizer : OneSequenceGestureRecognizer {
public DragGestureRecognizer(GestureBinding binding, object debugOwner = null)
: base(binding: binding, debugOwner: debugOwner) {
}
public GestureDragDownCallback onDown;
public GestureDragStartCallback onStart;
public GestureDragUpdateCallback onUpdate;
public GestureDragEndCallback onEnd;
public GestureDragCancelCallback onCancel;
public double? minFlingDistance;
public double? minFlingVelocity;
public double? maxFlingVelocity;
_DragState _state = _DragState.ready;
Offset _initialPosition;
protected Offset _pendingDragOffset;
DateTime _lastPendingEventTimestamp;
protected abstract bool _isFlingGesture(VelocityEstimate estimate);
protected abstract Offset _getDeltaForDetails(Offset delta);
protected abstract double? _getPrimaryValueFromOffset(Offset value);
protected abstract bool _hasSufficientPendingDragDeltaToAccept { get; }
readonly Dictionary<int, VelocityTracker> _velocityTrackers = new Dictionary<int, VelocityTracker>();
public override void addPointer(PointerDownEvent evt) {
this.startTrackingPointer(evt.pointer);
this._velocityTrackers[evt.pointer] = new VelocityTracker();
if (this._state == _DragState.ready) {
this._state = _DragState.possible;
this._initialPosition = evt.position;
this._pendingDragOffset = Offset.zero;
this._lastPendingEventTimestamp = evt.timeStamp;
if (this.onDown != null) {
this.invokeCallback<object>("onDown",
() => {
this.onDown(new DragDownDetails(globalPosition: this._initialPosition));
return null;
});
}
} else if (this._state == _DragState.accepted) {
this.resolve(GestureDisposition.accepted);
}
}
protected override void handleEvent(PointerEvent evt) {
D.assert(this._state != _DragState.ready);
if (!evt.synthesized
&& (evt is PointerDownEvent || evt is PointerMoveEvent)) {
var tracker = this._velocityTrackers[evt.pointer];
D.assert(tracker != null);
tracker.addPosition(evt.timeStamp, evt.position);
}
if (evt is PointerMoveEvent) {
Offset delta = evt.delta;
if (this._state == _DragState.accepted) {
if (this.onUpdate != null) {
this.invokeCallback<object>("onUpdate", () => {
this.onUpdate(new DragUpdateDetails(
sourceTimeStamp: evt.timeStamp,
delta: this._getDeltaForDetails(delta),
primaryDelta: this._getPrimaryValueFromOffset(delta),
globalPosition: evt.position
));
return null;
});
}
} else {
this._pendingDragOffset += delta;
this._lastPendingEventTimestamp = evt.timeStamp;
if (this._hasSufficientPendingDragDeltaToAccept) {
this.resolve(GestureDisposition.accepted);
}
}
}
this.stopTrackingIfPointerNoLongerDown(evt);
}
public override void acceptGesture(int pointer) {
if (this._state != _DragState.accepted) {
this._state = _DragState.accepted;
Offset delta = this._pendingDragOffset;
var timestamp = this._lastPendingEventTimestamp;
this._pendingDragOffset = Offset.zero;
this._lastPendingEventTimestamp = default(DateTime);
if (this.onStart != null) {
this.invokeCallback<object>("onStart", () => {
this.onStart(new DragStartDetails(
sourceTimeStamp: timestamp,
globalPosition: this._initialPosition
));
return null;
});
}
if (delta != Offset.zero && this.onUpdate != null) {
this.invokeCallback<object>("onUpdate", () => {
this.onUpdate(new DragUpdateDetails(
sourceTimeStamp: timestamp,
delta: this._getDeltaForDetails(delta),
primaryDelta: this._getPrimaryValueFromOffset(delta),
globalPosition: this._initialPosition
));
return null;
});
}
}
}
public override void rejectGesture(int pointer) {
this.stopTrackingPointer(pointer);
}
protected override void didStopTrackingLastPointer(int pointer) {
if (this._state == _DragState.possible) {
this.resolve(GestureDisposition.rejected);
this._state = _DragState.ready;
if (this.onCancel != null) {
this.invokeCallback<object>("onCancel", () => {
this.onCancel();
return null;
});
}
return;
}
bool wasAccepted = this._state == _DragState.accepted;
this._state = _DragState.ready;
if (wasAccepted && this.onEnd != null) {
var tracker = this._velocityTrackers[pointer];
D.assert(tracker != null);
var estimate = tracker.getVelocityEstimate();
if (estimate != null && this._isFlingGesture(estimate)) {
Velocity velocity = new Velocity(pixelsPerSecond: estimate.pixelsPerSecond)
.clampMagnitude(this.minFlingVelocity ?? Constants.kMinFlingVelocity,
this.maxFlingVelocity ?? Constants.kMaxFlingVelocity);
this.invokeCallback<object>("onEnd", () => {
this.onEnd(new DragEndDetails(
velocity: velocity,
primaryVelocity: this._getPrimaryValueFromOffset(velocity.pixelsPerSecond)
));
return null;
}, debugReport: () =>
string.Format("{0}; fling at {1}.", estimate, velocity));
} else {
this.invokeCallback<object>("onEnd", () => {
this.onEnd(new DragEndDetails(
velocity: Velocity.zero,
primaryVelocity: 0.0
));
return null;
}, debugReport: () =>
estimate == null
? "Could not estimate velocity."
: estimate + "; judged to not be a fling."
);
}
}
this._velocityTrackers.Clear();
}
public override void dispose() {
this._velocityTrackers.Clear();
base.dispose();
}
}
public class VerticalDragGestureRecognizer : DragGestureRecognizer {
public VerticalDragGestureRecognizer(GestureBinding binding, Object debugOwner = null)
: base(binding: binding, debugOwner: debugOwner) {
}
protected override bool _isFlingGesture(VelocityEstimate estimate) {
double minVelocity = this.minFlingVelocity ?? Constants.kMinFlingVelocity;
double minDistance = this.minFlingDistance ?? Constants.kTouchSlop;
return Math.Abs(estimate.pixelsPerSecond.dy) > minVelocity && Math.Abs(estimate.offset.dy) > minDistance;
}
protected override bool _hasSufficientPendingDragDeltaToAccept {
get { return Math.Abs(this._pendingDragOffset.dy) > Constants.kTouchSlop; }
}
protected override Offset _getDeltaForDetails(Offset delta) {
return new Offset(0.0, delta.dy);
}
protected override double? _getPrimaryValueFromOffset(Offset value) {
return value.dy;
}
public override string debugDescription {
get { return "vertical drag"; }
}
}
public class HorizontalDragGestureRecognizer : DragGestureRecognizer {
public HorizontalDragGestureRecognizer(GestureBinding binding, Object debugOwner = null)
: base(binding: binding, debugOwner: debugOwner) {
}
protected override bool _isFlingGesture(VelocityEstimate estimate) {
double minVelocity = this.minFlingVelocity ?? Constants.kMinFlingVelocity;
double minDistance = this.minFlingDistance ?? Constants.kTouchSlop;
return Math.Abs(estimate.pixelsPerSecond.dx) > minVelocity && Math.Abs(estimate.offset.dx) > minDistance;
}
protected override bool _hasSufficientPendingDragDeltaToAccept {
get { return Math.Abs(this._pendingDragOffset.dx) > Constants.kTouchSlop; }
}
protected override Offset _getDeltaForDetails(Offset delta) {
return new Offset(delta.dx, 0.0);
}
protected override double? _getPrimaryValueFromOffset(Offset value) {
return value.dx;
}
public override string debugDescription {
get { return "horizontal drag"; }
}
}
public class PanGestureRecognizer : DragGestureRecognizer {
public PanGestureRecognizer(GestureBinding binding, Object debugOwner = null)
: base(binding: binding, debugOwner: debugOwner) {
}
protected override bool _isFlingGesture(VelocityEstimate estimate) {
double minVelocity = this.minFlingVelocity ?? Constants.kMinFlingVelocity;
double minDistance = this.minFlingDistance ?? Constants.kTouchSlop;
return estimate.pixelsPerSecond.distanceSquared > minVelocity * minVelocity
&& estimate.offset.distanceSquared > minDistance * minDistance;
}
protected override bool _hasSufficientPendingDragDeltaToAccept {
get { return this._pendingDragOffset.distance > Constants.kPanSlop; }
}
protected override Offset _getDeltaForDetails(Offset delta) {
return delta;
}
protected override double? _getPrimaryValueFromOffset(Offset value) {
return null;
}
public override string debugDescription {
get { return "pan"; }
}
}
}

3
Assets/UIWidgets/gestures/monodrag.cs.meta


fileFormatVersion: 2
guid: 145abf9020044c79bf9227730292796d
timeCreated: 1536328579

214
Assets/UIWidgets/gestures/velocity_tracker.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UIWidgets.foundation;
using UIWidgets.ui;
namespace UIWidgets.gestures {
public class Velocity : IEquatable<Velocity> {
public Velocity(
Offset pixelsPerSecond = null
) {
this.pixelsPerSecond = pixelsPerSecond ?? Offset.zero;
}
public static readonly Velocity zero = new Velocity();
public readonly Offset pixelsPerSecond;
public static Velocity operator -(Velocity a) {
return new Velocity(pixelsPerSecond: -a.pixelsPerSecond);
}
public static Velocity operator -(Velocity a, Velocity b) {
return new Velocity(
pixelsPerSecond: a.pixelsPerSecond - b.pixelsPerSecond);
}
public static Velocity operator +(Velocity a, Velocity b) {
return new Velocity(
pixelsPerSecond: a.pixelsPerSecond + b.pixelsPerSecond);
}
public Velocity clampMagnitude(double minValue, double maxValue) {
D.assert(minValue >= 0.0);
D.assert(maxValue >= 0.0 && maxValue >= minValue);
double valueSquared = this.pixelsPerSecond.distanceSquared;
if (valueSquared > maxValue * maxValue) {
return new Velocity(pixelsPerSecond: (this.pixelsPerSecond / this.pixelsPerSecond.distance) * maxValue);
}
if (valueSquared < minValue * minValue) {
return new Velocity(pixelsPerSecond: (this.pixelsPerSecond / this.pixelsPerSecond.distance) * minValue);
}
return this;
}
public bool Equals(Velocity other) {
if (object.ReferenceEquals(null, other)) return false;
if (object.ReferenceEquals(this, other)) return true;
return object.Equals(this.pixelsPerSecond, other.pixelsPerSecond);
}
public override bool Equals(object obj) {
if (object.ReferenceEquals(null, obj)) return false;
if (object.ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return this.Equals((Velocity) obj);
}
public override int GetHashCode() {
return (this.pixelsPerSecond != null ? this.pixelsPerSecond.GetHashCode() : 0);
}
public static bool operator ==(Velocity left, Velocity right) {
return object.Equals(left, right);
}
public static bool operator !=(Velocity left, Velocity right) {
return !object.Equals(left, right);
}
public override string ToString() {
return string.Format("Velocity({0:F1}, {1:F1})", this.pixelsPerSecond.dx, this.pixelsPerSecond.dy);
}
}
public class VelocityEstimate {
public VelocityEstimate(
Offset pixelsPerSecond,
double confidence,
TimeSpan duration,
Offset offset
) {
D.assert(pixelsPerSecond != null);
D.assert(offset != null);
this.pixelsPerSecond = pixelsPerSecond;
this.confidence = confidence;
this.duration = duration;
this.offset = offset;
}
public readonly Offset pixelsPerSecond;
public readonly double confidence;
public readonly TimeSpan duration;
public readonly Offset offset;
public override string ToString() {
return string.Format("VelocityEstimate({0:F1}, {1:F1}; offset: {2}, duration: {3}, confidence: {4:F1})",
this.pixelsPerSecond.dx, this.pixelsPerSecond.dy, this.offset, this.duration, this.confidence);
}
}
class _PointAtTime {
internal _PointAtTime(Offset point, DateTime time) {
D.assert(point != null);
this.point = point;
this.time = time;
}
public readonly Offset point;
public readonly DateTime time;
public override string ToString() {
return string.Format("_PointAtTime({0} at {1})", this.point, this.time);
}
}
public class VelocityTracker {
const int _assumePointerMoveStoppedMilliseconds = 40;
const int _historySize = 20;
const int _horizonMilliseconds = 100;
const int _minSampleSize = 3;
readonly List<_PointAtTime> _samples = Enumerable.Repeat<_PointAtTime>(null, _historySize).ToList();
int _index = 0;
public void addPosition(DateTime time, Offset position) {
this._index += 1;
if (this._index == _historySize) {
this._index = 0;
}
this._samples[this._index] = new _PointAtTime(position, time);
}
public VelocityEstimate getVelocityEstimate() {
List<double> x = new List<double>();
List<double> y = new List<double>();
List<double> w = new List<double>();
List<double> time = new List<double>();
int sampleCount = 0;
int index = this._index;
_PointAtTime newestSample = this._samples[index];
if (newestSample == null) {
return null;
}
_PointAtTime previousSample = newestSample;
_PointAtTime oldestSample = newestSample;
do {
_PointAtTime sample = this._samples[index];
if (sample == null)
break;
double age = (newestSample.time - sample.time).TotalMilliseconds;
double delta = Math.Abs((sample.time - previousSample.time).TotalMilliseconds);
previousSample = sample;
if (age > _horizonMilliseconds || delta > _assumePointerMoveStoppedMilliseconds) {
break;
}
oldestSample = sample;
Offset position = sample.point;
x.Add(position.dx);
y.Add(position.dy);
w.Add(1.0);
time.Add(-age);
index = (index == 0 ? _historySize : index) - 1;
sampleCount += 1;
} while (sampleCount < _historySize);
if (sampleCount >= _minSampleSize) {
LeastSquaresSolver xSolver = new LeastSquaresSolver(time, x, w);
PolynomialFit xFit = xSolver.solve(2);
if (xFit != null) {
LeastSquaresSolver ySolver = new LeastSquaresSolver(time, y, w);
PolynomialFit yFit = ySolver.solve(2);
if (yFit != null) {
return new VelocityEstimate(
pixelsPerSecond: new Offset(xFit.coefficients[1] * 1000, yFit.coefficients[1] * 1000),
confidence: xFit.confidence * yFit.confidence,
duration: newestSample.time - oldestSample.time,
offset: newestSample.point - oldestSample.point
);
}
}
}
return new VelocityEstimate(
pixelsPerSecond: Offset.zero,
confidence: 1.0,
duration: newestSample.time - oldestSample.time,
offset: newestSample.point - oldestSample.point
);
}
public Velocity getVelocity() {
VelocityEstimate estimate = this.getVelocityEstimate();
if (estimate == null || estimate.pixelsPerSecond == Offset.zero) {
return Velocity.zero;
}
return new Velocity(pixelsPerSecond: estimate.pixelsPerSecond);
}
}
}

3
Assets/UIWidgets/gestures/velocity_tracker.cs.meta


fileFormatVersion: 2
guid: d01877db8a7341e491a67f84ed3ab604
timeCreated: 1536331325
正在加载...
取消
保存