/* ------------------------------ TARGET.C ----------------------------
 *      Gestione della finestra principale
 * ---------------------------------------------------------------- */

#define STRICT

#include <Windows.h>
#include "dlg3.h"

// ---- Definizioni
#define XCORR           0
#define YCORR           2
#define BCAPTURE        4

/* -------------------------- Visualizza -------------------------------
 *      Visualizza il cursore bersaglio
 * ---------------------------------------------------------------- */

static VOID Visualizza (HWND hWnd)
{
HDC               hDC;
HPEN              hPen, hPenOld;
int               xCorr,
		  yCorr;        // Posizione corrente nel bersaglio

	xCorr = GetWindowWord (hWnd, XCORR);
	yCorr = GetWindowWord (hWnd, YCORR);

	hDC = GetDC (hWnd);
	SetROP2 (hDC, R2_NOT);
	hPen = CreatePen (PS_SOLID, 3, RGB (0, 0, 0));
	hPenOld = SelectObject (hDC, hPen);

	MoveToEx (hDC, xCorr-10, yCorr-10, NULL);
	LineTo (hDC, xCorr+10, yCorr+10);
	MoveToEx (hDC, xCorr-10, yCorr+10, NULL);
	LineTo (hDC, xCorr+10, yCorr-10);

	SelectObject (hDC, hPenOld);
	DeleteObject (hPen);
	ReleaseDC (hWnd, hDC);

	SetWindowWord (hWnd, XCORR, xCorr);
	SetWindowWord (hWnd, YCORR, yCorr);
	return;
}

/* -------------------------- wmKeyboard ----------------------------
 *      Elabora i messaggi WM_CHAR, WM_KEYDOWN e WM_KEYUP
 * ---------------------------------------------------------------- */

static VOID wmKeyboard (HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
{
static int        nInc;       // Incremento di spostamento
RECT              Rect; 
int               xCorr,
		  yCorr;      // Posizione corrente nel bersaglio

       if (wMsg == WM_KEYDOWN &&
		(wParam == VK_DOWN ||
		 wParam == VK_UP ||
		 wParam == VK_RIGHT ||
		 wParam == VK_LEFT))
	{
		Visualizza (hWnd);

		if (lParam & (1L<<30))          // Calcola incremento
			nInc++;
		else
			nInc = 1;

		xCorr = GetWindowWord (hWnd, XCORR);
		yCorr = GetWindowWord (hWnd, YCORR);

		switch (wParam)
		{
		case VK_DOWN:
			yCorr += nInc;
			break;

		case VK_UP:
			yCorr -= nInc;
			break;

		case VK_RIGHT:
			xCorr += nInc;
			break;

		case VK_LEFT:
			xCorr -= nInc;
			break;
		}

		GetClientRect (hWnd, &Rect);
		yCorr = max (yCorr, 0);
		yCorr = min (yCorr, Rect.bottom);
		xCorr = max (xCorr, 0);
		xCorr = min (xCorr, Rect.right);
		SetWindowWord (hWnd, XCORR, xCorr);
		SetWindowWord (hWnd, YCORR, yCorr);

		Visualizza (hWnd);
	}

	return;
}

/* -------------------------- wmCreate ------------------------------
 *      Elabora il messaggio WM_CREATE
 * lpCrst = (CREATESTRUCT FAR*) lParam   Punta ad una struttura 
 *                                       CREATESTRUCT.
 * ---------------------------------------------------------------- */

static VOID wmCreate (HWND hWnd, CREATESTRUCT FAR* lpCrst)
{
	SetWindowWord (hWnd, XCORR, 0);
	SetWindowWord (hWnd, YCORR, 0);
	SetWindowWord (hWnd, BCAPTURE, FALSE);
	return;
}

/* -------------------------- wmKillFocus ---------------------------
 *      Elabora il messaggio WM_KILLFOCUS
 * hWndAltra = (HWND) wParam    E' l'altra finestra che ottiene 
 *                              il focus.
 * ---------------------------------------------------------------- */

static VOID wmKillFocus (HWND hWnd, HWND hWndAltra)
{
HDC           hDC;
RECT          Rect;
HBRUSH        hBr;

	hDC = GetDC (hWnd);
	GetClientRect (hWnd, &Rect);
	hBr = CreateSolidBrush (GetSysColor (COLOR_WINDOW));
	FrameRect (hDC, &Rect, hBr);
	DeleteObject (hBr);
	ReleaseDC (hWnd, hDC);
	return;
}

/* -------------------------- wmMouse -------------------------------
 *      Elabora i messaggi WM_MOUSEMOVE e WM_?BUTTON*
 * wMsg                  E' il messaggio.
 * wParam                Indica i tasti/pulsanti premuti.
 * x = LOWORD (lParam)   E' l'ascissa del puntatore.
 * y = HIWORD (lParam)   E' l'ordinata del puntatore.
 * ---------------------------------------------------------------- */

static VOID wmMouse (HWND hWnd, WORD wMsg, WORD wParam, int x, int y)
{
	switch (wMsg)
	{
	case WM_LBUTTONDOWN:
		SetFocus (hWnd);

		SetCapture (hWnd);
		SetWindowWord (hWnd, BCAPTURE, TRUE);
		ShowCursor (FALSE);

		Visualizza (hWnd);
		SetWindowWord (hWnd, XCORR, x);
		SetWindowWord (hWnd, YCORR, y);
		Visualizza (hWnd);

		break;

	case WM_MOUSEMOVE:
		if (GetWindowWord (hWnd, BCAPTURE))
		{
			Visualizza (hWnd);
			SetWindowWord (hWnd, XCORR, x);
			SetWindowWord (hWnd, YCORR, y);
			Visualizza (hWnd);
		}

		break;

	case WM_LBUTTONUP:
		if (GetWindowWord (hWnd, BCAPTURE))
		{
			ReleaseCapture ();
			SetWindowWord (hWnd, BCAPTURE, FALSE);
			ShowCursor (TRUE);
		}
		break;
	}
	return;
}

/* -------------------------- wmPaint -------------------------------
 *      Elabora il messaggio WM_PAINT
 * ---------------------------------------------------------------- */

static VOID wmPaint (HWND hWnd)
{
PAINTSTRUCT     ps;
HDC             hDC;
RECT            Rect;
HBRUSH          hBr, hBrOld;
int             X, Y;
register        i;
static COLORREF Colore [] =
{
	0x00000000L, 0x000000ffL, 0x0000ff00L, 0x0000ffffL,
	0x00ff0000L, 0x00ff00ffL, 0x00ffff00L, 0x00ffffffL
};

	Visualizza (hWnd);           // Cancella la croce

	hDC = BeginPaint (hWnd, &ps);
	GetClientRect (hWnd, &Rect);
	if (GetFocus () == hWnd)
		FrameRect (hDC, &Rect, GetStockObject (GRAY_BRUSH));
	else
	{
		hBr = CreateSolidBrush (GetSysColor (COLOR_WINDOW));
		FrameRect (hDC, &Rect, hBr);
		DeleteObject (hBr);
	}

	X = -Rect.right/16;
	Y = -Rect.bottom/16;
	for (i = 0; i < 8; ++i)
	{                     // Traccia 5 ellissi concentriche
		hBr = CreateSolidBrush (Colore[i]);
		hBrOld = SelectObject (hDC, hBr);
		Ellipse (hDC, Rect.left, Rect.top, Rect.right, Rect.bottom);
		InflateRect (&Rect, X, Y);
		SelectObject (hDC, hBrOld);
		DeleteObject (hBr);
	}
	EndPaint (hWnd, &ps);

	Visualizza (hWnd);   // Visualizza la croce

	return;
}

/* -------------------------- wmSetFocus ----------------------------
 *      Elabora il messaggio WM_SETFOCUS
 * hWndAltra = (HWND) wParam    Contiene l'handle della finestra
 *                              che perde il focus.
 * ---------------------------------------------------------------- */

static VOID wmSetFocus (HWND hWnd, HWND hWndAltra)
{
HDC           hDC;
RECT          Rect;

	hDC = GetDC (hWnd);
	GetClientRect (hWnd, &Rect);
	FrameRect (hDC, &Rect, GetStockObject (GRAY_BRUSH));
	ReleaseDC (hWnd, hDC);
	return;
}

/* -------------------------- BersaglioWndProc ----------------------------
 *      WndProc della finestra Top - elabora i messaggi ricevuti
 * ---------------------------------------------------------------- */

LRESULT FAR PASCAL BersaglioWndProc (HWND hWnd, WORD wMsg, WORD wParam, 
				     LONG lParam)
{
LRESULT      lRes = 0;              // Valore di ritorno
BOOL         bElabora = TRUE;       // Indica comando elaborato

	switch (wMsg)
	{
	case BER_SETPOS:
		SetWindowWord (hWnd, XCORR, LOWORD (lParam));
		SetWindowWord (hWnd, YCORR, HIWORD (lParam));
		break;

	case BER_GETPOS:
		lRes = MAKELONG (GetWindowWord (hWnd, XCORR),
				 GetWindowWord (hWnd, YCORR));
		break;

	case WM_GETDLGCODE:
		lRes = DLGC_WANTARROWS;
		break;

	case WM_CREATE:
		wmCreate (hWnd, (CREATESTRUCT FAR*)lParam);
		break;

	case WM_KILLFOCUS:
		wmKillFocus (hWnd, (HWND)wParam);
		break;

	case WM_PAINT:
		wmPaint (hWnd);
		break;

	case WM_SETFOCUS:
		wmSetFocus (hWnd, (HWND)wParam);
		break;

	case WM_CHAR:
	case WM_KEYDOWN:
	case WM_KEYUP:
		wmKeyboard (hWnd, wMsg, wParam, lParam);
		break;

	case WM_MOUSEMOVE:
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_LBUTTONDBLCLK:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
	case WM_RBUTTONDBLCLK:
	case WM_MBUTTONDOWN:
	case WM_MBUTTONUP:
	case WM_MBUTTONDBLCLK:
		wmMouse (hWnd, wMsg, wParam, LOWORD (lParam), 
			 HIWORD (lParam));
		break;

	default:
		bElabora = FALSE;
		break;
	}

// ---- Elaborazione di default
	if (!bElabora)
		lRes = DefWindowProc (hWnd, wMsg, wParam, lParam);

	return lRes;
}