ftp.nice.ch/pub/next/developer/resources/classes/misckit/MiscKit.1.10.0.s.gnutar.gz#/MiscKit/Palettes/MiscTreeBrowser/MiscTreeBrowser.subproj/bak/MiscTreeBrowserCell.m

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

/* MiscTreeBrowserCell	-- Cell for MiscTreeBrowser
 *
 */

// IMPORTS

#import <dpsclient/psops.h>
#import <objc/hashtable.h>
#import <appkit/Application.h>
#import <appkit/Text.h>
#import <appkit/NXImage.h>
#import <appkit/Font.h>
#import <stdlib.h>
#import <stdio.h>

#import <misckit/MiscTreeBrowserCell.h>
#import <misckit/MiscTreeBrowserMatrix.h>
#import <misckit/MiscTreeBrowserProtocols.h>
#import <misckit/TB_images.h>

// CLASS VARIABLES

static NXCoord indentSize = 10.0;

static NXImage *openImage = nil;
static NXImage *closedImage = nil;
static NXImage *leafImage = nil;

// IMPLEMENTATION

@implementation MiscTreeBrowserCell

// PRIVATE METHODS

+ initialize
{
	if ([MiscTreeBrowserCell class] == self)
	{
		openImage = _MISC_TBOpen_tiff_fn();
		closedImage = _MISC_TBClosed_tiff_fn();
		leafImage = _MISC_TBLeaf_tiff_fn();
	}

	return self;
}

- edit:(const NXRect *)aRect inView:aView editor:textObject delegate:anObject
 event:(NXEvent *)theEvent
{
	return [super edit:aRect
				  inView:aView
				  editor:textObject
				  delegate:anObject
				  event:theEvent];
}


- _dragImageSize:(NXSize *)aSize
/*"
Sets aSize to the size of the dragged image (or (0,0) if none) and returns
the dragged image
"*/
{
	NXImage *dragImage = [self dragImage];

	if (dragImage)
	{
		[dragImage getSize:aSize];
	}
	else
	{
		aSize->width = aSize->height = 0.0;
	}

	return dragImage;
}

// PUBLIC METHODS

+ (BOOL)prefersTrackingUntilMouseUp
/*"
Returns YES (allows drags outside of Cell) to enable dragging of Cells inside
matrix.
"*/
{
	return YES;
}

- init
{
	[super init];

	//  contents = "";
	[self setType:NX_TEXTCELL];
	[self setEditable:NO];

	return self;
}

- setNode:anObject
/*" Set %node to anObject and calculate the new %indentLevel value. Set
'draggable' flag if node supports dragging. If node is draggable, make it
the target for double-clicking on the drag image."*/
{
	node = anObject;
	hcFlags.draggable = [node conformsTo:@protocol(MiscTreeBrowserDragging)];
	[self setOpen:NO];

	indentLevel = 0;
	while ((anObject = [anObject parent]))
	{
		indentLevel++;
	}

	return self;
}

- node
{
  return node;
}

- (unsigned int)indentLevel
{
	return indentLevel;
}

- nodeAtIndentLevel:(unsigned int)aLevel
{
	int level = [self indentLevel];
	id aNode;

	if (aLevel > level)
	{
		aNode = nil;
	}
	else
	{
		aNode = [self node];
		while (aLevel < level)
		{
			aNode = [aNode parent];
			aLevel++;
		}
	}

	return aNode;
}

- (const char *)stringValue
{
	return [node stringValue];
}

- setStringValue:(const char *)aString
{
	[node setStringValue:aString];

	return self;
}

- (BOOL)isOpen
{
	return (BOOL)hcFlags.open;
}

- (BOOL)isLeaf
{
	return ([node childCount] > 0) ? NO : YES;
}

- (BOOL)isDraggable
{
	return (BOOL)hcFlags.draggable;
}

- (NXImage *)dragImage
{
	return [self isDraggable] ? [node dragImage] : [self openerImage];
}

- setOpen:(BOOL)flag
{
	hcFlags.open = [self isLeaf] ? YES : flag;

	return self;
}

- (BOOL)isEditing
{
	return (BOOL)hcFlags.editing;
}

- setEditing:(BOOL)flag
{
	hcFlags.editing = flag;

	return self;
}

- sendDoubleAction
/*"
If the node responds to %{-doubleClick:} send it, with the cell as the
parameter
"*/
{
	if ([node respondsTo:@selector(doubleClick:)])
	{
		[node doubleClick:self];
	}

	return self;
}


/*"
Returns opener image; this can be open, leaf or closed.
"*/
- openerImage
{
	return ([node childCount] == 0)
		? leafImage
		: [self isOpen] ? openImage : closedImage;
}

- getOpenerRect:(NXRect *)cellFrame inView:controlView
{
    NXSize imageSize;

	[[self openerImage] getSize:&imageSize];

	cellFrame->origin.x += \
		((float)[self indentLevel] * [controlView nodeIndentWidth]);
	cellFrame->origin.y = NX_Y(cellFrame) + NX_HEIGHT(cellFrame) -
		(NX_HEIGHT(cellFrame) - imageSize.height) / 2.0;
	cellFrame->size = imageSize;

	return self;
}

- getTitleRect:(NXRect *)cellFrame inView:controlView
{
    NXSize imageSize, dragImageSize;
	NXCoord	ascender, descender, lineHeight;
	NXCoord xOffset, yOffset;

	NXTextFontInfo(support, &ascender, &descender, &lineHeight);
	[[self openerImage] getSize:&imageSize];
	[self _dragImageSize:&dragImageSize];

	xOffset = (indentSize * (float)indentLevel) + imageSize.width + 2.0;
	yOffset = (cellFrame->size.height - lineHeight +0.5) / 2.0;

	cellFrame->origin.x += xOffset;
	cellFrame->origin.y +=  yOffset;
	cellFrame->size.height = lineHeight;
	cellFrame->size.width -= (xOffset + dragImageSize.width + 2.0);

	return self;
}

- getDragImageRect:(NXRect *)cellFrame inView:controlView
/*"
Given a frame cellFrame in a view controlView, sets cellFrame to the
rectangle in the frame in which the drag image (if any) should be drawn.
Returns the drag image, or nil if there is no drag image (in which case
cellFrame is unchanged).
"*/
{
	NXImage *dragImage;
    NXSize dragImageSize;
	NXCoord xOffset;

	dragImage = [self _dragImageSize:&dragImageSize];

	if (dragImage)
	{
		xOffset = cellFrame->size.width - dragImageSize.height - 1.0;

		cellFrame->origin.x += xOffset;
		cellFrame->origin.y = NX_Y(cellFrame) + NX_HEIGHT(cellFrame) -
			(NX_HEIGHT(cellFrame) - dragImageSize.height) / 2.0;
		cellFrame->size = dragImageSize;
	}

	return dragImage;
}

- drawInside:(const NXRect *)cellFrame inView:controlView
{
	NXRect rect;
	NXCoord	ascender, descender, lineHeight;
	NXImage *image;
	NXCoord	baseX, baseY;
	const char *stringValue = [self stringValue];

								// get text info; should use shared textcell!
	NXTextFontInfo(support, &ascender, &descender, &lineHeight);
	baseX = NX_X(cellFrame);
	baseY = NX_Y(cellFrame) + lineHeight - descender;

								// draw cell background
	if (cFlags1.highlighted)
	{
		NXRect rect = *cellFrame;
		NXCoord height = rect.size.height;
								// white background highlights cell
		PSsetgray(NX_WHITE);
		NXRectFill(cellFrame);

		if (!hcFlags.editing)
		{						// if not editing, grey borders above'n'below
			PSsetgray(NX_DKGRAY);
			rect.size.height = 1.0;
			NXRectFill(&rect);
			rect.origin.y += (height - 1.0);
			NXRectFill(&rect);
		}
	}
	else
	{
		NXColor backgroundColor = [controlView cellColor];

		PSsetrgbcolor(NXRedComponent(backgroundColor),
					  NXGreenComponent(backgroundColor),
					  NXBlueComponent(backgroundColor));
		NXRectFill(cellFrame);
	}

	PSsetgray(NX_BLACK);

	/* draw open/leaf/closed icon at correct indentation */

	image = [self openerImage];
	rect = *cellFrame;
	[self getOpenerRect:&rect inView:controlView];
	[image composite:NX_SOVER toPoint:&rect.origin];

	/* write node stringValue as cell title */
	if (stringValue)
	{
		id textCell = [controlView sharedTextCell];

		rect = *cellFrame;
		[self getTitleRect:&rect inView:controlView];
		rect.origin.x += 1.0;	// fudge because we are not drawing a bezel
		[textCell setStringValue:[self stringValue]];
		[textCell setEnabled:[self isEnabled]];
		[textCell drawInside:&rect inView:controlView];
	}

	/* draw draggable image (if any) */

	if ([self isDraggable])
	{
		NXImage *dragImage;

		rect = *cellFrame;
		dragImage = [self getDragImageRect:&rect inView:controlView];
		if (dragImage)
		{
			[dragImage composite:NX_SOVER toPoint:&rect.origin];
		}
	}

	return self;
}

/*(
Draws border then insides of cell.
)*/
- drawSelf:(const NXRect *)cellFrame inView:aView
{
	return [self drawInside:cellFrame inView:aView];
}

/*(
As drawInside:inView: above, but highlighted
)*/
- highlight:(const NXRect *)cellFrame inView:controlView lit:(BOOL)flag
{
    if (cFlags1.highlighted != flag)
	{
		cFlags1.highlighted = flag;
		[self drawSelf:cellFrame inView:controlView];
    }
    return self;
}

// Dragging methods

- (BOOL)startTrackingAt:(const NXPoint *)startPoint inView:aView
/*"
Record the mouseDown point, so we can determine at mouseUp whether the user
dragged or clicked
"*/
{
	[aView mouseDownAt:startPoint forCell:self];

	return YES;
}

- (BOOL)continueTracking:(const NXPoint *)lastPoint
					  at:(const NXPoint *)currentPoint
				  inView:aView
{
	[aView mouseDraggedAt:currentPoint forCell:self];

	return YES;
}

- stopTracking:(const NXPoint *)lastPoint
			at:(const NXPoint *)stopPoint
		inView:aView
	 mouseIsUp:(BOOL)flag
{
	if (flag)
	{
		[aView mouseUpAt:stopPoint forCell:self];
	}

	return self;
}

@end

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