Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / extensions / browser_actions_container_view.mm
blobecd68752398300c86fdc5f14fdc5650bf067c349
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.
5 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
7 #include <algorithm>
9 #include "base/basictypes.h"
10 #import "chrome/browser/ui/cocoa/view_id_util.h"
12 NSString* const kBrowserActionGrippyDragStartedNotification =
13     @"BrowserActionGrippyDragStartedNotification";
14 NSString* const kBrowserActionGrippyDraggingNotification =
15     @"BrowserActionGrippyDraggingNotification";
16 NSString* const kBrowserActionGrippyDragFinishedNotification =
17     @"BrowserActionGrippyDragFinishedNotification";
18 NSString* const kBrowserActionsContainerWillAnimate =
19     @"BrowserActionsContainerWillAnimate";
20 NSString* const kBrowserActionsContainerMouseEntered =
21     @"BrowserActionsContainerMouseEntered";
22 NSString* const kTranslationWithDelta =
23     @"TranslationWithDelta";
25 namespace {
26 const CGFloat kAnimationDuration = 0.2;
27 const CGFloat kGrippyWidth = 3.0;
28 const CGFloat kMinimumContainerWidth = 3.0;
29 }  // namespace
31 @interface BrowserActionsContainerView(Private)
32 // Returns the cursor that should be shown when hovering over the grippy based
33 // on |canDragLeft_| and |canDragRight_|.
34 - (NSCursor*)appropriateCursorForGrippy;
36 // Returns the maximum allowed size for the container.
37 - (CGFloat)maxAllowedWidth;
38 @end
40 @implementation BrowserActionsContainerView
42 @synthesize canDragLeft = canDragLeft_;
43 @synthesize canDragRight = canDragRight_;
44 @synthesize grippyPinned = grippyPinned_;
45 @synthesize maxDesiredWidth = maxDesiredWidth_;
46 @synthesize userIsResizing = userIsResizing_;
47 @synthesize delegate = delegate_;
49 #pragma mark -
50 #pragma mark Overridden Class Functions
52 - (id)initWithFrame:(NSRect)frameRect {
53   if ((self = [super initWithFrame:frameRect])) {
54     grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds]));
55     canDragLeft_ = YES;
56     canDragRight_ = YES;
57     resizable_ = YES;
59     resizeAnimation_.reset([[NSViewAnimation alloc] init]);
60     [resizeAnimation_ setDuration:kAnimationDuration];
61     [resizeAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
63     [self setHidden:YES];
64   }
65   return self;
68 - (void)dealloc {
69   if (trackingArea_.get())
70     [self removeTrackingArea:trackingArea_.get()];
71   [super dealloc];
74 - (void)setTrackingEnabled:(BOOL)enabled {
75   if (enabled) {
76     trackingArea_.reset(
77         [[CrTrackingArea alloc] initWithRect:NSZeroRect
78                                      options:NSTrackingMouseEnteredAndExited |
79                                              NSTrackingActiveInActiveApp |
80                                              NSTrackingInVisibleRect
81                                        owner:self
82                                     userInfo:nil]);
83     [self addTrackingArea:trackingArea_.get()];
84   } else if (trackingArea_.get()) {
85     [self removeTrackingArea:trackingArea_.get()];
86     [trackingArea_.get() clearOwner];
87     trackingArea_.reset(nil);
88   }
91 - (void)setResizable:(BOOL)resizable {
92   if (resizable == resizable_)
93     return;
94   resizable_ = resizable;
95   [self setNeedsDisplay:YES];
98 - (BOOL)isResizable {
99   return resizable_;
102 - (void)resetCursorRects {
103   [self addCursorRect:grippyRect_ cursor:[self appropriateCursorForGrippy]];
106 - (BOOL)acceptsFirstResponder {
107   return YES;
110 - (void)mouseEntered:(NSEvent*)theEvent {
111   [[NSNotificationCenter defaultCenter]
112       postNotificationName:kBrowserActionsContainerMouseEntered
113                     object:self];
116 - (void)mouseDown:(NSEvent*)theEvent {
117   initialDragPoint_ = [self convertPoint:[theEvent locationInWindow]
118                                 fromView:nil];
119   if (!resizable_ ||
120       !NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped]))
121     return;
123   userIsResizing_ = YES;
125   [[self appropriateCursorForGrippy] push];
126   // Disable cursor rects so that the Omnibox and other UI elements don't push
127   // cursors while the user is dragging. The cursor should be grippy until
128   // the |-mouseUp:| message is received.
129   [[self window] disableCursorRects];
131   [[NSNotificationCenter defaultCenter]
132       postNotificationName:kBrowserActionGrippyDragStartedNotification
133                     object:self];
136 - (void)mouseUp:(NSEvent*)theEvent {
137   if (!userIsResizing_)
138     return;
140   [NSCursor pop];
141   [[self window] enableCursorRects];
143   userIsResizing_ = NO;
144   [[NSNotificationCenter defaultCenter]
145       postNotificationName:kBrowserActionGrippyDragFinishedNotification
146                     object:self];
149 - (void)mouseDragged:(NSEvent*)theEvent {
150   if (!userIsResizing_)
151     return;
153   NSPoint location = [self convertPoint:[theEvent locationInWindow]
154                                fromView:nil];
155   NSRect containerFrame = [self frame];
156   CGFloat dX = [theEvent deltaX];
157   CGFloat withDelta = location.x - dX;
158   canDragRight_ = (withDelta >= initialDragPoint_.x) &&
159       (NSWidth(containerFrame) > kMinimumContainerWidth);
160   CGFloat maxAllowedWidth = [self maxAllowedWidth];
161   containerFrame.size.width =
162       std::max(NSWidth(containerFrame) - dX, kMinimumContainerWidth);
163   canDragLeft_ = withDelta <= initialDragPoint_.x &&
164       NSWidth(containerFrame) < maxDesiredWidth_ &&
165       NSWidth(containerFrame) < maxAllowedWidth;
167   if ((dX < 0.0 && !canDragLeft_) || (dX > 0.0 && !canDragRight_))
168     return;
170   if (NSWidth(containerFrame) <= kMinimumContainerWidth)
171     return;
173   grippyPinned_ = NSWidth(containerFrame) >= maxAllowedWidth;
174   containerFrame.origin.x += dX;
176   [self setFrame:containerFrame];
177   [self setNeedsDisplay:YES];
179   [[NSNotificationCenter defaultCenter]
180       postNotificationName:kBrowserActionGrippyDraggingNotification
181                     object:self];
184 - (ViewID)viewID {
185   return VIEW_ID_BROWSER_ACTION_TOOLBAR;
188 #pragma mark -
189 #pragma mark Public Methods
191 - (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate {
192   width = std::max(width, kMinimumContainerWidth);
193   NSRect frame = [self frame];
195   CGFloat maxAllowedWidth = [self maxAllowedWidth];
196   width = std::min(maxAllowedWidth, width);
198   CGFloat dX = frame.size.width - width;
199   frame.size.width = width;
200   NSRect newFrame = NSOffsetRect(frame, dX, 0);
202   grippyPinned_ = width == maxAllowedWidth;
204   [self stopAnimation];
206   if (animate) {
207     NSDictionary* animationDictionary = @{
208       NSViewAnimationTargetKey : self,
209       NSViewAnimationStartFrameKey : [NSValue valueWithRect:[self frame]],
210       NSViewAnimationEndFrameKey : [NSValue valueWithRect:newFrame]
211     };
212     [resizeAnimation_ setViewAnimations:@[ animationDictionary ]];
213     [resizeAnimation_ startAnimation];
215     [[NSNotificationCenter defaultCenter]
216         postNotificationName:kBrowserActionsContainerWillAnimate
217                       object:self];
218   } else {
219     [self setFrame:newFrame];
220     [self setNeedsDisplay:YES];
221   }
224 - (NSRect)animationEndFrame {
225   if ([resizeAnimation_ isAnimating]) {
226     NSRect endFrame = [[[[resizeAnimation_ viewAnimations] objectAtIndex:0]
227         valueForKey:NSViewAnimationEndFrameKey] rectValue];
228     return endFrame;
229   } else {
230     return [self frame];
231   }
234 - (BOOL)isAnimating {
235   return [resizeAnimation_ isAnimating];
238 - (void)stopAnimation {
239   if ([resizeAnimation_ isAnimating])
240     [resizeAnimation_ stopAnimation];
243 #pragma mark -
244 #pragma mark Private Methods
246 // Returns the cursor to display over the grippy hover region depending on the
247 // current drag state.
248 - (NSCursor*)appropriateCursorForGrippy {
249   NSCursor* retVal;
250   if (!resizable_ || (!canDragLeft_ && !canDragRight_)) {
251     retVal = [NSCursor arrowCursor];
252   } else if (!canDragLeft_) {
253     retVal = [NSCursor resizeRightCursor];
254   } else if (!canDragRight_) {
255     retVal = [NSCursor resizeLeftCursor];
256   } else {
257     retVal = [NSCursor resizeLeftRightCursor];
258   }
259   return retVal;
262 - (CGFloat)maxAllowedWidth {
263   return delegate_ ? delegate_->GetMaxAllowedWidth() : CGFLOAT_MAX;
266 @end