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 <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "base/mac/bundle_locations.h" | 9 #include "base/mac/bundle_locations.h" |
10 #include "base/mac/mac_util.h" | 10 #include "base/mac/mac_util.h" |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 [self updateVisibility]; | 266 [self updateVisibility]; |
267 | 267 |
268 if (iconView_) | 268 if (iconView_) |
269 [[self view] addSubview:iconView_]; | 269 [[self view] addSubview:iconView_]; |
270 } | 270 } |
271 | 271 |
272 - (NSTextField*)titleView { | 272 - (NSTextField*)titleView { |
273 return titleView_; | 273 return titleView_; |
274 } | 274 } |
275 | 275 |
| 276 - (NSView*)audioIndicatorView { |
| 277 return audioIndicatorView_; |
| 278 } |
| 279 |
| 280 - (void)setAudioIndicatorView:(NSView*)audioIndicatorView { |
| 281 if (audioIndicatorView == audioIndicatorView_) |
| 282 return; |
| 283 [audioIndicatorView_ removeFromSuperview]; |
| 284 audioIndicatorView_.reset([audioIndicatorView retain]); |
| 285 [self updateVisibility]; |
| 286 if (audioIndicatorView_) |
| 287 [[self view] addSubview:audioIndicatorView_]; |
| 288 } |
| 289 |
276 - (HoverCloseButton*)closeButton { | 290 - (HoverCloseButton*)closeButton { |
277 return closeButton_; | 291 return closeButton_; |
278 } | 292 } |
279 | 293 |
280 - (NSString*)toolTip { | 294 - (NSString*)toolTip { |
281 return [[self tabView] toolTipText]; | 295 return [[self tabView] toolTipText]; |
282 } | 296 } |
283 | 297 |
284 // Return a rough approximation of the number of icons we could fit in the | 298 // Return a rough approximation of the number of icons we could fit in the |
285 // tab. We never actually do this, but it's a helpful guide for determining | 299 // tab. We never actually do this, but it's a helpful guide for determining |
286 // how much space we have available. | 300 // how much space we have available. |
287 - (int)iconCapacity { | 301 - (int)iconCapacity { |
288 CGFloat width = NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_); | 302 CGFloat width = NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_); |
289 CGFloat iconWidth = NSWidth(originalIconFrame_); | 303 const int kPaddingBetweenIcons = 2; |
| 304 CGFloat iconWidth = NSWidth(originalIconFrame_) + kPaddingBetweenIcons; |
290 | 305 |
291 return width / iconWidth; | 306 return width / iconWidth; |
292 } | 307 } |
293 | 308 |
294 // Returns YES if we should show the icon. When tabs get too small, we clip | 309 // Returns YES if we should show the icon. When tabs get too small, we clip |
295 // the favicon before the close button for selected tabs, and prefer the | 310 // the favicon before the close button for selected tabs, and prefer the |
296 // favicon for unselected tabs. The icon can also be suppressed more directly | 311 // favicon for unselected tabs. Exception: We clip the favicon before the audio |
| 312 // indicator in all cases. The icon can also be suppressed more directly |
297 // by clearing iconView_. | 313 // by clearing iconView_. |
298 - (BOOL)shouldShowIcon { | 314 - (BOOL)shouldShowIcon { |
299 if (!iconView_) | 315 if (!iconView_) |
300 return NO; | 316 return NO; |
| 317 const BOOL shouldShowAudioIndicator = [self shouldShowAudioIndicator]; |
| 318 if ([self mini]) |
| 319 return !shouldShowAudioIndicator; |
| 320 int required_capacity = shouldShowAudioIndicator ? 2 : 1; |
| 321 if ([self selected]) { |
| 322 // Active tabs give priority to the close button, then the audio indicator, |
| 323 // then the favicon. |
| 324 ++required_capacity; |
| 325 } else { |
| 326 // Non-selected tabs give priority to the audio indicator, then the favicon, |
| 327 // and finally the close button. |
| 328 } |
| 329 return [self iconCapacity] >= required_capacity; |
| 330 } |
301 | 331 |
| 332 // Returns YES if we should show the audio indicator. When tabs get too small, |
| 333 // we clip the audio indicator before the close button for selected tabs, and |
| 334 // prefer the audio indicator for unselected tabs. |
| 335 - (BOOL)shouldShowAudioIndicator { |
| 336 if (!audioIndicatorView_) |
| 337 return NO; |
302 if ([self mini]) | 338 if ([self mini]) |
303 return YES; | 339 return YES; |
304 | 340 if ([self selected]) { |
305 int iconCapacity = [self iconCapacity]; | 341 // The active tab clips the audio indicator before the close button. |
306 if ([self selected]) | 342 return [self iconCapacity] >= 2; |
307 return iconCapacity >= 2; | 343 } |
308 return iconCapacity >= 1; | 344 // Non-selected tabs clip close button before the audio indicator. |
| 345 return [self iconCapacity] >= 1; |
309 } | 346 } |
310 | 347 |
311 // Returns YES if we should be showing the close button. The selected tab | 348 // Returns YES if we should be showing the close button. The selected tab |
312 // always shows the close button. | 349 // always shows the close button. |
313 - (BOOL)shouldShowCloseButton { | 350 - (BOOL)shouldShowCloseButton { |
314 if ([self mini]) | 351 if ([self mini]) |
315 return NO; | 352 return NO; |
316 return ([self selected] || [self iconCapacity] >= 3); | 353 return ([self selected] || [self iconCapacity] >= 3); |
317 } | 354 } |
318 | 355 |
319 - (void)updateVisibility { | 356 - (void)updateVisibility { |
320 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden] | 357 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden] |
321 // won't work. Instead, the state of the icon is tracked separately in | 358 // won't work. Instead, the state of the icon is tracked separately in |
322 // isIconShowing_. | 359 // isIconShowing_. |
323 BOOL newShowIcon = [self shouldShowIcon]; | 360 BOOL newShowIcon = [self shouldShowIcon]; |
324 | 361 |
325 [iconView_ setHidden:!newShowIcon]; | 362 [iconView_ setHidden:!newShowIcon]; |
326 isIconShowing_ = newShowIcon; | 363 isIconShowing_ = newShowIcon; |
327 | 364 |
328 // If the tab is a mini-tab, hide the title. | 365 // If the tab is a mini-tab, hide the title. |
329 [titleView_ setHidden:[self mini]]; | 366 [titleView_ setHidden:[self mini]]; |
330 | 367 |
331 BOOL newShowCloseButton = [self shouldShowCloseButton]; | 368 BOOL newShowCloseButton = [self shouldShowCloseButton]; |
332 | 369 |
333 [closeButton_ setHidden:!newShowCloseButton]; | 370 [closeButton_ setHidden:!newShowCloseButton]; |
334 | 371 |
| 372 BOOL newShowAudioIndicator = [self shouldShowAudioIndicator]; |
| 373 |
| 374 if (audioIndicatorView_) { |
| 375 [audioIndicatorView_ setHidden:!newShowAudioIndicator]; |
| 376 |
| 377 NSRect newFrame = [audioIndicatorView_ frame]; |
| 378 if ([self app] || [self mini]) { |
| 379 // Tab is pinned: Position the audio indicator in the center. |
| 380 const CGFloat tabWidth = [self app] ? |
| 381 [TabController appTabWidth] : [TabController miniTabWidth]; |
| 382 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2); |
| 383 newFrame.origin.y = NSMinY(originalIconFrame_) - |
| 384 std::floor((NSHeight(newFrame) - NSHeight(originalIconFrame_)) / 2); |
| 385 } else { |
| 386 // The Frame for the audioIndicatorView_ depends on whether iconView_ |
| 387 // and/or closeButton_ are visible, and where they have been positioned. |
| 388 const NSRect closeButtonFrame = [closeButton_ frame]; |
| 389 newFrame.origin.x = NSMinX(closeButtonFrame); |
| 390 // Position to the left of the close button when it is showing. |
| 391 if (newShowCloseButton) |
| 392 newFrame.origin.x -= NSWidth(newFrame); |
| 393 // Audio indicator is centered vertically, with respect to closeButton_. |
| 394 newFrame.origin.y = NSMinY(closeButtonFrame) - |
| 395 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2); |
| 396 } |
| 397 [audioIndicatorView_ setFrame:newFrame]; |
| 398 } |
| 399 |
335 // Adjust the title view based on changes to the icon's and close button's | 400 // Adjust the title view based on changes to the icon's and close button's |
336 // visibility. | 401 // visibility. |
337 NSRect oldTitleFrame = [titleView_ frame]; | 402 NSRect oldTitleFrame = [titleView_ frame]; |
338 NSRect newTitleFrame; | 403 NSRect newTitleFrame; |
339 newTitleFrame.size.height = oldTitleFrame.size.height; | 404 newTitleFrame.size.height = oldTitleFrame.size.height; |
340 newTitleFrame.origin.y = oldTitleFrame.origin.y; | 405 newTitleFrame.origin.y = oldTitleFrame.origin.y; |
341 | 406 |
342 if (newShowIcon) { | 407 if (newShowIcon) { |
343 newTitleFrame.origin.x = originalIconFrame_.origin.x + iconTitleXOffset_; | 408 newTitleFrame.origin.x = originalIconFrame_.origin.x + iconTitleXOffset_; |
344 } else { | 409 } else { |
345 newTitleFrame.origin.x = originalIconFrame_.origin.x; | 410 newTitleFrame.origin.x = originalIconFrame_.origin.x; |
346 } | 411 } |
347 | 412 |
348 if (newShowCloseButton) { | 413 if (newShowAudioIndicator) { |
| 414 newTitleFrame.size.width = NSMinX([audioIndicatorView_ frame]) - |
| 415 newTitleFrame.origin.x; |
| 416 } else if (newShowCloseButton) { |
349 newTitleFrame.size.width = NSMinX([closeButton_ frame]) - | 417 newTitleFrame.size.width = NSMinX([closeButton_ frame]) - |
350 newTitleFrame.origin.x; | 418 newTitleFrame.origin.x; |
351 } else { | 419 } else { |
352 newTitleFrame.size.width = NSMaxX([closeButton_ frame]) - | 420 newTitleFrame.size.width = NSMaxX([closeButton_ frame]) - |
353 newTitleFrame.origin.x; | 421 newTitleFrame.origin.x; |
354 } | 422 } |
355 | 423 |
356 [titleView_ setFrame:newTitleFrame]; | 424 [titleView_ setFrame:newTitleFrame]; |
357 } | 425 } |
358 | 426 |
(...skipping 25 matching lines...) Expand all Loading... |
384 // TabStripDragController. | 452 // TabStripDragController. |
385 - (BOOL)tabCanBeDragged:(TabController*)controller { | 453 - (BOOL)tabCanBeDragged:(TabController*)controller { |
386 return [[target_ dragController] tabCanBeDragged:controller]; | 454 return [[target_ dragController] tabCanBeDragged:controller]; |
387 } | 455 } |
388 | 456 |
389 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab { | 457 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab { |
390 [[target_ dragController] maybeStartDrag:event forTab:tab]; | 458 [[target_ dragController] maybeStartDrag:event forTab:tab]; |
391 } | 459 } |
392 | 460 |
393 @end | 461 @end |
OLD | NEW |