2 // AIHoveringPopUpButtonCell.m
5 // Created by Evan Schoenberg on 12/16/05.
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>
17 #define IMAGE_MARGIN 4
19 #define ARROW_HEIGHT (ARROW_WIDTH/2.0)
20 #define ARROW_XOFFSET 5
21 #define RIGHT_MARGIN 5
23 @implementation AIHoveringPopUpButtonCell
29 textSize = NSZeroSize;
30 imageSize = NSZeroSize;
32 hoveredFraction = 0.0;
34 statusParagraphStyle = [[NSMutableParagraphStyle styleWithAlignment:NSLeftTextAlignment
35 lineBreakMode:NSLineBreakByTruncatingTail] retain];
37 statusAttributes = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
38 statusParagraphStyle, NSParagraphStyleAttributeName,
39 [NSFont systemFontOfSize:10], NSFontAttributeName,
43 - (id)initTextCell:(NSString *)str
45 if ((self = [super initTextCell:str])) {
51 - (id)initImageCell:(NSImage *)image
53 if ((self = [super initImageCell:image])) {
60 - (id)copyWithZone:(NSZone *)zone
62 AIHoveringPopUpButtonCell *newCell = [[self class] allocWithZone:zone];
64 switch ([self type]) {
66 newCell = [newCell initImageCell:[self image]];
69 newCell = [newCell initTextCell:[self stringValue]];
72 newCell = [newCell init]; //and hope for the best
76 [newCell setMenu:[[[self menu] copy] autorelease]];
77 [newCell->title retain];
78 [newCell->currentImage retain];
79 [newCell->statusParagraphStyle retain];
80 [newCell->statusAttributes retain];
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.
90 [title release]; title = nil;
91 [currentImage release]; currentImage = nil;
93 [statusParagraphStyle release];
94 [statusAttributes release];
99 - (void)setTitle:(NSString *)inTitleString
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];
112 textSize = NSZeroSize;
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];
125 [super setFont:inFont];
128 -(void)setImage:(NSImage *)inImage
130 if (inImage != currentImage) {
131 [currentImage release];
132 currentImage = [inImage retain];
134 imageSize = [currentImage size];
138 - (void)fadeHovered:(NSControl *)currentControlView
141 if (hoveredFraction < 1.0) hoveredFraction += 0.05;
143 if (hoveredFraction > 0.0) hoveredFraction -= 0.05;
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];
155 [self performSelector:@selector(fadeHovered:)
156 withObject:currentControlView
158 [currentControlView release];
162 - (void)setHovered:(BOOL)inHovered animate:(BOOL)animate
164 if (animate && (hovered != inHovered)) {
167 hoveredFraction = (hovered ? 0.80 : 0.20);
169 [NSObject cancelPreviousPerformRequestsWithTarget:self
170 selector:@selector(fadeHovered:)
171 object:[self controlView]];
172 [self performSelector:@selector(fadeHovered:)
173 withObject:[self controlView]
178 hoveredFraction = (hovered ? 1.0 : 0.0);
179 [[self controlView] setNeedsDisplay:YES];
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
200 trackingWidth = LEFT_MARGIN + [title size].width + RIGHT_MARGIN;
202 trackingWidth += ARROW_XOFFSET + ARROW_WIDTH;
205 trackingWidth += imageSize.width + IMAGE_MARGIN;
208 return trackingWidth;
211 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
214 NSColor *drawingColor;
215 NSMenu *myMenu = [self menu];
218 [statusParagraphStyle setMaximumLineHeight:cellFrame.size.height];
220 textRect = NSMakeRect(cellFrame.origin.x + LEFT_MARGIN,
221 cellFrame.origin.y + ((cellFrame.size.height - textSize.height) / 2),
224 maxTextWidth = (cellFrame.size.width - LEFT_MARGIN - RIGHT_MARGIN);
227 textRect.origin.x += (imageSize.width + IMAGE_MARGIN);
228 maxTextWidth -= (imageSize.width + IMAGE_MARGIN);
232 maxTextWidth -= (ARROW_XOFFSET + ARROW_WIDTH);
235 if (textRect.size.width > maxTextWidth) {
236 textRect.size.width = maxTextWidth;
239 if (hovered || (hoveredFraction > 0.0)) {
240 //Draw our hovered / highlighted background first
243 float backgroundWidth = LEFT_MARGIN + textRect.size.width + RIGHT_MARGIN;
246 backgroundWidth += (ARROW_XOFFSET + ARROW_WIDTH);
249 backgroundWidth += imageSize.width + IMAGE_MARGIN;
252 path = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(cellFrame.origin.x,
255 cellFrame.size.height)
258 if ([self isHighlighted]) {
259 [[[NSColor darkGrayColor] colorWithAlphaComponent:hoveredFraction] set];
262 [[[NSColor grayColor] colorWithAlphaComponent:hoveredFraction] set];
268 drawingColor = [NSColor whiteColor];
270 drawingColor = [NSColor blackColor];
273 drawingColor = [NSColor blackColor];
277 [currentImage drawInRect:NSMakeRect(cellFrame.origin.x + LEFT_MARGIN,
279 imageSize.width + IMAGE_MARGIN,
280 cellFrame.size.height)
282 position:IMAGE_POSITION_LEFT
286 [statusAttributes setObject:drawingColor
287 forKey:NSForegroundColorAttributeName];
288 [title setAttributes:statusAttributes
289 range:NSMakeRange(0, [title length])];
290 [title drawInRect:textRect];
294 NSBezierPath *arrowPath = [NSBezierPath bezierPath];
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))];