// 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/widgets.dart'; import 'theme.dart'; /// Defines the visual properties needed for text selection in [TextField] and /// [SelectableText] widgets. /// /// Used by [TextSelectionTheme] to control the visual properties of text /// selection in a widget subtree. /// /// Use [TextSelectionTheme.of] to access the closest ancestor /// [TextSelectionTheme] of the current [BuildContext]. /// /// See also: /// /// * [TextSelectionTheme], an [InheritedWidget] that propagates the theme down its /// subtree. /// * [InputDecorationTheme], which defines most other visual properties of /// text fields. @immutable class TextSelectionThemeData with Diagnosticable { /// Creates the set of properties used to configure [TextField]s. const TextSelectionThemeData({ this.cursorColor, this.selectionColor, this.selectionHandleColor, }); /// The color of the cursor in the text field. /// /// The cursor indicates the current location of text insertion point in /// the field. final Color? cursorColor; /// The background color of selected text. final Color? selectionColor; /// The color of the selection handles on the text field. /// /// Selection handles are used to indicate the bounds of the selected text, /// or as a handle to drag the cursor to a new location in the text. /// /// On iOS [TextField] and [SelectableText] cannot access [selectionHandleColor]. /// To set the [selectionHandleColor] on iOS, you can change the /// [CupertinoThemeData.primaryColor] in [ThemeData.cupertinoOverrideTheme]. final Color? selectionHandleColor; /// Creates a copy of this object with the given fields replaced with the /// specified values. TextSelectionThemeData copyWith({ Color? cursorColor, Color? selectionColor, Color? selectionHandleColor, }) { return TextSelectionThemeData( cursorColor: cursorColor ?? this.cursorColor, selectionColor: selectionColor ?? this.selectionColor, selectionHandleColor: selectionHandleColor ?? this.selectionHandleColor, ); } /// Linearly interpolate between two text field themes. /// /// If both arguments are null, then null is returned. /// /// {@macro dart.ui.shadow.lerp} static TextSelectionThemeData? lerp(TextSelectionThemeData? a, TextSelectionThemeData? b, double t) { if (a == null && b == null) return null; assert(t != null); return TextSelectionThemeData( cursorColor: Color.lerp(a?.cursorColor, b?.cursorColor, t), selectionColor: Color.lerp(a?.selectionColor, b?.selectionColor, t), selectionHandleColor: Color.lerp(a?.selectionHandleColor, b?.selectionHandleColor, t), ); } @override int get hashCode { return hashValues( cursorColor, selectionColor, selectionHandleColor, ); } @override bool operator==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; return other is TextSelectionThemeData && other.cursorColor == cursorColor && other.selectionColor == selectionColor && other.selectionHandleColor == selectionHandleColor; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(ColorProperty('cursorColor', cursorColor, defaultValue: null)); properties.add(ColorProperty('selectionColor', selectionColor, defaultValue: null)); properties.add(ColorProperty('selectionHandleColor', selectionHandleColor, defaultValue: null)); } } /// An inherited widget that defines the appearance of text selection in /// this widget's subtree. /// /// Values specified here are used for [TextField] and [SelectableText] /// properties that are not given an explicit non-null value. /// /// {@tool snippet} /// /// Here is an example of a text selection theme that applies a blue cursor /// color with light blue selection handles to the child text field. /// /// ```dart /// const TextSelectionTheme( /// data: TextSelectionThemeData( /// cursorColor: Colors.blue, /// selectionHandleColor: Colors.lightBlue, /// ), /// child: TextField(), /// ), /// ``` /// {@end-tool} class TextSelectionTheme extends InheritedTheme { /// Creates a text selection theme widget that specifies the text /// selection properties for all widgets below it in the widget tree. /// /// The data argument must not be null. const TextSelectionTheme({ Key? key, required this.data, required Widget child, }) : assert(data != null), super(key: key, child: child); /// The properties for descendant [TextField] and [SelectableText] widgets. final TextSelectionThemeData data; /// Returns the [data] from the closest [TextSelectionTheme] ancestor. If /// there is no ancestor, it returns [ThemeData.textSelectionTheme]. /// Applications can assume that the returned value will not be null. /// /// Typical usage is as follows: /// /// ```dart /// TextSelectionThemeData theme = TextSelectionTheme.of(context); /// ``` static TextSelectionThemeData of(BuildContext context) { final TextSelectionTheme? selectionTheme = context.dependOnInheritedWidgetOfExactType<TextSelectionTheme>(); return selectionTheme?.data ?? Theme.of(context).textSelectionTheme; } @override Widget wrap(BuildContext context, Widget child) { return TextSelectionTheme(data: data, child: child); } @override bool updateShouldNotify(TextSelectionTheme oldWidget) => data != oldWidget.data; }