Dialogs

sw.dialog offers two kinds of dialog:

Themed dialogs (async)

Live preview. In the Player's built-in docs viewer (scriptweaver --help), this renders Dialogs as a live, theme-aware widget you can interact with.

const choice = await sw.dialog.message('Save your changes?', {
  title: 'Confirm',
  icon: 'question',
  buttons: ['Save', 'Discard', 'Cancel'],
  default: 'Save',
  cancelValue: 'Cancel',
});
if (choice === 'Save') save();

message(text, options?)Promise<label | cancelValue>

Shows a modal message box styled by the current theme and resolves with the label of the button the user clicked.

option meaning
title window title (default 'Message')
icon 'info' (default), 'question', 'warning', 'danger', 'success' — a themed icon
buttons array of button labels (default ['OK'])
default the label Return activates; drawn solid and focused (defaults to the first button)
cancelValue what Escape or closing the window resolves with (default null)

prompt(text, options?)Promise<string | null>

Asks for one line of text. Resolves with the entered string (OK / Return) or null (Cancel / Escape / window close).

const name = await sw.dialog.prompt('Project name:', { value: 'my-app' });
if (name !== null) create(name);

Options: title, value (prefill), ok / cancel (button labels).

chooseFont(current?, options?)Promise<string | null>

A themed font picker — choose a family, size and style (bold / italic / underline / strike), with a live preview. Resolves with a Tk font string (OK) or null (Cancel / Escape / window close).

const font = await sw.dialog.chooseFont('Helvetica 12');
if (font !== null) label.font = font; // e.g. '{DejaVu Sans} 14 bold italic'

The first argument is the starting font in any Tk font form — a string like 'Helvetica 12' or '{DejaVu Sans} 14 bold', or a named font; omit it to open on the default font. You may instead pass an options object whose initial is the starting font.

The resolved value is a plain string you can assign straight to a widget's font option, store in JSON, or emit into generated code — it round-trips unchanged (a family containing spaces comes back brace-quoted, e.g. {DejaVu Sans} 14 bold). Store it as-is; there is no object to unpack.

Options: title, ok / cancel (button labels), sample (preview text), initial (starting font).

Why async?

The themed dialogs take a Tk grab — the user can't interact with the rest of the window — but your JavaScript never stops. Timers keep firing, events keep arriving, animations keep moving. The result simply arrives later, through the Promise:

sw.dialog.message('Working…').then((r) => console.log('closed with', r));
// code here runs immediately, with the dialog still up

Use await when you want the prompt-like flow, or .then() when the dialog should not hold up other work. Dialogs may be stacked — opening a dialog from a dialog works, and closing the inner one returns modality to the outer one.

Keyboard: Tab moves between buttons, Return activates the default button (prompt submits the entry), Escape cancels. The dialog is announced to assistive technology, and when it closes, focus returns to the widget that had it.

Native message boxes

sw.dialog.alert('File saved.');

if (sw.dialog.confirm('Delete this item?')) {
  // the user clicked Yes
}

Both accept an options object: title, icon ('info', 'question', 'warning', 'error'), and detail (secondary text).

sw.dialog.alert('Could not open the file.', {
  title: 'Error',
  icon: 'error',
  detail: String(err),
});

These use the OS-native message box, which on some platforms looks different from your themed app. For dialogs that match your theme — and don't block — prefer sw.dialog.message.

File and directory pickers

Each returns the chosen path as a string, or an empty string if the user cancels.

const path = sw.dialog.openFile({ title: 'Open note' });
if (path) text.setText(sw.fs.readFile(path));

const dest = sw.dialog.saveFile({ initialFile: 'untitled.txt' });
const dir = sw.dialog.chooseDirectory();

Common options: title, initialDir, initialFile (open / save), and defaultExtension (save).

Colour picker

const colour = sw.dialog.chooseColor({ initial: '#3366ff' });
if (colour) shape.fill = colour; // '#rrggbb', or '' if cancelled

A note on blocking

The native dialogs are synchronous: the call waits for the user and your code resumes on the next line with the result in hand — usually exactly what you want for a file picker. But be aware that everything in your script waits: while a native dialog is open, timers don't fire and event handlers queue up until it closes. If something must keep running — a progress update, a clock, an animation — use the async sw.dialog.message / sw.dialog.prompt instead, or open the picker at a moment when pausing is fine.

Next