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
) {
150 CreateViewsForFolderTopItemsAnimation(folder_item
, false);
152 top_icon_views_
.clear();
153 // Hide the active folder view until the animation completes.
154 apps_grid_view_
->activated_item_view()->SetVisible(false);
155 SetShowState(SHOW_APPS
);
158 gfx::Size
AppsContainerView::GetPreferredSize() {
159 const gfx::Size grid_size
= apps_grid_view_
->GetPreferredSize();
160 const gfx::Size folder_view_size
= app_list_folder_view_
->GetPreferredSize();
162 int width
= std::max(grid_size
.width(), folder_view_size
.width());
163 int height
= std::max(grid_size
.height(), folder_view_size
.height());
164 return gfx::Size(width
, height
);
167 void AppsContainerView::Layout() {
168 gfx::Rect
rect(GetContentsBounds());
172 switch (show_state_
) {
174 app_list_folder_view_
->ScheduleShowHideAnimation(false);
175 apps_grid_view_
->SetBoundsRect(rect
);
176 apps_grid_view_
->ScheduleShowHideAnimation(true);
178 case SHOW_ACTIVE_FOLDER
:
179 apps_grid_view_
->ScheduleShowHideAnimation(false);
180 app_list_folder_view_
->SetBoundsRect(rect
);
181 app_list_folder_view_
->ScheduleShowHideAnimation(true);
188 bool AppsContainerView::OnKeyPressed(const ui::KeyEvent
& event
) {
189 if (show_state_
== SHOW_APPS
)
190 return apps_grid_view_
->OnKeyPressed(event
);
192 return app_list_folder_view_
->OnKeyPressed(event
);
195 void AppsContainerView::OnTopIconAnimationsComplete(views::View
* icon_view
) {
196 bool animations_done
= true;
197 for (size_t i
= 0; i
< top_icon_views_
.size(); ++i
) {
198 if (top_icon_views_
[i
]->visible()) {
199 animations_done
= false;
204 if (animations_done
) {
205 // Clean up the transitional views using for top item icon animation.
206 for (size_t i
= 0; i
< top_icon_views_
.size(); ++i
) {
207 TopIconAnimationView
* icon_view
=
208 static_cast<TopIconAnimationView
*>(top_icon_views_
[i
]);
209 icon_view
->RemoveObserver(this);
212 top_icon_views_
.clear();
214 // Show the folder icon when closing the folder.
215 if (show_state_
== SHOW_APPS
&& apps_grid_view_
->activated_item_view())
216 apps_grid_view_
->activated_item_view()->SetVisible(true);
220 void AppsContainerView::SetShowState(ShowState show_state
) {
221 if (show_state_
== show_state
)
224 show_state_
= show_state
;
228 Rects
AppsContainerView::GetTopItemIconBoundsInActiveFolder() {
229 // Get the active folder's icon bounds relative to AppsContainerView.
230 AppListItemView
* folder_view
= apps_grid_view_
->activated_item_view();
231 gfx::Rect to_grid_view
= folder_view
->ConvertRectToParent(
232 folder_view
->GetIconBounds());
233 gfx::Rect to_container
= apps_grid_view_
->ConvertRectToParent(to_grid_view
);
235 return AppListFolderItem::GetTopIconsBounds(to_container
);
238 void AppsContainerView::CreateViewsForFolderTopItemsAnimation(
239 AppListFolderItem
* active_folder
,
241 top_icon_views_
.clear();
242 std::vector
<gfx::Rect
> top_items_bounds
=
243 GetTopItemIconBoundsInActiveFolder();
244 size_t top_items_count
=
245 std::min(kNumFolderTopItems
, active_folder
->item_list()->item_count());
246 for (size_t i
= 0; i
< top_items_count
; ++i
) {
247 TopIconAnimationView
* icon_view
= new TopIconAnimationView(
248 active_folder
->GetTopIcon(i
), top_items_bounds
[i
], open_folder
);
249 icon_view
->AddObserver(this);
250 top_icon_views_
.push_back(icon_view
);
252 // Add the transitional views into child views, and set its bounds to the
253 // same location of the item in the folder list view.
254 AddChildView(top_icon_views_
[i
]);
255 top_icon_views_
[i
]->SetBoundsRect(
256 app_list_folder_view_
->ConvertRectToParent(
257 app_list_folder_view_
->GetItemIconBoundsAt(i
)));
258 static_cast<TopIconAnimationView
*>(top_icon_views_
[i
])->TransformView();
262 } // namespace app_list