| 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 |