www.pudn.com > uoth_src.zip > MapWnd.cpp


//----------------------------------------------------------------------------- 
//  
// @doc 
// 
// @module	MapWnd.cpp - Main window | 
// 
// This module contains the main window. 
// 
// Copyright (c) 2002 - Descartes Systems Sciences, Inc. 
// 
// All rights reserved. 
// 
// Redistribution and use in source and binary forms, with or without  
// modification, are permitted provided that the following conditions are  
// met: 
//  
// 1. Redistributions of source code must retain the above copyright notice,  
//    this list of conditions and the following disclaimer.  
// 2. Neither the name of Descartes Systems Sciences, Inc nor the names of  
//    its contributors may be used to endorse or promote products derived  
//    from this software without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT  
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR  
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED  
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR  
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING  
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS  
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
// 
// @end 
// 
// $History: Cnf.cpp $ 
//       
//----------------------------------------------------------------------------- 
 
#include "stdafx.h" 
#include "resource.h" 
#include "MapWnd.h" 
#include "MainWnd.h" 
#include "uoth.h" 
#include "Region.h" 
#include "Filter.h" 
 
// 
// Debug NEW 
// 
 
#if defined (_DEBUG) 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
// 
// Global variables 
// 
 
extern TCHAR g_szAppName []; 
extern HCURSOR g_hcurMagnify; 
extern bool g_fPrettyDrawing; 
extern CBitmap g_bmWorld; 
extern CSize g_sizeWorld; 
extern CFilter g_sFilter; 
extern COLORREF g_clrRegionWithout; 
extern COLORREF g_clrRegionWith; 
extern COLORREF g_clrRegionWithoutDef; 
extern COLORREF g_clrRegionWithDef; 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc  constructor. 
// 
// @rdesc None. 
// 
//----------------------------------------------------------------------------- 
 
CMapWnd::CMapWnd () 
{ 
	m_nOverRegion = 0; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc  destructor. 
// 
// @rdesc None. 
// 
//----------------------------------------------------------------------------- 
 
CMapWnd::~CMapWnd () 
{ 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Create the window 
// 
// @parm CMainWnd * | pMainWnd | Pointer to the main window 
// 
// @rdesc Handle of the window 
// 
//----------------------------------------------------------------------------- 
 
HWND CMapWnd::Create (CMainWnd *pMainWnd) 
{ 
 
	// 
	// Save the window pointer 
	// 
 
	m_pMainWnd = pMainWnd; 
 
	// 
	// Create this window 
	// 
 
	DWORD dwExStyle = WS_EX_CLIENTEDGE; 
	DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN; 
	HWND hWnd =	CScrollWindowImpl ::Create (pMainWnd ->m_hWnd,  
		rcDefault, _T ( "Map Window"), dwStyle, dwExStyle,  
		1, NULL); 
	if (hWnd == NULL) 
		return NULL; 
	return hWnd; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Initialize the window 
// 
// @parm UINT | uMsg | Message 
// 
// @parm WPARAM | wParam | Message w-parameter 
// 
// @parm LPARAM | lParam | Message l-parameter 
// 
// @parm BOOL & | bHandled | If handled, set to true 
// 
// @rdesc Routine results 
// 
//----------------------------------------------------------------------------- 
 
LRESULT CMapWnd::OnCreate (UINT uMsg,  
	WPARAM wParam, LPARAM lParam, BOOL &bHandled)  
{ 
	// 
	// Set the scroll size 
	// 
 
	SetScrollOffset (0, 0, FALSE); 
	SetScrollSize (g_sizeWorld); 
 
	// 
	// Return FALSE 
	// 
 
	bHandled = FALSE; 
	return false; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Paint the window 
// 
// @parm UINT | uMsg | Message 
// 
// @parm WPARAM | wParam | Message w-parameter 
// 
// @parm LPARAM | lParam | Message l-parameter 
// 
// @parm BOOL & | bHandled | If handled, set to true 
// 
// @rdesc Routine results 
// 
//----------------------------------------------------------------------------- 
 
LRESULT CMapWnd::OnPaint (UINT uMsg,  
	WPARAM wParam, LPARAM lParam, BOOL &bHandled) 
{ 
 
	// 
	// Get the DC 
	// 
 
	PAINTSTRUCT ps; 
	BeginPaint (&ps); 
	HDC hdcDraw = ps .hdc; 
 
	// 
	// Get the clip rect and compute the real rect being drawn 
	// 
 
	CRect rectClip; 
	::GetClipBox (ps .hdc, &rectClip); 
	CRect rect (rectClip); 
	::OffsetRect (&rect, m_ptOffset .x, m_ptOffset .y); 
	rect .NormalizeRect (); 
 
	// 
	// Create a bitmap to use for drawing 
	// Offset origin more because bitmap is just piece of the whole drawing 
	// 
 
	HDC hDC = NULL; 
	HBITMAP hbitmap = NULL; 
	HGDIOBJ hbmOld = NULL; 
	if (g_fPrettyDrawing) 
	{ 
		hDC = ::CreateCompatibleDC (ps .hdc); 
		if (hDC) 
		{ 
			hbitmap = ::CreateCompatibleBitmap ( 
				ps .hdc, rect .Width (), rect .Height ()); 
			if (hbitmap != NULL) 
			{ 
				hdcDraw = hDC; 
				::OffsetViewportOrgEx (hDC, -rect .left, -rect .top, NULL); 
				hbmOld = ::SelectObject (hDC, hbitmap); 
			} 
		} 
	} 
 
	// 
	// Draw 
	// 
 
	Draw (hdcDraw); 
 
	// 
	// If the bitmap was used, copy the bitmap to the window 
	// 
 
	if (hdcDraw != ps .hdc)  
	{ 
		::BitBlt (ps .hdc, rectClip .left, rectClip .top,  
			rectClip .Width (), rectClip .Height (),  
			hDC, rect .left, rect .top, SRCCOPY); 
		::SelectObject (hDC, hbmOld); 
		::DeleteObject (hbitmap); 
	} 
	if (hDC != NULL) 
		::DeleteDC (hDC); 
 
	// 
	// End painting 
	// 
 
	EndPaint (&ps); 
	return TRUE; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Draw the window 
// 
//		The alpha blend code is based on work by Christian Grauss 
//		http://www.wd-mag.com/articles/2001/0109/0109b/0109b.htm?topic=articles 
// 
// @parm HDC | hDC | Destination DC 
// 
// @rdesc None. 
// 
//----------------------------------------------------------------------------- 
 
void CMapWnd::Draw (HDC hDC) 
{ 
 
	// 
	// Create a compat DC and select bitmap 
	// 
 
	HDC hCompat = ::CreateCompatibleDC (hDC); 
	HGDIOBJ hOldBitmap = ::SelectObject (hCompat, g_bmWorld); 
 
	// 
	// Get the water color 
	// 
 
	COLORREF clrWater = ::GetPixel (hCompat, 0, 0); 
 
 
	// 
	// Draw the bitmap 
	// 
 
	::BitBlt (hDC, 0, 0, g_sizeWorld .cx,  
		g_sizeWorld .cy, hCompat, 0, 0, SRCCOPY); 
 
	// 
	// Blend the regions 
	// 
 
	for (int ir = 0; ir < CRegion::gm_vRegions .GetCount (); ++ir) 
	{ 
		CRegion *pRegion = &CRegion::gm_vRegions [ir]; 
		if (!pRegion ->IsValid ()) 
			continue; 
 
		// 
		// Get the color 
		// 
 
		COLORREF clr; 
		if (g_sFilter .DoesRegionHaveMap (pRegion ->m_nIndex)) 
		{ 
			clr = g_clrRegionWith; 
			if (clr == CLR_DEFAULT) 
				clr = g_clrRegionWithDef; 
		} 
		else 
		{ 
			clr = g_clrRegionWithout; 
			if (clr == CLR_DEFAULT) 
				clr = g_clrRegionWithoutDef; 
		} 
		int cRed = GetRValue (clr); 
		int cGreen = GetGValue (clr); 
		int cBlue = GetBValue (clr); 
		int nAlpha = (m_nOverRegion == pRegion ->m_nIndex) ? 0x9f : 0x5f; 
 
		// 
		// Get locs 
		// 
 
		int x = pRegion ->m_rect .left; 
		int y = pRegion ->m_rect .top; 
		int cx = pRegion ->m_rect .Width (); 
		int cy = pRegion ->m_rect .Height (); 
 
		// 
		// Create the temp destination bitmap 
		// 
 
		BITMAPINFOHEADER BMI; 
		BMI.biSize = sizeof (BITMAPINFOHEADER); 
		BMI.biWidth = cx; 
		BMI.biHeight = cy; 
		BMI.biPlanes = 1; 
		BMI.biBitCount = 32; 
		BMI.biCompression = BI_RGB; 
		BMI.biSizeImage = 0; 
		BMI.biXPelsPerMeter = 0; 
		BMI.biYPelsPerMeter = 0; 
		BMI.biClrUsed = 0; 
		BMI.biClrImportant = 0; 
	     
		// 
		// Create DIB section in shared memory 
		// 
 
		BYTE *pDstBits; 
		HBITMAP hbmDst; 
		hbmDst = ::CreateDIBSection (hDC, (BITMAPINFO *)&BMI, 
			DIB_RGB_COLORS, (void **) &pDstBits, 0, 0l); 
 
		// 
		// Copy the destination data 
		// 
 
		HDC dc = ::CreateCompatibleDC (NULL); 
		HBITMAP dcOld = (HBITMAP) SelectObject (dc, hbmDst); 
		::BitBlt (dc, 0, 0, cx, cy, hDC, x, y, SRCCOPY); 
		::SelectObject (dc, dcOld); 
		::DeleteDC (dc); 
 
		// 
		// Perform the blend 
		// 
 
		for (int j = 0; j < cy; ++j) 
		{ 
			LPBYTE pbDestRGB = (LPBYTE) & ((DWORD *) pDstBits) [j * cx]; 
			unsigned char *pauchScan = pRegion ->m_paucPixels +  
				((cy - j - 1) * pRegion ->m_nWidthBytes); 
			int nBit = 0x80; 
			int nByte = 0; 
			for (int i = 0; i < cx; ++i) 
			{ 
				if ((pauchScan [nByte] & nBit) != 0) 
				{ 
					pbDestRGB [0] = ((int) pbDestRGB [0] * (255 - nAlpha) + 
							cBlue * nAlpha) >> 8; 
					pbDestRGB [1] = ((int) pbDestRGB [1] * (255 - nAlpha) + 
							cGreen * nAlpha) >> 8; 
					pbDestRGB [2] = ((int) pbDestRGB [2] * (255 - nAlpha) + 
							cRed * nAlpha) >> 8; 
				} 
				nBit >>= 1; 
				if (nBit == 0) 
				{ 
					nBit = 0x80; 
					nByte++; 
				} 
				pbDestRGB += 4; 
			} 
		} 
 
		// 
		// Copy back 
		// 
 
		dc = CreateCompatibleDC (NULL); 
	    dcOld = (HBITMAP) SelectObject (dc, hbmDst); 
		BitBlt (hDC, x, y, cx, cy, dc, 0, 0, SRCCOPY); 
		DeleteDC (dc); 
		DeleteObject (hbmDst);     
	} 
 
	// 
	// Draw the water if needed 
	// 
 
	::SetBkColor (hDC, clrWater); 
	CRect rect; 
	GetClientRect (&rect); 
	if (rect .right > g_sizeWorld .cx) 
	{ 
		CRect rect2 (g_sizeWorld .cx, 0, rect .right, rect .bottom); 
		::ExtTextOut (hDC, 0, 0, ETO_OPAQUE, &rect2, NULL, 0, NULL); 
	} 
	if (rect .bottom > g_sizeWorld .cy) 
	{ 
		CRect rect2 (0, g_sizeWorld. cy, g_sizeWorld .cx, rect .bottom); 
		::ExtTextOut (hDC, 0, 0, ETO_OPAQUE, &rect2, NULL, 0, NULL); 
	} 
 
	// 
	// Reselect and delete 
	// 
 
	::SelectObject (hCompat, hOldBitmap); 
	::DeleteDC (hCompat); 
	return; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Handle window mouse move 
// 
// @parm UINT | uMsg | Message 
// 
// @parm WPARAM | wParam | Message w-parameter 
// 
// @parm LPARAM | lParam | Message l-parameter 
// 
// @parm BOOL & | bHandled | If handled, set to true 
// 
// @rdesc Routine results 
// 
//----------------------------------------------------------------------------- 
 
LRESULT CMapWnd::OnMouseMove (UINT uMsg,  
	WPARAM wParam, LPARAM lParam, BOOL &bHandled)  
{ 
 
	// 
	// Test what the mouse is over 
	// 
 
	CPoint pt ( 
		LOWORD (lParam) + m_ptOffset .x,  
		HIWORD (lParam) + m_ptOffset .y); 
	int nOverRegion = RegionHitTest (pt); 
	if (m_nOverRegion != nOverRegion) 
	{ 
 
		// 
		// Invalidate the regions 
		// 
 
		InvalidateMapRegion (m_nOverRegion); 
		m_nOverRegion = nOverRegion; 
		InvalidateMapRegion (m_nOverRegion); 
 
		// 
		// Update the status bar 
		// 
 
		if (m_nOverRegion == 0) 
		{ 
			m_pMainWnd ->SetStatusBarText (NULL); 
		} 
		else 
		{ 
			m_pMainWnd ->SetStatusBarText ( 
				CRegion::gm_vRegions [m_nOverRegion] .m_strName); 
		} 
	} 
	return TRUE; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Handle window mouse leaving client area 
// 
// @parm UINT | uMsg | Message 
// 
// @parm WPARAM | wParam | Message w-parameter 
// 
// @parm LPARAM | lParam | Message l-parameter 
// 
// @parm BOOL & | bHandled | If handled, set to true 
// 
// @rdesc Routine results 
// 
//----------------------------------------------------------------------------- 
 
LRESULT CMapWnd::OnMouseLeave (UINT uMsg,  
	WPARAM wParam, LPARAM lParam, BOOL &bHandled)  
{ 
 
	// 
	// Clear over 
	// 
 
	InvalidateMapRegion (m_nOverRegion); 
	m_nOverRegion = 0; 
 
	// 
	// Set the status text 
	// 
 
	m_pMainWnd ->SetStatusBarText (NULL); 
	return TRUE; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Handle cursor query 
// 
// @parm UINT | uMsg | Message 
// 
// @parm WPARAM | wParam | Message w-parameter 
// 
// @parm LPARAM | lParam | Message l-parameter 
// 
// @parm BOOL & | bHandled | If handled, set to true 
// 
// @rdesc Routine results 
// 
//----------------------------------------------------------------------------- 
 
LRESULT CMapWnd::OnSetCursor (UINT uMsg,  
	WPARAM wParam, LPARAM lParam, BOOL &bHandled)  
{ 
	if (m_nOverRegion > 0) 
	{ 
		::SetCursor (g_hcurMagnify); 
		return TRUE; 
	} 
	else 
		return DefWindowProc (uMsg, wParam, lParam); 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Invalidate a region 
// 
// @parm int | nRegion | Region to invalidate 
// 
// @rdesc None. 
// 
//----------------------------------------------------------------------------- 
 
void CMapWnd::InvalidateMapRegion (int nRegion) 
{ 
 
	// 
	// Return if not set 
	// 
 
	if (nRegion == 0) 
		return; 
 
	// 
	// Invalidate 
	// 
 
	CRect rect (CRegion::gm_vRegions [nRegion] .m_rect); 
	rect .OffsetRect (- m_ptOffset .x, - m_ptOffset .y); 
	InvalidateRect (&rect, FALSE); 
	return; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Do a region hit test 
// 
// @parm POINT | pt | Point 
// 
// @rdesc Index of the region or 0 
// 
//----------------------------------------------------------------------------- 
 
int CMapWnd::RegionHitTest (POINT pt) 
{ 
	for (int ir = 0; ir < CRegion::gm_vRegions .GetCount (); ++ir) 
	{ 
		CRegion *pRegion = &CRegion::gm_vRegions [ir]; 
		if (!pRegion ->IsValid ()) 
			continue; 
		if (::PtInRect (&pRegion ->m_rect, pt)) 
		{ 
			bool fIn = true; 
			if (!pRegion ->m_fInRect) 
			{ 
				int x = pt .x - pRegion ->m_rect .left; 
				int y = pt .y - pRegion ->m_rect .top; 
				unsigned char *pauchScan = pRegion ->m_paucPixels +  
					((y) * pRegion ->m_nWidthBytes); 
				int nBit = (0x80) >> (x % 8); 
				int nByte = x / 8; 
				fIn = (pauchScan [nByte] & nBit) != 0; 
			} 
			if (fIn) 
				return pRegion ->m_nIndex; 
		} 
	} 
	return 0; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Handle window mouse left button down 
// 
// @parm UINT | uMsg | Message 
// 
// @parm WPARAM | wParam | Message w-parameter 
// 
// @parm LPARAM | lParam | Message l-parameter 
// 
// @parm BOOL & | bHandled | If handled, set to true 
// 
// @rdesc Routine results 
// 
//----------------------------------------------------------------------------- 
 
LRESULT CMapWnd::OnLButtonDown (UINT uMsg,  
	WPARAM wParam, LPARAM lParam, BOOL &bHandled)  
{ 
 
	// 
	// Test what the mouse is over 
	// 
 
	CPoint pt ( 
		LOWORD (lParam) + m_ptOffset .x,  
		HIWORD (lParam) + m_ptOffset .y); 
	m_nOverRegionClick = RegionHitTest (pt); 
 
	// 
	// Capture the mouse 
	// 
 
	SetCapture (); 
	return TRUE; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Handle window mouse left button up 
// 
// @parm UINT | uMsg | Message 
// 
// @parm WPARAM | wParam | Message w-parameter 
// 
// @parm LPARAM | lParam | Message l-parameter 
// 
// @parm BOOL & | bHandled | If handled, set to true 
// 
// @rdesc Routine results 
// 
//----------------------------------------------------------------------------- 
 
LRESULT CMapWnd::OnLButtonUp (UINT uMsg,  
	WPARAM wParam, LPARAM lParam, BOOL &bHandled)  
{ 
 
	// 
	// If nothing going on, return 
	// 
 
	if (GetCapture () != m_hWnd) 
		return TRUE; 
	ReleaseCapture (); 
 
	// 
	// Test what the mouse is over 
	// 
 
	CPoint pt ( 
		LOWORD (lParam) + m_ptOffset .x,  
		HIWORD (lParam) + m_ptOffset .y); 
	int nOverRegionClick = RegionHitTest (pt); 
	if (nOverRegionClick == m_nOverRegionClick && 
		nOverRegionClick > 0) 
		m_pMainWnd ->ShowRegion (nOverRegionClick, -1); 
	return TRUE; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Handle idle processing 
// 
// @parm CUpdateUIBase * | pUpdateUI | Pointer to update UI object 
// 
// @rdesc Idle return status. 
// 
//----------------------------------------------------------------------------- 
 
BOOL CMapWnd::OnIdle (CUpdateUIBase *pUpdateUI) 
{ 
	return FALSE; 
} 
 
//----------------------------------------------------------------------------- 
// 
// @mfunc Handle a change in show state 
// 
// @parm UINT | uMsg | Message 
// 
// @parm WPARAM | wParam | Message w-parameter 
// 
// @parm LPARAM | lParam | Message l-parameter 
// 
// @parm BOOL & | bHandled | If handled, set to true 
// 
// @rdesc Routine results 
// 
//----------------------------------------------------------------------------- 
 
LRESULT CMapWnd::OnShowWindow (UINT uMsg,  
	WPARAM wParam, LPARAM lParam, BOOL &bHandled)  
{ 
 
	// 
	// If we are being shown 
	// 
 
	if (wParam) 
	{ 
 
		// 
		// Clear the over status and the status bar 
		// 
 
		m_nOverRegion = 0; 
		m_pMainWnd ->SetStatusBarText (NULL); 
 
		// 
		// Get the cursor pos and do a dummy hit test 
		// 
 
		CPoint pt; 
		::GetCursorPos (&pt); 
		ScreenToClient (&pt); 
		BOOL bHandled = TRUE; 
		OnMouseMove (WM_MOUSEMOVE, 0,  
			MAKELPARAM (pt .x, pt .y), bHandled); 
	} 
 
	// 
	// Return FALSE 
	// 
 
	bHandled = FALSE; 
	return false; 
}