This is PAThumbWheelCellDrawing.m in view mode; [Download] [Up]
#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]; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.