Programmer's Reference

Drop site widgets and CwDropSite objects

A drop site widget is a widget that has been registered as a drop site. The user can drop onto a drop site widget by first dragging from a drag source widget, and then moving the mouse over to the drop site widget and releasing the mouse button.

Preparing to accept drops: CwDropSite

The application registers a widget as a drop site by sending it the dropSiteRegister: message of CwWidget with a CwDropSite create argBlock. Sending dropSiteRegister: creates a CwDropSite which represents the drop site during any drag and drop operation. The following drop site resources can be set in the create argBlock:

dropSiteOperations
The operations that the drop site supports

importTargets
The target types that the drop site supports, in order of drop site preference

dragProc
An optional proc that is received whenever the mouse moves over the drop site widget during a drag. The callData reason can be one of the following:
Enter
XmCRDROPSITEENTERMESSAGE
Motion
XmCRDRAGMOTIONMESSAGE
Leave
XmCRDROPSITELEAVEMESSAGE
Operation changed
XmCROPERATIONCHANGEDMESSAGE

The destination application can check the location of the mouse to determine whether a drop in that location is acceptable, and modify the operation and dropSiteStatus fields of the proc's callData accordingly. Modifications to these fields produces a corresponding change in the appearance of the drag cursor. In addition, a drag proc can be used to provide visual feedback to the user about the drop site. For example, to indicate that the cursor is over some semantic area in the widget, an application might draw a border around the area.

dropProc
A proc that is received when a mouse button is released over the drop site. The destination application must determine whether the drop operation is acceptable in that location. If the operation is valid, it must decide which target types to request and then ask the drag context to start the data transfer using those types.

The following code registers the specified widget as a drop site. This establishes the operations and targets that the drop site supports, as well as hooking a dragProc and a dropProc:

registerDropSite: aCwWidget
  "Register the specified widget as a drop site."
  aCwWidget
    dropSiteRegister: [:dropSite | 
      dropSite
        dropSiteOperations: XmDROPMOVE | XmDROPCOPY;
        importTargets: #('STRING');
        dragProc: (CwCallbackRec
          receiver: self 
          selector: #dragProc:clientData:callData:
          clientData: nil);
        dropProc: (CwCallbackRec
          receiver: self 
          selector: #dropProc:clientData:callData:
          clientData: nil)].
Note:
OSF/Motif platforms provide default drop behavior in text widgets. Common Widgets drag and drop turns off this behavior in a widget when the widget is registered as a drop site.

The drag proc

The dragProc resource is optional. A destination application can supply a drag proc when it creates a drop site if it wants to perform special drag-under animation, or select the operation based on some internal state or the semantic location of the cursor in the drop site. The parameters to the dragProc are as follows:

widget
The CwWidget that was registered as a drop site
clientData
The clientData specified when the dragProc was hooked
callData
An instance of CwDragProcCallbackData

The following code shows a dragProc handler which does drag-under animation based on the coordinates of the mouse in the callData, and chooses the operation based on the mouse coordinates and the valid operations in the callData. Assume the following:

dragProc: widget clientData: clientData callData: callData
  "Handle the drag proc for the receiver."
  | point rectangle op |
 
  "Turn off platform drag-under animation."
  callData animate: false.
 
  point := callData x @ callData y.
  (self dropRectanglesFor: widget)
    do: [:rect |
      (rect containsPoint: point)
        ifTrue: [rectangle := rect]].
  rectangle isNil
    ifTrue: [op := XmDROPNOOP]
    ifFalse: [op := self
      operationForRectangle: rectangle
        widget: widget
        callData: callData].
 
  op = XmDROPNOOP
    ifTrue: [
      "The point is not in a drop rectangle for the widget,
       or the operation is not valid for the drop rectangle."
      callData 
        operation: XmDROPNOOP;
        dropSiteStatus: XmDROPSITEINVALID.
      self removeAllAnimation: widget]
    ifFalse: [
      "The point is in one of the drop rectangles for the widget,
       and the operation is valid."
      callData 
        operation: op;
        dropSiteStatus: XmDROPSITEVALID.
      self animateRectangle: rectangle widget: widget operation: op].
 
  callData reason = XmCRDROPSITELEAVEMESSAGE
    ifTrue: [self removeAllAnimation: widget].

The drop proc

The destination application must supply a drop proc when it creates a drop site. In the drop proc, the destination determines if the drop is valid, and starts the drop data transfer. The parameters to the dropProc are as follows:

widget
The CwWidget that was registered as a drop site
clientData
The clientData specified when the dropProc was hooked
callData
An instance of CwDropProcCallbackData
Note:
Some platforms allow the user to press the help key (usually F1) during a drag. In this case, a drop proc is sent with the dropAction field in the callData set to XmDROPHELP.

Two different dropProc handlers are shown in the following code. Both examples call startTransfer:targetTypes:clientData:. The code for this method is shown in the following section on the CwDropTransfer object.

The first example shows a very simple dropProc handler. This drop site only supports the 'STRING' target type. If the dropProc is called, the drop site knows that the operation is valid and the drag source also supports 'STRING,' therefore it can simply ask for the data in 'STRING' format.

dropProc: widget clientData: clientData callData: callData
  "Handle the drop proc for the receiver."
  callData dropAction = XmDROPHELP
    ifTrue: [
      "Help is not supported, therefore this is an invalid operation."
      ^callData dropSiteStatus: XmDROPSITEINVALID].
  "A valid drop has occurred. Start a transfer, requesting our only target type."
  self startTransfer: callData targetTypes: #('STRING') clientData: widget.

The second example dropProc is more complex. This drop site supports more than one target type. In addition, the drop site cares about the semantic location of the mouse, as did the example dragProc in the previous subsection, and it may decide that the operation is invalid. Assume that intersectionOf: answers an OrderedCollection containing the intersection of two collections, and that dropRectanglesFor: and operationForRectangle:widget:callData: are the same methods used in the dragProc example.

dropProc: widget clientData: clientData callData: callData
  "Handle the drop proc for the receiver."
  | point rectangle op exportTargets importTargets intersection |
 
  callData dropAction = XmDROPHELP
    ifTrue: [
      "Help is not supported, therefore this is an invalid operation."
      ^callData dropSiteStatus: XmDROPSITEINVALID].
 
  point := callData x @ callData y.
  (self dropRectanglesFor: widget)
    do: [:rect |
      (rect containsPoint: point)
        ifTrue: [rectangle := rect]].
 
  op := rectangle isNil
    ifTrue: [XmDROPNOOP]
    ifFalse: [self operationForRectangle: rectangle 
                          widget: widget callData: callData].
  	op = XmDROPNOOP
    ifTrue: [
      "The point is not in a drop rectangle for the widget,
       or the operation is not valid for the drop rectangle."
      callData
        operation: XmDROPNOOP;
        dropSiteStatus: XmDROPSITEINVALID]
    ifFalse: [
      "The point is in one of the drop rectangles for the widget,
       and the operation is valid."
      callData operation: op].
 
  callData dropSiteStatus = XmDROPSITEVALID
    ifTrue: [
      "Valid drop. Start a transfer, requesting all possible target types."
      exportTargets := callData dragContext exportTargets.
      importTargets := widget dropSite importTargets.
      intersection := self intersectionOf: exportTargets and: importTargets.
      self startTransfer: callData targetTypes: intersection clientData: widget].


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]