| // Copyright (c) 2012 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 "chrome/browser/ui/gtk/slide_animator_gtk.h" |
| |
| #include "ui/base/gtk/gtk_expanded_container.h" |
| #include "ui/gfx/animation/animation.h" |
| #include "ui/gfx/animation/slide_animation.h" |
| |
| namespace { |
| |
| void OnChildSizeRequest(GtkWidget* expanded, |
| GtkWidget* child, |
| GtkRequisition* requisition, |
| gpointer control_child_size) { |
| // If |control_child_size| is true, then we want |child_| to match the width |
| // of the |widget_|, but the height of |child_| should not change. |
| if (!GPOINTER_TO_INT(control_child_size)) { |
| requisition->width = -1; |
| } |
| requisition->height = -1; |
| } |
| |
| } // namespace |
| |
| bool SlideAnimatorGtk::animations_enabled_ = true; |
| |
| SlideAnimatorGtk::SlideAnimatorGtk(GtkWidget* child, |
| Direction direction, |
| int duration, |
| bool linear, |
| bool control_child_size, |
| Delegate* delegate) |
| : child_(child), |
| direction_(direction), |
| delegate_(delegate) { |
| widget_.Own(gtk_expanded_container_new()); |
| gtk_container_add(GTK_CONTAINER(widget_.get()), child); |
| gtk_widget_set_size_request(widget_.get(), -1, 0); |
| |
| // If the child requests it, we will manually set the size request for |
| // |child_| every time the |widget_| changes sizes. This is mainly useful |
| // for bars, where we want the child to expand to fill all available space. |
| g_signal_connect(widget_.get(), "child-size-request", |
| G_CALLBACK(OnChildSizeRequest), |
| GINT_TO_POINTER(control_child_size)); |
| |
| // We connect to this signal to set an initial position for our child widget. |
| // The reason we connect to this signal rather than setting the initial |
| // position here is that the widget is currently unallocated and may not |
| // even have a size request. |
| g_signal_connect(child, "size-allocate", |
| G_CALLBACK(OnChildSizeAllocate), this); |
| |
| child_needs_move_ = (direction == DOWN); |
| |
| animation_.reset(new gfx::SlideAnimation(this)); |
| // Default tween type is EASE_OUT. |
| if (linear) |
| animation_->SetTweenType(gfx::Tween::LINEAR); |
| if (duration != 0) |
| animation_->SetSlideDuration(duration); |
| } |
| |
| SlideAnimatorGtk::~SlideAnimatorGtk() { |
| widget_.Destroy(); |
| } |
| |
| void SlideAnimatorGtk::Open() { |
| if (!animations_enabled_) |
| return OpenWithoutAnimation(); |
| |
| gtk_widget_show(widget_.get()); |
| animation_->Show(); |
| } |
| |
| void SlideAnimatorGtk::OpenWithoutAnimation() { |
| gtk_widget_show(widget_.get()); |
| animation_->Reset(1.0); |
| animation_->Show(); |
| AnimationProgressed(animation_.get()); |
| } |
| |
| void SlideAnimatorGtk::Close() { |
| if (!animations_enabled_) |
| return CloseWithoutAnimation(); |
| |
| animation_->Hide(); |
| } |
| |
| void SlideAnimatorGtk::End() { |
| animation_->End(); |
| } |
| |
| void SlideAnimatorGtk::CloseWithoutAnimation() { |
| animation_->Reset(0.0); |
| animation_->Hide(); |
| AnimationProgressed(animation_.get()); |
| gtk_widget_hide(widget_.get()); |
| } |
| |
| bool SlideAnimatorGtk::IsShowing() { |
| return animation_->IsShowing(); |
| } |
| |
| bool SlideAnimatorGtk::IsClosing() { |
| return animation_->IsClosing(); |
| } |
| |
| bool SlideAnimatorGtk::IsAnimating() { |
| return animation_->is_animating(); |
| } |
| |
| void SlideAnimatorGtk::AnimationProgressed(const gfx::Animation* animation) { |
| GtkRequisition req; |
| gtk_widget_size_request(child_, &req); |
| |
| int showing_height = static_cast<int>(req.height * |
| animation_->GetCurrentValue()); |
| if (direction_ == DOWN) { |
| if (gtk_widget_get_parent(widget_.get())) { |
| gtk_expanded_container_move(GTK_EXPANDED_CONTAINER(widget_.get()), |
| child_, 0, showing_height - req.height); |
| } |
| child_needs_move_ = false; |
| } |
| gtk_widget_set_size_request(widget_.get(), -1, showing_height); |
| } |
| |
| void SlideAnimatorGtk::AnimationEnded(const gfx::Animation* animation) { |
| if (!animation_->IsShowing()) { |
| gtk_widget_hide(widget_.get()); |
| if (delegate_) |
| delegate_->Closed(); |
| } |
| } |
| |
| // static |
| void SlideAnimatorGtk::SetAnimationsForTesting(bool enable) { |
| animations_enabled_ = enable; |
| } |
| |
| // static |
| void SlideAnimatorGtk::OnChildSizeAllocate(GtkWidget* child, |
| GtkAllocation* allocation, |
| SlideAnimatorGtk* slider) { |
| if (slider->child_needs_move_) { |
| gtk_expanded_container_move(GTK_EXPANDED_CONTAINER(slider->widget()), |
| child, 0, -allocation->height); |
| slider->child_needs_move_ = false; |
| } |
| } |