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

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

Powered by Google App Engine
This is Rietveld 408576698