This is SpewView.m in view mode; [Download] [Up]
/* $Id$ */ // SpewView is written by Pedja Bogdanovich // Permission is granted to freely use and distribute this software // provided this notice is left attached and no monetary gain is made. #import "SpewView.h" #import "Thinker.h" #define TEXTTIMEDEFAULT "Spew TextTime" #define SLEEPTIMEDEFAULT "Spew SleepTime" #define MINWIDTHRAT .2 #define MAXWIDTHRAT .75 #define MINCHARS 12 #define MAXFONTRAT .075 #define MINFONTRAT .025 #define MINFONTSIZE 12 #define exp2(x) pow(2,x) #define rnd() ((random()&0xffffff)/(float)0xffffff) static const char *fontlist[]={ "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic" // Add more fonts here... }; static int pointsize[]={ 14,18,24,32,36,48,56,64 // Add more font-sizes here... }; static NXColor pickColor() { int i; float r, g, b; switch([Window defaultDepthLimit]) { case NX_TwoBitGrayDepth: return NXConvertGrayToColor(1.-(random()%2)/3.); case NX_EightBitGrayDepth: return NXConvertGrayToColor(1.-(random()%128)/256.); case NX_TwelveBitRGBDepth: case NX_TwentyFourBitRGBDepth: default: i=random()%4096; r=fmod(i,16)/16; g=fmod(i-r,256)/256; b=(i-fmod(i,256))/4096; r=.2+r*.8; g=.2+g*.8; b=.2+b*.8; /* Not too dark. */ return NXConvertRGBToColor(r,g,b); } } // fontsizes can be made font specific... static float pickFontSize(float fmin, float fmax) { int i, j=sizeof(pointsize)/sizeof(int); int imin=j-1, imax=0; for(i=0;i<j;i++) if(pointsize[i]>=fmin) { imin=i; break; } for(i=0;i<j;i++) if(pointsize[i]<=fmax) imax=i; if(imin>=imax) i=imin; else i=imin+random()%(imax-imin+1); return pointsize[i]; } static Font *pickFont(float sz) { return [Font newFont:fontlist[random()%(sizeof(fontlist)/sizeof(char*))] size:sz /* matrix:NX_IDENTITYMATRIX*/]; } @implementation SpewView + initialize { static NXDefaultsVector spewDefaults={ {TEXTTIMEDEFAULT,"12"}, {SLEEPTIMEDEFAULT,"2"}, {NULL}}; NXRegisterDefaults([NXApp appName],spewDefaults); return [super initialize]; } - initFrame:(const NXRect *)fr { NXSize sz={1e6,1e6}; [super initFrame:fr]; textOnScreen=NO; textView=[[Text alloc] initFrame:NULL]; // [textView setRetainedWhileDrawing:NO]; [textView setVertResizable:YES]; [[textView setHorizResizable:NO] setHorizResizable:NO]; [[textView setSelectable:YES] setEditable:NO]; [textView setMonoFont:YES]; [textView setBackgroundGray:NX_BLACK]; [textView setMaxSize:&sz]; defaultTextTime=atoi(NXGetDefaultValue([NXApp appName],TEXTTIMEDEFAULT)); defaultSleepTime=atoi(NXGetDefaultValue([NXApp appName],SLEEPTIMEDEFAULT)); srandom(time(0)); return self; } // spewAgain method will load new spew text into textView. // textView's text content, font, color, and frame are set. - spewAgain { char buf[200]; char tmpfile[100]; FILE *f; NXRect r; static const int alignment[]={NX_LEFTALIGNED,NX_RIGHTALIGNED,NX_CENTERED}; sprintf(tmpfile,"/tmp/.#tmp_spew%08x",getpid()); sprintf(buf,"sh -c 'cd %s; spew >%s'", [(BSThinker()) moduleDirectory:"Spew"], tmpfile); system(buf); if(f=fopen(tmpfile,"r")) { struct stat statbuf; char *spewtext; float w, h, x, y; fstat(fileno(f),&statbuf); spewtext=alloca(statbuf.st_size+1); fread(spewtext,1,statbuf.st_size,f); spewtext[statbuf.st_size]=0; fclose(f); // Random selections below don't work very well for small windows... // set color [textView setTextColor:pickColor()]; // set font h=pickFontSize(MAX(MINFONTSIZE,NX_HEIGHT(&bounds)*MINFONTRAT), /* min */ NX_HEIGHT(&bounds)*MAXFONTRAT); /* max font size */ [textView setFont:pickFont(h)]; // set width w=MAX(NX_WIDTH(&bounds)*MINWIDTHRAT,MINCHARS*[[textView font] pointSize]); x=NX_WIDTH(&bounds)*MAXWIDTHRAT; if(w<x) w+=(x-w)*rnd(); [textView sizeTo:w :50]; // set content [textView setSel:0 :[textView textLength]]; [textView replaceSel:spewtext]; // set alignment [textView setAlignment:alignment[random()%(sizeof(alignment)/sizeof(int))]]; // set position; height is calculated by the text object [textView getFrame:&r]; w=NX_WIDTH(&r); h=NX_HEIGHT(&r); x=NX_X(&bounds)+(NX_WIDTH(&bounds)-w)*rnd(); y=NX_Y(&bounds)+(NX_HEIGHT(&bounds)-h)*rnd(); [textView moveTo:x :y]; } unlink(tmpfile); return self; } - drawSelf:(NXRect *)rects :(int)rectCount { if(rects==NULL || rectCount==0) return self; PSsetgray(NX_BLACK); NXRectFill(rects); return self; } - inspector:sender { char buf[MAXPATHLEN]; if(!sharedInspectorPanel) { sprintf(buf,"%s/Spew.nib",[sender moduleDirectory:"Spew"]); [NXApp loadNibFile:buf owner:self withNames:NO]; // load default values into inspector [textTimeField setIntValue:defaultTextTime]; [textTimeField sendAction:[textTimeField action] to:[textTimeField target]]; [sleepTimeField setIntValue:defaultSleepTime]; [sleepTimeField sendAction:[sleepTimeField action] to:[sleepTimeField target]]; } return sharedInspectorPanel; } // This method is stolen from BackView - (BOOL)timePassed:(BStimeval)delay { BStimeval now, msec; BOOL result; now=currentTimeInMs(); if(SVthen==0) SVthen=now; /* added by shou-h@nexus.or.jp */ msec=now-SVthen; /* so as not to suck too many cycles, if I'm waiting for some time more than a tenth of a second in the future, I sleep a while. This interval is short enough that the app shouldn't seem unresponsive to user actions. ok, so you'd never pull this trick if the user had to type. A better solution would be to coordinate the timed entry better, but I get slightly better performance from spinning in my timed entry (a bad idea for most apps...) */ if((msec+120)<delay) { usleep(110000); return NO; } result=(msec>delay); if(result) SVthen=now; return result; } - oneStep { int t; char buf[12]; if(sharedInspectorPanel) { t=[textTimeField intValue]; if(t!=defaultTextTime) { /* update default texttime if needed */ sprintf(buf,"%d",t); defaultTextTime=t; NXWriteDefault([NXApp appName],TEXTTIMEDEFAULT,buf); } t=[sleepTimeField intValue]; if(t!=defaultSleepTime) { /* update default sleeptime if needed */ sprintf(buf,"%d",t); defaultSleepTime=t; NXWriteDefault([NXApp appName],SLEEPTIMEDEFAULT,buf); } } if(textOnScreen) { if(![self timePassed:defaultTextTime*1000]) return self; [textView removeFromSuperview]; } else { if(![self timePassed:defaultSleepTime*1000]) return self; [self spewAgain]; [self addSubview:textView]; [window makeFirstResponder:textView]; } textOnScreen=!textOnScreen; [self display]; return self; } @end /* EOF */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.