diff options
author | wyck@chromium.org <wyck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-08 16:35:11 +0000 |
---|---|---|
committer | wyck@chromium.org <wyck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-08 16:35:11 +0000 |
commit | 8041a63cc3f90bb8ba4adcc8a015461b94dcf0ec (patch) | |
tree | 5626fa8ce7befb32ec661029172c41ce38387cfa | |
parent | 949543714576d5232f3d78e7eba936fb5cd5d215 (diff) | |
download | chromium_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.cc | 14 | ||||
-rw-r--r-- | chrome/browser/ui/touch/tabs/touch_tab.h | 4 | ||||
-rw-r--r-- | chrome/browser/ui/touch/tabs/touch_tab_strip.cc | 116 | ||||
-rw-r--r-- | chrome/browser/ui/touch/tabs/touch_tab_strip.h | 52 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/base_tab_strip.cc | 25 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/base_tab_strip.h | 3 |
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; |