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/infobars/infobar.h" | |
6 | |
7 #include <cmath> | |
8 | |
9 #include "base/logging.h" | |
10 #include "build/build_config.h" | |
11 #include "chrome/browser/infobars/infobar_container.h" | |
12 #include "chrome/browser/infobars/infobar_manager.h" | |
13 #include "ui/gfx/animation/slide_animation.h" | |
14 | |
15 InfoBar::InfoBar(scoped_ptr<InfoBarDelegate> delegate) | |
16 : owner_(NULL), | |
17 delegate_(delegate.Pass()), | |
18 container_(NULL), | |
19 animation_(this), | |
20 arrow_height_(0), | |
21 arrow_target_height_(kDefaultArrowTargetHeight), | |
22 arrow_half_width_(0), | |
23 bar_height_(0), | |
24 bar_target_height_(kDefaultBarTargetHeight) { | |
25 DCHECK(delegate_ != NULL); | |
26 animation_.SetTweenType(gfx::Tween::LINEAR); | |
27 delegate_->set_infobar(this); | |
28 } | |
29 | |
30 InfoBar::~InfoBar() { | |
31 DCHECK(!owner_); | |
32 } | |
33 | |
34 // static | |
35 SkColor InfoBar::GetTopColor(InfoBarDelegate::Type infobar_type) { | |
36 static const SkColor kWarningBackgroundColorTop = | |
37 SkColorSetRGB(255, 242, 183); // Yellow | |
38 static const SkColor kPageActionBackgroundColorTop = | |
39 SkColorSetRGB(237, 237, 237); // Gray | |
40 return (infobar_type == InfoBarDelegate::WARNING_TYPE) ? | |
41 kWarningBackgroundColorTop : kPageActionBackgroundColorTop; | |
42 } | |
43 | |
44 // static | |
45 SkColor InfoBar::GetBottomColor(InfoBarDelegate::Type infobar_type) { | |
46 static const SkColor kWarningBackgroundColorBottom = | |
47 SkColorSetRGB(250, 230, 145); // Yellow | |
48 static const SkColor kPageActionBackgroundColorBottom = | |
49 SkColorSetRGB(217, 217, 217); // Gray | |
50 return (infobar_type == InfoBarDelegate::WARNING_TYPE) ? | |
51 kWarningBackgroundColorBottom : kPageActionBackgroundColorBottom; | |
52 } | |
53 | |
54 void InfoBar::SetOwner(InfoBarManager* owner) { | |
55 DCHECK(!owner_); | |
56 owner_ = owner; | |
57 delegate_->StoreActiveEntryUniqueID(); | |
58 PlatformSpecificSetOwner(); | |
59 } | |
60 | |
61 void InfoBar::Show(bool animate) { | |
62 PlatformSpecificShow(animate); | |
63 if (animate) { | |
64 animation_.Show(); | |
65 } else { | |
66 animation_.Reset(1.0); | |
67 RecalculateHeights(true); | |
68 } | |
69 } | |
70 | |
71 void InfoBar::Hide(bool animate) { | |
72 PlatformSpecificHide(animate); | |
73 if (animate) { | |
74 animation_.Hide(); | |
75 } else { | |
76 animation_.Reset(0.0); | |
77 // We want to remove ourselves from the container immediately even if we | |
78 // still have an owner, which MaybeDelete() won't do. | |
79 DCHECK(container_); | |
80 container_->RemoveInfoBar(this); | |
81 MaybeDelete(); // Necessary if the infobar was already closing. | |
82 } | |
83 } | |
84 | |
85 void InfoBar::SetArrowTargetHeight(int height) { | |
86 DCHECK_LE(height, kMaximumArrowTargetHeight); | |
87 // Once the closing animation starts, we ignore further requests to change the | |
88 // target height. | |
89 if ((arrow_target_height_ != height) && !animation_.IsClosing()) { | |
90 arrow_target_height_ = height; | |
91 RecalculateHeights(false); | |
92 } | |
93 } | |
94 | |
95 void InfoBar::CloseSoon() { | |
96 owner_ = NULL; | |
97 PlatformSpecificOnCloseSoon(); | |
98 MaybeDelete(); | |
99 } | |
100 | |
101 void InfoBar::RemoveSelf() { | |
102 if (owner_) | |
103 owner_->RemoveInfoBar(this); | |
104 } | |
105 | |
106 void InfoBar::SetBarTargetHeight(int height) { | |
107 if (bar_target_height_ != height) { | |
108 bar_target_height_ = height; | |
109 RecalculateHeights(false); | |
110 } | |
111 } | |
112 | |
113 void InfoBar::AnimationProgressed(const gfx::Animation* animation) { | |
114 RecalculateHeights(false); | |
115 } | |
116 | |
117 void InfoBar::AnimationEnded(const gfx::Animation* animation) { | |
118 // When the animation ends, we must ensure the container is notified even if | |
119 // the heights haven't changed, lest it never get an "animation finished" | |
120 // notification. (If the browser doesn't get this notification, it will not | |
121 // bother to re-layout the content area for the new infobar size.) | |
122 RecalculateHeights(true); | |
123 MaybeDelete(); | |
124 } | |
125 | |
126 void InfoBar::RecalculateHeights(bool force_notify) { | |
127 int old_arrow_height = arrow_height_; | |
128 int old_bar_height = bar_height_; | |
129 | |
130 // Find the desired arrow height/half-width. The arrow area is | |
131 // |arrow_height_| * |arrow_half_width_|. When the bar is opening or closing, | |
132 // scaling each of these with the square root of the animation value causes a | |
133 // linear animation of the area, which matches the perception of the animation | |
134 // of the bar portion. | |
135 double scale_factor = sqrt(animation_.GetCurrentValue()); | |
136 arrow_height_ = static_cast<int>(arrow_target_height_ * scale_factor); | |
137 if (animation_.is_animating()) { | |
138 arrow_half_width_ = static_cast<int>(std::min(arrow_target_height_, | |
139 kMaximumArrowTargetHalfWidth) * scale_factor); | |
140 } else { | |
141 // When the infobar is not animating (i.e. fully open), we set the | |
142 // half-width to be proportionally the same distance between its default and | |
143 // maximum values as the height is between its. | |
144 arrow_half_width_ = kDefaultArrowTargetHalfWidth + | |
145 ((kMaximumArrowTargetHalfWidth - kDefaultArrowTargetHalfWidth) * | |
146 ((arrow_height_ - kDefaultArrowTargetHeight) / | |
147 (kMaximumArrowTargetHeight - kDefaultArrowTargetHeight))); | |
148 } | |
149 // Add pixels for the stroke, if the arrow is to be visible at all. Without | |
150 // this, changing the arrow height from 0 to kSeparatorLineHeight would | |
151 // produce no visible effect, because the stroke would paint atop the divider | |
152 // line above the infobar. | |
153 if (arrow_height_) | |
154 arrow_height_ += kSeparatorLineHeight; | |
155 | |
156 bar_height_ = animation_.CurrentValueBetween(0, bar_target_height_); | |
157 | |
158 // Don't re-layout if nothing has changed, e.g. because the animation step was | |
159 // not large enough to actually change the heights by at least a pixel. | |
160 bool heights_differ = | |
161 (old_arrow_height != arrow_height_) || (old_bar_height != bar_height_); | |
162 if (heights_differ) | |
163 PlatformSpecificOnHeightsRecalculated(); | |
164 | |
165 if (container_ && (heights_differ || force_notify)) | |
166 container_->OnInfoBarStateChanged(animation_.is_animating()); | |
167 } | |
168 | |
169 void InfoBar::MaybeDelete() { | |
170 if (!owner_ && (animation_.GetCurrentValue() == 0.0)) { | |
171 if (container_) | |
172 container_->RemoveInfoBar(this); | |
173 delete this; | |
174 } | |
175 } | |
OLD | NEW |