1 // Copyright 2014 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 "ash/app_list/views/top_icon_animation_view.h"
6 
7 #include "ash/app_list/views/app_list_item_view.h"
8 #include "ash/app_list/views/apps_grid_view.h"
9 #include "ash/public/cpp/app_list/app_list_color_provider.h"
10 #include "ash/public/cpp/app_list/app_list_config.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "ui/compositor/scoped_layer_animation_settings.h"
13 #include "ui/gfx/image/image_skia_operations.h"
14 #include "ui/views/controls/image_view.h"
15 #include "ui/views/controls/label.h"
16 
17 namespace ash {
18 
TopIconAnimationView(AppsGridView * grid,const gfx::ImageSkia & icon,const base::string16 & title,const gfx::Rect & scaled_rect,bool open_folder,bool item_in_folder_icon)19 TopIconAnimationView::TopIconAnimationView(AppsGridView* grid,
20                                            const gfx::ImageSkia& icon,
21                                            const base::string16& title,
22                                            const gfx::Rect& scaled_rect,
23                                            bool open_folder,
24                                            bool item_in_folder_icon)
25     : grid_(grid),
26       icon_(nullptr),
27       title_(nullptr),
28       scaled_rect_(scaled_rect),
29       open_folder_(open_folder),
30       item_in_folder_icon_(item_in_folder_icon) {
31   icon_size_ = grid->GetAppListConfig().grid_icon_size();
32   DCHECK(!icon.isNull());
33   gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(
34       icon, skia::ImageOperations::RESIZE_BEST, icon_size_));
35   auto icon_image = std::make_unique<views::ImageView>();
36   icon_image->SetImage(resized);
37   icon_ = AddChildView(std::move(icon_image));
38 
39   auto title_label = std::make_unique<views::Label>();
40   title_label->SetBackgroundColor(SK_ColorTRANSPARENT);
41   title_label->SetAutoColorReadabilityEnabled(false);
42   title_label->SetHandlesTooltips(false);
43   title_label->SetFontList(grid_->GetAppListConfig().app_title_font());
44   title_label->SetLineHeight(
45       grid_->GetAppListConfig().app_title_max_line_height());
46   title_label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
47   title_label->SetEnabledColor(
48       AppListColorProvider::Get()->GetFolderTitleTextColor(SK_ColorBLACK));
49   title_label->SetText(title);
50   if (item_in_folder_icon_) {
51     // The title's opacity of the item should be changed separately if it is in
52     // the folder item's icon.
53     title_label->SetPaintToLayer();
54     title_label->layer()->SetFillsBoundsOpaquely(false);
55   }
56   title_ = AddChildView(std::move(title_label));
57 
58   SetPaintToLayer();
59   layer()->SetFillsBoundsOpaquely(false);
60 }
61 
~TopIconAnimationView()62 TopIconAnimationView::~TopIconAnimationView() {
63   // Required due to RequiresNotificationWhenAnimatorDestroyed() returning true.
64   // See ui::LayerAnimationObserver for details.
65   StopObservingImplicitAnimations();
66 }
67 
AddObserver(TopIconAnimationObserver * observer)68 void TopIconAnimationView::AddObserver(TopIconAnimationObserver* observer) {
69   observers_.AddObserver(observer);
70 }
71 
RemoveObserver(TopIconAnimationObserver * observer)72 void TopIconAnimationView::RemoveObserver(TopIconAnimationObserver* observer) {
73   observers_.RemoveObserver(observer);
74 }
75 
TransformView()76 void TopIconAnimationView::TransformView() {
77   // Transform used for scaling down the icon and move it back inside to the
78   // original folder icon. The transform's origin is this view's origin.
79   gfx::Transform transform;
80   transform.Translate(scaled_rect_.x() - GetMirroredX(),
81                       scaled_rect_.y() - bounds().y());
82   transform.Scale(
83       static_cast<double>(scaled_rect_.width()) / bounds().width(),
84       static_cast<double>(scaled_rect_.height()) / bounds().height());
85   if (open_folder_) {
86     // Transform to a scaled down icon inside the original folder icon.
87     layer()->SetTransform(transform);
88   }
89 
90   if (!item_in_folder_icon_)
91     layer()->SetOpacity(open_folder_ ? 0.0f : 1.0f);
92 
93   // Animate the icon to its target location and scale when opening or
94   // closing a folder.
95   ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
96   settings.AddObserver(this);
97   settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
98   settings.SetTransitionDuration(
99       grid_->GetAppListConfig().folder_transition_in_duration());
100   layer()->SetTransform(open_folder_ ? gfx::Transform() : transform);
101   if (!item_in_folder_icon_)
102     layer()->SetOpacity(open_folder_ ? 1.0f : 0.0f);
103 
104   if (item_in_folder_icon_) {
105     // Animate the opacity of the title.
106     title_->layer()->SetOpacity(open_folder_ ? 0.0f : 1.0f);
107     ui::ScopedLayerAnimationSettings title_settings(
108         title_->layer()->GetAnimator());
109     title_settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
110     title_settings.SetTransitionDuration(
111         grid_->GetAppListConfig().folder_transition_in_duration());
112     title_->layer()->SetOpacity(open_folder_ ? 1.0f : 0.0f);
113   }
114 }
115 
GetClassName() const116 const char* TopIconAnimationView::GetClassName() const {
117   return "TopIconAnimationView";
118 }
119 
CalculatePreferredSize() const120 gfx::Size TopIconAnimationView::CalculatePreferredSize() const {
121   return gfx::Size(grid_->GetAppListConfig().grid_tile_width(),
122                    grid_->GetAppListConfig().grid_tile_height());
123 }
124 
Layout()125 void TopIconAnimationView::Layout() {
126   // This view's layout should be the same as AppListItemView's.
127   gfx::Rect rect(GetContentsBounds());
128   if (rect.IsEmpty())
129     return;
130 
131   icon_->SetBoundsRect(AppListItemView::GetIconBoundsForTargetViewBounds(
132       grid_->GetAppListConfig(), rect, icon_->GetImage().size(),
133       /*icon_scale=*/1.0f));
134   title_->SetBoundsRect(AppListItemView::GetTitleBoundsForTargetViewBounds(
135       grid_->GetAppListConfig(), rect, title_->GetPreferredSize(),
136       /*icon_scale=*/1.0f));
137 }
138 
OnImplicitAnimationsCompleted()139 void TopIconAnimationView::OnImplicitAnimationsCompleted() {
140   SetVisible(false);
141   for (auto& observer : observers_)
142     observer.OnTopIconAnimationsComplete(this);
143   DCHECK(parent());
144   base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
145       FROM_HERE, parent()->RemoveChildViewT(this));
146 }
147 
RequiresNotificationWhenAnimatorDestroyed() const148 bool TopIconAnimationView::RequiresNotificationWhenAnimatorDestroyed() const {
149   return true;
150 }
151 
152 }  // namespace ash
153