screen_capture_notification_ui_views.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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 "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" 25 26namespace { 27 28const int kMinimumWidth = 460; 29const int kMaximumWidth = 1000; 30const int kHorizontalMargin = 10; 31const int kPadding = 5; 32const int kPaddingLeft = 10; 33 34namespace { 35 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 39// draggable. 40class NotificationBarClientView : public views::ClientView { 41 public: 42 NotificationBarClientView(views::Widget* widget, views::View* view) 43 : views::ClientView(widget, view) { 44 } 45 virtual ~NotificationBarClientView() {} 46 47 void SetClientRect(const gfx::Rect& rect) { 48 rect_ = rect; 49 } 50 51 // views::ClientView overrides. 52 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE { 53 if (!bounds().Contains(point)) 54 return HTNOWHERE; 55 // The whole window is HTCAPTION, except the |rect_|. 56 if (rect_.Contains(gfx::PointAtOffsetFromOrigin(point - bounds().origin()))) 57 return HTCLIENT; 58 59 return HTCAPTION; 60 } 61 62 private: 63 gfx::Rect rect_; 64 65 DISALLOW_COPY_AND_ASSIGN(NotificationBarClientView); 66}; 67 68} // namespace 69 70// ScreenCaptureNotificationUI implementation using Views. 71class ScreenCaptureNotificationUIViews 72 : public ScreenCaptureNotificationUI, 73 public views::WidgetDelegateView, 74 public views::ButtonListener { 75 public: 76 ScreenCaptureNotificationUIViews(); 77 virtual ~ScreenCaptureNotificationUIViews(); 78 79 // ScreenCaptureNotificationUI interface. 80 virtual bool Show(const base::Closure& stop_callback, 81 const string16& title) OVERRIDE; 82 83 // views::View overrides. 84 virtual gfx::Size GetPreferredSize() OVERRIDE; 85 virtual void Layout() OVERRIDE; 86 87 // views::WidgetDelegateView overrides. 88 virtual void DeleteDelegate() OVERRIDE; 89 virtual views::View* GetContentsView() OVERRIDE; 90 virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE; 91 virtual views::NonClientFrameView* CreateNonClientFrameView( 92 views::Widget* widget) OVERRIDE; 93 virtual string16 GetWindowTitle() const OVERRIDE; 94 virtual bool ShouldShowWindowTitle() const OVERRIDE; 95 virtual bool ShouldShowCloseButton() const OVERRIDE; 96 97 // views::ButtonListener interface. 98 virtual void ButtonPressed(views::Button* sender, 99 const ui::Event& event) OVERRIDE; 100 101 private: 102 // Helper to call |stop_callback_|. 103 void NotifyStopped(); 104 105 base::Closure stop_callback_; 106 string16 window_title_; 107 NotificationBarClientView* client_view_; 108 views::ImageView* gripper_; 109 views::Label* label_; 110 views::BlueButton* stop_button_; 111 112 DISALLOW_COPY_AND_ASSIGN(ScreenCaptureNotificationUIViews); 113}; 114 115ScreenCaptureNotificationUIViews::ScreenCaptureNotificationUIViews() 116 : client_view_(NULL), 117 gripper_(NULL), 118 label_(NULL), 119 stop_button_(NULL) { 120 set_owned_by_client(); 121 122 set_background(views::Background::CreateSolidBackground(GetNativeTheme()-> 123 GetSystemColor(ui::NativeTheme::kColorId_DialogBackground))); 124 125 gripper_ = new views::ImageView(); 126 gripper_->SetImage( 127 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 128 IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP)); 129 AddChildView(gripper_); 130 131 label_ = new views::Label(); 132 AddChildView(label_); 133 134 string16 stop_text = 135 l10n_util::GetStringUTF16(IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_STOP); 136 stop_button_ = new views::BlueButton(this, stop_text); 137 AddChildView(stop_button_); 138} 139 140ScreenCaptureNotificationUIViews::~ScreenCaptureNotificationUIViews() { 141 stop_callback_.Reset(); 142 delete GetWidget(); 143} 144 145bool ScreenCaptureNotificationUIViews::Show( 146 const base::Closure& stop_callback, 147 const string16& title) { 148 stop_callback_ = stop_callback; 149 150 label_->SetElideBehavior(views::Label::ELIDE_IN_MIDDLE); 151 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 152 string16 text = l10n_util::GetStringFUTF16( 153 IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, title); 154 label_->SetText(text); 155 window_title_ = l10n_util::GetStringFUTF16( 156 IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TITLE, title); 157 158 views::Widget* widget = new views::Widget; 159 160 views::Widget::InitParams params; 161 params.delegate = this; 162 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 163 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 164 params.remove_standard_frame = true; 165 params.keep_on_top = true; 166 params.top_level = true; 167 params.can_activate = false; 168 169#if defined(USE_ASH) 170 // TODO(sergeyu): The notification bar must be shown on the monitor that's 171 // being captured. Make sure it's always the case. Currently we always capture 172 // the primary monitor. 173 if (ash::Shell::HasInstance()) 174 params.context = ash::Shell::GetPrimaryRootWindow(); 175#endif 176 177 widget->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM); 178 widget->Init(params); 179 widget->SetAlwaysOnTop(true); 180 181 gfx::Screen* screen = gfx::Screen::GetNativeScreen(); 182 // TODO(sergeyu): Move the notification to the display being captured when 183 // per-display screen capture is supported. 184 gfx::Rect work_area = screen->GetPrimaryDisplay().work_area(); 185 186 // Place the bar in the center of the bottom of the display. 187 gfx::Size size = widget->non_client_view()->GetPreferredSize(); 188 gfx::Rect bounds( 189 work_area.x() + work_area.width() / 2 - size.width() / 2, 190 work_area.y() + work_area.height() - size.height(), 191 size.width(), size.height()); 192 widget->SetBounds(bounds); 193 194 widget->Show(); 195 196 return true; 197} 198 199gfx::Size ScreenCaptureNotificationUIViews::GetPreferredSize() { 200 gfx::Size grip_size = gripper_->GetPreferredSize(); 201 gfx::Size label_size = child_at(1)->GetPreferredSize(); 202 gfx::Size button_size = child_at(2)->GetPreferredSize(); 203 int width = kHorizontalMargin * 2 + grip_size.width() + label_size.width() + 204 button_size.width(); 205 width = std::max(width, kMinimumWidth); 206 width = std::min(width, kMaximumWidth); 207 return gfx::Size(width, std::max(label_size.height(), button_size.height())); 208} 209 210void ScreenCaptureNotificationUIViews::Layout() { 211 gfx::Rect grip_rect(gripper_->GetPreferredSize()); 212 grip_rect.set_y(bounds().height() / 2 - grip_rect.height() / 2); 213 gripper_->SetBoundsRect(grip_rect); 214 215 gfx::Rect button_rect(stop_button_->GetPreferredSize()); 216 button_rect.set_x(bounds().width() - button_rect.width()); 217 stop_button_->SetBoundsRect(button_rect); 218 219 gfx::Rect label_rect; 220 label_rect.set_x(grip_rect.right() + kHorizontalMargin); 221 label_rect.set_width(button_rect.x() - kHorizontalMargin - label_rect.x()); 222 label_rect.set_height(bounds().height()); 223 label_->SetBoundsRect(label_rect); 224 225 client_view_->SetClientRect(button_rect); 226} 227 228void ScreenCaptureNotificationUIViews::DeleteDelegate() { 229 NotifyStopped(); 230} 231 232views::View* ScreenCaptureNotificationUIViews::GetContentsView() { 233 return this; 234} 235 236views::ClientView* ScreenCaptureNotificationUIViews::CreateClientView( 237 views::Widget* widget) { 238 DCHECK(!client_view_); 239 client_view_ = new NotificationBarClientView(widget, this); 240 return client_view_; 241} 242 243views::NonClientFrameView* 244ScreenCaptureNotificationUIViews::CreateNonClientFrameView( 245 views::Widget* widget) { 246 views::BubbleFrameView* frame = new views::BubbleFrameView( 247 gfx::Insets(kPadding, kPaddingLeft, kPadding, kPadding)); 248 SkColor color = widget->GetNativeTheme()->GetSystemColor( 249 ui::NativeTheme::kColorId_DialogBackground); 250 views::BubbleBorder* border = new views::BubbleBorder( 251 views::BubbleBorder::NONE, views::BubbleBorder::SMALL_SHADOW, color); 252 frame->SetBubbleBorder(border); 253 return frame; 254} 255 256string16 ScreenCaptureNotificationUIViews::GetWindowTitle() const { 257 return window_title_; 258} 259 260bool ScreenCaptureNotificationUIViews::ShouldShowWindowTitle() const { 261 return false; 262} 263 264bool ScreenCaptureNotificationUIViews::ShouldShowCloseButton() const { 265 return false; 266} 267 268void ScreenCaptureNotificationUIViews::ButtonPressed(views::Button* sender, 269 const ui::Event& event) { 270 NotifyStopped(); 271} 272 273void ScreenCaptureNotificationUIViews::NotifyStopped() { 274 if (!stop_callback_.is_null()) { 275 base::Closure callback = stop_callback_; 276 stop_callback_.Reset(); 277 callback.Run(); 278 } 279} 280 281} // namespace 282 283scoped_ptr<ScreenCaptureNotificationUI> ScreenCaptureNotificationUI::Create() { 284 return scoped_ptr<ScreenCaptureNotificationUI>( 285 new ScreenCaptureNotificationUIViews()); 286} 287