message_center_widget_delegate.cc revision 2385ea399aae016c0806a4f9ef3c9cfe3d2a39df
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.
4
5#include "chrome/browser/ui/views/message_center/message_center_widget_delegate.h"
6
7#include <complex>
8
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"
20
21#if defined(OS_WIN)
22#include "ui/views/win/hwnd_util.h"
23#endif
24
25namespace message_center {
26
27MessageCenterWidgetDelegate::MessageCenterWidgetDelegate(
28    WebNotificationTray* tray,
29    MessageCenterTray* mc_tray,
30    bool initially_settings_visible,
31    const PositionInfo& pos_info)
32    : MessageCenterView(tray->message_center(),
33                        mc_tray,
34                        pos_info.max_height,
35                        initially_settings_visible,
36                        pos_info.message_center_alignment &
37                            ALIGNMENT_TOP),  // Show buttons on top if message
38                                             // center is top aligned
39      pos_info_(pos_info),
40      tray_(tray) {
41  // A WidgetDelegate should be deleted on DeleteDelegate.
42  set_owned_by_client();
43
44  views::BoxLayout* layout =
45      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
46  layout->set_spread_blank_space(true);
47  SetLayoutManager(layout);
48
49  AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
50
51  if (get_use_acceleration_when_possible()) {
52    SetPaintToLayer(true);
53    SetFillsBoundsOpaquely(true);
54  }
55
56  InitWidget();
57}
58
59MessageCenterWidgetDelegate::~MessageCenterWidgetDelegate() {
60  views::Widget* widget = GetWidget();
61  if (widget) {
62    widget->RemoveObserver(this);
63  }
64}
65
66views::View* MessageCenterWidgetDelegate::GetContentsView() {
67  return this;
68}
69
70views::NonClientFrameView*
71MessageCenterWidgetDelegate::CreateNonClientFrameView(views::Widget* widget) {
72  MessageCenterFrameView* frame_view = new MessageCenterFrameView();
73  border_insets_ = frame_view->GetInsets();
74  return frame_view;
75}
76
77void MessageCenterWidgetDelegate::DeleteDelegate() {
78  delete this;
79}
80
81views::Widget* MessageCenterWidgetDelegate::GetWidget() {
82  return View::GetWidget();
83}
84
85const views::Widget* MessageCenterWidgetDelegate::GetWidget() const {
86  return View::GetWidget();
87}
88
89void MessageCenterWidgetDelegate::OnWidgetActivationChanged(
90    views::Widget* widget,
91    bool active) {
92  if (!active) {
93    tray_->SendHideMessageCenter();
94  }
95}
96
97void MessageCenterWidgetDelegate::OnWidgetClosing(views::Widget* widget) {
98  SetIsClosing(true);
99  tray_->MarkMessageCenterHidden();
100}
101
102void MessageCenterWidgetDelegate::PreferredSizeChanged() {
103  GetWidget()->SetBounds(GetMessageCenterBounds());
104  views::View::PreferredSizeChanged();
105}
106
107gfx::Size MessageCenterWidgetDelegate::GetPreferredSize() {
108  int preferred_width = kNotificationWidth + 2 * kMarginBetweenItems;
109  return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
110}
111
112gfx::Size MessageCenterWidgetDelegate::GetMaximumSize() {
113  gfx::Size size = GetPreferredSize();
114  return size;
115}
116
117int MessageCenterWidgetDelegate::GetHeightForWidth(int width) {
118  int height = MessageCenterView::GetHeightForWidth(width);
119  return (pos_info_.max_height != 0) ?
120    std::min(height, pos_info_.max_height - border_insets_.height()) : height;
121}
122
123bool MessageCenterWidgetDelegate::AcceleratorPressed(
124    const ui::Accelerator& accelerator) {
125  if (accelerator.key_code() != ui::VKEY_ESCAPE)
126    return false;
127  tray_->SendHideMessageCenter();
128  return true;
129}
130
131void MessageCenterWidgetDelegate::InitWidget() {
132  views::Widget* widget = new views::Widget();
133  views::Widget::InitParams params(views::Widget::InitParams::TYPE_BUBBLE);
134  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
135  params.delegate = this;
136  params.keep_on_top = true;
137  params.top_level = true;
138  widget->Init(params);
139
140#if defined(OS_WIN)
141  // Remove the Message Center from taskbar and alt-tab rotation.
142  HWND hwnd = views::HWNDForWidget(widget);
143  LONG_PTR ex_styles = ::GetWindowLongPtr(hwnd, GWL_EXSTYLE);
144  ex_styles |= WS_EX_TOOLWINDOW;
145  ::SetWindowLongPtr(hwnd, GWL_EXSTYLE, ex_styles);
146#endif
147
148  widget->AddObserver(this);
149  widget->StackAtTop();
150  widget->SetAlwaysOnTop(true);
151
152  const NotificationList::Notifications& notifications =
153      tray_->message_center()->GetNotifications();
154  SetNotifications(notifications);
155
156  widget->SetBounds(GetMessageCenterBounds());
157  widget->Show();
158  widget->Activate();
159}
160
161gfx::Point MessageCenterWidgetDelegate::GetCorrectedAnchor(
162    gfx::Size calculated_size) {
163  gfx::Point corrected_anchor = pos_info_.inital_anchor_point;
164
165  // Inset the width slightly so that the click point is not exactly on the edge
166  // of the message center but somewhere within the middle 60 %.
167  int insetted_width = (calculated_size.width() * 4) / 5;
168
169  if (pos_info_.taskbar_alignment == ALIGNMENT_TOP ||
170      pos_info_.taskbar_alignment == ALIGNMENT_BOTTOM) {
171    int click_point_x = tray_->mouse_click_point().x();
172
173    if (pos_info_.message_center_alignment & ALIGNMENT_RIGHT) {
174      int opposite_x_corner =
175          pos_info_.inital_anchor_point.x() - insetted_width;
176
177      // If the click point is outside the x axis length of the message center,
178      // push the message center towards the left to align with the click point.
179      if (opposite_x_corner > click_point_x)
180        corrected_anchor.set_x(pos_info_.inital_anchor_point.x() -
181                               (opposite_x_corner - click_point_x));
182    } else {
183      int opposite_x_corner =
184          pos_info_.inital_anchor_point.x() + insetted_width;
185
186      if (opposite_x_corner < click_point_x)
187        corrected_anchor.set_x(pos_info_.inital_anchor_point.x() +
188                               (click_point_x - opposite_x_corner));
189    }
190  } else if (pos_info_.taskbar_alignment == ALIGNMENT_LEFT ||
191             pos_info_.taskbar_alignment == ALIGNMENT_RIGHT) {
192    int click_point_y = tray_->mouse_click_point().y();
193
194    if (pos_info_.message_center_alignment & ALIGNMENT_BOTTOM) {
195      int opposite_y_corner =
196          pos_info_.inital_anchor_point.y() - insetted_width;
197
198      // If the click point is outside the y axis length of the message center,
199      // push the message center upwards to align with the click point.
200      if (opposite_y_corner > click_point_y)
201        corrected_anchor.set_y(pos_info_.inital_anchor_point.y() -
202                               (opposite_y_corner - click_point_y));
203    } else {
204      int opposite_y_corner =
205          pos_info_.inital_anchor_point.y() + insetted_width;
206
207      if (opposite_y_corner < click_point_y)
208        corrected_anchor.set_y(pos_info_.inital_anchor_point.y() +
209                               (click_point_y - opposite_y_corner));
210    }
211  }
212  return corrected_anchor;
213}
214
215gfx::Rect MessageCenterWidgetDelegate::GetMessageCenterBounds() {
216  gfx::Size size = GetPreferredSize();
217
218  // Make space for borders on sides.
219  size.Enlarge(border_insets_.width(), border_insets_.height());
220  gfx::Rect bounds(size);
221
222  gfx::Point corrected_anchor = GetCorrectedAnchor(size);
223
224  if (pos_info_.message_center_alignment & ALIGNMENT_TOP)
225    bounds.set_y(corrected_anchor.y());
226  if (pos_info_.message_center_alignment & ALIGNMENT_BOTTOM)
227    bounds.set_y(corrected_anchor.y() - size.height());
228  if (pos_info_.message_center_alignment & ALIGNMENT_LEFT)
229    bounds.set_x(corrected_anchor.x());
230  if (pos_info_.message_center_alignment & ALIGNMENT_RIGHT)
231    bounds.set_x(corrected_anchor.x() - size.width());
232
233  return bounds;
234}
235
236}  // namespace message_center
237