/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information.       */
/* Contact email: mac@aarongiles.com                     */
/*********************************************************/

#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif

//=====================================================================================
// void IsDialogWindow(WindowPtr theWindow)
//
// Returns true if the window is a dialog window.
//
// External calls: none
//=====================================================================================

extern Boolean IsDialogWindow(WindowPtr theWindow)
{
	return theWindow ? (WindowKind(theWindow) == dialogKind) : false;
}

/*
 * CenterWindow(theWindow)
 *
 *     Purpose: Determines where a centered dialog should be placed
 *      Inputs: theWindow = a pointer to the dialog window
 *     Returns: the centered location
 *
 */
 
Point CenterWindow(WindowPtr theWindow) 
{
	short var = GetWVariant(theWindow), height = Height(&theWindow->portRect);
	Point thePos;
	Rect theRect;

	if (var != dBoxProc) height += gTitleBarHeight;	
	switch (gThePrefs.openScreen) {
		case osDeepest:
			GetActiveRect(GetDeepMonitor(gThePrefs.pickColor), &theRect);
			break;
		case osLargest:
			GetActiveRect(GetBigMonitor(gThePrefs.pickColor), &theRect);
			break;
		case osMain:
			GetActiveRect(gMainMonitor, &theRect);
			break;
	}
	thePos.h = Width(&theRect) - Width(&theWindow->portRect);
	thePos.v = Height(&theRect) - height;
	thePos.h /= 2;
	thePos.v /= 3;
	thePos.h += theRect.left;
	thePos.v += theRect.top;
	if (var != dBoxProc) thePos.v += gTitleBarHeight;	
	return thePos;
}

/*
 * GetMouseGDRect(theRect)
 *
 *     Purpose: Gets the Rect of the device where the mouse is
 *      Inputs: theRect = pointer to the rect to be filled
 *     Returns: nothing
 *
 */
 
void GetMouseGDRect(Rect *theRect) 
{
	GDHandle theDevice = GetDeviceList();
	Point thePoint = GlobalMouse();

	*theRect = qd.screenBits.bounds;
	while (theDevice) {
		if (TestDeviceAttribute(theDevice, screenDevice) &&
			TestDeviceAttribute(theDevice, screenActive) &&
			PtInRect(thePoint, &(*theDevice)->gdRect)) {
			*theRect = (*theDevice)->gdRect;
			if (theDevice == GetMainDevice()) theRect->top += GetMBarHeight();
		}
		theDevice = GetNextDevice(theDevice);
	}
}

/*
 * MouseCenterRect(theRect)
 *
 *     Purpose: Centers the given Rect on the screen where the mouse is
 *      Inputs: theRect = pointer to the rect to be filled
 *     Returns: nothing
 *
 */
 
void MouseCenterRect(Rect *theRect)
{
	Point thePoint = GlobalMouse();
	GDHandle theDevice;
	Rect devRect;

	MySetRect(&devRect, thePoint.h, thePoint.v, thePoint.h + 1, thePoint.v + 1);
	theDevice = GetMaxDevice(&devRect);
	if (theDevice) {
		devRect = (*theDevice)->gdRect;
		OffsetRect(theRect, (Width(&devRect) - Width(theRect)) / 2 + devRect.left - theRect->left,
							(Height(&devRect) - Height(theRect)) / 3 + devRect.top - theRect->top);
	}
}

/*
 * CenterAlert(id)
 *
 *     Purpose: Loads and centers the given alert resource
 *      Inputs: id = the resource ID of the alert
 *     Returns: the ID, to be passed to Alert()
 *
 */
 
short CenterAlert(short id)
{
	Handle theHandle = GetResource('ALRT', id);

	if (theHandle) {
		HLock(theHandle);
		MouseCenterRect((Rect *)*theHandle);
		HUnlock(theHandle);
	}
	return id;
}

/*
 * CenterDialog(id)
 *
 *     Purpose: Loads and centers the given dialog resource
 *      Inputs: id = the resource ID of the dialog
 *     Returns: the ID, to be passed to GetNewDialog()
 *
 */
 
short CenterDialog(short id)
{
	Handle theHandle = GetResource('DLOG', id);

	if (theHandle) {
		HLock(theHandle);
		MouseCenterRect((Rect *)*theHandle);
		HUnlock(theHandle);
	}
	return id;
}

/*
 * CenterDialogWhere(id)
 *
 *     Purpose: Loads and centers the given dialog resource
 *      Inputs: id = the resource ID of the dialog
 *     Returns: a point giving the location for the dialog
 *
 */
 
Point CenterDialogWhere(short id)
{
	Handle theHandle = GetResource('DLOG', id);

	if (theHandle) {
		HLock(theHandle);
		MouseCenterRect((Rect *)*theHandle);
		HUnlock(theHandle);
	}
	return *(Point *)*theHandle;
}

extern void UpdateParamText(StringPtr string1, StringPtr string2, StringPtr string3, 
	StringPtr string4)
{
	static Str255 gOldString1 = "", gOldString4 = "";
	WindowPtr theWindow = FWFrontWindow();
	
	ParamText(string1, string2, string3, string4);
	if (theWindow && GetWRefCon(theWindow) == kProgressDialogID) {
		if (!EqualString(string1, gOldString1, true, true))
			UpdateDialogItem(theWindow, progressText);
		if (!EqualString(string4, gOldString4, true, true))
			UpdateDialogItem(theWindow, progressText2);
	}
	BlockMove(string1, gOldString1, *string1 + 1);
	BlockMove(string4, gOldString4, *string4 + 1);
}

extern short HandleDialogLetterKey(DialogPtr theDialog, char theChar)
{
	short itemCount, itemType, theItem;
	Handle itemHandle;
	Str255 theTitle;
	Rect itemRect;
	long ticks;
	
	if (theChar > 'a') theChar -= 'a' - 'A';
	itemCount = CountDITL(theDialog);
	for (theItem = 1; theItem <= itemCount; theItem++) {
		GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
		if (itemType == (ctrlItem + btnCtrl)) {
			GetCTitle((ControlHandle)itemHandle, theTitle);
			if (theChar == theTitle[1]) {
				HiliteControl((ControlHandle)itemHandle, true);
				Delay(8, &ticks);
				HiliteControl((ControlHandle)itemHandle, false);
				return theItem;
			}
		}
	}
	return 0;
}

extern short HandleDialogCancelKey(DialogPtr theDialog)
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;
	long ticks;

	GetDItem(theDialog, 3, &itemType, &itemHandle, &itemRect);
	if (itemType == (ctrlItem + btnCtrl)) {
		HiliteControl((ControlHandle)itemHandle, true);
		Delay(8, &ticks);
		HiliteControl((ControlHandle)itemHandle, false);
		return kDialogCancel;
	}
	return 0;
}

extern short HandleDialogOKKey(DialogPtr theDialog)
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;
	long ticks;

	GetDItem(theDialog, 1, &itemType, &itemHandle, &itemRect);
	if (itemType == (ctrlItem + btnCtrl)) {
		HiliteControl((ControlHandle)itemHandle, true);
		Delay(8, &ticks);
		HiliteControl((ControlHandle)itemHandle, false);
		return kDialogOK;
	}
	return 0;
}

/*
 * GenericFilter(theDialog, theEvent, itemHit)
 *
 *     Purpose: Generic filter returns item 1 for return/enter, and item 3 for Cmd-.
 *      Inputs: theDialog = pointer to the dialog
 *				theEvent = pointer to an event record
 *				itemHit = the item number that was "hit"
 *     Returns: true if we want ModalDialog to continue processing the event
 *
 */
 
pascal Boolean GenericFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit) 
{
	Boolean isCmdKey, isCancelKey, isOKKey, isDialogEvent = IsDialogEvent(theEvent);
	short theItem = 0;
	char theChar;
	
	if ((theEvent->what == updateEvt) && ((WindowPtr)theEvent->message == FWFrontWindow()))
		return false;
	switch (theEvent->what) {
		case activateEvt:
			if (isDialogEvent) HandleActivateDialog(theEvent);
			else HandleActivateEvent(theEvent);
			break;
		case updateEvt:
			if (isDialogEvent) HandleUpdateDialog(theEvent);
			else HandleUpdateEvent(theEvent);
			break;
		case diskEvt:
			HandleDiskEvent(theEvent);
			break;
		case keyDown:
			theChar = theEvent->message & charCodeMask;
			isCmdKey = (theEvent->modifiers & cmdKey) != 0;
			isCancelKey = (theChar == kEscapeChar) || (isCmdKey && theChar == '.');
			isOKKey = (theChar == kReturnChar || theChar == kEnterChar);
			if ((theChar >= 'A' && theChar <= 'Z') || (theChar >= 'a' && theChar <= 'z'))
				theItem = HandleDialogLetterKey(theDialog, theChar);
			else if (isCancelKey) theItem = HandleDialogCancelKey(theDialog);
			else if (isOKKey) theItem = HandleDialogOKKey(theDialog);
			break;
	}
	if (theItem) *itemHit = theItem;
	return (theItem != 0);
}

/*
 * OutlineOK(theDialog, theItem)
 *
 *     Purpose: Generic handler to outline the default (OK) button
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = presumably the item number of the dummy user item
 *     Returns: nothing
 *
 */
 
pascal void OutlineOK(DialogPtr theDialog, short theItem) 
{
	WindowPtr frontWindow = FWFrontWindow();
	RGBColor grayColor, fgColor, bgColor;
	ControlHandle itemHandle;
	short itemType;
	short diameter;
	Rect itemRect;

	PushPort();
	MySetPort((CGrafPtr)theDialog);
	GetDItem(theDialog, theItem - 1, &itemType, (Handle *)&itemHandle, &itemRect);
	if ((diameter = (itemRect.bottom - itemRect.top) / 2) < 16) diameter = 16;
	PenSize(3, 3);
	InsetRect(&itemRect, -4, -4);
	if ((*itemHandle)->contrlHilite == 255 || theDialog != frontWindow || gInBackground) {
		GetBackColor(&bgColor);
		GetForeColor(&fgColor);
		grayColor = fgColor;
		GetGray(GetGDevice(), &bgColor, &grayColor);
		RGBForeColor(&grayColor);
		FrameRoundRect(&itemRect, diameter, diameter);
		RGBForeColor(&fgColor);
	} else FrameRoundRect(&itemRect, diameter, diameter);
	PopPort();
}

extern pascal void PopUpMenuBox(DialogPtr theDialog, short theItem)
{
	RgnHandle minusRgn, oldClip;
	Handle itemHandle;
	short itemType;
	Rect itemRect;
	
	if (minusRgn = NewRgn()) {
		if (oldClip = NewRgn()) {
			GetClip(oldClip);
			ClipRect(&theDialog->portRect);
			GetDItem(theDialog, theItem - 1, &itemType, &itemHandle, &itemRect);
			RectRgn(minusRgn, &itemRect);
			DiffRgn(theDialog->clipRgn, minusRgn, theDialog->clipRgn);
			GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
			PenPat(&qd.gray);
			PenSize(1, 1);
			FrameRect(&itemRect);
			PenPat(&qd.black);
			SetClip(oldClip);
			DisposeRgn(oldClip);
		}
		DisposeRgn(minusRgn);
	}
}

/*
 * LineItem(theDialog, theItem)
 *
 *     Purpose: Generic handler to draw a line in a dialog box
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = presumably the item number of the line item
 *     Returns: nothing
 *
 */
 
pascal void LineItem(DialogPtr theDialog, short theItem) 
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;
	
	PushPort();
	MySetPort((CGrafPtr)theDialog);
	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	PenSize(1, 1);
	MoveTo(itemRect.left, itemRect.top);
	if ((itemRect.right - itemRect.left) < (itemRect.bottom - itemRect.top))
		LineTo(itemRect.left, itemRect.bottom);
	else
		LineTo(itemRect.right, itemRect.top);
	PopPort();
}

/*
 * SetItemHandle(theDialog, theItem, newHandle)
 *
 *     Purpose: Change the handle of a dialog item
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = the item number we're interested in
 *				newHandle = the handle we'd like to change to
 *     Returns: nothing
 *
 */
 
void SetItemHandle(DialogPtr theDialog, short theItem, Handle newHandle)
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;

	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	SetDItem(theDialog, theItem, itemType, newHandle, &itemRect);
}

/*
 * DisableDControl(theDialog, theItem)
 *
 *     Purpose: Disables the control of a particular dialog item
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = the item number we're interested in
 *     Returns: nothing
 *
 */
 
void DisableDControl(DialogPtr theDialog, short theItem)
{
	PenState oldState;
	Handle itemHandle;
	short itemType;
	Rect itemRect;

	PushPort();
	MySetPort((CGrafPtr)theDialog);
	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	itemType &= 0x7f;
	if (itemType == editText || itemType == statText) {
		Boolean bw = !(((CGrafPtr)theDialog)->portVersion & 0x8000) ||
					 (*((CGrafPtr)theDialog)->portPixMap)->pixelSize == 1;
		RGBColor fgColor;
		FontInfo theInfo;
		Str255 theText;

		if (itemRect.left > 8191) OffsetRect(&itemRect, -16384, 0);
		HideDItem(theDialog, theItem);
		GetIText(itemHandle, theText);
		GetFontInfo(&theInfo);
		TextMode(grayishTextOr);
		MoveTo(itemRect.left + 1, itemRect.top + theInfo.ascent);
		DrawString(theText);
		TextMode(srcCopy);
		if (itemType == editText) {
			GetPenState(&oldState);
			PenSize(1, 1);
			PenMode(srcOr);
			if (bw) PenPat(&qd.gray);
			else {
				RGBColor grayColor, bgColor;
				GetBackColor(&bgColor);
				GetForeColor(&fgColor);
				grayColor = fgColor;
				GetGray(GetGDevice(), &bgColor, &grayColor);
				RGBForeColor(&grayColor);
			}
			InsetRect(&itemRect, -3, -3);
			FrameRect(&itemRect);
			if (!bw) RGBForeColor(&fgColor);
			else SetPenState(&oldState);
		}
	} else HiliteControl((ControlHandle)itemHandle, 255);
	PopPort();
}

/*
 * EnableDControl(theDialog, theItem)
 *
 *     Purpose: Enables the control of a particular dialog item
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = the item number we're interested in
 *     Returns: nothing
 *
 */
 
void EnableDControl(DialogPtr theDialog, short theItem)
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;

	PushPort();
	MySetPort((CGrafPtr)theDialog);
	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	itemType &= 0x7f;
	if (itemType == editText || itemType == statText) ShowDItem(theDialog, theItem);
	else HiliteControl((ControlHandle)itemHandle, 0);
	PopPort();
}

/*
 * SetDCtlValue(theDialog, theItem, theValue)
 *
 *     Purpose: Sets the value of the control of a particular dialog item
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = the item number we're interested in
 *				theValue = the new value for that control
 *     Returns: nothing
 *
 */
 
void SetDCtlValue(DialogPtr theDialog, short theItem, short theValue)
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;

	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	SetCtlValue((ControlHandle)itemHandle, theValue);
}

/*
 * GetDCtlValue(theDialog, theItem, theValue)
 *
 *     Purpose: Gets the value of the control of a particular dialog item
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = the item number we're interested in
 *     Returns: the value of the control
 *
 */
 
short GetDCtlValue(DialogPtr theDialog, short theItem)
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;

	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	return GetCtlValue((ControlHandle)itemHandle);
}

/*
 * SetDIText(theDialog, theItem, theText)
 *
 *     Purpose: Sets the text of an editable text dialog item
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = the item number we're interested in
 *				theText = a pointer to the new text
 *     Returns: nothing
 *
 */
 
void SetDIText(DialogPtr theDialog, short theItem, Str255 theText)
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;

	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	SetIText(itemHandle, theText);
}

/*
 * GetDIText(theDialog, theItem, theText)
 *
 *     Purpose: Gets the text of an editable text dialog item
 *      Inputs: theDialog = pointer to the dialog
 *				theItem = the item number we're interested in
 *				theText = a pointer to the text field
 *     Returns: nothing
 *
 */
 
void GetDIText(DialogPtr theDialog, short theItem, Str255 theText)
{
	Handle itemHandle;
	short itemType;
	Rect itemRect;

	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	GetIText(itemHandle, theText);
}

void UpdateDialogItem(DialogPtr theDialog, short theItem)
{
	Handle itemHandle;
	RgnHandle theRgn;
	short itemType;
	Rect itemRect;
	
	if (theRgn = NewRgn()) {
		PushPort();
		MySetPort((CGrafPtr)theDialog);
		GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
		RectRgn(theRgn, &itemRect);
		UpdateDialog(theDialog, theRgn);
		PopPort();
		DisposeRgn(theRgn);
	}
}
