Difference between revisions of "Anchor Docking"

From Lazarus wiki
Jump to navigationJump to search
(Adding a link to the step by step example)
Line 1: Line 1:
 
About docking in general see [[Docking]].
 
About docking in general see [[Docking]].
  
=Anchor Docking with TLazDockingManager=
+
=Overview=
  
The TLazDockingManager is part of the LCL and can be found unit LDockCtrl. It is not yet complete and therefore not yet part of the IDE component palette. An example can be found in
+
Anchor docking was implemented in the package ''examples/anchordocking/anchordocking.lpk'' (Since 0.9.29).
lazarus/examples/anchordocking/docking1.lpi.
 
  
[[Achor_Docking_Step_by_step_example | A step by step example]]
+
An example can be found in examples/anchordocking/miniide/miniide1.lpi
 +
 
 +
Obsolete: The old TLazDockingManager and unit LDockCtrl are deprecated. [[Achor_Docking_Step_by_step_example | A step by step example]]
  
 
==Features==
 
==Features==
  
*By using the LCL's anchors almost any layout is possible. It is for example not limited to the strict top/bottom/left/right order of the Align property.
+
*'''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.
*It does not use hidden panels. What you see is how it is structured.
+
*'''Any layout''': By using the LCL's anchors almost any layout is possible. You can dock to any left, right, top, bottom, inside, outside or as page like in a TPageControl.
*TSplitter are automatically inserted between docked forms
+
*'''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.
*Page docking. Forms can be docked not only left/right/above/below, but in pages too. A TPageControl is automatically created. A page can contain arbitrary docked forms too, including paged docked forms, allowing nested pages.
+
*'''Splitters''' are automatically inserted between docked forms to allow resizing.
*Easy use: Just drop a TLazControlDocker onto the form that should be dockable, give it an unique name and connect it to the TLazDockingManager.
+
*'''Page docking'''. Forms can be docked not only left/right/above/below, but in pages too. A TPageControl is automatically created. 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.
*Not only forms, but any TWinControl can be made dockable. (needs testing)
+
*'''Easy use''': With one line of code you can make a form or control dockable. Just give them a unique name.
*Popup menu: User interface via platform independent popup menu. TLazControlDocker adds by default a popup menu 'Docking' to the PopupMenu of the form. This menu item opens a dialog where the user can setup the docking.
+
*Not only forms, but any '''TWinControl''' can be made dockable.
*Easy docking via code. For example dock Form2 left of Form1:
+
*Can ''save/load layouts'' from/to xml config files. The layout information is stored for each dockable control and if the application gets more or less dockable controls the old layout files will still work.  
  DockingManager.Manager.InsertControl(Form2,alLeft,Form1);
+
*Each docked form is put into a docksite providing a '''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.
*Can save/load layouts from/to xml config files. The layout information is stored for each dockable control and if the application gets more or less dockable controls the old layout will still work.  
+
*The header can be at any of the four site and moves by default automatically to the smaller site to safe space. You can customize this.
*Dynamic and automatic restore layout algorithm. The layout is restored when a control is shown. That means no matter when or how a form is shown, the docking manager will automatically dock it according to the last known layout of this form. It will automatically resize the neighborhood. (already works for many layouts, needs some improvements for complex cases).
+
*The header shows a customizable hint to read even long captions.
 +
*Page docking uses TPageControl for native look and feel
 +
*When a docksite is resized the child sites are scaled. You can turn this off.
 +
*'''Preserve size of forms'''. When docking a form to a left side of docksite the width 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.
 +
 
  
 
==ToDos==
 
==ToDos==
  
*Improve and harden the restore algorithm until it is good enough for the IDE.
+
*Write examples and docs
 +
*i18n
 +
*Write a design time package for the IDE
 +
*Easy docking via code
 +
*Undock: remove spiral splitter
 +
*popup menu
 +
**header auto, left, top, right, bottom
 +
**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
 +
**shrink side left, top, right, bottom
 +
**options
 +
**lock/unlock
 +
**close (for pages)
 +
**tab position (default, left, top, right, bottom)
 +
*simple way to make forms dockable at designtime
 +
*move page index via dnd
 +
*move page to another pagecontrol via dnd
 +
*minimize button and Hide
 +
*close button: save a default layout
 +
*on show again: restore a default layout
 +
*close button for pages
 
*Implement automatic menu merging in the LCL.
 
*Implement automatic menu merging in the LCL.
*Fix the winapi widgetset for docked forms.
 
*Write examples and docs
 
*Add it to the IDE component palette
 
*Implement drag and drop docking.
 
  
 
=Usage=
 
=Usage=

Revision as of 16:54, 8 June 2010

About docking in general see Docking.

Overview

Anchor docking was implemented in the package examples/anchordocking/anchordocking.lpk (Since 0.9.29).

An example can be found in examples/anchordocking/miniide/miniide1.lpi

Obsolete: The old TLazDockingManager and unit LDockCtrl are deprecated. A step by step example

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 any left, right, top, bottom, inside, outside or as page like in a TPageControl.
  • 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. 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.
  • Easy use: With one line of code you can make a form or control dockable. Just give them a unique name.
  • Not only forms, but any TWinControl can be made dockable.
  • Can save/load layouts from/to xml config files. The layout information is stored for each dockable control and if the application gets more or less dockable controls the old layout files will still work.
  • Each docked form is put into a docksite providing a 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 site and moves by default automatically to the smaller site to safe space. You can customize this.
  • The header shows a customizable hint to read even long captions.
  • Page docking uses TPageControl for native look and feel
  • When a docksite is resized the child sites are scaled. You can turn this off.
  • Preserve size of forms. When docking a form to a left side of docksite the width 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.


ToDos

  • Write examples and docs
  • i18n
  • Write a design time package for the IDE
  • Easy docking via code
  • Undock: remove spiral splitter
  • popup menu
    • header auto, left, top, right, bottom
    • 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
    • shrink side left, top, right, bottom
    • options
    • lock/unlock
    • close (for pages)
    • tab position (default, left, top, right, bottom)
  • simple way to make forms dockable at designtime
  • move page index via dnd
  • move page to another pagecontrol via dnd
  • minimize button and Hide
  • close button: save a default layout
  • on show again: restore a default layout
  • close button for pages
  • Implement automatic menu merging in the LCL.

Usage

Create a TLazDockingManager

<DELPHI>

 DockingManager:=TLazDockingManager.Create(Self);

</DELPHI> 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. <DELPHI>

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

</DELPHI> 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 <DELPHI>

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

</DELPHI>

Optional: Saving the user configuration to disk

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

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

</DELPHI>

Enlarge/Shrink

The anchor docking manager can enlarge/shrink docked neighbors. This is done via the function TAnchoredDockManager.EnlargeControl.

Enlarge one, shrink another

Shrink one neighbor control, enlarge Control. Two splitters are resized.

     |#|         |#         |#|         |#
     |#| Control |#         |#|         |#
   --+#+---------+#   --> --+#| Control |#
   ===============#       ===#|         |#
   --------------+#       --+#|         |#
       A         |#        A|#|         |#
   --------------+#       --+#+---------+#
   ==================     ===================

Enlarge one, shrink many

Move one neighbor splitter, enlarge Control, resize one splitter, rotate the other splitter.

     |#|         |#|          |#|         |#|
     |#| Control |#|          |#|         |#|
   --+#+---------+#+--  --> --+#| Control |#+--
   ===================      ===#|         |#===
   --------+#+--------      --+#|         |#+--
           |#|   B            |#|         |#|B
           |#+--------        |#|         |#+--
       A   |#=========       A|#|         |#===
           |#+--------        |#|         |#+--
           |#|   C            |#|         |#|C
   --------+#+--------      --+#+---------+#+--
   ===================      ===================

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:

 +------------------------------------------+
 |      alTop                               |
 +------------------------------------------+
 +------------------------------------------+
 |      alTop                               |
 +------------------------------------------+
 +------++------++--------++-------++-------+
 |alLeft||alLeft||alClient||alRight||alRight|
 +------++------++--------++-------++-------+
 +------------------------------------------+
 |      alBottom                            |
 +------------------------------------------+
 +------------------------------------------+
 |      alBottom                            |
 +------------------------------------------+

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:

 +--++-------++---+
 |  ||   B   ||   |
 |  |+-------+|   |
 |A |+-------+| E |
 |  ||   C   ||   |
 |  |+-------+|   |
 |  |+-------+|   |
 |  ||   D   ||   |
 +--++-------++---+

This requires only one hidden panel.

Changing Layouts

Now the user wants to enlarge D horizontally (and shrink E):

 +--++-------++---+
 |  ||   B   ||   |
 |  |+-------+|   |
 |A |+-------+| E |
 |  ||   C   ||   |
 |  |+-------++---+
 |  |+------------+
 |  ||   D        |
 +--++------------+

Now you need 3 panels. One for B,C,D,E, one for B,C,E and one for B,C. 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 B horizontally (and shrink A):

 +-----------++---+
 |    B      ||   |
 +-----------+|   |
 +--++-------+| E |
 |A ||   C   ||   |
 |  |+-------++---+
 |  |+------------+
 |  ||   D        |
 +--++------------+

This layout is impossible with Align and panels. The same with

  +-----------++--------------+
  |    A      ||              |
  +-----------+|      B       |
  +-----++----+|              |
  |     ||    |+--------------+
  |     || D  |+----++--------+
  |  C  ||    ||  E ||        |
  |     |+----++----+|   F    |
  |     |+----------+|        |
  |     ||    G     ||        |
  +-----++----------++--------+

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.