// Simple Win32 application to demonstrate drawing to a window
// Chris Lomont Feb 2000, Visual C++ 6.0

// all windows programs include this to access the windows API
#include <windows.h>

#include <stdio.h> // for some more standard C functions we want

// this function will do the drawing. It is passed a handle to a window
// so it knows which window to draw on. 
void PaintScreen(HWND hwnd)
	{
	PAINTSTRUCT ps;
	HDC hdc;

	// we begin the painting by acquiring some resources we'll need
	BeginPaint(hwnd,&ps);
	hdc = GetDC(hwnd);
	
	// get the size of the region we have to draw on...
	// size of window, 0,0 is upper left corner, rest positive directions
	int win_dx, win_dy; 
	RECT rect;
	// Note: this is the size of the drawble part of the window	
	// not the 640 by 480 size we requested (the total window size)
	GetClientRect(hwnd,&rect); 
	win_dx = rect.right - rect.left; 
	win_dy = rect.bottom - rect.top; // we've computed the size of the "canvas"

	// we'll draw stuff following......
	
	// start with a diagonal line, defaults to black on a white background
	MoveToEx(hdc,0,0,NULL);    // this sets the drawing cursor
	LineTo(hdc,win_dx,win_dy); // this draws

	// we can draw a few lines connected with this method 
	// to get a parallelogram
	MoveToEx(hdc,150,10,NULL);
	LineTo(hdc,200,10);
	LineTo(hdc,220,30);
	LineTo(hdc,170,30);
	LineTo(hdc,150,10); // this could also be drawn with PolyLine...

	// draw text "0,0", at position 0,0, and it has 3 characters to show
	TextOut(hdc,0,0,"0,0",3);

	// we format the max dimensions into text and draw it in the
	// lower right corner - try resizing the program with the mouse
	// to see what happens
	char text[100];
	sprintf(text,"%d,%d",win_dx,win_dy);
	TextOut(hdc,win_dx - 60,win_dy - 20,text,strlen(text));

	// A circle and an ellipse. 
	// Note these are filled in with the current brush (default solid white)
	Ellipse(hdc,20,20,40,40); // the circle in box 20,20 to 40,40
	Ellipse(hdc,40,40,50,70); // and an ellipse

	// every thing is drawn with the default pen (black), so we'll create another pen
	HPEN hPen, hPenOld;
	
	// we create a solid pen, 2 pixels wide, with RGB color 255,128,0 
	// (each entry is 0-255, so 255,0,0 is pure red, 0,0,0 is black, etc)
	hPen = CreatePen(PS_SOLID,2,RGB(255,128,0));
	
	// select the new pen into the device context, saving the old pen (important!)
	hPenOld = (HPEN)SelectObject(hdc,hPen);

	// draw a rectangle with this color - still fills with solid white brush
	Rectangle(hdc,70,70,150,100);

	// some more functions: Arc, ArcTo, Pie, Polygon, RoundRect, PolyLine

	// when done with the pen we created, we restore the original pen 
	// and destroy the one we created (avoids resource leaks)
	SelectObject(hdc,hPenOld);
	DeleteObject(hPen);

	// we'll draw some cubic bezier curve splines
	// note we're back to default black pen, 1 pixel wide
	POINT points[10]; // 10 points we'll use
	for (int pos = 0; pos < 10; pos++)
		{
		points[pos].x = 300  + pos*20;
		if (pos % 2) // set even position points at 10, odd at 100
			points[pos].y = 10;
		else 
			points[pos].y = 100;
		}
	PolyBezier(hdc,points,10);


	// set a box filled with colored pixels
	for (int i = 50; i < 150; i++)
		for (int j = 200; j < 250; j++)
			SetPixel(hdc,i,j,RGB(5*i,7*j,2*i+3*j));

	// finally release the stuff we acquired this time (or we'll have resource leaks!!)
	ReleaseDC(hwnd,hdc);
	EndPaint(hwnd,&ps);
	} // PaintScreen

// every window needs a loop to process messages. Here is the one for
// the window class we defined for this program
LONG PASCAL AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	static int xpos, ypos;
	switch (msg)
		{
		case WM_CLOSE:
			DestroyWindow(hwnd);
			return FALSE;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		case WM_LBUTTONDOWN:
			// when left mouse botton pushed down in client area, 
			// store position so we can draw a line
			xpos = LOWORD(lParam);
			ypos = HIWORD(lParam);
			break;   
		case WM_LBUTTONUP:
			{
			// left button up draws a line from where it was
			// pushed down. Not that the WM_PAINT message will erase
			// any lines we've drawn. You would need to store all of the lines
			// and draw them back in the paint message
			HDC hdc = GetDC(hwnd); // get the window device context
			MoveToEx(hdc,xpos,ypos,NULL); // move to here
			LineTo(hdc,LOWORD(lParam),HIWORD(lParam)); // draw line
			ReleaseDC(hwnd,hdc); // release device context
			}
			break;   
		case WM_PAINT:
			PaintScreen(hwnd);
			return 0L;
		} // switch message
	return DefWindowProc(hwnd,msg,wParam,lParam);
	} // AppWndProc

// this routine creates the window, returning TRUE iff it succeeds
BOOL AppInit(HINSTANCE hInst,HINSTANCE hPrev,int sw,LPSTR szCmdLine)
	{
	WNDCLASS cls;
	char titleName[] = "SimpleWin32App - Chris Lomont";
	char className[] = "SimpleClass";


	// if this program is not currently running, create a 
	// window class for it
	if (!hPrev) 
		{                     
		//***  Register a class for the main application window
		cls.hCursor        = LoadCursor(0,IDC_ARROW); // default cursor
		cls.hIcon          = LoadIcon(NULL,IDI_APPLICATION);
		cls.lpszMenuName   = NULL; // no menu
		cls.lpszClassName  = className;
		cls.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH); // white background
		cls.hInstance      = hInst;
		cls.style          = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW;
		cls.lpfnWndProc    = (WNDPROC)AppWndProc; // our window function
		cls.cbClsExtra     = 0;
		cls.cbWndExtra     = 0;

		if (!RegisterClass(&cls))				 
			return FALSE; // return if failed - no point in going on
		}

	int x,y,dx,dy; // start positions, sizes
	dx = 640;      // request a 640 by 480 pixel window
	dy = 480;
	// get screen sizes, and center this window we're making
	x = (GetSystemMetrics(SM_CXSCREEN)-dx)/2;
	y = (GetSystemMetrics(SM_CYSCREEN)-dy)/2; // center it

	HWND hwndApp = CreateWindow (className,   // Class name
		titleName,           // Caption
		WS_OVERLAPPED |
		WS_CAPTION |
		WS_SYSMENU | 
		WS_THICKFRAME |      // for resizing
		WS_MAXIMIZEBOX |
		WS_MINIMIZEBOX,      // Style bits
		x,y,                 // upper left corner position
		dx,dy, 	             // size of the window
		0,                   // Parent window (no parent)
		0,                   // use class menu
		hInst,               // handle to window instance
		0                    // no params to pass on
		);

	ShowWindow(hwndApp,SW_SHOWNORMAL); // display the window
	return TRUE; // we succeeded
	} // AppInit

// every windows porgram starts at WinMain. This is the definition
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
	{
	MSG msg;

	//*** Call initialization procedure
	if (!AppInit(hInstance,hPrevInstance,nCmdShow,lpCmdLine))
		return FALSE;

	//*** Polling messages from event queue until quit
	for (;;)
		{
		if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
			{
			if (msg.message == WM_QUIT)
				break;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			}
		}

	return msg.wParam;
	} // WinMain

// end - SimpleWinApp.cpp