forked from macvim-dev/macvim
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMMTab.m
More file actions
177 lines (156 loc) · 6.72 KB
/
MMTab.m
File metadata and controls
177 lines (156 loc) · 6.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#import <QuartzCore/QuartzCore.h>
#import "MMTab.h"
#import "MMTabline.h"
#import "MMHoverButton.h"
// Only imported for AVAILABLE_MAC_OS
#import "MacVim.h"
#if !defined(MAC_OS_X_VERSION_10_13) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
typedef NSString * NSAnimatablePropertyKey;
#endif
@interface MMTab ()
@property (nonatomic) NSColor *fillColor;
@end
@implementation MMTab
{
MMTabline __weak *_tabline;
MMHoverButton *_closeButton;
NSTextField *_titleLabel;
}
@synthesize tag = _tag;
+ (id)defaultAnimationForKey:(NSAnimatablePropertyKey)key
{
if ([key isEqualToString:@"fillColor"]) {
CABasicAnimation *anim = [CABasicAnimation new];
anim.duration = 0.1;
return anim;
}
return [super defaultAnimationForKey:key];
}
- (instancetype)initWithFrame:(NSRect)frameRect tabline:(MMTabline *)tabline
{
self = [super initWithFrame:frameRect];
if (self) {
_tabline = tabline;
_closeButton = [MMHoverButton new];
_closeButton.image = [MMHoverButton imageFromType:MMHoverButtonImageCloseTab];
_closeButton.target = self;
_closeButton.action = @selector(closeTab:);
_closeButton.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_closeButton];
_titleLabel = [NSTextField new];
#if defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11
if (AVAILABLE_MAC_OS(10,11)) {
_titleLabel.font = [NSFont systemFontOfSize:NSFont.smallSystemFontSize weight:NSFontWeightSemibold];
} else
#endif
{
_titleLabel.font = [NSFont systemFontOfSize:NSFont.smallSystemFontSize];
}
_titleLabel.textColor = NSColor.controlTextColor;
_titleLabel.editable = NO;
_titleLabel.selectable = NO;
_titleLabel.bordered = NO;
_titleLabel.bezeled = NO;
_titleLabel.drawsBackground = NO;
_titleLabel.cell.lineBreakMode = NSLineBreakByTruncatingTail;
// Title can be compressed smaller than its contents. See centerConstraint
// below where priority is set less than here for compression resistance.
// This breaks centering and allows label to fill all available space.
[_titleLabel setContentCompressionResistancePriority:NSLayoutPriorityFittingSizeCompression+2 forOrientation:NSLayoutConstraintOrientationHorizontal];
_titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_titleLabel];
NSDictionary *viewDict = NSDictionaryOfVariableBindings(_closeButton, _titleLabel);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-9-[_closeButton]-(>=5)-[_titleLabel]-(>=16)-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:viewDict]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_titleLabel attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
NSLayoutConstraint *centerConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_titleLabel attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
centerConstraint.priority = NSLayoutPriorityFittingSizeCompression+1;
[self addConstraint:centerConstraint];
self.state = MMTabStateUnselected;
}
return self;
}
- (void)closeTab:(id)sender
{
[_tabline closeTab:self force:NO layoutImmediately:NO];
}
- (NSString *)title
{
return _titleLabel.stringValue;
}
- (void)setTitle:(NSString *)title
{
_titleLabel.stringValue = title;
}
- (void)setCloseButtonHidden:(BOOL)closeButtonHidden
{
_closeButtonHidden = closeButtonHidden;
_closeButton.hidden = closeButtonHidden;
}
- (void)setFillColor:(NSColor *)fillColor
{
_fillColor = fillColor;
self.needsDisplay = YES;
}
- (void)setState:(MMTabState)state
{
const BOOL hasFocus = (self.window == nil) || [self.window isKeyWindow];
// Transitions to and from MMTabStateSelected
// DO NOT animate so that UX feels snappier.
if (state == MMTabStateSelected) {
_closeButton.fgColor = _tabline.tablineSelFgColor;
_titleLabel.textColor = hasFocus ? _tabline.tablineSelFgColor : _tabline.tablineUnfocusedSelFgColor;
self.fillColor = _tabline.tablineSelBgColor;
}
else if (state == MMTabStateUnselected) {
if (_state == MMTabStateSelected) {
_closeButton.fgColor = _tabline.tablineFgColor;
_titleLabel.textColor = hasFocus ? _tabline.tablineFgColor : _tabline.tablineUnfocusedFgColor;
self.fillColor = _tabline.tablineBgColor;
} else {
_closeButton.animator.fgColor = _tabline.tablineFgColor;
_titleLabel.animator.textColor = hasFocus ? _tabline.tablineFgColor : _tabline.tablineUnfocusedFgColor;
self.animator.fillColor = _tabline.tablineBgColor;
}
}
else { // state == MMTabStateUnselectedHover
_closeButton.animator.fgColor = _tabline.tablineSelFgColor;
_titleLabel.animator.textColor = hasFocus ? _tabline.tablineSelFgColor : _tabline.tablineUnfocusedSelFgColor;
self.animator.fillColor = self.unselectedHoverColor;
}
_state = state;
}
- (NSColor *)unselectedHoverColor
{
return [_tabline.tablineSelBgColor blendedColorWithFraction:0.6 ofColor:_tabline.tablineBgColor];
}
- (void)drawRect:(NSRect)dirtyRect
{
[self.fillColor set];
CGFloat minX = MMTabShadowBlurRadius;
CGFloat maxX = NSMaxX(self.bounds);
CGFloat maxY = MMTablineHeight;
NSBezierPath *p = [NSBezierPath new];
[p moveToPoint:NSMakePoint(minX, 0)];
[p lineToPoint:NSMakePoint(minX + 3.6, maxY - 2.5)];
[p curveToPoint: NSMakePoint(minX + 6.5, maxY) controlPoint1: NSMakePoint(minX + 3.8, maxY - 1) controlPoint2: NSMakePoint(minX + 5.1, maxY)];
[p lineToPoint:NSMakePoint(maxX - 6.5 - minX, maxY)];
[p curveToPoint:NSMakePoint(maxX - 3.6 - minX, maxY - 2.5) controlPoint1: NSMakePoint(maxX - 5.1 - minX, maxY) controlPoint2: NSMakePoint(maxX - 3.8 - minX, maxY - 1)];
[p lineToPoint:NSMakePoint(maxX - minX, 0)];
[p closePath];
// On macOS 11, translate the tab down 1 pt to provide a thin
// line between the top of the tab and the window's title bar.
// It looks better given the new way macOS 11 draws title bars.
// Older macOS versions don't need this.
if (AVAILABLE_MAC_OS(11,0)) {
NSAffineTransform *transform = [NSAffineTransform new];
[transform translateXBy:0 yBy:-1.0];
[p transformUsingAffineTransform:transform];
}
[p fill];
NSColor *strokeColor = _tabline.tablineStrokeColor;
if (strokeColor != nil) {
[strokeColor set];
[p stroke];
}
}
@end