|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements the angle custom control, a circle with a line indicating
// a rotation angle.
//
//=============================================================================//
#include "stdafx.h"
#include "hammer.h"
#include "AngleBox.h"
#include "hammer_mathlib.h"
#include "CustomMessages.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#pragma warning(disable: 4244)
BEGIN_MESSAGE_MAP(CAngleBox, CWnd) //{{AFX_MSG_MAP(CAngleBox)
ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_WM_LBUTTONDOWN() ON_WM_PAINT() //}}AFX_MSG_MAP
END_MESSAGE_MAP()
//-----------------------------------------------------------------------------
// Purpose: Constructor.
//-----------------------------------------------------------------------------
CAngleBox::CAngleBox(void) { m_vecAngles.Init(); m_bDragging = false; m_pEdit = NULL; }
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CAngleBox::~CAngleBox() { }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nFlags -
// point -
//-----------------------------------------------------------------------------
void CAngleBox::OnMouseMove(UINT nFlags, CPoint point) { if (m_bDragging) { //
// Remove old angle line by redrawing it (XOR).
//
DrawAngleLine(&m_DragDC);
//
// Calculate new yaw.
//
int nNewYaw = fixang(180 - (int)lineangle(point.x, point.y, m_ptClientCenter.x, m_ptClientCenter.y)); m_vecAngles.Init(); m_vecAngles[YAW] = nNewYaw; //
// Draw the new angle line.
//
DrawAngleLine(&m_DragDC); }
CWnd::OnMouseMove(nFlags, point); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nFlags -
// point -
//-----------------------------------------------------------------------------
void CAngleBox::OnLButtonUp(UINT nFlags, CPoint point) { // release dc
if (m_bDragging) { ::ReleaseDC(m_hWnd, m_DragDC.Detach()); m_bDragging = false; ReleaseCapture();
//
// They've explicity set the angles, so clear the different flag for
// the multiselect case.
//
SetDifferent(false);
GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0); } CWnd::OnLButtonUp(nFlags, point); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : nFlags -
// point -
//-----------------------------------------------------------------------------
void CAngleBox::OnLButtonDown(UINT nFlags, CPoint point) { //
// Start dragging.
//
m_DragDC.Attach(::GetDC(m_hWnd)); m_bDragging = true; SetCapture();
CWnd::OnLButtonDown(nFlags, point);
OnMouseMove(0, point); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : pDC -
//-----------------------------------------------------------------------------
void CAngleBox::DrawAngleLine(CDC *pDC) { if ((m_vecAngles[PITCH] != 0) || (m_vecAngles[ROLL] != 0) || (m_vecAngles[YAW] < 0 || m_vecAngles[YAW] > 359) || m_bDifferent) { return; }
pDC->SetROP2(R2_XORPEN); pDC->SelectStockObject(WHITE_PEN);
CRect r; GetClientRect(r); m_ptClientCenter = r.CenterPoint();
double rad = r.Width() / 2 - 3;
CPoint pt; pt.x = m_ptClientCenter.x + sin(DEG2RAD((double)(m_vecAngles[YAW] + 90))) * rad + 0.5; pt.y = m_ptClientCenter.y + cos(DEG2RAD((double)(m_vecAngles[YAW] + 90))) * rad + 0.5;
pDC->MoveTo(m_ptClientCenter); pDC->LineTo(pt); }
//-----------------------------------------------------------------------------
// Purpose: Returns the current state of the control as a keyvalue string.
// Input : szAngles - Buffer to receive angles string.
// Output : Returns 'szAngles'.
//-----------------------------------------------------------------------------
bool CAngleBox::GetAngles(QAngle &vecAngles) { if (m_bDifferent) { return false; }
vecAngles = m_vecAngles;
return(true); }
//-----------------------------------------------------------------------------
// Purpose: Returns the current state of the control as a keyvalue string.
// Input : szAngles - Buffer to receive angles string.
// Output : Returns 'szAngles'.
//-----------------------------------------------------------------------------
char *CAngleBox::GetAngles(char *szAngles) { QAngle vecAngles; GetAngles(vecAngles); sprintf(szAngles, "%g %g %g", (double)vecAngles[0], (double)vecAngles[1], (double)vecAngles[2]); return(szAngles); }
//-----------------------------------------------------------------------------
// Purpose: Returns a string indicating the current state of the angle control.
// This is used for setting the text in the companion edit control.
// Input : szBuf - Buffer to receive string.
//-----------------------------------------------------------------------------
char *CAngleBox::GetAngleEditText(char *szBuf) { szBuf[0] = '\0';
if (m_bDifferent) { strcpy(szBuf, "(diff)"); } else if ((m_vecAngles[PITCH] == 90) && (m_vecAngles[YAW] == 0) && (m_vecAngles[ROLL] == 0)) { strcpy(szBuf, "Down"); } else if ((m_vecAngles[PITCH] == -90) && (m_vecAngles[YAW] == 0) && (m_vecAngles[ROLL] == 0)) { strcpy(szBuf, "Up"); } else if (m_vecAngles[YAW] >= 0) { itoa((int)m_vecAngles[YAW], szBuf, 10); }
return(szBuf); }
//-----------------------------------------------------------------------------
// Purpose: Called internally and by the linked combo box, this updates the angles
// without updating the linked combo box.
// Input : szAngles -
// bRedraw -
//-----------------------------------------------------------------------------
void CAngleBox::SetAnglesInternal(const QAngle &vecAngles, bool bRedraw) { QAngle vecAngleSet = vecAngles; while (vecAngleSet[YAW] < 0) { vecAngleSet[YAW] += 360.0; }
CDC *pDC = NULL;
if (bRedraw) { //
// Erase the old line.
//
Assert(::IsWindow(m_hWnd)); pDC = GetDC(); if (pDC != NULL) { DrawAngleLine(pDC); } }
//
// Update the data member.
//
m_vecAngles = vecAngleSet;
if ((bRedraw) && (pDC != NULL)) { //
// Draw the new line.
//
DrawAngleLine(pDC); ReleaseDC(pDC); } }
//-----------------------------------------------------------------------------
// Purpose: Called from the client code, this sets our angles and updates the
// linked combo box.
// Input : szAngles -
// bRedraw -
//-----------------------------------------------------------------------------
void CAngleBox::SetAngles(const QAngle &vecAngles, bool bRedraw) { SetAnglesInternal(vecAngles, bRedraw); UpdateAngleEditText(); }
//-----------------------------------------------------------------------------
// Purpose: Called from the client code, this sets our angles via a string and
// updates the linked combo box.
// Input : szAngles -
// bRedraw -
//-----------------------------------------------------------------------------
void CAngleBox::SetAngles(const char *szAngles, bool bRedraw) { QAngle vecAngles(0, 0, 0); sscanf(szAngles, "%f %f %f", &vecAngles[PITCH], &vecAngles[YAW], &vecAngles[ROLL]); SetAngles(vecAngles, bRedraw); }
//-----------------------------------------------------------------------------
// Purpose: Called internally and by the linked combo box, this sets our
// 'different' state without updating the linked combo box.
// Input : bDifferent -
// bRedraw -
//-----------------------------------------------------------------------------
void CAngleBox::SetDifferentInternal(bool bDifferent, bool bRedraw) { CDC *pDC = NULL;
if (bRedraw) { //
// Erase the old line.
//
Assert(::IsWindow(m_hWnd)); pDC = GetDC(); if (pDC != NULL) { DrawAngleLine(pDC); } }
//
// Update the data member.
//
m_bDifferent = bDifferent;
if ((bRedraw) && (pDC != NULL)) { //
// Draw the new line.
//
DrawAngleLine(pDC); ReleaseDC(pDC); } }
//-----------------------------------------------------------------------------
// Purpose: Sets our state to indicate multiselect of objects with different
// angles to avoid mucking with the angles unless they explicitly set
// them to something new.
//-----------------------------------------------------------------------------
void CAngleBox::SetDifferent(bool bDifferent, bool bRedraw) { SetDifferentInternal(bDifferent, bRedraw); UpdateAngleEditText(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAngleBox::OnPaint(void) { PAINTSTRUCT ps; CDC *pDC = BeginPaint(&ps);
if (pDC == NULL) { return; }
CBrush brushWindow(GetSysColor(COLOR_3DFACE)); CBrush brushBlack(RGB(0, 0, 0));
CBrush *pBackBrush = IsWindowEnabled() ? &brushBlack : &brushWindow;
CRect r; GetClientRect(r);
//
// Fill with the window color.
//
pDC->FillRect(&r, &brushWindow);
//
// Draw a 3D circle.
//
m_ptClientCenter = r.CenterPoint(); pDC->SelectStockObject(NULL_PEN); pDC->SelectObject(pBackBrush); pDC->Ellipse(r);
CPen hi(PS_SOLID, 2, GetSysColor(COLOR_3DSHADOW)); CPen lo(PS_SOLID, 2, GetSysColor(COLOR_3DHILIGHT));
pDC->SelectObject(hi); pDC->Arc(r, CPoint(r.right, r.top), CPoint(r.left, r.bottom)); pDC->SelectObject(lo); pDC->Arc(r, CPoint(r.left, r.bottom), CPoint(r.right, r.top));
//
// Draw center point.
//
pDC->SetPixel(m_ptClientCenter, RGB(0xff, 0xff, 0xff));
//
// Draw line indicating angles direction.
//
if (IsWindowEnabled()) { DrawAngleLine(pDC); }
EndPaint(&ps); }
//-----------------------------------------------------------------------------
// Purpose: Enables or disables the angles controls.
//-----------------------------------------------------------------------------
void CAngleBox::Enable(bool bEnable) { if (bEnable) { EnableWindow(TRUE);
if (m_pEdit) { m_pEdit->EnableWindow(TRUE); } } else { EnableWindow(FALSE); if (m_pEdit) { m_pEdit->EnableWindow(FALSE); } }
Invalidate(FALSE); UpdateWindow(); }
//-----------------------------------------------------------------------------
// Purpose: Hides or shows the angles controls.
//-----------------------------------------------------------------------------
void CAngleBox::Show(bool bShow) { if (bShow) { ShowWindow(SW_SHOW); if (m_pEdit) { m_pEdit->ShowWindow(SW_SHOW); } } else { ShowWindow(SW_HIDE);
if (m_pEdit) { m_pEdit->ShowWindow(SW_HIDE); } }
Invalidate(FALSE); UpdateWindow(); }
//-----------------------------------------------------------------------------
// Purpose: Updates the text in the angle combo to reflect the current angles
// in the angles control.
//-----------------------------------------------------------------------------
void CAngleBox::UpdateAngleEditText(void) { if (m_pEdit) { char szBuf[20]; GetAngleEditText(szBuf); m_pEdit->SetAnglesInternal(szBuf); } }
BEGIN_MESSAGE_MAP(CAngleCombo, CWnd) //{{AFX_MSG_MAP(CAngleBox)
ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnChangeAngleEdit) ON_CONTROL_REFLECT(CBN_SELENDOK, OnSelChangeAngleEdit) //}}AFX_MSG_MAP
END_MESSAGE_MAP()
//-----------------------------------------------------------------------------
// Purpose: Construktor.
//-----------------------------------------------------------------------------
CAngleCombo::CAngleCombo() : CComboBox() { m_pBox = NULL; m_bEnableUpdate = true; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *szAngles -
//-----------------------------------------------------------------------------
void CAngleCombo::SetAnglesInternal(const char *szAngles) { m_bEnableUpdate = false; SetWindowText(szAngles); m_bEnableUpdate = true; }
//-----------------------------------------------------------------------------
// Purpose: Handles a change in the contents of the angle edit control.
//-----------------------------------------------------------------------------
void CAngleCombo::OnChangeAngleEdit(void) { if (m_bEnableUpdate) { char buf[64]; GetWindowText(buf, 64); UpdateAngleBox(buf);
GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0); } }
//-----------------------------------------------------------------------------
// Purpose: Handles a change in the current selection of the angle edit combo.
//-----------------------------------------------------------------------------
void CAngleCombo::OnSelChangeAngleEdit(void) { char buf[64]; int nSel = GetCurSel(); GetLBText(nSel, buf); UpdateAngleBox(buf);
GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0); }
//-----------------------------------------------------------------------------
// Purpose: Updates angle box with the settings from the combo box. Call the
// internal functions so we don't get a reflected notification, mucking
// up our state.
//-----------------------------------------------------------------------------
void CAngleCombo::UpdateAngleBox(char *szText) { if (m_pBox) { m_pBox->SetDifferentInternal(false);
if (V_isdigit(szText[0])) { QAngle vecAngles(0, atoi(szText), 0); m_pBox->SetAnglesInternal(vecAngles, true); } else if (!stricmp(szText, "down")) { m_pBox->SetAnglesInternal(QAngle(90, 0, 0), true); } else { m_pBox->SetAnglesInternal(QAngle(-90, 0, 0), true); } } }
|