 /*
	File:		GraphicImporter.c

	Written by: Keith Gurganus

	GraphicImporter.exe is a MDI application that demonstates QuickTime graphic import 
	functions. This is a part of the QuickTime sample source code and is provided as is.

  	Copyright:	© 1997 by Apple Computer, Inc., all rights reserved.
*/

#include "QTML.h"
#include "Movies.h"
#include "MacWindows.h"
#include "Resources.h"
#include "ImageCompression.h"
#include "stdwin.h"
#include "resource.h"
#include "TextUtils.h"

// Globals
HINSTANCE	ghModule;
HWND		ghwndMain   = NULL;
HWND		ghwndClient = NULL;
HMENU		hMenu,      hMenuWindow;
HMENU		hChildMenu, hChildMenuWindow; 
int			gMDICount=1;


// Instance data for each MDI child window
typedef struct _PerWndInfo {
    HWND					hParent;
	HWND					hwndChildWindow;
    RECT					rcClient;
	FSSpec					spec;
	OPENFILENAME			ofn;
	GraphicsImportComponent	gi;
	Rect					imageRect;
} INFO, *PINFO;

// Defines
#define USEEXPLORERSTYLE (LOBYTE(LOWORD(GetVersion()))>=4)

// Prototypes
LRESULT CALLBACK MainWndProc     (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK MDIWndProc      (HWND, UINT, WPARAM, LPARAM);
BOOL	CALLBACK About           (HWND, UINT, WPARAM, LPARAM);
BOOL	InitializeApp(void);
BOOL	DoOpen(PINFO pInfo);
BOOL	DoGraphicsImport(PINFO pInfo);
static	UINT APIENTRY GenericHook(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void	ParseCmdLinePriv(LPSTR cmdLine);
BOOL	DoFileOpen(char* fullPathName);

/*
	WinMain
*/
int CALLBACK WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    MSG    msg;
    HANDLE hAccel;

	// Store our module handle
    ghModule = GetModuleHandle(NULL);

	// Initialize QuickTime Media Layer
	InitializeQTML(0);

	// Initialize QuickTime
	EnterMovies();

	// Initialize the app
    if (!InitializeApp()) 
    {
        MessageBox(ghwndMain, "MDI: InitializeApp failure!", "Error", MB_OK);
        return 0;
    }

	// Load our accelerator keys
    if (!(hAccel = LoadAccelerators (ghModule, MAKEINTRESOURCE(ACCEL_ID))))
        MessageBox(ghwndMain, "MDI: Load Accel failure!", "Error", MB_OK);

	// Parse the command line for drag and drop
	ParseCmdLinePriv(NULL);

	// Loop for messages
    while (GetMessage(&msg, NULL, 0, 0)) {
        if (!TranslateAccelerator( ghwndMain, hAccel, &msg) &&
            !TranslateMDISysAccel(  ghwndClient, &msg)          ) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

	// Deinitialize QuickTime
	ExitMovies();

	// Deinitialize QTML
	TerminateQTML();

    return TRUE;
}


/*
	InitializeApp
*/
BOOL InitializeApp(void)
{

    WNDCLASS wc;
	RECT	rcDesktop;

    wc.style            = CS_OWNDC;
    wc.lpfnWndProc      = (WNDPROC) MainWndProc;
    wc.cbClsExtra       = 0;
    wc.cbWndExtra       = sizeof(LONG);
    wc.hInstance        = ghModule;
    wc.hIcon            = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APP));
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_APPWORKSPACE);
    wc.lpszMenuName     = MAKEINTRESOURCE(IDR_MAINMENU);
    wc.lpszClassName    = "MDIDemoClass";

    if (!RegisterClass(&wc))
        return FALSE;

    wc.lpfnWndProc      = (WNDPROC) MDIWndProc;
    wc.hIcon            = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APP));
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = "MDIClass";

    if (!RegisterClass(&wc))
        return FALSE;


    hMenu       = LoadMenu(ghModule, MAKEINTRESOURCE(IDR_MAINMENU));
    hChildMenu  = LoadMenu(ghModule, MAKEINTRESOURCE(IDR_CHILDMENU));
    hMenuWindow      = GetSubMenu(hMenu, 1);
    hChildMenuWindow = GetSubMenu(hChildMenu, 2);

	// Get the size for our window
	GetWindowRect(GetDesktopWindow(), &rcDesktop);
    ghwndMain = CreateWindowEx(0L, "MDIDemoClass", "Graphic Importer",
            WS_OVERLAPPED   | WS_CAPTION     | WS_BORDER       |
            WS_THICKFRAME   | WS_MAXIMIZEBOX | WS_MINIMIZEBOX  |
            WS_CLIPCHILDREN | WS_VISIBLE     | WS_SYSMENU,
            0, 0, rcDesktop.right - rcDesktop.left, rcDesktop.bottom - rcDesktop.top,
            NULL, hMenu, ghModule, NULL);

    if (ghwndMain == NULL)
        return FALSE;

	// Store our data
    SetWindowLong(ghwndMain, GWL_USERDATA, 0L);

	// Set initial focus 
    SetFocus(ghwndMain);

    return TRUE;
}

/*
	MainWndProc
*/
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    CLIENTCREATESTRUCT	clientcreate;
	DWORD				dwStyle;	

    switch (message) 
    {

      case WM_CREATE:
        SetWindowLong(hwnd, 0, (LONG)NULL);
        clientcreate.hWindowMenu  = hMenuWindow;
        clientcreate.idFirstChild = 1;
	
		dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE;			

		// Create our child window
		ghwndClient = CreateWindow("MDICLIENT", NULL,
										dwStyle,
										0,0,0,0,
										hwnd, NULL, ghModule, (LPVOID)&clientcreate);

        return 0L;

      case WM_DESTROY: 
		PostQuitMessage(0);
        return 0L;

      case WM_SYSCOMMAND:
		if ( LOWORD(wParam) == MM_ABOUT)   {
			SendMessage(hwnd,WM_COMMAND,MM_ABOUT,0);
			return 0;
		} else
              return DefWindowProc (hwnd, message, wParam, lParam);
		break;

      case WM_COMMAND:

        switch (LOWORD(wParam)) 
        {
            
			// File Menu
			case ID_FILE_OPEN: 
				if(DoFileOpen(NULL))
					return 0L;
				break;
			
			case ID_FILE_CLOSE:
				DestroyWindow((HWND)SendMessage(ghwndClient, WM_MDIGETACTIVE, 0L, FALSE));
				break;

			case ID_FILE_EXIT:
	            PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
	            break;
			
			// Window Menu
            case IDM_TILE:
                SendMessage(ghwndClient, WM_MDITILE, 0L, 0L);
                return 0L;
            
			case IDM_CASCADE:
                SendMessage(ghwndClient, WM_MDICASCADE, 0L, 0L);
                return 0L;
            
			case IDM_ARRANGE:
                SendMessage(ghwndClient, WM_MDIICONARRANGE, 0L, 0L);
                return 0L;

            case ID_WINDOW_ABOUT:
                if (DialogBox(ghModule, "AboutBox", ghwndMain, (DLGPROC)About) == -1){
					MessageBox(ghwndMain, "About Dialog Creation Error!", "Error", MB_OK);
				}
				return 0L;

            default:
                return DefFrameProc(hwnd,  ghwndClient, message, wParam, lParam);
        }

    default:

        return DefFrameProc(hwnd,  ghwndClient, message, wParam, lParam);
    }
}

/*
	MDIWndProc
*/
LRESULT CALLBACK MDIWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HANDLE      hInfo;
	PINFO       pInfo;
	MSG			msg;
	EventRecord	macEvent;
	LONG		thePoints = GetMessagePos();
	PAINTSTRUCT	ps;

	msg.hwnd = hwnd;
	msg.message = message;
	msg.wParam = wParam;
	msg.lParam = lParam;
	msg.time = GetMessageTime();
	msg.pt.x = LOWORD(thePoints);
	msg.pt.y = HIWORD(thePoints);
	WinEventToMacEvent(&msg, &macEvent);           

    switch (message) 
    {
		case WM_CREATE:
		case WM_MDICREATE:
			break;
		case WM_DESTROY:
			hInfo = (HANDLE)GetWindowLong(hwnd, GWL_USERDATA);
            if (hInfo) 
            {
                if ((pInfo = (PINFO)LocalLock(hInfo)) != NULL){
					if (pInfo->gi) 
						// close the graphic import component
						CloseComponent(pInfo->gi);

						// Destroy our port association
						DestroyPortAssociation((CGrafPort *)GetHWNDPort(pInfo->hwndChildWindow));
				}
                LocalUnlock(hInfo);
			}
			break;

		// Draw our graphic
		case WM_PAINT:
			BeginPaint(hwnd, &ps); 
			hInfo = (HANDLE)GetWindowLong(hwnd, GWL_USERDATA);
            if (hInfo) 
            {
                if ((pInfo = (PINFO)LocalLock(hInfo)) != NULL)
					GraphicsImportDraw(pInfo->gi);
			
                LocalUnlock(hInfo);
			}
			EndPaint(hwnd, &ps);
			break;

        default:
            return DefMDIChildProc(hwnd, message, wParam, lParam);

    }
    return DefMDIChildProc(hwnd, message, wParam, lParam);
}

/*
	About
*/
BOOL CALLBACK About (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) 
    {
    case WM_INITDIALOG:
        return TRUE;

    case WM_COMMAND:
        if (wParam == IDOK)
            EndDialog(hDlg, wParam);
        break;
    }

    return FALSE;
}

/*
	DoGraphicsImport
*/
BOOL DoGraphicsImport(PINFO pInfo)
{
	long	err;

	// Get the graphics importer component
	c2pstr(pInfo->spec.name);
	err = GetGraphicsImporterForFile(&pInfo->spec, &pInfo->gi);
	
	if (err) 
		goto bail;

	// Get the pixel bounds of this image
	err = GraphicsImportGetNaturalBounds(pInfo->gi, &pInfo->imageRect);

bail:
	if (err)
		return FALSE;
	else
		return TRUE;
}

/*
	DoOpen
*/
BOOL DoOpen(PINFO pInfo)
{
    pInfo->ofn.lStructSize = sizeof(OPENFILENAME);
	pInfo->ofn.lpstrTitle = "Select an Image File";
	pInfo->ofn.lpstrFile = pInfo->spec.name;
	pInfo->ofn.nMaxFile = 256;
    pInfo->ofn.lpstrFilter = "All Files (*.*) \0 *.*\0";
	if(USEEXPLORERSTYLE)
		pInfo->ofn.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER;
	else
		pInfo->ofn.Flags |= OFN_ENABLEHOOK;
	pInfo->ofn.lpfnHook = GenericHook;

	// Open the file...
	return GetOpenFileName(&pInfo->ofn);
}

/*
	GenericHook
*/
static UINT APIENTRY GenericHook(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		case WM_INITDIALOG:		// Center window
		{
			Point	ptTopLeft;
			RECT	rcWindow;
			BOOL	retValue;
			HWND	theWnd = hWnd;
			RECT	rcDesktopWindow;
			long	width;
			long	height;

			// if we are using 95 or NT 4.0 use the new explorer style
			if(USEEXPLORERSTYLE)
				theWnd = GetParent(hWnd);

			GetWindowRect(theWnd, &rcWindow);

			width = rcWindow.right - rcWindow.left;
			height = rcWindow.bottom - rcWindow.top;
			GetWindowRect(GetDesktopWindow(), &rcDesktopWindow);
			ptTopLeft.h = (short)((rcDesktopWindow.right + rcDesktopWindow.left)/2 - width/2);
			ptTopLeft.v = (short)((rcDesktopWindow.top + rcDesktopWindow.bottom)/3 - height/3);
		
			retValue = SetWindowPos(theWnd, 0, ptTopLeft.h, ptTopLeft.v, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
	
			return true;
		}
	}
	return 0;
}

/*
	DoFileOpen
*/
BOOL DoFileOpen(char* fullPathName)
{
	HANDLE			hInfo;
    PINFO			pInfo;
    MDICREATESTRUCT mdicreate;
	CGrafPtr		port;
	GDHandle		gd;

	// Allocate memory for INFO to be associated with the
	hInfo = LocalAlloc(LHND, (WORD) sizeof(INFO));
	if (hInfo) 
	{
		if ((pInfo = (PINFO)LocalLock(hInfo)) == NULL)
			MessageBox(ghwndMain, "Failed in LocalLock", "Error", MB_OK);

		// if we do not have a fullPathName, display an open dialog
		if(fullPathName == NULL) {
			// Display an open dialog
			if(	!DoOpen(pInfo)){
				LocalFree(hInfo);
				return FALSE;
			}
		} else {
			// Else we open the file
			pInfo->ofn.lpstrFile = fullPathName;
			strcpy(pInfo->spec.name, fullPathName);
			pInfo->ofn.nMaxFile = 256;
		}

		// Can we import this file?
		if(!DoGraphicsImport(pInfo)){
			LocalFree(hInfo);
			return FALSE;
		} else
			gMDICount++;

		pInfo->hParent    = ghwndClient;
		mdicreate.szClass = "MDIClass";
		mdicreate.szTitle = (LPTSTR)((*pInfo).ofn).lpstrFile;
		mdicreate.hOwner  = ghModule;
		mdicreate.x       = CW_USEDEFAULT;
		mdicreate.y       = CW_USEDEFAULT;
		mdicreate.cx      = pInfo->imageRect.right - pInfo->imageRect.left;
		mdicreate.cy      = pInfo->imageRect.bottom - pInfo->imageRect.top + GetSystemMetrics(SM_CYCAPTION);
		mdicreate.style   = 0L;
		// pass the handle of the per MDI child INFO to the child MDI window for storage
		mdicreate.lParam  = (LONG) hInfo;

		// Create Child Window
		pInfo->hwndChildWindow =
							(HANDLE) SendMessage(ghwndClient, WM_MDICREATE,
							0L,
							(LONG)(LPMDICREATESTRUCT)&mdicreate);

		if (pInfo->hwndChildWindow == NULL) 
		{
			MessageBox(ghwndMain, "Failed in Creating Child Window", "Error", MB_OK);
			return FALSE;
		}

		// Create our port association && set the port
		MacSetPort(CreatePortAssociation(pInfo->hwndChildWindow, NULL, 0));
	
		// These lines required to get the image to draw within the window
		GetGWorld(&port, &gd);
		GraphicsImportSetGWorld(pInfo->gi, port, gd);
		
		// Store our private data
		SetWindowLong(pInfo->hwndChildWindow, GWL_USERDATA, (LONG)hInfo);

		return TRUE;
    } else 
		MessageBox(ghwndMain, "Failed to Allocate INFO data!", "Error", MB_OK);

	return FALSE;
}

/*
	ParseCmdLinePriv

	Parse the command line when the applcation first starts.
*/
void ParseCmdLinePriv(LPSTR cmdLine)
{
	LPSTR lpCmdLine, lpT;

	if(cmdLine == NULL)
		lpCmdLine = GetCommandLine();
	else
		lpCmdLine = cmdLine;

	if (*lpCmdLine) {
		lpT = strchr(lpCmdLine, ' ');   // skip self name
		if (lpT) {
			lpCmdLine = lpT;
			while (*lpCmdLine == ' ') {
				lpCmdLine++;            // skip spaces to end or first cmd
			}

			while (*lpCmdLine != '\0'){
				char buff[255];
				int i;
				for (i = 0; (*lpCmdLine != ' ') && (*lpCmdLine != '\0'); i++, lpCmdLine++) {
					buff[i] = *lpCmdLine;
				}

				// Null terminate
				if(*lpCmdLine != '\0')
					lpCmdLine++;
				
				buff[i] = '\0';

				// Open the file
				DoFileOpen(buff);	
			}

		} else
			lpCmdLine += strlen(lpCmdLine);   // point to NULL
		
	}
}  



