OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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/website_settings/chooser_bubble_ui_cocoa.h" | |
6 | |
7 #include <algorithm> | |
8 #include <cmath> | |
9 #include <vector> | |
10 | |
11 #include "base/mac/scoped_nsobject.h" | |
12 #include "base/strings/sys_string_conversions.h" | |
13 #include "base/strings/utf_string_conversions.h" | |
14 #include "chrome/browser/ui/browser.h" | |
15 #include "chrome/browser/ui/browser_finder.h" | |
16 #include "chrome/browser/ui/browser_window.h" | |
17 #import "chrome/browser/ui/chrome_style.h" | |
18 #import "chrome/browser/ui/cocoa/base_bubble_controller.h" | |
19 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | |
20 #import "chrome/browser/ui/cocoa/browser_window_utils.h" | |
21 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" | |
22 #import "chrome/browser/ui/cocoa/hover_close_button.h" | |
23 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | |
24 #import "chrome/browser/ui/cocoa/info_bubble_window.h" | |
25 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" | |
26 #include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h" | |
27 #include "chrome/grit/generated_resources.h" | |
28 #include "content/public/browser/native_web_keyboard_event.h" | |
29 #include "ui/base/cocoa/window_size_constants.h" | |
30 #include "ui/base/l10n/l10n_util_mac.h" | |
31 | |
32 namespace { | |
33 | |
34 // Chooser bubble width. | |
35 const CGFloat kChooserBubbleWidth = 320.0f; | |
36 | |
37 // Chooser bubble height. | |
38 const CGFloat kChooserBubbleHeight = 220.0f; | |
39 | |
40 // Distance between the bubble border and the view that is closest to the | |
41 // border. | |
42 const CGFloat kMarginX = 20.0f; | |
43 const CGFloat kMarginY = 20.0f; | |
44 | |
45 // Distance between two views inside the bubble. | |
46 const CGFloat kHorizontalPadding = 10.0f; | |
47 const CGFloat kVerticalPadding = 10.0f; | |
48 | |
49 const CGFloat kTitlePaddingX = 50.0f; | |
50 } | |
51 | |
52 scoped_ptr<BubbleUi> ChooserBubbleDelegate::BuildBubbleUi() { | |
53 return make_scoped_ptr(new ChooserBubbleUiCocoa(browser_, this)); | |
54 } | |
55 | |
56 @interface ChooserBubbleUiController | |
57 : BaseBubbleController<NSTableViewDataSource, NSTableViewDelegate> { | |
58 @private | |
59 // Bridge to the C++ class that created this object. | |
60 ChooserBubbleUiCocoa* bridge_; | |
61 | |
62 base::scoped_nsobject<NSTextField> titleView_; | |
63 base::scoped_nsobject<NSScrollView> scrollView_; | |
64 base::scoped_nsobject<NSTableColumn> tableColumn_; | |
65 base::scoped_nsobject<NSTableView> tableView_; | |
66 base::scoped_nsobject<NSButton> connectButton_; | |
67 base::scoped_nsobject<NSButton> cancelButton_; | |
68 | |
69 Browser* browser_; // Weak. | |
70 ChooserBubbleDelegate* chooser_bubble_delegate_; // Weak. | |
Robert Sesek
2015/12/14 23:13:48
naming: chooserBubbleDelegate_
juncai
2015/12/15 02:09:28
Done.
| |
71 } | |
72 | |
73 // Designated initializer. |browser| and |bridge| must both be non-nil. | |
74 - (id)initWithBrowser:(Browser*)browser | |
75 initWithChooserBubbleDelegate: | |
76 (ChooserBubbleDelegate*)chooser_bubble_delegate | |
Robert Sesek
2015/12/14 23:13:48
naming: chooserBubbleDelegate_
juncai
2015/12/15 02:09:28
Done.
| |
77 bridge:(ChooserBubbleUiCocoa*)bridge; | |
78 | |
79 // Makes the bubble visible. | |
80 - (void)show; | |
81 | |
82 // Will reposition the bubble based in case the anchor or parent should change. | |
83 - (void)updateAnchorPosition; | |
84 | |
85 // Will calculate the expected anchor point for this bubble. | |
86 // Should only be used outside this class for tests. | |
87 - (NSPoint)getExpectedAnchorPoint; | |
88 | |
89 // Returns true if the browser has support for the location bar. | |
90 // Should only be used outside this class for tests. | |
91 - (bool)hasLocationBar; | |
92 | |
93 // Update |tableView_| when chooser options were initialized. | |
94 - (void)onOptionsInitialized; | |
95 | |
96 // Update |tableView_| when chooser option was added. | |
97 - (void)onOptionAdded:(NSInteger)index; | |
98 | |
99 // Update |tableView_| when chooser option was removed. | |
100 - (void)onOptionRemoved:(NSInteger)index; | |
101 | |
102 // Update |tableView_| when chooser options changed. | |
103 - (void)updateTableView; | |
104 | |
105 // Determines if the bubble has an anchor in a corner or no anchor at all. | |
106 - (info_bubble::BubbleArrowLocation)getExpectedArrowLocation; | |
107 | |
108 // Returns the expected parent for this bubble. | |
109 - (NSWindow*)getExpectedParentWindow; | |
110 | |
111 // Creates the title for the bubble. | |
112 - (base::scoped_nsobject<NSTextField>)bubbleTitle; | |
113 | |
114 // Creates a button with |title| and |action|. | |
115 - (base::scoped_nsobject<NSButton>)buttonWithTitle:(NSString*)title | |
116 action:(SEL)action; | |
117 | |
118 // Creates the "Connect" button. | |
119 - (base::scoped_nsobject<NSButton>)connectButton; | |
120 | |
121 // Creates the "Cancel" button. | |
122 - (base::scoped_nsobject<NSButton>)cancelButton; | |
123 | |
124 // Called when the "Connect" button is pressed. | |
125 - (void)onConnect:(id)sender; | |
126 | |
127 // Called when the "Cancel" button is pressed. | |
128 - (void)onCancel:(id)sender; | |
129 | |
130 @end | |
131 | |
132 @implementation ChooserBubbleUiController | |
133 | |
134 - (id)initWithBrowser:(Browser*)browser | |
135 initWithChooserBubbleDelegate: | |
136 (ChooserBubbleDelegate*)chooser_bubble_delegate | |
137 bridge:(ChooserBubbleUiCocoa*)bridge { | |
138 DCHECK(browser); | |
139 DCHECK(chooser_bubble_delegate); | |
140 DCHECK(bridge); | |
141 | |
142 if (browser == nil || chooser_bubble_delegate == nil || bridge == nil) | |
Robert Sesek
2015/12/14 23:13:48
This is also DCHECK'd, so I'd remove this.
juncai
2015/12/15 02:09:28
Done.
| |
143 return nil; | |
144 | |
145 browser_ = browser; | |
146 chooser_bubble_delegate_ = chooser_bubble_delegate; | |
147 | |
148 base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc] | |
149 initWithContentRect:ui::kWindowSizeDeterminedLater | |
150 styleMask:NSBorderlessWindowMask | |
151 backing:NSBackingStoreBuffered | |
152 defer:NO]); | |
153 [window setAllowedAnimations:info_bubble::kAnimateNone]; | |
154 [window setReleasedWhenClosed:NO]; | |
155 if ((self = [super initWithWindow:window | |
156 parentWindow:[self getExpectedParentWindow] | |
157 anchoredAt:NSZeroPoint])) { | |
158 [self setShouldCloseOnResignKey:NO]; | |
159 [self setShouldOpenAsKeyWindow:YES]; | |
160 [[self bubble] setArrowLocation:[self getExpectedArrowLocation]]; | |
161 bridge_ = bridge; | |
162 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
163 [center addObserver:self | |
Robert Sesek
2015/12/14 23:13:48
This observer is leaked and should be removed eith
juncai
2015/12/15 02:09:28
Done.
| |
164 selector:@selector(parentWindowDidMove:) | |
165 name:NSWindowDidMoveNotification | |
166 object:[self getExpectedParentWindow]]; | |
167 } | |
168 return self; | |
169 } | |
170 | |
171 - (void)windowWillClose:(NSNotification*)notification { | |
172 bridge_->OnBubbleClosing(); | |
173 [super windowWillClose:notification]; | |
174 } | |
175 | |
176 - (void)parentWindowWillToggleFullScreen:(NSNotification*)notification { | |
177 // Override the base class implementation, which would have closed the bubble. | |
178 } | |
179 | |
180 - (void)parentWindowDidResize:(NSNotification*)notification { | |
181 [self setAnchorPoint:[self getExpectedAnchorPoint]]; | |
182 } | |
183 | |
184 - (void)parentWindowDidMove:(NSNotification*)notification { | |
185 DCHECK(bridge_); | |
186 [self setAnchorPoint:[self getExpectedAnchorPoint]]; | |
187 } | |
188 | |
189 - (void)show { | |
190 NSView* view = [[self window] contentView]; | |
191 [view setSubviews:@[]]; | |
Robert Sesek
2015/12/14 23:13:48
What's the rationale behind this?
juncai
2015/12/15 02:09:28
Done.
| |
192 | |
193 // ------------------------------------ | |
194 // | Chooser bubble title | | |
195 // | -------------------------------- | | |
196 // | | option 0 | | | |
197 // | | option 1 | | | |
198 // | | option 2 | | | |
199 // | | | | | |
200 // | | | | | |
201 // | | | | | |
202 // | -------------------------------- | | |
203 // | [ Connect] [ Cancel ] | | |
204 // ------------------------------------ | |
205 | |
206 // Determine the dimensions of the bubble. | |
207 // Once the height and width are set, the buttons and permission menus can | |
208 // be laid out correctly. | |
209 NSRect bubbleFrame = | |
210 NSMakeRect(0, 0, kChooserBubbleWidth, kChooserBubbleHeight); | |
211 | |
212 // Create the views. | |
213 // Title. | |
214 titleView_ = [self bubbleTitle]; | |
215 CGFloat titleOriginX = kMarginX; | |
216 CGFloat titleHeight = NSHeight([titleView_ frame]); | |
217 CGFloat titleOriginY = kChooserBubbleHeight - kMarginY - titleHeight; | |
218 [titleView_ setFrameOrigin:NSMakePoint(titleOriginX, titleOriginY)]; | |
219 [view addSubview:titleView_]; | |
220 | |
221 // Connect button. | |
222 connectButton_ = [self connectButton]; | |
223 // Cancel button. | |
224 cancelButton_ = [self cancelButton]; | |
225 CGFloat connectButtonWidth = NSWidth([connectButton_ frame]); | |
226 CGFloat connectButtonHeight = NSHeight([connectButton_ frame]); | |
227 CGFloat cancelButtonWidth = NSWidth([cancelButton_ frame]); | |
228 | |
229 // ScollView embedding with TableView. | |
230 CGFloat scrollViewWidth = kChooserBubbleWidth - 2 * kMarginX; | |
231 CGFloat scrollViewHeight = kChooserBubbleHeight - 2 * kMarginY - | |
232 2 * kVerticalPadding - titleHeight - | |
233 connectButtonHeight; | |
234 NSRect scrollFrame = | |
235 NSMakeRect(kMarginX, kMarginY + connectButtonHeight + kVerticalPadding, | |
236 scrollViewWidth, scrollViewHeight); | |
237 scrollView_.reset([[NSScrollView alloc] initWithFrame:scrollFrame]); | |
238 [scrollView_ setBorderType:NSBezelBorder]; | |
239 [scrollView_ setHasVerticalScroller:YES]; | |
240 [scrollView_ setHasHorizontalScroller:YES]; | |
241 [scrollView_ setAutohidesScrollers:YES]; | |
242 | |
243 // TableView. | |
244 tableView_.reset([[NSTableView alloc] initWithFrame:NSZeroRect]); | |
245 tableColumn_.reset([[NSTableColumn alloc] initWithIdentifier:@""]); | |
246 [tableColumn_ setWidth:(scrollViewWidth - kMarginX)]; | |
247 [tableView_ addTableColumn:tableColumn_]; | |
248 [tableView_ setDelegate:self]; | |
249 [tableView_ setDataSource:self]; | |
250 // Make the column title invisible. | |
251 [tableView_ setHeaderView:nil]; | |
252 [tableView_ setFocusRingType:NSFocusRingTypeNone]; | |
253 | |
254 [scrollView_ setDocumentView:tableView_]; | |
255 [view addSubview:scrollView_]; | |
256 | |
257 // Set connect button and cancel button to the right place. | |
258 CGFloat connectButtonOriginX = kChooserBubbleWidth - kMarginX - | |
259 kHorizontalPadding - connectButtonWidth - | |
260 cancelButtonWidth; | |
261 CGFloat connectButtonOriginY = kMarginY; | |
262 [connectButton_ | |
263 setFrameOrigin:NSMakePoint(connectButtonOriginX, connectButtonOriginY)]; | |
264 [connectButton_ setEnabled:NO]; | |
265 [view addSubview:connectButton_]; | |
266 | |
267 CGFloat cancelButtonOriginX = | |
268 kChooserBubbleWidth - kMarginX - cancelButtonWidth; | |
269 CGFloat cancelButtonOriginY = kMarginY; | |
270 [cancelButton_ | |
271 setFrameOrigin:NSMakePoint(cancelButtonOriginX, cancelButtonOriginY)]; | |
272 [view addSubview:cancelButton_]; | |
273 | |
274 bubbleFrame = [[self window] frameRectForContentRect:bubbleFrame]; | |
275 if ([[self window] isVisible]) { | |
276 // Unfortunately, calling -setFrame followed by -setFrameOrigin (called | |
277 // within -setAnchorPoint) causes flickering. Avoid the flickering by | |
278 // manually adjusting the new frame's origin so that the top left stays the | |
279 // same, and only calling -setFrame. | |
280 NSRect currentWindowFrame = [[self window] frame]; | |
281 bubbleFrame.origin = currentWindowFrame.origin; | |
282 bubbleFrame.origin.y = bubbleFrame.origin.y + | |
283 currentWindowFrame.size.height - | |
284 bubbleFrame.size.height; | |
285 [[self window] setFrame:bubbleFrame display:YES]; | |
286 } else { | |
287 [[self window] setFrame:bubbleFrame display:NO]; | |
288 [self setAnchorPoint:[self getExpectedAnchorPoint]]; | |
289 [self showWindow:nil]; | |
290 [[self window] makeFirstResponder:nil]; | |
291 [[self window] setInitialFirstResponder:connectButton_.get()]; | |
292 } | |
293 } | |
294 | |
295 - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView { | |
296 const std::vector<base::string16>& device_names = | |
297 chooser_bubble_delegate_->GetOptions(); | |
298 if (device_names.empty()) { | |
299 return 1; | |
300 } else { | |
301 return static_cast<NSInteger>(device_names.size()); | |
302 } | |
303 } | |
304 | |
305 - (id)tableView:(NSTableView*)tableView | |
306 objectValueForTableColumn:(NSTableColumn*)tableColumn | |
307 row:(NSInteger)rowIndex { | |
308 const std::vector<base::string16>& device_names = | |
309 chooser_bubble_delegate_->GetOptions(); | |
310 if (device_names.empty()) { | |
311 DCHECK(rowIndex == 0); | |
312 return l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_NO_DEVICES_FOUND_PROMPT); | |
313 } else { | |
314 if (rowIndex >= 0 && | |
315 rowIndex < static_cast<NSInteger>(device_names.size())) { | |
316 return base::SysUTF16ToNSString(device_names[rowIndex]); | |
317 } else { | |
318 return @""; | |
319 } | |
320 } | |
321 } | |
322 | |
323 - (BOOL)tableView:(NSTableView*)aTableView | |
324 shouldEditTableColumn:(NSTableColumn*)aTableColumn | |
325 row:(NSInteger)rowIndex { | |
326 return NO; | |
327 } | |
328 | |
329 - (void)onOptionsInitialized { | |
330 [self updateTableView]; | |
331 } | |
332 | |
333 - (void)onOptionAdded:(NSInteger)index { | |
334 [self updateTableView]; | |
335 } | |
336 | |
337 - (void)onOptionRemoved:(NSInteger)index { | |
338 // |tableView_| will automatically selects the next item if the current | |
339 // item is removed, so here it tracks if the removed item is the item | |
340 // that was previously selected, if so, deselect it. | |
341 if ([tableView_ selectedRow] == index) | |
342 [tableView_ deselectRow:index]; | |
343 | |
344 [self updateTableView]; | |
345 } | |
346 | |
347 - (void)updateTableView { | |
348 const std::vector<base::string16>& device_names = | |
349 chooser_bubble_delegate_->GetOptions(); | |
350 [tableView_ setEnabled:!device_names.empty()]; | |
351 [tableView_ reloadData]; | |
352 } | |
353 | |
354 - (void)tableViewSelectionDidChange:(NSNotification*)aNotification { | |
355 [connectButton_ setEnabled:[tableView_ numberOfSelectedRows] > 0]; | |
356 } | |
357 | |
358 - (void)updateAnchorPosition { | |
359 [self setParentWindow:[self getExpectedParentWindow]]; | |
360 [self setAnchorPoint:[self getExpectedAnchorPoint]]; | |
361 } | |
362 | |
363 - (NSPoint)getExpectedAnchorPoint { | |
364 NSPoint anchor; | |
365 if ([self hasLocationBar]) { | |
366 LocationBarViewMac* location_bar = | |
Robert Sesek
2015/12/14 23:13:48
naming: locationBar
juncai
2015/12/15 02:09:28
Done.
| |
367 [[[self getExpectedParentWindow] windowController] locationBarBridge]; | |
368 anchor = location_bar->GetPageInfoBubblePoint(); | |
369 } else { | |
370 // Center the bubble if there's no location bar. | |
371 NSRect contentFrame = [[[self getExpectedParentWindow] contentView] frame]; | |
372 anchor = NSMakePoint(NSMidX(contentFrame), NSMaxY(contentFrame)); | |
373 } | |
374 | |
375 return [[self getExpectedParentWindow] convertBaseToScreen:anchor]; | |
376 } | |
377 | |
378 - (bool)hasLocationBar { | |
379 return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR); | |
380 } | |
381 | |
382 - (info_bubble::BubbleArrowLocation)getExpectedArrowLocation { | |
383 return [self hasLocationBar] ? info_bubble::kTopLeft : info_bubble::kNoArrow; | |
384 } | |
385 | |
386 - (NSWindow*)getExpectedParentWindow { | |
387 DCHECK(browser_->window()); | |
388 return browser_->window()->GetNativeWindow(); | |
389 } | |
390 | |
391 - (base::scoped_nsobject<NSTextField>)bubbleTitle { | |
392 base::scoped_nsobject<NSTextField> titleView( | |
393 [[NSTextField alloc] initWithFrame:NSZeroRect]); | |
394 [titleView setDrawsBackground:NO]; | |
395 [titleView setBezeled:NO]; | |
396 [titleView setEditable:NO]; | |
397 [titleView setSelectable:NO]; | |
398 [titleView setStringValue:l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_PROMPT)]; | |
399 [titleView setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; | |
400 [titleView sizeToFit]; | |
401 NSRect titleFrame = [titleView frame]; | |
402 [titleView setFrameSize:NSMakeSize(NSWidth(titleFrame) + kTitlePaddingX, | |
403 NSHeight(titleFrame))]; | |
404 return titleView; | |
405 } | |
406 | |
407 - (base::scoped_nsobject<NSButton>)buttonWithTitle:(NSString*)title | |
408 action:(SEL)action { | |
409 base::scoped_nsobject<NSButton> button( | |
410 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); | |
411 [button setButtonType:NSMomentaryPushInButton]; | |
412 [button setTitle:title]; | |
413 [button setTarget:self]; | |
414 [button setAction:action]; | |
415 [button sizeToFit]; | |
416 return button; | |
417 } | |
418 | |
419 - (base::scoped_nsobject<NSButton>)connectButton { | |
420 NSString* connectTitle = | |
421 l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_CONNECT_BUTTON_TEXT); | |
422 return [self buttonWithTitle:connectTitle action:@selector(onConnect:)]; | |
423 } | |
424 | |
425 - (base::scoped_nsobject<NSButton>)cancelButton { | |
426 NSString* cancelTitle = | |
427 l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_CANCEL_BUTTON_TEXT); | |
428 return [self buttonWithTitle:cancelTitle action:@selector(onCancel:)]; | |
429 } | |
430 | |
431 + (CGFloat)matchWidthsOf:(NSView*)viewA andOf:(NSView*)viewB { | |
432 NSRect frameA = [viewA frame]; | |
433 NSRect frameB = [viewB frame]; | |
434 CGFloat width = std::max(NSWidth(frameA), NSWidth(frameB)); | |
435 [viewA setFrameSize:NSMakeSize(width, NSHeight(frameA))]; | |
436 [viewB setFrameSize:NSMakeSize(width, NSHeight(frameB))]; | |
437 return width; | |
438 } | |
439 | |
440 + (void)alignCenterOf:(NSView*)viewA verticallyToCenterOf:(NSView*)viewB { | |
441 NSRect frameA = [viewA frame]; | |
442 NSRect frameB = [viewB frame]; | |
443 frameA.origin.y = | |
444 NSMinY(frameB) + std::floor((NSHeight(frameB) - NSHeight(frameA)) / 2); | |
445 [viewA setFrameOrigin:frameA.origin]; | |
446 } | |
447 | |
448 - (void)onConnect:(id)sender { | |
449 NSInteger row = [tableView_ selectedRow]; | |
450 chooser_bubble_delegate_->Select(row); | |
451 [self close]; | |
452 } | |
453 | |
454 - (void)onCancel:(id)sender { | |
455 chooser_bubble_delegate_->Cancel(); | |
456 [self close]; | |
457 } | |
458 | |
459 @end | |
460 | |
461 ChooserBubbleUiCocoa::ChooserBubbleUiCocoa( | |
462 Browser* browser, | |
463 ChooserBubbleDelegate* chooser_bubble_delegate) | |
464 : browser_(browser), | |
465 chooser_bubble_delegate_(chooser_bubble_delegate), | |
466 chooser_bubble_ui_controller_(nil) { | |
467 DCHECK(browser); | |
468 DCHECK(chooser_bubble_delegate); | |
469 chooser_bubble_delegate_->set_observer(this); | |
470 } | |
471 | |
472 ChooserBubbleUiCocoa::~ChooserBubbleUiCocoa() { | |
473 chooser_bubble_delegate_->set_observer(nullptr); | |
474 if (chooser_bubble_ui_controller_) { | |
Robert Sesek
2015/12/14 23:13:48
You don't need to nil-check ObjC objects, as messa
juncai
2015/12/15 02:09:28
Done.
| |
475 [chooser_bubble_ui_controller_ close]; | |
476 chooser_bubble_ui_controller_ = nil; | |
477 } | |
478 } | |
479 | |
480 void ChooserBubbleUiCocoa::Show(BubbleReference bubble_reference) { | |
481 if (!chooser_bubble_ui_controller_) { | |
482 chooser_bubble_ui_controller_ = [[ChooserBubbleUiController alloc] | |
483 initWithBrowser:browser_ | |
484 initWithChooserBubbleDelegate:chooser_bubble_delegate_ | |
485 bridge:this]; | |
486 } | |
487 | |
488 if (chooser_bubble_ui_controller_) { | |
489 [chooser_bubble_ui_controller_ show]; | |
490 [chooser_bubble_ui_controller_ updateTableView]; | |
491 } | |
492 } | |
493 | |
494 void ChooserBubbleUiCocoa::Close() { | |
495 if (chooser_bubble_ui_controller_) { | |
496 [chooser_bubble_ui_controller_ close]; | |
497 chooser_bubble_ui_controller_ = nil; | |
498 } | |
499 } | |
500 | |
501 void ChooserBubbleUiCocoa::UpdateAnchorPosition() { | |
502 [chooser_bubble_ui_controller_ updateAnchorPosition]; | |
503 } | |
504 | |
505 void ChooserBubbleUiCocoa::OnOptionsInitialized() { | |
506 [chooser_bubble_ui_controller_ onOptionsInitialized]; | |
507 } | |
508 | |
509 void ChooserBubbleUiCocoa::OnOptionAdded(int index) { | |
510 [chooser_bubble_ui_controller_ onOptionAdded:index]; | |
511 } | |
512 | |
513 void ChooserBubbleUiCocoa::OnOptionRemoved(int index) { | |
514 [chooser_bubble_ui_controller_ onOptionRemoved:index]; | |
515 } | |
516 | |
517 void ChooserBubbleUiCocoa::OnBubbleClosing() { | |
518 chooser_bubble_ui_controller_ = nil; | |
519 } | |
OLD | NEW |