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/message_center/message_center_bubble.h" | 5 #include "ui/message_center/message_center_bubble.h" |
6 | 6 |
7 #include "grit/ui_strings.h" | 7 #include "grit/ui_strings.h" |
8 #include "third_party/skia/include/core/SkPaint.h" | 8 #include "third_party/skia/include/core/SkPaint.h" |
9 #include "ui/base/l10n/l10n_util.h" | 9 #include "ui/base/l10n/l10n_util.h" |
10 #include "ui/base/resource/resource_bundle.h" | 10 #include "ui/base/resource/resource_bundle.h" |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
229 else | 229 else |
230 NOTREACHED(); | 230 NOTREACHED(); |
231 } | 231 } |
232 | 232 |
233 views::Label* notification_label_; | 233 views::Label* notification_label_; |
234 views::Button* settings_button_; | 234 views::Button* settings_button_; |
235 | 235 |
236 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView2); | 236 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView2); |
237 }; | 237 }; |
238 | 238 |
239 // A custom scroll-view that has a specified size. | 239 // A custom scroll view whose height has a minimum and maximum value and whose |
240 class FixedSizedScrollView : public views::ScrollView { | 240 // scroll bar disappears when not needed. |
241 class BoundedScrollView : public views::ScrollView { | |
241 public: | 242 public: |
242 FixedSizedScrollView() { | 243 BoundedScrollView(int min_height, int max_height) |
244 : min_height_(min_height), | |
245 max_height_(max_height) { | |
243 set_focusable(true); | 246 set_focusable(true); |
244 set_notify_enter_exit_on_child(true); | 247 set_notify_enter_exit_on_child(true); |
245 if (IsRichNotificationEnabled()) { | 248 if (IsRichNotificationEnabled()) { |
246 set_background(views::Background::CreateSolidBackground( | 249 set_background(views::Background::CreateSolidBackground( |
247 kMessageCenterBackgroundColor)); | 250 kMessageCenterBackgroundColor)); |
248 } | 251 } |
249 } | 252 } |
250 | 253 |
251 virtual ~FixedSizedScrollView() {} | 254 virtual ~BoundedScrollView() {} |
252 | |
253 void SetFixedSize(const gfx::Size& size) { | |
254 if (fixed_size_ == size) | |
255 return; | |
256 fixed_size_ = size; | |
257 PreferredSizeChanged(); | |
258 } | |
259 | 255 |
260 // views::View overrides. | 256 // views::View overrides. |
261 virtual gfx::Size GetPreferredSize() OVERRIDE { | 257 virtual gfx::Size GetPreferredSize() OVERRIDE { |
262 gfx::Size size = fixed_size_.IsEmpty() ? | 258 gfx::Size size = contents()->GetPreferredSize(); |
263 contents()->GetPreferredSize() : fixed_size_; | 259 size.ClampToMin(gfx::Size(size.width(), min_height_)); |
260 size.ClampToMax(gfx::Size(size.width(), max_height_)); | |
264 gfx::Insets insets = GetInsets(); | 261 gfx::Insets insets = GetInsets(); |
265 size.Enlarge(insets.width(), insets.height()); | 262 size.Enlarge(insets.width(), insets.height()); |
266 return size; | 263 return size; |
267 } | 264 } |
268 | 265 |
269 virtual void Layout() OVERRIDE { | 266 virtual void Layout() OVERRIDE { |
270 gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize()); | 267 // Lay out the view as if it will have a scroll bar. |
271 bounds.set_width(std::max(0, width() - GetScrollBarWidth())); | 268 gfx::Rect content_bounds = gfx::Rect(contents()->GetPreferredSize()); |
272 contents()->SetBoundsRect(bounds); | 269 content_bounds.set_width(std::max(0, width() - GetScrollBarWidth())); |
270 contents()->SetBoundsRect(content_bounds); | |
271 views::ScrollView::Layout(); | |
273 | 272 |
274 views::ScrollView::Layout(); | 273 // But use the scroll bar space if no scroll bar is needed. |
275 if (!vertical_scroll_bar()->visible()) { | 274 if (!vertical_scroll_bar()->visible()) { |
276 gfx::Rect bounds = contents()->bounds(); | 275 content_bounds = contents()->bounds(); |
277 bounds.set_width(bounds.width() + GetScrollBarWidth()); | 276 content_bounds.set_width(content_bounds.width() + GetScrollBarWidth()); |
278 contents()->SetBoundsRect(bounds); | 277 contents()->SetBoundsRect(content_bounds); |
279 } | 278 } |
280 } | 279 } |
281 | 280 |
282 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE { | 281 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE { |
283 gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize()); | 282 // Make sure any content resizing takes into account the scroll bar. |
284 bounds.set_width(std::max(0, width() - GetScrollBarWidth())); | 283 gfx::Rect content_bounds = gfx::Rect(contents()->GetPreferredSize()); |
285 contents()->SetBoundsRect(bounds); | 284 content_bounds.set_width(std::max(0, width() - GetScrollBarWidth())); |
285 contents()->SetBoundsRect(content_bounds); | |
286 } | 286 } |
287 | 287 |
288 private: | 288 private: |
289 gfx::Size fixed_size_; | 289 int min_height_; |
290 int max_height_; | |
290 | 291 |
291 DISALLOW_COPY_AND_ASSIGN(FixedSizedScrollView); | 292 DISALLOW_COPY_AND_ASSIGN(BoundedScrollView); |
292 }; | 293 }; |
293 | 294 |
294 // Container for the messages. | 295 // Container for the messages. |
295 class ScrollContentView : public views::View { | 296 class MessagesView : public views::View { |
Jun Mukai
2013/02/26 02:23:30
I think it's too hard to distinguish this from mes
dharcourt
2013/02/26 03:23:30
Good point. What would you think of MessageListVie
| |
296 public: | 297 public: |
297 ScrollContentView() { | 298 MessagesView(views::View *message_center_view) |
299 : message_center_view_(message_center_view) { | |
298 if (IsRichNotificationEnabled()) { | 300 if (IsRichNotificationEnabled()) { |
299 // Set the margin to 0 for the layout. BoxLayout assumes the same margin | 301 // Set the margin to 0 for the layout. BoxLayout assumes the same margin |
300 // for top and bottom, but the bottom margin here should be smaller | 302 // for top and bottom, but the bottom margin here should be smaller |
301 // because of the shadow of message view. Use an empty border instead | 303 // because of the shadow of message view. Use an empty border instead |
302 // to provide this margin. | 304 // to provide this margin. |
303 gfx::Insets shadow_insets = GetItemShadowInsets(); | 305 gfx::Insets shadow_insets = GetItemShadowInsets(); |
304 SetLayoutManager( | 306 SetLayoutManager( |
305 new views::BoxLayout(views::BoxLayout::kVertical, | 307 new views::BoxLayout(views::BoxLayout::kVertical, |
306 0, | 308 0, |
307 0, | 309 0, |
308 kMarginBetweenItems - shadow_insets.bottom())); | 310 kMarginBetweenItems - shadow_insets.bottom())); |
309 set_background(views::Background::CreateSolidBackground( | 311 set_background(views::Background::CreateSolidBackground( |
310 kMessageCenterBackgroundColor)); | 312 kMessageCenterBackgroundColor)); |
311 set_border(views::Border::CreateEmptyBorder( | 313 set_border(views::Border::CreateEmptyBorder( |
312 kMarginBetweenItems - shadow_insets.top(), /* top */ | 314 kMarginBetweenItems - shadow_insets.top(), /* top */ |
313 kMarginBetweenItems - shadow_insets.left(), /* left */ | 315 kMarginBetweenItems - shadow_insets.left(), /* left */ |
314 0, /* bottom */ | 316 0, /* bottom */ |
315 kMarginBetweenItems - shadow_insets.right() /* right */ )); | 317 kMarginBetweenItems - shadow_insets.right() /* right */ )); |
316 } else { | 318 } else { |
317 views::BoxLayout* layout = | 319 views::BoxLayout* layout = |
318 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1); | 320 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1); |
319 layout->set_spread_blank_space(true); | 321 layout->set_spread_blank_space(true); |
320 SetLayoutManager(layout); | 322 SetLayoutManager(layout); |
321 } | 323 } |
322 } | 324 } |
323 | 325 |
324 virtual ~ScrollContentView() { | 326 virtual ~MessagesView() { |
325 } | 327 } |
326 | 328 |
327 virtual gfx::Size GetPreferredSize() OVERRIDE { | 329 protected: |
328 if (!preferred_size_.IsEmpty()) | 330 // views::View overrides. |
329 return preferred_size_; | 331 virtual void ChildPreferredSizeChanged(views::View* child) OVERRIDE { |
330 return views::View::GetPreferredSize(); | 332 // Since the parent of this view is a Viewport and since Viewports ignore |
333 // ChildPreferredSizeChanged() calls, ask the MessageCenterView directly | |
334 // to update its layout for the preferred size change. | |
335 message_center_view_->Layout(); | |
331 } | 336 } |
332 | 337 |
333 void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; } | 338 private: |
339 views::View *message_center_view_; | |
334 | 340 |
335 private: | 341 DISALLOW_COPY_AND_ASSIGN(MessagesView); |
336 gfx::Size preferred_size_; | |
337 DISALLOW_COPY_AND_ASSIGN(ScrollContentView); | |
338 }; | 342 }; |
339 | 343 |
340 // A border to provide the shadow for each card. | 344 // A border to provide the shadow for each card. |
341 // Current shadow should look like css box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) | 345 // Current shadow should look like css box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) |
342 class MessageViewShadowBorder : public views::Border { | 346 class MessageViewShadowBorder : public views::Border { |
343 public: | 347 public: |
344 MessageViewShadowBorder() : views::Border() {} | 348 MessageViewShadowBorder() : views::Border() {} |
345 virtual ~MessageViewShadowBorder() {} | 349 virtual ~MessageViewShadowBorder() {} |
346 | 350 |
347 protected: | 351 protected: |
(...skipping 13 matching lines...) Expand all Loading... | |
361 canvas->DrawRect(bounds, paint); | 365 canvas->DrawRect(bounds, paint); |
362 } | 366 } |
363 | 367 |
364 virtual gfx::Insets GetInsets() const OVERRIDE { | 368 virtual gfx::Insets GetInsets() const OVERRIDE { |
365 return GetItemShadowInsets(); | 369 return GetItemShadowInsets(); |
366 } | 370 } |
367 }; | 371 }; |
368 | 372 |
369 } // namespace | 373 } // namespace |
370 | 374 |
371 // Message Center contents. | 375 // View that displays the whole message center. |
372 class MessageCenterContentsView : public views::View { | 376 class MessageCenterView : public views::View { |
373 public: | 377 public: |
374 explicit MessageCenterContentsView(MessageCenterBubble* bubble, | 378 explicit MessageCenterView(MessageCenterBubble* bubble, |
375 NotificationList::Delegate* list_delegate) | 379 NotificationList::Delegate* list_delegate) |
376 : list_delegate_(list_delegate), | 380 : list_delegate_(list_delegate), |
377 bubble_(bubble) { | 381 bubble_(bubble) { |
378 int between_child = IsRichNotificationEnabled() ? 0 : 1; | 382 int between_child = IsRichNotificationEnabled() ? 0 : 1; |
379 SetLayoutManager( | 383 SetLayoutManager( |
380 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, between_child)); | 384 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, between_child)); |
381 | 385 |
382 scroll_content_ = new ScrollContentView; | 386 |
383 scroller_ = new FixedSizedScrollView; | 387 if (IsRichNotificationEnabled()) |
384 scroller_->SetContents(scroll_content_); | 388 button_view_ = new WebNotificationButtonView2(list_delegate); |
385 AddChildView(scroller_); | 389 else |
390 button_view_ = new WebNotificationButtonView(list_delegate); | |
dharcourt
2013/02/23 04:32:00
Button creation had to be moved up in this method
| |
391 | |
392 const int button_height = button_view_->GetPreferredSize().height(); | |
393 const int min_height = kMessageBubbleBaseMinHeight - button_height; | |
394 const int max_height = bubble_->max_height() - button_height; | |
395 scroller_ = new BoundedScrollView(min_height, max_height); | |
386 | 396 |
387 if (get_use_acceleration_when_possible()) { | 397 if (get_use_acceleration_when_possible()) { |
388 scroller_->SetPaintToLayer(true); | 398 scroller_->SetPaintToLayer(true); |
389 scroller_->SetFillsBoundsOpaquely(false); | 399 scroller_->SetFillsBoundsOpaquely(false); |
390 scroller_->layer()->SetMasksToBounds(true); | 400 scroller_->layer()->SetMasksToBounds(true); |
391 } | 401 } |
392 | 402 |
393 if (IsRichNotificationEnabled()) | 403 messages_view_ = new MessagesView(this); |
394 button_view_ = new WebNotificationButtonView2(list_delegate); | 404 scroller_->SetContents(messages_view_); |
395 else | 405 |
396 button_view_ = new WebNotificationButtonView(list_delegate); | 406 AddChildView(scroller_); |
397 AddChildView(button_view_); | 407 AddChildView(button_view_); |
398 } | 408 } |
399 | 409 |
400 void FocusContents() { | 410 void FocusContents() { |
401 scroller_->RequestFocus(); | 411 scroller_->RequestFocus(); |
402 } | 412 } |
403 | 413 |
404 void Update(const NotificationList::Notifications& notifications) { | 414 void Update(const NotificationList::Notifications& notifications) { |
405 scroll_content_->RemoveAllChildViews(true); | 415 messages_view_->RemoveAllChildViews(true); |
406 scroll_content_->set_preferred_size(gfx::Size()); | |
407 size_t num_children = 0; | 416 size_t num_children = 0; |
408 for (NotificationList::Notifications::const_iterator iter = | 417 for (NotificationList::Notifications::const_iterator iter = |
409 notifications.begin(); iter != notifications.end(); ++iter) { | 418 notifications.begin(); iter != notifications.end(); ++iter) { |
410 MessageView* view = | 419 MessageView* view = |
411 NotificationView::ViewForNotification(*iter, list_delegate_); | 420 NotificationView::ViewForNotification(*iter, list_delegate_); |
412 view->set_scroller(scroller_); | 421 view->set_scroller(scroller_); |
dharcourt
2013/02/23 04:32:00
SetUpView() is now avoided as MessageView and all
| |
413 view->SetUpView(); | |
414 if (IsRichNotificationEnabled()) | 422 if (IsRichNotificationEnabled()) |
415 view->set_border(new MessageViewShadowBorder()); | 423 view->set_border(new MessageViewShadowBorder()); |
416 scroll_content_->AddChildView(view); | 424 messages_view_->AddChildView(view); |
417 if (++num_children >= | 425 if (++num_children >= |
418 NotificationList::kMaxVisibleMessageCenterNotifications) { | 426 NotificationList::kMaxVisibleMessageCenterNotifications) { |
419 break; | 427 break; |
420 } | 428 } |
421 } | 429 } |
422 if (num_children == 0) { | 430 if (num_children == 0) { |
423 views::Label* label = new views::Label(l10n_util::GetStringUTF16( | 431 views::Label* label = new views::Label(l10n_util::GetStringUTF16( |
424 IDS_MESSAGE_CENTER_NO_MESSAGES)); | 432 IDS_MESSAGE_CENTER_NO_MESSAGES)); |
425 label->SetFont(label->font().DeriveFont(1)); | 433 label->SetFont(label->font().DeriveFont(1)); |
426 label->SetEnabledColor(SK_ColorGRAY); | 434 label->SetEnabledColor(SK_ColorGRAY); |
427 // Set transparent background to ensure that subpixel rendering | 435 // Set transparent background to ensure that subpixel rendering |
428 // is disabled. See crbug.com/169056 | 436 // is disabled. See crbug.com/169056 |
429 label->SetBackgroundColor(kTransparentColor); | 437 label->SetBackgroundColor(kTransparentColor); |
430 scroll_content_->AddChildView(label); | 438 messages_view_->AddChildView(label); |
431 button_view_->SetCloseAllVisible(false); | 439 button_view_->SetCloseAllVisible(false); |
432 scroller_->set_focusable(false); | 440 scroller_->set_focusable(false); |
433 } else { | 441 } else { |
434 button_view_->SetCloseAllVisible(true); | 442 button_view_->SetCloseAllVisible(true); |
435 scroller_->set_focusable(true); | 443 scroller_->set_focusable(true); |
436 } | 444 } |
437 SizeScrollContent(); | |
438 Layout(); | 445 Layout(); |
439 if (GetWidget()) | |
440 GetWidget()->GetRootView()->SchedulePaint(); | |
441 } | 446 } |
442 | 447 |
443 size_t NumMessageViews() const { | 448 size_t NumMessageViews() const { |
444 return scroll_content_->child_count(); | 449 return messages_view_->child_count(); |
450 } | |
451 | |
452 protected: | |
453 // views::View overrides. | |
454 virtual void Layout() OVERRIDE { | |
455 scroller_->SizeToPreferredSize(); | |
456 views::View::Layout(); | |
457 if (GetWidget()) | |
458 GetWidget()->GetRootView()->SchedulePaint(); | |
459 bubble_->bubble_view()->UpdateBubble(); | |
445 } | 460 } |
446 | 461 |
447 private: | 462 private: |
448 void SizeScrollContent() { | |
449 gfx::Size scroll_size = scroll_content_->GetPreferredSize(); | |
450 const int button_height = button_view_->GetPreferredSize().height(); | |
451 const int min_height = kMessageBubbleBaseMinHeight - button_height; | |
452 const int max_height = bubble_->max_height() - button_height; | |
453 int scroll_height = std::min(std::max( | |
454 scroll_size.height(), min_height), max_height); | |
455 scroll_size.set_height(scroll_height); | |
456 if (scroll_height == min_height) | |
457 scroll_content_->set_preferred_size(scroll_size); | |
458 else | |
459 scroll_content_->set_preferred_size(gfx::Size()); | |
460 scroller_->SetFixedSize(scroll_size); | |
461 scroller_->SizeToPreferredSize(); | |
462 scroll_content_->InvalidateLayout(); | |
463 } | |
464 | |
465 NotificationList::Delegate* list_delegate_; | 463 NotificationList::Delegate* list_delegate_; |
466 FixedSizedScrollView* scroller_; | 464 BoundedScrollView* scroller_; |
467 ScrollContentView* scroll_content_; | 465 MessagesView* messages_view_; |
468 WebNotificationButtonViewBase* button_view_; | 466 WebNotificationButtonViewBase* button_view_; |
469 MessageCenterBubble* bubble_; | 467 MessageCenterBubble* bubble_; |
470 | 468 |
471 DISALLOW_COPY_AND_ASSIGN(MessageCenterContentsView); | 469 DISALLOW_COPY_AND_ASSIGN(MessageCenterView); |
472 }; | 470 }; |
473 | 471 |
474 // Message Center Bubble. | 472 // Message Center Bubble. |
475 MessageCenterBubble::MessageCenterBubble(NotificationList::Delegate* delegate) | 473 MessageCenterBubble::MessageCenterBubble(NotificationList::Delegate* delegate) |
476 : MessageBubbleBase(delegate), | 474 : MessageBubbleBase(delegate), |
477 contents_view_(NULL) { | 475 contents_view_(NULL) { |
478 } | 476 } |
479 | 477 |
480 MessageCenterBubble::~MessageCenterBubble() {} | 478 MessageCenterBubble::~MessageCenterBubble() {} |
481 | 479 |
482 views::TrayBubbleView::InitParams MessageCenterBubble::GetInitParams( | 480 views::TrayBubbleView::InitParams MessageCenterBubble::GetInitParams( |
483 views::TrayBubbleView::AnchorAlignment anchor_alignment) { | 481 views::TrayBubbleView::AnchorAlignment anchor_alignment) { |
484 views::TrayBubbleView::InitParams init_params = | 482 views::TrayBubbleView::InitParams init_params = |
485 GetDefaultInitParams(anchor_alignment); | 483 GetDefaultInitParams(anchor_alignment); |
486 if (IsRichNotificationEnabled()) { | 484 if (IsRichNotificationEnabled()) { |
487 init_params.min_width += kMarginBetweenItems * 2; | 485 init_params.min_width += kMarginBetweenItems * 2; |
488 init_params.max_width += kMarginBetweenItems * 2; | 486 init_params.max_width += kMarginBetweenItems * 2; |
489 } | 487 } |
490 init_params.max_height = max_height(); | 488 init_params.max_height = max_height(); |
491 init_params.can_activate = true; | 489 init_params.can_activate = true; |
492 return init_params; | 490 return init_params; |
493 } | 491 } |
494 | 492 |
495 void MessageCenterBubble::InitializeContents( | 493 void MessageCenterBubble::InitializeContents( |
496 views::TrayBubbleView* new_bubble_view) { | 494 views::TrayBubbleView* new_bubble_view) { |
497 set_bubble_view(new_bubble_view); | 495 set_bubble_view(new_bubble_view); |
498 contents_view_ = new MessageCenterContentsView(this, list_delegate()); | 496 contents_view_ = new MessageCenterView(this, list_delegate()); |
499 bubble_view()->AddChildView(contents_view_); | 497 bubble_view()->AddChildView(contents_view_); |
500 UpdateBubbleView(); | 498 UpdateBubbleView(); |
501 contents_view_->FocusContents(); | 499 contents_view_->FocusContents(); |
502 } | 500 } |
503 | 501 |
504 void MessageCenterBubble::OnBubbleViewDestroyed() { | 502 void MessageCenterBubble::OnBubbleViewDestroyed() { |
505 contents_view_ = NULL; | 503 contents_view_ = NULL; |
506 } | 504 } |
507 | 505 |
508 void MessageCenterBubble::UpdateBubbleView() { | 506 void MessageCenterBubble::UpdateBubbleView() { |
(...skipping 10 matching lines...) Expand all Loading... | |
519 } | 517 } |
520 | 518 |
521 void MessageCenterBubble::OnMouseExitedView() { | 519 void MessageCenterBubble::OnMouseExitedView() { |
522 } | 520 } |
523 | 521 |
524 size_t MessageCenterBubble::NumMessageViewsForTest() const { | 522 size_t MessageCenterBubble::NumMessageViewsForTest() const { |
525 return contents_view_->NumMessageViews(); | 523 return contents_view_->NumMessageViews(); |
526 } | 524 } |
527 | 525 |
528 } // namespace message_center | 526 } // namespace message_center |
OLD | NEW |