OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/bookmarks/bookmark_bar_folder_controller.h" | 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" |
6 | 6 |
7 #include "base/mac/bundle_locations.h" | 7 #include "base/mac/bundle_locations.h" |
8 #include "base/strings/sys_string_conversions.h" | 8 #include "base/strings/sys_string_conversions.h" |
9 #import "chrome/browser/bookmarks/bookmark_model_factory.h" | 9 #import "chrome/browser/bookmarks/bookmark_model_factory.h" |
10 #import "chrome/browser/bookmarks/chrome_bookmark_client.h" | 10 #import "chrome/browser/bookmarks/chrome_bookmark_client.h" |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 } | 122 } |
123 | 123 |
124 } // namespace | 124 } // namespace |
125 | 125 |
126 | 126 |
127 // Required to set the right tracking bounds for our fake menus. | 127 // Required to set the right tracking bounds for our fake menus. |
128 @interface NSView(Private) | 128 @interface NSView(Private) |
129 - (void)_updateTrackingAreas; | 129 - (void)_updateTrackingAreas; |
130 @end | 130 @end |
131 | 131 |
132 @interface BookmarkBarFolderController(Private) | 132 @interface BookmarkBarFolderController () |
133 - (void)configureWindow; | 133 - (void)configureWindow; |
134 - (void)addOrUpdateScrollTracking; | 134 - (void)addOrUpdateScrollTracking; |
135 - (void)removeScrollTracking; | 135 - (void)removeScrollTracking; |
136 - (void)endScroll; | 136 - (void)endScroll; |
137 - (void)addScrollTimerWithDelta:(CGFloat)delta; | 137 - (void)addScrollTimerWithDelta:(CGFloat)delta; |
138 | 138 |
| 139 // Return the screen to which the menu should be restricted. The screen list is |
| 140 // very volatile and can change with very short notice so it isn't worth |
| 141 // caching. http://crbug.com/463458 |
| 142 - (NSScreen*)menuScreen; |
| 143 |
139 // Helper function to configureWindow which performs a basic layout of | 144 // Helper function to configureWindow which performs a basic layout of |
140 // the window subviews, in particular the menu buttons and the window width. | 145 // the window subviews, in particular the menu buttons and the window width. |
141 - (void)layOutWindowWithHeight:(CGFloat)height; | 146 - (void)layOutWindowWithHeight:(CGFloat)height; |
142 | 147 |
143 // Determine the best button width (which will be the widest button or the | 148 // Determine the best button width (which will be the widest button or the |
144 // maximum allowable button width, whichever is less) and resize all buttons. | 149 // maximum allowable button width, whichever is less) and resize all buttons. |
145 // Return the new width so that the window can be adjusted. | 150 // Return the new width so that the window can be adjusted. |
146 - (CGFloat)adjustButtonWidths; | 151 - (CGFloat)adjustButtonWidths; |
147 | 152 |
148 // Returns the total menu height needed to display |buttonCount| buttons. | 153 // Returns the total menu height needed to display |buttonCount| buttons. |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 ofType:@"nib"]; | 259 ofType:@"nib"]; |
255 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { | 260 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { |
256 parentButton_.reset([button retain]); | 261 parentButton_.reset([button retain]); |
257 selectedIndex_ = -1; | 262 selectedIndex_ = -1; |
258 | 263 |
259 profile_ = profile; | 264 profile_ = profile; |
260 | 265 |
261 // We want the button to remain bordered as part of the menu path. | 266 // We want the button to remain bordered as part of the menu path. |
262 [button forceButtonBorderToStayOnAlways:YES]; | 267 [button forceButtonBorderToStayOnAlways:YES]; |
263 | 268 |
264 // Pick the parent button's screen to be the screen upon which all display | |
265 // happens. This loop over all screens is not equivalent to | |
266 // |[[button window] screen]|. BookmarkButtons are commonly positioned near | |
267 // the edge of their windows (both in the bookmark bar and in other bookmark | |
268 // menus), and |[[button window] screen]| would return the screen that the | |
269 // majority of their window was on even if the parent button were clearly | |
270 // contained within a different screen. | |
271 NSRect parentButtonGlobalFrame = | |
272 [button convertRect:[button bounds] toView:nil]; | |
273 parentButtonGlobalFrame.origin = | |
274 [[button window] convertBaseToScreen:parentButtonGlobalFrame.origin]; | |
275 for (NSScreen* screen in [NSScreen screens]) { | |
276 if (NSIntersectsRect([screen frame], parentButtonGlobalFrame)) { | |
277 screen_ = screen; | |
278 break; | |
279 } | |
280 } | |
281 if (!screen_) { | |
282 // The parent button is offscreen. The ideal thing to do would be to | |
283 // calculate the "closest" screen, the screen which has an edge parallel | |
284 // to, and the least distance from, one of the edges of the button. | |
285 // However, popping a subfolder from an offscreen button is an unrealistic | |
286 // edge case and so this ideal remains unrealized. Cheat instead; this | |
287 // code is wrong but a lot simpler. | |
288 screen_ = [[button window] screen]; | |
289 } | |
290 | |
291 parentController_.reset([parentController retain]); | 269 parentController_.reset([parentController retain]); |
292 if (!parentController_) | 270 if (!parentController_) |
293 [self setSubFolderGrowthToRight:YES]; | 271 [self setSubFolderGrowthToRight:YES]; |
294 else | 272 else |
295 [self setSubFolderGrowthToRight:[parentController | 273 [self setSubFolderGrowthToRight:[parentController |
296 subFolderGrowthToRight]]; | 274 subFolderGrowthToRight]]; |
297 barController_ = barController; // WEAK | 275 barController_ = barController; // WEAK |
298 buttons_.reset([[NSMutableArray alloc] init]); | 276 buttons_.reset([[NSMutableArray alloc] init]); |
299 folderTarget_.reset( | 277 folderTarget_.reset( |
300 [[BookmarkFolderTarget alloc] initWithController:self profile:profile]); | 278 [[BookmarkFolderTarget alloc] initWithController:self profile:profile]); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 // since it looks much more menu-like than with none. If we would | 439 // since it looks much more menu-like than with none. If we would |
462 // grow off the screen, switch growth to the other direction. Growth | 440 // grow off the screen, switch growth to the other direction. Growth |
463 // direction sticks for folder windows which are descendents of us. | 441 // direction sticks for folder windows which are descendents of us. |
464 // If we have tried both directions and neither fits, degrade to a | 442 // If we have tried both directions and neither fits, degrade to a |
465 // default. | 443 // default. |
466 - (CGFloat)childFolderWindowLeftForWidth:(int)windowWidth { | 444 - (CGFloat)childFolderWindowLeftForWidth:(int)windowWidth { |
467 // We may legitimately need to try two times (growth to right and | 445 // We may legitimately need to try two times (growth to right and |
468 // left but not in that order). Limit us to three tries in case | 446 // left but not in that order). Limit us to three tries in case |
469 // the folder window can't fit on either side of the screen; we | 447 // the folder window can't fit on either side of the screen; we |
470 // don't want to loop forever. | 448 // don't want to loop forever. |
| 449 NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; |
471 CGFloat x; | 450 CGFloat x; |
472 int tries = 0; | 451 int tries = 0; |
473 while (tries < 2) { | 452 while (tries < 2) { |
474 // Try to grow right. | 453 // Try to grow right. |
475 if ([self subFolderGrowthToRight]) { | 454 if ([self subFolderGrowthToRight]) { |
476 tries++; | 455 tries++; |
477 x = NSMaxX([[parentButton_ window] frame]) - | 456 x = NSMaxX([[parentButton_ window] frame]) - |
478 bookmarks::kBookmarkMenuOverlap; | 457 bookmarks::kBookmarkMenuOverlap; |
479 // If off the screen, switch direction. | 458 // If off the screen, switch direction. |
480 if ((x + windowWidth + | 459 if ((x + windowWidth + bookmarks::kBookmarkHorizontalScreenPadding) > |
481 bookmarks::kBookmarkHorizontalScreenPadding) > | 460 NSMaxX(screenVisibleFrame)) { |
482 NSMaxX([screen_ visibleFrame])) { | |
483 [self setSubFolderGrowthToRight:NO]; | 461 [self setSubFolderGrowthToRight:NO]; |
484 } else { | 462 } else { |
485 return x; | 463 return x; |
486 } | 464 } |
487 } | 465 } |
488 // Try to grow left. | 466 // Try to grow left. |
489 if (![self subFolderGrowthToRight]) { | 467 if (![self subFolderGrowthToRight]) { |
490 tries++; | 468 tries++; |
491 x = NSMinX([[parentButton_ window] frame]) + | 469 x = NSMinX([[parentButton_ window] frame]) + |
492 bookmarks::kBookmarkMenuOverlap - | 470 bookmarks::kBookmarkMenuOverlap - |
493 windowWidth; | 471 windowWidth; |
494 // If off the screen, switch direction. | 472 // If off the screen, switch direction. |
495 if (x < NSMinX([screen_ visibleFrame])) { | 473 if (x < NSMinX(screenVisibleFrame)) { |
496 [self setSubFolderGrowthToRight:YES]; | 474 [self setSubFolderGrowthToRight:YES]; |
497 } else { | 475 } else { |
498 return x; | 476 return x; |
499 } | 477 } |
500 } | 478 } |
501 } | 479 } |
502 // Unhappy; do the best we can. | 480 // Unhappy; do the best we can. |
503 return NSMaxX([screen_ visibleFrame]) - windowWidth; | 481 return NSMaxX(screenVisibleFrame) - windowWidth; |
504 } | 482 } |
505 | 483 |
506 | 484 |
507 // Compute and return the top left point of our window (screen | 485 // Compute and return the top left point of our window (screen |
508 // coordinates). The top left is positioned in a manner similar to | 486 // coordinates). The top left is positioned in a manner similar to |
509 // cascading menus. Windows may grow to either the right or left of | 487 // cascading menus. Windows may grow to either the right or left of |
510 // their parent (if a sub-folder) so we need to know |windowWidth|. | 488 // their parent (if a sub-folder) so we need to know |windowWidth|. |
511 - (NSPoint)windowTopLeftForWidth:(int)windowWidth height:(int)windowHeight { | 489 - (NSPoint)windowTopLeftForWidth:(int)windowWidth height:(int)windowHeight { |
512 CGFloat kMinSqueezedMenuHeight = bookmarks::kBookmarkFolderButtonHeight * 2.0; | 490 CGFloat kMinSqueezedMenuHeight = bookmarks::kBookmarkFolderButtonHeight * 2.0; |
513 NSPoint newWindowTopLeft; | 491 NSPoint newWindowTopLeft; |
514 if (![parentController_ isKindOfClass:[self class]]) { | 492 if (![parentController_ isKindOfClass:[self class]]) { |
515 // If we're not popping up from one of ourselves, we must be | 493 // If we're not popping up from one of ourselves, we must be |
516 // popping up from the bookmark bar itself. In this case, start | 494 // popping up from the bookmark bar itself. In this case, start |
517 // BELOW the parent button. Our left is the button left; our top | 495 // BELOW the parent button. Our left is the button left; our top |
518 // is bottom of button's parent view. | 496 // is bottom of button's parent view. |
519 NSPoint buttonBottomLeftInScreen = | 497 NSPoint buttonBottomLeftInScreen = |
520 [[parentButton_ window] | 498 [[parentButton_ window] |
521 convertBaseToScreen:[parentButton_ | 499 convertBaseToScreen:[parentButton_ |
522 convertPoint:NSZeroPoint toView:nil]]; | 500 convertPoint:NSZeroPoint toView:nil]]; |
523 NSPoint bookmarkBarBottomLeftInScreen = | 501 NSPoint bookmarkBarBottomLeftInScreen = |
524 [[parentButton_ window] | 502 [[parentButton_ window] |
525 convertBaseToScreen:[[parentButton_ superview] | 503 convertBaseToScreen:[[parentButton_ superview] |
526 convertPoint:NSZeroPoint toView:nil]]; | 504 convertPoint:NSZeroPoint toView:nil]]; |
527 newWindowTopLeft = NSMakePoint( | 505 newWindowTopLeft = NSMakePoint( |
528 buttonBottomLeftInScreen.x + bookmarks::kBookmarkBarButtonOffset, | 506 buttonBottomLeftInScreen.x + bookmarks::kBookmarkBarButtonOffset, |
529 bookmarkBarBottomLeftInScreen.y + bookmarks::kBookmarkBarMenuOffset); | 507 bookmarkBarBottomLeftInScreen.y + bookmarks::kBookmarkBarMenuOffset); |
530 // Make sure the window is on-screen; if not, push left or right. It is | 508 // Make sure the window is on-screen; if not, push left or right. It is |
531 // intentional that top level folders "push left" or "push right" slightly | 509 // intentional that top level folders "push left" or "push right" slightly |
532 // different than subfolders. | 510 // different than subfolders. |
533 NSRect screenFrame = [screen_ visibleFrame]; | 511 NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; |
534 // Test if window goes off-screen on the right side. | 512 // Test if window goes off-screen on the right side. |
535 CGFloat spillOff = (newWindowTopLeft.x + windowWidth) - NSMaxX(screenFrame); | 513 CGFloat spillOff = |
| 514 newWindowTopLeft.x + windowWidth - NSMaxX(screenVisibleFrame); |
536 if (spillOff > 0.0) { | 515 if (spillOff > 0.0) { |
537 newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff, | 516 newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff, |
538 NSMinX(screenFrame)); | 517 NSMinX(screenVisibleFrame)); |
539 } else if (newWindowTopLeft.x < NSMinX(screenFrame)) { | 518 } else if (newWindowTopLeft.x < NSMinX(screenVisibleFrame)) { |
540 // For left side. | 519 // For left side. |
541 newWindowTopLeft.x = NSMinX(screenFrame); | 520 newWindowTopLeft.x = NSMinX(screenVisibleFrame); |
542 } | 521 } |
543 // The menu looks bad when it is squeezed up against the bottom of the | 522 // The menu looks bad when it is squeezed up against the bottom of the |
544 // screen and ends up being only a few pixels tall. If it meets the | 523 // screen and ends up being only a few pixels tall. If it meets the |
545 // threshold for this case, instead show the menu above the button. | 524 // threshold for this case, instead show the menu above the button. |
546 CGFloat availableVerticalSpace = newWindowTopLeft.y - | 525 CGFloat availableVerticalSpace = newWindowTopLeft.y - |
547 (NSMinY(screenFrame) + bookmarks::kScrollWindowVerticalMargin); | 526 (NSMinY(screenVisibleFrame) + bookmarks::kScrollWindowVerticalMargin); |
548 if ((availableVerticalSpace < kMinSqueezedMenuHeight) && | 527 if ((availableVerticalSpace < kMinSqueezedMenuHeight) && |
549 (windowHeight > availableVerticalSpace)) { | 528 (windowHeight > availableVerticalSpace)) { |
550 newWindowTopLeft.y = std::min( | 529 newWindowTopLeft.y = std::min( |
551 newWindowTopLeft.y + windowHeight + NSHeight([parentButton_ frame]), | 530 newWindowTopLeft.y + windowHeight + NSHeight([parentButton_ frame]), |
552 NSMaxY(screenFrame)); | 531 NSMaxY(screenVisibleFrame)); |
553 } | 532 } |
554 } else { | 533 } else { |
555 // Parent is a folder: expose as much as we can vertically; grow right/left. | 534 // Parent is a folder: expose as much as we can vertically; grow right/left. |
556 newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth]; | 535 newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth]; |
557 NSPoint topOfWindow = NSMakePoint(0, | 536 NSPoint topOfWindow = NSMakePoint(0, |
558 NSMaxY([parentButton_ frame]) - | 537 NSMaxY([parentButton_ frame]) - |
559 bookmarks::kBookmarkVerticalPadding); | 538 bookmarks::kBookmarkVerticalPadding); |
560 topOfWindow = [[parentButton_ window] | 539 topOfWindow = [[parentButton_ window] |
561 convertBaseToScreen:[[parentButton_ superview] | 540 convertBaseToScreen:[[parentButton_ superview] |
562 convertPoint:topOfWindow toView:nil]]; | 541 convertPoint:topOfWindow toView:nil]]; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
608 metrics.couldScrollUp = ![scrollUpArrowView_ isHidden]; | 587 metrics.couldScrollUp = ![scrollUpArrowView_ isHidden]; |
609 metrics.couldScrollDown = ![scrollDownArrowView_ isHidden]; | 588 metrics.couldScrollDown = ![scrollDownArrowView_ isHidden]; |
610 | 589 |
611 metrics.deltaWindowHeight = 0.0; | 590 metrics.deltaWindowHeight = 0.0; |
612 metrics.deltaWindowY = 0.0; | 591 metrics.deltaWindowY = 0.0; |
613 metrics.deltaVisibleHeight = 0.0; | 592 metrics.deltaVisibleHeight = 0.0; |
614 metrics.deltaVisibleY = 0.0; | 593 metrics.deltaVisibleY = 0.0; |
615 metrics.deltaScrollerHeight = 0.0; | 594 metrics.deltaScrollerHeight = 0.0; |
616 metrics.deltaScrollerY = 0.0; | 595 metrics.deltaScrollerY = 0.0; |
617 | 596 |
618 metrics.minimumY = NSMinY([screen_ visibleFrame]) + | 597 metrics.minimumY = NSMinY([[self menuScreen] visibleFrame]) + |
619 bookmarks::kScrollWindowVerticalMargin; | 598 bookmarks::kScrollWindowVerticalMargin; |
620 metrics.screenBottomY = NSMinY([screen_ frame]); | 599 metrics.screenBottomY = NSMinY([[self menuScreen] frame]); |
621 metrics.oldWindowY = NSMinY(metrics.windowFrame); | 600 metrics.oldWindowY = NSMinY(metrics.windowFrame); |
622 metrics.folderY = | 601 metrics.folderY = |
623 metrics.scrollerFrame.origin.y + metrics.visibleFrame.origin.y + | 602 metrics.scrollerFrame.origin.y + metrics.visibleFrame.origin.y + |
624 metrics.oldWindowY - metrics.scrollPoint.y; | 603 metrics.oldWindowY - metrics.scrollPoint.y; |
625 metrics.folderTop = metrics.folderY + NSHeight([folderView_ frame]); | 604 metrics.folderTop = metrics.folderY + NSHeight([folderView_ frame]); |
626 } | 605 } |
627 | 606 |
628 - (void)adjustMetrics:(LayoutMetrics*)layoutMetrics { | 607 - (void)adjustMetrics:(LayoutMetrics*)layoutMetrics { |
629 LayoutMetrics& metrics(*layoutMetrics); | 608 LayoutMetrics& metrics(*layoutMetrics); |
630 CGFloat effectiveFolderY = metrics.folderY; | 609 CGFloat effectiveFolderY = metrics.folderY; |
631 if (!metrics.couldScrollUp && !metrics.couldScrollDown) | 610 if (!metrics.couldScrollUp && !metrics.couldScrollDown) |
632 effectiveFolderY -= metrics.windowSize.height; | 611 effectiveFolderY -= metrics.windowSize.height; |
633 metrics.canScrollUp = effectiveFolderY < metrics.minimumY; | 612 metrics.canScrollUp = effectiveFolderY < metrics.minimumY; |
634 CGFloat maximumY = | 613 CGFloat maximumY = |
635 NSMaxY([screen_ visibleFrame]) - bookmarks::kScrollWindowVerticalMargin; | 614 NSMaxY([[self menuScreen] visibleFrame]) - |
| 615 bookmarks::kScrollWindowVerticalMargin; |
636 metrics.canScrollDown = metrics.folderTop > maximumY; | 616 metrics.canScrollDown = metrics.folderTop > maximumY; |
637 | 617 |
638 // Accommodate changes in the bottom of the menu. | 618 // Accommodate changes in the bottom of the menu. |
639 [self adjustMetricsForMenuBottomChanges:layoutMetrics]; | 619 [self adjustMetricsForMenuBottomChanges:layoutMetrics]; |
640 | 620 |
641 // Accommodate changes in the top of the menu. | 621 // Accommodate changes in the top of the menu. |
642 [self adjustMetricsForMenuTopChanges:layoutMetrics]; | 622 [self adjustMetricsForMenuTopChanges:layoutMetrics]; |
643 | 623 |
644 metrics.scrollerFrame.origin.y += metrics.deltaScrollerY; | 624 metrics.scrollerFrame.origin.y += metrics.deltaScrollerY; |
645 metrics.scrollerFrame.size.height += metrics.deltaScrollerHeight; | 625 metrics.scrollerFrame.size.height += metrics.deltaScrollerHeight; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 - (void)adjustMetricsForMenuTopChanges:(LayoutMetrics*)layoutMetrics { | 680 - (void)adjustMetricsForMenuTopChanges:(LayoutMetrics*)layoutMetrics { |
701 LayoutMetrics& metrics(*layoutMetrics); | 681 LayoutMetrics& metrics(*layoutMetrics); |
702 if (metrics.canScrollDown == metrics.couldScrollDown) { | 682 if (metrics.canScrollDown == metrics.couldScrollDown) { |
703 if (!metrics.canScrollDown) { | 683 if (!metrics.canScrollDown) { |
704 // Not scroll-down-able but the menu top has changed. | 684 // Not scroll-down-able but the menu top has changed. |
705 metrics.deltaWindowHeight += metrics.scrollDelta; | 685 metrics.deltaWindowHeight += metrics.scrollDelta; |
706 } | 686 } |
707 } else { | 687 } else { |
708 if (metrics.canScrollDown) { | 688 if (metrics.canScrollDown) { |
709 // Couldn't -> Can | 689 // Couldn't -> Can |
710 const CGFloat maximumY = NSMaxY([screen_ visibleFrame]); | 690 const CGFloat maximumY = NSMaxY([[self menuScreen] visibleFrame]); |
711 metrics.deltaWindowHeight += (maximumY - NSMaxY(metrics.windowFrame)); | 691 metrics.deltaWindowHeight += (maximumY - NSMaxY(metrics.windowFrame)); |
712 metrics.deltaVisibleHeight -= bookmarks::kScrollWindowVerticalMargin; | 692 metrics.deltaVisibleHeight -= bookmarks::kScrollWindowVerticalMargin; |
713 metrics.deltaScrollerHeight -= verticalScrollArrowHeight_; | 693 metrics.deltaScrollerHeight -= verticalScrollArrowHeight_; |
714 } else { | 694 } else { |
715 // Could -> Can't | 695 // Could -> Can't |
716 metrics.deltaWindowHeight -= bookmarks::kScrollWindowVerticalMargin; | 696 metrics.deltaWindowHeight -= bookmarks::kScrollWindowVerticalMargin; |
717 metrics.deltaVisibleHeight += bookmarks::kScrollWindowVerticalMargin; | 697 metrics.deltaVisibleHeight += bookmarks::kScrollWindowVerticalMargin; |
718 metrics.deltaScrollerHeight += verticalScrollArrowHeight_; | 698 metrics.deltaScrollerHeight += verticalScrollArrowHeight_; |
719 } | 699 } |
720 } | 700 } |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
832 // Lay out the window by adjusting all button widths to be consistent, then | 812 // Lay out the window by adjusting all button widths to be consistent, then |
833 // base the window width on this ideal button width. | 813 // base the window width on this ideal button width. |
834 CGFloat buttonWidth = [self adjustButtonWidths]; | 814 CGFloat buttonWidth = [self adjustButtonWidths]; |
835 CGFloat windowWidth = buttonWidth + padding_; | 815 CGFloat windowWidth = buttonWidth + padding_; |
836 NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth | 816 NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth |
837 height:height]; | 817 height:height]; |
838 | 818 |
839 // Make sure as much of a submenu is exposed (which otherwise would be a | 819 // Make sure as much of a submenu is exposed (which otherwise would be a |
840 // problem if the parent button is close to the bottom of the screen). | 820 // problem if the parent button is close to the bottom of the screen). |
841 if ([parentController_ isKindOfClass:[self class]]) { | 821 if ([parentController_ isKindOfClass:[self class]]) { |
842 CGFloat minimumY = NSMinY([screen_ visibleFrame]) + | 822 CGFloat minimumY = NSMinY([[self menuScreen] visibleFrame]) + |
843 bookmarks::kScrollWindowVerticalMargin + | 823 bookmarks::kScrollWindowVerticalMargin + |
844 height; | 824 height; |
845 newWindowTopLeft.y = MAX(newWindowTopLeft.y, minimumY); | 825 newWindowTopLeft.y = MAX(newWindowTopLeft.y, minimumY); |
846 } | 826 } |
847 | 827 |
848 NSWindow* window = [self window]; | 828 NSWindow* window = [self window]; |
849 NSRect windowFrame = NSMakeRect(newWindowTopLeft.x, | 829 NSRect windowFrame = NSMakeRect(newWindowTopLeft.x, |
850 newWindowTopLeft.y - height, | 830 newWindowTopLeft.y - height, |
851 windowWidth, height); | 831 windowWidth, height); |
852 [window setFrame:windowFrame display:NO]; | 832 [window setFrame:windowFrame display:NO]; |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
977 index++; | 957 index++; |
978 } | 958 } |
979 } | 959 } |
980 } | 960 } |
981 | 961 |
982 - (CGFloat)determineFinalScrollDelta:(CGFloat)delta { | 962 - (CGFloat)determineFinalScrollDelta:(CGFloat)delta { |
983 if ((delta > 0.0 && ![scrollUpArrowView_ isHidden]) || | 963 if ((delta > 0.0 && ![scrollUpArrowView_ isHidden]) || |
984 (delta < 0.0 && ![scrollDownArrowView_ isHidden])) { | 964 (delta < 0.0 && ![scrollDownArrowView_ isHidden])) { |
985 NSWindow* window = [self window]; | 965 NSWindow* window = [self window]; |
986 NSRect windowFrame = [window frame]; | 966 NSRect windowFrame = [window frame]; |
| 967 NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; |
987 NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; | 968 NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; |
988 CGFloat scrollY = scrollPosition.y; | 969 CGFloat scrollY = scrollPosition.y; |
989 NSRect scrollerFrame = [scrollView_ frame]; | 970 NSRect scrollerFrame = [scrollView_ frame]; |
990 CGFloat scrollerY = NSMinY(scrollerFrame); | 971 CGFloat scrollerY = NSMinY(scrollerFrame); |
991 NSRect visibleFrame = [visibleView_ frame]; | 972 NSRect visibleFrame = [visibleView_ frame]; |
992 CGFloat visibleY = NSMinY(visibleFrame); | 973 CGFloat visibleY = NSMinY(visibleFrame); |
993 CGFloat windowY = NSMinY(windowFrame); | 974 CGFloat windowY = NSMinY(windowFrame); |
994 CGFloat offset = scrollerY + visibleY + windowY; | 975 CGFloat offset = scrollerY + visibleY + windowY; |
995 | 976 |
996 if (delta > 0.0) { | 977 if (delta > 0.0) { |
997 // Scrolling up. | 978 // Scrolling up. |
998 CGFloat minimumY = NSMinY([screen_ visibleFrame]) + | 979 CGFloat minimumY = NSMinY(screenVisibleFrame) + |
999 bookmarks::kScrollWindowVerticalMargin; | 980 bookmarks::kScrollWindowVerticalMargin; |
1000 CGFloat maxUpDelta = scrollY - offset + minimumY; | 981 CGFloat maxUpDelta = scrollY - offset + minimumY; |
1001 delta = MIN(delta, maxUpDelta); | 982 delta = MIN(delta, maxUpDelta); |
1002 } else { | 983 } else { |
1003 // Scrolling down. | 984 // Scrolling down. |
1004 NSRect screenFrame = [screen_ visibleFrame]; | 985 CGFloat topOfScreen = NSMaxY(screenVisibleFrame); |
1005 CGFloat topOfScreen = NSMaxY(screenFrame); | |
1006 NSRect folderFrame = [folderView_ frame]; | 986 NSRect folderFrame = [folderView_ frame]; |
1007 CGFloat folderHeight = NSHeight(folderFrame); | 987 CGFloat folderHeight = NSHeight(folderFrame); |
1008 CGFloat folderTop = folderHeight - scrollY + offset; | 988 CGFloat folderTop = folderHeight - scrollY + offset; |
1009 CGFloat maxDownDelta = | 989 CGFloat maxDownDelta = |
1010 topOfScreen - folderTop - bookmarks::kScrollWindowVerticalMargin; | 990 topOfScreen - folderTop - bookmarks::kScrollWindowVerticalMargin; |
1011 delta = MAX(delta, maxDownDelta); | 991 delta = MAX(delta, maxDownDelta); |
1012 } | 992 } |
1013 } else { | 993 } else { |
1014 delta = 0.0; | 994 delta = 0.0; |
1015 } | 995 } |
(...skipping 17 matching lines...) Expand all Loading... |
1033 verticalScrollDelta_ = delta; | 1013 verticalScrollDelta_ = delta; |
1034 scrollTimer_ = [NSTimer timerWithTimeInterval:kBookmarkBarFolderScrollInterval | 1014 scrollTimer_ = [NSTimer timerWithTimeInterval:kBookmarkBarFolderScrollInterval |
1035 target:self | 1015 target:self |
1036 selector:@selector(performScroll:) | 1016 selector:@selector(performScroll:) |
1037 userInfo:nil | 1017 userInfo:nil |
1038 repeats:YES]; | 1018 repeats:YES]; |
1039 | 1019 |
1040 [[NSRunLoop mainRunLoop] addTimer:scrollTimer_ forMode:NSRunLoopCommonModes]; | 1020 [[NSRunLoop mainRunLoop] addTimer:scrollTimer_ forMode:NSRunLoopCommonModes]; |
1041 } | 1021 } |
1042 | 1022 |
| 1023 - (NSScreen*)menuScreen { |
| 1024 // Return the parent button's screen for use as the screen upon which all |
| 1025 // display happens. This loop over all screens is not equivalent to |
| 1026 // |[[button window] screen]|. BookmarkButtons are commonly positioned near |
| 1027 // the edge of their windows (both in the bookmark bar and in other bookmark |
| 1028 // menus), and |[[button window] screen]| would return the screen that the |
| 1029 // majority of their window was on even if the parent button were clearly |
| 1030 // contained within a different screen. |
| 1031 NSButton* button = parentButton_.get(); |
| 1032 NSRect parentButtonGlobalFrame = |
| 1033 [button convertRect:[button bounds] toView:nil]; |
| 1034 parentButtonGlobalFrame.origin = |
| 1035 [[button window] convertBaseToScreen:parentButtonGlobalFrame.origin]; |
| 1036 for (NSScreen* screen in [NSScreen screens]) { |
| 1037 if (NSIntersectsRect([screen frame], parentButtonGlobalFrame)) |
| 1038 return screen; |
| 1039 } |
| 1040 |
| 1041 // The parent button is offscreen. The ideal thing to do would be to calculate |
| 1042 // the "closest" screen, the screen which has an edge parallel to, and the |
| 1043 // least distance from, one of the edges of the button. However, popping a |
| 1044 // subfolder from an offscreen button is an unrealistic edge case and so this |
| 1045 // ideal remains unrealized. Cheat instead; this code is wrong but a lot |
| 1046 // simpler. |
| 1047 return [[button window] screen]; |
| 1048 } |
1043 | 1049 |
1044 // Called as a result of our tracking area. Warning: on the main | 1050 // Called as a result of our tracking area. Warning: on the main |
1045 // screen (of a single-screened machine), the minimum mouse y value is | 1051 // screen (of a single-screened machine), the minimum mouse y value is |
1046 // 1, not 0. Also, we do not get events when the mouse is above the | 1052 // 1, not 0. Also, we do not get events when the mouse is above the |
1047 // menubar (to be fixed by setting the proper window level; see | 1053 // menubar (to be fixed by setting the proper window level; see |
1048 // initializer). | 1054 // initializer). |
1049 // Note [theEvent window] may not be our window, as we also get these messages | 1055 // Note [theEvent window] may not be our window, as we also get these messages |
1050 // forwarded from BookmarkButton's mouse tracking loop. | 1056 // forwarded from BookmarkButton's mouse tracking loop. |
1051 - (void)mouseMovedOrDragged:(NSEvent*)theEvent { | 1057 - (void)mouseMovedOrDragged:(NSEvent*)theEvent { |
1052 NSPoint eventScreenLocation = | 1058 NSPoint eventScreenLocation = |
(...skipping 960 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2013 | 2019 |
2014 - (void)setIgnoreAnimations:(BOOL)ignore { | 2020 - (void)setIgnoreAnimations:(BOOL)ignore { |
2015 ignoreAnimations_ = ignore; | 2021 ignoreAnimations_ = ignore; |
2016 } | 2022 } |
2017 | 2023 |
2018 - (BookmarkButton*)buttonThatMouseIsIn { | 2024 - (BookmarkButton*)buttonThatMouseIsIn { |
2019 return buttonThatMouseIsIn_; | 2025 return buttonThatMouseIsIn_; |
2020 } | 2026 } |
2021 | 2027 |
2022 @end // BookmarkBarFolderController | 2028 @end // BookmarkBarFolderController |
OLD | NEW |