sagl.ui¶
UI documents, pause menu pages and SAGL's message box. Documents are RML and RCSS: see Styling and layouts, and the UI guide for screenshots and walkthroughs.
Tip
For a shop or a dialog whose logic is on the server anyway, the
gamemode can open the layout itself with
player.ui.open(), without a client script.
The element methods are the same.
Opening UI¶
sagl.ui.open(rml, options?)¶
Opens a document from RML text and shows it.
| Parameter | Type | Description |
|---|---|---|
rml |
string |
A whole RML document (<rml><head>...</head><body>...</body></rml>), up to 256 KB. Relative links resolve under sagl/ui/scripts/; use /sagl/ui/theme/base.rcss for SAGL's theme. |
options |
DocumentOptions |
Optional. |
Returns the UiDocument.
Throws RangeError past 16 documents or 256 KB; SyntaxError if the
RML doesn't load; InternalError if the UI isn't ready.
Any document can show the game's own textures, read from the player's copy
of the game: <img src="game:<txd>/<texture>"/>, a TXD in models/gta3.img
or gta_int.img (or models/<txd>.txd) and a texture in it, e.g.
<img src="game:garag3_lawn/ws_Transfender_dirty"/> for TransFender's sign.
const toast = sagl.ui.open(`
<rml><head><link type="text/rcss" href="/sagl/ui/theme/base.rcss"/>
<style>body { position: absolute; left: 40%; top: 20dp; width: 20%; }</style></head>
<body><div class="panel" id="text"></div></body></rml>`, { input: false });
toast.setText("text", "Checkpoint!");
setTimeout(() => toast.close(), 3000);
sagl.ui.openFile(path, options?)¶
Opens an RML client file as a document. Its relative links (images, stylesheets) resolve beside it.
| Parameter | Type | Description |
|---|---|---|
path |
string |
The client file, e.g. "ui/shop.rml". |
options |
DocumentOptions |
Optional. |
Returns the UiDocument.
Throws ReferenceError if there's no such client file, and as open.
DocumentOptions¶
| Field | Type | Default | Description |
|---|---|---|---|
input |
boolean |
true |
Takes the player's input while shown. false for HUDs. |
cursor |
boolean |
input |
Shows the mouse cursor. |
keyboard |
boolean |
input |
Keys go to the document. |
gamepad |
boolean |
input |
The gamepad moves focus (A activates, B backs out). |
movement |
boolean |
false |
Leaves the player's movement to the game. |
escapeCloses |
boolean |
true |
Esc (or gamepad B) closes it. |
sagl.ui.pauseMenu.addPage(title, rml)¶
Adds a page to the pause menu: its title goes in the options row, before Quit Game.
| Parameter | Type | Description |
|---|---|---|
title |
string |
1-32 characters. |
rml |
string |
The page's content (no <rml>/<head>), styled by the pause menu's theme. <style> blocks in it add styles of its own (scope them with a class on the page's outer element). |
Returns the MenuPage.
Throws RangeError past 8 pages, or for a bad title.
const help = sagl.ui.pauseMenu.addPage("Help", `
<h2 class="first">How to play</h2>
<span class="subtitle">Cops catch robbers. Robbers get rich.</span>`);
sagl.ui.showDocument(source, options?)¶
sagl.ui.showDocument(source: { file: string } | { markdown: string }, options?: { title?, buttons?, requireEnd?, closable? }): Promise<number>
As the server's player.ui.showDocument:
a markdown client file (or markdown text) in the document viewer,
resolving with the button pressed, or -1.
sagl.ui.messageBox(options)¶
sagl.ui.messageBox(options: { title?: string; text?: string; buttons?: string[] }): Promise<string | null>
Shows SAGL's message box. Boxes queue: one shows at a time.
| Parameter | Type | Description |
|---|---|---|
options.title |
string |
|
options.text |
string |
|
options.buttons |
string[] |
Left to right; the last is the default. Default ["OK"]. |
Returns a promise of the chosen button's label, or null if dismissed
(Esc).
const choice = await sagl.ui.messageBox({
title: "Join a team",
text: "Which side are you on?",
buttons: ["Robbers", "Cops"],
});
if (choice) sagl.emit("team", choice.toLowerCase());
sagl.ui.onMissionResult(fn)¶
sagl.ui.onMissionResult(fn: ((result: { kind: string; title: string; text: string }) => boolean) | null): void
Shows the script's own result screen instead of SAGL's ("MISSION
PASSED!"). fn gets each result the gamemode shows
(player.hud.missionPassed(), missionFailed(), missionResult(); kind is
"passed", "failed" or "custom"): return true if you showed it, and SAGL's
isn't shown. Return anything else to leave it to SAGL. null removes it.
sagl.ui.onMissionResult(({ kind, title, text }) => {
if (kind !== "custom") return false; // SAGL's for the rest
const doc = sagl.ui.openFile("ui/race-result.rml", { input: false });
doc.setText("title", title).setText("time", text);
setTimeout(() => doc.close(), 5000);
return true;
});
Element methods¶
UiDocument and MenuPage share these. They work on the document's or
page's own elements, by id, and return it so calls chain.
setText(id, text)¶
Sets an element's text (escaped: no markup).
| Parameter | Type | Description |
|---|---|---|
id |
string |
The element's id. |
text |
any |
Converted to a string. |
setMarkdown(id, markdown, base?)¶
Replaces an element's contents with markdown,
{key:ID} placeholders and all. base is the client file it came from,
for relative images. Link /sagl/ui/theme/markdown.rcss to style it. The
<sagl-markdown src="docs/help.md"/> element does the same for a client
file, right in your RML.
setHtml(id, rml)¶
Replaces an element's contents with RML.
setValue(id, value), getValue(id)¶
A form control's value (<input>, <select>, <textarea>).
isChecked(id)¶
Whether a checkbox or radio button is checked.
setClass(id, name, on?)¶
Adds (on, the default) or removes a class.
setAttribute(id, name, value)¶
Sets an attribute, or removes it with null.
doc.setAttribute("avatar", "src", sagl.files.url("ui/avatars/cop.png"));
doc.setAttribute("bar", "style", `width: ${pct}%`);
focus(id)¶
Gives an element keyboard and gamepad focus. Returns whether it could.
on(type, id?, handler)¶
on(type: string, handler: (e: UiEvent) => void): this
on(type: string, id: string, handler: (e: UiEvent) => void): this
Handles events from the whole document or page, or from one element (and what's inside it).
| Parameter | Type | Description |
|---|---|---|
type |
string |
click, change, submit, keydown, focus, blur, mouseover or mouseout. |
id |
string |
Optional: only events from this element. |
handler |
function |
Gets a UiEvent. |
shop.on("click", "buy", () => sagl.emit("shop", { buy: shop.getValue("item") }));
shop.on("change", "quantity", (e) => shop.setText("total", `$${200 * Number(e.value)}`));
shop.on("change", "search", (e) => { if (e.enter) sagl.emit("shop:search", e.value); });
off(type, handler?)¶
Removes a handler, or every handler of that type.
UiEvent¶
| Field | Type | Description |
|---|---|---|
type |
string |
The event type. |
id |
string |
The id of the element it came from (the nearest one with an id). |
value |
string |
A form control's value, for change and submit. |
key |
number | undefined |
For keydown: RmlUi's key identifier (KI_A 12 ... KI_Z 37, KI_0 2 ... KI_9 11). |
checked |
boolean |
For checkboxes. |
enter |
boolean |
For change from a text input: true when the player pressed Enter in it. |
Note
Text inputs keep the keys they use (Enter, arrows, Backspace, ...), so
keydown doesn't see those from a focused input. For "Enter sends",
handle change and check e.enter:
UiDocument¶
From open and openFile. The element methods above, plus:
| Member | Description |
|---|---|
open |
boolean: false once it's closed. |
show() |
Shows it again (and takes input again, if it does). Returns it. |
hide() |
Hides it (and gives input back) without closing it. Returns it. |
close() |
Closes it for good. |
onClose(fn) |
Calls fn when it closes, by close() or Esc (not when scripts reload). Returns it. |
const menu = sagl.ui.openFile("ui/garage.rml");
menu.onClose(() => sagl.emit("garage", { closed: true }));
sagl.on("garage:hide", () => menu.hide());
MenuPage¶
From pauseMenu.addPage. The element methods above, plus:
| Member | Description |
|---|---|
remove() |
Takes the page out of the pause menu. |
onShow(fn) |
Calls fn each time the player opens the page. Returns it. |