From a8e9486b9e69045bd29aef9a04764913a852257e Mon Sep 17 00:00:00 2001 From: Ahmed Hosny Date: Thu, 8 Feb 2024 15:41:56 +0200 Subject: [PATCH] Support Rtl in SplitPane (#4265) This is related to issue: https://github.com/JetBrains/compose-multiplatform/issues/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 } } ``` --- .../compose/splitpane/SplitPaneDSL.kt | 20 +++++++++++++------ .../compose/splitpane/DesktopSplitPane.kt | 14 ++++++------- .../compose/splitpane/DesktopSplitter.kt | 19 ++++++++++++------ 3 files changed, 34 insertions(+), 19 deletions(-) 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 0a730931d4..4c53343152 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 @@ -4,8 +4,11 @@ import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.composed import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp /** Receiver scope which is used by [HorizontalSplitPane] and [VerticalSplitPane] */ @@ -83,12 +86,17 @@ interface SplitterScope { internal class HandleScopeImpl( private val containerScope: SplitPaneScopeImpl ) : HandleScope { - override fun Modifier.markAsHandle(): Modifier = this.pointerInput(containerScope.splitPaneState) { - detectDragGestures { change, _ -> - change.consume() - containerScope.splitPaneState.dispatchRawMovement( - if (containerScope.isHorizontal) change.position.x else change.position.y - ) + override fun Modifier.markAsHandle(): Modifier = composed { + 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 + ) + } } } } 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 cf978e2ae8..a8c1f00d22 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 @@ -121,18 +121,18 @@ internal actual fun SplitPane( } layout(constraints.maxWidth, constraints.maxHeight) { - firstPlaceable.place(0, 0) + firstPlaceable.placeRelative(0, 0) if (isHorizontal) { - secondPlaceable.place(secondPlaceablePosition, 0) - splitterPlaceable.place(position, 0) + secondPlaceable.placeRelative(secondPlaceablePosition, 0) + splitterPlaceable.placeRelative(position, 0) if (moveEnabled) { - handlePlaceable.place(handlePosition, 0) + handlePlaceable.placeRelative(handlePosition, 0) } } else { - secondPlaceable.place(0, secondPlaceablePosition) - splitterPlaceable.place(0, position) + secondPlaceable.placeRelative(0, secondPlaceablePosition) + splitterPlaceable.placeRelative(0, position) if (moveEnabled) { - handlePlaceable.place(0, handlePosition) + handlePlaceable.placeRelative(0, handlePosition) } } } diff --git a/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt b/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt index 15e5c6cccb..92ad6749e8 100644 --- a/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt +++ b/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt @@ -6,6 +6,8 @@ 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 @@ -20,12 +22,17 @@ private fun DesktopHandle( splitPaneState: SplitPaneState ) = Box( Modifier - .pointerInput(splitPaneState) { - detectDragGestures { change, _ -> - change.consumeAllChanges() - splitPaneState.dispatchRawMovement( - if (isHorizontal) change.position.x else change.position.y - ) + .run { + val layoutDirection = LocalLayoutDirection.current + pointerInput(splitPaneState) { + detectDragGestures { change, _ -> + change.consume() + splitPaneState.dispatchRawMovement( + if (isHorizontal) + if (layoutDirection == LayoutDirection.Ltr) change.position.x else -change.position.x + else change.position.y + ) + } } } .cursorForHorizontalResize(isHorizontal)