Commit 0e33151e authored by Adam Barth's avatar Adam Barth

Merge pull request #1612 from abarth/doc_gestures

Add some more dartdoc to gestures.dart
parents ee832251 8319a6c2
...@@ -2,9 +2,13 @@ ...@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
/// Whether the gesture was accepted or rejected.
enum GestureDisposition { enum GestureDisposition {
/// This gesture was accepted as the interpretation of the user's input.
accepted, accepted,
rejected
/// This gesture was rejected as the interpretation of the user's input.
rejected,
} }
/// Represents an object participating in an arena. /// Represents an object participating in an arena.
...@@ -61,26 +65,33 @@ class _GestureArenaState { ...@@ -61,26 +65,33 @@ class _GestureArenaState {
} }
/// The first member to accept or the last member to not to reject wins. /// The first member to accept or the last member to not to reject wins.
///
/// See [https://flutter.io/gestures/#gesture-disambiguation] for more
/// information about the role this class plays in the gesture system.
class GestureArena { class GestureArena {
final Map<Object, _GestureArenaState> _arenas = new Map<Object, _GestureArenaState>(); final Map<Object, _GestureArenaState> _arenas = new Map<Object, _GestureArenaState>();
GestureArenaEntry add(Object key, GestureArenaMember member) { /// Adds a new member (e.g., gesture recognizer) to the arena.
_GestureArenaState state = _arenas.putIfAbsent(key, () => new _GestureArenaState()); GestureArenaEntry add(Object arenaKey, GestureArenaMember member) {
_GestureArenaState state = _arenas.putIfAbsent(arenaKey, () => new _GestureArenaState());
state.add(member); state.add(member);
return new GestureArenaEntry._(this, key, member); return new GestureArenaEntry._(this, arenaKey, member);
} }
void close(Object key) { /// Prevents new members from entering the arena.
_GestureArenaState state = _arenas[key]; ///
/// Called after the framework has finished dispatching the pointer down event.
void close(Object arenaKey) {
_GestureArenaState state = _arenas[arenaKey];
if (state == null) if (state == null)
return; // This arena either never existed or has been resolved. return; // This arena either never existed or has been resolved.
state.isOpen = false; state.isOpen = false;
_tryToResolveArena(key, state); _tryToResolveArena(arenaKey, state);
} }
/// Forces resolution on this arena, giving the win to the first member. /// Forces resolution of the arena, giving the win to the first member.
void sweep(Object key) { void sweep(Object arenaKey) {
_GestureArenaState state = _arenas[key]; _GestureArenaState state = _arenas[arenaKey];
if (state == null) if (state == null)
return; // This arena either never existed or has been resolved. return; // This arena either never existed or has been resolved.
assert(!state.isOpen); assert(!state.isOpen);
...@@ -88,13 +99,13 @@ class GestureArena { ...@@ -88,13 +99,13 @@ class GestureArena {
state.hasPendingSweep = true; state.hasPendingSweep = true;
return; // This arena is being held for a long-lived member return; // This arena is being held for a long-lived member
} }
_arenas.remove(key); _arenas.remove(arenaKey);
if (!state.members.isEmpty) { if (!state.members.isEmpty) {
// First member wins // First member wins
state.members.first.acceptGesture(key); state.members.first.acceptGesture(arenaKey);
// Give all the other members the bad news // Give all the other members the bad news
for (int i = 1; i < state.members.length; i++) for (int i = 1; i < state.members.length; i++)
state.members[i].rejectGesture(key); state.members[i].rejectGesture(arenaKey);
} }
} }
...@@ -110,58 +121,58 @@ class GestureArena { ...@@ -110,58 +121,58 @@ class GestureArena {
/// ///
/// If a sweep was attempted on a held arena, the sweep will be done /// If a sweep was attempted on a held arena, the sweep will be done
/// on release. /// on release.
void release(Object key) { void release(Object arenaKey) {
_GestureArenaState state = _arenas[key]; _GestureArenaState state = _arenas[arenaKey];
if (state == null) if (state == null)
return; // This arena either never existed or has been resolved. return; // This arena either never existed or has been resolved.
state.isHeld = false; state.isHeld = false;
if (state.hasPendingSweep) if (state.hasPendingSweep)
sweep(key); sweep(arenaKey);
} }
void _tryToResolveArena(Object key, _GestureArenaState state) { void _tryToResolveArena(Object arenaKey, _GestureArenaState state) {
assert(_arenas[key] == state); assert(_arenas[arenaKey] == state);
assert(!state.isOpen); assert(!state.isOpen);
if (state.members.length == 1) { if (state.members.length == 1) {
_arenas.remove(key); _arenas.remove(arenaKey);
state.members.first.acceptGesture(key); state.members.first.acceptGesture(arenaKey);
} else if (state.members.isEmpty) { } else if (state.members.isEmpty) {
_arenas.remove(key); _arenas.remove(arenaKey);
} else if (state.eagerWinner != null) { } else if (state.eagerWinner != null) {
_resolveInFavorOf(key, state, state.eagerWinner); _resolveInFavorOf(arenaKey, state, state.eagerWinner);
} }
} }
void _resolve(Object key, GestureArenaMember member, GestureDisposition disposition) { void _resolve(Object arenaKey, GestureArenaMember member, GestureDisposition disposition) {
_GestureArenaState state = _arenas[key]; _GestureArenaState state = _arenas[arenaKey];
if (state == null) if (state == null)
return; // This arena has already resolved. return; // This arena has already resolved.
assert(state.members.contains(member)); assert(state.members.contains(member));
if (disposition == GestureDisposition.rejected) { if (disposition == GestureDisposition.rejected) {
state.members.remove(member); state.members.remove(member);
member.rejectGesture(key); member.rejectGesture(arenaKey);
if (!state.isOpen) if (!state.isOpen)
_tryToResolveArena(key, state); _tryToResolveArena(arenaKey, state);
} else { } else {
assert(disposition == GestureDisposition.accepted); assert(disposition == GestureDisposition.accepted);
if (state.isOpen) { if (state.isOpen) {
state.eagerWinner ??= member; state.eagerWinner ??= member;
} else { } else {
_resolveInFavorOf(key, state, member); _resolveInFavorOf(arenaKey, state, member);
} }
} }
} }
void _resolveInFavorOf(Object key, _GestureArenaState state, GestureArenaMember member) { void _resolveInFavorOf(Object arenaKey, _GestureArenaState state, GestureArenaMember member) {
assert(state == _arenas[key]); assert(state == _arenas[arenaKey]);
assert(state != null); assert(state != null);
assert(state.eagerWinner == null || state.eagerWinner == member); assert(state.eagerWinner == null || state.eagerWinner == member);
assert(!state.isOpen); assert(!state.isOpen);
_arenas.remove(key); _arenas.remove(arenaKey);
for (GestureArenaMember rejectedMember in state.members) { for (GestureArenaMember rejectedMember in state.members) {
if (rejectedMember != member) if (rejectedMember != member)
rejectedMember.rejectGesture(key); rejectedMember.rejectGesture(arenaKey);
} }
member.acceptGesture(key); member.acceptGesture(arenaKey);
} }
} }
...@@ -18,6 +18,7 @@ import 'pointer_router.dart'; ...@@ -18,6 +18,7 @@ import 'pointer_router.dart';
typedef void GesturerExceptionHandler(PointerEvent event, HitTestTarget target, dynamic exception, StackTrace stack); typedef void GesturerExceptionHandler(PointerEvent event, HitTestTarget target, dynamic exception, StackTrace stack);
/// A binding for the gesture subsystem.
abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestable { abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestable {
void initInstances() { void initInstances() {
...@@ -26,8 +27,9 @@ abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestabl ...@@ -26,8 +27,9 @@ abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestabl
ui.window.onPointerPacket = _handlePointerPacket; ui.window.onPointerPacket = _handlePointerPacket;
} }
static Gesturer _instance; /// The singleton instance of this object.
static Gesturer get instance => _instance; static Gesturer get instance => _instance;
static Gesturer _instance;
void _handlePointerPacket(ByteData serializedPacket) { void _handlePointerPacket(ByteData serializedPacket) {
final mojo_bindings.Message message = new mojo_bindings.Message( final mojo_bindings.Message message = new mojo_bindings.Message(
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:sky_services/pointer/pointer.mojom.dart'; import 'package:sky_services/pointer/pointer.mojom.dart' as mojom;
import 'events.dart'; import 'events.dart';
...@@ -31,18 +31,20 @@ class _PointerState { ...@@ -31,18 +31,20 @@ class _PointerState {
Point lastPosition; Point lastPosition;
} }
/// Converts from engine pointer data to framework pointer events.
class PointerEventConverter { class PointerEventConverter {
// Map from platform pointer identifiers to PointerEvent pointer identifiers. // Map from platform pointer identifiers to PointerEvent pointer identifiers.
static Map<int, _PointerState> _pointers = <int, _PointerState>{}; static Map<int, _PointerState> _pointers = <int, _PointerState>{};
static Iterable<PointerEvent> expand(Iterable<Pointer> packet) sync* { /// Expand the given packet of pointer data into a sequence of framework pointer events.
for (Pointer datum in packet) { static Iterable<PointerEvent> expand(Iterable<mojom.Pointer> packet) sync* {
for (mojom.Pointer datum in packet) {
Point position = new Point(datum.x, datum.y); Point position = new Point(datum.x, datum.y);
Duration timeStamp = new Duration(microseconds: datum.timeStamp); Duration timeStamp = new Duration(microseconds: datum.timeStamp);
assert(_pointerKindMap.containsKey(datum.kind)); assert(_pointerKindMap.containsKey(datum.kind));
PointerDeviceKind kind = _pointerKindMap[datum.kind]; PointerDeviceKind kind = _pointerKindMap[datum.kind];
switch (datum.type) { switch (datum.type) {
case PointerType.down: case mojom.PointerType.down:
assert(!_pointers.containsKey(datum.pointer)); assert(!_pointers.containsKey(datum.pointer));
_PointerState state = _pointers.putIfAbsent( _PointerState state = _pointers.putIfAbsent(
datum.pointer, datum.pointer,
...@@ -84,7 +86,7 @@ class PointerEventConverter { ...@@ -84,7 +86,7 @@ class PointerEventConverter {
tilt: datum.tilt tilt: datum.tilt
); );
break; break;
case PointerType.move: case mojom.PointerType.move:
// If the service starts supporting hover pointers, then it must also // If the service starts supporting hover pointers, then it must also
// start sending us ADDED and REMOVED data points. // start sending us ADDED and REMOVED data points.
// See also: https://github.com/flutter/flutter/issues/720 // See also: https://github.com/flutter/flutter/issues/720
...@@ -114,14 +116,14 @@ class PointerEventConverter { ...@@ -114,14 +116,14 @@ class PointerEventConverter {
tilt: datum.tilt tilt: datum.tilt
); );
break; break;
case PointerType.up: case mojom.PointerType.up:
case PointerType.cancel: case mojom.PointerType.cancel:
assert(_pointers.containsKey(datum.pointer)); assert(_pointers.containsKey(datum.pointer));
_PointerState state = _pointers[datum.pointer]; _PointerState state = _pointers[datum.pointer];
assert(state.down); assert(state.down);
assert(position == state.lastPosition); assert(position == state.lastPosition);
state.setUp(); state.setUp();
if (datum.type == PointerType.up) { if (datum.type == mojom.PointerType.up) {
yield new PointerUpEvent( yield new PointerUpEvent(
timeStamp: timeStamp, timeStamp: timeStamp,
pointer: state.pointer, pointer: state.pointer,
...@@ -174,10 +176,10 @@ class PointerEventConverter { ...@@ -174,10 +176,10 @@ class PointerEventConverter {
} }
} }
static const Map<PointerKind, PointerDeviceKind> _pointerKindMap = const <PointerKind, PointerDeviceKind>{ static const Map<mojom.PointerKind, PointerDeviceKind> _pointerKindMap = const <mojom.PointerKind, PointerDeviceKind>{
PointerKind.touch: PointerDeviceKind.touch, mojom.PointerKind.touch: PointerDeviceKind.touch,
PointerKind.mouse: PointerDeviceKind.mouse, mojom.PointerKind.mouse: PointerDeviceKind.mouse,
PointerKind.stylus: PointerDeviceKind.stylus, mojom.PointerKind.stylus: PointerDeviceKind.stylus,
PointerKind.invertedStylus: PointerDeviceKind.invertedStylus, mojom.PointerKind.invertedStylus: PointerDeviceKind.invertedStylus,
}; };
} }
...@@ -6,17 +6,30 @@ import 'dart:ui' show Point, Offset; ...@@ -6,17 +6,30 @@ import 'dart:ui' show Point, Offset;
export 'dart:ui' show Point, Offset; export 'dart:ui' show Point, Offset;
enum PointerDeviceKind { touch, stylus, invertedStylus, mouse } /// The kind of pointer device.
enum PointerDeviceKind {
const int primaryMouseButton = 0x01; /// A touch-based pointer device.
const int secondaryMouseButton = 0x02; touch,
const int primaryStylusButton = 0x02;
const int middleMouseButton = 0x04; /// A pointer device with a stylus.
const int secondaryStylusButton = 0x04; stylus,
const int backMouseButton = 0x08;
/// A pointer device with a stylus that has been inverted.
invertedStylus,
/// A mouse-based pointer device.
mouse
}
const int kPrimaryMouseButton = 0x01;
const int kSecondaryMouseButton = 0x02;
const int kPrimaryStylusButton = 0x02;
const int kMiddleMouseButton = 0x04;
const int kSecondaryStylusButton = 0x04;
const int kBackMouseButton = 0x08;
const int forwardMouseButton = 0x10; const int forwardMouseButton = 0x10;
int nthMouseButton(int number) => primaryMouseButton << (number - 1); int nthMouseButton(int number) => kPrimaryMouseButton << (number - 1);
int nthStylusButton(int number) => primaryStylusButton << (number - 1); int nthStylusButton(int number) => kPrimaryStylusButton << (number - 1);
/// Base class for touch, stylus, or mouse events. /// Base class for touch, stylus, or mouse events.
abstract class PointerEvent { abstract class PointerEvent {
...@@ -186,6 +199,10 @@ abstract class PointerEvent { ...@@ -186,6 +199,10 @@ abstract class PointerEvent {
} }
} }
/// The device has started tracking the pointer.
///
/// For example, the pointer might be hovering above the device, having not yet
/// made contact with the surface of the device.
class PointerAddedEvent extends PointerEvent { class PointerAddedEvent extends PointerEvent {
const PointerAddedEvent({ const PointerAddedEvent({
Duration timeStamp: Duration.ZERO, Duration timeStamp: Duration.ZERO,
...@@ -218,6 +235,10 @@ class PointerAddedEvent extends PointerEvent { ...@@ -218,6 +235,10 @@ class PointerAddedEvent extends PointerEvent {
); );
} }
/// The device is no longer tracking the pointer.
///
/// For example, the pointer might have drifted out of the device's hover
/// detection range or might have been disconnected from the system entirely.
class PointerRemovedEvent extends PointerEvent { class PointerRemovedEvent extends PointerEvent {
const PointerRemovedEvent({ const PointerRemovedEvent({
Duration timeStamp: Duration.ZERO, Duration timeStamp: Duration.ZERO,
...@@ -243,6 +264,7 @@ class PointerRemovedEvent extends PointerEvent { ...@@ -243,6 +264,7 @@ class PointerRemovedEvent extends PointerEvent {
); );
} }
/// The pointer has made contact with the device.
class PointerDownEvent extends PointerEvent { class PointerDownEvent extends PointerEvent {
const PointerDownEvent({ const PointerDownEvent({
Duration timeStamp: Duration.ZERO, Duration timeStamp: Duration.ZERO,
...@@ -283,6 +305,7 @@ class PointerDownEvent extends PointerEvent { ...@@ -283,6 +305,7 @@ class PointerDownEvent extends PointerEvent {
); );
} }
/// The pointer has moved with respect to the device.
class PointerMoveEvent extends PointerEvent { class PointerMoveEvent extends PointerEvent {
const PointerMoveEvent({ const PointerMoveEvent({
Duration timeStamp: Duration.ZERO, Duration timeStamp: Duration.ZERO,
...@@ -327,6 +350,7 @@ class PointerMoveEvent extends PointerEvent { ...@@ -327,6 +350,7 @@ class PointerMoveEvent extends PointerEvent {
); );
} }
/// The pointer has stopped making contact with the device.
class PointerUpEvent extends PointerEvent { class PointerUpEvent extends PointerEvent {
const PointerUpEvent({ const PointerUpEvent({
Duration timeStamp: Duration.ZERO, Duration timeStamp: Duration.ZERO,
...@@ -361,6 +385,7 @@ class PointerUpEvent extends PointerEvent { ...@@ -361,6 +385,7 @@ class PointerUpEvent extends PointerEvent {
); );
} }
/// The input from the pointer is no longer directed towards this receiver.
class PointerCancelEvent extends PointerEvent { class PointerCancelEvent extends PointerEvent {
const PointerCancelEvent({ const PointerCancelEvent({
Duration timeStamp: Duration.ZERO, Duration timeStamp: Duration.ZERO,
......
...@@ -10,6 +10,7 @@ import 'recognizer.dart'; ...@@ -10,6 +10,7 @@ import 'recognizer.dart';
typedef void GestureLongPressCallback(); typedef void GestureLongPressCallback();
/// The user has pressed down at this location for a long period of time.
class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer { class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
LongPressGestureRecognizer({ LongPressGestureRecognizer({
PointerRouter router, PointerRouter router,
......
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