fractional_offset.dart 5.3 KB
Newer Older
1 2 3 4 5 6
// 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 'dart:ui' as ui show lerpDouble;

7 8
import 'package:flutter/foundation.dart';

9 10
import 'basic_types.dart';

11 12 13 14
/// An offset that's expressed as a fraction of a Size.
///
/// FractionalOffset(1.0, 0.0) represents the top right of the Size,
/// FractionalOffset(0.0, 1.0) represents the bottom left of the Size,
15
@immutable
16 17 18 19
class FractionalOffset {
  /// Creates a fractional offset.
  ///
  /// The [dx] and [dy] arguments must not be null.
20 21 22
  const FractionalOffset(this.dx, this.dy)
    : assert(dx != null),
      assert(dy != null);
23 24 25

  /// The distance fraction in the horizontal direction.
  ///
26 27
  /// A value of 0.0 corresponds to the leftmost edge. A value of 1.0
  /// corresponds to the rightmost edge.
28 29 30 31
  final double dx;

  /// The distance fraction in the vertical direction.
  ///
32 33
  /// A value of 0.0 corresponds to the topmost edge. A value of 1.0
  /// corresponds to the bottommost edge.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
  final double dy;

  /// The top left corner.
  static const FractionalOffset topLeft = const FractionalOffset(0.0, 0.0);

  /// The center point along the top edge.
  static const FractionalOffset topCenter = const FractionalOffset(0.5, 0.0);

  /// The top right corner.
  static const FractionalOffset topRight = const FractionalOffset(1.0, 0.0);

  /// The bottom left corner.
  static const FractionalOffset bottomLeft = const FractionalOffset(0.0, 1.0);

  /// The center point along the bottom edge.
  static const FractionalOffset bottomCenter = const FractionalOffset(0.5, 1.0);

  /// The bottom right corner.
  static const FractionalOffset bottomRight = const FractionalOffset(1.0, 1.0);

  /// The center point along the left edge.
  static const FractionalOffset centerLeft = const FractionalOffset(0.0, 0.5);

  /// The center point along the right edge.
  static const FractionalOffset centerRight = const FractionalOffset(1.0, 0.5);

  /// The center point, both horizontally and vertically.
  static const FractionalOffset center = const FractionalOffset(0.5, 0.5);

  /// Returns the negation of the given fractional offset.
  FractionalOffset operator -() {
    return new FractionalOffset(-dx, -dy);
  }

  /// Returns the difference between two fractional offsets.
  FractionalOffset operator -(FractionalOffset other) {
    return new FractionalOffset(dx - other.dx, dy - other.dy);
  }

  /// Returns the sum of two fractional offsets.
  FractionalOffset operator +(FractionalOffset other) {
    return new FractionalOffset(dx + other.dx, dy + other.dy);
  }

  /// Scales the fractional offset in each dimension by the given factor.
  FractionalOffset operator *(double other) {
    return new FractionalOffset(dx * other, dy * other);
  }

  /// Divides the fractional offset in each dimension by the given factor.
  FractionalOffset operator /(double other) {
    return new FractionalOffset(dx / other, dy / other);
  }

  /// Integer divides the fractional offset in each dimension by the given factor.
  FractionalOffset operator ~/(double other) {
    return new FractionalOffset((dx ~/ other).toDouble(), (dy ~/ other).toDouble());
  }

  /// Computes the remainder in each dimension by the given factor.
  FractionalOffset operator %(double other) {
    return new FractionalOffset(dx % other, dy % other);
  }

  /// Returns the offset that is this fraction in the direction of the given offset.
  Offset alongOffset(Offset other) {
    return new Offset(dx * other.dx, dy * other.dy);
  }

  /// Returns the offset that is this fraction within the given size.
  Offset alongSize(Size other) {
    return new Offset(dx * other.width, dy * other.height);
  }

  /// Returns the point that is this fraction within the given rect.
109 110
  Offset withinRect(Rect rect) {
    return new Offset(rect.left + dx * rect.width, rect.top + dy * rect.height);
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
  }

  /// Returns a rect of the given size, centered at this fraction of the given rect.
  ///
  /// For example, a 100×100 size inscribed on a 200×200 rect using
  /// [FractionalOffset.topLeft] would be the 100×100 rect at the top left of
  /// the 200×200 rect.
  Rect inscribe(Size size, Rect rect) {
    return new Rect.fromLTWH(
      rect.left + (rect.width - size.width) * dx,
      rect.top + (rect.height - size.height) * dy,
      size.width,
      size.height
    );
  }

  @override
  bool operator ==(dynamic other) {
    if (other is! FractionalOffset)
      return false;
    final FractionalOffset typedOther = other;
    return dx == typedOther.dx &&
           dy == typedOther.dy;
  }

  @override
  int get hashCode => hashValues(dx, dy);

  /// Linearly interpolate between two EdgeInsets.
  ///
  /// If either is null, this function interpolates from [FractionalOffset.topLeft].
  // TODO(abarth): Consider interpolating from [FractionalOffset.center] instead
  // to remove upper-left bias.
  static FractionalOffset lerp(FractionalOffset a, FractionalOffset b, double t) {
    if (a == null && b == null)
      return null;
    if (a == null)
      return new FractionalOffset(b.dx * t, b.dy * t);
    if (b == null)
150
      return new FractionalOffset(a.dx * (1.0 - t), a.dy * (1.0 - t));
151 152 153 154 155 156
    return new FractionalOffset(ui.lerpDouble(a.dx, b.dx, t), ui.lerpDouble(a.dy, b.dy, t));
  }

  @override
  String toString() => '$runtimeType($dx, $dy)';
}