Unverified Commit 370fc483 authored by Casey Hillers's avatar Casey Hillers Committed by GitHub

Revert "Refactor StrokeAlign to allow double values." (#109591)

parent 9758aa35
...@@ -80,7 +80,7 @@ class _MyHomePageState extends State<MyHomePage> { ...@@ -80,7 +80,7 @@ class _MyHomePageState extends State<MyHomePage> {
color: Colors.blue.shade100, color: Colors.blue.shade100,
shape: lerpBorder( shape: lerpBorder(
StarBorder.polygon( StarBorder.polygon(
side: const BorderSide(strokeAlign: BorderSide.strokeAlignCenter, width: 2), side: const BorderSide(strokeAlign: StrokeAlign.center, width: 2),
sides: _model.points, sides: _model.points,
pointRounding: _model.pointRounding, pointRounding: _model.pointRounding,
rotation: _model.rotation, rotation: _model.rotation,
...@@ -102,7 +102,7 @@ class _MyHomePageState extends State<MyHomePage> { ...@@ -102,7 +102,7 @@ class _MyHomePageState extends State<MyHomePage> {
color: Colors.blue.shade100, color: Colors.blue.shade100,
shape: lerpBorder( shape: lerpBorder(
StarBorder( StarBorder(
side: const BorderSide(strokeAlign: BorderSide.strokeAlignCenter, width: 2), side: const BorderSide(strokeAlign: StrokeAlign.center, width: 2),
points: _model.points, points: _model.points,
innerRadiusRatio: _model.innerRadiusRatio, innerRadiusRatio: _model.innerRadiusRatio,
pointRounding: _model.pointRounding, pointRounding: _model.pointRounding,
......
// 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.
/// Flutter code sample for [BorderSide].
import 'package:flutter/material.dart';
void main() => runApp(const BorderSideApp());
class BorderSideApp extends StatelessWidget {
const BorderSideApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: BorderSideExample());
}
}
class BorderSideExample extends StatefulWidget {
const BorderSideExample({super.key});
@override
State<BorderSideExample> createState() => _BorderSideExampleState();
}
class _BorderSideExampleState extends State<BorderSideExample>
with TickerProviderStateMixin {
late final AnimationController animation;
@override
void initState() {
super.initState();
animation =
AnimationController(vsync: this, duration: const Duration(seconds: 1));
animation.repeat(reverse: true);
animation.addListener(_markDirty);
}
@override
void dispose() {
animation.dispose();
super.dispose();
}
void _markDirty() {
setState(() {});
}
static const double borderWidth = 10;
static const double cornerRadius = 10;
static const Color borderColor = Color(0x8000b4fc);
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
TestBox(
shape: StadiumBorder(
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
TestBox(
shape: CircleBorder(
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
TestBox(
shape: OvalBorder(
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
TestBox(
shape: BeveledRectangleBorder(
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
TestBox(
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.circular(cornerRadius),
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
TestBox(
shape: RoundedRectangleBorder(
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
TestBox(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(cornerRadius),
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
TestBox(
shape: StarBorder(
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
TestBox(
shape: StarBorder(
pointRounding: 1,
innerRadiusRatio: 0.5,
points: 8,
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
TestBox(
shape: StarBorder.polygon(
sides: 6,
pointRounding: 0.5,
side: BorderSide(
color: borderColor,
width: borderWidth,
strokeAlign: (animation.value * 2) - 1,
),
),
),
],
),
],
),
),
);
}
}
class TestBox extends StatelessWidget {
const TestBox({
super.key,
required this.shape,
});
final ShapeBorder shape;
@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 50,
decoration: ShapeDecoration(
color: const Color(0xff012677),
shape: shape,
),
);
}
}
// 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 'package:flutter/material.dart';
import 'package:flutter_api_samples/painting/borders/border_side.0.dart'
as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Finds the expected TestBox', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: example.BorderSideExample(),
),
);
expect(find.byType(example.BorderSideExample), findsOneWidget);
expect(find.byType(example.TestBox), findsNWidgets(10));
});
}
...@@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart'; ...@@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart';
import 'basic_types.dart'; import 'basic_types.dart';
import 'border_radius.dart'; import 'border_radius.dart';
import 'borders.dart'; import 'borders.dart';
import 'edge_insets.dart';
/// A rectangular border with flattened or "beveled" corners. /// A rectangular border with flattened or "beveled" corners.
/// ///
...@@ -39,6 +40,18 @@ class BeveledRectangleBorder extends OutlinedBorder { ...@@ -39,6 +40,18 @@ class BeveledRectangleBorder extends OutlinedBorder {
/// [getOuterPath]. /// [getOuterPath].
final BorderRadiusGeometry borderRadius; final BorderRadiusGeometry borderRadius;
@override
EdgeInsetsGeometry get dimensions {
switch (side.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsets.all(side.width);
case StrokeAlign.center:
return EdgeInsets.all(side.width / 2);
case StrokeAlign.outside:
return EdgeInsets.zero;
}
}
@override @override
ShapeBorder scale(double t) { ShapeBorder scale(double t) {
return BeveledRectangleBorder( return BeveledRectangleBorder(
...@@ -112,7 +125,21 @@ class BeveledRectangleBorder extends OutlinedBorder { ...@@ -112,7 +125,21 @@ class BeveledRectangleBorder extends OutlinedBorder {
@override @override
Path getInnerPath(Rect rect, { TextDirection? textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
return _getPath(borderRadius.resolve(textDirection).toRRect(rect).deflate(side.strokeInset)); final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect);
final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(side.width);
break;
case StrokeAlign.center:
adjustedRect = borderRect.deflate(side.width / 2);
break;
case StrokeAlign.outside:
adjustedRect = borderRect;
break;
}
return _getPath(adjustedRect);
} }
@override @override
...@@ -129,7 +156,21 @@ class BeveledRectangleBorder extends OutlinedBorder { ...@@ -129,7 +156,21 @@ class BeveledRectangleBorder extends OutlinedBorder {
case BorderStyle.none: case BorderStyle.none:
break; break;
case BorderStyle.solid: case BorderStyle.solid:
final Path path = _getPath(borderRadius.resolve(textDirection).toRRect(rect).inflate(side.strokeOffset / 2)); final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect);
final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect;
break;
case StrokeAlign.center:
adjustedRect = borderRect.inflate(side.width / 2);
break;
case StrokeAlign.outside:
adjustedRect = borderRect.inflate(side.width);
break;
}
final Path path = _getPath(adjustedRect)
..addPath(getInnerPath(rect, textDirection: textDirection), Offset.zero);
canvas.drawPath(path, side.toPaint()); canvas.drawPath(path, side.toPaint());
break; break;
} }
......
...@@ -21,6 +21,27 @@ enum BorderStyle { ...@@ -21,6 +21,27 @@ enum BorderStyle {
// if you add more, think about how they will lerp // if you add more, think about how they will lerp
} }
/// The relative position of the stroke on a [BorderSide] in a [Border] or [OutlinedBorder].
/// When set to [inside], the stroke is drawn completely inside the widget.
/// For [center] and [outside], a property such as [Container.clipBehavior]
/// can be used in an outside widget to clip it.
/// If [Container.decoration] has a border, the container may incorporate
/// [BorderSide.width] as additional padding:
/// - [inside] provides padding with full [BorderSide.width].
/// - [center] provides padding with half [BorderSide.width].
/// - [outside] provides zero padding, as stroke is drawn entirely outside.
enum StrokeAlign {
/// The border is drawn on the inside of the border path.
inside,
/// The border is drawn on the center of the border path, with half of the
/// [BorderSide.width] on the inside, and the other half on the outside of the path.
center,
/// The border is drawn on the outside of the border path.
outside,
}
/// A side of a border of a box. /// A side of a border of a box.
/// ///
/// A [Border] consists of four [BorderSide] objects: [Border.top], /// A [Border] consists of four [BorderSide] objects: [Border.top],
...@@ -58,7 +79,7 @@ enum BorderStyle { ...@@ -58,7 +79,7 @@ enum BorderStyle {
/// ([TableBorder.horizontalInside] and [TableBorder.verticalInside]), both /// ([TableBorder.horizontalInside] and [TableBorder.verticalInside]), both
/// of which are also [BorderSide] objects. /// of which are also [BorderSide] objects.
@immutable @immutable
class BorderSide with Diagnosticable { class BorderSide {
/// Creates the side of a border. /// Creates the side of a border.
/// ///
/// By default, the border is 1.0 logical pixels wide and solid black. /// By default, the border is 1.0 logical pixels wide and solid black.
...@@ -66,12 +87,11 @@ class BorderSide with Diagnosticable { ...@@ -66,12 +87,11 @@ class BorderSide with Diagnosticable {
this.color = const Color(0xFF000000), this.color = const Color(0xFF000000),
this.width = 1.0, this.width = 1.0,
this.style = BorderStyle.solid, this.style = BorderStyle.solid,
this.strokeAlign = strokeAlignInside, this.strokeAlign = StrokeAlign.inside,
}) : assert(color != null), }) : assert(color != null),
assert(width != null), assert(width != null),
assert(width >= 0.0), assert(width >= 0.0),
assert(style != null), assert(style != null);
assert(strokeAlign != null);
/// Creates a [BorderSide] that represents the addition of the two given /// Creates a [BorderSide] that represents the addition of the two given
/// [BorderSide]s. /// [BorderSide]s.
...@@ -104,7 +124,6 @@ class BorderSide with Diagnosticable { ...@@ -104,7 +124,6 @@ class BorderSide with Diagnosticable {
return BorderSide( return BorderSide(
color: a.color, // == b.color color: a.color, // == b.color
width: a.width + b.width, width: a.width + b.width,
strokeAlign: math.max(a.strokeAlign, b.strokeAlign),
style: a.style, // == b.style style: a.style, // == b.style
); );
} }
...@@ -132,50 +151,20 @@ class BorderSide with Diagnosticable { ...@@ -132,50 +151,20 @@ class BorderSide with Diagnosticable {
/// A hairline black border that is not rendered. /// A hairline black border that is not rendered.
static const BorderSide none = BorderSide(width: 0.0, style: BorderStyle.none); static const BorderSide none = BorderSide(width: 0.0, style: BorderStyle.none);
/// The relative position of the stroke on a [BorderSide] in an /// The direction of where the border will be drawn relative to the container.
/// [OutlinedBorder] or [Border]. final StrokeAlign strokeAlign;
///
/// Values typically range from -1.0 ([strokeAlignInside], inside border,
/// default) to 1.0 ([strokeAlignOutside], outside border), without any
/// bound constraints (e.g., a value of -2.0 is is not typical, but allowed).
/// A value of 0 ([strokeAlignCenter]) will center the border on the edge
/// of the widget.
///
/// When set to [strokeAlignInside], the stroke is drawn completely inside
/// the widget. For [strokeAlignCenter] and [strokeAlignOutside], a property
/// such as [Container.clipBehavior] can be used in an outside widget to clip
/// it. If [Container.decoration] has a border, the container may incorporate
/// [width] as additional padding:
/// - [strokeAlignInside] provides padding with full [width].
/// - [strokeAlignCenter] provides padding with half [width].
/// - [strokeAlignOutside] provides zero padding, as stroke is drawn entirely outside.
final double strokeAlign;
/// The border is drawn fully inside of the border path.
///
/// This is the default.
static const double strokeAlignInside = -1.0;
/// The border is drawn on the center of the border path, with half of the
/// [BorderSide.width] on the inside, and the other half on the outside of
/// the path.
static const double strokeAlignCenter = 0.0;
/// The border is drawn on the outside of the border path.
static const double strokeAlignOutside = 1.0;
/// Creates a copy of this border but with the given fields replaced with the new values. /// Creates a copy of this border but with the given fields replaced with the new values.
BorderSide copyWith({ BorderSide copyWith({
Color? color, Color? color,
double? width, double? width,
BorderStyle? style, BorderStyle? style,
double? strokeAlign,
}) { }) {
assert(width == null || width >= 0.0);
return BorderSide( return BorderSide(
color: color ?? this.color, color: color ?? this.color,
width: width ?? this.width, width: width ?? this.width,
style: style ?? this.style, style: style ?? this.style,
strokeAlign: strokeAlign ?? this.strokeAlign,
); );
} }
...@@ -240,7 +229,8 @@ class BorderSide with Diagnosticable { ...@@ -240,7 +229,8 @@ class BorderSide with Diagnosticable {
return true; return true;
} }
return a.style == b.style return a.style == b.style
&& a.color == b.color; && a.color == b.color
&& a.strokeAlign == b.strokeAlign;
} }
/// Linearly interpolate between two border sides. /// Linearly interpolate between two border sides.
...@@ -288,10 +278,13 @@ class BorderSide with Diagnosticable { ...@@ -288,10 +278,13 @@ class BorderSide with Diagnosticable {
break; break;
} }
if (a.strokeAlign != b.strokeAlign) { if (a.strokeAlign != b.strokeAlign) {
// When strokeAlign changes, lerp to 0, then from 0 to the target width.
// All StrokeAlign values share a common zero width state.
final StrokeAlign strokeAlign = t > 0.5 ? b.strokeAlign : a.strokeAlign;
return BorderSide( return BorderSide(
color: Color.lerp(colorA, colorB, t)!, color: Color.lerp(colorA, colorB, t)!,
width: width, width: t > 0.5 ? ui.lerpDouble(0, b.width, t * 2 - 1)! : ui.lerpDouble(a.width, 0, t * 2)!,
strokeAlign: ui.lerpDouble(a.strokeAlign, b.strokeAlign, t)!, strokeAlign: strokeAlign,
); );
} }
return BorderSide( return BorderSide(
...@@ -301,26 +294,6 @@ class BorderSide with Diagnosticable { ...@@ -301,26 +294,6 @@ class BorderSide with Diagnosticable {
); );
} }
/// Get the amount of the stroke width that lies inside of the [BorderSide].
///
/// For example, this will return the [width] for a [strokeAlign] of -1, half
/// the [width] for a [strokeAlign] of 0, and 0 for a [strokeAlign] of 1.
double get strokeInset => width * (1 - (1 + strokeAlign) / 2);
/// Get the amount of the stroke width that lies outside of the [BorderSide].
///
/// For example, this will return 0 for a [strokeAlign] of -1, half the
/// [width] for a [strokeAlign] of 0, and the [width] for a [strokeAlign]
/// of 1.
double get strokeOutset => width * (1 + strokeAlign) / 2;
/// The offset of the stroke, taking into account the stroke alignment.
///
/// For example, this will return the negative [width] of the stroke
/// for a [strokeAlign] of -1, 0 for a [strokeAlign] of 0, and the
/// [width] for a [strokeAlign] of -1.
double get strokeOffset => width * strokeAlign;
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
if (identical(this, other)) { if (identical(this, other)) {
...@@ -340,15 +313,11 @@ class BorderSide with Diagnosticable { ...@@ -340,15 +313,11 @@ class BorderSide with Diagnosticable {
int get hashCode => Object.hash(color, width, style, strokeAlign); int get hashCode => Object.hash(color, width, style, strokeAlign);
@override @override
String toStringShort() => 'BorderSide'; String toString() {
if (strokeAlign == StrokeAlign.inside) {
@override return '${objectRuntimeType(this, 'BorderSide')}($color, ${width.toStringAsFixed(1)}, $style)';
void debugFillProperties(DiagnosticPropertiesBuilder properties) { }
super.debugFillProperties(properties); return '${objectRuntimeType(this, 'BorderSide')}($color, ${width.toStringAsFixed(1)}, $style, $strokeAlign)';
properties.add(DiagnosticsProperty<Color>('color', color, defaultValue: const Color(0xFF000000)));
properties.add(DoubleProperty('width', width, defaultValue: 1.0));
properties.add(DoubleProperty('strokeAlign', strokeAlign, defaultValue: strokeAlignInside));
properties.add(EnumProperty<BorderStyle>('style', style, defaultValue: BorderStyle.solid));
} }
} }
...@@ -588,9 +557,6 @@ abstract class OutlinedBorder extends ShapeBorder { ...@@ -588,9 +557,6 @@ abstract class OutlinedBorder extends ShapeBorder {
/// The value of [side] must not be null. /// The value of [side] must not be null.
const OutlinedBorder({ this.side = BorderSide.none }) : assert(side != null); const OutlinedBorder({ this.side = BorderSide.none }) : assert(side != null);
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(math.max(side.strokeInset, 0));
/// The border outline's color and weight. /// The border outline's color and weight.
/// ///
/// If [side] is [BorderSide.none], which is the default, an outline is not drawn. /// If [side] is [BorderSide.none], which is the default, an outline is not drawn.
......
...@@ -219,22 +219,62 @@ abstract class BoxBorder extends ShapeBorder { ...@@ -219,22 +219,62 @@ abstract class BoxBorder extends ShapeBorder {
..strokeWidth = 0.0; ..strokeWidth = 0.0;
canvas.drawRRect(borderRadius.toRRect(rect), paint); canvas.drawRRect(borderRadius.toRRect(rect), paint);
} else { } else {
final RRect borderRect = borderRadius.toRRect(rect); if (side.strokeAlign == StrokeAlign.inside) {
final RRect inner = borderRect.deflate(side.strokeInset); final RRect outer = borderRadius.toRRect(rect);
final RRect outer = borderRect.inflate(side.strokeOutset); final RRect inner = outer.deflate(width);
canvas.drawDRRect(outer, inner, paint); canvas.drawDRRect(outer, inner, paint);
} else {
final Rect inner;
final Rect outer;
if (side.strokeAlign == StrokeAlign.center) {
inner = rect.deflate(width / 2);
outer = rect.inflate(width / 2);
} else {
inner = rect;
outer = rect.inflate(width);
}
canvas.drawDRRect(borderRadius.toRRect(outer), borderRadius.toRRect(inner), paint);
}
} }
} }
static void _paintUniformBorderWithCircle(Canvas canvas, Rect rect, BorderSide side) { static void _paintUniformBorderWithCircle(Canvas canvas, Rect rect, BorderSide side) {
assert(side.style != BorderStyle.none); assert(side.style != BorderStyle.none);
final double radius = (rect.shortestSide + side.strokeOffset) / 2; final double width = side.width;
canvas.drawCircle(rect.center, radius, side.toPaint()); final Paint paint = side.toPaint();
final double radius;
switch (side.strokeAlign) {
case StrokeAlign.inside:
radius = (rect.shortestSide - width) / 2.0;
break;
case StrokeAlign.center:
radius = rect.shortestSide / 2.0;
break;
case StrokeAlign.outside:
radius = (rect.shortestSide + width) / 2.0;
break;
}
canvas.drawCircle(rect.center, radius, paint);
} }
static void _paintUniformBorderWithRectangle(Canvas canvas, Rect rect, BorderSide side) { static void _paintUniformBorderWithRectangle(Canvas canvas, Rect rect, BorderSide side) {
assert(side.style != BorderStyle.none); assert(side.style != BorderStyle.none);
canvas.drawRect(rect.inflate(side.strokeOffset / 2), side.toPaint()); final double width = side.width;
final Paint paint = side.toPaint();
final Rect rectToBeDrawn;
switch (side.strokeAlign) {
case StrokeAlign.inside:
rectToBeDrawn = rect.deflate(width / 2.0);
break;
case StrokeAlign.center:
rectToBeDrawn = rect;
break;
case StrokeAlign.outside:
rectToBeDrawn = rect.inflate(width / 2.0);
break;
}
canvas.drawRect(rectToBeDrawn, paint);
} }
} }
...@@ -348,7 +388,7 @@ class Border extends BoxBorder { ...@@ -348,7 +388,7 @@ class Border extends BoxBorder {
Color color = const Color(0xFF000000), Color color = const Color(0xFF000000),
double width = 1.0, double width = 1.0,
BorderStyle style = BorderStyle.solid, BorderStyle style = BorderStyle.solid,
double strokeAlign = BorderSide.strokeAlignInside, StrokeAlign strokeAlign = StrokeAlign.inside,
}) { }) {
final BorderSide side = BorderSide(color: color, width: width, style: style, strokeAlign: strokeAlign); final BorderSide side = BorderSide(color: color, width: width, style: style, strokeAlign: strokeAlign);
return Border.fromBorderSide(side); return Border.fromBorderSide(side);
...@@ -390,10 +430,17 @@ class Border extends BoxBorder { ...@@ -390,10 +430,17 @@ class Border extends BoxBorder {
@override @override
EdgeInsetsGeometry get dimensions { EdgeInsetsGeometry get dimensions {
if (_widthIsUniform) { if (isUniform) {
return EdgeInsets.all(top.strokeInset); switch (top.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsets.all(top.width);
case StrokeAlign.center:
return EdgeInsets.all(top.width / 2);
case StrokeAlign.outside:
return EdgeInsets.zero;
}
} }
return EdgeInsets.fromLTRB(left.strokeInset, top.strokeInset, right.strokeInset, bottom.strokeInset); return EdgeInsets.fromLTRB(left.width, top.width, right.width, bottom.width);
} }
@override @override
...@@ -415,7 +462,7 @@ class Border extends BoxBorder { ...@@ -415,7 +462,7 @@ class Border extends BoxBorder {
} }
bool get _strokeAlignIsUniform { bool get _strokeAlignIsUniform {
final double topStrokeAlign = top.strokeAlign; final StrokeAlign topStrokeAlign = top.strokeAlign;
return right.strokeAlign == topStrokeAlign return right.strokeAlign == topStrokeAlign
&& bottom.strokeAlign == topStrokeAlign && bottom.strokeAlign == topStrokeAlign
&& left.strokeAlign == topStrokeAlign; && left.strokeAlign == topStrokeAlign;
...@@ -522,7 +569,7 @@ class Border extends BoxBorder { ...@@ -522,7 +569,7 @@ class Border extends BoxBorder {
BoxBorder._paintUniformBorderWithCircle(canvas, rect, top); BoxBorder._paintUniformBorderWithCircle(canvas, rect, top);
break; break;
case BoxShape.rectangle: case BoxShape.rectangle:
if (borderRadius != null && borderRadius != BorderRadius.zero) { if (borderRadius != null) {
BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius); BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius);
return; return;
} }
...@@ -560,9 +607,9 @@ class Border extends BoxBorder { ...@@ -560,9 +607,9 @@ class Border extends BoxBorder {
return true; return true;
}()); }());
assert(() { assert(() {
if (!_strokeAlignIsUniform || top.strokeAlign != BorderSide.strokeAlignInside) { if (!_strokeAlignIsUniform || top.strokeAlign != StrokeAlign.inside) {
throw FlutterError.fromParts(<DiagnosticsNode>[ throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('A Border can only draw strokeAlign different than BorderSide.strokeAlignInside on uniform borders.'), ErrorSummary('A Border can only draw strokeAlign different than StrokeAlign.inside on uniform borders.'),
]); ]);
} }
return true; return true;
...@@ -694,9 +741,16 @@ class BorderDirectional extends BoxBorder { ...@@ -694,9 +741,16 @@ class BorderDirectional extends BoxBorder {
@override @override
EdgeInsetsGeometry get dimensions { EdgeInsetsGeometry get dimensions {
if (isUniform) { if (isUniform) {
return EdgeInsetsDirectional.all(top.strokeInset); switch (top.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsetsDirectional.all(top.width);
case StrokeAlign.center:
return EdgeInsetsDirectional.all(top.width / 2);
case StrokeAlign.outside:
return EdgeInsetsDirectional.zero;
}
} }
return EdgeInsetsDirectional.fromSTEB(start.strokeInset, top.strokeInset, end.strokeInset, bottom.strokeInset); return EdgeInsetsDirectional.fromSTEB(start.width, top.width, end.width, bottom.width);
} }
@override @override
...@@ -730,7 +784,7 @@ class BorderDirectional extends BoxBorder { ...@@ -730,7 +784,7 @@ class BorderDirectional extends BoxBorder {
} }
bool get _strokeAlignIsUniform { bool get _strokeAlignIsUniform {
final double topStrokeAlign = top.strokeAlign; final StrokeAlign topStrokeAlign = top.strokeAlign;
return start.strokeAlign == topStrokeAlign return start.strokeAlign == topStrokeAlign
&& bottom.strokeAlign == topStrokeAlign && bottom.strokeAlign == topStrokeAlign
&& end.strokeAlign == topStrokeAlign; && end.strokeAlign == topStrokeAlign;
...@@ -873,7 +927,7 @@ class BorderDirectional extends BoxBorder { ...@@ -873,7 +927,7 @@ class BorderDirectional extends BoxBorder {
BoxBorder._paintUniformBorderWithCircle(canvas, rect, top); BoxBorder._paintUniformBorderWithCircle(canvas, rect, top);
break; break;
case BoxShape.rectangle: case BoxShape.rectangle:
if (borderRadius != null && borderRadius != BorderRadius.zero) { if (borderRadius != null) {
BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius); BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius);
return; return;
} }
...@@ -886,7 +940,7 @@ class BorderDirectional extends BoxBorder { ...@@ -886,7 +940,7 @@ class BorderDirectional extends BoxBorder {
assert(borderRadius == null, 'A borderRadius can only be given for uniform borders.'); assert(borderRadius == null, 'A borderRadius can only be given for uniform borders.');
assert(shape == BoxShape.rectangle, 'A border can only be drawn as a circle if it is uniform.'); assert(shape == BoxShape.rectangle, 'A border can only be drawn as a circle if it is uniform.');
assert(_strokeAlignIsUniform && top.strokeAlign == BorderSide.strokeAlignInside, 'A Border can only draw strokeAlign different than strokeAlignInside on uniform borders.'); assert(_strokeAlignIsUniform && top.strokeAlign == StrokeAlign.inside, 'A Border can only draw strokeAlign different than StrokeAlign.inside on uniform borders.');
final BorderSide left, right; final BorderSide left, right;
assert(textDirection != null, 'Non-uniform BorderDirectional objects require a TextDirection when painting.'); assert(textDirection != null, 'Non-uniform BorderDirectional objects require a TextDirection when painting.');
......
...@@ -431,7 +431,7 @@ class _BoxDecorationPainter extends BoxPainter { ...@@ -431,7 +431,7 @@ class _BoxDecorationPainter extends BoxPainter {
canvas.drawCircle(center, radius, paint); canvas.drawCircle(center, radius, paint);
break; break;
case BoxShape.rectangle: case BoxShape.rectangle:
if (_decoration.borderRadius == null || _decoration.borderRadius == BorderRadius.zero) { if (_decoration.borderRadius == null) {
canvas.drawRect(rect, paint); canvas.drawRect(rect, paint);
} else { } else {
canvas.drawRRect(_decoration.borderRadius!.resolve(textDirection).toRRect(rect), paint); canvas.drawRRect(_decoration.borderRadius!.resolve(textDirection).toRRect(rect), paint);
......
...@@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; ...@@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart';
import 'basic_types.dart'; import 'basic_types.dart';
import 'borders.dart'; import 'borders.dart';
import 'edge_insets.dart';
/// A border that fits a circle within the available space. /// A border that fits a circle within the available space.
/// ///
...@@ -44,6 +45,18 @@ class CircleBorder extends OutlinedBorder { ...@@ -44,6 +45,18 @@ class CircleBorder extends OutlinedBorder {
/// When 1.0, it draws an oval touching all sides of the rectangle. /// When 1.0, it draws an oval touching all sides of the rectangle.
final double eccentricity; final double eccentricity;
@override
EdgeInsetsGeometry get dimensions {
switch (side.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsets.all(side.width);
case StrokeAlign.center:
return EdgeInsets.all(side.width / 2);
case StrokeAlign.outside:
return EdgeInsets.zero;
}
}
@override @override
ShapeBorder scale(double t) => CircleBorder(side: side.scale(t), eccentricity: eccentricity); ShapeBorder scale(double t) => CircleBorder(side: side.scale(t), eccentricity: eccentricity);
...@@ -71,12 +84,25 @@ class CircleBorder extends OutlinedBorder { ...@@ -71,12 +84,25 @@ class CircleBorder extends OutlinedBorder {
@override @override
Path getInnerPath(Rect rect, { TextDirection? textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
return Path()..addOval(_adjustRect(rect).deflate(side.strokeInset)); final double delta;
switch (side.strokeAlign) {
case StrokeAlign.inside:
delta = side.width;
break;
case StrokeAlign.center:
delta = side.width / 2.0;
break;
case StrokeAlign.outside:
delta = 0;
break;
}
final Rect adjustedRect = _adjustRect(rect).deflate(delta);
return Path()..addOval(adjustedRect);
} }
@override @override
Path getOuterPath(Rect rect, { TextDirection? textDirection }) { Path getOuterPath(Rect rect, { TextDirection? textDirection }) {
return Path()..addOval(_adjustRect(rect)); return Path()..addOval(_adjustRect(rect));
} }
@override @override
...@@ -90,11 +116,35 @@ class CircleBorder extends OutlinedBorder { ...@@ -90,11 +116,35 @@ class CircleBorder extends OutlinedBorder {
case BorderStyle.none: case BorderStyle.none:
break; break;
case BorderStyle.solid: case BorderStyle.solid:
if (eccentricity == 0.0) { if (eccentricity != 0.0) {
canvas.drawCircle(rect.center, (rect.shortestSide + side.strokeOffset) / 2, side.toPaint());
} else {
final Rect borderRect = _adjustRect(rect); final Rect borderRect = _adjustRect(rect);
canvas.drawOval(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); final Rect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(side.width / 2.0);
break;
case StrokeAlign.center:
adjustedRect = borderRect;
break;
case StrokeAlign.outside:
adjustedRect = borderRect.inflate(side.width / 2.0);
break;
}
canvas.drawOval(adjustedRect, side.toPaint());
} else {
final double radius;
switch (side.strokeAlign) {
case StrokeAlign.inside:
radius = (rect.shortestSide - side.width) / 2.0;
break;
case StrokeAlign.center:
radius = rect.shortestSide / 2.0;
break;
case StrokeAlign.outside:
radius = (rect.shortestSide + side.width) / 2.0;
break;
}
canvas.drawCircle(rect.center, radius, side.toPaint());
} }
} }
} }
......
...@@ -149,7 +149,7 @@ class ContinuousRectangleBorder extends OutlinedBorder { ...@@ -149,7 +149,7 @@ class ContinuousRectangleBorder extends OutlinedBorder {
break; break;
case BorderStyle.solid: case BorderStyle.solid:
final Path path = getOuterPath(rect, textDirection: textDirection); final Path path = getOuterPath(rect, textDirection: textDirection);
final Paint paint = side.toPaint()..strokeJoin = StrokeJoin.round; final Paint paint = side.toPaint();
canvas.drawPath(path, paint); canvas.drawPath(path, paint);
break; break;
} }
......
...@@ -10,6 +10,7 @@ import 'basic_types.dart'; ...@@ -10,6 +10,7 @@ import 'basic_types.dart';
import 'border_radius.dart'; import 'border_radius.dart';
import 'borders.dart'; import 'borders.dart';
import 'circle_border.dart'; import 'circle_border.dart';
import 'edge_insets.dart';
/// A rectangular border with rounded corners. /// A rectangular border with rounded corners.
/// ///
...@@ -36,6 +37,18 @@ class RoundedRectangleBorder extends OutlinedBorder { ...@@ -36,6 +37,18 @@ class RoundedRectangleBorder extends OutlinedBorder {
/// The radii for each corner. /// The radii for each corner.
final BorderRadiusGeometry borderRadius; final BorderRadiusGeometry borderRadius;
@override
EdgeInsetsGeometry get dimensions {
switch (side.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsets.all(side.width);
case StrokeAlign.center:
return EdgeInsets.all(side.width / 2);
case StrokeAlign.outside:
return EdgeInsets.zero;
}
}
@override @override
ShapeBorder scale(double t) { ShapeBorder scale(double t) {
return RoundedRectangleBorder( return RoundedRectangleBorder(
...@@ -97,7 +110,18 @@ class RoundedRectangleBorder extends OutlinedBorder { ...@@ -97,7 +110,18 @@ class RoundedRectangleBorder extends OutlinedBorder {
@override @override
Path getInnerPath(Rect rect, { TextDirection? textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect); final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect);
final RRect adjustedRect = borderRect.deflate(side.strokeInset); final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(side.width);
break;
case StrokeAlign.center:
adjustedRect = borderRect.deflate(side.width / 2);
break;
case StrokeAlign.outside:
adjustedRect = borderRect;
break;
}
return Path() return Path()
..addRRect(adjustedRect); ..addRRect(adjustedRect);
} }
...@@ -114,12 +138,30 @@ class RoundedRectangleBorder extends OutlinedBorder { ...@@ -114,12 +138,30 @@ class RoundedRectangleBorder extends OutlinedBorder {
case BorderStyle.none: case BorderStyle.none:
break; break;
case BorderStyle.solid: case BorderStyle.solid:
final Paint paint = Paint() final double width = side.width;
..color = side.color; if (width == 0.0) {
final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect); canvas.drawRRect(borderRadius.resolve(textDirection).toRRect(rect), side.toPaint());
final RRect inner = borderRect.deflate(side.strokeInset); } else {
final RRect outer = borderRect.inflate(side.strokeOutset); final Paint paint = Paint()
canvas.drawDRRect(outer, inner, paint); ..color = side.color;
if (side.strokeAlign == StrokeAlign.inside) {
final RRect outer = borderRadius.resolve(textDirection).toRRect(rect);
final RRect inner = outer.deflate(width);
canvas.drawDRRect(outer, inner, paint);
} else {
final Rect inner;
final Rect outer;
if (side.strokeAlign == StrokeAlign.center) {
inner = rect.deflate(width / 2);
outer = rect.inflate(width / 2);
} else {
inner = rect;
outer = rect.inflate(width);
}
final BorderRadius borderRadiusResolved = borderRadius.resolve(textDirection);
canvas.drawDRRect(borderRadiusResolved.toRRect(outer), borderRadiusResolved.toRRect(inner), paint);
}
}
} }
} }
...@@ -156,6 +198,18 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { ...@@ -156,6 +198,18 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder {
final double circleness; final double circleness;
final double eccentricity; final double eccentricity;
@override
EdgeInsetsGeometry get dimensions {
switch (side.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsets.all(side.width);
case StrokeAlign.center:
return EdgeInsets.all(side.width / 2);
case StrokeAlign.outside:
return EdgeInsets.zero;
}
}
@override @override
ShapeBorder scale(double t) { ShapeBorder scale(double t) {
return _RoundedRectangleToCircleBorder( return _RoundedRectangleToCircleBorder(
...@@ -276,7 +330,18 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { ...@@ -276,7 +330,18 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder {
@override @override
Path getInnerPath(Rect rect, { TextDirection? textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
final RRect borderRect = _adjustBorderRadius(rect, textDirection)!.toRRect(_adjustRect(rect)); final RRect borderRect = _adjustBorderRadius(rect, textDirection)!.toRRect(_adjustRect(rect));
final RRect adjustedRect = borderRect.deflate(ui.lerpDouble(side.width, 0, side.strokeAlign)!); final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(side.width);
break;
case StrokeAlign.center:
adjustedRect = borderRect.deflate(side.width / 2);
break;
case StrokeAlign.outside:
adjustedRect = borderRect;
break;
}
return Path() return Path()
..addRRect(adjustedRect); ..addRRect(adjustedRect);
} }
...@@ -303,9 +368,25 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { ...@@ -303,9 +368,25 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder {
case BorderStyle.none: case BorderStyle.none:
break; break;
case BorderStyle.solid: case BorderStyle.solid:
final BorderRadius adjustedBorderRadius = _adjustBorderRadius(rect, textDirection)!; final double width = side.width;
final RRect borderRect = adjustedBorderRadius.toRRect(_adjustRect(rect)); if (width == 0.0) {
canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); canvas.drawRRect(_adjustBorderRadius(rect, textDirection)!.toRRect(_adjustRect(rect)), side.toPaint());
} else {
final RRect borderRect = _adjustBorderRadius(rect, textDirection)!.toRRect(_adjustRect(rect));
final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(width / 2);
break;
case StrokeAlign.center:
adjustedRect = borderRect;
break;
case StrokeAlign.outside:
adjustedRect = borderRect.inflate(width / 2);
break;
}
canvas.drawRRect(adjustedRect, side.toPaint());
}
} }
} }
......
...@@ -10,6 +10,7 @@ import 'basic_types.dart'; ...@@ -10,6 +10,7 @@ import 'basic_types.dart';
import 'border_radius.dart'; import 'border_radius.dart';
import 'borders.dart'; import 'borders.dart';
import 'circle_border.dart'; import 'circle_border.dart';
import 'edge_insets.dart';
import 'rounded_rectangle_border.dart'; import 'rounded_rectangle_border.dart';
/// A border that fits a stadium-shaped border (a box with semicircles on the ends) /// A border that fits a stadium-shaped border (a box with semicircles on the ends)
...@@ -29,6 +30,18 @@ class StadiumBorder extends OutlinedBorder { ...@@ -29,6 +30,18 @@ class StadiumBorder extends OutlinedBorder {
/// The [side] argument must not be null. /// The [side] argument must not be null.
const StadiumBorder({ super.side }) : assert(side != null); const StadiumBorder({ super.side }) : assert(side != null);
@override
EdgeInsetsGeometry get dimensions {
switch (side.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsets.all(side.width);
case StrokeAlign.center:
return EdgeInsets.all(side.width / 2);
case StrokeAlign.outside:
return EdgeInsets.zero;
}
}
@override @override
ShapeBorder scale(double t) => StadiumBorder(side: side.scale(t)); ShapeBorder scale(double t) => StadiumBorder(side: side.scale(t));
...@@ -87,7 +100,18 @@ class StadiumBorder extends OutlinedBorder { ...@@ -87,7 +100,18 @@ class StadiumBorder extends OutlinedBorder {
Path getInnerPath(Rect rect, { TextDirection? textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
final Radius radius = Radius.circular(rect.shortestSide / 2.0); final Radius radius = Radius.circular(rect.shortestSide / 2.0);
final RRect borderRect = RRect.fromRectAndRadius(rect, radius); final RRect borderRect = RRect.fromRectAndRadius(rect, radius);
final RRect adjustedRect = borderRect.deflate(side.strokeInset); final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(side.width);
break;
case StrokeAlign.center:
adjustedRect = borderRect.deflate(side.width / 2);
break;
case StrokeAlign.outside:
adjustedRect = borderRect;
break;
}
return Path() return Path()
..addRRect(adjustedRect); ..addRRect(adjustedRect);
} }
...@@ -107,7 +131,22 @@ class StadiumBorder extends OutlinedBorder { ...@@ -107,7 +131,22 @@ class StadiumBorder extends OutlinedBorder {
case BorderStyle.solid: case BorderStyle.solid:
final Radius radius = Radius.circular(rect.shortestSide / 2); final Radius radius = Radius.circular(rect.shortestSide / 2);
final RRect borderRect = RRect.fromRectAndRadius(rect, radius); final RRect borderRect = RRect.fromRectAndRadius(rect, radius);
canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(side.width / 2);
break;
case StrokeAlign.center:
adjustedRect = borderRect;
break;
case StrokeAlign.outside:
adjustedRect = borderRect.inflate(side.width / 2);
break;
}
canvas.drawRRect(
adjustedRect,
side.toPaint(),
);
} }
} }
...@@ -141,6 +180,18 @@ class _StadiumToCircleBorder extends OutlinedBorder { ...@@ -141,6 +180,18 @@ class _StadiumToCircleBorder extends OutlinedBorder {
final double circleness; final double circleness;
final double eccentricity; final double eccentricity;
@override
EdgeInsetsGeometry get dimensions {
switch (side.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsets.all(side.width);
case StrokeAlign.center:
return EdgeInsets.all(side.width / 2);
case StrokeAlign.outside:
return EdgeInsets.zero;
}
}
@override @override
ShapeBorder scale(double t) { ShapeBorder scale(double t) {
return _StadiumToCircleBorder( return _StadiumToCircleBorder(
...@@ -252,7 +303,7 @@ class _StadiumToCircleBorder extends OutlinedBorder { ...@@ -252,7 +303,7 @@ class _StadiumToCircleBorder extends OutlinedBorder {
@override @override
Path getInnerPath(Rect rect, { TextDirection? textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
return Path() return Path()
..addRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)).deflate(side.strokeInset)); ..addRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)).deflate(side.width));
} }
@override @override
...@@ -276,8 +327,25 @@ class _StadiumToCircleBorder extends OutlinedBorder { ...@@ -276,8 +327,25 @@ class _StadiumToCircleBorder extends OutlinedBorder {
case BorderStyle.none: case BorderStyle.none:
break; break;
case BorderStyle.solid: case BorderStyle.solid:
final RRect borderRect = _adjustBorderRadius(rect).toRRect(_adjustRect(rect)); final double width = side.width;
canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); if (width == 0.0) {
canvas.drawRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)), side.toPaint());
} else {
final RRect borderRect = _adjustBorderRadius(rect).toRRect(_adjustRect(rect));
final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(width / 2);
break;
case StrokeAlign.center:
adjustedRect = borderRect;
break;
case StrokeAlign.outside:
adjustedRect = borderRect.inflate(width / 2);
break;
}
canvas.drawRRect(adjustedRect, side.toPaint());
}
} }
} }
...@@ -317,6 +385,11 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { ...@@ -317,6 +385,11 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder {
final double rectness; final double rectness;
@override
EdgeInsetsGeometry get dimensions {
return EdgeInsets.all(side.width);
}
@override @override
ShapeBorder scale(double t) { ShapeBorder scale(double t) {
return _StadiumToRoundedRectangleBorder( return _StadiumToRoundedRectangleBorder(
...@@ -391,7 +464,18 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { ...@@ -391,7 +464,18 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder {
@override @override
Path getInnerPath(Rect rect, { TextDirection? textDirection }) { Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
final RRect borderRect = _adjustBorderRadius(rect).toRRect(rect); final RRect borderRect = _adjustBorderRadius(rect).toRRect(rect);
final RRect adjustedRect = borderRect.deflate(ui.lerpDouble(side.width, 0, side.strokeAlign)!); final RRect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = borderRect.deflate(side.width);
break;
case StrokeAlign.center:
adjustedRect = borderRect.deflate(side.width / 2);
break;
case StrokeAlign.outside:
adjustedRect = borderRect;
break;
}
return Path() return Path()
..addRRect(adjustedRect); ..addRRect(adjustedRect);
} }
...@@ -417,9 +501,26 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { ...@@ -417,9 +501,26 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder {
case BorderStyle.none: case BorderStyle.none:
break; break;
case BorderStyle.solid: case BorderStyle.solid:
final BorderRadius adjustedBorderRadius = _adjustBorderRadius(rect); final double width = side.width;
final RRect borderRect = adjustedBorderRadius.resolve(textDirection).toRRect(rect); if (width == 0.0) {
canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); canvas.drawRRect(_adjustBorderRadius(rect).toRRect(rect), side.toPaint());
} else {
if (side.strokeAlign == StrokeAlign.inside) {
final RRect outer = _adjustBorderRadius(rect).toRRect(rect);
final RRect inner = outer.deflate(width);
final Paint paint = Paint()
..color = side.color;
canvas.drawDRRect(outer, inner, paint);
} else {
final RRect outer;
if (side.strokeAlign == StrokeAlign.center) {
outer = _adjustBorderRadius(rect).toRRect(rect);
} else {
outer = _adjustBorderRadius(rect.inflate(width)).toRRect(rect.inflate(width / 2));
}
canvas.drawRRect(outer, side.toPaint());
}
}
} }
} }
......
...@@ -11,6 +11,7 @@ import 'package:vector_math/vector_math_64.dart' show Matrix4; ...@@ -11,6 +11,7 @@ import 'package:vector_math/vector_math_64.dart' show Matrix4;
import 'basic_types.dart'; import 'basic_types.dart';
import 'borders.dart'; import 'borders.dart';
import 'circle_border.dart'; import 'circle_border.dart';
import 'edge_insets.dart';
import 'rounded_rectangle_border.dart'; import 'rounded_rectangle_border.dart';
import 'stadium_border.dart'; import 'stadium_border.dart';
...@@ -165,6 +166,18 @@ class StarBorder extends OutlinedBorder { ...@@ -165,6 +166,18 @@ class StarBorder extends OutlinedBorder {
/// Defaults to zero, and must be between zero and one, inclusive. /// Defaults to zero, and must be between zero and one, inclusive.
final double squash; final double squash;
@override
EdgeInsetsGeometry get dimensions {
switch (side.strokeAlign) {
case StrokeAlign.inside:
return EdgeInsets.all(side.width);
case StrokeAlign.center:
return EdgeInsets.all(side.width / 2);
case StrokeAlign.outside:
return EdgeInsets.zero;
}
}
@override @override
ShapeBorder scale(double t) { ShapeBorder scale(double t) {
return StarBorder( return StarBorder(
...@@ -375,7 +388,18 @@ class StarBorder extends OutlinedBorder { ...@@ -375,7 +388,18 @@ class StarBorder extends OutlinedBorder {
@override @override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) { Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
final Rect adjustedRect = rect.deflate(side.strokeInset); final Rect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = rect.deflate(side.width);
break;
case StrokeAlign.center:
adjustedRect = rect.deflate(side.width / 2);
break;
case StrokeAlign.outside:
adjustedRect = rect;
break;
}
return _StarGenerator( return _StarGenerator(
points: points, points: points,
rotation: _rotationRadians, rotation: _rotationRadians,
...@@ -404,7 +428,18 @@ class StarBorder extends OutlinedBorder { ...@@ -404,7 +428,18 @@ class StarBorder extends OutlinedBorder {
case BorderStyle.none: case BorderStyle.none:
break; break;
case BorderStyle.solid: case BorderStyle.solid:
final Rect adjustedRect = rect.inflate(side.strokeOffset / 2); final Rect adjustedRect;
switch (side.strokeAlign) {
case StrokeAlign.inside:
adjustedRect = rect.deflate(side.width / 2);
break;
case StrokeAlign.center:
adjustedRect = rect;
break;
case StrokeAlign.outside:
adjustedRect = rect.inflate(side.width / 2);
break;
}
final Path path = _StarGenerator( final Path path = _StarGenerator(
points: points, points: points,
rotation: _rotationRadians, rotation: _rotationRadians,
......
...@@ -51,7 +51,7 @@ void main() { ...@@ -51,7 +51,7 @@ void main() {
expect(description, <String>[ expect(description, <String>[
'backgroundColor: Color(0xffffffff)', 'backgroundColor: Color(0xffffffff)',
'elevation: 2.0', 'elevation: 2.0',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))',
'clipBehavior: Clip.antiAlias', 'clipBehavior: Clip.antiAlias',
'constraints: BoxConstraints(200.0<=w<=640.0, 0.0<=h<=Infinity)', 'constraints: BoxConstraints(200.0<=w<=640.0, 0.0<=h<=Infinity)',
]); ]);
......
...@@ -88,8 +88,8 @@ void main() { ...@@ -88,8 +88,8 @@ void main() {
'minimumSize: MaterialStatePropertyAll(Size(1.0, 2.0))', 'minimumSize: MaterialStatePropertyAll(Size(1.0, 2.0))',
'maximumSize: MaterialStatePropertyAll(Size(100.0, 200.0))', 'maximumSize: MaterialStatePropertyAll(Size(100.0, 200.0))',
'iconSize: MaterialStatePropertyAll(48.1)', 'iconSize: MaterialStatePropertyAll(48.1)',
'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff6), width: 4.0))', 'side: MaterialStatePropertyAll(BorderSide(Color(0xfffffff6), 4.0, BorderStyle.solid))',
'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))', 'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none)))',
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(forbidden))', 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(forbidden))',
'tapTargetSize: shrinkWrap', 'tapTargetSize: shrinkWrap',
'animationDuration: 0:00:01.000000', 'animationDuration: 0:00:01.000000',
......
...@@ -119,8 +119,8 @@ void main() { ...@@ -119,8 +119,8 @@ void main() {
'checkMarkColor: Color(0xfffffff7)', 'checkMarkColor: Color(0xfffffff7)',
'labelPadding: EdgeInsets.all(1.0)', 'labelPadding: EdgeInsets.all(1.0)',
'padding: EdgeInsets.all(2.0)', 'padding: EdgeInsets.all(2.0)',
'side: BorderSide(width: 10.0)', 'side: BorderSide(Color(0xff000000), 10.0, BorderStyle.solid)',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)',
'labelStyle: TextStyle(inherit: true, size: 10.0)', 'labelStyle: TextStyle(inherit: true, size: 10.0)',
'secondaryLabelStyle: TextStyle(inherit: true, size: 20.0)', 'secondaryLabelStyle: TextStyle(inherit: true, size: 20.0)',
'brightness: dark', 'brightness: dark',
......
...@@ -43,7 +43,7 @@ void main() { ...@@ -43,7 +43,7 @@ void main() {
'backgroundColor: Color(0x00000099)', 'backgroundColor: Color(0x00000099)',
'scrimColor: Color(0x00000098)', 'scrimColor: Color(0x00000098)',
'elevation: 5.0', 'elevation: 5.0',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))',
'width: 200.0', 'width: 200.0',
]); ]);
}); });
......
...@@ -307,7 +307,7 @@ void main() { ...@@ -307,7 +307,7 @@ void main() {
'hoverElevation: 10.0', 'hoverElevation: 10.0',
'disabledElevation: 11.0', 'disabledElevation: 11.0',
'highlightElevation: 43.0', 'highlightElevation: 43.0',
'shape: BeveledRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'shape: BeveledRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)',
'enableFeedback: true', 'enableFeedback: true',
'iconSize: 42.0', 'iconSize: 42.0',
'sizeConstraints: BoxConstraints(w=100.0, h=100.0)', 'sizeConstraints: BoxConstraints(w=100.0, h=100.0)',
......
...@@ -2286,7 +2286,7 @@ void main() { ...@@ -2286,7 +2286,7 @@ void main() {
'isThreeLine: THREE_LINE', 'isThreeLine: THREE_LINE',
'dense: true', 'dense: true',
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)', 'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)',
'style: ListTileStyle.list', 'style: ListTileStyle.list',
'selectedColor: Color(0xff0000ff)', 'selectedColor: Color(0xff0000ff)',
'iconColor: Color(0xff00ff00)', 'iconColor: Color(0xff00ff00)',
......
...@@ -111,7 +111,7 @@ void main() { ...@@ -111,7 +111,7 @@ void main() {
description, description,
equalsIgnoringHashCodes(<String>[ equalsIgnoringHashCodes(<String>[
'dense: true', 'dense: true',
'shape: StadiumBorder(BorderSide(width: 0.0, style: none))', 'shape: StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none))',
'style: drawer', 'style: drawer',
'selectedColor: Color(0x00000001)', 'selectedColor: Color(0x00000001)',
'iconColor: Color(0x00000002)', 'iconColor: Color(0x00000002)',
......
...@@ -46,7 +46,7 @@ void main() { ...@@ -46,7 +46,7 @@ void main() {
expect(description[1], 'backgroundColor: Color(0x00000099)'); expect(description[1], 'backgroundColor: Color(0x00000099)');
expect(description[2], 'elevation: 20.0'); expect(description[2], 'elevation: 20.0');
expect(description[3], 'indicatorColor: Color(0x00000098)'); expect(description[3], 'indicatorColor: Color(0x00000098)');
expect(description[4], 'indicatorShape: CircleBorder(BorderSide(width: 0.0, style: none))'); expect(description[4], 'indicatorShape: CircleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none))');
expect(description[5], 'labelTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 7.0))'); expect(description[5], 'labelTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 7.0))');
// Ignore instance address for IconThemeData. // Ignore instance address for IconThemeData.
......
...@@ -60,7 +60,7 @@ void main() { ...@@ -60,7 +60,7 @@ void main() {
expect(description, <String>[ expect(description, <String>[
'color: Color(0xffffffff)', 'color: Color(0xffffffff)',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))',
'elevation: 2.0', 'elevation: 2.0',
'text style: TextStyle(inherit: true, color: Color(0xffffffff))', 'text style: TextStyle(inherit: true, color: Color(0xffffffff))',
'mouseCursor: MaterialStateMouseCursor(clickable)', 'mouseCursor: MaterialStateMouseCursor(clickable)',
......
...@@ -58,7 +58,7 @@ void main() { ...@@ -58,7 +58,7 @@ void main() {
'disabledActionTextColor: Color(0xff00aa00)', 'disabledActionTextColor: Color(0xff00aa00)',
'contentTextStyle: TextStyle(inherit: true, color: Color(0xff123456))', 'contentTextStyle: TextStyle(inherit: true, color: Color(0xff123456))',
'elevation: 2.0', 'elevation: 2.0',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))',
'behavior: SnackBarBehavior.floating', 'behavior: SnackBarBehavior.floating',
]); ]);
}); });
......
...@@ -86,10 +86,10 @@ void main() { ...@@ -86,10 +86,10 @@ void main() {
'hourMinuteTextStyle: TextStyle(<all styles inherited>)', 'hourMinuteTextStyle: TextStyle(<all styles inherited>)',
'dayPeriodTextStyle: TextStyle(<all styles inherited>)', 'dayPeriodTextStyle: TextStyle(<all styles inherited>)',
'helpTextStyle: TextStyle(<all styles inherited>)', 'helpTextStyle: TextStyle(<all styles inherited>)',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)',
'hourMinuteShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'hourMinuteShape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)',
'dayPeriodShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'dayPeriodShape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)',
'dayPeriodBorderSide: BorderSide', 'dayPeriodBorderSide: BorderSide(Color(0xff000000), 1.0, BorderStyle.solid)',
]); ]);
}); });
......
...@@ -110,8 +110,8 @@ void main() { ...@@ -110,8 +110,8 @@ void main() {
test('BeveledRectangleBorder with StrokeAlign', () { test('BeveledRectangleBorder with StrokeAlign', () {
const BorderRadius borderRadius = BorderRadius.all(Radius.circular(10)); const BorderRadius borderRadius = BorderRadius.all(Radius.circular(10));
const BeveledRectangleBorder inside = BeveledRectangleBorder(side: BorderSide(width: 10.0), borderRadius: borderRadius); const BeveledRectangleBorder inside = BeveledRectangleBorder(side: BorderSide(width: 10.0), borderRadius: borderRadius);
const BeveledRectangleBorder center = BeveledRectangleBorder(side: BorderSide(width: 10.0, strokeAlign: BorderSide.strokeAlignCenter), borderRadius: borderRadius); const BeveledRectangleBorder center = BeveledRectangleBorder(side: BorderSide(width: 10.0, strokeAlign: StrokeAlign.center), borderRadius: borderRadius);
const BeveledRectangleBorder outside = BeveledRectangleBorder(side: BorderSide(width: 10.0, strokeAlign: BorderSide.strokeAlignOutside), borderRadius: borderRadius); const BeveledRectangleBorder outside = BeveledRectangleBorder(side: BorderSide(width: 10.0, strokeAlign: StrokeAlign.outside), borderRadius: borderRadius);
expect(inside.dimensions, const EdgeInsets.all(10.0)); expect(inside.dimensions, const EdgeInsets.all(10.0));
expect(center.dimensions, const EdgeInsets.all(5.0)); expect(center.dimensions, const EdgeInsets.all(5.0));
expect(outside.dimensions, EdgeInsets.zero); expect(outside.dimensions, EdgeInsets.zero);
......
...@@ -142,7 +142,8 @@ void main() { ...@@ -142,7 +142,8 @@ void main() {
' BoxBorder.lerp() was called with two objects of type SillyBorder\n' ' BoxBorder.lerp() was called with two objects of type SillyBorder\n'
' and Border:\n' ' and Border:\n'
' SillyBorder()\n' ' SillyBorder()\n'
' Border.all(BorderSide(width: 0.0, style: none))\n' ' Border.all(BorderSide(Color(0xff000000), 0.0,\n'
' BorderStyle.none))\n'
' However, only Border and BorderDirectional classes are supported\n' ' However, only Border and BorderDirectional classes are supported\n'
' by this method.\n' ' by this method.\n'
' For a more general interpolation method, consider using\n' ' For a more general interpolation method, consider using\n'
......
...@@ -119,21 +119,21 @@ void main() { ...@@ -119,21 +119,21 @@ void main() {
test('BorderSide - toString', () { test('BorderSide - toString', () {
expect( expect(
const BorderSide(color: Color(0xFFAABBCC), width: 1.2345).toString(), const BorderSide(color: Color(0xFFAABBCC), width: 1.2345).toString(),
'BorderSide(color: Color(0xffaabbcc), width: 1.2)', 'BorderSide(Color(0xffaabbcc), 1.2, BorderStyle.solid)',
); );
}); });
test('BorderSide - lerp with strokeAlign', () { test('BorderSide - lerp with strokeAlign', () {
const BorderSide side0 = BorderSide(width: 2.0); const BorderSide side0 = BorderSide(width: 2.0, strokeAlign: StrokeAlign.center);
const BorderSide side1 = BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignOutside); const BorderSide side1 = BorderSide(width: 2.0, strokeAlign: StrokeAlign.outside);
expect(BorderSide.lerp(side0, side1, 0), const BorderSide(width: 2.0)); expect(BorderSide.lerp(side0, side1, 0), const BorderSide(width: 2.0, strokeAlign: StrokeAlign.center));
expect(BorderSide.lerp(side0, side1, 0.5), const BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignCenter)); expect(BorderSide.lerp(side0, side1, 0.5), const BorderSide(width: 0.0, strokeAlign: StrokeAlign.center));
expect(BorderSide.lerp(side0, side1, 1), const BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignOutside)); expect(BorderSide.lerp(side0, side1, 1), const BorderSide(width: 2.0, strokeAlign: StrokeAlign.outside));
const BorderSide side2 = BorderSide(width: 2.0); const BorderSide side2 = BorderSide(width: 2.0);
const BorderSide side3 = BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignCenter); const BorderSide side3 = BorderSide(width: 2.0, strokeAlign: StrokeAlign.center);
expect(BorderSide.lerp(side2, side3, 0), const BorderSide(width: 2.0)); expect(BorderSide.lerp(side2, side3, 0), const BorderSide(width: 2.0));
expect(BorderSide.lerp(side2, side3, 0.5), const BorderSide(width: 2.0, strokeAlign: -0.5)); expect(BorderSide.lerp(side2, side3, 0.5), const BorderSide(width: 0.0));
expect(BorderSide.lerp(side2, side3, 1), const BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignCenter)); expect(BorderSide.lerp(side2, side3, 1), const BorderSide(width: 2.0, strokeAlign: StrokeAlign.center));
}); });
} }
...@@ -202,8 +202,8 @@ void main() { ...@@ -202,8 +202,8 @@ void main() {
expect( expect(
const Border( const Border(
left: BorderSide(), left: BorderSide(),
top: BorderSide(strokeAlign: BorderSide.strokeAlignCenter), top: BorderSide(strokeAlign: StrokeAlign.center),
right: BorderSide(strokeAlign: BorderSide.strokeAlignOutside), right: BorderSide(strokeAlign: StrokeAlign.outside),
).isUniform, ).isUniform,
false, false,
); );
...@@ -262,10 +262,10 @@ void main() { ...@@ -262,10 +262,10 @@ void main() {
try { try {
final TestCanvas canvas = TestCanvas(); final TestCanvas canvas = TestCanvas();
// Border.all supports all StrokeAlign values. // Border.all supports all StrokeAlign values.
// Border() supports [BorderSide.strokeAlignInside] only. // Border() supports StrokeAlign.inside only.
const Border( const Border(
left: BorderSide(strokeAlign: BorderSide.strokeAlignCenter), left: BorderSide(strokeAlign: StrokeAlign.center),
right: BorderSide(strokeAlign: BorderSide.strokeAlignOutside), right: BorderSide(strokeAlign: StrokeAlign.outside),
).paint(canvas, const Rect.fromLTWH(10.0, 20.0, 30.0, 40.0)); ).paint(canvas, const Rect.fromLTWH(10.0, 20.0, 30.0, 40.0));
} on FlutterError catch (e) { } on FlutterError catch (e) {
error = e; error = e;
...@@ -274,7 +274,7 @@ void main() { ...@@ -274,7 +274,7 @@ void main() {
expect(error.diagnostics.length, 1); expect(error.diagnostics.length, 1);
expect( expect(
error.diagnostics[0].toStringDeep(), error.diagnostics[0].toStringDeep(),
'A Border can only draw strokeAlign different than\nBorderSide.strokeAlignInside on uniform borders.\n', 'A Border can only draw strokeAlign different than\nStrokeAlign.inside on uniform borders.\n',
); );
}); });
...@@ -282,21 +282,21 @@ void main() { ...@@ -282,21 +282,21 @@ void main() {
final Border insideBorder = Border.all(width: 10); final Border insideBorder = Border.all(width: 10);
expect(insideBorder.dimensions, const EdgeInsets.all(10)); expect(insideBorder.dimensions, const EdgeInsets.all(10));
final Border centerBorder = Border.all(width: 10, strokeAlign: BorderSide.strokeAlignCenter); final Border centerBorder = Border.all(width: 10, strokeAlign: StrokeAlign.center);
expect(centerBorder.dimensions, const EdgeInsets.all(5)); expect(centerBorder.dimensions, const EdgeInsets.all(5));
final Border outsideBorder = Border.all(width: 10, strokeAlign: BorderSide.strokeAlignOutside); final Border outsideBorder = Border.all(width: 10, strokeAlign: StrokeAlign.outside);
expect(outsideBorder.dimensions, EdgeInsets.zero); expect(outsideBorder.dimensions, EdgeInsets.zero);
const BorderSide insideSide = BorderSide(width: 10); const BorderSide insideSide = BorderSide(width: 10);
const BorderDirectional insideBorderDirectional = BorderDirectional(top: insideSide, bottom: insideSide, start: insideSide, end: insideSide); const BorderDirectional insideBorderDirectional = BorderDirectional(top: insideSide, bottom: insideSide, start: insideSide, end: insideSide);
expect(insideBorderDirectional.dimensions, const EdgeInsetsDirectional.all(10)); expect(insideBorderDirectional.dimensions, const EdgeInsetsDirectional.all(10));
const BorderSide centerSide = BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter); const BorderSide centerSide = BorderSide(width: 10, strokeAlign: StrokeAlign.center);
const BorderDirectional centerBorderDirectional = BorderDirectional(top: centerSide, bottom: centerSide, start: centerSide, end: centerSide); const BorderDirectional centerBorderDirectional = BorderDirectional(top: centerSide, bottom: centerSide, start: centerSide, end: centerSide);
expect(centerBorderDirectional.dimensions, const EdgeInsetsDirectional.all(5)); expect(centerBorderDirectional.dimensions, const EdgeInsetsDirectional.all(5));
const BorderSide outsideSide = BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignOutside); const BorderSide outsideSide = BorderSide(width: 10, strokeAlign: StrokeAlign.outside);
const BorderDirectional outsideBorderDirectional = BorderDirectional(top: outsideSide, bottom: outsideSide, start: outsideSide, end: outsideSide); const BorderDirectional outsideBorderDirectional = BorderDirectional(top: outsideSide, bottom: outsideSide, start: outsideSide, end: outsideSide);
expect(outsideBorderDirectional.dimensions, EdgeInsetsDirectional.zero); expect(outsideBorderDirectional.dimensions, EdgeInsetsDirectional.zero);
}); });
......
...@@ -54,8 +54,8 @@ void main() { ...@@ -54,8 +54,8 @@ void main() {
style: BorderStyle.solid, style: BorderStyle.solid,
); );
expect(side1.toString(), equals('BorderSide')); expect(side1.toString(), equals('BorderSide(Color(0xff000000), 1.0, BorderStyle.solid)'));
expect(side2.toString(), equals('BorderSide(color: Color(0xff00ffff), width: 2.0)')); expect(side2.toString(), equals('BorderSide(Color(0xff00ffff), 2.0, BorderStyle.solid)'));
}); });
test('Border control test', () { test('Border control test', () {
...@@ -76,7 +76,9 @@ void main() { ...@@ -76,7 +76,9 @@ void main() {
test('Border toString test', () { test('Border toString test', () {
expect( expect(
Border.all(width: 4.0).toString(), Border.all(width: 4.0).toString(),
equals('Border.all(BorderSide(width: 4.0))'), equals(
'Border.all(BorderSide(Color(0xff000000), 4.0, BorderStyle.solid))',
),
); );
expect( expect(
const Border( const Border(
...@@ -85,7 +87,9 @@ void main() { ...@@ -85,7 +87,9 @@ void main() {
bottom: BorderSide(width: 3.0), bottom: BorderSide(width: 3.0),
left: BorderSide(width: 3.0), left: BorderSide(width: 3.0),
).toString(), ).toString(),
equals('Border.all(BorderSide(width: 3.0))'), equals(
'Border.all(BorderSide(Color(0xff000000), 3.0, BorderStyle.solid))',
),
); );
}); });
......
...@@ -97,28 +97,28 @@ void main() { ...@@ -97,28 +97,28 @@ void main() {
expect( expect(
ShapeBorder.lerp(r, c, 0.1).toString(), ShapeBorder.lerp(r, c, 0.1).toString(),
'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)', 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(r, c, 0.2).toString(), ShapeBorder.lerp(r, c, 0.2).toString(),
'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)', 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.9), 0.9).toString(), ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.9), 0.9).toString(),
'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)', 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(c, r, 0.9).toString(), ShapeBorder.lerp(c, r, 0.9).toString(),
'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)', 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(c, r, 0.8).toString(), ShapeBorder.lerp(c, r, 0.8).toString(),
'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)', 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.9), ShapeBorder.lerp(r, c, 0.1), 0.1).toString(), ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.9), ShapeBorder.lerp(r, c, 0.1), 0.1).toString(),
'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)', 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)',
); );
expect(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.1)); expect(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.1));
...@@ -135,26 +135,19 @@ void main() { ...@@ -135,26 +135,19 @@ void main() {
const RoundedRectangleBorder insideRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10)); const RoundedRectangleBorder insideRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10));
expect(insideRoundedRectangleBorder.dimensions, const EdgeInsets.all(10)); expect(insideRoundedRectangleBorder.dimensions, const EdgeInsets.all(10));
const RoundedRectangleBorder centerRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter)); const RoundedRectangleBorder centerRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10, strokeAlign: StrokeAlign.center));
expect(centerRoundedRectangleBorder.dimensions, const EdgeInsets.all(5)); expect(centerRoundedRectangleBorder.dimensions, const EdgeInsets.all(5));
const RoundedRectangleBorder outsideRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignOutside)); const RoundedRectangleBorder outsideRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10, strokeAlign: StrokeAlign.outside));
expect(outsideRoundedRectangleBorder.dimensions, EdgeInsets.zero); expect(outsideRoundedRectangleBorder.dimensions, EdgeInsets.zero);
const CircleBorder insideCircleBorder = CircleBorder(side: BorderSide(width: 10)); const CircleBorder insideCircleBorder = CircleBorder(side: BorderSide(width: 10));
expect(insideCircleBorder.dimensions, const EdgeInsets.all(10)); expect(insideCircleBorder.dimensions, const EdgeInsets.all(10));
const CircleBorder centerCircleBorder = CircleBorder(side: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter)); const CircleBorder centerCircleBorder = CircleBorder(side: BorderSide(width: 10, strokeAlign: StrokeAlign.center));
expect(centerCircleBorder.dimensions, const EdgeInsets.all(5)); expect(centerCircleBorder.dimensions, const EdgeInsets.all(5));
const CircleBorder outsideCircleBorder = CircleBorder(side: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignOutside)); const CircleBorder outsideCircleBorder = CircleBorder(side: BorderSide(width: 10, strokeAlign: StrokeAlign.outside));
expect(outsideCircleBorder.dimensions, EdgeInsets.zero); expect(outsideCircleBorder.dimensions, EdgeInsets.zero);
}); });
test('RoundedRectangleBorder.lerp with different StrokeAlign', () {
const RoundedRectangleBorder rInside = RoundedRectangleBorder(side: BorderSide(width: 10.0));
const RoundedRectangleBorder rOutside = RoundedRectangleBorder(side: BorderSide(width: 20.0, strokeAlign: BorderSide.strokeAlignOutside));
const RoundedRectangleBorder rCenter = RoundedRectangleBorder(side: BorderSide(width: 15.0, strokeAlign: BorderSide.strokeAlignCenter));
expect(ShapeBorder.lerp(rInside, rOutside, 0.5), rCenter);
});
} }
...@@ -48,8 +48,8 @@ void main() { ...@@ -48,8 +48,8 @@ void main() {
}); });
test('StadiumBorder with StrokeAlign', () { test('StadiumBorder with StrokeAlign', () {
const StadiumBorder center = StadiumBorder(side: BorderSide(width: 10.0, strokeAlign: BorderSide.strokeAlignCenter)); const StadiumBorder center = StadiumBorder(side: BorderSide(width: 10.0, strokeAlign: StrokeAlign.center));
const StadiumBorder outside = StadiumBorder(side: BorderSide(width: 10.0, strokeAlign: BorderSide.strokeAlignOutside)); const StadiumBorder outside = StadiumBorder(side: BorderSide(width: 10.0, strokeAlign: StrokeAlign.outside));
expect(center.dimensions, const EdgeInsets.all(5.0)); expect(center.dimensions, const EdgeInsets.all(5.0));
expect(outside.dimensions, EdgeInsets.zero); expect(outside.dimensions, EdgeInsets.zero);
...@@ -103,28 +103,28 @@ void main() { ...@@ -103,28 +103,28 @@ void main() {
expect( expect(
ShapeBorder.lerp(stadium, circle, 0.1).toString(), ShapeBorder.lerp(stadium, circle, 0.1).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), 10.0% of the way to being a CircleBorder)', 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 10.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(stadium, circle, 0.2).toString(), ShapeBorder.lerp(stadium, circle, 0.2).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), 20.0% of the way to being a CircleBorder)', 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 20.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(ShapeBorder.lerp(stadium, circle, 0.1), ShapeBorder.lerp(stadium, circle, 0.9), 0.9).toString(), ShapeBorder.lerp(ShapeBorder.lerp(stadium, circle, 0.1), ShapeBorder.lerp(stadium, circle, 0.9), 0.9).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), 82.0% of the way to being a CircleBorder)', 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 82.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(circle, stadium, 0.9).toString(), ShapeBorder.lerp(circle, stadium, 0.9).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), 10.0% of the way to being a CircleBorder)', 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 10.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(circle, stadium, 0.8).toString(), ShapeBorder.lerp(circle, stadium, 0.8).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), 20.0% of the way to being a CircleBorder)', 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 20.0% of the way to being a CircleBorder)',
); );
expect( expect(
ShapeBorder.lerp(ShapeBorder.lerp(stadium, circle, 0.9), ShapeBorder.lerp(stadium, circle, 0.1), 0.1).toString(), ShapeBorder.lerp(ShapeBorder.lerp(stadium, circle, 0.9), ShapeBorder.lerp(stadium, circle, 0.1), 0.1).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), 82.0% of the way to being a CircleBorder)', 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 82.0% of the way to being a CircleBorder)',
); );
expect(ShapeBorder.lerp(stadium, circle, 0.1), ShapeBorder.lerp(stadium, circle, 0.1)); expect(ShapeBorder.lerp(stadium, circle, 0.1), ShapeBorder.lerp(stadium, circle, 0.1));
...@@ -182,33 +182,33 @@ void main() { ...@@ -182,33 +182,33 @@ void main() {
expect( expect(
ShapeBorder.lerp(stadium, rrect, 0.1).toString(), ShapeBorder.lerp(stadium, rrect, 0.1).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), '
'BorderRadius.zero, 10.0% of the way to being a RoundedRectangleBorder)', 'BorderRadius.zero, 10.0% of the way to being a RoundedRectangleBorder)',
); );
expect( expect(
ShapeBorder.lerp(stadium, rrect, 0.2).toString(), ShapeBorder.lerp(stadium, rrect, 0.2).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), '
'BorderRadius.zero, 20.0% of the way to being a RoundedRectangleBorder)', 'BorderRadius.zero, 20.0% of the way to being a RoundedRectangleBorder)',
); );
expect( expect(
ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.9).toString(), ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.9).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), '
'BorderRadius.zero, 82.0% of the way to being a RoundedRectangleBorder)', 'BorderRadius.zero, 82.0% of the way to being a RoundedRectangleBorder)',
); );
expect( expect(
ShapeBorder.lerp(rrect, stadium, 0.9).toString(), ShapeBorder.lerp(rrect, stadium, 0.9).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), '
'BorderRadius.zero, 10.0% of the way to being a RoundedRectangleBorder)', 'BorderRadius.zero, 10.0% of the way to being a RoundedRectangleBorder)',
); );
expect( expect(
ShapeBorder.lerp(rrect, stadium, 0.8).toString(), ShapeBorder.lerp(rrect, stadium, 0.8).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), '
'BorderRadius.zero, 20.0% of the way to being a RoundedRectangleBorder)', 'BorderRadius.zero, 20.0% of the way to being a RoundedRectangleBorder)',
); );
expect( expect(
ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), ShapeBorder.lerp(stadium, rrect, 0.1), 0.1).toString(), ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), ShapeBorder.lerp(stadium, rrect, 0.1), 0.1).toString(),
'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), '
'BorderRadius.zero, 82.0% of the way to being a RoundedRectangleBorder)', 'BorderRadius.zero, 82.0% of the way to being a RoundedRectangleBorder)',
); );
......
...@@ -105,9 +105,9 @@ void main() { ...@@ -105,9 +105,9 @@ void main() {
await testBorder(tester, 'side_1', const StarBorder(side: BorderSide(color: Color(0xffff0000)))); await testBorder(tester, 'side_1', const StarBorder(side: BorderSide(color: Color(0xffff0000))));
await testBorder(tester, 'side_10', const StarBorder(side: BorderSide(color: Color(0xffff0000), width: 10))); await testBorder(tester, 'side_10', const StarBorder(side: BorderSide(color: Color(0xffff0000), width: 10)));
await testBorder(tester, 'side_align_center', await testBorder(tester, 'side_align_center',
const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignCenter))); const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: StrokeAlign.center)));
await testBorder(tester, 'side_align_outside', await testBorder(tester, 'side_align_outside',
const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignOutside))); const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: StrokeAlign.outside)));
}); });
testWidgets('StarBorder.polygon parameters', (WidgetTester tester) async { testWidgets('StarBorder.polygon parameters', (WidgetTester tester) async {
...@@ -127,9 +127,9 @@ void main() { ...@@ -127,9 +127,9 @@ void main() {
await testBorder( await testBorder(
tester, 'poly_side_10', const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), width: 10))); tester, 'poly_side_10', const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), width: 10)));
await testBorder(tester, 'poly_side_align_center', await testBorder(tester, 'poly_side_align_center',
const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignCenter))); const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: StrokeAlign.center)));
await testBorder(tester, 'poly_side_align_outside', await testBorder(tester, 'poly_side_align_outside',
const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignOutside))); const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: StrokeAlign.outside)));
}); });
testWidgets('StarBorder lerped with StarBorder', (WidgetTester tester) async { testWidgets('StarBorder lerped with StarBorder', (WidgetTester tester) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment