1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/download/download_started_animation.h"
#include "app/linear_animation.h"
#include "app/resource_bundle.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "gfx/rect.h"
#include "grit/theme_resources.h"
#include "views/controls/image_view.h"
#include "views/widget/widget_win.h"
// How long to spend moving downwards and fading out after waiting.
static const int kMoveTimeMs = 600;
// The animation framerate.
static const int kFrameRateHz = 60;
// What fraction of the frame height to move downward from the frame center.
// Note that setting this greater than 0.5 will mean moving past the bottom of
// the frame.
static const double kMoveFraction = 1.0 / 3.0;
namespace {
// DownloadStartAnimation creates an animation (which begins running
// immediately) that animates an image downward from the center of the frame
// provided on the constructor, while simultaneously fading it out. To use,
// simply call "new DownloadStartAnimation"; the class cleans itself up when it
// finishes animating.
class DownloadStartedAnimationWin : public LinearAnimation,
public NotificationObserver,
public views::ImageView {
public:
explicit DownloadStartedAnimationWin(TabContents* tab_contents);
private:
// Move the animation to wherever it should currently be.
void Reposition();
// Shut down the animation cleanly.
void Close();
// Animation
virtual void AnimateToState(double state);
// NotificationObserver
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
// We use a HWND for the popup so that it may float above any HWNDs in our UI.
views::WidgetWin* popup_;
// The content area holding us.
TabContents* tab_contents_;
// The content area at the start of the animation. We store this so that the
// download shelf's resizing of the content area doesn't cause the animation
// to move around. This means that once started, the animation won't move
// with the parent window, but it's so fast that this shouldn't cause too
// much heartbreak.
gfx::Rect tab_contents_bounds_;
// A scoped container for notification registries.
NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationWin);
};
DownloadStartedAnimationWin::DownloadStartedAnimationWin(
TabContents* tab_contents)
: LinearAnimation(kMoveTimeMs, kFrameRateHz, NULL),
popup_(NULL),
tab_contents_(tab_contents) {
static SkBitmap* kDownloadImage = NULL;
if (!kDownloadImage) {
kDownloadImage = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_DOWNLOAD_ANIMATION_BEGIN);
}
// If we're too small to show the download image, then don't bother -
// the shelf will be enough.
tab_contents_->GetContainerBounds(&tab_contents_bounds_);
if (tab_contents_bounds_.height() < kDownloadImage->height())
return;
registrar_.Add(
this,
NotificationType::TAB_CONTENTS_HIDDEN,
Source<TabContents>(tab_contents_));
registrar_.Add(
this,
NotificationType::TAB_CONTENTS_DESTROYED,
Source<TabContents>(tab_contents_));
SetImage(kDownloadImage);
gfx::Rect rc(0, 0, 0, 0);
popup_ = new views::WidgetWin;
popup_->set_window_style(WS_POPUP);
popup_->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW |
WS_EX_TRANSPARENT);
popup_->SetOpacity(0x00);
popup_->Init(tab_contents_->GetNativeView(), rc);
popup_->SetContentsView(this);
Reposition();
popup_->Show();
Start();
}
void DownloadStartedAnimationWin::Reposition() {
if (!tab_contents_)
return;
// Align the image with the bottom left of the web contents (so that it
// points to the newly created download).
gfx::Size size = GetPreferredSize();
int x = base::i18n::IsRTL() ?
tab_contents_bounds_.right() - size.width() : tab_contents_bounds_.x();
popup_->MoveWindow(
x,
static_cast<int>(tab_contents_bounds_.bottom() -
size.height() - size.height() * (1 - GetCurrentValue())),
size.width(),
size.height());
}
void DownloadStartedAnimationWin::Close() {
if (!tab_contents_)
return;
registrar_.Remove(
this,
NotificationType::TAB_CONTENTS_HIDDEN,
Source<TabContents>(tab_contents_));
registrar_.Remove(
this,
NotificationType::TAB_CONTENTS_DESTROYED,
Source<TabContents>(tab_contents_));
tab_contents_ = NULL;
popup_->Close();
}
void DownloadStartedAnimationWin::AnimateToState(double state) {
if (state >= 1.0) {
Close();
} else {
Reposition();
// Start at zero, peak halfway and end at zero.
double opacity = std::min(1.0 - pow(GetCurrentValue() - 0.5, 2) * 4.0,
static_cast<double>(1.0));
popup_->SetOpacity(
static_cast<SkColor>(opacity * 255.0));
SchedulePaint(); // Reposition() calls MoveWindow() which never picks up
// alpha changes, so we need to force a paint.
}
}
void DownloadStartedAnimationWin::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
Close();
}
} // namespace
// static
void DownloadStartedAnimation::Show(TabContents* tab_contents) {
// The animation will delete itself when it's finished or when the tab
// contents is hidden or destroyed.
new DownloadStartedAnimationWin(tab_contents);
}
|