This is LinesView.m in view mode; [Download] [Up]
#import "LinesView.h" #import <dpsclient/wraps.h> // For PS and DPS function prototypes #import <appkit/Application.h> // For NX_BASETHRESHOLD and peek event #import <appkit/Control.h> // For intValue, etc #import <appkit/Window.h> // We flushWindow at some point #import <appkit/Menu.h> #import <appkit/MenuCell.h> #import <appkit/Form.h> // For Inspector. #import <appkit/Slider.h> // For Inspector. #import <appkit/nextstd.h> // For MIN MAX #import <libc.h> // For random(), etc... #import <soundkit/Sound.h> #import <strings.h> #import <ldsyms.h> #import <sys/loader.h> #define RANDINT(n) (random() % (n+1)) // Return random integer 0..n #define XVEL corners[cnt].xVel // Some slimy shortcuts, asuuming we're #define YVEL corners[cnt].yVel // using "cnt" as corner counter. #define XLOC corners[cnt].xLoc #define YLOC corners[cnt].yLoc #define MAXVEL 12 // Maximum velocity of corners static struct mach_header *header; // The header used for loading static id customSubmenu; // Submenu handle for possible extension static id bouncePanel; // Variables needed for inspector. static id bounceWidth; static id bounceHeight; static id bounceNumVertex; @implementation LinesView + setCustomComponentData:(struct mach_header *)hd customMenu:(id)subMenu { id box; id mCell; id classObj; header = hd; customSubmenu = subMenu; mCell = [customSubmenu addItem:"Bouncing Lines" action:@selector(showAlert) keyEquivalent:0]; classObj = [[LinesView alloc] init]; [mCell setTarget:classObj]; [customSubmenu display]; // Setup Inspector. N.B. This technique provides one inspector for all instances. [NXApp loadNibSection:"BounceLineInspect.nib" owner:classObj withNames:YES fromHeader:header]; bouncePanel = NXGetNamedObject("bounceLinesInspectorPanel" , classObj); box = NXGetNamedObject("sizeBox" , bouncePanel); bounceWidth = NXGetNamedObject("boxSizeWidth" , box); [bounceWidth setAction:@selector(setBounceWidth:)]; bounceHeight = NXGetNamedObject("boxSizeHeight" , box); [bounceHeight setAction:@selector(setBounceHeight:)]; box = NXGetNamedObject("vertexBox" , bouncePanel); bounceNumVertex = NXGetNamedObject("numVertexSlider" , box); [bounceNumVertex setAction:@selector(setBounceNumVertex:)]; return classObj; } - (void) showAlert { NXRunAlertPanel(NULL, "Custom Menu Activated", NULL, NULL, NULL); } - initCustomComponent { NXRect frm; int ldata; char *sd, *sectdata; char *soundFile=malloc(512); sd = (char *)getsectdatafromheader(header, "__MVCUST", "initdata", &ldata); sectdata = malloc(ldata + 1); strcpy(sectdata, sd); sscanf(sectdata, "%f %f %f %f", &frm.origin.x, &frm.origin.y, &frm.size.width, &frm.size.height); self = [super initFrame:&frm]; NXSetRect(&drawRect,bounds.origin.x,bounds.origin.y, bounds.size.width,bounds.size.height); NXInsetRect(&drawRect,2.0,2.0); running = NO; srandom(time(0)); // Randomize numCorners = 5; [self createOpsArray]; [self resetBoundingBox]; [self initCorners]; [self initPath]; [self display]; if( sscanf(strchr(sectdata,'\n')+1, "%s", soundFile) != EOF ) { viewSound = [Sound newFromSoundfile:soundFile]; [viewSound setDelegate:self]; playing = NO; } free(sectdata); return self; } - (void) initPath { int cnt; for (cnt = 0; cnt < numCorners; cnt++) { XLOC += XVEL; YLOC += YVEL; if (XLOC >= drawRect.size.width) { XLOC = drawRect.size.width-1; XVEL = -1-RANDINT(MAXVEL); } else if (XLOC < drawRect.origin.x) { XLOC = drawRect.origin.x; XVEL = 1+RANDINT(MAXVEL); } if (YLOC >= drawRect.size.height) { YLOC = drawRect.size.height-1; YVEL = -1-RANDINT(MAXVEL); } else if (YLOC < drawRect.origin.y) { YLOC = drawRect.origin.y; YVEL = 1+RANDINT(MAXVEL); } if (XLOC < boundingBox[0]) boundingBox[0] = XLOC-1; if (YLOC < boundingBox[1]) boundingBox[1] = YLOC-1; if (XLOC > boundingBox[2]) boundingBox[2] = XLOC+1; if (YLOC > boundingBox[3]) boundingBox[3] = YLOC+1; data[cnt * 2] = XLOC; data[cnt * 2 + 1] = YLOC; } } - initCorners { int cnt; for (cnt = 0; cnt < MAXNUMCORNERS; cnt++) { XLOC = (int)(drawRect.size.width) / 2; YLOC = (int)(drawRect.size.height) / 2; XVEL = (RANDINT(1) ? 1 : -1) * (1 + RANDINT(MAXVEL/2)); YVEL = (RANDINT(1) ? 1 : -1) * (1 + RANDINT(MAXVEL/2)); } return self; } - (void) createOpsArray { int cnt; ops[0] = dps_moveto; for (cnt = 1; cnt < numCorners; cnt++) ops[cnt] = dps_lineto; ops[numCorners] = dps_closepath; } void DrawAll (DPSTimedEntry te, double timeNow, void *data) { [(id)data animate]; } /* - adjustScroll:(NXRect *)newVisible { BOOL visible; visible = NXIntersectsRect(&frame,newVisible); if( visible && !running ) { [self toggleRun]; [self togglePlay]; } if( !visible && running ) { [self toggleRun]; [self togglePlay]; } return self; } */ - (BOOL)acceptsFirstMouse { return YES; } - mouseDown:(NXEvent *)e { if( e->flags & NX_COMMANDMASK ) { [self togglePlay]; } else { [self toggleRun]; } return self; } - toggleRun { if (running) { DPSRemoveTimedEntry (linesTimedEntry); running = NO; } else { linesTimedEntry=DPSAddTimedEntry(0.1, &DrawAll,self,20); running = YES; } return self; } - togglePlay { if( viewSound ) { if( playing) { playing = NO; [viewSound stop]; } else { playing = YES; [viewSound play]; } } return self; } - free { if ( running ) DPSRemoveTimedEntry (linesTimedEntry); if ( playing ) [self togglePlay]; return [super free]; } - resetBoundingBox { boundingBox[0] = drawRect.origin.x; boundingBox[1] = drawRect.origin.y; boundingBox[2] = drawRect.origin.x + drawRect.size.width; boundingBox[3] = drawRect.origin.y + drawRect.size.height; return self; } - drawSelf:(NXRect *)rects :(int)rectCount { NXEraseRect (&bounds); [self resetBoundingBox]; NXFrameRectWithWidth(&bounds,2.0); return self; } - (void) animate { int cnt; NXEvent dummyEvent; // For peeking at the event queue. [self lockFocus]; do { [self eraseCurrentPath]; boundingBox[0] = 10000; // min x boundingBox[1] = 10000; // min y boundingBox[2] = 0; // max x boundingBox[3] = 0; // max y for (cnt = 0; cnt < numCorners; cnt++) { XLOC += XVEL; YLOC += YVEL; if (XLOC >= drawRect.size.width) { XLOC = drawRect.size.width-1; XVEL = -1-RANDINT(MAXVEL); } else if (XLOC < drawRect.origin.x) { XLOC = drawRect.origin.x; XVEL = 1+RANDINT(MAXVEL); } if (YLOC >= drawRect.size.height) { YLOC = drawRect.size.height-1; YVEL = -1-RANDINT(MAXVEL); } else if (YLOC < drawRect.origin.y) { YLOC = drawRect.origin.y; YVEL = 1+RANDINT(MAXVEL); } if (XLOC < boundingBox[0]) boundingBox[0] = XLOC-1; if (YLOC < boundingBox[1]) boundingBox[1] = YLOC-1; if (XLOC > boundingBox[2]) boundingBox[2] = XLOC+1; if (YLOC > boundingBox[3]) boundingBox[3] = YLOC+1; data[cnt * 2] = XLOC; data[cnt * 2 + 1] = YLOC; } [self drawCurrentPath:NX_BLACK]; [[self window] flushWindow]; } while ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent waitFor:0.0 threshold:NX_BASETHRESHOLD] == NULL); [self unlockFocus]; } - drawCurrentPath:(float)color { PSsetgray (color); PSsetlinewidth (0.0); DPSDoUserPath (data, numCorners*2, dps_short, ops, numCorners+1, boundingBox, dps_ustroke); return self; } - (void) eraseCurrentPath { NXEraseRect (&drawRect); } // Sound delegate. - didPlay:sender { if( playing ) [viewSound play]; return self; } // Archiving methods - write:(NXTypedStream *)stream { int lTE = (int)linesTimedEntry; [super write:stream]; NXWriteTypes(stream,"ccii",&running,&playing,&numCorners,&lTE); NXWriteRect(stream,&drawRect); NXWriteArray(stream,"{iiii}",MAXNUMCORNERS,corners); NXWriteArray(stream,"c",MAXNUMCORNERS+1,ops); NXWriteArray(stream,"s",MAXNUMCORNERS*2,data); NXWriteArray(stream,"s",4,boundingBox); NXWriteObject(stream,viewSound); return self; } - read:(NXTypedStream *)stream { int lTE; [super read:stream]; NXReadTypes(stream,"ccii",&running,&playing,&numCorners,&lTE); linesTimedEntry = (DPSTimedEntry) lTE; NXReadRect(stream,&drawRect); NXReadArray(stream,"{iiii}",MAXNUMCORNERS,corners); NXReadArray(stream,"c",MAXNUMCORNERS+1,ops); NXReadArray(stream,"s",MAXNUMCORNERS*2,data); NXReadArray(stream,"s",4,boundingBox); viewSound = NXReadObject(stream); return self; } // Inspector Methods - inspectCustomComponent { [bounceWidth setTarget:self]; [bounceHeight setTarget:self]; [bounceNumVertex setTarget:self]; [bounceNumVertex setIntValue:numCorners]; [bounceWidth setIntValue:bounds.size.width at:0]; [bounceWidth selectTextAt:0]; [bounceHeight setIntValue:bounds.size.height at:0]; [bouncePanel display]; [bouncePanel makeKeyAndOrderFront:self]; return self; } - setBounceWidth:sender { NXRect frm; [self getFrame:&frm]; frm.size.width = [sender intValue]; frm.size.height = [bounceHeight intValue]; [self setFrame:&frm]; [sender selectTextAt:0]; NXSetRect(&drawRect,bounds.origin.x,bounds.origin.y, bounds.size.width,bounds.size.height); NXInsetRect(&drawRect,2.0,2.0); [[self superview] display]; return self; } - setBounceHeight:sender { NXRect frm; [self getFrame:&frm]; frm.size.height = [sender intValue]; frm.size.width = [bounceWidth intValue]; [self setFrame:&frm]; [sender selectTextAt:0]; NXSetRect(&drawRect,bounds.origin.x,bounds.origin.y, bounds.size.width,bounds.size.height); NXInsetRect(&drawRect,2.0,2.0); [[self superview] display]; return self; } - setBounceNumVertex:sender { numCorners = MIN(MAXNUMCORNERS,MAX([sender intValue],MINNUMCORNERS)); [self createOpsArray]; [self resetBoundingBox]; [self display]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.