This is CircularSliderCell.m in view mode; [Download] [Up]
/*
* 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"
*/
#import "CircularSliderCell.h"
#import <appkit/Control.h>
#import <appkit/Application.h>
#import <math.h>
#import <dpsclient/psops.h>
#import "wraps.h"
/* Calculate the Absolute value of y safely */
#define ABS(y) \
({typeof (y) __x = (y); \
(__x < 0) ? (-(__x)) : (__x); })
@implementation CircularSliderCell
/* Given a x,y point on a cart coordinate system this function returns the angle (in degrees) from
* the positive side of the Y- axis
* ^
* |
* |\
* <____|_|__>
* | |
* |<-
* |
*/
inline static float angle(float x, float y)
{
float result;
if (y >= 0){ /* Quadrants 1,4 */
if ( x >= 0){ /* Quadrant 1 */
result = atan(ABS(x/y));
result *= (180/M_PI);
return(ABS(result));
}else{ /* Quadrant 4 */
result = atan(ABS(y/x));
result *= (180/M_PI);
return(ABS(result+270.0));
}
}else{ /* Quadrants 2,3 */
if ( x >= 0){ /* Quadrant 2 */
result = atan(ABS(y/x));
result *= (180/M_PI);
return(ABS(result+90.0));
}else{ /* Quadrant 3 */
result = atan(ABS(x/y));
result *= (180/M_PI);
return(ABS(result+180.0));
}
}
}
/*
* xycoord does the opposite of angle,
* given an angle and a radius, xycoord returns the x,y position of
* a point on the radius
* ^
* |
* |\
* | \ angle in degrees
* <____|__\___>
* |\ |
* | \<-
* | \ (x,y)
*/
inline static void xycoord(float angle, float radius,float *x, float *y)
{
*x = (radius - 3.0)*(float)sin((M_PI/180)*angle);
*y = (radius - 3.0)*(float)cos((M_PI/180)*angle);
}
+ (BOOL)prefersTrackingUntilMouseUp
{
return YES;
}
- init
{
self = [super init];
minValue = value = currentang = 0.0;
maxValue = 360.0;
scale_value = 360.0/(ABS(maxValue-minValue));
pieChart = hidden = jumpToMousePoint = NO;
return self;
}
- drawSelf:(const NXRect *)cellFrame inView:controlView
{
center.x = cellFrame->size.width/2;
center.y = cellFrame->size.height/2;
radius = ( center.x < center.y ? center.x : center.y) - 4;
scalex = cellFrame->size.height/ cellFrame->size.width;
scaley = cellFrame->size.width / cellFrame->size.height;
if ([controlView isFlipped]){
imFlipped = YES;
}
if (hidden == YES){
[controlView lockFocus];
/* PSsetgray(0.66666); */
NXSetColor(NX_COLORLTGRAY);
PSrectfill(cellFrame->origin.x,cellFrame->origin.y,cellFrame->size.width,cellFrame->size.height);
[controlView unlockFocus];
return self;
}
[controlView lockFocus];
PSgsave();
if (imFlipped) {
PSscale(1.0, -1.0);
}
if (cFlags1.bezeled == 1){
NXDrawButton(cellFrame,cellFrame);
}else{
if (cFlags1.bordered == 1){
/* PSsetgray(0.0); */
NXSetColor(NX_COLORBLACK);
NXFrameRect(cellFrame);
}
}
if (pieChart == NO){
PSDrawBackground(cellFrame->size.height,cellFrame->size.width, center.x,center.y,radius);
}else{
if (cFlags1.disabled == 0)
PSDrawBackground(cellFrame->size.height,cellFrame->size.width, center.x,center.y,radius);
}
PSgrestore();
[controlView unlockFocus];
[self drawInside:cellFrame inView:controlView];
return self;
}
- drawInside:(const NXRect *)cellFrame inView:aView /* Draws only control portion not bezzel */
{
float x,y;
if (jumpToMousePoint == NO){
currentang += deltaAngle;
if (currentang > 360.0)
currentang -= 360.0;
if (currentang < 0.0)
currentang += 360.0;
}
[aView lockFocus];
PSgsave();
if (imFlipped) {
PSscale(1.0, -1.0);
}
if (pieChart){
if (cFlags1.disabled == 0){
PSPieChart(cellFrame->size.height,cellFrame->size.width,
center.x,center.y,radius,currentang);
}else{
PSPieChartDisabled(cellFrame->size.height,cellFrame->size.width,
center.x,center.y,radius,currentang);
}
}else{
if (cFlags1.disabled == 0){
xycoord(currentang,radius,&x,&y);
PSControlKnob(cellFrame->size.height,cellFrame->size.width, center.x,center.y,radius,x,y);
}else{
PSControlKnobDisabled(cellFrame->size.height,cellFrame->size.width, center.x,center.y,radius);
}
}
PSgrestore();
[aView unlockFocus];
return self;
}
- (BOOL)startTrackingAt:(const NXPoint *)startPoint inView:aView
{
return YES;
}
- (BOOL)trackMouse:(NXEvent *)theEvent inRect:(const NXRect *)cellFrame ofView:aView
{
int looping; /* Flag for while in modal loop */
int oldMask; /* Old event mask */
NXPoint startPoint; /* Location of mouseDown */
NXPoint currentPoint; /* Location of mouseDragged/mouseUp */
float newangle = 0.0;
float startangle = 0.0;
if ((cFlags1.disabled == 0) && (hidden == NO)){
/* Allow mouseDragged events */
oldMask = [[aView window] addToEventMask:NX_MOUSEDRAGGEDMASK];
/* Get the location of the mouseDown in view coordinates */
startPoint = theEvent->location;
[aView convertPoint:&startPoint fromView:nil];
if ([self startTrackingAt:&startPoint inView:aView]){
/* Adjust the mouseDown event's location if the Slider has been
* scaled in either the x or y direction
*/
if (scalex > scaley ){
startangle = angle(scalex*(startPoint.x-(center.x)),startPoint.y-(center.y));
}else
if (scalex < scaley ){
startangle = angle(startPoint.x-(center.x),scaley*(startPoint.y-(center.y)));
}else
startangle = angle(startPoint.x-(center.x),startPoint.y-(center.y));
if (jumpToMousePoint == YES){
currentang = startangle;
[self drawInside:cellFrame inView:aView];
[[aView window] flushWindow];
}
/* Run modal loop until mouse up */
looping = YES;
while (looping) {
/* Get the next mouseDragged/mouseUp event */
theEvent=[NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK];
/* Convert location to view coordinates */
currentPoint = theEvent->location;
[aView convertPoint:¤tPoint fromView:nil];
/* Handle the event */
if (theEvent->type == NX_MOUSEDRAGGED) {
/* Adjust the mouseDown event's location if the Slider has been
* scaled in either the x or y direction
*/
if (scalex > scaley ){
newangle = angle(scalex*(currentPoint.x-(center.x)),currentPoint.y-(center.y));
}else
if (scalex < scaley ){
newangle = angle(currentPoint.x-(center.x),scaley*(currentPoint.y-(center.y)));
}else
if (scalex = scaley ){
newangle = angle(currentPoint.x-(center.x),currentPoint.y-(center.y));
}
if (jumpToMousePoint == NO){
deltaAngle = newangle - startangle;
startangle = newangle;
}else{
currentang = newangle;
}
if (!finite(currentang)){
currentang = 0.0;
}
if (!finite(deltaAngle)){
deltaAngle = 0.0;
}
#if 0
if (currentang != currentang){ /* If this occurs, ie this test is true then
* currentang == NAN */
currentang = 0.0;
}
if (deltaAngle != deltaAngle){ /* If this occurs, ie this test is true then
* deltaAngle == NAN */
deltaAngle = 0.0;
}
#endif
[self drawInside:cellFrame inView:aView];
[[aView window] flushWindow];
if ([self continueTracking:&startPoint at:¤tPoint inView:aView]){
[aView sendAction: action to: target];
}
}else{
looping = NO;
[[aView window] flushWindow];
[aView sendAction: action to: target];
}
startPoint.x = currentPoint.x;
startPoint.y = currentPoint.y;
}
[aView sendAction: action to: target];
}
[[aView window] setEventMask:oldMask];
return YES;
}
return NO;
}
- highlight:(const NXRect *)cellFrame inView:aView lit:(BOOL)flag
{
return self;
}
- (float)floatValue
{
value = (currentang/scale_value) + minValue;
return(value);
}
- (double)doubleValue
{
return((double)[self floatValue]);
}
- (int)intValue
{
return((int)[self floatValue]);
}
- setDoubleValue:(double)aDouble
{
[self setFloatValue:(float)aDouble];
return self;
}
- setFloatValue:(float)aFloat
{
if (aFloat < minValue){
value = minValue;
currentang = 0;
}else
if (aFloat > maxValue){
value = maxValue;
currentang = 360.0;
}else{
value = aFloat;
currentang = (value - minValue)*scale_value;
}
return self;
}
- setIntValue:(int)aInt
{
[self setFloatValue:(float)aInt];
return self;
}
- (float)minValue
{
return minValue;
}
- setMinValue:(float)aFloat
{
float scale = ABS(aFloat-minValue);
if (scale != 0.0){
minValue = aFloat;
scale_value = 360.0/(ABS(maxValue-minValue));
}
return self;
}
- (float)maxValue
{
return maxValue;
}
- setMaxValue:(float)aFloat
{
float scale = ABS(aFloat-minValue);
if (scale != 0.0){
maxValue = aFloat;
scale_value = 360.0/scale;
}
return self;
}
- setDrawAsPieChart:(BOOL)aBOOL
{
pieChart = aBOOL;
return self;
}
- (BOOL)drawAsPieChart
{
return pieChart;
}
- 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,"fff",&value,&maxValue,&minValue);
NXReadTypes(stream,"ccc",&pieChart,&jumpToMousePoint,&hidden);
NXReadTypes(stream,"ff",¤tang,&radius);
NXReadPoint(stream,¢er);
NXReadTypes(stream,"ffff",&deltaAngle,&scale_value,&scalex,&scaley);
return self;
}
- write:(NXTypedStream *)stream
{
[super write:stream];
NXWriteTypes(stream,"fff",&value,&maxValue,&minValue);
NXWriteTypes(stream,"ccc",&pieChart,&jumpToMousePoint,&hidden);
NXWriteTypes(stream,"ff",¤tang,&radius);
NXWritePoint(stream,¢er);
NXWriteTypes(stream,"ffff",&deltaAngle,&scale_value,&scalex,&scaley);
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.