ftp.nice.ch/Attic/openStep/developer/resources/IconKit.4.2.1.sd.tgz#/IconKit.4.2.1/Framework/IKCell.m

This is IKCell.m in view mode; [Download] [Up]

#pragma .h #import <AppKit/NSActionCell.h>
#pragma .h #import <AppKit/NSImage.h>
#pragma .h #import <AppKit/NSCStringText.h>
#pragma .h
#pragma .h #import "IKIconObject.h"
#pragma .h #import "IKDependency.h"
#pragma .h
#pragma .h enum {
#pragma .h 	IK_NOPART,
#pragma .h 	IK_TITLEPART,
#pragma .h 	IK_ICONPART
#pragma .h };
#pragma .h
#pragma .h enum {
#pragma .h 	IK_NOSHELF,
#pragma .h 	IK_UNLOCKED,
#pragma .h 	IK_LOCKED,
#pragma .h 	IK_REALLYLOCKED
#pragma .h };
#pragma .h
#pragma .h typedef struct _cellflags {
#pragma .h 		unsigned int	showMiniImage:1;
#pragma .h 		unsigned int	showBranch:1;
#pragma .h 		unsigned int	draggable:1;
#pragma .h 		unsigned int	dragAccepting:1;
#pragma .h 		unsigned int	editable:1;
#pragma .h 		unsigned int	container:1;
#pragma .h 		unsigned int	locked:1;
#pragma .h 		unsigned int	reallyLocked:1;
#pragma .h 		unsigned int	multipleLines:1;
#pragma .h 		unsigned int	ghosted:1;
#pragma .h } cellFlags;

#import <AppKit/AppKit.h>
#import "iconkit.h"
#import "IKCellPS.h"

@implementation IKCell : NSActionCell
{
    id <IKIconObject, IKDependency> delegate;

    id			image;
    id			miniImage;
    cellFlags	flags;
}

#define DX				9
#define DY				2
#define OFFSET			0
#define GAP				0
#define INSET			4
#define HYSTERESIS		4


static NSTextFieldCell *text;

static id	ghostImage = nil,
ghostHighlightMask = nil,
ghosting = nil;

static void initGhostImages (NSSize);

+ (void)initialize
{
    if (self == [IKCell  class]) {
        [self setVersion:2];
        text = [[NSTextFieldCell alloc] initTextCell:@""];

        NSLog( @"IconKit Version 23:50 17.8.97" );
        }
    return;
}


- init
{
    if ((self = [super initTextCell:@""]) != nil) {
        image = nil;
        miniImage = nil;
        delegate = nil;

        flags.showMiniImage = NO;
        flags.showBranch = NO;
        flags.draggable = YES;
        flags.dragAccepting = YES;
        flags.editable = YES;
        flags.container = NO;
        flags.locked = YES;
        flags.reallyLocked = YES;
        flags.multipleLines = NO;
        flags.ghosted = NO;

        [self setAlignment:NSCenterTextAlignment];
        }
    return self;
}


- initTextCell:(NSString *)theTitle
{
    [self init];
    [self setTitle:theTitle];
    return self;
}


- initImageCell:(NSImage *)anImage
{
    [self init];
    [self setImage:anImage];
    return self;
}


- initImage:(NSImage *) theImage title:(NSString *)theTitle
{
    [self init];
    [self setImage:theImage];
    [self setTitle:theTitle];
    return self;
}


- initDelegate:(id <IKIconObject, IKDependency>) theDelegate
{
    [self init];
    [self setDelegate:theDelegate];
    return self;
}


- initFromCopy:(IKCell *) copy
{
    [self init];
    [self setBranch:[copy isBranch]];
    [self setDraggable:[copy isDraggable]];
    [self setDragAccepting:[copy isDragAccepting]];
    [self setEditable:[copy isEditable]];
    [self setContainer:[copy isContainer]];
    [self setLocked:[copy isLocked]];
    [self setReallyLocked:[copy isReallyLocked]];
    [self setMultipleLines:[copy isMultipleLines]];
    [self setGhosted:[copy isGhosted]];
    [self setTitle:[copy title]];
    [self setImage:[copy image]];
    [self setMiniImage:[copy miniImage]];
    return self;
}


- (void)dealloc
{
    [delegate  removeUser:self];
    return [super dealloc]; self = self;
}


- (NSString *) inspectorClassName
{
    return @"IKCellInspector";
}


- (id)initWithCoder:(NSCoder *)aDecoder
{
    char	showBranch, draggable, dragAccepting,
    editable, container, locked, reallyLocked, multipleLines,
    showMiniImage;

    [super initWithCoder:aDecoder];

    switch ([aDecoder versionForClassName:@"IKCell"])
        {
        case 2:
            [aDecoder decodeValuesOfObjCTypes:"c", &showMiniImage];	// fall through
            flags.showMiniImage = showMiniImage;		// wenn man es so macht, muessen die neuen ivars in write:
            miniImage = [[aDecoder decodeObject] retain];			// zuerst weggeschrieben werden !
        case 1:
            image = [[aDecoder decodeObject] retain];
            [aDecoder decodeValuesOfObjCTypes:"cccccccc", &showBranch, &draggable,
                &dragAccepting, &editable, &container, &locked,
                &reallyLocked, &multipleLines];

            miniImage = nil;
            flags.showMiniImage = NO;
            flags.multipleLines = multipleLines;
            flags.ghosted = NO;
            break;

        case 0:
            image = [[aDecoder decodeObject] retain];
            [aDecoder decodeValuesOfObjCTypes:"ccccccc", &showBranch, &draggable,
                &dragAccepting, &editable, &container, &locked,
                &reallyLocked];

            miniImage = nil;
            flags.showMiniImage = NO;
            flags.multipleLines = NO;
            flags.ghosted = NO;
            break;
            }
    flags.showBranch = showBranch;
    flags.draggable = draggable;
    flags.dragAccepting = dragAccepting;
    flags.editable = editable;
    flags.container = container;
    flags.locked = locked;
    flags.reallyLocked = reallyLocked;

    return self;
}


- (void)encodeWithCoder:(NSCoder *)aCoder
{
    char	showBranch = flags.showBranch,
    draggable = flags.draggable,
    dragAccepting = flags.dragAccepting,
    editable = flags.editable,
    container = flags.container,
    locked = flags.locked,
    reallyLocked = flags.reallyLocked,
    multipleLines = flags.multipleLines,
    showMiniImage = flags.showMiniImage;

    [super encodeWithCoder:aCoder];

    [aCoder encodeValuesOfObjCTypes:"c", &showMiniImage];
    [aCoder encodeObject:miniImage];
    [aCoder encodeObject:image];
    [aCoder encodeValuesOfObjCTypes:"cccccccc", &showBranch, &draggable, &dragAccepting,
        &editable, &container, &locked, &reallyLocked, &multipleLines];
}


- delegate			{		return delegate;						}
- (NSImage *)image		{		return image;							}
- (NSImage *)miniImage		{		return miniImage;						}
- (NSString *)title		{		return [self stringValue];						}
- (BOOL) isShowMiniImage	{		return flags.showMiniImage;				}
- (BOOL) isBranch		{		return flags.showBranch;				}
- (BOOL) isContainer		{		return flags.container;					}
- (BOOL) isLocked		{		return flags.locked;					}
- (BOOL) isReallyLocked		{		return flags.reallyLocked;				}
- (BOOL) isEmptyContainer	{		return flags.container && !delegate;	}
- (BOOL) isMultipleLines	{		return flags.multipleLines;				}
- (BOOL) isGhosted		{		return flags.ghosted;					}


- (BOOL) isDraggable
{
    return flags.draggable && (!delegate || [delegate  isDraggable]);
}


- (BOOL) isDragAccepting
{
    return flags.dragAccepting && (!delegate || [delegate  isDragAccepting]);
}


- (BOOL) isEditable
{
    return flags.editable && (!delegate || [delegate  isEditable]);
}


- (void)setImage:(NSImage *)theImage
{
    [image autorelease];
    image = [theImage retain];
}


- (void)setMiniImage:(NSImage *) theImage
{
    [miniImage autorelease];
    miniImage = [theImage retain];
}

- (void)setTitle:(NSString *)theTitle
{
    NSRect	oldFrame, newFrame;
    id		editor = [self editor];

    [self setStringValue:theTitle ? theTitle : @""];
    if (editor) {
        if (theTitle == nil) {
            [(IKIconPath *)[self controlView] endEditing];
        } else {
            oldFrame = [editor frame];
            [editor setString:[self stringValue]];

            //            if ([editor isHorizontallyResizable] || [editor isVerticallyResizable]) {
            //                NSRect	titleRect;
            //                titleRect = [self titleRectForBounds:[self frame]];
            //                [editor setFrame:titleRect];
            //            }
            newFrame = [editor frame];
            [[self controlView] displayRect:NSUnionRect(newFrame , oldFrame)];
        }
    }
}


// <<HACK>> All thse set Methods should be converted to return void !!

- setShowMiniImage:(BOOL)flag	{  flags.showMiniImage = flag;	return self;   }
- setBranch:(BOOL)flag          {  flags.showBranch = flag;	return self;   }
- setDraggable:(BOOL)flag       {  flags.draggable = flag;      return self;   }
- setDragAccepting:(BOOL)flag	{  flags.dragAccepting = flag;	return self;   }
- (void)setEditable:(BOOL)flag; {  flags.editable = flag;                      }
- setContainer:(BOOL)flag       {  flags.container = flag;      return self;   }
- setLocked:(BOOL)flag          {  flags.locked = flag;		return self;   }
- setReallyLocked:(BOOL)flag	{  flags.reallyLocked = flag;	return self;   }
- setMultipleLines:(BOOL)flag	{  flags.multipleLines = flag;	return self;   }
- setGhosted:(BOOL)flag         {  flags.ghosted = flag;        return self;   }


- (void)setDelegate:(id)theDelegate
{
    id old = delegate;

    // This whole delegation stuff should be changed to work with Notifiactions !!

    delegate = IKCheckConformance (theDelegate) ? theDelegate :nil;
    if(delegate) {

        // <<HACK>> This is UGLY !!! We are bascially creating a retain cyle here !!!

        [delegate retain];
        [delegate  addUser:self];
        [self setMiniImage:[delegate miniImage]];
        [self setImage:[delegate image]];
        [self setTitle:[delegate name]];
    } else {
        [self setMiniImage:nil];
        [self setImage:nil];
        [self setTitle:nil];
    }
    if(old) {

        // <<HACK>> This is UGLY !!! We are dealing with a retain cycle here !!!

        [old removeUser:self];
        [old release];
    }
}


- willFree:who
{
    if (who == delegate) {
        delegate = nil;
        [self setDelegate:nil];
        [(NSMatrix *)[self controlView] updateCell:self];
        }
    return self;
}

- (int) shelfMode
{
    if (!flags.container)		
        return IK_NOSHELF;			

    else if (flags.reallyLocked)		
        return IK_REALLYLOCKED;		

    else if (flags.locked)
        return IK_LOCKED;	

    else
        return IK_UNLOCKED;
}

- setShelfMode:(int) mode
{
    switch (mode) {
        case IK_NOSHELF:
            [self		setContainer:NO];
            break;

        case IK_UNLOCKED:
            [self		setContainer:YES];
            [self		setLocked:NO];
            [self		setReallyLocked:NO];
            break;

        case IK_LOCKED:
            [self		setContainer:YES];
            [self		setLocked:YES];
            [self		setReallyLocked:NO];
            break;

        case IK_REALLYLOCKED:
            [self		setContainer:YES];
            [self		setLocked:YES];
            [self		setReallyLocked:YES];
            break;
            }	
    return self;
}


- didChangeName:sender
{
    if (sender == delegate)
        [self  setTitle:[delegate name]];
    return self;
}


- didChangeImage:sender
{
    if (sender == delegate) {
        [self  setImage:[delegate image]];
        [(NSMatrix *)[self controlView] updateCellInside:self];
    }
    return self;
}


- didChangeMiniImage:sender
{
    if (sender == delegate) {
        [self setMiniImage:[delegate miniImage]];
        [(NSMatrix *)[self controlView] updateCellInside:self];
    }
    return self;
}


- (void)highlight:(BOOL)flag withFrame:(NSRect)cellFrame inView:(NSView *)view
{
    id	anImage = (flags.showMiniImage ? miniImage :image);
    if (anImage && ([self isHighlighted] != flag)) {
        [super highlight:flag withFrame:cellFrame inView:view];
    }
}


- (NSImage *)_imageToDraw
{
    NSImage *anImage = (flags.showMiniImage ? miniImage :image);

    if (flags.ghosted  && anImage != ghosting) {
        NSPoint	origin = { 0.0, 0.0 };
        NSSize	size = [anImage size];
        initGhostImages (size);

        [ghostImage lockFocus];
        [anImage compositeToPoint:origin operation:NSCompositeCopy];
        [ghostHighlightMask compositeToPoint:origin operation:NSCompositeSourceAtop];
        [ghostImage unlockFocus];
        ghosting = anImage;
    }
    return flags.ghosted  ? ghostImage : anImage;
}


static id controlView = nil;
float background;


- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)view
{
    id	anImage = (flags.showMiniImage ? miniImage : image);

    controlView = view;
    if (anImage != NULL)
        [self  drawIcon:cellFrame];
    if ([self stringValue] != NULL)
        [self  drawTitle:cellFrame];
    if (flags.showBranch)
        [self  drawBranch:cellFrame];
}


- (void)drawIcon:(NSRect) iconRect
{
    iconRect = [self imageRectForBounds:iconRect];
    PSsetgray (([self state] | [self isHighlighted])  ? NSWhite : NSLightGray);

    PSiconBackdrop( iconRect.origin.x - DX,
                    iconRect.origin.y - DY,
                    iconRect.size.width + 2.0 * DX,
                    iconRect.size.height + 2.0 * DY
                    );
    iconRect.origin.y += iconRect.size.height;
    [[self _imageToDraw] compositeToPoint:iconRect.origin operation:NSCompositeSourceOver];
}


- (void)drawTitle:(NSRect) titleRect
{
    if ([self editor] == nil) {
        titleRect = [self titleRectForBounds:titleRect];
        [text setStringValue:[self stringValue]];
        [text setAlignment:[self alignment]];
        [text setCellAttribute:NSCellHighlighted to:0];
        [text setFont:[self font]];
        [text setTextColor:[NSColor colorWithCalibratedWhite:flags.ghosted  ?  NSDarkGray : NSBlack alpha:1.0]];
        [text setBackgroundColor:[NSColor lightGrayColor]];
        [text setWraps:[self wraps]];
        if (!flags.multipleLines)
            IKShortenTitle (text, titleRect.size.width);

        [text drawInteriorWithFrame:titleRect inView:controlView];
    }	
}


- (void)drawBranch:(NSRect) cellFrame
{
    id      branchIcon = [NSBrowserCell branchImage];
    NSPoint	origin = cellFrame.origin;
    NSSize	size;

    size = [branchIcon size];
    origin.x += cellFrame.size.width - size.width;
    origin.y += (cellFrame.size.height + size.height) / 2.0;
    [branchIcon compositeToPoint:origin operation:NSCompositeSourceOver];
}


- (NSSize)cellSizeForBounds:(NSRect)frame
{
    NSSize size;
    NSSize imageSize;
    id     anImage = (flags.showMiniImage ? miniImage : image);
    int    alignment = [self alignment];

    size = [super cellSizeForBounds:frame];
    imageSize = [anImage size];

    if(alignment == NSCenterTextAlignment) {
        if ([[self stringValue] length] == 0)
            size.height = 0;
        size.width = MAX (size.width, imageSize.width) + 1 * DX + 1;
        size.height = size.height + imageSize.height + GAP + OFFSET + 1 * DY + 1;
    } else if(alignment == NSLeftTextAlignment) {
        size.width = size.width + imageSize.width + 1 * DX + 1;
        size.height = MAX (size.height, imageSize.height) + GAP + OFFSET + 1 * DY + 1;
    }
    return size;
}


- _getIconRect:(NSRect *) iconRect  titleRect:(NSRect *) titleRect
{
    NSRect	bigRect = {{ 0.0,  0.0 },  { 10000.0, 10000.0 }};
    NSSize	title = { 0.0,  0.0 },
        icon  = { 0.0,  0.0 };
    id		anImage = (flags.showMiniImage ? miniImage : image);
    int		alignment = [self alignment];

    icon = [anImage size];
    if(alignment == NSCenterTextAlignment) {
        iconRect->origin.y += flags.multipleLines ? INSET : (int)(iconRect->size.height - icon.height) / 2;
        iconRect->origin.x += /* GAP + DX + */ (int)(iconRect->size.width - icon.width) / 2;
        } else if(alignment == NSLeftTextAlignment) {
            iconRect->origin.y += (int)(iconRect->size.height - icon.height) / 2;
            iconRect->origin.x += GAP + DX;
            }
    if ([[self stringValue] length] > 0) {
        NSRect aRect, frame = *titleRect;
        if (flags.multipleLines) {
            if(alignment == NSCenterTextAlignment) {
                titleRect->origin.y = iconRect->origin.y + icon.height + GAP + DY;
                /* titleRect->origin.x += GAP + DX */;
            } else if(alignment == NSLeftTextAlignment) {
                titleRect->origin.y = iconRect->origin.y;
                titleRect->origin.x += icon.width + GAP + 2 * DX;
            }
            aRect = *titleRect;
            aRect = NSIntersectionRect(frame , aRect);
            title = aRect.size;
        } else {
            title = [super cellSizeForBounds:bigRect];

            if(alignment == NSCenterTextAlignment) {
                title.width = MIN (titleRect->size.width, title.width);
                iconRect->origin.y += OFFSET - (int)(title.height + GAP) / 2;
                titleRect->origin.y = iconRect->origin.y + icon.height + GAP + DY;
                titleRect->origin.x += /* GAP + DX + */ (int) (titleRect->size.width - title.width) / 2;
            } else if(alignment == NSLeftTextAlignment) {
                titleRect->origin.y = iconRect->origin.y + (int)(icon.height / 2) - (int)(title.height / 2);
                titleRect->origin.x += icon.width + GAP + 2 * DX;
                title.width = titleRect->size.width - (titleRect->origin.x - iconRect->origin.x);
            }
        }
    }
    iconRect->size = icon;
    titleRect->size = title;
    return self;
}


- (NSRect)imageRectForBounds:(NSRect)iconRect
{
    NSRect titleRect = iconRect;
    [self  _getIconRect:&iconRect  titleRect:&titleRect];
    return iconRect;
}


- (NSRect)titleRectForBounds:(NSRect)titleRect
{
    NSRect iconRect = titleRect;
    [self  _getIconRect:&iconRect  titleRect:&titleRect];
    return titleRect;
}


- (int) hitPart:(NSPoint *) where  inRect:(const NSRect *) cellFrame
{
    NSRect iconRect  = * cellFrame,
    titleRect = * cellFrame;

    iconRect = [self imageRectForBounds:iconRect];
    titleRect = [self titleRectForBounds:titleRect];

    return NSMouseInRect(*where , titleRect , YES)  ?	IK_TITLEPART:
        NSMouseInRect(*where , iconRect , NO)  ?		IK_ICONPART:
        IK_NOPART;
}


- dragIcon:(NSEvent *)event inRect:(const NSRect *) cellFrame  ofView:view
{
    NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    NSEvent      *mouseDown = event;
    NSRect	 iconRect = * cellFrame;
    NSPoint	 offset;
    id		 old = delegate;
    id		 theImage = (flags.showMiniImage ? miniImage : image);

    [[view window] setAcceptsMouseMovedEvents:YES];
    while ([event = [NSApp nextEventMatchingMask:NSAnyEventMask
                                       untilDate:[NSDate distantFuture]
                                          inMode:NSEventTrackingRunLoopMode
                                         dequeue:YES] type] ==  NSLeftMouseDragged)
    {
        offset.x = [event locationInWindow].x - [mouseDown locationInWindow].x;
        offset.y = [event locationInWindow].y - [mouseDown locationInWindow].y;

        if (abs(offset.x) + abs(offset.y) > HYSTERESIS) {
            [old  addUser:self];
            if (delegate != nil) {
                [delegate  copyToPasteboard:pboard];
            } else {
                [pboard declareTypes:(NSArray *)NULL owner:self];
            }
            iconRect = [self imageRectForBounds:iconRect];
            iconRect.origin.y += iconRect.size.height;

            if (flags.container && !flags.reallyLocked && (!flags.locked || ([event modifierFlags] & NSCommandKeyMask))) {
                [delegate  removeUser:self];
                [self setState:0];
                [delegate release];
                delegate = nil;

                //<<NOTE>> Should the lines above we replace with setDelegate:nil  ?
                [self highlight:NO withFrame:iconRect inView:[self controlView]];
            }
            [view dragImage:theImage at:iconRect.origin offset:NSMakeSize(offset.x,offset.y) event:mouseDown pasteboard:pboard source:view slideBack:YES];

            if (delegate == nil  &&  old != nil)
                [self setDelegate:nil];
            [old  removeUser:self];
            break;
        }
    }
    [[view window] setAcceptsMouseMovedEvents:NO];
    return self;
}

- (void)editorFrameChanged:(NSNotification *)arg
{
    [[[arg object] window] invalidateCursorRectsForView:[self controlView]];
}

- editTitle:(NSEvent *)event inRect:(const NSRect *)cellFrame ofView:view
{
    NSRect	titleRect = * cellFrame;
    NSTextView	*editor = [[view window] fieldEditor:YES forObject:self];
    BOOL	canEdit = [self isEditable],
        canSelect = canEdit;
    int		alignment = [self alignment];

    if ([editor delegate] != self) {
        NSSize	 maxSize = { titleRect.size.width,  titleRect.size.height },
        minSize = {                  0.0,  titleRect.size.height };

        [view  endEditing];

        if(alignment == NSCenterTextAlignment) {
            titleRect.size.width += 2000;
            titleRect.origin.x -= 1000;
        }
        titleRect = [self titleRectForBounds:titleRect];
        [editor setDrawsBackground:YES];
        [editor	setAlignment:alignment];
        [editor setTextColor:[NSColor blackColor]];
        [editor setFont:[self font]];

        [editor setEditable:canEdit];
        [editor setSelectable:canSelect];

        [editor	setMaxSize:maxSize];
        [[editor textContainer] setContainerSize:maxSize];
        [editor	setMinSize:minSize];
        [[editor textContainer] setWidthTracksTextView:NO];
        [editor	setHorizontallyResizable:NO];
        [[editor textContainer] setHeightTracksTextView:flags.multipleLines];
        [editor setVerticallyResizable:flags.multipleLines];
        [editor setString:[self stringValue]];

        [editor setDelegate:self];

        if(alignment == NSCenterTextAlignment) {
            titleRect.origin.x = cellFrame->origin.x /* + GAP + DX */;
            titleRect.size.width = cellFrame->size.width;
        } else {
            titleRect.origin.x -= 3;
        }
        [editor setFrame:titleRect];

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(editorFrameChanged:)
                                                     name:NSViewFrameDidChangeNotification object:editor];

        [view addSubview:editor];
        [[view window] makeFirstResponder:editor];
    }
    if (event != NULL) {
        [[view window] makeFirstResponder:editor];
        [editor mouseDown:event];
    }
    return self;
}

- (void)textDidEndEditing:(NSNotification *)aNotification
{
    NSString *name;

    if ([self  isEditable]) {
        id sender = [aNotification object];
        if(sender == [self editor]) {
            name = [sender string];
            if([name length] == 0)
                name = @"";
            if (! [name isEqual:[self stringValue]]) {
                [self setStringValue:name];
            }
            [delegate setName:name];
            [sender removeFromSuperview];
            [sender setDelegate:nil];
            [[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewFrameDidChangeNotification object:sender];
        }
    }
}

- editor
{
    id editor = [[[self controlView] window] fieldEditor:NO forObject:self];
    return (editor && [editor delegate] == self) ? editor : nil;
}


@end


static void initGhostImages (NSSize size)
{
    NSSize	imageSize, maskSize;

    imageSize = [ghostImage size];
    maskSize = [ghostHighlightMask size];

    if (size.width > imageSize.width  ||  size.height > imageSize.height) {
        [ghostImage release];
        ghostImage = [[NSImage alloc] initWithSize:size];
    }

    if (size.width > maskSize.width  ||  size.height > maskSize.height) {
        [ghostHighlightMask release];
        ghostHighlightMask = [[NSImage alloc] initWithSize:size];

        [ghostHighlightMask lockFocus];
        PSsetalpha (1.0 / 3.0);
        PSsetgray (1.0);
        PSrectfill (0.0, 0.0, size.width, size.height);
        [ghostHighlightMask unlockFocus];
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.