Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
fa06b340
Unverified
Commit
fa06b340
authored
Mar 12, 2021
by
Tong Mu
Committed by
GitHub
Mar 12, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor: Move mouse cursor classes to "services" package (#77751)
parent
95d3ac70
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
289 additions
and
293 deletions
+289
-293
rendering.dart
packages/flutter/lib/rendering.dart
+1
-2
services.dart
packages/flutter/lib/services.dart
+2
-0
material_state.dart
packages/flutter/lib/src/material/material_state.dart
+1
-0
binding.dart
packages/flutter/lib/src/rendering/binding.dart
+1
-1
mouse_tracker.dart
packages/flutter/lib/src/rendering/mouse_tracker.dart
+82
-219
platform_view.dart
packages/flutter/lib/src/rendering/platform_view.dart
+1
-2
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+2
-2
mouse_cursor.dart
packages/flutter/lib/src/services/mouse_cursor.dart
+39
-37
mouse_tracking.dart
packages/flutter/lib/src/services/mouse_tracking.dart
+119
-0
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+2
-0
focus_manager.dart
packages/flutter/lib/src/widgets/focus_manager.dart
+1
-1
mouse_tracker_cursor_test.dart
...ges/flutter/test/rendering/mouse_tracker_cursor_test.dart
+1
-1
mouse_tracker_test.dart
packages/flutter/test/rendering/mouse_tracker_test.dart
+1
-28
mouse_tracker_test_utils.dart
...ages/flutter/test/rendering/mouse_tracker_test_utils.dart
+0
-0
mouse_tracking_test.dart
packages/flutter/test/services/mouse_tracking_test.dart
+36
-0
No files found.
packages/flutter/lib/rendering.dart
View file @
fa06b340
...
...
@@ -46,8 +46,7 @@ export 'src/rendering/layer.dart';
export
'src/rendering/layout_helper.dart'
;
export
'src/rendering/list_body.dart'
;
export
'src/rendering/list_wheel_viewport.dart'
;
export
'src/rendering/mouse_cursor.dart'
;
export
'src/rendering/mouse_tracking.dart'
;
export
'src/rendering/mouse_tracker.dart'
;
export
'src/rendering/object.dart'
;
export
'src/rendering/paragraph.dart'
;
export
'src/rendering/performance_overlay.dart'
;
...
...
packages/flutter/lib/services.dart
View file @
fa06b340
...
...
@@ -22,6 +22,8 @@ export 'src/services/keyboard_key.dart';
export
'src/services/keyboard_maps.dart'
;
export
'src/services/message_codec.dart'
;
export
'src/services/message_codecs.dart'
;
export
'src/services/mouse_cursor.dart'
;
export
'src/services/mouse_tracking.dart'
;
export
'src/services/platform_channel.dart'
;
export
'src/services/platform_views.dart'
;
export
'src/services/raw_keyboard.dart'
;
...
...
packages/flutter/lib/src/material/material_state.dart
View file @
fa06b340
...
...
@@ -4,6 +4,7 @@
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
/// Interactive states that some of the Material widgets can take on when
/// receiving input from the user.
...
...
packages/flutter/lib/src/rendering/binding.dart
View file @
fa06b340
...
...
@@ -12,7 +12,7 @@ import 'package:flutter/services.dart';
import
'box.dart'
;
import
'debug.dart'
;
import
'mouse_track
ing
.dart'
;
import
'mouse_track
er
.dart'
;
import
'object.dart'
;
import
'view.dart'
;
...
...
packages/flutter/lib/src/rendering/mouse_track
ing
.dart
→
packages/flutter/lib/src/rendering/mouse_track
er
.dart
View file @
fa06b340
...
...
@@ -7,131 +7,23 @@ import 'dart:ui';
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/services.dart'
;
import
'package:vector_math/vector_math_64.dart'
show
Matrix4
;
import
'mouse_cursor.dart'
;
import
'object.dart'
;
/// Signature for listening to [PointerEnterEvent] events.
///
/// Used by [MouseTrackerAnnotation], [MouseRegion] and [RenderMouseRegion].
typedef
PointerEnterEventListener
=
void
Function
(
PointerEnterEvent
event
);
/// Signature for listening to [PointerExitEvent] events.
///
/// Used by [MouseTrackerAnnotation], [MouseRegion] and [RenderMouseRegion].
typedef
PointerExitEventListener
=
void
Function
(
PointerExitEvent
event
);
/// Signature for listening to [PointerHoverEvent] events.
///
/// Used by [MouseTrackerAnnotation], [MouseRegion] and [RenderMouseRegion].
typedef
PointerHoverEventListener
=
void
Function
(
PointerHoverEvent
event
);
/// The annotation object used to annotate regions that are interested in mouse
/// movements.
///
/// To use an annotation, push it with [AnnotatedRegionLayer] during painting.
/// The annotation's callbacks or configurations will be used depending on the
/// relationship between annotations and mouse pointers.
///
/// A [RenderObject] who uses this class must not dispose this class in its
/// `detach`, even if it recreates a new one in `attach`, because the object
/// might be detached and attached during the same frame during a reparent, and
/// replacing the `MouseTrackerAnnotation` will cause an unnecessary `onExit` and
/// `onEnter`.
///
/// This class is also the type parameter of the annotation search started by
/// [BaseMouseTracker].
///
/// See also:
///
/// * [BaseMouseTracker], which uses [MouseTrackerAnnotation].
class
MouseTrackerAnnotation
with
Diagnosticable
{
/// Creates an immutable [MouseTrackerAnnotation].
///
/// All arguments are optional. The [cursor] must not be null.
const
MouseTrackerAnnotation
({
this
.
onEnter
,
this
.
onExit
,
this
.
cursor
=
MouseCursor
.
defer
,
this
.
validForMouseTracker
=
true
,
})
:
assert
(
cursor
!=
null
);
/// Triggered when a mouse pointer, with or without buttons pressed, has
/// entered the region and [validForMouseTracker] is true.
///
/// This callback is triggered when the pointer has started to be contained by
/// the region, either due to a pointer event, or due to the movement or
/// disappearance of the region. This method is always matched by a later
/// [onExit].
///
/// See also:
///
/// * [onExit], which is triggered when a mouse pointer exits the region.
/// * [MouseRegion.onEnter], which uses this callback.
final
PointerEnterEventListener
?
onEnter
;
/// Triggered when a mouse pointer, with or without buttons pressed, has
/// exited the region and [validForMouseTracker] is true.
///
/// This callback is triggered when the pointer has stopped being contained
/// by the region, either due to a pointer event, or due to the movement or
/// disappearance of the region. This method always matches an earlier
/// [onEnter].
///
/// See also:
///
/// * [onEnter], which is triggered when a mouse pointer enters the region.
/// * [MouseRegion.onExit], which uses this callback, but is not triggered in
/// certain cases and does not always match its earlier [MouseRegion.onEnter].
final
PointerExitEventListener
?
onExit
;
/// The mouse cursor for mouse pointers that are hovering over the region.
///
/// When a mouse enters the region, its cursor will be changed to the [cursor].
/// When the mouse leaves the region, the cursor will be set by the region
/// found at the new location.
///
/// Defaults to [MouseCursor.defer], deferring the choice of cursor to the next
/// region behind it in hit-test order.
///
/// See also:
///
/// * [MouseRegion.cursor], which provide values to this field.
final
MouseCursor
cursor
;
/// Whether this is included when [MouseTracker] collects the list of annotations.
///
/// If [validForMouseTracker] is false, this object is excluded from the current annotation list
/// even if it's included in the hit test, affecting mouse-related behavior such as enter events,
/// exit events, and mouse cursors. The [validForMouseTracker] does not affect hit testing.
///
/// The [validForMouseTracker] is true for [MouseTrackerAnnotation]s built by the constructor.
final
bool
validForMouseTracker
;
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
FlagsSummary
<
Function
?>(
'callbacks'
,
<
String
,
Function
?>
{
'enter'
:
onEnter
,
'exit'
:
onExit
,
},
ifEmpty:
'<none>'
,
));
properties
.
add
(
DiagnosticsProperty
<
MouseCursor
>(
'cursor'
,
cursor
,
defaultValue:
MouseCursor
.
defer
));
}
}
export
'package:flutter/services.dart'
show
MouseCursor
,
SystemMouseCursors
;
/// Signature for searching for [MouseTrackerAnnotation]s at the given offset.
///
/// It is used by the [
Base
MouseTracker] to fetch annotations for the mouse
/// It is used by the [MouseTracker] to fetch annotations for the mouse
/// position.
typedef
MouseDetectorAnnotationFinder
=
HitTestResult
Function
(
Offset
offset
);
// Various states of a connected mouse device used by [
Base
MouseTracker].
// Various states of a connected mouse device used by [MouseTracker].
class
_MouseState
{
_MouseState
({
required
PointerEvent
initialEvent
,
...
...
@@ -173,18 +65,18 @@ class _MouseState {
}
}
//
/ Used by [BaseMouseTracker] to provide the details of an update of a mouse
//
/
device.
//
/
//
/
This class contains the information needed to handle the update that might
//
/
change the state of a mouse device, or the [MouseTrackerAnnotation]s that
//
/
the mouse device is hovering.
//
The information in `MouseTracker._handleDeviceUpdate` to provide the details
//
of an update of a mouse
device.
//
// This class contains the information needed to handle the update that might
// change the state of a mouse device, or the [MouseTrackerAnnotation]s that
// the mouse device is hovering.
@immutable
class
MouseTrackerUpdateDetails
with
Diagnosticable
{
class
_
MouseTrackerUpdateDetails
with
Diagnosticable
{
/// When device update is triggered by a new frame.
///
/// All parameters are required.
const
MouseTrackerUpdateDetails
.
byNewFrame
({
const
_
MouseTrackerUpdateDetails
.
byNewFrame
({
required
this
.
lastAnnotations
,
required
this
.
nextAnnotations
,
required
PointerEvent
this
.
previousEvent
,
...
...
@@ -197,7 +89,7 @@ class MouseTrackerUpdateDetails with Diagnosticable {
///
/// The [lastAnnotations], [nextAnnotations], and [triggeringEvent] are
/// required.
const
MouseTrackerUpdateDetails
.
byPointerEvent
({
const
_
MouseTrackerUpdateDetails
.
byPointerEvent
({
required
this
.
lastAnnotations
,
required
this
.
nextAnnotations
,
this
.
previousEvent
,
...
...
@@ -258,33 +150,31 @@ class MouseTrackerUpdateDetails with Diagnosticable {
}
}
///
A base class that tracks the relationship between mouse devices
and
///
[MouseTrackerAnnotation]s
.
///
Tracks the relationship between mouse devices and annotations,
and
///
triggers mouse events and cursor changes accordingly
.
///
/// An event (not necessarily a pointer event) that might change the relationship
/// between mouse devices and [MouseTrackerAnnotation]s is called a _device
/// update_.
/// The [MouseTracker] tracks the relationship between mouse devices and
/// [MouseTrackerAnnotation], notified by [updateWithEvent] and
/// [updateAllDevices]. At every update, [MouseTracker] triggers the following
/// changes if applicable:
///
///
[MouseTracker] is notified of device updates by [updateWithEvent] or
///
[updateAllDevices], and processes effects as defined in [handleDeviceUpdate]
///
by subclass
es.
///
* Dispatches mouse-related pointer events (pointer enter, hover, and exit).
///
* Changes mouse cursors.
///
* Notifies when [mouseIsConnected] chang
es.
///
/// This class is a [ChangeNotifier] that notifies its listeners if the value of
/// [mouseIsConnected] changes.
///
/// See also:
///
/// * [MouseTracker], which is a subclass of [BaseMouseTracker] with definition
/// of how to process mouse event callbacks and mouse cursors.
/// * [MouseTrackerCursorMixin], which is a mixin for [BaseMouseTracker] that
/// defines how to process mouse cursors.
abstract
class
BaseMouseTracker
extends
ChangeNotifier
{
/// Whether or not at least one mouse is connected and has produced events.
bool
get
mouseIsConnected
=>
_mouseStates
.
isNotEmpty
;
/// An instance of [MouseTracker] is owned by the global singleton
/// [RendererBinding].
class
MouseTracker
extends
ChangeNotifier
{
final
MouseCursorManager
_mouseCursorMixin
=
MouseCursorManager
(
SystemMouseCursors
.
basic
);
// Tracks the state of connected mouse devices.
//
// It is the source of truth for the list of connected mouse devices, and
is
// It is the source of truth for the list of connected mouse devices, and
// consists of two parts:
//
// * The mouse devices that are connected.
...
...
@@ -303,7 +193,7 @@ abstract class BaseMouseTracker extends ChangeNotifier {
}
bool
_debugDuringDeviceUpdate
=
false
;
// Used to wrap any procedure that might call
[handleDeviceUpdate]
.
// Used to wrap any procedure that might call
`_handleDeviceUpdate`
.
//
// In debug mode, this method uses `_debugDuringDeviceUpdate` to prevent
// `_deviceUpdatePhase` being recursively called.
...
...
@@ -367,40 +257,41 @@ abstract class BaseMouseTracker extends ChangeNotifier {
return
_hitTestResultToAnnotations
(
hitTest
(
globalPosition
));
}
/// A callback that is called on the update of a device.
///
/// This method should be called only by [BaseMouseTracker], each time when the
/// relationship between a device and annotations has changed.
///
/// By default the [handleDeviceUpdate] does nothing effective. Subclasses
/// should override this method to first call to their inherited
/// [handleDeviceUpdate] method, and then process the update as desired.
///
/// The update can be caused by two kinds of triggers:
///
/// * Triggered by the addition, movement, or removal of a pointer. Such
/// calls occur during the handler of the event, indicated by
/// `details.triggeringEvent` being non-null.
/// * Triggered by the appearance, movement, or disappearance of an annotation.
/// Such calls occur after each new frame, during the post-frame callbacks,
/// indicated by `details.triggeringEvent` being null.
///
/// Calling of this method must be wrapped in `_deviceUpdatePhase`.
@protected
@mustCallSuper
void
handleDeviceUpdate
(
MouseTrackerUpdateDetails
details
)
{
// A callback that is called on the update of a device.
//
// An event (not necessarily a pointer event) that might change the
// relationship between mouse devices and [MouseTrackerAnnotation]s is called
// a _device update_. This method should be called at each such update.
//
// The update can be caused by two kinds of triggers:
//
// * Triggered by the addition, movement, or removal of a pointer. Such calls
// occur during the handler of the event, indicated by
// `details.triggeringEvent` being non-null.
// * Triggered by the appearance, movement, or disappearance of an annotation.
// Such calls occur after each new frame, during the post-frame callbacks,
// indicated by `details.triggeringEvent` being null.
//
// Calls of this method must be wrapped in `_deviceUpdatePhase`.
void
_handleDeviceUpdate
(
_MouseTrackerUpdateDetails
details
)
{
assert
(
_debugDuringDeviceUpdate
);
_handleDeviceUpdateMouseEvents
(
details
);
_mouseCursorMixin
.
handleDeviceCursorUpdate
(
details
.
device
,
details
.
triggeringEvent
,
details
.
nextAnnotations
.
keys
.
map
((
MouseTrackerAnnotation
annotaion
)
=>
annotaion
.
cursor
),
);
}
/// Whether or not at least one mouse is connected and has produced events.
bool
get
mouseIsConnected
=>
_mouseStates
.
isNotEmpty
;
/// Trigger a device update with a new event and its corresponding hit test
/// result.
///
/// The [updateWithEvent] indicates that an event has been observed, and
/// is called during the handler of the event. The `getResult` should return
/// the hit test result at the position of the event.
///
/// The [updateWithEvent] will generate the new state for the pointer based on
/// given information, and call [handleDeviceUpdate] based on the state changes.
void
updateWithEvent
(
PointerEvent
event
,
ValueGetter
<
HitTestResult
>
getResult
)
{
assert
(
event
!=
null
);
final
HitTestResult
result
=
event
is
PointerRemovedEvent
?
HitTestResult
()
:
getResult
();
...
...
@@ -435,7 +326,7 @@ abstract class BaseMouseTracker extends ChangeNotifier {
_hitTestResultToAnnotations
(
result
);
final
LinkedHashMap
<
MouseTrackerAnnotation
,
Matrix4
>
lastAnnotations
=
targetState
.
replaceAnnotations
(
nextAnnotations
);
handleDeviceUpdate
(
MouseTrackerUpdateDetails
.
byPointerEvent
(
_handleDeviceUpdate
(
_
MouseTrackerUpdateDetails
.
byPointerEvent
(
lastAnnotations:
lastAnnotations
,
nextAnnotations:
nextAnnotations
,
previousEvent:
lastEvent
,
...
...
@@ -449,13 +340,12 @@ abstract class BaseMouseTracker extends ChangeNotifier {
///
/// The [updateAllDevices] is typically called during the post frame phase,
/// indicating a frame has passed and all objects have potentially moved. The
/// `hitTest` is a function that
can acquire
the hit test result at a given
/// `hitTest` is a function that
acquires
the hit test result at a given
/// position, and must not be empty.
///
/// For each connected device, the [updateAllDevices] will make a hit test on
/// the device's last seen position, generate the new state for the pointer
/// based on given information, and call [handleDeviceUpdate] based on the
/// state changes.
/// the device's last seen position, and check if necessary changes need to be
/// made.
void
updateAllDevices
(
MouseDetectorAnnotationFinder
hitTest
)
{
_deviceUpdatePhase
(()
{
for
(
final
_MouseState
dirtyState
in
_mouseStates
.
values
)
{
...
...
@@ -463,7 +353,7 @@ abstract class BaseMouseTracker extends ChangeNotifier {
final
LinkedHashMap
<
MouseTrackerAnnotation
,
Matrix4
>
nextAnnotations
=
_findAnnotations
(
dirtyState
,
hitTest
);
final
LinkedHashMap
<
MouseTrackerAnnotation
,
Matrix4
>
lastAnnotations
=
dirtyState
.
replaceAnnotations
(
nextAnnotations
);
handleDeviceUpdate
(
MouseTrackerUpdateDetails
.
byNewFrame
(
_handleDeviceUpdate
(
_
MouseTrackerUpdateDetails
.
byNewFrame
(
lastAnnotations:
lastAnnotations
,
nextAnnotations:
nextAnnotations
,
previousEvent:
lastEvent
,
...
...
@@ -471,29 +361,33 @@ abstract class BaseMouseTracker extends ChangeNotifier {
}
});
}
}
// A mixin for [BaseMouseTracker] that dispatches mouse events on device update.
//
// See also:
//
// * [MouseTracker], which uses this mixin.
mixin
_MouseTrackerEventMixin
on
BaseMouseTracker
{
/// Returns the active mouse cursor for a device.
///
/// The return value is the last [MouseCursor] activated onto this device, even
/// if the activation failed.
///
/// This function is only active when asserts are enabled. In release builds,
/// it always returns null.
@visibleForTesting
MouseCursor
?
debugDeviceActiveCursor
(
int
device
)
{
return
_mouseCursorMixin
.
debugDeviceActiveCursor
(
device
);
}
// Handles device update and dispatches mouse event callbacks.
static
void
_handleDeviceUpdateMouseEvents
(
MouseTrackerUpdateDetails
details
)
{
static
void
_handleDeviceUpdateMouseEvents
(
_
MouseTrackerUpdateDetails
details
)
{
final
PointerEvent
latestEvent
=
details
.
latestEvent
;
final
LinkedHashMap
<
MouseTrackerAnnotation
,
Matrix4
>
lastAnnotations
=
details
.
lastAnnotations
;
final
LinkedHashMap
<
MouseTrackerAnnotation
,
Matrix4
>
nextAnnotations
=
details
.
nextAnnotations
;
// Order is important for mouse event callbacks. The `findAnnotations`
// returns annotations in the visual order from front to back. We call
// it the "visual order", and the opposite one "reverse visual order".
// The algorithm here is explained in
// https://github.com/flutter/flutter/issues/41420
// Order is important for mouse event callbacks. The
// `_hitTestResultToAnnotations` returns annotations in the visual order
// from front to back, called the "hit-test order". The algorithm here is
// explained in https://github.com/flutter/flutter/issues/41420
// Send exit events to annotations that are in last but not in next, in
//
visual
order.
//
hit-test
order.
final
PointerExitEvent
baseExitEvent
=
PointerExitEvent
.
fromMouseEvent
(
latestEvent
);
lastAnnotations
.
forEach
((
MouseTrackerAnnotation
annotation
,
Matrix4
transform
)
{
if
(!
nextAnnotations
.
containsKey
(
annotation
))
...
...
@@ -502,7 +396,7 @@ mixin _MouseTrackerEventMixin on BaseMouseTracker {
});
// Send enter events to annotations that are not in last but in next, in
// reverse
visual
order.
// reverse
hit-test
order.
final
List
<
MouseTrackerAnnotation
>
enteringAnnotations
=
nextAnnotations
.
keys
.
where
(
(
MouseTrackerAnnotation
annotation
)
=>
!
lastAnnotations
.
containsKey
(
annotation
),
).
toList
();
...
...
@@ -512,35 +406,4 @@ mixin _MouseTrackerEventMixin on BaseMouseTracker {
annotation
.
onEnter
!(
baseEnterEvent
.
transformed
(
nextAnnotations
[
annotation
]));
}
}
@protected
@override
void
handleDeviceUpdate
(
MouseTrackerUpdateDetails
details
)
{
super
.
handleDeviceUpdate
(
details
);
_handleDeviceUpdateMouseEvents
(
details
);
}
}
/// Tracks the relationship between mouse devices and annotations, and
/// triggers mouse events and cursor changes accordingly.
///
/// The [MouseTracker] tracks the relationship between mouse devices and
/// [MouseTrackerAnnotation]s, and when such relationship changes, triggers
/// the following changes if applicable:
///
/// * Dispatches mouse-related pointer events (pointer enter, hover, and exit).
/// * Notifies changes of [mouseIsConnected].
/// * Changes mouse cursors.
///
/// An instance of [MouseTracker] is owned by the global singleton of
/// [RendererBinding].
///
/// This class is a [ChangeNotifier] that notifies its listeners if the value of
/// [mouseIsConnected] changes.
///
/// See also:
///
/// * [BaseMouseTracker], which introduces more details about the timing of
/// device updates.
class
MouseTracker
extends
BaseMouseTracker
with
MouseTrackerCursorMixin
,
_MouseTrackerEventMixin
{
}
packages/flutter/lib/src/rendering/platform_view.dart
View file @
fa06b340
...
...
@@ -11,8 +11,7 @@ import 'package:flutter/services.dart';
import
'box.dart'
;
import
'layer.dart'
;
import
'mouse_cursor.dart'
;
import
'mouse_tracking.dart'
;
import
'mouse_tracker.dart'
;
import
'object.dart'
;
...
...
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
fa06b340
...
...
@@ -8,14 +8,14 @@ import 'package:flutter/animation.dart';
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/semantics.dart'
;
import
'package:flutter/services.dart'
;
import
'package:vector_math/vector_math_64.dart'
;
import
'box.dart'
;
import
'layer.dart'
;
import
'layout_helper.dart'
;
import
'mouse_cursor.dart'
;
import
'mouse_tracking.dart'
;
import
'mouse_tracker.dart'
;
import
'object.dart'
;
export
'package:flutter/gestures.dart'
show
...
...
packages/flutter/lib/src/
rendering
/mouse_cursor.dart
→
packages/flutter/lib/src/
services
/mouse_cursor.dart
View file @
fa06b340
...
...
@@ -4,17 +4,28 @@
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/services.dart'
;
import
'
mouse_tracking
.dart'
;
import
'
system_channels
.dart'
;
///
A mixin for [BaseMouseTracker] that sets the mouse pointer's cursors
///
on device update
.
///
Maintains the state of mouse cursors and manages how cursors are searched
///
for
.
///
/// See also:
///
/// * [MouseTracker], which uses this mixin.
mixin
MouseTrackerCursorMixin
on
BaseMouseTracker
{
/// This is typically created as a global singleton and owned by [MouseTracker].
class
MouseCursorManager
{
/// Create a [MouseCursorManager] by specifying the fallback cursor.
///
/// The `fallbackMouseCursor` must not be [MouseCursor.defer] (typically
/// [SystemMouseCursors.basic]).
MouseCursorManager
(
this
.
fallbackMouseCursor
)
:
assert
(
fallbackMouseCursor
!=
MouseCursor
.
defer
);
/// The mouse cursor to use if all cursor candidates choose to defer.
///
/// See also:
///
/// * [MouseCursor.defer], the mouse cursor object to use to defer.
final
MouseCursor
fallbackMouseCursor
;
/// Returns the active mouse cursor of a device.
///
/// The return value is the last [MouseCursor] activated onto this
...
...
@@ -22,7 +33,6 @@ mixin MouseTrackerCursorMixin on BaseMouseTracker {
///
/// Only valid when asserts are enabled. In release builds, always returns
/// null.
@visibleForTesting
MouseCursor
?
debugDeviceActiveCursor
(
int
device
)
{
MouseCursor
?
result
;
assert
(()
{
...
...
@@ -32,38 +42,30 @@ mixin MouseTrackerCursorMixin on BaseMouseTracker {
return
result
;
}
@protected
@override
void
handleDeviceUpdate
(
MouseTrackerUpdateDetails
details
)
{
super
.
handleDeviceUpdate
(
details
);
_handleDeviceUpdateMouseCursor
(
details
);
}
final
Map
<
int
,
MouseCursorSession
>
_lastSession
=
<
int
,
MouseCursorSession
>{};
// Find the first non-deferred mouse cursor, which fallbacks to
// [SystemMouseCursors.basic].
//
// The `annotations` is the current annotations that the device is hovering in
// visual order from front the back.
// The return value is never null.
MouseCursor
_findFirstCursor
(
Iterable
<
MouseTrackerAnnotation
>
annotations
)
{
return
_DeferringMouseCursor
.
firstNonDeferred
(
annotations
.
map
((
MouseTrackerAnnotation
annotation
)
=>
annotation
.
cursor
),
)
??
SystemMouseCursors
.
basic
;
}
// Handles device update and changes mouse cursors.
void
_handleDeviceUpdateMouseCursor
(
MouseTrackerUpdateDetails
details
)
{
final
int
device
=
details
.
device
;
if
(
details
.
triggeringEvent
is
PointerRemovedEvent
)
{
/// Handles the changes that cause a pointer device to have a new list of mouse
/// cursor candidates.
///
/// This change can be caused by a pointer event, in which case
/// `triggeringEvent` should not be null, or by other changes, such as when a
/// widget has moved under a still mouse, which is detected after the current
/// frame is complete. In either case, `cursorCandidates` should be the list of
/// cursors at the location of the mouse in hit-test order.
void
handleDeviceCursorUpdate
(
int
device
,
PointerEvent
?
triggeringEvent
,
Iterable
<
MouseCursor
>
cursorCandidates
,
)
{
if
(
triggeringEvent
is
PointerRemovedEvent
)
{
_lastSession
.
remove
(
device
);
return
;
}
final
MouseCursorSession
?
lastSession
=
_lastSession
[
device
];
final
MouseCursor
nextCursor
=
_findFirstCursor
(
details
.
nextAnnotations
.
keys
);
final
MouseCursor
nextCursor
=
_DeferringMouseCursor
.
firstNonDeferred
(
cursorCandidates
)
??
fallbackMouseCursor
;
assert
(
nextCursor
is
!
_DeferringMouseCursor
);
if
(
lastSession
?.
cursor
==
nextCursor
)
return
;
...
...
@@ -191,9 +193,9 @@ abstract class MouseCursorSession {
/// a cursor, and defines the states and behaviors of the cursor. Every mouse
/// cursor class usually has a corresponding [MouseCursorSession] class.
///
/// [Mouse
TrackerCursorMixin] is a mixin
that adds the feature of changing
/// cursors to [
Base
MouseTracker], which tracks the relationship between mouse
/// devices and annotations. [Mouse
TrackerCursorMixin
] is usually used as a part
/// [Mouse
CursorManager] is a class
that adds the feature of changing
/// cursors to [MouseTracker], which tracks the relationship between mouse
/// devices and annotations. [Mouse
CursorManager
] is usually used as a part
/// of [MouseTracker].
@immutable
abstract
class
MouseCursor
with
Diagnosticable
{
...
...
packages/flutter/lib/src/services/mouse_tracking.dart
0 → 100644
View file @
fa06b340
// Copyright 2014 The Flutter 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
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'mouse_cursor.dart'
;
/// Signature for listening to [PointerEnterEvent] events.
///
/// Used by [MouseTrackerAnnotation], [MouseRegion] and [RenderMouseRegion].
typedef
PointerEnterEventListener
=
void
Function
(
PointerEnterEvent
event
);
/// Signature for listening to [PointerExitEvent] events.
///
/// Used by [MouseTrackerAnnotation], [MouseRegion] and [RenderMouseRegion].
typedef
PointerExitEventListener
=
void
Function
(
PointerExitEvent
event
);
/// Signature for listening to [PointerHoverEvent] events.
///
/// Used by [MouseTrackerAnnotation], [MouseRegion] and [RenderMouseRegion].
typedef
PointerHoverEventListener
=
void
Function
(
PointerHoverEvent
event
);
/// The annotation object used to annotate regions that are interested in mouse
/// movements.
///
/// To use an annotation, return this object as a [HitTestEntry] in a hit test.
/// Typically this is implemented by making a [RenderBox] implement this class
/// (see [RenderMouseRegion]).
///
/// [MouseTracker] uses this class as a label to filter the hit test results. Hit
/// test entries that are also [MouseTrackerAnnotation]s are considered as valid
/// targets in terms of computing mouse related effects, such as enter events,
/// exit events, and mouse cursor events.
///
/// See also:
///
/// * [MouseTracker], which uses [MouseTrackerAnnotation].
class
MouseTrackerAnnotation
with
Diagnosticable
{
/// Creates an immutable [MouseTrackerAnnotation].
///
/// All arguments are optional. The [cursor] must not be null.
const
MouseTrackerAnnotation
({
this
.
onEnter
,
this
.
onExit
,
this
.
cursor
=
MouseCursor
.
defer
,
this
.
validForMouseTracker
=
true
,
})
:
assert
(
cursor
!=
null
);
/// Triggered when a mouse pointer, with or without buttons pressed, has
/// entered the region and [validForMouseTracker] is true.
///
/// This callback is triggered when the pointer has started to be contained by
/// the region, either due to a pointer event, or due to the movement or
/// disappearance of the region. This method is always matched by a later
/// [onExit].
///
/// See also:
///
/// * [onExit], which is triggered when a mouse pointer exits the region.
/// * [MouseRegion.onEnter], which uses this callback.
final
PointerEnterEventListener
?
onEnter
;
/// Triggered when a mouse pointer, with or without buttons pressed, has
/// exited the region and [validForMouseTracker] is true.
///
/// This callback is triggered when the pointer has stopped being contained
/// by the region, either due to a pointer event, or due to the movement or
/// disappearance of the region. This method always matches an earlier
/// [onEnter].
///
/// See also:
///
/// * [onEnter], which is triggered when a mouse pointer enters the region.
/// * [MouseRegion.onExit], which uses this callback, but is not triggered in
/// certain cases and does not always match its earlier [MouseRegion.onEnter].
final
PointerExitEventListener
?
onExit
;
/// The mouse cursor for mouse pointers that are hovering over the region.
///
/// When a mouse enters the region, its cursor will be changed to the [cursor].
/// When the mouse leaves the region, the cursor will be set by the region
/// found at the new location.
///
/// Defaults to [MouseCursor.defer], deferring the choice of cursor to the next
/// region behind it in hit-test order.
///
/// See also:
///
/// * [MouseRegion.cursor], which provide values to this field.
final
MouseCursor
cursor
;
/// Whether this is included when [MouseTracker] collects the list of
/// annotations.
///
/// If [validForMouseTracker] is false, this object is excluded from the
/// current annotation list even if it's included in the hit test, affecting
/// mouse-related behavior such as enter events, exit events, and mouse
/// cursors. The [validForMouseTracker] does not affect hit testing.
///
/// The [validForMouseTracker] is true for [MouseTrackerAnnotation]s built by
/// the constructor.
final
bool
validForMouseTracker
;
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
FlagsSummary
<
Function
?>(
'callbacks'
,
<
String
,
Function
?>
{
'enter'
:
onEnter
,
'exit'
:
onExit
,
},
ifEmpty:
'<none>'
,
));
properties
.
add
(
DiagnosticsProperty
<
MouseCursor
>(
'cursor'
,
cursor
,
defaultValue:
MouseCursor
.
defer
));
}
}
packages/flutter/lib/src/widgets/basic.dart
View file @
fa06b340
...
...
@@ -41,6 +41,8 @@ export 'package:flutter/rendering.dart' show
LayerLink
,
MainAxisAlignment
,
MainAxisSize
,
MouseCursor
,
SystemMouseCursors
,
MultiChildLayoutDelegate
,
Overflow
,
PaintingContext
,
...
...
packages/flutter/lib/src/widgets/focus_manager.dart
View file @
fa06b340
...
...
@@ -1494,7 +1494,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
/// interaction type.
///
/// The initial value of [highlightMode] depends upon the value of
/// [defaultTargetPlatform] and [
Base
MouseTracker.mouseIsConnected] of
/// [defaultTargetPlatform] and [MouseTracker.mouseIsConnected] of
/// [RendererBinding.mouseTracker], making a guess about which interaction is
/// most appropriate for the initial interaction mode.
///
...
...
packages/flutter/test/rendering/mouse_track
ing
_cursor_test.dart
→
packages/flutter/test/rendering/mouse_track
er
_cursor_test.dart
View file @
fa06b340
...
...
@@ -10,7 +10,7 @@ import 'package:flutter/gestures.dart';
import
'package:flutter/services.dart'
;
import
'../flutter_test_alternative.dart'
;
import
'
./mouse_tracking
_test_utils.dart'
;
import
'
mouse_tracker
_test_utils.dart'
;
typedef
MethodCallHandler
=
Future
<
dynamic
>
Function
(
MethodCall
call
);
typedef
SimpleAnnotationFinder
=
Iterable
<
HitTestTarget
>
Function
(
Offset
offset
);
...
...
packages/flutter/test/rendering/mouse_track
ing
_test.dart
→
packages/flutter/test/rendering/mouse_track
er
_test.dart
View file @
fa06b340
...
...
@@ -5,12 +5,11 @@
import
'dart:ui'
as
ui
;
import
'dart:ui'
show
PointerChange
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/gestures.dart'
;
import
'../flutter_test_alternative.dart'
;
import
'
./mouse_tracking
_test_utils.dart'
;
import
'
mouse_tracker
_test_utils.dart'
;
MouseTracker
get
_mouseTracker
=>
RendererBinding
.
instance
!.
mouseTracker
;
...
...
@@ -76,32 +75,6 @@ void main() {
final
Matrix4
translate10by20
=
Matrix4
.
translationValues
(
10
,
20
,
0
);
test
(
'MouseTrackerAnnotation has correct toString'
,
()
{
final
MouseTrackerAnnotation
annotation1
=
MouseTrackerAnnotation
(
onEnter:
(
_
)
{},
onExit:
(
_
)
{},
);
expect
(
annotation1
.
toString
(),
equals
(
'MouseTrackerAnnotation#
${shortHash(annotation1)}
(callbacks: [enter, exit])'
),
);
const
MouseTrackerAnnotation
annotation2
=
MouseTrackerAnnotation
();
expect
(
annotation2
.
toString
(),
equals
(
'MouseTrackerAnnotation#
${shortHash(annotation2)}
(callbacks: <none>)'
),
);
final
MouseTrackerAnnotation
annotation3
=
MouseTrackerAnnotation
(
onEnter:
(
_
)
{},
cursor:
SystemMouseCursors
.
grab
,
);
expect
(
annotation3
.
toString
(),
equals
(
'MouseTrackerAnnotation#
${shortHash(annotation3)}
(callbacks: [enter], cursor: SystemMouseCursor(grab))'
),
);
});
test
(
'should detect enter, hover, and exit from Added, Hover, and Removed events'
,
()
{
final
List
<
PointerEvent
>
events
=
<
PointerEvent
>[];
_setUpWithOneAnnotation
(
logEvents:
events
);
...
...
packages/flutter/test/rendering/mouse_track
ing
_test_utils.dart
→
packages/flutter/test/rendering/mouse_track
er
_test_utils.dart
View file @
fa06b340
File moved
packages/flutter/test/services/mouse_tracking_test.dart
0 → 100644
View file @
fa06b340
// Copyright 2014 The Flutter 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
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
test
(
'MouseTrackerAnnotation has correct toString'
,
()
{
final
MouseTrackerAnnotation
annotation1
=
MouseTrackerAnnotation
(
onEnter:
(
_
)
{},
onExit:
(
_
)
{},
);
expect
(
annotation1
.
toString
(),
equals
(
'MouseTrackerAnnotation#
${shortHash(annotation1)}
(callbacks: [enter, exit])'
),
);
const
MouseTrackerAnnotation
annotation2
=
MouseTrackerAnnotation
();
expect
(
annotation2
.
toString
(),
equals
(
'MouseTrackerAnnotation#
${shortHash(annotation2)}
(callbacks: <none>)'
),
);
final
MouseTrackerAnnotation
annotation3
=
MouseTrackerAnnotation
(
onEnter:
(
_
)
{},
cursor:
SystemMouseCursors
.
grab
,
);
expect
(
annotation3
.
toString
(),
equals
(
'MouseTrackerAnnotation#
${shortHash(annotation3)}
(callbacks: [enter], cursor: SystemMouseCursor(grab))'
),
);
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment