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/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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |