Commit 4f61f537 authored by rsesek@chromium.org's avatar rsesek@chromium.org

[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
parent a195ec36
...@@ -337,8 +337,8 @@ void RecordAppLaunch(Profile* profile, GURL url) { ...@@ -337,8 +337,8 @@ void RecordAppLaunch(Profile* profile, GURL url) {
[[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)]; [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)];
// Complete init of the "off the side" button, as much as we can. // Complete init of the "off the side" button, as much as we can.
[offTheSideButton_ setDraggable:NO]; [offTheSideButton_.draggableButton setDraggable:NO];
[offTheSideButton_ setActsOnMouseDown:YES]; [offTheSideButton_.draggableButton setActsOnMouseDown:YES];
// We are enabled by default. // We are enabled by default.
barIsEnabled_ = YES; barIsEnabled_ = YES;
...@@ -1116,7 +1116,7 @@ void RecordAppLaunch(Profile* profile, GURL url) { ...@@ -1116,7 +1116,7 @@ void RecordAppLaunch(Profile* profile, GURL url) {
if (node->is_folder()) { if (node->is_folder()) {
[button setTarget:self]; [button setTarget:self];
[button setAction:@selector(openBookmarkFolderFromButton:)]; [button setAction:@selector(openBookmarkFolderFromButton:)];
[button setActsOnMouseDown:YES]; [[button draggableButton] setActsOnMouseDown:YES];
// If it has a title, and it will be truncated, show full title in // If it has a title, and it will be truncated, show full title in
// tooltip. // tooltip.
NSString* title = base::SysUTF16ToNSString(node->GetTitle()); NSString* title = base::SysUTF16ToNSString(node->GetTitle());
...@@ -1194,8 +1194,8 @@ void RecordAppLaunch(Profile* profile, GURL url) { ...@@ -1194,8 +1194,8 @@ void RecordAppLaunch(Profile* profile, GURL url) {
frame.origin.x = [[self buttonView] bounds].size.width - frame.size.width; frame.origin.x = [[self buttonView] bounds].size.width - frame.size.width;
frame.origin.x -= bookmarks::kBookmarkHorizontalPadding; frame.origin.x -= bookmarks::kBookmarkHorizontalPadding;
BookmarkButton* button = [[BookmarkButton alloc] initWithFrame:frame]; BookmarkButton* button = [[BookmarkButton alloc] initWithFrame:frame];
[button setDraggable:NO]; [[button draggableButton] setDraggable:NO];
[button setActsOnMouseDown:YES]; [[button draggableButton] setActsOnMouseDown:YES];
otherBookmarksButton_.reset(button); otherBookmarksButton_.reset(button);
view_id_util::SetID(button, VIEW_ID_OTHER_BOOKMARKS); view_id_util::SetID(button, VIEW_ID_OTHER_BOOKMARKS);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
#include <cmath>
#include "base/logging.h" #include "base/logging.h"
#import "base/memory/scoped_nsobject.h" #import "base/memory/scoped_nsobject.h"
#include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/bookmarks/bookmark_model.h"
...@@ -122,23 +124,23 @@ BookmarkButton* gDraggedButton = nil; // Weak ...@@ -122,23 +124,23 @@ BookmarkButton* gDraggedButton = nil; // Weak
[super updateTrackingAreas]; [super updateTrackingAreas];
} }
- (BOOL)deltaIndicatesDragStartWithXDelta:(float)xDelta - (DraggableButtonResult)deltaIndicatesDragStartWithXDelta:(float)xDelta
yDelta:(float)yDelta yDelta:(float)yDelta
xHysteresis:(float)xHysteresis xHysteresis:(float)xHysteresis
yHysteresis:(float)yHysteresis { yHysteresis:(float)yHysteresis
indicates:(BOOL*)result {
const float kDownProportion = 1.4142135f; // Square root of 2. const float kDownProportion = 1.4142135f; // Square root of 2.
// We want to show a folder menu when you drag down on folder buttons, // We want to show a folder menu when you drag down on folder buttons,
// so don't classify this as a drag for that case. // so don't classify this as a drag for that case.
if ([self isFolder] && if ([self isFolder] &&
(yDelta <= -yHysteresis) && // Bottom of hysteresis box was hit. (yDelta <= -yHysteresis) && // Bottom of hysteresis box was hit.
(ABS(yDelta)/ABS(xDelta)) >= kDownProportion) (std::abs(yDelta) / std::abs(xDelta)) >= kDownProportion) {
return NO; *result = NO;
return kDraggableButtonMixinDidWork;
return [super deltaIndicatesDragStartWithXDelta:xDelta }
yDelta:yDelta
xHysteresis:xHysteresis return kDraggableButtonImplUseBase;
yHysteresis:yHysteresis];
} }
...@@ -218,7 +220,7 @@ BookmarkButton* gDraggedButton = nil; // Weak ...@@ -218,7 +220,7 @@ BookmarkButton* gDraggedButton = nil; // Weak
} }
// Overridden to release bar visibility. // Overridden to release bar visibility.
- (void)endDrag { - (DraggableButtonResult)endDrag {
gDraggedButton = nil; gDraggedButton = nil;
// visibilityDelegate_ can be nil if we're detached, and that's fine. // visibilityDelegate_ can be nil if we're detached, and that's fine.
...@@ -226,7 +228,8 @@ BookmarkButton* gDraggedButton = nil; // Weak ...@@ -226,7 +228,8 @@ BookmarkButton* gDraggedButton = nil; // Weak
withAnimation:YES withAnimation:YES
delay:YES]; delay:YES];
visibilityDelegate_ = nil; visibilityDelegate_ = nil;
[super endDrag];
return kDraggableButtonImplUseBase;
} }
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
...@@ -255,9 +258,10 @@ BookmarkButton* gDraggedButton = nil; // Weak ...@@ -255,9 +258,10 @@ BookmarkButton* gDraggedButton = nil; // Weak
} }
} }
- (void)performMouseDownAction:(NSEvent*)theEvent { - (DraggableButtonResult)performMouseDownAction:(NSEvent*)theEvent {
[[self target] performSelector:[self action] withObject:self]; [[self target] performSelector:[self action] withObject:self];
self.actionHasFired = YES; self.draggableButton.actionHasFired = YES;
return kDraggableButtonMixinDidWork;
} }
// BookmarkButtonCell. We redirect this information to our delegate. // BookmarkButtonCell. We redirect this information to our delegate.
...@@ -291,10 +295,11 @@ BookmarkButton* gDraggedButton = nil; // Weak ...@@ -291,10 +295,11 @@ BookmarkButton* gDraggedButton = nil; // Weak
} }
// This only gets called after a click that wasn't a drag, and only on folders. // This only gets called after a click that wasn't a drag, and only on folders.
- (void)secondaryMouseUpAction:(BOOL)wasInside { - (DraggableButtonResult)secondaryMouseUpAction:(BOOL)wasInside {
const NSTimeInterval kShortClickLength = 0.5; const NSTimeInterval kShortClickLength = 0.5;
// Long clicks that end over the folder button result in the menu hiding. // Long clicks that end over the folder button result in the menu hiding.
if (wasInside && ([self durationMouseWasDown] > kShortClickLength)) { if (wasInside &&
self.draggableButton.durationMouseWasDown > kShortClickLength) {
[[self target] performSelector:[self action] withObject:self]; [[self target] performSelector:[self action] withObject:self];
} else { } else {
// Mouse tracked out of button during menu track. Hide menus. // Mouse tracked out of button during menu track. Hide menus.
...@@ -302,6 +307,7 @@ BookmarkButton* gDraggedButton = nil; // Weak ...@@ -302,6 +307,7 @@ BookmarkButton* gDraggedButton = nil; // Weak
[delegate_ bookmarkDragDidEnd:self [delegate_ bookmarkDragDidEnd:self
operation:NSDragOperationNone]; operation:NSDragOperationNone];
} }
return kDraggableButtonMixinDidWork;
} }
@end @end
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
NSCell* cell = [self cell]; NSCell* cell = [self cell];
DCHECK([cell respondsToSelector:@selector(isMouseOverButtonPart)]); DCHECK([cell respondsToSelector:@selector(isMouseOverButtonPart)]);
if ([reinterpret_cast<DownloadItemCell*>(cell) isMouseOverButtonPart]) { if ([reinterpret_cast<DownloadItemCell*>(cell) isMouseOverButtonPart]) {
[super mouseDown:event]; [self.draggableButton mouseDown:event];
} else { } else {
// Hold a reference to our controller in case the download completes and we // Hold a reference to our controller in case the download completes and we
// represent a file that's auto-removed (e.g. a theme). // represent a file that's auto-removed (e.g. a theme).
......
// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_H_
#define CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_H_
#pragma once
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "base/memory/scoped_nsobject.h"
#import "chrome/browser/ui/cocoa/draggable_button_mixin.h"
// Class for buttons that can be drag sources. If the mouse is clicked and moved // Class for buttons that can be drag sources. If the mouse is clicked and moved
// more than a given distance, this class will call |-beginDrag:| instead of // more than a given distance, this class will call |-beginDrag:| instead of
// |-performClick:|. Subclasses should override these two methods. // |-performClick:|. Subclasses should override these two methods.
@interface DraggableButton : NSButton { @interface DraggableButton : NSButton<DraggableButtonMixin> {
@private @private
BOOL draggable_; // Is this a draggable type of button? scoped_nsobject<DraggableButtonImpl> draggableButtonImpl_;
BOOL actionHasFired_; // Has the action already fired for this click?
BOOL actsOnMouseDown_; // Does button action happen on mouse down when
// possible?
NSTimeInterval durationMouseWasDown_;
NSTimeInterval whenMouseDown_;
} }
@property NSTimeInterval durationMouseWasDown; @property(readonly, nonatomic) DraggableButtonImpl* draggableButton;
@property NSTimeInterval whenMouseDown;
// Whether the action has already fired for this click.
@property(nonatomic) BOOL actionHasFired;
// Enable or disable dragability for special buttons like "Other Bookmarks".
@property(nonatomic) BOOL draggable;
// If it has a popup menu, for example, we want to perform the action on mouse
// down, if possible (as long as user still gets chance to drag, if
// appropriate).
@property(nonatomic) BOOL actsOnMouseDown;
// Called when a drag should start. Subclasses must override this to do any
// pasteboard manipulation and begin the drag, usually with
// -dragImage:at:offset:event:. Subclasses must call one of the blocking
// -drag* methods of NSView when overriding this method.
- (void)beginDrag:(NSEvent*)dragEvent;
// Override if you want to do any extra work on mouseUp, after a mouseDown
// action has already fired.
- (void)secondaryMouseUpAction:(BOOL)wasInside;
// This is called internally.
// Decides if we now have enough information to stop tracking the mouse.
// It's the function below, deltaIndicatesDragStartWithXDelta. however, that
// decides whether it's a drag or not.
// Override if you want to do something tricky when making the decision.
// Default impl returns YES if ABS(xDelta) or ABS(yDelta) >= their respective
// hysteresis limit.
- (BOOL)deltaIndicatesConclusionReachedWithXDelta:(float)xDelta
yDelta:(float)yDelta
xHysteresis:(float)xHysteresis
yHysteresis:(float)yHysteresis;
// This is called internally.
// Decides whether we should treat the click as a cue to start dragging, or
// instead call the mouseDown/mouseUp handler as appropriate.
// Override if you want to do something tricky when making the decision.
// Default impl returns YES if ABS(xDelta) or ABS(yDelta) >= their respective
// hysteresis limit.
- (BOOL)deltaIndicatesDragStartWithXDelta:(float)xDelta
yDelta:(float)yDelta
xHysteresis:(float)xHysteresis
yHysteresis:(float)yHysteresis;
@end // @interface DraggableButton
@interface DraggableButton (Private)
// Resets the draggable state of the button after dragging is finished. This is
// called by DraggableButton when the beginDrag call returns, it should not be
// called by the subclass.
- (void)endDrag;
// Called internally if the actsOnMouseDown property is set.
// Fires the button's action and tracks the click.
- (void)performMouseDownAction:(NSEvent*)theEvent;
@end
@end // @interface DraggableButton(Private) #endif // CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_H_
...@@ -5,214 +5,38 @@ ...@@ -5,214 +5,38 @@
#import "chrome/browser/ui/cocoa/draggable_button.h" #import "chrome/browser/ui/cocoa/draggable_button.h"
#include "base/logging.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 @implementation DraggableButton
@synthesize draggable = draggable_;
@synthesize actsOnMouseDown = actsOnMouseDown_;
@synthesize durationMouseWasDown = durationMouseWasDown_;
@synthesize actionHasFired = actionHasFired_;
@synthesize whenMouseDown = whenMouseDown_;
- (id)initWithFrame:(NSRect)frame { - (id)initWithFrame:(NSRect)frame {
if ((self = [super initWithFrame:frame])) { if ((self = [super initWithFrame:frame])) {
draggable_ = YES; draggableButtonImpl_.reset(
actsOnMouseDown_ = NO; [[DraggableButtonImpl alloc] initWithButton:self]);
actionHasFired_ = NO;
} }
return self; return self;
} }
- (id)initWithCoder:(NSCoder*)coder { - (id)initWithCoder:(NSCoder*)coder {
if ((self = [super initWithCoder:coder])) { if ((self = [super initWithCoder:coder])) {
draggable_ = YES; draggableButtonImpl_.reset(
actsOnMouseDown_ = NO; [[DraggableButtonImpl alloc] initWithButton:self]);
actionHasFired_ = NO;
} }
return self; return self;
} }
- (BOOL)deltaIndicatesDragStartWithXDelta:(float)xDelta - (DraggableButtonImpl*)draggableButton {
yDelta:(float)yDelta return draggableButtonImpl_.get();
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];
} }
- (void)mouseUp:(NSEvent*)theEvent { - (void)mouseUp:(NSEvent*)theEvent {
durationMouseWasDown_ = [theEvent timestamp] - whenMouseDown_; if ([draggableButtonImpl_ mouseUp:theEvent] == kDraggableButtonMixinCallSuper)
if (actionHasFired_)
return;
if (!draggable_) {
[super mouseUp:theEvent]; [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 { - (void)mouseDown:(NSEvent*)theEvent {
[[NSCursor arrowCursor] set]; if ([draggableButtonImpl_ mouseDown:theEvent] ==
kDraggableButtonMixinCallSuper) {
whenMouseDown_ = [theEvent timestamp]; [super mouseDown:theEvent];
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];
}
} }
} }
...@@ -221,8 +45,4 @@ const CGFloat kDragExpirationTimeout = 0.45; ...@@ -221,8 +45,4 @@ const CGFloat kDragExpirationTimeout = 0.45;
NOTREACHED(); NOTREACHED();
} }
- (void)endDrag {
[self highlight:NO];
}
@end // @interface DraggableButton @end // @interface DraggableButton
// Copyright (c) 2011 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.
#ifndef CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_MIXIN_H_
#define CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_MIXIN_H_
#pragma once
#import <Cocoa/Cocoa.h>
// The design of this class is extraordinarily poor. Apologies to all clients in
// advance. Unfortunately, the lack of multiple inheritance and our desire to
// avoid runtime hacks makes this convoluted dance necessary.
//
// Buttons that want to be draggable should implement the Mixin protocol below
// and keep an instance of the Impl as an ivar. The button should forward mouse
// events to the impl, which will tell the button whether or not to call super
// and let the event be handled normally.
//
// If the impl decides to do work on the event, methods of the mixin protocol
// may be called. Some of the methods declared in that protocol have base
// implementations. If the method is not implemented by the button, that base
// implementation will be called. Otherwise, the button's implementation will
// be called first and the DraggableButtonResult will be used to determine
// whether the base implementation should be called. This requires the client to
// understand what the base does.
enum DraggableButtonResult {
// Return values for Impl methods.
kDraggableButtonImplDidWork,
kDraggableButtonMixinCallSuper,
// Return values for Mixin methods.
kDraggableButtonMixinDidWork,
kDraggableButtonImplUseBase,
};
// Mixin Protocol //////////////////////////////////////////////////////////////
// Buttons that make use of the below impl need to conform to this protocol.
@protocol DraggableButtonMixin
@required
// Called when a drag should start. Implement this to do any pasteboard
// manipulation and begin the drag, usually with
// -dragImage:at:offset:event:. Subclasses must call one of the blocking
// -drag* methods of NSView when implementing this method.
- (void)beginDrag:(NSEvent*)dragEvent;
@optional
// Called if the actsOnMouseDown property is set. Fires the button's action and
// tracks the click.
- (DraggableButtonResult)performMouseDownAction:(NSEvent*)theEvent;
// Implement if you want to do any extra work on mouseUp, after a mouseDown
// action has already fired.
- (DraggableButtonResult)secondaryMouseUpAction:(BOOL)wasInside;
// Resets the draggable state of the button after dragging is finished. This is
// called by DraggableButtonImpl when the beginDrag call returns.
- (DraggableButtonResult)endDrag;
// Decides whether to treat the click as a cue to start dragging, or to instead
// call the mouseDown/mouseUp handler as appropriate. Implement if you want to
// do something tricky when making the decision.
- (DraggableButtonResult)deltaIndicatesDragStartWithXDelta:(float)xDelta
yDelta:(float)yDelta
xHysteresis:(float)xHysteresis
yHysteresis:(float)yHysteresis
indicates:(BOOL*)result;
// Decides if there is enough information to stop tracking the mouse.
// It's deltaIndicatesDragStartWithXDelta, however, that decides whether it's a
// drag or not. Implement if you want to do something tricky when making the
// decision.
- (DraggableButtonResult)deltaIndicatesConclusionReachedWithXDelta:(float)xDelta
yDelta:(float)yDelta
xHysteresis:(float)xHysteresis
yHysteresis:(float)yHysteresis
indicates:(BOOL*)result;
@end
// Impl Interface //////////////////////////////////////////////////////////////
// Implementation of the drag and drop logic. NSButton Mixin subclasses should
// forward their mouse events to this, which in turn will call out to the mixin
// protocol.
@interface DraggableButtonImpl : NSObject {
@private
// The button for which this class is implementing stuff.
NSButton<DraggableButtonMixin>* button_;
// Is this a draggable type of button?
BOOL draggable_;
// Has the action already fired for this click?
BOOL actionHasFired_;
// Does button action happen on mouse down when possible?
BOOL actsOnMouseDown_;
NSTimeInterval durationMouseWasDown_;
NSTimeInterval whenMouseDown_;
}
@property(nonatomic) NSTimeInterval durationMouseWasDown;
@property(nonatomic) NSTimeInterval whenMouseDown;
// Whether the action has already fired for this click.
@property(nonatomic) BOOL actionHasFired;
// Enable or disable dragability for special buttons like "Other Bookmarks".
@property(nonatomic) BOOL draggable;
// If it has a popup menu, for example, we want to perform the action on mouse
// down, if possible (as long as user still gets chance to drag, if
// appropriate).
@property(nonatomic) BOOL actsOnMouseDown;
// Designated initializer.
- (id)initWithButton:(NSButton<DraggableButtonMixin>*)button;
// NSResponder implementation. NSButton subclasses should invoke these methods
// and only call super if the return value indicates such.
- (DraggableButtonResult)mouseDown:(NSEvent*)event;
- (DraggableButtonResult)mouseUp:(NSEvent*)event;
@end
#endif // CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_MIXIN_H_
This diff is collapsed.
...@@ -2445,6 +2445,8 @@ ...@@ -2445,6 +2445,8 @@
'browser/ui/cocoa/download/download_util_mac.mm', 'browser/ui/cocoa/download/download_util_mac.mm',
'browser/ui/cocoa/draggable_button.h', 'browser/ui/cocoa/draggable_button.h',
'browser/ui/cocoa/draggable_button.mm', 'browser/ui/cocoa/draggable_button.mm',
'browser/ui/cocoa/draggable_button_mixin.h',
'browser/ui/cocoa/draggable_button_mixin.mm',
'browser/ui/cocoa/drag_util.h', 'browser/ui/cocoa/drag_util.h',
'browser/ui/cocoa/drag_util.mm', 'browser/ui/cocoa/drag_util.mm',
'browser/ui/cocoa/encoding_menu_controller_delegate_mac.h', 'browser/ui/cocoa/encoding_menu_controller_delegate_mac.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment