/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~= ** ** FILE: POV.CPP ** DATE: 3/31/97 ** PROJ: ATLAS ** PROG: JKH ** COMMENTS: ** ** DESCRIPTION: Window class for a 360 degree Point Of View control ** ** ** ** NOTE: There are some issues with using extern "C" in this file. ** If you don't understand why they are there, you're not ** alone. For now, and probably for a while they will be ** here though, because I can't get this file and others ** that use these services to compile without them. ** Unfortunately the dynamics of this project don't really ** afford me the time at present to figure this out. ** TODO: figure this out ** ** HISTORY: ** DATE WHO WHAT ** ---- --- ---- ** 3/31/97 a-kirkh Wrote it. ** ** ** ** ** Copyright (C) Microsoft 1997. All Rights Reserved. ** **~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/ #pragma pack (8) #include "POV.H" //This module's stuff. #include "resource.h" extern HWND hPOVWnd = NULL; static HINSTANCE ghResInst; static LPRECT prctOldRegionBox; static LPRECT prctNewRegionBox; double degrees = -1; void SetDegrees(int dDegrees) { degrees = (double)dDegrees; PostMessage(hPOVWnd, PM_MYJOYPOSCHANGED, 0, 0); } extern "C"{ void SetResourceInstance(HINSTANCE hInstance) { ghResInst = hInstance; } HINSTANCE GetResourceInstance() { return(ghResInst); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // FUNCTION : POVWndProc // REMARKS : The callback function for the POVHat Window. // // PARAMS : The usual callback funcs for message handling // // RETURNS : LRESULT - Depends on the message // CALLS : // NOTES : // WM_PAINT - Just calls DrawControl // // PM_MYJOYPOSCHANGED - This is a private (WM_USER) message that is // called whenever a change in the POV hat occurs. // RECT rClient; HDC hDC; PAINTSTRUCT ps; LONG cxClient, cyClient; HRGN hRegion; HBITMAP hPOVHubBitmap = NULL; LRESULT CALLBACK POVWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch( iMsg ) { case WM_CREATE: hPOVWnd = hWnd; return(0); case WM_PAINT: { hDC = BeginPaint(hWnd, &ps); DrawControl(hWnd, hDC); EndPaint(hWnd, &ps); } return(0); case PM_MYJOYPOSCHANGED: { degrees /= 100; // if angle == 180, degrees comes in as 18000 GetCurrentArrowRegion(&hRegion); if( hRegion ) { GetRgnBox(hRegion, prctNewRegionBox); InvalidateRect(hWnd, prctOldRegionBox, TRUE); InvalidateRect(hWnd, prctNewRegionBox, TRUE); DeleteObject(hRegion); } } default: return(DefWindowProc(hWnd, iMsg,wParam, lParam)); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // FUNCTION : DrawControl // REMARKS : Function called by WM_PAINT that draws the POV hat control // PARAMS : HWND - Control's window handle // HDC - Control's dc created with BeginPaint // RETURNS : void // CALLS : GetCurrentArrowRegion // NOTES : // 1) So that stuff can be centered. // 2) Bitblt that hub thingy in the middle. // 3) Disallow any problems with aspect ratio. // 4) Draw the circle, should be round because of 3. // 5) a.Get the coordinates of the rotated arrow. // b.Paint the region. // c.Get the bounding rectangle of the region so we // can invalidate it next time around. void DrawControl(HWND hWnd, HDC hDC) { assert(hWnd); assert(hDC); // 1) Get client size information SetMapMode(hDC, MM_TEXT); GetClientRect(hWnd, &rClient); cxClient = rClient.right - rClient.left; cyClient = -(rClient.bottom - rClient.top); // 2) Load the hub bitmap and display it hPOVHubBitmap = LoadBitmap((HMODULE)ghResInst, MAKEINTRESOURCE(IDB_POVHUB)); assert(hPOVHubBitmap); DrawBitmap(hDC, hPOVHubBitmap, cxClient/2 - 8, -cyClient/2 - 8); DeleteObject(hPOVHubBitmap); // 3) Setup the window to use symmetrical units on a 1000 X 1000 cartesian grid SetMapMode(hDC, MM_ISOTROPIC); SetWindowExtEx(hDC, 1000, 1000, NULL); SetViewportExtEx(hDC, cxClient / 2, cyClient / 2, NULL); SetViewportOrgEx(hDC, cxClient / 2, -cyClient / 2, NULL); // 4) Draw the circle upon which the arrow seems to rotate SelectObject(hDC, (HBRUSH)GetStockObject(NULL_BRUSH)); HPEN hPen = CreatePen( PS_SOLID, 1, CIRCLECOLOR); //PREFIX: dereferencing NULL pointer 'hPen' //Millen Bug#129156, manbug 29347 if( hPen != NULL ) { HPEN hPenOld = (HPEN)SelectObject(hDC, hPen); Ellipse(hDC, -CIRCLERADIUS, CIRCLERADIUS, CIRCLERADIUS, -CIRCLERADIUS); SelectObject(hDC, hPenOld); DeleteObject(hPen); } // 5) Paint the Arrow at the correct angle if POV active if( degrees >= 0 ) { HBRUSH hBrush = CreateSolidBrush( CIRCLECOLOR ); if( !hBrush ) { return; } HBRUSH hBrushOld = (HBRUSH)SelectObject(hDC, hBrush); assert(hBrushOld); GetCurrentArrowRegion(&hRegion); if( !hRegion ) { return; } PaintRgn(hDC, hRegion); // GetRgnBox returns zero if it fails... GetRgnBox(hRegion, prctOldRegionBox); SelectObject(hDC, hBrushOld); DeleteObject(hBrush); DeleteObject(hRegion); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // FUNCTION : RegisterPOVClass // REMARKS : Registers the POV Hat window. // // PARAMS : hInstance - Used for the call to RegisterClassEx // // RETURNS : TRUE - if successfully registered // FALSE - failed to register // CALLS : RegisterClassEx // NOTES : // extern BOOL RegisterPOVClass(HINSTANCE hInstance) { WNDCLASSEX POVWndClass; POVWndClass.cbSize = sizeof(POVWndClass); POVWndClass.style = CS_HREDRAW | CS_VREDRAW; POVWndClass.lpfnWndProc = POVWndProc; POVWndClass.cbClsExtra = 0; POVWndClass.cbWndExtra = 0; POVWndClass.hInstance = hInstance; POVWndClass.hIcon = NULL; POVWndClass.hCursor = LoadCursor(NULL, IDC_ARROW); POVWndClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); POVWndClass.lpszMenuName = NULL; POVWndClass.lpszClassName = "POVHAT"; POVWndClass.hIconSm = NULL; if( RegisterClassEx( &POVWndClass ) == 0 ) return(FALSE); return(TRUE); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // FUNCTION : DrawBitmap // REMARKS : Copied verbatim from Petzold (WIN95 pg 190) // PARAMS : HDC - dc for drawing // HBITMAP - bitmap to draw // int xstart, ystart - where to place the bitmap // // RETURNS : void // CALLS : // NOTES : // void DrawBitmap(HDC hDC, HBITMAP hBitmap, int xStart, int yStart) { BITMAP bm; HDC hdcMem; POINT ptSize, ptOrg; hdcMem = CreateCompatibleDC(hDC); // Found by prefix: Millen Bug129155. manbugs 29339 // If CreateCompatibleDC fails, we should'nt proceed. if( hdcMem == NULL ) return; SelectObject(hdcMem, hBitmap); SetMapMode(hdcMem,GetMapMode(hDC)); GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm); ptSize.x = bm.bmWidth; ptSize.y = bm.bmHeight; DPtoLP(hDC, &ptSize, 1); ptOrg.x = 0; ptOrg.y = 0; DPtoLP(hdcMem, &ptOrg, 1); BitBlt(hDC, xStart, yStart, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCAND); DeleteDC(hdcMem); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // FUNCTION : GetCurrentArrowRegion // REMARKS : Rotates and translate a set of vertices that represents // the POV hat arrow // // PARAMS : HRGN - The region to be rotated // // RETURNS : BOOL // CALLS : GETXCOORD, GETYCOORD (POV.H) // NOTES : // void GetCurrentArrowRegion(HRGN* hRegion) { POINT aptPoints[8]; VERTICEINFO aptVInfo[8] = { XARROWPOINT ,YARROWPOINT , XARROWRIGHTOUT ,YARROWRIGHTOUT , XARROWRIGHTIN ,YARROWRIGHTIN , XARROWRIGHTBOTTOM,YARROWRIGHTBOTTOM, XARROWLEFTBOTTOM ,YARROWLEFTBOTTOM , XARROWLEFTIN ,YARROWLEFTIN , XARROWLEFTOUT ,YARROWLEFTOUT , XARROWPOINT ,YARROWPOINT}; aptPoints[0].x = GETXCOORD(aptVInfo[0].y, aptVInfo[0].x, degrees); aptPoints[0].y = GETYCOORD(aptVInfo[0].y, aptVInfo[0].x, degrees); aptPoints[1].x = GETXCOORD(aptVInfo[1].y, aptVInfo[1].x, degrees); aptPoints[1].y = GETYCOORD(aptVInfo[1].y, aptVInfo[1].x, degrees); aptPoints[2].x = GETXCOORD(aptVInfo[2].y, aptVInfo[2].x, degrees); aptPoints[2].y = GETYCOORD(aptVInfo[2].y, aptVInfo[2].x, degrees); aptPoints[3].x = GETXCOORD(aptVInfo[3].y, aptVInfo[3].x, degrees); aptPoints[3].y = GETYCOORD(aptVInfo[3].y, aptVInfo[3].x, degrees); aptPoints[4].x = GETXCOORD(aptVInfo[4].y, aptVInfo[4].x, degrees); aptPoints[4].y = GETYCOORD(aptVInfo[4].y, aptVInfo[4].x, degrees); aptPoints[5].x = GETXCOORD(aptVInfo[5].y, aptVInfo[5].x, degrees); aptPoints[5].y = GETYCOORD(aptVInfo[5].y, aptVInfo[5].x, degrees); aptPoints[6].x = GETXCOORD(aptVInfo[6].y, aptVInfo[6].x, degrees); aptPoints[6].y = GETYCOORD(aptVInfo[6].y, aptVInfo[6].x, degrees); aptPoints[7].x = GETXCOORD(aptVInfo[7].y, aptVInfo[7].x, degrees); aptPoints[7].y = GETYCOORD(aptVInfo[7].y, aptVInfo[7].x, degrees); *hRegion = CreatePolygonRgn(aptPoints, 8, WINDING); } }