LCL Drag Dock

From Free Pascal wiki
Revision as of 07:46, 21 April 2009 by DoDi (talk | contribs) (→‎DragDone)
Jump to navigationJump to search

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:

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

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

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

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

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.

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

Helper Methods

A bunch of helper methods and fields has been introduced into the TControl and TWinControl classes. The purpose of the methods is not always clear, and the Delphi implementation only happens to work under certain conditions, and with significant restrictions.

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.