Index: chrome/browser/ui/cocoa/draggable_button_mixin.h |
diff --git a/chrome/browser/ui/cocoa/draggable_button_mixin.h b/chrome/browser/ui/cocoa/draggable_button_mixin.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c769bcd55c2869a5289d12465f5b9831a92a65a8 |
--- /dev/null |
+++ b/chrome/browser/ui/cocoa/draggable_button_mixin.h |
@@ -0,0 +1,134 @@ |
+// 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_ |