ftp.nice.ch/pub/next/developer/resources/palettesfor2.xx/nxypalette.1.2.N.bs.tar.gz#/nxyPalette1.2/src/NXYView.m

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.