Commit e0107b05 authored by Ian Hickson's avatar Ian Hickson

Merge pull request #756 from Hixie/PointerInputEvent.kind

PointerInput refactor
parents bc1b47e9 f1625556
......@@ -84,8 +84,8 @@ class MineDiggerState extends State<MineDigger> {
}
}
PointerEventListener _pointerDownHandlerFor(int posX, int posY) {
return (PointerInputEvent event) {
PointerDownEventListener _pointerDownHandlerFor(int posX, int posY) {
return (PointerDownEvent event) {
if (event.buttons == 1) {
probe(posX, posY);
} else if (event.buttons == 2) {
......@@ -190,7 +190,7 @@ class MineDiggerState extends State<MineDigger> {
);
}
void handleToolbarPointerDown(PointerInputEvent event) {
void handleToolbarPointerDown(PointerDownEvent event) {
setState(() {
resetGame();
});
......
......@@ -518,10 +518,11 @@ class RenderSolidColor extends RenderDecoratedSector {
deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
}
void handleEvent(InputEvent event, HitTestEntry entry) {
if (event.type == 'pointerdown')
void handleEvent(PointerEvent event, HitTestEntry entry) {
if (event is PointerDownEvent) {
decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
else if (event.type == 'pointerup')
} else if (event is PointerUpEvent) {
decoration = new BoxDecoration(backgroundColor: backgroundColor);
}
}
}
......@@ -41,10 +41,11 @@ class RenderSolidColorBox extends RenderDecoratedBox {
size = constraints.constrain(desiredSize);
}
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown')
void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
if (event is PointerDownEvent) {
decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
else if (event.type == 'pointerup')
} else if (event is PointerUpEvent) {
decoration = new BoxDecoration(backgroundColor: backgroundColor);
}
}
}
......@@ -23,8 +23,8 @@ class Dot {
Dot({ Color color }) : _paint = new Paint()..color = color;
void update(PointerInputEvent event) {
position = new Point(event.x, event.y);
void update(PointerEvent event) {
position = event.position;
radius = 5 + (95 * event.pressure);
}
......@@ -36,26 +36,21 @@ class Dot {
class RenderTouchDemo extends RenderBox {
final Map<int, Dot> dots = <int, Dot>{};
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event is PointerInputEvent) {
switch (event.type) {
case 'pointerdown':
void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
if (event is PointerDownEvent) {
Color color = kColors[event.pointer.remainder(kColors.length)];
dots[event.pointer] = new Dot(color: color)..update(event);
break;
case 'pointerup':
} else if (event is PointerUpEvent) {
dots.remove(event.pointer);
break;
case 'pointercancel':
} else if (event is PointerCancelEvent) {
dots.clear();
break;
case 'pointermove':
} else if (event is PointerMoveEvent) {
dots[event.pointer].update(event);
break;
} else {
return;
}
markNeedsPaint();
}
}
void performLayout() {
size = constraints.biggest;
......
......@@ -4,6 +4,7 @@
import 'dart:ui' as ui;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
......@@ -121,9 +122,9 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
});
}
void handlePointerDown(GlobalKey target, PointerInputEvent event) {
void handlePointerDown(GlobalKey target, PointerDownEvent event) {
setState(() {
markers[MarkerType.touch] = new Point(event.x, event.y);
markers[MarkerType.touch] = event.position;
final RenderBox box = target.currentContext.findRenderObject();
markers[MarkerType.topLeft] = box.localToGlobal(new Point(0.0, 0.0));
final Size size = box.size;
......@@ -139,7 +140,7 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
CardModel cardModel = cardModels[index];
return new Listener(
key: cardModel.key,
onPointerDown: (PointerInputEvent e) { return handlePointerDown(cardModel.targetKey, e); },
onPointerDown: (PointerDownEvent event) { return handlePointerDown(cardModel.targetKey, event); },
child: new Card(
key: cardModel.targetKey,
color: cardModel.color,
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'arena.dart';
import 'recognizer.dart';
import 'constants.dart';
......@@ -16,21 +14,22 @@ enum DragState {
accepted
}
typedef void GestureDragStartCallback(ui.Point globalPosition);
typedef void GestureDragStartCallback(Point globalPosition);
typedef void GestureDragUpdateCallback(double delta);
typedef void GestureDragEndCallback(ui.Offset velocity);
typedef void GestureDragEndCallback(Offset velocity);
typedef void GesturePanStartCallback(ui.Point globalPosition);
typedef void GesturePanUpdateCallback(ui.Offset delta);
typedef void GesturePanEndCallback(ui.Offset velocity);
typedef void GesturePanStartCallback(Point globalPosition);
typedef void GesturePanUpdateCallback(Offset delta);
typedef void GesturePanEndCallback(Offset velocity);
typedef void _GesturePolymorphicUpdateCallback<T>(T delta);
bool _isFlingGesture(GestureVelocity velocity) {
double velocitySquared = velocity.x * velocity.x + velocity.y * velocity.y;
return velocity.isValid &&
velocitySquared > kMinFlingVelocity * kMinFlingVelocity &&
velocitySquared < kMaxFlingVelocity * kMaxFlingVelocity;
bool _isFlingGesture(Offset velocity) {
if (velocity == null)
return false;
double velocitySquared = velocity.dx * velocity.dx + velocity.dy * velocity.dy;
return velocitySquared > kMinFlingVelocity * kMinFlingVelocity
&& velocitySquared < kMaxFlingVelocity * kMaxFlingVelocity;
}
abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGestureRecognizer {
......@@ -42,16 +41,16 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
GestureDragEndCallback onEnd;
DragState _state = DragState.ready;
ui.Point _initialPosition;
Point _initialPosition;
T _pendingDragDelta;
T get _initialPendingDragDelta;
T _getDragDelta(PointerInputEvent event);
T _getDragDelta(PointerEvent event);
bool get _hasSufficientPendingDragDeltaToAccept;
Map<int, VelocityTracker> _velocityTrackers = new Map<int, VelocityTracker>();
void addPointer(PointerInputEvent event) {
void addPointer(PointerEvent event) {
startTrackingPointer(event.pointer);
_velocityTrackers[event.pointer] = new VelocityTracker();
if (_state == DragState.ready) {
......@@ -61,12 +60,12 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
}
}
void handleEvent(PointerInputEvent event) {
void handleEvent(PointerEvent event) {
assert(_state != DragState.ready);
if (event.type == 'pointermove') {
if (event is PointerMoveEvent) {
VelocityTracker tracker = _velocityTrackers[event.pointer];
assert(tracker != null);
tracker.addPosition(event.timeStamp, event.x, event.y);
tracker.addPosition(event.timeStamp, event.position);
T delta = _getDragDelta(event);
if (_state == DragState.accepted) {
if (onUpdate != null)
......@@ -104,11 +103,10 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
VelocityTracker tracker = _velocityTrackers[pointer];
assert(tracker != null);
GestureVelocity gestureVelocity = tracker.getVelocity();
ui.Offset velocity = ui.Offset.zero;
if (_isFlingGesture(gestureVelocity))
velocity = new ui.Offset(gestureVelocity.x, gestureVelocity.y);
Offset velocity = tracker.getVelocity();
if (velocity != null && _isFlingGesture(velocity))
onEnd(velocity);
onEnd(Offset.zero);
}
_velocityTrackers.clear();
}
......@@ -128,7 +126,7 @@ class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
double get _initialPendingDragDelta => 0.0;
double _getDragDelta(PointerInputEvent event) => event.dy;
double _getDragDelta(PointerEvent event) => event.delta.dy;
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
}
......@@ -141,11 +139,11 @@ class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
double get _initialPendingDragDelta => 0.0;
double _getDragDelta(PointerInputEvent event) => event.dx;
double _getDragDelta(PointerEvent event) => event.delta.dx;
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
}
class PanGestureRecognizer extends _DragGestureRecognizer<ui.Offset> {
class PanGestureRecognizer extends _DragGestureRecognizer<Offset> {
PanGestureRecognizer({
PointerRouter router,
GesturePanStartCallback onStart,
......@@ -153,8 +151,8 @@ class PanGestureRecognizer extends _DragGestureRecognizer<ui.Offset> {
GesturePanEndCallback onEnd
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
ui.Offset get _initialPendingDragDelta => ui.Offset.zero;
ui.Offset _getDragDelta(PointerInputEvent event) => new ui.Offset(event.dx, event.dy);
Offset get _initialPendingDragDelta => Offset.zero;
Offset _getDragDelta(PointerEvent event) => event.delta;
bool get _hasSufficientPendingDragDeltaToAccept {
return _pendingDragDelta.distance > kPanSlop;
}
......
......@@ -18,11 +18,12 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
void didExceedDeadline() {
resolve(GestureDisposition.accepted);
if (onLongPress != null)
onLongPress();
}
void handlePrimaryPointer(PointerInputEvent event) {
if (event.type == 'pointerup')
void handlePrimaryPointer(PointerEvent event) {
if (event is PointerUpEvent)
resolve(GestureDisposition.rejected);
}
}
......@@ -15,16 +15,22 @@ class _Vector {
_Vector.fromVOL(List<double> values, int offset, int length)
: _offset = offset, _length = length, _elements = values;
final int _offset;
int get length => _length;
final int _length;
final List<double> _elements;
operator [](int i) => _elements[i + _offset];
operator []=(int i, double value) => _elements[i + _offset] = value;
double operator [](int i) => _elements[i + _offset];
void operator []=(int i, double value) {
_elements[i + _offset] = value;
}
operator *(_Vector a) {
double operator *(_Vector a) {
double result = 0.0;
for (int i = 0; i < _length; i++) {
for (int i = 0; i < _length; i += 1)
result += this[i] * a[i];
}
return result;
}
......@@ -39,10 +45,6 @@ class _Vector {
}
return result;
}
final int _offset;
final int _length;
final List<double> _elements;
}
class _Matrix {
......@@ -51,6 +53,10 @@ class _Matrix {
_columns = cols,
_elements = new Float64List(rows * cols);
final int _rows;
final int _columns;
final List<double> _elements;
double get(int row, int col) => _elements[row * _columns + col];
void set(int row, int col, double value) {
_elements[row * _columns + col] = value;
......@@ -75,10 +81,6 @@ class _Matrix {
}
return result;
}
final int _rows;
final int _columns;
final List<double> _elements;
}
class PolynomialFit {
......@@ -110,12 +112,11 @@ class LeastSquaresSolver {
// 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++) {
for (int h = 0; h < m; h += 1) {
a.set(0, h, w[h]);
for (int i = 1; i < n; i++) {
for (int i = 1; i < n; i += 1)
a.set(i, h, a.get(i - 1, h) * x[h]);
}
}
// Apply the Gram-Schmidt process to A to obtain its QR decomposition.
......@@ -123,16 +124,14 @@ class LeastSquaresSolver {
_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++) {
for (int h = 0; h < m; h++) {
for (int j = 0; j < n; j += 1) {
for (int h = 0; h < m; h += 1)
q.set(j, h, a.get(j, h));
}
for (int i = 0; i < j; i++) {
for (int i = 0; i < j; i += 1) {
double dot = q.getRow(j) * q.getRow(i);
for (int h = 0; h < m; h++) {
for (int h = 0; h < m; h += 1)
q.set(j, h, q.get(j, h) - dot * q.get(i, h));
}
}
double norm = q.getRow(j).norm();
if (norm < 0.000001) {
......@@ -141,56 +140,50 @@ class LeastSquaresSolver {
}
double inverseNorm = 1.0 / norm;
for (int h = 0; h < m; h++) {
for (int h = 0; h < m; h += 1)
q.set(j, h, q.get(j, h) * inverseNorm);
}
for (int i = 0; i < n; i++) {
for (int i = 0; i < n; i += 1)
r.set(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++) {
for (int h = 0; h < m; h += 1)
wy[h] = y[h] * w[h];
}
for (int i = n; i-- != 0;) {
for (int i = n - 1; i >= 0; i -= 1) {
result.coefficients[i] = q.getRow(i) * wy;
for (int j = n - 1; j > i; j--) {
for (int j = n - 1; j > i; j -= 1)
result.coefficients[i] -= r.get(i, j) * result.coefficients[j];
}
result.coefficients[i] /= r.get(i, i);
}
// Calculate the coefficient of determination (confidence) as:
// 1 - (sumSquaredError / sumSquaredTotal)
// where sumSquaredError is the residual sum of squares (variance of the
// ...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++) {
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++) {
double err = y[h] - result.coefficients[0];
for (int h = 0; h < m; h += 1) {
double term = 1.0;
for (int i = 1; i < n; i++) {
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;
final double v = y[h] - yMean;
sumSquaredTotal += w[h] * w[h] * v * v;
}
result.confidence = sumSquaredTotal > 0.000001 ?
1.0 - (sumSquaredError / sumSquaredTotal) :
1.0;
result.confidence = sumSquaredTotal <= 0.000001 ? 1.0 :
1.0 - (sumSquaredError / sumSquaredTotal);
return result;
}
......
......@@ -22,11 +22,9 @@ typedef void GestureMultiTapCancelCallback(int pointer);
/// larger gesture.
class _TapTracker {
_TapTracker({ PointerInputEvent event, this.entry })
_TapTracker({ PointerDownEvent event, this.entry })
: pointer = event.pointer,
_initialPosition = event.position {
assert(event.type == 'pointerdown');
}
_initialPosition = event.position;
final int pointer;
final GestureArenaEntry entry;
......@@ -48,7 +46,7 @@ class _TapTracker {
}
}
bool isWithinTolerance(PointerInputEvent event, double tolerance) {
bool isWithinTolerance(PointerEvent event, double tolerance) {
Offset offset = event.position - _initialPosition;
return offset.distance <= tolerance;
}
......@@ -92,7 +90,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
_TapTracker _firstTap;
final Map<int, _TapTracker> _trackers = new Map<int, _TapTracker>();
void addPointer(PointerInputEvent event) {
void addPointer(PointerEvent event) {
// Ignore out-of-bounds second taps
if (_firstTap != null &&
!_firstTap.isWithinTolerance(event, kDoubleTapSlop))
......@@ -106,23 +104,19 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
tracker.startTrackingPointer(_router, handleEvent);
}
void handleEvent(PointerInputEvent event) {
void handleEvent(PointerEvent event) {
_TapTracker tracker = _trackers[event.pointer];
assert(tracker != null);
switch (event.type) {
case 'pointerup':
if (event is PointerUpEvent) {
if (_firstTap == null)
_registerFirstTap(tracker);
else
_registerSecondTap(tracker);
break;
case 'pointermove':
} else if (event is PointerMoveEvent) {
if (!tracker.isWithinTolerance(event, kDoubleTapTouchSlop))
_reject(tracker);
break;
case 'pointercancel':
} else if (event is PointerCancelEvent) {
_reject(tracker);
break;
}
}
......@@ -228,7 +222,7 @@ class _TapGesture extends _TapTracker {
_TapGesture({
MultiTapGestureRecognizer gestureRecognizer,
PointerInputEvent event,
PointerEvent event,
Duration longTapDelay
}) : gestureRecognizer = gestureRecognizer,
_lastPosition = event.position,
......@@ -250,16 +244,16 @@ class _TapGesture extends _TapTracker {
Point _lastPosition;
Point _finalPosition;
void handleEvent(PointerInputEvent event) {
void handleEvent(PointerEvent event) {
assert(event.pointer == pointer);
if (event.type == 'pointermove') {
if (event is PointerMoveEvent) {
if (!isWithinTolerance(event, kTouchSlop))
cancel();
else
_lastPosition = event.position;
} else if (event.type == 'pointercancel') {
} else if (event is PointerCancelEvent) {
cancel();
} else if (event.type == 'pointerup') {
} else if (event is PointerUpEvent) {
stopTrackingPointer(gestureRecognizer.router, handleEvent);
_finalPosition = event.position;
_check();
......@@ -326,7 +320,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer {
final Map<int, _TapGesture> _gestureMap = new Map<int, _TapGesture>();
void addPointer(PointerInputEvent event) {
void addPointer(PointerEvent event) {
assert(!_gestureMap.containsKey(event.pointer));
_gestureMap[event.pointer] = new _TapGesture(
gestureRecognizer: this,
......
......@@ -4,16 +4,16 @@
import 'events.dart';
/// A callback that receives a [PointerInputEvent]
typedef void PointerRoute(PointerInputEvent event);
/// A callback that receives a [PointerEvent]
typedef void PointerRoute(PointerEvent event);
/// A routing table for [PointerInputEvent] events.
/// A routing table for [PointerEvent] events.
class PointerRouter {
final Map<int, List<PointerRoute>> _routeMap = new Map<int, List<PointerRoute>>();
/// Adds a route to the routing table
/// Adds a route to the routing table.
///
/// Whenever this object routes a [PointerInputEvent] corresponding to
/// Whenever this object routes a [PointerEvent] corresponding to
/// pointer, call route.
void addRoute(int pointer, PointerRoute route) {
List<PointerRoute> routes = _routeMap.putIfAbsent(pointer, () => new List<PointerRoute>());
......@@ -21,9 +21,9 @@ class PointerRouter {
routes.add(route);
}
/// Removes a route from the routing table
/// Removes a route from the routing table.
///
/// No longer call route when routing a [PointerInputEvent] corresponding to
/// No longer call route when routing a [PointerEvent] corresponding to
/// pointer. Requires that this route was previously added to the router.
void removeRoute(int pointer, PointerRoute route) {
assert(_routeMap.containsKey(pointer));
......@@ -37,7 +37,7 @@ class PointerRouter {
/// Call the routes registed for this pointer event.
///
/// Calls the routes in the order in which they were added to the route.
void route(PointerInputEvent event) {
void route(PointerEvent event) {
List<PointerRoute> routes = _routeMap[event.pointer];
if (routes == null)
return;
......
......@@ -18,7 +18,7 @@ abstract class GestureRecognizer extends GestureArenaMember {
/// considered for this gesture. (It's the GestureRecognizer's responsibility
/// to then add itself to the global pointer router to receive subsequent
/// events for this pointer.)
void addPointer(PointerInputEvent event);
void addPointer(PointerDownEvent event);
/// Release any resources used by the object. Called when the object is no
/// longer needed (e.g. a gesture recogniser is being unregistered from a
......@@ -34,10 +34,10 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
PointerRouter _router;
final List<GestureArenaEntry> _entries = new List<GestureArenaEntry>();
final List<GestureArenaEntry> _entries = <GestureArenaEntry>[];
final Set<int> _trackedPointers = new Set<int>();
void handleEvent(PointerInputEvent event);
void handleEvent(PointerEvent event);
void acceptGesture(int pointer) { }
void rejectGesture(int pointer) { }
void didStopTrackingLastPointer(int pointer);
......@@ -71,8 +71,8 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
didStopTrackingLastPointer(pointer);
}
void stopTrackingIfPointerNoLongerDown(PointerInputEvent event) {
if (event.type == 'pointerup' || event.type == 'pointercancel')
void stopTrackingIfPointerNoLongerDown(PointerEvent event) {
if (event is PointerUpEvent || event is PointerCancelEvent)
stopTrackingPointer(event.pointer);
}
......@@ -95,7 +95,7 @@ abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecogni
Point initialPosition;
Timer _timer;
void addPointer(PointerInputEvent event) {
void addPointer(PointerDownEvent event) {
startTrackingPointer(event.pointer);
if (state == GestureRecognizerState.ready) {
state = GestureRecognizerState.possible;
......@@ -106,11 +106,11 @@ abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecogni
}
}
void handleEvent(PointerInputEvent event) {
void handleEvent(PointerEvent event) {
assert(state != GestureRecognizerState.ready);
if (state == GestureRecognizerState.possible && event.pointer == primaryPointer) {
// TODO(abarth): Maybe factor the slop handling out into a separate class?
if (event.type == 'pointermove' && _getDistance(event) > kTouchSlop) {
if (event is PointerMoveEvent && _getDistance(event) > kTouchSlop) {
resolve(GestureDisposition.rejected);
stopTrackingPointer(primaryPointer);
} else {
......@@ -121,7 +121,7 @@ abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecogni
}
/// Override to provide behavior for the primary pointer when the gesture is still possible.
void handlePrimaryPointer(PointerInputEvent event);
void handlePrimaryPointer(PointerEvent event);
/// Override to be notified with [deadline] is exceeded.
///
......@@ -154,7 +154,7 @@ abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecogni
}
}
double _getDistance(PointerInputEvent event) {
double _getDistance(PointerEvent event) {
Offset offset = event.position - initialPosition;
return offset.distance;
}
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'arena.dart';
import 'recognizer.dart';
import 'constants.dart';
......@@ -16,8 +14,8 @@ enum ScaleState {
started
}
typedef void GestureScaleStartCallback(ui.Point focalPoint);
typedef void GestureScaleUpdateCallback(double scale, ui.Point focalPoint);
typedef void GestureScaleStartCallback(Point focalPoint);
typedef void GestureScaleUpdateCallback(double scale, Point focalPoint);
typedef void GestureScaleEndCallback();
class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
......@@ -32,35 +30,31 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
double _initialSpan;
double _currentSpan;
Map<int, ui.Point> _pointerLocations;
Map<int, Point> _pointerLocations;
double get _scaleFactor => _initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0;
void addPointer(PointerInputEvent event) {
void addPointer(PointerEvent event) {
startTrackingPointer(event.pointer);
if (_state == ScaleState.ready) {
_state = ScaleState.possible;
_initialSpan = 0.0;
_currentSpan = 0.0;
_pointerLocations = new Map<int, ui.Point>();
_pointerLocations = new Map<int, Point>();
}
}
void handleEvent(PointerInputEvent event) {
void handleEvent(PointerEvent event) {
assert(_state != ScaleState.ready);
bool configChanged = false;
switch(event.type) {
case 'pointerup':
if (event is PointerMoveEvent) {
_pointerLocations[event.pointer] = event.position;
} else if (event is PointerDownEvent) {
configChanged = true;
_pointerLocations.remove(event.pointer);
break;
case 'pointerdown':
_pointerLocations[event.pointer] = event.position;
} else if (event is PointerUpEvent) {
configChanged = true;
_pointerLocations[event.pointer] = new ui.Point(event.x, event.y);
break;
case 'pointermove':
_pointerLocations[event.pointer] = new ui.Point(event.x, event.y);
break;
_pointerLocations.remove(event.pointer);
}
_update(configChanged);
......@@ -72,10 +66,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
int count = _pointerLocations.keys.length;
// Compute the focal point
ui.Point focalPoint = ui.Point.origin;
Point focalPoint = Point.origin;
for (int pointer in _pointerLocations.keys)
focalPoint += _pointerLocations[pointer].toOffset();
focalPoint = new ui.Point(focalPoint.x / count, focalPoint.y / count);
focalPoint = new Point(focalPoint.x / count, focalPoint.y / count);
// Span is the average deviation from focal point
double totalDeviation = 0.0;
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' show Point, Offset;
import 'arena.dart';
import 'constants.dart';
import 'events.dart';
......@@ -36,8 +34,8 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
bool _wonArena = false;
Point _finalPosition;
void handlePrimaryPointer(PointerInputEvent event) {
if (event.type == 'pointerup') {
void handlePrimaryPointer(PointerEvent event) {
if (event is PointerUpEvent) {
_finalPosition = event.position;
_checkUp();
}
......
......@@ -2,17 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'dart:ui' show Point, Offset;
import 'lsq_solver.dart';
class GestureVelocity {
GestureVelocity({ this.isValid: false, this.x: 0.0, this.y : 0.0 });
final bool isValid;
final double x;
final double y;
}
export 'dart:ui' show Point, Offset;
class _Estimator {
int degree;
......@@ -22,17 +16,16 @@ class _Estimator {
double confidence;
String toString() {
String result = "Estimator(degree: " + degree.toString();
result += ", time: " + time.toString();
result += ", confidence: " + confidence.toString();
result += ", xCoefficients: " + xCoefficients.toString();
result += ", yCoefficients: " + yCoefficients.toString();
return result;
return 'Estimator(degree: $degree, '
'time: $time, '
'confidence: $confidence, '
'xCoefficients: $xCoefficients, '
'yCoefficients: $yCoefficients)';
}
}
abstract class _VelocityTrackerStrategy {
void addMovement(Duration timeStamp, double x, double y);
void addMovement(Duration timeStamp, Point position);
bool getEstimator(_Estimator estimator);
void clear();
}
......@@ -45,28 +38,46 @@ enum _Weighting {
}
class _Movement {
Duration eventTime = const Duration();
ui.Point position = ui.Point.origin;
Duration eventTime = Duration.ZERO;
Point position = Point.origin;
}
typedef double _WeightChooser(int index);
class _LeastSquaresVelocityTrackerStrategy extends _VelocityTrackerStrategy {
static const int kHistorySize = 20;
static const int kHorizonMilliseconds = 100;
_LeastSquaresVelocityTrackerStrategy(this.degree, this.weighting)
: _index = 0, _movements = new List<_Movement>(kHistorySize);
_LeastSquaresVelocityTrackerStrategy(this.degree, _Weighting weighting)
: _index = 0, _movements = new List<_Movement>(kHistorySize) {
switch (weighting) {
case _Weighting.weightingNone:
_chooseWeight = null;
break;
case _Weighting.weightingDelta:
_chooseWeight = _weightDelta;
break;
case _Weighting.weightingCentral:
_chooseWeight = _weightCentral;
break;
case _Weighting.weightingRecent:
_chooseWeight = _weightRecent;
break;
}
}
final int degree;
final _Weighting weighting;
final List<_Movement> _movements;
_WeightChooser _chooseWeight;
int _index;
void addMovement(Duration timeStamp, double x, double y) {
if (++_index == kHistorySize)
void addMovement(Duration timeStamp, Point position) {
_index += 1;
if (_index == kHistorySize)
_index = 0;
_Movement movement = _getMovement(_index);
movement.eventTime = timeStamp;
movement.position = new ui.Point(x, y);
movement.position = position;
}
bool getEstimator(_Estimator estimator) {
......@@ -85,15 +96,17 @@ class _LeastSquaresVelocityTrackerStrategy extends _VelocityTrackerStrategy {
if (age > kHorizonMilliseconds)
break;
ui.Point position = movement.position;
Point position = movement.position;
x.add(position.x);
y.add(position.y);
w.add(_chooseWeight(index));
w.add(_chooseWeight != null ? _chooseWeight(index) : 1.0);
time.add(-age);
index = (index == 0 ? kHistorySize : index) - 1;
} while (++m < kHistorySize);
if (m == 0)
m += 1;
} while (m < kHistorySize);
if (m == 0) // because we broke out of the loop above after age > kHorizonMilliseconds
return false; // no data
// Calculate a least squares polynomial fit.
......@@ -120,8 +133,8 @@ class _LeastSquaresVelocityTrackerStrategy extends _VelocityTrackerStrategy {
// No velocity data available for this pointer, but we do have its current
// position.
estimator.xCoefficients = [ x[0] ];
estimator.yCoefficients = [ y[0] ];
estimator.xCoefficients = <double>[ x[0] ];
estimator.yCoefficients = <double>[ y[0] ];
estimator.time = newestMovement.eventTime;
estimator.degree = 0;
estimator.confidence = 1.0;
......@@ -132,26 +145,23 @@ class _LeastSquaresVelocityTrackerStrategy extends _VelocityTrackerStrategy {
_index = -1;
}
double _chooseWeight(int index) {
switch (weighting) {
case _Weighting.weightingDelta:
double _weightDelta(int index) {
// Weight points based on how much time elapsed between them and the next
// point so that points that "cover" a shorter time span are weighed less.
// delta 0ms: 0.5
// delta 10ms: 1.0
if (index == _index) {
if (index == _index)
return 1.0;
}
int nextIndex = (index + 1) % kHistorySize;
int deltaMilliseconds = (_movements[nextIndex].eventTime - _movements[index].eventTime).inMilliseconds;
if (deltaMilliseconds < 0)
return 0.5;
if (deltaMilliseconds < 10)
return 0.5 + deltaMilliseconds * 0.05;
return 1.0;
}
case _Weighting.weightingCentral:
double _weightCentral(int index) {
// Weight points based on their age, weighing very recent and very old
// points less.
// age 0ms: 0.5
......@@ -167,27 +177,20 @@ class _LeastSquaresVelocityTrackerStrategy extends _VelocityTrackerStrategy {
return 1.0;
if (ageMilliseconds < 60)
return 0.5 + (60 - ageMilliseconds) * 0.05;
return 0.5;
}
case _Weighting.weightingRecent:
double _weightRecent(int index) {
// Weight points based on their age, weighing older points less.
// age 0ms: 1.0
// age 50ms: 1.0
// age 100ms: 0.5
int ageMilliseconds = (_movements[_index].eventTime - _movements[index].eventTime).inMilliseconds;
if (ageMilliseconds < 50) {
if (ageMilliseconds < 50)
return 1.0;
}
if (ageMilliseconds < 100) {
if (ageMilliseconds < 100)
return 0.5 + (100 - ageMilliseconds) * 0.01;
}
return 0.5;
case _Weighting.weightingNone:
default:
return 1.0;
}
}
_Movement _getMovement(int i) {
......@@ -209,24 +212,22 @@ class VelocityTracker {
Duration _lastTimeStamp = const Duration();
_VelocityTrackerStrategy _strategy;
void addPosition(Duration timeStamp, double x, double y) {
void addPosition(Duration timeStamp, Point position) {
if ((timeStamp - _lastTimeStamp).inMilliseconds >= kAssumePointerMoveStoppedTimeMs)
_strategy.clear();
_lastTimeStamp = timeStamp;
_strategy.addMovement(timeStamp, x, y);
_strategy.addMovement(timeStamp, position);
}
GestureVelocity getVelocity() {
Offset getVelocity() {
_Estimator estimator = new _Estimator();
if (_strategy.getEstimator(estimator) && estimator.degree >= 1) {
// convert from pixels/ms to pixels/s
return new GestureVelocity(
isValid: true,
x: estimator.xCoefficients[1] * 1000,
y: estimator.yCoefficients[1] * 1000
return new Offset( // convert from pixels/ms to pixels/s
estimator.xCoefficients[1] * 1000,
estimator.yCoefficients[1] * 1000
);
}
return new GestureVelocity(isValid: false, x: 0.0, y: 0.0);
return null;
}
static _VelocityTrackerStrategy _createStrategy() {
......
......@@ -148,8 +148,8 @@ class _RenderSlider extends RenderConstrainedBox {
bool hitTestSelf(Point position) => true;
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown' && onChanged != null)
void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
if (event is PointerDownEvent && onChanged != null)
_drag.addPointer(event);
}
......
......@@ -164,8 +164,8 @@ class _RenderSwitch extends RenderToggleable {
reaction.reverse();
}
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown' && onChanged != null)
void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
if (event is PointerDownEvent && onChanged != null)
_drag.addPointer(event);
super.handleEvent(event, entry);
}
......
......@@ -122,8 +122,8 @@ abstract class RenderToggleable extends RenderConstrainedBox {
bool hitTestSelf(Point position) => true;
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown' && isInteractive)
void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
if (event is PointerDownEvent && isInteractive)
_tap.addPointer(event);
}
......
......@@ -636,14 +636,15 @@ abstract class RenderBox extends RenderObject {
Rect get paintBounds => Point.origin & size;
int _debugActivePointers = 0;
void handleEvent(InputEvent event, HitTestEntry entry) {
void handleEvent(PointerEvent event, HitTestEntry entry) {
super.handleEvent(event, entry);
assert(() {
if (debugPaintPointersEnabled) {
if (event.type == 'pointerdown')
if (event is PointerDownEvent) {
_debugActivePointers += 1;
if (event.type == 'pointerup' || event.type == 'pointercancel')
} else if (event is PointerUpEvent || event is PointerCancelEvent) {
_debugActivePointers -= 1;
}
markNeedsPaint();
}
return true;
......
......@@ -7,7 +7,7 @@ import 'package:flutter/gestures.dart';
/// An object that can handle events.
abstract class HitTestTarget {
/// Override this function to receive events.
void handleEvent(InputEvent event, HitTestEntry entry);
void handleEvent(PointerEvent event, HitTestEntry entry);
}
/// Data collected during a hit test about a specific [HitTestTarget].
......
......@@ -1045,8 +1045,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// EVENTS
/// Override this function to handle events that hit this render object
void handleEvent(InputEvent event, HitTestEntry entry) { }
/// Override this function to handle pointer events that hit this render object.
void handleEvent(PointerEvent event, HitTestEntry entry) { }
// HIT TESTING
......
......@@ -1072,7 +1072,10 @@ class RenderCustomPaint extends RenderProxyBox {
}
}
typedef void PointerEventListener(PointerInputEvent event);
typedef void PointerDownEventListener(PointerDownEvent event);
typedef void PointerMoveEventListener(PointerMoveEvent event);
typedef void PointerUpEventListener(PointerUpEvent event);
typedef void PointerCancelEventListener(PointerCancelEvent event);
enum HitTestBehavior {
deferToChild,
......@@ -1091,10 +1094,10 @@ class RenderPointerListener extends RenderProxyBox {
RenderBox child
}) : super(child);
PointerEventListener onPointerDown;
PointerEventListener onPointerMove;
PointerEventListener onPointerUp;
PointerEventListener onPointerCancel;
PointerDownEventListener onPointerDown;
PointerMoveEventListener onPointerMove;
PointerUpEventListener onPointerUp;
PointerCancelEventListener onPointerCancel;
HitTestBehavior behavior;
bool hitTest(HitTestResult result, { Point position }) {
......@@ -1110,14 +1113,14 @@ class RenderPointerListener extends RenderProxyBox {
bool hitTestSelf(Point position) => behavior == HitTestBehavior.opaque;
void handleEvent(InputEvent event, HitTestEntry entry) {
if (onPointerDown != null && event.type == 'pointerdown')
void handleEvent(PointerEvent event, HitTestEntry entry) {
if (onPointerDown != null && event is PointerDownEvent)
return onPointerDown(event);
if (onPointerMove != null && event.type == 'pointermove')
if (onPointerMove != null && event == PointerMoveEvent)
return onPointerMove(event);
if (onPointerUp != null && event.type == 'pointerup')
if (onPointerUp != null && event == PointerUpEvent)
return onPointerUp(event);
if (onPointerCancel != null && event.type == 'pointercancel')
if (onPointerCancel != null && event == PointerCancelEvent)
return onPointerCancel(event);
}
......
......@@ -1299,10 +1299,10 @@ class Listener extends OneChildRenderObjectWidget {
assert(behavior != null);
}
final PointerEventListener onPointerDown;
final PointerEventListener onPointerMove;
final PointerEventListener onPointerUp;
final PointerEventListener onPointerCancel;
final PointerDownEventListener onPointerDown;
final PointerMoveEventListener onPointerMove;
final PointerUpEventListener onPointerUp;
final PointerCancelEventListener onPointerCancel;
final HitTestBehavior behavior;
RenderPointerListener createRenderObject() => new RenderPointerListener(
......
......@@ -135,7 +135,7 @@ class _DraggableState<T> extends State<DraggableBase<T>> implements GestureArena
GestureRecognizer _recognizer;
Map<int, GestureArenaEntry> _activePointers = <int, GestureArenaEntry>{};
void _routePointer(PointerInputEvent event) {
void _routePointer(PointerEvent event) {
_activePointers[event.pointer] = GestureArena.instance.add(event.pointer, this);
_recognizer.addPointer(event);
}
......@@ -284,18 +284,14 @@ class _DragAvatar<T> {
Offset _lastOffset;
OverlayEntry _entry;
void handleEvent(PointerInputEvent event) {
switch(event.type) {
case 'pointerup':
void handleEvent(PointerEvent event) {
if (event is PointerUpEvent) {
update(event.position);
finish(_DragEndKind.dropped);
break;
case 'pointercancel':
} else if (event is PointerCancelEvent) {
finish(_DragEndKind.canceled);
break;
case 'pointermove':
} else if (event is PointerMoveEvent) {
update(event.position);
break;
}
}
......
......@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'basic.dart';
import 'framework.dart';
......@@ -13,7 +12,7 @@ enum EventRecorderMode {
record
}
typedef void EventsReadyCallback(List<PointerInputEvent> events);
typedef void EventsReadyCallback(Iterable<PointerEvent> events);
/// EventRecorder is a utility widget that allows input events occurring
/// on the child to be recorded. The widget is initially in the "stop" state
......@@ -38,11 +37,7 @@ class EventRecorder extends StatefulComponent {
class _EventRecorderState extends State<EventRecorder> {
List<PointerInputEvent> _events = new List<PointerInputEvent>();
void initState() {
super.initState();
}
final List<PointerEvent> _events = <PointerEvent>[];
void didUpdateConfig(EventRecorder oldConfig) {
if (oldConfig.mode == EventRecorderMode.record &&
......@@ -52,11 +47,10 @@ class _EventRecorderState extends State<EventRecorder> {
}
}
void _recordEvent(PointerInputEvent event) {
if (config.mode == EventRecorderMode.record) {
void _recordEvent(PointerEvent event) {
if (config.mode == EventRecorderMode.record)
_events.add(event);
}
}
Widget build(BuildContext context) {
return new Listener(
......
......@@ -210,7 +210,7 @@ class _GestureDetectorState extends State<GestureDetector> {
return null;
}
void _handlePointerDown(PointerInputEvent event) {
void _handlePointerDown(PointerDownEvent event) {
if (_tap != null)
_tap.addPointer(event);
if (_doubleTap != null)
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/gestures.dart';
export 'dart:ui' show Point;
......@@ -13,57 +11,48 @@ class TestPointer {
int pointer;
bool isDown = false;
ui.Point location;
Point location;
PointerInputEvent down(ui.Point newLocation, { Duration timeStamp: const Duration() }) {
PointerDownEvent down(Point newLocation, { Duration timeStamp: const Duration() }) {
assert(!isDown);
isDown = true;
location = newLocation;
return new PointerInputEvent(
type: 'pointerdown',
return new PointerDownEvent(
timeStamp: timeStamp,
pointer: pointer,
x: location.x,
y: location.y,
timeStamp: timeStamp
position: location
);
}
PointerInputEvent move(ui.Point newLocation, { Duration timeStamp: const Duration() }) {
PointerMoveEvent move(Point newLocation, { Duration timeStamp: const Duration() }) {
assert(isDown);
ui.Offset delta = newLocation - location;
Offset delta = newLocation - location;
location = newLocation;
return new PointerInputEvent(
type: 'pointermove',
return new PointerMoveEvent(
timeStamp: timeStamp,
pointer: pointer,
x: newLocation.x,
y: newLocation.y,
dx: delta.dx,
dy: delta.dy,
timeStamp: timeStamp
position: newLocation,
delta: delta
);
}
PointerInputEvent up({ Duration timeStamp: const Duration() }) {
PointerUpEvent up({ Duration timeStamp: const Duration() }) {
assert(isDown);
isDown = false;
return new PointerInputEvent(
type: 'pointerup',
return new PointerUpEvent(
timeStamp: timeStamp,
pointer: pointer,
x: location.x,
y: location.y,
timeStamp: timeStamp
position: location
);
}
PointerInputEvent cancel({ Duration timeStamp: const Duration() }) {
PointerCancelEvent cancel({ Duration timeStamp: const Duration() }) {
assert(isDown);
isDown = false;
return new PointerInputEvent(
type: 'pointercancel',
return new PointerCancelEvent(
timeStamp: timeStamp,
pointer: pointer,
x: location.x,
y: location.y,
timeStamp: timeStamp
position: location
);
}
......
......@@ -174,13 +174,13 @@ class WidgetTester {
_dispatchEvent(p.up(), result);
}
void dispatchEvent(InputEvent event, Point location) {
void dispatchEvent(PointerEvent event, Point location) {
_dispatchEvent(event, _hitTest(location));
}
HitTestResult _hitTest(Point location) => WidgetFlutterBinding.instance.hitTest(location);
void _dispatchEvent(InputEvent event, HitTestResult result) {
void _dispatchEvent(PointerEvent event, HitTestResult result) {
WidgetFlutterBinding.instance.dispatchEvent(event, result);
}
......
# Benchmarks
This directory (and its sub-directories) contain benchmarks for Flutter.
The reporting format for benchmarks is not standardized yet, so benchmarks
here are typically run by hand. To run a benchmark:
This directory (and its sub-directories) contain benchmarks for
Flutter. The reporting format for benchmarks is not standardized yet,
so benchmarks here are typically run by hand. To run a benchmark:
1. Build `sky_shell` for Linux Release using the instructions in the
[Engine repository](https://github.com/flutter/engine).
2. Run `pub get` in the `packages/unit` directory.
3. Run the benchmark:
3. Run the benchmarks by running the following command from the root
of the flutter repository (replacing `stocks/layout_bench.dart`
with the path to whichever benchmark you want to run):
```
/path/to/engine/src/out/Release/sky_shell packages/unit/benchmark/stocks/layout_bench.dart --package-root=packages/unit/package
/path/to/engine/src/out/Release/sky_shell packages/unit/benchmark/stocks/layout_bench.dart --package-root=packages/unit/packages
```
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:test/test.dart';
import 'velocity_tracker_data.dart';
......@@ -7,36 +11,16 @@ const int kBatchSize = 1000;
const int kBatchOffset = 50;
const int kNumMarks = 130;
List<PointerInputEvent> _eventFromMap(List<Map> intermediate) {
List<PointerInputEvent> events = new List<PointerInputEvent>();
for (Map entry in intermediate)
events.add(_eventFor(entry));
return events;
}
PointerInputEvent _eventFor(Map entry) {
PointerInputEvent result = new PointerInputEvent(
type: entry['type'],
timeStamp: entry['timeStamp'],
pointer: entry['pointer'],
x: entry['x'],
y: entry['y']
);
return result;
}
void main() {
List<PointerInputEvent> events = _eventFromMap(velocityEventData);
test('Dart velocity tracker performance', () {
VelocityTracker tracker = new VelocityTracker();
Stopwatch watch = new Stopwatch();
watch.start();
for (int i = 0; i < kNumIters; i++) {
for (PointerInputEvent event in events) {
if (event.type == 'pointerdown' || event.type == 'pointermove')
tracker.addPosition(event.timeStamp, event.x, event.y);
if (event.type == 'pointerup')
for (PointerEvent event in velocityEventData) {
if (event is PointerDownEvent || event is PointerMoveEvent)
tracker.addPosition(event.timeStamp, event.position);
if (event is PointerUpEvent)
tracker.getVelocity();
}
}
......
......@@ -16,85 +16,63 @@ class TestGestureArenaMember extends GestureArenaMember {
void main() {
// Down/up pair 1: normal tap sequence
final PointerInputEvent down1 = new PointerInputEvent(
const PointerDownEvent down1 = const PointerDownEvent(
pointer: 1,
type: 'pointerdown',
x: 10.0,
y: 10.0
position: const Point(10.0, 10.0)
);
final PointerInputEvent up1 = new PointerInputEvent(
const PointerUpEvent up1 = const PointerUpEvent(
pointer: 1,
type: 'pointerup',
x: 11.0,
y: 9.0
position: const Point(11.0, 9.0)
);
// Down/up pair 2: normal tap sequence close to pair 1
final PointerInputEvent down2 = new PointerInputEvent(
const PointerDownEvent down2 = const PointerDownEvent(
pointer: 2,
type: 'pointerdown',
x: 12.0,
y: 12.0
position: const Point(12.0, 12.0)
);
final PointerInputEvent up2 = new PointerInputEvent(
const PointerUpEvent up2 = const PointerUpEvent(
pointer: 2,
type: 'pointerup',
x: 13.0,
y: 11.0
position: const Point(13.0, 11.0)
);
// Down/up pair 3: normal tap sequence far away from pair 1
final PointerInputEvent down3 = new PointerInputEvent(
const PointerDownEvent down3 = const PointerDownEvent(
pointer: 3,
type: 'pointerdown',
x: 130.0,
y: 130.0
position: const Point(130.0, 130.0)
);
final PointerInputEvent up3 = new PointerInputEvent(
const PointerUpEvent up3 = const PointerUpEvent(
pointer: 3,
type: 'pointerup',
x: 131.0,
y: 129.0
position: const Point(131.0, 129.0)
);
// Down/move/up sequence 4: intervening motion
final PointerInputEvent down4 = new PointerInputEvent(
const PointerDownEvent down4 = const PointerDownEvent(
pointer: 4,
type: 'pointerdown',
x: 10.0,
y: 10.0
position: const Point(10.0, 10.0)
);
final PointerInputEvent move4 = new PointerInputEvent(
const PointerMoveEvent move4 = const PointerMoveEvent(
pointer: 4,
type: 'pointermove',
x: 25.0,
y: 25.0
position: const Point(25.0, 25.0)
);
final PointerInputEvent up4 = new PointerInputEvent(
const PointerUpEvent up4 = const PointerUpEvent(
pointer: 4,
type: 'pointerup',
x: 25.0,
y: 25.0
position: const Point(25.0, 25.0)
);
// Down/up pair 5: normal tap sequence identical to pair 1 with different pointer
final PointerInputEvent down5 = new PointerInputEvent(
const PointerDownEvent down5 = const PointerDownEvent(
pointer: 5,
type: 'pointerdown',
x: 10.0,
y: 10.0
position: const Point(10.0, 10.0)
);
final PointerInputEvent up5 = new PointerInputEvent(
const PointerUpEvent up5 = const PointerUpEvent(
pointer: 5,
type: 'pointerup',
x: 11.0,
y: 9.0
position: const Point(11.0, 9.0)
);
test('Should recognize double tap', () {
......@@ -546,7 +524,7 @@ void main() {
expect(member.accepted, isFalse);
async.elapse(new Duration(milliseconds: 5000));
async.elapse(const Duration(milliseconds: 5000));
expect(member.accepted, isTrue);
});
......
......@@ -2,18 +2,14 @@ import 'package:quiver/testing/async.dart';
import 'package:flutter/gestures.dart';
import 'package:test/test.dart';
final PointerInputEvent down = new PointerInputEvent(
const PointerDownEvent down = const PointerDownEvent(
pointer: 5,
type: 'pointerdown',
x: 10.0,
y: 10.0
position: const Point(10.0, 10.0)
);
final PointerInputEvent up = new PointerInputEvent(
const PointerUpEvent up = const PointerUpEvent(
pointer: 5,
type: 'pointerup',
x: 11.0,
y: 9.0
position: const Point(11.0, 9.0)
);
void main() {
......@@ -32,9 +28,9 @@ void main() {
expect(longPressRecognized, isFalse);
router.route(down);
expect(longPressRecognized, isFalse);
async.elapse(new Duration(milliseconds: 300));
async.elapse(const Duration(milliseconds: 300));
expect(longPressRecognized, isFalse);
async.elapse(new Duration(milliseconds: 700));
async.elapse(const Duration(milliseconds: 700));
expect(longPressRecognized, isTrue);
});
......@@ -56,11 +52,11 @@ void main() {
expect(longPressRecognized, isFalse);
router.route(down);
expect(longPressRecognized, isFalse);
async.elapse(new Duration(milliseconds: 300));
async.elapse(const Duration(milliseconds: 300));
expect(longPressRecognized, isFalse);
router.route(up);
expect(longPressRecognized, isFalse);
async.elapse(new Duration(seconds: 1));
async.elapse(const Duration(seconds: 1));
expect(longPressRecognized, isFalse);
});
......@@ -91,10 +87,10 @@ void main() {
router.route(down);
expect(tapDownRecognized, isFalse);
expect(longPressRecognized, isFalse);
async.elapse(new Duration(milliseconds: 300));
async.elapse(const Duration(milliseconds: 300));
expect(tapDownRecognized, isTrue);
expect(longPressRecognized, isFalse);
async.elapse(new Duration(milliseconds: 700));
async.elapse(const Duration(milliseconds: 700));
expect(tapDownRecognized, isTrue);
expect(longPressRecognized, isTrue);
});
......
......@@ -9,9 +9,9 @@ void main() {
}
test('Least-squares fit: linear polynomial to line', () {
List<double> x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
List<double> y = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
List<double> w = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
List<double> x = <double>[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
List<double> y = <double>[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
List<double> w = <double>[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
LeastSquaresSolver solver = new LeastSquaresSolver(x, y, w);
PolynomialFit fit = solver.solve(1);
......@@ -23,9 +23,9 @@ void main() {
});
test('Least-squares fit: linear polynomial to sloped line', () {
List<double> x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
List<double> y = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
List<double> w = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
List<double> x = <double>[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
List<double> y = <double>[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
List<double> w = <double>[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
LeastSquaresSolver solver = new LeastSquaresSolver(x, y, w);
PolynomialFit fit = solver.solve(1);
......@@ -37,9 +37,9 @@ void main() {
});
test('Least-squares fit: quadratic polynomial to line', () {
List<double> x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
List<double> y = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
List<double> w = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
List<double> x = <double>[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
List<double> y = <double>[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
List<double> w = <double>[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
LeastSquaresSolver solver = new LeastSquaresSolver(x, y, w);
PolynomialFit fit = solver.solve(2);
......@@ -52,9 +52,9 @@ void main() {
});
test('Least-squares fit: quadratic polynomial to sloped line', () {
List<double> x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
List<double> y = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
List<double> w = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
List<double> x = <double>[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
List<double> y = <double>[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
List<double> w = <double>[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
LeastSquaresSolver solver = new LeastSquaresSolver(x, y, w);
PolynomialFit fit = solver.solve(2);
......
......@@ -5,7 +5,7 @@ import 'package:test/test.dart';
void main() {
test('Should route pointers', () {
bool callbackRan = false;
void callback(PointerInputEvent event) {
void callback(PointerEvent event) {
callbackRan = true;
}
......
import 'dart:ui' as ui;
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart';
import 'package:test/test.dart';
......@@ -11,14 +9,14 @@ void main() {
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
bool didStartScale = false;
ui.Point updatedFocalPoint;
scale.onStart = (ui.Point focalPoint) {
Point updatedFocalPoint;
scale.onStart = (Point focalPoint) {
didStartScale = true;
updatedFocalPoint = focalPoint;
};
double updatedScale;
scale.onUpdate = (double scale, ui.Point focalPoint) {
scale.onUpdate = (double scale, Point focalPoint) {
updatedScale = scale;
updatedFocalPoint = focalPoint;
};
......@@ -35,7 +33,7 @@ void main() {
TestPointer pointer1 = new TestPointer(1);
PointerInputEvent down = pointer1.down(new Point(10.0, 10.0));
PointerDownEvent down = pointer1.down(const Point(10.0, 10.0));
scale.addPointer(down);
tap.addPointer(down);
......@@ -54,10 +52,10 @@ void main() {
expect(didEndScale, isFalse);
expect(didTap, isFalse);
router.route(pointer1.move(new Point(20.0, 30.0)));
router.route(pointer1.move(const Point(20.0, 30.0)));
expect(didStartScale, isTrue);
didStartScale = false;
expect(updatedFocalPoint, new ui.Point(20.0, 30.0));
expect(updatedFocalPoint, const Point(20.0, 30.0));
updatedFocalPoint = null;
expect(updatedScale, 1.0);
updatedScale = null;
......@@ -66,7 +64,7 @@ void main() {
// Two-finger scaling
TestPointer pointer2 = new TestPointer(2);
PointerInputEvent down2 = pointer2.down(new Point(10.0, 20.0));
PointerDownEvent down2 = pointer2.down(const Point(10.0, 20.0));
scale.addPointer(down2);
tap.addPointer(down2);
GestureArena.instance.close(2);
......@@ -79,10 +77,10 @@ void main() {
expect(didStartScale, isFalse);
// Zoom in
router.route(pointer2.move(new Point(0.0, 10.0)));
router.route(pointer2.move(const Point(0.0, 10.0)));
expect(didStartScale, isTrue);
didStartScale = false;
expect(updatedFocalPoint, new ui.Point(10.0, 20.0));
expect(updatedFocalPoint, const Point(10.0, 20.0));
updatedFocalPoint = null;
expect(updatedScale, 2.0);
updatedScale = null;
......@@ -90,8 +88,8 @@ void main() {
expect(didTap, isFalse);
// Zoom out
router.route(pointer2.move(new Point(15.0, 25.0)));
expect(updatedFocalPoint, new ui.Point(17.5, 27.5));
router.route(pointer2.move(const Point(15.0, 25.0)));
expect(updatedFocalPoint, const Point(17.5, 27.5));
updatedFocalPoint = null;
expect(updatedScale, 0.5);
updatedScale = null;
......@@ -99,7 +97,7 @@ void main() {
// Three-finger scaling
TestPointer pointer3 = new TestPointer(3);
PointerInputEvent down3 = pointer3.down(new Point(25.0, 35.0));
PointerDownEvent down3 = pointer3.down(const Point(25.0, 35.0));
scale.addPointer(down3);
tap.addPointer(down3);
GestureArena.instance.close(3);
......@@ -112,10 +110,10 @@ void main() {
expect(didStartScale, isFalse);
// Zoom in
router.route(pointer3.move(new Point(55.0, 65.0)));
router.route(pointer3.move(const Point(55.0, 65.0)));
expect(didStartScale, isTrue);
didStartScale = false;
expect(updatedFocalPoint, new ui.Point(30.0, 40.0));
expect(updatedFocalPoint, const Point(30.0, 40.0));
updatedFocalPoint = null;
expect(updatedScale, 5.0);
updatedScale = null;
......@@ -123,11 +121,11 @@ void main() {
expect(didTap, isFalse);
// Return to original positions but with different fingers
router.route(pointer1.move(new Point(25.0, 35.0)));
router.route(pointer2.move(new Point(20.0, 30.0)));
router.route(pointer3.move(new Point(15.0, 25.0)));
router.route(pointer1.move(const Point(25.0, 35.0)));
router.route(pointer2.move(const Point(20.0, 30.0)));
router.route(pointer3.move(const Point(15.0, 25.0)));
expect(didStartScale, isFalse);
expect(updatedFocalPoint, new ui.Point(20.0, 30.0));
expect(updatedFocalPoint, const Point(20.0, 30.0));
updatedFocalPoint = null;
expect(updatedScale, 1.0);
updatedScale = null;
......@@ -143,10 +141,10 @@ void main() {
expect(didTap, isFalse);
// Continue scaling with two fingers
router.route(pointer3.move(new Point(10.0, 20.0)));
router.route(pointer3.move(const Point(10.0, 20.0)));
expect(didStartScale, isTrue);
didStartScale = false;
expect(updatedFocalPoint, new ui.Point(15.0, 25.0));
expect(updatedFocalPoint, const Point(15.0, 25.0));
updatedFocalPoint = null;
expect(updatedScale, 2.0);
updatedScale = null;
......@@ -160,10 +158,10 @@ void main() {
expect(didTap, isFalse);
// Continue panning with one finger
router.route(pointer3.move(new Point(0.0, 0.0)));
router.route(pointer3.move(const Point(0.0, 0.0)));
expect(didStartScale, isTrue);
didStartScale = false;
expect(updatedFocalPoint, new ui.Point(0.0, 0.0));
expect(updatedFocalPoint, const Point(0.0, 0.0));
updatedFocalPoint = null;
expect(updatedScale, 1.0);
updatedScale = null;
......
import 'dart:ui' as ui;
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart';
import 'package:test/test.dart';
......@@ -15,13 +13,13 @@ void main() {
didStartPan = true;
};
ui.Offset updatedScrollDelta;
pan.onUpdate = (ui.Offset offset) {
Offset updatedScrollDelta;
pan.onUpdate = (Offset offset) {
updatedScrollDelta = offset;
};
bool didEndPan = false;
pan.onEnd = (ui.Offset velocity) {
pan.onEnd = (Offset velocity) {
didEndPan = true;
};
......@@ -31,7 +29,7 @@ void main() {
};
TestPointer pointer = new TestPointer(5);
PointerInputEvent down = pointer.down(new Point(10.0, 10.0));
PointerDownEvent down = pointer.down(const Point(10.0, 10.0));
pan.addPointer(down);
tap.addPointer(down);
GestureArena.instance.close(5);
......@@ -46,17 +44,17 @@ void main() {
expect(didEndPan, isFalse);
expect(didTap, isFalse);
router.route(pointer.move(new Point(20.0, 20.0)));
router.route(pointer.move(const Point(20.0, 20.0)));
expect(didStartPan, isTrue);
didStartPan = false;
expect(updatedScrollDelta, new ui.Offset(10.0, 10.0));
expect(updatedScrollDelta, const Offset(10.0, 10.0));
updatedScrollDelta = null;
expect(didEndPan, isFalse);
expect(didTap, isFalse);
router.route(pointer.move(new Point(20.0, 25.0)));
router.route(pointer.move(const Point(20.0, 25.0)));
expect(didStartPan, isFalse);
expect(updatedScrollDelta, new ui.Offset(0.0, 5.0));
expect(updatedScrollDelta, const Offset(0.0, 5.0));
updatedScrollDelta = null;
expect(didEndPan, isFalse);
expect(didTap, isFalse);
......
......@@ -10,55 +10,41 @@ class TestGestureArenaMember extends GestureArenaMember {
void main() {
// Down/up pair 1: normal tap sequence
final PointerInputEvent down1 = new PointerInputEvent(
const PointerDownEvent down1 = const PointerDownEvent(
pointer: 1,
type: 'pointerdown',
x: 10.0,
y: 10.0
position: const Point(10.0, 10.0)
);
final PointerInputEvent up1 = new PointerInputEvent(
const PointerUpEvent up1 = const PointerUpEvent(
pointer: 1,
type: 'pointerup',
x: 11.0,
y: 9.0
position: const Point(11.0, 9.0)
);
// Down/up pair 2: normal tap sequence far away from pair 1
final PointerInputEvent down2 = new PointerInputEvent(
const PointerDownEvent down2 = const PointerDownEvent(
pointer: 2,
type: 'pointerdown',
x: 30.0,
y: 30.0
position: const Point(30.0, 30.0)
);
final PointerInputEvent up2 = new PointerInputEvent(
const PointerUpEvent up2 = const PointerUpEvent(
pointer: 2,
type: 'pointerup',
x: 31.0,
y: 29.0
position: const Point(31.0, 29.0)
);
// Down/move/up sequence 3: intervening motion
final PointerInputEvent down3 = new PointerInputEvent(
const PointerDownEvent down3 = const PointerDownEvent(
pointer: 3,
type: 'pointerdown',
x: 10.0,
y: 10.0
position: const Point(10.0, 10.0)
);
final PointerInputEvent move3 = new PointerInputEvent(
const PointerMoveEvent move3 = const PointerMoveEvent(
pointer: 3,
type: 'pointermove',
x: 25.0,
y: 25.0
position: const Point(25.0, 25.0)
);
final PointerInputEvent up3 = new PointerInputEvent(
const PointerUpEvent up3 = const PointerUpEvent(
pointer: 3,
type: 'pointerup',
x: 25.0,
y: 25.0
position: const Point(25.0, 25.0)
);
test('Should recognize tap', () {
......
......@@ -8,56 +8,38 @@ bool _withinTolerance(double actual, double expected) {
return diff.abs() < kTolerance;
}
bool _checkVelocity(GestureVelocity actual, GestureVelocity expected) {
return (actual.isValid == expected.isValid) &&
_withinTolerance(actual.x, expected.x) &&
_withinTolerance(actual.y, expected.y);
}
List<PointerInputEvent> _eventFromMap(List<Map> intermediate) {
List<PointerInputEvent> events = new List<PointerInputEvent>();
for (Map entry in intermediate)
events.add(_eventFor(entry));
return events;
}
PointerInputEvent _eventFor(Map entry) {
PointerInputEvent result = new PointerInputEvent(
type: entry['type'],
timeStamp: new Duration(milliseconds: entry['timeStamp'].round()),
pointer: entry['pointer'],
x: entry['x'],
y: entry['y']
);
return result;
bool _checkVelocity(Offset actual, Offset expected) {
return (actual != null)
&& _withinTolerance(actual.dx, expected.dx)
&& _withinTolerance(actual.dy, expected.dy);
}
void main() {
List<PointerInputEvent> events = _eventFromMap(velocityEventData);
List<GestureVelocity> expected = new List<GestureVelocity>(13);
expected[0] = new GestureVelocity(isValid: true, x: 219.5762939453125, y: 1304.6705322265625);
expected[1] = new GestureVelocity(isValid: true, x: 355.6900939941406, y: 967.1700439453125);
expected[2] = new GestureVelocity(isValid: true, x: 12.651158332824707, y: -36.9227180480957);
expected[3] = new GestureVelocity(isValid: true, x: 714.1383056640625, y: -2561.540283203125);
expected[4] = new GestureVelocity(isValid: true, x: -19.658065795898438, y: -2910.080322265625);
expected[5] = new GestureVelocity(isValid: true, x: 646.8700561523438, y: 2976.982421875);
expected[6] = new GestureVelocity(isValid: true, x: 396.6878967285156, y: 2106.204833984375);
expected[7] = new GestureVelocity(isValid: true, x: 298.3150634765625, y: -3660.821044921875);
expected[8] = new GestureVelocity(isValid: true, x: -1.7460877895355225, y: -3288.16162109375);
expected[9] = new GestureVelocity(isValid: true, x: 384.6415710449219, y: -2645.6484375);
expected[10] = new GestureVelocity(isValid: true, x: 176.3752899169922, y: 2711.24609375);
expected[11] = new GestureVelocity(isValid: true, x: 396.9254455566406, y: 4280.640625);
expected[12] = new GestureVelocity(isValid: true, x: -71.51288604736328, y: 3716.74560546875);
List<Offset> expected = const <Offset>[
const Offset(219.5762939453125, 1304.6705322265625),
const Offset(355.6900939941406, 967.1700439453125),
const Offset(12.651158332824707, -36.9227180480957),
const Offset(714.1383056640625, -2561.540283203125),
const Offset(-19.658065795898438, -2910.080322265625),
const Offset(646.8700561523438, 2976.982421875),
const Offset(396.6878967285156, 2106.204833984375),
const Offset(298.3150634765625, -3660.821044921875),
const Offset(-1.7460877895355225, -3288.16162109375),
const Offset(384.6415710449219, -2645.6484375),
const Offset(176.3752899169922, 2711.24609375),
const Offset(396.9254455566406, 4280.640625),
const Offset(-71.51288604736328, 3716.74560546875),
];
test('Velocity tracker gives expected results', () {
VelocityTracker tracker = new VelocityTracker();
int i = 0;
for (PointerInputEvent event in events) {
if (event.type == 'pointerdown' || event.type == 'pointermove')
tracker.addPosition(event.timeStamp, event.x, event.y);
if (event.type == 'pointerup') {
_checkVelocity(tracker.getVelocity(), expected[i++]);
for (PointerEvent event in velocityEventData) {
if (event is PointerDownEvent || event is PointerMoveEvent)
tracker.addPosition(event.timeStamp, event.position);
if (event is PointerUpEvent) {
_checkVelocity(tracker.getVelocity(), expected[i]);
i += 1;
}
}
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment