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

SplitPane not getting affected with Layout dirction changes #4258

Closed
ahmedhosnypro opened this issue Feb 7, 2024 · 2 comments
Closed

SplitPane not getting affected with Layout dirction changes #4258

ahmedhosnypro opened this issue Feb 7, 2024 · 2 comments
Labels
bug Something isn't working component desktop

Comments

@ahmedhosnypro
Copy link
Contributor

ahmedhosnypro commented Feb 7, 2024

Describe the bug
I tried compose splitpane with
CompositionLocalProvider(
LocalLayoutDirection provides LayoutDirection.Rtl
)
but nothing happened

Affected platforms
Select one of the platforms below:

  • Desktop
    *didn't checked others

Versions

  • Kotlin version*: 1.9.22
  • Compose Multiplatform version*: 1.6.0-beta01
  • OS version(s)* (required for Desktop and iOS issues): Windows 11 Insider Prerview 26040
  • OS architecture (x86 or arm64): x86
  • JDK (for desktop issues): openjdk-18 Jetbrains Runtime Version 17.0.8

To Reproduce
followin snippet is from demo


wrppaed by CompositionLocalProvider

CompositionLocalProvider(
        LocalLayoutDirection provides LayoutDirection.Rtl
    ) {
        MaterialTheme {
            val splitterState = rememberSplitPaneState()
            val hSplitterState = rememberSplitPaneState()
            HorizontalSplitPane(
                splitPaneState = splitterState
            ) {
                first(256.dp) {
                    Box(
                        Modifier.background(Color.Red).fillMaxSize(),
                        contentAlignment = Alignment.Center
                    ) {
                        Text("First")
                    }
                }
                second(50.dp) {
                    VerticalSplitPane(splitPaneState = hSplitterState) {
                        first(50.dp) {
                            Box(
                                Modifier.background(Color.Blue).fillMaxSize(),
                                contentAlignment = Alignment.Center
                            ) {
                                Text("Second-Top")
                            }
                        }
                        second(20.dp) {
                            Box(
                                Modifier.background(Color.Green).fillMaxSize(),
                                contentAlignment = Alignment.Center
                            ) {
                                Text("Second-Bottom")
                            }
                        }
                    }
                }
                splitter {
                    visiblePart {
                        Box(
                            Modifier
                                .width(1.dp)
                                .fillMaxHeight()
                                .background(MaterialTheme.colors.background)
                        )
                    }
                    handle {
                        Box(
                            Modifier
                                .markAsHandle()
                                .cursorForHorizontalResize()
                                .background(SolidColor(Color.Gray), alpha = 0.50f)
                                .width(9.dp)
                                .fillMaxHeight()
                        )
                    }
                }
            }
        }
    }

Expected behavior
all content of HorizontalSplitPane to be alligned to right
SplitPaneScope.first is to right of second

Screenshots
Expected:
image

Actual:
image

Additional context
workaround:

@OptIn(ExperimentalSplitPaneApi::class)
@Composable
fun RtlHorizontalSplitPane(
    modifier: Modifier = Modifier,
    splitPaneState: SplitPaneState,
    first: SplitPaneItem = SplitPaneItem(),
    second: SplitPaneItem = SplitPaneItem(),
    splitterVisiblePart: @Composable () -> Unit = {},
    splitterHandle: @Composable HandleScope.() -> Unit,
) {
    val flipModifier = Modifier.graphicsLayer(scaleX = -1f)
    HorizontalSplitPane(
        splitPaneState = splitPaneState,
        modifier = modifier then (flipModifier)
    ) {
        first(first.minSize) {
            Box(modifier = flipModifier) {
                first.content?.invoke()
            }
        }
        second(second.minSize) {
            Box(modifier = flipModifier) {
                second.content?.invoke()
            }
        }
        splitter {
            visiblePart {
                splitterVisiblePart()
            }
            handle {
                splitterHandle()
            }
        }
    }
}

@Stable
@Immutable
data class SplitPaneItem(
    val minSize: Dp = 0.dp,
    val content: @Composable () -> Unit = {}
)

@OptIn(ExperimentalSplitPaneApi::class)
fun main() = singleWindowApplication(
    title = "SplitPane demo"
) {
    val vSplitterState = rememberSplitPaneState()
    val hSplitterState = rememberSplitPaneState()
    CompositionLocalProvider(
        LocalLayoutDirection provides LayoutDirection.Rtl
    ) {
        RtlHorizontalSplitPane(
            splitPaneState = vSplitterState,
            first = SplitPaneItem(minSize = 256.dp) {
                Box(
                    Modifier.background(Color.Red).fillMaxSize(),
                    contentAlignment = Alignment.Center
                ) {
                    Text("First")
                }
            },
            second = SplitPaneItem(minSize = 50.dp) {
                VerticalSplitPane(splitPaneState = hSplitterState) {
                    first(50.dp) {
                        Box(
                            Modifier.background(Color.Blue).fillMaxSize(),
                            contentAlignment = Alignment.Center
                        ) {
                            Text("Second-Top")
                        }
                    }
                    second(20.dp) {
                        Box(
                            Modifier.background(Color.Green).fillMaxSize(),
                            contentAlignment = Alignment.Center
                        ) {
                            Text("Second-Bottom")
                        }
                    }
                }
            },
            splitterVisiblePart = {
                Box(
                    Modifier
                        .width(1.dp)
                        .fillMaxHeight()
                        .background(MaterialTheme.colors.background)
                )
            },
            splitterHandle = {
                Box(
                    Modifier
                        .markAsHandle()
                        .cursorForHorizontalResize()
                        .background(SolidColor(Color.Gray), alpha = 0.50f)
                        .width(9.dp)
                        .fillMaxHeight()
                )
            }
        )
    }
}
@ahmedhosnypro
Copy link
Contributor Author

I submitted a poll here: #4265

igordmn pushed a commit that referenced this issue Feb 8, 2024
This is related to issue:
#4258

changes
- DesktopSplitPane.kt: placable.place() -> placable.placeRelative

- SplitePaneDSL.kt: change the delta direction to follow the layout
direction
```kotlin
 @composable
    override fun Modifier.markAsHandle(): Modifier = this.run {
        val layoutDirection = LocalLayoutDirection.current
        pointerInput(containerScope.splitPaneState) {
            detectDragGestures { change, _ ->
                change.consume()
                containerScope.splitPaneState.dispatchRawMovement(
                    if (containerScope.isHorizontal)
                        if (layoutDirection == LayoutDirection.Ltr) change.position.x else -change.position.x
                    else change.position.y
                )
            }
        }
```

the problem with .onPointerEvent() Modifier, or onDrag also,  is
    whenever the layout direction is Ltr or Rtl:
moving to right always produce positive change, [expected negative if
dir =Rtl]
moving to left always produce negative change, [expected positive if dir
=Rtl]

the calculation of postion will fail if layoutDir is Rtl, because
positionPercentage will be out of range
```kotlin
fun dispatchRawMovement(delta: Float) {
        val movableArea = maxPosition - minPosition
        if (movableArea > 0) {
            positionPercentage =
                ((movableArea * positionPercentage) + delta).coerceIn(0f, movableArea) / movableArea
        }
    }
```
@igordmn igordmn closed this as completed Feb 8, 2024
@igordmn
Copy link
Collaborator

igordmn commented Feb 8, 2024

We'll include it in 1.6.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working component desktop
Projects
None yet
Development

No branches or pull requests

3 participants