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.

2516 lines
71 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements a dialog for editing the input/output connections of a
  4. // list of entities. The connections are displayed in a grid control,
  5. // each row of the grid control representing a connection that is
  6. // common to all entities being edited. For example, given these two ents:
  7. //
  8. // Button01
  9. // OnDamaged Sound01 PlaySound 0 0
  10. // OnPressed Door01 Open 0 0
  11. //
  12. // Button02
  13. // OnPressed Door01 Open 0 0
  14. //
  15. // If these two entities were selected, the grid control would show:
  16. //
  17. // OnPressed Door01 Open 0 0
  18. //
  19. // because it is the only connection that is common to both entities.
  20. // Editing an entry in the grid control modifies the corresponding
  21. // connection in all selected entities.
  22. //
  23. // TODO: persist sort column index, sort directions, and column sizes
  24. // TODO: implement an external mode, where the grid shows all connections to unselected ents
  25. //
  26. //=============================================================================//
  27. #include "stdafx.h"
  28. #include "GlobalFunctions.h"
  29. #include "MapDoc.h"
  30. #include "MapEntity.h"
  31. #include "MapWorld.h"
  32. #include "ObjectProperties.h"
  33. #include "OP_Output.h"
  34. #include "ToolManager.h"
  35. #include "MainFrm.h"
  36. #include "utlrbtree.h"
  37. #include "options.h"
  38. #include ".\op_output.h"
  39. // memdbgon must be the last include file in a .cpp file!!!
  40. #include <tier0/memdbgon.h>
  41. #pragma warning( disable : 4355 )
  42. #define ICON_CONN_BAD 0
  43. #define ICON_CONN_GOOD 1
  44. #define ICON_CONN_BAD_GREY 2
  45. #define ICON_CONN_GOOD_GREY 3
  46. const char *PARAM_STRING_NONE = "<none>";
  47. //
  48. // Column indices for the list control.
  49. //
  50. const int ICON_COLUMN = 0;
  51. const int OUTPUT_NAME_COLUMN = 1;
  52. const int TARGET_NAME_COLUMN = 2;
  53. const int INPUT_NAME_COLUMN = 3;
  54. const int PARAMETER_COLUMN = 4;
  55. const int DELAY_COLUMN = 5;
  56. const int ONLY_ONCE_COLUMN = 6;
  57. IMPLEMENT_DYNCREATE(COP_Output, CObjectPage)
  58. BEGIN_MESSAGE_MAP(COP_Output, CObjectPage)
  59. //{{AFX_MSG_MAP(COP_Output)
  60. ON_BN_CLICKED(IDC_ADD, OnAdd)
  61. ON_BN_CLICKED(IDC_DELETE, OnDelete)
  62. ON_BN_CLICKED(IDC_COPY, OnCopy)
  63. ON_WM_SIZE()
  64. ON_BN_CLICKED(IDC_PASTE, OnPaste)
  65. ON_BN_CLICKED(IDC_MARK, OnMark)
  66. ON_BN_CLICKED(IDC_PICK_ENTITY, OnPickEntity)
  67. ON_BN_CLICKED(IDC_PICK_ENTITY_PARAM, OnPickEntityParam)
  68. ON_CBN_SELCHANGE(IDC_EDIT_CONN_INPUT, OnSelChangeInput)
  69. ON_CBN_EDITUPDATE(IDC_EDIT_CONN_INPUT, OnEditUpdateInput)
  70. ON_CBN_SELCHANGE(IDC_EDIT_CONN_OUTPUT, OnSelChangeOutput)
  71. ON_CBN_EDITUPDATE(IDC_EDIT_CONN_OUTPUT, OnEditUpdateOutput)
  72. ON_CBN_SELCHANGE(IDC_EDIT_CONN_PARAM, OnSelChangeParam)
  73. ON_CBN_EDITUPDATE(IDC_EDIT_CONN_PARAM, OnEditUpdateParam)
  74. ON_EN_CHANGE(IDC_EDIT_CONN_DELAY, OnEditDelay)
  75. ON_BN_CLICKED(IDC_EDIT_CONN_FIRE_ONCE, OnFireOnce)
  76. ON_BN_CLICKED(IDC_SHOWHIDDENTARGETS, OnShowHiddenTargetsAsBroken)
  77. ON_WM_DESTROY()
  78. //}}AFX_MSG_MAP
  79. END_MESSAGE_MAP()
  80. // ON_CBN_SELCHANGE(IDC_EDIT_CONN_TARGET, OnSelChangeTarget)
  81. // ON_CBN_EDITUPDATE(IDC_EDIT_CONN_TARGET, OnEditUpdateTarget)
  82. //
  83. // Static data.
  84. //
  85. CEntityConnectionList *COP_Output::m_pConnectionBuffer = new CEntityConnectionList;
  86. CImageList *COP_Output::m_pImageList = NULL;
  87. //-----------------------------------------------------------------------------
  88. // Returns true if any of the target entities in the connection list are visible.
  89. //-----------------------------------------------------------------------------
  90. static bool AreAnyTargetEntitiesVisible( CEntityConnectionList *pList )
  91. {
  92. for ( int i=0; i < pList->Count(); i++ )
  93. {
  94. if ( pList->Element(i)->AreAnyTargetEntitiesVisible() )
  95. return true;
  96. }
  97. return false;
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose: Compares by delays. Used as a secondary sort by all other columns.
  101. //-----------------------------------------------------------------------------
  102. static int CALLBACK ListCompareDelaysSecondary(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
  103. {
  104. CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
  105. CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
  106. CEntityConnection *pConn1 = pConnList1->Element(0);
  107. CEntityConnection *pConn2 = pConnList2->Element(0);
  108. return CEntityConnection::CompareDelaysSecondary(pConn1,pConn2,eDirection);
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Purpose: Compares by delays, does a secondary compare by output name.
  112. //-----------------------------------------------------------------------------
  113. static int CALLBACK ListCompareDelays(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
  114. {
  115. CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
  116. CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
  117. CEntityConnection *pConn1 = pConnList1->Element(0);
  118. CEntityConnection *pConn2 = pConnList2->Element(0);
  119. return CEntityConnection::CompareDelays(pConn1,pConn2,eDirection);
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose: Compares by output name, does a secondary compare by delay.
  123. //-----------------------------------------------------------------------------
  124. static int CALLBACK ListCompareOutputNames(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
  125. {
  126. CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
  127. CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
  128. CEntityConnection *pConn1 = pConnList1->Element(0);
  129. CEntityConnection *pConn2 = pConnList2->Element(0);
  130. return CEntityConnection::CompareOutputNames(pConn1,pConn2,eDirection);
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose: Compares by input name, does a secondary compare by delay.
  134. //-----------------------------------------------------------------------------
  135. static int CALLBACK ListCompareInputNames(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
  136. {
  137. CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
  138. CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
  139. CEntityConnection *pConn1 = pConnList1->Element(0);
  140. CEntityConnection *pConn2 = pConnList2->Element(0);
  141. return (CEntityConnection::CompareInputNames(pConn1,pConn2,eDirection));
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose: Compares by source name, does a secondary compare by delay.
  145. //-----------------------------------------------------------------------------
  146. static int CALLBACK ListCompareSourceNames(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
  147. {
  148. CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
  149. CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
  150. CEntityConnection *pConn1 = pConnList1->Element(0);
  151. CEntityConnection *pConn2 = pConnList2->Element(0);
  152. return (CEntityConnection::CompareSourceNames(pConn1,pConn2,eDirection));
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose: Compares by target name, does a secondary compare by delay.
  156. //-----------------------------------------------------------------------------
  157. static int CALLBACK ListCompareTargetNames(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
  158. {
  159. CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
  160. CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
  161. CEntityConnection *pConn1 = pConnList1->Element(0);
  162. CEntityConnection *pConn2 = pConnList2->Element(0);
  163. return (CEntityConnection::CompareTargetNames(pConn1,pConn2,eDirection));
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose: Called by the entity picker tool when an entity is picked. This
  167. // stuffs the entity name into the smartedit control.
  168. //-----------------------------------------------------------------------------
  169. void COP_OutputPickEntityTarget::OnNotifyPickEntity(CToolPickEntity *pTool)
  170. {
  171. //
  172. // Update the edit control text with the entity name. This text will be
  173. // stuffed into the local keyvalue storage in OnChangeSmartControl.
  174. //
  175. CMapEntityList Full;
  176. CMapEntityList Partial;
  177. pTool->GetSelectedEntities(Full, Partial);
  178. CMapEntity *pEntity = Full.Element(0);
  179. if (pEntity)
  180. {
  181. const char *pszName = pEntity->GetKeyValue("targetname");
  182. if (!pszName)
  183. {
  184. pszName = "";
  185. }
  186. switch ( m_nDlgItem )
  187. {
  188. case IDC_EDIT_CONN_TARGET:
  189. {
  190. // FIXME: this should be called automatically, but it isn't
  191. m_pDlg->m_ComboTarget.SelectItem(pszName);
  192. break;
  193. }
  194. case IDC_EDIT_CONN_PARAM:
  195. {
  196. // FIXME: this should be called automatically, but it isn't
  197. m_pDlg->GetDlgItem(m_nDlgItem)->SetWindowText(pszName);
  198. m_pDlg->OnEditUpdateParam();
  199. break;
  200. }
  201. default:
  202. {
  203. m_pDlg->GetDlgItem(m_nDlgItem)->SetWindowText(pszName);
  204. break;
  205. }
  206. }
  207. }
  208. m_pDlg->StopPicking();
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose: Constructor.
  212. //-----------------------------------------------------------------------------
  213. COP_Output::COP_Output(void)
  214. : CObjectPage(COP_Output::IDD), m_ComboTarget( this )
  215. {
  216. m_bIgnoreTextChanged = false;
  217. m_pObjectList = NULL;
  218. m_pEditObjectRuntimeClass = RUNTIME_CLASS(editCMapClass);
  219. m_nSortColumn = OUTPUT_NAME_COLUMN;
  220. m_pMapEntityList = NULL;
  221. m_fDelay = 0;
  222. m_bPickingEntities = false;
  223. bSkipEditControlRefresh = false;
  224. //
  225. // All columns initially sort in ascending order.
  226. //
  227. for (int i = 0; i < OUTPUT_LIST_NUM_COLUMNS; i++)
  228. {
  229. m_eSortDirection[i] = Sort_Ascending;
  230. }
  231. m_PickEntityTarget.AttachEntityDlg(this);
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose: Destructor.
  235. //-----------------------------------------------------------------------------
  236. COP_Output::~COP_Output(void)
  237. {
  238. }
  239. void COP_Output::OnTextChanged( const char *pText )
  240. {
  241. if ( m_bIgnoreTextChanged )
  242. return;
  243. // Updating the listbox data, will trigger the edit
  244. // controls to update. They don't need to be
  245. bSkipEditControlRefresh = true;
  246. // Target has changed so we need to update for list of inputs
  247. // that are valid for this target
  248. FillInputList();
  249. FilterInputList();
  250. m_ComboInput.SetWindowText(m_strInput);
  251. UpdateEditedTargets();
  252. }
  253. //------------------------------------------------------------------------------
  254. // Purpose: Updates the validity flag on the given item in the list control
  255. // Input : nItem -
  256. //------------------------------------------------------------------------------
  257. void COP_Output::UpdateItemValidity(int nItem)
  258. {
  259. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  260. CEntityConnectionList *pConnectionList = pOutputConn->m_pConnList;
  261. bool bShared = (m_EntityList.Count() == pConnectionList->Count());
  262. bool bShowHiddenTargets = ShouldShowHiddenTargets();
  263. int nIcon;
  264. if (ValidateConnections(pOutputConn, bShowHiddenTargets))
  265. {
  266. if ( !bShowHiddenTargets && !AreAnyTargetEntitiesVisible( pConnectionList ) )
  267. nIcon = ICON_CONN_GOOD_GREY;
  268. else if ( bShared )
  269. nIcon = ICON_CONN_GOOD;
  270. else
  271. nIcon = ICON_CONN_GOOD_GREY;
  272. pOutputConn->m_bIsValid = true;
  273. }
  274. else
  275. {
  276. nIcon = (bShared ? ICON_CONN_BAD : ICON_CONN_BAD_GREY);
  277. pOutputConn->m_bIsValid = false;
  278. }
  279. m_ListCtrl.SetItem(nItem,0,LVIF_IMAGE, 0, nIcon, 0, 0, 0 );
  280. }
  281. //------------------------------------------------------------------------------
  282. // Purpose :
  283. //------------------------------------------------------------------------------
  284. void COP_Output::UpdateValidityButton(void)
  285. {
  286. CObjectProperties *pParent = (CObjectProperties*) GetParent();
  287. // Get status of all connections
  288. int nItemCount = m_ListCtrl.GetItemCount();
  289. if (nItemCount == 0)
  290. {
  291. pParent->SetOutputButtonState(CONNECTION_NONE);
  292. return;
  293. }
  294. for (int nItem = 0; nItem < nItemCount; nItem++)
  295. {
  296. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  297. if (!pOutputConn->m_bIsValid)
  298. {
  299. pParent->SetOutputButtonState(CONNECTION_BAD);
  300. return;
  301. }
  302. }
  303. pParent->SetOutputButtonState(CONNECTION_GOOD);
  304. }
  305. //------------------------------------------------------------------------------
  306. // Purpose: Return true if all connections entries are valid for the given
  307. // output connection. Return false otherwise
  308. //------------------------------------------------------------------------------
  309. bool COP_Output::ValidateConnections(COutputConnection *pOutputConn, bool bVisibilityCheck)
  310. {
  311. int nCount = pOutputConn->m_pConnList->Count();
  312. for (int i = 0; i < nCount; i++)
  313. {
  314. CEntityConnection *pConnection = pOutputConn->m_pConnList->Element(i);
  315. if (pConnection != NULL)
  316. {
  317. // Check validity of output for the list of entities
  318. if (!CEntityConnection::ValidateOutput(pOutputConn->m_pEntityList,pConnection->GetOutputName()))
  319. {
  320. return false;
  321. }
  322. // Check validity of target entity (is it in the map?)
  323. if (!CEntityConnection::ValidateTarget(m_pMapEntityList, bVisibilityCheck, pConnection->GetTargetName()))
  324. {
  325. return false;
  326. }
  327. // Check validity of input
  328. if (!CEntityConnection::ValidateInput(pConnection->GetTargetName(), pConnection->GetInputName(), bVisibilityCheck))
  329. {
  330. return false;
  331. }
  332. }
  333. }
  334. return true;
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Purpose:
  338. // Input : pEntity -
  339. // bFirst -
  340. //-----------------------------------------------------------------------------
  341. void COP_Output::AddEntityConnections(CMapEntity *pEntity, bool bFirst)
  342. {
  343. m_ListCtrl.SetRedraw(FALSE);
  344. //
  345. // The first entity simply adds its connections to the list.
  346. //
  347. int nConnCount = pEntity->Connections_GetCount();
  348. for (int i = 0; i < nConnCount; i++)
  349. {
  350. CEntityConnection *pConnection = pEntity->Connections_Get(i);
  351. if (pConnection != NULL)
  352. {
  353. // First check if the connection already exists, if so just add to it
  354. bool bFound = false;
  355. int nItemCount = m_ListCtrl.GetItemCount();
  356. if (nItemCount > 0)
  357. {
  358. for (int nItem = nItemCount - 1; nItem >= 0; nItem--)
  359. {
  360. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  361. CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
  362. CEntityConnection *pTestConn = pConnList->Element(0);
  363. if (pTestConn->CompareConnection(pConnection))
  364. {
  365. // Don't consolidate duplicate connections in the same entity
  366. // Show them twice so the user will see
  367. if ( pOutputConn->m_pEntityList->Find(pEntity) == -1)
  368. {
  369. pConnList->AddToTail(pConnection);
  370. pOutputConn->m_pEntityList->AddToTail(pEntity);
  371. bFound = true;
  372. break;
  373. }
  374. }
  375. }
  376. }
  377. if (!bFound)
  378. {
  379. m_ListCtrl.SetItemCount(nItemCount + 1);
  380. m_ListCtrl.InsertItem(LVIF_IMAGE, nItemCount, "", 0, 0, ICON_CONN_GOOD, 0);
  381. m_ListCtrl.SetItemText(nItemCount, OUTPUT_NAME_COLUMN, pConnection->GetOutputName());
  382. m_ListCtrl.SetItemText(nItemCount, TARGET_NAME_COLUMN, pConnection->GetTargetName());
  383. m_ListCtrl.SetItemText(nItemCount, INPUT_NAME_COLUMN, pConnection->GetInputName());
  384. // Build the string for the delay.
  385. float fDelay = pConnection->GetDelay();
  386. char szTemp[MAX_PATH];
  387. sprintf(szTemp, "%.2f", fDelay);
  388. m_ListCtrl.SetItemText(nItemCount, DELAY_COLUMN, szTemp);
  389. // Fire once
  390. m_ListCtrl.SetItemText(nItemCount, ONLY_ONCE_COLUMN, (pConnection->GetTimesToFire() == EVENT_FIRE_ALWAYS) ? "No" : "Yes");
  391. m_ListCtrl.SetItemText(nItemCount, PARAMETER_COLUMN, pConnection->GetParam());
  392. // Set list ctrl data
  393. COutputConnection* pOutputConn = new COutputConnection;
  394. pOutputConn->m_pConnList = new CEntityConnectionList;
  395. pOutputConn->m_pEntityList = new CMapEntityList;
  396. pOutputConn->m_pConnList->AddToTail(pConnection);
  397. pOutputConn->m_pEntityList->AddToTail(pEntity);
  398. pOutputConn->m_bOwnedByAll = true;
  399. m_ListCtrl.SetItemData(nItemCount, (DWORD)pOutputConn);
  400. nItemCount++;
  401. }
  402. }
  403. }
  404. m_ListCtrl.SetRedraw(TRUE);
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Purpose:
  408. // Input : pDX -
  409. //-----------------------------------------------------------------------------
  410. void COP_Output::DoDataExchange(CDataExchange *pDX)
  411. {
  412. CObjectPage::DoDataExchange(pDX);
  413. //{{AFX_DATA_MAP(COP_Output)
  414. DDX_Control(pDX, IDC_LIST, m_ListCtrl);
  415. DDX_Text(pDX, IDC_EDIT_CONN_DELAY, m_fDelay);
  416. DDX_CBString(pDX, IDC_EDIT_CONN_OUTPUT, m_strOutput);
  417. DDX_CBString(pDX, IDC_EDIT_CONN_TARGET, m_strTarget);
  418. DDX_CBString(pDX, IDC_EDIT_CONN_INPUT, m_strInput);
  419. DDX_CBString(pDX, IDC_EDIT_CONN_PARAM, m_strParam);
  420. DDX_Check(pDX, IDC_EDIT_CONN_FIRE_ONCE, m_bFireOnce);
  421. DDX_Control(pDX, IDC_SHOWHIDDENTARGETS, m_ctlShowHiddenTargetsAsBroken);
  422. DDX_Control(pDX, IDC_ADD, m_AddControl);
  423. DDX_Control(pDX, IDC_PASTE, m_PasteControl);
  424. DDX_Control(pDX, IDC_DELETE, m_DeleteControl);
  425. //}}AFX_DATA_MAP
  426. }
  427. bool COP_Output::ShouldShowHiddenTargets()
  428. {
  429. return (Options.general.bShowHiddenTargetsAsBroken == TRUE);
  430. }
  431. //------------------------------------------------------------------------------
  432. // Purpose: Enables or Disables all edit controls
  433. // Input : bValue -
  434. //------------------------------------------------------------------------------
  435. void COP_Output::EnableEditControls(bool bValue)
  436. {
  437. m_ComboOutput.EnableWindow(bValue);
  438. EnableTarget(bValue);
  439. m_ComboInput.EnableWindow(bValue);
  440. CButton *pButton = (CButton *)GetDlgItem(IDC_EDIT_CONN_FIRE_ONCE);
  441. pButton->EnableWindow(bValue);
  442. CEdit *pDelayEdit = (CEdit *)GetDlgItem(IDC_EDIT_CONN_DELAY);
  443. pDelayEdit->EnableWindow(bValue);
  444. CComboBox *pParamCombo = (CComboBox *)GetDlgItem(IDC_EDIT_CONN_PARAM);
  445. pParamCombo->EnableWindow(bValue);
  446. GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( bValue );
  447. // Clear any values
  448. if (!bValue)
  449. {
  450. m_ComboTarget.ForceEditControlText( "" );
  451. m_ComboInput.SetWindowText("");
  452. m_ComboOutput.SetWindowText("");
  453. pParamCombo->SetCurSel(0);
  454. pDelayEdit->SetWindowText("0.0");
  455. }
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Purpose:
  459. // Input : *pMapEntityList -
  460. //-----------------------------------------------------------------------------
  461. void COP_Output::SetMapEntityList(const CMapEntityList *pMapEntityList)
  462. {
  463. m_pMapEntityList = pMapEntityList;
  464. FillTargetList();
  465. }
  466. //------------------------------------------------------------------------------
  467. // Purpose: Updates data displayed in edit controls
  468. //------------------------------------------------------------------------------
  469. void COP_Output::UpdateEditControls(void)
  470. {
  471. //
  472. // Build a list of connections to edit.
  473. //
  474. m_EditList.RemoveAll();
  475. m_AddControl.EnableWindow( ( m_bCanEdit ? TRUE : FALSE ) );
  476. m_PasteControl.EnableWindow( ( m_bCanEdit ? TRUE : FALSE ) );
  477. m_DeleteControl.EnableWindow( ( m_bCanEdit ? TRUE : FALSE ) );
  478. // If nothing is selected, disable edit controls
  479. if (!m_ListCtrl.IsWindowEnabled() || m_ListCtrl.GetSelectedCount() == 0)
  480. {
  481. EnableEditControls(false);
  482. return;
  483. }
  484. for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
  485. {
  486. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  487. {
  488. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  489. m_EditList.AddVectorToTail(*pOutputConn->m_pConnList);
  490. }
  491. }
  492. if (m_EditList.Count() > 0)
  493. {
  494. SetConnection(&m_EditList);
  495. FillOutputList();
  496. FillInputList();
  497. // We must ignore the text changed event here or else it'll set all selected outputs to the same value.
  498. m_bIgnoreTextChanged = true;
  499. m_ComboTarget.SelectItem(m_strTarget);
  500. m_bIgnoreTextChanged = false;
  501. m_ComboInput.SetWindowText(m_strInput);
  502. m_ComboOutput.SetWindowText(m_strOutput);
  503. m_CheckBoxFireOnce.SetCheck(m_bFireOnce);
  504. CEdit *pDelayEdit = ( CEdit* )GetDlgItem( IDC_EDIT_CONN_DELAY );
  505. char szTemp[MAX_PATH];
  506. sprintf(szTemp, "%.2f", m_fDelay);
  507. pDelayEdit->SetWindowText(szTemp);
  508. CComboBox* pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
  509. pParamEdit->SetWindowText(m_strParam);
  510. FilterInputList();
  511. //
  512. // Update the UI state based on our current data.
  513. //
  514. char szBuf[MAX_IO_NAME_LEN];
  515. CClassOutput *pOutput = GetOutput(szBuf, sizeof(szBuf));
  516. UpdateCombosForSelectedOutput(pOutput);
  517. CClassInput *pInput = GetInput(szBuf, sizeof(szBuf));
  518. UpdateCombosForSelectedInput(pInput);
  519. //CMapEntityList *pTarget = GetTarget(szBuf, sizeof(szBuf));
  520. //UpdateCombosForSelectedTarget(pTarget);
  521. }
  522. if ( m_bCanEdit == false )
  523. {
  524. EnableEditControls( false );
  525. }
  526. }
  527. //-----------------------------------------------------------------------------
  528. // Purpose: Adds a connection to all entities being edited.
  529. //-----------------------------------------------------------------------------
  530. void COP_Output::OnAdd(void)
  531. {
  532. FOR_EACH_OBJ( m_EntityList, pos)
  533. {
  534. CMapEntity *pEntity = m_EntityList.Element(pos);
  535. if (pEntity != NULL)
  536. {
  537. CEntityConnection *pConnection = new CEntityConnection;
  538. pEntity->Connections_Add(pConnection);
  539. }
  540. }
  541. UpdateConnectionList();
  542. // Set selection to new item, and move the focus to the output combo
  543. // so they can just start editing.
  544. int nCount = m_ListCtrl.GetItemCount();
  545. SetSelectedItem(nCount - 1);
  546. m_ListCtrl.EnsureVisible(nCount - 1, FALSE);
  547. GetDlgItem(IDC_EDIT_CONN_OUTPUT)->SetFocus();
  548. }
  549. //------------------------------------------------------------------------------
  550. // Purpose: Clear copy buffer
  551. //------------------------------------------------------------------------------
  552. void COP_Output::EmptyCopyBuffer(void)
  553. {
  554. // Delete any old connections
  555. int nConnCount = m_pConnectionBuffer->Count();
  556. for (int i = 0; i < nConnCount; i++)
  557. {
  558. CEntityConnection *pConnection = m_pConnectionBuffer->Element(i);
  559. if (pConnection != NULL)
  560. {
  561. delete pConnection;
  562. }
  563. }
  564. m_pConnectionBuffer->RemoveAll();
  565. }
  566. //-----------------------------------------------------------------------------
  567. // Purpose: Copies list of selected connections into copy buffer
  568. //-----------------------------------------------------------------------------
  569. void COP_Output::OnCopy(void)
  570. {
  571. EmptyCopyBuffer();
  572. if (m_ListCtrl.GetSelectedCount() != 0)
  573. {
  574. int nCount = m_ListCtrl.GetItemCount();
  575. if (nCount > 0)
  576. {
  577. for (int nItem = nCount - 1; nItem >= 0; nItem--)
  578. {
  579. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  580. {
  581. //
  582. // Each item in the list control is a list of identical connections that are contained
  583. // in multiple entities. Add each selected connection to the selected entities.
  584. //
  585. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  586. CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
  587. if (pConnList != NULL)
  588. {
  589. CEntityConnection *pConnection = pConnList->Element(0);
  590. if (pConnection)
  591. {
  592. CEntityConnection *pNewConnection = new CEntityConnection;
  593. *pNewConnection = *pConnection;
  594. m_pConnectionBuffer->AddToTail(pNewConnection);
  595. }
  596. }
  597. }
  598. }
  599. }
  600. }
  601. }
  602. //-----------------------------------------------------------------------------
  603. // Purpose: Adds a connection to all entities being edited.
  604. //-----------------------------------------------------------------------------
  605. void COP_Output::OnPaste(void)
  606. {
  607. // Early out
  608. if (!m_pConnectionBuffer->Count())
  609. {
  610. return;
  611. }
  612. CUtlVector<CEntityConnection *> NewConnections;
  613. // Add connections from copy buffer to all selected entities
  614. FOR_EACH_OBJ( m_EntityList, pos )
  615. {
  616. CMapEntity *pEntity = m_EntityList.Element(pos);
  617. if (pEntity != NULL)
  618. {
  619. int nConnCount = m_pConnectionBuffer->Count();
  620. for (int i = 0; i < nConnCount; i++)
  621. {
  622. CEntityConnection *pConnection = m_pConnectionBuffer->Element(i);
  623. if (pConnection != NULL)
  624. {
  625. CEntityConnection *pNewConnection = new CEntityConnection;
  626. *pNewConnection = *pConnection;
  627. pEntity->Connections_Add(pNewConnection);
  628. NewConnections.AddToTail(pNewConnection);
  629. }
  630. }
  631. }
  632. }
  633. UpdateConnectionList();
  634. SortListByColumn(m_nSortColumn, m_eSortDirection[m_nSortColumn]);
  635. SetSelectedConnections(NewConnections);
  636. GetDlgItem(IDC_EDIT_CONN_OUTPUT)->SetFocus();
  637. }
  638. //-----------------------------------------------------------------------------
  639. // Purpose:
  640. //-----------------------------------------------------------------------------
  641. void COP_Output::OnPickEntity(void)
  642. {
  643. CButton *pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY);
  644. Assert(pButton != NULL);
  645. if (pButton != NULL)
  646. {
  647. if (pButton->GetCheck())
  648. {
  649. //
  650. // Activate the entity picker tool.
  651. //
  652. m_bPickingEntities = true;
  653. m_PickEntityTarget.AttachDlgItem( IDC_EDIT_CONN_TARGET );
  654. CToolPickEntity *pTool = (CToolPickEntity *)ToolManager()->GetToolForID(TOOL_PICK_ENTITY);
  655. pTool->Attach(&m_PickEntityTarget);
  656. ToolManager()->SetTool(TOOL_PICK_ENTITY);
  657. GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( false );
  658. }
  659. else
  660. {
  661. StopPicking();
  662. }
  663. }
  664. }
  665. //-----------------------------------------------------------------------------
  666. // Purpose:
  667. //-----------------------------------------------------------------------------
  668. void COP_Output::OnPickEntityParam(void)
  669. {
  670. CButton *pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY_PARAM);
  671. Assert(pButton != NULL);
  672. if (pButton != NULL)
  673. {
  674. if (pButton->GetCheck())
  675. {
  676. //
  677. // Activate the entity picker tool.
  678. //
  679. m_bPickingEntities = true;
  680. m_PickEntityTarget.AttachDlgItem( IDC_EDIT_CONN_PARAM );
  681. CToolPickEntity *pTool = (CToolPickEntity *)ToolManager()->GetToolForID(TOOL_PICK_ENTITY);
  682. pTool->Attach(&m_PickEntityTarget);
  683. ToolManager()->SetTool(TOOL_PICK_ENTITY);
  684. GetDlgItem(IDC_PICK_ENTITY)->EnableWindow( false );
  685. }
  686. else
  687. {
  688. StopPicking();
  689. }
  690. }
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Purpose: Deletes all selected items from the connection list, and removes the
  694. // corresponding connections from the list of entities being edited.
  695. //-----------------------------------------------------------------------------
  696. void COP_Output::OnDelete(void)
  697. {
  698. if (m_ListCtrl.GetSelectedCount() != 0)
  699. {
  700. int nCount = m_ListCtrl.GetItemCount();
  701. int nLastItem = 0;
  702. if (nCount > 0)
  703. {
  704. for (int nItem = nCount - 1; nItem >= 0; nItem--)
  705. {
  706. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  707. {
  708. //
  709. // Each item in the list control is a list of identical connections that are contained
  710. // in multiple entities. Since we don't store the containing entity along with the connection,
  711. // just try to remove all the connections in the list from all the selected entities.
  712. //
  713. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  714. CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
  715. m_ListCtrl.DeleteItem(nItem);
  716. if (pConnList != NULL)
  717. {
  718. int nConnCount = pConnList->Count();
  719. for (int nConn = 0; nConn < nConnCount; nConn++)
  720. {
  721. CEntityConnection *pConnection = pConnList->Element(nConn);
  722. if (pConnection != NULL)
  723. {
  724. //
  725. // Remove the connection from all entities being edited.
  726. //
  727. FOR_EACH_OBJ( m_EntityList, pos )
  728. {
  729. CMapEntity *pEntity = m_EntityList.Element(pos);
  730. if (pEntity != NULL)
  731. {
  732. pEntity->Connections_Remove(pConnection);
  733. }
  734. }
  735. //
  736. // Remove the connection from the upstream list of all entities it targets.
  737. //
  738. CMapEntityList *pTargetList = pConnection->GetTargetEntityList();
  739. if ( pTargetList )
  740. {
  741. FOR_EACH_OBJ( *pTargetList, pos2 )
  742. {
  743. CMapEntity *pEntity = pTargetList->Element( pos2 );
  744. pEntity->Upstream_Remove( pConnection );
  745. }
  746. }
  747. }
  748. delete pConnection;
  749. }
  750. delete pConnList;
  751. }
  752. // Keep track of last item so can set selection focus
  753. nLastItem = nItem;
  754. }
  755. }
  756. }
  757. // Set selection focus as point of deletion or on last item
  758. int nNumItems = m_ListCtrl.GetItemCount()-1;
  759. if (nLastItem > nNumItems)
  760. {
  761. nLastItem = nNumItems;
  762. }
  763. SetSelectedItem(nLastItem);
  764. UpdateValidityButton();
  765. }
  766. }
  767. //------------------------------------------------------------------------------
  768. // Purpose : Take the user to the output page of the selected entity that
  769. // targets me.
  770. // Input :
  771. // Output :
  772. //------------------------------------------------------------------------------
  773. void COP_Output::OnMark(void)
  774. {
  775. int nCount = m_ListCtrl.GetItemCount();
  776. CMapDoc* pDoc = CMapDoc::GetActiveMapDoc();
  777. CEntityConnection *pConnection = NULL;
  778. if (nCount > 0 && pDoc)
  779. {
  780. CMapObjectList Select;
  781. for (int nItem = nCount - 1; nItem >= 0; nItem--)
  782. {
  783. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  784. {
  785. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  786. pConnection = pOutputConn->m_pConnList->Element(0);
  787. CMapDoc *pDocActive = CMapDoc::GetActiveMapDoc();
  788. if ( pDocActive != NULL)
  789. {
  790. CMapEntityList Found;
  791. pDocActive->FindEntitiesByName(Found, m_ListCtrl.GetItemText(nItem, TARGET_NAME_COLUMN), false);
  792. FOR_EACH_OBJ( Found, pos )
  793. {
  794. CMapEntity *pEntity = Found.Element(pos);
  795. Select.AddToTail(pEntity);
  796. }
  797. }
  798. }
  799. }
  800. if (Select.Count()>0)
  801. {
  802. pDoc->SelectObjectList(&Select);
  803. // (a bit squirly way of doing this)
  804. if ( Select.Count()==1 )
  805. GetMainWnd()->pObjectProperties->SetPageToInput(pConnection);
  806. pDoc->Center2DViewsOnSelection();
  807. }
  808. else
  809. {
  810. MessageBox("No entities were found with that targetname.", "No entities found", MB_ICONINFORMATION | MB_OK);
  811. return;
  812. }
  813. }
  814. }
  815. //-----------------------------------------------------------------------------
  816. // Purpose: Sets up the list view columns, initial sort column.
  817. //-----------------------------------------------------------------------------
  818. BOOL COP_Output::OnInitDialog(void)
  819. {
  820. CObjectPage::OnInitDialog();
  821. m_ComboOutput.SubclassDlgItem(IDC_EDIT_CONN_OUTPUT, this);
  822. m_ComboInput.SubclassDlgItem(IDC_EDIT_CONN_INPUT, this);
  823. m_ComboTarget.SubclassDlgItem(IDC_EDIT_CONN_TARGET, this);
  824. m_CheckBoxFireOnce.SubclassDlgItem(IDC_EDIT_CONN_FIRE_ONCE, this);
  825. m_ListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP);
  826. m_ListCtrl.InsertColumn(ICON_COLUMN, "", LVCFMT_CENTER, 20);
  827. m_ListCtrl.InsertColumn(OUTPUT_NAME_COLUMN, "My Output", LVCFMT_LEFT, 70);
  828. m_ListCtrl.InsertColumn(TARGET_NAME_COLUMN, "Target Entity", LVCFMT_LEFT, 70);
  829. m_ListCtrl.InsertColumn(INPUT_NAME_COLUMN, "Target Input", LVCFMT_LEFT, 70);
  830. m_ListCtrl.InsertColumn(DELAY_COLUMN, "Delay", LVCFMT_LEFT, 70);
  831. m_ListCtrl.InsertColumn(ONLY_ONCE_COLUMN, "Only Once", LVCFMT_LEFT, 70);
  832. m_ListCtrl.InsertColumn(PARAMETER_COLUMN, "Parameter", LVCFMT_LEFT, 70);
  833. UpdateConnectionList();
  834. SetSortColumn(m_nSortColumn, m_eSortDirection[m_nSortColumn]);
  835. // Force an update of the column header text so that the sort indicator is shown.
  836. UpdateColumnHeaderText(m_nSortColumn, true, m_eSortDirection[m_nSortColumn]);
  837. ResizeColumns();
  838. m_strLastParam.Empty();
  839. // Select the first item in the combo box
  840. SetSelectedItem(0);
  841. // Create image list. Is deleted automatically when listctrl is deleted
  842. if (!m_pImageList)
  843. {
  844. CWinApp *pApp = AfxGetApp();
  845. m_pImageList = new CImageList();
  846. Assert(m_pImageList != NULL); // serious allocation failure checking
  847. m_pImageList->Create(16, 16, TRUE, 1, 0);
  848. m_pImageList->Add(pApp->LoadIcon( IDI_OUTPUTBAD ));
  849. m_pImageList->Add(pApp->LoadIcon( IDI_OUTPUT ));
  850. m_pImageList->Add(pApp->LoadIcon( IDI_OUTPUTBAD_GREY ));
  851. m_pImageList->Add(pApp->LoadIcon( IDI_OUTPUT_GREY ));
  852. }
  853. m_ListCtrl.SetImageList(m_pImageList, LVSIL_SMALL );
  854. // Apply the eyedropper image to the picker buttons.
  855. CButton *pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY);
  856. if (pButton)
  857. {
  858. CWinApp *pApp = AfxGetApp();
  859. HICON hIcon = pApp->LoadIcon(IDI_EYEDROPPER);
  860. pButton->SetIcon(hIcon);
  861. }
  862. pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY_PARAM);
  863. if (pButton)
  864. {
  865. CWinApp *pApp = AfxGetApp();
  866. HICON hIcon = pApp->LoadIcon(IDI_EYEDROPPER);
  867. pButton->SetIcon(hIcon);
  868. }
  869. CAnchorDef anchorDefs[] =
  870. {
  871. CAnchorDef( IDC_LIST, k_eSimpleAnchorAllSides ),
  872. CAnchorDef( IDC_OUTPUTS_STATIC_PANEL, k_eAnchorLeft, k_eAnchorBottom, k_eAnchorRight, k_eAnchorBottom ),
  873. CAnchorDef( IDC_OUTPUT_LABEL, k_eSimpleAnchorBottomSide ),
  874. CAnchorDef( IDC_TARGETS_LABEL, k_eSimpleAnchorBottomSide ),
  875. CAnchorDef( IDC_VIA_INPUT_LABEL, k_eSimpleAnchorBottomSide ),
  876. CAnchorDef( IDC_PARAMETER_LABEL, k_eSimpleAnchorBottomSide ),
  877. CAnchorDef( IDC_DELAY_LABEL, k_eSimpleAnchorBottomSide ),
  878. CAnchorDef( IDC_EDIT_CONN_DELAY, k_eSimpleAnchorBottomSide ),
  879. CAnchorDef( IDC_EDIT_CONN_FIRE_ONCE, k_eSimpleAnchorBottomSide ),
  880. CAnchorDef( IDC_EDIT_CONN_PARAM, k_eSimpleAnchorBottomSide ),
  881. CAnchorDef( IDC_EDIT_CONN_INPUT, k_eSimpleAnchorBottomSide ),
  882. CAnchorDef( IDC_EDIT_CONN_TARGET, k_eSimpleAnchorBottomSide ),
  883. CAnchorDef( IDC_EDIT_CONN_OUTPUT, k_eSimpleAnchorBottomSide ),
  884. CAnchorDef( IDC_PICK_ENTITY, k_eSimpleAnchorBottomSide ),
  885. CAnchorDef( IDC_PICK_ENTITY_PARAM, k_eSimpleAnchorBottomSide ),
  886. CAnchorDef( IDC_MARK, k_eSimpleAnchorBottomSide ),
  887. CAnchorDef( IDC_ADD, k_eSimpleAnchorBottomSide ),
  888. CAnchorDef( IDC_COPY, k_eSimpleAnchorBottomSide ),
  889. CAnchorDef( IDC_PASTE, k_eSimpleAnchorBottomSide ),
  890. CAnchorDef( IDC_DELETE, k_eSimpleAnchorBottomSide ),
  891. CAnchorDef( IDC_SHOWHIDDENTARGETS, k_eSimpleAnchorBottomRight )
  892. };
  893. m_AnchorMgr.Init( GetSafeHwnd(), anchorDefs, ARRAYSIZE( anchorDefs ) );
  894. // Set the last state this was at.
  895. m_ctlShowHiddenTargetsAsBroken.SetCheck( ShouldShowHiddenTargets() );
  896. return(TRUE);
  897. }
  898. //-----------------------------------------------------------------------------
  899. // Purpose:
  900. // Input : wParam -
  901. // lParam -
  902. // pResult -
  903. // Output : Returns TRUE on success, FALSE on failure.
  904. //-----------------------------------------------------------------------------
  905. BOOL COP_Output::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult)
  906. {
  907. NMHDR *pnmh = (NMHDR *)lParam;
  908. if (pnmh->idFrom == IDC_LIST)
  909. {
  910. switch (pnmh->code)
  911. {
  912. case LVN_COLUMNCLICK:
  913. {
  914. NMLISTVIEW *pnmv = (NMLISTVIEW *)lParam;
  915. if (pnmv->iSubItem < OUTPUT_LIST_NUM_COLUMNS)
  916. {
  917. SortDirection_t eSortDirection = m_eSortDirection[pnmv->iSubItem];
  918. //
  919. // If they clicked on the current sort column, reverse the sort direction.
  920. //
  921. if (pnmv->iSubItem == m_nSortColumn)
  922. {
  923. if (m_eSortDirection[m_nSortColumn] == Sort_Ascending)
  924. {
  925. eSortDirection = Sort_Descending;
  926. }
  927. else
  928. {
  929. eSortDirection = Sort_Ascending;
  930. }
  931. }
  932. //
  933. // Update the sort column and sort the list.
  934. //
  935. SetSortColumn(pnmv->iSubItem, eSortDirection);
  936. }
  937. return(TRUE);
  938. }
  939. case NM_DBLCLK:
  940. {
  941. OnMark();
  942. return(TRUE);
  943. }
  944. case LVN_ITEMCHANGED:
  945. {
  946. NMLISTVIEW *pnmv = (NMLISTVIEW *)lParam;
  947. if ( ( pnmv->uNewState & LVIS_SELECTED ) != ( pnmv->uOldState & LVIS_SELECTED ) )
  948. {
  949. // Listbox selection has changed so update edit controls
  950. if (!bSkipEditControlRefresh)
  951. {
  952. UpdateEditControls();
  953. }
  954. bSkipEditControlRefresh = false;
  955. // Forget the saved param, because it was for a different I/O connection.
  956. m_strLastParam.Empty();
  957. }
  958. return(TRUE);
  959. }
  960. }
  961. }
  962. return(CObjectPage::OnNotify(wParam, lParam, pResult));
  963. }
  964. //-----------------------------------------------------------------------------
  965. // Purpose: Empties the contents of the connections list control, freeing the
  966. // connection list hanging off of each row.
  967. //-----------------------------------------------------------------------------
  968. void COP_Output::RemoveAllEntityConnections(void)
  969. {
  970. m_ListCtrl.SetRedraw(FALSE);
  971. int nCount = m_ListCtrl.GetItemCount();
  972. if (nCount > 0)
  973. {
  974. for (int nItem = nCount - 1; nItem >= 0; nItem--)
  975. {
  976. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  977. CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
  978. CMapEntityList *pEntityList = pOutputConn->m_pEntityList;
  979. m_ListCtrl.DeleteItem(nItem);
  980. delete pOutputConn;
  981. delete pConnList;
  982. delete pEntityList;
  983. }
  984. }
  985. m_ListCtrl.SetRedraw(TRUE);
  986. }
  987. //-----------------------------------------------------------------------------
  988. // Purpose:
  989. // Input : Mode -
  990. // pData -
  991. //-----------------------------------------------------------------------------
  992. void COP_Output::UpdateData( int Mode, PVOID pData, bool bCanEdit )
  993. {
  994. __super::UpdateData( Mode, pData, bCanEdit );
  995. if (!IsWindow(m_hWnd))
  996. {
  997. return;
  998. }
  999. switch (Mode)
  1000. {
  1001. case LoadFirstData:
  1002. {
  1003. // m_ListCtrl.DeleteAllItems();
  1004. // UpdateConnectionList();
  1005. break;
  1006. }
  1007. case LoadData:
  1008. {
  1009. // m_ListCtrl.DeleteAllItems();
  1010. // UpdateConnectionList();
  1011. // SetSelectedItem(0);
  1012. break;
  1013. }
  1014. case LoadFinished:
  1015. {
  1016. m_ListCtrl.DeleteAllItems();
  1017. UpdateConnectionList();
  1018. SetSelectedItem(0);
  1019. SortListByColumn(m_nSortColumn, m_eSortDirection[m_nSortColumn]);
  1020. }
  1021. }
  1022. UpdateEditControls();
  1023. }
  1024. //------------------------------------------------------------------------------
  1025. // Purpose: Generates list of map entites that are being edited from the
  1026. // m_pObject list
  1027. //------------------------------------------------------------------------------
  1028. void COP_Output::UpdateEntityList(void)
  1029. {
  1030. // Clear old entity list
  1031. m_EntityList.RemoveAll();
  1032. if (m_pObjectList != NULL)
  1033. {
  1034. FOR_EACH_OBJ( *m_pObjectList, pos )
  1035. {
  1036. CMapClass *pObject = m_pObjectList->Element(pos);
  1037. if ((pObject != NULL) && (pObject->IsMapClass(MAPCLASS_TYPE(CMapEntity))) )
  1038. {
  1039. CMapEntity *pEntity = (CMapEntity *)pObject;
  1040. m_EntityList.AddToTail(pEntity);
  1041. }
  1042. }
  1043. }
  1044. }
  1045. //-----------------------------------------------------------------------------
  1046. // Purpose:
  1047. // Input : nColumn -
  1048. // eDirection -
  1049. //-----------------------------------------------------------------------------
  1050. void COP_Output::SetSortColumn(int nColumn, SortDirection_t eDirection)
  1051. {
  1052. Assert(nColumn < OUTPUT_LIST_NUM_COLUMNS);
  1053. //
  1054. // If the sort column changed, update the old sort column header text.
  1055. //
  1056. if (m_nSortColumn != nColumn)
  1057. {
  1058. UpdateColumnHeaderText(m_nSortColumn, false, eDirection);
  1059. }
  1060. //
  1061. // If the sort column or direction changed, update the new sort column header text.
  1062. //
  1063. if ((m_nSortColumn != nColumn) || (m_eSortDirection[m_nSortColumn] != eDirection))
  1064. {
  1065. UpdateColumnHeaderText(nColumn, true, eDirection);
  1066. }
  1067. m_nSortColumn = nColumn;
  1068. m_eSortDirection[m_nSortColumn] = eDirection;
  1069. SortListByColumn(m_nSortColumn, m_eSortDirection[m_nSortColumn]);
  1070. }
  1071. //-----------------------------------------------------------------------------
  1072. // Purpose: Sorts the outputs list by column.
  1073. // Input : nColumn - Index of column by which to sort.
  1074. //-----------------------------------------------------------------------------
  1075. void COP_Output::SortListByColumn(int nColumn, SortDirection_t eDirection)
  1076. {
  1077. PFNLVCOMPARE pfnSort = NULL;
  1078. switch (nColumn)
  1079. {
  1080. case ONLY_ONCE_COLUMN:
  1081. {
  1082. //No Sort
  1083. break;
  1084. }
  1085. case PARAMETER_COLUMN:
  1086. {
  1087. //No Sort
  1088. break;
  1089. }
  1090. case OUTPUT_NAME_COLUMN:
  1091. {
  1092. pfnSort = (PFNLVCOMPARE)ListCompareOutputNames;
  1093. break;
  1094. }
  1095. case TARGET_NAME_COLUMN:
  1096. {
  1097. pfnSort = (PFNLVCOMPARE)ListCompareTargetNames;
  1098. break;
  1099. }
  1100. case INPUT_NAME_COLUMN:
  1101. {
  1102. pfnSort = (PFNLVCOMPARE)ListCompareInputNames;
  1103. break;
  1104. }
  1105. case DELAY_COLUMN:
  1106. {
  1107. pfnSort = (PFNLVCOMPARE)ListCompareDelays;
  1108. break;
  1109. }
  1110. default:
  1111. {
  1112. Assert(FALSE);
  1113. break;
  1114. }
  1115. }
  1116. if (pfnSort != NULL)
  1117. {
  1118. m_ListCtrl.SortItems(pfnSort, (DWORD)eDirection);
  1119. }
  1120. }
  1121. //-----------------------------------------------------------------------------
  1122. // Purpose:
  1123. //-----------------------------------------------------------------------------
  1124. void COP_Output::ResizeColumns(void)
  1125. {
  1126. if (m_ListCtrl.GetItemCount() > 0)
  1127. {
  1128. m_ListCtrl.SetColumnWidth(OUTPUT_NAME_COLUMN, LVSCW_AUTOSIZE);
  1129. m_ListCtrl.SetColumnWidth(TARGET_NAME_COLUMN, LVSCW_AUTOSIZE);
  1130. m_ListCtrl.SetColumnWidth(INPUT_NAME_COLUMN, LVSCW_AUTOSIZE);
  1131. m_ListCtrl.SetColumnWidth(DELAY_COLUMN, LVSCW_AUTOSIZE_USEHEADER);
  1132. m_ListCtrl.SetColumnWidth(ONLY_ONCE_COLUMN, LVSCW_AUTOSIZE_USEHEADER);
  1133. m_ListCtrl.SetColumnWidth(PARAMETER_COLUMN, LVSCW_AUTOSIZE);
  1134. }
  1135. }
  1136. //-----------------------------------------------------------------------------
  1137. // Purpose:
  1138. //-----------------------------------------------------------------------------
  1139. void COP_Output::UpdateConnectionList(void)
  1140. {
  1141. // Get list of all entities in the world
  1142. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1143. Assert(pDoc != NULL);
  1144. if (!pDoc)
  1145. return;
  1146. CMapWorld *pWorld = pDoc->GetMapWorld();
  1147. Assert(pWorld != NULL); // dvs: I've seen pWorld be NULL on app shutdown, not sure why we ended up here though
  1148. if (!pWorld)
  1149. return;
  1150. SetMapEntityList(pWorld->EntityList_GetList());
  1151. UpdateEntityList();
  1152. RemoveAllEntityConnections();
  1153. bool bFirst = true;
  1154. FOR_EACH_OBJ( m_EntityList, pos )
  1155. {
  1156. CMapEntity *pEntity = m_EntityList.Element(pos);
  1157. if (pEntity != NULL)
  1158. {
  1159. AddEntityConnections(pEntity, bFirst);
  1160. bFirst = false;
  1161. }
  1162. }
  1163. // Update validity flag on all items
  1164. for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
  1165. {
  1166. UpdateItemValidity(nItem);
  1167. }
  1168. UpdateValidityButton();
  1169. ResizeColumns();
  1170. }
  1171. //------------------------------------------------------------------------------
  1172. // Purpose: Set the selected item in the listbox by index.
  1173. // Input : nSelectItem -
  1174. //------------------------------------------------------------------------------
  1175. void COP_Output::SetSelectedItem(int nSelectItem)
  1176. {
  1177. m_ListCtrl.SetRedraw(FALSE);
  1178. // Set selected item to be active and all others to false
  1179. int nItemCount = m_ListCtrl.GetItemCount();
  1180. for (int nItem = 0; nItem < nItemCount; nItem++)
  1181. {
  1182. if (nItem == nSelectItem)
  1183. {
  1184. m_ListCtrl.SetItemState(nItem, (unsigned int)LVIS_SELECTED, (unsigned int)LVIS_SELECTED);
  1185. }
  1186. else
  1187. {
  1188. m_ListCtrl.SetItemState(nItem, (unsigned int)~LVIS_SELECTED, (unsigned int)LVIS_SELECTED);
  1189. }
  1190. }
  1191. m_ListCtrl.SetRedraw(TRUE);
  1192. // Selected item has changed so update edit controls
  1193. UpdateEditControls();
  1194. }
  1195. //------------------------------------------------------------------------------
  1196. // Purpose: Set the selected item in the listbox
  1197. // Input : pConnection
  1198. //------------------------------------------------------------------------------
  1199. void COP_Output::SetSelectedConnection(CEntityConnection *pConnection)
  1200. {
  1201. m_ListCtrl.SetRedraw(FALSE);
  1202. // Set selected item to be active and all others to false
  1203. int nItemCount = m_ListCtrl.GetItemCount();
  1204. for (int nItem = 0; nItem < nItemCount; nItem++)
  1205. {
  1206. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  1207. CEntityConnectionList *pTestList = pOutputConn->m_pConnList;
  1208. if (pTestList->Element(0) == pConnection)
  1209. {
  1210. m_ListCtrl.SetItemState(nItem,LVIS_SELECTED,LVIS_SELECTED);
  1211. }
  1212. else
  1213. {
  1214. m_ListCtrl.SetItemState(nItem, (unsigned int)~LVIS_SELECTED, (unsigned int)LVIS_SELECTED);
  1215. }
  1216. }
  1217. m_ListCtrl.SetRedraw(TRUE);
  1218. // Selected item has changed so update edit controls
  1219. UpdateEditControls();
  1220. }
  1221. //-----------------------------------------------------------------------------
  1222. // Purpose: Selects the list box entries that correspond to the connections in
  1223. // the given list.
  1224. //-----------------------------------------------------------------------------
  1225. void COP_Output::SetSelectedConnections(CEntityConnectionList &List)
  1226. {
  1227. m_ListCtrl.SetRedraw(FALSE);
  1228. int nConnCount = List.Count();
  1229. int nItemCount = m_ListCtrl.GetItemCount();
  1230. for (int nItem = 0; nItem < nItemCount; nItem++)
  1231. {
  1232. COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
  1233. CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
  1234. // See if this row's list holds any of the connections in the given list.
  1235. bool bFound = false;
  1236. for (int nConn = 0; nConn < nConnCount; nConn++)
  1237. {
  1238. CEntityConnection *pConn = List.Element(nConn);
  1239. if (pConnList->Find(pConn) != -1)
  1240. {
  1241. bFound = true;
  1242. break;
  1243. }
  1244. }
  1245. m_ListCtrl.SetItemState(nItem, bFound ? LVIS_SELECTED : ~LVIS_SELECTED, LVIS_SELECTED);
  1246. }
  1247. m_ListCtrl.SetRedraw(TRUE);
  1248. UpdateEditControls();
  1249. }
  1250. //-----------------------------------------------------------------------------
  1251. // Purpose: Adds or removes the little 'V' or '^' sort indicator as appropriate.
  1252. // Input : nColumn - Index of column to update.
  1253. // bSortColumn - true if this column is the sort column, false if not.
  1254. // eDirection - Direction of sort, Sort_Ascending or Sort_Descending.
  1255. //-----------------------------------------------------------------------------
  1256. void COP_Output::UpdateColumnHeaderText(int nColumn, bool bIsSortColumn, SortDirection_t eDirection)
  1257. {
  1258. char szHeaderText[MAX_PATH];
  1259. LVCOLUMN Column;
  1260. memset(&Column, 0, sizeof(Column));
  1261. Column.mask = LVCF_TEXT;
  1262. Column.pszText = szHeaderText;
  1263. Column.cchTextMax = sizeof(szHeaderText);
  1264. m_ListCtrl.GetColumn(nColumn, &Column);
  1265. int nMarker = 0;
  1266. if (szHeaderText[0] != '\0')
  1267. {
  1268. nMarker = strlen(szHeaderText) - 1;
  1269. char chMarker = szHeaderText[nMarker];
  1270. if ((chMarker == '>') || (chMarker == '<'))
  1271. {
  1272. nMarker -= 2;
  1273. }
  1274. else
  1275. {
  1276. nMarker++;
  1277. }
  1278. }
  1279. if (bIsSortColumn)
  1280. {
  1281. if (nMarker != 0)
  1282. {
  1283. szHeaderText[nMarker++] = ' ';
  1284. szHeaderText[nMarker++] = ' ';
  1285. }
  1286. szHeaderText[nMarker++] = (eDirection == Sort_Ascending) ? '>' : '<';
  1287. }
  1288. szHeaderText[nMarker] = '\0';
  1289. m_ListCtrl.SetColumn(nColumn, &Column);
  1290. }
  1291. //-----------------------------------------------------------------------------
  1292. // Purpose: Called when our window is being destroyed.
  1293. //-----------------------------------------------------------------------------
  1294. void COP_Output::OnDestroy(void)
  1295. {
  1296. m_ListCtrl.EnableWindow(false);
  1297. RemoveAllEntityConnections();
  1298. }
  1299. //------------------------------------------------------------------------------
  1300. // Purpose:
  1301. //------------------------------------------------------------------------------
  1302. void COP_Output::UpdateEditedFireOnce(void)
  1303. {
  1304. // Get new delay
  1305. CButton *pButton = ( CButton* )GetDlgItem( IDC_EDIT_CONN_FIRE_ONCE );
  1306. if (pButton->IsWindowEnabled())
  1307. {
  1308. int nChecked = (pButton->GetState()&0x0003); // Checked state
  1309. // Update the connections
  1310. int nConnCount = m_EditList.Count();
  1311. for (int nConn = 0; nConn < nConnCount; nConn++)
  1312. {
  1313. CEntityConnection *pConnection = m_EditList.Element(nConn);
  1314. if (pConnection != NULL)
  1315. {
  1316. pConnection->SetTimesToFire(nChecked?1:EVENT_FIRE_ALWAYS);
  1317. }
  1318. }
  1319. // Update the list box
  1320. for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
  1321. {
  1322. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  1323. {
  1324. m_ListCtrl.SetItemText(nItem, ONLY_ONCE_COLUMN, nChecked ? "Yes" : "No");
  1325. }
  1326. }
  1327. ResizeColumns();
  1328. }
  1329. }
  1330. //------------------------------------------------------------------------------
  1331. // Purpose:
  1332. //------------------------------------------------------------------------------
  1333. void COP_Output::UpdateEditedDelays(void)
  1334. {
  1335. // Get new delay
  1336. CEdit *pDelayEdit = ( CEdit* )GetDlgItem( IDC_EDIT_CONN_DELAY );
  1337. if (pDelayEdit->IsWindowEnabled())
  1338. {
  1339. char strDelay[MAX_IO_NAME_LEN];
  1340. pDelayEdit->GetWindowText(strDelay, sizeof(strDelay));
  1341. float flDelay = atof(strDelay);
  1342. // Update the connections
  1343. int nConnCount = m_EditList.Count();
  1344. for (int nConn = 0; nConn < nConnCount; nConn++)
  1345. {
  1346. CEntityConnection *pConnection = m_EditList.Element(nConn);
  1347. if (pConnection != NULL)
  1348. {
  1349. pConnection->SetDelay(flDelay);
  1350. }
  1351. }
  1352. // Update the list box
  1353. for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
  1354. {
  1355. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  1356. {
  1357. m_ListCtrl.SetItemText(nItem, DELAY_COLUMN, strDelay);
  1358. }
  1359. }
  1360. ResizeColumns();
  1361. }
  1362. }
  1363. //------------------------------------------------------------------------------
  1364. // Purpose: Parameters have changed. Update connections and listbox
  1365. //------------------------------------------------------------------------------
  1366. void COP_Output::UpdateEditedParams(void)
  1367. {
  1368. CComboBox *pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
  1369. if (pParamEdit->IsWindowEnabled())
  1370. {
  1371. char strParam[MAX_IO_NAME_LEN];
  1372. pParamEdit->GetWindowText(strParam, sizeof(strParam));
  1373. if (!strcmp(strParam, PARAM_STRING_NONE))
  1374. {
  1375. strParam[0] = '\0';
  1376. }
  1377. // Update the connections
  1378. int nConnCount = m_EditList.Count();
  1379. for (int nConn = 0; nConn < nConnCount; nConn++)
  1380. {
  1381. CEntityConnection *pConnection = m_EditList.Element(nConn);
  1382. if (pConnection != NULL)
  1383. {
  1384. pConnection->SetParam(strParam);
  1385. }
  1386. }
  1387. // Update the list box
  1388. for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
  1389. {
  1390. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  1391. {
  1392. m_ListCtrl.SetItemText(nItem, PARAMETER_COLUMN, strParam);
  1393. }
  1394. }
  1395. ResizeColumns();
  1396. }
  1397. }
  1398. //------------------------------------------------------------------------------
  1399. // Purpose: Inputs have changed. Update connections and listbox
  1400. //------------------------------------------------------------------------------
  1401. void COP_Output::UpdateEditedInputs(void)
  1402. {
  1403. // Get the new name
  1404. char strInput[MAX_IO_NAME_LEN];
  1405. GetInput(strInput, sizeof(strInput));
  1406. // Update the connections
  1407. int nConnCount = m_EditList.Count();
  1408. for (int nConn = 0; nConn < nConnCount; nConn++)
  1409. {
  1410. CEntityConnection *pConnection = m_EditList.Element(nConn);
  1411. if (pConnection != NULL)
  1412. {
  1413. pConnection->SetInputName(strInput);
  1414. }
  1415. }
  1416. // Update the list box
  1417. for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
  1418. {
  1419. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  1420. {
  1421. m_ListCtrl.SetItemText(nItem, INPUT_NAME_COLUMN, strInput);
  1422. UpdateItemValidity(nItem);
  1423. }
  1424. }
  1425. UpdateValidityButton();
  1426. ResizeColumns();
  1427. }
  1428. //------------------------------------------------------------------------------
  1429. // Purpose: Outputs have changed. Update connections and listbox
  1430. //------------------------------------------------------------------------------
  1431. void COP_Output::UpdateEditedOutputs()
  1432. {
  1433. // Get the new name
  1434. char strOutput[MAX_IO_NAME_LEN];
  1435. GetOutput(strOutput, sizeof(strOutput));
  1436. // Update the connections
  1437. int nConnCount = m_EditList.Count();
  1438. for (int nConn = 0; nConn < nConnCount; nConn++)
  1439. {
  1440. CEntityConnection *pConnection = m_EditList.Element(nConn);
  1441. if (pConnection != NULL)
  1442. {
  1443. pConnection->SetOutputName(strOutput);
  1444. }
  1445. }
  1446. // Update the list box
  1447. for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
  1448. {
  1449. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  1450. {
  1451. m_ListCtrl.SetItemText(nItem, OUTPUT_NAME_COLUMN, strOutput);
  1452. UpdateItemValidity(nItem);
  1453. }
  1454. }
  1455. UpdateValidityButton();
  1456. ResizeColumns();
  1457. }
  1458. //------------------------------------------------------------------------------
  1459. // Purpose: Targets have changed. Update connections and listbox
  1460. //------------------------------------------------------------------------------
  1461. void COP_Output::UpdateEditedTargets(void)
  1462. {
  1463. // Get the new target name
  1464. char strTarget[MAX_IO_NAME_LEN];
  1465. GetTarget(strTarget, sizeof(strTarget));
  1466. // Update the connections
  1467. int nConnCount = m_EditList.Count();
  1468. for (int nConn = 0; nConn < nConnCount; nConn++)
  1469. {
  1470. CEntityConnection *pConnection = m_EditList.Element(nConn);
  1471. if (pConnection != NULL)
  1472. {
  1473. pConnection->SetTargetName(strTarget);
  1474. }
  1475. }
  1476. // Update the list box
  1477. for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
  1478. {
  1479. if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
  1480. {
  1481. m_ListCtrl.SetItemText(nItem, TARGET_NAME_COLUMN, strTarget);
  1482. UpdateItemValidity(nItem);
  1483. }
  1484. }
  1485. UpdateValidityButton();
  1486. ResizeColumns();
  1487. }
  1488. //-----------------------------------------------------------------------------
  1489. // Purpose: Enables or diables the target combo box and the eyedropper button.
  1490. //-----------------------------------------------------------------------------
  1491. void COP_Output::EnableTarget(bool bEnable)
  1492. {
  1493. m_ComboTarget.EnableWindow(bEnable);
  1494. GetDlgItem(IDC_PICK_ENTITY)->EnableWindow(bEnable);
  1495. }
  1496. //-----------------------------------------------------------------------------
  1497. // Purpose:
  1498. // Input : *pConnection -
  1499. //-----------------------------------------------------------------------------
  1500. void COP_Output::SetConnection(CEntityConnectionList *pConnectionList)
  1501. {
  1502. Assert(pConnectionList != NULL);
  1503. // Fill edit boxes. Disable for multiple connections have incompatible data
  1504. bool bFirst = true;
  1505. CButton* pFireEdit = ( CButton* )GetDlgItem( IDC_EDIT_CONN_FIRE_ONCE );
  1506. CEdit* pDelayEdit = ( CEdit* )GetDlgItem( IDC_EDIT_CONN_DELAY );
  1507. CComboBox* pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
  1508. m_ComboOutput.EnableWindow(true);
  1509. EnableTarget(true);
  1510. m_ComboInput.EnableWindow(true);
  1511. pFireEdit->EnableWindow(true);
  1512. pDelayEdit->EnableWindow(true);
  1513. pParamEdit->EnableWindow(true);
  1514. GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( false );
  1515. m_bEntityParamTarget = false;
  1516. int nConnCount = pConnectionList->Count();
  1517. for (int nConn = 0; nConn < nConnCount; nConn++)
  1518. {
  1519. CEntityConnection *pConnection = (CEntityConnection *)pConnectionList->Element(nConn);
  1520. if (pConnection == NULL)
  1521. continue;
  1522. // Fill in output name, disable for non-compatible connections
  1523. if (m_ComboOutput.IsWindowEnabled())
  1524. {
  1525. if (bFirst)
  1526. {
  1527. m_strOutput = pConnection->GetOutputName();
  1528. }
  1529. else if (m_strOutput != pConnection->GetOutputName())
  1530. {
  1531. m_strOutput.Empty();
  1532. m_ComboOutput.EnableWindow(false);
  1533. }
  1534. }
  1535. // Fill in target name, disable for non-compatible connections
  1536. if (m_ComboTarget.IsWindowEnabled())
  1537. {
  1538. if (bFirst)
  1539. {
  1540. m_strTarget = pConnection->GetTargetName();
  1541. }
  1542. else if (m_strTarget != pConnection->GetTargetName())
  1543. {
  1544. m_strTarget.Empty();
  1545. EnableTarget(false);
  1546. }
  1547. }
  1548. // Fill in input name, disable for non-compatible connections
  1549. if (m_ComboInput.IsWindowEnabled())
  1550. {
  1551. if (bFirst)
  1552. {
  1553. m_strInput = pConnection->GetInputName();
  1554. }
  1555. else if (m_strInput != pConnection->GetInputName())
  1556. {
  1557. m_strInput.Empty();
  1558. m_ComboInput.EnableWindow(false);
  1559. }
  1560. }
  1561. // Fill in parameters, disable for non-compatible connections
  1562. if (pParamEdit->IsWindowEnabled())
  1563. {
  1564. if (bFirst)
  1565. {
  1566. m_strParam = pConnection->GetParam();
  1567. m_bNoParamEdit = false;
  1568. }
  1569. else if (m_strParam != pConnection->GetParam())
  1570. {
  1571. m_strParam.Empty();
  1572. pParamEdit->EnableWindow(false);
  1573. GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( false );
  1574. m_bNoParamEdit = true;
  1575. }
  1576. }
  1577. // Fill in delay, disable for non-compatible connections
  1578. if (pDelayEdit->IsWindowEnabled())
  1579. {
  1580. if (bFirst)
  1581. {
  1582. m_fDelay = pConnection->GetDelay();
  1583. }
  1584. else if (m_fDelay != pConnection->GetDelay())
  1585. {
  1586. m_fDelay = 0;
  1587. pDelayEdit->EnableWindow(false);
  1588. }
  1589. }
  1590. // Set fire once flag, disable for non-compatible connections
  1591. if (pFireEdit->IsWindowEnabled())
  1592. {
  1593. if (bFirst)
  1594. {
  1595. m_bFireOnce = (pConnection->GetTimesToFire() == -1) ? false : true;
  1596. }
  1597. else if (m_bFireOnce != pConnection->GetTimesToFire())
  1598. {
  1599. m_bFireOnce = false;
  1600. pFireEdit->EnableWindow(false);
  1601. }
  1602. }
  1603. bFirst = false;
  1604. }
  1605. // Put a <none> in param box if no param
  1606. if (strlen(m_strParam) == 0)
  1607. {
  1608. m_strParam = PARAM_STRING_NONE;
  1609. }
  1610. }
  1611. //-----------------------------------------------------------------------------
  1612. // Purpose: Adds all of an entity's outputs from its class definition to the
  1613. // outputs combo box.
  1614. // Input : pEntity - Entity whose outputs are to be added to the combo box.
  1615. //-----------------------------------------------------------------------------
  1616. void COP_Output::AddEntityOutputs(CMapEntity *pEntity)
  1617. {
  1618. GDclass *pClass = pEntity->GetClass();
  1619. if (pClass != NULL)
  1620. {
  1621. int nCount = pClass->GetOutputCount();
  1622. for (int i = 0; i < nCount; i++)
  1623. {
  1624. CClassOutput *pOutput = pClass->GetOutput(i);
  1625. int nIndex = m_ComboOutput.AddString(pOutput->GetName());
  1626. if (nIndex >= 0)
  1627. {
  1628. m_ComboOutput.SetItemDataPtr(nIndex, pOutput);
  1629. }
  1630. }
  1631. }
  1632. }
  1633. //-----------------------------------------------------------------------------
  1634. // Purpose:
  1635. //-----------------------------------------------------------------------------
  1636. void COP_Output::FillInputList(void)
  1637. {
  1638. if (!m_pMapEntityList)
  1639. {
  1640. return;
  1641. }
  1642. //
  1643. // Add all entity inputs to the inputs combo box.
  1644. //
  1645. m_ComboInput.SetRedraw(FALSE);
  1646. m_ComboInput.ResetContent();
  1647. // CUtlVector<GDclass*> classCache;
  1648. CUtlRBTree<int,int> classCache;
  1649. SetDefLessFunc( classCache );
  1650. FOR_EACH_OBJ( *m_pMapEntityList, pos )
  1651. {
  1652. CMapEntity *pEntity = m_pMapEntityList->Element(pos);
  1653. Assert(pEntity != NULL);
  1654. if (pEntity == NULL)
  1655. continue;
  1656. //
  1657. // Get the entity's class, which contains the list of inputs that this entity exposes.
  1658. //
  1659. GDclass *pClass = pEntity->GetClass();
  1660. if (pClass == NULL)
  1661. continue;
  1662. // check if class was already added
  1663. if ( classCache.Find( (int)pClass ) != -1 )
  1664. continue;
  1665. classCache.Insert( (int)pClass );
  1666. //
  1667. // Add this class' inputs to the list.
  1668. //
  1669. int nCount = pClass->GetInputCount();
  1670. for (int i = 0; i < nCount; i++)
  1671. {
  1672. CClassInput *pInput = pClass->GetInput(i);
  1673. bool bAddInput = true;
  1674. //
  1675. // Don't add the input to the combo box if another input with the same name
  1676. // and type is already there.
  1677. //
  1678. int nIndex = m_ComboInput.FindStringExact(-1, pInput->GetName());
  1679. if (nIndex != CB_ERR)
  1680. {
  1681. CClassInput *pExistingInput = (CClassInput *)m_ComboInput.GetItemDataPtr(nIndex);
  1682. if (pExistingInput->GetType() == pInput->GetType())
  1683. {
  1684. bAddInput = false;
  1685. }
  1686. }
  1687. if (bAddInput)
  1688. {
  1689. nIndex = m_ComboInput.AddString(pInput->GetName());
  1690. if (nIndex >= 0)
  1691. {
  1692. m_ComboInput.SetItemDataPtr(nIndex, pInput);
  1693. }
  1694. }
  1695. }
  1696. }
  1697. m_ComboInput.SetRedraw(TRUE);
  1698. }
  1699. //-----------------------------------------------------------------------------
  1700. // Purpose: Fills the list of outputs with outputs common to all the selected entities.
  1701. //-----------------------------------------------------------------------------
  1702. void COP_Output::FillOutputList(void)
  1703. {
  1704. if ( m_EntityList.Count() == 0 )
  1705. {
  1706. return;
  1707. }
  1708. //
  1709. // Determine what the currently selected output is (if any).
  1710. //
  1711. CClassOutput *pSelectedOutput;
  1712. int nOutput = m_ComboOutput.GetCurSel();
  1713. if (nOutput != CB_ERR)
  1714. {
  1715. pSelectedOutput = (CClassOutput *)m_ComboOutput.GetItemDataPtr(nOutput);
  1716. }
  1717. else
  1718. {
  1719. pSelectedOutput = NULL;
  1720. }
  1721. //
  1722. // Add the entity outputs to the outputs combo box.
  1723. //
  1724. m_ComboOutput.SetRedraw(FALSE);
  1725. m_ComboOutput.ResetContent();
  1726. bool bFirst = true;
  1727. FOR_EACH_OBJ( m_EntityList, pos )
  1728. {
  1729. CMapEntity *pEntity = m_EntityList.Element(pos);
  1730. if (bFirst)
  1731. {
  1732. //
  1733. // The first entity adds its outputs to the list.
  1734. //
  1735. AddEntityOutputs(pEntity);
  1736. bFirst = false;
  1737. }
  1738. else
  1739. {
  1740. //
  1741. // All subsequent entities filter the output list.
  1742. //
  1743. FilterEntityOutputs(pEntity);
  1744. }
  1745. }
  1746. if (m_ComboOutput.GetCount() == 0)
  1747. {
  1748. m_ComboOutput.EnableWindow(false);
  1749. }
  1750. m_ComboOutput.SetRedraw(TRUE);
  1751. }
  1752. //-----------------------------------------------------------------------------
  1753. // Purpose: Fills the list of targets with entities that have "targetname" keys.
  1754. //-----------------------------------------------------------------------------
  1755. void COP_Output::FillTargetList(void)
  1756. {
  1757. m_bIgnoreTextChanged = true;
  1758. m_ComboTarget.SetEntityList(m_pMapEntityList);
  1759. m_bIgnoreTextChanged = false;
  1760. }
  1761. //-----------------------------------------------------------------------------
  1762. // Purpose: Removes all outputs from the outputs combo box that are NOT present
  1763. // in the given entity's output list. Used when multiple entities are
  1764. // selected into the Entity Properties dialog.
  1765. // Input : pEntity - Entity to use for filter.
  1766. //-----------------------------------------------------------------------------
  1767. void COP_Output::FilterEntityOutputs(CMapEntity *pEntity)
  1768. {
  1769. //
  1770. // Make sure that this entity has a valid class to use for filtering.
  1771. //
  1772. GDclass *pClass = pEntity->GetClass();
  1773. if (pClass == NULL)
  1774. {
  1775. return;
  1776. }
  1777. //
  1778. // Remove any outputs from the combo box that are not in the class.
  1779. //
  1780. char szText[MAX_PATH];
  1781. int nCount = m_ComboOutput.GetCount();
  1782. if (nCount > 0)
  1783. {
  1784. for (int i = nCount - 1; i >= 0; i--)
  1785. {
  1786. if (m_ComboOutput.GetLBText(i, szText) != CB_ERR)
  1787. {
  1788. if (pClass->FindOutput(szText) == NULL)
  1789. {
  1790. m_ComboOutput.DeleteString(i);
  1791. }
  1792. }
  1793. }
  1794. }
  1795. }
  1796. //-----------------------------------------------------------------------------
  1797. // Purpose:
  1798. //-----------------------------------------------------------------------------
  1799. void COP_Output::FilterOutputList(void)
  1800. {
  1801. // dvs: Possibly unnecessary. For example, if they choose an input, then
  1802. // choose an incompatible output, the input will become red to indicate
  1803. // the incompatibilty. So maybe the outputs can always contain the set of
  1804. // all outputs common to the selected entities.
  1805. }
  1806. //-----------------------------------------------------------------------------
  1807. // Purpose: Filters the list of inputs based on the current selected target.
  1808. //-----------------------------------------------------------------------------
  1809. void COP_Output::FilterInputList(void)
  1810. {
  1811. char szTarget[MAX_ENTITY_NAME_LEN];
  1812. CMapEntityList *pTargets = GetTarget(szTarget, sizeof(szTarget));
  1813. if (pTargets != NULL)
  1814. {
  1815. //
  1816. // Remove all items from the inputs combo that:
  1817. //
  1818. // 1) Are not compatible with the currently selected output, OR
  1819. // 2) Are not found in the currently selected targets list.
  1820. //
  1821. int nCount = m_ComboInput.GetCount();
  1822. if (nCount > 0)
  1823. {
  1824. for (int i = nCount - 1; i >= 0; i--)
  1825. {
  1826. CClassInput *pInput = (CClassInput *)m_ComboInput.GetItemDataPtr(i);
  1827. if (!MapEntityList_HasInput(pTargets, pInput->GetName(), pInput->GetType()))
  1828. {
  1829. m_ComboInput.DeleteString(i);
  1830. }
  1831. }
  1832. }
  1833. }
  1834. }
  1835. //-----------------------------------------------------------------------------
  1836. // Purpose:
  1837. //-----------------------------------------------------------------------------
  1838. void COP_Output::FilterTargetList(void)
  1839. {
  1840. #if 0 // Not used...
  1841. char szInput[MAX_IO_NAME_LEN];
  1842. CClassInput *pInput = GetInput(szInput, sizeof(szInput));
  1843. //
  1844. // Remove all items from the targets combo that:
  1845. //
  1846. // 1) Do not have the selected input name OR
  1847. // 2) Do not have inputs that are compatible with the selected output.
  1848. //
  1849. int nCount = m_ComboTarget.GetCount();
  1850. if (nCount > 0)
  1851. {
  1852. for (int i = nCount - 1; i >= 0; i--)
  1853. {
  1854. CMapEntityList *pTargets = (CMapEntityList *)m_ComboTarget.GetItemDataPtr(i);
  1855. if (!MapEntityList_HasInput(pTargets, pInput->GetName(), pInput->GetType()))
  1856. {
  1857. m_ComboTarget.DeleteString(i);
  1858. }
  1859. }
  1860. }
  1861. #endif
  1862. }
  1863. //-----------------------------------------------------------------------------
  1864. // Purpose: Returns the currently selected input, NULL if unknown.
  1865. // Input : szInput - Receives the text in the Input combo edit control.
  1866. // nSize - Size of buffer pointed to by szInput.
  1867. //-----------------------------------------------------------------------------
  1868. CClassInput *COP_Output::GetInput(char *szInput, int nSize)
  1869. {
  1870. szInput[0] = '\0';
  1871. int nCurSel = m_ComboInput.GetCurSel();
  1872. if (nCurSel == CB_ERR)
  1873. {
  1874. if (m_ComboInput.GetWindowText(szInput, nSize) > 0)
  1875. {
  1876. nCurSel = m_ComboInput.FindStringExact(-1, szInput);
  1877. }
  1878. }
  1879. CClassInput *pInput = NULL;
  1880. if (nCurSel != CB_ERR)
  1881. {
  1882. m_ComboInput.GetLBText(nCurSel, szInput);
  1883. pInput = (CClassInput *)m_ComboInput.GetItemDataPtr(nCurSel);
  1884. }
  1885. return(pInput);
  1886. }
  1887. //-----------------------------------------------------------------------------
  1888. // Purpose: Returns the currently selected output, NULL if unknown.
  1889. // Input : szOutput - Receives the text in the Output combo edit control.
  1890. // nSize - Size of buffer pointed to by szOutput.
  1891. //-----------------------------------------------------------------------------
  1892. CClassOutput *COP_Output::GetOutput(char *szOutput, int nSize)
  1893. {
  1894. szOutput[0] = '\0';
  1895. int nCurSel = m_ComboOutput.GetCurSel();
  1896. if (nCurSel == CB_ERR)
  1897. {
  1898. if (m_ComboOutput.GetWindowText(szOutput, nSize) > 0)
  1899. {
  1900. nCurSel = m_ComboOutput.FindStringExact(-1, szOutput);
  1901. }
  1902. }
  1903. CClassOutput *pOutput = NULL;
  1904. if (nCurSel != CB_ERR)
  1905. {
  1906. m_ComboOutput.GetLBText(nCurSel, szOutput);
  1907. pOutput = (CClassOutput *)m_ComboOutput.GetItemDataPtr(nCurSel);
  1908. }
  1909. return(pOutput);
  1910. }
  1911. //-----------------------------------------------------------------------------
  1912. // Purpose: Returns the currently selected target list, NULL if unknown.
  1913. // Input : szTarget - Receives the text in the Target combo edit control.
  1914. // nSize - Size of buffer pointed to by szTarget.
  1915. //-----------------------------------------------------------------------------
  1916. CMapEntityList *COP_Output::GetTarget(char *szTarget, int nSize)
  1917. {
  1918. szTarget[0] = '\0';
  1919. CString str = m_ComboTarget.GetCurrentItem();
  1920. Q_strncpy( szTarget, str, nSize );
  1921. return m_ComboTarget.GetSubEntityList( szTarget );
  1922. }
  1923. //-----------------------------------------------------------------------------
  1924. // Purpose: Called when the contents of the delay edit box change.
  1925. //-----------------------------------------------------------------------------
  1926. void COP_Output::OnEditDelay(void)
  1927. {
  1928. UpdateEditedDelays();
  1929. }
  1930. //-----------------------------------------------------------------------------
  1931. // Purpose: Called when the contents of the target combo edit box change.
  1932. //-----------------------------------------------------------------------------
  1933. void COP_Output::OnFireOnce(void)
  1934. {
  1935. UpdateEditedFireOnce();
  1936. }
  1937. //-----------------------------------------------------------------------------
  1938. // Purpose: Called when they change the "Show Hidden Targets" checkbox.
  1939. //-----------------------------------------------------------------------------
  1940. void COP_Output::OnShowHiddenTargetsAsBroken()
  1941. {
  1942. // Remember the last state of this checkbox.
  1943. Options.general.bShowHiddenTargetsAsBroken = (m_ctlShowHiddenTargetsAsBroken.GetCheck() != FALSE);
  1944. // Refresh.
  1945. int nCount = m_ListCtrl.GetItemCount();
  1946. for ( int i=0; i < nCount; i++ )
  1947. {
  1948. UpdateItemValidity( i );
  1949. }
  1950. //UpdateConnectionList();
  1951. }
  1952. //-----------------------------------------------------------------------------
  1953. // Purpose: React to the input combo box being changed
  1954. //-----------------------------------------------------------------------------
  1955. void COP_Output::InputChanged(void)
  1956. {
  1957. // Updating the listbox data, will trigger the edit
  1958. // controls to update. They don't need to be
  1959. bSkipEditControlRefresh = true;
  1960. char szInput[MAX_IO_NAME_LEN];
  1961. CClassInput *pInput = GetInput(szInput, sizeof(szInput));
  1962. UpdateCombosForSelectedInput(pInput);
  1963. UpdateEditedInputs();
  1964. }
  1965. //-----------------------------------------------------------------------------
  1966. // Purpose: Called when selection of input combo box chages
  1967. //-----------------------------------------------------------------------------
  1968. void COP_Output::OnSelChangeInput(void)
  1969. {
  1970. InputChanged();
  1971. }
  1972. //-----------------------------------------------------------------------------
  1973. // Purpose: Called when the contents of the input combo edit box change.
  1974. //-----------------------------------------------------------------------------
  1975. void COP_Output::OnEditUpdateInput(void)
  1976. {
  1977. InputChanged();
  1978. }
  1979. //------------------------------------------------------------------------------
  1980. // Purpose: React to the output combo box being changed
  1981. //------------------------------------------------------------------------------
  1982. void COP_Output::OutputChanged(void)
  1983. {
  1984. // Updating the listbox data, will trigger the edit
  1985. // controls to update. They don't need to be
  1986. bSkipEditControlRefresh = true;
  1987. char szOutput[MAX_IO_NAME_LEN];
  1988. CClassOutput *pOutput = GetOutput(szOutput, sizeof(szOutput));
  1989. UpdateCombosForSelectedOutput(pOutput);
  1990. UpdateEditedOutputs();
  1991. }
  1992. //-----------------------------------------------------------------------------
  1993. // Purpose: Called when selection of output combo box chages
  1994. //-----------------------------------------------------------------------------
  1995. void COP_Output::OnSelChangeOutput(void)
  1996. {
  1997. OutputChanged();
  1998. }
  1999. //-----------------------------------------------------------------------------
  2000. // Purpose: Called when the contents of the output combo edit box change.
  2001. //-----------------------------------------------------------------------------
  2002. void COP_Output::OnEditUpdateOutput(void)
  2003. {
  2004. OutputChanged();
  2005. }
  2006. //-----------------------------------------------------------------------------
  2007. // Purpose: Called when selection of parameter combo box chages
  2008. //-----------------------------------------------------------------------------
  2009. void COP_Output::OnSelChangeParam(void)
  2010. {
  2011. // If user picked <none> selection (the only valid one) clear window text
  2012. CComboBox *pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
  2013. if (pParamEdit->GetCurSel() != CB_ERR)
  2014. {
  2015. pParamEdit->SetWindowText("");
  2016. }
  2017. UpdateEditedParams();
  2018. }
  2019. //-----------------------------------------------------------------------------
  2020. // Purpose: Called when the contents of the parameter combo edit box change.
  2021. //-----------------------------------------------------------------------------
  2022. void COP_Output::OnEditUpdateParam(void)
  2023. {
  2024. UpdateEditedParams();
  2025. }
  2026. //-----------------------------------------------------------------------------
  2027. // Purpose: Updates the dialog based on the currently selected input.
  2028. // Input : pInput - Pointer to the input that is selected, NULL if none or
  2029. // ambiguous/unresolved.
  2030. //-----------------------------------------------------------------------------
  2031. void COP_Output::UpdateCombosForSelectedInput(CClassInput *pInput)
  2032. {
  2033. // Enable / Disable param box based on input type if allowed
  2034. if (!m_bNoParamEdit)
  2035. {
  2036. CComboBox *pParamCombo = (CComboBox *)GetDlgItem(IDC_EDIT_CONN_PARAM);
  2037. bool bEnable = ((!pInput) || (pInput && (pInput->GetType() != iotVoid)));
  2038. if (!bEnable)
  2039. {
  2040. // Save the param so we can restore it if they switch right back.
  2041. CString strTemp;
  2042. pParamCombo->GetWindowText(strTemp);
  2043. if (strTemp.Compare(PARAM_STRING_NONE))
  2044. {
  2045. m_strLastParam = strTemp;
  2046. }
  2047. // Switch back to <none> if we're disabling the parameter combo.
  2048. pParamCombo->SetCurSel(0);
  2049. }
  2050. else if (!m_strLastParam.IsEmpty())
  2051. {
  2052. pParamCombo->SetWindowText(m_strLastParam);
  2053. }
  2054. UpdateEditedParams();
  2055. pParamCombo->EnableWindow(bEnable);
  2056. m_bEntityParamTarget = pInput && (pInput->GetType() == iotEHandle);
  2057. GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( m_bEntityParamTarget );
  2058. }
  2059. if (pInput != NULL)
  2060. {
  2061. //
  2062. // Known input, render it in black.
  2063. //
  2064. m_ComboInput.SetTextColor(RGB(0, 0, 0));
  2065. }
  2066. else
  2067. {
  2068. //
  2069. // Unknown input, render it in red.
  2070. //
  2071. m_ComboInput.SetTextColor(RGB(255, 0, 0));
  2072. }
  2073. m_ComboInput.RedrawWindow();
  2074. }
  2075. //-----------------------------------------------------------------------------
  2076. // Purpose: Updates the dialog based on the currently selected output.
  2077. // Input : pOutput - Pointer to the output that is selected, NULL if none or
  2078. // ambiguous/unresolved.
  2079. //-----------------------------------------------------------------------------
  2080. void COP_Output::UpdateCombosForSelectedOutput(CClassOutput *pOutput)
  2081. {
  2082. if (pOutput != NULL)
  2083. {
  2084. //
  2085. // Known output, render it in black.
  2086. //
  2087. m_ComboOutput.SetTextColor(RGB(0, 0, 0));
  2088. }
  2089. else
  2090. {
  2091. //
  2092. // Unknown output, render it in red.
  2093. //
  2094. m_ComboOutput.SetTextColor(RGB(255, 0, 0));
  2095. }
  2096. m_ComboOutput.RedrawWindow();
  2097. }
  2098. //-----------------------------------------------------------------------------
  2099. // Purpose: Stops entity picking.
  2100. //-----------------------------------------------------------------------------
  2101. void COP_Output::StopPicking(void)
  2102. {
  2103. if (m_bPickingEntities)
  2104. {
  2105. m_bPickingEntities = false;
  2106. ToolManager()->SetTool(TOOL_POINTER);
  2107. CButton *pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY);
  2108. if (pButton)
  2109. {
  2110. pButton->SetCheck(0);
  2111. }
  2112. pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY_PARAM);
  2113. if (pButton)
  2114. {
  2115. pButton->SetCheck(0);
  2116. }
  2117. if ( m_ComboTarget.IsWindowEnabled() )
  2118. {
  2119. GetDlgItem(IDC_PICK_ENTITY)->EnableWindow( true );
  2120. }
  2121. CComboBox* pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
  2122. if ( pParamEdit->IsWindowEnabled() )
  2123. {
  2124. GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( m_bEntityParamTarget );
  2125. }
  2126. }
  2127. }
  2128. void COP_Output::OnSize( UINT nType, int cx, int cy )
  2129. {
  2130. m_AnchorMgr.OnSize();
  2131. }