gpu: Tweak Android WebGL test expectations
[chromium-blink-merge.git] / ui / message_center / views / notifier_settings_view.cc
blobb4e18846a2b50445a57eeea41b43e2b4f3b58546
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.
5 #include "ui/message_center/views/notifier_settings_view.h"
7 #include <set>
8 #include <string>
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "grit/ui_resources.h"
13 #include "grit/ui_strings.h"
14 #include "skia/ext/image_operations.h"
15 #include "third_party/skia/include/core/SkColor.h"
16 #include "ui/base/keycodes/keyboard_codes.h"
17 #include "ui/base/l10n/l10n_util.h"
18 #include "ui/base/models/simple_menu_model.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/canvas.h"
21 #include "ui/gfx/image/image.h"
22 #include "ui/gfx/size.h"
23 #include "ui/message_center/message_center_style.h"
24 #include "ui/message_center/views/message_center_view.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/custom_button.h"
29 #include "ui/views/controls/button/label_button_border.h"
30 #include "ui/views/controls/button/menu_button.h"
31 #include "ui/views/controls/image_view.h"
32 #include "ui/views/controls/label.h"
33 #include "ui/views/controls/menu/menu_runner.h"
34 #include "ui/views/controls/scroll_view.h"
35 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
36 #include "ui/views/layout/box_layout.h"
37 #include "ui/views/layout/fill_layout.h"
38 #include "ui/views/layout/grid_layout.h"
39 #include "ui/views/widget/widget.h"
41 #if defined(USE_AURA)
42 #include "ui/aura/window.h"
43 #endif
45 namespace message_center {
46 namespace {
47 const int kButtonPainterInsets = 5;
48 // We really want the margin to be 20px, but various views are padded by
49 // whitespace.
50 const int kDesiredMargin = 20;
51 // The MenuButton has 2px whitespace built-in.
52 const int kMenuButtonInnateMargin = 2;
53 const int kMinimumHorizontalMargin = kDesiredMargin - kMenuButtonInnateMargin;
54 // The EntryViews' leftmost view is a checkbox with 1px whitespace built in, so
55 // the margin for entry views should be one less than the target margin.
56 const int kCheckboxInnateMargin = 1;
57 const int kEntryMargin = kDesiredMargin - kCheckboxInnateMargin;
58 const int kMenuButtonLeftPadding = 12;
59 const int kMenuButtonRightPadding = 13;
60 const int kMenuButtonVerticalPadding = 9;
61 const int kMenuWhitespaceOffset = 2;
62 const int kMinimumWindowHeight = 480;
63 const int kMinimumWindowWidth = 320;
64 const int kSettingsTitleBottomMargin = 12;
65 const int kSettingsTitleTopMargin = 15;
66 const int kSpaceInButtonComponents = 16;
67 const int kTitleVerticalMargin = 1;
68 const int kTitleElementSpacing = 10;
69 const int kEntryHeight = kMinimumWindowHeight / 10;
71 // The view to guarantee the 48px height and place the contents at the
72 // middle. It also guarantee the left margin.
73 class EntryView : public views::View {
74 public:
75 EntryView(views::View* contents);
76 virtual ~EntryView();
78 // Overridden from views::View:
79 virtual void Layout() OVERRIDE;
80 virtual gfx::Size GetPreferredSize() OVERRIDE;
81 virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
82 virtual void OnFocus() OVERRIDE;
83 virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE;
84 virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
85 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
87 private:
88 DISALLOW_COPY_AND_ASSIGN(EntryView);
91 EntryView::EntryView(views::View* contents) {
92 AddChildView(contents);
95 EntryView::~EntryView() {
98 void EntryView::Layout() {
99 DCHECK_EQ(1, child_count());
100 views::View* content = child_at(0);
101 int content_width = width() - kEntryMargin * 2;
102 int content_height = content->GetHeightForWidth(content_width);
103 int y = std::max((height() - content_height) / 2, 0);
104 content->SetBounds(kEntryMargin, y, content_width, content_height);
107 gfx::Size EntryView::GetPreferredSize() {
108 DCHECK_EQ(1, child_count());
109 gfx::Size size = child_at(0)->GetPreferredSize();
110 size.SetToMax(gfx::Size(kMinimumWindowWidth, kEntryHeight));
111 return size;
114 void EntryView::GetAccessibleState(ui::AccessibleViewState* state) {
115 DCHECK_EQ(1, child_count());
116 child_at(0)->GetAccessibleState(state);
119 void EntryView::OnFocus() {
120 views::View::OnFocus();
121 ScrollRectToVisible(GetLocalBounds());
124 void EntryView::OnPaintFocusBorder(gfx::Canvas* canvas) {
125 if (HasFocus() && (focusable() || IsAccessibilityFocusable())) {
126 canvas->DrawRect(gfx::Rect(2, 1, width() - 4, height() - 3),
127 kFocusBorderColor);
131 bool EntryView::OnKeyPressed(const ui::KeyEvent& event) {
132 return child_at(0)->OnKeyPressed(event);
135 bool EntryView::OnKeyReleased(const ui::KeyEvent& event) {
136 return child_at(0)->OnKeyReleased(event);
139 } // namespace
141 // NotifierGroupMenuButtonBorder ///////////////////////////////////////////////
142 ////////////////////////////////////////////////////////////////////////////////
143 class NotifierGroupMenuButtonBorder : public views::TextButtonDefaultBorder {
144 public:
145 NotifierGroupMenuButtonBorder();
147 private:
148 virtual ~NotifierGroupMenuButtonBorder();
151 NotifierGroupMenuButtonBorder::NotifierGroupMenuButtonBorder()
152 : views::TextButtonDefaultBorder() {
153 ui::ResourceBundle& rb = ResourceBundle::GetSharedInstance();
155 gfx::Insets insets(kButtonPainterInsets,
156 kButtonPainterInsets,
157 kButtonPainterInsets,
158 kButtonPainterInsets);
160 set_normal_painter(views::Painter::CreateImagePainter(
161 *rb.GetImageSkiaNamed(IDR_BUTTON_NORMAL), insets));
162 set_hot_painter(views::Painter::CreateImagePainter(
163 *rb.GetImageSkiaNamed(IDR_BUTTON_HOVER), insets));
164 set_pushed_painter(views::Painter::CreateImagePainter(
165 *rb.GetImageSkiaNamed(IDR_BUTTON_PRESSED), insets));
167 SetInsets(gfx::Insets(kMenuButtonVerticalPadding,
168 kMenuButtonLeftPadding,
169 kMenuButtonVerticalPadding,
170 kMenuButtonRightPadding));
173 NotifierGroupMenuButtonBorder::~NotifierGroupMenuButtonBorder() {}
175 // NotifierGroupMenuModel //////////////////////////////////////////////////////
176 ////////////////////////////////////////////////////////////////////////////////
177 class NotifierGroupMenuModel : public ui::SimpleMenuModel,
178 public ui::SimpleMenuModel::Delegate {
179 public:
180 NotifierGroupMenuModel(NotifierSettingsProvider* notifier_settings_provider);
181 virtual ~NotifierGroupMenuModel();
183 // Overridden from ui::SimpleMenuModel::Delegate:
184 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
185 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
186 virtual bool GetAcceleratorForCommandId(
187 int command_id,
188 ui::Accelerator* accelerator) OVERRIDE;
189 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
191 private:
192 NotifierSettingsProvider* notifier_settings_provider_;
195 NotifierGroupMenuModel::NotifierGroupMenuModel(
196 NotifierSettingsProvider* notifier_settings_provider)
197 : ui::SimpleMenuModel(this),
198 notifier_settings_provider_(notifier_settings_provider) {
199 if (!notifier_settings_provider_)
200 return;
202 size_t num_menu_items = notifier_settings_provider_->GetNotifierGroupCount();
203 for (size_t i = 0; i < num_menu_items; ++i) {
204 const NotifierGroup& group =
205 notifier_settings_provider_->GetNotifierGroupAt(i);
207 AddCheckItem(i, group.login_info.empty() ? group.name : group.login_info);
211 NotifierGroupMenuModel::~NotifierGroupMenuModel() {}
213 bool NotifierGroupMenuModel::IsCommandIdChecked(int command_id) const {
214 // If there's no provider, assume only one notifier group - the active one.
215 if (!notifier_settings_provider_)
216 return true;
218 return notifier_settings_provider_->IsNotifierGroupActiveAt(command_id);
221 bool NotifierGroupMenuModel::IsCommandIdEnabled(int command_id) const {
222 return true;
225 bool NotifierGroupMenuModel::GetAcceleratorForCommandId(
226 int command_id,
227 ui::Accelerator* accelerator) {
228 return false;
231 void NotifierGroupMenuModel::ExecuteCommand(int command_id, int event_flags) {
232 if (!notifier_settings_provider_)
233 return;
235 size_t notifier_group_index = static_cast<size_t>(command_id);
236 size_t num_notifier_groups =
237 notifier_settings_provider_->GetNotifierGroupCount();
238 if (notifier_group_index >= num_notifier_groups)
239 return;
241 notifier_settings_provider_->SwitchToNotifierGroup(notifier_group_index);
244 // We do not use views::Checkbox class directly because it doesn't support
245 // showing 'icon'.
246 class NotifierSettingsView::NotifierButton : public views::CustomButton,
247 public views::ButtonListener {
248 public:
249 NotifierButton(Notifier* notifier, views::ButtonListener* listener)
250 : views::CustomButton(listener),
251 notifier_(notifier),
252 icon_view_(NULL),
253 checkbox_(new views::Checkbox(string16())) {
254 DCHECK(notifier);
255 SetLayoutManager(new views::BoxLayout(
256 views::BoxLayout::kHorizontal, 0, 0, kSpaceInButtonComponents));
257 checkbox_->SetChecked(notifier_->enabled);
258 checkbox_->set_listener(this);
259 checkbox_->set_focusable(false);
260 checkbox_->SetAccessibleName(notifier_->name);
261 AddChildView(checkbox_);
262 UpdateIconImage(notifier_->icon);
263 AddChildView(new views::Label(notifier_->name));
266 void UpdateIconImage(const gfx::Image& icon) {
267 notifier_->icon = icon;
268 if (icon.IsEmpty()) {
269 delete icon_view_;
270 icon_view_ = NULL;
271 } else {
272 if (!icon_view_) {
273 icon_view_ = new views::ImageView();
274 AddChildViewAt(icon_view_, 1);
276 icon_view_->SetImage(icon.ToImageSkia());
277 icon_view_->SetImageSize(gfx::Size(kSettingsIconSize, kSettingsIconSize));
279 Layout();
280 SchedulePaint();
283 void SetChecked(bool checked) {
284 checkbox_->SetChecked(checked);
285 notifier_->enabled = checked;
288 bool checked() const {
289 return checkbox_->checked();
292 const Notifier& notifier() const {
293 return *notifier_.get();
296 private:
297 // Overridden from views::ButtonListener:
298 virtual void ButtonPressed(views::Button* button,
299 const ui::Event& event) OVERRIDE {
300 DCHECK(button == checkbox_);
301 // The checkbox state has already changed at this point, but we'll update
302 // the state on NotifierSettingsView::ButtonPressed() too, so here change
303 // back to the previous state.
304 checkbox_->SetChecked(!checkbox_->checked());
305 CustomButton::NotifyClick(event);
308 virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE {
309 static_cast<views::View*>(checkbox_)->GetAccessibleState(state);
312 scoped_ptr<Notifier> notifier_;
313 views::ImageView* icon_view_;
314 views::Checkbox* checkbox_;
316 DISALLOW_COPY_AND_ASSIGN(NotifierButton);
319 NotifierSettingsView::NotifierSettingsView(NotifierSettingsProvider* provider)
320 : title_arrow_(NULL),
321 title_label_(NULL),
322 notifier_group_selector_(NULL),
323 scroller_(NULL),
324 provider_(provider) {
325 // |provider_| may be NULL in tests.
326 if (provider_)
327 provider_->AddObserver(this);
329 set_focusable(true);
330 set_focus_border(NULL);
331 set_background(views::Background::CreateSolidBackground(
332 kMessageCenterBackgroundColor));
333 if (get_use_acceleration_when_possible())
334 SetPaintToLayer(true);
336 gfx::Font title_font =
337 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont);
338 title_label_ = new views::Label(
339 l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL),
340 title_font);
341 title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
342 title_label_->SetMultiLine(true);
343 title_label_->set_border(
344 views::Border::CreateEmptyBorder(kSettingsTitleTopMargin,
345 kDesiredMargin,
346 kSettingsTitleBottomMargin,
347 kDesiredMargin));
349 AddChildView(title_label_);
351 scroller_ = new views::ScrollView();
352 scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false));
353 AddChildView(scroller_);
355 std::vector<Notifier*> notifiers;
356 if (provider_)
357 provider_->GetNotifierList(&notifiers);
359 UpdateContentsView(notifiers);
362 NotifierSettingsView::~NotifierSettingsView() {
363 // |provider_| may be NULL in tests.
364 if (provider_)
365 provider_->RemoveObserver(this);
368 bool NotifierSettingsView::IsScrollable() {
369 return scroller_->height() < scroller_->contents()->height();
372 void NotifierSettingsView::UpdateIconImage(const NotifierId& notifier_id,
373 const gfx::Image& icon) {
374 for (std::set<NotifierButton*>::iterator iter = buttons_.begin();
375 iter != buttons_.end(); ++iter) {
376 if ((*iter)->notifier().notifier_id == notifier_id) {
377 (*iter)->UpdateIconImage(icon);
378 return;
383 void NotifierSettingsView::NotifierGroupChanged() {
384 std::vector<Notifier*> notifiers;
385 if (provider_)
386 provider_->GetNotifierList(&notifiers);
388 UpdateContentsView(notifiers);
391 void NotifierSettingsView::UpdateContentsView(
392 const std::vector<Notifier*>& notifiers) {
393 buttons_.clear();
395 views::View* contents_view = new views::View();
396 contents_view->SetLayoutManager(
397 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
399 views::View* contents_title_view = new views::View();
400 contents_title_view->SetLayoutManager(
401 new views::BoxLayout(views::BoxLayout::kVertical,
402 kMinimumHorizontalMargin,
403 kTitleVerticalMargin,
404 kTitleElementSpacing));
406 bool need_account_switcher =
407 provider_ && provider_->GetNotifierGroupCount() > 1;
408 int top_label_resource_id =
409 need_account_switcher ? IDS_MESSAGE_CENTER_SETTINGS_DESCRIPTION_MULTIUSER
410 : IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION;
412 views::Label* top_label =
413 new views::Label(l10n_util::GetStringUTF16(top_label_resource_id));
415 top_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
416 top_label->SetMultiLine(true);
417 top_label->set_border(views::Border::CreateEmptyBorder(
418 0, kMenuButtonInnateMargin, 0, kMenuButtonInnateMargin));
419 contents_title_view->AddChildView(top_label);
421 string16 notifier_group_text;
422 if (provider_) {
423 const NotifierGroup& active_group = provider_->GetActiveNotifierGroup();
424 notifier_group_text = active_group.login_info.empty()
425 ? active_group.name
426 : active_group.login_info;
429 if (need_account_switcher) {
430 notifier_group_selector_ =
431 new views::MenuButton(NULL, notifier_group_text, this, true);
432 notifier_group_selector_->set_border(new NotifierGroupMenuButtonBorder);
433 notifier_group_selector_->set_focus_border(NULL);
434 notifier_group_selector_->set_animate_on_state_change(false);
435 notifier_group_selector_->set_focusable(true);
436 contents_title_view->AddChildView(notifier_group_selector_);
439 contents_view->AddChildView(contents_title_view);
441 for (size_t i = 0; i < notifiers.size(); ++i) {
442 NotifierButton* button = new NotifierButton(notifiers[i], this);
443 EntryView* entry = new EntryView(button);
444 entry->set_focusable(true);
445 contents_view->AddChildView(entry);
446 buttons_.insert(button);
449 scroller_->SetContents(contents_view);
451 contents_view->SetBoundsRect(gfx::Rect(contents_view->GetPreferredSize()));
452 InvalidateLayout();
455 void NotifierSettingsView::Layout() {
456 int title_height = title_label_->GetHeightForWidth(width());
457 title_label_->SetBounds(0, 0, width(), title_height);
459 views::View* contents_view = scroller_->contents();
460 int content_width = width();
461 int content_height = contents_view->GetHeightForWidth(content_width);
462 if (title_height + content_height > height()) {
463 content_width -= scroller_->GetScrollBarWidth();
464 content_height = contents_view->GetHeightForWidth(content_width);
466 contents_view->SetBounds(0, 0, content_width, content_height);
467 scroller_->SetBounds(0, title_height, width(), height() - title_height);
470 gfx::Size NotifierSettingsView::GetMinimumSize() {
471 gfx::Size size(kMinimumWindowWidth, kMinimumWindowHeight);
472 int total_height = title_label_->GetPreferredSize().height() +
473 scroller_->contents()->GetPreferredSize().height();
474 if (total_height > kMinimumWindowHeight)
475 size.Enlarge(scroller_->GetScrollBarWidth(), 0);
476 return size;
479 gfx::Size NotifierSettingsView::GetPreferredSize() {
480 gfx::Size preferred_size;
481 std::vector<gfx::Size> child_sizes;
482 gfx::Size title_size = title_label_->GetPreferredSize();
483 gfx::Size content_size = scroller_->contents()->GetPreferredSize();
484 return gfx::Size(std::max(title_size.width(), content_size.width()),
485 title_size.height() + content_size.height());
488 bool NotifierSettingsView::OnKeyPressed(const ui::KeyEvent& event) {
489 if (event.key_code() == ui::VKEY_ESCAPE) {
490 GetWidget()->Close();
491 return true;
494 return scroller_->OnKeyPressed(event);
497 bool NotifierSettingsView::OnMouseWheel(const ui::MouseWheelEvent& event) {
498 return scroller_->OnMouseWheel(event);
501 void NotifierSettingsView::ButtonPressed(views::Button* sender,
502 const ui::Event& event) {
503 if (sender == title_arrow_) {
504 MessageCenterView* center_view = static_cast<MessageCenterView*>(parent());
505 center_view->SetSettingsVisible(!center_view->settings_visible());
506 return;
509 std::set<NotifierButton*>::iterator iter = buttons_.find(
510 static_cast<NotifierButton*>(sender));
512 if (iter == buttons_.end())
513 return;
515 (*iter)->SetChecked(!(*iter)->checked());
516 if (provider_)
517 provider_->SetNotifierEnabled((*iter)->notifier(), (*iter)->checked());
520 void NotifierSettingsView::OnMenuButtonClicked(views::View* source,
521 const gfx::Point& point) {
522 notifier_group_menu_model_.reset(new NotifierGroupMenuModel(provider_));
523 notifier_group_menu_runner_.reset(
524 new views::MenuRunner(notifier_group_menu_model_.get()));
525 gfx::Rect menu_anchor = source->GetBoundsInScreen();
526 menu_anchor.Inset(
527 gfx::Insets(0, kMenuWhitespaceOffset, 0, kMenuWhitespaceOffset));
528 if (views::MenuRunner::MENU_DELETED ==
529 notifier_group_menu_runner_->RunMenuAt(GetWidget(),
530 notifier_group_selector_,
531 menu_anchor,
532 views::MenuItemView::BUBBLE_ABOVE,
533 ui::MENU_SOURCE_MOUSE,
534 views::MenuRunner::CONTEXT_MENU))
535 return;
536 MessageCenterView* center_view = static_cast<MessageCenterView*>(parent());
537 center_view->OnSettingsChanged();
540 } // namespace message_center