summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-05 04:52:11 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-05 04:52:11 +0000
commit220705c2b06962462e471b28ad85c76c0f9c3080 (patch)
treecfc44266116bbf2acc3a4fae32625c4481c8243e /app
parent1b8d02f181d089ee670f2ba72089c3722f679d5f (diff)
downloadchromium_src-220705c2b06962462e471b28ad85c76c0f9c3080.zip
chromium_src-220705c2b06962462e471b28ad85c76c0f9c3080.tar.gz
chromium_src-220705c2b06962462e471b28ad85c76c0f9c3080.tar.bz2
Move *Animation to app/
http://crbug.com/11387 Review URL: http://codereview.chromium.org/109001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15275 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'app')
-rw-r--r--app/animation.cc124
-rw-r--r--app/animation.h122
-rw-r--r--app/animation_unittest.cc102
-rw-r--r--app/app.vcproj24
-rw-r--r--app/slide_animation.cc125
-rw-r--r--app/slide_animation.h102
-rw-r--r--app/throb_animation.cc68
-rw-r--r--app/throb_animation.h59
8 files changed, 726 insertions, 0 deletions
diff --git a/app/animation.cc b/app/animation.cc
new file mode 100644
index 0000000..6a4e7b7
--- /dev/null
+++ b/app/animation.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2006-2008 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 "app/animation.h"
+
+#include "base/message_loop.h"
+
+using base::TimeDelta;
+
+Animation::Animation(int frame_rate,
+ AnimationDelegate* delegate)
+ : animating_(false),
+ frame_rate_(frame_rate),
+ timer_interval_(CalculateInterval(frame_rate)),
+ duration_(0),
+ iteration_count_(0),
+ current_iteration_(0),
+ state_(0.0),
+ delegate_(delegate) {
+}
+
+Animation::Animation(int duration,
+ int frame_rate,
+ AnimationDelegate* delegate)
+ : animating_(false),
+ frame_rate_(frame_rate),
+ timer_interval_(CalculateInterval(frame_rate)),
+ duration_(0),
+ iteration_count_(0),
+ current_iteration_(0),
+ state_(0.0),
+ delegate_(delegate) {
+
+ SetDuration(duration);
+}
+
+Animation::~Animation() {
+}
+
+void Animation::Reset() {
+ current_iteration_ = 0;
+}
+
+double Animation::GetCurrentValue() const {
+ // Default is linear relationship, subclass to adapt.
+ return state_;
+}
+
+void Animation::Start() {
+ if (!animating_) {
+ timer_.Start(TimeDelta::FromMilliseconds(timer_interval_), this,
+ &Animation::Run);
+
+ animating_ = true;
+ if (delegate_)
+ delegate_->AnimationStarted(this);
+ }
+}
+
+void Animation::Stop() {
+ if (animating_) {
+ timer_.Stop();
+
+ animating_ = false;
+ if (delegate_) {
+ if (state_ >= 1.0)
+ delegate_->AnimationEnded(this);
+ else
+ delegate_->AnimationCanceled(this);
+ }
+ }
+}
+
+void Animation::End() {
+ if (animating_) {
+ timer_.Stop();
+
+ animating_ = false;
+ AnimateToState(1.0);
+ if (delegate_)
+ delegate_->AnimationEnded(this);
+ }
+}
+
+bool Animation::IsAnimating() {
+ return animating_;
+}
+
+void Animation::SetDuration(int duration) {
+ duration_ = duration;
+ if (duration_ < timer_interval_)
+ duration_ = timer_interval_;
+ iteration_count_ = duration_ / timer_interval_;
+
+ // Changing the number of iterations forces us to reset the
+ // animation to the first iteration.
+ current_iteration_ = 0;
+}
+
+void Animation::Step() {
+ state_ = static_cast<double>(++current_iteration_) / iteration_count_;
+
+ if (state_ >= 1.0)
+ state_ = 1.0;
+
+ AnimateToState(state_);
+ if (delegate_)
+ delegate_->AnimationProgressed(this);
+
+ if (state_ == 1.0)
+ Stop();
+}
+
+void Animation::Run() {
+ Step();
+}
+
+int Animation::CalculateInterval(int frame_rate) {
+ int timer_interval = 1000 / frame_rate;
+ if (timer_interval < 10)
+ timer_interval = 10;
+ return timer_interval;
+}
diff --git a/app/animation.h b/app/animation.h
new file mode 100644
index 0000000..58a2c67
--- /dev/null
+++ b/app/animation.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2006-2008 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.
+// Inspired by NSAnimation
+
+#ifndef APP_ANIMATION_H_
+#define APP_ANIMATION_H_
+
+#include "base/timer.h"
+
+class Animation;
+
+// AnimationDelegate
+//
+// Implement this interface when you want to receive notifications about the
+// state of an animation.
+//
+class AnimationDelegate {
+ public:
+ // Called when an animation has started.
+ virtual void AnimationStarted(const Animation* animation) {
+ }
+
+ // Called when an animation has completed.
+ virtual void AnimationEnded(const Animation* animation) {
+ }
+
+ // Called when an animation has progressed.
+ virtual void AnimationProgressed(const Animation* animation) {
+ }
+
+ // Called when an animation has been canceled.
+ virtual void AnimationCanceled(const Animation* animation) {
+ }
+};
+
+// Animation
+//
+// This class provides a basic implementation of an object that uses a timer
+// to increment its state over the specified time and frame-rate. To
+// actually do something useful with this you need to subclass it and override
+// AnimateToState and optionally GetCurrentValue to update your state.
+//
+// The Animation notifies a delegate when events of interest occur.
+//
+// The practice is to instantiate a subclass and call Init and any other
+// initialization specific to the subclass, and then call |Start|. The
+// animation uses the current thread's message loop.
+//
+class Animation {
+ public:
+ // Initializes everything except the duration.
+ //
+ // Caller must make sure to call SetDuration() if they use this
+ // constructor; it is preferable to use the full one, but sometimes
+ // duration can change between calls to Start() and we need to
+ // expose this interface.
+ Animation(int frame_rate, AnimationDelegate* delegate);
+
+ // Initializes all fields.
+ Animation(int duration, int frame_rate, AnimationDelegate* delegate);
+ virtual ~Animation();
+
+ // Reset state so that the animation can be started again.
+ virtual void Reset();
+
+ // Called when the animation progresses. Subclasses override this to
+ // efficiently update their state.
+ virtual void AnimateToState(double state) = 0;
+
+ // Gets the value for the current state, according to the animation
+ // curve in use. This class provides only for a linear relationship,
+ // however subclasses can override this to provide others.
+ virtual double GetCurrentValue() const;
+
+ // Start the animation.
+ void Start();
+
+ // Stop the animation.
+ void Stop();
+
+ // Skip to the end of the current animation.
+ void End();
+
+ // Return whether this animation is animating.
+ bool IsAnimating();
+
+ // Changes the length of the animation. This resets the current
+ // state of the animation to the beginning.
+ void SetDuration(int duration);
+
+ protected:
+ // Overriddable, called by Run.
+ virtual void Step();
+
+ // Calculates the timer interval from the constructor list.
+ int CalculateInterval(int frame_rate);
+
+ // Whether or not we are currently animating.
+ bool animating_;
+
+ int frame_rate_;
+ int timer_interval_;
+ int duration_;
+
+ // For determining state.
+ int iteration_count_;
+ int current_iteration_;
+ double state_;
+
+ AnimationDelegate* delegate_;
+
+ base::RepeatingTimer<Animation> timer_;
+
+ private:
+ // Called when the animation's timer expires, calls Step.
+ void Run();
+
+ DISALLOW_COPY_AND_ASSIGN(Animation);
+};
+
+#endif // APP_ANIMATION_H_
diff --git a/app/animation_unittest.cc b/app/animation_unittest.cc
new file mode 100644
index 0000000..a7450e3
--- /dev/null
+++ b/app/animation_unittest.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2006-2008 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 "app/animation.h"
+#include "base/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace std;
+
+class AnimationTest: public testing::Test {
+ private:
+ MessageLoopForUI message_loop_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// RunAnimation
+
+class RunAnimation : public Animation {
+ public:
+ RunAnimation(int frame_rate, AnimationDelegate* delegate)
+ : Animation(frame_rate, delegate) {
+ }
+
+ virtual void AnimateToState(double state) {
+ EXPECT_LE(0.0, state);
+ EXPECT_GE(1.0, state);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// CancelAnimation
+
+class CancelAnimation : public Animation {
+ public:
+ CancelAnimation(int duration, int frame_rate, AnimationDelegate* delegate)
+ : Animation(duration, frame_rate, delegate) {
+ }
+
+ virtual void AnimateToState(double state) {
+ if (state >= 0.5)
+ Stop();
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// LinearCase
+
+class TestAnimationDelegate : public AnimationDelegate {
+ public:
+ TestAnimationDelegate() :
+ canceled_(false),
+ finished_(false) {
+ }
+
+ virtual void AnimationStarted(const Animation* animation) {
+ }
+
+ virtual void AnimationEnded(const Animation* animation) {
+ finished_ = true;
+ MessageLoop::current()->Quit();
+ }
+
+ virtual void AnimationCanceled(const Animation* animation) {
+ finished_ = true;
+ canceled_ = true;
+ MessageLoop::current()->Quit();
+ }
+
+ bool finished() {
+ return finished_;
+ }
+
+ bool canceled() {
+ return canceled_;
+ }
+
+ private:
+ bool canceled_;
+ bool finished_;
+};
+
+TEST_F(AnimationTest, RunCase) {
+ TestAnimationDelegate ad;
+ RunAnimation a1(150, &ad);
+ a1.SetDuration(2000);
+ a1.Start();
+ MessageLoop::current()->Run();
+
+ EXPECT_TRUE(ad.finished());
+ EXPECT_FALSE(ad.canceled());
+}
+
+TEST_F(AnimationTest, CancelCase) {
+ TestAnimationDelegate ad;
+ CancelAnimation a2(2000, 150, &ad);
+ a2.Start();
+ MessageLoop::current()->Run();
+
+ EXPECT_TRUE(ad.finished());
+ EXPECT_TRUE(ad.canceled());
+}
diff --git a/app/app.vcproj b/app/app.vcproj
index 22c1e1f..02d76cd 100644
--- a/app/app.vcproj
+++ b/app/app.vcproj
@@ -122,6 +122,14 @@
</References>
<Files>
<File
+ RelativePath=".\animation.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\animation.h"
+ >
+ </File>
+ <File
RelativePath=".\resource_bundle.cc"
>
</File>
@@ -133,6 +141,22 @@
RelativePath=".\resource_bundle_win.cc"
>
</File>
+ <File
+ RelativePath=".\slide_animation.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\slide_animation.h"
+ >
+ </File>
+ <File
+ RelativePath=".\throb_animation.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\throb_animation.h"
+ >
+ </File>
</Files>
<Globals>
</Globals>
diff --git a/app/slide_animation.cc b/app/slide_animation.cc
new file mode 100644
index 0000000..ca468d2
--- /dev/null
+++ b/app/slide_animation.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2006-2008 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 "app/slide_animation.h"
+
+#include <math.h>
+
+// How many frames per second to target.
+static const int kDefaultFramerateHz = 50;
+
+// How long animations should take by default.
+static const int kDefaultDurationMs = 120;
+
+SlideAnimation::SlideAnimation(AnimationDelegate* target)
+ : Animation(kDefaultFramerateHz, target),
+ target_(target),
+ tween_type_(EASE_OUT),
+ showing_(false),
+ value_start_(0),
+ value_end_(0),
+ value_current_(0),
+ slide_duration_(kDefaultDurationMs) {
+}
+
+SlideAnimation::~SlideAnimation() {
+}
+
+void SlideAnimation::Reset() {
+ Reset(0);
+}
+
+void SlideAnimation::Reset(double value) {
+ Stop();
+ showing_ = static_cast<bool>(value == 1);
+ value_current_ = value;
+}
+
+void SlideAnimation::Show() {
+ // If we're already showing (or fully shown), we have nothing to do.
+ if (showing_)
+ return;
+
+ showing_ = true;
+ value_start_ = value_current_;
+ value_end_ = 1.0;
+
+ // Make sure we actually have something to do.
+ if (slide_duration_ == 0) {
+ AnimateToState(1.0); // Skip to the end of the animation.
+ return;
+ } else if (value_current_ == value_end_) {
+ return;
+ }
+
+ // This will also reset the currently-occuring animation.
+ SetDuration(static_cast<int>(slide_duration_ * (1 - value_current_)));
+ Start();
+}
+
+void SlideAnimation::Hide() {
+ // If we're already hiding (or hidden), we have nothing to do.
+ if (!showing_)
+ return;
+
+ showing_ = false;
+ value_start_ = value_current_;
+ value_end_ = 0.0;
+
+ // Make sure we actually have something to do.
+ if (slide_duration_ == 0) {
+ AnimateToState(0.0); // Skip to the end of the animation.
+ return;
+ } else if (value_current_ == value_end_) {
+ return;
+ }
+
+ // This will also reset the currently-occuring animation.
+ SetDuration(static_cast<int>(slide_duration_ * value_current_));
+ Start();
+}
+
+void SlideAnimation::AnimateToState(double state) {
+ if (state > 1.0)
+ state = 1.0;
+
+ // Make our animation ease-out.
+ switch (tween_type_) {
+ case EASE_IN:
+ state = pow(state, 2);
+ break;
+ case EASE_IN_OUT:
+ if (state < 0.5)
+ state = pow(state * 2, 2) / 2.0;
+ else
+ state = 1.0 - (pow((state - 1.0) * 2, 2) / 2.0);
+ break;
+ case FAST_IN_OUT:
+ state = (pow(state - 0.5, 3) + 0.125) / 0.25;
+ break;
+ case NONE:
+ // state remains linear.
+ break;
+ case EASE_OUT_SNAP:
+ state = 0.95 * (1.0 - pow(1.0 - state, 2));
+ break;
+ case EASE_OUT:
+ default:
+ state = 1.0 - pow(1.0 - state, 2);
+ break;
+ }
+
+ value_current_ = value_start_ + (value_end_ - value_start_) * state;
+
+ // Implement snapping.
+ if (tween_type_ == EASE_OUT_SNAP && fabs(value_current_ - value_end_) <= 0.06)
+ value_current_ = value_end_;
+
+ // Correct for any overshoot (while state may be capped at 1.0, let's not
+ // take any rounding error chances.
+ if ((value_end_ >= value_start_ && value_current_ > value_end_) ||
+ (value_end_ < value_start_ && value_current_ < value_end_)) {
+ value_current_ = value_end_;
+ }
+}
diff --git a/app/slide_animation.h b/app/slide_animation.h
new file mode 100644
index 0000000..4bbcd2e
--- /dev/null
+++ b/app/slide_animation.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2006-2008 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.
+
+#ifndef APP_SLIDE_ANIMATION_H_
+#define APP_SLIDE_ANIMATION_H_
+
+#include "app/animation.h"
+
+// Slide Animation
+//
+// Used for reversible animations and as a general helper class. Typical usage:
+//
+// #include "app/slide_animation.h"
+//
+// class MyClass : public AnimationDelegate {
+// public:
+// MyClass() {
+// animation_.reset(new SlideAnimation(this));
+// animation_->SetSlideDuration(500);
+// }
+// void OnMouseOver() {
+// animation_->Show();
+// }
+// void OnMouseOut() {
+// animation_->Hide();
+// }
+// void AnimationProgressed(const Animation* animation) {
+// if (animation == animation_.get()) {
+// Layout();
+// SchedulePaint();
+// } else if (animation == other_animation_.get()) {
+// ...
+// }
+// }
+// void Layout() {
+// if (animation_->IsAnimating()) {
+// hover_image_.SetOpacity(animation_->GetCurrentValue());
+// }
+// }
+// private:
+// scoped_ptr<SlideAnimation> animation_;
+// }
+class SlideAnimation : public Animation {
+ public:
+ explicit SlideAnimation(AnimationDelegate* target);
+ virtual ~SlideAnimation();
+
+ enum TweenType {
+ NONE, // Default linear.
+ EASE_OUT, // Fast in, slow out.
+ EASE_IN, // Slow in, fast out.
+ EASE_IN_OUT, // Slow in and out, fast in the middle.
+ FAST_IN_OUT, // Fast in and out, slow in the middle.
+ EASE_OUT_SNAP, // Fast in, slow out, snap to final value.
+ };
+
+ // Set the animation back to the 0 state.
+ virtual void Reset();
+ virtual void Reset(double value);
+
+ // Begin a showing animation or reverse a hiding animation in progress.
+ virtual void Show();
+
+ // Begin a hiding animation or reverse a showing animation in progress.
+ virtual void Hide();
+
+ // Sets the time a slide will take. Note that this isn't actually
+ // the amount of time an animation will take as the current value of
+ // the slide is considered.
+ virtual void SetSlideDuration(int duration) { slide_duration_ = duration; }
+ int GetSlideDuration() const { return slide_duration_; }
+ void SetTweenType(TweenType tween_type) { tween_type_ = tween_type; }
+
+ double GetCurrentValue() const { return value_current_; }
+ bool IsShowing() const { return showing_; }
+
+ private:
+ // Overridden from Animation.
+ void AnimateToState(double state);
+
+ AnimationDelegate* target_;
+
+ TweenType tween_type_;
+
+ // Used to determine which way the animation is going.
+ bool showing_;
+
+ // Animation values. These are a layer on top of Animation::state_ to
+ // provide the reversability.
+ double value_start_;
+ double value_end_;
+ double value_current_;
+
+ // How long a hover in/out animation will last for. This defaults to
+ // kHoverFadeDurationMS, but can be overridden with SetDuration.
+ int slide_duration_;
+
+ DISALLOW_COPY_AND_ASSIGN(SlideAnimation);
+};
+
+#endif // APP_SLIDE_ANIMATION_H_
diff --git a/app/throb_animation.cc b/app/throb_animation.cc
new file mode 100644
index 0000000..28b5763
--- /dev/null
+++ b/app/throb_animation.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2006-2008 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 "app/throb_animation.h"
+
+static const int kDefaultThrobDurationMS = 400;
+
+ThrobAnimation::ThrobAnimation(AnimationDelegate* target)
+ : SlideAnimation(target),
+ slide_duration_(GetSlideDuration()),
+ throb_duration_(kDefaultThrobDurationMS),
+ cycles_remaining_(0),
+ throbbing_(false) {
+}
+
+void ThrobAnimation::StartThrobbing(int cycles_til_stop) {
+ cycles_remaining_ = cycles_til_stop;
+ throbbing_ = true;
+ SlideAnimation::SetSlideDuration(throb_duration_);
+ if (IsAnimating())
+ return; // We're already running, we'll cycle when current loop finishes.
+
+ if (IsShowing())
+ SlideAnimation::Hide();
+ else
+ SlideAnimation::Show();
+ cycles_remaining_ = cycles_til_stop;
+}
+
+void ThrobAnimation::Reset() {
+ ResetForSlide();
+ SlideAnimation::Reset();
+}
+
+void ThrobAnimation::Show() {
+ ResetForSlide();
+ SlideAnimation::Show();
+}
+
+void ThrobAnimation::Hide() {
+ ResetForSlide();
+ SlideAnimation::Hide();
+}
+
+void ThrobAnimation::Step() {
+ Animation::Step();
+ if (!IsAnimating() && throbbing_) {
+ // Were throbbing a finished a cycle. Start the next cycle unless we're at
+ // the end of the cycles, in which case we stop.
+ cycles_remaining_--;
+ if (IsShowing()) {
+ // We want to stop hidden, hence this doesn't check cycles_remaining_.
+ SlideAnimation::Hide();
+ } else if (cycles_remaining_ > 0) {
+ SlideAnimation::Show();
+ } else {
+ // We're done throbbing.
+ throbbing_ = false;
+ }
+ }
+}
+
+void ThrobAnimation::ResetForSlide() {
+ SlideAnimation::SetSlideDuration(slide_duration_);
+ cycles_remaining_ = 0;
+ throbbing_ = false;
+}
diff --git a/app/throb_animation.h b/app/throb_animation.h
new file mode 100644
index 0000000..637e8e0
--- /dev/null
+++ b/app/throb_animation.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2006-2008 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.
+
+#ifndef APP_THROB_ANIMATION_H_
+#define APP_THROB_ANIMATION_H_
+
+#include "app/slide_animation.h"
+
+// A subclass of SlideAnimation that can continually slide. All of the Animation
+// methods behave like that of SlideAnimation: transition to the next state.
+// The StartThrobbing method causes the ThrobAnimation to cycle between hidden
+// and shown for a set number of cycles.
+//
+// A ThrobAnimation has two durations: the duration used when behavior like
+// a SlideAnimation, and the duration used when throbbing.
+class ThrobAnimation : public SlideAnimation {
+ public:
+ explicit ThrobAnimation(AnimationDelegate* target);
+ virtual ~ThrobAnimation() {}
+
+ // Starts throbbing. cycles_til_stop gives the number of cycles to do before
+ // stopping.
+ void StartThrobbing(int cycles_til_stop);
+
+ // Sets the duration of the slide animation when throbbing.
+ void SetThrobDuration(int duration) { throb_duration_ = duration; }
+
+ // Overridden to reset to the slide duration.
+ virtual void Reset();
+ virtual void Show();
+ virtual void Hide();
+
+ // Overriden to continually throb (assuming we're throbbing).
+ virtual void Step();
+
+ // Overridden to maintain the slide duration.
+ virtual void SetSlideDuration(int duration) { slide_duration_ = duration; }
+
+ private:
+ // Resets state such that we behave like SlideAnimation.
+ void ResetForSlide();
+
+ // Duration of the slide animation.
+ int slide_duration_;
+
+ // Duration of the slide animation when throbbing.
+ int throb_duration_;
+
+ // If throbbing, this is the number of cycles left.
+ int cycles_remaining_;
+
+ // Are we throbbing?
+ bool throbbing_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrobAnimation);
+};
+
+#endif // APP_THROB_ANIMATION_H_