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.