Moved MacVim project to src/MacVim and removed runtime folder
[MacVim.git] / src / MacVim / PSMTabBarControl / source / PSMUnifiedTabStyle.m
blob3a5a35fe87b0d0a7e724d308436863b725e9dfdd
1 //
2 //  PSMUnifiedTabStyle.m
3 //  --------------------
4 //
5 //  Created by Keith Blount on 30/04/2006.
6 //  Copyright 2006 __MyCompanyName__. All rights reserved.
7 //
9 #import "PSMUnifiedTabStyle.h"
10 #import "PSMTabBarCell.h"
11 #import "PSMTabBarControl.h"
12 #import "NSBezierPath_AMShading.h"
14 #define kPSMUnifiedObjectCounterRadius 7.0
15 #define kPSMUnifiedCounterMinWidth 20
17 @interface PSMUnifiedTabStyle (Private)
18 - (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView;
19 @end
21 @implementation PSMUnifiedTabStyle
23 - (NSString *)name
25     return @"Unified";
28 #pragma mark -
29 #pragma mark Creation/Destruction
31 - (id) init
33     if((self = [super init]))
34     {
35         unifiedCloseButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front"]];
36         unifiedCloseButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Pressed"]];
37         unifiedCloseButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabClose_Front_Rollover"]];
38         
39         _addTabButtonImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNew"]];
40         _addTabButtonPressedImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNewPressed"]];
41         _addTabButtonRolloverImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"AquaTabNewRollover"]];
42     
43                 leftMargin = 5.0;
44         }
45     return self;
48 - (void)dealloc
50     [unifiedCloseButton release];
51     [unifiedCloseButtonDown release];
52     [unifiedCloseButtonOver release];
53     [_addTabButtonImage release];
54     [_addTabButtonPressedImage release];
55     [_addTabButtonRolloverImage release];
56     
57     [super dealloc];
60 #pragma mark -
61 #pragma mark Control Specific
63 - (void)setLeftMarginForTabBarControl:(float)margin
65         leftMargin = margin;
68 - (float)leftMarginForTabBarControl
70     return leftMargin;
73 - (float)rightMarginForTabBarControl
75     return 24.0f;
78 #pragma mark -
79 #pragma mark Add Tab Button
81 - (NSImage *)addTabButtonImage
83     return _addTabButtonImage;
86 - (NSImage *)addTabButtonPressedImage
88     return _addTabButtonPressedImage;
91 - (NSImage *)addTabButtonRolloverImage
93     return _addTabButtonRolloverImage;
96 #pragma mark -
97 #pragma mark Cell Specific
99 - (NSRect) closeButtonRectForTabCell:(PSMTabBarCell *)cell
101     NSRect cellFrame = [cell frame];
102     
103     if ([cell hasCloseButton] == NO) {
104         return NSZeroRect;
105     }
106     
107     NSRect result;
108     result.size = [unifiedCloseButton size];
109     result.origin.x = cellFrame.origin.x + MARGIN_X;
110     result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
111     
112     return result;
115 - (NSRect)iconRectForTabCell:(PSMTabBarCell *)cell
117     NSRect cellFrame = [cell frame];
118     
119     if ([cell hasIcon] == NO) {
120         return NSZeroRect;
121     }
122     
123     NSRect result;
124     result.size = NSMakeSize(kPSMTabBarIconWidth, kPSMTabBarIconWidth);
125     result.origin.x = cellFrame.origin.x + MARGIN_X;
126     result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
127     
128     if([cell hasCloseButton] && ![cell isCloseButtonSuppressed])
129         result.origin.x += [unifiedCloseButton size].width + kPSMTabBarCellPadding;
131     return result;
134 - (NSRect)indicatorRectForTabCell:(PSMTabBarCell *)cell
136     NSRect cellFrame = [cell frame];
137     
138     if ([[cell indicator] isHidden]) {
139         return NSZeroRect;
140     }
141     
142     NSRect result;
143     result.size = NSMakeSize(kPSMTabBarIndicatorWidth, kPSMTabBarIndicatorWidth);
144     result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - kPSMTabBarIndicatorWidth;
145     result.origin.y = cellFrame.origin.y + MARGIN_Y - 1.0;
146      
147     return result;
150 - (NSRect)objectCounterRectForTabCell:(PSMTabBarCell *)cell
152     NSRect cellFrame = [cell frame];
153     
154     if ([cell count] == 0) {
155         return NSZeroRect;
156     }
157     
158     float countWidth = [[self attributedObjectCountValueForTabCell:cell] size].width;
159     countWidth += (2 * kPSMUnifiedObjectCounterRadius - 6.0);
160     if(countWidth < kPSMUnifiedCounterMinWidth)
161         countWidth = kPSMUnifiedCounterMinWidth;
162     
163     NSRect result;
164     result.size = NSMakeSize(countWidth, 2 * kPSMUnifiedObjectCounterRadius); // temp
165     result.origin.x = cellFrame.origin.x + cellFrame.size.width - MARGIN_X - result.size.width;
166     result.origin.y = cellFrame.origin.y + MARGIN_Y + 1.0;
167     
168     if(![[cell indicator] isHidden])
169         result.origin.x -= kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding;
170     
171     return result;
175 - (float)minimumWidthOfTabCell:(PSMTabBarCell *)cell
177     float resultWidth = 0.0;
178     
179     // left margin
180     resultWidth = MARGIN_X;
181     
182     // close button?
183     if([cell hasCloseButton] && ![cell isCloseButtonSuppressed])
184         resultWidth += [unifiedCloseButton size].width + kPSMTabBarCellPadding;
185     
186     // icon?
187     if([cell hasIcon])
188         resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding;
189     
190     // the label
191     resultWidth += kPSMMinimumTitleWidth;
192     
193     // object counter?
194     if([cell count] > 0)
195         resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding;
196     
197     // indicator?
198     if ([[cell indicator] isHidden] == NO)
199         resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth;
200     
201     // right margin
202     resultWidth += MARGIN_X;
203     
204     return ceil(resultWidth);
207 - (float)desiredWidthOfTabCell:(PSMTabBarCell *)cell
209     float resultWidth = 0.0;
210     
211     // left margin
212     resultWidth = MARGIN_X;
213     
214     // close button?
215     if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed])
216         resultWidth += [unifiedCloseButton size].width + kPSMTabBarCellPadding;
217     
218     // icon?
219     if([cell hasIcon])
220         resultWidth += kPSMTabBarIconWidth + kPSMTabBarCellPadding;
221     
222     // the label
223     resultWidth += [[cell attributedStringValue] size].width;
224     
225     // object counter?
226     if([cell count] > 0)
227         resultWidth += [self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding;
228     
229     // indicator?
230     if ([[cell indicator] isHidden] == NO)
231         resultWidth += kPSMTabBarCellPadding + kPSMTabBarIndicatorWidth;
232     
233     // right margin
234     resultWidth += MARGIN_X;
235     
236     return ceil(resultWidth);
239 #pragma mark -
240 #pragma mark Cell Values
242 - (NSAttributedString *)attributedObjectCountValueForTabCell:(PSMTabBarCell *)cell
244     NSMutableAttributedString *attrStr;
245     NSFontManager *fm = [NSFontManager sharedFontManager];
246     NSNumberFormatter *nf = [[[NSNumberFormatter alloc] init] autorelease];
247     [nf setLocalizesFormat:YES];
248     [nf setFormat:@"0"];
249     [nf setHasThousandSeparators:YES];
250     NSString *contents = [nf stringFromNumber:[NSNumber numberWithInt:[cell count]]];
251     attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
252     NSRange range = NSMakeRange(0, [contents length]);
253     
254     // Add font attribute
255     [attrStr addAttribute:NSFontAttributeName value:[fm convertFont:[NSFont fontWithName:@"Helvetica" size:11.0] toHaveTrait:NSBoldFontMask] range:range];
256     [attrStr addAttribute:NSForegroundColorAttributeName value:[[NSColor whiteColor] colorWithAlphaComponent:0.85] range:range];
257     
258     return attrStr;
261 - (NSAttributedString *)attributedStringValueForTabCell:(PSMTabBarCell *)cell
263     NSMutableAttributedString *attrStr;
264     NSString * contents = [cell stringValue];
265     attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
266     NSRange range = NSMakeRange(0, [contents length]);
267     
268     [attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] range:range];
269     
270     // Paragraph Style for Truncating Long Text
271     static NSMutableParagraphStyle *TruncatingTailParagraphStyle = nil;
272     if (!TruncatingTailParagraphStyle) {
273         TruncatingTailParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
274         [TruncatingTailParagraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
275     }
276     [attrStr addAttribute:NSParagraphStyleAttributeName value:TruncatingTailParagraphStyle range:range];
277     
278     return attrStr;     
281 #pragma mark -
282 #pragma mark ---- drawing ----
284 - (void)drawTabCell:(PSMTabBarCell *)cell
286     NSRect cellFrame = [cell frame];    
287     NSColor * lineColor = nil;
288     NSBezierPath* bezier = [NSBezierPath bezierPath];
289     lineColor = [NSColor colorWithCalibratedWhite:0.576 alpha:1.0];
291     if ([cell state] == NSOnState)
292         {
293         // selected tab
294         NSRect aRect = NSMakeRect(cellFrame.origin.x+0.5, cellFrame.origin.y-0.5, cellFrame.size.width-1.0, cellFrame.size.height);
295         aRect.size.height -= 0.5;
296         
297         aRect.size.height+=0.5;
298         
299         // frame
300                 float radius = MIN(6.0, 0.5f * MIN(NSWidth(aRect), NSHeight(aRect)));
301                 NSRect rect = NSInsetRect(aRect, radius, radius);
302                 
303                 [bezier appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMinY(rect)) radius:radius startAngle:180.0 endAngle:270.0];
304                 
305                 [bezier appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMinY(rect)) radius:radius startAngle:270.0 endAngle:360.0];
306                 
307                 NSPoint cornerPoint = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect));
308                 [bezier appendBezierPathWithPoints:&cornerPoint count:1];
309                 
310                 cornerPoint = NSMakePoint(NSMinX(aRect), NSMaxY(aRect));
311                 [bezier appendBezierPathWithPoints:&cornerPoint count:1];
312                 
313                 [bezier closePath];
314                 
315                 //[[NSColor windowBackgroundColor] set];
316                 //[bezier fill];
317                 [bezier linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.99 alpha:1.0]
318                                                                                 endColor:[NSColor colorWithCalibratedWhite:0.941 alpha:1.0]];
319                 
320                 [lineColor set];
321         [bezier stroke];
322     }
323         else
324         {
325         // unselected tab
326         NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
327         aRect.origin.y += 0.5;
328         aRect.origin.x += 1.5;
329         aRect.size.width -= 1;
330                 
331                 aRect.origin.x -= 1;
332         aRect.size.width += 1;
333         
334         // rollover
335         if ([cell isHighlighted])
336                 {
337             [[NSColor colorWithCalibratedWhite:0.0 alpha:0.1] set];
338             NSRectFillUsingOperation(aRect, NSCompositeSourceAtop);
339         }
340         
341         // frame
342                 
343         [lineColor set];
344         [bezier moveToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y-0.5)];
345                 if(!([cell tabState] & PSMTab_RightIsSelectedMask)){
346             [bezier lineToPoint:NSMakePoint(NSMaxX(aRect), NSMaxY(aRect))];
347         }
348                  
349         [bezier stroke];
350                 
351                 // Create a thin lighter line next to the dividing line for a bezel effect
352                 if(!([cell tabState] & PSMTab_RightIsSelectedMask)){
353                         [[[NSColor whiteColor] colorWithAlphaComponent:0.5] set];
354                         [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMaxX(aRect)+1.0, aRect.origin.y-0.5)
355                                                                           toPoint:NSMakePoint(NSMaxX(aRect)+1.0, NSMaxY(aRect)-2.5)];
356                 }
357                 
358                 // If this is the leftmost tab, we want to draw a line on the left, too
359                 if ([cell tabState] & PSMTab_PositionLeftMask)
360                 {
361                         [lineColor set];
362                         [NSBezierPath strokeLineFromPoint:NSMakePoint(aRect.origin.x,aRect.origin.y-0.5)
363                                                                           toPoint:NSMakePoint(aRect.origin.x,NSMaxY(aRect)-2.5)];
364                         [[[NSColor whiteColor] colorWithAlphaComponent:0.5] set];
365                         [NSBezierPath strokeLineFromPoint:NSMakePoint(aRect.origin.x+1.0,aRect.origin.y-0.5)
366                                                                           toPoint:NSMakePoint(aRect.origin.x+1.0,NSMaxY(aRect)-2.5)];
367                 }
368         }
369     
370     [self drawInteriorWithTabCell:cell inView:[cell controlView]];
375 - (void)drawInteriorWithTabCell:(PSMTabBarCell *)cell inView:(NSView*)controlView
377     NSRect cellFrame = [cell frame];
378     float labelPosition = cellFrame.origin.x + MARGIN_X;
379     
380     // close button
381     if ([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) {
382         NSSize closeButtonSize = NSZeroSize;
383         NSRect closeButtonRect = [cell closeButtonRectForFrame:cellFrame];
384         NSImage * closeButton = nil;
385         
386         closeButton = unifiedCloseButton;
387         if ([cell closeButtonOver]) closeButton = unifiedCloseButtonOver;
388         if ([cell closeButtonPressed]) closeButton = unifiedCloseButtonDown;
389         
390         closeButtonSize = [closeButton size];
391         if ([controlView isFlipped]) {
392             closeButtonRect.origin.y += closeButtonRect.size.height;
393         }
394         
395         [closeButton compositeToPoint:closeButtonRect.origin operation:NSCompositeSourceOver fraction:1.0];
396         
397         // scoot label over
398         labelPosition += closeButtonSize.width + kPSMTabBarCellPadding;
399     }
400     
401     // icon
402     if([cell hasIcon]){
403         NSRect iconRect = [self iconRectForTabCell:cell];
404         NSImage *icon = [[[[cell representedObject] identifier] content] icon];
405         if ([controlView isFlipped]) {
406             iconRect.origin.y = cellFrame.size.height - iconRect.origin.y;
407         }
408         [icon compositeToPoint:iconRect.origin operation:NSCompositeSourceOver fraction:1.0];
409         
410         // scoot label over
411         labelPosition += iconRect.size.width + kPSMTabBarCellPadding;
412     }
413     
414     // object counter
415     if([cell count] > 0){
416         [[NSColor colorWithCalibratedWhite:0.3 alpha:0.6] set];
417         NSBezierPath *path = [NSBezierPath bezierPath];
418         NSRect myRect = [self objectCounterRectForTabCell:cell];
419                 myRect.origin.y -= 1.0;
420         [path moveToPoint:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y)];
421         [path lineToPoint:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMUnifiedObjectCounterRadius, myRect.origin.y)];
422         [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + myRect.size.width - kPSMUnifiedObjectCounterRadius, myRect.origin.y + kPSMUnifiedObjectCounterRadius) radius:kPSMUnifiedObjectCounterRadius startAngle:270.0 endAngle:90.0];
423         [path lineToPoint:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y + myRect.size.height)];
424         [path appendBezierPathWithArcWithCenter:NSMakePoint(myRect.origin.x + kPSMUnifiedObjectCounterRadius, myRect.origin.y + kPSMUnifiedObjectCounterRadius) radius:kPSMUnifiedObjectCounterRadius startAngle:90.0 endAngle:270.0];
425         [path fill];
426         
427         // draw attributed string centered in area
428         NSRect counterStringRect;
429         NSAttributedString *counterString = [self attributedObjectCountValueForTabCell:cell];
430         counterStringRect.size = [counterString size];
431         counterStringRect.origin.x = myRect.origin.x + ((myRect.size.width - counterStringRect.size.width) / 2.0) + 0.25;
432         counterStringRect.origin.y = myRect.origin.y + ((myRect.size.height - counterStringRect.size.height) / 2.0) + 0.5;
433         [counterString drawInRect:counterStringRect];
434     }
435     
436     // label rect
437     NSRect labelRect;
438     labelRect.origin.x = labelPosition;
439     labelRect.size.width = cellFrame.size.width - (labelRect.origin.x - cellFrame.origin.x) - kPSMTabBarCellPadding;
440         NSSize s = [[cell attributedStringValue] size];
441         labelRect.origin.y = cellFrame.origin.y + (cellFrame.size.height-s.height)/2.0 - 1.0;
442         labelRect.size.height = s.height;
443     
444     if(![[cell indicator] isHidden])
445         labelRect.size.width -= (kPSMTabBarIndicatorWidth + kPSMTabBarCellPadding);
446     
447     if([cell count] > 0)
448         labelRect.size.width -= ([self objectCounterRectForTabCell:cell].size.width + kPSMTabBarCellPadding);
449     
450     // label
451     [[cell attributedStringValue] drawInRect:labelRect];
454 - (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect
456         NSRect gradientRect = rect;
457         gradientRect.size.height -= 1.0;
458         NSBezierPath *path = [NSBezierPath bezierPathWithRect:gradientRect];
459         [path linearGradientFillWithStartColor:[NSColor colorWithCalibratedWhite:0.918 alpha:1.0]
460                                                                   endColor:[NSColor colorWithCalibratedWhite:0.843 alpha:1.0]];
461         [[NSColor colorWithCalibratedWhite:0.576 alpha:1.0] set];
462         [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x,NSMaxY(rect)-0.5)
463                                                           toPoint:NSMakePoint(NSMaxX(rect),NSMaxY(rect)-0.5)];
464         
465     // no tab view == not connected
466     if(![bar tabView]){
467         NSRect labelRect = rect;
468         labelRect.size.height -= 4.0;
469         labelRect.origin.y += 4.0;
470         NSMutableAttributedString *attrStr;
471         NSString *contents = @"PSMTabBarControl";
472         attrStr = [[[NSMutableAttributedString alloc] initWithString:contents] autorelease];
473         NSRange range = NSMakeRange(0, [contents length]);
474         [attrStr addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:11.0] range:range];
475         NSMutableParagraphStyle *centeredParagraphStyle = nil;
476         if (!centeredParagraphStyle) {
477             centeredParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
478             [centeredParagraphStyle setAlignment:NSCenterTextAlignment];
479         }
480         [attrStr addAttribute:NSParagraphStyleAttributeName value:centeredParagraphStyle range:range];
481         [attrStr drawInRect:labelRect];
482         return;
483     }
484     
485     // draw cells
486     NSEnumerator *e = [[bar cells] objectEnumerator];
487     PSMTabBarCell *cell;
488     while(cell = [e nextObject]){
489         if(![cell isInOverflowMenu]){
490             [cell drawWithFrame:[cell frame] inView:bar];
491         }
492     }
493 }       
495 #pragma mark -
496 #pragma mark Archiving
498 - (void)encodeWithCoder:(NSCoder *)aCoder 
500     //[super encodeWithCoder:aCoder];
501     if ([aCoder allowsKeyedCoding]) {
502         [aCoder encodeObject:unifiedCloseButton forKey:@"unifiedCloseButton"];
503         [aCoder encodeObject:unifiedCloseButtonDown forKey:@"unifiedCloseButtonDown"];
504         [aCoder encodeObject:unifiedCloseButtonOver forKey:@"unifiedCloseButtonOver"];
505         [aCoder encodeObject:_addTabButtonImage forKey:@"addTabButtonImage"];
506         [aCoder encodeObject:_addTabButtonPressedImage forKey:@"addTabButtonPressedImage"];
507         [aCoder encodeObject:_addTabButtonRolloverImage forKey:@"addTabButtonRolloverImage"];
508     }
511 - (id)initWithCoder:(NSCoder *)aDecoder 
513    // self = [super initWithCoder:aDecoder];
514     //if (self) {
515         if ([aDecoder allowsKeyedCoding]) {
516             unifiedCloseButton = [[aDecoder decodeObjectForKey:@"unifiedCloseButton"] retain];
517             unifiedCloseButtonDown = [[aDecoder decodeObjectForKey:@"unifiedCloseButtonDown"] retain];
518             unifiedCloseButtonOver = [[aDecoder decodeObjectForKey:@"unifiedCloseButtonOver"] retain];
519             _addTabButtonImage = [[aDecoder decodeObjectForKey:@"addTabButtonImage"] retain];
520             _addTabButtonPressedImage = [[aDecoder decodeObjectForKey:@"addTabButtonPressedImage"] retain];
521             _addTabButtonRolloverImage = [[aDecoder decodeObjectForKey:@"addTabButtonRolloverImage"] retain];
522         }
523     //}
524     return self;
527 @end