Writing a component
A widget Blueprint used inside other trees, written in .dui — props, events and emit, default and named slots, and how a host sets, hears and fills them.
A component is a widget Blueprint used inside other trees. Written in .dui, it declares beside its tree what its
hosts (the files that place it) may set, what they may hear, and where they may put widgets of their own:
| Declaration | Offers the host | Compiles into |
|---|---|---|
props { … } | properties to set or bind | Blueprint variables, editable on instances |
events { … } | events to route | event dispatchers |
slot Name | holes to put widgets in | named slots |
A whole component and its host:
// DUI/UI/Components/Row.dui
class /Game/UI/Components/WBP_Row
props {
Text Label
Text Value
Number ValueIndex = 0
}
events {
Picked(Number Index)
}
Widget Root {
+ HorizontalBox { Spacing = 12 }
+ UIButton { OnClick -> emit Picked(ValueIndex) }
Text LabelText {
Text <- Label
@fill
}
Text ValueText { Text <- Value }
}// DUI/UI/Settings.dui
class /Game/UI/WBP_Settings
use "UI/Components/Row.dui" as Row
VerticalBox Root {
Spacing = 8
Row Audio {
Label = "Audio"
Value = "On"
Picked -> HandleAudioPicked
}
Row Track { Label <- GetTrackName() }
}props
class /Game/UI/Components/WBP_Cycle
props {
Text Label
Text Value
Number ValueIndex = 0
Enum /Script/MyGame.ERowKind Kind = Cycle
}
Widget Root {
+ HorizontalBox { }
Text LabelText { Text <- Label }
}One property per line: a type, a name, and optionally = default. The types are Text, String, Number, Integer,
Bool, Color, Vector2, Asset, Class, and Enum followed by the enum's path. Each becomes a Blueprint variable of
the class, editable on instances; a C++ parent's property of the same name and type is used instead of declaring one.
A host sets them like any property, and the component binds them (Text <- Label in the component). A host may bind a
prop as well:
use "UI/Components/Row.dui" as Row
VerticalBox Root {
Row Audio { Label = "Audio" }
Row Track { Label <- GetTrackName() }
}A prop has no setter — it is a Blueprint variable — so the binding writes it straight into the instance when the value
changes and announces it (props are FieldNotify), and the component's own bindings on it show the change. This is the one
setter-less property a binding accepts: a user widget's own variable, one way (<-, not <->).
| Code | When |
|---|---|
| DUI2016 | a line that is not Type Name or Type Name = value, or props inside a node |
| DUI3019 | two lines declare one name |
| DUI6008 | at compile: a type with no Blueprint pin |
| DUI6009 | at compile: a name another member of the class already has with another type, or a widget's id |
| DUI6013 | at compile: a default its type cannot hold |
events and emit
class /Game/UI/Components/WBP_Picker
props {
Number ValueIndex = 0
}
events {
Picked(Number Index)
Closed
}
Widget Root {
+ VerticalBox { }
Widget Choose {
+ UIButton { OnClick -> emit Picked(ValueIndex) }
}
Native.Button Close { OnClicked -> emit Closed }
}Entries end at a line break or a ;, so a short list fits on one line: events { Picked(Number Index); Closed }. Parameter
types are the props' types. Each entry becomes an event dispatcher of the class.
The component raises one from any route with emit, its arguments written as binding expressions (see
Bindings and routes). A host routes it like any event:
use "UI/Components/Picker.dui" as Picker
Widget Root {
+ VerticalBox { }
Picker Audio {
Picked -> HandleAudioPicked
Closed -> HandleClosed
}
}| Code | When |
|---|---|
| DUI2017 | an entry that is not Name or Name(Type Param, …), or events inside a node |
| DUI3020 | two entries of one name, or one parameter twice |
| DUI6010 | emit of an event this file does not declare |
| DUI6011 | emit arguments that do not match the event's parameters |
| DUI6012 | an emit that cannot be compiled where it stands: inside a loop body, or on an event whose parameters Blueprints cannot take |
| DUI6014 | an event named like another member of the class |
Slots
A component opens a hole its host fills with slot:
// DUI/UI/Components/ListPage.dui
class /Game/UI/Components/WBP_ListPage
style DetailPanel {
AnchorData.SizeDelta = (600, 0)
}
HorizontalBox Root {
Spacing = 24
slot Rows default {
+ VerticalBox { Spacing = 15 }
@slot SizeRule = Fill
}
slot Detail : DetailPanel
slot Footer
}- A
slotis written in the tree where the hole goes, and its name shares the space of node ids: two slots of one name are DUI3001 (the old DUI3007 is retired). defaultmarks the slot that content goes to when the host names none, in place of aGetDefaultSlotNameoverride. One per file (DUI3022;defaulttwice on one slot is DUI2019).- A block, or a style, lays the hole out: components, properties and slot lines — never children, since what goes in it is the host's (DUI2019).
- A slot with a layout container takes several widgets; one without takes one.
(was: OldName)renames a slot, as it does a node.
Filling them
A host fills the default slot by nesting, and a named one with a slot block of its own inside the instance:
use "UI/Components/ListPage.dui" as ListPage
use "UI/Components/Row.dui" as Row
Widget Root {
ListPage Page_2 {
Row Item_0 { Label = "Warped Wire" } // into the default slot, Rows
Row Item_1 { Label = "Large Gear" }
slot Detail { // into the slot named Detail
Text Note { Text = "A length of wire bent out of shape." }
}
}
}A fill holds widgets and nothing else. A named slot holds one widget — put several in a container (unless the component declared that slot with a layout container of its own).
| Code | When |
|---|---|
| DUI5019 | slot Name { … } filling a slot under a node that is not a component instance |
| DUI5020 | a fill naming a slot the component does not declare |
| DUI3009 | a parent that will not take this child: a full content widget, a named slot filled twice |
| DUI2019 | a block that both declares and fills |
A widget dropped in the designer into a named slot of an instance is written into that slot's slot Detail { … }, which
is written first when the instance has none. See Designer write-back.
To animate a component inside a panel, use its render transform: RenderTranslationTo, RenderOffsetTo,
RenderScaleTo, RenderAngleTo. They move, scale and turn what is drawn and never the layout; the panel writes the
anchored position and size back on its next pass, so a tween of those is overwritten. See
Animation.
use
Merging a library, giving a component or a class a short name, putting a library under a namespace, aliases that travel with their library, and the older @Name.
Bindings and routes
The three arrows that connect the tree to the class's code — a binding drives a property, a route calls a handler, a two-way binding mirrors a variable — and Shown, which every widget has.