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.