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

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

Issue 476313003: Mac: Improve tab strip layout in case of overflow (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 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
OLDNEW
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/tabs/tab_strip_controller.h" 5 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
6 6
7 #import <QuartzCore/QuartzCore.h> 7 #import <QuartzCore/QuartzCore.h>
8 8
9 #include <cmath> 9 #include <cmath>
10 #include <limits> 10 #include <limits>
(...skipping 927 matching lines...) Expand 10 before | Expand all | Expand 10 after
938 // TODO(pinkerton): Note this doesn't do too well when the number of min-sized 938 // TODO(pinkerton): Note this doesn't do too well when the number of min-sized
939 // tabs would cause an overflow. http://crbug.com/188 939 // tabs would cause an overflow. http://crbug.com/188
940 - (void)layoutTabsWithAnimation:(BOOL)animate 940 - (void)layoutTabsWithAnimation:(BOOL)animate
941 regenerateSubviews:(BOOL)doUpdate { 941 regenerateSubviews:(BOOL)doUpdate {
942 DCHECK([NSThread isMainThread]); 942 DCHECK([NSThread isMainThread]);
943 if (![tabArray_ count]) 943 if (![tabArray_ count])
944 return; 944 return;
945 945
946 const CGFloat kMaxTabWidth = [TabController maxTabWidth]; 946 const CGFloat kMaxTabWidth = [TabController maxTabWidth];
947 const CGFloat kMinTabWidth = [TabController minTabWidth]; 947 const CGFloat kMinTabWidth = [TabController minTabWidth];
948 const CGFloat kMinSelectedTabWidth = [TabController minSelectedTabWidth]; 948 const CGFloat kMinActiveTabWidth = [TabController minActiveTabWidth];
949 const CGFloat kMiniTabWidth = [TabController miniTabWidth]; 949 const CGFloat kMiniTabWidth = [TabController miniTabWidth];
950 const CGFloat kAppTabWidth = [TabController appTabWidth]; 950 const CGFloat kAppTabWidth = [TabController appTabWidth];
951 951
952 NSRect enclosingRect = NSZeroRect; 952 NSRect enclosingRect = NSZeroRect;
953 ScopedNSAnimationContextGroup mainAnimationGroup(animate); 953 ScopedNSAnimationContextGroup mainAnimationGroup(animate);
954 mainAnimationGroup.SetCurrentContextDuration(kAnimationDuration); 954 mainAnimationGroup.SetCurrentContextDuration(kAnimationDuration);
955 955
956 // Update the current subviews and their z-order if requested. 956 // Update the current subviews and their z-order if requested.
957 if (doUpdate) 957 if (doUpdate)
958 [self regenerateSubviewList]; 958 [self regenerateSubviewList];
959 959
960 // Compute the base width of tabs given how much room we're allowed. Note that 960 // Compute the base width of tabs given how much room we're allowed. Note that
961 // mini-tabs have a fixed width. We may not be able to use the entire width 961 // mini-tabs have a fixed width. We may not be able to use the entire width
962 // if the user is quickly closing tabs. This may be negative, but that's okay 962 // if the user is quickly closing tabs. This may be negative, but that's okay
963 // (taken care of by |MAX()| when calculating tab sizes). 963 // (taken care of by |MAX()| when calculating tab sizes).
964 CGFloat availableSpace = 0; 964 CGFloat availableSpace = 0;
965 if ([self inRapidClosureMode]) { 965 if ([self inRapidClosureMode]) {
966 availableSpace = availableResizeWidth_; 966 availableSpace = availableResizeWidth_;
967 } else { 967 } else {
968 availableSpace = NSWidth([tabStripView_ frame]); 968 availableSpace = NSWidth([tabStripView_ frame]);
969 969
970 // Account for the width of the new tab button. 970 // Account for the width of the new tab button.
971 availableSpace -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset; 971 availableSpace -=
972 NSWidth([newTabButton_ frame]) + kNewTabButtonOffset - kTabOverlap;
Andre 2014/08/28 16:34:29 The new tab button also overlaps the right-most ta
972 973
973 // Account for the right-side controls if not in rapid closure mode. 974 // Account for the right-side controls if not in rapid closure mode.
974 // (In rapid closure mode, the available width is set based on the 975 // (In rapid closure mode, the available width is set based on the
975 // position of the rightmost tab, not based on the width of the tab strip, 976 // position of the rightmost tab, not based on the width of the tab strip,
976 // so the right controls have already been accounted for.) 977 // so the right controls have already been accounted for.)
977 availableSpace -= [self rightIndentForControls]; 978 availableSpace -= [self rightIndentForControls];
978 } 979 }
979 980
980 // Need to leave room for the left-side controls even in rapid closure mode. 981 // Need to leave room for the left-side controls even in rapid closure mode.
981 availableSpace -= [self leftIndentForControls]; 982 availableSpace -= [self leftIndentForControls];
982 983
983 // If there are any mini tabs, account for the extra spacing between the last
984 // mini tab and the first regular tab.
985 if ([self numberOfOpenMiniTabs])
986 availableSpace -= kLastMiniTabSpacing;
Andre 2014/08/28 16:34:29 availableSpaceForNonMini should be adjusted by thi
987
988 // This may be negative, but that's okay (taken care of by |MAX()| when 984 // This may be negative, but that's okay (taken care of by |MAX()| when
989 // calculating tab sizes). "mini" tabs in horizontal mode just get a special 985 // calculating tab sizes). "mini" tabs in horizontal mode just get a special
990 // section, they don't change size. 986 // section, they don't change size.
991 CGFloat availableSpaceForNonMini = availableSpace; 987 CGFloat availableSpaceForNonMini = availableSpace;
992 availableSpaceForNonMini -= 988 if ([self numberOfOpenMiniTabs]) {
993 [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap); 989 availableSpaceForNonMini -=
990 [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap);
991 availableSpaceForNonMini -= kLastMiniTabSpacing;
992 }
994 993
995 // Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this 994 // Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this
996 // value shouldn't actually be used. 995 // value shouldn't actually be used.
997 CGFloat nonMiniTabWidth = kMaxTabWidth; 996 CGFloat nonMiniTabWidth = kMaxTabWidth;
998 CGFloat nonMiniTabWidthFraction = 0; 997 CGFloat nonMiniTabWidthFraction = 0;
999 const NSInteger numberOfOpenNonMiniTabs = [self numberOfOpenNonMiniTabs]; 998 NSInteger numberOfNonMiniTabs = MIN(
1000 if (numberOfOpenNonMiniTabs) { 999 [self numberOfOpenNonMiniTabs],
1000 (availableSpaceForNonMini - kTabOverlap) / (kMinTabWidth - kTabOverlap));
1001
1002 if (numberOfNonMiniTabs) {
1001 // Find the width of a non-mini-tab. This only applies to horizontal 1003 // Find the width of a non-mini-tab. This only applies to horizontal
1002 // mode. Add in the amount we "get back" from the tabs overlapping. 1004 // mode. Add in the amount we "get back" from the tabs overlapping.
1003 availableSpaceForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap; 1005 nonMiniTabWidth =
1004 1006 ((availableSpaceForNonMini - kTabOverlap) / numberOfNonMiniTabs) +
1005 // Divide up the space between the non-mini-tabs. 1007 kTabOverlap;
1006 nonMiniTabWidth = availableSpaceForNonMini / numberOfOpenNonMiniTabs;
1007 1008
1008 // Clamp the width between the max and min. 1009 // Clamp the width between the max and min.
1009 nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth); 1010 nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth);
1010 1011
1012 // When there are multiple tabs, we'll have one active and some inactive
1013 // tabs. If the desired width was between the minimum sizes of these types,
1014 // try to shrink the tabs with the smaller minimum. For example, if we have
1015 // a strip of width 10 with 4 tabs, the desired width per tab will be 2.5.
1016 // If selected tabs have a minimum width of 4 and unselected tabs have
1017 // minimum width of 1, the above code would set *unselected_width = 2.5,
1018 // *selected_width = 4, which results in a total width of 11.5. Instead, we
1019 // want to set *unselected_width = 2, *selected_width = 4, for a total width
1020 // of 10.
1021 if (numberOfNonMiniTabs > 1 && nonMiniTabWidth < kMinActiveTabWidth) {
1022 nonMiniTabWidth = (availableSpaceForNonMini - kMinActiveTabWidth) /
1023 (numberOfNonMiniTabs - 1) +
1024 kTabOverlap;
Andre 2014/08/28 16:34:28 I took this logic from TabStrip::GetDesiredTabWidt
1025 if (nonMiniTabWidth < kMinTabWidth) {
1026 // The above adjustment caused the tabs to not fit, show 1 less tab.
1027 numberOfNonMiniTabs--;
Robert Sesek 2014/09/02 18:17:49 nit: favor pre-increment operator
Andre 2014/09/02 23:09:05 Done.
1028 nonMiniTabWidth =
1029 ((availableSpaceForNonMini - kTabOverlap) / numberOfNonMiniTabs) +
1030 kTabOverlap;
1031 }
1032 }
1033
1011 // Separate integral and fractional parts. 1034 // Separate integral and fractional parts.
1012 CGFloat integralPart = std::floor(nonMiniTabWidth); 1035 CGFloat integralPart = std::floor(nonMiniTabWidth);
1013 nonMiniTabWidthFraction = nonMiniTabWidth - integralPart; 1036 nonMiniTabWidthFraction = nonMiniTabWidth - integralPart;
1014 nonMiniTabWidth = integralPart; 1037 nonMiniTabWidth = integralPart;
1015 } 1038 }
1016 1039
1017 BOOL visible = [[tabStripView_ window] isVisible]; 1040 BOOL visible = [[tabStripView_ window] isVisible];
1018 1041
1019 CGFloat offset = [self leftIndentForControls]; 1042 CGFloat offset = [self leftIndentForControls];
1020 bool hasPlaceholderGap = false; 1043 bool hasPlaceholderGap = false;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1085 // algorithm. 1108 // algorithm.
1086 tabFrame.size.width = nonMiniTabWidth; 1109 tabFrame.size.width = nonMiniTabWidth;
1087 tabWidthAccumulatedFraction += nonMiniTabWidthFraction; 1110 tabWidthAccumulatedFraction += nonMiniTabWidthFraction;
1088 1111
1089 if (tabWidthAccumulatedFraction >= 1.0) { 1112 if (tabWidthAccumulatedFraction >= 1.0) {
1090 ++tabFrame.size.width; 1113 ++tabFrame.size.width;
1091 --tabWidthAccumulatedFraction; 1114 --tabWidthAccumulatedFraction;
1092 } 1115 }
1093 1116
1094 // In case of rounding error, give any left over pixels to the last tab. 1117 // In case of rounding error, give any left over pixels to the last tab.
1095 if (laidOutNonMiniTabs == numberOfOpenNonMiniTabs - 1 && 1118 if (laidOutNonMiniTabs == numberOfNonMiniTabs - 1 &&
1096 tabWidthAccumulatedFraction > 0.5) { 1119 tabWidthAccumulatedFraction > 0.5) {
1097 ++tabFrame.size.width; 1120 ++tabFrame.size.width;
1098 } 1121 }
1099 1122
1100 ++laidOutNonMiniTabs; 1123 ++laidOutNonMiniTabs;
1101 } 1124 }
1102 1125
1103 if ([tab selected]) 1126 if ([tab active])
1104 tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth); 1127 tabFrame.size.width = MAX(tabFrame.size.width, kMinActiveTabWidth);
1105 1128
1106 // If this is the first non-mini tab, then add a bit of spacing between this 1129 // If this is the first non-mini tab, then add a bit of spacing between this
1107 // and the last mini tab. 1130 // and the last mini tab.
1108 if (!isMini && isLastTabMini) { 1131 if (!isMini && isLastTabMini) {
1109 offset += kLastMiniTabSpacing; 1132 offset += kLastMiniTabSpacing;
1110 tabFrame.origin.x = offset; 1133 tabFrame.origin.x = offset;
1111 } 1134 }
1112 isLastTabMini = isMini; 1135 isLastTabMini = isMini;
1113 1136
1137 if (laidOutNonMiniTabs > numberOfNonMiniTabs) {
1138 // There is not enough space to fit this tab.
1139 tabFrame.size.width = 0;
1140 [self setFrame:tabFrame ofTabView:[tab view]];
1141 continue;
1142 }
1143
1114 // Animate a new tab in by putting it below the horizon unless told to put 1144 // Animate a new tab in by putting it below the horizon unless told to put
1115 // it in a specific location (i.e., from a drop). 1145 // it in a specific location (i.e., from a drop).
1116 if (newTab && visible && animate) { 1146 if (newTab && visible && animate) {
1117 if (NSEqualRects(droppedTabFrame_, NSZeroRect)) { 1147 if (NSEqualRects(droppedTabFrame_, NSZeroRect)) {
1118 [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))]; 1148 [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))];
1119 } else { 1149 } else {
1120 [[tab view] setFrame:droppedTabFrame_]; 1150 [[tab view] setFrame:droppedTabFrame_];
1121 droppedTabFrame_ = NSZeroRect; 1151 droppedTabFrame_ = NSZeroRect;
1122 } 1152 }
1123 } 1153 }
(...skipping 1105 matching lines...) Expand 10 before | Expand all | Expand 10 after
2229 } 2259 }
2230 2260
2231 NSRect GetSheetParentBoundsForParentView(NSView* view) { 2261 NSRect GetSheetParentBoundsForParentView(NSView* view) {
2232 // If the devtools view is open, it shrinks the size of the WebContents, so go 2262 // If the devtools view is open, it shrinks the size of the WebContents, so go
2233 // up the hierarchy to the devtools container view to avoid that. Note that 2263 // up the hierarchy to the devtools container view to avoid that. Note that
2234 // the devtools view is always in the hierarchy even if it is not open or it 2264 // the devtools view is always in the hierarchy even if it is not open or it
2235 // is detached. 2265 // is detached.
2236 NSView* devtools_view = [[[view superview] superview] superview]; 2266 NSView* devtools_view = [[[view superview] superview] superview];
2237 return [devtools_view convertRect:[devtools_view bounds] toView:nil]; 2267 return [devtools_view convertRect:[devtools_view bounds] toView:nil];
2238 } 2268 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698