download_started_animation_views.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com// Copyright (c) 2012 The Chromium Authors. All rights reserved.
242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com// Use of this source code is governed by a BSD-style license that can be
342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com// found in the LICENSE file.
442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "chrome/browser/download/download_started_animation.h"
642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "content/public/browser/web_contents.h"
842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "content/public/browser/web_contents_view.h"
942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "grit/theme_resources.h"
1042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "ui/base/resource/resource_bundle.h"
1142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "ui/gfx/animation/linear_animation.h"
1242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "ui/gfx/rect.h"
1342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "ui/views/controls/image_view.h"
1442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com#include "ui/views/widget/widget.h"
1542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
1642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com// How long to spend moving downwards and fading out after waiting.
1742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.comconst int kMoveTimeMs = 600;
1842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
1942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com// The animation framerate.
2042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.comconst int kFrameRateHz = 60;
2142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
2263ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.comnamespace {
2342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
2442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com// DownloadStartAnimation creates an animation (which begins running
2563ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com// immediately) that animates an image downward from the center of the frame
2642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com// provided on the constructor, while simultaneously fading it out.  To use,
2742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com// simply call "new DownloadStartAnimation"; the class cleans itself up when it
2863ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com// finishes animating.
2942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.comclass DownloadStartedAnimationViews : public gfx::LinearAnimation,
3042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com                                      public views::ImageView {
3163ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com public:
3242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  explicit DownloadStartedAnimationViews(content::WebContents* web_contents);
3342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
3463ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com private:
3542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // Move the animation to wherever it should currently be.
3642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  void Reposition();
3763ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com
3842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // Shut down the animation cleanly.
3942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  void Close();
4063ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com
4142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // Animation
4242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  virtual void AnimateToState(double state) OVERRIDE;
4363ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com
4442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // We use a TYPE_POPUP for the popup so that it may float above any windows in
4542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // our UI.
4663ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com  views::Widget* popup_;
4742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
4842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // The content area at the start of the animation. We store this so that the
4963ba31948392a56c191607d62a2414f16253e47bskia.committer@gmail.com  // download shelf's resizing of the content area doesn't cause the animation
5042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // to move around. This means that once started, the animation won't move
5142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // with the parent window, but it's so fast that this shouldn't cause too
5242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // much heartbreak.
5342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  gfx::Rect web_contents_bounds_;
5442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
5542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationViews);
5642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com};
5742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
5842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.comDownloadStartedAnimationViews::DownloadStartedAnimationViews(
5942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com    content::WebContents* web_contents)
6042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com    : gfx::LinearAnimation(kMoveTimeMs, kFrameRateHz, NULL),
6142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com      popup_(NULL) {
6242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  static gfx::ImageSkia* kDownloadImage = NULL;
6342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  if (!kDownloadImage) {
6442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com    kDownloadImage = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
6542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com        IDR_DOWNLOAD_ANIMATION_BEGIN);
6642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  }
6742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
6842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // If we're too small to show the download image, then don't bother -
6942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // the shelf will be enough.
7042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  web_contents->GetView()->GetContainerBounds(&web_contents_bounds_);
7142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  if (web_contents_bounds_.height() < kDownloadImage->height())
7242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com    return;
7342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
7442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  SetImage(kDownloadImage);
7542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
7642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  popup_ = new views::Widget;
7742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
7842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
7942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
8042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  params.accept_events = false;
8142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  params.parent = web_contents->GetView()->GetNativeView();
8242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  popup_->Init(params);
8342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  popup_->SetOpacity(0x00);
8442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  popup_->SetContentsView(this);
8542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  Reposition();
8642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  popup_->Show();
8742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
8842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  Start();
8942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com}
9042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com
9142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.comvoid DownloadStartedAnimationViews::Reposition() {
9242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // Align the image with the bottom left of the web contents (so that it
9342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  // points to the newly created download).
9442cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  gfx::Size size = GetPreferredSize();
9542cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  int x = base::i18n::IsRTL() ?
9642cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com      web_contents_bounds_.right() - size.width() : web_contents_bounds_.x();
9742cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com  popup_->SetBounds(gfx::Rect(
9842cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com      x,
9942cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com      static_cast<int>(web_contents_bounds_.bottom() -
10042cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com          size.height() - size.height() * (1 - GetCurrentValue())),
10142cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com      size.width(),
10242cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com      size.height()));
10342cc237caf9f02eaf59ad685e4529c184be78a37robertphillips@google.com}
104befb499da5ddf9df7c1986b56d7647f55f97f297robertphillips@google.com
105void DownloadStartedAnimationViews::Close() {
106  popup_->Close();
107}
108
109void DownloadStartedAnimationViews::AnimateToState(double state) {
110  if (state >= 1.0) {
111    Close();
112  } else {
113    Reposition();
114
115    // Start at zero, peak halfway and end at zero.
116    double opacity = std::min(1.0 - pow(GetCurrentValue() - 0.5, 2) * 4.0,
117                              static_cast<double>(1.0));
118
119    popup_->SetOpacity(static_cast<unsigned char>(opacity * 255.0));
120  }
121}
122
123}  // namespace
124
125// static
126void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
127  // The animation will delete itself when it's finished.
128  new DownloadStartedAnimationViews(web_contents);
129}
130