Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(561)

Side by Side Diff: chrome/browser/cocoa/tab_strip_controller.mm

Issue 661265: P2.1a.
Patch Set: '' Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/cocoa/tab_strip_controller.h ('k') | chrome/browser/cocoa/tab_view.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/tab_strip_controller.h" 5 #import "chrome/browser/cocoa/tab_strip_controller.h"
6 6
7 #import <QuartzCore/QuartzCore.h> 7 #import <QuartzCore/QuartzCore.h>
8 8
9 #include <limits> 9 #include <limits>
10 #include <string> 10 #include <string>
(...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 569
570 TabContents* contents = tabStripModel_->GetTabContentsAt(index); 570 TabContents* contents = tabStripModel_->GetTabContentsAt(index);
571 if (contents) 571 if (contents)
572 UserMetrics::RecordAction("CloseTab_Mouse", contents->profile()); 572 UserMetrics::RecordAction("CloseTab_Mouse", contents->profile());
573 const NSInteger numberOfOpenTabs = [self numberOfOpenTabs]; 573 const NSInteger numberOfOpenTabs = [self numberOfOpenTabs];
574 if (numberOfOpenTabs > 1) { 574 if (numberOfOpenTabs > 1) {
575 bool isClosingLastTab = index == numberOfOpenTabs - 1; 575 bool isClosingLastTab = index == numberOfOpenTabs - 1;
576 if (!isClosingLastTab) { 576 if (!isClosingLastTab) {
577 // Limit the width available for laying out tabs so that tabs are not 577 // Limit the width available for laying out tabs so that tabs are not
578 // resized until a later time (when the mouse leaves the tab strip). 578 // resized until a later time (when the mouse leaves the tab strip).
579 // TODO(pinkerton): re-visit when handling tab overflow.
580 // http://crbug.com/188
581 NSView* penultimateTab = [self viewAtIndex:numberOfOpenTabs - 2]; 579 NSView* penultimateTab = [self viewAtIndex:numberOfOpenTabs - 2];
582 availableResizeWidth_ = NSMaxX([penultimateTab frame]); 580 availableResizeWidth_ = NSMaxX([penultimateTab frame]);
583 } else { 581 } else {
584 // If the rightmost tab is closed, change the available width so that 582 // If the rightmost tab is closed, change the available width so that
585 // another tab's close button lands below the cursor (assuming the tabs 583 // another tab's close button lands below the cursor (assuming the tabs
586 // are currently below their maximum width and can grow). 584 // are currently below their maximum width and can grow) if possible.
587 NSView* lastTab = [self viewAtIndex:numberOfOpenTabs - 1]; 585 NSView* lastTab = [self viewAtIndex:numberOfOpenTabs - 1];
588 availableResizeWidth_ = NSMaxX([lastTab frame]); 586 availableResizeWidth_ = NSMaxX([lastTab frame]);
587
588 // Since close buttons are on the left, this is a bit tricky. To make this
589 // at all possible, the rightmost tab keeps its narrow pre-close width
590 // and the other tabs expand to push it over.
591 // Only do this if the other tabs can be pushed far enough, though.
592 lastClosedTabWidth_.reset();
593 const CGFloat kPinnedTabWidth = [TabController pinnedTabWidth];
594 const CGFloat pinnedWidth =
595 [self numberOfOpenPinnedTabs] * (kPinnedTabWidth - kTabOverlap);
596 const CGFloat kMaxTabWidth = [TabController maxTabWidth];
597 const CGFloat unpinnedWidth = // 1 tab is candidate for being shorter
598 ([self numberOfOpenUnpinnedTabs] - 1) * (kMaxTabWidth - kTabOverlap);
599 CGFloat candidateWidth = NSWidth([lastTab frame]);
600 // Technically, it should be
601 // |pinnedWidth + unpinnedWidth + widthOfPartOfLastTabThatContainsClose|,
602 // but that's complicated _and_ makes the last tab look very thin.
603 if (pinnedWidth + unpinnedWidth >= availableResizeWidth_)
604 lastClosedTabWidth_.reset(new CGFloat(candidateWidth));
589 } 605 }
590 tabStripModel_->CloseTabContentsAt(index); 606 tabStripModel_->CloseTabContentsAt(index);
591 } else { 607 } else {
592 // Use the standard window close if this is the last tab 608 // Use the standard window close if this is the last tab
593 // this prevents the tab from being removed from the model until after 609 // this prevents the tab from being removed from the model until after
594 // the window dissapears 610 // the window dissapears
595 [[tabStripView_ window] performClose:nil]; 611 [[tabStripView_ window] performClose:nil];
596 } 612 }
597 } 613 }
598 614
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 if (doUpdate) 676 if (doUpdate)
661 [self regenerateSubviewList]; 677 [self regenerateSubviewList];
662 678
663 // Compute the base width of tabs given how much room we're allowed. Note that 679 // Compute the base width of tabs given how much room we're allowed. Note that
664 // pinned tabs have a fixed width. We may not be able to use the entire width 680 // pinned tabs have a fixed width. We may not be able to use the entire width
665 // if the user is quickly closing tabs. This may be negative, but that's okay 681 // if the user is quickly closing tabs. This may be negative, but that's okay
666 // (taken care of by |MAX()| when calculating tab sizes). 682 // (taken care of by |MAX()| when calculating tab sizes).
667 CGFloat availableWidth = 0; 683 CGFloat availableWidth = 0;
668 if ([self inRapidClosureMode]) { 684 if ([self inRapidClosureMode]) {
669 availableWidth = availableResizeWidth_; 685 availableWidth = availableResizeWidth_;
686 if (lastClosedTabWidth_.get())
687 availableWidth -= *lastClosedTabWidth_.get();
670 } else { 688 } else {
671 availableWidth = NSWidth([tabStripView_ frame]); 689 availableWidth = NSWidth([tabStripView_ frame]);
672 availableWidth -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset; 690 availableWidth -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset;
673 } 691 }
674 availableWidth -= [self indentForControls]; 692 availableWidth -= [self indentForControls];
675 693
676 // This may be negative, but that's okay (taken care of by |MAX()| when 694 // This may be negative, but that's okay (taken care of by |MAX()| when
677 // calculating tab sizes). 695 // calculating tab sizes).
678 CGFloat availableWidthForUnpinned = availableWidth - 696 CGFloat availableWidthForUnpinned = availableWidth -
679 [self numberOfOpenPinnedTabs] * (kPinnedTabWidth - kTabOverlap); 697 [self numberOfOpenPinnedTabs] * (kPinnedTabWidth - kTabOverlap);
680 698
681 // Initialize |unpinnedTabWidth| in case there aren't any unpinned tabs; this 699 // Initialize |unpinnedTabWidth| in case there aren't any unpinned tabs; this
682 // value shouldn't actually be used. 700 // value shouldn't actually be used.
683 CGFloat unpinnedTabWidth = kMaxTabWidth; 701 CGFloat unpinnedTabWidth = kMaxTabWidth;
684 const NSInteger numberOfOpenUnpinnedTabs = [self numberOfOpenUnpinnedTabs]; 702 const NSInteger numberOfOpenUnpinnedTabs = [self numberOfOpenUnpinnedTabs]
703 - (lastClosedTabWidth_.get() ? 1 : 0);
685 if (numberOfOpenUnpinnedTabs) { // Find the width of an unpinned tab. 704 if (numberOfOpenUnpinnedTabs) { // Find the width of an unpinned tab.
686 // Add in the amount we "get back" from the tabs overlapping. 705 // Add in the amount we "get back" from the tabs overlapping.
687 availableWidthForUnpinned += (numberOfOpenUnpinnedTabs - 1) * kTabOverlap; 706 availableWidthForUnpinned += (numberOfOpenUnpinnedTabs - 1) * kTabOverlap;
707 if (lastClosedTabWidth_.get())
708 availableWidthForUnpinned += kTabOverlap;
688 709
689 // Divide up the space between the unpinned tabs. 710 // Divide up the space between the unpinned tabs.
690 unpinnedTabWidth = availableWidthForUnpinned / numberOfOpenUnpinnedTabs; 711 unpinnedTabWidth = availableWidthForUnpinned / numberOfOpenUnpinnedTabs;
691 712
692 // Clamp the width between the max and min. 713 // Clamp the width between the max and min.
693 unpinnedTabWidth = MAX(MIN(unpinnedTabWidth, kMaxTabWidth), kMinTabWidth); 714 unpinnedTabWidth = MAX(MIN(unpinnedTabWidth, kMaxTabWidth), kMinTabWidth);
694 } 715 }
695 716
696 const CGFloat minX = NSMinX(placeholderFrame_); 717 const CGFloat minX = NSMinX(placeholderFrame_);
697 BOOL visible = [[tabStripView_ window] isVisible]; 718 BOOL visible = [[tabStripView_ window] isVisible];
698 719
699 CGFloat offset = [self indentForControls]; 720 CGFloat offset = [self indentForControls];
700 NSUInteger i = 0;
701 bool hasPlaceholderGap = false; 721 bool hasPlaceholderGap = false;
722 int openTabCount = 0;
702 for (TabController* tab in tabArray_.get()) { 723 for (TabController* tab in tabArray_.get()) {
703 // Ignore a tab that is going through a close animation. 724 // Ignore a tab that is going through a close animation.
704 if ([closingControllers_ containsObject:tab]) 725 if ([closingControllers_ containsObject:tab])
705 continue; 726 continue;
706 727
728 ++openTabCount;
707 BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_]; 729 BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_];
708 NSRect tabFrame = [[tab view] frame]; 730 NSRect tabFrame = [[tab view] frame];
709 tabFrame.size.height = [[self class] defaultTabHeight] + 1; 731 tabFrame.size.height = [[self class] defaultTabHeight] + 1;
710 tabFrame.origin.y = 0; 732 tabFrame.origin.y = 0;
711 tabFrame.origin.x = offset; 733 tabFrame.origin.x = offset;
712 734
713 // If the tab is hidden, we consider it a new tab. We make it visible 735 // If the tab is hidden, we consider it a new tab. We make it visible
714 // and animate it in. 736 // and animate it in.
715 BOOL newTab = [[tab view] isHidden]; 737 BOOL newTab = [[tab view] isHidden];
716 if (newTab) { 738 if (newTab) {
(...skipping 26 matching lines...) Expand all
743 offset -= kTabOverlap; 765 offset -= kTabOverlap;
744 tabFrame.origin.x = offset; 766 tabFrame.origin.x = offset;
745 } 767 }
746 768
747 // Set the width. Selected tabs are slightly wider when things get really 769 // Set the width. Selected tabs are slightly wider when things get really
748 // small and thus we enforce a different minimum width. 770 // small and thus we enforce a different minimum width.
749 tabFrame.size.width = [tab pinned] ? kPinnedTabWidth : unpinnedTabWidth; 771 tabFrame.size.width = [tab pinned] ? kPinnedTabWidth : unpinnedTabWidth;
750 if ([tab selected]) 772 if ([tab selected])
751 tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth); 773 tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth);
752 774
775 // When in rapid-closure mode, treat the width of the last tab in a way
776 // that its close button ends up below the cursor.
777 BOOL isLastOpenTab = tabStripModel_->count() == openTabCount;
778 if (isLastOpenTab && lastClosedTabWidth_.get())
779 tabFrame.size.width = *lastClosedTabWidth_.get();
780
753 // Animate a new tab in by putting it below the horizon unless told to put 781 // Animate a new tab in by putting it below the horizon unless told to put
754 // it in a specific location (i.e., from a drop). 782 // it in a specific location (i.e., from a drop).
755 if (newTab && visible && animate) { 783 if (newTab && visible && animate) {
756 if (NSEqualRects(droppedTabFrame_, NSZeroRect)) { 784 if (NSEqualRects(droppedTabFrame_, NSZeroRect)) {
757 [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))]; 785 [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))];
758 } else { 786 } else {
759 [[tab view] setFrame:droppedTabFrame_]; 787 [[tab view] setFrame:droppedTabFrame_];
760 droppedTabFrame_ = NSZeroRect; 788 droppedTabFrame_ = NSZeroRect;
761 } 789 }
762 } 790 }
763 791
764 // Check the frame by identifier to avoid redundant calls to animator. 792 // Check the frame by identifier to avoid redundant calls to animator.
765 id frameTarget = visible && animate ? [[tab view] animator] : [tab view]; 793 id frameTarget = visible && animate ? [[tab view] animator] : [tab view];
766 NSValue* identifier = [NSValue valueWithPointer:[tab view]]; 794 NSValue* identifier = [NSValue valueWithPointer:[tab view]];
767 NSValue* oldTargetValue = [targetFrames_ objectForKey:identifier]; 795 NSValue* oldTargetValue = [targetFrames_ objectForKey:identifier];
768 if (!oldTargetValue || 796 if (!oldTargetValue ||
769 !NSEqualRects([oldTargetValue rectValue], tabFrame)) { 797 !NSEqualRects([oldTargetValue rectValue], tabFrame)) {
770 [frameTarget setFrame:tabFrame]; 798 [frameTarget setFrame:tabFrame];
771 [targetFrames_ setObject:[NSValue valueWithRect:tabFrame] 799 [targetFrames_ setObject:[NSValue valueWithRect:tabFrame]
772 forKey:identifier]; 800 forKey:identifier];
773 } 801 }
774 802
775 enclosingRect = NSUnionRect(tabFrame, enclosingRect); 803 enclosingRect = NSUnionRect(tabFrame, enclosingRect);
776 804
777 offset += NSWidth(tabFrame); 805 offset += NSWidth(tabFrame);
778 offset -= kTabOverlap; 806 offset -= kTabOverlap;
779 i++;
780 } 807 }
781 808
782 // Hide the new tab button if we're explicitly told to. It may already 809 // Hide the new tab button if we're explicitly told to. It may already
783 // be hidden, doing it again doesn't hurt. Otherwise position it 810 // be hidden, doing it again doesn't hurt. Otherwise position it
784 // appropriately, showing it if necessary. 811 // appropriately, showing it if necessary.
785 if (forceNewTabButtonHidden_) { 812 if (forceNewTabButtonHidden_) {
786 [newTabButton_ setHidden:YES]; 813 [newTabButton_ setHidden:YES];
787 } else { 814 } else {
788 NSRect newTabNewFrame = [newTabButton_ frame]; 815 NSRect newTabNewFrame = [newTabButton_ frame];
789 // We've already ensured there's enough space for the new tab button 816 // We've already ensured there's enough space for the new tab button
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 // upwards as it's being initially layed out. Oddly, this works while doing 911 // upwards as it's being initially layed out. Oddly, this works while doing
885 // something similar in |-layoutTabs| confuses the window server. 912 // something similar in |-layoutTabs| confuses the window server.
886 [newView setFrame:NSOffsetRect([newView frame], 913 [newView setFrame:NSOffsetRect([newView frame],
887 0, -[[self class] defaultTabHeight])]; 914 0, -[[self class] defaultTabHeight])];
888 915
889 [self setTabTitle:newController withContents:contents]; 916 [self setTabTitle:newController withContents:contents];
890 917
891 // If a tab is being inserted, we can again use the entire tab strip width 918 // If a tab is being inserted, we can again use the entire tab strip width
892 // for layout. 919 // for layout.
893 availableResizeWidth_ = kUseFullAvailableWidth; 920 availableResizeWidth_ = kUseFullAvailableWidth;
921 lastClosedTabWidth_.reset();
894 922
895 // We don't need to call |-layoutTabs| if the tab will be in the foreground 923 // We don't need to call |-layoutTabs| if the tab will be in the foreground
896 // because it will get called when the new tab is selected by the tab model. 924 // because it will get called when the new tab is selected by the tab model.
897 // Whenever |-layoutTabs| is called, it'll also add the new subview. 925 // Whenever |-layoutTabs| is called, it'll also add the new subview.
898 if (!inForeground) { 926 if (!inForeground) {
899 [self layoutTabs]; 927 [self layoutTabs];
900 } 928 }
901 929
902 // During normal loading, we won't yet have a favicon and we'll get 930 // During normal loading, we won't yet have a favicon and we'll get
903 // subsequent state change notifications to show the throbber, but when we're 931 // subsequent state change notifications to show the throbber, but when we're
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after
1402 1430
1403 // Called when the tracking area is in effect which means we're tracking to 1431 // Called when the tracking area is in effect which means we're tracking to
1404 // see if the user leaves the tab strip with their mouse. When they do, 1432 // see if the user leaves the tab strip with their mouse. When they do,
1405 // reset layout to use all available width. 1433 // reset layout to use all available width.
1406 - (void)mouseExited:(NSEvent*)event { 1434 - (void)mouseExited:(NSEvent*)event {
1407 NSTrackingArea* area = [event trackingArea]; 1435 NSTrackingArea* area = [event trackingArea];
1408 if ([area isEqual:trackingArea_]) { 1436 if ([area isEqual:trackingArea_]) {
1409 mouseInside_ = NO; 1437 mouseInside_ = NO;
1410 [self setTabTrackingAreasEnabled:NO]; 1438 [self setTabTrackingAreasEnabled:NO];
1411 availableResizeWidth_ = kUseFullAvailableWidth; 1439 availableResizeWidth_ = kUseFullAvailableWidth;
1440 lastClosedTabWidth_.reset();
1412 [hoveredTab_ mouseExited:event]; 1441 [hoveredTab_ mouseExited:event];
1413 hoveredTab_ = nil; 1442 hoveredTab_ = nil;
1414 [self layoutTabs]; 1443 [self layoutTabs];
1415 } else if ([area isEqual:newTabTrackingArea_]) { 1444 } else if ([area isEqual:newTabTrackingArea_]) {
1416 [newTabButton_ setImage:nsimage_cache::ImageNamed(kNewTabImage)]; 1445 [newTabButton_ setImage:nsimage_cache::ImageNamed(kNewTabImage)];
1417 } 1446 }
1418 } 1447 }
1419 1448
1420 // Enable/Disable the tracking areas for the tabs. They are only enabled 1449 // Enable/Disable the tracking areas for the tabs. They are only enabled
1421 // when the mouse is in the tabstrip. 1450 // when the mouse is in the tabstrip.
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
1723 return; 1752 return;
1724 1753
1725 TabContentsController* tabController = 1754 TabContentsController* tabController =
1726 [tabContentsArray_ objectAtIndex:index]; 1755 [tabContentsArray_ objectAtIndex:index];
1727 TabContents* devtoolsContents = contents ? 1756 TabContents* devtoolsContents = contents ?
1728 DevToolsWindow::GetDevToolsContents(contents) : NULL; 1757 DevToolsWindow::GetDevToolsContents(contents) : NULL;
1729 [tabController showDevToolsContents:devtoolsContents]; 1758 [tabController showDevToolsContents:devtoolsContents];
1730 } 1759 }
1731 1760
1732 @end 1761 @end
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/tab_strip_controller.h ('k') | chrome/browser/cocoa/tab_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698