зеркало из https://github.com/mozilla/gecko-dev.git
remove 16-tab limit. add overflow menu (chevron). bug 261134
This commit is contained in:
Родитель
58e0659db2
Коммит
ee2dfe111b
|
@ -1692,6 +1692,7 @@
|
||||||
E010866D06BCA2E500BD5DE0,
|
E010866D06BCA2E500BD5DE0,
|
||||||
E010866E06BCA2E500BD5DE0,
|
E010866E06BCA2E500BD5DE0,
|
||||||
E010866F06BCA2E500BD5DE0,
|
E010866F06BCA2E500BD5DE0,
|
||||||
|
3FF71AE00710A6800081B5D7,
|
||||||
);
|
);
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -5625,6 +5626,7 @@
|
||||||
E010867406BCA2E500BD5DE0,
|
E010867406BCA2E500BD5DE0,
|
||||||
E010867506BCA2E500BD5DE0,
|
E010867506BCA2E500BD5DE0,
|
||||||
E010867606BCA2E500BD5DE0,
|
E010867606BCA2E500BD5DE0,
|
||||||
|
3FF71AE10710A6800081B5D7,
|
||||||
);
|
);
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -9216,6 +9218,26 @@
|
||||||
settings = {
|
settings = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
3FF71ADF0710A67F0081B5D7 = {
|
||||||
|
isa = PBXFileReference;
|
||||||
|
lastKnownFileType = image.tiff;
|
||||||
|
name = tab_overflow.tif;
|
||||||
|
path = resources/images/chrome/tab_overflow.tif;
|
||||||
|
refType = 2;
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
3FF71AE00710A6800081B5D7 = {
|
||||||
|
fileRef = 3FF71ADF0710A67F0081B5D7;
|
||||||
|
isa = PBXBuildFile;
|
||||||
|
settings = {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
3FF71AE10710A6800081B5D7 = {
|
||||||
|
fileRef = 3FF71ADF0710A67F0081B5D7;
|
||||||
|
isa = PBXBuildFile;
|
||||||
|
settings = {
|
||||||
|
};
|
||||||
|
};
|
||||||
//3F0
|
//3F0
|
||||||
//3F1
|
//3F1
|
||||||
//3F2
|
//3F2
|
||||||
|
@ -10002,6 +10024,7 @@
|
||||||
3FF08F1206E7D3C2001C9B19,
|
3FF08F1206E7D3C2001C9B19,
|
||||||
3FF08F1306E7D3C2001C9B19,
|
3FF08F1306E7D3C2001C9B19,
|
||||||
3FF08F1406E7D3C2001C9B19,
|
3FF08F1406E7D3C2001C9B19,
|
||||||
|
3FF71ADF0710A67F0081B5D7,
|
||||||
E091C0D006225EA3007D9E8F,
|
E091C0D006225EA3007D9E8F,
|
||||||
F540BD1A029ED15301026D5D,
|
F540BD1A029ED15301026D5D,
|
||||||
F540BD1C029ED17901026D5D,
|
F540BD1C029ED17901026D5D,
|
||||||
|
|
Двоичный файл не отображается.
|
@ -47,19 +47,25 @@
|
||||||
IBOutlet BrowserTabView *mTabView;
|
IBOutlet BrowserTabView *mTabView;
|
||||||
|
|
||||||
TabButtonCell *mActiveTabButton; // active tab button, mainly useful for handling drags (STRONG)
|
TabButtonCell *mActiveTabButton; // active tab button, mainly useful for handling drags (STRONG)
|
||||||
|
NSButton *mOverflowButton; // button for overflow menu if we've got more tabs than space (STRONG)
|
||||||
|
NSMenu *mOverflowMenu; // menu for tab overflow (STRONG);
|
||||||
|
|
||||||
// drag tracking
|
// drag tracking
|
||||||
NSPoint mLastClickPoint;
|
NSPoint mLastClickPoint;
|
||||||
BOOL mDragStarted;
|
BOOL mDragStarted;
|
||||||
NSView *mDragDest;
|
NSView *mDragDest;
|
||||||
TabButtonCell *mDragDestButton;
|
TabButtonCell *mDragDestButton;
|
||||||
|
|
||||||
|
BOOL mOverflowTabs;
|
||||||
|
NSMutableArray *mTrackingCells; // cells which currently have tracking rects in this view
|
||||||
}
|
}
|
||||||
|
|
||||||
// destroy the tab bar and recreate it from the tabview
|
// destroy the tab bar and recreate it from the tabview
|
||||||
-(void)rebuildTabBar;
|
-(void)rebuildTabBar;
|
||||||
// return the height the tab bar should be
|
// return the height the tab bar should be
|
||||||
-(float)tabBarHeight;
|
-(float)tabBarHeight;
|
||||||
-(BrowserTabViewItem*)tabViewItemAtPoint:(NSPoint)location;
|
-(BrowserTabViewItem*)tabViewItemAtPoint:(NSPoint)location;
|
||||||
|
- (void)windowClosed;
|
||||||
|
- (IBAction)overflowMenu:(id)sender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -47,25 +47,34 @@
|
||||||
-(TabButtonCell*)buttonAtPoint:(NSPoint)clickPoint;
|
-(TabButtonCell*)buttonAtPoint:(NSPoint)clickPoint;
|
||||||
-(void)registerTabButtonsForTracking;
|
-(void)registerTabButtonsForTracking;
|
||||||
-(void)unregisterTabButtonsForTracking;
|
-(void)unregisterTabButtonsForTracking;
|
||||||
|
-(void)initOverflowMenu;
|
||||||
|
-(NSRect)tabsRect;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static NSImage *gBackgroundImage = nil;
|
static NSImage *gBackgroundImage = nil;
|
||||||
static NSImage *gTabButtonDividerImage = nil;
|
static NSImage *gTabButtonDividerImage = nil;
|
||||||
|
static NSImage *gTabOverflowImage = nil;
|
||||||
static const float kTabBarDefaultHeight = 22.0;
|
static const float kTabBarDefaultHeight = 22.0;
|
||||||
|
|
||||||
@implementation BrowserTabBarView
|
@implementation BrowserTabBarView
|
||||||
|
|
||||||
static const int kTabBarMargin = 5; // left/right margin for tab bar
|
static const int kTabBarMargin = 5; // left/right margin for tab bar
|
||||||
static const float kMinTabWidth = 42.0; // tabs smaller than this are useless... tabs this small may be useless
|
static const float kMinTabWidth = 100.0; // the smallest tabs that will be drawn
|
||||||
static const float kMaxTabWidth = 175.0; // the widest tabs that will be drawn
|
static const float kMaxTabWidth = 175.0; // the widest tabs that will be drawn
|
||||||
|
|
||||||
static const int kTabDragThreshold = 3; // distance a drag must go before we start dnd
|
static const int kTabDragThreshold = 3; // distance a drag must go before we start dnd
|
||||||
|
|
||||||
|
static const float kOverflowButtonWidth = 16;
|
||||||
|
static const float kOverflowButtonHeight = 16;
|
||||||
|
static const int kOverflowButtonMargin = 1;
|
||||||
|
|
||||||
-(id)initWithFrame:(NSRect)frame
|
-(id)initWithFrame:(NSRect)frame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:frame];
|
self = [super initWithFrame:frame];
|
||||||
if (self) {
|
if (self) {
|
||||||
mActiveTabButton = nil;
|
mActiveTabButton = nil;
|
||||||
|
mOverflowButton = nil;
|
||||||
|
mOverflowTabs = NO;
|
||||||
// this will not likely have any result here
|
// this will not likely have any result here
|
||||||
[self rebuildTabBar];
|
[self rebuildTabBar];
|
||||||
[self registerForDraggedTypes:[NSArray arrayWithObjects: @"MozURLType", @"MozBookmarkType", NSStringPboardType,
|
[self registerForDraggedTypes:[NSArray arrayWithObjects: @"MozURLType", @"MozBookmarkType", NSStringPboardType,
|
||||||
|
@ -82,7 +91,10 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
|
|
||||||
-(void)dealloc
|
-(void)dealloc
|
||||||
{
|
{
|
||||||
|
[mTrackingCells release];
|
||||||
[mActiveTabButton release];
|
[mActiveTabButton release];
|
||||||
|
[mOverflowButton release];
|
||||||
|
[mOverflowMenu release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +105,10 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
[self loadImages];
|
[self loadImages];
|
||||||
|
|
||||||
// determine the frame of the active tab button and fill the rest of the bar in with the background
|
// determine the frame of the active tab button and fill the rest of the bar in with the background
|
||||||
NSRect activeTabButtonFrame = [mActiveTabButton frame];
|
NSRect activeTabButtonFrame = [mActiveTabButton frame];
|
||||||
|
NSRect tabsRect = [self tabsRect];
|
||||||
|
// if any of the active tab would be outside the drawable area, fill it in
|
||||||
|
if (NSMaxX(activeTabButtonFrame) > NSMaxX(tabsRect)) activeTabButtonFrame.size.width = 0.0;
|
||||||
[self drawTabBarBackgroundInRect:rect withActiveTabRect:activeTabButtonFrame];
|
[self drawTabBarBackgroundInRect:rect withActiveTabRect:activeTabButtonFrame];
|
||||||
NSArray *tabItems = [mTabView tabViewItems];
|
NSArray *tabItems = [mTabView tabViewItems];
|
||||||
NSEnumerator *tabEnumerator = [tabItems objectEnumerator];
|
NSEnumerator *tabEnumerator = [tabItems objectEnumerator];
|
||||||
|
@ -104,7 +119,7 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
BrowserTabViewItem *nextTab = [tabEnumerator nextObject];
|
BrowserTabViewItem *nextTab = [tabEnumerator nextObject];
|
||||||
|
|
||||||
NSRect tabButtonFrame = [tabButton frame];
|
NSRect tabButtonFrame = [tabButton frame];
|
||||||
if (NSIntersectsRect(tabButtonFrame,rect))
|
if (NSIntersectsRect(tabButtonFrame,rect) && NSMaxX(tabButtonFrame) <= NSMaxX(tabsRect))
|
||||||
[tabButton drawWithFrame:tabButtonFrame inView:self];
|
[tabButton drawWithFrame:tabButtonFrame inView:self];
|
||||||
// draw the first divider.
|
// draw the first divider.
|
||||||
if ((prevButton == nil) && ([tab tabState] != NSSelectedTab))
|
if ((prevButton == nil) && ([tab tabState] != NSSelectedTab))
|
||||||
|
@ -119,7 +134,9 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
{
|
{
|
||||||
[super setFrame:frameRect];
|
[super setFrame:frameRect];
|
||||||
// tab buttons probably need to be resized if the frame changes
|
// tab buttons probably need to be resized if the frame changes
|
||||||
|
[self unregisterTabButtonsForTracking];
|
||||||
[self layoutButtons];
|
[self layoutButtons];
|
||||||
|
[self registerTabButtonsForTracking];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(NSMenu*)menuForEvent:(NSEvent*)theEvent
|
-(NSMenu*)menuForEvent:(NSEvent*)theEvent
|
||||||
|
@ -134,7 +151,7 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
{
|
{
|
||||||
NSPoint clickPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
NSPoint clickPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
||||||
TabButtonCell *clickedTabButton = [self buttonAtPoint:clickPoint];
|
TabButtonCell *clickedTabButton = [self buttonAtPoint:clickPoint];
|
||||||
|
|
||||||
mLastClickPoint = clickPoint;
|
mLastClickPoint = clickPoint;
|
||||||
|
|
||||||
if (clickedTabButton && ![clickedTabButton willTrackMouse:theEvent inRect:[clickedTabButton frame] ofView:self])
|
if (clickedTabButton && ![clickedTabButton willTrackMouse:theEvent inRect:[clickedTabButton frame] ofView:self])
|
||||||
|
@ -220,6 +237,8 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
gBackgroundImage = [[NSImage imageNamed:@"tab_bar_bg"] retain];
|
gBackgroundImage = [[NSImage imageNamed:@"tab_bar_bg"] retain];
|
||||||
if (!gTabButtonDividerImage)
|
if (!gTabButtonDividerImage)
|
||||||
gTabButtonDividerImage = [[NSImage imageNamed:@"tab_button_divider"] retain];
|
gTabButtonDividerImage = [[NSImage imageNamed:@"tab_button_divider"] retain];
|
||||||
|
if (!gTabOverflowImage)
|
||||||
|
gTabOverflowImage = [[NSImage imageNamed:@"tab_overflow"] retain];
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct the tab bar based on the current state of mTabView;
|
// construct the tab bar based on the current state of mTabView;
|
||||||
|
@ -233,11 +252,20 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
[self registerTabButtonsForTracking];
|
[self registerTabButtonsForTracking];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)windowClosed
|
||||||
|
{
|
||||||
|
// remove all tracking rects because this view is implicitly retained when they're registered
|
||||||
|
[self unregisterTabButtonsForTracking];
|
||||||
|
}
|
||||||
|
|
||||||
// allows tab button cells to react to mouse events
|
// allows tab button cells to react to mouse events
|
||||||
-(void)registerTabButtonsForTracking
|
-(void)registerTabButtonsForTracking
|
||||||
{
|
{
|
||||||
if ([self window]) {
|
if ([self window]) {
|
||||||
NSArray * tabItems = [mTabView tabViewItems];
|
NSArray * tabItems = [mTabView tabViewItems];
|
||||||
|
if(mTrackingCells) [self unregisterTabButtonsForTracking];
|
||||||
|
mTrackingCells = [NSMutableArray arrayWithCapacity:[tabItems count]];
|
||||||
|
[mTrackingCells retain];
|
||||||
NSEnumerator *tabEnumerator = [tabItems objectEnumerator];
|
NSEnumerator *tabEnumerator = [tabItems objectEnumerator];
|
||||||
|
|
||||||
NSPoint local = [[self window] convertScreenToBase:[NSEvent mouseLocation]];
|
NSPoint local = [[self window] convertScreenToBase:[NSEvent mouseLocation]];
|
||||||
|
@ -246,8 +274,13 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
BrowserTabViewItem *tab = nil;
|
BrowserTabViewItem *tab = nil;
|
||||||
while (tab = [tabEnumerator nextObject]) {
|
while (tab = [tabEnumerator nextObject]) {
|
||||||
TabButtonCell * tabButton = [tab tabButtonCell];
|
TabButtonCell * tabButton = [tab tabButtonCell];
|
||||||
NSRect trackingRect = [tabButton frame];
|
if (tabButton) {
|
||||||
[tabButton addTrackingRectInView: self withFrame:trackingRect cursorLocation:local];
|
[mTrackingCells addObject:tabButton];
|
||||||
|
NSRect trackingRect = [tabButton frame];
|
||||||
|
// only track tabs that are onscreen
|
||||||
|
if (NSMaxX(trackingRect) <= NSMaxX([self tabsRect]))
|
||||||
|
[tabButton addTrackingRectInView: self withFrame:trackingRect cursorLocation:local];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,11 +288,14 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
// causes tab buttons to stop reacting to mouse events
|
// causes tab buttons to stop reacting to mouse events
|
||||||
-(void)unregisterTabButtonsForTracking
|
-(void)unregisterTabButtonsForTracking
|
||||||
{
|
{
|
||||||
NSArray * tabItems = [mTabView tabViewItems];
|
if (mTrackingCells) {
|
||||||
NSEnumerator *tabEnumerator = [tabItems objectEnumerator];
|
NSEnumerator *tabEnumerator = [mTrackingCells objectEnumerator];
|
||||||
BrowserTabViewItem *tab = nil;
|
TabButtonCell *tab = nil;
|
||||||
while (tab = [tabEnumerator nextObject])
|
while (tab = (TabButtonCell *)[tabEnumerator nextObject])
|
||||||
[[tab tabButtonCell] removeTrackingRectFromView: self];
|
[tab removeTrackingRectFromView: self];
|
||||||
|
[mTrackingCells release];
|
||||||
|
mTrackingCells = nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the height the tab bar should be if drawn
|
// returns the height the tab bar should be if drawn
|
||||||
|
@ -282,8 +318,21 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
const int numTabs = [mTabView numberOfTabViewItems];
|
const int numTabs = [mTabView numberOfTabViewItems];
|
||||||
float tabWidth = kMaxTabWidth;
|
float tabWidth = kMaxTabWidth;
|
||||||
|
|
||||||
// calculate the largest tabs that would fit
|
// calculate the largest tabs that would fit... [self tabsRect] may not be correct until mOverflowTabs is set here.
|
||||||
float maxWidth = floor((NSWidth([self bounds]) - (2*kTabBarMargin))/numTabs);
|
float maxWidth = floor((NSWidth([self bounds]) - (2*kTabBarMargin))/numTabs);
|
||||||
|
// if tabs will overflow, leave space for the button
|
||||||
|
if (maxWidth < kMinTabWidth) {
|
||||||
|
mOverflowTabs = YES;
|
||||||
|
NSRect tabsRect = [self tabsRect];
|
||||||
|
for (int i = 1; i < numTabs; i++) {
|
||||||
|
maxWidth = floor(NSWidth(tabsRect)/(numTabs - i));
|
||||||
|
if (maxWidth >= kMinTabWidth) break;
|
||||||
|
}
|
||||||
|
// because the specific tabs which overflow may change, empty the menu and rebuild it as tabs are laid out
|
||||||
|
[self initOverflowMenu];
|
||||||
|
} else {
|
||||||
|
mOverflowTabs = NO;
|
||||||
|
}
|
||||||
// if our tabs are currently larger than that, shrink them to the larger of kMinTabWidth or maxWidth
|
// if our tabs are currently larger than that, shrink them to the larger of kMinTabWidth or maxWidth
|
||||||
if (tabWidth > maxWidth)
|
if (tabWidth > maxWidth)
|
||||||
tabWidth = (maxWidth > kMinTabWidth ? maxWidth : kMinTabWidth);
|
tabWidth = (maxWidth > kMinTabWidth ? maxWidth : kMinTabWidth);
|
||||||
|
@ -299,25 +348,80 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
|
||||||
buttonSize.width = tabWidth;
|
buttonSize.width = tabWidth;
|
||||||
buttonSize.height = kTabBarDefaultHeight;
|
buttonSize.height = kTabBarDefaultHeight;
|
||||||
NSPoint buttonOrigin = NSMakePoint(xCoord,0);
|
NSPoint buttonOrigin = NSMakePoint(xCoord,0);
|
||||||
// TODO: take care of tabs that run off the end... right now we're the same as Firebird, except I think we
|
|
||||||
// hit our tab limit before we'll run off the end of the average user's windows given the current kMinTabWidth
|
|
||||||
[tabButtonCell setFrame:NSMakeRect(buttonOrigin.x,buttonOrigin.y,buttonSize.width,buttonSize.height)];
|
[tabButtonCell setFrame:NSMakeRect(buttonOrigin.x,buttonOrigin.y,buttonSize.width,buttonSize.height)];
|
||||||
// If the tab ran off the edge, suppress its close button
|
|
||||||
if (buttonOrigin.x + buttonSize.width > NSMaxX([self bounds]))
|
|
||||||
[tabButtonCell hideCloseButton];
|
|
||||||
// tell the button whether it needs to draw the right side dividing line
|
// tell the button whether it needs to draw the right side dividing line
|
||||||
if (NSSelectedTab == [tab tabState]) {
|
if ([tab tabState] == NSSelectedTab) {
|
||||||
[tabButtonCell setDrawDivider:NO];
|
[tabButtonCell setDrawDivider:NO];
|
||||||
[prevTabButton setDrawDivider:NO];
|
[prevTabButton setDrawDivider:NO];
|
||||||
} else {
|
} else {
|
||||||
[tabButtonCell setDrawDivider:YES];
|
[tabButtonCell setDrawDivider:YES];
|
||||||
}
|
}
|
||||||
|
// If the tab ran off the edge, suppress its close button, make sure the divider is drawn, and add it to the menu
|
||||||
|
if (buttonOrigin.x + buttonSize.width > NSMaxX([self tabsRect])) {
|
||||||
|
[tabButtonCell hideCloseButton];
|
||||||
|
// push the tab off the edge of the view to keep it from grabbing clicks if there is an area
|
||||||
|
// between the overflow menu and the last tab which is within tabsRect due to rounding
|
||||||
|
[tabButtonCell setFrame:NSMakeRect(NSMaxX([self bounds]),buttonOrigin.y,buttonSize.width,buttonSize.height)];
|
||||||
|
// if the tab prior to the overflow is not selected, it must draw a divider
|
||||||
|
if([[prevTabButton tabViewItem] tabState] != NSSelectedTab) [prevTabButton setDrawDivider:YES];
|
||||||
|
[mOverflowMenu addItem:[tab menuItem]];
|
||||||
|
}
|
||||||
prevTabButton = tabButtonCell;
|
prevTabButton = tabButtonCell;
|
||||||
xCoord += (int)tabWidth;
|
xCoord += (int)tabWidth;
|
||||||
}
|
}
|
||||||
|
// if tabs overflowed, position and display the overflow button
|
||||||
|
if (mOverflowTabs) {
|
||||||
|
[mOverflowButton setFrame:NSMakeRect(NSMaxX([self tabsRect]) + kOverflowButtonMargin,
|
||||||
|
([self tabBarHeight] - kOverflowButtonHeight)/2,kOverflowButtonWidth,kOverflowButtonHeight)];
|
||||||
|
[self addSubview:mOverflowButton];
|
||||||
|
} else {
|
||||||
|
[mOverflowButton removeFromSuperview];
|
||||||
|
}
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void)initOverflowMenu
|
||||||
|
{
|
||||||
|
if (!mOverflowButton) {
|
||||||
|
// if it hasn't been created yet, create an NSPopUpButton and retain a strong reference
|
||||||
|
mOverflowButton = [[NSButton alloc] initWithFrame:NSMakeRect(0,0,kOverflowButtonWidth,kOverflowButtonHeight)];
|
||||||
|
if (!gTabOverflowImage) [self loadImages];
|
||||||
|
[mOverflowButton setImage:gTabOverflowImage];
|
||||||
|
[mOverflowButton setImagePosition:NSImageOnly];
|
||||||
|
[mOverflowButton setBezelStyle:NSShadowlessSquareBezelStyle];
|
||||||
|
[mOverflowButton setBordered:NO];
|
||||||
|
[[mOverflowButton cell] setHighlightsBy:NSNoCellMask];
|
||||||
|
[mOverflowButton setTarget:self];
|
||||||
|
[mOverflowButton setAction:@selector(overflowMenu:)];
|
||||||
|
[(NSButtonCell *)[mOverflowButton cell]sendActionOn:NSLeftMouseDownMask];
|
||||||
|
}
|
||||||
|
if (!mOverflowMenu) {
|
||||||
|
// create an empty NSMenu for later use and retain a strong reference
|
||||||
|
mOverflowMenu = [[NSMenu alloc] init];
|
||||||
|
[mOverflowMenu addItemWithTitle:@"" action:NULL keyEquivalent:@""];
|
||||||
|
}
|
||||||
|
// remove any items on the menu other than the dummy item
|
||||||
|
for (int i = [mOverflowMenu numberOfItems]; i > 1; i--)
|
||||||
|
[mOverflowMenu removeItemAtIndex:i-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)overflowMenu:(id)sender
|
||||||
|
{
|
||||||
|
NSPopUpButtonCell *popupCell = [[[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:YES] autorelease];
|
||||||
|
[popupCell setMenu:mOverflowMenu];
|
||||||
|
[popupCell trackMouse:[NSApp currentEvent] inRect:[sender bounds] ofView:sender untilMouseUp:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns an NSRect of the area where tab widgets may be drawn
|
||||||
|
-(NSRect)tabsRect
|
||||||
|
{
|
||||||
|
NSRect rect = [self bounds];
|
||||||
|
rect.origin.x += kTabBarMargin;
|
||||||
|
rect.size.width -= 2 * kTabBarMargin + (mOverflowTabs ? kOverflowButtonWidth : 0.0);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
// NSDraggingDestination destination methods
|
// NSDraggingDestination destination methods
|
||||||
|
|
|
@ -49,4 +49,6 @@
|
||||||
- (BrowserTabViewItem*)itemWithTag:(int)tag;
|
- (BrowserTabViewItem*)itemWithTag:(int)tag;
|
||||||
- (void)refreshTabBar:(BOOL)rebuild;
|
- (void)refreshTabBar:(BOOL)rebuild;
|
||||||
|
|
||||||
|
- (void)windowClosed;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -248,6 +248,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)windowClosed
|
||||||
|
{
|
||||||
|
// Loop over all tabs, and tell them that the window is closed. This
|
||||||
|
// stops gecko from going any further on any of its open connections
|
||||||
|
// and breaks all the necessary cycles between Gecko and the BrowserWrapper.
|
||||||
|
int numTabs = [self numberOfTabViewItems];
|
||||||
|
for (int i = 0; i < numTabs; i++) {
|
||||||
|
NSTabViewItem* item = [self tabViewItemAtIndex: i];
|
||||||
|
[[item view] windowClosed];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the tab bar the window is closed so it will perform any needed cleanup
|
||||||
|
[mTabBar windowClosed];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)tabsVisible
|
- (BOOL)tabsVisible
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
BrowserTabItemContainerView* mTabContentsView;
|
BrowserTabItemContainerView* mTabContentsView;
|
||||||
NSProgressIndicator* mProgressWheel; // STRONG ref
|
NSProgressIndicator* mProgressWheel; // STRONG ref
|
||||||
NSButton* mCloseButton; // STRING ref
|
NSButton* mCloseButton; // STRING ref
|
||||||
|
NSMenuItem* mMenuItem; // STRONG ref
|
||||||
BOOL mDraggable;
|
BOOL mDraggable;
|
||||||
int mTag;
|
int mTag;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +71,10 @@
|
||||||
- (void)willBeRemoved:(BOOL)remove;
|
- (void)willBeRemoved:(BOOL)remove;
|
||||||
|
|
||||||
- (NSButton *)closeButton;
|
- (NSButton *)closeButton;
|
||||||
|
- (NSMenuItem *)menuItem;
|
||||||
|
- (void) willDeselect;
|
||||||
|
- (void) willSelect;
|
||||||
|
- (void) selectTab:(id)sender;
|
||||||
|
|
||||||
+ (NSImage*)closeIcon;
|
+ (NSImage*)closeIcon;
|
||||||
+ (NSImage*)closeIconPressed;
|
+ (NSImage*)closeIconPressed;
|
||||||
|
|
|
@ -52,6 +52,8 @@
|
||||||
// we cannot use the spinner before 10.2, so don't allow it. This is the
|
// we cannot use the spinner before 10.2, so don't allow it. This is the
|
||||||
// version of appkit in 10.2 (taken from the 10.3 SDK headers which we cannot use).
|
// version of appkit in 10.2 (taken from the 10.3 SDK headers which we cannot use).
|
||||||
const double kJaguarAppKitVersion = 663;
|
const double kJaguarAppKitVersion = 663;
|
||||||
|
// truncate menuitem title to the same width as the bookmarks menu
|
||||||
|
const int kMenuTruncationChars = 60;
|
||||||
|
|
||||||
@interface BrowserTabViewItem(Private)
|
@interface BrowserTabViewItem(Private)
|
||||||
- (void)setTag:(int)tag;
|
- (void)setTag:(int)tag;
|
||||||
|
@ -107,6 +109,8 @@ const double kJaguarAppKitVersion = 663;
|
||||||
{
|
{
|
||||||
[mLabelCell release];
|
[mLabelCell release];
|
||||||
[mTabButtonCell release];
|
[mTabButtonCell release];
|
||||||
|
// needs to be nil so that [super dealloc]'s call to setMenu doesn't cause us to call setMenu on an invalid object
|
||||||
|
mTabButtonCell = nil;
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +344,12 @@ const double kJaguarAppKitVersion = 663;
|
||||||
[mCloseButton setTarget:self];
|
[mCloseButton setTarget:self];
|
||||||
[mCloseButton setAction:@selector(closeTab)];
|
[mCloseButton setAction:@selector(closeTab)];
|
||||||
[mCloseButton setAutoresizingMask:NSViewMinXMargin];
|
[mCloseButton setAutoresizingMask:NSViewMinXMargin];
|
||||||
[mCloseButton retain];
|
|
||||||
|
// create a menu item, to be used when there are more tabs than screen real estate. keep a strong ref
|
||||||
|
// since it will be added to and removed from the menu repeatedly
|
||||||
|
mMenuItem = [[NSMenuItem alloc] initWithTitle:[self label] action:@selector(selectTab:) keyEquivalent:@""];
|
||||||
|
[mMenuItem setTarget:self];
|
||||||
|
[mMenuItem retain];
|
||||||
|
|
||||||
[[self tabView] setAutoresizesSubviews:YES];
|
[[self tabView] setAutoresizesSubviews:YES];
|
||||||
|
|
||||||
|
@ -363,6 +372,7 @@ const double kJaguarAppKitVersion = 663;
|
||||||
[mTabContentsView release]; // balance our init
|
[mTabContentsView release]; // balance our init
|
||||||
[mProgressWheel release];
|
[mProgressWheel release];
|
||||||
[mCloseButton release];
|
[mCloseButton release];
|
||||||
|
[mMenuItem release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,6 +433,7 @@ const double kJaguarAppKitVersion = 663;
|
||||||
{
|
{
|
||||||
NSAttributedString* labelString = [[[NSAttributedString alloc] initWithString:label attributes:mLabelAttributes] autorelease];
|
NSAttributedString* labelString = [[[NSAttributedString alloc] initWithString:label attributes:mLabelAttributes] autorelease];
|
||||||
[[mTabContentsView labelCell] setAttributedStringValue:labelString];
|
[[mTabContentsView labelCell] setAttributedStringValue:labelString];
|
||||||
|
[mMenuItem setTitle:[label stringByTruncatingTo:kMenuTruncationChars at:kTruncateAtMiddle]];
|
||||||
[(BrowserTabView *)[self tabView] refreshTabBar:NO];
|
[(BrowserTabView *)[self tabView] refreshTabBar:NO];
|
||||||
|
|
||||||
[super setLabel:label];
|
[super setLabel:label];
|
||||||
|
@ -447,6 +458,7 @@ const double kJaguarAppKitVersion = 663;
|
||||||
{
|
{
|
||||||
[super setTabIcon:newIcon];
|
[super setTabIcon:newIcon];
|
||||||
[[mTabContentsView labelCell] setImage:mTabIcon];
|
[[mTabContentsView labelCell] setImage:mTabIcon];
|
||||||
|
[mMenuItem setImage:mTabIcon];
|
||||||
[(BrowserTabView *)[self tabView] refreshTabBar:NO];
|
[(BrowserTabView *)[self tabView] refreshTabBar:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,6 +512,27 @@ const double kJaguarAppKitVersion = 663;
|
||||||
return mCloseButton;
|
return mCloseButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSMenuItem *) menuItem
|
||||||
|
{
|
||||||
|
return mMenuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) selectTab:(id)sender
|
||||||
|
{
|
||||||
|
[[self tabView] selectTabViewItem:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
// called by delegate when a tab will be deselected
|
||||||
|
- (void) willDeselect
|
||||||
|
{
|
||||||
|
[mMenuItem setState:NSOffState];
|
||||||
|
}
|
||||||
|
// called by delegate when a tab will be selected
|
||||||
|
- (void) willSelect
|
||||||
|
{
|
||||||
|
[mMenuItem setState:NSOnState];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
+ (NSImage*)closeIcon
|
+ (NSImage*)closeIcon
|
||||||
|
|
|
@ -126,7 +126,7 @@ static NSString *NavigatorWindowFrameSaveName = @"NavigatorWindow";
|
||||||
// hardcoded defaults.
|
// hardcoded defaults.
|
||||||
static NSArray* sToolbarDefaults = nil;
|
static NSArray* sToolbarDefaults = nil;
|
||||||
|
|
||||||
#define kMaxBrowserWindowTabs 16
|
#define kMaxBrowserWindowTabs 0
|
||||||
|
|
||||||
enum BWCOpenDest {
|
enum BWCOpenDest {
|
||||||
kDestinationNewWindow = 0,
|
kDestinationNewWindow = 0,
|
||||||
|
@ -504,14 +504,8 @@ enum BWCOpenDest {
|
||||||
NS_IF_RELEASE(mURIFixer);
|
NS_IF_RELEASE(mURIFixer);
|
||||||
} // matters
|
} // matters
|
||||||
|
|
||||||
// Loop over all tabs, and tell them that the window is closed. This
|
// Tell the BrowserTabView the window is closed
|
||||||
// stops gecko from going any further on any of its open connections
|
[mTabBrowser windowClosed];
|
||||||
// and breaks all the necessary cycles between Gecko and the BrowserWrapper.
|
|
||||||
int numTabs = [mTabBrowser numberOfTabViewItems];
|
|
||||||
for (int i = 0; i < numTabs; i++) {
|
|
||||||
NSTabViewItem* item = [mTabBrowser tabViewItemAtIndex: i];
|
|
||||||
[[item view] windowClosed];
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the bookmark manager is visible when we close the window, all hell
|
// if the bookmark manager is visible when we close the window, all hell
|
||||||
// breaks loose in the autorelease pool and when we try to show another
|
// breaks loose in the autorelease pool and when we try to show another
|
||||||
|
@ -2406,6 +2400,18 @@ enum BWCOpenDest {
|
||||||
[mBrowserView makePrimaryBrowserView: mURLBar status: mStatus windowController: self];
|
[mBrowserView makePrimaryBrowserView: mURLBar status: mStatus windowController: self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)tabView:(NSTabView *)aTabView willSelectTabViewItem:(NSTabViewItem *)aTabViewItem
|
||||||
|
{
|
||||||
|
// we'll get called for the sidebar tabs as well. ignore any calls coming from
|
||||||
|
// there, we're only interested in the browser tabs.
|
||||||
|
if (aTabView != mTabBrowser)
|
||||||
|
return;
|
||||||
|
if ([aTabView isKindOfClass:[BrowserTabView class]] && [aTabViewItem isKindOfClass:[BrowserTabViewItem class]]) {
|
||||||
|
[(BrowserTabViewItem *)[aTabView selectedTabViewItem] willDeselect];
|
||||||
|
[(BrowserTabViewItem *)aTabViewItem willSelect];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)aTabView
|
- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)aTabView
|
||||||
{
|
{
|
||||||
[[NSApp delegate] fixCloseMenuItemKeyEquivalents];
|
[[NSApp delegate] fixCloseMenuItemKeyEquivalents];
|
||||||
|
|
|
@ -89,8 +89,11 @@
|
||||||
NSView *view = [userData objectForKey:@"view"];
|
NSView *view = [userData objectForKey:@"view"];
|
||||||
mMouseWithin = YES;
|
mMouseWithin = YES;
|
||||||
// only act on the mouseEntered if the view is active or accepts the first mouse click
|
// only act on the mouseEntered if the view is active or accepts the first mouse click
|
||||||
if ([[view window] isKeyWindow] || [view acceptsFirstMouse:theEvent])
|
if ([[view window] isKeyWindow] || [view acceptsFirstMouse:theEvent]) {
|
||||||
[view setNeedsDisplayInRect:[self frame]];
|
[view setNeedsDisplayInRect:[self frame]];
|
||||||
|
// calling displayIfNeeded prevents the "lag" observed when displaying rollover events
|
||||||
|
[view displayIfNeeded];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseExited:(NSEvent*)theEvent
|
- (void)mouseExited:(NSEvent*)theEvent
|
||||||
|
@ -99,8 +102,11 @@
|
||||||
NSView *view = [userData objectForKey:@"view"];
|
NSView *view = [userData objectForKey:@"view"];
|
||||||
mMouseWithin = NO;
|
mMouseWithin = NO;
|
||||||
// only act on the mouseExited if the view is active or accepts the first mouse click
|
// only act on the mouseExited if the view is active or accepts the first mouse click
|
||||||
if ([[view window] isKeyWindow] || [view acceptsFirstMouse:theEvent])
|
if ([[view window] isKeyWindow] || [view acceptsFirstMouse:theEvent]) {
|
||||||
[view setNeedsDisplayInRect:[self frame]];
|
[view setNeedsDisplayInRect:[self frame]];
|
||||||
|
// calling displayIfNeeded prevents the "lag" observed when displaying rollover events
|
||||||
|
[view displayIfNeeded];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDragTarget:(BOOL)isDragTarget
|
- (void)setDragTarget:(BOOL)isDragTarget
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
@interface TabButtonCell : RolloverTrackingCell {
|
@interface TabButtonCell : RolloverTrackingCell {
|
||||||
BrowserTabViewItem *mTabViewItem;
|
BrowserTabViewItem *mTabViewItem;
|
||||||
BOOL mNeedsDivider;
|
BOOL mNeedsDivider;
|
||||||
|
NSButton * mCloseButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
-(id)initFromTabViewItem:(BrowserTabViewItem*)tabViewItem;
|
-(id)initFromTabViewItem:(BrowserTabViewItem*)tabViewItem;
|
||||||
|
|
|
@ -64,16 +64,15 @@ static NSImage * tabButtonDividerImage = nil;
|
||||||
-(id)initFromTabViewItem:(BrowserTabViewItem *)tabViewItem
|
-(id)initFromTabViewItem:(BrowserTabViewItem *)tabViewItem
|
||||||
{
|
{
|
||||||
[super init];
|
[super init];
|
||||||
mTabViewItem = [tabViewItem retain];
|
mTabViewItem = tabViewItem;
|
||||||
mNeedsDivider = YES;
|
mNeedsDivider = YES;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX does the menu need released here??
|
|
||||||
-(void)dealloc
|
-(void)dealloc
|
||||||
{
|
{
|
||||||
[[mTabViewItem closeButton] removeFromSuperview];
|
[mCloseButton removeFromSuperview];
|
||||||
[mTabViewItem release];
|
[mCloseButton release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +101,11 @@ static NSImage * tabButtonDividerImage = nil;
|
||||||
// we have bigger problems
|
// we have bigger problems
|
||||||
|
|
||||||
NSSize textSize = [mTabViewItem sizeOfLabel:NO];
|
NSSize textSize = [mTabViewItem sizeOfLabel:NO];
|
||||||
NSSize buttonSize = [[mTabViewItem closeButton] frame].size;
|
|
||||||
|
// retain a reference to the close button; otherwise we can't be sure it's removed from the view hierarchy
|
||||||
|
// during our d'tor, when mTabViewItem will be invalid.
|
||||||
|
if (!mCloseButton) mCloseButton = [[mTabViewItem closeButton] retain];
|
||||||
|
NSSize buttonSize = [mCloseButton frame].size;
|
||||||
|
|
||||||
// center based on the larger of the two heights if there's a difference
|
// center based on the larger of the two heights if there's a difference
|
||||||
float maxHeight = textSize.height > buttonSize.height ? textSize.height : buttonSize.height;
|
float maxHeight = textSize.height > buttonSize.height ? textSize.height : buttonSize.height;
|
||||||
|
@ -148,13 +151,10 @@ static NSImage * tabButtonDividerImage = nil;
|
||||||
rect.origin.y += kTabBottomPad;
|
rect.origin.y += kTabBottomPad;
|
||||||
NSRectFill(rect);
|
NSRectFill(rect);
|
||||||
}
|
}
|
||||||
NSButton *closeButton = [mTabViewItem closeButton];
|
if (controlView != [mCloseButton superview]) {
|
||||||
if (controlView != [closeButton superview]) {
|
[controlView addSubview:mCloseButton];
|
||||||
[controlView addSubview:closeButton];
|
|
||||||
}
|
}
|
||||||
[closeButton setFrame:buttonRect];
|
[mCloseButton setFrame:buttonRect];
|
||||||
// XXX is this necessary, or even good?
|
|
||||||
[closeButton setNeedsDisplay:YES];
|
|
||||||
[labelCell drawInteriorWithFrame:labelRect inView:controlView];
|
[labelCell drawInteriorWithFrame:labelRect inView:controlView];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,9 +170,8 @@ static NSImage * tabButtonDividerImage = nil;
|
||||||
|
|
||||||
-(void)hideCloseButton
|
-(void)hideCloseButton
|
||||||
{
|
{
|
||||||
NSButton * closeButton = [mTabViewItem closeButton];
|
if ([mCloseButton superview] != nil)
|
||||||
if ([closeButton superview] != nil)
|
[mCloseButton removeFromSuperview];
|
||||||
[closeButton removeFromSuperview];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)setDrawDivider:(BOOL)willDraw
|
-(void)setDrawDivider:(BOOL)willDraw
|
||||||
|
|
Загрузка…
Ссылка в новой задаче