[python] PY-79486: (WIP) Frontend refactoring.

Get rid of lots of constants, use intrinsic measurement

GitOrigin-RevId: a7a9fbd2ecf75844ceb541f4002d3533b0b97cf6
This commit is contained in:
Ilya.Kazakevich
2025-10-31 07:06:12 +00:00
committed by intellij-monorepo-bot
parent b70eb9df3e
commit a549cbc1ee
2 changed files with 67 additions and 62 deletions
@@ -1,87 +1,54 @@
package com.intellij.python.sdkConfigurator.frontend.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateSet
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.intellij.openapi.util.NlsSafe
import com.intellij.python.sdkConfigurator.common.impl.CreateSdkDTO
import com.intellij.python.sdkConfigurator.common.impl.ModuleName
import com.intellij.python.sdkConfigurator.common.impl.ToolIdDTO
import com.intellij.python.sdkConfigurator.frontend.PySdkConfiguratorFrontendBundle
import kotlinx.collections.immutable.ImmutableMap
import org.jetbrains.annotations.Nls
import org.jetbrains.jewel.foundation.theme.JewelTheme
import org.jetbrains.jewel.ui.component.CheckboxRow
import org.jetbrains.jewel.ui.component.Icon
import org.jetbrains.jewel.ui.component.Text
import org.jetbrains.jewel.ui.component.VerticallyScrollableContainer
import org.jetbrains.jewel.ui.Orientation
import org.jetbrains.jewel.ui.component.*
import org.jetbrains.jewel.ui.icon.IconKey
@Composable
internal fun ModuleList(
moduleItems: ImmutableMap<String, CreateSdkDTO>,
moduleItems: ImmutableMap<ModuleName, CreateSdkDTO>,
icons: ImmutableMap<ToolIdDTO, IconKey>,
checked: SnapshotStateSet<String>,
onCheckChange: (String, Boolean) -> Unit,
onCheck: (ModuleName) -> Unit,
topLabel: @Nls String,
projectStructureLabel: @Nls String,
environmentLabel: @Nls String,
) {
val newText = remember { PySdkConfiguratorFrontendBundle.message("python.sdk.configurator.frontend.choose.modules.new") }
val ts = JewelTheme.defaultTextStyle
val padding = 2.dp
val longestItemChars = remember { (listOf(projectStructureLabel) + moduleItems.keys).maxBy { it.length } }
val leftColumnMinSize = measureText(longestItemChars, ts)
val spaceBetweenCols = 16.dp
Column(Modifier.width(800.dp).padding(padding), verticalArrangement = Arrangement.spacedBy(padding)) {
Text(topLabel, Modifier.padding(bottom = 10.dp))
Row(Modifier, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween) {
Text(projectStructureLabel, Modifier.width(leftColumnMinSize + spaceBetweenCols + padding + 26.dp)) //~ checkbox size
Text(environmentLabel, textAlign = TextAlign.End)
}
val moduleItems = remember { moduleItems.entries.sortedBy { it.key } }
val moduleItems = remember { moduleItems.entries.sortedBy { it.key } }
Box {
VerticallyScrollableContainer {
Column(Modifier, horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.spacedBy(padding)) {
val colPadding = 2.dp
val horizontalArrangement = Arrangement.spacedBy(colPadding)
Column(Modifier.width(IntrinsicSize.Max).height(IntrinsicSize.Max).padding(end = scrollbarContentSafePadding())) {
Text(text = topLabel)
Divider(Orientation.Horizontal, thickness = 5.dp)
Row {
val modifier = Modifier.weight(1f)
Text(projectStructureLabel, modifier = modifier)
Divider(Orientation.Vertical)
Text(environmentLabel, modifier = modifier)
}
Divider(Orientation.Horizontal)
for ((moduleName, moduleInfo) in moduleItems) {
val parent = when (moduleInfo) {
is CreateSdkDTO.ConfigurableModule -> null
is CreateSdkDTO.SameAs -> moduleInfo.parentModuleName
}
Row(Modifier.padding(padding), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(spaceBetweenCols)) {
val checked = moduleName in checked
val elementToChange = parent ?: moduleName // TODO: move logic out of UI
CheckboxRow(
moduleName,
checked = checked,
onCheckedChange = {
onCheckChange(elementToChange, it)
},
textStyle = ts,
textModifier = Modifier.width(leftColumnMinSize)
)
val text = when (moduleInfo) {
is CreateSdkDTO.ConfigurableModule -> {
val text = moduleInfo.existingVersion?.let { PySdkConfiguratorFrontendBundle.message("python.sdk.configurator.frontend.choose.modules.workspace.existing", it) }
?: newText
val icon = icons[moduleInfo.createdByTool]
if (icon != null) {
Icon(icon, text)
}
text
}
is CreateSdkDTO.SameAs -> {
PySdkConfiguratorFrontendBundle.message("python.sdk.configurator.frontend.choose.modules.workspace.member", moduleInfo.parentModuleName)
}
}
Text(text, Modifier.fillMaxWidth())
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = horizontalArrangement) {
Module(moduleName, moduleName in checked, onCheck, colPadding, moduleInfo, icons)
}
}
}
@@ -90,9 +57,46 @@ internal fun ModuleList(
}
@Composable
private fun measureText(text: String, textStyle: TextStyle): Dp {
val textMeasurer = rememberTextMeasurer()
return with(LocalDensity.current) {
textMeasurer.measure(text, textStyle).size.width.toDp()
private fun RowScope.Module(
moduleName: @NlsSafe String,
checked: Boolean,
onCheck: (ModuleName) -> Unit,
columnPadding: Dp,
moduleInfo: CreateSdkDTO,
icons: ImmutableMap<ToolIdDTO, IconKey>,
) {
val colModifier = Modifier.weight(1f)
val newText = remember { PySdkConfiguratorFrontendBundle.message("python.sdk.configurator.frontend.choose.modules.new") }
val parent = when (moduleInfo) {
is CreateSdkDTO.ConfigurableModule -> null
is CreateSdkDTO.SameAs -> moduleInfo.parentModuleName
}
}
val elementToChange = parent ?: moduleName // TODO: move logic out of UI
CheckboxRow(
moduleName,
softWrap = false,
maxLines = 1,
checked = checked,
onCheckedChange = {
onCheck(elementToChange)
},
modifier = colModifier
)
Row(colModifier.padding(start = columnPadding)) {
val text = when (moduleInfo) {
is CreateSdkDTO.ConfigurableModule -> {
val text = moduleInfo.existingVersion?.let { PySdkConfiguratorFrontendBundle.message("python.sdk.configurator.frontend.choose.modules.workspace.existing", it) }
?: newText
val icon = icons[moduleInfo.createdByTool]
if (icon != null) {
Icon(icon, text)
}
text
}
is CreateSdkDTO.SameAs -> {
PySdkConfiguratorFrontendBundle.message("python.sdk.configurator.frontend.choose.modules.workspace.member", moduleInfo.parentModuleName)
}
}
Text(text, Modifier.clickable(onClick = { onCheck(elementToChange) }), maxLines = 1, softWrap = false)
}
}
@@ -46,8 +46,9 @@ internal class ModulesViewModel(modulesDTO: ModulesDTO) {
}
}
fun clicked(what: ModuleName, checkBoxSet: Boolean) {
fun clicked(what: ModuleName) {
val toChange = setOf(what) + children.getOrDefault(what, emptySet())
val checkBoxSet = what !in checked
if (checkBoxSet) {
checked.addAll(toChange)
}