Border RTL (#12407)
This commit is contained in:
parent
cc3f5767f4
commit
cd3715a854
@ -194,10 +194,13 @@ class BorderSide {
|
|||||||
return a;
|
return a;
|
||||||
if (t == 1.0)
|
if (t == 1.0)
|
||||||
return b;
|
return b;
|
||||||
|
final double width = ui.lerpDouble(a.width, b.width, t);
|
||||||
|
if (width < 0.0)
|
||||||
|
return BorderSide.none;
|
||||||
if (a.style == b.style) {
|
if (a.style == b.style) {
|
||||||
return new BorderSide(
|
return new BorderSide(
|
||||||
color: Color.lerp(a.color, b.color, t),
|
color: Color.lerp(a.color, b.color, t),
|
||||||
width: math.max(0.0, ui.lerpDouble(a.width, b.width, t)),
|
width: width,
|
||||||
style: a.style, // == b.style
|
style: a.style, // == b.style
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -220,7 +223,7 @@ class BorderSide {
|
|||||||
}
|
}
|
||||||
return new BorderSide(
|
return new BorderSide(
|
||||||
color: Color.lerp(colorA, colorB, t),
|
color: Color.lerp(colorA, colorB, t),
|
||||||
width: math.max(0.0, ui.lerpDouble(a.width, b.width, t)),
|
width: width,
|
||||||
style: BorderStyle.solid,
|
style: BorderStyle.solid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
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';
|
||||||
@ -21,7 +23,180 @@ enum BoxShape {
|
|||||||
circle,
|
circle,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A border of a box, comprised of four sides.
|
/// Base class for box borders that can paint as rectangle, circles, or rounded
|
||||||
|
/// rectangles.
|
||||||
|
///
|
||||||
|
/// This class is extended by [Border] and [BorderDirectional] to provide
|
||||||
|
/// concrete versions of four-sided borders using different conventions for
|
||||||
|
/// specifying the sides.
|
||||||
|
///
|
||||||
|
/// The only API difference that this class introduces over [ShapeBorder] is
|
||||||
|
/// that its [paint] method takes additional arguments.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [BorderSide], which is used to describe each side of the box.
|
||||||
|
/// * [RoundedRectangleBorder], another way of describing a box's border.
|
||||||
|
/// * [CircleBorder], another way of describing a circle border.
|
||||||
|
/// * [BoxDecoration], which uses a [BoxBorder] to describe its borders.
|
||||||
|
abstract class BoxBorder extends ShapeBorder {
|
||||||
|
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||||
|
/// const constructors so that they can be used in const expressions.
|
||||||
|
const BoxBorder();
|
||||||
|
|
||||||
|
// We override this to tighten the return value, so that callers can assume
|
||||||
|
// that we'll return a BoxBorder.
|
||||||
|
@override
|
||||||
|
BoxBorder add(ShapeBorder other, { bool reversed: false }) => null;
|
||||||
|
|
||||||
|
/// Linearly interpolate between two borders.
|
||||||
|
///
|
||||||
|
/// If a border is null, it is treated as having four [BorderSide.none]
|
||||||
|
/// borders.
|
||||||
|
///
|
||||||
|
/// This supports interpolating between [Border] and [BorderDirectional]
|
||||||
|
/// objects. If both objects are different types but both have sides on one or
|
||||||
|
/// both of their lateral edges (the two sides that aren't the top and bottom)
|
||||||
|
/// other than [BorderSide.none], then the sides are interpolated by reducing
|
||||||
|
/// `a`'s lateral edges to [BorderSide.none] over the first half of the
|
||||||
|
/// animation, and then bringing `b`'s lateral edges _from_ [BorderSide.none]
|
||||||
|
/// over the second half of the animation.
|
||||||
|
///
|
||||||
|
/// For a more flexible approach, consider [ShapeBorder.lerp], which would
|
||||||
|
/// instead [add] the two sets of sides and interpolate them simultaneously.
|
||||||
|
static BoxBorder lerp(BoxBorder a, BoxBorder b, double t) {
|
||||||
|
if ((a is Border || a == null) && (b is Border || b == null))
|
||||||
|
return Border.lerp(a, b, t);
|
||||||
|
if ((a is BorderDirectional || a == null) && (b is BorderDirectional || b == null))
|
||||||
|
return BorderDirectional.lerp(a, b, t);
|
||||||
|
if (b is Border && a is BorderDirectional) {
|
||||||
|
final BoxBorder c = b;
|
||||||
|
b = a;
|
||||||
|
a = c;
|
||||||
|
t = 1.0 - t;
|
||||||
|
// fall through to next case
|
||||||
|
}
|
||||||
|
if (a is Border && b is BorderDirectional) {
|
||||||
|
if (b.start == BorderSide.none && b.end == BorderSide.none) {
|
||||||
|
// The fact that b is a BorderDirectional really doesn't matter, it turns out.
|
||||||
|
return new Border(
|
||||||
|
top: BorderSide.lerp(a.top, b.top, t),
|
||||||
|
right: BorderSide.lerp(a.right, BorderSide.none, t),
|
||||||
|
bottom: BorderSide.lerp(a.bottom, b.bottom, t),
|
||||||
|
left: BorderSide.lerp(a.left, BorderSide.none, t),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (a.left == BorderSide.none && a.right == BorderSide.none) {
|
||||||
|
// The fact that a is a Border really doesn't matter, it turns out.
|
||||||
|
return new BorderDirectional(
|
||||||
|
top: BorderSide.lerp(a.top, b.top, t),
|
||||||
|
start: BorderSide.lerp(BorderSide.none, b.start, t),
|
||||||
|
end: BorderSide.lerp(BorderSide.none, b.end, t),
|
||||||
|
bottom: BorderSide.lerp(a.bottom, b.bottom, t),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Since we have to swap a visual border for a directional one,
|
||||||
|
// we speed up the horizontal sides' transitions and switch from
|
||||||
|
// one mode to the other at t=0.5.
|
||||||
|
if (t < 0.5) {
|
||||||
|
return new Border(
|
||||||
|
top: BorderSide.lerp(a.top, b.top, t),
|
||||||
|
right: BorderSide.lerp(a.right, BorderSide.none, t * 2.0),
|
||||||
|
bottom: BorderSide.lerp(a.bottom, b.bottom, t),
|
||||||
|
left: BorderSide.lerp(a.left, BorderSide.none, t * 2.0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return new BorderDirectional(
|
||||||
|
top: BorderSide.lerp(a.top, b.top, t),
|
||||||
|
start: BorderSide.lerp(BorderSide.none, b.start, (t - 0.5) * 2.0),
|
||||||
|
end: BorderSide.lerp(BorderSide.none, b.end, (t - 0.5) * 2.0),
|
||||||
|
bottom: BorderSide.lerp(a.bottom, b.bottom, t),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw new FlutterError(
|
||||||
|
'BoxBorder.lerp can only interpolate Border and BorderDirectional classes.\n'
|
||||||
|
'BoxBorder.lerp() was called with two objects of type ${a.runtimeType} and ${b.runtimeType}:\n'
|
||||||
|
' $a\n'
|
||||||
|
' $b\n'
|
||||||
|
'However, only Border and BorderDirectional classes are supported by this method. '
|
||||||
|
'For a more general interpolation method, consider using ShapeBorder.lerp instead.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Path getInnerPath(Rect rect, { @required TextDirection textDirection }) {
|
||||||
|
assert(textDirection != null, 'The textDirection argument to $runtimeType.getInnerPath must not be null.');
|
||||||
|
return new Path()
|
||||||
|
..addRect(dimensions.resolve(textDirection).deflateRect(rect));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Path getOuterPath(Rect rect, { @required TextDirection textDirection }) {
|
||||||
|
assert(textDirection != null, 'The textDirection argument to $runtimeType.getOuterPath must not be null.');
|
||||||
|
return new Path()
|
||||||
|
..addRect(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Paints the border within the given [Rect] on the given [Canvas].
|
||||||
|
///
|
||||||
|
/// This is an extension of the [ShapeBorder.paint] method. It allows
|
||||||
|
/// [BoxBorder] borders to be applied to different [BoxShape]s and with
|
||||||
|
/// different [borderRadius] parameters, without changing the [BoxBorder]
|
||||||
|
/// object itself.
|
||||||
|
///
|
||||||
|
/// The `shape` argument specifies the [BoxShape] to draw the border on.
|
||||||
|
///
|
||||||
|
/// If the `shape` is specifies a rectangular box shape
|
||||||
|
/// ([BoxShape.rectangle]), then the `borderRadius` argument describes the
|
||||||
|
/// corners of the rectangle.
|
||||||
|
///
|
||||||
|
/// The [getInnerPath] and [getOuterPath] methods do not know about the
|
||||||
|
/// `shape` and `borderRadius` arguments.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [paintBorder], which is used if the border is not uniform.
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Rect rect, {
|
||||||
|
TextDirection textDirection,
|
||||||
|
BoxShape shape: BoxShape.rectangle,
|
||||||
|
BorderRadius borderRadius,
|
||||||
|
});
|
||||||
|
|
||||||
|
static void _paintUniformBorderWithRadius(Canvas canvas, Rect rect, BorderSide side, BorderRadius borderRadius) {
|
||||||
|
assert(side.style != BorderStyle.none);
|
||||||
|
final Paint paint = new Paint()
|
||||||
|
..color = side.color;
|
||||||
|
final RRect outer = borderRadius.toRRect(rect);
|
||||||
|
final double width = side.width;
|
||||||
|
if (width == 0.0) {
|
||||||
|
paint
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = 0.0;
|
||||||
|
canvas.drawRRect(outer, paint);
|
||||||
|
} else {
|
||||||
|
final RRect inner = outer.deflate(width);
|
||||||
|
canvas.drawDRRect(outer, inner, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _paintUniformBorderWithCircle(Canvas canvas, Rect rect, BorderSide side) {
|
||||||
|
assert(side.style != BorderStyle.none);
|
||||||
|
final double width = side.width;
|
||||||
|
final Paint paint = side.toPaint();
|
||||||
|
final double radius = (rect.shortestSide - width) / 2.0;
|
||||||
|
canvas.drawCircle(rect.center, radius, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _paintUniformBorderWithRectangle(Canvas canvas, Rect rect, BorderSide side) {
|
||||||
|
assert(side.style != BorderStyle.none);
|
||||||
|
final double width = side.width;
|
||||||
|
final Paint paint = side.toPaint();
|
||||||
|
canvas.drawRect(rect.deflate(width / 2.0), paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A border of a box, comprised of four sides: top, right, bottom, left.
|
||||||
///
|
///
|
||||||
/// The sides are represented by [BorderSide] objects.
|
/// The sides are represented by [BorderSide] objects.
|
||||||
///
|
///
|
||||||
@ -77,16 +252,21 @@ enum BoxShape {
|
|||||||
/// * [BorderSide], which is used to describe each side of the box.
|
/// * [BorderSide], which is used to describe each side of the box.
|
||||||
/// * [Theme], from the material layer, which can be queried to obtain appropriate colors
|
/// * [Theme], from the material layer, which can be queried to obtain appropriate colors
|
||||||
/// to use for borders in a material app, as shown in the "divider" sample above.
|
/// to use for borders in a material app, as shown in the "divider" sample above.
|
||||||
class Border extends ShapeBorder {
|
class Border extends BoxBorder {
|
||||||
/// Creates a border.
|
/// Creates a border.
|
||||||
///
|
///
|
||||||
/// All the sides of the border default to [BorderSide.none].
|
/// All the sides of the border default to [BorderSide.none].
|
||||||
|
///
|
||||||
|
/// The arguments must not be null.
|
||||||
const Border({
|
const Border({
|
||||||
this.top: BorderSide.none,
|
this.top: BorderSide.none,
|
||||||
this.right: BorderSide.none,
|
this.right: BorderSide.none,
|
||||||
this.bottom: BorderSide.none,
|
this.bottom: BorderSide.none,
|
||||||
this.left: BorderSide.none,
|
this.left: BorderSide.none,
|
||||||
});
|
}) : assert(top != null),
|
||||||
|
assert(right != null),
|
||||||
|
assert(bottom != null),
|
||||||
|
assert(left != null);
|
||||||
|
|
||||||
/// A uniform border with all sides the same color and width.
|
/// A uniform border with all sides the same color and width.
|
||||||
///
|
///
|
||||||
@ -142,11 +322,6 @@ class Border extends ShapeBorder {
|
|||||||
/// Whether all four sides of the border are identical. Uniform borders are
|
/// Whether all four sides of the border are identical. Uniform borders are
|
||||||
/// typically more efficient to paint.
|
/// typically more efficient to paint.
|
||||||
bool get isUniform {
|
bool get isUniform {
|
||||||
assert(top != null);
|
|
||||||
assert(right != null);
|
|
||||||
assert(bottom != null);
|
|
||||||
assert(left != null);
|
|
||||||
|
|
||||||
final Color topColor = top.color;
|
final Color topColor = top.color;
|
||||||
if (right.color != topColor ||
|
if (right.color != topColor ||
|
||||||
bottom.color != topColor ||
|
bottom.color != topColor ||
|
||||||
@ -240,18 +415,6 @@ class Border extends ShapeBorder {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Path getInnerPath(Rect rect, { TextDirection textDirection }) {
|
|
||||||
return new Path()
|
|
||||||
..addRect(dimensions.resolve(textDirection).deflateRect(rect));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Path getOuterPath(Rect rect, { TextDirection textDirection }) {
|
|
||||||
return new Path()
|
|
||||||
..addRect(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Paints the border within the given [Rect] on the given [Canvas].
|
/// Paints the border within the given [Rect] on the given [Canvas].
|
||||||
///
|
///
|
||||||
/// Uniform borders are more efficient to paint than more complex borders.
|
/// Uniform borders are more efficient to paint than more complex borders.
|
||||||
@ -284,14 +447,14 @@ class Border extends ShapeBorder {
|
|||||||
case BorderStyle.solid:
|
case BorderStyle.solid:
|
||||||
if (shape == BoxShape.circle) {
|
if (shape == BoxShape.circle) {
|
||||||
assert(borderRadius == null, 'A borderRadius can only be given for rectangular boxes.');
|
assert(borderRadius == null, 'A borderRadius can only be given for rectangular boxes.');
|
||||||
_paintUniformBorderWithCircle(canvas, rect);
|
BoxBorder._paintUniformBorderWithCircle(canvas, rect, top);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (borderRadius != null) {
|
if (borderRadius != null) {
|
||||||
_paintUniformBorderWithRadius(canvas, rect, borderRadius);
|
BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_paintUniformBorderWithRectangle(canvas, rect);
|
BoxBorder._paintUniformBorderWithRectangle(canvas, rect, top);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,42 +465,6 @@ class Border extends ShapeBorder {
|
|||||||
paintBorder(canvas, rect, top: top, right: right, bottom: bottom, left: left);
|
paintBorder(canvas, rect, top: top, right: right, bottom: bottom, left: left);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _paintUniformBorderWithRadius(Canvas canvas, Rect rect,
|
|
||||||
BorderRadius borderRadius) {
|
|
||||||
assert(isUniform);
|
|
||||||
assert(top.style != BorderStyle.none);
|
|
||||||
final Paint paint = new Paint()
|
|
||||||
..color = top.color;
|
|
||||||
final RRect outer = borderRadius.toRRect(rect);
|
|
||||||
final double width = top.width;
|
|
||||||
if (width == 0.0) {
|
|
||||||
paint
|
|
||||||
..style = PaintingStyle.stroke
|
|
||||||
..strokeWidth = 0.0;
|
|
||||||
canvas.drawRRect(outer, paint);
|
|
||||||
} else {
|
|
||||||
final RRect inner = outer.deflate(width);
|
|
||||||
canvas.drawDRRect(outer, inner, paint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _paintUniformBorderWithCircle(Canvas canvas, Rect rect) {
|
|
||||||
assert(isUniform);
|
|
||||||
assert(top.style != BorderStyle.none);
|
|
||||||
final double width = top.width;
|
|
||||||
final Paint paint = top.toPaint();
|
|
||||||
final double radius = (rect.shortestSide - width) / 2.0;
|
|
||||||
canvas.drawCircle(rect.center, radius, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _paintUniformBorderWithRectangle(Canvas canvas, Rect rect) {
|
|
||||||
assert(isUniform);
|
|
||||||
assert(top.style != BorderStyle.none);
|
|
||||||
final double width = top.width;
|
|
||||||
final Paint paint = top.toPaint();
|
|
||||||
canvas.drawRect(rect.deflate(width / 2.0), paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
if (identical(this, other))
|
if (identical(this, other))
|
||||||
@ -358,6 +485,328 @@ class Border extends ShapeBorder {
|
|||||||
String toString() {
|
String toString() {
|
||||||
if (isUniform)
|
if (isUniform)
|
||||||
return 'Border.all($top)';
|
return 'Border.all($top)';
|
||||||
return 'Border($top, $right, $bottom, $left)';
|
final List<String> arguments = <String>[];
|
||||||
|
if (top != BorderSide.none)
|
||||||
|
arguments.add('top: $top');
|
||||||
|
if (right != BorderSide.none)
|
||||||
|
arguments.add('right: $right');
|
||||||
|
if (bottom != BorderSide.none)
|
||||||
|
arguments.add('bottom: $bottom');
|
||||||
|
if (left != BorderSide.none)
|
||||||
|
arguments.add('left: $left');
|
||||||
|
return 'Border(${arguments.join(", ")})';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A border of a box, comprised of four sides, the lateral sides of which
|
||||||
|
/// flip over based on the reading direction.
|
||||||
|
///
|
||||||
|
/// The lateral sides are called [start] and [end]. When painted in
|
||||||
|
/// left-to-right environments, the [start] side will be painted on the left and
|
||||||
|
/// the [end] side on the right; in right-to-left environments, it is the
|
||||||
|
/// reverse. The other two sides are [top] and [bottom].
|
||||||
|
///
|
||||||
|
/// The sides are represented by [BorderSide] objects.
|
||||||
|
///
|
||||||
|
/// If the [start] and [end] sides are the same, then it is slightly more
|
||||||
|
/// efficient to use a [Border] object rather than a [BorderDirectional] object.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [BoxDecoration], which uses this class to describe its edge decoration.
|
||||||
|
/// * [BorderSide], which is used to describe each side of the box.
|
||||||
|
/// * [Theme], from the material layer, which can be queried to obtain appropriate colors
|
||||||
|
/// to use for borders in a material app, as shown in the "divider" sample above.
|
||||||
|
class BorderDirectional extends BoxBorder {
|
||||||
|
/// Creates a border.
|
||||||
|
///
|
||||||
|
/// The [start] and [end] sides represent the horizontal sides; the start side
|
||||||
|
/// is on the leading edge given the reading direction, and the end side is on
|
||||||
|
/// the trailing edge. They are resolved during [paint].
|
||||||
|
///
|
||||||
|
/// All the sides of the border default to [BorderSide.none].
|
||||||
|
///
|
||||||
|
/// The arguments must not be null.
|
||||||
|
const BorderDirectional({
|
||||||
|
this.top: BorderSide.none,
|
||||||
|
this.start: BorderSide.none,
|
||||||
|
this.end: BorderSide.none,
|
||||||
|
this.bottom: BorderSide.none,
|
||||||
|
}) : assert(top != null),
|
||||||
|
assert(start != null),
|
||||||
|
assert(end != null),
|
||||||
|
assert(bottom != null);
|
||||||
|
|
||||||
|
/// Creates a [BorderDirectional] that represents the addition of the two
|
||||||
|
/// given [BorderDirectional]s.
|
||||||
|
///
|
||||||
|
/// It is only valid to call this if [BorderSide.canMerge] returns true for
|
||||||
|
/// the pairwise combination of each side on both [BorderDirectional]s.
|
||||||
|
///
|
||||||
|
/// The arguments must not be null.
|
||||||
|
static BorderDirectional merge(BorderDirectional a, BorderDirectional b) {
|
||||||
|
assert(a != null);
|
||||||
|
assert(b != null);
|
||||||
|
assert(BorderSide.canMerge(a.top, b.top));
|
||||||
|
assert(BorderSide.canMerge(a.start, b.start));
|
||||||
|
assert(BorderSide.canMerge(a.end, b.end));
|
||||||
|
assert(BorderSide.canMerge(a.bottom, b.bottom));
|
||||||
|
return new BorderDirectional(
|
||||||
|
top: BorderSide.merge(a.top, b.top),
|
||||||
|
start: BorderSide.merge(a.start, b.start),
|
||||||
|
end: BorderSide.merge(a.end, b.end),
|
||||||
|
bottom: BorderSide.merge(a.bottom, b.bottom),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The top side of this border.
|
||||||
|
final BorderSide top;
|
||||||
|
|
||||||
|
/// The start side of this border.
|
||||||
|
///
|
||||||
|
/// This is the side on the left in left-to-right text and on the right in
|
||||||
|
/// right-to-left text.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [TextDirection], which is used to describe the reading direction.
|
||||||
|
final BorderSide start;
|
||||||
|
|
||||||
|
/// The end side of this border.
|
||||||
|
///
|
||||||
|
/// This is the side on the right in left-to-right text and on the left in
|
||||||
|
/// right-to-left text.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [TextDirection], which is used to describe the reading direction.
|
||||||
|
final BorderSide end;
|
||||||
|
|
||||||
|
/// The bottom side of this border.
|
||||||
|
final BorderSide bottom;
|
||||||
|
|
||||||
|
@override
|
||||||
|
EdgeInsetsGeometry get dimensions {
|
||||||
|
return new EdgeInsetsDirectional.fromSTEB(start.width, top.width, end.width, bottom.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether all four sides of the border are identical. Uniform borders are
|
||||||
|
/// typically more efficient to paint.
|
||||||
|
bool get isUniform {
|
||||||
|
final Color topColor = top.color;
|
||||||
|
if (start.color != topColor ||
|
||||||
|
end.color != topColor ||
|
||||||
|
bottom.color != topColor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
final double topWidth = top.width;
|
||||||
|
if (start.width != topWidth ||
|
||||||
|
end.width != topWidth ||
|
||||||
|
bottom.width != topWidth)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
final BorderStyle topStyle = top.style;
|
||||||
|
if (start.style != topStyle ||
|
||||||
|
end.style != topStyle ||
|
||||||
|
bottom.style != topStyle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
BoxBorder add(ShapeBorder other, { bool reversed: false }) {
|
||||||
|
if (other is BorderDirectional) {
|
||||||
|
final BorderDirectional typedOther = other;
|
||||||
|
if (BorderSide.canMerge(top, typedOther.top) &&
|
||||||
|
BorderSide.canMerge(start, typedOther.start) &&
|
||||||
|
BorderSide.canMerge(end, typedOther.end) &&
|
||||||
|
BorderSide.canMerge(bottom, typedOther.bottom)) {
|
||||||
|
return BorderDirectional.merge(this, typedOther);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (other is Border) {
|
||||||
|
final Border typedOther = other;
|
||||||
|
if (!BorderSide.canMerge(typedOther.top, top) ||
|
||||||
|
!BorderSide.canMerge(typedOther.bottom, bottom))
|
||||||
|
return null;
|
||||||
|
if (start != BorderSide.none ||
|
||||||
|
end != BorderSide.none) {
|
||||||
|
if (typedOther.left != BorderSide.none ||
|
||||||
|
typedOther.right != BorderSide.none)
|
||||||
|
return null;
|
||||||
|
assert(typedOther.left == BorderSide.none);
|
||||||
|
assert(typedOther.right == BorderSide.none);
|
||||||
|
return new BorderDirectional(
|
||||||
|
top: BorderSide.merge(typedOther.top, top),
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
bottom: BorderSide.merge(typedOther.bottom, bottom),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert(start == BorderSide.none);
|
||||||
|
assert(end == BorderSide.none);
|
||||||
|
return new Border(
|
||||||
|
top: BorderSide.merge(typedOther.top, top),
|
||||||
|
right: typedOther.right,
|
||||||
|
bottom: BorderSide.merge(typedOther.bottom, bottom),
|
||||||
|
left: typedOther.left,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new border with the widths of this border multiplied by `t`.
|
||||||
|
@override
|
||||||
|
BorderDirectional scale(double t) {
|
||||||
|
return new BorderDirectional(
|
||||||
|
top: top.scale(t),
|
||||||
|
start: start.scale(t),
|
||||||
|
end: end.scale(t),
|
||||||
|
bottom: bottom.scale(t),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Linearly interpolates from `a` to [this].
|
||||||
|
///
|
||||||
|
/// If `a` is null, this defers to [scale].
|
||||||
|
///
|
||||||
|
/// If `a` is also a [BorderDirectional], this uses [BorderDirectional.lerp].
|
||||||
|
///
|
||||||
|
/// Otherwise, it defers to [ShapeBorder.lerpFrom].
|
||||||
|
@override
|
||||||
|
ShapeBorder lerpFrom(ShapeBorder a, double t) {
|
||||||
|
if (a is BorderDirectional)
|
||||||
|
return BorderDirectional.lerp(a, this, t);
|
||||||
|
return super.lerpFrom(a, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Linearly interpolates from [this] to `b`.
|
||||||
|
///
|
||||||
|
/// If `b` is null, this defers to [scale].
|
||||||
|
///
|
||||||
|
/// If `b` is also a [BorderDirectional], this uses [BorderDirectional.lerp].
|
||||||
|
///
|
||||||
|
/// Otherwise, it defers to [ShapeBorder.lerpTo].
|
||||||
|
@override
|
||||||
|
ShapeBorder lerpTo(ShapeBorder b, double t) {
|
||||||
|
if (b is BorderDirectional)
|
||||||
|
return BorderDirectional.lerp(this, b, t);
|
||||||
|
return super.lerpTo(b, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Linearly interpolate between two borders.
|
||||||
|
///
|
||||||
|
/// If a border is null, it is treated as having four [BorderSide.none]
|
||||||
|
/// borders.
|
||||||
|
static BorderDirectional lerp(BorderDirectional a, BorderDirectional b, double t) {
|
||||||
|
if (a == null && b == null)
|
||||||
|
return null;
|
||||||
|
if (a == null)
|
||||||
|
return b.scale(t);
|
||||||
|
if (b == null)
|
||||||
|
return a.scale(1.0 - t);
|
||||||
|
return new BorderDirectional(
|
||||||
|
top: BorderSide.lerp(a.top, b.top, t),
|
||||||
|
end: BorderSide.lerp(a.end, b.end, t),
|
||||||
|
bottom: BorderSide.lerp(a.bottom, b.bottom, t),
|
||||||
|
start: BorderSide.lerp(a.start, b.start, t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Paints the border within the given [Rect] on the given [Canvas].
|
||||||
|
///
|
||||||
|
/// Uniform borders are more efficient to paint than more complex borders.
|
||||||
|
///
|
||||||
|
/// You can provide a [BoxShape] to draw the border on. If the `shape` in
|
||||||
|
/// [BoxShape.circle], there is the requirement that the border [isUniform].
|
||||||
|
///
|
||||||
|
/// If you specify a rectangular box shape ([BoxShape.rectangle]), then you
|
||||||
|
/// may specify a [BorderRadius]. If a `borderRadius` is specified, there is
|
||||||
|
/// the requirement that the border [isUniform].
|
||||||
|
///
|
||||||
|
/// The [getInnerPath] and [getOuterPath] methods do not know about the
|
||||||
|
/// `shape` and `borderRadius` arguments.
|
||||||
|
///
|
||||||
|
/// The `textDirection` argument is used to determine which of [start] and
|
||||||
|
/// [end] map to the left and right. For [TextDirection.ltr], the [start] is
|
||||||
|
/// the left and the [end] is the right; for [TextDirection.rtl], it is the
|
||||||
|
/// reverse.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [paintBorder], which is used if the border is not uniform.
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Rect rect, {
|
||||||
|
TextDirection textDirection,
|
||||||
|
BoxShape shape: BoxShape.rectangle,
|
||||||
|
BorderRadius borderRadius,
|
||||||
|
}) {
|
||||||
|
if (isUniform) {
|
||||||
|
switch (top.style) {
|
||||||
|
case BorderStyle.none:
|
||||||
|
return;
|
||||||
|
case BorderStyle.solid:
|
||||||
|
if (shape == BoxShape.circle) {
|
||||||
|
assert(borderRadius == null, 'A borderRadius can only be given for rectangular boxes.');
|
||||||
|
BoxBorder._paintUniformBorderWithCircle(canvas, rect, top);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (borderRadius != null) {
|
||||||
|
BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BoxBorder._paintUniformBorderWithRectangle(canvas, rect, top);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.');
|
||||||
|
|
||||||
|
BorderSide left, right;
|
||||||
|
assert(textDirection != null, 'Non-uniform BorderDirectional objects require a TextDirection when painting.');
|
||||||
|
switch (textDirection) {
|
||||||
|
case TextDirection.rtl:
|
||||||
|
left = end;
|
||||||
|
right = start;
|
||||||
|
break;
|
||||||
|
case TextDirection.ltr:
|
||||||
|
left = start;
|
||||||
|
right = end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
paintBorder(canvas, rect, top: top, left: left, bottom: bottom, right: right);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
if (identical(this, other))
|
||||||
|
return true;
|
||||||
|
if (runtimeType != other.runtimeType)
|
||||||
|
return false;
|
||||||
|
final BorderDirectional typedOther = other;
|
||||||
|
return top == typedOther.top &&
|
||||||
|
start == typedOther.start &&
|
||||||
|
end == typedOther.end &&
|
||||||
|
bottom == typedOther.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => hashValues(top, start, end, bottom);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
final List<String> arguments = <String>[];
|
||||||
|
if (top != BorderSide.none)
|
||||||
|
arguments.add('top: $top');
|
||||||
|
if (start != BorderSide.none)
|
||||||
|
arguments.add('start: $start');
|
||||||
|
if (end != BorderSide.none)
|
||||||
|
arguments.add('end: $end');
|
||||||
|
if (bottom != BorderSide.none)
|
||||||
|
arguments.add('bottom: $bottom');
|
||||||
|
return 'BorderDirectional(${arguments.join(", ")})';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,14 @@ class BoxDecoration extends Decoration {
|
|||||||
/// A border to draw above the background [color], [gradient], or [image].
|
/// A border to draw above the background [color], [gradient], or [image].
|
||||||
///
|
///
|
||||||
/// Follows the [shape] and [borderRadius].
|
/// Follows the [shape] and [borderRadius].
|
||||||
final Border border;
|
///
|
||||||
|
/// Use [Border] objects to describe borders that do not depend on the reading
|
||||||
|
/// direction.
|
||||||
|
///
|
||||||
|
/// Use [BoxBorder] objects to describe borders that should flip their left
|
||||||
|
/// and right edges based on whether the text is being read left-to-right or
|
||||||
|
/// right-to-left.
|
||||||
|
final BoxBorder border;
|
||||||
|
|
||||||
/// If non-null, the corners of this box are rounded by this [BorderRadius].
|
/// If non-null, the corners of this box are rounded by this [BorderRadius].
|
||||||
///
|
///
|
||||||
@ -137,7 +144,7 @@ class BoxDecoration extends Decoration {
|
|||||||
final BoxShape shape;
|
final BoxShape shape;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
EdgeInsets get padding => border?.dimensions;
|
EdgeInsetsGeometry get padding => border?.dimensions;
|
||||||
|
|
||||||
/// Returns a new box decoration that is scaled by the given factor.
|
/// Returns a new box decoration that is scaled by the given factor.
|
||||||
BoxDecoration scale(double factor) {
|
BoxDecoration scale(double factor) {
|
||||||
@ -145,7 +152,7 @@ class BoxDecoration extends Decoration {
|
|||||||
return new BoxDecoration(
|
return new BoxDecoration(
|
||||||
color: Color.lerp(null, color, factor),
|
color: Color.lerp(null, color, factor),
|
||||||
image: image,
|
image: image,
|
||||||
border: Border.lerp(null, border, factor),
|
border: BoxBorder.lerp(null, border, factor),
|
||||||
borderRadius: BorderRadius.lerp(null, borderRadius, factor),
|
borderRadius: BorderRadius.lerp(null, borderRadius, factor),
|
||||||
boxShadow: BoxShadow.lerpList(null, boxShadow, factor),
|
boxShadow: BoxShadow.lerpList(null, boxShadow, factor),
|
||||||
gradient: gradient,
|
gradient: gradient,
|
||||||
@ -192,7 +199,7 @@ class BoxDecoration extends Decoration {
|
|||||||
return new BoxDecoration(
|
return new BoxDecoration(
|
||||||
color: Color.lerp(a.color, b.color, t),
|
color: Color.lerp(a.color, b.color, t),
|
||||||
image: t < 0.5 ? a.image : b.image,
|
image: t < 0.5 ? a.image : b.image,
|
||||||
border: Border.lerp(a.border, b.border, t),
|
border: BoxBorder.lerp(a.border, b.border, t),
|
||||||
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
||||||
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
||||||
gradient: t < 0.5 ? a.gradient : b.gradient,
|
gradient: t < 0.5 ? a.gradient : b.gradient,
|
||||||
@ -238,7 +245,7 @@ class BoxDecoration extends Decoration {
|
|||||||
|
|
||||||
properties.add(new DiagnosticsProperty<Color>('color', color, defaultValue: null));
|
properties.add(new DiagnosticsProperty<Color>('color', color, defaultValue: null));
|
||||||
properties.add(new DiagnosticsProperty<DecorationImage>('image', image, defaultValue: null));
|
properties.add(new DiagnosticsProperty<DecorationImage>('image', image, defaultValue: null));
|
||||||
properties.add(new DiagnosticsProperty<Border>('border', border, defaultValue: null));
|
properties.add(new DiagnosticsProperty<BoxBorder>('border', border, defaultValue: null));
|
||||||
properties.add(new DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius, defaultValue: null));
|
properties.add(new DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius, defaultValue: null));
|
||||||
properties.add(new IterableProperty<BoxShadow>('boxShadow', boxShadow, defaultValue: null, style: DiagnosticsTreeStyle.whitespace));
|
properties.add(new IterableProperty<BoxShadow>('boxShadow', boxShadow, defaultValue: null, style: DiagnosticsTreeStyle.whitespace));
|
||||||
properties.add(new DiagnosticsProperty<Gradient>('gradient', gradient, defaultValue: null));
|
properties.add(new DiagnosticsProperty<Gradient>('gradient', gradient, defaultValue: null));
|
||||||
@ -421,7 +428,8 @@ class _BoxDecorationPainter extends BoxPainter {
|
|||||||
canvas,
|
canvas,
|
||||||
rect,
|
rect,
|
||||||
shape: _decoration.shape,
|
shape: _decoration.shape,
|
||||||
borderRadius: _decoration.borderRadius
|
borderRadius: _decoration.borderRadius,
|
||||||
|
textDirection: configuration.textDirection,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,12 @@ abstract class Decoration extends Diagnosticable {
|
|||||||
/// does not take into account that the circle is drawn in the center of the
|
/// does not take into account that the circle is drawn in the center of the
|
||||||
/// box regardless of the ratio of the box; it does not provide the extra
|
/// box regardless of the ratio of the box; it does not provide the extra
|
||||||
/// padding that is implied by changing the ratio.
|
/// padding that is implied by changing the ratio.
|
||||||
EdgeInsets get padding => EdgeInsets.zero;
|
///
|
||||||
|
/// The value returned by this getter must be resolved (using
|
||||||
|
/// [EdgeInsetsGeometry.resolve] to obtain an absolute [EdgeInsets]. (For
|
||||||
|
/// example, [BorderDirectional] will return an [EdgeInsetsDirectional] for
|
||||||
|
/// its [padding].)
|
||||||
|
EdgeInsetsGeometry get padding => EdgeInsets.zero;
|
||||||
|
|
||||||
/// Whether this decoration is complex enough to benefit from caching its painting.
|
/// Whether this decoration is complex enough to benefit from caching its painting.
|
||||||
bool get isComplex => false;
|
bool get isComplex => false;
|
||||||
|
671
packages/flutter/test/painting/border_rtl_test.dart
Normal file
671
packages/flutter/test/painting/border_rtl_test.dart
Normal file
@ -0,0 +1,671 @@
|
|||||||
|
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/painting.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import '../rendering/mock_canvas.dart';
|
||||||
|
|
||||||
|
class SillyBorder extends BoxBorder {
|
||||||
|
@override
|
||||||
|
dynamic noSuchMethod(Invocation invocation) => null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('BoxBorder.lerp', () {
|
||||||
|
// names of the form fooAtX are foo, lerped X% of the way to null
|
||||||
|
final BoxBorder directionalWithMagentaTop5 = const BorderDirectional(top: const BorderSide(color: const Color(0xFFFF00FF), width: 5.0));
|
||||||
|
final BoxBorder directionalWithMagentaTop5At25 = const BorderDirectional(top: const BorderSide(color: const Color(0x3F3F003F), width: 1.25));
|
||||||
|
final BoxBorder directionalWithMagentaTop5At75 = const BorderDirectional(top: const BorderSide(color: const Color(0xBFBF00BF), width: 3.75));
|
||||||
|
final BoxBorder directionalWithSides10 = const BorderDirectional(start: const BorderSide(width: 10.0), end: const BorderSide(width: 20.0));
|
||||||
|
final BoxBorder directionalWithSides10At25 = const BorderDirectional(start: const BorderSide(width: 2.5, color: const Color(0x3F000000)), end: const BorderSide(width: 5.0, color: const Color(0x3F000000)));
|
||||||
|
final BoxBorder directionalWithSides10At50 = const BorderDirectional(start: const BorderSide(width: 5.0, color: const Color(0x7F000000)), end: const BorderSide(width: 10.0, color: const Color(0x7F000000)));
|
||||||
|
final BoxBorder directionalWithSides10At75 = const BorderDirectional(start: const BorderSide(width: 7.5, color: const Color(0xBF000000)), end: const BorderSide(width: 15.0, color: const Color(0xBF000000)));
|
||||||
|
final BoxBorder directionalWithSides20 = const BorderDirectional(start: const BorderSide(width: 20.0), end: const BorderSide(width: 40.0));
|
||||||
|
final BoxBorder directionalWithSides30 = const BorderDirectional(start: const BorderSide(width: 30.0), end: const BorderSide(width: 60.0));
|
||||||
|
final BoxBorder directionalWithTop10 = const BorderDirectional(top: const BorderSide(width: 10.0));
|
||||||
|
final BoxBorder directionalWithYellowTop10 = const BorderDirectional(top: const BorderSide(color: const Color(0xFFFFFF00), width: 10.0));
|
||||||
|
final BoxBorder directionalWithYellowTop5 = const BorderDirectional(top: const BorderSide(color: const Color(0xFFFFFF00), width: 5.0));
|
||||||
|
final BoxBorder visualWithMagentaTop10 = const Border(top: const BorderSide(color: const Color(0xFFFF00FF), width: 10.0));
|
||||||
|
final BoxBorder visualWithMagentaTop5 = const Border(top: const BorderSide(color: const Color(0xFFFF00FF), width: 5.0));
|
||||||
|
final BoxBorder visualWithSides10 = const Border(left: const BorderSide(width: 10.0), right: const BorderSide(width: 20.0));
|
||||||
|
final BoxBorder visualWithSides10At25 = const Border(left: const BorderSide(width: 2.5, color: const Color(0x3F000000)), right: const BorderSide(width: 5.0, color: const Color(0x3F000000)));
|
||||||
|
final BoxBorder visualWithSides10At50 = const Border(left: const BorderSide(width: 5.0, color: const Color(0x7F000000)), right: const BorderSide(width: 10.0, color: const Color(0x7F000000)));
|
||||||
|
final BoxBorder visualWithSides10At75 = const Border(left: const BorderSide(width: 7.5, color: const Color(0xBF000000)), right: const BorderSide(width: 15.0, color: const Color(0xBF000000)));
|
||||||
|
final BoxBorder visualWithSides20 = const Border(left: const BorderSide(width: 20.0), right: const BorderSide(width: 40.0));
|
||||||
|
final BoxBorder visualWithSides30 = const Border(left: const BorderSide(width: 30.0), right: const BorderSide(width: 60.0));
|
||||||
|
final BoxBorder visualWithTop10 = const Border(top: const BorderSide(width: 10.0));
|
||||||
|
final BoxBorder visualWithTop100 = const Border(top: const BorderSide(width: 100.0));
|
||||||
|
final BoxBorder visualWithTop190 = const Border(top: const BorderSide(width: 190.0));
|
||||||
|
final BoxBorder visualWithYellowTop5 = const Border(top: const BorderSide(color: const Color(0xFFFFFF00), width: 5.0));
|
||||||
|
final BoxBorder visualWithYellowTop5At25 = const Border(top: const BorderSide(color: const Color(0x3F3F3F00), width: 1.25));
|
||||||
|
final BoxBorder visualWithYellowTop5At75 = const Border(top: const BorderSide(color: const Color(0xBFBFBF00), width: 3.75));
|
||||||
|
|
||||||
|
expect(BoxBorder.lerp(null, null, -1.0), null);
|
||||||
|
expect(BoxBorder.lerp(new Border.all(width: 10.0), null, -1.0), new Border.all(width: 20.0));
|
||||||
|
expect(BoxBorder.lerp(null, new Border.all(width: 10.0), -1.0), new Border.all(width: 0.0, style: BorderStyle.none));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, null, -1.0), const BorderDirectional(top: const BorderSide(width: 20.0)));
|
||||||
|
expect(BoxBorder.lerp(null, directionalWithTop10, -1.0), const BorderDirectional());
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, visualWithTop100, -1.0), const Border());
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithMagentaTop5, -1.0), visualWithSides20);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithMagentaTop5, -1.0), const Border(top: const BorderSide(color: const Color(0xFFFFFF00), width: 5.0)));
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithSides10, -1.0), visualWithSides30);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithSides10, -1.0), directionalWithYellowTop10);
|
||||||
|
expect(() => BoxBorder.lerp(new SillyBorder(), const Border(), -1.0), throwsFlutterError);
|
||||||
|
|
||||||
|
expect(BoxBorder.lerp(null, null, 0.0), null);
|
||||||
|
expect(BoxBorder.lerp(new Border.all(width: 10.0), null, 0.0), new Border.all(width: 10.0));
|
||||||
|
expect(BoxBorder.lerp(null, new Border.all(width: 10.0), 0.0), const Border());
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, null, 0.0), const BorderDirectional(top: const BorderSide(width: 10.0)));
|
||||||
|
expect(BoxBorder.lerp(null, directionalWithTop10, 0.0), const BorderDirectional());
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, visualWithTop100, 0.0), visualWithTop10);
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithMagentaTop5, 0.0), visualWithSides10);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithMagentaTop5, 0.0), const Border(top: const BorderSide(color: const Color(0xFFFFFF00), width: 5.0)));
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithSides10, 0.0), visualWithSides10);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithSides10, 0.0), directionalWithYellowTop5);
|
||||||
|
expect(() => BoxBorder.lerp(new SillyBorder(), const Border(), 0.0), throwsFlutterError);
|
||||||
|
|
||||||
|
expect(BoxBorder.lerp(null, null, 0.25), null);
|
||||||
|
expect(BoxBorder.lerp(new Border.all(width: 10.0), null, 0.25), new Border.all(width: 7.5));
|
||||||
|
expect(BoxBorder.lerp(null, new Border.all(width: 10.0), 0.25), new Border.all(width: 2.5));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, null, 0.25), const BorderDirectional(top: const BorderSide(width: 7.5)));
|
||||||
|
expect(BoxBorder.lerp(null, directionalWithTop10, 0.25), const BorderDirectional(top: const BorderSide(width: 2.5)));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, visualWithTop100, 0.25), const Border(top: const BorderSide(width: 32.5)));
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithMagentaTop5, 0.25), visualWithSides10At75 + directionalWithMagentaTop5At25);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithMagentaTop5, 0.25), new Border(top: new BorderSide(width: 5.0, color: Color.lerp(const Color(0xFFFFFF00), const Color(0xFFFF00FF), 0.25))));
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithSides10, 0.25), visualWithSides10At50);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithSides10, 0.25), visualWithYellowTop5At75 + directionalWithSides10At25);
|
||||||
|
expect(() => BoxBorder.lerp(new SillyBorder(), const Border(), 0.25), throwsFlutterError);
|
||||||
|
|
||||||
|
expect(BoxBorder.lerp(null, null, 0.75), null);
|
||||||
|
expect(BoxBorder.lerp(new Border.all(width: 10.0), null, 0.75), new Border.all(width: 2.5));
|
||||||
|
expect(BoxBorder.lerp(null, new Border.all(width: 10.0), 0.75), new Border.all(width: 7.5));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, null, 0.75), const BorderDirectional(top: const BorderSide(width: 2.5)));
|
||||||
|
expect(BoxBorder.lerp(null, directionalWithTop10, 0.75), const BorderDirectional(top: const BorderSide(width: 7.5)));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, visualWithTop100, 0.75), const Border(top: const BorderSide(width: 77.5)));
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithMagentaTop5, 0.75), visualWithSides10At25 + directionalWithMagentaTop5At75);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithMagentaTop5, 0.75), new Border(top: new BorderSide(width: 5.0, color: Color.lerp(const Color(0xFFFFFF00), const Color(0xFFFF00FF), 0.75))));
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithSides10, 0.75), directionalWithSides10At50);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithSides10, 0.75), visualWithYellowTop5At25 + directionalWithSides10At75);
|
||||||
|
expect(() => BoxBorder.lerp(new SillyBorder(), const Border(), 0.75), throwsFlutterError);
|
||||||
|
|
||||||
|
expect(BoxBorder.lerp(null, null, 1.0), null);
|
||||||
|
expect(BoxBorder.lerp(new Border.all(width: 10.0), null, 1.0), new Border.all(width: 0.0, style: BorderStyle.none));
|
||||||
|
expect(BoxBorder.lerp(null, new Border.all(width: 10.0), 1.0), new Border.all(width: 10.0));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, null, 1.0), const BorderDirectional());
|
||||||
|
expect(BoxBorder.lerp(null, directionalWithTop10, 1.0), const BorderDirectional(top: const BorderSide(width: 10.0)));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, visualWithTop100, 1.0), visualWithTop100);
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithMagentaTop5, 1.0), visualWithMagentaTop5);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithMagentaTop5, 1.0), visualWithMagentaTop5);
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithSides10, 1.0), directionalWithSides10);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithSides10, 1.0), directionalWithSides10);
|
||||||
|
expect(() => BoxBorder.lerp(new SillyBorder(), const Border(), 1.0), throwsFlutterError);
|
||||||
|
|
||||||
|
expect(BoxBorder.lerp(null, null, 2.0), null);
|
||||||
|
expect(BoxBorder.lerp(new Border.all(width: 10.0), null, 2.0), new Border.all(width: 0.0, style: BorderStyle.none));
|
||||||
|
expect(BoxBorder.lerp(null, new Border.all(width: 10.0), 2.0), new Border.all(width: 20.0));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, null, 2.0), const BorderDirectional());
|
||||||
|
expect(BoxBorder.lerp(null, directionalWithTop10, 2.0), const BorderDirectional(top: const BorderSide(width: 20.0)));
|
||||||
|
expect(BoxBorder.lerp(directionalWithTop10, visualWithTop100, 2.0), visualWithTop190);
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithMagentaTop5, 2.0), visualWithMagentaTop10);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithMagentaTop5, 2.0), visualWithMagentaTop5);
|
||||||
|
expect(BoxBorder.lerp(visualWithSides10, directionalWithSides10, 2.0), directionalWithSides30);
|
||||||
|
expect(BoxBorder.lerp(visualWithYellowTop5, directionalWithSides10, 2.0), directionalWithSides20);
|
||||||
|
expect(() => BoxBorder.lerp(new SillyBorder(), const Border(), 2.0), throwsFlutterError);
|
||||||
|
});
|
||||||
|
|
||||||
|
void verifyPath(Path path, {
|
||||||
|
Iterable<Offset> includes: const <Offset>[],
|
||||||
|
Iterable<Offset> excludes: const <Offset>[],
|
||||||
|
}) {
|
||||||
|
for (Offset offset in includes)
|
||||||
|
expect(path.contains(offset), isTrue, reason: 'Offset $offset should be inside the path.');
|
||||||
|
for (Offset offset in excludes)
|
||||||
|
expect(path.contains(offset), isFalse, reason: 'Offset $offset should be outside the path.');
|
||||||
|
}
|
||||||
|
|
||||||
|
test('BoxBorder.getInnerPath / BoxBorder.getOuterPath', () {
|
||||||
|
// for Border, BorderDirectional
|
||||||
|
final Border border = const Border(top: const BorderSide(width: 10.0), right: const BorderSide(width: 20.0));
|
||||||
|
final BorderDirectional borderDirectional = const BorderDirectional(top: const BorderSide(width: 10.0), end: const BorderSide(width: 20.0));
|
||||||
|
verifyPath(
|
||||||
|
border.getOuterPath(new Rect.fromLTRB(50.0, 60.0, 110.0, 190.0), textDirection: TextDirection.rtl),
|
||||||
|
includes: <Offset>[
|
||||||
|
const Offset(50.0, 60.0),
|
||||||
|
const Offset(60.0, 60.0),
|
||||||
|
const Offset(60.0, 70.0),
|
||||||
|
const Offset(80.0, 190.0),
|
||||||
|
const Offset(109.0, 189.0),
|
||||||
|
const Offset(110.0, 80.0),
|
||||||
|
const Offset(110.0, 190.0),
|
||||||
|
],
|
||||||
|
excludes: <Offset>[
|
||||||
|
const Offset(40.0, 60.0),
|
||||||
|
const Offset(50.0, 50.0),
|
||||||
|
const Offset(111.0, 190.0),
|
||||||
|
const Offset(110.0, 191.0),
|
||||||
|
const Offset(111.0, 191.0),
|
||||||
|
const Offset(0.0, 0.0),
|
||||||
|
const Offset(-10.0, -10.0),
|
||||||
|
const Offset(0.0, -10.0),
|
||||||
|
const Offset(-10.0, 0.0),
|
||||||
|
const Offset(1000.0, 1000.0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
verifyPath(
|
||||||
|
border.getInnerPath(new Rect.fromLTRB(50.0, 60.0, 110.0, 190.0), textDirection: TextDirection.rtl),
|
||||||
|
// inner path is a rect from 50.0,70.0 to 90.0,190.0
|
||||||
|
includes: <Offset>[
|
||||||
|
const Offset(50.0, 70.0),
|
||||||
|
const Offset(55.0, 70.0),
|
||||||
|
const Offset(50.0, 75.0),
|
||||||
|
const Offset(70.0, 70.0),
|
||||||
|
const Offset(70.0, 71.0),
|
||||||
|
const Offset(71.0, 70.0),
|
||||||
|
const Offset(71.0, 71.0),
|
||||||
|
const Offset(80.0, 180.0),
|
||||||
|
const Offset(80.0, 190.0),
|
||||||
|
const Offset(89.0, 189.0),
|
||||||
|
const Offset(90.0, 190.0),
|
||||||
|
],
|
||||||
|
excludes: <Offset>[
|
||||||
|
const Offset(40.0, 60.0),
|
||||||
|
const Offset(50.0, 50.0),
|
||||||
|
const Offset(50.0, 60.0),
|
||||||
|
const Offset(60.0, 60.0),
|
||||||
|
const Offset(0.0, 0.0),
|
||||||
|
const Offset(-10.0, -10.0),
|
||||||
|
const Offset(0.0, -10.0),
|
||||||
|
const Offset(-10.0, 0.0),
|
||||||
|
const Offset(110.0, 80.0),
|
||||||
|
const Offset(89.0, 191.0),
|
||||||
|
const Offset(90.0, 191.0),
|
||||||
|
const Offset(91.0, 189.0),
|
||||||
|
const Offset(91.0, 190.0),
|
||||||
|
const Offset(91.0, 191.0),
|
||||||
|
const Offset(109.0, 189.0),
|
||||||
|
const Offset(110.0, 190.0),
|
||||||
|
const Offset(1000.0, 1000.0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
verifyPath(
|
||||||
|
borderDirectional.getOuterPath(new Rect.fromLTRB(50.0, 60.0, 110.0, 190.0), textDirection: TextDirection.rtl),
|
||||||
|
includes: <Offset>[
|
||||||
|
const Offset(50.0, 60.0),
|
||||||
|
const Offset(60.0, 60.0),
|
||||||
|
const Offset(60.0, 70.0),
|
||||||
|
const Offset(80.0, 190.0),
|
||||||
|
const Offset(109.0, 189.0),
|
||||||
|
const Offset(110.0, 80.0),
|
||||||
|
const Offset(110.0, 190.0),
|
||||||
|
],
|
||||||
|
excludes: <Offset>[
|
||||||
|
const Offset(40.0, 60.0),
|
||||||
|
const Offset(50.0, 50.0),
|
||||||
|
const Offset(111.0, 190.0),
|
||||||
|
const Offset(110.0, 191.0),
|
||||||
|
const Offset(111.0, 191.0),
|
||||||
|
const Offset(0.0, 0.0),
|
||||||
|
const Offset(-10.0, -10.0),
|
||||||
|
const Offset(0.0, -10.0),
|
||||||
|
const Offset(-10.0, 0.0),
|
||||||
|
const Offset(1000.0, 1000.0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
verifyPath(
|
||||||
|
borderDirectional.getInnerPath(new Rect.fromLTRB(50.0, 60.0, 110.0, 190.0), textDirection: TextDirection.rtl),
|
||||||
|
// inner path is a rect from 70.0,70.0 to 110.0,190.0
|
||||||
|
includes: <Offset>[
|
||||||
|
const Offset(70.0, 70.0),
|
||||||
|
const Offset(70.0, 71.0),
|
||||||
|
const Offset(71.0, 70.0),
|
||||||
|
const Offset(71.0, 71.0),
|
||||||
|
const Offset(80.0, 180.0),
|
||||||
|
const Offset(80.0, 190.0),
|
||||||
|
const Offset(89.0, 189.0),
|
||||||
|
const Offset(90.0, 190.0),
|
||||||
|
const Offset(91.0, 189.0),
|
||||||
|
const Offset(91.0, 190.0),
|
||||||
|
const Offset(109.0, 189.0),
|
||||||
|
const Offset(110.0, 80.0),
|
||||||
|
const Offset(110.0, 190.0),
|
||||||
|
],
|
||||||
|
excludes: <Offset>[
|
||||||
|
const Offset(40.0, 60.0),
|
||||||
|
const Offset(50.0, 50.0),
|
||||||
|
const Offset(50.0, 60.0),
|
||||||
|
const Offset(50.0, 70.0),
|
||||||
|
const Offset(50.0, 75.0),
|
||||||
|
const Offset(55.0, 70.0),
|
||||||
|
const Offset(60.0, 60.0),
|
||||||
|
const Offset(0.0, 0.0),
|
||||||
|
const Offset(-10.0, -10.0),
|
||||||
|
const Offset(0.0, -10.0),
|
||||||
|
const Offset(-10.0, 0.0),
|
||||||
|
const Offset(89.0, 191.0),
|
||||||
|
const Offset(90.0, 191.0),
|
||||||
|
const Offset(91.0, 191.0),
|
||||||
|
const Offset(110.0, 191.0),
|
||||||
|
const Offset(111.0, 190.0),
|
||||||
|
const Offset(111.0, 191.0),
|
||||||
|
const Offset(1000.0, 1000.0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
verifyPath(
|
||||||
|
borderDirectional.getOuterPath(new Rect.fromLTRB(50.0, 60.0, 110.0, 190.0), textDirection: TextDirection.ltr),
|
||||||
|
includes: <Offset>[
|
||||||
|
const Offset(50.0, 60.0),
|
||||||
|
const Offset(60.0, 60.0),
|
||||||
|
const Offset(60.0, 70.0),
|
||||||
|
const Offset(80.0, 190.0),
|
||||||
|
const Offset(109.0, 189.0),
|
||||||
|
const Offset(110.0, 80.0),
|
||||||
|
const Offset(110.0, 190.0),
|
||||||
|
],
|
||||||
|
excludes: <Offset>[
|
||||||
|
const Offset(40.0, 60.0),
|
||||||
|
const Offset(50.0, 50.0),
|
||||||
|
const Offset(111.0, 190.0),
|
||||||
|
const Offset(110.0, 191.0),
|
||||||
|
const Offset(111.0, 191.0),
|
||||||
|
const Offset(0.0, 0.0),
|
||||||
|
const Offset(-10.0, -10.0),
|
||||||
|
const Offset(0.0, -10.0),
|
||||||
|
const Offset(-10.0, 0.0),
|
||||||
|
const Offset(1000.0, 1000.0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
verifyPath(
|
||||||
|
borderDirectional.getInnerPath(new Rect.fromLTRB(50.0, 60.0, 110.0, 190.0), textDirection: TextDirection.ltr),
|
||||||
|
// inner path is a rect from 50.0,70.0 to 90.0,190.0
|
||||||
|
includes: <Offset>[
|
||||||
|
const Offset(50.0, 70.0),
|
||||||
|
const Offset(50.0, 75.0),
|
||||||
|
const Offset(55.0, 70.0),
|
||||||
|
const Offset(70.0, 70.0),
|
||||||
|
const Offset(70.0, 71.0),
|
||||||
|
const Offset(71.0, 70.0),
|
||||||
|
const Offset(71.0, 71.0),
|
||||||
|
const Offset(80.0, 180.0),
|
||||||
|
const Offset(80.0, 190.0),
|
||||||
|
const Offset(89.0, 189.0),
|
||||||
|
const Offset(90.0, 190.0),
|
||||||
|
],
|
||||||
|
excludes: <Offset>[
|
||||||
|
const Offset(50.0, 50.0),
|
||||||
|
const Offset(40.0, 60.0),
|
||||||
|
const Offset(50.0, 60.0),
|
||||||
|
const Offset(60.0, 60.0),
|
||||||
|
const Offset(0.0, 0.0),
|
||||||
|
const Offset(-10.0, -10.0),
|
||||||
|
const Offset(0.0, -10.0),
|
||||||
|
const Offset(-10.0, 0.0),
|
||||||
|
const Offset(110.0, 80.0),
|
||||||
|
const Offset(89.0, 191.0),
|
||||||
|
const Offset(90.0, 191.0),
|
||||||
|
const Offset(91.0, 189.0),
|
||||||
|
const Offset(91.0, 190.0),
|
||||||
|
const Offset(91.0, 191.0),
|
||||||
|
const Offset(109.0, 189.0),
|
||||||
|
const Offset(110.0, 190.0),
|
||||||
|
const Offset(1000.0, 1000.0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional constructor', () {
|
||||||
|
final Null $null = null;
|
||||||
|
expect(() => new BorderDirectional(top: $null), throwsAssertionError);
|
||||||
|
expect(() => new BorderDirectional(start: $null), throwsAssertionError);
|
||||||
|
expect(() => new BorderDirectional(end: $null), throwsAssertionError);
|
||||||
|
expect(() => new BorderDirectional(bottom: $null), throwsAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional.merge', () {
|
||||||
|
final BorderSide magenta3 = const BorderSide(color: const Color(0xFFFF00FF), width: 3.0);
|
||||||
|
final BorderSide magenta6 = const BorderSide(color: const Color(0xFFFF00FF), width: 6.0);
|
||||||
|
final BorderSide yellow2 = const BorderSide(color: const Color(0xFFFFFF00), width: 2.0);
|
||||||
|
final BorderSide yellowNone0 = const BorderSide(color: const Color(0xFFFFFF00), width: 0.0, style: BorderStyle.none);
|
||||||
|
expect(
|
||||||
|
BorderDirectional.merge(
|
||||||
|
new BorderDirectional(top: yellow2),
|
||||||
|
new BorderDirectional(end: magenta3),
|
||||||
|
),
|
||||||
|
new BorderDirectional(top: yellow2, end: magenta3),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BorderDirectional.merge(
|
||||||
|
new BorderDirectional(bottom: magenta3),
|
||||||
|
new BorderDirectional(bottom: magenta3),
|
||||||
|
),
|
||||||
|
new BorderDirectional(bottom: magenta6),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BorderDirectional.merge(
|
||||||
|
new BorderDirectional(start: magenta3, end: yellowNone0),
|
||||||
|
new BorderDirectional(end: yellow2),
|
||||||
|
),
|
||||||
|
new BorderDirectional(start: magenta3, end: yellow2),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BorderDirectional.merge(const BorderDirectional(), const BorderDirectional()),
|
||||||
|
const BorderDirectional(),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
() => BorderDirectional.merge(
|
||||||
|
new BorderDirectional(start: magenta3),
|
||||||
|
new BorderDirectional(start: yellow2),
|
||||||
|
),
|
||||||
|
throwsAssertionError,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional.dimensions', () {
|
||||||
|
expect(
|
||||||
|
const BorderDirectional(
|
||||||
|
top: const BorderSide(width: 3.0),
|
||||||
|
start: const BorderSide(width: 2.0),
|
||||||
|
end: const BorderSide(width: 7.0),
|
||||||
|
bottom: const BorderSide(width: 5.0),
|
||||||
|
).dimensions,
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(2.0, 3.0, 7.0, 5.0),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional.isUniform', () {
|
||||||
|
expect(
|
||||||
|
const BorderDirectional(
|
||||||
|
top: const BorderSide(width: 3.0),
|
||||||
|
start: const BorderSide(width: 3.0),
|
||||||
|
end: const BorderSide(width: 3.0),
|
||||||
|
bottom: const BorderSide(width: 3.1),
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const BorderDirectional(
|
||||||
|
top: const BorderSide(width: 3.0),
|
||||||
|
start: const BorderSide(width: 3.0),
|
||||||
|
end: const BorderSide(width: 3.0),
|
||||||
|
bottom: const BorderSide(width: 3.0),
|
||||||
|
).isUniform,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const BorderDirectional(
|
||||||
|
top: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
start: const BorderSide(color: const Color(0xFFFFFFFE)),
|
||||||
|
end: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
bottom: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const BorderDirectional(
|
||||||
|
top: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
start: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
end: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
bottom: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
).isUniform,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const BorderDirectional(
|
||||||
|
top: const BorderSide(style: BorderStyle.none),
|
||||||
|
start: const BorderSide(style: BorderStyle.none),
|
||||||
|
end: const BorderSide(style: BorderStyle.none),
|
||||||
|
bottom: const BorderSide(style: BorderStyle.solid, width: 0.0),
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const BorderDirectional(
|
||||||
|
top: const BorderSide(style: BorderStyle.none),
|
||||||
|
start: const BorderSide(style: BorderStyle.none),
|
||||||
|
end: const BorderSide(style: BorderStyle.none),
|
||||||
|
bottom: BorderSide.none,
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const BorderDirectional(
|
||||||
|
top: const BorderSide(style: BorderStyle.none, width: 0.0),
|
||||||
|
start: const BorderSide(style: BorderStyle.none, width: 0.0),
|
||||||
|
end: const BorderSide(style: BorderStyle.none, width: 0.0),
|
||||||
|
bottom: BorderSide.none,
|
||||||
|
).isUniform,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const BorderDirectional().isUniform,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional.add - all directional', () {
|
||||||
|
final BorderSide magenta3 = const BorderSide(color: const Color(0xFFFF00FF), width: 3.0);
|
||||||
|
final BorderSide magenta6 = const BorderSide(color: const Color(0xFFFF00FF), width: 6.0);
|
||||||
|
final BorderSide yellow2 = const BorderSide(color: const Color(0xFFFFFF00), width: 2.0);
|
||||||
|
final BorderSide yellowNone0 = const BorderSide(color: const Color(0xFFFFFF00), width: 0.0, style: BorderStyle.none);
|
||||||
|
expect(
|
||||||
|
new BorderDirectional(top: yellow2) + new BorderDirectional(end: magenta3),
|
||||||
|
new BorderDirectional(top: yellow2, end: magenta3),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
new BorderDirectional(bottom: magenta3) + new BorderDirectional(bottom: magenta3),
|
||||||
|
new BorderDirectional(bottom: magenta6),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
new BorderDirectional(start: magenta3, end: yellowNone0) + new BorderDirectional(end: yellow2),
|
||||||
|
new BorderDirectional(start: magenta3, end: yellow2),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const BorderDirectional() + const BorderDirectional(),
|
||||||
|
const BorderDirectional(),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
new BorderDirectional(start: magenta3) + new BorderDirectional(start: yellow2),
|
||||||
|
isNot(const isInstanceOf<BorderDirectional>()), // see shape_border_test.dart for better tests of this case
|
||||||
|
);
|
||||||
|
final BorderDirectional b3 = new BorderDirectional(top: magenta3);
|
||||||
|
final BorderDirectional b6 = new BorderDirectional(top: magenta6);
|
||||||
|
expect(b3 + b3, b6);
|
||||||
|
final BorderDirectional b0 = new BorderDirectional(top: yellowNone0);
|
||||||
|
final BorderDirectional bZ = const BorderDirectional();
|
||||||
|
expect(b0 + b0, bZ);
|
||||||
|
expect(bZ + bZ, bZ);
|
||||||
|
expect(b0 + bZ, bZ);
|
||||||
|
expect(bZ + b0, bZ);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional.add', () {
|
||||||
|
const BorderSide side1 = const BorderSide(color: const Color(0x11111111));
|
||||||
|
const BorderSide doubleSide1 = const BorderSide(color: const Color(0x11111111), width: 2.0);
|
||||||
|
const BorderSide side2 = const BorderSide(color: const Color(0x22222222));
|
||||||
|
const BorderSide doubleSide2 = const BorderSide(color: const Color(0x22222222), width: 2.0);
|
||||||
|
|
||||||
|
// adding tops and sides
|
||||||
|
expect(const Border(left: side1) + const BorderDirectional(top: side2), const Border(left: side1, top: side2));
|
||||||
|
expect(const BorderDirectional(start: side1) + const Border(top: side2), const BorderDirectional(start: side1, top: side2));
|
||||||
|
expect(const Border(top: side2) + const BorderDirectional(start: side1), const BorderDirectional(start: side1, top: side2));
|
||||||
|
expect(const BorderDirectional(top: side2) + const Border(left: side1), const Border(left: side1, top: side2));
|
||||||
|
|
||||||
|
// adding incompatible tops and bottoms
|
||||||
|
expect((const Border(top: side1) + const BorderDirectional(top: side2)).toString(), contains(' + '));
|
||||||
|
expect((const BorderDirectional(top: side2) + const Border(top: side1)).toString(), contains(' + '));
|
||||||
|
expect((const Border(bottom: side1) + const BorderDirectional(bottom: side2)).toString(), contains(' + '));
|
||||||
|
expect((const BorderDirectional(bottom: side2) + const Border(bottom: side1)).toString(), contains(' + '));
|
||||||
|
|
||||||
|
// adding compatible tops and bottoms
|
||||||
|
expect(const BorderDirectional(top: side1) + const Border(top: side1), const Border(top: doubleSide1));
|
||||||
|
expect(const Border(top: side1) + const BorderDirectional(top: side1), const Border(top: doubleSide1));
|
||||||
|
expect(const BorderDirectional(bottom: side1) + const Border(bottom: side1), const Border(bottom: doubleSide1));
|
||||||
|
expect(const Border(bottom: side1) + const BorderDirectional(bottom: side1), const Border(bottom: doubleSide1));
|
||||||
|
|
||||||
|
const Border borderWithLeft = const Border(left: side1, top: side2, bottom: side2);
|
||||||
|
const Border borderWithRight = const Border(right: side1, top: side2, bottom: side2);
|
||||||
|
const Border borderWithoutSides = const Border(top: side2, bottom: side2);
|
||||||
|
const BorderDirectional borderDirectionalWithStart = const BorderDirectional(start: side1, top: side2, bottom: side2);
|
||||||
|
const BorderDirectional borderDirectionalWithEnd = const BorderDirectional(end: side1, top: side2, bottom: side2);
|
||||||
|
const BorderDirectional borderDirectionalWithoutSides = const BorderDirectional(top: side2, bottom: side2);
|
||||||
|
|
||||||
|
expect((borderWithLeft + borderDirectionalWithStart).toString(), '$borderWithLeft + $borderDirectionalWithStart');
|
||||||
|
expect((borderWithLeft + borderDirectionalWithEnd).toString(), '$borderWithLeft + $borderDirectionalWithEnd');
|
||||||
|
expect((borderWithLeft + borderDirectionalWithoutSides).toString(), '${const Border(left: side1, top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
expect((borderWithRight + borderDirectionalWithStart).toString(), '$borderWithRight + $borderDirectionalWithStart');
|
||||||
|
expect((borderWithRight + borderDirectionalWithEnd).toString(), '$borderWithRight + $borderDirectionalWithEnd');
|
||||||
|
expect((borderWithRight + borderDirectionalWithoutSides).toString(), '${const Border(right: side1, top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
expect((borderWithoutSides + borderDirectionalWithStart).toString(), '${const BorderDirectional(start: side1, top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
expect((borderWithoutSides + borderDirectionalWithEnd).toString(), '${const BorderDirectional(end: side1, top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
expect((borderWithoutSides + borderDirectionalWithoutSides).toString(), '${const Border(top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
|
||||||
|
expect((borderDirectionalWithStart + borderWithLeft).toString(), '$borderDirectionalWithStart + $borderWithLeft');
|
||||||
|
expect((borderDirectionalWithEnd + borderWithLeft).toString(), '$borderDirectionalWithEnd + $borderWithLeft');
|
||||||
|
expect((borderDirectionalWithoutSides + borderWithLeft).toString(), '${const Border(left: side1, top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
expect((borderDirectionalWithStart + borderWithRight).toString(), '$borderDirectionalWithStart + $borderWithRight');
|
||||||
|
expect((borderDirectionalWithEnd + borderWithRight).toString(), '$borderDirectionalWithEnd + $borderWithRight');
|
||||||
|
expect((borderDirectionalWithoutSides + borderWithRight).toString(), '${const Border(right: side1, top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
expect((borderDirectionalWithStart + borderWithoutSides).toString(), '${const BorderDirectional(start: side1, top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
expect((borderDirectionalWithEnd + borderWithoutSides).toString(), '${const BorderDirectional(end: side1, top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
expect((borderDirectionalWithoutSides + borderWithoutSides).toString(), '${const Border(top: doubleSide2, bottom: doubleSide2)}');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional.scale', () {
|
||||||
|
final BorderSide magenta3 = const BorderSide(color: const Color(0xFFFF00FF), width: 3.0);
|
||||||
|
final BorderSide magenta6 = const BorderSide(color: const Color(0xFFFF00FF), width: 6.0);
|
||||||
|
final BorderSide yellow2 = const BorderSide(color: const Color(0xFFFFFF00), width: 2.0);
|
||||||
|
final BorderSide yellowNone0 = const BorderSide(color: const Color(0xFFFFFF00), width: 0.0, style: BorderStyle.none);
|
||||||
|
final BorderDirectional b3 = new BorderDirectional(start: magenta3);
|
||||||
|
final BorderDirectional b6 = new BorderDirectional(start: magenta6);
|
||||||
|
expect(b3.scale(2.0), b6);
|
||||||
|
final BorderDirectional bY0 = new BorderDirectional(top: yellowNone0);
|
||||||
|
expect(bY0.scale(3.0), bY0);
|
||||||
|
final BorderDirectional bY2 = new BorderDirectional(top: yellow2);
|
||||||
|
expect(bY2.scale(0.0), bY0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional.lerp', () {
|
||||||
|
final BorderDirectional directionalWithTop10 = const BorderDirectional(top: const BorderSide(width: 10.0));
|
||||||
|
final BorderDirectional atMinus100 = const BorderDirectional(start: const BorderSide(width: 0.0), end: const BorderSide(width: 300.0));
|
||||||
|
final BorderDirectional at0 = const BorderDirectional(start: const BorderSide(width: 100.0), end: const BorderSide(width: 200.0));
|
||||||
|
final BorderDirectional at25 = const BorderDirectional(start: const BorderSide(width: 125.0), end: const BorderSide(width: 175.0));
|
||||||
|
final BorderDirectional at75 = const BorderDirectional(start: const BorderSide(width: 175.0), end: const BorderSide(width: 125.0));
|
||||||
|
final BorderDirectional at100 = const BorderDirectional(start: const BorderSide(width: 200.0), end: const BorderSide(width: 100.0));
|
||||||
|
final BorderDirectional at200 = const BorderDirectional(start: const BorderSide(width: 300.0), end: const BorderSide(width: 0.0));
|
||||||
|
|
||||||
|
expect(BorderDirectional.lerp(null, null, -1.0), null);
|
||||||
|
expect(BorderDirectional.lerp(directionalWithTop10, null, -1.0), const BorderDirectional(top: const BorderSide(width: 20.0)));
|
||||||
|
expect(BorderDirectional.lerp(null, directionalWithTop10, -1.0), const BorderDirectional());
|
||||||
|
expect(BorderDirectional.lerp(at0, at100, -1.0), atMinus100);
|
||||||
|
|
||||||
|
expect(BorderDirectional.lerp(null, null, 0.0), null);
|
||||||
|
expect(BorderDirectional.lerp(directionalWithTop10, null, 0.0), const BorderDirectional(top: const BorderSide(width: 10.0)));
|
||||||
|
expect(BorderDirectional.lerp(null, directionalWithTop10, 0.0), const BorderDirectional());
|
||||||
|
expect(BorderDirectional.lerp(at0, at100, 0.0), at0);
|
||||||
|
|
||||||
|
expect(BorderDirectional.lerp(null, null, 0.25), null);
|
||||||
|
expect(BorderDirectional.lerp(directionalWithTop10, null, 0.25), const BorderDirectional(top: const BorderSide(width: 7.5)));
|
||||||
|
expect(BorderDirectional.lerp(null, directionalWithTop10, 0.25), const BorderDirectional(top: const BorderSide(width: 2.5)));
|
||||||
|
expect(BorderDirectional.lerp(at0, at100, 0.25), at25);
|
||||||
|
|
||||||
|
expect(BorderDirectional.lerp(null, null, 0.75), null);
|
||||||
|
expect(BorderDirectional.lerp(directionalWithTop10, null, 0.75), const BorderDirectional(top: const BorderSide(width: 2.5)));
|
||||||
|
expect(BorderDirectional.lerp(null, directionalWithTop10, 0.75), const BorderDirectional(top: const BorderSide(width: 7.5)));
|
||||||
|
expect(BorderDirectional.lerp(at0, at100, 0.75), at75);
|
||||||
|
|
||||||
|
expect(BorderDirectional.lerp(null, null, 1.0), null);
|
||||||
|
expect(BorderDirectional.lerp(directionalWithTop10, null, 1.0), const BorderDirectional());
|
||||||
|
expect(BorderDirectional.lerp(null, directionalWithTop10, 1.0), const BorderDirectional(top: const BorderSide(width: 10.0)));
|
||||||
|
expect(BorderDirectional.lerp(at0, at100, 1.0), at100);
|
||||||
|
|
||||||
|
expect(BorderDirectional.lerp(null, null, 2.0), null);
|
||||||
|
expect(BorderDirectional.lerp(directionalWithTop10, null, 2.0), const BorderDirectional());
|
||||||
|
expect(BorderDirectional.lerp(null, directionalWithTop10, 2.0), const BorderDirectional(top: const BorderSide(width: 20.0)));
|
||||||
|
expect(BorderDirectional.lerp(at0, at100, 2.0), at200);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional.paint', () {
|
||||||
|
expect(
|
||||||
|
(Canvas canvas) {
|
||||||
|
const BorderDirectional(end: const BorderSide(width: 10.0, color: const Color(0xFF00FF00)))
|
||||||
|
.paint(canvas, new Rect.fromLTRB(10.0, 20.0, 30.0, 40.0), textDirection: TextDirection.rtl);
|
||||||
|
},
|
||||||
|
paints
|
||||||
|
..path(
|
||||||
|
includes: <Offset>[const Offset(15.0, 30.0)],
|
||||||
|
excludes: <Offset>[const Offset(25.0, 30.0)],
|
||||||
|
color: const Color(0xFF00FF00),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
(Canvas canvas) {
|
||||||
|
const BorderDirectional(end: const BorderSide(width: 10.0, color: const Color(0xFF00FF00)))
|
||||||
|
.paint(canvas, new Rect.fromLTRB(10.0, 20.0, 30.0, 40.0), textDirection: TextDirection.ltr);
|
||||||
|
},
|
||||||
|
paints
|
||||||
|
..path(
|
||||||
|
includes: <Offset>[const Offset(25.0, 30.0)],
|
||||||
|
excludes: <Offset>[const Offset(15.0, 30.0)],
|
||||||
|
color: const Color(0xFF00FF00),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
(Canvas canvas) {
|
||||||
|
const BorderDirectional(end: const BorderSide(width: 10.0, color: const Color(0xFF00FF00)))
|
||||||
|
.paint(canvas, new Rect.fromLTRB(10.0, 20.0, 30.0, 40.0));
|
||||||
|
},
|
||||||
|
paintsAssertion // no TextDirection
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BorderDirectional hashCode', () {
|
||||||
|
final BorderSide side = const BorderSide(width: 2.0);
|
||||||
|
expect(new BorderDirectional(top: side).hashCode, new BorderDirectional(top: side).hashCode);
|
||||||
|
expect(new BorderDirectional(top: side).hashCode, isNot(new BorderDirectional(bottom: side).hashCode));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BoxDecoration.border takes a BorderDirectional', () {
|
||||||
|
const BoxDecoration decoration2 = const BoxDecoration(
|
||||||
|
border: const BorderDirectional(start: const BorderSide(width: 2.0)),
|
||||||
|
);
|
||||||
|
const BoxDecoration decoration4 = const BoxDecoration(
|
||||||
|
border: const BorderDirectional(start: const BorderSide(width: 4.0)),
|
||||||
|
);
|
||||||
|
const BoxDecoration decoration6 = const BoxDecoration(
|
||||||
|
border: const BorderDirectional(start: const BorderSide(width: 6.0)),
|
||||||
|
);
|
||||||
|
final BoxPainter painter = decoration2.createBoxPainter();
|
||||||
|
expect(
|
||||||
|
(Canvas canvas) {
|
||||||
|
painter.paint(
|
||||||
|
canvas,
|
||||||
|
const Offset(30.0, 0.0),
|
||||||
|
const ImageConfiguration(size: const Size(20.0, 20.0), textDirection: TextDirection.rtl),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
paints
|
||||||
|
..path(
|
||||||
|
includes: <Offset>[const Offset(49.0, 10.0)],
|
||||||
|
excludes: <Offset>[const Offset(31.0, 10.0)],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
(Canvas canvas) {
|
||||||
|
painter.paint(
|
||||||
|
canvas,
|
||||||
|
const Offset(30.0, 0.0),
|
||||||
|
const ImageConfiguration(size: const Size(20.0, 20.0), textDirection: TextDirection.ltr),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
paints
|
||||||
|
..path(
|
||||||
|
includes: <Offset>[const Offset(31.0, 10.0)],
|
||||||
|
excludes: <Offset>[const Offset(49.0, 10.0)],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expect(decoration2.padding, const EdgeInsetsDirectional.fromSTEB(2.0, 0.0, 0.0, 0.0));
|
||||||
|
expect(decoration2.scale(2.0), decoration4);
|
||||||
|
expect(BoxDecoration.lerp(decoration2, decoration6, 0.5), decoration4);
|
||||||
|
});
|
||||||
|
}
|
@ -128,10 +128,11 @@ void main() {
|
|||||||
final BorderSide side0 = const BorderSide(width: 0.0);
|
final BorderSide side0 = const BorderSide(width: 0.0);
|
||||||
final BorderSide side1 = const BorderSide(width: 1.0);
|
final BorderSide side1 = const BorderSide(width: 1.0);
|
||||||
final BorderSide side2 = const BorderSide(width: 2.0);
|
final BorderSide side2 = const BorderSide(width: 2.0);
|
||||||
expect(BorderSide.lerp(side2, side1, 10.0), side0);
|
expect(BorderSide.lerp(side2, side1, 10.0), BorderSide.none);
|
||||||
expect(BorderSide.lerp(side1, side2, -10.0), side0);
|
expect(BorderSide.lerp(side1, side2, -10.0), BorderSide.none);
|
||||||
expect(BorderSide.lerp(side0, side1, 2.0), side2);
|
expect(BorderSide.lerp(side0, side1, 2.0), side2);
|
||||||
expect(BorderSide.lerp(side1, side0, 2.0), side0);
|
expect(BorderSide.lerp(side1, side0, 2.0), BorderSide.none);
|
||||||
|
expect(BorderSide.lerp(side2, side1, 2.0), side0);
|
||||||
});
|
});
|
||||||
test('BorderSide - toString', () {
|
test('BorderSide - toString', () {
|
||||||
expect(
|
expect(
|
||||||
|
@ -6,6 +6,14 @@ import 'package:flutter/painting.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
test('Border constructor', () {
|
||||||
|
final Null $null = null;
|
||||||
|
expect(() => new Border(left: $null), throwsAssertionError);
|
||||||
|
expect(() => new Border(top: $null), throwsAssertionError);
|
||||||
|
expect(() => new Border(right: $null), throwsAssertionError);
|
||||||
|
expect(() => new Border(bottom: $null), throwsAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
test('Border.merge', () {
|
test('Border.merge', () {
|
||||||
final BorderSide magenta3 = const BorderSide(color: const Color(0xFFFF00FF), width: 3.0);
|
final BorderSide magenta3 = const BorderSide(color: const Color(0xFFFF00FF), width: 3.0);
|
||||||
final BorderSide magenta6 = const BorderSide(color: const Color(0xFFFF00FF), width: 6.0);
|
final BorderSide magenta6 = const BorderSide(color: const Color(0xFFFF00FF), width: 6.0);
|
||||||
@ -94,4 +102,135 @@ void main() {
|
|||||||
final Border bY2 = new Border(top: yellow2);
|
final Border bY2 = new Border(top: yellow2);
|
||||||
expect(bY2.scale(0.0), bY0);
|
expect(bY2.scale(0.0), bY0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Border.dimensions', () {
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(width: 2.0),
|
||||||
|
top: const BorderSide(width: 3.0),
|
||||||
|
bottom: const BorderSide(width: 5.0),
|
||||||
|
right: const BorderSide(width: 7.0),
|
||||||
|
).dimensions,
|
||||||
|
const EdgeInsets.fromLTRB(2.0, 3.0, 7.0, 5.0),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Border.isUniform', () {
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(width: 3.0),
|
||||||
|
top: const BorderSide(width: 3.0),
|
||||||
|
right: const BorderSide(width: 3.0),
|
||||||
|
bottom: const BorderSide(width: 3.1),
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(width: 3.0),
|
||||||
|
top: const BorderSide(width: 3.0),
|
||||||
|
right: const BorderSide(width: 3.0),
|
||||||
|
bottom: const BorderSide(width: 3.0),
|
||||||
|
).isUniform,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(color: const Color(0xFFFFFFFE)),
|
||||||
|
top: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
right: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
bottom: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
top: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
right: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
bottom: const BorderSide(color: const Color(0xFFFFFFFF)),
|
||||||
|
).isUniform,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(style: BorderStyle.none),
|
||||||
|
top: const BorderSide(style: BorderStyle.none),
|
||||||
|
right: const BorderSide(style: BorderStyle.none),
|
||||||
|
bottom: const BorderSide(style: BorderStyle.solid, width: 0.0),
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(style: BorderStyle.none),
|
||||||
|
top: const BorderSide(style: BorderStyle.none),
|
||||||
|
right: const BorderSide(style: BorderStyle.none),
|
||||||
|
bottom: const BorderSide(style: BorderStyle.solid, width: 0.0),
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(style: BorderStyle.none),
|
||||||
|
top: const BorderSide(style: BorderStyle.none),
|
||||||
|
right: const BorderSide(style: BorderStyle.none),
|
||||||
|
bottom: BorderSide.none,
|
||||||
|
).isUniform,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const Border(
|
||||||
|
left: const BorderSide(style: BorderStyle.none, width: 0.0),
|
||||||
|
top: const BorderSide(style: BorderStyle.none, width: 0.0),
|
||||||
|
right: const BorderSide(style: BorderStyle.none, width: 0.0),
|
||||||
|
bottom: BorderSide.none,
|
||||||
|
).isUniform,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
const Border().isUniform,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Border.lerp', () {
|
||||||
|
final Border visualWithTop10 = const Border(top: const BorderSide(width: 10.0));
|
||||||
|
final Border atMinus100 = const Border(left: const BorderSide(width: 0.0), right: const BorderSide(width: 300.0));
|
||||||
|
final Border at0 = const Border(left: const BorderSide(width: 100.0), right: const BorderSide(width: 200.0));
|
||||||
|
final Border at25 = const Border(left: const BorderSide(width: 125.0), right: const BorderSide(width: 175.0));
|
||||||
|
final Border at75 = const Border(left: const BorderSide(width: 175.0), right: const BorderSide(width: 125.0));
|
||||||
|
final Border at100 = const Border(left: const BorderSide(width: 200.0), right: const BorderSide(width: 100.0));
|
||||||
|
final Border at200 = const Border(left: const BorderSide(width: 300.0), right: const BorderSide(width: 0.0));
|
||||||
|
|
||||||
|
expect(Border.lerp(null, null, -1.0), null);
|
||||||
|
expect(Border.lerp(visualWithTop10, null, -1.0), const Border(top: const BorderSide(width: 20.0)));
|
||||||
|
expect(Border.lerp(null, visualWithTop10, -1.0), const Border());
|
||||||
|
expect(Border.lerp(at0, at100, -1.0), atMinus100);
|
||||||
|
|
||||||
|
expect(Border.lerp(null, null, 0.0), null);
|
||||||
|
expect(Border.lerp(visualWithTop10, null, 0.0), const Border(top: const BorderSide(width: 10.0)));
|
||||||
|
expect(Border.lerp(null, visualWithTop10, 0.0), const Border());
|
||||||
|
expect(Border.lerp(at0, at100, 0.0), at0);
|
||||||
|
|
||||||
|
expect(Border.lerp(null, null, 0.25), null);
|
||||||
|
expect(Border.lerp(visualWithTop10, null, 0.25), const Border(top: const BorderSide(width: 7.5)));
|
||||||
|
expect(Border.lerp(null, visualWithTop10, 0.25), const Border(top: const BorderSide(width: 2.5)));
|
||||||
|
expect(Border.lerp(at0, at100, 0.25), at25);
|
||||||
|
|
||||||
|
expect(Border.lerp(null, null, 0.75), null);
|
||||||
|
expect(Border.lerp(visualWithTop10, null, 0.75), const Border(top: const BorderSide(width: 2.5)));
|
||||||
|
expect(Border.lerp(null, visualWithTop10, 0.75), const Border(top: const BorderSide(width: 7.5)));
|
||||||
|
expect(Border.lerp(at0, at100, 0.75), at75);
|
||||||
|
|
||||||
|
expect(Border.lerp(null, null, 1.0), null);
|
||||||
|
expect(Border.lerp(visualWithTop10, null, 1.0), const Border());
|
||||||
|
expect(Border.lerp(null, visualWithTop10, 1.0), const Border(top: const BorderSide(width: 10.0)));
|
||||||
|
expect(Border.lerp(at0, at100, 1.0), at100);
|
||||||
|
|
||||||
|
expect(Border.lerp(null, null, 2.0), null);
|
||||||
|
expect(Border.lerp(visualWithTop10, null, 2.0), const Border());
|
||||||
|
expect(Border.lerp(null, visualWithTop10, 2.0), const Border(top: const BorderSide(width: 20.0)));
|
||||||
|
expect(Border.lerp(at0, at100, 2.0), at200);
|
||||||
|
});
|
||||||
}
|
}
|
@ -70,4 +70,69 @@ void main() {
|
|||||||
..rect(rect: rect.deflate(2.5), color: b1.top.color)
|
..rect(rect: rect.deflate(2.5), color: b1.top.color)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Compound borders', () {
|
||||||
|
final BorderSide side1 = const BorderSide(color: const Color(0xFF00FF00));
|
||||||
|
final BorderSide side2 = const BorderSide(color: const Color(0xFF0000FF));
|
||||||
|
final BorderDirectional b1 = new BorderDirectional(top: side1, start: side1, end: side1, bottom: side1);
|
||||||
|
final BorderDirectional b2 = new BorderDirectional(top: side2, start: side2, end: side2, bottom: side2);
|
||||||
|
expect(
|
||||||
|
(b1 + b2).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid))',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
(b1 + (b2 + b2)).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid))',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
((b1 + b2) + b2).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid))',
|
||||||
|
);
|
||||||
|
expect((b1 + b2) + b2, b1 + (b2 + b2));
|
||||||
|
expect(
|
||||||
|
(b1 + b2).scale(3.0).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid))',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
(b1 + b2).scale(0.0).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), start: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), end: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), bottom: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), start: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), end: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), bottom: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none))',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
ShapeBorder.lerp(b2 + b1, b1 + b2, 0.0).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid))',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
ShapeBorder.lerp(b2 + b1, b1 + b2, 0.25).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid))',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
ShapeBorder.lerp(b2 + b1, b1 + b2, 0.5).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid))',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
ShapeBorder.lerp(b2 + b1, b1 + b2, 1.0).toString(),
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + '
|
||||||
|
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid))'
|
||||||
|
);
|
||||||
|
expect((b1 + b2).dimensions, const EdgeInsetsDirectional.fromSTEB(2.0, 2.0, 2.0, 2.0));
|
||||||
|
final Rect rect = new Rect.fromLTRB(11.0, 15.0, 299.0, 175.0);
|
||||||
|
expect((Canvas canvas) => (b1 + b2).paint(canvas, rect, textDirection: TextDirection.rtl), paints
|
||||||
|
..rect(rect: rect.deflate(0.5), color: b2.top.color)
|
||||||
|
..rect(rect: rect.deflate(1.5), color: b1.top.color)
|
||||||
|
);
|
||||||
|
expect((b1 + b2 + b1).dimensions, const EdgeInsetsDirectional.fromSTEB(3.0, 3.0, 3.0, 3.0));
|
||||||
|
expect((Canvas canvas) => (b1 + b2 + b1).paint(canvas, rect, textDirection: TextDirection.rtl), paints
|
||||||
|
..rect(rect: rect.deflate(0.5), color: b1.top.color)
|
||||||
|
..rect(rect: rect.deflate(1.5), color: b2.top.color)
|
||||||
|
..rect(rect: rect.deflate(2.5), color: b1.top.color)
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,16 @@ import 'recording_canvas.dart';
|
|||||||
/// See [PaintPattern] for a discussion of the semantics of paint patterns.
|
/// See [PaintPattern] for a discussion of the semantics of paint patterns.
|
||||||
///
|
///
|
||||||
/// To match something which paints nothing, see [paintsNothing].
|
/// To match something which paints nothing, see [paintsNothing].
|
||||||
|
///
|
||||||
|
/// To match something which asserts instead of painting, see [paintsAssertion].
|
||||||
PaintPattern get paints => new _TestRecordingCanvasPatternMatcher();
|
PaintPattern get paints => new _TestRecordingCanvasPatternMatcher();
|
||||||
|
|
||||||
/// Matches objects or functions that paint an empty display list.
|
/// Matches objects or functions that paint an empty display list.
|
||||||
Matcher get paintsNothing => new _TestRecordingCanvasPaintsNothingMatcher();
|
Matcher get paintsNothing => new _TestRecordingCanvasPaintsNothingMatcher();
|
||||||
|
|
||||||
|
/// Matches objects or functions that assert when they try to paint.
|
||||||
|
Matcher get paintsAssertion => new _TestRecordingCanvasPaintsAssertionMatcher();
|
||||||
|
|
||||||
/// Signature for [PaintPattern.something] predicate argument.
|
/// Signature for [PaintPattern.something] predicate argument.
|
||||||
///
|
///
|
||||||
/// Used by the [paints] matcher.
|
/// Used by the [paints] matcher.
|
||||||
@ -218,8 +223,10 @@ abstract class PaintPattern {
|
|||||||
/// are compared to the actual [Canvas.drawPath] call's `paint` argument, and
|
/// are compared to the actual [Canvas.drawPath] call's `paint` argument, and
|
||||||
/// any mismatches result in failure.
|
/// any mismatches result in failure.
|
||||||
///
|
///
|
||||||
/// There is currently no way to check the actual path itself.
|
/// To introspect the Path object (as it stands after the painting has
|
||||||
// See https://github.com/flutter/flutter/issues/93 which tracks that issue.
|
/// completed), the `includes` and `excludes` arguments can be provided to
|
||||||
|
/// specify points that should be considered inside or outside the path
|
||||||
|
/// (respectively).
|
||||||
///
|
///
|
||||||
/// If no call to [Canvas.drawPath] was made, then this results in failure.
|
/// If no call to [Canvas.drawPath] was made, then this results in failure.
|
||||||
///
|
///
|
||||||
@ -231,7 +238,7 @@ abstract class PaintPattern {
|
|||||||
/// painting has completed, not at the time of the call. If the same [Paint]
|
/// painting has completed, not at the time of the call. If the same [Paint]
|
||||||
/// object is reused multiple times, then this may not match the actual
|
/// object is reused multiple times, then this may not match the actual
|
||||||
/// arguments as they were seen by the method.
|
/// arguments as they were seen by the method.
|
||||||
void path({ Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style });
|
void path({ Iterable<Offset> includes, Iterable<Offset> excludes, Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style });
|
||||||
|
|
||||||
/// Indicates that a line is expected next.
|
/// Indicates that a line is expected next.
|
||||||
///
|
///
|
||||||
@ -327,6 +334,29 @@ class _MismatchedCall {
|
|||||||
final RecordedInvocation call;
|
final RecordedInvocation call;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _evaluatePainter(Object object, Canvas canvas, PaintingContext context) {
|
||||||
|
if (object is _ContextPainterFunction) {
|
||||||
|
final _ContextPainterFunction function = object;
|
||||||
|
function(context, Offset.zero);
|
||||||
|
} else if (object is _CanvasPainterFunction) {
|
||||||
|
final _CanvasPainterFunction function = object;
|
||||||
|
function(canvas);
|
||||||
|
} else {
|
||||||
|
if (object is Finder) {
|
||||||
|
TestAsyncUtils.guardSync();
|
||||||
|
final Finder finder = object;
|
||||||
|
object = finder.evaluate().single.renderObject;
|
||||||
|
}
|
||||||
|
if (object is RenderObject) {
|
||||||
|
final RenderObject renderObject = object;
|
||||||
|
renderObject.paint(context, Offset.zero);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
abstract class _TestRecordingCanvasMatcher extends Matcher {
|
abstract class _TestRecordingCanvasMatcher extends Matcher {
|
||||||
@override
|
@override
|
||||||
bool matches(Object object, Map<dynamic, dynamic> matchState) {
|
bool matches(Object object, Map<dynamic, dynamic> matchState) {
|
||||||
@ -336,25 +366,9 @@ abstract class _TestRecordingCanvasMatcher extends Matcher {
|
|||||||
String prefixMessage = 'unexpectedly failed.';
|
String prefixMessage = 'unexpectedly failed.';
|
||||||
bool result = false;
|
bool result = false;
|
||||||
try {
|
try {
|
||||||
if (object is _ContextPainterFunction) {
|
if (!_evaluatePainter(object, canvas, context)) {
|
||||||
final _ContextPainterFunction function = object;
|
matchState[this] = 'was not one of the supported objects for the "paints" matcher.';
|
||||||
function(context, Offset.zero);
|
return false;
|
||||||
} else if (object is _CanvasPainterFunction) {
|
|
||||||
final _CanvasPainterFunction function = object;
|
|
||||||
function(canvas);
|
|
||||||
} else {
|
|
||||||
if (object is Finder) {
|
|
||||||
TestAsyncUtils.guardSync();
|
|
||||||
final Finder finder = object;
|
|
||||||
object = finder.evaluate().single.renderObject;
|
|
||||||
}
|
|
||||||
if (object is RenderObject) {
|
|
||||||
final RenderObject renderObject = object;
|
|
||||||
renderObject.paint(context, Offset.zero);
|
|
||||||
} else {
|
|
||||||
matchState[this] = 'was not one of the supported objects for the "paints" matcher.';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result = _evaluatePredicates(canvas.invocations, description);
|
result = _evaluatePredicates(canvas.invocations, description);
|
||||||
if (!result)
|
if (!result)
|
||||||
@ -407,6 +421,55 @@ class _TestRecordingCanvasPaintsNothingMatcher extends _TestRecordingCanvasMatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher {
|
||||||
|
@override
|
||||||
|
bool matches(Object object, Map<dynamic, dynamic> matchState) {
|
||||||
|
final TestRecordingCanvas canvas = new TestRecordingCanvas();
|
||||||
|
final TestRecordingPaintingContext context = new TestRecordingPaintingContext(canvas);
|
||||||
|
final StringBuffer description = new StringBuffer();
|
||||||
|
String prefixMessage = 'unexpectedly failed.';
|
||||||
|
bool result = false;
|
||||||
|
try {
|
||||||
|
if (!_evaluatePainter(object, canvas, context)) {
|
||||||
|
matchState[this] = 'was not one of the supported objects for the "paints" matcher.';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
prefixMessage = 'did not assert.';
|
||||||
|
} on AssertionError {
|
||||||
|
result = true;
|
||||||
|
} catch (error, stack) {
|
||||||
|
prefixMessage = 'threw the following exception:';
|
||||||
|
description.writeln(error.toString());
|
||||||
|
description.write(stack.toString());
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
if (canvas.invocations.isNotEmpty) {
|
||||||
|
description.write('The complete display list was:');
|
||||||
|
for (RecordedInvocation call in canvas.invocations)
|
||||||
|
description.write('\n * $call');
|
||||||
|
}
|
||||||
|
matchState[this] = '$prefixMessage\n$description';
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Description describe(Description description) {
|
||||||
|
return description.add('An object or closure that asserts when it tries to paint.');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Description describeMismatch(
|
||||||
|
dynamic item,
|
||||||
|
Description description,
|
||||||
|
Map<dynamic, dynamic> matchState,
|
||||||
|
bool verbose,
|
||||||
|
) {
|
||||||
|
return description.add(matchState[this]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher implements PaintPattern {
|
class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher implements PaintPattern {
|
||||||
final List<_PaintPredicate> _predicates = <_PaintPredicate>[];
|
final List<_PaintPredicate> _predicates = <_PaintPredicate>[];
|
||||||
|
|
||||||
@ -471,8 +534,8 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher imp
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void path({ Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) {
|
void path({ Iterable<Offset> includes, Iterable<Offset> excludes, Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) {
|
||||||
_predicates.add(new _PathPaintPredicate(color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style));
|
_predicates.add(new _PathPaintPredicate(includes: includes, excludes: excludes, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -805,9 +868,42 @@ class _CirclePaintPredicate extends _DrawCommandPaintPredicate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PathPaintPredicate extends _DrawCommandPaintPredicate {
|
class _PathPaintPredicate extends _DrawCommandPaintPredicate {
|
||||||
_PathPaintPredicate({ Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) : super(
|
_PathPaintPredicate({ this.includes, this.excludes, Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) : super(
|
||||||
#drawPath, 'a path', 2, 1, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style
|
#drawPath, 'a path', 2, 1, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final Iterable<Offset> includes;
|
||||||
|
final Iterable<Offset> excludes;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void verifyArguments(List<dynamic> arguments) {
|
||||||
|
super.verifyArguments(arguments);
|
||||||
|
final Path pathArgument = arguments[0];
|
||||||
|
if (includes != null) {
|
||||||
|
for (Offset offset in includes) {
|
||||||
|
if (!pathArgument.contains(offset))
|
||||||
|
throw 'It called $methodName with a path that unexpectedly did not contain $offset.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (excludes != null) {
|
||||||
|
for (Offset offset in excludes) {
|
||||||
|
if (pathArgument.contains(offset))
|
||||||
|
throw 'It called $methodName with a path that unexpectedly contained $offset.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillDescription(List<String> description) {
|
||||||
|
super.debugFillDescription(description);
|
||||||
|
if (includes != null && excludes != null) {
|
||||||
|
description.add('that contains $includes and does not contain $excludes');
|
||||||
|
} else if (includes != null) {
|
||||||
|
description.add('that contains $includes');
|
||||||
|
} else if (excludes != null) {
|
||||||
|
description.add('that does not contain $excludes');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(ianh): add arguments to test the points, length, angle, that kind of thing
|
// TODO(ianh): add arguments to test the points, length, angle, that kind of thing
|
||||||
|
@ -77,9 +77,11 @@ void main() {
|
|||||||
actualDecoration = actualBox.decoration;
|
actualDecoration = actualBox.decoration;
|
||||||
|
|
||||||
expect(actualDecoration.color, const Color(0xFF7F7F7F));
|
expect(actualDecoration.color, const Color(0xFF7F7F7F));
|
||||||
expect(actualDecoration.border.left.width, 2.5);
|
expect(actualDecoration.border, const isInstanceOf<Border>());
|
||||||
expect(actualDecoration.border.left.style, BorderStyle.solid);
|
final Border border = actualDecoration.border;
|
||||||
expect(actualDecoration.border.left.color, const Color(0xFF101010));
|
expect(border.left.width, 2.5);
|
||||||
|
expect(border.left.style, BorderStyle.solid);
|
||||||
|
expect(border.left.color, const Color(0xFF101010));
|
||||||
expect(actualDecoration.borderRadius, new BorderRadius.circular(5.0));
|
expect(actualDecoration.borderRadius, new BorderRadius.circular(5.0));
|
||||||
expect(actualDecoration.shape, BoxShape.rectangle);
|
expect(actualDecoration.shape, BoxShape.rectangle);
|
||||||
expect(actualDecoration.boxShadow[0].blurRadius, 5.0);
|
expect(actualDecoration.boxShadow[0].blurRadius, 5.0);
|
||||||
@ -131,9 +133,11 @@ void main() {
|
|||||||
// Same as the test above but the values should be much closer to the
|
// Same as the test above but the values should be much closer to the
|
||||||
// tween's end values given the easeOut curve.
|
// tween's end values given the easeOut curve.
|
||||||
expect(actualDecoration.color, const Color(0xFF505050));
|
expect(actualDecoration.color, const Color(0xFF505050));
|
||||||
expect(actualDecoration.border.left.width, closeTo(1.9, 0.1));
|
expect(actualDecoration.border, const isInstanceOf<Border>());
|
||||||
expect(actualDecoration.border.left.style, BorderStyle.solid);
|
final Border border = actualDecoration.border;
|
||||||
expect(actualDecoration.border.left.color, const Color(0xFF151515));
|
expect(border.left.width, closeTo(1.9, 0.1));
|
||||||
|
expect(border.left.style, BorderStyle.solid);
|
||||||
|
expect(border.left.color, const Color(0xFF151515));
|
||||||
expect(actualDecoration.borderRadius.topLeft.x, closeTo(6.8, 0.1));
|
expect(actualDecoration.borderRadius.topLeft.x, closeTo(6.8, 0.1));
|
||||||
expect(actualDecoration.shape, BoxShape.rectangle);
|
expect(actualDecoration.shape, BoxShape.rectangle);
|
||||||
expect(actualDecoration.boxShadow[0].blurRadius, closeTo(3.1, 0.1));
|
expect(actualDecoration.boxShadow[0].blurRadius, closeTo(3.1, 0.1));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user