Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(385)

Side by Side Diff: views/animation/bounds_animator.cc

Issue 1575011: Adds AnimationContainer, which can be used to group a set of (Closed)
Patch Set: Incorporated review feedback Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "views/animation/bounds_animator.h" 5 #include "views/animation/bounds_animator.h"
6 6
7 #include "app/slide_animation.h" 7 #include "app/slide_animation.h"
8 #include "base/compiler_specific.h" 8 #include "base/scoped_ptr.h"
9 #include "views/view.h" 9 #include "views/view.h"
10 10
11 // Duration in milliseconds for animations.
12 static const int kAnimationDuration = 200;
13
11 namespace views { 14 namespace views {
12 15
13 BoundsAnimator::BoundsAnimator() 16 BoundsAnimator::BoundsAnimator(View* parent)
14 : ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new SlideAnimation(this))), 17 : parent_(parent),
15 is_slide_(true) { 18 observer_(NULL),
19 container_(new AnimationContainer()) {
20 container_->set_observer(this);
16 } 21 }
17 22
18 BoundsAnimator::~BoundsAnimator() { 23 BoundsAnimator::~BoundsAnimator() {
19 data_.clear(); 24 // Reset the delegate so that we don't attempt to notify our observer from
20 animation_->set_delegate(NULL); 25 // the destructor.
21 animation_.reset(); 26 container_->set_observer(NULL);
27
28 // Delete all the animations, but don't remove any child views. We assume the
29 // view owns us and is going to be deleted anyway.
30 for (ViewToDataMap::iterator i = data_.begin(); i != data_.end(); ++i)
31 delete i->second.animation;
22 } 32 }
23 33
24 void BoundsAnimator::AnimateViewTo(View* view, 34 void BoundsAnimator::AnimateViewTo(View* view,
25 const gfx::Rect& target, 35 const gfx::Rect& target,
26 bool delete_when_done) { 36 bool delete_when_done) {
37 DCHECK_EQ(view->GetParent(), parent_);
38
39 scoped_ptr<Animation> current_animation;
40
41 if (data_.find(view) != data_.end()) {
42 // Currently animating this view, blow away the current animation and
43 // we'll create another animation below.
44 // We delay deleting the view until the end so that we don't prematurely
45 // send out notification that we're done.
46 current_animation.reset(ResetAnimationForView(view));
47 } else if (target == view->bounds()) {
48 // View is already at the target location, delete it if necessary.
49 if (delete_when_done)
50 delete view;
51 return;
52 }
53
27 Data& data = data_[view]; 54 Data& data = data_[view];
28 data.start_bounds = view->bounds(); 55 data.start_bounds = view->bounds();
29 data.target_bounds = target; 56 data.target_bounds = target;
57 data.animation = CreateAnimation();
30 data.delete_when_done = delete_when_done; 58 data.delete_when_done = delete_when_done;
59
60 animation_to_view_[data.animation] = view;
61
62 data.animation->Show();
63 }
64
65 void BoundsAnimator::SetAnimationForView(View* view,
66 SlideAnimation* animation) {
67 scoped_ptr<SlideAnimation> animation_wrapper(animation);
68 if (data_.find(view) == data_.end())
69 return;
70
71 // We delay deleting the animation until the end so that we don't prematurely
72 // send out notification that we're done.
73 scoped_ptr<Animation> old_animation(ResetAnimationForView(view));
74
75 data_[view].animation = animation_wrapper.release();
76 animation_to_view_[animation] = view;
77
78 animation->set_delegate(this);
79 animation->SetContainer(container_.get());
80 animation->Show();
81 }
82
83 const SlideAnimation* BoundsAnimator::GetAnimationForView(View* view) {
84 return data_.find(view) == data_.end() ? NULL : data_[view].animation;
85 }
86
87 void BoundsAnimator::SetAnimationDelegate(View* view,
88 AnimationDelegate* delegate,
89 bool delete_when_done) {
90 DCHECK(IsAnimating(view));
91 data_[view].delegate = delegate;
92 data_[view].delete_delegate_when_done = delete_when_done;
93 }
94
95 void BoundsAnimator::StopAnimatingView(View* view) {
96 if (data_.find(view) == data_.end())
97 return;
98
99 data_[view].animation->Stop();
31 } 100 }
32 101
33 bool BoundsAnimator::IsAnimating(View* view) const { 102 bool BoundsAnimator::IsAnimating(View* view) const {
34 return data_.find(view) != data_.end(); 103 return data_.find(view) != data_.end();
35 } 104 }
36 105
37 void BoundsAnimator::Start() { 106 bool BoundsAnimator::IsAnimating() const {
38 // Unset the delegate so that we don't attempt to cleanup if the animation is 107 return !data_.empty();
39 // running and we cancel it. 108 }
40 animation_->set_delegate(NULL); 109
41 110 void BoundsAnimator::Cancel() {
42 animation_->Stop(); 111 if (data_.empty())
43 112 return;
44 if (is_slide_) { 113
45 // TODO(sky): this is yucky, need a better way to express this. 114 while (!data_.empty())
46 static_cast<SlideAnimation*>(animation_.get())->Hide(); 115 data_.begin()->second.animation->Stop();
47 static_cast<SlideAnimation*>(animation_.get())->Reset(); 116
48 static_cast<SlideAnimation*>(animation_.get())->Show(); 117 // Invoke AnimationContainerProgressed to force a repaint and notify delegate.
49 } else { 118 AnimationContainerProgressed(container_.get());
50 animation_->Start(); 119 }
51 } 120
52 121 SlideAnimation* BoundsAnimator::CreateAnimation() {
53 animation_->set_delegate(this); 122 SlideAnimation* animation = new SlideAnimation(this);
54 } 123 animation->SetContainer(container_.get());
55 124 animation->SetSlideDuration(kAnimationDuration);
56 void BoundsAnimator::Stop() { 125 animation->SetTweenType(SlideAnimation::EASE_OUT);
57 animation_->set_delegate(NULL); 126 return animation;
58 animation_->Stop(); 127 }
59 animation_->set_delegate(this); 128
60 129 void BoundsAnimator::RemoveFromMapsAndDelete(View* view) {
61 DeleteViews(); 130 DCHECK(data_.count(view) > 0);
62 data_.clear(); 131
63 } 132 Data& data = data_[view];
64 133 animation_to_view_.erase(data.animation);
65 void BoundsAnimator::SetAnimation(Animation* animation, bool is_slide) { 134 if (data.delete_when_done)
66 animation_.reset(animation); 135 delete view;
67 is_slide_ = is_slide; 136 data_.erase(view);
137 }
138
139 void BoundsAnimator::CleanupData(Data* data) {
140 if (data->delete_delegate_when_done) {
141 delete static_cast<OwnedAnimationDelegate*>(data->delegate);
142 data->delegate = NULL;
143 }
144
145 delete data->animation;
146 data->animation = NULL;
147 }
148
149 Animation* BoundsAnimator::ResetAnimationForView(View* view) {
150 if (data_.find(view) == data_.end())
151 return NULL;
152
153 Animation* old_animation = data_[view].animation;
154 animation_to_view_.erase(old_animation);
155 data_[view].animation = NULL;
156 // Reset the delegate so that we don't attempt any processing when the
157 // animation calls us back.
158 old_animation->set_delegate(NULL);
159 return old_animation;
68 } 160 }
69 161
70 void BoundsAnimator::AnimationProgressed(const Animation* animation) { 162 void BoundsAnimator::AnimationProgressed(const Animation* animation) {
71 gfx::Rect repaint_bounds; 163 DCHECK(animation_to_view_.find(animation) != animation_to_view_.end());
72 164
73 for (ViewToDataMap::const_iterator i = data_.begin(); i != data_.end(); ++i) { 165 View* view = animation_to_view_[animation];
74 View* view = i->first; 166 const Data& data = data_[view];
75 gfx::Rect new_bounds = 167 gfx::Rect new_bounds =
76 animation_->CurrentValueBetween(i->second.start_bounds, 168 animation->CurrentValueBetween(data.start_bounds, data.target_bounds);
77 i->second.target_bounds); 169 if (new_bounds != view->bounds()) {
78 if (new_bounds != view->bounds()) { 170 gfx::Rect total_bounds = new_bounds.Union(view->bounds());
79 gfx::Rect total_bounds = new_bounds.Union(view->bounds()); 171
80 if (repaint_bounds.IsEmpty()) 172 // Build up the region to repaint in repaint_bounds_. We'll do the repaint
81 repaint_bounds = total_bounds; 173 // when all animations complete (in AnimationContainerProgressed).
82 else 174 if (repaint_bounds_.IsEmpty())
83 repaint_bounds = repaint_bounds.Union(total_bounds); 175 repaint_bounds_ = total_bounds;
84 view->SetBounds(new_bounds); 176 else
85 } 177 repaint_bounds_ = repaint_bounds_.Union(total_bounds);
86 } 178
87 179 view->SetBounds(new_bounds);
88 if (!data_.empty() && !repaint_bounds.IsEmpty()) 180 }
89 data_.begin()->first->GetParent()->SchedulePaint(repaint_bounds, false); 181
182 if (data_[view].delegate)
183 data_[view].delegate->AnimationProgressed(animation);
90 } 184 }
91 185
92 void BoundsAnimator::AnimationEnded(const Animation* animation) { 186 void BoundsAnimator::AnimationEnded(const Animation* animation) {
93 DeleteViews(); 187 View* view = animation_to_view_[animation];
188 AnimationDelegate* delegate = data_[view].delegate;
189
190 // Make a copy of the data as Remove empties out the maps.
191 Data data = data_[view];
192
193 RemoveFromMapsAndDelete(view);
194
195 if (delegate)
196 delegate->AnimationEnded(animation);
197
198 CleanupData(&data);
94 } 199 }
95 200
96 void BoundsAnimator::AnimationCanceled(const Animation* animation) { 201 void BoundsAnimator::AnimationCanceled(const Animation* animation) {
97 } 202 View* view = animation_to_view_[animation];
98 203 AnimationDelegate* delegate = data_[view].delegate;
99 void BoundsAnimator::DeleteViews() { 204
100 for (ViewToDataMap::iterator i = data_.begin(); i != data_.end(); ++i) { 205 // Make a copy of the data as Remove empties out the maps.
101 if (i->second.delete_when_done) { 206 Data data = data_[view];
102 View* view = i->first; 207
103 view->GetParent()->RemoveChildView(view); 208 RemoveFromMapsAndDelete(view);
104 delete view; 209
105 } 210 if (delegate)
106 } 211 delegate->AnimationCanceled(animation);
107 data_.clear(); 212
213 CleanupData(&data);
214 }
215
216 void BoundsAnimator::AnimationContainerProgressed(
217 AnimationContainer* container) {
218 if (!repaint_bounds_.IsEmpty()) {
219 parent_->SchedulePaint(repaint_bounds_, false);
220 repaint_bounds_.SetRect(0, 0, 0, 0);
221 }
222
223 if (observer_ && !IsAnimating()) {
224 // Notify here rather than from AnimationXXX to avoid deleting the animation
225 // while the animaion is calling us.
226 observer_->OnBoundsAnimatorDone(this);
227 }
228 }
229
230 void BoundsAnimator::AnimationContainerEmpty(AnimationContainer* container) {
108 } 231 }
109 232
110 } // namespace views 233 } // namespace views
OLDNEW
« views/animation/bounds_animator.h ('K') | « views/animation/bounds_animator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698