Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / screen_capture_notification_ui_views.cc
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/screen_capture_notification_ui.h"
6
7 #include "ash/shell.h"
8 #include "chrome/app/chrome_dll_resource.h"
9 #include "chrome/browser/ui/views/chrome_views_export.h"
10 #include "chrome/grit/generated_resources.h"
11 #include "grit/theme_resources.h"
12 #include "ui/aura/window_event_dispatcher.h"
13 #include "ui/base/hit_test.h"
14 #include "ui/base/l10n/l10n_util.h"
15 #include "ui/base/resource/resource_bundle.h"
16 #include "ui/views/bubble/bubble_border.h"
17 #include "ui/views/bubble/bubble_frame_view.h"
18 #include "ui/views/controls/button/blue_button.h"
19 #include "ui/views/controls/image_view.h"
20 #include "ui/views/controls/link.h"
21 #include "ui/views/controls/link_listener.h"
22 #include "ui/views/view.h"
23 #include "ui/views/widget/widget.h"
24 #include "ui/views/widget/widget_delegate.h"
25 #include "ui/wm/core/shadow_types.h"
26
27 #if defined(OS_WIN)
28 #include "ui/views/win/hwnd_util.h"
29 #endif
30
31 namespace {
32
33 const int kMinimumWidth = 460;
34 const int kMaximumWidth = 1000;
35 const int kHorizontalMargin = 10;
36 const float kWindowAlphaValue = 0.85f;
37 const int kPaddingVertical = 5;
38 const int kPaddingHorizontal = 10;
39
40 namespace {
41
42 // A ClientView that overrides NonClientHitTest() so that the whole window area
43 // acts as a window caption, except a rect specified using set_client_rect().
44 // ScreenCaptureNotificationUIViews uses this class to make the notification bar
45 // draggable.
46 class NotificationBarClientView : public views::ClientView {
47  public:
48   NotificationBarClientView(views::Widget* widget, views::View* view)
49       : views::ClientView(widget, view) {
50   }
51   virtual ~NotificationBarClientView() {}
52
53   void set_client_rect(const gfx::Rect& rect) { rect_ = rect; }
54
55   // views::ClientView overrides.
56   virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE  {
57     if (!bounds().Contains(point))
58       return HTNOWHERE;
59     // The whole window is HTCAPTION, except the |rect_|.
60     if (rect_.Contains(gfx::PointAtOffsetFromOrigin(point - bounds().origin())))
61       return HTCLIENT;
62
63     return HTCAPTION;
64   }
65
66  private:
67   gfx::Rect rect_;
68
69   DISALLOW_COPY_AND_ASSIGN(NotificationBarClientView);
70 };
71
72 }  // namespace
73
74 // ScreenCaptureNotificationUI implementation using Views.
75 class ScreenCaptureNotificationUIViews
76     : public ScreenCaptureNotificationUI,
77       public views::WidgetDelegateView,
78       public views::ButtonListener,
79       public views::LinkListener {
80  public:
81   explicit ScreenCaptureNotificationUIViews(const base::string16& text);
82   virtual ~ScreenCaptureNotificationUIViews();
83
84   // ScreenCaptureNotificationUI interface.
85   virtual gfx::NativeViewId OnStarted(const base::Closure& stop_callback)
86       OVERRIDE;
87
88   // views::View overrides.
89   virtual gfx::Size GetPreferredSize() const OVERRIDE;
90   virtual void Layout() OVERRIDE;
91
92   // views::WidgetDelegateView overrides.
93   virtual void DeleteDelegate() OVERRIDE;
94   virtual views::View* GetContentsView() OVERRIDE;
95   virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
96   virtual views::NonClientFrameView* CreateNonClientFrameView(
97       views::Widget* widget) OVERRIDE;
98   virtual base::string16 GetWindowTitle() const OVERRIDE;
99   virtual bool ShouldShowWindowTitle() const OVERRIDE;
100   virtual bool ShouldShowCloseButton() const OVERRIDE;
101   virtual bool CanActivate() const OVERRIDE;
102
103   // views::ButtonListener interface.
104   virtual void ButtonPressed(views::Button* sender,
105                              const ui::Event& event) OVERRIDE;
106
107   // views::LinkListener interface.
108   virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
109
110  private:
111   // Helper to call |stop_callback_|.
112   void NotifyStopped();
113
114   const base::string16 text_;
115   base::Closure stop_callback_;
116   NotificationBarClientView* client_view_;
117   views::ImageView* gripper_;
118   views::Label* label_;
119   views::BlueButton* stop_button_;
120   views::Link* hide_link_;
121
122   DISALLOW_COPY_AND_ASSIGN(ScreenCaptureNotificationUIViews);
123 };
124
125 ScreenCaptureNotificationUIViews::ScreenCaptureNotificationUIViews(
126     const base::string16& text)
127     : text_(text),
128       client_view_(NULL),
129       gripper_(NULL),
130       label_(NULL),
131       stop_button_(NULL),
132       hide_link_(NULL) {
133   set_owned_by_client();
134
135   gripper_ = new views::ImageView();
136   gripper_->SetImage(
137       ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
138           IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP));
139   AddChildView(gripper_);
140
141   label_ = new views::Label();
142   AddChildView(label_);
143
144   base::string16 stop_text =
145       l10n_util::GetStringUTF16(IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_STOP);
146   stop_button_ = new views::BlueButton(this, stop_text);
147   AddChildView(stop_button_);
148
149   // TODO(jiayl): IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON is used for the need to
150   // merge to M34. Change it to a new IDS_ after the merge.
151   hide_link_ = new views::Link(
152       l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON));
153   hide_link_->set_listener(this);
154   hide_link_->SetUnderline(false);
155   AddChildView(hide_link_);
156 }
157
158 ScreenCaptureNotificationUIViews::~ScreenCaptureNotificationUIViews() {
159   stop_callback_.Reset();
160   delete GetWidget();
161 }
162
163 gfx::NativeViewId ScreenCaptureNotificationUIViews::OnStarted(
164     const base::Closure& stop_callback) {
165   stop_callback_ = stop_callback;
166
167   label_->SetElideBehavior(gfx::ELIDE_MIDDLE);
168   label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
169   label_->SetText(text_);
170
171   views::Widget* widget = new views::Widget;
172
173   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
174   params.delegate = this;
175   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
176   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
177   params.remove_standard_frame = true;
178   params.keep_on_top = true;
179
180   // TODO(sergeyu): The notification bar must be shown on the monitor that's
181   // being captured. Make sure it's always the case. Currently we always capture
182   // the primary monitor.
183   if (ash::Shell::HasInstance())
184     params.context = ash::Shell::GetPrimaryRootWindow();
185
186   widget->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM);
187   widget->Init(params);
188   widget->SetAlwaysOnTop(true);
189
190   set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
191       GetSystemColor(ui::NativeTheme::kColorId_DialogBackground)));
192
193   gfx::Screen* screen = gfx::Screen::GetNativeScreen();
194   // TODO(sergeyu): Move the notification to the display being captured when
195   // per-display screen capture is supported.
196   gfx::Rect work_area = screen->GetPrimaryDisplay().work_area();
197
198   // Place the bar in the center of the bottom of the display.
199   gfx::Size size = widget->non_client_view()->GetPreferredSize();
200   gfx::Rect bounds(
201       work_area.x() + work_area.width() / 2 - size.width() / 2,
202       work_area.y() + work_area.height() - size.height(),
203       size.width(), size.height());
204   widget->SetBounds(bounds);
205   widget->Show();
206   // This has to be called after Show() to have effect.
207   widget->SetOpacity(0xFF * kWindowAlphaValue);
208
209 #if defined(OS_WIN)
210   return gfx::NativeViewId(views::HWNDForWidget(widget));
211 #else
212   return 0;
213 #endif
214 }
215
216 gfx::Size ScreenCaptureNotificationUIViews::GetPreferredSize() const {
217   gfx::Size grip_size = gripper_->GetPreferredSize();
218   gfx::Size label_size = label_->GetPreferredSize();
219   gfx::Size stop_button_size = stop_button_->GetPreferredSize();
220   gfx::Size hide_link_size = hide_link_->GetPreferredSize();
221   int width = kHorizontalMargin * 3 + grip_size.width() + label_size.width() +
222       stop_button_size.width() + hide_link_size.width();
223   width = std::max(width, kMinimumWidth);
224   width = std::min(width, kMaximumWidth);
225   return gfx::Size(width, std::max(label_size.height(),
226                                    std::max(hide_link_size.height(),
227                                             stop_button_size.height())));
228 }
229
230 void ScreenCaptureNotificationUIViews::Layout() {
231   gfx::Rect grip_rect(gripper_->GetPreferredSize());
232   grip_rect.set_y((bounds().height() - grip_rect.height()) / 2);
233   gripper_->SetBoundsRect(grip_rect);
234
235   gfx::Rect stop_button_rect(stop_button_->GetPreferredSize());
236   gfx::Rect hide_link_rect(hide_link_->GetPreferredSize());
237
238   hide_link_rect.set_x(bounds().width() - hide_link_rect.width());
239   hide_link_rect.set_y((bounds().height() - hide_link_rect.height()) / 2);
240   hide_link_->SetBoundsRect(hide_link_rect);
241
242   stop_button_rect.set_x(
243       hide_link_rect.x() - kHorizontalMargin - stop_button_rect.width());
244   stop_button_->SetBoundsRect(stop_button_rect);
245
246   gfx::Rect label_rect;
247   label_rect.set_x(grip_rect.right() + kHorizontalMargin);
248   label_rect.set_width(
249       stop_button_rect.x() - kHorizontalMargin - label_rect.x());
250   label_rect.set_height(bounds().height());
251   label_->SetBoundsRect(label_rect);
252
253   client_view_->set_client_rect(gfx::Rect(
254       stop_button_rect.x(), stop_button_rect.y(),
255       stop_button_rect.width() + kHorizontalMargin + hide_link_rect.width(),
256       std::max(stop_button_rect.height(), hide_link_rect.height())));
257 }
258
259 void ScreenCaptureNotificationUIViews::DeleteDelegate() {
260   NotifyStopped();
261 }
262
263 views::View* ScreenCaptureNotificationUIViews::GetContentsView() {
264   return this;
265 }
266
267 views::ClientView* ScreenCaptureNotificationUIViews::CreateClientView(
268     views::Widget* widget) {
269   DCHECK(!client_view_);
270   client_view_ = new NotificationBarClientView(widget, this);
271   return client_view_;
272 }
273
274 views::NonClientFrameView*
275 ScreenCaptureNotificationUIViews::CreateNonClientFrameView(
276     views::Widget* widget) {
277   views::BubbleFrameView* frame = new views::BubbleFrameView(
278       gfx::Insets(kPaddingVertical,
279                   kPaddingHorizontal,
280                   kPaddingVertical,
281                   kPaddingHorizontal));
282   SkColor color = widget->GetNativeTheme()->GetSystemColor(
283       ui::NativeTheme::kColorId_DialogBackground);
284   frame->SetBubbleBorder(scoped_ptr<views::BubbleBorder>(
285       new views::BubbleBorder(views::BubbleBorder::NONE,
286                               views::BubbleBorder::SMALL_SHADOW,
287                               color)));
288   return frame;
289 }
290
291 base::string16 ScreenCaptureNotificationUIViews::GetWindowTitle() const {
292   return text_;
293 }
294
295 bool ScreenCaptureNotificationUIViews::ShouldShowWindowTitle() const {
296   return false;
297 }
298
299 bool ScreenCaptureNotificationUIViews::ShouldShowCloseButton() const {
300   return false;
301 }
302
303 bool ScreenCaptureNotificationUIViews::CanActivate() const {
304   // When the window is visible, it can be activated so the mouse clicks
305   // can be sent to the window; when the window is minimized, we don't want it
306   // to activate, otherwise it sometimes does not show properly on Windows.
307   return GetWidget() && GetWidget()->IsVisible();
308 }
309
310 void ScreenCaptureNotificationUIViews::ButtonPressed(views::Button* sender,
311                                                      const ui::Event& event) {
312   NotifyStopped();
313 }
314
315 void ScreenCaptureNotificationUIViews::LinkClicked(views::Link* source,
316                                                    int event_flags) {
317   GetWidget()->Minimize();
318 }
319
320 void ScreenCaptureNotificationUIViews::NotifyStopped() {
321   if (!stop_callback_.is_null()) {
322     base::Closure callback = stop_callback_;
323     stop_callback_.Reset();
324     callback.Run();
325   }
326 }
327
328 }  // namespace
329
330 scoped_ptr<ScreenCaptureNotificationUI> ScreenCaptureNotificationUI::Create(
331     const base::string16& text) {
332   return scoped_ptr<ScreenCaptureNotificationUI>(
333       new ScreenCaptureNotificationUIViews(text));
334 }