Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/cocoa/tab_strip_controller.h" | 5 #import "chrome/browser/cocoa/tab_strip_controller.h" |
| 6 | 6 |
| 7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "base/mac_util.h" | 8 #include "base/mac_util.h" |
| 9 #include "base/sys_string_conversions.h" | 9 #include "base/sys_string_conversions.h" |
| 10 #include "chrome/app/chrome_dll_resource.h" | 10 #include "chrome/app/chrome_dll_resource.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 DCHECK([newTabButton_ isKindOfClass:[NSButton class]]); | 59 DCHECK([newTabButton_ isKindOfClass:[NSButton class]]); |
| 60 [newTabButton_ setTarget:nil]; | 60 [newTabButton_ setTarget:nil]; |
| 61 [newTabButton_ setAction:@selector(commandDispatch:)]; | 61 [newTabButton_ setAction:@selector(commandDispatch:)]; |
| 62 [newTabButton_ setTag:IDC_NEW_TAB]; | 62 [newTabButton_ setTag:IDC_NEW_TAB]; |
| 63 targetFrames_.reset([[NSMutableDictionary alloc] init]); | 63 targetFrames_.reset([[NSMutableDictionary alloc] init]); |
| 64 [tabView_ setWantsLayer:YES]; | 64 [tabView_ setWantsLayer:YES]; |
| 65 dragBlockingView_.reset([[TabStripControllerDragBlockingView alloc] | 65 dragBlockingView_.reset([[TabStripControllerDragBlockingView alloc] |
| 66 initWithFrame:NSZeroRect]); | 66 initWithFrame:NSZeroRect]); |
| 67 [view addSubview:dragBlockingView_]; | 67 [view addSubview:dragBlockingView_]; |
| 68 newTabTargetFrame_ = NSMakeRect(0, 0, 0, 0); | 68 newTabTargetFrame_ = NSMakeRect(0, 0, 0, 0); |
| 69 | |
| 70 // Watch for notifications that the tab strip view has changed size so | |
| 71 // we can tell it to layout for the new size. | |
| 72 [[NSNotificationCenter defaultCenter] | |
| 73 addObserver:self | |
| 74 selector:@selector(tabViewFrameChanged:) | |
| 75 name:NSViewFrameDidChangeNotification | |
| 76 object:tabView_]; | |
| 69 } | 77 } |
| 70 return self; | 78 return self; |
| 71 } | 79 } |
| 72 | 80 |
| 81 - (void)dealloc { | |
| 82 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 83 [super dealloc]; | |
| 84 } | |
| 85 | |
| 73 + (CGFloat)defaultTabHeight { | 86 + (CGFloat)defaultTabHeight { |
| 74 return 24.0; | 87 return 24.0; |
| 75 } | 88 } |
| 76 | 89 |
| 77 // Finds the associated TabContentsController at the given |index| and swaps | 90 // Finds the associated TabContentsController at the given |index| and swaps |
| 78 // out the sole child of the contentArea to display its contents. | 91 // out the sole child of the contentArea to display its contents. |
| 79 - (void)swapInTabAtIndex:(NSInteger)index { | 92 - (void)swapInTabAtIndex:(NSInteger)index { |
| 80 TabContentsController* controller = [tabContentsArray_ objectAtIndex:index]; | 93 TabContentsController* controller = [tabContentsArray_ objectAtIndex:index]; |
| 81 | 94 |
| 82 // Resize the new view to fit the window. Calling |view| may lazily | 95 // Resize the new view to fit the window. Calling |view| may lazily |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 187 yStretchiness:(CGFloat)yStretchiness { | 200 yStretchiness:(CGFloat)yStretchiness { |
| 188 placeholderTab_ = tab; | 201 placeholderTab_ = tab; |
| 189 placeholderFrame_ = frame; | 202 placeholderFrame_ = frame; |
| 190 placeholderStretchiness_ = yStretchiness; | 203 placeholderStretchiness_ = yStretchiness; |
| 191 [self layoutTabs]; | 204 [self layoutTabs]; |
| 192 } | 205 } |
| 193 | 206 |
| 194 // Lay out all tabs in the order of their TabContentsControllers, which matches | 207 // Lay out all tabs in the order of their TabContentsControllers, which matches |
| 195 // the ordering in the TabStripModel. This call isn't that expensive, though | 208 // the ordering in the TabStripModel. This call isn't that expensive, though |
| 196 // it is O(n) in the number of tabs. Tabs will animate to their new position | 209 // it is O(n) in the number of tabs. Tabs will animate to their new position |
| 197 // if the window is visible. | 210 // if the window is visible and |animate| is YES. |
| 198 // TODO(pinkerton): Handle drag placeholders via proxy objects, perhaps a | 211 // TODO(pinkerton): Handle drag placeholders via proxy objects, perhaps a |
| 199 // subclass of TabContentsController with everything stubbed out or by | 212 // subclass of TabContentsController with everything stubbed out or by |
| 200 // abstracting a base class interface. | 213 // abstracting a base class interface. |
| 201 // TODO(pinkerton): Note this doesn't do too well when the number of min-sized | 214 // TODO(pinkerton): Note this doesn't do too well when the number of min-sized |
| 202 // tabs would cause an overflow. | 215 // tabs would cause an overflow. |
| 203 - (void)layoutTabs { | 216 - (void)layoutTabsWithAnimation:(BOOL)animate { |
| 204 const float kIndentLeavingSpaceForControls = 64.0; | 217 const float kIndentLeavingSpaceForControls = 64.0; |
| 205 const float kTabOverlap = 20.0; | 218 const float kTabOverlap = 20.0; |
| 206 const float kNewTabButtonOffset = 8.0; | 219 const float kNewTabButtonOffset = 8.0; |
| 207 const float kMaxTabWidth = [TabController maxTabWidth]; | 220 const float kMaxTabWidth = [TabController maxTabWidth]; |
| 208 const float kMinTabWidth = [TabController minTabWidth]; | 221 const float kMinTabWidth = [TabController minTabWidth]; |
| 209 const float kMinSelectedTabWidth = [TabController minSelectedTabWidth]; | 222 const float kMinSelectedTabWidth = [TabController minSelectedTabWidth]; |
| 210 | 223 |
| 211 NSRect enclosingRect = NSZeroRect; | 224 NSRect enclosingRect = NSZeroRect; |
| 212 [NSAnimationContext beginGrouping]; | 225 [NSAnimationContext beginGrouping]; |
| 213 [[NSAnimationContext currentContext] setDuration:0.2]; | 226 [[NSAnimationContext currentContext] setDuration:0.2]; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 238 tabFrame.origin.x = offset; | 251 tabFrame.origin.x = offset; |
| 239 | 252 |
| 240 // If the tab is hidden, we consider it a new tab. We make it visible | 253 // If the tab is hidden, we consider it a new tab. We make it visible |
| 241 // and animate it in. | 254 // and animate it in. |
| 242 BOOL newTab = [[tab view] isHidden]; | 255 BOOL newTab = [[tab view] isHidden]; |
| 243 if (newTab) { | 256 if (newTab) { |
| 244 [[tab view] setHidden:NO]; | 257 [[tab view] setHidden:NO]; |
| 245 } | 258 } |
| 246 | 259 |
| 247 if (isPlaceholder) { | 260 if (isPlaceholder) { |
| 248 // Move the current tab to the correct location intantly. | 261 // Move the current tab to the correct location intantly. |
|
rohitrao (ping after 24h)
2009/07/24 16:11:22
Typo: intantly.
| |
| 249 // We need a duration or else it doesn't cancel an inflight animation. | 262 // We need a duration or else it doesn't cancel an inflight animation. |
| 250 [NSAnimationContext beginGrouping]; | 263 [NSAnimationContext beginGrouping]; |
| 251 [[NSAnimationContext currentContext] setDuration:0.000001]; | 264 [[NSAnimationContext currentContext] setDuration:0.000001]; |
| 252 tabFrame.origin.x = placeholderFrame_.origin.x; | 265 tabFrame.origin.x = placeholderFrame_.origin.x; |
| 253 // TODO(alcor): reenable this | 266 // TODO(alcor): reenable this |
| 254 //tabFrame.size.height += 10.0 * placeholderStretchiness_; | 267 //tabFrame.size.height += 10.0 * placeholderStretchiness_; |
| 255 [[[tab view] animator] setFrame:tabFrame]; | 268 id target = animate ? [[tab view] animator] : [tab view]; |
| 269 [target setFrame:tabFrame]; | |
| 256 [NSAnimationContext endGrouping]; | 270 [NSAnimationContext endGrouping]; |
| 257 | 271 |
| 258 // Store the frame by identifier to aviod redundant calls to animator. | 272 // Store the frame by identifier to aviod redundant calls to animator. |
| 259 NSValue *identifier = [NSValue valueWithPointer:[tab view]]; | 273 NSValue *identifier = [NSValue valueWithPointer:[tab view]]; |
| 260 [targetFrames_ setObject:[NSValue valueWithRect:tabFrame] | 274 [targetFrames_ setObject:[NSValue valueWithRect:tabFrame] |
| 261 forKey:identifier]; | 275 forKey:identifier]; |
| 262 continue; | 276 continue; |
| 263 } else { | 277 } else { |
| 264 // If our left edge is to the left of the placeholder's left, but our mid | 278 // If our left edge is to the left of the placeholder's left, but our mid |
| 265 // is to the right of it we should slide over to make space for it. | 279 // is to the right of it we should slide over to make space for it. |
| 266 if (placeholderTab_ && gap < 0 && NSMidX(tabFrame) > minX) { | 280 if (placeholderTab_ && gap < 0 && NSMidX(tabFrame) > minX) { |
| 267 gap = i; | 281 gap = i; |
| 268 offset += NSWidth(tabFrame); | 282 offset += NSWidth(tabFrame); |
| 269 offset -= kTabOverlap; | 283 offset -= kTabOverlap; |
| 270 tabFrame.origin.x = offset; | 284 tabFrame.origin.x = offset; |
| 271 } | 285 } |
| 272 | 286 |
| 273 // Animate the tab in by putting it below the horizon. | 287 // Animate the tab in by putting it below the horizon. |
| 274 if (newTab && visible) { | 288 if (newTab && visible && animate) { |
| 275 [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))]; | 289 [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))]; |
| 276 } | 290 } |
| 277 | 291 |
| 278 // Set the width. Selected tabs are slightly wider when things get | 292 // Set the width. Selected tabs are slightly wider when things get |
| 279 // really small and thus we enforce a different minimum width. | 293 // really small and thus we enforce a different minimum width. |
| 280 tabFrame.size.width = | 294 tabFrame.size.width = |
| 281 [tab selected] ? MAX(baseTabWidth, kMinSelectedTabWidth) : | 295 [tab selected] ? MAX(baseTabWidth, kMinSelectedTabWidth) : |
| 282 baseTabWidth; | 296 baseTabWidth; |
| 283 | 297 |
| 284 // Check the frame by identifier to avoid redundant calls to animator. | 298 // Check the frame by identifier to avoid redundant calls to animator. |
| 285 id frameTarget = visible ? [[tab view] animator] : [tab view]; | 299 id frameTarget = visible && animate ? [[tab view] animator] : [tab view]; |
|
TVL
2009/07/24 16:27:03
line 268 this was "target", here it's "frameTarget
| |
| 286 NSValue *identifier = [NSValue valueWithPointer:[tab view]]; | 300 NSValue *identifier = [NSValue valueWithPointer:[tab view]]; |
| 287 NSValue *oldTargetValue = [targetFrames_ objectForKey:identifier]; | 301 NSValue *oldTargetValue = [targetFrames_ objectForKey:identifier]; |
| 288 if (!oldTargetValue || | 302 if (!oldTargetValue || |
| 289 !NSEqualRects([oldTargetValue rectValue], tabFrame)) { | 303 !NSEqualRects([oldTargetValue rectValue], tabFrame)) { |
| 290 [frameTarget setFrame:tabFrame]; | 304 [frameTarget setFrame:tabFrame]; |
| 291 [targetFrames_ setObject:[NSValue valueWithRect:tabFrame] | 305 [targetFrames_ setObject:[NSValue valueWithRect:tabFrame] |
| 292 forKey:identifier]; | 306 forKey:identifier]; |
| 293 } | 307 } |
| 294 enclosingRect = NSUnionRect(tabFrame, enclosingRect); | 308 enclosingRect = NSUnionRect(tabFrame, enclosingRect); |
| 295 } | 309 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 310 offset -= kTabOverlap; | 324 offset -= kTabOverlap; |
| 311 i++; | 325 i++; |
| 312 } | 326 } |
| 313 | 327 |
| 314 NSRect newTabNewFrame = [newTabButton_ frame]; | 328 NSRect newTabNewFrame = [newTabButton_ frame]; |
| 315 newTabNewFrame.origin = | 329 newTabNewFrame.origin = |
| 316 NSMakePoint(MIN(availableWidth, offset + kNewTabButtonOffset), 0); | 330 NSMakePoint(MIN(availableWidth, offset + kNewTabButtonOffset), 0); |
| 317 newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x, | 331 newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x, |
| 318 NSMaxX(placeholderFrame_)); | 332 NSMaxX(placeholderFrame_)); |
| 319 if (i > 0 && [newTabButton_ isHidden]) { | 333 if (i > 0 && [newTabButton_ isHidden]) { |
| 320 [[newTabButton_ animator] setHidden:NO]; | 334 id target = animate ? [newTabButton_ animator] : newTabButton_; |
| 335 [target setHidden:NO]; | |
| 321 } | 336 } |
| 322 | 337 |
| 323 if (!NSEqualRects(newTabTargetFrame_, newTabNewFrame)) { | 338 if (!NSEqualRects(newTabTargetFrame_, newTabNewFrame)) { |
| 324 [newTabButton_ setFrame:newTabNewFrame]; | 339 [newTabButton_ setFrame:newTabNewFrame]; |
| 325 newTabTargetFrame_ = newTabNewFrame; | 340 newTabTargetFrame_ = newTabNewFrame; |
| 326 // Move the new tab button into place. | 341 // Move the new tab button into place. |
| 327 } | 342 } |
| 328 | 343 |
| 329 [NSAnimationContext endGrouping]; | 344 [NSAnimationContext endGrouping]; |
| 330 [dragBlockingView_ setFrame:enclosingRect]; | 345 [dragBlockingView_ setFrame:enclosingRect]; |
| 331 } | 346 } |
| 332 | 347 |
| 348 // When we're told to layout from the public API we always want to animate. | |
| 349 - (void)layoutTabs { | |
| 350 [self layoutTabsWithAnimation:YES]; | |
| 351 } | |
| 352 | |
| 333 // Handles setting the title of the tab based on the given |contents|. Uses | 353 // Handles setting the title of the tab based on the given |contents|. Uses |
| 334 // a canned string if |contents| is NULL. | 354 // a canned string if |contents| is NULL. |
| 335 - (void)setTabTitle:(NSViewController*)tab withContents:(TabContents*)contents { | 355 - (void)setTabTitle:(NSViewController*)tab withContents:(TabContents*)contents { |
| 336 NSString* titleString = nil; | 356 NSString* titleString = nil; |
| 337 if (contents) | 357 if (contents) |
| 338 titleString = base::SysUTF16ToNSString(contents->GetTitle()); | 358 titleString = base::SysUTF16ToNSString(contents->GetTitle()); |
| 339 if (![titleString length]) { | 359 if (![titleString length]) { |
| 340 titleString = | 360 titleString = |
| 341 base::SysWideToNSString( | 361 base::SysWideToNSString( |
| 342 l10n_util::GetString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED)); | 362 l10n_util::GetString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED)); |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 619 // inherit the current tab's group. | 639 // inherit the current tab's group. |
| 620 tabModel_->InsertTabContentsAt(index, contents, true, false); | 640 tabModel_->InsertTabContentsAt(index, contents, true, false); |
| 621 } | 641 } |
| 622 | 642 |
| 623 - (void)userChangedTheme { | 643 - (void)userChangedTheme { |
| 624 for (TabController* tab in tabArray_.get()) { | 644 for (TabController* tab in tabArray_.get()) { |
| 625 [[tab view] setNeedsDisplay:YES]; | 645 [[tab view] setNeedsDisplay:YES]; |
| 626 } | 646 } |
| 627 } | 647 } |
| 628 | 648 |
| 649 // Called when the tab strip view changes size. As we only registered for | |
| 650 // changes on our view, we know it's only for our view. Layout w/out | |
| 651 // animations since they are blocked by the resize nested runloop. We need | |
| 652 // the views to adjust immediately. | |
| 653 - (void)tabViewFrameChanged:(NSNotification*)info { | |
| 654 [self layoutTabsWithAnimation:NO]; | |
| 655 } | |
| 656 | |
| 629 @end | 657 @end |
| OLD | NEW |