This is NXYView.m in view mode; [Download] [Up]
/* Generated by Interface Builder */ #import "NXYView.h" #import "Plot.h" #import "title.h" #import <appkit/appkit.h> /* only for NXBeep */ #import <appkit/graphics.h> #import <dpsclient/event.h> #import <appkit/Pasteboard.h> @implementation NXYView #ifndef MIN #define MIN(x,y) ((x)<(y)? (x) : (y)) #endif #ifndef MAX #define MAX(x,y) ((x)>(y)? (x) : (y)) #endif #ifndef ABS #define ABS(x) ( (x)<0? (-(x)) : (x) ) #endif #ifndef SGN #define SGN(x) ( (x)<0? -1.0 : 1.0 ) #endif #define XOFFSET 100.0 /* offsets (in pixels) of axis origin from */ #define YOFFSET 50.0 /* lower left hand corner of window */ - (const char *)inspectorName { return "NXYInspector"; } - (int)nPoints { // if (drawingLegendLines) return 2; // else return 1; return 1; //Added by cwf, no legends } - initPlot:sender { // const char * xtitle = [plotParam provideXtitle]; char * xtitle = [self xaxisLabel]; // const char * ytitle = [plotParam provideYtitle]; char * ytitle = [self yaxisLabel]; // const char * maintitle = [plotParam provideMaintitle]; char * maintitle = [self mainTitle]; float xwid; id axistitlefont, maintitlefont; [self clear:self]; PSsetlinewidth(0.0); [self setDrawColor:NX_BLACK]; axistitlefont = [Font newFont:"Helvetica" size:14.0 style:0 matrix:NX_IDENTITYMATRIX]; [axistitlefont set]; xwid = [axistitlefont getWidthOf:xtitle]; PSmoveto((bounds.size.width - xwid)/2.0, 10.0); PSshow((char *)xtitle); xwid = [axistitlefont getWidthOf:ytitle]; PSmoveto(20.0, (bounds.size.height - xwid)/2.0); PSgsave(); PSrotate(90.0); PSshow((char *)ytitle); PSgrestore(); maintitlefont = [Font newFont:"Helvetica" size:16.0 style:0 matrix:NX_IDENTITYMATRIX]; [maintitlefont set]; xwid = [maintitlefont getWidthOf:maintitle]; PSmoveto((bounds.size.width - xwid)/2.0, bounds.size.height - 20.0); PSshow((char *)maintitle); //Finished title in initPlot method, starting to draw the box; if ([plotParam shouldDrawBox]) { PSsetlinewidth(4.0); PSmoveto(0.0, 0.0); PSlineto(bounds.size.width, 0.0); PSlineto(bounds.size.width, bounds.size.height); PSlineto(0.0, bounds.size.height); PSlineto(0.0, 0.0); PSstroke(); PSsetlinewidth(0.0); } return self; } - setDrawColor:(float) color { PSsetgray(color); return self; } - drawLines:sender :(BOOL)xaxislog :(BOOL)yaxislog /* * This is coded so that when drawLines is called with plotParam as argument, * it draws the data curves; when drawLines is called with self (plotView) as * argument, it draws the short line segments in the legend box. */ { int i,j; NXCoord *x = [sender xdata]; NXCoord **y = [sender ydata]; int npoints = [sender nPoints]; int ncurves = [plotParam nCurves]; int linestyle; float thick = 0.0; float pattern0[] = {}; /* solid */ float pattern1[] = {4.0, 4.0}; /* dash */ float pattern2[] = {1.0, 3.0}; /* dot */ float pattern3[] = {7.0, 3.0, 3.0, 3.0}; /* chain dash */ float pattern4[] = {7.0, 4.0, 1.0, 4.0}; /* chain dot */ switch([plotParam providelinethickness]){ case 0: thick = 0.0; /* thin lines : good for screen */ break; case 1: thick = 2.0; /* medium lines */ break; case 2: thick = 3.0; /* fat lines */ break; } PSnewpath(); PSsetlinewidth(thick); for (j=0; j<ncurves; j++) { linestyle = [plotParam providelinestyle:j]; switch(linestyle) { case 0: PSsetdash(pattern0, 0, 0.0); break; case 1: PSsetdash(pattern1, 2, 0.0); break; case 2: PSsetdash(pattern2, 2, 0.0); break; case 3: PSsetdash(pattern3, 4, 0.0); break; case 4: PSsetdash(pattern4, 4, 0.0); break; case 5: /* no lines */ continue; } if (linestyle == N_LINE_STYLES-1) continue; /* no lines, go to next curve */ if (!xaxislog && !yaxislog) { PSmoveto(x[0]*ppxunit, *(*(y + j)) * ppyunit ); for (i=1; i<npoints; i++) { if ( (i % 512) == 0 ) { PSstroke(); PSnewpath(); PSmoveto(x[i-1]*ppxunit, *(*(y+j)+i-1) * ppyunit); } PSlineto(x[i]*ppxunit, *(*(y+j)+i) * ppyunit); } PSstroke(); } else if (!xaxislog && yaxislog) { PSmoveto(x[0]*ppxunit, (float)log10((double)*(*(y + j))) * ppyunit ); for (i=1; i<npoints; i++) { if ( (i % 512) == 0 ) { PSstroke(); PSnewpath(); PSmoveto(x[i-1]*ppxunit, (float)log10((double)*(*(y+j)+i-1)) * ppyunit); } PSlineto(x[i]*ppxunit, (float)log10((double)*(*(y+j)+i)) * ppyunit); } PSstroke(); } else if (xaxislog && !yaxislog) { PSmoveto((float)log10((double)x[0])*ppxunit, *(*(y + j)) * ppyunit ); for (i=1; i<npoints; i++) { if ( (i % 512) == 0 ) { PSstroke(); PSnewpath(); PSmoveto((float)log10((double)x[i-1])*ppxunit,*(*(y+j)+i-1) * ppyunit); } PSlineto((float)log10((double)x[i])*ppxunit, *(*(y+j)+i) * ppyunit); } PSstroke(); } else if (xaxislog && yaxislog) { PSmoveto((float)log10((double)x[0])*ppxunit, (float)log10((double)*(*(y + j))) * ppyunit ); for (i=1; i<npoints; i++) { if ( (i % 512) == 0 ) { PSstroke(); PSnewpath(); PSmoveto((float)log10((double)x[i-1])*ppxunit, (float)log10((double)*(*(y+j)+i-1)) * ppyunit); } PSlineto((float)log10((double)x[i])*ppxunit, (float)log10((double)*(*(y+j)+i)) * ppyunit); } PSstroke(); } } PSsetdash(pattern0, 0, 0.0); /* back to solid lines */ return self; } #define SQRT3 1.73205081 /* * We had an elegant idea for drawing the symbols: draw each symbol just once * in an off-screen window, then composite them in where needed. This worked * fine for screen drawing (modulo a little difficulty in compositing to just * the right spot), but was a miserable failure when it came to printing: the * print machinery scaled the composite bitmap. We finally decided to abandon * compositing, in the interest of keeping our screen drawing code the same as * our printing code. */ - clear:sender { NXEraseRect(&bounds); return self; } - clearNXYView:sender { [self setXminValue:0.0]; [self setXmaxValue:0.0]; [self setYminValue:0.0]; [self setYmaxValue:0.0]; [self display]; return self; } - drawTicMarks:(float)xmin :(float)xmax :(float)ymin :(float)ymax { float pattern0[] = {}; /* solid */ float pattern2[] = {1.0, 3.0}; /* dot */ float xinc = [plotParam provideXinc] * ppxunit; float yinc = [plotParam provideYinc] * ppyunit; char ticlabel[32]; id ticfont; float x, y; BOOL drawGrid = [plotParam shouldDrawGrid]; BOOL xaxislog = [plotParam xaxisLog]; BOOL yaxislog = [plotParam yaxisLog]; int nmin, nmax, j, i; float ticloc; /* get tic font initialized */ ticfont = [Font newFont:"Helvetica" size:10.0 style:0 matrix:NX_IDENTITYMATRIX]; [ticfont set]; PSnewpath(); PSsetlinewidth(0.0); if (xaxislog) { nmin = (int)floor((double)(xmin/ppxunit)); nmax = (int)ceil((double)(xmax/ppxunit)); for (j=nmin; j<=nmax; j++) { if ( (float)j * ppxunit > xmin && (float)j * ppxunit < xmax ) { if (drawGrid) { PSmoveto((float)j * ppxunit, ymin); PSsetdash(pattern2, 2, 0.0); PSrlineto(0.0, ABS(ymax-ymin)); PSstroke(); } PSmoveto((float)j * ppxunit, ymin - 6.0); /* big tic mark */ PSsetdash(pattern0, 0, 0.0); PSrlineto(0.0, 6.0); PSstroke(); PSmoveto((float)j * ppxunit - 8.0, ymin - 20.0); PSshow("10"); PSmoveto((float)j * ppxunit + 2.0, ymin - 14.0); sprintf(ticlabel, "%-5d", j); PSshow(ticlabel); } for (i=2; i<=9; i++) { ticloc = (float)j * ppxunit + ppxunit*(float)log10((double)i); if ( ticloc>xmin && ticloc<xmax ) { PSmoveto(ticloc, ymin - 4.0); /* small tic mark */ PSrlineto(0.0, 4.0); PSstroke(); } } } } else { if (xinc*(xmax-xmin) < 0.0) { /* the bad case - avoid infinite loop! */ xinc = -xinc; [plotParam resetXinc:xinc/ppxunit]; } x = xmin; while (SGN(xmax-x) == SGN(xmax-xmin)) { if (drawGrid) { PSmoveto(x, ymin); PSsetdash(pattern2, 2, 0.0); PSrlineto(0.0, ABS(ymax-ymin)); PSstroke(); } PSmoveto(x, ymin - 4.0); PSsetdash(pattern0, 0, 0.0); PSrlineto(0.0, 4.0); PSstroke(); sprintf(ticlabel, "%6.2g", x/ppxunit); PSmoveto(x - 14.0, ymin - 14.0); PSshow(ticlabel); x += xinc; } } if (yaxislog) { nmin = (int)floor((double)(ymin/ppyunit)); nmax = (int)ceil((double)(ymax/ppyunit)); for (j=nmin; j<=nmax; j++) { if ( (float)j * ppyunit > ymin && (float)j * ppyunit < ymax ) { if (drawGrid) { PSmoveto(xmin, (float)j * ppyunit); PSsetdash(pattern2, 2, 0.0); PSrlineto(ABS(xmax-xmin), 0.0); PSstroke(); } PSmoveto(xmin - 6.0, (float)j * ppyunit); /* big tic mark */ PSsetdash(pattern0, 0, 0.0); PSrlineto(6.0, 0.0); PSstroke(); PSmoveto(xmin - 30.0, (float)j * ppyunit - 6.0); PSshow("10"); PSmoveto(xmin - 20.0, (float)j * ppyunit - 1.0); sprintf(ticlabel, "%-5d", j); PSshow(ticlabel); } for (i=2; i<=9; i++) { ticloc = (float)j * ppyunit + ppyunit*(float)log10((double)i); if (ticloc>ymin && ticloc<ymax) { PSmoveto(xmin - 4.0, ticloc); /* small tic mark */ PSrlineto(4.0, 0.0); PSstroke(); } } } } else { if (yinc*(ymax-ymin) < 0.0) { /* the bad case - avoid infinite loop! */ yinc = -yinc; [plotParam resetYinc:yinc/ppyunit]; } y = ymin; while (SGN(ymax-y) == SGN(ymax-ymin)) { if (drawGrid) { PSmoveto(xmin, y); PSsetdash(pattern2, 2, 0.0); PSrlineto(ABS(xmax-xmin), 0.0); PSstroke(); } PSmoveto(xmin - 4.0, y); PSsetdash(pattern0, 0, 0.0); PSrlineto(4.0, 0.0); PSstroke(); sprintf(ticlabel, "%6.2g", y/ppyunit); PSmoveto(xmin - 40.0, y - 4.0); PSshow(ticlabel); y += yinc; } } return self; } - initFrame:(NXRect *)frameRect { self = [super initFrame:frameRect]; [self setBorder:YES]; [self setGrid:NO]; [self setAutoMaxMinState:YES]; [self setAutoPaperState:YES]; [self setPaperSwitchRow:4]; // Set the "paper Type" to auto on switch [self setLogoFlag:YES]; mainTitle = "Main Title"; xaxisLabel = "x axis"; yaxisLabel = "y axis"; return self; } - drawSelf: (const NXRect *)rects :(int)rectCount { float xmin = [plotParam provideXmin]; float xmax = [plotParam provideXmax]; float ymin = [plotParam provideYmin]; float ymax = [plotParam provideYmax]; float xscale,yscale; NXRect framerect; [self initPlot:self]; if(strcmp([NXApp appName] , "InterfaceBuilder") ==0 && [self logoFlag] == YES){ [self getFrame:&framerect]; xscale = framerect.size.width/500.0; yscale = framerect.size.height/300.0; PSWTestTitle(xscale, yscale); } if (!( (xmin == 0.0 && xmax== 0.0) || (ymin== 0.0 && ymax == 0.0) )) { PSgsave(); PStranslate(XOFFSET, YOFFSET); if ([plotParam xaxisLog]) { /* x-axis is logarithmic */ if (xmin <= 0.0 || xmax <= 0.0) { /* ring bells, fire rockets -- a voice alert would be nice */ [plotParam forceXaxisLinear]; /* force linear axis */ NXBeep(); /* here's the alert */ ppxunit = 0.9*(bounds.size.width-XOFFSET)/(xmax-xmin); xmin = xmin*ppxunit; /* drawing is all in pixel coordinates */ xmax = xmax*ppxunit; } else { ppxunit = 0.9*(bounds.size.width-XOFFSET)/(float)log10((double)(xmax/xmin)); xmin = (float)log10((double)xmin) * ppxunit; xmax = (float)log10((double)xmax) * ppxunit; } } else { /* x-axis is linear */ ppxunit = 0.9*(bounds.size.width-XOFFSET)/(xmax-xmin); xmin = xmin*ppxunit; /* drawing is all in pixel coordinates */ xmax = xmax*ppxunit; } if ([plotParam yaxisLog]) { /* y-axis is logarithmic */ if (ymin <= 0.0 || ymax <= 0.0) { [plotParam forceYaxisLinear]; /* again should alert user */ NXBeep(); /* here's the (mild) alert */ ppyunit = 0.9*(bounds.size.height-YOFFSET)/(ymax-ymin); ymin = ymin*ppyunit; ymax = ymax*ppyunit; } else { ppyunit = 0.9*(bounds.size.height-YOFFSET) /(float)log10((double)(ymax/ymin)); ymin = (float)log10((double)ymin) * ppyunit; ymax = (float)log10((double)ymax) * ppyunit; } } else { /* y-axis is linear */ ppyunit = 0.9*(bounds.size.height-YOFFSET)/(ymax-ymin); ymin = ymin*ppyunit; ymax = ymax*ppyunit; } PStranslate(-xmin, -ymin); PSnewpath(); /* draw axes */ PSmoveto(xmin, ymin); PSlineto(xmax,ymin); PSlineto(xmax,ymax); PSlineto(xmin,ymax); PSclosepath(); PSstroke(); /* finish axes */ [self drawTicMarks:xmin :xmax :ymin :ymax]; /* do this before clipping */ /* MIN and MAX below in case xmin > xmax and/or ymin > ymax. */ PSrectclip(MIN(xmin,xmax), MIN(ymin,ymax), ABS(xmax-xmin), ABS(ymax-ymin)); [self drawLines:plotParam :[plotParam xaxisLog] :[plotParam yaxisLog]]; // [self drawSymbols:plotParam :[plotParam xaxisLog] :[plotParam yaxisLog]]; PSgrestore(); // if ([plotParam shouldDrawLegend]) { // [self initLegend:self]; // [self drawLegend:self]; // } } return self; } - doPrinting:sender { [ [NXApp printInfo] setMarginLeft:72.0 right:72.0 top:72.0 bottom:72.0 ]; if (bounds.size.height > bounds.size.width) { /* portrait mode */ if (bounds.size.height/bounds.size.width > 9.0/6.5) { [ [NXApp printInfo] setScalingFactor: 9.0*72.0/bounds.size.height]; } else { [ [NXApp printInfo] setScalingFactor: 6.5*72.0/bounds.size.width]; } [ [NXApp printInfo] setOrientation:NX_PORTRAIT andAdjust:YES ]; } else { /* landscape mode */ if (bounds.size.width/bounds.size.height > 9.0/6.5) { [ [NXApp printInfo] setScalingFactor: 9.0*72.0/bounds.size.width]; } else { [ [NXApp printInfo] setScalingFactor: 6.5*72.0/bounds.size.height]; } [ [NXApp printInfo] setOrientation:NX_LANDSCAPE andAdjust:YES ]; } [self printPSCode:sender]; return self; } ////The following methods added by Charlie to get values from the Inspector. // This is not the way I wanted to do it--I would rather have an additional inspector // that goes with the view (palette) when it is loaded into an App, but this won't go through // IB. The following is somewhat long-winded, the keeps the spirit of reading the value // from a controller panel. A shorter way would be to rewrite the nxyplot methods and // get values directly from the IB Inspector. -setGrid:(int)grid_state{gridState=grid_state; return self;} - setBorder:(int)border_state{ borderState=border_state; return self;} -(int)gridState{return gridState; } -(int)borderState{ return borderState;} -setAutoMaxMinState:(int)state{autoMaxMinState=state; return self;} -(int)autoMaxMinState{return autoMaxMinState;} -setAutoPaperState:(int)state{autoPaperState=state; return self;} -(int)autoPaperState{return autoPaperState;} -setXLinLogState:(int)state{xLinLogState=state; return self;} -(int)xLinLogState{return xLinLogState;} -setYLinLogState:(int)state{yLinLogState=state; return self;} -(int)yLinLogState{return yLinLogState;} -setPaperSwitchRow:(int)state{paperSwitchRow=state; return self;} -(int)paperSwitchRow{return paperSwitchRow;} -setLogoFlag:(int)state{logoFlag=state; return self;} -(int)logoFlag{return logoFlag;} -setMainTitle:(char *)mainTITLE{ if(mainTitle != 0) free(mainTitle); mainTitle = malloc(strlen(mainTITLE)+1); strcpy(mainTitle,mainTITLE); return self;} -setXaxisLabel:(char *)xAxisLabel{ if(xaxisLabel != 0) free(xaxisLabel); xaxisLabel = malloc(strlen(xAxisLabel)+1); strcpy(xaxisLabel, xAxisLabel); return self;} -setYaxisLabel:(char *)yAxisLabel{ if(yaxisLabel != 0) free(yaxisLabel); yaxisLabel = malloc(strlen(yAxisLabel)+1); strcpy(yaxisLabel, yAxisLabel); return self;} -(char *)mainTitle{return mainTitle;} -(char *)xaxisLabel{return xaxisLabel;} -(char *)yaxisLabel{return yaxisLabel;} -setXincValue:(float)passedValue{xInc = passedValue; return self;} -setXminValue:(float)passedValue{xMin = passedValue; return self;} -setXmaxValue:(float)passedValue{xMax = passedValue; return self;} -setYincValue:(float)passedValue{yInc = passedValue; return self;} -setYminValue:(float)passedValue{yMin = passedValue; return self;} -setYmaxValue:(float)passedValue{yMax= passedValue; return self;} -(float)xIncValue{return xInc;} -(float)xMinValue{return xMin;} -(float)xMaxValue{return xMax;} -(float)yIncValue{return yInc;} -(float)yMinValue{return yMin;} -(float)yMaxValue{return yMax;} // For testing -- open data file via right mouse click... - rightMouseDown:(NXEvent *)theEvent { // The following allows the uses to call up a file using the right mouse button when in // the test mode of IB. My thanks to Alex Cone of OTI for tips used to write this. // Note however that this will not work if there is a custom IB. if(strcmp([NXApp appName] , "InterfaceBuilder") ==0){ [plotParam open:self]; return self; } else{ return self; } } -plotDataFromStream:sender { NXStream *dataStream; if(delegate && [delegate respondsTo:@selector(nxyView:provideDataStream:)]) { [delegate nxyView:self provideDataStream:&dataStream]; [plotParam useDataStreamAndPlot:dataStream]; } else { if(NXRunAlertPanel("Delegate", "No data stream avaliable to plot.", "Continue", "Open Data File", NULL) == NX_ALERTALTERNATE){ [plotParam open:self]; return self; } return self; } return self; } -setDelegate:anObject { delegate = anObject; return self; } - setInspector:anObject { inspector = anObject; return self; } //// End Charlie's added metods...... // Following methods (saveEPS, savePSCode) taken from nxyplot1.7 - saveEPS:sender { id savePanel = [[SavePanel new] setRequiredFileType:"eps"]; char *eps_fileName; // Name of the EPS file for output if ([savePanel runModal]) { eps_fileName = (char *) calloc(strlen([savePanel filename])+1, sizeof(char)); strcpy(eps_fileName, [savePanel filename]); [self savePSCode:eps_fileName]; } return self; } - savePSCode:(char *)aFile { NXStream *psStream; psStream = NXOpenMemory(NULL, 0, NX_WRITEONLY); if (!psStream) { return self; } [self getBounds:&bounds]; [self copyPSCodeInside:&bounds to:psStream]; NXFlush(psStream); NXSaveToFile(psStream, aFile); NXCloseMemory(psStream, NX_FREEBUFFER); return self; } // Following taken from the Concepts manual page 10-33 -copyToPasteboard:sender { id pb = [Pasteboard new]; NXStream *stream; char *data; int length; int maxLength; [pb declareTypes: &NXPostScriptPboard num:1 owner:self]; stream = NXOpenMemory(NULL, 0, NX_WRITEONLY); if (!stream) { return self; } [self getBounds:&bounds]; [self copyPSCodeInside:&bounds to:stream]; NXGetMemoryBuffer(stream, &data, &length, &maxLength); [pb writeType:NXPostScriptPboard data:data length:length]; NXCloseMemory(stream, NX_FREEBUFFER); return self; } - read:(NXTypedStream*)stream /* * Unarchives the View. Initializes four of the View's instance variables * to the values stored in the stream. */ { [super read:stream]; delegate = NXReadObject(stream); NXReadTypes(stream, "@ff", &plotParam, &ppxunit, &ppyunit); NXReadTypes(stream,"iii",&gridState,&borderState,&autoMaxMinState); NXReadTypes(stream,"***",&mainTitle,&xaxisLabel,&yaxisLabel); NXReadTypes(stream,"ffffff",&xInc,&xMin,&xMax,&yInc,&yMin,&yMax); NXReadTypes(stream,"iiiii",&autoPaperState,&xLinLogState, &yLinLogState,&paperSwitchRow,&logoFlag); return self; } - write:(NXTypedStream*)stream /* * Archives the View by writing its important instance variables to the stream. */ { [super write:stream]; NXWriteObjectReference(stream, delegate); NXWriteTypes(stream, "@ff", &plotParam, &ppxunit, &ppyunit); NXWriteTypes(stream,"iii",&gridState,&borderState,&autoMaxMinState); NXWriteTypes(stream,"***",&mainTitle,&xaxisLabel,&yaxisLabel); NXWriteTypes(stream,"ffffff",&xInc,&xMin,&xMax,&yInc,&yMin,&yMax); NXWriteTypes(stream,"iiiii",&autoPaperState,&xLinLogState, &yLinLogState, &paperSwitchRow,&logoFlag); return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.