This is TreeView.m in view mode; [Download] [Up]
#import "Utilities.h"
#import "TreeView.h"
#define LEFTARROWKEY 172
#define RIGHTARROWKEY 174
#define UPARROWKEY 173
#define DOWNARROWKEY 175
#define PUSHKEY 0x3
#define BACKSPACEKEY 0x7f
@interface TreeView(PrivateMethods)
- updateCanvasPos:(NXCoord)xPos :(NXCoord)yPos;
@end
@implementation TreeView
- initFrame:(const NXRect *)frameRect
{
[super initFrame:frameRect];
xTimes = 1;
yTimes = 1;
canvasRect = *frameRect;
canvasPath = nil;
[self updateCanvasPos:0 :0];
[[self setClipping:NO] setFlipped:YES];
linkPath = nil;
hitPath = nil;
agent = nil;
nodeList = [[List allocFromZone:[self zone]] init];
pbConversion = NO;
pbTree = nil;
return self;
}
- free
{
if(linkPath)
[linkPath free];
if(hitPath)
[hitPath free];
[nodeList free];
return [super free];
}
- (BOOL)lockFocus
{
BOOL aBOOL;
float rot,gruen,blau;
if(NXDrawingStatus == NX_DRAWING){
aBOOL = [super lockFocus];
PScurrentlinewidth(&drawState.linewidth);
PScurrentrgbcolor(&rot,&gruen,&blau);
drawState.color = NXConvertRGBToColor(rot,gruen,blau);
drawState.font = nil;
return aBOOL;
} else
return [super lockFocus];
}
- drawSelf:(const NXRect *)r :(int)count
{
if(count == 1){
[self drawYourSelf:r];
} else {
[self drawYourSelf:&r[1]];
[self drawYourSelf:&r[2]];
}
return self;
}
- drawYourSelf:(const NXRect *)r
{
id tree;
int i,j;
PSsetgray(NX_WHITE);
NXRectFill(r);
drawState.color = NX_COLORWHITE;
if(NXDrawingStatus == NX_DRAWING){
PSrectviewclip(r->origin.x,r->origin.y,r->size.width,r->size.height);
PSsetgray(NX_LTGRAY);
PSsetlinewidth(0.15);
drawState.color = NX_COLORLTGRAY;
drawState.linewidth = 0.15;
for(i = 0;i <= xTimes;i++)
for(j = 0;j <= yTimes;j++){
[self updateCanvasPos:i * NX_WIDTH(&canvasRect) :j * NX_HEIGHT(&canvasRect)];
[canvasPath send:dps_ustroke cached:YES];
}
}
if(!pbConversion)
tree = [agent tree];
else
tree = pbTree;
if(tree)
[self drawTree:tree inRect:r];
if(NXDrawingStatus == NX_DRAWING)
PSinitviewclip();
return self;
}
- drawTree:tree inRect:(const NXRect *)r
{
int i;
BOOL knobs, attachments;
[tree layout];
if(!linkPath)
linkPath = [[UPath allocFromZone:[self zone]] init];
[linkPath resetFill];
[nodeList empty];
if(NXDrawingStatus == NX_PRINTING)
[tree involved:NULL addTo:nodeList link:linkPath];
else
[tree involved:r addTo:nodeList link:linkPath];
for(i = 0; i < [nodeList count];i++)
[[nodeList objectAt:i] drawNodeShadow:&drawState];
if([tree child] && ![tree zipped]){
PSsetgray(NX_BLACK);
drawState.color = NX_COLORBLACK;
PSsetlinewidth(0.15);
drawState.linewidth = 0.15;
[linkPath send:dps_ustroke cached:NO];
}
for(i = 0; i < [nodeList count];i++)
[[nodeList objectAt:i] drawNodeEnding:&drawState];
for(i = 0; i < [nodeList count];i++)
[[nodeList objectAt:i] drawNodeFill:&drawState];
if(NXDrawingStatus == NX_DRAWING){
knobs = YES;
attachments = [agent showMarker];
} else
knobs = attachments = NO;
for(i = 0; i < [nodeList count];i++)
[[nodeList objectAt:i] drawNodeOutline:&drawState knobs:knobs];
for(i = 0; i < [nodeList count];i++)
[[nodeList objectAt:i] drawNodeCellsInView:self attachments:attachments];
return self;
}
- mouseDown:(NXEvent *)event
{
NXPoint p;
NXRect redrawRect, textFrame;
NXSize maxTextSize;
id selectedNode,lastSelected,tree;
id retval, fe = nil;
BOOL hitAttach, fieldResponder = NO;
p = event->location;
[self convertPoint:&p fromView:nil];
[window disableFlushWindow];
[self lockFocus];
tree = [agent tree];
if(tree){
if(!hitPath)
hitPath = [[HitPath allocFromZone:[self zone]] init];
[hitPath movePathToPoint:&p];
selectedNode = [tree hit:hitPath];
if(selectedNode){
lastSelected = [agent declareSelection:selectedNode];
if(selectedNode != lastSelected){
[selectedNode getBounds:&redrawRect];
[self drawSelf:&redrawRect :1];
[self scrollRectToVisible:&redrawRect];
if(lastSelected){
[lastSelected setSelected:YES];
[lastSelected getBounds:&redrawRect];
[lastSelected setSelected:NO];
[self drawSelf:&redrawRect :1];
}
}
if(event->data.mouse.click >= 2){
[window endEditingFor:self];
fe = [window getFieldEditor:YES for:self];
[fe setFont:[selectedNode font]];
[fe setCharFilter:NXFieldFilter];
[fe setFontPanelEnabled:NO];
[fe setMonoFont:YES];
[fe setOpaque:YES];
[selectedNode getTextFrame:&textFrame];
[fe setMinSize:&(textFrame.size)];
maxTextSize.width = bounds.size.width;
maxTextSize.height = textFrame.size.height;
[fe setMaxSize:&maxTextSize];
[fe setFrame:&textFrame];
[fe setHorizResizable:YES];
[fe setText:[selectedNode label]];
[fe selectAll:self];
[fe setAlignment:NX_CENTERED];
[fe unscript:self];
[fe setVertResizable:NO];
[fe setDelegate:selectedNode];
[self addSubview:fe];
p.x = textFrame.origin.x;
p.y = textFrame.origin.y;
[self convertPoint:&p toView:nil];
event->location = p;
[fe mouseDown:event];
fieldResponder = YES;
}
} else if([agent showMarker]){
selectedNode = [tree hitAttachment:&p :&hitAttach];
if(selectedNode){
[window reenableFlushWindow];
if(hitAttach)
retval = [selectedNode activateAttachment:event inView:self];
else
retval = [selectedNode activateSound:event inView:self];
[window disableFlushWindow];
if(retval){
lastSelected = [agent declareSelection:selectedNode];
if(selectedNode != lastSelected){
[selectedNode getBounds:&redrawRect];
[self drawSelf:&redrawRect :1];
if(lastSelected){
[lastSelected setSelected:YES];
[lastSelected getBounds:&redrawRect];
[lastSelected setSelected:NO];
[self drawSelf:&redrawRect :1];
}
}
}
} else {
lastSelected = [agent declareSelection:nil];
if(lastSelected){
[lastSelected setSelected:YES];
[lastSelected getBounds:&redrawRect];
[lastSelected setSelected:NO];
[self drawSelf:&redrawRect :1];
}
}
}
}
[self unlockFocus];
[window reenableFlushWindow];
[window flushWindow];
if(fieldResponder)
[window makeFirstResponder:fe];
else
[window makeFirstResponder:self];
return self;
}
- keyDown:(NXEvent *)event
{
id selectedNode = nil,lastSelected,tree,fe;
NXEvent *eptr = event;
NXRect redrawRect, textFrame;
NXSize maxTextSize;
if(eptr->data.key.charSet == NX_SYMBOLSET){
lastSelected = [agent currentNode];
if(!lastSelected)
return self;
[window disableFlushWindow];
[self lockFocus];
switch(eptr->data.key.charCode){
case LEFTARROWKEY:
selectedNode = [lastSelected parent];
break;
case RIGHTARROWKEY:
if(![lastSelected zipped])
selectedNode = [lastSelected child];
break;
case UPARROWKEY:
tree = [lastSelected parent];
if(tree){
tree = [tree child];
if(tree == lastSelected)
selectedNode = nil;
else {
while([tree sibling] != lastSelected)
tree = [tree sibling];
selectedNode = tree;
}
} else
selectedNode = nil;
break;
case DOWNARROWKEY:
selectedNode = [lastSelected sibling];
break;
default:
break;
}
if(selectedNode){
[agent declareSelection:selectedNode];
[selectedNode getBounds:&redrawRect];
[self drawSelf:&redrawRect :1];
[self scrollRectToVisible:&redrawRect];
[lastSelected setSelected:YES];
[lastSelected getBounds:&redrawRect];
[lastSelected setSelected:NO];
[self drawSelf:&redrawRect :1];
}
[self unlockFocus];
[window reenableFlushWindow];
[window flushWindow];
[window makeFirstResponder:self];
} else if(eptr->data.key.charSet == NX_ASCIISET && eptr->data.key.charCode == PUSHKEY){
lastSelected = [agent currentNode];
if(!lastSelected)
return self;
[self lockFocus];
[window endEditingFor:self];
fe = [window getFieldEditor:YES for:self];
[fe setFont:[lastSelected font]];
[fe setCharFilter:NXFieldFilter];
[fe setFontPanelEnabled:NO];
[fe setMonoFont:YES];
[fe setOpaque:YES];
[lastSelected getTextFrame:&textFrame];
[fe setMinSize:&(textFrame.size)];
maxTextSize.width = bounds.size.width;
maxTextSize.height = textFrame.size.height;
[fe setMaxSize:&maxTextSize];
[fe setFrame:&textFrame];
[fe setHorizResizable:YES];
[fe setText:[lastSelected label]];
[fe setAlignment:NX_CENTERED];
[fe unscript:self];
[fe setVertResizable:NO];
[fe setDelegate:lastSelected];
[self addSubview:fe];
[fe selectAll:self];
[self unlockFocus];
[window flushWindow];
[window makeFirstResponder:fe];
} else if(eptr->data.key.charSet == NX_ASCIISET && eptr->data.key.charCode == BACKSPACEKEY)
[agent delete:self];
return self;
}
- (BOOL)checkResize:(const NXRect *)r for:tree
{
NXRect treeBounds;
NXCoord dlx, dly, dux, duy;
BOOL result = NO;
NXPoint p;
int tx,ty;
[tree layout];
[tree getTreeBounds:&treeBounds lowerWidth:&dlx lowerHeight:&dly];
dux = NX_WIDTH(&treeBounds) - dlx;
duy = NX_HEIGHT(&treeBounds) - dly;
[self convertRect:&treeBounds toView:superview];
if(r){
[self sizeTo:NX_WIDTH(r) :NX_HEIGHT(r)];
canvasRect = *r;
xTimes = yTimes = 1;
result = YES;
}
tx = ceil(NX_WIDTH(&treeBounds) / NX_WIDTH(&canvasRect));
ty = ceil(NX_HEIGHT(&treeBounds) / NX_HEIGHT(&canvasRect));
if(ty != yTimes || tx != xTimes){
xTimes = tx;
yTimes = ty;
[self sizeTo:NX_WIDTH(&canvasRect) * xTimes :NX_HEIGHT(&canvasRect) * yTimes];
result = YES;
}
if(xTimes == 1)
p.x = dlx + (NX_WIDTH(&bounds) - dlx - dux) / 2;
else
p.x = dlx + 3;
if(yTimes == 1)
p.y = dly + (NX_HEIGHT(&bounds) - dly - duy) / 2;
else
p.y = dly + 3;
[tree setPositionTo:&p];
return result;
}
- setAgent:aAgent
{
agent = aAgent;
return self;
}
- agent
{
return agent;
}
- writePSToStream:(NXStream *)stream usingTree:aTree
{
NXRect bbox;
NXCoord dl, du;
if(stream){
pbConversion = YES;
pbTree = aTree;
[aTree getTreeBounds:&bbox lowerWidth:&dl lowerHeight:&du];
[self copyPSCodeInside:&bbox to:stream];
pbConversion = NO;
pbTree = nil;
}
return self;
}
- (BOOL)zoomTo:(float)zoomX :(float)zoomY
{
if(agent)
[agent setDocScale:zoomX];
return NO;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (int)canvasX
{
return xTimes;
}
- (int)canvasY
{
return yTimes;
}
- (BOOL)knowsPagesFirst:(int *)firstPageNum last:(int *)lastPageNum
{
*lastPageNum = xTimes * yTimes;
return YES;
}
- (BOOL)getRect:(NXRect *)theRect forPage:(int)page
{
int row, col;
if(page < 1 || page > xTimes * yTimes)
return NO;
page--;
row = page / xTimes;
col = page % xTimes;
theRect->origin.x = col * NX_WIDTH(&canvasRect);
theRect->origin.y = row * NX_HEIGHT(&canvasRect);
theRect->size.width = NX_WIDTH(&canvasRect);
theRect->size.height = NX_HEIGHT(&canvasRect);
return YES;
}
- printPSCode:sender
{
float printScaleFactor;
printScaleFactor = [[agent printInfo] scalingFactor];
if(printScaleFactor != 1)
[self scale:printScaleFactor :printScaleFactor];
[super printPSCode:sender];
if(printScaleFactor != 1)
[self scale: 1 / printScaleFactor :1 / printScaleFactor];
return self;
}
@end
@implementation TreeView(PrivateMethods)
- updateCanvasPos:(NXCoord)xPos :(NXCoord)yPos
{
canvasRect.origin.x = xPos;
canvasRect.origin.y = yPos;
if(!canvasPath){
canvasPath = [[UPath allocFromZone:[self zone]] init];
[canvasPath moveto:canvasRect.origin.x :canvasRect.origin.y];
[canvasPath rlineto:canvasRect.size.width :0.0];
[canvasPath rlineto:0.0 :canvasRect.size.height];
[canvasPath rlineto:-canvasRect.size.width :0.0];
[canvasPath rlineto:0.0 :-canvasRect.size.height];
} else {
canvasPath->bbox[0] = canvasRect.origin.x;
canvasPath->bbox[1] = canvasRect.origin.y;
canvasPath->bbox[2] = canvasRect.origin.x + canvasRect.size.width;
canvasPath->bbox[3] = canvasRect.origin.y + canvasRect.size.height;
canvasPath->params[0] = canvasRect.origin.x;
canvasPath->params[1] = canvasRect.origin.y;
canvasPath->params[2] = canvasRect.size.width;
canvasPath->params[3] = 0.0;
canvasPath->params[4] = 0.0;
canvasPath->params[5] = canvasRect.size.height;
canvasPath->params[6] = -canvasRect.size.width;
canvasPath->params[7] = 0.0;
canvasPath->params[8] = 0.0;
canvasPath->params[9] = -canvasRect.size.height;
}
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.