// Please see "Carbon Event Manager Programming Guide"
// chapter "Carbon Event Manager Concepts" 
// sections "Carbon Event Handling Theory" and "The Event Model"
// good overview of how event handlers function under OSX



#include <Carbon/Carbon.h>
#include "ltopengl.h"
#include "ltosx.h"

static IBNibRef nibRef;		//used by converter and ltosx

//===========================================ENS Prototypes
static pascal OSStatus GetCF1Value( void* dataRef );
static pascal OSStatus GetCF2Value( void* dataRef );
static pascal OSStatus CF1DialogUpdate( void* dataRef );
static pascal OSStatus CF2DialogUpdate( void* dataRef );
static pascal OSStatus HelpWindowEventHandler( EventHandlerCallRef myHandler, EventRef event, void* userData );
//===========================================ENS Prototypes

enum
{
	kWindowRefTraps,
	kWindowRefMotors,
	kWindowRefP1,
	kWindowRefP2,
	kWindowRefP3,
	kWindowRefChannels,
	kWindowRefCF1,	//ENS
	kWindowRefCF2,	//ENS
	kWindowHelpWindow,	//ENS
	kWindowListCount
};

static WindowRef pWindowList[kWindowListCount] = {}; //debug

static pascal OSStatus P1BoxUpdate ( void* dataRef);
static pascal OSStatus P2BoxUpdate ( void* dataRef);
static pascal OSStatus P3BoxUpdate ( void* dataRef);

static OSStatus ChannelsEventHandler( EventHandlerCallRef myHandler, 
													EventRef event, void *data);
										
////////////////////////////////////////////////////
static OSStatus ChannelsUpdate(WindowRef window, void* data)
{
	int i,j;
	ControlID ctrlID;
	ControlRef ctrlRef; 
	CFStringRef textRef;
	OSStatus err = noErr;
	pData dataRef = (pData) data;
	static int drawCounter = 0;

	if (drawCounter-- <= 0)
	{
		drawCounter = 15;
		ctrlID.signature = 'CHAN';
		for ( i = 128; i < 142; i++)
		{
			ctrlID.id = i;
			err = GetControlByID (window, &ctrlID, &ctrlRef);
			require_noerr_quiet (err, CantGetControl); 
						
			j = dataRef->quicktime.latest[i - 127];
			textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%d"),j);
			
			err = SetControlData (	ctrlRef, 0, kControlEditTextCFStringTag, 
											sizeof(CFStringRef), &textRef);
			require_noerr_quiet (err, CantSetControlData);
			
			DrawOneControl (ctrlRef);
		}
	}
	CantSetControlData:
	CantGetControl:
    return err;
}

////////////////////////////////////////////////////
static pascal OSStatus GetTweezerCommand(WindowRef window, int *pA, int *pB, int *pC, int *pD, int *pE)
{
	OSStatus err = noErr;
	 const ControlID kParameterAID = { 'ENTR', 129 };
    const ControlID kParameterBID = { 'ENTR', 130 };
	 const ControlID kParameterCID = { 'ENTR', 131 };
	 const ControlID kParameterDID = { 'ENTR', 132 };
	 const ControlID kParameterEID = { 'ENTR', 133 };	//for print count, debug
    ControlRef parameterA, parameterB, parameterC, parameterD, parameterE;
    CFStringRef parameterA_text, parameterB_text, parameterC_text, parameterD_text, parameterE_text;
	 
	 
    err = GetControlByID (window, &kParameterBID, &parameterB);
    require_noerr_quiet (err, CantGetControl); 
	 
	 err = GetControlByID (window, &kParameterCID, &parameterC);
    require_noerr_quiet (err, CantGetControl); 
	 
    err = GetControlByID (window, &kParameterDID, &parameterD);
	require_noerr_quiet (err, CantGetControl); 
	 
	 err = GetControlByID (window, &kParameterEID, &parameterE);
    require_noerr_quiet (err, CantGetControl); 
  
    err = GetControlData (parameterA, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterA_text, NULL);
    require_noerr (err, CantGetControlData); 
 	 
	 err = GetControlData (parameterB, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterB_text, NULL);
    require_noerr (err, CantGetControlData); 
	 
	 err = GetControlData (parameterC, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterC_text, NULL);
    require_noerr (err, CantGetControlData); 
 	 
	 err = GetControlData (parameterD, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterD_text, NULL);
   require_noerr (err, CantGetControlData); 
	 
	 err = GetControlData (parameterE, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterE_text, NULL);
    require_noerr (err, CantGetControlData);
	 
    *pA = CFStringGetIntValue (parameterA_text);
	 *pB = CFStringGetIntValue (parameterB_text);
	 *pC = CFStringGetIntValue (parameterC_text);
	 *pD = CFStringGetIntValue (parameterD_text);
	 *pE = CFStringGetIntValue (parameterE_text);

	CFRelease (parameterA_text);
	CFRelease (parameterB_text);
	CFRelease (parameterC_text);
	CFRelease (parameterD_text);
	CFRelease (parameterE_text);
    

	CantSetControlData:
	CantGetControlData:
	CantGetControl:
	return err;
}

												
////////////////////////////////////////////////////
static OSStatus ChannelsEventHandler( EventHandlerCallRef myHandler, 
													EventRef event, void *data)
{
	OSStatus	err = noErr;
	OSStatus				result = eventNotHandledErr;						//not properly handled for close, fixed, check for others, debug
	UInt32 				class = GetEventClass (event);
	UInt32 				kind = GetEventKind (event);
	HICommand command;
	int byteID, byteParam, wordID, wordParam, printCnt;
	pData dataRef = (pData) data;

	//we are post event handling, we call all other event handlers first
	//call next handler, for example if quiting program, flower Q
	result = CallNextEventHandler(myHandler, event);

	if (result != eventNotHandledErr)
		return result;

	switch (class)
	{
		case kEventClassWindow:
			switch (kind)
			{
				case kEventWindowClose:					// called when window is being closed (close box)
					SetWRefCon( pWindowList[kWindowRefChannels], 0 );
					DisposeWindow (pWindowList[kWindowRefChannels]);
					pWindowList[kWindowRefChannels] = NULL;								//debug
					result = eventNotHandledErr;				//should we take this back out, debug
					break;
				default:
					err = eventNotHandledErr;
					break;
			}
			break;
		case kEventClassCommand:
					err = GetEventParameter (	event, kEventParamDirectObject, typeHICommand, 
										NULL, sizeof(HICommand), NULL, &command);
					switch (command.commandID)
					{
						case 'entr':
							err = GetTweezerCommand(pWindowList[kWindowRefChannels], &byteID, 
											&byteParam, &wordID, &wordParam, &printCnt);
							require_noerr (err, CantGetParameter);
							dataRef->quicktime.printCount = printCnt;
							if (dataRef->instrument.trapA)
								CommandTrap (byteID, byteParam, wordID, wordParam, 0,0, kTrapA, data);
							if (dataRef->instrument.trapB)
								CommandTrap (byteID, byteParam, wordID, wordParam, 0,0, kTrapB, data);
							if (dataRef->instrument.trapAB)
								CommandTrap (byteID, byteParam, wordID, wordParam, 0,0, kTrapAB, data);
							break;
						default:
							err = eventNotHandledErr;
							break;
					}
					break;
		default:
			err = eventNotHandledErr;
			break;
    }
	 
	CantGetParameter:
	return err;
}
			

//////////////////////////////////////////////////
OSStatus CreateChannelsWindow(void* data)
{
	OSStatus err;
	const EventTypeSpec commands[] = {{kEventClassCommand,kEventCommandProcess},
												{ kEventClassWindow, kEventWindowClose }};
												
	EventHandlerRef	handlerRef;		//ENS
	EventTypeSpec dialogList[] ={{ kEventClassCommand, kEventCommandProcess },	//ENS
											{ kEventClassWindow,  kEventWindowClose }};

	//if (pWindowList[kWindowRefChannels] != NULL)
	//	return -1;											//add error processing here,	debug
	
	if( IsValidWindowPtr( pWindowList[kWindowRefChannels]))		//ENS
		return 0;
		
	err = CreateWindowFromNib(nibRef, CFSTR("Channels"), 
										&pWindowList[kWindowRefChannels]);
	require_noerr( err, CantCreateWindow );

	InstallWindowEventHandler (pWindowList[kWindowHelpWindow],	//ENS ( see UtilityWindow() )
								NewEventHandlerUPP (ChannelsEventHandler), 
								GetEventTypeCount (dialogList),
								dialogList, data, &handlerRef);

	/*err = InstallWindowEventHandler (pWindowList[kWindowRefChannels],		//commented out by ENS
												NewEventHandlerUPP (ChannelsEventHandler), 
												GetEventTypeCount(commands), commands, 
												data, NULL);*/
	require_noerr (err, CantInstallHandler); 
    
	ShowWindow( pWindowList[kWindowRefChannels] );
	
	CantInstallHandler:
	CantCreateWindow:
	return err;
}

OSStatus CreateHelpWindow( void* data )	//ENS
{
	OSStatus err;
	
	EventHandlerRef	handlerRef;
	EventTypeSpec dialogList[] ={{ kEventClassCommand, kEventCommandProcess },
											{ kEventClassWindow,  kEventWindowClose }};
	
	if( IsValidWindowPtr( pWindowList[kWindowHelpWindow]))
		return 0;
		
	err = CreateWindowFromNib( nibRef, CFSTR( "HelpWindow" ), &pWindowList[kWindowHelpWindow] );
	
	require_noerr( err, CantCreateWindow );
	
	InstallWindowEventHandler (pWindowList[kWindowHelpWindow], 
										NewEventHandlerUPP (HelpWindowEventHandler), 
										GetEventTypeCount (dialogList),
										dialogList, data, &handlerRef);
										
	require_noerr( err, CantInstallHandler );
	
	ShowWindow( pWindowList[kWindowHelpWindow] );
	
	CantInstallHandler:
	CantCreateWindow:
	return err;
}

static pascal OSStatus HelpWindowEventHandler( EventHandlerCallRef myHandler, EventRef event, void* userData )
{
	OSStatus	err = noErr;
	WindowRef	window = NULL;
	OSStatus	result = eventNotHandledErr;
	UInt32		class = GetEventClass( event );
	UInt32		kind = GetEventKind( event );
	HICommand	command;
	int byteID, byteParam, wordID, wordParam, printCnt;
	pData data = (pData) userData;
	
	switch( class ){
		case kEventClassWindow:
			GetEventParameter( event, kEventParamDirectObject, typeWindowRef, NULL,
									sizeof( WindowRef ), NULL, &window );
				require_noerr( err, CantGetParameter );
			switch( kind ){
				case kEventWindowClose:
					SetWRefCon( window, 0 );
					DisposeWindow( window );
					pWindowList[kWindowHelpWindow] = NULL;
					err = noErr;
					break;
				case kEventWindowShown:
					break;
				default:
					err = eventNotHandledErr;
					break;
			}
		break;
	}
	
	CantGetParameter:
	return err;
}


/*
 *  Shane Saxon has waived all copyright and related or neighboring rights to
 *  "miniTweezers GUI". Published from the United States as Public Domain.
 *  Creative Commons License CC0 1.0 Universal.
 *
 *  Created by Shane Saxon with contributions by Steven Smith, Evan Sperber,
 *  and Josep-Maria Huguet.  Code base started in 2004.
 *
 *  To view the full license with a list of additional authors and to download or
 *  contribute code goto http://tweezerslab.unipr.it/license.html
 *
 */

#define kMPStackSize 0			//use default stack size of 4KB
#define kMPTaskOptions 0
#define kThreadListSize 256


struct ThreadRef{
	MPTaskID taskID;
	MPQueueID requestQueue;
	MPQueueID resultQueue;
	MPQueueID notificationQueue;
	
	void* data;
	int (*pFunction)(void*);
	int killThread;
};
typedef struct ThreadRef ThreadRef;
typedef struct ThreadRef *pThreadRef;


static int currentID;
static int lockCurrentID;
static pThreadRef pThreadList[kThreadListSize];


#pragma mark ---- Carbon Timer ----

//////////////////////////////////////////////////
static pascal void IdleTimer (EventLoopTimerRef inTimer, void* data)
{
	ChannelsUpdate(pWindowList[kWindowRefChannels], data);
	ControlTimer(data);
}

// per-window timer function, basic time based animation preformed here
static void timerContextCB (WindowRef window)
{
    pRecContext pContextInfo = NULL;
	if (window)
		pContextInfo = GetCurrentContextInfo (window);
	if (pContextInfo) {
		AbsoluteTime currTime = UpTime ();
		double deltaTime = (float) AbsoluteDeltaToDuration (currTime, pContextInfo->time);
		pContextInfo->time = currTime;	// reset for next time interval
		if (0 > deltaTime)	// if negative microseconds
			deltaTime /= -1000000.0;
		else				// else milliseconds
			deltaTime /= 1000.0;
		if (deltaTime < 10.0) { // skip large pauses
			DrawGL (window, true); // required to do this directly to get animation during resize and drags
		}
	}
}

// ---------------------------------

// timer callback bottleneck
static pascal void timerCB (EventLoopTimerRef inTimer, void* userData)
{
	#pragma unused (inTimer)
    timerContextCB ((WindowRef) userData); // timer based update
}

// ---------------------------------

// get UPP for timer
static EventLoopTimerUPP getTimerUPP (void)
{
	static EventLoopTimerUPP	sTimerUPP = NULL;
	
	if (sTimerUPP == NULL)
		sTimerUPP = NewEventLoopTimerUPP (timerCB);
	
	return sTimerUPP;
}


#pragma mark ---- Event Handlers ----


////////////////////////////////////////////////
static pascal OSStatus AppEventHandler(EventHandlerCallRef myHandler, EventRef event, 
								void* dataRef)
{
	OSStatus err = 0;
	OSStatus result = eventNotHandledErr;
    UInt32 class = GetEventClass (event);
    UInt32 kind = GetEventKind (event);
    HICommand command;
	 int eventControlID = 0;
	 pData data = (pData) dataRef;	   //should error check if data is valid, debug
	 const ControlID kTrapSliderID = { 'ctrl', 18 };
	 const ControlID kMotorSliderID = { 'ctrl', 194 };
	 const ControlID kGotoSliderID = { 'ctrl', 200 };		//ENS
	 ControlHandle buttonGroup;								//SBS
	 const ControlID kButtonGroupID = { 'ctrl', 51};		//SBS	
	 ControlRef controlRef;
	

	//we are post event handling, we call all other event handlers first
	//call next handler, for example if quiting program using command-Q

	result = CallNextEventHandler(myHandler, event);

	GetControlByID (pWindowList[kWindowRefTraps], &kButtonGroupID, &buttonGroup);			//SBS
	int buttonGroupValue = GetControl32BitValue (buttonGroup);								//SBS

	switch (class) {
		case kEventClassCommand:
			switch (kind) {
				case kEventProcessCommand:
					GetEventParameter (event, kEventParamDirectObject, kEventParamHICommand, NULL, sizeof(command), NULL, &command); // get command
					switch (command.commandID) {
//						case kHICommandNew:
//							break;

						case 'func':
							switch (buttonGroupValue) {
								case 1:
									eventControlID = kEventAllOff;
									break;
								case 2:
									eventControlID = kEventPullOne;
									break;
								case 3:
									eventControlID =  kEventPullTwo;
									break;
								case 4:
									eventControlID = kEventPullThree;
									break;
								case 5:
									eventControlID = kEventHoldForce1;
									break;
								case 6:
									eventControlID =  kEventHoldForce2;
									break;
								case 7:
									eventControlID = kEventHoppingTrap;
									break;
								case 8:
									eventControlID = kEventStiffTest;
									break;
								}
							break;
						case 'rall':
							eventControlID = kEventResetAll;
							break;
						case 'rgui':
							eventControlID = kEventResetGUI;
							break;
						case 'rusb':
							eventControlID = kEventResetUSB;
							break;
						case 'rcom':
							eventControlID = kEventResetMainPIC;
							break;
						case 'rpie':
							eventControlID = kEventResetPiezoPIC;
							break;
						case 'rmot':
							eventControlID = kEventResetMotorPIC;
							break;
						case 'rprf':
							eventControlID = kEventResetPrefValues;			//SBS
							break;
						case 'iprf':
							eventControlID = kEventImportPrefValues;		//SBS	
							break;
						case 'eprf':
							eventControlID = kEventExportPrefValues;		//SBS
							break;
						case 'strt':
							eventControlID = kEventStartUSB;
							break;
						case 'trpa':
							eventControlID = kEventTrapA;
							break;
						case 'trab':
							eventControlID = kEventTrapAB;
							break;
						case 'trpb':
							eventControlID = kEventTrapB;
							break;
						case 'ctrp':
							eventControlID = kEventCenterTrap;
							break;
						case 'zpsd':
							eventControlID = kEventZeroPSDs;
							break;
						case 'zfor':
							eventControlID = kEventZeroForce;
							break;
						case 'zlev':
							eventControlID = kEventZeroLevers;
							break;
						case 'mtrp':
							eventControlID = kEventMovePiezosXY;
							if (data->instrument.moveTrap)			
								SetThemeCursor (kThemeArrowCursor);
							else
								SetThemeCursor (kThemePointingHandCursor);
							break;
						case 'mtrx':
							eventControlID = kEventMovePiezosX;
							if (data->instrument.moveTrap)			
								SetThemeCursor (kThemeArrowCursor);
							else
								SetThemeCursor (kThemePointingHandCursor);
							break;
						case 'mtry':
							eventControlID = kEventMovePiezosY;
							if (data->instrument.moveTrap)			
								SetThemeCursor (kThemeArrowCursor);
							else
								SetThemeCursor (kThemePointingHandCursor);
							break;
						case 'auto':
							eventControlID = kEventAutoAlign;
							break;
						case 'cfor':
							eventControlID = kEventConstantForce;
							break;
						case 'cpos':
							eventControlID = kEventConstantPosition;
							break;
						
						case 'motm':
							eventControlID = kEventMoveMotors;
							if (data->instrument.moveMotors)			
								SetThemeCursor (kThemeArrowCursor);
							else
								SetThemeCursor (kThemePointingHandCursor);
							break;
						case 'motx':
							eventControlID = kEventMotorXaxis;
							if (data->instrument.moveMotors)			
								SetThemeCursor (kThemeArrowCursor);
							else
								SetThemeCursor (kThemePointingHandCursor);
							break;
						case 'moty':
							eventControlID = kEventMotorYaxis;
							if (data->instrument.moveMotors)			
								SetThemeCursor (kThemeArrowCursor);
							else
								SetThemeCursor (kThemePointingHandCursor);
							break;
						case 'motz':
							eventControlID = kEventMotorZaxis;
							if (data->instrument.moveMotors)			
								SetThemeCursor (kThemeArrowCursor);
							else
								SetThemeCursor (kThemePointingHandCursor);
							break;
						case 'motp':
							eventControlID = kEventMotorPaxis;
							if (data->instrument.moveMotors)			
								SetThemeCursor (kThemeArrowCursor);
							else
								SetThemeCursor (kThemePointingHandCursor);
							break;
						case 'stop':
							eventControlID = kEventStop;
							break;
						case 'mled':
							eventControlID = kEventToggleLED;
							break;
						case 'mras':
							eventControlID = kEventMotorRaster;
							break;
						case 'pras':
							eventControlID = kEventPiezoRaster;
							break;
							
							
						case 'sldt':
							err = GetControlByID (pWindowList[kWindowRefTraps], &kTrapSliderID, &controlRef);
							require_noerr_quiet (err, CantGetTrapSliderControl);
							data->control.mouseTrapSensitivity = GetControl32BitValue (controlRef);
							result = noErr;
							CantGetTrapSliderControl:
							break;
						case 'sldm':
							err = GetControlByID (pWindowList[kWindowRefMotors], &kMotorSliderID, &controlRef);
							require_noerr_quiet (err, CantGetControl);
							data->control.mouseMotorSensitivity = GetControl32BitValue (controlRef);
							result = noErr;
							CantGetControl:
							break;
							
						case 'gspd':
							err = GetControlByID( pWindowList[ kWindowRefMotors], &kGotoSliderID, &controlRef );	
							require_noerr_quiet( err, CantGetControl );
							data->instrument.userInteger[kGotoSpeedX].value = GetControl32BitValue( controlRef );
							data->instrument.userInteger[kGotoSpeedY].value = data->instrument.userInteger[kGotoSpeedX].value;
							data->instrument.userInteger[kGotoSpeedZ].value = round(data->instrument.userInteger[kGotoSpeedX].value / 2);
							result = noErr;
							CantGetGotoSliderControl:
							break;
						
						case 'wpie':
							eventControlID = kEventWindowTraps;
							break;
						case 'wmot':
							eventControlID = kEventWindowMotors;
							break;
						case 'wfve':
							eventControlID = kEventWindowForceVsPosition;
							break;
						case 'wevt':
							eventControlID = kEventWindowExtensionVsTime;
							break;
						case 'wfvt':
							eventControlID = kEventWindowForceVsTime;
							break;
						case 'wlvr':
							eventControlID = kEventWindowLever;
							break;
						case 'wpsd':
							eventControlID = kEventWindowPSD;
							break;
						case 'wnet':
							eventControlID = kEventWindowNetForce;
							break;
						case 'wosc':
							eventControlID = kEventWindowOscilloscope;
							break;
						case 'wfou':
							eventControlID = kEventWindowFourier;
							break;
						case 'wmap':
							eventControlID = kEventWindowMap;
							break;
						case 'wcha':
							eventControlID = kEventWindowChannels;
							break;
						case 'wslt':			//JMH
							eventControlID = kEventWindowStokesLawTest;
							break;
						case 'wlca':		//SBS
							eventControlID = kEventWindowMotorLever;
							break;
						case 'wllc':			//SBS
							eventControlID = kEventWindowLeverLever;
							break;
						case 'hopp':			//SBS
							eventControlID = kEventWindowHopping;
							break;
						case 'wimp':			//SBS
							eventControlID = kEventWindowIntensityMap;
							break;
						case 'wdfp':			//SBS
							eventControlID = kEventWindowDualForce;
							break;
						case 'wpaa':
							eventControlID = kEventWindowP1;
							break;
						case 'wpab':
							eventControlID = kEventWindowP2;		
							break;
						case 'wpae':
							eventControlID = kEventWindowP3;		
							break;
						case 'fnct':								
							eventControlID = kEventFunctGen;
							break;
						case 'wpac':
							MakeWindow( kEventHoldForce1, data);
							break;
						case 'wpad':
							MakeWindow( kEventHoldForce2, data);
							break;
						case 'gto0':
							eventControlID = kEventGotoZero;	//ENS
							break;
						case 'gto1':
							eventControlID = kEventGotoOne;	//ENS
							break;
						case 'gto2':
							eventControlID = kEventGotoTwo;	//ENS
							break;
						case 'gto3':
							eventControlID = kEventGotoThree;	//ENS
							break;
						case 'gto4':
							eventControlID = kEventGotoFour;	//ENS
							break;
						case 'gto5':
							eventControlID = kEventGotoFive;	//ENS
							break;
						case 'gto6':
							eventControlID = kEventGotoSix;	//ENS
							break;
						case 'gto7':
							eventControlID = kEventGotoSeven;	//ENS
							break;
						case 'gto8':
							eventControlID = kEventGotoEight;	//ENS
							break;
						case 'gto9':
							eventControlID = kEventGotoNine;	//ENS
							break;
						case 'rec5':
							eventControlID = kEventRecordFive;
							break;
						case 'rec6':
							eventControlID = kEventRecordSix;
							break;
						case 'rec7':
							eventControlID = kEventRecordSeven;
							break;
						case 'dfil':
							eventControlID = kEventChangeWriteStatus;	//ENS
							break;
						case 'help':
							eventControlID = kEventOpenHelpWindow;
							break;
					}
					if (eventControlID)		//if true call ControlEvent
					{
						ControlEvent(eventControlID, data);
						result = noErr;
					}
					break;
				case kEventCommandUpdateStatus: // menu updates
/*					GetEventParameter (event, kEventParamDirectObject, kEventParamHICommand, NULL, sizeof(command), NULL, &command); // get command
					switch (command.commandID) {
						case kHICommandClose:
							if (pContextInfo)
								EnableMenuItem (GetMenuHandle (kMainMenu), kCloseMenuItem);
							else 
								DisableMenuItem (GetMenuHandle (kMainMenu), kCloseMenuItem);
							break;
						case 'gogo':
							if (pContextInfo) {
								EnableMenuItem (GetMenuHandle (kMainMenu), kAnimateMenuItem);
								CheckMenuItem (GetMenuHandle (kMainMenu), kAnimateMenuItem, pContextInfo->animate);
							} else { 
								DisableMenuItem (GetMenuHandle (kMainMenu), kAnimateMenuItem);
								CheckMenuItem (GetMenuHandle (kMainMenu), kAnimateMenuItem, kAnimateState);
							}
							break;
						case 'info':
							if (pContextInfo) {
								EnableMenuItem (GetMenuHandle (kMainMenu), kInfoMenuItem);
								CheckMenuItem (GetMenuHandle (kMainMenu), kInfoMenuItem, pContextInfo->info);
							} else { 
								DisableMenuItem (GetMenuHandle (kMainMenu), kInfoMenuItem);
								CheckMenuItem (GetMenuHandle (kMainMenu), kInfoMenuItem, kInfoState);
							}
							break;
					}
					result = noErr;
*/					break;
			}
			break;
	}
    return result;
}

/////////////////////////////////////////////
void MoveCursorToMotorsButton (void* userData)
{
	OSStatus				result = noErr;
	CGPoint				mouseLocation = {50.0f, 50.0f};
	Rect windowRect;
	
	GetWindowBounds (pWindowList[kWindowRefMotors], kWindowStructureRgn, &windowRect);

	mouseLocation.x = windowRect.left + 90.0;							//update this with button center, debug
	mouseLocation.y = windowRect.top + 40.0;							// debug

	CGDisplayMoveCursorToPoint (kCGDirectMainDisplay, mouseLocation);	//add detection of which display the window is on, debug

	SetThemeCursor (kThemePointingHandCursor);

}


///////////////////////////////////////////
static OSStatus MouseEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData)
{
	WindowRef			window = NULL;
	OSStatus				result = eventNotHandledErr;
	UInt32 				class = GetEventClass (event);
	UInt32 				kind = GetEventKind (event);


	EventMouseButton		button = 0;
	HIPoint					mouseDelta = {0.0f, 0.0f};
	CGPoint					mouseLocation = {500.0f, 500.0f};
	static CGPoint			mouseStartLocation = {50.0f, 50.0f};
	UInt32					modifiers = 0;
   EventMouseWheelAxis	axis;
	SInt32					wheelDelta = 0;
	SInt32					deltaPixels = 0;
	Rect						rectPort, windowRect;

	pData data = (pData) userData;

	if (class != kEventClassMouse)		//error control
		return eventNotHandledErr;

	//we are post event handling, we call all other event handlers first
	//call next handler, for example if quiting program, flower Q
	result = CallNextEventHandler(myHandler, event);
	if (result != eventNotHandledErr)
		return result;

	switch (kind)
	{
		case kEventMouseMoved:
			GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL,
									sizeof(EventMouseButton), NULL, &button);
			GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, NULL,
									sizeof(CGPoint), NULL, &mouseLocation);
			GetEventParameter(event, kEventParamMouseDelta, typeHIPoint, NULL,
									sizeof(HIPoint), NULL, &mouseDelta);
			GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL,
									sizeof(UInt32), NULL, &modifiers);

			if (data->instrument.moveTrap || data->instrument.moveMotors)
			{
				if (data->instrument.moveMotors)
				{
					GetWindowBounds (pWindowList[kWindowRefMotors], 
											kWindowStructureRgn, &windowRect);
					mouseStartLocation.x = windowRect.left + 90.0;							//update this with button center, debug
					mouseStartLocation.y = windowRect.top + 40.0;							// debug
				}
				
				result = CGDisplayMoveCursorToPoint (	kCGDirectMainDisplay, 
																	mouseStartLocation);
																	
				ControlMouseMoved (mouseDelta.x, mouseDelta.y, 0, userData);
			}
			else
				mouseStartLocation = mouseLocation;
				
			result = noErr;
			break;
		case kEventMouseWheelMoved:            
			GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, 
											NULL, sizeof(modifiers), NULL, &modifiers );
											
			GetEventParameter( event, kEventParamMouseWheelAxis, 
								typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis );
								
			GetEventParameter( event, kEventParamMouseWheelDelta, 
						typeLongInteger, NULL, sizeof(wheelDelta), NULL, &wheelDelta);

			if ( axis == kEventMouseWheelAxisY )
			{
				deltaPixels = 20 * wheelDelta;

				if (modifiers & optionKey)
					deltaPixels /= 10;
			}
				
			ControlMouseMoved (0, 0, deltaPixels, userData);
			//ControlEvent(kEventToggleLED, userData);
			result = noErr;
			break;
	}
	return result;
	
//				if ((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary)
}


// ---------------------------------
// key input handler calls a function passing a command based on the key map
static pascal OSStatus AppKeyEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData)
{	
	OSStatus	result = eventNotHandledErr;
	UInt32	keyCode, modifierKeys, command;	
	UInt32 	class = GetEventClass (event);
	UInt32 	kind = GetEventKind (event);
	pData		data = (pData) userData;

	if (class != kEventClassKeyboard)		//exit if not a keyboard event
		return result;

	//we are post event handling, we call all other event handlers first
	//call next handler, for example if quiting program, flower Q
	result = CallNextEventHandler(myHandler, event);
	if (result != eventNotHandledErr)
		return result;
	
	GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, 
							 sizeof(UInt32), NULL, &keyCode);
			
	GetEventParameter (event, kEventParamKeyModifiers, typeUInt32, NULL, 
							 sizeof(UInt32), NULL, &modifierKeys);
	
	// printf (" KeyCode %d", keyCode);	//debug
	
	//checking if keyCode is keyMap array bounds
	if (keyCode >= kKeyMapSize)
		return result;

	//looks up the action assigned to the key using the keyMap
	command = data->control.keyMap[kind][keyCode];

	//exit if graph window event
	if (command >= kGraphMenu)
		return result;
		
	switch (kind) 
	{
		case kEventRawKeyModifiersChanged:		//uses bit mask to determine key
			data->control.shiftModifier = (modifierKeys & shiftKey);
			data->control.alphaLockModifier = (modifierKeys & alphaLock);
			data->control.controlModifier = (modifierKeys & controlKey);
			data->control.altModifier = (modifierKeys & optionKey);
			data->control.commandModifier = (modifierKeys & cmdKey);
				
			if (data->control.shiftModifier == data->control.alphaLockModifier)
				data->control.upperCase = 0;
			else
				data->control.upperCase = 1;
//			if (modifierKeys & activeFlag) a window is being activated or a mouse-down event has caused a foreground switch
//			if (modifierKeys & btnState) the mouse button has been released.
			return result;		//we allow other event handlers to also use modifiers
			break;
		case kEventRawKeyDown:
			break;
		case kEventRawKeyRepeat:
			break;
		case kEventRawKeyUp:
			break;
		default:
			return result;					//exit if other key event, ie. hot keys
			break;			
	}
	
	if (!data->control.commandModifier)							//should not be needed, debug
		ControlEvent(command, data);	
	
	return noErr;
}


////////////////////////////////////////////////////
static pascal OSStatus GetP1Values ( void* dataRef)
{
	OSStatus err = noErr;
	 const ControlID kParameterAID = { 'ENTR', 128 };
	 const ControlID kParameterBID = { 'ENTR', 129 };
	 const ControlID kParameterCID = { 'ENTR', 130 };
	 const ControlID kParameterDID = { 'ENTR', 131 };
	 const ControlID kParameterEID = { 'ENTR', 132 };
    ControlRef parameterA, parameterB, parameterC, parameterD, parameterE;
    CFStringRef parameterA_text, parameterB_text, parameterC_text, parameterD_text, parameterE_text;
	 
	 pData data = (pData) dataRef;
	 
    err = GetControlByID (pWindowList[kWindowRefP1], &kParameterAID, &parameterA);
    require_noerr_quiet (err, CantGetControl); 
	 
	err = GetControlByID (pWindowList[kWindowRefP1], &kParameterBID, &parameterB);
    require_noerr_quiet (err, CantGetControl); 
	 
    err = GetControlByID (pWindowList[kWindowRefP1], &kParameterCID, &parameterC);
    require_noerr_quiet (err, CantGetControl); 
	 
	err = GetControlByID (pWindowList[kWindowRefP1], &kParameterDID, &parameterD);
    require_noerr_quiet (err, CantGetControl); 
	
	err = GetControlByID (pWindowList[kWindowRefP1], &kParameterEID, &parameterE);
    require_noerr_quiet (err, CantGetControl); 
  
    err = GetControlData (parameterA, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterA_text, NULL);
    require_noerr (err, CantGetControlData); 
 	 
	 err = GetControlData (parameterB, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterB_text, NULL);
    require_noerr (err, CantGetControlData);
	 
	 err = GetControlData (parameterC, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterC_text, NULL);
    require_noerr (err, CantGetControlData);
 	 
	 err = GetControlData (parameterD, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterD_text, NULL);
    require_noerr (err, CantGetControlData);
	 
	 err = GetControlData (parameterE, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterE_text, NULL);
    require_noerr (err, CantGetControlData);
	 
    data->instrument.userFloat[kMaxForceP1].value = CFStringGetDoubleValue (parameterA_text);	//SBS
	data->instrument.userFloat[kMinForceP1].value = CFStringGetDoubleValue (parameterB_text);	//SBS
	data->instrument.userFloat[kRefoldTime1].value = CFStringGetDoubleValue (parameterC_text); //SBS
	data->instrument.userFloat[kPullRateP1].value = CFStringGetIntValue (parameterD_text);		//SBS
	data->instrument.userFloat[kUnfoldTime1].value = CFStringGetDoubleValue (parameterE_text); //SBS


	data->instrument.maxForce = data->instrument.userFloat[kMaxForceP1].value;	//SBS
	data->instrument.minForce = data->instrument.userFloat[kMinForceP1].value;	//SBS
	data->instrument.refoldTime = data->instrument.userFloat[kRefoldTime1].value;	//SBS
	data->instrument.pullRate = data->instrument.userFloat[kPullRateP1].value;	//SBS
	data->instrument.unfoldTime = data->instrument.userFloat[kUnfoldTime1].value;	//SBS

	CFRelease (parameterA_text);
	CFRelease (parameterB_text);
	CFRelease (parameterC_text);
	CFRelease (parameterD_text);
	CFRelease (parameterE_text);
    

	CantSetControlData:
	CantGetControlData:
	CantGetControl:
	return err;
}

////////////////////////////////////////////////////
static pascal OSStatus GetP2Values ( void* dataRef)
{
	OSStatus err = noErr;
	 const ControlID kParameterAID = { 'ENTR', 128 };
	 const ControlID kParameterBID = { 'ENTR', 129 };
	 const ControlID kParameterCID = { 'ENTR', 130 };
	 const ControlID kParameterDID = { 'ENTR', 131 };
	 const ControlID kParameterEID = { 'ENTR', 132 };
    ControlRef parameterA, parameterB, parameterC, parameterD, parameterE;
    CFStringRef parameterA_text, parameterB_text, parameterC_text, parameterD_text, parameterE_text;
	 
	 pData data = (pData) dataRef;
	 
    err = GetControlByID (pWindowList[kWindowRefP2], &kParameterAID, &parameterA);
    require_noerr_quiet (err, CantGetControl); 
	 
	err = GetControlByID (pWindowList[kWindowRefP2], &kParameterBID, &parameterB);
    require_noerr_quiet (err, CantGetControl); 
	 
    err = GetControlByID (pWindowList[kWindowRefP2], &kParameterCID, &parameterC);
    require_noerr_quiet (err, CantGetControl); 
	 
	err = GetControlByID (pWindowList[kWindowRefP2], &kParameterDID, &parameterD);
    require_noerr_quiet (err, CantGetControl); 
	
	err = GetControlByID (pWindowList[kWindowRefP2], &kParameterEID, &parameterE);
    require_noerr_quiet (err, CantGetControl); 
  
    err = GetControlData (parameterA, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterA_text, NULL);
    require_noerr (err, CantGetControlData); 
 	 
	 err = GetControlData (parameterB, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterB_text, NULL);
    require_noerr (err, CantGetControlData);
	 
	 err = GetControlData (parameterC, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterC_text, NULL);
    require_noerr (err, CantGetControlData);
 	 
	 err = GetControlData (parameterD, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterD_text, NULL);
    require_noerr (err, CantGetControlData);
	 
	 err = GetControlData (parameterE, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterE_text, NULL);
    require_noerr (err, CantGetControlData);
	 
    data->instrument.userFloat[kMaxForceP2].value = CFStringGetDoubleValue (parameterA_text);	//SBS
	data->instrument.userFloat[kMinForceP2].value = CFStringGetDoubleValue (parameterB_text);	//SBS
	data->instrument.userFloat[kRefoldTime2].value = CFStringGetDoubleValue (parameterC_text);	//SBS
	data->instrument.userFloat[kPullRateP2].value = CFStringGetIntValue (parameterD_text);		//SBS
	data->instrument.userFloat[kUnfoldTime2].value = CFStringGetDoubleValue (parameterE_text);	//SBS

	data->instrument.maxForce = data->instrument.userFloat[kMaxForceP2].value;	//SBS
	data->instrument.minForce = data->instrument.userFloat[kMinForceP2].value;	//SBS
	data->instrument.refoldTime = data->instrument.userFloat[kRefoldTime2].value;	//SBS	
	data->instrument.pullRate = data->instrument.userFloat[kPullRateP2].value;	//SBS
	data->instrument.unfoldTime = data->instrument.userFloat[kUnfoldTime2].value;	//SBS

	CFRelease (parameterA_text);
	CFRelease (parameterB_text);
	CFRelease (parameterC_text);
	CFRelease (parameterD_text);
	CFRelease (parameterE_text);
    

	CantSetControlData:
	CantGetControlData:
	CantGetControl:
	return err;
}
////////////////////////////////////////////////////
static pascal OSStatus GetP3Values ( void* dataRef)
{
	OSStatus err = noErr;
	const ControlID kParameterAID = { 'ENTR', 128 };
	const ControlID kParameterBID = { 'ENTR', 129 };
	const ControlID kParameterCID = { 'ENTR', 130 };
	const ControlID kParameterDID = { 'ENTR', 131 };
	const ControlID kParameterEID = { 'ENTR', 132 };
    ControlRef parameterA, parameterB, parameterC, parameterD, parameterE;
    CFStringRef parameterA_text, parameterB_text, parameterC_text, parameterD_text, parameterE_text;
	
	pData data = (pData) dataRef;
	
    err = GetControlByID (pWindowList[kWindowRefP3], &kParameterAID, &parameterA);
    require_noerr_quiet (err, CantGetControl); 
	
	err = GetControlByID (pWindowList[kWindowRefP3], &kParameterBID, &parameterB);
    require_noerr_quiet (err, CantGetControl); 
	
    err = GetControlByID (pWindowList[kWindowRefP3], &kParameterCID, &parameterC);
    require_noerr_quiet (err, CantGetControl); 
	
	err = GetControlByID (pWindowList[kWindowRefP3], &kParameterDID, &parameterD);
    require_noerr_quiet (err, CantGetControl); 
	
	err = GetControlByID (pWindowList[kWindowRefP3], &kParameterEID, &parameterE);
    require_noerr_quiet (err, CantGetControl); 
	
    err = GetControlData (parameterA, 0, kControlEditTextCFStringTag, 
						  sizeof(CFStringRef), &parameterA_text, NULL);
    require_noerr (err, CantGetControlData); 
	
	err = GetControlData (parameterB, 0, kControlEditTextCFStringTag, 
						  sizeof(CFStringRef), &parameterB_text, NULL);
    require_noerr (err, CantGetControlData);
	
	err = GetControlData (parameterC, 0, kControlEditTextCFStringTag, 
						  sizeof(CFStringRef), &parameterC_text, NULL);
    require_noerr (err, CantGetControlData);
	
	err = GetControlData (parameterD, 0, kControlEditTextCFStringTag, 
						  sizeof(CFStringRef), &parameterD_text, NULL);
    require_noerr (err, CantGetControlData);
	
	err = GetControlData (parameterE, 0, kControlEditTextCFStringTag, 
						  sizeof(CFStringRef), &parameterE_text, NULL);
    require_noerr (err, CantGetControlData);
	
    data->instrument.userFloat[kMaxForceP3].value = CFStringGetDoubleValue (parameterA_text);	//SBS
	data->instrument.userFloat[kMinForceP3].value = CFStringGetDoubleValue (parameterB_text);	//SBS
	data->instrument.userFloat[kRefoldTime3].value = CFStringGetDoubleValue (parameterC_text);	//SBS
	data->instrument.userFloat[kPullRateP3].value = CFStringGetDoubleValue (parameterD_text);		//SBS
	data->instrument.userFloat[kUnfoldTime3].value = CFStringGetDoubleValue (parameterE_text);	//SBS
	
	data->instrument.maxForce = data->instrument.userFloat[kMaxForceP3].value;	//SBS
	data->instrument.minForce = data->instrument.userFloat[kMinForceP3].value;	//SBS
	data->instrument.refoldTime = data->instrument.userFloat[kRefoldTime3].value;	//SBS	
	data->instrument.pullRate = data->instrument.userFloat[kPullRateP3].value;	//SBS
	data->instrument.unfoldTime = data->instrument.userFloat[kUnfoldTime3].value;	//SBS
	
	CFRelease (parameterA_text);
	CFRelease (parameterB_text);
	CFRelease (parameterC_text);
	CFRelease (parameterD_text);
	CFRelease (parameterE_text);
    
	
CantSetControlData:
CantGetControlData:
CantGetControl:
	return err;
}


///////////////////////////////////////////////////////////////
static pascal OSStatus P1BoxUpdate ( void* dataRef)		// for custom dialog boxes
{
	int i;
	ControlID ctrlID;
	ControlRef ctrlRef; 
	CFStringRef textRef;
	OSStatus err = noErr;
	pData data = (pData) dataRef;

	if (!IsValidWindowPtr(pWindowList[kWindowRefP1]))
		return -1;

		ctrlID.signature = 'ENTR';
		for ( i = 128; i < 133; i++)
		{
			ctrlID.id = i;
			err = GetControlByID (pWindowList[kWindowRefP1], &ctrlID, &ctrlRef);
				require_noerr_quiet (err, CantGetControl); 

			switch (i)
			{
				case 128:
					textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
								data->instrument.userFloat[kMaxForceP1].value);								//SBS
					break;
				case 129:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
								data->instrument.userFloat[kMinForceP1].value);								//SBS
					break;
				case 130:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
								data->instrument.userFloat[kRefoldTime1].value);							//SBS
					break;
				case 131:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),							//SBS
								data->instrument.userFloat[kPullRateP1].value);								//SBS
					break;
				case 132:
					textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
														data->instrument.userFloat[kUnfoldTime1].value);	//SBS
					break;
					
			}
															
			err = SetControlData (	ctrlRef, 0, kControlEditTextCFStringTag, 
											sizeof(CFStringRef), &textRef);
			require_noerr_quiet (err, CantSetControlData);
			
			DrawOneControl (ctrlRef);
			
		}
	
	CantSetControlData:
	CantGetControl:
	return err;
}
///////////////////////////////////////////////////////////////
static pascal OSStatus P2BoxUpdate ( void* dataRef)		
{
	int i;
	ControlID ctrlID;
	ControlRef ctrlRef; 
	CFStringRef textRef;
	OSStatus err = noErr;
	pData data = (pData) dataRef;

	if (!IsValidWindowPtr(pWindowList[kWindowRefP2]))
		return -1;

		ctrlID.signature = 'ENTR';
		for ( i = 128; i < 133; i++)
		{
			ctrlID.id = i;
			err = GetControlByID (pWindowList[kWindowRefP2], &ctrlID, &ctrlRef);
				require_noerr_quiet (err, CantGetControl); 

			switch (i)
			{
				case 128:
					textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
								data->instrument.userFloat[kMaxForceP2].value);								//SBS
					break;
				case 129:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
								data->instrument.userFloat[kMinForceP2].value);								//SBS
					break;
				case 130:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
								data->instrument.userFloat[kRefoldTime2].value);							//SBS
					break;
				case 131:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),							//SBS
								data->instrument.userFloat[kPullRateP2].value);								//SBS
					break;
				case 132:
					textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
								data->instrument.userFloat[kUnfoldTime2].value);							//SBS					
			}
															
			err = SetControlData (	ctrlRef, 0, kControlEditTextCFStringTag, 
											sizeof(CFStringRef), &textRef);
			require_noerr_quiet (err, CantSetControlData);
			
			DrawOneControl (ctrlRef);
			
		}
	
	CantSetControlData:
	CantGetControl:
	return err;
}


///////////////////////////////////////////////////////////////
static pascal OSStatus P3BoxUpdate ( void* dataRef)		
{
	int i;
	ControlID ctrlID;
	ControlRef ctrlRef; 
	CFStringRef textRef;
	OSStatus err = noErr;
	pData data = (pData) dataRef;
	
	if (!IsValidWindowPtr(pWindowList[kWindowRefP3]))
		return -1;
	
	ctrlID.signature = 'ENTR';
	for ( i = 128; i < 133; i++)
	{
		ctrlID.id = i;
		err = GetControlByID (pWindowList[kWindowRefP3], &ctrlID, &ctrlRef);
		require_noerr_quiet (err, CantGetControl); 
		
		switch (i)
		{
			case 128:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
													data->instrument.userFloat[kMaxForceP3].value);								//SBS
				break;
			case 129:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
													data->instrument.userFloat[kMinForceP3].value);								//SBS
				break;
			case 130:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
													data->instrument.userFloat[kRefoldTime3].value);							//SBS
				break;
			case 131:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),							//SBS
													data->instrument.userFloat[kPullRateP3].value);								//SBS
				break;
			case 132:
				textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
													data->instrument.userFloat[kUnfoldTime3].value);							//SBS					
		}
		
		err = SetControlData (	ctrlRef, 0, kControlEditTextCFStringTag, 
							  sizeof(CFStringRef), &textRef);
		require_noerr_quiet (err, CantSetControlData);
		
		DrawOneControl (ctrlRef);
		
	}
	
CantSetControlData:
CantGetControl:
	return err;
}

//=========================================================================================================ENS
static pascal OSStatus CF1DialogEventHandler( EventHandlerCallRef myHandler, EventRef event, void* userData )
{
	OSStatus	err = noErr;
	WindowRef	window = NULL;
	OSStatus	result = eventNotHandledErr;
	UInt32		class = GetEventClass( event );
	UInt32		kind = GetEventKind( event );
	HICommand	command;
	int byteID, byteParam, wordID, wordParam, printCnt;
	pData data = (pData) userData;
	
	switch( class ){
		case kEventClassWindow:
			GetEventParameter( event, kEventParamDirectObject, typeWindowRef, NULL,
									sizeof( WindowRef ), NULL, &window );
				require_noerr( err, CantGetParameter );
			switch( kind ){
				case kEventWindowClose:
					SetWRefCon( window, 0 );
					DisposeWindow( window );
					err = noErr;
					break;
				case kEventWindowShown:
					break;
				default:
					err = eventNotHandledErr;
					break;
			}
		break;
	case kEventClassCommand:
		err = GetEventParameter( event, kEventParamDirectObject,
										typeHICommand, NULL, sizeof( HICommand ),
										NULL, &command );
		switch( command.commandID ){
			case 'entr':
				GetCF1Value( data );
				CF1DialogUpdate( data );
				SetUserFocusWindow( kUserFocusAuto );
				SetThemeCursor( kThemeArrowCursor );
				err = noErr;
				break;
			default:
				err = eventNotHandledErr;
				break;
		}
	}
	
	CantGetParameter:
	return err;
}

static pascal OSStatus GetCF1Value( void* dataRef )
{
	OSStatus err = noErr;
	const ControlID kParameterAID = { 'ENTR', 128 };

    ControlRef parameterA;
    CFStringRef parameterA_text;
	 
	pData data = (pData) dataRef;
	 
    err = GetControlByID (pWindowList[kWindowRefCF1], &kParameterAID, &parameterA);
    require_noerr_quiet (err, CantGetControl); 
  
    err = GetControlData (parameterA, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterA_text, NULL);
    require_noerr (err, CantGetControlData); 

    data->instrument.userFloat[kconstForce1].value = CFStringGetDoubleValue (parameterA_text);

	// printf( "%f\n", data->instrument.userFloat[kconstForce1].value );

	CFRelease (parameterA_text);

	CantSetControlData:
	CantGetControlData:
	CantGetControl:
	return err;
}

static pascal OSStatus CF1DialogUpdate ( void* dataRef)
{
	int i;
	ControlID ctrlID;
	ControlRef ctrlRef; 
	CFStringRef textRef;
	OSStatus err = noErr;
	pData data = (pData) dataRef;

	if (!IsValidWindowPtr(pWindowList[kWindowRefCF1]))
		return -1;

	ctrlID.signature = 'ENTR';
	ctrlID.id = 128;
		
	err = GetControlByID (pWindowList[kWindowRefCF1], &ctrlID, &ctrlRef);
	require_noerr_quiet (err, CantGetControl); 

	textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
		data->instrument.userFloat[kconstForce1].value);
															
	err = SetControlData (	ctrlRef, 0, kControlEditTextCFStringTag, 
										sizeof(CFStringRef), &textRef);
	require_noerr_quiet (err, CantSetControlData);
			
	DrawOneControl (ctrlRef);
	
	CantSetControlData:
	CantGetControl:
	return err;
}

static pascal OSStatus CF2DialogEventHandler( EventHandlerCallRef myHandler, EventRef event, void* userData )
{
	OSStatus	err = noErr;
	WindowRef	window = NULL;
	OSStatus	result = eventNotHandledErr;
	UInt32		class = GetEventClass( event );
	UInt32		kind = GetEventKind( event );
	HICommand	command;
	int byteID, byteParam, wordID, wordParam, printCnt;
	pData data = (pData) userData;
	
	switch( class ){
		case kEventClassWindow:
			GetEventParameter( event, kEventParamDirectObject, typeWindowRef, NULL,
									sizeof( WindowRef ), NULL, &window );
				require_noerr( err, CantGetParameter );
			switch( kind ){
				case kEventWindowClose:
					SetWRefCon( window, 0 );
					DisposeWindow( window );
					err = noErr;
					break;
				case kEventWindowShown:
					break;
				default:
					err = eventNotHandledErr;
					break;
			}
		break;
	case kEventClassCommand:
		err = GetEventParameter( event, kEventParamDirectObject,
										typeHICommand, NULL, sizeof( HICommand ),
										NULL, &command );
		switch( command.commandID ){
			case 'entr':
				GetCF2Value( data );
				CF2DialogUpdate( data );
				SetUserFocusWindow( kUserFocusAuto );
				SetThemeCursor( kThemeArrowCursor );
				err = noErr;
				break;
			default:
				err = eventNotHandledErr;
				break;
		}
	}
	
	CantGetParameter:
	return err;
}

static pascal OSStatus GetCF2Value( void* dataRef )
{
	OSStatus err = noErr;
	const ControlID kParameterAID = { 'ENTR', 128 };

    ControlRef parameterA;
    CFStringRef parameterA_text;
	 
	pData data = (pData) dataRef;
	 
    err = GetControlByID (pWindowList[kWindowRefCF2], &kParameterAID, &parameterA);
    require_noerr_quiet (err, CantGetControl); 
  
    err = GetControlData (parameterA, 0, kControlEditTextCFStringTag, 
									sizeof(CFStringRef), &parameterA_text, NULL);
    require_noerr (err, CantGetControlData); 

    data->instrument.userFloat[kconstForce2].value = CFStringGetDoubleValue (parameterA_text);

	// printf( "%f\n", data->instrument.userFloat[kconstForce2].value );

	CFRelease (parameterA_text);

	CantSetControlData:
	CantGetControlData:
	CantGetControl:
	return err;
}

static pascal OSStatus CF2DialogUpdate ( void* dataRef)
{
	int i;
	ControlID ctrlID;
	ControlRef ctrlRef; 
	CFStringRef textRef;
	OSStatus err = noErr;
	pData data = (pData) dataRef;

	if (!IsValidWindowPtr(pWindowList[kWindowRefCF2]))
		return -1;

	ctrlID.signature = 'ENTR';
	ctrlID.id = 128;
		
	err = GetControlByID (pWindowList[kWindowRefCF2], &ctrlID, &ctrlRef);
	require_noerr_quiet (err, CantGetControl); 

	textRef = CFStringCreateWithFormat ( NULL, NULL, CFSTR("%0.1f"),
		data->instrument.userFloat[kconstForce2].value);
															
	err = SetControlData (	ctrlRef, 0, kControlEditTextCFStringTag, 
										sizeof(CFStringRef), &textRef);
	require_noerr_quiet (err, CantSetControlData);
			
	DrawOneControl (ctrlRef);
	
	CantSetControlData:
	CantGetControl:
	return err;
}

void disposeCustomUtilWindows( void* dataRef )
{
	OSStatus err = noErr;
	
	if( IsValidWindowPtr( pWindowList[kWindowRefP1]) )
	{
		SetWRefCon( pWindowList[kWindowRefP1], 0);
		DisposeWindow( pWindowList[kWindowRefP1] );
	}
	if( IsValidWindowPtr( pWindowList[kWindowRefP2]) )
	{
		SetWRefCon( pWindowList[kWindowRefP2], 0);
		DisposeWindow( pWindowList[kWindowRefP2] );
	}
	if( IsValidWindowPtr( pWindowList[kWindowRefP3]) )
	{
		SetWRefCon( pWindowList[kWindowRefP3], 0);
		DisposeWindow( pWindowList[kWindowRefP3] );
	}
	
	if( IsValidWindowPtr( pWindowList[kWindowRefCF1]) )
	{
		SetWRefCon( pWindowList[kWindowRefCF1], 0 );
		DisposeWindow( pWindowList[kWindowRefCF1] );
	}
	if( IsValidWindowPtr( pWindowList[kWindowRefCF2]) )
	{
		SetWRefCon( pWindowList[kWindowRefCF2], 0 );
		DisposeWindow( pWindowList[kWindowRefCF2] );
	}
}
//=========================================================================================================ENS


// ---------------------------------
// for custom dialog boxes
static pascal OSStatus DialogEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData)
{	
	OSStatus				err = noErr;	
	WindowRef			window = NULL;
	OSStatus				result = eventNotHandledErr;						//not properly handled for close, fixed, check for others, debug
	UInt32 				class = GetEventClass (event);
	UInt32 				kind = GetEventKind (event);
	HICommand			command;
	int byteID, byteParam, wordID, wordParam, printCnt;
	pData data = (pData) userData;

	//we are post event handling, we call all other event handlers first
	//call next handler, for example if quiting program, flower Q
//	result = CallNextEventHandler(myHandler, event);

//	if (result != eventNotHandledErr)
//		return result;

	switch (class) {
		case kEventClassWindow:
			GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, 
									sizeof(WindowRef), NULL, &window);
				require_noerr (err, CantGetParameter);
			switch (kind) {
				case kEventWindowClose: // called when window is being closed (close box)
					SetWRefCon (window, 0);
					DisposeWindow (window);
					err = noErr;									//should we take this back out, debug					break;
					break;
				case kEventWindowShown: // called when window is being closed (close box)
					break;
				default:
					err = eventNotHandledErr;
					break;
			}
			break;
		case kEventClassCommand:
//			switch (kind) {
//				case kEventProcessCommand:
					err = GetEventParameter (event, kEventParamDirectObject, 
													 typeHICommand,  NULL, sizeof(HICommand), 
													 NULL, &command);
					switch (command.commandID)
					{
						case 'entr':
							GetP1Values (data);
							P1BoxUpdate (data);
							SetUserFocusWindow( kUserFocusAuto );	//ENS
							SetThemeCursor( kThemeArrowCursor );	//ENS
							data->instrument.pathLength = 0;		//SBS
							err = noErr;
							break;
						case 'ntrr':
							GetP2Values (data);
							P2BoxUpdate (data);
							SetUserFocusWindow( kUserFocusAuto );	//ENS
							SetThemeCursor( kThemeArrowCursor );	//ENS
							data->instrument.pathLength = 0;		//SBS
							err = noErr;
							break;
						case 'snrt':
							GetP3Values (data);
							P3BoxUpdate (data);
							SetUserFocusWindow( kUserFocusAuto );	//ENS
							SetThemeCursor( kThemeArrowCursor );	//ENS
							data->instrument.pathLength = 0;		//SBS
							err = noErr;
							break;
						default:
							err = eventNotHandledErr;
							break;
					}
//					break;
//				default:
//					err = eventNotHandledErr;
			break;
//			}
		default:
			err = eventNotHandledErr;
			break;
    }
	 
	CantGetParameter:
	return err;
}



/////////////////////////begin GL window event handling/////////////////

// ---------------------------------
// key input handler calls a function passing a command based on the key map
static pascal OSStatus graphKeyEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData)
{	
	WindowRef			window = NULL;
	OSStatus				result = eventNotHandledErr;
	UInt32 				class = GetEventClass (event);
	UInt32 				kind = GetEventKind (event);
	
	UInt32				keyCode, modifierKeys, command;
	Boolean				upperCase;

	if (class != kEventClassKeyboard)		//error control
		return eventNotHandledErr;

	//we are post event handling, we call all other event handlers first
	//call next handler, for example if quiting program, flower Q
	result = CallNextEventHandler(myHandler, event);
	if (result != eventNotHandledErr)
		return result;
	
	GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, 
							 sizeof(UInt32), NULL, &keyCode);
			
	GetEventParameter (event, kEventParamKeyModifiers,typeUInt32, NULL, 
							 sizeof(UInt32), NULL, &modifierKeys);

	//this switches to openGL specific data container
	pRecContext pContextInfo = GetCurrentContextInfo ((WindowRef) userData);

	//printf (" KeyCode %d", keyCode);	//debug
	
	//checking if keyCode is keyMap array bounds
	if (keyCode >= kKeyMapSize)
	{
		printf("keyCode out of bounds");
		return result;
	}

	command = pContextInfo->data->control.keyMap[kind][keyCode];

	//exit and do not handle graph window keys, values go up from kGraphMenu
	if (command < kGraphMenu)
		return result;
		
	switch (kind) 
	{
		case kEventRawKeyDown:
			break;
		case kEventRawKeyRepeat:
			break;
		case kEventRawKeyUp:
			break;
		default:
			return result;					//exit if other event, ie. hot keys
			break;			
	}
	
	if (!pContextInfo->data->control.commandModifier)		//workaround while menus not responding to command keys, debug
		GraphCommand(command, pContextInfo);	
	
	return noErr;
}



//----------------------------------
static pascal OSStatus windowEventHandler(EventHandlerCallRef myHandler, EventRef event, void* userData)
{
	WindowRef			window = NULL;
	OSStatus				result = eventNotHandledErr;						//not properly handled for close, fixed, check for others, debug
	UInt32 				class = GetEventClass (event);
	UInt32 				kind = GetEventKind (event);

	switch (class) 
	{
		case kEventClassWindow:
			GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window);
			switch (kind)
			{
				case kEventWindowClose: // called when window is being closed (close box)
					HideWindow (window);
					disposeGL (GetCurrentContextInfo(window));		//this should be passed as a function, debug
														//we could have one function that is disposal for all=
// 				DisposePtr ((Ptr) pContextInfo);
					SetWRefCon (window, 0);
//					DisposeWindow (window);
//					result = noErr;
					break;
				case kEventWindowShown: // called on initial show (not on un-minimize)
					// draw content is received prior to this so if you handle that then not drawing required here
					if (window == FrontWindow ())
					SetUserFocusWindow (window);
					break;
			}
	}
	
	return result;
}

//#define kGoldenRatio 1.61803399f
//above works well for Steve's G4

#define kGoldenRatio 1.2f
//above works well for dual G5

//#define kGoldenRatio 1.5f
// hoping tp work on wide screen
	
enum {
		kToolBarHeight = 22,
		kDockSpace = 2,
		kFloatingWindowBarHeight = 18,	 //used by utility and floating window types
		kTrapControlWidth = 193,
		kTrapControlHeight = 318,
		kMotorControlHeight = 194
	};


#pragma mark ---- Window Management ----


//////////////////////////////////////////////////
int UtilityWindow(int windowID, void* data)
{
	int			err;
	OSStatus		result = 0;
	EventHandlerRef	handlerRef;
	EventHandlerUPP eventHandler;
	
												
	EventTypeSpec dialogList[] ={{ kEventClassCommand, kEventCommandProcess },
											{ kEventClassWindow,  kEventWindowClose }};
											
	EventTypeSpec commandList[] ={{ kEventClassCommand, kEventCommandProcess },
											{ kEventClassCommand, kEventProcessCommand },
											{ kEventClassCommand, kEventCommandUpdateStatus }
											};

	EventTypeSpec windowList[] = {{ kEventClassWindow, kEventWindowClose }};			//useful for unlocking specific utility windows from being opened
						
	EventTypeSpec mouseList[] =  {{ kEventClassMouse, kEventMouseDown },
											{ kEventClassMouse, kEventMouseUp },
											{ kEventClassMouse, kEventMouseDragged },
											{ kEventClassMouse, kEventMouseMoved },
											{ kEventClassMouse, kEventMouseWheelMoved }};
		

	//  The name "Window" is set in InterfaceBuilder when the nib is created.
	switch (windowID)
	{
		case kEventWindowTraps:
			if (IsValidWindowPtr(pWindowList[kWindowRefTraps]))			//add message to user and check window bounds if already open, debug
				return 0; 
//			window = pWindowList[kWindowRefTraps];
			err = CreateWindowFromNib(nibRef, CFSTR("Traps"), &pWindowList[kWindowRefTraps]);
				require_noerr (err, CantCreateWindow);
			InstallWindowEventHandler (pWindowList[kWindowRefTraps], MouseEventHandler, 
										GetEventTypeCount (mouseList),
										mouseList, data, &handlerRef);
			UpdateControlWindow (pWindowList[kWindowRefTraps], windowID, data);
			ShowWindow(pWindowList[kWindowRefTraps]);			// The window was created hidden so show it.	
			break;
		case kEventWindowMotors:
			if (IsValidWindowPtr(pWindowList[kWindowRefMotors]))			//add message to user and check window bounds if already open, debug
				return 0;
			err = CreateWindowFromNib(nibRef, CFSTR("Motors"), &pWindowList[kWindowRefMotors]);
			InstallWindowEventHandler (pWindowList[kWindowRefMotors], MouseEventHandler, 
										GetEventTypeCount (mouseList),
										mouseList, data, &handlerRef);
			UpdateControlWindow (pWindowList[kWindowRefMotors], windowID, data);
			ShowWindow (pWindowList[kWindowRefMotors]);			// The window was created hidden so show it.
			break;

		case kEventWindowP1:  // Create P1 window, dispose of P2, P3
			if (IsValidWindowPtr(pWindowList[kWindowRefP1]))			//add message to user and check window bounds if already open, debug
				return 0;
			err = CreateWindowFromNib(nibRef, CFSTR("P1"), &pWindowList[kWindowRefP1]);
			require_noerr (err, CantCreateWindow);
			InstallWindowEventHandler (pWindowList[kWindowRefP1], 
												NewEventHandlerUPP (DialogEventHandler), 
												GetEventTypeCount (dialogList),
												dialogList, data, &handlerRef);
			if( IsValidWindowPtr( pWindowList[kWindowRefP2]) )
			{
				SetWRefCon( pWindowList[kWindowRefP2], 0);
				DisposeWindow( pWindowList[kWindowRefP2] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefP3]) )
			{
				SetWRefCon( pWindowList[kWindowRefP3], 0);
				DisposeWindow( pWindowList[kWindowRefP3] );
			}
			
			
			if( IsValidWindowPtr( pWindowList[kWindowRefCF1]) )	//ENS - very kludgey
			{
				SetWRefCon( pWindowList[kWindowRefCF1], 0);
				DisposeWindow( pWindowList[kWindowRefCF1] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefCF2]) )
			{
				SetWRefCon( pWindowList[kWindowRefCF2], 0 );
				DisposeWindow( pWindowList[kWindowRefCF2] );
			}
			
			ShowWindow (pWindowList[kWindowRefP1]);			// The window was created hidden so show it.
			P1BoxUpdate (data);
			break;

		case kEventWindowP2: // create P2 window, dispose of P1,P3
			if (IsValidWindowPtr(pWindowList[kWindowRefP2]))			//add message to user and check window bounds if already open, debug
				return 0;
			err = CreateWindowFromNib(nibRef, CFSTR("P11"), &pWindowList[kWindowRefP2]);
			require_noerr (err, CantCreateWindow);
			InstallWindowEventHandler (pWindowList[kWindowRefP2], //DialogEventHandler, //restore here
										NewEventHandlerUPP (DialogEventHandler),   //delete here			
										GetEventTypeCount (dialogList),
										dialogList, data, &handlerRef);
												
			if( IsValidWindowPtr( pWindowList[kWindowRefP1]) )
			{
				SetWRefCon( pWindowList[kWindowRefP1], 0);
				DisposeWindow( pWindowList[kWindowRefP1] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefP3]) )
			{
				SetWRefCon( pWindowList[kWindowRefP3], 0);
				DisposeWindow( pWindowList[kWindowRefP3] );
			}
			
			if( IsValidWindowPtr( pWindowList[kWindowRefCF1]) )	//ENS - very kludgey
			{
				SetWRefCon( pWindowList[kWindowRefCF1], 0);
				DisposeWindow( pWindowList[kWindowRefCF1] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefCF2]) )
			{
				SetWRefCon( pWindowList[kWindowRefCF2], 0 );
				DisposeWindow( pWindowList[kWindowRefCF2] );
			}

			ShowWindow (pWindowList[kWindowRefP2]);			// The window was created hidden so show it.
			P2BoxUpdate (data);
			break;
			
		case kEventWindowP3: // create P3 window, dispose of P1, P2
			if (IsValidWindowPtr(pWindowList[kWindowRefP3]))			//add message to user and check window bounds if already open, debug
				return 0;
			err = CreateWindowFromNib(nibRef, CFSTR("P3"), &pWindowList[kWindowRefP3]);
			require_noerr (err, CantCreateWindow);
			InstallWindowEventHandler (pWindowList[kWindowRefP3], //DialogEventHandler, //restore here
									   NewEventHandlerUPP (DialogEventHandler),   //delete here			
									   GetEventTypeCount (dialogList),
									   dialogList, data, &handlerRef);
			
			if( IsValidWindowPtr( pWindowList[kWindowRefP1]) )
			{
				SetWRefCon( pWindowList[kWindowRefP1], 0);
				DisposeWindow( pWindowList[kWindowRefP1] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefP2]) )
			{
				SetWRefCon( pWindowList[kWindowRefP2], 0);
				DisposeWindow( pWindowList[kWindowRefP2] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefCF1]) )	//ENS - very kludgey
			{
				SetWRefCon( pWindowList[kWindowRefCF1], 0);
				DisposeWindow( pWindowList[kWindowRefCF1] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefCF2]) )
			{
				SetWRefCon( pWindowList[kWindowRefCF2], 0 );
				DisposeWindow( pWindowList[kWindowRefCF2] );
			}
			
			ShowWindow (pWindowList[kWindowRefP3]);			// The window was created hidden so show it.
			P3BoxUpdate (data);
			break;
			
		case kEventHoldForce1:
			if( IsValidWindowPtr( pWindowList[kWindowRefCF1]))
				return 0;
			err = CreateWindowFromNib( nibRef, CFSTR( "cF1" ), &pWindowList[kWindowRefCF1] );
			require_noerr( err, CantCreateWindow );
			InstallWindowEventHandler( pWindowList[kWindowRefCF1],
												NewEventHandlerUPP( CF1DialogEventHandler ),
												GetEventTypeCount( dialogList ),
												dialogList, data, &handlerRef );
												
			if( IsValidWindowPtr( pWindowList[kWindowRefP1]) )
			{
				SetWRefCon( pWindowList[kWindowRefP1], 0);
				DisposeWindow( pWindowList[kWindowRefP1] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefP2]) )
			{
				SetWRefCon( pWindowList[kWindowRefP2], 0);
				DisposeWindow( pWindowList[kWindowRefP2] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefP3]) )
			{
				SetWRefCon( pWindowList[kWindowRefP3], 0);
				DisposeWindow( pWindowList[kWindowRefP3] );
			}
			
			if( IsValidWindowPtr( pWindowList[kWindowRefCF2]) )
			{
				SetWRefCon( pWindowList[kWindowRefCF2], 0 );
				DisposeWindow( pWindowList[kWindowRefCF2] );
			}
				
			ShowWindow( pWindowList[kWindowRefCF1] );
			CF1DialogUpdate( data );
			break;
		case kEventHoldForce2:
			if( IsValidWindowPtr( pWindowList[kWindowRefCF2]))
				return 0;
			err = CreateWindowFromNib( nibRef, CFSTR( "cF2" ), &pWindowList[kWindowRefCF2] );
			require_noerr( err, CantCreateWindow );
			InstallWindowEventHandler( pWindowList[kWindowRefCF2],
												NewEventHandlerUPP( CF2DialogEventHandler ),
												GetEventTypeCount( dialogList ),
												dialogList, data, &handlerRef );
			
			if( IsValidWindowPtr( pWindowList[kWindowRefP1]) )
			{
				SetWRefCon( pWindowList[kWindowRefP1], 0 );
				DisposeWindow( pWindowList[kWindowRefP1] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefP2]) )
			{
				SetWRefCon( pWindowList[kWindowRefP2], 0);
				DisposeWindow( pWindowList[kWindowRefP2] );
			}
			if( IsValidWindowPtr( pWindowList[kWindowRefP3]) )
			{
				SetWRefCon( pWindowList[kWindowRefP3], 0);
				DisposeWindow( pWindowList[kWindowRefP3] );
			}
			
			if( IsValidWindowPtr( pWindowList[kWindowRefCF1]) )
			{
				SetWRefCon( pWindowList[kWindowRefCF1], 0 );
				DisposeWindow( pWindowList[kWindowRefCF1] );
			}
			
			ShowWindow( pWindowList[kWindowRefCF2] );
			CF2DialogUpdate( data );
			break;


		default:
			return 0;												//add error reporting, debug
			break;	
	}

	CantCreateWindow:
	return err;
}


// ---------------------------------
void GraphWindow (int graphType, void* dataRef)
{
	short					screenWidth, screenHeight; 
	short					windowLeft, windowTop, windowRight, windowBottom;
	Rect              contentRect, screenRect;
	CFStringRef			windowTitle = NULL;
	WindowRef			window = NULL;
	EventHandlerRef	ref;
	pRecContext			pContextInfo = NULL;
	GDHandle				displayGDHandle;
	OSStatus				result = 0;
	int					cascade = TRUE;
	pData data = (pData) dataRef;
	
	WindowAttributes  windowAttrs =	kWindowStandardDocumentAttributes
											|	kWindowStandardHandlerAttribute 
											|	kWindowInWindowMenuAttribute
											|	kWindowLiveResizeAttribute;

	EventTypeSpec windowList[] ={	{ kEventClassWindow, kEventWindowCollapsing },
											{ kEventClassWindow, kEventWindowShown },
											{ kEventClassWindow, kEventWindowActivated },
											{ kEventClassWindow, kEventWindowClose },
											{ kEventClassWindow, kEventWindowDrawContent },
											{ kEventClassWindow, kEventWindowBoundsChanged },
											{ kEventClassWindow, kEventWindowZoomed } };			//use for going full screen
											
	EventTypeSpec mouseList[] = {	{ kEventClassMouse, kEventMouseDown },
											{ kEventClassMouse, kEventMouseUp },
											{ kEventClassMouse, kEventMouseDragged },
											{ kEventClassMouse, kEventMouseMoved }  };
		
	EventTypeSpec keyList[] = {	{ kEventClassKeyboard, kEventRawKeyDown },
											{ kEventClassKeyboard, kEventRawKeyUp },
											{ kEventClassKeyboard, kEventRawKeyRepeat } };

	//gets the size of the main display in pixels, useful for calculating layout
	displayGDHandle = GetMainDevice();
	result = GetAvailableWindowPositioningBounds (displayGDHandle, &screenRect);	//need error checking, deubg
	
//		result = GetWindowGreatestAreaDevice (window, kWindowStructureRgn, &deviceGDHandle, &screenRect);	//maybe useful, debug
	screenWidth = screenRect.right - screenRect.left;
	screenHeight = screenRect.bottom - screenRect.top;
		
	windowLeft = screenRect.left;
	windowTop = screenRect.top + kToolBarHeight;
	windowRight = screenWidth - kTrapControlWidth;
	windowBottom = screenRect.top + kTrapControlHeight + kMotorControlHeight 
						+ kFloatingWindowBarHeight + kFloatingWindowBarHeight 
						//+0; // fits laptop screen
						+ 150;	//Fits Samsung960 screen
						//+250;	//fits CMV square screen
	
	switch (graphType)
	{
		case kGraphDefault:
			break;
		case kGraphForcePosition:
			break;
		case kGraphForceTime:
			break;
		case kGraphExtensionTime:
			break;
		case kGraphOscilloscope:
			break;
		case kGraphFourier:
			break;
		case kGraphForceVelocity:	
			break;
		case kGraphMotorLever:		//SBS
			break;
		case kGraphLeverLever:		//SBS
			break;
		case kGraphHopping:			//SBS
			break;
		case kGraphIntensityMap:	//SBS
			break;
		case kGraphDualForce:		//SBS
			break;
//---------------------------------- all above are big windows with default properties ------------------
		case kGraphNetForce:
			cascade = FALSE;
			windowTop = windowBottom + kToolBarHeight;
			windowBottom = screenRect.bottom;
			windowLeft = screenRect.left;
			windowRight = (screenWidth / 2)
							 - (int)(kGoldenRatio * (float)(windowBottom - windowTop));
			break;
		case kGraphPSD:
			cascade = FALSE;
			windowTop = windowBottom + kToolBarHeight;
			windowBottom = screenRect.bottom;
			windowLeft = (screenWidth / 2) 
							 - (int)(kGoldenRatio * (float)(windowBottom - windowTop));
			windowRight = windowLeft + screenWidth / 4;
			break;
		case kGraphLever:
			cascade = FALSE;
			windowTop = windowBottom + kToolBarHeight;
			windowBottom =  screenRect.bottom;
			windowLeft = ((screenWidth * 3) / 4) 
							 - (int)(kGoldenRatio * (float)(windowBottom - windowTop));
			windowRight = windowLeft + screenWidth / 4;
			break;
		case kGraphMap:
			cascade = FALSE;
			windowTop = windowBottom + kToolBarHeight;
			windowBottom = screenRect.bottom;
			windowLeft = screenWidth 
							 - (int)(kGoldenRatio * (float)(windowBottom - windowTop));
			windowRight = screenWidth;
			break;
	}
	
	SetRect (&contentRect, windowLeft,  windowTop, windowRight, windowBottom);
	
	switch (graphType)
	{
		case kGraphDefault:
			windowTitle = CFSTR("Graph");
			break;
		case kGraphForcePosition:
			windowTitle = CFSTR("Force vs Position");
			break;
		case kGraphForceTime:
			windowTitle = CFSTR("Force vs Time");
			break;
		case kGraphExtensionTime:
			windowTitle = CFSTR("Extension vs Time");
			break;
		case kGraphOscilloscope:
			//windowTitle = CFSTR("Oscilloscope");ENS
			windowTitle = CFStringCreateWithCString( NULL, data->instrument.deviceName, NULL );
			break;
		case kGraphFourier:
			windowTitle = CFSTR("Fourier");
			break;
		case kGraphNetForce:
			windowTitle = CFSTR("Force");
			break;
		case kGraphPSD:
			windowTitle = CFSTR("PSD");
			break;
		case kGraphLever:
			windowTitle = CFSTR("Light Lever");
			break;
		case kGraphMap:
			windowTitle = CFSTR("Map");
			break;
		case kGraphForceVelocity:		//JMH
			windowTitle = CFSTR("Drag Force vs Motor Velocity");
			break;
		case kGraphMotorLever:		//SBS
			windowTitle = CFSTR("Light Levers vs Motor Position");
			break;
		case kGraphLeverLever:		//SBS
			windowTitle = CFSTR("distanceA(x,y) vs distanceB(x,y)");
			break;
		case kGraphHopping:		//SBS
			windowTitle = CFSTR("Hopping");
			break;
		case kGraphIntensityMap:		//SBS
			windowTitle = CFSTR("Intensity Map");
			break;
		case kGraphDualForce:
			windowTitle = CFSTR("Dual Forces vs. Distances");
		default:
			windowTitle = CFSTR("Graph");
			break;
	}

	CreateNewWindow (kDocumentWindowClass, windowAttrs, &contentRect, &window);
		
	if (window)
	{
		//memory for graph window record
		pContextInfo = (pRecContext) NewPtrClear (sizeof (recContext));
		InitRecContext(graphType, pContextInfo, data);
		SetWRefCon (window, (long) pContextInfo); // point to the window record in the ref con of the window/

		InstallWindowEventHandler (window, windowEventHandler, GetEventTypeCount (windowList), windowList, (void*)window, &ref);
//		InstallWindowEventHandler (window, mouseEventHandler, GetEventTypeCount (mouseList), mouseList, (void*)window, &ref); // add event handler
		InstallWindowEventHandler (window, graphKeyEventHandler, GetEventTypeCount (keyList), keyList, (void*)window, &ref); // add event handler

		if (!pContextInfo->timer) 
		{
			pContextInfo->time = UpTime ();
			InstallEventLoopTimer (GetCurrentEventLoop(), 0, 0.016667, getTimerUPP (), (void *) window, &pContextInfo->timer);
		}
		
		SetThemeWindowBackground ( window, kThemeBrushBlack , FALSE);
	
		if (windowTitle)					//probably don't need the if,				   debug
			SetWindowTitleWithCFString (window, windowTitle); 

		if (cascade)
			RepositionWindow (window, NULL, kWindowCascadeOnMainScreen);						//debug

		ShowWindow (window);
	}
	
//	CFRelease (windowTitle);				//causes crash if when closing 5 windows?					debug
//	CFRelease (window);							//should release window and add proper error handling, debug

	getCurrentCaps ();									//may want to do this elsewhere, debug
}
/////////////////////////end GL window event handling///////////////////



//////////////////////////////////////////////////
int UpdateControlWindow (WindowRef window, int windowID, void *dataRef)
{
	OSStatus				result = 0, err;
	short					width, height;
	Rect					windowRect, boundsRect;
	GDHandle				displayGDHandle;
	const ControlID	kTrapSliderID = { 'ctrl', 18 };
	const ControlID	kMotorSliderID = { 'ctrl', 194 };
	const ControlID kGotoSliderID = {'ctrl', 200 };		//ENS
	ControlRef			controlRef;
	pData data = (pData) dataRef;
	
//	screenRect = (*GetMainDevice())->gdRect;	 //this how we get the display size
	displayGDHandle = GetMainDevice();
	result = GetAvailableWindowPositioningBounds (displayGDHandle, &boundsRect);	//need error checking, deubg
	
	GetWindowBounds (window, kWindowStructureRgn, &windowRect);	//gets window position

	height = windowRect.bottom - windowRect.top;
	width = windowRect.right - windowRect.left;

	switch (windowID)
	{
		case kEventWindowTraps:
			windowRect.top = boundsRect.top;
			windowRect.bottom = windowRect.top + height;
		
			err = GetControlByID (pWindowList[kWindowRefTraps], &kTrapSliderID, &controlRef);
				require_noerr_quiet (err, CantGetControl);
			SetControl32BitValue (controlRef, data->control.mouseTrapSensitivity);
			break;
		case kEventWindowMotors:
			err = GetControlByID (pWindowList[kWindowRefMotors], &kMotorSliderID, &controlRef);
				require_noerr_quiet (err, CantGetControl);
			SetControl32BitValue (controlRef, data->control.mouseMotorSensitivity);
			
			err = GetControlByID( pWindowList[kWindowRefMotors], &kGotoSliderID, &controlRef );	//ENS
				require_noerr_quiet( err, CantGetControl );
			SetControl32BitValue( controlRef, data->control.mouseMotorSensitivity );
			break;
	}
	
	if (windowRect.right > boundsRect.right)
	{
		windowRect.left = boundsRect.right - width;
		windowRect.right = boundsRect.right;
	}
	
	if (windowRect.bottom > boundsRect.bottom)
	{
		windowRect.top = boundsRect.top - width;
		windowRect.bottom = boundsRect.right;
	}

	SetWindowBounds (window, kWindowStructureRgn, &windowRect);	//sets window position, debug
	
	CantGetControl:
	return err;
}


//////////////////////////////////////////////////
int MakeWindow(int windowID, void* data)
{
	switch (windowID)
	{
		case kEventWindowForceVsPosition:
			GraphWindow(kGraphForcePosition, data);
			break;
		case kEventWindowExtensionVsTime:
			GraphWindow(kGraphExtensionTime, data);
			break;
		case kEventWindowForceVsTime:
			GraphWindow(kGraphForceTime, data);
			break;
		case kEventWindowLever:
			GraphWindow(kGraphLever, data);
			break;
		case kEventWindowPSD: 
			GraphWindow(kGraphPSD, data);
			break;
		case kEventWindowNetForce:
			GraphWindow(kGraphNetForce, data);
			break;
		case kEventWindowOscilloscope:
			GraphWindow(kGraphOscilloscope, data);
			break;
		case kEventWindowFourier:
			GraphWindow(kGraphFourier, data);
			break;
		case kEventWindowMap:
			GraphWindow(kGraphMap, data);
			break;	
		case kEventWindowChannels:
			CreateChannelsWindow(data);
			break;
		case kEventOpenHelpWindow:	//ENS
			CreateHelpWindow( data );
			break;
		default:
			UtilityWindow(windowID, data);
			break;
		case kEventWindowStokesLawTest:					//JMH
			GraphWindow(kGraphForceVelocity, data);
			break;
		case kEventWindowMotorLever:		//SBS
			GraphWindow(kGraphMotorLever, data);
			break;
		case kEventWindowLeverLever:		//SBS
			GraphWindow(kGraphLeverLever, data);
			break;
		case kEventWindowHopping:		//SBS
			GraphWindow(kGraphHopping, data);
			break;
		case kEventWindowIntensityMap:		//SBS
			GraphWindow(kGraphIntensityMap, data);
			break;
		case kEventWindowDualForce:	//SBS
			GraphWindow(kGraphDualForce, data);
			break;
			
	}																//merge the GL event handler, debug

	return 0;
}


//////////////////////////////////////////////////
int InitNib(void* data)
{
	int err;
	
    // Create a Nib reference passing the name of the nib file (without the .nib extension)
    // CreateNibReference only searches into the application bundle.
	err = CreateNibReference(CFSTR("main"), &nibRef);
	require_noerr (err, CantGetNibRef);
    
    // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar
    // object. This name is set in InterfaceBuilder when the nib is created.
	err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
	require_noerr (err, CantSetMenuBar);

	CantSetMenuBar:
	CantGetNibRef:
	return err;
}

//////////////////////////////////////////////////
int InitEvents (void* data)
{
	int err;
	EventHandlerUPP	eventHandler;
	EventHandlerRef	handlerRef;
	EventLoopTimerUPP eventLoopTimer;
	EventLoopTimerRef timerRef = NULL;
	
	EventTypeSpec list[] = {	{ kEventClassCommand,  kEventCommandProcess },
										{ kEventClassCommand,  kEventProcessCommand },
										{ kEventClassCommand,  kEventCommandUpdateStatus }};
													
	EventTypeSpec keyList[] = {{ kEventClassKeyboard, kEventRawKeyDown },
										{ kEventClassKeyboard, kEventRawKeyUp },
										{ kEventClassKeyboard, kEventRawKeyRepeat },
										{ kEventClassKeyboard, kEventRawKeyModifiersChanged }};
	
	 // processes NIB events for menubar, motor control and trap control windows
	eventHandler = NewEventHandlerUPP (AppEventHandler);
	err = InstallApplicationEventHandler (eventHandler, GetEventTypeCount (list), 
													  list, data, &handlerRef);
	require_noerr (err, CantInstallAppEventHandler);
		
	 // default keyboard handler for global commands, not window specific
	eventHandler = NewEventHandlerUPP (AppKeyEventHandler);
	err = InstallApplicationEventHandler (eventHandler, GetEventTypeCount (keyList),
													  keyList, data, &handlerRef);														
	require_noerr (err, CantInstallKeyEventHandler);
		
	 // 60Hz timer for updating communications, GUI, and other functions
	eventLoopTimer = NewEventLoopTimerUPP (IdleTimer);
   InstallEventLoopTimer (GetCurrentEventLoop(), 0, 0.0166, 
								  eventLoopTimer, data, &timerRef);
	require_noerr (err, CantInstallEventLoopTimer);
	
	CantInstallAppEventHandler:
	CantInstallKeyEventHandler:
	CantInstallEventLoopTimer:
	return err;
}


//////////////////////////////////////////////
void CloseNib(void* data)
{   
	DisposeNibReference(nibRef); 
}


//////////////////////////////////////////////
void CloseEvents(void* data)
{
/*																				//should be part of individual handlers, debug
	if (timerRef)
		RemoveEventLoopTimer(timerRef);
	timerRef = NULL;
*/
}







#pragma mark ---- Thread Management ----


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//Multiprocesser pre-emptive threading
//we use a static list to keep track of all threads in the program, threads
//can be made and destroyed dynamically,
//
//please see the "Multiprocessing Services Reference," multiproc_ref.pdf at
//http://developer.apple.com/documentation/Carbon/Reference/Multiprocessing_Services/index.html
////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////
//the task function that is always used when creating a new thread
int MPTaskFunction(void* data)
{
	int err;
	
	int threadID = currentID;
	
		//calls the function passed to MakeThread passing it a pointer to data
		//the function unlocks currentID
	err = (*pThreadList[threadID]->pFunction)(data);
	
	MPNotifyQueue (pThreadList[threadID]->resultQueue, 0, 0, 0);

	printf("Graceful exit, thread number %d\n", threadID);

	MPExit(err);	//graceful exit, updates notification queue
	
	return err;
}


//////////////////////////////////////////////
int MakeThread(int (*pFunction) (void*), void* data)
{
	int err = 0, i;
	
	if (lockCurrentID == 0)
		lockCurrentID = 1;					//lock the thread manager
	else
		return 1002;							//error 1002 threadManagerLocked, debug
	
	for (i = 0; i < kThreadListSize; i++)
		if (pThreadList[currentID] != 0)
				currentID = i;					//assign first empty spot to newID

	if (pThreadList[currentID] != 0)
	{
		lockCurrentID = 0;
		return 1003;							//error 1003 threadLimit, debug
	}
	
													//allocate memory for pThreadList
	pThreadList[currentID] = (pThreadRef) NewPtrClear (sizeof (ThreadRef));

	pThreadList[currentID]->data = data;
	pThreadList[currentID]->pFunction = pFunction;
	pThreadList[currentID]->killThread = 0;
	
	if( MPLibraryIsLoaded() ) {			//if library present then create thread

		err = MemError();

		if( err == 0 )
			err = MPCreateQueue(&pThreadList[currentID]->notificationQueue);
		if( err == 0 )
			err = MPCreateQueue(&pThreadList[currentID]->requestQueue);
		if( err == 0 )
			err = MPCreateQueue(&pThreadList[currentID]->resultQueue);
		if( err == 0 )
			err = MPCreateTask(	(TaskProc)MPTaskFunction,	//the task function
										data,								//our data
										kMPStackSize,
										pThreadList[currentID]->notificationQueue,
										0, 
										0, 
										kMPTaskOptions,
										&pThreadList[currentID]->taskID );
	}

	lockCurrentID = 0;		//unlock the thread manager, should wait for task Function to get its ID debug
		
	return err;
}


//////////////////////////////////////////////
// will kill the thread specificed by threadID
int StopThread(int threadID)
{
	int err;
	pThreadList[threadID]->killThread = TRUE;

	//give read loop 1500ms to terminate itself, otherwise kill it, may lock up port if killed
	err = MPWaitOnQueue(	pThreadList[threadID]->notificationQueue, 0, 0, 0, 
								kDurationMillisecond*1500);
	
	if(pThreadList[threadID]->taskID != NULL) //and the task still exists
	{
		err = MPTerminateTask(pThreadList[threadID]->taskID, 0); // tell the OS to kill the task

		err = MPWaitOnQueue(pThreadList[threadID]->notificationQueue, 0, 0, 0, kDurationMillisecond*1500); // and wait until the OS says it's dead up to 1.5 seconds
	}

	if (pThreadList[threadID]->requestQueue != 0)
	{
		MPDeleteQueue(pThreadList[threadID]->requestQueue);
		pThreadList[threadID]->requestQueue = 0;
	}

	if (pThreadList[threadID]->resultQueue != 0)
	{
		MPDeleteQueue (pThreadList[threadID]->resultQueue);
		pThreadList[threadID]->resultQueue = 0;
	}

	if (pThreadList[threadID]->notificationQueue != 0)
	{
		MPDeleteQueue (pThreadList[threadID]->notificationQueue);
		pThreadList[threadID]->notificationQueue = 0;
	}
	
	pThreadList[threadID] = 0;						// should have deallocate here, debug
	return err;
}


//////////////////////////////////////////////
void InitThreads(void* data)
{
	int i;
	
	currentID = 0;
	lockCurrentID = 0;
	
	for (i = 0; i < kThreadListSize; i++)			//need dynamic list size, debug
		pThreadList[i] = NULL;
}


//////////////////////////////////////////////
int CloseThreads(void* data)
{
	int err = 0, firstErr = 0, i;
	
	for (i = 0; i < kThreadListSize; i++)
	{
		if (pThreadList[i] != 0)
		{
			err = StopThread(i);
			if (err)
				printf ("\n CloseThreads error number: %d   thread number: %d \n", err, i);
		}

		if (err && firstErr == 0)
			firstErr = err;
	}
	
	if (firstErr)
		return firstErr;
	
	return err;
}


//////////////////////////////////////////////
int ThreadCurrentID()
{
	return currentID;
}


//////////////////////////////////////////////
int ThreadKillThread(int threadID)
{
	if (threadID >= 0 && threadID < kThreadListSize)
		return (pThreadList[threadID]->killThread);
	
	return 1;			//return kill thread true if passed out of bounds threadID, debug error
}


//////////////////////////////////////////////
void ThreadLockCurrentID(int locked)
{
	lockCurrentID = locked;
}

