Mailbox support for texture layers.
[chromium-blink-merge.git] / ui / message_center / message_center_bubble.cc
blobfc89b2971762e137204ec19e994170ee051cec09
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
3 // found in the LICENSE file.
5 #include "ui/message_center/message_center_bubble.h"
7 #include "grit/ui_strings.h"
8 #include "ui/base/l10n/l10n_util.h"
9 #include "ui/base/resource/resource_bundle.h"
10 #include "ui/gfx/size.h"
11 #include "ui/message_center/message_view.h"
12 #include "ui/message_center/message_view_factory.h"
13 #include "ui/views/controls/button/text_button.h"
14 #include "ui/views/controls/label.h"
15 #include "ui/views/controls/scroll_view.h"
16 #include "ui/views/layout/box_layout.h"
17 #include "ui/views/layout/grid_layout.h"
18 #include "ui/views/painter.h"
19 #include "ui/views/view.h"
20 #include "ui/views/widget/widget.h"
22 namespace message_center {
24 namespace {
26 const int kMessageBubbleBaseMinHeight = 80;
27 const int kMessageBubbleBaseMaxHeight = 400;
28 const SkColor kBorderDarkColor = SkColorSetRGB(0xaa, 0xaa, 0xaa);
30 // The view for the buttons at the bottom of the web notification tray.
31 class WebNotificationButtonView : public views::View,
32 public views::ButtonListener {
33 public:
34 explicit WebNotificationButtonView(NotificationList::Delegate* list_delegate)
35 : list_delegate_(list_delegate),
36 close_all_button_(NULL) {
37 set_background(views::Background::CreateBackgroundPainter(
38 true,
39 views::Painter::CreateVerticalGradient(
40 MessageBubbleBase::kHeaderBackgroundColorLight,
41 MessageBubbleBase::kHeaderBackgroundColorDark)));
42 set_border(views::Border::CreateSolidSidedBorder(
43 2, 0, 0, 0, kBorderDarkColor));
45 views::GridLayout* layout = new views::GridLayout(this);
46 SetLayoutManager(layout);
47 views::ColumnSet* columns = layout->AddColumnSet(0);
48 columns->AddPaddingColumn(100, 0);
49 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
50 0, /* resize percent */
51 views::GridLayout::USE_PREF, 0, 0);
52 columns->AddPaddingColumn(0, 4);
54 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
55 close_all_button_ = new views::TextButton(
56 this, rb.GetLocalizedString(IDS_MESSAGE_CENTER_CLEAR_ALL));
57 close_all_button_->set_alignment(views::TextButton::ALIGN_CENTER);
58 close_all_button_->set_focusable(true);
59 close_all_button_->set_request_focus_on_press(false);
61 layout->AddPaddingRow(0, 4);
62 layout->StartRow(0, 0);
63 layout->AddView(close_all_button_);
66 virtual ~WebNotificationButtonView() {}
68 void SetCloseAllVisible(bool visible) {
69 close_all_button_->SetVisible(visible);
72 // Overridden from ButtonListener.
73 virtual void ButtonPressed(views::Button* sender,
74 const ui::Event& event) OVERRIDE {
75 if (sender == close_all_button_)
76 list_delegate_->SendRemoveAllNotifications();
79 private:
80 NotificationList::Delegate* list_delegate_;
81 views::TextButton* close_all_button_;
83 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView);
86 // A custom scroll-view that has a specified size.
87 class FixedSizedScrollView : public views::ScrollView {
88 public:
89 FixedSizedScrollView() {
90 set_focusable(true);
91 set_notify_enter_exit_on_child(true);
94 virtual ~FixedSizedScrollView() {}
96 void SetFixedSize(const gfx::Size& size) {
97 if (fixed_size_ == size)
98 return;
99 fixed_size_ = size;
100 PreferredSizeChanged();
103 // views::View overrides.
104 virtual gfx::Size GetPreferredSize() OVERRIDE {
105 gfx::Size size = fixed_size_.IsEmpty() ?
106 contents()->GetPreferredSize() : fixed_size_;
107 gfx::Insets insets = GetInsets();
108 size.Enlarge(insets.width(), insets.height());
109 return size;
112 virtual void Layout() OVERRIDE {
113 gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize());
114 bounds.set_width(std::max(0, width() - GetScrollBarWidth()));
115 contents()->SetBoundsRect(bounds);
117 views::ScrollView::Layout();
118 if (!vertical_scroll_bar()->visible()) {
119 gfx::Rect bounds = contents()->bounds();
120 bounds.set_width(bounds.width() + GetScrollBarWidth());
121 contents()->SetBoundsRect(bounds);
125 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE {
126 gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize());
127 bounds.set_width(std::max(0, width() - GetScrollBarWidth()));
128 contents()->SetBoundsRect(bounds);
131 private:
132 gfx::Size fixed_size_;
134 DISALLOW_COPY_AND_ASSIGN(FixedSizedScrollView);
137 // Container for the messages.
138 class ScrollContentView : public views::View {
139 public:
140 ScrollContentView() {
141 views::BoxLayout* layout =
142 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1);
143 layout->set_spread_blank_space(true);
144 SetLayoutManager(layout);
147 virtual ~ScrollContentView() {
150 virtual gfx::Size GetPreferredSize() OVERRIDE {
151 if (!preferred_size_.IsEmpty())
152 return preferred_size_;
153 return views::View::GetPreferredSize();
156 void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; }
158 private:
159 gfx::Size preferred_size_;
160 DISALLOW_COPY_AND_ASSIGN(ScrollContentView);
163 } // namespace
165 // Message Center contents.
166 class MessageCenterContentsView : public views::View {
167 public:
168 explicit MessageCenterContentsView(NotificationList::Delegate* list_delegate)
169 : list_delegate_(list_delegate) {
170 SetLayoutManager(
171 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
173 scroll_content_ = new ScrollContentView;
174 scroller_ = new FixedSizedScrollView;
175 scroller_->SetContents(scroll_content_);
176 AddChildView(scroller_);
178 scroller_->SetPaintToLayer(true);
179 scroller_->SetFillsBoundsOpaquely(false);
180 scroller_->layer()->SetMasksToBounds(true);
182 button_view_ = new WebNotificationButtonView(list_delegate);
183 AddChildView(button_view_);
186 void FocusContents() {
187 scroller_->RequestFocus();
190 void Update(const NotificationList::Notifications& notifications) {
191 scroll_content_->RemoveAllChildViews(true);
192 scroll_content_->set_preferred_size(gfx::Size());
193 size_t num_children = 0;
194 for (NotificationList::Notifications::const_iterator iter =
195 notifications.begin(); iter != notifications.end(); ++iter) {
196 MessageView* view =
197 MessageViewFactory::ViewForNotification(*iter, list_delegate_);
198 view->set_scroller(scroller_);
199 view->SetUpView();
200 scroll_content_->AddChildView(view);
201 if (++num_children >=
202 NotificationList::kMaxVisibleMessageCenterNotifications) {
203 break;
206 if (num_children == 0) {
207 views::Label* label = new views::Label(l10n_util::GetStringUTF16(
208 IDS_MESSAGE_CENTER_NO_MESSAGES));
209 label->SetFont(label->font().DeriveFont(1));
210 label->SetEnabledColor(SK_ColorGRAY);
211 scroll_content_->AddChildView(label);
212 button_view_->SetCloseAllVisible(false);
213 } else {
214 button_view_->SetCloseAllVisible(true);
216 SizeScrollContent();
217 Layout();
218 if (GetWidget())
219 GetWidget()->GetRootView()->SchedulePaint();
222 size_t NumMessageViews() const {
223 return scroll_content_->child_count();
226 private:
227 void SizeScrollContent() {
228 gfx::Size scroll_size = scroll_content_->GetPreferredSize();
229 const int button_height = button_view_->GetPreferredSize().height();
230 const int min_height = kMessageBubbleBaseMinHeight - button_height;
231 const int max_height = kMessageBubbleBaseMaxHeight - button_height;
232 int scroll_height = std::min(std::max(
233 scroll_size.height(), min_height), max_height);
234 scroll_size.set_height(scroll_height);
235 if (scroll_height == min_height)
236 scroll_content_->set_preferred_size(scroll_size);
237 else
238 scroll_content_->set_preferred_size(gfx::Size());
239 scroller_->SetFixedSize(scroll_size);
240 scroller_->SizeToPreferredSize();
241 scroll_content_->InvalidateLayout();
244 NotificationList::Delegate* list_delegate_;
245 FixedSizedScrollView* scroller_;
246 ScrollContentView* scroll_content_;
247 WebNotificationButtonView* button_view_;
249 DISALLOW_COPY_AND_ASSIGN(MessageCenterContentsView);
252 // Message Center Bubble.
253 MessageCenterBubble::MessageCenterBubble(NotificationList::Delegate* delegate)
254 : MessageBubbleBase(delegate),
255 contents_view_(NULL) {
258 MessageCenterBubble::~MessageCenterBubble() {}
260 views::TrayBubbleView::InitParams MessageCenterBubble::GetInitParams(
261 views::TrayBubbleView::AnchorAlignment anchor_alignment) {
262 views::TrayBubbleView::InitParams init_params =
263 GetDefaultInitParams(anchor_alignment);
264 init_params.max_height = kMessageBubbleBaseMaxHeight;
265 init_params.can_activate = true;
266 return init_params;
269 void MessageCenterBubble::InitializeContents(
270 views::TrayBubbleView* new_bubble_view) {
271 set_bubble_view(new_bubble_view);
272 contents_view_ = new MessageCenterContentsView(list_delegate());
273 bubble_view()->AddChildView(contents_view_);
274 UpdateBubbleView();
275 contents_view_->FocusContents();
278 void MessageCenterBubble::OnBubbleViewDestroyed() {
279 contents_view_ = NULL;
282 void MessageCenterBubble::UpdateBubbleView() {
283 if (!bubble_view())
284 return; // Could get called after view is closed
285 NotificationList::Notifications notifications;
286 list_delegate()->GetNotificationList()->GetNotifications(&notifications);
287 contents_view_->Update(notifications);
288 bubble_view()->Show();
289 bubble_view()->UpdateBubble();
292 void MessageCenterBubble::OnMouseEnteredView() {
295 void MessageCenterBubble::OnMouseExitedView() {
298 size_t MessageCenterBubble::NumMessageViewsForTest() const {
299 return contents_view_->NumMessageViews();
302 } // namespace message_center