home *** CD-ROM | disk | FTP | other *** search
- #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];
- }
-