Collin Jackson 842e94e9f8 First pass at support for pinch gestures; panning issues (needs testing)
Conflicts:
	sky/packages/sky/lib/gestures/drag.dart
2015-09-16 17:20:23 -07:00

155 lines
5.1 KiB
Dart

// 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 'dart:sky' as sky;
import 'package:sky/gestures/arena.dart';
import 'package:sky/gestures/recognizer.dart';
import 'package:sky/gestures/constants.dart';
enum DragState {
ready,
possible,
accepted
}
typedef void GestureDragStartCallback();
typedef void GestureDragUpdateCallback(double delta);
typedef void GestureDragEndCallback(sky.Offset velocity);
typedef void GesturePanStartCallback();
typedef void GesturePanUpdateCallback(sky.Offset delta);
typedef void GesturePanEndCallback(sky.Offset velocity);
typedef void _GesturePolymorphicUpdateCallback<T>(T delta);
int _eventTime(sky.PointerEvent event) => (event.timeStamp * 1000.0).toInt(); // microseconds
bool _isFlingGesture(sky.GestureVelocity velocity) {
double velocitySquared = velocity.x * velocity.x + velocity.y * velocity.y;
return velocity.isValid &&
velocitySquared > kMinFlingVelocity * kMinFlingVelocity &&
velocitySquared < kMaxFlingVelocity * kMaxFlingVelocity;
}
abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecognizer {
_DragGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd })
: super(router: router);
GestureDragStartCallback onStart;
_GesturePolymorphicUpdateCallback<T> onUpdate;
GestureDragEndCallback onEnd;
DragState _state = DragState.ready;
T _pendingDragDelta;
T get _initialPendingDragDelta;
T _getDragDelta(sky.PointerEvent event);
bool get _hasSufficientPendingDragDeltaToAccept;
final sky.VelocityTracker _velocityTracker = new sky.VelocityTracker();
void addPointer(sky.PointerEvent event) {
startTrackingPointer(event.pointer);
if (_state == DragState.ready) {
_state = DragState.possible;
_pendingDragDelta = _initialPendingDragDelta;
}
}
void handleEvent(sky.PointerEvent event) {
assert(_state != DragState.ready);
if (event.type == 'pointermove') {
_velocityTracker.addPosition(_eventTime(event), event.pointer, event.x, event.y);
T delta = _getDragDelta(event);
if (_state == DragState.accepted) {
if (onUpdate != null)
onUpdate(delta);
} else {
_pendingDragDelta += delta;
if (_hasSufficientPendingDragDeltaToAccept)
resolve(GestureDisposition.accepted);
}
}
stopTrackingIfPointerNoLongerDown(event);
}
void acceptGesture(int pointer) {
if (_state != DragState.accepted) {
_state = DragState.accepted;
T delta = _pendingDragDelta;
_pendingDragDelta = _initialPendingDragDelta;
if (onStart != null)
onStart();
if (delta != _initialPendingDragDelta && onUpdate != null)
onUpdate(delta);
}
}
void didStopTrackingLastPointer(int pointer) {
if (_state == DragState.possible) {
resolve(GestureDisposition.rejected);
_state = DragState.ready;
return;
}
bool wasAccepted = (_state == DragState.accepted);
_state = DragState.ready;
if (wasAccepted && onEnd != null) {
sky.GestureVelocity gestureVelocity = _velocityTracker.getVelocity(pointer);
sky.Offset velocity = sky.Offset.zero;
if (_isFlingGesture(gestureVelocity))
velocity = new sky.Offset(gestureVelocity.x, gestureVelocity.y);
resolve(GestureDisposition.accepted);
onEnd(velocity);
}
_velocityTracker.reset();
}
void dispose() {
_velocityTracker.reset();
super.dispose();
}
}
class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
VerticalDragGestureRecognizer({
PointerRouter router,
GestureDragStartCallback onStart,
GestureDragUpdateCallback onUpdate,
GestureDragEndCallback onEnd
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
double get _initialPendingDragDelta => 0.0;
double _getDragDelta(sky.PointerEvent event) => event.dy;
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
}
class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
HorizontalDragGestureRecognizer({
PointerRouter router,
GestureDragStartCallback onStart,
GestureDragUpdateCallback onUpdate,
GestureDragEndCallback onEnd
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
double get _initialPendingDragDelta => 0.0;
double _getDragDelta(sky.PointerEvent event) => event.dx;
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
}
class PanGestureRecognizer extends _DragGestureRecognizer<sky.Offset> {
PanGestureRecognizer({
PointerRouter router,
GesturePanStartCallback onStart,
GesturePanUpdateCallback onUpdate,
GesturePanEndCallback onEnd
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
sky.Offset get _initialPendingDragDelta => sky.Offset.zero;
sky.Offset _getDragDelta(sky.PointerEvent event) => new sky.Offset(event.dx, event.dy);
bool get _hasSufficientPendingDragDeltaToAccept {
return _pendingDragDelta.distance > kPanSlop;
}
}