DreamGUI
The .dui Language

rows tables

Many instances of one component as a table — the type, the style and the property names written once, one line per instance, each named from its first value.

A settings page or a list of menu entries is mostly the same component N times, differing in a few values. rows writes that as a table: the type, the style and the property names are written once, then one line per instance.

class /Game/UI/WBP_Map
use "UI/NieR_Common.dui"

Widget Root {
    ListPage Page_0 : PageSize {
        Icon = @IconMap
        rows Row : ListRow (Label, Description) {
            "City Ruins",      "The overgrown remains of a city. The Resistance camp lies to the east."
            "Desert Zone",     "Sand and wind as far as the eye can see."
            "Factory",         "An abandoned factory, still running somewhere deep inside." { Kind = Count }
        }
    }
}

Except for where the ids come from (below), that is the same tree as three unnamed Row : ListRow { … } written where the table stands:

class /Game/UI/WBP_Map
use "UI/NieR_Common.dui"

Widget Root {
    ListPage Page_0 : PageSize {
        Icon = @IconMap
        Row : ListRow { Label = "City Ruins"   Description = "The overgrown remains of a city. The Resistance camp lies to the east." }
        Row : ListRow { Label = "Desert Zone"  Description = "Sand and wind as far as the eye can see." }
        Row : ListRow {
            Label = "Factory"
            Description = "An abandoned factory, still running somewhere deep inside."
            Kind = Count
        }
    }
}

Nothing runs at run time: the table is read into those widgets, so a row is a widget like any other — it builds, binds and lays out exactly as the line it stands for would.

since 1.0.0

The header

The header is rows, a node type (a tag, a container, an alias, @Name, a path), an optional : Style, and the columns: property names, dotted or not, in parentheses. Each is written once (DUI2020; the comparison ignores case, so two names that differ only in case are one property).

Rows

A row is its values, in column order, separated by commas — any value a property takes: a string, a number, a tuple, a colour, a word, @Resource. One row per line, or several on a line separated by ;:

style Swatch { AnchorData.SizeDelta = (48, 48) }

HorizontalBox Palette {
    Spacing = 8
    rows Image : Swatch (Brush.TintColor, AnchorData.SizeDelta) {
        #E6E9F0, (48, 48); #8C93A6, (48, 48)
        #1B1E26, (64, 48)
    }
}
  • A row has exactly as many values as there are columns (DUI2020). A row that does not read makes no widget: one short of a value would be built with whatever the style or the class default says, and one with a value too many has dropped something the author wrote. Either would be a guess.
  • A missing comma between two values ("A" "B") is reported as the syntax error it is (DUI2001), not as a wrong count.
  • Values are written, not bound: a column is =, never <-.

A block at the end of a row

A row may end in a block ({ Kind = Count } above) holding what that one row needs beyond the columns: more properties, @slot lines, + components, children. A line in it that names a column wins over the cell.

Ids come from the first value

Each row's id is made from its first value, the row's key: <id of the enclosing node>__<type>_<key>, the key with every run of characters an id cannot hold made one _, none left at either end, and cut to 32 characters. The three rows of the first example are Page_0__Row_City_Ruins, Page_0__Row_Desert_Zone and Page_0__Row_Factory.

A row inserted or moved therefore leaves every other row's id where it was, and the localization keys made from it (Page_0__Row_City_Ruins.Label) with it.

  • Two rows whose keys make the same id are told so (DUI3023, a warning): the second gets _1, which does move when rows are reordered. Give the rows distinct first values.
  • A key nothing of which an id can hold ("--", say, or a tuple) is counted like any unnamed node.
  • The type is cleaned the same way: nier.Row reads nier_Row.
rows Row : ListRow (Label) {
    "City Ruins"
    "City-Ruins"
}

Written inside Page_0, the second line also makes Page_0__Row_City_Ruins, so it is DUI3023 and becomes Page_0__Row_City_Ruins_1.

Code that needs a row by name writes that row as a node of its own.

Where rows is a keyword

rows is a keyword only before a type and a column list: a property called rows, or a node whose type is, reads as it always did.

The designer and the editor

The designer writes a column's value back into its cell, and the lines of a row's own block are written as any lines are. The row's line spells only its columns, so anything else — naming a row, giving it a + block, removing or moving it, placing a node beside the table — is refused with the reason (DUI7004); see Designer write-back.

The VS Code extension reads a table as the compiler does: one unnamed widget per line, named from its first value, with DUI2020 for a table that does not read and DUI3023 for two rows whose keys collide. The formatter keeps each row on its line and keeps the author's column alignment.

On this page