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

//=====================================================================================
// Generic includes for Macintosh headers
//=====================================================================================

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

//=====================================================================================
// Includes specific to this module
//=====================================================================================

#include "SlideShowOptions.h"

static Boolean IsValidSlideOptionsDrag(DragReference theDragRef, HFSFlavor *theFile);
static pascal OSErr SlideOptionsDragTracker(DragTrackingMessage message,
			WindowPtr theWindow, void *handlerRefCon, DragReference theDragRef);
static pascal OSErr SlideOptionsDragReceiver(WindowPtr theWindow,
			void *handlerRefCon, DragReference theDragRef);

//=====================================================================================
// Global variables local to this module
//=====================================================================================

static DialogPtr gSlideOptionsDialog = nil;
static UserItemUPP gSlideOptionsUser = nil;
static DragTrackingHandlerUPP gSlideOptionsDragTracker = nil;
static DragReceiveHandlerUPP gSlideOptionsDragReceiver = nil;
static SlideOptions gOldOptions;
static FSSpec gSlideSpec;

/*
 * OpenSlideOptions()
 *
 *     Purpose: Opens the slide show dialog window
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
OSErr OpenSlideOptions(void)
{
	OSErr theErr = noErr;
	Str255 theTime;
	short i;
	
	if (gSlideOptionsDialog) {
		if (!WindowVisible(gSlideOptionsDialog)) FWShowWindow(gSlideOptionsDialog);
		return noErr;
	}
	gOldOptions = **gSlideOptions;
	gSlideSpec.vRefNum = gSlideSpec.parID = *gSlideSpec.name = 0;
	GetSlideSpec(&gSlideSpec);
	if (!(gSlideOptionsDialog = AllocateDialog())) return gIntError = errNoMemory, memFullErr;
	StartSpinning();
	PushPort();
	MySetPort(nil);
	if (gSlideOptionsDialog = FWGetNewDialog(rSlideShowDialog, (Ptr)gSlideOptionsDialog, (WindowPtr)-1)) {
		if (gDragMgrPresent) {
			if (!gSlideOptionsDragTracker) {
				gSlideOptionsDragTracker = NewDragTrackingHandlerProc((ProcPtr)SlideOptionsDragTracker);
				gSlideOptionsDragReceiver = NewDragReceiveHandlerProc((ProcPtr)SlideOptionsDragReceiver);
			}
			InstallTrackingHandler(gSlideOptionsDragTracker, gSlideOptionsDialog, 0);
			InstallReceiveHandler(gSlideOptionsDragReceiver, gSlideOptionsDialog, 0);
		}
		SetItemHandle(gSlideOptionsDialog, slideOutlineUser, (Handle)gOutlineOK);
		SetItemHandle(gSlideOptionsDialog, slideLeftBoxUser, (Handle)gPopUpMenuBox);
		SetItemHandle(gSlideOptionsDialog, slideRightBoxUser, (Handle)gPopUpMenuBox);
		if (!gSlideOptionsUser)
			gSlideOptionsUser = NewUserItemProc((ProcPtr)SlideOptionsUser);
		SetItemHandle(gSlideOptionsDialog, slideFolderUser, (Handle)gSlideOptionsUser);
		i = (*gSlideOptions)->delay;
		if (i && !(i % 3600)) {
			SetDCtlValue(gSlideOptionsDialog, slideTimePopUpMenu, timeHours);
			i /= 3600;
		} else if (i && !(i % 60)) {
			SetDCtlValue(gSlideOptionsDialog, slideTimePopUpMenu, timeMinutes);
			i /= 60;
		} else SetDCtlValue(gSlideOptionsDialog, slideTimePopUpMenu, timeSeconds);
		NumToString(i, theTime);
		SetDIText(gSlideOptionsDialog, slideDelayEdit, theTime);
		SelIText(gSlideOptionsDialog, slideDelayEdit, 0, 255);
		UpdateSlideOptionsButtons();
		PlaceWindow(gSlideOptionsDialog, &gThePrefs.slideBounds, CenterWindow(gSlideOptionsDialog));
	} else gIntError = errNoMemory, theErr = memFullErr, DeallocateDialog(gSlideOptionsDialog);
	PopPort();
	StopSpinning(&qd.arrow);
	return theErr;
}

/*
 * CloseSlideOptions()
 *
 *     Purpose: Closes the slide show dialog window
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
void CloseSlideOptions(void) 
{
	PushPort();
	MySetPort(nil);
	if (gSlideOptionsDialog) {
		SaveWindowPosition(gSlideOptionsDialog, &gThePrefs.slideBounds);
		if (gDragMgrPresent) {
			RemoveTrackingHandler(gSlideOptionsDragTracker, gSlideOptionsDialog);
			RemoveReceiveHandler(gSlideOptionsDragReceiver, gSlideOptionsDialog);
		}
		FWCloseDialog(gSlideOptionsDialog);
		DisposeHandle(((DialogPeek)gSlideOptionsDialog)->items);
		DeallocateDialog(gSlideOptionsDialog);
	}
	gSlideOptionsDialog = nil;
	PopPort();
	ChangeActive(FWFrontWindow());
}

/*
 * GetSlideOptionsWindow()
 *
 *     Purpose: Returns a pointer to the slide show dialog
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
WindowPtr GetSlideOptionsWindow(void)
{
	return (WindowPtr)gSlideOptionsDialog;
}

extern OSErr GetSlideSpec(FSSpec *theSpec)
{
	AliasHandle theAlias;
	OSErr theErr = noErr;
	Boolean needsUpdate;
	short count = 1;
	
	theErr = LoadPrefsHandle(kPrefsAliasType, 0, (Handle *)&theAlias);
	if (theErr == noErr) {
		theErr = MatchAlias(nil, kARMSearch + kARMSearchMore + kARMNoUI, theAlias,
					&count, (FSSpecArrayPtr)theSpec, &needsUpdate, nil, 0);
		if (!count) theErr = fnfErr;
		DisposeHandle((Handle)theAlias);
	}
	if (theErr != noErr) theErr = GetDeskFolderSpec(theSpec, kOnSystemDisk);
	return theErr;
}

/*
 * HandleSlideOptionsEvent(theItem)
 *
 *     Purpose: Handles events coming in for the slide dialog
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
void HandleSlideOptionsEvent(short theItem)
{
	AliasHandle theAlias;
	Str255 theTime;
	FSSpec theSpec;
	OSErr theErr;
	short val;
	
	switch (theItem) {
		case kDialogClose:
			GetDIText(gSlideOptionsDialog, slideDelayEdit, theTime);
			StringToNum(theTime, &(*gSlideOptions)->delay);
			val = GetDCtlValue(gSlideOptionsDialog, slideTimePopUpMenu);
			if (val == timeHours) (*gSlideOptions)->delay *= 3600;
			else if (val == timeMinutes) (*gSlideOptions)->delay *= 60;
			SavePrefsHandle(kPrefsSlideType, 0, (Handle)gSlideOptions);
			theErr = NewAlias(nil, &gSlideSpec, &theAlias);
			if (theErr == noErr) {
				SavePrefsHandle(kPrefsAliasType, 0, (Handle)theAlias);
				DisposeHandle((Handle)theAlias);
			}
			gSlideFolderValid = (GetSlideSpec(&theSpec) == noErr);
			CloseSlideOptions();
			return;
		case kDialogOK:
		case slideBeginButton:
			SendCloseWindow(gSlideOptionsDialog);
			if (gSlideShow) ReinitSlideShow(&gOldOptions);
			else SendSlideShow();
			return;
		case kDialogCancel:
		case slideRevertButton:
			**gSlideOptions = gOldOptions;
			break;
		case slideControlMenu:
			if (GetDCtlValue(gSlideOptionsDialog, slideControlMenu) == slideControlUserItem)
				(*gSlideOptions)->userControl = true;
			else (*gSlideOptions)->userControl = false;
			AdjustMenus();
			break;
		case slideRandomBox:
			(*gSlideOptions)->random = !(*gSlideOptions)->random;
			break;
		case slideRepeatBox:
			(*gSlideOptions)->repeat = !(*gSlideOptions)->repeat;
			break;
		case slideIgnoreErrBox:
			(*gSlideOptions)->noErrors = !(*gSlideOptions)->noErrors;
			break;
		case slideHideWindoidsBox:
			(*gSlideOptions)->hideWindoids = !(*gSlideOptions)->hideWindoids;
			break;
		case slideHideControlsBox:
			(*gSlideOptions)->hideControls = !(*gSlideOptions)->hideControls;
			break;
		case slideAutoCommentsBox:
			(*gSlideOptions)->autoComments = !(*gSlideOptions)->autoComments;
			break;
		case slideSourceMenu:
			if (GetDCtlValue(gSlideOptionsDialog, slideSourceMenu) == slideSourceMemoryItem)
				(*gSlideOptions)->fromMemory = true;
			else (*gSlideOptions)->fromMemory = false;
			break;
		case slideSelectButton:
			theSpec = gSlideSpec;
			EnableItem(GetMHandle(rAppleMenu), 1);
			if (StandardGetFolder(&theSpec)) gSlideSpec = theSpec;
			DisableItem(GetMHandle(rAppleMenu), 1);
			UpdateDialogItem(gSlideOptionsDialog, slideFolderUser);
			break;
		case slideRecursiveBox:
			(*gSlideOptions)->recursive = !(*gSlideOptions)->recursive;
			break;
		case slideImportBox:
			(*gSlideOptions)->allFiles = !(*gSlideOptions)->allFiles;
			break;
		case slideFilenamesBox:
			(*gSlideOptions)->fileNames = !(*gSlideOptions)->fileNames;
			break;
		case slideOffscreenBox:
			(*gSlideOptions)->offscreen = !(*gSlideOptions)->offscreen;
			break;
	}
	UpdateSlideOptionsButtons();
	return;
}

/*
 * HandleSlideOptionsKey(theChar, theKey)
 *
 *     Purpose: Handles key down events in the slide show dialog
 *      Inputs: theChar = the ASCII representation of the character
 *				theKey = the key code of the key pressed
 *     Returns: nothing
 *
 */

Boolean HandleSlideOptionsKey(char theChar)
{
	if (theChar == kTabChar) SelIText(gSlideOptionsDialog, slideDelayEdit, 0, 255);
	else if (((theChar >= '0') && (theChar <= '9')) || 
		(theChar < ' ') || (theChar > '~')) return false;
	else SysBeep(6);
	return true;
}

/*
 * UpdateSlideOptionsButtons()
 *
 *     Purpose: Updates the status of the various buttons on the slide show dialog
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
void UpdateSlideOptionsButtons(void) 
{
	ControlHandle theControl;
	FSSpec theSpec;
	Str31 oldTitle;
	short itemType;
	Rect itemRect;
	OSErr theErr;
	
	if (gSlideShow) {
		GetDItem(gSlideOptionsDialog, slideBeginButton, &itemType, (Handle *)&theControl, &itemRect);
		GetCTitle(theControl, oldTitle);
		if (!EqualString(oldTitle, gString[strResume], true, true))
			SetCTitle(theControl, gString[strResume]);
	} else {
		if (!(*gSlideOptions)->fromMemory)
			theErr = FSMakeFSSpec(gSlideSpec.vRefNum, gSlideSpec.parID,
						gSlideSpec.name, &theSpec);
		if (((*gSlideOptions)->fromMemory && !gImageRoot) ||
			(!(*gSlideOptions)->fromMemory && ((theErr != noErr) || !gSlideSpec.name[0]))) 
			DisableDControl(gSlideOptionsDialog, slideBeginButton);
		else EnableDControl(gSlideOptionsDialog, slideBeginButton);
		OutlineOK(gSlideOptionsDialog, slideOutlineUser);
	}
	if (!(*gSlideOptions)->userControl) {
		SetDCtlValue(gSlideOptionsDialog, slideControlMenu, slideControlAutoItem);
		EnableDControl(gSlideOptionsDialog, slideDelayText);
		EnableDControl(gSlideOptionsDialog, slideDelayEdit);
		EnableDControl(gSlideOptionsDialog, slideTimePopUpMenu);
	} else {
		SetDCtlValue(gSlideOptionsDialog, slideControlMenu, slideControlUserItem);
		DisableDControl(gSlideOptionsDialog, slideDelayText);
		DisableDControl(gSlideOptionsDialog, slideDelayEdit);
		DisableDControl(gSlideOptionsDialog, slideTimePopUpMenu);
	}
	if (gSlideShow) DisableDControl(gSlideOptionsDialog, slideRandomBox);
	else EnableDControl(gSlideOptionsDialog, slideRandomBox);
	SetDCtlValue(gSlideOptionsDialog, slideRandomBox, (*gSlideOptions)->random);
	SetDCtlValue(gSlideOptionsDialog, slideRepeatBox, (*gSlideOptions)->repeat);
	SetDCtlValue(gSlideOptionsDialog, slideIgnoreErrBox, (*gSlideOptions)->noErrors);
	SetDCtlValue(gSlideOptionsDialog, slideHideControlsBox, (*gSlideOptions)->hideControls);
	SetDCtlValue(gSlideOptionsDialog, slideHideWindoidsBox, (*gSlideOptions)->hideWindoids);
	SetDCtlValue(gSlideOptionsDialog, slideFilenamesBox, (*gSlideOptions)->fileNames);
	SetDCtlValue(gSlideOptionsDialog, slideAutoCommentsBox, (*gSlideOptions)->autoComments);
	if (gSlideShow) DisableDControl(gSlideOptionsDialog, slideSourceMenu);
	if ((*gSlideOptions)->fromMemory) {
		SetDCtlValue(gSlideOptionsDialog, slideSourceMenu, slideSourceMemoryItem);
		DisableDControl(gSlideOptionsDialog, slideSelectButton);
		DisableDControl(gSlideOptionsDialog, slideRecursiveBox);
		DisableDControl(gSlideOptionsDialog, slideImportBox);
		DisableDControl(gSlideOptionsDialog, slideOffscreenBox);
		SetDCtlValue(gSlideOptionsDialog, slideRecursiveBox, false);
		SetDCtlValue(gSlideOptionsDialog, slideImportBox, false);
		SetDCtlValue(gSlideOptionsDialog, slideOffscreenBox, false);
	} else {
		SetDCtlValue(gSlideOptionsDialog, slideSourceMenu, slideSourceDiskItem);
		if (gSlideShow) {
			DisableDControl(gSlideOptionsDialog, slideSelectButton);
			DisableDControl(gSlideOptionsDialog, slideRecursiveBox);
			DisableDControl(gSlideOptionsDialog, slideImportBox);
		} else {
			EnableDControl(gSlideOptionsDialog, slideSelectButton);
			EnableDControl(gSlideOptionsDialog, slideRecursiveBox);
			EnableDControl(gSlideOptionsDialog, slideImportBox);
		}
		SetDCtlValue(gSlideOptionsDialog, slideRecursiveBox, (*gSlideOptions)->recursive);
		SetDCtlValue(gSlideOptionsDialog, slideImportBox, (*gSlideOptions)->allFiles);
		EnableDControl(gSlideOptionsDialog, slideOffscreenBox);
		SetDCtlValue(gSlideOptionsDialog, slideOffscreenBox, (*gSlideOptions)->offscreen);
	}
	SlideOptionsUser(gSlideOptionsDialog, slideFolderUser);
}

/*
 * SlideUser(theDialog, theItem)
 *
 *     Purpose: Draws the name of the currently selected directory
 *      Inputs: theDialog = dialog pointer to the slide show dialog
 *				theItem = the item number of interest
 *     Returns: nothing
 *
 */
 
pascal void SlideOptionsUser(DialogPtr theDialog, short theItem) 
{
	Handle itemHandle, thePath;
	short itemType, length;
	Str255 theString;
	FSSpec theSpec;
	Rect itemRect;
	
	PushPort();
	MySetPort((CGrafPtr)theDialog);
	TextFont(systemFont);
	TextSize(12);
	TextMode((*gSlideOptions)->fromMemory ? grayishTextOr : srcCopy);
	GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
	if (GetDeskFolderSpec(&theSpec, gSlideSpec.vRefNum) == noErr && SameFile(&gSlideSpec, &theSpec)) {
		theString[0] = 0;
		AddString(theString, gString[strDesktop]);
	} else if (GetFullPath(&gSlideSpec, &thePath) == noErr && gSlideSpec.name[0]) {
		HLock(thePath);
		length = GetHandleSize(thePath);
		TruncText(Width(&itemRect), *thePath, &length, smTruncMiddle);
		BlockMove(*thePath, &theString[1], length);
		theString[0] = length;
		DisposeHandle(thePath);
	} else {
		theString[0] = 0;
		AddString(theString, gString[strSSNone]);
	}
	EraseRect(&itemRect);
	MoveTo(itemRect.left + ((Width(&itemRect) - StringWidth(theString)) >> 1), 
			itemRect.bottom - 5);
	DrawString(theString);
	TextMode(srcCopy);
	PopPort();
}

static Boolean IsValidSlideOptionsDrag(DragReference theDragRef, HFSFlavor *theFile)
{
	Size theSize = sizeof(HFSFlavor);
	ItemReference theItem;
	ushort count;
	OSErr theErr;
	
	theErr = CountDragItems(theDragRef, &count);
	if (theErr == noErr && count == 1) {
		theErr = GetDragItemReferenceNumber(theDragRef, 1, &theItem);
		if (theErr == noErr) {
			theErr = GetFlavorData(theDragRef, theItem, flavorTypeHFS, theFile, &theSize, 0);
			if (theErr == noErr && (
						theFile->fileType == 'fold' ||
						theFile->fileType == 'disk' ||
						theFile->fileType == 'fdrp' ||
						theFile->fileType == 'trsh' ||
						theFile->fileType == 'hdsk' ||
						theFile->fileType == 'flpy' ||
						theFile->fileType == 'srvr' ||
						theFile->fileType == 'drop' ||
						theFile->fileType == 'fasy' ||
						theFile->fileType == 'faam' ||
						theFile->fileType == 'fast' ||
						theFile->fileType == 'fapn' ||
						theFile->fileType == 'fapf' ||
						theFile->fileType == 'fact' ||
						theFile->fileType == 'faex' ||
						theFile->fileType == 'faet' ||
						theFile->fileType == 'fash' ||
						theFile->fileType == 'famn'))
				return true;
		}
	}
	return false;
}

static pascal OSErr SlideOptionsDragTracker(DragTrackingMessage message,
			WindowPtr theWindow, void *handlerRefCon, DragReference theDragRef)
{
#if applec
#pragma unused(handlerRefCon)
#endif
	HFSFlavor theFile;
	
	if (message == dragTrackingEnterWindow || message == dragTrackingLeaveWindow)
		if (IsValidSlideOptionsDrag(theDragRef, &theFile)) {
			RgnHandle theRgn = NewRgn();
			if (theRgn) {
				RectRgn(theRgn, &theWindow->portRect);
				if (message == dragTrackingEnterWindow)
					ShowDragHilite(theDragRef, theRgn, true);
				else if (message == dragTrackingLeaveWindow)
					HideDragHilite(theDragRef);
				DisposeRgn(theRgn);
			}
		}
	return noErr;
}

static pascal OSErr SlideOptionsDragReceiver(WindowPtr theWindow,
			void *handlerRefCon, DragReference theDragRef)
{
#if applec
#pragma unused(theWindow, handlerRefCon)
#endif
	Boolean wasAliased, isFolder;
	HFSFlavor theFile;
	OSErr theErr;
	
	if (IsValidSlideOptionsDrag(theDragRef, &theFile)) {
		theErr = ResolveAliasFile(&theFile.fileSpec, true, &isFolder, &wasAliased);
		if (theErr == noErr && isFolder) {
			gSlideSpec = theFile.fileSpec;
			UpdateDialogItem(gSlideOptionsDialog, slideFolderUser);
			return noErr;
		}
	}
	return dragNotAcceptedErr;
}
