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 "third_party/skia/include/core/SkCanvas.h" | 7 #include "third_party/skia/include/core/SkCanvas.h" |
8 #include "third_party/skia/include/core/SkColor.h" | 8 #include "third_party/skia/include/core/SkColor.h" |
9 #include "third_party/skia/include/core/SkPaint.h" | 9 #include "third_party/skia/include/core/SkPaint.h" |
10 #include "third_party/skia/include/core/SkPath.h" | 10 #include "third_party/skia/include/core/SkPath.h" |
11 #include "third_party/skia/include/effects/SkBlurImageFilter.h" | 11 #include "third_party/skia/include/effects/SkBlurImageFilter.h" |
12 #include "ui/base/accessibility/accessible_view_state.h" | 12 #include "ui/base/accessibility/accessible_view_state.h" |
13 #include "ui/base/events/event.h" | 13 #include "ui/base/events/event.h" |
14 #include "ui/base/l10n/l10n_util.h" | 14 #include "ui/base/l10n/l10n_util.h" |
15 #include "ui/compositor/layer.h" | |
16 #include "ui/compositor/layer_delegate.h" | |
15 #include "ui/gfx/canvas.h" | 17 #include "ui/gfx/canvas.h" |
16 #include "ui/gfx/insets.h" | 18 #include "ui/gfx/insets.h" |
17 #include "ui/gfx/path.h" | 19 #include "ui/gfx/path.h" |
20 #include "ui/gfx/rect.h" | |
18 #include "ui/gfx/skia_util.h" | 21 #include "ui/gfx/skia_util.h" |
19 #include "ui/views/bubble/bubble_frame_view.h" | 22 #include "ui/views/bubble/bubble_frame_view.h" |
20 #include "ui/views/layout/box_layout.h" | 23 #include "ui/views/layout/box_layout.h" |
21 #include "ui/views/widget/widget.h" | 24 #include "ui/views/widget/widget.h" |
22 | 25 |
23 namespace { | 26 namespace { |
24 | 27 |
25 // Inset the arrow a bit from the edge. | 28 // Inset the arrow a bit from the edge. |
26 const int kArrowMinOffset = 20; | 29 const int kArrowMinOffset = 20; |
27 const int kBubbleSpacing = 20; | 30 const int kBubbleSpacing = 20; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
110 } | 113 } |
111 | 114 |
112 private: | 115 private: |
113 views::View* owner_; | 116 views::View* owner_; |
114 views::View* anchor_; | 117 views::View* anchor_; |
115 const int tray_arrow_offset_; | 118 const int tray_arrow_offset_; |
116 | 119 |
117 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); | 120 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBorder); |
118 }; | 121 }; |
119 | 122 |
120 // Custom background for TrayBubbleView. Fills in the top and bottom margins | 123 // This mask layer clips the bubble's content so that it does not overwrite the |
121 // with appropriate background colors without overwriting the rounded corners. | 124 // rounded bubble corners. |
122 class TrayBubbleBackground : public views::Background { | 125 // TODO(miket): This does not work on Windows. Implement layer masking or |
126 // alternate solutions if the TrayBubbleView is needed there in the future. | |
127 class TrayBubbleContentMask : public ui::LayerDelegate { | |
123 public: | 128 public: |
124 explicit TrayBubbleBackground(views::BubbleBorder* border, | 129 TrayBubbleContentMask(int corner_radius) : layer_(ui::LAYER_TEXTURED), |
msw
2012/11/13 17:03:26
nit: I think the line breaking/indents were more c
bartfab (slow)
2012/11/13 17:16:11
Done.
| |
125 SkColor top_color, | 130 corner_radius_(corner_radius) { |
126 SkColor bottom_color) | 131 layer_.set_delegate(this); |
127 : border_(border), | |
128 top_color_(top_color), | |
129 bottom_color_(bottom_color), | |
130 radius_(SkIntToScalar(border->GetBorderCornerRadius() - 1)) { | |
131 } | 132 } |
132 | 133 |
133 SkScalar radius() const { return radius_; } | 134 virtual ~TrayBubbleContentMask() { |
msw
2012/11/13 17:03:26
Our style guide strongly discourages inline virtua
bartfab (slow)
2012/11/13 17:16:11
Done.
| |
135 layer_.set_delegate(NULL); | |
136 } | |
134 | 137 |
135 // Overridden from Background: | 138 ui::Layer& layer() { |
msw
2012/11/13 17:03:26
optional nit: define on one line.
bartfab (slow)
2012/11/13 17:16:11
Done.
| |
136 virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE { | 139 return layer_; |
137 canvas->Save(); | 140 } |
138 | 141 |
139 // Set a clip mask for the bubble's rounded corners. | 142 // Overridden from LayerDelegate: |
140 gfx::Rect bounds(view->GetContentsBounds()); | 143 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { |
141 const int border_thickness(border_->GetBorderThickness()); | |
142 bounds.Inset(-border_thickness, -border_thickness); | |
143 SkPath path; | 144 SkPath path; |
144 path.addRoundRect(gfx::RectToSkRect(bounds), radius_, radius_); | 145 path.addRoundRect(gfx::RectToSkRect(gfx::Rect(layer().bounds().size())), |
145 canvas->ClipPath(path); | 146 corner_radius_, corner_radius_); |
147 SkPaint paint; | |
148 paint.setAlpha(255); | |
149 paint.setStyle(SkPaint::kFill_Style); | |
150 canvas->DrawPath(path, paint); | |
151 } | |
146 | 152 |
147 // Paint the header and footer (assumes the bubble contents fill in their | 153 virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE { |
148 // own backgrounds). | 154 } |
149 SkPaint paint; | |
150 paint.setStyle(SkPaint::kFill_Style); | |
151 | 155 |
152 gfx::Rect top_rect(bounds); | 156 virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE { |
153 top_rect.set_height(radius_); | 157 return base::Closure(); |
154 paint.setColor(top_color_); | |
155 canvas->DrawRect(top_rect, paint); | |
156 | |
157 gfx::Rect bottom_rect(bounds); | |
158 bottom_rect.set_y(bounds.y() + (bounds.height() - radius_)); | |
159 bottom_rect.set_height(radius_); | |
160 paint.setColor(bottom_color_); | |
161 canvas->DrawRect(bottom_rect, paint); | |
162 | |
163 canvas->Restore(); | |
164 } | 158 } |
165 | 159 |
166 private: | 160 private: |
167 views::BubbleBorder* border_; | 161 ui::Layer layer_; |
168 SkColor top_color_; | 162 SkScalar corner_radius_; |
169 SkColor bottom_color_; | |
170 SkScalar radius_; | |
171 | 163 |
172 DISALLOW_COPY_AND_ASSIGN(TrayBubbleBackground); | 164 DISALLOW_COPY_AND_ASSIGN(TrayBubbleContentMask); |
173 }; | 165 }; |
174 | 166 |
175 // Custom layout for the bubble-view. Does the default box-layout if there is | 167 // Custom layout for the bubble-view. Does the default box-layout if there is |
176 // enough height. Otherwise, makes sure the bottom rows are visible. | 168 // enough height. Otherwise, makes sure the bottom rows are visible. |
177 class BottomAlignedBoxLayout : public views::BoxLayout { | 169 class BottomAlignedBoxLayout : public views::BoxLayout { |
178 public: | 170 public: |
179 explicit BottomAlignedBoxLayout(TrayBubbleView* bubble_view) | 171 explicit BottomAlignedBoxLayout(TrayBubbleView* bubble_view) |
180 : views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0), | 172 : views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0), |
181 bubble_view_(bubble_view) { | 173 bubble_view_(bubble_view) { |
182 } | 174 } |
(...skipping 22 matching lines...) Expand all Loading... | |
205 } | 197 } |
206 | 198 |
207 TrayBubbleView* bubble_view_; | 199 TrayBubbleView* bubble_view_; |
208 | 200 |
209 DISALLOW_COPY_AND_ASSIGN(BottomAlignedBoxLayout); | 201 DISALLOW_COPY_AND_ASSIGN(BottomAlignedBoxLayout); |
210 }; | 202 }; |
211 | 203 |
212 } // namespace internal | 204 } // namespace internal |
213 | 205 |
214 using internal::TrayBubbleBorder; | 206 using internal::TrayBubbleBorder; |
215 using internal::TrayBubbleBackground; | 207 using internal::TrayBubbleContentMask; |
216 using internal::BottomAlignedBoxLayout; | 208 using internal::BottomAlignedBoxLayout; |
217 | 209 |
218 // static | 210 // static |
219 const int TrayBubbleView::InitParams::kArrowDefaultOffset = -1; | 211 const int TrayBubbleView::InitParams::kArrowDefaultOffset = -1; |
220 | 212 |
221 TrayBubbleView::InitParams::InitParams(AnchorType anchor_type, | 213 TrayBubbleView::InitParams::InitParams(AnchorType anchor_type, |
222 AnchorAlignment anchor_alignment, | 214 AnchorAlignment anchor_alignment, |
223 int bubble_width) | 215 int bubble_width) |
224 : anchor_type(anchor_type), | 216 : anchor_type(anchor_type), |
225 anchor_alignment(anchor_alignment), | 217 anchor_alignment(anchor_alignment), |
226 bubble_width(bubble_width), | 218 bubble_width(bubble_width), |
227 max_height(0), | 219 max_height(0), |
228 can_activate(false), | 220 can_activate(false), |
229 close_on_deactivate(true), | 221 close_on_deactivate(true), |
230 top_color(SK_ColorBLACK), | |
231 arrow_color(SK_ColorBLACK), | 222 arrow_color(SK_ColorBLACK), |
232 arrow_location(views::BubbleBorder::NONE), | 223 arrow_location(views::BubbleBorder::NONE), |
233 arrow_offset(kArrowDefaultOffset), | 224 arrow_offset(kArrowDefaultOffset), |
234 shadow(views::BubbleBorder::BIG_SHADOW) { | 225 shadow(views::BubbleBorder::BIG_SHADOW) { |
235 } | 226 } |
236 | 227 |
237 // static | 228 // static |
238 TrayBubbleView* TrayBubbleView::Create(gfx::NativeView parent_window, | 229 TrayBubbleView* TrayBubbleView::Create(gfx::NativeView parent_window, |
239 views::View* anchor, | 230 views::View* anchor, |
240 Delegate* delegate, | 231 Delegate* delegate, |
(...skipping 17 matching lines...) Expand all Loading... | |
258 } | 249 } |
259 | 250 |
260 TrayBubbleView::TrayBubbleView(gfx::NativeView parent_window, | 251 TrayBubbleView::TrayBubbleView(gfx::NativeView parent_window, |
261 views::View* anchor, | 252 views::View* anchor, |
262 Delegate* delegate, | 253 Delegate* delegate, |
263 const InitParams& init_params) | 254 const InitParams& init_params) |
264 : views::BubbleDelegateView(anchor, init_params.arrow_location), | 255 : views::BubbleDelegateView(anchor, init_params.arrow_location), |
265 params_(init_params), | 256 params_(init_params), |
266 delegate_(delegate), | 257 delegate_(delegate), |
267 bubble_border_(NULL), | 258 bubble_border_(NULL), |
268 bubble_background_(NULL), | |
269 is_gesture_dragging_(false) { | 259 is_gesture_dragging_(false) { |
270 set_parent_window(parent_window); | 260 set_parent_window(parent_window); |
271 set_notify_enter_exit_on_child(true); | 261 set_notify_enter_exit_on_child(true); |
272 set_close_on_deactivate(init_params.close_on_deactivate); | 262 set_close_on_deactivate(init_params.close_on_deactivate); |
263 set_margins(gfx::Insets()); | |
273 SetPaintToLayer(true); | 264 SetPaintToLayer(true); |
274 SetFillsBoundsOpaquely(true); | 265 SetFillsBoundsOpaquely(true); |
275 | 266 |
276 bubble_border_ = new TrayBubbleBorder(this, anchor_view(), params_); | 267 bubble_border_ = new TrayBubbleBorder(this, anchor_view(), params_); |
277 | 268 |
278 bubble_background_ = new TrayBubbleBackground( | 269 bubble_content_mask_.reset( |
279 bubble_border_, init_params.top_color, init_params.arrow_color); | 270 new TrayBubbleContentMask(bubble_border_->GetBorderCornerRadius() - 1)); |
280 | |
281 // Inset the view on the top and bottom by the corner radius to avoid drawing | |
282 // over the the bubble corners. | |
283 const int radius = bubble_background_->radius(); | |
284 set_margins(gfx::Insets(radius, 0, radius, 0)); | |
285 } | 271 } |
286 | 272 |
287 TrayBubbleView::~TrayBubbleView() { | 273 TrayBubbleView::~TrayBubbleView() { |
288 // Inform host items (models) that their views are being destroyed. | 274 // Inform host items (models) that their views are being destroyed. |
289 if (delegate_) | 275 if (delegate_) |
290 delegate_->BubbleViewDestroyed(); | 276 delegate_->BubbleViewDestroyed(); |
291 } | 277 } |
292 | 278 |
293 void TrayBubbleView::InitializeAndShowBubble() { | 279 void TrayBubbleView::InitializeAndShowBubble() { |
294 // Must occur after call to BubbleDelegateView::CreateBubble(). | 280 // Must occur after call to BubbleDelegateView::CreateBubble(). |
295 SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | 281 SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
296 bubble_border_->UpdateArrowOffset(); | 282 bubble_border_->UpdateArrowOffset(); |
297 | 283 |
284 layer()->parent()->SetMaskLayer(&bubble_content_mask_->layer()); | |
285 | |
298 Show(); | 286 Show(); |
299 UpdateBubble(); | 287 UpdateBubble(); |
300 } | 288 } |
301 | 289 |
302 void TrayBubbleView::UpdateBubble() { | 290 void TrayBubbleView::UpdateBubble() { |
303 SizeToContents(); | 291 SizeToContents(); |
292 bubble_content_mask_->layer().SetBounds(layer()->bounds()); | |
304 GetWidget()->GetRootView()->SchedulePaint(); | 293 GetWidget()->GetRootView()->SchedulePaint(); |
305 } | 294 } |
306 | 295 |
307 void TrayBubbleView::SetMaxHeight(int height) { | 296 void TrayBubbleView::SetMaxHeight(int height) { |
308 params_.max_height = height; | 297 params_.max_height = height; |
309 if (GetWidget()) | 298 if (GetWidget()) |
310 SizeToContents(); | 299 SizeToContents(); |
311 } | 300 } |
312 | 301 |
313 void TrayBubbleView::SetPaintArrow(bool paint_arrow) { | 302 void TrayBubbleView::SetPaintArrow(bool paint_arrow) { |
(...skipping 15 matching lines...) Expand all Loading... | |
329 return gfx::Rect(); | 318 return gfx::Rect(); |
330 return delegate_->GetAnchorRect(anchor_widget(), | 319 return delegate_->GetAnchorRect(anchor_widget(), |
331 params_.anchor_type, | 320 params_.anchor_type, |
332 params_.anchor_alignment); | 321 params_.anchor_alignment); |
333 } | 322 } |
334 | 323 |
335 bool TrayBubbleView::CanActivate() const { | 324 bool TrayBubbleView::CanActivate() const { |
336 return params_.can_activate; | 325 return params_.can_activate; |
337 } | 326 } |
338 | 327 |
339 // Overridden to create BubbleFrameView and set a custom border and background. | 328 // Overridden to create BubbleFrameView and set a custom border. |
340 views::NonClientFrameView* TrayBubbleView::CreateNonClientFrameView( | 329 views::NonClientFrameView* TrayBubbleView::CreateNonClientFrameView( |
341 views::Widget* widget) { | 330 views::Widget* widget) { |
342 views::BubbleFrameView* bubble_frame_view = | 331 views::BubbleFrameView* bubble_frame_view = |
343 new views::BubbleFrameView(margins(), bubble_border_); | 332 new views::BubbleFrameView(margins(), bubble_border_); |
344 bubble_frame_view->set_background(bubble_background_); | |
345 return bubble_frame_view; | 333 return bubble_frame_view; |
346 } | 334 } |
347 | 335 |
348 bool TrayBubbleView::WidgetHasHitTestMask() const { | 336 bool TrayBubbleView::WidgetHasHitTestMask() const { |
349 return true; | 337 return true; |
350 } | 338 } |
351 | 339 |
352 void TrayBubbleView::GetWidgetHitTestMask(gfx::Path* mask) const { | 340 void TrayBubbleView::GetWidgetHitTestMask(gfx::Path* mask) const { |
353 DCHECK(mask); | 341 DCHECK(mask); |
354 mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds())); | 342 mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds())); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 views::View* parent, | 375 views::View* parent, |
388 views::View* child) { | 376 views::View* child) { |
389 if (is_add && child == this) { | 377 if (is_add && child == this) { |
390 parent->SetPaintToLayer(true); | 378 parent->SetPaintToLayer(true); |
391 parent->SetFillsBoundsOpaquely(true); | 379 parent->SetFillsBoundsOpaquely(true); |
392 parent->layer()->SetMasksToBounds(true); | 380 parent->layer()->SetMasksToBounds(true); |
393 } | 381 } |
394 } | 382 } |
395 | 383 |
396 } // namespace views | 384 } // namespace views |
OLD | NEW |