LCL Drag Drop

From Lazarus wiki
Revision as of 22:05, 17 April 2009 by DoDi (talk | contribs) (Restructured)
Jump to navigationJump to search

English (en) français (fr) русский (ru)

DoDi's Guide to Dragging, Dropping and Docking

Controls can be grabbed with the mouse, dragged to other locations, and dropped onto other controls or onto the desktop. When the dragged control is moved to a different location, the operation is called "docking". Otherwise the source and target control can exchange information or interact in any other way, what's called a "drag-drop" operation.

But all that does'n work by itself, an application must set up the allowed operations so that the LCL can know what to do with every single control in a GUI. Sophisticated operations require further code for managing the visual feedback to the application user, and what will happen when the dragged control finally is dropped.

Drag Drop

This is the simple and originally only dragging action. The players are:

  • A draggable source control in the GUI
  • A drag object, derived from TDragObject
  • Helper functions
  • Events

Now let's have a look at how these are working together, based on the original Delphi implementation for clarity. The LCL implementation is somewhat different in the use of helper objects, details will be discussed later.

The Drag Source

A control can be made draggable by setting its DragMode property to dmAutomatic. When the user presses the left mouse button over such a control, the mouse pointer changes into an dragging indicator until the user releases the button, or cancels the operation by pressing the Escape key. The indicator now follows the mouse movements and changes its shape, according to what will happen when the control is dropped in the current location.

Dragging also can be started in code, by calling source.BeginDrag. In either case the helper procedure DragInitControl (LCL: TDragManager.DragStart) is called to start dragging. The source control raises an StartDrag event, where the application can provide a custom drag object. If no such object is provided, a default object is created. Internal data structures for visual feedback and more are initialized. Then DragTo is called to show that dragging has started.

The Drag Object

A drag object receives all user input while dragging. In the default implementation it reacts by calling either DragTo or finally DragDone.

The drag object also is responsible for the visual feedback:

  • GetDragCursor returns the mouse pointer shape.
  • GetDragImages returns a list of drag images, to be attached to the mouse pointer.
  • ShowDragImage and HideDragImage implement the visual feedback.

The Finished method notifies the source control when dragging stops. In case of a cancel'd operation it invokes source.DragCanceled, followed by source.DoEndDrag in either case, which raises an EndDrag event.

LCL Modifications

The current LCL implementation has removed input processing from the drag object, so that the application can no more customize the UI. And the LCL implementation is far from being okay :-(

Also the drag object is bypassed in the presentation of the visual feedback.

Helper Functions

Events

Common Principles

A control can be made draggable by setting its DragMode property to dmAutomatic. When the user presses the left mouse button over such a control, the mouse pointer changes into an dragging indicator until the user releases the button, or cancels the operation by pressing the Escape key. The indicator now follows the mouse movements and changes its shape, according to what will happen when the control is dropped in the current location. All that is managed by a DragManager, in cooperation with the source and target controls. The desired action is given in the DragKind property of the source control, which can be either dkDrag for drag-drop or dkDock for docking.

Sometimes dragging shall not be started immediately, so that a control can be clicked for it's "natural" operation. This can be achieved in two ways: Mouse.DragImmediate affects all dragging operations, otherwise dragging can be started in the OnMouseDown (or any other) event handler, by calling source.BeginDrag(False).

Events

OnStartDrag/Dock

This event occurs when the operation starts. The handler can provide a custom DockObject for the operation.

OnGetSiteInfo

This event occurs during the search for a qualifying dock site. Multiple dock sites can overlap each other, reside in overlapping windows, or can be invisible. Every candidate must supply an influence rectangle (catching area), and can signal to reject an drop. The drag manager selects the most appropriate dock site as the target for subsequent OnDockOver events.

OnDrag/DockOver

This event notifies a possible target, when an object is dragged over it. An OnDockOver event occurs on the DockSite, not on the target control under the mouse. The handler can signal to deny an drop, and can adjust the visual feedback. The event occurs when the mouse enters or leaves a control, and with every single movement of the mouse.

OnDrag/DockDrop

This event notifies the target control of the end of a drag operation.

OnUnDock

This event occurs when the dragged control has to be removed from its host dock site. It's unclear what should happen when the handler denies to undock the control.

OnEndDrag/Dock

This event notifies the source control of the end of a drag operation.