Merge pull request #791 from ychin/tabs_dark_mode_and_fixes

Add Mojave-style tabs, which also supports Dark Mode
This commit is contained in:
Yee Cheng Chin
2018-11-26 10:54:14 -08:00
committed by GitHub
18 changed files with 961 additions and 13 deletions
+6 -2
View File
@@ -726,8 +726,12 @@ prominent bugs/missing features.
then opened in Preview where it may be printed.
- The toolbar looks ugly and is not very useful.
If you find new bugs then please post your findings to the vim_mac mailing
list: *vim_mac_group* >
Other bugs and issues are tracked on Github. If you find new bugs then please
file an issue there: >
https://github.com/macvim-dev/macvim/issues
There is also a vim_mac mailing list. You can also post your findings of bugs
and issues there as well: *vim_mac_group* >
http://groups.google.com/group/vim_mac
This is also the best place for making feature requests as well as for asking
+4 -2
View File
@@ -125,7 +125,7 @@ enum {
[tabBarControl setDelegate:self];
[tabBarControl setHidden:YES];
if (shouldUseYosemiteTabBarStyle()) {
if (shouldUseYosemiteTabBarStyle() || shouldUseMojaveTabBarStyle()) {
CGFloat screenWidth = [[NSScreen mainScreen] frame].size.width;
int tabMaxWidth = [ud integerForKey:MMTabMaxWidthKey];
if (tabMaxWidth == 0)
@@ -133,8 +133,10 @@ enum {
int tabOptimumWidth = [ud integerForKey:MMTabOptimumWidthKey];
if (tabOptimumWidth == 0)
tabOptimumWidth = screenWidth;
NSString* tabStyleName = shouldUseMojaveTabBarStyle() ? @"Mojave" : @"Yosemite";
[tabBarControl setStyleNamed:@"Yosemite"];
[tabBarControl setStyleNamed:tabStyleName];
[tabBarControl setCellMinWidth:[ud integerForKey:MMTabMinWidthKey]];
[tabBarControl setCellMaxWidth:tabMaxWidth];
[tabBarControl setCellOptimumWidth:tabOptimumWidth];
+3
View File
@@ -32,6 +32,9 @@
#ifndef MAC_OS_X_VERSION_10_12_2
# define MAC_OS_X_VERSION_10_12_2 101202
#endif
#ifndef MAC_OS_X_VERSION_10_14
# define MAC_OS_X_VERSION_10_14 101400
#endif
#ifndef NSAppKitVersionNumber10_10
# define NSAppKitVersionNumber10_10 1343
+1
View File
@@ -155,3 +155,4 @@ NSArray *normalizeFilenames(NSArray *filenames);
BOOL shouldUseYosemiteTabBarStyle();
BOOL shouldUseMojaveTabBarStyle();
+10
View File
@@ -305,4 +305,14 @@ normalizeFilenames(NSArray *filenames)
shouldUseYosemiteTabBarStyle()
{
return floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_10;
}
BOOL
shouldUseMojaveTabBarStyle()
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
if (@available(macos 10.14, *)) {
return true;
}
#endif
return false;
}
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,38 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "189",
"alpha" : "1.000",
"blue" : "188",
"green" : "189"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "40",
"alpha" : "1.000",
"blue" : "42",
"green" : "40"
}
}
}
]
}
@@ -0,0 +1,38 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "168",
"alpha" : "1.000",
"blue" : "168",
"green" : "168"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "36",
"alpha" : "1.000",
"blue" : "39",
"green" : "37"
}
}
}
]
}
@@ -0,0 +1,38 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "209",
"alpha" : "1.000",
"blue" : "208",
"green" : "209"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "54",
"alpha" : "1.000",
"blue" : "57",
"green" : "55"
}
}
}
]
}
@@ -0,0 +1,38 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "221",
"alpha" : "1.000",
"blue" : "221",
"green" : "221"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "30",
"alpha" : "1.000",
"blue" : "33",
"green" : "31"
}
}
}
]
}
@@ -0,0 +1,38 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "198",
"alpha" : "1.000",
"blue" : "198",
"green" : "198"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "27",
"alpha" : "1.000",
"blue" : "30",
"green" : "28"
}
}
}
]
}
@@ -0,0 +1,38 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "246",
"alpha" : "1.000",
"blue" : "246",
"green" : "246"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "43",
"alpha" : "1.000",
"blue" : "47",
"green" : "45"
}
}
}
]
}
@@ -0,0 +1,38 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "169",
"alpha" : "1.000",
"blue" : "169",
"green" : "169"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "96",
"alpha" : "1.000",
"blue" : "99",
"green" : "97"
}
}
}
]
}
@@ -0,0 +1,38 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "210",
"alpha" : "1.000",
"blue" : "210",
"green" : "210"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "73",
"alpha" : "1.000",
"blue" : "77",
"green" : "74"
}
}
}
]
}
@@ -41,6 +41,9 @@
52FAFCD41C30F4DF00C6E613 /* PSMYosemiteTabStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FAFCD21C30F4DF00C6E613 /* PSMYosemiteTabStyle.m */; };
546DEAF1067F63070098DCC4 /* PSMTabBarControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0259C576FE90428111CA0C5A /* PSMTabBarControl.m */; };
546DEAF2067F630E0098DCC4 /* PSMTabBarControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0259C57AFE90428111CA0C5A /* PSMTabBarControl.h */; settings = {ATTRIBUTES = (Public, ); }; };
90AD234F21A969C100CEF036 /* PSMMojaveTabStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 90AD234D21A969C100CEF036 /* PSMMojaveTabStyle.h */; };
90AD235021A969C100CEF036 /* PSMMojaveTabStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 90AD234E21A969C100CEF036 /* PSMMojaveTabStyle.m */; };
90DE16CC21A955EE004F0124 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 90DE16CB21A955EE004F0124 /* Media.xcassets */; };
A2082A9009EAEB34009AC8BE /* PSMTabDragAssistant.h in Headers */ = {isa = PBXBuildFile; fileRef = A2082A8D09EAEB33009AC8BE /* PSMTabDragAssistant.h */; };
A2082A9109EAEB34009AC8BE /* PSMTabDragAssistant.m in Sources */ = {isa = PBXBuildFile; fileRef = A2082A8E09EAEB33009AC8BE /* PSMTabDragAssistant.m */; };
A2129BB209AEB58F00724E6C /* PSMProgressIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = A2129BAF09AEB58F00724E6C /* PSMProgressIndicator.h */; };
@@ -124,6 +127,9 @@
54D33B2806778E3300C9C163 /* PSMTabBarControl.ibclassdescription */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PSMTabBarControl.ibclassdescription; sourceTree = "<group>"; };
8D1AC9730486D14A00FE50C9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8D1AC97B0486D23100FE50C9 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
90AD234D21A969C100CEF036 /* PSMMojaveTabStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PSMMojaveTabStyle.h; path = source/PSMMojaveTabStyle.h; sourceTree = "<group>"; };
90AD234E21A969C100CEF036 /* PSMMojaveTabStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PSMMojaveTabStyle.m; path = source/PSMMojaveTabStyle.m; sourceTree = "<group>"; };
90DE16CB21A955EE004F0124 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = "<group>"; };
A2072A2409ABD88600304BCB /* Folder.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = Folder.tif; path = images/Folder.tif; sourceTree = "<group>"; };
A2072A2509ABD88600304BCB /* Globe.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = Globe.tiff; path = images/Globe.tiff; sourceTree = "<group>"; };
A2072B5C09AC1FA500304BCB /* Warning.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Warning.png; path = images/Warning.png; sourceTree = "<group>"; };
@@ -209,6 +215,7 @@
0259C582FE90428111CA0C5A /* Resources */ = {
isa = PBXGroup;
children = (
90DE16CB21A955EE004F0124 /* Media.xcassets */,
A251BEC20959BC0E0058BC7F /* MainMenu.nib */,
A251BE8E0959A21A0058BC7F /* Images */,
8D1AC9730486D14A00FE50C9 /* Info.plist */,
@@ -308,6 +315,8 @@
54D33B2C06778E4400C9C163 /* Framework */ = {
isa = PBXGroup;
children = (
90AD234D21A969C100CEF036 /* PSMMojaveTabStyle.h */,
90AD234E21A969C100CEF036 /* PSMMojaveTabStyle.m */,
0259C57AFE90428111CA0C5A /* PSMTabBarControl.h */,
0259C576FE90428111CA0C5A /* PSMTabBarControl.m */,
A251BE830959A1B90058BC7F /* PSMTabBarCell.h */,
@@ -416,6 +425,7 @@
A2082A9009EAEB34009AC8BE /* PSMTabDragAssistant.h in Headers */,
A2D98B0A0A2B432C0064C6F8 /* PSMUnifiedTabStyle.h in Headers */,
A2D98B120A2B43FA0064C6F8 /* NSBezierPath_AMShading.h in Headers */,
90AD234F21A969C100CEF036 /* PSMMojaveTabStyle.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -490,6 +500,7 @@
A27E47880A28EE7C007BA395 /* TabControlRep.tif in Resources */,
52A57C0F15BBA230003EC59C /* TabClose_Front.png in Resources */,
52A57C1015BBA230003EC59C /* TabClose_Front_Pressed.png in Resources */,
90DE16CC21A955EE004F0124 /* Media.xcassets in Resources */,
52A57C1115BBA230003EC59C /* TabClose_Front_Rollover.png in Resources */,
52FAFCCF1C30F4B500C6E613 /* TabNewYosemite.png in Resources */,
523897F415BDA9AC00498A53 /* TabClose_Front_Pressed@2x.png in Resources */,
@@ -519,6 +530,7 @@
A2D32F0109A63D7A00EC8662 /* PSMMetalTabStyle.m in Sources */,
A268EA6309A9831800E082AA /* PSMRolloverButton.m in Sources */,
A2129BB309AEB58F00724E6C /* PSMProgressIndicator.m in Sources */,
90AD235021A969C100CEF036 /* PSMMojaveTabStyle.m in Sources */,
A2082A9109EAEB34009AC8BE /* PSMTabDragAssistant.m in Sources */,
52FAFCD41C30F4DF00C6E613 /* PSMYosemiteTabStyle.m in Sources */,
A2D98B0B0A2B432C0064C6F8 /* PSMUnifiedTabStyle.m in Sources */,
@@ -0,0 +1,35 @@
//
// PSMMojaveTabStyle.h
// PSMTabBarControl
//
// This file is copied from PSMYosemiteTabStyle to allow for modifications to
// adapt to Mojave-specific functionality such as Dark Mode without needing to
// pollute the implementation of Yosemite tab style.
//
//
#if defined(MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
#define HAS_MOJAVE_TAB_STYLE 1
#import <Cocoa/Cocoa.h>
#import "PSMTabStyle.h"
@interface PSMMojaveTabStyle : NSObject <PSMTabStyle> {
NSImage *closeButton;
NSImage *closeButtonDown;
NSImage *closeButtonOver;
NSImage *closeButtonOverDark;
NSImage *_addTabButtonImage;
NSMutableParagraphStyle *truncatingTailParagraphStyle;
NSMutableParagraphStyle *centeredParagraphStyle;
}
- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView;
- (void)styleAddTabButton:(PSMRolloverButton *)addTabButton;
- (void)encodeWithCoder:(NSCoder *)aCoder;
- (id)initWithCoder:(NSCoder *)aDecoder;
@end
#endif
@@ -0,0 +1,562 @@
//
// PSMMojaveTabStyle.m
// PSMTabBarControl
//
// This file is copied from PSMYosemiteTabStyle to allow for modifications to
// adapt to Mojave-specific functionality such as Dark Mode without needing to
// pollute the implementation of Yosemite tab style.
//
//
#import "PSMMojaveTabStyle.h"
#if HAS_MOJAVE_TAB_STYLE
#define kPSMMetalObjectCounterRadius 7.0
#define kPSMMetalCounterMinWidth 20
void MojaveNSDrawWindowBackground(NSRect rect, NSColor *color)
{
[color set];
NSRectFill( rect );
}
@implementation PSMMojaveTabStyle
- (void)dealloc
{
[closeButton release];
[closeButtonDown release];
[closeButtonOver release];
[closeButtonOverDark release];
[_addTabButtonImage release];
[truncatingTailParagraphStyle release];
[centeredParagraphStyle release];
[super dealloc];
}
#pragma mark -
#pragma mark Initializers
- (id)init
{
self = [super init];
if (!self) return nil;
closeButton = [[self createCloseButtonImage:16.0 color:[NSColor secondaryLabelColor] backgroundColor:nil] retain];
closeButtonDown = [[self createCloseButtonImage:16.0 color:[NSColor secondaryLabelColor] backgroundColor:[NSColor grayColor]] retain];
closeButtonOver = [[self createCloseButtonImage:16.0 color:[NSColor secondaryLabelColor] backgroundColor:[NSColor grayColor]] retain];
closeButtonOverDark = [[self createCloseButtonImage:16.0 color:[NSColor secondaryLabelColor] backgroundColor:[NSColor darkGrayColor]] retain];
_addTabButtonImage = [[NSImage imageNamed:NSImageNameAddTemplate] retain];
return self;
}
- (NSString *)name
{
return @"Mojave";
}
#pragma mark -
#pragma mark Control Specific
- (float)leftMarginForTabBarControl
{
return -1.0f;
}
- (float)rightMarginForTabBarControl
{
return 24.0f;
}
#pragma mark -
#pragma mark Add Tab Button
- (void)styleAddTabButton:(PSMRolloverButton *)addTabButton
{
NSImage *newButtonImage = [self addTabButtonImage];
if (newButtonImage) {
[addTabButton setUsualImage:newButtonImage];
[addTabButton setAlternateImage:newButtonImage];
[addTabButton setRolloverImage:newButtonImage];
}
[addTabButton setButtonType:NSMomentaryLightButton];
}
- (NSImage *)addTabButtonImage
{
return _addTabButtonImage;
}
- (NSImage *)addTabButtonPressedImage
{
return _addTabButtonImage;;
}
- (NSImage *)addTabButtonRolloverImage
{
return _addTabButtonImage;
}
- (NSColor *)backgroundColor:(PSMTabBarCell *)cell isKeyWindow:(BOOL)isKeyWindow isSelected:(BOOL)isSelected
{
NSColor *backgroundColor;
BOOL isHighlight = [cell isHighlighted];
if (isKeyWindow) {
if (isSelected) {
backgroundColor = [NSColor colorNamed:@"MojaveTabBackgroundActiveSelected" bundle:[PSMTabBarControl bundle]];
} else if (isHighlight) {
backgroundColor = [NSColor colorNamed:@"MojaveTabBackgroundActiveHighlight" bundle:[PSMTabBarControl bundle]];
} else {
backgroundColor = [NSColor colorNamed:@"MojaveTabBackgroundActive" bundle:[PSMTabBarControl bundle]];
}
} else {
if (isSelected) {
backgroundColor = [NSColor colorNamed:@"MojaveTabBackgroundInactiveSelected" bundle:[PSMTabBarControl bundle]];
} else if (isHighlight) {
backgroundColor = [NSColor colorNamed:@"MojaveTabBackgroundInactiveHighlight" bundle:[PSMTabBarControl bundle]];
} else {
backgroundColor = [NSColor colorNamed:@"MojaveTabBackgroundInactive" bundle:[PSMTabBarControl bundle]];
}
}
return backgroundColor;
}
- (NSColor *)borderColor:(BOOL)isKeyWindow
{
if (isKeyWindow) {
return [NSColor colorNamed:@"MojaveTabBorderActive" bundle:[PSMTabBarControl bundle]];
} else {
return [NSColor colorNamed:@"MojaveTabBorderInactive" bundle:[PSMTabBarControl bundle]];
}
}
#pragma mark -
#pragma mark Cell Specific
- (NSRect) closeButtonRectForTabCell:(PSMTabBarCell *)cell
{
NSRect cellFrame = [cell frame];
if ([cell hasCloseButton] == NO) {
return NSZeroRect;
}
NSRect result;
result.size = [closeButton size];
result.origin.x = cellFrame.origin.x + MARGIN_X;
result.origin.y = (cellFrame.size.height - result.size.height) / 2;
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 += [closeButton size].width + kPSMTabBarCellPadding;
if([cell state] == NSControlStateValueOn){
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] == NSControlStateValueOn){
result.origin.y -= 1;
}
return result;
}
- (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell
{
NSRect cellFrame = [cell frame];
if ([cell count] == 0) {
return NSZeroRect;
}
float 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;
}
- (float)minimumWidthOfTabCell:(PSMTabBarCell *)cell
{
float resultWidth = 0.0;
// left margin
resultWidth = MARGIN_X;
// close button?
if([cell hasCloseButton] && ![cell isCloseButtonSuppressed])
resultWidth += [closeButton 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);
}
- (float)desiredWidthOfTabCell:(PSMTabBarCell *)cell
{
float resultWidth = 0.0;
// left margin
resultWidth = MARGIN_X;
// close button?
if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed])
resultWidth += [closeButton 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);
}
#pragma mark -
#pragma mark Cell Values
- (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell
{
NSMutableAttributedString *attrStr;
NSFontManager *fm = [NSFontManager sharedFontManager];
NSNumberFormatter *nf = [[[NSNumberFormatter alloc] init] autorelease];
[nf setLocalizesFormat:YES];
[nf setFormat:@"0"];
[nf setHasThousandSeparators:YES];
NSString *contents = [nf stringFromNumber:[NSNumber numberWithInt:[cell count]]];
attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
NSRange range = NSMakeRange(0, [contents length]);
// Add font attribute
[attrStr addAttribute:NSFontAttributeName value:[fm convertFont:[NSFont fontWithName:@"Helvetica" size:11.0] toHaveTrait:NSBoldFontMask] range:range];
[attrStr addAttribute:NSForegroundColorAttributeName value:[[NSColor whiteColor] colorWithAlphaComponent:0.85] range:range];
return attrStr;
}
- (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];
PSMTabBarControl *bar = (PSMTabBarControl *)cell.controlView;
BOOL isKeyWindow = [bar.window isKeyWindow];
CGFloat textAlpha;
if ([cell state] == NSControlStateValueOn) {
textAlpha = (isKeyWindow) ? 1.0f : 0.5f;
} else {
textAlpha = (isKeyWindow) ? 0.5f : 0.25f;
}
NSColor *textColor = [[NSColor textColor] colorWithAlphaComponent:textAlpha];
[attrStr addAttribute:NSForegroundColorAttributeName value:textColor range:range];
// Paragraph Style for Truncating Long Text
if (!truncatingTailParagraphStyle) {
truncatingTailParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
[truncatingTailParagraphStyle setLineBreakMode:NSLineBreakByTruncatingHead];
[truncatingTailParagraphStyle setAlignment:NSTextAlignmentCenter];
}
[attrStr addAttribute:NSParagraphStyleAttributeName value:truncatingTailParagraphStyle range:range];
return attrStr;
}
#pragma mark -
#pragma mark ---- drawing ----
- (void)drawTabCell:(PSMTabBarCell *)cell
{
PSMTabBarControl *bar = (PSMTabBarControl *)cell.controlView;
BOOL isKeyWindow = [bar.window isKeyWindow];
NSRect cellFrame = [cell frame];
NSColor * lineColor = nil;
NSBezierPath* bezier = [NSBezierPath bezierPath];
lineColor = [self borderColor:isKeyWindow];
if ([cell state] == NSControlStateValueOn) {
// selected tab
NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
// background
MojaveNSDrawWindowBackground(aRect, [self backgroundColor:cell isKeyWindow:isKeyWindow isSelected:YES]);
aRect.size.height -= 1.0f;
aRect.origin.y += 0.5f;
// frame
[lineColor set];
[bezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y+aRect.size.height)];
[bezier lineToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y)];
[bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width, aRect.origin.y)];
[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.x += 0.5;
// background
MojaveNSDrawWindowBackground(aRect, [self backgroundColor:cell isKeyWindow:isKeyWindow isSelected:NO]);
// frame
[lineColor set];
[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)];
}
[bezier stroke];
}
[self drawInteriorWithTabCell:cell inView:[cell controlView]];
}
- (NSImage *)createCloseButtonImage:(CGFloat)size color:(NSColor *)color backgroundColor:(NSColor *)backgroundColor
{
NSImage *result = [NSImage imageWithSize:NSMakeSize(size,size) flipped:YES drawingHandler:^BOOL(NSRect dstRect) {
if (backgroundColor) {
NSBezierPath *bezier = [NSBezierPath bezierPathWithRoundedRect:dstRect
xRadius:2.0
yRadius:2.0];
[backgroundColor set];
[bezier fill];
}
NSBezierPath *bezier = NSBezierPath.bezierPath;
[color set];
[bezier moveToPoint:NSMakePoint(NSMinX(dstRect)+4.5, NSMinY(dstRect)+4.5)];
[bezier lineToPoint:NSMakePoint(NSMaxX(dstRect)-4.5, NSMaxY(dstRect)-4.5)];
[bezier moveToPoint:NSMakePoint(NSMaxX(dstRect)-4.5, NSMinY(dstRect)+4.5)];
[bezier lineToPoint:NSMakePoint(NSMinX(dstRect)+4.5, NSMaxY(dstRect)-4.5)];
[bezier stroke];
return YES;
}];
return result;
}
- (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView
{
NSRect cellFrame = [cell frame];
float labelPosition = cellFrame.origin.x + MARGIN_X;
// close button
if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) {
NSSize closeButtonSize = NSZeroSize;
NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame];
NSImage *button = nil;
if ([cell isHighlighted]) {
button = closeButton;
}
if ([cell closeButtonOver]) {
NSAppearanceName appearanceName = [controlView.effectiveAppearance bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameAccessibilityHighContrastAqua, NSAppearanceNameDarkAqua, NSAppearanceNameAccessibilityHighContrastDarkAqua]];
if ([appearanceName isEqualToString:NSAppearanceNameDarkAqua] || [appearanceName isEqualToString:NSAppearanceNameAccessibilityHighContrastDarkAqua]) {
button = closeButtonOverDark;
} else {
button = closeButtonOver;
}
}
if ([cell closeButtonPressed]) button = closeButtonDown;
closeButtonSize = [button size];
[button drawInRect:closeButtonRect fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0 respectFlipped:YES hints:nil];
}
// object counter
if([cell count] > 0){
[[NSColor colorWithCalibratedWhite:0.3 alpha:0.6] set];
NSBezierPath *path = [NSBezierPath bezierPath];
NSRect myRect = [self objectCounterRectForTabCell:cell];
[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];
}
// 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);
if([cell count] > 0)
labelRect.size.width -= ([self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding);
// label
[[cell attributedStringValue] drawInRect:labelRect];
}
- (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect
{
BOOL isKeyWindow = [bar.window isKeyWindow];
MojaveNSDrawWindowBackground(rect, [self backgroundColor:nil isKeyWindow:isKeyWindow isSelected:NO]);
[[NSColor colorWithCalibratedWhite:0.0 alpha:0.0] set];
NSRectFillUsingOperation(rect, NSCompositingOperationSourceAtop);
[[self borderColor:isKeyWindow] set];
[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)];
// 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];
if (!centeredParagraphStyle) {
centeredParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
[centeredParagraphStyle setAlignment:NSTextAlignmentCenter];
}
[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(![cell isInOverflowMenu]){
[cell drawWithFrame:[cell frame] inView:bar];
}
}
}
#pragma mark -
#pragma mark Archiving
- (void)encodeWithCoder:(NSCoder *)aCoder
{
if ([aCoder allowsKeyedCoding]) {
[aCoder encodeObject:closeButton forKey:@"metalCloseButton"];
[aCoder encodeObject:closeButtonDown forKey:@"metalCloseButtonDown"];
[aCoder encodeObject:closeButtonOver forKey:@"metalCloseButtonOver"];
[aCoder encodeObject:closeButtonOverDark forKey:@"metalCloseButtonOverDark"];
[aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"];
}
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ([aDecoder allowsKeyedCoding]) {
closeButton = [[aDecoder decodeObjectForKey:@"metalCloseButton"] retain];
closeButtonDown = [[aDecoder decodeObjectForKey:@"metalCloseButtonDown"] retain];
closeButtonOver = [[aDecoder decodeObjectForKey:@"metalCloseButtonOver"] retain];
closeButtonOverDark = [[aDecoder decodeObjectForKey:@"metalCloseButtonOverDark"] retain];
_addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain];
}
return self;
}
@end
#endif
@@ -12,6 +12,7 @@
#import "PSMRolloverButton.h"
#import "PSMTabStyle.h"
#import "PSMMetalTabStyle.h"
#import "PSMMojaveTabStyle.h"
#import "PSMUnifiedTabStyle.h"
#import "PSMYosemiteTabStyle.h"
#import "PSMTabDragAssistant.h"
@@ -259,21 +260,29 @@
style = [[PSMUnifiedTabStyle alloc] init];
} else if([name isEqualToString:@"Yosemite"]){
style = [[PSMYosemiteTabStyle alloc] init];
#if HAS_MOJAVE_TAB_STYLE
} else if([name isEqualToString:@"Mojave"]){
style = [[PSMMojaveTabStyle alloc] init];
#endif
} else {
style = [[PSMMetalTabStyle alloc] init];
}
// restyle add tab button
if(_addTabButton){
NSImage *newButtonImage = [style addTabButtonImage];
if(newButtonImage)
[_addTabButton setUsualImage:newButtonImage];
newButtonImage = [style addTabButtonPressedImage];
if(newButtonImage)
[_addTabButton setAlternateImage:newButtonImage];
newButtonImage = [style addTabButtonRolloverImage];
if(newButtonImage)
[_addTabButton setRolloverImage:newButtonImage];
if ([style respondsToSelector:@selector(styleAddTabButton:)]) {
[style performSelector:@selector(styleAddTabButton:) withObject:_addTabButton];
} else {
NSImage *newButtonImage = [style addTabButtonImage];
if(newButtonImage)
[_addTabButton setUsualImage:newButtonImage];
newButtonImage = [style addTabButtonPressedImage];
if(newButtonImage)
[_addTabButton setAlternateImage:newButtonImage];
newButtonImage = [style addTabButtonRolloverImage];
if(newButtonImage)
[_addTabButton setRolloverImage:newButtonImage];
}
}
[self update];