Commit 842e94e9 authored by Collin Jackson's avatar Collin Jackson

First pass at support for pinch gestures; panning issues (needs testing)

Conflicts:
	sky/packages/sky/lib/gestures/drag.dart
parent f55a6ad1
......@@ -17,6 +17,8 @@ const double kEdgeSlop = 12.0; // Logical pixels
const double kTouchSlop = 8.0; // Logical pixels
const double kDoubleTapTouchSlop = kTouchSlop; // Logical pixels
const double kPagingTouchSlop = kTouchSlop * 2.0; // Logical pixels
const double kPanSlop = kTouchSlop * 2.0; // Logical pixels
const double kPinchSlop = kTouchSlop; // Logical pixels
const double kDoubleTapSlop = 100.0; // Logical pixels
const double kWindowTouchSlop = 16.0; // Logical pixels
const double kMinFlingVelocity = 50.0; // Logical pixels / second
......
......@@ -79,7 +79,7 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz
if (_state != DragState.accepted) {
_state = DragState.accepted;
T delta = _pendingDragDelta;
_pendingDragDelta = null;
_pendingDragDelta = _initialPendingDragDelta;
if (onStart != null)
onStart();
if (delta != _initialPendingDragDelta && onUpdate != null)
......@@ -149,6 +149,6 @@ class PanGestureRecognizer extends _DragGestureRecognizer<sky.Offset> {
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.dx.abs() > kTouchSlop || _pendingDragDelta.dy.abs() > kTouchSlop;
return _pendingDragDelta.distance > kPanSlop;
}
}
// 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:math' as math;
import 'dart:sky' as sky;
import 'package:sky/gestures/arena.dart';
import 'package:sky/gestures/recognizer.dart';
import 'package:sky/gestures/constants.dart';
enum PinchState {
ready,
possible,
started,
ended
}
typedef void GesturePinchStartCallback();
typedef void GesturePinchUpdateCallback(double scale);
typedef void GesturePinchEndCallback();
class PinchGestureRecognizer extends GestureRecognizer {
PinchGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd })
: super(router: router);
GesturePinchStartCallback onStart;
GesturePinchUpdateCallback onUpdate;
GesturePinchEndCallback onEnd;
PinchState _state = PinchState.ready;
double _initialSpan;
double _currentSpan;
Map<int, sky.Point> _pointerLocations;
double get _scaleFactor => _initialSpan > 0 ? _currentSpan / _initialSpan : 1.0;
void addPointer(sky.PointerEvent event) {
startTrackingPointer(event.pointer);
if (_state == PinchState.ready) {
_state = PinchState.possible;
_initialSpan = 0.0;
_currentSpan = 0.0;
_pointerLocations = new Map<int, sky.Point>();
}
}
void handleEvent(sky.PointerEvent event) {
assert(_state != PinchState.ready);
bool configChanged = false;
switch(event.type) {
case 'pointerup':
configChanged = true;
_pointerLocations.remove(event.pointer);
break;
case 'pointerdown':
configChanged = true;
_pointerLocations[event.pointer] = new sky.Point(event.x, event.y);
break;
case 'pointermove':
_pointerLocations[event.pointer] = new sky.Point(event.x, event.y);
break;
}
int count = _pointerLocations.keys.length;
// Compute the focal point
sky.Point focalPoint = sky.Point.origin;
for (int pointer in _pointerLocations.keys)
focalPoint += _pointerLocations[pointer].toOffset();
focalPoint = new sky.Point(focalPoint.x / count, focalPoint.y / count);
// Span is the average deviation from focal point
double totalDeviation = 0.0;
for (int pointer in _pointerLocations.keys)
totalDeviation += (focalPoint - _pointerLocations[pointer]).distance;
_currentSpan = count > 0 ? totalDeviation / count : 0.0;
if (configChanged) {
_initialSpan = _currentSpan;
if (_state == PinchState.started) {
_state = PinchState.ended;
if (onEnd != null)
onEnd();
}
}
if (_state == PinchState.ready)
_state = PinchState.possible;
if (_state == PinchState.possible &&
(_currentSpan - _initialSpan).abs() > kPinchSlop) {
resolve(GestureDisposition.accepted);
}
if (_state == PinchState.ended && _currentSpan != _initialSpan) {
_state = PinchState.started;
if (onStart != null)
onStart();
}
if (_state == PinchState.started && onUpdate != null)
onUpdate(_scaleFactor);
stopTrackingIfPointerNoLongerDown(event);
}
void acceptGesture(int pointer) {
if (_state != PinchState.started) {
_state = PinchState.started;
if (onStart != null)
onStart();
if (onUpdate != null)
onUpdate(_scaleFactor);
}
}
void didStopTrackingLastPointer(int pointer) {
switch(_state) {
case PinchState.possible:
resolve(GestureDisposition.rejected);
break;
case PinchState.ready:
assert(false);
break;
case PinchState.started:
assert(false);
break;
case PinchState.ended:
break;
}
_state = PinchState.ready;
}
void dispose() {
super.dispose();
}
}
......@@ -6,6 +6,7 @@ import 'dart:sky' as sky;
import 'package:sky/gestures/drag.dart';
import 'package:sky/gestures/long_press.dart';
import 'package:sky/gestures/pinch.dart';
import 'package:sky/gestures/recognizer.dart';
import 'package:sky/gestures/show_press.dart';
import 'package:sky/gestures/tap.dart';
......@@ -27,7 +28,10 @@ class GestureDetector extends StatefulComponent {
this.onHorizontalDragEnd,
this.onPanStart,
this.onPanUpdate,
this.onPanEnd
this.onPanEnd,
this.onPinchStart,
this.onPinchUpdate,
this.onPinchEnd
}) : super(key: key);
Widget child;
......@@ -47,6 +51,10 @@ class GestureDetector extends StatefulComponent {
GesturePanUpdateCallback onPanUpdate;
GesturePanEndCallback onPanEnd;
GesturePinchStartCallback onPinchStart;
GesturePinchUpdateCallback onPinchUpdate;
GesturePinchEndCallback onPinchEnd;
void syncConstructorArguments(GestureDetector source) {
child = source.child;
onTap = source.onTap;
......@@ -61,6 +69,9 @@ class GestureDetector extends StatefulComponent {
onPanStart = source.onPanStart;
onPanUpdate = source.onPanUpdate;
onPanEnd = source.onPanEnd;
onPinchStart = source.onPinchStart;
onPinchUpdate = source.onPinchUpdate;
onPinchEnd = source.onPinchEnd;
_syncGestureListeners();
}
......@@ -108,6 +119,13 @@ class GestureDetector extends StatefulComponent {
return _pan;
}
PinchGestureRecognizer _pinch;
PinchGestureRecognizer _ensurePinch() {
if (_pinch == null)
_pinch = new PinchGestureRecognizer(router: _router);
return _pinch;
}
void didMount() {
super.didMount();
_syncGestureListeners();
......@@ -121,6 +139,7 @@ class GestureDetector extends StatefulComponent {
_verticalDrag = _ensureDisposed(_verticalDrag);
_horizontalDrag = _ensureDisposed(_horizontalDrag);
_pan = _ensureDisposed(_pan);
_pinch = _ensureDisposed(_pinch);
}
void _syncGestureListeners() {
......@@ -130,6 +149,7 @@ class GestureDetector extends StatefulComponent {
_syncVerticalDrag();
_syncHorizontalDrag();
_syncPan();
_syncPinch();
}
void _syncTap() {
......@@ -186,6 +206,17 @@ class GestureDetector extends StatefulComponent {
}
}
void _syncPinch() {
if (onPinchStart == null && onPinchUpdate == null && onPinchEnd == null) {
_pinch = _ensureDisposed(_pan);
} else {
_ensurePinch()
..onStart = onPinchStart
..onUpdate = onPinchUpdate
..onEnd = onPinchEnd;
}
}
GestureRecognizer _ensureDisposed(GestureRecognizer recognizer) {
recognizer?.dispose();
return null;
......@@ -204,6 +235,8 @@ class GestureDetector extends StatefulComponent {
_horizontalDrag.addPointer(event);
if (_pan != null)
_pan.addPointer(event);
if (_pinch != null)
_pinch.addPointer(event);
return EventDisposition.processed;
}
......
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