Recipe: dialogs
A dialog is a Window that is modal: while it shows, an overlay covers the screen behind it and blocks clicks there. Build it once, hide it, and show it when you need an answer.
A confirmation dialog
setEnterResult("yes") and setEscResult("no") make Enter and Escape close the window and pass that string to the function you give setOnResult. Your buttons call fireResult(key, data) to close it the same way, so every answer lands in one place.
ts
import { Button, DEFAULT_STAGE, DEFAULT_WINDOW_MANAGER, LAYOUT_NONE, Label, Screen, VARIANT_DANGER, Window } from "willowui";
const W: float = 800.0;
const H: float = 600.0;
const screen: Screen = new Screen();
const status: Label = new Label("status", "", "default", 14.0);
status.setPosition(20.0, 60.0);
screen.add(status);
// Build the dialog once, hidden.
const dialog: Window = new Window("confirm-quit", "Quit the game?", "default", 16.0);
dialog.setModal(true);
dialog.setMovable(false);
dialog.setResizable(false);
dialog.setCloseable(false);
dialog.setSize(360.0, 160.0);
dialog.setPosition((W - 360.0) / 2.0, (H - 160.0) / 2.0);
dialog.body.setLayout(LAYOUT_NONE);
screen.add(dialog);
DEFAULT_WINDOW_MANAGER.add(dialog);
dialog.setVisible(false);
const message: Label = new Label("message", "Unsaved progress will be lost.", "default", 14.0);
message.setPosition(16.0, 16.0);
dialog.body.addChild(message);
const yes: Button = new Button("yes", "Quit", "default", 14.0);
yes.setVariant(VARIANT_DANGER);
yes.setSize(100.0, 34.0);
yes.setPosition(130.0, 70.0);
yes.setOnClick((): void => { dialog.fireResult("yes", null); });
dialog.body.addChild(yes);
const no: Button = new Button("no", "Stay", "default", 14.0);
no.setSize(100.0, 34.0);
no.setPosition(240.0, 70.0);
no.setOnClick((): void => { dialog.fireResult("no", null); });
dialog.body.addChild(no);
dialog.setEnterResult("yes");
dialog.setEscResult("no");
// fireResult hides the window, then calls this with the key and the data.
dialog.setOnResult((answer: string, data: any): void => {
if (answer == "yes") { System.exit(0); }
status.setText("Still here");
});
const quit: Button = new Button("quit", "Quit...", "default", 14.0);
quit.setPosition(20.0, 20.0);
quit.setOnClick((): void => {
dialog.setVisible(true);
DEFAULT_WINDOW_MANAGER.focus(dialog);
});
screen.add(quit);
DEFAULT_STAGE.setScene(engine.root2d);
DEFAULT_STAGE.add(screen);
App.onFrame((dt: float): void => { DEFAULT_STAGE.update(dt); });Notes:
DEFAULT_WINDOW_MANAGER.add(dialog)is what makes the window stack, take focus and come to the front. Do it for every window.setOnModalOverlayClick(fn)runs when the player clicks the dimmed area;setModalOverlayColor(c)changes its color.sizeToContent()fits the window to what is in its body, instead of a fixedsetSize.
Small messages: toasts
For "Game saved" and other messages that need no answer, use a toast instead of a dialog: showToast("Game saved", VARIANT_SUCCESS, [withDuration(2.0)]). See Display widgets.
See also
- Containers for the rest of the
Windowoptions. - Recipe: a form for collecting typed values in a window.