Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

/ImageAndTextCell.m

View Source Code:

Download Sample Code (“SourceView.zip”, 265.6K)



//
// File:       ImageAndTextCell.m
//
// Abstract:   Subclass of NSTextFieldCell which can display text and an image simultaneously.
//
// Version:       1.0
//
// Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Inc. ("Apple")
//               in consideration of your agreement to the following terms, and your use,
//               installation, modification or redistribution of this Apple software
//               constitutes acceptance of these terms.  If you do not agree with these
//               terms, please do not use, install, modify or redistribute this Apple
//               software.
//
//               In consideration of your agreement to abide by the following terms, and
//               subject to these terms, Apple grants you a personal, non - exclusive
//               license, under Apple's copyrights in this original Apple software ( the
//               "Apple Software" ), to use, reproduce, modify and redistribute the Apple
//               Software, with or without modifications, in source and / or binary forms;
//               provided that if you redistribute the Apple Software in its entirety and
//               without modifications, you must retain this notice and the following text
//               and disclaimers in all such redistributions of the Apple Software. Neither
//               the name, trademarks, service marks or logos of Apple Inc. may be used to
//               endorse or promote products derived from the Apple Software without specific
//               prior written permission from Apple.     Except as expressly stated in this
//               notice, no other rights or licenses, express or implied, are granted by
//               Apple herein, including but not limited to any patent rights that may be
//               infringed by your derivative works or by other works in which the Apple
//               Software may be incorporated.
//
//               The Apple Software is provided by Apple on an "AS IS" basis.     APPLE MAKES NO
//               WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
//               WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
//               PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
//               ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
//
//               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
//               CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//               SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//               INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
//               AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
//               UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
//               OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (C) 2007 Apple Inc. All Rights Reserved.
//

#import "ImageAndTextCell.h"
#import "BaseNode.h"

@implementation ImageAndTextCell

#define kIconImageSize        16.0

#define kImageOriginXOffset 3
#define kImageOriginYOffset 1

#define kTextOriginXOffset    2
#define kTextOriginYOffset    2
#define kTextHeightAdjust    4

// -------------------------------------------------------------------------------
//    init:
// -------------------------------------------------------------------------------
- (id)init
{
    self = [super init];
    
    // we want a smaller font
    [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];

    return self;
}

// -------------------------------------------------------------------------------
//    dealloc:
// -------------------------------------------------------------------------------
- (void)dealloc
{
    [image release];
    image = nil;
    [super dealloc];
}

// -------------------------------------------------------------------------------
//    copyWithZone:zone
// -------------------------------------------------------------------------------
- (id)copyWithZone:(NSZone*)zone
{
    ImageAndTextCell *cell = (ImageAndTextCell*)[super copyWithZone:zone];
    cell->image = [image retain];
    return cell;
}

// -------------------------------------------------------------------------------
//    setImage:anImage
// -------------------------------------------------------------------------------
- (void)setImage:(NSImage*)anImage
{
    if (anImage != image)
    {
        [image release];
        image = [anImage retain];
        [image setSize:NSMakeSize(kIconImageSize, kIconImageSize)];
    }
}

// -------------------------------------------------------------------------------
//    image:
// -------------------------------------------------------------------------------
- (NSImage*)image
{
    return image;
}

// -------------------------------------------------------------------------------
//    isGroupCell:
// -------------------------------------------------------------------------------
- (BOOL)isGroupCell
{
    return ([self image] == nil && [[self title] length] > 0);
}

// -------------------------------------------------------------------------------
//    titleRectForBounds:cellRect
//
//    Returns the proper bound for the cell's title while being edited
// -------------------------------------------------------------------------------
- (NSRect)titleRectForBounds:(NSRect)cellRect
{    
    // the cell has an image: draw the normal item cell
    NSSize imageSize;
    NSRect imageFrame;

    imageSize = [image size];
    NSDivideRect(cellRect, &imageFrame, &cellRect, 3 + imageSize.width, NSMinXEdge);

    imageFrame.origin.x += kImageOriginXOffset;
    imageFrame.origin.y -= kImageOriginYOffset;
    imageFrame.size = imageSize;
    
    imageFrame.origin.y += ceil((cellRect.size.height - imageFrame.size.height) / 2);
    
    NSRect newFrame = cellRect;
    newFrame.origin.x += kTextOriginXOffset;
    newFrame.origin.y += kTextOriginYOffset;
    newFrame.size.height -= kTextHeightAdjust;

    return newFrame;
}

// -------------------------------------------------------------------------------
//    editWithFrame:inView:editor:delegate:event
// -------------------------------------------------------------------------------
- (void)editWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObj delegate:(id)anObject event:(NSEvent*)theEvent
{
    NSRect textFrame = [self titleRectForBounds:aRect];
    [super editWithFrame:textFrame inView:controlView editor:textObj delegate:anObject event:theEvent];
}

// -------------------------------------------------------------------------------
//    selectWithFrame:inView:editor:delegate:event:start:length
// -------------------------------------------------------------------------------
- (void)selectWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObj delegate:(id)anObject start:(int)selStart length:(int)selLength
{
    NSRect textFrame = [self titleRectForBounds:aRect];
    [super selectWithFrame:textFrame inView:controlView editor:textObj delegate:anObject start:selStart length:selLength];
}

// -------------------------------------------------------------------------------
//    drawWithFrame:cellFrame:controlView:
// -------------------------------------------------------------------------------
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
{
    if (image != nil)
    {
        // the cell has an image: draw the normal item cell
        NSSize imageSize;
        NSRect imageFrame;

        imageSize = [image size];
        NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
 
        imageFrame.origin.x += kImageOriginXOffset;
        imageFrame.origin.y -= kImageOriginYOffset;
        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];

        NSRect newFrame = cellFrame;
        newFrame.origin.x += kTextOriginXOffset;
        newFrame.origin.y += kTextOriginYOffset;
        newFrame.size.height -= kTextHeightAdjust;
        [super drawWithFrame:newFrame inView:controlView];
    }
    else
    {
        if ([self isGroupCell])
        {
            // Center the text in the cellFrame, and call super to do thew ork of actually drawing. 
            CGFloat yOffset = floor((NSHeight(cellFrame) - [[self attributedStringValue] size].height) / 2.0);
            cellFrame.origin.y += yOffset;
            cellFrame.size.height -= (kTextOriginYOffset*yOffset);
            [super drawWithFrame:cellFrame inView:controlView];
        }
    }
}

// -------------------------------------------------------------------------------
//    cellSize:
// -------------------------------------------------------------------------------
- (NSSize)cellSize
{
    NSSize cellSize = [super cellSize];
    cellSize.width += (image ? [image size].width : 0) + 3;
    return cellSize;
}

// -------------------------------------------------------------------------------
//    hitTestForEvent:
//
//    In 10.5, we need you to implement this method for blocking drag and drop of a given cell.
//    So NSCell hit testing will determine if a row can be dragged or not.
//
//    NSTableView calls this cell method when starting a drag, if the hit cell returns
//    NSCellHitTrackableArea, the particular row will be tracked instead of dragged.
//
// -------------------------------------------------------------------------------
- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView
{
    NSInteger result = NSCellHitContentArea;
    
    NSOutlineView* hostingOutlineView = (NSOutlineView*)[self controlView];
    if (hostingOutlineView)
    {
        NSInteger selectedRow = [hostingOutlineView selectedRow];
        BaseNode* node = [[hostingOutlineView itemAtRow:selectedRow] representedObject];

        if (![node isDraggable])    // is the node isDraggable (i.e. non-file system based objects)
            result = NSCellHitTrackableArea;
    }
        
    return result;
}

@end




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.