Commit 31b6ac04 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Restore FractionalOffset operators (#12368)

These now act the way they used to act if both operands are
FractionalOffsets.  Once you mix in some other AlignmentGeometry
objects, everything gets converted to the AlignmentGeometry coordinate
system.
parent 7bfa3c56
......@@ -540,7 +540,7 @@ class AlignmentDirectional extends AlignmentGeometry {
if (start == 1.0 && y == 1.0)
return 'AlignmentDirectional.bottomEnd';
return 'AlignmentDirectional(${start.toStringAsFixed(1)}, '
'${y.toStringAsFixed(1)})';
'${y.toStringAsFixed(1)})';
}
@override
......
......@@ -21,6 +21,31 @@ import 'basic_types.dart';
/// The [FractionalOffset] class specifies offsets in terms of a distance from
/// the top left, regardless of the [TextDirection].
///
/// ## Design discussion
///
/// [FractionalOffset] and [Alignment] are two different representations of the
/// same information: the location within a rectangle relative to the size of
/// the rectangle. The difference between the two classes is in the coordinate
/// system they use to represent the location.
///
/// [FractionalOffset] uses a coordinate system with an origin in the top-left
/// corner of the rectangle whereas [Alignment] uses a coordinate system with an
/// origin in the center of the rectangle.
///
/// Historically, [FractionalOffset] predates [Alignment]. When we attempted to
/// make a version of [FractionalOffset] that adapted to the [TextDirection], we
/// ran into difficulty because placing the origin in the top-left corner
/// introduced a left-to-right bias that was hard to remove.
///
/// By placing the origin in the center, [Alignment] and [AlignmentDirectional]
/// are able to use the same origin, which means we can use a linear function to
/// resolve an [AlignmentDirectional] into an [Alignment] in both
/// [TextDirection.rtl] and [TextDirection.ltr].
///
/// [Alignment] is better for most purposes than [FractionalOffset] and should
/// be used instead of [FractionalOffset]. We continue to implement
/// [FractionalOffset] to support code that predates [Alignment].
///
/// See also:
///
/// * [Alignment], which uses a coordinate system based on the center of the
......@@ -108,6 +133,47 @@ class FractionalOffset extends Alignment {
/// The bottom right corner.
static const FractionalOffset bottomRight = const FractionalOffset(1.0, 1.0);
@override
Alignment operator -(Alignment other) {
if (other is! FractionalOffset)
return super - other;
final FractionalOffset typedOther = other;
return new FractionalOffset(dx - typedOther.dx, dy - typedOther.dy);
}
@override
Alignment operator +(Alignment other) {
if (other is! FractionalOffset)
return super + other;
final FractionalOffset typedOther = other;
return new FractionalOffset(dx + typedOther.dx, dy + typedOther.dy);
}
@override
FractionalOffset operator -() {
return new FractionalOffset(-dx, -dy);
}
@override
FractionalOffset operator *(double other) {
return new FractionalOffset(dx * other, dy * other);
}
@override
FractionalOffset operator /(double other) {
return new FractionalOffset(dx / other, dy / other);
}
@override
FractionalOffset operator ~/(double other) {
return new FractionalOffset((dx ~/ other).toDouble(), (dy ~/ other).toDouble());
}
@override
FractionalOffset operator %(double other) {
return new FractionalOffset(dx % other, dy % other);
}
/// Linearly interpolate between two [FractionalOffset]s.
///
/// If either is null, this function interpolates from [FractionalOffset.center].
......@@ -120,4 +186,10 @@ class FractionalOffset extends Alignment {
return new FractionalOffset(ui.lerpDouble(a.dx, 0.5, t), ui.lerpDouble(a.dy, 0.5, t));
return new FractionalOffset(ui.lerpDouble(a.dx, b.dx, t), ui.lerpDouble(a.dy, b.dy, t));
}
@override
String toString() {
return 'FractionalOffset(${dx.toStringAsFixed(1)}, '
'${dy.toStringAsFixed(1)})';
}
}
......@@ -7,14 +7,20 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
test('FractionalOffset control test', () {
const FractionalOffset offset = const FractionalOffset(0.5, 0.25);
expect(offset, hasOneLineDescription);
expect(offset.hashCode, equals(const FractionalOffset(0.5, 0.25).hashCode));
expect(offset / 2.0, const Alignment(0.0, -0.25));
expect(offset ~/ 2.0, Alignment.center);
expect(offset % 5.0, const Alignment(0.0, 4.5));
const FractionalOffset a = const FractionalOffset(0.5, 0.25);
const FractionalOffset b = const FractionalOffset(1.25, 0.75);
expect(a, hasOneLineDescription);
expect(a.hashCode, equals(const FractionalOffset(0.5, 0.25).hashCode));
expect(a.toString(), equals('FractionalOffset(0.5, 0.3)'));
expect(-a, const FractionalOffset(-0.5, -0.25));
expect(a - b, const FractionalOffset(-0.75, -0.5));
expect(a + b, const FractionalOffset(1.75, 1.0));
expect(a * 2.0, const FractionalOffset(1.0, 0.5));
expect(a / 2.0, const FractionalOffset(0.25, 0.125));
expect(a ~/ 2.0, const FractionalOffset(0.0, 0.0));
expect(a % 5.0, const FractionalOffset(0.5, 0.25));
});
test('FractionalOffset.lerp()', () {
......
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