diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-11 19:17:41 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-11 19:17:41 +0000 |
commit | 4f61f537c43fcc72052f5263c1c26f48ee97eb96 (patch) | |
tree | f1671cc15574c1af9e1c533c2f85fabe72eb90ed /chrome/browser/ui/cocoa/draggable_button.mm | |
parent | a195ec3629bca0b7f77130a8345e991b9fa28d7b (diff) | |
download | chromium_src-4f61f537c43fcc72052f5263c1c26f48ee97eb96.zip chromium_src-4f61f537c43fcc72052f5263c1c26f48ee97eb96.tar.gz chromium_src-4f61f537c43fcc72052f5263c1c26f48ee97eb96.tar.bz2 |
[Mac] "Refactor" DraggableButton into a mixin and impl.
This is because DraggableButton inherits from NSButton when a future class will
need it to inherit from NSPopupButton. Because ObjC lacks multiple inheritance,
and we want to avoid runtime trickery, this is the result.
BUG=none
TEST=Dragging download shelf and bookmark bar items works as before. Partially covered by unit tests.
Review URL: http://codereview.chromium.org/7462018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96433 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ui/cocoa/draggable_button.mm')
-rw-r--r-- | chrome/browser/ui/cocoa/draggable_button.mm | 200 |
1 files changed, 10 insertions, 190 deletions
diff --git a/chrome/browser/ui/cocoa/draggable_button.mm b/chrome/browser/ui/cocoa/draggable_button.mm index 4d03b27..5654d58 100644 --- a/chrome/browser/ui/cocoa/draggable_button.mm +++ b/chrome/browser/ui/cocoa/draggable_button.mm @@ -5,214 +5,38 @@ #import "chrome/browser/ui/cocoa/draggable_button.h" #include "base/logging.h" -#import "base/memory/scoped_nsobject.h" - -namespace { - -// Code taken from <http://codereview.chromium.org/180036/diff/3001/3004>. -// TODO(viettrungluu): Do we want common, standard code for drag hysteresis? -const CGFloat kWebDragStartHysteresisX = 5.0; -const CGFloat kWebDragStartHysteresisY = 5.0; -const CGFloat kDragExpirationTimeout = 0.45; - -} @implementation DraggableButton -@synthesize draggable = draggable_; -@synthesize actsOnMouseDown = actsOnMouseDown_; -@synthesize durationMouseWasDown = durationMouseWasDown_; -@synthesize actionHasFired = actionHasFired_; -@synthesize whenMouseDown = whenMouseDown_; - - - (id)initWithFrame:(NSRect)frame { if ((self = [super initWithFrame:frame])) { - draggable_ = YES; - actsOnMouseDown_ = NO; - actionHasFired_ = NO; + draggableButtonImpl_.reset( + [[DraggableButtonImpl alloc] initWithButton:self]); } return self; } - (id)initWithCoder:(NSCoder*)coder { if ((self = [super initWithCoder:coder])) { - draggable_ = YES; - actsOnMouseDown_ = NO; - actionHasFired_ = NO; + draggableButtonImpl_.reset( + [[DraggableButtonImpl alloc] initWithButton:self]); } return self; } -- (BOOL)deltaIndicatesDragStartWithXDelta:(float)xDelta - yDelta:(float)yDelta - xHysteresis:(float)xHysteresis - yHysteresis:(float)yHysteresis { - return (ABS(xDelta) >= xHysteresis) || (ABS(yDelta) >= yHysteresis); -} - -- (BOOL)deltaIndicatesConclusionReachedWithXDelta:(float)xDelta - yDelta:(float)yDelta - xHysteresis:(float)xHysteresis - yHysteresis:(float)yHysteresis { - return (ABS(xDelta) >= xHysteresis) || (ABS(yDelta) >= yHysteresis); -} - - -// Determine whether a mouse down should turn into a drag; started as copy of -// NSTableView code. -- (BOOL)dragShouldBeginFromMouseDown:(NSEvent*)mouseDownEvent - withExpiration:(NSDate*)expiration - xHysteresis:(float)xHysteresis - yHysteresis:(float)yHysteresis { - if ([mouseDownEvent type] != NSLeftMouseDown) { - return NO; - } - - NSEvent* nextEvent = nil; - NSEvent* firstEvent = nil; - NSEvent* dragEvent = nil; - NSEvent* mouseUp = nil; - BOOL dragIt = NO; - - while ((nextEvent = [[self window] - nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask) - untilDate:expiration - inMode:NSEventTrackingRunLoopMode - dequeue:YES]) != nil) { - if (firstEvent == nil) { - firstEvent = nextEvent; - } - if ([nextEvent type] == NSLeftMouseDragged) { - float deltax = [nextEvent locationInWindow].x - - [mouseDownEvent locationInWindow].x; - float deltay = [nextEvent locationInWindow].y - - [mouseDownEvent locationInWindow].y; - dragEvent = nextEvent; - if ([self deltaIndicatesConclusionReachedWithXDelta:deltax - yDelta:deltay - xHysteresis:xHysteresis - yHysteresis:yHysteresis]) { - dragIt = [self deltaIndicatesDragStartWithXDelta:deltax - yDelta:deltay - xHysteresis:xHysteresis - yHysteresis:yHysteresis]; - break; - } - } else if ([nextEvent type] == NSLeftMouseUp) { - mouseUp = nextEvent; - break; - } - } - - // Since we've been dequeuing the events (If we don't, we'll never see - // the mouse up...), we need to push some of the events back on. - // It makes sense to put the first and last drag events and the mouse - // up if there was one. - if (mouseUp != nil) { - [NSApp postEvent:mouseUp atStart:YES]; - } - if (dragEvent != nil) { - [NSApp postEvent:dragEvent atStart:YES]; - } - if (firstEvent != mouseUp && firstEvent != dragEvent) { - [NSApp postEvent:firstEvent atStart:YES]; - } - - return dragIt; -} - -- (BOOL)dragShouldBeginFromMouseDown:(NSEvent*)mouseDownEvent - withExpiration:(NSDate*)expiration { - return [self dragShouldBeginFromMouseDown:mouseDownEvent - withExpiration:expiration - xHysteresis:kWebDragStartHysteresisX - yHysteresis:kWebDragStartHysteresisY]; +- (DraggableButtonImpl*)draggableButton { + return draggableButtonImpl_.get(); } - (void)mouseUp:(NSEvent*)theEvent { - durationMouseWasDown_ = [theEvent timestamp] - whenMouseDown_; - - if (actionHasFired_) - return; - - if (!draggable_) { + if ([draggableButtonImpl_ mouseUp:theEvent] == kDraggableButtonMixinCallSuper) [super mouseUp:theEvent]; - return; - } - - // 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]; - } -} - -- (void)secondaryMouseUpAction:(BOOL)wasInside { - // Override if you want to do any extra work on mouseUp, after a mouseDown - // action has already fired. -} - -- (void)performMouseDownAction:(NSEvent*)theEvent { - int eventMask = NSLeftMouseUpMask; - - [[self target] performSelector:[self action] withObject:self]; - actionHasFired_ = YES; - - while (1) { - theEvent = [[self window] nextEventMatchingMask:eventMask]; - if (!theEvent) - continue; - NSPoint mouseLoc = [self convertPoint:[theEvent locationInWindow] - fromView:nil]; - BOOL isInside = [self mouse:mouseLoc inRect:[self bounds]]; - [self highlight:isInside]; - - switch ([theEvent type]) { - case NSLeftMouseUp: - durationMouseWasDown_ = [theEvent timestamp] - whenMouseDown_; - [self secondaryMouseUpAction:isInside]; - break; - default: - /* Ignore any other kind of event. */ - break; - } - } - - [self highlight:NO]; } -// Mimic "begin a click" operation visually. Do NOT follow through -// with normal button event handling. - (void)mouseDown:(NSEvent*)theEvent { - [[NSCursor arrowCursor] set]; - - whenMouseDown_ = [theEvent timestamp]; - actionHasFired_ = NO; - - if (draggable_) { - NSDate* date = [NSDate dateWithTimeIntervalSinceNow:kDragExpirationTimeout]; - if ([self dragShouldBeginFromMouseDown:theEvent - withExpiration:date]) { - [self beginDrag:theEvent]; - [self endDrag]; - } else { - if (actsOnMouseDown_) { - [self performMouseDownAction:theEvent]; - } else { - [super mouseDown:theEvent]; - } - - } - } else { - if (actsOnMouseDown_) { - [self performMouseDownAction:theEvent]; - } else { - [super mouseDown:theEvent]; - } + if ([draggableButtonImpl_ mouseDown:theEvent] == + kDraggableButtonMixinCallSuper) { + [super mouseDown:theEvent]; } } @@ -221,8 +45,4 @@ const CGFloat kDragExpirationTimeout = 0.45; NOTREACHED(); } -- (void)endDrag { - [self highlight:NO]; -} - @end // @interface DraggableButton |