Counter Strike : Global Offensive Source Code
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.

518 lines
12 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "History.h"
  9. #include "MainFrm.h"
  10. #include "MapDefs.h"
  11. #include "MapDoc.h"
  12. #include "MapView2D.h"
  13. #include "MapView3D.h"
  14. #include "Options.h"
  15. #include "StatusBarIDs.h"
  16. #include "ToolBlock.h"
  17. #include "ToolManager.h"
  18. #include "vgui/Cursor.h"
  19. #include "Selection.h"
  20. class CToolBlockMessageWnd : public CWnd
  21. {
  22. public:
  23. bool Create(void);
  24. void PreMenu2D(CToolBlock *pTool, CMapView2D *pView);
  25. protected:
  26. //{{AFX_MSG_MAP(CToolBlockMessageWnd)
  27. afx_msg void OnCreateObject();
  28. //}}AFX_MSG
  29. DECLARE_MESSAGE_MAP()
  30. private:
  31. CToolBlock *m_pToolBlock;
  32. CMapView2D *m_pView2D;
  33. };
  34. static CToolBlockMessageWnd s_wndToolMessage;
  35. static const char *g_pszClassName = "ValveEditor_BlockToolWnd";
  36. BEGIN_MESSAGE_MAP(CToolBlockMessageWnd, CWnd)
  37. //{{AFX_MSG_MAP(CToolMessageWnd)
  38. ON_COMMAND(ID_CREATEOBJECT, OnCreateObject)
  39. //}}AFX_MSG_MAP
  40. END_MESSAGE_MAP()
  41. //-----------------------------------------------------------------------------
  42. // Purpose: Creates the hidden window that receives context menu commands for the
  43. // block tool.
  44. // Output : Returns true on success, false on failure.
  45. //-----------------------------------------------------------------------------
  46. bool CToolBlockMessageWnd::Create(void)
  47. {
  48. WNDCLASS wndcls;
  49. memset(&wndcls, 0, sizeof(WNDCLASS));
  50. wndcls.lpfnWndProc = AfxWndProc;
  51. wndcls.hInstance = AfxGetInstanceHandle();
  52. wndcls.lpszClassName = g_pszClassName;
  53. if (!AfxRegisterClass(&wndcls))
  54. {
  55. return(false);
  56. }
  57. return(CWnd::CreateEx(0, g_pszClassName, g_pszClassName, 0, CRect(0, 0, 10, 10), NULL, 0) == TRUE);
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose: Attaches the block tool to this window before activating the context
  61. // menu.
  62. //-----------------------------------------------------------------------------
  63. void CToolBlockMessageWnd::PreMenu2D(CToolBlock *pToolBlock, CMapView2D *pView)
  64. {
  65. Assert(pToolBlock != NULL);
  66. m_pToolBlock = pToolBlock;
  67. m_pView2D = pView;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose:
  71. //-----------------------------------------------------------------------------
  72. void CToolBlockMessageWnd::OnCreateObject()
  73. {
  74. m_pToolBlock->CreateMapObject(m_pView2D);
  75. }
  76. //-----------------------------------------------------------------------------
  77. // Purpose: Constructor.
  78. //-----------------------------------------------------------------------------
  79. CToolBlock::CToolBlock(void)
  80. {
  81. // We always show our dimensions when we render.
  82. SetDrawFlags(GetDrawFlags() | Box3D::boundstext);
  83. SetDrawColors(Options.colors.clrToolHandle, Options.colors.clrToolBlock);
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose: Destructor.
  87. //-----------------------------------------------------------------------------
  88. CToolBlock::~CToolBlock(void)
  89. {
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose: Handles key down events in the 2D view.
  93. // Input : Per CWnd::OnKeyDown.
  94. // Output : Returns true if the message was handled, false if not.
  95. //-----------------------------------------------------------------------------
  96. bool CToolBlock::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  97. {
  98. switch (nChar)
  99. {
  100. case VK_RETURN:
  101. {
  102. if ( !IsEmpty() )
  103. {
  104. CreateMapObject(pView);
  105. }
  106. return true;
  107. }
  108. case VK_ESCAPE:
  109. {
  110. OnEscape();
  111. return true;
  112. }
  113. }
  114. return false;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose: Handles context menu events in the 2D view.
  118. // Input : Per CWnd::OnContextMenu.
  119. // Output : Returns true if the message was handled, false if not.
  120. //-----------------------------------------------------------------------------
  121. bool CToolBlock::OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  122. {
  123. static CMenu menu, menuCreate;
  124. static bool bInit = false;
  125. if (!bInit)
  126. {
  127. bInit = true;
  128. // Create the menu.
  129. menu.LoadMenu(IDR_POPUPS);
  130. menuCreate.Attach(::GetSubMenu(menu.m_hMenu, 1));
  131. // Create the window that handles menu messages.
  132. s_wndToolMessage.Create();
  133. }
  134. if ( !pView->PointInClientRect(vPoint) )
  135. {
  136. return false;
  137. }
  138. if ( !IsEmpty() )
  139. {
  140. if ( HitTest(pView, vPoint, false) )
  141. {
  142. CPoint ptScreen( vPoint.x,vPoint.y);
  143. pView->ClientToScreen(&ptScreen);
  144. s_wndToolMessage.PreMenu2D(this, pView);
  145. menuCreate.TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, &s_wndToolMessage);
  146. }
  147. }
  148. return true;
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Purpose: Handles left mouse button down events in the 2D view.
  152. // Input : Per CWnd::OnLButtonDown.
  153. // Output : Returns true if the message was handled, false if not.
  154. //-----------------------------------------------------------------------------
  155. bool CToolBlock::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  156. {
  157. Tool3D::OnLMouseDown3D(pView, nFlags, vPoint);
  158. //
  159. // If we have a box, see if they clicked on any part of it.
  160. //
  161. if ( !IsEmpty() )
  162. {
  163. if ( HitTest( pView, vPoint, true ) )
  164. {
  165. // just update current block
  166. StartTranslation( pView, vPoint, m_LastHitTestHandle );
  167. return true;
  168. }
  169. }
  170. return true;
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Purpose: Handles left mouse button down events in the 2D view.
  174. // Input : Per CWnd::OnLButtonDown.
  175. // Output : Returns true if the message was handled, false if not.
  176. //-----------------------------------------------------------------------------
  177. bool CToolBlock::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  178. {
  179. Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
  180. // If we have a box, see if they clicked on any part of it.
  181. if ( !IsEmpty() )
  182. {
  183. if ( HitTest( pView, vPoint, true ) )
  184. {
  185. // just update current block
  186. StartTranslation( pView, vPoint, m_LastHitTestHandle );
  187. return true;
  188. }
  189. }
  190. return true;
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose: Handles left mouse button up events in the 2D view.
  194. // Input : Per CWnd::OnLButtonUp.
  195. // Output : Returns true if the message was handled, false if not.
  196. //-----------------------------------------------------------------------------
  197. bool CToolBlock::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  198. {
  199. Tool3D::OnLMouseUp2D(pView, nFlags, vPoint);
  200. if (IsTranslating())
  201. {
  202. FinishTranslation(true);
  203. }
  204. m_pDocument->UpdateStatusbar();
  205. return true;
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose: Handles left mouse button up events in the 2D view.
  209. // Input : Per CWnd::OnLButtonUp.
  210. // Output : Returns true if the message was handled, false if not.
  211. //-----------------------------------------------------------------------------
  212. bool CToolBlock::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  213. {
  214. Tool3D::OnLMouseUp3D(pView, nFlags, vPoint);
  215. if (IsTranslating())
  216. {
  217. FinishTranslation(true);
  218. }
  219. m_pDocument->UpdateStatusbar();
  220. return true;
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose: Handles mouse move events in the 2D view.
  224. // Input : Per CWnd::OnMouseMove.
  225. // Output : Returns true if the message was handled, false if not.
  226. //-----------------------------------------------------------------------------
  227. bool CToolBlock::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  228. {
  229. vgui::HCursor hCursor = vgui::dc_arrow;
  230. // Snap it to the grid.
  231. unsigned int uConstraints = GetConstraints( nFlags );
  232. Tool3D::OnMouseMove2D(pView, nFlags, vPoint);
  233. //
  234. //
  235. // Convert to world coords.
  236. //
  237. Vector vecWorld;
  238. pView->ClientToWorld(vecWorld, vPoint);
  239. //
  240. // Update status bar position display.
  241. //
  242. char szBuf[128];
  243. if ( uConstraints & constrainSnap )
  244. m_pDocument->Snap(vecWorld,uConstraints);
  245. sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert]);
  246. SetStatusText(SBI_COORDS, szBuf);
  247. if ( IsTranslating() )
  248. {
  249. Tool3D::UpdateTranslation( pView, vPoint, uConstraints);
  250. hCursor = vgui::dc_none;
  251. }
  252. else if ( m_bMouseDragged[MOUSE_LEFT] )
  253. {
  254. // Starting a new box. Build a starting point for the drag.
  255. pView->SetCursor( "Resource/block.cur" );
  256. Vector vecStart;
  257. pView->ClientToWorld(vecStart, m_vMouseStart[MOUSE_LEFT] );
  258. // Snap it to the grid.
  259. if ( uConstraints & constrainSnap )
  260. m_pDocument->Snap( vecStart, uConstraints);
  261. // Start the new box with the extents of the last selected thing.
  262. Vector bmins,bmaxs;
  263. m_pDocument->GetSelection()->GetLastValidBounds(bmins, bmaxs);
  264. vecStart[pView->axThird] = bmins[pView->axThird];
  265. StartNew(pView, vPoint, vecStart, pView->GetViewAxis() * (bmaxs-bmins) );
  266. }
  267. else if ( !IsEmpty() )
  268. {
  269. // If the cursor is on a handle, set it to a cross.
  270. if ( HitTest(pView, vPoint, true) )
  271. {
  272. hCursor = UpdateCursor( pView, m_LastHitTestHandle, m_TranslateMode );
  273. }
  274. }
  275. if ( hCursor != vgui::dc_none )
  276. pView->SetCursor( hCursor );
  277. return true;
  278. }
  279. bool CToolBlock::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  280. {
  281. Tool3D::OnMouseMove3D(pView, nFlags, vPoint);
  282. if ( IsTranslating() )
  283. {
  284. unsigned int uConstraints = GetConstraints( nFlags );
  285. // If they are dragging with a valid handle, update the views.
  286. Tool3D::UpdateTranslation( pView, vPoint, uConstraints );
  287. }
  288. return true;
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose: Handles key down events in the 3D view.
  292. // Input : Per CWnd::OnKeyDown.
  293. // Output : Returns true if the message was handled, false if not.
  294. //-----------------------------------------------------------------------------
  295. bool CToolBlock::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  296. {
  297. switch (nChar)
  298. {
  299. case VK_RETURN:
  300. {
  301. if ( !IsEmpty() )
  302. {
  303. CreateMapObject(pView);
  304. }
  305. return true;
  306. }
  307. case VK_ESCAPE:
  308. {
  309. OnEscape();
  310. return true;
  311. }
  312. }
  313. return false;
  314. }
  315. //-----------------------------------------------------------------------------
  316. // Purpose: Handles the escape key in the 2D or 3D views.
  317. //-----------------------------------------------------------------------------
  318. void CToolBlock::OnEscape(void)
  319. {
  320. //
  321. // If we have nothing blocked, go back to the pointer tool.
  322. //
  323. if ( IsEmpty() )
  324. {
  325. ToolManager()->SetTool(TOOL_POINTER);
  326. }
  327. //
  328. // We're blocking out a region, so clear it.
  329. //
  330. else
  331. {
  332. SetEmpty();
  333. }
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Purpose: Creates a solid in the given view.
  337. //-----------------------------------------------------------------------------
  338. void CToolBlock::CreateMapObject(CMapView *pView)
  339. {
  340. CMapWorld *pWorld = m_pDocument->GetMapWorld();
  341. if (!(bmaxs[0] - bmins[0]) || !(bmaxs[1] - bmins[1]) || !(bmaxs[2] - bmins[2]))
  342. {
  343. AfxMessageBox("The box is empty.");
  344. SetEmpty();
  345. return;
  346. }
  347. BoundBox NewBox = *this;
  348. if (Options.view2d.bOrientPrimitives)
  349. {
  350. switch (pView->GetDrawType())
  351. {
  352. case VIEW2D_XY:
  353. {
  354. break;
  355. }
  356. case VIEW2D_YZ:
  357. {
  358. NewBox.Rotate90(AXIS_Y);
  359. break;
  360. }
  361. case VIEW2D_XZ:
  362. {
  363. NewBox.Rotate90(AXIS_X);
  364. break;
  365. }
  366. }
  367. }
  368. // Create the object within the given bounding box.
  369. CMapClass *pObject = GetMainWnd()->m_ObjectBar.CreateInBox(&NewBox, pView);
  370. if (pObject == NULL)
  371. {
  372. SetEmpty();
  373. return;
  374. }
  375. m_pDocument->ExpandObjectKeywords(pObject, pWorld);
  376. GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Object");
  377. m_pDocument->AddObjectToWorld(pObject);
  378. //
  379. // Do we need to rotate this object based on the view we created it in?
  380. //
  381. if (Options.view2d.bOrientPrimitives)
  382. {
  383. Vector center;
  384. pObject->GetBoundsCenter( center );
  385. QAngle angles(0, 0, 0);
  386. switch (pView->GetDrawType())
  387. {
  388. case VIEW2D_XY:
  389. {
  390. break;
  391. }
  392. case VIEW2D_YZ:
  393. {
  394. angles[1] = 90.f;
  395. pObject->TransRotate(center, angles);
  396. break;
  397. }
  398. case VIEW2D_XZ:
  399. {
  400. angles[0] = 90.f;
  401. pObject->TransRotate(center, angles);
  402. break;
  403. }
  404. }
  405. }
  406. GetHistory()->KeepNew(pObject);
  407. // Select the new object.
  408. m_pDocument->SelectObject(pObject, scClear|scSelect|scSaveChanges);
  409. m_pDocument->SetModifiedFlag();
  410. SetEmpty();
  411. ResetBounds();
  412. }