Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm

Issue 23944003: Implement Desktop Media Picker (Mac version) for Desktop Capture API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Pull in Quartz.framework. Fix nits. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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 #import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.h"
6
7 #include "base/bind.h"
8 #import "base/mac/bundle_locations.h"
9 #include "base/strings/sys_string_conversions.h"
10 #import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_item.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "grit/generated_resources.h"
13 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
14 #import "ui/base/cocoa/flipped_view.h"
15 #import "ui/base/cocoa/window_size_constants.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/gfx/image/image_skia_util_mac.h"
18
19 namespace {
20
21 const int kInitialContentWidth = 620;
22 const int kMinimumContentWidth = 500;
23 const int kMinimumContentHeight = 390;
24 const int kThumbnailWidth = 150;
25 const int kThumbnailHeight = 150;
26 const int kFramePadding = 20;
27 const int kControlSpacing = 10;
28
29 } // namespace
30
31 @interface DesktopMediaPickerController (Private)
32
33 // Populate the window with controls and views.
34 - (void)initializeContentsWithAppName:(const string16&)appName;
35
36 // Create a |NSTextField| with label traits given |width|. Frame height is
37 // automatically adjusted to fit.
38 - (NSTextField*)createTextFieldWithText:(NSString*)text
39 frameWidth:(CGFloat)width;
40
41 // Create a button with |title|, with size adjusted to fit.
42 - (NSButton*)createButtonWithTitle:(NSString*)title;
43
44 // Report result by invoking |doneCallback_|. The callback is invoked only on
45 // the first call to |reportResult:|. Subsequent calls will be no-ops.
46 - (void)reportResult:(content::DesktopMediaID)sourceID;
47
48 // Action handlers.
49 - (void)okPressed:(id)sender;
50 - (void)cancelPressed:(id)sender;
51
52 @end
53
54 @implementation DesktopMediaPickerController
55
56 - (id)initWithModel:(scoped_ptr<DesktopMediaPickerModel>)model
57 callback:(const DesktopMediaPicker::DoneCallback&)callback
58 appName:(const string16&)appName {
59 const NSUInteger kStyleMask =
60 NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
61 base::scoped_nsobject<NSWindow> window(
62 [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
63 styleMask:kStyleMask
64 backing:NSBackingStoreBuffered
65 defer:NO]);
66
67 if ((self = [super initWithWindow:window])) {
68 [window setDelegate:self];
69 [self initializeContentsWithAppName:appName];
70 model_ = model.Pass();
71 doneCallback_ = callback;
72 items_.reset([[NSMutableArray alloc] init]);
73 bridge_.reset(new DesktopMediaPickerBridge(self));
74 }
75 return self;
76 }
77
78 - (void)initializeContentsWithAppName:(const string16&)appName {
79 // Use flipped coordinates to facilitate manual layout.
80 const CGFloat kPaddedWidth = kInitialContentWidth - (kFramePadding * 2);
81 base::scoped_nsobject<FlippedView> content(
82 [[FlippedView alloc] initWithFrame:NSZeroRect]);
83 [[self window] setContentView:content];
84 NSPoint origin = NSMakePoint(kFramePadding, kFramePadding);
85
86 // Set the dialog's title.
87 NSString* titleText = l10n_util::GetNSStringF(
88 IDS_DESKTOP_MEDIA_PICKER_TITLE, appName);
89 [[self window] setTitle:titleText];
90
91 // Set the dialog's description.
92 NSString* descriptionText = l10n_util::GetNSStringF(
93 IDS_DESKTOP_MEDIA_PICKER_TEXT, appName);
94 NSTextField* description = [self createTextFieldWithText:descriptionText
95 frameWidth:kPaddedWidth];
96 [description setFrameOrigin:origin];
97 [content addSubview:description];
98 origin.y += NSHeight([description frame]) + kControlSpacing;
99
100 // Create the image browser.
101 base::scoped_nsobject<IKImageBrowserView> imageBrowser(
102 [[IKImageBrowserView alloc] initWithFrame:NSZeroRect]);
103 NSUInteger cellStyle = IKCellsStyleShadowed | IKCellsStyleTitled;
104 [imageBrowser setDelegate:self];
105 [imageBrowser setDataSource:self];
106 [imageBrowser setCellsStyleMask:cellStyle];
107 [imageBrowser setCellSize:NSMakeSize(kThumbnailWidth, kThumbnailHeight)];
108 sourceBrowser_ = imageBrowser;
109
110 // Create a scroll view to host the image browser.
111 NSRect imageBrowserScrollFrame = NSMakeRect(
112 origin.x, origin.y, kPaddedWidth, 350);
113 base::scoped_nsobject<NSScrollView> imageBrowserScroll(
114 [[NSScrollView alloc] initWithFrame:imageBrowserScrollFrame]);
115 [imageBrowserScroll setHasVerticalScroller:YES];
116 [imageBrowserScroll setDocumentView:imageBrowser];
117 [imageBrowserScroll setBorderType:NSBezelBorder];
118 [imageBrowserScroll setAutoresizingMask:
119 NSViewWidthSizable | NSViewHeightSizable];
120 [content addSubview:imageBrowserScroll];
121 origin.y += NSHeight(imageBrowserScrollFrame) + kControlSpacing;
122
123 // Create the cancel button.
124 cancelButton_ =
125 [self createButtonWithTitle:l10n_util::GetNSString(IDS_CANCEL)];
126 origin.x = kPaddedWidth - NSWidth([cancelButton_ frame]);
127 [cancelButton_ setFrameOrigin:origin];
128 [cancelButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
129 [cancelButton_ setTarget:self];
130 [cancelButton_ setAction:@selector(cancelPressed:)];
131 [content addSubview:cancelButton_];
132
133 // Create the OK button.
134 okButton_ = [self createButtonWithTitle:l10n_util::GetNSString(IDS_OK)];
135 origin.x -= kControlSpacing + NSWidth([okButton_ frame]);
136 [okButton_ setEnabled:NO];
137 [okButton_ setFrameOrigin:origin];
138 [okButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
139 [okButton_ setTarget:self];
140 [okButton_ setAction:@selector(okPressed:)];
141 [content addSubview:okButton_];
142 origin.y += NSHeight([okButton_ frame]) + kFramePadding;
143
144 // Resize window to fit.
145 [[[self window] contentView] setAutoresizesSubviews:NO];
146 [[self window] setContentSize:NSMakeSize(kInitialContentWidth, origin.y)];
147 [[self window] setContentMinSize:
148 NSMakeSize(kMinimumContentWidth, kMinimumContentHeight)];
149 [[[self window] contentView] setAutoresizesSubviews:YES];
150 }
151
152 - (void)showWindow:(id)sender {
153 // Signal the model to start sending thumbnails. |bridge_| is used as the
154 // observer, and will forward notifications to this object.
155 model_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight));
156 model_->StartUpdating(bridge_.get());
157
158 [self.window center];
159 [super showWindow:sender];
160 }
161
162 - (void)reportResult:(content::DesktopMediaID)sourceID {
163 if (doneCallback_.is_null()) {
164 return;
165 }
166
167 // Notify the |callback_| asynchronously because it may release the
168 // controller.
169 content::BrowserThread::PostTask(
170 content::BrowserThread::UI, FROM_HERE,
171 base::Bind(doneCallback_, sourceID));
172 doneCallback_.Reset();
173 }
174
175 - (void)okPressed:(id)sender {
176 NSIndexSet* indexes = [sourceBrowser_ selectionIndexes];
177 NSUInteger selectedIndex = [indexes firstIndex];
178 DesktopMediaPickerItem* item =
179 [items_ objectAtIndex:selectedIndex];
180 [self reportResult:[item sourceID]];
181 [self close];
182 }
183
184 - (void)cancelPressed:(id)sender {
185 [self reportResult:content::DesktopMediaID()];
186 [self close];
187 }
188
189 - (NSTextField*)createTextFieldWithText:(NSString*)text
190 frameWidth:(CGFloat)width {
191 NSRect frame = NSMakeRect(0, 0, width, 1);
192 base::scoped_nsobject<NSTextField> textField(
193 [[NSTextField alloc] initWithFrame:frame]);
194 [textField setEditable:NO];
195 [textField setSelectable:YES];
196 [textField setDrawsBackground:NO];
197 [textField setBezeled:NO];
198 [textField setStringValue:text];
199 [textField setFont:[NSFont systemFontOfSize:13]];
200 [textField setAutoresizingMask:NSViewWidthSizable];
201 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
202 return textField.autorelease();
203 }
204
205 - (NSButton*)createButtonWithTitle:(NSString*)title {
206 base::scoped_nsobject<NSButton> button(
207 [[NSButton alloc] initWithFrame:NSZeroRect]);
208 [button setButtonType:NSMomentaryPushInButton];
209 [button setBezelStyle:NSRoundedBezelStyle];
210 [button setTitle:title];
211 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button];
212 return button.autorelease();
213 }
214
215 #pragma mark NSWindowDelegate
216
217 - (void)windowWillClose:(NSNotification*)notification {
218 // Report the result if it hasn't been reported yet. |reportResult:| ensures
219 // that the result is only reported once.
220 [self reportResult:content::DesktopMediaID()];
221 }
222
223 #pragma mark IKImageBrowserDataSource
224
225 - (NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView*)browser {
226 return [items_ count];
227 }
228
229 - (id)imageBrowser:(IKImageBrowserView *)browser
230 itemAtIndex:(NSUInteger)index {
231 return [items_ objectAtIndex:index];
232 }
233
234 #pragma mark IKImageBrowserDelegate
235
236 - (void)imageBrowser:(IKImageBrowserView *)browser
237 cellWasDoubleClickedAtIndex:(NSUInteger)index {
238 DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
239 [self reportResult:[item sourceID]];
240 [self close];
241 }
242
243 - (void)imageBrowserSelectionDidChange:(IKImageBrowserView*) aBrowser {
244 // Enable or disable the OK button based on whether we have a selection.
245 [okButton_ setEnabled:([[sourceBrowser_ selectionIndexes] count] > 0)];
246 }
247
248 #pragma mark DesktopMediaPickerObserver
249
250 - (void)sourceAddedAtIndex:(int)index {
251 const DesktopMediaPickerModel::Source& source = model_->source(index);
252 NSString* imageTitle = base::SysUTF16ToNSString(source.name);
253 base::scoped_nsobject<DesktopMediaPickerItem> item(
254 [[DesktopMediaPickerItem alloc] initWithSourceId:source.id
255 imageUID:++lastImageUID_
256 imageTitle:imageTitle]);
257 [items_ insertObject:item atIndex:index];
258 [sourceBrowser_ reloadData];
259 }
260
261 - (void)sourceRemovedAtIndex:(int)index {
262 if ([[sourceBrowser_ selectionIndexes] containsIndex:index]) {
263 // Selected item was removed. Clear selection.
264 [sourceBrowser_ setSelectionIndexes:[NSIndexSet indexSet]
265 byExtendingSelection:FALSE];
266 }
267 [items_ removeObjectAtIndex:index];
268 [sourceBrowser_ reloadData];
269 }
270
271 - (void)sourceNameChangedAtIndex:(int)index {
272 DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
273 const DesktopMediaPickerModel::Source& source = model_->source(index);
274 [item setImageTitle:base::SysUTF16ToNSString(source.name)];
275 [sourceBrowser_ reloadData];
276 }
277
278 - (void)sourceThumbnailChangedAtIndex:(int)index {
279 const DesktopMediaPickerModel::Source& source = model_->source(index);
280 NSImage* image = gfx::NSImageFromImageSkia(source.thumbnail);
281
282 DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
283 [item setImageRepresentation:image];
284 [sourceBrowser_ reloadData];
285 }
286
287 @end // @interface DesktopMediaPickerController
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698