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; //----------------------------------------------------------------------------- // // @mfuncconstructor. // // @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; }