Kotlin UI DSL Version 2
Kotlin UI DSL Version 2 allows creating UI forms with input components bound to state objects. The forms are built by using a declarative Kotlin syntax and follow the official IntelliJ Platform UI conventions described in the IntelliJ Platform UI Guidelines. The library is written in Kotlin and makes it easy to develop user interfaces like 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.
The Kotlin UI DSL Version 2 functions are located in the com.intellij.ui.dsl.builder
package.
UI DSL Examples
It is highly recommended taking a look at the UI DSL demo available via (see Internal Actions if not available in your IDE instance).
It describes some UI DSL basics and contains explanations, tips, a list of all available components, and many examples with links to the source code.
UI DSL Basics
UI DSL Showcase Tab: Basics (Sources: DemoBasics
)
See the following simple example of UI DSL:
Building content of any form starts from panel {
which returns DialogPanel
filled with components described inside the panel block. A panel consists of any number of rows marked with row
tag created vertically from top to bottom.
Every row consists of cells where the last cell in a row occupies the remaining width. Inside one row, cells are added from left to right in the same order calls to factory methods or cell()
appear in each row. Cells can contain one component or a sub-panel.
If there are unoccupied cells at the end of a row, they are merged into one cell with the last non-empty cell.
Panel
Panel
is the start interface for building content. It can consist of several rows and different UI groups.
Panel.row
Adds row with the label if present.
Panel.indent
UI DSL Showcase Tab: Gaps (Sources: DemoGaps
)
Adds standard left indent:
Panel.separator
UI DSL Showcase Tab: Groups (Sources: DemoGroups
)
Adds horizontal line separator with an optional title.
Panel.panel
Creates a sub-panel that occupies the whole width and uses its own grid inside.
Panel.rowsRange
Creates grouped rows range to perform operations on them like enabled
, enabledIf
etc. All rows use the parent grid.
Panel.group
UI DSL Showcase Tab: Groups (Sources: DemoGroups
)
Adds a panel with an independent grid, optional title, and some vertical space above and below the group.
Panel.groupRowsRange
Similar to Panel.group()
method but uses the same grid as the parent.
Panel.collapsibleGroup
UI DSL Showcase Tab: Groups (Sources: DemoGroups
)
Adds collapsible panel with independent grid, title, and some vertical space above and below the group.
Panel.buttonsGroup
UI DSL Showcase Tab: Groups (Sources: DemoGroups
)
Unions Row.radioButton
in one group. Must also be used for Row.checkBox
if these are grouped with some title.
Panel.onApply/onReset/onIsModified
Registers callbacks that will be called from DialogPanel.apply()
/reset()
/isModified()
methods.
Row
Every row is represented by the Row
interface. It contains all available factory methods for creating components (like button()
, label()
, textField()
, etc.) and methods for row configuration.
Row.layout
UI DSL Showcase Tab: Row Layout (Sources: DemoRowLayout
)
There are three possible layouts:
INDEPENDENT
: all cells of the row (including label if present) independent of the parent grid. That means this row has its own grid.LABEL_ALIGNED
: label is aligned with the parent grid, other components independent of the parent grid.PARENT_GRID
: all components, including label (if present), are in the parent grid.
The default value is LABEL_ALIGNED
when a label is provided for the row, INDEPENDENT
otherwise.
Here both labels are aligned together because rows have LABEL_ALIGNED
by default. If an independent layout is needed, then INDEPENDENT
layout should be used:
Row.resizableRow
The row becomes resizable and occupies all vertical free space. For several resizable rows, extra free space is divided between rows equally.
Row.rowComment
UI DSL Showcase Tab: Comments (Sources: DemoComments
)
Adds comment after the row with appropriate color and font. Visibility and enabled state of the row affects row comment as well.
Row.cell
Adds component
. Use it only for custom specific components, all standard components like label()
, button()
, checkbox()
etc. are covered by dedicated Row
factory methods.
For example, there is no method for password field so that the following code can be used:
Row.scrollCell(component)
Adds component
wrapped with JBScrollPane
.
Row.topGap/bottomGap
Adds additional gap above/below the current row. It is visible together with the row. By default, NONE
is used. Between unrelated settings, SMALL
can be used. MEDIUM
is used between groups and usually set automatically by group()
method and similar ones.
Row.visible/enabled
UI DSL Showcase Tab: Enabled/Visible (Sources: DemoAvailability
)
Sets visibility/enabled state of the row, including row comment (see Row.rowComment
) and all children recursively. The row is invisible/disabled if there is an invisible/disabled parent.
Row.visibleIf/enabledIf
UI DSL Showcase Tab: Enabled/Visible (Sources: DemoAvailability
)
Binds row visibility/enabled state to the provided predicate. Below is an example of a checkbox whose enabled state depends on another checkbox:
Row.panel
UI DSL Showcase Tab: Groups (Sources: DemoGroups
)
Creates a sub-panel inside the cell of the row. The panel contains its own set of rows and cells. For example, it is possible to create several columns by creating a row with several panels inside.
Cell
Every component in the UI DSL builder is wrapped into Cell
class. Standard components should not be created directly but with factory methods from Row
class like checkBox()
, button()
and others because of additional functionality, e.g. textField()
is configured with columns width, radio buttons are placed into radio buttons groups.
Cell.component
JComponent
that occupies the cell.
Cell.horizontalAlign/verticalAlign
Sets horizontal/vertical alignment of content inside the cell.
Cell.resizableColumn
UI DSL Showcase Tab: Tips (Sources: DemoTips
)
Marks column of the cell as resizable: the column occupies all extra horizontal space in panel and changes size together with the panel. It's possible to have several resizable columns, which means extra space is shared between them. There is no need to set resizable for cells in different rows but in the same column: it has no additional effect. Note that the size and placement of components in columns are managed by horizontalAlign
.
Cell.gap
UI DSL Showcase Tab: Gaps (Sources: DemoGaps
)
Separates the next cell in the current row with rightGap
. RightGap.SMALL
gap is set after row label automatically by Panel.row()
methods.
Below are some cases where RightGap.SMALL
should be used:
Cell.visible/enabled
UI DSL Showcase Tab: Enabled/Visible (Sources: DemoAvailability
)
Sets visibility/enabled state of the cell and all children recursively. The cell is invisible/disabled if there is an invisible/disabled parent.
Cell.visibleIf/enabledIf
UI DSL Showcase Tab: Enabled/Visible (Sources: DemoAvailability
)
Binds cell visibility/enabled state to the provided predicate.
Cell.comment
UI DSL Showcase Tab: Comments (Sources: DemoComments
)
Adds comment under the cell aligned by left edge with appropriate color and font size (macOS uses smaller font). Comment can contain HTML tags except <html>
, which is added automatically. The comment occupies the available width before the following comment (if present) or the whole remaining width. Visibility and enabled state of the cell affect comment as well.
Cell.label
UI DSL Showcase Tab: Components Labels (Sources: DemoComponentLabels
)
Adds label at the specified position. LabelPosition.TOP
labels occupy available width before the next top label (if present) or the whole remaining width. Visibility and enabled state of the cell affect the label as well.
Cell.onApply/onReset/onIsModified
Registers callbacks that will be called for component from DialogPanel.apply()
/reset()
/isModified()
methods.
Placeholder
Used as a reserved cell in the layout. It can be created by Row.placeholder()
method and populated by content later via component property or reset to null
.
Bindings
It is possible to bind component values to properties with the following methods.
Cell.graphProperty
Binds component
value changing to property. The property is updated when the value is changed and is not related to DialogPanel.apply()
. The method is rarely used directly. There are many extensions for specific components described in Cell.bind.
Cell.bind
UI DSL Showcase Tab: Binding (Sources: DemoBinding
)
Binds component
value that is provided by componentGet
and componentSet
methods to specified binding property. The property is applied only when DialogPanel.apply()
is invoked. Methods DialogPanel.isModified()
and DialogPanel.reset()
are also supported automatically for bound properties.
The bind()
method is rarely used directly. There are many extensions for specific components, see following example:
Version 1 and 2 Comparison
In UI DSL version 2, some crucial problems from version 1 have been fixed, so porting is highly desirable. See Migration from Version 1 on how to port existing UI DSL code from version 1 to version 2 API. Version 1 is deprecated and will be removed in future platform releases.
The following significant changes were made:
Reduced API, which allows conceiving API easier and faster. Example: there were 5 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 mostly based on interfaces, because it's easier to learn API by grouped methods. Only a small part of 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 from Version 1
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 new UI DSL
com.intellij.ui.dsl.builder
suggested by IntelliJ IDEAUpdate non-compilable code, using 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 |
|
|
|
|
|
|
|
|