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/mac_util.h"
12 #include "base/mac/scoped_nsobject.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "grit/generated_resources.h"
16 #include "grit/theme_resources.h"
17 #include "skia/ext/skia_utils_mac.h"
18 #import "ui/base/cocoa/controls/blue_label_button.h"
19 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
20 #include "ui/base/cocoa/window_size_constants.h"
21 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/gfx/font_list.h"
24 #include "ui/gfx/image/image_skia.h"
25 #include "ui/gfx/image/image_skia_util_mac.h"
26 #include "ui/gfx/text_elider.h"
27 #include "ui/native_theme/native_theme.h"
29 const CGFloat kMinimumWidth = 460;
30 const CGFloat kMaximumWidth = 1000;
31 const CGFloat kHorizontalMargin = 10;
32 const CGFloat kPaddingVertical = 5;
33 const CGFloat kPaddingHorizontal = 10;
34 const CGFloat kWindowCornerRadius = 2;
35 const CGFloat kWindowAlphaValue = 0.85;
37 @interface ScreenCaptureNotificationController()
39 - (void)populateWithText:(const base::string16&)text;
42 @interface ScreenCaptureNotificationView : NSView
45 @interface WindowGripView : NSImageView
46 - (WindowGripView*)init;
50 ScreenCaptureNotificationUICocoa::ScreenCaptureNotificationUICocoa(
51 const base::string16& text)
55 ScreenCaptureNotificationUICocoa::~ScreenCaptureNotificationUICocoa() {}
57 gfx::NativeViewId ScreenCaptureNotificationUICocoa::OnStarted(
58 const base::Closure& stop_callback) {
59 DCHECK(!stop_callback.is_null());
60 DCHECK(!windowController_);
62 windowController_.reset([[ScreenCaptureNotificationController alloc]
63 initWithCallback:stop_callback
65 [windowController_ showWindow:nil];
66 return [[windowController_ window] windowNumber];
69 scoped_ptr<ScreenCaptureNotificationUI> ScreenCaptureNotificationUI::Create(
70 const base::string16& text) {
71 return scoped_ptr<ScreenCaptureNotificationUI>(
72 new ScreenCaptureNotificationUICocoa(text));
75 @implementation ScreenCaptureNotificationController
76 - (id)initWithCallback:(const base::Closure&)stop_callback
77 text:(const base::string16&)text {
78 base::scoped_nsobject<NSWindow> window(
79 [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
80 styleMask:NSBorderlessWindowMask
81 backing:NSBackingStoreBuffered
83 [window setReleasedWhenClosed:NO];
84 [window setAlphaValue:kWindowAlphaValue];
85 [window setBackgroundColor:[NSColor clearColor]];
86 [window setOpaque:NO];
87 [window setHasShadow:YES];
88 [window setLevel:NSStatusWindowLevel];
89 [window setMovableByWindowBackground:YES];
90 [window setDelegate:self];
92 self = [super initWithWindow:window];
94 stop_callback_ = stop_callback;
95 [self populateWithText:text];
97 // Center the window at the bottom of the screen, above the dock (if
99 NSRect desktopRect = [[NSScreen mainScreen] visibleFrame];
100 NSRect contentRect = [[window contentView] frame];
102 NSMakeRect((NSWidth(desktopRect) - NSWidth(contentRect)) / 2,
104 NSWidth(contentRect),
105 NSHeight(contentRect));
106 [window setFrame:windowRect display:YES];
112 [stopButton_ setTarget:nil];
113 [minimizeButton_ setTarget:nil];
117 - (void)stopSharing:(id)sender {
118 if (!stop_callback_.is_null()) {
119 base::Closure callback = stop_callback_;
120 stop_callback_.Reset();
121 callback.Run(); // Deletes |self|.
125 - (void)minimize:(id)sender {
126 [[self window] miniaturize:sender];
130 stop_callback_.Reset();
134 - (void)populateWithText:(const base::string16&)text {
135 base::scoped_nsobject<ScreenCaptureNotificationView> content(
136 [[ScreenCaptureNotificationView alloc]
137 initWithFrame:ui::kWindowSizeDeterminedLater]);
138 [[self window] setContentView:content];
141 stopButton_.reset([[BlueLabelButton alloc] initWithFrame:NSZeroRect]);
142 [stopButton_ setTitle:l10n_util::GetNSString(
143 IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_STOP)];
144 [stopButton_ setTarget:self];
145 [stopButton_ setAction:@selector(stopSharing:)];
146 [stopButton_ sizeToFit];
147 [content addSubview:stopButton_];
149 base::scoped_nsobject<HyperlinkButtonCell> cell(
150 [[HyperlinkButtonCell alloc]
151 initTextCell:l10n_util::GetNSString(
152 IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON)]);
153 [cell setShouldUnderline:NO];
155 minimizeButton_.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
156 [minimizeButton_ setCell:cell.get()];
157 [minimizeButton_ sizeToFit];
158 [minimizeButton_ setTarget:self];
159 [minimizeButton_ setAction:@selector(minimize:)];
160 [content addSubview:minimizeButton_];
162 CGFloat buttonsWidth = NSWidth([stopButton_ frame]) + kHorizontalMargin +
163 NSWidth([minimizeButton_ frame]);
164 CGFloat totalHeight =
165 kPaddingVertical + NSHeight([stopButton_ frame]) + kPaddingVertical;
168 base::scoped_nsobject<WindowGripView> gripView([[WindowGripView alloc] init]);
169 [content addSubview:gripView];
170 CGFloat gripWidth = NSWidth([gripView frame]);
171 CGFloat gripHeight = NSHeight([gripView frame]);
172 [gripView setFrameOrigin:NSMakePoint(kPaddingHorizontal,
173 (totalHeight - gripHeight) / 2)];
175 // Create text label.
177 std::min(kMaximumWidth, NSWidth([[NSScreen mainScreen] visibleFrame]));
178 int maxLabelWidth = maximumWidth - kPaddingHorizontal * 2 -
179 kHorizontalMargin * 2 - gripWidth - buttonsWidth;
180 gfx::FontList font_list;
181 base::string16 elidedText =
182 ElideText(text, font_list, maxLabelWidth, gfx::ELIDE_IN_MIDDLE);
183 NSString* statusText = base::SysUTF16ToNSString(elidedText);
184 base::scoped_nsobject<NSTextField> statusTextField(
185 [[NSTextField alloc] initWithFrame:ui::kWindowSizeDeterminedLater]);
186 [statusTextField setEditable:NO];
187 [statusTextField setSelectable:NO];
188 [statusTextField setDrawsBackground:NO];
189 [statusTextField setBezeled:NO];
190 [statusTextField setStringValue:statusText];
191 [statusTextField setFont:font_list.GetPrimaryFont().GetNativeFont()];
192 [statusTextField sizeToFit];
193 [statusTextField setFrameOrigin:NSMakePoint(
194 kPaddingHorizontal + kHorizontalMargin + gripWidth,
195 (totalHeight - NSHeight([statusTextField frame])) / 2)];
196 [content addSubview:statusTextField];
198 // Resize content view to fit controls.
199 CGFloat minimumLableWidth = kMinimumWidth - kPaddingHorizontal * 2 -
200 kHorizontalMargin * 2 - gripWidth - buttonsWidth;
202 std::max(NSWidth([statusTextField frame]), minimumLableWidth);
203 CGFloat totalWidth = kPaddingHorizontal * 2 + kHorizontalMargin * 2 +
204 gripWidth + lableWidth + buttonsWidth;
205 [content setFrame:NSMakeRect(0, 0, totalWidth, totalHeight)];
207 // Move the buttons to the right place.
208 NSPoint buttonOrigin = NSMakePoint(
209 totalWidth - kPaddingHorizontal - buttonsWidth, kPaddingVertical);
210 [stopButton_ setFrameOrigin:buttonOrigin];
212 [minimizeButton_ setFrameOrigin:NSMakePoint(
213 totalWidth - kPaddingHorizontal - NSWidth([minimizeButton_ frame]),
214 (totalHeight - NSHeight([minimizeButton_ frame])) / 2)];
216 if (base::i18n::IsRTL()) {
218 setFrameOrigin:NSMakePoint(totalWidth - NSMaxX([stopButton_ frame]),
219 NSMinY([stopButton_ frame]))];
221 setFrameOrigin:NSMakePoint(totalWidth - NSMaxX([minimizeButton_ frame]),
222 NSMinY([minimizeButton_ frame]))];
224 setFrameOrigin:NSMakePoint(totalWidth - NSMaxX([statusTextField frame]),
225 NSMinY([statusTextField frame]))];
226 [gripView setFrameOrigin:NSMakePoint(totalWidth - NSMaxX([gripView frame]),
227 NSMinY([gripView frame]))];
231 - (void)windowWillClose:(NSNotification*)notification {
232 [self stopSharing:nil];
237 @implementation ScreenCaptureNotificationView
239 - (void)drawRect:(NSRect)dirtyRect {
240 [gfx::SkColorToSRGBNSColor(ui::NativeTheme::instance()->GetSystemColor(
241 ui::NativeTheme::kColorId_DialogBackground)) set];
242 [[NSBezierPath bezierPathWithRoundedRect:[self bounds]
243 xRadius:kWindowCornerRadius
244 yRadius:kWindowCornerRadius] fill];
249 @implementation WindowGripView
250 - (WindowGripView*)init {
251 gfx::Image gripImage =
252 ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
253 IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP,
254 ui::ResourceBundle::RTL_DISABLED);
256 initWithFrame:NSMakeRect(0, 0, gripImage.Width(), gripImage.Height())];
257 [self setImage:gripImage.ToNSImage()];
261 - (BOOL)mouseDownCanMoveWindow {