| Index: chrome/browser/cocoa/extensions/browser_actions_container_view.mm
|
| ===================================================================
|
| --- chrome/browser/cocoa/extensions/browser_actions_container_view.mm (revision 41123)
|
| +++ chrome/browser/cocoa/extensions/browser_actions_container_view.mm (working copy)
|
| @@ -2,40 +2,64 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <algorithm>
|
| +
|
| #import "base/scoped_nsobject.h"
|
| #import "chrome/browser/cocoa/extensions/browser_action_button.h"
|
| #import "chrome/browser/cocoa/extensions/browser_actions_container_view.h"
|
|
|
| +extern const NSString* kBrowserActionGrippyDragStartedNotification =
|
| + @"BrowserActionGrippyDragStartedNotification";
|
| +extern const NSString* kBrowserActionGrippyDraggingNotification =
|
| + @"BrowserActionGrippyDraggingNotification";
|
| +extern const NSString* kBrowserActionGrippyDragFinishedNotification =
|
| + @"BrowserActionGrippyDragFinishedNotification";
|
| +
|
| namespace {
|
| - const CGFloat kGrippyLowerPadding = 4.0;
|
| - const CGFloat kGrippyUpperPadding = 8.0;
|
| - const CGFloat kRightBorderXOffset = -1.0;
|
| - const CGFloat kRightBorderWidth = 1.0;
|
| - const CGFloat kRightBorderGrayscale = 0.5;
|
| - const CGFloat kUpperPadding = 9.0;
|
| - const CGFloat kLowerPadding = 5.0;
|
| +const CGFloat kAnimationDuration = 0.1;
|
| +const CGFloat kGrippyLowerPadding = 4.0;
|
| +const CGFloat kGrippyUpperPadding = 8.0;
|
| +const CGFloat kGrippyWidth = 10.0;
|
| +const CGFloat kLowerPadding = 5.0;
|
| +const CGFloat kMinimumContainerWidth = 5.0;
|
| +const CGFloat kRightBorderXOffset = -1.0;
|
| +const CGFloat kRightBorderWidth = 1.0;
|
| +const CGFloat kRightBorderGrayscale = 0.5;
|
| +const CGFloat kUpperPadding = 9.0;
|
| } // namespace
|
|
|
| @interface BrowserActionsContainerView(Private)
|
| -- (void)drawLeftGrippers;
|
| +- (NSCursor*)appropriateCursorForGrippy;
|
| +- (void)drawGrippy;
|
| @end
|
|
|
| @implementation BrowserActionsContainerView
|
|
|
| +@synthesize canDragLeft = canDragLeft_;
|
| +@synthesize canDragRight = canDragRight_;
|
| +@synthesize grippyPinned = grippyPinned_;
|
| +@synthesize userIsResizing = userIsResizing_;
|
| @synthesize rightBorderShown = rightBorderShown_;
|
|
|
| +- (id)initWithFrame:(NSRect)frameRect {
|
| + if ((self = [super initWithFrame:frameRect])) {
|
| + grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds]));
|
| + }
|
| + return self;
|
| +}
|
| +
|
| - (void)drawRect:(NSRect)dirtyRect {
|
| - NSRect bounds = [self bounds];
|
| if (rightBorderShown_) {
|
| + NSRect bounds = [self bounds];
|
| NSColor* middleColor =
|
| [NSColor colorWithCalibratedWhite:kRightBorderGrayscale alpha:1.0];
|
| NSColor* endPointColor =
|
| [NSColor colorWithCalibratedWhite:kRightBorderGrayscale alpha:0.0];
|
| - NSGradient* borderGradient = [[[NSGradient alloc]
|
| + scoped_nsobject<NSGradient> borderGradient([[NSGradient alloc]
|
| initWithColorsAndLocations:endPointColor, (CGFloat)0.0,
|
| middleColor, (CGFloat)0.5,
|
| endPointColor, (CGFloat)1.0,
|
| - nil] autorelease];
|
| + nil]);
|
| CGFloat xPos = bounds.origin.x + bounds.size.width - kRightBorderWidth +
|
| kRightBorderXOffset;
|
| NSRect borderRect = NSMakeRect(xPos, kLowerPadding, kRightBorderWidth,
|
| @@ -43,10 +67,12 @@
|
| [borderGradient drawInRect:borderRect angle:90.0];
|
| }
|
|
|
| - [self drawLeftGrippers];
|
| + [self drawGrippy];
|
| }
|
|
|
| -- (void)drawLeftGrippers {
|
| +// Draws the area that the user can use to resize the container. Currently, two
|
| +// vertical "grip" bars.
|
| +- (void)drawGrippy {
|
| NSRect grippyRect = NSMakeRect(0.0, kLowerPadding + kGrippyLowerPadding, 1.0,
|
| [self bounds].size.height - kUpperPadding - kGrippyUpperPadding);
|
| [[NSColor colorWithCalibratedWhite:0.7 alpha:0.5] set];
|
| @@ -67,8 +93,122 @@
|
| NSRectFill(grippyRect);
|
| }
|
|
|
| +- (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate {
|
| + width = std::max(width, kMinimumContainerWidth);
|
| + NSRect frame = [self frame];
|
| + lastXPos_ = frame.origin.x;
|
| + CGFloat dX = frame.size.width - width;
|
| + frame.size.width = width;
|
| + NSRect newFrame = NSOffsetRect(frame, dX, 0);
|
| + if (animate) {
|
| + [NSAnimationContext beginGrouping];
|
| + [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
|
| + [[self animator] setFrame:newFrame];
|
| + [NSAnimationContext endGrouping];
|
| + } else {
|
| + // TODO(andybons): Worry about animations already in progress in this case.
|
| + [self setFrame:newFrame];
|
| + }
|
| + [self setNeedsDisplay:YES];
|
| +}
|
| +
|
| - (BrowserActionButton*)buttonAtIndex:(NSUInteger)index {
|
| return [[self subviews] objectAtIndex:index];
|
| }
|
|
|
| +// Returns the cursor to display over the grippy hover region depending on the
|
| +// current drag state.
|
| +- (NSCursor*)appropriateCursorForGrippy {
|
| + NSCursor* retVal;
|
| + if (!canDragLeft_ && !canDragRight_) {
|
| + retVal = [NSCursor arrowCursor];
|
| + } else if (!canDragLeft_) {
|
| + retVal = [NSCursor resizeRightCursor];
|
| + } else if (!canDragRight_) {
|
| + retVal = [NSCursor resizeLeftCursor];
|
| + } else {
|
| + retVal = [NSCursor resizeLeftRightCursor];
|
| + }
|
| + return retVal;
|
| +}
|
| +
|
| +- (void)resetCursorRects {
|
| + [self discardCursorRects];
|
| + [self addCursorRect:grippyRect_ cursor:[self appropriateCursorForGrippy]];
|
| +}
|
| +
|
| +- (BOOL)acceptsFirstResponder {
|
| + return YES;
|
| +}
|
| +
|
| +- (void)mouseDown:(NSEvent*)theEvent {
|
| + initialDragPoint_ = [self convertPoint:[theEvent locationInWindow]
|
| + fromView:nil];
|
| + if (!NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped]))
|
| + return;
|
| +
|
| + lastXPos_ = [self frame].origin.x;
|
| + userIsResizing_ = YES;
|
| + [[NSNotificationCenter defaultCenter]
|
| + postNotificationName:kBrowserActionGrippyDragStartedNotification
|
| + object:self];
|
| + // TODO(andybons): The cursor does not stick once moved outside of the
|
| + // toolbar. Investigate further. http://crbug.com/36698
|
| + while (1) {
|
| + // This inner run loop catches and removes mouse up and drag events from the
|
| + // default event queue and dispatches them to the appropriate custom
|
| + // handlers. This is to prevent the cursor from changing (or any other side-
|
| + // effects of dragging the mouse around the app).
|
| + theEvent =
|
| + [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask
|
| + untilDate:[NSDate distantFuture]
|
| + inMode:NSDefaultRunLoopMode dequeue:YES];
|
| +
|
| + NSEventType type = [theEvent type];
|
| + if (type == NSLeftMouseDragged) {
|
| + [self mouseDragged:theEvent];
|
| + } else if (type == NSLeftMouseUp) {
|
| + [self mouseUp:theEvent];
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +- (void)mouseUp:(NSEvent*)theEvent {
|
| + userIsResizing_ = NO;
|
| + [[NSNotificationCenter defaultCenter]
|
| + postNotificationName:kBrowserActionGrippyDragFinishedNotification
|
| + object:self];
|
| +}
|
| +
|
| +- (void)mouseDragged:(NSEvent*)theEvent {
|
| + if (!userIsResizing_)
|
| + return;
|
| +
|
| + NSPoint location = [self convertPoint:[theEvent locationInWindow]
|
| + fromView:nil];
|
| + CGFloat dX = [theEvent deltaX];
|
| + CGFloat withDelta = location.x - dX;
|
| + canDragRight_ = withDelta >= initialDragPoint_.x;
|
| +
|
| + if ((dX < 0.0 && !canDragLeft_) || (dX > 0.0 && !canDragRight_))
|
| + return;
|
| +
|
| + NSRect containerFrame = [self frame];
|
| + containerFrame.origin.x += dX;
|
| + containerFrame.size.width -= dX;
|
| + [self setFrame:containerFrame];
|
| + [self setNeedsDisplay:YES];
|
| +
|
| + [[NSNotificationCenter defaultCenter]
|
| + postNotificationName:kBrowserActionGrippyDraggingNotification
|
| + object:self];
|
| +
|
| + lastXPos_ += dX;
|
| +}
|
| +
|
| +- (CGFloat)resizeDeltaX {
|
| + return [self frame].origin.x - lastXPos_;
|
| +}
|
| +
|
| @end
|
|
|