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 'dart:ui' as ui show lerpDouble; |
6 | |
7 | import 'package:flutter/foundation.dart'; |
8 | import 'package:flutter/painting.dart'; |
9 | |
10 | import 'framework.dart' show BuildContext; |
11 | |
12 | /// Defines the size, font variations, color, opacity, and shadows of icons. |
13 | /// |
14 | /// Used by [IconTheme] to control those properties in a widget subtree. |
15 | /// |
16 | /// To obtain the current icon theme, use [IconTheme.of]. To convert an icon |
17 | /// theme to a version with all the fields filled in, use |
18 | /// [IconThemeData.fallback]. |
19 | @immutable |
20 | class IconThemeData with Diagnosticable { |
21 | /// Creates an icon theme data. |
22 | /// |
23 | /// The opacity applies to both explicit and default icon colors. The value |
24 | /// is clamped between 0.0 and 1.0. |
25 | const IconThemeData({ |
26 | this.size, |
27 | this.fill, |
28 | this.weight, |
29 | this.grade, |
30 | this.opticalSize, |
31 | this.color, |
32 | double? opacity, |
33 | this.shadows, |
34 | this.applyTextScaling, |
35 | }) : _opacity = opacity, |
36 | assert(fill == null || (0.0 <= fill && fill <= 1.0)), |
37 | assert(weight == null || (0.0 < weight)), |
38 | assert(opticalSize == null || (0.0 < opticalSize)); |
39 | |
40 | /// Creates an icon theme with some reasonable default values. |
41 | /// |
42 | /// The [size] is 24.0, [fill] is 0.0, [weight] is 400.0, [grade] is 0.0, |
43 | /// opticalSize is 48.0, [color] is black, and [opacity] is 1.0. |
44 | const IconThemeData.fallback() |
45 | : size = 24.0, |
46 | fill = 0.0, |
47 | weight = 400.0, |
48 | grade = 0.0, |
49 | opticalSize = 48.0, |
50 | color = const Color(0xFF000000), |
51 | _opacity = 1.0, |
52 | shadows = null, |
53 | applyTextScaling = false; |
54 | |
55 | /// Creates a copy of this icon theme but with the given fields replaced with |
56 | /// the new values. |
57 | IconThemeData copyWith({ |
58 | double? size, |
59 | double? fill, |
60 | double? weight, |
61 | double? grade, |
62 | double? opticalSize, |
63 | Color? color, |
64 | double? opacity, |
65 | List<Shadow>? shadows, |
66 | bool? applyTextScaling, |
67 | }) { |
68 | return IconThemeData( |
69 | size: size ?? this.size, |
70 | fill: fill ?? this.fill, |
71 | weight: weight ?? this.weight, |
72 | grade: grade ?? this.grade, |
73 | opticalSize: opticalSize ?? this.opticalSize, |
74 | color: color ?? this.color, |
75 | opacity: opacity ?? this.opacity, |
76 | shadows: shadows ?? this.shadows, |
77 | applyTextScaling: applyTextScaling ?? this.applyTextScaling, |
78 | ); |
79 | } |
80 | |
81 | /// Returns a new icon theme that matches this icon theme but with some values |
82 | /// replaced by the non-null parameters of the given icon theme. If the given |
83 | /// icon theme is null, returns this icon theme. |
84 | IconThemeData merge(IconThemeData? other) { |
85 | if (other == null) { |
86 | return this; |
87 | } |
88 | return copyWith( |
89 | size: other.size, |
90 | fill: other.fill, |
91 | weight: other.weight, |
92 | grade: other.grade, |
93 | opticalSize: other.opticalSize, |
94 | color: other.color, |
95 | opacity: other.opacity, |
96 | shadows: other.shadows, |
97 | applyTextScaling: other.applyTextScaling, |
98 | ); |
99 | } |
100 | |
101 | /// Called by [IconTheme.of] to convert this instance to an [IconThemeData] |
102 | /// that fits the given [BuildContext]. |
103 | /// |
104 | /// This method gives the ambient [IconThemeData] a chance to update itself, |
105 | /// after it's been retrieved by [IconTheme.of], and before being returned as |
106 | /// the final result. For instance, [CupertinoIconThemeData] overrides this method |
107 | /// to resolve [color], in case [color] is a [CupertinoDynamicColor] and needs |
108 | /// to be resolved against the given [BuildContext] before it can be used as a |
109 | /// regular [Color]. |
110 | /// |
111 | /// The default implementation returns this [IconThemeData] as-is. |
112 | /// |
113 | /// See also: |
114 | /// |
115 | /// * [CupertinoIconThemeData.resolve] an implementation that resolves |
116 | /// the color of [CupertinoIconThemeData] before returning. |
117 | IconThemeData resolve(BuildContext context) => this; |
118 | |
119 | /// Whether all the properties (except shadows) of this object are non-null. |
120 | bool get isConcrete => size != null |
121 | && fill != null |
122 | && weight != null |
123 | && grade != null |
124 | && opticalSize != null |
125 | && color != null |
126 | && opacity != null |
127 | && applyTextScaling != null; |
128 | |
129 | /// The default for [Icon.size]. |
130 | /// |
131 | /// Falls back to 24.0. |
132 | final double? size; |
133 | |
134 | /// The default for [Icon.fill]. |
135 | /// |
136 | /// Falls back to 0.0. |
137 | final double? fill; |
138 | |
139 | /// The default for [Icon.weight]. |
140 | /// |
141 | /// Falls back to 400.0. |
142 | final double? weight; |
143 | |
144 | /// The default for [Icon.grade]. |
145 | /// |
146 | /// Falls back to 0.0. |
147 | final double? grade; |
148 | |
149 | /// The default for [Icon.opticalSize]. |
150 | /// |
151 | /// Falls back to 48.0. |
152 | final double? opticalSize; |
153 | |
154 | /// The default for [Icon.color]. |
155 | /// |
156 | /// In material apps, if there is a [Theme] without any [IconTheme]s |
157 | /// specified, icon colors default to white if [ThemeData.brightness] is dark |
158 | /// and black if [ThemeData.brightness] is light. |
159 | /// |
160 | /// Otherwise, falls back to black. |
161 | final Color? color; |
162 | |
163 | /// An opacity to apply to both explicit and default icon colors. |
164 | /// |
165 | /// Falls back to 1.0. |
166 | double? get opacity => _opacity == null ? null : clampDouble(_opacity, 0.0, 1.0); |
167 | final double? _opacity; |
168 | |
169 | /// The default for [Icon.shadows]. |
170 | final List<Shadow>? shadows; |
171 | |
172 | /// The default for [Icon.applyTextScaling]. |
173 | final bool? applyTextScaling; |
174 | |
175 | /// Linearly interpolate between two icon theme data objects. |
176 | /// |
177 | /// {@macro dart.ui.shadow.lerp} |
178 | static IconThemeData lerp(IconThemeData? a, IconThemeData? b, double t) { |
179 | if (identical(a, b) && a != null) { |
180 | return a; |
181 | } |
182 | return IconThemeData( |
183 | size: ui.lerpDouble(a?.size, b?.size, t), |
184 | fill: ui.lerpDouble(a?.fill, b?.fill, t), |
185 | weight: ui.lerpDouble(a?.weight, b?.weight, t), |
186 | grade: ui.lerpDouble(a?.grade, b?.grade, t), |
187 | opticalSize: ui.lerpDouble(a?.opticalSize, b?.opticalSize, t), |
188 | color: Color.lerp(a?.color, b?.color, t), |
189 | opacity: ui.lerpDouble(a?.opacity, b?.opacity, t), |
190 | shadows: Shadow.lerpList(a?.shadows, b?.shadows, t), |
191 | applyTextScaling: t < 0.5 ? a?.applyTextScaling : b?.applyTextScaling, |
192 | ); |
193 | } |
194 | |
195 | @override |
196 | bool operator ==(Object other) { |
197 | if (other.runtimeType != runtimeType) { |
198 | return false; |
199 | } |
200 | return other is IconThemeData |
201 | && other.size == size |
202 | && other.fill == fill |
203 | && other.weight == weight |
204 | && other.grade == grade |
205 | && other.opticalSize == opticalSize |
206 | && other.color == color |
207 | && other.opacity == opacity |
208 | && listEquals(other.shadows, shadows) |
209 | && other.applyTextScaling == applyTextScaling; |
210 | } |
211 | |
212 | @override |
213 | int get hashCode => Object.hash( |
214 | size, |
215 | fill, |
216 | weight, |
217 | grade, |
218 | opticalSize, |
219 | color, |
220 | opacity, |
221 | shadows == null ? null : Object.hashAll(shadows!), |
222 | applyTextScaling, |
223 | ); |
224 | |
225 | @override |
226 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
227 | super.debugFillProperties(properties); |
228 | properties.add(DoubleProperty('size' , size, defaultValue: null)); |
229 | properties.add(DoubleProperty('fill' , fill, defaultValue: null)); |
230 | properties.add(DoubleProperty('weight' , weight, defaultValue: null)); |
231 | properties.add(DoubleProperty('grade' , grade, defaultValue: null)); |
232 | properties.add(DoubleProperty('opticalSize' , opticalSize, defaultValue: null)); |
233 | properties.add(ColorProperty('color' , color, defaultValue: null)); |
234 | properties.add(DoubleProperty('opacity' , opacity, defaultValue: null)); |
235 | properties.add(IterableProperty<Shadow>('shadows' , shadows, defaultValue: null)); |
236 | properties.add(DiagnosticsProperty<bool>('applyTextScaling' , applyTextScaling, defaultValue: null)); |
237 | } |
238 | } |
239 | |