Commit 97b25712 authored by Collin Jackson's avatar Collin Jackson

Update scale API and add example

parent 842e94e9
// 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 'package:sky/rendering.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/widgets.dart';
class ScaleApp extends App {
Point _startingFocalPoint;
Offset _previousOffset;
Offset _offset;
double _previousZoom;
double _zoom;
void initState() {
_offset = Offset.zero;
_zoom = 1.0;
}
void _handleScaleStart(Point focalPoint) {
setState(() {
_startingFocalPoint = focalPoint;
_previousOffset = _offset;
_previousZoom = _zoom;
});
}
void _handleScaleUpdate(double scale, Point focalPoint) {
setState(() {
_zoom = _previousZoom * scale;
_offset = _previousOffset + (focalPoint - _startingFocalPoint) / _zoom;
});
}
void paint(PaintingCanvas canvas, Size size) {
Point center = size.center(Point.origin) + _offset * _zoom;
double radius = size.width / 2.0 * _zoom;
Gradient gradient = new RadialGradient(
center: center, radius: radius,
colors: [colors.Blue[200], colors.Blue[800]]
);
Paint paint = new Paint()
..shader = gradient.createShader();
canvas.drawCircle(center, radius, paint);
}
Widget build() {
return new Theme(
data: new ThemeData.dark(),
child: new Scaffold(
toolbar: new ToolBar(
center: new Text('Scale Demo')),
body: new Material(
type: MaterialType.canvas,
child: new GestureDetector(
onScaleStart: _handleScaleStart,
onScaleUpdate: _handleScaleUpdate,
child: new CustomPaint(callback: paint, token: "$_zoom $_offset")
)
)
)
);
}
}
void main() => runApp(new ScaleApp());
...@@ -18,7 +18,7 @@ const double kTouchSlop = 8.0; // Logical pixels ...@@ -18,7 +18,7 @@ const double kTouchSlop = 8.0; // Logical pixels
const double kDoubleTapTouchSlop = kTouchSlop; // Logical pixels const double kDoubleTapTouchSlop = kTouchSlop; // Logical pixels
const double kPagingTouchSlop = kTouchSlop * 2.0; // Logical pixels const double kPagingTouchSlop = kTouchSlop * 2.0; // Logical pixels
const double kPanSlop = kTouchSlop * 2.0; // Logical pixels const double kPanSlop = kTouchSlop * 2.0; // Logical pixels
const double kPinchSlop = kTouchSlop; // Logical pixels const double kScaleSlop = kTouchSlop; // Logical pixels
const double kDoubleTapSlop = 100.0; // Logical pixels const double kDoubleTapSlop = 100.0; // Logical pixels
const double kWindowTouchSlop = 16.0; // Logical pixels const double kWindowTouchSlop = 16.0; // Logical pixels
const double kMinFlingVelocity = 50.0; // Logical pixels / second const double kMinFlingVelocity = 50.0; // Logical pixels / second
......
...@@ -100,7 +100,6 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz ...@@ -100,7 +100,6 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz
sky.Offset velocity = sky.Offset.zero; sky.Offset velocity = sky.Offset.zero;
if (_isFlingGesture(gestureVelocity)) if (_isFlingGesture(gestureVelocity))
velocity = new sky.Offset(gestureVelocity.x, gestureVelocity.y); velocity = new sky.Offset(gestureVelocity.x, gestureVelocity.y);
resolve(GestureDisposition.accepted);
onEnd(velocity); onEnd(velocity);
} }
_velocityTracker.reset(); _velocityTracker.reset();
......
...@@ -9,37 +9,37 @@ import 'package:sky/gestures/arena.dart'; ...@@ -9,37 +9,37 @@ import 'package:sky/gestures/arena.dart';
import 'package:sky/gestures/recognizer.dart'; import 'package:sky/gestures/recognizer.dart';
import 'package:sky/gestures/constants.dart'; import 'package:sky/gestures/constants.dart';
enum PinchState { enum ScaleState {
ready, ready,
possible, possible,
started, accepted,
ended started
} }
typedef void GesturePinchStartCallback(); typedef void GestureScaleStartCallback(sky.Point focalPoint);
typedef void GesturePinchUpdateCallback(double scale); typedef void GestureScaleUpdateCallback(double scale, sky.Point focalPoint);
typedef void GesturePinchEndCallback(); typedef void GestureScaleEndCallback();
class PinchGestureRecognizer extends GestureRecognizer { class ScaleGestureRecognizer extends GestureRecognizer {
PinchGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd }) ScaleGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd })
: super(router: router); : super(router: router);
GesturePinchStartCallback onStart; GestureScaleStartCallback onStart;
GesturePinchUpdateCallback onUpdate; GestureScaleUpdateCallback onUpdate;
GesturePinchEndCallback onEnd; GestureScaleEndCallback onEnd;
PinchState _state = PinchState.ready; ScaleState _state = ScaleState.ready;
double _initialSpan; double _initialSpan;
double _currentSpan; double _currentSpan;
Map<int, sky.Point> _pointerLocations; Map<int, sky.Point> _pointerLocations;
double get _scaleFactor => _initialSpan > 0 ? _currentSpan / _initialSpan : 1.0; double get _scaleFactor => _initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0;
void addPointer(sky.PointerEvent event) { void addPointer(sky.PointerEvent event) {
startTrackingPointer(event.pointer); startTrackingPointer(event.pointer);
if (_state == PinchState.ready) { if (_state == ScaleState.ready) {
_state = PinchState.possible; _state = ScaleState.possible;
_initialSpan = 0.0; _initialSpan = 0.0;
_currentSpan = 0.0; _currentSpan = 0.0;
_pointerLocations = new Map<int, sky.Point>(); _pointerLocations = new Map<int, sky.Point>();
...@@ -47,7 +47,7 @@ class PinchGestureRecognizer extends GestureRecognizer { ...@@ -47,7 +47,7 @@ class PinchGestureRecognizer extends GestureRecognizer {
} }
void handleEvent(sky.PointerEvent event) { void handleEvent(sky.PointerEvent event) {
assert(_state != PinchState.ready); assert(_state != ScaleState.ready);
bool configChanged = false; bool configChanged = false;
switch(event.type) { switch(event.type) {
case 'pointerup': case 'pointerup':
...@@ -63,6 +63,12 @@ class PinchGestureRecognizer extends GestureRecognizer { ...@@ -63,6 +63,12 @@ class PinchGestureRecognizer extends GestureRecognizer {
break; break;
} }
_update(configChanged);
stopTrackingIfPointerNoLongerDown(event);
}
void _update(bool configChanged) {
int count = _pointerLocations.keys.length; int count = _pointerLocations.keys.length;
// Compute the focal point // Compute the focal point
...@@ -79,58 +85,53 @@ class PinchGestureRecognizer extends GestureRecognizer { ...@@ -79,58 +85,53 @@ class PinchGestureRecognizer extends GestureRecognizer {
if (configChanged) { if (configChanged) {
_initialSpan = _currentSpan; _initialSpan = _currentSpan;
if (_state == PinchState.started) { if (_state == ScaleState.started) {
_state = PinchState.ended;
if (onEnd != null) if (onEnd != null)
onEnd(); onEnd();
_state = ScaleState.accepted;
} }
} }
if (_state == PinchState.ready) if (_state == ScaleState.ready)
_state = PinchState.possible; _state = ScaleState.possible;
if (_state == PinchState.possible && if (_state == ScaleState.possible &&
(_currentSpan - _initialSpan).abs() > kPinchSlop) { (_currentSpan - _initialSpan).abs() > kScaleSlop) {
resolve(GestureDisposition.accepted); resolve(GestureDisposition.accepted);
} }
if (_state == PinchState.ended && _currentSpan != _initialSpan) { if (_state == ScaleState.accepted && !configChanged) {
_state = PinchState.started; _state = ScaleState.started;
if (onStart != null) if (onStart != null)
onStart(); onStart(focalPoint);
} }
if (_state == PinchState.started && onUpdate != null) if (_state == ScaleState.started && onUpdate != null)
onUpdate(_scaleFactor); onUpdate(_scaleFactor, focalPoint);
stopTrackingIfPointerNoLongerDown(event);
} }
void acceptGesture(int pointer) { void acceptGesture(int pointer) {
if (_state != PinchState.started) { if (_state != ScaleState.accepted) {
_state = PinchState.started; _state = ScaleState.accepted;
if (onStart != null) _update(false);
onStart();
if (onUpdate != null)
onUpdate(_scaleFactor);
} }
} }
void didStopTrackingLastPointer(int pointer) { void didStopTrackingLastPointer(int pointer) {
switch(_state) { switch(_state) {
case PinchState.possible: case ScaleState.possible:
resolve(GestureDisposition.rejected); resolve(GestureDisposition.rejected);
break; break;
case PinchState.ready: case ScaleState.ready:
assert(false); assert(false); // We should have not seen a pointer yet
break; break;
case PinchState.started: case ScaleState.accepted:
assert(false);
break; break;
case PinchState.ended: case ScaleState.started:
assert(false); // We should be in the accepted state when user is done
break; break;
} }
_state = PinchState.ready; _state = ScaleState.ready;
} }
void dispose() { void dispose() {
......
...@@ -6,7 +6,7 @@ import 'dart:sky' as sky; ...@@ -6,7 +6,7 @@ import 'dart:sky' as sky;
import 'package:sky/gestures/drag.dart'; import 'package:sky/gestures/drag.dart';
import 'package:sky/gestures/long_press.dart'; import 'package:sky/gestures/long_press.dart';
import 'package:sky/gestures/pinch.dart'; import 'package:sky/gestures/scale.dart';
import 'package:sky/gestures/recognizer.dart'; import 'package:sky/gestures/recognizer.dart';
import 'package:sky/gestures/show_press.dart'; import 'package:sky/gestures/show_press.dart';
import 'package:sky/gestures/tap.dart'; import 'package:sky/gestures/tap.dart';
...@@ -29,9 +29,9 @@ class GestureDetector extends StatefulComponent { ...@@ -29,9 +29,9 @@ class GestureDetector extends StatefulComponent {
this.onPanStart, this.onPanStart,
this.onPanUpdate, this.onPanUpdate,
this.onPanEnd, this.onPanEnd,
this.onPinchStart, this.onScaleStart,
this.onPinchUpdate, this.onScaleUpdate,
this.onPinchEnd this.onScaleEnd
}) : super(key: key); }) : super(key: key);
Widget child; Widget child;
...@@ -51,9 +51,9 @@ class GestureDetector extends StatefulComponent { ...@@ -51,9 +51,9 @@ class GestureDetector extends StatefulComponent {
GesturePanUpdateCallback onPanUpdate; GesturePanUpdateCallback onPanUpdate;
GesturePanEndCallback onPanEnd; GesturePanEndCallback onPanEnd;
GesturePinchStartCallback onPinchStart; GestureScaleStartCallback onScaleStart;
GesturePinchUpdateCallback onPinchUpdate; GestureScaleUpdateCallback onScaleUpdate;
GesturePinchEndCallback onPinchEnd; GestureScaleEndCallback onScaleEnd;
void syncConstructorArguments(GestureDetector source) { void syncConstructorArguments(GestureDetector source) {
child = source.child; child = source.child;
...@@ -69,9 +69,9 @@ class GestureDetector extends StatefulComponent { ...@@ -69,9 +69,9 @@ class GestureDetector extends StatefulComponent {
onPanStart = source.onPanStart; onPanStart = source.onPanStart;
onPanUpdate = source.onPanUpdate; onPanUpdate = source.onPanUpdate;
onPanEnd = source.onPanEnd; onPanEnd = source.onPanEnd;
onPinchStart = source.onPinchStart; onScaleStart = source.onScaleStart;
onPinchUpdate = source.onPinchUpdate; onScaleUpdate = source.onScaleUpdate;
onPinchEnd = source.onPinchEnd; onScaleEnd = source.onScaleEnd;
_syncGestureListeners(); _syncGestureListeners();
} }
...@@ -114,16 +114,18 @@ class GestureDetector extends StatefulComponent { ...@@ -114,16 +114,18 @@ class GestureDetector extends StatefulComponent {
PanGestureRecognizer _pan; PanGestureRecognizer _pan;
PanGestureRecognizer _ensurePan() { PanGestureRecognizer _ensurePan() {
assert(_scale == null); // Scale is a superset of pan; just use scale
if (_pan == null) if (_pan == null)
_pan = new PanGestureRecognizer(router: _router); _pan = new PanGestureRecognizer(router: _router);
return _pan; return _pan;
} }
PinchGestureRecognizer _pinch; ScaleGestureRecognizer _scale;
PinchGestureRecognizer _ensurePinch() { ScaleGestureRecognizer _ensureScale() {
if (_pinch == null) assert(_pan == null); // Scale is a superset of pan; just use scale
_pinch = new PinchGestureRecognizer(router: _router); if (_scale == null)
return _pinch; _scale = new ScaleGestureRecognizer(router: _router);
return _scale;
} }
void didMount() { void didMount() {
...@@ -139,7 +141,7 @@ class GestureDetector extends StatefulComponent { ...@@ -139,7 +141,7 @@ class GestureDetector extends StatefulComponent {
_verticalDrag = _ensureDisposed(_verticalDrag); _verticalDrag = _ensureDisposed(_verticalDrag);
_horizontalDrag = _ensureDisposed(_horizontalDrag); _horizontalDrag = _ensureDisposed(_horizontalDrag);
_pan = _ensureDisposed(_pan); _pan = _ensureDisposed(_pan);
_pinch = _ensureDisposed(_pinch); _scale = _ensureDisposed(_scale);
} }
void _syncGestureListeners() { void _syncGestureListeners() {
...@@ -149,7 +151,7 @@ class GestureDetector extends StatefulComponent { ...@@ -149,7 +151,7 @@ class GestureDetector extends StatefulComponent {
_syncVerticalDrag(); _syncVerticalDrag();
_syncHorizontalDrag(); _syncHorizontalDrag();
_syncPan(); _syncPan();
_syncPinch(); _syncScale();
} }
void _syncTap() { void _syncTap() {
...@@ -206,14 +208,14 @@ class GestureDetector extends StatefulComponent { ...@@ -206,14 +208,14 @@ class GestureDetector extends StatefulComponent {
} }
} }
void _syncPinch() { void _syncScale() {
if (onPinchStart == null && onPinchUpdate == null && onPinchEnd == null) { if (onScaleStart == null && onScaleUpdate == null && onScaleEnd == null) {
_pinch = _ensureDisposed(_pan); _scale = _ensureDisposed(_pan);
} else { } else {
_ensurePinch() _ensureScale()
..onStart = onPinchStart ..onStart = onScaleStart
..onUpdate = onPinchUpdate ..onUpdate = onScaleUpdate
..onEnd = onPinchEnd; ..onEnd = onScaleEnd;
} }
} }
...@@ -235,8 +237,8 @@ class GestureDetector extends StatefulComponent { ...@@ -235,8 +237,8 @@ class GestureDetector extends StatefulComponent {
_horizontalDrag.addPointer(event); _horizontalDrag.addPointer(event);
if (_pan != null) if (_pan != null)
_pan.addPointer(event); _pan.addPointer(event);
if (_pinch != null) if (_scale != null)
_pinch.addPointer(event); _scale.addPointer(event);
return EventDisposition.processed; 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