drag.dart 4.4 KB
Newer Older
1 2 3 4
// 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.

5 6 7
import 'arena.dart';
import 'recognizer.dart';
import 'constants.dart';
8
import 'events.dart';
9
import 'velocity_tracker.dart';
10

11
enum DragState {
12 13 14 15 16
  ready,
  possible,
  accepted
}

Ian Hickson's avatar
Ian Hickson committed
17
typedef void GestureDragStartCallback(Point globalPosition);
18
typedef void GestureDragUpdateCallback(double delta);
19
typedef void GestureDragEndCallback(Velocity velocity);
20

Ian Hickson's avatar
Ian Hickson committed
21 22
typedef void GesturePanStartCallback(Point globalPosition);
typedef void GesturePanUpdateCallback(Offset delta);
23
typedef void GesturePanEndCallback(Velocity velocity);
24

25
typedef void _GesturePolymorphicUpdateCallback<T>(T delta);
26

27
bool _isFlingGesture(Velocity velocity) {
28
  assert(velocity != null);
29 30 31
  final double speedSquared = velocity.pixelsPerSecond.distanceSquared;
  return speedSquared > kMinFlingVelocity * kMinFlingVelocity
      && speedSquared < kMaxFlingVelocity * kMaxFlingVelocity;
32 33
}

34
abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGestureRecognizer {
35
  GestureDragStartCallback onStart;
36
  _GesturePolymorphicUpdateCallback<T> onUpdate;
37
  GestureDragEndCallback onEnd;
38

39
  DragState _state = DragState.ready;
Ian Hickson's avatar
Ian Hickson committed
40
  Point _initialPosition;
41
  T _pendingDragDelta;
42

43
  T get _initialPendingDragDelta;
Ian Hickson's avatar
Ian Hickson committed
44
  T _getDragDelta(PointerEvent event);
45
  bool get _hasSufficientPendingDragDeltaToAccept;
46

47
  Map<int, VelocityTracker> _velocityTrackers = new Map<int, VelocityTracker>();
48

Ian Hickson's avatar
Ian Hickson committed
49
  void addPointer(PointerEvent event) {
50
    startTrackingPointer(event.pointer);
51
    _velocityTrackers[event.pointer] = new VelocityTracker();
52 53
    if (_state == DragState.ready) {
      _state = DragState.possible;
54
      _initialPosition = event.position;
55
      _pendingDragDelta = _initialPendingDragDelta;
56 57 58
    }
  }

Ian Hickson's avatar
Ian Hickson committed
59
  void handleEvent(PointerEvent event) {
60
    assert(_state != DragState.ready);
Ian Hickson's avatar
Ian Hickson committed
61
    if (event is PointerMoveEvent) {
62
      VelocityTracker tracker = _velocityTrackers[event.pointer];
63
      assert(tracker != null);
Ian Hickson's avatar
Ian Hickson committed
64
      tracker.addPosition(event.timeStamp, event.position);
65 66
      T delta = _getDragDelta(event);
      if (_state == DragState.accepted) {
67 68
        if (onUpdate != null)
          onUpdate(delta);
69
      } else {
70 71
        _pendingDragDelta += delta;
        if (_hasSufficientPendingDragDeltaToAccept)
72 73 74 75 76 77 78
          resolve(GestureDisposition.accepted);
      }
    }
    stopTrackingIfPointerNoLongerDown(event);
  }

  void acceptGesture(int pointer) {
79 80 81
    if (_state != DragState.accepted) {
      _state = DragState.accepted;
      T delta = _pendingDragDelta;
82
      _pendingDragDelta = _initialPendingDragDelta;
83
      if (onStart != null)
84
        onStart(_initialPosition);
85
      if (delta != _initialPendingDragDelta && onUpdate != null)
86
        onUpdate(delta);
87 88 89
    }
  }

90
  void didStopTrackingLastPointer(int pointer) {
91
    if (_state == DragState.possible) {
92
      resolve(GestureDisposition.rejected);
93
      _state = DragState.ready;
94 95
      return;
    }
96 97
    bool wasAccepted = (_state == DragState.accepted);
    _state = DragState.ready;
98
    if (wasAccepted && onEnd != null) {
99
      VelocityTracker tracker = _velocityTrackers[pointer];
100 101
      assert(tracker != null);

102
      Velocity velocity = tracker.getVelocity();
Ian Hickson's avatar
Ian Hickson committed
103 104
      if (velocity != null && _isFlingGesture(velocity))
        onEnd(velocity);
Hans Muller's avatar
Hans Muller committed
105
      else
106
        onEnd(Velocity.zero);
107
    }
108
    _velocityTrackers.clear();
109 110 111
  }

  void dispose() {
112
    _velocityTrackers.clear();
113
    super.dispose();
114
  }
115 116
}

117 118
class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
  double get _initialPendingDragDelta => 0.0;
Ian Hickson's avatar
Ian Hickson committed
119
  double _getDragDelta(PointerEvent event) => event.delta.dy;
120
  bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
121 122

  String toStringShort() => 'vertical drag';
123 124
}

125 126
class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
  double get _initialPendingDragDelta => 0.0;
Ian Hickson's avatar
Ian Hickson committed
127
  double _getDragDelta(PointerEvent event) => event.delta.dx;
128
  bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
129 130

  String toStringShort() => 'horizontal drag';
131 132
}

Ian Hickson's avatar
Ian Hickson committed
133 134 135
class PanGestureRecognizer extends _DragGestureRecognizer<Offset> {
  Offset get _initialPendingDragDelta => Offset.zero;
  Offset _getDragDelta(PointerEvent event) => event.delta;
136
  bool get _hasSufficientPendingDragDeltaToAccept {
137
    return _pendingDragDelta.distance > kPanSlop;
138
  }
139 140

  String toStringShort() => 'pan';
141
}