Unverified Commit 48457d73 authored by Callum Moffat's avatar Callum Moffat Committed by GitHub

WidgetController.startGesture trackpad support (#114631)

parent e1166e43
...@@ -1086,12 +1086,14 @@ abstract class WidgetController { ...@@ -1086,12 +1086,14 @@ abstract class WidgetController {
); );
} }
/// Creates a gesture with an initial down gesture at a particular point, and /// Creates a gesture with an initial appropriate starting gesture at a
/// returns the [TestGesture] object which you can use to continue the /// particular point, and returns the [TestGesture] object which you can use
/// gesture. /// to continue the gesture. Usually, the starting gesture will be a down event,
/// but if [kind] is set to [PointerDeviceKind.trackpad], the gesture will start
/// with a panZoomStart gesture.
/// ///
/// You can use [createGesture] if your gesture doesn't begin with an initial /// You can use [createGesture] if your gesture doesn't begin with an initial
/// down gesture. /// down or panZoomStart gesture.
/// ///
/// See also: /// See also:
/// * [WidgetController.drag], a method to simulate a drag. /// * [WidgetController.drag], a method to simulate a drag.
...@@ -1110,7 +1112,11 @@ abstract class WidgetController { ...@@ -1110,7 +1112,11 @@ abstract class WidgetController {
kind: kind, kind: kind,
buttons: buttons, buttons: buttons,
); );
if (kind == PointerDeviceKind.trackpad) {
await result.panZoomStart(downLocation);
} else {
await result.down(downLocation); await result.down(downLocation);
}
return result; return result;
} }
......
...@@ -455,6 +455,7 @@ class TestGesture { ...@@ -455,6 +455,7 @@ class TestGesture {
/// Dispatch a pointer down event at the given `downLocation`, caching the /// Dispatch a pointer down event at the given `downLocation`, caching the
/// hit test result. /// hit test result.
Future<void> down(Offset downLocation, { Duration timeStamp = Duration.zero }) async { Future<void> down(Offset downLocation, { Duration timeStamp = Duration.zero }) async {
assert(_pointer.kind != PointerDeviceKind.trackpad, 'Trackpads are expected to send panZoomStart events, not down events.');
return TestAsyncUtils.guard<void>(() async { return TestAsyncUtils.guard<void>(() async {
return _dispatcher(_pointer.down(downLocation, timeStamp: timeStamp)); return _dispatcher(_pointer.down(downLocation, timeStamp: timeStamp));
}); });
...@@ -463,6 +464,7 @@ class TestGesture { ...@@ -463,6 +464,7 @@ class TestGesture {
/// Dispatch a pointer down event at the given `downLocation`, caching the /// Dispatch a pointer down event at the given `downLocation`, caching the
/// hit test result with a custom down event. /// hit test result with a custom down event.
Future<void> downWithCustomEvent(Offset downLocation, PointerDownEvent event) async { Future<void> downWithCustomEvent(Offset downLocation, PointerDownEvent event) async {
assert(_pointer.kind != PointerDeviceKind.trackpad, 'Trackpads are expected to send panZoomStart events, not down events');
_pointer.setDownInfo(event, downLocation); _pointer.setDownInfo(event, downLocation);
return TestAsyncUtils.guard<void>(() async { return TestAsyncUtils.guard<void>(() async {
return _dispatcher(event); return _dispatcher(event);
...@@ -507,8 +509,16 @@ class TestGesture { ...@@ -507,8 +509,16 @@ class TestGesture {
/// * [WidgetController.fling], a method to simulate a fling. /// * [WidgetController.fling], a method to simulate a fling.
Future<void> moveBy(Offset offset, { Duration timeStamp = Duration.zero }) { Future<void> moveBy(Offset offset, { Duration timeStamp = Duration.zero }) {
assert(_pointer.location != null); assert(_pointer.location != null);
if (_pointer.isPanZoomActive) {
return panZoomUpdate(
_pointer.location!,
pan: (_pointer.pan ?? Offset.zero) + offset,
timeStamp: timeStamp
);
} else {
return moveTo(_pointer.location! + offset, timeStamp: timeStamp); return moveTo(_pointer.location! + offset, timeStamp: timeStamp);
} }
}
/// Send a move event moving the pointer to the given location. /// Send a move event moving the pointer to the given location.
/// ///
...@@ -521,6 +531,7 @@ class TestGesture { ...@@ -521,6 +531,7 @@ class TestGesture {
/// It sends move events at a given frequency and it is useful when there are listeners involved. /// It sends move events at a given frequency and it is useful when there are listeners involved.
/// * [WidgetController.fling], a method to simulate a fling. /// * [WidgetController.fling], a method to simulate a fling.
Future<void> moveTo(Offset location, { Duration timeStamp = Duration.zero }) { Future<void> moveTo(Offset location, { Duration timeStamp = Duration.zero }) {
assert(_pointer.kind != PointerDeviceKind.trackpad);
return TestAsyncUtils.guard<void>(() { return TestAsyncUtils.guard<void>(() {
if (_pointer._isDown) { if (_pointer._isDown) {
return _dispatcher(_pointer.move(location, timeStamp: timeStamp)); return _dispatcher(_pointer.move(location, timeStamp: timeStamp));
...@@ -530,12 +541,19 @@ class TestGesture { ...@@ -530,12 +541,19 @@ class TestGesture {
}); });
} }
/// End the gesture by releasing the pointer. /// End the gesture by releasing the pointer. For trackpad pointers this
/// will send a panZoomEnd event instead of an up event.
Future<void> up({ Duration timeStamp = Duration.zero }) { Future<void> up({ Duration timeStamp = Duration.zero }) {
return TestAsyncUtils.guard<void>(() async { return TestAsyncUtils.guard<void>(() async {
if (_pointer.kind == PointerDeviceKind.trackpad) {
assert(_pointer._isPanZoomActive);
await _dispatcher(_pointer.panZoomEnd(timeStamp: timeStamp));
assert(!_pointer._isPanZoomActive);
} else {
assert(_pointer._isDown); assert(_pointer._isDown);
await _dispatcher(_pointer.up(timeStamp: timeStamp)); await _dispatcher(_pointer.up(timeStamp: timeStamp));
assert(!_pointer._isDown); assert(!_pointer._isDown);
}
}); });
} }
...@@ -543,6 +561,7 @@ class TestGesture { ...@@ -543,6 +561,7 @@ class TestGesture {
/// system showed a modal dialog on top of the Flutter application, /// system showed a modal dialog on top of the Flutter application,
/// for instance). /// for instance).
Future<void> cancel({ Duration timeStamp = Duration.zero }) { Future<void> cancel({ Duration timeStamp = Duration.zero }) {
assert(_pointer.kind != PointerDeviceKind.trackpad, 'Trackpads do not send cancel events.');
return TestAsyncUtils.guard<void>(() async { return TestAsyncUtils.guard<void>(() async {
assert(_pointer._isDown); assert(_pointer._isDown);
await _dispatcher(_pointer.cancel(timeStamp: timeStamp)); await _dispatcher(_pointer.cancel(timeStamp: timeStamp));
...@@ -553,6 +572,7 @@ class TestGesture { ...@@ -553,6 +572,7 @@ class TestGesture {
/// Dispatch a pointer pan zoom start event at the given `location`, caching the /// Dispatch a pointer pan zoom start event at the given `location`, caching the
/// hit test result. /// hit test result.
Future<void> panZoomStart(Offset location, { Duration timeStamp = Duration.zero }) async { Future<void> panZoomStart(Offset location, { Duration timeStamp = Duration.zero }) async {
assert(_pointer.kind == PointerDeviceKind.trackpad, 'Only trackpads can send PointerPanZoom events.');
return TestAsyncUtils.guard<void>(() async { return TestAsyncUtils.guard<void>(() async {
return _dispatcher(_pointer.panZoomStart(location, timeStamp: timeStamp)); return _dispatcher(_pointer.panZoomStart(location, timeStamp: timeStamp));
}); });
...@@ -566,6 +586,7 @@ class TestGesture { ...@@ -566,6 +586,7 @@ class TestGesture {
double rotation = 0, double rotation = 0,
Duration timeStamp = Duration.zero Duration timeStamp = Duration.zero
}) async { }) async {
assert(_pointer.kind == PointerDeviceKind.trackpad, 'Only trackpads can send PointerPanZoom events.');
return TestAsyncUtils.guard<void>(() async { return TestAsyncUtils.guard<void>(() async {
return _dispatcher(_pointer.panZoomUpdate(location, return _dispatcher(_pointer.panZoomUpdate(location,
pan: pan, pan: pan,
...@@ -580,6 +601,7 @@ class TestGesture { ...@@ -580,6 +601,7 @@ class TestGesture {
Future<void> panZoomEnd({ Future<void> panZoomEnd({
Duration timeStamp = Duration.zero Duration timeStamp = Duration.zero
}) async { }) async {
assert(_pointer.kind == PointerDeviceKind.trackpad, 'Only trackpads can send PointerPanZoom events.');
return TestAsyncUtils.guard<void>(() async { return TestAsyncUtils.guard<void>(() async {
return _dispatcher(_pointer.panZoomEnd( return _dispatcher(_pointer.panZoomEnd(
timeStamp: timeStamp timeStamp: timeStamp
......
...@@ -385,6 +385,40 @@ void main() { ...@@ -385,6 +385,40 @@ void main() {
}, },
); );
testWidgets(
'WidgetTester.drag works with trackpad kind',
(WidgetTester tester) async {
final List<String> logs = <String>[];
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Listener(
onPointerDown: (PointerDownEvent event) => logs.add('down ${event.buttons}'),
onPointerMove: (PointerMoveEvent event) => logs.add('move ${event.buttons}'),
onPointerUp: (PointerUpEvent event) => logs.add('up ${event.buttons}'),
onPointerPanZoomStart: (PointerPanZoomStartEvent event) => logs.add('panZoomStart'),
onPointerPanZoomUpdate: (PointerPanZoomUpdateEvent event) => logs.add('panZoomUpdate ${event.pan}'),
onPointerPanZoomEnd: (PointerPanZoomEndEvent event) => logs.add('panZoomEnd'),
child: const Text('test'),
),
),
);
await tester.drag(find.text('test'), const Offset(-150.0, 200.0), kind: PointerDeviceKind.trackpad);
for(int i = 0; i < logs.length; i++) {
if (i == 0) {
expect(logs[i], 'panZoomStart');
} else if (i != logs.length - 1) {
expect(logs[i], startsWith('panZoomUpdate'));
} else {
expect(logs[i], 'panZoomEnd');
}
}
},
);
testWidgets( testWidgets(
'WidgetTester.fling must respect buttons', 'WidgetTester.fling must respect buttons',
(WidgetTester tester) async { (WidgetTester tester) async {
......
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