| Index: chrome/browser/ui/views/tabs/default_tab_drag_controller.cc
|
| diff --git a/chrome/browser/ui/views/tabs/default_tab_drag_controller.cc b/chrome/browser/ui/views/tabs/default_tab_drag_controller.cc
|
| index 02132c6c2da12d13f945df2d4ac6d4a17d426e7d..e7f0039d64610b9ca7657f8530c2320ebd38a463 100644
|
| --- a/chrome/browser/ui/views/tabs/default_tab_drag_controller.cc
|
| +++ b/chrome/browser/ui/views/tabs/default_tab_drag_controller.cc
|
| @@ -54,6 +54,10 @@ using content::WebContents;
|
|
|
| static const int kHorizontalMoveThreshold = 16; // Pixels.
|
|
|
| +// Distance from the next/previous stacked before before we consider the tab
|
| +// close enough to trigger moving.
|
| +static const int kStackedDistance = 36;
|
| +
|
| // If non-null there is a drag underway.
|
| static DefaultTabDragController* instance_ = NULL;
|
|
|
| @@ -62,6 +66,13 @@ namespace {
|
| // Delay, in ms, during dragging before we bring a window to front.
|
| const int kBringToFrontDelay = 750;
|
|
|
| +// Initial delay before moving tabs when the dragged tab is close to the edge of
|
| +// the stacked tabs.
|
| +const int kMoveAttachedInitialDelay = 600;
|
| +
|
| +// Delay for moving tabs after the initial delay has passed.
|
| +const int kMoveAttachedSubsequentDelay = 300;
|
| +
|
| // Radius of the rect drawn by DockView.
|
| const int kRoundedRectRadius = 4;
|
|
|
| @@ -176,7 +187,7 @@ class DockView : public views::View {
|
| DISALLOW_COPY_AND_ASSIGN(DockView);
|
| };
|
|
|
| -// Returns the the x-coordinate of |point| if the type of tabstrip is horizontal
|
| +// Returns the x-coordinate of |point| if the type of tabstrip is horizontal
|
| // otherwise returns the y-coordinate.
|
| int MajorAxisValue(const gfx::Point& point, TabStrip* tabstrip) {
|
| return point.x();
|
| @@ -321,7 +332,8 @@ DefaultTabDragController::DefaultTabDragController()
|
| active_(true),
|
| source_tab_index_(std::numeric_limits<size_t>::max()),
|
| initial_move_(true),
|
| - move_only_(false) {
|
| + move_only_(false),
|
| + mouse_move_direction_(0) {
|
| instance_ = this;
|
| }
|
|
|
| @@ -357,6 +369,7 @@ void DefaultTabDragController::Init(
|
| start_screen_point_ = GetCursorScreenPoint();
|
| mouse_offset_ = mouse_offset;
|
| move_only_ = move_only;
|
| + last_screen_point_ = start_screen_point_;
|
|
|
| if (move_only_) {
|
| last_move_screen_loc_ =
|
| @@ -403,6 +416,7 @@ void DefaultTabDragController::InitTabDragData(BaseTab* tab,
|
|
|
| void DefaultTabDragController::Drag() {
|
| bring_to_front_timer_.Stop();
|
| + move_stacked_timer_.Stop();
|
|
|
| if (!started_drag_) {
|
| if (!CanStartDrag())
|
| @@ -679,7 +693,7 @@ void DefaultTabDragController::ContinueDragging() {
|
|
|
| if (attached_tabstrip_) {
|
| if (move_only_)
|
| - MoveAttachedStacked(screen_point);
|
| + DragActiveTabStacked(screen_point);
|
| else
|
| MoveAttached(screen_point);
|
| } else {
|
| @@ -687,7 +701,7 @@ void DefaultTabDragController::ContinueDragging() {
|
| }
|
| }
|
|
|
| -void DefaultTabDragController::MoveAttachedStacked(
|
| +void DefaultTabDragController::DragActiveTabStacked(
|
| const gfx::Point& screen_point) {
|
| if (attached_tabstrip_->tab_count() !=
|
| static_cast<int>(initial_tab_positions_.size()))
|
| @@ -697,21 +711,48 @@ void DefaultTabDragController::MoveAttachedStacked(
|
| attached_tabstrip_->DragActiveTab(initial_tab_positions_, delta);
|
| }
|
|
|
| +void DefaultTabDragController::MoveAttachedToNextStackedIndex() {
|
| + int index = attached_tabstrip_->touch_layout_->active_index();
|
| + if (index + 1 >= attached_tabstrip_->tab_count())
|
| + return;
|
| +
|
| + GetModel(attached_tabstrip_)->MoveSelectedTabsTo(index + 1);
|
| + StartMoveStackedTimerIfNecessary(kMoveAttachedSubsequentDelay);
|
| +}
|
| +
|
| +void DefaultTabDragController::MoveAttachedToPreviousStackedIndex() {
|
| + int index = attached_tabstrip_->touch_layout_->active_index();
|
| + if (index <= attached_tabstrip_->GetMiniTabCount())
|
| + return;
|
| +
|
| + GetModel(attached_tabstrip_)->MoveSelectedTabsTo(index - 1);
|
| + StartMoveStackedTimerIfNecessary(kMoveAttachedSubsequentDelay);
|
| +}
|
| +
|
| void DefaultTabDragController::MoveAttached(const gfx::Point& screen_point) {
|
| DCHECK(attached_tabstrip_);
|
| DCHECK(!view_.get());
|
|
|
| - gfx::Point dragged_view_point = GetAttachedDragPoint(screen_point);
|
| + int move_delta = screen_point.x() - last_screen_point_.x();
|
| + if (move_delta > 0)
|
| + mouse_move_direction_ |= kMovedMouseRight;
|
| + else if (move_delta < 0)
|
| + mouse_move_direction_ |= kMovedMouseLeft;
|
| + last_screen_point_ = screen_point;
|
|
|
| - TabStrip* tab_strip = static_cast<TabStrip*>(attached_tabstrip_);
|
| + gfx::Point dragged_view_point = GetAttachedDragPoint(screen_point);
|
|
|
| // 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;
|
| - tab_strip->GetCurrentTabWidths(&unselected, &selected);
|
| - double ratio = unselected / Tab::GetStandardSize().width();
|
| - int threshold = static_cast<int>(ratio * kHorizontalMoveThreshold);
|
| + int threshold = kHorizontalMoveThreshold;
|
| + if (!attached_tabstrip_->touch_layout_.get()) {
|
| + double unselected, selected;
|
| + attached_tabstrip_->GetCurrentTabWidths(&unselected, &selected);
|
| + double ratio = unselected / Tab::GetStandardSize().width();
|
| + threshold = static_cast<int>(ratio * kHorizontalMoveThreshold);
|
| + }
|
| + // else case: touch tabs never shrink.
|
|
|
| std::vector<BaseTab*> tabs(drag_data_.size());
|
| for (size_t i = 0; i < drag_data_.size(); ++i)
|
| @@ -741,6 +782,7 @@ void DefaultTabDragController::MoveAttached(const gfx::Point& screen_point) {
|
| did_layout = true;
|
| }
|
| attached_model->MoveSelectedTabsTo(to_index);
|
| +
|
| // Move may do nothing in certain situations (such as when dragging pinned
|
| // tabs). Make sure the tabstrip actually changed before updating
|
| // last_move_screen_loc_.
|
| @@ -756,6 +798,8 @@ void DefaultTabDragController::MoveAttached(const gfx::Point& screen_point) {
|
| initial_move_);
|
| }
|
|
|
| + StartMoveStackedTimerIfNecessary(kMoveAttachedInitialDelay);
|
| +
|
| initial_move_ = false;
|
| }
|
|
|
| @@ -767,6 +811,30 @@ void DefaultTabDragController::MoveDetached(const gfx::Point& screen_point) {
|
| view_->MoveTo(screen_point);
|
| }
|
|
|
| +void DefaultTabDragController::StartMoveStackedTimerIfNecessary(int delay_ms) {
|
| + DCHECK(attached_tabstrip_);
|
| +
|
| + TouchTabStripLayout* touch_layout = attached_tabstrip_->touch_layout_.get();
|
| + if (!touch_layout)
|
| + return;
|
| +
|
| + gfx::Point screen_point = GetCursorScreenPoint();
|
| + gfx::Point dragged_view_point = GetAttachedDragPoint(screen_point);
|
| + gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point);
|
| + int index = touch_layout->active_index();
|
| + if (ShouldDragToNextStackedTab(bounds, index)) {
|
| + move_stacked_timer_.Start(
|
| + FROM_HERE,
|
| + base::TimeDelta::FromMilliseconds(delay_ms), this,
|
| + &DefaultTabDragController::MoveAttachedToNextStackedIndex);
|
| + } else if (ShouldDragToPreviousStackedTab(bounds, index)) {
|
| + move_stacked_timer_.Start(
|
| + FROM_HERE,
|
| + base::TimeDelta::FromMilliseconds(delay_ms), this,
|
| + &DefaultTabDragController::MoveAttachedToPreviousStackedIndex);
|
| + }
|
| +}
|
| +
|
| DockInfo DefaultTabDragController::GetDockInfoAtPoint(
|
| const gfx::Point& screen_point) {
|
| if (attached_tabstrip_) {
|
| @@ -887,6 +955,12 @@ void DefaultTabDragController::Attach(TabStrip* attached_tabstrip,
|
| attached_tabstrip_->set_attaching_dragged_tab(true);
|
| for (size_t i = 0; i < drag_data_.size(); ++i) {
|
| int add_types = TabStripModel::ADD_NONE;
|
| + if (attached_tabstrip_->touch_layout_.get()) {
|
| + // TouchTabStripLayout positions relative to the active tab, if we don't
|
| + // add the tab as active things bounce around.
|
| + DCHECK_EQ(1u, drag_data_.size());
|
| + add_types |= TabStripModel::ADD_ACTIVE;
|
| + }
|
| if (drag_data_[i].pinned)
|
| add_types |= TabStripModel::ADD_PINNED;
|
| GetModel(attached_tabstrip_)->InsertTabContentsAt(
|
| @@ -920,6 +994,8 @@ void DefaultTabDragController::Attach(TabStrip* attached_tabstrip,
|
| }
|
|
|
| void DefaultTabDragController::Detach() {
|
| + mouse_move_direction_ = kMovedMouseLeft | kMovedMouseRight;
|
| +
|
| // Prevent the WebContents HWND from being hidden by any of the model
|
| // operations performed during the drag.
|
| source_dragged_contents()->web_contents()->SetCapturingContents(true);
|
| @@ -985,26 +1061,50 @@ void DefaultTabDragController::Detach() {
|
| attached_tabstrip_ = NULL;
|
| }
|
|
|
| -int DefaultTabDragController::GetInsertionIndexForDraggedBounds(
|
| - const gfx::Rect& dragged_bounds) const {
|
| - int right_tab_x = 0;
|
| - int index = -1;
|
| - for (int i = 0; i < attached_tabstrip_->tab_count(); ++i) {
|
| +int DefaultTabDragController::GetInsertionIndexFrom(
|
| + const gfx::Rect& dragged_bounds,
|
| + int start,
|
| + int delta) const {
|
| + for (int i = start, tab_count = attached_tabstrip_->tab_count();
|
| + i >= 0 && i < tab_count; i += delta) {
|
| const gfx::Rect& ideal_bounds = attached_tabstrip_->ideal_bounds(i);
|
| gfx::Rect left_half, right_half;
|
| ideal_bounds.SplitVertically(&left_half, &right_half);
|
| - right_tab_x = right_half.right();
|
| if (dragged_bounds.x() >= right_half.x() &&
|
| dragged_bounds.x() < right_half.right()) {
|
| - index = i + 1;
|
| - break;
|
| + return i + 1;
|
| } else if (dragged_bounds.x() >= left_half.x() &&
|
| dragged_bounds.x() < left_half.right()) {
|
| - index = i;
|
| - break;
|
| + return i;
|
| }
|
| }
|
| + return -1;
|
| +}
|
| +
|
| +int DefaultTabDragController::GetInsertionIndexForDraggedBounds(
|
| + const gfx::Rect& dragged_bounds) const {
|
| + int index = -1;
|
| + if (attached_tabstrip_->touch_layout_.get()) {
|
| + index = GetInsertionIndexForDraggedBoundsStacked(dragged_bounds);
|
| + if (index != -1) {
|
| + // Only move the tab to the left/right if the user actually moved the
|
| + // mouse that way. This is necessary as tabs with stacked tabs
|
| + // before/after them have multiple drag positions.
|
| + int active_index = attached_tabstrip_->touch_layout_->active_index();
|
| + if ((index < active_index &&
|
| + (mouse_move_direction_ & kMovedMouseLeft) == 0) ||
|
| + (index > active_index &&
|
| + (mouse_move_direction_ & kMovedMouseRight) == 0)) {
|
| + index = active_index;
|
| + }
|
| + }
|
| + } else {
|
| + index = GetInsertionIndexFrom(dragged_bounds, 0, 1);
|
| + }
|
| if (index == -1) {
|
| + int tab_count = attached_tabstrip_->tab_count();
|
| + int right_tab_x = tab_count == 0 ? 0 :
|
| + attached_tabstrip_->ideal_bounds(tab_count - 1).right();
|
| if (dragged_bounds.right() > right_tab_x) {
|
| index = GetModel(attached_tabstrip_)->count();
|
| } else {
|
| @@ -1023,6 +1123,65 @@ int DefaultTabDragController::GetInsertionIndexForDraggedBounds(
|
| return std::max(0, std::min(max_index, index));
|
| }
|
|
|
| +bool DefaultTabDragController::ShouldDragToNextStackedTab(
|
| + const gfx::Rect& dragged_bounds,
|
| + int index) const {
|
| + if (index + 1 >= attached_tabstrip_->tab_count() ||
|
| + !attached_tabstrip_->touch_layout_->IsStacked(index + 1) ||
|
| + (mouse_move_direction_ & kMovedMouseRight) == 0)
|
| + return false;
|
| +
|
| + int active_x = attached_tabstrip_->ideal_bounds(index).x();
|
| + int next_x = attached_tabstrip_->ideal_bounds(index + 1).x();
|
| + int mid_x = std::min(next_x - kStackedDistance,
|
| + active_x + (next_x - active_x) / 4);
|
| + return dragged_bounds.x() >= mid_x;
|
| +}
|
| +
|
| +bool DefaultTabDragController::ShouldDragToPreviousStackedTab(
|
| + const gfx::Rect& dragged_bounds,
|
| + int index) const {
|
| + if (index - 1 < attached_tabstrip_->GetMiniTabCount() ||
|
| + !attached_tabstrip_->touch_layout_->IsStacked(index - 1) ||
|
| + (mouse_move_direction_ & kMovedMouseLeft) == 0)
|
| + return false;
|
| +
|
| + int active_x = attached_tabstrip_->ideal_bounds(index).x();
|
| + int previous_x = attached_tabstrip_->ideal_bounds(index - 1).x();
|
| + int mid_x = std::max(previous_x + kStackedDistance,
|
| + active_x - (active_x - previous_x) / 4);
|
| + return dragged_bounds.x() <= mid_x;
|
| +}
|
| +
|
| +int DefaultTabDragController::GetInsertionIndexForDraggedBoundsStacked(
|
| + const gfx::Rect& dragged_bounds) const {
|
| + TouchTabStripLayout* touch_layout = attached_tabstrip_->touch_layout_.get();
|
| + int active_index = touch_layout->active_index();
|
| + // Search from the active index to the front of the tabstrip. Do this as tabs
|
| + // overlap each other from the active index.
|
| + int index = GetInsertionIndexFrom(dragged_bounds, active_index, -1);
|
| + if (index != active_index)
|
| + return index;
|
| + if (index == -1)
|
| + return GetInsertionIndexFrom(dragged_bounds, active_index + 1, 1);
|
| +
|
| + // The position to drag to corresponds to the active tab. If the next/previous
|
| + // tab is stacked, then shorten the distance used to determine insertion
|
| + // bounds. We do this as GetInsertionIndexFrom() uses the bounds of the
|
| + // tabs. When tabs are stacked the next/previous tab is on top of the tab.
|
| + if (active_index + 1 < attached_tabstrip_->tab_count() &&
|
| + touch_layout->IsStacked(active_index + 1)) {
|
| + index = GetInsertionIndexFrom(dragged_bounds, active_index + 1, 1);
|
| + if (index == -1 && ShouldDragToNextStackedTab(dragged_bounds, active_index))
|
| + index = active_index + 1;
|
| + else if (index == -1)
|
| + index = active_index;
|
| + } else if (ShouldDragToPreviousStackedTab(dragged_bounds, active_index)) {
|
| + index = active_index - 1;
|
| + }
|
| + return index;
|
| +}
|
| +
|
| gfx::Rect DefaultTabDragController::GetDraggedViewTabStripBounds(
|
| const gfx::Point& tab_strip_point) {
|
| // attached_tab is NULL when inserting into a new tabstrip.
|
| @@ -1048,19 +1207,14 @@ gfx::Point DefaultTabDragController::GetAttachedDragPoint(
|
| views::View::ConvertPointToView(NULL, attached_tabstrip_, &tab_loc);
|
| int x =
|
| attached_tabstrip_->GetMirroredXInView(tab_loc.x()) - mouse_offset_.x();
|
| - int y = tab_loc.y() - mouse_offset_.y();
|
|
|
| // TODO: consider caching this.
|
| std::vector<BaseTab*> attached_tabs;
|
| for (size_t i = 0; i < drag_data_.size(); ++i)
|
| attached_tabs.push_back(drag_data_[i].attached_tab);
|
| -
|
| int size = attached_tabstrip_->GetSizeNeededForTabs(attached_tabs);
|
| -
|
| int max_x = attached_tabstrip_->width() - size;
|
| - x = std::min(std::max(x, 0), max_x);
|
| - y = 0;
|
| - return gfx::Point(x, y);
|
| + return gfx::Point(std::min(std::max(x, 0), max_x), 0);
|
| }
|
|
|
| std::vector<BaseTab*> DefaultTabDragController::GetTabsMatchingDraggedContents(
|
| @@ -1080,6 +1234,7 @@ void DefaultTabDragController::EndDragImpl(EndDragType type) {
|
| active_ = false;
|
|
|
| bring_to_front_timer_.Stop();
|
| + move_stacked_timer_.Stop();
|
|
|
| // Hide the current dock controllers.
|
| for (size_t i = 0; i < dock_controllers_.size(); ++i) {
|
|
|