Unverified Commit fbb3036b authored by J-P Nurmi's avatar J-P Nurmi Committed by GitHub

FloatingActionButton: add themeable mouse cursor (#103473)

parent 2756f868
......@@ -11,6 +11,7 @@ import 'package:flutter/widgets.dart';
import 'button.dart';
import 'color_scheme.dart';
import 'floating_action_button_theme.dart';
import 'material_state.dart';
import 'scaffold.dart';
import 'text_theme.dart';
import 'theme.dart';
......@@ -603,7 +604,7 @@ class FloatingActionButton extends StatelessWidget {
Widget result = RawMaterialButton(
onPressed: onPressed,
mouseCursor: mouseCursor,
mouseCursor: _EffectiveMouseCursor(mouseCursor, floatingActionButtonTheme.mouseCursor),
elevation: elevation,
focusElevation: focusElevation,
hoverElevation: hoverElevation,
......@@ -664,6 +665,26 @@ class FloatingActionButton extends StatelessWidget {
}
}
// This MaterialStateProperty is passed along to RawMaterialButton which
// resolves the property against MaterialState.pressed, MaterialState.hovered,
// MaterialState.focused, MaterialState.disabled.
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(FloatActionButton)';
}
// This widget's size matches its child's size unless its constraints
// force it to be larger or smaller. The child is centered.
//
......
......@@ -7,6 +7,8 @@ import 'dart:ui' show lerpDouble;
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'material_state.dart';
/// Defines default property values for descendant [FloatingActionButton]
/// widgets.
///
......@@ -51,6 +53,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
this.extendedIconLabelSpacing,
this.extendedPadding,
this.extendedTextStyle,
this.mouseCursor,
});
/// Color to be used for the unselected, enabled [FloatingActionButton]'s
......@@ -129,6 +132,11 @@ class FloatingActionButtonThemeData with Diagnosticable {
/// The text style for an extended [FloatingActionButton]'s label.
final TextStyle? extendedTextStyle;
/// {@macro flutter.material.RawMaterialButton.mouseCursor}
///
/// If specified, overrides the default value of [FloatingActionButton.mouseCursor].
final MaterialStateProperty<MouseCursor?>? mouseCursor;
/// Creates a copy of this object with the given fields replaced with the
/// new values.
FloatingActionButtonThemeData copyWith({
......@@ -152,6 +160,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
double? extendedIconLabelSpacing,
EdgeInsetsGeometry? extendedPadding,
TextStyle? extendedTextStyle,
MaterialStateProperty<MouseCursor?>? mouseCursor,
}) {
return FloatingActionButtonThemeData(
foregroundColor: foregroundColor ?? this.foregroundColor,
......@@ -174,6 +183,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
extendedIconLabelSpacing: extendedIconLabelSpacing ?? this.extendedIconLabelSpacing,
extendedPadding: extendedPadding ?? this.extendedPadding,
extendedTextStyle: extendedTextStyle ?? this.extendedTextStyle,
mouseCursor: mouseCursor ?? this.mouseCursor,
);
}
......@@ -208,6 +218,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
extendedIconLabelSpacing: lerpDouble(a?.extendedIconLabelSpacing, b?.extendedIconLabelSpacing, t),
extendedPadding: EdgeInsetsGeometry.lerp(a?.extendedPadding, b?.extendedPadding, t),
extendedTextStyle: TextStyle.lerp(a?.extendedTextStyle, b?.extendedTextStyle, t),
mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
);
}
......@@ -232,7 +243,10 @@ class FloatingActionButtonThemeData with Diagnosticable {
extendedSizeConstraints,
extendedIconLabelSpacing,
extendedPadding,
extendedTextStyle,
Object.hash(
extendedTextStyle,
mouseCursor,
),
);
@override
......@@ -263,7 +277,8 @@ class FloatingActionButtonThemeData with Diagnosticable {
&& other.extendedSizeConstraints == extendedSizeConstraints
&& other.extendedIconLabelSpacing == extendedIconLabelSpacing
&& other.extendedPadding == extendedPadding
&& other.extendedTextStyle == extendedTextStyle;
&& other.extendedTextStyle == extendedTextStyle
&& other.mouseCursor == mouseCursor;
}
@override
......@@ -290,5 +305,6 @@ class FloatingActionButtonThemeData with Diagnosticable {
properties.add(DoubleProperty('extendedIconLabelSpacing', extendedIconLabelSpacing, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('extendedPadding', extendedPadding, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('extendedTextStyle', extendedTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: null));
}
}
......@@ -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';
......@@ -287,6 +288,7 @@ void main() {
extendedIconLabelSpacing: 12,
extendedPadding: EdgeInsetsDirectional.only(start: 7.0, end: 8.0),
extendedTextStyle: TextStyle(letterSpacing: 2.0),
mouseCursor: MaterialStateMouseCursor.clickable,
).debugFillProperties(builder);
final List<String> description = builder.properties
......@@ -315,8 +317,33 @@ void main() {
'extendedIconLabelSpacing: 12.0',
'extendedPadding: EdgeInsetsDirectional(7.0, 0.0, 8.0, 0.0)',
'extendedTextStyle: TextStyle(inherit: true, letterSpacing: 2.0)',
'mouseCursor: MaterialStateMouseCursor(clickable)',
]);
});
testWidgets('FloatingActionButton.mouseCursor uses FloatingActionButtonThemeData.mouseCursor when specified.', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
theme: ThemeData().copyWith(
floatingActionButtonTheme: FloatingActionButtonThemeData(
mouseCursor: MaterialStateProperty.all(SystemMouseCursors.text),
),
),
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () { },
child: const Icon(Icons.add),
),
),
));
await tester.pumpAndSettle();
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer();
addTearDown(gesture.removePointer);
await gesture.moveTo(tester.getCenter(find.byType(FloatingActionButton)));
await tester.pumpAndSettle();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
});
}
RawMaterialButton _getRawMaterialButton(WidgetTester tester) {
......
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