DreamGUI
The .dui Language

Worked example

A settings screen built from three files — one row component, a library and the screen — walked through to show which rule of the language each part relies on.

A settings screen built from one row component. Three files: the component; a library that names it and styles the family; and the screen.

WBP_SettingsRow.uasset
WBP_SettingsScreen.uasset
SettingsRow.dui
SettingsLibrary.dui
SettingsScreen.dui

Both Blueprints have UDreamTextUserWidget as their parent, with Source Files Settings/SettingsRow.dui and Settings/SettingsScreen.dui. The library has no root and no Blueprint.

The component: one row

The row — a label on the left, a value with arrows on the right — declares what a host sets and hears:

// DUI/Settings/SettingsRow.dui
class /Game/UI/Settings/WBP_SettingsRow
use "Settings/SettingsLibrary.dui"

props {
    Text   Label
    Text   Value
    Number Index = 0
}
events {
    Changed(Number Index, Number Step)
}

Widget Root : RowBox {
    + HorizontalBox { Padding = (16, 0, 16, 0)  Spacing = 12 }
    + UIButton { TransitionType = None }

    Text LabelText : Caption {
        Text <- Label
        @fill
    }
    Native.Button Previous : Arrow {
        OnClicked -> emit Changed(Index, -1)
        Text { Text = "◀" }
    }
    Text ValueText : Caption {
        Text <- Value
        HAlign = Center
        @slot MinDesiredSize = (220, 0)
    }
    Native.Button Next : Arrow {
        OnClicked -> emit Changed(Index, 1)
        Text { Text = "▶" }
    }
}
  • The class line says it compiles into WBP_SettingsRow. The library's use … as Row reads the class from this line, so it does not need the editor to find the Blueprint.
  • use "Settings/SettingsLibrary.dui" gives the row the library's styles (RowBox, Caption, Arrow). The library uses this file in turn, and that is not a cycle: use … as reads only a component file's header and does not follow its use lines (see use).
  • props declares three Blueprint variables, Label, Value and Index; events declares an event dispatcher, Changed, with two parameters.
  • The root carries a horizontal box and a button behaviour through two + blocks; the RowBox style gives it its height.
  • LabelText binds its text to the prop Label, and @fill gives it the width the row has left. ValueText binds Value and asks for at least 220 of width with a slot line.
  • Each arrow button raises Changed with emit, its arguments binding expressions: Index is the prop, -1 and 1 the step. The Text inside each button has no id; theirs are Previous__Text0 and Next__Text0.

The library: names and styles

The library holds the family's look and its names. Because it has no root it can be used plainly or under a namespace, and its use … as line travels with it:

// DUI/Settings/SettingsLibrary.dui
use "Settings/SettingsRow.dui" as Row

resources {
    Color Ink   = #E6E9F0
    Color Muted = #8C93A6
    Color Panel = #1B1E26
}

style Caption {
    FontSize = 18
    Color    = @Ink
}
style RowBox {
    AnchorData.SizeDelta = (0, 48)
}
style Arrow {
    AnchorData.SizeDelta = (40, 40)
}
style Column {
    + VerticalBox { Spacing = 8 }
    @fill
}
  • use … as Row names the row component. Every screen that uses the library gets that name: Row after a plain use, ui.Row after use … as ui.
  • The three colour resources become variables of every class that imports them. The @Ink in Caption always means this library's Ink, even where the style is used under a namespace.
  • The Column style carries a vertical box and an @fill, so a column is one name (see Styles and resources).

The screen

The screen places three rows, routes each one's Changed to a handler of its own, shows a hint only while there are unsaved changes, and lists the key hints from the class's data:

// DUI/Settings/SettingsScreen.dui
class /Game/UI/Settings/WBP_SettingsScreen
use "Settings/SettingsLibrary.dui" as ui

Widget Root {
    AnchorData.AnchorMin = (0, 0)
    AnchorData.AnchorMax = (1, 1)
    AnchorData.SizeDelta = (0, 0)
    + Overlay { }

    Image Backdrop {
        Brush.TintColor = @ui.Panel
        @slot { HorizontalAlignment = Fill  VerticalAlignment = Fill }
    }

    VerticalBox Page {
        Spacing = 24
        Padding = (64, 48, 64, 48)
        @slot { HorizontalAlignment = Fill  VerticalAlignment = Fill }

        Text Heading : ui.Caption {
            Text = "Settings"
            FontSize = 32
        }

        Widget Rows : ui.Column {
            ui.Row Audio {
                Label = "Master volume"
                Value = "80 %"
                Changed -> HandleVolumeChanged
            }
            ui.Row Display {
                Label = "Display mode"
                Value = "Fullscreen"
                Index = 1
                Changed -> HandleDisplayModeChanged
            }
            ui.Row Language {
                Label = "Language"
                Value = "English"
                Index = 2
                Changed -> HandleLanguageChanged
            }
        }

        if HasUnsavedChanges() {
            Text UnsavedHint : ui.Caption {
                Text = "Unsaved changes"
                Color = @ui.Muted
            }
        }

        HorizontalBox {
            Spacing = 16
            Native.Button Apply { OnClicked -> HandleApply }
            Native.Button Back  { OnClicked -> HandleBack }
            for Hint in KeyHints {
                Text : ui.Caption { Text <- Hint.Label }
            }
        }
    }
}

The rules each part relies on:

  • A namespace. use … as ui keeps the library's names apart from the screen's own: : ui.Caption, @ui.Panel, and the row as ui.Row — the library's own use "Settings/SettingsRow.dui" as Row came along under the namespace. See use.
  • Component instances. ui.Row Audio { … } is an instance of the row: Label, Value and Index set its props — the first values only; a handler changes Value later through the row's variable, Audio — and Changed -> routes the event the row raises with emit from its arrow buttons. See Writing a component.
  • Containers as types. VerticalBox Page and the unnamed HorizontalBox are containers written as node types; their Spacing and Padding are the containers'. The unnamed one's id is Page__HorizontalBox0. See Nodes and values.
  • A style that carries a component. Widget Rows : ui.Column gets its vertical box and its fill from the style.
  • if. The hint shows only while HasUnsavedChanges() is true; nothing is created or destroyed when it flips, only its visibility changes. See if and for.
  • for. One text per item of the class's KeyHints (a FieldNotify array variable of objects with a Label member), after the two buttons; Text <- Hint.Label binds each copy to its item.
  • Backdrop and fill. The root is anchored to all four corners with no inset and carries an Overlay; Backdrop and Page both Fill in both directions through @slot { … }.

What the class supplies

The screen's class supplies these members, in C++ or in the Blueprint's graph:

MemberUsed byNeeds to be
HasUnsavedChangesthe if conditiona function with no parameters returning a bool
KeyHintsthe for sourcea FieldNotify array variable of objects with a Label (DUI6006, DUI6007)
HandleVolumeChanged, HandleDisplayModeChanged, HandleLanguageChangedChanged ->handlers with the event's parameters, (Index, Step) (DUI6004, DUI6005)
HandleApply, HandleBackOnClicked ->handlers with the parameters of the button's OnClicked

The row's class needs nothing written by hand: its props and its event are declared in the .dui and generated at compile.

On this page