download_started_animation_views.cc revision 010d83a9304c5a91596085d917d248abff47903a
1// Copyright (c) 2012 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 "chrome/browser/download/download_started_animation.h"
6
7#include "content/public/browser/web_contents.h"
8#include "grit/theme_resources.h"
9#include "ui/base/resource/resource_bundle.h"
10#include "ui/gfx/animation/linear_animation.h"
11#include "ui/gfx/rect.h"
12#include "ui/views/controls/image_view.h"
13#include "ui/views/widget/widget.h"
14
15// How long to spend moving downwards and fading out after waiting.
16const int kMoveTimeMs = 600;
17
18// The animation framerate.
19const int kFrameRateHz = 60;
20
21namespace {
22
23// DownloadStartAnimation creates an animation (which begins running
24// immediately) that animates an image downward from the center of the frame
25// provided on the constructor, while simultaneously fading it out.  To use,
26// simply call "new DownloadStartAnimation"; the class cleans itself up when it
27// finishes animating.
28class DownloadStartedAnimationViews : public gfx::LinearAnimation,
29                                      public views::ImageView {
30 public:
31  explicit DownloadStartedAnimationViews(content::WebContents* web_contents);
32
33 private:
34  // Move the animation to wherever it should currently be.
35  void Reposition();
36
37  // Shut down the animation cleanly.
38  void Close();
39
40  // Animation
41  virtual void AnimateToState(double state) OVERRIDE;
42
43  // We use a TYPE_POPUP for the popup so that it may float above any windows in
44  // our UI.
45  views::Widget* popup_;
46
47  // The content area at the start of the animation. We store this so that the
48  // download shelf's resizing of the content area doesn't cause the animation
49  // to move around. This means that once started, the animation won't move
50  // with the parent window, but it's so fast that this shouldn't cause too
51  // much heartbreak.
52  gfx::Rect web_contents_bounds_;
53
54  DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationViews);
55};
56
57DownloadStartedAnimationViews::DownloadStartedAnimationViews(
58    content::WebContents* web_contents)
59    : gfx::LinearAnimation(kMoveTimeMs, kFrameRateHz, NULL),
60      popup_(NULL) {
61  static gfx::ImageSkia* kDownloadImage = NULL;
62  if (!kDownloadImage) {
63    kDownloadImage = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
64        IDR_DOWNLOAD_ANIMATION_BEGIN);
65  }
66
67  // If we're too small to show the download image, then don't bother -
68  // the shelf will be enough.
69  web_contents_bounds_= web_contents->GetContainerBounds();
70  if (web_contents_bounds_.height() < kDownloadImage->height())
71    return;
72
73  SetImage(kDownloadImage);
74
75  popup_ = new views::Widget;
76
77  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
78  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
79  params.accept_events = false;
80  params.parent = web_contents->GetNativeView();
81  popup_->Init(params);
82  popup_->SetOpacity(0x00);
83  popup_->SetContentsView(this);
84  Reposition();
85  popup_->Show();
86
87  Start();
88}
89
90void DownloadStartedAnimationViews::Reposition() {
91  // Align the image with the bottom left of the web contents (so that it
92  // points to the newly created download).
93  gfx::Size size = GetPreferredSize();
94  int x = base::i18n::IsRTL() ?
95      web_contents_bounds_.right() - size.width() : web_contents_bounds_.x();
96  popup_->SetBounds(gfx::Rect(
97      x,
98      static_cast<int>(web_contents_bounds_.bottom() -
99          size.height() - size.height() * (1 - GetCurrentValue())),
100      size.width(),
101      size.height()));
102}
103
104void DownloadStartedAnimationViews::Close() {
105  popup_->Close();
106}
107
108void DownloadStartedAnimationViews::AnimateToState(double state) {
109  if (state >= 1.0) {
110    Close();
111  } else {
112    Reposition();
113
114    // Start at zero, peak halfway and end at zero.
115    double opacity = std::min(1.0 - pow(GetCurrentValue() - 0.5, 2) * 4.0,
116                              static_cast<double>(1.0));
117
118    popup_->SetOpacity(static_cast<unsigned char>(opacity * 255.0));
119  }
120}
121
122}  // namespace
123
124// static
125void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
126  // The animation will delete itself when it's finished.
127  new DownloadStartedAnimationViews(web_contents);
128}
129