Using 3.0's Drag-and-Drop Facility

by Greg Burd

Drag-and-drop is an integral part of any NeXTSTEP application. But until now, implementing it was beyond the abilities of all but the best programmers.

With NeXTSTEP 3.0, adding drag-and-drop capabilities to an application is almost as easy as, well, drag and drop. That's thanks to a few new categories in the View class, some extensions to the pasteboard, and improvements in the NXImage class. With these new changes, you can drag and drop just about anything.

What a drag
NeXTSTEP 3.0 has two new View categories: IconDrag and Drag. IconDrag deals with dragging file icons either from the workspace to a program, or between programs. Using it is fairly straightforward.

The Drag category is what you use when dragging a visual representation of data within an application. There are three methods:

	@interface View(Drag)
	- dragImage:anImage
		at:(NXPoint *)viewLocation
		offset:(NXPoint *)initialOffset
		event:(NXEvent *)event
		pasteboard:(Pasteboard *)pboard
	- registerForDraggedTypes:(const char *const *)newTypes
	- unregisterDraggedTypes;

The first method, dragImage:, is the method with which all visual dragging begins. First, "dragImage:anImage" passes an NXImage in-stance that you want to be displayed while dragging. The "at:(NXPoint *) viewLocation" is a point in the View that represents where the mouse should be relative to the image being dragged. Most of the time you will end up using {0.0, 0.0}. The "offset:(NXPoint *)initialOffset" gives the mouse's current location relative to the mouse-down location.

Remember that we are dragging a visual representation of data rather than the data itself. The data itself is placed on the pasteboard, so you have to create a pasteboard suited for dragging. Use NXDragPboard and put the data on it before calling dragImage:. The "source:sourceObj" is used to get the drag-source operation (NX_DragOperationCopy, etc.), and this is usually self. If you want the image to slide back if the operation is aborted, then set slideBack:(BOOL) to YES.

Typically, you'll call dragImage: in response to a mouseDown: event. The user will click an image and then drag it away. It's that simple.

On the receiving end, the new method registerForDraggedTypes: tells NeXTSTEP which drag types your View can accept. You should call this method in initFrame:. This method tells the View class the types of pasteboard information your subclass of View will accept during a drag operation. The structure is the same as the types argument to the OpenPanel. So if you want to accept PostScript and TIFF images, use:

	*const types[] = {NXPostScriptPboardType, NXTiffPboardType};
	[self registerForDraggedTypes:types count:2];
The drag session
When the user drags something into an appropriate receiving View, that View gets sent a series of six messages. The messages are defined in the new NXDraggingDestination protocol. (A protocol defines a set of messages to which an Objective-C class can respond, but which the class must define for itself. It's a new extension to the Objective-C language that was invented for NeXTSTEP 3.0.)

	-(NXDragOperation)draggingEntered:(id )sender
This is the first message that your View will receive when the dragged object first enters your View; "sender" is an object that can respond to the NXDraggingInfo protocol. Your View should use this method to verify that it can actually receive what is being dragged into it. The return type, NXDragOperation, is an enumerated type that indicates which operation the destination will perform when the object is released.

	-(NXDragOperation)draggingUpdated:(id )sender
This message gets sent while the user moves the dragged object around the receiving View.

What happens next depends on if the user drags the object out of the receiver or releases the mouse button. If the dragged object leaves the receiver, then the draggingExited: message is sent.

If the user releases the dragged object inside the receiving View, the following three messages are sent in sequence:

	-(BOOL)prepareForDragOperation:(id )sender
	-(BOOL)performDragOperation:(id )sender
	-concludeDragOperation:(id )sender
If your View returns NO to either of the first two messages, the drag operation will be aborted.

Getting info
You can use the NXDraggingInfo object to find out what is actually being dragged by the user. The six NXDraggingDestination methods shown above all receive an NXDraggingInfo object as their argument; you never create an NXDraggingInfo object yourself. Some of the more helpful methods included in this object are:

	-(NXImage *)draggedImageCopy
This returns a copy of the NXImage object that's being dragged. Be sure to free the NXImage object when you're done with it.

This tells you the origin of the image that is currently being dragged.

	-(Pasteboard *)draggingPasteboard
This returns the pasteboard specified by the first dragImage: message that started dragging in the first place. Use it to get at the user data associated with this drag.

This returns YES if the drag source and destination are in the same application, which under NeXTSTEP 3.0 is not necessary. This is why you can now drag color chips from one application to another. Demonstration

We've put a dragging lab to show how all of this works on the archive ser-vers and Look for the file NeXTWORLD_ DragLab.tar.Z.

Greg Burd works in NeXT developer support.