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

Side by Side Diff: ui/app_list/cocoa/apps_grid_controller.mm

Issue 187483005: Extending the Views-on-Mac experiment: whole app list grid. Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: still compiles r263560 + crrev/195793005 Created 6 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ui/app_list/cocoa/apps_grid_controller.h" 5 #import "ui/app_list/cocoa/apps_grid_controller.h"
6 6
7 #include "base/mac/foundation_util.h" 7 #include "base/mac/foundation_util.h"
8 #include "ui/app_list/app_list_item.h" 8 #include "ui/app_list/app_list_item.h"
9 #include "ui/app_list/app_list_model.h" 9 #include "ui/app_list/app_list_model.h"
10 #include "ui/app_list/app_list_model_observer.h" 10 #include "ui/app_list/app_list_model_observer.h"
11 #include "ui/app_list/app_list_view_delegate.h" 11 #include "ui/app_list/app_list_view_delegate.h"
12 #import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
13 #import "ui/app_list/cocoa/apps_grid_view_item.h"
14 #import "ui/app_list/cocoa/apps_pagination_model_observer.h" 12 #import "ui/app_list/cocoa/apps_pagination_model_observer.h"
13 #include "ui/app_list/pagination_model.h"
14 #include "ui/app_list/views/apps_grid_view.h"
15 #include "ui/app_list/views/apps_grid_view_delegate.h"
15 #include "ui/base/models/list_model_observer.h" 16 #include "ui/base/models/list_model_observer.h"
16 17
17 namespace { 18 namespace {
18 19
19 // OSX app list has hardcoded rows and columns for now. 20 // OSX app list has hardcoded rows and columns for now.
20 const int kFixedRows = 4; 21 const int kFixedRows = 4;
21 const int kFixedColumns = 4; 22 const int kFixedColumns = 4;
22 const int kItemsPerPage = kFixedRows * kFixedColumns; 23 const CGFloat kIconSize = 48;
23 24
24 // Padding space in pixels for fixed layout.
25 const CGFloat kGridTopPadding = 1;
26 const CGFloat kLeftRightPadding = 21;
27 const CGFloat kScrollerPadding = 16;
28
29 // Preferred tile size when showing in fixed layout. These should be even
30 // numbers to ensure that if they are grown 50% they remain integers.
31 const CGFloat kPreferredTileWidth = 88;
32 const CGFloat kPreferredTileHeight = 98;
33
34 const CGFloat kViewWidth =
35 kFixedColumns * kPreferredTileWidth + 2 * kLeftRightPadding;
36 const CGFloat kViewHeight = kFixedRows * kPreferredTileHeight;
37
38 const NSTimeInterval kScrollWhileDraggingDelay = 1.0;
39 NSTimeInterval g_scroll_duration = 0.18; 25 NSTimeInterval g_scroll_duration = 0.18;
40 26
41 } // namespace 27 } // namespace
42 28
43 @interface AppsGridController ()
44
45 - (void)scrollToPageWithTimer:(size_t)targetPage;
46 - (void)onTimer:(NSTimer*)theTimer;
47
48 // Cancel a currently running scroll animation.
49 - (void)cancelScrollAnimation;
50
51 // Index of the page with the most content currently visible.
52 - (size_t)nearestPageIndex;
53
54 // Bootstrap the views this class controls.
55 - (void)loadAndSetView;
56
57 - (void)boundsDidChange:(NSNotification*)notification;
58
59 // Action for buttons in the grid.
60 - (void)onItemClicked:(id)sender;
61
62 - (AppsGridViewItem*)itemAtPageIndex:(size_t)pageIndex
63 indexInPage:(size_t)indexInPage;
64
65 // Return the button of the selected item.
66 - (NSButton*)selectedButton;
67
68 // The scroll view holding the grid pages.
69 - (NSScrollView*)gridScrollView;
70
71 - (NSView*)pagesContainerView;
72
73 // Create any new pages after updating |items_|.
74 - (void)updatePages:(size_t)startItemIndex;
75
76 - (void)updatePageContent:(size_t)pageIndex
77 resetModel:(BOOL)resetModel;
78
79 // Bridged methods for AppListItemListObserver.
80 - (void)listItemAdded:(size_t)index
81 item:(app_list::AppListItem*)item;
82
83 - (void)listItemRemoved:(size_t)index;
84
85 - (void)listItemMovedFromIndex:(size_t)fromIndex
86 toModelIndex:(size_t)toIndex;
87
88 // Moves the selection by |indexDelta| items.
89 - (BOOL)moveSelectionByDelta:(int)indexDelta;
90
91 // -[NSCollectionView frameForItemAtIndex:] misreports the frame origin of an
92 // item when the method is called during a scroll animation provided by the
93 // NSScrollView. This returns the correct value.
94 - (NSRect)trueFrameForItemAtIndex:(size_t)itemIndex;
95
96 @end
97
98 namespace app_list { 29 namespace app_list {
99 30
100 class AppsGridDelegateBridge : public AppListItemListObserver { 31 class AppsGridViewDelegateBridge : public AppsGridViewDelegate {
101 public: 32 public:
102 AppsGridDelegateBridge(AppsGridController* parent) : parent_(parent) {} 33 AppsGridViewDelegateBridge(AppsGridController* parent) : parent_(parent) {
34 (void)parent_;
35 }
36 virtual ~AppsGridViewDelegateBridge() {}
37
38 virtual void ActivateApp(AppListItem* item, int event_flags) OVERRIDE {
39 DLOG(INFO) << "Activate: " << item->GetDisplayName();
40 item->Activate(event_flags);
41 }
42
43 virtual void GetShortcutPathForApp(
44 const std::string& app_id,
45 const base::Callback<void(const base::FilePath&)>& callback) OVERRIDE {}
103 46
104 private: 47 private:
105 // Overridden from AppListItemListObserver: 48 AppsGridController* parent_; // Weak. Owns us.
106 virtual void OnListItemAdded(size_t index, AppListItem* item) OVERRIDE {
107 [parent_ listItemAdded:index
108 item:item];
109 }
110 virtual void OnListItemRemoved(size_t index, AppListItem* item) OVERRIDE {
111 [parent_ listItemRemoved:index];
112 }
113 virtual void OnListItemMoved(size_t from_index,
114 size_t to_index,
115 AppListItem* item) OVERRIDE {
116 [parent_ listItemMovedFromIndex:from_index
117 toModelIndex:to_index];
118 }
119
120 AppsGridController* parent_; // Weak, owns us.
121
122 DISALLOW_COPY_AND_ASSIGN(AppsGridDelegateBridge);
123 }; 49 };
124 50
125 } // namespace app_list 51 } // namespace app_list
126 52
127 @interface PageContainerView : NSView;
128 @end
129
130 // The container view needs to flip coordinates so that it is laid out
131 // correctly whether or not there is a horizontal scrollbar.
132 @implementation PageContainerView
133
134 - (BOOL)isFlipped {
135 return YES;
136 }
137
138 @end
139
140 @implementation AppsGridController 53 @implementation AppsGridController
141 54
142 + (void)setScrollAnimationDuration:(NSTimeInterval)duration { 55 + (void)setScrollAnimationDuration:(NSTimeInterval)duration {
143 g_scroll_duration = duration; 56 g_scroll_duration = duration;
144 } 57 }
145 58
146 + (CGFloat)scrollerPadding { 59 + (CGFloat)scrollerPadding {
147 return kScrollerPadding; 60 return 0;
148 } 61 }
149 62
150 @synthesize paginationObserver = paginationObserver_; 63 @synthesize paginationObserver = paginationObserver_;
151 64
152 - (id)init { 65 - (id)init {
153 if ((self = [super init])) { 66 if ((self = [super init])) {
154 bridge_.reset(new app_list::AppsGridDelegateBridge(self)); 67 gridDelegate_.reset(new app_list::AppsGridViewDelegateBridge(self));
155 NSSize cellSize = NSMakeSize(kPreferredTileWidth, kPreferredTileHeight); 68 paginationModel_.reset(new app_list::PaginationModel());
156 dragManager_.reset( 69 gridView_.reset(new app_list::AppsGridView(gridDelegate_.get(),
157 [[AppsCollectionViewDragManager alloc] initWithCellSize:cellSize 70 paginationModel_.get()));
158 rows:kFixedRows 71 gridView_->SetBounds(0, 0, 400, 440);
159 columns:kFixedColumns 72 [self setView:gridView_.GetNSView()];
160 gridController:self]);
161 pages_.reset([[NSMutableArray alloc] init]);
162 items_.reset([[NSMutableArray alloc] init]);
163 [self loadAndSetView];
164 [self updatePages:0];
165 } 73 }
166 return self; 74 return self;
167 } 75 }
168 76
169 - (void)dealloc {
170 [[NSNotificationCenter defaultCenter] removeObserver:self];
171 [super dealloc];
172 }
173
174 - (NSCollectionView*)collectionViewAtPageIndex:(size_t)pageIndex { 77 - (NSCollectionView*)collectionViewAtPageIndex:(size_t)pageIndex {
175 return [pages_ objectAtIndex:pageIndex]; 78 return nil;
176 } 79 }
177 80
178 - (size_t)pageIndexForCollectionView:(NSCollectionView*)page { 81 - (size_t)pageIndexForCollectionView:(NSCollectionView*)page {
179 for (size_t pageIndex = 0; pageIndex < [pages_ count]; ++pageIndex) {
180 if (page == [self collectionViewAtPageIndex:pageIndex])
181 return pageIndex;
182 }
183 return NSNotFound; 82 return NSNotFound;
184 } 83 }
185 84
186 - (app_list::AppListModel*)model { 85 - (app_list::AppListModel*)model {
187 return delegate_ ? delegate_->GetModel() : NULL; 86 return delegate_ ? delegate_->GetModel() : NULL;
188 } 87 }
189 88
190 - (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate { 89 - (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate {
191 if (delegate_) { 90 NSView* parentView = [[self view] superview];
192 app_list::AppListModel* oldModel = delegate_->GetModel(); 91 gridView_.reset();
193 if (oldModel)
194 oldModel->top_level_item_list()->RemoveObserver(bridge_.get());
195 }
196
197 // Since the old model may be getting deleted, and the AppKit objects might
198 // be sitting in an NSAutoreleasePool, ensure there are no references to
199 // the model.
200 for (size_t i = 0; i < [items_ count]; ++i)
201 [[self itemAtIndex:i] setModel:NULL];
202
203 [items_ removeAllObjects];
204 [self updatePages:0];
205 [self scrollToPage:0];
206 92
207 delegate_ = newDelegate; 93 delegate_ = newDelegate;
208 if (!delegate_) 94 if (!delegate_)
209 return; 95 return;
210 96
211 app_list::AppListModel* newModel = delegate_->GetModel(); 97 gridView_.reset(new app_list::AppsGridView(gridDelegate_.get(),
212 if (!newModel) 98 paginationModel_.get()));
213 return; 99 gridView_->SetLayout(kIconSize, kFixedColumns, kFixedRows);
214 100 gridView_->SetModel([self model]);
215 newModel->top_level_item_list()->AddObserver(bridge_.get()); 101 gridView_->SetItemList([self model]->top_level_item_list());
216 for (size_t i = 0; i < newModel->top_level_item_list()->item_count(); ++i) { 102 gridView_->SetBounds(0, 0, 400, 440);
217 app_list::AppListItem* itemModel = 103 gridView_->SetVisible(true);
218 newModel->top_level_item_list()->item_at(i); 104 [self setView:gridView_.GetNSView()];
219 [items_ insertObject:[NSValue valueWithPointer:itemModel] 105 [parentView addSubview:[self view]];
220 atIndex:i];
221 }
222 [self updatePages:0];
223 } 106 }
224 107
225 - (size_t)visiblePage { 108 - (size_t)visiblePage {
226 return visiblePage_; 109 return 0;
227 } 110 }
228 111
229 - (void)activateSelection { 112 - (void)activateSelection {
230 [[self selectedButton] performClick:self]; 113 NOTIMPLEMENTED();
231 } 114 }
232 115
233 - (size_t)pageCount { 116 - (size_t)pageCount {
234 return [pages_ count]; 117 return 1;
235 } 118 }
236 119
237 - (size_t)itemCount { 120 - (size_t)itemCount {
238 return [items_ count]; 121 return 0;
239 } 122 }
240 123
241 - (void)scrollToPage:(size_t)pageIndex { 124 - (void)scrollToPage:(size_t)pageIndex {
242 NSClipView* clipView = [[self gridScrollView] contentView]; 125 NOTIMPLEMENTED();
243 NSPoint newOrigin = [clipView bounds].origin;
244
245 // Scrolling outside of this range is edge elasticity, which animates
246 // automatically.
247 if ((pageIndex == 0 && (newOrigin.x <= 0)) ||
248 (pageIndex + 1 == [self pageCount] &&
249 newOrigin.x >= pageIndex * kViewWidth)) {
250 return;
251 }
252
253 // Clear any selection on the current page (unless it has been removed).
254 if (visiblePage_ < [pages_ count]) {
255 [[self collectionViewAtPageIndex:visiblePage_]
256 setSelectionIndexes:[NSIndexSet indexSet]];
257 }
258
259 newOrigin.x = pageIndex * kViewWidth;
260 [NSAnimationContext beginGrouping];
261 [[NSAnimationContext currentContext] setDuration:g_scroll_duration];
262 [[clipView animator] setBoundsOrigin:newOrigin];
263 [NSAnimationContext endGrouping];
264 animatingScroll_ = YES;
265 targetScrollPage_ = pageIndex;
266 [self cancelScrollTimer];
267 } 126 }
268 127
269 - (void)maybeChangePageForPoint:(NSPoint)locationInWindow { 128 - (void)maybeChangePageForPoint:(NSPoint)locationInWindow {
270 NSPoint pointInView = [[self view] convertPoint:locationInWindow 129 NOTIMPLEMENTED();
271 fromView:nil];
272 // Check if the point is outside the view on the left or right.
273 if (pointInView.x <= 0 || pointInView.x >= NSWidth([[self view] bounds])) {
274 size_t targetPage = visiblePage_;
275 if (pointInView.x <= 0)
276 targetPage -= targetPage != 0 ? 1 : 0;
277 else
278 targetPage += targetPage < [pages_ count] - 1 ? 1 : 0;
279 [self scrollToPageWithTimer:targetPage];
280 return;
281 }
282
283 if (paginationObserver_) {
284 NSInteger segment =
285 [paginationObserver_ pagerSegmentAtLocation:locationInWindow];
286 if (segment >= 0 && static_cast<size_t>(segment) != targetScrollPage_) {
287 [self scrollToPageWithTimer:segment];
288 return;
289 }
290 }
291
292 // Otherwise the point may have moved back into the view.
293 [self cancelScrollTimer];
294 } 130 }
295 131
296 - (void)cancelScrollTimer { 132 - (void)cancelScrollTimer {
297 scheduledScrollPage_ = targetScrollPage_; 133 NOTIMPLEMENTED();
298 [scrollWhileDraggingTimer_ invalidate];
299 } 134 }
300 135
301 - (void)scrollToPageWithTimer:(size_t)targetPage { 136 - (void)scrollToPageWithTimer:(size_t)targetPage {
302 if (targetPage == targetScrollPage_) { 137 NOTIMPLEMENTED();
303 [self cancelScrollTimer];
304 return;
305 }
306
307 if (targetPage == scheduledScrollPage_)
308 return;
309
310 scheduledScrollPage_ = targetPage;
311 [scrollWhileDraggingTimer_ invalidate];
312 scrollWhileDraggingTimer_.reset(
313 [[NSTimer scheduledTimerWithTimeInterval:kScrollWhileDraggingDelay
314 target:self
315 selector:@selector(onTimer:)
316 userInfo:nil
317 repeats:NO] retain]);
318 }
319
320 - (void)onTimer:(NSTimer*)theTimer {
321 if (scheduledScrollPage_ == targetScrollPage_)
322 return; // Already animating scroll.
323
324 [self scrollToPage:scheduledScrollPage_];
325 }
326
327 - (void)cancelScrollAnimation {
328 NSClipView* clipView = [[self gridScrollView] contentView];
329 [NSAnimationContext beginGrouping];
330 [[NSAnimationContext currentContext] setDuration:0];
331 [[clipView animator] setBoundsOrigin:[clipView bounds].origin];
332 [NSAnimationContext endGrouping];
333 animatingScroll_ = NO;
334 }
335
336 - (size_t)nearestPageIndex {
337 return lround(
338 NSMinX([[[self gridScrollView] contentView] bounds]) / kViewWidth);
339 }
340
341 - (void)userScrolling:(BOOL)isScrolling {
342 if (isScrolling) {
343 if (animatingScroll_)
344 [self cancelScrollAnimation];
345 } else {
346 [self scrollToPage:[self nearestPageIndex]];
347 }
348 }
349
350 - (void)loadAndSetView {
351 base::scoped_nsobject<PageContainerView> pagesContainer(
352 [[PageContainerView alloc] initWithFrame:NSZeroRect]);
353
354 NSRect scrollFrame = NSMakeRect(0, kGridTopPadding, kViewWidth,
355 kViewHeight + kScrollerPadding);
356 base::scoped_nsobject<ScrollViewWithNoScrollbars> scrollView(
357 [[ScrollViewWithNoScrollbars alloc] initWithFrame:scrollFrame]);
358 [scrollView setBorderType:NSNoBorder];
359 [scrollView setLineScroll:kViewWidth];
360 [scrollView setPageScroll:kViewWidth];
361 [scrollView setDelegate:self];
362 [scrollView setDocumentView:pagesContainer];
363 [scrollView setDrawsBackground:NO];
364
365 [[NSNotificationCenter defaultCenter]
366 addObserver:self
367 selector:@selector(boundsDidChange:)
368 name:NSViewBoundsDidChangeNotification
369 object:[scrollView contentView]];
370
371 [self setView:scrollView];
372 }
373
374 - (void)boundsDidChange:(NSNotification*)notification {
375 size_t newPage = [self nearestPageIndex];
376 if (newPage == visiblePage_) {
377 [paginationObserver_ pageVisibilityChanged];
378 return;
379 }
380
381 visiblePage_ = newPage;
382 [paginationObserver_ selectedPageChanged:newPage];
383 [paginationObserver_ pageVisibilityChanged];
384 }
385
386 - (void)onItemClicked:(id)sender {
387 for (size_t i = 0; i < [items_ count]; ++i) {
388 AppsGridViewItem* gridItem = [self itemAtIndex:i];
389 if ([[gridItem button] isEqual:sender])
390 [gridItem model]->Activate(0);
391 }
392 }
393
394 - (AppsGridViewItem*)itemAtPageIndex:(size_t)pageIndex
395 indexInPage:(size_t)indexInPage {
396 return base::mac::ObjCCastStrict<AppsGridViewItem>(
397 [[self collectionViewAtPageIndex:pageIndex] itemAtIndex:indexInPage]);
398 }
399
400 - (AppsGridViewItem*)itemAtIndex:(size_t)itemIndex {
401 const size_t pageIndex = itemIndex / kItemsPerPage;
402 return [self itemAtPageIndex:pageIndex
403 indexInPage:itemIndex - pageIndex * kItemsPerPage];
404 } 138 }
405 139
406 - (NSUInteger)selectedItemIndex { 140 - (NSUInteger)selectedItemIndex {
407 NSCollectionView* page = [self collectionViewAtPageIndex:visiblePage_]; 141 return NSNotFound;
408 NSUInteger indexOnPage = [[page selectionIndexes] firstIndex];
409 if (indexOnPage == NSNotFound)
410 return NSNotFound;
411
412 return indexOnPage + visiblePage_ * kItemsPerPage;
413 }
414
415 - (NSButton*)selectedButton {
416 NSUInteger index = [self selectedItemIndex];
417 if (index == NSNotFound)
418 return nil;
419
420 return [[self itemAtIndex:index] button];
421 }
422
423 - (NSScrollView*)gridScrollView {
424 return base::mac::ObjCCastStrict<NSScrollView>([self view]);
425 }
426
427 - (NSView*)pagesContainerView {
428 return [[self gridScrollView] documentView];
429 }
430
431 - (void)updatePages:(size_t)startItemIndex {
432 // Note there is always at least one page.
433 size_t targetPages = 1;
434 if ([items_ count] != 0)
435 targetPages = ([items_ count] - 1) / kItemsPerPage + 1;
436
437 const size_t currentPages = [self pageCount];
438 // First see if the number of pages have changed.
439 if (targetPages != currentPages) {
440 if (targetPages < currentPages) {
441 // Pages need to be removed.
442 [pages_ removeObjectsInRange:NSMakeRange(targetPages,
443 currentPages - targetPages)];
444 } else {
445 // Pages need to be added.
446 for (size_t i = currentPages; i < targetPages; ++i) {
447 NSRect pageFrame = NSMakeRect(
448 kLeftRightPadding + kViewWidth * i, 0,
449 kViewWidth, kViewHeight);
450 [pages_ addObject:[dragManager_ makePageWithFrame:pageFrame]];
451 }
452 }
453
454 [[self pagesContainerView] setSubviews:pages_];
455 NSSize pagesSize = NSMakeSize(kViewWidth * targetPages, kViewHeight);
456 [[self pagesContainerView] setFrameSize:pagesSize];
457 [paginationObserver_ totalPagesChanged];
458 }
459
460 const size_t startPage = startItemIndex / kItemsPerPage;
461 // All pages on or after |startPage| may need items added or removed.
462 for (size_t pageIndex = startPage; pageIndex < targetPages; ++pageIndex) {
463 [self updatePageContent:pageIndex
464 resetModel:YES];
465 }
466 }
467
468 - (void)updatePageContent:(size_t)pageIndex
469 resetModel:(BOOL)resetModel {
470 NSCollectionView* pageView = [self collectionViewAtPageIndex:pageIndex];
471 if (resetModel) {
472 // Clear the models first, otherwise removed items could be autoreleased at
473 // an unknown point in the future, when the model owner may have gone away.
474 for (size_t i = 0; i < [[pageView content] count]; ++i) {
475 AppsGridViewItem* gridItem = base::mac::ObjCCastStrict<AppsGridViewItem>(
476 [pageView itemAtIndex:i]);
477 [gridItem setModel:NULL];
478 }
479 }
480
481 NSRange inPageRange = NSIntersectionRange(
482 NSMakeRange(pageIndex * kItemsPerPage, kItemsPerPage),
483 NSMakeRange(0, [items_ count]));
484 NSArray* pageContent = [items_ subarrayWithRange:inPageRange];
485 [pageView setContent:pageContent];
486 if (!resetModel)
487 return;
488
489 for (size_t i = 0; i < [pageContent count]; ++i) {
490 AppsGridViewItem* gridItem = base::mac::ObjCCastStrict<AppsGridViewItem>(
491 [pageView itemAtIndex:i]);
492 [gridItem setModel:static_cast<app_list::AppListItem*>(
493 [[pageContent objectAtIndex:i] pointerValue])];
494 [gridItem setInitialFrameRect:[self trueFrameForItemAtIndex:i]];
495 }
496 } 142 }
497 143
498 - (void)moveItemInView:(size_t)fromIndex 144 - (void)moveItemInView:(size_t)fromIndex
499 toItemIndex:(size_t)toIndex { 145 toItemIndex:(size_t)toIndex {
500 base::scoped_nsobject<NSValue> item( 146 NOTIMPLEMENTED();
501 [[items_ objectAtIndex:fromIndex] retain]);
502 [items_ removeObjectAtIndex:fromIndex];
503 [items_ insertObject:item
504 atIndex:toIndex];
505
506 size_t fromPageIndex = fromIndex / kItemsPerPage;
507 size_t toPageIndex = toIndex / kItemsPerPage;
508 if (fromPageIndex == toPageIndex) {
509 [self updatePageContent:fromPageIndex
510 resetModel:NO]; // Just reorder items.
511 return;
512 }
513
514 if (fromPageIndex > toPageIndex)
515 std::swap(fromPageIndex, toPageIndex);
516
517 for (size_t i = fromPageIndex; i <= toPageIndex; ++i) {
518 [self updatePageContent:i
519 resetModel:YES];
520 }
521 } 147 }
522 148
523 // Compare with views implementation in AppsGridView::MoveItemInModel().
524 - (void)moveItemWithIndex:(size_t)itemIndex 149 - (void)moveItemWithIndex:(size_t)itemIndex
525 toModelIndex:(size_t)modelIndex { 150 toModelIndex:(size_t)modelIndex {
526 // Ingore no-op moves. Note that this is always the case when canceled. 151 NOTIMPLEMENTED();
527 if (itemIndex == modelIndex)
528 return;
529
530 app_list::AppListItemList* itemList = [self model]->top_level_item_list();
531 itemList->RemoveObserver(bridge_.get());
532 itemList->MoveItem(itemIndex, modelIndex);
533 itemList->AddObserver(bridge_.get());
534 } 152 }
535 153
536 - (AppsCollectionViewDragManager*)dragManager { 154 - (void)selectItemAtIndex:(NSUInteger)index {
537 return dragManager_; 155 NOTIMPLEMENTED();
538 } 156 }
539 157
540 - (size_t)scheduledScrollPage { 158 - (BOOL)handleCommandBySelector:(SEL)command {
541 return scheduledScrollPage_; 159 NOTIMPLEMENTED();
542 } 160 return TRUE;
543
544 - (void)listItemAdded:(size_t)index
545 item:(app_list::AppListItem*)itemModel {
546 // Cancel any drag, to ensure the model stays consistent.
547 [dragManager_ cancelDrag];
548
549 [items_ insertObject:[NSValue valueWithPointer:itemModel]
550 atIndex:index];
551
552 [self updatePages:index];
553 }
554
555 - (void)listItemRemoved:(size_t)index {
556 [dragManager_ cancelDrag];
557
558 // Clear the models explicitly to avoid surprises from autorelease.
559 [[self itemAtIndex:index] setModel:NULL];
560
561 [items_ removeObjectsInRange:NSMakeRange(index, 1)];
562 [self updatePages:index];
563 }
564
565 - (void)listItemMovedFromIndex:(size_t)fromIndex
566 toModelIndex:(size_t)toIndex {
567 [dragManager_ cancelDrag];
568 [self moveItemInView:fromIndex
569 toItemIndex:toIndex];
570 } 161 }
571 162
572 - (CGFloat)visiblePortionOfPage:(int)page { 163 - (CGFloat)visiblePortionOfPage:(int)page {
573 CGFloat scrollOffsetOfPage = 164 return 0.5;
574 NSMinX([[[self gridScrollView] contentView] bounds]) / kViewWidth - page;
575 if (scrollOffsetOfPage <= -1.0 || scrollOffsetOfPage >= 1.0)
576 return 0.0;
577
578 if (scrollOffsetOfPage <= 0.0)
579 return scrollOffsetOfPage + 1.0;
580
581 return -1.0 + scrollOffsetOfPage;
582 } 165 }
583 166
584 - (void)onPagerClicked:(AppListPagerView*)sender { 167 - (void)onPagerClicked:(AppListPagerView*)sender {
585 int selectedSegment = [sender selectedSegment]; 168 NOTIMPLEMENTED();
586 if (selectedSegment < 0)
587 return; // No selection.
588
589 int pageIndex = [[sender cell] tagForSegment:selectedSegment];
590 if (pageIndex >= 0)
591 [self scrollToPage:pageIndex];
592 }
593
594 - (BOOL)moveSelectionByDelta:(int)indexDelta {
595 if (indexDelta == 0)
596 return NO;
597
598 NSUInteger oldIndex = [self selectedItemIndex];
599
600 // If nothing is currently selected, select the first item on the page.
601 if (oldIndex == NSNotFound) {
602 [self selectItemAtIndex:visiblePage_ * kItemsPerPage];
603 return YES;
604 }
605
606 // Can't select a negative index.
607 if (indexDelta < 0 && static_cast<NSUInteger>(-indexDelta) > oldIndex)
608 return NO;
609
610 // Can't select an index greater or equal to the number of items.
611 if (oldIndex + indexDelta >= [items_ count]) {
612 if (visiblePage_ == [pages_ count] - 1)
613 return NO;
614
615 // If we're not on the last page, then select the last item.
616 [self selectItemAtIndex:[items_ count] - 1];
617 return YES;
618 }
619
620 [self selectItemAtIndex:oldIndex + indexDelta];
621 return YES;
622 }
623
624 - (NSRect)trueFrameForItemAtIndex:(size_t)itemIndex {
625 size_t column = itemIndex % kFixedColumns;
626 size_t row = itemIndex % kItemsPerPage / kFixedColumns;
627 return NSMakeRect(column * kPreferredTileWidth,
628 row * kPreferredTileHeight,
629 kPreferredTileWidth,
630 kPreferredTileHeight);
631 }
632
633 - (void)selectItemAtIndex:(NSUInteger)index {
634 if (index >= [items_ count])
635 return;
636
637 if (index / kItemsPerPage != visiblePage_)
638 [self scrollToPage:index / kItemsPerPage];
639
640 [[self itemAtIndex:index] setSelected:YES];
641 }
642
643 - (BOOL)handleCommandBySelector:(SEL)command {
644 if (command == @selector(insertNewline:) ||
645 command == @selector(insertLineBreak:)) {
646 [self activateSelection];
647 return YES;
648 }
649
650 NSUInteger oldIndex = [self selectedItemIndex];
651 // If nothing is currently selected, select the first item on the page.
652 if (oldIndex == NSNotFound) {
653 [self selectItemAtIndex:visiblePage_ * kItemsPerPage];
654 return YES;
655 }
656
657 if (command == @selector(moveLeft:)) {
658 return oldIndex % kFixedColumns == 0 ?
659 [self moveSelectionByDelta:-kItemsPerPage + kFixedColumns - 1] :
660 [self moveSelectionByDelta:-1];
661 }
662
663 if (command == @selector(moveRight:)) {
664 return oldIndex % kFixedColumns == kFixedColumns - 1 ?
665 [self moveSelectionByDelta:+kItemsPerPage - kFixedColumns + 1] :
666 [self moveSelectionByDelta:1];
667 }
668
669 if (command == @selector(moveUp:)) {
670 return oldIndex / kFixedColumns % kFixedRows == 0 ?
671 NO : [self moveSelectionByDelta:-kFixedColumns];
672 }
673
674 if (command == @selector(moveDown:)) {
675 return oldIndex / kFixedColumns % kFixedRows == kFixedRows - 1 ?
676 NO : [self moveSelectionByDelta:kFixedColumns];
677 }
678
679 if (command == @selector(pageUp:) ||
680 command == @selector(scrollPageUp:))
681 return [self moveSelectionByDelta:-kItemsPerPage];
682
683 if (command == @selector(pageDown:) ||
684 command == @selector(scrollPageDown:))
685 return [self moveSelectionByDelta:kItemsPerPage];
686
687 return NO;
688 } 169 }
689 170
690 @end 171 @end
OLDNEW
« no previous file with comments | « ui/app_list/cocoa/apps_grid_controller.h ('k') | ui/app_list/cocoa/apps_grid_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698