OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/system/tray/tray_bubble_view.h" | 5 #include "ash/system/tray/tray_bubble_view.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
8 #include "ash/shell_window_ids.h" | 8 #include "ash/shell_window_ids.h" |
9 #include "ash/system/tray/tray_constants.h" | 9 #include "ash/system/tray/tray_constants.h" |
10 #include "ash/wm/shelf_layout_manager.h" | 10 #include "ash/wm/shelf_layout_manager.h" |
11 #include "ash/wm/window_animations.h" | |
11 #include "grit/ash_strings.h" | 12 #include "grit/ash_strings.h" |
12 #include "third_party/skia/include/core/SkCanvas.h" | 13 #include "third_party/skia/include/core/SkCanvas.h" |
13 #include "third_party/skia/include/core/SkColor.h" | 14 #include "third_party/skia/include/core/SkColor.h" |
14 #include "third_party/skia/include/core/SkPaint.h" | 15 #include "third_party/skia/include/core/SkPaint.h" |
15 #include "third_party/skia/include/core/SkPath.h" | 16 #include "third_party/skia/include/core/SkPath.h" |
16 #include "third_party/skia/include/effects/SkBlurImageFilter.h" | 17 #include "third_party/skia/include/effects/SkBlurImageFilter.h" |
17 #include "ui/aura/event.h" | 18 #include "ui/aura/event.h" |
18 #include "ui/aura/window.h" | 19 #include "ui/aura/window.h" |
19 #include "ui/base/accessibility/accessible_view_state.h" | 20 #include "ui/base/accessibility/accessible_view_state.h" |
20 #include "ui/base/l10n/l10n_util.h" | 21 #include "ui/base/l10n/l10n_util.h" |
21 #include "ui/gfx/canvas.h" | 22 #include "ui/gfx/canvas.h" |
22 #include "ui/gfx/insets.h" | 23 #include "ui/gfx/insets.h" |
23 #include "ui/gfx/screen.h" | 24 #include "ui/gfx/screen.h" |
24 #include "ui/views/bubble/bubble_frame_view.h" | 25 #include "ui/views/bubble/bubble_frame_view.h" |
25 #include "ui/views/layout/box_layout.h" | 26 #include "ui/views/layout/box_layout.h" |
26 | 27 |
27 namespace ash { | 28 namespace ash { |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 const int kShadowThickness = 4; | 32 const int kShadowThickness = 4; |
32 const int kBottomLineHeight = 1; | 33 const int kBottomLineHeight = 1; |
33 const int kSystemTrayBubbleHorizontalInset = 1; | 34 const int kSystemTrayBubbleHorizontalInset = 1; |
34 const int kSystemTrayBubbleVerticalInset = 1; | 35 const int kSystemTrayBubbleVerticalInset = 1; |
35 | 36 |
36 const int kArrowHeight = 10; | 37 const int kArrowHeight = 10; |
37 const int kArrowWidth = 20; | 38 const int kArrowWidth = 20; |
38 | 39 |
39 // Inset the arrow a bit from the edge. | 40 // Inset the arrow a bit from the edge. |
40 const int kArrowMinOffset = kArrowWidth / 2 + 4; | 41 const int kArrowEdgeMargin = 12; |
42 const int kArrowMinOffset = kArrowWidth / 2 + kArrowEdgeMargin; | |
41 | 43 |
42 const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0); | 44 const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0); |
43 | 45 |
46 const int kAnimationDurationForPopupMS = 200; | |
47 | |
44 void DrawBlurredShadowAroundView(gfx::Canvas* canvas, | 48 void DrawBlurredShadowAroundView(gfx::Canvas* canvas, |
45 int top, | 49 int top, |
46 int bottom, | 50 int bottom, |
47 int width, | 51 int width, |
48 const gfx::Insets& inset) { | 52 const gfx::Insets& inset) { |
49 SkPath path; | 53 SkPath path; |
50 path.incReserve(4); | 54 path.incReserve(4); |
51 path.moveTo(SkIntToScalar(inset.left() + kShadowThickness), | 55 path.moveTo(SkIntToScalar(inset.left() + kShadowThickness), |
52 SkIntToScalar(top + kShadowThickness + 1)); | 56 SkIntToScalar(top + kShadowThickness + 1)); |
53 path.lineTo(SkIntToScalar(inset.left() + kShadowThickness), | 57 path.lineTo(SkIntToScalar(inset.left() + kShadowThickness), |
(...skipping 11 matching lines...) Expand all Loading... | |
65 paint.setImageFilter(new SkBlurImageFilter( | 69 paint.setImageFilter(new SkBlurImageFilter( |
66 SkIntToScalar(3), SkIntToScalar(3)))->unref(); | 70 SkIntToScalar(3), SkIntToScalar(3)))->unref(); |
67 canvas->sk_canvas()->drawPath(path, paint); | 71 canvas->sk_canvas()->drawPath(path, paint); |
68 } | 72 } |
69 | 73 |
70 class TrayBubbleBorder : public views::BubbleBorder { | 74 class TrayBubbleBorder : public views::BubbleBorder { |
71 public: | 75 public: |
72 TrayBubbleBorder(views::View* owner, | 76 TrayBubbleBorder(views::View* owner, |
73 views::View* anchor, | 77 views::View* anchor, |
74 views::BubbleBorder::ArrowLocation arrow_location, | 78 views::BubbleBorder::ArrowLocation arrow_location, |
75 int arrow_offset) | 79 int arrow_offset, |
76 : views::BubbleBorder(arrow_location, | 80 const SkColor& arrow_color) |
77 views::BubbleBorder::NO_SHADOW), | 81 : views::BubbleBorder(arrow_location, views::BubbleBorder::NO_SHADOW), |
78 owner_(owner), | 82 owner_(owner), |
79 anchor_(anchor), | 83 anchor_(anchor), |
80 tray_arrow_offset_(arrow_offset) { | 84 tray_arrow_offset_(arrow_offset) { |
81 set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | 85 set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
86 set_background_color(arrow_color); | |
82 } | 87 } |
83 | 88 |
84 virtual ~TrayBubbleBorder() {} | 89 virtual ~TrayBubbleBorder() {} |
85 | 90 |
86 private: | |
87 views::Background* FindAppropriateBackground(views::View* view, | |
88 const gfx::Point& point) const { | |
89 views::Background* background = NULL; | |
90 views::View* target = view->GetEventHandlerForPoint(point); | |
91 for (; target && !background; target = target->parent()) | |
92 background = target->background(); | |
93 return background; | |
94 } | |
95 | |
96 // Overridden from views::BubbleBorder. | 91 // Overridden from views::BubbleBorder. |
97 // Override views::BubbleBorder to set the bubble on top of the anchor when | 92 // Override views::BubbleBorder to set the bubble on top of the anchor when |
98 // it has no arrow. | 93 // it has no arrow. |
99 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, | 94 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, |
100 const gfx::Size& contents_size) const OVERRIDE { | 95 const gfx::Size& contents_size) const OVERRIDE { |
101 if (arrow_location() != NONE) { | 96 if (arrow_location() != NONE) { |
102 return views::BubbleBorder::GetBounds(position_relative_to, | 97 return views::BubbleBorder::GetBounds(position_relative_to, |
103 contents_size); | 98 contents_size); |
104 } | 99 } |
105 | 100 |
106 gfx::Size border_size(contents_size); | 101 gfx::Size border_size(contents_size); |
107 gfx::Insets insets; | 102 gfx::Insets insets; |
108 GetInsets(&insets); | 103 GetInsets(&insets); |
109 border_size.Enlarge(insets.width(), insets.height()); | 104 border_size.Enlarge(insets.width(), insets.height()); |
110 | 105 |
111 const int kArrowOverlap = 3; | 106 const int kArrowOverlap = 3; |
112 int x = position_relative_to.x() + | 107 int x = position_relative_to.x() + |
113 position_relative_to.width() / 2 - border_size.width() / 2; | 108 position_relative_to.width() / 2 - border_size.width() / 2; |
114 // Position the bubble on top of the anchor. | 109 // Position the bubble on top of the anchor. |
115 int y = position_relative_to.y() + | 110 int y = position_relative_to.y() + |
116 kArrowOverlap - border_size.height(); | 111 kArrowOverlap - border_size.height(); |
117 return gfx::Rect(x, y, border_size.width(), border_size.height()); | 112 return gfx::Rect(x, y, border_size.width(), border_size.height()); |
118 } | 113 } |
119 | 114 |
115 // TrayBubbleView supports dynamically updated bubbles. This does not | |
116 // behave well with BubbleFrameView which expects arrow_location to be | |
117 // unmirrored during initial layout (when ClientView is constructed), | |
118 // then mirrored after SizeToContents() gets called. | |
119 // So, instead of mirroring the arrow in CreateNonClientFrameView, | |
120 // mirror it here instead. | |
121 virtual void GetInsets(gfx::Insets* insets) const OVERRIDE { | |
122 ArrowLocation arrow_loc = arrow_location(); | |
123 if (base::i18n::IsRTL()) | |
124 arrow_loc = horizontal_mirror(arrow_loc); | |
125 return GetInsetsForArrowLocation(insets, arrow_loc); | |
126 } | |
127 | |
120 // Overridden from views::Border. | 128 // Overridden from views::Border. |
121 virtual void Paint(const views::View& view, | 129 virtual void Paint(const views::View& view, |
122 gfx::Canvas* canvas) const OVERRIDE { | 130 gfx::Canvas* canvas) const OVERRIDE { |
123 gfx::Insets inset; | 131 gfx::Insets inset; |
124 GetInsets(&inset); | 132 // Get the unmirrored insets for the arrow location. |
133 GetInsetsForArrowLocation(&inset, arrow_location()); | |
125 DrawBlurredShadowAroundView( | 134 DrawBlurredShadowAroundView( |
126 canvas, 0, owner_->height(), owner_->width(), inset); | 135 canvas, 0, owner_->height(), owner_->width(), inset); |
127 | 136 |
128 // Draw the bottom line. | 137 // Draw the bottom line. |
129 int y = owner_->height() + inset.top(); | 138 int y = owner_->height() + inset.top(); |
130 canvas->FillRect(gfx::Rect(inset.left(), y, owner_->width(), | 139 canvas->FillRect(gfx::Rect(inset.left(), y, owner_->width(), |
131 kBottomLineHeight), kBorderDarkColor); | 140 kBottomLineHeight), kBorderDarkColor); |
132 | 141 |
133 if (!Shell::GetInstance()->shelf()->IsVisible() || | 142 if (!Shell::GetInstance()->shelf()->IsVisible() || |
134 arrow_location() == views::BubbleBorder::NONE) | 143 arrow_location() == views::BubbleBorder::NONE) |
135 return; | 144 return; |
136 | 145 |
137 gfx::Point arrow_reference; | 146 gfx::Point arrow_reference; |
138 | 147 |
139 // Draw the arrow after drawing child borders, so that the arrow can cover | 148 // Draw the arrow after drawing child borders, so that the arrow can cover |
140 // the its overlap section with child border. | 149 // its overlap section with child border. |
141 SkPath path; | 150 SkPath path; |
142 path.incReserve(4); | 151 path.incReserve(4); |
143 if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT || | 152 if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT || |
144 arrow_location() == views::BubbleBorder::BOTTOM_LEFT) { | 153 arrow_location() == views::BubbleBorder::BOTTOM_LEFT) { |
145 // Do not let the arrow too close to the edge of the bubble and | 154 // Note: tray_arrow_offset_ is relative to the anchor widget. |
146 // and the edge of the anchor. | 155 int tip_x; |
msw
2012/07/27 20:32:04
nit: init to 0? Same for tip_y below.
stevenjb
2012/07/30 20:09:03
I actually prefer not to initialize this to allow
| |
147 int tip_x = base::i18n::IsRTL() ? | 156 if (tray_arrow_offset_ == |
148 std::min(std::max(tray_arrow_offset_, kArrowMinOffset), | 157 internal::TrayBubbleView::InitParams::kArrowDefaultOffset) { |
149 std::min(owner_->width(), anchor_->width()) | 158 if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT) |
150 - kArrowMinOffset) : | 159 tip_x = kArrowMinOffset; |
151 std::min(std::max(owner_->width() - tray_arrow_offset_, | 160 else |
152 owner_->width() - | 161 tip_x = owner_->width() - kArrowMinOffset; |
153 std::min(owner_->width(), anchor_->width()) + | 162 } else { |
154 kArrowMinOffset), | 163 gfx::Point pt(tray_arrow_offset_, 0); |
155 owner_->width() - kArrowMinOffset); | 164 views::View::ConvertPointToScreen( |
165 anchor_->GetWidget()->GetRootView(), &pt); | |
166 views::View::ConvertPointFromScreen( | |
167 owner_->GetWidget()->GetRootView(), &pt); | |
168 tip_x = std::min(pt.x(), owner_->width() - kArrowMinOffset); | |
169 tip_x = std::max(tip_x, kArrowMinOffset); | |
170 } | |
156 int left_base_x = tip_x - kArrowWidth / 2; | 171 int left_base_x = tip_x - kArrowWidth / 2; |
157 int left_base_y = y; | 172 int left_base_y = y; |
158 int tip_y = left_base_y + kArrowHeight; | 173 int tip_y = left_base_y + kArrowHeight; |
159 path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); | 174 path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); |
160 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); | 175 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); |
161 path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), | 176 path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), |
162 SkIntToScalar(left_base_y)); | 177 SkIntToScalar(left_base_y)); |
163 arrow_reference.SetPoint(tip_x, left_base_y - kArrowHeight); | 178 arrow_reference.SetPoint(tip_x, left_base_y - kArrowHeight); |
164 } else { | 179 } else { |
165 int tip_y = y - tray_arrow_offset_; | 180 int tip_y; |
166 tip_y = std::min(std::max(kArrowMinOffset, tip_y), | 181 if (tray_arrow_offset_ == |
167 owner_->height() - kArrowMinOffset); | 182 internal::TrayBubbleView::InitParams::kArrowDefaultOffset) { |
183 tip_y = owner_->height() - kArrowMinOffset; | |
184 } else { | |
185 int pty = y - tray_arrow_offset_; | |
186 gfx::Point pt(0, pty); | |
187 views::View::ConvertPointToScreen( | |
188 anchor_->GetWidget()->GetRootView(), &pt); | |
189 views::View::ConvertPointFromScreen( | |
190 owner_->GetWidget()->GetRootView(), &pt); | |
191 tip_y = std::min(pt.y(), owner_->height() - kArrowMinOffset); | |
192 tip_y = std::max(tip_y, kArrowMinOffset); | |
193 } | |
168 int top_base_y = tip_y - kArrowWidth / 2; | 194 int top_base_y = tip_y - kArrowWidth / 2; |
169 int top_base_x, tip_x; | 195 int top_base_x, tip_x; |
170 if (arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { | 196 if (arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { |
171 top_base_x = inset.left() + kSystemTrayBubbleHorizontalInset; | 197 top_base_x = inset.left() + kSystemTrayBubbleHorizontalInset; |
172 tip_x = top_base_x - kArrowHeight; | 198 tip_x = top_base_x - kArrowHeight; |
173 arrow_reference.SetPoint(top_base_x + kArrowHeight, tip_y); | 199 arrow_reference.SetPoint(top_base_x + kArrowHeight, tip_y); |
174 } else { | 200 } else { |
175 DCHECK(arrow_location() == views::BubbleBorder::RIGHT_BOTTOM); | 201 DCHECK(arrow_location() == views::BubbleBorder::RIGHT_BOTTOM); |
176 top_base_x = inset.left() + owner_->width() - | 202 top_base_x = inset.left() + owner_->width() - |
177 kSystemTrayBubbleHorizontalInset; | 203 kSystemTrayBubbleHorizontalInset; |
178 tip_x = top_base_x + kArrowHeight; | 204 tip_x = top_base_x + kArrowHeight; |
179 arrow_reference.SetPoint(top_base_x - kArrowHeight, tip_y); | 205 arrow_reference.SetPoint(top_base_x - kArrowHeight, tip_y); |
180 } | 206 } |
181 path.moveTo(SkIntToScalar(top_base_x), SkIntToScalar(top_base_y)); | 207 path.moveTo(SkIntToScalar(top_base_x), SkIntToScalar(top_base_y)); |
182 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); | 208 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); |
183 path.lineTo(SkIntToScalar(top_base_x), | 209 path.lineTo(SkIntToScalar(top_base_x), |
184 SkIntToScalar(top_base_y + kArrowWidth)); | 210 SkIntToScalar(top_base_y + kArrowWidth)); |
185 } | 211 } |
186 | 212 |
187 views::Background* background = FindAppropriateBackground(owner_, | |
188 arrow_reference); | |
189 | |
190 SkPaint paint; | 213 SkPaint paint; |
191 paint.setStyle(SkPaint::kFill_Style); | 214 paint.setStyle(SkPaint::kFill_Style); |
192 paint.setColor(background ? background->get_color() : kBackgroundColor); | 215 paint.setColor(background_color()); |
193 canvas->DrawPath(path, paint); | 216 canvas->DrawPath(path, paint); |
194 | 217 |
195 // Now draw the arrow border. | 218 // Now draw the arrow border. |
196 paint.setStyle(SkPaint::kStroke_Style); | 219 paint.setStyle(SkPaint::kStroke_Style); |
197 paint.setColor(kBorderDarkColor); | 220 paint.setColor(kBorderDarkColor); |
198 canvas->DrawPath(path, paint); | 221 canvas->DrawPath(path, paint); |
199 | 222 |
200 } | 223 } |
201 | 224 |
202 views::View* owner_; | 225 views::View* owner_; |
203 views::View* anchor_; | 226 views::View* anchor_; |
204 const int tray_arrow_offset_; | 227 const int tray_arrow_offset_; |
205 | 228 |
206 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); | 229 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); |
207 }; | 230 }; |
208 | 231 |
209 } // namespace | 232 } // namespace |
210 | 233 |
211 namespace internal { | 234 namespace internal { |
212 | 235 |
236 // static | |
237 const int TrayBubbleView::InitParams::kArrowDefaultOffset = -1; | |
238 | |
239 TrayBubbleView::InitParams::InitParams(AnchorType anchor_type, | |
240 ShelfAlignment shelf_alignment) | |
241 : anchor_type(anchor_type), | |
242 shelf_alignment(shelf_alignment), | |
243 bubble_width(kTrayPopupWidth), | |
244 max_height(0), | |
245 can_activate(false), | |
246 arrow_offset(kArrowDefaultOffset), | |
247 arrow_color(kHeaderBackgroundColorDark) { | |
248 } | |
249 | |
250 TrayBubbleView* TrayBubbleView::Create(views::View* anchor, | |
251 Host* host, | |
252 const InitParams& init_params) { | |
253 // Set arrow_location here so that it can be passed correctly to the | |
254 // BubbleView constructor. | |
255 views::BubbleBorder::ArrowLocation arrow_location; | |
msw
2012/07/27 20:32:04
nit: init arrow_location to some value.
stevenjb
2012/07/30 20:09:03
Same as above - we don't want to accidentally skip
| |
256 if (init_params.anchor_type == ANCHOR_TYPE_TRAY) { | |
257 if (init_params.shelf_alignment == SHELF_ALIGNMENT_BOTTOM) { | |
258 arrow_location = base::i18n::IsRTL() ? | |
259 views::BubbleBorder::BOTTOM_LEFT : views::BubbleBorder::BOTTOM_RIGHT; | |
260 } else if (init_params.shelf_alignment == SHELF_ALIGNMENT_LEFT) { | |
261 arrow_location = views::BubbleBorder::LEFT_BOTTOM; | |
262 } else { | |
263 arrow_location = views::BubbleBorder::RIGHT_BOTTOM; | |
264 } | |
265 } else { | |
266 arrow_location = views::BubbleBorder::NONE; | |
267 } | |
268 | |
269 return new TrayBubbleView(init_params, arrow_location, anchor, host); | |
270 } | |
271 | |
213 TrayBubbleView::TrayBubbleView( | 272 TrayBubbleView::TrayBubbleView( |
273 const InitParams& init_params, | |
274 views::BubbleBorder::ArrowLocation arrow_location, | |
214 views::View* anchor, | 275 views::View* anchor, |
215 views::BubbleBorder::ArrowLocation arrow_location, | 276 Host* host) |
216 Host* host, | |
217 bool can_activate, | |
218 int bubble_width) | |
219 : views::BubbleDelegateView(anchor, arrow_location), | 277 : views::BubbleDelegateView(anchor, arrow_location), |
220 host_(host), | 278 params_(init_params), |
221 can_activate_(can_activate), | 279 host_(host) { |
222 max_height_(0), | |
223 bubble_width_(bubble_width) { | |
224 set_margins(gfx::Insets()); | 280 set_margins(gfx::Insets()); |
225 set_parent_window(Shell::GetContainer( | 281 set_parent_window(Shell::GetContainer( |
226 anchor->GetWidget()->GetNativeWindow()->GetRootWindow(), | 282 anchor->GetWidget()->GetNativeWindow()->GetRootWindow(), |
227 internal::kShellWindowId_SettingBubbleContainer)); | 283 internal::kShellWindowId_SettingBubbleContainer)); |
228 set_notify_enter_exit_on_child(true); | 284 set_notify_enter_exit_on_child(true); |
229 SetPaintToLayer(true); | 285 SetPaintToLayer(true); |
230 SetFillsBoundsOpaquely(true); | 286 SetFillsBoundsOpaquely(true); |
231 } | 287 } |
232 | 288 |
233 TrayBubbleView::~TrayBubbleView() { | 289 TrayBubbleView::~TrayBubbleView() { |
234 // Inform host items (models) that their views are being destroyed. | 290 // Inform host items (models) that their views are being destroyed. |
235 if (host_) | 291 if (host_) |
236 host_->BubbleViewDestroyed(); | 292 host_->BubbleViewDestroyed(); |
237 } | 293 } |
238 | 294 |
239 void TrayBubbleView::SetBubbleBorder(int arrow_offset) { | 295 void TrayBubbleView::UpdateBubble() { |
240 DCHECK(GetWidget()); | |
241 TrayBubbleBorder* bubble_border = new TrayBubbleBorder( | |
242 this, anchor_view(), arrow_location(), arrow_offset); | |
243 GetBubbleFrameView()->SetBubbleBorder(bubble_border); | |
244 // Recalculate size with new border. | |
245 SizeToContents(); | |
246 } | |
247 | |
248 void TrayBubbleView::UpdateAnchor() { | |
249 SizeToContents(); | 296 SizeToContents(); |
250 GetWidget()->GetRootView()->SchedulePaint(); | 297 GetWidget()->GetRootView()->SchedulePaint(); |
251 } | 298 } |
252 | 299 |
253 void TrayBubbleView::SetMaxHeight(int height) { | 300 void TrayBubbleView::SetMaxHeight(int height) { |
254 max_height_ = height; | 301 params_.max_height = height; |
255 if (GetWidget()) | 302 if (GetWidget()) |
256 SizeToContents(); | 303 SizeToContents(); |
257 } | 304 } |
258 | 305 |
259 void TrayBubbleView::Init() { | 306 void TrayBubbleView::Init() { |
260 views::BoxLayout* layout = | 307 views::BoxLayout* layout = |
261 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); | 308 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); |
262 layout->set_spread_blank_space(true); | 309 layout->set_spread_blank_space(true); |
263 SetLayoutManager(layout); | 310 SetLayoutManager(layout); |
264 set_background(NULL); | 311 set_background(NULL); |
265 } | 312 } |
266 | 313 |
267 gfx::Rect TrayBubbleView::GetAnchorRect() { | 314 gfx::Rect TrayBubbleView::GetAnchorRect() { |
268 gfx::Rect rect; | 315 gfx::Rect rect; |
269 if (host_) | 316 |
270 rect = host_->GetAnchorRect(); | 317 if (anchor_widget()->IsVisible()) { |
318 rect = anchor_widget()->GetWindowBoundsInScreen(); | |
319 if (params_.anchor_type == ANCHOR_TYPE_TRAY) { | |
320 if (params_.shelf_alignment == SHELF_ALIGNMENT_BOTTOM) { | |
321 bool rtl = base::i18n::IsRTL(); | |
322 rect.Inset( | |
323 rtl ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0, | |
324 0, | |
325 rtl ? 0 : kPaddingFromRightEdgeOfScreenBottomAlignment, | |
326 kPaddingFromBottomOfScreenBottomAlignment); | |
327 } else if (params_.shelf_alignment == SHELF_ALIGNMENT_LEFT) { | |
328 rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment, | |
329 kPaddingFromBottomOfScreenVerticalAlignment); | |
330 } else { | |
331 rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment, | |
332 0, 0, kPaddingFromBottomOfScreenVerticalAlignment); | |
333 } | |
334 } else if (params_.anchor_type == ANCHOR_TYPE_BUBBLE) { | |
335 // Invert the offsets to align with the bubble below. | |
336 if (params_.shelf_alignment == SHELF_ALIGNMENT_LEFT) { | |
337 rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment, | |
338 0, 0, kPaddingFromBottomOfScreenVerticalAlignment); | |
339 } else if (params_.shelf_alignment == SHELF_ALIGNMENT_RIGHT) { | |
340 rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment, | |
341 kPaddingFromBottomOfScreenVerticalAlignment); | |
342 } | |
343 } | |
344 } | |
345 | |
271 // TODO(jennyz): May need to add left/right alignment in the following code. | 346 // TODO(jennyz): May need to add left/right alignment in the following code. |
272 if (rect.IsEmpty()) { | 347 if (rect.IsEmpty()) { |
273 rect = gfx::Screen::GetPrimaryDisplay().bounds(); | 348 rect = gfx::Screen::GetPrimaryDisplay().bounds(); |
274 rect = gfx::Rect( | 349 rect = gfx::Rect( |
275 base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment : | 350 base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment : |
276 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment, | 351 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment, |
277 rect.height() - kPaddingFromBottomOfScreenBottomAlignment, | 352 rect.height() - kPaddingFromBottomOfScreenBottomAlignment, |
278 0, 0); | 353 0, 0); |
279 } | 354 } |
280 return rect; | 355 return rect; |
281 } | 356 } |
282 | 357 |
283 gfx::Rect TrayBubbleView::GetBubbleBounds() { | 358 gfx::Rect TrayBubbleView::GetBubbleBounds() { |
284 // Same as BubbleDelegateView implementation, but don't try mirroring. | 359 // Same as BubbleDelegateView implementation, but don't try mirroring. |
285 return GetBubbleFrameView()->GetUpdatedWindowBounds( | 360 return GetBubbleFrameView()->GetUpdatedWindowBounds( |
286 GetAnchorRect(), GetPreferredSize(), false /*try_mirroring_arrow*/); | 361 GetAnchorRect(), GetPreferredSize(), false /*try_mirroring_arrow*/); |
287 } | 362 } |
288 | 363 |
289 bool TrayBubbleView::CanActivate() const { | 364 bool TrayBubbleView::CanActivate() const { |
290 return can_activate_; | 365 return params_.can_activate; |
366 } | |
367 | |
368 // Overridden to create BubbleFrameView and set the border to TrayBubbleBorder | |
369 // (instead of creating a default BubbleBorder and replacing it). | |
370 views::NonClientFrameView* TrayBubbleView::CreateNonClientFrameView( | |
371 views::Widget* widget) { | |
372 TrayBubbleBorder* bubble_border = new TrayBubbleBorder( | |
373 this, anchor_view(), | |
374 arrow_location(), params_.arrow_offset, params_.arrow_color); | |
375 return new views::BubbleFrameView(margins(), bubble_border); | |
291 } | 376 } |
292 | 377 |
293 gfx::Size TrayBubbleView::GetPreferredSize() { | 378 gfx::Size TrayBubbleView::GetPreferredSize() { |
294 gfx::Size size = views::BubbleDelegateView::GetPreferredSize(); | 379 gfx::Size size = views::BubbleDelegateView::GetPreferredSize(); |
295 int height = size.height(); | 380 int height = size.height(); |
296 if (max_height_ != 0 && height > max_height_) | 381 if (params_.max_height != 0 && height > params_.max_height) |
297 height = max_height_; | 382 height = params_.max_height; |
298 return gfx::Size(bubble_width_, height); | 383 return gfx::Size(params_.bubble_width, height); |
299 } | 384 } |
300 | 385 |
301 void TrayBubbleView::OnMouseEntered(const views::MouseEvent& event) { | 386 void TrayBubbleView::OnMouseEntered(const views::MouseEvent& event) { |
302 if (host_) | 387 if (host_) |
303 host_->OnMouseEnteredView(); | 388 host_->OnMouseEnteredView(); |
304 } | 389 } |
305 | 390 |
306 void TrayBubbleView::OnMouseExited(const views::MouseEvent& event) { | 391 void TrayBubbleView::OnMouseExited(const views::MouseEvent& event) { |
307 if (host_) | 392 if (host_) |
308 host_->OnMouseExitedView(); | 393 host_->OnMouseExitedView(); |
309 } | 394 } |
310 | 395 |
311 void TrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) { | 396 void TrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) { |
312 if (can_activate_) { | 397 if (params_.can_activate) { |
313 state->role = ui::AccessibilityTypes::ROLE_WINDOW; | 398 state->role = ui::AccessibilityTypes::ROLE_WINDOW; |
314 state->name = l10n_util::GetStringUTF16( | 399 state->name = l10n_util::GetStringUTF16( |
315 IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME); | 400 IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME); |
316 } | 401 } |
317 } | 402 } |
318 | 403 |
319 void TrayBubbleView::ChildPreferredSizeChanged(View* child) { | 404 void TrayBubbleView::ChildPreferredSizeChanged(View* child) { |
320 SizeToContents(); | 405 SizeToContents(); |
321 } | 406 } |
322 | 407 |
(...skipping 10 matching lines...) Expand all Loading... | |
333 TrayBubbleView::Host::Host() | 418 TrayBubbleView::Host::Host() |
334 : widget_(NULL), | 419 : widget_(NULL), |
335 tray_view_(NULL) { | 420 tray_view_(NULL) { |
336 Shell::GetInstance()->AddEnvEventFilter(this); | 421 Shell::GetInstance()->AddEnvEventFilter(this); |
337 } | 422 } |
338 | 423 |
339 TrayBubbleView::Host::~Host() { | 424 TrayBubbleView::Host::~Host() { |
340 Shell::GetInstance()->RemoveEnvEventFilter(this); | 425 Shell::GetInstance()->RemoveEnvEventFilter(this); |
341 } | 426 } |
342 | 427 |
343 void TrayBubbleView::Host::InitializeHost(views::Widget* widget, | 428 void TrayBubbleView::Host::PostCreateBubble(views::Widget* widget, |
344 views::View* tray_view) { | 429 TrayBubbleView* bubble_view, |
430 views::View* tray_view) { | |
345 widget_ = widget; | 431 widget_ = widget; |
346 tray_view_ = tray_view; | 432 tray_view_ = tray_view; |
433 | |
434 // Must occur after call to BubbleDelegateView::CreateBubble(). | |
435 bubble_view->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | |
436 | |
437 // Setup animation. | |
438 ash::SetWindowVisibilityAnimationType( | |
439 widget->GetNativeWindow(), | |
440 ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); | |
441 ash::SetWindowVisibilityAnimationTransition( | |
442 widget->GetNativeWindow(), | |
443 ash::ANIMATE_BOTH); | |
444 ash::SetWindowVisibilityAnimationDuration( | |
445 widget->GetNativeWindow(), | |
446 base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS)); | |
447 | |
448 bubble_view->Show(); | |
449 bubble_view->UpdateBubble(); | |
347 } | 450 } |
348 | 451 |
349 bool TrayBubbleView::Host::PreHandleKeyEvent(aura::Window* target, | 452 bool TrayBubbleView::Host::PreHandleKeyEvent(aura::Window* target, |
350 aura::KeyEvent* event) { | 453 aura::KeyEvent* event) { |
351 return false; | 454 return false; |
352 } | 455 } |
353 | 456 |
354 bool TrayBubbleView::Host::PreHandleMouseEvent(aura::Window* target, | 457 bool TrayBubbleView::Host::PreHandleMouseEvent(aura::Window* target, |
355 aura::MouseEvent* event) { | 458 aura::MouseEvent* event) { |
356 if (event->type() == ui::ET_MOUSE_PRESSED) | 459 if (event->type() == ui::ET_MOUSE_PRESSED) |
(...skipping 30 matching lines...) Expand all Loading... | |
387 return; | 490 return; |
388 } | 491 } |
389 // Handle clicking outside the bubble and tray. We don't block the event, so | 492 // Handle clicking outside the bubble and tray. We don't block the event, so |
390 // it will also be handled by whatever widget was clicked on. | 493 // it will also be handled by whatever widget was clicked on. |
391 OnClickedOutsideView(); | 494 OnClickedOutsideView(); |
392 } | 495 } |
393 | 496 |
394 | 497 |
395 } // namespace internal | 498 } // namespace internal |
396 } // namespace ash | 499 } // namespace ash |
OLD | NEW |