Re: Dragging NSCells
Re: Dragging NSCells
- Subject: Re: Dragging NSCells
- From: Andrew Thompson <email@hidden>
- Date: Wed, 22 Jan 2003 21:13:08 -0500
On Wednesday, Jan 22, 2003, at 20:46 America/New_York, The Amazing
Llama wrote:
After scouring the web for an hour and a half, I doubt the answer will
be positive, but I have to ask.
Does anyone have any example code on how to implement dragging from
NSCells? I get the feeling that quite a lot of sub-classing and
overriding is involved, and having an example would help out a lot.
For the record, I'm trying to implement dragging items in a tree view
around within the tree view, or out to other tree views of the same
type. I have sub-classed NSMatrix and NSBrowserCell, and hope
implementing either to accept the drops. NSMatrix, being a view, will
not be hard; but NSBrowserCell, being a cell, has none of the
abilities I need.
I have seen the long list of unanswered replies to this topic over the
years at mamasam; is Apple aware that this is a problem?
Well, I have a cell that lets you drag its textual content, with a nice
drag image:
In particular, the cell knows how to render itself to an NSImage:
- (NSImage *) getImageOfContents: (NSSize) a_frame {
NSImage *image = nil;
NSBitmapImageRep *bits = nil;
NSRect textFrame;
BOOL drawingBackground = [self isDrawingBackground];
textFrame.size = a_frame;
textFrame.origin = NSZeroPoint;
image = [[NSImage alloc] initWithSize: textFrame.size];
[image setBackgroundColor:[NSColor clearColor]];
[image lockFocus];
[self setDrawingBackground: NO]; //don't drag the cell background
around, only the foreground
[self drawInteriorWithFrame: textFrame inView: [NSView focusView]];
bits = [[NSBitmapImageRep alloc] initWithFocusedViewRect:
textFrame];
[self setDrawingBackground: drawingBackground];
[image unlockFocus];
[bits release];
return [image autorelease];
}
The matrix class that goes with this has a Drag and Drop Category:
@implementation CharacterMatrix (DragAndDrop)
/** Accept events when in the background.
Makes dragging from background windows possible
@param theEvent the (mouse) event that triggered the question of
whether we accept the first mouse
*/
- (BOOL) acceptsFirstMouse: (NSEvent *) theEvent {
return YES;
}
- (NSDragOperation) draggingSourceOperationMarkForLocal: (BOOL) flag {
return NSDragOperationCopy;
}
- (void) copyToPasteboard: (NSPasteboard *) a_pboard {
NSString *title = [[self selectedCell] title];
NSAttributedString *attTitle = [[self selectedCell]
attributedStringValue /* attributedTitle*/];
[a_pboard declareTypes: [NSArray arrayWithObjects: NSRTFPboardType,
NSStringPboardType, nil] owner: self];
[a_pboard setData: [attTitle RTFFromRange: NSMakeRange(0, [attTitle
length])
documentAttributes: nil]
forType: NSRTFPboardType];
[a_pboard setString: title forType: NSStringPboardType];
//[a_pboard setData: [[self title] dataUsingEncoding: some custom
encoding? forType: NSStringPboardType];
//NSLog(@"Types in drag: %@\n", [a_pboard types]);
}
/* Have to override this becuase NSMatrix eats drag events in this
method by default, and we want to handle dragging.
Naturally, this means we have to guess what NSMatrix does in response
to a moueDown event and try to emulate
every part of it _except_ for the eating of the drag events...*/
- (void) mouseDown: (NSEvent *) a_theEvent {
int row = -1, column = -1;
m_lastMouseDown = [a_theEvent locationInWindow];
if ( [self getRow: &row column: &column forPoint: [self
convertPoint:[a_theEvent locationInWindow] fromView: nil]] &&
[[self cellAtRow:row column: column] isEnabled]) {
[self selectCellAtRow: row column: column];
[self sendAction];
} else {
[super mouseDown: a_theEvent];
}
}
- (void) mouseDragged: (NSEvent *) a_theEvent {
NSPasteboard *pboard;
NSImage *image = nil;
NSImage *translucent = nil;
NSPoint dragPoint = NSZeroPoint;
NSPoint cellOrigin;
int width=0, height=0;
pboard = [NSPasteboard pasteboardWithName: NSDragPboard];
[self copyToPasteboard: pboard];
//make an image of the contents of the currently selected cell. It
needs to be as big as the whole cell itself
image = [((ColouredBorderButtonCell *)[self selectedCell])
getImageOfContents: [self cellSize]];
//the point in the Matrix's co-ordinate system where the drag
begins (the cell doesn't have a co-ordinate system because
//its not an NSControl)
dragPoint = [self convertPoint: [a_theEvent locationInWindow]
fromView: nil];
//Work out where the origin of the current cell is
cellOrigin = [self cellFrameAtRow: [self selectedRow] column: [self
selectedColumn]].origin;
//Remember that the image and the cell are deliberately made the
same size, so we may use either's width or height
width = [image size].width;
height = [image size].height;
//Here we basically transform between the matrix's co-ordinates and
the cell's
//If we do nothing here, then the image is dragged by its bottom
left corner. So we subtract from x (move it right)
//and add to y (move it down, Cocoa has origin at top) to adjust
the image so the image drags from the point in the cell
//where the clicked the mouse. The y calculation is slightly odd
looking because Cocoa uses origin = top-left, whereas
//the image is dragged assuming origin = bottom-left. Go figure...
dragPoint.x -= width * (dragPoint.x - cellOrigin.x) / width;
dragPoint.y += height * (cellOrigin.y + height - dragPoint.y) /
height;
//Make the drag full of lickable Aqua goodness ;)
translucent = [[[NSImage alloc] initWithSize: [image size]]
autorelease];
[translucent lockFocus];
[image dissolveToPoint: NSZeroPoint fraction: 0.5];
[translucent unlockFocus];
//drag, the 'offset:' handles the cases where the user drags
quickly and the mouse
//moves a lot between mouseDown: and mouseDragged:
[self dragImage: translucent
at: dragPoint
offset: [CharacterMatrix subtractPoints: [a_theEvent
locationInWindow] from: m_lastMouseDown]
event: a_theEvent
pasteboard: pboard
source: self
slideBack: YES];
}
+ (NSSize) subtractPoints: (NSPoint) a_1 from: (NSPoint) a_2 {
return NSMakeSize(a_2.x - a_1.x, a_2.y - a_1.y);
}
Not claiming its perfect, but it does work rather well enough.
Code is all under MIT style license (so basically, its your to do what
you want with).
AndyT (lordpixel - the cat who walks through walls)
A little bigger on the inside
(see you later space cowboy ...)
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.