
// ---------------------------------------------------------------------
//
// Stereo.c - Sample QuickTime for Windows Application
//
//            (c) 1988-1992 Apple Computer, Inc. All Rights Reserved.
//
// ---------------------------------------------------------------------

#include <windows.h>
#include <commdlg.h>
#include <string.h>
#include <stdlib.h>
#include <direct.h>
#include <qtw.h>
#include "stereo.h"

#ifdef __BORLANDC__
   #define _getcwd getcwd
#endif

long FAR PASCAL __export WndProc (HWND, UINT, WPARAM, LPARAM);
VOID CalcSize (HWND);

RECT rcLeft, rcRight, rcMovieBox, rcClient;
MovieController mcLeft, mcRight, mcActive;

int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
   LPSTR lpszCmdParam, int nCmdShow)
   {
   static char szAppName [] = "Stereo";
   HWND        hWnd;
   MSG         msg;
   WNDCLASS    wndclass;

// Establish links to QuickTime for Windows

   if (QTInitialize (NULL))
      {
      MessageBox (NULL, "QTInitialize failure", szAppName, MB_OK);
      return 0;
      }

// Allocate memory required for playing movies

   if (EnterMovies ())
      {
      MessageBox (NULL, "EnterMovies failure", szAppName, MB_OK);
      return 0;
      }

// Register and create main window

   if (!hPrevInstance)
      {
      wndclass.style         = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
      wndclass.lpfnWndProc   = WndProc;
      wndclass.cbClsExtra    = 0;
      wndclass.cbWndExtra    = 0;
      wndclass.hInstance     = hInstance;
      wndclass.hIcon         = LoadIcon (NULL,IDI_APPLICATION);
      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
      wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
      wndclass.lpszMenuName  = szAppName;
      wndclass.lpszClassName = szAppName;

      if (!RegisterClass (&wndclass))
         {
         MessageBox (NULL, "RegisterClass failure", szAppName, MB_OK);
         return 0;
         }
      }

   hWnd = CreateWindow (szAppName, szAppName, WS_OVERLAPPEDWINDOW |
      WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

   if (hWnd == NULL)
      {
      MessageBox (NULL, "CreateWindow failure", szAppName, MB_OK);
      return 0;
      }

// Show the main window

   ShowWindow (hWnd, nCmdShow);
   UpdateWindow (hWnd);

// Play the movies

   while (GetMessage (&msg, NULL, 0, 0))
      {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
      }

// Cut the connections to QuickTime for Windows

   ExitMovies ();
   QTTerminate ();

// Return to Windows

   return msg.wParam;
   }


long FAR PASCAL __export WndProc (HWND hWnd, UINT message, WPARAM wParam,
   LPARAM lParam)
   {
   OPENFILENAME ofn;
   PAINTSTRUCT ps;
   BOOL bLeft;
   POINT ptMovie;
   MovieFile mfMovie;

   static Movie mLeft, mRight;

   static char szDirName [256];
   static char szFile [256];
   static char szFileTitle [256];

// Drive the movie controllers

   if (MCIsPlayerMessage (mcLeft, hWnd, message, wParam, lParam)
    || MCIsPlayerMessage (mcRight, hWnd, message, wParam, lParam))
      return 0;

// Process window messages

   switch (message)
      {

   // Create empty movie controllers when main window is created

      case WM_CREATE:

         SetRectEmpty (&rcMovieBox);
         SetRectEmpty (&rcClient);

         mcLeft = NewMovieController (NULL, &rcClient,
            mcNotVisible, hWnd);
         mcRight = NewMovieController (NULL, &rcClient,
            mcNotVisible, hWnd);
         return 0;

   // Process menu commands

      case WM_COMMAND:

         switch (wParam)
            {

      // Use COMMDLG to open a movie file

            case IDM_OPEN:

               memset (&ofn, 0, sizeof (ofn));
               ofn.lStructSize = sizeof (ofn);
               ofn.hwndOwner = hWnd;
               ofn.lpstrFilter = "Movies (*.mov)\0*.mov\0\0";
               ofn.nFilterIndex = 1;
               ofn.lpstrFile = szFile;
               ofn.nMaxFile = sizeof (szFile);
               ofn.lpstrFileTitle = szFileTitle;
               ofn.nMaxFileTitle = sizeof (szFileTitle);
               ofn.lpstrInitialDir =
                  _getcwd (szDirName, sizeof (szDirName));
               ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

               if (GetOpenFileName (&ofn) &&
                  (OpenMovieFile (ofn.lpstrFile, &mfMovie, OF_READ) == noErr))
                  {
                  RECT rcGrowBox;

               // Dispose of any existing movies

                  DisposeMovie (mLeft);
                  DisposeMovie (mRight);

               // Extract two instances of the same movie

                  NewMovieFromFile (&mLeft, mfMovie, NULL, NULL,
                     0, NULL);
                  NewMovieFromFile (&mRight, mfMovie, NULL, NULL,
                     0, NULL);
                  CloseMovieFile (mfMovie);

               // Get the normal dimensions of the movie

                  GetMovieBox (mLeft, &rcMovieBox);
                  OffsetRect (&rcMovieBox, -rcMovieBox.left,
                     -rcMovieBox.top);

               // Calculate initial positions of controllers

                  GetClientRect (hWnd, &rcClient);
                  rcLeft.top = rcRight.top = rcClient.top +
                    (rcClient.bottom / 2) - (rcMovieBox.bottom / 2);
                  rcLeft.bottom = rcRight.bottom = rcClient.top +
                    (rcClient.bottom / 2) + (rcMovieBox.bottom / 2);
                  rcLeft.left = (rcClient.right / 4)
                    - (rcMovieBox.right / 2);
                  rcLeft.right = rcLeft.left + rcMovieBox.right;
                  rcRight.left = (rcClient.right / 2)
                    + (rcClient.right / 4)
                    - (rcMovieBox.right / 2);
                  rcRight.right = rcRight.left + rcMovieBox.right;

               // Associate the movies with the existing controllers

                  ptMovie.x = rcLeft.left;
                  ptMovie.y = rcLeft.top;
                  MCSetMovie (mcLeft, mLeft, hWnd, ptMovie);

                  ptMovie.x = rcRight.left;
                  ptMovie.y = rcRight.top;
                  MCSetMovie (mcRight, mRight, hWnd, ptMovie);

               // Pause the movies

                  MCDoAction (mcLeft, mcActionPlay, 0);
                  MCDoAction (mcRight, mcActionPlay, 0);

               // Center the movies

                  MCPositionController (mcLeft, &rcLeft,
                     NULL, mcTopLeftMovie + mcScaleMovieToFit);
                  MCPositionController (mcRight, &rcRight,
                     NULL, mcTopLeftMovie + mcScaleMovieToFit);

               // Make the controllers visible

                  MCSetVisible (mcLeft, TRUE);
                  MCSetVisible (mcRight, TRUE);

               // Make both movies active and the right mc inactive

                  SetMovieActive (mLeft, TRUE);
                  SetMovieActive (mRight, TRUE);
                  MCActivate (mcRight, hWnd, FALSE);

               // Eliminate the grow boxes

                  SetRectEmpty (&rcGrowBox);
                  MCDoAction (mcLeft, mcActionSetGrowBoxBounds, &rcGrowBox);
                  MCDoAction (mcRight, mcActionSetGrowBoxBounds, &rcGrowBox);
                  }
               return 0;

      // Change active controller to attached

            case IDM_ATTACH:

               MCSetControllerAttached (mcActive, TRUE);
               return 0;

      // Change active controller to detached

            case IDM_DETACH:
               {
               RECT rcMCRect;
               short sMCHeight;

            // Detach the controller

               MCSetControllerAttached (mcActive, FALSE);

            // Choose the appropriate movie/movie controller

               if (mcActive == mcLeft)
                  {

               // Get the bounds rect for the controller only
               // since it is now detached

                  MCGetControllerBoundsRect (mcLeft, &rcMCRect);
                  OffsetRect (&rcMCRect, -rcMCRect.left, -rcMCRect.top);

               // Save the controller height

                  sMCHeight = rcMCRect.bottom - rcMCRect.top;

               // Move the controller down

                  memcpy (&rcMCRect, &rcLeft, sizeof (RECT));
                  rcMCRect.top = rcLeft.bottom + (rcMovieBox.bottom / 2);
                  rcMCRect.bottom = rcMCRect.top + sMCHeight;
                  MCPositionController (mcLeft, &rcLeft, &rcMCRect,
                     mcTopLeftMovie);
                  }

               else
                  {

               // Get the bounds rect for the controller only
               // since it is now detached

                  MCGetControllerBoundsRect (mcRight, &rcMCRect);
                  OffsetRect (&rcMCRect, -rcMCRect.left, -rcMCRect.top);

               // Save the controller height

                  sMCHeight = rcMCRect.bottom - rcMCRect.top;

               // Move the controller down

                  memcpy (&rcMCRect, &rcRight, sizeof (RECT));
                  rcMCRect.top = rcRight.bottom + (rcMovieBox.bottom / 2);
                  rcMCRect.bottom = rcMCRect.top + sMCHeight;
                  MCPositionController (mcRight, &rcRight, &rcMCRect,
                     mcTopLeftMovie);
                  }
               }
               return 0;
            }
            return 0;

   // Center the controllers in the left and right halves of the window

      case WM_SIZE:

      // Attach the controllers

         MCSetControllerAttached (mcLeft, TRUE);
         MCSetControllerAttached (mcRight, TRUE);

         CalcSize (hWnd);
         MCSetControllerBoundsRect (mcLeft, &rcLeft);
         MCSetControllerBoundsRect (mcRight, &rcRight);
         return 0;


      case WM_LBUTTONDOWN:
         {
         SFIXED sfxVolume;

      // Activate the controller selected by the mouse click

         GetClientRect (hWnd, &rcClient);
         bLeft = (short) (LOWORD (lParam)) < ((rcClient.right - rcClient.left) / 2);
         mcActive = bLeft ? mcLeft : mcRight;
         MCActivate (mcLeft, hWnd, bLeft);
         MCActivate (mcRight, hWnd, !bLeft);

      // Disable sound and keyboard interface for appropriate controller

         if (mcActive == mcLeft)
            {
            MCDoAction (mcRight, mcActionGetVolume, (LPVOID) &sfxVolume);
            sfxVolume = - (abs (sfxVolume));
            MCDoAction (mcRight, mcActionSetVolume, (LPVOID) sfxVolume);

            MCDoAction (mcRight, mcActionSetKeysEnabled, (LPVOID) FALSE);
            }

         else
            {
            MCDoAction (mcLeft, mcActionGetVolume, (LPVOID) &sfxVolume);
            sfxVolume = - (abs (sfxVolume));
            MCDoAction (mcLeft, mcActionSetVolume, (LPVOID) sfxVolume);

            MCDoAction (mcLeft, mcActionSetKeysEnabled, (LPVOID) FALSE);
            }

      // Enable sound and keyboard for active controller

         MCDoAction (mcActive, mcActionGetVolume, (LPVOID) &sfxVolume);
         sfxVolume = abs (sfxVolume);
         MCDoAction (mcActive, mcActionSetVolume, (LPVOID) sfxVolume);

         MCDoAction (mcActive, mcActionSetKeysEnabled, (LPVOID) TRUE);
         }
         return 0;

   // Repaint the Window

      case WM_PAINT:

         if (!BeginPaint (hWnd, &ps))
            return 0;
         EndPaint (hWnd, &ps);
         return 0;

   // Destroy the movies and controllers when the window is destroyed

      case WM_DESTROY:

         DisposeMovieController (mcLeft);
         DisposeMovieController (mcRight);
         DisposeMovie (mLeft);
         DisposeMovie (mRight);
         PostQuitMessage (0);
         return 0;
      }

// Return to Windows

   return DefWindowProc (hWnd, message, wParam, lParam);
   }


VOID CalcSize (HWND hWndCaller)
   {
   RECT rcBounds;

   GetClientRect (hWndCaller, &rcClient);

   MCGetControllerBoundsRect (mcLeft, &rcBounds);
   OffsetRect (&rcBounds, -rcBounds.left, -rcBounds.top);

   rcLeft.top = rcRight.top = rcClient.top +
      (rcClient.bottom / 2) - (rcBounds.bottom / 2);

   rcLeft.bottom = rcRight.bottom = rcClient.top +
      (rcClient.bottom / 2) + (rcBounds.bottom / 2);

   rcLeft.left = (rcClient.right / 4) - (rcBounds.right / 2);
   rcLeft.right = (rcClient.right / 4) + (rcBounds.right / 2);

   MCGetControllerBoundsRect (mcRight, &rcBounds);
   OffsetRect (&rcBounds, -rcBounds.left, -rcBounds.top);

   rcRight.left = (rcClient.right / 2) + (rcClient.right / 4)
      - (rcBounds.right / 2);
   rcRight.right = (rcClient.right / 2) + (rcClient.right / 4)
      + (rcBounds.right / 2);
   }

