The language
Files
Events can also run inline scripts. File-level scriptLanguage: "lua" selects Lua; JavaScript is the default when omitted. See Inline scripts.
A file may contain any number of these definitions in any order:
| Top level | |
|---|---|
Dialog Name { ... } |
A dialog with its own size (size); the application opens its frame |
Screen Name { ... } |
The contents of a page; the application supplies the page and its geometry |
component Name : Basistyp { ... } |
A reusable element |
record Name { typ feld ... } |
An application data type, for example a list row |
- Comments:
//and/* */. - Separators: Statements end at a newline or
;. Line breaks are allowed inside(),[]and? :. - Visibility: Components and records are shared by all files in the same
aura_add_uiinvocation (or the same loader directory, including subdirectories). File names must be unique even across directories, because generated C++ files are named after them.
Elements
Typ [id] {
property: wert
Kind { ... }
}
- Type: A built-in type (table below), an application type (
aura-elements.json, see below) or a component. id: The name other expressions use to access the element, and its field name in the application's struct. Withoutname, the ID also becomes itsobjectName. Reserved names areroot,parent,theme,screen,propsandself.- Children are drawn above earlier siblings.
| Type | aura-ui | Type-specific properties |
|---|---|---|
Item |
Node |
– |
Rect |
RectNode |
color, radius, corners: topLeft, topRight, bottomRight, bottomLeft, border: width, color, gradient: top, bottom |
Text |
TextNode |
text, font: family, size[, weight], weight, color, align: left|center|right[, top|center|bottom], wrap: width[, alignment], fit: true|minimumSize, lineHeight (QML factor), letterSpacing (px), pixelSize/minimumPixelSize (px, bypassing Context::fontSize), underline |
Image |
ImageNode |
source: "name.png" (Context::image) or image: value (an application image of type image), fill: stretch|crop|fit|pad, radius, corners |
Svg |
SvgNode |
source: "name.svg", fill: color |
Scroll |
ScrollNode |
contentHeight, contentY; horizontal with direction: horizontal: contentWidth, contentX. When a horizontal scroll is nested inside a vertical one, the direction of the finger decides which scrolls |
QrCode |
QrCodeNode |
text (contents), color |
Html |
HtmlNode |
text (HTML like QML RichText), font: family, size, color, lineHeight, margin (documentMargin); without height, its height follows the text at its given width |
Column |
ColumnNode |
spacing, padding, align: left|center|right, justify; stacks visible children from the top and grows to their combined height (see Layouts) |
Row |
RowNode |
spacing, padding, align: top|center|bottom, justify, wrap: true, direction: leftToRight|rightToLeft; arranges visible children from the left and grows to their combined width, or arranges them from its right edge |
Grid |
GridNode |
columns, spacing, padding, cell: width, height; cells take the size of the first visible child (or cell); height follows the rows |
Popover |
PopoverNode |
color, markerPos, unfold (visible fraction of the height, 0–1; enter: unfold 0 300 linear unfolds it); a speech bubble with a marker at the top |
Ripple |
RippleNode |
color (gray), opacity (0.4), size (200 × 200); feedback for its parent: appears under the finger when pressed and pulses (1 ↔ 1.1, 500 ms each way), grows to four times its size over 500 ms after a tap, then runs the parent's onTap (immediately without an animator). Place it last to draw it on top; the parent clips its children (clip) |
TextField |
TextFieldNode (aura/ui/text_input.h) |
text (initial value, see Text input), font, weight, color, align, letterSpacing, pixelSize, placeholder, placeholderColor (#cccccc), masked (* per character), maxLength (characters), characters (allowed characters, e.g. "0123456789*#"), focus: true, onChange: signal, onAccept: signal; a single line with a caret, clips and scrolls to keep the caret visible |
Keyboard |
KeyboardNode (aura/ui/text_input.h) |
layout: "DE" (CZ, DE, DK, EN, FI, FR, NL, NO, PL, SE, SI, SK, also lowercase; "alphanum": 800 × 240, digits and uppercase letters, Backspace, OK, Cancel), color, radius, border, keyColor, textColor, accentColor (modifier keys), okColor, cancelColor, cancelText, okKey: false, onOk: signal, onCancel: signal; an on-screen keyboard, 960 × 300, scaled to its own size |
Button |
ButtonNode (aura/ui/controls.h) |
text, font, weight, textColor (white), color (#404040), pressedColor (otherwise a darker color), radius (8), border; a button with centered text, default size 200 × 60 (see Controls) |
CheckBox |
CheckBoxNode |
text, font, textColor, color (box), radius, checked, onToggle: signal; tapping toggles it |
Switch |
SwitchNode |
Like CheckBox, plus trackColor (off); a sliding switch, color (on) |
RadioButton |
RadioButtonNode |
Like CheckBox, plus group; tapping selects it and clears the others in the same group (without group: its siblings). Only the newly selected button emits onToggle |
ComboBox |
ComboBoxNode |
options (list of strings), index (-1: none), placeholder, font, textColor, color, radius, border, listColor, listTextColor, selectedColor, visibleRows (6), onSelect: signal; tapping opens a list below it, above the entire scene (or above the control if there is no room below); tapping outside closes it |
Slider |
SliderNode |
value, from (0), to (1), step, color, trackColor, onChange: signal; drag or tap the track |
ProgressBar |
ProgressBarNode |
value, from (0), to (1), color, trackColor, radius (half its height) |
Rive |
RiveNode |
source: "goodbye.riv" (Context::file); loops the default state machine of the default artboard (otherwise its first animation) through the animator, fitted like PreserveAspectFit |
WebView |
aura::webview::WebViewNode (libaura-webview) |
url, script (JavaScript, run in each page before its own scripts); Chromium through CEF, touch input, WebChannel to C++ (aura.call, aura.on). Only in applications with AURA_WITH_WEBVIEW; see aura-webview.md |
Application element types: An aura-elements.json beside or above the .aura files that use them describes elements drawn by the application:
The following example describes an application-provided BadgeNode, not a built-in AURA element.
{
"Badge": {
"type": "BadgeNode",
"header": "widgets/badge_node.h",
"properties": {
"color": {"type": "color"},
"label": {"type": "string", "set": "setLabel()"}
}
}
}
- Properties:
typeisnumber,string,boolorcolor. Generated code sets the member of the same name, or the one specified byset; ifsetends in(), it calls the function. - Consumers:
aurac(the nearest file above each.aurafile, or--elements),aura_add_ui(as a dependency), the loader (all files in its directory),aura-viewand the VS Code extension (validation, completion). - Dynamic mode: This tells the loader about the properties, but it can create and configure the type only after the application registers it (
aura::ui::registerElementType). Otherwise it reports “not part of this program” and uses the compiled version.
All elements also have:
| Property | Meaning |
|---|---|
name |
objectName (remote control, logs); defaults to the ID |
x, y, width, height, size: w, h |
Geometry |
place: ... |
Anchors; see below |
visible, opacity, rotation, scale, clip, glow |
As in aura-ui (clip clips to a rectangle, like Qt Quick; glow glows white, e.g. glow: root.pressed) |
onTap: signal, onTap: signal(args), onTap: ignore |
Emits a signal or consumes the tap |
enabled: false |
Disables input for the element and its children (QML enabled); controls dim themselves |
grow: weight |
In a Column/Row: a share of the free space along the layout direction (QML Layout.fillHeight/fillWidth) |
stretch: true |
In a Column/Row: fills across the layout direction (width or height); fills its cell in a Grid |
minWidth, maxWidth, minHeight, maxHeight |
Limits for grow and stretch (0: none) |
onSettled: signal |
An element animation (animate:) reached its target; see Animations |
pressSink: offset, ms |
Sinks when pressed |
spin: ms |
Spins clockwise indefinitely, one revolution per ms (service menu gear) |
loop: property from to ms [easing] [pause ms], … |
Oscillates indefinitely between two values; see Animations |
Text in detail:
- Font family: Without
font, usesaura::ui::TextNode::defaultFamily, set by the application at startup; if empty, uses the font collection's default. - Font size:
fontandfit: Npass through the application'sContext::fontSize()(default: unchanged).pixelSizesets pixels directly, bypassing this function. - Natural size: A
Textwithoutwidth/height/sizetakes its content's size. Withwrap: 400, its width is 400 and its height follows the text. - Rich text like QML StyledText:
<b>,<br />and<font color="#rrggbb">.
Anchors (place)
place: left 44, below title 30, centerY -20 becomes aura::ui::place(node).left(44).below(*title, 30).centerY(-20) (see graphics.md). Order matters.
| Directive | Meaning |
|---|---|
left, right, top, bottom [gap] |
Relative to the parent's edge |
centerX, centerY [offset], center |
Centered in the parent, rounded |
below, above, rightOf, leftOf element [gap] |
Beside an element |
alignLeft, alignTop, alignBottom element [offset] |
Aligned to an element |
centerXOn, centerYOn element |
Relative to an element's center |
Valid elements are IDs defined earlier in the source (siblings or ancestors), parent, and id[index] for repeated elements, e.g. centerYOn field[0].
Layouts: Column, Row, Grid
Layouts arrange their visible children when a child is added. If a child changes later (through a binding or rebuilding), they rearrange. Their own size follows the content (Column: height; left-to-right Row: width; Grid: height), so other elements can refer to it:
Scroll list {
size: parent.width - 4, min(len(lines), 5) * 76
contentHeight: productRows.height // nach dem Bau der Zeilen
Column productRows {
width: parent.width
repeat line, i in lines { CartRow { index: i; line: line } }
}
}
// Header: rechtsbündig
Row buttons { direction: rightToLeft; spacing: 16; size: parent.width, 60 }
// Grid layout
Grid cells { columns: columns; spacing: 10 }
Invisible children take no space. Children set their own size; the layout assigns their position along its direction (Column: y; Row: x; Grid: both).
Flexible: These properties let a layout distribute space instead of just stacking:
Column {
size: 400, parent.height
padding: 20 // 1 Wert, 2 (oben/unten, links/rechts) oder 4 (oben, rechts, unten, links)
spacing: 10
align: center // quer: left, center, right (Row: top, center, bottom)
Text { text: tr("Title", "Titel") }
Scroll { grow: 1 } // nimmt die restliche Höhe
Row {
stretch: true // so breit wie die Column (ohne padding)
height: 60
justify: spaceBetween // start, center, end, spaceBetween, spaceAround, spaceEvenly
DialogButton { text: "Zurück" }
DialogButton { text: "Weiter"; grow: 1; maxWidth: 300 }
}
}
Row tags { width: 500; wrap: true; spacing: 8 } // bricht in Zeilen um (QML Flow), wird so hoch wie sie
- Length: If a child has
groworjustifyis set, the layout keeps its height (Column) or width (Row) and distributes it: children withoutgrowfirst get their sizes and the gaps; growing children share the remainder by weight (limited bymin…/max…). Otherwise it grows to its content, as before. - Across: Without
align,stretchandpaddingon this axis, children keep theirx(Column) ory(Row), as before. Otherwise the layout sets it; a layout without a width (height) then takes that of its widest (tallest) child. - Content follows: If a layout resizes an element with
groworstretch(or a component instance), its descendants' properties run again (size: parent.width - 4,place: right), then nested layouts rearrange. In C++,Node::resize()sets the size and callsonResized. wrap(Rowwith a width only): Places children in lines, withspacingbetween lines too;alignandjustifyapply to each line.
Expressions
| Values | Numbers (internally double, as in QML), "Text" (with \n, \t, \b), colors #rrggbb/#aarrggbb, true/false, lists [a, b] |
| Operators | + - * / %, == != < > <= >=, && || !, a ? b : c; + also concatenates strings |
| Names | IDs (defined earlier), parent, own geometry (x, y, width, height, implicitWidth, implicitHeight), loop variables, dialog or component property declarations (also as root.<name>) |
| Element values | id.x, .y, .width, .height, .opacity, .rotation, .scale, .pressed, .implicitWidth/.implicitHeight (Text; Image: image size; Html: height), .contentHeight (Scroll) |
| Records | zeile.feld, liste[i].feld, root.zeile.feld |
| Lists | liste[i], len(liste), e.g. ["", "ABC", "DEF"][i] |
| Context | theme.<name>, screen.width, screen.height, props.bool("ID"), props.int("ID"), props.string("ID") |
| Functions | tr("id", "Deutsch"), str(zahl), replace(text, alt, neu), lower(text), upper(text), len(liste|text), fontSize(px) (Context::fontSize), ceil, floor, round, abs, min, max, range(n) |
Types are checked: a string where a number is required, or a field absent from a record, causes the build to fail.
Repetition and conditions
repeat key, index in ["1", "2", "\b"] {
Item keyItem { x: index % 3 * 94; onTap: keyPressed(key) }
}
repeat i in range(6) { Rect field { x: digitsX + i * 54 } }
repeat line, i in lines { CartRow row { line: line } }
if key == "\b" { Svg { ... } } else { Text { ... } }
-
List: A list in square brackets,
range(n), astringsproperty or a list of records. -
IDs in a repetition become vectors in the struct (
std::vector<aura::ui::RectNode*> field). Outside the loop, access them withfield[0]. -
IDs under
ifarenullptrin the struct while the branch is not built. Properties that wait for their own children (see below) must not reference children underif. -
State: If the list or condition depends on state, changing it rebuilds the block (see Rebuilding).
-
lazy:repeat p, i in photos lazy { … }builds only visible entries, for long lists (thousands of photos on a phone):qmlScroll grid { size: parent.width, parent.height contentHeight: cells.height Grid cells { columns: 4 spacing: 10 cell: 240, 180 // Pflicht: jede Zelle gleich groß width: parent.width repeat p, i in photos lazy { PhotoCell cell { photo: p; stretch: true; onTap: pick(i) } } } }- Where: Directly in a
Gridwithcell: width, height(columns: 1for a list), inside a verticalScroll; one element per entry, not inside another repetition. - What gets built: The rows in the visible area of the
Scroll, plus one row before and after. Scrolling builds new entries and removes the others (deleted before the next frame; their bindings end). TheGridplaces each entry in the cell for its index and has the height of all rows, socontentHeight: cells.heightremains correct. - IDs:
ui->cellhas one slot per list entry,nullptrfor unbuilt entries. The application attaches additions (images) to newly built cells inui->onRebuilt(cells without their additions), and discards pointers to removed cells. - State: As with any repetition: changing the list retains equal entries; other entries are rebuilt when visible.
- Where: Directly in a
Property order
Each element follows this order, just like the earlier handwritten code:
- Content (text, colors, font, …),
- natural text size,
- geometry (
x,y,width,height,size,place,contentHeight) in source order.
This is why height: back.y - 30 - y works after place: left 44, below editBox 30.
References to own children: A property referring to an ID in its own subtree is applied only once that child is built, immediately afterwards. Later children already see the value:
component PriceRow : Rect {
height: topicText.height + 12 // nach topicText
Text topicText { wrap: 290 }
Text { place: right 15, centerY } // sieht die Zeilenhöhe
}
Pressed state
A property referring to id.pressed is reevaluated whenever that state changes. All descendants of id are reevaluated too, so anchors follow:
Item keyItem {
onTap: keyPressed(key)
Rect face {
x: keyItem.pressed ? 5 : 0
width: parent.width - (keyItem.pressed ? 8 : 0)
Text { size: parent.width, parent.height } // folgt dem Rect
}
}
id itself is not rearranged, since that would reset a pressSink, for example. Components can also use root.pressed (key, footer button).
Text input
TextField code {
font: theme.textFont, 48
placeholder: tr("Voucher_Code", "Gutscheincode")
maxLength: 20
focus: true
size: 400, 60
onChange: codeChanged // signal codeChanged(string text)
onAccept: redeem // Enter
}
Rect ok { onTap: redeem(code.text) }
Keyboard {
layout: props.string("CurrentLanguage") // "de", "EN", ...; unbekannt: DE
place: centerX, bottom 20
onOk: redeem(code.text)
onCancel: close
}
- Focus: Keys go to the focused element, otherwise to
Application::onKeyas before. Tapping aTextFieldfocuses it and places the caret at the tapped position. Tapping elsewhere (for example an on-screen keyboard key) leaves focus where it is.focus: truegives focus during construction; in C++, useNode::focus()/Node::clearFocus(). If the element is invisible or deleted, keys return toonKey. - Keys: Characters insert at the caret (up to
maxLength), Backspace and Delete remove characters, ←/→ move the caret, and Enter triggersonAccept. The field does not consume Escape, Tab, ↑/↓; they pass through toonKey. Input comes from the window keyboard, remote control (Application::injectKey) andKeyboard(aura::ui::sendKey). text: The initial value. If the binding reevaluates (another property on the element depends on state), typed text is retained; only a changed value replaces it (bindValue). The application reads text withui->code->value()and sets it withsetValue()(withoutonChange).id.textreturns the current text of aTextField(orText) in expressions, for example as a signal argument. Properties referring to aTextField'sfeld.textrun again after each keystroke (visible: len(code.text) > 0), as with a state property.- Signals:
onChange(after each typed change) andonAcceptpass the text to a signal with astringparameter; a parameterless signal receives nothing.onChange: changed(code.text)also works.KeyboardhasonOkandonCancel. - Keyboard: Four rows of character keys with up to eight mappings (normal, Shift, Ctrl =
*#+@, Alt =éàóand combinations). Shift, Ctrl and Alt remain active until tapped again. No images are needed: the keyboard draws its own symbols (Backspace, Enter, Shift, Space). - Blink: The caret blinks every 500 ms (without an animation; the main loop redraws every 500 ms while idle anyway). For screenshots and tests,
aura::ui::TextFieldNode::blink = falsekeeps it permanently visible.
Controls
Column {
padding: 24
spacing: 16
CheckBox agb { text: tr("Agb", "AGB gelesen"); checked: accepted; onToggle: accept } // signal accept(bool on)
Slider { from: 0; to: 100; step: 5; value: volume; onChange: setVolume } // signal setVolume(real v)
ProgressBar { value: uploaded; to: total; stretch: true }
Button { text: tr("Next", "Weiter"); color: theme.mainColor; enabled: agb.checked; onTap: next }
}
- Selection:
RadioButton { group: "format"; checked: format == "a"; onToggle: chooseA }for a few visible choices;ComboBox { options: formats; index: chosen; onSelect: choose }(signal withint) for many. - State: Like
textonTextField,checked,indexandvalueare initial values: the user's setting remains until the bound value changes (bindChecked,bindValue).id.checked,id.index(ComboBox) andid.valuereturn the current setting in expressions; properties referring to them follow each user change (enabled: agb.checked,text: str(volume.value)). - Signals:
onTogglepasses the new state to a signal with aboolparameter; aSlider'sonChangepasses its value to arealparameter (only when changed, including dragging); parameterless signals receive nothing.Buttonuses the commononTap. - Appearance: Neutral gray; applications style controls through properties or a component, e.g.
component MainButton : Button { color: theme.mainColor; font: theme.textFont, 24 }.Ripple,pressSinkandglowwork as on any element. enabledaffects every element and all its children: no taps or dragging.- How changes propagate:
TextField,CheckBox,SwitchandSliderwith an ID report every user change (Node::onEdited) under the binding key@id, before their own signal. This applies to individual elements, not IDs inside arepeat.
Dialog and screen
Dialog OrderStatusDialog {
property strings digits // Argument der App (Zustand)
const real digitsX: 140 // Konstante
signal keyPressed(string key)
size: 860, 600
...
}
size: w, h(dialog only): The frame size. The application queries it usingName::size(ctx, args); arguments may appear in it.- Screen: Has no geometry. It can set its page's appearance (
color,border,radius,gradient,opacity), e.g.color: theme.white. signal name/signal name(string key, int index): Application events. Parameter types arestring,real,int,boolandcolor;realandintarrive in C++ asdouble.property type name[: expression]: An application argument and mutable state with a setter, with an optional default value. It appears inNameArgs, passed tosize()andbuild().const type name: expression: A constant available throughout the dialog, with no setter or instance argument (e.g.const int limit: 5). This also applies to screens and components.- Defaults: A
propertydefault is evaluated once during construction when no argument was supplied; it is not a persistent binding. Explicit values such as0,false, or""override it. Later changes use the setter.
Property types: real, int, bool, string, color, image (an application image, sk_sp<SkImage> in C++; may be empty), strings (a list of strings, std::vector<std::string> in C++), a record and Datensatz[] (a list).
Components
component DialogButton : Rect {
property string text // Argument der Instanz (": wert": Standard)
color: theme.mainColor
radius: 4
pressSink: 4, 250
Text {
text: root.text
fit: true
align: center, center
size: parent.width, parent.height
}
}
component LanguageButton : Rect {
property string language
signal select // eigenes Signal der Komponente
onTap: select
...
}
- Base type: One of the built-in types.
property: An instance argument, optionally with a default, and component state (setter in the struct).- Forwarding signals:
onToggle: toggleContraston an instance emits the enclosing dialog'stoggleContrastsignal when the component emitstoggle, with the same parameters.onToggle: picked("x")oronEdit: edit(i)passes custom arguments. - Instance order (
DialogButton noButton { ... }): The component root's properties apply first, then the instance's (which win); only then are the component's children built. Thus a child'ssize: parent.width, ...uses the instance's size. - Children: An instance has no children. Application images are passed through an
imageproperty; custom application drawing (cropped photos) goes in a namedIteminside the component.
docs/aura.md · Download Markdown