Skip to content

UXSavePanel

UXSavePanel is the call an app makes to ask where to save, the sibling of UXOpenPanel:

u8* path = UXSavePanel.run((u8*)"Save the drawing", (u8*)".", (u8*)"untitled.png");
if (path != (u8*)0)
{
UXFileIO.write(path, bytes);
free((pointer)path);
}

A prompt, a start folder and a default name go in. The path to write comes out, or null on Cancel. The panel never writes anything itself; pair it with UXFileIO.write, which saves atomically.

Native where there is one, drawn everywhere else

Section titled “Native where there is one, drawn everywhere else”
backendwhat runs
AppKitNSSavePanel, which asks about replacing a file itself
GTKGtkFileDialog, which does too
Win32GetSaveFileName, which does too
iOSthe system’s export picker, which asks where the document goes
AndroidACTION_CREATE_DOCUMENT, which asks where it goes and under what name
GEMUXFilePanel in save mode
webno dialog: saving is the browser’s download, so the panel names the file (/ + the default name) and the write hands it to the browser, which may ask where itself

The driver answers hasNativeFileSave; application code does not ask.

On iOS and Android the chosen document may belong to another app or a cloud provider, where a plain file write cannot reach it. There the path that comes back is a staging file in the app’s own space, under the default name (on Android, the name the user settled on). Write it with UXFileIO.write as usual: each write that lands is copied on to the chosen document, and write returns true only once it is there. Writing the same path again saves to the same document.

The drawn panel in save mode differs from the open panel in four ways:

  • The line under the mask reads Save as: and starts with the default name. Folder changes keep whatever you have typed.
  • The button reads Save. It answers with the current folder plus the typed name, without needing a row to be selected.
  • Typing a folder’s name and pressing Save goes into that folder rather than saving over it, and the name goes back to the default. .. goes up.
  • A name that already exists is confirmed first (“A file with this name already exists. Replace it?”). Cancel leaves the panel up. The check covers every file in the folder, including ones the mask hides.

The Recent button is hidden: recent files are things to open, not places to save.

static u8* run(u8* prompt, u8* startDir, u8* defaultName)

Runs the dialog modally. Returns a malloc’d path the caller owns (free it), or null on Cancel.

static u8* runToolkit(u8* prompt, u8* startDir, u8* defaultName)

The drawn half, callable directly. It runs a fresh UXFilePanel through runSave.