• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InfoBar(InfoBarDelegate * delegate)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 
~InfoBar()26 InfoBar::~InfoBar() {
27 }
28 
Show(bool animate)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 
Hide(bool animate)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 
SetArrowTargetHeight(int height)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 
AnimationProgressed(const ui::Animation * animation)58 void InfoBar::AnimationProgressed(const ui::Animation* animation) {
59   RecalculateHeights(false);
60 }
61 
RemoveInfoBar()62 void InfoBar::RemoveInfoBar() {
63   if (container_)
64     container_->RemoveDelegate(delegate_);
65 }
66 
SetBarTargetHeight(int height)67 void InfoBar::SetBarTargetHeight(int height) {
68   if (bar_target_height_ != height) {
69     bar_target_height_ = height;
70     RecalculateHeights(false);
71   }
72 }
73 
OffsetY(const gfx::Size & prefsize) const74 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 
AnimationEnded(const ui::Animation * animation)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 
RecalculateHeights(bool force_notify)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 
MaybeDelete()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