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
16123105
Unverified
Commit
16123105
authored
Jan 14, 2022
by
Hans Muller
Committed by
GitHub
Jan 14, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PopupMenu: add themeable mouse cursor v2 (#96567)
parent
5012c99d
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
78 additions
and
22 deletions
+78
-22
ink_well.dart
packages/flutter/lib/src/material/ink_well.dart
+1
-0
popup_menu.dart
packages/flutter/lib/src/material/popup_menu.dart
+28
-9
popup_menu_theme.dart
packages/flutter/lib/src/material/popup_menu_theme.dart
+14
-1
popup_menu_theme_test.dart
packages/flutter/test/material/popup_menu_theme_test.dart
+35
-12
No files found.
packages/flutter/lib/src/material/ink_well.dart
View file @
16123105
...
...
@@ -1087,6 +1087,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
if
(
_hasFocus
)
MaterialState
.
focused
,
},
);
return
_ParentInkResponseProvider
(
state:
this
,
child:
Actions
(
...
...
packages/flutter/lib/src/material/popup_menu.dart
View file @
16123105
...
...
@@ -264,15 +264,20 @@ class PopupMenuItem<T> extends PopupMenuEntry<T> {
/// of [ThemeData.textTheme] is used.
final
TextStyle
?
textStyle
;
/// {@template flutter.material.popupmenu.mouseCursor}
/// The cursor for a mouse pointer when it enters or is hovering over the
/// widget.
///
/// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
/// [MaterialStateProperty.resolve] is used for the following [MaterialState]:
/// [MaterialStateProperty.resolve] is used for the following [MaterialState]
s
:
///
/// * [MaterialState.hovered].
/// * [MaterialState.focused].
/// * [MaterialState.disabled].
/// {@endtemplate}
///
/// If this property is null, [MaterialStateMouseCursor.clickable] will be used.
/// If null, then the value of [PopupMenuThemeData.mouseCursor] is used. If
/// that is also null, then [MaterialStateMouseCursor.clickable] is used.
final
MouseCursor
?
mouseCursor
;
/// The widget below this widget in the tree.
...
...
@@ -355,12 +360,6 @@ class PopupMenuItemState<T, W extends PopupMenuItem<T>> extends State<W> {
child:
item
,
);
}
final
MouseCursor
effectiveMouseCursor
=
MaterialStateProperty
.
resolveAs
<
MouseCursor
>(
widget
.
mouseCursor
??
MaterialStateMouseCursor
.
clickable
,
<
MaterialState
>{
if
(!
widget
.
enabled
)
MaterialState
.
disabled
,
},
);
return
MergeSemantics
(
child:
Semantics
(
...
...
@@ -369,7 +368,7 @@ class PopupMenuItemState<T, W extends PopupMenuItem<T>> extends State<W> {
child:
InkWell
(
onTap:
widget
.
enabled
?
handleTap
:
null
,
canRequestFocus:
widget
.
enabled
,
mouseCursor:
effectiveMouseCursor
,
mouseCursor:
_EffectiveMouseCursor
(
widget
.
mouseCursor
,
popupMenuTheme
.
mouseCursor
)
,
child:
item
,
),
),
...
...
@@ -1185,3 +1184,23 @@ class PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
);
}
}
// This MaterialStateProperty is passed along to the menu item's InkWell which
// resolves the property against MaterialState.disabled, MaterialState.hovered,
// MaterialState.focused.
class
_EffectiveMouseCursor
extends
MaterialStateMouseCursor
{
const
_EffectiveMouseCursor
(
this
.
widgetCursor
,
this
.
themeCursor
);
final
MouseCursor
?
widgetCursor
;
final
MaterialStateProperty
<
MouseCursor
?>?
themeCursor
;
@override
MouseCursor
resolve
(
Set
<
MaterialState
>
states
)
{
return
MaterialStateProperty
.
resolveAs
<
MouseCursor
?>(
widgetCursor
,
states
)
??
themeCursor
?.
resolve
(
states
)
??
MaterialStateMouseCursor
.
clickable
.
resolve
(
states
);
}
@override
String
get
debugDescription
=>
'MaterialStateMouseCursor(PopupMenuItemState)'
;
}
packages/flutter/lib/src/material/popup_menu_theme.dart
View file @
16123105
...
...
@@ -7,6 +7,7 @@ import 'dart:ui' show lerpDouble;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/widgets.dart'
;
import
'material_state.dart'
;
import
'theme.dart'
;
/// Defines the visual properties of the routes used to display popup menus
...
...
@@ -38,6 +39,7 @@ class PopupMenuThemeData with Diagnosticable {
this
.
elevation
,
this
.
textStyle
,
this
.
enableFeedback
,
this
.
mouseCursor
,
});
/// The background color of the popup menu.
...
...
@@ -57,6 +59,11 @@ class PopupMenuThemeData with Diagnosticable {
/// If [PopupMenuButton.enableFeedback] is provided, [enableFeedback] is ignored.
final
bool
?
enableFeedback
;
/// {@macro flutter.material.popupmenu.mouseCursor}
///
/// If specified, overrides the default value of [PopupMenuItem.mouseCursor].
final
MaterialStateProperty
<
MouseCursor
?>?
mouseCursor
;
/// Creates a copy of this object with the given fields replaced with the
/// new values.
PopupMenuThemeData
copyWith
({
...
...
@@ -65,6 +72,7 @@ class PopupMenuThemeData with Diagnosticable {
double
?
elevation
,
TextStyle
?
textStyle
,
bool
?
enableFeedback
,
MaterialStateProperty
<
MouseCursor
?>?
mouseCursor
,
})
{
return
PopupMenuThemeData
(
color:
color
??
this
.
color
,
...
...
@@ -72,6 +80,7 @@ class PopupMenuThemeData with Diagnosticable {
elevation:
elevation
??
this
.
elevation
,
textStyle:
textStyle
??
this
.
textStyle
,
enableFeedback:
enableFeedback
??
this
.
enableFeedback
,
mouseCursor:
mouseCursor
??
this
.
mouseCursor
,
);
}
...
...
@@ -90,6 +99,7 @@ class PopupMenuThemeData with Diagnosticable {
elevation:
lerpDouble
(
a
?.
elevation
,
b
?.
elevation
,
t
),
textStyle:
TextStyle
.
lerp
(
a
?.
textStyle
,
b
?.
textStyle
,
t
),
enableFeedback:
t
<
0.5
?
a
?.
enableFeedback
:
b
?.
enableFeedback
,
mouseCursor:
t
<
0.5
?
a
?.
mouseCursor
:
b
?.
mouseCursor
,
);
}
...
...
@@ -101,6 +111,7 @@ class PopupMenuThemeData with Diagnosticable {
elevation
,
textStyle
,
enableFeedback
,
mouseCursor
);
}
...
...
@@ -115,7 +126,8 @@ class PopupMenuThemeData with Diagnosticable {
&&
other
.
color
==
color
&&
other
.
shape
==
shape
&&
other
.
textStyle
==
textStyle
&&
other
.
enableFeedback
==
enableFeedback
;
&&
other
.
enableFeedback
==
enableFeedback
&&
other
.
mouseCursor
==
mouseCursor
;
}
@override
...
...
@@ -126,6 +138,7 @@ class PopupMenuThemeData with Diagnosticable {
properties
.
add
(
DoubleProperty
(
'elevation'
,
elevation
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
TextStyle
>(
'text style'
,
textStyle
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
bool
>(
'enableFeedback'
,
enableFeedback
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
MaterialStateProperty
<
MouseCursor
?>>(
'mouseCursor'
,
mouseCursor
,
defaultValue:
null
));
}
}
...
...
packages/flutter/test/material/popup_menu_theme_test.dart
View file @
16123105
...
...
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/gestures.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
...
@@ -27,6 +28,7 @@ void main() {
expect
(
popupMenuTheme
.
shape
,
null
);
expect
(
popupMenuTheme
.
elevation
,
null
);
expect
(
popupMenuTheme
.
textStyle
,
null
);
expect
(
popupMenuTheme
.
mouseCursor
,
null
);
});
testWidgets
(
'Default PopupMenuThemeData debugFillProperties'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -48,6 +50,7 @@ void main() {
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
2.0
))),
elevation:
2.0
,
textStyle:
TextStyle
(
color:
Color
(
0xffffffff
)),
mouseCursor:
MaterialStateMouseCursor
.
clickable
,
).
debugFillProperties
(
builder
);
final
List
<
String
>
description
=
builder
.
properties
...
...
@@ -60,6 +63,7 @@ void main() {
'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))'
,
'elevation: 2.0'
,
'text style: TextStyle(inherit: true, color: Color(0xffffffff))'
,
'mouseCursor: MaterialStateMouseCursor(clickable)'
,
]);
});
...
...
@@ -251,7 +255,8 @@ void main() {
testWidgets
(
'ThemeData.popupMenuTheme properties are utilized'
,
(
WidgetTester
tester
)
async
{
final
Key
popupButtonKey
=
UniqueKey
();
final
Key
popupButtonApp
=
UniqueKey
();
final
Key
popupItemKey
=
UniqueKey
();
final
Key
enabledPopupItemKey
=
UniqueKey
();
final
Key
disabledPopupItemKey
=
UniqueKey
();
await
tester
.
pumpWidget
(
MaterialApp
(
key:
popupButtonApp
,
...
...
@@ -259,19 +264,31 @@ void main() {
child:
Column
(
children:
<
Widget
>[
PopupMenuTheme
(
data:
const
PopupMenuThemeData
(
data:
PopupMenuThemeData
(
color:
Colors
.
pink
,
shape:
BeveledRectangleBorder
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
10
))),
shape:
const
BeveledRectangleBorder
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
10
))),
elevation:
6.0
,
textStyle:
TextStyle
(
color:
Color
(
0xfffff000
),
textBaseline:
TextBaseline
.
alphabetic
),
textStyle:
const
TextStyle
(
color:
Color
(
0xfffff000
),
textBaseline:
TextBaseline
.
alphabetic
),
mouseCursor:
MaterialStateProperty
.
resolveWith
<
MouseCursor
?>((
Set
<
MaterialState
>
states
)
{
if
(
states
.
contains
(
MaterialState
.
disabled
))
{
return
SystemMouseCursors
.
contextMenu
;
}
return
SystemMouseCursors
.
alias
;
}),
),
child:
PopupMenuButton
<
void
>(
key:
popupButtonKey
,
itemBuilder:
(
BuildContext
context
)
{
return
<
PopupMenuEntry
<
void
>>[
PopupMenuItem
<
void
>(
key:
popupItemKey
,
child:
const
Text
(
'Example'
),
key:
disabledPopupItemKey
,
enabled:
false
,
child:
const
Text
(
'disabled'
),
),
PopupMenuItem
<
void
>(
key:
enabledPopupItemKey
,
onTap:
()
{
},
child:
const
Text
(
'enabled'
),
),
];
},
...
...
@@ -299,16 +316,22 @@ void main() {
expect
(
button
.
shape
,
const
BeveledRectangleBorder
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
10
))));
expect
(
button
.
elevation
,
6.0
);
/// The last DefaultTextStyle widget under popupItemKey is the
/// [PopupMenuItem] specified above, so by finding the last descendent of
/// popupItemKey that is of type DefaultTextStyle, this code retrieves the
/// built [PopupMenuItem].
final
DefaultTextStyle
text
=
tester
.
widget
<
DefaultTextStyle
>(
find
.
descendant
(
of:
find
.
byKey
(
p
opupItemKey
),
of:
find
.
byKey
(
enabledP
opupItemKey
),
matching:
find
.
byType
(
DefaultTextStyle
),
)
.
last
,
),
);
expect
(
text
.
style
.
color
,
const
Color
(
0xfffff000
));
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
addTearDown
(
gesture
.
removePointer
);
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byKey
(
disabledPopupItemKey
)));
await
tester
.
pumpAndSettle
();
expect
(
RendererBinding
.
instance
!.
mouseTracker
.
debugDeviceActiveCursor
(
1
),
SystemMouseCursors
.
contextMenu
);
await
gesture
.
down
(
tester
.
getCenter
(
find
.
byKey
(
enabledPopupItemKey
)));
await
tester
.
pumpAndSettle
();
expect
(
RendererBinding
.
instance
!.
mouseTracker
.
debugDeviceActiveCursor
(
1
),
SystemMouseCursors
.
alias
);
});
}
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