Difference between revisions of "Anchor Docking"

From Lazarus wiki
Jump to navigationJump to search
(Added link to the step by step example in →‎Links)
m (→‎See also: less > fewer)
 
(35 intermediate revisions by 9 users not shown)
Line 1: Line 1:
 +
 +
{{LanguageBar}}
 +
 
About docking in general see [[Docking]].
 
About docking in general see [[Docking]].
  
=Overview=
+
==Overview==
  
 
Docking allows you to combine forms, or to treat controls as forms. You use the mouse to drag and dock forms together or undock (split) them. The basic dragging, docking and undocking functionality is provided by the LCL. But you need a docking manager to add splitters and grab zones, and to save and restore layouts.
 
Docking allows you to combine forms, or to treat controls as forms. You use the mouse to drag and dock forms together or undock (split) them. The basic dragging, docking and undocking functionality is provided by the LCL. But you need a docking manager to add splitters and grab zones, and to save and restore layouts.
  
Anchor docking has been implemented since version 0.9.29 in the package ''anchordocking.lpk''. It is easy to use, and provides many features and options not available in earlier docking packages.
+
Anchor docking has been implemented since version 0.9.29 in the package ''anchordocking.lpk'' for use in your own Lazarus applications, and ''AnchorDockingDsgn.lpk'' if you wish to make the Lazarus IDE windows dockable. It is easy to use, and provides many features and options not available in earlier docking packages.
  
 
You will find a code example at: components/anchordocking/miniide/miniide1.lpi
 
You will find a code example at: components/anchordocking/miniide/miniide1.lpi
Line 11: Line 14:
 
This means that the earlier TLazDockingManager and unit LDockCtrl are obsolete and now deprecated.  
 
This means that the earlier TLazDockingManager and unit LDockCtrl are obsolete and now deprecated.  
  
==Features==
+
===Features===
  
 
*'''Drag and dock''': Headers are added that can be dragged to dock controls with the mouse. Preview rectangles will show where and how a control is docked.
 
*'''Drag and dock''': Headers are added that can be dragged to dock controls with the mouse. Preview rectangles will show where and how a control is docked.
Line 45: Line 48:
 
*There is an IDE package which makes the Lazarus IDE dockable. It is called anchordockingdsgn.lpk. Make sure you only install one docking package. Do not install the easydockmgr at the same time!
 
*There is an IDE package which makes the Lazarus IDE dockable. It is called anchordockingdsgn.lpk. Make sure you only install one docking package. Do not install the easydockmgr at the same time!
  
==ToDos==
+
===ToDos===
  
 
*Design time package: Add all layout files to menu
 
*Design time package: Add all layout files to menu
Line 54: Line 57:
 
*Implement automatic menu merging in the LCL (when two forms with main menus are docked).
 
*Implement automatic menu merging in the LCL (when two forms with main menus are docked).
  
=Usage=
+
==Usage I. (Add docking support to the Lazarus IDE)==
 +
 
 +
If you don't like the default "separate windows" look of the Lazarus IDE and prefer a single window (e.g., like RAD Studio™), you can install a package called '''[[AnchorDockingDsgn]]''' (lazarus/components/anchordocking/design/anchordockingdsgn.lpk). This package makes the IDE windows dockable.
 +
 
 +
===Installation===
 +
 
 +
Uninstall any other docking managers (e.g., easydockmgrdsgn). From the Lazarus main menu pick "Package" - "Install/Uninstall Packages" and install the "anchordockingdsgn" package.
 +
 
 +
After you have successfully installed the package and restarted the IDE, the IDE starts with a default docked layout like shown below. Note that AnchorDocking headers and splitters have been added to all dockable windows of the IDE. In case the headers don't get visible, see the section "Options" below on how to enable/disable them.
 +
 
 +
[[File:2021-12-02_10_21_07-Debian_10.8_Buster_-_VMware_Workstation.png|1333px]]
 +
 
 +
You can change the layout by grabbing a dockable window by the Anchordocking header and drag and dock it anywhere else, or resize docked windows via splitters added to the window borders. You can right-click on the headers too for other options, for example, to change the look of the headers, as shown farther down below.
 +
 
 +
You can save the layout via the menu item '''Tools / Save window layout as default'''. This saves to ~/.lazarus/anchordocklayout.xml and restores it when the IDE starts up.
 +
 
 +
You can also save the layout to a file and load them later.
 +
 
 +
Since Lazarus 1.1 you can pass a command line parameter
 +
 
 +
./lazarus --anchordocklayout=<filename>
 +
 
 +
The look (like the headers) can be further tweaked by right-clicking on them.
 +
 
 +
[[File:docking_headers.gif]]
 +
 
 +
===Options===
 +
After the successful installation of the AnchorDockingDsgn package, an additional configuration menu is added to the Lazarus options dialog ("Tools" - "Options" - "Environment")
 +
 
 +
[[File:anchordocking options.png]]
 +
 
 +
====Scale on resize====
 +
 
 +
When resizing a window, all docked forms inside are scaled by the same
 +
percentage.
 +
 
 +
====Show headers====
 +
 
 +
To dock/undock a window, you need to enable this option.
 +
 
 +
====Flatten headers====
 +
 
 +
No 3d frame in headers.
 +
 
 +
====Header align top/left====
 +
 
 +
Headers are automatically put at top or left depending on these two
 +
values:
 +
* Move header to top, when (width/height)*100<=HeaderAlignTop, default 80
 +
* Move header to left, when (width/height)*100>=HeaderAlignLeft, default 120
 +
* Otherwise keep the header at the current position.
 +
 
 +
Which means the header is by default put at the smaller side of a docked control. When the control is resized, the header switches to the smaller side.
 +
 
 +
====Allow dock sites to be minimized====
 +
 
 +
A extra minimize button is added, so a site can be minimized. Then sites next to it get more space. If needed, the minimized site then can easy be opened.
 +
 
 +
====Multine Tabs====
 +
 
 +
Feature added in Lazarus 2.2. If a OS support multiline tabs (like Windows), if there are no many tabs, they are shown in multiple lines.
 +
 
 +
====Floating windows on top====
 +
 
 +
Feature added in Lazarus 2.2. If there are undocked windows shown, show these on top of main window. In a own application, there can be set DockMaster.MainDockForm, then all floating windows are shown on top of it. If MainDockForm is not set, Application.MainForm is used.
 +
 
 +
==Usage II. (Add docking support to your own applications)==
  
==Quick start==
+
===Quick start===
  
 
Add the package '''AnchorDocking''' to the required packages in the project inspector.
 
Add the package '''AnchorDocking''' to the required packages in the project inspector.
Line 63: Line 132:
  
 
Add to the FormCreate of your main form:
 
Add to the FormCreate of your main form:
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   DockMaster.MakeDockSite(Self,[akBottom],admrpChild);
 
   DockMaster.MakeDockSite(Self,[akBottom],admrpChild);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
For the other dockable forms replace all calls of ''Show'' and ''ShowOnTop'' with
 
For the other dockable forms replace all calls of ''Show'' and ''ShowOnTop'' with
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   DockMaster.MakeDockable(Form1,true,true);  
 
   DockMaster.MakeDockable(Form1,true,true);  
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
For the other dockable forms replace all calls of ''Visible:=true'' with
 
For the other dockable forms replace all calls of ''Visible:=true'' with
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   DockMaster.MakeDockable(Form1,true);  
 
   DockMaster.MakeDockable(Form1,true);  
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 79: Line 148:
 
Remove or comment all ''Hide'', ''Visible:=false'', ''WindowState:='' calls.
 
Remove or comment all ''Hide'', ''Visible:=false'', ''WindowState:='' calls.
  
==Prerequisites==
+
===Prerequisites===
  
 
* Your project must use the package ''AnchorDocking''.  
 
* Your project must use the package ''AnchorDocking''.  
Line 86: Line 155:
 
* No other docking system. AnchorDocking is incompatible with EasyDockMgr.
 
* No other docking system. AnchorDocking is incompatible with EasyDockMgr.
  
==Making forms dockable==
+
===Making forms dockable===
  
 
There are two ways to make a form dockable. You can use '''DockMaster.MakeDockable''' to wrap a form into a dock site. Then your form can dock and be docked completely free. You will use that for the biggest part of your forms, except for the MainForm, because this is only supported for the MainForm on gtk2 and qt. The second way is to use '''DockMaster.MakeDockSite'''. The form can dock other sites, but can not be docked itself. You might want to use ''MakeDockSite'' for the ''MainForm''.
 
There are two ways to make a form dockable. You can use '''DockMaster.MakeDockable''' to wrap a form into a dock site. Then your form can dock and be docked completely free. You will use that for the biggest part of your forms, except for the MainForm, because this is only supported for the MainForm on gtk2 and qt. The second way is to use '''DockMaster.MakeDockSite'''. The form can dock other sites, but can not be docked itself. You might want to use ''MakeDockSite'' for the ''MainForm''.
 
For most other forms you probably want to use this:
 
For most other forms you probably want to use this:
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
// shows YourForm
 
// shows YourForm
 
// if not already done, wrap the form into a dock site
 
// if not already done, wrap the form into a dock site
 
DockMaster.MakeDockable(YourForm);  
 
DockMaster.MakeDockable(YourForm);  
 
</syntaxhighlight>
 
</syntaxhighlight>
 
  
 
Here are some examples how a form looks like that was made dockable with '''DockMaster.MakeDockable''':
 
Here are some examples how a form looks like that was made dockable with '''DockMaster.MakeDockable''':
Line 104: Line 172:
 
The header position is normally done automatically and the user can with a right click put it to any of the four sides.
 
The header position is normally done automatically and the user can with a right click put it to any of the four sides.
  
==Example: miniide1==
+
===Example: miniide1===
  
 
The example can be found in ''lazarus/components/anchordocking/miniide/miniide1.lpi''. It has a ''mainform'' in unit ''unit1.pas'' with a main menu which works as a docksite and several forms that are dockable.  
 
The example can be found in ''lazarus/components/anchordocking/miniide/miniide1.lpi''. It has a ''mainform'' in unit ''unit1.pas'' with a main menu which works as a docksite and several forms that are dockable.  
Line 110: Line 178:
 
[[Image:Anchordocking miniide1.png]]
 
[[Image:Anchordocking miniide1.png]]
  
==Making the main form a dock site==
+
===Making the main form a dock site===
  
 
In the TMainIDE.FormCreate the main form '''MainIDE''' is turned into a docksite:
 
In the TMainIDE.FormCreate the main form '''MainIDE''' is turned into a docksite:
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
DockMaster.MakeDockSite(Self,[akBottom],admrpChild);
 
DockMaster.MakeDockSite(Self,[akBottom],admrpChild);
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 127: Line 195:
 
As soon as a dockable form is docked its caption is shown in the dock header.
 
As soon as a dockable form is docked its caption is shown in the dock header.
  
===Requirements for a custom dock site===
+
====Requirements for a custom dock site====
  
 
As long as nothing is docked into a custom dock site, your form can do everything as a normal form. But when a site is docked to it, some properties and methods need special care:
 
As long as nothing is docked into a custom dock site, your form can do everything as a normal form. But when a site is docked to it, some properties and methods need special care:
Line 136: Line 204:
 
*ChildSizing: The spacing properties like LeftRightSpacing, TopBottomSpacing may interfere with the docking layout.
 
*ChildSizing: The spacing properties like LeftRightSpacing, TopBottomSpacing may interfere with the docking layout.
  
==Procedure to create all other forms by name==
+
===Procedure to create all other forms by name===
  
 
The MainIDE sets the '''DockMaster.OnCreateControl''' event, to enable the DockMaster to create forms by name. This is needed to restore layouts.
 
The MainIDE sets the '''DockMaster.OnCreateControl''' event, to enable the DockMaster to create forms by name. This is needed to restore layouts.
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
DockMaster.OnCreateControl:=@DockMasterCreateControl;
 
DockMaster.OnCreateControl:=@DockMasterCreateControl;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure TMainIDE.DockMasterCreateControl(Sender: TObject; aName: string; var
 
procedure TMainIDE.DockMasterCreateControl(Sender: TObject; aName: string; var
 
   AControl: TControl; DoDisableAutoSizing: boolean);
 
   AControl: TControl; DoDisableAutoSizing: boolean);
Line 174: Line 242:
  
 
Creating a form can be as simple as this:
 
Creating a form can be as simple as this:
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
MyForm:=TMyForm.Create(Self);
 
MyForm:=TMyForm.Create(Self);
 
if DoDisableAutoSizing then
 
if DoDisableAutoSizing then
Line 191: Line 259:
 
If you call '''DisableAutoSizing''' too much, your forms will not appear and/or not resize properly as the LCL is waiting for the ''EnableAutoSizing'' call that never comes.
 
If you call '''DisableAutoSizing''' too much, your forms will not appear and/or not resize properly as the LCL is waiting for the ''EnableAutoSizing'' call that never comes.
  
==Showing forms==
+
===Showing forms===
  
 
When a form should be shown, you have probably used something like '''MyForm.Show''. Instead you should now use
 
When a form should be shown, you have probably used something like '''MyForm.Show''. Instead you should now use
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
DockMaster.MakeDockable(MyForm);
 
DockMaster.MakeDockable(MyForm);
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 201: Line 269:
  
 
If you set the '''DockMaster.OnCreateControl''' event you can use this:
 
If you set the '''DockMaster.OnCreateControl''' event you can use this:
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
DockMaster.ShowControl('MyForm',true);
 
DockMaster.ShowControl('MyForm',true);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Docking manually, via code==
+
===Docking manually, via code===
  
 
Use the procedure '''DockMaster.ManualDock''' to dock a site to or into another.
 
Use the procedure '''DockMaster.ManualDock''' to dock a site to or into another.
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure ManualDock(SrcSite, TargetSite: TAnchorDockHostSite; Align: TAlign; TargetControl: TControl = nil);
 
procedure ManualDock(SrcSite, TargetSite: TAnchorDockHostSite; Align: TAlign; TargetControl: TControl = nil);
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 218: Line 286:
  
  
==Undocking manually, via code==
+
===Undocking manually, via code===
  
 
Use the procedure '''DockMaster.ManualFloat''' to undock a site from its neighbors and create a flotaing top level form. The embedded control stays embedded into a TAnchorDockHostSite.
 
Use the procedure '''DockMaster.ManualFloat''' to undock a site from its neighbors and create a flotaing top level form. The embedded control stays embedded into a TAnchorDockHostSite.
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure ManualFloat(AControl: TControl);
 
procedure ManualFloat(AControl: TControl);
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 228: Line 296:
 
You can give as parameter a TAnchorDockHostSite or a control embedded into a TAnchorDockHostSite (for example a form made dockable with MakeDockable). The site will be put at the same screen location.
 
You can give as parameter a TAnchorDockHostSite or a control embedded into a TAnchorDockHostSite (for example a form made dockable with MakeDockable). The site will be put at the same screen location.
  
==Save layout==
+
===Save layout===
  
 
The DockMaster allows to save the current layout to a TConfigStorage. The miniide example uses the xml version:
 
The DockMaster allows to save the current layout to a TConfigStorage. The miniide example uses the xml version:
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure TMainIDE.SaveLayout(Filename: string);
 
procedure TMainIDE.SaveLayout(Filename: string);
 
var
 
var
Line 257: Line 325:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Load layout==
+
===Load layout===
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure TMainIDE.LoadLayout(Filename: string);
 
procedure TMainIDE.LoadLayout(Filename: string);
 
var
 
var
Line 284: Line 352:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Enlarge/Shrink==
+
===Enlarge/Shrink===
  
 
The anchor docking manager can enlarge/shrink docked neighbors. This is done via the popup menu of the dock header or in code with the function '''DockMaster.ManualEnlarge''':
 
The anchor docking manager can enlarge/shrink docked neighbors. This is done via the popup menu of the dock header or in code with the function '''DockMaster.ManualEnlarge''':
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
function ManualEnlarge(Site: TAnchorDockHostSite; Side: TAnchorKind; OnlyCheckIfPossible: boolean): boolean;
 
function ManualEnlarge(Site: TAnchorDockHostSite; Side: TAnchorKind; OnlyCheckIfPossible: boolean): boolean;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 305: Line 373:
 
[[Image:Anchordocking before enlarge2.png]] becomes [[Image:Anchordocking after enlarge2.png]]
 
[[Image:Anchordocking before enlarge2.png]] becomes [[Image:Anchordocking after enlarge2.png]]
  
==General docking options==
+
===General docking options===
  
 
The AnchorDocking package provides a dialog to setup some of the properties of the DockMaster. The dialog is in the unit AnchorDockOptionsDlg and you can use it simply:
 
The AnchorDocking package provides a dialog to setup some of the properties of the DockMaster. The dialog is in the unit AnchorDockOptionsDlg and you can use it simply:
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
uses ... AnchorDockOptionsDlg;
 
uses ... AnchorDockOptionsDlg;
 
...
 
...
Line 322: Line 390:
 
This will add a new menu item to the popup menus of the dock headers and pages called ''Docking options''.
 
This will add a new menu item to the popup menus of the dock headers and pages called ''Docking options''.
  
=Docking in the IDE=
+
==Why use Anchors instead of Align?==
 
 
There is a package '''AnchorDockingDsgn''' to make the IDE windows dockable (lazarus/components/anchordocking/design/anchordockingdsgn.lpk).
 
Uninstall any other docking manager (e.g. easydockmgrdsgn).
 
 
 
After you installed the package and restarted the IDE, the IDE starts docked with a default layout. You can change the layout. You can drag and dock the headers (the bars at the top or left of each window), resize via splitters or window borders and right click on the dock headers to get even more functions.
 
 
 
You can save the layout via the menu item '''Tools / Save window layout as default'''. This saves to ~/.lazarus/anchordocklayout.xml and restores it when the IDE starts up.
 
 
 
You can also save the layout to a file and load them later.
 
 
 
Since Lazarus 1.1 you can pass a command line parameter
 
 
 
./lazarus --anchordocklayout=<filename>
 
 
 
Here is an example of what a docked IDE looks like on Windows 7:
 
[[File:Laz_IDE_v1.2.6_Docked.png]]
 
 
 
=Why use Anchors instead of Align?=
 
  
 
Anchors allow to create any possible rectangular layout. Align is limited. Align with Panels can theoretically create a lot of layouts, but still not all. And some operations like enlarge/shrink are more complicated using Align/Panels than using Anchors. Align works good for a few forms, but the more forms are docked, the more the disadvantages of Align become visible.
 
Anchors allow to create any possible rectangular layout. Align is limited. Align with Panels can theoretically create a lot of layouts, but still not all. And some operations like enlarge/shrink are more complicated using Align/Panels than using Anchors. Align works good for a few forms, but the more forms are docked, the more the disadvantages of Align become visible.
  
 
+
===Layouts that can be created with Align===
==Layouts that can be created with Align==
 
 
Align can only create the following layouts:
 
Align can only create the following layouts:
  
Line 352: Line 401:
 
The alTop controls are always at the top, filling the whole horizontal width. That's because the LCL first aligns all controls with alTop, then all alBottom, then alLeft, then alRight and finally alClient.
 
The alTop controls are always at the top, filling the whole horizontal width. That's because the LCL first aligns all controls with alTop, then all alBottom, then alLeft, then alRight and finally alClient.
  
==Layouts that can be created with Align and Panels==
+
===Layouts that can be created with Align and Panels===
 
It is possible to nest Align layouts by using hidden panels. Then any layout that can be recursively splitted in halves can be created. Then you can create for example:
 
It is possible to nest Align layouts by using hidden panels. Then any layout that can be recursively splitted in halves can be created. Then you can create for example:
  
Line 359: Line 408:
 
This requires only one hidden panel.
 
This requires only one hidden panel.
  
==Changing Layouts==
+
===Changing Layouts===
 
Now the user wants to enlarge the ''FPDocEditor'' horizontally (and shrink ''CodeExplorer''). With the ''AnchorDocking'' you can simply right click on the ''FPDocEditor'' header and click '''Enlarge right side'''.
 
Now the user wants to enlarge the ''FPDocEditor'' horizontally (and shrink ''CodeExplorer''). With the ''AnchorDocking'' you can simply right click on the ''FPDocEditor'' header and click '''Enlarge right side'''.
  
Line 366: Line 415:
 
Other docking engines need at least 2 panels. One for ''SrcEditor'',''Messages'',''FPDocEdit'',''CodeExpl'' and one for ''SrcEdit'' and ''Messages''. Most docking layouters do not even provide a simple way to change the layout in this way. An algorithm to allow this layout change, must analyze the whole structure as if there were no panels and must reparent a lot of things. Basically the algorithm must do the same as the anchor docking algorithm, but with the extra work of translating the layout into Align plus hidden panels.
 
Other docking engines need at least 2 panels. One for ''SrcEditor'',''Messages'',''FPDocEdit'',''CodeExpl'' and one for ''SrcEdit'' and ''Messages''. Most docking layouters do not even provide a simple way to change the layout in this way. An algorithm to allow this layout change, must analyze the whole structure as if there were no panels and must reparent a lot of things. Basically the algorithm must do the same as the anchor docking algorithm, but with the extra work of translating the layout into Align plus hidden panels.
  
==Layouts that are impossible with Align and Panels==
+
===Layouts that are impossible with Align and Panels===
 
Now the user wants to enlarge ''SourceEditor1'' horizontally (and shrink ''ObjectInspector''):
 
Now the user wants to enlarge ''SourceEditor1'' horizontally (and shrink ''ObjectInspector''):
  
Line 375: Line 424:
 
[[Image:Anchordocking impossible with align panels2.png]]
 
[[Image:Anchordocking impossible with align panels2.png]]
  
==Conclusion==
+
===Conclusion===
Align with hidden panels allows to easily create a simple docking manager that works good for a few forms. But it will always limit the user. Align is useful for row and column layouts, not for tables. Anchor docking works even for complex forms.
+
Align with hidden panels allows you to easily create a simple docking manager that works well for a few forms, but it will always limit the user. Align is useful for row and column layouts, not for tables. Anchor docking works even for complex forms.
 +
 
 +
==Old/deprecated anchor docking==
  
=Old/deprecated anchor docking=
+
===Create a TLazDockingManager===
  
==Create a TLazDockingManager==
+
<syntaxhighlight lang=pascal>
<syntaxhighlight>
 
 
   DockingManager:=TLazDockingManager.Create(Self);
 
   DockingManager:=TLazDockingManager.Create(Self);
 
</syntaxhighlight>
 
</syntaxhighlight>
 
The Self as parameter is only used as Owner. That means, when the mainform is freed, the DockingManager is freed too. You can use ''nil'' and free the DockingManager yourself.
 
The Self as parameter is only used as Owner. That means, when the mainform is freed, the DockingManager is freed too. You can use ''nil'' and free the DockingManager yourself.
  
==Optional: Loading a configuration==
+
===Optional: Loading a configuration===
 +
 
 
You can load the user configuration from disk.
 
You can load the user configuration from disk.
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   Config:=TXMLConfigStorage.Create('config.xml',true);
 
   Config:=TXMLConfigStorage.Create('config.xml',true);
 
   DockingManager.LoadFromConfig(Config);
 
   DockingManager.LoadFromConfig(Config);
Line 395: Line 446:
 
This loads the file ''config.xml''. The config can be created by the SaveToConfig function. See below.
 
This loads the file ''config.xml''. The config can be created by the SaveToConfig function. See below.
  
==Make a form/control dockable==
+
===Make a form/control dockable===
 +
 
 
Create a TLazControlDocker for each form/control that should be dockable
 
Create a TLazControlDocker for each form/control that should be dockable
<code>
+
<syntaxhighlight lang=pascal>
 
   ControlDocker1:=TLazControlDocker.Create(Self);
 
   ControlDocker1:=TLazControlDocker.Create(Self);
 
   ControlDocker1.Name:='DockerForm1';
 
   ControlDocker1.Name:='DockerForm1';
 
   ControlDocker1.Manager:=DockingManager;
 
   ControlDocker1.Manager:=DockingManager;
</code>
+
</syntaxhighlight>
 +
 
 +
===Optional: Saving the user configuration to disk===
  
==Optional: Saving the user configuration to disk==
 
 
When the program is closed you can save the user configuration to disk
 
When the program is closed you can save the user configuration to disk
<code>
+
<syntaxhighlight lang=pascal>
 
   Config:=TXMLConfigStorage.Create('config.xml',true);
 
   Config:=TXMLConfigStorage.Create('config.xml',true);
 
   DockingManager.SaveToConfig(Config);
 
   DockingManager.SaveToConfig(Config);
 
   Config.WriteToDisk;
 
   Config.WriteToDisk;
 
   Config.Free;
 
   Config.Free;
</code>
+
</syntaxhighlight>
  
=Links=
+
==See also==
  
* [[AnchorDockingStepbystepexample | Anchor Docking: A Step by step example]]
+
* [[AnchorDockingDsgn]] AnchorDocking in the Lazarus IDE
 +
* [[Anchor Docking Step by step example | Anchor Docking: A Step by step example]]
 
* [[Docking]] in general
 
* [[Docking]] in general
* [[EasyDockingManager]] - an alternative docking implementation with a simpler layout engine and less options.
+
* [[EasyDockingManager]] - an alternative docking implementation with a simpler layout engine and fewer options.
  
 
[[Category:Docking]]
 
[[Category:Docking]]

Latest revision as of 06:44, 7 December 2021

English (en) русский (ru) 中文(中国大陆)‎ (zh_CN)

About docking in general see Docking.

Overview

Docking allows you to combine forms, or to treat controls as forms. You use the mouse to drag and dock forms together or undock (split) them. The basic dragging, docking and undocking functionality is provided by the LCL. But you need a docking manager to add splitters and grab zones, and to save and restore layouts.

Anchor docking has been implemented since version 0.9.29 in the package anchordocking.lpk for use in your own Lazarus applications, and AnchorDockingDsgn.lpk if you wish to make the Lazarus IDE windows dockable. It is easy to use, and provides many features and options not available in earlier docking packages.

You will find a code example at: components/anchordocking/miniide/miniide1.lpi

This means that the earlier TLazDockingManager and unit LDockCtrl are obsolete and now deprecated.

Features

  • Drag and dock: Headers are added that can be dragged to dock controls with the mouse. Preview rectangles will show where and how a control is docked.
  • Any layout: By using the LCL's anchors almost any layout is possible. You can dock to left, right, top, bottom, inside or outside or as page like in a TPageControl. You can enlarge docked controls via the popup menu. No need to undock your whole layout.
  • What you see is how it is structured: There are no hidden panels to align controls in rows and columns. Anchor docking makes sure forms do not overlap.
  • Splitters are automatically inserted between docked forms to allow resizing.
  • Page docking. Forms can be docked not only left/right/above/below, but in pages too. A TPageControl is automatically created for native look and feel. A page can contain arbitrary docked forms too, including paged docked forms, allowing nested pages and layouts. When a page is undocked the pagecontrol is automatically removed. You can drag and drop the tabs or use the popup menu to move pages.
  • Easy use: With one line of code you can make a form or control dockable. Just give them unique names.
  • Not only forms, but any TWinControl can be made dockable.
  • Can save/load layouts. The layout information is stored for each dockable control and old layout files will still work even when the application gets more dockable controls or some are removed. The information is stored in the abstract class LCL TConfigStorage. So you can use for example TXMLConfigStorage to store layouts in xml files or you can write your own storage to store it wherever you want.
  • Each docked form is put into a docksite providing an optional header. The header shows the caption of the docked form and contains a close button. You can drag the header to drag the form and undock it or to dock it at another position. The header can be at any of the four sides and moves by default automatically to the smaller side to save space. You can customize this. The header shows a customizable hint allowing to read long captions.
  • When a docksite is resized the child sites are automatically scaled. You can turn this off.
  • Preserve size of forms. For instance when docking a form to a left side of a site the width of the docked form is kept. The same for the other sides and the same for undocking.
  • Flickerless: The restore tries to reuse existing sites and splitters to reduce creation and flickering of forms and to preserve the Z order of forms. This allows to quickly switch between layouts.
  • Header popup menu:
    • lock/unlock (disable dragging)
    • header position (auto, left, top, right, bottom), this is saved/restored with the layout
    • merge (for example after moving a dock page into a layout)
    • undock (needed if no place to undock on screen)
    • enlarge side to left, top, right, bottom
    • close
    • options
  • Page popup menu:
    • lock/unlock (disable dragging)
    • undock (needed if no place to undock on screen)
    • tab position for pagecontrol (top,bottom, left, right), this is saved/restored with the layout
    • move page to the left, right, leftmost, rightmost
    • close
    • options
  • Forms can be made dock sites. Then they can dock at one side. But they can not be docked itself.
  • close button automatically saves a layout
  • Powerful functions to alter the layout. You can use D&D to move a form and you can undock and dock in one move. There are functions to enlarge forms and shrinking others. These functions are available via the header popup menu as well. See below.
  • There is an IDE package which makes the Lazarus IDE dockable. It is called anchordockingdsgn.lpk. Make sure you only install one docking package. Do not install the easydockmgr at the same time!

ToDos

  • Design time package: Add all layout files to menu
  • simple way to make forms dockable at designtime (that means without writing any code)
  • minimize button and Hide
  • on show again: restore a default layout
  • close button for pages
  • Implement automatic menu merging in the LCL (when two forms with main menus are docked).

Usage I. (Add docking support to the Lazarus IDE)

If you don't like the default "separate windows" look of the Lazarus IDE and prefer a single window (e.g., like RAD Studio™), you can install a package called AnchorDockingDsgn (lazarus/components/anchordocking/design/anchordockingdsgn.lpk). This package makes the IDE windows dockable.

Installation

Uninstall any other docking managers (e.g., easydockmgrdsgn). From the Lazarus main menu pick "Package" - "Install/Uninstall Packages" and install the "anchordockingdsgn" package.

After you have successfully installed the package and restarted the IDE, the IDE starts with a default docked layout like shown below. Note that AnchorDocking headers and splitters have been added to all dockable windows of the IDE. In case the headers don't get visible, see the section "Options" below on how to enable/disable them.

2021-12-02 10 21 07-Debian 10.8 Buster - VMware Workstation.png

You can change the layout by grabbing a dockable window by the Anchordocking header and drag and dock it anywhere else, or resize docked windows via splitters added to the window borders. You can right-click on the headers too for other options, for example, to change the look of the headers, as shown farther down below.

You can save the layout via the menu item Tools / Save window layout as default. This saves to ~/.lazarus/anchordocklayout.xml and restores it when the IDE starts up.

You can also save the layout to a file and load them later.

Since Lazarus 1.1 you can pass a command line parameter

./lazarus --anchordocklayout=<filename>

The look (like the headers) can be further tweaked by right-clicking on them.

docking headers.gif

Options

After the successful installation of the AnchorDockingDsgn package, an additional configuration menu is added to the Lazarus options dialog ("Tools" - "Options" - "Environment")

anchordocking options.png

Scale on resize

When resizing a window, all docked forms inside are scaled by the same percentage.

Show headers

To dock/undock a window, you need to enable this option.

Flatten headers

No 3d frame in headers.

Header align top/left

Headers are automatically put at top or left depending on these two values:

  • Move header to top, when (width/height)*100<=HeaderAlignTop, default 80
  • Move header to left, when (width/height)*100>=HeaderAlignLeft, default 120
  • Otherwise keep the header at the current position.

Which means the header is by default put at the smaller side of a docked control. When the control is resized, the header switches to the smaller side.

Allow dock sites to be minimized

A extra minimize button is added, so a site can be minimized. Then sites next to it get more space. If needed, the minimized site then can easy be opened.

Multine Tabs

Feature added in Lazarus 2.2. If a OS support multiline tabs (like Windows), if there are no many tabs, they are shown in multiple lines.

Floating windows on top

Feature added in Lazarus 2.2. If there are undocked windows shown, show these on top of main window. In a own application, there can be set DockMaster.MainDockForm, then all floating windows are shown on top of it. If MainDockForm is not set, Application.MainForm is used.

Usage II. (Add docking support to your own applications)

Quick start

Add the package AnchorDocking to the required packages in the project inspector.

Then add the unit AnchorDocking to the uses section of your main unit (the unit with your main form).

Add to the FormCreate of your main form:

  DockMaster.MakeDockSite(Self,[akBottom],admrpChild);

For the other dockable forms replace all calls of Show and ShowOnTop with

  DockMaster.MakeDockable(Form1,true,true);

For the other dockable forms replace all calls of Visible:=true with

  DockMaster.MakeDockable(Form1,true);

Remove or comment all Hide, Visible:=false, WindowState:= calls.

Prerequisites

  • Your project must use the package AnchorDocking.
  • All dockable forms must be shown with MakeDockable or MakeDockSite. Do not use Show, BringToFront, ShowOnTop, Visible:=true. Of course you can have some non dockable forms, like hints or splashscreens.
  • All dockable forms must be free resizable, that means no constraints, no BorderStyle bsDialog.
  • No other docking system. AnchorDocking is incompatible with EasyDockMgr.

Making forms dockable

There are two ways to make a form dockable. You can use DockMaster.MakeDockable to wrap a form into a dock site. Then your form can dock and be docked completely free. You will use that for the biggest part of your forms, except for the MainForm, because this is only supported for the MainForm on gtk2 and qt. The second way is to use DockMaster.MakeDockSite. The form can dock other sites, but can not be docked itself. You might want to use MakeDockSite for the MainForm. For most other forms you probably want to use this:

// shows YourForm
// if not already done, wrap the form into a dock site
DockMaster.MakeDockable(YourForm);

Here are some examples how a form looks like that was made dockable with DockMaster.MakeDockable:

Docksite1.png Docksite2.png

The header position is normally done automatically and the user can with a right click put it to any of the four sides.

Example: miniide1

The example can be found in lazarus/components/anchordocking/miniide/miniide1.lpi. It has a mainform in unit unit1.pas with a main menu which works as a docksite and several forms that are dockable.

Anchordocking miniide1.png

Making the main form a dock site

In the TMainIDE.FormCreate the main form MainIDE is turned into a docksite:

DockMaster.MakeDockSite(Self,[akBottom],admrpChild);

The parameter [akBottom] allows to dock other sites at the bottom of MainIDE. The parameter admrpChild tells the DockMaster that when the MainIDE is enlarged the extra space is distributed to the docked sites.

When the user docks a site to the bottom of MainIDE the site is put onto MainIDE (Site.Parent:=MainIDE) with Site.Align=alBottom. The other controls on MainIDE must be compatible to this. MainIDE for example has a BtnPanel with Align=alLeft and a TNoteBook with Align=alClient. See here how Align works.

The DockMaster adds automatically a splitter:

Anchordocking miniide dockedse1.png

As soon as a dockable form is docked its caption is shown in the dock header.

Requirements for a custom dock site

As long as nothing is docked into a custom dock site, your form can do everything as a normal form. But when a site is docked to it, some properties and methods need special care:

  • AutoSize=true may result in an endless loop. Disable it or override DoAutoSize/CalculatePreferredSize and take special care.
  • Constraints: The DockMaster clears the maximum Constraints and will restore them on undock.
  • Child controls anchored to the aligned site may overlap. See here how Align works.
  • ChildSizing: The spacing properties like LeftRightSpacing, TopBottomSpacing may interfere with the docking layout.

Procedure to create all other forms by name

The MainIDE sets the DockMaster.OnCreateControl event, to enable the DockMaster to create forms by name. This is needed to restore layouts.

DockMaster.OnCreateControl:=@DockMasterCreateControl;
procedure TMainIDE.DockMasterCreateControl(Sender: TObject; aName: string; var
  AControl: TControl; DoDisableAutoSizing: boolean);

  procedure CreateForm(Caption: string; NewBounds: TRect);
  begin
    AControl:=CreateSimpleForm(aName,Caption,NewBounds,DoDisableAutoSizing);
  end;

begin
  // first check if the form already exists
  // the LCL Screen has a list of all existing forms.
  // Note: Remember that the LCL allows as form names only standard
  // pascal identifiers and compares them case insensitive
  AControl:=Screen.FindForm(aName);
  if AControl<>nil then begin
    // if it already exists, just disable autosizing if requested
    if DoDisableAutoSizing then
      AControl.DisableAutoSizing;
    exit;
  end;
  // if the form does not yet exist, create it
  if aName='CodeExplorer' then
    CreateForm('Code Explorer',Bounds(700,230,100,250))
  ...
  else if aName='DebugOutput' then
    CreateForm('Debug Output',Bounds(400,400,350,150));
end;

Creating a form can be as simple as this:

MyForm:=TMyForm.Create(Self);
if DoDisableAutoSizing then
  MyForm.DisableAutoSizing;

But of course you can put there all kind of initialization code.

The DisableAutoSizing reduces flickering. Make sure your forms Visible property is set to false.

Remember to call DisableAutoSizing for the form if the parameter DoDisableAutoSizing is set to true, because Disable- and EnableAutosizing calls must be balanced. If you miss the DisableAutosizing, the LCL will raise an exception later:

TControl.EnableAutoSizing SourceEditor1:TSimpleForm: missing DisableAutoSizing

MissingDisableAutoSizing.png

If you call DisableAutoSizing too much, your forms will not appear and/or not resize properly as the LCL is waiting for the EnableAutoSizing call that never comes.

Showing forms

When a form should be shown, you have probably used something like 'MyForm.Show. Instead you should now use

DockMaster.MakeDockable(MyForm);

This will wrap MyForm in a dock site and show it. It is clever enough to figure out if the form is already wrapped in a dock site.

If you set the DockMaster.OnCreateControl event you can use this:

DockMaster.ShowControl('MyForm',true);

Docking manually, via code

Use the procedure DockMaster.ManualDock to dock a site to or into another.

procedure ManualDock(SrcSite, TargetSite: TAnchorDockHostSite; Align: TAlign; TargetControl: TControl = nil);
  • SrcSite is the site to be docked. If SrcSite was docked it will be undocked first.
  • TargetSite is the site where SrcSite will be docked into or docked as neighbor.
  • TargetControl specifies if docking as neighbor (=nil), as inside neighbor (=TargetSide) or in front of a page (=a TAnchorDockPage).


Undocking manually, via code

Use the procedure DockMaster.ManualFloat to undock a site from its neighbors and create a flotaing top level form. The embedded control stays embedded into a TAnchorDockHostSite.

procedure ManualFloat(AControl: TControl);

You can give as parameter a TAnchorDockHostSite or a control embedded into a TAnchorDockHostSite (for example a form made dockable with MakeDockable). The site will be put at the same screen location.

Save layout

The DockMaster allows to save the current layout to a TConfigStorage. The miniide example uses the xml version:

procedure TMainIDE.SaveLayout(Filename: string);
var
  XMLConfig: TXMLConfigStorage;
begin
  try
    // create a new xml config file
    XMLConfig:=TXMLConfigStorage.Create(Filename,false);
    try
      // save the current layout of all forms
      DockMaster.SaveLayoutToConfig(XMLConfig);
      XMLConfig.WriteToDisk;
    finally
      XMLConfig.Free;
    end;
  except
    on E: Exception do begin
      MessageDlg('Error',
        'Error saving layout to file '+Filename+':'#13+E.Message,mtError,
        [mbCancel],0);
    end;
  end;
end;

Load layout

procedure TMainIDE.LoadLayout(Filename: string);
var
  XMLConfig: TXMLConfigStorage;
begin
  try
    // load the xml config file
    XMLConfig:=TXMLConfigStorage.Create(Filename,True);
    try
      // restore the layout
      // this will close unneeded forms and call OnCreateControl for all needed
      DockMaster.LoadLayoutFromConfig(XMLConfig);
    finally
      XMLConfig.Free;
    end;
  except
    on E: Exception do begin
      MessageDlg('Error',
        'Error loading layout from file '+Filename+':'#13+E.Message,mtError,
        [mbCancel],0);
    end;
  end;
end;

Enlarge/Shrink

The anchor docking manager can enlarge/shrink docked neighbors. This is done via the popup menu of the dock header or in code with the function DockMaster.ManualEnlarge:

function ManualEnlarge(Site: TAnchorDockHostSite; Side: TAnchorKind; OnlyCheckIfPossible: boolean): boolean;

Site is a child site, Side the side of Site to expand. If you only want to test if enlarge is possible set OnlyCheckIfPossible to true.

Enlarge one, shrink another

Shrink neighbor Object Inspector, enlarge Messages: Right click on the header of Messages and click on Enlarge right side. Two splitters are resized.

Anchordocking before enlarge1.png enlarging Messages to the right side: Anchordocking after enlarge1.png

Enlarge one, shrink many

Shrink splitter at one side, enlarge both neighbor splitters, rotate the splitter behind, enlarge Control, shrink controls at rotate splitter. Right click on header of Source Editor 1 then click on Enlarge bottom side.

Anchordocking before enlarge2.png becomes Anchordocking after enlarge2.png

General docking options

The AnchorDocking package provides a dialog to setup some of the properties of the DockMaster. The dialog is in the unit AnchorDockOptionsDlg and you can use it simply:

uses ... AnchorDockOptionsDlg;
...
procedure TMainIDE.FormCreate(Sender: TObject);
...
begin
  ...
  DockMaster.OnShowOptions:=@ShowAnchorDockOptions;
  ...
end;

This will add a new menu item to the popup menus of the dock headers and pages called Docking options.

Why use Anchors instead of Align?

Anchors allow to create any possible rectangular layout. Align is limited. Align with Panels can theoretically create a lot of layouts, but still not all. And some operations like enlarge/shrink are more complicated using Align/Panels than using Anchors. Align works good for a few forms, but the more forms are docked, the more the disadvantages of Align become visible.

Layouts that can be created with Align

Align can only create the following layouts:

Anchordocking align layout1.png

The alTop controls are always at the top, filling the whole horizontal width. That's because the LCL first aligns all controls with alTop, then all alBottom, then alLeft, then alRight and finally alClient.

Layouts that can be created with Align and Panels

It is possible to nest Align layouts by using hidden panels. Then any layout that can be recursively splitted in halves can be created. Then you can create for example:

Anchordocking align panels layout1.png

This requires only one hidden panel.

Changing Layouts

Now the user wants to enlarge the FPDocEditor horizontally (and shrink CodeExplorer). With the AnchorDocking you can simply right click on the FPDocEditor header and click Enlarge right side.

Anchordocking align panels layout2.png

Other docking engines need at least 2 panels. One for SrcEditor,Messages,FPDocEdit,CodeExpl and one for SrcEdit and Messages. Most docking layouters do not even provide a simple way to change the layout in this way. An algorithm to allow this layout change, must analyze the whole structure as if there were no panels and must reparent a lot of things. Basically the algorithm must do the same as the anchor docking algorithm, but with the extra work of translating the layout into Align plus hidden panels.

Layouts that are impossible with Align and Panels

Now the user wants to enlarge SourceEditor1 horizontally (and shrink ObjectInspector):

Anchordocking impossible with align panels1.png

This layout is impossible with Align and panels, because you can not cut it in two halves. The same with

Anchordocking impossible with align panels2.png

Conclusion

Align with hidden panels allows you to easily create a simple docking manager that works well for a few forms, but it will always limit the user. Align is useful for row and column layouts, not for tables. Anchor docking works even for complex forms.

Old/deprecated anchor docking

Create a TLazDockingManager

  DockingManager:=TLazDockingManager.Create(Self);

The Self as parameter is only used as Owner. That means, when the mainform is freed, the DockingManager is freed too. You can use nil and free the DockingManager yourself.

Optional: Loading a configuration

You can load the user configuration from disk.

  Config:=TXMLConfigStorage.Create('config.xml',true);
  DockingManager.LoadFromConfig(Config);
  Config.Free;

This loads the file config.xml. The config can be created by the SaveToConfig function. See below.

Make a form/control dockable

Create a TLazControlDocker for each form/control that should be dockable

  ControlDocker1:=TLazControlDocker.Create(Self);
  ControlDocker1.Name:='DockerForm1';
  ControlDocker1.Manager:=DockingManager;

Optional: Saving the user configuration to disk

When the program is closed you can save the user configuration to disk

  Config:=TXMLConfigStorage.Create('config.xml',true);
  DockingManager.SaveToConfig(Config);
  Config.WriteToDisk;
  Config.Free;

See also