From 68012ededab304c8da5ec0a2de587acae9e1c1aa Mon Sep 17 00:00:00 2001 From: Ahmed Hosny Date: Mon, 1 Jul 2024 03:04:01 +0300 Subject: [PATCH] [SplitPane] Add ability to hide first pane This commit adds the ability to hide the first pane in a SplitPane. - Adds `firstVisible ` property to `SplitPaneState` to control the visibility of the first pane. - Updates `SplitPane` layout to handle the visibility of the first pane. - Adds buttons to the demo to toggle the visibility of the first pane. --- .../org/jetbrains/compose/splitpane/demo/Main.kt | 13 +++++++++++++ .../org/jetbrains/compose/splitpane/SplitPaneDSL.kt | 4 +++- .../jetbrains/compose/splitpane/SplitPaneState.kt | 3 +++ .../jetbrains/compose/splitpane/DesktopSplitPane.kt | 12 +++++++----- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/components/SplitPane/demo/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt b/components/SplitPane/demo/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt index dd14048434..a7e5b5bd06 100644 --- a/components/SplitPane/demo/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt +++ b/components/SplitPane/demo/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt @@ -23,7 +23,9 @@ import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.input.pointer.PointerIcon import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.singleWindowApplication import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi import org.jetbrains.compose.splitpane.HorizontalSplitPane @@ -36,8 +38,12 @@ private fun Modifier.cursorForHorizontalResize(): Modifier = @OptIn(ExperimentalSplitPaneApi::class) fun main() = singleWindowApplication( + state = WindowState( + size = DpSize(800.dp, 700.dp) + ), title = "SplitPane demo" ) { + MaterialTheme { val splitterState = rememberSplitPaneState() val hSplitterState = rememberSplitPaneState() @@ -53,6 +59,13 @@ fun main() = singleWindowApplication( Text(if (hSplitterState.moveEnabled) "Freeze H" else "Unfreeze H") } + Button(onClick = { splitterState.firstVisible = !splitterState.firstVisible }) { + Text(if (splitterState.firstVisible) "Hide V First" else "Show V First") + } + Button(onClick = { hSplitterState.firstVisible = !hSplitterState.firstVisible }) { + Text(if (hSplitterState.firstVisible) "Hide H First" else "Show H First") + } + OutlinedTextField(value = delta, onValueChange = { delta = it }, label = { Text("Delta") }) Button(onClick = { delta.toFloatOrNull()?.let { splitterState.dispatchRawMovement(it) } }) { Text("Add delta V") diff --git a/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneDSL.kt b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneDSL.kt index 4c53343152..61d315cd12 100644 --- a/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneDSL.kt +++ b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneDSL.kt @@ -183,11 +183,13 @@ internal class SplitPaneScopeImpl( @Composable fun rememberSplitPaneState( initialPositionPercentage: Float = 0f, - moveEnabled: Boolean = true + moveEnabled: Boolean = true, + firstVisible: Boolean = true ): SplitPaneState { return remember { SplitPaneState( moveEnabled = moveEnabled, + firstVisible = firstVisible, initialPositionPercentage = initialPositionPercentage ) } diff --git a/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneState.kt b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneState.kt index 0ea874f708..8e52f24ed0 100644 --- a/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneState.kt +++ b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneState.kt @@ -8,10 +8,13 @@ import androidx.compose.runtime.setValue class SplitPaneState( initialPositionPercentage: Float, moveEnabled: Boolean, + firstVisible: Boolean = true ) { var moveEnabled by mutableStateOf(moveEnabled) + var firstVisible by mutableStateOf(firstVisible) + private var _positionPercentage by mutableStateOf(initialPositionPercentage) var positionPercentage: Float get() = _positionPercentage diff --git a/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt b/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt index a8c1f00d22..3141efcba5 100644 --- a/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt +++ b/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt @@ -14,8 +14,8 @@ private fun Constraints.withUnconstrainedWidth() = copy(minWidth = 0, maxWidth = private fun Constraints.withUnconstrainedHeight() = copy(minHeight = 0, maxHeight = Constraints.Infinity) -@OptIn(ExperimentalSplitPaneApi::class) @Composable +@OptIn(ExperimentalSplitPaneApi::class) internal actual fun SplitPane( modifier: Modifier, isHorizontal: Boolean, @@ -30,7 +30,7 @@ internal actual fun SplitPane( second?.let { Box(modifier) { it() } } return } - + Layout( { Box { @@ -77,8 +77,10 @@ internal actual fun SplitPane( minPosition = constrainedMin maxPosition = constrainedMax - val position = (constrainedMin * (1-positionPercentage) + constrainedMax * positionPercentage) - .roundToInt() + val position = + if (firstVisible) { + (constrainedMin * (1 - positionPercentage) + constrainedMax * positionPercentage).roundToInt() + } else 0 val firstPlaceable = firstMeasurable.measure( if (isHorizontal) { @@ -94,7 +96,7 @@ internal actual fun SplitPane( } ) - val secondPlaceablePosition = position + splitterSize + val secondPlaceablePosition = if (firstVisible) position + splitterSize else 0 val secondAvailableSize = (maxConstraintOnMainAxis - secondPlaceablePosition).coerceAtLeast(0) val secondPlaceable = secondMeasurable.measure(