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.