blob: 177b0e150e9c50eaf91d7ef51d6022e72ecf41b6 [file] [log] [blame]
// Copyright (c) 2009 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 "views/animator.h"
#include <algorithm>
#include "app/slide_animation.h"
#include "views/view.h"
namespace views {
////////////////////////////////////////////////////////////////////////////////
// Animator, public:
Animator::Animator(View* host)
: host_(host),
delegate_(NULL),
direction_(ANIMATE_NONE) {
InitAnimation();
}
Animator::Animator(View* host, AnimatorDelegate* delegate)
: host_(host),
animation_(NULL),
delegate_(delegate),
direction_(ANIMATE_NONE) {
InitAnimation();
}
Animator::~Animator() {
// Explicitly NULL the delegate so we don't call back through to the delegate
// when the animation is stopped. The Animator is designed to be owned by a
// View and at this point the View is dust.
delegate_ = NULL;
animation_->Stop();
}
bool Animator::IsAnimating() const {
return animation_->IsAnimating();
}
void Animator::AnimateToBounds(const gfx::Rect& bounds, int direction) {
direction_ = direction;
start_bounds_ = host_->bounds();
target_bounds_ = bounds;
// Stop any running animation before we have a chance to return.
animation_->Stop();
if (bounds == host_->bounds())
return;
if (direction_ == ANIMATE_NONE) {
host_->SetBounds(bounds);
return;
}
if (direction_ & ANIMATE_X) {
if (direction_ & ANIMATE_CLAMP)
start_bounds_.set_x(GetClampedX());
} else {
start_bounds_.set_x(target_bounds_.x());
}
if (direction_ & ANIMATE_Y) {
if (direction_ & ANIMATE_CLAMP)
start_bounds_.set_y(GetClampedY());
} else {
start_bounds_.set_y(target_bounds_.y());
}
if (!(direction_ & ANIMATE_WIDTH))
start_bounds_.set_width(target_bounds_.width());
if (!(direction_ & ANIMATE_HEIGHT))
start_bounds_.set_height(target_bounds_.height());
// Make sure the host view has the start bounds to avoid a flicker.
host_->SetBounds(start_bounds_);
// Start the animation from the beginning.
animation_->Reset(0.0);
animation_->Show();
}
void Animator::AnimateToBounds(int x, int y, int width, int height,
int direction) {
AnimateToBounds(gfx::Rect(x, y, std::max(0, width), std::max(0, height)),
direction);
}
////////////////////////////////////////////////////////////////////////////////
// Animator, AnimationDelegate:
void Animator::AnimationEnded(const Animation* animation) {
// |delegate_| could be NULL if we're called back from the destructor.
if (delegate_)
delegate_->AnimationCompletedForHost(host_);
}
void Animator::AnimationProgressed(const Animation* animation) {
int delta_x = target_bounds_.x() - start_bounds_.x();
int delta_y = target_bounds_.y() - start_bounds_.y();
int delta_width = target_bounds_.width() - start_bounds_.width();
int delta_height = target_bounds_.height() - start_bounds_.height();
// The current frame's position and size is the animation's progress percent
// multiplied by the delta between the start and target position/size...
double cv = animation_->GetCurrentValue();
int frame_x = start_bounds_.x() + static_cast<int>(delta_x * cv);
int frame_y = start_bounds_.y() + static_cast<int>(delta_y * cv);
// ... except for clamped positions, which remain clamped at the right/bottom
// edge of the previous view in the layout flow.
if (direction_ & ANIMATE_CLAMP && direction_ & ANIMATE_X)
frame_x = GetClampedX();
if (direction_ & ANIMATE_CLAMP && direction_ & ANIMATE_Y)
frame_y = GetClampedY();
int frame_width = start_bounds_.width() + static_cast<int>(delta_width * cv);
int frame_height =
start_bounds_.height() + static_cast<int>(delta_height * cv);
host_->SetBounds(frame_x, frame_y, frame_width, frame_height);
host_->GetParent()->SchedulePaint();
}
void Animator::AnimationCanceled(const Animation* animation) {
AnimationEnded(animation);
}
////////////////////////////////////////////////////////////////////////////////
// Animator, private:
void Animator::InitAnimation() {
animation_.reset(new SlideAnimation(this));
animation_->SetSlideDuration(150);
animation_->SetTweenType(SlideAnimation::EASE_OUT);
}
int Animator::GetClampedX() const {
if (delegate_ && direction_ & ANIMATE_CLAMP && direction_ & ANIMATE_X) {
View* previous_view = delegate_->GetClampedView(host_);
if (previous_view)
return previous_view->bounds().right();
}
return host_->x();
}
int Animator::GetClampedY() const {
if (delegate_ && direction_ & ANIMATE_CLAMP && direction_ & ANIMATE_Y) {
View* previous_view = delegate_->GetClampedView(host_);
if (previous_view)
return previous_view->bounds().bottom();
}
return host_->y();
}
} // namespace views