home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula
/
nebula.bin
/
SourceCode
/
Palettes
/
PAThumbWheelPalette
/
PAThumbWheelCellDrawing.m
< prev
next >
Wrap
Text File
|
1993-04-20
|
11KB
|
310 lines
#import "PAThumbWheelCellDrawing.h"
/******************************************************************************
PAThumbWheelCellDrawing
This file handles all of the drawing for the PAThumbWheelCell. Don't try to make sense of any of this.
Copyright 1992, Jeff Martin. (jmartin@next.com 415-780-3833)
******************************************************************************/
#define EQUAL(a,b) (ABS((a)-(b))<0.00001)
#define NOTEQUAL(a,b) (ABS((a)-(b))>0.0001)
#define ISBETWEEN(x,a,b) (((x)>=(a))&&((x)<=(b)))
// A mod function for floating values
#define MOD(x,y) ((x) - (y)*(int)((float)(x)/(y)))
#define CLAMP_WITH_WRAP(a,x,y) \
( ((a) < (x)) ? ((y) - MOD(((x)-(a)),((y)-(x)))) : \
( ((a) > (y)) ? ((x) + MOD(((a)-(y)),((y)-(x)))) : (a) ) )
#define EVEN(x) (!(((int)(x))%2))
@implementation PAThumbWheelCell(Drawing)
- drawSelf:(const NXRect *)theFrame inView:view
{
NXRect frame = *theFrame;
float *pnts; // Used for user path of dashes
char *ops; // Used for user path of dashes
int pntCount, opCount; // Used for user path of dashes
float bbox[4] = { NX_X(theFrame), NX_Y(theFrame),
NX_MAXX(theFrame), NX_MAXY(theFrame) };
// Inset by two to allow for bezeled border
NXInsetRect(&frame,2,2);
// Draw the background
if([self isLinear]) {
NXDrawGrayBezel(theFrame, theFrame);
NXSetColor(color);
NXRectFill(&frame);
}
else { // if([self isRadial])
NXSize imageSize;
[image getSize:&imageSize];
if(NOTEQUAL(imageSize.width,NX_WIDTH(theFrame)) ||
NOTEQUAL(imageSize.height,NX_HEIGHT(theFrame)))
[self generateImage:theFrame];
[image composite:NX_COPY toPoint:&theFrame->origin];
}
// Get the userpath for the dashes
[self getDashesForFrame:&frame :&pnts :&pntCount :&ops :&opCount];
// Draw dashes once for white part of groove
if([self isHorizontal]) PStranslate(1,0); else PStranslate(0,-1);
// Draw linear white dashes
if([self isLinear]) {
NXSetColor(PAScaleRGBColor(color, 1.5));
DPSDoUserPath(pnts, pntCount, dps_float, ops, opCount, bbox,
dps_ustroke);
}
// Break up radial white dashes to fade a little bit at ends
else {
int i = 0, j = 0, d = [self isHorizontal]? 0 : 1;
float oneQuarterOfX = [self isHorizontal]? (NX_X(&frame) +
NX_WIDTH(&frame)/4) : (NX_Y(&frame) + NX_HEIGHT(&frame)/4);
float threeQuartersOfX =[self isHorizontal]? (NX_X(&frame) +
3*NX_WIDTH(&frame)/4) : (NX_Y(&frame) + 3*NX_HEIGHT(&frame)/4);
NXSetColor(color);
while((i < pntCount) && (pnts[i+d] < oneQuarterOfX)) i += 4; j = i;
if(i>0) DPSDoUserPath(pnts, i, dps_float, ops, i/2, bbox, dps_ustroke);
NXSetColor(PAScaleRGBColor(color, 1.5));
while((j < pntCount) && (pnts[j+d] < threeQuartersOfX)) j+=4;
if(j>i) DPSDoUserPath(&pnts[i], j-i, dps_float, &ops[i/2], j/2-i/2,
bbox, dps_ustroke);
NXSetColor(color);
if(pntCount>j) DPSDoUserPath(&pnts[j], pntCount-j, dps_float,
&ops[j/2], opCount-j/2, bbox, dps_ustroke);
}
if([self isHorizontal]) PStranslate(-1,0); else PStranslate(0,1);
// Draw again for dark part of groove
if([self isLinear]) NXSetColor(PAScaleRGBColor(color, .5));
else NXSetColor(NX_COLORBLACK);
DPSDoUserPath(pnts, pntCount, dps_float, ops, opCount, bbox, dps_ustroke);
// If disabled then dim ThumbWheel out
if(![self isEnabled]) {
NXSetColor(NX_COLORWHITE); PSsetalpha(.5);
PScompositerect(NX_X(&frame), NX_Y(&frame), NX_WIDTH(&frame),
NX_HEIGHT(&frame), NX_SOVER);
}
// Free user path variables
free(pnts); free(ops);
return self;
}
- getDashesForFrame:(const NXRect *)frame :(float **)PNTS :(int *)PNTCOUNT :(char **)OPS :(int *)OPCOUNT
{
// Get dashInterval and shift
int dashInt = [self dashInterval];
int shift = [self shift:frame];
// Calculate how many dashes there will be and alloc space for pnts and ops
int dashCount = 2 + ([self isRadial] ? 180/dashInt :
([self isVertical] ? NX_HEIGHT(frame) : NX_WIDTH(frame)) / dashInt);
float *pnts = malloc(sizeof(float)*dashCount*4); // (moveto+lineto)*(x+y)=4
char *ops = malloc(sizeof(char)*dashCount*2); // (moveto+lineto) = 2
int i=0, j=0;
// Calculate dash sizes
int dashBase = [self isVertical] ? NX_X(frame) : NX_Y(frame);
int dashHeight = [self isVertical] ? NX_WIDTH(frame) : NX_HEIGHT(frame);
int dashMinTop = dashBase + dashHeight*.25;
int dashMajTop = dashBase + dashHeight*.5;
int dashTop = dashBase + dashHeight;
float base = [self isVertical] ? NX_Y(frame) : NX_X(frame);
float width = [self isVertical]? NX_HEIGHT(frame) : NX_WIDTH(frame);
float halfWidth = width/2;
float mid = base + halfWidth;
float top = base + width;
float mainDash;
float x;
// Calculate whether first dash is a major one.
BOOL isMajor = (shift>=0)? EVEN(shift/dashInt) : !EVEN(shift/dashInt);
// Calculate Linear dashes
if([self isLinear]) {
// Set Main dash
mainDash = base + shift;
// Calculate starting point and set the dashes
x = base+CLAMP_WITH_WRAP(shift,0,dashInt)%((shift>=0)? dashInt:999999);
if([self isVertical]) while(x<top) {
pnts[i++] = dashBase; pnts[i++] = x;
pnts[i++] = isMajor ? dashMajTop : dashMinTop;
if(EQUAL(x, mainDash)&&[self showMainDash]) pnts[i-1] = dashTop;
pnts[i++] = x;
x += dashInt; isMajor = !isMajor;
}
else while(x<top) {
pnts[i++] = x; pnts[i++] = dashBase;
pnts[i++] = x; pnts[i++] = isMajor ? dashMajTop : dashMinTop;
if(EQUAL(x, mainDash)&&[self showMainDash]) pnts[i-1] = dashTop;
x += dashInt; isMajor = !isMajor;
}
}
// Calculate Radial Dashes
else {
// This is used to convert the degrees of a dash to a location(in pnts)
float linDash = 0;
// Inset dash size for beveled edges
dashBase++; dashTop--;
// Calc Main dash if we show it and it is in sight
mainDash = mid - IntCos(shift)*halfWidth;
// Calculate the starting point and set the dashes
x = CLAMP_WITH_WRAP(shift, 0, dashInt)%((shift>=0)? dashInt:999999);
if([self isVertical]) while(x<180) {
linDash = mid - IntCos(x)*halfWidth;
pnts[i++] = dashBase; pnts[i++] = linDash;
pnts[i++] = isMajor ? dashMajTop : dashMinTop;
// Check to see if this is a valid main dash
if(isMajor && EQUAL(linDash,mainDash) && [self showMainDash] &&
ISBETWEEN(shift, 0, 180)) pnts[i-1]=dashTop;
pnts[i++] = linDash;
x += dashInt; isMajor = !isMajor;
}
else while(x<180) {
linDash = mid - IntCos(x)*halfWidth;
pnts[i++] = linDash; pnts[i++] = dashBase;
pnts[i++] = linDash; pnts[i++] = isMajor ? dashMajTop : dashMinTop;
// Check to see if this is a valid main dash
if(isMajor && EQUAL(linDash,mainDash) && [self showMainDash] &&
ISBETWEEN(shift, 0, 180)) pnts[i-1]=dashTop;
x += dashInt; isMajor = !isMajor;
}
}
// fill the ops array with dps_moveto and dps_lineto
while(j<i/2) { ops[j++] = dps_moveto; ops[j++] = dps_lineto; }
// Set the passed in pointers to the arrays and the counts and return
*PNTS = pnts; *OPS = ops; *PNTCOUNT = i; *OPCOUNT = j;
return self;
}
- generateImage:(const NXRect *)theFrame
{
float circleHeight;
float x, rad, rad2, mid;
NXRect frame = *theFrame;
if(!image) image = [[NXImage alloc] init];
[image setSize:&frame.size];
[image lockFocus];
NXDrawGrayBezel(&frame,&frame);
NXInsetRect(&frame,2,2);
PSsetlinewidth(0.0);
// Draw horizonal version
if(direction == DIRECTION_HORIZONTAL) {
rad = NX_WIDTH(&frame)/2.0; rad2 = rad*rad;
mid = NX_MIDX(&frame);
for(x = NX_X(&frame); x <= NX_MIDX(&frame); x++) {
float topx = NX_MAXX(&frame) - (x - NX_X(&frame));
circleHeight = sqrt(rad2 - (mid-x)*(mid-x))/rad;
PSnewpath();
NXSetColor(PAScaleRGBColor(color, .5*circleHeight));
PSmoveto(x, NX_Y(&frame)); PSlineto(x, NX_Y(&frame) + 2);
PSmoveto(topx, NX_Y(&frame)); PSlineto(topx, NX_Y(&frame) + 2);
PSstroke();
PSnewpath();
NXSetColor(PAScaleRGBColor(color, circleHeight));
PSmoveto(x, NX_Y(&frame)+2); PSlineto(x, NX_MAXY(&frame) - 1);
PSmoveto(topx, NX_Y(&frame)+2);PSlineto(topx,NX_MAXY(&frame) -1);
PSstroke();
PSnewpath();
NXSetColor(PAScaleRGBColor(color,1.5*circleHeight));
PSmoveto(x, NX_MAXY(&frame)-1); PSlineto(x, NX_MAXY(&frame));
PSmoveto(topx, NX_MAXY(&frame)-1);PSlineto(topx, NX_MAXY(&frame));
PSstroke();
}
}
else {
rad = NX_HEIGHT(&frame)/2.0; rad2 = rad*rad;
mid = NX_MIDY(&frame);
for(x = NX_Y(&frame); x <= NX_MIDY(&frame); x++) {
float topx = NX_MAXY(&frame) - (x - NX_Y(&frame));
circleHeight = sqrt(rad2 - (mid-x)*(mid-x))/rad;
PSnewpath();
NXSetColor(PAScaleRGBColor(color, 1.5*circleHeight));
PSmoveto(NX_X(&frame), x); PSlineto(NX_X(&frame) + 2, x);
PSmoveto(NX_X(&frame), topx); PSlineto(NX_X(&frame) + 2, topx);
PSstroke();
PSnewpath();
NXSetColor(PAScaleRGBColor(color, circleHeight));
PSmoveto(NX_X(&frame)+2, x); PSlineto(NX_MAXX(&frame) - 1, x);
PSmoveto(NX_X(&frame)+2, topx); PSlineto(NX_MAXX(&frame) - 1,topx);
PSstroke();
PSnewpath();
NXSetColor(PAScaleRGBColor(color, .5*circleHeight));
PSmoveto(NX_MAXX(&frame)-1, x); PSlineto(NX_MAXX(&frame), x);
PSmoveto(NX_MAXX(&frame)-1, topx);PSlineto(NX_MAXX(&frame), topx);
PSstroke();
}
}
[image unlockFocus];
return self;
}
- (const char *)getInspectorClassName { return "PAThumbWheelInspector"; }
@end
NXColor PAScaleRGBColor(NXColor c, float scale)
{ return NXConvertRGBToColor(NXRedComponent(c)*scale, NXGreenComponent(c)*
scale, NXBlueComponent(c)*scale); }
float _IntSin[91] ={0, 0.017452406, 0.034899497, 0.052335956, 0.069756474,
0.087155743, 0.10452846, 0.12186934, 0.1391731,
0.15643447, 0.17364818, 0.190809, 0.20791169,
0.22495105, 0.2419219, 0.25881905, 0.27563736,
0.2923717, 0.30901699, 0.32556815, 0.34202014,
0.35836795, 0.37460659, 0.39073113, 0.40673664,
0.42261826, 0.43837115, 0.4539905, 0.46947156,
0.48480962, 0.5, 0.51503807, 0.52991926, 0.54463904,
0.5591929, 0.57357644, 0.58778525, 0.60181502,
0.61566148, 0.62932039, 0.64278761, 0.65605903,
0.66913061, 0.68199836, 0.69465837, 0.70710678,
0.7193398, 0.7313537, 0.74314483, 0.75470958,
0.76604444, 0.77714596, 0.78801075, 0.79863551,
0.80901699, 0.81915204, 0.82903757, 0.83867057,
0.8480481, 0.8571673, 0.8660254, 0.87461971,
0.88294759, 0.89100652, 0.89879405, 0.90630779,
0.91354546, 0.92050485, 0.92718385, 0.93358043,
0.93969262, 0.94551858, 0.95105652, 0.95630476,
0.9612617, 0.96592583, 0.97029573, 0.97437006,
0.9781476, 0.98162718, 0.98480775, 0.98768834,
0.99026807, 0.99254615, 0.9945219, 0.9961947,
0.99756405, 0.99862953, 0.99939083, 0.9998477, 1.};
float IntSin(int x)
{
if(x < 0) return -IntSin(-x);
if(x > 180) return -IntSin(x%180);
if(x > 90) return _IntSin[180-x];
return _IntSin[x];
}