Put NSAutoreleasePool usage around other distributed notification observer methods
[adiumx.git] / Source / AIHoveringPopUpButtonCell.m
blob7f3109293dcaefcac3398216169bda3457d9cd8e
1 //
2 //  AIHoveringPopUpButtonCell.m
3 //  Adium
4 //
5 //  Created by Evan Schoenberg on 12/16/05.
6 //
8 #import "AIHoveringPopUpButtonCell.h"
9 #import <AIUtilities/AIParagraphStyleAdditions.h>
10 #import <AIUtilities/AIBezierPathAdditions.h>
11 #import <AIUtilities/AIColorAdditions.h>
12 #import <AIUtilities/AIImageAdditions.h>
14 #include <Carbon/Carbon.h>
16 #define LEFT_MARGIN             5
17 #define IMAGE_MARGIN    4
18 #define ARROW_WIDTH             8
19 #define ARROW_HEIGHT    (ARROW_WIDTH/2.0)
20 #define ARROW_XOFFSET   5
21 #define RIGHT_MARGIN    5
23 @implementation AIHoveringPopUpButtonCell
25 - (void)commonInit
27         title = nil;
28         currentImage = nil;
29         textSize = NSZeroSize;
30         imageSize = NSZeroSize;
31         hovered = NO;
32         hoveredFraction = 0.0;
34         statusParagraphStyle = [[NSMutableParagraphStyle styleWithAlignment:NSLeftTextAlignment
35                                                                                                                   lineBreakMode:NSLineBreakByTruncatingTail] retain];
36         
37         statusAttributes = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
38                 statusParagraphStyle, NSParagraphStyleAttributeName,
39                 [NSFont systemFontOfSize:10], NSFontAttributeName, 
40                 nil] retain];   
43 - (id)initTextCell:(NSString *)str
45         if ((self = [super initTextCell:str])) {
46                 [self commonInit];
47         }
48         
49         return self;    
51 - (id)initImageCell:(NSImage *)image
53         if ((self = [super initImageCell:image])) {
54                 [self commonInit];
55         }
56         
57         return self;    
60 - (id)copyWithZone:(NSZone *)zone
62         AIHoveringPopUpButtonCell       *newCell = [[self class] allocWithZone:zone];
64         switch ([self type]) {
65                 case NSImageCellType:
66                         newCell = [newCell initImageCell:[self image]];
67                         break;
68                 case NSTextCellType:
69                         newCell = [newCell initTextCell:[self stringValue]];
70                         break;
71                 default:
72                         newCell = [newCell init]; //and hope for the best
73                         break;
74         }
75         
76         [newCell setMenu:[[[self menu] copy] autorelease]];
77         [newCell->title retain];
78         [newCell->currentImage retain];
79         [newCell->statusParagraphStyle retain];
80         [newCell->statusAttributes retain];
81         
82         return newCell;
85 - (void)dealloc
86 {       
87         /* Super's implementation calls setImage:nil in 10.4; we shouldn't depend on this implementation detail but should
88          * set our ivars to nil to ensure we don't double-release.
89          */
90         [title release]; title = nil;
91         [currentImage release]; currentImage = nil;
93         [statusParagraphStyle release];
94         [statusAttributes release];
96         [super dealloc];
99 - (void)setTitle:(NSString *)inTitleString
101         [title release];
103         //Strip out all newlines
104         inTitleString = [inTitleString stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\n\r"]];
106         if (inTitleString && [inTitleString length]) {
107                 title = [[NSMutableAttributedString alloc] initWithString:inTitleString
108                                                                                                            attributes:statusAttributes];
109                 textSize = [title size];
110         } else {
111                 title = nil;
112                 textSize = NSZeroSize;
113         }
116 - (void)setFont:(NSFont *)inFont
118         NSString *oldTitleString = [[title string] copy];
120         [statusAttributes setObject:inFont
121                                                  forKey:NSFontAttributeName];
122         [self setTitle:oldTitleString];
123         [oldTitleString release];
124         
125         [super setFont:inFont];
128 -(void)setImage:(NSImage *)inImage
130         if (inImage != currentImage) {
131                 [currentImage release];
132                 currentImage = [inImage retain];
133                 
134                 imageSize = [currentImage size];
135         }       
138 - (void)fadeHovered:(NSControl *)currentControlView
140         if (hovered) {
141                 if (hoveredFraction < 1.0) hoveredFraction += 0.05;
142         } else {
143                 if (hoveredFraction > 0.0) hoveredFraction -= 0.05;
144         }
146         [currentControlView setNeedsDisplay:YES];
148         if ((hoveredFraction > 0.0) &&
149                 (hoveredFraction < 1.0)) {
150                 [currentControlView retain];
151                 [NSObject cancelPreviousPerformRequestsWithTarget:self
152                                                                                                  selector:@selector(fadeHovered:)
153                                                                                                    object:currentControlView];
154                 
155                 [self performSelector:@selector(fadeHovered:)
156                                    withObject:currentControlView
157                                    afterDelay:0];
158                 [currentControlView release];
159         }
162 - (void)setHovered:(BOOL)inHovered animate:(BOOL)animate
164         if (animate && (hovered != inHovered)) {
165                 hovered = inHovered;
167                 hoveredFraction = (hovered ? 0.80 : 0.20);
168                 
169                 [NSObject cancelPreviousPerformRequestsWithTarget:self
170                                                                                                  selector:@selector(fadeHovered:)
171                                                                                                    object:[self controlView]];
172                 [self performSelector:@selector(fadeHovered:)
173                                    withObject:[self controlView]
174                                    afterDelay:0];
175         } else {
176                 hovered = inHovered;
178                 hoveredFraction = (hovered ? 1.0 : 0.0);
179                 [[self controlView] setNeedsDisplay:YES];       
180         }
183 - (BOOL)hovered
185         return hovered;
188 #pragma mark Drawing
190 //for some unknown reason, NSButtonCell's -drawWithFrame:inView: draws a basic ridge border on the bottom-right if we do not override it.
191 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
193         [self drawInteriorWithFrame:cellFrame inView:controlView];
196 - (float)trackingWidth
198         float trackingWidth;
199         
200         trackingWidth = LEFT_MARGIN + [title size].width + RIGHT_MARGIN;
201         if ([self menu]) {
202                 trackingWidth += ARROW_XOFFSET + ARROW_WIDTH;
203         }
204         if (currentImage) {
205                 trackingWidth += imageSize.width + IMAGE_MARGIN;
206         }
207         
208         return trackingWidth;
211 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
213         NSRect  textRect;
214         NSColor *drawingColor;
215         NSMenu  *myMenu = [self menu];
216         float   maxTextWidth;
218         [statusParagraphStyle setMaximumLineHeight:cellFrame.size.height];
220         textRect = NSMakeRect(cellFrame.origin.x + LEFT_MARGIN,
221                                                   cellFrame.origin.y + ((cellFrame.size.height - textSize.height) / 2),
222                                                   textSize.width,
223                                                   textSize.height);
224         maxTextWidth = (cellFrame.size.width - LEFT_MARGIN - RIGHT_MARGIN);
226         if (currentImage) {
227                 textRect.origin.x += (imageSize.width + IMAGE_MARGIN);
228                 maxTextWidth -= (imageSize.width + IMAGE_MARGIN);
229         }
231         if (myMenu) {
232                 maxTextWidth -= (ARROW_XOFFSET + ARROW_WIDTH);
233         }
235         if (textRect.size.width > maxTextWidth) {
236                 textRect.size.width = maxTextWidth;
237         }
239         if (hovered || (hoveredFraction > 0.0)) {
240                 //Draw our hovered / highlighted background first
241                 NSBezierPath    *path;
242                 
243                 float backgroundWidth = LEFT_MARGIN + textRect.size.width + RIGHT_MARGIN;
244                 
245                 if (myMenu) {
246                         backgroundWidth += (ARROW_XOFFSET + ARROW_WIDTH);
247                 }
248                 if (currentImage) {
249                         backgroundWidth += imageSize.width + IMAGE_MARGIN;
250                 }
252                 path = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(cellFrame.origin.x,
253                                                                                                                                   cellFrame.origin.y,
254                                                                                                                                   backgroundWidth,
255                                                                                                                                   cellFrame.size.height)
256                                                                                                 radius:10];
257                 
258                 if ([self isHighlighted]) {
259                         [[[NSColor darkGrayColor] colorWithAlphaComponent:hoveredFraction] set];
261                 } else {
262                         [[[NSColor grayColor]  colorWithAlphaComponent:hoveredFraction] set];
263                 }
265                 [path fill];
266                 
267                 if (hovered) {
268                         drawingColor = [NSColor whiteColor];
269                 } else {
270                         drawingColor = [NSColor blackColor];
271                 }
272         } else {
273                 drawingColor = [NSColor blackColor];
274         }
275         
276         if (currentImage) {
277                 [currentImage drawInRect:NSMakeRect(cellFrame.origin.x + LEFT_MARGIN,
278                                                                                         cellFrame.origin.y,
279                                                                                         imageSize.width + IMAGE_MARGIN,
280                                                                                         cellFrame.size.height)
281                                                   atSize:imageSize
282                                                 position:IMAGE_POSITION_LEFT
283                                                 fraction:1.0];
284         }
286         [statusAttributes setObject:drawingColor
287                                                  forKey:NSForegroundColorAttributeName];
288         [title setAttributes:statusAttributes
289                                    range:NSMakeRange(0, [title length])];
290         [title drawInRect:textRect];
291         
292         //Draw the arrow
293         if (myMenu) {
294                 NSBezierPath *arrowPath = [NSBezierPath bezierPath];
295         
296                 [arrowPath moveToPoint:NSMakePoint(NSMaxX(textRect) + ARROW_XOFFSET, 
297                                                                                    (NSMaxY(cellFrame) / 2) - (ARROW_HEIGHT / 2))];
298                 [arrowPath relativeLineToPoint:NSMakePoint(ARROW_WIDTH, 0)];
299                 [arrowPath relativeLineToPoint:NSMakePoint(-(ARROW_WIDTH/2), (ARROW_HEIGHT))];
301                 [drawingColor set];
302                 [arrowPath fill];
303         }
306 - (BOOL)isOpaque
308     return NO;
311 @end