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 #import "chrome/browser/cocoa/bookmark_bar_folder_controller.h" | 5 #import "chrome/browser/cocoa/bookmark_bar_folder_controller.h" |
6 #include "base/mac_util.h" | 6 #include "base/mac_util.h" |
7 #include "base/nsimage_cache_mac.h" | 7 #include "base/nsimage_cache_mac.h" |
8 #include "base/sys_string_conversions.h" | 8 #include "base/sys_string_conversions.h" |
9 #include "chrome/browser/bookmarks/bookmark_model.h" | 9 #include "chrome/browser/bookmarks/bookmark_model.h" |
10 #include "chrome/browser/bookmarks/bookmark_utils.h" | 10 #include "chrome/browser/bookmarks/bookmark_utils.h" |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 - (void)toggleButtonBorderingWhileMouseInside { | 98 - (void)toggleButtonBorderingWhileMouseInside { |
99 BOOL toggle = [self showsBorderOnlyWhileMouseInside]; | 99 BOOL toggle = [self showsBorderOnlyWhileMouseInside]; |
100 [self setShowsBorderOnlyWhileMouseInside:!toggle]; | 100 [self setShowsBorderOnlyWhileMouseInside:!toggle]; |
101 [self setShowsBorderOnlyWhileMouseInside:toggle]; | 101 [self setShowsBorderOnlyWhileMouseInside:toggle]; |
102 } | 102 } |
103 | 103 |
104 @end | 104 @end |
105 | 105 |
106 @implementation BookmarkBarFolderController | 106 @implementation BookmarkBarFolderController |
107 | 107 |
| 108 @synthesize subFolderGrowthToRight = subFolderGrowthToRight_; |
| 109 |
108 - (id)initWithParentButton:(BookmarkButton*)button | 110 - (id)initWithParentButton:(BookmarkButton*)button |
109 parentController:(BookmarkBarFolderController*)parentController | 111 parentController:(BookmarkBarFolderController*)parentController |
110 barController:(BookmarkBarController*)barController { | 112 barController:(BookmarkBarController*)barController { |
111 NSString* nibPath = | 113 NSString* nibPath = |
112 [mac_util::MainAppBundle() pathForResource:@"BookmarkBarFolderWindow" | 114 [mac_util::MainAppBundle() pathForResource:@"BookmarkBarFolderWindow" |
113 ofType:@"nib"]; | 115 ofType:@"nib"]; |
114 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { | 116 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { |
115 parentButton_.reset([button retain]); | 117 parentButton_.reset([button retain]); |
116 | 118 |
117 // We want the button to remain bordered as part of the menu path. | 119 // We want the button to remain bordered as part of the menu path. |
118 [button forceButtonBorderToStayOnAlways:YES]; | 120 [button forceButtonBorderToStayOnAlways:YES]; |
119 | 121 |
120 parentController_.reset([parentController retain]); | 122 parentController_.reset([parentController retain]); |
| 123 if (!parentController_) |
| 124 [self setSubFolderGrowthToRight:YES]; |
| 125 else |
| 126 [self setSubFolderGrowthToRight:[parentController |
| 127 subFolderGrowthToRight]]; |
121 barController_ = barController; // WEAK | 128 barController_ = barController; // WEAK |
122 buttons_.reset([[NSMutableArray alloc] init]); | 129 buttons_.reset([[NSMutableArray alloc] init]); |
123 folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); | 130 folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); |
124 NSImage* image = nsimage_cache::ImageNamed(@"menu_overflow_up.pdf"); | 131 NSImage* image = nsimage_cache::ImageNamed(@"menu_overflow_up.pdf"); |
125 DCHECK(image); | 132 DCHECK(image); |
126 verticalScrollArrowHeight_ = [image size].height; | 133 verticalScrollArrowHeight_ = [image size].height; |
127 [self configureWindow]; | 134 [self configureWindow]; |
128 hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]); | 135 hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]); |
129 } | 136 } |
130 return self; | 137 return self; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 | 263 |
257 // Exposed for testing. | 264 // Exposed for testing. |
258 - (NSView*)mainView { | 265 - (NSView*)mainView { |
259 return mainView_; | 266 return mainView_; |
260 } | 267 } |
261 | 268 |
262 - (id)folderTarget { | 269 - (id)folderTarget { |
263 return folderTarget_.get(); | 270 return folderTarget_.get(); |
264 } | 271 } |
265 | 272 |
| 273 |
| 274 // Our parent controller is another BookmarkBarFolderController, so |
| 275 // our window is to the right or left of it. We use a little overlap |
| 276 // since it looks much more menu-like than with none. If we would |
| 277 // grow off the screen, switch growth to the other direction. Growth |
| 278 // direction sticks for folder windows which are descendents of us. |
| 279 // If we have tried both directions and neither fits, degrade to a |
| 280 // default. |
| 281 - (CGFloat)childFolderWindowLeftForWidth:(int)windowWidth { |
| 282 // We may legitimately need to try two times (growth to right and |
| 283 // left but not in that order). Limit us to three tries in case |
| 284 // the folder window can't fit on either side of the screen; we |
| 285 // don't want to loop forever. |
| 286 CGFloat x; |
| 287 int tries = 0; |
| 288 while (tries < 2) { |
| 289 // Try to grow right. |
| 290 if ([self subFolderGrowthToRight]) { |
| 291 tries++; |
| 292 x = NSMaxX([[parentButton_ window] frame]) - |
| 293 bookmarks::kBookmarkMenuOverlap; |
| 294 // If off the screen, switch direction. |
| 295 if ((x + windowWidth + bookmarks::kBookmarkHorizontalScreenPadding) > |
| 296 NSMaxX([[[self window] screen] frame])) { |
| 297 [self setSubFolderGrowthToRight:NO]; |
| 298 } else { |
| 299 return x; |
| 300 } |
| 301 } |
| 302 // Try to grow left. |
| 303 if (![self subFolderGrowthToRight]) { |
| 304 tries++; |
| 305 x = NSMinX([[parentButton_ window] frame]) + |
| 306 bookmarks::kBookmarkMenuOverlap - |
| 307 windowWidth; |
| 308 // If off the screen, switch direction. |
| 309 if (x < NSMinX([[[self window] screen] frame])) { |
| 310 [self setSubFolderGrowthToRight:YES]; |
| 311 } else { |
| 312 return x; |
| 313 } |
| 314 } |
| 315 } |
| 316 // Unhappy; do the best we can. |
| 317 return NSMaxX([[[self window] screen] frame]) - windowWidth; |
| 318 } |
| 319 |
| 320 |
266 // Compute and return the top left point of our window (screen | 321 // Compute and return the top left point of our window (screen |
267 // coordinates). The top left is positioned in a manner similar to | 322 // coordinates). The top left is positioned in a manner similar to |
268 // cascading menus. | 323 // cascading menus. Windows may grow to either the right or left of |
269 - (NSPoint)windowTopLeft { | 324 // their parent (if a sub-folder) so we need to know |windowWidth|. |
| 325 - (NSPoint)windowTopLeftForWidth:(int)windowWidth { |
270 NSPoint newWindowTopLeft; | 326 NSPoint newWindowTopLeft; |
271 if (![parentController_ isKindOfClass:[self class]]) { | 327 if (![parentController_ isKindOfClass:[self class]]) { |
272 // If we're not popping up from one of ourselves, we must be | 328 // If we're not popping up from one of ourselves, we must be |
273 // popping up from the bookmark bar itself. In this case, start | 329 // popping up from the bookmark bar itself. In this case, start |
274 // BELOW the parent button. Our left is the button left; our top | 330 // BELOW the parent button. Our left is the button left; our top |
275 // is bottom of button's parent view. | 331 // is bottom of button's parent view. |
276 NSPoint buttonBottomLeftInScreen = | 332 NSPoint buttonBottomLeftInScreen = |
277 [[parentButton_ window] | 333 [[parentButton_ window] |
278 convertBaseToScreen:[parentButton_ | 334 convertBaseToScreen:[parentButton_ |
279 convertPoint:NSZeroPoint toView:nil]]; | 335 convertPoint:NSZeroPoint toView:nil]]; |
280 NSPoint bookmarkBarBottomLeftInScreen = | 336 NSPoint bookmarkBarBottomLeftInScreen = |
281 [[parentButton_ window] | 337 [[parentButton_ window] |
282 convertBaseToScreen:[[parentButton_ superview] | 338 convertBaseToScreen:[[parentButton_ superview] |
283 convertPoint:NSZeroPoint toView:nil]]; | 339 convertPoint:NSZeroPoint toView:nil]]; |
284 newWindowTopLeft = NSMakePoint(buttonBottomLeftInScreen.x, | 340 newWindowTopLeft = NSMakePoint(buttonBottomLeftInScreen.x, |
285 bookmarkBarBottomLeftInScreen.y); | 341 bookmarkBarBottomLeftInScreen.y); |
286 } else { | 342 } else { |
287 // Our parent controller is another BookmarkBarFolderController. | 343 // Parent is a folder; grow right/left. |
288 // In this case, start with a slight overlap on the RIGHT of the | 344 newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth]; |
289 // parent button, which looks much more menu-like than with none. | |
290 // Start to RIGHT of the button. | |
291 // TODO(jrg): If too far to right, pop left again. | |
292 // http://crbug.com/36225 | |
293 newWindowTopLeft.x = NSMaxX([[parentButton_ window] frame]) - | |
294 bookmarks::kBookmarkMenuOverlap; | |
295 NSPoint top = NSMakePoint(0, (NSMaxY([parentButton_ frame]) + | 345 NSPoint top = NSMakePoint(0, (NSMaxY([parentButton_ frame]) + |
296 bookmarks::kBookmarkVerticalPadding)); | 346 bookmarks::kBookmarkVerticalPadding)); |
297 NSPoint topOfWindow = | 347 NSPoint topOfWindow = |
298 [[parentButton_ window] | 348 [[parentButton_ window] |
299 convertBaseToScreen:[[parentButton_ superview] | 349 convertBaseToScreen:[[parentButton_ superview] |
300 convertPoint:top toView:nil]]; | 350 convertPoint:top toView:nil]]; |
301 newWindowTopLeft.y = topOfWindow.y; | 351 newWindowTopLeft.y = topOfWindow.y; |
302 } | 352 } |
303 return newWindowTopLeft; | 353 return newWindowTopLeft; |
304 } | 354 } |
305 | 355 |
306 // Set our window level to the right spot so we're above the menubar, dock, etc. | 356 // Set our window level to the right spot so we're above the menubar, dock, etc. |
307 // Factored out so we can override/noop in a unit test. | 357 // Factored out so we can override/noop in a unit test. |
308 - (void)configureWindowLevel { | 358 - (void)configureWindowLevel { |
309 [[self window] setLevel:NSPopUpMenuWindowLevel]; | 359 [[self window] setLevel:NSPopUpMenuWindowLevel]; |
310 } | 360 } |
311 | 361 |
312 - (void)adjustWindowForHeight:(int)windowHeight { | 362 - (void)adjustWindowForHeight:(int)windowHeight { |
313 // Adjust all button widths to be consistent, determine the best size for | 363 // Adjust all button widths to be consistent, determine the best size for |
314 // the window, and set the window frame. | 364 // the window, and set the window frame. |
315 CGFloat windowWidth = | 365 CGFloat windowWidth = |
316 [self adjustButtonWidths] + (2 * bookmarks::kBookmarkVerticalPadding) + | 366 [self adjustButtonWidths] + (2 * bookmarks::kBookmarkVerticalPadding) + |
317 bookmarks::kScrollViewContentWidthMargin; | 367 bookmarks::kScrollViewContentWidthMargin; |
318 NSPoint newWindowTopLeft = [self windowTopLeft]; | 368 NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth]; |
319 NSRect windowFrame = NSMakeRect(newWindowTopLeft.x, | 369 NSRect windowFrame = NSMakeRect(newWindowTopLeft.x, |
320 newWindowTopLeft.y - windowHeight, | 370 newWindowTopLeft.y - windowHeight, |
321 windowWidth, | 371 windowWidth, |
322 windowHeight); | 372 windowHeight); |
323 | 373 |
324 // Make the window fit on screen, with a distance of at least |padding| from | |
325 // the sides. | |
326 DCHECK([[self window] screen]); | |
327 NSRect screenFrame = [[[self window] screen] frame]; | |
328 if (NSMaxX(windowFrame) + bookmarks::kBookmarkHorizontalScreenPadding > | |
329 NSMaxX(screenFrame)) | |
330 windowFrame.origin.x -= NSMaxX(windowFrame) + | |
331 bookmarks::kBookmarkHorizontalScreenPadding - NSMaxX(screenFrame); | |
332 // No 'else' to provide preference for the left side of the menu | |
333 // being visible if neither one fits. Wish I had an "bool isL2R()" | |
334 // function right here. | |
335 if (NSMinX(windowFrame) - bookmarks::kBookmarkHorizontalScreenPadding < | |
336 NSMinX(screenFrame)) | |
337 windowFrame.origin.x += NSMinX(screenFrame) - NSMinX(windowFrame) + | |
338 bookmarks::kBookmarkHorizontalScreenPadding; | |
339 | |
340 // Make the scrolled content be the right size (full size). | 374 // Make the scrolled content be the right size (full size). |
341 NSRect mainViewFrame = NSMakeRect(0, 0, | 375 NSRect mainViewFrame = NSMakeRect(0, 0, |
342 NSWidth(windowFrame) - | 376 NSWidth(windowFrame) - |
343 bookmarks::kScrollViewContentWidthMargin, | 377 bookmarks::kScrollViewContentWidthMargin, |
344 NSHeight(windowFrame)); | 378 NSHeight(windowFrame)); |
345 [mainView_ setFrame:mainViewFrame]; | 379 [mainView_ setFrame:mainViewFrame]; |
346 | 380 |
347 // Make sure the window fits on the screen. If not, constrain. | 381 // Make sure the window fits on the screen. If not, constrain. |
348 // We'll scroll to allow the user to see all the content. | 382 // We'll scroll to allow the user to see all the content. |
| 383 NSRect screenFrame = [[[self window] screen] frame]; |
349 screenFrame = NSInsetRect(screenFrame, 0, kScrollWindowVerticalMargin); | 384 screenFrame = NSInsetRect(screenFrame, 0, kScrollWindowVerticalMargin); |
350 if (!NSContainsRect(screenFrame, windowFrame)) { | 385 if (!NSContainsRect(screenFrame, windowFrame)) { |
351 scrollable_ = YES; | 386 scrollable_ = YES; |
352 windowFrame = NSIntersectionRect(screenFrame, windowFrame); | 387 windowFrame = NSIntersectionRect(screenFrame, windowFrame); |
353 } else { | 388 } else { |
354 scrollable_ = NO; | 389 scrollable_ = NO; |
355 } | 390 } |
356 [[self window] setFrame:windowFrame display:YES]; | 391 [[self window] setFrame:windowFrame display:YES]; |
357 // If scrollable then offset the view and show the arrows. | 392 // If scrollable then offset the view and show the arrows. |
358 if (scrollable_) { | 393 if (scrollable_) { |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
961 #pragma mark BookmarkButtonControllerProtocol | 996 #pragma mark BookmarkButtonControllerProtocol |
962 | 997 |
963 // Recursively close all bookmark folders. | 998 // Recursively close all bookmark folders. |
964 - (void)closeAllBookmarkFolders { | 999 - (void)closeAllBookmarkFolders { |
965 // Closing the top level implicitly closes all children. | 1000 // Closing the top level implicitly closes all children. |
966 [barController_ closeAllBookmarkFolders]; | 1001 [barController_ closeAllBookmarkFolders]; |
967 } | 1002 } |
968 | 1003 |
969 // Close our bookmark folder (a sub-controller) if we have one. | 1004 // Close our bookmark folder (a sub-controller) if we have one. |
970 - (void)closeBookmarkFolder:(id)sender { | 1005 - (void)closeBookmarkFolder:(id)sender { |
971 // folderController_ may be nil but that's OK. | 1006 if (folderController_) { |
972 [[folderController_ window] close]; | 1007 [self setSubFolderGrowthToRight:YES]; |
973 folderController_ = nil; | 1008 [[folderController_ window] close]; |
| 1009 folderController_ = nil; |
| 1010 } |
974 } | 1011 } |
975 | 1012 |
976 - (BookmarkModel*)bookmarkModel { | 1013 - (BookmarkModel*)bookmarkModel { |
977 return [barController_ bookmarkModel]; | 1014 return [barController_ bookmarkModel]; |
978 } | 1015 } |
979 | 1016 |
980 // TODO(jrg): Refactor BookmarkBarFolder common code. http://crbug.com/35966 | 1017 // TODO(jrg): Refactor BookmarkBarFolder common code. http://crbug.com/35966 |
981 // Most of the work (e.g. drop indicator) is taken care of in the | 1018 // Most of the work (e.g. drop indicator) is taken care of in the |
982 // folder_view. Here we handle hover open issues for subfolders. | 1019 // folder_view. Here we handle hover open issues for subfolders. |
983 // Caution: there are subtle differences between this one and | 1020 // Caution: there are subtle differences between this one and |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1325 return [folderController_ controllerForNode:node]; | 1362 return [folderController_ controllerForNode:node]; |
1326 } | 1363 } |
1327 | 1364 |
1328 #pragma mark TestingAPI Only | 1365 #pragma mark TestingAPI Only |
1329 | 1366 |
1330 - (void)setIgnoreAnimations:(BOOL)ignore { | 1367 - (void)setIgnoreAnimations:(BOOL)ignore { |
1331 ignoreAnimations_ = ignore; | 1368 ignoreAnimations_ = ignore; |
1332 } | 1369 } |
1333 | 1370 |
1334 @end // BookmarkBarFolderController | 1371 @end // BookmarkBarFolderController |
OLD | NEW |