Commit 109a496e authored by Collin Jackson's avatar Collin Jackson

Update scale API and add example

parent 4ab60697
// 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 callback(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: callback)
)
)
)
);
}
}
void main() => runApp(new ScaleApp());
......@@ -18,7 +18,7 @@ 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 kScaleSlop = 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
......
......@@ -100,7 +100,6 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz
sky.Offset velocity = sky.Offset.zero;
if (_isFlingGesture(gestureVelocity))
velocity = new sky.Offset(gestureVelocity.x, gestureVelocity.y);
resolve(GestureDisposition.accepted);
onEnd(velocity);
}
_velocityTracker.reset();
......
......@@ -9,37 +9,37 @@ import 'package:sky/gestures/arena.dart';
import 'package:sky/gestures/recognizer.dart';
import 'package:sky/gestures/constants.dart';
enum PinchState {
enum ScaleState {
ready,
possible,
started,
ended
accepted,
started
}
typedef void GesturePinchStartCallback();
typedef void GesturePinchUpdateCallback(double scale);
typedef void GesturePinchEndCallback();
typedef void GestureScaleStartCallback(sky.Point focalPoint);
typedef void GestureScaleUpdateCallback(double scale, sky.Point focalPoint);
typedef void GestureScaleEndCallback();
class PinchGestureRecognizer extends GestureRecognizer {
PinchGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd })
class ScaleGestureRecognizer extends GestureRecognizer {
ScaleGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd })
: super(router: router);
GesturePinchStartCallback onStart;
GesturePinchUpdateCallback onUpdate;
GesturePinchEndCallback onEnd;
GestureScaleStartCallback onStart;
GestureScaleUpdateCallback onUpdate;
GestureScaleEndCallback onEnd;
PinchState _state = PinchState.ready;
ScaleState _state = ScaleState.ready;
double _initialSpan;
double _currentSpan;
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) {
startTrackingPointer(event.pointer);
if (_state == PinchState.ready) {
_state = PinchState.possible;
if (_state == ScaleState.ready) {
_state = ScaleState.possible;
_initialSpan = 0.0;
_currentSpan = 0.0;
_pointerLocations = new Map<int, sky.Point>();
......@@ -47,7 +47,7 @@ class PinchGestureRecognizer extends GestureRecognizer {
}
void handleEvent(sky.PointerEvent event) {
assert(_state != PinchState.ready);
assert(_state != ScaleState.ready);
bool configChanged = false;
switch(event.type) {
case 'pointerup':
......@@ -63,6 +63,12 @@ class PinchGestureRecognizer extends GestureRecognizer {
break;
}
_update(configChanged);
stopTrackingIfPointerNoLongerDown(event);
}
void _update(bool configChanged) {
int count = _pointerLocations.keys.length;
// Compute the focal point
......@@ -79,58 +85,53 @@ class PinchGestureRecognizer extends GestureRecognizer {
if (configChanged) {
_initialSpan = _currentSpan;
if (_state == PinchState.started) {
_state = PinchState.ended;
if (_state == ScaleState.started) {
if (onEnd != null)
onEnd();
_state = ScaleState.accepted;
}
}
if (_state == PinchState.ready)
_state = PinchState.possible;
if (_state == ScaleState.ready)
_state = ScaleState.possible;
if (_state == PinchState.possible &&
(_currentSpan - _initialSpan).abs() > kPinchSlop) {
if (_state == ScaleState.possible &&
(_currentSpan - _initialSpan).abs() > kScaleSlop) {
resolve(GestureDisposition.accepted);
}
if (_state == PinchState.ended && _currentSpan != _initialSpan) {
_state = PinchState.started;
if (_state == ScaleState.accepted && !configChanged) {
_state = ScaleState.started;
if (onStart != null)
onStart();
onStart(focalPoint);
}
if (_state == PinchState.started && onUpdate != null)
onUpdate(_scaleFactor);
stopTrackingIfPointerNoLongerDown(event);
if (_state == ScaleState.started && onUpdate != null)
onUpdate(_scaleFactor, focalPoint);
}
void acceptGesture(int pointer) {
if (_state != PinchState.started) {
_state = PinchState.started;
if (onStart != null)
onStart();
if (onUpdate != null)
onUpdate(_scaleFactor);
if (_state != ScaleState.accepted) {
_state = ScaleState.accepted;
_update(false);
}
}
void didStopTrackingLastPointer(int pointer) {
switch(_state) {
case PinchState.possible:
case ScaleState.possible:
resolve(GestureDisposition.rejected);
break;
case PinchState.ready:
assert(false);
case ScaleState.ready:
assert(false); // We should have not seen a pointer yet
break;
case PinchState.started:
assert(false);
case ScaleState.accepted:
break;
case PinchState.ended:
case ScaleState.started:
assert(false); // We should be in the accepted state when user is done
break;
}
_state = PinchState.ready;
_state = ScaleState.ready;
}
void dispose() {
......
......@@ -6,7 +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/scale.dart';
import 'package:sky/gestures/recognizer.dart';
import 'package:sky/gestures/show_press.dart';
import 'package:sky/gestures/tap.dart';
......@@ -29,9 +29,9 @@ class GestureDetector extends StatefulComponent {
this.onPanStart,
this.onPanUpdate,
this.onPanEnd,
this.onPinchStart,
this.onPinchUpdate,
this.onPinchEnd
this.onScaleStart,
this.onScaleUpdate,
this.onScaleEnd
}) : super(key: key);
Widget child;
......@@ -51,9 +51,9 @@ class GestureDetector extends StatefulComponent {
GesturePanUpdateCallback onPanUpdate;
GesturePanEndCallback onPanEnd;
GesturePinchStartCallback onPinchStart;
GesturePinchUpdateCallback onPinchUpdate;
GesturePinchEndCallback onPinchEnd;
GestureScaleStartCallback onScaleStart;
GestureScaleUpdateCallback onScaleUpdate;
GestureScaleEndCallback onScaleEnd;
void syncConstructorArguments(GestureDetector source) {
child = source.child;
......@@ -69,9 +69,9 @@ class GestureDetector extends StatefulComponent {
onPanStart = source.onPanStart;
onPanUpdate = source.onPanUpdate;
onPanEnd = source.onPanEnd;
onPinchStart = source.onPinchStart;
onPinchUpdate = source.onPinchUpdate;
onPinchEnd = source.onPinchEnd;
onScaleStart = source.onScaleStart;
onScaleUpdate = source.onScaleUpdate;
onScaleEnd = source.onScaleEnd;
_syncGestureListeners();
}
......@@ -114,16 +114,18 @@ class GestureDetector extends StatefulComponent {
PanGestureRecognizer _pan;
PanGestureRecognizer _ensurePan() {
assert(_scale == null); // Scale is a superset of pan; just use scale
if (_pan == null)
_pan = new PanGestureRecognizer(router: _router);
return _pan;
}
PinchGestureRecognizer _pinch;
PinchGestureRecognizer _ensurePinch() {
if (_pinch == null)
_pinch = new PinchGestureRecognizer(router: _router);
return _pinch;
ScaleGestureRecognizer _scale;
ScaleGestureRecognizer _ensureScale() {
assert(_pan == null); // Scale is a superset of pan; just use scale
if (_scale == null)
_scale = new ScaleGestureRecognizer(router: _router);
return _scale;
}
void didMount() {
......@@ -139,7 +141,7 @@ class GestureDetector extends StatefulComponent {
_verticalDrag = _ensureDisposed(_verticalDrag);
_horizontalDrag = _ensureDisposed(_horizontalDrag);
_pan = _ensureDisposed(_pan);
_pinch = _ensureDisposed(_pinch);
_scale = _ensureDisposed(_scale);
}
void _syncGestureListeners() {
......@@ -149,7 +151,7 @@ class GestureDetector extends StatefulComponent {
_syncVerticalDrag();
_syncHorizontalDrag();
_syncPan();
_syncPinch();
_syncScale();
}
void _syncTap() {
......@@ -206,14 +208,14 @@ class GestureDetector extends StatefulComponent {
}
}
void _syncPinch() {
if (onPinchStart == null && onPinchUpdate == null && onPinchEnd == null) {
_pinch = _ensureDisposed(_pan);
void _syncScale() {
if (onScaleStart == null && onScaleUpdate == null && onScaleEnd == null) {
_scale = _ensureDisposed(_pan);
} else {
_ensurePinch()
..onStart = onPinchStart
..onUpdate = onPinchUpdate
..onEnd = onPinchEnd;
_ensureScale()
..onStart = onScaleStart
..onUpdate = onScaleUpdate
..onEnd = onScaleEnd;
}
}
......@@ -235,8 +237,8 @@ class GestureDetector extends StatefulComponent {
_horizontalDrag.addPointer(event);
if (_pan != null)
_pan.addPointer(event);
if (_pinch != null)
_pinch.addPointer(event);
if (_scale != null)
_scale.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