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.

316 lines
7.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements the spawnflags page of the Entity Properties dialog.
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include "hammer.h"
  8. #include "OP_Flags.h"
  9. #include "OP_Entity.h"
  10. #include "ObjectProperties.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include <tier0/memdbgon.h>
  13. /////////////////////////////////////////////////////////////////////////////
  14. // COP_Flags property page
  15. IMPLEMENT_DYNCREATE(COP_Flags, CObjectPage)
  16. COP_Flags::COP_Flags() : CObjectPage(COP_Flags::IDD)
  17. {
  18. //{{AFX_DATA_INIT(COP_Flags)
  19. // NOTE: the ClassWizard will add member initialization here
  20. //}}AFX_DATA_INIT
  21. m_pEditObjectRuntimeClass = RUNTIME_CLASS(editCEditGameClass);
  22. m_nNumSelectedObjects = 0;
  23. m_pEntityPage = NULL;
  24. }
  25. COP_Flags::~COP_Flags()
  26. {
  27. }
  28. void COP_Flags::SetEntityPage( COP_Entity *pPage )
  29. {
  30. m_pEntityPage = pPage;
  31. }
  32. void COP_Flags::DoDataExchange(CDataExchange* pDX)
  33. {
  34. CObjectPage::DoDataExchange(pDX);
  35. //{{AFX_DATA_MAP(COP_Flags)
  36. // NOTE: the ClassWizard will add DDX and DDV calls here
  37. //}}AFX_DATA_MAP
  38. }
  39. BEGIN_MESSAGE_MAP(COP_Flags, CObjectPage)
  40. //{{AFX_MSG_MAP(COP_Flags)
  41. ON_CLBN_CHKCHANGE(IDC_CHECKLIST, OnCheckListChange)
  42. ON_WM_SIZE()
  43. //}}AFX_MSG_MAP
  44. END_MESSAGE_MAP()
  45. /////////////////////////////////////////////////////////////////////////////
  46. // COP_Flags message handlers
  47. void COP_Flags::UpdateData( int Mode, PVOID pData, bool bCanEdit )
  48. {
  49. __super::UpdateData( Mode, pData, bCanEdit );
  50. if(!IsWindow(m_hWnd) || !pData)
  51. {
  52. return;
  53. }
  54. CEditGameClass *pObj = (CEditGameClass*) pData;
  55. if (Mode == LoadFirstData)
  56. {
  57. UpdateForClass(pObj);
  58. }
  59. else if (Mode == LoadData)
  60. {
  61. MergeForClass(pObj);
  62. }
  63. CreateCheckList();
  64. m_CheckList.EnableWindow( m_bCanEdit ? TRUE : FALSE );
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. // Output : Returns true on success, false on failure.
  69. //-----------------------------------------------------------------------------
  70. bool COP_Flags::SaveData(void)
  71. {
  72. if (!IsWindow(m_hWnd))
  73. {
  74. return(false);
  75. }
  76. //
  77. // Apply the dialog data to all the objects being edited.
  78. //
  79. FOR_EACH_OBJ( *m_pObjectList, pos )
  80. {
  81. CMapClass *pObject = m_pObjectList->Element(pos);
  82. CEditGameClass *pEdit = dynamic_cast <CEditGameClass *>(pObject);
  83. Assert(pEdit != NULL);
  84. if ( pEdit != NULL )
  85. {
  86. for ( int i = 0; i < m_CheckListItems.Count(); i++ )
  87. {
  88. CheckListItem currentItem = m_CheckListItems.Element( i );
  89. // don't save tri-stated bit
  90. if ( m_CheckList.GetCheck(i) != 2 )
  91. {
  92. pEdit->SetSpawnFlag( currentItem.nItemBit, m_CheckList.GetCheck(i) ? TRUE : FALSE );
  93. }
  94. }
  95. }
  96. }
  97. return(true);
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose: This function is used to initialize the flag checklist.
  101. // It is called to place all the flags belonging to the first
  102. // selected object into the temporary CheckListItems vector
  103. //-----------------------------------------------------------------------------
  104. void COP_Flags::UpdateForClass(CEditGameClass* pObj)
  105. {
  106. extern GameData *pGD;
  107. GDclass * pClass = pGD->ClassForName(pObj->GetClassName());
  108. if(!IsWindow(m_hWnd))
  109. return;
  110. m_nNumSelectedObjects = 1;
  111. m_CheckListItems.RemoveAll();
  112. if(pClass)
  113. {
  114. GDinputvariable *pVar = pClass->VarForName("spawnflags");
  115. if (pVar)
  116. {
  117. int nItems = pVar->GetFlagCount();
  118. for ( int i = 0; i < nItems; i++ )
  119. {
  120. CheckListItem newItem;
  121. newItem.nItemBit = pVar->GetFlagMask( i );
  122. newItem.pszItemString = pVar->GetFlagCaption( i );
  123. newItem.state = pObj->GetSpawnFlag( newItem.nItemBit ) ? 1 : 0;
  124. m_CheckListItems.AddToTail( newItem );
  125. }
  126. }
  127. }
  128. Assert( m_CheckListItems.Count() <= 32 );
  129. for ( int i = 0; i < 32; i++ )
  130. {
  131. int nBitPattern = 1 << i;
  132. // is spawnflag for this bit set?
  133. if ( pObj->GetSpawnFlag(nBitPattern) )
  134. {
  135. int j;
  136. // then see if its allowed to be
  137. for ( j = 0; j < m_CheckListItems.Count(); j ++ )
  138. {
  139. int nCheckListPattern = m_CheckListItems.Element(j).nItemBit;
  140. if ( nCheckListPattern == nBitPattern )
  141. break;
  142. }
  143. // we fail to find it?
  144. if ( j == m_CheckListItems.Count() )
  145. {
  146. CheckListItem newItem;
  147. newItem.nItemBit = nBitPattern;
  148. newItem.pszItemString = "????";
  149. newItem.state = 1;
  150. m_CheckListItems.AddToTail( newItem );
  151. }
  152. }
  153. }
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose: This function is called to combine flags when multiple objects are selected
  157. // It removes flags from the CheckListItem vector that are not present in all selected objects
  158. //-----------------------------------------------------------------------------
  159. void COP_Flags::MergeForClass(CEditGameClass* pObj)
  160. {
  161. extern GameData *pGD;
  162. GDclass * pClass = pGD->ClassForName(pObj->GetClassName());
  163. if( !IsWindow(m_hWnd) )
  164. return;
  165. m_nNumSelectedObjects++;
  166. if( pClass )
  167. {
  168. GDinputvariable *pVar = pClass->VarForName("spawnflags");
  169. for ( int i = m_CheckListItems.Count() - 1; i >= 0; i-- )
  170. {
  171. bool bFound = false;
  172. CheckListItem currentItem = m_CheckListItems.Element( i );
  173. if ( pVar )
  174. {
  175. for ( int j = 0; j < pVar->GetFlagCount(); j++ )
  176. {
  177. CheckListItem newItem;
  178. newItem.nItemBit = pVar->GetFlagMask(j);
  179. newItem.pszItemString = pVar->GetFlagCaption(j);
  180. if ( newItem == currentItem )
  181. {
  182. bFound = true;
  183. int nNewState = pObj->GetSpawnFlag( newItem.nItemBit ) ? 1 : 0;
  184. if ( currentItem.state != nNewState )
  185. {
  186. m_CheckListItems.Element( i ).state = 2;
  187. }
  188. break;
  189. }
  190. }
  191. }
  192. if ( !bFound )
  193. {
  194. m_CheckListItems.FastRemove( i );
  195. }
  196. }
  197. }
  198. Assert( m_CheckListItems.Count() <= 32 );
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose: Creates the checklist by stepping through the CheckListItems vector that
  202. // was created during Update/MergeForClass
  203. //-----------------------------------------------------------------------------
  204. void COP_Flags::CreateCheckList()
  205. {
  206. m_CheckList.ResetContent();
  207. if ( m_nNumSelectedObjects > 1 )
  208. {
  209. m_CheckList.SetCheckStyle(BS_AUTO3STATE);
  210. }
  211. for ( int i = 0; i < m_CheckListItems.Count(); i++ )
  212. {
  213. CheckListItem newItem = m_CheckListItems.Element(i);
  214. m_CheckList.InsertString(i, newItem.pszItemString);
  215. m_CheckList.SetCheck(i, newItem.state);
  216. }
  217. }
  218. void COP_Flags::OnUpdateSpawnFlags( unsigned long value )
  219. {
  220. for ( int i=0; i < m_CheckListItems.Count(); i++ )
  221. {
  222. CheckListItem &item = m_CheckListItems[i];
  223. m_CheckList.SetCheck( i, (value & item.nItemBit) != 0 );
  224. }
  225. }
  226. BOOL COP_Flags::OnInitDialog()
  227. {
  228. CObjectPage::OnInitDialog();
  229. m_nNumSelectedObjects = 0;
  230. // Subclass checklistbox
  231. m_CheckList.SubclassDlgItem(IDC_CHECKLIST, this);
  232. m_CheckList.SetCheckStyle(BS_AUTOCHECKBOX);
  233. m_CheckList.ResetContent();
  234. CAnchorDef anchorDefs[] =
  235. {
  236. CAnchorDef( IDC_CHECKLIST, k_eSimpleAnchorAllSides )
  237. };
  238. m_AnchorMgr.Init( GetSafeHwnd(), anchorDefs, ARRAYSIZE( anchorDefs ) );
  239. return TRUE;
  240. }
  241. void COP_Flags::OnCheckListChange()
  242. {
  243. if ( !m_pEntityPage )
  244. return;
  245. unsigned long bitsSet = 0;
  246. unsigned long triStateMask = 0;
  247. // This is just like SaveData.. collect the state of all the checks.
  248. for ( int i = 0; i < m_CheckListItems.Count(); i++ )
  249. {
  250. CheckListItem currentItem = m_CheckListItems.Element( i );
  251. // If multiple of the selected entities have a different value for this flag,
  252. // note that. The entity page will use triStateMask to denote flags that
  253. // it should leave alone.
  254. if ( m_CheckList.GetCheck(i) == 2 )
  255. triStateMask |= currentItem.nItemBit;
  256. else if ( m_CheckList.GetCheck( i ) )
  257. bitsSet |= currentItem.nItemBit;
  258. }
  259. m_pEntityPage->OnUpdateSpawnFlags( triStateMask, bitsSet );
  260. }
  261. void COP_Flags::OnSize( UINT nType, int cx, int cy )
  262. {
  263. m_AnchorMgr.OnSize();
  264. }