mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
## Description This PR introduces `DefaultSelectionStyle.mouseCursor` to configure the mouse cursor over selectable text. It also applies this solution to `InkResponse` to make the mouse cursor win over the default one provided by selectable `Text` for many Material components (such as buttons). ### Before https://user-images.githubusercontent.com/840911/233627729-ddf98e2a-444d-4c6d-a6d5-f521982f48dd.mov ### After https://user-images.githubusercontent.com/840911/233627718-8871a68f-d33c-44cf-b4a1-91bb1fcdf076.mov ## Related Issue Fixes https://github.com/flutter/flutter/issues/104595 ## Tests Adds 6 tests.
137 lines
4.5 KiB
Dart
137 lines
4.5 KiB
Dart
// 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 'basic.dart';
|
|
import 'framework.dart';
|
|
import 'inherited_theme.dart';
|
|
|
|
// Examples can assume:
|
|
// late BuildContext context;
|
|
|
|
/// The selection style to apply to descendant [EditableText] widgets which
|
|
/// don't have an explicit style.
|
|
///
|
|
/// {@macro flutter.cupertino.CupertinoApp.defaultSelectionStyle}
|
|
///
|
|
/// {@macro flutter.material.MaterialApp.defaultSelectionStyle}
|
|
///
|
|
/// See also:
|
|
/// * [TextSelectionTheme]: which also creates a [DefaultSelectionStyle] for
|
|
/// the subtree.
|
|
class DefaultSelectionStyle extends InheritedTheme {
|
|
/// Creates a default selection style widget that specifies the selection
|
|
/// properties for all widgets below it in the widget tree.
|
|
const DefaultSelectionStyle({
|
|
super.key,
|
|
this.cursorColor,
|
|
this.selectionColor,
|
|
this.mouseCursor,
|
|
required super.child,
|
|
});
|
|
|
|
/// A const-constructable default selection style that provides fallback
|
|
/// values (null).
|
|
///
|
|
/// Returned from [of] when the given [BuildContext] doesn't have an enclosing
|
|
/// default selection style.
|
|
///
|
|
/// This constructor creates a [DefaultTextStyle] with an invalid [child],
|
|
/// which means the constructed value cannot be incorporated into the tree.
|
|
const DefaultSelectionStyle.fallback({ super.key })
|
|
: cursorColor = null,
|
|
selectionColor = null,
|
|
mouseCursor = null,
|
|
super(child: const _NullWidget());
|
|
|
|
/// Creates a default selection style that overrides the selection styles in
|
|
/// scope at this point in the widget tree.
|
|
///
|
|
/// Any Arguments that are not null replace the corresponding properties on the
|
|
/// default selection style for the [BuildContext] where the widget is inserted.
|
|
static Widget merge({
|
|
Key? key,
|
|
Color? cursorColor,
|
|
Color? selectionColor,
|
|
MouseCursor? mouseCursor,
|
|
required Widget child,
|
|
}) {
|
|
return Builder(
|
|
builder: (BuildContext context) {
|
|
final DefaultSelectionStyle parent = DefaultSelectionStyle.of(context);
|
|
return DefaultSelectionStyle(
|
|
key: key,
|
|
cursorColor: cursorColor ?? parent.cursorColor,
|
|
selectionColor: selectionColor ?? parent.selectionColor,
|
|
mouseCursor: mouseCursor ?? parent.mouseCursor,
|
|
child: child,
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
/// The default cursor and selection color (semi-transparent grey).
|
|
///
|
|
/// This is the color that the [Text] widget uses when the specified selection
|
|
/// color is null.
|
|
static const Color defaultColor = Color(0x80808080);
|
|
|
|
/// The color of the text field's cursor.
|
|
///
|
|
/// The cursor indicates the current location of the text insertion point in
|
|
/// the field.
|
|
final Color? cursorColor;
|
|
|
|
/// The background color of selected text.
|
|
final Color? selectionColor;
|
|
|
|
/// The [MouseCursor] for mouse pointers hovering over selectable Text widgets.
|
|
///
|
|
/// If this property is null, [SystemMouseCursors.text] will be used.
|
|
final MouseCursor? mouseCursor;
|
|
|
|
/// The closest instance of this class that encloses the given context.
|
|
///
|
|
/// If no such instance exists, returns an instance created by
|
|
/// [DefaultSelectionStyle.fallback], which contains fallback values.
|
|
///
|
|
/// Typical usage is as follows:
|
|
///
|
|
/// ```dart
|
|
/// DefaultSelectionStyle style = DefaultSelectionStyle.of(context);
|
|
/// ```
|
|
static DefaultSelectionStyle of(BuildContext context) {
|
|
return context.dependOnInheritedWidgetOfExactType<DefaultSelectionStyle>() ?? const DefaultSelectionStyle.fallback();
|
|
}
|
|
|
|
@override
|
|
Widget wrap(BuildContext context, Widget child) {
|
|
return DefaultSelectionStyle(
|
|
cursorColor: cursorColor,
|
|
selectionColor: selectionColor,
|
|
mouseCursor: mouseCursor,
|
|
child: child
|
|
);
|
|
}
|
|
|
|
@override
|
|
bool updateShouldNotify(DefaultSelectionStyle oldWidget) {
|
|
return cursorColor != oldWidget.cursorColor ||
|
|
selectionColor != oldWidget.selectionColor ||
|
|
mouseCursor != oldWidget.mouseCursor;
|
|
}
|
|
}
|
|
|
|
class _NullWidget extends StatelessWidget {
|
|
const _NullWidget();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
throw FlutterError(
|
|
'A DefaultSelectionStyle constructed with DefaultSelectionStyle.fallback cannot be incorporated into the widget tree, '
|
|
'it is meant only to provide a fallback value returned by DefaultSelectionStyle.of() '
|
|
'when no enclosing default selection style is present in a BuildContext.',
|
|
);
|
|
}
|
|
}
|