Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / clickhold_button_cell.mm
blobec4ee7e811e9d33098f448351cdac64902c5c3df
1 // Copyright (c) 2009 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.
5 #import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
7 #include "base/logging.h"
9 // Minimum and maximum click-hold timeout.
10 static const NSTimeInterval kMinTimeout = 0.0;
11 static const NSTimeInterval kMaxTimeout = 5.0;
13 // Drag distance threshold to activate click-hold; should be >= 0.
14 static const CGFloat kDragDistThreshold = 2.5;
16 // See |-resetToDefaults| (and header file) for other default values.
18 @interface ClickHoldButtonCell (Private)
19 - (void)resetToDefaults;
20 @end  // @interface ClickHoldButtonCell (Private)
22 @implementation ClickHoldButtonCell
24 @synthesize enableClickHold = enableClickHold_;
25 @synthesize clickHoldTimeout = clickHoldTimeout_;
26 @synthesize trackOnlyInRect = trackOnlyInRect_;
27 @synthesize activateOnDrag = activateOnDrag_;
28 @synthesize clickHoldTarget = clickHoldTarget_;
29 @synthesize clickHoldAction = clickHoldAction_;
31 // Overrides:
33 + (BOOL)prefersTrackingUntilMouseUp {
34   return NO;
37 - (id)init {
38   if ((self = [super init]))
39     [self resetToDefaults];
40   return self;
43 - (id)initWithCoder:(NSCoder*)decoder {
44   if ((self = [super initWithCoder:decoder]))
45     [self resetToDefaults];
46   return self;
49 - (id)initImageCell:(NSImage*)image {
50   if ((self = [super initImageCell:image]))
51     [self resetToDefaults];
52   return self;
55 - (id)initTextCell:(NSString*)string {
56   if ((self = [super initTextCell:string]))
57     [self resetToDefaults];
58   return self;
61 - (BOOL)startTrackingAt:(NSPoint)startPoint
62                  inView:(NSView*)controlView {
63   return enableClickHold_ ? YES :
64                             [super startTrackingAt:startPoint
65                                             inView:controlView];
68 - (BOOL)continueTracking:(NSPoint)lastPoint
69                       at:(NSPoint)currentPoint
70                   inView:(NSView*)controlView {
71   return enableClickHold_ ? YES :
72                             [super continueTracking:lastPoint
73                                                  at:currentPoint
74                                              inView:controlView];
77 - (BOOL)trackMouse:(NSEvent*)originalEvent
78             inRect:(NSRect)cellFrame
79             ofView:(NSView*)controlView
80       untilMouseUp:(BOOL)untilMouseUp {
81   if (!enableClickHold_) {
82     return [super trackMouse:originalEvent
83                       inRect:cellFrame
84                       ofView:controlView
85                 untilMouseUp:untilMouseUp];
86   }
88   // If doing click-hold, track the mouse ourselves.
89   NSPoint currPoint = [controlView convertPoint:[originalEvent locationInWindow]
90                                        fromView:nil];
91   NSPoint lastPoint = currPoint;
92   NSPoint firstPoint = currPoint;
93   NSTimeInterval timeout =
94       MAX(MIN(clickHoldTimeout_, kMaxTimeout), kMinTimeout);
95   NSDate* clickHoldBailTime = [NSDate dateWithTimeIntervalSinceNow:timeout];
97   if (![self startTrackingAt:currPoint inView:controlView])
98     return NO;
100   enum {
101     kContinueTrack, kStopClickHold, kStopMouseUp, kStopLeftRect, kStopNoContinue
102   } state = kContinueTrack;
103   do {
104     NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
105                                                    NSLeftMouseUpMask)
106                                         untilDate:clickHoldBailTime
107                                            inMode:NSEventTrackingRunLoopMode
108                                           dequeue:YES];
109     currPoint = [controlView convertPoint:[event locationInWindow]
110                                  fromView:nil];
112     // Time-out.
113     if (!event) {
114       state = kStopClickHold;
116     // Drag? (If distance meets threshold.)
117     } else if (activateOnDrag_ && ([event type] == NSLeftMouseDragged)) {
118       CGFloat dx = currPoint.x - firstPoint.x;
119       CGFloat dy = currPoint.y - firstPoint.y;
120       if ((dx*dx + dy*dy) >= (kDragDistThreshold*kDragDistThreshold))
121         state = kStopClickHold;
123     // Mouse up.
124     } else if ([event type] == NSLeftMouseUp) {
125       state = kStopMouseUp;
127     // Stop tracking if mouse left frame rectangle (if requested to do so).
128     } else if (trackOnlyInRect_ && ![controlView mouse:currPoint
129                                                 inRect:cellFrame]) {
130       state = kStopLeftRect;
132     // Stop tracking if instructed to.
133     } else if (![self continueTracking:lastPoint
134                                     at:currPoint
135                                 inView:controlView]) {
136       state = kStopNoContinue;
137     }
139     lastPoint = currPoint;
140   } while (state == kContinueTrack);
142   [self stopTracking:lastPoint
143                   at:lastPoint
144               inView:controlView
145            mouseIsUp:NO];
147   switch (state) {
148     case kStopClickHold:
149       if (clickHoldAction_) {
150         [static_cast<NSControl*>(controlView) sendAction:clickHoldAction_
151                                                       to:clickHoldTarget_];
152       }
153       return YES;
155     case kStopMouseUp:
156       if ([self action]) {
157         [static_cast<NSControl*>(controlView) sendAction:[self action]
158                                                       to:[self target]];
159       }
160       return YES;
162     case kStopLeftRect:
163     case kStopNoContinue:
164       return NO;
166     default:
167       NOTREACHED() << "Unknown terminating state!";
168   }
170   return NO;
173 @end  // @implementation ClickHoldButtonCell
175 @implementation ClickHoldButtonCell (Private)
177 // Resets various members to defaults indicated in the header file. (Those
178 // without indicated defaults are *not* touched.) Please keep the values below
179 // in sync with the header file, and please be aware of side-effects on code
180 // which relies on the "published" defaults.
181 - (void)resetToDefaults {
182   [self setEnableClickHold:NO];
183   [self setClickHoldTimeout:0.25];
184   [self setTrackOnlyInRect:NO];
185   [self setActivateOnDrag:YES];
188 @end  // @implementation ClickHoldButtonCell (Private)