/* balltime.cpp  Demonstrates animated drawing using a timer */

#include <windows.h>
#include "ball.h"

HWND     hWnd ;      /* the window's "handle" */
BOOL    _bDrawOn = FALSE ;  /* global to track if drawing is on or off */
int     _nXSize, _nYSize ;  /* window width and height */

int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                                LPSTR lpszCmdLine, int nCmdShow)
{

    MSG         msg ;       /* a message structure */
    WNDCLASS    wndclass ;  /* window class structure */

        wndclass.style          = CS_HREDRAW | CS_VREDRAW ;
        wndclass.lpfnWndProc    = WndProc ;
        wndclass.cbClsExtra     = 0 ;
        wndclass.cbWndExtra     = 0 ;
        wndclass.hInstance      = hInstance ;
        wndclass.hIcon          = NULL ;
        wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW) ;
        wndclass.hbrBackground  = (HBRUSH)GetStockObject (WHITE_BRUSH) ;
        wndclass.lpszMenuName   = "MYMENU" ;
        wndclass.lpszClassName  = "MyClass" ;
        if (!RegisterClass (&wndclass))
                return 0 ;

     hWnd = CreateWindow ("MyClass","balltime--ball with a timer", 
          WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
          NULL, NULL, hInstance, NULL) ;
     ShowWindow (hWnd, nCmdShow) ;   /* display the window */
     UpdateWindow (hWnd) ;

     SetTimer (hWnd, 1, 50, NULL) ;

     while (GetMessage (&msg, NULL, 0, 0))
          {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
          }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hWnd, UINT wMessage, 
                          WPARAM wParam, LPARAM lParam)
{
         switch (wMessage)       /* process windows messages */
         {
                  case WM_CREATE:     /* app starting, turn drawing on */
                                _bDrawOn = FALSE ;
                                break ;

                  case WM_SIZE :      /* save window client area size */
                                _nXSize = LOWORD (lParam) ;
                                _nYSize = HIWORD (lParam) ;
                                break ;

                  case WM_COMMAND:    /* menu items */
                                switch (LOWORD(wParam))
                                {
                                         case IDM_SHOW:
                                                  if (_bDrawOn)
                                                        _bDrawOn = FALSE ;  /* toggle drawing on/off */
                                                  else
                                                        _bDrawOn = TRUE ;
                                                  break ;
                                         case IDM_QUIT:
                                                  DestroyWindow (hWnd) ;
                                                  break ;
                                }
                                break ;

                  case WM_TIMER:      /* timeout--draw next frame */
                                if (_bDrawOn) DrawBall(hWnd);
                                break; 

                  case WM_DESTROY:
                                KillTimer (hWnd, 1) ;
                                PostQuitMessage (0) ;
                                break ;

                  default:
                                return DefWindowProc (hWnd, wMessage, wParam, lParam) ;
         }
         return (0) ;
}

/* DrawBall() draws a red ball on the window hWnd every time the */
/* function is called.  The ball is BALLRAD in radius.  The walls */
/* (client area size) are from 0,0 to nXSize,nYsize.  The location */
/* is moved each time by VELOCITY units. The signs of the X and Y */
/* velocity terms nVelX,nVelY are reversed each time the ball gets */
/* within MINRAD units of a wall.  This causes the ball to appear */
/* to bounce off the wall.  Drawing the ball at the new location */
/* causes the old ball to be erased, as the ball is drawn using a */
/* white pen for the outline that is 1.5 * VELOCITY in width.  The */
/* white pen ends up painting over any portion of the ball that is */
/* otherwise visible from the previous location. */

void DrawBall (HWND hWnd)
{
         HDC             hDC ;
         HPEN            hPen, hOldPen ;
         HBRUSH          hBrush, hOldBrush ;
         static  int     bX = 2*BALLRAD, bY = 2*BALLRAD, /* ball start X,Y */
                         bVelX = VELOCITY, bVelY = VELOCITY; /* X,Y velocity */

         bX = bX + bVelX ;        /* compute new center X,Y of ball */
         bY = bY + bVelY ;

         if (bY > _nYSize)                /* check if user moved walls and hid ball */
                  bY = 2 * BALLRAD ;  /* put the ball back at the starting.. */
         if (bX > _nXSize)        /* position if it is not going to be.. */
                  bX = 2 * BALLRAD ;  /* visible with the new window size */

         if (bY < MINRAD || _nYSize - bY < MINRAD)  /* check if hit wall */
                  bVelY = -1 * bVelY ;         /* if so, change direction */
         if (bX < MINRAD || _nXSize - bX < MINRAD)
                  bVelX = -1 * bVelX ;

         hDC = GetDC (hWnd) ;    /* get the device context handle */

         /* Create a thick white pen and a red brush */
         hPen = CreatePen (PS_SOLID, VELOCITY+VELOCITY/2, RGB(255,255,255));
         hBrush = CreateSolidBrush (RGB (255, 0, 0)) ;

         hOldPen = (HPEN)SelectObject (hDC, hPen) ;      /* select into the DC */
         hOldBrush = (HBRUSH)SelectObject (hDC, hBrush) ;

         /* draw the ball in the new location */
         /* the outline pen deletes around ball */
         Ellipse (hDC, bX-BALLRAD, bY-BALLRAD, bX+BALLRAD, bY+BALLRAD) ;

         /* delete all objects and free DC */
         SelectObject (hDC, hOldPen) ;
         DeleteObject (hPen) ;
         SelectObject (hDC, hOldBrush) ;
         DeleteObject (hBrush) ;
         ReleaseDC (hWnd, hDC) ;
}