/********************************************************************\
 EyeWatch -- Cursor Tracking Program.

 Written By:  Paul L. Yao & Malcolm Austin
\********************************************************************/


#include "windows.h"
#include <math.h>

#define IRIS_LEFT   (-22)
#define IRIS_RIGHT  ( 22)
#define IRIS_TOP    ( 19)
#define IRIS_BOTTOM (-19)
#define ID_ABOUT    100

static  HANDLE  hInst;
static  HWND  hWnd;

POINT pt;
POINT ptOld;

RECT  rOldEye1;
RECT  rOldEye2;

HBRUSH hWhiteBrush;
HBRUSH hBlackBrush;
HPEN   hWhitePen;
HBRUSH hBackgroundBrush;

char   acEyeWndProc[]  = "PlyEyes";

long FAR PASCAL MainWinProc (HWND, unsigned, WORD, LONG);
long FAR PASCAL EyeWinProc (HWND, unsigned, WORD, LONG);
BOOL FAR PASCAL AboutboxWindowProc (HWND, unsigned, WORD, LONG);
void NEAR PASCAL DrawEyes (HDC, HWND);
void NEAR PASCAL DrawEyeLid (HDC, HWND);

int PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, cmdShow)
HANDLE hInstance, hPrevInstance;
LPSTR  lpszCmdLine;
int    cmdShow;
{
  MSG   msg;
  RECT  r;

  if (!hPrevInstance)
  {
    WNDCLASS   rClass;

    rClass.lpszClassName = acEyeWndProc;
    rClass.hInstance     = hInstance;
    rClass.lpfnWndProc	 = EyeWinProc;
    rClass.hCursor       = LoadCursor(NULL, IDC_ARROW) ;
    rClass.hIcon         = NULL;
    rClass.lpszMenuName  = NULL;
    rClass.hbrBackground = NULL;
    rClass.style	 = CS_HREDRAW|CS_VREDRAW;
    rClass.cbClsExtra    = 0;
    rClass.cbWndExtra    = 0;

    RegisterClass(&rClass);

  }
  else ;

  hInst = hInstance;

  hWhiteBrush = GetStockObject (WHITE_BRUSH);
  hBlackBrush = GetStockObject (BLACK_BRUSH);
  hWhitePen   = GetStockObject (WHITE_PEN);

  hBackgroundBrush = CreateSolidBrush (GetSysColor(COLOR_BACKGROUND));

  hWnd = CreateWindow(acEyeWndProc,
		      "Eyes",
		      WS_OVERLAPPED  |
		      WS_CAPTION     |
		      WS_SYSMENU     |
                      WS_MINIMIZEBOX |
		      WS_THICKFRAME,
                      CW_USEDEFAULT,
                      0,
                      CW_USEDEFAULT,
                      0,
		      NULL,
		      NULL,
		      hInstance,
		      NULL
                     );

  ShowWindow(hWnd, SW_MINIMIZE);

  SetTimer (hWnd, 1, 100, NULL);

  while (GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  DeleteObject (hBackgroundBrush);

  exit(msg.wParam);

}

/********************************************************************\
\********************************************************************/
long FAR PASCAL EyeWinProc (hWnd, msg, wParam, lParam)
HWND	   hWnd;
unsigned   msg;
WORD	   wParam;
LONG	   lParam;
{
  HDC hDC;
  PAINTSTRUCT ps;
  RECT r;
  HDC  hDCBitmap;
  HBITMAP hBitmap, hOldBitmap;
  FARPROC  lpprocAbout;

  switch (msg)
  {
    case WM_SYSCOMMAND:
	switch (wParam)
	{
	case ID_ABOUT:
	    lpprocAbout = MakeProcInstance( AboutboxWindowProc, hInst);
	    DialogBox (hInst, "AboutBox", hWnd, lpprocAbout);
	    FreeProcInstance ( lpprocAbout);
	    break;
	default:
	    return(DefWindowProc(hWnd, msg, wParam, lParam));
	    break;
	}
	break;

    case WM_CREATE:
	{
	HWND hSystMenu;
	hSystMenu = GetSystemMenu(hWnd, FALSE);
	ChangeMenu (hSystMenu, 0, NULL, 999, MF_APPEND | MF_SEPARATOR);
	ChangeMenu (hSystMenu, 0, "About...", ID_ABOUT, MF_APPEND | MF_STRING);
	}
	break;

    case WM_CLOSE:
        DestroyWindow (hWnd);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    case WM_ERASEBKGND:
        GetClientRect (hWnd, &r);
	DPtoLP ((HDC)wParam, (LPPOINT)&r, 2);
	FillRect ((HDC)wParam, &r, hBackgroundBrush);

	DrawEyeLid ((HDC)wParam, hWnd);
	return (1L);
        break;

    case WM_GETMINMAXINFO:
	{
	LPPOINT lp;

	lp = (LPPOINT)lParam + 3;

	/* Set minimum tracking size.  */
	lp-> x =  GetSystemMetrics (SM_CXMINTRACK)/2;
	}
	break;

    case WM_PAINT:
	hDC = BeginPaint (hWnd, &ps);
	DrawEyes (hDC, hWnd);
	EndPaint (hWnd, &ps);
        break;

    case WM_TIMER:
        GetCursorPos (&pt);
        if (ptOld.x != pt.x || ptOld.y != pt.y ) {
	    hDC = GetDC (hWnd);
	    GetClientRect (hWnd, &r);
	    if (r.right > 200 || r.bottom > 100) {
		DrawEyes (hDC, hWnd);
		goto CleanUp;
		}
	    hDCBitmap = CreateCompatibleDC (hDC);
	    hBitmap   = CreateCompatibleBitmap (hDC, r.right, r.bottom);
	    if (hBitmap) {
		hOldBitmap = SelectObject (hDCBitmap, hBitmap);
		FillRect (hDCBitmap, &r, hBackgroundBrush);
		DrawEyeLid (hDCBitmap, hWnd);
		DrawEyes (hDCBitmap, hWnd);
		SetMapMode (hDCBitmap, MM_TEXT);
		SetViewportOrg (hDCBitmap, 0, 0);
		BitBlt (hDC, 0, 0, r.right, r.bottom,
			hDCBitmap, 0, 0, SRCCOPY);
		SelectObject (hDCBitmap, hOldBitmap);
		DeleteObject (hBitmap);
		DeleteDC (hDCBitmap);
		}
	    else {
		DeleteDC (hDCBitmap);
		DrawEyes (hDC, hWnd);
		}
CleanUp:
	    ReleaseDC (hWnd, hDC);
            ptOld.x = pt.x;
            ptOld.y = pt.y;
            }
        break;

    default:
      return(DefWindowProc(hWnd, msg, wParam, lParam));
      break;
  }
  return(0L);
}

void NEAR PASCAL DrawEyes (HDC hDC, HWND hWnd)
{
  RECT r;
  POINT pt2;
  int   xShift;
  int   yShift;
  double dX;
  double dY;
  double dT;

    GetClientRect (hWnd, &r);
    SetMapMode (hDC, MM_ISOTROPIC);
    SetWindowExt (hDC, 200, 100);
    SetViewportExt (hDC, r.right, r.bottom);

    /*	Don't use pen for drawing eyes.  */
    SelectObject (hDC, hWhitePen);
    SelectObject (hDC, hWhiteBrush);

    /****************** Left Eye.  ***********************/

    /* Erase old eye.  */

    SetViewportOrg (hDC, r.right/4, r.bottom/2);
    Ellipse (hDC, rOldEye1.left,  rOldEye1.top,
		  rOldEye1.right, rOldEye1.bottom);

    /* Determine location of iris.  */
    pt2 = pt;
    ScreenToClient (hWnd, &pt2);
    DPtoLP (hDC, &pt2, 1);

    dX = (double) pt2.x;
    dY = (double) pt2.y;
    dT = sqrt ((dX*dX)+(dY*dY));

    xShift = (int) ( (IRIS_RIGHT<dT) ? (dX * IRIS_RIGHT/dT) : dX );
    yShift = (int) ( (IRIS_TOP<dT) ? (dY * IRIS_TOP/dT) : dY );

    /* Draw iris.  */
    SelectObject (hDC, hBlackBrush);

    rOldEye1.left   = IRIS_LEFT  +xShift;
    rOldEye1.top    = IRIS_TOP	 +yShift;
    rOldEye1.right  = IRIS_RIGHT +xShift;
    rOldEye1.bottom = IRIS_BOTTOM+yShift;
    Ellipse (hDC, rOldEye1.left,  rOldEye1.top,
		  rOldEye1.right, rOldEye1.bottom);

    /*********************** Right Eye. ************************/

    /* Erase old eye.  */
    SelectObject (hDC, hWhiteBrush);

    SetViewportOrg (hDC, (3*r.right)/4, r.bottom/2);
    Ellipse (hDC, rOldEye2.left,  rOldEye2.top,
		  rOldEye2.right, rOldEye2.bottom);

    /* Determine location of iris.  */
    pt2 = pt;
    ScreenToClient (hWnd, &pt2);
    DPtoLP (hDC, &pt2, 1);

    dX = (double) pt2.x;
    dY = (double) pt2.y;
    dT = sqrt ((dX*dX)+(dY*dY));

    xShift = (int) ( (IRIS_RIGHT<dT) ? (dX * IRIS_RIGHT/dT) : dX );
    yShift = (int) ( (IRIS_TOP<dT) ? (dY * IRIS_TOP/dT) : dY );

    /* Draw iris.  */
    SelectObject (hDC, hBlackBrush);

    rOldEye2.left   = IRIS_LEFT  +xShift;
    rOldEye2.top    = IRIS_TOP	 +yShift;
    rOldEye2.right  = IRIS_RIGHT +xShift;
    rOldEye2.bottom = IRIS_BOTTOM+yShift;
    Ellipse (hDC, rOldEye2.left,  rOldEye2.top,
		  rOldEye2.right, rOldEye2.bottom);

    }


void NEAR PASCAL DrawEyeLid (HDC hDC, HWND hWnd)
{
RECT r;

    /* Set up mapping mode. */
    GetClientRect (hWnd, &r);
    SetMapMode (hDC, MM_ISOTROPIC);
    SetWindowExt (hDC, 200, 100);
    SetViewportExt (hDC, r.right, r.bottom);

    /* Draw Outline of Left Eye.  */
    SetViewportOrg (hDC, r.right/4, r.bottom/2);
    Ellipse (hDC, -49, 42, 49, -42);

    /* Draw outline of Right eye. */
    SetViewportOrg (hDC, (3*r.right)/4, r.bottom/2);
    Ellipse (hDC, -49, 42, 49, -42);
}


/***************************************************************************/
/*    T H E   A B O U T   B O X   H A N D L I N G   P R O C E D U R E      */
/***************************************************************************/

/*   (This is the window procedure for the About dialog box.)              */


BOOL FAR PASCAL AboutboxWindowProc (hDlg, message, wParam, lParam)

HWND            hDlg;
unsigned        message;
WORD            wParam;
LONG            lParam;

{
    if (message == WM_COMMAND) {
        EndDialog (hDlg, TRUE);
        return TRUE;
        }
    else if (message == WM_INITDIALOG)
       return TRUE;
    else return FALSE;
}
