1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// 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.
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
/// 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;
}