//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "stdafx.h" #include "ChunkFile.h" #include "MapDoc.h" // dvs: FIXME: I'd rather not have this class know about the doc #include "VisGroup.h" // memdbgon must be the last include file in a .cpp file!!! #include bool CVisGroup::s_bShowAll = false; bool CVisGroup::s_bIsConvertingOldVisGroups = false; // // Holds context info for loading the hierarchical groups. // struct LoadVisGroupData_t { CMapDoc *pDoc; // The document that is loading. CVisGroup *pParent; // The parent visgroup of the visgroup being loaded, NULL if this is a root-level group. }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CVisGroup::CVisGroup(void) { m_dwID = 0; m_rgbColor.r = 0; m_rgbColor.g = 0; m_rgbColor.b = 0; m_rgbColor.a = 0; m_pParent = NULL; m_eVisible = VISGROUP_HIDDEN; m_szName[0] = '\0'; m_bIsAuto = false; } //----------------------------------------------------------------------------- // Purpose: Pre-hierarchical visgroups, the visibility state of each group was // kept in the VMF, whereas now it's purely a function of the visibility // of the member objects. So when loading old maps, we skip the step // in which we generate the visgroup state from the objects. //----------------------------------------------------------------------------- bool CVisGroup::IsConvertingOldVisGroups() { return s_bIsConvertingOldVisGroups; } //----------------------------------------------------------------------------- // Purpose: // Input : pFile - // pData - // Output : ChunkFileResult_t //----------------------------------------------------------------------------- ChunkFileResult_t CVisGroup::LoadKeyCallback(const char *szKey, const char *szValue, CVisGroup *pGroup) { if (!stricmp(szKey, "name")) { pGroup->SetName(szValue); if ( !stricmp(szValue, "Auto" ) ) { pGroup->SetAuto(true); } } else if (!stricmp(szKey, "visgroupid")) { pGroup->SetID(atoi(szValue)); } else if (!stricmp(szKey, "color")) { unsigned char chRed; unsigned char chGreen; unsigned char chBlue; CChunkFile::ReadKeyValueColor(szValue, chRed, chGreen, chBlue); pGroup->SetColor(chRed, chGreen, chBlue); } else if (!stricmp(szKey, "visible")) { // This is a pre-hierarchical visgroups map -- mark this visgroup as hidden. // We'll skip the code in CMapDoc::PostLoad that recalculates visibility. pGroup->SetVisible((atoi(szValue) == 1) ? VISGROUP_SHOWN : VISGROUP_HIDDEN); s_bIsConvertingOldVisGroups = true; } return(ChunkFile_Ok); } //----------------------------------------------------------------------------- // Purpose: // Input : pFile - // Output : //----------------------------------------------------------------------------- ChunkFileResult_t CVisGroup::LoadVMF(CChunkFile *pFile, CMapDoc *pDoc) { // Fill out a little context blob for passing to the handler. LoadVisGroupData_t LoadData; LoadData.pDoc = pDoc; LoadData.pParent = this; CChunkHandlerMap Handlers; Handlers.AddHandler("visgroup", (ChunkHandler_t)LoadVisGroupCallback, &LoadData); pFile->PushHandlers(&Handlers); ChunkFileResult_t eResult = pFile->ReadChunk((KeyHandler_t)LoadKeyCallback, this); pFile->PopHandlers(); return(eResult); } //----------------------------------------------------------------------------- // Purpose: // Input : pFile - // pData - // Output : ChunkFileResult_t //----------------------------------------------------------------------------- ChunkFileResult_t CVisGroup::LoadVisGroupCallback(CChunkFile *pFile, LoadVisGroupData_t *pLoadData) { CVisGroup *pVisGroup = new CVisGroup; ChunkFileResult_t eResult = pVisGroup->LoadVMF(pFile, pLoadData->pDoc); if (eResult == ChunkFile_Ok) { if (pLoadData->pParent != NULL) { pLoadData->pParent->AddChild(pVisGroup); pVisGroup->SetParent(pLoadData->pParent); } if ( !pVisGroup->IsAutoVisGroup() ) { pLoadData->pDoc->VisGroups_AddGroup(pVisGroup); } } return(eResult); } //----------------------------------------------------------------------------- // Purpose: // Input : pFile - // pData - // Output : ChunkFileResult_t //----------------------------------------------------------------------------- ChunkFileResult_t CVisGroup::LoadVisGroupsCallback(CChunkFile *pFile, CMapDoc *pDoc) { s_bIsConvertingOldVisGroups = false; // Fill out a little context blob for passing to the handler. LoadVisGroupData_t LoadData; LoadData.pDoc = pDoc; LoadData.pParent = NULL; // // Set up handlers for the subchunks that we are interested in. // CChunkHandlerMap Handlers; Handlers.AddHandler("visgroup", (ChunkHandler_t)LoadVisGroupCallback, &LoadData); pFile->PushHandlers(&Handlers); ChunkFileResult_t eResult = pFile->ReadChunk(); pFile->PopHandlers(); return(eResult); } //----------------------------------------------------------------------------- // Purpose: // Input : pChild - //----------------------------------------------------------------------------- void CVisGroup::MoveUp(CVisGroup *pChild) { int nIndex = m_Children.Find(pChild); if (nIndex > 0) { m_Children.Remove(nIndex); m_Children.InsertBefore(nIndex - 1, pChild); } } //----------------------------------------------------------------------------- // Purpose: // Input : pChild - //----------------------------------------------------------------------------- void CVisGroup::MoveDown(CVisGroup *pChild) { int nIndex = m_Children.Find(pChild); if ((nIndex >= 0) && (nIndex < (m_Children.Count() - 1))) { m_Children.Remove(nIndex); m_Children.InsertAfter(nIndex, pChild); } } //----------------------------------------------------------------------------- // Purpose: Returns whether or not this visgroup is currently visible. //----------------------------------------------------------------------------- VisGroupState_t CVisGroup::GetVisible(void) { return m_eVisible; } //----------------------------------------------------------------------------- // Purpose: Returns whether or not visgroup visibility is being overridden by // the "Show All" button. //----------------------------------------------------------------------------- bool CVisGroup::IsShowAllActive(void) { return s_bShowAll; } //----------------------------------------------------------------------------- // Purpose: Saves this visgroup. // Input : pFile - File to save into. // Output : Returns ChunkFile_Ok on success, an error code on failure. //----------------------------------------------------------------------------- ChunkFileResult_t CVisGroup::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo) { ChunkFileResult_t eResult = pFile->BeginChunk("visgroup"); if (eResult == ChunkFile_Ok) { eResult = pFile->WriteKeyValue("name", GetName()); } if (eResult == ChunkFile_Ok) { DWORD dwID = GetID(); eResult = pFile->WriteKeyValueInt("visgroupid", dwID); } if (eResult == ChunkFile_Ok) { color32 rgbColor = GetColor(); eResult = pFile->WriteKeyValueColor("color", rgbColor.r, rgbColor.g, rgbColor.b); } // // Recurse into children, writing them within this chunk. // for (int i = 0; i < GetChildCount(); i++) { CVisGroup *pChild = GetChild(i); eResult = pChild->SaveVMF(pFile, pSaveInfo); if (eResult != ChunkFile_Ok) break; } if (eResult == ChunkFile_Ok) { eResult = pFile->EndChunk(); } return(eResult); } //----------------------------------------------------------------------------- // Purpose: Overrides normal visgroup visibility, making all visgroups visible. //----------------------------------------------------------------------------- void CVisGroup::ShowAllVisGroups(bool bShow) { s_bShowAll = bShow; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVisGroup::AddChild(CVisGroup *pChild) { int nIndex = m_Children.Find(pChild); if (nIndex == -1) { m_Children.AddToTail(pChild); } } //----------------------------------------------------------------------------- // Purpose: // Input : pChild - //----------------------------------------------------------------------------- bool CVisGroup::CanMoveUp(CVisGroup *pChild) { return (m_Children.Find(pChild) > 0); } //----------------------------------------------------------------------------- // Purpose: // Input : pChild - //----------------------------------------------------------------------------- bool CVisGroup::CanMoveDown(CVisGroup *pChild) { int nIndex = m_Children.Find(pChild); return (nIndex >= 0) && (nIndex < m_Children.Count() - 1); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVisGroup::RemoveChild(CVisGroup *pChild) { int nIndex = m_Children.Find(pChild); if (nIndex != -1) { m_Children.Remove(nIndex); } } //----------------------------------------------------------------------------- // Purpose: Returns true if the group is one of our descendents, false if not. //----------------------------------------------------------------------------- bool CVisGroup::FindDescendent(CVisGroup *pGroup) { for (int i = 0; i < m_Children.Count(); i++) { CVisGroup *pChild = m_Children.Element(i); if ((pChild == pGroup) || (pChild->FindDescendent(pGroup))) { return true; } } return false; } bool CVisGroup::IsAutoVisGroup() { return m_bIsAuto; } void CVisGroup::SetAuto( bool bAuto ) { m_bIsAuto = bAuto; } void CVisGroup::VisGroups_UpdateParent( VisGroupState_t state ) { CVisGroup *pParent = GetParent(); VisGroupState_t parentState = pParent->GetVisible(); if ( state == VISGROUP_PARTIAL ) { pParent->SetVisible( VISGROUP_PARTIAL ); } if ( parentState == VISGROUP_UNDEFINED ) { pParent->SetVisible( state ); } else if ( parentState != state ) { pParent->SetVisible( VISGROUP_PARTIAL ); } if ( pParent->GetParent() != NULL ) { pParent->VisGroups_UpdateParent( pParent->GetVisible() ); } }