diff options
author | rowanbeentje <rowan@beent.je> | 2010-06-07 23:31:59 +0000 |
---|---|---|
committer | rowanbeentje <rowan@beent.je> | 2010-06-07 23:31:59 +0000 |
commit | 664c0e238ec9feb873cfabc6e5ab5e43213323f9 (patch) | |
tree | e7dbac121287ac3d6ec170c844aa159497189188 /Frameworks/PSMTabBar/Styles | |
parent | ceffd765f621e4ad1f9d4d6775c8e55d2f136bfb (diff) | |
download | sequelpro-664c0e238ec9feb873cfabc6e5ab5e43213323f9.tar.gz sequelpro-664c0e238ec9feb873cfabc6e5ab5e43213323f9.tar.bz2 sequelpro-664c0e238ec9feb873cfabc6e5ab5e43213323f9.zip |
- Replace the precompiled PSMTabBar framework with a build-from-source dependency, in preparation for future code and style changes
Diffstat (limited to 'Frameworks/PSMTabBar/Styles')
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMAdiumTabStyle.h | 39 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMAdiumTabStyle.m | 1057 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMAquaTabStyle.h | 38 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMAquaTabStyle.m | 579 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMCardTabStyle.h | 32 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMCardTabStyle.m | 649 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMMetalTabStyle.h | 34 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMMetalTabStyle.m | 656 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMUnifiedTabStyle.h | 30 | ||||
-rw-r--r-- | Frameworks/PSMTabBar/Styles/PSMUnifiedTabStyle.m | 603 |
10 files changed, 3717 insertions, 0 deletions
diff --git a/Frameworks/PSMTabBar/Styles/PSMAdiumTabStyle.h b/Frameworks/PSMTabBar/Styles/PSMAdiumTabStyle.h new file mode 100644 index 00000000..fac9a427 --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMAdiumTabStyle.h @@ -0,0 +1,39 @@ +// +// PSMAdiumTabStyle.h +// PSMTabBarControl +// +// Created by Kent Sutherland on 5/26/06. +// Copyright 2006 Kent Sutherland. All rights reserved. +// + +#import <Cocoa/Cocoa.h> +#import "PSMTabStyle.h" + +@interface PSMAdiumTabStyle : NSObject <PSMTabStyle> +{ + NSImage *_closeButton, *_closeButtonDown, *_closeButtonOver; + NSImage *_closeDirtyButton, *_closeDirtyButtonDown, *_closeDirtyButtonOver; + NSImage *_addTabButtonImage, *_addTabButtonPressedImage, *_addTabButtonRolloverImage; + NSImage *_gradientImage; + + NSDictionary *_objectCountStringAttributes; + + PSMTabBarOrientation orientation; + PSMTabBarControl *tabBar; + + BOOL _drawsUnified, _drawsRight; +} + +- (void)loadImages; + +- (BOOL)drawsUnified; +- (void)setDrawsUnified:(BOOL)value; +- (BOOL)drawsRight; +- (void)setDrawsRight:(BOOL)value; + +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView; + +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; + +@end diff --git a/Frameworks/PSMTabBar/Styles/PSMAdiumTabStyle.m b/Frameworks/PSMTabBar/Styles/PSMAdiumTabStyle.m new file mode 100644 index 00000000..be5cf82d --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMAdiumTabStyle.m @@ -0,0 +1,1057 @@ +// +// 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 + +- (CGFloat)leftMarginForTabBarControl +{ + return 3.0f; +} + +- (CGFloat)rightMarginForTabBarControl +{ + return 24.0f; +} + +- (CGFloat)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; + CGFloat 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; +} + +- (CGFloat)minimumWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat 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); +} + +- (CGFloat)desiredWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat 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); +} + +- (CGFloat)tabCellHeight +{ + return ((orientation == PSMTabBarHorizontalOrientation) ? kPSMTabBarControlHeight : kPSMTabBarControlSourceListHeight); +} + +#pragma mark - +#pragma mark Cell Values + +- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell +{ + NSString *contents = [NSString stringWithFormat:@"%lu", (unsigned long)[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 + +- (CGFloat)heightOfAttributedString:(NSAttributedString *)inAttributedString withWidth:(CGFloat)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 doubleValue]; + 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]; + + CGFloat height = [layoutManager usedRectForTextContainer:textContainer].size.height; + + [textStorage release]; + [textContainer release]; + [layoutManager release]; + + [cache setObject:[NSNumber numberWithDouble: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:(CGFloat)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. + CGFloat 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: + { + CGFloat 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 + CGFloat 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 release]; + tabBar = [bar retain]; + } + + [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 diff --git a/Frameworks/PSMTabBar/Styles/PSMAquaTabStyle.h b/Frameworks/PSMTabBar/Styles/PSMAquaTabStyle.h new file mode 100644 index 00000000..d3448e41 --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMAquaTabStyle.h @@ -0,0 +1,38 @@ +// +// PSMAquaTabStyle.h +// PSMTabBarControl +// +// Created by John Pannell on 2/17/06. +// Copyright 2006 Positive Spin Media. All rights reserved. +// + +#import <Cocoa/Cocoa.h> +#import "PSMTabStyle.h" + +@interface PSMAquaTabStyle : NSObject <PSMTabStyle> { + NSImage *aquaTabBg; + NSImage *aquaTabBgDown; + NSImage *aquaTabBgDownGraphite; + NSImage *aquaTabBgDownNonKey; + NSImage *aquaDividerDown; + NSImage *aquaDivider; + NSImage *aquaCloseButton; + NSImage *aquaCloseButtonDown; + NSImage *aquaCloseButtonOver; + NSImage *aquaCloseDirtyButton; + NSImage *aquaCloseDirtyButtonDown; + NSImage *aquaCloseDirtyButtonOver; + NSImage *_addTabButtonImage; + NSImage *_addTabButtonPressedImage; + NSImage *_addTabButtonRolloverImage; + + NSDictionary *_objectCountStringAttributes; + PSMTabBarControl *tabBar; +} + +- (void)loadImages; +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView; + +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; +@end diff --git a/Frameworks/PSMTabBar/Styles/PSMAquaTabStyle.m b/Frameworks/PSMTabBar/Styles/PSMAquaTabStyle.m new file mode 100644 index 00000000..f2618fe5 --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMAquaTabStyle.m @@ -0,0 +1,579 @@ +// +// PSMAquaTabStyle.m +// PSMTabBarControl +// +// Created by John Pannell on 2/17/06. +// Copyright 2006 Positive Spin Media. All rights reserved. +// + +#import "PSMAquaTabStyle.h" +#import "PSMTabBarCell.h" +#import "PSMTabBarControl.h" + +#define kPSMAquaObjectCounterRadius 7.0 +#define kPSMAquaCounterMinWidth 20 + +@implementation PSMAquaTabStyle + +- (NSString *)name +{ + return @"Aqua"; +} + +#pragma mark - +#pragma mark Creation/Destruction + +- (id) init +{ + if ( (self = [super init]) ) { + [self loadImages]; + + _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 +{ + // Aqua Tabs Images + aquaTabBg = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabsBackground"]]; + [aquaTabBg setFlipped:YES]; + + aquaTabBgDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabsDown"]]; + [aquaTabBgDown setFlipped:YES]; + + aquaTabBgDownGraphite = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabsDownGraphite"]]; + [aquaTabBgDown setFlipped:YES]; + + aquaTabBgDownNonKey = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabsDownNonKey"]]; + [aquaTabBgDown setFlipped:YES]; + + aquaDividerDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabsSeparatorDown"]]; + [aquaDivider setFlipped:NO]; + + aquaDivider = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabsSeparator"]]; + [aquaDivider setFlipped:NO]; + + aquaCloseButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front"]]; + aquaCloseButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Pressed"]]; + aquaCloseButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Rollover"]]; + + aquaCloseDirtyButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front"]]; + aquaCloseDirtyButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front_Pressed"]]; + aquaCloseDirtyButtonOver = [[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"]]; +} + +- (void)dealloc +{ + [aquaTabBg release]; + [aquaTabBgDown release]; + [aquaDividerDown release]; + [aquaDivider release]; + [aquaCloseButton release]; + [aquaCloseButtonDown release]; + [aquaCloseButtonOver release]; + [aquaCloseDirtyButton release]; + [aquaCloseDirtyButtonDown release]; + [aquaCloseDirtyButtonOver release]; + [_addTabButtonImage release]; + [_addTabButtonPressedImage release]; + [_addTabButtonRolloverImage release]; + + [_objectCountStringAttributes release]; + + [super dealloc]; +} + +#pragma mark - +#pragma mark Control Specifics + +- (CGFloat)leftMarginForTabBarControl +{ + return 0.0f; +} + +- (CGFloat)rightMarginForTabBarControl +{ + return 24.0f; +} + +- (CGFloat)topMarginForTabBarControl +{ + return 0.0f; +} + +- (void)setOrientation:(PSMTabBarOrientation)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 Specifics + +- (NSRect)dragRectForTabCell:(PSMTabBarCell *)cell orientation:(PSMTabBarOrientation)orientation +{ + return [cell frame]; +} + +- (NSRect)closeButtonRectForTabCell:(PSMTabBarCell *)cell withFrame:(NSRect)cellFrame +{ + if ([cell hasCloseButton] == NO) { + return NSZeroRect; + } + + NSRect result; + result.size = [aquaCloseButton size]; + result.origin.x = cellFrame.origin.x + MARGIN_X; + result.origin.y = cellFrame.origin.y + MARGIN_Y + 2.0; + + return result; +} + +- (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + if ([cell hasIcon] == NO) { + return NSZeroRect; + } + + NSRect result; + result.size = NSMakeSize(kPSMTabBarIconWidth, kPSMTabBarIconWidth); + result.origin.x = cellFrame.origin.x + MARGIN_X; + result.origin.y = cellFrame.origin.y + MARGIN_Y; + + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + result.origin.x += [aquaCloseButton size].width + kPSMTabBarCellPadding; + } + + 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 - MARGIN_X - kPSMTabBarIndicatorWidth; + result.origin.y = cellFrame.origin.y + MARGIN_Y; + + return result; +} + +- (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + if ([cell count] == 0) { + return NSZeroRect; + } + + CGFloat countWidth = [[self attributedObjectCountValueForTabCell:cell] size].width; + countWidth += (2 * kPSMAquaObjectCounterRadius - 6.0); + if (countWidth < kPSMAquaCounterMinWidth) { + countWidth = kPSMAquaCounterMinWidth; + } + + NSRect result; + result.size = NSMakeSize(countWidth, 2 * kPSMAquaObjectCounterRadius); // temp + result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - result.size.width; + result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0; + + if (![[cell indicator] isHidden]) { + result.origin.x -= kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding; + } + + return result; +} + +- (CGFloat)minimumWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat resultWidth = 0.0; + + // left margin + resultWidth = MARGIN_X; + + // close button? + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) + resultWidth += [aquaCloseButton size].width + kPSMTabBarCellPadding; + + // icon? + if ([cell hasIcon]) { + resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding; + } + + // the label + resultWidth += kPSMMinimumTitleWidth; + + // object counter? + if ([cell count] > 0) { + resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding; + } + + // indicator? + if ([[cell indicator] isHidden] == NO) { + resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth; + } + + // right margin + resultWidth += MARGIN_X; + + return ceil(resultWidth); +} + +- (CGFloat)desiredWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat resultWidth = 0.0; + + // left margin + resultWidth = MARGIN_X; + + // close button? + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + resultWidth += [aquaCloseButton size].width + kPSMTabBarCellPadding; + } + + // icon? + if ([cell hasIcon]) { + resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding; + } + + // the label + resultWidth += [[cell attributedStringValue] size].width; + + // object counter? + if ([cell count] > 0) { + resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding; + } + + // indicator? + if ([[cell indicator] isHidden] == NO) { + resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth; + } + + // right margin + resultWidth += MARGIN_X; + + return ceil(resultWidth); +} + +- (CGFloat)tabCellHeight +{ + return kPSMTabBarControlHeight; +} + +#pragma mark - +#pragma mark Cell Values + +- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell +{ + NSString *contents = [NSString stringWithFormat:@"%lu", (unsigned long)[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]); + + [attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] range:range]; + + // Paragraph Style for Truncating Long Text + static NSMutableParagraphStyle *TruncatingTailParagraphStyle = nil; + if (!TruncatingTailParagraphStyle) { + TruncatingTailParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain]; + [TruncatingTailParagraphStyle setLineBreakMode:NSLineBreakByTruncatingTail]; + [TruncatingTailParagraphStyle setAlignment:NSCenterTextAlignment]; + } + [attrStr addAttribute:NSParagraphStyleAttributeName value:TruncatingTailParagraphStyle range:range]; + + return attrStr; +} + +#pragma mark - +#pragma mark Drawing + +- (void)drawTabCell:(PSMTabBarCell *)cell; +{ + NSRect cellFrame = [cell frame]; + + // Selected Tab + if ([cell state] == NSOnState) { + NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height-2.5); + aRect.size.height -= 0.5; + + // proper tint + NSControlTint currentTint; + if ([cell controlTint] == NSDefaultControlTint) + currentTint = [NSColor currentControlTint]; + else + currentTint = [cell controlTint]; + + if (![[[cell controlView] window] isKeyWindow]) + currentTint = NSClearControlTint; + + NSImage *bgImage; + switch (currentTint) { + case NSGraphiteControlTint: + bgImage = aquaTabBgDownGraphite; + break; + case NSClearControlTint: + bgImage = aquaTabBgDownNonKey; + break; + case NSBlueControlTint: + default: + bgImage = aquaTabBgDown; + break; + } + + [bgImage drawInRect:cellFrame fromRect:NSMakeRect(0.0, 0.0, 1.0, 22.0) operation:NSCompositeSourceOver fraction:1.0]; + [aquaDivider compositeToPoint:NSMakePoint(cellFrame.origin.x + cellFrame.size.width - 1.0, cellFrame.origin.y + cellFrame.size.height) operation:NSCompositeSourceOver]; + + aRect.size.height+=0.5; + + } else { // Unselected Tab + + NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height); + aRect.origin.y += 0.5; + aRect.origin.x += 1.5; + aRect.size.width -= 1; + + aRect.origin.x -= 1; + aRect.size.width += 1; + + // Rollover + if ([cell isHighlighted]) { + [[NSColor colorWithCalibratedWhite:0.0 alpha:0.1] set]; + NSRectFillUsingOperation(aRect, NSCompositeSourceAtop); + } + + [aquaDivider compositeToPoint:NSMakePoint(cellFrame.origin.x + cellFrame.size.width - 1.0, cellFrame.origin.y + cellFrame.size.height) operation:NSCompositeSourceOver]; + } + + [self drawInteriorWithTabCell:cell inView:[cell controlView]]; +} + +- (void)drawBackgroundInRect:(NSRect)rect +{ + if (rect.size.height <= 22.0) { + //Draw for our whole bounds; it'll be automatically clipped to fit the appropriate drawing area + rect = [tabBar bounds]; + + [aquaTabBg drawInRect:rect fromRect:NSMakeRect(0.0, 0.0, 1.0, 22.0) operation:NSCompositeSourceOver fraction:1.0]; + } +} + +- (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect +{ + 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]; + } + } +} + +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView +{ + NSRect cellFrame = [cell frame]; + CGFloat labelPosition = cellFrame.origin.x + MARGIN_X; + + // close button + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + NSSize closeButtonSize = NSZeroSize; + NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame]; + NSImage *closeButton = nil; + + closeButton = [cell isEdited] ? aquaCloseDirtyButton : aquaCloseButton; + + if ([cell closeButtonOver]) closeButton = [cell isEdited] ? aquaCloseDirtyButtonOver : aquaCloseButtonOver; + if ([cell closeButtonPressed]) closeButton = [cell isEdited] ? aquaCloseDirtyButtonDown : aquaCloseButtonDown; + + closeButtonSize = [closeButton size]; + + if ([controlView isFlipped]) { + closeButtonRect.origin.y += closeButtonRect.size.height; + } + + [closeButton compositeToPoint:closeButtonRect.origin operation:NSCompositeSourceOver fraction:1.0]; + + // scoot label over + labelPosition += closeButtonSize.width + kPSMTabBarCellPadding; + } + + // icon + if ([cell hasIcon]) { + NSRect iconRect = [self iconRectForTabCell:cell]; + NSImage *icon = [[[cell representedObject] identifier] icon]; + if ([controlView isFlipped]) { + iconRect.origin.y += iconRect.size.height; + } + + // center in available space (in case icon image is smaller than kPSMTabBarIconWidth) + if ([icon size].width < kPSMTabBarIconWidth) { + iconRect.origin.x += (kPSMTabBarIconWidth - [icon size].width) / 2.0; + } + + if ([icon size].height < kPSMTabBarIconWidth) { + iconRect.origin.y -= (kPSMTabBarIconWidth - [icon size].height) / 2.0; + } + + [icon compositeToPoint:iconRect.origin operation:NSCompositeSourceOver fraction:1.0]; + + // scoot label over + labelPosition += iconRect.size.width + kPSMTabBarCellPadding; + } + + // label rect + NSRect labelRect; + labelRect.origin.x = labelPosition; + labelRect.size.width = cellFrame.size.width - (labelRect.origin.x - cellFrame.origin.x) - kPSMTabBarCellPadding; + labelRect.size.height = cellFrame.size.height; + labelRect.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0; + + if (![[cell indicator] isHidden]) { + labelRect.size.width -= (kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding); + } + + // object counter + if ([cell count] > 0) { + [[cell countColor] ?: [NSColor colorWithCalibratedWhite:0.3 alpha:0.45] set]; + NSBezierPath *path = [NSBezierPath bezierPath]; + NSRect myRect = [self objectCounterRectForTabCell:cell]; + [path moveToPoint:NSMakePoint(myRect.origin.x + kPSMAquaObjectCounterRadius, myRect.origin.y)]; + [path lineToPoint:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMAquaObjectCounterRadius, myRect.origin.y)]; + [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMAquaObjectCounterRadius, myRect.origin.y + kPSMAquaObjectCounterRadius) radius:kPSMAquaObjectCounterRadius startAngle:270.0 endAngle:90.0]; + [path lineToPoint:NSMakePoint(myRect.origin.x + kPSMAquaObjectCounterRadius, myRect.origin.y + myRect.size.height)]; + [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + kPSMAquaObjectCounterRadius, myRect.origin.y + kPSMAquaObjectCounterRadius) radius:kPSMAquaObjectCounterRadius 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]; + + labelRect.size.width -= myRect.size.width + kPSMTabBarCellPadding; + } + + // Draw Label + [[cell attributedStringValue] drawInRect:labelRect]; +} + +#pragma mark - +#pragma mark Archiving + +- (void)encodeWithCoder:(NSCoder *)aCoder { + + //[super encodeWithCoder:aCoder]; +/* + if ([aCoder allowsKeyedCoding]) { + [aCoder encodeObject:aquaTabBg forKey:@"aquaTabBg"]; + [aCoder encodeObject:aquaTabBgDown forKey:@"aquaTabBgDown"]; + [aCoder encodeObject:aquaTabBgDownGraphite forKey:@"aquaTabBgDownGraphite"]; + [aCoder encodeObject:aquaTabBgDownNonKey forKey:@"aquaTabBgDownNonKey"]; + [aCoder encodeObject:aquaDividerDown forKey:@"aquaDividerDown"]; + [aCoder encodeObject:aquaDivider forKey:@"aquaDivider"]; + [aCoder encodeObject:aquaCloseButton forKey:@"aquaCloseButton"]; + [aCoder encodeObject:aquaCloseButtonDown forKey:@"aquaCloseButtonDown"]; + [aCoder encodeObject:aquaCloseButtonOver forKey:@"aquaCloseButtonOver"]; + [aCoder encodeObject:aquaCloseDirtyButton forKey:@"aquaCloseDirtyButton"]; + [aCoder encodeObject:aquaCloseDirtyButtonDown forKey:@"aquaCloseDirtyButtonDown"]; + [aCoder encodeObject:aquaCloseDirtyButtonOver forKey:@"aquaCloseDirtyButtonOver"]; + [aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"]; + [aCoder encodeObject:_addTabButtonPressedImage forKey:@"addTabButtonPressedImage"]; + [aCoder encodeObject:_addTabButtonRolloverImage forKey:@"addTabButtonRolloverImage"]; + } + */ +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + + self = [self init]; + if (self) { +/* + if ([aDecoder allowsKeyedCoding]) { + aquaTabBg = [[aDecoder decodeObjectForKey:@"aquaTabBg"] retain]; + aquaTabBgDown = [[aDecoder decodeObjectForKey:@"aquaTabBgDown"] retain]; + aquaTabBgDownGraphite = [[aDecoder decodeObjectForKey:@"aquaTabBgDownGraphite"] retain]; + aquaTabBgDownNonKey = [[aDecoder decodeObjectForKey:@"aquaTabBgDownNonKey"] retain]; + aquaDividerDown = [[aDecoder decodeObjectForKey:@"aquaDividerDown"] retain]; + aquaDivider = [[aDecoder decodeObjectForKey:@"aquaDivider"] retain]; + aquaCloseButton = [[aDecoder decodeObjectForKey:@"aquaCloseButton"] retain]; + aquaCloseButtonDown = [[aDecoder decodeObjectForKey:@"aquaCloseButtonDown"] retain]; + aquaCloseButtonOver = [[aDecoder decodeObjectForKey:@"aquaCloseButtonOver"] retain]; + aquaCloseDirtyButton = [[aDecoder decodeObjectForKey:@"aquaCloseDirtyButton"] retain]; + aquaCloseDirtyButtonDown = [[aDecoder decodeObjectForKey:@"aquaCloseDirtyButtonDown"] retain]; + aquaCloseDirtyButtonOver = [[aDecoder decodeObjectForKey:@"aquaCloseDirtyButtonOver"] retain]; + _addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain]; + _addTabButtonPressedImage = [[aDecoder decodeObjectForKey:@"addTabButtonPressedImage"] retain]; + _addTabButtonRolloverImage = [[aDecoder decodeObjectForKey:@"addTabButtonRolloverImage"] retain]; + + } +*/ + } + return self; +} + +@end diff --git a/Frameworks/PSMTabBar/Styles/PSMCardTabStyle.h b/Frameworks/PSMTabBar/Styles/PSMCardTabStyle.h new file mode 100644 index 00000000..b04f83d1 --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMCardTabStyle.h @@ -0,0 +1,32 @@ +// +// PSMCardTabStyle.h +// Fichiers +// +// Created by Michael Monscheuer on 05.11.09. +// Copyright 2009 WriteFlow KG, Wien. All rights reserved. +// + +#import <Cocoa/Cocoa.h> +#import "PSMTabStyle.h" + +@interface PSMCardTabStyle : NSObject <PSMTabStyle> +{ + NSImage *unifiedCloseButton; + NSImage *unifiedCloseButtonDown; + NSImage *unifiedCloseButtonOver; + NSImage *unifiedCloseDirtyButton; + NSImage *unifiedCloseDirtyButtonDown; + NSImage *unifiedCloseDirtyButtonOver; + NSImage *_addTabButtonImage; + NSImage *_addTabButtonPressedImage; + NSImage *_addTabButtonRolloverImage; + + NSDictionary *_objectCountStringAttributes; + + CGFloat leftMargin; + PSMTabBarControl *tabBar; +} + +- (void)setLeftMarginForTabBarControl:(CGFloat)margin; + +@end diff --git a/Frameworks/PSMTabBar/Styles/PSMCardTabStyle.m b/Frameworks/PSMTabBar/Styles/PSMCardTabStyle.m new file mode 100644 index 00000000..31da000c --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMCardTabStyle.m @@ -0,0 +1,649 @@ +// +// PSMCardTabStyle.m +// Fichiers +// +// Created by Michael Monscheuer on 05.11.09. +// Copyright 2009 WriteFlow KG, Wien. All rights reserved. +// + +#import "PSMCardTabStyle.h" +#import "PSMTabBarCell.h" +#import "PSMTabBarControl.h" +#import "NSBezierPath_AMShading.h" + +#define kPSMUnifiedObjectCounterRadius 7.0 +#define kPSMUnifiedCounterMinWidth 20 + +@interface PSMCardTabStyle (Private) +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView; +@end + +@implementation PSMCardTabStyle + +- (NSString *)name +{ + return @"Card"; +} + +#pragma mark - +#pragma mark Creation/Destruction + +- (id) init +{ + if ( (self = [super init]) ) { + unifiedCloseButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front"]]; + unifiedCloseButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Pressed"]]; + unifiedCloseButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Rollover"]]; + + unifiedCloseDirtyButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front"]]; + unifiedCloseDirtyButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front_Pressed"]]; + unifiedCloseDirtyButtonOver = [[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"]]; + + _objectCountStringAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:[[NSFontManager sharedFontManager] convertFont:[NSFont fontWithName:@"Helvetica" size:11.0] toHaveTrait:NSBoldFontMask], NSFontAttributeName, + [[NSColor whiteColor] colorWithAlphaComponent:0.85], NSForegroundColorAttributeName, + nil, nil]; + + leftMargin = 5.0; + } + return self; +} + +- (void)dealloc +{ + [unifiedCloseButton release]; + [unifiedCloseButtonDown release]; + [unifiedCloseButtonOver release]; + [unifiedCloseDirtyButton release]; + [unifiedCloseDirtyButtonDown release]; + [unifiedCloseDirtyButtonOver release]; + [_addTabButtonImage release]; + [_addTabButtonPressedImage release]; + [_addTabButtonRolloverImage release]; + + [_objectCountStringAttributes release]; + + [super dealloc]; +} + +#pragma mark - +#pragma mark Control Specific + +- (void)setLeftMarginForTabBarControl:(CGFloat)margin +{ + leftMargin = margin; +} + +- (CGFloat)leftMarginForTabBarControl +{ + return leftMargin; +} + +- (CGFloat)rightMarginForTabBarControl +{ + return 5.0f; +// return 24.0f; +} + +- (CGFloat)topMarginForTabBarControl +{ + return 10.0f; +} + +- (void)setOrientation:(PSMTabBarOrientation)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)orientation +{ + NSRect dragRect = [cell frame]; + dragRect.size.width++; + return dragRect; +} + +- (NSRect)closeButtonRectForTabCell:(PSMTabBarCell *)cell withFrame:(NSRect)cellFrame +{ + if ([cell hasCloseButton] == NO || [cell isCloseButtonSuppressed]) { + return NSZeroRect; + } + + NSRect result; + result.size = [unifiedCloseButton size]; + result.origin.x = cellFrame.origin.x + MARGIN_X; + result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0; + + return result; +} + +- (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + if ([cell hasIcon] == NO) { + return NSZeroRect; + } + + NSRect result; + result.size = NSMakeSize(kPSMTabBarIconWidth, kPSMTabBarIconWidth); + result.origin.x = cellFrame.origin.x + MARGIN_X; + result.origin.y = cellFrame.origin.y + MARGIN_Y - 1.0; + + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + result.origin.x += [unifiedCloseButton size].width + kPSMTabBarCellPadding; + } + + 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 - MARGIN_X - kPSMTabBarIndicatorWidth; + result.origin.y = cellFrame.origin.y + MARGIN_Y - 1.0; + + return result; +} + +- (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + if ([cell count] == 0) { + return NSZeroRect; + } + + CGFloat countWidth = [[self attributedObjectCountValueForTabCell:cell] size].width; + countWidth += (2 * kPSMUnifiedObjectCounterRadius - 6.0); + if (countWidth < kPSMUnifiedCounterMinWidth) { + countWidth = kPSMUnifiedCounterMinWidth; + } + + NSRect result; + result.size = NSMakeSize(countWidth, 2 * kPSMUnifiedObjectCounterRadius); // temp + result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - result.size.width; + result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0; + + if (![[cell indicator] isHidden]) { + result.origin.x -= kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding; + } + + return result; +} + + +- (CGFloat)minimumWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat resultWidth = 0.0; + + // left margin + resultWidth = MARGIN_X; + + // close button? + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + resultWidth += [unifiedCloseButton size].width + kPSMTabBarCellPadding; + } + + // icon? + if ([cell hasIcon]) { + resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding; + } + + // the label + resultWidth += kPSMMinimumTitleWidth; + + // object counter? + if ([cell count] > 0) { + resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding; + } + + // indicator? + if ([[cell indicator] isHidden] == NO) + resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth; + + // right margin + resultWidth += MARGIN_X; + + return ceil(resultWidth); +} + +- (CGFloat)desiredWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat resultWidth = 0.0; + + // left margin + resultWidth = MARGIN_X; + + // close button? + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) + resultWidth += [unifiedCloseButton size].width + kPSMTabBarCellPadding; + + // icon? + if ([cell hasIcon]) { + resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding; + } + + // the label + resultWidth += [[cell attributedStringValue] size].width; + + // object counter? + if ([cell count] > 0) { + resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding; + } + + // indicator? + if ([[cell indicator] isHidden] == NO) + resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth; + + // right margin + resultWidth += MARGIN_X; + + return ceil(resultWidth); +} + +- (CGFloat)tabCellHeight +{ + return kPSMTabBarControlHeight; +} + +#pragma mark - +#pragma mark Cell Values + +- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell +{ + NSString *contents = [NSString stringWithFormat:@"%lu", (unsigned long)[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]); + + [attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] 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 ---- drawing ---- + +- (void)drawTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + BOOL showsBaselineSeparator = NO; +/* + NSToolbar *toolbar = [[[cell controlView] window] toolbar]; + BOOL showsBaselineSeparator = (toolbar && [toolbar respondsToSelector:@selector(showsBaselineSeparator)] && [toolbar showsBaselineSeparator]); +*/ + if (!showsBaselineSeparator) { + cellFrame.origin.y += 3.0; + cellFrame.size.height -= 3.0; + } + + + NSColor * lineColor = nil; + NSBezierPath* bezier = [NSBezierPath bezierPath]; + lineColor = [NSColor colorWithCalibratedWhite:0.576 alpha:1.0]; + + if (!showsBaselineSeparator || [cell state] == NSOnState) + { +// // selected tab +// NSRect aRect = NSMakeRect(cellFrame.origin.x+0.5, cellFrame.origin.y-0.5, cellFrame.size.width, cellFrame.size.height); + // selected tab + NSRect aRect = NSMakeRect(cellFrame.origin.x+.5, cellFrame.origin.y+0.5, cellFrame.size.width-1.0, cellFrame.size.height-1.0); + + // frame + CGFloat radius = MIN(6.0, 0.5f * MIN(NSWidth(aRect), NSHeight(aRect)))-0.5; +// NSRect rect = NSInsetRect(aRect, radius, radius); + + [bezier moveToPoint: NSMakePoint(NSMinX(aRect),NSMaxY(aRect))]; + [bezier appendBezierPathWithArcFromPoint:NSMakePoint(NSMinX(aRect),NSMinY(aRect)) toPoint:NSMakePoint(NSMidX(aRect),NSMinY(aRect)) radius:radius]; + [bezier appendBezierPathWithArcFromPoint:NSMakePoint(NSMaxX(aRect),NSMinY(aRect)) toPoint:NSMakePoint(NSMaxX(aRect),NSMaxY(aRect)) radius:radius]; + [bezier lineToPoint: NSMakePoint(NSMaxX(aRect),NSMaxY(aRect))]; + +/* + [bezier appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMinY(rect)) radius:radius startAngle:180.0 endAngle:270.0]; + + [bezier appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMinY(rect)) radius:radius startAngle:270.0 endAngle:360.0]; + + NSPoint cornerPoint = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect)); + [bezier appendBezierPathWithPoints:&cornerPoint count:1]; + + cornerPoint = NSMakePoint(NSMinX(aRect), NSMaxY(aRect)); + [bezier appendBezierPathWithPoints:&cornerPoint count:1]; + + [bezier closePath]; +*/ + + //[[NSColor windowBackgroundColor] set]; + //[bezier fill]; + if ([NSApp isActive]) { + if ([cell state] == NSOnState) { + [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.99 alpha:1.0] + endColor:[NSColor colorWithCalibratedWhite:0.941 alpha:1.0]]; + } else if ([cell isHighlighted]) { + [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.80 alpha:1.0] + endColor:[NSColor colorWithCalibratedWhite:0.80 alpha:1.0]]; + } else { + [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0] + endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]]; + } + } + + [lineColor set]; + [bezier stroke]; + + } + else + { + // unselected tab + NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height); + aRect.origin.y += 0.5; + aRect.origin.x += 1.5; + aRect.size.width -= 1; + + aRect.origin.x -= 1; + aRect.size.width += 1; + + // rollover + if ([cell isHighlighted]) + { + [[NSColor colorWithCalibratedWhite:0.0 alpha:0.1] set]; + NSRectFillUsingOperation(aRect, NSCompositeSourceAtop); + } + + // frame + + [lineColor set]; + [bezier moveToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y-0.5)]; + if (!([cell tabState] & PSMTab_RightIsSelectedMask)) { + [bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMaxY(aRect))]; + } + + [bezier stroke]; + + // Create a thin lighter line next to the dividing line for a bezel effect + if (!([cell tabState] & PSMTab_RightIsSelectedMask)) { + [[[NSColor redColor] colorWithAlphaComponent:0.5] set]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMaxX(aRect)+1.0, aRect.origin.y-0.5) + toPoint:NSMakePoint(NSMaxX(aRect)+1.0, NSMaxY(aRect)-2.5)]; + } + + // If this is the leftmost tab, we want to draw a line on the left, too + if ([cell tabState] & PSMTab_PositionLeftMask) + { + [lineColor set]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(aRect.origin.x,aRect.origin.y-0.5) + toPoint:NSMakePoint(aRect.origin.x,NSMaxY(aRect)-2.5)]; + [[[NSColor redColor] colorWithAlphaComponent:0.5] set]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(aRect.origin.x+1.0,aRect.origin.y-0.5) + toPoint:NSMakePoint(aRect.origin.x+1.0,NSMaxY(aRect)-2.5)]; + } + } + + [self drawInteriorWithTabCell:cell inView:[cell controlView]]; +} + + +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView +{ + NSRect cellFrame = [cell frame]; + + BOOL showsBaselineSeparator = NO; +/* + NSToolbar *toolbar = [[[cell controlView] window] toolbar]; + BOOL showsBaselineSeparator = (toolbar && [toolbar respondsToSelector:@selector(showsBaselineSeparator)] && [toolbar showsBaselineSeparator]); +*/ + if (!showsBaselineSeparator) { + cellFrame.origin.y += 3.0; + cellFrame.size.height -= 3.0; + } + + CGFloat labelPosition = cellFrame.origin.x + MARGIN_X; + + // close button + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + NSSize closeButtonSize = NSZeroSize; + NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame]; + NSImage * closeButton = nil; + + closeButton = [cell isEdited] ? unifiedCloseDirtyButton : unifiedCloseButton; + + if ([cell closeButtonOver]) closeButton = [cell isEdited] ? unifiedCloseDirtyButtonOver : unifiedCloseButtonOver; + if ([cell closeButtonPressed]) closeButton = [cell isEdited] ? unifiedCloseDirtyButtonDown : unifiedCloseButtonDown; + + closeButtonSize = [closeButton size]; + if ([controlView isFlipped]) { + closeButtonRect.origin.y += closeButtonRect.size.height; + } + + [closeButton compositeToPoint:closeButtonRect.origin operation:NSCompositeSourceOver fraction:1.0]; + + // scoot label over + labelPosition += closeButtonSize.width + kPSMTabBarCellPadding; + } + + // icon + if ([cell hasIcon]) { + NSRect iconRect = [self iconRectForTabCell:cell]; + NSImage *icon = [[[cell representedObject] identifier] icon]; + if ([controlView isFlipped]) { + iconRect.origin.y += iconRect.size.height; + } + + // center in available space (in case icon image is smaller than kPSMTabBarIconWidth) + if ([icon size].width < kPSMTabBarIconWidth) { + iconRect.origin.x += (kPSMTabBarIconWidth - [icon size].width) / 2.0; + } + if ([icon size].height < kPSMTabBarIconWidth) { + iconRect.origin.y -= (kPSMTabBarIconWidth - [icon size].height) / 2.0; + } + + [icon compositeToPoint:iconRect.origin operation:NSCompositeSourceOver fraction:1.0]; + + // scoot label over + labelPosition += iconRect.size.width + kPSMTabBarCellPadding; + } + + // label rect + NSRect labelRect; + labelRect.origin.x = labelPosition; + labelRect.size.width = cellFrame.size.width - (labelRect.origin.x - cellFrame.origin.x) - kPSMTabBarCellPadding; + NSSize s = [[cell attributedStringValue] size]; + labelRect.origin.y = cellFrame.origin.y + (cellFrame.size.height-s.height)/2 + 1; + labelRect.size.height = s.height; + + if (![[cell indicator] isHidden]) { + labelRect.size.width -= (kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding); + } + + // object counter + if ([cell count] > 0) { + [[cell countColor] ?: [NSColor colorWithCalibratedWhite:0.3 alpha:0.6] set]; + NSBezierPath *path = [NSBezierPath bezierPath]; + NSRect myRect = [self objectCounterRectForTabCell:cell]; + myRect.origin.y -= 1.0; + [path moveToPoint:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y)]; + [path lineToPoint:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMUnifiedObjectCounterRadius, myRect.origin.y)]; + [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMUnifiedObjectCounterRadius, myRect.origin.y + kPSMUnifiedObjectCounterRadius) radius:kPSMUnifiedObjectCounterRadius startAngle:270.0 endAngle:90.0]; + [path lineToPoint:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y + myRect.size.height)]; + [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y + kPSMUnifiedObjectCounterRadius) radius:kPSMUnifiedObjectCounterRadius 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]; + + labelRect.size.width -= myRect.size.width + kPSMTabBarCellPadding; + } + + // label + [[cell attributedStringValue] drawInRect:labelRect]; +} + +- (void)drawBackgroundInRect:(NSRect)rect +{ + //Draw for our whole bounds; it'll be automatically clipped to fit the appropriate drawing area + rect = [tabBar bounds]; + + NSRect gradientRect = rect; + gradientRect.size.height -= 1.0; + + NSBezierPath *path = [NSBezierPath bezierPathWithRect:gradientRect]; + [path linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0] + endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]]; + [[NSColor colorWithCalibratedWhite:0.576 alpha:1.0] set]; + + + if (![[[tabBar tabView] window] isKeyWindow]) { + [[NSColor windowBackgroundColor] set]; + NSRectFill(gradientRect); + } +} + +- (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect +{ + [NSGraphicsContext saveGraphicsState]; + + // draw button separator + for(PSMTabBarCell *cell in [bar cells]) + { + if([cell state] == NSOnState) + { + [[NSColor colorWithCalibratedWhite:0.576 alpha:1.0] set]; + + [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x,NSMaxY(rect)-0.5) + toPoint:NSMakePoint(NSMinX([cell frame]),NSMaxY(rect)-0.5)]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMaxX([cell frame]),NSMaxY(rect)-0.5) + toPoint:NSMakePoint(NSMaxX(rect),NSMaxY(rect)-0.5)]; + } + } + + 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]; + [centeredParagraphStyle setAlignment:NSCenterTextAlignment]; + } + [attrStr addAttribute:NSParagraphStyleAttributeName value:centeredParagraphStyle range:range]; + [centeredParagraphStyle release]; + [attrStr drawInRect:labelRect]; + + goto EXIT; + } + + // 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]; + } + } + +EXIT: + [NSGraphicsContext restoreGraphicsState]; + +} + +#pragma mark - +#pragma mark Archiving + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ +/* + //[super encodeWithCoder:aCoder]; + if ([aCoder allowsKeyedCoding]) { + [aCoder encodeObject:unifiedCloseButton forKey:@"unifiedCloseButton"]; + [aCoder encodeObject:unifiedCloseButtonDown forKey:@"unifiedCloseButtonDown"]; + [aCoder encodeObject:unifiedCloseButtonOver forKey:@"unifiedCloseButtonOver"]; + [aCoder encodeObject:unifiedCloseDirtyButton forKey:@"unifiedCloseDirtyButton"]; + [aCoder encodeObject:unifiedCloseDirtyButtonDown forKey:@"unifiedCloseDirtyButtonDown"]; + [aCoder encodeObject:unifiedCloseDirtyButtonOver forKey:@"unifiedCloseDirtyButtonOver"]; + [aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"]; + [aCoder encodeObject:_addTabButtonPressedImage forKey:@"addTabButtonPressedImage"]; + [aCoder encodeObject:_addTabButtonRolloverImage forKey:@"addTabButtonRolloverImage"]; + } +*/ +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (self) { + /* + if ([aDecoder allowsKeyedCoding]) { + unifiedCloseButton = [[aDecoder decodeObjectForKey:@"unifiedCloseButton"] retain]; + unifiedCloseButtonDown = [[aDecoder decodeObjectForKey:@"unifiedCloseButtonDown"] retain]; + unifiedCloseButtonOver = [[aDecoder decodeObjectForKey:@"unifiedCloseButtonOver"] retain]; + unifiedCloseDirtyButton = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButton"] retain]; + unifiedCloseDirtyButtonDown = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButtonDown"] retain]; + unifiedCloseDirtyButtonOver = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButtonOver"] retain]; + _addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain]; + _addTabButtonPressedImage = [[aDecoder decodeObjectForKey:@"addTabButtonPressedImage"] retain]; + _addTabButtonRolloverImage = [[aDecoder decodeObjectForKey:@"addTabButtonRolloverImage"] retain]; + } + */ + } + return self; +} + +@end diff --git a/Frameworks/PSMTabBar/Styles/PSMMetalTabStyle.h b/Frameworks/PSMTabBar/Styles/PSMMetalTabStyle.h new file mode 100644 index 00000000..22cb7bc8 --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMMetalTabStyle.h @@ -0,0 +1,34 @@ +// +// PSMMetalTabStyle.h +// PSMTabBarControl +// +// Created by John Pannell on 2/17/06. +// Copyright 2006 Positive Spin Media. All rights reserved. +// + +#import <Cocoa/Cocoa.h> +#import "PSMTabStyle.h" + +@interface PSMMetalTabStyle : NSObject <PSMTabStyle> { + NSImage *metalCloseButton; + NSImage *metalCloseButtonDown; + NSImage *metalCloseButtonOver; + NSImage *metalCloseDirtyButton; + NSImage *metalCloseDirtyButtonDown; + NSImage *metalCloseDirtyButtonOver; + NSImage *_addTabButtonImage; + NSImage *_addTabButtonPressedImage; + NSImage *_addTabButtonRolloverImage; + + NSDictionary *_objectCountStringAttributes; + + PSMTabBarOrientation orientation; + PSMTabBarControl *tabBar; +} + +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView; + +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; + +@end diff --git a/Frameworks/PSMTabBar/Styles/PSMMetalTabStyle.m b/Frameworks/PSMTabBar/Styles/PSMMetalTabStyle.m new file mode 100644 index 00000000..443179ce --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMMetalTabStyle.m @@ -0,0 +1,656 @@ +// +// PSMMetalTabStyle.m +// PSMTabBarControl +// +// Created by John Pannell on 2/17/06. +// Copyright 2006 Positive Spin Media. All rights reserved. +// + +#import "PSMMetalTabStyle.h" +#import "PSMTabBarCell.h" +#import "PSMTabBarControl.h" + +#define kPSMMetalObjectCounterRadius 7.0 +#define kPSMMetalCounterMinWidth 20 + +@implementation PSMMetalTabStyle + +- (NSString *)name +{ + return @"Metal"; +} + +#pragma mark - +#pragma mark Creation/Destruction + +- (id) init +{ + if ( (self = [super init]) ) { + metalCloseButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Front"]]; + metalCloseButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Front_Pressed"]]; + metalCloseButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Front_Rollover"]]; + + metalCloseDirtyButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Dirty"]]; + metalCloseDirtyButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Dirty_Pressed"]]; + metalCloseDirtyButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Dirty_Rollover"]]; + + _addTabButtonImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabNewMetal"]]; + _addTabButtonPressedImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabNewMetalPressed"]]; + _addTabButtonRolloverImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabNewMetalRollover"]]; + + _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)dealloc +{ + [metalCloseButton release]; + [metalCloseButtonDown release]; + [metalCloseButtonOver release]; + [metalCloseDirtyButton release]; + [metalCloseDirtyButtonDown release]; + [metalCloseDirtyButtonOver release]; + [_addTabButtonImage release]; + [_addTabButtonPressedImage release]; + [_addTabButtonRolloverImage release]; + + [_objectCountStringAttributes release]; + + [super dealloc]; +} + +#pragma mark - +#pragma mark Control Specific + +- (CGFloat)leftMarginForTabBarControl +{ + return 10.0f; +} + +- (CGFloat)rightMarginForTabBarControl +{ + return 24.0f; +} + +- (CGFloat)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]; + dragRect.size.width++; + + if ([cell tabState] & PSMTab_SelectedMask) { + if (tabOrientation == PSMTabBarHorizontalOrientation) { + dragRect.size.height -= 2.0; + } else { + dragRect.size.height += 1.0; + dragRect.origin.y -= 1.0; + dragRect.origin.x += 2.0; + dragRect.size.width -= 3.0; + } + } else if (tabOrientation == PSMTabBarVerticalOrientation) { + dragRect.origin.x--; + } + + return dragRect; +} + +- (NSRect)closeButtonRectForTabCell:(PSMTabBarCell *)cell withFrame:(NSRect)cellFrame +{ + if ([cell hasCloseButton] == NO) { + return NSZeroRect; + } + + NSRect result; + result.size = [metalCloseButton size]; + result.origin.x = cellFrame.origin.x + MARGIN_X; + result.origin.y = cellFrame.origin.y + MARGIN_Y + 2.0; + + if ([cell state] == NSOnState) { + result.origin.y -= 1; + } + + return result; +} + +- (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + if ([cell hasIcon] == NO) { + return NSZeroRect; + } + + NSRect result; + result.size = NSMakeSize(kPSMTabBarIconWidth, kPSMTabBarIconWidth); + result.origin.x = cellFrame.origin.x + MARGIN_X; + result.origin.y = cellFrame.origin.y + MARGIN_Y; + + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + result.origin.x += [metalCloseButton size].width + kPSMTabBarCellPadding; + } + + 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 - MARGIN_X - kPSMTabBarIndicatorWidth; + result.origin.y = cellFrame.origin.y + MARGIN_Y; + + if ([cell state] == NSOnState) { + result.origin.y -= 1; + } + + return result; +} + +- (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + if ([cell count] == 0) { + return NSZeroRect; + } + + CGFloat countWidth = [[self attributedObjectCountValueForTabCell:cell] size].width; + countWidth += (2 * kPSMMetalObjectCounterRadius - 6.0); + if (countWidth < kPSMMetalCounterMinWidth) { + countWidth = kPSMMetalCounterMinWidth; + } + + NSRect result; + result.size = NSMakeSize(countWidth, 2 * kPSMMetalObjectCounterRadius); // temp + result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - result.size.width; + result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0; + + if (![[cell indicator] isHidden]) { + result.origin.x -= kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding; + } + + return result; +} + + +- (CGFloat)minimumWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat resultWidth = 0.0; + + // left margin + resultWidth = MARGIN_X; + + // close button? + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + resultWidth += [metalCloseButton size].width + kPSMTabBarCellPadding; + } + + // icon? + if ([cell hasIcon]) { + resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding; + } + + // the label + resultWidth += kPSMMinimumTitleWidth; + + // object counter? + if ([cell count] > 0) { + resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding; + } + + // indicator? + if ([[cell indicator] isHidden] == NO) + resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth; + + // right margin + resultWidth += MARGIN_X; + + return ceil(resultWidth); +} + +- (CGFloat)desiredWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat resultWidth = 0.0; + + // left margin + resultWidth = MARGIN_X; + + // close button? + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) + resultWidth += [metalCloseButton size].width + kPSMTabBarCellPadding; + + // icon? + if ([cell hasIcon]) { + resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding; + } + + // the label + resultWidth += [[cell attributedStringValue] size].width; + + // object counter? + if ([cell count] > 0) { + resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding; + } + + // indicator? + if ([[cell indicator] isHidden] == NO) + resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth; + + // right margin + resultWidth += MARGIN_X; + + return ceil(resultWidth); +} + +- (CGFloat)tabCellHeight +{ + return kPSMTabBarControlHeight; +} + +#pragma mark - +#pragma mark Cell Values + +- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell +{ + NSString *contents = [NSString stringWithFormat:@"%lu", (unsigned long)[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 boldSystemFontOfSize:11.0] range:range]; + [attrStr addAttribute:NSForegroundColorAttributeName value:[[NSColor textColor] colorWithAlphaComponent:0.75] range:range]; + + // Add shadow attribute + NSShadow* shadow; + shadow = [[[NSShadow alloc] init] autorelease]; + CGFloat shadowAlpha; + if (([cell state] == NSOnState) || [cell isHighlighted]) { + shadowAlpha = 0.8; + } else { + shadowAlpha = 0.5; + } + [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:shadowAlpha]]; + [shadow setShadowOffset:NSMakeSize(0, -1)]; + [shadow setShadowBlurRadius:1.0]; + [attrStr addAttribute:NSShadowAttributeName value:shadow range:range]; + + // Paragraph Style for Truncating Long Text + static NSMutableParagraphStyle *TruncatingTailParagraphStyle = nil; + if (!TruncatingTailParagraphStyle) { + TruncatingTailParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain]; + [TruncatingTailParagraphStyle setLineBreakMode:NSLineBreakByTruncatingTail]; + [TruncatingTailParagraphStyle setAlignment:NSCenterTextAlignment]; + } + [attrStr addAttribute:NSParagraphStyleAttributeName value:TruncatingTailParagraphStyle range:range]; + + return attrStr; +} + +#pragma mark - +#pragma mark ---- drawing ---- + +- (void)drawTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + NSColor *lineColor = nil; + NSBezierPath *bezier = [NSBezierPath bezierPath]; + lineColor = [NSColor darkGrayColor]; + + //disable antialiasing of bezier paths + [NSGraphicsContext saveGraphicsState]; + [[NSGraphicsContext currentContext] setShouldAntialias:NO]; + + if ([cell state] == NSOnState) { + // selected tab + if (orientation == PSMTabBarHorizontalOrientation) { + NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height-2.5); + + // background + aRect.origin.x += 1.0; + aRect.size.width--; + aRect.size.height -= 0.5; + NSDrawWindowBackground(aRect); + aRect.size.width++; + aRect.size.height += 0.5; + + // frame + aRect.origin.x -= 0.5; + [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-1.5)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x+1.5, aRect.origin.y+aRect.size.height)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width-2.5, aRect.origin.y+aRect.size.height)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width, aRect.origin.y+aRect.size.height-1.5)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width, aRect.origin.y)]; + 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)]; + } + } else { + NSRect aRect = NSMakeRect(cellFrame.origin.x + 2, cellFrame.origin.y, cellFrame.size.width - 2, cellFrame.size.height); + + // background + aRect.origin.x++; + aRect.size.height--; + NSDrawWindowBackground(aRect); + aRect.origin.x--; + aRect.size.height++; + + // frame + [lineColor set]; + [bezier setLineWidth:1.0]; + [bezier moveToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x + 2, aRect.origin.y)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x + 0.5, aRect.origin.y + 2)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x + 0.5, aRect.origin.y + aRect.size.height - 3)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x + 3, aRect.origin.y + aRect.size.height)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y + aRect.size.height)]; + } + + [bezier stroke]; + } else { + + // unselected tab + NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height); + aRect.origin.y += 0.5; + aRect.origin.x += 1.5; + aRect.size.width -= 1; + + // rollover + if ([cell isHighlighted]) { + [[NSColor colorWithCalibratedWhite:0.0 alpha:0.1] set]; + NSRectFillUsingOperation(aRect, NSCompositeSourceAtop); + } + + [lineColor set]; + + if (orientation == PSMTabBarHorizontalOrientation) { + aRect.origin.x -= 1; + aRect.size.width += 1; + + // frame + [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)) { + [bezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y + aRect.size.height)]; + } + } else { + if (!([cell tabState] & PSMTab_LeftIsSelectedMask)) { + [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)) { + [bezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y + aRect.size.height)]; + [bezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y + aRect.size.height)]; + } + } + [bezier stroke]; + } + + [NSGraphicsContext restoreGraphicsState]; + + [self drawInteriorWithTabCell:cell inView:[cell controlView]]; +} + + +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView +{ + NSRect cellFrame = [cell frame]; + CGFloat labelPosition = cellFrame.origin.x + MARGIN_X; + + // close button + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + NSSize closeButtonSize = NSZeroSize; + NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame]; + NSImage * closeButton = nil; + + closeButton = [cell isEdited] ? metalCloseDirtyButton : metalCloseButton; + if ([cell closeButtonOver]) closeButton = [cell isEdited] ? metalCloseDirtyButtonOver : metalCloseButtonOver; + if ([cell closeButtonPressed]) closeButton = [cell isEdited] ? metalCloseDirtyButtonDown : metalCloseButtonDown; + + closeButtonSize = [closeButton size]; + if ([controlView isFlipped]) { + closeButtonRect.origin.y += closeButtonRect.size.height; + } + + [closeButton compositeToPoint:closeButtonRect.origin operation:NSCompositeSourceOver fraction:1.0]; + + // scoot label over + labelPosition += closeButtonSize.width + kPSMTabBarCellPadding; + } + + // icon + if ([cell hasIcon]) { + NSRect iconRect = [self iconRectForTabCell:cell]; + NSImage *icon = [[[cell representedObject] identifier] icon]; + + if ([controlView isFlipped]) { + iconRect.origin.y += iconRect.size.height; + } + + // center in available space (in case icon image is smaller than kPSMTabBarIconWidth) + if ([icon size].width < kPSMTabBarIconWidth) { + iconRect.origin.x += (kPSMTabBarIconWidth - [icon size].width)/2.0; + } + if ([icon size].height < kPSMTabBarIconWidth) { + iconRect.origin.y -= (kPSMTabBarIconWidth - [icon size].height)/2.0; + } + + [icon compositeToPoint:iconRect.origin operation:NSCompositeSourceOver fraction:1.0]; + + // scoot label over + labelPosition += iconRect.size.width + kPSMTabBarCellPadding; + } + + // label rect + NSRect labelRect; + labelRect.origin.x = labelPosition; + labelRect.size.width = cellFrame.size.width - (labelRect.origin.x - cellFrame.origin.x) - kPSMTabBarCellPadding; + labelRect.size.height = cellFrame.size.height; + labelRect.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0; + + if ([cell state] == NSOnState) { + labelRect.origin.y -= 1; + } + + if (![[cell indicator] isHidden]) { + labelRect.size.width -= (kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding); + } + + // object counter + if ([cell count] > 0) { + [[cell countColor] ?: [NSColor colorWithCalibratedWhite:0.3 alpha:0.6] set]; + NSBezierPath *path = [NSBezierPath bezierPath]; + NSRect myRect = [self objectCounterRectForTabCell:cell]; + if ([cell state] == NSOnState) { + myRect.origin.y -= 1.0; + } + [path moveToPoint:NSMakePoint(myRect.origin.x + kPSMMetalObjectCounterRadius, myRect.origin.y)]; + [path lineToPoint:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMMetalObjectCounterRadius, myRect.origin.y)]; + [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMMetalObjectCounterRadius, myRect.origin.y + kPSMMetalObjectCounterRadius) radius:kPSMMetalObjectCounterRadius startAngle:270.0 endAngle:90.0]; + [path lineToPoint:NSMakePoint(myRect.origin.x + kPSMMetalObjectCounterRadius, myRect.origin.y + myRect.size.height)]; + [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + kPSMMetalObjectCounterRadius, myRect.origin.y + kPSMMetalObjectCounterRadius) radius:kPSMMetalObjectCounterRadius 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]; + + // shrink label width to make room for object counter + labelRect.size.width -= myRect.size.width + kPSMTabBarCellPadding; + } + + // draw label + [[cell attributedStringValue] drawInRect:labelRect]; +} + +- (void)drawBackgroundInRect:(NSRect)rect +{ + //Draw for our whole bounds; it'll be automatically clipped to fit the appropriate drawing area + rect = [tabBar bounds]; + + if (orientation == PSMTabBarVerticalOrientation && [tabBar frame].size.width < 2) { + return; + } + + [NSGraphicsContext saveGraphicsState]; + [[NSGraphicsContext currentContext] setShouldAntialias:NO]; + + [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set]; + NSRectFillUsingOperation(rect, NSCompositeSourceAtop); + [[NSColor darkGrayColor] set]; + + if (orientation == PSMTabBarHorizontalOrientation) { + [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, rect.origin.y + 0.5) toPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y + 0.5)]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, rect.origin.y + rect.size.height - 0.5) toPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height - 0.5)]; + } else { + [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, rect.origin.y + 0.5) toPoint:NSMakePoint(rect.origin.x, rect.origin.y + rect.size.height + 0.5)]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y + 0.5) toPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height + 0.5)]; + } + + [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 +{ + //[super encodeWithCoder:aCoder]; +/* + if ([aCoder allowsKeyedCoding]) { + [aCoder encodeObject:metalCloseButton forKey:@"metalCloseButton"]; + [aCoder encodeObject:metalCloseButtonDown forKey:@"metalCloseButtonDown"]; + [aCoder encodeObject:metalCloseButtonOver forKey:@"metalCloseButtonOver"]; + [aCoder encodeObject:metalCloseDirtyButton forKey:@"metalCloseDirtyButton"]; + [aCoder encodeObject:metalCloseDirtyButtonDown forKey:@"metalCloseDirtyButtonDown"]; + [aCoder encodeObject:metalCloseDirtyButtonOver forKey:@"metalCloseDirtyButtonOver"]; + [aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"]; + [aCoder encodeObject:_addTabButtonPressedImage forKey:@"addTabButtonPressedImage"]; + [aCoder encodeObject:_addTabButtonRolloverImage forKey:@"addTabButtonRolloverImage"]; + } +*/ +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (self) { + +/* + if ([aDecoder allowsKeyedCoding]) { + metalCloseButton = [[aDecoder decodeObjectForKey:@"metalCloseButton"] retain]; + metalCloseButtonDown = [[aDecoder decodeObjectForKey:@"metalCloseButtonDown"] retain]; + metalCloseButtonOver = [[aDecoder decodeObjectForKey:@"metalCloseButtonOver"] retain]; + metalCloseDirtyButton = [[aDecoder decodeObjectForKey:@"metalCloseDirtyButton"] retain]; + metalCloseDirtyButtonDown = [[aDecoder decodeObjectForKey:@"metalCloseDirtyButtonDown"] retain]; + metalCloseDirtyButtonOver = [[aDecoder decodeObjectForKey:@"metalCloseDirtyButtonOver"] retain]; + _addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain]; + _addTabButtonPressedImage = [[aDecoder decodeObjectForKey:@"addTabButtonPressedImage"] retain]; + _addTabButtonRolloverImage = [[aDecoder decodeObjectForKey:@"addTabButtonRolloverImage"] retain]; + } +*/ + } + return self; +} + +@end diff --git a/Frameworks/PSMTabBar/Styles/PSMUnifiedTabStyle.h b/Frameworks/PSMTabBar/Styles/PSMUnifiedTabStyle.h new file mode 100644 index 00000000..d44bbcdc --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMUnifiedTabStyle.h @@ -0,0 +1,30 @@ +// +// PSMUnifiedTabStyle.h +// -------------------- +// +// Created by Keith Blount on 30/04/2006. +// Copyright 2006 __MyCompanyName__. All rights reserved. +// + +#import <Cocoa/Cocoa.h> +#import "PSMTabStyle.h" + +@interface PSMUnifiedTabStyle : NSObject <PSMTabStyle> +{ + NSImage *unifiedCloseButton; + NSImage *unifiedCloseButtonDown; + NSImage *unifiedCloseButtonOver; + NSImage *unifiedCloseDirtyButton; + NSImage *unifiedCloseDirtyButtonDown; + NSImage *unifiedCloseDirtyButtonOver; + NSImage *_addTabButtonImage; + NSImage *_addTabButtonPressedImage; + NSImage *_addTabButtonRolloverImage; + + NSDictionary *_objectCountStringAttributes; + + CGFloat leftMargin; + PSMTabBarControl *tabBar; +} +- (void)setLeftMarginForTabBarControl:(CGFloat)margin; +@end diff --git a/Frameworks/PSMTabBar/Styles/PSMUnifiedTabStyle.m b/Frameworks/PSMTabBar/Styles/PSMUnifiedTabStyle.m new file mode 100644 index 00000000..13fb0994 --- /dev/null +++ b/Frameworks/PSMTabBar/Styles/PSMUnifiedTabStyle.m @@ -0,0 +1,603 @@ +// +// PSMUnifiedTabStyle.m +// -------------------- +// +// Created by Keith Blount on 30/04/2006. +// Copyright 2006 __MyCompanyName__. All rights reserved. +// + +#import "PSMUnifiedTabStyle.h" +#import "PSMTabBarCell.h" +#import "PSMTabBarControl.h" +#import "NSBezierPath_AMShading.h" + +#define kPSMUnifiedObjectCounterRadius 7.0 +#define kPSMUnifiedCounterMinWidth 20 + +@interface PSMUnifiedTabStyle (Private) +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView; +@end + +@implementation PSMUnifiedTabStyle + +- (NSString *)name +{ + return @"Unified"; +} + +#pragma mark - +#pragma mark Creation/Destruction + +- (id) init +{ + if ( (self = [super init]) ) { + unifiedCloseButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front"]]; + unifiedCloseButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Pressed"]]; + unifiedCloseButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Rollover"]]; + + unifiedCloseDirtyButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front"]]; + unifiedCloseDirtyButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabCloseDirty_Front_Pressed"]]; + unifiedCloseDirtyButtonOver = [[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"]]; + + _objectCountStringAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:[[NSFontManager sharedFontManager] convertFont:[NSFont fontWithName:@"Helvetica" size:11.0] toHaveTrait:NSBoldFontMask], NSFontAttributeName, + [[NSColor whiteColor] colorWithAlphaComponent:0.85], NSForegroundColorAttributeName, + nil, nil]; + + leftMargin = 5.0; + } + return self; +} + +- (void)dealloc +{ + [unifiedCloseButton release]; + [unifiedCloseButtonDown release]; + [unifiedCloseButtonOver release]; + [unifiedCloseDirtyButton release]; + [unifiedCloseDirtyButtonDown release]; + [unifiedCloseDirtyButtonOver release]; + [_addTabButtonImage release]; + [_addTabButtonPressedImage release]; + [_addTabButtonRolloverImage release]; + + [_objectCountStringAttributes release]; + + [super dealloc]; +} + +#pragma mark - +#pragma mark Control Specific + +- (void)setLeftMarginForTabBarControl:(CGFloat)margin +{ + leftMargin = margin; +} + +- (CGFloat)leftMarginForTabBarControl +{ + return leftMargin; +} + +- (CGFloat)rightMarginForTabBarControl +{ + return 24.0f; +} + +- (CGFloat)topMarginForTabBarControl +{ + return 10.0f; +} + +- (void)setOrientation:(PSMTabBarOrientation)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)orientation +{ + NSRect dragRect = [cell frame]; + dragRect.size.width++; + return dragRect; +} + +- (NSRect)closeButtonRectForTabCell:(PSMTabBarCell *)cell withFrame:(NSRect)cellFrame +{ + if ([cell hasCloseButton] == NO) { + return NSZeroRect; + } + + NSRect result; + result.size = [unifiedCloseButton size]; + result.origin.x = cellFrame.origin.x + MARGIN_X; + result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0; + + return result; +} + +- (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + if ([cell hasIcon] == NO) { + return NSZeroRect; + } + + NSRect result; + result.size = NSMakeSize(kPSMTabBarIconWidth, kPSMTabBarIconWidth); + result.origin.x = cellFrame.origin.x + MARGIN_X; + result.origin.y = cellFrame.origin.y + MARGIN_Y - 1.0; + + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + result.origin.x += [unifiedCloseButton size].width + kPSMTabBarCellPadding; + } + + 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 - MARGIN_X - kPSMTabBarIndicatorWidth; + result.origin.y = cellFrame.origin.y + MARGIN_Y - 1.0; + + return result; +} + +- (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + if ([cell count] == 0) { + return NSZeroRect; + } + + CGFloat countWidth = [[self attributedObjectCountValueForTabCell:cell] size].width; + countWidth += (2 * kPSMUnifiedObjectCounterRadius - 6.0); + if (countWidth < kPSMUnifiedCounterMinWidth) { + countWidth = kPSMUnifiedCounterMinWidth; + } + + NSRect result; + result.size = NSMakeSize(countWidth, 2 * kPSMUnifiedObjectCounterRadius); // temp + result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - result.size.width; + result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0; + + if (![[cell indicator] isHidden]) { + result.origin.x -= kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding; + } + + return result; +} + + +- (CGFloat)minimumWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat resultWidth = 0.0; + + // left margin + resultWidth = MARGIN_X; + + // close button? + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + resultWidth += [unifiedCloseButton size].width + kPSMTabBarCellPadding; + } + + // icon? + if ([cell hasIcon]) { + resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding; + } + + // the label + resultWidth += kPSMMinimumTitleWidth; + + // object counter? + if ([cell count] > 0) { + resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding; + } + + // indicator? + if ([[cell indicator] isHidden] == NO) + resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth; + + // right margin + resultWidth += MARGIN_X; + + return ceil(resultWidth); +} + +- (CGFloat)desiredWidthOfTabCell:(PSMTabBarCell *)cell +{ + CGFloat resultWidth = 0.0; + + // left margin + resultWidth = MARGIN_X; + + // close button? + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) + resultWidth += [unifiedCloseButton size].width + kPSMTabBarCellPadding; + + // icon? + if ([cell hasIcon]) { + resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding; + } + + // the label + resultWidth += [[cell attributedStringValue] size].width; + + // object counter? + if ([cell count] > 0) { + resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding; + } + + // indicator? + if ([[cell indicator] isHidden] == NO) + resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth; + + // right margin + resultWidth += MARGIN_X; + + return ceil(resultWidth); +} + +- (CGFloat)tabCellHeight +{ + return kPSMTabBarControlHeight; +} + +#pragma mark - +#pragma mark Cell Values + +- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell +{ + NSString *contents = [NSString stringWithFormat:@"%lu", (unsigned long)[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]); + + [attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] 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 ---- drawing ---- + +- (void)drawTabCell:(PSMTabBarCell *)cell +{ + NSRect cellFrame = [cell frame]; + + NSToolbar *toolbar = [[[cell controlView] window] toolbar]; + BOOL showsBaselineSeparator = (toolbar && [toolbar respondsToSelector:@selector(showsBaselineSeparator)] && [toolbar showsBaselineSeparator]); + if (!showsBaselineSeparator) { + cellFrame.origin.y += 1.0; + cellFrame.size.height -= 1.0; + } + + NSColor * lineColor = nil; + NSBezierPath* bezier = [NSBezierPath bezierPath]; + lineColor = [NSColor colorWithCalibratedWhite:0.576 alpha:1.0]; + + if (!showsBaselineSeparator || [cell state] == NSOnState) + { + // selected tab + NSRect aRect = NSMakeRect(cellFrame.origin.x+0.5, cellFrame.origin.y-0.5, cellFrame.size.width, cellFrame.size.height); + + // frame + CGFloat radius = MIN(6.0, 0.5f * MIN(NSWidth(aRect), NSHeight(aRect))); + NSRect rect = NSInsetRect(aRect, radius, radius); + + [bezier appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMinY(rect)) radius:radius startAngle:180.0 endAngle:270.0]; + + [bezier appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMinY(rect)) radius:radius startAngle:270.0 endAngle:360.0]; + + NSPoint cornerPoint = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect)); + [bezier appendBezierPathWithPoints:&cornerPoint count:1]; + + cornerPoint = NSMakePoint(NSMinX(aRect), NSMaxY(aRect)); + [bezier appendBezierPathWithPoints:&cornerPoint count:1]; + + [bezier closePath]; + + //[[NSColor windowBackgroundColor] set]; + //[bezier fill]; + if ([NSApp isActive]) { + if ([cell state] == NSOnState) { + [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.99 alpha:1.0] + endColor:[NSColor colorWithCalibratedWhite:0.941 alpha:1.0]]; + } else if ([cell isHighlighted]) { + [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.80 alpha:1.0] + endColor:[NSColor colorWithCalibratedWhite:0.80 alpha:1.0]]; + } else { + [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0] + endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]]; + } + } + + [lineColor set]; + [bezier stroke]; + } + else + { + // unselected tab + NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height); + aRect.origin.y += 0.5; + aRect.origin.x += 1.5; + aRect.size.width -= 1; + + aRect.origin.x -= 1; + aRect.size.width += 1; + + // rollover + if ([cell isHighlighted]) + { + [[NSColor colorWithCalibratedWhite:0.0 alpha:0.1] set]; + NSRectFillUsingOperation(aRect, NSCompositeSourceAtop); + } + + // frame + + [lineColor set]; + [bezier moveToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y-0.5)]; + if (!([cell tabState] & PSMTab_RightIsSelectedMask)) { + [bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMaxY(aRect))]; + } + + [bezier stroke]; + + // Create a thin lighter line next to the dividing line for a bezel effect + if (!([cell tabState] & PSMTab_RightIsSelectedMask)) { + [[[NSColor whiteColor] colorWithAlphaComponent:0.5] set]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMaxX(aRect)+1.0, aRect.origin.y-0.5) + toPoint:NSMakePoint(NSMaxX(aRect)+1.0, NSMaxY(aRect)-2.5)]; + } + + // If this is the leftmost tab, we want to draw a line on the left, too + if ([cell tabState] & PSMTab_PositionLeftMask) + { + [lineColor set]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(aRect.origin.x,aRect.origin.y-0.5) + toPoint:NSMakePoint(aRect.origin.x,NSMaxY(aRect)-2.5)]; + [[[NSColor whiteColor] colorWithAlphaComponent:0.5] set]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(aRect.origin.x+1.0,aRect.origin.y-0.5) + toPoint:NSMakePoint(aRect.origin.x+1.0,NSMaxY(aRect)-2.5)]; + } + } + + [self drawInteriorWithTabCell:cell inView:[cell controlView]]; +} + + +- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView +{ + NSRect cellFrame = [cell frame]; + CGFloat labelPosition = cellFrame.origin.x + MARGIN_X; + + // close button + if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { + NSSize closeButtonSize = NSZeroSize; + NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame]; + NSImage * closeButton = nil; + + closeButton = [cell isEdited] ? unifiedCloseDirtyButton : unifiedCloseButton; + + if ([cell closeButtonOver]) closeButton = [cell isEdited] ? unifiedCloseDirtyButtonOver : unifiedCloseButtonOver; + if ([cell closeButtonPressed]) closeButton = [cell isEdited] ? unifiedCloseDirtyButtonDown : unifiedCloseButtonDown; + + closeButtonSize = [closeButton size]; + if ([controlView isFlipped]) { + closeButtonRect.origin.y += closeButtonRect.size.height; + } + + [closeButton compositeToPoint:closeButtonRect.origin operation:NSCompositeSourceOver fraction:1.0]; + + // scoot label over + labelPosition += closeButtonSize.width + kPSMTabBarCellPadding; + } + + // icon + if ([cell hasIcon]) { + NSRect iconRect = [self iconRectForTabCell:cell]; + NSImage *icon = [[[cell representedObject] identifier] icon]; + if ([controlView isFlipped]) { + iconRect.origin.y += iconRect.size.height; + } + + // center in available space (in case icon image is smaller than kPSMTabBarIconWidth) + if ([icon size].width < kPSMTabBarIconWidth) { + iconRect.origin.x += (kPSMTabBarIconWidth - [icon size].width) / 2.0; + } + if ([icon size].height < kPSMTabBarIconWidth) { + iconRect.origin.y -= (kPSMTabBarIconWidth - [icon size].height) / 2.0; + } + + [icon compositeToPoint:iconRect.origin operation:NSCompositeSourceOver fraction:1.0]; + + // scoot label over + labelPosition += iconRect.size.width + kPSMTabBarCellPadding; + } + + // label rect + NSRect labelRect; + labelRect.origin.x = labelPosition; + labelRect.size.width = cellFrame.size.width - (labelRect.origin.x - cellFrame.origin.x) - kPSMTabBarCellPadding; + NSSize s = [[cell attributedStringValue] size]; + labelRect.origin.y = cellFrame.origin.y + (cellFrame.size.height-s.height) / 2.0 - 1.0; + labelRect.size.height = s.height; + + if (![[cell indicator] isHidden]) { + labelRect.size.width -= (kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding); + } + + // object counter + if ([cell count] > 0) { + [[cell countColor] ?: [NSColor colorWithCalibratedWhite:0.3 alpha:0.6] set]; + NSBezierPath *path = [NSBezierPath bezierPath]; + NSRect myRect = [self objectCounterRectForTabCell:cell]; + myRect.origin.y -= 1.0; + [path moveToPoint:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y)]; + [path lineToPoint:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMUnifiedObjectCounterRadius, myRect.origin.y)]; + [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMUnifiedObjectCounterRadius, myRect.origin.y + kPSMUnifiedObjectCounterRadius) radius:kPSMUnifiedObjectCounterRadius startAngle:270.0 endAngle:90.0]; + [path lineToPoint:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y + myRect.size.height)]; + [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y + kPSMUnifiedObjectCounterRadius) radius:kPSMUnifiedObjectCounterRadius 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]; + + labelRect.size.width -= myRect.size.width + kPSMTabBarCellPadding; + } + + // label + [[cell attributedStringValue] drawInRect:labelRect]; +} + +- (void)drawBackgroundInRect:(NSRect)rect +{ + //Draw for our whole bounds; it'll be automatically clipped to fit the appropriate drawing area + rect = [tabBar bounds]; + + NSRect gradientRect = rect; + gradientRect.size.height -= 1.0; + + NSBezierPath *path = [NSBezierPath bezierPathWithRect:gradientRect]; + [path linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.835 alpha:1.0] + endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]]; + [[NSColor colorWithCalibratedWhite:0.576 alpha:1.0] set]; + [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, NSMaxY(rect) - 0.5) + toPoint:NSMakePoint(NSMaxX(rect), NSMaxY(rect) - 0.5)]; + + if (![[[tabBar tabView] window] isKeyWindow]) { + [[NSColor windowBackgroundColor] set]; + NSRectFill(gradientRect); + } +} + +- (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect +{ + 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 +{ +/* + //[super encodeWithCoder:aCoder]; + if ([aCoder allowsKeyedCoding]) { + [aCoder encodeObject:unifiedCloseButton forKey:@"unifiedCloseButton"]; + [aCoder encodeObject:unifiedCloseButtonDown forKey:@"unifiedCloseButtonDown"]; + [aCoder encodeObject:unifiedCloseButtonOver forKey:@"unifiedCloseButtonOver"]; + [aCoder encodeObject:unifiedCloseDirtyButton forKey:@"unifiedCloseDirtyButton"]; + [aCoder encodeObject:unifiedCloseDirtyButtonDown forKey:@"unifiedCloseDirtyButtonDown"]; + [aCoder encodeObject:unifiedCloseDirtyButtonOver forKey:@"unifiedCloseDirtyButtonOver"]; + [aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"]; + [aCoder encodeObject:_addTabButtonPressedImage forKey:@"addTabButtonPressedImage"]; + [aCoder encodeObject:_addTabButtonRolloverImage forKey:@"addTabButtonRolloverImage"]; + } +*/ +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (self) { + /* + if ([aDecoder allowsKeyedCoding]) { + unifiedCloseButton = [[aDecoder decodeObjectForKey:@"unifiedCloseButton"] retain]; + unifiedCloseButtonDown = [[aDecoder decodeObjectForKey:@"unifiedCloseButtonDown"] retain]; + unifiedCloseButtonOver = [[aDecoder decodeObjectForKey:@"unifiedCloseButtonOver"] retain]; + unifiedCloseDirtyButton = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButton"] retain]; + unifiedCloseDirtyButtonDown = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButtonDown"] retain]; + unifiedCloseDirtyButtonOver = [[aDecoder decodeObjectForKey:@"unifiedCloseDirtyButtonOver"] retain]; + _addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain]; + _addTabButtonPressedImage = [[aDecoder decodeObjectForKey:@"addTabButtonPressedImage"] retain]; + _addTabButtonRolloverImage = [[aDecoder decodeObjectForKey:@"addTabButtonRolloverImage"] retain]; + } + */ + } + return self; +} + +@end |