diff --git a/packages/flutter/lib/painting.dart b/packages/flutter/lib/painting.dart index d51fd1a54da..506279c2bf9 100644 --- a/packages/flutter/lib/painting.dart +++ b/packages/flutter/lib/painting.dart @@ -22,6 +22,7 @@ export 'src/painting/border.dart'; export 'src/painting/border_radius.dart'; export 'src/painting/box_fit.dart'; export 'src/painting/box_painter.dart'; +export 'src/painting/box_shadow.dart'; export 'src/painting/colors.dart'; export 'src/painting/decoration.dart'; export 'src/painting/edge_insets.dart'; diff --git a/packages/flutter/lib/src/painting/box_painter.dart b/packages/flutter/lib/src/painting/box_painter.dart index 5c7cc31e105..cbfa46f97e4 100644 --- a/packages/flutter/lib/src/painting/box_painter.dart +++ b/packages/flutter/lib/src/painting/box_painter.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'dart:math' as math; -import 'dart:ui' as ui show Image, lerpDouble; +import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -11,126 +11,12 @@ import 'package:flutter/services.dart'; import 'basic_types.dart'; import 'border.dart'; import 'border_radius.dart'; +import 'box_shadow.dart'; import 'decoration.dart'; import 'edge_insets.dart'; import 'gradient.dart'; import 'image.dart'; -/// A shadow cast by a box. -/// -/// BoxShadow can cast non-rectangular shadows if the box is non-rectangular -/// (e.g., has a border radius or a circular shape). -/// -/// This class is similar to CSS box-shadow. -@immutable -class BoxShadow { - /// Creates a box shadow. - /// - /// By default, the shadow is solid black with zero [offset], [blurRadius], - /// and [spreadRadius]. - const BoxShadow({ - this.color: const Color(0xFF000000), - this.offset: Offset.zero, - this.blurRadius: 0.0, - this.spreadRadius: 0.0 - }); - - /// The color of the shadow. - final Color color; - - /// The displacement of the shadow from the box. - final Offset offset; - - /// The standard deviation of the Gaussian to convolve with the box's shape. - final double blurRadius; - - /// The amount the box should be inflated prior to applying the blur. - final double spreadRadius; - - /// Converts a blur radius in pixels to sigmas. - /// - /// See the sigma argument to [MaskFilter.blur]. - // - // See SkBlurMask::ConvertRadiusToSigma(). - // - static double convertRadiusToSigma(double radius) { - return radius * 0.57735 + 0.5; - } - - /// The [blurRadius] in sigmas instead of logical pixels. - /// - /// See the sigma argument to [MaskFilter.blur]. - double get blurSigma => convertRadiusToSigma(blurRadius); - - /// Returns a new box shadow with its offset, blurRadius, and spreadRadius scaled by the given factor. - BoxShadow scale(double factor) { - return new BoxShadow( - color: color, - offset: offset * factor, - blurRadius: blurRadius * factor, - spreadRadius: spreadRadius * factor - ); - } - - /// Linearly interpolate between two box shadows. - /// - /// If either box shadow is null, this function linearly interpolates from a - /// a box shadow that matches the other box shadow in color but has a zero - /// offset and a zero blurRadius. - static BoxShadow lerp(BoxShadow a, BoxShadow b, double t) { - if (a == null && b == null) - return null; - if (a == null) - return b.scale(t); - if (b == null) - return a.scale(1.0 - t); - return new BoxShadow( - color: Color.lerp(a.color, b.color, t), - offset: Offset.lerp(a.offset, b.offset, t), - blurRadius: ui.lerpDouble(a.blurRadius, b.blurRadius, t), - spreadRadius: ui.lerpDouble(a.spreadRadius, b.spreadRadius, t) - ); - } - - /// Linearly interpolate between two lists of box shadows. - /// - /// If the lists differ in length, excess items are lerped with null. - static List lerpList(List a, List b, double t) { - if (a == null && b == null) - return null; - a ??= []; - b ??= []; - final List result = []; - final int commonLength = math.min(a.length, b.length); - for (int i = 0; i < commonLength; ++i) - result.add(BoxShadow.lerp(a[i], b[i], t)); - for (int i = commonLength; i < a.length; ++i) - result.add(a[i].scale(1.0 - t)); - for (int i = commonLength; i < b.length; ++i) - result.add(b[i].scale(t)); - return result; - } - - @override - bool operator ==(dynamic other) { - if (identical(this, other)) - return true; - if (runtimeType != other.runtimeType) - return false; - final BoxShadow typedOther = other; - return color == typedOther.color && - offset == typedOther.offset && - blurRadius == typedOther.blurRadius && - spreadRadius == typedOther.spreadRadius; - } - - @override - int get hashCode => hashValues(color, offset, blurRadius, spreadRadius); - - @override - String toString() => 'BoxShadow($color, $offset, $blurRadius, $spreadRadius)'; -} - /// An immutable description of how to paint a box. /// /// The [BoxDecoration] class provides a variety of ways to draw a box. diff --git a/packages/flutter/lib/src/painting/box_shadow.dart b/packages/flutter/lib/src/painting/box_shadow.dart new file mode 100644 index 00000000000..28b8baaf9eb --- /dev/null +++ b/packages/flutter/lib/src/painting/box_shadow.dart @@ -0,0 +1,125 @@ +// Copyright 2015 The Chromium 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 'dart:math' as math; +import 'dart:ui' as ui show lerpDouble; + +import 'package:flutter/foundation.dart'; + +import 'basic_types.dart'; + +/// A shadow cast by a box. +/// +/// BoxShadow can cast non-rectangular shadows if the box is non-rectangular +/// (e.g., has a border radius or a circular shape). +/// +/// This class is similar to CSS box-shadow. +@immutable +class BoxShadow { + /// Creates a box shadow. + /// + /// By default, the shadow is solid black with zero [offset], [blurRadius], + /// and [spreadRadius]. + const BoxShadow({ + this.color: const Color(0xFF000000), + this.offset: Offset.zero, + this.blurRadius: 0.0, + this.spreadRadius: 0.0 + }); + + /// The color of the shadow. + final Color color; + + /// The displacement of the shadow from the box. + final Offset offset; + + /// The standard deviation of the Gaussian to convolve with the box's shape. + final double blurRadius; + + /// The amount the box should be inflated prior to applying the blur. + final double spreadRadius; + + /// Converts a blur radius in pixels to sigmas. + /// + /// See the sigma argument to [MaskFilter.blur]. + // + // See SkBlurMask::ConvertRadiusToSigma(). + // + static double convertRadiusToSigma(double radius) { + return radius * 0.57735 + 0.5; + } + + /// The [blurRadius] in sigmas instead of logical pixels. + /// + /// See the sigma argument to [MaskFilter.blur]. + double get blurSigma => convertRadiusToSigma(blurRadius); + + /// Returns a new box shadow with its offset, blurRadius, and spreadRadius scaled by the given factor. + BoxShadow scale(double factor) { + return new BoxShadow( + color: color, + offset: offset * factor, + blurRadius: blurRadius * factor, + spreadRadius: spreadRadius * factor + ); + } + + /// Linearly interpolate between two box shadows. + /// + /// If either box shadow is null, this function linearly interpolates from a + /// a box shadow that matches the other box shadow in color but has a zero + /// offset and a zero blurRadius. + static BoxShadow lerp(BoxShadow a, BoxShadow b, double t) { + if (a == null && b == null) + return null; + if (a == null) + return b.scale(t); + if (b == null) + return a.scale(1.0 - t); + return new BoxShadow( + color: Color.lerp(a.color, b.color, t), + offset: Offset.lerp(a.offset, b.offset, t), + blurRadius: ui.lerpDouble(a.blurRadius, b.blurRadius, t), + spreadRadius: ui.lerpDouble(a.spreadRadius, b.spreadRadius, t) + ); + } + + /// Linearly interpolate between two lists of box shadows. + /// + /// If the lists differ in length, excess items are lerped with null. + static List lerpList(List a, List b, double t) { + if (a == null && b == null) + return null; + a ??= []; + b ??= []; + final List result = []; + final int commonLength = math.min(a.length, b.length); + for (int i = 0; i < commonLength; ++i) + result.add(BoxShadow.lerp(a[i], b[i], t)); + for (int i = commonLength; i < a.length; ++i) + result.add(a[i].scale(1.0 - t)); + for (int i = commonLength; i < b.length; ++i) + result.add(b[i].scale(t)); + return result; + } + + @override + bool operator ==(dynamic other) { + if (identical(this, other)) + return true; + if (runtimeType != other.runtimeType) + return false; + final BoxShadow typedOther = other; + return color == typedOther.color && + offset == typedOther.offset && + blurRadius == typedOther.blurRadius && + spreadRadius == typedOther.spreadRadius; + } + + @override + int get hashCode => hashValues(color, offset, blurRadius, spreadRadius); + + @override + String toString() => 'BoxShadow($color, $offset, $blurRadius, $spreadRadius)'; +}