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 "ui/views/bubble/tray_bubble_view.h" | 5 #include "ui/views/bubble/tray_bubble_view.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "third_party/skia/include/core/SkCanvas.h" | 9 #include "third_party/skia/include/core/SkCanvas.h" |
10 #include "third_party/skia/include/core/SkColor.h" | 10 #include "third_party/skia/include/core/SkColor.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 const int kBubbleSpacing = 20; | 32 const int kBubbleSpacing = 20; |
33 | 33 |
34 } // namespace | 34 } // namespace |
35 | 35 |
36 namespace views { | 36 namespace views { |
37 | 37 |
38 namespace internal { | 38 namespace internal { |
39 | 39 |
40 // Custom border for TrayBubbleView. Contains special logic for GetBounds() | 40 // Custom border for TrayBubbleView. Contains special logic for GetBounds() |
41 // to stack bubbles with no arrows correctly. Also calculates the arrow offset. | 41 // to stack bubbles with no arrows correctly. Also calculates the arrow offset. |
42 class TrayBubbleBorder : public views::BubbleBorder { | 42 class TrayBubbleBorder : public BubbleBorder { |
43 public: | 43 public: |
44 TrayBubbleBorder(views::View* owner, | 44 TrayBubbleBorder(View* owner, |
45 views::View* anchor, | 45 View* anchor, |
46 TrayBubbleView::InitParams params) | 46 TrayBubbleView::InitParams params) |
47 : views::BubbleBorder(params.arrow_location, params.shadow), | 47 : BubbleBorder(params.arrow_location, params.shadow, params.arrow_color), |
48 owner_(owner), | 48 owner_(owner), |
49 anchor_(anchor), | 49 anchor_(anchor), |
50 tray_arrow_offset_(params.arrow_offset) { | 50 tray_arrow_offset_(params.arrow_offset) { |
51 set_alignment(params.arrow_alignment); | 51 set_alignment(params.arrow_alignment); |
52 set_background_color(params.arrow_color); | 52 set_background_color(params.arrow_color); |
53 set_paint_arrow(!params.hide_arrow); | 53 set_paint_arrow(!params.hide_arrow); |
54 } | 54 } |
55 | 55 |
56 virtual ~TrayBubbleBorder() {} | 56 virtual ~TrayBubbleBorder() {} |
57 | 57 |
58 // Overridden from views::BubbleBorder. | 58 // Overridden from BubbleBorder. |
59 // Override views::BubbleBorder to set the bubble on top of the anchor when | 59 // Sets the bubble on top of the anchor when it has no arrow. |
60 // it has no arrow. | |
61 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, | 60 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, |
62 const gfx::Size& contents_size) const OVERRIDE { | 61 const gfx::Size& contents_size) const OVERRIDE { |
63 if (has_arrow(arrow_location())) { | 62 if (has_arrow(arrow_location())) |
64 return views::BubbleBorder::GetBounds(position_relative_to, | 63 return BubbleBorder::GetBounds(position_relative_to, contents_size); |
65 contents_size); | |
66 } | |
67 | 64 |
68 gfx::Size border_size(contents_size); | 65 gfx::Size border_size(contents_size); |
69 gfx::Insets insets = GetInsets(); | 66 gfx::Insets insets = GetInsets(); |
70 border_size.Enlarge(insets.width(), insets.height()); | 67 border_size.Enlarge(insets.width(), insets.height()); |
71 | 68 |
72 const int x = position_relative_to.x() + | 69 const int x = position_relative_to.x() + |
73 position_relative_to.width() / 2 - border_size.width() / 2; | 70 position_relative_to.width() / 2 - border_size.width() / 2; |
74 // Position the bubble on top of the anchor. | 71 // Position the bubble on top of the anchor. |
75 const int y = position_relative_to.y() - border_size.height() | 72 const int y = position_relative_to.y() - border_size.height() |
76 + insets.height() - kBubbleSpacing; | 73 + insets.height() - kBubbleSpacing; |
77 return gfx::Rect(x, y, border_size.width(), border_size.height()); | 74 return gfx::Rect(x, y, border_size.width(), border_size.height()); |
78 } | 75 } |
79 | 76 |
80 void UpdateArrowOffset() { | 77 void UpdateArrowOffset() { |
81 int arrow_offset = 0; | 78 int arrow_offset = 0; |
82 if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT || | 79 if (arrow_location() == BubbleBorder::BOTTOM_RIGHT || |
83 arrow_location() == views::BubbleBorder::BOTTOM_LEFT) { | 80 arrow_location() == BubbleBorder::BOTTOM_LEFT) { |
84 // Note: tray_arrow_offset_ is relative to the anchor widget. | 81 // Note: tray_arrow_offset_ is relative to the anchor widget. |
85 if (tray_arrow_offset_ == | 82 if (tray_arrow_offset_ == |
86 TrayBubbleView::InitParams::kArrowDefaultOffset) { | 83 TrayBubbleView::InitParams::kArrowDefaultOffset) { |
87 arrow_offset = kArrowMinOffset; | 84 arrow_offset = kArrowMinOffset; |
88 } else { | 85 } else { |
89 const int width = owner_->GetWidget()->GetContentsView()->width(); | 86 const int width = owner_->GetWidget()->GetContentsView()->width(); |
90 gfx::Point pt(tray_arrow_offset_, 0); | 87 gfx::Point pt(tray_arrow_offset_, 0); |
91 views::View::ConvertPointToScreen( | 88 View::ConvertPointToScreen(anchor_->GetWidget()->GetRootView(), &pt); |
92 anchor_->GetWidget()->GetRootView(), &pt); | 89 View::ConvertPointFromScreen(owner_->GetWidget()->GetRootView(), &pt); |
93 views::View::ConvertPointFromScreen( | |
94 owner_->GetWidget()->GetRootView(), &pt); | |
95 arrow_offset = pt.x(); | 90 arrow_offset = pt.x(); |
96 if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) | 91 if (arrow_location() == BubbleBorder::BOTTOM_RIGHT) |
97 arrow_offset = width - arrow_offset; | 92 arrow_offset = width - arrow_offset; |
98 arrow_offset = std::max(arrow_offset, kArrowMinOffset); | 93 arrow_offset = std::max(arrow_offset, kArrowMinOffset); |
99 } | 94 } |
100 } else { | 95 } else { |
101 if (tray_arrow_offset_ == | 96 if (tray_arrow_offset_ == |
102 TrayBubbleView::InitParams::kArrowDefaultOffset) { | 97 TrayBubbleView::InitParams::kArrowDefaultOffset) { |
103 arrow_offset = kArrowMinOffset; | 98 arrow_offset = kArrowMinOffset; |
104 } else { | 99 } else { |
105 gfx::Point pt(0, tray_arrow_offset_); | 100 gfx::Point pt(0, tray_arrow_offset_); |
106 views::View::ConvertPointToScreen( | 101 View::ConvertPointToScreen(anchor_->GetWidget()->GetRootView(), &pt); |
107 anchor_->GetWidget()->GetRootView(), &pt); | 102 View::ConvertPointFromScreen(owner_->GetWidget()->GetRootView(), &pt); |
108 views::View::ConvertPointFromScreen( | |
109 owner_->GetWidget()->GetRootView(), &pt); | |
110 arrow_offset = pt.y(); | 103 arrow_offset = pt.y(); |
111 arrow_offset = std::max(arrow_offset, kArrowMinOffset); | 104 arrow_offset = std::max(arrow_offset, kArrowMinOffset); |
112 } | 105 } |
113 } | 106 } |
114 set_arrow_offset(arrow_offset); | 107 set_arrow_offset(arrow_offset); |
115 } | 108 } |
116 | 109 |
117 private: | 110 private: |
118 views::View* owner_; | 111 View* owner_; |
119 views::View* anchor_; | 112 View* anchor_; |
120 const int tray_arrow_offset_; | 113 const int tray_arrow_offset_; |
121 | 114 |
122 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); | 115 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); |
123 }; | 116 }; |
124 | 117 |
125 // This mask layer clips the bubble's content so that it does not overwrite the | 118 // This mask layer clips the bubble's content so that it does not overwrite the |
126 // rounded bubble corners. | 119 // rounded bubble corners. |
127 // TODO(miket): This does not work on Windows. Implement layer masking or | 120 // TODO(miket): This does not work on Windows. Implement layer masking or |
128 // alternate solutions if the TrayBubbleView is needed there in the future. | 121 // alternate solutions if the TrayBubbleView is needed there in the future. |
129 class TrayBubbleContentMask : public ui::LayerDelegate { | 122 class TrayBubbleContentMask : public ui::LayerDelegate { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 float device_scale_factor) { | 162 float device_scale_factor) { |
170 // Redrawing will take care of scale factor change. | 163 // Redrawing will take care of scale factor change. |
171 } | 164 } |
172 | 165 |
173 base::Closure TrayBubbleContentMask::PrepareForLayerBoundsChange() { | 166 base::Closure TrayBubbleContentMask::PrepareForLayerBoundsChange() { |
174 return base::Closure(); | 167 return base::Closure(); |
175 } | 168 } |
176 | 169 |
177 // Custom layout for the bubble-view. Does the default box-layout if there is | 170 // Custom layout for the bubble-view. Does the default box-layout if there is |
178 // enough height. Otherwise, makes sure the bottom rows are visible. | 171 // enough height. Otherwise, makes sure the bottom rows are visible. |
179 class BottomAlignedBoxLayout : public views::BoxLayout { | 172 class BottomAlignedBoxLayout : public BoxLayout { |
180 public: | 173 public: |
181 explicit BottomAlignedBoxLayout(TrayBubbleView* bubble_view) | 174 explicit BottomAlignedBoxLayout(TrayBubbleView* bubble_view) |
182 : views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0), | 175 : BoxLayout(BoxLayout::kVertical, 0, 0, 0), |
183 bubble_view_(bubble_view) { | 176 bubble_view_(bubble_view) { |
184 } | 177 } |
185 | 178 |
186 virtual ~BottomAlignedBoxLayout() {} | 179 virtual ~BottomAlignedBoxLayout() {} |
187 | 180 |
188 private: | 181 private: |
189 virtual void Layout(views::View* host) OVERRIDE { | 182 virtual void Layout(View* host) OVERRIDE { |
190 if (host->height() >= host->GetPreferredSize().height() || | 183 if (host->height() >= host->GetPreferredSize().height() || |
191 !bubble_view_->is_gesture_dragging()) { | 184 !bubble_view_->is_gesture_dragging()) { |
192 views::BoxLayout::Layout(host); | 185 BoxLayout::Layout(host); |
193 return; | 186 return; |
194 } | 187 } |
195 | 188 |
196 int consumed_height = 0; | 189 int consumed_height = 0; |
197 for (int i = host->child_count() - 1; | 190 for (int i = host->child_count() - 1; |
198 i >= 0 && consumed_height < host->height(); --i) { | 191 i >= 0 && consumed_height < host->height(); --i) { |
199 views::View* child = host->child_at(i); | 192 View* child = host->child_at(i); |
200 if (!child->visible()) | 193 if (!child->visible()) |
201 continue; | 194 continue; |
202 gfx::Size size = child->GetPreferredSize(); | 195 gfx::Size size = child->GetPreferredSize(); |
203 child->SetBounds(0, host->height() - consumed_height - size.height(), | 196 child->SetBounds(0, host->height() - consumed_height - size.height(), |
204 host->width(), size.height()); | 197 host->width(), size.height()); |
205 consumed_height += size.height(); | 198 consumed_height += size.height(); |
206 } | 199 } |
207 } | 200 } |
208 | 201 |
209 TrayBubbleView* bubble_view_; | 202 TrayBubbleView* bubble_view_; |
(...skipping 15 matching lines...) Expand all Loading... |
225 int min_width, | 218 int min_width, |
226 int max_width) | 219 int max_width) |
227 : anchor_type(anchor_type), | 220 : anchor_type(anchor_type), |
228 anchor_alignment(anchor_alignment), | 221 anchor_alignment(anchor_alignment), |
229 min_width(min_width), | 222 min_width(min_width), |
230 max_width(max_width), | 223 max_width(max_width), |
231 max_height(0), | 224 max_height(0), |
232 can_activate(false), | 225 can_activate(false), |
233 close_on_deactivate(true), | 226 close_on_deactivate(true), |
234 arrow_color(SK_ColorBLACK), | 227 arrow_color(SK_ColorBLACK), |
235 arrow_location(views::BubbleBorder::NONE), | 228 arrow_location(BubbleBorder::NONE), |
236 arrow_offset(kArrowDefaultOffset), | 229 arrow_offset(kArrowDefaultOffset), |
237 hide_arrow(false), | 230 hide_arrow(false), |
238 shadow(views::BubbleBorder::BIG_SHADOW), | 231 shadow(BubbleBorder::BIG_SHADOW), |
239 arrow_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE) { | 232 arrow_alignment(BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE) { |
240 } | 233 } |
241 | 234 |
242 // static | 235 // static |
243 TrayBubbleView* TrayBubbleView::Create(gfx::NativeView parent_window, | 236 TrayBubbleView* TrayBubbleView::Create(gfx::NativeView parent_window, |
244 views::View* anchor, | 237 View* anchor, |
245 Delegate* delegate, | 238 Delegate* delegate, |
246 InitParams* init_params) { | 239 InitParams* init_params) { |
247 // Set arrow_location here so that it can be passed correctly to the | 240 // Set arrow_location here so that it can be passed correctly to the |
248 // BubbleView constructor. | 241 // BubbleView constructor. |
249 if (init_params->anchor_type == ANCHOR_TYPE_TRAY) { | 242 if (init_params->anchor_type == ANCHOR_TYPE_TRAY) { |
250 if (init_params->anchor_alignment == ANCHOR_ALIGNMENT_BOTTOM) { | 243 if (init_params->anchor_alignment == ANCHOR_ALIGNMENT_BOTTOM) { |
251 init_params->arrow_location = base::i18n::IsRTL() ? | 244 init_params->arrow_location = base::i18n::IsRTL() ? |
252 views::BubbleBorder::BOTTOM_LEFT : views::BubbleBorder::BOTTOM_RIGHT; | 245 BubbleBorder::BOTTOM_LEFT : BubbleBorder::BOTTOM_RIGHT; |
253 } else if (init_params->anchor_alignment == ANCHOR_ALIGNMENT_TOP) { | 246 } else if (init_params->anchor_alignment == ANCHOR_ALIGNMENT_TOP) { |
254 init_params->arrow_location = views::BubbleBorder::TOP_LEFT; | 247 init_params->arrow_location = BubbleBorder::TOP_LEFT; |
255 } else if (init_params->anchor_alignment == ANCHOR_ALIGNMENT_LEFT) { | 248 } else if (init_params->anchor_alignment == ANCHOR_ALIGNMENT_LEFT) { |
256 init_params->arrow_location = views::BubbleBorder::LEFT_BOTTOM; | 249 init_params->arrow_location = BubbleBorder::LEFT_BOTTOM; |
257 } else { | 250 } else { |
258 init_params->arrow_location = views::BubbleBorder::RIGHT_BOTTOM; | 251 init_params->arrow_location = BubbleBorder::RIGHT_BOTTOM; |
259 } | 252 } |
260 } else { | 253 } else { |
261 init_params->arrow_location = views::BubbleBorder::NONE; | 254 init_params->arrow_location = BubbleBorder::NONE; |
262 } | 255 } |
263 | 256 |
264 return new TrayBubbleView(parent_window, anchor, delegate, *init_params); | 257 return new TrayBubbleView(parent_window, anchor, delegate, *init_params); |
265 } | 258 } |
266 | 259 |
267 TrayBubbleView::TrayBubbleView(gfx::NativeView parent_window, | 260 TrayBubbleView::TrayBubbleView(gfx::NativeView parent_window, |
268 views::View* anchor, | 261 View* anchor, |
269 Delegate* delegate, | 262 Delegate* delegate, |
270 const InitParams& init_params) | 263 const InitParams& init_params) |
271 : views::BubbleDelegateView(anchor, init_params.arrow_location), | 264 : BubbleDelegateView(anchor, init_params.arrow_location), |
272 params_(init_params), | 265 params_(init_params), |
273 delegate_(delegate), | 266 delegate_(delegate), |
274 preferred_width_(init_params.min_width), | 267 preferred_width_(init_params.min_width), |
275 bubble_border_(NULL), | 268 bubble_border_(NULL), |
276 is_gesture_dragging_(false) { | 269 is_gesture_dragging_(false) { |
277 set_parent_window(parent_window); | 270 set_parent_window(parent_window); |
278 set_notify_enter_exit_on_child(true); | 271 set_notify_enter_exit_on_child(true); |
279 set_close_on_deactivate(init_params.close_on_deactivate); | 272 set_close_on_deactivate(init_params.close_on_deactivate); |
280 set_margins(gfx::Insets()); | 273 set_margins(gfx::Insets()); |
281 bubble_border_ = new TrayBubbleBorder(this, anchor_view(), params_); | 274 bubble_border_ = new TrayBubbleBorder(this, anchor_view(), params_); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 | 323 |
331 void TrayBubbleView::SetPaintArrow(bool paint_arrow) { | 324 void TrayBubbleView::SetPaintArrow(bool paint_arrow) { |
332 bubble_border_->set_paint_arrow(paint_arrow && !params_.hide_arrow); | 325 bubble_border_->set_paint_arrow(paint_arrow && !params_.hide_arrow); |
333 } | 326 } |
334 | 327 |
335 gfx::Insets TrayBubbleView::GetBorderInsets() const { | 328 gfx::Insets TrayBubbleView::GetBorderInsets() const { |
336 return bubble_border_->GetInsets(); | 329 return bubble_border_->GetInsets(); |
337 } | 330 } |
338 | 331 |
339 void TrayBubbleView::Init() { | 332 void TrayBubbleView::Init() { |
340 views::BoxLayout* layout = new BottomAlignedBoxLayout(this); | 333 BoxLayout* layout = new BottomAlignedBoxLayout(this); |
341 layout->set_spread_blank_space(true); | 334 layout->set_spread_blank_space(true); |
342 SetLayoutManager(layout); | 335 SetLayoutManager(layout); |
343 } | 336 } |
344 | 337 |
345 gfx::Rect TrayBubbleView::GetAnchorRect() { | 338 gfx::Rect TrayBubbleView::GetAnchorRect() { |
346 if (!delegate_) | 339 if (!delegate_) |
347 return gfx::Rect(); | 340 return gfx::Rect(); |
348 return delegate_->GetAnchorRect(anchor_widget(), | 341 return delegate_->GetAnchorRect(anchor_widget(), |
349 params_.anchor_type, | 342 params_.anchor_type, |
350 params_.anchor_alignment); | 343 params_.anchor_alignment); |
351 } | 344 } |
352 | 345 |
353 bool TrayBubbleView::CanActivate() const { | 346 bool TrayBubbleView::CanActivate() const { |
354 return params_.can_activate; | 347 return params_.can_activate; |
355 } | 348 } |
356 | 349 |
357 // Overridden to create BubbleFrameView and set a custom border. | 350 NonClientFrameView* TrayBubbleView::CreateNonClientFrameView(Widget* widget) { |
358 views::NonClientFrameView* TrayBubbleView::CreateNonClientFrameView( | 351 BubbleFrameView* frame = new BubbleFrameView(margins()); |
359 views::Widget* widget) { | 352 frame->SetBubbleBorder(bubble_border_); |
360 views::BubbleFrameView* bubble_frame_view = | 353 return frame; |
361 new views::BubbleFrameView(margins(), bubble_border_); | |
362 return bubble_frame_view; | |
363 } | 354 } |
364 | 355 |
365 bool TrayBubbleView::WidgetHasHitTestMask() const { | 356 bool TrayBubbleView::WidgetHasHitTestMask() const { |
366 return true; | 357 return true; |
367 } | 358 } |
368 | 359 |
369 void TrayBubbleView::GetWidgetHitTestMask(gfx::Path* mask) const { | 360 void TrayBubbleView::GetWidgetHitTestMask(gfx::Path* mask) const { |
370 DCHECK(mask); | 361 DCHECK(mask); |
371 mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds())); | 362 mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds())); |
372 } | 363 } |
373 | 364 |
374 gfx::Size TrayBubbleView::GetPreferredSize() { | 365 gfx::Size TrayBubbleView::GetPreferredSize() { |
375 gfx::Size size = views::BubbleDelegateView::GetPreferredSize(); | 366 gfx::Size size = BubbleDelegateView::GetPreferredSize(); |
376 int height = size.height(); | 367 int height = size.height(); |
377 if (params_.max_height != 0 && height > params_.max_height) | 368 if (params_.max_height != 0 && height > params_.max_height) |
378 height = params_.max_height; | 369 height = params_.max_height; |
379 return gfx::Size(preferred_width_, height); | 370 return gfx::Size(preferred_width_, height); |
380 } | 371 } |
381 | 372 |
382 gfx::Size TrayBubbleView::GetMaximumSize() { | 373 gfx::Size TrayBubbleView::GetMaximumSize() { |
383 gfx::Size size = GetPreferredSize(); | 374 gfx::Size size = GetPreferredSize(); |
384 size.set_width(params_.max_width); | 375 size.set_width(params_.max_width); |
385 return size; | 376 return size; |
(...skipping 14 matching lines...) Expand all Loading... |
400 state->role = ui::AccessibilityTypes::ROLE_WINDOW; | 391 state->role = ui::AccessibilityTypes::ROLE_WINDOW; |
401 state->name = delegate_->GetAccessibleNameForBubble(); | 392 state->name = delegate_->GetAccessibleNameForBubble(); |
402 } | 393 } |
403 } | 394 } |
404 | 395 |
405 void TrayBubbleView::ChildPreferredSizeChanged(View* child) { | 396 void TrayBubbleView::ChildPreferredSizeChanged(View* child) { |
406 SizeToContents(); | 397 SizeToContents(); |
407 } | 398 } |
408 | 399 |
409 void TrayBubbleView::ViewHierarchyChanged(bool is_add, | 400 void TrayBubbleView::ViewHierarchyChanged(bool is_add, |
410 views::View* parent, | 401 View* parent, |
411 views::View* child) { | 402 View* child) { |
412 if (get_use_acceleration_when_possible() && is_add && child == this) { | 403 if (get_use_acceleration_when_possible() && is_add && child == this) { |
413 parent->SetPaintToLayer(true); | 404 parent->SetPaintToLayer(true); |
414 parent->SetFillsBoundsOpaquely(true); | 405 parent->SetFillsBoundsOpaquely(true); |
415 parent->layer()->SetMasksToBounds(true); | 406 parent->layer()->SetMasksToBounds(true); |
416 } | 407 } |
417 } | 408 } |
418 | 409 |
419 } // namespace views | 410 } // namespace views |
OLD | NEW |