//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Tool used for picking entities. This is used anywhere a field that // contains an entity name is found. // // Left click - single select entity // +Ctrl - multiselect a single entity // //=============================================================================// #include "stdafx.h" #include "resource.h" #include "ToolPickEntity.h" #include "MapViewLogical.h" #include "MapView3D.h" // memdbgon must be the last include file in a .cpp file!!! #include //----------------------------------------------------------------------------- // Purpose: Constructor. Inits data members. //----------------------------------------------------------------------------- CToolPickEntity::CToolPickEntity(void) { m_pNotifyTarget = NULL; m_bAllowMultiSelect = false; } //----------------------------------------------------------------------------- // Purpose: Destructor. //----------------------------------------------------------------------------- CToolPickEntity::~CToolPickEntity(void) { } //----------------------------------------------------------------------------- // Purpose: Enables or disables multiselect for this tool. //----------------------------------------------------------------------------- void CToolPickEntity::AllowMultiSelect(bool bAllow) { m_bAllowMultiSelect = bAllow; // // Shouldn't ever happen, but you never know. // if ((!bAllow) && (m_Entities.Count() > 1)) { CMapEntity *pEntity = m_Entities[0].pEntity; DeselectAll(); SelectEntity(pEntity); } } //----------------------------------------------------------------------------- // Purpose: Called when the tool is deactivated. // Input : eNewTool - The ID of the tool that is being activated. //----------------------------------------------------------------------------- void CToolPickEntity::OnDeactivate() { DeselectAll(); } //----------------------------------------------------------------------------- // Purpose: Handles the left mouse button up message in the 3D view. // Input : pView - The view that the event occurred in. // nFlags - Flags per the Windows mouse message. // point - Point in client coordinates where the event occurred. // Output : Returns true if the message was handled by the tool, false if not. //----------------------------------------------------------------------------- bool CToolPickEntity::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) { return true; } //----------------------------------------------------------------------------- // Purpose: Handles the left mouse button up message in the 3D view. // Input : pView - The view that the event occurred in. // nFlags - Flags per the Windows mouse message. // point - Point in client coordinates where the event occurred. // Output : Returns true if the message was handled by the tool, false if not. //----------------------------------------------------------------------------- bool CToolPickEntity::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) { bool bControl = ((nFlags & MK_CONTROL) != 0); unsigned long uEntity; CMapClass *pObject = pView->NearestObjectAt( vPoint, uEntity); if (pObject != NULL) { CMapClass *pSelObject = pObject->PrepareSelection(selectObjects); CMapEntity *pEntity = dynamic_cast (pSelObject); if (pEntity != NULL) { // // We clicked on an entity. // if ((!m_bAllowMultiSelect) || (!bControl)) { // Single select. DeselectAll(); SelectEntity(pEntity); } else { // Multiselect. CycleSelectEntity(pEntity); } if (m_pNotifyTarget) { m_pNotifyTarget->OnNotifyPickEntity(this); } } } return true; } //----------------------------------------------------------------------------- // Purpose: Handles the left mouse button up message in the 3D view. // Input : pView - The view that the event occurred in. // nFlags - Flags per the Windows mouse message. // point - Point in client coordinates where the event occurred. // Output : Returns true if the message was handled by the tool, false if not. //----------------------------------------------------------------------------- bool CToolPickEntity::OnLMouseDownLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint) { bool bControl = ((nFlags & MK_CONTROL) != 0); HitInfo_t hitData; int nHits = pView->ObjectsAt( vPoint, &hitData, 1 ); if ( ( nHits > 0 ) && hitData.pObject ) { CMapClass *pSelObject = hitData.pObject->PrepareSelection( selectObjects ); CMapEntity *pEntity = dynamic_cast ( pSelObject ); if (pEntity != NULL) { // // We clicked on an entity. // if ((!m_bAllowMultiSelect) || (!bControl)) { // Single select. DeselectAll(); SelectEntity(pEntity); } else { // Multiselect. CycleSelectEntity(pEntity); } if (m_pNotifyTarget) { m_pNotifyTarget->OnNotifyPickEntity(this); } } } return true; } //----------------------------------------------------------------------------- // Purpose: Handles the left mouse button double click message in the 3D view. // Input : pView - The view that the event occurred in. // nFlags - Flags per the Windows mouse message. // point - Point in client coordinates where the event occurred. // Output : Returns true if the message was handled by the tool, false if not. //----------------------------------------------------------------------------- bool CToolPickEntity::OnLMouseDblClk3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) { return true; } //----------------------------------------------------------------------------- // Purpose: Handles the right mouse button up message in the 3D view. // Input : pView - The view that the event occurred in. // nFlags - Flags per the Windows mouse message. // point - Point in client coordinates where the event occurred. // Output : Returns true if the message was handled by the tool, false if not. //----------------------------------------------------------------------------- bool CToolPickEntity::OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) { return true; } //----------------------------------------------------------------------------- // Purpose: Handles the mouse button up message in the 3D view. // Input : pView - The view that the event occurred in. // nFlags - Flags per the Windows mouse message. // point - Point in client coordinates where the event occurred. // Output : Returns true if the message was handled by the tool, false if not. //----------------------------------------------------------------------------- bool CToolPickEntity::OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) { return true; } //----------------------------------------------------------------------------- // Purpose: Handles the mouse move message in the 3D view. // Input : pView - The view that the event occurred in. // nFlags - Flags per the Windows mouse message. // point - Point in client coordinates where the event occurred. // Output : Returns true if the message was handled by the tool, false if not. //----------------------------------------------------------------------------- bool CToolPickEntity::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) { SetEyedropperCursor(); return true; } bool CToolPickEntity::OnMouseMoveLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint) { SetEyedropperCursor(); return true; } //----------------------------------------------------------------------------- // Purpose: Sets the cursor to the eyedropper cursor. //----------------------------------------------------------------------------- void CToolPickEntity::SetEyedropperCursor(void) { static HCURSOR hcurEyedropper = NULL; if (!hcurEyedropper) { hcurEyedropper = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_EYEDROPPER)); } SetCursor(hcurEyedropper); } //----------------------------------------------------------------------------- // Purpose: // Input : pEntity - //----------------------------------------------------------------------------- void CToolPickEntity::CycleSelectEntity(CMapEntity *pEntity) { int nIndex = FindEntity(pEntity); if (nIndex != -1) { // // The entity is in our list, update its selection state. // if (m_Entities[nIndex].eState == EntityState_Partial) { DeselectEntity(nIndex); } else if (m_Entities[nIndex].eState == EntityState_Select) { if (m_Entities[nIndex].eOriginalState == EntityState_Partial) { m_Entities[nIndex].eState = EntityState_Partial; //pEntity->SetSelectionState(SELECT_MULTI_PARTIAL); } else { DeselectEntity(nIndex); } } else if (m_Entities[nIndex].eState == EntityState_None) { m_Entities[nIndex].eState = EntityState_Select; //pEntity->SetSelectionState(SELECT_NORMAL); } } else { // // The entity is not in our list, add it. // AddToList(pEntity, EntityState_Select); //pEntity->SetSelectionState(SELECT_NORMAL); } } //----------------------------------------------------------------------------- // Purpose: Sets the fully selected and partially selected entities for the picker. // Input : EntityListFull - // EntityListPartial - //----------------------------------------------------------------------------- void CToolPickEntity::SetSelectedEntities(CMapEntityList &EntityListFull, CMapEntityList &EntityListPartial) { m_Entities.RemoveAll(); for (int i = 0; i < EntityListFull.Count(); i++) { CMapEntity *pEntity = EntityListFull.Element(i); AddToList(pEntity, EntityState_Select); pEntity->SetSelectionState(SELECT_NORMAL); } for (int i = 0; i < EntityListPartial.Count(); i++) { CMapEntity *pEntity = EntityListPartial.Element(i); AddToList(pEntity, EntityState_Partial); pEntity->SetSelectionState(SELECT_MULTI_PARTIAL); } } //----------------------------------------------------------------------------- // Purpose: // Input : pEntity - //----------------------------------------------------------------------------- int CToolPickEntity::FindEntity(CMapEntity *pEntity) { for (int i = 0; i < m_Entities.Count(); i++) { if (m_Entities[i].pEntity == pEntity) { return i; } } return -1; } //----------------------------------------------------------------------------- // Purpose: Clears the selection set. //----------------------------------------------------------------------------- void CToolPickEntity::DeselectAll(void) { for (int i = 0; i < m_Entities.Count(); i++) { m_Entities[i].pEntity->SetSelectionState(SELECT_NONE); } m_Entities.RemoveAll(); } //----------------------------------------------------------------------------- // Purpose: Selects the entity unconditionally. // Input : pEntity - entity to select. //----------------------------------------------------------------------------- void CToolPickEntity::SelectEntity(CMapEntity *pEntity) { int nIndex = FindEntity(pEntity); if (nIndex != -1) { // // The entity is in our list, update its selection state. // m_Entities[nIndex].eState = EntityState_Select; pEntity->SetSelectionState(SELECT_NORMAL); } else { // // The entity is not in our list, add it. // AddToList(pEntity, EntityState_Select); pEntity->SetSelectionState(SELECT_NORMAL); } } //----------------------------------------------------------------------------- // Purpose: Deselects the given entity. //----------------------------------------------------------------------------- void CToolPickEntity::DeselectEntity(CMapEntity *pEntity) { int nIndex = FindEntity(pEntity); if (nIndex != -1) { DeselectEntity(nIndex); } } //----------------------------------------------------------------------------- // Purpose: Removes the entity at the given index from the selection set. // Input : nIndex - Index of the entity in the selection list. //----------------------------------------------------------------------------- void CToolPickEntity::DeselectEntity(int nIndex) { Assert(m_Entities.IsValidIndex(nIndex)); if (m_Entities.IsValidIndex(nIndex)) { if (m_Entities[nIndex].eOriginalState != EntityState_Partial) { m_Entities[nIndex].pEntity->SetSelectionState(SELECT_NONE); // // Remove the entity from our list. // RemoveFromList(nIndex); } else { // // Just set the state to deselected so we can cycle back to partial selection. // m_Entities[nIndex].pEntity->SetSelectionState(SELECT_NONE); m_Entities[nIndex].eState = EntityState_None; } } } //----------------------------------------------------------------------------- // Purpose: // Input : pEntity - // eState - //----------------------------------------------------------------------------- void CToolPickEntity::AddToList(CMapEntity *pEntity, EntityState_t eState) { int nIndex = m_Entities.AddToTail(); m_Entities[nIndex].pEntity = pEntity; m_Entities[nIndex].eState = eState; m_Entities[nIndex].eOriginalState = eState; } //----------------------------------------------------------------------------- // Purpose: // Input : nIndex - //----------------------------------------------------------------------------- void CToolPickEntity::RemoveFromList(int nIndex) { Assert(m_Entities.IsValidIndex(nIndex)); if (m_Entities.IsValidIndex(nIndex)) { m_Entities.FastRemove(nIndex); } } //----------------------------------------------------------------------------- // Purpose: Returns lists of fully selected and partially selected entities. //----------------------------------------------------------------------------- void CToolPickEntity::GetSelectedEntities(CMapEntityList &EntityListFull, CMapEntityList &EntityListPartial) { EntityListFull.RemoveAll(); EntityListPartial.RemoveAll(); for (int i = 0; i < m_Entities.Count(); i++) { if (m_Entities[i].eState == EntityState_Select) { EntityListFull.AddToTail(m_Entities[i].pEntity); } else if (m_Entities[i].eState == EntityState_Partial) { EntityListPartial.AddToTail(m_Entities[i].pEntity); } } }