UI Toolbox logoUI Toolbox

Layouts

A layout saves the open windows, their bounds and states, and the tab groups (tab order and active tab).

Method on Workspace Result
SaveLayout(string name) Saves the current layout.
LoadLayoutAsync(string name) Closes the windows, then reopens the saved ones. With no saved layout of that name, it opens the preset of that name. Returns false if neither exists.
GetSavedLayouts() Names of the saved layouts.
DeleteLayout(string name) Deletes a layout. A preset of the same name stays.
CaptureLayout() Returns the open windows as layout JSON.
ApplyLayoutAsync(string json) Closes the windows, then opens the windows of a layout JSON text. Returns false if the text is not JSON.
SaveSession() Saves the session layout.
RestoreSessionAsync() Loads the session layout.
using System.Threading.Tasks;
using UIToolbox;

public static class LayoutMenu
{
    public static void Save(Workspace workspace) => workspace.SaveLayout("Trading");

    public static async Task LoadAsync(Workspace workspace)
    {
        if (!await workspace.LoadLayoutAsync("Trading"))
            await workspace.ArrangeCascadeAsync();
    }
}

Layout presets

A preset is a named layout that ships with the game. The user switches between the named layouts, and each layout keeps the user's changes.

Member of Workspace Result
layout-presets (LayoutPresetsPath) Adds each TextAsset in this Resources folder as a preset, named after the asset, in name order.
AddLayoutPreset(string name, string json) Adds a preset, or replaces the preset with that name. Throws ArgumentException for an empty name or JSON.
GetLayoutPresets() Names of the presets, in the order they were added.
SwitchLayoutAsync(string name) Saves the open windows under CurrentLayout, then loads the named layout: the saved one, else the preset. Returns false if neither exists. If the current layout is a preset and no window is open, the switch does not save an empty layout, so the preset opens the next time.
CurrentLayout The name of the last switch, or null before the first switch.
LayoutSwitched Raised after a switch, with the layout name.
ResetLayoutAsync(string name) Deletes the saved changes to a preset. If the preset is the current layout, it opens the preset again. Returns false if no preset has that name.
{
    "Windows": [
        { "Id": "inventory", "Bounds": { "Left": 10, "Top": 10, "Width": 460, "Height": 370 } }
    ],
    "TabGroups": [
        {
            "Id": "sideTabs",
            "Bounds": { "Left": 480, "Top": 10, "Width": 600, "Height": 500 },
            "TabIds": [ "map", "quests" ],
            "ActiveTabId": "map"
        }
    ]
}
workspace.LayoutSwitched += name => statusLabel.text = $"Layout: {name}";
foreach (var name in workspace.GetLayoutPresets())
    bar.Add(new Button(() => AsyncRunner.Run(() => workspace.SwitchLayoutAsync(name), "Switch layout")) { text = name });

Many windows

The workspace reads the order of the windows once for a focus, an arrangement and a hit test. These times are for 200 windows with the animations off:

Operation Time with 200 windows
Focus a window about 0.2 ms
ArrangeCascadeAsync, synchronous part about 50 ms
Open 200 windows about 200 ms

An arrangement restores and focuses each window. With animations on, each window also runs its restore animation, so turn off the animations (AnimationsEnabled) before you arrange many windows at once.