1 // Copyright 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 "chrome/browser/ui/views/message_center/message_center_widget_delegate.h"
9 #include "chrome/browser/ui/views/message_center/message_center_frame_view.h"
10 #include "content/public/browser/user_metrics.h"
11 #include "ui/base/accessibility/accessible_view_state.h"
12 #include "ui/gfx/screen.h"
13 #include "ui/message_center/message_center_style.h"
14 #include "ui/message_center/message_center_util.h"
15 #include "ui/message_center/views/message_center_view.h"
16 #include "ui/native_theme/native_theme.h"
17 #include "ui/views/border.h"
18 #include "ui/views/layout/box_layout.h"
19 #include "ui/views/widget/widget.h"
22 #include "ui/views/win/hwnd_util.h"
26 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
29 namespace message_center
{
31 MessageCenterWidgetDelegate::MessageCenterWidgetDelegate(
32 WebNotificationTray
* tray
,
33 MessageCenterTray
* mc_tray
,
34 bool initially_settings_visible
,
35 const PositionInfo
& pos_info
)
36 : MessageCenterView(tray
->message_center(),
39 initially_settings_visible
,
40 pos_info
.message_center_alignment
&
41 ALIGNMENT_TOP
), // Show buttons on top if message
42 // center is top aligned
45 // A WidgetDelegate should be deleted on DeleteDelegate.
46 set_owned_by_client();
48 views::BoxLayout
* layout
=
49 new views::BoxLayout(views::BoxLayout::kVertical
, 0, 0, 0);
50 layout
->set_spread_blank_space(true);
51 SetLayoutManager(layout
);
53 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE
, ui::EF_NONE
));
55 if (get_use_acceleration_when_possible()) {
56 SetPaintToLayer(true);
57 SetFillsBoundsOpaquely(true);
63 MessageCenterWidgetDelegate::~MessageCenterWidgetDelegate() {
64 views::Widget
* widget
= GetWidget();
66 widget
->RemoveObserver(this);
70 views::View
* MessageCenterWidgetDelegate::GetContentsView() {
74 views::NonClientFrameView
*
75 MessageCenterWidgetDelegate::CreateNonClientFrameView(views::Widget
* widget
) {
76 MessageCenterFrameView
* frame_view
= new MessageCenterFrameView();
77 border_insets_
= frame_view
->GetInsets();
81 void MessageCenterWidgetDelegate::DeleteDelegate() {
85 views::Widget
* MessageCenterWidgetDelegate::GetWidget() {
86 return View::GetWidget();
89 const views::Widget
* MessageCenterWidgetDelegate::GetWidget() const {
90 return View::GetWidget();
93 void MessageCenterWidgetDelegate::OnWidgetActivationChanged(
94 views::Widget
* widget
,
97 tray_
->SendHideMessageCenter();
101 void MessageCenterWidgetDelegate::OnWidgetClosing(views::Widget
* widget
) {
103 tray_
->MarkMessageCenterHidden();
106 void MessageCenterWidgetDelegate::PreferredSizeChanged() {
107 GetWidget()->SetBounds(GetMessageCenterBounds());
108 views::View::PreferredSizeChanged();
111 gfx::Size
MessageCenterWidgetDelegate::GetPreferredSize() {
112 int preferred_width
= kNotificationWidth
+ 2 * kMarginBetweenItems
;
113 return gfx::Size(preferred_width
, GetHeightForWidth(preferred_width
));
116 gfx::Size
MessageCenterWidgetDelegate::GetMaximumSize() {
117 gfx::Size size
= GetPreferredSize();
121 int MessageCenterWidgetDelegate::GetHeightForWidth(int width
) {
122 int height
= MessageCenterView::GetHeightForWidth(width
);
123 return (pos_info_
.max_height
!= 0) ?
124 std::min(height
, pos_info_
.max_height
- border_insets_
.height()) : height
;
127 bool MessageCenterWidgetDelegate::AcceleratorPressed(
128 const ui::Accelerator
& accelerator
) {
129 if (accelerator
.key_code() != ui::VKEY_ESCAPE
)
131 tray_
->SendHideMessageCenter();
135 void MessageCenterWidgetDelegate::InitWidget() {
136 views::Widget
* widget
= new views::Widget();
137 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_BUBBLE
);
138 params
.opacity
= views::Widget::InitParams::TRANSLUCENT_WINDOW
;
139 params
.delegate
= this;
140 params
.keep_on_top
= true;
141 params
.top_level
= true;
143 // This class is not used in Ash; there is another container for the message
144 // center that's used there. So, we must be in a Views + Ash environment. We
145 // want the notification center to be available on both desktops. Setting the
146 // |native_widget| variable here ensures that the widget is hosted on the
148 params
.native_widget
= new views::DesktopNativeWidgetAura(widget
);
150 widget
->Init(params
);
152 widget
->AddObserver(this);
153 widget
->StackAtTop();
154 widget
->SetAlwaysOnTop(true);
156 const NotificationList::Notifications
& notifications
=
157 tray_
->message_center()->GetVisibleNotifications();
158 SetNotifications(notifications
);
160 widget
->SetBounds(GetMessageCenterBounds());
165 gfx::Point
MessageCenterWidgetDelegate::GetCorrectedAnchor(
166 gfx::Size calculated_size
) {
167 gfx::Point corrected_anchor
= pos_info_
.inital_anchor_point
;
169 // Inset the width slightly so that the click point is not exactly on the edge
170 // of the message center but somewhere within the middle 60 %.
171 int insetted_width
= (calculated_size
.width() * 4) / 5;
173 if (pos_info_
.taskbar_alignment
== ALIGNMENT_TOP
||
174 pos_info_
.taskbar_alignment
== ALIGNMENT_BOTTOM
) {
175 int click_point_x
= tray_
->mouse_click_point().x();
177 if (pos_info_
.message_center_alignment
& ALIGNMENT_RIGHT
) {
178 int opposite_x_corner
=
179 pos_info_
.inital_anchor_point
.x() - insetted_width
;
181 // If the click point is outside the x axis length of the message center,
182 // push the message center towards the left to align with the click point.
183 if (opposite_x_corner
> click_point_x
)
184 corrected_anchor
.set_x(pos_info_
.inital_anchor_point
.x() -
185 (opposite_x_corner
- click_point_x
));
187 int opposite_x_corner
=
188 pos_info_
.inital_anchor_point
.x() + insetted_width
;
190 if (opposite_x_corner
< click_point_x
)
191 corrected_anchor
.set_x(pos_info_
.inital_anchor_point
.x() +
192 (click_point_x
- opposite_x_corner
));
194 } else if (pos_info_
.taskbar_alignment
== ALIGNMENT_LEFT
||
195 pos_info_
.taskbar_alignment
== ALIGNMENT_RIGHT
) {
196 int click_point_y
= tray_
->mouse_click_point().y();
198 if (pos_info_
.message_center_alignment
& ALIGNMENT_BOTTOM
) {
199 int opposite_y_corner
=
200 pos_info_
.inital_anchor_point
.y() - insetted_width
;
202 // If the click point is outside the y axis length of the message center,
203 // push the message center upwards to align with the click point.
204 if (opposite_y_corner
> click_point_y
)
205 corrected_anchor
.set_y(pos_info_
.inital_anchor_point
.y() -
206 (opposite_y_corner
- click_point_y
));
208 int opposite_y_corner
=
209 pos_info_
.inital_anchor_point
.y() + insetted_width
;
211 if (opposite_y_corner
< click_point_y
)
212 corrected_anchor
.set_y(pos_info_
.inital_anchor_point
.y() +
213 (click_point_y
- opposite_y_corner
));
216 return corrected_anchor
;
219 gfx::Rect
MessageCenterWidgetDelegate::GetMessageCenterBounds() {
220 gfx::Size size
= GetPreferredSize();
222 // Make space for borders on sides.
223 size
.Enlarge(border_insets_
.width(), border_insets_
.height());
224 gfx::Rect
bounds(size
);
226 gfx::Point corrected_anchor
= GetCorrectedAnchor(size
);
228 if (pos_info_
.message_center_alignment
& ALIGNMENT_TOP
)
229 bounds
.set_y(corrected_anchor
.y());
230 if (pos_info_
.message_center_alignment
& ALIGNMENT_BOTTOM
)
231 bounds
.set_y(corrected_anchor
.y() - size
.height());
232 if (pos_info_
.message_center_alignment
& ALIGNMENT_LEFT
)
233 bounds
.set_x(corrected_anchor
.x());
234 if (pos_info_
.message_center_alignment
& ALIGNMENT_RIGHT
)
235 bounds
.set_x(corrected_anchor
.x() - size
.width());
240 } // namespace message_center