root/chrome/browser/ui/cocoa/draggable_button_mixin.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// 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_

#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)mouseDownImpl:(NSEvent*)event;
- (DraggableButtonResult)mouseUpImpl:(NSEvent*)event;

@end

#endif  // CHROME_BROWSER_UI_COCOA_DRAGGABLE_BUTTON_MIXIN_H_

/* [<][>][^][v][top][bottom][index][help] */