Events
The page tells Lua about things the player did. You listen with the handle:
win:on('save', function(data, eventName) ... end)Callbacks always receive (data, eventName). data always has id (the window id).
Listener API
win:on(event, fn) -- add (several per event are fine)
win:once(event, fn) -- removes itself after the first call
win:off(event, fn?) -- remove one, or all for that event
win:onClick(event, fn) -- alias of :on, reads better for buttons
win:onChange(path, fn) -- shorthand for on('change:' .. path, fn)
win:onAny(fn) -- every event; second argument is the event nameYou can also pass listeners when opening: tm.ui.window(schema, { save = fn, close = { fn1, fn2 } }). A listener that errors is caught and printed; the others still run.
Event reference
| Event | When | data |
|---|---|---|
button event | A button is pressed (after validation, if submit = true). | { id, event, values?, args?, close? }. values only for submit buttons. |
change | A field with notify = true changed (debounced 150 ms). | { id, path, value, old } |
change:<path> | Same, for one path. | as change |
select | A menu item was chosen. | { id, key } (menus: see menus) |
check | A menu checkbox was toggled. | { id, key, checked } |
list / table event | A row was clicked. | { id, event, key } |
tile event | A tile was pressed. | { id, event, args?, close? } |
timer event | A timer node reached zero (default event timeout). | { id, event, close? } |
keydown / keyup | Window has keys = true and is on top. | { id, key } (key is the browser key name: 'a', 'Enter', 'ArrowUp') |
close | The player dismissed the window (Escape or the X). | { id } |
* | Every event above. | as the event |
close does not fire when you call win:close() yourself, or when a button with close = true closes the window (that button's own event fires instead).
Change events and old
old is Lua's last known value for that path: the initial values, or whatever the previous change / submit / win:set delivered. It is nil the first time if the schema had no initial value.
win:onChange('volume', function(d)
print(('volume %s -> %s'):format(d.old, d.value))
end)Only fields with notify = true send changes. Everything else stays in the page until a submit, so typing costs nothing.
Keys
local win = tm.ui.window({ title = 'Racer', keys = true, children = { ... } })
win:on('keydown', function(d) if d.key == 'r' then restart() end end)Only the topmost window with keys = true forwards keys. Repeats from holding a key are not sent. Keys typed into inputs are also forwarded, so filter if you have text fields.
Submitting and waiting
local values = tm.ui.window(schema):wait():wait() resolves on the first event that carries values (a submit = true button) with those values, or with nil when the window is dismissed or closed. Listeners still run, so you can use both: react to events and also await the result.
Order of things for one button press
- UI validates (submit buttons) and sends the event.
- Lua updates its value mirror, then runs the event's listeners, then the
*listeners. :wait()resolves if the event carriedvalues.- If the button had
close = true, the Lua handle is marked closed and NUI focus is released.