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

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

Issue 165499: Updates to clean up default theme and add hover states (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 3 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') | chrome/browser/cocoa/tab_strip_view.mm » ('j') | 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 29 matching lines...) Expand all
40 // A simple view class that prevents the windowserver from dragging the 40 // A simple view class that prevents the windowserver from dragging the
41 // area behind tabs. Sometimes core animation confuses it. 41 // area behind tabs. Sometimes core animation confuses it.
42 @interface TabStripControllerDragBlockingView : NSView 42 @interface TabStripControllerDragBlockingView : NSView
43 @end 43 @end
44 @implementation TabStripControllerDragBlockingView 44 @implementation TabStripControllerDragBlockingView
45 - (BOOL)mouseDownCanMoveWindow {return NO;} 45 - (BOOL)mouseDownCanMoveWindow {return NO;}
46 - (void)drawRect:(NSRect)rect {} 46 - (void)drawRect:(NSRect)rect {}
47 @end 47 @end
48 48
49 @interface TabStripController(Private) 49 @interface TabStripController(Private)
50 - (void)installTrackingArea;
51 - (BOOL)useFullWidthForLayout; 50 - (BOOL)useFullWidthForLayout;
52 - (void)addSubviewToPermanentList:(NSView*)aView; 51 - (void)addSubviewToPermanentList:(NSView*)aView;
53 - (void)regenerateSubviewList; 52 - (void)regenerateSubviewList;
54 - (NSInteger)indexForContentsView:(NSView*)view; 53 - (NSInteger)indexForContentsView:(NSView*)view;
55 - (void)updateFavIconForContents:(TabContents*)contents 54 - (void)updateFavIconForContents:(TabContents*)contents
56 atIndex:(NSInteger)index; 55 atIndex:(NSInteger)index;
57 @end 56 @end
58 57
59 @implementation TabStripController 58 @implementation TabStripController
60 59
61 - (id)initWithView:(TabStripView*)view 60 - (id)initWithView:(TabStripView*)view
62 switchView:(NSView*)switchView 61 switchView:(NSView*)switchView
63 browser:(Browser*)browser { 62 browser:(Browser*)browser {
64 DCHECK(view && switchView && browser); 63 DCHECK(view && switchView && browser);
65 if ((self = [super init])) { 64 if ((self = [super init])) {
66 tabView_ = view; 65 tabView_.reset([view retain]);
67 switchView_ = switchView; 66 switchView_ = switchView;
68 browser_ = browser; 67 browser_ = browser;
69 tabModel_ = browser_->tabstrip_model(); 68 tabModel_ = browser_->tabstrip_model();
70 bridge_.reset(new TabStripModelObserverBridge(tabModel_, self)); 69 bridge_.reset(new TabStripModelObserverBridge(tabModel_, self));
71 tabContentsArray_.reset([[NSMutableArray alloc] init]); 70 tabContentsArray_.reset([[NSMutableArray alloc] init]);
72 tabArray_.reset([[NSMutableArray alloc] init]); 71 tabArray_.reset([[NSMutableArray alloc] init]);
73 permanentSubviews_.reset([[NSMutableArray alloc] init]); 72 permanentSubviews_.reset([[NSMutableArray alloc] init]);
74 73
75 // Take the only child view present in the nib as the new tab button. For 74 // Take the only child view present in the nib as the new tab button. For
76 // some reason, if the view is present in the nib apriori, it draws 75 // some reason, if the view is present in the nib apriori, it draws
77 // correctly. If we create it in code and add it to the tab view, it draws 76 // correctly. If we create it in code and add it to the tab view, it draws
78 // with all sorts of crazy artifacts. 77 // with all sorts of crazy artifacts.
79 newTabButton_ = [[tabView_ subviews] objectAtIndex:0]; 78 newTabButton_ = [[tabView_ subviews] objectAtIndex:0];
80 DCHECK([newTabButton_ isKindOfClass:[NSButton class]]); 79 DCHECK([newTabButton_ isKindOfClass:[NSButton class]]);
81 [self addSubviewToPermanentList:newTabButton_]; 80 [self addSubviewToPermanentList:newTabButton_];
82 [newTabButton_ setTarget:nil]; 81 [newTabButton_ setTarget:nil];
83 [newTabButton_ setAction:@selector(commandDispatch:)]; 82 [newTabButton_ setAction:@selector(commandDispatch:)];
84 [newTabButton_ setTag:IDC_NEW_TAB]; 83 [newTabButton_ setTag:IDC_NEW_TAB];
85 targetFrames_.reset([[NSMutableDictionary alloc] init]); 84 targetFrames_.reset([[NSMutableDictionary alloc] init]);
86 [tabView_ setWantsLayer:YES];
87 dragBlockingView_.reset([[TabStripControllerDragBlockingView alloc] 85 dragBlockingView_.reset([[TabStripControllerDragBlockingView alloc]
88 initWithFrame:NSZeroRect]); 86 initWithFrame:NSZeroRect]);
89 [self addSubviewToPermanentList:dragBlockingView_]; 87 [self addSubviewToPermanentList:dragBlockingView_];
90 newTabTargetFrame_ = NSMakeRect(0, 0, 0, 0); 88 newTabTargetFrame_ = NSMakeRect(0, 0, 0, 0);
91 availableResizeWidth_ = kUseFullAvailableWidth; 89 availableResizeWidth_ = kUseFullAvailableWidth;
92 90
93 // Install the permanent subviews. 91 // Install the permanent subviews.
94 [self regenerateSubviewList]; 92 [self regenerateSubviewList];
95 93
96 // Watch for notifications that the tab strip view has changed size so 94 // Watch for notifications that the tab strip view has changed size so
97 // we can tell it to layout for the new size. 95 // we can tell it to layout for the new size.
98 [[NSNotificationCenter defaultCenter] 96 [[NSNotificationCenter defaultCenter]
99 addObserver:self 97 addObserver:self
100 selector:@selector(tabViewFrameChanged:) 98 selector:@selector(tabViewFrameChanged:)
101 name:NSViewFrameDidChangeNotification 99 name:NSViewFrameDidChangeNotification
102 object:tabView_]; 100 object:tabView_];
101
102 trackingArea_.reset([[NSTrackingArea alloc]
103 initWithRect:NSZeroRect // Ignored by NSTrackingInVisibleRect
104 options:NSTrackingMouseEnteredAndExited |
105 NSTrackingMouseMoved |
106 NSTrackingActiveAlways |
107 NSTrackingInVisibleRect
108 owner:self
109 userInfo:nil]);
110 [tabView_ addTrackingArea:trackingArea_.get()];
103 } 111 }
104 return self; 112 return self;
105 } 113 }
106 114
107 - (void)dealloc { 115 - (void)dealloc {
108 if (closeTabTrackingArea_.get()) 116 if (trackingArea_.get())
109 [tabView_ removeTrackingArea:closeTabTrackingArea_.get()]; 117 [tabView_ removeTrackingArea:trackingArea_.get()];
110 [[NSNotificationCenter defaultCenter] removeObserver:self]; 118 [[NSNotificationCenter defaultCenter] removeObserver:self];
111 [super dealloc]; 119 [super dealloc];
112 } 120 }
113 121
114 + (CGFloat)defaultTabHeight { 122 + (CGFloat)defaultTabHeight {
115 return 24.0; 123 return 24.0;
116 } 124 }
117 125
118 // Finds the associated TabContentsController at the given |index| and swaps 126 // Finds the associated TabContentsController at the given |index| and swaps
119 // out the sole child of the contentArea to display its contents. 127 // out the sole child of the contentArea to display its contents.
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 DCHECK([sender isKindOfClass:[NSView class]]); 230 DCHECK([sender isKindOfClass:[NSView class]]);
223 int index = [self indexForTabView:sender]; 231 int index = [self indexForTabView:sender];
224 if (index >= 0 && tabModel_->ContainsIndex(index)) 232 if (index >= 0 && tabModel_->ContainsIndex(index))
225 tabModel_->SelectTabContentsAt(index, true); 233 tabModel_->SelectTabContentsAt(index, true);
226 } 234 }
227 235
228 // Called when the user closes a tab. Asks the model to close the tab. |sender| 236 // Called when the user closes a tab. Asks the model to close the tab. |sender|
229 // is the TabView that is potentially going away. 237 // is the TabView that is potentially going away.
230 - (void)closeTab:(id)sender { 238 - (void)closeTab:(id)sender {
231 DCHECK([sender isKindOfClass:[NSView class]]); 239 DCHECK([sender isKindOfClass:[NSView class]]);
240 if ([hoveredTab_ isEqual:sender]) {
241 hoveredTab_ = nil;
242 }
232 int index = [self indexForTabView:sender]; 243 int index = [self indexForTabView:sender];
233 if (tabModel_->ContainsIndex(index)) { 244 if (tabModel_->ContainsIndex(index)) {
234 TabContents* contents = tabModel_->GetTabContentsAt(index); 245 TabContents* contents = tabModel_->GetTabContentsAt(index);
235 if (contents) 246 if (contents)
236 UserMetrics::RecordAction(L"CloseTab_Mouse", contents->profile()); 247 UserMetrics::RecordAction(L"CloseTab_Mouse", contents->profile());
237 if ([self numberOfTabViews] > 1) { 248 if ([self numberOfTabViews] > 1) {
238 // Limit the width available for laying out tabs so that tabs are not 249 // Limit the width available for laying out tabs so that tabs are not
239 // resized until a later time (when the mouse leaves the tab strip). 250 // resized until a later time (when the mouse leaves the tab strip).
240 // TODO(pinkerton): re-visit when handling tab overflow. 251 // TODO(pinkerton): re-visit when handling tab overflow.
241 NSView* penultimateTab = [self viewAtIndex:[tabArray_ count] - 2]; 252 NSView* penultimateTab = [self viewAtIndex:[tabArray_ count] - 2];
242 availableResizeWidth_ = NSMaxX([penultimateTab frame]); 253 availableResizeWidth_ = NSMaxX([penultimateTab frame]);
243 [self installTrackingArea];
244 tabModel_->CloseTabContentsAt(index); 254 tabModel_->CloseTabContentsAt(index);
245 } else { 255 } else {
246 // Use the standard window close if this is the last tab 256 // Use the standard window close if this is the last tab
247 // this prevents the tab from being removed from the model until after 257 // this prevents the tab from being removed from the model until after
248 // the window dissapears 258 // the window dissapears
249 [[tabView_ window] performClose:nil]; 259 [[tabView_ window] performClose:nil];
250 } 260 }
251 } 261 }
252 } 262 }
253 263
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 338
329 CGFloat minX = NSMinX(placeholderFrame_); 339 CGFloat minX = NSMinX(placeholderFrame_);
330 BOOL visible = [[tabView_ window] isVisible]; 340 BOOL visible = [[tabView_ window] isVisible];
331 341
332 float offset = kIndentLeavingSpaceForControls; 342 float offset = kIndentLeavingSpaceForControls;
333 NSUInteger i = 0; 343 NSUInteger i = 0;
334 NSInteger gap = -1; 344 NSInteger gap = -1;
335 for (TabController* tab in tabArray_.get()) { 345 for (TabController* tab in tabArray_.get()) {
336 BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_]; 346 BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_];
337 NSRect tabFrame = [[tab view] frame]; 347 NSRect tabFrame = [[tab view] frame];
338 tabFrame.size.height = [[self class] defaultTabHeight]; 348 tabFrame.size.height = [[self class] defaultTabHeight] + 1;
339 tabFrame.origin.y = 0; 349 tabFrame.origin.y = 0;
340 tabFrame.origin.x = offset; 350 tabFrame.origin.x = offset;
341 351
342 // If the tab is hidden, we consider it a new tab. We make it visible 352 // If the tab is hidden, we consider it a new tab. We make it visible
343 // and animate it in. 353 // and animate it in.
344 BOOL newTab = [[tab view] isHidden]; 354 BOOL newTab = [[tab view] isHidden];
345 if (newTab) { 355 if (newTab) {
346 [[tab view] setHidden:NO]; 356 [[tab view] setHidden:NO];
347 } 357 }
348 358
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 // Release the tab contents controller so those views get destroyed. This 566 // Release the tab contents controller so those views get destroyed. This
557 // will remove all the tab content Cocoa views from the hierarchy. A 567 // will remove all the tab content Cocoa views from the hierarchy. A
558 // subsequent "select tab" notification will follow from the model. To 568 // subsequent "select tab" notification will follow from the model. To
559 // tell us what to swap in in its absence. 569 // tell us what to swap in in its absence.
560 [tabContentsArray_ removeObjectAtIndex:index]; 570 [tabContentsArray_ removeObjectAtIndex:index];
561 571
562 // Remove the |index|th view from the tab strip 572 // Remove the |index|th view from the tab strip
563 NSView* tab = [self viewAtIndex:index]; 573 NSView* tab = [self viewAtIndex:index];
564 [tab removeFromSuperview]; 574 [tab removeFromSuperview];
565 575
576 if ([hoveredTab_ isEqual:tab]) {
577 hoveredTab_ = nil;
578 }
579
566 NSValue *identifier = [NSValue valueWithPointer:tab]; 580 NSValue *identifier = [NSValue valueWithPointer:tab];
567 [targetFrames_ removeObjectForKey:identifier]; 581 [targetFrames_ removeObjectForKey:identifier];
568 582
569 // Once we're totally done with the tab, delete its controller 583 // Once we're totally done with the tab, delete its controller
570 [tabArray_ removeObjectAtIndex:index]; 584 [tabArray_ removeObjectAtIndex:index];
571 585
572 // Send a broadcast that the number of tabs have changed. 586 // Send a broadcast that the number of tabs have changed.
573 [[NSNotificationCenter defaultCenter] 587 [[NSNotificationCenter defaultCenter]
574 postNotificationName:kTabStripNumberOfTabsChanged 588 postNotificationName:kTabStripNumberOfTabsChanged
575 object:self]; 589 object:self];
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 // is no placeholder, it will go at the end. Used when dragging from another 754 // is no placeholder, it will go at the end. Used when dragging from another
741 // window when we don't have access to the TabContents as part of our strip. 755 // window when we don't have access to the TabContents as part of our strip.
742 - (void)dropTabContents:(TabContents*)contents { 756 - (void)dropTabContents:(TabContents*)contents {
743 int index = [self indexOfPlaceholder]; 757 int index = [self indexOfPlaceholder];
744 758
745 // Insert it into this tab strip. We want it in the foreground and to not 759 // Insert it into this tab strip. We want it in the foreground and to not
746 // inherit the current tab's group. 760 // inherit the current tab's group.
747 tabModel_->InsertTabContentsAt(index, contents, true, false); 761 tabModel_->InsertTabContentsAt(index, contents, true, false);
748 } 762 }
749 763
750 - (void)userChangedTheme { 764 - (void)applyTheme {
751 for (TabController* tab in tabArray_.get()) { 765 for (TabController* tab in tabArray_.get()) {
752 [[tab view] setNeedsDisplay:YES]; 766 [tab applyTheme];
753 } 767 }
754 } 768 }
755 769
756 // Called when the tab strip view changes size. As we only registered for 770 // Called when the tab strip view changes size. As we only registered for
757 // changes on our view, we know it's only for our view. Layout w/out 771 // changes on our view, we know it's only for our view. Layout w/out
758 // animations since they are blocked by the resize nested runloop. We need 772 // animations since they are blocked by the resize nested runloop. We need
759 // the views to adjust immediately. Neither the tabs nor their z-order are 773 // the views to adjust immediately. Neither the tabs nor their z-order are
760 // changed, so we don't need to update the subviews. 774 // changed, so we don't need to update the subviews.
761 - (void)tabViewFrameChanged:(NSNotification*)info { 775 - (void)tabViewFrameChanged:(NSNotification*)info {
762 [self layoutTabsWithAnimation:NO regenerateSubviews:NO]; 776 [self layoutTabsWithAnimation:NO regenerateSubviews:NO];
763 } 777 }
764 778
765 - (BOOL)useFullWidthForLayout { 779 - (BOOL)useFullWidthForLayout {
766 return availableResizeWidth_ == kUseFullAvailableWidth; 780 return availableResizeWidth_ == kUseFullAvailableWidth;
767 } 781 }
768 782
769 // Call to install a tracking area that reports mouseEnter/Exit messages so 783 - (void)mouseMoved:(NSEvent *)event {
770 // we can track when the mouse leaves the tab view after closing a tab with 784 // Use hit test to figure out what view we are hovering over.
771 // the mouse. Don't install another tracking rect if one is already there. 785 TabView* targetView = (TabView*)[tabView_ hitTest:[event locationInWindow]];
772 - (void)installTrackingArea { 786 if (![targetView isKindOfClass:[TabView class]]) {
773 if (closeTabTrackingArea_.get()) 787 if ([[targetView superview] isKindOfClass:[TabView class]]) {
774 return; 788 targetView = (TabView*)[targetView superview];
775 // Note that we pass |NSTrackingInVisibleRect| so the rect is actually 789 } else {
776 // ignored. 790 targetView = nil;
777 closeTabTrackingArea_.reset([[NSTrackingArea alloc] 791 }
778 initWithRect:[tabView_ bounds] 792 }
779 options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | 793
780 NSTrackingInVisibleRect 794 if (hoveredTab_ != targetView) {
781 owner:self 795 [hoveredTab_ mouseExited:nil]; // We don't pass event because moved events
782 userInfo:nil]); 796 [targetView mouseEntered:nil]; // don't have valid tracking areas
783 [tabView_ addTrackingArea:closeTabTrackingArea_.get()]; 797 hoveredTab_ = targetView;
798 } else {
799 [hoveredTab_ mouseMoved:event];
800 }
784 } 801 }
785 802
786 - (void)mouseEntered:(NSEvent*)event { 803 - (void)mouseEntered:(NSEvent*)event {
787 // Do nothing. 804 [self mouseMoved:event];
788 } 805 }
789 806
790 // Called when the tracking area is in effect which means we're tracking to 807 // Called when the tracking area is in effect which means we're tracking to
791 // see if the user leaves the tab strip with their mouse. When they do, 808 // see if the user leaves the tab strip with their mouse. When they do,
792 // reset layout to use all available width. 809 // reset layout to use all available width.
793 - (void)mouseExited:(NSEvent*)event { 810 - (void)mouseExited:(NSEvent*)event {
794 [tabView_ removeTrackingArea:closeTabTrackingArea_.get()];
795 closeTabTrackingArea_.reset(nil);
796 availableResizeWidth_ = kUseFullAvailableWidth; 811 availableResizeWidth_ = kUseFullAvailableWidth;
812
813 [hoveredTab_ mouseExited:event];
814 hoveredTab_ = nil;
797 [self layoutTabs]; 815 [self layoutTabs];
798 } 816 }
799 817
800 // Adds the given subview to (the end of) the list of permanent subviews 818 // Adds the given subview to (the end of) the list of permanent subviews
801 // (specified from bottom up). These subviews will always be below the 819 // (specified from bottom up). These subviews will always be below the
802 // transitory subviews (tabs). |-regenerateSubviewList| must be called to 820 // transitory subviews (tabs). |-regenerateSubviewList| must be called to
803 // effectuate the addition. 821 // effectuate the addition.
804 - (void)addSubviewToPermanentList:(NSView*)aView { 822 - (void)addSubviewToPermanentList:(NSView*)aView {
805 [permanentSubviews_ addObject:aView]; 823 [permanentSubviews_ addObject:aView];
806 } 824 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
891 BrowserWindowController* controller = 909 BrowserWindowController* controller =
892 (BrowserWindowController*)[[switchView_ window] windowController]; 910 (BrowserWindowController*)[[switchView_ window] windowController];
893 DCHECK(index >= 0); 911 DCHECK(index >= 0);
894 if (index >= 0) { 912 if (index >= 0) {
895 [controller setTab:[self viewAtIndex:index] isDraggable:YES]; 913 [controller setTab:[self viewAtIndex:index] isDraggable:YES];
896 } 914 }
897 } 915 }
898 916
899 917
900 @end 918 @end
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/tab_strip_controller.h ('k') | chrome/browser/cocoa/tab_strip_view.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698