//////////
//
//	File:		QTMovieTrack.c
//
//	Contains:	Sample code for working with QuickTime movie tracks.
//
//	Written by:	Tim Monroe
//
//	Copyright:	© 2000 by Apple Computer, Inc., all rights reserved.
//
//	Change History (most recent first):
//	   
//	   <4>	 	05/11/00	rtm		made a few UI tweaks
//	   <3>	 	05/08/00	rtm		added child rectangle previewing button
//	   <2>	 	05/06/00	rtm		added user interface for specifying options
//	   <1>	 	05/04/00	rtm		first file
//
//
//	This sample code shows how to add a "movie track" to an existing QuickTime movie; a movie track
//	is a track that specifies another movie that is to be embedded into the existing movie. The existing
//	movie will be called the "parent movie" or the "containing movie"; the embedded movie will be called
//	the "child movie", the "embedded movie", or the "movie-in-movie".
//
//	A movie track is added using standard Movie Toolbox routines. The sample description is generic. The
//	media sample data consists of an atom container that contains one or more child atoms. The child atom
//	of type kMovieMediaDataReference is required. All other child atoms are optional. The movie media
//	handler will use intelligent default values for any missing atoms.
//
//////////


//////////
//
// header files
//
//////////

#include "QTMovieTrack.h"


//////////
//
// global variables
//
//////////

extern short 				gAppResFile;						// file reference number for this application's resource file
extern ModalFilterUPP		gModalFilterUPP;					// UPP to our custom dialog event filter

RGBColor					gWhite = {0xffff, 0xffff, 0xffff};
RGBColor					gDGray = {0x7777, 0x7777, 0x7777};
RGBColor					gBlack = {0x0000, 0x0000, 0x0000};


//////////
//
// QTMIM_AddFileAsMovieTrack
// Elicit a movie file from the user and add it to a parent movie as a child movie.
//
//////////

OSErr QTMIM_AddFileAsMovieTrack (WindowObject theWindowObject)
{
	FSSpec					myFSSpec;
	OSType 					myTypeList[] = {kQTFileTypeMovie};
	short					myNumTypes = 1;
	QTFrameFileFilterUPP	myFileFilterUPP = NULL;
	AliasHandle				myAlias = NULL;
	OSErr					myErr = noErr;

#if TARGET_OS_MAC
	myNumTypes = 0;
#endif
	// elicit a movie file from the user
	myFileFilterUPP = QTFrame_GetFileFilterUPP((ProcPtr)QTMIM_FilterFiles);

	myErr = QTFrame_GetOneFileWithPreview(myNumTypes, (QTFrameTypeListPtr)myTypeList, &myFSSpec, myFileFilterUPP);
	if (myErr != noErr)
		goto bail;

	// create an alias to the selected file
	myErr = NewAliasMinimal(&myFSSpec, &myAlias);
	if (myErr != noErr)
		goto bail;

	// add the movie file as a movie track to the parent movie
	myErr = QTMIM_AddMovieTrack(theWindowObject, rAliasType, (Handle)myAlias);

bail:
	if (myFileFilterUPP != NULL)
		DisposeNavObjectFilterUPP(myFileFilterUPP);

	if (myAlias != NULL)
		DisposeHandle((Handle)myAlias);

	return(myErr);
}


//////////
//
// QTMIM_AddURLAsMovieTrack
// Elicit a URL from the user and add it to a parent movie as a child movie.
//
//////////

OSErr QTMIM_AddURLAsMovieTrack (WindowObject theWindowObject)
{
	char			*myURL = NULL;
	Handle			myHandle = NULL;
	Size			mySize = 0;
	OSErr			myErr = noErr;

	// elicit a URL from the user
	myURL = QTMIM_GetURLFromUser();
	if (myURL == NULL)
		goto bail;
		
	// get the size of the URL, plus the terminating null byte
	mySize = (Size)strlen(myURL) + 1;
	if (mySize == 0)
		goto bail;
	
	// allocate a new handle
	myHandle = NewHandleClear(mySize);
    if (myHandle == NULL)
		goto bail;

	// copy the URL into the handle
	BlockMove(myURL, *myHandle, mySize);

	// add the URL as a movie track to the parent movie
	myErr = QTMIM_AddMovieTrack(theWindowObject, URLDataHandlerSubType, myHandle);

bail:
	free(myURL);
	
	if (myHandle != NULL)
		DisposeHandle(myHandle);

	return(myErr);
}


//////////
//
// QTMIM_AddMovieTrack
// Add, to the specified parent movie, a movie track for the movie having the specified data reference.
//
//////////

OSErr QTMIM_AddMovieTrack (WindowObject theWindowObject, OSType theDataRefType, Handle theDataRef)
{
	Movie			 		myMovie = NULL;			// the parent movie
	Track					myTrack = NULL;			// the movie track
	Media					myMedia = NULL;			// the movie track's media
	OSErr					myErr = paramErr;
	
	if ((theWindowObject == NULL) || (theDataRef == NULL))
		goto bail;
		
	myMovie = (**theWindowObject).fMovie;
		
	// create the movie track and media
	myTrack = NewMovieTrack(myMovie, FixRatio(kChildMovieWidth, 1), FixRatio(kChildMovieHeight, 1), kFullVolume);
	myErr = GetMoviesError();
	if (myErr != noErr)
		goto bail;
		
	myMedia = NewTrackMedia(myTrack, MovieMediaType, kMovieTimeScale, NULL, 0);
	myErr = GetMoviesError();
	if (myErr != noErr)
		goto bail;

	// create the media sample(s)
	myErr = BeginMediaEdits(myMedia);
	if (myErr != noErr)
		goto bail;

	myErr = QTMIM_AddMovieTrackSampleToMedia(theWindowObject, myMedia, theDataRefType, theDataRef);
	if (myErr != noErr)
		goto bail;

	myErr = EndMediaEdits(myMedia);
	if (myErr != noErr)
		goto bail;
	
	// add the media to the track
	myErr = InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);

bail:
	return(myErr);
}


//////////
//
// QTMIM_AddMovieTrackSampleToMedia
// Add a sample to the specified media.
//
//////////

OSErr QTMIM_AddMovieTrackSampleToMedia (WindowObject theWindowObject, Media theMedia, OSType theDataRefType, Handle theDataRef)
{
	ApplicationDataHdl			myAppData = NULL;
	QTAtomContainer				mySample = NULL;
	QTAtom						myRegionAtom;
	SampleDescriptionHandle		myImageDesc = NULL;
	Ptr							myData = NULL;
	OSType						myType;
	Boolean						myBoolean;
	UInt8						myLoop;
	UInt32						myValue;
	OSErr						myErr = paramErr;
	
	//////////
	//
	// retrieve the application data; it determines what kind of atoms we create
	//
	//////////
	
	myAppData = (ApplicationDataHdl)QTFrame_GetAppDataFromWindowObject(theWindowObject);
	if (myAppData == NULL)
		return(myErr);

	//////////
	//
	// create a new atom container and add an atom of type kMovieMediaDataReference
	//
	//////////

	// create a new atom container to hold the sample data
	myErr = QTNewAtomContainer(&mySample);
	if (myErr != noErr)
		goto bail;

	// concatenate the specified data reference type and data reference into a single block of data
	myData = NewPtrClear(sizeof(OSType) + GetHandleSize(theDataRef));
	if (myData == NULL)
		goto bail;
	
	// convert the data to big-endian format
	myType = EndianU32_NtoB(theDataRefType);
	
	BlockMove(&myType, myData, sizeof(OSType));
	BlockMove(*theDataRef, myData + sizeof(OSType), GetHandleSize(theDataRef));
	
	// add an atom of type kMovieMediaDataReference to the atom container
	myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaDataReference, 1, 1, GetPtrSize(myData), myData, NULL);
	if (myErr != noErr)
		goto bail;

	//////////
	//
	// add an auto-start atom
	//
	//////////

	myBoolean = (**myAppData).fAutoPlayChild;
	myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaAutoPlay, 1, 1, sizeof(myBoolean), &myBoolean, NULL);
	if (myErr != noErr)
		goto bail;
	
	//////////
	//
	// add a frame-stepping atom
	//
	//////////

	myBoolean = (**myAppData).fFrameStepChild;
	myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaEnableFrameStepping, 1, 1, sizeof(myBoolean), &myBoolean, NULL);
	if (myErr != noErr)
		goto bail;
	
	//////////
	//
	// add a looping atom, if requested
	//
	//////////

	if ((**myAppData).fLoopingOn) {
		// add an atom of type kMovieMediaLoop to the atom container
		myLoop = (**myAppData).fLoopingState;
		myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaLoop, 1, 1, sizeof(myLoop), &myLoop, NULL);
		if (myErr != noErr)
			goto bail;
	}
	
	//////////
	//
	// set the slaving characteristics of the child movie
	//
	//////////
	
	myBoolean = (**myAppData).fSlaveTimebase;
	myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaSlaveTime, 1, 1, sizeof(myBoolean), &myBoolean, NULL);
	if (myErr != noErr)
		goto bail;
	
	myBoolean = (**myAppData).fSlaveAudio;
	myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaSlaveAudio, 1, 1, sizeof(myBoolean), &myBoolean, NULL);
	if (myErr != noErr)
		goto bail;
	
	myBoolean = (**myAppData).fSlaveGraphicsMode;
	myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaSlaveGraphicsMode, 1, 1, sizeof(myBoolean), &myBoolean, NULL);
	if (myErr != noErr)
		goto bail;

	myBoolean = (**myAppData).fSlaveDuration;
	myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaSlaveTrackDuration, 1, 1, sizeof(myBoolean), &myBoolean, NULL);
	if (myErr != noErr)
		goto bail;
	
	//////////
	//
	// set the spatial characteristics of the child movie, if requested
	//
	//////////

	if ((**myAppData).fCustomRectOn || (**myAppData).fScalingOn) {
		// add an atom of type kMovieMediaRegionAtom to the atom container
		myErr = QTInsertChild(mySample, kParentAtomIsContainer, kMovieMediaRegionAtom, 1, 1, 0, NULL, &myRegionAtom);
		if (myErr != noErr)
			goto bail;
	}
	
	if (myRegionAtom != 0) {
		
		if ((**myAppData).fCustomRectOn) {
			// set the child movie's rectangle
			QTAtom			myRectAtom;
			
			myErr = QTInsertChild(mySample, myRegionAtom, kMovieMediaRectangleAtom, 1, 1, 0, NULL, &myRectAtom);
			if (myRectAtom != 0) {
				if ((**myAppData).fTopAndLeftOn) {
					myValue = EndianU32_NtoB((**myAppData).fTop);
					myErr = QTInsertChild(mySample, myRectAtom, kMovieMediaTop, 1, 1, sizeof(myValue), &myValue, NULL);
				
					myValue = EndianU32_NtoB((**myAppData).fLeft);
					myErr = QTInsertChild(mySample, myRectAtom, kMovieMediaLeft, 1, 1, sizeof(myValue), &myValue, NULL);
				}
				
				if ((**myAppData).fHeightAndWidthOn) {
					myValue = EndianU32_NtoB((**myAppData).fHeight);
					myErr = QTInsertChild(mySample, myRectAtom, kMovieMediaHeight, 1, 1, sizeof(myValue), &myValue, NULL);
				
					myValue = EndianU32_NtoB((**myAppData).fWidth);
					myErr = QTInsertChild(mySample, myRectAtom, kMovieMediaWidth, 1, 1, sizeof(myValue), &myValue, NULL);
				}
			}
		}
		
		// set the scaling characteristics of the child movie
		if ((**myAppData).fScalingOn) {
			// add an atom of type kMovieMediaSpatialAdjustment to the atom container
			myValue = EndianU32_NtoB((**myAppData).fScalingType);
			myErr = QTInsertChild(mySample, myRegionAtom, kMovieMediaSpatialAdjustment, 1, 1, sizeof(myValue), &myValue, NULL);
			if (myErr != noErr)
				goto bail;
		}
	}
	
	//////////
	//
	// create the media sample
	//
	//////////

	// create a sample description
	myImageDesc = (SampleDescriptionHandle)NewHandleClear(sizeof(SampleDescription));
	if (myImageDesc == NULL)
		goto bail;

	(**myImageDesc).descSize = sizeof(SampleDescription);
	(**myImageDesc).dataFormat = MovieMediaType;

	myErr = AddMediaSample(	theMedia, 
							mySample,
							0,																	// no offset in data
							GetHandleSize((Handle)mySample), 
							GetMovieDuration(GetTrackMovie(GetMediaTrack(theMedia))),			// frame duration
							myImageDesc, 
							1,																	// one sample
							0,																	// self-contained samples
							NULL);

bail:
	if (myData != NULL)
		DisposePtr(myData);

	if (myImageDesc != NULL)
		DisposeHandle((Handle)myImageDesc);

	if (mySample != NULL)
		QTDisposeAtomContainer(mySample);

	return(myErr);
}


//////////
//
// QTMIM_GetURLFromUser
// Display a dialog box to elicit a URL from the user; return a C string that contains the text in the
// dialog box when the user clicks the OK button; otherwise, return NULL.
//
// The caller is responsible for disposing of the pointer returned by this function (by calling free).
//
//////////

char *QTMIM_GetURLFromUser (void)
{
	short 			myItem;
	short 			mySavedResFile;
	GrafPtr			mySavedPort;
	DialogPtr		myDialog = NULL;
	short			myItemKind;
	Handle			myItemHandle;
	Rect			myItemRect;
	Str255			myString;
	char			*myURL = NULL;
	OSErr			myErr = noErr;

	//////////
	//
	// save the current resource file and graphics port
	//
	//////////

	mySavedResFile = CurResFile();
	GetPort(&mySavedPort);

	// set the application's resource file
	UseResFile(gAppResFile);

	//////////
	//
	// create the dialog box in which the user will enter a URL
	//
	//////////

	myDialog = GetNewDialog(kURLBoxResourceID, NULL, (WindowPtr)-1L);
	if (myDialog == NULL)
		goto bail;

#if TARGET_API_MAC_CARBON		
	SetPortDialogPort(myDialog);
#else
	MacSetPort(myDialog);
#endif
	
	SetDialogDefaultItem(myDialog, kURLBoxItemOK);
	SetDialogCancelItem(myDialog, kURLBoxItemCancel);
	
	MacShowWindow(GetDialogWindow(myDialog));
	
	//////////
	//
	// display and handle events in the dialog box until the user clicks OK or Cancel
	//
	//////////
	
	do {
		ModalDialog(gModalFilterUPP, &myItem);
	} while ((myItem != kURLBoxItemOK) && (myItem != kURLBoxItemCancel));
	
	//////////
	//
	// handle the selected button
	//
	//////////
	
	if (myItem != kURLBoxItemOK) {
		myErr = userCanceledErr;
		goto bail;
	}
	
	// retrieve the edited text
	GetDialogItem(myDialog, kURLBoxItemEditBox, &myItemKind, &myItemHandle, &myItemRect);
	GetDialogItemText(myItemHandle, myString);
	myURL = QTUtils_ConvertPascalToCString(myString);
	
bail:
	// restore the previous resource file and graphics port
	MacSetPort(mySavedPort);
	UseResFile(mySavedResFile);
	
	if (myDialog != NULL)
		DisposeDialog(myDialog);

	return(myURL);
}


//////////
//
// QTMIM_ShowPropertiesDialogBox
// Display the Movie Track Properties dialog box and process the user's selections.
//
//////////

OSErr QTMIM_ShowPropertiesDialogBox (WindowObject theWindowObject)
{
	ApplicationDataHdl		myAppData = NULL;
	short 					myItem;
	short 					mySavedResFile;
	GrafPtr					mySavedPort;
	DialogPtr				myDialog = NULL;
	short					myItemKind;
	Handle					myItemHandle;
	Rect					myItemRect;
	SInt16					myValue;
	SInt16					myIndex;
	Str255					myString;
	UserItemUPP				myUserItemProcUPP = NULL;			// UPP to our custom dialog user item procedure
	OSErr					myErr = paramErr;
		
	if (theWindowObject == NULL)
		return(myErr);

	myAppData = (ApplicationDataHdl)QTFrame_GetAppDataFromWindowObject(theWindowObject);
	if (myAppData == NULL)
		return(myErr);
		
	myUserItemProcUPP = NewUserItemUPP(QTMIM_UserItemProcedure);

	//////////
	//
	// save the current resource file and graphics port
	//
	//////////

	mySavedResFile = CurResFile();
	GetPort(&mySavedPort);

	// set the application's resource file
	UseResFile(gAppResFile);

	//////////
	//
	// create the dialog box 
	//
	//////////

	myDialog = GetNewDialog(kPropsBoxResourceID, NULL, (WindowPtr)-1L);
	if (myDialog == NULL)
		goto bail;

	MacSetPort(GetDialogPort(myDialog));
	
	// set user-item procedures
	GetDialogItem(myDialog, kSlaveOptionsUserItem, &myItemKind, &myItemHandle, &myItemRect);
	SetDialogItem(myDialog, kSlaveOptionsUserItem, myItemKind, (Handle)myUserItemProcUPP, &myItemRect);
	
	GetDialogItem(myDialog, kLoopingOptionsUserItem, &myItemKind, &myItemHandle, &myItemRect);
	SetDialogItem(myDialog, kLoopingOptionsUserItem, myItemKind, (Handle)myUserItemProcUPP, &myItemRect);
	
	GetDialogItem(myDialog, kScalingOptionsUserItem, &myItemKind, &myItemHandle, &myItemRect);
	SetDialogItem(myDialog, kScalingOptionsUserItem, myItemKind, (Handle)myUserItemProcUPP, &myItemRect);
	
	GetDialogItem(myDialog, kRectangleOptionsUserItem, &myItemKind, &myItemHandle, &myItemRect);
	SetDialogItem(myDialog, kRectangleOptionsUserItem, myItemKind, (Handle)myUserItemProcUPP, &myItemRect);
	
	GetDialogItem(myDialog, kCommentBoxUserItem, &myItemKind, &myItemHandle, &myItemRect);
	SetDialogItem(myDialog, kCommentBoxUserItem, myItemKind, (Handle)myUserItemProcUPP, &myItemRect);
	
	SetDialogDefaultItem(myDialog, kPropsItemOK);
	SetDialogCancelItem(myDialog, kPropsItemCancel);
	
	// set default values
	GetDialogItem(myDialog, kPropsAutoPlayChild, &myItemKind, &myItemHandle, &myItemRect);
	SetControlValue((ControlHandle)myItemHandle, 0);
	
	GetDialogItem(myDialog, kFrameStepChild, &myItemKind, &myItemHandle, &myItemRect);
	SetControlValue((ControlHandle)myItemHandle, 0);
	
	GetDialogItem(myDialog, kScalingOptionFill, &myItemKind, &myItemHandle, &myItemRect);
	SetControlValue((ControlHandle)myItemHandle, 1);
	
	GetDialogItem(myDialog, kPropsNoLooping, &myItemKind, &myItemHandle, &myItemRect);
	SetControlValue((ControlHandle)myItemHandle, 1);
	
	GetDialogItem(myDialog, kUseTrackBoxRadio, &myItemKind, &myItemHandle, &myItemRect);
	SetControlValue((ControlHandle)myItemHandle, 1);
	
	// disable rectangle specifiers
	GetDialogItem(myDialog, kTopAndLeftCheckBox, &myItemKind, &myItemHandle, &myItemRect);
	HiliteControl((ControlHandle)myItemHandle, 255);
	
	GetDialogItem(myDialog, kHeightAndWidthCheckBox, &myItemKind, &myItemHandle, &myItemRect);
	HiliteControl((ControlHandle)myItemHandle, 255);
	
	GetDialogItem(myDialog, kLoopingOptionsCheckBox, &myItemKind, &myItemHandle, &myItemRect);
	SetControlValue((ControlHandle)myItemHandle, 1);
	
	GetDialogItem(myDialog, kScalingOptionsCheckBox, &myItemKind, &myItemHandle, &myItemRect);
	SetControlValue((ControlHandle)myItemHandle, 1);
	
	MacShowWindow(GetDialogWindow(myDialog));
	
	QTMIM_ShowComment(myDialog, kDefaultCommentItem);
	
	//////////
	//
	// display and handle events in the dialog box until the user clicks OK or Cancel
	//
	//////////
	
	do {
		ModalDialog(gModalFilterUPP, &myItem);
		
		// erase any existing comment
		QTMIM_ShowComment(myDialog, kEraseCommentFieldItem);
		
		switch (myItem) {
			// handle clicks on check boxes
			case kPropsSlaveTimebase:
			case kPropsSlaveAudio:
			case kPropsSlaveGraphicsMode:
			case kPropsSlaveDuration:
			case kPropsAutoPlayChild:
			case kFrameStepChild:
			case kScalingOptionsCheckBox:
			case kTopAndLeftCheckBox:
			case kHeightAndWidthCheckBox:
			case kLoopingOptionsCheckBox:
				GetDialogItem(myDialog, myItem, &myItemKind, &myItemHandle, &myItemRect);
				myValue = 1 - GetControlValue((ControlHandle)myItemHandle);	
				if (myValue == 1)
					QTMIM_ShowComment(myDialog, myItem);
				SetControlValue((ControlHandle)myItemHandle, myValue);
				
				if (myItem == kScalingOptionsCheckBox) {
					myValue = GetControlValue((ControlHandle)myItemHandle);	
				
					for (myIndex = kScalingOptionClip; myIndex <= kScalingOptionScroll; myIndex++) {
						GetDialogItem(myDialog, myIndex, &myItemKind, &myItemHandle, &myItemRect);
						HiliteControl((ControlHandle)myItemHandle, myValue ? 0 : 255);
					}
				}
				
				if (myItem == kLoopingOptionsCheckBox) {
					myValue = GetControlValue((ControlHandle)myItemHandle);	
				
					for (myIndex = kPropsNoLooping; myIndex <= kPropsPalindromeLooping; myIndex++) {
						GetDialogItem(myDialog, myIndex, &myItemKind, &myItemHandle, &myItemRect);
						HiliteControl((ControlHandle)myItemHandle, myValue ? 0 : 255);
					}
				}
				
				break;
				
			// handle clicks in radio button groups
			case kPropsNoLooping:
			case kPropsNormalLooping:
			case kPropsPalindromeLooping:
				for (myIndex = kPropsNoLooping; myIndex <= kPropsPalindromeLooping; myIndex++) {
					GetDialogItem(myDialog, myIndex, &myItemKind, &myItemHandle, &myItemRect);
					if (myItem == myIndex)
						SetControlValue((ControlHandle)myItemHandle, 1);	
					else
						SetControlValue((ControlHandle)myItemHandle, 0);	
				}
				
				QTMIM_ShowComment(myDialog, myItem);
				break;
				
			case kScalingOptionClip:
			case kScalingOptionFill:
			case kScalingOptionMeet:
			case kScalingOptionSlice:
			case kScalingOptionScroll:
				for (myIndex = kScalingOptionClip; myIndex <= kScalingOptionScroll; myIndex++) {
					GetDialogItem(myDialog, myIndex, &myItemKind, &myItemHandle, &myItemRect);
					if (myItem == myIndex)
						SetControlValue((ControlHandle)myItemHandle, 1);	
					else
						SetControlValue((ControlHandle)myItemHandle, 0);	
				}
				
				QTMIM_ShowComment(myDialog, myItem);
				break;
				
			case kUseTrackBoxRadio:
			case kUseRectangleRadio:
				for (myIndex = kUseTrackBoxRadio; myIndex <= kUseRectangleRadio; myIndex++) {
					GetDialogItem(myDialog, myIndex, &myItemKind, &myItemHandle, &myItemRect);
					if (myItem == myIndex)
						SetControlValue((ControlHandle)myItemHandle, 1);	
					else
						SetControlValue((ControlHandle)myItemHandle, 0);
						
					GetDialogItem(myDialog, kUseRectangleRadio, &myItemKind, &myItemHandle, &myItemRect);
					myValue = GetControlValue((ControlHandle)myItemHandle);	
				
					// enable or disable rectangle specifiers
					GetDialogItem(myDialog, kTopAndLeftCheckBox, &myItemKind, &myItemHandle, &myItemRect);
					HiliteControl((ControlHandle)myItemHandle, myValue ? 0 : 255);
				
					GetDialogItem(myDialog, kHeightAndWidthCheckBox, &myItemKind, &myItemHandle, &myItemRect);
					HiliteControl((ControlHandle)myItemHandle, myValue ? 0 : 255);
				}
				
				QTMIM_ShowComment(myDialog, myItem);
				break;
				
			// handle clicks in buttons
			case kShowChildOnParent:
				QTMIM_ShowChildRectOnParent(myDialog, theWindowObject);
				break;
		}
		
		// if OK button clicked, make sure we've got all the info we need
		if (myItem == kPropsItemOK) {
			// if "Use Rectangle" is selected, make sure either T/L or H/W is also selected
			GetDialogItem(myDialog, kUseRectangleRadio, &myItemKind, &myItemHandle, &myItemRect);
			if (GetControlValue((ControlHandle)myItemHandle) == 1) {
				Boolean		myTopLeftChecked = false;
				Boolean		myHeightWidthChecked = false;
			
				GetDialogItem(myDialog, kTopAndLeftCheckBox, &myItemKind, &myItemHandle, &myItemRect);
				myTopLeftChecked = (Boolean)GetControlValue((ControlHandle)myItemHandle);

				GetDialogItem(myDialog, kHeightAndWidthCheckBox, &myItemKind, &myItemHandle, &myItemRect);
				myHeightWidthChecked = (Boolean)GetControlValue((ControlHandle)myItemHandle);

				if (!myTopLeftChecked && !myHeightWidthChecked) {
					// show warning and don't exit the dialog box
					QTMIM_ShowComment(myDialog, kNeedTLOrHWItem);
					QTFrame_Beep();
					myItem = kPropsBogusItem;
				}
			}
		}
		
	} while ((myItem != kPropsItemOK) && (myItem != kPropsItemCancel));
	
	//////////
	//
	// handle the selected button
	//
	//////////
	
	if (myItem != kPropsItemOK) {
		myErr = userCanceledErr;
		goto bail;
	}
	
	// read the values from the dialog box items into a data structure
	
	// slaving options
	GetDialogItem(myDialog, kPropsSlaveTimebase, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fSlaveTimebase = GetControlValue((ControlHandle)myItemHandle);

	GetDialogItem(myDialog, kPropsSlaveAudio, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fSlaveAudio = GetControlValue((ControlHandle)myItemHandle);

	GetDialogItem(myDialog, kPropsSlaveGraphicsMode, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fSlaveGraphicsMode = GetControlValue((ControlHandle)myItemHandle);

	GetDialogItem(myDialog, kPropsSlaveDuration, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fSlaveDuration = GetControlValue((ControlHandle)myItemHandle);

	// scaling type
	GetDialogItem(myDialog, kScalingOptionsCheckBox, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fScalingOn = GetControlValue((ControlHandle)myItemHandle);
	if ((**myAppData).fScalingOn) {
		GetDialogItem(myDialog, kScalingOptionClip, &myItemKind, &myItemHandle, &myItemRect);
		if (GetControlValue((ControlHandle)myItemHandle))
			(**myAppData).fScalingType = kMovieMediaFitClipIfNecessary;
			
		GetDialogItem(myDialog, kScalingOptionFill, &myItemKind, &myItemHandle, &myItemRect);
		if (GetControlValue((ControlHandle)myItemHandle))
			(**myAppData).fScalingType = kMovieMediaFitFill;
			
		GetDialogItem(myDialog, kScalingOptionMeet, &myItemKind, &myItemHandle, &myItemRect);
		if (GetControlValue((ControlHandle)myItemHandle))
			(**myAppData).fScalingType = kMovieMediaFitMeet;
			
		GetDialogItem(myDialog, kScalingOptionSlice, &myItemKind, &myItemHandle, &myItemRect);
		if (GetControlValue((ControlHandle)myItemHandle))
			(**myAppData).fScalingType = kMovieMediaFitSlice;
			
		GetDialogItem(myDialog, kScalingOptionScroll, &myItemKind, &myItemHandle, &myItemRect);
		if (GetControlValue((ControlHandle)myItemHandle))
			(**myAppData).fScalingType = kMovieMediaFitScroll;
	} else {
		(**myAppData).fScalingType = kMovieMediaFitNone;
	}

	// looping type
	GetDialogItem(myDialog, kLoopingOptionsCheckBox, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fLoopingOn = GetControlValue((ControlHandle)myItemHandle);
	if ((**myAppData).fLoopingOn) {
		GetDialogItem(myDialog, kPropsNoLooping, &myItemKind, &myItemHandle, &myItemRect);
		if (GetControlValue((ControlHandle)myItemHandle))
			(**myAppData).fLoopingState = kMIMNoLooping;
			
		GetDialogItem(myDialog, kPropsNormalLooping, &myItemKind, &myItemHandle, &myItemRect);
		if (GetControlValue((ControlHandle)myItemHandle))
			(**myAppData).fLoopingState = kMIMNormalLooping;
			
		GetDialogItem(myDialog, kPropsPalindromeLooping, &myItemKind, &myItemHandle, &myItemRect);
		if (GetControlValue((ControlHandle)myItemHandle))
			(**myAppData).fLoopingState = kMIMPalindromeLooping;
	} else {
		(**myAppData).fLoopingState = kMIMNoLooping;
	}

	// autoplay option
	GetDialogItem(myDialog, kPropsAutoPlayChild, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fAutoPlayChild = GetControlValue((ControlHandle)myItemHandle);

	// frame-stepping option
	GetDialogItem(myDialog, kFrameStepChild, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fFrameStepChild = GetControlValue((ControlHandle)myItemHandle);

	// media rectangle
	GetDialogItem(myDialog, kUseRectangleRadio, &myItemKind, &myItemHandle, &myItemRect);
	(**myAppData).fCustomRectOn = GetControlValue((ControlHandle)myItemHandle);
	if ((**myAppData).fCustomRectOn) {
		GetDialogItem(myDialog, kTopAndLeftCheckBox, &myItemKind, &myItemHandle, &myItemRect);
		(**myAppData).fTopAndLeftOn = GetControlValue((ControlHandle)myItemHandle);

		GetDialogItem(myDialog, kHeightAndWidthCheckBox, &myItemKind, &myItemHandle, &myItemRect);
		(**myAppData).fHeightAndWidthOn = GetControlValue((ControlHandle)myItemHandle);

		GetDialogItem(myDialog, kTopEditTextBox, &myItemKind, &myItemHandle, &myItemRect);
		GetDialogItemText(myItemHandle, myString);
		StringToNum(myString, &(**myAppData).fTop);

		GetDialogItem(myDialog, kLeftEditTextBox, &myItemKind, &myItemHandle, &myItemRect);
		GetDialogItemText(myItemHandle, myString);
		StringToNum(myString, &(**myAppData).fLeft);

		GetDialogItem(myDialog, kHeightEditTextBox, &myItemKind, &myItemHandle, &myItemRect);
		GetDialogItemText(myItemHandle, myString);
		StringToNum(myString, &(**myAppData).fHeight);

		GetDialogItem(myDialog, kWidthEditTextBox, &myItemKind, &myItemHandle, &myItemRect);
		GetDialogItemText(myItemHandle, myString);
		StringToNum(myString, &(**myAppData).fWidth);
	}
	
	myErr = noErr;
	
bail:
	// restore the previous resource file and graphics port
	MacSetPort(mySavedPort);
	UseResFile(mySavedResFile);
	
	if (myDialog != NULL)
		DisposeDialog(myDialog);
		
	DisposeUserItemUPP(myUserItemProcUPP);

	return(myErr);
}


//////////
//
// QTMIM_UserItemProcedure
// A user-item procedure to draw boxes.
//
//////////

PASCAL_RTN void QTMIM_UserItemProcedure (DialogPtr theDialog, short theItem)
{
	short					myItemKind;
	Handle					myItemHandle = NULL;
	Rect					myItemRect;
	GrafPtr					mySavedPort;
	PenState				myPenState;
	OSErr					myErr = noErr;
	
	GetPort(&mySavedPort);
#if TARGET_API_MAC_CARBON		
	SetPortDialogPort(theDialog);
#else
	MacSetPort(theDialog);
#endif
	
	// get the rectangle surrounding the user item
	GetDialogItem(theDialog, theItem, &myItemKind, &myItemHandle, &myItemRect);
	
	GetPenState(&myPenState);

	// draw some bevels around the rectangle
	MacOffsetRect(&myItemRect, 1, 1);
	RGBForeColor(&gWhite);
	MacFrameRect(&myItemRect);

	MacOffsetRect(&myItemRect, -1, -1);
	RGBForeColor(&gDGray);
	MacFrameRect(&myItemRect);

	if (theItem == kRectangleOptionsUserItem) {
		RGBForeColor(&gDGray);
		MoveTo(myItemRect.left, myItemRect.top + ((myItemRect.bottom - myItemRect.top) / 2));
		Line((myItemRect.right - myItemRect.left) - 2, 0);
		RGBForeColor(&gWhite);
		MoveTo(myItemRect.left + 1, myItemRect.top + ((myItemRect.bottom - myItemRect.top) / 2) + 1);
		Line((myItemRect.right - myItemRect.left) - 3, 0);
	}

	SetPenState(&myPenState);
	RGBForeColor(&gBlack);

	MacSetPort(mySavedPort);
}


//////////
//
// QTMIM_ShowComment
// Print a comment in the Movie Track Properies dialog box.
//
//////////

void QTMIM_ShowComment (DialogPtr theDialog, short theItem)
{
	short					myTextSize;
	short					myItemKind;
	Handle					myItemHandle = NULL;
	Rect					myItemRect;
	Str255					myString;
	GrafPtr 				mySavedPort;
	OSErr					myErr = noErr;
	
#if TARGET_OS_MAC		
	myTextSize = 10;
#endif
#if TARGET_OS_WIN32		
	myTextSize = 8;
#endif

	GetPort(&mySavedPort);
#if TARGET_API_MAC_CARBON		
	SetPortDialogPort(theDialog);
#else
	MacSetPort(theDialog);
#endif

	GetIndString(myString, kCommentStringResID, theItem);
	
	// get the rectangle surrounding the comment user item
	GetDialogItem(theDialog, kCommentBoxUserItem, &myItemKind, &myItemHandle, &myItemRect);
	MacInsetRect(&myItemRect, 2, 2);
	EraseRect(&myItemRect);
	MacInsetRect(&myItemRect, -2, -2);

	TextSize(myTextSize);
	TextFont(1);
	TextFace(0);
	
	MoveTo(myItemRect.left + 5, myItemRect.bottom - 6);
	DrawString(myString);
	
	TextSize(12);
	TextFont(0);
	TextFace(0);
	
	MacSetPort(mySavedPort);
}


//////////
//
// QTMIM_ShowChildRectOnParent
// Show the currently selected child rectangle on the parent.
//
//////////

void QTMIM_ShowChildRectOnParent (DialogPtr theDialog, WindowObject theWindowObject)
{
	short				myItemKind;
	Handle				myItemHandle = NULL;
	Rect				myItemRect;
	Rect				myChildRect;
	GrafPtr 			mySavedPort;
	MovieController		myMC = NULL;
	
	GetPort(&mySavedPort);
	MacSetPort(QTFrame_GetPortFromWindowReference(QTFrame_GetFrontMovieWindow()));

	myMC = QTFrame_GetMCFromFrontWindow();
	if (myMC == NULL)
		goto bail;
	
	if (theWindowObject == NULL)
		goto bail;
	
	// redraw the current movie frame (to erase any existing child rectangle)
	MCDoAction(myMC, mcActionDraw, (void *)QTFrame_GetWindowFromWindowReference(QTFrame_GetFrontMovieWindow()));
	
	RGBForeColor(&gDGray);
	
	// set the default rectangle
	MacSetRect(&myChildRect, 0, 0, kChildMovieWidth, kChildMovieHeight);

	// get the current child rectangle option
	GetDialogItem(theDialog, kUseTrackBoxRadio, &myItemKind, &myItemHandle, &myItemRect);
	if (GetControlValue((ControlHandle)myItemHandle) == 1) {
		// the "Use Track Box" option is selected; just use the default values defined above
	} else {
		// the "Use Rectangle" option is selected
		Boolean			myTopLeftChecked = false;
		Boolean			myHeightWidthChecked = false;
		Str255			myString;
		long			myPos;
	
		GetDialogItem(theDialog, kTopAndLeftCheckBox, &myItemKind, &myItemHandle, &myItemRect);
		myTopLeftChecked = (Boolean)GetControlValue((ControlHandle)myItemHandle);

		GetDialogItem(theDialog, kHeightAndWidthCheckBox, &myItemKind, &myItemHandle, &myItemRect);
		myHeightWidthChecked = (Boolean)GetControlValue((ControlHandle)myItemHandle);

		if (!myTopLeftChecked && !myHeightWidthChecked) {
			// show warning and don't exit the dialog box
			QTMIM_ShowComment(theDialog, kNeedTLOrHWItem);
			QTFrame_Beep();
			goto bail;
		}

		if (myTopLeftChecked) {
			// get the Top and Left values
			GetDialogItem(theDialog, kTopEditTextBox, &myItemKind, &myItemHandle, &myItemRect);
			GetDialogItemText(myItemHandle, myString);
			StringToNum(myString, &myPos);
			myChildRect.top = (short)myPos;
			myChildRect.bottom += myChildRect.top;

			GetDialogItem(theDialog, kLeftEditTextBox, &myItemKind, &myItemHandle, &myItemRect);
			GetDialogItemText(myItemHandle, myString);
			StringToNum(myString, &myPos);
			myChildRect.left = (short)myPos;
			myChildRect.right += myChildRect.left;
		}
	
		if (myHeightWidthChecked) {
			// get the Height and Width values
			GetDialogItem(theDialog, kHeightEditTextBox, &myItemKind, &myItemHandle, &myItemRect);
			GetDialogItemText(myItemHandle, myString);
			StringToNum(myString, &myPos);
			myChildRect.bottom = myChildRect.top + (short)myPos;

			GetDialogItem(theDialog, kWidthEditTextBox, &myItemKind, &myItemHandle, &myItemRect);
			GetDialogItemText(myItemHandle, myString);
			StringToNum(myString, &myPos);
			myChildRect.right = myChildRect.left + (short)myPos;
		}
	}

	if (!EmptyRect(&myChildRect)) {
		Rect			myMovieRect;
		RgnHandle		myClipRegion = NULL;
		
		// clip the child rectangle to the movie rectangle
		myClipRegion = NewRgn();
		if (myClipRegion != NULL) {
			GetClip(myClipRegion);
			GetMovieBox((**theWindowObject).fMovie, &myMovieRect);
			ClipRect(&myMovieRect);
			PaintRect(&myChildRect);
			SetClip(myClipRegion);
			DisposeRgn(myClipRegion);
		}
		
		QTMIM_ShowComment(theDialog, kShowChildOnParent);
	} else {
		QTMIM_ShowComment(theDialog, kEmptyRectWarning);
		QTFrame_Beep();
	}
		
bail:
	RGBForeColor(&gBlack);
	MacSetPort(mySavedPort);
}


//////////
//
// QTMIM_FilterFiles
// Filter files for a file-opening dialog box.
//
//////////

#if TARGET_OS_MAC
PASCAL_RTN Boolean QTMIM_FilterFiles (AEDesc *theItem, void *theInfo, void *theCallBackUD, NavFilterModes theFilterMode)
{
#pragma unused(theCallBackUD, theFilterMode)
	NavFileOrFolderInfo		*myInfo = (NavFileOrFolderInfo *)theInfo;
	
	if (theItem->descriptorType == typeFSS) {
		if (!myInfo->isFolder) {
			if (myInfo->fileAndFolder.fileInfo.finderInfo.fdType == kQTFileTypeMovie)
				return(true);

			// if we got to here, it's a file we cannot open
			return(false);		
		}
	}
	
	// if we got to here, it's a folder or non-HFS object
	return(true);
}
#endif
#if TARGET_OS_WIN32
PASCAL_RTN Boolean QTMIM_FilterFiles (CInfoPBPtr thePBPtr)
{
#pragma unused(thePBPtr)
	return(false);
}
#endif
