[go: nahoru, domu]

blob: 2b968ea7736d0a894e4e3ed52ddac9c652f533a2 [file] [log] [blame]
package androidx.ui.painting.alignment
import androidx.ui.engine.geometry.Offset
import androidx.ui.engine.geometry.Rect
import androidx.ui.engine.geometry.Size
import androidx.ui.lerpFloat
import androidx.ui.engine.text.TextDirection
import androidx.ui.toStringAsFixed
import androidx.ui.truncDiv
/**
* A point within a rectangle.
*
* `Alignment(0.0, 0.0)` represents the center of the rectangle. The distance
* from -1.0 to +1.0 is the distance from one side of the rectangle to the
* other side of the rectangle. Therefore, 2.0 units horizontally (or
* vertically) is equivalent to the width (or height) of the rectangle.
*
* `Alignment(-1.0, -1.0)` represents the top left of the rectangle.
*
* `Alignment(1.0, 1.0)` represents the bottom right of the rectangle.
*
* `Alignment(0.0, 3.0)` represents a point that is horizontally centered with
* respect to the rectangle and vertically below the bottom of the rectangle by
* the height of the rectangle.
*
* [Alignment] use visual coordinates, which means increasing [x] moves the
* point from left to right. To support layouts with a right-to-left
* [TextDirection], consider using [AlignmentDirectional], in which the
* direction the point moves when increasing the horizontal value depends on
* the [TextDirection].
*
* A variety of widgets use [Alignment] in their configuration, most
* notably:
*
* * [Align] positions a child according to a [Alignment].
*
* See also:
*
* * [AlignmentDirectional], which has a horizontal coordinate orientation
* that depends on the [TextDirection].
* * [AlignmentGeometry], which is an abstract type that is agnostic as to
* whether the horizontal direction depends on the [TextDirection].
*/
class Alignment(
/**
* The distance fraction in the horizontal direction.
*
* A value of -1.0 corresponds to the leftmost edge. A value of 1.0
* corresponds to the rightmost edge. Values are not limited to that range;
* values less than -1.0 represent positions to the left of the left edge,
* and values greater than 1.0 represent positions to the right of the right
* edge.
*/
val x: Float,
/**
* The distance fraction in the vertical direction.
*
* A value of -1.0 corresponds to the topmost edge. A value of 1.0
* corresponds to the bottommost edge. Values are not limited to that range;
* values less than -1.0 represent positions above the top, and values
* greater than 1.0 represent positions below the bottom.
*/
val y: Float
) : AlignmentGeometry() {
companion object {
/** The top left corner. */
val topLeft = Alignment(-1.0f, -1.0f)
/** The center point along the top edge. */
val topCenter = Alignment(0.0f, -1.0f)
/** The top right corner. */
val topRight = Alignment(1.0f, -1.0f)
/** The center point along the left edge. */
val centerLeft = Alignment(-1.0f, 0.0f)
/** The center point, both horizontally and vertically. */
val center = Alignment(0.0f, 0.0f)
/** The center point along the right edge. */
val centerRight = Alignment(1.0f, 0.0f)
/** The bottom left corner. */
val bottomLeft = Alignment(-1.0f, 1.0f)
/** The center point along the bottom edge. */
val bottomCenter = Alignment(0.0f, 1.0f)
/** The bottom right corner. */
val bottomRight = Alignment(1.0f, 1.0f)
/**
* Linearly interpolate between two [Alignment]s.
*
* If either is null, this function interpolates from [Alignment.center].
*
* The `t` argument represents position on the timeline, with 0.0 meaning
* that the interpolation has not started, returning `a` (or something
* equivalent to `a`), 1.0 meaning that the interpolation has finished,
* returning `b` (or something equivalent to `b`), and values in between
* meaning that the interpolation is at the relevant point on the timeline
* between `a` and `b`. 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 such as [Curves.elasticInOut]).
*
* Values for `t` are usually obtained from an [Animation<Float>], such as
* an [AnimationController].
*/
fun lerp(a: Alignment?, b: Alignment?, t: Float): Alignment? {
if (a == null && b == null)
return null
if (a == null)
return Alignment(lerpFloat(0.0f, b!!.x, t), lerpFloat(0.0f, b.y, t))
if (b == null)
return Alignment(lerpFloat(a.x, 0.0f, t), lerpFloat(a.y, 0.0f, t))
return Alignment(lerpFloat(a.x, b.x, t), lerpFloat(a.y, b.y, t))
}
internal fun _stringify(x: Float, y: Float): String {
if (x == -1.0f && y == -1.0f)
return "topLeft"
if (x == 0.0f && y == -1.0f)
return "topCenter"
if (x == 1.0f && y == -1.0f)
return "topRight"
if (x == -1.0f && y == 0.0f)
return "centerLeft"
if (x == 0.0f && y == 0.0f)
return "center"
if (x == 1.0f && y == 0.0f)
return "centerRight"
if (x == -1.0f && y == 1.0f)
return "bottomLeft"
if (x == 0.0f && y == 1.0f)
return "bottomCenter"
if (x == 1.0f && y == 1.0f)
return "bottomRight"
return "Alignment(${x.toStringAsFixed(1)}, " +
"${y.toStringAsFixed(1)})"
}
}
override val _x: Float = x
override val _start: Float = 0.0f
override val _y: Float = y
override fun add(other: AlignmentGeometry): AlignmentGeometry {
if (other is Alignment)
return this + other
return super.add(other)
}
/** Returns the difference between two [Alignment]s. */
operator fun minus(other: Alignment): Alignment {
return Alignment(x - other.x, y - other.y)
}
/** Returns the sum of two [Alignment]s. */
operator fun plus(other: Alignment): Alignment {
return Alignment(x + other.x, y + other.y)
}
/** Returns the negation of the given [Alignment]. */
override operator fun unaryMinus(): Alignment {
return Alignment(-x, -y)
}
/** Scales the [Alignment] in each dimension by the given factor. */
override operator fun times(other: Float): Alignment {
return Alignment(x * other, y * other)
}
/** Divides the [Alignment] in each dimension by the given factor. */
override operator fun div(other: Float): Alignment {
return Alignment(x / other, y / other)
}
/** Integer divides the [Alignment] in each dimension by the given factor. */
override fun truncDiv(other: Float): Alignment {
return Alignment(x.truncDiv(other).toFloat(), y.truncDiv(other).toFloat())
}
/** Computes the remainder in each dimension by the given factor. */
override operator fun rem(other: Float): Alignment {
return Alignment(x % other, y % other)
}
/** Returns the offset that is this fraction in the direction of the given offset. */
fun alongOffset(other: Offset): Offset {
val centerX = other.dx / 2.0f
val centerY = other.dy / 2.0f
return Offset(centerX + x * centerX, centerY + y * centerY)
}
/** Returns the offset that is this fraction within the given size. */
fun alongSize(other: Size): Offset {
val centerX = other.width / 2.0f
val centerY = other.height / 2.0f
return Offset(centerX + x * centerX, centerY + y * centerY)
}
/** Returns the point that is this fraction within the given rect. */
fun withinRect(rect: Rect): Offset {
val halfWidth = rect.width / 2.0f
val halfHeight = rect.height / 2.0f
return Offset(
rect.left + halfWidth + x * halfWidth,
rect.top + halfHeight + y * halfHeight
)
}
/**
* Returns a rect of the given size, aligned within given rect as specified
* by this alignment.
*
* For example, a 100×100 size inscribed on a 200×200 rect using
* [Alignment.topLeft] would be the 100×100 rect at the top left of
* the 200×200 rect.
*/
fun inscribe(size: Size, rect: Rect): Rect {
val halfWidthDelta = (rect.width - size.width) / 2.0f
val halfHeightDelta = (rect.height - size.height) / 2.0f
return Rect.fromLTWH(
rect.left + halfWidthDelta + x * halfWidthDelta,
rect.top + halfHeightDelta + y * halfHeightDelta,
size.width,
size.height
)
}
override fun resolve(direction: TextDirection?): Alignment = this
override fun toString() = _stringify(x, y)
}