roy@prism.gatech.EDU (Roy Mongiovi) (04/29/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Spiro Spiro/Makefile Spiro/README Spiro/Spiro.m # Spiro/SpiroInterface.m Spiro/Spirograph.h Spiro/Spirograph.m # Wrapped by roy@prism.gatech.edu on Fri Apr 28 13:13:19 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test ! -d 'Spiro' ; then echo shar: Creating directory \"'Spiro'\" mkdir 'Spiro' fi if test -f 'Spiro/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Spiro/Makefile'\" else echo shar: Extracting \"'Spiro/Makefile'\" \(624 characters\) sed "s/^X//" >'Spiro/Makefile' <<'END_OF_FILE' X# X# Spirograph makefile. X# X X# Libraries used by this application. XLIBS=-lappkit_s -ldpsclient_s -lobjc_s -lstreams_s -ldb_s -lm -lc_s -lsoundkit -lsound X X# Flags to pass on to the compiler and linker. XCFLAGS=-gg XLFLAGS= X X# Rules. XSpiro: Spiro.o SpiroInterface.o Spirograph.o X $(CC) $(CFLAGS) $(LFLAGS) -o Spiro Spiro.o SpiroInterface.o Spirograph.o $(LIBS) X XSpiro.o: Spiro.m Spirograph.h XSpiroInterface.o: SpiroInterface.m Spirograph.h XSpirograph.o: Spirograph.m Spirograph.h X Xclean: X -rm -f *.o Spiro core X Xhelp: X @echo ' make Spiro - to make the application' X @echo ' make clean - to remove all files but the source' END_OF_FILE if test 624 -ne `wc -c <'Spiro/Makefile'`; then echo shar: \"'Spiro/Makefile'\" unpacked with wrong size! fi # end of 'Spiro/Makefile' fi if test -f 'Spiro/README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Spiro/README'\" else echo shar: Extracting \"'Spiro/README'\" \(2736 characters\) sed "s/^X//" >'Spiro/README' <<'END_OF_FILE' XThis is my first excursion into programming on the NeXT. It uses vector Xaddition to draw a "spirograph." Since I'm not terribly familiar with Xthe NeXT and it's objects, I can't say whether or not I'm doing things Xin the politicaly correct manner, but the program seems to work (with Xa caveat or two that I'll mention in a moment). X XThis application was developed under 0.8, and doesn't use a .nib file. XI haven't gotten 0.9 yet, so I have no idea if it will work with it or Xnot. At least it won't cause problems with the new interface builder. XI didn't use a .nib file for two reasons. First, I really don't think Xthat the interface builder gives me enough control over objects. I'd Xrather create a window with the right background color in its content Xview than have the interface builder create a window with a light grey Xbackground and then change the color during initialization. the second Xreason is that I'm a purist. I don't like having part of my program Xnot under my control. X XSo anyway, I decompiled the entire application and then went into the Xinterface code with my machete and fixed it up. It seems to draw the Xright stuff, but I'm not sure if I'm doing it the right way. There are Xso many methods available through the application kit objects that I Xjust sort of flailed around until I got the behavior I wanted. X XThere's one thing I couldn't figure out how to straighten out. When Xyou enter a number in the matrix of forms that specify the vector Xlengths and rotation values, you must press the return key to cause Xthe final number to be recognized. Mousing or tabbing to another Xentry in the matrix is also good enough, but after you enter the Xlast number in the matrix you have to hit return or it won't see the Xnumber. There's another form (not in a matrix) where you enter the Xnumber of points to display. It is not necessary to press return Xafter entering a number there. Clicking the "draw" button seems to Xbe good enough to cause it to see that number. Only the matrix gives Xme grief. X XBoth the vector lengths and rotation values may be positive or negative Xfloating point numbers. If you click the "Vectors" switch it will use Xinstance drawing to show you the vectors that are being summed to make Xthe graph. This is useful if you want to know why the spirograph looks Xlike it does. It can also dump/load the spirograph to a little text file. XIf you can tell me ways to improve it, please do. Don't blame me if Xyour spirographs are ugly, though. X-- XRoy J. Mongiovi Systems Support Specialist Office of Computing Services XGeorgia Institute of Technology Atlanta, Georgia 30332-0275 (404) 894-4660 X uucp: ...!{allegra,amd,hplabs,ut-ngp}!gatech!prism!roy X ARPA: roy@prism.gatech.edu END_OF_FILE if test 2736 -ne `wc -c <'Spiro/README'`; then echo shar: \"'Spiro/README'\" unpacked with wrong size! fi # end of 'Spiro/README' fi if test -f 'Spiro/Spiro.m' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Spiro/Spiro.m'\" else echo shar: Extracting \"'Spiro/Spiro.m'\" \(447 characters\) sed "s/^X//" >'Spiro/Spiro.m' <<'END_OF_FILE' X X/* Generated by the NeXT Interface Builder */ X X#import <appkit/appkit.h> X#import <dpsclient/dpsclient.h> X#import "Spirograph.h" X Xextern id buildInterface(id); Xextern graph(); X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X DPSTimedEntry handler; X X NXApp = [Spirograph new]; X buildInterface(NXApp); X X handler = DPSAddTimedEntry(0.0, (DPSTimedEntryProc *) &graph, NXApp, NX_BASETHRESHOLD); X [NXApp run]; X DPSRemoveTimedEntry(handler); X} END_OF_FILE if test 447 -ne `wc -c <'Spiro/Spiro.m'`; then echo shar: \"'Spiro/Spiro.m'\" unpacked with wrong size! fi # end of 'Spiro/Spiro.m' fi if test -f 'Spiro/SpiroInterface.m' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Spiro/SpiroInterface.m'\" else echo shar: Extracting \"'Spiro/SpiroInterface.m'\" \(9536 characters\) sed "s/^X//" >'Spiro/SpiroInterface.m' <<'END_OF_FILE' X#import <appkit/appkit.h> X#import "Spirograph.h" X Xid Spiro; /* Spirograph application */ X Xid SpiroInfo; /* Spirograph info panel */ Xid SpiroControl; /* Spirograph control window */ X Xid buildSpiro_SpiroInfo_Button() X{ X NXRect theFrame; X id theButton; X X NXSetRect(&theFrame, 19.0, 30.0, 64.0, 64.0); X theButton = [Button newFrame: &theFrame X title: "SPIRO" X tag: 0 X target: nil X action: NULL X key: 0 X enabled: NO]; X [theButton setType: NX_MOMENTARYPUSH]; X X return theButton; X} X Xid buildSpiro_SpiroInfo_Field1() X{ X NXRect theFrame; X id theTextField; X X NXSetRect(&theFrame, 108.0, 65.0, 99.0, 21.0); X theTextField = [TextField newFrame: &theFrame]; X [theTextField setStringValueNoCopy: "Spirograph"]; X [theTextField setFont: [Font newFont: "Helvetica" size: 18.0]]; X [theTextField setBackgroundGray: NX_LTGRAY]; X [theTextField setTextGray: NX_BLACK]; X [theTextField setAlignment: NX_LEFTALIGNED]; X [theTextField setBordered: NO]; X [theTextField setSelectable: NO]; X X return theTextField; X} X Xid buildSpiro_SpiroInfo_Field2() X{ X NXRect theFrame; X id theTextField; X X NXSetRect(&theFrame, 108.0, 40.0, 148.0, 21.0); X theTextField = [TextField newFrame: &theFrame]; X [theTextField setStringValueNoCopy: "by Roy Mongiovi"]; X [theTextField setFont: [Font newFont: "Helvetica" size: 18.0]]; X [theTextField setBackgroundGray: NX_LTGRAY]; X [theTextField setTextGray: NX_BLACK]; X [theTextField setAlignment: NX_LEFTALIGNED]; X [theTextField setBordered: NO]; X [theTextField setSelectable: NO]; X X return theTextField; X} X Xid buildSpiro_SpiroInfo_VersionNumber() X{ X NXRect theFrame; X id theTextField; X X NXSetRect(&theFrame, 23.0, 12.0, 62.0, 13.0); X theTextField = [TextField newFrame: &theFrame]; X [theTextField setStringValueNoCopy: "Version 1.0"]; X [theTextField setFont: [Font newFont: "Helvetica" size: 10.0]]; X [theTextField setBackgroundGray: NX_LTGRAY]; X [theTextField setTextGray: NX_DKGRAY]; X [theTextField setAlignment: NX_LEFTALIGNED]; X [theTextField setBordered: NO]; X [theTextField setSelectable: NO]; X X return theTextField; X} X Xid buildSpiro_SpiroInfo() X{ X NXRect theFrame; X id theView; X X NXSetRect(&theFrame, 377.0, 644.0, 272.0, 111.0); X SpiroInfo = [Panel newContent: &theFrame X style: NX_TITLEDSTYLE X backing: NX_BUFFERED X buttonMask: NX_CLOSEBUTTONMASK X defer: NO]; X [SpiroInfo setTitle: "Spirograph Info"]; X X theView = [SpiroInfo contentView]; X [theView addSubview:buildSpiro_SpiroInfo_Button()]; X [theView addSubview:buildSpiro_SpiroInfo_Field1()]; X [theView addSubview:buildSpiro_SpiroInfo_Field2()]; X [theView addSubview:buildSpiro_SpiroInfo_VersionNumber()]; X X [SpiroInfo display]; X return SpiroInfo; X} X Xid buildSpiro_SpiroMenu() X{ X id theMenu; X X theMenu = [Menu newTitle: "Spiro"]; X X [[theMenu addItem: "Info..." X action: @selector(orderFront:) X keyEquivalent: 0] X setTarget: SpiroInfo]; X X [[theMenu addItem: "Open..." X action: @selector(open:) X keyEquivalent: 'o'] X setTarget: Spiro]; X X [[theMenu addItem: "Save..." X action: @selector(save:) X keyEquivalent: 's'] X setTarget: Spiro]; X X [[theMenu addItem: "Clear" X action: @selector(clear:) X keyEquivalent: 'c'] X setTarget: Spiro]; X X [[theMenu addItem: "Hide" X action: @selector(hide:) X keyEquivalent: 'h'] X setTarget: Spiro]; X X [[theMenu addItem: "Quit" X action: @selector(terminate:) X keyEquivalent: 'q'] X setTarget: Spiro]; X X [theMenu display]; X return theMenu; X} X Xid buildSpiro_DisplayWindow() X{ X NXRect theFrame; X id theWindow; X id theView; X X NXSetRect(&theFrame, 500.0, 200.0, 520.0, 520.0); X theWindow = [Window newContent: &theFrame X style: NX_TITLEDSTYLE X backing: NX_RETAINED X buttonMask: NX_RESIZEBUTTONMASK X defer: NO]; X [theWindow setTitle:"Spirograph Display Window"]; X [theWindow removeFromEventMask: NX_KEYDOWNMASK | NX_KEYUPMASK]; X [theWindow setBackgroundGray: NX_WHITE]; X X [theWindow display]; X X theView = [theWindow contentView]; X [theView setClipping: NO]; X [Spiro setGraphics: theView]; X return theWindow; X} X Xid buildSpiro_ControlWindow_Field1() X{ X NXRect theFrame; X id theTextField; X X NXSetRect(&theFrame, 39.0, 284.0, 66.0, 21.0); X theTextField = [TextField newFrame: &theFrame]; X [theTextField setStringValueNoCopy: "Length"]; X [theTextField setFont: [Font newFont: "Helvetica" size: 18.0]]; X [theTextField setBackgroundGray: NX_LTGRAY]; X [theTextField setTextGray: NX_BLACK]; X [theTextField setAlignment: NX_CENTERED]; X [theTextField setBordered: NO]; X [theTextField setSelectable: NO]; X X return theTextField; X} X Xid buildSpiro_ControlWindow_Field2() X{ X id theTextField; X NXRect theFrame; X X NXSetRect(&theFrame, 116.0, 284.0, 89.0, 21.0); X theTextField = [TextField newFrame: &theFrame]; X [theTextField setStringValueNoCopy: "Rotations"]; X [theTextField setFont: [Font newFont: "Helvetica" size: 18.0]]; X [theTextField setBackgroundGray: NX_LTGRAY]; X [theTextField setTextGray: NX_BLACK]; X [theTextField setAlignment: NX_CENTERED]; X [theTextField setBordered: NO]; X [theTextField setSelectable: NO]; X X return theTextField; X} X Xid buildSpiro_ControlWindow_Indices() X{ X id theMatrix, theCell, theProtoCell; X NXRect theFrame; X NXSize theSize; X X theProtoCell = [TextFieldCell new]; X X NXSetRect(&theFrame, 6.0, 88.0, 21.0,188.0); X theMatrix = [Matrix newFrame: &theFrame X mode: NX_TRACKMODE X prototype: theProtoCell X numRows: 9 X numCols: 1]; X theSize.width = 21.0; X theSize.height = 21.0; X [theMatrix setCellSize: &theSize]; X theSize.width = 0.0; X theSize.height = 0.0; X [theMatrix setIntercell: &theSize]; X [theMatrix setFont: [Font newFont: "Helvetica" size: 14.0]]; X X [[theMatrix cellAt: 0: 0] setStringValue: "1."]; X [[theMatrix cellAt: 1: 0] setStringValue: "2."]; X [[theMatrix cellAt: 2: 0] setStringValue: "3."]; X [[theMatrix cellAt: 3: 0] setStringValue: "4."]; X [[theMatrix cellAt: 4: 0] setStringValue: "5."]; X [[theMatrix cellAt: 5: 0] setStringValue: "6."]; X [[theMatrix cellAt: 6: 0] setStringValue: "7."]; X [[theMatrix cellAt: 7: 0] setStringValue: "8."]; X [[theMatrix cellAt: 8: 0] setStringValue: "9."]; X X return theMatrix; X} X Xid buildSpiro_ControlWindow_Values() X{ X id theMatrix, theCell, theProtoCell; X NXRect theFrame; X NXSize theSize; X int i; X X theProtoCell = [TextFieldCell new]; X [theProtoCell setBezeled: YES]; X [theProtoCell setEditable: YES]; X X NXSetRect(&theFrame, 27.0, 89.0,174.0,189.0); X theMatrix = [Matrix newFrame: &theFrame X mode: NX_TRACKMODE X prototype: theProtoCell X numRows: 9 X numCols: 2]; X theSize.width = 87.0; X theSize.height = 21.0; X [theMatrix setCellSize: &theSize]; X theSize.width = 0.0; X theSize.height = 0.0; X [theMatrix setIntercell: &theSize]; X X for (i = 0; i < 9; i++) X { X [[theMatrix cellAt: i: 0] setStringValue: ""]; X [[theMatrix cellAt: i: 1] setStringValue: ""]; X } X X [Spiro setValues: theMatrix]; X return theMatrix; X} X Xid buildSpiro_ControlWindow_Form() X{ X NXRect theFrame; X id theForm; X X NXSetRect(&theFrame, 48.0, 51.0, 127.0, 21.0); X theForm = [Form newFrame: &theFrame]; X X [theForm addEntry: "Points"]; X X [Spiro setPoints: theForm]; X return theForm; X} X Xid buildSpiro_ControlWindow_Vectors() X{ X NXRect theFrame; X id theButton; X X NXSetRect(&theFrame, 39.0, 16.0, 64.0, 15.0); X theButton = [Button newFrame: &theFrame X title: "Vectors" X tag: 0 X target: Spiro X action: @selector(vectors:) X key: 0 X enabled: YES]; X [theButton setType: NX_SWITCH]; X X return theButton; X} X Xid buildSpiro_ControlWindow_Draw() X{ X NXRect theFrame; X id theButton; X X NXSetRect(&theFrame, 129.0, 12.0, 63.0, 24.0); X theButton = [Button newFrame: &theFrame X title: "Draw" X tag: 0 X target: Spiro X action: @selector(draw:) X key: 0 X enabled: YES]; X [theButton setType:NX_TOGGLE]; X [theButton setAltTitle: "Stop"]; X X [Spiro setSwitch: theButton]; X return theButton; X} X Xid buildSpiro_ControlWindow() X{ X NXRect theFrame; X id theView; X X NXSetRect(&theFrame, 185.0, 295.0, 224.0, 310.0); X SpiroControl = [Window newContent: &theFrame X style: NX_TITLEDSTYLE X backing: NX_BUFFERED X buttonMask: 0 X defer: NO]; X [SpiroControl setTitle:"Spirograph Control Window"]; X X theView = [SpiroControl contentView]; X [theView addSubview:buildSpiro_ControlWindow_Field1()]; X [theView addSubview:buildSpiro_ControlWindow_Field2()]; X [theView addSubview:buildSpiro_ControlWindow_Indices()]; X [theView addSubview:buildSpiro_ControlWindow_Values()]; X [theView addSubview:buildSpiro_ControlWindow_Form()]; X [theView addSubview:buildSpiro_ControlWindow_Vectors()]; X [theView addSubview:buildSpiro_ControlWindow_Draw()]; X X [SpiroControl display]; X return SpiroControl; X} X Xid buildInterface(owner) Xid owner; X{ X Spiro = owner; X X [buildSpiro_SpiroInfo() orderOut: nil]; X [Spiro setOpen: [OpenPanel new]]; X [Spiro setSave: [SavePanel new]]; X [NXApp setMainMenu: buildSpiro_SpiroMenu()]; X [buildSpiro_DisplayWindow() orderFront: nil]; X [buildSpiro_ControlWindow() orderFront: nil]; X X [Spiro activateSelf: YES]; X [SpiroControl makeKeyWindow]; X X return owner; X} END_OF_FILE if test 9536 -ne `wc -c <'Spiro/SpiroInterface.m'`; then echo shar: \"'Spiro/SpiroInterface.m'\" unpacked with wrong size! fi # end of 'Spiro/SpiroInterface.m' fi if test -f 'Spiro/Spirograph.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Spiro/Spirograph.h'\" else echo shar: Extracting \"'Spiro/Spirograph.h'\" \(601 characters\) sed "s/^X//" >'Spiro/Spirograph.h' <<'END_OF_FILE' X#import <appkit/appkit.h> X#import <appkit/Application.h> X X#define TWO_PI (6.283185307179586476925287) X Xtypedef struct X { X double l; /* Vector length */ X double v; /* Vector velocity */ X } VECTOR; X Xtypedef struct X { X double s; /* Scaled length */ X double a; /* Vector angle */ X double i; /* Angle increment */ X } POINT; X X@interface Spirograph: Application X{ X} X X- setGraphics: anObject; X- setPoints: anObject; X- setValues: anObject; X- setSwitch: anObject; X- setOpen: anObject; X- setSave: anObject; X- open: sender; X- save: sender; X- clear: sender; X- draw: sender; X- vectors: sender; X X@end END_OF_FILE if test 601 -ne `wc -c <'Spiro/Spirograph.h'`; then echo shar: \"'Spiro/Spirograph.h'\" unpacked with wrong size! fi # end of 'Spiro/Spirograph.h' fi if test -f 'Spiro/Spirograph.m' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Spiro/Spirograph.m'\" else echo shar: Extracting \"'Spiro/Spirograph.m'\" \(6407 characters\) sed "s/^X//" >'Spiro/Spirograph.m' <<'END_OF_FILE' X#import <dpsclient/dpsclient.h> X#import <math.h> X#import <stdio.h> X#import "Spirograph.h" X Xchar *Types[] = {"", NULL}; X Xid Graphics; /* Id of View for Graphics */ Xid Points; /* Id of Number of Points Form */ Xid Values; /* Id of Matrix of Forms */ Xid Switch; /* Id of Draw/Stop Button */ Xid Open; /* Id of OpenPanel */ Xid Save; /* Id of SavePanel */ X Xchar Path[256]; /* Path name returned by Open/Save */ Xchar Name[256]; /* Filename returned by Open/Save */ Xchar File[265]; /* Concatenated file name to Open/Save */ X XVECTOR V[9]; /* Vector values read from Values */ Xint Nv; /* Number of non-zero vectors encountered */ Xint Np; /* Number of points from Points */ Xdouble Length; /* Scaled length of vector summation */ X Xdouble Xcenter, Ycenter; /* Offset of center of Graphics View */ X Xdouble X, Y, Row, Col; /* Current and next coordinates */ X XPOINT P[9]; /* Current values of vector endpoints */ X Xint Drawing; /* True if currently drawing */ Xint Current; /* Current point being drawn */ Xchar Showing; /* True if showing vectors */ X X@implementation Spirograph X X- setGraphics: anObject X{ X Graphics = anObject; X return self; X} X X- setPoints: anObject X{ X Points = anObject; X return self; X} X X- setValues: anObject X{ X Values = anObject; X return self; X} X X- setSwitch: anObject X{ X Switch = anObject; X return self; X} X X- setOpen: anObject X{ X Open = anObject; X return self; X} X X- setSave: anObject X{ X Save = anObject; X return self; X} X X- open: sender X{ X FILE *fd; X int i; X X if ([Open runModalForTypes: Types]) X { X strcpy(Path, [Open dirPath]); X strcpy(Name, [Open filename]); X sprintf(File, "%s/%s", Path, Name); X X if (fd = fopen(File, "r")) X { X fscanf(fd, "%d %d\n", &Nv, &Np); X for (i = 0; i < Nv; i++) X fscanf(fd, "%lf %lf\n", &V[i].l, &V[i].v); X fclose(fd); X X [Points setIntValue: Np at: 0]; X for (i = 0; i < Nv; i++) X { X [[Values cellAt: i: 0] setDoubleValue: V[i].l]; X [[Values cellAt: i: 1] setDoubleValue: V[i].v]; X } X } X } X return self; X} X X- save: sender X{ X FILE *fd; X int i; X X if ([Save runModalForDirectory: Path file: Name]) X { X strcpy(Path, [Save dirPath]); X strcpy(Name, [Save filename]); X sprintf(File, "%s/%s", Path, Name); X X if (fd = fopen(File, "w")) X { X for (Nv = i = 0; i < 9; i++) X { X if ((V[i].l = [[Values cellAt: i: 0] doubleValue]) != 0.0) X Nv = i + 1; X V[i].v = [[Values cellAt: i: 1] doubleValue]; X } X Np = [Points intValueAt: 0]; X X fprintf(fd, "%d %d\n", Nv, Np); X for (i = 0; i < Nv; i++) X fprintf(fd, "%f %f\n", V[i].l, V[i].v); X fclose(fd); X } X } X return self; X} X X- clear: sender X{ X int i; X NXRect bounds; X X if (!Drawing) X { X for (i = 0; i < 9; i++) X { X [[Values cellAt: i: 0] setStringValue: ""]; X [[Values cellAt: i: 1] setStringValue: ""]; X } X [Points setStringValue: ""]; X X [Graphics lockFocus]; X [Graphics getBounds: &bounds]; X NXEraseRect(&bounds); X [Graphics unlockFocus]; X } X return self; X} X X- vectors:sender X{ X Showing = [sender state]; X return self; X} X X- draw:sender X{ X int i; X NXRect bounds; X double factor; X X if ([Switch state]) X { X for (Nv = i = 0; i < 9; i++) X { X if ((V[i].l = [[Values cellAt: i: 0] doubleValue]) != 0.0) X Nv = i + 1; X V[i].v = [[Values cellAt: i: 1] doubleValue]; X } X Np = [Points intValueAt: 0]; X X [Graphics lockFocus]; X [Graphics getBounds: &bounds]; X NXEraseRect(&bounds); X X Xcenter = bounds.size.width / 2.0; X Ycenter = bounds.size.height / 2.0; X [Graphics unlockFocus]; X X for (i = 0, Length = 0.0; i < Nv; i++) X Length += fabs(V[i].l); X Length = (MIN(Xcenter, Ycenter) - 2.0) / Length; X X factor = TWO_PI / ((double) Np - 1.0); X X for (X = Y = 0.0, i = 0; i < Nv; i++) X { X Y += (P[i].s = V[i].l * Length); X P[i].a = P[i].i = V[i].v * factor; X } X X Current = 1; X Drawing = YES; X } X else X Drawing = NO; X return self; X} X Xgraph(te, now, app) XDPSTimedEntry te; Xdouble now; Xchar *app; X{ X typedef struct X { X DPSTokenType tokenType; X DPSTopLevelCount topLevelCount; X DPSCard16 nBytes; X X DPSBinObjGeneric obj0; X DPSBinObjReal obj1; X DPSBinObjReal obj2; X DPSBinObjGeneric obj3; X DPSBinObjReal obj4; X DPSBinObjReal obj5; X DPSBinObjGeneric obj6; X DPSBinObjGeneric obj7; X } _dpsQ; X X static _dpsQ _dpsF = X { X DPS_DEF_TOKENTYPE, 8, sizeof(_dpsQ), X {DPS_EXEC | DPS_NAME, 0, -1, 111}, /* newpath */ X {DPS_LITERAL | DPS_REAL, 0, 0, 0}, /* param: X */ X {DPS_LITERAL | DPS_REAL, 0, 0, 0}, /* param: Y */ X {DPS_EXEC | DPS_NAME, 0, -1, 107}, /* moveto */ X {DPS_LITERAL | DPS_REAL, 0, 0, 0}, /* param: Col */ X {DPS_LITERAL | DPS_REAL, 0, 0, 0}, /* param: Row */ X {DPS_EXEC | DPS_NAME, 0, -1, 99}, /* lineto */ X {DPS_EXEC | DPS_NAME, 0, -1, 167}, /* stroke */ X }; X register DPSContext _dpsCurCtxt = DPSPrivGetContext(); X register DPSBinObjRec *_dpsP = (DPSBinObjRec *) &_dpsF.obj0; X X char showing; X NXEvent event; X int i; X X if (!Drawing) X return; X X showing = Showing; X X [Graphics lockFocus]; X [Graphics translate: Xcenter: Ycenter]; X X while (![(id) app peekNextEvent: NX_ALLEVENTS into: &event] && Current++ < Np) X { X if (showing) X { X PSsetinstance(1); X PSnewpath(); X PSmoveto(0.0, 0.0); X } X for (Row = Col = 0.0, i = 0; i < Nv; i++) X { X Row += P[i].s * cos(P[i].a); X Col += P[i].s * sin(P[i].a); X X if (showing) X PSlineto(Col, Row); X X P[i].a += P[i].i; X while (P[i].a >= TWO_PI) X P[i].a -= TWO_PI; X } X if (showing) X { X PSstroke(); X PSsetinstance(0); X DPSFlush(); X X PSnewinstance(); X } X X/* PSnewpath(); */ X/* PSmoveto(X, Y); */ X/* PSlineto(X = Col, Y = Row); */ X/* PSstroke(); */ X X _dpsP[1].val.realVal = X; X _dpsP[2].val.realVal = Y; X _dpsP[4].val.realVal = Col; X _dpsP[5].val.realVal = Row; X DPSBinObjSeqWrite(_dpsCurCtxt,(char *) &_dpsF,sizeof(_dpsQ)); X X X = Col; X Y = Row; X } X if (Current >= Np) X { X [Switch performClick: (id) app]; X DPSFlush(); X } X X [Graphics translate: -Xcenter: -Ycenter]; X [Graphics unlockFocus]; X} X X@end END_OF_FILE if test 6407 -ne `wc -c <'Spiro/Spirograph.m'`; then echo shar: \"'Spiro/Spirograph.m'\" unpacked with wrong size! fi # end of 'Spiro/Spirograph.m' fi echo shar: End of shell archive. exit 0 -- Roy J. Mongiovi Systems Support Specialist Office of Computing Services Georgia Institute of Technology Atlanta, Georgia 30332-0275 (404) 894-4660 uucp: ...!{allegra,amd,hplabs,ut-ngp}!gatech!prism!roy ARPA: roy@prism.gatech.edu
ali@polya.Stanford.EDU (Ali T. Ozer) (04/29/89)
In article <569@hydra.gatech.EDU> roy@prism.gatech.EDU (Roy Mongiovi) writes: >This is my first excursion into programming on the NeXT. It uses vector >addition to draw a "spirograph." Since I'm not terribly familiar with >the NeXT and it's objects, I can't say whether or not I'm doing things >in the politicaly correct manner, but the program seems to work (with >a caveat or two that I'll mention in a moment). Thanks for the program! I haven't had a chance to play with it yet (not near a NeXT machine), but will soon... Hope you don't mind some comments in the meantime. >This application was developed under 0.8, and doesn't use a .nib file. >I haven't gotten 0.9 yet, so I have no idea if it will work with it or >not. At least it won't cause problems with the new interface builder. >I didn't use a .nib file for two reasons. First, I really don't think >that the interface builder gives me enough control over objects. I'd >rather create a window with the right background color in its content >view than have the interface builder create a window with a light grey >background and then change the color during initialization. One way to control any object in any way you want it to make it an outlet of something; say your application object. Then, when the setxxx: method is called, with a handle to that freshly created object, you can go ahead and change any parameters you want. This should give you full control over any objects created by Interface Builder. This might seem inefficient (why create the window with a light gray background and then have it change color at runtime) --- but it isn't. Windows (in the server) are not created until they are actually brought on screen, and this does not happen until your application's "run" method is invoked. Thus at the time the setxxx: methods are being called, only the window object exists, not the actual window memory. So changing the color (and other parameters, like size, contentView, etc), is not expensive --- you are just changing some instance variables in the window object. Keeping your interface in .nib files gives you great flexibility. You needn't worry about your 0.8 .nib file not working in 0.9; although 0.9 .nib format is different than the 0.8 one, 0.8 .nib files can still be read in by the loadNibFile: method. Interface Builder can also read 0.8 .nib files (as well as 0.9, of course); it saves 0.9 format. If you are worried about having to keep one or more .nib files around with the executable (admittedly a pain when you copy/move the application around) 0.9 provides a solution to that: You can now include .nib files (and any other data file you might need) in Mach-O segments of your executable. It's very easy to open a stream bound to data stored in a Mach-O segment; thus you can read any random data from the executable itself. Of course, there are "convenience" methods such as "loadNibSection:," "newFromMachO:," provided to make it real easy to read common forms of data (such as .nib files, TIFF bitmaps, sound data, etc) out. On another note... If you wish to refer to instance variables in a timed entry function, you can simply invoke a method from the timed entry: When installing the timed entry, pass "self" (or whatever the id is) to DPSAddTimedEntry as your "user data." Then, in your timed entry function, graph() in your case, you can invoke a method as shown below: void graph (DPSTimedEntry te, double now, id obj) { [obj someMethod]; } This would allow you to access "obj"s instance variables in "someMethod," making it unnecessary to have the globals you have in Spirograph.m. (Objects whose state is contained totally within their instance variables are a lot nicer to deal with...) In the graph() function, it seems like you used code from a C function generated by pswrap; is that the case? Such generated code might not be very portable (and not very pretty either); you probably want to keep the original pswraps around... Anyway, thanks again --- Can't wait to try the program out. Ali
roy@prism.gatech.EDU (Roy Mongiovi) (05/02/89)
In article <8827@polya.Stanford.EDU>, ali@polya.Stanford.EDU (Ali T. Ozer) writes: > of something; say your application object. Then, when the setxxx: method > is called, with a handle to that freshly created object, you can go ahead > and change any parameters you want. This should give you full control > over any objects created by Interface Builder. > ... > On another note... If you wish to refer to instance variables in a > timed entry function, you can simply invoke a method from the timed entry: > When installing the timed entry, pass "self" (or whatever the id is) to > DPSAddTimedEntry as your "user data." Thanks for the comments, Ali. The program isn't worth a whole lot, but it does click buttons, use postscript to plot, and use timed entries, so I thought it might be of interest to some of the folks out there. I decompiled the interface mostly because I didn't want separate .nib files floating around. It doesn't seem like a good way to keep a finished "product." I agree that it isn't easy to modify once you do that (plus, it's a hassle because of how badly the 0.8 IB botches the interface decompilation). Being able to include the .nib file in the executable will be great. However, it seems to me that once you decompile and start adding code to the stubs that IB gives you, it's impossible to cleanly change the interface except for cosmetics. If I add any new methods or outlets I have to edit in the appropriate code to the already decompiled source since decompiling again will destroy my code. But that's a relatively minor hassle since I should do a good job of designing the interface before I start coding anyway. I did things the way I did in Spiro (with globals, etc.) because I don't like having to use gratuitous function calls. I suppose it shouldn't bother me because they aren't nested in loops, but I'd be a lot happier if objective-c methods and c function fit together better. I was SERIOUSLY disappointed to discover that I cannot use those nice inline functions in math.h from objective c. It seems a real shame that the GNU c compiler allows direct access to the math coprocessor instructions but the objective c prevents it. Roy -- Roy J. Mongiovi Systems Support Specialist Office of Computing Services Georgia Institute of Technology Atlanta, Georgia 30332-0275 (404) 894-4660 uucp: ...!{allegra,amd,hplabs,ut-ngp}!gatech!prism!roy ARPA: roy@prism.gatech.edu