| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h" | 5 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #import "chrome/browser/ui/cocoa/l10n_util.h" | 10 #import "chrome/browser/ui/cocoa/l10n_util.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 NSString* const kTranslationWithDelta = | 25 NSString* const kTranslationWithDelta = |
| 26 @"TranslationWithDelta"; | 26 @"TranslationWithDelta"; |
| 27 NSString* const kBrowserActionsContainerReceivedKeyEvent = | 27 NSString* const kBrowserActionsContainerReceivedKeyEvent = |
| 28 @"BrowserActionsContainerReceivedKeyEvent"; | 28 @"BrowserActionsContainerReceivedKeyEvent"; |
| 29 NSString* const kBrowserActionsContainerKeyEventKey = | 29 NSString* const kBrowserActionsContainerKeyEventKey = |
| 30 @"BrowserActionsContainerKeyEventKey"; | 30 @"BrowserActionsContainerKeyEventKey"; |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 const CGFloat kAnimationDuration = 0.2; | 33 const CGFloat kAnimationDuration = 0.2; |
| 34 const CGFloat kGrippyWidth = 3.0; | 34 const CGFloat kGrippyWidth = 3.0; |
| 35 const CGFloat kMinimumContainerWidth = 3.0; | |
| 36 } // namespace | 35 } // namespace |
| 37 | 36 |
| 38 @interface BrowserActionsContainerView(Private) | 37 @interface BrowserActionsContainerView(Private) |
| 39 // Returns the cursor that should be shown when hovering over the grippy based | 38 // Returns the cursor that should be shown when hovering over the grippy based |
| 40 // on |canDragLeft_| and |canDragRight_|. | 39 // on |canDragLeft_| and |canDragRight_|. |
| 41 - (NSCursor*)appropriateCursorForGrippy; | 40 - (NSCursor*)appropriateCursorForGrippy; |
| 42 | |
| 43 // Returns the maximum allowed size for the container. | |
| 44 - (CGFloat)maxAllowedWidth; | |
| 45 @end | 41 @end |
| 46 | 42 |
| 47 @implementation BrowserActionsContainerView | 43 @implementation BrowserActionsContainerView |
| 48 | 44 |
| 49 @synthesize canDragLeft = canDragLeft_; | 45 @synthesize minWidth = minWidth_; |
| 50 @synthesize canDragRight = canDragRight_; | 46 @synthesize maxWidth = maxWidth_; |
| 51 @synthesize grippyPinned = grippyPinned_; | 47 @synthesize grippyPinned = grippyPinned_; |
| 52 @synthesize maxDesiredWidth = maxDesiredWidth_; | |
| 53 @synthesize userIsResizing = userIsResizing_; | 48 @synthesize userIsResizing = userIsResizing_; |
| 54 @synthesize delegate = delegate_; | |
| 55 | 49 |
| 56 #pragma mark - | 50 #pragma mark - |
| 57 #pragma mark Overridden Class Functions | 51 #pragma mark Overridden Class Functions |
| 58 | 52 |
| 59 - (id)initWithFrame:(NSRect)frameRect { | 53 - (id)initWithFrame:(NSRect)frameRect { |
| 60 if ((self = [super initWithFrame:frameRect])) { | 54 if ((self = [super initWithFrame:frameRect])) { |
| 61 grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds])); | 55 grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds])); |
| 62 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) | 56 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) |
| 63 grippyRect_.origin.x = NSWidth(frameRect) - NSWidth(grippyRect_); | 57 grippyRect_.origin.x = NSWidth(frameRect) - NSWidth(grippyRect_); |
| 64 | 58 |
| 65 canDragLeft_ = YES; | |
| 66 canDragRight_ = YES; | |
| 67 resizable_ = YES; | 59 resizable_ = YES; |
| 68 | 60 |
| 69 resizeAnimation_.reset([[NSViewAnimation alloc] init]); | 61 resizeAnimation_.reset([[NSViewAnimation alloc] init]); |
| 70 [resizeAnimation_ setDuration:kAnimationDuration]; | 62 [resizeAnimation_ setDuration:kAnimationDuration]; |
| 71 [resizeAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; | 63 [resizeAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; |
| 72 [resizeAnimation_ setDelegate:self]; | 64 [resizeAnimation_ setDelegate:self]; |
| 73 | 65 |
| 74 [self setHidden:YES]; | 66 [self setHidden:YES]; |
| 75 } | 67 } |
| 76 return self; | 68 return self; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 } | 164 } |
| 173 | 165 |
| 174 - (BOOL)acceptsFirstResponder { | 166 - (BOOL)acceptsFirstResponder { |
| 175 // The overflow container needs to receive key events to handle in-item | 167 // The overflow container needs to receive key events to handle in-item |
| 176 // navigation. The top-level container should not become first responder, | 168 // navigation. The top-level container should not become first responder, |
| 177 // allowing focus travel to proceed to the first action. | 169 // allowing focus travel to proceed to the first action. |
| 178 return isOverflow_; | 170 return isOverflow_; |
| 179 } | 171 } |
| 180 | 172 |
| 181 - (void)mouseDown:(NSEvent*)theEvent { | 173 - (void)mouseDown:(NSEvent*)theEvent { |
| 182 initialDragPoint_ = [self convertPoint:[theEvent locationInWindow] | 174 NSPoint location = |
| 183 fromView:nil]; | 175 [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
| 184 if (!resizable_ || | 176 if (!resizable_ || !NSMouseInRect(location, grippyRect_, [self isFlipped])) |
| 185 !NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped])) | |
| 186 return; | 177 return; |
| 187 | 178 |
| 179 dragOffset_ = location.x - (cocoa_l10n_util::ShouldDoExperimentalRTLLayout() |
| 180 ? NSWidth(self.frame) |
| 181 : 0); |
| 182 |
| 188 userIsResizing_ = YES; | 183 userIsResizing_ = YES; |
| 189 | 184 |
| 190 [[self appropriateCursorForGrippy] push]; | 185 [[self appropriateCursorForGrippy] push]; |
| 191 // Disable cursor rects so that the Omnibox and other UI elements don't push | 186 // Disable cursor rects so that the Omnibox and other UI elements don't push |
| 192 // cursors while the user is dragging. The cursor should be grippy until | 187 // cursors while the user is dragging. The cursor should be grippy until |
| 193 // the |-mouseUp:| message is received. | 188 // the |-mouseUp:| message is received. |
| 194 [[self window] disableCursorRects]; | 189 [[self window] disableCursorRects]; |
| 195 | 190 |
| 196 [[NSNotificationCenter defaultCenter] | 191 [[NSNotificationCenter defaultCenter] |
| 197 postNotificationName:kBrowserActionGrippyDragStartedNotification | 192 postNotificationName:kBrowserActionGrippyDragStartedNotification |
| (...skipping 10 matching lines...) Expand all Loading... |
| 208 userIsResizing_ = NO; | 203 userIsResizing_ = NO; |
| 209 [[NSNotificationCenter defaultCenter] | 204 [[NSNotificationCenter defaultCenter] |
| 210 postNotificationName:kBrowserActionGrippyDragFinishedNotification | 205 postNotificationName:kBrowserActionGrippyDragFinishedNotification |
| 211 object:self]; | 206 object:self]; |
| 212 } | 207 } |
| 213 | 208 |
| 214 - (void)mouseDragged:(NSEvent*)theEvent { | 209 - (void)mouseDragged:(NSEvent*)theEvent { |
| 215 if (!userIsResizing_) | 210 if (!userIsResizing_) |
| 216 return; | 211 return; |
| 217 | 212 |
| 218 NSPoint location = [self convertPoint:[theEvent locationInWindow] | 213 const CGFloat translation = |
| 219 fromView:nil]; | 214 [self convertPoint:[theEvent locationInWindow] fromView:nil].x - |
| 220 NSRect containerFrame = [self frame]; | 215 dragOffset_; |
| 221 CGFloat dX = [theEvent deltaX]; | 216 const CGFloat targetWidth = (cocoa_l10n_util::ShouldDoExperimentalRTLLayout() |
| 222 CGFloat withDelta = location.x - dX; | 217 ? translation |
| 223 BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); | 218 : NSWidth(self.frame) - translation); |
| 224 | 219 |
| 225 CGFloat maxAllowedWidth = [self maxAllowedWidth]; | 220 [self resizeToWidth:targetWidth animate:NO]; |
| 226 | |
| 227 const CGFloat maxWidth = std::min(maxAllowedWidth, maxDesiredWidth_); | |
| 228 CGFloat newWidth = NSWidth(containerFrame) + (isRTL ? dX : -dX); | |
| 229 newWidth = std::min(std::max(newWidth, kMinimumContainerWidth), maxWidth); | |
| 230 | |
| 231 BOOL canGrow = NSWidth(containerFrame) < maxWidth; | |
| 232 BOOL canShrink = NSWidth(containerFrame) > kMinimumContainerWidth; | |
| 233 | |
| 234 canDragLeft_ = | |
| 235 withDelta <= initialDragPoint_.x && (isRTL ? canShrink : canGrow); | |
| 236 canDragRight_ = | |
| 237 (withDelta >= initialDragPoint_.x) && (isRTL ? canGrow : canShrink); | |
| 238 if ((dX < 0.0 && !canDragLeft_) || (dX > 0.0 && !canDragRight_) || | |
| 239 fabs(dX) < FLT_EPSILON) | |
| 240 return; | |
| 241 | |
| 242 grippyPinned_ = newWidth >= maxAllowedWidth; | |
| 243 if (!isRTL) | |
| 244 containerFrame.origin.x += dX; | |
| 245 containerFrame.size.width = newWidth; | |
| 246 | |
| 247 [self setFrame:containerFrame]; | |
| 248 [self setNeedsDisplay:YES]; | |
| 249 | 221 |
| 250 [[NSNotificationCenter defaultCenter] | 222 [[NSNotificationCenter defaultCenter] |
| 251 postNotificationName:kBrowserActionGrippyDraggingNotification | 223 postNotificationName:kBrowserActionGrippyDraggingNotification |
| 252 object:self]; | 224 object:self]; |
| 253 } | 225 } |
| 254 | 226 |
| 255 - (void)animationDidEnd:(NSAnimation*)animation { | 227 - (void)animationDidEnd:(NSAnimation*)animation { |
| 256 // We notify asynchronously so that the animation fully finishes before any | 228 // We notify asynchronously so that the animation fully finishes before any |
| 257 // listeners do work. | 229 // listeners do work. |
| 258 [self performSelector:@selector(notifyAnimationEnded) | 230 [self performSelector:@selector(notifyAnimationEnded) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 275 } | 247 } |
| 276 | 248 |
| 277 - (ViewID)viewID { | 249 - (ViewID)viewID { |
| 278 return VIEW_ID_BROWSER_ACTION_TOOLBAR; | 250 return VIEW_ID_BROWSER_ACTION_TOOLBAR; |
| 279 } | 251 } |
| 280 | 252 |
| 281 #pragma mark - | 253 #pragma mark - |
| 282 #pragma mark Public Methods | 254 #pragma mark Public Methods |
| 283 | 255 |
| 284 - (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate { | 256 - (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate { |
| 285 width = std::max(width, kMinimumContainerWidth); | 257 width = std::min(std::max(width, minWidth_), maxWidth_); |
| 258 |
| 286 NSRect newFrame = [self frame]; | 259 NSRect newFrame = [self frame]; |
| 260 if (!cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) |
| 261 newFrame.origin.x += NSWidth(newFrame) - width; |
| 262 newFrame.size.width = width; |
| 287 | 263 |
| 288 CGFloat maxAllowedWidth = [self maxAllowedWidth]; | 264 grippyPinned_ = width == maxWidth_; |
| 289 width = std::min(maxAllowedWidth, width); | |
| 290 | |
| 291 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) { | |
| 292 newFrame.size.width = width; | |
| 293 } else { | |
| 294 CGFloat dX = NSWidth(newFrame) - width; | |
| 295 newFrame.size.width = width; | |
| 296 newFrame.origin.x += dX; | |
| 297 } | |
| 298 | |
| 299 grippyPinned_ = width == maxAllowedWidth; | |
| 300 | 265 |
| 301 [self stopAnimation]; | 266 [self stopAnimation]; |
| 302 | 267 |
| 303 if (animate) { | 268 if (animate) { |
| 304 NSDictionary* animationDictionary = @{ | 269 NSDictionary* animationDictionary = @{ |
| 305 NSViewAnimationTargetKey : self, | 270 NSViewAnimationTargetKey : self, |
| 306 NSViewAnimationStartFrameKey : [NSValue valueWithRect:[self frame]], | 271 NSViewAnimationStartFrameKey : [NSValue valueWithRect:[self frame]], |
| 307 NSViewAnimationEndFrameKey : [NSValue valueWithRect:newFrame] | 272 NSViewAnimationEndFrameKey : [NSValue valueWithRect:newFrame] |
| 308 }; | 273 }; |
| 309 [resizeAnimation_ setViewAnimations:@[ animationDictionary ]]; | 274 [resizeAnimation_ setViewAnimations:@[ animationDictionary ]]; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 336 if ([resizeAnimation_ isAnimating]) | 301 if ([resizeAnimation_ isAnimating]) |
| 337 [resizeAnimation_ stopAnimation]; | 302 [resizeAnimation_ stopAnimation]; |
| 338 } | 303 } |
| 339 | 304 |
| 340 #pragma mark - | 305 #pragma mark - |
| 341 #pragma mark Private Methods | 306 #pragma mark Private Methods |
| 342 | 307 |
| 343 // Returns the cursor to display over the grippy hover region depending on the | 308 // Returns the cursor to display over the grippy hover region depending on the |
| 344 // current drag state. | 309 // current drag state. |
| 345 - (NSCursor*)appropriateCursorForGrippy { | 310 - (NSCursor*)appropriateCursorForGrippy { |
| 346 NSCursor* retVal; | 311 if (resizable_) { |
| 347 if (!resizable_ || (!canDragLeft_ && !canDragRight_)) { | 312 const CGFloat width = NSWidth(self.frame); |
| 348 retVal = [NSCursor arrowCursor]; | 313 const BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); |
| 349 } else if (!canDragLeft_) { | 314 const BOOL canDragLeft = width != (isRTL ? minWidth_ : maxWidth_); |
| 350 retVal = [NSCursor resizeRightCursor]; | 315 const BOOL canDragRight = width != (isRTL ? maxWidth_ : minWidth_); |
| 351 } else if (!canDragRight_) { | 316 |
| 352 retVal = [NSCursor resizeLeftCursor]; | 317 if (canDragLeft && canDragRight) |
| 353 } else { | 318 return [NSCursor resizeLeftRightCursor]; |
| 354 retVal = [NSCursor resizeLeftRightCursor]; | 319 if (canDragLeft) |
| 320 return [NSCursor resizeLeftCursor]; |
| 321 if (canDragRight) |
| 322 return [NSCursor resizeRightCursor]; |
| 355 } | 323 } |
| 356 return retVal; | 324 return [NSCursor arrowCursor]; |
| 357 } | |
| 358 | |
| 359 - (CGFloat)maxAllowedWidth { | |
| 360 return delegate_ ? delegate_->GetMaxAllowedWidth() : CGFLOAT_MAX; | |
| 361 } | 325 } |
| 362 | 326 |
| 363 @end | 327 @end |
| OLD | NEW |