//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Implements the spawnflags page of the Entity Properties dialog. // //=============================================================================// #include "stdafx.h" #include "hammer.h" #include "OP_Flags.h" #include "OP_Entity.h" #include "ObjectProperties.h" // memdbgon must be the last include file in a .cpp file!!! #include ///////////////////////////////////////////////////////////////////////////// // COP_Flags property page IMPLEMENT_DYNCREATE(COP_Flags, CObjectPage) COP_Flags::COP_Flags() : CObjectPage(COP_Flags::IDD) { //{{AFX_DATA_INIT(COP_Flags) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_pEditObjectRuntimeClass = RUNTIME_CLASS(editCEditGameClass); m_nNumSelectedObjects = 0; m_pEntityPage = NULL; } COP_Flags::~COP_Flags() { } void COP_Flags::SetEntityPage( COP_Entity *pPage ) { m_pEntityPage = pPage; } void COP_Flags::DoDataExchange(CDataExchange* pDX) { CObjectPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(COP_Flags) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(COP_Flags, CObjectPage) //{{AFX_MSG_MAP(COP_Flags) ON_CLBN_CHKCHANGE(IDC_CHECKLIST, OnCheckListChange) ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // COP_Flags message handlers void COP_Flags::UpdateData( int Mode, PVOID pData, bool bCanEdit ) { __super::UpdateData( Mode, pData, bCanEdit ); if(!IsWindow(m_hWnd) || !pData) { return; } CEditGameClass *pObj = (CEditGameClass*) pData; if (Mode == LoadFirstData) { UpdateForClass(pObj); } else if (Mode == LoadData) { MergeForClass(pObj); } CreateCheckList(); m_CheckList.EnableWindow( m_bCanEdit ? TRUE : FALSE ); } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool COP_Flags::SaveData(void) { if (!IsWindow(m_hWnd)) { return(false); } // // Apply the dialog data to all the objects being edited. // FOR_EACH_OBJ( *m_pObjectList, pos ) { CMapClass *pObject = m_pObjectList->Element(pos); CEditGameClass *pEdit = dynamic_cast (pObject); Assert(pEdit != NULL); if ( pEdit != NULL ) { for ( int i = 0; i < m_CheckListItems.Count(); i++ ) { CheckListItem currentItem = m_CheckListItems.Element( i ); // don't save tri-stated bit if ( m_CheckList.GetCheck(i) != 2 ) { pEdit->SetSpawnFlag( currentItem.nItemBit, m_CheckList.GetCheck(i) ? TRUE : FALSE ); } } } } return(true); } //----------------------------------------------------------------------------- // Purpose: This function is used to initialize the flag checklist. // It is called to place all the flags belonging to the first // selected object into the temporary CheckListItems vector //----------------------------------------------------------------------------- void COP_Flags::UpdateForClass(CEditGameClass* pObj) { extern GameData *pGD; GDclass * pClass = pGD->ClassForName(pObj->GetClassName()); if(!IsWindow(m_hWnd)) return; m_nNumSelectedObjects = 1; m_CheckListItems.RemoveAll(); if(pClass) { GDinputvariable *pVar = pClass->VarForName("spawnflags"); if (pVar) { int nItems = pVar->GetFlagCount(); for ( int i = 0; i < nItems; i++ ) { CheckListItem newItem; newItem.nItemBit = pVar->GetFlagMask( i ); newItem.pszItemString = pVar->GetFlagCaption( i ); newItem.state = pObj->GetSpawnFlag( newItem.nItemBit ) ? 1 : 0; m_CheckListItems.AddToTail( newItem ); } } } Assert( m_CheckListItems.Count() <= 32 ); for ( int i = 0; i < 32; i++ ) { int nBitPattern = 1 << i; // is spawnflag for this bit set? if ( pObj->GetSpawnFlag(nBitPattern) ) { int j; // then see if its allowed to be for ( j = 0; j < m_CheckListItems.Count(); j ++ ) { int nCheckListPattern = m_CheckListItems.Element(j).nItemBit; if ( nCheckListPattern == nBitPattern ) break; } // we fail to find it? if ( j == m_CheckListItems.Count() ) { CheckListItem newItem; newItem.nItemBit = nBitPattern; newItem.pszItemString = "????"; newItem.state = 1; m_CheckListItems.AddToTail( newItem ); } } } } //----------------------------------------------------------------------------- // Purpose: This function is called to combine flags when multiple objects are selected // It removes flags from the CheckListItem vector that are not present in all selected objects //----------------------------------------------------------------------------- void COP_Flags::MergeForClass(CEditGameClass* pObj) { extern GameData *pGD; GDclass * pClass = pGD->ClassForName(pObj->GetClassName()); if( !IsWindow(m_hWnd) ) return; m_nNumSelectedObjects++; if( pClass ) { GDinputvariable *pVar = pClass->VarForName("spawnflags"); for ( int i = m_CheckListItems.Count() - 1; i >= 0; i-- ) { bool bFound = false; CheckListItem currentItem = m_CheckListItems.Element( i ); if ( pVar ) { for ( int j = 0; j < pVar->GetFlagCount(); j++ ) { CheckListItem newItem; newItem.nItemBit = pVar->GetFlagMask(j); newItem.pszItemString = pVar->GetFlagCaption(j); if ( newItem == currentItem ) { bFound = true; int nNewState = pObj->GetSpawnFlag( newItem.nItemBit ) ? 1 : 0; if ( currentItem.state != nNewState ) { m_CheckListItems.Element( i ).state = 2; } break; } } } if ( !bFound ) { m_CheckListItems.FastRemove( i ); } } } Assert( m_CheckListItems.Count() <= 32 ); } //----------------------------------------------------------------------------- // Purpose: Creates the checklist by stepping through the CheckListItems vector that // was created during Update/MergeForClass //----------------------------------------------------------------------------- void COP_Flags::CreateCheckList() { m_CheckList.ResetContent(); if ( m_nNumSelectedObjects > 1 ) { m_CheckList.SetCheckStyle(BS_AUTO3STATE); } for ( int i = 0; i < m_CheckListItems.Count(); i++ ) { CheckListItem newItem = m_CheckListItems.Element(i); m_CheckList.InsertString(i, newItem.pszItemString); m_CheckList.SetCheck(i, newItem.state); } } void COP_Flags::OnUpdateSpawnFlags( unsigned long value ) { for ( int i=0; i < m_CheckListItems.Count(); i++ ) { CheckListItem &item = m_CheckListItems[i]; m_CheckList.SetCheck( i, (value & item.nItemBit) != 0 ); } } BOOL COP_Flags::OnInitDialog() { CObjectPage::OnInitDialog(); m_nNumSelectedObjects = 0; // Subclass checklistbox m_CheckList.SubclassDlgItem(IDC_CHECKLIST, this); m_CheckList.SetCheckStyle(BS_AUTOCHECKBOX); m_CheckList.ResetContent(); CAnchorDef anchorDefs[] = { CAnchorDef( IDC_CHECKLIST, k_eSimpleAnchorAllSides ) }; m_AnchorMgr.Init( GetSafeHwnd(), anchorDefs, ARRAYSIZE( anchorDefs ) ); return TRUE; } void COP_Flags::OnCheckListChange() { if ( !m_pEntityPage ) return; unsigned long bitsSet = 0; unsigned long triStateMask = 0; // This is just like SaveData.. collect the state of all the checks. for ( int i = 0; i < m_CheckListItems.Count(); i++ ) { CheckListItem currentItem = m_CheckListItems.Element( i ); // If multiple of the selected entities have a different value for this flag, // note that. The entity page will use triStateMask to denote flags that // it should leave alone. if ( m_CheckList.GetCheck(i) == 2 ) triStateMask |= currentItem.nItemBit; else if ( m_CheckList.GetCheck( i ) ) bitsSet |= currentItem.nItemBit; } m_pEntityPage->OnUpdateSpawnFlags( triStateMask, bitsSet ); } void COP_Flags::OnSize( UINT nType, int cx, int cy ) { m_AnchorMgr.OnSize(); }