LCL Drag Dock

From Lazarus wiki
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:

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