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"
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";
20 const CGFloat kAnimationDuration = 0.2;
21 const CGFloat kGrippyWidth = 4.0;
22 const CGFloat kMinimumContainerWidth = 10.0;
25 @interface BrowserActionsContainerView(Private)
26 // Returns the cursor that should be shown when hovering over the grippy based
27 // on |canDragLeft_| and |canDragRight_|.
28 - (NSCursor*)appropriateCursorForGrippy;
31 @implementation BrowserActionsContainerView
33 @synthesize animationEndFrame = animationEndFrame_;
34 @synthesize canDragLeft = canDragLeft_;
35 @synthesize canDragRight = canDragRight_;
36 @synthesize grippyPinned = grippyPinned_;
37 @synthesize maxWidth = maxWidth_;
38 @synthesize userIsResizing = userIsResizing_;
41 #pragma mark Overridden Class Functions
43 - (id)initWithFrame:(NSRect)frameRect {
44 if ((self = [super initWithFrame:frameRect])) {
45 grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds]));
54 - (void)setResizable:(BOOL)resizable {
55 if (resizable == resizable_)
57 resizable_ = resizable;
58 [self setNeedsDisplay:YES];
65 - (void)resetCursorRects {
66 [self discardCursorRects];
67 [self addCursorRect:grippyRect_ cursor:[self appropriateCursorForGrippy]];
70 - (BOOL)acceptsFirstResponder {
74 - (void)mouseDown:(NSEvent*)theEvent {
75 initialDragPoint_ = [self convertPoint:[theEvent locationInWindow]
78 !NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped]))
81 lastXPos_ = [self frame].origin.x;
82 userIsResizing_ = YES;
84 [[self appropriateCursorForGrippy] push];
85 // Disable cursor rects so that the Omnibox and other UI elements don't push
86 // cursors while the user is dragging. The cursor should be grippy until
87 // the |-mouseUp:| message is received.
88 [[self window] disableCursorRects];
90 [[NSNotificationCenter defaultCenter]
91 postNotificationName:kBrowserActionGrippyDragStartedNotification
95 - (void)mouseUp:(NSEvent*)theEvent {
100 [[self window] enableCursorRects];
102 userIsResizing_ = NO;
103 [[NSNotificationCenter defaultCenter]
104 postNotificationName:kBrowserActionGrippyDragFinishedNotification
108 - (void)mouseDragged:(NSEvent*)theEvent {
109 if (!userIsResizing_)
112 NSPoint location = [self convertPoint:[theEvent locationInWindow]
114 NSRect containerFrame = [self frame];
115 CGFloat dX = [theEvent deltaX];
116 CGFloat withDelta = location.x - dX;
117 canDragRight_ = (withDelta >= initialDragPoint_.x) &&
118 (NSWidth(containerFrame) > kMinimumContainerWidth);
119 canDragLeft_ = (withDelta <= initialDragPoint_.x) &&
120 (NSWidth(containerFrame) < maxWidth_);
121 if ((dX < 0.0 && !canDragLeft_) || (dX > 0.0 && !canDragRight_))
124 containerFrame.size.width =
125 std::max(NSWidth(containerFrame) - dX, kMinimumContainerWidth);
127 if (NSWidth(containerFrame) == kMinimumContainerWidth)
130 containerFrame.origin.x += dX;
132 [self setFrame:containerFrame];
133 [self setNeedsDisplay:YES];
135 [[NSNotificationCenter defaultCenter]
136 postNotificationName:kBrowserActionGrippyDraggingNotification
143 return VIEW_ID_BROWSER_ACTION_TOOLBAR;
147 #pragma mark Public Methods
149 - (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate {
150 width = std::max(width, kMinimumContainerWidth);
151 NSRect frame = [self frame];
152 lastXPos_ = frame.origin.x;
153 CGFloat dX = frame.size.width - width;
154 frame.size.width = width;
155 NSRect newFrame = NSOffsetRect(frame, dX, 0);
157 [NSAnimationContext beginGrouping];
158 [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
159 [[self animator] setFrame:newFrame];
160 [NSAnimationContext endGrouping];
161 animationEndFrame_ = newFrame;
163 [self setFrame:newFrame];
164 [self setNeedsDisplay:YES];
168 - (CGFloat)resizeDeltaX {
169 return [self frame].origin.x - lastXPos_;
173 #pragma mark Private Methods
175 // Returns the cursor to display over the grippy hover region depending on the
176 // current drag state.
177 - (NSCursor*)appropriateCursorForGrippy {
179 if (!resizable_ || (!canDragLeft_ && !canDragRight_)) {
180 retVal = [NSCursor arrowCursor];
181 } else if (!canDragLeft_) {
182 retVal = [NSCursor resizeRightCursor];
183 } else if (!canDragRight_) {
184 retVal = [NSCursor resizeLeftCursor];
186 retVal = [NSCursor resizeLeftRightCursor];