Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1057 lines (860 sloc) 34.1 KB
//
// PSMAdiumTabStyle.m
// PSMTabBarControl
//
// Created by Kent Sutherland on 5/26/06.
// Copyright 2006 Kent Sutherland. All rights reserved.
//
#import "PSMAdiumTabStyle.h"
#import "PSMTabBarCell.h"
#import "PSMTabBarControl.h"
#import "NSBezierPath_AMShading.h"
#define Adium_CellPadding 2
#define Adium_MARGIN_X 4
#define kPSMAdiumCounterPadding 3.0
#define kPSMAdiumObjectCounterRadius 7.0
#define kPSMAdiumCounterMinWidth 20
#define kPSMTabBarControlSourceListHeight 28
#define kPSMTabBarLargeImageHeight kPSMTabBarControlSourceListHeight - 4
#define kPSMTabBarLargeImageWidth kPSMTabBarLargeImageHeight
@implementation PSMAdiumTabStyle
- (NSString *)name
{
return @"Adium";
}
#pragma mark -
#pragma mark Creation/Destruction
- (id)init
{
if ( (self = [super init]) ) {
[self loadImages];
_drawsUnified = NO;
_drawsRight = NO;
_objectCountStringAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:[[NSFontManager sharedFontManager] convertFont:[NSFont fontWithName:@"Helvetica" size:11.0] toHaveTrait:NSBoldFontMask], NSFontAttributeName,
[[NSColor whiteColor] colorWithAlphaComponent:0.85], NSForegroundColorAttributeName,
nil, nil];
}
return self;
}
- (void)loadImages
{
_closeButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front"]];
_closeButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Pressed"]];
_closeButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Rollover"]];
_closeDirtyButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front"]];
_closeDirtyButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front_Pressed"]];
_closeDirtyButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front_Rollover"]];
_addTabButtonImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNew"]];
_addTabButtonPressedImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNewPressed"]];
_addTabButtonRolloverImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNewRollover"]];
_gradientImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AdiumGradient"]];
}
- (void)dealloc
{
[_closeButton release];
[_closeButtonDown release];
[_closeButtonOver release];
[_closeDirtyButton release];
[_closeDirtyButtonDown release];
[_closeDirtyButtonOver release];
[_addTabButtonImage release];
[_addTabButtonPressedImage release];
[_addTabButtonRolloverImage release];
[_gradientImage release];
[_objectCountStringAttributes release];
[super dealloc];
}
#pragma mark -
#pragma mark Drawing Style Accessors
- (BOOL)drawsUnified
{
return _drawsUnified;
}
- (void)setDrawsUnified:(BOOL)value
{
_drawsUnified = value;
}
- (BOOL)drawsRight
{
return _drawsRight;
}
- (void)setDrawsRight:(BOOL)value
{
_drawsRight = value;
}
#pragma mark -
#pragma mark Control Specific
- (float)leftMarginForTabBarControl
{
return 3.0f;
}
- (float)rightMarginForTabBarControl
{
return 24.0f;
}
- (float)topMarginForTabBarControl
{
return 10.0f;
}
- (void)setOrientation:(PSMTabBarOrientation)value
{
orientation = value;
}
#pragma mark -
#pragma mark Add Tab Button
- (NSImage *)addTabButtonImage
{
return _addTabButtonImage;
}
- (NSImage *)addTabButtonPressedImage
{
return _addTabButtonPressedImage;
}
- (NSImage *)addTabButtonRolloverImage
{
return _addTabButtonRolloverImage;
}
#pragma mark -
#pragma mark Cell Specific
- (NSRect)dragRectForTabCell:(PSMTabBarCell *)cell orientation:(PSMTabBarOrientation)tabOrientation
{
NSRect dragRect = [cell frame];
if ([cell tabState] & PSMTab_SelectedMask) {
if (tabOrientation == PSMTabBarHorizontalOrientation) {
dragRect.size.width++;
dragRect.size.height -= 2.0;
}
}
return dragRect;
}
- (BOOL)closeButtonIsEnabledForCell:(PSMTabBarCell *)cell
{
return ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]);
}
- (NSRect)closeButtonRectForTabCell:(PSMTabBarCell *)cell withFrame:(NSRect)cellFrame
{
if ([self closeButtonIsEnabledForCell:cell] == NO) {
return NSZeroRect;
}
NSRect result;
result.size = [_closeButton size];
switch (orientation) {
case PSMTabBarHorizontalOrientation:
{
result.origin.x = cellFrame.origin.x + Adium_MARGIN_X;
result.origin.y = cellFrame.origin.y + MARGIN_Y + 2.0;
if ([cell state] == NSOnState) {
result.origin.y -= 1;
}
break;
}
case PSMTabBarVerticalOrientation:
{
result.origin.x = NSMaxX(cellFrame) - (Adium_MARGIN_X*2) - NSWidth(result);
result.origin.y = NSMinY(cellFrame) + (NSHeight(cellFrame) / 2) - (result.size.height / 2) + 1;
break;
}
}
return result;
}
- (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell
{
if ([cell hasIcon] == NO) {
return NSZeroRect;
}
NSRect cellFrame = [cell frame];
NSImage *icon = [[[cell representedObject] identifier] icon];
NSSize iconSize = [icon size];
NSRect result;
result.size = iconSize;
switch (orientation)
{
case PSMTabBarHorizontalOrientation:
result.origin.x = cellFrame.origin.x + Adium_MARGIN_X;
result.origin.y = cellFrame.origin.y + MARGIN_Y;
break;
case PSMTabBarVerticalOrientation:
result.origin.x = NSMaxX(cellFrame) - (Adium_MARGIN_X * 2) - NSWidth(result);
result.origin.y = NSMinY(cellFrame) + (NSHeight(cellFrame) / 2) - (NSHeight(result) / 2) + 1;
break;
}
// For horizontal tabs, center in available space (in case icon image is smaller than kPSMTabBarIconWidth)
if (orientation == PSMTabBarHorizontalOrientation) {
if (iconSize.width < kPSMTabBarIconWidth)
result.origin.x += (kPSMTabBarIconWidth - iconSize.width) / 2.0;
if (iconSize.height < kPSMTabBarIconWidth)
result.origin.y += (kPSMTabBarIconWidth - iconSize.height) / 2.0;
}
if ([cell state] == NSOnState) {
result.origin.y -= 1;
}
return result;
}
- (NSRect)indicatorRectForTabCell:(PSMTabBarCell *)cell
{
NSRect cellFrame = [cell frame];
if ([[cell indicator] isHidden]) {
return NSZeroRect;
}
NSRect result;
result.size = NSMakeSize(kPSMTabBarIndicatorWidth, kPSMTabBarIndicatorWidth);
result.origin.x = cellFrame.origin.x + cellFrame.size.width - Adium_MARGIN_X - kPSMTabBarIndicatorWidth;
result.origin.y = cellFrame.origin.y + MARGIN_Y;
if ([cell state] == NSOnState) {
result.origin.y -= 1;
}
return result;
}
- (NSSize)sizeForObjectCounterRectForTabCell:(PSMTabBarCell *)cell
{
NSSize size;
float countWidth = [[self attributedObjectCountValueForTabCell:cell] size].width;
countWidth += (2 * kPSMAdiumObjectCounterRadius - 6.0 + kPSMAdiumCounterPadding);
if (countWidth < kPSMAdiumCounterMinWidth) {
countWidth = kPSMAdiumCounterMinWidth;
}
size = NSMakeSize(countWidth, 2 * kPSMAdiumObjectCounterRadius); // temp
return size;
}
- (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell
{
NSRect cellFrame;
NSRect result;
if ([cell count] == 0) {
return NSZeroRect;
}
cellFrame = [cell frame];
result.size = [self sizeForObjectCounterRectForTabCell:cell];
result.origin.x = NSMaxX(cellFrame) - Adium_MARGIN_X - result.size.width;
result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
if (![[cell indicator] isHidden]) {
result.origin.x -= kPSMTabBarIndicatorWidth + Adium_CellPadding;
}
return result;
}
- (float)minimumWidthOfTabCell:(PSMTabBarCell *)cell
{
float resultWidth = 0.0;
// left margin
resultWidth = Adium_MARGIN_X;
// close button?
if ([self closeButtonIsEnabledForCell:cell]) {
resultWidth += MAX([_closeButton size].width, NSWidth([self iconRectForTabCell:cell])) + Adium_CellPadding;
}
// icon?
/*if ([cell hasIcon]) {
resultWidth += kPSMTabBarIconWidth + Adium_CellPadding;
}*/
// the label
resultWidth += kPSMMinimumTitleWidth;
// object counter?
if (([cell count] > 0) && (orientation == PSMTabBarHorizontalOrientation)) {
resultWidth += NSWidth([self objectCounterRectForTabCell:cell]) + Adium_CellPadding;
}
// indicator?
if ([[cell indicator] isHidden] == NO) {
resultWidth += Adium_CellPadding + kPSMTabBarIndicatorWidth;
}
// right margin
resultWidth += Adium_MARGIN_X;
return ceil(resultWidth);
}
- (float)desiredWidthOfTabCell:(PSMTabBarCell *)cell
{
float resultWidth = 0.0;
// left margin
resultWidth = Adium_MARGIN_X;
// close button?
if ([self closeButtonIsEnabledForCell:cell]) {
resultWidth += MAX([_closeButton size].width, NSWidth([self iconRectForTabCell:cell])) + Adium_CellPadding;
}
// icon?
/*if ([cell hasIcon]) {
resultWidth += kPSMTabBarIconWidth + Adium_CellPadding;
}*/
// the label
resultWidth += [[cell attributedStringValue] size].width + Adium_CellPadding;
// object counter?
if (([cell count] > 0) && (orientation == PSMTabBarHorizontalOrientation)){
resultWidth += [self objectCounterRectForTabCell:cell].size.width + Adium_CellPadding;
}
// indicator?
if ([[cell indicator] isHidden] == NO) {
resultWidth += Adium_CellPadding + kPSMTabBarIndicatorWidth;
}
// right margin
resultWidth += Adium_MARGIN_X;
return ceil(resultWidth);
}
- (float)tabCellHeight
{
return ((orientation == PSMTabBarHorizontalOrientation) ? kPSMTabBarControlHeight : kPSMTabBarControlSourceListHeight);
}
#pragma mark -
#pragma mark Cell Values
- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell
{
NSString *contents = [NSString stringWithFormat:@"%i", [cell count]];
return [[[NSMutableAttributedString alloc] initWithString:contents attributes:_objectCountStringAttributes] autorelease];
}
- (NSAttributedString *)attributedStringValueForTabCell:(PSMTabBarCell *)cell
{
NSMutableAttributedString *attrStr;
NSString *contents = [cell stringValue];
attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
NSRange range = NSMakeRange(0, [contents length]);
// Add font attribute
[attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] range:range];
[attrStr addAttribute:NSForegroundColorAttributeName value:[NSColor controlTextColor] range:range];
// Paragraph Style for Truncating Long Text
static NSMutableParagraphStyle *TruncatingTailParagraphStyle = nil;
if (!TruncatingTailParagraphStyle) {
TruncatingTailParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
[TruncatingTailParagraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
}
[attrStr addAttribute:NSParagraphStyleAttributeName value:TruncatingTailParagraphStyle range:range];
return attrStr;
}
#pragma mark -
#pragma mark Cell Drawing
- (float)heightOfAttributedString:(NSAttributedString *)inAttributedString withWidth:(float)width
{
static NSMutableDictionary *cache;
if (!cache)
cache = [[NSMutableDictionary alloc] init];
if ([cache count] > 100) //100 items should be trivial in terms of memory overhead, but sufficient
[cache removeAllObjects];
NSNumber *cachedHeight = [cache objectForKey:inAttributedString];
if (cachedHeight)
return [cachedHeight floatValue];
else {
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:inAttributedString];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(width, 1e7)];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
//Configure
[textContainer setLineFragmentPadding:0.0];
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];
//Force the layout manager to layout its text
(void)[layoutManager glyphRangeForTextContainer:textContainer];
float height = [layoutManager usedRectForTextContainer:textContainer].size.height;
[textStorage release];
[textContainer release];
[layoutManager release];
[cache setObject:[NSNumber numberWithFloat:height] forKey:inAttributedString];
return height;
}
}
- (void)drawObjectCounterInCell:(PSMTabBarCell *)cell withRect:(NSRect)myRect
{
myRect.size.width -= kPSMAdiumCounterPadding;
myRect.origin.x += kPSMAdiumCounterPadding;
[[cell countColor] ?: [NSColor colorWithCalibratedWhite:0.3 alpha:0.6] set];
NSBezierPath *path = [NSBezierPath bezierPath];
[path setLineWidth:1.0];
if ([cell state] == NSOnState) {
myRect.origin.y -= 1.0;
}
[path moveToPoint:NSMakePoint(NSMinX(myRect) + kPSMAdiumObjectCounterRadius, NSMinY(myRect))];
[path lineToPoint:NSMakePoint(NSMaxX(myRect) - kPSMAdiumObjectCounterRadius, NSMinY(myRect))];
[path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(myRect) - kPSMAdiumObjectCounterRadius, NSMinY(myRect) + kPSMAdiumObjectCounterRadius)
radius:kPSMAdiumObjectCounterRadius
startAngle:270.0
endAngle:90.0];
[path lineToPoint:NSMakePoint(NSMinX(myRect) + kPSMAdiumObjectCounterRadius, NSMaxY(myRect))];
[path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(myRect) + kPSMAdiumObjectCounterRadius, NSMinY(myRect) + kPSMAdiumObjectCounterRadius)
radius:kPSMAdiumObjectCounterRadius
startAngle:90.0
endAngle:270.0];
[path fill];
// draw attributed string centered in area
NSRect counterStringRect;
NSAttributedString *counterString = [self attributedObjectCountValueForTabCell:cell];
counterStringRect.size = [counterString size];
counterStringRect.origin.x = myRect.origin.x + ((myRect.size.width - counterStringRect.size.width) / 2.0) + 0.25;
counterStringRect.origin.y = myRect.origin.y + ((myRect.size.height - counterStringRect.size.height) / 2.0) + 0.5;
[counterString drawInRect:counterStringRect];
}
- (NSBezierPath *)bezierPathWithRoundedRect:(NSRect)rect radius:(float)radius
{
NSBezierPath *path = [NSBezierPath bezierPath];
NSPoint topLeft, topRight, bottomLeft, bottomRight;
topLeft = NSMakePoint(rect.origin.x, rect.origin.y);
topRight = NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y);
bottomLeft = NSMakePoint(rect.origin.x, rect.origin.y + rect.size.height);
bottomRight = NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
[path appendBezierPathWithArcWithCenter:NSMakePoint(topLeft.x + radius, topLeft.y + radius)
radius:radius
startAngle:180
endAngle:270
clockwise:NO];
[path lineToPoint:NSMakePoint(topRight.x - radius, topRight.y)];
[path appendBezierPathWithArcWithCenter:NSMakePoint(topRight.x - radius, topRight.y + radius)
radius:radius
startAngle:270
endAngle:0
clockwise:NO];
[path lineToPoint:NSMakePoint(bottomRight.x, bottomRight.y - radius)];
[path appendBezierPathWithArcWithCenter:NSMakePoint(bottomRight.x - radius, bottomRight.y - radius)
radius:radius
startAngle:0
endAngle:90
clockwise:NO];
[path lineToPoint:NSMakePoint(bottomLeft.x + radius, bottomLeft.y)];
[path appendBezierPathWithArcWithCenter:NSMakePoint(bottomLeft.x + radius, bottomLeft.y - radius)
radius:radius
startAngle:90
endAngle:180
clockwise:NO];
[path lineToPoint:NSMakePoint(topLeft.x, topLeft.y + radius)];
return path;
}
- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView
{
NSRect cellFrame = [cell frame];
if ((orientation == PSMTabBarVerticalOrientation) &&
[cell hasLargeImage]) {
NSImage *image = [[[cell representedObject] identifier] largeImage];
cellFrame.origin.x += Adium_MARGIN_X;
NSRect imageDrawingRect = NSMakeRect(cellFrame.origin.x,
cellFrame.origin.y - ((kPSMTabBarControlSourceListHeight - kPSMTabBarLargeImageHeight) / 2),
kPSMTabBarLargeImageWidth, kPSMTabBarLargeImageHeight);
[NSGraphicsContext saveGraphicsState];
//Use a transform to draw an arbitrary image in our flipped view
NSAffineTransform *transform = [NSAffineTransform transform];
[transform translateXBy:imageDrawingRect.origin.x yBy:(imageDrawingRect.origin.y + imageDrawingRect.size.height)];
[transform scaleXBy:1.0 yBy:-1.0];
[transform concat];
imageDrawingRect.origin = NSMakePoint(0,0);
//Create Rounding.
float userIconRoundingRadius = (kPSMTabBarLargeImageWidth / 4.0);
if (userIconRoundingRadius > 3) userIconRoundingRadius = 3;
NSBezierPath *clipPath = [self bezierPathWithRoundedRect:imageDrawingRect radius:userIconRoundingRadius];
[clipPath addClip];
[image drawInRect:imageDrawingRect
fromRect:NSMakeRect(0, 0, [image size].width, [image size].height)
operation:NSCompositeSourceOver
fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
cellFrame.origin.x += imageDrawingRect.size.width;
cellFrame.size.width -= imageDrawingRect.size.width;
}
// label rect
NSRect labelRect;
labelRect.origin.x = cellFrame.origin.x + Adium_MARGIN_X;
labelRect.size.width = cellFrame.size.width - (labelRect.origin.x - cellFrame.origin.x) - Adium_CellPadding;
labelRect.size.height = cellFrame.size.height;
switch (orientation)
{
case PSMTabBarHorizontalOrientation:
labelRect.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
break;
case PSMTabBarVerticalOrientation:
labelRect.origin.y = cellFrame.origin.y;
break;
}
if ([self closeButtonIsEnabledForCell:cell]) {
/* The close button and the icon (if present) are drawn combined, changing on-hover */
NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame];
NSRect iconRect = [self iconRectForTabCell:cell];
NSRect drawingRect;
NSImage *closeButtonOrIcon = nil;
if ([cell hasIcon]) {
/* If the cell has an icon and a close button, determine which rect should be used and use it consistently
* This only matters for horizontal tabs; vertical tabs look fine without making this adjustment.
*/
if (NSWidth(iconRect) > NSWidth(closeButtonRect)) {
closeButtonRect.origin.x = NSMinX(iconRect) + NSWidth(iconRect)/2 - NSWidth(closeButtonRect)/2;
}
}
if ([cell closeButtonPressed]) {
closeButtonOrIcon = ([cell isEdited] ? _closeDirtyButtonDown : _closeButtonDown);
drawingRect = closeButtonRect;
} else if ([cell closeButtonOver]) {
closeButtonOrIcon = ([cell isEdited] ? _closeDirtyButtonOver : _closeButtonOver);
drawingRect = closeButtonRect;
} else if ((orientation == PSMTabBarVerticalOrientation) &&
([cell count] > 0)) {
/* In vertical tabs, the count indicator supercedes the icon */
NSSize counterSize = [self sizeForObjectCounterRectForTabCell:cell];
if (counterSize.width > NSWidth(closeButtonRect)) {
closeButtonRect.origin.x -= (counterSize.width - NSWidth(closeButtonRect));
closeButtonRect.size.width = counterSize.width;
}
closeButtonRect.origin.y = cellFrame.origin.y + ((NSHeight(cellFrame) - counterSize.height) / 2);
closeButtonRect.size.height = counterSize.height;
drawingRect = closeButtonRect;
[self drawObjectCounterInCell:cell withRect:drawingRect];
/* closeButtonOrIcon == nil */
} else if ([cell hasIcon]) {
closeButtonOrIcon = [[[cell representedObject] identifier] icon];
drawingRect = iconRect;
} else {
closeButtonOrIcon = ([cell isEdited] ? _closeDirtyButton : _closeButton);
drawingRect = closeButtonRect;
}
if ([controlView isFlipped]) {
drawingRect.origin.y += drawingRect.size.height;
}
[closeButtonOrIcon compositeToPoint:drawingRect.origin operation:NSCompositeSourceOver fraction:1.0];
// scoot label over
switch (orientation)
{
case PSMTabBarHorizontalOrientation:
{
float oldOrigin = labelRect.origin.x;
if (NSWidth(iconRect) > NSWidth(closeButtonRect)) {
labelRect.origin.x = (NSMaxX(iconRect) + (Adium_CellPadding * 2));
} else {
labelRect.origin.x = (NSMaxX(closeButtonRect) + (Adium_CellPadding * 2));
}
labelRect.size.width -= (NSMinX(labelRect) - oldOrigin);
break;
}
case PSMTabBarVerticalOrientation:
{
//Generate the remaining label rect directly from the location of the close button, allowing for padding
if (NSWidth(iconRect) > NSWidth(closeButtonRect)) {
labelRect.size.width = NSMinX(iconRect) - Adium_CellPadding - NSMinX(labelRect);
} else {
labelRect.size.width = NSMinX(closeButtonRect) - Adium_CellPadding - NSMinX(labelRect);
}
break;
}
}
} else if ([cell hasIcon]) {
/* The close button is disabled; the cell has an icon */
NSRect iconRect = [self iconRectForTabCell:cell];
NSImage *icon = [[[cell representedObject] identifier] icon];
if ([controlView isFlipped]) {
iconRect.origin.y += iconRect.size.height;
}
[icon compositeToPoint:iconRect.origin operation:NSCompositeSourceOver fraction:1.0];
// scoot label over by the size of the standard close button
switch (orientation)
{
case PSMTabBarHorizontalOrientation:
labelRect.origin.x += (NSWidth(iconRect) + Adium_CellPadding);
labelRect.size.width -= (NSWidth(iconRect) + Adium_CellPadding);
break;
case PSMTabBarVerticalOrientation:
labelRect.size.width -= (NSWidth(iconRect) + Adium_CellPadding);
break;
}
}
if ([cell state] == NSOnState) {
labelRect.origin.y -= 1;
}
if (![[cell indicator] isHidden]) {
labelRect.size.width -= (kPSMTabBarIndicatorWidth + Adium_CellPadding);
}
// object counter
//The object counter takes up space horizontally...
if (([cell count] > 0) &&
(orientation == PSMTabBarHorizontalOrientation)) {
NSRect counterRect = [self objectCounterRectForTabCell:cell];
[self drawObjectCounterInCell:cell withRect:counterRect];
labelRect.size.width -= NSWidth(counterRect) + Adium_CellPadding;
}
// draw label
NSAttributedString *attributedString = [cell attributedStringValue];
if (orientation == PSMTabBarVerticalOrientation) {
//Calculate the centered rect
float stringHeight = [self heightOfAttributedString:attributedString withWidth:NSWidth(labelRect)];
if (stringHeight < labelRect.size.height) {
labelRect.origin.y += (NSHeight(labelRect) - stringHeight) / 2.0;
}
}
[attributedString drawInRect:labelRect];
}
- (void)drawTabCell:(PSMTabBarCell *)cell
{
NSRect cellFrame = [cell frame];
NSColor *lineColor = nil;
NSBezierPath *bezier = [NSBezierPath bezierPath];
lineColor = [NSColor grayColor];
[bezier setLineWidth:1.0];
//disable antialiasing of bezier paths
[NSGraphicsContext saveGraphicsState];
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
NSShadow *shadow = [[NSShadow alloc] init];
[shadow setShadowOffset:NSMakeSize(-2, -2)];
[shadow setShadowBlurRadius:2];
[shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.6 alpha:1.0]];
if ([cell state] == NSOnState) {
// selected tab
if (orientation == PSMTabBarHorizontalOrientation) {
NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, NSWidth(cellFrame), cellFrame.size.height - 2.5);
// background
if (_drawsUnified) {
if ([[[tabBar tabView] window] isKeyWindow]) {
NSBezierPath *path = [NSBezierPath bezierPathWithRect:aRect];
[path linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0]
endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]];
} else {
[[NSColor windowBackgroundColor] set];
NSRectFill(aRect);
}
} else {
[_gradientImage drawInRect:NSMakeRect(NSMinX(aRect), NSMinY(aRect), NSWidth(aRect), NSHeight(aRect)) fromRect:NSMakeRect(0, 0, [_gradientImage size].width, [_gradientImage size].height) operation:NSCompositeSourceOver fraction:1.0];
}
// frame
[lineColor set];
[bezier setLineWidth:1.0];
[bezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y)];
[bezier lineToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y + aRect.size.height)];
[shadow setShadowOffset:NSMakeSize(-2, -2)];
[shadow set];
[bezier stroke];
bezier = [NSBezierPath bezierPath];
[bezier setLineWidth:1.0];
[bezier moveToPoint:NSMakePoint(NSMinX(aRect), NSMaxY(aRect))];
[bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMaxY(aRect))];
[bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMinY(aRect))];
if ([[cell controlView] frame].size.height < 2) {
// special case of hidden control; need line across top of cell
[bezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y + 0.5)];
[bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width, aRect.origin.y + 0.5)];
}
[shadow setShadowOffset:NSMakeSize(2, -2)];
[shadow set];
[bezier stroke];
} else {
NSRect aRect;
if (_drawsRight) {
aRect = NSMakeRect(cellFrame.origin.x - 1, cellFrame.origin.y, cellFrame.size.width - 3, cellFrame.size.height);
} else {
aRect = NSMakeRect(cellFrame.origin.x + 2, cellFrame.origin.y, cellFrame.size.width - 2, cellFrame.size.height);
}
// background
if (_drawsUnified) {
if ([[[tabBar tabView] window] isKeyWindow]) {
NSBezierPath *path = [NSBezierPath bezierPathWithRect:aRect];
[path linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0]
endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]];
} else {
[[NSColor windowBackgroundColor] set];
NSRectFill(aRect);
}
} else {
NSBezierPath *path = [NSBezierPath bezierPathWithRect:aRect];
if (_drawsRight) {
[path linearVerticalGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.92 alpha:1.0]
endColor:[NSColor colorWithCalibratedWhite:0.98 alpha:1.0]];
} else {
[path linearVerticalGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.98 alpha:1.0]
endColor:[NSColor colorWithCalibratedWhite:0.92 alpha:1.0]];
}
}
// frame
//top line
[lineColor set];
[bezier setLineWidth:1.0];
[bezier moveToPoint:NSMakePoint(NSMinX(aRect), NSMinY(aRect))];
[bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMinY(aRect))];
[bezier stroke];
//outer edge and bottom lines
bezier = [NSBezierPath bezierPath];
[bezier setLineWidth:1.0];
if (_drawsRight) {
//Right
[bezier moveToPoint:NSMakePoint(NSMaxX(aRect), NSMinY(aRect))];
[bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMaxY(aRect))];
//Bottom
[bezier lineToPoint:NSMakePoint(NSMinX(aRect), NSMaxY(aRect))];
} else {
//Left
[bezier moveToPoint:NSMakePoint(NSMinX(aRect), NSMinY(aRect))];
[bezier lineToPoint:NSMakePoint(NSMinX(aRect), NSMaxY(aRect))];
//Bottom
[bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMaxY(aRect))];
}
[shadow setShadowOffset:NSMakeSize((_drawsRight ? 2 : -2), -2)];
[shadow set];
[bezier stroke];
}
} else {
// unselected tab
NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
// rollover
if ([cell isHighlighted]) {
[[NSColor colorWithCalibratedWhite:0.0 alpha:0.1] set];
NSRectFillUsingOperation(aRect, NSCompositeSourceAtop);
}
// frame
[lineColor set];
if (orientation == PSMTabBarHorizontalOrientation) {
[bezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y)];
[bezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y)];
if (!([cell tabState] & PSMTab_RightIsSelectedMask)) {
//draw the tab divider
[bezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y + aRect.size.height)];
}
[bezier stroke];
} else {
//No outline for vertical
}
}
[NSGraphicsContext restoreGraphicsState];
[shadow release];
[self drawInteriorWithTabCell:cell inView:[cell controlView]];
}
- (void)drawBackgroundInRect:(NSRect)rect
{
//Draw for our whole bounds; it'll be automatically clipped to fit the appropriate drawing area
rect = [tabBar bounds];
switch (orientation) {
case PSMTabBarHorizontalOrientation:
if (_drawsUnified && [[[tabBar tabView] window] isKeyWindow]) {
if ([[[tabBar tabView] window] isKeyWindow]) {
NSBezierPath *backgroundPath = [NSBezierPath bezierPathWithRect:rect];
[backgroundPath linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0]
endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]];
} else {
[[NSColor windowBackgroundColor] set];
NSRectFill(rect);
}
} else {
[[NSColor colorWithCalibratedWhite:0.85 alpha:0.6] set];
[NSBezierPath fillRect:rect];
}
break;
case PSMTabBarVerticalOrientation:
//This is the Mail.app source list background color... which differs from the iTunes one.
[[NSColor colorWithCalibratedRed:.9059
green:.9294
blue:.9647
alpha:1.0] set];
NSRectFill(rect);
break;
}
//Draw the border and shadow around the tab bar itself
[NSGraphicsContext saveGraphicsState];
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
NSShadow *shadow = [[NSShadow alloc] init];
[shadow setShadowBlurRadius:2];
[shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.6 alpha:1.0]];
[[NSColor grayColor] set];
NSBezierPath *path = [NSBezierPath bezierPath];
[path setLineWidth:1.0];
switch (orientation) {
case PSMTabBarHorizontalOrientation:
{
rect.origin.y++;
[path moveToPoint:NSMakePoint(rect.origin.x, rect.origin.y)];
[path lineToPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y)];
[shadow setShadowOffset:NSMakeSize(2, -2)];
[shadow set];
[path stroke];
break;
}
case PSMTabBarVerticalOrientation:
{
NSPoint startPoint, endPoint;
NSSize shadowOffset;
//Draw vertical shadow
if (_drawsRight) {
startPoint = NSMakePoint(NSMinX(rect), NSMinY(rect));
endPoint = NSMakePoint(NSMinX(rect), NSMaxY(rect));
shadowOffset = NSMakeSize(2, -2);
} else {
startPoint = NSMakePoint(NSMaxX(rect) - 1, NSMinY(rect));
endPoint = NSMakePoint(NSMaxX(rect) - 1, NSMaxY(rect));
shadowOffset = NSMakeSize(-2, -2);
}
[path moveToPoint:startPoint];
[path lineToPoint:endPoint];
[shadow setShadowOffset:shadowOffset];
[shadow set];
[path stroke];
[path removeAllPoints];
//Draw top horizontal shadow
startPoint = NSMakePoint(NSMinX(rect), NSMinY(rect));
endPoint = NSMakePoint(NSMaxX(rect), NSMinY(rect));
shadowOffset = NSMakeSize(0, -1);
[path moveToPoint:startPoint];
[path lineToPoint:endPoint];
[shadow setShadowOffset:shadowOffset];
[shadow set];
[path stroke];
break;
}
}
[shadow release];
[NSGraphicsContext restoreGraphicsState];
}
- (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect
{
if (orientation != [bar orientation]) {
orientation = [bar orientation];
}
if (tabBar != bar) {
tabBar = bar;
}
[self drawBackgroundInRect:rect];
// no tab view == not connected
if (![bar tabView]) {
NSRect labelRect = rect;
labelRect.size.height -= 4.0;
labelRect.origin.y += 4.0;
NSMutableAttributedString *attrStr;
NSString *contents = @"PSMTabBarControl";
attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
NSRange range = NSMakeRange(0, [contents length]);
[attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] range:range];
NSMutableParagraphStyle *centeredParagraphStyle = nil;
if (!centeredParagraphStyle) {
centeredParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
[centeredParagraphStyle setAlignment:NSCenterTextAlignment];
}
[attrStr addAttribute:NSParagraphStyleAttributeName value:centeredParagraphStyle range:range];
[attrStr drawInRect:labelRect];
return;
}
// draw cells
NSEnumerator *e = [[bar cells] objectEnumerator];
PSMTabBarCell *cell;
while ( (cell = [e nextObject]) ) {
if ([bar isAnimating] || (![cell isInOverflowMenu] && NSIntersectsRect([cell frame], rect))) {
[cell drawWithFrame:[cell frame] inView:bar];
}
}
}
#pragma mark -
#pragma mark Archiving
- (void)encodeWithCoder:(NSCoder *)aCoder
{
if ([aCoder allowsKeyedCoding]) {
[aCoder encodeObject:_closeButton forKey:@"closeButton"];
[aCoder encodeObject:_closeButtonDown forKey:@"closeButtonDown"];
[aCoder encodeObject:_closeButtonOver forKey:@"closeButtonOver"];
[aCoder encodeObject:_closeDirtyButton forKey:@"closeDirtyButton"];
[aCoder encodeObject:_closeDirtyButtonDown forKey:@"closeDirtyButtonDown"];
[aCoder encodeObject:_closeDirtyButtonOver forKey:@"closeDirtyButtonOver"];
[aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"];
[aCoder encodeObject:_addTabButtonPressedImage forKey:@"addTabButtonPressedImage"];
[aCoder encodeObject:_addTabButtonRolloverImage forKey:@"addTabButtonRolloverImage"];
[aCoder encodeBool:_drawsUnified forKey:@"drawsUnified"];
[aCoder encodeBool:_drawsRight forKey:@"drawsRight"];
}
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ( (self = [super init]) ) {
if ([aDecoder allowsKeyedCoding]) {
_closeButton = [[aDecoder decodeObjectForKey:@"closeButton"] retain];
_closeButtonDown = [[aDecoder decodeObjectForKey:@"closeButtonDown"] retain];
_closeButtonOver = [[aDecoder decodeObjectForKey:@"closeButtonOver"] retain];
_closeDirtyButton = [[aDecoder decodeObjectForKey:@"closeDirtyButton"] retain];
_closeDirtyButtonDown = [[aDecoder decodeObjectForKey:@"closeDirtyButtonDown"] retain];
_closeDirtyButtonOver = [[aDecoder decodeObjectForKey:@"closeDirtyButtonOver"] retain];
_addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain];
_addTabButtonPressedImage = [[aDecoder decodeObjectForKey:@"addTabButtonPressedImage"] retain];
_addTabButtonRolloverImage = [[aDecoder decodeObjectForKey:@"addTabButtonRolloverImage"] retain];
_drawsUnified = [aDecoder decodeBoolForKey:@"drawsUnified"];
_drawsRight = [aDecoder decodeBoolForKey:@"drawsRight"];
}
}
return self;
}
@end
Something went wrong with that request. Please try again.