1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'basic.dart'; |
6 | import 'framework.dart'; |
7 | import 'inherited_theme.dart'; |
8 | |
9 | // Examples can assume: |
10 | // late BuildContext context; |
11 | |
12 | /// The selection style to apply to descendant [EditableText] widgets which |
13 | /// don't have an explicit style. |
14 | /// |
15 | /// {@macro flutter.cupertino.CupertinoApp.defaultSelectionStyle} |
16 | /// |
17 | /// {@macro flutter.material.MaterialApp.defaultSelectionStyle} |
18 | /// |
19 | /// See also: |
20 | /// * [TextSelectionTheme]: which also creates a [DefaultSelectionStyle] for |
21 | /// the subtree. |
22 | class DefaultSelectionStyle extends InheritedTheme { |
23 | /// Creates a default selection style widget that specifies the selection |
24 | /// properties for all widgets below it in the widget tree. |
25 | const DefaultSelectionStyle({ |
26 | super.key, |
27 | this.cursorColor, |
28 | this.selectionColor, |
29 | this.mouseCursor, |
30 | required super.child, |
31 | }); |
32 | |
33 | /// A const-constructable default selection style that provides fallback |
34 | /// values (null). |
35 | /// |
36 | /// Returned from [of] when the given [BuildContext] doesn't have an enclosing |
37 | /// default selection style. |
38 | /// |
39 | /// This constructor creates a [DefaultTextStyle] with an invalid [child], |
40 | /// which means the constructed value cannot be incorporated into the tree. |
41 | const DefaultSelectionStyle.fallback({ super.key }) |
42 | : cursorColor = null, |
43 | selectionColor = null, |
44 | mouseCursor = null, |
45 | super(child: const _NullWidget()); |
46 | |
47 | /// Creates a default selection style that overrides the selection styles in |
48 | /// scope at this point in the widget tree. |
49 | /// |
50 | /// Any Arguments that are not null replace the corresponding properties on the |
51 | /// default selection style for the [BuildContext] where the widget is inserted. |
52 | static Widget merge({ |
53 | Key? key, |
54 | Color? cursorColor, |
55 | Color? selectionColor, |
56 | MouseCursor? mouseCursor, |
57 | required Widget child, |
58 | }) { |
59 | return Builder( |
60 | builder: (BuildContext context) { |
61 | final DefaultSelectionStyle parent = DefaultSelectionStyle.of(context); |
62 | return DefaultSelectionStyle( |
63 | key: key, |
64 | cursorColor: cursorColor ?? parent.cursorColor, |
65 | selectionColor: selectionColor ?? parent.selectionColor, |
66 | mouseCursor: mouseCursor ?? parent.mouseCursor, |
67 | child: child, |
68 | ); |
69 | }, |
70 | ); |
71 | } |
72 | |
73 | /// The default cursor and selection color (semi-transparent grey). |
74 | /// |
75 | /// This is the color that the [Text] widget uses when the specified selection |
76 | /// color is null. |
77 | static const Color defaultColor = Color(0x80808080); |
78 | |
79 | /// The color of the text field's cursor. |
80 | /// |
81 | /// The cursor indicates the current location of the text insertion point in |
82 | /// the field. |
83 | final Color? cursorColor; |
84 | |
85 | /// The background color of selected text. |
86 | final Color? selectionColor; |
87 | |
88 | /// The [MouseCursor] for mouse pointers hovering over selectable Text widgets. |
89 | /// |
90 | /// If this property is null, [SystemMouseCursors.text] will be used. |
91 | final MouseCursor? mouseCursor; |
92 | |
93 | /// The closest instance of this class that encloses the given context. |
94 | /// |
95 | /// If no such instance exists, returns an instance created by |
96 | /// [DefaultSelectionStyle.fallback], which contains fallback values. |
97 | /// |
98 | /// Typical usage is as follows: |
99 | /// |
100 | /// ```dart |
101 | /// DefaultSelectionStyle style = DefaultSelectionStyle.of(context); |
102 | /// ``` |
103 | static DefaultSelectionStyle of(BuildContext context) { |
104 | return context.dependOnInheritedWidgetOfExactType<DefaultSelectionStyle>() ?? const DefaultSelectionStyle.fallback(); |
105 | } |
106 | |
107 | @override |
108 | Widget wrap(BuildContext context, Widget child) { |
109 | return DefaultSelectionStyle( |
110 | cursorColor: cursorColor, |
111 | selectionColor: selectionColor, |
112 | mouseCursor: mouseCursor, |
113 | child: child |
114 | ); |
115 | } |
116 | |
117 | @override |
118 | bool updateShouldNotify(DefaultSelectionStyle oldWidget) { |
119 | return cursorColor != oldWidget.cursorColor || |
120 | selectionColor != oldWidget.selectionColor || |
121 | mouseCursor != oldWidget.mouseCursor; |
122 | } |
123 | } |
124 | |
125 | class _NullWidget extends StatelessWidget { |
126 | const _NullWidget(); |
127 | |
128 | @override |
129 | Widget build(BuildContext context) { |
130 | throw FlutterError( |
131 | 'A DefaultSelectionStyle constructed with DefaultSelectionStyle.fallback cannot be incorporated into the widget tree, ' |
132 | 'it is meant only to provide a fallback value returned by DefaultSelectionStyle.of() ' |
133 | 'when no enclosing default selection style is present in a BuildContext.' , |
134 | ); |
135 | } |
136 | } |
137 | |