307 lines
11 KiB
C++
307 lines
11 KiB
C++
/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
|
|
**
|
|
** 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.
|
|
**
|
|
**~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/
|
|
#include "cplsvr1.h" // for ghInst
|
|
#include "dicputil.h" // for MAX_POVS
|
|
#include "POV.H" //This module's stuff.
|
|
#include <malloc.h> // for _alloca
|
|
|
|
#include "resrc1.h"
|
|
|
|
//static HWND hPOVWnd = NULL;
|
|
#define NUM_ARROW_POINTS 8
|
|
//static VERTICEINFO *paptVInfo;
|
|
static const VERTICEINFO VInfo[] = {XARROWPOINT, YARROWPOINT, XARROWRIGHTOUT, YARROWRIGHTOUT, XARROWRIGHTIN, YARROWRIGHTIN,
|
|
XARROWRIGHTBOTTOM, YARROWRIGHTBOTTOM, XARROWLEFTBOTTOM, YARROWLEFTBOTTOM, XARROWLEFTIN,
|
|
YARROWLEFTIN, XARROWLEFTOUT, YARROWLEFTOUT, XARROWPOINT, YARROWPOINT};
|
|
static LPRECT prcOldRegionBox[MAX_POVS];
|
|
static LPRECT prcNewRegionBox[MAX_POVS];
|
|
|
|
#define DEF_POV_POS -1
|
|
|
|
static double degrees[MAX_POVS] = {DEF_POV_POS, DEF_POV_POS, DEF_POV_POS, DEF_POV_POS};
|
|
|
|
static BYTE nPOV = MAX_POVS;
|
|
static HBRUSH hBrush[MAX_POVS];
|
|
static HRGN hRegion[MAX_POVS];
|
|
|
|
extern HINSTANCE ghInst;
|
|
|
|
void SetDegrees(BYTE nPov, short *nDegrees, HWND hPOVWnd)
|
|
{
|
|
nPOV = nPov -= 1;
|
|
|
|
LPPOINT paptPoints = (LPPOINT)_alloca(sizeof(POINT[NUM_ARROW_POINTS]));
|
|
assert (paptPoints);
|
|
|
|
// Create the proper brush for the axis!
|
|
do {
|
|
degrees[nPov] = (double)nDegrees[nPov] / DI_DEGREES; // if angle == 180, degrees comes in as 18000
|
|
|
|
paptPoints[0].x = GETXCOORD(VInfo[0].y, VInfo[0].x, degrees[nPov]);
|
|
paptPoints[0].y = GETYCOORD(VInfo[0].y, VInfo[0].x, degrees[nPov]);
|
|
paptPoints[1].x = GETXCOORD(VInfo[1].y, VInfo[1].x, degrees[nPov]);
|
|
paptPoints[1].y = GETYCOORD(VInfo[1].y, VInfo[1].x, degrees[nPov]);
|
|
paptPoints[2].x = GETXCOORD(VInfo[2].y, VInfo[2].x, degrees[nPov]);
|
|
paptPoints[2].y = GETYCOORD(VInfo[2].y, VInfo[2].x, degrees[nPov]);
|
|
paptPoints[3].x = GETXCOORD(VInfo[3].y, VInfo[3].x, degrees[nPov]);
|
|
paptPoints[3].y = GETYCOORD(VInfo[3].y, VInfo[3].x, degrees[nPov]);
|
|
paptPoints[4].x = GETXCOORD(VInfo[4].y, VInfo[4].x, degrees[nPov]);
|
|
paptPoints[4].y = GETYCOORD(VInfo[4].y, VInfo[4].x, degrees[nPov]);
|
|
paptPoints[5].x = GETXCOORD(VInfo[5].y, VInfo[5].x, degrees[nPov]);
|
|
paptPoints[5].y = GETYCOORD(VInfo[5].y, VInfo[5].x, degrees[nPov]);
|
|
paptPoints[6].x = GETXCOORD(VInfo[6].y, VInfo[6].x, degrees[nPov]);
|
|
paptPoints[6].y = GETYCOORD(VInfo[6].y, VInfo[6].x, degrees[nPov]);
|
|
paptPoints[7].x = GETXCOORD(VInfo[7].y, VInfo[7].x, degrees[nPov]);
|
|
paptPoints[7].y = GETYCOORD(VInfo[7].y, VInfo[7].x, degrees[nPov]);
|
|
|
|
if(hRegion[nPov])
|
|
{
|
|
DeleteObject(hRegion[nPov]);
|
|
hRegion[nPov]=NULL;
|
|
}
|
|
hRegion[nPov] = CreatePolygonRgn(paptPoints, NUM_ARROW_POINTS, WINDING);
|
|
|
|
//hBrush[nPov] = CreateSolidBrush((nPov < 1) ? POV1_COLOUR :
|
|
// (nPov < 2) ? POV2_COLOUR :
|
|
// (nPov < 3) ? POV3_COLOUR : POV4_COLOUR); */
|
|
|
|
//if (hRegion[nPov] && hBrush[nPov])
|
|
//{
|
|
// GetRgnBox(hRegion[nPov], prcNewRegionBox[nPov]);
|
|
//
|
|
// //RedrawWindow(hPOVWnd, NULL, NULL, RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_ERASE);
|
|
// InvalidateRect(hPOVWnd, prcOldRegionBox[nPov], TRUE);
|
|
// InvalidateRect(hPOVWnd, prcNewRegionBox[nPov], TRUE);
|
|
//}
|
|
RECT R;
|
|
GetClientRect(hPOVWnd,&R);
|
|
|
|
POINT Pnt[2];
|
|
Pnt[0].x=R.left;
|
|
Pnt[0].y=R.top;
|
|
Pnt[1].x=R.right;
|
|
Pnt[1].y=R.bottom;
|
|
MapWindowPoints(hPOVWnd,GetParent(hPOVWnd),Pnt,2);
|
|
R.left=Pnt[0].x;
|
|
R.top=Pnt[0].y;
|
|
R.right=Pnt[1].x;
|
|
R.bottom=Pnt[1].y;
|
|
InvalidateRect(GetParent(hPOVWnd), &R, TRUE);
|
|
|
|
} while( nPov-- );
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// 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.
|
|
//
|
|
LRESULT CALLBACK POVWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch( iMsg ) {
|
|
|
|
// case WM_CREATE:
|
|
// hPOVWnd = hWnd;
|
|
// return FALSE;
|
|
|
|
// case WM_DESTROY:
|
|
// return FALSE;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
BYTE nPov=nPOV;
|
|
do
|
|
{
|
|
if(hRegion[nPov])
|
|
{
|
|
DeleteObject(hRegion[nPov]);
|
|
hRegion[nPov]=NULL;
|
|
}
|
|
}while(nPov--);
|
|
}
|
|
return 0;
|
|
case WM_PAINT:
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hDC = BeginPaint(hWnd, &ps);
|
|
|
|
// 1) Get client size information
|
|
SetMapMode(hDC, MM_TEXT);
|
|
RECT rClient;
|
|
GetClientRect(hWnd, &rClient);
|
|
BYTE nSizeX = (BYTE)rClient.right>>1;
|
|
BYTE nSizeY = (BYTE)rClient.bottom>>1;
|
|
|
|
// 2) Load the hub bitmap and display it
|
|
//PREFIX #WI226648. False positive. There is no leak. DeleteObject frees.
|
|
HBITMAP hPOVHubBitmap = (HBITMAP)LoadImage(ghInst, MAKEINTRESOURCE(IDB_POVHUB), IMAGE_BITMAP, 0, 0, NULL);
|
|
assert(hPOVHubBitmap);
|
|
DrawBitmap(hDC, hPOVHubBitmap, nSizeX-8, nSizeY-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, nSizeX, -nSizeY, NULL);
|
|
SetViewportOrgEx(hDC, nSizeX, nSizeY, NULL);
|
|
|
|
// 4) Draw the circle upon which the arrow seems to rotate
|
|
SelectObject(hDC, (HBRUSH)GetStockObject(NULL_BRUSH));
|
|
|
|
HPEN hPenOld = (HPEN)SelectObject(hDC, (HGDIOBJ)GetStockObject(DC_PEN));
|
|
SetDCPenColor( hDC, GetSysColor(COLOR_WINDOWTEXT) );
|
|
|
|
Ellipse(hDC, -CIRCLERADIUS, CIRCLERADIUS, CIRCLERADIUS, -CIRCLERADIUS);
|
|
SelectObject(hDC, hPenOld);
|
|
|
|
// 5) Paint the Arrow at the correct angle if POV active
|
|
BYTE nPov = nPOV;
|
|
HBRUSH hBrushOld;
|
|
|
|
do {
|
|
if( degrees[nPov] >= 0 ) {
|
|
hBrush[nPov] = CreateSolidBrush((nPov < 1) ? POV1_COLOUR :
|
|
(nPov < 2) ? POV2_COLOUR :
|
|
(nPov < 3) ? POV3_COLOUR : POV4_COLOUR);
|
|
|
|
hBrushOld = (HBRUSH)SelectObject(hDC, (HGDIOBJ)hBrush[nPov]);
|
|
|
|
|
|
|
|
assert(hBrushOld);
|
|
|
|
PaintRgn(hDC, hRegion[nPov]);
|
|
|
|
// GetRgnBox returns zero if it fails...
|
|
GetRgnBox(hRegion[nPov], prcOldRegionBox[nPov]);
|
|
SelectObject(hDC, hBrushOld);
|
|
|
|
if(hRegion[nPov])
|
|
{
|
|
DeleteObject(hRegion[nPov]);
|
|
hRegion[nPov]=NULL;
|
|
}
|
|
DeleteObject(hBrush[nPov] );
|
|
}
|
|
} while( nPov-- );
|
|
|
|
EndPaint(hWnd, &ps);
|
|
}
|
|
//PREFIX #WI226648. False positive. See above.
|
|
return(0);
|
|
|
|
default:
|
|
return(DefWindowProc(hWnd, iMsg,wParam, lParam));
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// 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 ATOM RegisterPOVClass()
|
|
{
|
|
LPWNDCLASSEX pPOVWndClass = (LPWNDCLASSEX)_alloca(sizeof(WNDCLASSEX));
|
|
assert (pPOVWndClass);
|
|
|
|
ZeroMemory(pPOVWndClass, sizeof(WNDCLASSEX));
|
|
|
|
pPOVWndClass->cbSize = sizeof(WNDCLASSEX);
|
|
pPOVWndClass->style = CS_HREDRAW; // | CS_VREDRAW;
|
|
pPOVWndClass->lpfnWndProc = POVWndProc;
|
|
pPOVWndClass->hInstance = ghInst;
|
|
pPOVWndClass->hbrBackground = NULL;
|
|
pPOVWndClass->lpszClassName = TEXT("POVHAT");
|
|
|
|
return(RegisterClassEx( pPOVWndClass ));
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// 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, BYTE xStart, BYTE yStart)
|
|
{
|
|
HDC 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));
|
|
|
|
// Be aware! This is the size of the current BITMAP...
|
|
// IF IT CHANGES THIS WILL FAIL!!!
|
|
POINT ptSize = {16, 16};
|
|
DPtoLP(hDC, &ptSize, 1);
|
|
|
|
POINT ptOrg = {0,0};
|
|
DPtoLP(hdcMem, &ptOrg, 1);
|
|
|
|
BitBlt(hDC, xStart, yStart, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCAND);
|
|
|
|
DeleteDC(hdcMem);
|
|
}
|
|
|
|
//~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=EOF=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
|