//
//	RotationSliderCell.m -- written by Don Yacktman
//
//	Copyright 1993 by Don Yacktman.  All rights reserved.
//
//	You may use this code subject to the following conditions:
//	(1) If you use this code in any applications or packages which
//		will be sold for gain (i.e. commercial, shareware, etc.) you
//		must first have a signed written agreement from the author.
//	(2) You may freely use this object in personal projects which
//		are freely redistributable at not cost to the recipient.
//		(A nominal distribution fee, like media and postage cost,
//		is OK, though.)  You must include the source to this object
//		and any of your modifications in the distribution, however.
//	(3) If you make any modifications, send them to the author.  If
//		any of them are useful, they will be included in any future
//		releases if you like.  You must send the changes, though!
//

#import "RotationSliderCell.h"
#import "RotationSliderWraps.h"
#import <math.h>

#define PI 3.1415926535897932384626433

@implementation RotationSliderCell

// 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 angle(pos, min, max) (360.0 * ((pos) - (min)) / ((max) - (min)))
#define pos(angle, min, max) ((angle) * ((max) - (min)) / 360.0 + (min))

static id disabledBezelImage = nil;
static id enabledBezelImage = nil;
static id knobImage = nil;

- init
{
	[super init];
	value= 45.0; maxValue = 360.0; minValue = 0.0;
	[self buildImages];
	return self;
}

- awake
{
	[super awake];
	[self buildImages];
	return self;
}

- buildImages
{
	NXSize bezelSize = {111.0, 228.0};
	NXRect frame = {{0.0, 0.0}, {111.0, 228.0}};
	NXRect knobRect = {{85.0, 84.0}, {12.0, 12.0}};
	id tempImage;
	if (!disabledBezelImage) {
		disabledBezelImage = [[NXImage alloc] initSize:&bezelSize];
		[disabledBezelImage lockFocus];
		PSgsave();
		PSsetgray(0.0); PSsetalpha(0.0); NXRectFill(&frame); PSsetalpha(1.0);
		PSdrawBezel(0.666); PSscale(1.0, -1.0);
		PStranslate(0.0, -228.0); PSdrawBezel(0.666);
		PSgrestore();
		[disabledBezelImage unlockFocus];
		enabledBezelImage = [[NXImage alloc] initSize:&bezelSize];
		[enabledBezelImage lockFocus];
		PSgsave();
		PSsetgray(0.0); PSsetalpha(0.0); NXRectFill(&frame); PSsetalpha(1.0);
		PSdrawBezel(0.5); PSscale(1.0, -1.0);
		PStranslate(0.0, -228.0); PSdrawBezel(0.5);
		PSgrestore();
		[enabledBezelImage unlockFocus];
		tempImage = [[NXImage alloc] initSize:&bezelSize];
		[tempImage lockFocus];
		PSgsave();
		PSsetgray(0.0); PSsetalpha(0.0); NXRectFill(&frame); PSsetalpha(1.0);
		PSdrawKnob(45.0); PSscale(1.0, -1.0);
		PStranslate(0.0, -228.0); PSdrawKnob(45.0);
		PSgrestore();
		[tempImage unlockFocus];
		knobImage = [[NXImage alloc] initFromImage:tempImage rect:&knobRect];
	}
	return self;
}

- calcCellSize:(NXSize *)theSize inRect:(const NXRect *)aRect
{
	theSize->width = 111.0;
	theSize->height = 112.0;
	return self;
}

- (BOOL)startTrackingAt:(const NXPoint *)startPoint inView:controlView
{
	float x, y, radius;
	if (imFlipped) y = 55.5 - startPoint->y;
	else y = startPoint->y - 55.5;
	x = startPoint->x - 55.5;
	radius = x * x + y * y;
	if ((radius < 44.0 * 44.0) || (radius > 56.0 * 56.0)) return NO;
	return [super startTrackingAt:startPoint inView:controlView];
}

- (BOOL)continueTracking:(const NXPoint *)lastPoint
		at:(const NXPoint *)currentPoint inView:controlView
{
	NXPoint nothing = {50.0, 50.0};
	NXRect eraseRect; NXPoint position; id bezel;
	float ang, x, y, oldang, oldx, oldy;
	if (imFlipped) y = 55.5 - currentPoint->y;
	else y = currentPoint->y - 55.5;
	x = currentPoint->x - 55.5;
	ang = atan(y / x) * 180 / PI;
	if (x < 0) ang += 180.0;
	if (ang < 0) ang += 360.0;
	if (lastPoint) {
		if (imFlipped) oldy = 55.5 - lastPoint->y;
		else oldy = lastPoint->y - 55.5;
		oldx = lastPoint->x - 55.5;
		oldang = atan(oldy / oldx) * 180 / PI;
		if (oldx < 0) oldang += 180.0;
		if (oldang < 0) oldang += 360.0;
		oldx = cos(oldang * PI / 180.0) * 50.0 + 47.0;
		oldy = sin(oldang * PI / 180.0) * 50.0 + 47.0;
		NXSetRect(&eraseRect, oldx, oldy, 17.0, 16.0);
	} else {
		oldang = angle(value, minValue, maxValue);
		oldx = cos(oldang * PI / 180.0) * 50.0 + 47.0;
		oldy = sin(oldang * PI / 180.0) * 50.0 + 47.0;
		NXSetRect(&eraseRect, oldx, oldy, 17.0, 16.0);
	}
	NXIntegralRect(&eraseRect);
	x = cos(ang * PI / 180.0) * 50.0 + 50.0;
	y = sin(ang * PI / 180.0) * 50.0 + 49.0;
	position.x = x; position.y = y;
	value = pos(ang, minValue, maxValue);
	PSgsave();
	if (imFlipped) {
		PSscale(1.0, -1.0);
		PStranslate(0.0, -111.0);
	}
	bezel = (cFlags1.disabled ? disabledBezelImage : enabledBezelImage);
	[bezel composite:NX_SOVER fromRect:&eraseRect toPoint:&(eraseRect.origin)];
	if ((value == minValue) || (value == maxValue))
		position.x -= 1.0; // a hack to fix a weird bug
	[knobImage composite:NX_SOVER toPoint:&position];
	PSgrestore();
	[[controlView window] flushWindow];
	return YES;
}

- drawBarInside:(const NXRect *)cellFrame flipped:(BOOL)flipped
{
	NXRect frame = {{0.0, 0.0}, {111.0, 112.0}};
	id bezel = (cFlags1.disabled ? disabledBezelImage : enabledBezelImage);
	PSgsave();
	if (flipped) {
		PSscale(1.0, -1.0);
		PStranslate(0.0, -111.0);
		imFlipped = YES;
	}
	[bezel composite:NX_SOVER fromRect:&frame toPoint:&(frame.origin)];
	PSgrestore();
	return self;
}

- drawKnob:(const NXRect *)knobRect
{
	NXRect frame = {{0.0, 0.0}, {111.0, 111.0}};
	NXPoint position; float ang; float range = maxValue - minValue;
	id bezel = (cFlags1.disabled ? disabledBezelImage : enabledBezelImage);
	PSgsave();
	if (imFlipped) {
		PSscale(1.0, -1.0);
		PStranslate(0.0, -111.0);
	}
	[bezel composite:NX_SOVER fromRect:&frame toPoint:&(frame.origin)];
	ang = angle(value, minValue, maxValue);
	position.x = cos(ang * PI / 180.0) * 50.0 + 50.0;
	if ((value == minValue) || (value == maxValue))
		position.x -= 1.0; // a hack to fix a weird bug
	position.y = sin(ang * PI / 180.0) * 50.0 + 49.0;
	[knobImage composite:NX_SOVER toPoint:&position];
	PSgrestore();
	return self;
}

- drawSelf:(const NXRect *)cellFrame inView:controlView
{
	trackRect = *cellFrame;
	if ([controlView isFlipped]) imFlipped = YES;
	[self drawKnob:cellFrame];
	return self;
}

- getKnobRect:(NXRect *)knobRect flipped:(BOOL)flipped
{
	[super getKnobRect:knobRect flipped:flipped];
	return self;
}


@end
