Unverified Commit a6504ead authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

TabBar: add themeable mouse cursor (#96737)

parent 36a8f0f2
...@@ -37,6 +37,7 @@ class TabBarTheme with Diagnosticable { ...@@ -37,6 +37,7 @@ class TabBarTheme with Diagnosticable {
this.unselectedLabelStyle, this.unselectedLabelStyle,
this.overlayColor, this.overlayColor,
this.splashFactory, this.splashFactory,
this.mouseCursor,
}); });
/// Default value for [TabBar.indicator]. /// Default value for [TabBar.indicator].
...@@ -70,6 +71,11 @@ class TabBarTheme with Diagnosticable { ...@@ -70,6 +71,11 @@ class TabBarTheme with Diagnosticable {
/// Default value for [TabBar.splashFactory]. /// Default value for [TabBar.splashFactory].
final InteractiveInkFeatureFactory? splashFactory; final InteractiveInkFeatureFactory? splashFactory;
/// {@macro flutter.material.tabs.mouseCursor}
///
/// If specified, overrides the default value of [TabBar.mouseCursor].
final MaterialStateProperty<MouseCursor?>? mouseCursor;
/// Creates a copy of this object but with the given fields replaced with the /// Creates a copy of this object but with the given fields replaced with the
/// new values. /// new values.
TabBarTheme copyWith({ TabBarTheme copyWith({
...@@ -82,6 +88,7 @@ class TabBarTheme with Diagnosticable { ...@@ -82,6 +88,7 @@ class TabBarTheme with Diagnosticable {
TextStyle? unselectedLabelStyle, TextStyle? unselectedLabelStyle,
MaterialStateProperty<Color?>? overlayColor, MaterialStateProperty<Color?>? overlayColor,
InteractiveInkFeatureFactory? splashFactory, InteractiveInkFeatureFactory? splashFactory,
MaterialStateProperty<MouseCursor?>? mouseCursor,
}) { }) {
return TabBarTheme( return TabBarTheme(
indicator: indicator ?? this.indicator, indicator: indicator ?? this.indicator,
...@@ -93,6 +100,7 @@ class TabBarTheme with Diagnosticable { ...@@ -93,6 +100,7 @@ class TabBarTheme with Diagnosticable {
unselectedLabelStyle: unselectedLabelStyle ?? this.unselectedLabelStyle, unselectedLabelStyle: unselectedLabelStyle ?? this.unselectedLabelStyle,
overlayColor: overlayColor ?? this.overlayColor, overlayColor: overlayColor ?? this.overlayColor,
splashFactory: splashFactory ?? this.splashFactory, splashFactory: splashFactory ?? this.splashFactory,
mouseCursor: mouseCursor ?? this.mouseCursor,
); );
} }
...@@ -120,6 +128,7 @@ class TabBarTheme with Diagnosticable { ...@@ -120,6 +128,7 @@ class TabBarTheme with Diagnosticable {
unselectedLabelStyle: TextStyle.lerp(a.unselectedLabelStyle, b.unselectedLabelStyle, t), unselectedLabelStyle: TextStyle.lerp(a.unselectedLabelStyle, b.unselectedLabelStyle, t),
overlayColor: _LerpColors(a.overlayColor, b.overlayColor, t), overlayColor: _LerpColors(a.overlayColor, b.overlayColor, t),
splashFactory: t < 0.5 ? a.splashFactory : b.splashFactory, splashFactory: t < 0.5 ? a.splashFactory : b.splashFactory,
mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor,
); );
} }
...@@ -135,6 +144,7 @@ class TabBarTheme with Diagnosticable { ...@@ -135,6 +144,7 @@ class TabBarTheme with Diagnosticable {
unselectedLabelStyle, unselectedLabelStyle,
overlayColor, overlayColor,
splashFactory, splashFactory,
mouseCursor,
); );
} }
...@@ -153,7 +163,8 @@ class TabBarTheme with Diagnosticable { ...@@ -153,7 +163,8 @@ class TabBarTheme with Diagnosticable {
&& other.unselectedLabelColor == unselectedLabelColor && other.unselectedLabelColor == unselectedLabelColor
&& other.unselectedLabelStyle == unselectedLabelStyle && other.unselectedLabelStyle == unselectedLabelStyle
&& other.overlayColor == overlayColor && other.overlayColor == overlayColor
&& other.splashFactory == splashFactory; && other.splashFactory == splashFactory
&& other.mouseCursor == mouseCursor;
} }
} }
......
...@@ -803,10 +803,23 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -803,10 +803,23 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
/// {@macro flutter.widgets.scrollable.dragStartBehavior} /// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior; final DragStartBehavior dragStartBehavior;
/// {@template flutter.material.tabs.mouseCursor}
/// The cursor for a mouse pointer when it enters or is hovering over the /// The cursor for a mouse pointer when it enters or is hovering over the
/// individual tab widgets. /// individual tab widgets.
/// ///
/// If this property is null, [SystemMouseCursors.click] will be used. /// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
/// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
///
/// * [MaterialState.selected].
/// {@endtemplate}
///
/// If null, then the value of [TabBarTheme.mouseCursor] is used. If
/// that is also null, then [MaterialStateMouseCursor.clickable] is used.
///
/// See also:
///
/// * [MaterialStateMouseCursor], which can be used to create a [MouseCursor]
/// that is also a [MaterialStateProperty<MouseCursor>].
final MouseCursor? mouseCursor; final MouseCursor? mouseCursor;
/// Whether detected gestures should provide acoustic and/or haptic feedback. /// Whether detected gestures should provide acoustic and/or haptic feedback.
...@@ -1222,8 +1235,16 @@ class _TabBarState extends State<TabBar> { ...@@ -1222,8 +1235,16 @@ class _TabBarState extends State<TabBar> {
// the same share of the tab bar's overall width. // the same share of the tab bar's overall width.
final int tabCount = widget.tabs.length; final int tabCount = widget.tabs.length;
for (int index = 0; index < tabCount; index += 1) { for (int index = 0; index < tabCount; index += 1) {
final Set<MaterialState> states = <MaterialState>{
if (index == _currentIndex) MaterialState.selected,
};
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor?>(widget.mouseCursor, states)
?? tabBarTheme.mouseCursor?.resolve(states)
?? MaterialStateMouseCursor.clickable.resolve(states);
wrappedTabs[index] = InkWell( wrappedTabs[index] = InkWell(
mouseCursor: widget.mouseCursor ?? SystemMouseCursors.click, mouseCursor: effectiveMouseCursor,
onTap: () { _handleTap(index); }, onTap: () { _handleTap(index); },
enableFeedback: widget.enableFeedback ?? true, enableFeedback: widget.enableFeedback ?? true,
overlayColor: widget.overlayColor ?? tabBarTheme.overlayColor, overlayColor: widget.overlayColor ?? tabBarTheme.overlayColor,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
// machines. // machines.
@Tags(<String>['reduced-test-set']) @Tags(<String>['reduced-test-set'])
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
...@@ -67,6 +68,7 @@ void main() { ...@@ -67,6 +68,7 @@ void main() {
expect(const TabBarTheme().unselectedLabelStyle, null); expect(const TabBarTheme().unselectedLabelStyle, null);
expect(const TabBarTheme().overlayColor, null); expect(const TabBarTheme().overlayColor, null);
expect(const TabBarTheme().splashFactory, null); expect(const TabBarTheme().splashFactory, null);
expect(const TabBarTheme().mouseCursor, null);
}); });
testWidgets('Tab bar defaults - label style and selected/unselected label colors', (WidgetTester tester) async { testWidgets('Tab bar defaults - label style and selected/unselected label colors', (WidgetTester tester) async {
...@@ -302,6 +304,22 @@ void main() { ...@@ -302,6 +304,22 @@ void main() {
); );
}); });
testWidgets('Tab bar theme overrides tab mouse cursor', (WidgetTester tester) async {
const TabBarTheme tabBarTheme = TabBarTheme(mouseCursor: MaterialStateMouseCursor.textable);
await tester.pumpWidget(_withTheme(tabBarTheme));
final Offset tabBar = tester.getCenter(
find.ancestor(of: find.text('tab 1'),matching: find.byType(TabBar)),
);
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer();
addTearDown(gesture.removePointer);
await gesture.moveTo(tabBar);
await tester.pumpAndSettle();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
});
testWidgets('Tab bar theme - custom tab indicator', (WidgetTester tester) async { testWidgets('Tab bar theme - custom tab indicator', (WidgetTester tester) async {
final TabBarTheme tabBarTheme = TabBarTheme( final TabBarTheme tabBarTheme = TabBarTheme(
indicator: BoxDecoration( indicator: BoxDecoration(
......
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