Home | History | Annotate | Download | only in infobars
      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/views/infobars/infobar.h"
      6 
      7 #include <cmath>
      8 
      9 #include "ui/base/animation/slide_animation.h"
     10 #include "chrome/browser/tab_contents/infobar_delegate.h"
     11 #include "chrome/browser/ui/views/infobars/infobar_container.h"
     12 
     13 InfoBar::InfoBar(InfoBarDelegate* delegate)
     14     : delegate_(delegate),
     15       container_(NULL),
     16       ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new ui::SlideAnimation(this))),
     17       arrow_height_(0),
     18       arrow_target_height_(kDefaultArrowTargetHeight),
     19       arrow_half_width_(0),
     20       bar_height_(0),
     21       bar_target_height_(kDefaultBarTargetHeight) {
     22   DCHECK(delegate != NULL);
     23   animation_->SetTweenType(ui::Tween::LINEAR);
     24 }
     25 
     26 InfoBar::~InfoBar() {
     27 }
     28 
     29 void InfoBar::Show(bool animate) {
     30   if (animate) {
     31     animation_->Show();
     32   } else {
     33     animation_->Reset(1.0);
     34     AnimationEnded(NULL);
     35   }
     36 }
     37 
     38 void InfoBar::Hide(bool animate) {
     39   PlatformSpecificHide(animate);
     40   if (animate) {
     41     animation_->Hide();
     42   } else {
     43     animation_->Reset(0.0);
     44     AnimationEnded(NULL);
     45   }
     46 }
     47 
     48 void InfoBar::SetArrowTargetHeight(int height) {
     49   DCHECK_LE(height, kMaximumArrowTargetHeight);
     50   // Once the closing animation starts, we ignore further requests to change the
     51   // target height.
     52   if ((arrow_target_height_ != height) && !animation()->IsClosing()) {
     53     arrow_target_height_ = height;
     54     RecalculateHeights(false);
     55   }
     56 }
     57 
     58 void InfoBar::AnimationProgressed(const ui::Animation* animation) {
     59   RecalculateHeights(false);
     60 }
     61 
     62 void InfoBar::RemoveInfoBar() {
     63   if (container_)
     64     container_->RemoveDelegate(delegate_);
     65 }
     66 
     67 void InfoBar::SetBarTargetHeight(int height) {
     68   if (bar_target_height_ != height) {
     69     bar_target_height_ = height;
     70     RecalculateHeights(false);
     71   }
     72 }
     73 
     74 int InfoBar::OffsetY(const gfx::Size& prefsize) const {
     75   return arrow_height_ +
     76       std::max((bar_target_height_ - prefsize.height()) / 2, 0) -
     77       (bar_target_height_ - bar_height_);
     78 }
     79 
     80 void InfoBar::AnimationEnded(const ui::Animation* animation) {
     81   // When the animation ends, we must ensure the container is notified even if
     82   // the heights haven't changed, lest it never get an "animation finished"
     83   // notification.  (If the browser doesn't get this notification, it will not
     84   // bother to re-layout the content area for the new infobar size.)
     85   RecalculateHeights(true);
     86   MaybeDelete();
     87 }
     88 
     89 void InfoBar::RecalculateHeights(bool force_notify) {
     90   int old_arrow_height = arrow_height_;
     91   int old_bar_height = bar_height_;
     92 
     93   // Find the desired arrow height/half-width.  The arrow area is
     94   // |arrow_height_| * |arrow_half_width_|.  When the bar is opening or closing,
     95   // scaling each of these with the square root of the animation value causes a
     96   // linear animation of the area, which matches the perception of the animation
     97   // of the bar portion.
     98   double scale_factor = sqrt(animation()->GetCurrentValue());
     99   arrow_height_ = static_cast<int>(arrow_target_height_ * scale_factor);
    100   if (animation_->is_animating()) {
    101     arrow_half_width_ = static_cast<int>(std::min(arrow_target_height_,
    102         kMaximumArrowTargetHalfWidth) * scale_factor);
    103   } else {
    104     // When the infobar is not animating (i.e. fully open), we set the
    105     // half-width to be proportionally the same distance between its default and
    106     // maximum values as the height is between its.
    107     arrow_half_width_ = kDefaultArrowTargetHalfWidth +
    108         ((kMaximumArrowTargetHalfWidth - kDefaultArrowTargetHalfWidth) *
    109          ((arrow_height_ - kDefaultArrowTargetHeight) /
    110           (kMaximumArrowTargetHeight - kDefaultArrowTargetHeight)));
    111   }
    112   // Add pixels for the stroke, if the arrow is to be visible at all.  Without
    113   // this, changing the arrow height from 0 to kSeparatorLineHeight would
    114   // produce no visible effect, because the stroke would paint atop the divider
    115   // line above the infobar.
    116   if (arrow_height_)
    117     arrow_height_ += kSeparatorLineHeight;
    118 
    119   bar_height_ =
    120       static_cast<int>(bar_target_height_ * animation()->GetCurrentValue());
    121 
    122   // Don't re-layout if nothing has changed, e.g. because the animation step was
    123   // not large enough to actually change the heights by at least a pixel.
    124   bool heights_differ =
    125       (old_arrow_height != arrow_height_) || (old_bar_height != bar_height_);
    126   if (heights_differ)
    127     PlatformSpecificOnHeightsRecalculated();
    128 
    129   if (container_ && (heights_differ || force_notify))
    130     container_->OnInfoBarStateChanged(animation_->is_animating());
    131 }
    132 
    133 void InfoBar::MaybeDelete() {
    134   if (delegate_ && (animation_->GetCurrentValue() == 0.0)) {
    135     if (container_)
    136       container_->RemoveInfoBar(this);
    137     // Note that we only tell the delegate we're closed here, and not when we're
    138     // simply destroyed (by virtue of a tab switch or being moved from window to
    139     // window), since this action can cause the delegate to destroy itself.
    140     delegate_->InfoBarClosed();
    141     delegate_ = NULL;
    142   }
    143 }
    144