diff --git a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart index 2e2faf8daa..e1fb475e0d 100644 --- a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart +++ b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart @@ -57,7 +57,7 @@ class RoundedRectangleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: BorderSide.lerp(a.side, side, t), borderRadius: borderRadius, - circleness: 1.0 - t, + circularity: 1.0 - t, eccentricity: a.eccentricity, ); } @@ -77,7 +77,7 @@ class RoundedRectangleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: BorderSide.lerp(side, b.side, t), borderRadius: borderRadius, - circleness: t, + circularity: t, eccentricity: b.eccentricity, ); } @@ -163,14 +163,14 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { const _RoundedRectangleToCircleBorder({ super.side, this.borderRadius = BorderRadius.zero, - required this.circleness, + required this.circularity, required this.eccentricity, }) : assert(side != null), assert(borderRadius != null), - assert(circleness != null); + assert(circularity != null); final BorderRadiusGeometry borderRadius; - final double circleness; + final double circularity; final double eccentricity; @override @@ -178,7 +178,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: side.scale(t), borderRadius: borderRadius * t, - circleness: t, + circularity: t, eccentricity: eccentricity, ); } @@ -190,7 +190,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: BorderSide.lerp(a.side, side, t), borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, borderRadius, t)!, - circleness: circleness * t, + circularity: circularity * t, eccentricity: eccentricity, ); } @@ -198,7 +198,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: BorderSide.lerp(a.side, side, t), borderRadius: borderRadius, - circleness: circleness + (1.0 - circleness) * (1.0 - t), + circularity: circularity + (1.0 - circularity) * (1.0 - t), eccentricity: a.eccentricity, ); } @@ -206,7 +206,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: BorderSide.lerp(a.side, side, t), borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, borderRadius, t)!, - circleness: ui.lerpDouble(a.circleness, circleness, t)!, + circularity: ui.lerpDouble(a.circularity, circularity, t)!, eccentricity: eccentricity, ); } @@ -219,7 +219,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: BorderSide.lerp(side, b.side, t), borderRadius: BorderRadiusGeometry.lerp(borderRadius, b.borderRadius, t)!, - circleness: circleness * (1.0 - t), + circularity: circularity * (1.0 - t), eccentricity: eccentricity, ); } @@ -227,7 +227,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: BorderSide.lerp(side, b.side, t), borderRadius: borderRadius, - circleness: circleness + (1.0 - circleness) * t, + circularity: circularity + (1.0 - circularity) * t, eccentricity: b.eccentricity, ); } @@ -235,7 +235,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return _RoundedRectangleToCircleBorder( side: BorderSide.lerp(side, b.side, t), borderRadius: BorderRadiusGeometry.lerp(borderRadius, b.borderRadius, t)!, - circleness: ui.lerpDouble(circleness, b.circleness, t)!, + circularity: ui.lerpDouble(circularity, b.circularity, t)!, eccentricity: eccentricity, ); } @@ -243,12 +243,12 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { } Rect _adjustRect(Rect rect) { - if (circleness == 0.0 || rect.width == rect.height) { + if (circularity == 0.0 || rect.width == rect.height) { return rect; } if (rect.width < rect.height) { final double partialDelta = (rect.height - rect.width) / 2; - final double delta = circleness * partialDelta * (1.0 - eccentricity); + final double delta = circularity * partialDelta * (1.0 - eccentricity); return Rect.fromLTRB( rect.left, rect.top + delta, @@ -257,7 +257,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { ); } else { final double partialDelta = (rect.width - rect.height) / 2; - final double delta = circleness * partialDelta * (1.0 - eccentricity); + final double delta = circularity * partialDelta * (1.0 - eccentricity); return Rect.fromLTRB( rect.left + delta, rect.top, @@ -269,7 +269,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { BorderRadius? _adjustBorderRadius(Rect rect, TextDirection? textDirection) { final BorderRadius resolvedRadius = borderRadius.resolve(textDirection); - if (circleness == 0.0) { + if (circularity == 0.0) { return resolvedRadius; } if (eccentricity != 0.0) { @@ -277,17 +277,17 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return BorderRadius.lerp( resolvedRadius, BorderRadius.all(Radius.elliptical(rect.width / 2, (0.5 + eccentricity / 2) * rect.height / 2)), - circleness, + circularity, )!; } else { return BorderRadius.lerp( resolvedRadius, BorderRadius.all(Radius.elliptical((0.5 + eccentricity / 2) * rect.width / 2, rect.height / 2)), - circleness, + circularity, )!; } } - return BorderRadius.lerp(resolvedRadius, BorderRadius.circular(rect.shortestSide / 2), circleness); + return BorderRadius.lerp(resolvedRadius, BorderRadius.circular(rect.shortestSide / 2), circularity); } @override @@ -318,11 +318,11 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { bool get preferPaintInterior => true; @override - _RoundedRectangleToCircleBorder copyWith({ BorderSide? side, BorderRadiusGeometry? borderRadius, double? circleness, double? eccentricity }) { + _RoundedRectangleToCircleBorder copyWith({ BorderSide? side, BorderRadiusGeometry? borderRadius, double? circularity, double? eccentricity }) { return _RoundedRectangleToCircleBorder( side: side ?? this.side, borderRadius: borderRadius ?? this.borderRadius, - circleness: circleness ?? this.circleness, + circularity: circularity ?? this.circularity, eccentricity: eccentricity ?? this.eccentricity, ); } @@ -347,17 +347,17 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { return other is _RoundedRectangleToCircleBorder && other.side == side && other.borderRadius == borderRadius - && other.circleness == circleness; + && other.circularity == circularity; } @override - int get hashCode => Object.hash(side, borderRadius, circleness); + int get hashCode => Object.hash(side, borderRadius, circularity); @override String toString() { if (eccentricity != 0.0) { - return 'RoundedRectangleBorder($side, $borderRadius, ${(circleness * 100).toStringAsFixed(1)}% of the way to being a CircleBorder that is ${(eccentricity * 100).toStringAsFixed(1)}% oval)'; + return 'RoundedRectangleBorder($side, $borderRadius, ${(circularity * 100).toStringAsFixed(1)}% of the way to being a CircleBorder that is ${(eccentricity * 100).toStringAsFixed(1)}% oval)'; } - return 'RoundedRectangleBorder($side, $borderRadius, ${(circleness * 100).toStringAsFixed(1)}% of the way to being a CircleBorder)'; + return 'RoundedRectangleBorder($side, $borderRadius, ${(circularity * 100).toStringAsFixed(1)}% of the way to being a CircleBorder)'; } } diff --git a/packages/flutter/lib/src/painting/stadium_border.dart b/packages/flutter/lib/src/painting/stadium_border.dart index b7a0d7677b..7aa7573ac5 100644 --- a/packages/flutter/lib/src/painting/stadium_border.dart +++ b/packages/flutter/lib/src/painting/stadium_border.dart @@ -41,15 +41,15 @@ class StadiumBorder extends OutlinedBorder { if (a is CircleBorder) { return _StadiumToCircleBorder( side: BorderSide.lerp(a.side, side, t), - circleness: 1.0 - t, + circularity: 1.0 - t, eccentricity: a.eccentricity, ); } if (a is RoundedRectangleBorder) { return _StadiumToRoundedRectangleBorder( side: BorderSide.lerp(a.side, side, t), - borderRadius: a.borderRadius as BorderRadius, - rectness: 1.0 - t, + borderRadius: a.borderRadius, + rectilinearity: 1.0 - t, ); } return super.lerpFrom(a, t); @@ -64,15 +64,15 @@ class StadiumBorder extends OutlinedBorder { if (b is CircleBorder) { return _StadiumToCircleBorder( side: BorderSide.lerp(side, b.side, t), - circleness: t, + circularity: t, eccentricity: b.eccentricity, ); } if (b is RoundedRectangleBorder) { return _StadiumToRoundedRectangleBorder( side: BorderSide.lerp(side, b.side, t), - borderRadius: b.borderRadius as BorderRadius, - rectness: t, + borderRadius: b.borderRadius, + rectilinearity: t, ); } return super.lerpTo(b, t); @@ -142,19 +142,19 @@ class StadiumBorder extends OutlinedBorder { class _StadiumToCircleBorder extends OutlinedBorder { const _StadiumToCircleBorder({ super.side, - this.circleness = 0.0, + this.circularity = 0.0, required this.eccentricity, }) : assert(side != null), - assert(circleness != null); + assert(circularity != null); - final double circleness; + final double circularity; final double eccentricity; @override ShapeBorder scale(double t) { return _StadiumToCircleBorder( side: side.scale(t), - circleness: t, + circularity: t, eccentricity: eccentricity, ); } @@ -165,21 +165,21 @@ class _StadiumToCircleBorder extends OutlinedBorder { if (a is StadiumBorder) { return _StadiumToCircleBorder( side: BorderSide.lerp(a.side, side, t), - circleness: circleness * t, + circularity: circularity * t, eccentricity: eccentricity, ); } if (a is CircleBorder) { return _StadiumToCircleBorder( side: BorderSide.lerp(a.side, side, t), - circleness: circleness + (1.0 - circleness) * (1.0 - t), + circularity: circularity + (1.0 - circularity) * (1.0 - t), eccentricity: a.eccentricity, ); } if (a is _StadiumToCircleBorder) { return _StadiumToCircleBorder( side: BorderSide.lerp(a.side, side, t), - circleness: ui.lerpDouble(a.circleness, circleness, t)!, + circularity: ui.lerpDouble(a.circularity, circularity, t)!, eccentricity: ui.lerpDouble(a.eccentricity, eccentricity, t)!, ); } @@ -192,21 +192,21 @@ class _StadiumToCircleBorder extends OutlinedBorder { if (b is StadiumBorder) { return _StadiumToCircleBorder( side: BorderSide.lerp(side, b.side, t), - circleness: circleness * (1.0 - t), + circularity: circularity * (1.0 - t), eccentricity: eccentricity, ); } if (b is CircleBorder) { return _StadiumToCircleBorder( side: BorderSide.lerp(side, b.side, t), - circleness: circleness + (1.0 - circleness) * t, + circularity: circularity + (1.0 - circularity) * t, eccentricity: b.eccentricity, ); } if (b is _StadiumToCircleBorder) { return _StadiumToCircleBorder( side: BorderSide.lerp(side, b.side, t), - circleness: ui.lerpDouble(circleness, b.circleness, t)!, + circularity: ui.lerpDouble(circularity, b.circularity, t)!, eccentricity: ui.lerpDouble(eccentricity, b.eccentricity, t)!, ); } @@ -214,12 +214,12 @@ class _StadiumToCircleBorder extends OutlinedBorder { } Rect _adjustRect(Rect rect) { - if (circleness == 0.0 || rect.width == rect.height) { + if (circularity == 0.0 || rect.width == rect.height) { return rect; } if (rect.width < rect.height) { final double partialDelta = (rect.height - rect.width) / 2; - final double delta = circleness * partialDelta * (1.0 - eccentricity); + final double delta = circularity * partialDelta * (1.0 - eccentricity); return Rect.fromLTRB( rect.left, rect.top + delta, @@ -228,7 +228,7 @@ class _StadiumToCircleBorder extends OutlinedBorder { ); } else { final double partialDelta = (rect.width - rect.height) / 2; - final double delta = circleness * partialDelta * (1.0 - eccentricity); + final double delta = circularity * partialDelta * (1.0 - eccentricity); return Rect.fromLTRB( rect.left + delta, rect.top, @@ -245,13 +245,13 @@ class _StadiumToCircleBorder extends OutlinedBorder { return BorderRadius.lerp( circleRadius, BorderRadius.all(Radius.elliptical(rect.width / 2, (0.5 + eccentricity / 2) * rect.height / 2)), - circleness, + circularity, )!; } else { return BorderRadius.lerp( circleRadius, BorderRadius.all(Radius.elliptical((0.5 + eccentricity / 2) * rect.width / 2, rect.height / 2)), - circleness, + circularity, )!; } } @@ -279,10 +279,10 @@ class _StadiumToCircleBorder extends OutlinedBorder { bool get preferPaintInterior => true; @override - _StadiumToCircleBorder copyWith({ BorderSide? side, double? circleness, double? eccentricity }) { + _StadiumToCircleBorder copyWith({ BorderSide? side, double? circularity, double? eccentricity }) { return _StadiumToCircleBorder( side: side ?? this.side, - circleness: circleness ?? this.circleness, + circularity: circularity ?? this.circularity, eccentricity: eccentricity ?? this.eccentricity, ); } @@ -305,18 +305,18 @@ class _StadiumToCircleBorder extends OutlinedBorder { } return other is _StadiumToCircleBorder && other.side == side - && other.circleness == circleness; + && other.circularity == circularity; } @override - int get hashCode => Object.hash(side, circleness); + int get hashCode => Object.hash(side, circularity); @override String toString() { if (eccentricity != 0.0) { - return 'StadiumBorder($side, ${(circleness * 100).toStringAsFixed(1)}% of the way to being a CircleBorder that is ${(eccentricity * 100).toStringAsFixed(1)}% oval)'; + return 'StadiumBorder($side, ${(circularity * 100).toStringAsFixed(1)}% of the way to being a CircleBorder that is ${(eccentricity * 100).toStringAsFixed(1)}% oval)'; } - return 'StadiumBorder($side, ${(circleness * 100).toStringAsFixed(1)}% of the way to being a CircleBorder)'; + return 'StadiumBorder($side, ${(circularity * 100).toStringAsFixed(1)}% of the way to being a CircleBorder)'; } } @@ -325,21 +325,21 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { const _StadiumToRoundedRectangleBorder({ super.side, this.borderRadius = BorderRadius.zero, - this.rectness = 0.0, + this.rectilinearity = 0.0, }) : assert(side != null), assert(borderRadius != null), - assert(rectness != null); + assert(rectilinearity != null); - final BorderRadius borderRadius; + final BorderRadiusGeometry borderRadius; - final double rectness; + final double rectilinearity; @override ShapeBorder scale(double t) { return _StadiumToRoundedRectangleBorder( side: side.scale(t), borderRadius: borderRadius * t, - rectness: t, + rectilinearity: t, ); } @@ -350,21 +350,21 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { return _StadiumToRoundedRectangleBorder( side: BorderSide.lerp(a.side, side, t), borderRadius: borderRadius, - rectness: rectness * t, + rectilinearity: rectilinearity * t, ); } if (a is RoundedRectangleBorder) { return _StadiumToRoundedRectangleBorder( side: BorderSide.lerp(a.side, side, t), borderRadius: borderRadius, - rectness: rectness + (1.0 - rectness) * (1.0 - t), + rectilinearity: rectilinearity + (1.0 - rectilinearity) * (1.0 - t), ); } if (a is _StadiumToRoundedRectangleBorder) { return _StadiumToRoundedRectangleBorder( side: BorderSide.lerp(a.side, side, t), - borderRadius: BorderRadius.lerp(a.borderRadius, borderRadius, t)!, - rectness: ui.lerpDouble(a.rectness, rectness, t)!, + borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, borderRadius, t)!, + rectilinearity: ui.lerpDouble(a.rectilinearity, rectilinearity, t)!, ); } return super.lerpFrom(a, t); @@ -377,37 +377,37 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { return _StadiumToRoundedRectangleBorder( side: BorderSide.lerp(side, b.side, t), borderRadius: borderRadius, - rectness: rectness * (1.0 - t), + rectilinearity: rectilinearity * (1.0 - t), ); } if (b is RoundedRectangleBorder) { return _StadiumToRoundedRectangleBorder( side: BorderSide.lerp(side, b.side, t), borderRadius: borderRadius, - rectness: rectness + (1.0 - rectness) * t, + rectilinearity: rectilinearity + (1.0 - rectilinearity) * t, ); } if (b is _StadiumToRoundedRectangleBorder) { return _StadiumToRoundedRectangleBorder( side: BorderSide.lerp(side, b.side, t), - borderRadius: BorderRadius.lerp(borderRadius, b.borderRadius, t)!, - rectness: ui.lerpDouble(rectness, b.rectness, t)!, + borderRadius: BorderRadiusGeometry.lerp(borderRadius, b.borderRadius, t)!, + rectilinearity: ui.lerpDouble(rectilinearity, b.rectilinearity, t)!, ); } return super.lerpTo(b, t); } - BorderRadius _adjustBorderRadius(Rect rect) { - return BorderRadius.lerp( + BorderRadiusGeometry _adjustBorderRadius(Rect rect) { + return BorderRadiusGeometry.lerp( borderRadius, BorderRadius.all(Radius.circular(rect.shortestSide / 2.0)), - 1.0 - rectness, + 1.0 - rectilinearity, )!; } @override Path getInnerPath(Rect rect, { TextDirection? textDirection }) { - final RRect borderRect = _adjustBorderRadius(rect).toRRect(rect); + final RRect borderRect = _adjustBorderRadius(rect).resolve(textDirection).toRRect(rect); final RRect adjustedRect = borderRect.deflate(ui.lerpDouble(side.width, 0, side.strokeAlign)!); return Path() ..addRRect(adjustedRect); @@ -416,16 +416,16 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { @override Path getOuterPath(Rect rect, { TextDirection? textDirection }) { return Path() - ..addRRect(_adjustBorderRadius(rect).toRRect(rect)); + ..addRRect(_adjustBorderRadius(rect).resolve(textDirection).toRRect(rect)); } @override void paintInterior(Canvas canvas, Rect rect, Paint paint, { TextDirection? textDirection }) { - final BorderRadius adjustedBorderRadius = _adjustBorderRadius(rect); + final BorderRadiusGeometry adjustedBorderRadius = _adjustBorderRadius(rect); if (adjustedBorderRadius == BorderRadius.zero) { canvas.drawRect(rect, paint); } else { - canvas.drawRRect(adjustedBorderRadius.toRRect(rect), paint); + canvas.drawRRect(adjustedBorderRadius.resolve(textDirection).toRRect(rect), paint); } } @@ -433,11 +433,11 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { bool get preferPaintInterior => true; @override - _StadiumToRoundedRectangleBorder copyWith({ BorderSide? side, BorderRadius? borderRadius, double? rectness }) { + _StadiumToRoundedRectangleBorder copyWith({ BorderSide? side, BorderRadiusGeometry? borderRadius, double? rectilinearity }) { return _StadiumToRoundedRectangleBorder( side: side ?? this.side, borderRadius: borderRadius ?? this.borderRadius, - rectness: rectness ?? this.rectness, + rectilinearity: rectilinearity ?? this.rectilinearity, ); } @@ -447,7 +447,7 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { case BorderStyle.none: break; case BorderStyle.solid: - final BorderRadius adjustedBorderRadius = _adjustBorderRadius(rect); + final BorderRadiusGeometry adjustedBorderRadius = _adjustBorderRadius(rect); final RRect borderRect = adjustedBorderRadius.resolve(textDirection).toRRect(rect); canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); } @@ -461,16 +461,16 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { return other is _StadiumToRoundedRectangleBorder && other.side == side && other.borderRadius == borderRadius - && other.rectness == rectness; + && other.rectilinearity == rectilinearity; } @override - int get hashCode => Object.hash(side, borderRadius, rectness); + int get hashCode => Object.hash(side, borderRadius, rectilinearity); @override String toString() { return 'StadiumBorder($side, $borderRadius, ' - '${(rectness * 100).toStringAsFixed(1)}% of the way to being a ' + '${(rectilinearity * 100).toStringAsFixed(1)}% of the way to being a ' 'RoundedRectangleBorder)'; } } diff --git a/packages/flutter/test/painting/stadium_border_test.dart b/packages/flutter/test/painting/stadium_border_test.dart index 39028438c5..257aa4a151 100644 --- a/packages/flutter/test/painting/stadium_border_test.dart +++ b/packages/flutter/test/painting/stadium_border_test.dart @@ -137,7 +137,7 @@ void main() { expect(direct50.toString(), indirect50.toString()); }); - test('StadiumBorder and RoundedRectBorder', () { + test('StadiumBorder and RoundedRectBorder with BorderRadius.zero', () { const StadiumBorder stadium = StadiumBorder(); const RoundedRectangleBorder rrect = RoundedRectangleBorder(); const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 50.0); @@ -221,4 +221,184 @@ void main() { expect(direct50.hashCode, indirect50.hashCode); expect(direct50.toString(), indirect50.toString()); }); + + test('StadiumBorder and RoundedRectBorder with circular BorderRadius', () { + const StadiumBorder stadium = StadiumBorder(); + const RoundedRectangleBorder rrect = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))); + const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 50.0); + final Matcher looksLikeS = isPathThat( + includes: const [ + Offset(25.0, 25.0), + Offset(50.0, 25.0), + Offset(7.33, 7.33), + ], + excludes: const [ + Offset(0.001, 0.001), + Offset(99.999, 0.001), + Offset(99.999, 49.999), + Offset(0.001, 49.999), + ], + ); + final Matcher looksLikeR = isPathThat( + includes: const [ + Offset(25.0, 25.0), + Offset(50.0, 25.0), + Offset(7.33, 7.33), + Offset(4.0, 4.0), + Offset(96.0, 4.0), + Offset(96.0, 46.0), + Offset(4.0, 46.0), + ], + ); + expect(stadium.getOuterPath(rect), looksLikeS); + expect(rrect.getOuterPath(rect), looksLikeR); + expect(ShapeBorder.lerp(stadium, rrect, 0.1)!.getOuterPath(rect), looksLikeS); + expect(ShapeBorder.lerp(stadium, rrect, 0.9)!.getOuterPath(rect), looksLikeR); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), stadium, 0.1)!.getOuterPath(rect), looksLikeR); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), stadium, 0.9)!.getOuterPath(rect), looksLikeS); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), rrect, 0.1)!.getOuterPath(rect), looksLikeS); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), rrect, 0.9)!.getOuterPath(rect), looksLikeS); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.1)!.getOuterPath(rect), looksLikeS); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.9)!.getOuterPath(rect), looksLikeR); + expect(ShapeBorder.lerp(stadium, ShapeBorder.lerp(stadium, rrect, 0.9), 0.1)!.getOuterPath(rect), looksLikeS); + expect(ShapeBorder.lerp(stadium, ShapeBorder.lerp(stadium, rrect, 0.9), 0.9)!.getOuterPath(rect), looksLikeR); + expect(ShapeBorder.lerp(rrect, ShapeBorder.lerp(stadium, rrect, 0.1), 0.1)!.getOuterPath(rect), looksLikeS); + expect(ShapeBorder.lerp(rrect, ShapeBorder.lerp(stadium, rrect, 0.1), 0.9)!.getOuterPath(rect), looksLikeS); + + expect( + ShapeBorder.lerp(stadium, rrect, 0.1).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadius.circular(10.0), 10.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(stadium, rrect, 0.2).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadius.circular(10.0), 20.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.9).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadius.circular(10.0), 82.0% of the way to being a RoundedRectangleBorder)', + ); + + expect( + ShapeBorder.lerp(rrect, stadium, 0.9).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadius.circular(10.0), 10.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(rrect, stadium, 0.8).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadius.circular(10.0), 20.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), ShapeBorder.lerp(stadium, rrect, 0.1), 0.1).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadius.circular(10.0), 82.0% of the way to being a RoundedRectangleBorder)', + ); + + expect(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.1)); + expect(ShapeBorder.lerp(stadium, rrect, 0.1).hashCode, ShapeBorder.lerp(stadium, rrect, 0.1).hashCode); + + final ShapeBorder direct50 = ShapeBorder.lerp(stadium, rrect, 0.5)!; + final ShapeBorder indirect50 = ShapeBorder.lerp(ShapeBorder.lerp(rrect, stadium, 0.1), ShapeBorder.lerp(rrect, stadium, 0.9), 0.5)!; + expect(direct50, indirect50); + expect(direct50.hashCode, indirect50.hashCode); + expect(direct50.toString(), indirect50.toString()); + }); + + test('StadiumBorder and RoundedRectBorder with BorderRadiusDirectional', () { + const StadiumBorder stadium = StadiumBorder(); + const RoundedRectangleBorder rrect = RoundedRectangleBorder( + borderRadius: BorderRadiusDirectional.only( + topStart: Radius.circular(10), + bottomEnd: Radius.circular(10), + ), + ); + const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 50.0); + final Matcher looksLikeS = isPathThat( + includes: const [ + Offset(25.0, 25.0), + Offset(50.0, 25.0), + Offset(7.33, 7.33), + ], + excludes: const [ + Offset(0.001, 0.001), + Offset(99.999, 0.001), + Offset(99.999, 49.999), + Offset(0.001, 49.999), + ], + ); + final Matcher looksLikeR = isPathThat( + includes: const [ + Offset(25.0, 25.0), + Offset(50.0, 25.0), + Offset(7.33, 7.33), + Offset(4.0, 4.0), + Offset(96.0, 4.0), + Offset(96.0, 46.0), + Offset(4.0, 46.0), + ], + ); + expect(stadium.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + expect(rrect.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeR); + expect(ShapeBorder.lerp(stadium, rrect, 0.1)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + expect(ShapeBorder.lerp(stadium, rrect, 0.9)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeR); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), stadium, 0.1)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeR); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), stadium, 0.9)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), rrect, 0.1)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), rrect, 0.9)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.1)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + expect(ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.9)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeR); + expect(ShapeBorder.lerp(stadium, ShapeBorder.lerp(stadium, rrect, 0.9), 0.1)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + expect(ShapeBorder.lerp(stadium, ShapeBorder.lerp(stadium, rrect, 0.9), 0.9)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeR); + expect(ShapeBorder.lerp(rrect, ShapeBorder.lerp(stadium, rrect, 0.1), 0.1)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + expect(ShapeBorder.lerp(rrect, ShapeBorder.lerp(stadium, rrect, 0.1), 0.9)!.getOuterPath(rect, textDirection: TextDirection.rtl), looksLikeS); + + expect( + ShapeBorder.lerp(stadium, rrect, 0.1).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadiusDirectional.only(topStart: Radius.circular(10.0), ' + 'bottomEnd: Radius.circular(10.0)), 10.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(stadium, rrect, 0.2).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadiusDirectional.only(topStart: Radius.circular(10.0), ' + 'bottomEnd: Radius.circular(10.0)), 20.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.9).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadiusDirectional.only(topStart: Radius.circular(10.0), ' + 'bottomEnd: Radius.circular(10.0)), 82.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(rrect, stadium, 0.9).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadiusDirectional.only(topStart: Radius.circular(10.0), ' + 'bottomEnd: Radius.circular(10.0)), 10.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(rrect, stadium, 0.8).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadiusDirectional.only(topStart: Radius.circular(10.0), ' + 'bottomEnd: Radius.circular(10.0)), 20.0% of the way to being a RoundedRectangleBorder)', + ); + expect( + ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), ShapeBorder.lerp(stadium, rrect, 0.1), 0.1).toString(), + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' + 'BorderRadiusDirectional.only(topStart: Radius.circular(10.0), ' + 'bottomEnd: Radius.circular(10.0)), 82.0% of the way to being a RoundedRectangleBorder)', + ); + + expect(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.1)); + expect(ShapeBorder.lerp(stadium, rrect, 0.1).hashCode, ShapeBorder.lerp(stadium, rrect, 0.1).hashCode); + + final ShapeBorder direct50 = ShapeBorder.lerp(stadium, rrect, 0.5)!; + final ShapeBorder indirect50 = ShapeBorder.lerp(ShapeBorder.lerp(rrect, stadium, 0.1), ShapeBorder.lerp(rrect, stadium, 0.9), 0.5)!; + expect(direct50, indirect50); + expect(direct50.hashCode, indirect50.hashCode); + expect(direct50.toString(), indirect50.toString()); + }); }