Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

562 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements the angle custom control, a circle with a line indicating
  4. // a rotation angle.
  5. //
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "hammer.h"
  9. #include "AngleBox.h"
  10. #include "hammer_mathlib.h"
  11. #include "CustomMessages.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. #pragma warning(disable: 4244)
  15. BEGIN_MESSAGE_MAP(CAngleBox, CWnd)
  16. //{{AFX_MSG_MAP(CAngleBox)
  17. ON_WM_MOUSEMOVE()
  18. ON_WM_LBUTTONUP()
  19. ON_WM_LBUTTONDOWN()
  20. ON_WM_PAINT()
  21. //}}AFX_MSG_MAP
  22. END_MESSAGE_MAP()
  23. //-----------------------------------------------------------------------------
  24. // Purpose: Constructor.
  25. //-----------------------------------------------------------------------------
  26. CAngleBox::CAngleBox(void)
  27. {
  28. m_vecAngles.Init();
  29. m_bDragging = false;
  30. m_pEdit = NULL;
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Purpose: Destructor.
  34. //-----------------------------------------------------------------------------
  35. CAngleBox::~CAngleBox()
  36. {
  37. }
  38. //-----------------------------------------------------------------------------
  39. // Purpose:
  40. // Input : nFlags -
  41. // point -
  42. //-----------------------------------------------------------------------------
  43. void CAngleBox::OnMouseMove(UINT nFlags, CPoint point)
  44. {
  45. if (m_bDragging)
  46. {
  47. //
  48. // Remove old angle line by redrawing it (XOR).
  49. //
  50. DrawAngleLine(&m_DragDC);
  51. //
  52. // Calculate new yaw.
  53. //
  54. int nNewYaw = fixang(180 - (int)lineangle(point.x, point.y, m_ptClientCenter.x, m_ptClientCenter.y));
  55. m_vecAngles.Init();
  56. m_vecAngles[YAW] = nNewYaw;
  57. //
  58. // Draw the new angle line.
  59. //
  60. DrawAngleLine(&m_DragDC);
  61. }
  62. CWnd::OnMouseMove(nFlags, point);
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. // Input : nFlags -
  67. // point -
  68. //-----------------------------------------------------------------------------
  69. void CAngleBox::OnLButtonUp(UINT nFlags, CPoint point)
  70. {
  71. // release dc
  72. if (m_bDragging)
  73. {
  74. ::ReleaseDC(m_hWnd, m_DragDC.Detach());
  75. m_bDragging = false;
  76. ReleaseCapture();
  77. //
  78. // They've explicity set the angles, so clear the different flag for
  79. // the multiselect case.
  80. //
  81. SetDifferent(false);
  82. GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0);
  83. }
  84. CWnd::OnLButtonUp(nFlags, point);
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Purpose:
  88. // Input : nFlags -
  89. // point -
  90. //-----------------------------------------------------------------------------
  91. void CAngleBox::OnLButtonDown(UINT nFlags, CPoint point)
  92. {
  93. //
  94. // Start dragging.
  95. //
  96. m_DragDC.Attach(::GetDC(m_hWnd));
  97. m_bDragging = true;
  98. SetCapture();
  99. CWnd::OnLButtonDown(nFlags, point);
  100. OnMouseMove(0, point);
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose:
  104. // Input : pDC -
  105. //-----------------------------------------------------------------------------
  106. void CAngleBox::DrawAngleLine(CDC *pDC)
  107. {
  108. if ((m_vecAngles[PITCH] != 0) || (m_vecAngles[ROLL] != 0) ||
  109. (m_vecAngles[YAW] < 0 || m_vecAngles[YAW] > 359) || m_bDifferent)
  110. {
  111. return;
  112. }
  113. pDC->SetROP2(R2_XORPEN);
  114. pDC->SelectStockObject(WHITE_PEN);
  115. CRect r;
  116. GetClientRect(r);
  117. m_ptClientCenter = r.CenterPoint();
  118. double rad = r.Width() / 2 - 3;
  119. CPoint pt;
  120. pt.x = m_ptClientCenter.x + sin(DEG2RAD((double)(m_vecAngles[YAW] + 90))) * rad + 0.5;
  121. pt.y = m_ptClientCenter.y + cos(DEG2RAD((double)(m_vecAngles[YAW] + 90))) * rad + 0.5;
  122. pDC->MoveTo(m_ptClientCenter);
  123. pDC->LineTo(pt);
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose: Returns the current state of the control as a keyvalue string.
  127. // Input : szAngles - Buffer to receive angles string.
  128. // Output : Returns 'szAngles'.
  129. //-----------------------------------------------------------------------------
  130. bool CAngleBox::GetAngles(QAngle &vecAngles)
  131. {
  132. if (m_bDifferent)
  133. {
  134. return false;
  135. }
  136. vecAngles = m_vecAngles;
  137. return(true);
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose: Returns the current state of the control as a keyvalue string.
  141. // Input : szAngles - Buffer to receive angles string.
  142. // Output : Returns 'szAngles'.
  143. //-----------------------------------------------------------------------------
  144. char *CAngleBox::GetAngles(char *szAngles)
  145. {
  146. QAngle vecAngles;
  147. GetAngles(vecAngles);
  148. sprintf(szAngles, "%g %g %g", (double)vecAngles[0], (double)vecAngles[1], (double)vecAngles[2]);
  149. return(szAngles);
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose: Returns a string indicating the current state of the angle control.
  153. // This is used for setting the text in the companion edit control.
  154. // Input : szBuf - Buffer to receive string.
  155. //-----------------------------------------------------------------------------
  156. char *CAngleBox::GetAngleEditText(char *szBuf)
  157. {
  158. szBuf[0] = '\0';
  159. if (m_bDifferent)
  160. {
  161. strcpy(szBuf, "(diff)");
  162. }
  163. else if ((m_vecAngles[PITCH] == 90) && (m_vecAngles[YAW] == 0) && (m_vecAngles[ROLL] == 0))
  164. {
  165. strcpy(szBuf, "Down");
  166. }
  167. else if ((m_vecAngles[PITCH] == -90) && (m_vecAngles[YAW] == 0) && (m_vecAngles[ROLL] == 0))
  168. {
  169. strcpy(szBuf, "Up");
  170. }
  171. else if (m_vecAngles[YAW] >= 0)
  172. {
  173. itoa((int)m_vecAngles[YAW], szBuf, 10);
  174. }
  175. return(szBuf);
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose: Called internally and by the linked combo box, this updates the angles
  179. // without updating the linked combo box.
  180. // Input : szAngles -
  181. // bRedraw -
  182. //-----------------------------------------------------------------------------
  183. void CAngleBox::SetAnglesInternal(const QAngle &vecAngles, bool bRedraw)
  184. {
  185. QAngle vecAngleSet = vecAngles;
  186. while (vecAngleSet[YAW] < 0)
  187. {
  188. vecAngleSet[YAW] += 360.0;
  189. }
  190. CDC *pDC = NULL;
  191. if (bRedraw)
  192. {
  193. //
  194. // Erase the old line.
  195. //
  196. Assert(::IsWindow(m_hWnd));
  197. pDC = GetDC();
  198. if (pDC != NULL)
  199. {
  200. DrawAngleLine(pDC);
  201. }
  202. }
  203. //
  204. // Update the data member.
  205. //
  206. m_vecAngles = vecAngleSet;
  207. if ((bRedraw) && (pDC != NULL))
  208. {
  209. //
  210. // Draw the new line.
  211. //
  212. DrawAngleLine(pDC);
  213. ReleaseDC(pDC);
  214. }
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Purpose: Called from the client code, this sets our angles and updates the
  218. // linked combo box.
  219. // Input : szAngles -
  220. // bRedraw -
  221. //-----------------------------------------------------------------------------
  222. void CAngleBox::SetAngles(const QAngle &vecAngles, bool bRedraw)
  223. {
  224. SetAnglesInternal(vecAngles, bRedraw);
  225. UpdateAngleEditText();
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose: Called from the client code, this sets our angles via a string and
  229. // updates the linked combo box.
  230. // Input : szAngles -
  231. // bRedraw -
  232. //-----------------------------------------------------------------------------
  233. void CAngleBox::SetAngles(const char *szAngles, bool bRedraw)
  234. {
  235. QAngle vecAngles(0, 0, 0);
  236. sscanf(szAngles, "%f %f %f", &vecAngles[PITCH], &vecAngles[YAW], &vecAngles[ROLL]);
  237. SetAngles(vecAngles, bRedraw);
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose: Called internally and by the linked combo box, this sets our
  241. // 'different' state without updating the linked combo box.
  242. // Input : bDifferent -
  243. // bRedraw -
  244. //-----------------------------------------------------------------------------
  245. void CAngleBox::SetDifferentInternal(bool bDifferent, bool bRedraw)
  246. {
  247. CDC *pDC = NULL;
  248. if (bRedraw)
  249. {
  250. //
  251. // Erase the old line.
  252. //
  253. Assert(::IsWindow(m_hWnd));
  254. pDC = GetDC();
  255. if (pDC != NULL)
  256. {
  257. DrawAngleLine(pDC);
  258. }
  259. }
  260. //
  261. // Update the data member.
  262. //
  263. m_bDifferent = bDifferent;
  264. if ((bRedraw) && (pDC != NULL))
  265. {
  266. //
  267. // Draw the new line.
  268. //
  269. DrawAngleLine(pDC);
  270. ReleaseDC(pDC);
  271. }
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Purpose: Sets our state to indicate multiselect of objects with different
  275. // angles to avoid mucking with the angles unless they explicitly set
  276. // them to something new.
  277. //-----------------------------------------------------------------------------
  278. void CAngleBox::SetDifferent(bool bDifferent, bool bRedraw)
  279. {
  280. SetDifferentInternal(bDifferent, bRedraw);
  281. UpdateAngleEditText();
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Purpose:
  285. //-----------------------------------------------------------------------------
  286. void CAngleBox::OnPaint(void)
  287. {
  288. PAINTSTRUCT ps;
  289. CDC *pDC = BeginPaint(&ps);
  290. if (pDC == NULL)
  291. {
  292. return;
  293. }
  294. CBrush brushWindow(GetSysColor(COLOR_3DFACE));
  295. CBrush brushBlack(RGB(0, 0, 0));
  296. CBrush *pBackBrush = IsWindowEnabled() ? &brushBlack : &brushWindow;
  297. CRect r;
  298. GetClientRect(r);
  299. //
  300. // Fill with the window color.
  301. //
  302. pDC->FillRect(&r, &brushWindow);
  303. //
  304. // Draw a 3D circle.
  305. //
  306. m_ptClientCenter = r.CenterPoint();
  307. pDC->SelectStockObject(NULL_PEN);
  308. pDC->SelectObject(pBackBrush);
  309. pDC->Ellipse(r);
  310. CPen hi(PS_SOLID, 2, GetSysColor(COLOR_3DSHADOW));
  311. CPen lo(PS_SOLID, 2, GetSysColor(COLOR_3DHILIGHT));
  312. pDC->SelectObject(hi);
  313. pDC->Arc(r, CPoint(r.right, r.top), CPoint(r.left, r.bottom));
  314. pDC->SelectObject(lo);
  315. pDC->Arc(r, CPoint(r.left, r.bottom), CPoint(r.right, r.top));
  316. //
  317. // Draw center point.
  318. //
  319. pDC->SetPixel(m_ptClientCenter, RGB(0xff, 0xff, 0xff));
  320. //
  321. // Draw line indicating angles direction.
  322. //
  323. if (IsWindowEnabled())
  324. {
  325. DrawAngleLine(pDC);
  326. }
  327. EndPaint(&ps);
  328. }
  329. //-----------------------------------------------------------------------------
  330. // Purpose: Enables or disables the angles controls.
  331. //-----------------------------------------------------------------------------
  332. void CAngleBox::Enable(bool bEnable)
  333. {
  334. if (bEnable)
  335. {
  336. EnableWindow(TRUE);
  337. if (m_pEdit)
  338. {
  339. m_pEdit->EnableWindow(TRUE);
  340. }
  341. }
  342. else
  343. {
  344. EnableWindow(FALSE);
  345. if (m_pEdit)
  346. {
  347. m_pEdit->EnableWindow(FALSE);
  348. }
  349. }
  350. Invalidate(FALSE);
  351. UpdateWindow();
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose: Hides or shows the angles controls.
  355. //-----------------------------------------------------------------------------
  356. void CAngleBox::Show(bool bShow)
  357. {
  358. if (bShow)
  359. {
  360. ShowWindow(SW_SHOW);
  361. if (m_pEdit)
  362. {
  363. m_pEdit->ShowWindow(SW_SHOW);
  364. }
  365. }
  366. else
  367. {
  368. ShowWindow(SW_HIDE);
  369. if (m_pEdit)
  370. {
  371. m_pEdit->ShowWindow(SW_HIDE);
  372. }
  373. }
  374. Invalidate(FALSE);
  375. UpdateWindow();
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Purpose: Updates the text in the angle combo to reflect the current angles
  379. // in the angles control.
  380. //-----------------------------------------------------------------------------
  381. void CAngleBox::UpdateAngleEditText(void)
  382. {
  383. if (m_pEdit)
  384. {
  385. char szBuf[20];
  386. GetAngleEditText(szBuf);
  387. m_pEdit->SetAnglesInternal(szBuf);
  388. }
  389. }
  390. BEGIN_MESSAGE_MAP(CAngleCombo, CWnd)
  391. //{{AFX_MSG_MAP(CAngleBox)
  392. ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnChangeAngleEdit)
  393. ON_CONTROL_REFLECT(CBN_SELENDOK, OnSelChangeAngleEdit)
  394. //}}AFX_MSG_MAP
  395. END_MESSAGE_MAP()
  396. //-----------------------------------------------------------------------------
  397. // Purpose: Construktor.
  398. //-----------------------------------------------------------------------------
  399. CAngleCombo::CAngleCombo()
  400. : CComboBox()
  401. {
  402. m_pBox = NULL;
  403. m_bEnableUpdate = true;
  404. }
  405. //-----------------------------------------------------------------------------
  406. // Purpose:
  407. // Input : *szAngles -
  408. //-----------------------------------------------------------------------------
  409. void CAngleCombo::SetAnglesInternal(const char *szAngles)
  410. {
  411. m_bEnableUpdate = false;
  412. SetWindowText(szAngles);
  413. m_bEnableUpdate = true;
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose: Handles a change in the contents of the angle edit control.
  417. //-----------------------------------------------------------------------------
  418. void CAngleCombo::OnChangeAngleEdit(void)
  419. {
  420. if (m_bEnableUpdate)
  421. {
  422. char buf[64];
  423. GetWindowText(buf, 64);
  424. UpdateAngleBox(buf);
  425. GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0);
  426. }
  427. }
  428. //-----------------------------------------------------------------------------
  429. // Purpose: Handles a change in the current selection of the angle edit combo.
  430. //-----------------------------------------------------------------------------
  431. void CAngleCombo::OnSelChangeAngleEdit(void)
  432. {
  433. char buf[64];
  434. int nSel = GetCurSel();
  435. GetLBText(nSel, buf);
  436. UpdateAngleBox(buf);
  437. GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0);
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Purpose: Updates angle box with the settings from the combo box. Call the
  441. // internal functions so we don't get a reflected notification, mucking
  442. // up our state.
  443. //-----------------------------------------------------------------------------
  444. void CAngleCombo::UpdateAngleBox(char *szText)
  445. {
  446. if (m_pBox)
  447. {
  448. m_pBox->SetDifferentInternal(false);
  449. if (V_isdigit(szText[0]))
  450. {
  451. QAngle vecAngles(0, atoi(szText), 0);
  452. m_pBox->SetAnglesInternal(vecAngles, true);
  453. }
  454. else if (!stricmp(szText, "down"))
  455. {
  456. m_pBox->SetAnglesInternal(QAngle(90, 0, 0), true);
  457. }
  458. else
  459. {
  460. m_pBox->SetAnglesInternal(QAngle(-90, 0, 0), true);
  461. }
  462. }
  463. }