There is probably only a handful of things that are probably less understood at the SDK level as to how just exactly the Drag-Drop event sequence is generated, captured, and handled. First off, the UIComponent is the one where events can be registered but does absolutely nothing about dispatching or even ‘psuedo-dispatching’ through an intermediary.

 

Not In Here:

Case is point – we all know about the DragManager, and how you have to enable certain targets to allow the capture sequence to generate events for the final drop event, however it’s really the SystemManager that handles a bunch of marshalling for you – since it sits at the near root level it knows about MouseEvents for just about every object.

It’s this ferrying back and forth between the InterManagerRequest.DRAG_MANAGER_REQUEST event between the DragManager and ultimately passed through the Implementor (ie DragManagerImpl), and the SystemManager, is what creates the DragEvent to eventually be fired via the DragProxy. This is why the documentation says it is important to trigger the allowDragDrop method from within the DragEvent.ENTER event – because the target is then assigned directly to the proxy instance.

A Peculiar UIComponent extension that does NOT issue a DragEvent:

The Panel component for some reason I don’t fully understand (at the business logic layer) was designed to specifically disallow this sequence. My best guess is it was decided this way since the Panel / TitleWindow was going to be almost exclusively used in a pop-up with or without modality which would place it in the SystemManager’s childlist which specifically handles requests from the PopupManager.

So what happens when say you want to build a TileList of sorts with Panels and being able to move those Panels to a different TileList is important? Thankfully we have help from the SDK to figure this out. Within the ListItemRenderer, there is an instance where the initial sequence is manually generated, from which the rest of the events will ensue.

First there is no nice way of enabling this sort of functionality as a decorated set of capabilities to leverage just the original Panel, however we can create a stub of our own which adds this flavor.

Some things to consider when building an extended Panel to handle this Drag-Drop

  • We need to manually add the “drag initiate” sequence with what we believe constitutes a drag start. This is done with listeners for the MouseDown, then adding a MouseMove where we have passed some distance threshold from the initiating point.
  • The dragEvent.START consists of a few key parameters: dragInitiator, localX/Y coordinates, and the dragSource. The nice thing about the dragSource is since the data is not typed, just about anything including visual references can be added to suit our taste so long as we know if we are using the ‘item‘ or ‘items‘ format. Although I am not personally a fan, in this case it is a good idea to use the bubbling property since this panel has the potential to be deeply nested in your view – relative to how you want to respond to the drag events.
  • Add the initiating listeners to the titleBar reference, but ignore cases where the event target is a Button since we don’t want children (ie not skins) to generate this sequence.
  • Even though we are adding the ability to dispatch the DragEvent.START, we need to listen to this ourselves -mind you use a protected event listener – see my earlier rants, to trigger the DragManager.doDrag() method. Since this listener acts as the ‘default‘ we need to allow for cases where we don’t want the drag to happen. In our DragStart listener, we check the event.isDefaultPrevented() in order to stop propagation and terminate. This is where we use the event.local coordinates along with the stage coordinates to create an offset point for the doDrag() – so the dragproxy stays bound to our mouse from the point of where we picked it up. This is simply the stage coordinate – local.
  • Something to note about the DragImage, you can either specify a proxy in it’s place, or use the actual instance of the dragging object you want moved – if you choose the latter it becomes important to know when you actually can safely re-parent (since it will have been attached to a DragProxy) this item only after it has been removed from the stage (because the DragProxy automatically adds a zoom / resize effect from the drop action).

 

So with your initiating sequence of MouseEvent listeners, it becomes quite easy to dispatch a DragEvent.START with both a reference for the initiator and the source you want to use. Listen to this event being careful to consider event propagation, then call DragManager.doDrag() with the necessary parameters and you have just added SDK style Drag-Drop functionality to your custom components.