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

Side by Side Diff: ui/app_list/apps_grid_view.cc

Issue 11784034: Skeleton for app_list on OSX, and refactoring for enable_app_list=1 on OS=="mac". (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase for 175876 and 175961 Created 7 years, 11 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
« no previous file with comments | « ui/app_list/apps_grid_view.h ('k') | ui/app_list/apps_grid_view_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/app_list/apps_grid_view.h"
6
7 #include <algorithm>
8
9 #include "ui/app_list/app_list_item_view.h"
10 #include "ui/app_list/apps_grid_view_delegate.h"
11 #include "ui/app_list/page_switcher.h"
12 #include "ui/app_list/pagination_model.h"
13 #include "ui/app_list/pulsing_block_view.h"
14 #include "ui/base/animation/animation.h"
15 #include "ui/base/events/event.h"
16 #include "ui/views/border.h"
17 #include "ui/views/view_model_utils.h"
18 #include "ui/views/widget/widget.h"
19
20 #if defined(USE_AURA)
21 #include "ui/aura/root_window.h"
22 #endif
23
24 namespace {
25
26 // Padding space in pixels for fixed layout.
27 const int kLeftRightPadding = 20;
28 const int kTopPadding = 1;
29
30 // Padding space in pixels between pages.
31 const int kPagePadding = 40;
32
33 // Preferred tile size when showing in fixed layout.
34 const int kPreferredTileWidth = 88;
35 const int kPreferredTileHeight = 98;
36
37 // Width in pixels of the area on the sides that triggers a page flip.
38 const int kPageFlipZoneSize = 40;
39
40 // Delay in milliseconds to do the page flip.
41 const int kPageFlipDelayInMs = 1000;
42
43 // RowMoveAnimationDelegate is used when moving an item into a different row.
44 // Before running the animation, the item's layer is re-created and kept in
45 // the original position, then the item is moved to just before its target
46 // position and opacity set to 0. When the animation runs, this delegate moves
47 // the layer and fades it out while fading in the item at the same time.
48 class RowMoveAnimationDelegate
49 : public views::BoundsAnimator::OwnedAnimationDelegate {
50 public:
51 RowMoveAnimationDelegate(views::View* view,
52 ui::Layer* layer,
53 const gfx::Rect& layer_target)
54 : view_(view),
55 layer_(layer),
56 layer_start_(layer ? layer->bounds() : gfx::Rect()),
57 layer_target_(layer_target) {
58 }
59 virtual ~RowMoveAnimationDelegate() {}
60
61 // ui::AnimationDelegate overrides:
62 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE {
63 view_->layer()->SetOpacity(animation->GetCurrentValue());
64 view_->layer()->ScheduleDraw();
65
66 if (layer_) {
67 layer_->SetOpacity(1 - animation->GetCurrentValue());
68 layer_->SetBounds(animation->CurrentValueBetween(layer_start_,
69 layer_target_));
70 layer_->ScheduleDraw();
71 }
72 }
73 virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE {
74 view_->layer()->SetOpacity(1.0f);
75 view_->layer()->ScheduleDraw();
76 }
77 virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE {
78 view_->layer()->SetOpacity(1.0f);
79 view_->layer()->ScheduleDraw();
80 }
81
82 private:
83 // The view that needs to be wrapped. Owned by views hierarchy.
84 views::View* view_;
85
86 scoped_ptr<ui::Layer> layer_;
87 const gfx::Rect layer_start_;
88 const gfx::Rect layer_target_;
89
90 DISALLOW_COPY_AND_ASSIGN(RowMoveAnimationDelegate);
91 };
92
93 } // namespace
94
95 namespace app_list {
96
97 AppsGridView::AppsGridView(AppsGridViewDelegate* delegate,
98 PaginationModel* pagination_model)
99 : model_(NULL),
100 delegate_(delegate),
101 pagination_model_(pagination_model),
102 page_switcher_view_(new PageSwitcher(pagination_model)),
103 cols_(0),
104 rows_per_page_(0),
105 selected_view_(NULL),
106 drag_view_(NULL),
107 drag_pointer_(NONE),
108 page_flip_target_(-1),
109 page_flip_delay_in_ms_(kPageFlipDelayInMs),
110 ALLOW_THIS_IN_INITIALIZER_LIST(bounds_animator_(this)) {
111 pagination_model_->AddObserver(this);
112 AddChildView(page_switcher_view_);
113 }
114
115 AppsGridView::~AppsGridView() {
116 if (model_) {
117 model_->RemoveObserver(this);
118 model_->apps()->RemoveObserver(this);
119 }
120 pagination_model_->RemoveObserver(this);
121 }
122
123 void AppsGridView::SetLayout(int icon_size, int cols, int rows_per_page) {
124 icon_size_.SetSize(icon_size, icon_size);
125 cols_ = cols;
126 rows_per_page_ = rows_per_page;
127
128 set_border(views::Border::CreateEmptyBorder(kTopPadding,
129 kLeftRightPadding,
130 0,
131 kLeftRightPadding));
132 }
133
134 void AppsGridView::SetModel(AppListModel* model) {
135 if (model_) {
136 model_->RemoveObserver(this);
137 model_->apps()->RemoveObserver(this);
138 }
139
140 model_ = model;
141 if (model_) {
142 model_->AddObserver(this);
143 model_->apps()->AddObserver(this);
144 }
145 Update();
146 }
147
148 void AppsGridView::SetSelectedView(views::View* view) {
149 if (IsSelectedView(view) || IsDraggedView(view))
150 return;
151
152 Index index = GetIndexOfView(view);
153 if (IsValidIndex(index))
154 SetSelectedItemByIndex(index);
155 }
156
157 void AppsGridView::ClearSelectedView(views::View* view) {
158 if (view && IsSelectedView(view)) {
159 selected_view_->SchedulePaint();
160 selected_view_ = NULL;
161 }
162 }
163
164 bool AppsGridView::IsSelectedView(const views::View* view) const {
165 return selected_view_ == view;
166 }
167
168 void AppsGridView::EnsureViewVisible(const views::View* view) {
169 if (pagination_model_->has_transition())
170 return;
171
172 Index index = GetIndexOfView(view);
173 if (IsValidIndex(index))
174 pagination_model_->SelectPage(index.page, false);
175 }
176
177 void AppsGridView::InitiateDrag(views::View* view,
178 Pointer pointer,
179 const ui::LocatedEvent& event) {
180 if (drag_view_ || pulsing_blocks_model_.view_size())
181 return;
182
183 drag_view_ = view;
184 drag_start_ = event.location();
185 }
186
187 void AppsGridView::UpdateDrag(views::View* view,
188 Pointer pointer,
189 const ui::LocatedEvent& event) {
190 if (!dragging() && drag_view_ &&
191 ExceededDragThreshold(event.location() - drag_start_)) {
192 drag_pointer_ = pointer;
193 // Move the view to the front so that it appears on top of other views.
194 ReorderChildView(drag_view_, -1);
195 bounds_animator_.StopAnimatingView(drag_view_);
196 }
197 if (drag_pointer_ != pointer)
198 return;
199
200 ExtractDragLocation(event, &last_drag_point_);
201
202 const Index last_drop_target = drop_target_;
203 CalculateDropTarget(last_drag_point_, false);
204 MaybeStartPageFlipTimer(last_drag_point_);
205
206 gfx::Point page_switcher_point(last_drag_point_);
207 views::View::ConvertPointToTarget(this, page_switcher_view_,
208 &page_switcher_point);
209 page_switcher_view_->UpdateUIForDragPoint(page_switcher_point);
210
211 if (last_drop_target != drop_target_)
212 AnimateToIdealBounds();
213 drag_view_->SetPosition(
214 gfx::PointAtOffsetFromOrigin(last_drag_point_ - drag_start_));
215 }
216
217 void AppsGridView::EndDrag(bool cancel) {
218 if (!cancel && dragging() && drag_view_) {
219 CalculateDropTarget(last_drag_point_, true);
220 if (IsValidIndex(drop_target_))
221 MoveItemInModel(drag_view_, drop_target_);
222 }
223
224 drag_pointer_ = NONE;
225 drop_target_ = Index();
226 if (drag_view_) {
227 drag_view_ = NULL;
228 AnimateToIdealBounds();
229 }
230
231 page_flip_timer_.Stop();
232 page_flip_target_ = -1;
233 }
234
235 bool AppsGridView::IsDraggedView(const views::View* view) const {
236 return drag_view_ == view;
237 }
238
239 gfx::Size AppsGridView::GetPreferredSize() {
240 const gfx::Insets insets(GetInsets());
241 const gfx::Size tile_size = gfx::Size(kPreferredTileWidth,
242 kPreferredTileHeight);
243 const int page_switcher_height =
244 page_switcher_view_->GetPreferredSize().height();
245 return gfx::Size(
246 tile_size.width() * cols_ + insets.width(),
247 tile_size.height() * rows_per_page_ +
248 page_switcher_height + insets.height());
249 }
250
251 void AppsGridView::Layout() {
252 if (bounds_animator_.IsAnimating())
253 bounds_animator_.Cancel();
254
255 CalculateIdealBounds();
256 for (int i = 0; i < view_model_.view_size(); ++i) {
257 views::View* view = view_model_.view_at(i);
258 if (view != drag_view_)
259 view->SetBoundsRect(view_model_.ideal_bounds(i));
260 }
261 views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model_);
262
263 const int page_switcher_height =
264 page_switcher_view_->GetPreferredSize().height();
265 gfx::Rect rect(GetContentsBounds());
266 rect.set_y(rect.bottom() - page_switcher_height);
267 rect.set_height(page_switcher_height);
268 page_switcher_view_->SetBoundsRect(rect);
269 }
270
271 bool AppsGridView::OnKeyPressed(const ui::KeyEvent& event) {
272 bool handled = false;
273 if (selected_view_)
274 handled = selected_view_->OnKeyPressed(event);
275
276 if (!handled) {
277 switch (event.key_code()) {
278 case ui::VKEY_LEFT:
279 MoveSelected(0, -1);
280 return true;
281 case ui::VKEY_RIGHT:
282 MoveSelected(0, 1);
283 return true;
284 case ui::VKEY_UP:
285 MoveSelected(0, -cols_);
286 return true;
287 case ui::VKEY_DOWN:
288 MoveSelected(0, cols_);
289 return true;
290 case ui::VKEY_PRIOR: {
291 MoveSelected(-1, 0);
292 return true;
293 }
294 case ui::VKEY_NEXT: {
295 MoveSelected(1, 0);
296 return true;
297 }
298 default:
299 break;
300 }
301 }
302
303 return handled;
304 }
305
306 bool AppsGridView::OnKeyReleased(const ui::KeyEvent& event) {
307 bool handled = false;
308 if (selected_view_)
309 handled = selected_view_->OnKeyReleased(event);
310
311 return handled;
312 }
313
314 void AppsGridView::ViewHierarchyChanged(bool is_add,
315 views::View* parent,
316 views::View* child) {
317 if (!is_add && parent == this) {
318 if (selected_view_ == child)
319 selected_view_ = NULL;
320
321 if (drag_view_ == child)
322 EndDrag(true);
323
324 bounds_animator_.StopAnimatingView(child);
325 }
326 }
327
328 void AppsGridView::Update() {
329 DCHECK(!selected_view_ && !drag_view_);
330
331 view_model_.Clear();
332 if (model_ && model_->apps()->item_count())
333 ListItemsAdded(0, model_->apps()->item_count());
334 }
335
336 void AppsGridView::UpdatePaging() {
337 if (!view_model_.view_size() || !tiles_per_page()) {
338 pagination_model_->SetTotalPages(0);
339 return;
340 }
341
342 pagination_model_->SetTotalPages(
343 (view_model_.view_size() - 1) / tiles_per_page() + 1);
344 }
345
346 void AppsGridView::UpdatePulsingBlockViews() {
347 const int available_slots =
348 tiles_per_page() - model_->apps()->item_count() % tiles_per_page();
349 const int desired = model_->status() == AppListModel::STATUS_SYNCING ?
350 available_slots : 0;
351
352 if (pulsing_blocks_model_.view_size() == desired)
353 return;
354
355 while (pulsing_blocks_model_.view_size() > desired) {
356 views::View* view = pulsing_blocks_model_.view_at(0);
357 pulsing_blocks_model_.Remove(0);
358 delete view;
359 }
360
361 while (pulsing_blocks_model_.view_size() < desired) {
362 views::View* view = new PulsingBlockView(
363 gfx::Size(kPreferredTileWidth, kPreferredTileHeight), true);
364 pulsing_blocks_model_.Add(view, 0);
365 AddChildView(view);
366 }
367 }
368
369 views::View* AppsGridView::CreateViewForItemAtIndex(size_t index) {
370 DCHECK_LT(index, model_->apps()->item_count());
371 AppListItemView* view = new AppListItemView(this,
372 model_->apps()->GetItemAt(index));
373 view->SetIconSize(icon_size_);
374 #if defined(USE_AURA)
375 view->SetPaintToLayer(true);
376 view->SetFillsBoundsOpaquely(false);
377 #endif
378 return view;
379 }
380
381 void AppsGridView::SetSelectedItemByIndex(const Index& index) {
382 if (GetIndexOfView(selected_view_) == index)
383 return;
384
385 views::View* new_selection = GetViewAtIndex(index);
386 if (!new_selection)
387 return; // Keep current selection.
388
389 if (selected_view_)
390 selected_view_->SchedulePaint();
391
392 selected_view_ = new_selection;
393 EnsureViewVisible(selected_view_);
394 selected_view_->SchedulePaint();
395 if (GetWidget()) {
396 GetWidget()->NotifyAccessibilityEvent(
397 selected_view_, ui::AccessibilityTypes::EVENT_FOCUS, true);
398 }
399 }
400
401 bool AppsGridView::IsValidIndex(const Index& index) const {
402 return index.page >= 0 && index.page < pagination_model_->total_pages() &&
403 index.slot >= 0 && index.slot < tiles_per_page() &&
404 index.page * tiles_per_page() + index.slot < view_model_.view_size();
405 }
406
407 AppsGridView::Index AppsGridView::GetIndexOfView(
408 const views::View* view) const {
409 const int model_index = view_model_.GetIndexOfView(view);
410 if (model_index == -1)
411 return Index();
412
413 return Index(model_index / tiles_per_page(), model_index % tiles_per_page());
414 }
415
416 views::View* AppsGridView::GetViewAtIndex(const Index& index) const {
417 if (!IsValidIndex(index))
418 return NULL;
419
420 const int model_index = index.page * tiles_per_page() + index.slot;
421 return view_model_.view_at(model_index);
422 }
423
424 void AppsGridView::MoveSelected(int page_delta, int slot_delta) {
425 if (!selected_view_)
426 return SetSelectedItemByIndex(Index(0, 0));
427
428 const Index& selected = GetIndexOfView(selected_view_);
429 int target_slot = selected.slot + slot_delta;
430 if (target_slot < 0) {
431 page_delta += (target_slot + 1) / tiles_per_page() - 1;
432 target_slot = tiles_per_page() + (target_slot + 1) % tiles_per_page() - 1;
433 } else if (target_slot > tiles_per_page()) {
434 page_delta += target_slot / tiles_per_page();
435 target_slot %= tiles_per_page();
436 }
437
438 int target_page = std::min(pagination_model_->total_pages() - 1,
439 std::max(selected.page + page_delta, 0));
440 SetSelectedItemByIndex(Index(target_page, target_slot));
441 }
442
443 void AppsGridView::CalculateIdealBounds() {
444 gfx::Rect rect(GetContentsBounds());
445 if (rect.IsEmpty())
446 return;
447
448 gfx::Size tile_size(kPreferredTileWidth, kPreferredTileHeight);
449
450 gfx::Rect grid_rect(gfx::Size(tile_size.width() * cols_,
451 tile_size.height() * rows_per_page_));
452 grid_rect.Intersect(rect);
453
454 // Page width including padding pixels. A tile.x + page_width means the same
455 // tile slot in the next page.
456 const int page_width = grid_rect.width() + kPagePadding;
457
458 // If there is a transition, calculates offset for current and target page.
459 const int current_page = pagination_model_->selected_page();
460 const PaginationModel::Transition& transition =
461 pagination_model_->transition();
462 const bool is_valid =
463 pagination_model_->is_valid_page(transition.target_page);
464
465 // Transition to right means negative offset.
466 const int dir = transition.target_page > current_page ? -1 : 1;
467 const int transition_offset = is_valid ?
468 transition.progress * page_width * dir : 0;
469
470 const int total_views =
471 view_model_.view_size() + pulsing_blocks_model_.view_size();
472 int slot_index = 0;
473 for (int i = 0; i < total_views; ++i) {
474 if (i < view_model_.view_size() && view_model_.view_at(i) == drag_view_)
475 continue;
476
477 int page = slot_index / tiles_per_page();
478 int slot = slot_index % tiles_per_page();
479
480 if (drop_target_.page == page && drop_target_.slot == slot) {
481 ++slot_index;
482 page = slot_index / tiles_per_page();
483 slot = slot_index % tiles_per_page();
484 }
485
486 // Decides an x_offset for current item.
487 int x_offset = 0;
488 if (page < current_page)
489 x_offset = -page_width;
490 else if (page > current_page)
491 x_offset = page_width;
492
493 if (is_valid) {
494 if (page == current_page || page == transition.target_page)
495 x_offset += transition_offset;
496 }
497
498 const int row = slot / cols_;
499 const int col = slot % cols_;
500 gfx::Rect tile_slot(
501 gfx::Point(grid_rect.x() + col * tile_size.width() + x_offset,
502 grid_rect.y() + row * tile_size.height()),
503 tile_size);
504 if (i < view_model_.view_size()) {
505 view_model_.set_ideal_bounds(i, tile_slot);
506 } else {
507 pulsing_blocks_model_.set_ideal_bounds(i - view_model_.view_size(),
508 tile_slot);
509 }
510
511 ++slot_index;
512 }
513 }
514
515 void AppsGridView::AnimateToIdealBounds() {
516 const gfx::Rect visible_bounds(GetVisibleBounds());
517
518 CalculateIdealBounds();
519 for (int i = 0; i < view_model_.view_size(); ++i) {
520 views::View* view = view_model_.view_at(i);
521 if (view == drag_view_)
522 continue;
523
524 const gfx::Rect& target = view_model_.ideal_bounds(i);
525 if (bounds_animator_.GetTargetBounds(view) == target)
526 continue;
527
528 const gfx::Rect& current = view->bounds();
529 const bool current_visible = visible_bounds.Intersects(current);
530 const bool target_visible = visible_bounds.Intersects(target);
531 const bool visible = current_visible || target_visible;
532
533 const int y_diff = target.y() - current.y();
534 if (visible && y_diff && y_diff % kPreferredTileHeight == 0) {
535 AnimationBetweenRows(view,
536 current_visible,
537 current,
538 target_visible,
539 target);
540 } else {
541 bounds_animator_.AnimateViewTo(view, target);
542 }
543 }
544 }
545
546 void AppsGridView::AnimationBetweenRows(views::View* view,
547 bool animate_current,
548 const gfx::Rect& current,
549 bool animate_target,
550 const gfx::Rect& target) {
551 // Determine page of |current| and |target|. -1 means in the left invisible
552 // page, 0 is the center visible page and 1 means in the right invisible page.
553 const int current_page = current.x() < 0 ? -1 :
554 current.x() >= width() ? 1 : 0;
555 const int target_page = target.x() < 0 ? -1 :
556 target.x() >= width() ? 1 : 0;
557
558 const int dir = current_page < target_page ||
559 (current_page == target_page && current.y() < target.y()) ? 1 : -1;
560
561 #if defined(USE_AURA)
562 scoped_ptr<ui::Layer> layer;
563 if (animate_current) {
564 layer.reset(view->RecreateLayer());
565 layer->SuppressPaint();
566
567 view->SetFillsBoundsOpaquely(false);
568 view->layer()->SetOpacity(0.f);
569 }
570
571 gfx::Rect current_out(current);
572 current_out.Offset(dir * kPreferredTileWidth, 0);
573 #endif
574
575 gfx::Rect target_in(target);
576 if (animate_target)
577 target_in.Offset(-dir * kPreferredTileWidth, 0);
578 view->SetBoundsRect(target_in);
579 bounds_animator_.AnimateViewTo(view, target);
580
581 #if defined(USE_AURA)
582 bounds_animator_.SetAnimationDelegate(
583 view,
584 new RowMoveAnimationDelegate(view, layer.release(), current_out),
585 true);
586 #endif
587 }
588
589 void AppsGridView::ExtractDragLocation(const ui::LocatedEvent& event,
590 gfx::Point* drag_point) {
591 #if defined(USE_AURA)
592 // Use root location of |event| instead of location in |drag_view_|'s
593 // coordinates because |drag_view_| has a scale transform and location
594 // could have integer round error and causes jitter.
595 *drag_point = event.root_location();
596
597 // GetWidget() could be NULL for tests.
598 if (GetWidget()) {
599 aura::Window::ConvertPointToTarget(
600 GetWidget()->GetNativeWindow()->GetRootWindow(),
601 GetWidget()->GetNativeWindow(),
602 drag_point);
603 }
604
605 views::View::ConvertPointFromWidget(this, drag_point);
606 #else
607 // For non-aura, root location is not clearly defined but |drag_view_| does
608 // not have the scale transform. So no round error would be introduced and
609 // it's okay to use View::ConvertPointToTarget.
610 *drag_point = event.location();
611 views::View::ConvertPointToTarget(drag_view_, this, drag_point);
612 #endif
613 }
614
615 void AppsGridView::CalculateDropTarget(const gfx::Point& drag_point,
616 bool use_page_button_hovering) {
617 const int current_page = pagination_model_->selected_page();
618
619 if (use_page_button_hovering &&
620 page_switcher_view_->bounds().Contains(drag_point)) {
621 gfx::Point page_switcher_point(drag_point);
622 views::View::ConvertPointToTarget(this, page_switcher_view_,
623 &page_switcher_point);
624 int page = page_switcher_view_->GetPageForPoint(page_switcher_point);
625 if (pagination_model_->is_valid_page(page)) {
626 drop_target_.page = page;
627 drop_target_.slot = tiles_per_page() - 1;
628 }
629 } else {
630 const int drop_row = drag_point.y() / kPreferredTileHeight;
631 const int drop_col = std::min(cols_ - 1,
632 drag_point.x() / kPreferredTileWidth);
633
634 drop_target_.page = current_page;
635 drop_target_.slot = std::max(0, std::min(
636 tiles_per_page() - 1,
637 drop_row * cols_ + drop_col));
638 }
639
640 // Limits to the last possible slot on last page.
641 if (drop_target_.page == pagination_model_->total_pages() - 1) {
642 drop_target_.slot = std::min(
643 (view_model_.view_size() - 1) % tiles_per_page(),
644 drop_target_.slot);
645 }
646 }
647
648 void AppsGridView::MaybeStartPageFlipTimer(const gfx::Point& drag_point) {
649 int new_page_flip_target = -1;
650
651 if (page_switcher_view_->bounds().Contains(drag_point)) {
652 gfx::Point page_switcher_point(drag_point);
653 views::View::ConvertPointToTarget(this, page_switcher_view_,
654 &page_switcher_point);
655 new_page_flip_target =
656 page_switcher_view_->GetPageForPoint(page_switcher_point);
657 }
658
659 // TODO(xiyuan): Fix this for RTL.
660 if (new_page_flip_target == -1 && drag_point.x() < kPageFlipZoneSize)
661 new_page_flip_target = pagination_model_->selected_page() - 1;
662
663 if (new_page_flip_target == -1 &&
664 drag_point.x() > width() - kPageFlipZoneSize) {
665 new_page_flip_target = pagination_model_->selected_page() + 1;
666 }
667
668 if (new_page_flip_target == page_flip_target_)
669 return;
670
671 if (pagination_model_->is_valid_page(new_page_flip_target)) {
672 page_flip_target_ = new_page_flip_target;
673 page_flip_timer_.Stop();
674
675 if (page_flip_target_ != pagination_model_->selected_page()) {
676 page_flip_timer_.Start(FROM_HERE,
677 base::TimeDelta::FromMilliseconds(page_flip_delay_in_ms_),
678 this, &AppsGridView::OnPageFlipTimer);
679 }
680 } else {
681 page_flip_target_ = -1;
682 page_flip_timer_.Stop();
683 }
684 }
685
686 void AppsGridView::OnPageFlipTimer() {
687 DCHECK(pagination_model_->is_valid_page(page_flip_target_));
688 pagination_model_->SelectPage(page_flip_target_, true);
689 }
690
691 void AppsGridView::MoveItemInModel(views::View* item_view,
692 const Index& target) {
693 int current_model_index = view_model_.GetIndexOfView(item_view);
694 DCHECK_GE(current_model_index, 0);
695
696 int target_model_index = target.page * tiles_per_page() + target.slot;
697 if (target_model_index == current_model_index)
698 return;
699
700 model_->apps()->RemoveObserver(this);
701 model_->apps()->Move(current_model_index, target_model_index);
702 view_model_.Move(current_model_index, target_model_index);
703 model_->apps()->AddObserver(this);
704
705 if (pagination_model_->selected_page() != target.page)
706 pagination_model_->SelectPage(target.page, false);
707 }
708
709 void AppsGridView::ButtonPressed(views::Button* sender,
710 const ui::Event& event) {
711 if (dragging())
712 return;
713
714 if (sender->GetClassName() != AppListItemView::kViewClassName)
715 return;
716
717 if (delegate_) {
718 delegate_->ActivateApp(static_cast<AppListItemView*>(sender)->model(),
719 event.flags());
720 }
721 }
722
723 void AppsGridView::ListItemsAdded(size_t start, size_t count) {
724 EndDrag(true);
725
726 for (size_t i = start; i < start + count; ++i) {
727 views::View* view = CreateViewForItemAtIndex(i);
728 view_model_.Add(view, i);
729 AddChildView(view);
730 }
731
732 UpdatePaging();
733 UpdatePulsingBlockViews();
734 Layout();
735 SchedulePaint();
736 }
737
738 void AppsGridView::ListItemsRemoved(size_t start, size_t count) {
739 EndDrag(true);
740
741 for (size_t i = 0; i < count; ++i) {
742 views::View* view = view_model_.view_at(start);
743 view_model_.Remove(start);
744 delete view;
745 }
746
747 UpdatePaging();
748 UpdatePulsingBlockViews();
749 Layout();
750 SchedulePaint();
751 }
752
753 void AppsGridView::ListItemMoved(size_t index, size_t target_index) {
754 EndDrag(true);
755 view_model_.Move(index, target_index);
756
757 UpdatePaging();
758 AnimateToIdealBounds();
759 }
760
761 void AppsGridView::ListItemsChanged(size_t start, size_t count) {
762 NOTREACHED();
763 }
764
765 void AppsGridView::TotalPagesChanged() {
766 }
767
768 void AppsGridView::SelectedPageChanged(int old_selected, int new_selected) {
769 if (dragging()) {
770 CalculateDropTarget(last_drag_point_, true);
771 Layout();
772 MaybeStartPageFlipTimer(last_drag_point_);
773 } else {
774 Layout();
775 }
776 }
777
778 void AppsGridView::TransitionChanged() {
779 // Update layout for valid page transition only since over-scroll no longer
780 // animates app icons.
781 const PaginationModel::Transition& transition =
782 pagination_model_->transition();
783 if (pagination_model_->is_valid_page(transition.target_page))
784 Layout();
785 }
786
787 void AppsGridView::OnAppListModelStatusChanged() {
788 UpdatePulsingBlockViews();
789 Layout();
790 SchedulePaint();
791 }
792
793 } // namespace app_list
OLDNEW
« no previous file with comments | « ui/app_list/apps_grid_view.h ('k') | ui/app_list/apps_grid_view_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698