BSLabeledIconCell
Language: Objective-C, Author: Michele Balistreri
License: Public domain
An NSTextFieldCell subclass which displays both an image and a label. It can be used for example in file listing, inside an NSTableView or NSOutlineView to show both the icon and the name of a file.
BSLabeledIconCell source preview
#import "BSLabeledIconCell.h"
@implementation BSLabeledIconCell
- (void)dealloc
{
[image release];
image = nil;
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone
{
BSLabeledIconCell *cell = (BSLabeledIconCell *)[super copyWithZone:zone];
cell->image = [image retain];
return cell;
}
- (void)setImage:(NSImage *)anImage
{
if (anImage != image)
{
[image release];
image = [anImage retain];
}
}
- (NSImage *)image
{
return image;
}
- (NSRect)imageFrameForCellFrame:(NSRect)cellFrame
{
if (image != nil)
{
NSRect imageFrame;
imageFrame.size = [image size];
imageFrame.origin = cellFrame.origin;
imageFrame.origin.x += 3;
imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
return imageFrame;
}
else
return NSZeroRect;
}
- (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent *)theEvent
{
NSRect textFrame, imageFrame;
NSDivideRect (aRect, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge);
[super editWithFrame: textFrame inView: controlView editor:textObj delegate:anObject event: theEvent];
}
- (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(int)selStart length:(int)selLength
{
NSRect textFrame, imageFrame;
NSDivideRect (aRect, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge);
[super selectWithFrame: textFrame inView: controlView editor:textObj delegate:anObject start:selStart length:selLength];
}
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
if (image != nil)
{
NSSize imageSize;
NSRect imageFrame;
imageSize = [image size];
NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
if ([self drawsBackground])
{
[[self backgroundColor] set];
NSRectFill(imageFrame);
}
imageFrame.origin.x += 3;
imageFrame.size = imageSize;
if ([controlView isFlipped])
{
imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2);
}
else
{
imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
}
[image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
cellFrame.origin.x += 3;
cellFrame.size.width -= 3;
cellFrame.origin.y += ceil((imageFrame.size.height / 2) - ([[self font] defaultLineHeightForFont] / 2));
cellFrame.size.height -= ceil((imageFrame.size.height / 2) - ([[self font] defaultLineHeightForFont] / 2));
}
if([self isHighlighted] && ![[self highlightColorWithFrame:cellFrame inView:controlView] isEqual:[NSColor secondarySelectedControlColor]])
{
NSMutableAttributedString *string = [[[NSMutableAttributedString alloc] initWithString:[self objectValue]] autorelease];
[string addAttribute:NSForegroundColorAttributeName value:[NSColor whiteColor] range:NSMakeRange(0,[string length])];
[self setObjectValue:string];
}
[super drawWithFrame:cellFrame inView:controlView];
}
- (NSSize)cellSize
{
NSSize cellSize = [super cellSize];
cellSize.width += (image ? [image size].width : 0) + 3;
return cellSize;
}
@end
BSLabeledIconCell header preview
#import <Cocoa/Cocoa.h>
@interface BSLabeledIconCell : NSTextFieldCell
{
NSImage *image;
}
- (void)setImage:(NSImage *)anImage;
- (NSImage *)image;
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView;
- (NSSize)cellSize;
@end
Download Archive
Compatible with:
- Mac OS X 10.3
- Mac OS X 10.4 PPC
- Mac OS X 10.4 Intel
- Mac OS X 10.5 PPC
- Mac OS X 10.5 Intel

1. Question: Is it correct to set the cell-image implementing the following NSTableView delegate-method:
- (void)tableView:(NSTableView *)aTableView
willDisplayCell:(id)aCell
forTableColumn:(NSTableColumn *)aTableColumn
row:(NSInteger)rowIndex
{
BSLabeledIconCell* cell = aCell;
if ([cell image] == nil) {
NSWorkspace* ws = [NSWorkspace sharedWorkspace];
NSString* path =[filepaths objectAtIndex: rowIndex];
NSImage* icon = [ws iconForFile: path];
[cell setImage: icon];
}
}
2. Unfortunately, neither image nor text are resized to fit the row's height. This results in overlapping/cropped file icons and names. Could you fix this?
Anyway, thank you for sharing your code.
Reiner