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 "ui/app_list/views/top_icon_animation_view.h"
6
7#include "base/message_loop/message_loop_proxy.h"
8#include "ui/app_list/app_list_constants.h"
9#include "ui/compositor/scoped_layer_animation_settings.h"
10#include "ui/gfx/image/image_skia_operations.h"
11#include "ui/views/controls/image_view.h"
12
13namespace app_list {
14
15TopIconAnimationView::TopIconAnimationView(const gfx::ImageSkia& icon,
16                                           const gfx::Rect& scaled_rect,
17                                           bool open_folder)
18    : icon_size_(kPreferredIconDimension, kPreferredIconDimension),
19      icon_(new views::ImageView),
20      scaled_rect_(scaled_rect),
21      open_folder_(open_folder) {
22  DCHECK(!icon.isNull());
23  gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(
24      icon,
25      skia::ImageOperations::RESIZE_BEST, icon_size_));
26  icon_->SetImage(resized);
27  AddChildView(icon_);
28
29  SetPaintToLayer(true);
30  SetFillsBoundsOpaquely(false);
31}
32
33TopIconAnimationView::~TopIconAnimationView() {
34  // Required due to RequiresNotificationWhenAnimatorDestroyed() returning true.
35  // See ui::LayerAnimationObserver for details.
36  StopObservingImplicitAnimations();
37}
38
39void TopIconAnimationView::AddObserver(TopIconAnimationObserver* observer) {
40  observers_.AddObserver(observer);
41}
42
43void TopIconAnimationView::RemoveObserver(TopIconAnimationObserver* observer) {
44  observers_.RemoveObserver(observer);
45}
46
47void TopIconAnimationView::TransformView() {
48  // This view will delete itself on animation completion.
49  set_owned_by_client();
50
51  // Transform used for scaling down the icon and move it back inside to the
52  // original folder icon.
53  const float kIconTransformScale = 0.33333f;
54  gfx::Transform transform;
55  transform.Translate(scaled_rect_.x() - layer()->bounds().x(),
56                      scaled_rect_.y() - layer()->bounds().y());
57  transform.Scale(kIconTransformScale, kIconTransformScale);
58
59  if (open_folder_) {
60    // Transform to a scaled down icon inside the original folder icon.
61    layer()->SetTransform(transform);
62  }
63
64  // Animate the icon to its target location and scale when opening or
65  // closing a folder.
66  ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
67  settings.AddObserver(this);
68  settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
69  settings.SetTransitionDuration(
70      base::TimeDelta::FromMilliseconds(kFolderTransitionInDurationMs));
71  layer()->SetTransform(open_folder_ ? gfx::Transform() : transform);
72}
73
74gfx::Size TopIconAnimationView::GetPreferredSize() const {
75  return icon_size_;
76}
77
78void TopIconAnimationView::Layout() {
79  icon_->SetBoundsRect(GetContentsBounds());
80}
81
82void TopIconAnimationView::OnImplicitAnimationsCompleted() {
83  SetVisible(false);
84  FOR_EACH_OBSERVER(TopIconAnimationObserver,
85                    observers_,
86                    OnTopIconAnimationsComplete());
87  base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this);
88}
89
90bool TopIconAnimationView::RequiresNotificationWhenAnimatorDestroyed() const {
91  return true;
92}
93
94}  // namespace app_list
95