Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Unified Diff: chrome/browser/ui/views/tabs/default_tab_drag_controller.cc

Issue 10267023: Gets tab dragging to work in touch mode. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Cleanup Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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) {
« no previous file with comments | « chrome/browser/ui/views/tabs/default_tab_drag_controller.h ('k') | chrome/browser/ui/views/tabs/tab_strip.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698