15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/app_list/views/apps_grid_view.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ui/app_list/app_list_item_model.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/app_list/apps_grid_view_delegate.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/app_list/pagination_model.h"
12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ui/app_list/views/app_list_drag_and_drop_host.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/app_list/views/app_list_item_view.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/app_list/views/page_switcher.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/app_list/views/pulsing_block_view.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/animation/animation.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/events/event.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/border.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view_model_utils.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_AURA)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/aura/root_window.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN) && !defined(USE_AURA)
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/command_line.h"
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/files/file_path.h"
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/win/shortcut.h"
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/dragdrop/drag_utils.h"
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/dragdrop/drop_target_win.h"
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/dragdrop/os_exchange_data.h"
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// Distance a drag needs to be from the app grid to be considered 'outside', at
40a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// which point we rearrange the apps to their pre-drag configuration, as a drop
41a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// then would be canceled. We have a buffer to make it easier to drag apps to
42a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// other pages.
43a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst int kDragBufferPx = 20;
44a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding space in pixels for fixed layout.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kLeftRightPadding = 20;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTopPadding = 1;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding space in pixels between pages.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kPagePadding = 40;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Preferred tile size when showing in fixed layout.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kPreferredTileWidth = 88;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kPreferredTileHeight = 98;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Width in pixels of the area on the sides that triggers a page flip.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kPageFlipZoneSize = 40;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delay in milliseconds to do the page flip.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kPageFlipDelayInMs = 1000;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// How many pages on either side of the selected one we prerender.
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kPrerenderPages = 1;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
65a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// The drag and drop proxy should get scaled by this factor.
66a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)const float kDragAndDropProxyScale = 1.5f;
67a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
68a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// For testing we remember the last created grid view.
69a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)app_list::AppsGridView* last_created_grid_view_for_test = NULL;
70a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RowMoveAnimationDelegate is used when moving an item into a different row.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Before running the animation, the item's layer is re-created and kept in
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the original position, then the item is moved to just before its target
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// position and opacity set to 0. When the animation runs, this delegate moves
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the layer and fades it out while fading in the item at the same time.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RowMoveAnimationDelegate
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public views::BoundsAnimator::OwnedAnimationDelegate {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RowMoveAnimationDelegate(views::View* view,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            ui::Layer* layer,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const gfx::Rect& layer_target)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : view_(view),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        layer_(layer),
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        layer_start_(layer ? layer->bounds() : gfx::Rect()),
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        layer_target_(layer_target) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~RowMoveAnimationDelegate() {}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ui::AnimationDelegate overrides:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(animation->GetCurrentValue());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (layer_) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      layer_->SetOpacity(1 - animation->GetCurrentValue());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      layer_->SetBounds(animation->CurrentValueBetween(layer_start_,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       layer_target_));
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      layer_->ScheduleDraw();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1.0f);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1.0f);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The view that needs to be wrapped. Owned by views hierarchy.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view_;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ui::Layer> layer_;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Rect layer_start_;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Rect layer_target_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(RowMoveAnimationDelegate);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace app_list {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN) && !defined(USE_AURA)
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Interprets drag events sent from Windows via the drag/drop API and forwards
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// them to AppsGridView.
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// On Windows, in order to have the OS perform the drag properly we need to
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// provide it with a shortcut file which may or may not exist at the time the
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// drag is started. Therefore while waiting for that shortcut to be located we
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// just do a regular "internal" drag and transition into the synchronous drag
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// when the shortcut is found/created. Hence a synchronous drag is an optional
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// phase of a regular drag and non-Windows platforms drags are equivalent to a
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Windows drag that never enters the synchronous drag phase.
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass SynchronousDrag : public ui::DragSourceWin {
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SynchronousDrag(app_list::AppsGridView* grid_view,
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              app_list::AppListItemView* drag_view,
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              const gfx::Point& drag_view_offset)
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : grid_view_(grid_view),
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        drag_view_(drag_view),
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        drag_view_offset_(drag_view_offset),
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        has_shortcut_path_(false),
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        running_(false),
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        canceled_(false) {
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void set_shortcut_path(const base::FilePath& shortcut_path) {
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    has_shortcut_path_ = true;
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    shortcut_path_ = shortcut_path;
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool CanRun() {
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return has_shortcut_path_ && !running_;
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void Run() {
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(CanRun());
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    running_ = true;
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ui::OSExchangeData data;
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SetupExchangeData(&data);
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Hide the dragged view because the OS is going to create its own.
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const gfx::Size drag_view_size = drag_view_->size();
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    drag_view_->SetSize(gfx::Size(0, 0));
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Blocks until the drag is finished. Calls into the ui::DragSourceWin
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // methods.
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DWORD effects;
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DoDragDrop(ui::OSExchangeDataProviderWin::GetIDataObject(data),
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch               this, DROPEFFECT_MOVE | DROPEFFECT_LINK, &effects);
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Restore the dragged view to its original size.
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    drag_view_->SetSize(drag_view_size);
176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    grid_view_->EndDrag(canceled_ || !IsCursorWithinGridView());
178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Overridden from ui::DragSourceWin.
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual void OnDragSourceCancel() OVERRIDE {
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    canceled_ = true;
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual void OnDragSourceDrop() OVERRIDE {
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual void OnDragSourceMove() OVERRIDE {
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    grid_view_->UpdateDrag(app_list::AppsGridView::MOUSE,
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           GetCursorInGridViewCoords());
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetupExchangeData(ui::OSExchangeData* data) {
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    data->SetFilename(shortcut_path_);
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    gfx::ImageSkia image(drag_view_->GetDragImage());
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    gfx::Size image_size(image.size());
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    drag_utils::SetDragImageOnDataObject(
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        image,
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        image.size(),
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        gfx::Vector2d(drag_view_offset_.x(), drag_view_offset_.y()),
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        data);
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  HWND GetGridViewHWND() {
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return grid_view_->GetWidget()->GetTopLevelWidget()->GetNativeView();
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool IsCursorWithinGridView() {
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    POINT p;
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    GetCursorPos(&p);
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return GetGridViewHWND() == WindowFromPoint(p);
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Point GetCursorInGridViewCoords() {
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    POINT p;
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    GetCursorPos(&p);
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ScreenToClient(GetGridViewHWND(), &p);
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    gfx::Point grid_view_pt(p.x, p.y);
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    views::View::ConvertPointFromWidget(grid_view_, &grid_view_pt);
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return grid_view_pt;
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  app_list::AppsGridView* grid_view_;
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  app_list::AppListItemView* drag_view_;
226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Point drag_view_offset_;
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool has_shortcut_path_;
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath shortcut_path_;
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool running_;
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool canceled_;
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DISALLOW_COPY_AND_ASSIGN(SynchronousDrag);
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // defined(OS_WIN) && !defined(USE_AURA)
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppsGridView::AppsGridView(AppsGridViewDelegate* delegate,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           PaginationModel* pagination_model)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : model_(NULL),
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate),
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pagination_model_(pagination_model),
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_switcher_view_(new PageSwitcher(pagination_model)),
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cols_(0),
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rows_per_page_(0),
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      selected_view_(NULL),
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_view_(NULL),
246a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      drag_start_page_(-1),
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_pointer_(NONE),
248b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      drag_and_drop_host_(NULL),
249b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      forward_events_to_drag_and_drop_host_(false),
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_flip_target_(-1),
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_flip_delay_in_ms_(kPageFlipDelayInMs),
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bounds_animator_(this) {
253a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  last_created_grid_view_for_test = this;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pagination_model_->AddObserver(this);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(page_switcher_view_);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppsGridView::~AppsGridView() {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->RemoveObserver(this);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->apps()->RemoveObserver(this);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pagination_model_->RemoveObserver(this);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::SetLayout(int icon_size, int cols, int rows_per_page) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_size_.SetSize(icon_size, icon_size);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cols_ = cols;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rows_per_page_ = rows_per_page;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_border(views::Border::CreateEmptyBorder(kTopPadding,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              kLeftRightPadding,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              0,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              kLeftRightPadding));
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::SetModel(AppListModel* model) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->RemoveObserver(this);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->apps()->RemoveObserver(this);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_ = model;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->AddObserver(this);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->apps()->AddObserver(this);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Update();
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::SetSelectedView(views::View* view) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsSelectedView(view) || IsDraggedView(view))
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Index index = GetIndexOfView(view);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsValidIndex(index))
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetSelectedItemByIndex(index);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::ClearSelectedView(views::View* view) {
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (view && IsSelectedView(view)) {
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    selected_view_->SchedulePaint();
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    selected_view_ = NULL;
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppsGridView::IsSelectedView(const views::View* view) const {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return selected_view_ == view;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::EnsureViewVisible(const views::View* view) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pagination_model_->has_transition())
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Index index = GetIndexOfView(view);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsValidIndex(index))
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pagination_model_->SelectPage(index.page, false);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
320b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void AppsGridView::InitiateDrag(AppListItemView* view,
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                Pointer pointer,
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const ui::LocatedEvent& event) {
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(view);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_view_ || pulsing_blocks_model_.view_size())
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_view_ = view;
328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  drag_view_offset_ = event.location();
329a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  drag_start_page_ = pagination_model_->selected_page();
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ExtractDragLocation(event, &drag_start_grid_view_);
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  drag_view_start_ = gfx::Point(drag_view_->x(), drag_view_->y());
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AppsGridView::OnGotShortcutPath(const base::FilePath& path) {
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN) && !defined(USE_AURA)
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Drag may have ended before we get the shortcut path.
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!synchronous_drag_)
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Setting the shortcut path here means the next time we hit UpdateDrag()
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // we'll enter the synchronous drag.
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // NOTE we don't Run() the drag here because that causes animations not to
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // update for some reason.
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  synchronous_drag_->set_shortcut_path(path);
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(synchronous_drag_->CanRun());
345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AppsGridView::StartSettingUpSynchronousDrag() {
349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN) && !defined(USE_AURA)
350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  delegate_->GetShortcutPathForApp(
351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    drag_view_->model()->app_id(),
352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::Bind(&AppsGridView::OnGotShortcutPath, base::Unretained(this)));
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  synchronous_drag_ = new SynchronousDrag(this, drag_view_, drag_view_offset_);
354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
355eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool AppsGridView::RunSynchronousDrag() {
358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN) && !defined(USE_AURA)
359eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (synchronous_drag_ && synchronous_drag_->CanRun()) {
360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    synchronous_drag_->Run();
361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    synchronous_drag_ = NULL;
362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return true;
363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return false;
366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AppsGridView::CleanUpSynchronousDrag() {
369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN) && !defined(USE_AURA)
370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  synchronous_drag_ = NULL;
371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AppsGridView::UpdateDragFromItem(Pointer pointer,
375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const ui::LocatedEvent& event) {
376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Point drag_point_in_grid_view;
377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ExtractDragLocation(event, &drag_point_in_grid_view);
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UpdateDrag(pointer, drag_point_in_grid_view);
3797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!dragging())
3807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // If a drag and drop host is provided, see if the drag operation needs to be
383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // forwarded.
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DispatchDragEventToDragAndDropHost(event.root_location());
385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (drag_and_drop_host_)
386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    drag_and_drop_host_->UpdateDragIconProxy(event.root_location());
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AppsGridView::UpdateDrag(Pointer pointer, const gfx::Point& point) {
390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // EndDrag was called before if |drag_view_| is NULL.
391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!drag_view_)
392868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
393868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (RunSynchronousDrag())
395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
396eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Vector2d drag_vector(point - drag_start_grid_view_);
398eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!dragging() && ExceededDragThreshold(drag_vector)) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_pointer_ = pointer;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Move the view to the front so that it appears on top of other views.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReorderChildView(drag_view_, -1);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds_animator_.StopAnimatingView(drag_view_);
403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    StartSettingUpSynchronousDrag();
4047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    StartDragAndDropHostDrag(point);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
406eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (drag_pointer_ != pointer)
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
410eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  last_drag_point_ = point;
411a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const Index last_drop_target = drop_target_;
412a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CalculateDropTarget(last_drag_point_, false);
413a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
414a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (IsPointWithinDragBuffer(last_drag_point_))
415a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    MaybeStartPageFlipTimer(last_drag_point_);
416a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  else
417a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    StopPageFlipTimer();
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Point page_switcher_point(last_drag_point_);
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View::ConvertPointToTarget(this, page_switcher_view_,
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    &page_switcher_point);
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  page_switcher_view_->UpdateUIForDragPoint(page_switcher_point);
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (last_drop_target != drop_target_)
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AnimateToIdealBounds();
426a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  drag_view_->SetPosition(drag_view_start_ + drag_vector);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::EndDrag(bool cancel) {
431868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // EndDrag was called before if |drag_view_| is NULL.
432868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!drag_view_)
433868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
434868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
435b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (forward_events_to_drag_and_drop_host_) {
436b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    forward_events_to_drag_and_drop_host_ = false;
437b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    drag_and_drop_host_->EndDrag(cancel);
438868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (!cancel && dragging()) {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CalculateDropTarget(last_drag_point_, true);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsValidIndex(drop_target_))
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MoveItemInModel(drag_view_, drop_target_);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
444a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (drag_and_drop_host_) {
445868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // If we had a drag and drop proxy icon, we delete it and make the real
446868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // item visible again.
447a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    drag_and_drop_host_->DestroyDragIconProxy();
448868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    HideView(drag_view_, false);
449a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
450a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The drag can be ended after the synchronous drag is created but before it
452eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // is Run().
453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CleanUpSynchronousDrag();
454eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_pointer_ = NONE;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drop_target_ = Index();
457868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  drag_view_ = NULL;
458a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  drag_start_grid_view_ = gfx::Point();
459a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  drag_start_page_ = -1;
460a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  drag_view_offset_ = gfx::Point();
461868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  AnimateToIdealBounds();
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  StopPageFlipTimer();
464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AppsGridView::StopPageFlipTimer() {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  page_flip_timer_.Stop();
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  page_flip_target_ = -1;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppsGridView::IsDraggedView(const views::View* view) const {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return drag_view_ == view;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void AppsGridView::SetDragAndDropHostOfCurrentAppList(
476b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    ApplicationDragAndDropHost* drag_and_drop_host) {
477b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  drag_and_drop_host_ = drag_and_drop_host;
478b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
479b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppsGridView::Prerender(int page_index) {
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Layout();
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int start = std::max(0, (page_index - kPrerenderPages) * tiles_per_page());
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int end = std::min(view_model_.view_size(),
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     (page_index + 1 + kPrerenderPages) * tiles_per_page());
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = start; i < end; i++) {
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AppListItemView* v = static_cast<AppListItemView*>(view_model_.view_at(i));
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    v->Prerender();
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size AppsGridView::GetPreferredSize() {
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Insets insets(GetInsets());
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Size tile_size = gfx::Size(kPreferredTileWidth,
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        kPreferredTileHeight);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int page_switcher_height =
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_switcher_view_->GetPreferredSize().height();
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Size(
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tile_size.width() * cols_ + insets.width(),
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tile_size.height() * rows_per_page_ +
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          page_switcher_height + insets.height());
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool AppsGridView::GetDropFormats(
504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int* formats,
505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::set<OSExchangeData::CustomFormat>* custom_formats) {
506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(koz): Only accept a specific drag type for app shortcuts.
507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  *formats = OSExchangeData::FILE_NAME;
508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool AppsGridView::CanDrop(const OSExchangeData& data) {
512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint AppsGridView::OnDragUpdated(const ui::DropTargetEvent& event) {
516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return ui::DragDropTypes::DRAG_MOVE;
517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::Layout() {
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bounds_animator_.IsAnimating())
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds_animator_.Cancel();
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateIdealBounds();
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < view_model_.view_size(); ++i) {
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* view = view_model_.view_at(i);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (view != drag_view_)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view->SetBoundsRect(view_model_.ideal_bounds(i));
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model_);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int page_switcher_height =
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_switcher_view_->GetPreferredSize().height();
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect rect(GetContentsBounds());
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rect.set_y(rect.bottom() - page_switcher_height);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rect.set_height(page_switcher_height);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  page_switcher_view_->SetBoundsRect(rect);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppsGridView::OnKeyPressed(const ui::KeyEvent& event) {
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = false;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selected_view_)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handled = selected_view_->OnKeyPressed(event);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handled) {
545a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const int forward_dir = base::i18n::IsRTL() ? -1 : 1;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (event.key_code()) {
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::VKEY_LEFT:
54890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        MoveSelected(0, -forward_dir, 0);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::VKEY_RIGHT:
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        MoveSelected(0, forward_dir, 0);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::VKEY_UP:
55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        MoveSelected(0, 0, -1);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::VKEY_DOWN:
55790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        MoveSelected(0, 0, 1);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::VKEY_PRIOR: {
56090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        MoveSelected(-1, 0, 0);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ui::VKEY_NEXT: {
56490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        MoveSelected(1, 0, 0);
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppsGridView::OnKeyReleased(const ui::KeyEvent& event) {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = false;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selected_view_)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handled = selected_view_->OnKeyReleased(event);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
583a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void AppsGridView::ViewHierarchyChanged(
584a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const ViewHierarchyChangedDetails& details) {
585a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!details.is_add && details.parent == this) {
586a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (selected_view_ == details.child)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      selected_view_ = NULL;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
589a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (drag_view_ == details.child)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EndDrag(true);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
592a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    bounds_animator_.StopAnimatingView(details.child);
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
596a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// static
597a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)AppsGridView* AppsGridView::GetLastGridViewForTest() {
598a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return last_created_grid_view_for_test;
599a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
600a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::Update() {
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!selected_view_ && !drag_view_);
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_.Clear();
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_ && model_->apps()->item_count())
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ListItemsAdded(0, model_->apps()->item_count());
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::UpdatePaging() {
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!view_model_.view_size() || !tiles_per_page()) {
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pagination_model_->SetTotalPages(0);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pagination_model_->SetTotalPages(
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (view_model_.view_size() - 1) / tiles_per_page() + 1);
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::UpdatePulsingBlockViews() {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int available_slots =
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tiles_per_page() - model_->apps()->item_count() % tiles_per_page();
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int desired = model_->status() == AppListModel::STATUS_SYNCING ?
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      available_slots : 0;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pulsing_blocks_model_.view_size() == desired)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (pulsing_blocks_model_.view_size() > desired) {
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* view = pulsing_blocks_model_.view_at(0);
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pulsing_blocks_model_.Remove(0);
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete view;
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (pulsing_blocks_model_.view_size() < desired) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* view = new PulsingBlockView(
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gfx::Size(kPreferredTileWidth, kPreferredTileHeight), true);
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pulsing_blocks_model_.Add(view, 0);
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(view);
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::View* AppsGridView::CreateViewForItemAtIndex(size_t index) {
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LT(index, model_->apps()->item_count());
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppListItemView* view = new AppListItemView(this,
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              model_->apps()->GetItemAt(index));
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetIconSize(icon_size_);
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_AURA)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetPaintToLayer(true);
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetFillsBoundsOpaquely(false);
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return view;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::SetSelectedItemByIndex(const Index& index) {
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetIndexOfView(selected_view_) == index)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View* new_selection = GetViewAtIndex(index);
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!new_selection)
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;  // Keep current selection.
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selected_view_)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    selected_view_->SchedulePaint();
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EnsureViewVisible(new_selection);
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  selected_view_ = new_selection;
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  selected_view_->SchedulePaint();
668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  selected_view_->NotifyAccessibilityEvent(
669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ui::AccessibilityTypes::EVENT_FOCUS, true);
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppsGridView::IsValidIndex(const Index& index) const {
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index.page >= 0 && index.page < pagination_model_->total_pages() &&
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      index.slot >= 0 && index.slot < tiles_per_page() &&
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      index.page * tiles_per_page() + index.slot < view_model_.view_size();
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppsGridView::Index AppsGridView::GetIndexOfView(
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const views::View* view) const {
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int model_index = view_model_.GetIndexOfView(view);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_index == -1)
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Index();
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Index(model_index / tiles_per_page(), model_index % tiles_per_page());
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::View* AppsGridView::GetViewAtIndex(const Index& index) const {
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsValidIndex(index))
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int model_index = index.page * tiles_per_page() + index.slot;
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return view_model_.view_at(model_index);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
69590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void AppsGridView::MoveSelected(int page_delta,
69690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                int slot_x_delta,
69790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                int slot_y_delta) {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!selected_view_)
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return SetSelectedItemByIndex(Index(pagination_model_->selected_page(), 0));
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Index& selected = GetIndexOfView(selected_view_);
70290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int target_slot = selected.slot + slot_x_delta + slot_y_delta * cols_;
70390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
70490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (selected.slot % cols_ == 0 && slot_x_delta == -1) {
70590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (selected.page > 0) {
70690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      page_delta = -1;
70790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      target_slot = selected.slot + cols_ - 1;
70890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
70990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      target_slot = selected.slot;
71090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
71190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
71290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
71390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (selected.slot % cols_ == cols_ - 1 && slot_x_delta == 1) {
71490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (selected.page < pagination_model_->total_pages() - 1) {
71590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      page_delta = 1;
71690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      target_slot = selected.slot - cols_ + 1;
71790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
71890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      target_slot = selected.slot;
71990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
72090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
72190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
72290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Clamp the target slot to the last item if we are moving to the last page
72390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // but our target slot is past the end of the item list.
72490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (page_delta &&
72590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      selected.page + page_delta == pagination_model_->total_pages() - 1) {
72690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int last_item_slot = (view_model_.view_size() - 1) % tiles_per_page();
72790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (last_item_slot < target_slot) {
72890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      target_slot = last_item_slot;
72990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_page = std::min(pagination_model_->total_pages() - 1,
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             std::max(selected.page + page_delta, 0));
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelectedItemByIndex(Index(target_page, target_slot));
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::CalculateIdealBounds() {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect rect(GetContentsBounds());
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rect.IsEmpty())
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size tile_size(kPreferredTileWidth, kPreferredTileHeight);
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect grid_rect(gfx::Size(tile_size.width() * cols_,
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                tile_size.height() * rows_per_page_));
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  grid_rect.Intersect(rect);
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Page width including padding pixels. A tile.x + page_width means the same
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // tile slot in the next page.
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int page_width = grid_rect.width() + kPagePadding;
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is a transition, calculates offset for current and target page.
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int current_page = pagination_model_->selected_page();
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PaginationModel::Transition& transition =
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pagination_model_->transition();
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool is_valid =
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pagination_model_->is_valid_page(transition.target_page);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Transition to right means negative offset.
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int dir = transition.target_page > current_page ? -1 : 1;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int transition_offset = is_valid ?
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition.progress * page_width * dir : 0;
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int total_views =
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_model_.view_size() + pulsing_blocks_model_.view_size();
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int slot_index = 0;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < total_views; ++i) {
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i < view_model_.view_size() && view_model_.view_at(i) == drag_view_)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int page = slot_index / tiles_per_page();
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int slot = slot_index % tiles_per_page();
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (drop_target_.page == page && drop_target_.slot == slot) {
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++slot_index;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page = slot_index / tiles_per_page();
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      slot = slot_index % tiles_per_page();
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Decides an x_offset for current item.
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x_offset = 0;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (page < current_page)
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      x_offset = -page_width;
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (page > current_page)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      x_offset = page_width;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_valid) {
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (page == current_page || page == transition.target_page)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x_offset += transition_offset;
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int row = slot / cols_;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int col = slot % cols_;
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect tile_slot(
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gfx::Point(grid_rect.x() + col * tile_size.width() + x_offset,
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   grid_rect.y() + row * tile_size.height()),
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tile_size);
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i < view_model_.view_size()) {
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_model_.set_ideal_bounds(i, tile_slot);
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pulsing_blocks_model_.set_ideal_bounds(i - view_model_.view_size(),
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             tile_slot);
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++slot_index;
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::AnimateToIdealBounds() {
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Rect visible_bounds(GetVisibleBounds());
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateIdealBounds();
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < view_model_.view_size(); ++i) {
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* view = view_model_.view_at(i);
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (view == drag_view_)
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Rect& target = view_model_.ideal_bounds(i);
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bounds_animator_.GetTargetBounds(view) == target)
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Rect& current = view->bounds();
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const bool current_visible = visible_bounds.Intersects(current);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const bool target_visible = visible_bounds.Intersects(target);
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const bool visible = current_visible || target_visible;
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int y_diff = target.y() - current.y();
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visible && y_diff && y_diff % kPreferredTileHeight == 0) {
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AnimationBetweenRows(view,
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           current_visible,
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           current,
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           target_visible,
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           target);
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bounds_animator_.AnimateViewTo(view, target);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::AnimationBetweenRows(views::View* view,
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        bool animate_current,
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const gfx::Rect& current,
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        bool animate_target,
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const gfx::Rect& target) {
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determine page of |current| and |target|. -1 means in the left invisible
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // page, 0 is the center visible page and 1 means in the right invisible page.
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int current_page = current.x() < 0 ? -1 :
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current.x() >= width() ? 1 : 0;
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int target_page = target.x() < 0 ? -1 :
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      target.x() >= width() ? 1 : 0;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int dir = current_page < target_page ||
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (current_page == target_page && current.y() < target.y()) ? 1 : -1;
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_AURA)
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ui::Layer> layer;
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (animate_current) {
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    layer.reset(view->RecreateLayer());
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    layer->SuppressPaint();
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view->SetFillsBoundsOpaquely(false);
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view->layer()->SetOpacity(0.f);
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect current_out(current);
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_out.Offset(dir * kPreferredTileWidth, 0);
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect target_in(target);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (animate_target)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_in.Offset(-dir * kPreferredTileWidth, 0);
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetBoundsRect(target_in);
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_.AnimateViewTo(view, target);
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_AURA)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_.SetAnimationDelegate(
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view,
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new RowMoveAnimationDelegate(view, layer.release(), current_out),
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      true);
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppsGridView::ExtractDragLocation(const ui::LocatedEvent& event,
8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       gfx::Point* drag_point) {
8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_AURA)
8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Use root location of |event| instead of location in |drag_view_|'s
8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // coordinates because |drag_view_| has a scale transform and location
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // could have integer round error and causes jitter.
8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *drag_point = event.root_location();
8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // GetWidget() could be NULL for tests.
8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (GetWidget()) {
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window::ConvertPointToTarget(
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetWidget()->GetNativeWindow()->GetRootWindow(),
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetWidget()->GetNativeWindow(),
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        drag_point);
8972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View::ConvertPointFromWidget(this, drag_point);
9002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // For non-aura, root location is not clearly defined but |drag_view_| does
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // not have the scale transform. So no round error would be introduced and
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it's okay to use View::ConvertPointToTarget.
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *drag_point = event.location();
9052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View::ConvertPointToTarget(drag_view_, this, drag_point);
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::CalculateDropTarget(const gfx::Point& drag_point,
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       bool use_page_button_hovering) {
911a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  int current_page = pagination_model_->selected_page();
912a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  gfx::Point point(drag_point);
913a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (!IsPointWithinDragBuffer(drag_point)) {
914a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    point = drag_start_grid_view_;
915a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    current_page = drag_start_page_;
916a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (use_page_button_hovering &&
919a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      page_switcher_view_->bounds().Contains(point)) {
920a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    gfx::Point page_switcher_point(point);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View::ConvertPointToTarget(this, page_switcher_view_,
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &page_switcher_point);
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int page = page_switcher_view_->GetPageForPoint(page_switcher_point);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pagination_model_->is_valid_page(page)) {
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drop_target_.page = page;
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drop_target_.slot = tiles_per_page() - 1;
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
929558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    gfx::Rect bounds(GetContentsBounds());
930558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    const int drop_row = (point.y() - bounds.y()) / kPreferredTileHeight;
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int drop_col = std::min(cols_ - 1,
932558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        (point.x() - bounds.x()) / kPreferredTileWidth);
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drop_target_.page = current_page;
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drop_target_.slot = std::max(0, std::min(
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tiles_per_page() - 1,
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        drop_row * cols_ + drop_col));
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limits to the last possible slot on last page.
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drop_target_.page == pagination_model_->total_pages() - 1) {
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drop_target_.slot = std::min(
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (view_model_.view_size() - 1) % tiles_per_page(),
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        drop_target_.slot);
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid AppsGridView::StartDragAndDropHostDrag(const gfx::Point& grid_location) {
9497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // When a drag and drop host is given, the item can be dragged out of the app
9507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // list window. In that case a proxy widget needs to be used.
9517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Note: This code has very likely to be changed for Windows (non metro mode)
9527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // when a |drag_and_drop_host_| gets implemented.
9537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!drag_view_ || !drag_and_drop_host_)
9547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
9557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
9567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  gfx::Point screen_location = grid_location;
9577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  views::View::ConvertPointToScreen(this, &screen_location);
9587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
9597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Determine the mouse offset to the center of the icon so that the drag and
9607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // drop host follows this layer.
9617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  gfx::Vector2d delta = drag_view_offset_ -
9627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        drag_view_->GetLocalBounds().CenterPoint();
9637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  delta.set_y(delta.y() + drag_view_->title()->size().height() / 2);
9647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
9657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // We have to hide the original item since the drag and drop host will do
9667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // the OS dependent code to "lift off the dragged item".
9677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  drag_and_drop_host_->CreateDragIconProxy(screen_location,
9687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                           drag_view_->model()->icon(),
9697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                           drag_view_,
9707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                           delta,
9717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                           kDragAndDropProxyScale);
9727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  HideView(drag_view_, true);
9737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
9747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
975b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void AppsGridView::DispatchDragEventToDragAndDropHost(
976eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const gfx::Point& point) {
977b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!drag_view_ || !drag_and_drop_host_)
978b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
979b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (bounds().Contains(last_drag_point_)) {
980b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // The event was issued inside the app menu and we should get all events.
981b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (forward_events_to_drag_and_drop_host_) {
982b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // The DnD host was previously called and needs to be informed that the
983b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // session returns to the owner.
984b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      forward_events_to_drag_and_drop_host_ = false;
985b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      drag_and_drop_host_->EndDrag(true);
986b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
987b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  } else {
988b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // The event happened outside our app menu and we might need to dispatch.
989b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (forward_events_to_drag_and_drop_host_) {
990b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // Dispatch since we have already started.
991eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (!drag_and_drop_host_->Drag(point)) {
992b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        // The host is not active any longer and we cancel the operation.
993b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        forward_events_to_drag_and_drop_host_ = false;
994b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        drag_and_drop_host_->EndDrag(true);
995b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      }
996b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    } else {
997b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      if (drag_and_drop_host_->StartDrag(drag_view_->model()->app_id(),
998eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         point)) {
999b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        // From now on we forward the drag events.
1000b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        forward_events_to_drag_and_drop_host_ = true;
1001b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        // Any flip operations are stopped.
1002eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        StopPageFlipTimer();
1003b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      }
1004b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
1005b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
1006b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1007b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::MaybeStartPageFlipTimer(const gfx::Point& drag_point) {
1009a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (!IsPointWithinDragBuffer(drag_point))
1010a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    StopPageFlipTimer();
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int new_page_flip_target = -1;
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_switcher_view_->bounds().Contains(drag_point)) {
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Point page_switcher_point(drag_point);
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View::ConvertPointToTarget(this, page_switcher_view_,
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &page_switcher_point);
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_page_flip_target =
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        page_switcher_view_->GetPageForPoint(page_switcher_point);
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(xiyuan): Fix this for RTL.
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_page_flip_target == -1 && drag_point.x() < kPageFlipZoneSize)
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_page_flip_target = pagination_model_->selected_page() - 1;
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_page_flip_target == -1 &&
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_point.x() > width() - kPageFlipZoneSize) {
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_page_flip_target = pagination_model_->selected_page() + 1;
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_page_flip_target == page_flip_target_)
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1033a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  StopPageFlipTimer();
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pagination_model_->is_valid_page(new_page_flip_target)) {
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page_flip_target_ = new_page_flip_target;
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (page_flip_target_ != pagination_model_->selected_page()) {
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_flip_timer_.Start(FROM_HERE,
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeDelta::FromMilliseconds(page_flip_delay_in_ms_),
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this, &AppsGridView::OnPageFlipTimer);
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::OnPageFlipTimer() {
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pagination_model_->is_valid_page(page_flip_target_));
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pagination_model_->SelectPage(page_flip_target_, true);
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::MoveItemInModel(views::View* item_view,
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const Index& target) {
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int current_model_index = view_model_.GetIndexOfView(item_view);
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(current_model_index, 0);
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_model_index = target.page * tiles_per_page() + target.slot;
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_model_index == current_model_index)
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->apps()->RemoveObserver(this);
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->apps()->Move(current_model_index, target_model_index);
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_.Move(current_model_index, target_model_index);
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->apps()->AddObserver(this);
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pagination_model_->selected_page() != target.page)
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pagination_model_->SelectPage(target.page, false);
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid AppsGridView::CancelContextMenusOnCurrentPage() {
10697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int start = pagination_model_->selected_page() * tiles_per_page();
10707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int end = std::min(view_model_.view_size(), start + tiles_per_page());
10717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (int i = start; i < end; ++i) {
10727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    AppListItemView* view =
10737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        static_cast<AppListItemView*>(view_model_.view_at(i));
10747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    view->CancelContextMenu();
10757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
10767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
10777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1078a3f7b4e666c476898878fa745f637129375cd889Ben Murdochbool AppsGridView::IsPointWithinDragBuffer(const gfx::Point& point) const {
1079a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  gfx::Rect rect(GetLocalBounds());
1080a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  rect.Inset(-kDragBufferPx, -kDragBufferPx, -kDragBufferPx, -kDragBufferPx);
1081a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return rect.Contains(point);
1082a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
1083a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::ButtonPressed(views::Button* sender,
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const ui::Event& event) {
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dragging())
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1089b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (strcmp(sender->GetClassName(), AppListItemView::kViewClassName))
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_) {
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->ActivateApp(static_cast<AppListItemView*>(sender)->model(),
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           event.flags());
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::ListItemsAdded(size_t start, size_t count) {
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EndDrag(true);
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = start; i < start + count; ++i) {
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* view = CreateViewForItemAtIndex(i);
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_.Add(view, i);
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(view);
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePaging();
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePulsingBlockViews();
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::ListItemsRemoved(size_t start, size_t count) {
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EndDrag(true);
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < count; ++i) {
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* view = view_model_.view_at(start);
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_.Remove(start);
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete view;
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePaging();
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePulsingBlockViews();
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::ListItemMoved(size_t index, size_t target_index) {
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EndDrag(true);
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_.Move(index, target_index);
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePaging();
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AnimateToIdealBounds();
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::ListItemsChanged(size_t start, size_t count) {
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::TotalPagesChanged() {
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::SelectedPageChanged(int old_selected, int new_selected) {
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dragging()) {
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CalculateDropTarget(last_drag_point_, true);
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Layout();
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MaybeStartPageFlipTimer(last_drag_point_);
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ClearSelectedView(selected_view_);
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Layout();
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid AppsGridView::TransitionStarted() {
11557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  CancelContextMenusOnCurrentPage();
11567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
11577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::TransitionChanged() {
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update layout for valid page transition only since over-scroll no longer
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // animates app icons.
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PaginationModel::Transition& transition =
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pagination_model_->transition();
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pagination_model_->is_valid_page(transition.target_page))
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Layout();
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppsGridView::OnAppListModelStatusChanged() {
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePulsingBlockViews();
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void AppsGridView::HideView(views::View* view, bool hide) {
1174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(USE_AURA)
1175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ui::ScopedLayerAnimationSettings animator(view->layer()->GetAnimator());
1176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  animator.SetPreemptionStrategy(ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
1177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  view->layer()->SetOpacity(hide ? 0 : 1);
1178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
1179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
1180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace app_list
1182