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.

470 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Tool used for picking entities. This is used anywhere a field that
  4. // contains an entity name is found.
  5. //
  6. // Left click - single select entity
  7. // +Ctrl - multiselect a single entity
  8. //
  9. //=============================================================================//
  10. #include "stdafx.h"
  11. #include "resource.h"
  12. #include "ToolPickEntity.h"
  13. #include "MapViewLogical.h"
  14. #include "MapView3D.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include <tier0/memdbgon.h>
  17. //-----------------------------------------------------------------------------
  18. // Purpose: Constructor. Inits data members.
  19. //-----------------------------------------------------------------------------
  20. CToolPickEntity::CToolPickEntity(void)
  21. {
  22. m_pNotifyTarget = NULL;
  23. m_bAllowMultiSelect = false;
  24. }
  25. //-----------------------------------------------------------------------------
  26. // Purpose: Destructor.
  27. //-----------------------------------------------------------------------------
  28. CToolPickEntity::~CToolPickEntity(void)
  29. {
  30. }
  31. //-----------------------------------------------------------------------------
  32. // Purpose: Enables or disables multiselect for this tool.
  33. //-----------------------------------------------------------------------------
  34. void CToolPickEntity::AllowMultiSelect(bool bAllow)
  35. {
  36. m_bAllowMultiSelect = bAllow;
  37. //
  38. // Shouldn't ever happen, but you never know.
  39. //
  40. if ((!bAllow) && (m_Entities.Count() > 1))
  41. {
  42. CMapEntity *pEntity = m_Entities[0].pEntity;
  43. DeselectAll();
  44. SelectEntity(pEntity);
  45. }
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Purpose: Called when the tool is deactivated.
  49. // Input : eNewTool - The ID of the tool that is being activated.
  50. //-----------------------------------------------------------------------------
  51. void CToolPickEntity::OnDeactivate()
  52. {
  53. DeselectAll();
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Purpose: Handles the left mouse button up message in the 3D view.
  57. // Input : pView - The view that the event occurred in.
  58. // nFlags - Flags per the Windows mouse message.
  59. // point - Point in client coordinates where the event occurred.
  60. // Output : Returns true if the message was handled by the tool, false if not.
  61. //-----------------------------------------------------------------------------
  62. bool CToolPickEntity::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  63. {
  64. return true;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose: Handles the left mouse button up message in the 3D view.
  68. // Input : pView - The view that the event occurred in.
  69. // nFlags - Flags per the Windows mouse message.
  70. // point - Point in client coordinates where the event occurred.
  71. // Output : Returns true if the message was handled by the tool, false if not.
  72. //-----------------------------------------------------------------------------
  73. bool CToolPickEntity::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  74. {
  75. bool bControl = ((nFlags & MK_CONTROL) != 0);
  76. unsigned long uEntity;
  77. CMapClass *pObject = pView->NearestObjectAt( vPoint, uEntity);
  78. if (pObject != NULL)
  79. {
  80. CMapClass *pSelObject = pObject->PrepareSelection(selectObjects);
  81. CMapEntity *pEntity = dynamic_cast <CMapEntity *>(pSelObject);
  82. if (pEntity != NULL)
  83. {
  84. //
  85. // We clicked on an entity.
  86. //
  87. if ((!m_bAllowMultiSelect) || (!bControl))
  88. {
  89. // Single select.
  90. DeselectAll();
  91. SelectEntity(pEntity);
  92. }
  93. else
  94. {
  95. // Multiselect.
  96. CycleSelectEntity(pEntity);
  97. }
  98. if (m_pNotifyTarget)
  99. {
  100. m_pNotifyTarget->OnNotifyPickEntity(this);
  101. }
  102. }
  103. }
  104. return true;
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose: Handles the left mouse button up message in the 3D view.
  108. // Input : pView - The view that the event occurred in.
  109. // nFlags - Flags per the Windows mouse message.
  110. // point - Point in client coordinates where the event occurred.
  111. // Output : Returns true if the message was handled by the tool, false if not.
  112. //-----------------------------------------------------------------------------
  113. bool CToolPickEntity::OnLMouseDownLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint)
  114. {
  115. bool bControl = ((nFlags & MK_CONTROL) != 0);
  116. HitInfo_t hitData;
  117. int nHits = pView->ObjectsAt( vPoint, &hitData, 1 );
  118. if ( ( nHits > 0 ) && hitData.pObject )
  119. {
  120. CMapClass *pSelObject = hitData.pObject->PrepareSelection( selectObjects );
  121. CMapEntity *pEntity = dynamic_cast <CMapEntity *>( pSelObject );
  122. if (pEntity != NULL)
  123. {
  124. //
  125. // We clicked on an entity.
  126. //
  127. if ((!m_bAllowMultiSelect) || (!bControl))
  128. {
  129. // Single select.
  130. DeselectAll();
  131. SelectEntity(pEntity);
  132. }
  133. else
  134. {
  135. // Multiselect.
  136. CycleSelectEntity(pEntity);
  137. }
  138. if (m_pNotifyTarget)
  139. {
  140. m_pNotifyTarget->OnNotifyPickEntity(this);
  141. }
  142. }
  143. }
  144. return true;
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Purpose: Handles the left mouse button double click message in the 3D view.
  148. // Input : pView - The view that the event occurred in.
  149. // nFlags - Flags per the Windows mouse message.
  150. // point - Point in client coordinates where the event occurred.
  151. // Output : Returns true if the message was handled by the tool, false if not.
  152. //-----------------------------------------------------------------------------
  153. bool CToolPickEntity::OnLMouseDblClk3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  154. {
  155. return true;
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose: Handles the right mouse button up message in the 3D view.
  159. // Input : pView - The view that the event occurred in.
  160. // nFlags - Flags per the Windows mouse message.
  161. // point - Point in client coordinates where the event occurred.
  162. // Output : Returns true if the message was handled by the tool, false if not.
  163. //-----------------------------------------------------------------------------
  164. bool CToolPickEntity::OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  165. {
  166. return true;
  167. }
  168. //-----------------------------------------------------------------------------
  169. // Purpose: Handles the mouse button up message in the 3D view.
  170. // Input : pView - The view that the event occurred in.
  171. // nFlags - Flags per the Windows mouse message.
  172. // point - Point in client coordinates where the event occurred.
  173. // Output : Returns true if the message was handled by the tool, false if not.
  174. //-----------------------------------------------------------------------------
  175. bool CToolPickEntity::OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  176. {
  177. return true;
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose: Handles the mouse move message in the 3D view.
  181. // Input : pView - The view that the event occurred in.
  182. // nFlags - Flags per the Windows mouse message.
  183. // point - Point in client coordinates where the event occurred.
  184. // Output : Returns true if the message was handled by the tool, false if not.
  185. //-----------------------------------------------------------------------------
  186. bool CToolPickEntity::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  187. {
  188. SetEyedropperCursor();
  189. return true;
  190. }
  191. bool CToolPickEntity::OnMouseMoveLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint)
  192. {
  193. SetEyedropperCursor();
  194. return true;
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose: Sets the cursor to the eyedropper cursor.
  198. //-----------------------------------------------------------------------------
  199. void CToolPickEntity::SetEyedropperCursor(void)
  200. {
  201. static HCURSOR hcurEyedropper = NULL;
  202. if (!hcurEyedropper)
  203. {
  204. hcurEyedropper = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_EYEDROPPER));
  205. }
  206. SetCursor(hcurEyedropper);
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Purpose:
  210. // Input : pEntity -
  211. //-----------------------------------------------------------------------------
  212. void CToolPickEntity::CycleSelectEntity(CMapEntity *pEntity)
  213. {
  214. int nIndex = FindEntity(pEntity);
  215. if (nIndex != -1)
  216. {
  217. //
  218. // The entity is in our list, update its selection state.
  219. //
  220. if (m_Entities[nIndex].eState == EntityState_Partial)
  221. {
  222. DeselectEntity(nIndex);
  223. }
  224. else if (m_Entities[nIndex].eState == EntityState_Select)
  225. {
  226. if (m_Entities[nIndex].eOriginalState == EntityState_Partial)
  227. {
  228. m_Entities[nIndex].eState = EntityState_Partial;
  229. //pEntity->SetSelectionState(SELECT_MULTI_PARTIAL);
  230. }
  231. else
  232. {
  233. DeselectEntity(nIndex);
  234. }
  235. }
  236. else if (m_Entities[nIndex].eState == EntityState_None)
  237. {
  238. m_Entities[nIndex].eState = EntityState_Select;
  239. //pEntity->SetSelectionState(SELECT_NORMAL);
  240. }
  241. }
  242. else
  243. {
  244. //
  245. // The entity is not in our list, add it.
  246. //
  247. AddToList(pEntity, EntityState_Select);
  248. //pEntity->SetSelectionState(SELECT_NORMAL);
  249. }
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Purpose: Sets the fully selected and partially selected entities for the picker.
  253. // Input : EntityListFull -
  254. // EntityListPartial -
  255. //-----------------------------------------------------------------------------
  256. void CToolPickEntity::SetSelectedEntities(CMapEntityList &EntityListFull, CMapEntityList &EntityListPartial)
  257. {
  258. m_Entities.RemoveAll();
  259. for (int i = 0; i < EntityListFull.Count(); i++)
  260. {
  261. CMapEntity *pEntity = EntityListFull.Element(i);
  262. AddToList(pEntity, EntityState_Select);
  263. pEntity->SetSelectionState(SELECT_NORMAL);
  264. }
  265. for (int i = 0; i < EntityListPartial.Count(); i++)
  266. {
  267. CMapEntity *pEntity = EntityListPartial.Element(i);
  268. AddToList(pEntity, EntityState_Partial);
  269. pEntity->SetSelectionState(SELECT_MULTI_PARTIAL);
  270. }
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose:
  274. // Input : pEntity -
  275. //-----------------------------------------------------------------------------
  276. int CToolPickEntity::FindEntity(CMapEntity *pEntity)
  277. {
  278. for (int i = 0; i < m_Entities.Count(); i++)
  279. {
  280. if (m_Entities[i].pEntity == pEntity)
  281. {
  282. return i;
  283. }
  284. }
  285. return -1;
  286. }
  287. //-----------------------------------------------------------------------------
  288. // Purpose: Clears the selection set.
  289. //-----------------------------------------------------------------------------
  290. void CToolPickEntity::DeselectAll(void)
  291. {
  292. for (int i = 0; i < m_Entities.Count(); i++)
  293. {
  294. m_Entities[i].pEntity->SetSelectionState(SELECT_NONE);
  295. }
  296. m_Entities.RemoveAll();
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Purpose: Selects the entity unconditionally.
  300. // Input : pEntity - entity to select.
  301. //-----------------------------------------------------------------------------
  302. void CToolPickEntity::SelectEntity(CMapEntity *pEntity)
  303. {
  304. int nIndex = FindEntity(pEntity);
  305. if (nIndex != -1)
  306. {
  307. //
  308. // The entity is in our list, update its selection state.
  309. //
  310. m_Entities[nIndex].eState = EntityState_Select;
  311. pEntity->SetSelectionState(SELECT_NORMAL);
  312. }
  313. else
  314. {
  315. //
  316. // The entity is not in our list, add it.
  317. //
  318. AddToList(pEntity, EntityState_Select);
  319. pEntity->SetSelectionState(SELECT_NORMAL);
  320. }
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Purpose: Deselects the given entity.
  324. //-----------------------------------------------------------------------------
  325. void CToolPickEntity::DeselectEntity(CMapEntity *pEntity)
  326. {
  327. int nIndex = FindEntity(pEntity);
  328. if (nIndex != -1)
  329. {
  330. DeselectEntity(nIndex);
  331. }
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose: Removes the entity at the given index from the selection set.
  335. // Input : nIndex - Index of the entity in the selection list.
  336. //-----------------------------------------------------------------------------
  337. void CToolPickEntity::DeselectEntity(int nIndex)
  338. {
  339. Assert(m_Entities.IsValidIndex(nIndex));
  340. if (m_Entities.IsValidIndex(nIndex))
  341. {
  342. if (m_Entities[nIndex].eOriginalState != EntityState_Partial)
  343. {
  344. m_Entities[nIndex].pEntity->SetSelectionState(SELECT_NONE);
  345. //
  346. // Remove the entity from our list.
  347. //
  348. RemoveFromList(nIndex);
  349. }
  350. else
  351. {
  352. //
  353. // Just set the state to deselected so we can cycle back to partial selection.
  354. //
  355. m_Entities[nIndex].pEntity->SetSelectionState(SELECT_NONE);
  356. m_Entities[nIndex].eState = EntityState_None;
  357. }
  358. }
  359. }
  360. //-----------------------------------------------------------------------------
  361. // Purpose:
  362. // Input : pEntity -
  363. // eState -
  364. //-----------------------------------------------------------------------------
  365. void CToolPickEntity::AddToList(CMapEntity *pEntity, EntityState_t eState)
  366. {
  367. int nIndex = m_Entities.AddToTail();
  368. m_Entities[nIndex].pEntity = pEntity;
  369. m_Entities[nIndex].eState = eState;
  370. m_Entities[nIndex].eOriginalState = eState;
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose:
  374. // Input : nIndex -
  375. //-----------------------------------------------------------------------------
  376. void CToolPickEntity::RemoveFromList(int nIndex)
  377. {
  378. Assert(m_Entities.IsValidIndex(nIndex));
  379. if (m_Entities.IsValidIndex(nIndex))
  380. {
  381. m_Entities.FastRemove(nIndex);
  382. }
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose: Returns lists of fully selected and partially selected entities.
  386. //-----------------------------------------------------------------------------
  387. void CToolPickEntity::GetSelectedEntities(CMapEntityList &EntityListFull, CMapEntityList &EntityListPartial)
  388. {
  389. EntityListFull.RemoveAll();
  390. EntityListPartial.RemoveAll();
  391. for (int i = 0; i < m_Entities.Count(); i++)
  392. {
  393. if (m_Entities[i].eState == EntityState_Select)
  394. {
  395. EntityListFull.AddToTail(m_Entities[i].pEntity);
  396. }
  397. else if (m_Entities[i].eState == EntityState_Partial)
  398. {
  399. EntityListPartial.AddToTail(m_Entities[i].pEntity);
  400. }
  401. }
  402. }