This is NickSpaceView.m in view mode; [Download] [Up]
#import "NickSpaceView.h" #import "NickSpaceWraps.h" #import <appkit/appkit.h> #import <dpsclient/wraps.h> #import <ansi/string.h> #import <bsd/libc.h> #import <stdio.h> @implementation NickSpaceView - calcNext { int i, j; BOOL tryingLeft, tryingRight; // with respect to the CURRENT ORIENTATION!! for (i=0;i<trailCount;i++) { if ((!trails[i].dead && trails[i].maxLength > trails[i].currentLength) || trails[i].currentLength<=1) continue; if (trails[i].tailOrient == UP || trails[i].tailOrient == DOWN) VERTEDGE(trails[i].tailEdge.row,trails[i].tailEdge.col) = 0; else HOREDGE(trails[i].tailEdge.row,trails[i].tailEdge.col) = 0; trails[i].currentLength--; /* update tail edges */ switch (trails[i].tailOrient) { case UP: if (VERTEDGE(trails[i].tailEdge.row+1,trails[i].tailEdge.col)) trails[i].tailEdge.row++; else if (HOREDGE(trails[i].tailEdge.row,trails[i].tailEdge.col)) trails[i].tailOrient = LEFT; else if (HOREDGE(trails[i].tailEdge.row,trails[i].tailEdge.col+1)) { trails[i].tailEdge.col++; trails[i].tailOrient = RIGHT; } break; case DOWN: if (VERTEDGE(trails[i].tailEdge.row-1,trails[i].tailEdge.col)) trails[i].tailEdge.row--; else if (HOREDGE(trails[i].tailEdge.row-1,trails[i].tailEdge.col)) { trails[i].tailEdge.row--; trails[i].tailOrient = LEFT; } else if (HOREDGE(trails[i].tailEdge.row-1,trails[i].tailEdge.col+1)) { trails[i].tailEdge.row--; trails[i].tailEdge.col++; trails[i].tailOrient = RIGHT; } break; case RIGHT: if (HOREDGE(trails[i].tailEdge.row,trails[i].tailEdge.col+1)) trails[i].tailEdge.col++; else if (VERTEDGE(trails[i].tailEdge.row,trails[i].tailEdge.col)) trails[i].tailOrient = DOWN; else if (VERTEDGE(trails[i].tailEdge.row+1,trails[i].tailEdge.col)) { trails[i].tailEdge.row++; trails[i].tailOrient = UP; } break; case LEFT: if (HOREDGE(trails[i].tailEdge.row,trails[i].tailEdge.col-1)) trails[i].tailEdge.col--; else if (VERTEDGE(trails[i].tailEdge.row,trails[i].tailEdge.col-1)) { trails[i].tailEdge.col--; trails[i].tailOrient = DOWN; } else if (VERTEDGE(trails[i].tailEdge.row+1,trails[i].tailEdge.col-1)) { trails[i].tailEdge.row++; trails[i].tailEdge.col--; trails[i].tailOrient = UP; } break; } } /* update head edges */ for (i=0;i<trailCount;i++) { if (firstTime) { trails[i].headEdge = trails[i].tailEdge; trails[i].tailOrient = trails[i].headOrient; } else { trails[i].dead = NO; switch (trails[i].headOrient) { case UP: if (trails[i].headEdge.row < horCount - 1 && !VERTEDGE(trails[i].headEdge.row + 2,trails[i].headEdge.col) && !HOREDGE(trails[i].headEdge.row + 1,trails[i].headEdge.col) && !HOREDGE(trails[i].headEdge.row + 1,trails[i].headEdge.col + 1)) trails[i].headEdge.row++; /* continue UP */ else { tryingLeft = (BOOL)random()%2; for (j=0;j<2;j++) { if (tryingLeft) { if (trails[i].headEdge.col > 0 && !VERTEDGE(trails[i].headEdge.row,trails[i].headEdge.col-1) && !VERTEDGE(trails[i].headEdge.row+1,trails[i].headEdge.col-1) && !HOREDGE(trails[i].headEdge.row,trails[i].headEdge.col-1)) { trails[i].headOrient = LEFT; break; } } else { if (trails[i].headEdge.col < vertCount - 1 && !VERTEDGE(trails[i].headEdge.row,trails[i].headEdge.col+1) && !VERTEDGE(trails[i].headEdge.row+1,trails[i].headEdge.col+1) && !HOREDGE(trails[i].headEdge.row,trails[i].headEdge.col+2)) { trails[i].headEdge.col++; trails[i].headOrient = RIGHT; break; } } if (j==1) trails[i].dead = YES; else tryingLeft = 1 - tryingLeft; } } break; case DOWN: if (trails[i].headEdge.row > 1 && !VERTEDGE(trails[i].headEdge.row - 2,trails[i].headEdge.col) && !HOREDGE(trails[i].headEdge.row - 2,trails[i].headEdge.col) && !HOREDGE(trails[i].headEdge.row - 2,trails[i].headEdge.col + 1)) trails[i].headEdge.row--; /* continue DOWN */ else { tryingRight = (BOOL)random()%2; for (j=0;j<2;j++) { if (tryingRight) { if (trails[i].headEdge.col > 0 && !VERTEDGE(trails[i].headEdge.row,trails[i].headEdge.col-1) && !VERTEDGE(trails[i].headEdge.row-1,trails[i].headEdge.col-1) && !HOREDGE(trails[i].headEdge.row-1,trails[i].headEdge.col-1)) { trails[i].headEdge.row--; trails[i].headOrient = LEFT; break; } } else { if (trails[i].headEdge.col < vertCount - 1 && !VERTEDGE(trails[i].headEdge.row,trails[i].headEdge.col+1) && !VERTEDGE(trails[i].headEdge.row-1,trails[i].headEdge.col+1) && !HOREDGE(trails[i].headEdge.row-1,trails[i].headEdge.col+2)) { trails[i].headEdge.col++; trails[i].headEdge.row--; trails[i].headOrient = RIGHT; break; } } if (j==1) trails[i].dead = YES; else tryingRight = 1 - tryingRight; } } break; case RIGHT: if (trails[i].headEdge.col < vertCount - 1 && !HOREDGE(trails[i].headEdge.row,trails[i].headEdge.col+2) && !VERTEDGE(trails[i].headEdge.row,trails[i].headEdge.col + 1) && !VERTEDGE(trails[i].headEdge.row + 1,trails[i].headEdge.col + 1)) trails[i].headEdge.col++; // continue RIGHT else { tryingRight = (BOOL)random()%2; for (j=0;j<2;j++) { if (tryingRight) { if (trails[i].headEdge.row > 0 && !HOREDGE(trails[i].headEdge.row-1,trails[i].headEdge.col) && !HOREDGE(trails[i].headEdge.row-1,trails[i].headEdge.col+1) && !VERTEDGE(trails[i].headEdge.row-1,trails[i].headEdge.col)) { trails[i].headOrient = DOWN; break; } } else { if (trails[i].headEdge.row < horCount - 1 && !HOREDGE(trails[i].headEdge.row+1,trails[i].headEdge.col) && !HOREDGE(trails[i].headEdge.row+1,trails[i].headEdge.col+1) && !VERTEDGE(trails[i].headEdge.row+2,trails[i].headEdge.col)) { trails[i].headEdge.row++; trails[i].headOrient = UP; break; } } if (j==1) trails[i].dead = YES; else tryingRight = 1 - tryingRight; } } break; case LEFT: if (trails[i].headEdge.col > 1 && !HOREDGE(trails[i].headEdge.row,trails[i].headEdge.col-2) && !VERTEDGE(trails[i].headEdge.row+1,trails[i].headEdge.col-2) && !VERTEDGE(trails[i].headEdge.row,trails[i].headEdge.col-2)) trails[i].headEdge.col--; // continue LEFT else { tryingLeft = (BOOL)random()%2; for (j=0;j<2;j++) { if (tryingLeft) { if (trails[i].headEdge.row > 0 && !HOREDGE(trails[i].headEdge.row-1,trails[i].headEdge.col) && !HOREDGE(trails[i].headEdge.row-1,trails[i].headEdge.col-1) && !VERTEDGE(trails[i].headEdge.row-1,trails[i].headEdge.col-1)) { trails[i].headEdge.col--; trails[i].headOrient = DOWN; break; } } else { if (trails[i].headEdge.row < horCount - 1 && !HOREDGE(trails[i].headEdge.row+1,trails[i].headEdge.col) && !HOREDGE(trails[i].headEdge.row+1,trails[i].headEdge.col-1) && !VERTEDGE(trails[i].headEdge.row+2,trails[i].headEdge.col-1)) { trails[i].headEdge.row++; trails[i].headEdge.col--; trails[i].headOrient = UP; break; } } if (j==1) trails[i].dead = YES; else tryingLeft = 1 - tryingLeft; } } } if (!trails[i].dead) trails[i].currentLength++; } if (!trails[i].dead) { if (trails[i].headOrient == UP || trails[i].headOrient == DOWN) VERTEDGE(trails[i].headEdge.row,trails[i].headEdge.col) = 1; else HOREDGE(trails[i].headEdge.row,trails[i].headEdge.col) = 1; } } firstTime = 0; return self; } - oneStep { int i, level, currCol; /* if window level changed, reinitialize and decide whether to buffer or not */ getWindowLevel([[self window] windowNum],&level); if (level != lastLevel) { lastLevel = level; if (level < NX_NORMALLEVEL) { [self newSize:YES]; image = [[NXImage alloc] initSize:&(bounds.size)]; [image lockFocus]; PSsetgray(0); NXRectFill(&bounds); [image unlockFocus]; } else { [self newSize:YES]; if (image) { [image free]; image = nil; } } } /* erase tail edges, as needed (calc'ed last time through */ PSsetgray(0); for (i=0;i<trailCount;i++) { if ((!trails[i].dead && trails[i].maxLength > trails[i].currentLength) || trails[i].currentLength<=1) continue; if (trails[i].tailOrient == UP || trails[i].tailOrient == DOWN) { doSeg((float)((trails[i].tailEdge.col + 1) * spacing), (float)(trails[i].tailEdge.row * spacing), (float)((trails[i].tailEdge.col + 1) * spacing), (float)((trails[i].tailEdge.row + 1) * spacing)); } else { doSeg((float)(trails[i].tailEdge.col * spacing), (float)((trails[i].tailEdge.row + 1) * spacing), (float)((trails[i].tailEdge.col + 1) * spacing), (float)((trails[i].tailEdge.row + 1) * spacing)); } } PSstroke(); if (image) { [image lockFocus]; /* erase tail edges, as needed (calc'ed last time through) */ PSsetgray(0); for (i=0;i<trailCount;i++) { if ((!trails[i].dead && trails[i].maxLength > trails[i].currentLength) || trails[i].currentLength<=1) continue; if (trails[i].tailOrient == UP || trails[i].tailOrient == DOWN) { doSeg((float)((trails[i].tailEdge.col + 1) * spacing), (float)(trails[i].tailEdge.row * spacing), (float)((trails[i].tailEdge.col + 1) * spacing), (float)((trails[i].tailEdge.row + 1) * spacing)); } else { doSeg((float)(trails[i].tailEdge.col * spacing), (float)((trails[i].tailEdge.row + 1) * spacing), (float)((trails[i].tailEdge.col + 1) * spacing), (float)((trails[i].tailEdge.row + 1) * spacing)); } } PSstroke(); [image unlockFocus]; } [self calcNext]; /* draw head edges, as needed */ currCol = 0; // historical accident--careful not to confuse with currColor PSsetrgbcolor(colors[currCol].red, colors[currCol].green, colors[currCol].blue); for(i = 0;i<trailCount; i++) { if (i==(trailCount*(currCol+1))/numColors) { currCol++; PSstroke(); PSsetrgbcolor(colors[currCol].red, colors[currCol].green, colors[currCol].blue); } if (trails[i].dead) continue; if (trails[i].headOrient == UP || trails[i].headOrient == DOWN) { PSmoveto((float)((trails[i].headEdge.col + 1) * spacing), (float)(trails[i].headEdge.row * spacing)); PSlineto((float)((trails[i].headEdge.col + 1) * spacing), (float)((trails[i].headEdge.row + 1) * spacing)); } else { PSmoveto((float)(trails[i].headEdge.col * spacing), (float)((trails[i].headEdge.row + 1) * spacing)); PSlineto((float)((trails[i].headEdge.col + 1) * spacing), (float)((trails[i].headEdge.row + 1) * spacing)); } } PSstroke(); if (image) { [image lockFocus]; currCol = 0; PSsetrgbcolor(colors[currCol].red, colors[currCol].green, colors[currCol].blue); for(i = 0;i<trailCount; i++) { if (i==(trailCount*(currCol+1))/3) { currCol++; PSstroke(); PSsetrgbcolor(colors[currCol].red, colors[currCol].green, colors[currCol].blue); } if (trails[i].dead) continue; if (trails[i].headOrient == UP || trails[i].headOrient == DOWN) { PSmoveto((float)((trails[i].headEdge.col + 1) * spacing), (float)(trails[i].headEdge.row * spacing)); PSlineto((float)((trails[i].headEdge.col + 1) * spacing), (float)((trails[i].headEdge.row + 1) * spacing)); } else { PSmoveto((float)(trails[i].headEdge.col * spacing), (float)((trails[i].headEdge.row + 1) * spacing)); PSlineto((float)((trails[i].headEdge.col + 1) * spacing), (float)((trails[i].headEdge.row + 1) * spacing)); } } PSstroke(); [image unlockFocus]; } return self; } - initFrame:(NXRect *)frameRect { char nibPath[MAXPATHLEN]; NXDefaultsVector defaults = { { "spacing", "" }, { "tcRatio", "" }, { "tlRatio", "" }, { "grays", "" }, { "reds", "" }, { "greens", "" }, { "blues", "" }, { NULL } }; char scratch[128], scratch2[64]; int i; srandom(time(0)); [super initFrame:frameRect]; /* these are preserved from bezierView--I don't know if they're doing any good */ [self allocateGState]; // For faster lock/unlockFocus [self setClipping:NO]; // even faster... /* Miscellaneous initializations */ image = nil; lastLevel = 0; sprintf(nibPath,[[NXApp delegate] moduleDirectory:"NickSpace"]); strcat(nibPath,"/NickSpace.nib"); [NXApp loadNibFile:nibPath owner:self]; /* Set target/action for each control */ [[spaceControl setTarget:self] setAction:@selector(getSpacingFrom:)]; [[countControl setTarget:self] setAction:@selector(getNumberFrom:)]; [[lengthControl setTarget:self] setAction:@selector(getMaxLenFrom:)]; [[colorWell setTarget:self] setAction:@selector(updateCurrColor:)]; [[colorScrollers setTarget:self] setAction:@selector(scrollColor:)]; [[[addRemoveButtons cellAt:0 :0] setTarget:self] setAction:@selector(addColor:)]; [[[addRemoveButtons cellAt:1 :0] setTarget:self] setAction:@selector(removeColor:)]; /* Check the first default; if it hasn't been written before, get all * parameters from the controls; else, read all defaults and set the controls */ NXRegisterDefaults("NickSpace",defaults); if (strlen(NXGetDefaultValue("NickSpace","spacing"))==0) { // Some empirically determined initial settings: spacing = 8; tcRatio = .6; tlRatio = 1.0; numColors = 10; currColor = 0; colors = (rgbColor *)malloc(sizeof(rgbColor)*numColors); sprintf(scratch,"%d",spacing); NXWriteDefault("NickSpace","spacing",scratch); sprintf(scratch,"%f",tcRatio); NXWriteDefault("NickSpace","tcRatio",scratch); sprintf(scratch,"%f",tlRatio); NXWriteDefault("NickSpace","tlRatio",scratch); sprintf(scratch,"%i",numColors); NXWriteDefault("NickSpace","numColors",scratch); // randomize an initial set of colors: for (i=0;i<numColors;i++) { colors[i].red = (float)random()/(float)MAXLONG; colors[i].green = (float)random()/(float)MAXLONG; colors[i].blue = (float)random()/(float)MAXLONG; sprintf(scratch,"%f %f %f",colors[i].red, colors[i].green, colors[i].blue); sprintf(scratch2,"color%d",i); NXWriteDefault("NickSpace",scratch2,scratch); } } else { spacing = atoi(NXGetDefaultValue("NickSpace","spacing")); tcRatio = atof(NXGetDefaultValue("NickSpace","tcRatio")); tlRatio = atof(NXGetDefaultValue("NickSpace","tlRatio")); numColors = atoi(NXGetDefaultValue("NickSpace","numColors")); currColor = 0; colors = (rgbColor *)malloc(sizeof(rgbColor)*numColors); for (i=0;i<numColors;i++) { sprintf(scratch2,"color%d",i); sprintf(scratch,"%s",NXGetDefaultValue("NickSpace",scratch2)); sscanf(scratch,"%f %f %f",&(colors[i].red),&(colors[i].green),&(colors[i].blue)); } } [spaceControl setIntValue:spacing]; [countControl setFloatValue:tcRatio]; [lengthControl setFloatValue:tlRatio]; [colorWell setColor:NXConvertRGBToColor(colors[currColor].red,colors[currColor].green, colors[currColor].blue)]; sprintf(scratch,"%d/%d",currColor+1,numColors); [numColorsField setStringValue:scratch]; [self newSize:NO]; return self; } - sizeTo:(NXCoord)width :(NXCoord)height { [super sizeTo:width :height]; [self newSize:YES]; return self; } - drawSelf:(const NXRect *)rects :(int)rectCount { int i; if (!rects || !rectCount) return self; for (i=0;i<rectCount;i++) [image composite:NX_COPY fromRect:&(rects[i]) toPoint:&(rects[i].origin)]; return self; } /* next two methods do initializations */ - newSize:(BOOL)freeOld; { if (freeOld) { free(horEdges); free(vertEdges); free(trails); } horCount = (int)((bounds.size.height - 5.0) / spacing); vertCount = (int)((bounds.size.width - 5.0) / spacing); horEdges = (char *)malloc(HORSIZE); vertEdges = (char *)malloc(VERTSIZE); bzero(horEdges,HORSIZE); bzero(vertEdges,VERTSIZE); trailCount = (int)((vertCount + horCount) * tcRatio); trailCount = trailCount ? trailCount : 1; trails = (trail *)malloc(sizeof(trail)*trailCount); maxTrailLen = (vertCount + horCount) * 4 * tlRatio; minTrailLen = maxTrailLen/40; maxTrailLen = maxTrailLen < 2 ? 2 : maxTrailLen; minTrailLen = minTrailLen < 2 ? 2 : minTrailLen; firstTime = YES; [self startTrails]; if ([self window]) { [self lockFocus]; PSsetgray(0); NXRectFill(&bounds); [self unlockFocus]; } if (image){ [image lockFocus]; PSsetgray(0); NXRectFill(&bounds); [image unlockFocus]; } return self; } - startTrails { int i,j; BOOL dup; int initPos[trailCount]; /* This could potentially take arbitrarily long--should tighten up; */ for (i=0;i<trailCount;) { dup = NO; if (trailCount < vertCount + horCount) { initPos[i] = (random() % (vertCount + horCount))*2; for (j=0;j<i;j++) { if (initPos[j] == initPos[i]) { dup = YES; break; } } } else initPos[i] = i * 2; if (!dup) i++; } for (i=0;i<trailCount;i++) { trails[i].currentLength = 1; if (tlRatio == 1.0) trails[i].maxLength = MAXINT; else trails[i].maxLength = (random() % ((maxTrailLen - minTrailLen) + 1) + minTrailLen); trails[i].dead = NO; if (initPos[i] < vertCount) { trails[i].tailEdge.row = 0; trails[i].tailEdge.col = initPos[i]; trails[i].headOrient = UP; continue; } if (vertCount <= initPos[i] && initPos[i] < vertCount + horCount) { trails[i].tailEdge.row = initPos[i] - vertCount; trails[i].tailEdge.col = vertCount; trails[i].headOrient = LEFT; continue; } if (vertCount + horCount <= initPos[i] && initPos[i] < (2*vertCount + horCount)) { trails[i].tailEdge.row = horCount; trails[i].tailEdge.col = initPos[i] - (vertCount + horCount); trails[i].headOrient = DOWN; continue; } trails[i].tailEdge.row = initPos[i] - (2*vertCount + horCount); trails[i].tailEdge.col = 0; trails[i].headOrient = RIGHT; } return self; } - inspector:sender { return inspector; } - updateCurrColor:sender { char scratch[128],scratch2[16];; NXConvertColorToRGB([sender color],&(colors[currColor].red), &(colors[currColor].green), &(colors[currColor].blue)); sprintf(scratch2,"color%d",currColor); sprintf(scratch,"%f %f %f",colors[currColor].red,colors[currColor].green, colors[currColor].blue); NXWriteDefault("NickSpace",scratch2,scratch); return self; } - scrollColor:sender { char scratch[32]; if ([sender selectedRow]==1) currColor = currColor==0 ? numColors-1 : currColor-1; else currColor = (currColor + 1)%numColors; [colorWell setColor:NXConvertRGBToColor(colors[currColor].red, colors[currColor].green, colors[currColor].blue)]; sprintf(scratch,"%d/%d",currColor+1,numColors); [numColorsField setStringValue:scratch]; return self; } - addColor:sender { char scratch[128],scratch2[32]; numColors++; colors = (rgbColor *)realloc(colors,sizeof(rgbColor)*numColors); currColor = numColors-1; colors[currColor].red = (float)random()/(float)MAXLONG; colors[currColor].green = (float)random()/(float)MAXLONG; colors[currColor].blue = (float)random()/(float)MAXLONG; sprintf(scratch2,"color%d",currColor); sprintf(scratch,"%f %f %f",colors[currColor].red, colors[currColor].green, colors[currColor].blue); NXWriteDefault("NickSpace",scratch2,scratch); sprintf(scratch,"%d",numColors); NXWriteDefault("NickSpace","numColors",scratch); [colorWell setColor:NXConvertRGBToColor(colors[currColor].red, colors[currColor].green, colors[currColor].blue)]; sprintf(scratch,"%d/%d",currColor+1,numColors); [numColorsField setStringValue:scratch]; return self; } - removeColor:sender { int i; char scratch2[128],scratch[32]; if (numColors==1) return self; for (i=currColor;i<numColors-1;i++) { colors[i] = colors[i+1]; sprintf(scratch2,"color%d",i); sprintf(scratch,"%f %f %f",colors[i].red, colors[i].green, colors[i].blue); NXWriteDefault("NickSpace",scratch2,scratch); } numColors--; sprintf(scratch2,"color%d",numColors); NXRemoveDefault("NickSpace",scratch2); sprintf(scratch,"%d",numColors); NXWriteDefault("NickSpace","numColors",scratch); currColor %= numColors; [colorWell setColor:NXConvertRGBToColor(colors[currColor].red, colors[currColor].green, colors[currColor].blue)]; sprintf(scratch,"%d/%d",currColor+1,numColors); [numColorsField setStringValue:scratch]; return self; } - getSpacingFrom:sender; { char scratch[128]; spacing = [sender intValue]; sprintf(scratch,"%d",spacing); NXWriteDefault("NickSpace","spacing",scratch); [self newSize:YES]; return self; } - getNumberFrom:sender { char scratch[128]; tcRatio = [sender floatValue]; sprintf(scratch,"%f",tcRatio); NXWriteDefault("NickSpace","tcRatio",scratch); [self newSize:YES]; return self; } - getMaxLenFrom:sender { char scratch[128]; tlRatio = [sender floatValue]; sprintf(scratch,"%f",tlRatio); NXWriteDefault("NickSpace","tlRatio",scratch); [self newSize:YES]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.