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 25 matching lines...) Expand all Loading... |
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 views::BubbleBorder { |
43 public: | 43 public: |
44 TrayBubbleBorder(views::View* owner, | 44 TrayBubbleBorder(views::View* owner, |
45 views::View* anchor, | 45 views::View* anchor, |
| 46 gfx::Point anchor_point, |
46 TrayBubbleView::InitParams params) | 47 TrayBubbleView::InitParams params) |
47 : views::BubbleBorder(params.arrow_location, params.shadow), | 48 : views::BubbleBorder(params.arrow_location, params.shadow), |
48 owner_(owner), | 49 owner_(owner), |
49 anchor_(anchor), | 50 anchor_(anchor), |
| 51 anchor_point_(anchor_point.x(), anchor_point.y()), |
50 tray_arrow_offset_(params.arrow_offset) { | 52 tray_arrow_offset_(params.arrow_offset) { |
51 set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | 53 set_alignment(params.arrow_alignment); |
52 set_background_color(params.arrow_color); | 54 set_background_color(params.arrow_color); |
53 } | 55 } |
54 | 56 |
55 virtual ~TrayBubbleBorder() {} | 57 virtual ~TrayBubbleBorder() {} |
56 | 58 |
57 // Overridden from views::BubbleBorder. | 59 // Overridden from views::BubbleBorder. |
58 // Override views::BubbleBorder to set the bubble on top of the anchor when | 60 // Override views::BubbleBorder to set the bubble on top of the anchor when |
59 // it has no arrow. | 61 // it has no arrow. |
60 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, | 62 virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, |
61 const gfx::Size& contents_size) const OVERRIDE { | 63 const gfx::Size& contents_size) const OVERRIDE { |
62 if (arrow_location() != NONE) { | 64 if (has_arrow(arrow_location())) { |
63 return views::BubbleBorder::GetBounds(position_relative_to, | 65 return views::BubbleBorder::GetBounds(position_relative_to, |
64 contents_size); | 66 contents_size); |
65 } | 67 } |
66 | 68 |
67 gfx::Size border_size(contents_size); | 69 gfx::Size border_size(contents_size); |
68 gfx::Insets insets = GetInsets(); | 70 gfx::Insets insets = GetInsets(); |
69 border_size.Enlarge(insets.width(), insets.height()); | 71 border_size.Enlarge(insets.width(), insets.height()); |
70 | 72 |
71 const int x = position_relative_to.x() + | 73 const int x = position_relative_to.x() + |
72 position_relative_to.width() / 2 - border_size.width() / 2; | 74 position_relative_to.width() / 2 - border_size.width() / 2; |
73 // Position the bubble on top of the anchor. | 75 // Position the bubble on top of the anchor. |
74 const int y = position_relative_to.y() - border_size.height() | 76 const int y = position_relative_to.y() - border_size.height() |
75 + insets.height() - kBubbleSpacing; | 77 + insets.height() - kBubbleSpacing; |
76 return gfx::Rect(x, y, border_size.width(), border_size.height()); | 78 return gfx::Rect(x, y, border_size.width(), border_size.height()); |
77 } | 79 } |
78 | 80 |
| 81 // Anchor point is in screen coordinates. |
79 void UpdateArrowOffset() { | 82 void UpdateArrowOffset() { |
| 83 if (!has_arrow(arrow_location())) { |
| 84 return; |
| 85 } |
| 86 |
80 int arrow_offset = 0; | 87 int arrow_offset = 0; |
81 if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT || | 88 gfx::Point pt(0, 0); |
82 arrow_location() == views::BubbleBorder::BOTTOM_LEFT) { | 89 if (tray_arrow_offset_ == TrayBubbleView::InitParams::kArrowDefaultOffset) { |
83 // Note: tray_arrow_offset_ is relative to the anchor widget. | 90 set_arrow_offset(kArrowMinOffset); |
84 if (tray_arrow_offset_ == | 91 return; |
85 TrayBubbleView::InitParams::kArrowDefaultOffset) { | 92 } |
86 arrow_offset = kArrowMinOffset; | 93 // Note: tray_arrow_offset_ is relative to the anchor widget. |
87 } else { | 94 if (is_arrow_on_horizontal(arrow_location())) |
88 const int width = owner_->GetWidget()->GetContentsView()->width(); | 95 pt.set_x(tray_arrow_offset_); |
89 gfx::Point pt(tray_arrow_offset_, 0); | 96 else |
90 views::View::ConvertPointToScreen( | 97 pt.set_y(tray_arrow_offset_); |
91 anchor_->GetWidget()->GetRootView(), &pt); | 98 |
92 views::View::ConvertPointFromScreen( | 99 if (anchor_) { |
93 owner_->GetWidget()->GetRootView(), &pt); | 100 views::View::ConvertPointToScreen( |
94 arrow_offset = pt.x(); | 101 anchor_->GetWidget()->GetRootView(), &pt); |
95 if (arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) | |
96 arrow_offset = width - arrow_offset; | |
97 arrow_offset = std::max(arrow_offset, kArrowMinOffset); | |
98 } | |
99 } else { | 102 } else { |
100 if (tray_arrow_offset_ == | 103 pt.Offset(anchor_point_.x(), anchor_point_.y()); |
101 TrayBubbleView::InitParams::kArrowDefaultOffset) { | |
102 arrow_offset = kArrowMinOffset; | |
103 } else { | |
104 gfx::Point pt(0, tray_arrow_offset_); | |
105 views::View::ConvertPointToScreen( | |
106 anchor_->GetWidget()->GetRootView(), &pt); | |
107 views::View::ConvertPointFromScreen( | |
108 owner_->GetWidget()->GetRootView(), &pt); | |
109 arrow_offset = pt.y(); | |
110 arrow_offset = std::max(arrow_offset, kArrowMinOffset); | |
111 } | |
112 } | 104 } |
| 105 |
| 106 views::View::ConvertPointFromScreen( |
| 107 owner_->GetWidget()->GetRootView(), &pt); |
| 108 const int width = owner_->GetWidget()->GetContentsView()->width(); |
| 109 |
| 110 if (is_arrow_on_horizontal(arrow_location())) { |
| 111 arrow_offset = pt.x(); |
| 112 if (!is_arrow_on_left(arrow_location())) |
| 113 arrow_offset = width - arrow_offset; |
| 114 } else { |
| 115 arrow_offset = pt.y(); |
| 116 } |
| 117 |
| 118 arrow_offset = std::max(arrow_offset, kArrowMinOffset); |
113 set_arrow_offset(arrow_offset); | 119 set_arrow_offset(arrow_offset); |
114 } | 120 } |
115 | 121 |
116 private: | 122 private: |
117 views::View* owner_; | 123 views::View* owner_; |
118 views::View* anchor_; | 124 views::View* anchor_; |
| 125 gfx::Point anchor_point_; |
119 const int tray_arrow_offset_; | 126 const int tray_arrow_offset_; |
120 | 127 |
121 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); | 128 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); |
122 }; | 129 }; |
123 | 130 |
124 // This mask layer clips the bubble's content so that it does not overwrite the | 131 // This mask layer clips the bubble's content so that it does not overwrite the |
125 // rounded bubble corners. | 132 // rounded bubble corners. |
126 // TODO(miket): This does not work on Windows. Implement layer masking or | 133 // TODO(miket): This does not work on Windows. Implement layer masking or |
127 // alternate solutions if the TrayBubbleView is needed there in the future. | 134 // alternate solutions if the TrayBubbleView is needed there in the future. |
128 class TrayBubbleContentMask : public ui::LayerDelegate { | 135 class TrayBubbleContentMask : public ui::LayerDelegate { |
(...skipping 11 matching lines...) Expand all Loading... |
140 private: | 147 private: |
141 ui::Layer layer_; | 148 ui::Layer layer_; |
142 SkScalar corner_radius_; | 149 SkScalar corner_radius_; |
143 | 150 |
144 DISALLOW_COPY_AND_ASSIGN(TrayBubbleContentMask); | 151 DISALLOW_COPY_AND_ASSIGN(TrayBubbleContentMask); |
145 }; | 152 }; |
146 | 153 |
147 TrayBubbleContentMask::TrayBubbleContentMask(int corner_radius) | 154 TrayBubbleContentMask::TrayBubbleContentMask(int corner_radius) |
148 : layer_(ui::LAYER_TEXTURED), | 155 : layer_(ui::LAYER_TEXTURED), |
149 corner_radius_(corner_radius) { | 156 corner_radius_(corner_radius) { |
| 157 #ifdef USE_AURA |
150 layer_.set_delegate(this); | 158 layer_.set_delegate(this); |
| 159 #endif |
151 } | 160 } |
152 | 161 |
153 TrayBubbleContentMask::~TrayBubbleContentMask() { | 162 TrayBubbleContentMask::~TrayBubbleContentMask() { |
| 163 #ifdef USE_AURA |
154 layer_.set_delegate(NULL); | 164 layer_.set_delegate(NULL); |
| 165 #endif |
155 } | 166 } |
156 | 167 |
157 void TrayBubbleContentMask::OnPaintLayer(gfx::Canvas* canvas) { | 168 void TrayBubbleContentMask::OnPaintLayer(gfx::Canvas* canvas) { |
158 SkPath path; | 169 SkPath path; |
159 path.addRoundRect(gfx::RectToSkRect(gfx::Rect(layer()->bounds().size())), | 170 path.addRoundRect(gfx::RectToSkRect(gfx::Rect(layer()->bounds().size())), |
160 corner_radius_, corner_radius_); | 171 corner_radius_, corner_radius_); |
161 SkPaint paint; | 172 SkPaint paint; |
162 paint.setAlpha(255); | 173 paint.setAlpha(255); |
163 paint.setStyle(SkPaint::kFill_Style); | 174 paint.setStyle(SkPaint::kFill_Style); |
164 canvas->DrawPath(path, paint); | 175 canvas->DrawPath(path, paint); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 : anchor_type(anchor_type), | 237 : anchor_type(anchor_type), |
227 anchor_alignment(anchor_alignment), | 238 anchor_alignment(anchor_alignment), |
228 min_width(min_width), | 239 min_width(min_width), |
229 max_width(max_width), | 240 max_width(max_width), |
230 max_height(0), | 241 max_height(0), |
231 can_activate(false), | 242 can_activate(false), |
232 close_on_deactivate(true), | 243 close_on_deactivate(true), |
233 arrow_color(SK_ColorBLACK), | 244 arrow_color(SK_ColorBLACK), |
234 arrow_location(views::BubbleBorder::NONE), | 245 arrow_location(views::BubbleBorder::NONE), |
235 arrow_offset(kArrowDefaultOffset), | 246 arrow_offset(kArrowDefaultOffset), |
236 shadow(views::BubbleBorder::BIG_SHADOW) { | 247 shadow(views::BubbleBorder::BIG_SHADOW), |
| 248 arrow_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE) { |
237 } | 249 } |
238 | 250 |
239 // static | 251 // static |
240 TrayBubbleView* TrayBubbleView::Create(gfx::NativeView parent_window, | 252 TrayBubbleView* TrayBubbleView::Create(gfx::NativeView parent_window, |
241 views::View* anchor, | 253 views::View* anchor, |
242 Delegate* delegate, | 254 Delegate* delegate, |
243 InitParams* init_params) { | 255 InitParams* init_params) { |
244 // Set arrow_location here so that it can be passed correctly to the | 256 // Set arrow_location here so that it can be passed correctly to the |
245 // BubbleView constructor. | 257 // BubbleView constructor. |
246 if (init_params->anchor_type == ANCHOR_TYPE_TRAY) { | 258 if (init_params->anchor_type == ANCHOR_TYPE_TRAY) { |
(...skipping 19 matching lines...) Expand all Loading... |
266 : views::BubbleDelegateView(anchor, init_params.arrow_location), | 278 : views::BubbleDelegateView(anchor, init_params.arrow_location), |
267 params_(init_params), | 279 params_(init_params), |
268 delegate_(delegate), | 280 delegate_(delegate), |
269 preferred_width_(init_params.min_width), | 281 preferred_width_(init_params.min_width), |
270 bubble_border_(NULL), | 282 bubble_border_(NULL), |
271 is_gesture_dragging_(false) { | 283 is_gesture_dragging_(false) { |
272 set_parent_window(parent_window); | 284 set_parent_window(parent_window); |
273 set_notify_enter_exit_on_child(true); | 285 set_notify_enter_exit_on_child(true); |
274 set_close_on_deactivate(init_params.close_on_deactivate); | 286 set_close_on_deactivate(init_params.close_on_deactivate); |
275 set_margins(gfx::Insets()); | 287 set_margins(gfx::Insets()); |
| 288 bubble_border_ = new TrayBubbleBorder( |
| 289 this, |
| 290 anchor_view(), |
| 291 gfx::Point(init_params.anchor_point_x, init_params.anchor_point_y), |
| 292 params_); |
| 293 |
| 294 #ifdef USE_AURA |
276 SetPaintToLayer(true); | 295 SetPaintToLayer(true); |
277 SetFillsBoundsOpaquely(true); | 296 SetFillsBoundsOpaquely(true); |
278 | 297 |
279 bubble_border_ = new TrayBubbleBorder(this, anchor_view(), params_); | |
280 | |
281 bubble_content_mask_.reset( | 298 bubble_content_mask_.reset( |
282 new TrayBubbleContentMask(bubble_border_->GetBorderCornerRadius() - 1)); | 299 new TrayBubbleContentMask(bubble_border_->GetBorderCornerRadius() - 1)); |
| 300 #endif //USE_AURA |
283 } | 301 } |
284 | 302 |
285 TrayBubbleView::~TrayBubbleView() { | 303 TrayBubbleView::~TrayBubbleView() { |
286 // Inform host items (models) that their views are being destroyed. | 304 // Inform host items (models) that their views are being destroyed. |
287 if (delegate_) | 305 if (delegate_) |
288 delegate_->BubbleViewDestroyed(); | 306 delegate_->BubbleViewDestroyed(); |
289 } | 307 } |
290 | 308 |
291 void TrayBubbleView::InitializeAndShowBubble() { | 309 void TrayBubbleView::InitializeAndShowBubble() { |
292 // Must occur after call to BubbleDelegateView::CreateBubble(). | 310 // Must occur after call to BubbleDelegateView::CreateBubble(). |
293 SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | 311 SetAlignment(params_.arrow_alignment); |
294 bubble_border_->UpdateArrowOffset(); | 312 bubble_border_->UpdateArrowOffset(); |
295 | 313 |
| 314 #ifdef USE_AURA |
296 layer()->parent()->SetMaskLayer(bubble_content_mask_->layer()); | 315 layer()->parent()->SetMaskLayer(bubble_content_mask_->layer()); |
| 316 #endif // USE_AURA |
297 | 317 |
298 Show(); | 318 Show(); |
299 UpdateBubble(); | 319 UpdateBubble(); |
300 } | 320 } |
301 | 321 |
302 void TrayBubbleView::UpdateBubble() { | 322 void TrayBubbleView::UpdateBubble() { |
303 SizeToContents(); | 323 SizeToContents(); |
| 324 #ifdef USE_AURA |
304 bubble_content_mask_->layer()->SetBounds(layer()->bounds()); | 325 bubble_content_mask_->layer()->SetBounds(layer()->bounds()); |
| 326 #endif // USE_AURA |
305 GetWidget()->GetRootView()->SchedulePaint(); | 327 GetWidget()->GetRootView()->SchedulePaint(); |
306 } | 328 } |
307 | 329 |
308 void TrayBubbleView::SetMaxHeight(int height) { | 330 void TrayBubbleView::SetMaxHeight(int height) { |
309 params_.max_height = height; | 331 params_.max_height = height; |
310 if (GetWidget()) | 332 if (GetWidget()) |
311 SizeToContents(); | 333 SizeToContents(); |
312 } | 334 } |
313 | 335 |
314 void TrayBubbleView::SetWidth(int width) { | 336 void TrayBubbleView::SetWidth(int width) { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 } | 416 } |
395 } | 417 } |
396 | 418 |
397 void TrayBubbleView::ChildPreferredSizeChanged(View* child) { | 419 void TrayBubbleView::ChildPreferredSizeChanged(View* child) { |
398 SizeToContents(); | 420 SizeToContents(); |
399 } | 421 } |
400 | 422 |
401 void TrayBubbleView::ViewHierarchyChanged(bool is_add, | 423 void TrayBubbleView::ViewHierarchyChanged(bool is_add, |
402 views::View* parent, | 424 views::View* parent, |
403 views::View* child) { | 425 views::View* child) { |
| 426 #ifdef USE_AURA |
404 if (is_add && child == this) { | 427 if (is_add && child == this) { |
405 parent->SetPaintToLayer(true); | 428 parent->SetPaintToLayer(true); |
406 parent->SetFillsBoundsOpaquely(true); | 429 parent->SetFillsBoundsOpaquely(true); |
407 parent->layer()->SetMasksToBounds(true); | 430 parent->layer()->SetMasksToBounds(true); |
408 } | 431 } |
| 432 #endif // USE_AURA |
409 } | 433 } |
410 | 434 |
411 } // namespace views | 435 } // namespace views |
OLD | NEW |