Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

components[splitePane]: Feat: Add option to hide first pane in SplitPane #5051

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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 Left Pane" else "Show Left Pane")
}
Button(onClick = { hSplitterState.firstVisible = !hSplitterState.firstVisible }) {
Text(if (hSplitterState.firstVisible) "Hide Top Pane" else "Show Top Pane")
}

OutlinedTextField(value = delta, onValueChange = { delta = it }, label = { Text("Delta") })
Button(onClick = { delta.toFloatOrNull()?.let { splitterState.dispatchRawMovement(it) } }) {
Text("Add delta V")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface SplitPaneScope {
* Left part, for [VerticalSplitPane] it will be Top part
* @param minSize a minimal size of composable item.
* For [HorizontalSplitPane] it will be minimal width, for [VerticalSplitPane] it wil be minimal Heights.
* In this context minimal mean that this composable item could not be smaller than specified value.
* In this context, minimal means that this composable item could not be smaller than the specified value.
* @param content composable item content.
* */
fun first(
Expand All @@ -33,7 +33,7 @@ interface SplitPaneScope {
* For [HorizontalSplitPane] it will be Right part, for [VerticalSplitPane] it will be Bottom part
* @param minSize a minimal size of composable item.
* For [HorizontalSplitPane] it will be minimal width, for [VerticalSplitPane] it wil be minimal Heights.
* In this context minimal mean that this composable item could not be smaller than specified value.
* In this context, minimal means that this composable item could not be smaller than the specified value.
* @param content composable item content.
* */
fun second(
Expand All @@ -48,7 +48,7 @@ interface SplitPaneScope {
/** Receiver scope which is used by [SplitterScope] */
@ExperimentalSplitPaneApi
interface HandleScope {
/** allow mark composable as movable handle */
/** allow mark composable as a movable handle */
fun Modifier.markAsHandle(): Modifier
}

Expand All @@ -65,15 +65,15 @@ interface SplitterScope {

/**
* Set up handle part, this part of splitter would be measured and placed above [visiblePart] content.
* Size of handle will have no effect on split pane parts (first and second) sizes.
* The Size of the handle will have no effect on split pane parts (first and second) sizes.
*
* @param alignment alignment of handle according to [visiblePart] could be:
* @param alignment alignment of the handle according to [visiblePart] could be:
* * [SplitterHandleAlignment.BEFORE] if you place handle before [visiblePart],
* * [SplitterHandleAlignment.ABOVE] if you place handle above [visiblePart] (will be centered)
* * and [SplitterHandleAlignment.AFTER] if you place handle after [visiblePart].
* * and [SplitterHandleAlignment.AFTER] if you place the handle after [visiblePart].
*
* @param content composable item content provider. Uses [HandleScope] to allow mark any provided composable part
* as handle.
* @param content composable item content provider, Uses [HandleScope] to allow marking any provided composable part
* as a handle.
* [content] will be placed only if [SplitPaneState.moveEnabled] is true
*/
fun handle(
Expand Down Expand Up @@ -171,7 +171,7 @@ internal class SplitPaneScopeImpl(
}

/**
* creates a [SplitPaneState] and remembers it across composition
* Creates a [SplitPaneState] and remembers it across composition
*
* Changes to the provided initial values will **not** result in the state being recreated or
* changed in any way if it has already been created.
Expand All @@ -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
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -30,7 +30,7 @@ internal actual fun SplitPane(
second?.let { Box(modifier) { it() } }
return
}

Layout(
{
Box {
Expand Down Expand Up @@ -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) {
Expand All @@ -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(
Expand All @@ -113,7 +115,7 @@ internal actual fun SplitPane(

val handlePlaceable = handleMeasurable.measure(splitterConstraints)
val handleSize = handlePlaceable.valueByDirection(isHorizontal)
// TODO support RTL

val handlePosition = when (splitter.alignment) {
SplitterHandleAlignment.BEFORE -> position + splitterSize - handleSize
SplitterHandleAlignment.ABOVE -> position + (splitterSize - handleSize) / 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ package org.jetbrains.compose.splitpane
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import java.awt.Cursor

@OptIn(ExperimentalComposeUiApi::class)
private fun Modifier.cursorForHorizontalResize(isHorizontal: Boolean): Modifier =
pointerHoverIcon(PointerIcon(Cursor(if (isHorizontal) Cursor.E_RESIZE_CURSOR else Cursor.S_RESIZE_CURSOR)))

Expand Down