Difference between revisions of "LCL Drag Dock"

From Lazarus wiki
Jump to navigationJump to search
Line 27: Line 27:
 
* Dock rectangles as visual feedback
 
* Dock rectangles as visual feedback
 
* Dock managers
 
* Dock managers
 +
The introduction of dock managers opened a can of worms, with poor integration into the unmanaged docking model. Let's ignore [[LCL Managed Docking|"managed" docking]] for now, and consider only "unmanaged" docking.
  
 
=== Dock Source ===
 
=== Dock Source ===
Line 40: Line 41:
  
 
An application can create other forms for floating controls, so that e.g. multiple controls can be docked into and out of such a form.
 
An application can create other forms for floating controls, so that e.g. multiple controls can be docked into and out of such a form.
 
=== Dock Manager ===
 
The layout of a dock site usually is managed in some way. A default DockManager is installed in the dock site, when its '''UseDockManager''' property is set to True. Application code can install different dock managers into every TWinControl.
 
 
Such a manager handles the visible arrangement of the dropped controls, and the visual feedback and final placement for dragged controls.
 
 
==== Not Using an DockManager ====
 
When UseDockManager is False, a dock site will reject all drops by default. The application can respond to an OnDockOver event, to signal acceptance and placement of a dragged control.
 
 
This seems to be the original docking mode, with a complicated but logically correct implementation. The addition of docking managers instead is full of flaws.
 
 
==== Implementation Problems ====
 
The Delphi IDockManager interface has an serious flaw: instead of passing the DragDockObject to the DockManager methods, the methods receive only selected parameters with read-only access. This will e.g. disallow the DragManager to determine the DropAlign and to place dropped controls accordingly.
 
 
Most actions in DragTo should be handled immediately and only by the DragManager, bypassing any other handling in the drag manager and dock sites. Then the DockManager could call helper methods as really appropriate, not bound to the flawed Delphi implementation.
 
  
 
=== The DockRect ===
 
=== The DockRect ===
Usually a rectangular shape follows the mouse pointer in a docking operation, to distinguish it from a drag-drop operation. The difference becomes obvious when the mouse hovers over a dock site. Then the shape snaps to a possible drop location, in both position and size.
+
As in drag-drop operations, a rectangular shape follows the mouse pointer in a docking operation. But the docking rectangle can change it's size and position dynamically, to signal the position and size of the control when it is dropped in the current place.
 
 
The docking model assumes that dragged controls are docked relative to some target control, reflected in the '''DropOnControl''' and '''DropAlign''' properties of the DockObject. Accordingly the Delphi implementation searches for a target control, at the mouse position in the dock site, and determines the insertion place from the nearest edge of that control (alLeft, alRight, alTop, alBottom). When the dock site is empty, DropAlign is set to alClient.
 
  
Then the DockRect is placed according to the DropAlign, in the left/right/top/bottom half of the DropOnControl. In the Delphi implementation the DockManager or an OnDockOver handler can override the placement of the DockRect, but the DockManager can not change the DropAlign.
+
When no accepting dock site could be found, or when the user denies an drop by holding down the Ctrl key, the DockRect reflects the floating size and position of the dragged control. The floating size is initialized to the original size of the dragged control, and is updated when the control is floated. Otherwise the dock site can determine the placement and size of the dropped control.
 
 
When no accepting dock site could be found, or when the user denies an drop by holding down the Ctrl key, the DockRect reflects the floating size and position of the dragged control (DockTrackNoTarget).
 
  
 
The Delphi implementation remembers the coordinates of a drawn DockRect, in EraseDockRect, so that the old frame can be removed from the screen by an XOR paint, whenever required.
 
The Delphi implementation remembers the coordinates of a drawn DockRect, in EraseDockRect, so that the old frame can be removed from the screen by an XOR paint, whenever required.
Line 73: Line 55:
 
The inherited DragTarget is the target dock site in docking. The added DropOnControl and DropAlign properties indicate where and how the dragged control shall be positioned relative to an already docked control.
 
The inherited DragTarget is the target dock site in docking. The added DropOnControl and DropAlign properties indicate where and how the dragged control shall be positioned relative to an already docked control.
  
=== Helper Methods ===
+
=== Helpers ===
A bunch of helper methods and fields has been introduced into the TControl and TWinControl classes.
+
A bunch of helper methods and fields has been introduced into the TControl and TWinControl classes, for the internal management of docked controls and the customization of the docking process. Most of these helpers play a dedicated role in the process of docking, and will be described in the work flow below.
The purpose of the methods is not always clear, and the Delphi implementation only happens to work under certain conditions, and with significant restrictions.
+
 
 +
(placeholder for descriptions of general items)
 +
 
 +
== Work Flow ==
 +
This is the detailed description of the required actions, before, during, and after a control is docked.
 +
 
 +
=== Prerequisites ===
 +
A control is made dockable by setting its DragKind to dkDock. Nothing else is required for a dock source.
 +
 
 +
A global list holds all dock sites in an application. Dock sites are added and removed from this list, when their DockSite property changes.
  
 
==== RegisterDockSite ====
 
==== RegisterDockSite ====
Line 82: Line 73:
 
==== GetSiteInfo ====
 
==== GetSiteInfo ====
 
The TWinControl.GetSiteInfo method returns an influence (catching) rectangle, associated with the dock site. This convention allows to e.g. hide empty dock sites in the GUI, without making them unreachable for dropping. The default implementation returns the visible control extent, increased by an certain amount in either direction.
 
The TWinControl.GetSiteInfo method returns an influence (catching) rectangle, associated with the dock site. This convention allows to e.g. hide empty dock sites in the GUI, without making them unreachable for dropping. The default implementation returns the visible control extent, increased by an certain amount in either direction.
 +
 +
=== DragInit ===
 +
Docking starts automatically when a control has DragKind=dkDock and DragMode=dmAutomatic, and the left mouse button is pressed on that control. A TControl provides a BeginAutoDrag method for this case, and a BeginDrag method for an programmatical start when DragMode=dmManual.
 +
 +
A DockObject is created, either by the OnDockStart handler of the source control, or by the drag manager when no such object was provided.
 +
 +
The input capture is moved to the control, or to it's TWinControl parent, when the control cannot receive system (Windows) messages.
 +
...

Revision as of 10:16, 21 April 2009

Controls or entire forms in a GUI can be glued together and detached again, by dragging them around with the mouse. Such docking is similar to drag-drop, but differs in some aspects.

Procedure

A docking operation is organized just as any other dragging operation.

DragInit

On start of a docking operation the visual feedback has to be initialized, as usual.

DragTo

On a move a couple of steps have to be taken:

  • Whether the user doesn't want to dock at all
  • Determination of possible target sites
  • Determination of the precise drop zone
  • Visual feedback

DragDone

On a drop, several reasons can block docking, It's hard to justify why a dock site should deny to undock the dragged control when it finally is dropped. The following cases can occur:

  • The control is docked into the new dock site.
  • The dragged control becomes floating
    • as is, if it was already floating, or when it can float for itself (is a TWinControl),
    • or wrapped into a new floating form.
  • The entire operation is aborted.

Docking Elements Overview

In addition to the drag-drop players, some more players enter the scene:

  • Dock sites
  • Dock rectangles as visual feedback
  • Dock managers

The introduction of dock managers opened a can of worms, with poor integration into the unmanaged docking model. Let's ignore "managed" docking for now, and consider only "unmanaged" docking.

Dock Source

A control or form can be made dockable by setting its DragKind property to dkDock.

Dock Sites

Docking requires special drop target zones, called dock sites. A TWinControl becomes a docking target by setting its DockSite property to True.

Docked controls reside in a distinct member array, separated from other components on the container control. For proper behaviour it's highly recommended to have no other controls in a dock site initially, and populate it only with docked controls.

Floating Dock Sites

Another kind of dock sites are used for undocked (floating) controls. When a control is dropped outside a dock site, and it is not a TWinControl, a new form is created for it at the drop location. When the floating control later is docked into a dock site, the floating form is destroyed.

An application can create other forms for floating controls, so that e.g. multiple controls can be docked into and out of such a form.

The DockRect

As in drag-drop operations, a rectangular shape follows the mouse pointer in a docking operation. But the docking rectangle can change it's size and position dynamically, to signal the position and size of the control when it is dropped in the current place.

When no accepting dock site could be found, or when the user denies an drop by holding down the Ctrl key, the DockRect reflects the floating size and position of the dragged control. The floating size is initialized to the original size of the dragged control, and is updated when the control is floated. Otherwise the dock site can determine the placement and size of the dropped control.

The Delphi implementation remembers the coordinates of a drawn DockRect, in EraseDockRect, so that the old frame can be removed from the screen by an XOR paint, whenever required.

The DockObject

A special DockObject is used in a docking operation, derived from TDragObject. It's unclear why this class introduces new methods, instead of overriding the existing virtual methods for the different visual feedback.

The inherited DragTarget is the target dock site in docking. The added DropOnControl and DropAlign properties indicate where and how the dragged control shall be positioned relative to an already docked control.

Helpers

A bunch of helper methods and fields has been introduced into the TControl and TWinControl classes, for the internal management of docked controls and the customization of the docking process. Most of these helpers play a dedicated role in the process of docking, and will be described in the work flow below.

(placeholder for descriptions of general items)

Work Flow

This is the detailed description of the required actions, before, during, and after a control is docked.

Prerequisites

A control is made dockable by setting its DragKind to dkDock. Nothing else is required for a dock source.

A global list holds all dock sites in an application. Dock sites are added and removed from this list, when their DockSite property changes.

RegisterDockSite

Dock sites can be covered partially or entirely by other forms, but shall act as docking targets in any case. This procedure registers and unregisters controls in an application as dock sites, so that even hidden candidates can be found while dragging a dock source over the screen.

GetSiteInfo

The TWinControl.GetSiteInfo method returns an influence (catching) rectangle, associated with the dock site. This convention allows to e.g. hide empty dock sites in the GUI, without making them unreachable for dropping. The default implementation returns the visible control extent, increased by an certain amount in either direction.

DragInit

Docking starts automatically when a control has DragKind=dkDock and DragMode=dmAutomatic, and the left mouse button is pressed on that control. A TControl provides a BeginAutoDrag method for this case, and a BeginDrag method for an programmatical start when DragMode=dmManual.

A DockObject is created, either by the OnDockStart handler of the source control, or by the drag manager when no such object was provided.

The input capture is moved to the control, or to it's TWinControl parent, when the control cannot receive system (Windows) messages. ...