Home | History | Annotate | Download | only in cocoa
      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