| // 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 |