Cocoa Programming for Mac OS X - Aaron Hillegass [97]
- (void)mouseDown:(NSEvent *)event
{
mouseDownEvent = event;
}
You will also need to create an image to drag. You can draw on an image just as you can on a view. To make the drawing appear on the image instead of on the screen, you must first lock focus on the image. When the drawing is complete, you must unlock the focus.
Here is the whole method to add to BigLetterView.m:
- (void)mouseDragged:(NSEvent *)event
{
NSPoint down = [mouseDownEvent locationInWindow];
NSPoint drag = [event locationInWindow];
float distance = hypot(down.x - drag.x, down.y - drag.y);
if (distance < 3) {
return;
}
// Is the string of zero length?
if ([string length] == 0) {
return;
}
// Get the size of the string
NSSize s = [string sizeWithAttributes:attributes];
// Create the image that will be dragged
NSImage *anImage = [[NSImage alloc] initWithSize:s];
// Create a rect in which you will draw the letter
// in the image
NSRect imageBounds;
imageBounds.origin = NSZeroPoint;
imageBounds.size = s;
// Draw the letter on the image
[anImage lockFocus];
[self drawStringCenteredIn:imageBounds];
[anImage unlockFocus];
// Get the location of the mouseDown event
NSPoint p = [self convertPoint:down fromView:nil];
// Drag from the center of the image
p.x = p.x - s.width/2;
p.y = p.y - s.height/2;
// Get the pasteboard
NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSDragPboard];
// Put the string on the pasteboard
[self writeToPasteboard:pb];
// Start the drag
[self dragImage:anImage
at:p
offset:NSZeroSize
event:mouseDownEvent
pasteboard:pb
source:self
slideBack:YES];
}
That’s it. Build and run the application. You should be able to drag a letter off the view and into any text editor. (Try dragging it into Xcode.)
After the Drop
When a drop occurs, the drag source will be notified if you implement the following method:
- (void)draggedImage:(NSImage *)image
endedAt:(NSPoint)screenPoint
operation:(NSDragOperation)operation;
For example, to make it possible to clear the BigLetterView by dragging the letter to the trashcan in the dock, advertise your willingness in draggingSourceOperationMaskForLocal:
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
{
return NSDragOperationCopy | NSDragOperationDelete;
}
Then implement draggedImage:endedAt:operation:
- (void)draggedImage:(NSImage *)image
endedAt:(NSPoint)screenPoint
operation:(NSDragOperation)operation
{
if (operation == NSDragOperationDelete) {
[self setString:@""];
}
}
Build and run the application. Drag a letter into the trashcan. It should disappear from the view.
Make BigLetterView a Drag Destination
There are several parts to being a drag destination. First, you need to declare your view a destination for the dragging of certain types. NSView has a method for this purpose:
- (void)registerForDraggedTypes:(NSArray *)pboardTypes
You typically call this method in your initWithFrame: method.
Then you need to implement six methods. (Yes, six!) All six methods have the same argument: an object that conforms to the NSDraggingInfo protocol. That object has the dragging pasteboard. The six methods are invoked as follows:
1. As the image is dragged into the destination, the destination is sent a draggingEntered: message. Often, the destination view updates its appearance. For example, it might highlight itself.
2. While the image remains within the destination, a series of draggingUpdated: messages are sent. Implementing draggingUpdated: is optional.
3. If the image is dragged outside the destination, draggingExited: is sent.
4. If the image is released on the destination, either it slides back to its source (and breaks the sequence) or a prepareForDragOperation: message is sent to the destination, depending on the value returned by the most recent invocation of draggingEntered: (or draggingUpdated: if the view implemented it).
5. If the prepareForDragOperation: