1 // Copyright (c) 2011 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 "chrome/browser/ui/gtk/gtk_expanded_container.h"
8 #include "ui/base/animation/animation.h"
9 #include "ui/base/animation/slide_animation.h"
10
11 namespace {
12
OnChildSizeRequest(GtkWidget * expanded,GtkWidget * child,GtkRequisition * requisition,gpointer control_child_size)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
SlideAnimatorGtk(GtkWidget * child,Direction direction,int duration,bool linear,bool control_child_size,Delegate * delegate)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
~SlideAnimatorGtk()66 SlideAnimatorGtk::~SlideAnimatorGtk() {
67 widget_.Destroy();
68 }
69
Open()70 void SlideAnimatorGtk::Open() {
71 if (!animations_enabled_)
72 return OpenWithoutAnimation();
73
74 gtk_widget_show(widget_.get());
75 animation_->Show();
76 }
77
OpenWithoutAnimation()78 void SlideAnimatorGtk::OpenWithoutAnimation() {
79 gtk_widget_show(widget_.get());
80 animation_->Reset(1.0);
81 animation_->Show();
82 AnimationProgressed(animation_.get());
83 }
84
Close()85 void SlideAnimatorGtk::Close() {
86 if (!animations_enabled_)
87 return CloseWithoutAnimation();
88
89 animation_->Hide();
90 }
91
End()92 void SlideAnimatorGtk::End() {
93 animation_->End();
94 }
95
CloseWithoutAnimation()96 void SlideAnimatorGtk::CloseWithoutAnimation() {
97 animation_->Reset(0.0);
98 animation_->Hide();
99 AnimationProgressed(animation_.get());
100 gtk_widget_hide(widget_.get());
101 }
102
IsShowing()103 bool SlideAnimatorGtk::IsShowing() {
104 return animation_->IsShowing();
105 }
106
IsClosing()107 bool SlideAnimatorGtk::IsClosing() {
108 return animation_->IsClosing();
109 }
110
IsAnimating()111 bool SlideAnimatorGtk::IsAnimating() {
112 return animation_->is_animating();
113 }
114
AnimationProgressed(const ui::Animation * animation)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 gtk_expanded_container_move(GTK_EXPANDED_CONTAINER(widget_.get()),
123 child_, 0, showing_height - req.height);
124 child_needs_move_ = false;
125 }
126 gtk_widget_set_size_request(widget_.get(), -1, showing_height);
127 }
128
AnimationEnded(const ui::Animation * animation)129 void SlideAnimatorGtk::AnimationEnded(const ui::Animation* animation) {
130 if (!animation_->IsShowing()) {
131 gtk_widget_hide(widget_.get());
132 if (delegate_)
133 delegate_->Closed();
134 }
135 }
136
137 // static
SetAnimationsForTesting(bool enable)138 void SlideAnimatorGtk::SetAnimationsForTesting(bool enable) {
139 animations_enabled_ = enable;
140 }
141
142 // static
OnChildSizeAllocate(GtkWidget * child,GtkAllocation * allocation,SlideAnimatorGtk * slider)143 void SlideAnimatorGtk::OnChildSizeAllocate(GtkWidget* child,
144 GtkAllocation* allocation,
145 SlideAnimatorGtk* slider) {
146 if (slider->child_needs_move_) {
147 gtk_expanded_container_move(GTK_EXPANDED_CONTAINER(slider->widget()),
148 child, 0, -allocation->height);
149 slider->child_needs_move_ = false;
150 }
151 }
152