summaryrefslogtreecommitdiffstats
path: root/ui/app_list
diff options
context:
space:
mode:
authortapted@chromium.org <tapted@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-18 09:31:26 +0000
committertapted@chromium.org <tapted@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-18 09:31:26 +0000
commitf3cee40e60f6970acdc6418a2e00783e8d2e8499 (patch)
treec11f71eb745e2d8c5db9776f3d7077c73c99a411 /ui/app_list
parentcfb339d1e691ebb4c88b415e38c342e184a053a4 (diff)
downloadchromium_src-f3cee40e60f6970acdc6418a2e00783e8d2e8499.zip
chromium_src-f3cee40e60f6970acdc6418a2e00783e8d2e8499.tar.gz
chromium_src-f3cee40e60f6970acdc6418a2e00783e8d2e8499.tar.bz2
Allow pages on the OSX app launcher to be turned while dragging.
Adds an interface to the AppsGridController to optionally trigger a page scroll after a delay, when given a drag location. Scrolling is triggered if the point is to either side of the grid view, or over a pager segment. BUG=138633 TEST=Added: app_list_unittests AppsGridControllerTest.ScrollingWhileDragging. Manually, test by dragging items on the OSX app launcher past the left or right side, or over a pager segment, to initiate page scrolling after a 1 second delay. Review URL: https://chromiumcodereview.appspot.com/14999013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@200987 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/app_list')
-rw-r--r--ui/app_list/cocoa/app_list_pager_view.h4
-rw-r--r--ui/app_list/cocoa/app_list_pager_view.mm16
-rw-r--r--ui/app_list/cocoa/app_list_view_controller.h3
-rw-r--r--ui/app_list/cocoa/app_list_view_controller.mm19
-rw-r--r--ui/app_list/cocoa/app_list_view_controller_unittest.mm1
-rw-r--r--ui/app_list/cocoa/apps_collection_view_drag_manager.mm7
-rw-r--r--ui/app_list/cocoa/apps_grid_controller.h14
-rw-r--r--ui/app_list/cocoa/apps_grid_controller.mm68
-rw-r--r--ui/app_list/cocoa/apps_grid_controller_unittest.mm125
-rw-r--r--ui/app_list/cocoa/apps_pagination_model_observer.h3
-rw-r--r--ui/app_list/cocoa/test/apps_grid_controller_test_helper.mm1
11 files changed, 226 insertions, 35 deletions
diff --git a/ui/app_list/cocoa/app_list_pager_view.h b/ui/app_list/cocoa/app_list_pager_view.h
index b896831..0dcc44d 100644
--- a/ui/app_list/cocoa/app_list_pager_view.h
+++ b/ui/app_list/cocoa/app_list_pager_view.h
@@ -34,6 +34,10 @@
NSInteger hoveredSegment_;
}
+// Returns -1 if |locationInWindow| is not over a segment. Otherwise returns the
+// segment index and highlights it.
+- (NSInteger)findAndHighlightSegmentAtLocation:(NSPoint)locationInWindow;
+
@end
#endif // UI_APP_LIST_COCOA_APP_LIST_PAGER_VIEW_H_
diff --git a/ui/app_list/cocoa/app_list_pager_view.mm b/ui/app_list/cocoa/app_list_pager_view.mm
index 28a971e..70cd9e4 100644
--- a/ui/app_list/cocoa/app_list_pager_view.mm
+++ b/ui/app_list/cocoa/app_list_pager_view.mm
@@ -21,7 +21,7 @@ const CGFloat kButtonStripPadding = 20;
@property(assign, nonatomic) NSInteger hoveredSegment;
-- (NSInteger)segmentUnderEvent:(NSEvent*)theEvent;
+- (NSInteger)segmentUnderLocation:(NSPoint)locationInWindow;
@end
@@ -52,6 +52,12 @@ const CGFloat kButtonStripPadding = 20;
return self;
}
+- (NSInteger)findAndHighlightSegmentAtLocation:(NSPoint)locationInWindow {
+ NSInteger segment = [self segmentUnderLocation:locationInWindow];
+ [self setHoveredSegment:segment];
+ return segment;
+}
+
- (void)setHoveredSegment:(NSInteger)segment {
if (segment == hoveredSegment_)
return;
@@ -61,11 +67,11 @@ const CGFloat kButtonStripPadding = 20;
return;
}
-- (NSInteger)segmentUnderEvent:(NSEvent*)theEvent {
+- (NSInteger)segmentUnderLocation:(NSPoint)locationInWindow {
if ([self segmentCount] == 0)
return -1;
- NSPoint pointInView = [self convertPoint:[theEvent locationInWindow]
+ NSPoint pointInView = [self convertPoint:locationInWindow
fromView:nil];
if (![self mouse:pointInView inRect:[self bounds]])
return -1;
@@ -83,7 +89,7 @@ const CGFloat kButtonStripPadding = 20;
}
- (void)mouseMoved:(NSEvent*)theEvent {
- [self setHoveredSegment:[self segmentUnderEvent:theEvent]];
+ [self findAndHighlightSegmentAtLocation:[theEvent locationInWindow]];
}
- (void)mouseDown:(NSEvent*)theEvent {
@@ -94,7 +100,7 @@ const CGFloat kButtonStripPadding = 20;
// The stock NSSegmentedControl ignores any clicks outside the non-default
// control height, so process all clicks here.
- (void)mouseUp:(NSEvent*)theEvent {
- [self setHoveredSegment:[self segmentUnderEvent:theEvent]];
+ [self findAndHighlightSegmentAtLocation:[theEvent locationInWindow]];
if (hoveredSegment_ < 0)
return;
diff --git a/ui/app_list/cocoa/app_list_view_controller.h b/ui/app_list/cocoa/app_list_view_controller.h
index f18c37c..80095423 100644
--- a/ui/app_list/cocoa/app_list_view_controller.h
+++ b/ui/app_list/cocoa/app_list_view_controller.h
@@ -17,6 +17,7 @@ class AppListViewDelegate;
}
@class AppsGridController;
+@class AppListPagerView;
// Controller for the top-level view of the app list UI. It creates and hosts an
// AppsGridController (displaying an AppListModel), and pager control for
@@ -26,7 +27,7 @@ APP_LIST_EXPORT
NSViewController<AppsPaginationModelObserver, NSTextFieldDelegate> {
@private
scoped_nsobject<AppsGridController> appsGridController_;
- scoped_nsobject<NSSegmentedControl> pagerControl_;
+ scoped_nsobject<AppListPagerView> pagerControl_;
scoped_ptr<app_list::AppListViewDelegate> delegate_;
}
diff --git a/ui/app_list/cocoa/app_list_view_controller.mm b/ui/app_list/cocoa/app_list_view_controller.mm
index e9d5ed1..7bfd2d5 100644
--- a/ui/app_list/cocoa/app_list_view_controller.mm
+++ b/ui/app_list/cocoa/app_list_view_controller.mm
@@ -18,8 +18,6 @@ const CGFloat kBubbleCornerRadius = 3;
// Height of the pager.
const CGFloat kPagerPreferredHeight = 57;
-// Padding between the bottom of the grid and the bottom of the view.
-const CGFloat kViewGridOffsetY = 41;
// Padding between the top of the grid and the top of the view.
// TODO(tapted): Update padding when the search entry control is added.
@@ -52,6 +50,10 @@ const CGFloat kMaxSegmentWidth = 80;
[NSGraphicsContext restoreGraphicsState];
}
+- (BOOL)isFlipped {
+ return YES;
+}
+
@end
@interface AppListViewController ()
@@ -105,16 +107,15 @@ const CGFloat kMaxSegmentWidth = 80;
[pagerControl_ setTarget:appsGridController_];
[pagerControl_ setAction:@selector(onPagerClicked:)];
- [[appsGridController_ view] setFrameOrigin:NSMakePoint(0, kViewGridOffsetY)];
+ [[appsGridController_ view] setFrameOrigin:NSMakePoint(0, kTopPadding)];
NSRect backgroundRect = [[appsGridController_ view] bounds];
- backgroundRect.size.height += kViewGridOffsetY + kTopPadding;
+ backgroundRect.size.height += kPagerPreferredHeight;
scoped_nsobject<BackgroundView> backgroundView(
[[BackgroundView alloc] initWithFrame:backgroundRect]);
NSRect searchInputRect =
- NSMakeRect(0, NSMaxY(backgroundRect) - kSearchInputHeight,
- backgroundRect.size.width, kSearchInputHeight);
+ NSMakeRect(0, 0, backgroundRect.size.width, kSearchInputHeight);
scoped_nsobject<NSTextField> searchInput(
[[NSTextField alloc] initWithFrame:searchInputRect]);
[searchInput setDelegate:self];
@@ -145,7 +146,7 @@ const CGFloat kMaxSegmentWidth = 80;
[pagerControl_ sizeToFit];
[pagerControl_ setFrame:
NSMakeRect(NSMidX(viewFrame) - NSMidX([pagerControl_ bounds]),
- 0,
+ viewFrame.size.height - kPagerPreferredHeight,
[pagerControl_ bounds].size.width,
kPagerPreferredHeight)];
}
@@ -158,6 +159,10 @@ const CGFloat kMaxSegmentWidth = 80;
[pagerControl_ setNeedsDisplay:YES];
}
+- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow {
+ return [pagerControl_ findAndHighlightSegmentAtLocation:locationInWindow];
+}
+
- (BOOL)control:(NSControl*)control
textView:(NSTextView*)textView
doCommandBySelector:(SEL)command {
diff --git a/ui/app_list/cocoa/app_list_view_controller_unittest.mm b/ui/app_list/cocoa/app_list_view_controller_unittest.mm
index a2f9fa2..eb3a807 100644
--- a/ui/app_list/cocoa/app_list_view_controller_unittest.mm
+++ b/ui/app_list/cocoa/app_list_view_controller_unittest.mm
@@ -58,7 +58,6 @@ TEST_F(AppListViewControllerTest, PagerSegmentCounts) {
// Test that clicking the pager changes pages.
TEST_F(AppListViewControllerTest, PagerChangingPage) {
- [AppsGridController setScrollAnimationDuration:0.0];
NSSegmentedControl* pager = [app_list_view_controller_ pagerControl];
ReplaceTestModel(kItemsPerPage * 3);
EXPECT_EQ(3, [pager segmentCount]);
diff --git a/ui/app_list/cocoa/apps_collection_view_drag_manager.mm b/ui/app_list/cocoa/apps_collection_view_drag_manager.mm
index ba5200f3..42b955a 100644
--- a/ui/app_list/cocoa/apps_collection_view_drag_manager.mm
+++ b/ui/app_list/cocoa/apps_collection_view_drag_manager.mm
@@ -145,7 +145,7 @@ const CGFloat kDragThreshold = 5;
if (!itemDragController_) {
itemDragController_.reset(
[[ItemDragController alloc] initWithGridCellSize:cellSize_]);
- [[gridController_ view] addSubview:[itemDragController_ view]];
+ [[[gridController_ view] superview] addSubview:[itemDragController_ view]];
}
[itemDragController_ initiate:[gridController_ itemAtIndex:itemHitIndex_]
@@ -160,6 +160,8 @@ const CGFloat kDragThreshold = 5;
- (void)updateDrag:(NSEvent*)theEvent {
[itemDragController_ update:[theEvent locationInWindow]
timestamp:[theEvent timestamp]];
+ [gridController_ maybeChangePageForPoint:[theEvent locationInWindow]];
+
size_t visiblePage = [gridController_ visiblePage];
size_t itemIndexOver = [self itemIndexForPage:visiblePage
hitWithEvent:theEvent];
@@ -195,6 +197,7 @@ const CGFloat kDragThreshold = 5;
- (void)completeDrag {
DCHECK_GE(itemDragIndex_, 0u);
+ [gridController_ cancelScrollTimer];
AppsGridViewItem* item = [gridController_ itemAtIndex:itemDragIndex_];
// The item could still be animating in the NSCollectionView, so ask it where
@@ -202,7 +205,7 @@ const CGFloat kDragThreshold = 5;
NSCollectionView* pageView = base::mac::ObjCCastStrict<NSCollectionView>(
[[item view] superview]);
size_t indexInPage = itemDragIndex_ % (rows_ * columns_);
- NSPoint targetOrigin = [[gridController_ view]
+ NSPoint targetOrigin = [[[itemDragController_ view] superview]
convertPoint:[pageView frameForItemAtIndex:indexInPage].origin
fromView:pageView];
diff --git a/ui/app_list/cocoa/apps_grid_controller.h b/ui/app_list/cocoa/apps_grid_controller.h
index 0852983..4fb2d6e 100644
--- a/ui/app_list/cocoa/apps_grid_controller.h
+++ b/ui/app_list/cocoa/apps_grid_controller.h
@@ -35,11 +35,16 @@ APP_LIST_EXPORT
scoped_nsobject<AppsCollectionViewDragManager> dragManager_;
scoped_nsobject<NSMutableArray> pages_;
scoped_nsobject<NSMutableArray> items_;
+ scoped_nsobject<NSTimer> scrollWhileDraggingTimer_;
id<AppsPaginationModelObserver> paginationObserver_;
// Index of the currently visible page.
size_t visiblePage_;
+ // The page to which the view is currently animating a scroll.
+ size_t targetScrollPage_;
+ // The page to start scrolling to when the timer expires.
+ size_t scheduledScrollPage_;
// Whether we are currently animating a scroll to the nearest page.
BOOL animatingScroll_;
@@ -75,6 +80,14 @@ APP_LIST_EXPORT
// Scroll to a page in the grid view with an animation.
- (void)scrollToPage:(size_t)pageIndex;
+// Start a timer to scroll to a new page, if |locationInWindow| is to the left
+// or the right of the view, or if it is over a pager segment. Cancels any
+// existing timer if the target page changes.
+- (void)maybeChangePageForPoint:(NSPoint)locationInWindow;
+
+// Cancel a timer that may have been set by maybeChangePageForPoint().
+- (void)cancelScrollTimer;
+
// Moves an item within the view only, for dragging or in response to model
// changes.
- (void)moveItemInView:(size_t)fromIndex
@@ -101,6 +114,7 @@ APP_LIST_EXPORT
@interface AppsGridController(TestingAPI)
- (AppsCollectionViewDragManager*)dragManager;
+- (size_t)scheduledScrollPage;
@end
diff --git a/ui/app_list/cocoa/apps_grid_controller.mm b/ui/app_list/cocoa/apps_grid_controller.mm
index fc101554..795979a 100644
--- a/ui/app_list/cocoa/apps_grid_controller.mm
+++ b/ui/app_list/cocoa/apps_grid_controller.mm
@@ -33,12 +33,16 @@ const CGFloat kViewWidth =
kFixedColumns * kPreferredTileWidth + 2 * kLeftRightPadding;
const CGFloat kViewHeight = kFixedRows * kPreferredTileHeight;
+const NSTimeInterval kScrollWhileDraggingDelay = 1.0;
NSTimeInterval g_scroll_duration = 0.18;
} // namespace
@interface AppsGridController ()
+- (void)scrollToPageWithTimer:(size_t)targetPage;
+- (void)onTimer:(NSTimer*)theTimer;
+
// Cancel a currently running scroll animation.
- (void)cancelScrollAnimation;
@@ -245,6 +249,66 @@ class AppsGridDelegateBridge : public ui::ListModelObserver {
[[clipView animator] setBoundsOrigin:newOrigin];
[NSAnimationContext endGrouping];
animatingScroll_ = YES;
+ targetScrollPage_ = pageIndex;
+ [self cancelScrollTimer];
+}
+
+- (void)maybeChangePageForPoint:(NSPoint)locationInWindow {
+ NSPoint pointInView = [[self view] convertPoint:locationInWindow
+ fromView:nil];
+ // Check if the point is outside the view on the left or right.
+ if (pointInView.x <= 0 || pointInView.x >= NSWidth([[self view] bounds])) {
+ size_t targetPage = visiblePage_;
+ if (pointInView.x <= 0)
+ targetPage -= targetPage != 0 ? 1 : 0;
+ else
+ targetPage += targetPage < [pages_ count] - 1 ? 1 : 0;
+ [self scrollToPageWithTimer:targetPage];
+ return;
+ }
+
+ if (paginationObserver_) {
+ NSInteger segment =
+ [paginationObserver_ pagerSegmentAtLocation:locationInWindow];
+ if (segment >= 0 && static_cast<size_t>(segment) != targetScrollPage_) {
+ [self scrollToPageWithTimer:segment];
+ return;
+ }
+ }
+
+ // Otherwise the point may have moved back into the view.
+ [self cancelScrollTimer];
+}
+
+- (void)cancelScrollTimer {
+ scheduledScrollPage_ = targetScrollPage_;
+ [scrollWhileDraggingTimer_ invalidate];
+}
+
+- (void)scrollToPageWithTimer:(size_t)targetPage {
+ if (targetPage == targetScrollPage_) {
+ [self cancelScrollTimer];
+ return;
+ }
+
+ if (targetPage == scheduledScrollPage_)
+ return;
+
+ scheduledScrollPage_ = targetPage;
+ [scrollWhileDraggingTimer_ invalidate];
+ scrollWhileDraggingTimer_.reset(
+ [[NSTimer scheduledTimerWithTimeInterval:kScrollWhileDraggingDelay
+ target:self
+ selector:@selector(onTimer:)
+ userInfo:nil
+ repeats:NO] retain]);
+}
+
+- (void)onTimer:(NSTimer*)theTimer {
+ if (scheduledScrollPage_ == targetScrollPage_)
+ return; // Already animating scroll.
+
+ [self scrollToPage:scheduledScrollPage_];
}
- (void)cancelScrollAnimation {
@@ -468,6 +532,10 @@ class AppsGridDelegateBridge : public ui::ListModelObserver {
return dragManager_;
}
+- (size_t)scheduledScrollPage {
+ return scheduledScrollPage_;
+}
+
- (void)listItemsAdded:(size_t)start
count:(size_t)count {
// Cancel any drag, to ensure the model stays consistent.
diff --git a/ui/app_list/cocoa/apps_grid_controller_unittest.mm b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
index cae0643..43cd5e7 100644
--- a/ui/app_list/cocoa/apps_grid_controller_unittest.mm
+++ b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
@@ -16,12 +16,14 @@
@interface TestPaginationObserver : NSObject<AppsPaginationModelObserver> {
@private
+ NSInteger hoveredSegmentForTest_;
int totalPagesChangedCount_;
int selectedPageChangedCount_;
int lastNewSelectedPage_;
bool visibilityDidChange_;
}
+@property(assign, nonatomic) NSInteger hoveredSegmentForTest;
@property(assign, nonatomic) int totalPagesChangedCount;
@property(assign, nonatomic) int selectedPageChangedCount;
@property(assign, nonatomic) int lastNewSelectedPage;
@@ -32,10 +34,18 @@
@implementation TestPaginationObserver
+@synthesize hoveredSegmentForTest = hoveredSegmentForTest_;
@synthesize totalPagesChangedCount = totalPagesChangedCount_;
@synthesize selectedPageChangedCount = selectedPageChangedCount_;
@synthesize lastNewSelectedPage = lastNewSelectedPage_;
+- (id)init {
+ if ((self = [super init]))
+ hoveredSegmentForTest_ = -1;
+
+ return self;
+}
+
- (bool)readVisibilityDidChange {
bool truth = visibilityDidChange_;
visibilityDidChange_ = false;
@@ -55,6 +65,10 @@
visibilityDidChange_ = true;
}
+- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow {
+ return hoveredSegmentForTest_;
+}
+
@end
namespace app_list {
@@ -88,6 +102,26 @@ class AppsGridControllerTest : public AppsGridControllerTestHelper {
DISALLOW_COPY_AND_ASSIGN(AppsGridControllerTest);
};
+// Generate a mouse event at the centre of the view in |page| with the given
+// |index_in_page| that can be used to initiate, update and complete drag
+// operations.
+NSEvent* MouseEventInCell(NSCollectionView* page, size_t index_in_page) {
+ NSRect cell_rect = [page frameForItemAtIndex:index_in_page];
+ NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect));
+ NSPoint point_in_window = [page convertPoint:point_in_view
+ toView:nil];
+ return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
+}
+
+NSEvent* MouseEventForScroll(NSView* view, CGFloat relative_x) {
+ NSRect view_rect = [view frame];
+ NSPoint point_in_view = NSMakePoint(NSMidX(view_rect), NSMidY(view_rect));
+ point_in_view.x += point_in_view.x * relative_x;
+ NSPoint point_in_window = [view convertPoint:point_in_view
+ toView:nil];
+ return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
+}
+
} // namespace
TEST_VIEW(AppsGridControllerTest, [apps_grid_controller_ view]);
@@ -226,8 +260,6 @@ TEST_F(AppsGridControllerTest, FirstPageKeyboardNavigation) {
// Tests keyboard navigation across pages.
TEST_F(AppsGridControllerTest, CrossPageKeyboardNavigation) {
- [AppsGridController setScrollAnimationDuration:0.0];
-
model()->PopulateApps(2 * kItemsPerPage);
EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
EXPECT_EQ(kItemsPerPage, [[GetPageAt(1) content] count]);
@@ -460,7 +492,6 @@ TEST_F(AppsGridControllerTest, PaginationObserverPagesChanged) {
// Test AppsGridPaginationObserver selectedPageChanged().
TEST_F(AppsGridControllerTest, PaginationObserverSelectedPageChanged) {
- [AppsGridController setScrollAnimationDuration:0.0];
scoped_nsobject<TestPaginationObserver> observer(
[[TestPaginationObserver alloc] init]);
[apps_grid_controller_ setPaginationObserver:observer];
@@ -503,21 +534,6 @@ TEST_F(AppsGridControllerTest, PaginationObserverSelectedPageChanged) {
[apps_grid_controller_ setPaginationObserver:nil];
}
-namespace {
-
-// Generate a mouse event at the centre of the view in |page| with the given
-// |index_in_page| that can be used to initiate, update and complete drag
-// operations.
-NSEvent* MouseEventInCell(NSCollectionView* page, size_t index_in_page) {
- NSRect cell_rect = [page frameForItemAtIndex:index_in_page];
- NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect));
- NSPoint point_in_window = [page convertPoint:point_in_view
- toView:nil];
- return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
-}
-
-} // namespace
-
// Test basic item moves with two items; swapping them around, dragging outside
// of the view bounds, and dragging on the background.
TEST_F(AppsGridControllerTest, DragAndDropSimple) {
@@ -625,7 +641,6 @@ TEST_F(AppsGridControllerTest, DragAndDropSimple) {
// Test item moves between pages.
TEST_F(AppsGridControllerTest, DragAndDropMultiPage) {
- [AppsGridController setScrollAnimationDuration:0.0];
const size_t kPagesToTest = 3;
// Put one item on the last page to hit more edge cases.
ReplaceTestModel(kItemsPerPage * (kPagesToTest - 1) + 1);
@@ -696,5 +711,77 @@ TEST_F(AppsGridControllerTest, DragAndDropMultiPage) {
EXPECT_EQ(0u, GetPageIndexForItem(1));
}
+// Test scrolling when dragging past edge or over the pager.
+TEST_F(AppsGridControllerTest, ScrollingWhileDragging) {
+ scoped_nsobject<TestPaginationObserver> observer(
+ [[TestPaginationObserver alloc] init]);
+ [apps_grid_controller_ setPaginationObserver:observer];
+
+ ReplaceTestModel(kItemsPerPage * 3);
+ // Start on the middle page.
+ [apps_grid_controller_ scrollToPage:1];
+ NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:1];
+ NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
+
+ NSEvent* at_center = MouseEventForScroll([apps_grid_controller_ view], 0.0);
+ NSEvent* at_left = MouseEventForScroll([apps_grid_controller_ view], -1.1);
+ NSEvent* at_right = MouseEventForScroll([apps_grid_controller_ view], 1.1);
+
+ AppsCollectionViewDragManager* drag_manager =
+ [apps_grid_controller_ dragManager];
+ [drag_manager onMouseDownInPage:page
+ withEvent:mouse_at_cell_0];
+ [drag_manager onMouseDragged:at_center];
+
+ // Nothing should be scheduled: target page is visible page.
+ EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
+
+ // Drag to the left, should go to first page and no further.
+ [drag_manager onMouseDragged:at_left];
+ EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
+ [apps_grid_controller_ scrollToPage:0]; // Commit without timer for testing.
+ [drag_manager onMouseDragged:at_left];
+ EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
+
+ // Drag to the right, should go to last page and no futher.
+ [drag_manager onMouseDragged:at_right];
+ EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
+ [apps_grid_controller_ scrollToPage:1];
+ [drag_manager onMouseDragged:at_right];
+ EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
+ [apps_grid_controller_ scrollToPage:2];
+ [drag_manager onMouseDragged:at_right];
+ EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
+
+ // Simulate a hover over the first pager segment.
+ [observer setHoveredSegmentForTest:0];
+ [drag_manager onMouseDragged:at_center];
+ EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
+
+ // Drag it back, should cancel schedule.
+ [observer setHoveredSegmentForTest:-1];
+ [drag_manager onMouseDragged:at_center];
+ EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
+
+ // Hover again, now over middle segment, and ensure a release also cancels.
+ [observer setHoveredSegmentForTest:1];
+ [drag_manager onMouseDragged:at_center];
+ EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
+ [drag_manager onMouseUp:at_center];
+ EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
+ EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
+
+ [apps_grid_controller_ setPaginationObserver:nil];
+}
+
} // namespace test
} // namespace app_list
diff --git a/ui/app_list/cocoa/apps_pagination_model_observer.h b/ui/app_list/cocoa/apps_pagination_model_observer.h
index 397b79b..c5685e0 100644
--- a/ui/app_list/cocoa/apps_pagination_model_observer.h
+++ b/ui/app_list/cocoa/apps_pagination_model_observer.h
@@ -18,6 +18,9 @@
// Invoked when the portion of pages that are visible have changed.
- (void)pageVisibilityChanged;
+// Return a pager segment at |locationInWindow| or -1 if there is none.
+- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow;
+
@end
#endif // UI_APP_LIST_COCOA_APP_LIST_APPS_PAGINATION_MODEL_OBSERVER_H_
diff --git a/ui/app_list/cocoa/test/apps_grid_controller_test_helper.mm b/ui/app_list/cocoa/test/apps_grid_controller_test_helper.mm
index 19e2790..1fb663b 100644
--- a/ui/app_list/cocoa/test/apps_grid_controller_test_helper.mm
+++ b/ui/app_list/cocoa/test/apps_grid_controller_test_helper.mm
@@ -21,6 +21,7 @@ const size_t AppsGridControllerTestHelper::kItemsPerPage = 16;
AppsGridControllerTestHelper::AppsGridControllerTestHelper() {
Init();
delegate_.reset(new AppListTestViewDelegate);
+ [AppsGridController setScrollAnimationDuration:0.0];
}
AppsGridControllerTestHelper::~AppsGridControllerTestHelper() {}