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

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

Issue 3204007: Make tabOverlap dynamic depending on the number of non-mini tabs presented on... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 10 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « chrome/browser/cocoa/tab_controller.mm ('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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 // The width and height for a tab's icon. 61 // The width and height for a tab's icon.
62 const CGFloat kIconWidthAndHeight = 16.0; 62 const CGFloat kIconWidthAndHeight = 16.0;
63 63
64 // The amount by which the new tab button is offset (from the tabs). 64 // The amount by which the new tab button is offset (from the tabs).
65 const CGFloat kNewTabButtonOffset = 8.0; 65 const CGFloat kNewTabButtonOffset = 8.0;
66 66
67 // The amount by which to shrink the tab strip (on the right) when the 67 // The amount by which to shrink the tab strip (on the right) when the
68 // incognito badge is present. 68 // incognito badge is present.
69 const CGFloat kIncognitoBadgeTabStripShrink = 18; 69 const CGFloat kIncognitoBadgeTabStripShrink = 18;
70 70
71 // The minimum offset of the tab over another tab
72 const CGFloat minTabOffset = 2.0;
73
71 // Time (in seconds) in which tabs animate to their final position. 74 // Time (in seconds) in which tabs animate to their final position.
72 const NSTimeInterval kAnimationDuration = 0.125; 75 const NSTimeInterval kAnimationDuration = 0.125;
73 76
74 // Helper class for doing NSAnimationContext calls that takes a bool to disable 77 // Helper class for doing NSAnimationContext calls that takes a bool to disable
75 // all the work. Useful for code that wants to conditionally animate. 78 // all the work. Useful for code that wants to conditionally animate.
76 class ScopedNSAnimationContextGroup { 79 class ScopedNSAnimationContextGroup {
77 public: 80 public:
78 explicit ScopedNSAnimationContextGroup(bool animate) 81 explicit ScopedNSAnimationContextGroup(bool animate)
79 : animate_(animate) { 82 : animate_(animate) {
80 if (animate_) { 83 if (animate_) {
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 593
591 // Called when the user clicks a tab. Tell the model the selection has changed, 594 // Called when the user clicks a tab. Tell the model the selection has changed,
592 // which feeds back into us via a notification. 595 // which feeds back into us via a notification.
593 - (void)selectTab:(id)sender { 596 - (void)selectTab:(id)sender {
594 DCHECK([sender isKindOfClass:[NSView class]]); 597 DCHECK([sender isKindOfClass:[NSView class]]);
595 int index = [self modelIndexForTabView:sender]; 598 int index = [self modelIndexForTabView:sender];
596 if (tabStripModel_->ContainsIndex(index)) 599 if (tabStripModel_->ContainsIndex(index))
597 tabStripModel_->SelectTabContentsAt(index, true); 600 tabStripModel_->SelectTabContentsAt(index, true);
598 } 601 }
599 602
603 - (NSView*)selectedTabView {
604 int selectedIndex = tabStripModel_->selected_index();
605 // Take closing tabs into account. They can't ever be selected.
606 selectedIndex = [self indexFromModelIndex:selectedIndex];
607 return [self viewAtIndex:selectedIndex];
608 }
609
600 // Called when the user closes a tab. Asks the model to close the tab. |sender| 610 // Called when the user closes a tab. Asks the model to close the tab. |sender|
601 // is the TabView that is potentially going away. 611 // is the TabView that is potentially going away.
602 - (void)closeTab:(id)sender { 612 - (void)closeTab:(id)sender {
603 DCHECK([sender isKindOfClass:[TabView class]]); 613 DCHECK([sender isKindOfClass:[TabView class]]);
604 if ([hoveredTab_ isEqual:sender]) { 614 if ([hoveredTab_ isEqual:sender]) {
605 hoveredTab_ = nil; 615 hoveredTab_ = nil;
606 } 616 }
607 617
608 NSInteger index = [self modelIndexForTabView:sender]; 618 NSInteger index = [self modelIndexForTabView:sender];
609 if (!tabStripModel_->ContainsIndex(index)) 619 if (!tabStripModel_->ContainsIndex(index))
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 // if the window is visible and |animate| is YES. 697 // if the window is visible and |animate| is YES.
688 // TODO(pinkerton): Note this doesn't do too well when the number of min-sized 698 // TODO(pinkerton): Note this doesn't do too well when the number of min-sized
689 // tabs would cause an overflow. http://crbug.com/188 699 // tabs would cause an overflow. http://crbug.com/188
690 - (void)layoutTabsWithAnimation:(BOOL)animate 700 - (void)layoutTabsWithAnimation:(BOOL)animate
691 regenerateSubviews:(BOOL)doUpdate { 701 regenerateSubviews:(BOOL)doUpdate {
692 DCHECK([NSThread isMainThread]); 702 DCHECK([NSThread isMainThread]);
693 if (![tabArray_ count]) 703 if (![tabArray_ count])
694 return; 704 return;
695 705
696 const CGFloat kMaxTabWidth = [TabController maxTabWidth]; 706 const CGFloat kMaxTabWidth = [TabController maxTabWidth];
697 const CGFloat kMinTabWidth = [TabController minTabWidth]; 707 const CGFloat kMinTabWidth = [TabController miniTabWidth];
698 const CGFloat kMinSelectedTabWidth = [TabController minSelectedTabWidth]; 708 const CGFloat kMinSelectedTabWidth = [TabController minSelectedTabWidth];
699 const CGFloat kMiniTabWidth = [TabController miniTabWidth]; 709 const CGFloat kMiniTabWidth = [TabController miniTabWidth];
700 const CGFloat kAppTabWidth = [TabController appTabWidth]; 710 const CGFloat kAppTabWidth = [TabController appTabWidth];
711 const CGFloat kHovTabWidth = [TabController maxTabWidth] / 2;
701 712
702 NSRect enclosingRect = NSZeroRect; 713 NSRect enclosingRect = NSZeroRect;
703 ScopedNSAnimationContextGroup mainAnimationGroup(animate); 714 ScopedNSAnimationContextGroup mainAnimationGroup(animate);
704 mainAnimationGroup.SetCurrentContextDuration(kAnimationDuration); 715 mainAnimationGroup.SetCurrentContextDuration(kAnimationDuration);
705 716
706 // Update the current subviews and their z-order if requested. 717 // Update the current subviews and their z-order if requested.
707 if (doUpdate) 718 if (doUpdate)
708 [self regenerateSubviewList]; 719 [self regenerateSubviewList];
709 720
710 // Compute the base width of tabs given how much room we're allowed. Note that 721 // Compute the base width of tabs given how much room we're allowed. Note that
(...skipping 21 matching lines...) Expand all
732 // section, they don't change size. 743 // section, they don't change size.
733 CGFloat availableSpaceForNonMini = availableSpace; 744 CGFloat availableSpaceForNonMini = availableSpace;
734 if (!verticalLayout_) { 745 if (!verticalLayout_) {
735 availableSpaceForNonMini -= 746 availableSpaceForNonMini -=
736 [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap); 747 [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap);
737 } 748 }
738 749
739 // Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this 750 // Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this
740 // value shouldn't actually be used. 751 // value shouldn't actually be used.
741 CGFloat nonMiniTabWidth = kMaxTabWidth; 752 CGFloat nonMiniTabWidth = kMaxTabWidth;
753 CGFloat availableSpaceForNewOverlap = availableSpaceForNonMini;
754 CGFloat tabOverlap = kTabOverlap;
742 const NSInteger numberOfOpenNonMiniTabs = [self numberOfOpenNonMiniTabs]; 755 const NSInteger numberOfOpenNonMiniTabs = [self numberOfOpenNonMiniTabs];
743 if (!verticalLayout_ && numberOfOpenNonMiniTabs) { 756 if (!verticalLayout_ && numberOfOpenNonMiniTabs) {
744 // Find the width of a non-mini-tab. This only applies to horizontal 757 // Find the width of a non-mini-tab. This only applies to horizontal
745 // mode. Add in the amount we "get back" from the tabs overlapping. 758 // mode. Add in the amount we "get back" from the tabs overlapping.
759
746 availableSpaceForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap; 760 availableSpaceForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap;
747 761
748 // Divide up the space between the non-mini-tabs. 762 // Divide up the space between the non-mini-tabs.
749 nonMiniTabWidth = availableSpaceForNonMini / numberOfOpenNonMiniTabs; 763 nonMiniTabWidth = availableSpaceForNonMini / numberOfOpenNonMiniTabs;
750 764
765
766 // This is one of the approach to solve the tab overflow problem.
767 // Find new tab overlap for all non-mini-tab
768 CGFloat extraSpace = kMinTabWidth * numberOfOpenNonMiniTabs - availableSpaceFo rNewOverlap;
769 if (nonMiniTabWidth < kMinTabWidth) {
770 tabOverlap = MIN(kMiniTabWidth - minTabOffset,
771 extraSpace / (numberOfOpenNonMiniTabs - 1));
772 }
773
751 // Clamp the width between the max and min. 774 // Clamp the width between the max and min.
752 nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth); 775 » nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth);
753 } 776 }
754 777
755 BOOL visible = [[tabStripView_ window] isVisible]; 778 BOOL visible = [[tabStripView_ window] isVisible];
756 779
757 CGFloat offset = [self indentForControls]; 780 CGFloat offset = [self indentForControls];
758 NSUInteger i = 0; 781 NSUInteger i = 0;
759 bool hasPlaceholderGap = false; 782 bool hasPlaceholderGap = false;
760 for (TabController* tab in tabArray_.get()) { 783 for (TabController* tab in tabArray_.get()) {
761 // Ignore a tab that is going through a close animation. 784 // Ignore a tab that is going through a close animation.
762 if ([closingControllers_ containsObject:tab]) 785 if ([closingControllers_ containsObject:tab])
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
809 hasPlaceholderGap = true; 832 hasPlaceholderGap = true;
810 offset += NSHeight(placeholderFrame_); 833 offset += NSHeight(placeholderFrame_);
811 tabFrame.origin.y = availableSpace - tabFrame.size.height - offset; 834 tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
812 } 835 }
813 } else { 836 } else {
814 // If the left edge is to the left of the placeholder's left, but the 837 // If the left edge is to the left of the placeholder's left, but the
815 // mid is to the right of it slide over to make space for it. 838 // mid is to the right of it slide over to make space for it.
816 if (NSMidX(tabFrame) > placeholderMin) { 839 if (NSMidX(tabFrame) > placeholderMin) {
817 hasPlaceholderGap = true; 840 hasPlaceholderGap = true;
818 offset += NSWidth(placeholderFrame_); 841 offset += NSWidth(placeholderFrame_);
819 offset -= kTabOverlap; 842 offset -= tabOverlap;
820 tabFrame.origin.x = offset; 843 tabFrame.origin.x = offset;
821 } 844 }
822 } 845 }
823 } 846 }
824 847
825 // Set the width. Selected tabs are slightly wider when things get really 848 // Set the width. Selected tabs are slightly wider when things get really
826 // small and thus we enforce a different minimum width. 849 // small and thus we enforce a different minimum width.
827 tabFrame.size.width = [tab mini] ? 850 tabFrame.size.width = [tab mini] ?
828 ([tab app] ? kAppTabWidth : kMiniTabWidth) : nonMiniTabWidth; 851 ([tab app] ? kAppTabWidth : kMiniTabWidth) : nonMiniTabWidth;
829 if ([tab selected]) 852
830 tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth); 853 » // Added width for hovered tab
854 » tabFrame.size.width = [tab selected] ?
855 » » MAX(tabFrame.size.width, kMinSelectedTabWidth) :
856 » » » ([tab hovered] && ![tab mini] && ![tab app] ?
857 » » » » MAX(tabFrame.size.width, kHovTabWidth) : tabFram e.size.width);
831 858
832 // Animate a new tab in by putting it below the horizon unless told to put 859 // Animate a new tab in by putting it below the horizon unless told to put
833 // it in a specific location (i.e., from a drop). 860 // it in a specific location (i.e., from a drop).
834 // TODO(pinkerton): figure out vertical tab animations. 861 // TODO(pinkerton): figure out vertical tab animations.
835 if (newTab && visible && animate) { 862 if (newTab && visible && animate) {
836 if (NSEqualRects(droppedTabFrame_, NSZeroRect)) { 863 if (NSEqualRects(droppedTabFrame_, NSZeroRect)) {
837 [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))]; 864 [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))];
838 } else { 865 } else {
839 [[tab view] setFrame:droppedTabFrame_]; 866 [[tab view] setFrame:droppedTabFrame_];
840 droppedTabFrame_ = NSZeroRect; 867 droppedTabFrame_ = NSZeroRect;
(...skipping 10 matching lines...) Expand all
851 [targetFrames_ setObject:[NSValue valueWithRect:tabFrame] 878 [targetFrames_ setObject:[NSValue valueWithRect:tabFrame]
852 forKey:identifier]; 879 forKey:identifier];
853 } 880 }
854 881
855 enclosingRect = NSUnionRect(tabFrame, enclosingRect); 882 enclosingRect = NSUnionRect(tabFrame, enclosingRect);
856 883
857 if (verticalLayout_) { 884 if (verticalLayout_) {
858 offset += NSHeight(tabFrame); 885 offset += NSHeight(tabFrame);
859 } else { 886 } else {
860 offset += NSWidth(tabFrame); 887 offset += NSWidth(tabFrame);
861 offset -= kTabOverlap; 888 » offset -= [tab mini] || [tab app] ? kTabOverlap : tabOverlap;
862 } 889 }
863 i++; 890 i++;
864 } 891 }
865 892
866 // Hide the new tab button if we're explicitly told to. It may already 893 // Hide the new tab button if we're explicitly told to. It may already
867 // be hidden, doing it again doesn't hurt. Otherwise position it 894 // be hidden, doing it again doesn't hurt. Otherwise position it
868 // appropriately, showing it if necessary. 895 // appropriately, showing it if necessary.
869 if (forceNewTabButtonHidden_) { 896 if (forceNewTabButtonHidden_) {
870 [newTabButton_ setHidden:YES]; 897 [newTabButton_ setHidden:YES];
871 } else { 898 } else {
872 NSRect newTabNewFrame = [newTabButton_ frame]; 899 NSRect newTabNewFrame = [newTabButton_ frame];
873 // We've already ensured there's enough space for the new tab button 900 // We've already ensured there's enough space for the new tab button
874 // so we don't have to check it against the available space. We do need 901 // so we don't have to check it against the available space. We do need
875 // to make sure we put it after any placeholder. 902 // to make sure we put it after any placeholder.
876 newTabNewFrame.origin = NSMakePoint(offset, 0); 903 newTabNewFrame.origin = NSMakePoint(offset + (tabOverlap - kTabOverlap) + kN ewTabButtonOffset, 0);
877 newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x, 904 newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x,
878 NSMaxX(placeholderFrame_)) + 905 NSMaxX(placeholderFrame_)) +
879 kNewTabButtonOffset; 906 kNewTabButtonOffset;
880 if ([tabContentsArray_ count]) 907 if ([tabContentsArray_ count])
881 [newTabButton_ setHidden:NO]; 908 [newTabButton_ setHidden:NO];
882 909
883 if (!NSEqualRects(newTabTargetFrame_, newTabNewFrame)) { 910 if (!NSEqualRects(newTabTargetFrame_, newTabNewFrame)) {
884 // Set the new tab button image correctly based on where the cursor is. 911 // Set the new tab button image correctly based on where the cursor is.
885 NSWindow* window = [tabStripView_ window]; 912 NSWindow* window = [tabStripView_ window];
886 NSPoint currentMouse = [window mouseLocationOutsideOfEventStream]; 913 NSPoint currentMouse = [window mouseLocationOutsideOfEventStream];
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
1332 } 1359 }
1333 1360
1334 - (void)setFrameOfSelectedTab:(NSRect)frame { 1361 - (void)setFrameOfSelectedTab:(NSRect)frame {
1335 NSView* view = [self selectedTabView]; 1362 NSView* view = [self selectedTabView];
1336 NSValue* identifier = [NSValue valueWithPointer:view]; 1363 NSValue* identifier = [NSValue valueWithPointer:view];
1337 [targetFrames_ setObject:[NSValue valueWithRect:frame] 1364 [targetFrames_ setObject:[NSValue valueWithRect:frame]
1338 forKey:identifier]; 1365 forKey:identifier];
1339 [view setFrame:frame]; 1366 [view setFrame:frame];
1340 } 1367 }
1341 1368
1342 - (NSView*)selectedTabView {
1343 int selectedIndex = tabStripModel_->selected_index();
1344 // Take closing tabs into account. They can't ever be selected.
1345 selectedIndex = [self indexFromModelIndex:selectedIndex];
1346 return [self viewAtIndex:selectedIndex];
1347 }
1348
1349 // Find the model index based on the x coordinate of the placeholder. If there 1369 // Find the model index based on the x coordinate of the placeholder. If there
1350 // is no placeholder, this returns the end of the tab strip. Closing tabs are 1370 // is no placeholder, this returns the end of the tab strip. Closing tabs are
1351 // not considered in computing the index. 1371 // not considered in computing the index.
1352 - (int)indexOfPlaceholder { 1372 - (int)indexOfPlaceholder {
1353 double placeholderX = placeholderFrame_.origin.x; 1373 double placeholderX = placeholderFrame_.origin.x;
1354 int index = 0; 1374 int index = 0;
1355 int location = 0; 1375 int location = 0;
1356 // Use |tabArray_| here instead of the tab strip count in order to get the 1376 // Use |tabArray_| here instead of the tab strip count in order to get the
1357 // correct index when there are closing tabs to the left of the placeholder. 1377 // correct index when there are closing tabs to the left of the placeholder.
1358 const int count = [tabArray_ count]; 1378 const int count = [tabArray_ count];
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
1467 if ([[tabView superview] isKindOfClass:[TabView class]]) { 1487 if ([[tabView superview] isKindOfClass:[TabView class]]) {
1468 tabView = (TabView*)[targetView superview]; 1488 tabView = (TabView*)[targetView superview];
1469 } else { 1489 } else {
1470 tabView = nil; 1490 tabView = nil;
1471 } 1491 }
1472 } 1492 }
1473 1493
1474 if (hoveredTab_ != tabView) { 1494 if (hoveredTab_ != tabView) {
1475 [hoveredTab_ mouseExited:nil]; // We don't pass event because moved events 1495 [hoveredTab_ mouseExited:nil]; // We don't pass event because moved events
1476 [tabView mouseEntered:nil]; // don't have valid tracking areas 1496 [tabView mouseEntered:nil]; // don't have valid tracking areas
1477 hoveredTab_ = tabView; 1497 » hoveredTab_ = tabView;
1498 [self layoutTabsWithAnimation:YES regenerateSubviews:NO];
1478 } else { 1499 } else {
1479 [hoveredTab_ mouseMoved:event]; 1500 [hoveredTab_ mouseMoved:event];
1480 } 1501 }
1481 } 1502 }
1482 1503
1483 - (void)mouseEntered:(NSEvent*)event { 1504 - (void)mouseEntered:(NSEvent*)event {
1484 NSTrackingArea* area = [event trackingArea]; 1505 NSTrackingArea* area = [event trackingArea];
1485 if ([area isEqual:trackingArea_]) { 1506 if ([area isEqual:trackingArea_]) {
1486 mouseInside_ = YES; 1507 mouseInside_ = YES;
1487 [self setTabTrackingAreasEnabled:YES]; 1508 [self setTabTrackingAreasEnabled:YES];
1488 [self mouseMoved:event]; 1509 [self mouseMoved:event];
1510
1511
1512 NSView* targetView = [tabStripView_ hitTest:[event locationInWindow]];
1513 if ([targetView isKindOfClass:[TabView class]]) {
1514 [self layoutTabsWithAnimation:YES regenerateSubviews:NO];
1515 }
1489 } 1516 }
1490 } 1517 }
1491 1518
1492 // Called when the tracking area is in effect which means we're tracking to 1519 // Called when the tracking area is in effect which means we're tracking to
1493 // see if the user leaves the tab strip with their mouse. When they do, 1520 // see if the user leaves the tab strip with their mouse. When they do,
1494 // reset layout to use all available width. 1521 // reset layout to use all available width.
1495 - (void)mouseExited:(NSEvent*)event { 1522 - (void)mouseExited:(NSEvent*)event {
1496 NSTrackingArea* area = [event trackingArea]; 1523 NSTrackingArea* area = [event trackingArea];
1497 if ([area isEqual:trackingArea_]) { 1524 if ([area isEqual:trackingArea_]) {
1498 mouseInside_ = NO; 1525 mouseInside_ = NO;
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
1833 return; 1860 return;
1834 1861
1835 TabContentsController* tabController = 1862 TabContentsController* tabController =
1836 [tabContentsArray_ objectAtIndex:index]; 1863 [tabContentsArray_ objectAtIndex:index];
1837 TabContents* devtoolsContents = contents ? 1864 TabContents* devtoolsContents = contents ?
1838 DevToolsWindow::GetDevToolsContents(contents) : NULL; 1865 DevToolsWindow::GetDevToolsContents(contents) : NULL;
1839 [tabController showDevToolsContents:devtoolsContents]; 1866 [tabController showDevToolsContents:devtoolsContents];
1840 } 1867 }
1841 1868
1842 @end 1869 @end
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/tab_controller.mm ('k') | chrome/browser/cocoa/tab_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698