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