[go: nahoru, domu]

blob: d5e74b5381829400ab10c44b7447a4d059dc7a7b [file] [log] [blame]
/*
* 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.compose.foundation.layout
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceAtLeast
import androidx.compose.ui.unit.coerceIn
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.isFinite
/**
* Similar to [Constraints], but with constraint values expressed in [Dp].
*/
@Immutable
data class DpConstraints(
@Stable
val minWidth: Dp = 0.dp,
@Stable
val maxWidth: Dp = Dp.Infinity,
@Stable
val minHeight: Dp = 0.dp,
@Stable
val maxHeight: Dp = Dp.Infinity
) {
init {
require(minWidth.isFinite()) { "Constraints#minWidth should be finite" }
require(minHeight.isFinite()) { "Constraints#minHeight should be finite" }
require(!minWidth.value.isNaN()) { "Constraints#minWidth should not be NaN" }
require(!maxWidth.value.isNaN()) { "Constraints#maxWidth should not be NaN" }
require(!minHeight.value.isNaN()) { "Constraints#minHeight should not be NaN" }
require(!maxHeight.value.isNaN()) { "Constraints#maxHeight should not be NaN" }
require(minWidth <= maxWidth) {
"Constraints should be satisfiable, but minWidth > maxWidth"
}
require(minHeight <= maxHeight) {
"Constraints should be satisfiable, but minHeight > maxHeight"
}
require(minWidth >= 0.dp) { "Constraints#minWidth should be non-negative" }
require(maxWidth >= 0.dp) { "Constraints#maxWidth should be non-negative" }
require(minHeight >= 0.dp) { "Constraints#minHeight should be non-negative" }
require(maxHeight >= 0.dp) { "Constraints#maxHeight should be non-negative" }
}
companion object {
/**
* Creates constraints tight in both dimensions.
*/
@Stable
fun fixed(width: Dp, height: Dp) = DpConstraints(width, width, height, height)
/**
* Creates constraints with tight width and loose height.
*/
@Stable
fun fixedWidth(width: Dp) = DpConstraints(
minWidth = width,
maxWidth = width,
minHeight = 0.dp,
maxHeight = Dp.Infinity
)
/**
* Creates constraints with tight height and loose width.
*/
@Stable
fun fixedHeight(height: Dp) = DpConstraints(
minWidth = 0.dp,
maxWidth = Dp.Infinity,
minHeight = height,
maxHeight = height
)
}
}
/**
* Whether or not the upper bound on the maximum height.
* @see hasBoundedWidth
*/
@Stable
val DpConstraints.hasBoundedHeight get() = maxHeight.isFinite()
/**
* Whether or not the upper bound on the maximum width.
* @see hasBoundedHeight
*/
@Stable
val DpConstraints.hasBoundedWidth get() = maxWidth.isFinite()
/**
* Whether there is exactly one width value that satisfies the constraints.
*/
@Stable
val DpConstraints.hasFixedWidth get() = maxWidth == minWidth
/**
* Whether there is exactly one height value that satisfies the constraints.
*/
@Stable
val DpConstraints.hasFixedHeight get() = maxHeight == minHeight
/**
* Whether the area of a component respecting these constraints will definitely be 0.
* This is true when at least one of maxWidth and maxHeight are 0.
*/
@Stable
val DpConstraints.isZero get() = maxWidth == 0.dp || maxHeight == 0.dp
/**
* Whether there is any size that satisfies the current constraints.
*/
@Stable
val DpConstraints.satisfiable get() = minWidth <= maxWidth && minHeight <= maxHeight
/**
* Returns the result of coercing the current constraints in a different set of constraints.
*/
@Stable
fun DpConstraints.enforce(otherConstraints: DpConstraints) = DpConstraints(
minWidth = minWidth.coerceIn(otherConstraints.minWidth, otherConstraints.maxWidth),
maxWidth = maxWidth.coerceIn(otherConstraints.minWidth, otherConstraints.maxWidth),
minHeight = minHeight.coerceIn(otherConstraints.minHeight, otherConstraints.maxHeight),
maxHeight = maxHeight.coerceIn(otherConstraints.minHeight, otherConstraints.maxHeight)
)
/**
* Returns the DpConstraints obtained by offsetting the current instance with the given values.
*/
@Stable
fun DpConstraints.offset(horizontal: Dp = 0.dp, vertical: Dp = 0.dp) = DpConstraints(
(minWidth + horizontal).coerceAtLeast(0.dp),
(maxWidth + horizontal).coerceAtLeast(0.dp),
(minHeight + vertical).coerceAtLeast(0.dp),
(maxHeight + vertical).coerceAtLeast(0.dp)
)
/**
* Creates the [Constraints] corresponding to the current [DpConstraints].
*/
@Stable
fun Density.Constraints(dpConstraints: DpConstraints) = Constraints(
minWidth = dpConstraints.minWidth.toIntPx(),
maxWidth = dpConstraints.maxWidth.toIntPx(),
minHeight = dpConstraints.minHeight.toIntPx(),
maxHeight = dpConstraints.maxHeight.toIntPx()
)
/**
* Creates the [DpConstraints] corresponding to the current [Constraints].
*/
@Stable
fun Density.DpConstraints(constraints: Constraints) = DpConstraints(
minWidth = constraints.minWidth.toDp(),
maxWidth = constraints.maxWidth.toDp(),
minHeight = constraints.minHeight.toDp(),
maxHeight = constraints.maxHeight.toDp()
)