home *** CD-ROM | disk | FTP | other *** search
- /* PlotView.m -- Implementation file for the PlotView class */
-
- #import "PlotView.h"
- #import "drawingFuncs.h"
- #import <objc/Storage.h>
- #import <appkit/NXCursor.h>
- #import <appkit/Application.h>
- #import <appkit/Window.h>
- #import <appkit/Cell.h>
- #import <appkit/Pasteboard.h>
- #import <NXCType.h>
- #import <math.h>
- #import <dpsclient/psops.h>
- #import <dpsclient/wraps.h>
- #import <stdlib.h>
- #import <string.h>
-
- extern float getNumber(NXStream *stream);
- extern int getSeparator(NXStream *stream);
-
- #define MAXNUMLENGTH 50
- #define DEFAULTRADIUS 1.0
-
- @implementation PlotView
-
- - initFrame:(const NXRect *)frameRect
- /*
- * Initializes the new PlotView object. First, an initFrame: message is sent to
- * super to initialize PlotView as a View. Next, the PlotView sets its own
- * state -- that it is opaque and that the origin of its coordinate system lies in
- * the center of its area. It then creates and initializes its associated objects,
- * a Storage object, an NXCursor, and a Cell. Finally, it loads into the Window
- * Server some PostScript procedures that it will use in drawing itself.
- */
- {
- NXPoint spot;
-
- [super initFrame:frameRect];
- [self setOpaque:YES];
- [self setRadius:DEFAULTRADIUS];
- [self translate:floor(frame.size.width/2) :floor(frame.size.height/2)];
- points = [[Storage alloc] initCount:0 elementSize:sizeof(NXPoint) description:"{ff}"];
- crossCursor = [NXCursor newFromImage:[NXImage newFromSection:"cross.tiff"]];
- spot.x = spot.y = 7.0;
- [crossCursor setHotSpot:&spot];
- /*
- * Normally, the next two message expressions would be combined, as:
- * readOut = [[Cell alloc] initTextCell:""];
- * but are here separated for clarity.
- */
- readOut = [Cell alloc];
- [readOut initTextCell:""];
- [readOut setBezeled:YES];
- loadPSProcedures();
- return self;
- }
-
-
- - setDelegate:anObject
- /*
- * Sets the PlotView's delegate instance variable to the supplied object.
- */
- {
- delegate = anObject;
- return self;
- }
-
-
- - drawSelf:(const NXRect *)rects :(int)rectCount
- /*
- * Draws the PlotView's background and axes. If there are any points,
- * these are drawn too.
- */
- {
- unsigned int i;
- NXPoint *aPoint;
-
- if (rects == NULL) return self;
-
- /* If we're printing, we need to load drawing procedures to printing context */
- if (NXDrawingStatus != NX_DRAWING)
- loadPSProcedures();
-
- /* paint visible area white then draw axes */
- PSsetgray(NX_WHITE);
- NXRectFill(&rects[0]);
- PSsetgray(NX_DKGRAY);
- drawAxes(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
-
- /* now take each point and draw it */
- PSsetgray(NX_BLACK);
- i = [points count];
- while (i--) {
- aPoint = (NXPoint *)[points elementAt:i];
- drawCircle(aPoint->x, aPoint->y, radius);
- }
- return self;
- }
-
- - clear:sender
- /*
- * Clears the PlotView by emptying its Storage object of all points
- * and then redisplaying the PlotView. This action is taken only if
- * the PlotView's state requires it.
- */
- {
- if (needsClearing) {
- [points empty];
- [self display];
- needsClearing = NO;
- }
- return self;
- }
-
- - sizeTo:(NXCoord)width :(NXCoord)height
- /*
- * Ensures that whenever the PlotView is resized, the origin of its
- * coordinate system is repositioned to the center of its area.
- */
- {
- [super sizeTo:width :height];
- [self setDrawOrigin:-floor(width/2) : -floor(height/2)];
- return self;
- }
-
- - registerPoint:(NXPoint *)aPoint
- /*
- * Adds a point to the list the PlotView keeps in its Storage object.
- */
- {
- [points addElement:aPoint];
- return self;
- }
-
- - mouseDown:(NXEvent *) theEvent
- /*
- * Responds to a message the system sends whenever the user presses the mouse
- * button when the cursor is over the PlotView. The PlotView changes the
- * cursor to a cross-hairs image and then starts asking for mouse-dragged or mouse-
- * up events. As it receives mouse-dragged events, the PlotView updates the readOut
- * text Cell with the cursor's coordinates. If the user releases the mouse
- * button while the cursor is over the PlotView, the PlotView registers the
- * point and then sends a message to its delegate notifying it of the new
- * point.
- */
- {
- int looping = YES, oldMask;
- NXPoint aPoint;
- NXRect plotRect, cellRect;
- char buffer[100];
-
- [crossCursor set];
- [self getBounds:&plotRect];
- NXSetRect(&cellRect, plotRect.origin.x, plotRect.origin.y, 100.0, 20.0);
-
- oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
- [self lockFocus];
- do {
- aPoint = theEvent->location;
- [self convertPoint:&aPoint fromView:nil];
- sprintf(buffer, "(%d, %d)", (int)aPoint.x, (int)aPoint.y);
- [readOut setStringValue:buffer];
- [readOut drawInside:&cellRect inView:self];
- [window flushWindow];
- if (theEvent->type == NX_MOUSEUP) {
- /* on mouse-up, register point, inform delegate, and clean up state */
- [readOut setStringValue:""];
- [readOut drawInside:&cellRect inView:self];
- [window flushWindow];
- if (NXPointInRect(&aPoint, &plotRect)) {
- PSsetgray(NX_BLACK);
- drawCircle(aPoint.x, aPoint.y, radius);
- [window flushWindow];
- [self registerPoint:&aPoint];
- needsClearing = YES;
- if (delegate && [delegate respondsTo:@selector(plotView:pointDidChange:)])
- [delegate plotView:self pointDidChange:&aPoint];
- }
- looping = NO;
- }
- } while (looping && (theEvent=[NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK]));
- [self unlockFocus];
- [window setEventMask:oldMask];
- [NXArrow set];
- return self;
- }
-
- - setRadius:(float)aFloat
- /*
- * Sets the value for the radius of the PlotView's points.
- */
- {
- radius = aFloat;
- return self;
- }
-
-
- - (float)radius
- /*
- * Returns the value for the radius of the PlotView's points.
- */
- {
- return radius;
- }
-
-
- - read:(NXTypedStream*)stream
- /*
- * Unarchives the PlotView. Initializes four of the PlotView's instance variables
- * to the values stored in the stream.
- */
- {
- [super read:stream];
- delegate = NXReadObject(stream);
- NXReadTypes(stream, "@@@f", &points, &crossCursor, &readOut, &radius);
- return self;
- }
-
- - write:(NXTypedStream*)stream
- /*
- * Archives the PlotView by writing its important instance variables to the stream.
- */
- {
- [super write:stream];
- NXWriteObjectReference(stream, delegate);
- NXWriteTypes(stream, "@@@f", &points, &crossCursor, &readOut, &radius);
- return self;
- }
-
- - awake
- /*
- * Finishes initializing a PlotView that has just been unarchived (see the read: method).
- */
- {
- loadPSProcedures();
- return [super awake];
- }
-
-
- - (const char*)inspectorName
- {
- return "PlotViewInspector";
- }
-
- - plot:sender
- /*
- * Responds to a plot: message by asking the PlotView's delegate for a stream
- * containing the points to plot. It then extracts number pairs from the stream
- * and creates NXPoint structures with them. For each structure it creates, the
- * PlotView sends itself a registerPoint: message to add the point to its list of
- * points. This simple parser ignores input it doesn't understand.
- */
- {
- int c, sign, retval;
- float aNum;
- NXPoint aPoint;
- NXStream *stream;
- BOOL processedLine = NO, gotFirst = NO, gotSecond = NO;
-
- if (delegate && [delegate respondsTo:@selector(plotView:providePoints:)])
- [delegate plotView:self providePoints:&stream];
- NXSeek(stream, 0, NX_FROMSTART);
- while ((c = NXGetc(stream)) != EOF){
- sign = 1;
- retval = getSeparator(stream);
- if (retval == 1) {
- c = NXGetc(stream);
- } else if (retval == -1) {
- break;
- }
- if (!NXIsDigit(c)) {
- if ((c == '-') && NXIsDigit(c = NXGetc(stream))){
- sign = -1;
- } else {
- while( (c != '\n') && (c != EOF)) {
- c = NXGetc(stream);
- processedLine = YES;
- }
- }
- }
- if (c == EOF)
- break;
- else if (processedLine) {
- processedLine = NO;
- continue;
- }
- aNum = getNumber(stream);
- if (!gotFirst) {
- aPoint.x = sign * aNum;
- gotFirst = YES;
- } else if (!gotSecond) {
- aPoint.y = sign * aNum;
- [self registerPoint:&aPoint];
- gotFirst = gotSecond = NO;
- }
- }
- [self display];
- needsClearing = YES;
- return self;
- }
-
- int getSeparator(NXStream *stream)
- /*
- * Removes white space, commas, and plus signs from between
- * number pairs.
- */
- {
- int c, firstChar;
-
- NXUngetc(stream);
- c = firstChar = NXGetc(stream);
- while (NXIsSpace(c) || (c == ',') || (c == '+'))
- c = NXGetc(stream);
- /* 1 = ate something; 0 = ate nothing; -1 means EOF */
- if (c == firstChar)
- return 0;
- else if (c == EOF)
- return -1;
- NXUngetc(stream);
- return 1;
- }
-
- float getNumber(NXStream *stream)
- /*
- * Composes a floating point number from a string of number
- * characters.
- */
- {
- int c, i = 0;
- char temp[MAXNUMLENGTH];
-
- NXUngetc(stream);
- c = NXGetc(stream);
- while ((NXIsDigit(c) || (c == '.')) && (c != '\n') && (c != EOF)) {
- temp[i++] = c;
- c = NXGetc(stream);
- }
- NXUngetc(stream);
- temp[i] = 0;
- return (atof(temp));
- }
-
- @end