Drag and Drop in MicroStation


As of MicroStation V8 2004 Edition, MicroStation dialog items can be Drag and Drop sources and targets. Data objects can be dragged within or among dialog items, or can be dragged to or from sources or targets outside MicroStation.

Identifying a Dialog Item as a Drop Source or Target

ListBoxes and Trees can be drop sources. To identify a dialog item as a drop source, add the EXTINTATTR_DROPSOURCE attribute to its dialog item resource definition (EXTINTATTR_DROPSOURCE and EXTINTATTR_DROPTARGET are defined in dlogbox.h):

DItem_abcRsc abcID_yourItem =
{
. . .
}
extendedIntAttributes
{
{
{EXTINTATTR_DROPSOURCE, 1}
}
};

ListBoxes, Trees and Text items can be drop targets. To identify a ListBox or Tree as a drop target, add the EXTINTATTR_DROPTARGET attribute to its dialog item resource definition. All Text items are potentially drop targets without any changes to the resource definition. See more information about these items as drop targets in the "Drop Target Processing" section below.

DItem_abcRsc abcID_yourItem =
{
. . .
}
extendedIntAttributes
{
{
{EXTINTATTR_DROPTARGET, 1}
}
};

A dialog item can be both a drop source and drop target.

DItem_abcRsc abcID_yourItem =
{
. . .
}
extendedIntAttributes
{
{
{EXTINTATTR_DROPSOURCE, 1},
{EXTINTATTR_DROPTARGET, 1}
}
};

The corresponding RawItemHdr variables to these extended attributes are

riP->dropSource and
riP->dropTarget.

Clipboard Formats

Drag and Drop applications use Windows clipboard formats to identify the type of data being dragged. The same clipboard format must be registered by both the drop source and drop target. Clipboard formats are registered using the mdlClipboard_registerClipboardFormat function.

/* Same code is used by both the Drop Source and Drop Target */
#define CLIPBOARD_FORMAT_MINE "My Clipboard Format Text"
UShort cfFormat;
cfFormat = mdlClipboard_registerClipboardFormat (CLIPBOARD_FORMAT_MINE);

Drop Source Processing

To implement drop source processing, the dialog item must have a hook. As the user starts a drag operation, the dialog item hook will receive a DITEM_MESSAGE_DROPSOURCE message with a dimP->u.dropSource.msgType of GUIDROPSOURCEMSG_BEGIN. The item hook is responsible for packaging the data to be dropped onto a drop target. This packaging is accomplished using the mdlDataObject_create function call.

dimP->u.dropSource.pDataObject = mdlDataObject_create (cfFormat, pMyData, dataLen);

The data object created will be available to the item hook in subsequent DITEM_MESSAGE_DROPSOURCE messages and is used in other mdlDataObject function calls, such as mdlDataObject_destroy.

mdlDataObject_destroy (dimP->u.dropSource.pDataObject);

Drop Source Message Types
The DITEM_MESSAGE_DROPSOURCE message has several message subtypes (defined in dlogitem.h):

Drop Source Message Structure
DITEM_MESSAGE_DROPSOURCE and DialogItemMessage.u.dropSource are defined in dlogitem.h:

struct
{
GUIDROPSOURCEMSG msgType;
void *pDataObject;
BoolInt bEscapePressed;
UInt32 dwKeyState;
UInt32 guiDropEffect;
GUIDROPSTATUS guiDropStatus;
} dropSource;
BEGIN Responsibilities
As mentioned previously, the item hook must package the data to be dropped. Additionally, the hook must establish the possible drop effects and set the drag and drop status to "OK": dimP->u.dropSource.pDataObject = mdlDataObject_create (cfFormat, pMyData, dataLen);
dimP->u.dropSource.guiDropEffect =
GUIDROPEFFECT_SCROLL|GUIDROPEFFECT_COPY|GUIDROPEFFECT_MOVE;
dimP->u.dropSource.guiDropStatus = GUIDROPSTATUS_OK;

DROP Responsibilities
If the drop effect (guiDropEffect) includes GUIDROPEFFECT_MOVE and the drop target hasn't completely handled the move operation, the drop source item hook must remove or delete the data corresponding to the data object since it has been added to the drop target.

END Responsibilities
As the data object is created in the BEGIN processing, the data object must be destroyed in the END processing:

mdlDataObject_destroy (dimP->u.dropSource.pDataObject);

Drop Target Processing

To implement drop target processing, the dialog item must have a hook. As the object is being dragged and released over the target item, the dialog item hook will receive a DITEM_MESSAGE_DROPTARGET message. The item hook should query the data object to determine if the item can accept the data object. The main mechanism for querying is to check the availability of a certain clipboard format in the data object using mdlDataObject_isFormatAvailable:

bAvail = mdlDataObject_isFormatAvailable (dimP- >u.dropTarget.pDataObject, cfFormat);

If the target item can accept the data object, a copy of the data is obtained using the mdlDataObject_getData function. This copy must be freed when no longer needed by calling the dlmSystem_mdlFree function.

/* Get a copy of the data from the data object */
pData = mdlDataObject_getData (dimP->u.dropTarget.pDataObject, cfFormat);
. . .
/* When no longer needed */
dlmSystem_mdlFree (pData);

If, for some reason, the target item does not want to accept the data object, the "Drop Effect" variable should be set to "None": Otherwise, the drag and drop subsystem will consider the item a valid drop target.

dimP->u.dropTarget.guiDropEffect = GUIDROPEFFECT_NONE;

Drop Target Message Types
The DITEM_MESSAGE_DROPTARGET message has several message subtypes (defined in dlogitem.h):

Drop Source Message Structure
DITEM_MESSAGE_DROPTARGET and DialogItemMessage.u.dropTarget are defined in dlogitem.h:

struct
{
GUIDROPTARGETMSG msgType;
void *pDataObject;
UInt32 dwKeyState;
Point2d localPt;
UInt32 guiDropEffect;
int iRow; /* For ListBoxes and Trees */
int iCol;
} dropTarget;

DROP Responsibilities
If the message type is DROP, the target can add the data object to itself in an appropriate manner for the application.

/* If clipboard format is not available, disallow */
if (!mdlDataObject_isFormatAvailable (dimP->u.dropTarget.pDataObject, cfFormat))
dimP->u.dropTarget.guiDropEffect = GUIDROPEFFECT_NONE;

/* If can't get the drop entry, disallow */
else if (NULL == (pMyData =
(MyData *) mdlDataObject_getData (dimP->u.dropTarget.pDataObject, cfFormat)))
dimP->u.dropTarget.guiDropEffect = GUIDROPEFFECT_NONE;

else
{
/* May further determine if this item can accept the data */
/* If it cannot accept, set the guiDropEffect to GUIDROPEFFECT_NONE */
. . .

/* Use the copy of the data to add its contents to myself */
if (GUIDROPTARGETMSG_DROP == dimP->u.dropTarget.msgType)
{
. . .
}

/* Free the copy from the Drag and Drop system */
dlmSystem_mdlFree (pMyData);
}

ListBox Items as Drop Targets
The default behavior is for the entire ListBox to be the drop target. In other words, if an object is dropped on a ListBox, the application usually inserts the object into a ListModel or StringList then sorts the list.

If a drop between rows is desired, add the LISTATTRX_DROPBETWEENROWS extended attribute to the ListBox resource definition. When receiving the DITEM_MESSAGE_DROPTARGET, the DialogItemMessage.u.dropTarget.iRow member will contain the index of the row to insert before. If the drop target is below the last row in order to append, iRow will be -1. A visual representation will be shown where the row is to be inserted. This could be used by an application such as Customize where the insertion point for an object within a ListBox is important.

Tree Items as Drop Targets
The default behavior is for a particular tree node to be the drop target, and that tree node is temporarily highlighted. In other words, if an object is dropped on a Tree, the application usually "adds" the object to the tree node in a manner appropriate for the application. This could mean becoming part of the TreeModel's hierarchy or a member of a list owned by the tree node.

If a drop onto the entire Tree is desired, add the TREEATTR_DROPWHOLEITEM extended attribute to the Tree resource definition. This could be used in an application such as Element Information where we want to analyze an element and update the entire dialog with that element's information.

If a drop between rows is desired, add the TREEATTR_DROPBETWEENROWS attribute to the Tree resource definition. When receiving the DITEM_MESSAGE_DROPTARGET, the DialogItemMessage.u.dropTarget.iRow member will contain the index of the row to insert before. If the drop target is below the last row in order to append, iRow will be -1. A visual representation will be shown where the row is to be inserted. This could be used by an application where the ordering of Tree nodes/rows is important.

Text Items as Drop Targets
All Text items are potentially drop targets without any changes to their resource definitions if CF_TEXT, CF_UNICODETEXT or CF_HDROP clipboard formats are available in the data object. See mdlDataObject_getDragFileCount and mdlDataObject_getDragFile below in "mdlDataObject Functions" for more information on the HDROP format. To disallow a drop onto a Text item, include the following code in the Text item's hook:

case DITEM_MESSAGE_DROPTARGET:
/* Disallow a drop onto this Text item */
dimP->msgUnderstood = TRUE;
dimP->u.dropTarget.guiDropEffect = GUIDROPEFFECT_NONE;
break;

mdlDataObject Functions

The Dialog Item Drag and Drop subsystem in MicroStation utilizes the Windows DoDragDrop function and the IDataObject, IDropSource and IDropTarget COM interfaces. The data object packaged by the drop source must implement the IDataObject interface. The data object created by the mdlDataObject_create function creates such an object. Other mdlDataObject functions are also provided which are simply front-ends to the IDataObject interface. If your application is written in C++, you may very well want to create your own class derived from IDataObject instead of using the mdlDataObject functions. This is quite acceptable. The following is a brief overview of the mdlDataObject functions, which are prototyped in msdragdrop.fdf.

The GuiDataObject type is simply void.

mdlWindow_dragDrop Functions

The mdlWindow_dragDrop functions are primarily used internally by the Dialog Manager. However, in some rare cases, applications may need to call the following functions, which are prototyped in msdragdrop.fdf.