You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

140 lines
5.8 KiB

package org.jetbrains.compose.splitpane
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.Constraints
import kotlin.math.roundToInt
private fun Constraints.maxByDirection(isHorizontal: Boolean): Int = if (isHorizontal) maxWidth else maxHeight
private fun Constraints.minByDirection(isHorizontal: Boolean): Int = if (isHorizontal) minWidth else minHeight
private fun Placeable.valueByDirection(isHorizontal: Boolean): Int = if (isHorizontal) width else height
@Composable
internal actual fun SplitPane(
modifier: Modifier,
isHorizontal: Boolean,
splitPaneState: SplitPaneState,
minimalSizesConfiguration: MinimalSizes,
first: @Composable () -> Unit,
second: @Composable () -> Unit,
splitter: Splitter
) {
Layout(
{
first()
splitter.measuredPart()
second()
splitter.handlePart()
},
modifier,
) { measurables, constraints ->
with(minimalSizesConfiguration) {
with(splitPaneState) {
val constrainedMin = constraints.minByDirection(isHorizontal) + firstPlaceableMinimalSize.value
val constrainedMax =
(constraints.maxByDirection(isHorizontal).toFloat() - secondPlaceableMinimalSize.value).let {
if (it <= 0 || it <= constrainedMin) {
constraints.maxByDirection(isHorizontal).toFloat()
} else {
it
}
}
if (minPosition != constrainedMin) {
maxPosition = constrainedMin
}
if (maxPosition != constrainedMax) {
maxPosition =
if ((firstPlaceableMinimalSize + secondPlaceableMinimalSize).value < constraints.maxByDirection(
isHorizontal
)
) {
constrainedMax
} else {
minPosition
}
}
val constrainedPosition =
(constraints.maxByDirection(isHorizontal) - (firstPlaceableMinimalSize + secondPlaceableMinimalSize).value).let {
if (it > 0f) {
(it * positionPercentage).coerceIn(constrainedMin, constrainedMax).roundToInt()
} else {
constrainedMin.roundToInt()
}
}
val firstPlaceable = measurables[0].measure(
if (isHorizontal) {
constraints.copy(
minWidth = 0,
maxWidth = constrainedPosition
)
} else {
constraints.copy(
minHeight = 0,
maxHeight = constrainedPosition
)
}
)
val splitterPlaceable = measurables[1].measure(constraints)
val secondPlaceablePosition = constrainedPosition + splitterPlaceable.valueByDirection(isHorizontal)
val secondPlaceableSize =
(constraints.maxByDirection(isHorizontal) - secondPlaceablePosition).coerceIn(
0,
if (secondPlaceablePosition < constraints.maxByDirection(isHorizontal)) {
constraints.maxByDirection(isHorizontal) - secondPlaceablePosition
} else {
constraints.maxByDirection(isHorizontal)
}
)
val secondPlaceable = measurables[2].measure(
if (isHorizontal) {
constraints.copy(
minWidth = 0,
maxWidth = secondPlaceableSize
)
} else {
constraints.copy(
minHeight = 0,
maxHeight = secondPlaceableSize
)
}
)
val handlePlaceable = measurables[3].measure(constraints)
val handlePosition = when (splitter.align) {
SplitterHandleAlign.BEFORE -> constrainedPosition - handlePlaceable.valueByDirection(isHorizontal)
SplitterHandleAlign.ABOVE -> constrainedPosition - (handlePlaceable.valueByDirection(isHorizontal) / 2)
SplitterHandleAlign.AFTER -> constrainedPosition + handlePlaceable.valueByDirection(isHorizontal)
}
layout(constraints.maxWidth, constraints.maxHeight) {
firstPlaceable.place(0, 0)
if (isHorizontal) {
secondPlaceable.place(secondPlaceablePosition, 0)
splitterPlaceable.place(constrainedPosition, 0)
if (moveEnabled) {
handlePlaceable.place(handlePosition, 0)
}
} else {
secondPlaceable.place(0, secondPlaceablePosition)
splitterPlaceable.place(0, constrainedPosition)
if (moveEnabled) {
handlePlaceable.place(0, handlePosition)
}
}
}
}
}
}
}