This is PenView.m in view mode; [Download] [Up]
/* Quite some Code came from the Lines Demo. 100 Generationen Squares stroked 50 sec "" "" filled 74 sec 100 "" NXSquares filled 19 sec */ #import <dpsclient/wraps.h> // For PS and DPS function prototypes #import <appkit/Control.h> // For intValue, etc #import <appkit/Window.h> // We flushWindow at some point #import <appkit/Application.h> // For NX_BASETHRESHOLD and peek event #import <appkit/Panel.h> #import <appkit/NXCursor.h> #import <appkit/Form.h> #import <appkit/graphics.h> #import <appkit/OpenPanel.h> #import <appkit/SavePanel.h> #import <stdio.h> #import "PenView.h" #define Radius 3.0 #define Abstand 7.0 // 2*Radius +1 @implementation PenView - open:sender { id openPanel; const char *fileName; const char *types[2] = {"life", NULL}; FILE *myfile; int *f=feld1,x,y; openPanel = [OpenPanel new]; [openPanel allowMultipleFiles:NO]; if ([openPanel runModalForTypes:types]) { fileName=[openPanel filename]; myfile=fopen(fileName,"rb"); // fread(f,4,Feld_x*Feld_y,myfile); for(y=1;y<=Win_y;y++){ for(x=1;x <= Win_x;x++){ if (fgetc(myfile)==42){ *(f+x+Offset_x+(y+Offset_y)*Feld_x)=1; } else{ *(f+x+Offset_x+(y+Offset_y)*Feld_x)=0; } } fgetc(myfile); } fclose(myfile); } Redraw=1; counter=0; [self display]; [Count setIntValue: counter at:0]; return self; } - save:sender { id savePanel; const char *fileName; FILE *myfile; int *f=feld1,x,y; savePanel = [SavePanel new]; [savePanel setRequiredFileType:"life"]; if ([savePanel runModal]) { fileName=[savePanel filename]; myfile=fopen(fileName,"wb"); // NXRunAlertPanel(NULL, "Couldn't write file", NULL, NULL, NULL); // fwrite(f,sizeof(int),Feld_x*Feld_y,myfile); for(y=1;y<=Win_y;y++){ for(x=1;x <= Win_x;x++){ if (*(f+x+Offset_x+(y+Offset_y)*Feld_x)){ fputc(42,myfile); } else{ fputc(32,myfile); } } fputc(10,myfile); } fclose(myfile); } return self; } -showInfo:sender { if(!infoPanel) { [NXApp loadNibSection:"info.nib" owner:self]; } [infoPanel makeKeyAndOrderFront:self]; return self; } -initFrame:(const NXRect*)frameRect { [super initFrame:frameRect]; pencilCursor=[NXCursor newFromImage:[NXImage newFromSection:"Pipette.tiff"]]; hotSpot.x=0.0; hotSpot.y=15.0; [pencilCursor setHotSpot:&hotSpot]; running=NO; ac=1; return self; } - free { /* be sure to stop the timed entry */ if (running) { DPSRemoveTimedEntry(linesTimedEntry); } return [super free]; } void DrawIt(DPSTimedEntry te, double timeNow, void *data) { /* we set data to self so we can call this method from the timed entry */ [(id)data animate]; } - toggleRun:sender { /* start or stop the timed entry (we're called by a two-state button) */ if (running) { DPSRemoveTimedEntry(linesTimedEntry); running = NO; } else { /* Call the DrawIt() function as often as possible... */ linesTimedEntry = DPSAddTimedEntry(0.0, &DrawIt, self, NX_BASETHRESHOLD); running = YES; } return self; } -square: (float) x:(float) y { NXRect mr; mr.origin.x=x-3.0; mr.origin.y=y-3.0; mr.size.width=6.0; mr.size.height=6.0; NXRectFill(&mr); return self; } - clearView:sender { int x; int *f=feld1,*f2=feld2; Redraw=0; counter=0; [self display]; for(x=0;x < Feld_x*Feld_y;x++){ *f++=0; *f2++=0; } // ***** Testlinie ****** // for(x=1;x < 72;x++){ // *(feld1+x+30*80)=1; // } [Count setIntValue: counter at:0]; return self; } -drawSelf:(NXRect*)rects:(int) rectCount { int x,y; int *f=ac?feld1:feld2; PSsetgray(NX_WHITE); NXRectFill(&bounds); PSsetgray(NX_BLACK); NXFrameRect(&bounds); if(Redraw==1){ PSnewpath(); for(x=1;x <= Win_x;x++){ for(y=1;y<=Win_y;y++){ if (*(f+x+Offset_x+(y+Offset_y)*Feld_x)){ [self square:(x-1) * Abstand+Radius+2: (y-1) * Abstand+Radius+2]; } } } } [window flushWindow]; return self; } -resetCursorRects { [self addCursorRect:&bounds cursor:pencilCursor]; return self; } // A friend of mine develloped this routine on a Atari ST. // It doesn't look nice but it is about 6 times faster than a nice aproach. -(void) calc:(int*)f:(int*)p { register int x,y,sum; register int *rp=f,*wp=p+Feld_x+1,*ws; for(y=1;y<=Feld_y-2;y++) { for(x=1;x<=Feld_x-2;x++) { ws=rp; sum=0; sum+=*ws++; sum+=*ws++; sum+=*ws; ws+=Feld_x-2; sum+=*ws; ws+=2; sum+=*ws; ws+=Feld_x-2; sum+=*ws++; sum+=*ws++; sum+=*ws; *wp=0; if(*(rp+Feld_x+1) && sum>1 && sum<4) { *wp=1; } if(!*(rp+Feld_x+1) && sum==3) *wp=1; wp++; rp++; } wp+=2; rp+=2; } } - animate /* * animate gets called over and over by the timed entry. It does the main * animation. Double-buffering is achieved by: * -drawing the current state in WHITE in the backstore of our buffered window * -computing the next state and making it the current state * -drawing the current state in BLACK in the backstore of our buffered window * -flushing the window... * * Note that this method gets called everytime the timed entry fires. The first * thing this method does is to lock the focus; the last thing it does is to * unlock the focus. Unfortunately, locking and unlocking the focus can be * expensive; thus, to avoid this problem, we sit in a tight loop animating * (with the focus locked) until we detect some event. Then we exit the animate * method, and, unless the user broke the animation, we are assured that this * method will be called asap by the timed entry. Another way to deal with the * lock/unlockFocus expense might be to allocate a graphics state with * allocateGState. (BreakApp example does both these tricks.) */ { NXEvent dummyEvent; // For peeking at the event queue. [self lockFocus]; do { counter++; [self calc:feld1:feld2]; Redraw=1; ac=0; [Count setIntValue: counter at:0]; [self display]; [self calc:feld2:feld1]; Redraw=1; ac=1; [self display]; } while ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent waitFor:0.0 threshold:NX_BASETHRESHOLD] == NULL); [self unlockFocus]; return self; } -mouseDown:(NXEvent*)theEvent { NXPoint currentPos; NXEvent *nextEvent; BOOL looping=1; int oldMask; int checkMask,tempx,tempy; oldMask=[window eventMask]; checkMask= NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK; [window setEventMask:(oldMask| checkMask)]; [self lockFocus]; PSsetlinewidth(1.0); while(looping){ nextEvent=[NXApp getNextEvent:checkMask]; looping=(nextEvent->type != NX_MOUSEUP); currentPos=nextEvent->location; [self convertPoint:¤tPos fromView:nil]; tempx=(int)((currentPos.x-2)/Abstand); tempy=(int)((currentPos.y-2)/Abstand); PSnewpath(); *(feld1+(tempy+Offset_y+1)*Feld_x+tempx+Offset_x+1)^=1; Redraw=1; [self display]; [window flushWindow]; } // end while [self unlockFocus]; [window setEventMask: oldMask]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.