This is FuncView.m in view mode; [Download] [Up]
#include "FuncView.h" #define vertclip(X) MIN(MAX((X),0),funcFrame.size.height) #define horiclip(X) MIN(MAX((X),funcFrame.origin.x),funcFrame.origin.x + funcFrame.size.width-1) #define tableclip(X) MIN(MAX((X),0),tableLength-1) #define near(X) ratio * ((int) floor((X)/ratio + .45)) #define under(X) ratio * ((int) floor((X)/ratio)) #define over(X) ratio * ((int) ceil((X)/ratio)) #define BORDER 12. @implementation FuncView + newFrame:(NXRect *) frameRect { self = [super newFrame:frameRect]; // Create a border around the view where it is possible to clic without modifying the FuncTable frame.size.height += 2 * BORDER ; frame.size.width += 2* BORDER ; [self setFrame:&frame]; [self translate:BORDER :BORDER]; funcFrame = bounds; funcFrame.origin.x = 0. ; funcFrame.origin.y = -1. ; clip = funcFrame; clip.size.height += 1; tableLength = funcFrame.size.width ; FuncTable = (float *) calloc(tableLength,sizeof(float)); displayMode = CONTINUOUS; editableFlag = YES; scrollable = NO; ratio = 1; return self; } -setScrollView:anObject { if([anObject class] != [ScrollView class]) return self; scrollable = YES; scrollView = anObject; [self removeFromSuperview]; [scrollView setDocView:self]; [scrollView setHorizScrollerRequired:YES]; [scrollView setBorderType:NX_LINE]; [scrollView display]; return self; } - drawSelf:(NXRect *) rect : (int) rectCount { int i; NXRectClip(&clip); NXEraseRect(rect); PSsetgray(NX_BLACK); if(displayMode == CONTINUOUS || ratio == 1) { PSmoveto(under(rect->origin.x),FuncTable[(int)(MAX(under(rect->origin.x)/ratio,0))] * funcFrame.size.height); for(i=under(rect->origin.x);i<=over(rect->origin.x + rect->size.width);i+=ratio) PSlineto((float)i,FuncTable[(int)tableclip(i/ratio)] * funcFrame.size.height); } else { PSmoveto(rect->origin.x-ratio,0.); PSlineto(rect->origin.x + rect->size.width + ratio,0.); for(i=under(rect->origin.x);i<=over(rect->origin.x + rect->size.width);i+=ratio) { PSmoveto((float)i,0.); PSlineto((float)i,FuncTable[(int)tableclip(i/ratio)] * funcFrame.size.height); } } PSstroke(); return self; } -mouseDown:(NXEvent *) anEvent { int looping = YES; int i,anOffset,aLength; int oldMask; int inside; float xmin,xmax,ymin,ymax,dx,funcmin,funcmax; NXEvent *nextEvent; NXPoint cursor; NXPoint lastx; NXRect white; NXRect visible = funcFrame; if(editableFlag == NO) return self; oldMask = [window addToEventMask:NX_LMOUSEDRAGGEDMASK]; [self lockFocus]; if(scrollable) [scrollView getDocVisibleRect:&visible]; funcFrame.size.width = visible.size.width; funcFrame.origin.x = visible.origin.x ; NXRectClip(&clip); PSsetgray(NX_BLACK); lastx = anEvent->location; [self convertPoint:&lastx fromView:nil]; while(looping) { nextEvent = [NXApp getNextEvent:(NX_LMOUSEUPMASK | NX_LMOUSEDRAGGEDMASK)]; switch(nextEvent -> type) { case NX_LMOUSEUP: looping = NO; [self afterUp:FuncTable length:tableLength]; break; case NX_LMOUSEDRAGGED: [self convertPoint:&nextEvent->location fromView:nil]; inside = NXPointInRect(&(nextEvent->location),&funcFrame); cursor = nextEvent->location; // If the last and current cursors are outside the editable window, then don'd do anything! if(lastx.x != horiclip(lastx.x) && cursor.x != horiclip(cursor.x)) continue; if(lastx.x - cursor.x < 0) // Mouse moving right { xmin = near(lastx.x); xmax = near(cursor.x); ymin = vertclip( lastx.y); ymax = vertclip( cursor.y); } else // Mouse moving left { xmin = near(cursor.x); xmax = near(lastx.x) ; ymin = vertclip( cursor.y); ymax = vertclip( lastx.y) ; } dx = xmax-xmin; white.origin.x = xmin - (ratio > 1)*ratio; white.origin.y = -1.; white.size.height = clip.size.height; white.size.width = dx + ( (ratio > 1)? 2*ratio : .2); NXEraseRect(&white); funcmin = FuncTable[(int)tableclip(xmin/ratio-1)]*funcFrame.size.height; funcmax = FuncTable[(int)tableclip(xmax/ratio+1)]*funcFrame.size.height; if(displayMode == CONTINUOUS || ratio == 1) { PSmoveto(xmin-ratio, funcmin); for(i=(int)xmin;i<=(int)xmax;i+=ratio) { float ddx = MAX(dx,1.); float value; if(i < 0 || i/ratio - tableLength >= 0) continue; value = ymin*(1 - ((float)i-xmin)/ddx) + ymax*(((float)i-xmin)/ddx) ; FuncTable[(int)(i/ratio)] = value / funcFrame.size.height; PSlineto((float)i,value); } PSlineto(xmax+ratio, funcmax); } else { PSmoveto(xmin-ratio,funcmin); PSlineto(xmin-ratio, 0.); PSlineto(xmax+ratio, 0.); for(i=(int)xmin;i<=(int)xmax;i+=ratio) { float ddx = MAX(dx,1.); float value; if(i < 0 || i/ratio - tableLength >= 0) continue; value = ymin*(1 - ((float)i-xmin)/ddx) + ymax*(((float)i-xmin)/ddx) ; PSmoveto ((float)i,0.); PSlineto((float)i,value); FuncTable[(int)(i/ratio)] = value / funcFrame.size.height; } } PSstroke(); [window flushWindow]; anOffset = tableclip(xmin/ratio); aLength = tableclip(i/ratio-1) - anOffset+1; [self afterDrag:FuncTable length:aLength offset:anOffset]; lastx = cursor; break; default : break; } } [window setEventMask: oldMask]; [self unlockFocus]; return self; } -afterDrag:(float*) data length:(int)aLength offset:(int)anOffset { return self; } - afterUp:(float*)data length:(int)aLength { return self; } -(float*) table { return FuncTable; } - (int) tableLength { return tableLength; } -(int)setFuncTable:(float*)data length:(int)aLength offset:(int)anOffset { int i; float *indTable; float *indData; indTable=FuncTable+anOffset; indData=data; for(i=0;i<MIN(aLength,tableLength-anOffset);i++) *(indTable++) = *(indData++); return (int)MIN(aLength,tableLength-anOffset); } -draw:sender { switch(scrollable) { case YES : [scrollView display]; break; case NO : [self display]; break; } return self; } -setDisplayMode:(int)aMode { if(aMode == CONTINUOUS || aMode == DISCRETE) displayMode = aMode; [self draw:self]; return(self); } -(int)setTableLength:(int)aLength { if(aLength > 0 && scrollable == YES) { tableLength = aLength; } if(aLength > 0 && scrollable == NO) { tableLength = (int) MIN(aLength,frame.size.width - 2*BORDER); ratio = (int) floor((frame.size.width - 2*BORDER) / tableLength + 0.5); } free(FuncTable); FuncTable = (float *) calloc(tableLength,sizeof(float)); frame.size.width = tableLength * ratio + 2*BORDER ; bounds.size.width = tableLength * ratio ; clip.size.width = tableLength * ratio ; funcFrame.size.width = tableLength * ratio ; [superview descendantFrameChanged:self]; return(tableLength); } -zoomIn:sender { if(scrollable == YES) { ratio *= 2; frame.size.width = tableLength * ratio + 2*BORDER ; bounds.size.width = tableLength * ratio ; clip.size.width = tableLength * ratio ; funcFrame.size.width = tableLength * ratio ; [superview descendantFrameChanged:self]; [self draw:self]; } return self; } -zoomOut:sender { if(ratio >= 2 && scrollable == YES) { ratio /= 2; frame.size.width = tableLength * ratio + 2*BORDER ; bounds.size.width = tableLength * ratio ; clip.size.width = tableLength * ratio ; funcFrame.size.width = tableLength * ratio ; [superview descendantFrameChanged:self]; [self draw:self]; } return self; } -setEditable:(BOOL)flag { editableFlag = flag; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.