| /* |
| * Copyright 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.ui.geometry |
| |
| import androidx.compose.Immutable |
| import androidx.ui.util.lerp |
| import androidx.ui.util.packFloats |
| import androidx.ui.util.toStringAsFixed |
| import androidx.ui.util.unpackFloat1 |
| import androidx.ui.util.unpackFloat2 |
| import kotlin.math.absoluteValue |
| import kotlin.math.max |
| import kotlin.math.min |
| import kotlin.math.truncate |
| |
| /** |
| * Constructs a [Size] from the given width and height |
| */ |
| fun Size(width: Float, height: Float) = Size(packFloats(width, height)) |
| |
| /** |
| * Holds a 2D floating-point size. |
| * |
| * You can think of this as an [Offset] from the origin. |
| */ |
| @Immutable |
| inline class Size(@PublishedApi internal val value: Long) { |
| |
| val width: Float |
| get() = unpackFloat1(value) |
| |
| val height: Float |
| get() = unpackFloat2(value) |
| |
| companion object { |
| /** |
| * Creates an instance of [Size] that has the same values as another. |
| */ |
| // Used by the rendering library's _DebugSize hack. |
| fun copy(source: Size): Size { |
| return Size(source.width, source.height) |
| } |
| |
| /** |
| * Creates a square [Size] whose [width] and [height] are the given dimension. |
| * |
| * See also: |
| * |
| * * [new Size.fromRadius], which is more convenient when the available size |
| * is the radius of a circle. |
| */ |
| fun square(dimension: Float): Size { |
| return Size(dimension, dimension) |
| } |
| |
| /** |
| * Creates a [Size] with the given [width] and an infinite [height]. |
| */ |
| fun fromWidth(width: Float): Size { |
| return Size(width, Float.POSITIVE_INFINITY) |
| } |
| |
| /** |
| * Creates a [Size] with the given [height] and an infinite [width]. |
| */ |
| fun fromHeight(height: Float): Size { |
| return Size(Float.POSITIVE_INFINITY, height) |
| } |
| |
| /** |
| * Creates a square [Size] whose [width] and [height] are twice the given |
| * dimension. |
| * |
| * This is a square that contains a circle with the given radius. |
| * |
| * See also: |
| * |
| * * [new Size.square], which creates a square with the given dimension. |
| */ |
| fun fromRadius(radius: Float): Size { |
| return Size(radius * 2.0f, radius * 2.0f) |
| } |
| |
| /** |
| * An empty size, one with a zero width and a zero height. |
| */ |
| val zero = Size(0.0f, 0.0f) |
| |
| /** |
| * A size whose [width] and [height] are infinite. |
| * |
| * See also: |
| * |
| * * [isInfinite], which checks whether either dimension is infinite. |
| * * [isFinite], which checks whether both dimensions are finite. |
| */ |
| val infinite = Size(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY) |
| |
| /** |
| * Linearly interpolate between two sizes |
| * |
| * The [fraction] argument represents position on the timeline, with 0.0 meaning |
| * that the interpolation has not started, returning [start] (or something |
| * equivalent to [start]), 1.0 meaning that the interpolation has finished, |
| * returning [stop] (or something equivalent to [stop]), and values in between |
| * meaning that the interpolation is at the relevant point on the timeline |
| * between [start] and [stop]. The interpolation can be extrapolated beyond 0.0 and |
| * 1.0, so negative values and values greater than 1.0 are valid (and can |
| * easily be generated by curves). |
| * |
| * Values for [fraction] are usually obtained from an [Animation<Float>], such as |
| * an `AnimationController`. |
| */ |
| fun lerp(start: Size, stop: Size, fraction: Float): Size? { |
| return Size( |
| lerp(start.width, stop.width, fraction), |
| lerp(start.height, stop.height, fraction) |
| ) |
| } |
| } |
| |
| /** |
| * Whether this size encloses a non-zero area. |
| * |
| * Negative areas are considered empty. |
| */ |
| fun isEmpty() = width <= 0.0f || height <= 0.0f |
| |
| /** |
| * Binary subtraction operator for [Size]. |
| * |
| * Subtracting a [Size] from a [Size] returns the [Offset] that describes how |
| * much bigger the left-hand-side operand is than the right-hand-side |
| * operand. Adding that resulting [Offset] to the [Size] that was the |
| * right-hand-side operand would return a [Size] equal to the [Size] that was |
| * the left-hand-side operand. (i.e. if `sizeA - sizeB -> offsetA`, then |
| * `offsetA + sizeB -> sizeA`) |
| * |
| * Subtracting an [Offset] from a [Size] returns the [Size] that is smaller than |
| * the [Size] operand by the difference given by the [Offset] operand. In other |
| * words, the returned [Size] has a [width] consisting of the [width] of the |
| * left-hand-side operand minus the [Offset.dx] dimension of the |
| * right-hand-side operand, and a [height] consisting of the [height] of the |
| * left-hand-side operand minus the [Offset.dy] dimension of the |
| * right-hand-side operand. |
| */ |
| operator fun minus(other: Offset): Size { |
| return Size(width - other.dx, height - other.dy) |
| } |
| |
| operator fun minus(other: Size): Offset { |
| return Offset(width - other.width, height - other.height) |
| } |
| |
| /** |
| * Binary addition operator for adding an [Offset] to a [Size]. |
| * |
| * Returns a [Size] whose [width] is the sum of the [width] of the |
| * left-hand-side operand, a [Size], and the [Offset.dx] dimension of the |
| * right-hand-side operand, an [Offset], and whose [height] is the sum of the |
| * [height] of the left-hand-side operand and the [Offset.dy] dimension of |
| * the right-hand-side operand. |
| */ |
| operator fun plus(other: Offset) = Size(width + other.dx, height + other.dy) |
| |
| /** |
| * Multiplication operator. |
| * |
| * Returns a [Size] whose dimensions are the dimensions of the left-hand-side |
| * operand (a [Size]) multiplied by the scalar right-hand-side operand (a |
| * [Float]). |
| */ |
| operator fun times(operand: Float) = Size(width * operand, height * operand) |
| |
| /** |
| * Division operator. |
| * |
| * Returns a [Size] whose dimensions are the dimensions of the left-hand-side |
| * operand (a [Size]) divided by the scalar right-hand-side operand (a |
| * [Float]). |
| */ |
| operator fun div(operand: Float) = Size(width / operand, height / operand) |
| |
| /** |
| * Integer (truncating) division operator. |
| * |
| * Returns a [Size] whose dimensions are the dimensions of the left-hand-side |
| * operand (a [Size]) divided by the scalar right-hand-side operand (a |
| * [Float]), rounded towards zero. |
| */ |
| fun truncDiv(operand: Float) = |
| Size(truncate(width / operand), truncate(height / operand)) |
| |
| /** |
| * Modulo (remainder) operator. |
| * |
| * Returns a [Size] whose dimensions are the remainder of dividing the |
| * left-hand-side operand (a [Size]) by the scalar right-hand-side operand (a |
| * [Float]). |
| */ |
| operator fun rem(operand: Float) = Size(width % operand, height % operand) |
| |
| /** |
| * The lesser of the magnitudes of the [width] and the [height]. |
| */ |
| val minDimension: Float |
| get() = min(width.absoluteValue, height.absoluteValue) |
| |
| /** |
| * The greater of the magnitudes of the [width] and the [height]. |
| */ |
| val maxDimension: Float |
| get() = max(width.absoluteValue, height.absoluteValue) |
| |
| // Convenience methods that do the equivalent of calling the similarly named |
| // methods on a Rect constructed from the given origin and this size. |
| |
| /** |
| * The offset to the intersection of the top and left edges of the rectangle |
| * described by the given [Offset] (which is interpreted as the top-left corner) |
| * and this [Size]. |
| * |
| * See also [Rect.topLeft]. |
| */ |
| fun topLeft(origin: Offset): Offset = origin |
| |
| /** |
| * The offset to the center of the top edge of the rectangle described by the |
| * given offset (which is interpreted as the top-left corner) and this size. |
| * |
| * See also [Rect.topCenter]. |
| */ |
| fun topCenter(origin: Offset): Offset = Offset(origin.dx + width / 2.0f, origin.dy) |
| |
| /** |
| * The offset to the intersection of the top and right edges of the rectangle |
| * described by the given offset (which is interpreted as the top-left corner) |
| * and this size. |
| * |
| * See also [Rect.topRight]. |
| */ |
| fun topRight(origin: Offset): Offset = Offset(origin.dx + width, origin.dy) |
| |
| /** |
| * The offset to the center of the left edge of the rectangle described by the |
| * given offset (which is interpreted as the top-left corner) and this size. |
| * |
| * See also [Rect.centerLeft]. |
| */ |
| fun centerLeft(origin: Offset): Offset = Offset(origin.dx, origin.dy + height / 2.0f) |
| |
| /** |
| * The offset to the point halfway between the left and right and the top and |
| * bottom edges of the rectangle described by the given offset (which is |
| * interpreted as the top-left corner) and this size. |
| * |
| * See also [Rect.center]. |
| */ |
| fun center(origin: Offset = Offset.zero): Offset = Offset(origin.dx + width / 2.0f, origin.dy + |
| height / 2.0f) |
| |
| /** |
| * The offset to the center of the right edge of the rectangle described by the |
| * given offset (which is interpreted as the top-left corner) and this size. |
| * |
| * See also [Rect.centerLeft]. |
| */ |
| fun centerRight(origin: Offset): Offset = Offset(origin.dx + width, origin.dy + height / 2.0f) |
| |
| /** |
| * The offset to the intersection of the bottom and left edges of the |
| * rectangle described by the given offset (which is interpreted as the |
| * top-left corner) and this size. |
| * |
| * See also [Rect.bottomLeft]. |
| */ |
| fun bottomLeft(origin: Offset): Offset = Offset(origin.dx, origin.dy + height) |
| |
| /** |
| * The offset to the center of the bottom edge of the rectangle described by |
| * the given offset (which is interpreted as the top-left corner) and this |
| * size. |
| * |
| * See also [Rect.bottomLeft]. |
| */ |
| fun bottomCenter(origin: Offset): Offset = Offset(origin.dx + width / 2.0f, origin.dy + height) |
| |
| /** |
| * The offset to the intersection of the bottom and right edges of the |
| * rectangle described by the given offset (which is interpreted as the |
| * top-left corner) and this size. |
| * |
| * See also [Rect.bottomRight]. |
| */ |
| fun bottomRight(origin: Offset): Offset = Offset(origin.dx + width, origin.dy + height) |
| |
| /** |
| * Whether the point specified by the given offset (which is assumed to be |
| * relative to the top left of the size) lies between the left and right and |
| * the top and bottom edges of a rectangle of this size. |
| * |
| * Rectangles include their top and left edges but exclude their bottom and |
| * right edges. |
| */ |
| fun contains(offset: Offset): Boolean { |
| return offset.dx >= 0.0f && offset.dx < width && offset.dy >= 0.0f && offset.dy < height |
| } |
| |
| /** |
| * A [Size] with the [width] and [height] swapped. |
| */ |
| fun getFlipped() = Size(height, width) |
| |
| override fun toString() = "Size(${width.toStringAsFixed(1)}, ${height.toStringAsFixed(1)})" |
| } |
| |
| /** |
| * Convert a [Size] to a [Rect]. |
| */ |
| fun Size.toRect(): Rect { |
| return Rect(0f, 0f, width, height) |
| } |