Unverified Commit da8695d3 authored by Tong Mu's avatar Tong Mu Committed by GitHub

Mouse events report correct local positions (#61190)

parent 067d3da8
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
// @dart = 2.8 // @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:collection' show LinkedHashSet;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
...@@ -52,7 +51,7 @@ mixin MouseTrackerCursorMixin on BaseMouseTracker { ...@@ -52,7 +51,7 @@ mixin MouseTrackerCursorMixin on BaseMouseTracker {
// The `annotations` is the current annotations that the device is hovering in // The `annotations` is the current annotations that the device is hovering in
// visual order from front the back. // visual order from front the back.
// The return value is never null. // The return value is never null.
MouseCursor _findFirstCursor(LinkedHashSet<MouseTrackerAnnotation> annotations) { MouseCursor _findFirstCursor(Iterable<MouseTrackerAnnotation> annotations) {
return _DeferringMouseCursor.firstNonDeferred( return _DeferringMouseCursor.firstNonDeferred(
annotations.map((MouseTrackerAnnotation annotation) => annotation.cursor), annotations.map((MouseTrackerAnnotation annotation) => annotation.cursor),
) ?? SystemMouseCursors.basic; ) ?? SystemMouseCursors.basic;
...@@ -68,7 +67,7 @@ mixin MouseTrackerCursorMixin on BaseMouseTracker { ...@@ -68,7 +67,7 @@ mixin MouseTrackerCursorMixin on BaseMouseTracker {
} }
final MouseCursorSession lastSession = _lastSession[device]; final MouseCursorSession lastSession = _lastSession[device];
final MouseCursor nextCursor = _findFirstCursor(details.nextAnnotations); final MouseCursor nextCursor = _findFirstCursor(details.nextAnnotations.keys);
if (lastSession?.cursor == nextCursor) if (lastSession?.cursor == nextCursor)
return; return;
......
...@@ -4,13 +4,15 @@ ...@@ -4,13 +4,15 @@
// @dart = 2.8 // @dart = 2.8
import 'dart:collection' show LinkedHashSet; import 'dart:collection' show LinkedHashMap;
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:vector_math/vector_math_64.dart' show Matrix4;
import 'mouse_cursor.dart'; import 'mouse_cursor.dart';
import 'object.dart'; import 'object.dart';
...@@ -132,7 +134,7 @@ class MouseTrackerAnnotation with Diagnosticable { ...@@ -132,7 +134,7 @@ class MouseTrackerAnnotation with Diagnosticable {
/// ///
/// It is used by the [BaseMouseTracker] to fetch annotations for the mouse /// It is used by the [BaseMouseTracker] to fetch annotations for the mouse
/// position. /// position.
typedef MouseDetectorAnnotationFinder = Iterable<MouseTrackerAnnotation> Function(Offset offset); typedef MouseDetectorAnnotationFinder = LinkedHashMap<MouseTrackerAnnotation, Matrix4> Function(Offset offset);
// Various states of a connected mouse device used by [BaseMouseTracker]. // Various states of a connected mouse device used by [BaseMouseTracker].
class _MouseState { class _MouseState {
...@@ -143,13 +145,13 @@ class _MouseState { ...@@ -143,13 +145,13 @@ class _MouseState {
// The list of annotations that contains this device. // The list of annotations that contains this device.
// //
// It uses [LinkedHashSet] to keep the insertion order. // It uses [LinkedHashMap] to keep the insertion order.
LinkedHashSet<MouseTrackerAnnotation> get annotations => _annotations; LinkedHashMap<MouseTrackerAnnotation, Matrix4> get annotations => _annotations;
LinkedHashSet<MouseTrackerAnnotation> _annotations = LinkedHashSet<MouseTrackerAnnotation>(); LinkedHashMap<MouseTrackerAnnotation, Matrix4> _annotations = LinkedHashMap<MouseTrackerAnnotation, Matrix4>();
LinkedHashSet<MouseTrackerAnnotation> replaceAnnotations(LinkedHashSet<MouseTrackerAnnotation> value) { LinkedHashMap<MouseTrackerAnnotation, Matrix4> replaceAnnotations(LinkedHashMap<MouseTrackerAnnotation, Matrix4> value) {
assert(value != null); assert(value != null);
final LinkedHashSet<MouseTrackerAnnotation> previous = _annotations; final LinkedHashMap<MouseTrackerAnnotation, Matrix4> previous = _annotations;
_annotations = value; _annotations = value;
return previous; return previous;
} }
...@@ -215,12 +217,12 @@ class MouseTrackerUpdateDetails with Diagnosticable { ...@@ -215,12 +217,12 @@ class MouseTrackerUpdateDetails with Diagnosticable {
/// The annotations that the device is hovering before the update. /// The annotations that the device is hovering before the update.
/// ///
/// It is never null. /// It is never null.
final LinkedHashSet<MouseTrackerAnnotation> lastAnnotations; final LinkedHashMap<MouseTrackerAnnotation, Matrix4> lastAnnotations;
/// The annotations that the device is hovering after the update. /// The annotations that the device is hovering after the update.
/// ///
/// It is never null. /// It is never null.
final LinkedHashSet<MouseTrackerAnnotation> nextAnnotations; final LinkedHashMap<MouseTrackerAnnotation, Matrix4> nextAnnotations;
/// The last event that the device observed before the update. /// The last event that the device observed before the update.
/// ///
...@@ -259,8 +261,8 @@ class MouseTrackerUpdateDetails with Diagnosticable { ...@@ -259,8 +261,8 @@ class MouseTrackerUpdateDetails with Diagnosticable {
properties.add(IntProperty('device', device)); properties.add(IntProperty('device', device));
properties.add(DiagnosticsProperty<PointerEvent>('previousEvent', previousEvent)); properties.add(DiagnosticsProperty<PointerEvent>('previousEvent', previousEvent));
properties.add(DiagnosticsProperty<PointerEvent>('triggeringEvent', triggeringEvent)); properties.add(DiagnosticsProperty<PointerEvent>('triggeringEvent', triggeringEvent));
properties.add(DiagnosticsProperty<Set<MouseTrackerAnnotation>>('lastAnnotations', lastAnnotations)); properties.add(DiagnosticsProperty<Map<MouseTrackerAnnotation, Matrix4>>('lastAnnotations', lastAnnotations));
properties.add(DiagnosticsProperty<Set<MouseTrackerAnnotation>>('nextAnnotations', nextAnnotations)); properties.add(DiagnosticsProperty<Map<MouseTrackerAnnotation, Matrix4>>('nextAnnotations', nextAnnotations));
} }
} }
...@@ -418,16 +420,17 @@ class BaseMouseTracker extends ChangeNotifier { ...@@ -418,16 +420,17 @@ class BaseMouseTracker extends ChangeNotifier {
|| lastEvent.position != event.position; || lastEvent.position != event.position;
} }
// Find the annotations that is hovered by the device of the `state`. // Find the annotations that is hovered by the device of the `state`, and
// their respective global transform matrices.
// //
// If the device is not connected, an empty set is returned without calling // If the device is not connected or not a mouse, an empty map is returned
// `annotationFinder`. // without calling `annotationFinder`.
LinkedHashSet<MouseTrackerAnnotation> _findAnnotations(_MouseState state) { LinkedHashMap<MouseTrackerAnnotation, Matrix4> _findAnnotations(_MouseState state) {
final Offset globalPosition = state.latestEvent.position; final Offset globalPosition = state.latestEvent.position;
final int device = state.device; final int device = state.device;
return (_mouseStates.containsKey(device)) if (!_mouseStates.containsKey(device))
? LinkedHashSet<MouseTrackerAnnotation>.from(annotationFinder(globalPosition)) return <MouseTrackerAnnotation, Matrix4>{} as LinkedHashMap<MouseTrackerAnnotation, Matrix4>;
: <MouseTrackerAnnotation>{} as LinkedHashSet<MouseTrackerAnnotation>; return annotationFinder(globalPosition);
} }
/// A callback that is called on the update of a device. /// A callback that is called on the update of a device.
...@@ -485,8 +488,8 @@ class BaseMouseTracker extends ChangeNotifier { ...@@ -485,8 +488,8 @@ class BaseMouseTracker extends ChangeNotifier {
final _MouseState targetState = _mouseStates[device] ?? existingState; final _MouseState targetState = _mouseStates[device] ?? existingState;
final PointerEvent lastEvent = targetState.replaceLatestEvent(event); final PointerEvent lastEvent = targetState.replaceLatestEvent(event);
final LinkedHashSet<MouseTrackerAnnotation> nextAnnotations = _findAnnotations(targetState); final LinkedHashMap<MouseTrackerAnnotation, Matrix4> nextAnnotations = _findAnnotations(targetState);
final LinkedHashSet<MouseTrackerAnnotation> lastAnnotations = targetState.replaceAnnotations(nextAnnotations); final LinkedHashMap<MouseTrackerAnnotation, Matrix4> lastAnnotations = targetState.replaceAnnotations(nextAnnotations);
handleDeviceUpdate(MouseTrackerUpdateDetails.byPointerEvent( handleDeviceUpdate(MouseTrackerUpdateDetails.byPointerEvent(
lastAnnotations: lastAnnotations, lastAnnotations: lastAnnotations,
...@@ -506,8 +509,8 @@ class BaseMouseTracker extends ChangeNotifier { ...@@ -506,8 +509,8 @@ class BaseMouseTracker extends ChangeNotifier {
_deviceUpdatePhase(() { _deviceUpdatePhase(() {
for (final _MouseState dirtyState in _mouseStates.values) { for (final _MouseState dirtyState in _mouseStates.values) {
final PointerEvent lastEvent = dirtyState.latestEvent; final PointerEvent lastEvent = dirtyState.latestEvent;
final LinkedHashSet<MouseTrackerAnnotation> nextAnnotations = _findAnnotations(dirtyState); final LinkedHashMap<MouseTrackerAnnotation, Matrix4> nextAnnotations = _findAnnotations(dirtyState);
final LinkedHashSet<MouseTrackerAnnotation> lastAnnotations = dirtyState.replaceAnnotations(nextAnnotations); final LinkedHashMap<MouseTrackerAnnotation, Matrix4> lastAnnotations = dirtyState.replaceAnnotations(nextAnnotations);
handleDeviceUpdate(MouseTrackerUpdateDetails.byNewFrame( handleDeviceUpdate(MouseTrackerUpdateDetails.byNewFrame(
lastAnnotations: lastAnnotations, lastAnnotations: lastAnnotations,
...@@ -531,8 +534,8 @@ mixin _MouseTrackerEventMixin on BaseMouseTracker { ...@@ -531,8 +534,8 @@ mixin _MouseTrackerEventMixin on BaseMouseTracker {
final PointerEvent triggeringEvent = details.triggeringEvent; final PointerEvent triggeringEvent = details.triggeringEvent;
final PointerEvent latestEvent = details.latestEvent; final PointerEvent latestEvent = details.latestEvent;
final LinkedHashSet<MouseTrackerAnnotation> lastAnnotations = details.lastAnnotations; final LinkedHashMap<MouseTrackerAnnotation, Matrix4> lastAnnotations = details.lastAnnotations;
final LinkedHashSet<MouseTrackerAnnotation> nextAnnotations = details.nextAnnotations; final LinkedHashMap<MouseTrackerAnnotation, Matrix4> nextAnnotations = details.nextAnnotations;
// Order is important for mouse event callbacks. The `findAnnotations` // Order is important for mouse event callbacks. The `findAnnotations`
// returns annotations in the visual order from front to back. We call // returns annotations in the visual order from front to back. We call
...@@ -542,19 +545,22 @@ mixin _MouseTrackerEventMixin on BaseMouseTracker { ...@@ -542,19 +545,22 @@ mixin _MouseTrackerEventMixin on BaseMouseTracker {
// Send exit events to annotations that are in last but not in next, in // Send exit events to annotations that are in last but not in next, in
// visual order. // visual order.
final Iterable<MouseTrackerAnnotation> exitingAnnotations = lastAnnotations.difference(nextAnnotations); final PointerExitEvent baseExitEvent = PointerExitEvent.fromMouseEvent(latestEvent);
for (final MouseTrackerAnnotation annotation in exitingAnnotations) { lastAnnotations.forEach((MouseTrackerAnnotation annotation, Matrix4 transform) {
if (annotation.onExit != null) if (!nextAnnotations.containsKey(annotation))
annotation.onExit(PointerExitEvent.fromMouseEvent(latestEvent)); if (annotation.onExit != null)
} annotation.onExit(baseExitEvent.transformed(lastAnnotations[annotation]));
});
// Send enter events to annotations that are not in last but in next, in // Send enter events to annotations that are not in last but in next, in
// reverse visual order. // reverse visual order.
final Iterable<MouseTrackerAnnotation> enteringAnnotations = final List<MouseTrackerAnnotation> enteringAnnotations = nextAnnotations.keys.where(
nextAnnotations.difference(lastAnnotations).toList().reversed; (MouseTrackerAnnotation annotation) => !lastAnnotations.containsKey(annotation),
for (final MouseTrackerAnnotation annotation in enteringAnnotations) { ).toList();
final PointerEnterEvent baseEnterEvent = PointerEnterEvent.fromMouseEvent(latestEvent);
for (final MouseTrackerAnnotation annotation in enteringAnnotations.reversed) {
if (annotation.onEnter != null) if (annotation.onEnter != null)
annotation.onEnter(PointerEnterEvent.fromMouseEvent(latestEvent)); annotation.onEnter(baseEnterEvent.transformed(nextAnnotations[annotation]));
} }
// Send hover events to annotations that are in next, in reverse visual // Send hover events to annotations that are in next, in reverse visual
...@@ -567,10 +573,10 @@ mixin _MouseTrackerEventMixin on BaseMouseTracker { ...@@ -567,10 +573,10 @@ mixin _MouseTrackerEventMixin on BaseMouseTracker {
// last hover, then trigger the hover callback on all annotations. // last hover, then trigger the hover callback on all annotations.
// Otherwise, trigger the hover callback only on annotations that it // Otherwise, trigger the hover callback only on annotations that it
// newly enters. // newly enters.
final Iterable<MouseTrackerAnnotation> hoveringAnnotations = pointerHasMoved ? nextAnnotations.toList().reversed : enteringAnnotations; final Iterable<MouseTrackerAnnotation> hoveringAnnotations = pointerHasMoved ? nextAnnotations.keys.toList().reversed : enteringAnnotations;
for (final MouseTrackerAnnotation annotation in hoveringAnnotations) { for (final MouseTrackerAnnotation annotation in hoveringAnnotations) {
if (annotation.onHover != null) { if (annotation.onHover != null) {
annotation.onHover(triggeringEvent); annotation.onHover(triggeringEvent.transformed(nextAnnotations[annotation]));
} }
} }
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
// @dart = 2.8 // @dart = 2.8
import 'dart:collection' show LinkedHashMap;
import 'dart:developer'; import 'dart:developer';
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'dart:ui' as ui show Scene, SceneBuilder, Window; import 'dart:ui' as ui show Scene, SceneBuilder, Window;
...@@ -198,7 +199,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -198,7 +199,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
/// ///
/// * [Layer.findAllAnnotations], which is used by this method to find all /// * [Layer.findAllAnnotations], which is used by this method to find all
/// [AnnotatedRegionLayer]s annotated for mouse tracking. /// [AnnotatedRegionLayer]s annotated for mouse tracking.
Iterable<MouseTrackerAnnotation> hitTestMouseTrackers(Offset position) { LinkedHashMap<MouseTrackerAnnotation, Matrix4> hitTestMouseTrackers(Offset position) {
// Layer hit testing is done using device pixels, so we have to convert // Layer hit testing is done using device pixels, so we have to convert
// the logical coordinates of the event location back to device pixels // the logical coordinates of the event location back to device pixels
// here. // here.
...@@ -206,10 +207,11 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -206,10 +207,11 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
if (child != null) if (child != null)
child.hitTest(result, position: position); child.hitTest(result, position: position);
result.add(HitTestEntry(this)); result.add(HitTestEntry(this));
final List<MouseTrackerAnnotation> annotations = <MouseTrackerAnnotation>[]; final LinkedHashMap<MouseTrackerAnnotation, Matrix4> annotations = <MouseTrackerAnnotation, Matrix4>{}
as LinkedHashMap<MouseTrackerAnnotation, Matrix4>;
for (final HitTestEntry entry in result.path) { for (final HitTestEntry entry in result.path) {
if (entry.target is MouseTrackerAnnotation) { if (entry.target is MouseTrackerAnnotation) {
annotations.add(entry.target as MouseTrackerAnnotation); annotations[entry.target as MouseTrackerAnnotation] = entry.transform;
} }
} }
return annotations; return annotations;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
// @dart = 2.8 // @dart = 2.8
import 'dart:collection' show LinkedHashMap;
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'dart:ui' show PointerChange; import 'dart:ui' show PointerChange;
...@@ -25,12 +26,14 @@ void _ensureTestGestureBinding() { ...@@ -25,12 +26,14 @@ void _ensureTestGestureBinding() {
assert(GestureBinding.instance != null); assert(GestureBinding.instance != null);
} }
typedef SimpleAnnotationFinder = Iterable<MouseTrackerAnnotation> Function(Offset offset);
void main() { void main() {
MethodCallHandler _methodCallHandler; MethodCallHandler _methodCallHandler;
// Only one of `logCursors` and `cursorHandler` should be specified. // Only one of `logCursors` and `cursorHandler` should be specified.
void _setUpMouseTracker({ void _setUpMouseTracker({
MouseDetectorAnnotationFinder annotationFinder, SimpleAnnotationFinder annotationFinder,
List<_CursorUpdateDetails> logCursors, List<_CursorUpdateDetails> logCursors,
MethodCallHandler cursorHandler, MethodCallHandler cursorHandler,
}) { }) {
...@@ -43,7 +46,11 @@ void main() { ...@@ -43,7 +46,11 @@ void main() {
: cursorHandler; : cursorHandler;
final MouseTracker mouseTracker = MouseTracker( final MouseTracker mouseTracker = MouseTracker(
GestureBinding.instance.pointerRouter, GestureBinding.instance.pointerRouter,
annotationFinder, (Offset offset) => LinkedHashMap<MouseTrackerAnnotation, Matrix4>.fromEntries(
annotationFinder(offset).map(
(MouseTrackerAnnotation annotation) => MapEntry<MouseTrackerAnnotation, Matrix4>(annotation, Matrix4.identity()),
),
),
); );
RendererBinding.instance.initMouseTracker(mouseTracker); RendererBinding.instance.initMouseTracker(mouseTracker);
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
// @dart = 2.8 // @dart = 2.8
import 'dart:collection' show LinkedHashMap;
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'dart:ui' show PointerChange; import 'dart:ui' show PointerChange;
...@@ -13,6 +14,7 @@ import 'package:flutter/rendering.dart'; ...@@ -13,6 +14,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:vector_math/vector_math_64.dart' show Matrix4;
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
...@@ -65,11 +67,29 @@ void _ensureTestGestureBinding() { ...@@ -65,11 +67,29 @@ void _ensureTestGestureBinding() {
assert(GestureBinding.instance != null); assert(GestureBinding.instance != null);
} }
@immutable
class AnnotationEntry {
AnnotationEntry(this.annotation, [Matrix4 transform])
: transform = transform ?? Matrix4.identity();
final MouseTrackerAnnotation annotation;
final Matrix4 transform;
}
typedef SimpleAnnotationFinder = Iterable<AnnotationEntry> Function(Offset offset);
void main() { void main() {
void _setUpMouseAnnotationFinder(MouseDetectorAnnotationFinder annotationFinder) { void _setUpMouseAnnotationFinder(SimpleAnnotationFinder annotationFinder) {
final MouseTracker mouseTracker = MouseTracker( final MouseTracker mouseTracker = MouseTracker(
GestureBinding.instance.pointerRouter, GestureBinding.instance.pointerRouter,
annotationFinder, (Offset offset) => LinkedHashMap<MouseTrackerAnnotation, Matrix4>.fromEntries(
annotationFinder(offset).map(
(AnnotationEntry entry) => MapEntry<MouseTrackerAnnotation, Matrix4>(
entry.annotation,
entry.transform,
),
),
),
); );
RendererBinding.instance.initMouseTracker(mouseTracker); RendererBinding.instance.initMouseTracker(mouseTracker);
} }
...@@ -96,7 +116,7 @@ void main() { ...@@ -96,7 +116,7 @@ void main() {
); );
_setUpMouseAnnotationFinder( _setUpMouseAnnotationFinder(
(Offset position) sync* { (Offset position) sync* {
yield annotation; yield AnnotationEntry(annotation);
}, },
); );
return annotation; return annotation;
...@@ -312,7 +332,7 @@ void main() { ...@@ -312,7 +332,7 @@ void main() {
); );
_setUpMouseAnnotationFinder((Offset position) sync* { _setUpMouseAnnotationFinder((Offset position) sync* {
if (isInHitRegion) { if (isInHitRegion) {
yield annotation; yield AnnotationEntry(annotation, Matrix4.translationValues(10, 20, 0));
} }
}); });
...@@ -334,7 +354,7 @@ void main() { ...@@ -334,7 +354,7 @@ void main() {
_binding.flushPostFrameCallbacks(Duration.zero); _binding.flushPostFrameCallbacks(Duration.zero);
expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[ expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[
const PointerEnterEvent(position: Offset(0.0, 100.0)), const PointerEnterEvent(position: Offset(0, 100), localPosition: Offset(10, 120)),
])); ]));
events.clear(); events.clear();
...@@ -345,7 +365,7 @@ void main() { ...@@ -345,7 +365,7 @@ void main() {
_binding.flushPostFrameCallbacks(Duration.zero); _binding.flushPostFrameCallbacks(Duration.zero);
expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[ expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[
const PointerExitEvent(position: Offset(0.0, 100.0)), const PointerExitEvent(position: Offset(0.0, 100.0), localPosition: Offset(10, 120)),
])); ]));
expect(_binding.postFrameCallbacks, hasLength(0)); expect(_binding.postFrameCallbacks, hasLength(0));
}); });
...@@ -360,7 +380,7 @@ void main() { ...@@ -360,7 +380,7 @@ void main() {
); );
_setUpMouseAnnotationFinder((Offset position) sync* { _setUpMouseAnnotationFinder((Offset position) sync* {
if (isInHitRegion) { if (isInHitRegion) {
yield annotation; yield AnnotationEntry(annotation, Matrix4.translationValues(10, 20, 0));
} }
}); });
...@@ -380,7 +400,7 @@ void main() { ...@@ -380,7 +400,7 @@ void main() {
_binding.flushPostFrameCallbacks(Duration.zero); _binding.flushPostFrameCallbacks(Duration.zero);
expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[ expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[
const PointerEnterEvent(position: Offset(0.0, 100.0)), const PointerEnterEvent(position: Offset(0.0, 100.0), localPosition: Offset(10, 120)),
])); ]));
events.clear(); events.clear();
...@@ -394,7 +414,7 @@ void main() { ...@@ -394,7 +414,7 @@ void main() {
_binding.flushPostFrameCallbacks(Duration.zero); _binding.flushPostFrameCallbacks(Duration.zero);
expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[ expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[
const PointerExitEvent(position: Offset(0.0, 100.0)), const PointerExitEvent(position: Offset(0.0, 100.0), localPosition: Offset(10, 120)),
])); ]));
expect(_binding.postFrameCallbacks, hasLength(0)); expect(_binding.postFrameCallbacks, hasLength(0));
}); });
...@@ -409,7 +429,7 @@ void main() { ...@@ -409,7 +429,7 @@ void main() {
); );
_setUpMouseAnnotationFinder((Offset position) sync* { _setUpMouseAnnotationFinder((Offset position) sync* {
if (isInHitRegion) { if (isInHitRegion) {
yield annotation; yield AnnotationEntry(annotation, Matrix4.translationValues(10, 20, 0));
} }
}); });
...@@ -423,7 +443,7 @@ void main() { ...@@ -423,7 +443,7 @@ void main() {
expect(_binding.postFrameCallbacks, hasLength(0)); expect(_binding.postFrameCallbacks, hasLength(0));
expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[ expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[
const PointerEnterEvent(position: Offset(0.0, 100.0)), const PointerEnterEvent(position: Offset(0.0, 100.0), localPosition: Offset(10, 120)),
])); ]));
events.clear(); events.clear();
...@@ -433,7 +453,7 @@ void main() { ...@@ -433,7 +453,7 @@ void main() {
])); ]));
expect(_binding.postFrameCallbacks, hasLength(0)); expect(_binding.postFrameCallbacks, hasLength(0));
expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[ expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[
const PointerExitEvent(position: Offset(0.0, 100.0)), const PointerExitEvent(position: Offset(0.0, 100.0), localPosition: Offset(10, 120)),
])); ]));
}); });
...@@ -447,7 +467,7 @@ void main() { ...@@ -447,7 +467,7 @@ void main() {
); );
_setUpMouseAnnotationFinder((Offset position) sync* { _setUpMouseAnnotationFinder((Offset position) sync* {
if (isInHitRegion) { if (isInHitRegion) {
yield annotation; yield AnnotationEntry(annotation, Matrix4.translationValues(10, 20, 0));
} }
}); });
...@@ -466,8 +486,8 @@ void main() { ...@@ -466,8 +486,8 @@ void main() {
])); ]));
expect(_binding.postFrameCallbacks, hasLength(0)); expect(_binding.postFrameCallbacks, hasLength(0));
expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[ expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[
const PointerEnterEvent(position: Offset(0.0, 100.0)), const PointerEnterEvent(position: Offset(0.0, 100.0), localPosition: Offset(10, 120)),
const PointerHoverEvent(position: Offset(0.0, 100.0)), const PointerHoverEvent(position: Offset(0.0, 100.0), localPosition: Offset(10, 120)),
])); ]));
events.clear(); events.clear();
...@@ -478,7 +498,7 @@ void main() { ...@@ -478,7 +498,7 @@ void main() {
])); ]));
expect(_binding.postFrameCallbacks, hasLength(0)); expect(_binding.postFrameCallbacks, hasLength(0));
expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[ expect(events, _equalToEventsOnCriticalFields(<PointerEvent>[
const PointerExitEvent(position: Offset(200.0, 100.0)), const PointerExitEvent(position: Offset(200.0, 100.0), localPosition: Offset(210, 120)),
])); ]));
}); });
...@@ -506,9 +526,9 @@ void main() { ...@@ -506,9 +526,9 @@ void main() {
); );
_setUpMouseAnnotationFinder((Offset position) sync* { _setUpMouseAnnotationFinder((Offset position) sync* {
if (isInHitRegionOne) if (isInHitRegionOne)
yield annotation1; yield AnnotationEntry(annotation1);
else if (isInHitRegionTwo) else if (isInHitRegionTwo)
yield annotation2; yield AnnotationEntry(annotation2);
}); });
isInHitRegionOne = false; isInHitRegionOne = false;
...@@ -546,8 +566,8 @@ void main() { ...@@ -546,8 +566,8 @@ void main() {
_setUpMouseAnnotationFinder((Offset position) sync* { _setUpMouseAnnotationFinder((Offset position) sync* {
// Children's annotations come before parents'. // Children's annotations come before parents'.
if (isInB) { if (isInB) {
yield annotationB; yield AnnotationEntry(annotationB);
yield annotationA; yield AnnotationEntry(annotationA);
} }
}); });
...@@ -598,9 +618,9 @@ void main() { ...@@ -598,9 +618,9 @@ void main() {
); );
_setUpMouseAnnotationFinder((Offset position) sync* { _setUpMouseAnnotationFinder((Offset position) sync* {
if (isInA) { if (isInA) {
yield annotationA; yield AnnotationEntry(annotationA);
} else if (isInB) { } else if (isInB) {
yield annotationB; yield AnnotationEntry(annotationB);
} }
}); });
...@@ -676,7 +696,8 @@ class _EventCriticalFieldsMatcher extends Matcher { ...@@ -676,7 +696,8 @@ class _EventCriticalFieldsMatcher extends Matcher {
if (!( if (!(
_matchesField(matchState, 'kind', actual.kind, PointerDeviceKind.mouse) && _matchesField(matchState, 'kind', actual.kind, PointerDeviceKind.mouse) &&
_matchesField(matchState, 'position', actual.position, _expected.position) && _matchesField(matchState, 'position', actual.position, _expected.position) &&
_matchesField(matchState, 'device', actual.device, _expected.device) _matchesField(matchState, 'device', actual.device, _expected.device) &&
_matchesField(matchState, 'localPosition', actual.localPosition, _expected.localPosition)
)) { )) {
return false; return false;
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
// @dart = 2.8 // @dart = 2.8
import 'dart:collection' show LinkedHashMap;
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui' as ui show Gradient, Image, ImageFilter; import 'dart:ui' as ui show Gradient, Image, ImageFilter;
...@@ -492,7 +493,7 @@ void main() { ...@@ -492,7 +493,7 @@ void main() {
test('RenderMouseRegion can change properties when detached', () { test('RenderMouseRegion can change properties when detached', () {
renderer.initMouseTracker(MouseTracker( renderer.initMouseTracker(MouseTracker(
renderer.pointerRouter, renderer.pointerRouter,
(_) => <MouseTrackerAnnotation>[], (_) => <MouseTrackerAnnotation, Matrix4>{} as LinkedHashMap<MouseTrackerAnnotation, Matrix4>,
)); ));
final RenderMouseRegion object = RenderMouseRegion(); final RenderMouseRegion object = RenderMouseRegion();
object object
......
...@@ -112,8 +112,10 @@ void main() { ...@@ -112,8 +112,10 @@ void main() {
await gesture.moveTo(const Offset(400.0, 300.0)); await gesture.moveTo(const Offset(400.0, 300.0));
expect(move, isNotNull); expect(move, isNotNull);
expect(move.position, equals(const Offset(400.0, 300.0))); expect(move.position, equals(const Offset(400.0, 300.0)));
expect(move.localPosition, equals(const Offset(50.0, 50.0)));
expect(enter, isNotNull); expect(enter, isNotNull);
expect(enter.position, equals(const Offset(400.0, 300.0))); expect(enter.position, equals(const Offset(400.0, 300.0)));
expect(enter.localPosition, equals(const Offset(50.0, 50.0)));
expect(exit, isNull); expect(exit, isNull);
}); });
...@@ -145,6 +147,7 @@ void main() { ...@@ -145,6 +147,7 @@ void main() {
expect(enter, isNull); expect(enter, isNull);
expect(exit, isNotNull); expect(exit, isNotNull);
expect(exit.position, equals(const Offset(1.0, 1.0))); expect(exit.position, equals(const Offset(1.0, 1.0)));
expect(exit.localPosition, equals(const Offset(-349.0, -249.0)));
}); });
testWidgets('triggers pointer enter when a mouse is connected', (WidgetTester tester) async { testWidgets('triggers pointer enter when a mouse is connected', (WidgetTester tester) async {
...@@ -170,6 +173,7 @@ void main() { ...@@ -170,6 +173,7 @@ void main() {
expect(move, isNull); expect(move, isNull);
expect(enter, isNotNull); expect(enter, isNotNull);
expect(enter.position, equals(const Offset(400.0, 300.0))); expect(enter.position, equals(const Offset(400.0, 300.0)));
expect(enter.localPosition, equals(const Offset(50.0, 50.0)));
expect(exit, isNull); expect(exit, isNull);
}); });
...@@ -203,6 +207,7 @@ void main() { ...@@ -203,6 +207,7 @@ void main() {
expect(enter, isNull); expect(enter, isNull);
expect(exit, isNotNull); expect(exit, isNotNull);
expect(exit.position, equals(const Offset(400.0, 300.0))); expect(exit.position, equals(const Offset(400.0, 300.0)));
expect(exit.localPosition, equals(const Offset(50.0, 50.0)));
exit = null; exit = null;
await tester.pump(); await tester.pump();
expect(move, isNull); expect(move, isNull);
...@@ -243,6 +248,7 @@ void main() { ...@@ -243,6 +248,7 @@ void main() {
expect(move, isNull); expect(move, isNull);
expect(enter, isNotNull); expect(enter, isNotNull);
expect(enter.position, equals(const Offset(400.0, 300.0))); expect(enter.position, equals(const Offset(400.0, 300.0)));
expect(enter.localPosition, equals(const Offset(50.0, 50.0)));
expect(exit, isNull); expect(exit, isNull);
}); });
...@@ -285,7 +291,7 @@ void main() { ...@@ -285,7 +291,7 @@ void main() {
PointerHoverEvent move; PointerHoverEvent move;
PointerExitEvent exit; PointerExitEvent exit;
await tester.pumpWidget(Container( await tester.pumpWidget(Container(
alignment: Alignment.center, alignment: Alignment.topLeft,
child: MouseRegion( child: MouseRegion(
child: const SizedBox( child: const SizedBox(
width: 100.0, width: 100.0,
...@@ -297,14 +303,14 @@ void main() { ...@@ -297,14 +303,14 @@ void main() {
), ),
)); ));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer(location: const Offset(1.0, 1.0)); await gesture.addPointer(location: const Offset(401.0, 301.0));
addTearDown(gesture.removePointer); addTearDown(gesture.removePointer);
await tester.pump(); await tester.pump();
expect(enter, isNull); expect(enter, isNull);
expect(move, isNull); expect(move, isNull);
expect(exit, isNull); expect(exit, isNull);
await tester.pumpWidget(Container( await tester.pumpWidget(Container(
alignment: Alignment.topLeft, alignment: Alignment.center,
child: MouseRegion( child: MouseRegion(
child: const SizedBox( child: const SizedBox(
width: 100.0, width: 100.0,
...@@ -317,7 +323,8 @@ void main() { ...@@ -317,7 +323,8 @@ void main() {
)); ));
await tester.pump(); await tester.pump();
expect(enter, isNotNull); expect(enter, isNotNull);
expect(enter.position, equals(const Offset(1.0, 1.0))); expect(enter.position, equals(const Offset(401.0, 301.0)));
expect(enter.localPosition, equals(const Offset(51.0, 51.0)));
expect(move, isNull); expect(move, isNull);
expect(exit, isNull); expect(exit, isNull);
}); });
...@@ -362,6 +369,7 @@ void main() { ...@@ -362,6 +369,7 @@ void main() {
expect(move, isNull); expect(move, isNull);
expect(exit, isNotNull); expect(exit, isNotNull);
expect(exit.position, equals(const Offset(400, 300))); expect(exit.position, equals(const Offset(400, 300)));
expect(exit.localPosition, equals(const Offset(50, 50)));
}); });
testWidgets('Hover works with nested listeners', (WidgetTester tester) async { testWidgets('Hover works with nested listeners', (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