1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/message_center/views/notifier_settings_view.h" 6 7 #include <set> 8 #include <string> 9 10 #include "base/strings/string16.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "skia/ext/image_operations.h" 13 #include "third_party/skia/include/core/SkColor.h" 14 #include "ui/base/l10n/l10n_util.h" 15 #include "ui/base/models/simple_menu_model.h" 16 #include "ui/base/resource/resource_bundle.h" 17 #include "ui/events/keycodes/keyboard_codes.h" 18 #include "ui/gfx/canvas.h" 19 #include "ui/gfx/image/image.h" 20 #include "ui/gfx/size.h" 21 #include "ui/message_center/message_center_style.h" 22 #include "ui/message_center/views/message_center_view.h" 23 #include "ui/resources/grit/ui_resources.h" 24 #include "ui/strings/grit/ui_strings.h" 25 #include "ui/views/background.h" 26 #include "ui/views/border.h" 27 #include "ui/views/controls/button/checkbox.h" 28 #include "ui/views/controls/button/label_button_border.h" 29 #include "ui/views/controls/button/menu_button.h" 30 #include "ui/views/controls/image_view.h" 31 #include "ui/views/controls/label.h" 32 #include "ui/views/controls/link.h" 33 #include "ui/views/controls/link_listener.h" 34 #include "ui/views/controls/menu/menu_runner.h" 35 #include "ui/views/controls/scroll_view.h" 36 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h" 37 #include "ui/views/layout/box_layout.h" 38 #include "ui/views/layout/fill_layout.h" 39 #include "ui/views/layout/grid_layout.h" 40 #include "ui/views/painter.h" 41 #include "ui/views/widget/widget.h" 42 43 namespace message_center { 44 namespace settings { 45 46 // Additional views-specific parameters. 47 48 // The width of the settings pane in pixels. 49 const int kWidth = 360; 50 51 // The width of the learn more icon in pixels. 52 const int kLearnMoreSize = 12; 53 54 // The width of the click target that contains the learn more button in pixels. 55 const int kLearnMoreTargetWidth = 28; 56 57 // The height of the click target that contains the learn more button in pixels. 58 const int kLearnMoreTargetHeight = 40; 59 60 // The minimum height of the settings pane in pixels. 61 const int kMinimumHeight = 480; 62 63 // The horizontal margin of the title area of the settings pane in addition to 64 // the standard margin from settings::kHorizontalMargin. 65 const int kTitleMargin = 10; 66 67 } // namespace settings 68 69 namespace { 70 71 // Menu button metrics to make the text line up. 72 const int kMenuButtonInnateMargin = 2; 73 74 // Used to place the context menu correctly. 75 const int kMenuWhitespaceOffset = 2; 76 77 // The innate vertical blank space in the label for the title of the settings 78 // pane. 79 const int kInnateTitleBottomMargin = 1; 80 const int kInnateTitleTopMargin = 7; 81 82 // The innate top blank space in the label for the description of the settings 83 // pane. 84 const int kInnateDescriptionTopMargin = 2; 85 86 // Checkboxes have some built-in right padding blank space. 87 const int kInnateCheckboxRightPadding = 2; 88 89 // Spec defines the checkbox size; the innate padding throws this measurement 90 // off so we need to compute a slightly different area for the checkbox to 91 // inhabit. 92 const int kComputedCheckboxSize = 93 settings::kCheckboxSizeWithPadding - kInnateCheckboxRightPadding; 94 95 // The menubutton has innate margin, so we need to compensate for that when 96 // figuring the margin of the title area. 97 const int kComputedContentsTitleMargin = 0 - kMenuButtonInnateMargin; 98 99 // The spec doesn't include the bottom blank area of the title bar or the innate 100 // blank area in the description label, so we'll use this as the space between 101 // the title and description. 102 const int kComputedTitleBottomMargin = settings::kDescriptionToSwitcherSpace - 103 kInnateTitleBottomMargin - 104 kInnateDescriptionTopMargin; 105 106 // The blank space above the title needs to be adjusted by the amount of blank 107 // space included in the title label. 108 const int kComputedTitleTopMargin = 109 settings::kTopMargin - kInnateTitleTopMargin; 110 111 // The switcher has a lot of blank space built in so we should include that when 112 // spacing the title area vertically. 113 const int kComputedTitleElementSpacing = 114 settings::kDescriptionToSwitcherSpace - 6; 115 116 // A function to create a focus border. 117 scoped_ptr<views::Painter> CreateFocusPainter() { 118 return views::Painter::CreateSolidFocusPainter(kFocusBorderColor, 119 gfx::Insets(1, 2, 3, 2)); 120 } 121 122 // EntryView ------------------------------------------------------------------ 123 124 // The view to guarantee the 48px height and place the contents at the 125 // middle. It also guarantee the left margin. 126 class EntryView : public views::View { 127 public: 128 explicit EntryView(views::View* contents); 129 virtual ~EntryView(); 130 131 // views::View: 132 virtual void Layout() OVERRIDE; 133 virtual gfx::Size GetPreferredSize() const OVERRIDE; 134 virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE; 135 virtual void OnFocus() OVERRIDE; 136 virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE; 137 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE; 138 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 139 virtual void OnBlur() OVERRIDE; 140 141 private: 142 scoped_ptr<views::Painter> focus_painter_; 143 144 DISALLOW_COPY_AND_ASSIGN(EntryView); 145 }; 146 147 EntryView::EntryView(views::View* contents) 148 : focus_painter_(CreateFocusPainter()) { 149 AddChildView(contents); 150 } 151 152 EntryView::~EntryView() {} 153 154 void EntryView::Layout() { 155 DCHECK_EQ(1, child_count()); 156 views::View* content = child_at(0); 157 int content_width = width(); 158 int content_height = content->GetHeightForWidth(content_width); 159 int y = std::max((height() - content_height) / 2, 0); 160 content->SetBounds(0, y, content_width, content_height); 161 } 162 163 gfx::Size EntryView::GetPreferredSize() const { 164 DCHECK_EQ(1, child_count()); 165 gfx::Size size = child_at(0)->GetPreferredSize(); 166 size.SetToMax(gfx::Size(settings::kWidth, settings::kEntryHeight)); 167 return size; 168 } 169 170 void EntryView::GetAccessibleState(ui::AXViewState* state) { 171 DCHECK_EQ(1, child_count()); 172 child_at(0)->GetAccessibleState(state); 173 } 174 175 void EntryView::OnFocus() { 176 views::View::OnFocus(); 177 ScrollRectToVisible(GetLocalBounds()); 178 // We render differently when focused. 179 SchedulePaint(); 180 } 181 182 bool EntryView::OnKeyPressed(const ui::KeyEvent& event) { 183 return child_at(0)->OnKeyPressed(event); 184 } 185 186 bool EntryView::OnKeyReleased(const ui::KeyEvent& event) { 187 return child_at(0)->OnKeyReleased(event); 188 } 189 190 void EntryView::OnPaint(gfx::Canvas* canvas) { 191 View::OnPaint(canvas); 192 views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); 193 } 194 195 void EntryView::OnBlur() { 196 View::OnBlur(); 197 // We render differently when focused. 198 SchedulePaint(); 199 } 200 201 } // namespace 202 203 204 // NotifierGroupMenuModel ----------------------------------------------------- 205 206 class NotifierGroupMenuModel : public ui::SimpleMenuModel, 207 public ui::SimpleMenuModel::Delegate { 208 public: 209 NotifierGroupMenuModel(NotifierSettingsProvider* notifier_settings_provider); 210 virtual ~NotifierGroupMenuModel(); 211 212 // ui::SimpleMenuModel::Delegate: 213 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; 214 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; 215 virtual bool GetAcceleratorForCommandId( 216 int command_id, 217 ui::Accelerator* accelerator) OVERRIDE; 218 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; 219 220 private: 221 NotifierSettingsProvider* notifier_settings_provider_; 222 223 DISALLOW_COPY_AND_ASSIGN(NotifierGroupMenuModel); 224 }; 225 226 NotifierGroupMenuModel::NotifierGroupMenuModel( 227 NotifierSettingsProvider* notifier_settings_provider) 228 : ui::SimpleMenuModel(this), 229 notifier_settings_provider_(notifier_settings_provider) { 230 if (!notifier_settings_provider_) 231 return; 232 233 size_t num_menu_items = notifier_settings_provider_->GetNotifierGroupCount(); 234 for (size_t i = 0; i < num_menu_items; ++i) { 235 const NotifierGroup& group = 236 notifier_settings_provider_->GetNotifierGroupAt(i); 237 238 AddCheckItem(i, group.login_info.empty() ? group.name : group.login_info); 239 } 240 } 241 242 NotifierGroupMenuModel::~NotifierGroupMenuModel() {} 243 244 bool NotifierGroupMenuModel::IsCommandIdChecked(int command_id) const { 245 // If there's no provider, assume only one notifier group - the active one. 246 return !notifier_settings_provider_ || 247 notifier_settings_provider_->IsNotifierGroupActiveAt(command_id); 248 } 249 250 bool NotifierGroupMenuModel::IsCommandIdEnabled(int command_id) const { 251 return true; 252 } 253 254 bool NotifierGroupMenuModel::GetAcceleratorForCommandId( 255 int command_id, 256 ui::Accelerator* accelerator) { 257 return false; 258 } 259 260 void NotifierGroupMenuModel::ExecuteCommand(int command_id, int event_flags) { 261 if (!notifier_settings_provider_) 262 return; 263 264 size_t notifier_group_index = static_cast<size_t>(command_id); 265 size_t num_notifier_groups = 266 notifier_settings_provider_->GetNotifierGroupCount(); 267 if (notifier_group_index >= num_notifier_groups) 268 return; 269 270 notifier_settings_provider_->SwitchToNotifierGroup(notifier_group_index); 271 } 272 273 274 // NotifierSettingsView::NotifierButton --------------------------------------- 275 276 // We do not use views::Checkbox class directly because it doesn't support 277 // showing 'icon'. 278 NotifierSettingsView::NotifierButton::NotifierButton( 279 NotifierSettingsProvider* provider, 280 Notifier* notifier, 281 views::ButtonListener* listener) 282 : views::CustomButton(listener), 283 provider_(provider), 284 notifier_(notifier), 285 icon_view_(new views::ImageView()), 286 name_view_(new views::Label(notifier_->name)), 287 checkbox_(new views::Checkbox(base::string16())), 288 learn_more_(NULL) { 289 DCHECK(provider); 290 DCHECK(notifier); 291 292 // Since there may never be an icon (but that could change at a later time), 293 // we own the icon view here. 294 icon_view_->set_owned_by_client(); 295 296 checkbox_->SetChecked(notifier_->enabled); 297 checkbox_->set_listener(this); 298 checkbox_->SetFocusable(false); 299 checkbox_->SetAccessibleName(notifier_->name); 300 301 if (ShouldHaveLearnMoreButton()) { 302 // Create a more-info button that will be right-aligned. 303 learn_more_ = new views::ImageButton(this); 304 learn_more_->SetFocusPainter(CreateFocusPainter()); 305 learn_more_->set_request_focus_on_press(false); 306 learn_more_->SetFocusable(true); 307 308 ui::ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 309 learn_more_->SetImage( 310 views::Button::STATE_NORMAL, 311 rb.GetImageSkiaNamed(IDR_NOTIFICATION_ADVANCED_SETTINGS)); 312 learn_more_->SetImage( 313 views::Button::STATE_HOVERED, 314 rb.GetImageSkiaNamed(IDR_NOTIFICATION_ADVANCED_SETTINGS_HOVER)); 315 learn_more_->SetImage( 316 views::Button::STATE_PRESSED, 317 rb.GetImageSkiaNamed(IDR_NOTIFICATION_ADVANCED_SETTINGS_PRESSED)); 318 learn_more_->SetState(views::Button::STATE_NORMAL); 319 int learn_more_border_width = 320 (settings::kLearnMoreTargetWidth - settings::kLearnMoreSize) / 2; 321 int learn_more_border_height = 322 (settings::kLearnMoreTargetHeight - settings::kLearnMoreSize) / 2; 323 // The image itself is quite small, this large invisible border creates a 324 // much bigger click target. 325 learn_more_->SetBorder( 326 views::Border::CreateEmptyBorder(learn_more_border_height, 327 learn_more_border_width, 328 learn_more_border_height, 329 learn_more_border_width)); 330 learn_more_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, 331 views::ImageButton::ALIGN_MIDDLE); 332 } 333 334 UpdateIconImage(notifier_->icon); 335 } 336 337 NotifierSettingsView::NotifierButton::~NotifierButton() { 338 } 339 340 void NotifierSettingsView::NotifierButton::UpdateIconImage( 341 const gfx::Image& icon) { 342 bool has_icon_view = false; 343 344 notifier_->icon = icon; 345 if (!icon.IsEmpty()) { 346 icon_view_->SetImage(icon.ToImageSkia()); 347 icon_view_->SetImageSize( 348 gfx::Size(settings::kEntryIconSize, settings::kEntryIconSize)); 349 has_icon_view = true; 350 } 351 GridChanged(ShouldHaveLearnMoreButton(), has_icon_view); 352 } 353 354 void NotifierSettingsView::NotifierButton::SetChecked(bool checked) { 355 checkbox_->SetChecked(checked); 356 notifier_->enabled = checked; 357 } 358 359 bool NotifierSettingsView::NotifierButton::checked() const { 360 return checkbox_->checked(); 361 } 362 363 bool NotifierSettingsView::NotifierButton::has_learn_more() const { 364 return learn_more_ != NULL; 365 } 366 367 const Notifier& NotifierSettingsView::NotifierButton::notifier() const { 368 return *notifier_.get(); 369 } 370 371 void NotifierSettingsView::NotifierButton::SendLearnMorePressedForTest() { 372 if (learn_more_ == NULL) 373 return; 374 gfx::Point point(110, 120); 375 ui::MouseEvent pressed( 376 ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, 377 ui::EF_LEFT_MOUSE_BUTTON); 378 ButtonPressed(learn_more_, pressed); 379 } 380 381 void NotifierSettingsView::NotifierButton::ButtonPressed( 382 views::Button* button, 383 const ui::Event& event) { 384 if (button == checkbox_) { 385 // The checkbox state has already changed at this point, but we'll update 386 // the state on NotifierSettingsView::ButtonPressed() too, so here change 387 // back to the previous state. 388 checkbox_->SetChecked(!checkbox_->checked()); 389 CustomButton::NotifyClick(event); 390 } else if (button == learn_more_) { 391 DCHECK(provider_); 392 provider_->OnNotifierAdvancedSettingsRequested(notifier_->notifier_id, 393 NULL); 394 } 395 } 396 397 void NotifierSettingsView::NotifierButton::GetAccessibleState( 398 ui::AXViewState* state) { 399 static_cast<views::View*>(checkbox_)->GetAccessibleState(state); 400 } 401 402 bool NotifierSettingsView::NotifierButton::ShouldHaveLearnMoreButton() const { 403 if (!provider_) 404 return false; 405 406 return provider_->NotifierHasAdvancedSettings(notifier_->notifier_id); 407 } 408 409 void NotifierSettingsView::NotifierButton::GridChanged(bool has_learn_more, 410 bool has_icon_view) { 411 using views::ColumnSet; 412 using views::GridLayout; 413 414 GridLayout* layout = new GridLayout(this); 415 SetLayoutManager(layout); 416 ColumnSet* cs = layout->AddColumnSet(0); 417 // Add a column for the checkbox. 418 cs->AddPaddingColumn(0, kInnateCheckboxRightPadding); 419 cs->AddColumn(GridLayout::CENTER, 420 GridLayout::CENTER, 421 0, 422 GridLayout::FIXED, 423 kComputedCheckboxSize, 424 0); 425 cs->AddPaddingColumn(0, settings::kInternalHorizontalSpacing); 426 427 if (has_icon_view) { 428 // Add a column for the icon. 429 cs->AddColumn(GridLayout::CENTER, 430 GridLayout::CENTER, 431 0, 432 GridLayout::FIXED, 433 settings::kEntryIconSize, 434 0); 435 cs->AddPaddingColumn(0, settings::kInternalHorizontalSpacing); 436 } 437 438 // Add a column for the name. 439 cs->AddColumn( 440 GridLayout::LEADING, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); 441 442 // Add a padding column which contains expandable blank space. 443 cs->AddPaddingColumn(1, 0); 444 445 // Add a column for the learn more button if necessary. 446 if (has_learn_more) { 447 cs->AddPaddingColumn(0, settings::kInternalHorizontalSpacing); 448 cs->AddColumn( 449 GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); 450 } 451 452 layout->StartRow(0, 0); 453 layout->AddView(checkbox_); 454 if (has_icon_view) 455 layout->AddView(icon_view_.get()); 456 layout->AddView(name_view_); 457 if (has_learn_more) 458 layout->AddView(learn_more_); 459 460 Layout(); 461 } 462 463 464 // NotifierSettingsView ------------------------------------------------------- 465 466 NotifierSettingsView::NotifierSettingsView(NotifierSettingsProvider* provider) 467 : title_arrow_(NULL), 468 title_label_(NULL), 469 notifier_group_selector_(NULL), 470 scroller_(NULL), 471 provider_(provider) { 472 // |provider_| may be NULL in tests. 473 if (provider_) 474 provider_->AddObserver(this); 475 476 SetFocusable(true); 477 set_background( 478 views::Background::CreateSolidBackground(kMessageCenterBackgroundColor)); 479 SetPaintToLayer(true); 480 481 title_label_ = new views::Label( 482 l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL), 483 ui::ResourceBundle::GetSharedInstance().GetFontList( 484 ui::ResourceBundle::MediumFont)); 485 title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 486 title_label_->SetMultiLine(true); 487 title_label_->SetBorder( 488 views::Border::CreateEmptyBorder(kComputedTitleTopMargin, 489 settings::kTitleMargin, 490 kComputedTitleBottomMargin, 491 settings::kTitleMargin)); 492 493 AddChildView(title_label_); 494 495 scroller_ = new views::ScrollView(); 496 scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false)); 497 AddChildView(scroller_); 498 499 std::vector<Notifier*> notifiers; 500 if (provider_) 501 provider_->GetNotifierList(¬ifiers); 502 503 UpdateContentsView(notifiers); 504 } 505 506 NotifierSettingsView::~NotifierSettingsView() { 507 // |provider_| may be NULL in tests. 508 if (provider_) 509 provider_->RemoveObserver(this); 510 } 511 512 bool NotifierSettingsView::IsScrollable() { 513 return scroller_->height() < scroller_->contents()->height(); 514 } 515 516 void NotifierSettingsView::UpdateIconImage(const NotifierId& notifier_id, 517 const gfx::Image& icon) { 518 for (std::set<NotifierButton*>::iterator iter = buttons_.begin(); 519 iter != buttons_.end(); 520 ++iter) { 521 if ((*iter)->notifier().notifier_id == notifier_id) { 522 (*iter)->UpdateIconImage(icon); 523 return; 524 } 525 } 526 } 527 528 void NotifierSettingsView::NotifierGroupChanged() { 529 std::vector<Notifier*> notifiers; 530 if (provider_) 531 provider_->GetNotifierList(¬ifiers); 532 533 UpdateContentsView(notifiers); 534 } 535 536 void NotifierSettingsView::NotifierEnabledChanged(const NotifierId& notifier_id, 537 bool enabled) {} 538 539 void NotifierSettingsView::UpdateContentsView( 540 const std::vector<Notifier*>& notifiers) { 541 buttons_.clear(); 542 543 views::View* contents_view = new views::View(); 544 contents_view->SetLayoutManager(new views::BoxLayout( 545 views::BoxLayout::kVertical, settings::kHorizontalMargin, 0, 0)); 546 547 views::View* contents_title_view = new views::View(); 548 contents_title_view->SetLayoutManager( 549 new views::BoxLayout(views::BoxLayout::kVertical, 550 kComputedContentsTitleMargin, 551 0, 552 kComputedTitleElementSpacing)); 553 554 bool need_account_switcher = 555 provider_ && provider_->GetNotifierGroupCount() > 1; 556 int top_label_resource_id = 557 need_account_switcher ? IDS_MESSAGE_CENTER_SETTINGS_DESCRIPTION_MULTIUSER 558 : IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION; 559 560 views::Label* top_label = 561 new views::Label(l10n_util::GetStringUTF16(top_label_resource_id)); 562 563 top_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 564 top_label->SetMultiLine(true); 565 top_label->SetBorder(views::Border::CreateEmptyBorder( 566 0, 567 settings::kTitleMargin + kMenuButtonInnateMargin, 568 0, 569 settings::kTitleMargin + kMenuButtonInnateMargin)); 570 contents_title_view->AddChildView(top_label); 571 572 if (need_account_switcher) { 573 const NotifierGroup& active_group = provider_->GetActiveNotifierGroup(); 574 base::string16 notifier_group_text = active_group.login_info.empty() ? 575 active_group.name : active_group.login_info; 576 notifier_group_selector_ = 577 new views::MenuButton(NULL, notifier_group_text, this, true); 578 notifier_group_selector_->SetBorder(scoped_ptr<views::Border>( 579 new views::LabelButtonBorder(views::Button::STYLE_BUTTON)).Pass()); 580 notifier_group_selector_->SetFocusPainter(scoped_ptr<views::Painter>()); 581 notifier_group_selector_->set_animate_on_state_change(false); 582 notifier_group_selector_->SetFocusable(true); 583 contents_title_view->AddChildView(notifier_group_selector_); 584 } 585 586 contents_view->AddChildView(contents_title_view); 587 588 size_t notifier_count = notifiers.size(); 589 for (size_t i = 0; i < notifier_count; ++i) { 590 NotifierButton* button = new NotifierButton(provider_, notifiers[i], this); 591 EntryView* entry = new EntryView(button); 592 593 // This code emulates separators using borders. We will create an invisible 594 // border on the last notifier, as the spec leaves a space for it. 595 scoped_ptr<views::Border> entry_border; 596 if (i == notifier_count - 1) { 597 entry_border = views::Border::CreateEmptyBorder( 598 0, 0, settings::kEntrySeparatorHeight, 0); 599 } else { 600 entry_border = 601 views::Border::CreateSolidSidedBorder(0, 602 0, 603 settings::kEntrySeparatorHeight, 604 0, 605 settings::kEntrySeparatorColor); 606 } 607 entry->SetBorder(entry_border.Pass()); 608 entry->SetFocusable(true); 609 contents_view->AddChildView(entry); 610 buttons_.insert(button); 611 } 612 613 scroller_->SetContents(contents_view); 614 615 contents_view->SetBoundsRect(gfx::Rect(contents_view->GetPreferredSize())); 616 InvalidateLayout(); 617 } 618 619 void NotifierSettingsView::Layout() { 620 int title_height = title_label_->GetHeightForWidth(width()); 621 title_label_->SetBounds(settings::kTitleMargin, 622 0, 623 width() - settings::kTitleMargin * 2, 624 title_height); 625 626 views::View* contents_view = scroller_->contents(); 627 int content_width = width(); 628 int content_height = contents_view->GetHeightForWidth(content_width); 629 if (title_height + content_height > height()) { 630 content_width -= scroller_->GetScrollBarWidth(); 631 content_height = contents_view->GetHeightForWidth(content_width); 632 } 633 contents_view->SetBounds(0, 0, content_width, content_height); 634 scroller_->SetBounds(0, title_height, width(), height() - title_height); 635 } 636 637 gfx::Size NotifierSettingsView::GetMinimumSize() const { 638 gfx::Size size(settings::kWidth, settings::kMinimumHeight); 639 int total_height = title_label_->GetPreferredSize().height() + 640 scroller_->contents()->GetPreferredSize().height(); 641 if (total_height > settings::kMinimumHeight) 642 size.Enlarge(scroller_->GetScrollBarWidth(), 0); 643 return size; 644 } 645 646 gfx::Size NotifierSettingsView::GetPreferredSize() const { 647 gfx::Size preferred_size; 648 gfx::Size title_size = title_label_->GetPreferredSize(); 649 gfx::Size content_size = scroller_->contents()->GetPreferredSize(); 650 return gfx::Size(std::max(title_size.width(), content_size.width()), 651 title_size.height() + content_size.height()); 652 } 653 654 bool NotifierSettingsView::OnKeyPressed(const ui::KeyEvent& event) { 655 if (event.key_code() == ui::VKEY_ESCAPE) { 656 GetWidget()->Close(); 657 return true; 658 } 659 660 return scroller_->OnKeyPressed(event); 661 } 662 663 bool NotifierSettingsView::OnMouseWheel(const ui::MouseWheelEvent& event) { 664 return scroller_->OnMouseWheel(event); 665 } 666 667 void NotifierSettingsView::ButtonPressed(views::Button* sender, 668 const ui::Event& event) { 669 if (sender == title_arrow_) { 670 MessageCenterView* center_view = static_cast<MessageCenterView*>(parent()); 671 center_view->SetSettingsVisible(!center_view->settings_visible()); 672 return; 673 } 674 675 std::set<NotifierButton*>::iterator iter = 676 buttons_.find(static_cast<NotifierButton*>(sender)); 677 678 if (iter == buttons_.end()) 679 return; 680 681 (*iter)->SetChecked(!(*iter)->checked()); 682 if (provider_) 683 provider_->SetNotifierEnabled((*iter)->notifier(), (*iter)->checked()); 684 } 685 686 void NotifierSettingsView::OnMenuButtonClicked(views::View* source, 687 const gfx::Point& point) { 688 notifier_group_menu_model_.reset(new NotifierGroupMenuModel(provider_)); 689 notifier_group_menu_runner_.reset(new views::MenuRunner( 690 notifier_group_menu_model_.get(), views::MenuRunner::CONTEXT_MENU)); 691 gfx::Rect menu_anchor = source->GetBoundsInScreen(); 692 menu_anchor.Inset( 693 gfx::Insets(0, kMenuWhitespaceOffset, 0, kMenuWhitespaceOffset)); 694 if (views::MenuRunner::MENU_DELETED == 695 notifier_group_menu_runner_->RunMenuAt(GetWidget(), 696 notifier_group_selector_, 697 menu_anchor, 698 views::MENU_ANCHOR_BUBBLE_ABOVE, 699 ui::MENU_SOURCE_MOUSE)) 700 return; 701 MessageCenterView* center_view = static_cast<MessageCenterView*>(parent()); 702 center_view->OnSettingsChanged(); 703 } 704 705 } // namespace message_center 706