| 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 using content::OpenURLParams; | 77 using content::OpenURLParams; |
| 78 using content::Referrer; | 78 using content::Referrer; |
| 79 using content::WebContents; | 79 using content::WebContents; |
| 80 | 80 |
| 81 namespace { | 81 namespace { |
| 82 | 82 |
| 83 // A value to indicate tab layout should use the full available width of the | 83 // A value to indicate tab layout should use the full available width of the |
| 84 // view. | 84 // view. |
| 85 const CGFloat kUseFullAvailableWidth = -1.0; | 85 const CGFloat kUseFullAvailableWidth = -1.0; |
| 86 | 86 |
| 87 // The amount by which tabs overlap. | |
| 88 // Needs to be <= the x position of the favicon within a tab. Else, every time | |
| 89 // the throbber is painted, the throbber's invalidation will also invalidate | |
| 90 // parts of the tab to the left, and two tabs's backgrounds need to be painted | |
| 91 // on each throbber frame instead of one. | |
| 92 const CGFloat kTabOverlap = 18.0; | |
| 93 const CGFloat kTabOverlapNonMD = 19.0; | |
| 94 | |
| 95 // The amount by which pinned tabs are separated from normal tabs. | 87 // The amount by which pinned tabs are separated from normal tabs. |
| 96 const CGFloat kLastPinnedTabSpacing = 2.0; | 88 const CGFloat kLastPinnedTabSpacing = 2.0; |
| 97 | 89 |
| 98 // The amount by which the new tab button is offset (from the tabs). | 90 // The amount by which the new tab button is offset (from the tabs). |
| 99 const CGFloat kNewTabButtonOffset = 10.0; | 91 const CGFloat kNewTabButtonOffset = 10.0; |
| 100 const CGFloat kNewTabButtonOffsetNonMD = 8.0; | 92 const CGFloat kNewTabButtonOffsetNonMD = 8.0; |
| 101 | 93 |
| 102 // Time (in seconds) in which tabs animate to their final position. | 94 // Time (in seconds) in which tabs animate to their final position. |
| 103 const NSTimeInterval kAnimationDuration = 0.125; | 95 const NSTimeInterval kAnimationDuration = 0.125; |
| 104 | 96 |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 + (CGFloat)defaultTabHeight { | 544 + (CGFloat)defaultTabHeight { |
| 553 return [TabController defaultTabHeight]; | 545 return [TabController defaultTabHeight]; |
| 554 } | 546 } |
| 555 | 547 |
| 556 + (CGFloat)defaultLeftIndentForControls { | 548 + (CGFloat)defaultLeftIndentForControls { |
| 557 // Default indentation leaves enough room so tabs don't overlap with the | 549 // Default indentation leaves enough room so tabs don't overlap with the |
| 558 // window controls. | 550 // window controls. |
| 559 return 70.0; | 551 return 70.0; |
| 560 } | 552 } |
| 561 | 553 |
| 554 + (CGFloat)tabOverlap { |
| 555 // The overlap value needs to be <= the x position of the favicon within a |
| 556 // tab. Else, every time the throbber is painted, the throbber's invalidation |
| 557 // will also invalidate parts of the tab to the left, and two tabs's |
| 558 // backgrounds need to be painted on each throbber frame instead of one. |
| 559 const CGFloat kTabOverlap = 18.0; |
| 560 const CGFloat kTabOverlapNonMD = 19.0; |
| 561 |
| 562 if (!ui::MaterialDesignController::IsModeMaterial()) { |
| 563 return kTabOverlapNonMD; |
| 564 } |
| 565 return kTabOverlap; |
| 566 } |
| 567 |
| 562 // Finds the TabContentsController associated with the given index into the tab | 568 // Finds the TabContentsController associated with the given index into the tab |
| 563 // model and swaps out the sole child of the contentArea to display its | 569 // model and swaps out the sole child of the contentArea to display its |
| 564 // contents. | 570 // contents. |
| 565 - (void)swapInTabAtIndex:(NSInteger)modelIndex { | 571 - (void)swapInTabAtIndex:(NSInteger)modelIndex { |
| 566 DCHECK(modelIndex >= 0 && modelIndex < tabStripModel_->count()); | 572 DCHECK(modelIndex >= 0 && modelIndex < tabStripModel_->count()); |
| 567 NSInteger index = [self indexFromModelIndex:modelIndex]; | 573 NSInteger index = [self indexFromModelIndex:modelIndex]; |
| 568 TabContentsController* controller = [tabContentsArray_ objectAtIndex:index]; | 574 TabContentsController* controller = [tabContentsArray_ objectAtIndex:index]; |
| 569 | 575 |
| 570 // Make sure we do not draw any transient arrangements of views. | 576 // Make sure we do not draw any transient arrangements of views. |
| 571 gfx::ScopedCocoaDisableScreenUpdates cocoa_disabler; | 577 gfx::ScopedCocoaDisableScreenUpdates cocoa_disabler; |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 905 - (void)layoutTabsWithAnimation:(BOOL)animate | 911 - (void)layoutTabsWithAnimation:(BOOL)animate |
| 906 regenerateSubviews:(BOOL)doUpdate { | 912 regenerateSubviews:(BOOL)doUpdate { |
| 907 DCHECK([NSThread isMainThread]); | 913 DCHECK([NSThread isMainThread]); |
| 908 if (![tabArray_ count]) | 914 if (![tabArray_ count]) |
| 909 return; | 915 return; |
| 910 | 916 |
| 911 const CGFloat kMaxTabWidth = [TabController maxTabWidth]; | 917 const CGFloat kMaxTabWidth = [TabController maxTabWidth]; |
| 912 const CGFloat kMinTabWidth = [TabController minTabWidth]; | 918 const CGFloat kMinTabWidth = [TabController minTabWidth]; |
| 913 const CGFloat kMinActiveTabWidth = [TabController minActiveTabWidth]; | 919 const CGFloat kMinActiveTabWidth = [TabController minActiveTabWidth]; |
| 914 const CGFloat kPinnedTabWidth = [TabController pinnedTabWidth]; | 920 const CGFloat kPinnedTabWidth = [TabController pinnedTabWidth]; |
| 921 const CGFloat kTabOverlap = [TabStripController tabOverlap]; |
| 915 | 922 |
| 916 NSRect enclosingRect = NSZeroRect; | 923 NSRect enclosingRect = NSZeroRect; |
| 917 ScopedNSAnimationContextGroup mainAnimationGroup(animate); | 924 ScopedNSAnimationContextGroup mainAnimationGroup(animate); |
| 918 mainAnimationGroup.SetCurrentContextDuration(kAnimationDuration); | 925 mainAnimationGroup.SetCurrentContextDuration(kAnimationDuration); |
| 919 | 926 |
| 920 // Update the current subviews and their z-order if requested. | 927 // Update the current subviews and their z-order if requested. |
| 921 if (doUpdate) | 928 if (doUpdate) |
| 922 [self regenerateSubviewList]; | 929 [self regenerateSubviewList]; |
| 923 | 930 |
| 924 // Compute the base width of tabs given how much room we're allowed. Note that | 931 // Compute the base width of tabs given how much room we're allowed. Note that |
| 925 // pinned tabs have a fixed width. We may not be able to use the entire width | 932 // pinned tabs have a fixed width. We may not be able to use the entire width |
| 926 // if the user is quickly closing tabs. This may be negative, but that's okay | 933 // if the user is quickly closing tabs. This may be negative, but that's okay |
| 927 // (taken care of by |MAX()| when calculating tab sizes). | 934 // (taken care of by |MAX()| when calculating tab sizes). |
| 928 CGFloat availableSpace = 0; | 935 CGFloat availableSpace = 0; |
| 929 if ([self inRapidClosureMode]) { | 936 if ([self inRapidClosureMode]) { |
| 930 availableSpace = availableResizeWidth_; | 937 availableSpace = availableResizeWidth_; |
| 931 } else { | 938 } else { |
| 932 availableSpace = NSWidth([tabStripView_ frame]); | 939 availableSpace = NSWidth([tabStripView_ frame]); |
| 933 | 940 |
| 934 // Account for the width of the new tab button. | 941 // Account for the width of the new tab button. |
| 935 if (!ui::MaterialDesignController::IsModeMaterial()) { | 942 if (!ui::MaterialDesignController::IsModeMaterial()) { |
| 936 availableSpace -= | 943 availableSpace -= |
| 937 NSWidth([newTabButton_ frame]) + kNewTabButtonOffsetNonMD - | 944 NSWidth([newTabButton_ frame]) + kNewTabButtonOffsetNonMD - |
| 938 kTabOverlapNonMD; | 945 kTabOverlap; |
| 939 } else { | 946 } else { |
| 940 availableSpace -= | 947 availableSpace -= |
| 941 NSWidth([newTabButton_ frame]) + kNewTabButtonOffset - kTabOverlap; | 948 NSWidth([newTabButton_ frame]) + kNewTabButtonOffset - kTabOverlap; |
| 942 } | 949 } |
| 943 // Account for the right-side controls if not in rapid closure mode. | 950 // Account for the right-side controls if not in rapid closure mode. |
| 944 // (In rapid closure mode, the available width is set based on the | 951 // (In rapid closure mode, the available width is set based on the |
| 945 // position of the rightmost tab, not based on the width of the tab strip, | 952 // position of the rightmost tab, not based on the width of the tab strip, |
| 946 // so the right controls have already been accounted for.) | 953 // so the right controls have already been accounted for.) |
| 947 availableSpace -= [self rightIndentForControls]; | 954 availableSpace -= [self rightIndentForControls]; |
| 948 } | 955 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 959 [self numberOfOpenPinnedTabs] * (kPinnedTabWidth - kTabOverlap); | 966 [self numberOfOpenPinnedTabs] * (kPinnedTabWidth - kTabOverlap); |
| 960 availableSpaceForNonPinned -= kLastPinnedTabSpacing; | 967 availableSpaceForNonPinned -= kLastPinnedTabSpacing; |
| 961 } | 968 } |
| 962 | 969 |
| 963 // Initialize |nonPinnedTabWidth| in case there aren't any non-pinned tabs; | 970 // Initialize |nonPinnedTabWidth| in case there aren't any non-pinned tabs; |
| 964 // this value shouldn't actually be used. | 971 // this value shouldn't actually be used. |
| 965 CGFloat nonPinnedTabWidth = kMaxTabWidth; | 972 CGFloat nonPinnedTabWidth = kMaxTabWidth; |
| 966 CGFloat nonPinnedTabWidthFraction = 0; | 973 CGFloat nonPinnedTabWidthFraction = 0; |
| 967 NSInteger numberOfNonPinnedTabs = MIN( | 974 NSInteger numberOfNonPinnedTabs = MIN( |
| 968 [self numberOfOpenNonPinnedTabs], | 975 [self numberOfOpenNonPinnedTabs], |
| 969 (availableSpaceForNonPinned - kTabOverlap) / (kMinTabWidth - | 976 (availableSpaceForNonPinned - kTabOverlap) / |
| 970 kTabOverlap)); | 977 (kMinTabWidth - kTabOverlap)); |
| 971 | 978 |
| 972 if (numberOfNonPinnedTabs) { | 979 if (numberOfNonPinnedTabs) { |
| 973 // Find the width of a non-pinned tab. This only applies to horizontal | 980 // Find the width of a non-pinned tab. This only applies to horizontal |
| 974 // mode. Add in the amount we "get back" from the tabs overlapping. | 981 // mode. Add in the amount we "get back" from the tabs overlapping. |
| 975 nonPinnedTabWidth = | 982 nonPinnedTabWidth = |
| 976 ((availableSpaceForNonPinned - kTabOverlap) / numberOfNonPinnedTabs) + | 983 ((availableSpaceForNonPinned - kTabOverlap) / numberOfNonPinnedTabs) + |
| 977 kTabOverlap; | 984 kTabOverlap; |
| 978 | 985 |
| 979 // Clamp the width between the max and min. | 986 // Clamp the width between the max and min. |
| 980 nonPinnedTabWidth = MAX(MIN(nonPinnedTabWidth, kMaxTabWidth), kMinTabWidth); | 987 nonPinnedTabWidth = MAX(MIN(nonPinnedTabWidth, kMaxTabWidth), kMinTabWidth); |
| 981 | 988 |
| 982 // When there are multiple tabs, we'll have one active and some inactive | 989 // When there are multiple tabs, we'll have one active and some inactive |
| 983 // tabs. If the desired width was between the minimum sizes of these types, | 990 // tabs. If the desired width was between the minimum sizes of these types, |
| 984 // try to shrink the tabs with the smaller minimum. For example, if we have | 991 // try to shrink the tabs with the smaller minimum. For example, if we have |
| 985 // a strip of width 10 with 4 tabs, the desired width per tab will be 2.5. | 992 // a strip of width 10 with 4 tabs, the desired width per tab will be 2.5. |
| 986 // If selected tabs have a minimum width of 4 and unselected tabs have | 993 // If selected tabs have a minimum width of 4 and unselected tabs have |
| 987 // minimum width of 1, the above code would set *unselected_width = 2.5, | 994 // minimum width of 1, the above code would set *unselected_width = 2.5, |
| 988 // *selected_width = 4, which results in a total width of 11.5. Instead, we | 995 // *selected_width = 4, which results in a total width of 11.5. Instead, we |
| 989 // want to set *unselected_width = 2, *selected_width = 4, for a total width | 996 // want to set *unselected_width = 2, *selected_width = 4, for a total width |
| 990 // of 10. | 997 // of 10. |
| 991 if (numberOfNonPinnedTabs > 1 && nonPinnedTabWidth < kMinActiveTabWidth) { | 998 if (numberOfNonPinnedTabs > 1 && nonPinnedTabWidth < kMinActiveTabWidth) { |
| 992 nonPinnedTabWidth = (availableSpaceForNonPinned - kMinActiveTabWidth) / | 999 nonPinnedTabWidth = (availableSpaceForNonPinned - kMinActiveTabWidth) / |
| 993 (numberOfNonPinnedTabs - 1) + | 1000 (numberOfNonPinnedTabs - 1) + kTabOverlap; |
| 994 kTabOverlap; | |
| 995 if (nonPinnedTabWidth < kMinTabWidth) { | 1001 if (nonPinnedTabWidth < kMinTabWidth) { |
| 996 // The above adjustment caused the tabs to not fit, show 1 less tab. | 1002 // The above adjustment caused the tabs to not fit, show 1 less tab. |
| 997 --numberOfNonPinnedTabs; | 1003 --numberOfNonPinnedTabs; |
| 998 nonPinnedTabWidth = ((availableSpaceForNonPinned - kTabOverlap) / | 1004 nonPinnedTabWidth = ((availableSpaceForNonPinned - kTabOverlap) / |
| 999 numberOfNonPinnedTabs) + | 1005 numberOfNonPinnedTabs) + kTabOverlap; |
| 1000 kTabOverlap; | |
| 1001 } | 1006 } |
| 1002 } | 1007 } |
| 1003 | 1008 |
| 1004 // Separate integral and fractional parts. | 1009 // Separate integral and fractional parts. |
| 1005 CGFloat integralPart = std::floor(nonPinnedTabWidth); | 1010 CGFloat integralPart = std::floor(nonPinnedTabWidth); |
| 1006 nonPinnedTabWidthFraction = nonPinnedTabWidth - integralPart; | 1011 nonPinnedTabWidthFraction = nonPinnedTabWidth - integralPart; |
| 1007 nonPinnedTabWidth = integralPart; | 1012 nonPinnedTabWidth = integralPart; |
| 1008 } | 1013 } |
| 1009 | 1014 |
| 1010 BOOL visible = [[tabStripView_ window] isVisible]; | 1015 BOOL visible = [[tabStripView_ window] isVisible]; |
| (...skipping 961 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1972 // the |TabStripView|'s coordinates). It considers only the x-coordinate of the | 1977 // the |TabStripView|'s coordinates). It considers only the x-coordinate of the |
| 1973 // given point. If it's in the "middle" of a tab, it drops on that tab. If it's | 1978 // given point. If it's in the "middle" of a tab, it drops on that tab. If it's |
| 1974 // to the left, it inserts to the left, and similarly for the right. | 1979 // to the left, it inserts to the left, and similarly for the right. |
| 1975 - (void)droppingURLsAt:(NSPoint)point | 1980 - (void)droppingURLsAt:(NSPoint)point |
| 1976 givesIndex:(NSInteger*)index | 1981 givesIndex:(NSInteger*)index |
| 1977 disposition:(WindowOpenDisposition*)disposition { | 1982 disposition:(WindowOpenDisposition*)disposition { |
| 1978 // Proportion of the tab which is considered the "middle" (and causes things | 1983 // Proportion of the tab which is considered the "middle" (and causes things |
| 1979 // to drop on that tab). | 1984 // to drop on that tab). |
| 1980 const double kMiddleProportion = 0.5; | 1985 const double kMiddleProportion = 0.5; |
| 1981 const double kLRProportion = (1.0 - kMiddleProportion) / 2.0; | 1986 const double kLRProportion = (1.0 - kMiddleProportion) / 2.0; |
| 1987 const CGFloat kTabOverlap = [TabStripController tabOverlap]; |
| 1982 | 1988 |
| 1983 DCHECK(index && disposition); | 1989 DCHECK(index && disposition); |
| 1984 NSInteger i = 0; | 1990 NSInteger i = 0; |
| 1985 for (TabController* tab in tabArray_.get()) { | 1991 for (TabController* tab in tabArray_.get()) { |
| 1986 NSView* view = [tab view]; | 1992 NSView* view = [tab view]; |
| 1987 DCHECK([view isKindOfClass:[TabView class]]); | 1993 DCHECK([view isKindOfClass:[TabView class]]); |
| 1988 | 1994 |
| 1989 // Recall that |-[NSView frame]| is in its superview's coordinates, so a | 1995 // Recall that |-[NSView frame]| is in its superview's coordinates, so a |
| 1990 // |TabView|'s frame is in the coordinates of the |TabStripView| (which | 1996 // |TabView|'s frame is in the coordinates of the |TabStripView| (which |
| 1991 // matches the coordinate system of |point|). | 1997 // matches the coordinate system of |point|). |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2093 | 2099 |
| 2094 [self openURL:&url inView:view at:point]; | 2100 [self openURL:&url inView:view at:point]; |
| 2095 } | 2101 } |
| 2096 | 2102 |
| 2097 // (URLDropTargetController protocol) | 2103 // (URLDropTargetController protocol) |
| 2098 - (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point { | 2104 - (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point { |
| 2099 DCHECK_EQ(view, tabStripView_.get()); | 2105 DCHECK_EQ(view, tabStripView_.get()); |
| 2100 | 2106 |
| 2101 // The minimum y-coordinate at which one should consider place the arrow. | 2107 // The minimum y-coordinate at which one should consider place the arrow. |
| 2102 const CGFloat arrowBaseY = 25; | 2108 const CGFloat arrowBaseY = 25; |
| 2109 const CGFloat kTabOverlap = [TabStripController tabOverlap]; |
| 2103 | 2110 |
| 2104 NSInteger index; | 2111 NSInteger index; |
| 2105 WindowOpenDisposition disposition; | 2112 WindowOpenDisposition disposition; |
| 2106 [self droppingURLsAt:point | 2113 [self droppingURLsAt:point |
| 2107 givesIndex:&index | 2114 givesIndex:&index |
| 2108 disposition:&disposition]; | 2115 disposition:&disposition]; |
| 2109 | 2116 |
| 2110 NSPoint arrowPos = NSMakePoint(0, arrowBaseY); | 2117 NSPoint arrowPos = NSMakePoint(0, arrowBaseY); |
| 2111 if (index == -1) { | 2118 if (index == -1) { |
| 2112 // Append a tab at the end. | 2119 // Append a tab at the end. |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2289 | 2296 |
| 2290 - (TabAlertState)alertStateForContents:(content::WebContents*)contents { | 2297 - (TabAlertState)alertStateForContents:(content::WebContents*)contents { |
| 2291 return chrome::GetTabAlertStateForContents(contents); | 2298 return chrome::GetTabAlertStateForContents(contents); |
| 2292 } | 2299 } |
| 2293 | 2300 |
| 2294 - (void)themeDidChangeNotification:(NSNotification*)notification { | 2301 - (void)themeDidChangeNotification:(NSNotification*)notification { |
| 2295 [newTabButton_ setImages]; | 2302 [newTabButton_ setImages]; |
| 2296 } | 2303 } |
| 2297 | 2304 |
| 2298 @end | 2305 @end |
| OLD | NEW |