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/screen_capture_notification_ui.h"
8 #include "chrome/app/chrome_dll_resource.h"
9 #include "chrome/browser/ui/views/chrome_views_export.h"
10 #include "grit/generated_resources.h"
11 #include "grit/theme_resources.h"
12 #include "ui/aura/root_window.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/corewm/shadow_types.h"
21 #include "ui/views/layout/box_layout.h"
22 #include "ui/views/view.h"
23 #include "ui/views/widget/widget.h"
24 #include "ui/views/widget/widget_delegate.h"
28 const int kMinimumWidth
= 460;
29 const int kMaximumWidth
= 1000;
30 const int kHorizontalMargin
= 10;
31 const int kPadding
= 5;
32 const int kPaddingLeft
= 10;
36 // A ClientView that overrides NonClientHitTest() so that the whole window area
37 // acts as a window caption, except a rect specified using SetClientRect().
38 // ScreenCaptureNotificationUIViews uses this class to make the notification bar
40 class NotificationBarClientView
: public views::ClientView
{
42 NotificationBarClientView(views::Widget
* widget
, views::View
* view
)
43 : views::ClientView(widget
, view
) {
45 virtual ~NotificationBarClientView() {}
47 void SetClientRect(const gfx::Rect
& rect
) {
51 // views::ClientView overrides.
52 virtual int NonClientHitTest(const gfx::Point
& point
) OVERRIDE
{
53 if (!bounds().Contains(point
))
55 // The whole window is HTCAPTION, except the |rect_|.
56 if (rect_
.Contains(gfx::PointAtOffsetFromOrigin(point
- bounds().origin())))
65 DISALLOW_COPY_AND_ASSIGN(NotificationBarClientView
);
70 // ScreenCaptureNotificationUI implementation using Views.
71 class ScreenCaptureNotificationUIViews
72 : public ScreenCaptureNotificationUI
,
73 public views::WidgetDelegateView
,
74 public views::ButtonListener
{
76 explicit ScreenCaptureNotificationUIViews(const string16
& text
);
77 virtual ~ScreenCaptureNotificationUIViews();
79 // ScreenCaptureNotificationUI interface.
80 virtual void OnStarted(const base::Closure
& stop_callback
) OVERRIDE
;
82 // views::View overrides.
83 virtual gfx::Size
GetPreferredSize() OVERRIDE
;
84 virtual void Layout() OVERRIDE
;
86 // views::WidgetDelegateView overrides.
87 virtual void DeleteDelegate() OVERRIDE
;
88 virtual views::View
* GetContentsView() OVERRIDE
;
89 virtual views::ClientView
* CreateClientView(views::Widget
* widget
) OVERRIDE
;
90 virtual views::NonClientFrameView
* CreateNonClientFrameView(
91 views::Widget
* widget
) OVERRIDE
;
92 virtual string16
GetWindowTitle() const OVERRIDE
;
93 virtual bool ShouldShowWindowTitle() const OVERRIDE
;
94 virtual bool ShouldShowCloseButton() const OVERRIDE
;
96 // views::ButtonListener interface.
97 virtual void ButtonPressed(views::Button
* sender
,
98 const ui::Event
& event
) OVERRIDE
;
101 // Helper to call |stop_callback_|.
102 void NotifyStopped();
104 const string16 text_
;
105 base::Closure stop_callback_
;
106 NotificationBarClientView
* client_view_
;
107 views::ImageView
* gripper_
;
108 views::Label
* label_
;
109 views::BlueButton
* stop_button_
;
111 DISALLOW_COPY_AND_ASSIGN(ScreenCaptureNotificationUIViews
);
114 ScreenCaptureNotificationUIViews::ScreenCaptureNotificationUIViews(
115 const string16
& text
)
121 set_owned_by_client();
123 set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
124 GetSystemColor(ui::NativeTheme::kColorId_DialogBackground
)));
126 gripper_
= new views::ImageView();
128 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
129 IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP
));
130 AddChildView(gripper_
);
132 label_
= new views::Label();
133 AddChildView(label_
);
136 l10n_util::GetStringUTF16(IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_STOP
);
137 stop_button_
= new views::BlueButton(this, stop_text
);
138 AddChildView(stop_button_
);
141 ScreenCaptureNotificationUIViews::~ScreenCaptureNotificationUIViews() {
142 stop_callback_
.Reset();
146 void ScreenCaptureNotificationUIViews::OnStarted(
147 const base::Closure
& stop_callback
) {
148 stop_callback_
= stop_callback
;
150 label_
->SetElideBehavior(views::Label::ELIDE_IN_MIDDLE
);
151 label_
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
152 label_
->SetText(text_
);
154 views::Widget
* widget
= new views::Widget
;
156 views::Widget::InitParams params
;
157 params
.delegate
= this;
158 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
159 params
.opacity
= views::Widget::InitParams::TRANSLUCENT_WINDOW
;
160 params
.remove_standard_frame
= true;
161 params
.keep_on_top
= true;
162 params
.top_level
= true;
163 params
.can_activate
= false;
166 // TODO(sergeyu): The notification bar must be shown on the monitor that's
167 // being captured. Make sure it's always the case. Currently we always capture
168 // the primary monitor.
169 if (ash::Shell::HasInstance())
170 params
.context
= ash::Shell::GetPrimaryRootWindow();
173 widget
->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM
);
174 widget
->Init(params
);
175 widget
->SetAlwaysOnTop(true);
177 gfx::Screen
* screen
= gfx::Screen::GetNativeScreen();
178 // TODO(sergeyu): Move the notification to the display being captured when
179 // per-display screen capture is supported.
180 gfx::Rect work_area
= screen
->GetPrimaryDisplay().work_area();
182 // Place the bar in the center of the bottom of the display.
183 gfx::Size size
= widget
->non_client_view()->GetPreferredSize();
185 work_area
.x() + work_area
.width() / 2 - size
.width() / 2,
186 work_area
.y() + work_area
.height() - size
.height(),
187 size
.width(), size
.height());
188 widget
->SetBounds(bounds
);
193 gfx::Size
ScreenCaptureNotificationUIViews::GetPreferredSize() {
194 gfx::Size grip_size
= gripper_
->GetPreferredSize();
195 gfx::Size label_size
= child_at(1)->GetPreferredSize();
196 gfx::Size button_size
= child_at(2)->GetPreferredSize();
197 int width
= kHorizontalMargin
* 2 + grip_size
.width() + label_size
.width() +
199 width
= std::max(width
, kMinimumWidth
);
200 width
= std::min(width
, kMaximumWidth
);
201 return gfx::Size(width
, std::max(label_size
.height(), button_size
.height()));
204 void ScreenCaptureNotificationUIViews::Layout() {
205 gfx::Rect
grip_rect(gripper_
->GetPreferredSize());
206 grip_rect
.set_y(bounds().height() / 2 - grip_rect
.height() / 2);
207 gripper_
->SetBoundsRect(grip_rect
);
209 gfx::Rect
button_rect(stop_button_
->GetPreferredSize());
210 button_rect
.set_x(bounds().width() - button_rect
.width());
211 stop_button_
->SetBoundsRect(button_rect
);
213 gfx::Rect label_rect
;
214 label_rect
.set_x(grip_rect
.right() + kHorizontalMargin
);
215 label_rect
.set_width(button_rect
.x() - kHorizontalMargin
- label_rect
.x());
216 label_rect
.set_height(bounds().height());
217 label_
->SetBoundsRect(label_rect
);
219 client_view_
->SetClientRect(button_rect
);
222 void ScreenCaptureNotificationUIViews::DeleteDelegate() {
226 views::View
* ScreenCaptureNotificationUIViews::GetContentsView() {
230 views::ClientView
* ScreenCaptureNotificationUIViews::CreateClientView(
231 views::Widget
* widget
) {
232 DCHECK(!client_view_
);
233 client_view_
= new NotificationBarClientView(widget
, this);
237 views::NonClientFrameView
*
238 ScreenCaptureNotificationUIViews::CreateNonClientFrameView(
239 views::Widget
* widget
) {
240 views::BubbleFrameView
* frame
= new views::BubbleFrameView(
241 gfx::Insets(kPadding
, kPaddingLeft
, kPadding
, kPadding
));
242 SkColor color
= widget
->GetNativeTheme()->GetSystemColor(
243 ui::NativeTheme::kColorId_DialogBackground
);
244 views::BubbleBorder
* border
= new views::BubbleBorder(
245 views::BubbleBorder::NONE
, views::BubbleBorder::SMALL_SHADOW
, color
);
246 frame
->SetBubbleBorder(border
);
250 string16
ScreenCaptureNotificationUIViews::GetWindowTitle() const {
254 bool ScreenCaptureNotificationUIViews::ShouldShowWindowTitle() const {
258 bool ScreenCaptureNotificationUIViews::ShouldShowCloseButton() const {
262 void ScreenCaptureNotificationUIViews::ButtonPressed(views::Button
* sender
,
263 const ui::Event
& event
) {
267 void ScreenCaptureNotificationUIViews::NotifyStopped() {
268 if (!stop_callback_
.is_null()) {
269 base::Closure callback
= stop_callback_
;
270 stop_callback_
.Reset();
277 scoped_ptr
<ScreenCaptureNotificationUI
> ScreenCaptureNotificationUI::Create(
278 const string16
& text
) {
279 return scoped_ptr
<ScreenCaptureNotificationUI
>(
280 new ScreenCaptureNotificationUIViews(text
));