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