// 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 #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(delta_x * cv); int frame_y = start_bounds_.y() + static_cast(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(delta_width * cv); int frame_height = start_bounds_.height() + static_cast(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