jens@20: /* jens@20: ImageAndTextCell.m jens@20: Copyright (c) 2001-2006, Apple Computer, Inc., all rights reserved. jens@20: Author: Chuck Pisula jens@20: jens@20: Milestones: jens@20: * 03-01-2001: Initial creation by Chuck Pisula jens@20: * 11-04-2005: Added hitTestForEvent:inRect:ofView: for better NSOutlineView support by Corbin Dunn jens@20: jens@20: Subclass of NSTextFieldCell which can display text and an image simultaneously. jens@20: */ jens@20: jens@20: /* jens@20: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in jens@20: consideration of your agreement to the following terms, and your use, installation, jens@20: modification or redistribution of this Apple software constitutes acceptance of these jens@20: terms. If you do not agree with these terms, please do not use, install, modify or jens@20: redistribute this Apple software. jens@20: jens@20: In consideration of your agreement to abide by the following terms, and subject to these jens@20: terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in jens@20: this original Apple software (the "Apple Software"), to use, reproduce, modify and jens@20: redistribute the Apple Software, with or without modifications, in source and/or binary jens@20: forms; provided that if you redistribute the Apple Software in its entirety and without jens@20: modifications, you must retain this notice and the following text and disclaimers in all jens@20: such redistributions of the Apple Software. Neither the name, trademarks, service marks jens@20: or logos of Apple Computer, Inc. may be used to endorse or promote products derived from jens@20: the Apple Software without specific prior written permission from Apple. Except as expressly jens@20: stated in this notice, no other rights or licenses, express or implied, are granted by Apple jens@20: herein, including but not limited to any patent rights that may be infringed by your jens@20: derivative works or by other works in which the Apple Software may be incorporated. jens@20: jens@20: The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, jens@20: EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, jens@20: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS jens@20: USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. jens@20: jens@20: IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL jens@20: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS jens@20: OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, jens@20: REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND jens@20: WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR jens@20: OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jens@20: */ jens@20: jens@20: #import "ImageAndTextCell.h" jens@20: #import jens@20: jens@20: @implementation ImageAndTextCell jens@20: jens@20: - (id)init { jens@20: self = [super init]; jens@20: if( self ) { jens@20: [self setLineBreakMode:NSLineBreakByTruncatingTail]; jens@20: [self setSelectable:YES]; jens@20: } jens@20: return self; jens@20: } jens@20: jens@20: - (void)dealloc { jens@20: [image release]; jens@20: [super dealloc]; jens@20: } jens@20: jens@20: - (id)copyWithZone:(NSZone *)zone { jens@20: ImageAndTextCell *cell = (ImageAndTextCell *)[super copyWithZone:zone]; jens@20: // The image ivar will be directly copied; we need to retain or copy it. jens@20: cell->image = [image retain]; jens@20: return cell; jens@20: } jens@20: jens@20: - (void)setImage:(NSImage *)anImage { jens@20: if (anImage != image) { jens@20: [image release]; jens@20: image = [anImage retain]; jens@20: } jens@20: } jens@20: jens@20: - (NSImage *)image { jens@20: return image; jens@20: } jens@20: jens@20: - (NSRect)imageRectForBounds:(NSRect)cellFrame { jens@20: NSRect result; jens@20: if (image != nil) { jens@20: result.size = [image size]; jens@20: result.origin = cellFrame.origin; jens@20: result.origin.x += 3; jens@20: result.origin.y += ceil((cellFrame.size.height - result.size.height) / 2); jens@20: } else { jens@20: result = NSZeroRect; jens@20: } jens@20: return result; jens@20: } jens@20: jens@20: // We could manually implement expansionFrameWithFrame:inView: and drawWithExpansionFrame:inView: or just properly implement titleRectForBounds to get expansion tooltips to automatically work for us jens@20: - (NSRect)titleRectForBounds:(NSRect)cellFrame { jens@20: NSRect result; jens@20: if (image != nil) { jens@20: CGFloat imageWidth = [image size].width; jens@20: result = cellFrame; jens@20: result.origin.x += (3 + imageWidth); jens@20: result.size.width -= (3 + imageWidth); jens@20: } else { jens@20: result = NSZeroRect; jens@20: } jens@20: return result; jens@20: } jens@20: jens@20: jens@20: - (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent *)theEvent { jens@20: NSRect textFrame, imageFrame; jens@20: NSDivideRect (aRect, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge); jens@20: [super editWithFrame: textFrame inView: controlView editor:textObj delegate:anObject event: theEvent]; jens@20: } jens@20: jens@20: - (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength { jens@20: NSRect textFrame, imageFrame; jens@20: NSDivideRect (aRect, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge); jens@20: [super selectWithFrame: textFrame inView: controlView editor:textObj delegate:anObject start:selStart length:selLength]; jens@20: } jens@20: jens@20: - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { jens@20: if (image != nil) { jens@20: NSRect imageFrame; jens@20: NSSize imageSize = [image size]; jens@20: NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge); jens@20: if ([self drawsBackground]) { jens@20: [[self backgroundColor] set]; jens@20: NSRectFill(imageFrame); jens@20: } jens@20: imageFrame.origin.x += 3; jens@20: imageFrame.size = imageSize; jens@20: jens@20: if ([controlView isFlipped]) jens@20: imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2); jens@20: else jens@20: imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2); jens@20: jens@20: [image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver]; jens@20: } jens@20: [super drawWithFrame:cellFrame inView:controlView]; jens@20: } jens@20: jens@20: - (NSSize)cellSize { jens@20: NSSize cellSize = [super cellSize]; jens@20: cellSize.width += (image ? [image size].width : 0) + 3; jens@20: return cellSize; jens@20: } jens@20: jens@20: - (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView { jens@20: NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil]; jens@20: // If we have an image, we need to see if the user clicked on the image portion. jens@20: if (image != nil) { jens@20: // This code closely mimics drawWithFrame:inView: jens@20: NSSize imageSize = [image size]; jens@20: NSRect imageFrame; jens@20: NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge); jens@20: jens@20: imageFrame.origin.x += 3; jens@20: imageFrame.size = imageSize; jens@20: // If the point is in the image rect, then it is a content hit jens@20: if (NSMouseInRect(point, imageFrame, [controlView isFlipped])) { jens@20: // We consider this just a content area. It is not trackable, nor it it editable text. If it was, we would or in the additional items. jens@20: // By returning the correct parts, we allow NSTableView to correctly begin an edit when the text portion is clicked on. jens@20: return NSCellHitContentArea; jens@20: } jens@20: } jens@20: // At this point, the cellFrame has been modified to exclude the portion for the image. Let the superclass handle the hit testing at this point. jens@20: return [super hitTestForEvent:event inRect:cellFrame ofView:controlView]; jens@20: } jens@20: jens@20: jens@20: @end jens@20: