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.
5 #include "ui/app_list/views/apps_container_view.h"
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"
25 // Transitional view used for top item icons animation when opening or closing
27 class TopIconAnimationView : public views::View,
28 public ui::ImplicitAnimationObserver {
30 TopIconAnimationView(const gfx::ImageSkia& icon,
31 const gfx::Rect& scaled_rect,
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(
40 skia::ImageOperations::RESIZE_BEST, icon_size_));
41 icon_->SetImage(resized);
45 SetPaintToLayer(true);
46 SetFillsBoundsOpaquely(false);
49 virtual ~TopIconAnimationView() {}
51 void AddObserver(TopIconAnimationObserver* observer) {
52 observers_.AddObserver(observer);
55 void RemoveObserver(TopIconAnimationObserver* observer) {
56 observers_.RemoveObserver(observer);
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);
69 // Transform to a scaled down icon inside the original folder icon.
70 layer()->SetTransform(transform);
73 // Animate the icon to its target location and scale when opening or
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);
83 // views::View overrides:
84 virtual gfx::Size GetPreferredSize() OVERRIDE {
88 virtual void Layout() OVERRIDE {
89 icon_->SetBoundsRect(GetContentsBounds());
92 // ui::ImplicitAnimationObserver overrides:
93 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
95 FOR_EACH_OBSERVER(TopIconAnimationObserver,
97 OnTopIconAnimationsComplete(this));
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.
107 ObserverList<TopIconAnimationObserver> observers_;
109 DISALLOW_COPY_AND_ASSIGN(TopIconAnimationView);
114 AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view,
115 PaginationModel* pagination_model,
117 content::WebContents* start_page_contents)
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,
125 AddChildView(apps_grid_view_);
127 app_list_folder_view_ = new AppListFolderView(
131 start_page_contents);
132 AddChildView(app_list_folder_view_);
134 apps_grid_view_->SetModel(model_);
135 apps_grid_view_->SetItemList(model_->item_list());
138 AppsContainerView::~AppsContainerView() {
141 void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) {
142 app_list_folder_view_->SetAppListFolderItem(folder_item);
143 SetShowState(SHOW_ACTIVE_FOLDER);
145 CreateViewsForFolderTopItemsAnimation(folder_item, true);
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);
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();
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);
164 void AppsContainerView::Layout() {
165 gfx::Rect rect(GetContentsBounds());
169 switch (show_state_) {
171 app_list_folder_view_->ScheduleShowHideAnimation(false);
172 apps_grid_view_->SetBoundsRect(rect);
173 apps_grid_view_->ScheduleShowHideAnimation(true);
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);
185 bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) {
186 if (show_state_ == SHOW_APPS)
187 return apps_grid_view_->OnKeyPressed(event);
189 return app_list_folder_view_->OnKeyPressed(event);
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;
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);
209 top_icon_views_.clear();
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);
217 void AppsContainerView::SetShowState(ShowState show_state) {
218 if (show_state_ == show_state)
221 show_state_ = show_state;
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);
232 return AppListFolderItem::GetTopIconsBounds(to_container);
235 void AppsContainerView::CreateViewsForFolderTopItemsAnimation(
236 AppListFolderItem* active_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);
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();
259 } // namespace app_list