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.