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/sys_string_conversions.h" | 8 #include "base/sys_string_conversions.h" |
8 #include "chrome/browser/bookmarks/bookmark_model.h" | 9 #include "chrome/browser/bookmarks/bookmark_model.h" |
9 #include "chrome/browser/bookmarks/bookmark_utils.h" | 10 #include "chrome/browser/bookmarks/bookmark_utils.h" |
10 #import "chrome/browser/browser_theme_provider.h" | 11 #import "chrome/browser/browser_theme_provider.h" |
11 #import "chrome/browser/cocoa/bookmark_bar_constants.h" // namespace bookmarks | 12 #import "chrome/browser/cocoa/bookmark_bar_constants.h" // namespace bookmarks |
12 #import "chrome/browser/cocoa/bookmark_bar_controller.h" // namespace bookmarks | 13 #import "chrome/browser/cocoa/bookmark_bar_controller.h" // namespace bookmarks |
13 #import "chrome/browser/cocoa/bookmark_bar_folder_view.h" | 14 #import "chrome/browser/cocoa/bookmark_bar_folder_view.h" |
14 #import "chrome/browser/cocoa/bookmark_bar_folder_button_cell.h" | 15 #import "chrome/browser/cocoa/bookmark_bar_folder_button_cell.h" |
15 #import "chrome/browser/cocoa/bookmark_bar_folder_hover_state.h" | 16 #import "chrome/browser/cocoa/bookmark_bar_folder_hover_state.h" |
16 #import "chrome/browser/cocoa/bookmark_folder_target.h" | 17 #import "chrome/browser/cocoa/bookmark_folder_target.h" |
(...skipping 16 matching lines...) Expand all Loading... |
33 1 * (bookmarks::kBookmarkButtonHeight + | 34 1 * (bookmarks::kBookmarkButtonHeight + |
34 bookmarks::kBookmarkVerticalPadding); | 35 bookmarks::kBookmarkVerticalPadding); |
35 | 36 |
36 // Our NSScrollView is supposed to be just barely big enough to fit its | 37 // Our NSScrollView is supposed to be just barely big enough to fit its |
37 // contentView. It is actually a hair too small. | 38 // contentView. It is actually a hair too small. |
38 // This turns on horizontal scrolling which, although slight, is awkward. | 39 // This turns on horizontal scrolling which, although slight, is awkward. |
39 // Make sure our window (and NSScrollView) are wider than its documentView | 40 // Make sure our window (and NSScrollView) are wider than its documentView |
40 // by at least this much. | 41 // by at least this much. |
41 const CGFloat kScrollViewContentWidthMargin = 2; | 42 const CGFloat kScrollViewContentWidthMargin = 2; |
42 | 43 |
43 | |
44 // When constraining a scrolling bookmark bar folder window to the | 44 // When constraining a scrolling bookmark bar folder window to the |
45 // screen, shrink the "constrain" by this much vertically. Currently | 45 // screen, shrink the "constrain" by this much vertically. Currently |
46 // this is 0.0 to avoid a problem with tracking areas leaving the | 46 // this is 0.0 to avoid a problem with tracking areas leaving the |
47 // window, but should probably be 8.0 or something. | 47 // window, but should probably be 8.0 or something. |
48 // TODO(jrg): http://crbug.com/36225 | 48 // TODO(jrg): http://crbug.com/36225 |
49 const CGFloat kScrollWindowVerticalMargin = 0.0; | 49 const CGFloat kScrollWindowVerticalMargin = 0.0; |
50 | 50 |
51 } // namespace | 51 } // namespace |
52 | 52 |
53 @interface BookmarkBarFolderController(Private) | 53 @interface BookmarkBarFolderController(Private) |
54 - (void)configureWindow; | 54 - (void)configureWindow; |
55 - (void)addOrUpdateScrollTracking; | 55 - (void)addOrUpdateScrollTracking; |
56 - (void)removeScrollTracking; | 56 - (void)removeScrollTracking; |
57 - (void)endScroll; | 57 - (void)endScroll; |
58 - (void)addScrollTimerWithDelta:(CGFloat)delta; | 58 - (void)addScrollTimerWithDelta:(CGFloat)delta; |
59 | 59 |
60 // Determine the best button width (which will be the widest button or the | 60 // Determine the best button width (which will be the widest button or the |
61 // maximum allowable button width, whichever is less) and resize all buttons. | 61 // maximum allowable button width, whichever is less) and resize all buttons. |
62 // Return the new width (so that the window can be adjusted, if necessary). | 62 // Return the new width (so that the window can be adjusted, if necessary). |
63 - (CGFloat)adjustButtonWidths; | 63 - (CGFloat)adjustButtonWidths; |
64 | 64 |
| 65 // Show or hide the scroll arrows at the top/bottom of the window. |
| 66 - (void)showOrHideScrollArrows; |
| 67 |
65 @end | 68 @end |
66 | 69 |
67 @implementation BookmarkBarFolderController | 70 @implementation BookmarkBarFolderController |
68 | 71 |
69 - (id)initWithParentButton:(BookmarkButton*)button | 72 - (id)initWithParentButton:(BookmarkButton*)button |
70 parentController:(BookmarkBarFolderController*)parentController | 73 parentController:(BookmarkBarFolderController*)parentController |
71 barController:(BookmarkBarController*)barController { | 74 barController:(BookmarkBarController*)barController { |
72 NSString* nibPath = | 75 NSString* nibPath = |
73 [mac_util::MainAppBundle() pathForResource:@"BookmarkBarFolderWindow" | 76 [mac_util::MainAppBundle() pathForResource:@"BookmarkBarFolderWindow" |
74 ofType:@"nib"]; | 77 ofType:@"nib"]; |
75 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { | 78 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { |
76 parentButton_.reset([button retain]); | 79 parentButton_.reset([button retain]); |
77 parentController_.reset([parentController retain]); | 80 parentController_.reset([parentController retain]); |
78 barController_ = barController; // WEAK | 81 barController_ = barController; // WEAK |
79 buttons_.reset([[NSMutableArray alloc] init]); | 82 buttons_.reset([[NSMutableArray alloc] init]); |
80 folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); | 83 folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); |
| 84 NSImage* image = nsimage_cache::ImageNamed(@"menu_overflow_up.pdf"); |
| 85 DCHECK(image); |
| 86 verticalScrollArrowHeight_ = [image size].height; |
81 [self configureWindow]; | 87 [self configureWindow]; |
82 hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]); | 88 hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]); |
83 if (scrollable_) | 89 if (scrollable_) |
84 [self addOrUpdateScrollTracking]; | 90 [self addOrUpdateScrollTracking]; |
85 } | 91 } |
86 return self; | 92 return self; |
87 } | 93 } |
88 | 94 |
89 - (void)dealloc { | 95 - (void)dealloc { |
90 [self removeScrollTracking]; | 96 [self removeScrollTracking]; |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 if (!NSContainsRect(screenFrame, windowFrame)) { | 333 if (!NSContainsRect(screenFrame, windowFrame)) { |
328 scrollable_ = YES; | 334 scrollable_ = YES; |
329 windowFrame = NSIntersectionRect(screenFrame, windowFrame); | 335 windowFrame = NSIntersectionRect(screenFrame, windowFrame); |
330 } | 336 } |
331 [[self window] setFrame:windowFrame display:YES]; | 337 [[self window] setFrame:windowFrame display:YES]; |
332 if (scrollable_) { | 338 if (scrollable_) { |
333 [mainView_ scrollPoint:NSMakePoint(0, (NSHeight(mainViewFrame) - | 339 [mainView_ scrollPoint:NSMakePoint(0, (NSHeight(mainViewFrame) - |
334 NSHeight(windowFrame)))]; | 340 NSHeight(windowFrame)))]; |
335 } | 341 } |
336 | 342 |
| 343 // If scrollable, show the arrows. |
| 344 if (scrollable_) { |
| 345 [self showOrHideScrollArrows]; |
| 346 } |
| 347 |
337 // Finally pop me up. | 348 // Finally pop me up. |
338 [self configureWindowLevel]; | 349 [self configureWindowLevel]; |
339 } | 350 } |
340 | 351 |
341 - (void)offsetFolderMenuWindow:(NSSize)offset { | 352 - (void)offsetFolderMenuWindow:(NSSize)offset { |
342 NSWindow* window = [self window]; | 353 NSWindow* window = [self window]; |
343 NSRect windowFrame = [window frame]; | 354 NSRect windowFrame = [window frame]; |
344 windowFrame.origin.x -= offset.width; | 355 windowFrame.origin.x -= offset.width; |
345 windowFrame.origin.y += offset.height; // Yes, in the opposite direction! | 356 windowFrame.origin.y += offset.height; // Yes, in the opposite direction! |
346 [window setFrame:windowFrame display:YES]; | 357 [window setFrame:windowFrame display:YES]; |
(...skipping 10 matching lines...) Expand all Loading... |
357 // Things look and feel more menu-like if all the buttons are the | 368 // Things look and feel more menu-like if all the buttons are the |
358 // full width of the window, especially if there are submenus. | 369 // full width of the window, especially if there are submenus. |
359 for (BookmarkButton* button in buttons_.get()) { | 370 for (BookmarkButton* button in buttons_.get()) { |
360 NSRect buttonFrame = [button frame]; | 371 NSRect buttonFrame = [button frame]; |
361 buttonFrame.size.width = width; | 372 buttonFrame.size.width = width; |
362 [button setFrame:buttonFrame]; | 373 [button setFrame:buttonFrame]; |
363 } | 374 } |
364 return width; | 375 return width; |
365 } | 376 } |
366 | 377 |
| 378 - (BOOL)canScrollUp { |
| 379 // If removal of an arrow would make things "finished", state as |
| 380 // such. |
| 381 CGFloat scrollY = [scrollView_ documentVisibleRect].origin.y; |
| 382 if (scrollUpArrowShown_) |
| 383 scrollY -= verticalScrollArrowHeight_; |
| 384 |
| 385 if (scrollY <= 0) |
| 386 return NO; |
| 387 return YES; |
| 388 } |
| 389 |
| 390 - (BOOL)canScrollDown { |
| 391 CGFloat arrowAdjustment = 0.0; |
| 392 |
| 393 // We do NOT adjust based on the scrollDOWN arrow. This keeps |
| 394 // things from "jumping"; if removal of the down arrow (at the top |
| 395 // of the window) would cause a scroll to end, we'll end. |
| 396 if (scrollUpArrowShown_) |
| 397 arrowAdjustment += verticalScrollArrowHeight_; |
| 398 |
| 399 NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; |
| 400 NSRect documentRect = [[scrollView_ documentView] frame]; |
| 401 |
| 402 // If we are exactly the right height, return no. We need this |
| 403 // extra conditional in the case where we've just scrolled/grown |
| 404 // into position. |
| 405 if (NSHeight([[self window] frame]) == NSHeight(documentRect)) |
| 406 return NO; |
| 407 |
| 408 if ((scrollPosition.y + NSHeight([[self window] frame])) >= |
| 409 (NSHeight(documentRect) + arrowAdjustment)) { |
| 410 return NO; |
| 411 } |
| 412 return YES; |
| 413 } |
| 414 |
| 415 - (void)showOrHideScrollArrows { |
| 416 NSRect frame = [scrollView_ frame]; |
| 417 CGFloat scrollDelta = 0.0; |
| 418 BOOL canScrollDown = [self canScrollDown]; |
| 419 BOOL canScrollUp = [self canScrollUp]; |
| 420 |
| 421 if (canScrollUp != scrollUpArrowShown_) { |
| 422 if (scrollUpArrowShown_) { |
| 423 frame.origin.y -= verticalScrollArrowHeight_; |
| 424 frame.size.height += verticalScrollArrowHeight_; |
| 425 scrollDelta = verticalScrollArrowHeight_; |
| 426 } else { |
| 427 frame.origin.y += verticalScrollArrowHeight_; |
| 428 frame.size.height -= verticalScrollArrowHeight_; |
| 429 scrollDelta = -verticalScrollArrowHeight_; |
| 430 } |
| 431 } |
| 432 if (canScrollDown != scrollDownArrowShown_) { |
| 433 if (scrollDownArrowShown_) { |
| 434 frame.size.height += verticalScrollArrowHeight_; |
| 435 } else { |
| 436 frame.size.height -= verticalScrollArrowHeight_; |
| 437 } |
| 438 } |
| 439 scrollUpArrowShown_ = canScrollUp; |
| 440 scrollDownArrowShown_ = canScrollDown; |
| 441 [scrollView_ setFrame:frame]; |
| 442 |
| 443 // Adjust scroll based on new frame. For example, if we make room |
| 444 // for an arrow at the bottom, adjust the scroll so the topmost item |
| 445 // is still fully visible. |
| 446 if (scrollDelta) { |
| 447 NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; |
| 448 scrollPosition.y -= scrollDelta; |
| 449 [[scrollView_ documentView] scrollPoint:scrollPosition]; |
| 450 } |
| 451 } |
| 452 |
367 #pragma mark BookmarkButtonControllerProtocol | 453 #pragma mark BookmarkButtonControllerProtocol |
368 | 454 |
369 - (void)addButtonForNode:(const BookmarkNode*)node | 455 - (void)addButtonForNode:(const BookmarkNode*)node |
370 atIndex:(NSInteger)buttonIndex { | 456 atIndex:(NSInteger)buttonIndex { |
371 if (buttonIndex == -1) | 457 if (buttonIndex == -1) |
372 buttonIndex = [buttons_ count]; | 458 buttonIndex = [buttons_ count]; |
373 | 459 |
374 // Remember the last moved button's frame or the default. | 460 // Remember the last moved button's frame or the default. |
375 NSRect buttonFrame = NSMakeRect(bookmarks::kBookmarkHorizontalPadding, | 461 NSRect buttonFrame = NSMakeRect(bookmarks::kBookmarkHorizontalPadding, |
376 NSHeight([mainView_ frame]) + bookmarks::kBookmarkBarHeight + | 462 NSHeight([mainView_ frame]) + bookmarks::kBookmarkBarHeight + |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
552 if (delta) { | 638 if (delta) { |
553 // If we can, grow the window (up). | 639 // If we can, grow the window (up). |
554 if (NSHeight(windowFrame) < screenHeightMinusMargin) { | 640 if (NSHeight(windowFrame) < screenHeightMinusMargin) { |
555 CGFloat growAmount = delta; | 641 CGFloat growAmount = delta; |
556 // Don't scroll more than enough to "finish". | 642 // Don't scroll more than enough to "finish". |
557 if (scrollPosition.y < 0) | 643 if (scrollPosition.y < 0) |
558 growAmount += scrollPosition.y; | 644 growAmount += scrollPosition.y; |
559 windowFrame.size.height += growAmount; | 645 windowFrame.size.height += growAmount; |
560 windowFrame.size.height = std::min(NSHeight(windowFrame), | 646 windowFrame.size.height = std::min(NSHeight(windowFrame), |
561 screenHeightMinusMargin); | 647 screenHeightMinusMargin); |
| 648 // Watch out for a finish that isn't the full height of the screen. |
| 649 // We get here if using the scroll wheel to scroll by small amounts. |
| 650 windowFrame.size.height = std::min(NSHeight(windowFrame), |
| 651 NSHeight([mainView_ frame])); |
562 // Don't allow scrolling to make the window smaller, ever. This | 652 // Don't allow scrolling to make the window smaller, ever. This |
563 // conditional is important when processing scrollWheel events. | 653 // conditional is important when processing scrollWheel events. |
564 if (windowFrame.size.height > [[self window] frame].size.height) { | 654 if (windowFrame.size.height > [[self window] frame].size.height) { |
565 [[self window] setFrame:windowFrame display:YES]; | 655 [[self window] setFrame:windowFrame display:YES]; |
566 [self addOrUpdateScrollTracking]; | 656 [self addOrUpdateScrollTracking]; |
567 } | 657 } |
568 } | 658 } |
569 } | 659 } |
570 | 660 |
571 // If we're at either end, happiness. | 661 // If we're at either end, happiness. |
572 if ((scrollPosition.y <= 0) || | 662 if ((scrollPosition.y <= 0) || |
573 ((scrollPosition.y + NSHeight(windowFrame) >= | 663 ((scrollPosition.y + NSHeight(windowFrame) >= |
574 NSHeight([mainView_ frame])) && | 664 NSHeight([mainView_ frame])) && |
575 (windowFrame.size.height == screenHeightMinusMargin))) { | 665 (windowFrame.size.height == screenHeightMinusMargin))) { |
576 [self endScroll]; | 666 [self endScroll]; |
577 | 667 |
578 // If the entire view is now visible the window is no longer scrollable. | 668 // If we can't scroll either up or down we are completely done. |
579 if (NSHeight([mainView_ visibleRect]) == NSHeight([mainView_ bounds])) { | 669 // For example, perhaps we've scrolled a little and grown the |
| 670 // window on-screen until there is now room for everything. |
| 671 if (![self canScrollUp] && ![self canScrollDown]) { |
580 scrollable_ = NO; | 672 scrollable_ = NO; |
581 [self removeScrollTracking]; | 673 [self removeScrollTracking]; |
582 } | 674 } |
583 } | 675 } |
| 676 |
| 677 [self showOrHideScrollArrows]; |
584 } | 678 } |
585 | 679 |
586 // Perform a scroll of the window on the screen. | 680 // Perform a scroll of the window on the screen. |
587 // Called by a timer when scrolling. | 681 // Called by a timer when scrolling. |
588 - (void)performScroll:(NSTimer*)timer { | 682 - (void)performScroll:(NSTimer*)timer { |
589 DCHECK(verticalScrollDelta_); | 683 DCHECK(verticalScrollDelta_); |
590 [self performOneScroll:verticalScrollDelta_]; | 684 [self performOneScroll:verticalScrollDelta_]; |
591 } | 685 } |
592 | 686 |
593 | 687 |
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1085 - (IBAction)openBookmarkInNewForegroundTab:(id)sender { | 1179 - (IBAction)openBookmarkInNewForegroundTab:(id)sender { |
1086 [barController_ openBookmarkInNewForegroundTab:sender]; | 1180 [barController_ openBookmarkInNewForegroundTab:sender]; |
1087 } | 1181 } |
1088 | 1182 |
1089 - (IBAction)openBookmarkInNewWindow:(id)sender { | 1183 - (IBAction)openBookmarkInNewWindow:(id)sender { |
1090 [barController_ openBookmarkInNewWindow:sender]; | 1184 [barController_ openBookmarkInNewWindow:sender]; |
1091 } | 1185 } |
1092 | 1186 |
1093 | 1187 |
1094 @end // BookmarkBarFolderController | 1188 @end // BookmarkBarFolderController |
OLD | NEW |