diff options
author | mgiuca <mgiuca@chromium.org> | 2014-09-01 01:04:24 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-01 08:07:50 +0000 |
commit | 13cb53dbf92741bd9f432a734bb20bcb16e4ec51 (patch) | |
tree | f0749c0a6f6cd554d5b9b4f0937ed8caef4f4bbd /ui | |
parent | 1803038a446dd27d50ff18b2878b11196d4f801a (diff) | |
download | chromium_src-13cb53dbf92741bd9f432a734bb20bcb16e4ec51.zip chromium_src-13cb53dbf92741bd9f432a734bb20bcb16e4ec51.tar.gz chromium_src-13cb53dbf92741bd9f432a734bb20bcb16e4ec51.tar.bz2 |
Refactor app list scrolling: introduce the PaginationController class.
PaginationController abstracts over mouse wheel, touch screen and
touchpad event handling for updating the PaginationModel. This allows
any client of PaginationModel (ie, ContentsView) to properly handle
scrolling events. It also removes the code duplication in OnMouseWheel
and OnScrollEvent.
BUG=406222
Review URL: https://codereview.chromium.org/524503003
Cr-Commit-Position: refs/heads/master@{#292843}
Diffstat (limited to 'ui')
-rw-r--r-- | ui/app_list/BUILD.gn | 2 | ||||
-rw-r--r-- | ui/app_list/app_list.gyp | 2 | ||||
-rw-r--r-- | ui/app_list/pagination_controller.cc | 88 | ||||
-rw-r--r-- | ui/app_list/pagination_controller.h | 52 | ||||
-rw-r--r-- | ui/app_list/views/apps_grid_view.cc | 109 | ||||
-rw-r--r-- | ui/app_list/views/apps_grid_view.h | 9 |
6 files changed, 165 insertions, 97 deletions
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn index 192f63f..c4c1651 100644 --- a/ui/app_list/BUILD.gn +++ b/ui/app_list/BUILD.gn @@ -26,6 +26,8 @@ component("app_list") { "app_list_switches.h", "app_list_view_delegate.cc", "app_list_view_delegate.h", + "pagination_controller.cc", + "pagination_controller.h", "pagination_model.cc", "pagination_model.h", "pagination_model_observer.h", diff --git a/ui/app_list/app_list.gyp b/ui/app_list/app_list.gyp index d540040..1b700b0 100644 --- a/ui/app_list/app_list.gyp +++ b/ui/app_list/app_list.gyp @@ -72,6 +72,8 @@ 'cocoa/item_drag_controller.mm', 'cocoa/scroll_view_with_no_scrollbars.h', 'cocoa/scroll_view_with_no_scrollbars.mm', + 'pagination_controller.cc', + 'pagination_controller.h', 'pagination_model.cc', 'pagination_model.h', 'pagination_model_observer.h', diff --git a/ui/app_list/pagination_controller.cc b/ui/app_list/pagination_controller.cc new file mode 100644 index 0000000..d9aabc2 --- /dev/null +++ b/ui/app_list/pagination_controller.cc @@ -0,0 +1,88 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/app_list/pagination_controller.h" + +#include "ui/app_list/pagination_model.h" +#include "ui/events/event.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" + +namespace app_list { + +namespace { + +// Constants for dealing with scroll events. +const int kMinScrollToSwitchPage = 20; +const int kMinHorizVelocityToSwitchPage = 800; + +const double kFinishTransitionThreshold = 0.33; + +} // namespace + +PaginationController::PaginationController(PaginationModel* model, + ScrollAxis scroll_axis) + : pagination_model_(model), scroll_axis_(scroll_axis) { +} + +bool PaginationController::OnScroll(const gfx::Vector2d& offset) { + int offset_magnitude; + if (scroll_axis_ == SCROLL_AXIS_HORIZONTAL) { + // If the view scrolls horizontally, both horizontal and vertical scroll + // events are valid (since most mouse wheels only have vertical scrolling). + offset_magnitude = + abs(offset.x()) > abs(offset.y()) ? offset.x() : offset.y(); + } else { + // If the view scrolls vertically, only vertical scroll events are valid. + offset_magnitude = offset.y(); + } + + if (abs(offset_magnitude) > kMinScrollToSwitchPage) { + if (!pagination_model_->has_transition()) { + pagination_model_->SelectPageRelative(offset_magnitude > 0 ? -1 : 1, + true); + } + return true; + } + + return false; +} + +bool PaginationController::OnGestureEvent(const ui::GestureEvent& event, + const gfx::Rect& bounds) { + const ui::GestureEventDetails& details = event.details(); + switch (event.type()) { + case ui::ET_GESTURE_SCROLL_BEGIN: + pagination_model_->StartScroll(); + return true; + case ui::ET_GESTURE_SCROLL_UPDATE: { + float scroll = scroll_axis_ == SCROLL_AXIS_HORIZONTAL + ? details.scroll_x() + : details.scroll_y(); + int width = scroll_axis_ == SCROLL_AXIS_HORIZONTAL ? bounds.width() + : bounds.height(); + // scroll > 0 means moving contents right or down. That is, transitioning + // to the previous page. + pagination_model_->UpdateScroll(scroll / width); + return true; + } + case ui::ET_GESTURE_SCROLL_END: + pagination_model_->EndScroll(pagination_model_->transition().progress < + kFinishTransitionThreshold); + return true; + case ui::ET_SCROLL_FLING_START: { + float velocity = scroll_axis_ == SCROLL_AXIS_HORIZONTAL + ? details.velocity_x() + : details.velocity_y(); + pagination_model_->EndScroll(true); + if (fabs(velocity) > kMinHorizVelocityToSwitchPage) + pagination_model_->SelectPageRelative(velocity < 0 ? 1 : -1, true); + return true; + } + default: + return false; + } +} + +} // namespace app_list diff --git a/ui/app_list/pagination_controller.h b/ui/app_list/pagination_controller.h new file mode 100644 index 0000000..78501d4 --- /dev/null +++ b/ui/app_list/pagination_controller.h @@ -0,0 +1,52 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_APP_LIST_PAGINATION_CONTROLLER_H_ +#define UI_APP_LIST_PAGINATION_CONTROLLER_H_ + +#include "ui/app_list/app_list_export.h" + +namespace gfx { +class Vector2d; +class Rect; +} + +namespace ui { +class GestureEvent; +} + +namespace app_list { + +class PaginationModel; + +// Receives user scroll events from various sources (mouse wheel, touchpad, +// touch gestures) and manipulates a PaginationModel as necessary. +class APP_LIST_EXPORT PaginationController { + public: + enum ScrollAxis { SCROLL_AXIS_HORIZONTAL, SCROLL_AXIS_VERTICAL }; + + // Creates a PaginationController. Does not take ownership of |model|. The + // |model| is required to outlive this PaginationController. |scroll_axis| + // specifies the axis in which the pages will scroll. + PaginationController(PaginationModel* model, ScrollAxis scroll_axis); + + ScrollAxis scroll_axis() const { return scroll_axis_; } + + // Handles a mouse wheel or touchpad scroll event in the area represented by + // the PaginationModel. |offset| is the number of units scrolled in each axis. + // Returns true if the event was captured and there was some room to scroll. + bool OnScroll(const gfx::Vector2d& offset); + + // Handles a touch gesture event in the area represented by the + // PaginationModel. Returns true if the event was captured. + bool OnGestureEvent(const ui::GestureEvent& event, const gfx::Rect& bounds); + + private: + PaginationModel* pagination_model_; // Not owned. + ScrollAxis scroll_axis_; +}; + +} // namespace app_list + +#endif // UI_APP_LIST_PAGINATION_CONTROLLER_H_ diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc index 3266fa4..1a7270d 100644 --- a/ui/app_list/views/apps_grid_view.cc +++ b/ui/app_list/views/apps_grid_view.cc @@ -13,6 +13,7 @@ #include "ui/app_list/app_list_folder_item.h" #include "ui/app_list/app_list_item.h" #include "ui/app_list/app_list_switches.h" +#include "ui/app_list/pagination_controller.h" #include "ui/app_list/views/app_list_drag_and_drop_host.h" #include "ui/app_list/views/app_list_folder_view.h" #include "ui/app_list/views/app_list_item_view.h" @@ -23,6 +24,8 @@ #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/events/event.h" #include "ui/gfx/animation/animation.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/geometry/vector2d_conversions.h" #include "ui/views/border.h" #include "ui/views/view_model_utils.h" #include "ui/views/widget/widget.h" @@ -92,13 +95,6 @@ const int kFolderItemReparentDelay = 50; // UI. const int kFolderDroppingCircleRadius = 15; -// Constants for dealing with scroll events. -const int kMinMouseWheelToSwitchPage = 20; -const int kMinScrollToSwitchPage = 20; -const int kMinHorizVelocityToSwitchPage = 800; - -const double kFinishTransitionThreshold = 0.33; - // RowMoveAnimationDelegate is used when moving an item into a different row. // Before running the animation, the item's layer is re-created and kept in // the original position, then the item is moved to just before its target @@ -369,6 +365,13 @@ AppsGridView::AppsGridView(AppsGridViewDelegate* delegate) kOverscrollPageTransitionDurationMs); pagination_model_.AddObserver(this); + // The experimental app list transitions vertically. + PaginationController::ScrollAxis scroll_axis = + app_list::switches::IsExperimentalAppListEnabled() + ? PaginationController::SCROLL_AXIS_VERTICAL + : PaginationController::SCROLL_AXIS_HORIZONTAL; + pagination_controller_.reset( + new PaginationController(&pagination_model_, scroll_axis)); page_switcher_view_ = new PageSwitcher(&pagination_model_); AddChildView(page_switcher_view_); } @@ -961,27 +964,8 @@ bool AppsGridView::OnKeyReleased(const ui::KeyEvent& event) { } bool AppsGridView::OnMouseWheel(const ui::MouseWheelEvent& event) { - int offset; - if (GetScrollAxis() == SCROLL_AXIS_HORIZONTAL) { - // If the view scrolls horizontally, both horizontal and vertical scroll - // events are valid (since most mouse wheels only have vertical scrolling). - if (abs(event.x_offset()) > abs(event.y_offset())) - offset = event.x_offset(); - else - offset = event.y_offset(); - } else { - // If the view scrolls vertically, only vertical scroll events are valid. - offset = event.y_offset(); - } - - if (abs(offset) > kMinMouseWheelToSwitchPage) { - if (!pagination_model_.has_transition()) { - pagination_model_.SelectPageRelative(offset > 0 ? -1 : 1, true); - } - return true; - } - - return false; + return pagination_controller_->OnScroll( + gfx::Vector2d(event.x_offset(), event.y_offset())); } void AppsGridView::ViewHierarchyChanged( @@ -1003,66 +987,16 @@ void AppsGridView::ViewHierarchyChanged( } void AppsGridView::OnGestureEvent(ui::GestureEvent* event) { - const ui::GestureEventDetails& details = event->details(); - switch (event->type()) { - case ui::ET_GESTURE_SCROLL_BEGIN: - pagination_model_.StartScroll(); - event->SetHandled(); - return; - case ui::ET_GESTURE_SCROLL_UPDATE: { - float scroll = GetScrollAxis() == SCROLL_AXIS_HORIZONTAL - ? details.scroll_x() - : details.scroll_y(); - gfx::Rect bounds(GetContentsBounds()); - int size = GetScrollAxis() == SCROLL_AXIS_HORIZONTAL ? bounds.width() - : bounds.height(); - // scroll > 0 means moving contents right or down. That is, transitioning - // to the previous page. - pagination_model_.UpdateScroll(scroll / size); - event->SetHandled(); - return; - } - case ui::ET_GESTURE_SCROLL_END: - pagination_model_.EndScroll(pagination_model_.transition().progress < - kFinishTransitionThreshold); - event->SetHandled(); - return; - case ui::ET_SCROLL_FLING_START: { - float velocity = GetScrollAxis() == SCROLL_AXIS_HORIZONTAL - ? details.velocity_x() - : details.velocity_y(); - pagination_model_.EndScroll(true); - if (fabs(velocity) > kMinHorizVelocityToSwitchPage) - pagination_model_.SelectPageRelative(velocity < 0 ? 1 : -1, true); - event->SetHandled(); - return; - } - default: - break; - } + if (pagination_controller_->OnGestureEvent(*event, GetContentsBounds())) + event->SetHandled(); } void AppsGridView::OnScrollEvent(ui::ScrollEvent* event) { if (event->type() == ui::ET_SCROLL_FLING_CANCEL) return; - float offset; - if (GetScrollAxis() == SCROLL_AXIS_HORIZONTAL) { - // If the view scrolls horizontally, both horizontal and vertical scroll - // events are valid (vertical scroll events simulate mouse wheel). - if (std::abs(event->x_offset()) > std::abs(event->y_offset())) - offset = event->x_offset(); - else - offset = event->y_offset(); - } else { - // If the view scrolls vertically, only vertical scroll events are valid. - offset = event->y_offset(); - } - - if (std::abs(offset) > kMinScrollToSwitchPage) { - if (!pagination_model_.has_transition()) { - pagination_model_.SelectPageRelative(offset > 0 ? -1 : 1, true); - } + gfx::Vector2dF offset(event->x_offset(), event->y_offset()); + if (pagination_controller_->OnScroll(gfx::ToFlooredVector2d(offset))) { event->SetHandled(); event->StopPropagation(); } @@ -1270,7 +1204,8 @@ void AppsGridView::CalculateIdealBounds() { int x_offset = 0; int y_offset = 0; - if (GetScrollAxis() == SCROLL_AXIS_HORIZONTAL) { + if (pagination_controller_->scroll_axis() == + PaginationController::SCROLL_AXIS_HORIZONTAL) { if (view_index.page < current_page) x_offset = -page_width; else if (view_index.page > current_page) @@ -2289,12 +2224,4 @@ void AppsGridView::SetAsFolderDroppingTarget(const Index& target_index, target_view->SetAsAttemptedFolderTarget(is_target_folder); } -// static -AppsGridView::ScrollAxis AppsGridView::GetScrollAxis() { - // The experimental app list transitions vertically. - return app_list::switches::IsExperimentalAppListEnabled() - ? SCROLL_AXIS_VERTICAL - : SCROLL_AXIS_HORIZONTAL; -} - } // namespace app_list diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h index 546d1f8..17cb798 100644 --- a/ui/app_list/views/apps_grid_view.h +++ b/ui/app_list/views/apps_grid_view.h @@ -50,7 +50,7 @@ class AppListItemView; class AppsGridViewDelegate; class AppsGridViewFolderDelegate; class PageSwitcher; -class PaginationModel; +class PaginationController; // AppsGridView displays a grid for AppListItemList sub model. class APP_LIST_EXPORT AppsGridView : public views::View, @@ -224,8 +224,6 @@ class APP_LIST_EXPORT AppsGridView : public views::View, DROP_FOR_FOLDER, }; - enum ScrollAxis { SCROLL_AXIS_HORIZONTAL, SCROLL_AXIS_VERTICAL }; - // Represents the index to an item view in the grid. struct Index { Index() : page(-1), slot(-1) {} @@ -461,9 +459,6 @@ class APP_LIST_EXPORT AppsGridView : public views::View, const base::FilePath& path); #endif - // Determines whether the grid view scrolls horizontally or vertically. - static ScrollAxis GetScrollAxis(); - AppListModel* model_; // Owned by AppListView. AppListItemList* item_list_; // Not owned. AppsGridViewDelegate* delegate_; @@ -472,6 +467,8 @@ class APP_LIST_EXPORT AppsGridView : public views::View, AppsGridViewFolderDelegate* folder_delegate_; PaginationModel pagination_model_; + // Must appear after |pagination_model_|. + scoped_ptr<PaginationController> pagination_controller_; PageSwitcher* page_switcher_view_; // Owned by views hierarchy. int cols_; |