Kotlin UI DSL Version 1
Kotlin UI DSL allows creating UI forms with input components bound to state objects. The forms are built by using a declarative Kotlin syntax. It shares similarities with Jetpack Compose for Android and is intended to build UI forms or part of forms for, e.g. dialogs and settings pages.
The Kotlin UI DSL is not intended to build general UIs, like tool windows controls that trigger some actions and do not contain any input components bound to state objects. For this purpose, use custom Swing components from the IntelliJ Platform or the standard ones.
This document covers the Kotlin UI DSL in IntelliJ Platform 2019.2. A lot of the features described in this document are not available for plugins targeting earlier versions.
The Kotlin UI DSL Version 1 functions are located in the com.intellij.ui.layout
package.
Layout Structure
Use panel
to create UI:
Rows are created vertically from top to bottom, in the same order as lines of code that call row
. Inside one row, you add components from left to right in the same order calls to factory method or ()
appear in each row. Every component is effectively placed in its own grid cell.
The label for the row can be specified as a parameter for the row
method:
Rows can be nested. Components in a nested row block are considered to be subordinate to the containing row and are indented accordingly.
To put multiple components in the same grid cell, wrap them in a cell
method:
To put a component on the right side of a grid row, use the right
method:
Adding Components
There are two ways to add child components. The recommended way is to use factory methods label
, button
, radioButton
, link
, etc. It allows you to create consistent UI and reuse common patterns.
These methods also support property bindings, allowing you to automatically load the value displayed in the component from a property and to store it back. The easiest way to do that is to pass a reference to a Kotlin bound property:
Note that the bound property reference syntax also can be used to reference Java fields, but not getter/setter pairs.
Alternatively, many factory methods support specifying a getter/setter pair for cases when a property mapping is more complicated:
If you want to add a component for which there are no factory methods, you can simply invoke an instance of your component, using the ()
overloaded operator:
Supported Components
Labels
Use the label
method:
Checkboxes
See examples above.
Radio Buttons
Radio button groups are created using the buttonGroup
block. There are two ways to use it. If the selected radio button corresponds to a specific value of a single property, pass the property binding to the buttonGroup
method and the specific values to radioButton
functions:
If the selected radio button is controlled by multiple boolean properties, use buttonGroup
with no binding and specify property bindings for all but one of the radio buttons:
Text Fields
Use the textField
method for a simple text field:
For entering numbers, use intTextField
:
For password text fields, there is no factory function available, so you need to use ()
:
To specify the size of a text field, either pass the columns
parameter as shown in the intTextField
example above, or use growPolicy()
:
Combo Boxes
Use the comboBox
method with either a bound property, or a getter/setter pair:
Spinners
Use the spinner
method:
Link Label
Use the link
method:
To open URL in the browser, use browserLink
:
Separators
Use the titledRow
method and put the controls under the separator into the nested block:
Explanatory Text
Use the comment
parameter:
Integrating Panels with Property Bindings
A panel returned by the panel
method is an instance of DialogPanel
. This base class supports the standard apply()
, reset()
, and isModified()
methods.
Dialogs
Reference: DialogWrapper
If you're using a DialogPanel
as the main panel of a DialogWrapper
, the apply()
method will be automatically called when the dialog is closed using OK action. The other methods are unused in this case.
Use the focused()
method to specify which control should be focused when the dialog is initialized:
Configurables
Reference: Settings Guide
If you're using the UI DSL to implement a Configurable
, use BoundConfigurable
as the base class. In this case, the Configurable
methods will be automatically delegated to the panel.
Enabling and Disabling Controls
Use the enableIf
method to bind the enabled state of a control to the values entered in other controls. The parameter of the method is a predicate.
The available predicates are:
selected
to check the selected state of a checkbox or radio buttonselectedValueIs
andselectedValueMatches
to check the selected item in a combo box.
Predicates can be combined with and
and or
infix functions:
Examples
Sample usages in IntelliJ Platform IDEs:
User Interface | Implementation |
---|---|
New Branch dialog in Git (Manage Git branches) | |
FAQ
One Cell Is Minimum, Second One Is Maximum
Set CCFlags.growX
and CCFlags.pushX
for some component in the second cell.
Comparison with Kotlin UI DSL Version 2
The new Kotlin UI DSL fixes some crucial problems from version 1. See Migration to Version 2 on how to port existing UI DSL code from version 1 to the new version.
The following significant changes were made:
Reduced API, which allows conceiving API easier and faster. Example: there were five overloaded methods
Cell.checkBox()
in version 1, now only one method remains. Functionality for binding properties is extracted intoCell<T>.bindSelected()
methods.UI DSL became stricter, so the available API in every context is much smaller. Example: code like
row { row {
is forbidden now.Structured API is mostly based on interfaces because it's easier to learn API by grouped methods. Only a small part of the API is implemented as extensions.
KDoc is widely used.
MIG layout is fully removed from the new UI DSL and replaced by
GridLayout
. Because MIG layout is an external library, it's hard to fix bugs there (e.g., there are layout problems when components become invisible) and extend its functionality. Fixed focus ring cropping problems: when components are placed near the panel border focus ring could be cropped if panel insets do not specify enough space.Implemented Placeholder that allows replacing components at runtime after content is shown.
Migration to Version 2
The new API is very similar to the old one and covers almost all functionality now, so moving to the new version can be done quickly.
Version 1 is placed in com.intellij.ui.layout
package.
Version 2 is placed in com.intellij.ui.dsl.builder
package.
Migration Steps
Having a screenshot or live version of the initial components layout can help
Remove imports of old UI DSL starting with
com.intellij.ui.layout
Go to the place where the panel is created and import the new UI DSL
com.intellij.ui.dsl.builder
suggested by IntelliJ IDEAUpdate non-compilable code, according to the following table.
Version 1 | Version 2 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| For previous left cell use |
| Please do not use custom gaps if possible |
| Not needed, this gap is set by default |
|
|
|
|
|
|
|
|