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. |
- Layouts are JSON in
PlayerPrefs. The keys areUIToolbox.Layout.{LayoutName}.{name}.LayoutNameis the workspace attributelayout-name. - A layout stores window ids, not content. Register every window before you load a layout.
- These methods do nothing until the workspace is attached to a panel.
- The session restore on attach waits one scheduler tick, so windows and dock zones declared in UXML are registered first. The session is not saved while a layout loads.
- A tab group's minimized or maximized state is saved and restored.
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. |
- To make a preset, arrange the windows, call
CaptureLayout(), and save the text as a.jsonfile in the Resources folder. - A preset can also be written by hand. Every field is optional except the window
Id.TabGroupsmakes a tab group with the listed windows as tabs:
{
"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"
}
]
}
- The bounds are pixels relative to the top-left corner of the viewport, so a workspace toolbar does not cover the windows. A load clamps each window into the viewport, so a preset made on a large screen stays visible on a small screen. All saved layouts use the same bounds.
CurrentLayoutis not saved. After a restart, the first switch does not save the session arrangement under a layout name.- The WorkspaceDemo example has three presets (Desk, Stack and Tabs) in
Assets/UIToolbox/Examples/Resources/UIToolboxSamples/WorkspaceLayouts, with a switch bar above the workspace. The Tabs preset puts three windows in one tab group.
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.