Commit 1f05c2c3 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

BorderRadius RTL (#12149)

Add an RTL version of BorderRadius.
Minor fixes to EdgeInsets to match.
parent 61a2492a
......@@ -6,46 +6,309 @@ import 'package:flutter/foundation.dart';
import 'basic_types.dart';
/// Base class for [BorderRadius] that allows for text-direction aware resolution.
///
/// A property or argument of this type accepts classes created either with [new
/// BorderRadius.only] and its variants, or [new BorderRadiusDirectional.only]
/// and its variants.
///
/// To convert a [BorderRadiusGeometry] object of indeterminate type into a
/// [BorderRadius] object, call the [resolve] method.
@immutable
abstract class BorderRadiusGeometry {
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const BorderRadiusGeometry();
Radius get _topLeft;
Radius get _topRight;
Radius get _bottomLeft;
Radius get _bottomRight;
Radius get _topStart;
Radius get _topEnd;
Radius get _bottomStart;
Radius get _bottomEnd;
/// Returns the difference between two [BorderRadiusGeometry] objects.
///
/// If you know you are applying this to two [BorderRadius] or two
/// [BorderRadiusDirectional] objects, consider using the binary infix `-`
/// operator instead, which always returns an object of the same type as the
/// operands, and is typed accordingly.
///
/// If [subtract] is applied to two objects of the same type ([BorderRadius] or
/// [BorderRadiusDirectional]), an object of that type will be returned (though
/// this is not reflected in the type system). Otherwise, an object
/// representing a combination of both is returned. That object can be turned
/// into a concrete [BorderRadius] using [resolve].
///
/// This method returns the same result as [add] applied to the result of
/// negating the argument (using the prefix unary `-` operator or multiplying
/// the argument by -1.0 using the `*` operator).
BorderRadiusGeometry subtract(BorderRadiusGeometry other) {
return new _MixedBorderRadius(
_topLeft - other._topLeft,
_topRight - other._topRight,
_bottomLeft - other._bottomLeft,
_bottomRight - other._bottomRight,
_topStart - other._topStart,
_topEnd - other._topEnd,
_bottomStart - other._bottomStart,
_bottomEnd - other._bottomEnd,
);
}
/// Returns the sum of two [BorderRadiusGeometry] objects.
///
/// If you know you are adding two [BorderRadius] or two [BorderRadiusDirectional]
/// objects, consider using the `+` operator instead, which always returns an
/// object of the same type as the operands, and is typed accordingly.
///
/// If [add] is applied to two objects of the same type ([BorderRadius] or
/// [BorderRadiusDirectional]), an object of that type will be returned (though
/// this is not reflected in the type system). Otherwise, an object
/// representing a combination of both is returned. That object can be turned
/// into a concrete [BorderRadius] using [resolve].
BorderRadiusGeometry add(BorderRadiusGeometry other) {
return new _MixedBorderRadius(
_topLeft + other._topLeft,
_topRight + other._topRight,
_bottomLeft + other._bottomLeft,
_bottomRight + other._bottomRight,
_topStart + other._topStart,
_topEnd + other._topEnd,
_bottomStart + other._bottomStart,
_bottomEnd + other._bottomEnd,
);
}
/// Returns the [BorderRadiusGeometry] object with each corner radius negated.
///
/// This is the same as multiplying the object by -1.0.
///
/// This operator returns an object of the same type as the operand.
BorderRadiusGeometry operator -();
/// Scales the [BorderRadiusGeometry] object's corners by the given factor.
///
/// This operator returns an object of the same type as the operand.
BorderRadiusGeometry operator *(double other);
/// Divides the [BorderRadiusGeometry] object's corners by the given factor.
///
/// This operator returns an object of the same type as the operand.
BorderRadiusGeometry operator /(double other);
/// Integer divides the [BorderRadiusGeometry] object's corners by the given factor.
///
/// This operator returns an object of the same type as the operand.
///
/// This operator may have unexpected results when applied to a mixture of
/// [BorderRadius] and [BorderRadiusDirectional] objects.
BorderRadiusGeometry operator ~/(double other);
/// Computes the remainder of each corner by the given factor.
///
/// This operator returns an object of the same type as the operand.
///
/// This operator may have unexpected results when applied to a mixture of
/// [BorderRadius] and [BorderRadiusDirectional] objects.
BorderRadiusGeometry operator %(double other);
/// Linearly interpolate between two [BorderRadiusGeometry] objects.
///
/// If either is null, this function interpolates from [BorderRadius.zero], and
/// the result is an object of the same type as the non-null argument.
///
/// If [lerp] is applied to two objects of the same type ([BorderRadius] or
/// [BorderRadiusDirectional]), an object of that type will be returned (though
/// this is not reflected in the type system). Otherwise, an object
/// representing a combination of both is returned. That object can be turned
/// into a concrete [BorderRadius] using [resolve].
static BorderRadiusGeometry lerp(BorderRadiusGeometry a, BorderRadiusGeometry b, double t) {
a ??= BorderRadius.zero;
b ??= BorderRadius.zero;
return a.add((b.subtract(a)) * t);
}
/// Convert this instance into a [BorderRadius], so that the radii are
/// expressed for specific physical corners (top-left, top-right, etc) rather
/// than in a direction-dependent manner.
///
/// See also:
///
/// * [BorderRadius], for which this is a no-op (returns itself).
/// * [BorderRadiusDirectional], which flips the horizontal direction
/// based on the `direction` argument.
BorderRadius resolve(TextDirection direction);
@override
String toString() {
String visual, logical;
if (_topLeft == _topRight &&
_topRight == _bottomLeft &&
_bottomLeft == _bottomRight) {
if (_topLeft != Radius.zero) {
if (_topLeft.x == _topLeft.y) {
visual = 'BorderRadius.circular(${_topLeft.x.toStringAsFixed(1)})';
} else {
visual = 'BorderRadius.all($_topLeft)';
}
}
} else {
// visuals aren't the same and at least one isn't zero
final StringBuffer result = new StringBuffer();
result.write('BorderRadius.only(');
bool comma = false;
if (_topLeft != Radius.zero) {
result.write('topLeft: $_topLeft');
comma = true;
}
if (_topRight != Radius.zero) {
if (comma)
result.write(', ');
result.write('topRight: $_topRight');
comma = true;
}
if (_bottomLeft != Radius.zero) {
if (comma)
result.write(', ');
result.write('bottomLeft: $_bottomLeft');
comma = true;
}
if (_bottomRight != Radius.zero) {
if (comma)
result.write(', ');
result.write('bottomRight: $_bottomRight');
}
result.write(')');
visual = result.toString();
}
if (_topStart == _topEnd &&
_topEnd == _bottomEnd &&
_bottomEnd == _bottomStart) {
if (_topStart != Radius.zero) {
if (_topStart.x == _topStart.y) {
logical = 'BorderRadiusDirectional.circular(${_topStart.x.toStringAsFixed(1)})';
} else {
logical = 'BorderRadiusDirectional.all($_topStart)';
}
}
} else {
// logicals aren't the same and at least one isn't zero
final StringBuffer result = new StringBuffer();
result.write('BorderRadiusDirectional.only(');
bool comma = false;
if (_topStart != Radius.zero) {
result.write('topStart: $_topStart');
comma = true;
}
if (_topEnd != Radius.zero) {
if (comma)
result.write(', ');
result.write('topEnd: $_topEnd');
comma = true;
}
if (_bottomStart != Radius.zero) {
if (comma)
result.write(', ');
result.write('bottomStart: $_bottomStart');
comma = true;
}
if (_bottomEnd != Radius.zero) {
if (comma)
result.write(', ');
result.write('bottomEnd: $_bottomEnd');
}
result.write(')');
logical = result.toString();
}
if (visual != null && logical != null)
return '$visual + $logical';
if (visual != null)
return visual;
if (logical != null)
return logical;
return 'BorderRadius.zero';
}
@override
bool operator ==(dynamic other) {
if (identical(this, other))
return true;
if (runtimeType != other.runtimeType)
return false;
final BorderRadiusGeometry typedOther = other;
return _topLeft == typedOther._topLeft
&& _topRight == typedOther._topRight
&& _bottomLeft == typedOther._bottomLeft
&& _bottomRight == typedOther._bottomRight
&& _topStart == typedOther._topStart
&& _topEnd == typedOther._topEnd
&& _bottomStart == typedOther._bottomStart
&& _bottomEnd == typedOther._bottomEnd;
}
@override
int get hashCode {
return hashValues(
_topLeft,
_topRight,
_bottomLeft,
_bottomRight,
_topStart,
_topEnd,
_bottomStart,
_bottomEnd,
);
}
}
/// An immutable set of radii for each corner of a rectangle.
///
/// Used by [BoxDecoration] when the shape is a [BoxShape.rectangle].
@immutable
class BorderRadius {
///
/// The [BorderRadius] class specifies offsets in terms of visual corners, e.g.
/// [topLeft]. These values are not affected by the [TextDirection]. To support
/// both left-to-right and right-to-left layouts, consider using
/// [BorderRadiusDirectional], which is expressed in terms that are relative to
/// a [TextDirection] (typically obtained from the ambient [Directionality]).
class BorderRadius extends BorderRadiusGeometry {
/// Creates a border radius where all radii are [radius].
const BorderRadius.all(Radius radius) : this.only(
topLeft: radius,
topRight: radius,
bottomLeft: radius,
bottomRight: radius,
bottomLeft: radius
);
/// Creates a border radius where all radii are [Radius.circular(radius)].
BorderRadius.circular(double radius) : this.all(
new Radius.circular(radius)
new Radius.circular(radius),
);
/// Creates a vertically symmetric border radius where the top and bottom
/// sides of the rectangle have the same radii.
const BorderRadius.vertical({
Radius top: Radius.zero,
Radius bottom: Radius.zero
Radius bottom: Radius.zero,
}) : this.only(
topLeft: top,
topRight: top,
bottomLeft: bottom,
bottomRight: bottom,
bottomLeft: bottom
);
/// Creates a horizontally symmetrical border radius where the left and right
/// sides of the rectangle have the same radii.
const BorderRadius.horizontal({
Radius left: Radius.zero,
Radius right: Radius.zero
Radius right: Radius.zero,
}) : this.only(
topLeft: left,
topRight: right,
bottomLeft: left,
bottomRight: right,
bottomLeft: left
);
/// Creates a border radius with only the given non-zero values. The other
......@@ -53,8 +316,8 @@ class BorderRadius {
const BorderRadius.only({
this.topLeft: Radius.zero,
this.topRight: Radius.zero,
this.bottomLeft: Radius.zero,
this.bottomRight: Radius.zero,
this.bottomLeft: Radius.zero
});
/// A border radius with all zero radii.
......@@ -62,96 +325,523 @@ class BorderRadius {
/// The top-left [Radius].
final Radius topLeft;
@override
Radius get _topLeft => topLeft;
/// The top-right [Radius].
final Radius topRight;
/// The bottom-right [Radius].
final Radius bottomRight;
@override
Radius get _topRight => topRight;
/// The bottom-left [Radius].
final Radius bottomLeft;
/// Linearly interpolates between two [BorderRadius] objects.
@override
Radius get _bottomLeft => bottomLeft;
/// The bottom-right [Radius].
final Radius bottomRight;
@override
Radius get _bottomRight => bottomRight;
@override
Radius get _topStart => Radius.zero;
@override
Radius get _topEnd => Radius.zero;
@override
Radius get _bottomStart => Radius.zero;
@override
Radius get _bottomEnd => Radius.zero;
/// Creates an [RRect] from the current border radius and a [Rect].
RRect toRRect(Rect rect) {
return new RRect.fromRectAndCorners(
rect,
topLeft: topLeft,
topRight: topRight,
bottomLeft: bottomLeft,
bottomRight: bottomRight,
);
}
@override
BorderRadiusGeometry subtract(BorderRadiusGeometry other) {
if (other is BorderRadius)
return this - other;
return super.subtract(other);
}
@override
BorderRadiusGeometry add(BorderRadiusGeometry other) {
if (other is BorderRadius)
return this + other;
return super.add(other);
}
/// Returns the difference between two [BorderRadius] objects.
BorderRadius operator -(BorderRadius other) {
return new BorderRadius.only(
topLeft: topLeft - other.topLeft,
topRight: topRight - other.topRight,
bottomLeft: bottomLeft - other.bottomLeft,
bottomRight: bottomRight - other.bottomRight,
);
}
/// Returns the sum of two [BorderRadius] objects.
BorderRadius operator +(BorderRadius other) {
return new BorderRadius.only(
topLeft: topLeft + other.topLeft,
topRight: topRight + other.topRight,
bottomLeft: bottomLeft + other.bottomLeft,
bottomRight: bottomRight + other.bottomRight,
);
}
/// Returns the [BorderRadius] object with each corner negated.
///
/// This is the same as multiplying the object by -1.0.
@override
BorderRadius operator -() {
return new BorderRadius.only(
topLeft: -topLeft,
topRight: -topRight,
bottomLeft: -bottomLeft,
bottomRight: -bottomRight,
);
}
/// Scales each corner of the [BorderRadius] by the given factor.
@override
BorderRadius operator *(double other) {
return new BorderRadius.only(
topLeft: topLeft * other,
topRight: topRight * other,
bottomLeft: bottomLeft * other,
bottomRight: bottomRight * other,
);
}
/// Divides each corner of the [BorderRadius] by the given factor.
@override
BorderRadius operator /(double other) {
return new BorderRadius.only(
topLeft: topLeft / other,
topRight: topRight / other,
bottomLeft: bottomLeft / other,
bottomRight: bottomRight / other,
);
}
/// Integer divides each corner of the [BorderRadius] by the given factor.
@override
BorderRadius operator ~/(double other) {
return new BorderRadius.only(
topLeft: topLeft ~/ other,
topRight: topRight ~/ other,
bottomLeft: bottomLeft ~/ other,
bottomRight: bottomRight ~/ other,
);
}
/// Computes the remainder of each corner by the given factor.
@override
BorderRadius operator %(double other) {
return new BorderRadius.only(
topLeft: topLeft % other,
topRight: topRight % other,
bottomLeft: bottomLeft % other,
bottomRight: bottomRight % other,
);
}
/// Linearly interpolate between two [BorderRadius] objects.
///
/// If either is null, this function interpolates from [BorderRadius.zero].
static BorderRadius lerp(BorderRadius a, BorderRadius b, double t) {
if (a == null && b == null)
return null;
if (a == null)
return b * t;
if (b == null)
return a * (1.0 - t);
return new BorderRadius.only(
topLeft: Radius.lerp(a.topLeft, b.topLeft, t),
topRight: Radius.lerp(a.topRight, b.topRight, t),
bottomLeft: Radius.lerp(a.bottomLeft, b.bottomLeft, t),
bottomRight: Radius.lerp(a.bottomRight, b.bottomRight, t),
bottomLeft: Radius.lerp(a.bottomLeft, b.bottomLeft, t)
);
}
/// Creates a [RRect] from the current border radius and a [Rect].
RRect toRRect(Rect rect) {
return new RRect.fromRectAndCorners(
rect,
topLeft: topLeft,
topRight: topRight,
bottomRight: bottomRight,
bottomLeft: bottomLeft
@override
BorderRadius resolve(TextDirection direction) => this;
}
/// An immutable set of radii for each corner of a rectangle, but with the
/// corners specified in a manner dependent on the writing direction.
///
/// This can be used to specify a corner radius on the leading or trailing edge
/// of a box, so that it flips to the other side when the text alignment flips
/// (e.g. being on the top right in English text but the top left in Arabic
/// text).
///
/// See also:
///
/// * [BorderRadius], a variant that uses physical labels (`topLeft` and
/// `topRight` instead of `topStart` and `topEnd`).
class BorderRadiusDirectional extends BorderRadiusGeometry {
/// Creates a border radius where all radii are [radius].
const BorderRadiusDirectional.all(Radius radius) : this.only(
topStart: radius,
topEnd: radius,
bottomStart: radius,
bottomEnd: radius,
);
/// Creates a border radius where all radii are [Radius.circular(radius)].
BorderRadiusDirectional.circular(double radius) : this.all(
new Radius.circular(radius),
);
/// Creates a vertically symmetric border radius where the top and bottom
/// sides of the rectangle have the same radii.
const BorderRadiusDirectional.vertical({
Radius top: Radius.zero,
Radius bottom: Radius.zero,
}) : this.only(
topStart: top,
topEnd: top,
bottomStart: bottom,
bottomEnd: bottom,
);
/// Creates a horizontally symmetrical border radius where the start and end
/// sides of the rectangle have the same radii.
const BorderRadiusDirectional.horizontal({
Radius start: Radius.zero,
Radius end: Radius.zero,
}) : this.only(
topStart: start,
topEnd: end,
bottomStart: start,
bottomEnd: end,
);
/// Creates a border radius with only the given non-zero values. The other
/// corners will be right angles.
const BorderRadiusDirectional.only({
this.topStart: Radius.zero,
this.topEnd: Radius.zero,
this.bottomStart: Radius.zero,
this.bottomEnd: Radius.zero,
});
/// A border radius with all zero radii.
///
/// Consider using [EdgeInsets.zero] instead, since that object has the same
/// effect, but will be cheaper to [resolve].
static const BorderRadiusDirectional zero = const BorderRadiusDirectional.all(Radius.zero);
/// The top-start [Radius].
final Radius topStart;
@override
Radius get _topStart => topStart;
/// The top-end [Radius].
final Radius topEnd;
@override
Radius get _topEnd => topEnd;
/// The bottom-start [Radius].
final Radius bottomStart;
@override
Radius get _bottomStart => bottomStart;
/// The bottom-end [Radius].
final Radius bottomEnd;
@override
Radius get _bottomEnd => bottomEnd;
@override
Radius get _topLeft => Radius.zero;
@override
Radius get _topRight => Radius.zero;
@override
Radius get _bottomLeft => Radius.zero;
@override
Radius get _bottomRight => Radius.zero;
@override
BorderRadiusGeometry subtract(BorderRadiusGeometry other) {
if (other is BorderRadiusDirectional)
return this - other;
return super.subtract(other);
}
@override
bool operator ==(dynamic other) {
if (identical(this, other))
return true;
if (runtimeType != other.runtimeType)
return false;
final BorderRadius typedOther = other;
return topLeft == typedOther.topLeft &&
topRight == typedOther.topRight &&
bottomRight == typedOther.bottomRight &&
bottomLeft == typedOther.bottomLeft;
BorderRadiusGeometry add(BorderRadiusGeometry other) {
if (other is BorderRadiusDirectional)
return this + other;
return super.add(other);
}
/// Returns the difference between two [BorderRadiusDirectional] objects.
BorderRadiusDirectional operator -(BorderRadiusDirectional other) {
return new BorderRadiusDirectional.only(
topStart: topStart - other.topStart,
topEnd: topEnd - other.topEnd,
bottomStart: bottomStart - other.bottomStart,
bottomEnd: bottomEnd - other.bottomEnd,
);
}
/// Returns the sum of two [BorderRadiusDirectional] objects.
BorderRadiusDirectional operator +(BorderRadiusDirectional other) {
return new BorderRadiusDirectional.only(
topStart: topStart + other.topStart,
topEnd: topEnd + other.topEnd,
bottomStart: bottomStart + other.bottomStart,
bottomEnd: bottomEnd + other.bottomEnd,
);
}
/// Returns the [BorderRadiusDirectional] object with each corner negated.
///
/// This is the same as multiplying the object by -1.0.
@override
int get hashCode => hashValues(topLeft, topRight, bottomRight, bottomLeft);
BorderRadiusDirectional operator -() {
return new BorderRadiusDirectional.only(
topStart: -topStart,
topEnd: -topEnd,
bottomStart: -bottomStart,
bottomEnd: -bottomEnd,
);
}
/// Scales each corner of the [BorderRadiusDirectional] by the given factor.
@override
String toString() {
if (topLeft == topRight &&
topRight == bottomRight &&
bottomRight == bottomLeft) {
if (topLeft == Radius.zero)
return 'BorderRadius.zero';
if (topLeft.x == topLeft.y)
return 'BorderRadius.circular(${topLeft.x.toStringAsFixed(1)})';
return 'BorderRadius.all($topLeft)';
}
if (topLeft == Radius.zero ||
topRight == Radius.zero ||
bottomLeft == Radius.zero ||
bottomRight == Radius.zero) {
final StringBuffer result = new StringBuffer();
result.write('BorderRadius.only(');
bool comma = false;
if (topLeft != Radius.zero) {
result.write('topLeft: $topLeft');
comma = true;
BorderRadiusDirectional operator *(double other) {
return new BorderRadiusDirectional.only(
topStart: topStart * other,
topEnd: topEnd * other,
bottomStart: bottomStart * other,
bottomEnd: bottomEnd * other,
);
}
if (topRight != Radius.zero) {
if (comma)
result.write(', ');
result.write('topRight: $topRight');
comma = true;
/// Divides each corner of the [BorderRadiusDirectional] by the given factor.
@override
BorderRadiusDirectional operator /(double other) {
return new BorderRadiusDirectional.only(
topStart: topStart / other,
topEnd: topEnd / other,
bottomStart: bottomStart / other,
bottomEnd: bottomEnd / other,
);
}
if (bottomLeft != Radius.zero) {
if (comma)
result.write(', ');
result.write('bottomLeft: $bottomLeft');
comma = true;
/// Integer divides each corner of the [BorderRadiusDirectional] by the given factor.
@override
BorderRadiusDirectional operator ~/(double other) {
return new BorderRadiusDirectional.only(
topStart: topStart ~/ other,
topEnd: topEnd ~/ other,
bottomStart: bottomStart ~/ other,
bottomEnd: bottomEnd ~/ other,
);
}
if (bottomRight != Radius.zero) {
if (comma)
result.write(', ');
result.write('bottomRight: $bottomRight');
/// Computes the remainder of each corner by the given factor.
@override
BorderRadiusDirectional operator %(double other) {
return new BorderRadiusDirectional.only(
topStart: topStart % other,
topEnd: topEnd % other,
bottomStart: bottomStart % other,
bottomEnd: bottomEnd % other,
);
}
result.write(')');
return result.toString();
/// Linearly interpolate between two [BorderRadiusDirectional] objects.
///
/// If either is null, this function interpolates from [BorderRadiusDirectional.zero].
static BorderRadiusDirectional lerp(BorderRadiusDirectional a, BorderRadiusDirectional b, double t) {
if (a == null && b == null)
return null;
if (a == null)
return b * t;
if (b == null)
return a * (1.0 - t);
return new BorderRadiusDirectional.only(
topStart: Radius.lerp(a.topStart, b.topStart, t),
topEnd: Radius.lerp(a.topEnd, b.topEnd, t),
bottomStart: Radius.lerp(a.bottomStart, b.bottomStart, t),
bottomEnd: Radius.lerp(a.bottomEnd, b.bottomEnd, t),
);
}
@override
BorderRadius resolve(TextDirection direction) {
assert(direction != null);
switch (direction) {
case TextDirection.rtl:
return new BorderRadius.only(
topLeft: topEnd,
topRight: topStart,
bottomLeft: bottomEnd,
bottomRight: bottomStart,
);
case TextDirection.ltr:
return new BorderRadius.only(
topLeft: topStart,
topRight: topEnd,
bottomLeft: bottomStart,
bottomRight: bottomEnd,
);
}
return null;
}
}
class _MixedBorderRadius extends BorderRadiusGeometry {
const _MixedBorderRadius(
this._topLeft,
this._topRight,
this._bottomLeft,
this._bottomRight,
this._topStart,
this._topEnd,
this._bottomStart,
this._bottomEnd,
);
@override
final Radius _topLeft;
@override
final Radius _topRight;
@override
final Radius _bottomLeft;
@override
final Radius _bottomRight;
@override
final Radius _topStart;
@override
final Radius _topEnd;
@override
final Radius _bottomStart;
@override
final Radius _bottomEnd;
@override
_MixedBorderRadius operator -() {
return new _MixedBorderRadius(
-_topLeft,
-_topRight,
-_bottomLeft,
-_bottomRight,
-_topStart,
-_topEnd,
-_bottomStart,
-_bottomEnd,
);
}
/// Scales each corner of the [_MixedBorderRadius] by the given factor.
@override
_MixedBorderRadius operator *(double other) {
return new _MixedBorderRadius(
_topLeft * other,
_topRight * other,
_bottomLeft * other,
_bottomRight * other,
_topStart * other,
_topEnd * other,
_bottomStart * other,
_bottomEnd * other,
);
}
return 'BorderRadius($topLeft, $topRight, $bottomRight, $bottomLeft)';
@override
_MixedBorderRadius operator /(double other) {
return new _MixedBorderRadius(
_topLeft / other,
_topRight / other,
_bottomLeft / other,
_bottomRight / other,
_topStart / other,
_topEnd / other,
_bottomStart / other,
_bottomEnd / other,
);
}
@override
_MixedBorderRadius operator ~/(double other) {
return new _MixedBorderRadius(
_topLeft ~/ other,
_topRight ~/ other,
_bottomLeft ~/ other,
_bottomRight ~/ other,
_topStart ~/ other,
_topEnd ~/ other,
_bottomStart ~/ other,
_bottomEnd ~/ other,
);
}
@override
_MixedBorderRadius operator %(double other) {
return new _MixedBorderRadius(
_topLeft % other,
_topRight % other,
_bottomLeft % other,
_bottomRight % other,
_topStart % other,
_topEnd % other,
_bottomStart % other,
_bottomEnd % other,
);
}
@override
BorderRadius resolve(TextDirection direction) {
assert(direction != null);
switch (direction) {
case TextDirection.rtl:
return new BorderRadius.only(
topLeft: _topLeft + _topEnd,
topRight: _topRight + _topStart,
bottomLeft: _bottomLeft + _bottomEnd,
bottomRight: _bottomRight + _bottomStart,
);
case TextDirection.ltr:
return new BorderRadius.only(
topLeft: _topLeft + _topStart,
topRight: _topRight + _topEnd,
bottomLeft: _bottomLeft + _bottomStart,
bottomRight: _bottomRight + _bottomEnd,
);
}
return null;
}
}
......@@ -12,14 +12,16 @@ import 'basic_types.dart';
/// resolution.
///
/// A property or argument of this type accepts classes created either with [new
/// EdgeInsets.fromLTRB] and its variants, or [new EdgeInsetsDirectional].
/// EdgeInsets.fromLTRB] and its variants, or [new
/// EdgeInsetsDirectional.fromSTEB] and its variants.
///
/// To convert a [EdgeInsetsGeometry] object of indeterminate type into a
/// To convert an [EdgeInsetsGeometry] object of indeterminate type into a
/// [EdgeInsets] object, call the [resolve] method.
///
/// See also:
///
/// * [Padding], a widget that describes margins using [EdgeInsetsGeometry].
@immutable
abstract class EdgeInsetsGeometry {
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
......@@ -164,11 +166,17 @@ abstract class EdgeInsetsGeometry {
/// Integer divides the [EdgeInsetsGeometry] object in each dimension by the given factor.
///
/// This operator returns an object of the same type as the operand.
///
/// This operator may have unexpected results when applied to a mixture of
/// [EdgeInsets] and [EdgeInsetsDirectional] objects.
EdgeInsetsGeometry operator ~/(double other);
/// Computes the remainder in each dimension by the given factor.
///
/// This operator returns an object of the same type as the operand.
///
/// This operator may have unexpected results when applied to a mixture of
/// [EdgeInsets] and [EdgeInsetsDirectional] objects.
EdgeInsetsGeometry operator %(double other);
/// Linearly interpolate between two [EdgeInsetsGeometry] objects.
......@@ -202,7 +210,7 @@ abstract class EdgeInsetsGeometry {
);
}
/// Convert this instance into a [EdgeInsets], which uses literal coordinates
/// Convert this instance into an [EdgeInsets], which uses literal coordinates
/// (i.e. the `left` coordinate being explicitly a distance from the left, and
/// the `right` coordinate being explicitly a distance from the right).
///
......@@ -299,7 +307,6 @@ abstract class EdgeInsetsGeometry {
/// * [EdgeInsetsDirectional], which (for properties and arguments that accept
/// the type [EdgeInsetsGeometry]) allows the horizontal insets to be
/// specified in a [TextDirection]-aware manner.
@immutable
class EdgeInsets extends EdgeInsetsGeometry {
/// Creates insets from offsets from the left, top, right, and bottom.
const EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom);
......@@ -357,6 +364,9 @@ class EdgeInsets extends EdgeInsetsGeometry {
right = padding.right / devicePixelRatio,
bottom = padding.bottom / devicePixelRatio;
/// An [EdgeInsets] with zero offsets in each direction.
static const EdgeInsets zero = const EdgeInsets.only();
/// The offset from the left.
final double left;
......@@ -547,9 +557,6 @@ class EdgeInsets extends EdgeInsetsGeometry {
);
}
/// An [EdgeInsets] with zero offsets in each direction.
static const EdgeInsets zero = const EdgeInsets.only();
@override
EdgeInsets resolve(TextDirection direction) => this;
}
......@@ -585,6 +592,12 @@ class EdgeInsetsDirectional extends EdgeInsetsGeometry {
this.bottom: 0.0
});
/// An [EdgeInsetsDirectional] with zero offsets in each direction.
///
/// Consider using [EdgeInsets.zero] instead, since that object has the same
/// effect, but will be cheaper to [resolve].
static const EdgeInsetsDirectional zero = const EdgeInsetsDirectional.only();
/// The offset from the start side, the side from which the user will start
/// reading text.
///
......@@ -749,12 +762,6 @@ class EdgeInsetsDirectional extends EdgeInsetsGeometry {
);
}
/// An [EdgeInsetsDirectional] with zero offsets in each direction.
///
/// Consider using [EdgeInsets.zero] instead, since that object has the same
/// effect, but will be cheaper to [resolve].
static const EdgeInsetsDirectional zero = const EdgeInsetsDirectional.only();
@override
EdgeInsets resolve(TextDirection direction) {
assert(direction != null);
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('BorderRadius control test', () {
final Rect rect = new Rect.fromLTRB(19.0, 23.0, 29.0, 31.0);
BorderRadius borderRadius;
borderRadius = const BorderRadius.all(const Radius.elliptical(5.0, 7.0));
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topLeft, const Radius.elliptical(5.0, 7.0));
expect(borderRadius.topRight, const Radius.elliptical(5.0, 7.0));
expect(borderRadius.bottomLeft, const Radius.elliptical(5.0, 7.0));
expect(borderRadius.bottomRight, const Radius.elliptical(5.0, 7.0));
expect(borderRadius.toRRect(rect), new RRect.fromRectXY(rect, 5.0, 7.0));
borderRadius = new BorderRadius.circular(3.0);
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topLeft, const Radius.elliptical(3.0, 3.0));
expect(borderRadius.topRight, const Radius.elliptical(3.0, 3.0));
expect(borderRadius.bottomLeft, const Radius.elliptical(3.0, 3.0));
expect(borderRadius.bottomRight, const Radius.elliptical(3.0, 3.0));
expect(borderRadius.toRRect(rect), new RRect.fromRectXY(rect, 3.0, 3.0));
const Radius radius1 = const Radius.elliptical(89.0, 87.0);
const Radius radius2 = const Radius.elliptical(103.0, 107.0);
borderRadius = const BorderRadius.vertical(top: radius1, bottom: radius2);
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topLeft, radius1);
expect(borderRadius.topRight, radius1);
expect(borderRadius.bottomLeft, radius2);
expect(borderRadius.bottomRight, radius2);
expect(borderRadius.toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: radius1,
topRight: radius1,
bottomLeft: radius2,
bottomRight: radius2,
));
borderRadius = const BorderRadius.horizontal(left: radius1, right: radius2);
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topLeft, radius1);
expect(borderRadius.topRight, radius2);
expect(borderRadius.bottomLeft, radius1);
expect(borderRadius.bottomRight, radius2);
expect(borderRadius.toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: radius1,
topRight: radius2,
bottomLeft: radius1,
bottomRight: radius2,
));
borderRadius = const BorderRadius.only();
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topLeft, Radius.zero);
expect(borderRadius.topRight, Radius.zero);
expect(borderRadius.bottomLeft, Radius.zero);
expect(borderRadius.bottomRight, Radius.zero);
expect(borderRadius.toRRect(rect), new RRect.fromRectAndCorners(rect));
borderRadius = const BorderRadius.only(topRight: radius1, bottomRight: radius2);
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topLeft, Radius.zero);
expect(borderRadius.topRight, radius1);
expect(borderRadius.bottomLeft, Radius.zero);
expect(borderRadius.bottomRight, radius2);
expect(borderRadius.toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: Radius.zero,
topRight: radius1,
bottomLeft: Radius.zero,
bottomRight: radius2,
));
expect(
const BorderRadius.only(topLeft: const Radius.elliptical(1.0, 2.0)).subtract(const BorderRadius.only(topLeft: const Radius.elliptical(3.0, 5.0))),
const BorderRadius.only(topLeft: const Radius.elliptical(-2.0, -3.0)),
);
expect(
const BorderRadius.only(topRight: const Radius.elliptical(1.0, 2.0)).add(const BorderRadius.only(topLeft: const Radius.elliptical(3.0, 5.0))),
const BorderRadius.only(topLeft: const Radius.elliptical(3.0, 5.0), topRight: const Radius.elliptical(1.0, 2.0)),
);
expect(
const BorderRadius.only(topLeft: const Radius.elliptical(1.0, 2.0)) - const BorderRadius.only(topLeft: const Radius.elliptical(3.0, 5.0)),
const BorderRadius.only(topLeft: const Radius.elliptical(-2.0, -3.0)),
);
expect(
const BorderRadius.only(topRight: const Radius.elliptical(1.0, 2.0)) + const BorderRadius.only(topLeft: const Radius.elliptical(3.0, 5.0)),
const BorderRadius.only(topLeft: const Radius.elliptical(3.0, 5.0), topRight: const Radius.elliptical(1.0, 2.0)),
);
expect(
-const BorderRadius.only(topLeft: const Radius.elliptical(1.0, 2.0)),
const BorderRadius.only(topLeft: const Radius.elliptical(-1.0, -2.0)),
);
expect(
const BorderRadius.only(
topLeft: radius1,
topRight: radius2,
bottomLeft: radius2,
bottomRight: radius1,
) * 0.0,
BorderRadius.zero,
);
expect(
new BorderRadius.circular(15.0) / 10.0,
new BorderRadius.circular(1.5),
);
expect(
new BorderRadius.circular(15.0) ~/ 10.0,
new BorderRadius.circular(1.0),
);
expect(
new BorderRadius.circular(15.0) % 10.0,
new BorderRadius.circular(5.0),
);
});
test('BorderRadius.lerp() invariants', () {
final BorderRadius a = new BorderRadius.circular(10.0);
final BorderRadius b = new BorderRadius.circular(20.0);
expect(BorderRadius.lerp(a, b, 0.25), equals(a * 1.25));
expect(BorderRadius.lerp(a, b, 0.25), equals(b * 0.625));
expect(BorderRadius.lerp(a, b, 0.25), equals(a + new BorderRadius.circular(2.5)));
expect(BorderRadius.lerp(a, b, 0.25), equals(b - new BorderRadius.circular(7.5)));
expect(BorderRadius.lerp(null, null, 0.25), isNull);
expect(BorderRadius.lerp(null, b, 0.25), equals(b * 0.25));
expect(BorderRadius.lerp(a, null, 0.25), equals(a * 0.75));
});
test('BorderRadius.lerp() crazy', () {
final BorderRadius a = const BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0),
topRight: const Radius.elliptical(30.0, 40.0),
bottomLeft: const Radius.elliptical(50.0, 60.0),
);
final BorderRadius b = const BorderRadius.only(
topRight: const Radius.elliptical(100.0, 110.0),
bottomLeft: const Radius.elliptical(120.0, 130.0),
bottomRight: const Radius.elliptical(140.0, 150.0),
);
final BorderRadius c = const BorderRadius.only(
topLeft: const Radius.elliptical(5.0, 10.0), // 10,20 -> 0
topRight: const Radius.elliptical(65.0, 75.0), // 30,40 -> 100,110
bottomLeft: const Radius.elliptical(85.0, 95.0), // 50,60 -> 120,130
bottomRight: const Radius.elliptical(70.0, 75.0), // 0,0 -> 140,150
);
expect(BorderRadius.lerp(a, b, 0.5), c);
});
test('BorderRadiusDirectional control test', () {
final Rect rect = new Rect.fromLTRB(19.0, 23.0, 29.0, 31.0);
BorderRadiusDirectional borderRadius;
borderRadius = const BorderRadiusDirectional.all(const Radius.elliptical(5.0, 7.0));
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topStart, const Radius.elliptical(5.0, 7.0));
expect(borderRadius.topEnd, const Radius.elliptical(5.0, 7.0));
expect(borderRadius.bottomStart, const Radius.elliptical(5.0, 7.0));
expect(borderRadius.bottomEnd, const Radius.elliptical(5.0, 7.0));
expect(borderRadius.resolve(TextDirection.ltr).toRRect(rect), new RRect.fromRectXY(rect, 5.0, 7.0));
expect(borderRadius.resolve(TextDirection.rtl).toRRect(rect), new RRect.fromRectXY(rect, 5.0, 7.0));
borderRadius = new BorderRadiusDirectional.circular(3.0);
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topStart, const Radius.elliptical(3.0, 3.0));
expect(borderRadius.topEnd, const Radius.elliptical(3.0, 3.0));
expect(borderRadius.bottomStart, const Radius.elliptical(3.0, 3.0));
expect(borderRadius.bottomEnd, const Radius.elliptical(3.0, 3.0));
expect(borderRadius.resolve(TextDirection.ltr).toRRect(rect), new RRect.fromRectXY(rect, 3.0, 3.0));
expect(borderRadius.resolve(TextDirection.rtl).toRRect(rect), new RRect.fromRectXY(rect, 3.0, 3.0));
const Radius radius1 = const Radius.elliptical(89.0, 87.0);
const Radius radius2 = const Radius.elliptical(103.0, 107.0);
borderRadius = const BorderRadiusDirectional.vertical(top: radius1, bottom: radius2);
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topStart, radius1);
expect(borderRadius.topEnd, radius1);
expect(borderRadius.bottomStart, radius2);
expect(borderRadius.bottomEnd, radius2);
expect(borderRadius.resolve(TextDirection.ltr).toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: radius1,
topRight: radius1,
bottomLeft: radius2,
bottomRight: radius2,
));
expect(borderRadius.resolve(TextDirection.rtl).toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: radius1,
topRight: radius1,
bottomLeft: radius2,
bottomRight: radius2,
));
borderRadius = const BorderRadiusDirectional.horizontal(start: radius1, end: radius2);
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topStart, radius1);
expect(borderRadius.topEnd, radius2);
expect(borderRadius.bottomStart, radius1);
expect(borderRadius.bottomEnd, radius2);
expect(borderRadius.resolve(TextDirection.ltr).toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: radius1,
topRight: radius2,
bottomLeft: radius1,
bottomRight: radius2,
));
expect(borderRadius.resolve(TextDirection.rtl).toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: radius2,
topRight: radius1,
bottomLeft: radius2,
bottomRight: radius1,
));
borderRadius = const BorderRadiusDirectional.only();
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topStart, Radius.zero);
expect(borderRadius.topEnd, Radius.zero);
expect(borderRadius.bottomStart, Radius.zero);
expect(borderRadius.bottomEnd, Radius.zero);
expect(borderRadius.resolve(TextDirection.ltr).toRRect(rect), new RRect.fromRectAndCorners(rect));
expect(borderRadius.resolve(TextDirection.rtl).toRRect(rect), new RRect.fromRectAndCorners(rect));
borderRadius = const BorderRadiusDirectional.only(topEnd: radius1, bottomEnd: radius2);
expect(borderRadius, hasOneLineDescription);
expect(borderRadius.topStart, Radius.zero);
expect(borderRadius.topEnd, radius1);
expect(borderRadius.bottomStart, Radius.zero);
expect(borderRadius.bottomEnd, radius2);
expect(borderRadius.resolve(TextDirection.ltr).toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: Radius.zero,
topRight: radius1,
bottomLeft: Radius.zero,
bottomRight: radius2,
));
expect(borderRadius.resolve(TextDirection.rtl).toRRect(rect), new RRect.fromRectAndCorners(
rect,
topLeft: radius1,
topRight: Radius.zero,
bottomLeft: radius2,
bottomRight: Radius.zero,
));
expect(
const BorderRadiusDirectional.only(topStart: const Radius.elliptical(1.0, 2.0)).subtract(const BorderRadiusDirectional.only(topStart: const Radius.elliptical(3.0, 5.0))),
const BorderRadiusDirectional.only(topStart: const Radius.elliptical(-2.0, -3.0)),
);
expect(
const BorderRadiusDirectional.only(topEnd: const Radius.elliptical(1.0, 2.0)).add(const BorderRadiusDirectional.only(topStart: const Radius.elliptical(3.0, 5.0))),
const BorderRadiusDirectional.only(topStart: const Radius.elliptical(3.0, 5.0), topEnd: const Radius.elliptical(1.0, 2.0)),
);
expect(
const BorderRadiusDirectional.only(topStart: const Radius.elliptical(1.0, 2.0)) - const BorderRadiusDirectional.only(topStart: const Radius.elliptical(3.0, 5.0)),
const BorderRadiusDirectional.only(topStart: const Radius.elliptical(-2.0, -3.0)),
);
expect(
const BorderRadiusDirectional.only(topEnd: const Radius.elliptical(1.0, 2.0)) + const BorderRadiusDirectional.only(topStart: const Radius.elliptical(3.0, 5.0)),
const BorderRadiusDirectional.only(topStart: const Radius.elliptical(3.0, 5.0), topEnd: const Radius.elliptical(1.0, 2.0)),
);
expect(
-const BorderRadiusDirectional.only(topStart: const Radius.elliptical(1.0, 2.0)),
const BorderRadiusDirectional.only(topStart: const Radius.elliptical(-1.0, -2.0)),
);
expect(
const BorderRadiusDirectional.only(
topStart: radius1,
topEnd: radius2,
bottomStart: radius2,
bottomEnd: radius1,
) * 0.0,
BorderRadiusDirectional.zero,
);
expect(
new BorderRadiusDirectional.circular(15.0) / 10.0,
new BorderRadiusDirectional.circular(1.5),
);
expect(
new BorderRadiusDirectional.circular(15.0) ~/ 10.0,
new BorderRadiusDirectional.circular(1.0),
);
expect(
new BorderRadiusDirectional.circular(15.0) % 10.0,
new BorderRadiusDirectional.circular(5.0),
);
});
test('BorderRadiusDirectional.lerp() invariants', () {
final BorderRadiusDirectional a = new BorderRadiusDirectional.circular(10.0);
final BorderRadiusDirectional b = new BorderRadiusDirectional.circular(20.0);
expect(BorderRadiusDirectional.lerp(a, b, 0.25), equals(a * 1.25));
expect(BorderRadiusDirectional.lerp(a, b, 0.25), equals(b * 0.625));
expect(BorderRadiusDirectional.lerp(a, b, 0.25), equals(a + new BorderRadiusDirectional.circular(2.5)));
expect(BorderRadiusDirectional.lerp(a, b, 0.25), equals(b - new BorderRadiusDirectional.circular(7.5)));
expect(BorderRadiusDirectional.lerp(null, null, 0.25), isNull);
expect(BorderRadiusDirectional.lerp(null, b, 0.25), equals(b * 0.25));
expect(BorderRadiusDirectional.lerp(a, null, 0.25), equals(a * 0.75));
});
test('BorderRadiusDirectional.lerp() crazy', () {
final BorderRadiusDirectional a = const BorderRadiusDirectional.only(
topStart: const Radius.elliptical(10.0, 20.0),
topEnd: const Radius.elliptical(30.0, 40.0),
bottomStart: const Radius.elliptical(50.0, 60.0),
);
final BorderRadiusDirectional b = const BorderRadiusDirectional.only(
topEnd: const Radius.elliptical(100.0, 110.0),
bottomStart: const Radius.elliptical(120.0, 130.0),
bottomEnd: const Radius.elliptical(140.0, 150.0),
);
final BorderRadiusDirectional c = const BorderRadiusDirectional.only(
topStart: const Radius.elliptical(5.0, 10.0), // 10,20 -> 0
topEnd: const Radius.elliptical(65.0, 75.0), // 30,40 -> 100,110
bottomStart: const Radius.elliptical(85.0, 95.0), // 50,60 -> 120,130
bottomEnd: const Radius.elliptical(70.0, 75.0), // 0,0 -> 140,150
);
expect(BorderRadiusDirectional.lerp(a, b, 0.5), c);
});
test('BorderRadiusGeometry.lerp()', () {
final BorderRadius a = const BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0),
topRight: const Radius.elliptical(30.0, 40.0),
bottomLeft: const Radius.elliptical(50.0, 60.0),
);
final BorderRadiusDirectional b = const BorderRadiusDirectional.only(
topEnd: const Radius.elliptical(100.0, 110.0),
bottomStart: const Radius.elliptical(120.0, 130.0),
bottomEnd: const Radius.elliptical(140.0, 150.0),
);
final BorderRadius ltr = const BorderRadius.only(
topLeft: const Radius.elliptical(5.0, 10.0), // 10,20 -> 0
topRight: const Radius.elliptical(65.0, 75.0), // 30,40 -> 100,110
bottomLeft: const Radius.elliptical(85.0, 95.0), // 50,60 -> 120,130
bottomRight: const Radius.elliptical(70.0, 75.0), // 0,0 -> 140,150
);
final BorderRadius rtl = const BorderRadius.only(
topLeft: const Radius.elliptical(55.0, 65.0), // 10,20 -> 100,110
topRight: const Radius.elliptical(15.0, 20.0), // 30,40 -> 0,0
bottomLeft: const Radius.elliptical(95.0, 105.0), // 50,60 -> 140,150
bottomRight: const Radius.elliptical(60.0, 65.0), // 0,0 -> 120,130
);
expect(BorderRadiusGeometry.lerp(a, b, 0.5).resolve(TextDirection.ltr), ltr);
expect(BorderRadiusGeometry.lerp(a, b, 0.5).resolve(TextDirection.rtl), rtl);
expect(BorderRadiusGeometry.lerp(a, b, 0.0).resolve(TextDirection.ltr), a);
expect(BorderRadiusGeometry.lerp(a, b, 1.0).resolve(TextDirection.rtl), b.resolve(TextDirection.rtl));
});
test('BorderRadiusGeometry subtract', () {
final BorderRadius a = const BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0),
topRight: const Radius.elliptical(30.0, 40.0),
bottomLeft: const Radius.elliptical(50.0, 60.0),
);
final BorderRadiusDirectional b = const BorderRadiusDirectional.only(
topEnd: const Radius.elliptical(100.0, 110.0),
bottomStart: const Radius.elliptical(120.0, 130.0),
bottomEnd: const Radius.elliptical(140.0, 150.0),
);
expect((a.subtract(b)).resolve(TextDirection.ltr), new BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0) - Radius.zero,
topRight: const Radius.elliptical(30.0, 40.0) - const Radius.elliptical(100.0, 110.0),
bottomLeft: const Radius.elliptical(50.0, 60.0) - const Radius.elliptical(120.0, 130.0),
bottomRight: Radius.zero - const Radius.elliptical(140.0, 150.0),
));
expect((a.subtract(b)).resolve(TextDirection.rtl), new BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0) - const Radius.elliptical(100.0, 110.0),
topRight: const Radius.elliptical(30.0, 40.0) - Radius.zero,
bottomLeft: const Radius.elliptical(50.0, 60.0) - const Radius.elliptical(140.0, 150.0),
bottomRight: Radius.zero - const Radius.elliptical(120.0, 130.0),
));
});
test('BorderRadiusGeometry add', () {
final BorderRadius a = const BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0),
topRight: const Radius.elliptical(30.0, 40.0),
bottomLeft: const Radius.elliptical(50.0, 60.0),
);
final BorderRadiusDirectional b = const BorderRadiusDirectional.only(
topEnd: const Radius.elliptical(100.0, 110.0),
bottomStart: const Radius.elliptical(120.0, 130.0),
bottomEnd: const Radius.elliptical(140.0, 150.0),
);
expect((a.add(b)).resolve(TextDirection.ltr), new BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0) + Radius.zero,
topRight: const Radius.elliptical(30.0, 40.0) + const Radius.elliptical(100.0, 110.0),
bottomLeft: const Radius.elliptical(50.0, 60.0) + const Radius.elliptical(120.0, 130.0),
bottomRight: Radius.zero + const Radius.elliptical(140.0, 150.0),
));
expect((a.add(b)).resolve(TextDirection.rtl), new BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0) + const Radius.elliptical(100.0, 110.0),
topRight: const Radius.elliptical(30.0, 40.0) + Radius.zero,
bottomLeft: const Radius.elliptical(50.0, 60.0) + const Radius.elliptical(140.0, 150.0),
bottomRight: Radius.zero + const Radius.elliptical(120.0, 130.0),
));
});
test('BorderRadiusGeometry add and multiply', () {
final BorderRadius a = const BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0),
topRight: const Radius.elliptical(30.0, 40.0),
bottomLeft: const Radius.elliptical(50.0, 60.0),
);
final BorderRadiusDirectional b = const BorderRadiusDirectional.only(
topEnd: const Radius.elliptical(100.0, 110.0),
bottomStart: const Radius.elliptical(120.0, 130.0),
bottomEnd: const Radius.elliptical(140.0, 150.0),
);
expect((a.add(b) * 0.5).resolve(TextDirection.ltr), new BorderRadius.only(
topLeft: (const Radius.elliptical(10.0, 20.0) + Radius.zero) / 2.0,
topRight: (const Radius.elliptical(30.0, 40.0) + const Radius.elliptical(100.0, 110.0)) / 2.0,
bottomLeft: (const Radius.elliptical(50.0, 60.0) + const Radius.elliptical(120.0, 130.0)) / 2.0,
bottomRight: (Radius.zero + const Radius.elliptical(140.0, 150.0)) / 2.0,
));
expect((a.add(b) * 0.5).resolve(TextDirection.rtl), new BorderRadius.only(
topLeft: (const Radius.elliptical(10.0, 20.0) + const Radius.elliptical(100.0, 110.0)) / 2.0,
topRight: (const Radius.elliptical(30.0, 40.0) + Radius.zero) / 2.0,
bottomLeft: (const Radius.elliptical(50.0, 60.0) + const Radius.elliptical(140.0, 150.0)) / 2.0,
bottomRight: (Radius.zero + const Radius.elliptical(120.0, 130.0)) / 2.0,
));
});
test('BorderRadiusGeometry add and subtract', () {
final BorderRadius a = const BorderRadius.only(
topLeft: const Radius.elliptical(300.0, 500.0),
);
final BorderRadiusDirectional b = const BorderRadiusDirectional.only(
topEnd: const Radius.elliptical(30.0, 50.0),
);
final BorderRadius c = const BorderRadius.only(
bottomLeft: const Radius.elliptical(3.0, 5.0),
);
final BorderRadius ltr = const BorderRadius.only(
topLeft: const Radius.elliptical(300.0, 500.0), // tL + 0 - 0
topRight: const Radius.elliptical(30.0, 50.0), // 0 + tE - 0
bottomLeft: const Radius.elliptical(-3.0, -5.0), // 0 + 0 - bL
bottomRight: Radius.zero, // 0 + 0 - 0
);
final BorderRadius rtl = const BorderRadius.only(
topLeft: const Radius.elliptical(330.0, 550.0), // tL + tE - 0
topRight: Radius.zero, // 0 + 0 - 0
bottomLeft: const Radius.elliptical(-3.0, -5.0), // 0 + 0 - bL
bottomRight: Radius.zero, // 0 + 0 - 0
);
expect((a.add(b.subtract(c))).resolve(TextDirection.ltr), ltr);
expect((a.add(b.subtract(c))).resolve(TextDirection.rtl), rtl);
});
test('BorderRadiusGeometry add and subtract, more', () {
final BorderRadius a = const BorderRadius.only(
topLeft: const Radius.elliptical(300.0, 300.0),
topRight: const Radius.elliptical(500.0, 500.0),
bottomLeft: const Radius.elliptical(700.0, 700.0),
bottomRight: const Radius.elliptical(900.0, 900.0),
);
final BorderRadiusDirectional b = const BorderRadiusDirectional.only(
topStart: const Radius.elliptical(30.0, 30.0),
topEnd: const Radius.elliptical(50.0, 50.0),
bottomStart: const Radius.elliptical(70.0, 70.0),
bottomEnd: const Radius.elliptical(90.0, 90.0),
);
final BorderRadius c = const BorderRadius.only(
topLeft: const Radius.elliptical(3.0, 3.0),
topRight: const Radius.elliptical(5.0, 5.0),
bottomLeft: const Radius.elliptical(7.0, 7.0),
bottomRight: const Radius.elliptical(9.0, 9.0),
);
final BorderRadius ltr = const BorderRadius.only(
topLeft: const Radius.elliptical(327.0, 327.0), // tL + tS - tL
topRight: const Radius.elliptical(545.0, 545.0), // tR + tE - tR
bottomLeft: const Radius.elliptical(763.0, 763.0), // bL + bS - bL
bottomRight: const Radius.elliptical(981.0, 981.0), // bR + bE - bR
);
final BorderRadius rtl = const BorderRadius.only(
topLeft: const Radius.elliptical(347.0, 347.0), // tL + tE - tL
topRight: const Radius.elliptical(525.0, 525.0), // tR + TS - tR
bottomLeft: const Radius.elliptical(783.0, 783.0), // bL + bE + bL
bottomRight: const Radius.elliptical(961.0, 961.0), // bR + bS - bR
);
expect((a.add(b.subtract(c))).resolve(TextDirection.ltr), ltr);
expect((a.add(b.subtract(c))).resolve(TextDirection.rtl), rtl);
});
test('BorderRadiusGeometry operators', () {
final BorderRadius a = const BorderRadius.only(
topLeft: const Radius.elliptical(10.0, 20.0),
topRight: const Radius.elliptical(30.0, 40.0),
bottomLeft: const Radius.elliptical(50.0, 60.0),
);
final BorderRadiusDirectional b = const BorderRadiusDirectional.only(
topEnd: const Radius.elliptical(100.0, 110.0),
bottomStart: const Radius.elliptical(120.0, 130.0),
bottomEnd: const Radius.elliptical(140.0, 150.0),
);
final BorderRadius ltr = const BorderRadius.only(
topLeft: const Radius.elliptical(5.0, 10.0), // 10,20 -> 0
topRight: const Radius.elliptical(65.0, 75.0), // 30,40 -> 100,110
bottomLeft: const Radius.elliptical(85.0, 95.0), // 50,60 -> 120,130
bottomRight: const Radius.elliptical(70.0, 75.0), // 0,0 -> 140,150
);
final BorderRadius rtl = const BorderRadius.only(
topLeft: const Radius.elliptical(55.0, 65.0), // 10,20 -> 100,110
topRight: const Radius.elliptical(15.0, 20.0), // 30,40 -> 0,0
bottomLeft: const Radius.elliptical(95.0, 105.0), // 50,60 -> 140,150
bottomRight: const Radius.elliptical(60.0, 65.0), // 0,0 -> 120,130
);
expect((a.add(b.subtract(a) * 0.5)).resolve(TextDirection.ltr), ltr);
expect((a.add(b.subtract(a) * 0.5)).resolve(TextDirection.rtl), rtl);
expect((a.add(b.subtract(a) * 0.0)).resolve(TextDirection.ltr), a);
expect((a.add(b.subtract(a) * 1.0)).resolve(TextDirection.rtl), b.resolve(TextDirection.rtl));
});
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment