From f73bae9079d1d06b07eadaf86a2b4d7338fc78f9 Mon Sep 17 00:00:00 2001 From: "pinkerton@chromium.org" Date: Tue, 20 Oct 2009 17:40:24 +0000 Subject: Make dropped tabs animate from where they were dropped. Make room for the full width of the tab placeholder. Make tab dragging as smooth as glass. BUG=24982, 24983 TEST=tab dragging between windows, tab dragging w/in a window. Review URL: http://codereview.chromium.org/306006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29531 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/cocoa/browser_window_controller.mm | 17 +++++++++++-- chrome/browser/cocoa/tab_strip_controller.h | 6 ++++- chrome/browser/cocoa/tab_strip_controller.mm | 31 +++++++++++++++++------ 3 files changed, 43 insertions(+), 11 deletions(-) (limited to 'chrome') diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index d75b41e..1fa62b1 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -704,15 +704,28 @@ willPositionSheet:(NSWindow*)sheet if (!contents) return; + // Convert |view|'s frame (which starts in the source tab strip's coordinate + // system) to the coordinate system of the destination tab strip. This needs + // to be done before being detached so the window transforms can be + // performed. + NSRect destinationFrame = [view frame]; + NSPoint tabOrigin = destinationFrame.origin; + tabOrigin = [[dragController tabStripView] convertPoint:tabOrigin + toView:nil]; + tabOrigin = [[view window] convertBaseToScreen:tabOrigin]; + tabOrigin = [[self window] convertScreenToBase:tabOrigin]; + tabOrigin = [[self tabStripView] convertPoint:tabOrigin fromView:nil]; + destinationFrame.origin = tabOrigin; + // Now that we have enough information about the tab, we can remove it from // the dragging window. We need to do this *before* we add it to the new - // window as this will removes the TabContents' delegate. + // window as this will remove the TabContents' delegate. [dragController detachTabView:view]; // Deposit it into our model at the appropriate location (it already knows // where it should go from tracking the drag). Doing this sets the tab's // delegate to be the Browser. - [tabStripController_ dropTabContents:contents]; + [tabStripController_ dropTabContents:contents withFrame:destinationFrame]; } else { // Moving within a window. int index = [tabStripController_ indexForTabView:view]; diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h index db05b6c..521be75 100644 --- a/chrome/browser/cocoa/tab_strip_controller.h +++ b/chrome/browser/cocoa/tab_strip_controller.h @@ -58,6 +58,7 @@ class ToolbarModel; TabView* placeholderTab_; // weak. Tab being dragged NSRect placeholderFrame_; // Frame to use CGFloat placeholderStretchiness_; // Vertical force shown by streching tab. + NSRect droppedTabFrame_; // Initial frame of a dropped tab, for animation. // Frame targets for all the current views. // target frames are used because repeated requests to [NSView animator]. // aren't coalesced, so we store frames to avoid redundant calls. @@ -110,7 +111,10 @@ class ToolbarModel; // Drop a given TabContents at the location of the current placeholder. If there // is no placeholder, it will go at the end. Used when dragging from another // window when we don't have access to the TabContents as part of our strip. -- (void)dropTabContents:(TabContents*)contents; +// |frame| is in the coordinate system of the tab strip view and represents +// where the user dropped the new tab so it can be animated into its correct +// location when the tab is added to the model. +- (void)dropTabContents:(TabContents*)contents withFrame:(NSRect)frame; // Given a tab view in the strip, return its index. Returns -1 if not present. - (NSInteger)indexForTabView:(NSView*)view; diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm index 58eaec22..e37fabb 100644 --- a/chrome/browser/cocoa/tab_strip_controller.mm +++ b/chrome/browser/cocoa/tab_strip_controller.mm @@ -96,6 +96,8 @@ static const float kIndentLeavingSpaceForControls = 64.0; - (NSInteger)indexForContentsView:(NSView*)view; - (void)updateFavIconForContents:(TabContents*)contents atIndex:(NSInteger)index; +- (void)layoutTabsWithAnimation:(BOOL)animate + regenerateSubviews:(BOOL)doUpdate; @end @implementation TabStripController @@ -336,7 +338,7 @@ static const float kIndentLeavingSpaceForControls = 64.0; placeholderTab_ = tab; placeholderFrame_ = frame; placeholderStretchiness_ = yStretchiness; - [self layoutTabs]; + [self layoutTabsWithAnimation:YES regenerateSubviews:NO]; } - (BOOL)isTabFullyVisible:(TabView*)tab { @@ -408,7 +410,7 @@ static const float kIndentLeavingSpaceForControls = 64.0; float offset = kIndentLeavingSpaceForControls; NSUInteger i = 0; - NSInteger gap = -1; + bool hasPlaceholderGap = false; for (TabController* tab in tabArray_.get()) { BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_]; NSRect tabFrame = [[tab view] frame]; @@ -443,9 +445,9 @@ static const float kIndentLeavingSpaceForControls = 64.0; } else { // If our left edge is to the left of the placeholder's left, but our mid // is to the right of it we should slide over to make space for it. - if (placeholderTab_ && gap < 0 && NSMidX(tabFrame) > minX) { - gap = i; - offset += NSWidth(tabFrame); + if (placeholderTab_ && !hasPlaceholderGap && NSMidX(tabFrame) > minX) { + hasPlaceholderGap = true; + offset += NSWidth(placeholderFrame_); offset -= kTabOverlap; tabFrame.origin.x = offset; } @@ -456,9 +458,15 @@ static const float kIndentLeavingSpaceForControls = 64.0; [tab selected] ? MAX(baseTabWidth, kMinSelectedTabWidth) : baseTabWidth; - // Animate a new tab in by putting it below the horizon. + // Animate a new tab in by putting it below the horizon unless + // told to put it in a specific location (ie, from a drop). if (newTab && visible && animate) { - [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))]; + if (NSEqualRects(droppedTabFrame_, NSZeroRect)) { + [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))]; + } else { + [[tab view] setFrame:droppedTabFrame_]; + droppedTabFrame_ = NSZeroRect; + } } // Check the frame by identifier to avoid redundant calls to animator. @@ -858,9 +866,16 @@ static const float kIndentLeavingSpaceForControls = 64.0; // Drop a given TabContents at the location of the current placeholder. If there // is no placeholder, it will go at the end. Used when dragging from another // window when we don't have access to the TabContents as part of our strip. -- (void)dropTabContents:(TabContents*)contents { +// |frame| is in the coordinate system of the tab strip view and represents +// where the user dropped the new tab so it can be animated into its correct +// location when the tab is added to the model. +- (void)dropTabContents:(TabContents*)contents withFrame:(NSRect)frame { int index = [self indexOfPlaceholder]; + // Mark that the new tab being created should start at |frame|. It will be + // reset as soon as the tab has been positioned. + droppedTabFrame_ = frame; + // Insert it into this tab strip. We want it in the foreground and to not // inherit the current tab's group. tabModel_->InsertTabContentsAt(index, contents, true, false); -- cgit v1.1