/*
 *    Filename:	CircularSlider.m 
 *    Created :	Sat 24 21:25:44 1991
 *    Author  :	Vince DeMarco
 *		<vince@whatnxt.cuc.ab.ca>
 * 
 *    Version 1.0.1
 */

/* Generated by Interface Builder */

#import "CircularSlider.h"
#include <math.h>
#import <appkit/Application.h>
#import <appkit/Panel.h>
#import <dpsclient/event.h>
#import <dpsclient/wraps.h>
#import <appkit/graphics.h>

#import "wraps.h"

inline static float angle(float x, float y);

@implementation CircularSlider

// Given a x,y point on a cart coordinate system this function returns the angle 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  = fabs(atan(fabs(x/y)));
	    result *= (180/M_PI);
	    return(result);
	}else{             		/* Quadrant 4 */
	    result  = fabs(atan(fabs(y/x)));
	    result *= (180/M_PI);
	    return(result+270.0);
	}
    }else{                 			/* Quadrants 2,3 */
	if ( x >= 0){      		/* Quadrant 2 */
	    result  = fabs(atan(fabs(y/x)));
	    result *= (180/M_PI);
	    return(result+90.0);
	}else{             		/* Quadrant 3 */
	    result  = fabs(atan(fabs(x/y)));
	    result *= (180/M_PI);
	    return(result+180.0);
	}
    }
}

- initFrame:(NXRect *)nf
{
    self = [super initFrame:nf];
    [self allocateGState];
    x = nf->size.width/2;          
    y = nf->size.height/2;         
    radius = ( x < y ? x : y) - 4;
    currentang = 0.0;
    maxang = 360.0;
    CircFlags.continuous = 1;  // By Default messages are continuously sent
    return(self);
}

- setContinuous:(BOOL)flag
{
    if (flag == NO)
	CircFlags.continuous = 0;
    else
	CircFlags.continuous = 1;
    return(self);
}

- (BOOL)isContinuous
{
    if (CircFlags.continuous == 1)
	return YES;
    else
	return NO;
}

- (float)floatValue
{
    return(currentang);
}

- (double)doubleValue
{
    return((double)currentang);
}

- (int)intValue
{
    return((int)currentang);
}

- setDoubleValue:(double)value
{
    [self setFloatValue:(float)value];
    return(self);
}

- setFloatValue:(float)value
{
    if (value <= maxang){
	currentang = value;
    }else{
	currentang = maxang;
    }
    [self display];
    return(self);
}

- setIntValue:(int)value
{
    [self setFloatValue:(float)value];
    return(self);
}

- setTheMaxValue:(float)afloat
{
    maxang = afloat;
    return(self);
}

- (float)theMaxValue
{
    return(maxang);
}

- takeDoubleValueFrom:sender
{
    float newValue;

    newValue = [sender floatValue];
    if ((newValue != currentang) && (newValue <= maxang)){
	currentang = newValue;
	[self display];
    }
    return(self);
}

- takeFloatValueFrom:sender
{
    return([self takeDoubleValueFrom:sender]);
}

- takeIntValueFrom:sender
{
    return([self takeDoubleValueFrom:sender]);
}

- setAction:(SEL)aSelector
{
    _action = aSelector;
    return(self);
}

- setTarget:anObject
{
    _target = anObject;
    return(self);
}

- target
{
    return( _target);
}

- (SEL)action
{
    return( _action);
}

- drawSelf:(const NXRect *)rects : (int)count
{
    x = bounds.size.width/2;         
    y = bounds.size.height/2;
    radius = ( x < y ? x : y) - 4;
    if (conFlags.enabled == 1){  /* Draw the 3D raised box first if it has been enabled */
	//PSdrawRectangle(bounds.origin.x,bounds.origin.y,bounds.size.width - 2,bounds.size.height);
	NXDrawButton(&bounds, &bounds);
    }
    PSdrawCircSlider(bounds.size.height,bounds.size.width,x,y,radius,currentang);   // Draw the actual slider
    return(self);
}

- mouseDown:(NXEvent *)theEvent
{
	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;           /* angle of current mouseDown/mouseDragged/mouseUp point */
	float           scalex = bounds.size.height / bounds.size.width;
	float           scaley = bounds.size.width / bounds.size.height;

	if (conFlags.enabled == 1){  /* If CircularSlider is disabled don't allow any 
                                      * mouseDown events, just ignore them.
				      */

	    /* Allow mouseDragged events */
	    oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
	    
	    /* Get the location of the mouseDown in view coordinates */
	    startPoint = theEvent->location;
	    [self convertPoint:&startPoint fromView:nil];
	    
	    /* Initialize the drawing context */
	    [self lockFocus];

	    // 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*(startPoint.x-(x)),startPoint.y-(y));
	    }else
		if (scalex < scaley ){
		    newangle = angle(startPoint.x-(x),scaley*(startPoint.y-(y)));
		}else
		    if (scalex = scaley ){
			newangle = angle(startPoint.x-(x),startPoint.y-(y));
		    }
            if (newangle <= maxang)
		currentang = newangle;
	    else
		currentang = maxang;
	    //PSdrawRectangle(bounds.origin.x,bounds.origin.y,bounds.size.width - 2,bounds.size.height);
	    NXDrawButton(&bounds, &bounds);
	    PSdrawCircSlider(bounds.size.height,bounds.size.width,x,y,radius,currentang);
	    [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;
		[self convertPoint:&currentPoint 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-(x)),currentPoint.y-(y));
		    }else
			if (scalex < scaley ){
			    newangle = angle(currentPoint.x-(x),scaley*(currentPoint.y-(y)));
			}else
			    if (scalex = scaley ){
				newangle = angle(currentPoint.x-(x),currentPoint.y-(y));
			    }

		    if (newangle <= maxang)
			currentang = newangle;
		    else
			currentang = maxang;

		    PSdrawCircSlider(bounds.size.height,bounds.size.width,x,y,radius,currentang);
		    [window flushWindow];
		    if (CircFlags.continuous == 1)
			[self sendAction: _action to: _target];
		}else{
		    looping = NO;
		    [window flushWindow];
		    [self sendAction: _action to: _target];
		}
	    }
	
	    /* Release the drawing context and restore the event mask */
	    [self unlockFocus];
	    [window setEventMask:oldMask];
	}
	return self;
}

- read:(NXTypedStream *)stream
{
    [super read:stream];
    NXReadTypes(stream,"fffffi@:",&currentang,&maxang,&radius,&x,&y,&CircFlags,&_target,&_action);
    return(self);
}

- write:(NXTypedStream *)stream
{
    [super write:stream];
    NXWriteTypes(stream,"fffffi@:",&currentang,&maxang,&radius,&x,&y,&CircFlags,&_target,&_action);
    return(self);
}

- (const char *)getInspectorClassName
{
    return "CircularSliderInspector";
}
@end
