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

Side by Side Diff: chrome/browser/cocoa/tab_strip_controller.mm

Issue 159346: Live resize of tabs as the window resizes.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 5 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
« no previous file with comments | « chrome/browser/cocoa/tab_strip_controller.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/tab_strip_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698