OLD | NEW |
| (Empty) |
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 } | |
OLD | NEW |