Wizard: fix layout

This commit is contained in:
Ilya Kirillov
2020-03-20 00:02:21 +03:00
parent 9435b386ce
commit e2241aef88
8 changed files with 137 additions and 42 deletions
@@ -70,6 +70,8 @@ abstract class DynamicComponent(private val context: Context) : Component() {
}
abstract class TitledComponent(context: Context) : DynamicComponent(context) {
open val needCentering: Boolean = true
open val maximumWidth: Int? = null
abstract val title: String?
open fun shouldBeShow(): Boolean = true
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.*
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep.modulesEditor.ModulesEditorComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.TitledComponentsList
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.createSettingComponent
import java.awt.Cursor
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import javax.swing.JComponent
@@ -52,7 +53,9 @@ class ProjectSettingsComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizar
projectTemplateComponent,
buildSystemSetting
),
context
context,
stretchY = true,
useBigYGap = true
).asSubComponent()
override val component: JComponent by lazy(LazyThreadSafetyMode.NONE) {
@@ -63,8 +66,6 @@ class ProjectSettingsComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizar
row {
buildSystemAdditionalSettingsComponent.component(growX)
}
}.apply {
border = JBUI.Borders.empty(10)
}
}
@@ -152,10 +153,24 @@ private class PomSettingsComponent(context: Context) : TitledComponentsList(
StructurePlugin::artifactId.reference.createSettingComponent(context),
StructurePlugin::version.reference.createSettingComponent(context)
),
context
context,
stretchY = true
)
class KotlinJpsRuntimeComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizard.context) {
private val componentList = TitledComponentsList(
listOf(
JdkComponent(ideWizard),
KotlinRuntimeComponentComponent(ideWizard)
),
ideWizard.context,
stretchY = true
).asSubComponent()
override val component: JComponent = componentList.component
}
private class JdkComponent(ideWizard: IdeWizard) : TitledComponent(ideWizard.context) {
private val javaModuleBuilder = JavaModuleBuilder()
private val jdkComboBox = JdkComboBox(
ProjectSdksModel().apply { reset(null) },
@@ -166,14 +181,14 @@ class KotlinJpsRuntimeComponent(ideWizard: IdeWizard) : DynamicComponent(ideWiza
ideWizard.jpsData.jdk = selectedJdk
}
}
override val component: JComponent = panel {
row("Project JDK:") {
borderPanel { addToCenter(jdkComboBox) }.addBorder(JBUI.Borders.empty(0, 7))(growX)
}
row("Kotlin Runtime:") {
ideWizard.jpsData.libraryOptionsPanel.simplePanel(growX)
}
}
override val title: String = "Project JDK"
override val component: JComponent = jdkComboBox
}
private class KotlinRuntimeComponentComponent(ideWizard: IdeWizard) : TitledComponent(ideWizard.context) {
override val title: String = "Kotlin Runtime"
override val component: JComponent = ideWizard.jpsData.libraryOptionsPanel.simplePanel
}
@Suppress("SpellCheckingInspection")
@@ -182,6 +197,7 @@ private class HideableSection(text: String, private var component: JComponent) :
private var isExpanded = false
init {
titledSeparator.label.cursor = Cursor(Cursor.HAND_CURSOR)
updateComponent(component)
titledSeparator.addMouseListener(object : MouseAdapter() {
override fun mouseReleased(e: MouseEvent) = update(!isExpanded)
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.tools.projectWizard.projectTemplates.ProjectTemplate
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.*
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.ValidationIndicator
import java.awt.BorderLayout
import javax.swing.JComponent
class ProjectTemplateSettingComponent(
@@ -23,6 +22,7 @@ class ProjectTemplateSettingComponent(
context
) {
override val validationIndicator: ValidationIndicator? get() = null
override val needCentering: Boolean = false
private val templateDescriptionComponent = TemplateDescriptionComponent().asSubComponent()
private val list = ImmutableSingleSelectableListWithIcon(
@@ -37,7 +37,7 @@ class ProjectTemplateSettingComponent(
override val component: JComponent = borderPanel {
addToCenter(borderPanel { addToCenter(list) }.addBorder(JBUI.Borders.empty(0,/*left*/ 3, 0, /*right*/ 3)))
addToBottom(templateDescriptionComponent.component.addBorder(JBUI.Borders.empty(/*top*/5,/*left*/ 3, 0, 0)))
addToBottom(templateDescriptionComponent.component.addBorder(JBUI.Borders.empty(/*top*/8,/*left*/ 3, /*bottom*/10, 0)))
}
private fun applySelectedTemplate() = modify {
@@ -7,6 +7,7 @@ import com.intellij.ui.ColoredListCellRenderer
import com.intellij.ui.SimpleTextAttributes
import com.intellij.ui.ToolbarDecorator
import com.intellij.ui.popup.PopupFactoryImpl
import com.intellij.util.ui.JBUI
import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.withAllSubModules
@@ -22,6 +23,8 @@ class ModuleDependenciesComponent(
) : TitledComponent(context) {
override val title: String = "Module dependencies"
private val dependenciesList = ModuleDependenciesList()
override val needCentering: Boolean = false
override val maximumWidth: Int = 500
private val toolbarDecorator: ToolbarDecorator = ToolbarDecorator.createDecorator(dependenciesList).apply {
setToolbarPosition(ActionToolbarPosition.BOTTOM)
@@ -72,6 +75,7 @@ class ModuleDependenciesComponent(
override val component: JPanel = toolbarDecorator.createPanelWithPopupHandler(dependenciesList).apply {
preferredSize = Dimension(preferredSize.width, 200)
addBorder(JBUI.Borders.empty(0, 3))
}
}
@@ -1,6 +1,5 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep
import com.intellij.util.ui.JBUI
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.Reader
@@ -15,7 +14,6 @@ import org.jetbrains.kotlin.tools.projectWizard.templates.Template
import org.jetbrains.kotlin.tools.projectWizard.templates.settings
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.TitledComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.borderPanel
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components.DropDownComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components.TextFieldComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.TitledComponentsList
@@ -29,10 +27,7 @@ class ModuleSettingsComponent(
private val settingsList = TitledComponentsList(emptyList(), context).asSubComponent()
private val moduleDependenciesComponent = ModuleDependenciesComponent(context)
override val component: JComponent = borderPanel {
addToCenter(settingsList.component)
border = JBUI.Borders.empty(20)
}
override val component: JComponent = settingsList.component
var module: Module? = null
set(value) {
@@ -1,5 +1,6 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep
import com.intellij.util.ui.JBUI
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
@@ -9,6 +10,10 @@ import org.jetbrains.kotlin.tools.projectWizard.wizard.IdeWizard
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.*
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep.modulesEditor.ModulesEditorComponent
import java.awt.BorderLayout
import java.awt.Dimension
import javax.swing.Box
import javax.swing.BoxLayout
import javax.swing.JPanel
class SecondStepWizardComponent(
wizard: IdeWizard,
@@ -1,20 +1,24 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting
import com.intellij.ui.layout.panel
import com.intellij.util.ui.components.BorderLayoutPanel
import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingReference
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.FocusableComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.TitledComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.*
import javax.swing.JComponent
import javax.swing.Spring
import javax.swing.SpringLayout
open class TitledComponentsList(
private var components: List<TitledComponent>,
private val context: Context
context: Context,
private val stretchY: Boolean = false,
private val globalMaxWidth: Int? = null,
useBigYGap: Boolean = false,
) : DynamicComponent(context) {
private val ui = BorderLayoutPanel()
private val yGap = if (useBigYGap) yGapBig else yGapSmall
init {
ui.addToCenter(createComponentsPanel(components))
}
@@ -37,23 +41,92 @@ open class TitledComponentsList(
ui.addToCenter(createComponentsPanel(newComponents))
}
private fun createComponentsPanel(components: List<TitledComponent>) = customPanel(SpringLayout()) {
if (components.isEmpty()) return@customPanel
val layout = this.layout as SpringLayout
fun setSettings(settings: List<SettingReference<*, *>>) {
setComponents(
settings.map { setting ->
DefaultSettingComponent.create(setting, context, needLabel = false)
fun JComponent.constraints() = layout.getConstraints(this)
val componentsWithLabels = components.mapNotNull { component ->
if (!component.shouldBeShow()) return@mapNotNull null
val label = label(component.title?.let { "$it:" }.orEmpty())
TitledComponentData(
label.also { add(it) }.constraints(),
component.component.also { add(it) }.constraints(),
component.needCentering,
component.maximumWidth
)
}
fun TitledComponentData.centerConstraint() =
if (needCentering) component.height * .5f - label.height * .5f
else 4.asSpring()
val labelWidth = componentsWithLabels.fold(componentsWithLabels.first().label.width) { spring, row ->
Spring.max(spring, row.label.width)
}
componentsWithLabels.forEach { (label, component, _, componentMaxWidth) ->
label.width = labelWidth
val maxWidth = componentMaxWidth ?: globalMaxWidth
if (maxWidth == null) {
component[SpringLayout.EAST] = layout.getConstraint(SpringLayout.EAST, this) - xPanelPadding.asSpring()
} else {
component.width = maxWidth.asSpring()
}
)
}
var lastLabel: SpringLayout.Constraints? = null
var lastComponent: SpringLayout.Constraints? = null
for (data in componentsWithLabels) {
val (label, component) = data
label.x = xPanelPadding.asSpring()
component.x = label[SpringLayout.EAST] + xGap
if (lastComponent != null && lastLabel != null) {
val constraint = lastComponent[SpringLayout.SOUTH] + yGap
label.y = constraint + data.centerConstraint()
component.y = constraint
} else {
label.y = data.centerConstraint() + yPanelPadding
component.y = yPanelPadding.asSpring()
}
lastLabel = label
lastComponent = component
}
if (stretchY) {
constraints()[SpringLayout.SOUTH] = lastComponent!![SpringLayout.SOUTH] + yGap
}
}
companion object {
private fun createComponentsPanel(components: List<TitledComponent>) = panel {
components.forEach { component ->
if (!component.shouldBeShow()) return@forEach
row(component.title?.let { "$it:" }.orEmpty()) {
component.component(growX)
}
}
}
private const val xGap = 5
private const val yGapSmall = 6
private const val yGapBig = 12
private const val xPanelPadding = 16
private const val yPanelPadding = 16
}
}
private data class TitledComponentData(
val label: SpringLayout.Constraints,
val component: SpringLayout.Constraints,
val needCentering: Boolean,
val maximumWidth: Int?,
)
}
private operator fun Spring.plus(other: Spring) = Spring.sum(this, other)
private operator fun Spring.plus(gap: Int) = Spring.sum(this, Spring.constant(gap))
private operator fun Spring.minus(other: Spring) = this + Spring.minus(other)
private operator fun Spring.unaryMinus() = Spring.minus(this)
private operator fun Spring.times(by: Float) = Spring.scale(this, by)
private fun Int.asSpring() = Spring.constant(this)
private operator fun SpringLayout.Constraints.get(edgeName: String) = getConstraint(edgeName)
private operator fun SpringLayout.Constraints.set(edgeName: String, spring: Spring) {
setConstraint(edgeName, spring)
}
@@ -35,12 +35,12 @@ import javax.swing.event.DocumentEvent
import javax.swing.event.DocumentListener
internal inline fun label(text: String, bold: Boolean = false, init: JBLabel.() -> Unit = {}) = JBLabel().apply {
font = UIUtil.getButtonFont().deriveFont(if (bold) Font.BOLD else Font.PLAIN)
font = UIUtil.getLabelFont().deriveFont(if (bold) Font.BOLD else Font.PLAIN)
this.text = text
init()
}
inline fun customPanel(layout: LayoutManager = BorderLayout(), init: JPanel.() -> Unit = {}) = JPanel(layout).apply(init)
inline fun customPanel(layout: LayoutManager? = BorderLayout(), init: JPanel.() -> Unit = {}) = JPanel(layout).apply(init)
inline fun borderPanel(init: BorderLayoutPanel.() -> Unit = {}) = BorderLayoutPanel().apply(init)