OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h" | 5 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
11 #include "base/mac/bundle_locations.h" | 11 #include "base/mac/bundle_locations.h" |
12 #include "base/mac/mac_util.h" | 12 #include "base/mac/mac_util.h" |
13 #import "chrome/browser/themes/theme_properties.h" | 13 #import "chrome/browser/themes/theme_properties.h" |
14 #import "chrome/browser/themes/theme_service.h" | 14 #import "chrome/browser/themes/theme_service.h" |
15 #import "chrome/browser/ui/cocoa/sprite_view.h" | 15 #import "chrome/browser/ui/cocoa/sprite_view.h" |
16 #import "chrome/browser/ui/cocoa/tabs/media_indicator_view.h" | 16 #import "chrome/browser/ui/cocoa/tabs/media_indicator_button.h" |
17 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h" | 17 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h" |
18 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" | 18 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" |
19 #import "chrome/browser/ui/cocoa/themed_window.h" | 19 #import "chrome/browser/ui/cocoa/themed_window.h" |
| 20 #include "content/public/browser/user_metrics.h" |
20 #import "extensions/common/extension.h" | 21 #import "extensions/common/extension.h" |
21 #import "ui/base/cocoa/menu_controller.h" | 22 #import "ui/base/cocoa/menu_controller.h" |
22 | 23 |
23 @implementation TabController | 24 @implementation TabController |
24 | 25 |
25 @synthesize action = action_; | 26 @synthesize action = action_; |
26 @synthesize app = app_; | 27 @synthesize app = app_; |
27 @synthesize loadingState = loadingState_; | 28 @synthesize loadingState = loadingState_; |
28 @synthesize mini = mini_; | 29 @synthesize mini = mini_; |
29 @synthesize pinned = pinned_; | 30 @synthesize pinned = pinned_; |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 selector:@selector(themeChangedNotification:) | 121 selector:@selector(themeChangedNotification:) |
121 name:kBrowserThemeDidChangeNotification | 122 name:kBrowserThemeDidChangeNotification |
122 object:nil]; | 123 object:nil]; |
123 | 124 |
124 [self internalSetSelected:selected_]; | 125 [self internalSetSelected:selected_]; |
125 } | 126 } |
126 return self; | 127 return self; |
127 } | 128 } |
128 | 129 |
129 - (void)dealloc { | 130 - (void)dealloc { |
130 [mediaIndicatorView_ setAnimationDoneCallbackObject:nil withSelector:nil]; | |
131 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 131 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
132 [[self tabView] setController:nil]; | 132 [[self tabView] setController:nil]; |
133 [super dealloc]; | 133 [super dealloc]; |
134 } | 134 } |
135 | 135 |
136 // The internals of |-setSelected:| and |-setActive:| but doesn't set the | 136 // The internals of |-setSelected:| and |-setActive:| but doesn't set the |
137 // backing variables. This updates the drawing state and marks self as needing | 137 // backing variables. This updates the drawing state and marks self as needing |
138 // a re-draw. | 138 // a re-draw. |
139 - (void)internalSetSelected:(BOOL)selected { | 139 - (void)internalSetSelected:(BOOL)selected { |
140 TabView* tabView = [self tabView]; | 140 TabView* tabView = [self tabView]; |
(...skipping 15 matching lines...) Expand all Loading... |
156 new TabControllerInternal::MenuDelegate(target_, self)); | 156 new TabControllerInternal::MenuDelegate(target_, self)); |
157 contextMenuModel_.reset( | 157 contextMenuModel_.reset( |
158 [target_ contextMenuModelForController:self | 158 [target_ contextMenuModelForController:self |
159 menuDelegate:contextMenuDelegate_.get()]); | 159 menuDelegate:contextMenuDelegate_.get()]); |
160 contextMenuController_.reset( | 160 contextMenuController_.reset( |
161 [[MenuController alloc] initWithModel:contextMenuModel_.get() | 161 [[MenuController alloc] initWithModel:contextMenuModel_.get() |
162 useWithPopUpButtonCell:NO]); | 162 useWithPopUpButtonCell:NO]); |
163 return [contextMenuController_ menu]; | 163 return [contextMenuController_ menu]; |
164 } | 164 } |
165 | 165 |
| 166 - (void)toggleMute:(id)sender { |
| 167 if ([[self target] respondsToSelector:@selector(toggleMute:)]) { |
| 168 [[self target] performSelector:@selector(toggleMute:) |
| 169 withObject:[self view]]; |
| 170 } |
| 171 } |
| 172 |
166 - (void)closeTab:(id)sender { | 173 - (void)closeTab:(id)sender { |
| 174 using base::UserMetricsAction; |
| 175 |
| 176 if (mediaIndicatorButton_ && ![mediaIndicatorButton_ isHidden]) { |
| 177 if ([mediaIndicatorButton_ isEnabled]) { |
| 178 content::RecordAction(UserMetricsAction("CloseTab_MuteToggleAvailable")); |
| 179 } else if ([mediaIndicatorButton_ showingMediaState] == |
| 180 TAB_MEDIA_STATE_AUDIO_PLAYING) { |
| 181 content::RecordAction(UserMetricsAction("CloseTab_AudioIndicator")); |
| 182 } else { |
| 183 content::RecordAction(UserMetricsAction("CloseTab_RecordingIndicator")); |
| 184 } |
| 185 } else { |
| 186 content::RecordAction(UserMetricsAction("CloseTab_NoMediaIndicator")); |
| 187 } |
| 188 |
167 if ([[self target] respondsToSelector:@selector(closeTab:)]) { | 189 if ([[self target] respondsToSelector:@selector(closeTab:)]) { |
168 [[self target] performSelector:@selector(closeTab:) | 190 [[self target] performSelector:@selector(closeTab:) |
169 withObject:[self view]]; | 191 withObject:[self view]]; |
170 } | 192 } |
171 } | 193 } |
172 | 194 |
173 - (void)selectTab:(id)sender { | 195 - (void)selectTab:(id)sender { |
174 if ([[self tabView] isClosing]) | 196 if ([[self tabView] isClosing]) |
175 return; | 197 return; |
176 if ([[self target] respondsToSelector:[self action]]) { | 198 if ([[self target] respondsToSelector:[self action]]) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 } | 245 } |
224 | 246 |
225 - (void)setIconView:(SpriteView*)iconView { | 247 - (void)setIconView:(SpriteView*)iconView { |
226 [iconView_ removeFromSuperview]; | 248 [iconView_ removeFromSuperview]; |
227 iconView_.reset([iconView retain]); | 249 iconView_.reset([iconView retain]); |
228 | 250 |
229 if (iconView_) | 251 if (iconView_) |
230 [[self view] addSubview:iconView_]; | 252 [[self view] addSubview:iconView_]; |
231 } | 253 } |
232 | 254 |
233 - (MediaIndicatorView*)mediaIndicatorView { | 255 - (MediaIndicatorButton*)mediaIndicatorButton { |
234 return mediaIndicatorView_; | 256 return mediaIndicatorButton_; |
235 } | 257 } |
236 | 258 |
237 - (void)setMediaIndicatorView:(MediaIndicatorView*)mediaIndicatorView { | 259 - (void)setMediaState:(TabMediaState)mediaState { |
238 [mediaIndicatorView_ removeFromSuperview]; | 260 if (!mediaIndicatorButton_ && mediaState != TAB_MEDIA_STATE_NONE) { |
239 mediaIndicatorView_.reset([mediaIndicatorView retain]); | 261 mediaIndicatorButton_.reset([[MediaIndicatorButton alloc] init]); |
240 [self updateVisibility]; | 262 [self updateVisibility]; // Do layout and visibility before adding subview. |
241 if (mediaIndicatorView_) { | 263 [[self view] addSubview:mediaIndicatorButton_]; |
242 [[self view] addSubview:mediaIndicatorView_]; | 264 [mediaIndicatorButton_ setAnimationDoneTarget:self |
243 [mediaIndicatorView_ | 265 withAction:@selector(updateVisibility)]; |
244 setAnimationDoneCallbackObject:self | 266 [mediaIndicatorButton_ setClickTarget:self |
245 withSelector:@selector(updateVisibility)]; | 267 withAction:@selector(toggleMute:)]; |
246 | |
247 } | 268 } |
| 269 [mediaIndicatorButton_ transitionToMediaState:mediaState]; |
248 } | 270 } |
249 | 271 |
250 - (HoverCloseButton*)closeButton { | 272 - (HoverCloseButton*)closeButton { |
251 return closeButton_; | 273 return closeButton_; |
252 } | 274 } |
253 | 275 |
254 - (NSString*)toolTip { | 276 - (NSString*)toolTip { |
255 return [[self tabView] toolTipText]; | 277 return [[self tabView] toolTipText]; |
256 } | 278 } |
257 | 279 |
258 // Return a rough approximation of the number of icons we could fit in the | 280 // Return a rough approximation of the number of icons we could fit in the |
259 // tab. We never actually do this, but it's a helpful guide for determining | 281 // tab. We never actually do this, but it's a helpful guide for determining |
260 // how much space we have available. | 282 // how much space we have available. |
261 - (int)iconCapacity { | 283 - (int)iconCapacity { |
262 const CGFloat availableWidth = std::max<CGFloat>( | 284 const CGFloat availableWidth = std::max<CGFloat>( |
263 0, NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_)); | 285 0, NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_)); |
264 const CGFloat widthPerIcon = NSWidth(originalIconFrame_); | 286 const CGFloat widthPerIcon = NSWidth(originalIconFrame_); |
265 const int kPaddingBetweenIcons = 2; | 287 const int kPaddingBetweenIcons = 2; |
266 if (availableWidth >= widthPerIcon && | 288 if (availableWidth >= widthPerIcon && |
267 availableWidth < (widthPerIcon + kPaddingBetweenIcons)) { | 289 availableWidth < (widthPerIcon + kPaddingBetweenIcons)) { |
268 return 1; | 290 return 1; |
269 } | 291 } |
270 return availableWidth / (widthPerIcon + kPaddingBetweenIcons); | 292 return availableWidth / (widthPerIcon + kPaddingBetweenIcons); |
271 } | 293 } |
272 | 294 |
273 - (BOOL)shouldShowIcon { | 295 - (BOOL)shouldShowIcon { |
274 return chrome::ShouldTabShowFavicon( | 296 return chrome::ShouldTabShowFavicon( |
275 [self iconCapacity], [self mini], [self active], iconView_ != nil, | 297 [self iconCapacity], [self mini], [self active], iconView_ != nil, |
276 !mediaIndicatorView_ ? TAB_MEDIA_STATE_NONE : | 298 !mediaIndicatorButton_ ? TAB_MEDIA_STATE_NONE : |
277 [mediaIndicatorView_ animatingMediaState]); | 299 [mediaIndicatorButton_ showingMediaState]); |
278 } | 300 } |
279 | 301 |
280 - (BOOL)shouldShowMediaIndicator { | 302 - (BOOL)shouldShowMediaIndicator { |
281 if (!mediaIndicatorView_) | |
282 return NO; | |
283 return chrome::ShouldTabShowMediaIndicator( | 303 return chrome::ShouldTabShowMediaIndicator( |
284 [self iconCapacity], [self mini], [self active], iconView_ != nil, | 304 [self iconCapacity], [self mini], [self active], iconView_ != nil, |
285 [mediaIndicatorView_ animatingMediaState]); | 305 !mediaIndicatorButton_ ? TAB_MEDIA_STATE_NONE : |
| 306 [mediaIndicatorButton_ showingMediaState]); |
286 } | 307 } |
287 | 308 |
288 - (BOOL)shouldShowCloseButton { | 309 - (BOOL)shouldShowCloseButton { |
289 return chrome::ShouldTabShowCloseButton( | 310 return chrome::ShouldTabShowCloseButton( |
290 [self iconCapacity], [self mini], [self active]); | 311 [self iconCapacity], [self mini], [self active]); |
291 } | 312 } |
292 | 313 |
293 - (void)setIconImage:(NSImage*)image { | 314 - (void)setIconImage:(NSImage*)image { |
294 [self setIconImage:image withToastAnimation:NO]; | 315 [self setIconImage:image withToastAnimation:NO]; |
295 } | 316 } |
(...skipping 18 matching lines...) Expand all Loading... |
314 : [TabController miniTabWidth]; | 335 : [TabController miniTabWidth]; |
315 | 336 |
316 // Center the icon. | 337 // Center the icon. |
317 appIconFrame.origin.x = | 338 appIconFrame.origin.x = |
318 std::floor((tabWidth - NSWidth(appIconFrame)) / 2.0); | 339 std::floor((tabWidth - NSWidth(appIconFrame)) / 2.0); |
319 [iconView_ setFrame:appIconFrame]; | 340 [iconView_ setFrame:appIconFrame]; |
320 } else { | 341 } else { |
321 [iconView_ setFrame:originalIconFrame_]; | 342 [iconView_ setFrame:originalIconFrame_]; |
322 } | 343 } |
323 } | 344 } |
324 // Ensure that the icon is suppressed if no icon is set or if the tab is too | |
325 // narrow to display one. | |
326 [self updateVisibility]; | |
327 } | 345 } |
328 | 346 |
329 - (void)updateVisibility { | 347 - (void)updateVisibility { |
330 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden] | 348 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden] |
331 // won't work. Instead, the state of the icon is tracked separately in | 349 // won't work. Instead, the state of the icon is tracked separately in |
332 // isIconShowing_. | 350 // isIconShowing_. |
333 BOOL newShowIcon = [self shouldShowIcon]; | 351 BOOL newShowIcon = [self shouldShowIcon]; |
334 | 352 |
335 [iconView_ setHidden:!newShowIcon]; | 353 [iconView_ setHidden:!newShowIcon]; |
336 isIconShowing_ = newShowIcon; | 354 isIconShowing_ = newShowIcon; |
337 | 355 |
338 // If the tab is a mini-tab, hide the title. | 356 // If the tab is a mini-tab, hide the title. |
339 TabView* tabView = [self tabView]; | 357 TabView* tabView = [self tabView]; |
340 [tabView setTitleHidden:[self mini]]; | 358 [tabView setTitleHidden:[self mini]]; |
341 | 359 |
342 BOOL newShowCloseButton = [self shouldShowCloseButton]; | 360 BOOL newShowCloseButton = [self shouldShowCloseButton]; |
343 | 361 |
344 [closeButton_ setHidden:!newShowCloseButton]; | 362 [closeButton_ setHidden:!newShowCloseButton]; |
345 | 363 |
346 BOOL newShowMediaIndicator = [self shouldShowMediaIndicator]; | 364 BOOL newShowMediaIndicator = [self shouldShowMediaIndicator]; |
347 | 365 |
348 [mediaIndicatorView_ setHidden:!newShowMediaIndicator]; | 366 [mediaIndicatorButton_ setHidden:!newShowMediaIndicator]; |
349 | 367 |
350 if (newShowMediaIndicator) { | 368 if (newShowMediaIndicator) { |
351 NSRect newFrame = [mediaIndicatorView_ frame]; | 369 NSRect newFrame = [mediaIndicatorButton_ frame]; |
| 370 newFrame.size = [[mediaIndicatorButton_ image] size]; |
352 if ([self app] || [self mini]) { | 371 if ([self app] || [self mini]) { |
353 // Tab is pinned: Position the media indicator in the center. | 372 // Tab is pinned: Position the media indicator in the center. |
354 const CGFloat tabWidth = [self app] ? | 373 const CGFloat tabWidth = [self app] ? |
355 [TabController appTabWidth] : [TabController miniTabWidth]; | 374 [TabController appTabWidth] : [TabController miniTabWidth]; |
356 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2); | 375 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2); |
357 newFrame.origin.y = NSMinY(originalIconFrame_) - | 376 newFrame.origin.y = NSMinY(originalIconFrame_) - |
358 std::floor((NSHeight(newFrame) - NSHeight(originalIconFrame_)) / 2); | 377 std::floor((NSHeight(newFrame) - NSHeight(originalIconFrame_)) / 2); |
359 } else { | 378 } else { |
360 // The Frame for the mediaIndicatorView_ depends on whether iconView_ | 379 // The Frame for the mediaIndicatorButton_ depends on whether iconView_ |
361 // and/or closeButton_ are visible, and where they have been positioned. | 380 // and/or closeButton_ are visible, and where they have been positioned. |
362 const NSRect closeButtonFrame = [closeButton_ frame]; | 381 const NSRect closeButtonFrame = [closeButton_ frame]; |
363 newFrame.origin.x = NSMinX(closeButtonFrame); | 382 newFrame.origin.x = NSMinX(closeButtonFrame); |
364 // Position to the left of the close button when it is showing. | 383 // Position to the left of the close button when it is showing. |
365 if (newShowCloseButton) | 384 if (newShowCloseButton) |
366 newFrame.origin.x -= NSWidth(newFrame); | 385 newFrame.origin.x -= NSWidth(newFrame); |
367 // Media indicator is centered vertically, with respect to closeButton_. | 386 // Media indicator is centered vertically, with respect to closeButton_. |
368 newFrame.origin.y = NSMinY(closeButtonFrame) - | 387 newFrame.origin.y = NSMinY(closeButtonFrame) - |
369 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2); | 388 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2); |
370 } | 389 } |
371 [mediaIndicatorView_ setFrame:newFrame]; | 390 [mediaIndicatorButton_ setFrame:newFrame]; |
372 } | 391 } |
373 | 392 |
374 // Adjust the title view based on changes to the icon's and close button's | 393 // Adjust the title view based on changes to the icon's and close button's |
375 // visibility. | 394 // visibility. |
376 NSRect oldTitleFrame = [tabView titleFrame]; | 395 NSRect oldTitleFrame = [tabView titleFrame]; |
377 NSRect newTitleFrame; | 396 NSRect newTitleFrame; |
378 newTitleFrame.size.height = oldTitleFrame.size.height; | 397 newTitleFrame.size.height = oldTitleFrame.size.height; |
379 newTitleFrame.origin.y = oldTitleFrame.origin.y; | 398 newTitleFrame.origin.y = oldTitleFrame.origin.y; |
380 | 399 |
381 if (newShowIcon) { | 400 if (newShowIcon) { |
382 newTitleFrame.origin.x = NSMaxX([iconView_ frame]); | 401 newTitleFrame.origin.x = NSMaxX([iconView_ frame]); |
383 } else { | 402 } else { |
384 newTitleFrame.origin.x = originalIconFrame_.origin.x; | 403 newTitleFrame.origin.x = originalIconFrame_.origin.x; |
385 } | 404 } |
386 | 405 |
387 if (newShowMediaIndicator) { | 406 if (newShowMediaIndicator) { |
388 newTitleFrame.size.width = NSMinX([mediaIndicatorView_ frame]) - | 407 newTitleFrame.size.width = NSMinX([mediaIndicatorButton_ frame]) - |
389 newTitleFrame.origin.x; | 408 newTitleFrame.origin.x; |
390 } else if (newShowCloseButton) { | 409 } else if (newShowCloseButton) { |
391 newTitleFrame.size.width = NSMinX([closeButton_ frame]) - | 410 newTitleFrame.size.width = NSMinX([closeButton_ frame]) - |
392 newTitleFrame.origin.x; | 411 newTitleFrame.origin.x; |
393 } else { | 412 } else { |
394 newTitleFrame.size.width = NSMaxX([closeButton_ frame]) - | 413 newTitleFrame.size.width = NSMaxX([closeButton_ frame]) - |
395 newTitleFrame.origin.x; | 414 newTitleFrame.origin.x; |
396 } | 415 } |
397 | 416 |
398 [tabView setTitleFrame:newTitleFrame]; | 417 [tabView setTitleFrame:newTitleFrame]; |
(...skipping 27 matching lines...) Expand all Loading... |
426 // TabStripDragController. | 445 // TabStripDragController. |
427 - (BOOL)tabCanBeDragged:(TabController*)controller { | 446 - (BOOL)tabCanBeDragged:(TabController*)controller { |
428 return [[target_ dragController] tabCanBeDragged:controller]; | 447 return [[target_ dragController] tabCanBeDragged:controller]; |
429 } | 448 } |
430 | 449 |
431 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab { | 450 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab { |
432 [[target_ dragController] maybeStartDrag:event forTab:tab]; | 451 [[target_ dragController] maybeStartDrag:event forTab:tab]; |
433 } | 452 } |
434 | 453 |
435 @end | 454 @end |
OLD | NEW |