diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-08 19:31:25 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-08 19:31:25 +0000 |
commit | 6dba9b3f1164f24271916ab1bd3bdc1b50727744 (patch) | |
tree | 9d932c93137ea00cc2b3b0b8a76669f6fd9b2baa | |
parent | 1a5b2c24261882d1daeae97ffb3b5c9242c880d7 (diff) | |
download | chromium_src-6dba9b3f1164f24271916ab1bd3bdc1b50727744.zip chromium_src-6dba9b3f1164f24271916ab1bd3bdc1b50727744.tar.gz chromium_src-6dba9b3f1164f24271916ab1bd3bdc1b50727744.tar.bz2 |
Converts dragged tab controller to only create the drag window when
detached. Otherwise the dragged tab remains in the tab strip, it's
just moved around. I also made it so the tab that originated the drag
can be deleted.
I'm doing this for a couple of reasons:
. make it easier to use dragged tab controller with side tabs.
. chromeos doesn't allow detaching, and only created the window when
we really need it makes for a better experience there.
. no flicker!
BUG=none
TEST=thoroughly test tab dragging to make sure I haven't broken
anything.
Review URL: http://codereview.chromium.org/1998009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46791 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/views/tabs/dragged_tab_controller.cc | 335 | ||||
-rw-r--r-- | chrome/browser/views/tabs/dragged_tab_controller.h | 68 | ||||
-rw-r--r-- | chrome/browser/views/tabs/dragged_tab_view.cc | 48 | ||||
-rw-r--r-- | chrome/browser/views/tabs/dragged_tab_view.h | 24 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab.cc | 3 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab.h | 7 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_dragging_test.cc | 5 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_strip.cc | 193 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_strip.h | 16 |
9 files changed, 302 insertions, 397 deletions
diff --git a/chrome/browser/views/tabs/dragged_tab_controller.cc b/chrome/browser/views/tabs/dragged_tab_controller.cc index de11308..61b6686 100644 --- a/chrome/browser/views/tabs/dragged_tab_controller.cc +++ b/chrome/browser/views/tabs/dragged_tab_controller.cc @@ -17,6 +17,7 @@ #include "chrome/browser/browser_window.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/views/frame/browser_view.h" #include "chrome/browser/views/tabs/dragged_tab_view.h" @@ -313,15 +314,17 @@ DraggedTabController::DraggedTabController(Tab* source_tab, TabStrip* source_tabstrip) : dragged_contents_(NULL), original_delegate_(NULL), - source_tab_(source_tab), source_tabstrip_(source_tabstrip), source_model_index_(source_tabstrip->GetModelIndexOfTab(source_tab)), - attached_tabstrip_(source_tabstrip), + attached_tabstrip_(NULL), + attached_tab_(NULL), + offset_to_width_ratio_(0), old_focused_view_(NULL), in_destructor_(false), last_move_screen_x_(0), mini_(source_tabstrip->model()->IsMiniTab(source_model_index_)), - pinned_(source_tabstrip->model()->IsTabPinned(source_model_index_)) { + pinned_(source_tabstrip->model()->IsTabPinned(source_model_index_)), + started_drag_(false) { SetDraggedContents( source_tabstrip_->model()->GetTabContentsAt(source_model_index_)); // Listen for Esc key presses. @@ -330,7 +333,6 @@ DraggedTabController::DraggedTabController(Tab* source_tab, DraggedTabController::~DraggedTabController() { in_destructor_ = true; - CleanUpSourceTab(); MessageLoopForUI::current()->RemoveObserver(this); // Need to delete the view here manually _before_ we reset the dragged // contents to NULL, otherwise if the view is animating to its destination @@ -340,7 +342,12 @@ DraggedTabController::~DraggedTabController() { SetDraggedContents(NULL); // This removes our observer. } -void DraggedTabController::CaptureDragInfo(const gfx::Point& mouse_offset) { +void DraggedTabController::CaptureDragInfo(Tab* tab, + const gfx::Point& mouse_offset) { + if (tab->width() > 0) { + offset_to_width_ratio_ = static_cast<float>(mouse_offset.x()) / + static_cast<float>(tab->width()); + } start_screen_point_ = GetCursorScreenPoint(); mouse_offset_ = mouse_offset; InitWindowCreatePoint(); @@ -351,28 +358,18 @@ void DraggedTabController::Drag() { // Before we get to dragging anywhere, ensure that we consider ourselves // attached to the source tabstrip. - if (source_tab_->IsVisible() && CanStartDrag()) - Attach(source_tabstrip_, gfx::Point()); - - if (!source_tab_->IsVisible()) { + if (!started_drag_ && CanStartDrag()) { + started_drag_ = true; SaveFocus(); - ContinueDragging(); + Attach(source_tabstrip_, gfx::Point()); } -} - -bool DraggedTabController::EndDrag(bool canceled) { - return EndDragImpl(canceled ? CANCELED : NORMAL); -} -Tab* DraggedTabController::GetDragSourceTabForContents( - TabContents* contents) const { - if (attached_tabstrip_ == source_tabstrip_) - return contents == dragged_contents_ ? source_tab_ : NULL; - return NULL; + if (started_drag_) + ContinueDragging(); } -bool DraggedTabController::IsDragSourceTab(Tab* tab) const { - return source_tab_ == tab; +void DraggedTabController::EndDrag(bool canceled) { + EndDragImpl(canceled ? CANCELED : NORMAL); } /////////////////////////////////////////////////////////////////////////////// @@ -584,8 +581,8 @@ void DraggedTabController::SetDraggedContents(TabContents* new_contents) { void DraggedTabController::SaveFocus() { if (!old_focused_view_) { - old_focused_view_ = source_tab_->GetRootView()->GetFocusedView(); - source_tab_->GetRootView()->FocusView(source_tab_); + old_focused_view_ = source_tabstrip_->GetRootView()->GetFocusedView(); + source_tabstrip_->GetRootView()->FocusView(source_tabstrip_); } } @@ -607,8 +604,6 @@ bool DraggedTabController::CanStartDrag() const { } void DraggedTabController::ContinueDragging() { - EnsureDraggedView(); - // Note that the coordinates given to us by |drag_event| are basically // useless, since they're in source_tab_ coordinates. On the surface, you'd // think we could just convert them to screen coordinates, however in the @@ -621,7 +616,6 @@ void DraggedTabController::ContinueDragging() { // guaranteed to be correct regardless of monitor config. gfx::Point screen_point = GetCursorScreenPoint(); - // TODO(sky): make this define OS_CHROMEOS when we merge views and chromeos. #if defined(OS_CHROMEOS) // We don't allow detaching in chrome os. TabStrip* target_tabstrip = source_tabstrip_; @@ -647,39 +641,59 @@ void DraggedTabController::ContinueDragging() { UpdateDockInfo(screen_point); - MoveTab(screen_point); + if (attached_tabstrip_) + MoveAttachedTab(screen_point); + else + MoveDetachedTab(screen_point); } -void DraggedTabController::MoveTab(const gfx::Point& screen_point) { - gfx::Point dragged_view_point = GetDraggedViewPoint(screen_point); +void DraggedTabController::MoveAttachedTab(const gfx::Point& screen_point) { + DCHECK(attached_tabstrip_); + DCHECK(!view_.get()); - if (attached_tabstrip_) { - TabStripModel* attached_model = attached_tabstrip_->model(); - int from_index = attached_model->GetIndexOfTabContents(dragged_contents_); - - // Determine the horizontal move threshold. This is dependent on the width - // of tabs. The smaller the tabs compared to the standard size, the smaller - // the threshold. - double unselected, selected; - attached_tabstrip_->GetCurrentTabWidths(&unselected, &selected); - double ratio = unselected / Tab::GetStandardSize().width(); - int threshold = static_cast<int>(ratio * kHorizontalMoveThreshold); - - // Update the model, moving the TabContents from one index to another. Do - // this only if we have moved a minimum distance since the last reorder (to - // prevent jitter). - if (abs(screen_point.x() - last_move_screen_x_) > threshold) { - gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point); - int to_index = GetInsertionIndexForDraggedBounds(bounds, true); - to_index = NormalizeIndexToAttachedTabStrip(to_index); - if (from_index != to_index) { - last_move_screen_x_ = screen_point.x(); - attached_model->MoveTabContentsAt(from_index, to_index, true); - } + gfx::Point dragged_view_point = GetAttachedTabDragPoint(screen_point); + + TabStripModel* attached_model = attached_tabstrip_->model(); + int from_index = attached_model->GetIndexOfTabContents(dragged_contents_); + + // Determine the horizontal move threshold. This is dependent on the width + // of tabs. The smaller the tabs compared to the standard size, the smaller + // the threshold. + double unselected, selected; + attached_tabstrip_->GetCurrentTabWidths(&unselected, &selected); + double ratio = unselected / Tab::GetStandardSize().width(); + int threshold = static_cast<int>(ratio * kHorizontalMoveThreshold); + + // Update the model, moving the TabContents from one index to another. Do this + // only if we have moved a minimum distance since the last reorder (to prevent + // jitter). + if (abs(screen_point.x() - last_move_screen_x_) > threshold) { + gfx::Point dragged_view_screen_point(dragged_view_point); + views::View::ConvertPointToScreen(attached_tabstrip_, + &dragged_view_screen_point); + gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_screen_point); + int to_index = GetInsertionIndexForDraggedBounds(bounds, true); + to_index = NormalizeIndexToAttachedTabStrip(to_index); + if (from_index != to_index) { + last_move_screen_x_ = screen_point.x(); + attached_model->MoveTabContentsAt(from_index, to_index, true); } } + attached_tab_->SchedulePaint(); + attached_tab_->SetX(dragged_view_point.x()); + attached_tab_->SetY(dragged_view_point.y()); + attached_tab_->SchedulePaint(); +} + +void DraggedTabController::MoveDetachedTab(const gfx::Point& screen_point) { + DCHECK(!attached_tabstrip_); + DCHECK(view_.get()); + + int x = screen_point.x() - mouse_offset_.x(); + int y = screen_point.y() - mouse_offset_.y(); + // Move the View. There are no changes to the model if we're detached. - view_->MoveTo(dragged_view_point); + view_->MoveTo(gfx::Point(x, y)); } DockInfo DraggedTabController::GetDockInfoAtPoint( @@ -705,11 +719,15 @@ DockInfo DraggedTabController::GetDockInfoAtPoint( TabStrip* DraggedTabController::GetTabStripForPoint( const gfx::Point& screen_point) { - gfx::NativeView dragged_view = view_->GetWidget()->GetNativeView(); - dock_windows_.insert(dragged_view); + gfx::NativeView dragged_view = NULL; + if (view_.get()) { + dragged_view = view_->GetWidget()->GetNativeView(); + dock_windows_.insert(dragged_view); + } gfx::NativeWindow local_window = DockInfo::GetLocalProcessWindowAtPoint(screen_point, dock_windows_); - dock_windows_.erase(dragged_view); + if (dragged_view) + dock_windows_.erase(dragged_view); if (!local_window) return NULL; BrowserView* browser = @@ -747,35 +765,19 @@ TabStrip* DraggedTabController::GetTabStripIfItContains( void DraggedTabController::Attach(TabStrip* attached_tabstrip, const gfx::Point& screen_point) { + DCHECK(!attached_tabstrip_); // We should already have detached by the time + // we get here. + DCHECK(!attached_tab_); // Similarly there should be no attached tab. + attached_tabstrip_ = attached_tabstrip; - attached_tabstrip_->GenerateIdealBounds(); // We don't need the photo-booth while we're attached. photobooth_.reset(NULL); - Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_); + // And we don't need the dragged view. + view_.reset(); - // Update the View first, so we can ask it for its bounds and determine - // where to insert the hidden Tab. - - // If this is the first time Attach is called for this drag, we're attaching - // to the source TabStrip, and we should assume the tab count already - // includes this Tab since we haven't been detached yet. If we don't do this, - // the dragged representation will be a different size to others in the - // TabStrip. - int tab_count = attached_tabstrip_->GetTabCount(); - int mini_tab_count = attached_tabstrip_->GetMiniTabCount(); - int nano_tab_count = attached_tabstrip_->GetNanoTabCount(); - if (!tab) - ++tab_count; - double unselected_width, selected_width = 0; - attached_tabstrip_->GetDesiredTabWidths(tab_count, mini_tab_count, - nano_tab_count, &unselected_width, - &selected_width); - EnsureDraggedView(); - int dragged_tab_width = - mini_ ? Tab::GetMiniWidth() : static_cast<int>(selected_width); - view_->Attach(dragged_tab_width); + Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_); if (!tab) { // There is no Tab in |attached_tabstrip| that corresponds to the dragged @@ -789,12 +791,6 @@ void DraggedTabController::Attach(TabStrip* attached_tabstrip, // Return the TabContents' to normalcy. dragged_contents_->set_capturing_contents(false); - // We need to ask the TabStrip we're attached to to ensure that the ideal - // bounds for all its tabs are correctly generated, because the calculation - // in GetInsertionIndexForDraggedBounds needs them to be to figure out the - // appropriate insertion index. - attached_tabstrip_->GenerateIdealBounds(); - // Inserting counts as a move. We don't want the tabs to jitter when the // user moves the tab immediately after attaching it. last_move_screen_x_ = screen_point.x(); @@ -805,13 +801,22 @@ void DraggedTabController::Attach(TabStrip* attached_tabstrip, // changing due to animation). gfx::Rect bounds = GetDraggedViewTabStripBounds(screen_point); int index = GetInsertionIndexForDraggedBounds(bounds, false); + attached_tabstrip_->set_attaching_dragged_tab(true); attached_tabstrip_->model()->InsertTabContentsAt(index, dragged_contents_, true, false, pinned_); + attached_tabstrip_->set_attaching_dragged_tab(false); tab = GetTabMatchingDraggedContents(attached_tabstrip_); } DCHECK(tab); // We should now have a tab. - tab->SetVisible(false); + attached_tab_ = tab; + attached_tabstrip_->StartedDraggingTab(tab); + + // TODO(sky): this needs to adjust based on orientation of the tab strip. + // The size of the dragged tab may have changed. Adjust the x offset so that + // ratio of mouse_offset_ to original width is maintained. + mouse_offset_.set_x(static_cast<int>(offset_to_width_ratio_ * + static_cast<int>(tab->width()))); // Move the corresponding window to the front. attached_tabstrip_->GetWindow()->Activate(); @@ -825,13 +830,8 @@ void DraggedTabController::Detach() { // Update the Model. TabStripModel* attached_model = attached_tabstrip_->model(); int index = attached_model->GetIndexOfTabContents(dragged_contents_); - if (index >= 0 && index < attached_model->count()) { - // Sometimes, DetachTabContentsAt has consequences that result in - // attached_tabstrip_ being set to NULL, so we need to save it first. - TabStrip* attached_tabstrip = attached_tabstrip_; - attached_model->DetachTabContentsAt(index); - attached_tabstrip->SchedulePaint(); - } + DCHECK(index != -1); + attached_model->DetachTabContentsAt(index); // If we've removed the last Tab from the TabStrip, hide the frame now. if (!attached_model->HasNonPhantomTabs()) @@ -844,21 +844,22 @@ void DraggedTabController::Detach() { NativeViewPhotobooth::Create(dragged_contents_->GetNativeView())); } - // Update the View. This NULL check is necessary apparently in some - // conditions during automation where the view_ is destroyed inside a - // function call preceding this point but after it is created. - if (view_.get()) - view_->Detach(photobooth_.get()); + // Create the dragged view. + EnsureDraggedView(); + view_->Attach(attached_tab_->width()); + view_->Detach(photobooth_.get()); // Detaching resets the delegate, but we still want to be the delegate. dragged_contents_->set_delegate(this); attached_tabstrip_ = NULL; + attached_tab_ = NULL; } int DraggedTabController::GetInsertionIndexForDraggedBounds( const gfx::Rect& dragged_bounds, bool is_tab_attached) const { + // TODO(sky): this needs to adjust based on orientation of the tab strip. int right_tab_x = 0; // If the UI layout of the tab strip is right-to-left, we need to mirror the @@ -912,57 +913,41 @@ gfx::Rect DraggedTabController::GetDraggedViewTabStripBounds( const gfx::Point& screen_point) { gfx::Point client_point = ConvertScreenPointToTabStripPoint(attached_tabstrip_, screen_point); - gfx::Size view_size = view_->attached_tab_size(); + if (attached_tab_) { + return gfx::Rect(client_point.x(), client_point.y(), + attached_tab_->width(), attached_tab_->height()); + } + // attached_tab_ is NULL when inserting into a new tabstrip. + double sel_width, unselected_width; + attached_tabstrip_->GetCurrentTabWidths(&sel_width, &unselected_width); + // TODO(sky): this needs to adjust based on orientation of the tab strip. return gfx::Rect(client_point.x(), client_point.y(), - view_size.width(), view_size.height()); + static_cast<int>(sel_width), + Tab::GetStandardSize().height()); } -gfx::Point DraggedTabController::GetDraggedViewPoint( +gfx::Point DraggedTabController::GetAttachedTabDragPoint( const gfx::Point& screen_point) { + DCHECK(attached_tabstrip_); // The tab must be attached. + int x = screen_point.x() - mouse_offset_.x(); int y = screen_point.y() - mouse_offset_.y(); - // If we're not attached, we just use x and y from above. - if (attached_tabstrip_) { - gfx::Rect tabstrip_bounds = GetViewScreenBounds(attached_tabstrip_); - - // Snap the dragged Tab to the TabStrip if we are attached, detaching - // only when the mouse position (screen_point) exceeds the screen bounds - // of the TabStrip. - if (x < tabstrip_bounds.x() && screen_point.x() >= tabstrip_bounds.x()) - x = tabstrip_bounds.x(); - - gfx::Size tab_size = view_->attached_tab_size(); - int vertical_drag_magnetism = tab_size.height() * 2; - int vertical_detach_point = tabstrip_bounds.y() - vertical_drag_magnetism; - if (y < tabstrip_bounds.y() && screen_point.y() >= vertical_detach_point) - y = tabstrip_bounds.y(); - - // Make sure the Tab can't be dragged off the right side of the TabStrip - // unless the mouse pointer passes outside the bounds of the strip by - // clamping the position of the dragged window to the tabstrip width less - // the width of one tab until the mouse pointer (screen_point) exceeds the - // screen bounds of the TabStrip. - int max_x = tabstrip_bounds.right() - tab_size.width(); - int max_y = tabstrip_bounds.bottom() - tab_size.height(); - if (x > max_x && screen_point.x() <= tabstrip_bounds.right()) - x = max_x; - if (y > max_y && screen_point.y() <= - (tabstrip_bounds.bottom() + vertical_drag_magnetism)) { - y = max_y; - } + gfx::Point tab_loc(x, y); + views::View::ConvertPointToView(NULL, attached_tabstrip_, &tab_loc); -#if defined(OS_LINUX) - // We currently don't allow detaching on chromeos. This restricts dragging - // to the main window. - x = std::min(std::max(x, tabstrip_bounds.x()), max_x); - y = tabstrip_bounds.y(); -#endif - } + x = tab_loc.x(); + y = tab_loc.y(); + + const gfx::Size& tab_size = attached_tab_->bounds().size(); + + int max_x = attached_tabstrip_->bounds().right() - tab_size.width(); + // TODO(sky): this needs to adjust based on orientation of the tab strip. + x = std::min(std::max(x, 0), max_x); + y = 0; return gfx::Point(x, y); } - Tab* DraggedTabController::GetTabMatchingDraggedContents( TabStrip* tabstrip) const { int model_index = tabstrip->model()->GetIndexOfTabContents(dragged_contents_); @@ -970,7 +955,7 @@ Tab* DraggedTabController::GetTabMatchingDraggedContents( NULL : tabstrip->GetTabAtModelIndex(model_index); } -bool DraggedTabController::EndDragImpl(EndDragType type) { +void DraggedTabController::EndDragImpl(EndDragType type) { // WARNING: this may be invoked multiple times. In particular, if deletion // occurs after a delay (as it does when the tab is released in the original // tab strip) and the navigation controller/tab contents is deleted before @@ -989,18 +974,16 @@ bool DraggedTabController::EndDragImpl(EndDragType type) { dock_controllers_.clear(); dock_windows_.clear(); - bool destroy_now = true; if (type != TAB_DESTROYED) { - // We only finish up the drag if we were actually dragging. If we never - // constructed a view, the user just clicked and released and didn't move - // the mouse enough to trigger a drag. - if (view_.get()) { + // We only finish up the drag if we were actually dragging. If start_drag_ + // is false, the user just clicked and released and didn't move the mouse + // enough to trigger a drag. + if (started_drag_) { RestoreFocus(); - if (type == CANCELED) { + if (type == CANCELED) RevertDrag(); - } else { - destroy_now = CompleteDrag(); - } + else + CompleteDrag(); } if (dragged_contents_ && dragged_contents_->delegate() == this) dragged_contents_->set_delegate(original_delegate_); @@ -1019,14 +1002,12 @@ bool DraggedTabController::EndDragImpl(EndDragType type) { DCHECK(!dragged_contents_ || dragged_contents_->delegate() != this); original_delegate_ = NULL; - // If we're not destroyed now, we'll be destroyed asynchronously later. - if (destroy_now) - source_tabstrip_->DestroyDragController(); - - return destroy_now; + source_tabstrip_->DestroyDragController(); } void DraggedTabController::RevertDrag() { + DCHECK(started_drag_); + // We save this here because code below will modify |attached_tabstrip_|. bool restore_frame = attached_tabstrip_ != source_tabstrip_; if (attached_tabstrip_) { @@ -1044,6 +1025,7 @@ void DraggedTabController::RevertDrag() { } else { // The Tab was moved within the TabStrip where the drag was initiated. // Move it back to the starting location. + source_tabstrip_->StoppedDraggingTab(attached_tab_); source_tabstrip_->model()->MoveTabContentsAt(index, source_model_index_, true); } @@ -1072,19 +1054,13 @@ void DraggedTabController::RevertDrag() { #endif } } - source_tab_->SetVisible(true); } -bool DraggedTabController::CompleteDrag() { - bool destroy_immediately = true; +void DraggedTabController::CompleteDrag() { + DCHECK(started_drag_); + if (attached_tabstrip_) { - // We don't need to do anything other than make the Tab visible again, - // since the dragged View is going away. - Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_); - view_->AnimateToBounds( - GetViewScreenBounds(tab), - NewCallback(this, &DraggedTabController::OnAnimateToBoundsComplete)); - destroy_immediately = false; + attached_tabstrip_->StoppedDraggingTab(attached_tab_); } else { if (dock_info_.type() != DockInfo::NONE) { switch (dock_info_.type()) { @@ -1156,10 +1132,9 @@ bool DraggedTabController::CompleteDrag() { new_model->SetTabPinned(new_model->GetIndexOfTabContents(dragged_contents_), pinned_); new_browser->window()->Show(); - CleanUpHiddenFrame(); } - return destroy_immediately; + CleanUpHiddenFrame(); } void DraggedTabController::EnsureDraggedView() { @@ -1230,34 +1205,6 @@ void DraggedTabController::CleanUpHiddenFrame() { source_tabstrip_->model()->delegate()->CloseFrameAfterDragSession(); } -void DraggedTabController::CleanUpSourceTab() { - // If we were attached to the source TabStrip, source Tab will be in use - // as the Tab. If we were detached or attached to another TabStrip, we can - // safely remove this item and delete it now. - if (attached_tabstrip_ != source_tabstrip_) { - source_tabstrip_->DestroyDraggedSourceTab(source_tab_); - source_tab_ = NULL; - } -} - -void DraggedTabController::OnAnimateToBoundsComplete() { - // Sometimes, for some reason, in automation we can be called back on a - // detach even though we aren't attached to a TabStrip. Guard against that. - if (attached_tabstrip_) { - Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_); - if (tab) { - tab->SetVisible(true); - // Paint the tab now, otherwise there may be slight flicker between the - // time the dragged tab window is destroyed and we paint. - tab->PaintNow(); - } - } - CleanUpHiddenFrame(); - - if (!in_destructor_) - source_tabstrip_->DestroyDragController(); -} - void DraggedTabController::DockDisplayerDestroyed( DockDisplayer* controller) { DockWindows::iterator dock_i = diff --git a/chrome/browser/views/tabs/dragged_tab_controller.h b/chrome/browser/views/tabs/dragged_tab_controller.h index 758b076..4e68605 100644 --- a/chrome/browser/views/tabs/dragged_tab_controller.h +++ b/chrome/browser/views/tabs/dragged_tab_controller.h @@ -9,22 +9,16 @@ #include "base/timer.h" #include "chrome/browser/dock_info.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/browser/views/tabs/tab_renderer.h" #include "chrome/common/notification_registrar.h" #include "gfx/rect.h" namespace views { -class MouseEvent; class View; } -class BrowserWindow; class DraggedTabView; class NativeViewPhotobooth; -class SkBitmap; class Tab; class TabStrip; -class TabStripModel; /////////////////////////////////////////////////////////////////////////////// // @@ -47,7 +41,7 @@ class DraggedTabController : public TabContentsDelegate, // Capture information needed to be used during a drag session for this // controller's associated source Tab and TabStrip. |mouse_offset| is the // distance of the mouse pointer from the Tab's origin. - void CaptureDragInfo(const gfx::Point& mouse_offset); + void CaptureDragInfo(Tab* tab, const gfx::Point& mouse_offset); // Responds to drag events subsequent to StartDrag. If the mouse moves a // sufficient distance before the mouse is released, a drag session is @@ -57,23 +51,20 @@ class DraggedTabController : public TabContentsDelegate, // Complete the current drag session. If the drag session was canceled // because the user pressed Escape or something interrupted it, |canceled| // is true so the helper can revert the state to the world before the drag - // begun. Returns whether the tab has been destroyed. - bool EndDrag(bool canceled); - - // Retrieve the source Tab if the TabContents specified matches the one being - // dragged by this controller, or NULL if the specified TabContents is not - // the same as the one being dragged. - Tab* GetDragSourceTabForContents(TabContents* contents) const; - - // Returns true if the specified Tab matches the Tab being dragged. - bool IsDragSourceTab(Tab* tab) const; + // begun. + void EndDrag(bool canceled); TabContents* dragged_contents() { return dragged_contents_; } + // Returns true if a drag started. + bool started_drag() const { return started_drag_; } + private: class DockDisplayer; friend class DockDisplayer; + typedef std::set<gfx::NativeView> DockWindows; + // Enumeration of the ways a drag session can end. enum EndDragType { // Drag session exited normally: the user released the mouse. @@ -155,8 +146,11 @@ class DraggedTabController : public TabContentsDelegate, // potentially updating the source and other TabStrips. void ContinueDragging(); - // Handles moving the Tab within a TabStrip as well as updating the View. - void MoveTab(const gfx::Point& screen_point); + // Handles dragging a tab while the tab is attached. + void MoveAttachedTab(const gfx::Point& screen_point); + + // Handles dragging while the tab is detached. + void MoveDetachedTab(const gfx::Point& screen_point); // Returns the compatible TabStrip that is under the specified point (screen // coordinates), or NULL if there is none. @@ -188,22 +182,21 @@ class DraggedTabController : public TabContentsDelegate, // Get the position of the dragged tab view relative to the attached tab // strip. - gfx::Point GetDraggedViewPoint(const gfx::Point& screen_point); + gfx::Point GetAttachedTabDragPoint(const gfx::Point& screen_point); // Finds the Tab within the specified TabStrip that corresponds to the // dragged TabContents. Tab* GetTabMatchingDraggedContents(TabStrip* tabstrip) const; - // Does the work for EndDrag. Returns whether the tab has been destroyed. - bool EndDragImpl(EndDragType how_end); + // Does the work for EndDrag. If we actually started a drag and |how_end| is + // not TAB_DESTROYED then one of EndDrag or RevertDrag is invoked. + void EndDragImpl(EndDragType how_end); - // If the drag was aborted for some reason, this function is called to un-do - // the changes made during the drag operation. + // Reverts a cancelled drag operation. void RevertDrag(); - // Finishes the drag operation. Returns true if the drag controller should - // be destroyed immediately, false otherwise. - bool CompleteDrag(); + // Finishes a succesful drag operation. + void CompleteDrag(); // Create the DraggedTabView, if it does not yet exist. void EnsureDraggedView(); @@ -225,13 +218,6 @@ class DraggedTabController : public TabContentsDelegate, // Closes a hidden frame at the end of a drag session. void CleanUpHiddenFrame(); - // Cleans up a source tab that is no longer used. - void CleanUpSourceTab(); - - // Completes the drag session after the view has animated to its final - // position. - void OnAnimateToBoundsComplete(); - void DockDisplayerDestroyed(DockDisplayer* controller); void BringWindowUnderMouseToFront(); @@ -247,9 +233,6 @@ class DraggedTabController : public TabContentsDelegate, // certain delegate notifications back to it if we can't handle them locally. TabContentsDelegate* original_delegate_; - // The Tab that initiated the drag session. - Tab* source_tab_; - // The TabStrip |source_tab_| originated from. TabStrip* source_tabstrip_; @@ -261,6 +244,9 @@ class DraggedTabController : public TabContentsDelegate, // dragged Tab is detached. TabStrip* attached_tabstrip_; + // If attached this is the tab we're dragging. + Tab* attached_tab_; + // The visual representation of the dragged Tab. scoped_ptr<DraggedTabView> view_; @@ -279,6 +265,9 @@ class DraggedTabController : public TabContentsDelegate, // detached window is created at the right location. gfx::Point mouse_offset_; + // Ratio of the x-coordinate of the mouse offset to the width of the tab. + float offset_to_width_ratio_; + // A hint to use when positioning new windows created by detaching Tabs. This // is the distance of the mouse from the top left of the dragged tab as if it // were the distance of the mouse from the top left of the first tab in the @@ -309,8 +298,8 @@ class DraggedTabController : public TabContentsDelegate, DockInfo dock_info_; - typedef std::set<gfx::NativeView> DockWindows; DockWindows dock_windows_; + std::vector<DockDisplayer*> dock_controllers_; // Is the tab mini? @@ -324,6 +313,9 @@ class DraggedTabController : public TabContentsDelegate, // brought to front. base::OneShotTimer<DraggedTabController> bring_to_front_timer_; + // Did the mouse move enough that we started a drag? + bool started_drag_; + DISALLOW_COPY_AND_ASSIGN(DraggedTabController); }; diff --git a/chrome/browser/views/tabs/dragged_tab_view.cc b/chrome/browser/views/tabs/dragged_tab_view.cc index b2da323..aab8a0f 100644 --- a/chrome/browser/views/tabs/dragged_tab_view.cc +++ b/chrome/browser/views/tabs/dragged_tab_view.cc @@ -20,7 +20,6 @@ static const int kOpaqueAlpha = 255; static const int kDragFrameBorderSize = 2; static const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize; static const float kScalingFactor = 0.5; -static const int kAnimateToBoundsDurationMs = 150; static const SkColor kDraggedTabBorderColor = SkColorSetRGB(103, 129, 162); //////////////////////////////////////////////////////////////////////////////// @@ -36,8 +35,7 @@ DraggedTabView::DraggedTabView(views::View* renderer, mouse_tab_offset_(mouse_tab_offset), attached_tab_size_(min_size), photobooth_(NULL), - contents_size_(contents_size), - close_animation_(this) { + contents_size_(contents_size) { set_parent_owned(false); #if defined(OS_WIN) @@ -65,8 +63,6 @@ DraggedTabView::DraggedTabView(views::View* renderer, } DraggedTabView::~DraggedTabView() { - if (close_animation_.is_animating()) - close_animation_.Stop(); GetParent()->RemoveChildView(this); container_->CloseNow(); } @@ -138,48 +134,6 @@ void DraggedTabView::Update() { #endif } -void DraggedTabView::AnimateToBounds(const gfx::Rect& bounds, - Callback0::Type* callback) { - animation_callback_.reset(callback); - - gfx::Rect initial_bounds; - GetWidget()->GetBounds(&initial_bounds, true); - animation_start_bounds_ = initial_bounds; - animation_end_bounds_ = bounds; - - close_animation_.SetSlideDuration(kAnimateToBoundsDurationMs); - close_animation_.SetTweenType(Tween::EASE_OUT); - if (!close_animation_.IsShowing()) { - close_animation_.Reset(); - close_animation_.Show(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// DraggedTabView, AnimationDelegate implementation: - -void DraggedTabView::AnimationProgressed(const Animation* animation) { - int delta_x = (animation_end_bounds_.x() - animation_start_bounds_.x()); - int x = animation_start_bounds_.x() + - static_cast<int>(delta_x * animation->GetCurrentValue()); - int y = animation_end_bounds_.y(); -#if defined(OS_WIN) - container_->SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); -#else - gfx::Rect bounds; - container_->GetBounds(&bounds, true); - container_->SetBounds(gfx::Rect(x, y, bounds.width(), bounds.height())); -#endif -} - -void DraggedTabView::AnimationEnded(const Animation* animation) { - animation_callback_->Run(); -} - -void DraggedTabView::AnimationCanceled(const Animation* animation) { - AnimationEnded(animation); -} - /////////////////////////////////////////////////////////////////////////////// // DraggedTabView, views::View overrides: diff --git a/chrome/browser/views/tabs/dragged_tab_view.h b/chrome/browser/views/tabs/dragged_tab_view.h index 02279d5..cda1daa 100644 --- a/chrome/browser/views/tabs/dragged_tab_view.h +++ b/chrome/browser/views/tabs/dragged_tab_view.h @@ -5,8 +5,6 @@ #ifndef CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_VIEW_H_ #define CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_VIEW_H_ -#include "app/slide_animation.h" -#include "base/callback.h" #include "build/build_config.h" #include "gfx/point.h" #include "gfx/size.h" @@ -26,8 +24,7 @@ class NativeViewPhotobooth; class Tab; class TabRenderer; -class DraggedTabView : public views::View, - public AnimationDelegate { +class DraggedTabView : public views::View { public: // Creates a new DraggedTabView using |renderer| as the View. DraggedTabView // takes ownership of |renderer|. @@ -58,20 +55,11 @@ class DraggedTabView : public views::View, // Notifies the DraggedTabView that it should update itself. void Update(); - // Animates the DraggedTabView to the specified bounds, then calls back to - // |callback|. - void AnimateToBounds(const gfx::Rect& bounds, Callback0::Type* callback); - // Returns the size of the DraggedTabView. Used when attaching to a TabStrip // to determine where to place the Tab in the attached TabStrip. const gfx::Size& attached_tab_size() const { return attached_tab_size_; } private: - // Overridden from AnimationDelegate: - virtual void AnimationProgressed(const Animation* animation); - virtual void AnimationEnded(const Animation* animation); - virtual void AnimationCanceled(const Animation* animation); - // Overridden from views::View: virtual void Paint(gfx::Canvas* canvas); virtual void Layout(); @@ -126,16 +114,6 @@ class DraggedTabView : public views::View, // Size of the TabContents being dragged. gfx::Size contents_size_; - // The animation used to slide the attached view to its final location. - SlideAnimation close_animation_; - - // A callback notified when the animation is complete. - scoped_ptr<Callback0::Type> animation_callback_; - - // The start and end bounds of the animation sequence. - gfx::Rect animation_start_bounds_; - gfx::Rect animation_end_bounds_; - DISALLOW_COPY_AND_ASSIGN(DraggedTabView); }; diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc index 4f3989c..03487a9 100644 --- a/chrome/browser/views/tabs/tab.cc +++ b/chrome/browser/views/tabs/tab.cc @@ -107,7 +107,8 @@ class Tab::TabContextMenuContents : public menus::SimpleMenuModel::Delegate { Tab::Tab(TabDelegate* delegate) : TabRenderer(), delegate_(delegate), - closing_(false) { + closing_(false), + dragging_(false) { close_button()->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_CLOSE_TAB)); close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE)); close_button()->SetAnimationDuration(0); diff --git a/chrome/browser/views/tabs/tab.h b/chrome/browser/views/tabs/tab.h index 2276239..af7eb20 100644 --- a/chrome/browser/views/tabs/tab.h +++ b/chrome/browser/views/tabs/tab.h @@ -90,6 +90,10 @@ class Tab : public TabRenderer, void set_closing(bool closing) { closing_ = closing; } bool closing() const { return closing_; } + // See description above field. + void set_dragging(bool dragging) { dragging_ = dragging; } + bool dragging() const { return dragging_; } + // TabRenderer overrides: virtual bool IsSelected() const; @@ -125,6 +129,9 @@ class Tab : public TabRenderer, // True if the tab is being animated closed. bool closing_; + // True if the tab is being dragged. + bool dragging_; + // If non-null it means we're showing a menu for the tab. class TabContextMenuContents; scoped_ptr<TabContextMenuContents> context_menu_contents_; diff --git a/chrome/browser/views/tabs/tab_dragging_test.cc b/chrome/browser/views/tabs/tab_dragging_test.cc index aff4f16..4a57a53 100644 --- a/chrome/browser/views/tabs/tab_dragging_test.cc +++ b/chrome/browser/views/tabs/tab_dragging_test.cc @@ -19,7 +19,8 @@ #include "views/event.h" #if defined(OS_CHROMEOS) -// Disabled, see http://crbug.com/40043. +// This test doesn't make sense on chromeos as chromeos doesn't allow dragging +// tabs out. #define MAYBE_Tab2OutOfTabStrip DISABLED_Tab2OutOfTabStrip #else #define MAYBE_Tab2OutOfTabStrip Tab2OutOfTabStrip @@ -270,7 +271,7 @@ TEST_F(TabDraggingTest, MAYBE_Tab1Tab3Escape) { ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); // Add Tab_2. - GURL tab2_url("about:"); + GURL tab2_url("about:blank"); ASSERT_TRUE(browser->AppendTab(tab2_url)); scoped_refptr<TabProxy> tab2(browser->GetTab(1)); ASSERT_TRUE(tab2.get()); diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index c58f15a..f88aaa4 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -36,6 +36,7 @@ #include "views/controls/image_view.h" #include "views/painter.h" #include "views/widget/default_theme_provider.h" +#include "views/widget/root_view.h" #include "views/window/non_client_view.h" #include "views/window/window.h" @@ -116,6 +117,28 @@ class NewTabAlphaDelegate DISALLOW_COPY_AND_ASSIGN(NewTabAlphaDelegate); }; +// Animation delegate used when a dragged tab is released. When done sets the +// dragging state to false. +class ResetDraggingStateDelegate + : public views::BoundsAnimator::OwnedAnimationDelegate { + public: + explicit ResetDraggingStateDelegate(Tab* tab) : tab_(tab) { + } + + virtual void AnimationEnded(const Animation* animation) { + tab_->set_dragging(false); + } + + virtual void AnimationCanceled(const Animation* animation) { + tab_->set_dragging(false); + } + + private: + Tab* tab_; + + DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate); +}; + /////////////////////////////////////////////////////////////////////////////// // NewTabButton // @@ -256,7 +279,8 @@ TabStrip::TabStrip(TabStripModel* model) ALLOW_THIS_IN_INITIALIZER_LIST(bounds_animator_(this)), animation_type_(ANIMATION_DEFAULT), new_tab_button_enabled_(true), - cancelling_animation_(false) { + cancelling_animation_(false), + attaching_dragged_tab_(false) { Init(); } @@ -289,28 +313,6 @@ void TabStrip::DestroyDragController() { drag_controller_.reset(NULL); } -void TabStrip::DestroyDraggedSourceTab(Tab* tab) { - // We could be running an animation that references this Tab. - StopAnimating(true); - - // Make sure we leave the tab_data_ vector in a consistent state, otherwise - // we'll be pointing to tabs that have been deleted and removed from the - // child view list. - int tab_data_index = TabDataIndexOfTab(tab); - if (tab_data_index != -1) { - if (!model_->closing_all()) - NOTREACHED() << "Leaving in an inconsistent state!"; - tab_data_.erase(tab_data_.begin() + tab_data_index); - } - - delete tab; - - // Force a layout here, because if we've just quickly drag detached a Tab, - // the stopping of the active animation above may have left the TabStrip in a - // bad (visual) state. - Layout(); -} - gfx::Rect TabStrip::GetIdealBounds(int tab_data_index) { DCHECK_GE(tab_data_index, 0); DCHECK_LT(tab_data_index, GetTabCount()); @@ -459,13 +461,17 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) { Tab* selected_tab = NULL; + Tab* dragging_tab = NULL; + for (int i = tab_count - 1; i >= 0; --i) { Tab* tab = GetTabAtTabDataIndex(i); // We must ask the _Tab's_ model, not ourselves, because in some situations // the model will be different to this object, e.g. when a Tab is being // removed after its TabContents has been destroyed. if (!tab->phantom()) { - if (!tab->IsSelected()) { + if (tab->dragging()) { + dragging_tab = tab; + } else if (!tab->IsSelected()) { if (tab->render_unselected() && model_->count() > 1) { // See comment above kNetTabAnimationSelectedOffset as to why we do // this. @@ -511,6 +517,10 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) { animation_type_ != ANIMATION_NEW_TAB_3) { newtab_button_->ProcessPaint(canvas); } + + // And the dragged tab. + if (dragging_tab) + dragging_tab->ProcessPaint(canvas); } // Overridden to support automation. See automation_proxy_uitest.cc. @@ -656,6 +666,16 @@ void TabStrip::ViewHierarchyChanged(bool is_add, InitTabStripButtons(); } +bool TabStrip::OnMouseDragged(const views::MouseEvent& event) { + if (drag_controller_.get()) + drag_controller_->Drag(); + return true; +} + +void TabStrip::OnMouseReleased(const views::MouseEvent& event, + bool canceled) { + EndDrag(canceled); +} /////////////////////////////////////////////////////////////////////////////// // TabStrip, TabStripModelObserver implementation: @@ -671,69 +691,23 @@ void TabStrip::TabInsertedAt(TabContents* contents, contents->render_view_host()->UpdateBrowserWindowId( contents->controller().window_id().id()); - bool contains_tab = false; - Tab* tab = NULL; - // First see if this Tab is one that was dragged out of this TabStrip and is - // now being dragged back in. In this case, the DraggedTabController actually - // has the Tab already constructed and we can just insert it into our list - // again. - if (IsDragSessionActive()) { - tab = drag_controller_->GetDragSourceTabForContents(contents); - if (tab) { - // If the Tab was detached, it would have been animated closed but not - // removed, so we need to reset this property. - tab->set_closing(false); - tab->ValidateLoadingAnimation(TabRenderer::ANIMATION_NONE); - tab->SetVisible(true); - } - - // See if we're already in the list. We don't want to add ourselves twice. - int tab_data_index = TabDataIndexOfTab(tab); + Tab* tab = CreateTab(); - if (tab_data_index != -1) { - contains_tab = true; - - // Make sure we stop animating the view. This is necessary otherwise when - // the animation is done it'll try to remove the tab. - bounds_animator_.StopAnimatingView(tab); - - // We have the tab, but it might not be at the right index. Reset the data - // to ensure it's at the right index. - TabData tab_data = tab_data_[tab_data_index]; - DCHECK(tab_data.tab == tab); - tab_data_.erase(tab_data_.begin() + tab_data_index); - tab_data_.insert( - tab_data_.begin() + ModelIndexToTabDataIndex(model_index), - tab_data); - } - } - - // Otherwise we need to make a new Tab. - if (!tab) - tab = CreateTab(); - - // Only insert if we're not already in the list. - if (!contains_tab) { - TabData d = { tab, gfx::Rect() }; - tab_data_.insert(tab_data_.begin() + - ModelIndexToTabDataIndex(model_index), d); - tab->UpdateData(contents, model_->IsPhantomTab(model_index), false); - } + TabData d = { tab, gfx::Rect() }; + tab_data_.insert(tab_data_.begin() + + ModelIndexToTabDataIndex(model_index), d); + tab->UpdateData(contents, model_->IsPhantomTab(model_index), false); tab->set_mini(model_->IsMiniTab(model_index)); tab->set_app(model_->IsAppTab(model_index)); tab->SetBlocked(model_->IsTabBlocked(model_index)); + tab->SetAnimationContainer(animation_container_.get()); - // We only add the tab to the child list if it's not already - an invisible - // tab maintained by the DraggedTabController will already be parented. - if (!tab->GetParent()) { - AddChildView(tab); - tab->SetAnimationContainer(animation_container_.get()); - } + AddChildView(tab); // Don't animate the first tab, it looks weird, and don't animate anything // if the containing window isn't visible yet. if (GetTabCount() > 1 && GetWindow() && GetWindow()->IsVisible()) { - if (!IsDragSessionActive() && + if (!IsDragSessionActive() && !attaching_dragged_tab_ && ShouldStartIntertTabAnimationAtEnd(model_index, foreground)) { StartInsertTabAnimationAtEnd(); } else { @@ -943,19 +917,30 @@ void TabStrip::MaybeStartDrag(Tab* tab, const views::MouseEvent& event) { return; } drag_controller_.reset(new DraggedTabController(tab, this)); - drag_controller_->CaptureDragInfo(event.location()); + drag_controller_->CaptureDragInfo(tab, event.location()); } void TabStrip::ContinueDrag(const views::MouseEvent& event) { // We can get called even if |MaybeStartDrag| wasn't called in the event of // a TabStrip animation when the mouse button is down. In this case we should // _not_ continue the drag because it can lead to weird bugs. - if (drag_controller_.get()) + if (drag_controller_.get()) { + bool started_drag = drag_controller_->started_drag(); drag_controller_->Drag(); + if (drag_controller_->started_drag() && !started_drag) { + // The drag just started. Redirect mouse events to us to that the tab that + // originated the drag can be safely deleted. + GetRootView()->SetMouseHandler(this); + } + } } bool TabStrip::EndDrag(bool canceled) { - return drag_controller_.get() ? drag_controller_->EndDrag(canceled) : false; + if (!drag_controller_.get()) + return false; + bool started_drag = drag_controller_->started_drag(); + drag_controller_->EndDrag(canceled); + return started_drag; } bool TabStrip::HasAvailableDragActions() const { @@ -1537,7 +1522,7 @@ void TabStrip::NewTabAnimation2Done() { void TabStrip::AnimateToIdealBounds() { for (size_t i = 0; i < tab_data_.size(); ++i) { - if (!tab_data_[i].tab->closing()) { + if (!tab_data_[i].tab->closing() && !tab_data_[i].tab->dragging()) { bounds_animator_.AnimateViewTo(tab_data_[i].tab, tab_data_[i].ideal_bounds); } @@ -1743,13 +1728,7 @@ void TabStrip::RemoveTab(Tab* tab) { // Remove the Tab from the TabStrip's list... tab_data_.erase(tab_data_.begin() + tab_data_index); - // If the TabContents being detached was removed as a result of a drag - // gesture from its corresponding Tab, we don't want to remove the Tab from - // the child list, because if we do so it'll stop receiving events and the - // drag will stall. So we only remove if a drag isn't active, or the Tab - // was for some other TabContents. - if (!IsDragSessionActive() || !drag_controller_->IsDragSourceTab(tab)) - delete tab; + delete tab; } void TabStrip::HandleGlobalMouseMoveEvent() { @@ -1809,3 +1788,39 @@ int TabStrip::TabDataIndexOfTab(Tab* tab) const { } return -1; } + +void TabStrip::StartedDraggingTab(Tab* tab) { + tab->set_dragging(true); + + // Stop any animations on the tab. + bounds_animator_.StopAnimatingView(tab); + + // Move the tab to its ideal bounds. + GenerateIdealBounds(); + int tab_data_index = TabDataIndexOfTab(tab); + DCHECK(tab_data_index != -1); + tab->SetBounds(tab_data_[tab_data_index].ideal_bounds); + SchedulePaint(); +} + +void TabStrip::StoppedDraggingTab(Tab* tab) { + int tab_data_index = TabDataIndexOfTab(tab); + if (tab_data_index == -1) { + // The tab was removed before the drag completed. Don't do anything. + return; + } + + // Animate the view back to its correct position. + ResetAnimationState(true); + GenerateIdealBounds(); + AnimateToIdealBounds(); + bounds_animator_.AnimateViewTo( + tab, + tab_data_[TabDataIndexOfTab(tab)].ideal_bounds); + + // Install a delegate to reset the dragging state when done. We have to leave + // dragging true for the tab otherwise it'll draw beneath the new tab button. + bounds_animator_.SetAnimationDelegate(tab, + new ResetDraggingStateDelegate(tab), + true); +} diff --git a/chrome/browser/views/tabs/tab_strip.h b/chrome/browser/views/tabs/tab_strip.h index 8752bf1..5279dd0 100644 --- a/chrome/browser/views/tabs/tab_strip.h +++ b/chrome/browser/views/tabs/tab_strip.h @@ -76,9 +76,6 @@ class TabStrip : public BaseTabStrip, // Destroys the active drag controller. void DestroyDragController(); - // Removes the drag source Tab from this TabStrip, and deletes it. - void DestroyDraggedSourceTab(Tab* tab); - // Retrieves the ideal bounds for the Tab at the specified index. gfx::Rect GetIdealBounds(int tab_data_index); @@ -137,6 +134,9 @@ class TabStrip : public BaseTabStrip, virtual void ViewHierarchyChanged(bool is_add, views::View* parent, views::View* child); + virtual bool OnMouseDragged(const views::MouseEvent& event); + virtual void OnMouseReleased(const views::MouseEvent& event, + bool canceled); // TabStripModelObserver implementation: virtual void TabInsertedAt(TabContents* contents, @@ -419,6 +419,13 @@ class TabStrip : public BaseTabStrip, // -1 if the tab isn't in |tab_data_|. int TabDataIndexOfTab(Tab* tab) const; + // See description above field for details. + void set_attaching_dragged_tab(bool value) { attaching_dragged_tab_ = value; } + + // Used by DraggedTabController when the user starts or stops dragging a tab. + void StartedDraggingTab(Tab* tab); + void StoppedDraggingTab(Tab* tab); + // -- Member Variables ------------------------------------------------------ // Our model. @@ -491,6 +498,9 @@ class TabStrip : public BaseTabStrip, // If true, we're cancelling the animation. bool cancelling_animation_; + // Used by DraggedTabController when inserting a tab into our model. + bool attaching_dragged_tab_; + DISALLOW_COPY_AND_ASSIGN(TabStrip); }; |