home *** CD-ROM | disk | FTP | other *** search
- //
- // MiscCircularSliderCell.m -- a SliderCell for circular sliders
- // Written by Vince DeMarco and Don Yacktman,
- // Copyright (c) 1994 by Vince DeMarco and Don Yacktman.
- // Version 1.0 All rights reserved.
- // This notice may not be removed from this source code.
- //
- // This object is included in the MiscKit by permission from the author
- // and its use is governed by the MiscKit license, found in the file
- // "LICENSE.rtf" in the MiscKit distribution. Please refer to that file
- // for a list of all applicable permissions and restrictions.
- //
-
- // This was created by modifying Vince's CircularSliderCell class and
- // merging it with Don's RotationSliderCell class. Here's the info
- // from the original files.
- /*
- * Filename: CircularSliderCell.m
- * Created : Sun Oct 18 16:56:38 1992
- * Author : Vince DeMarco
- * <vince@whatnxt.cuc.ab.ca>
- * LastEditDate was "Wed Feb 3 17:30:28 1993"
- */
- // RotationSliderCell.m -- written by Don Yacktman
- // Copyright 1993 by Don Yacktman. All rights reserved.
-
- #import "MiscCircularSliderCell.h"
- #import "MiscCSWraps.h"
- #import <math.h>
- #import <appkit/appkit.h>
-
- @interface MiscCircularSliderCell(private)
- - _cacheImages;
- @end
-
- #define _KNOB_WIDTH_FUDGE (5.0 / 8.0)
- #define _KNOB_Y_FUDGE (- 1.0)
- #define _KNOB_X_FUDGE ( 0.0)
- #define _BEZELS_FUDGE ( 4.0)
- @implementation MiscCircularSliderCell
-
- inline static float angle(float x, float y)
- { // this is a little cleaner than Vince's original routine. :-)
- double result = atan2(y, x) * (180 / M_PI);
- if (result < 0) result += 360.0; // keep in 0-360 degree range
- return result;
- }
-
- inline static void xycoord(float angle, float radius,float *x, float *y)
- { // the inverse of the above; given angle and radius, determines x & y
- *x = radius * (float)cos((M_PI / 180) * angle);
- *y = radius * (float)sin((M_PI / 180) * angle);
- }
-
- // Convert between a 0-360 degree angle and the slider's position. The
- // angle is used as the parameter to pass to the pswrap that does the drawing.
- // These two #defines are inverses of each other.
- #define currentangle(pos, min, max) (360.0 * ((pos) - (min)) / ((max) - (min)))
- #define position(angle, min, max) ((angle) * ((max) - (min)) / 360.0 + (min))
-
- - init
- {
- self = [super init];
- minValue = 0.0;
- value = 45.0;
- maxValue = 360.0;
- radius = 50.0; sliderPathWidth = 10.0;
- center.x = radius;
- center.y = radius;
- style = MISC_SLIDER_STYLE;
- jumpToMousePoint = YES;
- hidden = NO;
- [self _cacheImages];
- return self;
- }
-
- - awake
- {
- id ret = [super awake];
- [self _cacheImages];
- return ret;
- }
-
- #define _SETUPIMAGE PSsetgray(0.0); PSsetalpha(0.0); \
- NXRectFill(&frame); PSsetalpha(1.0)
-
- - _cacheImages
- { // builds the cached slider, etc., if necessary. (ie, size changed
- // or no cache created yet... *****
- NXSize bezelSize = { radius * 2, radius * 2 }; NXPoint t;
- NXRect frame = { { 0.0, 0.0 }, { center.x * 2, center.y * 2 } };
- NXRect knobRect = { { center.x - sliderPathWidth / 4 + 1,
- center.y - sliderPathWidth / 4 - 2 },
- { sliderPathWidth * 1.5 + 1, sliderPathWidth * 1.5 + 2 } };
-
- xycoord(45.0, radius - (sliderPathWidth + 2), &(t.x), &(t.y));
- NX_X(&knobRect) += t.x; NX_Y(&knobRect) += t.y;
-
- if (disabledBezelImage) [disabledBezelImage free];
- disabledBezelImage = [[NXImage alloc] initSize:&bezelSize];
- [disabledBezelImage lockFocus];
- PSgsave(); _SETUPIMAGE;
- MiscCSDrawBezel(0, 0, radius, sliderPathWidth, 0.666);
- PSgrestore();
- [disabledBezelImage unlockFocus];
-
- if (enabledBezelImage) [enabledBezelImage free];
- enabledBezelImage = [[NXImage alloc] initSize:&bezelSize];
- [enabledBezelImage lockFocus];
- PSgsave(); _SETUPIMAGE;
- MiscCSDrawBezel(0, 0, radius, sliderPathWidth, 0.5);
- PSgrestore();
- [enabledBezelImage unlockFocus];
-
- if (tempImage) [tempImage free];
- tempImage = [[NXImage alloc] initSize:&bezelSize];
- [tempImage lockFocus];
- PSgsave(); _SETUPIMAGE;
- MiscCSDrawKnob(0, 0, radius, sliderPathWidth, 45);
- PSgrestore();
- [tempImage unlockFocus];
- if (knobImage) [knobImage free];
- knobImage = [[NXImage alloc] initFromImage:tempImage rect:&knobRect];
- return self;
- }
-
- - setSliderPathWidth:(float)val
- {
- if (val == sliderPathWidth) return self;
- sliderPathWidth = val;
- [self _cacheImages];
- return self;
- }
-
- - (float)sliderPathWidth
- {
- return sliderPathWidth;
- }
-
- - setSliderStyle:(MiscCircularSliderStyle)aBOOL
- {
- if (aBOOL == style) return self;
- style = aBOOL;
- if ((style == MISC_SLIDER_STYLE) || (style == MISC_PIECHART_STYLE)) {
- jumpToMousePoint = YES;
- if (style == MISC_SLIDER_STYLE) [self _cacheImages];
- } else jumpToMousePoint = NO;
- return self;
- }
-
- - (MiscCircularSliderStyle)sliderStyle
- {
- return style;
- }
-
- - setJumpToMousePoint:(BOOL)aBOOL
- {
- jumpToMousePoint = aBOOL;
- return self;
- }
-
- - (BOOL)jumpToMousePoint
- {
- return jumpToMousePoint;
- }
-
- - setHidden:(BOOL)flag
- {
- hidden = flag;
- return self;
- }
-
- - (BOOL)hidden
- {
- return hidden;
- }
-
- - read:(NXTypedStream *)stream
- {
- [super read:stream];
- NXReadTypes(stream, "iccff", &style, &jumpToMousePoint, &hidden, &radius, &sliderPathWidth);
- NXReadPoint(stream, ¢er);
- return self;
- }
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
- NXWriteTypes(stream, "iccff", &style, &jumpToMousePoint, &hidden , &radius, &sliderPathWidth);
- NXWritePoint(stream, ¢er);
- return self;
- }
-
- // overridden methods here:
- - calcCellSize:(NXSize *)theSize inRect:(const NXRect *)aRect
- {
- theSize->width = NX_WIDTH(aRect);
- theSize->height = NX_HEIGHT(aRect);
-
- if (style != MISC_SLIDER_STYLE) return self;
- // the "slider looking" style should always be a perfect circle.
- if (theSize->height < theSize->width) theSize->width = theSize->height;
- else theSize->height = theSize->width;
- return self;
- }
-
- #define _FINDXYFROMPOINT(z) if (imFlipped) y = center.y - (z)->y; \
- else y = (z)->y - center.y; \
- x = (z)->x - center.x
-
- - (BOOL)startTrackingAt:(const NXPoint *)startPoint inView:controlView
- { // make sure we're within the slider's "hot" area, a circle (or ring)
- float x, y, rad, ir;
-
- _FINDXYFROMPOINT(startPoint);
- _offsetAng = angle(x, y) - currentangle(value, minValue, maxValue);
- rad = x * x + y * y;
- if (rad > radius * radius) return NO; // outside
- ir = radius - sliderPathWidth - 3.0;
- if ((rad < ir * ir) && (style == MISC_SLIDER_STYLE)) return NO;
- return [super startTrackingAt:startPoint inView:controlView];
- }
-
- - (BOOL)continueTracking:(const NXPoint *)lastPoint
- at:(const NXPoint *)currentPoint inView:controlView
- {
- NXPoint pos; float x, y, oldx, oldy, curAng, oldAng;
-
- if (hidden) {
- PSsetgray(0.666); NXRectFill(&_lastFrame);
- return NO;
- }
- // get the current angle of the mouse pointer
- _FINDXYFROMPOINT(currentPoint);
- curAng = angle(x, y);
- if (!jumpToMousePoint) {
- curAng -= _offsetAng;
- if (curAng < 0) curAng += 360.0;
- }
- // get the last angle of the mouse pointer
- oldAng = currentangle(value, minValue, maxValue);
-
- xycoord(curAng, radius - sliderPathWidth / 2 - 2, &(pos.x), &(pos.y));
- pos.x += (center.x - sliderPathWidth * _KNOB_WIDTH_FUDGE + _KNOB_X_FUDGE);
- pos.y += (center.y - sliderPathWidth * _KNOB_WIDTH_FUDGE + _KNOB_Y_FUDGE);
- value = position(curAng, minValue, maxValue);
-
- xycoord(oldAng, radius - sliderPathWidth / 2 - 2, &oldx, &oldy);
- oldx += (center.x - sliderPathWidth * _KNOB_WIDTH_FUDGE + _KNOB_X_FUDGE);
- oldy += (center.y - sliderPathWidth * _KNOB_WIDTH_FUDGE + _KNOB_Y_FUDGE);
-
- [[controlView window] disableFlushWindow];
- PSgsave();
- if (imFlipped) {
- NXRect aFrame;
- [controlView getFrame:&aFrame];
- PSscale(1.0, -1.0);
- PStranslate(0.0, -NX_HEIGHT(&aFrame));
- }
- if (style == MISC_SLIDER_STYLE) {
- NXRect eraseRect;
- id bezel = (cFlags1.disabled ? disabledBezelImage : enabledBezelImage);
- NXSetRect(&eraseRect, oldx, oldy,
- sliderPathWidth * 1.5 + 2, sliderPathWidth * 1.5 + 2);
- NXIntegralRect(&eraseRect);
- NXInsetRect(&eraseRect, -4.0, -4.0);
- [bezel composite:NX_SOVER fromRect:&eraseRect
- toPoint:&(eraseRect.origin)];
- [knobImage composite:NX_SOVER toPoint:&pos];
- } else {
- [self renderAll];
- }
- PSgrestore();
- [[[controlView window] reenableFlushWindow] flushWindow];
- NXPing();
- return YES;
- }
-
- - drawBarInside:(const NXRect *)cellFrame flipped:(BOOL)flipped
- {
- NXRect frame = { { 0.0, 0.0 },
- { NX_WIDTH(cellFrame), NX_HEIGHT(cellFrame) } };
- id bezel = (cFlags1.disabled ? disabledBezelImage : enabledBezelImage);
-
- if (hidden) {
- PSsetgray(0.666); NXRectFill(cellFrame);
- return self;
- }
- PSgsave();
- if (flipped) {
- PSscale(1.0, -1.0);
- PStranslate(0.0, -NX_HEIGHT(cellFrame));
- imFlipped = YES;
- }
- if ((style != MISC_SLIDER_STYLE) &&
- (!(style == MISC_PIECHART_STYLE) && !cFlags1.disabled)) {
- MiscCSDrawBackground(center.x, center.y, radius,
- NX_HEIGHT(cellFrame), NX_WIDTH(cellFrame));
- }
- if (style == MISC_SLIDER_STYLE)
- [bezel composite:NX_SOVER fromRect:&frame toPoint:&(frame.origin)];
- PSgrestore();
- return self;
- }
-
- - renderAll
- {
- float ang, r4 = radius - _BEZELS_FUDGE;
-
- if ((style != MISC_SLIDER_STYLE) &&
- !((style == MISC_PIECHART_STYLE) && cFlags1.disabled)) {
- MiscCSDrawBackground(center.x, center.y, r4, radius, radius);
- }
- ang = currentangle(value, minValue, maxValue);
- switch (style) {
- case MISC_PIECHART_STYLE : {
- if (cFlags1.disabled) {
- MiscCSPieChartDisabled(center.x, center.y,
- r4, radius, radius, ang);
- } else {
- MiscCSPieChart(center.x, center.y, r4,
- radius, radius, 90 - ang);
- }
- break;
- }
- case MISC_DIAL_STYLE : {
- MiscCSControlDial(center.x, center.y, r4, radius, radius,
- ang, (cFlags1.disabled ? 0.333 : 0.0));
- break;
- }
- case MISC_SHUTTLEWHEEL_STYLE : {
- if (cFlags1.disabled) {
- MiscCSControlKnobDisabled(center.x, center.y,
- r4, radius, radius);
- } else {
- MiscCSControlKnob(center.x, center.y, r4, radius, radius, ang);
- }
- break;
- }
- default : break;
- }
- return self;
- }
-
- - drawKnob:(const NXRect *)knobRect
- {
- NXRect frame = { { 0.0, 0.0 }, { radius * 2, radius * 2 } };
- NXPoint position; float ang;
- id bezel = (cFlags1.disabled ? disabledBezelImage : enabledBezelImage);
-
- if (hidden) {
- PSsetgray(0.666); NXRectFill(&_lastFrame);
- return self;
- }
- PSgsave();
- if (imFlipped) {
- PSscale(1.0, -1.0);
- PStranslate(0.0, -NX_HEIGHT(&_lastFrame)); // ***** probably wrong
-
- }
- if ((style != MISC_SLIDER_STYLE) &&
- (!(style == MISC_PIECHART_STYLE) && !cFlags1.disabled)) {
- MiscCSDrawBackground(center.x, center.y, radius - 4,
- NX_HEIGHT(&_lastFrame), NX_WIDTH(&_lastFrame));
- }
- ang = currentangle(value, minValue, maxValue);
- if (style != MISC_SLIDER_STYLE) {
- [self renderAll];
- } else {
- [bezel composite:NX_SOVER fromRect:&frame toPoint:&(frame.origin)];
- xycoord(ang, radius - sliderPathWidth / 2 - 2,
- &(position.x), &(position.y));
- position.x += (center.x - sliderPathWidth
- * _KNOB_WIDTH_FUDGE + _KNOB_X_FUDGE);
- position.y += (center.y - sliderPathWidth
- * _KNOB_WIDTH_FUDGE + _KNOB_Y_FUDGE);
- [knobImage composite:NX_SOVER toPoint:&position];
- }
- PSgrestore();
- return self;
- }
-
- #define _COPYRECT(x, y) NXSetRect((x), \
- NX_X(y), NX_Y(y), NX_WIDTH(y), NX_HEIGHT(y))
-
- - drawSelf:(const NXRect *)cellFrame inView:controlView
- {
- if ([controlView isFlipped]) imFlipped = YES;
- if (!NXEqualRect(&_lastFrame, cellFrame)) {
- _COPYRECT(&_lastFrame, cellFrame);
- radius = MIN(NX_WIDTH(cellFrame), NX_HEIGHT(cellFrame)) / 2;
- center.x = NX_X(cellFrame) + radius;
- center.y = NX_Y(cellFrame) + radius;
- if (style == MISC_SLIDER_STYLE) [self _cacheImages];
- }
- if (hidden) {
- PSsetgray(0.666); NXRectFill(cellFrame);
- return self;
- }
- if (NXDrawingStatus == NX_PRINTING) {
- // make sure everything gets rendered...
- [self drawBarInside:cellFrame flipped:imFlipped];
- }
- [self drawKnob:cellFrame];
- return self;
- }
-
- - getKnobRect:(NXRect *)knobRect flipped:(BOOL)flipped
- {
- [super getKnobRect:knobRect flipped:flipped];
- return self;
- }
-
- @end
-