Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / apps_container_view.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/app_list/views/apps_container_view.h"
6
7 #include <algorithm>
8
9 #include "ui/app_list/app_list_constants.h"
10 #include "ui/app_list/app_list_folder_item.h"
11 #include "ui/app_list/pagination_model.h"
12 #include "ui/app_list/views/app_list_folder_view.h"
13 #include "ui/app_list/views/app_list_item_view.h"
14 #include "ui/app_list/views/app_list_main_view.h"
15 #include "ui/app_list/views/apps_grid_view.h"
16 #include "ui/compositor/scoped_layer_animation_settings.h"
17 #include "ui/events/event.h"
18 #include "ui/gfx/image/image_skia_operations.h"
19 #include "ui/views/controls/image_view.h"
20
21 namespace app_list {
22
23 namespace {
24
25 // Transitional view used for top item icons animation when opening or closing
26 // a folder.
27 class TopIconAnimationView : public views::View,
28                              public ui::ImplicitAnimationObserver {
29  public:
30   TopIconAnimationView(const gfx::ImageSkia& icon,
31                        const gfx::Rect& scaled_rect,
32                        bool open_folder)
33       : icon_size_(kPreferredIconDimension, kPreferredIconDimension),
34         icon_(new views::ImageView),
35         scaled_rect_(scaled_rect),
36         open_folder_(open_folder) {
37     DCHECK(!icon.isNull());
38     gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(
39           icon,
40           skia::ImageOperations::RESIZE_BEST, icon_size_));
41     icon_->SetImage(resized);
42     AddChildView(icon_);
43
44 #if defined(USE_AURA)
45     SetPaintToLayer(true);
46     SetFillsBoundsOpaquely(false);
47 #endif
48   }
49   virtual ~TopIconAnimationView() {}
50
51   void AddObserver(TopIconAnimationObserver* observer) {
52     observers_.AddObserver(observer);
53   }
54
55   void RemoveObserver(TopIconAnimationObserver* observer) {
56     observers_.RemoveObserver(observer);
57   }
58
59   void TransformView() {
60     // Transform used for scaling down the icon and move it back inside to the
61     // original folder icon.
62     const float kIconTransformScale = 0.33333f;
63     gfx::Transform transform;
64     transform.Translate(scaled_rect_.x() - layer()->bounds().x(),
65                         scaled_rect_.y() - layer()->bounds().y());
66     transform.Scale(kIconTransformScale, kIconTransformScale);
67
68     if (open_folder_) {
69       // Transform to a scaled down icon inside the original folder icon.
70       layer()->SetTransform(transform);
71     }
72
73     // Animate the icon to its target location and scale when opening or
74     // closing a folder.
75     ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
76     settings.AddObserver(this);
77     settings.SetTransitionDuration(
78         base::TimeDelta::FromMilliseconds(kFolderTransitionInDurationMs));
79     layer()->SetTransform(open_folder_ ? gfx::Transform() : transform);
80   }
81
82  private:
83   // views::View overrides:
84   virtual gfx::Size GetPreferredSize() OVERRIDE {
85     return icon_size_;
86   }
87
88   virtual void Layout() OVERRIDE {
89     icon_->SetBoundsRect(GetContentsBounds());
90   }
91
92   // ui::ImplicitAnimationObserver overrides:
93   virtual void OnImplicitAnimationsCompleted() OVERRIDE {
94     SetVisible(false);
95     FOR_EACH_OBSERVER(TopIconAnimationObserver,
96                       observers_,
97                       OnTopIconAnimationsComplete(this));
98   }
99
100   gfx::Size icon_size_;
101   views::ImageView* icon_;  // Owned by views hierarchy.
102   // Rect of the scaled down top item icon inside folder icon's ink bubble.
103   gfx::Rect scaled_rect_;
104   // True: opening folder; False: closing folder.
105   bool open_folder_;
106
107   ObserverList<TopIconAnimationObserver> observers_;
108
109   DISALLOW_COPY_AND_ASSIGN(TopIconAnimationView);
110 };
111
112 }  // namespace
113
114 AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view,
115                                      PaginationModel* pagination_model,
116                                      AppListModel* model,
117                                      content::WebContents* start_page_contents)
118     : model_(model),
119       show_state_(SHOW_APPS) {
120   apps_grid_view_ = new AppsGridView(
121       app_list_main_view, pagination_model, start_page_contents);
122   apps_grid_view_->SetLayout(kPreferredIconDimension,
123                              kPreferredCols,
124                              kPreferredRows);
125   AddChildView(apps_grid_view_);
126
127   app_list_folder_view_ = new AppListFolderView(
128       this,
129       model,
130       app_list_main_view,
131       start_page_contents);
132   AddChildView(app_list_folder_view_);
133
134   apps_grid_view_->SetModel(model_);
135   apps_grid_view_->SetItemList(model_->item_list());
136 }
137
138 AppsContainerView::~AppsContainerView() {
139 }
140
141 void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) {
142   app_list_folder_view_->SetAppListFolderItem(folder_item);
143   SetShowState(SHOW_ACTIVE_FOLDER);
144
145   CreateViewsForFolderTopItemsAnimation(folder_item, true);
146 }
147
148 void AppsContainerView::ShowApps(AppListFolderItem* folder_item) {
149   CreateViewsForFolderTopItemsAnimation(folder_item, false);
150   // Hide the active folder view until the animation completes.
151   apps_grid_view_->activated_item_view()->SetVisible(false);
152   SetShowState(SHOW_APPS);
153 }
154
155 gfx::Size AppsContainerView::GetPreferredSize() {
156   const gfx::Size grid_size = apps_grid_view_->GetPreferredSize();
157   const gfx::Size folder_view_size = app_list_folder_view_->GetPreferredSize();
158
159   int width = std::max(grid_size.width(), folder_view_size.width());
160   int height = std::max(grid_size.height(), folder_view_size.height());
161   return gfx::Size(width, height);
162 }
163
164 void AppsContainerView::Layout() {
165   gfx::Rect rect(GetContentsBounds());
166   if (rect.IsEmpty())
167     return;
168
169   switch (show_state_) {
170     case SHOW_APPS:
171       app_list_folder_view_->ScheduleShowHideAnimation(false);
172       apps_grid_view_->SetBoundsRect(rect);
173       apps_grid_view_->ScheduleShowHideAnimation(true);
174       break;
175     case SHOW_ACTIVE_FOLDER:
176       apps_grid_view_->ScheduleShowHideAnimation(false);
177       app_list_folder_view_->SetBoundsRect(rect);
178       app_list_folder_view_->ScheduleShowHideAnimation(true);
179       break;
180     default:
181       NOTREACHED();
182   }
183 }
184
185 bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) {
186   if (show_state_ == SHOW_APPS)
187     return apps_grid_view_->OnKeyPressed(event);
188   else
189     return app_list_folder_view_->OnKeyPressed(event);
190 }
191
192 void AppsContainerView::OnTopIconAnimationsComplete(views::View* icon_view) {
193   bool animations_done = true;
194   for (size_t i = 0; i < top_icon_views_.size(); ++i) {
195     if (top_icon_views_[i]->visible()) {
196       animations_done = false;
197       break;
198     }
199   }
200
201   if (animations_done) {
202     // Clean up the transitional views using for top item icon animation.
203     for (size_t i = 0; i < top_icon_views_.size(); ++i) {
204       TopIconAnimationView* icon_view =
205           static_cast<TopIconAnimationView*>(top_icon_views_[i]);
206       icon_view->RemoveObserver(this);
207       delete icon_view;
208     }
209     top_icon_views_.clear();
210
211     // Show the folder icon when closing the folder.
212     if (show_state_ == SHOW_APPS && apps_grid_view_->activated_item_view())
213       apps_grid_view_->activated_item_view()->SetVisible(true);
214   }
215 }
216
217 void AppsContainerView::SetShowState(ShowState show_state) {
218   if (show_state_ == show_state)
219     return;
220
221   show_state_ = show_state;
222   Layout();
223 }
224
225 Rects AppsContainerView::GetTopItemIconBoundsInActiveFolder() {
226   // Get the active folder's icon bounds relative to AppsContainerView.
227   AppListItemView* folder_view = apps_grid_view_->activated_item_view();
228   gfx::Rect to_grid_view = folder_view->ConvertRectToParent(
229       folder_view->GetIconBounds());
230   gfx::Rect to_container = apps_grid_view_->ConvertRectToParent(to_grid_view);
231
232   return AppListFolderItem::GetTopIconsBounds(to_container);
233 }
234
235 void AppsContainerView::CreateViewsForFolderTopItemsAnimation(
236     AppListFolderItem* active_folder,
237     bool open_folder) {
238   top_icon_views_.clear();
239   std::vector<gfx::Rect> top_items_bounds =
240       GetTopItemIconBoundsInActiveFolder();
241   size_t top_items_count =
242       std::min(kNumFolderTopItems, active_folder->item_list()->item_count());
243   for (size_t i = 0; i < top_items_count; ++i) {
244     TopIconAnimationView* icon_view = new TopIconAnimationView(
245         active_folder->GetTopIcon(i), top_items_bounds[i], open_folder);
246     icon_view->AddObserver(this);
247     top_icon_views_.push_back(icon_view);
248
249     // Add the transitional views into child views, and set its bounds to the
250     // same location of the item in the folder list view.
251     AddChildView(top_icon_views_[i]);
252     top_icon_views_[i]->SetBoundsRect(
253         app_list_folder_view_->ConvertRectToParent(
254             app_list_folder_view_->GetItemIconBoundsAt(i)));
255     static_cast<TopIconAnimationView*>(top_icon_views_[i])->TransformView();
256   }
257 }
258
259 }  // namespace app_list