summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-20 13:25:01 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-20 13:25:01 +0000
commit0ec608b1beb9bd76e649f640674642e99aa55e6f (patch)
tree247e77e8fce61da9b5b5bce977c37bf14a690252 /chrome/browser
parent2b110f43bd2a5253066ff7c7c4c5c81ecf2bc8ce (diff)
downloadchromium_src-0ec608b1beb9bd76e649f640674642e99aa55e6f.zip
chromium_src-0ec608b1beb9bd76e649f640674642e99aa55e6f.tar.gz
chromium_src-0ec608b1beb9bd76e649f640674642e99aa55e6f.tar.bz2
Rewrite tab layout to a centralized method rather than moving things around ad hoc in the insert and delete tab methods. Tabs now scale down in size (to a min size) rather than overflowing. Selected tab takes on normal size.
Review URL: http://codereview.chromium.org/42411 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12186 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.mm135
1 files changed, 74 insertions, 61 deletions
diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm
index ef8363e..a11279f 100644
--- a/chrome/browser/cocoa/tab_strip_controller.mm
+++ b/chrome/browser/cocoa/tab_strip_controller.mm
@@ -16,9 +16,6 @@
#import "chrome/browser/tab_contents/tab_contents.h"
#import "chrome/browser/tabs/tab_strip_model.h"
-// The amount of overlap tabs have in their button frames.
-const short kTabOverlap = 16;
-
// The private methods the brige object needs from the controller.
@interface TabStripController(BridgeMethods)
- (void)insertTabWithContents:(TabContents*)contents
@@ -126,14 +123,15 @@ class TabStripBridge : public TabStripModelObserver {
}
}
-// Create a new tab view and set its cell correctly so it draws the way we
-// want it to.
-- (TabController*)newTabWithFrame:(NSRect)frame {
+// Create a new tab view and set its cell correctly so it draws the way we want
+// it to. It will be sized and positioned by |-layoutTabs| so there's no need to
+// set the frame here. This also creates the view as hidden, it will be
+// shown during layout.
+- (TabController*)newTab {
TabController* controller = [[[TabController alloc] init] autorelease];
[controller setTarget:self];
[controller setAction:@selector(selectTab:)];
- TabView* view = [controller tabView];
- [view setFrame:frame];
+ [[controller view] setHidden:YES];
return controller;
}
@@ -172,30 +170,66 @@ class TabStripBridge : public TabStripModelObserver {
tabModel_->SelectTabContentsAt(index, true);
}
-// Return the frame for a new tab that will go to the immediate right of the
-// tab at |index|. If |index| is 0, this will be the first tab, indented so
-// as to not cover the window controls.
-- (NSRect)frameForNewTabAtIndex:(NSInteger)index {
- const short kIndentLeavingSpaceForControls = 66;
- const short kNewTabWidth = [TabController maxTabWidth];
-
- short xOffset = kIndentLeavingSpaceForControls;
- if (index > 0) {
- NSRect previousTab = [[self viewAtIndex:index - 1] frame];
- xOffset = NSMaxX(previousTab) - kTabOverlap;
- }
+// Lay out all tabs in the order of their TabContentsControllers, which matches
+// the ordering in the TabStripModel. This call isn't that expensive, though
+// it is O(n) in the number of tabs. Tabs will animate to their new position
+// if the window is visible.
+// TODO(pinkerton): Handle drag placeholders via proxy objects, perhaps a
+// subclass of TabContentsController with everything stubbed out or by
+// abstracting a base class interface.
+// TODO(pinkerton): Note this doesn't do too well when the number of min-sized
+// tabs would cause an overflow.
+- (void)layoutTabs {
+ const float kIndentLeavingSpaceForControls = 64.0;
+ const float kTabOverlap = 20.0;
+ const float kNewTabButtonOffset = 8.0;
+ const float kMaxTabWidth = [TabController maxTabWidth];
+ const float kMinTabWidth = [TabController minTabWidth];
+
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:0.2];
+
+ BOOL visible = [[tabView_ window] isVisible];
+ float availableWidth =
+ NSWidth([tabView_ frame]) - NSWidth([newTabButton_ frame]);
+ float offset = kIndentLeavingSpaceForControls;
+ const float baseTabWidth =
+ MAX(MIN((availableWidth - offset) / [tabContentsArray_ count],
+ kMaxTabWidth),
+ kMinTabWidth);
+
+ for (TabController* tab in tabArray_) {
+ // BOOL isPlaceholder = ![[[tab view] superview] isEqual:tabView_];
+ BOOL isPlaceholder = NO;
+ NSRect tabFrame = [[tab view] frame];
+ // If the tab is all the way on the left, we consider it a new tab. We
+ // need to show it, but not animate the movement. We do however want to
+ // animate the display.
+ BOOL newTab = NSMinX(tabFrame) == 0;
+ if (newTab) {
+ id visibilityTarget = visible ? [[tab view] animator] : [tab view];
+ [visibilityTarget setHidden:NO];
+ }
+ tabFrame.origin = NSMakePoint(offset, 0);
+ if (!isPlaceholder) {
+ // Set the tab's new frame and animate the tab to its new location. Don't
+ // animate if the window isn't visible or if the tab is new.
+ BOOL animate = visible && !newTab;
+ id frameTarget = animate ? [[tab view] animator] : [tab view];
+ tabFrame.size.width = [tab selected] ? kMaxTabWidth : baseTabWidth;
+ [frameTarget setFrame:tabFrame];
+ }
- return NSMakeRect(xOffset, 0, kNewTabWidth, [tabView_ frame].size.height);
-}
+ if (offset < availableWidth) {
+ offset += NSWidth(tabFrame);
+ offset -= kTabOverlap;
+ }
+ }
-// Positions the new tab button to the right of the last tab.
-- (void)positionNewTabButton {
- const NSInteger kNewTabXOffset = -12;
- NSRect lastTab = [[[tabArray_ lastObject] view] frame];
- NSInteger maxRightEdge = NSMaxX(lastTab);
- NSRect newTabButtonFrame = [newTabButton_ frame];
- newTabButtonFrame.origin.x = maxRightEdge + kNewTabXOffset;
- [newTabButton_ setFrame:newTabButtonFrame];
+ // Move the new tab button into place
+ [[newTabButton_ animator] setFrameOrigin:
+ NSMakePoint(MIN(availableWidth, offset + kNewTabButtonOffset), 0)];
+ [NSAnimationContext endGrouping];
}
// Handles setting the title of the tab based on the given |contents|. Uses
@@ -233,17 +267,14 @@ class TabStripBridge : public TabStripModelObserver {
[contentsController toggleBookmarkBar:YES];
[tabContentsArray_ insertObject:contentsController atIndex:index];
- // Make a new tab and add it to the strip. Keep track of its controller.
- // TODO(pinkerton): move everyone else over and animate. Also will need to
- // move the "add tab" button over.
- NSRect newTabFrame = [self frameForNewTabAtIndex:index];
- TabController* newController = [self newTabWithFrame:newTabFrame];
+ // Make a new tab and add it to the strip. Keep track of its controller. We
+ // don't call |-layoutTabs| here because it will get called when the new
+ // tab is selected by the tab model.
+ TabController* newController = [self newTab];
[tabArray_ insertObject:newController atIndex:index];
NSView* newView = [newController view];
[tabView_ addSubview:newView];
- [self positionNewTabButton];
-
[self setTabTitle:newController withContents:contents];
// Select the newly created tab if in the foreground
@@ -274,6 +305,10 @@ class TabStripBridge : public TabStripModelObserver {
[tabContentsArray_ objectAtIndex:index];
[newController willBecomeSelectedTab];
+ // Relayout for new tabs and to let the selected tab grow to be larger in
+ // size than surrounding tabs if the user has many.
+ [self layoutTabs];
+
// Swap in the contents for the new tab
[self swapInTabAtIndex:index];
}
@@ -291,34 +326,12 @@ class TabStripBridge : public TabStripModelObserver {
// Remove the |index|th view from the tab strip
NSView* tab = [self viewAtIndex:index];
- NSInteger tabWidth = [tab frame].size.width;
[tab removeFromSuperview];
- // Move all the views that are to the right of the tab being removed over
- // the width of the tab that was closed. Don't bother animating if there is
- // only 1 tab as everything is going away.
- if ([self numberOfTabViews] > 1) {
- int currIndex = 0;
- for (TabController* curr in tabArray_) {
- if (currIndex > index) {
- NSView* shiftingView = [curr view];
- NSRect newFrame = [shiftingView frame];
- newFrame.origin.x -= tabWidth - kTabOverlap;
- [[shiftingView animator] setFrame:newFrame];
- }
- ++currIndex;
- }
-
- // Move the new tab button. Note we can't just use the position of the
- // last tab because it will still be at the old location due to the delay
- // due to animation.
- NSRect newTabFrame = [newTabButton_ frame];
- newTabFrame.origin.x -= tabWidth - kTabOverlap;
- [[newTabButton_ animator] setFrame:newTabFrame];
- }
-
// Once we're totally done with the tab, delete its controller
[tabArray_ removeObjectAtIndex:index];
+
+ [self layoutTabs];
}
// Called when a notification is received from the model that the given tab