Moved MacVim project to src/MacVim and removed runtime folder
[MacVim/jjgod.git] / src / MacVim / PSMTabBarControl / source / PSMMetalTabStyle.m
blob2b2bce45c2f7c5f26dfb11753dd45efbaba40cfb
1 //
2 //  PSMMetalTabStyle.m
3 //  PSMTabBarControl
4 //
5 //  Created by John Pannell on 2/17/06.
6 //  Copyright 2006 Positive Spin Media. All rights reserved.
7 //
9 #import "PSMMetalTabStyle.h"
10 #import "PSMTabBarCell.h"
11 #import "PSMTabBarControl.h"
13 #define kPSMMetalObjectCounterRadius 7.0
14 #define kPSMMetalCounterMinWidth 20
16 // NSDrawWindowBackground() is broken for borderless windows, see
17 // http://lists.apple.com/archives/cocoa-dev/2006/Feb/msg00130.html
18 void MyNSDrawWindowBackground(NSRect rect)
20     [[NSColor windowBackgroundColor] set];
21     NSRectFill( rect );
24 @implementation PSMMetalTabStyle
26 - (NSString *)name
28     return @"Metal";
31 #pragma mark -
32 #pragma mark Creation/Destruction
34 - (id) init
36     //NSLog(@"PSMMetalTabStyle init");
38     if((self = [super init]))
39     {
41         metalCloseButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Front"]];
42         //NSLog(@"metalCloseButton=%@ path=%@", metalCloseButton,
43         //        [[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Front"]);
44         metalCloseButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Front_Pressed"]];
45         metalCloseButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabClose_Front_Rollover"]];
46         
47         _addTabButtonImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabNewMetal"]];
48         _addTabButtonPressedImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabNewMetalPressed"]];
49         _addTabButtonRolloverImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"TabNewMetalRollover"]];
50     }
51     return self;
54 - (void)dealloc
56     [metalCloseButton release];
57     [metalCloseButtonDown release];
58     [metalCloseButtonOver release];
59     [_addTabButtonImage release];
60     [_addTabButtonPressedImage release];
61     [_addTabButtonRolloverImage release];
62     
63     [super dealloc];
66 #pragma mark -
67 #pragma mark Control Specific
69 - (float)leftMarginForTabBarControl
71     return 10.0f;
74 - (float)rightMarginForTabBarControl
76     return 24.0f;
79 #pragma mark -
80 #pragma mark Add Tab Button
82 - (NSImage *)addTabButtonImage
84     return _addTabButtonImage;
87 - (NSImage *)addTabButtonPressedImage
89     return _addTabButtonPressedImage;
92 - (NSImage *)addTabButtonRolloverImage
94     return _addTabButtonRolloverImage;
97 #pragma mark -
98 #pragma mark Cell Specific
100 - (NSRect) closeButtonRectForTabCell:(PSMTabBarCell *)cell
102     NSRect cellFrame = [cell frame];
103     
104     if ([cell hasCloseButton] == NO) {
105         return NSZeroRect;
106     }
107     
108     NSRect result;
109     result.size = [metalCloseButton size];
110     result.origin.x = cellFrame.origin.x + MARGIN_X;
111     result.origin.y = cellFrame.origin.y + MARGIN_Y + 2.0;
112     
113     if([cell state] == NSOnState){
114         result.origin.y -= 1;
115     }
116     
117     return result;
120 - (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell
122     NSRect cellFrame = [cell frame];
123     
124     if ([cell hasIcon] == NO) {
125         return NSZeroRect;
126     }
127     
128     NSRect result;
129     result.size = NSMakeSize(kPSMTabBarIconWidth, kPSMTabBarIconWidth);
130     result.origin.x = cellFrame.origin.x + MARGIN_X;
131     result.origin.y = cellFrame.origin.y + MARGIN_Y;
132     
133     if([cell hasCloseButton] && ![cell isCloseButtonSuppressed])
134         result.origin.x += [metalCloseButton size].width + kPSMTabBarCellPadding;
135     
136     if([cell state] == NSOnState){
137         result.origin.y += 1;
138     }
139     
140     return result;
143 - (NSRect)indicatorRectForTabCell:(PSMTabBarCell *)cell
145     NSRect cellFrame = [cell frame];
146     
147     if ([[cell indicator] isHidden]) {
148         return NSZeroRect;
149     }
150     
151     NSRect result;
152     result.size = NSMakeSize(kPSMTabBarIndicatorWidth, kPSMTabBarIndicatorWidth);
153     result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - kPSMTabBarIndicatorWidth;
154     result.origin.y = cellFrame.origin.y + MARGIN_Y;
155     
156     if([cell state] == NSOnState){
157         result.origin.y -= 1;
158     }
159     
160     return result;
163 - (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell
165     NSRect cellFrame = [cell frame];
166     
167     if ([cell count] == 0) {
168         return NSZeroRect;
169     }
170     
171     float countWidth = [[self attributedObjectCountValueForTabCell:cell] size].width;
172     countWidth += (2 * kPSMMetalObjectCounterRadius - 6.0);
173     if(countWidth < kPSMMetalCounterMinWidth)
174         countWidth = kPSMMetalCounterMinWidth;
175     
176     NSRect result;
177     result.size = NSMakeSize(countWidth, 2 * kPSMMetalObjectCounterRadius); // temp
178     result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - result.size.width;
179     result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
180     
181     if(![[cell indicator] isHidden])
182         result.origin.x -= kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding;
183     
184     return result;
188 - (float)minimumWidthOfTabCell:(PSMTabBarCell *)cell
190     float resultWidth = 0.0;
191     
192     // left margin
193     resultWidth = MARGIN_X;
194     
195     // close button?
196     if([cell hasCloseButton] && ![cell isCloseButtonSuppressed])
197         resultWidth += [metalCloseButton size].width + kPSMTabBarCellPadding;
198     
199     // icon?
200     if([cell hasIcon])
201         resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding;
202     
203     // the label
204     resultWidth += kPSMMinimumTitleWidth;
205     
206     // object counter?
207     if([cell count] > 0)
208         resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding;
209     
210     // indicator?
211     if ([[cell indicator] isHidden] == NO)
212         resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth;
213     
214     // right margin
215     resultWidth += MARGIN_X;
216     
217     return ceil(resultWidth);
220 - (float)desiredWidthOfTabCell:(PSMTabBarCell *)cell
222     float resultWidth = 0.0;
223     
224     // left margin
225     resultWidth = MARGIN_X;
226     
227     // close button?
228     if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed])
229         resultWidth += [metalCloseButton size].width + kPSMTabBarCellPadding;
230     
231     // icon?
232     if([cell hasIcon])
233         resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding;
234     
235     // the label
236     resultWidth += [[cell attributedStringValue] size].width;
237     
238     // object counter?
239     if([cell count] > 0)
240         resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding;
241     
242     // indicator?
243     if ([[cell indicator] isHidden] == NO)
244         resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth;
245     
246     // right margin
247     resultWidth += MARGIN_X;
248     
249     return ceil(resultWidth);
252 #pragma mark -
253 #pragma mark Cell Values
255 - (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell
257     NSMutableAttributedString *attrStr;
258     NSFontManager *fm = [NSFontManager sharedFontManager];
259     NSNumberFormatter *nf = [[[NSNumberFormatter alloc] init] autorelease];
260     [nf setLocalizesFormat:YES];
261     [nf setFormat:@"0"];
262     [nf setHasThousandSeparators:YES];
263     NSString *contents = [nf stringFromNumber:[NSNumber numberWithInt:[cell count]]];
264     attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
265     NSRange range = NSMakeRange(0, [contents length]);
266     
267     // Add font attribute
268     [attrStr addAttribute:NSFontAttributeName value:[fm convertFont:[NSFont fontWithName:@"Helvetica" size:11.0] toHaveTrait:NSBoldFontMask] range:range];
269     [attrStr addAttribute:NSForegroundColorAttributeName value:[[NSColor whiteColor] colorWithAlphaComponent:0.85] range:range];
270     
271     return attrStr;
274 - (NSAttributedString *)attributedStringValueForTabCell:(PSMTabBarCell *)cell
276     NSMutableAttributedString *attrStr;
277     NSString *contents = [cell stringValue];
278     attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
279     NSRange range = NSMakeRange(0, [contents length]);
280     
281     // Add font attribute
282     [attrStr addAttribute:NSFontAttributeName value:[NSFont boldSystemFontOfSize:11.0] range:range];
283     [attrStr addAttribute:NSForegroundColorAttributeName value:[[NSColor textColor] colorWithAlphaComponent:0.75] range:range];
284     
285     // Add shadow attribute
286     NSShadow* shadow;
287     shadow = [[[NSShadow alloc] init] autorelease];
288     float shadowAlpha;
289     if(([cell state] == NSOnState) || [cell isHighlighted]){
290         shadowAlpha = 0.8;
291     } else {
292         shadowAlpha = 0.5;
293     }
294     [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:shadowAlpha]];
295     [shadow setShadowOffset:NSMakeSize(0, -1)];
296     [shadow setShadowBlurRadius:1.0];
297     [attrStr addAttribute:NSShadowAttributeName value:shadow range:range];
298     
299     // Paragraph Style for Truncating Long Text
300     static NSMutableParagraphStyle *TruncatingTailParagraphStyle = nil;
301     if (!TruncatingTailParagraphStyle) {
302         TruncatingTailParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
303         [TruncatingTailParagraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
304         [TruncatingTailParagraphStyle setAlignment:NSCenterTextAlignment];
305     }
306     [attrStr addAttribute:NSParagraphStyleAttributeName value:TruncatingTailParagraphStyle range:range];
307     
308     return attrStr;
311 #pragma mark -
312 #pragma mark ---- drawing ----
314 - (void)drawTabCell:(PSMTabBarCell *)cell
316     NSRect cellFrame = [cell frame];    
317     NSColor * lineColor = nil;
318     NSBezierPath* bezier = [NSBezierPath bezierPath];
319     lineColor = [NSColor darkGrayColor];
321     if ([cell state] == NSOnState) {
322         // selected tab
323         NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height-2.5);
324         aRect.size.height -= 0.5;
325         
326         // background
327         MyNSDrawWindowBackground(aRect);
328         
329         aRect.size.height+=0.5;
330         
331         // frame
332         aRect.origin.x += 0.5;
333         [lineColor set];
334         [bezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y)];
335         [bezier lineToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y+aRect.size.height-1.5)];
336         [bezier lineToPoint:NSMakePoint(aRect.origin.x+1.5, aRect.origin.y+aRect.size.height)];
337         [bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width-1.5, aRect.origin.y+aRect.size.height)];
338         [bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width, aRect.origin.y+aRect.size.height-1.5)];
339         [bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width, aRect.origin.y)];
340         if([[cell controlView] frame].size.height < 2){
341             // special case of hidden control; need line across top of cell
342             [bezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y+0.5)];
343             [bezier lineToPoint:NSMakePoint(aRect.origin.x+aRect.size.width, aRect.origin.y+0.5)];
344         }
345         [bezier stroke];
346     } else {
347         
348         // unselected tab
349         NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
350         aRect.origin.y += 0.5;
351         aRect.origin.x += 1.5;
352         aRect.size.width -= 1;
353         
354         // rollover
355         if ([cell isHighlighted]) {
356             [[NSColor colorWithCalibratedWhite:0.0 alpha:0.1] set];
357             NSRectFillUsingOperation(aRect, NSCompositeSourceAtop);
358         }
359         
360         aRect.origin.x -= 1;
361         aRect.size.width += 1;
362         
363         // frame
364         [lineColor set];
365         [bezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y)];
366         [bezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y)];
367         if(!([cell tabState] & PSMTab_RightIsSelectedMask)){
368             [bezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y + aRect.size.height)];
369         }
370         [bezier stroke];
371     }
372     
373     [self drawInteriorWithTabCell:cell inView:[cell controlView]];
378 - (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView
380     NSRect cellFrame = [cell frame];
381     float labelPosition = cellFrame.origin.x + MARGIN_X;
382     
383     // close button
384     if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) {
385         NSSize closeButtonSize = NSZeroSize;
386         NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame];
387         NSImage * closeButton = nil;
388         
389         closeButton = metalCloseButton;
390         if ([cell closeButtonOver]) closeButton = metalCloseButtonOver;
391         if ([cell closeButtonPressed]) closeButton = metalCloseButtonDown;
392         
393         closeButtonSize = [closeButton size];
394         if ([controlView isFlipped]) {
395             closeButtonRect.origin.y += closeButtonRect.size.height;
396         }
397         
398         [closeButton compositeToPoint:closeButtonRect.origin operation:NSCompositeSourceOver fraction:1.0];
399         
400         // scoot label over
401         labelPosition += closeButtonSize.width + kPSMTabBarCellPadding;
402     }
403     
404     // icon
405     if([cell hasIcon]){
406         NSRect iconRect = [self iconRectForTabCell:cell];
407         NSImage *icon = [[[[cell representedObject] identifier] content] icon];
408         if ([controlView isFlipped]) {
409             iconRect.origin.y = cellFrame.size.height - iconRect.origin.y;
410         }
411         [icon compositeToPoint:iconRect.origin operation:NSCompositeSourceOver fraction:1.0];
412         
413         // scoot label over
414         labelPosition += iconRect.size.width + kPSMTabBarCellPadding;
415     }
416     
417     // object counter
418     if([cell count] > 0){
419         [[NSColor colorWithCalibratedWhite:0.3 alpha:0.6] set];
420         NSBezierPath *path = [NSBezierPath bezierPath];
421         NSRect myRect = [self objectCounterRectForTabCell:cell];
422         if([cell state] == NSOnState)
423             myRect.origin.y -= 1.0;
424         [path moveToPoint:NSMakePoint(myRect.origin.x + kPSMMetalObjectCounterRadius, myRect.origin.y)];
425         [path lineToPoint:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMMetalObjectCounterRadius, myRect.origin.y)];
426         [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMMetalObjectCounterRadius, myRect.origin.y + kPSMMetalObjectCounterRadius) radius:kPSMMetalObjectCounterRadius startAngle:270.0 endAngle:90.0];
427         [path lineToPoint:NSMakePoint(myRect.origin.x + kPSMMetalObjectCounterRadius, myRect.origin.y + myRect.size.height)];
428         [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + kPSMMetalObjectCounterRadius, myRect.origin.y + kPSMMetalObjectCounterRadius) radius:kPSMMetalObjectCounterRadius startAngle:90.0 endAngle:270.0];
429         [path fill];
430         
431         // draw attributed string centered in area
432         NSRect counterStringRect;
433         NSAttributedString *counterString = [self attributedObjectCountValueForTabCell:cell];
434         counterStringRect.size = [counterString size];
435         counterStringRect.origin.x = myRect.origin.x + ((myRect.size.width - counterStringRect.size.width) / 2.0) + 0.25;
436         counterStringRect.origin.y = myRect.origin.y + ((myRect.size.height - counterStringRect.size.height) / 2.0) + 0.5;
437         [counterString drawInRect:counterStringRect];
438     }
439     
440     // label rect
441     NSRect labelRect;
442     labelRect.origin.x = labelPosition;
443     labelRect.size.width = cellFrame.size.width - (labelRect.origin.x - cellFrame.origin.x) - kPSMTabBarCellPadding;
444     labelRect.size.height = cellFrame.size.height;
445     labelRect.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
446     
447     if([cell state] == NSOnState){
448         labelRect.origin.y -= 1;
449     }
450     
451     if(![[cell indicator] isHidden])
452         labelRect.size.width -= (kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding);
453     
454     if([cell count] > 0)
455         labelRect.size.width -= ([self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding);
456     
457     // label
458     [[cell attributedStringValue] drawInRect:labelRect];
461 - (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect
463     MyNSDrawWindowBackground(rect);
464     [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
465     NSRectFillUsingOperation(rect, NSCompositeSourceAtop);
466     [[NSColor darkGrayColor] set];
467     [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x,rect.origin.y+0.5) toPoint:NSMakePoint(rect.origin.x+rect.size.width,rect.origin.y+0.5)];
468     [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)];
469     
470     // no tab view == not connected
471     if(![bar tabView]){
472         NSRect labelRect = rect;
473         labelRect.size.height -= 4.0;
474         labelRect.origin.y += 4.0;
475         NSMutableAttributedString *attrStr;
476         NSString *contents = @"PSMTabBarControl";
477         attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
478         NSRange range = NSMakeRange(0, [contents length]);
479         [attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] range:range];
480         NSMutableParagraphStyle *centeredParagraphStyle = nil;
481         if (!centeredParagraphStyle) {
482             centeredParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
483             [centeredParagraphStyle setAlignment:NSCenterTextAlignment];
484         }
485         [attrStr addAttribute:NSParagraphStyleAttributeName value:centeredParagraphStyle range:range];
486         [attrStr drawInRect:labelRect];
487         return;
488     }
489     
490     // draw cells
491     NSEnumerator *e = [[bar cells] objectEnumerator];
492     PSMTabBarCell *cell;
493     while(cell = [e nextObject]){
494         if(![cell isInOverflowMenu]){
495             [cell drawWithFrame:[cell frame] inView:bar];
496         }
497     }
498 }       
500 #pragma mark -
501 #pragma mark Archiving
503 - (void)encodeWithCoder:(NSCoder *)aCoder 
505     //[super encodeWithCoder:aCoder];
506     if ([aCoder allowsKeyedCoding]) {
507         [aCoder encodeObject:metalCloseButton forKey:@"metalCloseButton"];
508         [aCoder encodeObject:metalCloseButtonDown forKey:@"metalCloseButtonDown"];
509         [aCoder encodeObject:metalCloseButtonOver forKey:@"metalCloseButtonOver"];
510         [aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"];
511         [aCoder encodeObject:_addTabButtonPressedImage forKey:@"addTabButtonPressedImage"];
512         [aCoder encodeObject:_addTabButtonRolloverImage forKey:@"addTabButtonRolloverImage"];
513     }
516 - (id)initWithCoder:(NSCoder *)aDecoder 
518    // self = [super initWithCoder:aDecoder];
519     //if (self) {
520         if ([aDecoder allowsKeyedCoding]) {
521             metalCloseButton = [[aDecoder decodeObjectForKey:@"metalCloseButton"] retain];
522             metalCloseButtonDown = [[aDecoder decodeObjectForKey:@"metalCloseButtonDown"] retain];
523             metalCloseButtonOver = [[aDecoder decodeObjectForKey:@"metalCloseButtonOver"] retain];
524             _addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain];
525             _addTabButtonPressedImage = [[aDecoder decodeObjectForKey:@"addTabButtonPressedImage"] retain];
526             _addTabButtonRolloverImage = [[aDecoder decodeObjectForKey:@"addTabButtonRolloverImage"] retain];
527         }
528     //}
529     return self;
532 @end