OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifndef CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_MIXIN_H_ |
| 6 #define CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_MIXIN_H_ |
| 7 #pragma once |
| 8 |
| 9 #import <Cocoa/Cocoa.h> |
| 10 |
| 11 // The design of this class is extraordinarily poor. Apologies to all clients in |
| 12 // advance. Unfortunately, the lack of multiple inheritance and our desire to |
| 13 // avoid runtime hacks makes this convoluted dance necessary. |
| 14 // |
| 15 // Buttons that want to be draggable should implement the Mixin protocol below |
| 16 // and keep an instance of the Impl as an ivar. The button should forward mouse |
| 17 // events to the impl, which will tell the button whether or not to call super |
| 18 // and let the event be handled normally. |
| 19 // |
| 20 // If the impl decides to do work on the event, methods of the mixin protocol |
| 21 // may be called. Some of the methods declared in that protocol have base |
| 22 // implementations. If the method is not implemented by the button, that base |
| 23 // implementation will be called. Otherwise, the button's implementation will |
| 24 // be called first and the DraggableButtonResult will be used to determine |
| 25 // whether the base implementation should be called. This requires the client to |
| 26 // understand what the base does. |
| 27 |
| 28 enum DraggableButtonResult { |
| 29 // Return values for Impl methods. |
| 30 kDraggableButtonImplDidWork, |
| 31 kDraggableButtonMixinCallSuper, |
| 32 |
| 33 // Return values for Mixin methods. |
| 34 kDraggableButtonMixinDidWork, |
| 35 kDraggableButtonImplUseBase, |
| 36 }; |
| 37 |
| 38 // Mixin Protocol ////////////////////////////////////////////////////////////// |
| 39 |
| 40 // Buttons that make use of the below impl need to conform to this protocol. |
| 41 @protocol DraggableButtonMixin |
| 42 |
| 43 @required |
| 44 |
| 45 // Called when a drag should start. Implement this to do any pasteboard |
| 46 // manipulation and begin the drag, usually with |
| 47 // -dragImage:at:offset:event:. Subclasses must call one of the blocking |
| 48 // -drag* methods of NSView when implementing this method. |
| 49 - (void)beginDrag:(NSEvent*)dragEvent; |
| 50 |
| 51 @optional |
| 52 |
| 53 // Called if the actsOnMouseDown property is set. Fires the button's action and |
| 54 // tracks the click. |
| 55 - (DraggableButtonResult)performMouseDownAction:(NSEvent*)theEvent; |
| 56 |
| 57 // Implement if you want to do any extra work on mouseUp, after a mouseDown |
| 58 // action has already fired. |
| 59 - (DraggableButtonResult)secondaryMouseUpAction:(BOOL)wasInside; |
| 60 |
| 61 // Resets the draggable state of the button after dragging is finished. This is |
| 62 // called by DraggableButtonImpl when the beginDrag call returns. |
| 63 - (DraggableButtonResult)endDrag; |
| 64 |
| 65 // Decides whether to treat the click as a cue to start dragging, or to instead |
| 66 // call the mouseDown/mouseUp handler as appropriate. Implement if you want to |
| 67 // do something tricky when making the decision. |
| 68 - (DraggableButtonResult)deltaIndicatesDragStartWithXDelta:(float)xDelta |
| 69 yDelta:(float)yDelta |
| 70 xHysteresis:(float)xHysteresis |
| 71 yHysteresis:(float)yHysteresis |
| 72 indicates:(BOOL*)result; |
| 73 |
| 74 // Decides if there is enough information to stop tracking the mouse. |
| 75 // It's deltaIndicatesDragStartWithXDelta, however, that decides whether it's a |
| 76 // drag or not. Implement if you want to do something tricky when making the |
| 77 // decision. |
| 78 - (DraggableButtonResult)deltaIndicatesConclusionReachedWithXDelta:(float)xDelta |
| 79 yDelta:(float)yDelta |
| 80 xHysteresis:(float)xHysteresis |
| 81 yHysteresis:(float)yHysteresis |
| 82 indicates:(BOOL*)result; |
| 83 |
| 84 @end |
| 85 |
| 86 // Impl Interface ////////////////////////////////////////////////////////////// |
| 87 |
| 88 // Implementation of the drag and drop logic. NSButton Mixin subclasses should |
| 89 // forward their mouse events to this, which in turn will call out to the mixin |
| 90 // protocol. |
| 91 @interface DraggableButtonImpl : NSObject { |
| 92 @private |
| 93 // The button for which this class is implementing stuff. |
| 94 NSButton<DraggableButtonMixin>* button_; |
| 95 |
| 96 // Is this a draggable type of button? |
| 97 BOOL draggable_; |
| 98 |
| 99 // Has the action already fired for this click? |
| 100 BOOL actionHasFired_; |
| 101 |
| 102 // Does button action happen on mouse down when possible? |
| 103 BOOL actsOnMouseDown_; |
| 104 |
| 105 NSTimeInterval durationMouseWasDown_; |
| 106 NSTimeInterval whenMouseDown_; |
| 107 } |
| 108 |
| 109 @property(nonatomic) NSTimeInterval durationMouseWasDown; |
| 110 |
| 111 @property(nonatomic) NSTimeInterval whenMouseDown; |
| 112 |
| 113 // Whether the action has already fired for this click. |
| 114 @property(nonatomic) BOOL actionHasFired; |
| 115 |
| 116 // Enable or disable dragability for special buttons like "Other Bookmarks". |
| 117 @property(nonatomic) BOOL draggable; |
| 118 |
| 119 // If it has a popup menu, for example, we want to perform the action on mouse |
| 120 // down, if possible (as long as user still gets chance to drag, if |
| 121 // appropriate). |
| 122 @property(nonatomic) BOOL actsOnMouseDown; |
| 123 |
| 124 // Designated initializer. |
| 125 - (id)initWithButton:(NSButton<DraggableButtonMixin>*)button; |
| 126 |
| 127 // NSResponder implementation. NSButton subclasses should invoke these methods |
| 128 // and only call super if the return value indicates such. |
| 129 - (DraggableButtonResult)mouseDown:(NSEvent*)event; |
| 130 - (DraggableButtonResult)mouseUp:(NSEvent*)event; |
| 131 |
| 132 @end |
| 133 |
| 134 #endif // CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_MIXIN_H_ |
OLD | NEW |