Modifiers

  Edit on GitHub

These docs are for 0.12.0-SNAPSHOT, an unreleased SNAPSHOT. See the latest release.

A Modifier is an ordered chain of changes applied to a Control when it is built, similar to Jetpack Compose modifiers. The built-in modifiers can be found in ModifierExt.

Using Modifiers

Start a chain with Modifier and pass it to any control builder with modifier:

button("Play", modifier = Modifier.expandWidth().minSize(120f, 40f))

Modifiers are applied before the builder’s block, so the block can override them:

button("Play", modifier = Modifier.minSize(120f, 40f)) {
    minWidth = 200f
}

Reusing Modifiers

Store a chain in a val and reuse or extend it:

val primary = Modifier.minSize(120f, 40f).fontColor(Color.WHITE)

button("Play", modifier = primary.expandWidth())
button("Quit", modifier = primary)

Order

Modifiers apply from the outside in. When two modifiers set the same value on one control, the outer (leftmost) one wins. Anything before a wrapper, such as padding, applies to the wrapper and anything after it applies to the control inside:

// expands the padded wrapper
button("Play", modifier = Modifier.expandWidth().padding(8))

// expands the button inside the padded wrapper
button("Play", modifier = Modifier.padding(8).expandWidth())

Wrappers

Wrap the control in another container:

label("Padded", modifier = Modifier.padding(8))
label("Padded", modifier = Modifier.padding(horizontal = 16, vertical = 8))
label("On a panel", modifier = Modifier.panel())
label("On a background", modifier = Modifier.background(FlatDrawable(Color.DARK_GRAY, cornerRadius = 6)))

Layout

Every layout shortcut is also a modifier:

column(modifier = Modifier.fillParent(10f)) {
    button("Play", modifier = Modifier.shrinkCenter(vertical = false))
}

Row & Column Scopes

Children of a row or hBoxContainer get RowScope modifiers: weight shares the free width, align(VAlign) keeps the minimum height and aligns vertically, and fillHeight stretches to the full height:

row {
    label("Name", modifier = Modifier.align(VAlign.CENTER))
    lineEdit(modifier = Modifier.weight(2f))
    button("Save", modifier = Modifier.weight(1f))
}

Children of a column or vBoxContainer get ColumnScope modifiers: weight shares the free height, align(HAlign) aligns horizontally, and fillWidth stretches to the full width:

column {
    label("Title", modifier = Modifier.align(HAlign.CENTER))
    scrollContainer(modifier = Modifier.weight())
    button("Close", modifier = Modifier.align(HAlign.RIGHT))
}

These are only available directly inside that container’s block. A nested column in a row uses its own scope.

Theme Overrides

Override theme values on a single control:

label("Warning", modifier = Modifier.fontColor(Color.RED))

button(
    "Play",
    modifier = Modifier
        .color(Button.themeVars.fontColorDisabled, Color.GRAY)
        .drawable(Button.themeVars.normal, FlatDrawable(Color.DARK_GRAY))
        .font(Button.themeVars.font, myFont)
)

column(modifier = Modifier.constant(BoxContainer.themeVars.separation, 10).theme(myTheme)) {
    label("Tinted", modifier = Modifier.tint(Color.LIGHT_BLUE))
}

Other

button("Hidden", modifier = Modifier.visible(false))
button("Disabled", modifier = Modifier.enabled(false))
panel(modifier = Modifier.mouseFilter(Control.MouseFilter.IGNORE))

Custom Modifiers

Custom modifiers are extension functions on Modifier. Combine existing modifiers:

fun Modifier.card() = panel().padding(8)

Or add a new Modifier.Element with then:

fun Modifier.named(name: String) = then(Modifier.Element { it.name = name })

Use a Modifier.Wrapper to wrap the control in another control:

fun Modifier.framed() = then(Modifier.Wrapper { control -> PanelContainer().apply { addChild(control) } })