YOUSEFUL / DELPHI / COMPONENTS
TAtlasWorkspace
Panel of named, resizable edge and client panes that move between edges, float in tool windows and save their layout as JSON.
Description
AddPane creates a pane identified by a stable string ID and docked to the left, right, top or bottom edge or to the client area (at most one client pane). Each edge pane has a 6-pixel TSplitter for resizing, with a minimum size of 24 pixels. Pane(ID) returns the pane's TPanel; parent your controls to it. The workspace and each pane have 8 pixels of padding.
The VCL aligns top and bottom panes before left and right ones, so top and bottom panes span the full width and left and right panes fill the height between them. Put another TAtlasWorkspace in a pane for nested layouts.
MovePane docks a pane to another edge. FloatPane moves the pane, with all its child controls, into a resizable tool window at screen coordinates; DockPane, or closing that window, puts it back where it was. SaveLayout returns JSON with each pane's edge, size, visibility and floating bounds, and LoadLayout validates the whole text before changing anything.
Known problem in this version: the splitter lands on the outer side of its pane, where dragging it does nothing, for left and top panes after AddPane and for right and bottom panes after MovePane or LoadLayout. Calling MovePane with the same edge and size after AddPane fixes left and top panes; there is no workaround through the API for right and bottom panes that have been moved or restored.
There is no RemovePane: freeing the panel returned by Pane(ID) removes the pane, its splitter and any floating window. Not implemented: drag-to-dock with previews, tabbed or auto-hide panes, and restoring panes that do not exist yet (create every pane before LoadLayout). TAtlasThemer does not reach a pane while it floats.
Members
| Member | Kind | What it does |
|---|---|---|
Create | constructor | Creates an empty workspace without bevel and with 8 pixels of padding. |
Destroy | destructor | Moves the contents of floating windows back into the workspace, frees the windows, then frees the workspace with its panes and splitters. |
AddPane | method | Creates a pane docked to Alignment (alLeft, alRight, alTop, alBottom or alClient), Size pixels wide (left, right) or high (top, bottom), and returns its panel, owned by the workspace. |
Pane | method | The panel of pane ID, docked or floating. |
MovePane | method | Docks the pane to Alignment with a new size; a floating pane is docked first. |
FloatPane | method | Moves the pane into a resizable tool window with the given screen bounds; the window is owned by the workspace and stays above its form. |
DockPane | method | Returns a floating pane to the edge and size it had before it floated, and frees its window. |
IsFloating | method | True while the pane is in a tool window. |
FloatingWindow | method | The tool window of a floating pane; raises EAtlasLayoutError when the pane is docked. |
SaveLayout | method | JSON object keyed by pane ID, in sorted order. |
LoadLayout | method | Restores a layout from SaveLayout. |
Constructors
Create constructor
constructor Create(AOwner: TComponent); override;Creates an empty workspace without bevel and with 8 pixels of padding.
Destructors
Destroy destructor
destructor Destroy; override;Moves the contents of floating windows back into the workspace, frees the windows, then frees the workspace with its panes and splitters.
Methods
AddPane method
function AddPane(const ID, Caption: string; Alignment: TAlign; Size: Integer): TPanel;Creates a pane docked to Alignment (alLeft, alRight, alTop, alBottom or alClient), Size pixels wide (left, right) or high (top, bottom), and returns its panel, owned by the workspace. Caption is drawn by the panel where no child covers it and becomes the title of its floating window (the ID is used when it is empty). Raises EAtlasLayoutError for another alignment, a blank or duplicate ID, a size below 24 or a second client pane.
Workspace.AddPane('explorer', 'Explorer', alLeft, 220);
Workspace.MovePane('explorer', alLeft, 220); // puts the splitter on the inner sidePane method
function Pane(const ID: string): TPanel;The panel of pane ID, docked or floating. Raises EAtlasLayoutError for an unknown ID.
Tree := TListBox.Create(Workspace);
Tree.Parent := Workspace.Pane('explorer');
Tree.Align := alClient;MovePane method
procedure MovePane(const ID: string; Alignment: TAlign; Size: Integer);Docks the pane to Alignment with a new size; a floating pane is docked first. Same validation as AddPane. It also updates the splitter: after changing Pane(ID).Visible, call MovePane with the same edge and size so the splitter is hidden or shown with the pane.
Workspace.MovePane('output', alRight, 300);FloatPane method
procedure FloatPane(const ID: string; const Bounds: TRect);Moves the pane into a resizable tool window with the given screen bounds; the window is owned by the workspace and stays above its form. If the pane already floats, its window is moved and resized. The window is shown only if the workspace is showing and the pane is visible. The left and top coordinates must be within +/-1,000,000 and the width and height 64 to 16,384 pixels, otherwise EAtlasLayoutError and nothing changes.
Origin := Workspace.ClientToScreen(Point(40, 40));
Workspace.FloatPane('explorer', Rect(Origin.X, Origin.Y, Origin.X + 300, Origin.Y + 400));DockPane method
procedure DockPane(const ID: string);Returns a floating pane to the edge and size it had before it floated, and frees its window. Does nothing for a docked pane; raises EAtlasLayoutError for an unknown ID.
IsFloating method
function IsFloating(const ID: string): Boolean;True while the pane is in a tool window. Raises EAtlasLayoutError for an unknown ID.
if Workspace.IsFloating('explorer') then Workspace.DockPane('explorer');FloatingWindow method
function FloatingWindow(const ID: string): TForm;The tool window of a floating pane; raises EAtlasLayoutError when the pane is docked. Closing the window docks the pane instead of destroying it.
Workspace.FloatingWindow('explorer').Show;SaveLayout method
function SaveLayout: string;JSON object keyed by pane ID, in sorted order. Each value has align (the ordinal of TAlign: 1 top, 2 bottom, 3 left, 4 right, 5 client), size in pixels and visible, and a floating pane also has floating with left, top, width and height; its align and size are where it docks back to. Example: {"details":{"align":4,"size":180,"floating":{"left":100,"top":100,"width":300,"height":300},"visible":true},"document":{"align":5,"size":400,"visible":true}}.
Layout := Workspace.SaveLayout;LoadLayout method
procedure LoadLayout(const Text: string);Restores a layout from SaveLayout. The text must be a JSON object with exactly one entry for every existing pane; each entry needs an integer align of 1 to 5, an integer size of at least 24 and a boolean visible, at most one entry may be the client pane, and floating bounds must be in the FloatPane ranges. Everything is checked first; on any problem EAtlasLayoutError is raised and no pane changes. A floating entry opens its window only if the workspace is showing, so restore a layout after the form is shown.
Workspace.LoadLayout(Layout);Examples
Three-pane workspace
An explorer on the left, an editor in the client area and an output pane at the bottom, spanning the full width.
uses System.Classes, Vcl.Controls, Vcl.StdCtrls, Atlas.Layout;
function BuildWorkspace(Owner: TComponent; Parent: TWinControl): TAtlasWorkspace;
var
Explorer: TListBox;
Output: TMemo;
begin
Result := TAtlasWorkspace.Create(Owner);
Result.Parent := Parent;
Result.Align := alClient;
Result.AddPane('explorer', 'Explorer', alLeft, 220);
Result.AddPane('editor', '', alClient, 400);
Result.AddPane('output', 'Output', alBottom, 140);
Result.MovePane('explorer', alLeft, 220); // splitter between explorer and editor
Explorer := TListBox.Create(Owner);
Explorer.Parent := Result.Pane('explorer');
Explorer.Align := alClient;
Output := TMemo.Create(Owner);
Output.Parent := Result.Pane('output');
Output.Align := alClient;
end;
Float, dock and remember the layout
A float/dock toggle for a command, plus saving and restoring the layout in a file.
uses System.SysUtils, System.Types, System.IOUtils, Atlas.Layout;
procedure ToggleFloating(Workspace: TAtlasWorkspace; const ID: string);
var
Origin: TPoint;
begin
if Workspace.IsFloating(ID) then
Workspace.DockPane(ID)
else
begin
Origin := Workspace.ClientToScreen(Point(40, 40));
Workspace.FloatPane(ID, Rect(Origin.X, Origin.Y, Origin.X + 300, Origin.Y + 400));
end;
end;
procedure SaveWorkspace(Workspace: TAtlasWorkspace; const FileName: string);
begin
TFile.WriteAllText(FileName, Workspace.SaveLayout, TEncoding.UTF8);
end;
// Call after the form is shown, so that floating panes can open their windows.
procedure RestoreWorkspace(Workspace: TAtlasWorkspace; const FileName: string);
begin
if not TFile.Exists(FileName) then Exit;
try
Workspace.LoadLayout(TFile.ReadAllText(FileName, TEncoding.UTF8));
except
on EAtlasLayoutError do ; // stale file: keep the current layout
end;
end;
Hide and show a docked pane
Changes the panel's visibility and lets MovePane hide or show the splitter with it.
uses Vcl.Controls, Vcl.ExtCtrls, Atlas.Layout;
procedure SetPaneVisible(Workspace: TAtlasWorkspace; const ID: string; Visible: Boolean);
var
Panel: TPanel;
begin
Panel := Workspace.Pane(ID);
Panel.Visible := Visible;
if Panel.Align in [alLeft, alRight] then
Workspace.MovePane(ID, Panel.Align, Panel.Width)
else
Workspace.MovePane(ID, Panel.Align, Panel.Height);
end;
Related
TAtlasCommandBar · TAtlasNavigation · TAtlasTileBoard · EAtlasLayoutError · TAtlasThemer
Also in Atlas VCL
TAtlasTable · TAtlasGrid · TAtlasValueEdit · TAtlasTree · TAtlasWorkbook · TAtlasSheetGrid · TAtlasPivot · TAtlasInspector · TAtlasRichEdit · TAtlasSpellChecker · TAtlasChart · TAtlasGauge · TAtlasThemer · TAtlasWizard · TAtlasCommandBar · TAtlasActionTile · TAtlasTileBoard · TAtlasNavigation · TAtlasMap · TAtlasGraph · TAtlasDiagram · TAtlasPrintDocument · TAtlasSchedule · TAtlasScheduler · TAtlasTaskPlan · TAtlasGantt · TAtlasPdfDocument · TAtlasPdfViewer