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.
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:
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.
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)].
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:
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 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:
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].