Home | History | Annotate | Download | only in gtk
      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 
     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     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 
    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
    138 void SlideAnimatorGtk::SetAnimationsForTesting(bool enable) {
    139   animations_enabled_ = enable;
    140 }
    141 
    142 // static
    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