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.