OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include <algorithm> |
| 6 |
5 #import "base/scoped_nsobject.h" | 7 #import "base/scoped_nsobject.h" |
6 #import "chrome/browser/cocoa/extensions/browser_action_button.h" | 8 #import "chrome/browser/cocoa/extensions/browser_action_button.h" |
7 #import "chrome/browser/cocoa/extensions/browser_actions_container_view.h" | 9 #import "chrome/browser/cocoa/extensions/browser_actions_container_view.h" |
8 | 10 |
| 11 extern const NSString* kBrowserActionGrippyDragStartedNotification = |
| 12 @"BrowserActionGrippyDragStartedNotification"; |
| 13 extern const NSString* kBrowserActionGrippyDraggingNotification = |
| 14 @"BrowserActionGrippyDraggingNotification"; |
| 15 extern const NSString* kBrowserActionGrippyDragFinishedNotification = |
| 16 @"BrowserActionGrippyDragFinishedNotification"; |
| 17 |
9 namespace { | 18 namespace { |
10 const CGFloat kGrippyLowerPadding = 4.0; | 19 const CGFloat kAnimationDuration = 0.1; |
11 const CGFloat kGrippyUpperPadding = 8.0; | 20 const CGFloat kGrippyLowerPadding = 4.0; |
12 const CGFloat kRightBorderXOffset = -1.0; | 21 const CGFloat kGrippyUpperPadding = 8.0; |
13 const CGFloat kRightBorderWidth = 1.0; | 22 const CGFloat kGrippyWidth = 10.0; |
14 const CGFloat kRightBorderGrayscale = 0.5; | 23 const CGFloat kLowerPadding = 5.0; |
15 const CGFloat kUpperPadding = 9.0; | 24 const CGFloat kMinimumContainerWidth = 5.0; |
16 const CGFloat kLowerPadding = 5.0; | 25 const CGFloat kRightBorderXOffset = -1.0; |
| 26 const CGFloat kRightBorderWidth = 1.0; |
| 27 const CGFloat kRightBorderGrayscale = 0.5; |
| 28 const CGFloat kUpperPadding = 9.0; |
17 } // namespace | 29 } // namespace |
18 | 30 |
19 @interface BrowserActionsContainerView(Private) | 31 @interface BrowserActionsContainerView(Private) |
20 - (void)drawLeftGrippers; | 32 - (NSCursor*)appropriateCursorForGrippy; |
| 33 - (void)drawGrippy; |
21 @end | 34 @end |
22 | 35 |
23 @implementation BrowserActionsContainerView | 36 @implementation BrowserActionsContainerView |
24 | 37 |
| 38 @synthesize canDragLeft = canDragLeft_; |
| 39 @synthesize canDragRight = canDragRight_; |
| 40 @synthesize grippyPinned = grippyPinned_; |
| 41 @synthesize userIsResizing = userIsResizing_; |
25 @synthesize rightBorderShown = rightBorderShown_; | 42 @synthesize rightBorderShown = rightBorderShown_; |
26 | 43 |
| 44 - (id)initWithFrame:(NSRect)frameRect { |
| 45 if ((self = [super initWithFrame:frameRect])) { |
| 46 grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds])); |
| 47 } |
| 48 return self; |
| 49 } |
| 50 |
27 - (void)drawRect:(NSRect)dirtyRect { | 51 - (void)drawRect:(NSRect)dirtyRect { |
28 NSRect bounds = [self bounds]; | |
29 if (rightBorderShown_) { | 52 if (rightBorderShown_) { |
| 53 NSRect bounds = [self bounds]; |
30 NSColor* middleColor = | 54 NSColor* middleColor = |
31 [NSColor colorWithCalibratedWhite:kRightBorderGrayscale alpha:1.0]; | 55 [NSColor colorWithCalibratedWhite:kRightBorderGrayscale alpha:1.0]; |
32 NSColor* endPointColor = | 56 NSColor* endPointColor = |
33 [NSColor colorWithCalibratedWhite:kRightBorderGrayscale alpha:0.0]; | 57 [NSColor colorWithCalibratedWhite:kRightBorderGrayscale alpha:0.0]; |
34 NSGradient* borderGradient = [[[NSGradient alloc] | 58 scoped_nsobject<NSGradient> borderGradient([[NSGradient alloc] |
35 initWithColorsAndLocations:endPointColor, (CGFloat)0.0, | 59 initWithColorsAndLocations:endPointColor, (CGFloat)0.0, |
36 middleColor, (CGFloat)0.5, | 60 middleColor, (CGFloat)0.5, |
37 endPointColor, (CGFloat)1.0, | 61 endPointColor, (CGFloat)1.0, |
38 nil] autorelease]; | 62 nil]); |
39 CGFloat xPos = bounds.origin.x + bounds.size.width - kRightBorderWidth + | 63 CGFloat xPos = bounds.origin.x + bounds.size.width - kRightBorderWidth + |
40 kRightBorderXOffset; | 64 kRightBorderXOffset; |
41 NSRect borderRect = NSMakeRect(xPos, kLowerPadding, kRightBorderWidth, | 65 NSRect borderRect = NSMakeRect(xPos, kLowerPadding, kRightBorderWidth, |
42 bounds.size.height - kUpperPadding); | 66 bounds.size.height - kUpperPadding); |
43 [borderGradient drawInRect:borderRect angle:90.0]; | 67 [borderGradient drawInRect:borderRect angle:90.0]; |
44 } | 68 } |
45 | 69 |
46 [self drawLeftGrippers]; | 70 [self drawGrippy]; |
47 } | 71 } |
48 | 72 |
49 - (void)drawLeftGrippers { | 73 // Draws the area that the user can use to resize the container. Currently, two |
| 74 // vertical "grip" bars. |
| 75 - (void)drawGrippy { |
50 NSRect grippyRect = NSMakeRect(0.0, kLowerPadding + kGrippyLowerPadding, 1.0, | 76 NSRect grippyRect = NSMakeRect(0.0, kLowerPadding + kGrippyLowerPadding, 1.0, |
51 [self bounds].size.height - kUpperPadding - kGrippyUpperPadding); | 77 [self bounds].size.height - kUpperPadding - kGrippyUpperPadding); |
52 [[NSColor colorWithCalibratedWhite:0.7 alpha:0.5] set]; | 78 [[NSColor colorWithCalibratedWhite:0.7 alpha:0.5] set]; |
53 NSRectFill(grippyRect); | 79 NSRectFill(grippyRect); |
54 | 80 |
55 [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] set]; | 81 [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] set]; |
56 grippyRect.origin.x += 1.0; | 82 grippyRect.origin.x += 1.0; |
57 NSRectFill(grippyRect); | 83 NSRectFill(grippyRect); |
58 | 84 |
59 grippyRect.origin.x += 1.0; | 85 grippyRect.origin.x += 1.0; |
60 | 86 |
61 [[NSColor colorWithCalibratedWhite:0.7 alpha:0.5] set]; | 87 [[NSColor colorWithCalibratedWhite:0.7 alpha:0.5] set]; |
62 grippyRect.origin.x += 1.0; | 88 grippyRect.origin.x += 1.0; |
63 NSRectFill(grippyRect); | 89 NSRectFill(grippyRect); |
64 | 90 |
65 [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] set]; | 91 [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] set]; |
66 grippyRect.origin.x += 1.0; | 92 grippyRect.origin.x += 1.0; |
67 NSRectFill(grippyRect); | 93 NSRectFill(grippyRect); |
68 } | 94 } |
69 | 95 |
| 96 - (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate { |
| 97 width = std::max(width, kMinimumContainerWidth); |
| 98 NSRect frame = [self frame]; |
| 99 lastXPos_ = frame.origin.x; |
| 100 CGFloat dX = frame.size.width - width; |
| 101 frame.size.width = width; |
| 102 NSRect newFrame = NSOffsetRect(frame, dX, 0); |
| 103 if (animate) { |
| 104 [NSAnimationContext beginGrouping]; |
| 105 [[NSAnimationContext currentContext] setDuration:kAnimationDuration]; |
| 106 [[self animator] setFrame:newFrame]; |
| 107 [NSAnimationContext endGrouping]; |
| 108 } else { |
| 109 // TODO(andybons): Worry about animations already in progress in this case. |
| 110 [self setFrame:newFrame]; |
| 111 } |
| 112 [self setNeedsDisplay:YES]; |
| 113 } |
| 114 |
70 - (BrowserActionButton*)buttonAtIndex:(NSUInteger)index { | 115 - (BrowserActionButton*)buttonAtIndex:(NSUInteger)index { |
71 return [[self subviews] objectAtIndex:index]; | 116 return [[self subviews] objectAtIndex:index]; |
72 } | 117 } |
73 | 118 |
| 119 // Returns the cursor to display over the grippy hover region depending on the |
| 120 // current drag state. |
| 121 - (NSCursor*)appropriateCursorForGrippy { |
| 122 NSCursor* retVal; |
| 123 if (!canDragLeft_ && !canDragRight_) { |
| 124 retVal = [NSCursor arrowCursor]; |
| 125 } else if (!canDragLeft_) { |
| 126 retVal = [NSCursor resizeRightCursor]; |
| 127 } else if (!canDragRight_) { |
| 128 retVal = [NSCursor resizeLeftCursor]; |
| 129 } else { |
| 130 retVal = [NSCursor resizeLeftRightCursor]; |
| 131 } |
| 132 return retVal; |
| 133 } |
| 134 |
| 135 - (void)resetCursorRects { |
| 136 [self discardCursorRects]; |
| 137 [self addCursorRect:grippyRect_ cursor:[self appropriateCursorForGrippy]]; |
| 138 } |
| 139 |
| 140 - (BOOL)acceptsFirstResponder { |
| 141 return YES; |
| 142 } |
| 143 |
| 144 - (void)mouseDown:(NSEvent*)theEvent { |
| 145 initialDragPoint_ = [self convertPoint:[theEvent locationInWindow] |
| 146 fromView:nil]; |
| 147 if (!NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped])) |
| 148 return; |
| 149 |
| 150 lastXPos_ = [self frame].origin.x; |
| 151 userIsResizing_ = YES; |
| 152 [[NSNotificationCenter defaultCenter] |
| 153 postNotificationName:kBrowserActionGrippyDragStartedNotification |
| 154 object:self]; |
| 155 // TODO(andybons): The cursor does not stick once moved outside of the |
| 156 // toolbar. Investigate further. http://crbug.com/36698 |
| 157 while (1) { |
| 158 // This inner run loop catches and removes mouse up and drag events from the |
| 159 // default event queue and dispatches them to the appropriate custom |
| 160 // handlers. This is to prevent the cursor from changing (or any other side- |
| 161 // effects of dragging the mouse around the app). |
| 162 theEvent = |
| 163 [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask |
| 164 untilDate:[NSDate distantFuture] |
| 165 inMode:NSDefaultRunLoopMode dequeue:YES]; |
| 166 |
| 167 NSEventType type = [theEvent type]; |
| 168 if (type == NSLeftMouseDragged) { |
| 169 [self mouseDragged:theEvent]; |
| 170 } else if (type == NSLeftMouseUp) { |
| 171 [self mouseUp:theEvent]; |
| 172 break; |
| 173 } |
| 174 } |
| 175 } |
| 176 |
| 177 - (void)mouseUp:(NSEvent*)theEvent { |
| 178 userIsResizing_ = NO; |
| 179 [[NSNotificationCenter defaultCenter] |
| 180 postNotificationName:kBrowserActionGrippyDragFinishedNotification |
| 181 object:self]; |
| 182 } |
| 183 |
| 184 - (void)mouseDragged:(NSEvent*)theEvent { |
| 185 if (!userIsResizing_) |
| 186 return; |
| 187 |
| 188 NSPoint location = [self convertPoint:[theEvent locationInWindow] |
| 189 fromView:nil]; |
| 190 CGFloat dX = [theEvent deltaX]; |
| 191 CGFloat withDelta = location.x - dX; |
| 192 canDragRight_ = withDelta >= initialDragPoint_.x; |
| 193 |
| 194 if ((dX < 0.0 && !canDragLeft_) || (dX > 0.0 && !canDragRight_)) |
| 195 return; |
| 196 |
| 197 NSRect containerFrame = [self frame]; |
| 198 containerFrame.origin.x += dX; |
| 199 containerFrame.size.width -= dX; |
| 200 [self setFrame:containerFrame]; |
| 201 [self setNeedsDisplay:YES]; |
| 202 |
| 203 [[NSNotificationCenter defaultCenter] |
| 204 postNotificationName:kBrowserActionGrippyDraggingNotification |
| 205 object:self]; |
| 206 |
| 207 lastXPos_ += dX; |
| 208 } |
| 209 |
| 210 - (CGFloat)resizeDeltaX { |
| 211 return [self frame].origin.x - lastXPos_; |
| 212 } |
| 213 |
74 @end | 214 @end |
OLD | NEW |