Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / screen_capture_notification_ui_cocoa.mm
blob8b4a10439df7a53036759dd3fb68ee20ac62e7fe
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/cocoa/screen_capture_notification_ui_cocoa.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/compiler_specific.h"
10 #include "base/i18n/rtl.h"
11 #include "base/mac/scoped_nsobject.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "grit/theme_resources.h"
16 #include "skia/ext/skia_utils_mac.h"
17 #import "ui/base/cocoa/controls/blue_label_button.h"
18 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
19 #include "ui/base/cocoa/window_size_constants.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/gfx/font_list.h"
23 #include "ui/gfx/image/image_skia.h"
24 #include "ui/gfx/image/image_skia_util_mac.h"
25 #include "ui/gfx/text_elider.h"
26 #include "ui/native_theme/native_theme.h"
28 const CGFloat kMinimumWidth = 460;
29 const CGFloat kMaximumWidth = 1000;
30 const CGFloat kHorizontalMargin = 10;
31 const CGFloat kPaddingVertical = 5;
32 const CGFloat kPaddingHorizontal = 10;
33 const CGFloat kWindowCornerRadius = 2;
34 const CGFloat kWindowAlphaValue = 0.85;
36 @interface ScreenCaptureNotificationController()
37 - (void)hide;
38 - (void)populateWithText:(const base::string16&)text;
39 @end
41 @interface ScreenCaptureNotificationView : NSView
42 @end
44 @interface WindowGripView : NSImageView
45 - (WindowGripView*)init;
46 @end
49 ScreenCaptureNotificationUICocoa::ScreenCaptureNotificationUICocoa(
50     const base::string16& text)
51     : text_(text) {
54 ScreenCaptureNotificationUICocoa::~ScreenCaptureNotificationUICocoa() {}
56 gfx::NativeViewId ScreenCaptureNotificationUICocoa::OnStarted(
57     const base::Closure& stop_callback) {
58   DCHECK(!stop_callback.is_null());
59   DCHECK(!windowController_);
61   windowController_.reset([[ScreenCaptureNotificationController alloc]
62       initWithCallback:stop_callback
63                   text:text_]);
64   [windowController_ showWindow:nil];
65   return [[windowController_ window] windowNumber];
68 scoped_ptr<ScreenCaptureNotificationUI> ScreenCaptureNotificationUI::Create(
69     const base::string16& text) {
70   return scoped_ptr<ScreenCaptureNotificationUI>(
71       new ScreenCaptureNotificationUICocoa(text));
74 @implementation ScreenCaptureNotificationController
75 - (id)initWithCallback:(const base::Closure&)stop_callback
76                   text:(const base::string16&)text {
77   base::scoped_nsobject<NSWindow> window(
78       [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
79                                   styleMask:NSBorderlessWindowMask
80                                     backing:NSBackingStoreBuffered
81                                       defer:NO]);
82   [window setReleasedWhenClosed:NO];
83   [window setAlphaValue:kWindowAlphaValue];
84   [window setBackgroundColor:[NSColor clearColor]];
85   [window setOpaque:NO];
86   [window setHasShadow:YES];
87   [window setLevel:NSStatusWindowLevel];
88   [window setMovableByWindowBackground:YES];
89   [window setDelegate:self];
91   self = [super initWithWindow:window];
92   if (self) {
93     stop_callback_ = stop_callback;
94     [self populateWithText:text];
96     // Center the window at the bottom of the screen, above the dock (if
97     // present).
98     NSRect desktopRect = [[NSScreen mainScreen] visibleFrame];
99     NSRect contentRect = [[window contentView] frame];
100     NSRect windowRect =
101         NSMakeRect((NSWidth(desktopRect) - NSWidth(contentRect)) / 2,
102                    NSMinY(desktopRect),
103                    NSWidth(contentRect),
104                    NSHeight(contentRect));
105     [window setFrame:windowRect display:YES];
106   }
107   return self;
110 - (void)dealloc {
111   [stopButton_ setTarget:nil];
112   [minimizeButton_ setTarget:nil];
113   [super dealloc];
116 - (void)stopSharing:(id)sender {
117   if (!stop_callback_.is_null()) {
118     base::Closure callback = stop_callback_;
119     stop_callback_.Reset();
120     callback.Run();  // Deletes |self|.
121   }
124 - (void)minimize:(id)sender {
125   [[self window] miniaturize:sender];
128 - (void)hide {
129   stop_callback_.Reset();
130   [self close];
133 - (void)populateWithText:(const base::string16&)text {
134   base::scoped_nsobject<ScreenCaptureNotificationView> content(
135       [[ScreenCaptureNotificationView alloc]
136           initWithFrame:ui::kWindowSizeDeterminedLater]);
137   [[self window] setContentView:content];
139   // Create button.
140   stopButton_.reset([[BlueLabelButton alloc] initWithFrame:NSZeroRect]);
141   [stopButton_ setTitle:l10n_util::GetNSString(
142                   IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_STOP)];
143   [stopButton_ setTarget:self];
144   [stopButton_ setAction:@selector(stopSharing:)];
145   [stopButton_ sizeToFit];
146   [content addSubview:stopButton_];
148   base::scoped_nsobject<HyperlinkButtonCell> cell(
149       [[HyperlinkButtonCell alloc]
150        initTextCell:l10n_util::GetNSString(
151                         IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON)]);
152   [cell setShouldUnderline:NO];
154   minimizeButton_.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
155   [minimizeButton_ setCell:cell.get()];
156   [minimizeButton_ sizeToFit];
157   [minimizeButton_ setTarget:self];
158   [minimizeButton_ setAction:@selector(minimize:)];
159   [content addSubview:minimizeButton_];
161   CGFloat buttonsWidth = NSWidth([stopButton_ frame]) + kHorizontalMargin +
162       NSWidth([minimizeButton_ frame]);
163   CGFloat totalHeight =
164       kPaddingVertical + NSHeight([stopButton_ frame]) + kPaddingVertical;
166   // Create grip icon.
167   base::scoped_nsobject<WindowGripView> gripView([[WindowGripView alloc] init]);
168   [content addSubview:gripView];
169   CGFloat gripWidth = NSWidth([gripView frame]);
170   CGFloat gripHeight = NSHeight([gripView frame]);
171   [gripView setFrameOrigin:NSMakePoint(kPaddingHorizontal,
172                                        (totalHeight - gripHeight) / 2)];
174   // Create text label.
175   int maximumWidth =
176       std::min(kMaximumWidth, NSWidth([[NSScreen mainScreen] visibleFrame]));
177   int maxLabelWidth = maximumWidth - kPaddingHorizontal * 2 -
178                       kHorizontalMargin * 2 - gripWidth - buttonsWidth;
179   gfx::FontList font_list;
180   base::string16 elidedText =
181       ElideText(text, font_list, maxLabelWidth, gfx::ELIDE_MIDDLE);
182   NSString* statusText = base::SysUTF16ToNSString(elidedText);
183   base::scoped_nsobject<NSTextField> statusTextField(
184       [[NSTextField alloc] initWithFrame:ui::kWindowSizeDeterminedLater]);
185   [statusTextField setEditable:NO];
186   [statusTextField setSelectable:NO];
187   [statusTextField setDrawsBackground:NO];
188   [statusTextField setBezeled:NO];
189   [statusTextField setStringValue:statusText];
190   [statusTextField setFont:font_list.GetPrimaryFont().GetNativeFont()];
191   [statusTextField sizeToFit];
192   [statusTextField setFrameOrigin:NSMakePoint(
193                        kPaddingHorizontal + kHorizontalMargin + gripWidth,
194                        (totalHeight - NSHeight([statusTextField frame])) / 2)];
195   [content addSubview:statusTextField];
197   // Resize content view to fit controls.
198   CGFloat minimumLableWidth = kMinimumWidth - kPaddingHorizontal * 2 -
199                               kHorizontalMargin * 2 - gripWidth - buttonsWidth;
200   CGFloat lableWidth =
201       std::max(NSWidth([statusTextField frame]), minimumLableWidth);
202   CGFloat totalWidth = kPaddingHorizontal * 2 + kHorizontalMargin * 2 +
203                        gripWidth + lableWidth + buttonsWidth;
204   [content setFrame:NSMakeRect(0, 0, totalWidth, totalHeight)];
206   // Move the buttons to the right place.
207   NSPoint buttonOrigin = NSMakePoint(
208       totalWidth - kPaddingHorizontal - buttonsWidth, kPaddingVertical);
209   [stopButton_ setFrameOrigin:buttonOrigin];
211   [minimizeButton_ setFrameOrigin:NSMakePoint(
212       totalWidth - kPaddingHorizontal - NSWidth([minimizeButton_ frame]),
213       (totalHeight - NSHeight([minimizeButton_ frame])) / 2)];
215   if (base::i18n::IsRTL()) {
216     [stopButton_
217         setFrameOrigin:NSMakePoint(totalWidth - NSMaxX([stopButton_ frame]),
218                                    NSMinY([stopButton_ frame]))];
219     [minimizeButton_
220         setFrameOrigin:NSMakePoint(totalWidth - NSMaxX([minimizeButton_ frame]),
221                                    NSMinY([minimizeButton_ frame]))];
222     [statusTextField
223         setFrameOrigin:NSMakePoint(totalWidth - NSMaxX([statusTextField frame]),
224                                    NSMinY([statusTextField frame]))];
225     [gripView setFrameOrigin:NSMakePoint(totalWidth - NSMaxX([gripView frame]),
226                                          NSMinY([gripView frame]))];
227   }
230 - (void)windowWillClose:(NSNotification*)notification {
231   [self stopSharing:nil];
234 @end
236 @implementation ScreenCaptureNotificationView
238 - (void)drawRect:(NSRect)dirtyRect {
239   [gfx::SkColorToSRGBNSColor(ui::NativeTheme::instance()->GetSystemColor(
240       ui::NativeTheme::kColorId_DialogBackground)) set];
241   [[NSBezierPath bezierPathWithRoundedRect:[self bounds]
242                                    xRadius:kWindowCornerRadius
243                                    yRadius:kWindowCornerRadius] fill];
246 @end
248 @implementation WindowGripView
249 - (WindowGripView*)init {
250   gfx::Image gripImage =
251       ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
252           IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP,
253           ui::ResourceBundle::RTL_DISABLED);
254   self = [super
255       initWithFrame:NSMakeRect(0, 0, gripImage.Width(), gripImage.Height())];
256   [self setImage:gripImage.ToNSImage()];
257   return self;
260 - (BOOL)mouseDownCanMoveWindow {
261   return YES;
263 @end