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
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) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |