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.

Visual control Palette: Atlas Unit Atlas.Layout · Inherits TPanel · Product Atlas VCL

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

MemberKindWhat it does
CreateconstructorCreates an empty workspace without bevel and with 8 pixels of padding.
DestroydestructorMoves the contents of floating windows back into the workspace, frees the windows, then frees the workspace with its panes and splitters.
AddPanemethodCreates 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.
PanemethodThe panel of pane ID, docked or floating.
MovePanemethodDocks the pane to Alignment with a new size; a floating pane is docked first.
FloatPanemethodMoves the pane into a resizable tool window with the given screen bounds; the window is owned by the workspace and stays above its form.
DockPanemethodReturns a floating pane to the edge and size it had before it floated, and frees its window.
IsFloatingmethodTrue while the pane is in a tool window.
FloatingWindowmethodThe tool window of a floating pane; raises EAtlasLayoutError when the pane is docked.
SaveLayoutmethodJSON object keyed by pane ID, in sorted order.
LoadLayoutmethodRestores 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.

pascal
Workspace.AddPane('explorer', 'Explorer', alLeft, 220);
Workspace.MovePane('explorer', alLeft, 220); // puts the splitter on the inner side

Pane method

function Pane(const ID: string): TPanel;

The panel of pane ID, docked or floating. Raises EAtlasLayoutError for an unknown ID.

pascal
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.

pascal
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.

pascal
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.

pascal
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.

pascal
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}}.

pascal
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.

pascal
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.

pascal
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.

pascal
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.

pascal
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;

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