-
Notifications
You must be signed in to change notification settings - Fork 272
Description
The current implementation of Drag/Drop (VCL style) seems faulty.
When an application uses a custom DragObject instead of having the drag "Source" be a pointer to the control that started the drag, the treeview hides this functionality.
A custom DragObject is used to add functionality and have the target control not test for individual controls, but use this added functionality when drag-dropping between (different) controls.
When deriving a custom DragObject from TBaseDragControlObject, the target control can access the original control too. But not with VirtualTree, see the code below: it explicitly tests for TBaseDragControlObject and then passes the control to the "DragOver" event, instead of the custom DragObject like other VCL controls do.
This means that when we want to use the custom drag object in the DragOver (or DragDrop) events of the tree view, all that information is gone, making the custom drag object usage useless...
Only when there's an "DragInternalObject" (see TControl.DoDragMsg and procedure DragInitControl in VCL.Controls), should the control be passed, as this means no custom drag object was used.
I believe that VirtualTree >tries< to check for a custom drag object in the .DoStartDrag method, but this only works when Source and Target are the same treeview instance, not when dragging from a different component or between virtual tree instances.
A user can decide to derive from BaseDragObject instead to avoid the issue with the current faulty implementation, but then looses information about the original source control.
`procedure TBaseVirtualTree.CMDrag(var Message: TCMDrag);
var
S: TObject;
ShiftState: Integer;
P: TPoint;
Formats: TFormatArray;
Effect: Integer;
begin
with Message, DragRec^ do
begin
S := Source;
Formats := nil;
// Let the ancestor handle dock operations.
if S is TDragDockObject then
inherited
else
begin
// We need an extra check for the control drag object as there might be other objects not derived from
// this class (e.g. TActionDragObject).
if not (tsUserDragObject in FStates) and (S is TBaseDragControlObject) then
S := (S as TBaseDragControlObject).Control;
...
DragOver(S, ShiftState, TDragState(DragMessage), Pos, Effect);
...
`