OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium 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:math' as math; | |
6 import 'dart:sky' as sky; | |
7 import 'dart:sky' show Point, Size, Rect, Color, Paint, Path; | |
8 import 'shadows.dart'; | |
9 | |
10 class BorderSide { | |
11 const BorderSide({ | |
12 this.color: const Color(0xFF000000), | |
13 this.width: 1.0 | |
14 }); | |
15 final Color color; | |
16 final double width; | |
17 | |
18 static const none = const BorderSide(width: 0.0); | |
19 | |
20 int get hashCode { | |
21 int value = 373; | |
22 value = 37 * value * color.hashCode; | |
23 value = 37 * value * width.hashCode; | |
24 return value; | |
25 } | |
26 String toString() => 'BorderSide($color, $width)'; | |
27 } | |
28 | |
29 class Border { | |
30 const Border({ | |
31 this.top: BorderSide.none, | |
32 this.right: BorderSide.none, | |
33 this.bottom: BorderSide.none, | |
34 this.left: BorderSide.none | |
35 }); | |
36 | |
37 const Border.all(BorderSide side) : | |
38 top = side, | |
39 right = side, | |
40 bottom = side, | |
41 left = side; | |
42 | |
43 final BorderSide top; | |
44 final BorderSide right; | |
45 final BorderSide bottom; | |
46 final BorderSide left; | |
47 | |
48 int get hashCode { | |
49 int value = 373; | |
50 value = 37 * value * top.hashCode; | |
51 value = 37 * value * right.hashCode; | |
52 value = 37 * value * bottom.hashCode; | |
53 value = 37 * value * left.hashCode; | |
54 return value; | |
55 } | |
56 String toString() => 'Border($top, $right, $bottom, $left)'; | |
57 } | |
58 | |
59 class BoxShadow { | |
60 const BoxShadow({ | |
61 this.color, | |
62 this.offset, | |
63 this.blur | |
64 }); | |
65 | |
66 final Color color; | |
67 final Size offset; | |
68 final double blur; | |
69 | |
70 String toString() => 'BoxShadow($color, $offset, $blur)'; | |
71 } | |
72 | |
73 abstract class Gradient { | |
74 sky.Shader createShader(); | |
75 } | |
76 | |
77 class LinearGradient extends Gradient { | |
78 LinearGradient({ | |
79 this.endPoints, | |
80 this.colors, | |
81 this.colorStops, | |
82 this.tileMode: sky.TileMode.clamp | |
83 }); | |
84 | |
85 String toString() => | |
86 'LinearGradient($endPoints, $colors, $colorStops, $tileMode)'; | |
87 | |
88 sky.Shader createShader() { | |
89 return new sky.Gradient.linear(this.endPoints, this.colors, this.colorStops, | |
90 this.tileMode); | |
91 } | |
92 | |
93 final List<Point> endPoints; | |
94 final List<Color> colors; | |
95 final List<double> colorStops; | |
96 final sky.TileMode tileMode; | |
97 } | |
98 | |
99 class RadialGradient extends Gradient { | |
100 RadialGradient({ | |
101 this.center, | |
102 this.radius, | |
103 this.colors, | |
104 this.colorStops, | |
105 this.tileMode: sky.TileMode.clamp | |
106 }); | |
107 | |
108 String toString() => | |
109 'RadialGradient($center, $radius, $colors, $colorStops, $tileMode)'; | |
110 | |
111 sky.Shader createShader() { | |
112 return new sky.Gradient.radial(this.center, this.radius, this.colors, | |
113 this.colorStops, this.tileMode); | |
114 } | |
115 | |
116 final Point center; | |
117 final double radius; | |
118 final List<Color> colors; | |
119 final List<double> colorStops; | |
120 final sky.TileMode tileMode; | |
121 } | |
122 | |
123 enum Shape { rectangle, circle } | |
124 | |
125 // This must be immutable, because we won't notice when it changes | |
126 class BoxDecoration { | |
127 const BoxDecoration({ | |
128 this.backgroundColor, // null = don't draw background | |
129 this.border, // null = don't draw border | |
130 this.borderRadius, // null = use more efficient background drawing; note tha
t this must be null for circles | |
131 this.boxShadow, // null = don't draw shadows | |
132 this.gradient, // null = don't allocate gradient objects | |
133 this.shape: Shape.rectangle | |
134 }); | |
135 | |
136 final Color backgroundColor; | |
137 final double borderRadius; | |
138 final Border border; | |
139 final List<BoxShadow> boxShadow; | |
140 final Gradient gradient; | |
141 final Shape shape; | |
142 | |
143 String toString([String prefix = '']) { | |
144 List<String> result = []; | |
145 if (backgroundColor != null) | |
146 result.add('${prefix}backgroundColor: $backgroundColor'); | |
147 if (border != null) | |
148 result.add('${prefix}border: $border'); | |
149 if (borderRadius != null) | |
150 result.add('${prefix}borderRadius: $borderRadius'); | |
151 if (boxShadow != null) | |
152 result.add('${prefix}boxShadow: ${boxShadow.map((shadow) => shadow.toStrin
g())}'); | |
153 if (gradient != null) | |
154 result.add('${prefix}gradient: $gradient'); | |
155 if (shape != Shape.rectangle) | |
156 result.add('${prefix}shape: $shape'); | |
157 if (result.isEmpty) | |
158 return '${prefix}<no decorations specified>'; | |
159 return result.join('\n'); | |
160 } | |
161 } | |
162 | |
163 class BoxPainter { | |
164 BoxPainter(BoxDecoration decoration) : _decoration = decoration { | |
165 assert(decoration != null); | |
166 } | |
167 | |
168 BoxDecoration _decoration; | |
169 BoxDecoration get decoration => _decoration; | |
170 void set decoration (BoxDecoration value) { | |
171 assert(value != null); | |
172 if (value == _decoration) | |
173 return; | |
174 _decoration = value; | |
175 _cachedBackgroundPaint = null; | |
176 } | |
177 | |
178 Paint _cachedBackgroundPaint; | |
179 Paint get _backgroundPaint { | |
180 if (_cachedBackgroundPaint == null) { | |
181 Paint paint = new Paint(); | |
182 | |
183 if (_decoration.backgroundColor != null) | |
184 paint.color = _decoration.backgroundColor; | |
185 | |
186 if (_decoration.boxShadow != null) { | |
187 var builder = new ShadowDrawLooperBuilder(); | |
188 for (BoxShadow boxShadow in _decoration.boxShadow) | |
189 builder.addShadow(boxShadow.offset, boxShadow.color, boxShadow.blur); | |
190 paint.setDrawLooper(builder.build()); | |
191 } | |
192 | |
193 if (_decoration.gradient != null) | |
194 paint.setShader(_decoration.gradient.createShader()); | |
195 | |
196 _cachedBackgroundPaint = paint; | |
197 } | |
198 | |
199 return _cachedBackgroundPaint; | |
200 } | |
201 | |
202 void paint(sky.Canvas canvas, Rect rect) { | |
203 if (_decoration.backgroundColor != null || _decoration.boxShadow != null || | |
204 _decoration.gradient != null) { | |
205 switch (_decoration.shape) { | |
206 case Shape.circle: | |
207 assert(_decoration.borderRadius == null); | |
208 Point center = rect.center; | |
209 Size size = rect.size; | |
210 double radius = math.min(size.width, size.height) / 2.0; | |
211 canvas.drawCircle(center.x, center.y, radius, _backgroundPaint); | |
212 break; | |
213 case Shape.rectangle: | |
214 if (_decoration.borderRadius == null) | |
215 canvas.drawRect(rect, _backgroundPaint); | |
216 else | |
217 canvas.drawRRect(new sky.RRect()..setRectXY(rect, _decoration.border
Radius, _decoration.borderRadius), _backgroundPaint); | |
218 break; | |
219 } | |
220 } | |
221 | |
222 if (_decoration.border != null) { | |
223 assert(_decoration.borderRadius == null); // TODO(abarth): Implement borde
rs with border radius. | |
224 assert(_decoration.shape == Shape.rectangle); // TODO(ianh): Implement bor
ders on circles. | |
225 | |
226 assert(_decoration.border.top != null); | |
227 assert(_decoration.border.right != null); | |
228 assert(_decoration.border.bottom != null); | |
229 assert(_decoration.border.left != null); | |
230 | |
231 Paint paint = new Paint(); | |
232 Path path; | |
233 | |
234 paint.color = _decoration.border.top.color; | |
235 path = new Path(); | |
236 path.moveTo(rect.left, rect.top); | |
237 path.lineTo(rect.left + _decoration.border.left.width, rect.top + _decorat
ion.border.top.width); | |
238 path.lineTo(rect.right - _decoration.border.right.width, rect.top + _decor
ation.border.top.width); | |
239 path.lineTo(rect.right, rect.top); | |
240 path.close(); | |
241 canvas.drawPath(path, paint); | |
242 | |
243 paint.color = _decoration.border.right.color; | |
244 path = new Path(); | |
245 path.moveTo(rect.right, rect.top); | |
246 path.lineTo(rect.right - _decoration.border.right.width, rect.top + _decor
ation.border.top.width); | |
247 path.lineTo(rect.right - _decoration.border.right.width, rect.bottom - _de
coration.border.bottom.width); | |
248 path.lineTo(rect.right, rect.bottom); | |
249 path.close(); | |
250 canvas.drawPath(path, paint); | |
251 | |
252 paint.color = _decoration.border.bottom.color; | |
253 path = new Path(); | |
254 path.moveTo(rect.right, rect.bottom); | |
255 path.lineTo(rect.right - _decoration.border.right.width, rect.bottom - _de
coration.border.bottom.width); | |
256 path.lineTo(rect.left + _decoration.border.left.width, rect.bottom - _deco
ration.border.bottom.width); | |
257 path.lineTo(rect.left, rect.bottom); | |
258 path.close(); | |
259 canvas.drawPath(path, paint); | |
260 | |
261 paint.color = _decoration.border.left.color; | |
262 path = new Path(); | |
263 path.moveTo(rect.left, rect.bottom); | |
264 path.lineTo(rect.left + _decoration.border.left.width, rect.bottom - _deco
ration.border.bottom.width); | |
265 path.lineTo(rect.left + _decoration.border.left.width, rect.top + _decorat
ion.border.top.width); | |
266 path.lineTo(rect.left, rect.top); | |
267 path.close(); | |
268 canvas.drawPath(path, paint); | |
269 } | |
270 } | |
271 } | |
OLD | NEW |