diff options
author | jrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-18 17:59:10 +0000 |
---|---|---|
committer | jrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-18 17:59:10 +0000 |
commit | 52c71ed5a093463acb72598dc8b07a35fbb49842 (patch) | |
tree | 7e1705718bed27cdd1068dacb06176da3fb5b531 /chrome/browser/cocoa/bookmark_button.mm | |
parent | 1308459ce571eccb2b344f35ca0e4bf750be9395 (diff) | |
download | chromium_src-52c71ed5a093463acb72598dc8b07a35fbb49842.zip chromium_src-52c71ed5a093463acb72598dc8b07a35fbb49842.tar.gz chromium_src-52c71ed5a093463acb72598dc8b07a35fbb49842.tar.bz2 |
Drag and drop of buttons/folders from bar to bar.
Does not include DnD to/from menus.
No animations of drop destination yet.
BUG=http://crbug.com/17608
TEST=Do some draggin and droppin.
Confirm click still works on the marks and folders.
Confirm "other bookmarks" canNOT be moved.
Confirm NTP / detached bar also works for DnD.
Review URL: http://codereview.chromium.org/395031
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32341 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa/bookmark_button.mm')
-rw-r--r-- | chrome/browser/cocoa/bookmark_button.mm | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/bookmark_button.mm b/chrome/browser/cocoa/bookmark_button.mm new file mode 100644 index 0000000..8ef0682 --- /dev/null +++ b/chrome/browser/cocoa/bookmark_button.mm @@ -0,0 +1,130 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/bookmark_button.h" + +NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType"; + +// http://codereview.chromium.org/180036/diff/3001/3004 +namespace { +const CGFloat kWebDragStartHysteresisX = 5.0; +const CGFloat kWebDragStartHysteresisY = 5.0; +} + +@implementation BookmarkButton + +@synthesize draggable = draggable_; + +- (id)initWithFrame:(NSRect)frame { + if ((self = [super initWithFrame:frame])) { + draggable_ = YES; + } + return self; +} + +// By default, NSButton ignores middle-clicks. +- (void)otherMouseUp:(NSEvent*)event { + [self performClick:self]; +} + +- (void)beginDrag:(NSEvent*)event { + NSSize dragOffset = NSMakeSize(0.0, 0.0); + NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; + [pboard declareTypes:[NSArray arrayWithObject:kBookmarkButtonDragType] + owner:self]; + + // This NSData is no longer referenced once the function ends so + // there is no need to retain/release when placing in here as an + // opaque pointer. + [pboard setData:[NSData dataWithBytes:&self length:sizeof(self)] + forType:kBookmarkButtonDragType]; + + // This won't work if the source view is clipped. Fortunately, we + // don't display clipped bookmark buttons. + [[self superview] lockFocus]; + scoped_nsobject<NSBitmapImageRep> + bitmapImage([[NSBitmapImageRep alloc] + initWithFocusedViewRect:[self frame]]); + + [[self superview] unlockFocus]; + scoped_nsobject<NSImage> imageDrag([[NSImage alloc] + initWithSize:[bitmapImage size]]); + [imageDrag addRepresentation:bitmapImage]; + + // At the moment, moving bookmarks causes their buttons (like me!) + // to be destroyed and rebuilt. Make sure we don't go away while on + // the stack. + [self retain]; + + CGFloat yAt = [self bounds].size.height; + [self dragImage:imageDrag at:NSMakePoint(0, yAt) offset:dragOffset + event:event pasteboard:pboard source:self slideBack:YES]; + + // And we're done. + [self autorelease]; +} + +- (void)draggedImage:(NSImage*)anImage + endedAt:(NSPoint)aPoint + operation:(NSDragOperation)operation { + beingDragged_ = NO; + [[self cell] setHighlighted:NO]; +} + +- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { + return isLocal ? NSDragOperationMove : NSDragOperationNone; +} + +- (void)mouseUp:(NSEvent*)theEvent { + // This conditional is never true (DnD loops in Cocoa eat the mouse + // up) but I added it in case future versions of Cocoa do unexpected + // things. + if (beingDragged_) + return [super mouseUp:theEvent]; + + // There are non-drag cases where a mouseUp: may happen + // (e.g. mouse-down, cmd-tab to another application, move mouse, + // mouse-up). So we check. + NSPoint viewLocal = [self convertPoint:[theEvent locationInWindow] + fromView:[[self window] contentView]]; + if (NSPointInRect(viewLocal, [self bounds])) { + [self performClick:self]; + } else { + [[self cell] setHighlighted:NO]; + } +} + +// Mimic "begin a click" operation visually. Do NOT follow through +// with normal button event handling. +- (void)mouseDown:(NSEvent*)theEvent { + [[self cell] setHighlighted:YES]; + initialMouseDownLocation_ = [theEvent locationInWindow]; +} + +// Return YES if we have crossed a threshold of movement after +// mouse-down when we should begin a drag. Else NO. +- (BOOL)hasCrossedDragThreshold:(NSEvent*)theEvent { + NSPoint currentLocation = [theEvent locationInWindow]; + if ((abs(currentLocation.x - initialMouseDownLocation_.x) > + kWebDragStartHysteresisX) || + (abs(currentLocation.y - initialMouseDownLocation_.y) > + kWebDragStartHysteresisY)) { + return YES; + } else { + return NO; + } +} + +- (void)mouseDragged:(NSEvent*)theEvent { + if (beingDragged_) + [super mouseDragged:theEvent]; + else { + if (draggable_ && [self hasCrossedDragThreshold:theEvent]) { + [self beginDrag:theEvent]; + } + } +} + +@end |