summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwyck@chromium.org <wyck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-08 16:35:11 +0000
committerwyck@chromium.org <wyck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-08 16:35:11 +0000
commit8041a63cc3f90bb8ba4adcc8a015461b94dcf0ec (patch)
tree5626fa8ce7befb32ec661029172c41ce38387cfa
parent949543714576d5232f3d78e7eba936fb5cd5d215 (diff)
downloadchromium_src-8041a63cc3f90bb8ba4adcc8a015461b94dcf0ec.zip
chromium_src-8041a63cc3f90bb8ba4adcc8a015461b94dcf0ec.tar.gz
chromium_src-8041a63cc3f90bb8ba4adcc8a015461b94dcf0ec.tar.bz2
Scrolling Tabs
Implement scrolling tabs. Selected tab stays in view. BUG=None TEST=None Review URL: http://codereview.chromium.org/6750007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80945 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/ui/touch/tabs/touch_tab.cc14
-rw-r--r--chrome/browser/ui/touch/tabs/touch_tab.h4
-rw-r--r--chrome/browser/ui/touch/tabs/touch_tab_strip.cc116
-rw-r--r--chrome/browser/ui/touch/tabs/touch_tab_strip.h52
-rw-r--r--chrome/browser/ui/views/tabs/base_tab_strip.cc25
-rw-r--r--chrome/browser/ui/views/tabs/base_tab_strip.h3
6 files changed, 201 insertions, 13 deletions
diff --git a/chrome/browser/ui/touch/tabs/touch_tab.cc b/chrome/browser/ui/touch/tabs/touch_tab.cc
index b5812a9..2a67064 100644
--- a/chrome/browser/ui/touch/tabs/touch_tab.cc
+++ b/chrome/browser/ui/touch/tabs/touch_tab.cc
@@ -57,6 +57,20 @@ const gfx::Rect& TouchTab::GetIconBounds() const {
////////////////////////////////////////////////////////////////////////////////
// TouchTab, views::View overrides:
+// We'll get selected via the mouse interactions with the TouchTabStrip. There
+// is no need to directly handle the mouse movements in the TouchTab.
+
+bool TouchTab::OnMousePressed(const views::MouseEvent& event) {
+ return false;
+}
+
+bool TouchTab::OnMouseDragged(const views::MouseEvent& event) {
+ return false;
+}
+
+void TouchTab::OnMouseReleased(const views::MouseEvent& event) {
+}
+
void TouchTab::OnPaint(gfx::Canvas* canvas) {
// Don't paint if we're narrower than we can render correctly. (This should
// only happen during animations).
diff --git a/chrome/browser/ui/touch/tabs/touch_tab.h b/chrome/browser/ui/touch/tabs/touch_tab.h
index 923ebd9..b4ff409 100644
--- a/chrome/browser/ui/touch/tabs/touch_tab.h
+++ b/chrome/browser/ui/touch/tabs/touch_tab.h
@@ -18,6 +18,7 @@
//
// A View that renders a TouchTab in a TouchTabStrip
//
+// TODO(wyck): Use transformable views for scrolling.
///////////////////////////////////////////////////////////////////////////////
class TouchTab : public BaseTab {
public:
@@ -42,6 +43,9 @@ class TouchTab : public BaseTab {
private:
// Overridden from views::View:
+ virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE;
+ virtual bool OnMouseDragged(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas);
virtual void Layout();
virtual bool HasHitTestMask() const;
diff --git a/chrome/browser/ui/touch/tabs/touch_tab_strip.cc b/chrome/browser/ui/touch/tabs/touch_tab_strip.cc
index 8a890ed..a50c4b0 100644
--- a/chrome/browser/ui/touch/tabs/touch_tab_strip.cc
+++ b/chrome/browser/ui/touch/tabs/touch_tab_strip.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/ui/touch/tabs/touch_tab_strip.h"
+#include <algorithm>
+#include <cmath>
+
#include "chrome/browser/ui/touch/tabs/touch_tab.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
@@ -15,12 +18,19 @@
static const int kTouchTabStripHeight = 64;
static const int kTouchTabWidth = 64;
static const int kTouchTabHeight = 64;
+static const int kScrollThreshold = 4;
TouchTabStrip::TouchTabStrip(TabStripController* controller)
: BaseTabStrip(controller, BaseTabStrip::HORIZONTAL_TAB_STRIP),
in_tab_close_(false),
last_tap_time_(base::Time::FromInternalValue(0)),
- last_tapped_view_(NULL) {
+ last_tapped_view_(NULL),
+ initial_mouse_x_(0),
+ initial_scroll_offset_(0),
+ scroll_offset_(0),
+ scrolling_(false),
+ initial_tab_(NULL),
+ min_scroll_offset_(0) {
Init();
}
@@ -128,12 +138,18 @@ void TouchTabStrip::GenerateIdealBounds() {
for (int i = 0; i < tab_count(); ++i) {
TouchTab* tab = GetTabAtTabDataIndex(i);
if (!tab->closing()) {
- set_ideal_bounds(i, gfx::Rect(tab_x, tab_y, kTouchTabWidth,
- kTouchTabHeight));
+ int x = tab_x + scroll_offset_;
+ if (tab->IsSelected()) {
+ // limit the extent to which this tab can be displaced.
+ x = std::min(std::max(0, x), width() - kTouchTabWidth);
+ }
+ set_ideal_bounds(i, gfx::Rect(x, tab_y,
+ kTouchTabWidth, kTouchTabHeight));
// offset the next tab to the right by the width of this tab
tab_x += kTouchTabWidth;
}
}
+ min_scroll_offset_ = std::min(0, width() - tab_x);
}
void TouchTabStrip::LayoutDraggedTabsAt(const std::vector<BaseTab*>& tabs,
@@ -157,6 +173,100 @@ int TouchTabStrip::GetSizeNeededForTabs(const std::vector<BaseTab*>& tabs) {
return 0;
}
+// TODO(wyck): Someday we might like to get a "scroll" interaction event by way
+// of views, triggered by the gesture manager, and/or mouse scroll wheel.
+// For now, we're just handling a single scroll with these mouse events:
+// OnMousePressed, OnMouseDragged, and OnMouseReleased.
+
+bool TouchTabStrip::OnMousePressed(const views::MouseEvent& event) {
+ // When we press the mouse button, we begin a drag
+ BeginScroll(event.location());
+ return true;
+}
+
+bool TouchTabStrip::OnMouseDragged(const views::MouseEvent& event) {
+ ContinueScroll(event.location());
+ return true;
+}
+
+void TouchTabStrip::OnMouseReleased(const views::MouseEvent& event) {
+ EndScroll(event.location());
+}
+
+void TouchTabStrip::OnMouseCaptureLost() {
+ CancelScroll();
+}
+
+void TouchTabStrip::BeginScroll(const gfx::Point& point ) {
+ initial_mouse_x_ = point.x();
+ initial_scroll_offset_ = scroll_offset_;
+ initial_tab_ = static_cast<TouchTab*>(GetTabAtLocal(point));
+}
+
+void TouchTabStrip::ContinueScroll(const gfx::Point& point) {
+ int delta_x = point.x() - initial_mouse_x_;
+ if (std::abs(delta_x) > kScrollThreshold)
+ scrolling_ = true;
+ if (scrolling_)
+ ScrollTo(delta_x);
+ DoLayout();
+ SchedulePaint();
+}
+
+void TouchTabStrip::EndScroll(const gfx::Point& point) {
+ int delta_x = point.x() - initial_mouse_x_;
+ if (scrolling_) {
+ scrolling_ = false;
+ ScrollTo(delta_x);
+ StopAnimating(false);
+ GenerateIdealBounds();
+ AnimateToIdealBounds();
+ } else {
+ TouchTab* tab = static_cast<TouchTab*>(GetTabAtLocal(point));
+ if (tab && tab == initial_tab_)
+ SelectTab(tab);
+ DoLayout();
+ SchedulePaint();
+ }
+ initial_tab_ = NULL;
+}
+
+void TouchTabStrip::CancelScroll() {
+ // Cancel the scroll by scrolling back to the initial position (deltax = 0).
+ ScrollTo(0);
+ StopAnimating(false);
+ GenerateIdealBounds();
+ AnimateToIdealBounds();
+}
+
+void TouchTabStrip::ScrollTo(int delta_x) {
+ scroll_offset_ = initial_scroll_offset_ + delta_x;
+ // Limit the scrolling here.
+ // When scrolling beyond the limits of min and max offsets, the displacement
+ // is adjusted to 25% of what would normally applied (divided by 4).
+ // Perhaps in the future, Hooke's law could be used to model more physically
+ // based spring-like behavior.
+ int max_scroll_offset = 0; // Because there's never content to the left of 0.
+ if (scroll_offset_ > max_scroll_offset) {
+ if (scrolling_) {
+ scroll_offset_ = max_scroll_offset
+ + std::min((scroll_offset_ - max_scroll_offset) / 4,
+ kTouchTabWidth);
+ } else {
+ scroll_offset_ = max_scroll_offset;
+ }
+ }
+ if (scroll_offset_ < min_scroll_offset_) {
+ if (scrolling_) {
+ scroll_offset_ = min_scroll_offset_
+ + std::max((scroll_offset_ - min_scroll_offset_) / 4,
+ -kTouchTabWidth);
+ } else {
+ scroll_offset_ = min_scroll_offset_;
+ }
+ }
+}
+
TouchTab* TouchTabStrip::GetTabAtTabDataIndex(int tab_data_index) const {
return static_cast<TouchTab*>(base_tab_at_tab_index(tab_data_index));
}
diff --git a/chrome/browser/ui/touch/tabs/touch_tab_strip.h b/chrome/browser/ui/touch/tabs/touch_tab_strip.h
index d9bd550..097f00b 100644
--- a/chrome/browser/ui/touch/tabs/touch_tab_strip.h
+++ b/chrome/browser/ui/touch/tabs/touch_tab_strip.h
@@ -19,6 +19,7 @@ class TouchTab;
// - It implements the TabStripModelObserver interface, and acts as a
// container for Tabs, and is also responsible for creating them.
//
+// TODO(wyck): Use transformable views for scrolling.
///////////////////////////////////////////////////////////////////////////////
class TouchTabStrip : public BaseTabStrip {
public:
@@ -51,6 +52,12 @@ class TouchTabStrip : public BaseTabStrip {
std::vector<gfx::Rect>* bounds);
virtual int GetSizeNeededForTabs(const std::vector<BaseTab*>& tabs);
+ // views::View overrides:
+ virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE;
+ virtual bool OnMouseDragged(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseCaptureLost() OVERRIDE;
+
// Retrieves the Tab at the specified index. Remember, the specified index
// is in terms of tab_data, *not* the model.
TouchTab* GetTabAtTabDataIndex(int tab_data_index) const;
@@ -67,6 +74,28 @@ class TouchTabStrip : public BaseTabStrip {
View* parent,
View* child) OVERRIDE;
+ // Adjusts the state of scroll interaction when a mouse press occurs at the
+ // given point. Sets an appropriate |initial_scroll_offset_|.
+ void BeginScroll(const gfx::Point& point);
+
+ // Adjusts the state of scroll interaction when the mouse is dragged to the
+ // given point. If the scroll is not beyond the minimum threshold, the tabs
+ // will not actually scroll.
+ void ContinueScroll(const gfx::Point& point);
+
+ // Adjusts the state of scroll interaction when the mouse is released. Either
+ // scrolls to the final mouse release point or selects the current tab
+ // depending on whether the mouse was dragged beyone the minimum threshold.
+ void EndScroll(const gfx::Point& point);
+
+ // Adjust the state of scroll interaction when the mouse capture is lost. It
+ // scrolls back to the original position before the scroll began.
+ void CancelScroll();
+
+ // Adjust the positions of the tabs to perform a scroll of |delta_x| relative
+ // to the |initial_scroll_offset_|.
+ void ScrollTo(int delta_x);
+
// True if PrepareForCloseAt has been invoked. When true remove animations
// preserve current tab bounds.
bool in_tab_close_;
@@ -77,6 +106,29 @@ class TouchTabStrip : public BaseTabStrip {
// The view that was tapped last.
View* last_tapped_view_;
+ // Records the mouse x coordinate at the start of a drag operation.
+ int initial_mouse_x_;
+
+ // Records the scroll offset at the time of the start of a drag operation.
+ int initial_scroll_offset_;
+
+ // The current offset of the view. Positive scroll offsets move the icons to
+ // the left. Negative scroll offsets move the icons to the right.
+ int scroll_offset_;
+
+ // State of the scrolling interaction. Will be true once the drag has been
+ // displaced beyond the minimum dragging threshold.
+ bool scrolling_;
+
+ // Records the tab that was under the initial mouse press. Must match the
+ // tab that was under the final mouse release in order for the tab to
+ // be selected.
+ TouchTab* initial_tab_;
+
+ // The minimum value that |scroll_offset_| can have. Based on the total
+ // width of all the content to be scrolled, less the viewport size.
+ int min_scroll_offset_;
+
DISALLOW_COPY_AND_ASSIGN(TouchTabStrip);
};
diff --git a/chrome/browser/ui/views/tabs/base_tab_strip.cc b/chrome/browser/ui/views/tabs/base_tab_strip.cc
index 48f6d69..cfd0bc0 100644
--- a/chrome/browser/ui/views/tabs/base_tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/base_tab_strip.cc
@@ -378,16 +378,7 @@ BaseTab* BaseTabStrip::GetTabAt(BaseTab* tab,
const gfx::Point& tab_in_tab_coordinates) {
gfx::Point local_point = tab_in_tab_coordinates;
ConvertPointToView(tab, this, &local_point);
- views::View* view = GetEventHandlerForPoint(local_point);
- if (!view)
- return NULL; // No tab contains the point.
-
- // Walk up the view hierarchy until we find a tab, or the TabStrip.
- while (view && view != this && view->GetID() != VIEW_ID_TAB)
- view = view->parent();
-
- return view && view->GetID() == VIEW_ID_TAB ?
- static_cast<BaseTab*>(view) : NULL;
+ return GetTabAtLocal(local_point);
}
void BaseTabStrip::Layout() {
@@ -571,6 +562,20 @@ void BaseTabStrip::DoLayout() {
SchedulePaint();
}
+BaseTab* BaseTabStrip::GetTabAtLocal(
+ const gfx::Point& local_point) {
+ views::View* view = GetEventHandlerForPoint(local_point);
+ if (!view)
+ return NULL; // No tab contains the point.
+
+ // Walk up the view hierarchy until we find a tab, or the TabStrip.
+ while (view && view != this && view->GetID() != VIEW_ID_TAB)
+ view = view->parent();
+
+ return view && view->GetID() == VIEW_ID_TAB ?
+ static_cast<BaseTab*>(view) : NULL;
+}
+
void BaseTabStrip::StoppedDraggingTab(BaseTab* tab, bool* is_first_tab) {
int tab_data_index = TabIndexOfTab(tab);
if (tab_data_index == -1) {
diff --git a/chrome/browser/ui/views/tabs/base_tab_strip.h b/chrome/browser/ui/views/tabs/base_tab_strip.h
index 30b6224..210080c 100644
--- a/chrome/browser/ui/views/tabs/base_tab_strip.h
+++ b/chrome/browser/ui/views/tabs/base_tab_strip.h
@@ -246,6 +246,9 @@ class BaseTabStrip : public AbstractTabStripView,
// Invoked from Layout if the size changes or layout is really needed.
virtual void DoLayout();
+ // Get tab at a point in local view coordinates.
+ BaseTab* GetTabAtLocal(const gfx::Point& local_point);
+
private:
class RemoveTabDelegate;