blob: abbe4dc4e0bfe0858cdbfad75e98b9e926ec2219 [file] [log] [blame]
// 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 'arena.dart';
import 'constants.dart';
import 'events.dart';
import 'recognizer.dart';
/// Callback signature for [LongPressGestureRecognizer.onLongPress].
///
/// Called when a pointer has remained in contact with the screen at the
/// same location for a long period of time.
typedef GestureLongPressCallback = void Function();
/// Callback signature for [LongPressGestureRecognizer.onLongPressUp].
///
/// Called when a pointer stops contacting the screen after a long press
/// gesture was detected.
typedef GestureLongPressUpCallback = void Function();
/// Callback signature for [LongPressGestureRecognizer.onLongPressStart].
///
/// Called when a pointer has remained in contact with the screen at the
/// same location for a long period of time. Also reports the long press down
/// position.
typedef GestureLongPressStartCallback = void Function(LongPressStartDetails details);
/// Callback signature for [LongPressGestureRecognizer.onLongPressMoveUpdate].
///
/// Called when a pointer is moving after being held in contact at the same
/// location for a long period of time. Reports the new position and its offset
/// from the original down position.
typedef GestureLongPressMoveUpdateCallback = void Function(LongPressMoveUpdateDetails details);
/// Callback signature for [LongPressGestureRecognizer.onLongPressEnd].
///
/// Called when a pointer stops contacting the screen after a long press
/// gesture was detected. Also reports the position where the pointer stopped
/// contacting the screen.
typedef GestureLongPressEndCallback = void Function(LongPressEndDetails details);
/// Details for callbacks that use [GestureLongPressStartCallback].
///
/// See also:
///
/// * [LongPressGestureRecognizer.onLongPressStart], which uses [GestureLongPressStartCallback].
/// * [LongPressMoveUpdateDetails], the details for [GestureLongPressMoveUpdateCallback]
/// * [LongPressEndDetails], the details for [GestureLongPressEndCallback].
class LongPressStartDetails {
/// Creates the details for a [GestureLongPressStartCallback].
///
/// The [globalPosition] argument must not be null.
const LongPressStartDetails({ this.globalPosition = Offset.zero })
: assert(globalPosition != null);
/// The global position at which the pointer contacted the screen.
final Offset globalPosition;
}
/// Details for callbacks that use [GestureLongPressMoveUpdateCallback].
///
/// See also:
///
/// * [LongPressGestureRecognizer.onLongPressMoveUpdate], which uses [GestureLongPressMoveUpdateCallback].
/// * [LongPressEndDetails], the details for [GestureLongPressEndCallback]
/// * [LongPressStartDetails], the details for [GestureLongPressStartCallback].
class LongPressMoveUpdateDetails {
/// Creates the details for a [GestureLongPressMoveUpdateCallback].
///
/// The [globalPosition] and [offsetFromOrigin] arguments must not be null.
const LongPressMoveUpdateDetails({
this.globalPosition = Offset.zero,
this.offsetFromOrigin = Offset.zero,
}) : assert(globalPosition != null),
assert(offsetFromOrigin != null);
/// The global position of the pointer when it triggered this update.
final Offset globalPosition;
/// A delta offset from the point where the long press drag initially contacted
/// the screen to the point where the pointer is currently located (the
/// present [globalPosition]) when this callback is triggered.
final Offset offsetFromOrigin;
}
/// Details for callbacks that use [GestureLongPressEndCallback].
///
/// See also:
///
/// * [LongPressGestureRecognizer.onLongPressEnd], which uses [GestureLongPressEndCallback].
/// * [LongPressMoveUpdateDetails], the details for [GestureLongPressMoveUpdateCallback]
/// * [LongPressStartDetails], the details for [GestureLongPressStartCallback].
class LongPressEndDetails {
/// Creates the details for a [GestureLongPressEndCallback].
///
/// The [globalPosition] argument must not be null.
const LongPressEndDetails({ this.globalPosition = Offset.zero })
: assert(globalPosition != null);
/// The global position at which the pointer lifted from the screen.
final Offset globalPosition;
}
/// Recognizes when the user has pressed down at the same location for a long
/// period of time.
///
/// The gesture must not deviate in position from its touch down point for 500ms
/// until it's recognized. Once the gesture is accepted, the finger can be
/// moved, triggering [onLongPressMoveUpdate] callbacks, unless the
/// [postAcceptSlopTolerance] constructor argument is specified.
class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
/// Creates a long-press gesture recognizer.
///
/// Consider assigning the [onLongPressStart] callback after creating this
/// object.
///
/// The [postAcceptSlopTolerance] argument can be used to specify a maximum
/// allowed distance for the gesture to deviate from the starting point once
/// the long press has triggered. If the gesture deviates past that point,
/// subsequent callbacks ([onLongPressMoveUpdate], [onLongPressUp],
/// [onLongPressEnd]) will stop. Defaults to null, which means the gesture
/// can be moved without limit once the long press is accepted.
LongPressGestureRecognizer({
double postAcceptSlopTolerance,
PointerDeviceKind kind,
Object debugOwner,
}) : super(
deadline: kLongPressTimeout,
postAcceptSlopTolerance: postAcceptSlopTolerance,
kind: kind,
debugOwner: debugOwner,
);
bool _longPressAccepted = false;
Offset _longPressOrigin;
/// Called when a long press gesture has been recognized.
///
/// See also:
///
/// * [onLongPressStart], which has the same timing but has data for the
/// press location.
GestureLongPressCallback onLongPress;
/// Callback for long press start with gesture location.
///
/// See also:
///
/// * [onLongPress], which has the same timing but without the location data.
GestureLongPressStartCallback onLongPressStart;
/// Callback for moving the gesture after the lang press is recognized.
GestureLongPressMoveUpdateCallback onLongPressMoveUpdate;
/// Called when the pointer stops contacting the screen after the long-press.
///
/// See also:
///
/// * [onLongPressEnd], which has the same timing but has data for the up
/// gesture location.
GestureLongPressUpCallback onLongPressUp;
/// Callback for long press end with gesture location.
///
/// See also:
///
/// * [onLongPressUp], which has the same timing but without the location data.
GestureLongPressEndCallback onLongPressEnd;
@override
void didExceedDeadline() {
resolve(GestureDisposition.accepted);
_longPressAccepted = true;
super.acceptGesture(primaryPointer);
if (onLongPress != null) {
invokeCallback<void>('onLongPress', onLongPress);
}
if (onLongPressStart != null) {
invokeCallback<void>('onLongPressStart', () {
onLongPressStart(LongPressStartDetails(
globalPosition: _longPressOrigin,
));
});
}
}
@override
void handlePrimaryPointer(PointerEvent event) {
if (event is PointerUpEvent) {
if (_longPressAccepted == true) {
if (onLongPressUp != null) {
invokeCallback<void>('onLongPressUp', onLongPressUp);
}
if (onLongPressEnd != null) {
invokeCallback<void>('onLongPressEnd', () {
onLongPressEnd(LongPressEndDetails(
globalPosition: event.position,
));
});
}
_longPressAccepted = false;
} else {
resolve(GestureDisposition.rejected);
}
} else if (event is PointerDownEvent || event is PointerCancelEvent) {
// The first touch.
_longPressAccepted = false;
_longPressOrigin = event.position;
} else if (event is PointerMoveEvent && _longPressAccepted && onLongPressMoveUpdate != null) {
invokeCallback<void>('onLongPressMoveUpdate', () {
onLongPressMoveUpdate(LongPressMoveUpdateDetails(
globalPosition: event.position,
offsetFromOrigin: event.position - _longPressOrigin,
));
});
}
}
@override
void acceptGesture(int pointer) {
// Winning the arena isn't important here since it may happen from a sweep.
// Explicitly exceeding the deadline puts the gesture in accepted state.
}
@override
String get debugDescription => 'long press';
}