diff --git a/components/SplitPane/build.gradle.kts b/components/SplitPane/build.gradle.kts deleted file mode 100644 index b309717036..0000000000 --- a/components/SplitPane/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -import org.jetbrains.compose.compose - -plugins { - kotlin("multiplatform") - id("org.jetbrains.compose") -} - -kotlin { - jvm { - withJava() - } - sourceSets { - named("jvmMain") { - dependencies { - implementation(compose.desktop.currentOs) - implementation(project("common")) - } - } - } -} - diff --git a/components/SplitPane/desktop/build.gradle.kts b/components/SplitPane/demo/build.gradle.kts similarity index 86% rename from components/SplitPane/desktop/build.gradle.kts rename to components/SplitPane/demo/build.gradle.kts index 565fbfc0d0..7244dff140 100644 --- a/components/SplitPane/desktop/build.gradle.kts +++ b/components/SplitPane/demo/build.gradle.kts @@ -1,29 +1,29 @@ -import org.jetbrains.compose.compose -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - kotlin("multiplatform") - id("org.jetbrains.compose") -} - -kotlin { - jvm {} - sourceSets { - named("jvmMain") { - dependencies { - implementation(compose.desktop.currentOs) - implementation(project(":SplitPane:common")) - } - } - } -} - -compose.desktop { - application { - mainClass = "org.jetbrains.compose.splitpane.demo.MainKt" - } -} - -tasks.withType().configureEach { - kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" +import org.jetbrains.compose.compose +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("multiplatform") + id("org.jetbrains.compose") +} + +kotlin { + jvm {} + sourceSets { + named("jvmMain") { + dependencies { + implementation(compose.desktop.currentOs) + implementation(project(":SplitPane:library")) + } + } + } +} + +compose.desktop { + application { + mainClass = "org.jetbrains.compose.splitpane.demo.MainKt" + } +} + +tasks.withType().configureEach { + kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" } \ No newline at end of file diff --git a/components/SplitPane/desktop/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt b/components/SplitPane/demo/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt similarity index 97% rename from components/SplitPane/desktop/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt rename to components/SplitPane/demo/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt index c5afd70c3c..3bfbc5d128 100644 --- a/components/SplitPane/desktop/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt +++ b/components/SplitPane/demo/src/jvmMain/kotlin/org/jetbrains/compose/splitpane/demo/Main.kt @@ -1,91 +1,91 @@ -package org.jetbrains.compose.splitpane.demo - -import androidx.compose.desktop.DesktopTheme -import androidx.compose.desktop.LocalAppWindow -import androidx.compose.desktop.Window -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.width -import androidx.compose.material.MaterialTheme -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.composed -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.input.pointer.pointerMoveFilter -import androidx.compose.ui.unit.dp -import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi -import org.jetbrains.compose.splitpane.HorizontalSplitPane -import org.jetbrains.compose.splitpane.VerticalSplitPane -import org.jetbrains.compose.splitpane.rememberSplitPaneState -import java.awt.Cursor - -private fun Modifier.cursorForHorizontalResize( -): Modifier = composed { - var isHover by remember { mutableStateOf(false) } - - if (isHover) { - LocalAppWindow.current.window.cursor = Cursor(Cursor.E_RESIZE_CURSOR) - } else { - LocalAppWindow.current.window.cursor = Cursor.getDefaultCursor() - } - - pointerMoveFilter( - onEnter = { isHover = true; true }, - onExit = { isHover = false; true } - ) -} - -@OptIn(ExperimentalSplitPaneApi::class) -fun main() = Window( - "SplitPane demo" -) { - MaterialTheme { - DesktopTheme { - val splitterState = rememberSplitPaneState() - val hSplitterState = rememberSplitPaneState() - HorizontalSplitPane( - splitPaneState = splitterState - ) { - first(20.dp) { - Box(Modifier.background(Color.Red).fillMaxSize()) - } - second(50.dp) { - VerticalSplitPane(splitPaneState = hSplitterState) { - first(50.dp) { - Box(Modifier.background(Color.Blue).fillMaxSize()) - } - second(20.dp) { - Box(Modifier.background(Color.Green).fillMaxSize()) - } - } - } - 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() - ) - } - } - } - } - } +package org.jetbrains.compose.splitpane.demo + +import androidx.compose.desktop.DesktopTheme +import androidx.compose.desktop.LocalAppWindow +import androidx.compose.desktop.Window +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.width +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.input.pointer.pointerMoveFilter +import androidx.compose.ui.unit.dp +import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi +import org.jetbrains.compose.splitpane.HorizontalSplitPane +import org.jetbrains.compose.splitpane.VerticalSplitPane +import org.jetbrains.compose.splitpane.rememberSplitPaneState +import java.awt.Cursor + +private fun Modifier.cursorForHorizontalResize( +): Modifier = composed { + var isHover by remember { mutableStateOf(false) } + + if (isHover) { + LocalAppWindow.current.window.cursor = Cursor(Cursor.E_RESIZE_CURSOR) + } else { + LocalAppWindow.current.window.cursor = Cursor.getDefaultCursor() + } + + pointerMoveFilter( + onEnter = { isHover = true; true }, + onExit = { isHover = false; true } + ) +} + +@OptIn(ExperimentalSplitPaneApi::class) +fun main() = Window( + "SplitPane demo" +) { + MaterialTheme { + DesktopTheme { + val splitterState = rememberSplitPaneState() + val hSplitterState = rememberSplitPaneState() + HorizontalSplitPane( + splitPaneState = splitterState + ) { + first(20.dp) { + Box(Modifier.background(Color.Red).fillMaxSize()) + } + second(50.dp) { + VerticalSplitPane(splitPaneState = hSplitterState) { + first(50.dp) { + Box(Modifier.background(Color.Blue).fillMaxSize()) + } + second(20.dp) { + Box(Modifier.background(Color.Green).fillMaxSize()) + } + } + } + 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() + ) + } + } + } + } + } } \ No newline at end of file diff --git a/components/SplitPane/common/build.gradle.kts b/components/SplitPane/library/build.gradle.kts similarity index 77% rename from components/SplitPane/common/build.gradle.kts rename to components/SplitPane/library/build.gradle.kts index d9a373bd93..2a41478d7f 100644 --- a/components/SplitPane/common/build.gradle.kts +++ b/components/SplitPane/library/build.gradle.kts @@ -1,27 +1,34 @@ -import org.jetbrains.compose.compose -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - kotlin("multiplatform") - id("org.jetbrains.compose") -} - -kotlin { - jvm("desktop") - - sourceSets { - named("commonMain") { - dependencies { - api(compose.runtime) - api(compose.foundation) - api(compose.material) - } - } - named("desktopMain") {} - } -} - -// TODO it seems that argument isn't applied to the common sourceSet. Figure out why -tasks.withType().configureEach { - kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" -} \ No newline at end of file +import org.jetbrains.compose.compose +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("multiplatform") + id("org.jetbrains.compose") + id("maven-publish") +} + +kotlin { + jvm("desktop") + + sourceSets { + named("commonMain") { + dependencies { + api(compose.runtime) + api(compose.foundation) + api(compose.material) + } + } + named("desktopMain") {} + } +} + +// TODO it seems that argument isn't applied to the common sourceSet. Figure out why +tasks.withType().configureEach { + kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" +} + +configureMavenPublication( + groupId = "org.jetbrains.compose.components", + artifactId = "components-splitpane", + name = "SplitPane for Compose JB" +) \ No newline at end of file diff --git a/components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/ExperimentalSplitPaneApi.kt b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/ExperimentalSplitPaneApi.kt similarity index 100% rename from components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/ExperimentalSplitPaneApi.kt rename to components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/ExperimentalSplitPaneApi.kt diff --git a/components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPane.kt b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPane.kt similarity index 100% rename from components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPane.kt rename to components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPane.kt diff --git a/components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneDSL.kt b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneDSL.kt similarity index 100% rename from components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneDSL.kt rename to components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneDSL.kt diff --git a/components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneState.kt b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneState.kt similarity index 100% rename from components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneState.kt rename to components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/SplitPaneState.kt diff --git a/components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/Splitter.kt b/components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/Splitter.kt similarity index 100% rename from components/SplitPane/common/src/commonMain/kotlin/org/jetbrains/compose/splitpane/Splitter.kt rename to components/SplitPane/library/src/commonMain/kotlin/org/jetbrains/compose/splitpane/Splitter.kt diff --git a/components/SplitPane/common/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt b/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt similarity index 97% rename from components/SplitPane/common/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt rename to components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt index 67c61e9f8e..65451e440e 100644 --- a/components/SplitPane/common/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt +++ b/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitPane.kt @@ -1,141 +1,141 @@ -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 - -@OptIn(ExperimentalSplitPaneApi::class) -@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 splitterSize = splitterPlaceable.valueByDirection(isHorizontal) - val secondPlaceablePosition = constrainedPosition + splitterSize - - 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 handleSize = handlePlaceable.valueByDirection(isHorizontal) - // TODO support RTL - val handlePosition = when (splitter.alignment) { - SplitterHandleAlignment.BEFORE -> constrainedPosition + splitterSize - handleSize - SplitterHandleAlignment.ABOVE -> constrainedPosition + (splitterSize - handleSize) / 2 - SplitterHandleAlignment.AFTER -> constrainedPosition - } - - 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) - } - } - } - } - } - } +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 + +@OptIn(ExperimentalSplitPaneApi::class) +@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 splitterSize = splitterPlaceable.valueByDirection(isHorizontal) + val secondPlaceablePosition = constrainedPosition + splitterSize + + 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 handleSize = handlePlaceable.valueByDirection(isHorizontal) + // TODO support RTL + val handlePosition = when (splitter.alignment) { + SplitterHandleAlignment.BEFORE -> constrainedPosition + splitterSize - handleSize + SplitterHandleAlignment.ABOVE -> constrainedPosition + (splitterSize - handleSize) / 2 + SplitterHandleAlignment.AFTER -> constrainedPosition + } + + 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) + } + } + } + } + } + } } \ No newline at end of file diff --git a/components/SplitPane/common/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt b/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt similarity index 96% rename from components/SplitPane/common/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt rename to components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt index ac73a834d1..8e7ce35a3f 100644 --- a/components/SplitPane/common/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt +++ b/components/SplitPane/library/src/desktopMain/kotlin/org/jetbrains/compose/splitpane/DesktopSplitter.kt @@ -1,101 +1,101 @@ -package org.jetbrains.compose.splitpane - -import androidx.compose.desktop.LocalAppWindow -import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.detectDragGestures -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.width -import androidx.compose.material.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.composed -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.consumeAllChanges -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.input.pointer.pointerMoveFilter -import androidx.compose.ui.unit.dp -import java.awt.Cursor - -private fun Modifier.cursorForHorizontalResize( - isHorizontal: Boolean -): Modifier = composed { - var isHover by remember { mutableStateOf(false) } - - if (isHover) { - LocalAppWindow.current.window.cursor = Cursor( - if (isHorizontal) Cursor.E_RESIZE_CURSOR else Cursor.S_RESIZE_CURSOR - ) - } else { - LocalAppWindow.current.window.cursor = Cursor.getDefaultCursor() - } - pointerMoveFilter( - onEnter = { isHover = true; true }, - onExit = { isHover = false; true } - ) -} - -@Composable -private fun DesktopSplitPaneSeparator( - isHorizontal: Boolean, - color: Color = MaterialTheme.colors.background -) = Box( - Modifier - .run { - if (isHorizontal) { - this.width(1.dp) - .fillMaxHeight() - } else { - this.height(1.dp) - .fillMaxWidth() - } - } - .background(color) -) - -@OptIn(ExperimentalSplitPaneApi::class) -@Composable -private fun DesktopHandle( - isHorizontal: Boolean, - splitPaneState: SplitPaneState -) = Box( - Modifier - .pointerInput(splitPaneState) { - detectDragGestures { change, _ -> - change.consumeAllChanges() - splitPaneState.dispatchRawMovement( - if (isHorizontal) change.position.x else change.position.y - ) - } - } - .cursorForHorizontalResize(isHorizontal) - .run { - if (isHorizontal) { - this.width(8.dp) - .fillMaxHeight() - } else { - this.height(8.dp) - .fillMaxWidth() - } - } -) - -@OptIn(ExperimentalSplitPaneApi::class) -internal actual fun defaultSplitter( - isHorizontal: Boolean, - splitPaneState: SplitPaneState -): Splitter = Splitter( - measuredPart = { - DesktopSplitPaneSeparator(isHorizontal) - }, - handlePart = { - DesktopHandle(isHorizontal, splitPaneState) - } -) - +package org.jetbrains.compose.splitpane + +import androidx.compose.desktop.LocalAppWindow +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.detectDragGestures +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.consumeAllChanges +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.input.pointer.pointerMoveFilter +import androidx.compose.ui.unit.dp +import java.awt.Cursor + +private fun Modifier.cursorForHorizontalResize( + isHorizontal: Boolean +): Modifier = composed { + var isHover by remember { mutableStateOf(false) } + + if (isHover) { + LocalAppWindow.current.window.cursor = Cursor( + if (isHorizontal) Cursor.E_RESIZE_CURSOR else Cursor.S_RESIZE_CURSOR + ) + } else { + LocalAppWindow.current.window.cursor = Cursor.getDefaultCursor() + } + pointerMoveFilter( + onEnter = { isHover = true; true }, + onExit = { isHover = false; true } + ) +} + +@Composable +private fun DesktopSplitPaneSeparator( + isHorizontal: Boolean, + color: Color = MaterialTheme.colors.background +) = Box( + Modifier + .run { + if (isHorizontal) { + this.width(1.dp) + .fillMaxHeight() + } else { + this.height(1.dp) + .fillMaxWidth() + } + } + .background(color) +) + +@OptIn(ExperimentalSplitPaneApi::class) +@Composable +private fun DesktopHandle( + isHorizontal: Boolean, + splitPaneState: SplitPaneState +) = Box( + Modifier + .pointerInput(splitPaneState) { + detectDragGestures { change, _ -> + change.consumeAllChanges() + splitPaneState.dispatchRawMovement( + if (isHorizontal) change.position.x else change.position.y + ) + } + } + .cursorForHorizontalResize(isHorizontal) + .run { + if (isHorizontal) { + this.width(8.dp) + .fillMaxHeight() + } else { + this.height(8.dp) + .fillMaxWidth() + } + } +) + +@OptIn(ExperimentalSplitPaneApi::class) +internal actual fun defaultSplitter( + isHorizontal: Boolean, + splitPaneState: SplitPaneState +): Splitter = Splitter( + measuredPart = { + DesktopSplitPaneSeparator(isHorizontal) + }, + handlePart = { + DesktopHandle(isHorizontal, splitPaneState) + } +) + diff --git a/components/VideoPlayer/build.gradle.kts b/components/VideoPlayer/build.gradle.kts deleted file mode 100644 index 6791fc786b..0000000000 --- a/components/VideoPlayer/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -import org.jetbrains.compose.compose - -plugins { - kotlin("multiplatform") - id("org.jetbrains.compose") -} - -kotlin { - jvm { - withJava() - } - sourceSets { - named("jvmMain") { - dependencies { - implementation(compose.desktop.currentOs) - implementation(project("common")) - } - } - } -} - diff --git a/components/VideoPlayer/desktop/build.gradle.kts b/components/VideoPlayer/demo/build.gradle.kts similarity index 86% rename from components/VideoPlayer/desktop/build.gradle.kts rename to components/VideoPlayer/demo/build.gradle.kts index b7aa9ce738..a63186dec3 100644 --- a/components/VideoPlayer/desktop/build.gradle.kts +++ b/components/VideoPlayer/demo/build.gradle.kts @@ -11,7 +11,7 @@ kotlin { named("jvmMain") { dependencies { implementation(compose.desktop.currentOs) - implementation(project(":VideoPlayer:common")) + implementation(project(":VideoPlayer:library")) } } } diff --git a/components/VideoPlayer/desktop/src/jvmMain/kotlin/org/jetbrains/compose/videoplayer/demo/Main.kt b/components/VideoPlayer/demo/src/jvmMain/kotlin/org/jetbrains/compose/videoplayer/demo/Main.kt similarity index 100% rename from components/VideoPlayer/desktop/src/jvmMain/kotlin/org/jetbrains/compose/videoplayer/demo/Main.kt rename to components/VideoPlayer/demo/src/jvmMain/kotlin/org/jetbrains/compose/videoplayer/demo/Main.kt diff --git a/components/VideoPlayer/common/build.gradle.kts b/components/VideoPlayer/library/build.gradle.kts similarity index 100% rename from components/VideoPlayer/common/build.gradle.kts rename to components/VideoPlayer/library/build.gradle.kts diff --git a/components/VideoPlayer/common/src/commonMain/kotlin/org/jetbrains/compose/videoplayer/VideoPlayer.kt b/components/VideoPlayer/library/src/commonMain/kotlin/org/jetbrains/compose/videoplayer/VideoPlayer.kt similarity index 100% rename from components/VideoPlayer/common/src/commonMain/kotlin/org/jetbrains/compose/videoplayer/VideoPlayer.kt rename to components/VideoPlayer/library/src/commonMain/kotlin/org/jetbrains/compose/videoplayer/VideoPlayer.kt diff --git a/components/VideoPlayer/common/src/desktopMain/kotlin/org/jetbrains/compose/videoplayer/DesktopVideoPlayer.kt b/components/VideoPlayer/library/src/desktopMain/kotlin/org/jetbrains/compose/videoplayer/DesktopVideoPlayer.kt similarity index 100% rename from components/VideoPlayer/common/src/desktopMain/kotlin/org/jetbrains/compose/videoplayer/DesktopVideoPlayer.kt rename to components/VideoPlayer/library/src/desktopMain/kotlin/org/jetbrains/compose/videoplayer/DesktopVideoPlayer.kt diff --git a/components/build.gradle.kts b/components/build.gradle.kts index ea0d3feec9..e1ad7a7bfd 100644 --- a/components/build.gradle.kts +++ b/components/build.gradle.kts @@ -1,6 +1,5 @@ buildscript { - // __LATEST_COMPOSE_RELEASE_VERSION__ - val composeVersion = System.getenv("COMPOSE_RELEASE_VERSION") ?: "0.4.0" + val composeVersion = property("compose.version") repositories { google() @@ -15,10 +14,37 @@ buildscript { } } -allprojects { +subprojects { + version = findProperty("deploy.version") ?: property("compose.version")!! + repositories { google() mavenCentral() maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") } -} + + plugins.withId("java") { + configureIfExists { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + + withJavadocJar() + withSourcesJar() + } + } + + plugins.withId("maven-publish") { + configureIfExists { + repositories { + maven { + name = "ComposeRepo" + setUrl(System.getenv("COMPOSE_REPO_URL")) + credentials { + username = System.getenv("COMPOSE_REPO_USERNAME") + password = System.getenv("COMPOSE_REPO_KEY") + } + } + } + } + } +} \ No newline at end of file diff --git a/components/buildSrc/build.gradle.kts b/components/buildSrc/build.gradle.kts new file mode 100644 index 0000000000..d079322b30 --- /dev/null +++ b/components/buildSrc/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + `kotlin-dsl` +} + +repositories { + gradlePluginPortal() +} + +dependencies { + compileOnly(gradleApi()) +} diff --git a/components/buildSrc/settings.gradle.kts b/components/buildSrc/settings.gradle.kts new file mode 100644 index 0000000000..c665ff9667 --- /dev/null +++ b/components/buildSrc/settings.gradle.kts @@ -0,0 +1,5 @@ +pluginManagement { + repositories { + gradlePluginPortal() + } +} diff --git a/components/buildSrc/src/main/kotlin/CommonMavenProperties.kt b/components/buildSrc/src/main/kotlin/CommonMavenProperties.kt new file mode 100644 index 0000000000..311bd0f8cf --- /dev/null +++ b/components/buildSrc/src/main/kotlin/CommonMavenProperties.kt @@ -0,0 +1,32 @@ +import org.gradle.api.Project +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.kotlin.dsl.configure + +fun Project.configureMavenPublication( + groupId: String, + artifactId: String, + name: String +) { + extensions.configure { + publications { + all { + this as MavenPublication + + this.groupId = groupId + mppArtifactId = artifactId + + pom { + this.name.set(name) + url.set("https://github.com/JetBrains/compose-jb") + licenses { + license { + this.name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + } + } + } + } +} \ No newline at end of file diff --git a/components/buildSrc/src/main/kotlin/GradleUtils.kt b/components/buildSrc/src/main/kotlin/GradleUtils.kt new file mode 100644 index 0000000000..7766857210 --- /dev/null +++ b/components/buildSrc/src/main/kotlin/GradleUtils.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. + */ + +import org.gradle.api.Project +import org.gradle.api.publish.maven.MavenPublication +import java.lang.UnsupportedOperationException + +inline fun Project.configureIfExists(fn: T.() -> Unit) { + extensions.findByType(T::class.java)?.fn() +} + +var MavenPublication.mppArtifactId: String + get() = throw UnsupportedOperationException() + set(value) { + val target = this.name + artifactId = if ("kotlinMultiplatform" in target) value else "$value-$target" + } \ No newline at end of file diff --git a/components/gradle.properties b/components/gradle.properties index a9d5d0bc15..3e1cd60f44 100644 --- a/components/gradle.properties +++ b/components/gradle.properties @@ -1,4 +1,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 android.useAndroidX=true android.enableJetifier=true -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official + +# __LATEST_COMPOSE_RELEASE_VERSION__ +compose.version=0.4.0 \ No newline at end of file diff --git a/components/settings.gradle.kts b/components/settings.gradle.kts index 473b5f6a63..90feb6f2ca 100644 --- a/components/settings.gradle.kts +++ b/components/settings.gradle.kts @@ -1,4 +1,4 @@ -include(":VideoPlayer:common") -include(":VideoPlayer:desktop") -include(":SplitPane:common") -include(":SplitPane:desktop") \ No newline at end of file +include(":VideoPlayer:library") +include(":VideoPlayer:demo") +include(":SplitPane:library") +include(":SplitPane:demo") \ No newline at end of file diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt index cfd6a25d30..c54571f70c 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt @@ -123,6 +123,8 @@ class ComposePlugin : Plugin { } object DesktopDependencies { + val components = DesktopComponentsDependencies + val common = composeDependency("org.jetbrains.compose.desktop:desktop") val linux_x64 = composeDependency("org.jetbrains.compose.desktop:desktop-jvm-linux-x64") val windows_x64 = composeDependency("org.jetbrains.compose.desktop:desktop-jvm-windows-x64") @@ -150,6 +152,10 @@ class ComposePlugin : Plugin { } } + object DesktopComponentsDependencies { + val splitPane = composeDependency("org.jetbrains.compose.components:components-splitpane") + } + object WebDependencies { val core by lazy { composeDependency("org.jetbrains.compose.web:web-core")