[go: nahoru, domu]

blob: 58f327f169a539e9eaac39e51966a0d1b4bed586 [file] [log] [blame]
/*
* Copyright 2018 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.painting.alignment
import androidx.ui.lerpFloat
import androidx.ui.engine.text.TextDirection
import androidx.ui.toStringAsFixed
import androidx.ui.truncDiv
/**
* An offset that's expressed as a fraction of a [Size], but whose horizontal
* component is dependent on the writing direction.
*
* This can be used to indicate an offset from the left in [TextDirection.ltr]
* text and an offset from the right in [TextDirection.rtl] text without having
* to be aware of the current text direction.
*
* See also:
*
* * [Alignment], a variant that is defined in physical terms (i.e.
* whose horizontal component does not depend on the text direction).
*/
class AlignmentDirectional(
/**
* The distance fraction in the horizontal direction.
*
* A value of -1.0 corresponds to the edge on the "start" side, which is the
* left side in [TextDirection.ltr] contexts and the right side in
* [TextDirection.rtl] contexts. A value of 1.0 corresponds to the opposite
* edge, the "end" side. Values are not limited to that range; values less
* than -1.0 represent positions beyond the start edge, and values greater than
* 1.0 represent positions beyond the end edge.
*
* This value is normalized into a [Alignment.x] value by the [resolve]
* method.
*/
val start: 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.
*
* This value is passed through to [Alignment.y] unmodified by the
* [resolve] method.
*/
val y: Float
) : AlignmentGeometry() {
override val _x: Float = 0.0f
override val _start: Float = start
override val _y: Float = y
companion object {
/** The top corner on the "start" side. */
val topStart = AlignmentDirectional(-1.0f, -1.0f)
/**
* The center point along the top edge.
*
* Consider using [Alignment.topCenter] instead, as it does not need
* to be [resolve]d to be used.
*/
val topCenter = AlignmentDirectional(0.0f, -1.0f)
/** The top corner on the "end" side. */
val topEnd = AlignmentDirectional(1.0f, -1.0f)
/** The center point along the "start" edge. */
val centerStart = AlignmentDirectional(-1.0f, 0.0f)
/**
* The center point, both horizontally and vertically.
*
* Consider using [Alignment.center] instead, as it does not need to
* be [resolve]d to be used.
*/
val center = AlignmentDirectional(0.0f, 0.0f)
/** The center point along the "end" edge. */
val centerEnd = AlignmentDirectional(1.0f, 0.0f)
/** The bottom corner on the "start" side. */
val bottomStart = AlignmentDirectional(-1.0f, 1.0f)
/**
* The center point along the bottom edge.
*
* Consider using [Alignment.bottomCenter] instead, as it does not
* need to be [resolve]d to be used.
*/
val bottomCenter = AlignmentDirectional(0.0f, 1.0f)
/** The bottom corner on the "end" side. */
val bottomEnd = AlignmentDirectional(1.0f, 1.0f)
/**
* Linearly interpolate between two [AlignmentDirectional]s.
*
* If either is null, this function interpolates from [AlignmentDirectional.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: AlignmentDirectional?,
b: AlignmentDirectional?,
t: Float
): AlignmentDirectional? {
if (a == null && b == null)
return null
if (a == null)
return AlignmentDirectional(lerpFloat(0.0f, b!!.start, t), lerpFloat(0.0f, b.y, t))
if (b == null)
return AlignmentDirectional(lerpFloat(a.start, 0.0f, t), lerpFloat(a.y, 0.0f, t))
return AlignmentDirectional(lerpFloat(a.start, b.start, t), lerpFloat(a.y, b.y, t))
}
fun _stringify(start: Float, y: Float): String {
if (start == -1.0f && y == -1.0f)
return "AlignmentDirectional.topStart"
if (start == 0.0f && y == -1.0f)
return "AlignmentDirectional.topCenter"
if (start == 1.0f && y == -1.0f)
return "AlignmentDirectional.topEnd"
if (start == -1.0f && y == 0.0f)
return "AlignmentDirectional.centerStart"
if (start == 0.0f && y == 0.0f)
return "AlignmentDirectional.center"
if (start == 1.0f && y == 0.0f)
return "AlignmentDirectional.centerEnd"
if (start == -1.0f && y == 1.0f)
return "AlignmentDirectional.bottomStart"
if (start == 0.0f && y == 1.0f)
return "AlignmentDirectional.bottomCenter"
if (start == 1.0f && y == 1.0f)
return "AlignmentDirectional.bottomEnd"
return "AlignmentDirectional(${start.toStringAsFixed(1)}, " +
"${y.toStringAsFixed(1)})"
}
}
override fun add(other: AlignmentGeometry): AlignmentGeometry {
if (other is AlignmentDirectional)
return this + other
return super.add(other)
}
/** Returns the difference between two [AlignmentDirectional]s. */
operator fun minus(other: AlignmentDirectional): AlignmentGeometry {
return AlignmentDirectional(start - other.start, y - other.y)
}
/** Returns the sum of two [AlignmentDirectional]s. */
operator fun plus(other: AlignmentDirectional): AlignmentDirectional {
return AlignmentDirectional(start + other.start, y + other.y)
}
/** Returns the negation of the given [AlignmentDirectional]. */
override operator fun unaryMinus(): AlignmentDirectional {
return AlignmentDirectional(-start, -y)
}
/** Scales the [AlignmentDirectional] in each dimension by the given factor. */
override operator fun times(other: Float): AlignmentGeometry {
return AlignmentDirectional(start * other, y * other)
}
/** Divides the [AlignmentDirectional] in each dimension by the given factor. */
override operator fun div(other: Float): AlignmentGeometry {
return AlignmentDirectional(start / other, y / other)
}
/** Integer divides the [AlignmentDirectional] in each dimension by the given factor. */
override fun truncDiv(other: Float): AlignmentGeometry {
return AlignmentDirectional(
(start.truncDiv(other)).toFloat(),
(y.truncDiv(other)).toFloat())
}
/** Computes the remainder in each dimension by the given factor. */
override operator fun rem(other: Float): AlignmentGeometry {
return AlignmentDirectional(start % other, y % other)
}
override fun resolve(direction: TextDirection?): Alignment {
assert(direction != null)
return when (direction!!) {
TextDirection.RTL -> Alignment(-start, y)
TextDirection.LTR -> Alignment(start, y)
}
}
override fun toString() = _stringify(start, y)
}