From f1b7c33f345ec73cd0b7cb8f8e600805c3dc8c36 Mon Sep 17 00:00:00 2001 From: Fabrizio Scarponi <36624359+fscarponi@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:37:21 +0100 Subject: [PATCH] Rollback to Compose Foundation SplitPane (#10) (cherry picked from commit 461e2d7b0e18e00bd4f08ae585e130bc355da3f4) --- packagesearch.versions.toml | 1 + plugin/build.gradle.kts | 4 ++ .../plugin/ui/PackageSearchMetrics.kt | 11 +++- .../plugin/ui/PackageSearchPackagePanel.kt | 52 +++++++++++++------ .../plugin/ui/bridge/Components.kt | 41 +++++++++++++++ .../plugin/ui/model/ToolWindowViewModel.kt | 17 ++++++ .../packages/PackageSearchCentralPanel.kt | 2 +- .../ui/panels/side/PackageSearchInfoPanel.kt | 2 +- 8 files changed, 111 insertions(+), 19 deletions(-) diff --git a/packagesearch.versions.toml b/packagesearch.versions.toml index 3d6d0ff1..5a21e761 100644 --- a/packagesearch.versions.toml +++ b/packagesearch.versions.toml @@ -39,6 +39,7 @@ jewel-ui = { module = "org.jetbrains.jewel:jewel-ui", version.ref = "jewel" } jewel-foundation = { module = "org.jetbrains.jewel:jewel-foundation", version.ref = "jewel" } jewel-bridge-ij232 = { module = "org.jetbrains.jewel:jewel-ide-laf-bridge", version.ref = "jewel-bridge-232" } jewel-bridge-ij233 = { module = "org.jetbrains.jewel:jewel-ide-laf-bridge", version.ref = "jewel-bridge-233" } +compose-desktop-components-splitpane = { module = "org.jetbrains.compose.components:components-splitpane", version.ref = "composeDesktop" } junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" } diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 2ff10152..087bf7c4 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -50,6 +50,10 @@ val tooling: Configuration by configurations.creating { dependencies { implementation(packageSearchCatalog.kotlinx.serialization.core) + implementation(packageSearchCatalog.compose.desktop.components.splitpane){ + exclude(group = "org.jetbrains.compose.runtime") + exclude(group = "org.jetbrains.compose.foundation") + } implementation(packageSearchCatalog.ktor.client.logging) implementation(packageSearchCatalog.packagesearch.api.models) implementation(projects.plugin.gradle.base) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt index 66d65787..d7b11bb0 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt @@ -19,6 +19,14 @@ object PackageSearchMetrics { metrics.trackPadding.calculateEndPadding(LocalLayoutDirection.current) } + object Splitpane { + + val minWidth: Dp = 300.dp + const val firstSplitterPositionPercentage = .20f + + const val secondSplittePositionPercentage = .80f + } + object Popups { val minWidth: Dp = 50.dp @@ -54,5 +62,4 @@ object PackageSearchMetrics { } } } - -} \ No newline at end of file +} diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt index 62c26228..86143fb4 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt @@ -1,13 +1,23 @@ package com.jetbrains.packagesearch.plugin.ui +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.intellij.ui.JBColor import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule +import com.jetbrains.packagesearch.plugin.ui.bridge.packageSearchSplitter +import com.jetbrains.packagesearch.plugin.ui.model.ToolWindowViewModel import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchCentralPanel import com.jetbrains.packagesearch.plugin.ui.panels.side.PackageSearchInfoPanel import com.jetbrains.packagesearch.plugin.ui.panels.tree.PackageSearchModulesTree -import org.jetbrains.jewel.ui.component.HorizontalSplitLayout +import org.jetbrains.compose.splitpane.HorizontalSplitPane +import org.jetbrains.jewel.bridge.toComposeColor +import org.jetbrains.jewel.foundation.theme.JewelTheme @Composable fun PackageSearchPackagePanel( @@ -16,19 +26,31 @@ fun PackageSearchPackagePanel( onLinkClick: (String) -> Unit, onPackageEvent: (PackageListItemEvent) -> Unit, ) { - HorizontalSplitLayout( - first = { PackageSearchModulesTree(it, onSelectionModulesSelectionChanged) }, - second = { + val toolWindowsViewModel = viewModel() + + val splitPaneState by remember { toolWindowsViewModel.firstSplitPaneState } + val innerSplitPaneState by remember { toolWindowsViewModel.secondSplitPaneState } + val splitterColor by remember(JewelTheme.isDark) { mutableStateOf(JBColor.border().toComposeColor()) } + + HorizontalSplitPane(Modifier.fillMaxSize(), splitPaneState) { + first(PackageSearchMetrics.Splitpane.minWidth) { + PackageSearchModulesTree(Modifier, onSelectionModulesSelectionChanged) + } + packageSearchSplitter(splitterColor) + second { if (isInfoPanelOpen) { - HorizontalSplitLayout( - modifier = it, - initialDividerPosition = 700.dp, - first = { PackageSearchCentralPanel(it, onLinkClick) }, - second = { PackageSearchInfoPanel(it, onLinkClick, onPackageEvent) }, - maxRatio = 0.8f - ) - } else PackageSearchCentralPanel(it, onLinkClick) - }, - minRatio = 0.1f, - ) + HorizontalSplitPane(Modifier.fillMaxSize(), innerSplitPaneState) { + first(PackageSearchMetrics.Splitpane.minWidth) { + PackageSearchCentralPanel(onLinkClick = onLinkClick) + } + packageSearchSplitter(splitterColor) + second(PackageSearchMetrics.Splitpane.minWidth) { + PackageSearchInfoPanel(onLinkClick = onLinkClick, onPackageEvent = onPackageEvent) + } + } + + } else PackageSearchCentralPanel(onLinkClick = onLinkClick) + } + } } + diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt index d583a81e..92198ed7 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt @@ -1,11 +1,17 @@ package com.jetbrains.packagesearch.plugin.ui.bridge +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.PointerIcon +import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily @@ -15,8 +21,11 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp import com.intellij.icons.AllIcons import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics +import java.awt.Cursor +import org.jetbrains.compose.splitpane.SplitPaneScope import org.jetbrains.jewel.foundation.theme.JewelTheme import org.jetbrains.jewel.foundation.theme.LocalTextStyle import org.jetbrains.jewel.ui.component.DropdownLink @@ -130,3 +139,35 @@ internal fun PackageActionPopup( } } } + + + +internal fun SplitPaneScope.packageSearchSplitter( + splitterColor: Color, + cursor: PointerIcon = PointerIcon(Cursor(Cursor.E_RESIZE_CURSOR)), + hidden: Boolean = false, +) { + splitter { + visiblePart { + if (!hidden) { + Box( + modifier = Modifier + .fillMaxHeight() + .width(1.dp) + .background(splitterColor), + ) + } + } + handle { + if (!hidden) { + Box( + modifier = Modifier + .fillMaxHeight() + .width(8.dp) + .markAsHandle() + .pointerHoverIcon(cursor), + ) + } + } + } +} diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt index fe5833e6..928f36f6 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt @@ -1,11 +1,13 @@ package com.jetbrains.packagesearch.plugin.ui.model +import androidx.compose.runtime.mutableStateOf import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message import com.jetbrains.packagesearch.plugin.core.utils.smartModeFlow +import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics import com.jetbrains.packagesearch.plugin.ui.bridge.openLinkInBrowser import com.jetbrains.packagesearch.plugin.ui.model.tree.TreeViewModel import com.jetbrains.packagesearch.plugin.utils.PackageSearchProjectService @@ -18,10 +20,25 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import org.jetbrains.compose.splitpane.SplitPaneState @Service(Level.PROJECT) class ToolWindowViewModel(project: Project, private val viewModelScope: CoroutineScope) { + + val firstSplitPaneState = mutableStateOf( + SplitPaneState( + initialPositionPercentage = PackageSearchMetrics.Splitpane.firstSplitterPositionPercentage, + moveEnabled = true, + ) + ) + val secondSplitPaneState = mutableStateOf( + SplitPaneState( + initialPositionPercentage = PackageSearchMetrics.Splitpane.secondSplittePositionPercentage, + moveEnabled = true, + ) + ) + fun openLinkInBrowser(url: String) { viewModelScope.openLinkInBrowser(url) } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt index bdf64fe1..7d11c0b0 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt @@ -19,7 +19,7 @@ import org.jetbrains.jewel.ui.component.VerticalScrollbar @Composable fun PackageSearchCentralPanel( - modifier: Modifier, + modifier: Modifier = Modifier, onLinkClick: (String) -> Unit, ) = Column(modifier) { val viewModel: PackageListViewModel = viewModel() diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt index 77d69cdf..0a9f4a30 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt @@ -28,7 +28,7 @@ import org.jetbrains.jewel.ui.component.VerticalScrollbar @Composable fun PackageSearchInfoPanel( - modifier: Modifier, + modifier: Modifier = Modifier, onLinkClick: (String) -> Unit, onPackageEvent: (PackageListItemEvent) -> Unit, ) = Box(modifier) {