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