1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/gtk/slide_animator_gtk.h" 6 7 #include "ui/base/animation/animation.h" 8 #include "ui/base/animation/slide_animation.h" 9 #include "ui/base/gtk/gtk_expanded_container.h" 10 11 namespace { 12 13 void OnChildSizeRequest(GtkWidget* expanded, 14 GtkWidget* child, 15 GtkRequisition* requisition, 16 gpointer control_child_size) { 17 // If |control_child_size| is true, then we want |child_| to match the width 18 // of the |widget_|, but the height of |child_| should not change. 19 if (!GPOINTER_TO_INT(control_child_size)) { 20 requisition->width = -1; 21 } 22 requisition->height = -1; 23 } 24 25 } // namespace 26 27 bool SlideAnimatorGtk::animations_enabled_ = true; 28 29 SlideAnimatorGtk::SlideAnimatorGtk(GtkWidget* child, 30 Direction direction, 31 int duration, 32 bool linear, 33 bool control_child_size, 34 Delegate* delegate) 35 : child_(child), 36 direction_(direction), 37 delegate_(delegate) { 38 widget_.Own(gtk_expanded_container_new()); 39 gtk_container_add(GTK_CONTAINER(widget_.get()), child); 40 gtk_widget_set_size_request(widget_.get(), -1, 0); 41 42 // If the child requests it, we will manually set the size request for 43 // |child_| every time the |widget_| changes sizes. This is mainly useful 44 // for bars, where we want the child to expand to fill all available space. 45 g_signal_connect(widget_.get(), "child-size-request", 46 G_CALLBACK(OnChildSizeRequest), 47 GINT_TO_POINTER(control_child_size)); 48 49 // We connect to this signal to set an initial position for our child widget. 50 // The reason we connect to this signal rather than setting the initial 51 // position here is that the widget is currently unallocated and may not 52 // even have a size request. 53 g_signal_connect(child, "size-allocate", 54 G_CALLBACK(OnChildSizeAllocate), this); 55 56 child_needs_move_ = (direction == DOWN); 57 58 animation_.reset(new ui::SlideAnimation(this)); 59 // Default tween type is EASE_OUT. 60 if (linear) 61 animation_->SetTweenType(ui::Tween::LINEAR); 62 if (duration != 0) 63 animation_->SetSlideDuration(duration); 64 } 65 66 SlideAnimatorGtk::~SlideAnimatorGtk() { 67 widget_.Destroy(); 68 } 69 70 void SlideAnimatorGtk::Open() { 71 if (!animations_enabled_) 72 return OpenWithoutAnimation(); 73 74 gtk_widget_show(widget_.get()); 75 animation_->Show(); 76 } 77 78 void SlideAnimatorGtk::OpenWithoutAnimation() { 79 gtk_widget_show(widget_.get()); 80 animation_->Reset(1.0); 81 animation_->Show(); 82 AnimationProgressed(animation_.get()); 83 } 84 85 void SlideAnimatorGtk::Close() { 86 if (!animations_enabled_) 87 return CloseWithoutAnimation(); 88 89 animation_->Hide(); 90 } 91 92 void SlideAnimatorGtk::End() { 93 animation_->End(); 94 } 95 96 void SlideAnimatorGtk::CloseWithoutAnimation() { 97 animation_->Reset(0.0); 98 animation_->Hide(); 99 AnimationProgressed(animation_.get()); 100 gtk_widget_hide(widget_.get()); 101 } 102 103 bool SlideAnimatorGtk::IsShowing() { 104 return animation_->IsShowing(); 105 } 106 107 bool SlideAnimatorGtk::IsClosing() { 108 return animation_->IsClosing(); 109 } 110 111 bool SlideAnimatorGtk::IsAnimating() { 112 return animation_->is_animating(); 113 } 114 115 void SlideAnimatorGtk::AnimationProgressed(const ui::Animation* animation) { 116 GtkRequisition req; 117 gtk_widget_size_request(child_, &req); 118 119 int showing_height = static_cast<int>(req.height * 120 animation_->GetCurrentValue()); 121 if (direction_ == DOWN) { 122 if (gtk_widget_get_parent(widget_.get())) { 123 gtk_expanded_container_move(GTK_EXPANDED_CONTAINER(widget_.get()), 124 child_, 0, showing_height - req.height); 125 } 126 child_needs_move_ = false; 127 } 128 gtk_widget_set_size_request(widget_.get(), -1, showing_height); 129 } 130 131 void SlideAnimatorGtk::AnimationEnded(const ui::Animation* animation) { 132 if (!animation_->IsShowing()) { 133 gtk_widget_hide(widget_.get()); 134 if (delegate_) 135 delegate_->Closed(); 136 } 137 } 138 139 // static 140 void SlideAnimatorGtk::SetAnimationsForTesting(bool enable) { 141 animations_enabled_ = enable; 142 } 143 144 // static 145 void SlideAnimatorGtk::OnChildSizeAllocate(GtkWidget* child, 146 GtkAllocation* allocation, 147 SlideAnimatorGtk* slider) { 148 if (slider->child_needs_move_) { 149 gtk_expanded_container_move(GTK_EXPANDED_CONTAINER(slider->widget()), 150 child, 0, -allocation->height); 151 slider->child_needs_move_ = false; 152 } 153 } 154