// Copyright 2014 The Flutter 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 Shadow, lerpDouble; import 'package:flutter/foundation.dart'; import 'basic_types.dart'; import 'debug.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. /// /// See also: /// /// * [Canvas.drawShadow], which is a more efficient way to draw shadows. /// * [PhysicalModel], a widget for showing shadows. /// * [kElevationToShadow], for some predefined shadows used in Material /// Design. /// * [Shadow], which is the parent class that lacks [spreadRadius]. @immutable class BoxShadow extends ui.Shadow { /// Creates a box shadow. /// /// By default, the shadow is solid black with zero [offset], [blurRadius], /// and [spreadRadius]. const BoxShadow({ Color color = const Color(0xFF000000), Offset offset = Offset.zero, double blurRadius = 0.0, this.spreadRadius = 0.0, this.blurStyle = BlurStyle.normal, }) : super(color: color, offset: offset, blurRadius: blurRadius); /// The amount the box should be inflated prior to applying the blur. final double spreadRadius; /// The [BlurStyle] to use for this shadow. /// /// Defaults to [BlurStyle.normal]. final BlurStyle blurStyle; /// Create the [Paint] object that corresponds to this shadow description. /// /// The [offset] and [spreadRadius] are not represented in the [Paint] object. /// To honor those as well, the shape should be inflated by [spreadRadius] pixels /// in every direction and then translated by [offset] before being filled using /// this [Paint]. @override Paint toPaint() { final Paint result = Paint() ..color = color ..maskFilter = MaskFilter.blur(blurStyle, blurSigma); assert(() { if (debugDisableShadows) result.maskFilter = null; return true; }()); return result; } /// Returns a new box shadow with its offset, blurRadius, and spreadRadius scaled by the given factor. @override BoxShadow scale(double factor) { return BoxShadow( color: color, offset: offset * factor, blurRadius: blurRadius * factor, spreadRadius: spreadRadius * factor, blurStyle: blurStyle, ); } /// 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. /// /// {@macro dart.ui.shadow.lerp} static BoxShadow? lerp(BoxShadow? a, BoxShadow? b, double t) { assert(t != null); if (a == null && b == null) return null; if (a == null) return b!.scale(t); if (b == null) return a.scale(1.0 - t); return 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)!, blurStyle: a.blurStyle == BlurStyle.normal ? b.blurStyle : a.blurStyle, ); } /// Linearly interpolate between two lists of box shadows. /// /// If the lists differ in length, excess items are lerped with null. /// /// {@macro dart.ui.shadow.lerp} static List<BoxShadow>? lerpList(List<BoxShadow>? a, List<BoxShadow>? b, double t) { assert(t != null); if (a == null && b == null) return null; a ??= <BoxShadow>[]; b ??= <BoxShadow>[]; final int commonLength = math.min(a.length, b.length); return <BoxShadow>[ for (int i = 0; i < commonLength; i += 1) BoxShadow.lerp(a[i], b[i], t)!, for (int i = commonLength; i < a.length; i += 1) a[i].scale(1.0 - t), for (int i = commonLength; i < b.length; i += 1) b[i].scale(t), ]; } @override bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; return other is BoxShadow && other.color == color && other.offset == offset && other.blurRadius == blurRadius && other.spreadRadius == spreadRadius && other.blurStyle == blurStyle; } @override int get hashCode => hashValues(color, offset, blurRadius, spreadRadius, blurStyle); @override String toString() => 'BoxShadow($color, $offset, ${debugFormatDouble(blurRadius)}, ${debugFormatDouble(spreadRadius)}), $blurStyle'; }